From f00a75c094c340c4e7435665816c3273c870e849 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Oct 2009 15:17:45 +0100 Subject: [PATCH 0001/3892] ARM: Pass VMA to copy_user_highpage() implementations Our copy_user_highpage() implementations may require cache maintainence. Ensure that implementations have all necessary details to perform this maintainence. Signed-off-by: Russell King --- arch/arm/include/asm/page.h | 7 ++++--- arch/arm/mm/copypage-feroceon.c | 2 +- arch/arm/mm/copypage-v3.c | 2 +- arch/arm/mm/copypage-v4mc.c | 2 +- arch/arm/mm/copypage-v4wb.c | 2 +- arch/arm/mm/copypage-v4wt.c | 2 +- arch/arm/mm/copypage-v6.c | 4 ++-- arch/arm/mm/copypage-xsc3.c | 2 +- arch/arm/mm/copypage-xscale.c | 2 +- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 3a32af4cce30..a485ac3c8696 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -117,11 +117,12 @@ #endif struct page; +struct vm_area_struct; struct cpu_user_fns { void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr); void (*cpu_copy_user_highpage)(struct page *to, struct page *from, - unsigned long vaddr); + unsigned long vaddr, struct vm_area_struct *vma); }; #ifdef MULTI_USER @@ -137,7 +138,7 @@ extern struct cpu_user_fns cpu_user; extern void __cpu_clear_user_highpage(struct page *page, unsigned long vaddr); extern void __cpu_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr); + unsigned long vaddr, struct vm_area_struct *vma); #endif #define clear_user_highpage(page,vaddr) \ @@ -145,7 +146,7 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from, #define __HAVE_ARCH_COPY_USER_HIGHPAGE #define copy_user_highpage(to,from,vaddr,vma) \ - __cpu_copy_user_highpage(to, from, vaddr) + __cpu_copy_user_highpage(to, from, vaddr, vma) #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) extern void copy_page(void *to, const void *from); diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index 70997d5bee2d..e2e8d29c548b 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -68,7 +68,7 @@ feroceon_copy_user_page(void *kto, const void *kfrom) } void feroceon_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; diff --git a/arch/arm/mm/copypage-v3.c b/arch/arm/mm/copypage-v3.c index de9c06854ad7..f72303e1d804 100644 --- a/arch/arm/mm/copypage-v3.c +++ b/arch/arm/mm/copypage-v3.c @@ -38,7 +38,7 @@ v3_copy_user_page(void *kto, const void *kfrom) } void v3_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 7370a7142b04..598c51ad5071 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -69,7 +69,7 @@ mc_copy_user_page(void *from, void *to) } void v4_mc_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto = kmap_atomic(to, KM_USER1); diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index 9ab098414227..e9920f68b76b 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -48,7 +48,7 @@ v4wb_copy_user_page(void *kto, const void *kfrom) } void v4wb_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c index 300efafd6643..172e6a55458e 100644 --- a/arch/arm/mm/copypage-v4wt.c +++ b/arch/arm/mm/copypage-v4wt.c @@ -44,7 +44,7 @@ v4wt_copy_user_page(void *kto, const void *kfrom) } void v4wt_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 4127a7bddfe5..334d5602770e 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -34,7 +34,7 @@ static DEFINE_SPINLOCK(v6_lock); * attack the kernel's existing mapping of these pages. */ static void v6_copy_user_highpage_nonaliasing(struct page *to, - struct page *from, unsigned long vaddr) + struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; @@ -73,7 +73,7 @@ static void discard_old_kernel_data(void *kto) * Copy the page, taking account of the cache colour. */ static void v6_copy_user_highpage_aliasing(struct page *to, - struct page *from, unsigned long vaddr) + struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { unsigned int offset = CACHE_COLOUR(vaddr); unsigned long kfrom, kto; diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index bc4525f5ab23..18ae05d5829c 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -71,7 +71,7 @@ xsc3_mc_copy_user_page(void *kto, const void *kfrom) } void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto, *kfrom; diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 76824d3e966a..9920c0ae2096 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -91,7 +91,7 @@ mc_copy_user_page(void *from, void *to) } void xscale_mc_copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr) + unsigned long vaddr, struct vm_area_struct *vma) { void *kto = kmap_atomic(to, KM_USER1); -- GitLab From 2725898fc9bb2121ac0fb1b5e4faf4fc09014729 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Oct 2009 15:34:22 +0100 Subject: [PATCH 0002/3892] ARM: Flush user mapping on VIVT processors when copying a page Steven Walter writes: > I've been tracking down an instance of userspace data corruption, > and I believe I have found a window during fork where data can be > lost. The corruption is occurring on an ARMv5 system with VIVT > caches. Here's the scenario in question. Thread A is forking, > Thread B is running in userspace: > > Thread A: flush_cache_mm() (dup_mmap) > Thread B: writes to a page in the above mm > Thread A: pte_wrprotect() the above page (copy_one_pte) > Thread B: writes to the same page again > > During thread B's second write, he'll take a fault and enter the > do_wp_page() case. We'll end up calling copy_page(), which notably > uses the kernel virtual addresses for the old and new pages. This > means that the new page does not necessarily have the data from the > first write. Now there are two conflicting copies of the same > cache-line in dcache. If the userspace cache-line flushes before > the kernel cache-line, we lose the changes made during the first > write. do_wp_page does call flush_dcache_page on the newly-copied > page, but there's still a window where the CPU could flush the > userspace cache-line before then. Resolve this by flushing the user mapping before copying the page on processors with a writeback VIVT cache. Note: this does have a performance impact, and so needs further consideration before being merged - can we optimize out some of the cache flushes if, eg, we know that the page isn't yet mapped? Thread: Signed-off-by: Russell King --- arch/arm/mm/copypage-feroceon.c | 1 + arch/arm/mm/copypage-v4wb.c | 1 + arch/arm/mm/copypage-xsc3.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index e2e8d29c548b..5eb4fd93893d 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -74,6 +74,7 @@ void feroceon_copy_user_highpage(struct page *to, struct page *from, kto = kmap_atomic(to, KM_USER0); kfrom = kmap_atomic(from, KM_USER1); + flush_cache_page(vma, vaddr, page_to_pfn(from)); feroceon_copy_user_page(kto, kfrom); kunmap_atomic(kfrom, KM_USER1); kunmap_atomic(kto, KM_USER0); diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index e9920f68b76b..7c2eb55cd4a9 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -54,6 +54,7 @@ void v4wb_copy_user_highpage(struct page *to, struct page *from, kto = kmap_atomic(to, KM_USER0); kfrom = kmap_atomic(from, KM_USER1); + flush_cache_page(vma, vaddr, page_to_pfn(from)); v4wb_copy_user_page(kto, kfrom); kunmap_atomic(kfrom, KM_USER1); kunmap_atomic(kto, KM_USER0); diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index 18ae05d5829c..747ad4140fc7 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -77,6 +77,7 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, kto = kmap_atomic(to, KM_USER0); kfrom = kmap_atomic(from, KM_USER1); + flush_cache_page(vma, vaddr, page_to_pfn(from)); xsc3_mc_copy_user_page(kto, kfrom); kunmap_atomic(kfrom, KM_USER1); kunmap_atomic(kto, KM_USER0); -- GitLab From 7b76bfc86757ca5e7b0a62f50003752da77c115b Mon Sep 17 00:00:00 2001 From: Dick Streefland Date: Tue, 6 Oct 2009 22:35:40 +0200 Subject: [PATCH 0003/3892] kconfig: simplification of scripts/extract-ikconfig I've rewritten the extract-ikconfig script to extract the kernel configuration from a kernel compiled with CONFIG_IKCONFIG. The main motivation for the rewrite was to remove the dependency on the external C program binoffset.c, which is compiled on the initial run. The binoffset executable is invoked with a relative path, which means that the old script can only be run from the top of the kernel tree, and only when you have write permission in the scripts directory. The new script uses tr/grep/tail/zcat only, and can be invoked from anywhere. The binoffset.c program has been removed. This script requires GNU grep 2.5 (released 2002-03-13) or higher, because the -o option was introduced in that version. Signed-off-by: Dick Streefland LKML-Reference: <20091006203540.GA14634@streefland.net> Tested-by: Steven Rostedt Cc: Sam Ravnborg Signed-off-by: Steven Rostedt --- Documentation/dontdiff | 1 - scripts/.gitignore | 1 - scripts/binoffset.c | 163 --------------------------------------- scripts/extract-ikconfig | 127 +++++++++++------------------- 4 files changed, 44 insertions(+), 248 deletions(-) delete mode 100644 scripts/binoffset.c diff --git a/Documentation/dontdiff b/Documentation/dontdiff index e1efc400bed6..bc01a5a9d663 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -68,7 +68,6 @@ autoconf.h* bbootsect bin2c binkernel.spec -binoffset bootsect bounds.h bsetup diff --git a/scripts/.gitignore b/scripts/.gitignore index 52cab46ae35a..c5d5db54c009 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -6,5 +6,4 @@ kallsyms pnmtologo bin2c unifdef -binoffset ihex2fw diff --git a/scripts/binoffset.c b/scripts/binoffset.c deleted file mode 100644 index 1a2e39b8e3e5..000000000000 --- a/scripts/binoffset.c +++ /dev/null @@ -1,163 +0,0 @@ -/*************************************************************************** - * binoffset.c - * (C) 2002 Randy Dunlap - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# binoffset.c: -# - searches a (binary) file for a specified (binary) pattern -# - returns the offset of the located pattern or ~0 if not found -# - exits with exit status 0 normally or non-0 if pattern is not found -# or any other error occurs. - -****************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VERSION "0.1" -#define BUF_SIZE (16 * 1024) -#define PAT_SIZE 100 - -char *progname; -char *inputname; -int inputfd; -unsigned int bix; /* buf index */ -unsigned char patterns [PAT_SIZE] = {0}; /* byte-sized pattern array */ -int pat_len; /* actual number of pattern bytes */ -unsigned char *madr; /* mmap address */ -size_t filesize; -int num_matches = 0; -off_t firstloc = 0; - -void usage (void) -{ - fprintf (stderr, "%s ver. %s\n", progname, VERSION); - fprintf (stderr, "usage: %s filename pattern_bytes\n", - progname); - fprintf (stderr, " [prints location of pattern_bytes in file]\n"); - exit (1); -} - -void get_pattern (int pat_count, char *pats []) -{ - int ix, err, tmp; - -#ifdef DEBUG - fprintf (stderr,"get_pattern: count = %d\n", pat_count); - for (ix = 0; ix < pat_count; ix++) - fprintf (stderr, " pat # %d: [%s]\n", ix, pats[ix]); -#endif - - for (ix = 0; ix < pat_count; ix++) { - tmp = 0; - err = sscanf (pats[ix], "%5i", &tmp); - if (err != 1 || tmp > 0xff) { - fprintf (stderr, "pattern or value error in pattern # %d [%s]\n", - ix, pats[ix]); - usage (); - } - patterns [ix] = tmp; - } - pat_len = pat_count; -} - -void search_pattern (void) -{ - for (bix = 0; bix < filesize; bix++) { - if (madr[bix] == patterns[0]) { - if (memcmp (&madr[bix], patterns, pat_len) == 0) { - if (num_matches == 0) - firstloc = bix; - num_matches++; - } - } - } -} - -#ifdef NOTDEF -size_t get_filesize (int fd) -{ - off_t end_off = lseek (fd, 0, SEEK_END); - lseek (fd, 0, SEEK_SET); - return (size_t) end_off; -} -#endif - -size_t get_filesize (int fd) -{ - int err; - struct stat stat; - - err = fstat (fd, &stat); - fprintf (stderr, "filesize: %ld\n", err < 0 ? (long)err : stat.st_size); - if (err < 0) - return err; - return (size_t) stat.st_size; -} - -int main (int argc, char *argv []) -{ - progname = argv[0]; - - if (argc < 3) - usage (); - - get_pattern (argc - 2, argv + 2); - - inputname = argv[1]; - - inputfd = open (inputname, O_RDONLY); - if (inputfd == -1) { - fprintf (stderr, "%s: cannot open '%s'\n", - progname, inputname); - exit (3); - } - - filesize = get_filesize (inputfd); - - madr = mmap (0, filesize, PROT_READ, MAP_PRIVATE, inputfd, 0); - if (madr == MAP_FAILED) { - fprintf (stderr, "mmap error = %d\n", errno); - close (inputfd); - exit (4); - } - - search_pattern (); - - if (munmap (madr, filesize)) - fprintf (stderr, "munmap error = %d\n", errno); - - if (close (inputfd)) - fprintf (stderr, "%s: error %d closing '%s'\n", - progname, errno, inputname); - - fprintf (stderr, "number of pattern matches = %d\n", num_matches); - if (num_matches == 0) - firstloc = ~0; - printf ("%ld\n", firstloc); - fprintf (stderr, "%ld\n", firstloc); - - exit (num_matches ? 0 : 2); -} - -/* end binoffset.c */ diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig index de233ff43c1c..37f30d36c944 100755 --- a/scripts/extract-ikconfig +++ b/scripts/extract-ikconfig @@ -1,92 +1,53 @@ #!/bin/sh -# extracts .config info from a [b]zImage file -# uses: binoffset (new), dd, zcat, strings, grep -# $arg1 is [b]zImage filename - -binoffset="./scripts/binoffset" -test -e $binoffset || cc -o $binoffset ./scripts/binoffset.c || exit 1 - -IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54" -IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44" -dump_config() { - file="$1" - - start=`$binoffset $file $IKCFG_ST 2>/dev/null` - [ "$?" != "0" ] && start="-1" - if [ "$start" -eq "-1" ]; then - return - fi - end=`$binoffset $file $IKCFG_ED 2>/dev/null` - [ "$?" != "0" ] && end="-1" - if [ "$end" -eq "-1" ]; then - return - fi - - start=`expr $start + 8` - size=`expr $end - $start` - - dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat - - clean_up - exit 0 -} - - -usage() -{ - echo " usage: extract-ikconfig [b]zImage_filename" -} - -clean_up() +# ---------------------------------------------------------------------- +# extract-ikconfig - Extract the .config file from a kernel image +# +# This will only work when the kernel was compiled with CONFIG_IKCONFIG. +# +# The obscure use of the "tr" filter is to work around older versions of +# "grep" that report the byte offset of the line instead of the pattern. +# +# (c) 2009, Dick Streefland +# Licensed under the terms of the GNU General Public License. +# ---------------------------------------------------------------------- + +gz1='\037\213\010' +gz2='01' +cf1='IKCFG_ST\037\213\010' +cf2='0123456789' + +dump_config() { - if [ "$TMPFILE" != "" ]; then - rm -f $TMPFILE + if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"` + then + pos=${pos%%:*} + tail -c+$(($pos+8)) "$1" | zcat -q + exit 0 fi } -if [ $# -lt 1 ] +# Check invocation: +me=${0##*/} +img=$1 +if [ $# -ne 1 -o ! -s "$img" ] then - usage - exit 1 + echo "Usage: $me " >&2 + exit 2 fi -TMPFILE=`mktemp -t ikconfig-XXXXXX` || exit 1 -image="$1" - -# vmlinux: Attempt to dump the configuration from the file directly -dump_config "$image" - -GZHDR1="0x1f 0x8b 0x08 0x00" -GZHDR2="0x1f 0x8b 0x08 0x08" - -ELFHDR="0x7f 0x45 0x4c 0x46" - -# vmlinux.gz: Check for a compressed images -off=`$binoffset "$image" $GZHDR1 2>/dev/null` -[ "$?" != "0" ] && off="-1" -if [ "$off" -eq "-1" ]; then - off=`$binoffset "$image" $GZHDR2 2>/dev/null` - [ "$?" != "0" ] && off="-1" -fi -if [ "$off" -eq "0" ]; then - zcat <"$image" >"$TMPFILE" - dump_config "$TMPFILE" -elif [ "$off" -ne "-1" ]; then - (dd ibs="$off" skip=1 count=0 && dd bs=512k) <"$image" 2>/dev/null | \ - zcat >"$TMPFILE" - dump_config "$TMPFILE" - -# check if this is simply an ELF file -else - off=`$binoffset "$image" $ELFHDR 2>/dev/null` - [ "$?" != "0" ] && off="-1" - if [ "$off" -eq "0" ]; then - dump_config "$image" - fi -fi - -echo "ERROR: Unable to extract kernel configuration information." -echo " This kernel image may not have the config info." - -clean_up +# Initial attempt for uncompressed images or objects: +dump_config "$img" + +# That didn't work, so decompress and try again: +tmp=/tmp/ikconfig$$ +trap "rm -f $tmp" 0 +for pos in `tr "$gz1\n$gz2" "\n$gz2=" < "$img" | grep -abo "^$gz2"` +do + pos=${pos%%:*} + tail -c+$pos "$img" | zcat 2> /dev/null > $tmp + dump_config $tmp +done + +# Bail out: +echo "$me: Cannot find kernel config." >&2 exit 1 -- GitLab From 83cb16727085b18191f45eb0ede6bf1f97d67a7a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 14 Oct 2009 17:48:38 +0200 Subject: [PATCH 0004/3892] nvram: Drop the BKL from nvram_open() It's safe to remove the BKL from nvram_open(): there's no open() versus read() races: nvram_init() is very simple and race-free, it registers the device then puts it into /proc - there's no state init to race with. Cc: Wim Van Sebroeck Cc: Al Viro Cc: Frederic Weisbecker Cc: Thomas Gleixner LKML-Reference: <1255116426-7270-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- drivers/char/nvram.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 2100a8f7bd86..7cf4518c030f 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -329,14 +329,12 @@ static int nvram_ioctl(struct inode *inode, struct file *file, static int nvram_open(struct inode *inode, struct file *file) { - lock_kernel(); spin_lock(&nvram_state_lock); if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || (nvram_open_mode & NVRAM_EXCL) || ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) { spin_unlock(&nvram_state_lock); - unlock_kernel(); return -EBUSY; } @@ -347,7 +345,6 @@ static int nvram_open(struct inode *inode, struct file *file) nvram_open_cnt++; spin_unlock(&nvram_state_lock); - unlock_kernel(); return 0; } -- GitLab From f25234f1c21ad9878bd38719381e13f4ef1990ce Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 1 Nov 2009 14:46:26 +0100 Subject: [PATCH 0005/3892] CRIS v32: Should index be positive? `port' is used as index for writing to pins during allocation/deallocation. It should be positive. Signed-off-by: Roel Kluin Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/pinmux.c | 4 ++-- arch/cris/arch-v32/mach-a3/pinmux.c | 2 +- arch/cris/arch-v32/mach-fs/pinmux.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/cris/arch-v32/kernel/pinmux.c b/arch/cris/arch-v32/kernel/pinmux.c index 6eb54ea1c976..f6f3637a4194 100644 --- a/arch/cris/arch-v32/kernel/pinmux.c +++ b/arch/cris/arch-v32/kernel/pinmux.c @@ -54,7 +54,7 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) crisv32_pinmux_init(); - if (port > PORTS) + if (port > PORTS || port < 0) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); @@ -197,7 +197,7 @@ crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) crisv32_pinmux_init(); - if (port > PORTS) + if (port > PORTS || port < 0) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); diff --git a/arch/cris/arch-v32/mach-a3/pinmux.c b/arch/cris/arch-v32/mach-a3/pinmux.c index 0a28c9bedfb7..18648ef2d874 100644 --- a/arch/cris/arch-v32/mach-a3/pinmux.c +++ b/arch/cris/arch-v32/mach-a3/pinmux.c @@ -242,7 +242,7 @@ crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) crisv32_pinmux_init(); - if (port > PORTS) + if (port > PORTS || port < 0) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c index d722ad9ae626..38f29eec14a6 100644 --- a/arch/cris/arch-v32/mach-fs/pinmux.c +++ b/arch/cris/arch-v32/mach-fs/pinmux.c @@ -54,7 +54,7 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) crisv32_pinmux_init(); - if (port > PORTS) + if (port > PORTS || port < 0) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); @@ -195,7 +195,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) crisv32_pinmux_init(); - if (port > PORTS) + if (port > PORTS || port < 0) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); -- GitLab From d8fe989e7368a26e4baf9acb55524c71e5c3a117 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 Nov 2009 13:13:41 +0100 Subject: [PATCH 0006/3892] cris: Fixup last users of irq_chip->typename The typename member of struct irq_chip was kept for migration purposes and is obsolete since more than 2 years. Fix up the leftovers. Signed-off-by: Thomas Gleixner Cc: Mikael Starvik Cc: linux-cris-kernel@axis.com Signed-off-by: Jesper Nilsson --- arch/cris/arch-v10/kernel/irq.c | 2 +- arch/cris/arch-v32/kernel/irq.c | 2 +- arch/cris/kernel/irq.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index 5d75f77f9c73..1a61efc13982 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -133,7 +133,7 @@ static void end_crisv10_irq(unsigned int irq) } static struct irq_chip crisv10_irq_type = { - .typename = "CRISv10", + .name = "CRISv10", .startup = startup_crisv10_irq, .shutdown = shutdown_crisv10_irq, .enable = enable_crisv10_irq, diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index 57668db25031..b6241198fb98 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -336,7 +336,7 @@ int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest) } static struct irq_chip crisv32_irq_type = { - .typename = "CRISv32", + .name = "CRISv32", .startup = startup_crisv32_irq, .shutdown = shutdown_crisv32_irq, .enable = enable_crisv32_irq, diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index 0ca7d9892cc6..48fbdbdb58a8 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); #endif - seq_printf(p, " %14s", irq_desc[i].chip->typename); + seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) -- GitLab From e169cfbef46d62e042614ffafa8880eed1d894bb Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 14:53:09 -0700 Subject: [PATCH 0007/3892] of/flattree: merge find_flat_dt_string and initial_boot_params Merge common code between Microblaze and PowerPC. Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/Kconfig | 1 + arch/microblaze/kernel/prom.c | 8 -------- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/prom.c | 12 ------------ drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/fdt.c | 21 +++++++++++++++++++++ include/linux/of_fdt.h | 4 ++++ 8 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 drivers/of/fdt.c diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index bbd8327f1890..f39c9275a29b 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -111,6 +111,7 @@ config CMDLINE_FORCE config OF def_bool y + select OF_FLATTREE config PROC_DEVICETREE bool "Support for device tree in /proc" diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index b817df172aa9..06d620ab4168 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -47,17 +47,9 @@ static int __initdata dt_root_size_cells; typedef u32 cell_t; -static struct boot_param_header *initial_boot_params; - /* export that to outside world */ struct device_node *of_chosen; -static inline char *find_flat_dt_string(u32 offset) -{ - return ((char *)initial_boot_params) + - initial_boot_params->off_dt_strings + offset; -} - /** * This function is used to scan the flattened device-tree, it is * used to extract the memory informations at boot before we can diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 2ba14e77296c..2a75c6ae2a8b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -163,6 +163,7 @@ config PPC_OF config OF def_bool y + select OF_FLATTREE config PPC_UDBG_16550 bool diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4ec300862466..fccf7e49bb28 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -73,12 +73,6 @@ unsigned long tce_alloc_start, tce_alloc_end; typedef u32 cell_t; -#if 0 -static struct boot_param_header *initial_boot_params __initdata; -#else -struct boot_param_header *initial_boot_params; -#endif - extern struct device_node *allnodes; /* temporary while merging */ extern rwlock_t devtree_lock; /* temporary while merging */ @@ -86,12 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -static inline char *find_flat_dt_string(u32 offset) -{ - return ((char *)initial_boot_params) + - initial_boot_params->off_dt_strings + offset; -} - /** * This function is used to scan the flattened device-tree, it is * used to extract the memory informations at boot before we can diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index d2fa27c5c1b2..462825e03123 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,3 +1,7 @@ +config OF_FLATTREE + bool + depends on OF + config OF_DEVICE def_bool y depends on OF && (SPARC || PPC_OF || MICROBLAZE) diff --git a/drivers/of/Makefile b/drivers/of/Makefile index bdfb5f5d4b06..f232cc98ce00 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,4 +1,5 @@ obj-y = base.o +obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c new file mode 100644 index 000000000000..9faa9a5cbdf0 --- /dev/null +++ b/drivers/of/fdt.c @@ -0,0 +1,21 @@ +/* + * Functions for working with the Flattened Device Tree data format + * + * Copyright 2009 Benjamin Herrenschmidt, IBM Corp + * benh@kernel.crashing.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include + +struct boot_param_header *initial_boot_params; + +char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + + initial_boot_params->off_dt_strings + offset; +} diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 41d432b13553..d1a79f3da789 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -57,7 +57,11 @@ struct boot_param_header { u32 dt_struct_size; /* size of the DT structure block */ }; +/* TBD: Temporary export of fdt globals - remove when code fully merged */ +extern struct boot_param_header *initial_boot_params; + /* For scanning the flat device-tree at boot time */ +extern char *find_flat_dt_string(u32 offset); extern int __init of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, int depth, void *data), -- GitLab From c8cb7a59842c0b512b44f6f818cdb0b5a3ddc89e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 18:54:23 -0700 Subject: [PATCH 0008/3892] of/flattree: merge of_scan_flat_dt Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 61 --------------------------------- arch/powerpc/kernel/prom.c | 61 --------------------------------- drivers/of/fdt.c | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 122 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 06d620ab4168..0db8ee64ffe6 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,67 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -/** - * This function is used to scan the flattened device-tree, it is - * used to extract the memory informations at boot before we can - * unflatten the tree - */ -int __init of_scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - int rc = 0; - int depth = -1; - - do { - u32 tag = *((u32 *)p); - char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth--; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = *((u32 *)p); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = _ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - printk(KERN_WARNING "Invalid tag %x scanning flattened" - " device tree !\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = _ALIGN(p + strlen(pathp) + 1, 4); - if ((*pathp) == '/') { - char *lp, *np; - for (lp = NULL, np = pathp; *np; np++) - if ((*np) == '/') - lp = np+1; - if (lp != NULL) - pathp = lp; - } - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while (1); - - return rc; -} - unsigned long __init of_get_flat_dt_root(void) { unsigned long p = ((unsigned long)initial_boot_params) + diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fccf7e49bb28..14a07b9e00d1 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -80,67 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -/** - * This function is used to scan the flattened device-tree, it is - * used to extract the memory informations at boot before we can - * unflatten the tree - */ -int __init of_scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - int rc = 0; - int depth = -1; - - do { - u32 tag = *((u32 *)p); - char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth --; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = *((u32 *)p); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = _ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - printk(KERN_WARNING "Invalid tag %x scanning flattened" - " device tree !\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = _ALIGN(p + strlen(pathp) + 1, 4); - if ((*pathp) == '/') { - char *lp, *np; - for (lp = NULL, np = pathp; *np; np++) - if ((*np) == '/') - lp = np+1; - if (lp != NULL) - pathp = lp; - } - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while(1); - - return rc; -} - unsigned long __init of_get_flat_dt_root(void) { unsigned long p = ((unsigned long)initial_boot_params) + diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9faa9a5cbdf0..dd9057cb7aa7 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -19,3 +19,67 @@ char *find_flat_dt_string(u32 offset) return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + offset; } + +/** + * of_scan_flat_dt - scan flattened tree blob and call callback on each. + * @it: callback function + * @data: context data pointer + * + * This function is used to scan the flattened device-tree, it is + * used to extract the memory information at boot before we can + * unflatten the tree + */ +int __init of_scan_flat_dt(int (*it)(unsigned long node, + const char *uname, int depth, + void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + int depth = -1; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) { + depth--; + continue; + } + if (tag == OF_DT_NOP) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Invalid tag %x in flat device tree!\n", tag); + return -EINVAL; + } + depth++; + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); + if (rc != 0) + break; + } while (1); + + return rc; +} -- GitLab From 819d2819303654c6829d572e698e2d0021c08599 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 19:44:23 -0700 Subject: [PATCH 0009/3892] of/flattree: merge of_get_flat_dt_root Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 12 ------------ arch/powerpc/kernel/prom.c | 12 ------------ drivers/of/fdt.c | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 0db8ee64ffe6..7eb6f8bdb81a 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,18 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -unsigned long __init of_get_flat_dt_root(void) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - - while (*((u32 *)p) == OF_DT_NOP) - p += 4; - BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); - p += 4; - return _ALIGN(p + strlen((char *)p) + 1, 4); -} - /** * This function can be used within scan_flattened_dt callback to get * access to properties diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 14a07b9e00d1..b5d5f85e9c2c 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -80,18 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -unsigned long __init of_get_flat_dt_root(void) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - - while(*((u32 *)p) == OF_DT_NOP) - p += 4; - BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE); - p += 4; - return _ALIGN(p + strlen((char *)p) + 1, 4); -} - /** * This function can be used within scan_flattened_dt callback to get * access to properties diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index dd9057cb7aa7..f41d739aa2f7 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -83,3 +83,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, return rc; } + +/** + * of_get_flat_dt_root - find the root node in the flat blob + */ +unsigned long __init of_get_flat_dt_root(void) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + + while (*((u32 *)p) == OF_DT_NOP) + p += 4; + BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); + p += 4; + return _ALIGN(p + strlen((char *)p) + 1, 4); +} + -- GitLab From 31a6a87dfc34fbf02aef9a160adf558ec56d3ccd Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 19:49:38 -0700 Subject: [PATCH 0010/3892] of/flattree: remove __init annotations from the header file __init annotation belongs in the .c file, not the header. Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- include/linux/of_fdt.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index d1a79f3da789..81231e04e8f3 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -62,15 +62,13 @@ extern struct boot_param_header *initial_boot_params; /* For scanning the flat device-tree at boot time */ extern char *find_flat_dt_string(u32 offset); -extern int __init of_scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data); -extern void __init *of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size); -extern int __init of_flat_dt_is_compatible(unsigned long node, - const char *name); -extern unsigned long __init of_get_flat_dt_root(void); +extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, + int depth, void *data), + void *data); +extern void *of_get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size); +extern int of_flat_dt_is_compatible(unsigned long node, const char *name); +extern unsigned long of_get_flat_dt_root(void); /* Other Prototypes */ extern void finish_device_tree(void); -- GitLab From ca900cfa2944448bdb76e1246f282e59bc65f472 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:06:59 -0700 Subject: [PATCH 0011/3892] of/flattree: merge of_get_flat_dt_prop Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 42 ---------------------------------- arch/powerpc/kernel/prom.c | 42 ---------------------------------- drivers/of/fdt.c | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 84 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 7eb6f8bdb81a..d75c6253c0de 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,48 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -/** - * This function can be used within scan_flattened_dt callback to get - * access to properties - */ -void *__init of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) -{ - unsigned long p = node; - - do { - u32 tag = *((u32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = *((u32 *)p); - noff = *((u32 *)(p + 4)); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = find_flat_dt_string(noff); - if (nstr == NULL) { - printk(KERN_WARNING "Can't find property index" - " name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = _ALIGN(p, 4); - } while (1); -} - int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) { const char *cp; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index b5d5f85e9c2c..cd0a2bfc978b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -80,48 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -/** - * This function can be used within scan_flattened_dt callback to get - * access to properties - */ -void* __init of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) -{ - unsigned long p = node; - - do { - u32 tag = *((u32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = *((u32 *)p); - noff = *((u32 *)(p + 4)); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = find_flat_dt_string(noff); - if (nstr == NULL) { - printk(KERN_WARNING "Can't find property index" - " name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = _ALIGN(p, 4); - } while(1); -} - int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) { const char* cp; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index f41d739aa2f7..b17a9086cbfc 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -99,3 +99,46 @@ unsigned long __init of_get_flat_dt_root(void) return _ALIGN(p + strlen((char *)p) + 1, 4); } +/** + * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr + * + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +void *__init of_get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag == OF_DT_NOP) + continue; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + if (initial_boot_params->version < 0x10) + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + pr_warning("Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while (1); +} + -- GitLab From 00e38efd90f27518ec96b37b1c7773e3ac529966 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:00 -0700 Subject: [PATCH 0012/3892] of/flattree: Merge of_flat_dt_is_compatible Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 19 ------------------- arch/powerpc/kernel/prom.c | 19 ------------------- drivers/of/fdt.c | 24 ++++++++++++++++++++++++ 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index d75c6253c0de..eb27bd3a39b4 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,25 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) -{ - const char *cp; - unsigned long cplen, l; - - cp = of_get_flat_dt_prop(node, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (strncasecmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} - static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index cd0a2bfc978b..413e608863dd 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -80,25 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) -{ - const char* cp; - unsigned long cplen, l; - - cp = of_get_flat_dt_prop(node, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (strncasecmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} - static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b17a9086cbfc..5cdd958db9af 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -142,3 +142,27 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, } while (1); } +/** + * of_flat_dt_is_compatible - Return true if given node has compat in compatible list + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +{ + const char *cp; + unsigned long cplen, l; + + cp = of_get_flat_dt_prop(node, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncasecmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + -- GitLab From bbd33931a08362f78266a4016211a35947b91041 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:00 -0700 Subject: [PATCH 0013/3892] of/flattree: Merge unflatten_dt_node Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 195 --------------------------------- arch/powerpc/kernel/prom.c | 194 --------------------------------- drivers/of/fdt.c | 200 ++++++++++++++++++++++++++++++++++ include/linux/of_fdt.h | 4 + 4 files changed, 204 insertions(+), 389 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index eb27bd3a39b4..021770abfbd7 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,201 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, - unsigned long align) -{ - void *res; - - *mem = _ALIGN(*mem, align); - res = (void *)*mem; - *mem += size; - - return res; -} - -static unsigned long __init unflatten_dt_node(unsigned long mem, - unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) -{ - struct device_node *np; - struct property *pp, **prev_pp = NULL; - char *pathp; - u32 tag; - unsigned int l, allocl; - int has_name = 0; - int new_format = 0; - - tag = *((u32 *)(*p)); - if (tag != OF_DT_BEGIN_NODE) { - printk("Weird tag at start of node: %x\n", tag); - return mem; - } - *p += 4; - pathp = (char *)*p; - l = allocl = strlen(pathp) + 1; - *p = _ALIGN(*p + l, 4); - - /* version 0x10 has a more compact unit name here instead of the full - * path. we accumulate the full path size using "fpsize", we'll rebuild - * it later. We detect this because the first character of the name is - * not '/'. - */ - if ((*pathp) != '/') { - new_format = 1; - if (fpsize == 0) { - /* root node: special case. fpsize accounts for path - * plus terminating zero. root node only has '/', so - * fpsize should be 2, but we want to avoid the first - * level nodes to have two '/' so we use fpsize 1 here - */ - fpsize = 1; - allocl = 2; - } else { - /* account for '/' and path size minus terminal 0 - * already in 'l' - */ - fpsize += l; - allocl = fpsize; - } - } - - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, - __alignof__(struct device_node)); - if (allnextpp) { - memset(np, 0, sizeof(*np)); - np->full_name = ((char *)np) + sizeof(struct device_node); - if (new_format) { - char *p2 = np->full_name; - /* rebuild full path for new format */ - if (dad && dad->parent) { - strcpy(p2, dad->full_name); -#ifdef DEBUG - if ((strlen(p2) + l + 1) != allocl) { - pr_debug("%s: p: %d, l: %d, a: %d\n", - pathp, (int)strlen(p2), - l, allocl); - } -#endif - p2 += strlen(p2); - } - *(p2++) = '/'; - memcpy(p2, pathp, l); - } else - memcpy(np->full_name, pathp, l); - prev_pp = &np->properties; - **allnextpp = np; - *allnextpp = &np->allnext; - if (dad != NULL) { - np->parent = dad; - /* we temporarily use the next field as `last_child'*/ - if (dad->next == NULL) - dad->child = np; - else - dad->next->sibling = np; - dad->next = np; - } - kref_init(&np->kref); - } - while (1) { - u32 sz, noff; - char *pname; - - tag = *((u32 *)(*p)); - if (tag == OF_DT_NOP) { - *p += 4; - continue; - } - if (tag != OF_DT_PROP) - break; - *p += 4; - sz = *((u32 *)(*p)); - noff = *((u32 *)((*p) + 4)); - *p += 8; - if (initial_boot_params->version < 0x10) - *p = _ALIGN(*p, sz >= 8 ? 8 : 4); - - pname = find_flat_dt_string(noff); - if (pname == NULL) { - printk(KERN_INFO - "Can't find property name in list !\n"); - break; - } - if (strcmp(pname, "name") == 0) - has_name = 1; - l = strlen(pname) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property), - __alignof__(struct property)); - if (allnextpp) { - if (strcmp(pname, "linux,phandle") == 0) { - np->node = *((u32 *)*p); - if (np->linux_phandle == 0) - np->linux_phandle = np->node; - } - if (strcmp(pname, "ibm,phandle") == 0) - np->linux_phandle = *((u32 *)*p); - pp->name = pname; - pp->length = sz; - pp->value = (void *)*p; - *prev_pp = pp; - prev_pp = &pp->next; - } - *p = _ALIGN((*p) + sz, 4); - } - /* with version 0x10 we may not have the name property, recreate - * it here from the unit name if absent - */ - if (!has_name) { - char *p1 = pathp, *ps = pathp, *pa = NULL; - int sz; - - while (*p1) { - if ((*p1) == '@') - pa = p1; - if ((*p1) == '/') - ps = p1 + 1; - p1++; - } - if (pa < ps) - pa = p1; - sz = (pa - ps) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, - __alignof__(struct property)); - if (allnextpp) { - pp->name = "name"; - pp->length = sz; - pp->value = pp + 1; - *prev_pp = pp; - prev_pp = &pp->next; - memcpy(pp->value, ps, sz - 1); - ((char *)pp->value)[sz - 1] = 0; - pr_debug("fixed up name for %s -> %s\n", pathp, - (char *)pp->value); - } - } - if (allnextpp) { - *prev_pp = NULL; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - } - while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); - tag = *((u32 *)(*p)); - } - if (tag != OF_DT_END_NODE) { - printk(KERN_INFO "Weird tag at end of node: %x\n", tag); - return mem; - } - *p += 4; - return mem; -} - /** * unflattens the device-tree passed by the firmware, creating the * tree of struct device_node. It also fills the "name" and "type" diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 413e608863dd..a102a0a33ed1 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -80,200 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ struct device_node *of_chosen; -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, - unsigned long align) -{ - void *res; - - *mem = _ALIGN(*mem, align); - res = (void *)*mem; - *mem += size; - - return res; -} - -static unsigned long __init unflatten_dt_node(unsigned long mem, - unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) -{ - struct device_node *np; - struct property *pp, **prev_pp = NULL; - char *pathp; - u32 tag; - unsigned int l, allocl; - int has_name = 0; - int new_format = 0; - - tag = *((u32 *)(*p)); - if (tag != OF_DT_BEGIN_NODE) { - printk("Weird tag at start of node: %x\n", tag); - return mem; - } - *p += 4; - pathp = (char *)*p; - l = allocl = strlen(pathp) + 1; - *p = _ALIGN(*p + l, 4); - - /* version 0x10 has a more compact unit name here instead of the full - * path. we accumulate the full path size using "fpsize", we'll rebuild - * it later. We detect this because the first character of the name is - * not '/'. - */ - if ((*pathp) != '/') { - new_format = 1; - if (fpsize == 0) { - /* root node: special case. fpsize accounts for path - * plus terminating zero. root node only has '/', so - * fpsize should be 2, but we want to avoid the first - * level nodes to have two '/' so we use fpsize 1 here - */ - fpsize = 1; - allocl = 2; - } else { - /* account for '/' and path size minus terminal 0 - * already in 'l' - */ - fpsize += l; - allocl = fpsize; - } - } - - - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, - __alignof__(struct device_node)); - if (allnextpp) { - memset(np, 0, sizeof(*np)); - np->full_name = ((char*)np) + sizeof(struct device_node); - if (new_format) { - char *p = np->full_name; - /* rebuild full path for new format */ - if (dad && dad->parent) { - strcpy(p, dad->full_name); -#ifdef DEBUG - if ((strlen(p) + l + 1) != allocl) { - DBG("%s: p: %d, l: %d, a: %d\n", - pathp, (int)strlen(p), l, allocl); - } -#endif - p += strlen(p); - } - *(p++) = '/'; - memcpy(p, pathp, l); - } else - memcpy(np->full_name, pathp, l); - prev_pp = &np->properties; - **allnextpp = np; - *allnextpp = &np->allnext; - if (dad != NULL) { - np->parent = dad; - /* we temporarily use the next field as `last_child'*/ - if (dad->next == 0) - dad->child = np; - else - dad->next->sibling = np; - dad->next = np; - } - kref_init(&np->kref); - } - while(1) { - u32 sz, noff; - char *pname; - - tag = *((u32 *)(*p)); - if (tag == OF_DT_NOP) { - *p += 4; - continue; - } - if (tag != OF_DT_PROP) - break; - *p += 4; - sz = *((u32 *)(*p)); - noff = *((u32 *)((*p) + 4)); - *p += 8; - if (initial_boot_params->version < 0x10) - *p = _ALIGN(*p, sz >= 8 ? 8 : 4); - - pname = find_flat_dt_string(noff); - if (pname == NULL) { - printk("Can't find property name in list !\n"); - break; - } - if (strcmp(pname, "name") == 0) - has_name = 1; - l = strlen(pname) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property), - __alignof__(struct property)); - if (allnextpp) { - if (strcmp(pname, "linux,phandle") == 0) { - np->node = *((u32 *)*p); - if (np->linux_phandle == 0) - np->linux_phandle = np->node; - } - if (strcmp(pname, "ibm,phandle") == 0) - np->linux_phandle = *((u32 *)*p); - pp->name = pname; - pp->length = sz; - pp->value = (void *)*p; - *prev_pp = pp; - prev_pp = &pp->next; - } - *p = _ALIGN((*p) + sz, 4); - } - /* with version 0x10 we may not have the name property, recreate - * it here from the unit name if absent - */ - if (!has_name) { - char *p = pathp, *ps = pathp, *pa = NULL; - int sz; - - while (*p) { - if ((*p) == '@') - pa = p; - if ((*p) == '/') - ps = p + 1; - p++; - } - if (pa < ps) - pa = p; - sz = (pa - ps) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, - __alignof__(struct property)); - if (allnextpp) { - pp->name = "name"; - pp->length = sz; - pp->value = pp + 1; - *prev_pp = pp; - prev_pp = &pp->next; - memcpy(pp->value, ps, sz - 1); - ((char *)pp->value)[sz - 1] = 0; - DBG("fixed up name for %s -> %s\n", pathp, - (char *)pp->value); - } - } - if (allnextpp) { - *prev_pp = NULL; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - } - while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); - tag = *((u32 *)(*p)); - } - if (tag != OF_DT_END_NODE) { - printk("Weird tag at end of node: %x\n", tag); - return mem; - } - *p += 4; - return mem; -} - static int __init early_parse_mem(char *p) { if (!p) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 5cdd958db9af..6852ecf6d1e1 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -166,3 +166,203 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return 0; } +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +/** + * unflatten_dt_node - Alloc and populate a device_node from the flat tree + * @p: pointer to node in flat tree + * @dad: Parent struct device_node + * @allnextpp: pointer to ->allnext from last allocated device_node + * @fpsize: Size of the node path up at the current depth. + */ +unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = allocl = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we'll rebuild + * it later. We detect this because the first character of the name is + * not '/'. + */ + if ((*pathp) != '/') { + new_format = 1; + if (fpsize == 0) { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has '/', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two '/' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } else { + /* account for '/' and path size minus terminal 0 + * already in 'l' + */ + fpsize += l; + allocl = fpsize; + } + } + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char *)np) + sizeof(struct device_node); + if (new_format) { + char *fn = np->full_name; + /* rebuild full path for new format */ + if (dad && dad->parent) { + strcpy(fn, dad->full_name); +#ifdef DEBUG + if ((strlen(fn) + l + 1) != allocl) { + pr_debug("%s: p: %d, l: %d, a: %d\n", + pathp, (int)strlen(fn), + l, allocl); + } +#endif + fn += strlen(fn); + } + *(fn++) = '/'; + memcpy(fn, pathp, l); + } else + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the next field as `last_child'*/ + if (dad->next == NULL) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + kref_init(&np->kref); + } + while (1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag == OF_DT_NOP) { + *p += 4; + continue; + } + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p += 8; + if (initial_boot_params->version < 0x10) + *p = _ALIGN(*p, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + pr_info("Can't find property name in list !\n"); + break; + } + if (strcmp(pname, "name") == 0) + has_name = 1; + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if (!has_name) { + char *p1 = pathp, *ps = pathp, *pa = NULL; + int sz; + + while (*p1) { + if ((*p1) == '@') + pa = p1; + if ((*p1) == '/') + ps = p1 + 1; + p1++; + } + if (pa < ps) + pa = p1; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, + __alignof__(struct property)); + if (allnextpp) { + pp->name = "name"; + pp->length = sz; + pp->value = pp + 1; + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + pr_debug("fixed up name for %s -> %s\n", pathp, + (char *)pp->value); + } + } + if (allnextpp) { + *prev_pp = NULL; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + pr_err("Weird tag at end of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 81231e04e8f3..ace9068e07e8 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -69,6 +69,10 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); +extern unsigned long unflatten_dt_node(unsigned long mem, unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize); /* Other Prototypes */ extern void finish_device_tree(void); -- GitLab From 41f880091c15b039ffcc8b3d831656b81517a6d3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:07:01 -0700 Subject: [PATCH 0014/3892] of/flattree: Merge unflatten_device_tree Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/include/asm/prom.h | 1 - arch/microblaze/kernel/prom.c | 49 ---------------------------- arch/powerpc/kernel/prom.c | 50 ---------------------------- drivers/of/fdt.c | 52 ++++++++++++++++++++++++++++++ include/linux/of.h | 3 ++ include/linux/of_fdt.h | 4 --- 6 files changed, 55 insertions(+), 104 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index ef3ec1d6ceb3..07d1063f9aae 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -37,7 +37,6 @@ extern struct device_node *of_chosen; #define HAVE_ARCH_DEVTREE_FIXUPS -extern struct device_node *allnodes; /* temporary while merging */ extern rwlock_t devtree_lock; /* temporary while merging */ /* For updating the device tree at runtime */ diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 021770abfbd7..901d538c15ef 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -50,55 +50,6 @@ typedef u32 cell_t; /* export that to outside world */ struct device_node *of_chosen; -/** - * unflattens the device-tree passed by the firmware, creating the - * tree of struct device_node. It also fills the "name" and "type" - * pointers of the nodes so the normal device-tree walking functions - * can be used (this used to be done by finish_device_tree) - */ -void __init unflatten_device_tree(void) -{ - unsigned long start, mem, size; - struct device_node **allnextp = &allnodes; - - pr_debug(" -> unflatten_device_tree()\n"); - - /* First pass, scan for size */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - size = unflatten_dt_node(0, &start, NULL, NULL, 0); - size = (size | 3) + 1; - - pr_debug(" size is %lx, allocating...\n", size); - - /* Allocate memory for the expanded device tree */ - mem = lmb_alloc(size + 4, __alignof__(struct device_node)); - mem = (unsigned long) __va(mem); - - ((u32 *)mem)[size / 4] = 0xdeadbeef; - - pr_debug(" unflattening %lx...\n", mem); - - /* Second pass, do actual unflattening */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - unflatten_dt_node(mem, &start, NULL, &allnextp, 0); - if (*((u32 *)start) != OF_DT_END) - printk(KERN_WARNING "Weird tag at end of tree: %08x\n", - *((u32 *)start)); - if (((u32 *)mem)[size / 4] != 0xdeadbeef) - printk(KERN_WARNING "End of tree marker overwritten: %08x\n", - ((u32 *)mem)[size / 4]); - *allnextp = NULL; - - /* Get pointer to OF "/chosen" node for use everywhere */ - of_chosen = of_find_node_by_path("/chosen"); - if (of_chosen == NULL) - of_chosen = of_find_node_by_path("/chosen@0"); - - pr_debug(" <- unflatten_device_tree()\n"); -} - #define early_init_dt_scan_drconf_memory(node) 0 static int __init early_init_dt_scan_cpus(unsigned long node, diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index a102a0a33ed1..1280f3484ad3 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -73,8 +73,6 @@ unsigned long tce_alloc_start, tce_alloc_end; typedef u32 cell_t; -extern struct device_node *allnodes; /* temporary while merging */ - extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ @@ -119,54 +117,6 @@ static void __init move_device_tree(void) DBG("<- move_device_tree\n"); } -/** - * unflattens the device-tree passed by the firmware, creating the - * tree of struct device_node. It also fills the "name" and "type" - * pointers of the nodes so the normal device-tree walking functions - * can be used (this used to be done by finish_device_tree) - */ -void __init unflatten_device_tree(void) -{ - unsigned long start, mem, size; - struct device_node **allnextp = &allnodes; - - DBG(" -> unflatten_device_tree()\n"); - - /* First pass, scan for size */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - size = unflatten_dt_node(0, &start, NULL, NULL, 0); - size = (size | 3) + 1; - - DBG(" size is %lx, allocating...\n", size); - - /* Allocate memory for the expanded device tree */ - mem = lmb_alloc(size + 4, __alignof__(struct device_node)); - mem = (unsigned long) __va(mem); - - ((u32 *)mem)[size / 4] = 0xdeadbeef; - - DBG(" unflattening %lx...\n", mem); - - /* Second pass, do actual unflattening */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - unflatten_dt_node(mem, &start, NULL, &allnextp, 0); - if (*((u32 *)start) != OF_DT_END) - printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (((u32 *)mem)[size / 4] != 0xdeadbeef) - printk(KERN_WARNING "End of tree marker overwritten: %08x\n", - ((u32 *)mem)[size / 4] ); - *allnextp = NULL; - - /* Get pointer to OF "/chosen" node for use everywhere */ - of_chosen = of_find_node_by_path("/chosen"); - if (of_chosen == NULL) - of_chosen = of_find_node_by_path("/chosen@0"); - - DBG(" <- unflatten_device_tree()\n"); -} - /* * ibm,pa-features is a per-cpu property that contains a string of * attribute descriptors, each of which has a 2 byte header plus up diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6852ecf6d1e1..43d236cbc17b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -9,6 +9,8 @@ * version 2 as published by the Free Software Foundation. */ +#include +#include #include #include @@ -366,3 +368,53 @@ unsigned long __init unflatten_dt_node(unsigned long mem, *p += 4; return mem; } + +/** + * unflatten_device_tree - create tree of device_nodes from flat blob + * + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + + pr_debug(" -> unflatten_device_tree()\n"); + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + pr_debug(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = lmb_alloc(size + 4, __alignof__(struct device_node)); + mem = (unsigned long) __va(mem); + + ((u32 *)mem)[size / 4] = 0xdeadbeef; + + pr_debug(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp, 0); + if (*((u32 *)start) != OF_DT_END) + pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (((u32 *)mem)[size / 4] != 0xdeadbeef) + pr_warning("End of tree marker overwritten: %08x\n", + ((u32 *)mem)[size / 4]); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + if (of_chosen == NULL) + of_chosen = of_find_node_by_path("/chosen@0"); + + pr_debug(" <- unflatten_device_tree()\n"); +} diff --git a/include/linux/of.h b/include/linux/of.h index e7facd8fbce8..bec215792c4f 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -63,6 +63,9 @@ struct device_node { #endif }; +/* Pointer for first entry in chain of all nodes. */ +extern struct device_node *allnodes; + static inline int of_node_check_flag(struct device_node *n, unsigned long flag) { return test_bit(flag, &n->_flags); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index ace9068e07e8..81231e04e8f3 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -69,10 +69,6 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); -extern unsigned long unflatten_dt_node(unsigned long mem, unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize); /* Other Prototypes */ extern void finish_device_tree(void); -- GitLab From 02af11b03fce3ddb264d7873d7a2e295e697938c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:16:45 -0700 Subject: [PATCH 0015/3892] of: merge prom_{add,remove,modify}_property Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- arch/microblaze/kernel/prom.c | 113 --------------------------------- arch/powerpc/kernel/prom.c | 114 --------------------------------- drivers/of/base.c | 116 ++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 227 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 901d538c15ef..a38e3733a09c 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -606,119 +606,6 @@ out_unlock: write_unlock_irqrestore(&devtree_lock, flags); } -/* - * Add a property to a node - */ -int prom_add_property(struct device_node *np, struct property *prop) -{ - struct property **next; - unsigned long flags; - - prop->next = NULL; - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (strcmp(prop->name, (*next)->name) == 0) { - /* duplicate ! don't insert it */ - write_unlock_irqrestore(&devtree_lock, flags); - return -1; - } - next = &(*next)->next; - } - *next = prop; - write_unlock_irqrestore(&devtree_lock, flags); - -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_add_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - -/* - * Remove a property from a node. Note that we don't actually - * remove it, since we have given out who-knows-how-many pointers - * to the data using get-property. Instead we just move the property - * to the "dead properties" list, so it won't be found any more. - */ -int prom_remove_property(struct device_node *np, struct property *prop) -{ - struct property **next; - unsigned long flags; - int found = 0; - - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (*next == prop) { - /* found the node */ - *next = prop->next; - prop->next = np->deadprops; - np->deadprops = prop; - found = 1; - break; - } - next = &(*next)->next; - } - write_unlock_irqrestore(&devtree_lock, flags); - - if (!found) - return -ENODEV; - -#ifdef CONFIG_PROC_DEVICETREE - /* try to remove the proc node as well */ - if (np->pde) - proc_device_tree_remove_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - -/* - * Update a property in a node. Note that we don't actually - * remove it, since we have given out who-knows-how-many pointers - * to the data using get-property. Instead we just move the property - * to the "dead properties" list, and add the new property to the - * property list - */ -int prom_update_property(struct device_node *np, - struct property *newprop, - struct property *oldprop) -{ - struct property **next; - unsigned long flags; - int found = 0; - - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (*next == oldprop) { - /* found the node */ - newprop->next = oldprop->next; - *next = newprop; - oldprop->next = np->deadprops; - np->deadprops = oldprop; - found = 1; - break; - } - next = &(*next)->next; - } - write_unlock_irqrestore(&devtree_lock, flags); - - if (!found) - return -ENODEV; - -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_update_prop(np->pde, newprop, oldprop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) static struct debugfs_blob_wrapper flat_dt_blob; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1280f3484ad3..7f8856655144 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1130,120 +1130,6 @@ static int __init prom_reconfig_setup(void) __initcall(prom_reconfig_setup); #endif -/* - * Add a property to a node - */ -int prom_add_property(struct device_node* np, struct property* prop) -{ - struct property **next; - unsigned long flags; - - prop->next = NULL; - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (strcmp(prop->name, (*next)->name) == 0) { - /* duplicate ! don't insert it */ - write_unlock_irqrestore(&devtree_lock, flags); - return -1; - } - next = &(*next)->next; - } - *next = prop; - write_unlock_irqrestore(&devtree_lock, flags); - -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_add_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - -/* - * Remove a property from a node. Note that we don't actually - * remove it, since we have given out who-knows-how-many pointers - * to the data using get-property. Instead we just move the property - * to the "dead properties" list, so it won't be found any more. - */ -int prom_remove_property(struct device_node *np, struct property *prop) -{ - struct property **next; - unsigned long flags; - int found = 0; - - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (*next == prop) { - /* found the node */ - *next = prop->next; - prop->next = np->deadprops; - np->deadprops = prop; - found = 1; - break; - } - next = &(*next)->next; - } - write_unlock_irqrestore(&devtree_lock, flags); - - if (!found) - return -ENODEV; - -#ifdef CONFIG_PROC_DEVICETREE - /* try to remove the proc node as well */ - if (np->pde) - proc_device_tree_remove_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - -/* - * Update a property in a node. Note that we don't actually - * remove it, since we have given out who-knows-how-many pointers - * to the data using get-property. Instead we just move the property - * to the "dead properties" list, and add the new property to the - * property list - */ -int prom_update_property(struct device_node *np, - struct property *newprop, - struct property *oldprop) -{ - struct property **next; - unsigned long flags; - int found = 0; - - write_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (*next == oldprop) { - /* found the node */ - newprop->next = oldprop->next; - *next = newprop; - oldprop->next = np->deadprops; - np->deadprops = oldprop; - found = 1; - break; - } - next = &(*next)->next; - } - write_unlock_irqrestore(&devtree_lock, flags); - - if (!found) - return -ENODEV; - -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_update_prop(np->pde, newprop, oldprop); -#endif /* CONFIG_PROC_DEVICETREE */ - - return 0; -} - - /* Find the device node for a given logical cpu number, also returns the cpu * local thread number (index in ibm,interrupt-server#s) if relevant and * asked for (non NULL) diff --git a/drivers/of/base.c b/drivers/of/base.c index e6627b2320f1..ec56739eb247 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -658,3 +658,119 @@ err0: return ret; } EXPORT_SYMBOL(of_parse_phandles_with_args); + +/** + * prom_add_property - Add a property to a node + */ +int prom_add_property(struct device_node *np, struct property *prop) +{ + struct property **next; + unsigned long flags; + + prop->next = NULL; + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (strcmp(prop->name, (*next)->name) == 0) { + /* duplicate ! don't insert it */ + write_unlock_irqrestore(&devtree_lock, flags); + return -1; + } + next = &(*next)->next; + } + *next = prop; + write_unlock_irqrestore(&devtree_lock, flags); + +#ifdef CONFIG_PROC_DEVICETREE + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_add_prop(np->pde, prop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} + +/** + * prom_remove_property - Remove a property from a node. + * + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" + * list, so it won't be found any more. + */ +int prom_remove_property(struct device_node *np, struct property *prop) +{ + struct property **next; + unsigned long flags; + int found = 0; + + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (*next == prop) { + /* found the node */ + *next = prop->next; + prop->next = np->deadprops; + np->deadprops = prop; + found = 1; + break; + } + next = &(*next)->next; + } + write_unlock_irqrestore(&devtree_lock, flags); + + if (!found) + return -ENODEV; + +#ifdef CONFIG_PROC_DEVICETREE + /* try to remove the proc node as well */ + if (np->pde) + proc_device_tree_remove_prop(np->pde, prop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} + +/* + * prom_update_property - Update a property in a node. + * + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" list, + * and add the new property to the property list + */ +int prom_update_property(struct device_node *np, + struct property *newprop, + struct property *oldprop) +{ + struct property **next; + unsigned long flags; + int found = 0; + + write_lock_irqsave(&devtree_lock, flags); + next = &np->properties; + while (*next) { + if (*next == oldprop) { + /* found the node */ + newprop->next = oldprop->next; + *next = newprop; + oldprop->next = np->deadprops; + np->deadprops = oldprop; + found = 1; + break; + } + next = &(*next)->next; + } + write_unlock_irqrestore(&devtree_lock, flags); + + if (!found) + return -ENODEV; + +#ifdef CONFIG_PROC_DEVICETREE + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_update_prop(np->pde, newprop, oldprop); +#endif /* CONFIG_PROC_DEVICETREE */ + + return 0; +} -- GitLab From 2be09cb993826b52c9fc1d44747c20dd43a50038 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 23 Nov 2009 20:16:46 -0700 Subject: [PATCH 0016/3892] of: remove special case definition of of_read_ulong() Special case of of_read_ulong() was defined for PPC32 to toss away all but the last 32 bits when a large number value was read, and the 'normal' version for ppc64 just #defined of_read_ulong to of_read_number which causes compiler warnings on MicroBlaze and other 32 bit architectures because it returns a u64 instead of a ulong. This patch fixes the problem by defining a common implementation of of_read_ulong() that works everywhere. Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Tested-by: Michal Simek --- include/linux/of.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/of.h b/include/linux/of.h index bec215792c4f..d4c014a35ea5 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -113,14 +113,11 @@ static inline u64 of_read_number(const u32 *cell, int size) } /* Like of_read_number, but we want an unsigned long result */ -#ifdef CONFIG_PPC32 static inline unsigned long of_read_ulong(const u32 *cell, int size) { - return cell[size-1]; + /* toss away upper bits if unsigned long is smaller than u64 */ + return of_read_number(cell, size); } -#else -#define of_read_ulong(cell, size) of_read_number(cell, size) -#endif #include -- GitLab From 71f6e0645be42f93c0f90dfcc93b9d2d277c2ee6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Dec 2009 15:11:08 +0900 Subject: [PATCH 0017/3892] ASoC: sh_fsi: avoid using global variable Current FSI driver use global variable to access device data. But this style will be broken if SuperH come with multiple FSI blocks in future. To solve this problem, this patch use cpu_dai->private_data. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 115 ++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9c49c11c43ce..7506ef6d287a 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -92,6 +92,7 @@ struct fsi_priv { void __iomem *base; struct snd_pcm_substream *substream; + struct fsi_master *master; int fifo_max; int chan; @@ -110,8 +111,6 @@ struct fsi_master { struct sh_fsi_platform_info *info; }; -static struct fsi_master *master; - /************************************************************************ @@ -166,7 +165,7 @@ static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); } -static int fsi_master_write(u32 reg, u32 data) +static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -175,7 +174,7 @@ static int fsi_master_write(u32 reg, u32 data) return __fsi_reg_write((u32)(master->base + reg), data); } -static u32 fsi_master_read(u32 reg) +static u32 fsi_master_read(struct fsi_master *master, u32 reg) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -184,7 +183,8 @@ static u32 fsi_master_read(u32 reg) return __fsi_reg_read((u32)(master->base + reg)); } -static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) +static int fsi_master_mask_set(struct fsi_master *master, + u32 reg, u32 mask, u32 data) { if ((reg < MREG_START) || (reg > MREG_END)) @@ -200,43 +200,29 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) ************************************************************************/ -static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) +static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) { - struct snd_soc_pcm_runtime *rtd; - struct fsi_priv *fsi = NULL; - - if (!substream || !master) - return NULL; - - rtd = substream->private_data; - switch (rtd->dai->cpu_dai->id) { - case 0: - fsi = &master->fsia; - break; - case 1: - fsi = &master->fsib; - break; - } - - return fsi; + return fsi->master; } static int fsi_is_port_a(struct fsi_priv *fsi) { - /* return - * 1 : port a - * 0 : port b - */ + return fsi->master->base == fsi->base; +} - if (fsi == &master->fsia) - return 1; +static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *dai = machine->cpu_dai; - return 0; + return dai->private_data; } static u32 fsi_get_info_flags(struct fsi_priv *fsi) { int is_porta = fsi_is_port_a(fsi); + struct fsi_master *master = fsi_get_master(fsi); return is_porta ? master->info->porta_flags : master->info->portb_flags; @@ -314,27 +300,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) { u32 data = fsi_port_ab_io_bit(fsi, is_play); + struct fsi_master *master = fsi_get_master(fsi); - fsi_master_mask_set(IMSK, data, data); - fsi_master_mask_set(IEMSK, data, data); + fsi_master_mask_set(master, IMSK, data, data); + fsi_master_mask_set(master, IEMSK, data, data); } static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) { u32 data = fsi_port_ab_io_bit(fsi, is_play); + struct fsi_master *master = fsi_get_master(fsi); - fsi_master_mask_set(IMSK, data, 0); - fsi_master_mask_set(IEMSK, data, 0); + fsi_master_mask_set(master, IMSK, data, 0); + fsi_master_mask_set(master, IEMSK, data, 0); } static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) { u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); + struct fsi_master *master = fsi_get_master(fsi); if (enable) - fsi_master_mask_set(CLK_RST, val, val); + fsi_master_mask_set(master, CLK_RST, val, val); else - fsi_master_mask_set(CLK_RST, val, 0); + fsi_master_mask_set(master, CLK_RST, val, 0); } static void fsi_irq_init(struct fsi_priv *fsi, int is_play) @@ -355,23 +344,23 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play) fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); /* clear interrupt factor */ - fsi_master_mask_set(INT_ST, data, 0); + fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0); } -static void fsi_soft_all_reset(void) +static void fsi_soft_all_reset(struct fsi_master *master) { - u32 status = fsi_master_read(SOFT_RST); + u32 status = fsi_master_read(master, SOFT_RST); /* port AB reset */ status &= 0x000000ff; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); mdelay(10); /* soft reset */ status &= 0x000000f0; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); status |= 0x00000001; - fsi_master_write(SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status); mdelay(10); } @@ -517,12 +506,13 @@ static int fsi_data_pop(struct fsi_priv *fsi) static irqreturn_t fsi_interrupt(int irq, void *data) { - u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; - u32 int_st = fsi_master_read(INT_ST); + struct fsi_master *master = data; + u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010; + u32 int_st = fsi_master_read(master, INT_ST); /* clear irq status */ - fsi_master_write(SOFT_RST, status); - fsi_master_write(SOFT_RST, status | 0x00000010); + fsi_master_write(master, SOFT_RST, status); + fsi_master_write(master, SOFT_RST, status | 0x00000010); if (int_st & INT_A_OUT) fsi_data_push(&master->fsia); @@ -533,7 +523,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) if (int_st & INT_B_IN) fsi_data_pop(&master->fsib); - fsi_master_write(INT_ST, 0x0000000); + fsi_master_write(master, INT_ST, 0x0000000); return IRQ_HANDLED; } @@ -548,7 +538,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) static int fsi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); const char *msg; u32 flags = fsi_get_info_flags(fsi); u32 fmt; @@ -667,7 +657,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, static void fsi_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; fsi_irq_disable(fsi, is_play); @@ -679,7 +669,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); struct snd_pcm_runtime *runtime = substream->runtime; int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; @@ -760,7 +750,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct fsi_priv *fsi = fsi_get(substream); + struct fsi_priv *fsi = fsi_get_priv(substream); long location; location = (fsi->byte_offset - 1); @@ -870,10 +860,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); ************************************************************************/ static int fsi_probe(struct platform_device *pdev) { + struct fsi_master *master; struct resource *res; unsigned int irq; int ret; + if (0 != pdev->id) { + dev_err(&pdev->dev, "current fsi support id 0 only now\n"); + return -ENODEV; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || !irq) { @@ -899,15 +895,19 @@ static int fsi_probe(struct platform_device *pdev) master->irq = irq; master->info = pdev->dev.platform_data; master->fsia.base = master->base; + master->fsia.master = master; master->fsib.base = master->base + 0x40; + master->fsib.master = master; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); fsi_soc_dai[0].dev = &pdev->dev; + fsi_soc_dai[0].private_data = &master->fsia; fsi_soc_dai[1].dev = &pdev->dev; + fsi_soc_dai[1].private_data = &master->fsib; - fsi_soft_all_reset(); + fsi_soft_all_reset(master); ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); if (ret) { @@ -937,6 +937,10 @@ exit: static int fsi_remove(struct platform_device *pdev) { + struct fsi_master *master; + + master = fsi_get_master(fsi_soc_dai[0].private_data); + snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); snd_soc_unregister_platform(&fsi_soc_platform); @@ -946,7 +950,12 @@ static int fsi_remove(struct platform_device *pdev) iounmap(master->base); kfree(master); - master = NULL; + + fsi_soc_dai[0].dev = NULL; + fsi_soc_dai[0].private_data = NULL; + fsi_soc_dai[1].dev = NULL; + fsi_soc_dai[1].private_data = NULL; + return 0; } -- GitLab From a47979b5aa2117848b742828c98abe7eea42a9ff Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Thu, 3 Dec 2009 18:56:56 +0530 Subject: [PATCH 0018/3892] ASoC: DaVinci: Update suspend/resume support for McASP driver Add clock enable and disable calls to resume and suspend respectively. Also add a member to the audio device data structure which tracks the clock status. Tested on DA850/OMAP-L138 EVM. For the purpose of testing, the patches[1] which add suspend-to-RAM support to DA850/OMAP-L138 SoC were applied. [1] http://linux.davincidsp.com/pipermail/davinci-linux-open-source/ 2009-November/016958.html Signed-off-by: Chaithrika U S Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 18 ++++++++++++++++-- sound/soc/davinci/davinci-mcasp.h | 1 + sound/soc/davinci/davinci-pcm.c | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0a302e1080d9..a613bbb0bc91 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -767,14 +767,27 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, int ret = 0; switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + if (!dev->clk_active) { + clk_enable(dev->clk); + dev->clk_active = 1; + } + /* Fall through */ + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_mcasp_start(dev, substream->stream); break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: + davinci_mcasp_stop(dev, substream->stream); + if (dev->clk_active) { + clk_disable(dev->clk); + dev->clk_active = 0; + } + + break; + + case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(dev, substream->stream); break; @@ -866,6 +879,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } clk_enable(dev->clk); + dev->clk_active = 1; dev->base = (void __iomem *)IO_ADDRESS(mem->start); dev->op_mode = pdata->op_mode; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 582c9249ef09..e755b5121ec7 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -44,6 +44,7 @@ struct davinci_audio_dev { int sample_rate; struct clk *clk; unsigned int codec_fmt; + u8 clk_active; /* McASP specific data */ int tdm_slots; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index ad4d7f47a86b..80c7fdf2f521 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name) static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | -- GitLab From 3a7aaed714bbe3c071000d720f0cce186d1897a4 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Fri, 4 Dec 2009 13:49:10 +0200 Subject: [PATCH 0019/3892] ASoC: tlv320dac33: Add support for regulator framework Take the regulator framework in use for managing the power sources. Signed-off-by: Ilkka Koskinen Acked-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 92 +++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 9c8903dbe647..5037454974b6 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -58,11 +59,19 @@ enum dac33_state { DAC33_FLUSH, }; +#define DAC33_NUM_SUPPLIES 3 +static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = { + "AVDD", + "DVDD", + "IOVDD", +}; + struct tlv320dac33_priv { struct mutex mutex; struct workqueue_struct *dac33_wq; struct work_struct work; struct snd_soc_codec codec; + struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; int power_gpio; int chip_power; int irq; @@ -297,28 +306,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) dac33_write(codec, DAC33_PWR_CTRL, reg); } -static void dac33_hard_power(struct snd_soc_codec *codec, int power) +static int dac33_hard_power(struct snd_soc_codec *codec, int power) { struct tlv320dac33_priv *dac33 = codec->private_data; + int ret; mutex_lock(&dac33->mutex); if (power) { - if (dac33->power_gpio >= 0) { - gpio_set_value(dac33->power_gpio, 1); - dac33->chip_power = 1; - /* Restore registers */ - dac33_restore_regs(codec); + ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), + dac33->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", ret); + goto exit; } + + if (dac33->power_gpio >= 0) + gpio_set_value(dac33->power_gpio, 1); + + dac33->chip_power = 1; + + /* Restore registers */ + dac33_restore_regs(codec); + dac33_soft_power(codec, 1); } else { dac33_soft_power(codec, 0); - if (dac33->power_gpio >= 0) { + if (dac33->power_gpio >= 0) gpio_set_value(dac33->power_gpio, 0); - dac33->chip_power = 0; + + ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), + dac33->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to disable supplies: %d\n", ret); + goto exit; } + + dac33->chip_power = 0; } - mutex_unlock(&dac33->mutex); +exit: + mutex_unlock(&dac33->mutex); + return ret; } static int dac33_get_nsample(struct snd_kcontrol *kcontrol, @@ -469,6 +499,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) static int dac33_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + int ret; + switch (level) { case SND_SOC_BIAS_ON: dac33_soft_power(codec, 1); @@ -476,12 +508,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) - dac33_hard_power(codec, 1); + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = dac33_hard_power(codec, 1); + if (ret != 0) + return ret; + } + dac33_soft_power(codec, 0); break; case SND_SOC_BIAS_OFF: - dac33_hard_power(codec, 0); + ret = dac33_hard_power(codec, 0); + if (ret != 0) + return ret; + break; } codec->bias_level = level; @@ -959,6 +998,9 @@ static int dac33_soc_probe(struct platform_device *pdev) /* power on device */ dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Bias level configuration has enabled regulator an extra time */ + regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); + return 0; pcm_err: @@ -1039,7 +1081,7 @@ static int dac33_i2c_probe(struct i2c_client *client, struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; struct snd_soc_codec *codec; - int ret = 0; + int ret, i; if (client->dev.platform_data == NULL) { dev_err(&client->dev, "Platform data not set\n"); @@ -1130,6 +1172,24 @@ static int dac33_i2c_probe(struct i2c_client *client, } } + for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++) + dac33->supplies[i].supply = dac33_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies), + dac33->supplies); + + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err_get; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), + dac33->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_enable; + } + ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); @@ -1149,6 +1209,10 @@ static int dac33_i2c_probe(struct i2c_client *client, return ret; error_codec: + regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); +err_enable: + regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); +err_get: if (dac33->irq >= 0) { free_irq(dac33->irq, &dac33->codec); destroy_workqueue(dac33->dac33_wq); @@ -1177,6 +1241,8 @@ static int dac33_i2c_remove(struct i2c_client *client) if (dac33->irq >= 0) free_irq(dac33->irq, &dac33->codec); + regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); + destroy_workqueue(dac33->dac33_wq); snd_soc_unregister_dai(&dac33_dai); snd_soc_unregister_codec(&dac33->codec); -- GitLab From dd1b3d53c2e5b9cccec9001fc0b63f6b686a4ac9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Dec 2009 14:22:03 +0000 Subject: [PATCH 0020/3892] ASoC: Export snd_soc_update_bits_unlocked() Allows custom controls to use it. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d7718f9280d..08909ccd235b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -253,6 +253,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, /* codec register bit access */ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, unsigned int mask, unsigned int value); +int snd_soc_update_bits_locked(struct snd_soc_codec *codec, + unsigned short reg, unsigned int mask, + unsigned int value); int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, unsigned int mask, unsigned int value); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ef8f28284cb9..8b900a842677 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1427,9 +1427,9 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits); * * Returns 1 for change else 0. */ -static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, - unsigned short reg, unsigned int mask, - unsigned int value) +int snd_soc_update_bits_locked(struct snd_soc_codec *codec, + unsigned short reg, unsigned int mask, + unsigned int value) { int change; @@ -1439,6 +1439,7 @@ static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, return change; } +EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); /** * snd_soc_test_bits - test register for change -- GitLab From d033c36ae5cec22c893c710cd026fb732c4086b9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Dec 2009 15:25:56 +0000 Subject: [PATCH 0021/3892] ASoC: Display the power register in DAPM widget debugfs Make it a bit easier to tie DAPM widgets in with the register map without referring to the source by including the register location controlled by the widget. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-dapm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0d294ef72590..846678aa3d35 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1147,9 +1147,16 @@ static ssize_t dapm_widget_power_read_file(struct file *file, out = is_connected_output_ep(w); dapm_clear_walk(w->codec); - ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", + ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", w->name, w->power ? "On" : "Off", in, out); + if (w->reg >= 0) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + " - R%d(0x%x) bit %d", + w->reg, w->reg, w->shift); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); + if (w->sname) ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", w->sname, -- GitLab From a91eb199e4dc8a2ab3fb7a53f1a23ce82b29fc04 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Nov 2009 11:56:07 +0000 Subject: [PATCH 0022/3892] ASoC: Initial WM8904 CODEC driver The WM8904 is a high performance ultra-low power stereo CODEC optimised for portable audio applications, with features including a class W amplifier, FLL with free running mode, Mobile ReTune and ground referenced headphone and line outputs. Support for some features, most particularly the digital microphone interface, is not yet present. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/wm8904.h | 57 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8904.c | 2538 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8904.h | 1681 ++++++++++++++++++++++++ 5 files changed, 4282 insertions(+) create mode 100644 include/sound/wm8904.h create mode 100644 sound/soc/codecs/wm8904.c create mode 100644 sound/soc/codecs/wm8904.h diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h new file mode 100644 index 000000000000..d66575a601be --- /dev/null +++ b/include/sound/wm8904.h @@ -0,0 +1,57 @@ +/* + * Platform data for WM8904 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_PDATA_H__ +#define __MFD_WM8994_PDATA_H__ + +#define WM8904_DRC_REGS 4 +#define WM8904_EQ_REGS 25 + +/** + * DRC configurations are specified with a label and a set of register + * values to write (the enable bits will be ignored). At runtime an + * enumerated control will be presented for each DRC block allowing + * the user to choose the configration to use. + * + * Configurations may be generated by hand or by using the DRC control + * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/ + * for details. + */ +struct wm8904_drc_cfg { + const char *name; + u16 regs[WM8904_DRC_REGS]; +}; + +/** + * ReTune Mobile configurations are specified with a label, sample + * rate and set of values to write (the enable bits will be ignored). + * + * Configurations are expected to be generated using the ReTune Mobile + * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/ + */ +struct wm8904_retune_mobile_cfg { + const char *name; + unsigned int rate; + u16 regs[WM8904_EQ_REGS]; +}; + +struct wm8904_pdata { + int num_drc_cfgs; + struct wm8904_drc_cfg *drc_cfgs; + + int num_retune_mobile_cfgs; + struct wm8904_retune_mobile_cfg *retune_mobile_cfgs; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 52b005f8fed4..011d3ab7e64a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C + select SND_SOC_WM8904 if I2C select SND_SOC_WM8940 if I2C select SND_SOC_WM8960 if I2C select SND_SOC_WM8961 if I2C @@ -203,6 +204,9 @@ config SND_SOC_WM8900 config SND_SOC_WM8903 tristate +config SND_SOC_WM8904 + tristate + config SND_SOC_WM8940 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index dbaecb133ac7..0471d9044205 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -36,6 +36,7 @@ snd-soc-wm8753-objs := wm8753.o snd-soc-wm8776-objs := wm8776.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o +snd-soc-wm8904-objs := wm8904.o snd-soc-wm8940-objs := wm8940.o snd-soc-wm8960-objs := wm8960.o snd-soc-wm8961-objs := wm8961.o @@ -92,6 +93,7 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o +obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c new file mode 100644 index 000000000000..8310e5d14b83 --- /dev/null +++ b/sound/soc/codecs/wm8904.c @@ -0,0 +1,2538 @@ +/* + * wm8904.c -- WM8904 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8904.h" + +static struct snd_soc_codec *wm8904_codec; +struct snd_soc_codec_device soc_codec_dev_wm8904; + +#define WM8904_NUM_DCS_CHANNELS 4 + +#define WM8904_NUM_SUPPLIES 5 +static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD", + "CPVDD", + "MICVDD", +}; + +/* codec private data */ +struct wm8904_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8904_MAX_REGISTER + 1]; + + struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES]; + + struct wm8904_pdata *pdata; + + int deemph; + + /* Platform provided DRC configuration */ + const char **drc_texts; + int drc_cfg; + struct soc_enum drc_enum; + + /* Platform provided ReTune mobile configuration */ + int num_retune_mobile_texts; + const char **retune_mobile_texts; + int retune_mobile_cfg; + struct soc_enum retune_mobile_enum; + + /* FLL setup */ + int fll_src; + int fll_fref; + int fll_fout; + + /* Clocking configuration */ + unsigned int mclk_rate; + int sysclk_src; + unsigned int sysclk_rate; + + int tdm_width; + int tdm_slots; + int bclk; + int fs; + + /* DC servo configuration - cached offset values */ + int dcs_state[WM8904_NUM_DCS_CHANNELS]; +}; + +static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = { + 0x8904, /* R0 - SW Reset and ID */ + 0x0000, /* R1 - Revision */ + 0x0000, /* R2 */ + 0x0000, /* R3 */ + 0x0018, /* R4 - Bias Control 0 */ + 0x0000, /* R5 - VMID Control 0 */ + 0x0000, /* R6 - Mic Bias Control 0 */ + 0x0000, /* R7 - Mic Bias Control 1 */ + 0x0001, /* R8 - Analogue DAC 0 */ + 0x9696, /* R9 - mic Filter Control */ + 0x0001, /* R10 - Analogue ADC 0 */ + 0x0000, /* R11 */ + 0x0000, /* R12 - Power Management 0 */ + 0x0000, /* R13 */ + 0x0000, /* R14 - Power Management 2 */ + 0x0000, /* R15 - Power Management 3 */ + 0x0000, /* R16 */ + 0x0000, /* R17 */ + 0x0000, /* R18 - Power Management 6 */ + 0x0000, /* R19 */ + 0x945E, /* R20 - Clock Rates 0 */ + 0x0C05, /* R21 - Clock Rates 1 */ + 0x0006, /* R22 - Clock Rates 2 */ + 0x0000, /* R23 */ + 0x0050, /* R24 - Audio Interface 0 */ + 0x000A, /* R25 - Audio Interface 1 */ + 0x00E4, /* R26 - Audio Interface 2 */ + 0x0040, /* R27 - Audio Interface 3 */ + 0x0000, /* R28 */ + 0x0000, /* R29 */ + 0x00C0, /* R30 - DAC Digital Volume Left */ + 0x00C0, /* R31 - DAC Digital Volume Right */ + 0x0000, /* R32 - DAC Digital 0 */ + 0x0008, /* R33 - DAC Digital 1 */ + 0x0000, /* R34 */ + 0x0000, /* R35 */ + 0x00C0, /* R36 - ADC Digital Volume Left */ + 0x00C0, /* R37 - ADC Digital Volume Right */ + 0x0010, /* R38 - ADC Digital 0 */ + 0x0000, /* R39 - Digital Microphone 0 */ + 0x01AF, /* R40 - DRC 0 */ + 0x3248, /* R41 - DRC 1 */ + 0x0000, /* R42 - DRC 2 */ + 0x0000, /* R43 - DRC 3 */ + 0x0085, /* R44 - Analogue Left Input 0 */ + 0x0085, /* R45 - Analogue Right Input 0 */ + 0x0044, /* R46 - Analogue Left Input 1 */ + 0x0044, /* R47 - Analogue Right Input 1 */ + 0x0000, /* R48 */ + 0x0000, /* R49 */ + 0x0000, /* R50 */ + 0x0000, /* R51 */ + 0x0000, /* R52 */ + 0x0000, /* R53 */ + 0x0000, /* R54 */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x002D, /* R57 - Analogue OUT1 Left */ + 0x002D, /* R58 - Analogue OUT1 Right */ + 0x0039, /* R59 - Analogue OUT2 Left */ + 0x0039, /* R60 - Analogue OUT2 Right */ + 0x0000, /* R61 - Analogue OUT12 ZC */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x0000, /* R64 */ + 0x0000, /* R65 */ + 0x0000, /* R66 */ + 0x0000, /* R67 - DC Servo 0 */ + 0x0000, /* R68 - DC Servo 1 */ + 0xAAAA, /* R69 - DC Servo 2 */ + 0x0000, /* R70 */ + 0xAAAA, /* R71 - DC Servo 4 */ + 0xAAAA, /* R72 - DC Servo 5 */ + 0x0000, /* R73 - DC Servo 6 */ + 0x0000, /* R74 - DC Servo 7 */ + 0x0000, /* R75 - DC Servo 8 */ + 0x0000, /* R76 - DC Servo 9 */ + 0x0000, /* R77 - DC Servo Readback 0 */ + 0x0000, /* R78 */ + 0x0000, /* R79 */ + 0x0000, /* R80 */ + 0x0000, /* R81 */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0000, /* R88 */ + 0x0000, /* R89 */ + 0x0000, /* R90 - Analogue HP 0 */ + 0x0000, /* R91 */ + 0x0000, /* R92 */ + 0x0000, /* R93 */ + 0x0000, /* R94 - Analogue Lineout 0 */ + 0x0000, /* R95 */ + 0x0000, /* R96 */ + 0x0000, /* R97 */ + 0x0000, /* R98 - Charge Pump 0 */ + 0x0000, /* R99 */ + 0x0000, /* R100 */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x0004, /* R104 - Class W 0 */ + 0x0000, /* R105 */ + 0x0000, /* R106 */ + 0x0000, /* R107 */ + 0x0000, /* R108 - Write Sequencer 0 */ + 0x0000, /* R109 - Write Sequencer 1 */ + 0x0000, /* R110 - Write Sequencer 2 */ + 0x0000, /* R111 - Write Sequencer 3 */ + 0x0000, /* R112 - Write Sequencer 4 */ + 0x0000, /* R113 */ + 0x0000, /* R114 */ + 0x0000, /* R115 */ + 0x0000, /* R116 - FLL Control 1 */ + 0x0007, /* R117 - FLL Control 2 */ + 0x0000, /* R118 - FLL Control 3 */ + 0x2EE0, /* R119 - FLL Control 4 */ + 0x0004, /* R120 - FLL Control 5 */ + 0x0014, /* R121 - GPIO Control 1 */ + 0x0010, /* R122 - GPIO Control 2 */ + 0x0010, /* R123 - GPIO Control 3 */ + 0x0000, /* R124 - GPIO Control 4 */ + 0x0000, /* R125 */ + 0x0000, /* R126 - Digital Pulls */ + 0x0000, /* R127 - Interrupt Status */ + 0xFFFF, /* R128 - Interrupt Status Mask */ + 0x0000, /* R129 - Interrupt Polarity */ + 0x0000, /* R130 - Interrupt Debounce */ + 0x0000, /* R131 */ + 0x0000, /* R132 */ + 0x0000, /* R133 */ + 0x0000, /* R134 - EQ1 */ + 0x000C, /* R135 - EQ2 */ + 0x000C, /* R136 - EQ3 */ + 0x000C, /* R137 - EQ4 */ + 0x000C, /* R138 - EQ5 */ + 0x000C, /* R139 - EQ6 */ + 0x0FCA, /* R140 - EQ7 */ + 0x0400, /* R141 - EQ8 */ + 0x00D8, /* R142 - EQ9 */ + 0x1EB5, /* R143 - EQ10 */ + 0xF145, /* R144 - EQ11 */ + 0x0B75, /* R145 - EQ12 */ + 0x01C5, /* R146 - EQ13 */ + 0x1C58, /* R147 - EQ14 */ + 0xF373, /* R148 - EQ15 */ + 0x0A54, /* R149 - EQ16 */ + 0x0558, /* R150 - EQ17 */ + 0x168E, /* R151 - EQ18 */ + 0xF829, /* R152 - EQ19 */ + 0x07AD, /* R153 - EQ20 */ + 0x1103, /* R154 - EQ21 */ + 0x0564, /* R155 - EQ22 */ + 0x0559, /* R156 - EQ23 */ + 0x4000, /* R157 - EQ24 */ + 0x0000, /* R158 */ + 0x0000, /* R159 */ + 0x0000, /* R160 */ + 0x0000, /* R161 - Control Interface Test 1 */ + 0x0000, /* R162 */ + 0x0000, /* R163 */ + 0x0000, /* R164 */ + 0x0000, /* R165 */ + 0x0000, /* R166 */ + 0x0000, /* R167 */ + 0x0000, /* R168 */ + 0x0000, /* R169 */ + 0x0000, /* R170 */ + 0x0000, /* R171 */ + 0x0000, /* R172 */ + 0x0000, /* R173 */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 */ + 0x0000, /* R177 */ + 0x0000, /* R178 */ + 0x0000, /* R179 */ + 0x0000, /* R180 */ + 0x0000, /* R181 */ + 0x0000, /* R182 */ + 0x0000, /* R183 */ + 0x0000, /* R184 */ + 0x0000, /* R185 */ + 0x0000, /* R186 */ + 0x0000, /* R187 */ + 0x0000, /* R188 */ + 0x0000, /* R189 */ + 0x0000, /* R190 */ + 0x0000, /* R191 */ + 0x0000, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0000, /* R195 */ + 0x0000, /* R196 */ + 0x0000, /* R197 */ + 0x0000, /* R198 */ + 0x0000, /* R199 */ + 0x0000, /* R200 */ + 0x0000, /* R201 */ + 0x0000, /* R202 */ + 0x0000, /* R203 */ + 0x0000, /* R204 - Analogue Output Bias 0 */ + 0x0000, /* R205 */ + 0x0000, /* R206 */ + 0x0000, /* R207 */ + 0x0000, /* R208 */ + 0x0000, /* R209 */ + 0x0000, /* R210 */ + 0x0000, /* R211 */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 */ + 0x0000, /* R216 */ + 0x0000, /* R217 */ + 0x0000, /* R218 */ + 0x0000, /* R219 */ + 0x0000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 */ + 0x0000, /* R225 */ + 0x0000, /* R226 */ + 0x0000, /* R227 */ + 0x0000, /* R228 */ + 0x0000, /* R229 */ + 0x0000, /* R230 */ + 0x0000, /* R231 */ + 0x0000, /* R232 */ + 0x0000, /* R233 */ + 0x0000, /* R234 */ + 0x0000, /* R235 */ + 0x0000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0000, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0000, /* R243 */ + 0x0000, /* R244 */ + 0x0000, /* R245 */ + 0x0000, /* R246 */ + 0x0000, /* R247 - FLL NCO Test 0 */ + 0x0019, /* R248 - FLL NCO Test 1 */ +}; + +static struct { + int readable; + int writable; + int vol; +} wm8904_access[] = { + { 0xFFFF, 0xFFFF, 1 }, /* R0 - SW Reset and ID */ + { 0x0000, 0x0000, 0 }, /* R1 - Revision */ + { 0x0000, 0x0000, 0 }, /* R2 */ + { 0x0000, 0x0000, 0 }, /* R3 */ + { 0x001F, 0x001F, 0 }, /* R4 - Bias Control 0 */ + { 0x0047, 0x0047, 0 }, /* R5 - VMID Control 0 */ + { 0x007F, 0x007F, 0 }, /* R6 - Mic Bias Control 0 */ + { 0xC007, 0xC007, 0 }, /* R7 - Mic Bias Control 1 */ + { 0x001E, 0x001E, 0 }, /* R8 - Analogue DAC 0 */ + { 0xFFFF, 0xFFFF, 0 }, /* R9 - mic Filter Control */ + { 0x0001, 0x0001, 0 }, /* R10 - Analogue ADC 0 */ + { 0x0000, 0x0000, 0 }, /* R11 */ + { 0x0003, 0x0003, 0 }, /* R12 - Power Management 0 */ + { 0x0000, 0x0000, 0 }, /* R13 */ + { 0x0003, 0x0003, 0 }, /* R14 - Power Management 2 */ + { 0x0003, 0x0003, 0 }, /* R15 - Power Management 3 */ + { 0x0000, 0x0000, 0 }, /* R16 */ + { 0x0000, 0x0000, 0 }, /* R17 */ + { 0x000F, 0x000F, 0 }, /* R18 - Power Management 6 */ + { 0x0000, 0x0000, 0 }, /* R19 */ + { 0x7001, 0x7001, 0 }, /* R20 - Clock Rates 0 */ + { 0x3C07, 0x3C07, 0 }, /* R21 - Clock Rates 1 */ + { 0xD00F, 0xD00F, 0 }, /* R22 - Clock Rates 2 */ + { 0x0000, 0x0000, 0 }, /* R23 */ + { 0x1FFF, 0x1FFF, 0 }, /* R24 - Audio Interface 0 */ + { 0x3DDF, 0x3DDF, 0 }, /* R25 - Audio Interface 1 */ + { 0x0F1F, 0x0F1F, 0 }, /* R26 - Audio Interface 2 */ + { 0x0FFF, 0x0FFF, 0 }, /* R27 - Audio Interface 3 */ + { 0x0000, 0x0000, 0 }, /* R28 */ + { 0x0000, 0x0000, 0 }, /* R29 */ + { 0x00FF, 0x01FF, 0 }, /* R30 - DAC Digital Volume Left */ + { 0x00FF, 0x01FF, 0 }, /* R31 - DAC Digital Volume Right */ + { 0x0FFF, 0x0FFF, 0 }, /* R32 - DAC Digital 0 */ + { 0x1E4E, 0x1E4E, 0 }, /* R33 - DAC Digital 1 */ + { 0x0000, 0x0000, 0 }, /* R34 */ + { 0x0000, 0x0000, 0 }, /* R35 */ + { 0x00FF, 0x01FF, 0 }, /* R36 - ADC Digital Volume Left */ + { 0x00FF, 0x01FF, 0 }, /* R37 - ADC Digital Volume Right */ + { 0x0073, 0x0073, 0 }, /* R38 - ADC Digital 0 */ + { 0x1800, 0x1800, 0 }, /* R39 - Digital Microphone 0 */ + { 0xDFEF, 0xDFEF, 0 }, /* R40 - DRC 0 */ + { 0xFFFF, 0xFFFF, 0 }, /* R41 - DRC 1 */ + { 0x003F, 0x003F, 0 }, /* R42 - DRC 2 */ + { 0x07FF, 0x07FF, 0 }, /* R43 - DRC 3 */ + { 0x009F, 0x009F, 0 }, /* R44 - Analogue Left Input 0 */ + { 0x009F, 0x009F, 0 }, /* R45 - Analogue Right Input 0 */ + { 0x007F, 0x007F, 0 }, /* R46 - Analogue Left Input 1 */ + { 0x007F, 0x007F, 0 }, /* R47 - Analogue Right Input 1 */ + { 0x0000, 0x0000, 0 }, /* R48 */ + { 0x0000, 0x0000, 0 }, /* R49 */ + { 0x0000, 0x0000, 0 }, /* R50 */ + { 0x0000, 0x0000, 0 }, /* R51 */ + { 0x0000, 0x0000, 0 }, /* R52 */ + { 0x0000, 0x0000, 0 }, /* R53 */ + { 0x0000, 0x0000, 0 }, /* R54 */ + { 0x0000, 0x0000, 0 }, /* R55 */ + { 0x0000, 0x0000, 0 }, /* R56 */ + { 0x017F, 0x01FF, 0 }, /* R57 - Analogue OUT1 Left */ + { 0x017F, 0x01FF, 0 }, /* R58 - Analogue OUT1 Right */ + { 0x017F, 0x01FF, 0 }, /* R59 - Analogue OUT2 Left */ + { 0x017F, 0x01FF, 0 }, /* R60 - Analogue OUT2 Right */ + { 0x000F, 0x000F, 0 }, /* R61 - Analogue OUT12 ZC */ + { 0x0000, 0x0000, 0 }, /* R62 */ + { 0x0000, 0x0000, 0 }, /* R63 */ + { 0x0000, 0x0000, 0 }, /* R64 */ + { 0x0000, 0x0000, 0 }, /* R65 */ + { 0x0000, 0x0000, 0 }, /* R66 */ + { 0x000F, 0x000F, 0 }, /* R67 - DC Servo 0 */ + { 0xFFFF, 0xFFFF, 1 }, /* R68 - DC Servo 1 */ + { 0x0F0F, 0x0F0F, 0 }, /* R69 - DC Servo 2 */ + { 0x0000, 0x0000, 0 }, /* R70 */ + { 0x007F, 0x007F, 0 }, /* R71 - DC Servo 4 */ + { 0x007F, 0x007F, 0 }, /* R72 - DC Servo 5 */ + { 0x00FF, 0x00FF, 1 }, /* R73 - DC Servo 6 */ + { 0x00FF, 0x00FF, 1 }, /* R74 - DC Servo 7 */ + { 0x00FF, 0x00FF, 1 }, /* R75 - DC Servo 8 */ + { 0x00FF, 0x00FF, 1 }, /* R76 - DC Servo 9 */ + { 0x0FFF, 0x0000, 1 }, /* R77 - DC Servo Readback 0 */ + { 0x0000, 0x0000, 0 }, /* R78 */ + { 0x0000, 0x0000, 0 }, /* R79 */ + { 0x0000, 0x0000, 0 }, /* R80 */ + { 0x0000, 0x0000, 0 }, /* R81 */ + { 0x0000, 0x0000, 0 }, /* R82 */ + { 0x0000, 0x0000, 0 }, /* R83 */ + { 0x0000, 0x0000, 0 }, /* R84 */ + { 0x0000, 0x0000, 0 }, /* R85 */ + { 0x0000, 0x0000, 0 }, /* R86 */ + { 0x0000, 0x0000, 0 }, /* R87 */ + { 0x0000, 0x0000, 0 }, /* R88 */ + { 0x0000, 0x0000, 0 }, /* R89 */ + { 0x00FF, 0x00FF, 0 }, /* R90 - Analogue HP 0 */ + { 0x0000, 0x0000, 0 }, /* R91 */ + { 0x0000, 0x0000, 0 }, /* R92 */ + { 0x0000, 0x0000, 0 }, /* R93 */ + { 0x00FF, 0x00FF, 0 }, /* R94 - Analogue Lineout 0 */ + { 0x0000, 0x0000, 0 }, /* R95 */ + { 0x0000, 0x0000, 0 }, /* R96 */ + { 0x0000, 0x0000, 0 }, /* R97 */ + { 0x0001, 0x0001, 0 }, /* R98 - Charge Pump 0 */ + { 0x0000, 0x0000, 0 }, /* R99 */ + { 0x0000, 0x0000, 0 }, /* R100 */ + { 0x0000, 0x0000, 0 }, /* R101 */ + { 0x0000, 0x0000, 0 }, /* R102 */ + { 0x0000, 0x0000, 0 }, /* R103 */ + { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */ + { 0x0000, 0x0000, 0 }, /* R105 */ + { 0x0000, 0x0000, 0 }, /* R106 */ + { 0x0000, 0x0000, 0 }, /* R107 */ + { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */ + { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */ + { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */ + { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */ + { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */ + { 0x0000, 0x0000, 0 }, /* R113 */ + { 0x0000, 0x0000, 0 }, /* R114 */ + { 0x0000, 0x0000, 0 }, /* R115 */ + { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */ + { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */ + { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */ + { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */ + { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */ + { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */ + { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */ + { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */ + { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */ + { 0x0000, 0x0000, 0 }, /* R125 */ + { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */ + { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */ + { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */ + { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */ + { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */ + { 0x0000, 0x0000, 0 }, /* R131 */ + { 0x0000, 0x0000, 0 }, /* R132 */ + { 0x0000, 0x0000, 0 }, /* R133 */ + { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */ + { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */ + { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */ + { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */ + { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */ + { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */ + { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */ + { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */ + { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */ + { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */ + { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */ + { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */ + { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */ + { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */ + { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */ + { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */ + { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */ + { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */ + { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */ + { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */ + { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */ + { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */ + { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */ + { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */ + { 0x0000, 0x0000, 0 }, /* R158 */ + { 0x0000, 0x0000, 0 }, /* R159 */ + { 0x0000, 0x0000, 0 }, /* R160 */ + { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */ + { 0x0000, 0x0000, 0 }, /* R162 */ + { 0x0000, 0x0000, 0 }, /* R163 */ + { 0x0000, 0x0000, 0 }, /* R164 */ + { 0x0000, 0x0000, 0 }, /* R165 */ + { 0x0000, 0x0000, 0 }, /* R166 */ + { 0x0000, 0x0000, 0 }, /* R167 */ + { 0x0000, 0x0000, 0 }, /* R168 */ + { 0x0000, 0x0000, 0 }, /* R169 */ + { 0x0000, 0x0000, 0 }, /* R170 */ + { 0x0000, 0x0000, 0 }, /* R171 */ + { 0x0000, 0x0000, 0 }, /* R172 */ + { 0x0000, 0x0000, 0 }, /* R173 */ + { 0x0000, 0x0000, 0 }, /* R174 */ + { 0x0000, 0x0000, 0 }, /* R175 */ + { 0x0000, 0x0000, 0 }, /* R176 */ + { 0x0000, 0x0000, 0 }, /* R177 */ + { 0x0000, 0x0000, 0 }, /* R178 */ + { 0x0000, 0x0000, 0 }, /* R179 */ + { 0x0000, 0x0000, 0 }, /* R180 */ + { 0x0000, 0x0000, 0 }, /* R181 */ + { 0x0000, 0x0000, 0 }, /* R182 */ + { 0x0000, 0x0000, 0 }, /* R183 */ + { 0x0000, 0x0000, 0 }, /* R184 */ + { 0x0000, 0x0000, 0 }, /* R185 */ + { 0x0000, 0x0000, 0 }, /* R186 */ + { 0x0000, 0x0000, 0 }, /* R187 */ + { 0x0000, 0x0000, 0 }, /* R188 */ + { 0x0000, 0x0000, 0 }, /* R189 */ + { 0x0000, 0x0000, 0 }, /* R190 */ + { 0x0000, 0x0000, 0 }, /* R191 */ + { 0x0000, 0x0000, 0 }, /* R192 */ + { 0x0000, 0x0000, 0 }, /* R193 */ + { 0x0000, 0x0000, 0 }, /* R194 */ + { 0x0000, 0x0000, 0 }, /* R195 */ + { 0x0000, 0x0000, 0 }, /* R196 */ + { 0x0000, 0x0000, 0 }, /* R197 */ + { 0x0000, 0x0000, 0 }, /* R198 */ + { 0x0000, 0x0000, 0 }, /* R199 */ + { 0x0000, 0x0000, 0 }, /* R200 */ + { 0x0000, 0x0000, 0 }, /* R201 */ + { 0x0000, 0x0000, 0 }, /* R202 */ + { 0x0000, 0x0000, 0 }, /* R203 */ + { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */ + { 0x0000, 0x0000, 0 }, /* R205 */ + { 0x0000, 0x0000, 0 }, /* R206 */ + { 0x0000, 0x0000, 0 }, /* R207 */ + { 0x0000, 0x0000, 0 }, /* R208 */ + { 0x0000, 0x0000, 0 }, /* R209 */ + { 0x0000, 0x0000, 0 }, /* R210 */ + { 0x0000, 0x0000, 0 }, /* R211 */ + { 0x0000, 0x0000, 0 }, /* R212 */ + { 0x0000, 0x0000, 0 }, /* R213 */ + { 0x0000, 0x0000, 0 }, /* R214 */ + { 0x0000, 0x0000, 0 }, /* R215 */ + { 0x0000, 0x0000, 0 }, /* R216 */ + { 0x0000, 0x0000, 0 }, /* R217 */ + { 0x0000, 0x0000, 0 }, /* R218 */ + { 0x0000, 0x0000, 0 }, /* R219 */ + { 0x0000, 0x0000, 0 }, /* R220 */ + { 0x0000, 0x0000, 0 }, /* R221 */ + { 0x0000, 0x0000, 0 }, /* R222 */ + { 0x0000, 0x0000, 0 }, /* R223 */ + { 0x0000, 0x0000, 0 }, /* R224 */ + { 0x0000, 0x0000, 0 }, /* R225 */ + { 0x0000, 0x0000, 0 }, /* R226 */ + { 0x0000, 0x0000, 0 }, /* R227 */ + { 0x0000, 0x0000, 0 }, /* R228 */ + { 0x0000, 0x0000, 0 }, /* R229 */ + { 0x0000, 0x0000, 0 }, /* R230 */ + { 0x0000, 0x0000, 0 }, /* R231 */ + { 0x0000, 0x0000, 0 }, /* R232 */ + { 0x0000, 0x0000, 0 }, /* R233 */ + { 0x0000, 0x0000, 0 }, /* R234 */ + { 0x0000, 0x0000, 0 }, /* R235 */ + { 0x0000, 0x0000, 0 }, /* R236 */ + { 0x0000, 0x0000, 0 }, /* R237 */ + { 0x0000, 0x0000, 0 }, /* R238 */ + { 0x0000, 0x0000, 0 }, /* R239 */ + { 0x0000, 0x0000, 0 }, /* R240 */ + { 0x0000, 0x0000, 0 }, /* R241 */ + { 0x0000, 0x0000, 0 }, /* R242 */ + { 0x0000, 0x0000, 0 }, /* R243 */ + { 0x0000, 0x0000, 0 }, /* R244 */ + { 0x0000, 0x0000, 0 }, /* R245 */ + { 0x0000, 0x0000, 0 }, /* R246 */ + { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */ + { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ +}; + +static int wm8904_volatile_register(unsigned int reg) +{ + return wm8904_access[reg].vol; +} + +static int wm8904_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0); +} + +static int wm8904_configure_clocking(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + unsigned int clock0, clock2, rate; + + /* Gate the clock while we're updating to avoid misclocking */ + clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_SYSCLK_SRC, 0); + + /* This should be done on init() for bypass paths */ + switch (wm8904->sysclk_src) { + case WM8904_CLK_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate); + + clock2 &= ~WM8904_SYSCLK_SRC; + rate = wm8904->mclk_rate; + + /* Ensure the FLL is stopped */ + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); + break; + + case WM8904_CLK_FLL: + dev_dbg(codec->dev, "Using %dHz FLL clock\n", + wm8904->fll_fout); + + clock2 |= WM8904_SYSCLK_SRC; + rate = wm8904->fll_fout; + break; + + default: + dev_err(codec->dev, "System clock not configured\n"); + return -EINVAL; + } + + /* SYSCLK shouldn't be over 13.5MHz */ + if (rate > 13500000) { + clock0 = WM8904_MCLK_DIV; + wm8904->sysclk_rate = rate / 2; + } else { + clock0 = 0; + wm8904->sysclk_rate = rate; + } + + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV, + clock0); + + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2); + + dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate); + + return 0; +} + +static void wm8904_set_drc(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int save, i; + + /* Save any enables; the configuration should clear them. */ + save = snd_soc_read(codec, WM8904_DRC_0); + + for (i = 0; i < WM8904_DRC_REGS; i++) + snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff, + pdata->drc_cfgs[wm8904->drc_cfg].regs[i]); + + /* Reenable the DRC */ + snd_soc_update_bits(codec, WM8904_DRC_0, + WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save); +} + +static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int value = ucontrol->value.integer.value[0]; + + if (value >= pdata->num_drc_cfgs) + return -EINVAL; + + wm8904->drc_cfg = value; + + wm8904_set_drc(codec); + + return 0; +} + +static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; + + return 0; +} + +static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int best, best_val, save, i, cfg; + + if (!pdata || !wm8904->num_retune_mobile_texts) + return; + + /* Find the version of the currently selected configuration + * with the nearest sample rate. */ + cfg = wm8904->retune_mobile_cfg; + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8904->retune_mobile_texts[cfg]) == 0 && + abs(pdata->retune_mobile_cfgs[i].rate + - wm8904->fs) < best_val) { + best = i; + best_val = abs(pdata->retune_mobile_cfgs[i].rate + - wm8904->fs); + } + } + + dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n", + pdata->retune_mobile_cfgs[best].name, + pdata->retune_mobile_cfgs[best].rate, + wm8904->fs); + + /* The EQ will be disabled while reconfiguring it, remember the + * current configuration. + */ + save = snd_soc_read(codec, WM8904_EQ1); + + for (i = 0; i < WM8904_EQ_REGS; i++) + snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff, + pdata->retune_mobile_cfgs[best].regs[i]); + + snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save); +} + +static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + struct wm8904_pdata *pdata = wm8904->pdata; + int value = ucontrol->value.integer.value[0]; + + if (value >= pdata->num_retune_mobile_cfgs) + return -EINVAL; + + wm8904->retune_mobile_cfg = value; + + wm8904_set_retune_mobile(codec); + + return 0; +} + +static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; + + return 0; +} + +static int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int wm8904_set_deemph(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + int val, i, best; + + /* If we're using deemphasis select the nearest available sample + * rate. + */ + if (wm8904->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - wm8904->fs) < + abs(deemph_settings[best] - wm8904->fs)) + best = i; + } + + val = best << WM8904_DEEMPH_SHIFT; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, + WM8904_DEEMPH_MASK, val); +} + +static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + + return wm8904->deemph; +} + +static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8904_priv *wm8904 = codec->private_data; + int deemph = ucontrol->value.enumerated.item[0]; + + if (deemph > 1) + return -EINVAL; + + wm8904->deemph = deemph; + + return wm8904_set_deemph(codec); +} + +static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); + +static const char *input_mode_text[] = { + "Single-Ended", "Differential Line", "Differential Mic" +}; + +static const struct soc_enum lin_mode = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); + +static const struct soc_enum rin_mode = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); + +static const char *hpf_mode_text[] = { + "Hi-fi", "Voice 1", "Voice 2", "Voice 3" +}; + +static const struct soc_enum hpf_mode = + SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); + +static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = { +SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT, + WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv), + +SOC_ENUM("Left Caputure Mode", lin_mode), +SOC_ENUM("Right Capture Mode", rin_mode), + +/* No TLV since it depends on mode */ +SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, + WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), +SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, + WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0), + +SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), +SOC_ENUM("High Pass Filter Mode", hpf_mode), + +SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0), +}; + +static const char *drc_path_text[] = { + "ADC", "DAC" +}; + +static const struct soc_enum drc_path = + SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); + +static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { +SOC_SINGLE_TLV("Digital Playback Boost Volume", + WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv), +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT, + WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), + +SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv), +SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1), +SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT, + WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0), + +SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv), +SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1), +SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT, + WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0), + +SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0), +SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0), +SOC_ENUM("DRC Path", drc_path), +SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0), +SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + wm8904_get_deemph, wm8904_put_deemph), +}; + +static const struct snd_kcontrol_new wm8904_snd_controls[] = { +SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0, + sidetone_tlv), +}; + +static const struct snd_kcontrol_new wm8904_eq_controls[] = { +SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv), +}; + +static int cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + BUG_ON(event != SND_SOC_DAPM_POST_PMU); + + /* Maximum startup time */ + udelay(500); + + return 0; +} + +static int sysclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8904_priv *wm8904 = codec->private_data; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* If we're using the FLL then we only start it when + * required; we assume that the configuration has been + * done previously and all we need to do is kick it + * off. + */ + switch (wm8904->sysclk_src) { + case WM8904_CLK_FLL: + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA, + WM8904_FLL_OSC_ENA); + + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_ENA, + WM8904_FLL_ENA); + break; + + default: + break; + } + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); + break; + } + + return 0; +} + +static int out_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8904_priv *wm8904 = codec->private_data; + int reg, val; + int dcs_mask; + int dcs_l, dcs_r; + int dcs_l_reg, dcs_r_reg; + int timeout; + + /* This code is shared between HP and LINEOUT; we do all our + * power management in stereo pairs to avoid latency issues so + * we reuse shift to identify which rather than strcmp() the + * name. */ + reg = w->shift; + + switch (reg) { + case WM8904_ANALOGUE_HP_0: + dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1; + dcs_r_reg = WM8904_DC_SERVO_8; + dcs_l_reg = WM8904_DC_SERVO_9; + dcs_l = 0; + dcs_r = 1; + break; + case WM8904_ANALOGUE_LINEOUT_0: + dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3; + dcs_r_reg = WM8904_DC_SERVO_6; + dcs_l_reg = WM8904_DC_SERVO_7; + dcs_l = 2; + dcs_r = 3; + break; + default: + BUG(); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Power on the amplifier */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_ENA | WM8904_HPR_ENA, + WM8904_HPL_ENA | WM8904_HPR_ENA); + + /* Enable the first stage */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY, + WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY); + + /* Power up the DC servo */ + snd_soc_update_bits(codec, WM8904_DC_SERVO_0, + dcs_mask, dcs_mask); + + /* Either calibrate the DC servo or restore cached state + * if we have that. + */ + if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) { + dev_dbg(codec->dev, "Restoring DC servo state\n"); + + snd_soc_write(codec, dcs_l_reg, + wm8904->dcs_state[dcs_l]); + snd_soc_write(codec, dcs_r_reg, + wm8904->dcs_state[dcs_r]); + + snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask); + + timeout = 20; + } else { + dev_dbg(codec->dev, "Calibrating DC servo\n"); + + snd_soc_write(codec, WM8904_DC_SERVO_1, + dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT); + + timeout = 500; + } + + /* Wait for DC servo to complete */ + dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT; + do { + val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0); + if ((val & dcs_mask) == dcs_mask) + break; + + msleep(1); + } while (--timeout); + + if ((val & dcs_mask) != dcs_mask) + dev_warn(codec->dev, "DC servo timed out\n"); + else + dev_dbg(codec->dev, "DC servo ready\n"); + + /* Enable the output stage */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, + WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP); + + /* Unshort the output itself */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_RMV_SHORT | + WM8904_HPR_RMV_SHORT, + WM8904_HPL_RMV_SHORT | + WM8904_HPR_RMV_SHORT); + + break; + + case SND_SOC_DAPM_PRE_PMD: + /* Short the output */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_RMV_SHORT | + WM8904_HPR_RMV_SHORT, 0); + + /* Cache the DC servo configuration; this will be + * invalidated if we change the configuration. */ + wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg); + wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg); + + snd_soc_update_bits(codec, WM8904_DC_SERVO_0, + dcs_mask, 0); + + /* Disable the amplifier input and output stages */ + snd_soc_update_bits(codec, reg, + WM8904_HPL_ENA | WM8904_HPR_ENA | + WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY | + WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, + 0); + break; + } + + return 0; +} + +static const char *lin_text[] = { + "IN1L", "IN2L", "IN3L" +}; + +static const struct soc_enum lin_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text); + +static const struct snd_kcontrol_new lin_mux = + SOC_DAPM_ENUM("Left Capture Mux", lin_enum); + +static const struct soc_enum lin_inv_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text); + +static const struct snd_kcontrol_new lin_inv_mux = + SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); + +static const char *rin_text[] = { + "IN1R", "IN2R", "IN3R" +}; + +static const struct soc_enum rin_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text); + +static const struct snd_kcontrol_new rin_mux = + SOC_DAPM_ENUM("Right Capture Mux", rin_enum); + +static const struct soc_enum rin_inv_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text); + +static const struct snd_kcontrol_new rin_inv_mux = + SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); + +static const char *aif_text[] = { + "Left", "Right" +}; + +static const struct soc_enum aifoutl_enum = + SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text); + +static const struct snd_kcontrol_new aifoutl_mux = + SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); + +static const struct soc_enum aifoutr_enum = + SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text); + +static const struct snd_kcontrol_new aifoutr_mux = + SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); + +static const struct soc_enum aifinl_enum = + SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text); + +static const struct snd_kcontrol_new aifinl_mux = + SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); + +static const struct soc_enum aifinr_enum = + SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text); + +static const struct snd_kcontrol_new aifinr_mux = + SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); + +static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_widget wm8904_adc_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1L"), +SND_SOC_DAPM_INPUT("IN1R"), +SND_SOC_DAPM_INPUT("IN2L"), +SND_SOC_DAPM_INPUT("IN2R"), +SND_SOC_DAPM_INPUT("IN3L"), +SND_SOC_DAPM_INPUT("IN3R"), + +SND_SOC_DAPM_MICBIAS("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0), + +SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux), +SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0, + &lin_inv_mux), +SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux), +SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0, + &rin_inv_mux), + +SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0, + NULL, 0), +SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0, + NULL, 0), + +SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0), +SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0), + +SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux), +SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux), + +SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = { +SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux), +SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux), + +SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0), +SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0), + +SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event, + SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_PGA("HPL PGA", WM8904_POWER_MANAGEMENT_2, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("HPR PGA", WM8904_POWER_MANAGEMENT_2, 0, 0, NULL, 0), + +SND_SOC_DAPM_PGA("LINEL PGA", WM8904_POWER_MANAGEMENT_3, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("LINER PGA", WM8904_POWER_MANAGEMENT_3, 0, 0, NULL, 0), + +SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0, + 0, NULL, 0, out_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0, + 0, NULL, 0, out_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_OUTPUT("HPOUTL"), +SND_SOC_DAPM_OUTPUT("HPOUTR"), +SND_SOC_DAPM_OUTPUT("LINEOUTL"), +SND_SOC_DAPM_OUTPUT("LINEOUTR"), +}; + +static const char *out_mux_text[] = { + "DAC", "Bypass" +}; + +static const struct soc_enum hpl_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text); + +static const struct snd_kcontrol_new hpl_mux = + SOC_DAPM_ENUM("HPL Mux", hpl_enum); + +static const struct soc_enum hpr_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text); + +static const struct snd_kcontrol_new hpr_mux = + SOC_DAPM_ENUM("HPR Mux", hpr_enum); + +static const struct soc_enum linel_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text); + +static const struct snd_kcontrol_new linel_mux = + SOC_DAPM_ENUM("LINEL Mux", linel_enum); + +static const struct soc_enum liner_enum = + SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); + +static const struct snd_kcontrol_new liner_mux = + SOC_DAPM_ENUM("LINEL Mux", liner_enum); + +static const char *sidetone_text[] = { + "None", "Left", "Right" +}; + +static const struct soc_enum dacl_sidetone_enum = + SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text); + +static const struct snd_kcontrol_new dacl_sidetone_mux = + SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); + +static const struct soc_enum dacr_sidetone_enum = + SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text); + +static const struct snd_kcontrol_new dacr_sidetone_mux = + SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); + +static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 0), +SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux), +SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux), + +SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), +SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux), +SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux), +}; + +static const struct snd_soc_dapm_route core_intercon[] = { + { "CLK_DSP", NULL, "SYSCLK" }, + { "TOCLK", NULL, "SYSCLK" }, +}; + +static const struct snd_soc_dapm_route adc_intercon[] = { + { "Left Capture Mux", "IN1L", "IN1L" }, + { "Left Capture Mux", "IN2L", "IN2L" }, + { "Left Capture Mux", "IN3L", "IN3L" }, + + { "Left Capture Inverting Mux", "IN1L", "IN1L" }, + { "Left Capture Inverting Mux", "IN2L", "IN2L" }, + { "Left Capture Inverting Mux", "IN3L", "IN3L" }, + + { "Right Capture Mux", "IN1R", "IN1R" }, + { "Right Capture Mux", "IN2R", "IN2R" }, + { "Right Capture Mux", "IN3R", "IN3R" }, + + { "Right Capture Inverting Mux", "IN1R", "IN1R" }, + { "Right Capture Inverting Mux", "IN2R", "IN2R" }, + { "Right Capture Inverting Mux", "IN3R", "IN3R" }, + + { "Left Capture PGA", NULL, "Left Capture Mux" }, + { "Left Capture PGA", NULL, "Left Capture Inverting Mux" }, + + { "Right Capture PGA", NULL, "Right Capture Mux" }, + { "Right Capture PGA", NULL, "Right Capture Inverting Mux" }, + + { "AIFOUTL", "Left", "ADCL" }, + { "AIFOUTL", "Right", "ADCR" }, + { "AIFOUTR", "Left", "ADCL" }, + { "AIFOUTR", "Right", "ADCR" }, + + { "ADCL", NULL, "CLK_DSP" }, + { "ADCL", NULL, "Left Capture PGA" }, + + { "ADCR", NULL, "CLK_DSP" }, + { "ADCR", NULL, "Right Capture PGA" }, +}; + +static const struct snd_soc_dapm_route dac_intercon[] = { + { "DACL", "Right", "AIFINR" }, + { "DACL", "Left", "AIFINL" }, + { "DACL", NULL, "CLK_DSP" }, + + { "DACR", "Right", "AIFINR" }, + { "DACR", "Left", "AIFINL" }, + { "DACR", NULL, "CLK_DSP" }, + + { "Charge pump", NULL, "SYSCLK" }, + + { "Headphone Output", NULL, "HPL PGA" }, + { "Headphone Output", NULL, "HPR PGA" }, + { "Headphone Output", NULL, "Charge pump" }, + { "Headphone Output", NULL, "TOCLK" }, + + { "Line Output", NULL, "LINEL PGA" }, + { "Line Output", NULL, "LINER PGA" }, + { "Line Output", NULL, "Charge pump" }, + { "Line Output", NULL, "TOCLK" }, + + { "HPOUTL", NULL, "Headphone Output" }, + { "HPOUTR", NULL, "Headphone Output" }, + + { "LINEOUTL", NULL, "Line Output" }, + { "LINEOUTR", NULL, "Line Output" }, +}; + +static const struct snd_soc_dapm_route wm8904_intercon[] = { + { "Left Sidetone", "Left", "ADCL" }, + { "Left Sidetone", "Right", "ADCR" }, + { "DACL", NULL, "Left Sidetone" }, + + { "Right Sidetone", "Left", "ADCL" }, + { "Right Sidetone", "Right", "ADCR" }, + { "DACR", NULL, "Right Sidetone" }, + + { "Left Bypass", NULL, "Class G" }, + { "Left Bypass", NULL, "Left Capture PGA" }, + + { "Right Bypass", NULL, "Class G" }, + { "Right Bypass", NULL, "Right Capture PGA" }, + + { "HPL Mux", "DAC", "DACL" }, + { "HPL Mux", "Bypass", "Left Bypass" }, + + { "HPR Mux", "DAC", "DACR" }, + { "HPR Mux", "Bypass", "Right Bypass" }, + + { "LINEL Mux", "DAC", "DACL" }, + { "LINEL Mux", "Bypass", "Left Bypass" }, + + { "LINER Mux", "DAC", "DACR" }, + { "LINER Mux", "Bypass", "Right Bypass" }, + + { "HPL PGA", NULL, "HPL Mux" }, + { "HPR PGA", NULL, "HPR Mux" }, + + { "LINEL PGA", NULL, "LINEL Mux" }, + { "LINER PGA", NULL, "LINER Mux" }, +}; + +static int wm8904_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_add_controls(codec, wm8904_adc_snd_controls, + ARRAY_SIZE(wm8904_adc_snd_controls)); + snd_soc_add_controls(codec, wm8904_dac_snd_controls, + ARRAY_SIZE(wm8904_dac_snd_controls)); + snd_soc_add_controls(codec, wm8904_snd_controls, + ARRAY_SIZE(wm8904_snd_controls)); + + snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets, + ARRAY_SIZE(wm8904_core_dapm_widgets)); + snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets, + ARRAY_SIZE(wm8904_adc_dapm_widgets)); + snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, + ARRAY_SIZE(wm8904_dac_dapm_widgets)); + snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets, + ARRAY_SIZE(wm8904_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, core_intercon, + ARRAY_SIZE(core_intercon)); + snd_soc_dapm_add_routes(codec, adc_intercon, ARRAY_SIZE(adc_intercon)); + snd_soc_dapm_add_routes(codec, dac_intercon, ARRAY_SIZE(dac_intercon)); + snd_soc_dapm_add_routes(codec, wm8904_intercon, + ARRAY_SIZE(wm8904_intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static struct { + int ratio; + unsigned int clk_sys_rate; +} clk_sys_rates[] = { + { 64, 0 }, + { 128, 1 }, + { 192, 2 }, + { 256, 3 }, + { 384, 4 }, + { 512, 5 }, + { 786, 6 }, + { 1024, 7 }, + { 1408, 8 }, + { 1536, 9 }, +}; + +static struct { + int rate; + int sample_rate; +} sample_rates[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 1 }, + { 16000, 2 }, + { 22050, 3 }, + { 24000, 3 }, + { 32000, 4 }, + { 44100, 5 }, + { 48000, 5 }, +}; + +static struct { + int div; /* *10 due to .5s */ + int bclk_div; +} bclk_divs[] = { + { 10, 0 }, + { 15, 1 }, + { 20, 2 }, + { 30, 3 }, + { 40, 4 }, + { 50, 5 }, + { 55, 6 }, + { 60, 7 }, + { 80, 8 }, + { 100, 9 }, + { 110, 10 }, + { 120, 11 }, + { 160, 12 }, + { 200, 13 }, + { 220, 14 }, + { 240, 16 }, + { 200, 17 }, + { 320, 18 }, + { 440, 19 }, + { 480, 20 }, +}; + + +static int wm8904_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8904_priv *wm8904 = codec->private_data; + int ret, i, best, best_val, cur_val; + unsigned int aif1 = 0; + unsigned int aif2 = 0; + unsigned int aif3 = 0; + unsigned int clock1 = 0; + unsigned int dac_digital1 = 0; + + /* What BCLK do we need? */ + wm8904->fs = params_rate(params); + if (wm8904->tdm_slots) { + dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n", + wm8904->tdm_slots, wm8904->tdm_width); + wm8904->bclk = snd_soc_calc_bclk(wm8904->fs, + wm8904->tdm_width, 2, + wm8904->tdm_slots); + } else { + wm8904->bclk = snd_soc_params_to_bclk(params); + } + + dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk); + + ret = wm8904_configure_clocking(codec); + if (ret != 0) + return ret; + + /* Select nearest CLK_SYS_RATE */ + best = 0; + best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio) + - wm8904->fs); + for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { + cur_val = abs((wm8904->sysclk_rate / + clk_sys_rates[i].ratio) - wm8904->fs);; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", + clk_sys_rates[best].ratio); + clock1 |= (clk_sys_rates[best].clk_sys_rate + << WM8904_CLK_SYS_RATE_SHIFT); + + /* SAMPLE_RATE */ + best = 0; + best_val = abs(wm8904->fs - sample_rates[0].rate); + for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { + /* Closest match */ + cur_val = abs(wm8904->fs - sample_rates[i].rate); + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", + sample_rates[best].rate); + clock1 |= (sample_rates[best].sample_rate + << WM8904_SAMPLE_RATE_SHIFT); + + /* Enable sloping stopband filter for low sample rates */ + if (wm8904->fs <= 24000) + dac_digital1 |= WM8904_DAC_SB_FILT; + + /* BCLK_DIV */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div) + - wm8904->bclk; + if (cur_val < 0) /* Table is sorted */ + break; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div; + dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", + bclk_divs[best].div, wm8904->bclk); + aif2 |= bclk_divs[best].bclk_div; + + /* LRCLK is a simple fraction of BCLK */ + dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs); + aif3 |= wm8904->bclk / wm8904->fs; + + /* Apply the settings */ + snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, + WM8904_DAC_SB_FILT, dac_digital1); + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, + WM8904_AIF_WL_MASK, aif1); + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2, + WM8904_BCLK_DIV_MASK, aif2); + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3, + WM8904_LRCLK_RATE_MASK, aif3); + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1, + WM8904_SAMPLE_RATE_MASK | + WM8904_CLK_SYS_RATE_MASK, clock1); + + /* Update filters for the new settings */ + wm8904_set_retune_mobile(codec); + wm8904_set_deemph(codec); + + return 0; +} + + +static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8904_priv *priv = codec->private_data; + + switch (clk_id) { + case WM8904_CLK_MCLK: + priv->sysclk_src = clk_id; + priv->mclk_rate = freq; + break; + + case WM8904_CLK_FLL: + priv->sysclk_src = clk_id; + break; + + default: + return -EINVAL; + } + + dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); + + wm8904_configure_clocking(codec); + + return 0; +} + +static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int aif1 = 0; + unsigned int aif3 = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBS_CFM: + aif3 |= WM8904_LRCLK_DIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + aif1 |= WM8904_BCLK_DIR; + break; + case SND_SOC_DAIFMT_CBM_CFM: + aif1 |= WM8904_BCLK_DIR; + aif3 |= WM8904_LRCLK_DIR; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif1 |= WM8904_AIF_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif1 |= 0x3; + break; + case SND_SOC_DAIFMT_I2S: + aif1 |= 0x2; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif1 |= 0x1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8904_AIF_BCLK_INV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8904_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif1 |= WM8904_AIF_LRCLK_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, + WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV | + WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1); + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3, + WM8904_LRCLK_DIR, aif3); + + return 0; +} + + +static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8904_priv *wm8904 = codec->private_data; + int aif1 = 0; + + /* Don't need to validate anything if we're turning off TDM */ + if (slots == 0) + goto out; + + /* Note that we allow configurations we can't handle ourselves - + * for example, we can generate clocks for slots 2 and up even if + * we can't use those slots ourselves. + */ + aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM; + + switch (rx_mask) { + case 3: + break; + case 0xc: + aif1 |= WM8904_AIFADC_TDM_CHAN; + break; + default: + return -EINVAL; + } + + + switch (tx_mask) { + case 3: + break; + case 0xc: + aif1 |= WM8904_AIFDAC_TDM_CHAN; + break; + default: + return -EINVAL; + } + +out: + wm8904->tdm_width = slot_width; + wm8904->tdm_slots = slots / 2; + + snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1, + WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN | + WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1); + + return 0; +} + +struct _fll_div { + u16 fll_fratio; + u16 fll_outdiv; + u16 fll_clk_ref_div; + u16 n; + u16 k; +}; + +/* The size in bits of the FLL divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +static struct { + unsigned int min; + unsigned int max; + u16 fll_fratio; + int ratio; +} fll_fratios[] = { + { 0, 64000, 4, 16 }, + { 64000, 128000, 3, 8 }, + { 128000, 256000, 2, 4 }, + { 256000, 1000000, 1, 2 }, + { 1000000, 13500000, 0, 1 }, +}; + +static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, + unsigned int Fout) +{ + u64 Kpart; + unsigned int K, Ndiv, Nmod, target; + unsigned int div; + int i; + + /* Fref must be <=13.5MHz */ + div = 1; + fll_div->fll_clk_ref_div = 0; + while ((Fref / div) > 13500000) { + div *= 2; + fll_div->fll_clk_ref_div++; + + if (div > 8) { + pr_err("Can't scale %dMHz input down to <=13.5MHz\n", + Fref); + return -EINVAL; + } + } + + pr_debug("Fref=%u Fout=%u\n", Fref, Fout); + + /* Apply the division for our remaining calculations */ + Fref /= div; + + /* Fvco should be 90-100MHz; don't check the upper bound */ + div = 4; + while (Fout * div < 90000000) { + div++; + if (div > 64) { + pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", + Fout); + return -EINVAL; + } + } + target = Fout * div; + fll_div->fll_outdiv = div - 1; + + pr_debug("Fvco=%dHz\n", target); + + /* Find an appropraite FLL_FRATIO and factor it out of the target */ + for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { + if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { + fll_div->fll_fratio = fll_fratios[i].fll_fratio; + target /= fll_fratios[i].ratio; + break; + } + } + if (i == ARRAY_SIZE(fll_fratios)) { + pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); + return -EINVAL; + } + + /* Now, calculate N.K */ + Ndiv = target / Fref; + + fll_div->n = Ndiv; + Nmod = target % Fref; + pr_debug("Nmod=%d\n", Nmod); + + /* Calculate fractional part - scale up so we can round. */ + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + + do_div(Kpart, Fref); + + K = Kpart & 0xFFFFFFFF; + + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + fll_div->k = K / 10; + + pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n", + fll_div->n, fll_div->k, + fll_div->fll_fratio, fll_div->fll_outdiv, + fll_div->fll_clk_ref_div); + + return 0; +} + +static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source, + unsigned int Fref, unsigned int Fout) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8904_priv *wm8904 = codec->private_data; + struct _fll_div fll_div; + int ret, val; + int clock2, fll1; + + /* Any change? */ + if (source == wm8904->fll_src && Fref == wm8904->fll_fref && + Fout == wm8904->fll_fout) + return 0; + + if (Fout == 0) { + dev_dbg(codec->dev, "FLL disabled\n"); + + wm8904->fll_fref = 0; + wm8904->fll_fout = 0; + + /* Gate SYSCLK to avoid glitches */ + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_CLK_SYS_ENA, 0); + + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); + + goto out; + } + + /* Validate the FLL ID */ + switch (source) { + case WM8904_FLL_MCLK: + case WM8904_FLL_LRCLK: + case WM8904_FLL_BCLK: + ret = fll_factors(&fll_div, Fref, Fout); + if (ret != 0) + return ret; + break; + + case WM8904_FLL_FREE_RUNNING: + dev_dbg(codec->dev, "Using free running FLL\n"); + /* Force 12MHz and output/4 for now */ + Fout = 12000000; + Fref = 12000000; + + memset(&fll_div, 0, sizeof(fll_div)); + fll_div.fll_outdiv = 3; + break; + + default: + dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id); + return -EINVAL; + } + + /* Save current state then disable the FLL and SYSCLK to avoid + * misclocking */ + clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); + fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1); + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_CLK_SYS_ENA, 0); + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0); + + /* Unlock forced oscilator control to switch it on/off */ + snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1, + WM8904_USER_KEY, WM8904_USER_KEY); + + if (fll_id == WM8904_FLL_FREE_RUNNING) { + val = WM8904_FLL_FRC_NCO; + } else { + val = 0; + } + + snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO, + val); + snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1, + WM8904_USER_KEY, 0); + + switch (fll_id) { + case WM8904_FLL_MCLK: + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, + WM8904_FLL_CLK_REF_SRC_MASK, 0); + break; + + case WM8904_FLL_LRCLK: + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, + WM8904_FLL_CLK_REF_SRC_MASK, 1); + break; + + case WM8904_FLL_BCLK: + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, + WM8904_FLL_CLK_REF_SRC_MASK, 2); + break; + } + + if (fll_div.k) + val = WM8904_FLL_FRACN_ENA; + else + val = 0; + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_FRACN_ENA, val); + + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2, + WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK, + (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) | + (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT)); + + snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k); + + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK, + fll_div.n << WM8904_FLL_N_SHIFT); + + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5, + WM8904_FLL_CLK_REF_DIV_MASK, + fll_div.fll_clk_ref_div + << WM8904_FLL_CLK_REF_DIV_SHIFT); + + dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); + + wm8904->fll_fref = Fref; + wm8904->fll_fout = Fout; + wm8904->fll_src = source; + + /* Enable the FLL if it was previously active */ + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_OSC_ENA, fll1); + snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1, + WM8904_FLL_ENA, fll1); + +out: + /* Reenable SYSCLK if it was previously active */ + snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, + WM8904_CLK_SYS_ENA, clock2); + + return 0; +} + +static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int val; + + if (mute) + val = WM8904_DAC_MUTE; + else + val = 0; + + snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val); + + return 0; +} + +static int wm8904_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8904_priv *wm8904 = codec->private_data; + int ret, i; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VMID resistance 2*50k */ + snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, + WM8904_VMID_RES_MASK, + 0x1 << WM8904_VMID_RES_SHIFT); + + /* Normal bias current */ + snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, + WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + + /* Sync back cached values if they're + * different from the hardware default. + */ + for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { + if (!wm8904_access[i].writable) + continue; + + if (wm8904->reg_cache[i] == wm8904_reg[i]) + continue; + + snd_soc_write(codec, i, wm8904->reg_cache[i]); + } + + /* Enable bias */ + snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, + WM8904_BIAS_ENA, WM8904_BIAS_ENA); + + /* Enable VMID, VMID buffering, 2*5k resistance */ + snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, + WM8904_VMID_ENA | + WM8904_VMID_RES_MASK, + WM8904_VMID_ENA | + 0x3 << WM8904_VMID_RES_SHIFT); + + /* Let VMID ramp */ + msleep(1); + } + + /* Maintain VMID with 2*250k */ + snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, + WM8904_VMID_RES_MASK, + 0x2 << WM8904_VMID_RES_SHIFT); + + /* Bias current *0.5 */ + snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, + WM8904_ISEL_MASK, 0); + break; + + case SND_SOC_BIAS_OFF: + /* Turn off VMID */ + snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0, + WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0); + + /* Stop bias generation */ + snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, + WM8904_BIAS_ENA, 0); + + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8904_RATES SNDRV_PCM_RATE_8000_96000 + +#define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8904_dai_ops = { + .set_sysclk = wm8904_set_sysclk, + .set_fmt = wm8904_set_fmt, + .set_tdm_slot = wm8904_set_tdm_slot, + .set_pll = wm8904_set_fll, + .hw_params = wm8904_hw_params, + .digital_mute = wm8904_digital_mute, +}; + +struct snd_soc_dai wm8904_dai = { + .name = "WM8904", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8904_RATES, + .formats = WM8904_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM8904_RATES, + .formats = WM8904_FORMATS, + }, + .ops = &wm8904_dai_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(wm8904_dai); + +#ifdef CONFIG_PM +static int wm8904_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8904_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm8904_suspend NULL +#define wm8904_resume NULL +#endif + +static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904) +{ + struct snd_soc_codec *codec = &wm8904->codec; + struct wm8904_pdata *pdata = wm8904->pdata; + struct snd_kcontrol_new control = + SOC_ENUM_EXT("EQ Mode", + wm8904->retune_mobile_enum, + wm8904_get_retune_mobile_enum, + wm8904_put_retune_mobile_enum); + int ret, i, j; + const char **t; + + /* We need an array of texts for the enum API but the number + * of texts is likely to be less than the number of + * configurations due to the sample rate dependency of the + * configurations. */ + wm8904->num_retune_mobile_texts = 0; + wm8904->retune_mobile_texts = NULL; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + for (j = 0; j < wm8904->num_retune_mobile_texts; j++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8904->retune_mobile_texts[j]) == 0) + break; + } + + if (j != wm8904->num_retune_mobile_texts) + continue; + + /* Expand the array... */ + t = krealloc(wm8904->retune_mobile_texts, + sizeof(char *) * + (wm8904->num_retune_mobile_texts + 1), + GFP_KERNEL); + if (t == NULL) + continue; + + /* ...store the new entry... */ + t[wm8904->num_retune_mobile_texts] = + pdata->retune_mobile_cfgs[i].name; + + /* ...and remember the new version. */ + wm8904->num_retune_mobile_texts++; + wm8904->retune_mobile_texts = t; + } + + dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", + wm8904->num_retune_mobile_texts); + + wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; + wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; + + ret = snd_soc_add_controls(&wm8904->codec, &control, 1); + if (ret != 0) + dev_err(wm8904->codec.dev, + "Failed to add ReTune Mobile control: %d\n", ret); +} + +static void wm8904_handle_pdata(struct wm8904_priv *wm8904) +{ + struct snd_soc_codec *codec = &wm8904->codec; + struct wm8904_pdata *pdata = wm8904->pdata; + int ret, i; + + if (!pdata) { + snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls, + ARRAY_SIZE(wm8904_eq_controls)); + return; + } + + dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs); + + if (pdata->num_drc_cfgs) { + struct snd_kcontrol_new control = + SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum, + wm8904_get_drc_enum, wm8904_put_drc_enum); + + /* We need an array of texts for the enum API */ + wm8904->drc_texts = kmalloc(sizeof(char *) + * pdata->num_drc_cfgs, GFP_KERNEL); + if (!wm8904->drc_texts) { + dev_err(wm8904->codec.dev, + "Failed to allocate %d DRC config texts\n", + pdata->num_drc_cfgs); + return; + } + + for (i = 0; i < pdata->num_drc_cfgs; i++) + wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; + + wm8904->drc_enum.max = pdata->num_drc_cfgs; + wm8904->drc_enum.texts = wm8904->drc_texts; + + ret = snd_soc_add_controls(&wm8904->codec, &control, 1); + if (ret != 0) + dev_err(wm8904->codec.dev, + "Failed to add DRC mode control: %d\n", ret); + + wm8904_set_drc(codec); + } + + dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", + pdata->num_retune_mobile_cfgs); + + if (pdata->num_retune_mobile_cfgs) + wm8904_handle_retune_mobile_pdata(wm8904); + else + snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls, + ARRAY_SIZE(wm8904_eq_controls)); +} + +static int wm8904_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8904_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8904_codec; + codec = wm8904_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + wm8904_handle_pdata(codec->private_data); + + wm8904_add_widgets(codec); + + return ret; + +pcm_err: + return ret; +} + +static int wm8904_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8904 = { + .probe = wm8904_probe, + .remove = wm8904_remove, + .suspend = wm8904_suspend, + .resume = wm8904_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904); + +static int wm8904_register(struct wm8904_priv *wm8904, + enum snd_soc_control_type control) +{ + int ret; + struct snd_soc_codec *codec = &wm8904->codec; + int i; + + if (wm8904_codec) { + dev_err(codec->dev, "Another WM8904 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8904; + codec->name = "WM8904"; + codec->owner = THIS_MODULE; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8904_set_bias_level; + codec->dai = &wm8904_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8904_MAX_REGISTER; + codec->reg_cache = &wm8904->reg_cache; + codec->volatile_register = wm8904_volatile_register; + + memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); + + ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) + wm8904->supplies[i].supply = wm8904_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + + ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID); + if (ret < 0) { + dev_err(codec->dev, "Failed to read ID register\n"); + goto err_enable; + } + if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) { + dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret); + ret = -EINVAL; + goto err_enable; + } + + ret = snd_soc_read(codec, WM8904_REVISION); + if (ret < 0) { + dev_err(codec->dev, "Failed to read device revision: %d\n", + ret); + goto err_enable; + } + dev_info(codec->dev, "revision %c\n", ret + 'A'); + + ret = wm8904_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err_enable; + } + + wm8904_dai.dev = codec->dev; + + /* Change some default settings - latch VU and enable ZC */ + wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU; + wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU; + wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU; + wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU; + wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU | + WM8904_HPOUTLZC; + wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU | + WM8904_HPOUTRZC; + wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU | + WM8904_LINEOUTLZC; + wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU | + WM8904_LINEOUTRZC; + wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE; + + /* Set Class W by default - this will be managed by the Class + * G widget at runtime where bypass paths are available. + */ + wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR; + + /* Use normal bias source */ + wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL; + + wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Bias level configuration will have done an extra enable */ + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); + + wm8904_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8904_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); +err: + kfree(wm8904); + return ret; +} + +static void wm8904_unregister(struct wm8904_priv *wm8904) +{ + wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF); + regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); + snd_soc_unregister_dai(&wm8904_dai); + snd_soc_unregister_codec(&wm8904->codec); + kfree(wm8904); + wm8904_codec = NULL; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8904_priv *wm8904; + struct snd_soc_codec *codec; + + wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL); + if (wm8904 == NULL) + return -ENOMEM; + + codec = &wm8904->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8904); + codec->control_data = i2c; + wm8904->pdata = i2c->dev.platform_data; + + codec->dev = &i2c->dev; + + return wm8904_register(wm8904, SND_SOC_I2C); +} + +static __devexit int wm8904_i2c_remove(struct i2c_client *client) +{ + struct wm8904_priv *wm8904 = i2c_get_clientdata(client); + wm8904_unregister(wm8904); + return 0; +} + +static const struct i2c_device_id wm8904_i2c_id[] = { + { "wm8904", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); + +static struct i2c_driver wm8904_i2c_driver = { + .driver = { + .name = "WM8904", + .owner = THIS_MODULE, + }, + .probe = wm8904_i2c_probe, + .remove = __devexit_p(wm8904_i2c_remove), + .id_table = wm8904_i2c_id, +}; +#endif + +static int __init wm8904_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8904_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n", + ret); + } +#endif + return 0; +} +module_init(wm8904_modinit); + +static void __exit wm8904_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8904_i2c_driver); +#endif +} +module_exit(wm8904_exit); + +MODULE_DESCRIPTION("ASoC WM8904 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h new file mode 100644 index 000000000000..b68886df34e4 --- /dev/null +++ b/sound/soc/codecs/wm8904.h @@ -0,0 +1,1681 @@ +/* + * wm8904.h -- WM8904 ASoC driver + * + * Copyright 2009 Wolfson Microelectronics, plc + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8904_H +#define _WM8904_H + +#define WM8904_CLK_MCLK 1 +#define WM8904_CLK_FLL 2 + +#define WM8904_FLL_MCLK 1 +#define WM8904_FLL_BCLK 2 +#define WM8904_FLL_LRCLK 3 +#define WM8904_FLL_FREE_RUNNING 4 + +extern struct snd_soc_dai wm8904_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8904; + +/* + * Register values. + */ +#define WM8904_SW_RESET_AND_ID 0x00 +#define WM8904_REVISION 0x01 +#define WM8904_BIAS_CONTROL_0 0x04 +#define WM8904_VMID_CONTROL_0 0x05 +#define WM8904_MIC_BIAS_CONTROL_0 0x06 +#define WM8904_MIC_BIAS_CONTROL_1 0x07 +#define WM8904_ANALOGUE_DAC_0 0x08 +#define WM8904_MIC_FILTER_CONTROL 0x09 +#define WM8904_ANALOGUE_ADC_0 0x0A +#define WM8904_POWER_MANAGEMENT_0 0x0C +#define WM8904_POWER_MANAGEMENT_2 0x0E +#define WM8904_POWER_MANAGEMENT_3 0x0F +#define WM8904_POWER_MANAGEMENT_6 0x12 +#define WM8904_CLOCK_RATES_0 0x14 +#define WM8904_CLOCK_RATES_1 0x15 +#define WM8904_CLOCK_RATES_2 0x16 +#define WM8904_AUDIO_INTERFACE_0 0x18 +#define WM8904_AUDIO_INTERFACE_1 0x19 +#define WM8904_AUDIO_INTERFACE_2 0x1A +#define WM8904_AUDIO_INTERFACE_3 0x1B +#define WM8904_DAC_DIGITAL_VOLUME_LEFT 0x1E +#define WM8904_DAC_DIGITAL_VOLUME_RIGHT 0x1F +#define WM8904_DAC_DIGITAL_0 0x20 +#define WM8904_DAC_DIGITAL_1 0x21 +#define WM8904_ADC_DIGITAL_VOLUME_LEFT 0x24 +#define WM8904_ADC_DIGITAL_VOLUME_RIGHT 0x25 +#define WM8904_ADC_DIGITAL_0 0x26 +#define WM8904_DIGITAL_MICROPHONE_0 0x27 +#define WM8904_DRC_0 0x28 +#define WM8904_DRC_1 0x29 +#define WM8904_DRC_2 0x2A +#define WM8904_DRC_3 0x2B +#define WM8904_ANALOGUE_LEFT_INPUT_0 0x2C +#define WM8904_ANALOGUE_RIGHT_INPUT_0 0x2D +#define WM8904_ANALOGUE_LEFT_INPUT_1 0x2E +#define WM8904_ANALOGUE_RIGHT_INPUT_1 0x2F +#define WM8904_ANALOGUE_OUT1_LEFT 0x39 +#define WM8904_ANALOGUE_OUT1_RIGHT 0x3A +#define WM8904_ANALOGUE_OUT2_LEFT 0x3B +#define WM8904_ANALOGUE_OUT2_RIGHT 0x3C +#define WM8904_ANALOGUE_OUT12_ZC 0x3D +#define WM8904_DC_SERVO_0 0x43 +#define WM8904_DC_SERVO_1 0x44 +#define WM8904_DC_SERVO_2 0x45 +#define WM8904_DC_SERVO_4 0x47 +#define WM8904_DC_SERVO_5 0x48 +#define WM8904_DC_SERVO_6 0x49 +#define WM8904_DC_SERVO_7 0x4A +#define WM8904_DC_SERVO_8 0x4B +#define WM8904_DC_SERVO_9 0x4C +#define WM8904_DC_SERVO_READBACK_0 0x4D +#define WM8904_ANALOGUE_HP_0 0x5A +#define WM8904_ANALOGUE_LINEOUT_0 0x5E +#define WM8904_CHARGE_PUMP_0 0x62 +#define WM8904_CLASS_W_0 0x68 +#define WM8904_WRITE_SEQUENCER_0 0x6C +#define WM8904_WRITE_SEQUENCER_1 0x6D +#define WM8904_WRITE_SEQUENCER_2 0x6E +#define WM8904_WRITE_SEQUENCER_3 0x6F +#define WM8904_WRITE_SEQUENCER_4 0x70 +#define WM8904_FLL_CONTROL_1 0x74 +#define WM8904_FLL_CONTROL_2 0x75 +#define WM8904_FLL_CONTROL_3 0x76 +#define WM8904_FLL_CONTROL_4 0x77 +#define WM8904_FLL_CONTROL_5 0x78 +#define WM8904_GPIO_CONTROL_1 0x79 +#define WM8904_GPIO_CONTROL_2 0x7A +#define WM8904_GPIO_CONTROL_3 0x7B +#define WM8904_GPIO_CONTROL_4 0x7C +#define WM8904_DIGITAL_PULLS 0x7E +#define WM8904_INTERRUPT_STATUS 0x7F +#define WM8904_INTERRUPT_STATUS_MASK 0x80 +#define WM8904_INTERRUPT_POLARITY 0x81 +#define WM8904_INTERRUPT_DEBOUNCE 0x82 +#define WM8904_EQ1 0x86 +#define WM8904_EQ2 0x87 +#define WM8904_EQ3 0x88 +#define WM8904_EQ4 0x89 +#define WM8904_EQ5 0x8A +#define WM8904_EQ6 0x8B +#define WM8904_EQ7 0x8C +#define WM8904_EQ8 0x8D +#define WM8904_EQ9 0x8E +#define WM8904_EQ10 0x8F +#define WM8904_EQ11 0x90 +#define WM8904_EQ12 0x91 +#define WM8904_EQ13 0x92 +#define WM8904_EQ14 0x93 +#define WM8904_EQ15 0x94 +#define WM8904_EQ16 0x95 +#define WM8904_EQ17 0x96 +#define WM8904_EQ18 0x97 +#define WM8904_EQ19 0x98 +#define WM8904_EQ20 0x99 +#define WM8904_EQ21 0x9A +#define WM8904_EQ22 0x9B +#define WM8904_EQ23 0x9C +#define WM8904_EQ24 0x9D +#define WM8904_CONTROL_INTERFACE_TEST_1 0xA1 +#define WM8904_ANALOGUE_OUTPUT_BIAS_0 0xCC +#define WM8904_FLL_NCO_TEST_0 0xF7 +#define WM8904_FLL_NCO_TEST_1 0xF8 + +#define WM8904_REGISTER_COUNT 101 +#define WM8904_MAX_REGISTER 0xF8 + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - SW Reset and ID + */ +#define WM8904_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ +#define WM8904_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ +#define WM8904_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ + +/* + * R1 (0x01) - Revision + */ +#define WM8904_REVISION_MASK 0x000F /* REVISION - [3:0] */ +#define WM8904_REVISION_SHIFT 0 /* REVISION - [3:0] */ +#define WM8904_REVISION_WIDTH 16 /* REVISION - [3:0] */ + +/* + * R4 (0x04) - Bias Control 0 + */ +#define WM8904_POBCTRL 0x0010 /* POBCTRL */ +#define WM8904_POBCTRL_MASK 0x0010 /* POBCTRL */ +#define WM8904_POBCTRL_SHIFT 4 /* POBCTRL */ +#define WM8904_POBCTRL_WIDTH 1 /* POBCTRL */ +#define WM8904_ISEL_MASK 0x000C /* ISEL - [3:2] */ +#define WM8904_ISEL_SHIFT 2 /* ISEL - [3:2] */ +#define WM8904_ISEL_WIDTH 2 /* ISEL - [3:2] */ +#define WM8904_STARTUP_BIAS_ENA 0x0002 /* STARTUP_BIAS_ENA */ +#define WM8904_STARTUP_BIAS_ENA_MASK 0x0002 /* STARTUP_BIAS_ENA */ +#define WM8904_STARTUP_BIAS_ENA_SHIFT 1 /* STARTUP_BIAS_ENA */ +#define WM8904_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ +#define WM8904_BIAS_ENA 0x0001 /* BIAS_ENA */ +#define WM8904_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ +#define WM8904_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ +#define WM8904_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ + +/* + * R5 (0x05) - VMID Control 0 + */ +#define WM8904_VMID_BUF_ENA 0x0040 /* VMID_BUF_ENA */ +#define WM8904_VMID_BUF_ENA_MASK 0x0040 /* VMID_BUF_ENA */ +#define WM8904_VMID_BUF_ENA_SHIFT 6 /* VMID_BUF_ENA */ +#define WM8904_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ +#define WM8904_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */ +#define WM8904_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */ +#define WM8904_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */ +#define WM8904_VMID_ENA 0x0001 /* VMID_ENA */ +#define WM8904_VMID_ENA_MASK 0x0001 /* VMID_ENA */ +#define WM8904_VMID_ENA_SHIFT 0 /* VMID_ENA */ +#define WM8904_VMID_ENA_WIDTH 1 /* VMID_ENA */ + +/* + * R6 (0x06) - Mic Bias Control 0 + */ +#define WM8904_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */ +#define WM8904_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */ +#define WM8904_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */ +#define WM8904_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */ +#define WM8904_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */ +#define WM8904_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */ +#define WM8904_MICDET_ENA 0x0002 /* MICDET_ENA */ +#define WM8904_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */ +#define WM8904_MICDET_ENA_SHIFT 1 /* MICDET_ENA */ +#define WM8904_MICDET_ENA_WIDTH 1 /* MICDET_ENA */ +#define WM8904_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */ +#define WM8904_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */ +#define WM8904_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */ +#define WM8904_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ + +/* + * R7 (0x07) - Mic Bias Control 1 + */ +#define WM8904_MIC_DET_FILTER_ENA 0x8000 /* MIC_DET_FILTER_ENA */ +#define WM8904_MIC_DET_FILTER_ENA_MASK 0x8000 /* MIC_DET_FILTER_ENA */ +#define WM8904_MIC_DET_FILTER_ENA_SHIFT 15 /* MIC_DET_FILTER_ENA */ +#define WM8904_MIC_DET_FILTER_ENA_WIDTH 1 /* MIC_DET_FILTER_ENA */ +#define WM8904_MIC_SHORT_FILTER_ENA 0x4000 /* MIC_SHORT_FILTER_ENA */ +#define WM8904_MIC_SHORT_FILTER_ENA_MASK 0x4000 /* MIC_SHORT_FILTER_ENA */ +#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT 14 /* MIC_SHORT_FILTER_ENA */ +#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH 1 /* MIC_SHORT_FILTER_ENA */ +#define WM8904_MICBIAS_SEL_MASK 0x0007 /* MICBIAS_SEL - [2:0] */ +#define WM8904_MICBIAS_SEL_SHIFT 0 /* MICBIAS_SEL - [2:0] */ +#define WM8904_MICBIAS_SEL_WIDTH 3 /* MICBIAS_SEL - [2:0] */ + +/* + * R8 (0x08) - Analogue DAC 0 + */ +#define WM8904_DAC_BIAS_SEL_MASK 0x0018 /* DAC_BIAS_SEL - [4:3] */ +#define WM8904_DAC_BIAS_SEL_SHIFT 3 /* DAC_BIAS_SEL - [4:3] */ +#define WM8904_DAC_BIAS_SEL_WIDTH 2 /* DAC_BIAS_SEL - [4:3] */ +#define WM8904_DAC_VMID_BIAS_SEL_MASK 0x0006 /* DAC_VMID_BIAS_SEL - [2:1] */ +#define WM8904_DAC_VMID_BIAS_SEL_SHIFT 1 /* DAC_VMID_BIAS_SEL - [2:1] */ +#define WM8904_DAC_VMID_BIAS_SEL_WIDTH 2 /* DAC_VMID_BIAS_SEL - [2:1] */ + +/* + * R9 (0x09) - mic Filter Control + */ +#define WM8904_MIC_DET_SET_THRESHOLD_MASK 0xF000 /* MIC_DET_SET_THRESHOLD - [15:12] */ +#define WM8904_MIC_DET_SET_THRESHOLD_SHIFT 12 /* MIC_DET_SET_THRESHOLD - [15:12] */ +#define WM8904_MIC_DET_SET_THRESHOLD_WIDTH 4 /* MIC_DET_SET_THRESHOLD - [15:12] */ +#define WM8904_MIC_DET_RESET_THRESHOLD_MASK 0x0F00 /* MIC_DET_RESET_THRESHOLD - [11:8] */ +#define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT 8 /* MIC_DET_RESET_THRESHOLD - [11:8] */ +#define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH 4 /* MIC_DET_RESET_THRESHOLD - [11:8] */ +#define WM8904_MIC_SHORT_SET_THRESHOLD_MASK 0x00F0 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ +#define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ +#define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */ +#define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK 0x000F /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ +#define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT 0 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ +#define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH 4 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */ + +/* + * R10 (0x0A) - Analogue ADC 0 + */ +#define WM8904_ADC_OSR128 0x0001 /* ADC_OSR128 */ +#define WM8904_ADC_OSR128_MASK 0x0001 /* ADC_OSR128 */ +#define WM8904_ADC_OSR128_SHIFT 0 /* ADC_OSR128 */ +#define WM8904_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ + +/* + * R12 (0x0C) - Power Management 0 + */ +#define WM8904_INL_ENA 0x0002 /* INL_ENA */ +#define WM8904_INL_ENA_MASK 0x0002 /* INL_ENA */ +#define WM8904_INL_ENA_SHIFT 1 /* INL_ENA */ +#define WM8904_INL_ENA_WIDTH 1 /* INL_ENA */ +#define WM8904_INR_ENA 0x0001 /* INR_ENA */ +#define WM8904_INR_ENA_MASK 0x0001 /* INR_ENA */ +#define WM8904_INR_ENA_SHIFT 0 /* INR_ENA */ +#define WM8904_INR_ENA_WIDTH 1 /* INR_ENA */ + +/* + * R14 (0x0E) - Power Management 2 + */ +#define WM8904_HPL_PGA_ENA 0x0002 /* HPL_PGA_ENA */ +#define WM8904_HPL_PGA_ENA_MASK 0x0002 /* HPL_PGA_ENA */ +#define WM8904_HPL_PGA_ENA_SHIFT 1 /* HPL_PGA_ENA */ +#define WM8904_HPL_PGA_ENA_WIDTH 1 /* HPL_PGA_ENA */ +#define WM8904_HPR_PGA_ENA 0x0001 /* HPR_PGA_ENA */ +#define WM8904_HPR_PGA_ENA_MASK 0x0001 /* HPR_PGA_ENA */ +#define WM8904_HPR_PGA_ENA_SHIFT 0 /* HPR_PGA_ENA */ +#define WM8904_HPR_PGA_ENA_WIDTH 1 /* HPR_PGA_ENA */ + +/* + * R15 (0x0F) - Power Management 3 + */ +#define WM8904_LINEOUTL_PGA_ENA 0x0002 /* LINEOUTL_PGA_ENA */ +#define WM8904_LINEOUTL_PGA_ENA_MASK 0x0002 /* LINEOUTL_PGA_ENA */ +#define WM8904_LINEOUTL_PGA_ENA_SHIFT 1 /* LINEOUTL_PGA_ENA */ +#define WM8904_LINEOUTL_PGA_ENA_WIDTH 1 /* LINEOUTL_PGA_ENA */ +#define WM8904_LINEOUTR_PGA_ENA 0x0001 /* LINEOUTR_PGA_ENA */ +#define WM8904_LINEOUTR_PGA_ENA_MASK 0x0001 /* LINEOUTR_PGA_ENA */ +#define WM8904_LINEOUTR_PGA_ENA_SHIFT 0 /* LINEOUTR_PGA_ENA */ +#define WM8904_LINEOUTR_PGA_ENA_WIDTH 1 /* LINEOUTR_PGA_ENA */ + +/* + * R18 (0x12) - Power Management 6 + */ +#define WM8904_DACL_ENA 0x0008 /* DACL_ENA */ +#define WM8904_DACL_ENA_MASK 0x0008 /* DACL_ENA */ +#define WM8904_DACL_ENA_SHIFT 3 /* DACL_ENA */ +#define WM8904_DACL_ENA_WIDTH 1 /* DACL_ENA */ +#define WM8904_DACR_ENA 0x0004 /* DACR_ENA */ +#define WM8904_DACR_ENA_MASK 0x0004 /* DACR_ENA */ +#define WM8904_DACR_ENA_SHIFT 2 /* DACR_ENA */ +#define WM8904_DACR_ENA_WIDTH 1 /* DACR_ENA */ +#define WM8904_ADCL_ENA 0x0002 /* ADCL_ENA */ +#define WM8904_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ +#define WM8904_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ +#define WM8904_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ +#define WM8904_ADCR_ENA 0x0001 /* ADCR_ENA */ +#define WM8904_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ +#define WM8904_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ +#define WM8904_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ + +/* + * R20 (0x14) - Clock Rates 0 + */ +#define WM8904_TOCLK_RATE_DIV16 0x4000 /* TOCLK_RATE_DIV16 */ +#define WM8904_TOCLK_RATE_DIV16_MASK 0x4000 /* TOCLK_RATE_DIV16 */ +#define WM8904_TOCLK_RATE_DIV16_SHIFT 14 /* TOCLK_RATE_DIV16 */ +#define WM8904_TOCLK_RATE_DIV16_WIDTH 1 /* TOCLK_RATE_DIV16 */ +#define WM8904_TOCLK_RATE_X4 0x2000 /* TOCLK_RATE_X4 */ +#define WM8904_TOCLK_RATE_X4_MASK 0x2000 /* TOCLK_RATE_X4 */ +#define WM8904_TOCLK_RATE_X4_SHIFT 13 /* TOCLK_RATE_X4 */ +#define WM8904_TOCLK_RATE_X4_WIDTH 1 /* TOCLK_RATE_X4 */ +#define WM8904_SR_MODE 0x1000 /* SR_MODE */ +#define WM8904_SR_MODE_MASK 0x1000 /* SR_MODE */ +#define WM8904_SR_MODE_SHIFT 12 /* SR_MODE */ +#define WM8904_SR_MODE_WIDTH 1 /* SR_MODE */ +#define WM8904_MCLK_DIV 0x0001 /* MCLK_DIV */ +#define WM8904_MCLK_DIV_MASK 0x0001 /* MCLK_DIV */ +#define WM8904_MCLK_DIV_SHIFT 0 /* MCLK_DIV */ +#define WM8904_MCLK_DIV_WIDTH 1 /* MCLK_DIV */ + +/* + * R21 (0x15) - Clock Rates 1 + */ +#define WM8904_CLK_SYS_RATE_MASK 0x3C00 /* CLK_SYS_RATE - [13:10] */ +#define WM8904_CLK_SYS_RATE_SHIFT 10 /* CLK_SYS_RATE - [13:10] */ +#define WM8904_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [13:10] */ +#define WM8904_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */ +#define WM8904_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */ +#define WM8904_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */ + +/* + * R22 (0x16) - Clock Rates 2 + */ +#define WM8904_MCLK_INV 0x8000 /* MCLK_INV */ +#define WM8904_MCLK_INV_MASK 0x8000 /* MCLK_INV */ +#define WM8904_MCLK_INV_SHIFT 15 /* MCLK_INV */ +#define WM8904_MCLK_INV_WIDTH 1 /* MCLK_INV */ +#define WM8904_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ +#define WM8904_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */ +#define WM8904_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */ +#define WM8904_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */ +#define WM8904_TOCLK_RATE 0x1000 /* TOCLK_RATE */ +#define WM8904_TOCLK_RATE_MASK 0x1000 /* TOCLK_RATE */ +#define WM8904_TOCLK_RATE_SHIFT 12 /* TOCLK_RATE */ +#define WM8904_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */ +#define WM8904_OPCLK_ENA 0x0008 /* OPCLK_ENA */ +#define WM8904_OPCLK_ENA_MASK 0x0008 /* OPCLK_ENA */ +#define WM8904_OPCLK_ENA_SHIFT 3 /* OPCLK_ENA */ +#define WM8904_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */ +#define WM8904_CLK_SYS_ENA 0x0004 /* CLK_SYS_ENA */ +#define WM8904_CLK_SYS_ENA_MASK 0x0004 /* CLK_SYS_ENA */ +#define WM8904_CLK_SYS_ENA_SHIFT 2 /* CLK_SYS_ENA */ +#define WM8904_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ +#define WM8904_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ +#define WM8904_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ +#define WM8904_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ +#define WM8904_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ +#define WM8904_TOCLK_ENA 0x0001 /* TOCLK_ENA */ +#define WM8904_TOCLK_ENA_MASK 0x0001 /* TOCLK_ENA */ +#define WM8904_TOCLK_ENA_SHIFT 0 /* TOCLK_ENA */ +#define WM8904_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */ + +/* + * R24 (0x18) - Audio Interface 0 + */ +#define WM8904_DACL_DATINV 0x1000 /* DACL_DATINV */ +#define WM8904_DACL_DATINV_MASK 0x1000 /* DACL_DATINV */ +#define WM8904_DACL_DATINV_SHIFT 12 /* DACL_DATINV */ +#define WM8904_DACL_DATINV_WIDTH 1 /* DACL_DATINV */ +#define WM8904_DACR_DATINV 0x0800 /* DACR_DATINV */ +#define WM8904_DACR_DATINV_MASK 0x0800 /* DACR_DATINV */ +#define WM8904_DACR_DATINV_SHIFT 11 /* DACR_DATINV */ +#define WM8904_DACR_DATINV_WIDTH 1 /* DACR_DATINV */ +#define WM8904_DAC_BOOST_MASK 0x0600 /* DAC_BOOST - [10:9] */ +#define WM8904_DAC_BOOST_SHIFT 9 /* DAC_BOOST - [10:9] */ +#define WM8904_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [10:9] */ +#define WM8904_LOOPBACK 0x0100 /* LOOPBACK */ +#define WM8904_LOOPBACK_MASK 0x0100 /* LOOPBACK */ +#define WM8904_LOOPBACK_SHIFT 8 /* LOOPBACK */ +#define WM8904_LOOPBACK_WIDTH 1 /* LOOPBACK */ +#define WM8904_AIFADCL_SRC 0x0080 /* AIFADCL_SRC */ +#define WM8904_AIFADCL_SRC_MASK 0x0080 /* AIFADCL_SRC */ +#define WM8904_AIFADCL_SRC_SHIFT 7 /* AIFADCL_SRC */ +#define WM8904_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */ +#define WM8904_AIFADCR_SRC 0x0040 /* AIFADCR_SRC */ +#define WM8904_AIFADCR_SRC_MASK 0x0040 /* AIFADCR_SRC */ +#define WM8904_AIFADCR_SRC_SHIFT 6 /* AIFADCR_SRC */ +#define WM8904_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */ +#define WM8904_AIFDACL_SRC 0x0020 /* AIFDACL_SRC */ +#define WM8904_AIFDACL_SRC_MASK 0x0020 /* AIFDACL_SRC */ +#define WM8904_AIFDACL_SRC_SHIFT 5 /* AIFDACL_SRC */ +#define WM8904_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */ +#define WM8904_AIFDACR_SRC 0x0010 /* AIFDACR_SRC */ +#define WM8904_AIFDACR_SRC_MASK 0x0010 /* AIFDACR_SRC */ +#define WM8904_AIFDACR_SRC_SHIFT 4 /* AIFDACR_SRC */ +#define WM8904_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */ +#define WM8904_ADC_COMP 0x0008 /* ADC_COMP */ +#define WM8904_ADC_COMP_MASK 0x0008 /* ADC_COMP */ +#define WM8904_ADC_COMP_SHIFT 3 /* ADC_COMP */ +#define WM8904_ADC_COMP_WIDTH 1 /* ADC_COMP */ +#define WM8904_ADC_COMPMODE 0x0004 /* ADC_COMPMODE */ +#define WM8904_ADC_COMPMODE_MASK 0x0004 /* ADC_COMPMODE */ +#define WM8904_ADC_COMPMODE_SHIFT 2 /* ADC_COMPMODE */ +#define WM8904_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */ +#define WM8904_DAC_COMP 0x0002 /* DAC_COMP */ +#define WM8904_DAC_COMP_MASK 0x0002 /* DAC_COMP */ +#define WM8904_DAC_COMP_SHIFT 1 /* DAC_COMP */ +#define WM8904_DAC_COMP_WIDTH 1 /* DAC_COMP */ +#define WM8904_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ +#define WM8904_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ +#define WM8904_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ +#define WM8904_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ + +/* + * R25 (0x19) - Audio Interface 1 + */ +#define WM8904_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ +#define WM8904_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */ +#define WM8904_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */ +#define WM8904_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */ +#define WM8904_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ +#define WM8904_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */ +#define WM8904_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */ +#define WM8904_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */ +#define WM8904_AIFADC_TDM 0x0800 /* AIFADC_TDM */ +#define WM8904_AIFADC_TDM_MASK 0x0800 /* AIFADC_TDM */ +#define WM8904_AIFADC_TDM_SHIFT 11 /* AIFADC_TDM */ +#define WM8904_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */ +#define WM8904_AIFADC_TDM_CHAN 0x0400 /* AIFADC_TDM_CHAN */ +#define WM8904_AIFADC_TDM_CHAN_MASK 0x0400 /* AIFADC_TDM_CHAN */ +#define WM8904_AIFADC_TDM_CHAN_SHIFT 10 /* AIFADC_TDM_CHAN */ +#define WM8904_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */ +#define WM8904_AIF_TRIS 0x0100 /* AIF_TRIS */ +#define WM8904_AIF_TRIS_MASK 0x0100 /* AIF_TRIS */ +#define WM8904_AIF_TRIS_SHIFT 8 /* AIF_TRIS */ +#define WM8904_AIF_TRIS_WIDTH 1 /* AIF_TRIS */ +#define WM8904_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ +#define WM8904_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ +#define WM8904_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ +#define WM8904_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ +#define WM8904_BCLK_DIR 0x0040 /* BCLK_DIR */ +#define WM8904_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ +#define WM8904_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ +#define WM8904_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ +#define WM8904_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ +#define WM8904_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ +#define WM8904_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ +#define WM8904_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ +#define WM8904_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ +#define WM8904_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ +#define WM8904_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ +#define WM8904_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ +#define WM8904_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ +#define WM8904_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ + +/* + * R26 (0x1A) - Audio Interface 2 + */ +#define WM8904_OPCLK_DIV_MASK 0x0F00 /* OPCLK_DIV - [11:8] */ +#define WM8904_OPCLK_DIV_SHIFT 8 /* OPCLK_DIV - [11:8] */ +#define WM8904_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [11:8] */ +#define WM8904_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ +#define WM8904_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ +#define WM8904_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ + +/* + * R27 (0x1B) - Audio Interface 3 + */ +#define WM8904_LRCLK_DIR 0x0800 /* LRCLK_DIR */ +#define WM8904_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */ +#define WM8904_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */ +#define WM8904_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ +#define WM8904_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ +#define WM8904_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ +#define WM8904_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ + +/* + * R30 (0x1E) - DAC Digital Volume Left + */ +#define WM8904_DAC_VU 0x0100 /* DAC_VU */ +#define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */ +#define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */ +#define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */ +#define WM8904_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ +#define WM8904_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */ +#define WM8904_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */ + +/* + * R31 (0x1F) - DAC Digital Volume Right + */ +#define WM8904_DAC_VU 0x0100 /* DAC_VU */ +#define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */ +#define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */ +#define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */ +#define WM8904_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ +#define WM8904_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */ +#define WM8904_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */ + +/* + * R32 (0x20) - DAC Digital 0 + */ +#define WM8904_ADCL_DAC_SVOL_MASK 0x0F00 /* ADCL_DAC_SVOL - [11:8] */ +#define WM8904_ADCL_DAC_SVOL_SHIFT 8 /* ADCL_DAC_SVOL - [11:8] */ +#define WM8904_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [11:8] */ +#define WM8904_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8904_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8904_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8904_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ +#define WM8904_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ +#define WM8904_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ +#define WM8904_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */ +#define WM8904_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */ +#define WM8904_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */ + +/* + * R33 (0x21) - DAC Digital 1 + */ +#define WM8904_DAC_MONO 0x1000 /* DAC_MONO */ +#define WM8904_DAC_MONO_MASK 0x1000 /* DAC_MONO */ +#define WM8904_DAC_MONO_SHIFT 12 /* DAC_MONO */ +#define WM8904_DAC_MONO_WIDTH 1 /* DAC_MONO */ +#define WM8904_DAC_SB_FILT 0x0800 /* DAC_SB_FILT */ +#define WM8904_DAC_SB_FILT_MASK 0x0800 /* DAC_SB_FILT */ +#define WM8904_DAC_SB_FILT_SHIFT 11 /* DAC_SB_FILT */ +#define WM8904_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */ +#define WM8904_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ +#define WM8904_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ +#define WM8904_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ +#define WM8904_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ +#define WM8904_DAC_UNMUTE_RAMP 0x0200 /* DAC_UNMUTE_RAMP */ +#define WM8904_DAC_UNMUTE_RAMP_MASK 0x0200 /* DAC_UNMUTE_RAMP */ +#define WM8904_DAC_UNMUTE_RAMP_SHIFT 9 /* DAC_UNMUTE_RAMP */ +#define WM8904_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */ +#define WM8904_DAC_OSR128 0x0040 /* DAC_OSR128 */ +#define WM8904_DAC_OSR128_MASK 0x0040 /* DAC_OSR128 */ +#define WM8904_DAC_OSR128_SHIFT 6 /* DAC_OSR128 */ +#define WM8904_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ +#define WM8904_DAC_MUTE 0x0008 /* DAC_MUTE */ +#define WM8904_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ +#define WM8904_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ +#define WM8904_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ +#define WM8904_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ +#define WM8904_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ +#define WM8904_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ + +/* + * R36 (0x24) - ADC Digital Volume Left + */ +#define WM8904_ADC_VU 0x0100 /* ADC_VU */ +#define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */ +#define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */ +#define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */ +#define WM8904_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ +#define WM8904_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */ +#define WM8904_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */ + +/* + * R37 (0x25) - ADC Digital Volume Right + */ +#define WM8904_ADC_VU 0x0100 /* ADC_VU */ +#define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */ +#define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */ +#define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */ +#define WM8904_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ +#define WM8904_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */ +#define WM8904_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */ + +/* + * R38 (0x26) - ADC Digital 0 + */ +#define WM8904_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */ +#define WM8904_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */ +#define WM8904_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */ +#define WM8904_ADC_HPF 0x0010 /* ADC_HPF */ +#define WM8904_ADC_HPF_MASK 0x0010 /* ADC_HPF */ +#define WM8904_ADC_HPF_SHIFT 4 /* ADC_HPF */ +#define WM8904_ADC_HPF_WIDTH 1 /* ADC_HPF */ +#define WM8904_ADCL_DATINV 0x0002 /* ADCL_DATINV */ +#define WM8904_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */ +#define WM8904_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */ +#define WM8904_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */ +#define WM8904_ADCR_DATINV 0x0001 /* ADCR_DATINV */ +#define WM8904_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */ +#define WM8904_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */ +#define WM8904_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */ + +/* + * R39 (0x27) - Digital Microphone 0 + */ +#define WM8904_DMIC_ENA 0x1000 /* DMIC_ENA */ +#define WM8904_DMIC_ENA_MASK 0x1000 /* DMIC_ENA */ +#define WM8904_DMIC_ENA_SHIFT 12 /* DMIC_ENA */ +#define WM8904_DMIC_ENA_WIDTH 1 /* DMIC_ENA */ +#define WM8904_DMIC_SRC 0x0800 /* DMIC_SRC */ +#define WM8904_DMIC_SRC_MASK 0x0800 /* DMIC_SRC */ +#define WM8904_DMIC_SRC_SHIFT 11 /* DMIC_SRC */ +#define WM8904_DMIC_SRC_WIDTH 1 /* DMIC_SRC */ + +/* + * R40 (0x28) - DRC 0 + */ +#define WM8904_DRC_ENA 0x8000 /* DRC_ENA */ +#define WM8904_DRC_ENA_MASK 0x8000 /* DRC_ENA */ +#define WM8904_DRC_ENA_SHIFT 15 /* DRC_ENA */ +#define WM8904_DRC_ENA_WIDTH 1 /* DRC_ENA */ +#define WM8904_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */ +#define WM8904_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */ +#define WM8904_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */ +#define WM8904_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */ +#define WM8904_DRC_GS_HYST_LVL_MASK 0x1800 /* DRC_GS_HYST_LVL - [12:11] */ +#define WM8904_DRC_GS_HYST_LVL_SHIFT 11 /* DRC_GS_HYST_LVL - [12:11] */ +#define WM8904_DRC_GS_HYST_LVL_WIDTH 2 /* DRC_GS_HYST_LVL - [12:11] */ +#define WM8904_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM8904_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM8904_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM8904_DRC_FF_DELAY 0x0020 /* DRC_FF_DELAY */ +#define WM8904_DRC_FF_DELAY_MASK 0x0020 /* DRC_FF_DELAY */ +#define WM8904_DRC_FF_DELAY_SHIFT 5 /* DRC_FF_DELAY */ +#define WM8904_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */ +#define WM8904_DRC_GS_ENA 0x0008 /* DRC_GS_ENA */ +#define WM8904_DRC_GS_ENA_MASK 0x0008 /* DRC_GS_ENA */ +#define WM8904_DRC_GS_ENA_SHIFT 3 /* DRC_GS_ENA */ +#define WM8904_DRC_GS_ENA_WIDTH 1 /* DRC_GS_ENA */ +#define WM8904_DRC_QR 0x0004 /* DRC_QR */ +#define WM8904_DRC_QR_MASK 0x0004 /* DRC_QR */ +#define WM8904_DRC_QR_SHIFT 2 /* DRC_QR */ +#define WM8904_DRC_QR_WIDTH 1 /* DRC_QR */ +#define WM8904_DRC_ANTICLIP 0x0002 /* DRC_ANTICLIP */ +#define WM8904_DRC_ANTICLIP_MASK 0x0002 /* DRC_ANTICLIP */ +#define WM8904_DRC_ANTICLIP_SHIFT 1 /* DRC_ANTICLIP */ +#define WM8904_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */ +#define WM8904_DRC_GS_HYST 0x0001 /* DRC_GS_HYST */ +#define WM8904_DRC_GS_HYST_MASK 0x0001 /* DRC_GS_HYST */ +#define WM8904_DRC_GS_HYST_SHIFT 0 /* DRC_GS_HYST */ +#define WM8904_DRC_GS_HYST_WIDTH 1 /* DRC_GS_HYST */ + +/* + * R41 (0x29) - DRC 1 + */ +#define WM8904_DRC_ATK_MASK 0xF000 /* DRC_ATK - [15:12] */ +#define WM8904_DRC_ATK_SHIFT 12 /* DRC_ATK - [15:12] */ +#define WM8904_DRC_ATK_WIDTH 4 /* DRC_ATK - [15:12] */ +#define WM8904_DRC_DCY_MASK 0x0F00 /* DRC_DCY - [11:8] */ +#define WM8904_DRC_DCY_SHIFT 8 /* DRC_DCY - [11:8] */ +#define WM8904_DRC_DCY_WIDTH 4 /* DRC_DCY - [11:8] */ +#define WM8904_DRC_QR_THR_MASK 0x00C0 /* DRC_QR_THR - [7:6] */ +#define WM8904_DRC_QR_THR_SHIFT 6 /* DRC_QR_THR - [7:6] */ +#define WM8904_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [7:6] */ +#define WM8904_DRC_QR_DCY_MASK 0x0030 /* DRC_QR_DCY - [5:4] */ +#define WM8904_DRC_QR_DCY_SHIFT 4 /* DRC_QR_DCY - [5:4] */ +#define WM8904_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [5:4] */ +#define WM8904_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ +#define WM8904_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ +#define WM8904_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ +#define WM8904_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ +#define WM8904_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ +#define WM8904_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ + +/* + * R42 (0x2A) - DRC 2 + */ +#define WM8904_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */ +#define WM8904_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */ +#define WM8904_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */ +#define WM8904_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */ +#define WM8904_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */ +#define WM8904_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */ + +/* + * R43 (0x2B) - DRC 3 + */ +#define WM8904_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */ +#define WM8904_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */ +#define WM8904_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */ +#define WM8904_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */ +#define WM8904_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */ +#define WM8904_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */ + +/* + * R44 (0x2C) - Analogue Left Input 0 + */ +#define WM8904_LINMUTE 0x0080 /* LINMUTE */ +#define WM8904_LINMUTE_MASK 0x0080 /* LINMUTE */ +#define WM8904_LINMUTE_SHIFT 7 /* LINMUTE */ +#define WM8904_LINMUTE_WIDTH 1 /* LINMUTE */ +#define WM8904_LIN_VOL_MASK 0x001F /* LIN_VOL - [4:0] */ +#define WM8904_LIN_VOL_SHIFT 0 /* LIN_VOL - [4:0] */ +#define WM8904_LIN_VOL_WIDTH 5 /* LIN_VOL - [4:0] */ + +/* + * R45 (0x2D) - Analogue Right Input 0 + */ +#define WM8904_RINMUTE 0x0080 /* RINMUTE */ +#define WM8904_RINMUTE_MASK 0x0080 /* RINMUTE */ +#define WM8904_RINMUTE_SHIFT 7 /* RINMUTE */ +#define WM8904_RINMUTE_WIDTH 1 /* RINMUTE */ +#define WM8904_RIN_VOL_MASK 0x001F /* RIN_VOL - [4:0] */ +#define WM8904_RIN_VOL_SHIFT 0 /* RIN_VOL - [4:0] */ +#define WM8904_RIN_VOL_WIDTH 5 /* RIN_VOL - [4:0] */ + +/* + * R46 (0x2E) - Analogue Left Input 1 + */ +#define WM8904_INL_CM_ENA 0x0040 /* INL_CM_ENA */ +#define WM8904_INL_CM_ENA_MASK 0x0040 /* INL_CM_ENA */ +#define WM8904_INL_CM_ENA_SHIFT 6 /* INL_CM_ENA */ +#define WM8904_INL_CM_ENA_WIDTH 1 /* INL_CM_ENA */ +#define WM8904_L_IP_SEL_N_MASK 0x0030 /* L_IP_SEL_N - [5:4] */ +#define WM8904_L_IP_SEL_N_SHIFT 4 /* L_IP_SEL_N - [5:4] */ +#define WM8904_L_IP_SEL_N_WIDTH 2 /* L_IP_SEL_N - [5:4] */ +#define WM8904_L_IP_SEL_P_MASK 0x000C /* L_IP_SEL_P - [3:2] */ +#define WM8904_L_IP_SEL_P_SHIFT 2 /* L_IP_SEL_P - [3:2] */ +#define WM8904_L_IP_SEL_P_WIDTH 2 /* L_IP_SEL_P - [3:2] */ +#define WM8904_L_MODE_MASK 0x0003 /* L_MODE - [1:0] */ +#define WM8904_L_MODE_SHIFT 0 /* L_MODE - [1:0] */ +#define WM8904_L_MODE_WIDTH 2 /* L_MODE - [1:0] */ + +/* + * R47 (0x2F) - Analogue Right Input 1 + */ +#define WM8904_INR_CM_ENA 0x0040 /* INR_CM_ENA */ +#define WM8904_INR_CM_ENA_MASK 0x0040 /* INR_CM_ENA */ +#define WM8904_INR_CM_ENA_SHIFT 6 /* INR_CM_ENA */ +#define WM8904_INR_CM_ENA_WIDTH 1 /* INR_CM_ENA */ +#define WM8904_R_IP_SEL_N_MASK 0x0030 /* R_IP_SEL_N - [5:4] */ +#define WM8904_R_IP_SEL_N_SHIFT 4 /* R_IP_SEL_N - [5:4] */ +#define WM8904_R_IP_SEL_N_WIDTH 2 /* R_IP_SEL_N - [5:4] */ +#define WM8904_R_IP_SEL_P_MASK 0x000C /* R_IP_SEL_P - [3:2] */ +#define WM8904_R_IP_SEL_P_SHIFT 2 /* R_IP_SEL_P - [3:2] */ +#define WM8904_R_IP_SEL_P_WIDTH 2 /* R_IP_SEL_P - [3:2] */ +#define WM8904_R_MODE_MASK 0x0003 /* R_MODE - [1:0] */ +#define WM8904_R_MODE_SHIFT 0 /* R_MODE - [1:0] */ +#define WM8904_R_MODE_WIDTH 2 /* R_MODE - [1:0] */ + +/* + * R57 (0x39) - Analogue OUT1 Left + */ +#define WM8904_HPOUTL_MUTE 0x0100 /* HPOUTL_MUTE */ +#define WM8904_HPOUTL_MUTE_MASK 0x0100 /* HPOUTL_MUTE */ +#define WM8904_HPOUTL_MUTE_SHIFT 8 /* HPOUTL_MUTE */ +#define WM8904_HPOUTL_MUTE_WIDTH 1 /* HPOUTL_MUTE */ +#define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */ +#define WM8904_HPOUTLZC 0x0040 /* HPOUTLZC */ +#define WM8904_HPOUTLZC_MASK 0x0040 /* HPOUTLZC */ +#define WM8904_HPOUTLZC_SHIFT 6 /* HPOUTLZC */ +#define WM8904_HPOUTLZC_WIDTH 1 /* HPOUTLZC */ +#define WM8904_HPOUTL_VOL_MASK 0x003F /* HPOUTL_VOL - [5:0] */ +#define WM8904_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [5:0] */ +#define WM8904_HPOUTL_VOL_WIDTH 6 /* HPOUTL_VOL - [5:0] */ + +/* + * R58 (0x3A) - Analogue OUT1 Right + */ +#define WM8904_HPOUTR_MUTE 0x0100 /* HPOUTR_MUTE */ +#define WM8904_HPOUTR_MUTE_MASK 0x0100 /* HPOUTR_MUTE */ +#define WM8904_HPOUTR_MUTE_SHIFT 8 /* HPOUTR_MUTE */ +#define WM8904_HPOUTR_MUTE_WIDTH 1 /* HPOUTR_MUTE */ +#define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */ +#define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */ +#define WM8904_HPOUTRZC 0x0040 /* HPOUTRZC */ +#define WM8904_HPOUTRZC_MASK 0x0040 /* HPOUTRZC */ +#define WM8904_HPOUTRZC_SHIFT 6 /* HPOUTRZC */ +#define WM8904_HPOUTRZC_WIDTH 1 /* HPOUTRZC */ +#define WM8904_HPOUTR_VOL_MASK 0x003F /* HPOUTR_VOL - [5:0] */ +#define WM8904_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [5:0] */ +#define WM8904_HPOUTR_VOL_WIDTH 6 /* HPOUTR_VOL - [5:0] */ + +/* + * R59 (0x3B) - Analogue OUT2 Left + */ +#define WM8904_LINEOUTL_MUTE 0x0100 /* LINEOUTL_MUTE */ +#define WM8904_LINEOUTL_MUTE_MASK 0x0100 /* LINEOUTL_MUTE */ +#define WM8904_LINEOUTL_MUTE_SHIFT 8 /* LINEOUTL_MUTE */ +#define WM8904_LINEOUTL_MUTE_WIDTH 1 /* LINEOUTL_MUTE */ +#define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */ +#define WM8904_LINEOUTLZC 0x0040 /* LINEOUTLZC */ +#define WM8904_LINEOUTLZC_MASK 0x0040 /* LINEOUTLZC */ +#define WM8904_LINEOUTLZC_SHIFT 6 /* LINEOUTLZC */ +#define WM8904_LINEOUTLZC_WIDTH 1 /* LINEOUTLZC */ +#define WM8904_LINEOUTL_VOL_MASK 0x003F /* LINEOUTL_VOL - [5:0] */ +#define WM8904_LINEOUTL_VOL_SHIFT 0 /* LINEOUTL_VOL - [5:0] */ +#define WM8904_LINEOUTL_VOL_WIDTH 6 /* LINEOUTL_VOL - [5:0] */ + +/* + * R60 (0x3C) - Analogue OUT2 Right + */ +#define WM8904_LINEOUTR_MUTE 0x0100 /* LINEOUTR_MUTE */ +#define WM8904_LINEOUTR_MUTE_MASK 0x0100 /* LINEOUTR_MUTE */ +#define WM8904_LINEOUTR_MUTE_SHIFT 8 /* LINEOUTR_MUTE */ +#define WM8904_LINEOUTR_MUTE_WIDTH 1 /* LINEOUTR_MUTE */ +#define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */ +#define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */ +#define WM8904_LINEOUTRZC 0x0040 /* LINEOUTRZC */ +#define WM8904_LINEOUTRZC_MASK 0x0040 /* LINEOUTRZC */ +#define WM8904_LINEOUTRZC_SHIFT 6 /* LINEOUTRZC */ +#define WM8904_LINEOUTRZC_WIDTH 1 /* LINEOUTRZC */ +#define WM8904_LINEOUTR_VOL_MASK 0x003F /* LINEOUTR_VOL - [5:0] */ +#define WM8904_LINEOUTR_VOL_SHIFT 0 /* LINEOUTR_VOL - [5:0] */ +#define WM8904_LINEOUTR_VOL_WIDTH 6 /* LINEOUTR_VOL - [5:0] */ + +/* + * R61 (0x3D) - Analogue OUT12 ZC + */ +#define WM8904_HPL_BYP_ENA 0x0008 /* HPL_BYP_ENA */ +#define WM8904_HPL_BYP_ENA_MASK 0x0008 /* HPL_BYP_ENA */ +#define WM8904_HPL_BYP_ENA_SHIFT 3 /* HPL_BYP_ENA */ +#define WM8904_HPL_BYP_ENA_WIDTH 1 /* HPL_BYP_ENA */ +#define WM8904_HPR_BYP_ENA 0x0004 /* HPR_BYP_ENA */ +#define WM8904_HPR_BYP_ENA_MASK 0x0004 /* HPR_BYP_ENA */ +#define WM8904_HPR_BYP_ENA_SHIFT 2 /* HPR_BYP_ENA */ +#define WM8904_HPR_BYP_ENA_WIDTH 1 /* HPR_BYP_ENA */ +#define WM8904_LINEOUTL_BYP_ENA 0x0002 /* LINEOUTL_BYP_ENA */ +#define WM8904_LINEOUTL_BYP_ENA_MASK 0x0002 /* LINEOUTL_BYP_ENA */ +#define WM8904_LINEOUTL_BYP_ENA_SHIFT 1 /* LINEOUTL_BYP_ENA */ +#define WM8904_LINEOUTL_BYP_ENA_WIDTH 1 /* LINEOUTL_BYP_ENA */ +#define WM8904_LINEOUTR_BYP_ENA 0x0001 /* LINEOUTR_BYP_ENA */ +#define WM8904_LINEOUTR_BYP_ENA_MASK 0x0001 /* LINEOUTR_BYP_ENA */ +#define WM8904_LINEOUTR_BYP_ENA_SHIFT 0 /* LINEOUTR_BYP_ENA */ +#define WM8904_LINEOUTR_BYP_ENA_WIDTH 1 /* LINEOUTR_BYP_ENA */ + +/* + * R67 (0x43) - DC Servo 0 + */ +#define WM8904_DCS_ENA_CHAN_3 0x0008 /* DCS_ENA_CHAN_3 */ +#define WM8904_DCS_ENA_CHAN_3_MASK 0x0008 /* DCS_ENA_CHAN_3 */ +#define WM8904_DCS_ENA_CHAN_3_SHIFT 3 /* DCS_ENA_CHAN_3 */ +#define WM8904_DCS_ENA_CHAN_3_WIDTH 1 /* DCS_ENA_CHAN_3 */ +#define WM8904_DCS_ENA_CHAN_2 0x0004 /* DCS_ENA_CHAN_2 */ +#define WM8904_DCS_ENA_CHAN_2_MASK 0x0004 /* DCS_ENA_CHAN_2 */ +#define WM8904_DCS_ENA_CHAN_2_SHIFT 2 /* DCS_ENA_CHAN_2 */ +#define WM8904_DCS_ENA_CHAN_2_WIDTH 1 /* DCS_ENA_CHAN_2 */ +#define WM8904_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8904_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8904_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */ +#define WM8904_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */ +#define WM8904_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8904_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8904_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */ +#define WM8904_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */ + +/* + * R68 (0x44) - DC Servo 1 + */ +#define WM8904_DCS_TRIG_SINGLE_3 0x8000 /* DCS_TRIG_SINGLE_3 */ +#define WM8904_DCS_TRIG_SINGLE_3_MASK 0x8000 /* DCS_TRIG_SINGLE_3 */ +#define WM8904_DCS_TRIG_SINGLE_3_SHIFT 15 /* DCS_TRIG_SINGLE_3 */ +#define WM8904_DCS_TRIG_SINGLE_3_WIDTH 1 /* DCS_TRIG_SINGLE_3 */ +#define WM8904_DCS_TRIG_SINGLE_2 0x4000 /* DCS_TRIG_SINGLE_2 */ +#define WM8904_DCS_TRIG_SINGLE_2_MASK 0x4000 /* DCS_TRIG_SINGLE_2 */ +#define WM8904_DCS_TRIG_SINGLE_2_SHIFT 14 /* DCS_TRIG_SINGLE_2 */ +#define WM8904_DCS_TRIG_SINGLE_2_WIDTH 1 /* DCS_TRIG_SINGLE_2 */ +#define WM8904_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8904_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8904_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */ +#define WM8904_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */ +#define WM8904_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8904_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8904_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */ +#define WM8904_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */ +#define WM8904_DCS_TRIG_SERIES_3 0x0800 /* DCS_TRIG_SERIES_3 */ +#define WM8904_DCS_TRIG_SERIES_3_MASK 0x0800 /* DCS_TRIG_SERIES_3 */ +#define WM8904_DCS_TRIG_SERIES_3_SHIFT 11 /* DCS_TRIG_SERIES_3 */ +#define WM8904_DCS_TRIG_SERIES_3_WIDTH 1 /* DCS_TRIG_SERIES_3 */ +#define WM8904_DCS_TRIG_SERIES_2 0x0400 /* DCS_TRIG_SERIES_2 */ +#define WM8904_DCS_TRIG_SERIES_2_MASK 0x0400 /* DCS_TRIG_SERIES_2 */ +#define WM8904_DCS_TRIG_SERIES_2_SHIFT 10 /* DCS_TRIG_SERIES_2 */ +#define WM8904_DCS_TRIG_SERIES_2_WIDTH 1 /* DCS_TRIG_SERIES_2 */ +#define WM8904_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8904_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8904_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */ +#define WM8904_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */ +#define WM8904_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8904_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8904_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */ +#define WM8904_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */ +#define WM8904_DCS_TRIG_STARTUP_3 0x0080 /* DCS_TRIG_STARTUP_3 */ +#define WM8904_DCS_TRIG_STARTUP_3_MASK 0x0080 /* DCS_TRIG_STARTUP_3 */ +#define WM8904_DCS_TRIG_STARTUP_3_SHIFT 7 /* DCS_TRIG_STARTUP_3 */ +#define WM8904_DCS_TRIG_STARTUP_3_WIDTH 1 /* DCS_TRIG_STARTUP_3 */ +#define WM8904_DCS_TRIG_STARTUP_2 0x0040 /* DCS_TRIG_STARTUP_2 */ +#define WM8904_DCS_TRIG_STARTUP_2_MASK 0x0040 /* DCS_TRIG_STARTUP_2 */ +#define WM8904_DCS_TRIG_STARTUP_2_SHIFT 6 /* DCS_TRIG_STARTUP_2 */ +#define WM8904_DCS_TRIG_STARTUP_2_WIDTH 1 /* DCS_TRIG_STARTUP_2 */ +#define WM8904_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8904_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8904_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */ +#define WM8904_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */ +#define WM8904_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8904_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8904_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */ +#define WM8904_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */ +#define WM8904_DCS_TRIG_DAC_WR_3 0x0008 /* DCS_TRIG_DAC_WR_3 */ +#define WM8904_DCS_TRIG_DAC_WR_3_MASK 0x0008 /* DCS_TRIG_DAC_WR_3 */ +#define WM8904_DCS_TRIG_DAC_WR_3_SHIFT 3 /* DCS_TRIG_DAC_WR_3 */ +#define WM8904_DCS_TRIG_DAC_WR_3_WIDTH 1 /* DCS_TRIG_DAC_WR_3 */ +#define WM8904_DCS_TRIG_DAC_WR_2 0x0004 /* DCS_TRIG_DAC_WR_2 */ +#define WM8904_DCS_TRIG_DAC_WR_2_MASK 0x0004 /* DCS_TRIG_DAC_WR_2 */ +#define WM8904_DCS_TRIG_DAC_WR_2_SHIFT 2 /* DCS_TRIG_DAC_WR_2 */ +#define WM8904_DCS_TRIG_DAC_WR_2_WIDTH 1 /* DCS_TRIG_DAC_WR_2 */ +#define WM8904_DCS_TRIG_DAC_WR_1 0x0002 /* DCS_TRIG_DAC_WR_1 */ +#define WM8904_DCS_TRIG_DAC_WR_1_MASK 0x0002 /* DCS_TRIG_DAC_WR_1 */ +#define WM8904_DCS_TRIG_DAC_WR_1_SHIFT 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8904_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8904_DCS_TRIG_DAC_WR_0 0x0001 /* DCS_TRIG_DAC_WR_0 */ +#define WM8904_DCS_TRIG_DAC_WR_0_MASK 0x0001 /* DCS_TRIG_DAC_WR_0 */ +#define WM8904_DCS_TRIG_DAC_WR_0_SHIFT 0 /* DCS_TRIG_DAC_WR_0 */ +#define WM8904_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */ + +/* + * R69 (0x45) - DC Servo 2 + */ +#define WM8904_DCS_TIMER_PERIOD_23_MASK 0x0F00 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8904_DCS_TIMER_PERIOD_23_SHIFT 8 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8904_DCS_TIMER_PERIOD_23_WIDTH 4 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8904_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8904_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8904_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */ + +/* + * R71 (0x47) - DC Servo 4 + */ +#define WM8904_DCS_SERIES_NO_23_MASK 0x007F /* DCS_SERIES_NO_23 - [6:0] */ +#define WM8904_DCS_SERIES_NO_23_SHIFT 0 /* DCS_SERIES_NO_23 - [6:0] */ +#define WM8904_DCS_SERIES_NO_23_WIDTH 7 /* DCS_SERIES_NO_23 - [6:0] */ + +/* + * R72 (0x48) - DC Servo 5 + */ +#define WM8904_DCS_SERIES_NO_01_MASK 0x007F /* DCS_SERIES_NO_01 - [6:0] */ +#define WM8904_DCS_SERIES_NO_01_SHIFT 0 /* DCS_SERIES_NO_01 - [6:0] */ +#define WM8904_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [6:0] */ + +/* + * R73 (0x49) - DC Servo 6 + */ +#define WM8904_DCS_DAC_WR_VAL_3_MASK 0x00FF /* DCS_DAC_WR_VAL_3 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_3_SHIFT 0 /* DCS_DAC_WR_VAL_3 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_3_WIDTH 8 /* DCS_DAC_WR_VAL_3 - [7:0] */ + +/* + * R74 (0x4A) - DC Servo 7 + */ +#define WM8904_DCS_DAC_WR_VAL_2_MASK 0x00FF /* DCS_DAC_WR_VAL_2 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_2_SHIFT 0 /* DCS_DAC_WR_VAL_2 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_2_WIDTH 8 /* DCS_DAC_WR_VAL_2 - [7:0] */ + +/* + * R75 (0x4B) - DC Servo 8 + */ +#define WM8904_DCS_DAC_WR_VAL_1_MASK 0x00FF /* DCS_DAC_WR_VAL_1 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_1_SHIFT 0 /* DCS_DAC_WR_VAL_1 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [7:0] */ + +/* + * R76 (0x4C) - DC Servo 9 + */ +#define WM8904_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8904_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */ + +/* + * R77 (0x4D) - DC Servo Readback 0 + */ +#define WM8904_DCS_CAL_COMPLETE_MASK 0x0F00 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8904_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8904_DCS_CAL_COMPLETE_WIDTH 4 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8904_DCS_DAC_WR_COMPLETE_MASK 0x00F0 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8904_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8904_DCS_DAC_WR_COMPLETE_WIDTH 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8904_DCS_STARTUP_COMPLETE_MASK 0x000F /* DCS_STARTUP_COMPLETE - [3:0] */ +#define WM8904_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [3:0] */ +#define WM8904_DCS_STARTUP_COMPLETE_WIDTH 4 /* DCS_STARTUP_COMPLETE - [3:0] */ + +/* + * R90 (0x5A) - Analogue HP 0 + */ +#define WM8904_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ +#define WM8904_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ +#define WM8904_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ +#define WM8904_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ +#define WM8904_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ +#define WM8904_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ +#define WM8904_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ +#define WM8904_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ +#define WM8904_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ +#define WM8904_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ +#define WM8904_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ +#define WM8904_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ +#define WM8904_HPL_ENA 0x0010 /* HPL_ENA */ +#define WM8904_HPL_ENA_MASK 0x0010 /* HPL_ENA */ +#define WM8904_HPL_ENA_SHIFT 4 /* HPL_ENA */ +#define WM8904_HPL_ENA_WIDTH 1 /* HPL_ENA */ +#define WM8904_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ +#define WM8904_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ +#define WM8904_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ +#define WM8904_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ +#define WM8904_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ +#define WM8904_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ +#define WM8904_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ +#define WM8904_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ +#define WM8904_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ +#define WM8904_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ +#define WM8904_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ +#define WM8904_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ +#define WM8904_HPR_ENA 0x0001 /* HPR_ENA */ +#define WM8904_HPR_ENA_MASK 0x0001 /* HPR_ENA */ +#define WM8904_HPR_ENA_SHIFT 0 /* HPR_ENA */ +#define WM8904_HPR_ENA_WIDTH 1 /* HPR_ENA */ + +/* + * R94 (0x5E) - Analogue Lineout 0 + */ +#define WM8904_LINEOUTL_RMV_SHORT 0x0080 /* LINEOUTL_RMV_SHORT */ +#define WM8904_LINEOUTL_RMV_SHORT_MASK 0x0080 /* LINEOUTL_RMV_SHORT */ +#define WM8904_LINEOUTL_RMV_SHORT_SHIFT 7 /* LINEOUTL_RMV_SHORT */ +#define WM8904_LINEOUTL_RMV_SHORT_WIDTH 1 /* LINEOUTL_RMV_SHORT */ +#define WM8904_LINEOUTL_ENA_OUTP 0x0040 /* LINEOUTL_ENA_OUTP */ +#define WM8904_LINEOUTL_ENA_OUTP_MASK 0x0040 /* LINEOUTL_ENA_OUTP */ +#define WM8904_LINEOUTL_ENA_OUTP_SHIFT 6 /* LINEOUTL_ENA_OUTP */ +#define WM8904_LINEOUTL_ENA_OUTP_WIDTH 1 /* LINEOUTL_ENA_OUTP */ +#define WM8904_LINEOUTL_ENA_DLY 0x0020 /* LINEOUTL_ENA_DLY */ +#define WM8904_LINEOUTL_ENA_DLY_MASK 0x0020 /* LINEOUTL_ENA_DLY */ +#define WM8904_LINEOUTL_ENA_DLY_SHIFT 5 /* LINEOUTL_ENA_DLY */ +#define WM8904_LINEOUTL_ENA_DLY_WIDTH 1 /* LINEOUTL_ENA_DLY */ +#define WM8904_LINEOUTL_ENA 0x0010 /* LINEOUTL_ENA */ +#define WM8904_LINEOUTL_ENA_MASK 0x0010 /* LINEOUTL_ENA */ +#define WM8904_LINEOUTL_ENA_SHIFT 4 /* LINEOUTL_ENA */ +#define WM8904_LINEOUTL_ENA_WIDTH 1 /* LINEOUTL_ENA */ +#define WM8904_LINEOUTR_RMV_SHORT 0x0008 /* LINEOUTR_RMV_SHORT */ +#define WM8904_LINEOUTR_RMV_SHORT_MASK 0x0008 /* LINEOUTR_RMV_SHORT */ +#define WM8904_LINEOUTR_RMV_SHORT_SHIFT 3 /* LINEOUTR_RMV_SHORT */ +#define WM8904_LINEOUTR_RMV_SHORT_WIDTH 1 /* LINEOUTR_RMV_SHORT */ +#define WM8904_LINEOUTR_ENA_OUTP 0x0004 /* LINEOUTR_ENA_OUTP */ +#define WM8904_LINEOUTR_ENA_OUTP_MASK 0x0004 /* LINEOUTR_ENA_OUTP */ +#define WM8904_LINEOUTR_ENA_OUTP_SHIFT 2 /* LINEOUTR_ENA_OUTP */ +#define WM8904_LINEOUTR_ENA_OUTP_WIDTH 1 /* LINEOUTR_ENA_OUTP */ +#define WM8904_LINEOUTR_ENA_DLY 0x0002 /* LINEOUTR_ENA_DLY */ +#define WM8904_LINEOUTR_ENA_DLY_MASK 0x0002 /* LINEOUTR_ENA_DLY */ +#define WM8904_LINEOUTR_ENA_DLY_SHIFT 1 /* LINEOUTR_ENA_DLY */ +#define WM8904_LINEOUTR_ENA_DLY_WIDTH 1 /* LINEOUTR_ENA_DLY */ +#define WM8904_LINEOUTR_ENA 0x0001 /* LINEOUTR_ENA */ +#define WM8904_LINEOUTR_ENA_MASK 0x0001 /* LINEOUTR_ENA */ +#define WM8904_LINEOUTR_ENA_SHIFT 0 /* LINEOUTR_ENA */ +#define WM8904_LINEOUTR_ENA_WIDTH 1 /* LINEOUTR_ENA */ + +/* + * R98 (0x62) - Charge Pump 0 + */ +#define WM8904_CP_ENA 0x0001 /* CP_ENA */ +#define WM8904_CP_ENA_MASK 0x0001 /* CP_ENA */ +#define WM8904_CP_ENA_SHIFT 0 /* CP_ENA */ +#define WM8904_CP_ENA_WIDTH 1 /* CP_ENA */ + +/* + * R104 (0x68) - Class W 0 + */ +#define WM8904_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */ +#define WM8904_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */ +#define WM8904_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */ +#define WM8904_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */ + +/* + * R108 (0x6C) - Write Sequencer 0 + */ +#define WM8904_WSEQ_ENA 0x0100 /* WSEQ_ENA */ +#define WM8904_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */ +#define WM8904_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */ +#define WM8904_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM8904_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8904_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8904_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ + +/* + * R109 (0x6D) - Write Sequencer 1 + */ +#define WM8904_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8904_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8904_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8904_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */ +#define WM8904_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */ +#define WM8904_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */ +#define WM8904_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ +#define WM8904_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ +#define WM8904_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ + +/* + * R110 (0x6E) - Write Sequencer 2 + */ +#define WM8904_WSEQ_EOS 0x4000 /* WSEQ_EOS */ +#define WM8904_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */ +#define WM8904_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */ +#define WM8904_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ +#define WM8904_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */ +#define WM8904_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */ +#define WM8904_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */ +#define WM8904_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ +#define WM8904_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ +#define WM8904_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ + +/* + * R111 (0x6F) - Write Sequencer 3 + */ +#define WM8904_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ +#define WM8904_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ +#define WM8904_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ +#define WM8904_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM8904_WSEQ_START 0x0100 /* WSEQ_START */ +#define WM8904_WSEQ_START_MASK 0x0100 /* WSEQ_START */ +#define WM8904_WSEQ_START_SHIFT 8 /* WSEQ_START */ +#define WM8904_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM8904_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ +#define WM8904_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ +#define WM8904_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ + +/* + * R112 (0x70) - Write Sequencer 4 + */ +#define WM8904_WSEQ_CURRENT_INDEX_MASK 0x03F0 /* WSEQ_CURRENT_INDEX - [9:4] */ +#define WM8904_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [9:4] */ +#define WM8904_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [9:4] */ +#define WM8904_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ +#define WM8904_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ +#define WM8904_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ +#define WM8904_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ + +/* + * R116 (0x74) - FLL Control 1 + */ +#define WM8904_FLL_FRACN_ENA 0x0004 /* FLL_FRACN_ENA */ +#define WM8904_FLL_FRACN_ENA_MASK 0x0004 /* FLL_FRACN_ENA */ +#define WM8904_FLL_FRACN_ENA_SHIFT 2 /* FLL_FRACN_ENA */ +#define WM8904_FLL_FRACN_ENA_WIDTH 1 /* FLL_FRACN_ENA */ +#define WM8904_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */ +#define WM8904_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */ +#define WM8904_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */ +#define WM8904_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */ +#define WM8904_FLL_ENA 0x0001 /* FLL_ENA */ +#define WM8904_FLL_ENA_MASK 0x0001 /* FLL_ENA */ +#define WM8904_FLL_ENA_SHIFT 0 /* FLL_ENA */ +#define WM8904_FLL_ENA_WIDTH 1 /* FLL_ENA */ + +/* + * R117 (0x75) - FLL Control 2 + */ +#define WM8904_FLL_OUTDIV_MASK 0x3F00 /* FLL_OUTDIV - [13:8] */ +#define WM8904_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [13:8] */ +#define WM8904_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [13:8] */ +#define WM8904_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */ +#define WM8904_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */ +#define WM8904_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */ +#define WM8904_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ +#define WM8904_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ +#define WM8904_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ + +/* + * R118 (0x76) - FLL Control 3 + */ +#define WM8904_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */ +#define WM8904_FLL_K_SHIFT 0 /* FLL_K - [15:0] */ +#define WM8904_FLL_K_WIDTH 16 /* FLL_K - [15:0] */ + +/* + * R119 (0x77) - FLL Control 4 + */ +#define WM8904_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ +#define WM8904_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ +#define WM8904_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ +#define WM8904_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */ +#define WM8904_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */ +#define WM8904_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */ + +/* + * R120 (0x78) - FLL Control 5 + */ +#define WM8904_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8904_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8904_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8904_FLL_CLK_REF_SRC_MASK 0x0003 /* FLL_CLK_REF_SRC - [1:0] */ +#define WM8904_FLL_CLK_REF_SRC_SHIFT 0 /* FLL_CLK_REF_SRC - [1:0] */ +#define WM8904_FLL_CLK_REF_SRC_WIDTH 2 /* FLL_CLK_REF_SRC - [1:0] */ + +/* + * R121 (0x79) - GPIO Control 1 + */ +#define WM8904_GPIO1_PU 0x0020 /* GPIO1_PU */ +#define WM8904_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */ +#define WM8904_GPIO1_PU_SHIFT 5 /* GPIO1_PU */ +#define WM8904_GPIO1_PU_WIDTH 1 /* GPIO1_PU */ +#define WM8904_GPIO1_PD 0x0010 /* GPIO1_PD */ +#define WM8904_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */ +#define WM8904_GPIO1_PD_SHIFT 4 /* GPIO1_PD */ +#define WM8904_GPIO1_PD_WIDTH 1 /* GPIO1_PD */ +#define WM8904_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ +#define WM8904_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */ +#define WM8904_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */ + +/* + * R122 (0x7A) - GPIO Control 2 + */ +#define WM8904_GPIO2_PU 0x0020 /* GPIO2_PU */ +#define WM8904_GPIO2_PU_MASK 0x0020 /* GPIO2_PU */ +#define WM8904_GPIO2_PU_SHIFT 5 /* GPIO2_PU */ +#define WM8904_GPIO2_PU_WIDTH 1 /* GPIO2_PU */ +#define WM8904_GPIO2_PD 0x0010 /* GPIO2_PD */ +#define WM8904_GPIO2_PD_MASK 0x0010 /* GPIO2_PD */ +#define WM8904_GPIO2_PD_SHIFT 4 /* GPIO2_PD */ +#define WM8904_GPIO2_PD_WIDTH 1 /* GPIO2_PD */ +#define WM8904_GPIO2_SEL_MASK 0x000F /* GPIO2_SEL - [3:0] */ +#define WM8904_GPIO2_SEL_SHIFT 0 /* GPIO2_SEL - [3:0] */ +#define WM8904_GPIO2_SEL_WIDTH 4 /* GPIO2_SEL - [3:0] */ + +/* + * R123 (0x7B) - GPIO Control 3 + */ +#define WM8904_GPIO3_PU 0x0020 /* GPIO3_PU */ +#define WM8904_GPIO3_PU_MASK 0x0020 /* GPIO3_PU */ +#define WM8904_GPIO3_PU_SHIFT 5 /* GPIO3_PU */ +#define WM8904_GPIO3_PU_WIDTH 1 /* GPIO3_PU */ +#define WM8904_GPIO3_PD 0x0010 /* GPIO3_PD */ +#define WM8904_GPIO3_PD_MASK 0x0010 /* GPIO3_PD */ +#define WM8904_GPIO3_PD_SHIFT 4 /* GPIO3_PD */ +#define WM8904_GPIO3_PD_WIDTH 1 /* GPIO3_PD */ +#define WM8904_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ +#define WM8904_GPIO3_SEL_SHIFT 0 /* GPIO3_SEL - [3:0] */ +#define WM8904_GPIO3_SEL_WIDTH 4 /* GPIO3_SEL - [3:0] */ + +/* + * R124 (0x7C) - GPIO Control 4 + */ +#define WM8904_GPI7_ENA 0x0200 /* GPI7_ENA */ +#define WM8904_GPI7_ENA_MASK 0x0200 /* GPI7_ENA */ +#define WM8904_GPI7_ENA_SHIFT 9 /* GPI7_ENA */ +#define WM8904_GPI7_ENA_WIDTH 1 /* GPI7_ENA */ +#define WM8904_GPI8_ENA 0x0100 /* GPI8_ENA */ +#define WM8904_GPI8_ENA_MASK 0x0100 /* GPI8_ENA */ +#define WM8904_GPI8_ENA_SHIFT 8 /* GPI8_ENA */ +#define WM8904_GPI8_ENA_WIDTH 1 /* GPI8_ENA */ +#define WM8904_GPIO_BCLK_MODE_ENA 0x0080 /* GPIO_BCLK_MODE_ENA */ +#define WM8904_GPIO_BCLK_MODE_ENA_MASK 0x0080 /* GPIO_BCLK_MODE_ENA */ +#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT 7 /* GPIO_BCLK_MODE_ENA */ +#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH 1 /* GPIO_BCLK_MODE_ENA */ +#define WM8904_GPIO_BCLK_SEL_MASK 0x000F /* GPIO_BCLK_SEL - [3:0] */ +#define WM8904_GPIO_BCLK_SEL_SHIFT 0 /* GPIO_BCLK_SEL - [3:0] */ +#define WM8904_GPIO_BCLK_SEL_WIDTH 4 /* GPIO_BCLK_SEL - [3:0] */ + +/* + * R126 (0x7E) - Digital Pulls + */ +#define WM8904_MCLK_PU 0x0080 /* MCLK_PU */ +#define WM8904_MCLK_PU_MASK 0x0080 /* MCLK_PU */ +#define WM8904_MCLK_PU_SHIFT 7 /* MCLK_PU */ +#define WM8904_MCLK_PU_WIDTH 1 /* MCLK_PU */ +#define WM8904_MCLK_PD 0x0040 /* MCLK_PD */ +#define WM8904_MCLK_PD_MASK 0x0040 /* MCLK_PD */ +#define WM8904_MCLK_PD_SHIFT 6 /* MCLK_PD */ +#define WM8904_MCLK_PD_WIDTH 1 /* MCLK_PD */ +#define WM8904_DACDAT_PU 0x0020 /* DACDAT_PU */ +#define WM8904_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */ +#define WM8904_DACDAT_PU_SHIFT 5 /* DACDAT_PU */ +#define WM8904_DACDAT_PU_WIDTH 1 /* DACDAT_PU */ +#define WM8904_DACDAT_PD 0x0010 /* DACDAT_PD */ +#define WM8904_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */ +#define WM8904_DACDAT_PD_SHIFT 4 /* DACDAT_PD */ +#define WM8904_DACDAT_PD_WIDTH 1 /* DACDAT_PD */ +#define WM8904_LRCLK_PU 0x0008 /* LRCLK_PU */ +#define WM8904_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */ +#define WM8904_LRCLK_PU_SHIFT 3 /* LRCLK_PU */ +#define WM8904_LRCLK_PU_WIDTH 1 /* LRCLK_PU */ +#define WM8904_LRCLK_PD 0x0004 /* LRCLK_PD */ +#define WM8904_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */ +#define WM8904_LRCLK_PD_SHIFT 2 /* LRCLK_PD */ +#define WM8904_LRCLK_PD_WIDTH 1 /* LRCLK_PD */ +#define WM8904_BCLK_PU 0x0002 /* BCLK_PU */ +#define WM8904_BCLK_PU_MASK 0x0002 /* BCLK_PU */ +#define WM8904_BCLK_PU_SHIFT 1 /* BCLK_PU */ +#define WM8904_BCLK_PU_WIDTH 1 /* BCLK_PU */ +#define WM8904_BCLK_PD 0x0001 /* BCLK_PD */ +#define WM8904_BCLK_PD_MASK 0x0001 /* BCLK_PD */ +#define WM8904_BCLK_PD_SHIFT 0 /* BCLK_PD */ +#define WM8904_BCLK_PD_WIDTH 1 /* BCLK_PD */ + +/* + * R127 (0x7F) - Interrupt Status + */ +#define WM8904_IRQ 0x0400 /* IRQ */ +#define WM8904_IRQ_MASK 0x0400 /* IRQ */ +#define WM8904_IRQ_SHIFT 10 /* IRQ */ +#define WM8904_IRQ_WIDTH 1 /* IRQ */ +#define WM8904_GPIO_BCLK_EINT 0x0200 /* GPIO_BCLK_EINT */ +#define WM8904_GPIO_BCLK_EINT_MASK 0x0200 /* GPIO_BCLK_EINT */ +#define WM8904_GPIO_BCLK_EINT_SHIFT 9 /* GPIO_BCLK_EINT */ +#define WM8904_GPIO_BCLK_EINT_WIDTH 1 /* GPIO_BCLK_EINT */ +#define WM8904_WSEQ_EINT 0x0100 /* WSEQ_EINT */ +#define WM8904_WSEQ_EINT_MASK 0x0100 /* WSEQ_EINT */ +#define WM8904_WSEQ_EINT_SHIFT 8 /* WSEQ_EINT */ +#define WM8904_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */ +#define WM8904_GPIO3_EINT 0x0080 /* GPIO3_EINT */ +#define WM8904_GPIO3_EINT_MASK 0x0080 /* GPIO3_EINT */ +#define WM8904_GPIO3_EINT_SHIFT 7 /* GPIO3_EINT */ +#define WM8904_GPIO3_EINT_WIDTH 1 /* GPIO3_EINT */ +#define WM8904_GPIO2_EINT 0x0040 /* GPIO2_EINT */ +#define WM8904_GPIO2_EINT_MASK 0x0040 /* GPIO2_EINT */ +#define WM8904_GPIO2_EINT_SHIFT 6 /* GPIO2_EINT */ +#define WM8904_GPIO2_EINT_WIDTH 1 /* GPIO2_EINT */ +#define WM8904_GPIO1_EINT 0x0020 /* GPIO1_EINT */ +#define WM8904_GPIO1_EINT_MASK 0x0020 /* GPIO1_EINT */ +#define WM8904_GPIO1_EINT_SHIFT 5 /* GPIO1_EINT */ +#define WM8904_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */ +#define WM8904_GPI8_EINT 0x0010 /* GPI8_EINT */ +#define WM8904_GPI8_EINT_MASK 0x0010 /* GPI8_EINT */ +#define WM8904_GPI8_EINT_SHIFT 4 /* GPI8_EINT */ +#define WM8904_GPI8_EINT_WIDTH 1 /* GPI8_EINT */ +#define WM8904_GPI7_EINT 0x0008 /* GPI7_EINT */ +#define WM8904_GPI7_EINT_MASK 0x0008 /* GPI7_EINT */ +#define WM8904_GPI7_EINT_SHIFT 3 /* GPI7_EINT */ +#define WM8904_GPI7_EINT_WIDTH 1 /* GPI7_EINT */ +#define WM8904_FLL_LOCK_EINT 0x0004 /* FLL_LOCK_EINT */ +#define WM8904_FLL_LOCK_EINT_MASK 0x0004 /* FLL_LOCK_EINT */ +#define WM8904_FLL_LOCK_EINT_SHIFT 2 /* FLL_LOCK_EINT */ +#define WM8904_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */ +#define WM8904_MIC_SHRT_EINT 0x0002 /* MIC_SHRT_EINT */ +#define WM8904_MIC_SHRT_EINT_MASK 0x0002 /* MIC_SHRT_EINT */ +#define WM8904_MIC_SHRT_EINT_SHIFT 1 /* MIC_SHRT_EINT */ +#define WM8904_MIC_SHRT_EINT_WIDTH 1 /* MIC_SHRT_EINT */ +#define WM8904_MIC_DET_EINT 0x0001 /* MIC_DET_EINT */ +#define WM8904_MIC_DET_EINT_MASK 0x0001 /* MIC_DET_EINT */ +#define WM8904_MIC_DET_EINT_SHIFT 0 /* MIC_DET_EINT */ +#define WM8904_MIC_DET_EINT_WIDTH 1 /* MIC_DET_EINT */ + +/* + * R128 (0x80) - Interrupt Status Mask + */ +#define WM8904_IM_GPIO_BCLK_EINT 0x0200 /* IM_GPIO_BCLK_EINT */ +#define WM8904_IM_GPIO_BCLK_EINT_MASK 0x0200 /* IM_GPIO_BCLK_EINT */ +#define WM8904_IM_GPIO_BCLK_EINT_SHIFT 9 /* IM_GPIO_BCLK_EINT */ +#define WM8904_IM_GPIO_BCLK_EINT_WIDTH 1 /* IM_GPIO_BCLK_EINT */ +#define WM8904_IM_WSEQ_EINT 0x0100 /* IM_WSEQ_EINT */ +#define WM8904_IM_WSEQ_EINT_MASK 0x0100 /* IM_WSEQ_EINT */ +#define WM8904_IM_WSEQ_EINT_SHIFT 8 /* IM_WSEQ_EINT */ +#define WM8904_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */ +#define WM8904_IM_GPIO3_EINT 0x0080 /* IM_GPIO3_EINT */ +#define WM8904_IM_GPIO3_EINT_MASK 0x0080 /* IM_GPIO3_EINT */ +#define WM8904_IM_GPIO3_EINT_SHIFT 7 /* IM_GPIO3_EINT */ +#define WM8904_IM_GPIO3_EINT_WIDTH 1 /* IM_GPIO3_EINT */ +#define WM8904_IM_GPIO2_EINT 0x0040 /* IM_GPIO2_EINT */ +#define WM8904_IM_GPIO2_EINT_MASK 0x0040 /* IM_GPIO2_EINT */ +#define WM8904_IM_GPIO2_EINT_SHIFT 6 /* IM_GPIO2_EINT */ +#define WM8904_IM_GPIO2_EINT_WIDTH 1 /* IM_GPIO2_EINT */ +#define WM8904_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */ +#define WM8904_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */ +#define WM8904_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */ +#define WM8904_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */ +#define WM8904_IM_GPI8_EINT 0x0010 /* IM_GPI8_EINT */ +#define WM8904_IM_GPI8_EINT_MASK 0x0010 /* IM_GPI8_EINT */ +#define WM8904_IM_GPI8_EINT_SHIFT 4 /* IM_GPI8_EINT */ +#define WM8904_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */ +#define WM8904_IM_GPI7_EINT 0x0008 /* IM_GPI7_EINT */ +#define WM8904_IM_GPI7_EINT_MASK 0x0008 /* IM_GPI7_EINT */ +#define WM8904_IM_GPI7_EINT_SHIFT 3 /* IM_GPI7_EINT */ +#define WM8904_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */ +#define WM8904_IM_FLL_LOCK_EINT 0x0004 /* IM_FLL_LOCK_EINT */ +#define WM8904_IM_FLL_LOCK_EINT_MASK 0x0004 /* IM_FLL_LOCK_EINT */ +#define WM8904_IM_FLL_LOCK_EINT_SHIFT 2 /* IM_FLL_LOCK_EINT */ +#define WM8904_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */ +#define WM8904_IM_MIC_SHRT_EINT 0x0002 /* IM_MIC_SHRT_EINT */ +#define WM8904_IM_MIC_SHRT_EINT_MASK 0x0002 /* IM_MIC_SHRT_EINT */ +#define WM8904_IM_MIC_SHRT_EINT_SHIFT 1 /* IM_MIC_SHRT_EINT */ +#define WM8904_IM_MIC_SHRT_EINT_WIDTH 1 /* IM_MIC_SHRT_EINT */ +#define WM8904_IM_MIC_DET_EINT 0x0001 /* IM_MIC_DET_EINT */ +#define WM8904_IM_MIC_DET_EINT_MASK 0x0001 /* IM_MIC_DET_EINT */ +#define WM8904_IM_MIC_DET_EINT_SHIFT 0 /* IM_MIC_DET_EINT */ +#define WM8904_IM_MIC_DET_EINT_WIDTH 1 /* IM_MIC_DET_EINT */ + +/* + * R129 (0x81) - Interrupt Polarity + */ +#define WM8904_GPIO_BCLK_EINT_POL 0x0200 /* GPIO_BCLK_EINT_POL */ +#define WM8904_GPIO_BCLK_EINT_POL_MASK 0x0200 /* GPIO_BCLK_EINT_POL */ +#define WM8904_GPIO_BCLK_EINT_POL_SHIFT 9 /* GPIO_BCLK_EINT_POL */ +#define WM8904_GPIO_BCLK_EINT_POL_WIDTH 1 /* GPIO_BCLK_EINT_POL */ +#define WM8904_WSEQ_EINT_POL 0x0100 /* WSEQ_EINT_POL */ +#define WM8904_WSEQ_EINT_POL_MASK 0x0100 /* WSEQ_EINT_POL */ +#define WM8904_WSEQ_EINT_POL_SHIFT 8 /* WSEQ_EINT_POL */ +#define WM8904_WSEQ_EINT_POL_WIDTH 1 /* WSEQ_EINT_POL */ +#define WM8904_GPIO3_EINT_POL 0x0080 /* GPIO3_EINT_POL */ +#define WM8904_GPIO3_EINT_POL_MASK 0x0080 /* GPIO3_EINT_POL */ +#define WM8904_GPIO3_EINT_POL_SHIFT 7 /* GPIO3_EINT_POL */ +#define WM8904_GPIO3_EINT_POL_WIDTH 1 /* GPIO3_EINT_POL */ +#define WM8904_GPIO2_EINT_POL 0x0040 /* GPIO2_EINT_POL */ +#define WM8904_GPIO2_EINT_POL_MASK 0x0040 /* GPIO2_EINT_POL */ +#define WM8904_GPIO2_EINT_POL_SHIFT 6 /* GPIO2_EINT_POL */ +#define WM8904_GPIO2_EINT_POL_WIDTH 1 /* GPIO2_EINT_POL */ +#define WM8904_GPIO1_EINT_POL 0x0020 /* GPIO1_EINT_POL */ +#define WM8904_GPIO1_EINT_POL_MASK 0x0020 /* GPIO1_EINT_POL */ +#define WM8904_GPIO1_EINT_POL_SHIFT 5 /* GPIO1_EINT_POL */ +#define WM8904_GPIO1_EINT_POL_WIDTH 1 /* GPIO1_EINT_POL */ +#define WM8904_GPI8_EINT_POL 0x0010 /* GPI8_EINT_POL */ +#define WM8904_GPI8_EINT_POL_MASK 0x0010 /* GPI8_EINT_POL */ +#define WM8904_GPI8_EINT_POL_SHIFT 4 /* GPI8_EINT_POL */ +#define WM8904_GPI8_EINT_POL_WIDTH 1 /* GPI8_EINT_POL */ +#define WM8904_GPI7_EINT_POL 0x0008 /* GPI7_EINT_POL */ +#define WM8904_GPI7_EINT_POL_MASK 0x0008 /* GPI7_EINT_POL */ +#define WM8904_GPI7_EINT_POL_SHIFT 3 /* GPI7_EINT_POL */ +#define WM8904_GPI7_EINT_POL_WIDTH 1 /* GPI7_EINT_POL */ +#define WM8904_FLL_LOCK_EINT_POL 0x0004 /* FLL_LOCK_EINT_POL */ +#define WM8904_FLL_LOCK_EINT_POL_MASK 0x0004 /* FLL_LOCK_EINT_POL */ +#define WM8904_FLL_LOCK_EINT_POL_SHIFT 2 /* FLL_LOCK_EINT_POL */ +#define WM8904_FLL_LOCK_EINT_POL_WIDTH 1 /* FLL_LOCK_EINT_POL */ +#define WM8904_MIC_SHRT_EINT_POL 0x0002 /* MIC_SHRT_EINT_POL */ +#define WM8904_MIC_SHRT_EINT_POL_MASK 0x0002 /* MIC_SHRT_EINT_POL */ +#define WM8904_MIC_SHRT_EINT_POL_SHIFT 1 /* MIC_SHRT_EINT_POL */ +#define WM8904_MIC_SHRT_EINT_POL_WIDTH 1 /* MIC_SHRT_EINT_POL */ +#define WM8904_MIC_DET_EINT_POL 0x0001 /* MIC_DET_EINT_POL */ +#define WM8904_MIC_DET_EINT_POL_MASK 0x0001 /* MIC_DET_EINT_POL */ +#define WM8904_MIC_DET_EINT_POL_SHIFT 0 /* MIC_DET_EINT_POL */ +#define WM8904_MIC_DET_EINT_POL_WIDTH 1 /* MIC_DET_EINT_POL */ + +/* + * R130 (0x82) - Interrupt Debounce + */ +#define WM8904_GPIO_BCLK_EINT_DB 0x0200 /* GPIO_BCLK_EINT_DB */ +#define WM8904_GPIO_BCLK_EINT_DB_MASK 0x0200 /* GPIO_BCLK_EINT_DB */ +#define WM8904_GPIO_BCLK_EINT_DB_SHIFT 9 /* GPIO_BCLK_EINT_DB */ +#define WM8904_GPIO_BCLK_EINT_DB_WIDTH 1 /* GPIO_BCLK_EINT_DB */ +#define WM8904_WSEQ_EINT_DB 0x0100 /* WSEQ_EINT_DB */ +#define WM8904_WSEQ_EINT_DB_MASK 0x0100 /* WSEQ_EINT_DB */ +#define WM8904_WSEQ_EINT_DB_SHIFT 8 /* WSEQ_EINT_DB */ +#define WM8904_WSEQ_EINT_DB_WIDTH 1 /* WSEQ_EINT_DB */ +#define WM8904_GPIO3_EINT_DB 0x0080 /* GPIO3_EINT_DB */ +#define WM8904_GPIO3_EINT_DB_MASK 0x0080 /* GPIO3_EINT_DB */ +#define WM8904_GPIO3_EINT_DB_SHIFT 7 /* GPIO3_EINT_DB */ +#define WM8904_GPIO3_EINT_DB_WIDTH 1 /* GPIO3_EINT_DB */ +#define WM8904_GPIO2_EINT_DB 0x0040 /* GPIO2_EINT_DB */ +#define WM8904_GPIO2_EINT_DB_MASK 0x0040 /* GPIO2_EINT_DB */ +#define WM8904_GPIO2_EINT_DB_SHIFT 6 /* GPIO2_EINT_DB */ +#define WM8904_GPIO2_EINT_DB_WIDTH 1 /* GPIO2_EINT_DB */ +#define WM8904_GPIO1_EINT_DB 0x0020 /* GPIO1_EINT_DB */ +#define WM8904_GPIO1_EINT_DB_MASK 0x0020 /* GPIO1_EINT_DB */ +#define WM8904_GPIO1_EINT_DB_SHIFT 5 /* GPIO1_EINT_DB */ +#define WM8904_GPIO1_EINT_DB_WIDTH 1 /* GPIO1_EINT_DB */ +#define WM8904_GPI8_EINT_DB 0x0010 /* GPI8_EINT_DB */ +#define WM8904_GPI8_EINT_DB_MASK 0x0010 /* GPI8_EINT_DB */ +#define WM8904_GPI8_EINT_DB_SHIFT 4 /* GPI8_EINT_DB */ +#define WM8904_GPI8_EINT_DB_WIDTH 1 /* GPI8_EINT_DB */ +#define WM8904_GPI7_EINT_DB 0x0008 /* GPI7_EINT_DB */ +#define WM8904_GPI7_EINT_DB_MASK 0x0008 /* GPI7_EINT_DB */ +#define WM8904_GPI7_EINT_DB_SHIFT 3 /* GPI7_EINT_DB */ +#define WM8904_GPI7_EINT_DB_WIDTH 1 /* GPI7_EINT_DB */ +#define WM8904_FLL_LOCK_EINT_DB 0x0004 /* FLL_LOCK_EINT_DB */ +#define WM8904_FLL_LOCK_EINT_DB_MASK 0x0004 /* FLL_LOCK_EINT_DB */ +#define WM8904_FLL_LOCK_EINT_DB_SHIFT 2 /* FLL_LOCK_EINT_DB */ +#define WM8904_FLL_LOCK_EINT_DB_WIDTH 1 /* FLL_LOCK_EINT_DB */ +#define WM8904_MIC_SHRT_EINT_DB 0x0002 /* MIC_SHRT_EINT_DB */ +#define WM8904_MIC_SHRT_EINT_DB_MASK 0x0002 /* MIC_SHRT_EINT_DB */ +#define WM8904_MIC_SHRT_EINT_DB_SHIFT 1 /* MIC_SHRT_EINT_DB */ +#define WM8904_MIC_SHRT_EINT_DB_WIDTH 1 /* MIC_SHRT_EINT_DB */ +#define WM8904_MIC_DET_EINT_DB 0x0001 /* MIC_DET_EINT_DB */ +#define WM8904_MIC_DET_EINT_DB_MASK 0x0001 /* MIC_DET_EINT_DB */ +#define WM8904_MIC_DET_EINT_DB_SHIFT 0 /* MIC_DET_EINT_DB */ +#define WM8904_MIC_DET_EINT_DB_WIDTH 1 /* MIC_DET_EINT_DB */ + +/* + * R134 (0x86) - EQ1 + */ +#define WM8904_EQ_ENA 0x0001 /* EQ_ENA */ +#define WM8904_EQ_ENA_MASK 0x0001 /* EQ_ENA */ +#define WM8904_EQ_ENA_SHIFT 0 /* EQ_ENA */ +#define WM8904_EQ_ENA_WIDTH 1 /* EQ_ENA */ + +/* + * R135 (0x87) - EQ2 + */ +#define WM8904_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */ +#define WM8904_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */ +#define WM8904_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */ + +/* + * R136 (0x88) - EQ3 + */ +#define WM8904_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */ +#define WM8904_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */ +#define WM8904_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */ + +/* + * R137 (0x89) - EQ4 + */ +#define WM8904_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */ +#define WM8904_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */ +#define WM8904_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */ + +/* + * R138 (0x8A) - EQ5 + */ +#define WM8904_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */ +#define WM8904_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */ +#define WM8904_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */ + +/* + * R139 (0x8B) - EQ6 + */ +#define WM8904_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */ +#define WM8904_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */ +#define WM8904_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */ + +/* + * R140 (0x8C) - EQ7 + */ +#define WM8904_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */ +#define WM8904_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */ +#define WM8904_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */ + +/* + * R141 (0x8D) - EQ8 + */ +#define WM8904_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */ +#define WM8904_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */ +#define WM8904_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */ + +/* + * R142 (0x8E) - EQ9 + */ +#define WM8904_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */ +#define WM8904_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */ +#define WM8904_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */ + +/* + * R143 (0x8F) - EQ10 + */ +#define WM8904_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */ +#define WM8904_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */ +#define WM8904_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */ + +/* + * R144 (0x90) - EQ11 + */ +#define WM8904_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */ +#define WM8904_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */ +#define WM8904_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */ + +/* + * R145 (0x91) - EQ12 + */ +#define WM8904_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */ +#define WM8904_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */ +#define WM8904_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */ + +/* + * R146 (0x92) - EQ13 + */ +#define WM8904_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */ +#define WM8904_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */ +#define WM8904_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */ + +/* + * R147 (0x93) - EQ14 + */ +#define WM8904_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */ +#define WM8904_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */ +#define WM8904_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */ + +/* + * R148 (0x94) - EQ15 + */ +#define WM8904_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */ +#define WM8904_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */ +#define WM8904_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */ + +/* + * R149 (0x95) - EQ16 + */ +#define WM8904_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */ +#define WM8904_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */ +#define WM8904_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */ + +/* + * R150 (0x96) - EQ17 + */ +#define WM8904_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */ +#define WM8904_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */ +#define WM8904_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */ + +/* + * R151 (0x97) - EQ18 + */ +#define WM8904_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */ +#define WM8904_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */ +#define WM8904_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */ + +/* + * R152 (0x98) - EQ19 + */ +#define WM8904_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */ +#define WM8904_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */ +#define WM8904_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */ + +/* + * R153 (0x99) - EQ20 + */ +#define WM8904_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */ +#define WM8904_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */ +#define WM8904_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */ + +/* + * R154 (0x9A) - EQ21 + */ +#define WM8904_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */ +#define WM8904_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */ +#define WM8904_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */ + +/* + * R155 (0x9B) - EQ22 + */ +#define WM8904_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */ +#define WM8904_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */ +#define WM8904_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */ + +/* + * R156 (0x9C) - EQ23 + */ +#define WM8904_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */ +#define WM8904_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */ +#define WM8904_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */ + +/* + * R157 (0x9D) - EQ24 + */ +#define WM8904_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */ +#define WM8904_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */ +#define WM8904_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */ + +/* + * R161 (0xA1) - Control Interface Test 1 + */ +#define WM8904_USER_KEY 0x0002 /* USER_KEY */ +#define WM8904_USER_KEY_MASK 0x0002 /* USER_KEY */ +#define WM8904_USER_KEY_SHIFT 1 /* USER_KEY */ +#define WM8904_USER_KEY_WIDTH 1 /* USER_KEY */ + +/* + * R204 (0xCC) - Analogue Output Bias 0 + */ +#define WM8904_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */ +#define WM8904_PGA_BIAS_SHIFT 4 /* PGA_BIAS - [6:4] */ +#define WM8904_PGA_BIAS_WIDTH 3 /* PGA_BIAS - [6:4] */ + +/* + * R247 (0xF7) - FLL NCO Test 0 + */ +#define WM8904_FLL_FRC_NCO 0x0001 /* FLL_FRC_NCO */ +#define WM8904_FLL_FRC_NCO_MASK 0x0001 /* FLL_FRC_NCO */ +#define WM8904_FLL_FRC_NCO_SHIFT 0 /* FLL_FRC_NCO */ +#define WM8904_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */ + +/* + * R248 (0xF8) - FLL NCO Test 1 + */ +#define WM8904_FLL_FRC_NCO_VAL_MASK 0x003F /* FLL_FRC_NCO_VAL - [5:0] */ +#define WM8904_FLL_FRC_NCO_VAL_SHIFT 0 /* FLL_FRC_NCO_VAL - [5:0] */ +#define WM8904_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [5:0] */ + +#endif -- GitLab From ffbfd336f9eac361e1630cfcb17a70607551daf2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Nov 2009 17:56:11 +0100 Subject: [PATCH 0023/3892] ASoC: Add regulator support to CS4270 codec driver Signed-off-by: Daniel Mack Acked-by: Timur Tabi Cc: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ffe122d1cd76..8b5457542a0e 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "cs4270.h" @@ -106,6 +107,10 @@ #define CS4270_MUTE_DAC_A 0x01 #define CS4270_MUTE_DAC_B 0x02 +static const char *supply_names[] = { + "va", "vd", "vlc" +}; + /* Private data for the CS4270 */ struct cs4270_private { struct snd_soc_codec codec; @@ -114,6 +119,9 @@ struct cs4270_private { unsigned int mode; /* The mode (I2S or left-justified) */ unsigned int slave_mode; unsigned int manual_mute; + + /* power domain regulators */ + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; }; /** @@ -579,7 +587,8 @@ static int cs4270_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = cs4270_codec; - int ret; + struct cs4270_private *cs4270 = codec->private_data; + int i, ret; /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ socdev->card->codec = codec; @@ -599,6 +608,15 @@ static int cs4270_probe(struct platform_device *pdev) goto error_free_pcms; } + /* get the power supply regulators */ + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + cs4270->supplies[i].supply = supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + if (ret < 0) + goto error_free_pcms; + return 0; error_free_pcms: @@ -616,8 +634,11 @@ error_free_pcms: static int cs4270_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = cs4270_codec; + struct cs4270_private *cs4270 = codec->private_data; snd_soc_free_pcms(socdev); + regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); return 0; }; @@ -799,17 +820,33 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) { struct snd_soc_codec *codec = cs4270_codec; - int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; + struct cs4270_private *cs4270 = codec->private_data; + int reg, ret; - return snd_soc_write(codec, CS4270_PWRCTL, reg); + reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; + if (reg < 0) + return reg; + + ret = snd_soc_write(codec, CS4270_PWRCTL, reg); + if (ret < 0) + return ret; + + regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + + return 0; } static int cs4270_soc_resume(struct platform_device *pdev) { struct snd_soc_codec *codec = cs4270_codec; + struct cs4270_private *cs4270 = codec->private_data; struct i2c_client *i2c_client = codec->control_data; int reg; + regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + /* In case the device was put to hard reset during sleep, we need to * wait 500ns here before any I2C communication. */ ndelay(500); -- GitLab From 09a072947791088b88ae15111cf68fc5aaaf758d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 9 Nov 2009 16:27:40 +0900 Subject: [PATCH 0024/3892] sh: hw-breakpoints: Add preliminary support for SH-4A UBC. This adds preliminary support for the SH-4A UBC to the hw-breakpoints API. Presently only a single channel is implemented, and the ptrace interface still needs to be converted. This is the first step to cleaning up the long-standing UBC mess, making the UBC more generally accessible, and finally making it SMP safe. An additional abstraction will be layered on top of this as with the perf events code to permit the various CPU families to wire up support for their own specific UBCs, as many variations exist. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 1 + arch/sh/include/asm/Kbuild | 4 +- arch/sh/include/asm/hw_breakpoint.h | 53 ++++ arch/sh/include/asm/kdebug.h | 2 + arch/sh/include/asm/processor_32.h | 8 +- arch/sh/include/asm/system.h | 2 - arch/sh/include/asm/thread_info.h | 2 + arch/sh/include/asm/ubc.h | 8 +- arch/sh/kernel/Makefile | 1 + arch/sh/kernel/cpu/sh3/ex.S | 2 +- arch/sh/kernel/hw_breakpoint.c | 416 ++++++++++++++++++++++++++++ arch/sh/kernel/process_32.c | 94 +------ arch/sh/kernel/ptrace_32.c | 19 -- 13 files changed, 495 insertions(+), 117 deletions(-) create mode 100644 arch/sh/include/asm/hw_breakpoint.h create mode 100644 arch/sh/kernel/hw_breakpoint.c diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 88cdeb9f72d9..d563884833e9 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -39,6 +39,7 @@ config SUPERH32 select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FUNCTION_GRAPH_TRACER select HAVE_ARCH_KGDB + select HAVE_HW_BREAKPOINT if CPU_SH4A select ARCH_HIBERNATION_POSSIBLE if MMU config SUPERH64 diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild index e121c30f797d..46cb93477bcb 100644 --- a/arch/sh/include/asm/Kbuild +++ b/arch/sh/include/asm/Kbuild @@ -1,6 +1,8 @@ include include/asm-generic/Kbuild.asm -header-y += cachectl.h cpu-features.h +header-y += cachectl.h +header-y += cpu-features.h +header-y += hw_breakpoint.h unifdef-y += unistd_32.h unifdef-y += unistd_64.h diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h new file mode 100644 index 000000000000..0f4a00f60058 --- /dev/null +++ b/arch/sh/include/asm/hw_breakpoint.h @@ -0,0 +1,53 @@ +#ifndef __ASM_SH_HW_BREAKPOINT_H +#define __ASM_SH_HW_BREAKPOINT_H + +#include +#include +#include + +#ifdef __KERNEL__ +#define __ARCH_HW_BREAKPOINT_H + +struct arch_hw_breakpoint { + char *name; /* Contains name of the symbol to set bkpt */ + unsigned long address; + unsigned long asid; + u16 len; + u16 type; +}; + +enum { + SH_BREAKPOINT_READ = (1 << 1), + SH_BREAKPOINT_WRITE = (1 << 2), + SH_BREAKPOINT_RW = SH_BREAKPOINT_READ | SH_BREAKPOINT_WRITE, + + SH_BREAKPOINT_LEN_1 = (1 << 12), + SH_BREAKPOINT_LEN_2 = (1 << 13), + SH_BREAKPOINT_LEN_4 = SH_BREAKPOINT_LEN_1 | SH_BREAKPOINT_LEN_2, + SH_BREAKPOINT_LEN_8 = (1 << 14), +}; + +/* Total number of available UBC channels */ +#define HBP_NUM 1 /* XXX */ + +struct perf_event; +struct task_struct; +struct pmu; + +extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len); +extern int arch_validate_hwbkpt_settings(struct perf_event *bp, + struct task_struct *tsk); +extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data); + +int arch_install_hw_breakpoint(struct perf_event *bp); +void arch_uninstall_hw_breakpoint(struct perf_event *bp); +void hw_breakpoint_pmu_read(struct perf_event *bp); +void hw_breakpoint_pmu_unthrottle(struct perf_event *bp); + +extern void arch_fill_perf_breakpoint(struct perf_event *bp); + +extern struct pmu perf_ops_bp; + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_HW_BREAKPOINT_H */ diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h index 985219f9759e..5f6d2e9ccb7c 100644 --- a/arch/sh/include/asm/kdebug.h +++ b/arch/sh/include/asm/kdebug.h @@ -6,6 +6,8 @@ enum die_val { DIE_TRAP, DIE_NMI, DIE_OOPS, + DIE_BREAKPOINT, + DIE_SSTEP, }; #endif /* __ASM_SH_KDEBUG_H */ diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 9a8714945dc9..f4b54040dbc3 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -14,6 +14,7 @@ #include #include #include +#include /* * Default implementation of macro that returns current @@ -99,8 +100,8 @@ struct thread_struct { unsigned long sp; unsigned long pc; - /* Hardware debugging registers */ - unsigned long ubc_pc; + /* Save middle states of ptrace breakpoints */ + struct perf_event *ptrace_bps[NR_UBC_CHANNELS]; /* floating point info */ union sh_fpu_union fpu; @@ -111,9 +112,6 @@ struct thread_struct { #endif }; -/* Count of active tasks with UBC settings */ -extern int ubc_usercnt; - #define INIT_THREAD { \ .sp = sizeof(init_stack) + (long) &init_stack, \ } diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index b5c5acdc8c0e..1014da8b3ed3 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -144,8 +144,6 @@ void per_cpu_trap_init(void); void default_idle(void); void cpu_idle_wait(void); -asmlinkage void break_point_trap(void); - #ifdef CONFIG_SUPERH32 #define BUILD_TRAP_HANDLER(name) \ asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5, \ diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index bdeb9d46d17d..8ab9145bf50b 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -117,6 +117,7 @@ extern void free_thread_info(struct thread_info *ti); #define TIF_SECCOMP 6 /* secure computing */ #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ #define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ +#define TIF_DEBUG 9 /* uses UBC */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 18 @@ -131,6 +132,7 @@ extern void free_thread_info(struct thread_info *ti); #define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) +#define _TIF_DEBUG (1 << TIF_DEBUG) #define _TIF_USEDFPU (1 << TIF_USEDFPU) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_FREEZE (1 << TIF_FREEZE) diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h index 4ca4b7717371..dd7878197b6e 100644 --- a/arch/sh/include/asm/ubc.h +++ b/arch/sh/include/asm/ubc.h @@ -10,8 +10,8 @@ */ #ifndef __ASM_SH_UBC_H #define __ASM_SH_UBC_H -#ifdef __KERNEL__ +#ifdef __KERNEL__ #include /* User Break Controller */ @@ -60,6 +60,12 @@ #define BRCR_UBDE (1 << 0) #endif +/* + * All SH parts have 2 UBC channels. I defy any hardware designer to + * invalidate this assertion. + */ +#define NR_UBC_CHANNELS 2 + #ifndef __ASSEMBLY__ /* arch/sh/kernel/cpu/ubc.S */ extern void ubc_sleep(void); diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index a2d0a40f3848..649daadd4519 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o EXTRA_CFLAGS += -Werror diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S index 46610c35c232..99b4d020179a 100644 --- a/arch/sh/kernel/cpu/sh3/ex.S +++ b/arch/sh/kernel/cpu/sh3/ex.S @@ -49,7 +49,7 @@ ENTRY(exception_handling_table) .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ .long nmi_trap_handler /* 1C0 */ ! Allow trap to debugger - .long break_point_trap /* 1E0 */ + .long breakpoint_trap_handler /* 1E0 */ /* * Pad the remainder of the table out, exceptions residing in far diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c new file mode 100644 index 000000000000..ff3cb3d7df8f --- /dev/null +++ b/arch/sh/kernel/hw_breakpoint.c @@ -0,0 +1,416 @@ +/* + * arch/sh/kernel/hw_breakpoint.c + * + * Unified kernel/user-space hardware breakpoint facility for the on-chip UBC. + * + * Copyright (C) 2009 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ubc_context { + unsigned long pc; + unsigned long state; +}; + +/* Per cpu ubc channel state */ +static DEFINE_PER_CPU(struct ubc_context, ubc_ctx[HBP_NUM]); + +/* + * Stores the breakpoints currently in use on each breakpoint address + * register for each cpus + */ +static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]); + +static int __init ubc_init(void) +{ + __raw_writel(0, UBC_CAMR0); + __raw_writel(0, UBC_CBR0); + __raw_writel(0, UBC_CBCR); + + __raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR0); + + /* dummy read for write posting */ + (void)__raw_readl(UBC_CRR0); + + return 0; +} +arch_initcall(ubc_init); + +/* + * Install a perf counter breakpoint. + * + * We seek a free UBC channel and use it for this breakpoint. + * + * Atomic: we hold the counter->ctx->lock and we only handle variables + * and registers local to this cpu. + */ +int arch_install_hw_breakpoint(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + struct ubc_context *ubc_ctx; + int i; + + for (i = 0; i < HBP_NUM; i++) { + struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); + + if (!*slot) { + *slot = bp; + break; + } + } + + if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot")) + return -EBUSY; + + ubc_ctx = &__get_cpu_var(ubc_ctx[i]); + + ubc_ctx->pc = info->address; + ubc_ctx->state = info->len | info->type; + + __raw_writel(UBC_CBR_CE | ubc_ctx->state, UBC_CBR0); + __raw_writel(ubc_ctx->pc, UBC_CAR0); + + return 0; +} + +/* + * Uninstall the breakpoint contained in the given counter. + * + * First we search the debug address register it uses and then we disable + * it. + * + * Atomic: we hold the counter->ctx->lock and we only handle variables + * and registers local to this cpu. + */ +void arch_uninstall_hw_breakpoint(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + struct ubc_context *ubc_ctx; + int i; + + for (i = 0; i < HBP_NUM; i++) { + struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); + + if (*slot == bp) { + *slot = NULL; + break; + } + } + + if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot")) + return; + + ubc_ctx = &__get_cpu_var(ubc_ctx[i]); + ubc_ctx->pc = 0; + ubc_ctx->state &= ~(info->len | info->type); + + __raw_writel(ubc_ctx->pc, UBC_CBR0); + __raw_writel(ubc_ctx->state, UBC_CAR0); +} + +static int get_hbp_len(u16 hbp_len) +{ + unsigned int len_in_bytes = 0; + + switch (hbp_len) { + case SH_BREAKPOINT_LEN_1: + len_in_bytes = 1; + break; + case SH_BREAKPOINT_LEN_2: + len_in_bytes = 2; + break; + case SH_BREAKPOINT_LEN_4: + len_in_bytes = 4; + break; + case SH_BREAKPOINT_LEN_8: + len_in_bytes = 8; + break; + } + return len_in_bytes; +} + +/* + * Check for virtual address in user space. + */ +int arch_check_va_in_userspace(unsigned long va, u16 hbp_len) +{ + unsigned int len; + + len = get_hbp_len(hbp_len); + + return (va <= TASK_SIZE - len); +} + +/* + * Check for virtual address in kernel space. + */ +static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len) +{ + unsigned int len; + + len = get_hbp_len(hbp_len); + + return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); +} + +/* + * Store a breakpoint's encoded address, length, and type. + */ +static int arch_store_info(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + + /* + * User-space requests will always have the address field populated + * For kernel-addresses, either the address or symbol name can be + * specified. + */ + if (info->name) + info->address = (unsigned long)kallsyms_lookup_name(info->name); + if (info->address) { + info->asid = get_asid(); + return 0; + } + + return -EINVAL; +} + +int arch_bp_generic_fields(int sh_len, int sh_type, + int *gen_len, int *gen_type) +{ + /* Len */ + switch (sh_len) { + case SH_BREAKPOINT_LEN_1: + *gen_len = HW_BREAKPOINT_LEN_1; + break; + case SH_BREAKPOINT_LEN_2: + *gen_len = HW_BREAKPOINT_LEN_2; + break; + case SH_BREAKPOINT_LEN_4: + *gen_len = HW_BREAKPOINT_LEN_4; + break; + case SH_BREAKPOINT_LEN_8: + *gen_len = HW_BREAKPOINT_LEN_8; + break; + default: + return -EINVAL; + } + + /* Type */ + switch (sh_type) { + case SH_BREAKPOINT_READ: + *gen_type = HW_BREAKPOINT_R; + case SH_BREAKPOINT_WRITE: + *gen_type = HW_BREAKPOINT_W; + break; + case SH_BREAKPOINT_RW: + *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int arch_build_bp_info(struct perf_event *bp) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + + info->address = bp->attr.bp_addr; + + /* Len */ + switch (bp->attr.bp_len) { + case HW_BREAKPOINT_LEN_1: + info->len = SH_BREAKPOINT_LEN_1; + break; + case HW_BREAKPOINT_LEN_2: + info->len = SH_BREAKPOINT_LEN_2; + break; + case HW_BREAKPOINT_LEN_4: + info->len = SH_BREAKPOINT_LEN_4; + break; + case HW_BREAKPOINT_LEN_8: + info->len = SH_BREAKPOINT_LEN_8; + break; + default: + return -EINVAL; + } + + /* Type */ + switch (bp->attr.bp_type) { + case HW_BREAKPOINT_R: + info->type = SH_BREAKPOINT_READ; + break; + case HW_BREAKPOINT_W: + info->type = SH_BREAKPOINT_WRITE; + break; + case HW_BREAKPOINT_W | HW_BREAKPOINT_R: + info->type = SH_BREAKPOINT_RW; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * Validate the arch-specific HW Breakpoint register settings + */ +int arch_validate_hwbkpt_settings(struct perf_event *bp, + struct task_struct *tsk) +{ + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + unsigned int align; + int ret; + + ret = arch_build_bp_info(bp); + if (ret) + return ret; + + ret = -EINVAL; + + switch (info->len) { + case SH_BREAKPOINT_LEN_1: + align = 0; + break; + case SH_BREAKPOINT_LEN_2: + align = 1; + break; + case SH_BREAKPOINT_LEN_4: + align = 3; + break; + case SH_BREAKPOINT_LEN_8: + align = 7; + break; + default: + return ret; + } + + if (bp->callback) + ret = arch_store_info(bp); + + if (ret < 0) + return ret; + + /* + * Check that the low-order bits of the address are appropriate + * for the alignment implied by len. + */ + if (info->address & align) + return -EINVAL; + + /* Check that the virtual address is in the proper range */ + if (tsk) { + if (!arch_check_va_in_userspace(info->address, info->len)) + return -EFAULT; + } else { + if (!arch_check_va_in_kernelspace(info->address, info->len)) + return -EFAULT; + } + + return 0; +} + +/* + * Release the user breakpoints used by ptrace + */ +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) +{ + int i; + struct thread_struct *t = &tsk->thread; + + for (i = 0; i < HBP_NUM; i++) { + unregister_hw_breakpoint(t->ptrace_bps[i]); + t->ptrace_bps[i] = NULL; + } +} + +static int __kprobes hw_breakpoint_handler(struct die_args *args) +{ + int cpu, i, rc = NOTIFY_STOP; + struct perf_event *bp; + unsigned long val; + + val = __raw_readl(UBC_CBR0); + __raw_writel(val & ~UBC_CBR_CE, UBC_CBR0); + + cpu = get_cpu(); + for (i = 0; i < HBP_NUM; i++) { + /* + * The counter may be concurrently released but that can only + * occur from a call_rcu() path. We can then safely fetch + * the breakpoint, use its callback, touch its counter + * while we are in an rcu_read_lock() path. + */ + rcu_read_lock(); + + bp = per_cpu(bp_per_reg[i], cpu); + if (bp) { + rc = NOTIFY_DONE; + } else { + rcu_read_unlock(); + break; + } + + (bp->callback)(bp, args->regs); + + rcu_read_unlock(); + } + + if (bp) { + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + + __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0); + __raw_writel(info->address, UBC_CAR0); + } + + put_cpu(); + + return rc; +} + +BUILD_TRAP_HANDLER(breakpoint) +{ + unsigned long ex = lookup_exception_vector(); + TRAP_HANDLER_DECL; + + notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); +} + +/* + * Handle debug exception notifications. + */ +int __kprobes hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data) +{ + if (val != DIE_BREAKPOINT) + return NOTIFY_DONE; + + return hw_breakpoint_handler(data); +} + +void hw_breakpoint_pmu_read(struct perf_event *bp) +{ + /* TODO */ +} + +void hw_breakpoint_pmu_unthrottle(struct perf_event *bp) +{ + /* TODO */ +} diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 0673c4746be3..4a2c866f9773 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ #include #include -int ubc_usercnt = 0; - #ifdef CONFIG_32BIT static void watchdog_trigger_immediate(void) { @@ -148,16 +147,15 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ void exit_thread(void) { - if (current->thread.ubc_pc) { - current->thread.ubc_pc = 0; - ubc_usercnt -= 1; - } } void flush_thread(void) { -#if defined(CONFIG_SH_FPU) struct task_struct *tsk = current; + + flush_ptrace_hw_breakpoint(tsk); + +#if defined(CONFIG_SH_FPU) /* Forget lazy FPU state */ clear_fpu(tsk, task_pt_regs(tsk)); clear_used_math(); @@ -195,9 +193,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, { struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs; -#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP) struct task_struct *tsk = current; -#endif #if defined(CONFIG_SH_FPU) unlazy_fpu(tsk, regs); @@ -234,53 +230,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; - p->thread.ubc_pc = 0; + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); return 0; } -/* Tracing by user break controller. */ -static void ubc_set_tracing(int asid, unsigned long pc) -{ -#if defined(CONFIG_CPU_SH4A) - unsigned long val; - - val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE); - val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid)); - - ctrl_outl(val, UBC_CBR0); - ctrl_outl(pc, UBC_CAR0); - ctrl_outl(0x0, UBC_CAMR0); - ctrl_outl(0x0, UBC_CBCR); - - val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); - ctrl_outl(val, UBC_CRR0); - - /* Read UBC register that we wrote last, for checking update */ - val = ctrl_inl(UBC_CRR0); - -#else /* CONFIG_CPU_SH4A */ - ctrl_outl(pc, UBC_BARA); - -#ifdef CONFIG_MMU - ctrl_outb(asid, UBC_BASRA); -#endif - - ctrl_outl(0, UBC_BAMRA); - - if (current_cpu_data.type == CPU_SH7729 || - current_cpu_data.type == CPU_SH7710 || - current_cpu_data.type == CPU_SH7712 || - current_cpu_data.type == CPU_SH7203){ - ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); - ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); - } else { - ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); - ctrl_outw(BRCR_PCBA, UBC_BRCR); - } -#endif /* CONFIG_CPU_SH4A */ -} - /* * switch_to(x,y) should switch tasks from x to y. * @@ -302,25 +256,6 @@ __switch_to(struct task_struct *prev, struct task_struct *next) : "r" (task_thread_info(next))); #endif - /* If no tasks are using the UBC, we're done */ - if (ubc_usercnt == 0) - /* If no tasks are using the UBC, we're done */; - else if (next->thread.ubc_pc && next->mm) { - int asid = 0; -#ifdef CONFIG_MMU - asid |= cpu_asid(smp_processor_id(), next->mm); -#endif - ubc_set_tracing(asid, next->thread.ubc_pc); - } else { -#if defined(CONFIG_CPU_SH4A) - ctrl_outl(UBC_CBR_INIT, UBC_CBR0); - ctrl_outl(UBC_CRR_INIT, UBC_CRR0); -#else - ctrl_outw(0, UBC_BBRA); - ctrl_outw(0, UBC_BBRB); -#endif - } - return prev; } @@ -412,20 +347,3 @@ unsigned long get_wchan(struct task_struct *p) return pc; } - -asmlinkage void break_point_trap(void) -{ - /* Clear tracing. */ -#if defined(CONFIG_CPU_SH4A) - ctrl_outl(UBC_CBR_INIT, UBC_CBR0); - ctrl_outl(UBC_CRR_INIT, UBC_CRR0); -#else - ctrl_outw(0, UBC_BBRA); - ctrl_outw(0, UBC_BBRB); - ctrl_outl(0, UBC_BRCR); -#endif - current->thread.ubc_pc = 0; - ubc_usercnt -= 1; - - force_sig(SIGTRAP, current); -} diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 9be35f348093..bdb10446cbac 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -65,31 +65,12 @@ static inline int put_stack_long(struct task_struct *task, int offset, void user_enable_single_step(struct task_struct *child) { - /* Next scheduling will set up UBC */ - if (child->thread.ubc_pc == 0) - ubc_usercnt += 1; - - child->thread.ubc_pc = get_stack_long(child, - offsetof(struct pt_regs, pc)); - set_tsk_thread_flag(child, TIF_SINGLESTEP); } void user_disable_single_step(struct task_struct *child) { clear_tsk_thread_flag(child, TIF_SINGLESTEP); - - /* - * Ensure the UBC is not programmed at the next context switch. - * - * Normally this is not needed but there are sequences such as - * singlestep, signal delivery, and continue that leave the - * ubc_pc non-zero leading to spurious SIGTRAPs. - */ - if (child->thread.ubc_pc != 0) { - ubc_usercnt -= 1; - child->thread.ubc_pc = 0; - } } /* -- GitLab From f409adf5b1db55ece7e80b67a944f9c0d3fe93e9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 1 Dec 2009 14:02:00 +0100 Subject: [PATCH 0025/3892] futex: Protect pid lookup in compat code with RCU find_task_by_vpid() in compat_sys_get_robust_list() does not require tasklist_lock. It can be protected with rcu_read_lock as done in sys_get_robust_list() already. Signed-off-by: Thomas Gleixner Cc: Darren Hart Cc: Peter Zijlstra --- kernel/futex_compat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 235716556bf1..d49afb2395e5 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -146,7 +146,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, struct task_struct *p; ret = -ESRCH; - read_lock(&tasklist_lock); + rcu_read_lock(); p = find_task_by_vpid(pid); if (!p) goto err_unlock; @@ -157,7 +157,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, !capable(CAP_SYS_PTRACE)) goto err_unlock; head = p->compat_robust_list; - read_unlock(&tasklist_lock); + rcu_read_unlock(); } if (put_user(sizeof(*head), len_ptr)) @@ -165,7 +165,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, return put_user(ptr_to_compat(head), head_ptr); err_unlock: - read_unlock(&tasklist_lock); + rcu_read_unlock(); return ret; } -- GitLab From f7b3a8355ba6cad251297844a0bdd08898ea36e0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:26:58 -0700 Subject: [PATCH 0026/3892] of/flattree: Merge early_init_dt_check_for_initrd() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/prom.c | 32 ------------------------------ arch/powerpc/kernel/prom.c | 30 ---------------------------- drivers/of/fdt.c | 37 +++++++++++++++++++++++++++++++++++ include/linux/of_fdt.h | 1 + 4 files changed, 38 insertions(+), 62 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index a38e3733a09c..7959495b1d00 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -113,38 +113,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node, return 0; } -#ifdef CONFIG_BLK_DEV_INITRD -static void __init early_init_dt_check_for_initrd(unsigned long node) -{ - unsigned long l; - u32 *prop; - - pr_debug("Looking for initrd properties... "); - - prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); - if (prop) { - initrd_start = (unsigned long) - __va((u32)of_read_ulong(prop, l/4)); - - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); - if (prop) { - initrd_end = (unsigned long) - __va((u32)of_read_ulong(prop, 1/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } - - pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", - initrd_start, initrd_end); -} -#else -static inline void early_init_dt_check_for_initrd(unsigned long node) -{ -} -#endif /* CONFIG_BLK_DEV_INITRD */ - static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 7f8856655144..1ecd6c6ecabd 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -373,36 +373,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node, return 0; } -#ifdef CONFIG_BLK_DEV_INITRD -static void __init early_init_dt_check_for_initrd(unsigned long node) -{ - unsigned long l; - u32 *prop; - - DBG("Looking for initrd properties... "); - - prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); - if (prop) { - initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); - - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); - if (prop) { - initrd_end = (unsigned long) - __va(of_read_ulong(prop, l/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } - - DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end); -} -#else -static inline void early_init_dt_check_for_initrd(unsigned long node) -{ -} -#endif /* CONFIG_BLK_DEV_INITRD */ - static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 43d236cbc17b..6ad98e85dc93 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -369,6 +370,42 @@ unsigned long __init unflatten_dt_node(unsigned long mem, return mem; } +#ifdef CONFIG_BLK_DEV_INITRD +/** + * early_init_dt_check_for_initrd - Decode initrd location from flat tree + * @node: reference to node containing initrd location ('chosen') + */ +void __init early_init_dt_check_for_initrd(unsigned long node) +{ + unsigned long len; + u32 *prop; + + pr_debug("Looking for initrd properties... "); + + prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); + if (prop) { + initrd_start = (unsigned long) + __va(of_read_ulong(prop, len/4)); + + prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); + if (prop) { + initrd_end = (unsigned long) + __va(of_read_ulong(prop, len/4)); + initrd_below_start_ok = 1; + } else { + initrd_start = 0; + } + } + + pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", + initrd_start, initrd_end); +} +#else +inline void early_init_dt_check_for_initrd(unsigned long node) +{ +} +#endif /* CONFIG_BLK_DEV_INITRD */ + /** * unflatten_device_tree - create tree of device_nodes from flat blob * diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 81231e04e8f3..ec2db8278c3f 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -69,6 +69,7 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); +extern void early_init_dt_check_for_initrd(unsigned long node); /* Other Prototypes */ extern void finish_device_tree(void); -- GitLab From f00abd94918c9780f9d2d961fc0e419c11457922 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:27:10 -0700 Subject: [PATCH 0027/3892] of/flattree: Merge earlyinit_dt_scan_root() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Tested-by: Wolfram Sang --- arch/microblaze/kernel/prom.c | 23 ----------------------- arch/powerpc/kernel/prom.c | 24 ------------------------ drivers/of/fdt.c | 26 ++++++++++++++++++++++++++ include/linux/of_fdt.h | 6 ++++++ 4 files changed, 32 insertions(+), 47 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 7959495b1d00..189179a9b554 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -42,9 +42,6 @@ #include #include -static int __initdata dt_root_addr_cells; -static int __initdata dt_root_size_cells; - typedef u32 cell_t; /* export that to outside world */ @@ -158,26 +155,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, return 1; } -static int __init early_init_dt_scan_root(unsigned long node, - const char *uname, int depth, void *data) -{ - u32 *prop; - - if (depth != 0) - return 0; - - prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = (prop == NULL) ? 1 : *prop; - pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); - - prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = (prop == NULL) ? 2 : *prop; - pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); - - /* break now */ - return 1; -} - static u64 __init dt_mem_next_cell(int s, cell_t **cellp) { cell_t *p = *cellp; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1ecd6c6ecabd..78f65a4d8b03 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -61,10 +61,6 @@ #define DBG(fmt...) #endif - -static int __initdata dt_root_addr_cells; -static int __initdata dt_root_size_cells; - #ifdef CONFIG_PPC64 int __initdata iommu_is_off; int __initdata iommu_force_on; @@ -436,26 +432,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, return 1; } -static int __init early_init_dt_scan_root(unsigned long node, - const char *uname, int depth, void *data) -{ - u32 *prop; - - if (depth != 0) - return 0; - - prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = (prop == NULL) ? 1 : *prop; - DBG("dt_root_size_cells = %x\n", dt_root_size_cells); - - prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = (prop == NULL) ? 2 : *prop; - DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); - - /* break now */ - return 1; -} - static u64 __init dt_mem_next_cell(int s, cell_t **cellp) { cell_t *p = *cellp; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6ad98e85dc93..be200be47269 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,9 @@ #include #include +int __initdata dt_root_addr_cells; +int __initdata dt_root_size_cells; + struct boot_param_header *initial_boot_params; char *find_flat_dt_string(u32 offset) @@ -406,6 +409,29 @@ inline void early_init_dt_check_for_initrd(unsigned long node) } #endif /* CONFIG_BLK_DEV_INITRD */ +/** + * early_init_dt_scan_root - fetch the top level address and size cells + */ +int __init early_init_dt_scan_root(unsigned long node, const char *uname, + int depth, void *data) +{ + u32 *prop; + + if (depth != 0) + return 0; + + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); + + prop = of_get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); + + /* break now */ + return 1; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index ec2db8278c3f..828c3cdaea78 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -58,6 +58,8 @@ struct boot_param_header { }; /* TBD: Temporary export of fdt globals - remove when code fully merged */ +extern int __initdata dt_root_addr_cells; +extern int __initdata dt_root_size_cells; extern struct boot_param_header *initial_boot_params; /* For scanning the flat device-tree at boot time */ @@ -71,6 +73,10 @@ extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); extern void early_init_dt_check_for_initrd(unsigned long node); +/* Early flat tree scan hooks */ +extern int early_init_dt_scan_root(unsigned long node, const char *uname, + int depth, void *data); + /* Other Prototypes */ extern void finish_device_tree(void); extern void unflatten_device_tree(void); -- GitLab From 83f7a06eb479e2aeb83536e77a2cb14cc2285e32 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Nov 2009 03:37:56 -0700 Subject: [PATCH 0028/3892] of/flattree: merge dt_mem_next_cell Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Tested-by: Wolfram Sang --- arch/microblaze/kernel/prom.c | 8 -------- arch/powerpc/kernel/prom.c | 8 -------- drivers/of/fdt.c | 8 ++++++++ include/linux/of_fdt.h | 1 + 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 189179a9b554..e0f4c34ed0f2 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -155,14 +155,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, return 1; } -static u64 __init dt_mem_next_cell(int s, cell_t **cellp) -{ - cell_t *p = *cellp; - - *cellp = p + s; - return of_read_number(p, s); -} - static int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data) { diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 78f65a4d8b03..048e3a3e9876 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -432,14 +432,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, return 1; } -static u64 __init dt_mem_next_cell(int s, cell_t **cellp) -{ - cell_t *p = *cellp; - - *cellp = p + s; - return of_read_number(p, s); -} - #ifdef CONFIG_PPC_PSERIES /* * Interpret the ibm,dynamic-memory property in the diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index be200be47269..ebce509b0886 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -432,6 +432,14 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } +u64 __init dt_mem_next_cell(int s, u32 **cellp) +{ + u32 *p = *cellp; + + *cellp = p + s; + return of_read_number(p, s); +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 828c3cdaea78..d1a37e56031e 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -72,6 +72,7 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name, extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); extern void early_init_dt_check_for_initrd(unsigned long node); +extern u64 dt_mem_next_cell(int s, u32 **cellp); /* Early flat tree scan hooks */ extern int early_init_dt_scan_root(unsigned long node, const char *uname, -- GitLab From 0f0b56c3f2df4a083fc9e934266e5bab1710e286 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 10 Dec 2009 23:42:17 -0700 Subject: [PATCH 0029/3892] of/flattree: eliminate cell_t typedef A cell is firmly established as a u32. No need to do an ugly typedef to redefine it to cell_t. Eliminate the unnecessary typedef so that it doesn't have to be added to the of_fdt header file Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/prom.c | 10 ++++------ arch/powerpc/kernel/prom.c | 14 ++++++-------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index e0f4c34ed0f2..50d8b09d5e3f 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -42,8 +42,6 @@ #include #include -typedef u32 cell_t; - /* export that to outside world */ struct device_node *of_chosen; @@ -159,7 +157,7 @@ static int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data) { char *type = of_get_flat_dt_prop(node, "device_type", NULL); - cell_t *reg, *endp; + __be32 *reg, *endp; unsigned long l; /* Look for the ibm,dynamic-reconfiguration-memory node */ @@ -178,13 +176,13 @@ static int __init early_init_dt_scan_memory(unsigned long node, } else if (strcmp(type, "memory") != 0) return 0; - reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); + reg = (__be32 *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); if (reg == NULL) - reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); + reg = (__be32 *)of_get_flat_dt_prop(node, "reg", &l); if (reg == NULL) return 0; - endp = reg + (l / sizeof(cell_t)); + endp = reg + (l / sizeof(__be32)); pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", uname, l, reg[0], reg[1], reg[2], reg[3]); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 048e3a3e9876..4e3181cded44 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -67,8 +67,6 @@ int __initdata iommu_force_on; unsigned long tce_alloc_start, tce_alloc_end; #endif -typedef u32 cell_t; - extern rwlock_t devtree_lock; /* temporary while merging */ /* export that to outside world */ @@ -441,22 +439,22 @@ static int __init early_init_dt_scan_chosen(unsigned long node, */ static int __init early_init_dt_scan_drconf_memory(unsigned long node) { - cell_t *dm, *ls, *usm; + __be32 *dm, *ls, *usm; unsigned long l, n, flags; u64 base, size, lmb_size; unsigned int is_kexec_kdump = 0, rngs; ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l); - if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t)) + if (ls == NULL || l < dt_root_size_cells * sizeof(__be32)) return 0; lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls); dm = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l); - if (dm == NULL || l < sizeof(cell_t)) + if (dm == NULL || l < sizeof(__be32)) return 0; n = *dm++; /* number of entries */ - if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t)) + if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(__be32)) return 0; /* check if this is a kexec/kdump kernel. */ @@ -515,7 +513,7 @@ static int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data) { char *type = of_get_flat_dt_prop(node, "device_type", NULL); - cell_t *reg, *endp; + __be32 *reg, *endp; unsigned long l; /* Look for the ibm,dynamic-reconfiguration-memory node */ @@ -540,7 +538,7 @@ static int __init early_init_dt_scan_memory(unsigned long node, if (reg == NULL) return 0; - endp = reg + (l / sizeof(cell_t)); + endp = reg + (l / sizeof(__be32)); DBG("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", uname, l, reg[0], reg[1], reg[2], reg[3]); -- GitLab From 86e032213424958b45564d0cc96b3316641a49d3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 10 Dec 2009 23:42:21 -0700 Subject: [PATCH 0030/3892] of/flattree: merge early_init_dt_scan_chosen() Merge common code between PowerPC and Microblaze. This patch splits the arch-specific stuff out into a new function, early_init_dt_scan_chosen_arch(). Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/prom.c | 44 ++------------------------------- arch/powerpc/kernel/prom.c | 46 ++++++++--------------------------- drivers/of/fdt.c | 38 +++++++++++++++++++++++++++++ include/linux/of_fdt.h | 3 +++ 4 files changed, 53 insertions(+), 78 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 50d8b09d5e3f..5505bcffd7dd 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -108,49 +108,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node, return 0; } -static int __init early_init_dt_scan_chosen(unsigned long node, - const char *uname, int depth, void *data) +void __init early_init_dt_scan_chosen_arch(unsigned long node) { - unsigned long l; - char *p; - - pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - - if (depth != 1 || - (strcmp(uname, "chosen") != 0 && - strcmp(uname, "chosen@0") != 0)) - return 0; - -#ifdef CONFIG_KEXEC - lprop = (u64 *)of_get_flat_dt_prop(node, - "linux,crashkernel-base", NULL); - if (lprop) - crashk_res.start = *lprop; - - lprop = (u64 *)of_get_flat_dt_prop(node, - "linux,crashkernel-size", NULL); - if (lprop) - crashk_res.end = crashk_res.start + *lprop - 1; -#endif - - early_init_dt_check_for_initrd(node); - - /* Retreive command line */ - p = of_get_flat_dt_prop(node, "bootargs", &l); - if (p != NULL && l > 0) - strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); - -#ifdef CONFIG_CMDLINE -#ifndef CONFIG_CMDLINE_FORCE - if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) -#endif - strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif /* CONFIG_CMDLINE */ - - pr_debug("Command line is: %s\n", cmd_line); - - /* break now */ - return 1; + /* No Microblaze specific code here */ } static int __init early_init_dt_scan_memory(unsigned long node, diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4e3181cded44..877fad9b3745 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -367,18 +367,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node, return 0; } -static int __init early_init_dt_scan_chosen(unsigned long node, - const char *uname, int depth, void *data) +void __init early_init_dt_scan_chosen_arch(unsigned long node) { unsigned long *lprop; - unsigned long l; - char *p; - - DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - - if (depth != 1 || - (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) - return 0; #ifdef CONFIG_PPC64 /* check if iommu is forced on or off */ @@ -389,17 +380,17 @@ static int __init early_init_dt_scan_chosen(unsigned long node, #endif /* mem=x on the command line is the preferred mechanism */ - lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); - if (lprop) - memory_limit = *lprop; + lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); + if (lprop) + memory_limit = *lprop; #ifdef CONFIG_PPC64 - lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); - if (lprop) - tce_alloc_start = *lprop; - lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); - if (lprop) - tce_alloc_end = *lprop; + lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); + if (lprop) + tce_alloc_start = *lprop; + lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); + if (lprop) + tce_alloc_end = *lprop; #endif #ifdef CONFIG_KEXEC @@ -411,23 +402,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, if (lprop) crashk_res.end = crashk_res.start + *lprop - 1; #endif - - early_init_dt_check_for_initrd(node); - - /* Retreive command line */ - p = of_get_flat_dt_prop(node, "bootargs", &l); - if (p != NULL && l > 0) - strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); - -#ifdef CONFIG_CMDLINE - if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) - strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif /* CONFIG_CMDLINE */ - - DBG("Command line is: %s\n", cmd_line); - - /* break now */ - return 1; } #ifdef CONFIG_PPC_PSERIES diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ebce509b0886..616a4767a950 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,10 @@ #include #include +#ifdef CONFIG_PPC +#include +#endif /* CONFIG_PPC */ + int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -440,6 +444,40 @@ u64 __init dt_mem_next_cell(int s, u32 **cellp) return of_read_number(p, s); } +int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long l; + char *p; + + pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + + if (depth != 1 || + (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) + return 0; + + early_init_dt_check_for_initrd(node); + + /* Retreive command line */ + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); + +#ifdef CONFIG_CMDLINE +#ifndef CONFIG_CMDLINE_FORCE + if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) +#endif + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + early_init_dt_scan_chosen_arch(node); + + pr_debug("Command line is: %s\n", cmd_line); + + /* break now */ + return 1; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index d1a37e56031e..8118d4559dd5 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -71,6 +71,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern unsigned long of_get_flat_dt_root(void); +extern void early_init_dt_scan_chosen_arch(unsigned long node); +extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, + int depth, void *data); extern void early_init_dt_check_for_initrd(unsigned long node); extern u64 dt_mem_next_cell(int s, u32 **cellp); -- GitLab From 14ff3e78304e3f7fe18f950c3aa0686e6800b3fb Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 10 Dec 2009 20:39:28 +0100 Subject: [PATCH 0031/3892] ALSA: dt019x: merge into the als100 driver The als100 driver is so similar to the dt019x/als007 driver that one driver's source can be used for both drivers with only few changes. Merge the dt019x driver into the als100. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/Kconfig | 21 +-- sound/isa/Makefile | 2 - sound/isa/als100.c | 121 ++++++++++++----- sound/isa/dt019x.c | 321 --------------------------------------------- 4 files changed, 90 insertions(+), 375 deletions(-) delete mode 100644 sound/isa/dt019x.c diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 02fe81ca88fd..194af3b01e13 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -63,15 +63,16 @@ config SND_AD1848 will be called snd-ad1848. config SND_ALS100 - tristate "Avance Logic ALS100/ALS120" + tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx" depends on PNP select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP help - Say Y here to include support for soundcards based on Avance - Logic ALS100, ALS110, ALS120 and ALS200 chips. + Say Y here to include support for soundcards based on the + Diamond Technologies DT-019X or Avance Logic chips: ALS007, + ALS100, ALS110, ALS120 and ALS200 chips. To compile this driver as a module, choose M here: the module will be called snd-als100. @@ -127,20 +128,6 @@ config SND_CS4236 To compile this driver as a module, choose M here: the module will be called snd-cs4236. -config SND_DT019X - tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" - depends on PNP - select ISAPNP - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB16_DSP - help - Say Y here to include support for soundcards based on the - Diamond Technologies DT-019X or Avance Logic ALS-007 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-dt019x. - config SND_ES968 tristate "Generic ESS ES968 driver" depends on PNP diff --git a/sound/isa/Makefile b/sound/isa/Makefile index b906b9a1a81e..c73d30c4f462 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o snd-als100-objs := als100.o snd-azt2320-objs := azt2320.o snd-cmi8330-objs := cmi8330.o -snd-dt019x-objs := dt019x.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sc6000-objs := sc6000.o @@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o obj-$(CONFIG_SND_ALS100) += snd-als100.o obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o -obj-$(CONFIG_SND_DT019X) += snd-dt019x.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SC6000) += snd-sc6000.o diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 5fd52e4d7079..20becc89f6f6 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -2,9 +2,13 @@ /* card-als100.c - driver for Avance Logic ALS100 based soundcards. Copyright (C) 1999-2000 by Massimo Piccioni + Copyright (C) 1999-2002 by Massimo Piccioni Thanks to Pierfrancesco 'qM2' Passerini. + Generalised for soundcards based on DT-0196 and ALS-007 chips + by Jonathan Woithe : June 2002. + 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 @@ -33,10 +37,10 @@ #define PFX "als100: " -MODULE_AUTHOR("Massimo Piccioni "); -MODULE_DESCRIPTION("Avance Logic ALS1X0"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," +MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0"); +MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," + "{Avance Logic ALS-007}}" + "{{Avance Logic,ALS100 - PRO16PNP}," "{Avance Logic,ALS110}," "{Avance Logic,ALS120}," "{Avance Logic,ALS200}," @@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," "{Avance Logic,ALS120}," "{RTL,RTL3000}}"); +MODULE_AUTHOR("Massimo Piccioni "); +MODULE_LICENSE("GPL"); + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ @@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for als100 based soundcard."); +MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard."); module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); +MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard."); module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); +MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard."); + +MODULE_ALIAS("snd-dt019x"); struct snd_card_als100 { - int dev_no; struct pnp_dev *dev; struct pnp_dev *devmpu; struct pnp_dev *devopl; @@ -72,25 +80,43 @@ struct snd_card_als100 { }; static struct pnp_card_device_id snd_als100_pnpids[] = { + /* DT197A30 */ + { .id = "RWB1688", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_DT019X }, + /* DT0196 / ALS-007 */ + { .id = "ALS0007", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_DT019X }, /* ALS100 - PRO16PNP */ - { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, + { .id = "ALS0001", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS110 - MF1000 - Digimate 3D Sound */ - { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } }, + { .id = "ALS0110", + .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS120 */ - { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, + { .id = "ALS0120", + .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS200 */ - { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } }, + { .id = "ALS0200", + .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS200 OEM */ - { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } }, + { .id = "ALS0200", + .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } }, + .driver_data = SB_HW_ALS100 }, /* RTL3000 */ - { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, - { .id = "", } /* end */ + { .id = "RTL3000", + .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, + .driver_data = SB_HW_ALS100 }, + { .id = "" } /* end */ }; MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); -#define DRIVER_NAME "snd-card-als100" - static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, struct pnp_card_link *card, const struct pnp_card_device_id *id) @@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, return err; } port[dev] = pnp_port_start(pdev, 0); - dma8[dev] = pnp_dma(pdev, 1); - dma16[dev] = pnp_dma(pdev, 0); + if (id->driver_data == SB_HW_DT019X) + dma8[dev] = pnp_dma(pdev, 0); + else { + dma8[dev] = pnp_dma(pdev, 1); + dma16[dev] = pnp_dma(pdev, 0); + } irq[dev] = pnp_irq(pdev, 0); pdev = acard->devmpu; @@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev, } snd_card_set_dev(card, &pcard->card->dev); - if ((error = snd_sbdsp_create(card, port[dev], - irq[dev], - snd_sb16dsp_interrupt, - dma8[dev], - dma16[dev], - SB_HW_ALS100, &chip)) < 0) { + if (pid->driver_data == SB_HW_DT019X) + dma16[dev] = -1; + + error = snd_sbdsp_create(card, port[dev], irq[dev], + snd_sb16dsp_interrupt, + dma8[dev], dma16[dev], + pid->driver_data, + &chip); + if (error < 0) { snd_card_free(card); return error; } acard->chip = chip; - strcpy(card->driver, "ALS100"); - strcpy(card->shortname, "Avance Logic ALS100"); - sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev], dma16[dev]); + if (pid->driver_data == SB_HW_DT019X) { + strcpy(card->driver, "DT-019X"); + strcpy(card->shortname, "Diamond Tech. DT-019X"); + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", + card->shortname, chip->name, chip->port, + irq[dev], dma8[dev]); + } else { + strcpy(card->driver, "ALS100"); + strcpy(card->shortname, "Avance Logic ALS100"); + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", + card->shortname, chip->name, chip->port, + irq[dev], dma8[dev], dma16[dev]); + } if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); @@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev, } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, + int mpu_type = MPU401_HW_ALS100; + + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + + if (pid->driver_data == SB_HW_DT019X) + mpu_type = MPU401_HW_MPU401; + + if (snd_mpu401_uart_new(card, 0, + mpu_type, mpu_port[dev], 0, - mpu_irq[dev], IRQF_DISABLED, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } @@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard) static struct pnp_card_driver als100_pnpc_driver = { .flags = PNP_DRIVER_RES_DISABLE, - .name = "als100", + .name = "als100", .id_table = snd_als100_pnpids, .probe = snd_als100_pnp_detect, .remove = __devexit_p(snd_als100_pnp_remove), @@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void) if (!als100_devices) { pnp_unregister_card_driver(&als100_pnpc_driver); #ifdef MODULE - snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); + snd_printk(KERN_ERR "no Avance Logic based soundcards found\n"); #endif return -ENODEV; } diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c deleted file mode 100644 index 80f5b1af9be8..000000000000 --- a/sound/isa/dt019x.c +++ /dev/null @@ -1,321 +0,0 @@ - -/* - dt019x.c - driver for Diamond Technologies DT-0197H based soundcards. - Copyright (C) 1999, 2002 by Massimo Piccioni - - Generalised for soundcards based on DT-0196 and ALS-007 chips - by Jonathan Woithe : June 2002. - - 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 -#include -#include -#include - -#define PFX "dt019x: " - -MODULE_AUTHOR("Massimo Piccioni "); -MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," - "{Avance Logic ALS-007}}"); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ -static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ -static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ -static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); - -struct snd_card_dt019x { - struct pnp_dev *dev; - struct pnp_dev *devmpu; - struct pnp_dev *devopl; - struct snd_sb *chip; -}; - -static struct pnp_card_device_id snd_dt019x_pnpids[] = { - /* DT197A30 */ - { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, - /* DT0196 / ALS-007 */ - { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, - { .id = "", } -}; - -MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids); - - -#define DRIVER_NAME "snd-card-dt019x" - - -static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *pid) -{ - struct pnp_dev *pdev; - int err; - - acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); - if (acard->dev == NULL) - return -ENODEV; - - acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); - acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); - - pdev = acard->dev; - - err = pnp_activate_dev(pdev); - if (err < 0) { - snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); - return err; - } - - port[dev] = pnp_port_start(pdev, 0); - dma8[dev] = pnp_dma(pdev, 0); - irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n", - port[dev],irq[dev],dma8[dev]); - - pdev = acard->devmpu; - if (pdev != NULL) { - err = pnp_activate_dev(pdev); - if (err < 0) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); - goto __mpu_error; - } - mpu_port[dev] = pnp_port_start(pdev, 0); - mpu_irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n", - mpu_port[dev],mpu_irq[dev]); - } else { - __mpu_error: - acard->devmpu = NULL; - mpu_port[dev] = -1; - } - - pdev = acard->devopl; - if (pdev != NULL) { - err = pnp_activate_dev(pdev); - if (err < 0) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); - goto __fm_error; - } - fm_port[dev] = pnp_port_start(pdev, 0); - snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]); - } else { - __fm_error: - acard->devopl = NULL; - fm_port[dev] = -1; - } - - return 0; -} - -static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) -{ - int error; - struct snd_sb *chip; - struct snd_card *card; - struct snd_card_dt019x *acard; - struct snd_opl3 *opl3; - - error = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_card_dt019x), &card); - if (error < 0) - return error; - acard = card->private_data; - - snd_card_set_dev(card, &pcard->card->dev); - if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) { - snd_card_free(card); - return error; - } - - if ((error = snd_sbdsp_create(card, port[dev], - irq[dev], - snd_sb16dsp_interrupt, - dma8[dev], - -1, - SB_HW_DT019X, - &chip)) < 0) { - snd_card_free(card); - return error; - } - acard->chip = chip; - - strcpy(card->driver, "DT-019X"); - strcpy(card->shortname, "Diamond Tech. DT-019X"); - sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev]); - - if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return error; - } - if ((error = snd_sbmixer_new(chip)) < 0) { - snd_card_free(card); - return error; - } - - if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if (mpu_irq[dev] == SNDRV_AUTO_IRQ) - mpu_irq[dev] = -1; - if (snd_mpu401_uart_new(card, 0, -/* MPU401_HW_SB,*/ - MPU401_HW_MPU401, - mpu_port[dev], 0, - mpu_irq[dev], - mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, - NULL) < 0) - snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); - } - - if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, - fm_port[dev], - fm_port[dev] + 2, - OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n", - fm_port[dev], fm_port[dev] + 2); - } else { - if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { - snd_card_free(card); - return error; - } - if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return error; - } - } - } - - if ((error = snd_card_register(card)) < 0) { - snd_card_free(card); - return error; - } - pnp_set_card_drvdata(pcard, card); - return 0; -} - -static unsigned int __devinitdata dt019x_devices; - -static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, - const struct pnp_card_device_id *pid) -{ - static int dev; - int res; - - for ( ; dev < SNDRV_CARDS; dev++) { - if (!enable[dev]) - continue; - res = snd_card_dt019x_probe(dev, card, pid); - if (res < 0) - return res; - dev++; - dt019x_devices++; - return 0; - } - return -ENODEV; -} - -static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard) -{ - snd_card_free(pnp_get_card_drvdata(pcard)); - pnp_set_card_drvdata(pcard, NULL); -} - -#ifdef CONFIG_PM -static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) -{ - struct snd_card *card = pnp_get_card_drvdata(pcard); - struct snd_card_dt019x *acard = card->private_data; - struct snd_sb *chip = acard->chip; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_sbmixer_suspend(chip); - return 0; -} - -static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard) -{ - struct snd_card *card = pnp_get_card_drvdata(pcard); - struct snd_card_dt019x *acard = card->private_data; - struct snd_sb *chip = acard->chip; - - snd_sbdsp_reset(chip); - snd_sbmixer_resume(chip); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif - -static struct pnp_card_driver dt019x_pnpc_driver = { - .flags = PNP_DRIVER_RES_DISABLE, - .name = "dt019x", - .id_table = snd_dt019x_pnpids, - .probe = snd_dt019x_pnp_probe, - .remove = __devexit_p(snd_dt019x_pnp_remove), -#ifdef CONFIG_PM - .suspend = snd_dt019x_pnp_suspend, - .resume = snd_dt019x_pnp_resume, -#endif -}; - -static int __init alsa_card_dt019x_init(void) -{ - int err; - - err = pnp_register_card_driver(&dt019x_pnpc_driver); - if (err) - return err; - - if (!dt019x_devices) { - pnp_unregister_card_driver(&dt019x_pnpc_driver); -#ifdef MODULE - snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); -#endif - return -ENODEV; - } - return 0; -} - -static void __exit alsa_card_dt019x_exit(void) -{ - pnp_unregister_card_driver(&dt019x_pnpc_driver); -} - -module_init(alsa_card_dt019x_init) -module_exit(alsa_card_dt019x_exit) -- GitLab From b2e8d7dab9d82be3851b8cbcc1ab64b1b2575844 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 10 Dec 2009 20:40:18 +0100 Subject: [PATCH 0032/3892] ALSA: opti93x: move controls definitions to opti93x driver Move OPTi93x controls definitions to the opti93x driver from the common wss-lib library module. These controls are used only by the opti93x driver. Also, fix capture source names. They are the same as opl3sa2 names. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 85 ++++++++++++++++++++++++++++++ sound/isa/wss/wss_lib.c | 80 ++++++---------------------- 2 files changed, 100 insertions(+), 65 deletions(-) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 106be6e471f7..ea4a67120468 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -546,6 +547,85 @@ __skip_mpu: #ifdef OPTi93X +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); + +static struct snd_kcontrol_new snd_opti93x_controls[] = { +WSS_DOUBLE("Master Playback Switch", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, + db_scale_6bit), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), +WSS_DOUBLE("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +WSS_DOUBLE("Mic Playback Switch", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Aux Playback Switch", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +}; + +static int __devinit snd_opti93x_mixer(struct snd_wss *chip) +{ + struct snd_card *card; + unsigned int idx; + struct snd_ctl_elem_id id1, id2; + int err; + + if (snd_BUG_ON(!chip || !chip->pcm)) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + memset(&id1, 0, sizeof(id1)); + memset(&id2, 0, sizeof(id2)); + id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + /* reassign AUX0 switch to CD */ + strcpy(id1.name, "Aux Playback Switch"); + strcpy(id2.name, "CD Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { + snd_printk(KERN_ERR "Cannot rename opti93x control\n"); + return err; + } + /* reassign AUX1 switch to FM */ + strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strcpy(id2.name, "FM Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { + snd_printk(KERN_ERR "Cannot rename opti93x control\n"); + return err; + } + /* remove AUX1 volume */ + strcpy(id1.name, "Aux Playback Volume"); id1.index = 1; + snd_ctl_remove_id(card, &id1); + + /* Replace WSS volume controls with OPTi93x volume controls */ + id1.index = 0; + for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { + strcpy(id1.name, snd_opti93x_controls[idx].name); + snd_ctl_remove_id(card, &id1); + + err = snd_ctl_add(card, + snd_ctl_new1(&snd_opti93x_controls[idx], chip)); + if (err < 0) + return err; + } + return 0; +} + static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { struct snd_wss *codec = dev_id; @@ -752,6 +832,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) error = snd_wss_mixer(codec); if (error < 0) return error; +#ifdef OPTi93X + error = snd_opti93x_mixer(codec); + if (error < 0) + return error; +#endif #ifdef CS4231 error = snd_wss_timer(codec, 0, &timer); if (error < 0) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5b9d6c18bc45..9191b32d9130 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, case WSS_HW_INTERWAVE: ptexts = gusmax_texts; break; + case WSS_HW_OPTI93X: case WSS_HW_OPL3SA2: ptexts = opl3sa_texts; break; @@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), }; -static struct snd_kcontrol_new snd_opti93x_controls[] = { -WSS_DOUBLE("Master Playback Switch", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE_TLV("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, - db_scale_6bit), -WSS_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -WSS_DOUBLE("FM Playback Switch", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Line Playback Switch", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), -WSS_DOUBLE("Mic Playback Switch", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -WSS_DOUBLE("CD Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Aux Playback Switch", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_wss_info_mux, - .get = snd_wss_get_mux, - .put = snd_wss_put_mux, -} -}; - int snd_wss_mixer(struct snd_wss *chip) { struct snd_card *card; unsigned int idx; int err; + int count = ARRAY_SIZE(snd_wss_controls); if (snd_BUG_ON(!chip || !chip->pcm)) return -EINVAL; @@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip) strcpy(card->mixername, chip->pcm->name); - if (chip->hardware == WSS_HW_OPTI93X) - for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_opti93x_controls[idx], - chip)); - if (err < 0) - return err; - } - else { - int count = ARRAY_SIZE(snd_wss_controls); - - /* Use only the first 11 entries on AD1848 */ - if (chip->hardware & WSS_HW_AD1848_MASK) - count = 11; - - for (idx = 0; idx < count; idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_wss_controls[idx], - chip)); - if (err < 0) - return err; - } + /* Use only the first 11 entries on AD1848 */ + if (chip->hardware & WSS_HW_AD1848_MASK) + count = 11; + /* There is no loopback on OPTI93X */ + else if (chip->hardware == WSS_HW_OPTI93X) + count = 9; + + for (idx = 0; idx < count; idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_wss_controls[idx], + chip)); + if (err < 0) + return err; } return 0; } -- GitLab From e9d0a803c127e2e30afb0df780ccb3af4e2adb28 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 12 Dec 2009 09:51:03 +0100 Subject: [PATCH 0033/3892] ALSA: opti93x: use dB scale for mixer controls Add dB scale for mixer controls. Fix dB scale for Master Volume control. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 36 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index ea4a67120468..b0ea310c87de 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -547,32 +547,40 @@ __skip_mpu: #ifdef OPTi93X -static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0); static struct snd_kcontrol_new snd_opti93x_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, - db_scale_6bit), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -WSS_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), + db_scale_5bit_3db_step), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1, + db_scale_5bit), +WSS_DOUBLE_TLV("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE_TLV("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), +WSS_DOUBLE_TLV("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), }; static int __devinit snd_opti93x_mixer(struct snd_wss *chip) -- GitLab From 74c2b45b714e49b427584b4bd8f44f1a24d82d9c Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 13 Dec 2009 21:13:44 +0100 Subject: [PATCH 0034/3892] ALSA: sb_mixer: convert pointer tables to mixer control tables Convert table of pointers to mixer controls into tables of the mixer controls. It saves about 20% of the snd-sb-common module size reported by lsmod. The als4000 uses part of sb16's control table. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/sb/sb_mixer.c | 330 ++++++++++++++-------------------------- 1 file changed, 115 insertions(+), 215 deletions(-) diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 318ff0c823e7..8cfc41fbe368 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty * SB 2.0 specific mixer elements */ -static struct sbmix_elem snd_sb20_ctl_master_play_vol = - SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); -static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = - SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); -static struct sbmix_elem snd_sb20_ctl_synth_play_vol = - SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); -static struct sbmix_elem snd_sb20_ctl_cd_play_vol = - SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); - -static struct sbmix_elem *snd_sb20_controls[] = { - &snd_sb20_ctl_master_play_vol, - &snd_sb20_ctl_pcm_play_vol, - &snd_sb20_ctl_synth_play_vol, - &snd_sb20_ctl_cd_play_vol +static struct sbmix_elem snd_sb20_controls[] = { + SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), + SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), + SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), + SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) }; static unsigned char snd_sb20_init_values[][2] = { @@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = { /* * SB Pro specific mixer elements */ -static struct sbmix_elem snd_sbpro_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = - SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); -static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); -static struct sbmix_elem snd_sbpro_ctl_capture_source = +static struct sbmix_elem snd_sbpro_controls[] = { + SB_DOUBLE("Master Playback Volume", + SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), + SB_DOUBLE("PCM Playback Volume", + SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), + SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), + SB_DOUBLE("Synth Playback Volume", + SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), + SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), + SB_DOUBLE("Line Playback Volume", + SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), + SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), { .name = "Capture Source", .type = SB_MIX_CAPTURE_PRO - }; -static struct sbmix_elem snd_sbpro_ctl_capture_filter = - SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); -static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = - SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); - -static struct sbmix_elem *snd_sbpro_controls[] = { - &snd_sbpro_ctl_master_play_vol, - &snd_sbpro_ctl_pcm_play_vol, - &snd_sbpro_ctl_pcm_play_filter, - &snd_sbpro_ctl_synth_play_vol, - &snd_sbpro_ctl_cd_play_vol, - &snd_sbpro_ctl_line_play_vol, - &snd_sbpro_ctl_mic_play_vol, - &snd_sbpro_ctl_capture_source, - &snd_sbpro_ctl_capture_filter, - &snd_sbpro_ctl_capture_low_filter + }, + SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), + SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) }; static unsigned char snd_sbpro_init_values[][2] = { @@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = { /* * SB16 specific mixer elements */ -static struct sbmix_elem snd_sb16_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = - SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); -static struct sbmix_elem snd_sb16_ctl_tone_bass = - SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); -static struct sbmix_elem snd_sb16_ctl_tone_treble = - SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); -static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_synth_capture_route = - SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); -static struct sbmix_elem snd_sb16_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_cd_capture_route = - SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); -static struct sbmix_elem snd_sb16_ctl_cd_play_switch = - SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); -static struct sbmix_elem snd_sb16_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_line_capture_route = - SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); -static struct sbmix_elem snd_sb16_ctl_line_play_switch = - SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); -static struct sbmix_elem snd_sb16_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_mic_capture_route = - SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); -static struct sbmix_elem snd_sb16_ctl_mic_play_switch = - SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); -static struct sbmix_elem snd_sb16_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); -static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = - SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); -static struct sbmix_elem snd_sb16_ctl_capture_vol = - SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); -static struct sbmix_elem snd_sb16_ctl_play_vol = - SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); -static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = - SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); - -static struct sbmix_elem *snd_sb16_controls[] = { - &snd_sb16_ctl_master_play_vol, - &snd_sb16_ctl_3d_enhance_switch, - &snd_sb16_ctl_tone_bass, - &snd_sb16_ctl_tone_treble, - &snd_sb16_ctl_pcm_play_vol, - &snd_sb16_ctl_synth_capture_route, - &snd_sb16_ctl_synth_play_vol, - &snd_sb16_ctl_cd_capture_route, - &snd_sb16_ctl_cd_play_switch, - &snd_sb16_ctl_cd_play_vol, - &snd_sb16_ctl_line_capture_route, - &snd_sb16_ctl_line_play_switch, - &snd_sb16_ctl_line_play_vol, - &snd_sb16_ctl_mic_capture_route, - &snd_sb16_ctl_mic_play_switch, - &snd_sb16_ctl_mic_play_vol, - &snd_sb16_ctl_pc_speaker_vol, - &snd_sb16_ctl_capture_vol, - &snd_sb16_ctl_play_vol, - &snd_sb16_ctl_auto_mic_gain +static struct sbmix_elem snd_sb16_controls[] = { + SB_DOUBLE("Master Playback Volume", + SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), + SB_DOUBLE("PCM Playback Volume", + SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("Synth Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), + SB_DOUBLE("Synth Playback Volume", + SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("CD Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), + SB_DOUBLE("CD Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), + SB_DOUBLE("CD Playback Volume", + SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("Mic Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), + SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), + SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), + SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), + SB_DOUBLE("Capture Volume", + SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), + SB_DOUBLE("Playback Volume", + SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), + SB16_INPUT_SW("Line Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), + SB_DOUBLE("Line Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), + SB_DOUBLE("Line Playback Volume", + SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), + SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), + SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), + SB_DOUBLE("Tone Control - Bass", + SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), + SB_DOUBLE("Tone Control - Treble", + SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) }; static unsigned char snd_sb16_init_values[][2] = { @@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = { /* * DT019x specific mixer elements */ -static struct sbmix_elem snd_dt019x_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); -static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = - SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); -static struct sbmix_elem snd_dt019x_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = - SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); -static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = - SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); -static struct sbmix_elem snd_dt019x_ctl_capture_source = +static struct sbmix_elem snd_dt019x_controls[] = { + /* ALS4000 below has some parts which we might be lacking, + * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ + SB_DOUBLE("Master Playback Volume", + SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), + SB_DOUBLE("PCM Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), + SB_DOUBLE("PCM Playback Volume", + SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), + SB_DOUBLE("Synth Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), + SB_DOUBLE("Synth Playback Volume", + SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), + SB_DOUBLE("CD Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), + SB_DOUBLE("CD Playback Volume", + SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), + SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), + SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), + SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), + SB_DOUBLE("Line Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), + SB_DOUBLE("Line Playback Volume", + SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), { .name = "Capture Source", .type = SB_MIX_CAPTURE_DT019X - }; - -static struct sbmix_elem *snd_dt019x_controls[] = { - /* ALS4000 below has some parts which we might be lacking, - * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ - &snd_dt019x_ctl_master_play_vol, - &snd_dt019x_ctl_pcm_play_vol, - &snd_dt019x_ctl_synth_play_vol, - &snd_dt019x_ctl_cd_play_vol, - &snd_dt019x_ctl_mic_play_vol, - &snd_dt019x_ctl_pc_speaker_vol, - &snd_dt019x_ctl_line_play_vol, - &snd_sb16_ctl_mic_play_switch, - &snd_sb16_ctl_cd_play_switch, - &snd_sb16_ctl_line_play_switch, - &snd_dt019x_ctl_pcm_play_switch, - &snd_dt019x_ctl_synth_play_switch, - &snd_dt019x_ctl_capture_source + } }; static unsigned char snd_dt019x_init_values[][2] = { @@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = { /* * ALS4000 specific mixer elements */ -static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = - SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); -static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = { +static struct sbmix_elem snd_als4000_controls[] = { + SB_DOUBLE("PCM Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), + SB_DOUBLE("Synth Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), + SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), + SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), + { .name = "Master Mono Capture Route", .type = SB_MIX_MONO_CAPTURE_ALS4K - }; -static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = - SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); -static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = - SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); -static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback = - SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); -static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback = + }, + SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), + SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), + SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), SB_SINGLE("Digital Loopback Switch", - SB_ALS4000_CR3_CONFIGURATION, 7, 0x01); -/* FIXME: functionality of 3D controls might be swapped, I didn't find - * a description of how to identify what is supposed to be what */ -static struct sbmix_elem snd_als4000_3d_control_switch = - SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); -static struct sbmix_elem snd_als4000_3d_control_ratio = - SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); -static struct sbmix_elem snd_als4000_3d_control_freq = + SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), + /* FIXME: functionality of 3D controls might be swapped, I didn't find + * a description of how to identify what is supposed to be what */ + SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ - SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); -static struct sbmix_elem snd_als4000_3d_control_delay = + SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, * but what ALSA 3D attribute is that actually? "Center", "Depth", * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ - SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); -static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = - SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); -static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch = + SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), + SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", - SB_ALS4000_FMDAC, 5, 0x01); + SB_ALS4000_FMDAC, 5, 0x01), #ifdef NOT_AVAILABLE -static struct sbmix_elem snd_als4000_ctl_fmdac = - SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); -static struct sbmix_elem snd_als4000_ctl_qsound = - SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); -#endif - -static struct sbmix_elem *snd_als4000_controls[] = { - /* ALS4000a.PDF regs page */ - &snd_sb16_ctl_master_play_vol, /* MX30/31 12 */ - &snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */ - &snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */ - &snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */ - &snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */ - &snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */ - &snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */ - &snd_sb16_ctl_cd_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */ - &snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */ - &snd_sb16_ctl_line_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_line_play_vol, /* MX38/39 13 */ - &snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */ - &snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */ - &snd_sb16_ctl_mic_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_mic_play_vol, /* MX3A 13 */ - &snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */ - &snd_sb16_ctl_capture_vol, /* MX3F/40 15 */ - &snd_sb16_ctl_play_vol, /* MX41/42 15 */ - &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */ - &snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */ - &snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */ - &snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */ - &snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */ - &snd_als4000_3d_control_switch, /* MX50 17 */ - &snd_als4000_3d_control_ratio, /* MX50 17 */ - &snd_als4000_3d_control_freq, /* MX50 17 */ - &snd_als4000_3d_control_delay, /* MX51 18 */ - &snd_als4000_3d_control_poweroff_switch, /* MX51 18 */ - &snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */ -#ifdef NOT_AVAILABLE - &snd_als4000_ctl_fmdac, - &snd_als4000_ctl_qsound, + SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), + SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), #endif }; @@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = { { SB_ALS4000_MIC_IN_GAIN, 0 }, }; - /* */ static int snd_sbmixer_init(struct snd_sb *chip, - struct sbmix_elem **controls, + struct sbmix_elem *controls, int controls_count, unsigned char map[][2], int map_count, @@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip, } for (idx = 0; idx < controls_count; idx++) { - if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) + err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); + if (err < 0) return err; } snd_component_add(card, name); @@ -908,6 +799,15 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; case SB_HW_ALS4000: + /* use only the first 16 controls from SB16 */ + err = snd_sbmixer_init(chip, + snd_sb16_controls, + 16, + snd_sb16_init_values, + ARRAY_SIZE(snd_sb16_init_values), + "ALS4000"); + if (err < 0) + return err; if ((err = snd_sbmixer_init(chip, snd_als4000_controls, ARRAY_SIZE(snd_als4000_controls), -- GitLab From 2ef7f3dbd7a70a48c3f09b498df528cb00ea03a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 5 Nov 2009 13:29:36 +0000 Subject: [PATCH 0035/3892] ARM: Fix ptrace accesses Signed-off-by: Russell King --- arch/arm/include/asm/cacheflush.h | 24 ++------------- arch/arm/include/asm/smp_plat.h | 5 +++ arch/arm/mm/flush.c | 51 ++++++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 730aefcfbee3..3d2ef54c7cb9 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -316,12 +316,8 @@ static inline void outer_flush_range(unsigned long start, unsigned long end) * processes address space. Really, we want to allow our "user * space" model to handle this. */ -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ - do { \ - memcpy(dst, src, len); \ - flush_ptrace_access(vma, page, vaddr, dst, len, 1);\ - } while (0) - +extern void copy_to_user_page(struct vm_area_struct *, struct page *, + unsigned long, void *, const void *, unsigned long); #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ do { \ memcpy(dst, src, len); \ @@ -355,17 +351,6 @@ vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig } } -static inline void -vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page, - unsigned long uaddr, void *kaddr, - unsigned long len, int write) -{ - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { - unsigned long addr = (unsigned long)kaddr; - __cpuc_coherent_kern_range(addr, addr + len); - } -} - #ifndef CONFIG_CPU_CACHE_VIPT #define flush_cache_mm(mm) \ vivt_flush_cache_mm(mm) @@ -373,15 +358,10 @@ vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page, vivt_flush_cache_range(vma,start,end) #define flush_cache_page(vma,addr,pfn) \ vivt_flush_cache_page(vma,addr,pfn) -#define flush_ptrace_access(vma,page,ua,ka,len,write) \ - vivt_flush_ptrace_access(vma,page,ua,ka,len,write) #else extern void flush_cache_mm(struct mm_struct *mm); extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn); -extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, - unsigned long uaddr, void *kaddr, - unsigned long len, int write); #endif #define flush_cache_dup_mm(mm) flush_cache_mm(mm) diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h index 59303e200845..e6215305544a 100644 --- a/arch/arm/include/asm/smp_plat.h +++ b/arch/arm/include/asm/smp_plat.h @@ -13,4 +13,9 @@ static inline int tlb_ops_need_broadcast(void) return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; } +static inline int cache_ops_need_broadcast(void) +{ + return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1; +} + #endif diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 6f3a4b7a3b82..e34f095e2090 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -87,13 +88,26 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged()) __flush_icache_all(); } +#else +#define flush_pfn_alias(pfn,vaddr) do { } while (0) +#endif +#ifdef CONFIG_SMP +static void flush_ptrace_access_other(void *args) +{ + __flush_icache_all(); +} +#endif + +static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, - unsigned long uaddr, void *kaddr, - unsigned long len, int write) + unsigned long uaddr, void *kaddr, unsigned long len) { if (cache_is_vivt()) { - vivt_flush_ptrace_access(vma, page, uaddr, kaddr, len, write); + if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { + unsigned long addr = (unsigned long)kaddr; + __cpuc_coherent_kern_range(addr, addr + len); + } return; } @@ -104,16 +118,37 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, } /* VIPT non-aliasing cache */ - if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)) && - vma->vm_flags & VM_EXEC) { + if (vma->vm_flags & VM_EXEC) { unsigned long addr = (unsigned long)kaddr; - /* only flushing the kernel mapping on non-aliasing VIPT */ __cpuc_coherent_kern_range(addr, addr + len); +#ifdef CONFIG_SMP + if (cache_ops_need_broadcast()) + smp_call_function(flush_ptrace_access_other, + NULL, 1); +#endif } } -#else -#define flush_pfn_alias(pfn,vaddr) do { } while (0) + +/* + * Copy user data from/to a page which is mapped into a different + * processes address space. Really, we want to allow our "user + * space" model to handle this. + * + * Note that this code needs to run on the current CPU. + */ +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long uaddr, void *dst, const void *src, + unsigned long len) +{ +#ifdef CONFIG_SMP + preempt_disable(); #endif + memcpy(dst, src, len); + flush_ptrace_access(vma, page, uaddr, dst, len); +#ifdef CONFIG_SMP + preempt_enable(); +#endif +} void __flush_dcache_page(struct address_space *mapping, struct page *page) { -- GitLab From 63978ab3e3e963db28093b53bb4598f2702e1ad7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 14 Dec 2009 12:48:35 +0100 Subject: [PATCH 0036/3892] sound: add Edirol UA-101 support Add experimental support for the Edirol UA-101 audio/MIDI interface. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 7 + sound/usb/Kconfig | 12 + sound/usb/Makefile | 2 + sound/usb/ua101.c | 1457 +++++++++++++++++ sound/usb/usbaudio.c | 54 - sound/usb/usbaudio.h | 1 - sound/usb/usbquirks.h | 31 - 7 files changed, 1478 insertions(+), 86 deletions(-) create mode 100644 sound/usb/ua101.c diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 8923597bd2bd..7a0a4a9dc18d 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1791,6 +1791,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-ua101 + ---------------- + + Module for the Edirol UA-101 audio/MIDI interface. + + This module supports multiple devices, autoprobe and hotplugging. + Module snd-usb-audio -------------------- diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 73525c048e7f..8c2925814ce4 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -21,6 +21,18 @@ config SND_USB_AUDIO To compile this driver as a module, choose M here: the module will be called snd-usb-audio. +config SND_USB_UA101 + tristate "Edirol UA-101 driver (EXPERIMENTAL)" + depends on EXPERIMENTAL + select SND_PCM + select SND_RAWMIDI + help + Say Y here to include support for the Edirol UA-101 audio/MIDI + interface. + + To compile this driver as a module, choose M here: the module + will be called snd-ua101. + config SND_USB_USX2Y tristate "Tascam US-122, US-224 and US-428 USB driver" depends on X86 || PPC || ALPHA diff --git a/sound/usb/Makefile b/sound/usb/Makefile index abb288bfe35d..5bf64aef9558 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -4,9 +4,11 @@ snd-usb-audio-objs := usbaudio.o usbmixer.o snd-usb-lib-objs := usbmidi.o +snd-ua101-objs := ua101.o # Toplevel Module Dependency obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o +obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c new file mode 100644 index 000000000000..ab9f8a2e1938 --- /dev/null +++ b/sound/usb/ua101.c @@ -0,0 +1,1457 @@ +/* + * Edirol UA-101 driver + * Copyright (c) Clemens Ladisch + * + * This driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver 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 driver. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbaudio.h" + +MODULE_DESCRIPTION("Edirol UA-101 driver"); +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}"); + +/* I use my UA-1A for testing because I don't have a UA-101 ... */ +#define UA1A_HACK + +/* + * Should not be lower than the minimum scheduling delay of the host + * controller. Some Intel controllers need more than one frame; as long as + * that driver doesn't tell us about this, use 1.5 frames just to be sure. + */ +#define MIN_QUEUE_LENGTH 12 +/* Somewhat random. */ +#define MAX_QUEUE_LENGTH 30 +/* + * This magic value optimizes memory usage efficiency for the UA-101's packet + * sizes at all sample rates, taking into account the stupid cache pool sizes + * that usb_buffer_alloc() uses. + */ +#define DEFAULT_QUEUE_LENGTH 21 + +#define MAX_PACKET_SIZE 672 /* hardware specific */ +#define MAX_MEMORY_BUFFERS DIV_ROUND_UP(MAX_QUEUE_LENGTH, \ + PAGE_SIZE / MAX_PACKET_SIZE) + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static unsigned int queue_length = 21; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "card index"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "enable card"); +module_param(queue_length, uint, 0644); +MODULE_PARM_DESC(queue_length, "USB queue length in microframes, " + __stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH)); + +enum { + INTF_PLAYBACK, + INTF_CAPTURE, + INTF_MIDI, + + INTF_COUNT +}; + +/* bits in struct ua101::states */ +enum { + USB_CAPTURE_RUNNING, + USB_PLAYBACK_RUNNING, + ALSA_CAPTURE_OPEN, + ALSA_PLAYBACK_OPEN, + ALSA_CAPTURE_RUNNING, + ALSA_PLAYBACK_RUNNING, + CAPTURE_URB_COMPLETED, + PLAYBACK_URB_COMPLETED, + DISCONNECTED, +}; + +struct ua101 { + struct usb_device *dev; + struct snd_card *card; + struct usb_interface *intf[INTF_COUNT]; + int card_index; + struct snd_pcm *pcm; + struct list_head midi_list; + u64 format_bit; + unsigned int rate; + unsigned int packets_per_second; + spinlock_t lock; + struct mutex mutex; + unsigned long states; + + /* FIFO to synchronize playback rate to capture rate */ + unsigned int rate_feedback_start; + unsigned int rate_feedback_count; + u8 rate_feedback[MAX_QUEUE_LENGTH]; + + struct list_head ready_playback_urbs; + struct tasklet_struct playback_tasklet; + wait_queue_head_t alsa_capture_wait; + wait_queue_head_t rate_feedback_wait; + wait_queue_head_t alsa_playback_wait; + struct ua101_stream { + struct snd_pcm_substream *substream; + unsigned int usb_pipe; + unsigned int channels; + unsigned int frame_bytes; + unsigned int max_packet_bytes; + unsigned int period_pos; + unsigned int buffer_pos; + unsigned int queue_length; + struct ua101_urb { + struct urb urb; + struct usb_iso_packet_descriptor iso_frame_desc[1]; + struct list_head ready_list; + } *urbs[MAX_QUEUE_LENGTH]; + struct { + unsigned int size; + void *addr; + dma_addr_t dma; + } buffers[MAX_MEMORY_BUFFERS]; + } capture, playback; + + unsigned int fps[10]; + unsigned int frame_counter; +}; + +static DEFINE_MUTEX(devices_mutex); +static unsigned int devices_used; +static struct usb_driver ua101_driver; + +static void abort_alsa_playback(struct ua101 *ua); +static void abort_alsa_capture(struct ua101 *ua); + +/* allocate virtual buffer; may be called more than once */ +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc_user(size); + if (!runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 0; +} + +/* free virtual buffer; may be called more than once */ +static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + vfree(runtime->dma_area); + runtime->dma_area = NULL; + return 0; +} + +/* get the physical page pointer at the given offset */ +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +static const char *usb_error_string(int err) +{ + switch (err) { + case -ENODEV: + return "no device"; + case -ENOENT: + return "endpoint not enabled"; + case -EPIPE: + return "endpoint stalled"; + case -ENOSPC: + return "not enough bandwidth"; + case -ESHUTDOWN: + return "device disabled"; + case -EHOSTUNREACH: + return "device suspended"; + case -EINVAL: + case -EAGAIN: + case -EFBIG: + case -EMSGSIZE: + return "internal error"; + default: + return "unknown error"; + } +} + +static void abort_usb_capture(struct ua101 *ua) +{ + if (test_and_clear_bit(USB_CAPTURE_RUNNING, &ua->states)) { + wake_up(&ua->alsa_capture_wait); + wake_up(&ua->rate_feedback_wait); + } +} + +static void abort_usb_playback(struct ua101 *ua) +{ + if (test_and_clear_bit(USB_PLAYBACK_RUNNING, &ua->states)) + wake_up(&ua->alsa_playback_wait); +} + +static void playback_urb_complete(struct urb *usb_urb) +{ + struct ua101_urb *urb = (struct ua101_urb *)usb_urb; + struct ua101 *ua = urb->urb.context; + unsigned long flags; + + if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ + urb->urb.status == -ENODEV || /* device removed */ + urb->urb.status == -ECONNRESET || /* unlinked */ + urb->urb.status == -ESHUTDOWN)) { /* device disabled */ + abort_usb_playback(ua); + abort_alsa_playback(ua); + return; + } + + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { + /* append URB to FIFO */ + spin_lock_irqsave(&ua->lock, flags); + list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); + if (ua->rate_feedback_count > 0) + tasklet_schedule(&ua->playback_tasklet); + ua->playback.substream->runtime->delay -= + urb->urb.iso_frame_desc[0].length / + ua->playback.frame_bytes; + spin_unlock_irqrestore(&ua->lock, flags); + } +} + +static void first_playback_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + + urb->complete = playback_urb_complete; + playback_urb_complete(urb); + + set_bit(PLAYBACK_URB_COMPLETED, &ua->states); + wake_up(&ua->alsa_playback_wait); +} + +/* copy data from the ALSA ring buffer into the URB buffer */ +static bool copy_playback_data(struct ua101_stream *stream, struct urb *urb, + unsigned int frames) +{ + struct snd_pcm_runtime *runtime; + unsigned int frame_bytes, frames1; + const u8 *source; + + runtime = stream->substream->runtime; + frame_bytes = stream->frame_bytes; + source = runtime->dma_area + stream->buffer_pos * frame_bytes; + if (stream->buffer_pos + frames <= runtime->buffer_size) { + memcpy(urb->transfer_buffer, source, frames * frame_bytes); + } else { + /* wrap around at end of ring buffer */ + frames1 = runtime->buffer_size - stream->buffer_pos; + memcpy(urb->transfer_buffer, source, frames1 * frame_bytes); + memcpy(urb->transfer_buffer + frames1 * frame_bytes, + runtime->dma_area, (frames - frames1) * frame_bytes); + } + + stream->buffer_pos += frames; + if (stream->buffer_pos >= runtime->buffer_size) + stream->buffer_pos -= runtime->buffer_size; + stream->period_pos += frames; + if (stream->period_pos >= runtime->period_size) { + stream->period_pos -= runtime->period_size; + return true; + } + return false; +} + +static inline void add_with_wraparound(struct ua101 *ua, + unsigned int *value, unsigned int add) +{ + *value += add; + if (*value >= ua->playback.queue_length) + *value -= ua->playback.queue_length; +} + +static void playback_tasklet(unsigned long data) +{ + struct ua101 *ua = (void *)data; + unsigned long flags; + unsigned int frames; + struct ua101_urb *urb; + bool do_period_elapsed = false; + int err; + + if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states))) + return; + + /* + * Synchronizing the playback rate to the capture rate is done by using + * the same sequence of packet sizes for both streams. + * Submitting a playback URB therefore requires both a ready URB and + * the size of the corresponding capture packet, i.e., both playback + * and capture URBs must have been completed. Since the USB core does + * not guarantee that playback and capture complete callbacks are + * called alternately, we use two FIFOs for packet sizes and read URBs; + * submitting playback URBs is possible as long as both FIFOs are + * nonempty. + */ + spin_lock_irqsave(&ua->lock, flags); + while (ua->rate_feedback_count > 0 && + !list_empty(&ua->ready_playback_urbs)) { + /* take packet size out of FIFO */ + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + + /* take URB out of FIFO */ + urb = list_first_entry(&ua->ready_playback_urbs, + struct ua101_urb, ready_list); + list_del(&urb->ready_list); + + /* fill packet with data or silence */ + urb->urb.iso_frame_desc[0].length = + frames * ua->playback.frame_bytes; + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + do_period_elapsed |= copy_playback_data(&ua->playback, + &urb->urb, + frames); + else + memset(urb->urb.transfer_buffer, 0, + urb->urb.iso_frame_desc[0].length); + + /* and off you go ... */ + err = usb_submit_urb(&urb->urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + spin_unlock_irqrestore(&ua->lock, flags); + abort_usb_playback(ua); + abort_alsa_playback(ua); + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + return; + } + ua->playback.substream->runtime->delay += frames; + } + spin_unlock_irqrestore(&ua->lock, flags); + if (do_period_elapsed) + snd_pcm_period_elapsed(ua->playback.substream); +} + +/* copy data from the URB buffer into the ALSA ring buffer */ +static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb, + unsigned int frames) +{ + struct snd_pcm_runtime *runtime; + unsigned int frame_bytes, frames1; + u8 *dest; + + runtime = stream->substream->runtime; + frame_bytes = stream->frame_bytes; + dest = runtime->dma_area + stream->buffer_pos * frame_bytes; + if (stream->buffer_pos + frames <= runtime->buffer_size) { + memcpy(dest, urb->transfer_buffer, frames * frame_bytes); + } else { + /* wrap around at end of ring buffer */ + frames1 = runtime->buffer_size - stream->buffer_pos; + memcpy(dest, urb->transfer_buffer, frames1 * frame_bytes); + memcpy(runtime->dma_area, + urb->transfer_buffer + frames1 * frame_bytes, + (frames - frames1) * frame_bytes); + } + + stream->buffer_pos += frames; + if (stream->buffer_pos >= runtime->buffer_size) + stream->buffer_pos -= runtime->buffer_size; + stream->period_pos += frames; + if (stream->period_pos >= runtime->period_size) { + stream->period_pos -= runtime->period_size; + return true; + } + return false; +} + +static void capture_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + struct ua101_stream *stream = &ua->capture; + unsigned long flags; + unsigned int frames, write_ptr; + bool do_period_elapsed; + int err; + + if (unlikely(urb->status == -ENOENT || /* unlinked */ + urb->status == -ENODEV || /* device removed */ + urb->status == -ECONNRESET || /* unlinked */ + urb->status == -ESHUTDOWN)) /* device disabled */ + goto stream_stopped; + + if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0) + frames = urb->iso_frame_desc[0].actual_length / + stream->frame_bytes; + else + frames = 0; + + spin_lock_irqsave(&ua->lock, flags); + + if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + do_period_elapsed = copy_capture_data(stream, urb, frames); + else + do_period_elapsed = false; + + if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + spin_unlock_irqrestore(&ua->lock, flags); + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + goto stream_stopped; + } + + /* append packet size to FIFO */ + write_ptr = ua->rate_feedback_start; + add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); + ua->rate_feedback[write_ptr] = frames; + if (ua->rate_feedback_count < ua->playback.queue_length) { + ua->rate_feedback_count++; + if (ua->rate_feedback_count == + ua->playback.queue_length) + wake_up(&ua->rate_feedback_wait); + } else { + /* + * Ring buffer overflow; this happens when the playback + * stream is not running. Throw away the oldest entry, + * so that the playback stream, when it starts, sees + * the most recent packet sizes. + */ + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + } + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && + !list_empty(&ua->ready_playback_urbs)) + tasklet_schedule(&ua->playback_tasklet); + } + + spin_unlock_irqrestore(&ua->lock, flags); + + if (do_period_elapsed) + snd_pcm_period_elapsed(stream->substream); + + /* for debugging: measure the sample rate relative to the USB clock */ + ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames; + if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) { + printk(KERN_DEBUG "capture rate:"); + for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames) + printk(KERN_CONT " %u", ua->fps[frames]); + printk(KERN_CONT "\n"); + memset(ua->fps, 0, sizeof(ua->fps)); + ua->frame_counter = 0; + } + return; + +stream_stopped: + abort_usb_playback(ua); + abort_usb_capture(ua); + abort_alsa_playback(ua); + abort_alsa_capture(ua); +} + +static void first_capture_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + + urb->complete = capture_urb_complete; + capture_urb_complete(urb); + + set_bit(CAPTURE_URB_COMPLETED, &ua->states); + wake_up(&ua->alsa_capture_wait); +} + +static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) { + int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); + if (err < 0) { + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + return err; + } + } + return 0; +} + +static void kill_stream_urbs(struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) + usb_kill_urb(&stream->urbs[i]->urb); +} + +static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) +{ + struct usb_host_interface *alts; + + alts = ua->intf[intf_index]->cur_altsetting; + if (alts->desc.bAlternateSetting != 1) { + int err = usb_set_interface(ua->dev, + alts->desc.bInterfaceNumber, 1); + if (err < 0) { + dev_err(&ua->dev->dev, + "cannot initialize interface; error %d: %s\n", + err, usb_error_string(err)); + return err; + } + } + return 0; +} + +static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) +{ + struct usb_host_interface *alts; + + alts = ua->intf[intf_index]->cur_altsetting; + if (alts->desc.bAlternateSetting != 0) { + int err = usb_set_interface(ua->dev, + alts->desc.bInterfaceNumber, 0); + if (err < 0 && !test_bit(DISCONNECTED, &ua->states)) + dev_warn(&ua->dev->dev, + "interface reset failed; error %d: %s\n", + err, usb_error_string(err)); + } +} + +static void stop_usb_capture(struct ua101 *ua) +{ + clear_bit(USB_CAPTURE_RUNNING, &ua->states); + + kill_stream_urbs(&ua->capture); + + disable_iso_interface(ua, INTF_CAPTURE); +} + +static int start_usb_capture(struct ua101 *ua) +{ + int err; + + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + + if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return 0; + + kill_stream_urbs(&ua->capture); + + err = enable_iso_interface(ua, INTF_CAPTURE); + if (err < 0) + return err; + + clear_bit(CAPTURE_URB_COMPLETED, &ua->states); + ua->capture.urbs[0]->urb.complete = first_capture_urb_complete; + ua->rate_feedback_start = 0; + ua->rate_feedback_count = 0; + + set_bit(USB_CAPTURE_RUNNING, &ua->states); + err = submit_stream_urbs(ua, &ua->capture); + if (err < 0) + stop_usb_capture(ua); + return err; +} + +static void stop_usb_playback(struct ua101 *ua) +{ + clear_bit(USB_PLAYBACK_RUNNING, &ua->states); + + kill_stream_urbs(&ua->playback); + + tasklet_kill(&ua->playback_tasklet); + + disable_iso_interface(ua, INTF_PLAYBACK); +} + +static int start_usb_playback(struct ua101 *ua) +{ + unsigned int i, frames; + struct urb *urb; + int err = 0; + + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return 0; + + kill_stream_urbs(&ua->playback); + tasklet_kill(&ua->playback_tasklet); + + err = enable_iso_interface(ua, INTF_PLAYBACK); + if (err < 0) + return err; + + clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); + ua->playback.urbs[0]->urb.complete = + first_playback_urb_complete; + spin_lock_irq(&ua->lock); + INIT_LIST_HEAD(&ua->ready_playback_urbs); + spin_unlock_irq(&ua->lock); + + /* + * We submit the initial URBs all at once, so we have to wait for the + * packet size FIFO to be full. + */ + wait_event(ua->rate_feedback_wait, + ua->rate_feedback_count >= ua->playback.queue_length || + !test_bit(USB_CAPTURE_RUNNING, &ua->states) || + test_bit(DISCONNECTED, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) { + stop_usb_playback(ua); + return -ENODEV; + } + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) { + stop_usb_playback(ua); + return -EIO; + } + + for (i = 0; i < ua->playback.queue_length; ++i) { + /* all initial URBs contain silence */ + spin_lock_irq(&ua->lock); + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + spin_unlock_irq(&ua->lock); + urb = &ua->playback.urbs[i]->urb; + urb->iso_frame_desc[0].length = + frames * ua->playback.frame_bytes; + memset(urb->transfer_buffer, 0, + urb->iso_frame_desc[0].length); + } + + set_bit(USB_PLAYBACK_RUNNING, &ua->states); + err = submit_stream_urbs(ua, &ua->playback); + if (err < 0) + stop_usb_playback(ua); + return err; +} + +static void abort_alsa_capture(struct ua101 *ua) +{ + if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); +} + +static void abort_alsa_playback(struct ua101 *ua) +{ + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); +} + +static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, + unsigned int channels) +{ + int err; + + substream->runtime->hw.info = + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_FIFO_IN_FRAMES; + substream->runtime->hw.formats = ua->format_bit; + substream->runtime->hw.rates = snd_pcm_rate_to_rate_bit(ua->rate); + substream->runtime->hw.rate_min = ua->rate; + substream->runtime->hw.rate_max = ua->rate; + substream->runtime->hw.channels_min = channels; + substream->runtime->hw.channels_max = channels; + substream->runtime->hw.buffer_bytes_max = 45000 * 1024; + substream->runtime->hw.period_bytes_min = 1; + substream->runtime->hw.period_bytes_max = UINT_MAX; + substream->runtime->hw.periods_min = 2; + substream->runtime->hw.periods_max = UINT_MAX; + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_TIME, + 1500000 / ua->packets_per_second, + 8192000); + if (err < 0) + return err; + err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); + return err; +} + +static int capture_pcm_open(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + ua->capture.substream = substream; + err = set_stream_hw(ua, substream, ua->capture.channels); + if (err < 0) + return err; + substream->runtime->hw.fifo_size = + DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second); + substream->runtime->delay = substream->runtime->hw.fifo_size; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + set_bit(ALSA_CAPTURE_OPEN, &ua->states); + mutex_unlock(&ua->mutex); + return err; +} + +static int playback_pcm_open(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + ua->playback.substream = substream; + err = set_stream_hw(ua, substream, ua->playback.channels); + if (err < 0) + return err; + substream->runtime->hw.fifo_size = + DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length, + ua->packets_per_second); + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err < 0) + goto error; + err = start_usb_playback(ua); + if (err < 0) { + if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) + stop_usb_capture(ua); + goto error; + } + set_bit(ALSA_PLAYBACK_OPEN, &ua->states); +error: + mutex_unlock(&ua->mutex); + return err; +} + +static int capture_pcm_close(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + + mutex_lock(&ua->mutex); + clear_bit(ALSA_CAPTURE_OPEN, &ua->states); + if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states)) + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + return 0; +} + +static int playback_pcm_close(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + + mutex_lock(&ua->mutex); + stop_usb_playback(ua); + clear_bit(ALSA_PLAYBACK_OPEN, &ua->states); + if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + return 0; +} + +static int capture_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int playback_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + err = start_usb_playback(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_free_vmalloc_buffer(substream); + return 0; +} + +static int capture_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + /* + * The EHCI driver schedules the first packet of an iso stream at 10 ms + * in the future, i.e., no data is actually captured for that long. + * Take the wait here so that the stream is known to be actually + * running when the start trigger has been called. + */ + wait_event(ua->alsa_capture_wait, + test_bit(CAPTURE_URB_COMPLETED, &ua->states) || + !test_bit(USB_CAPTURE_RUNNING, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return -EIO; + + ua->capture.period_pos = 0; + ua->capture.buffer_pos = 0; + return 0; +} + +static int playback_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + err = start_usb_playback(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + /* see the comment in capture_pcm_prepare() */ + wait_event(ua->alsa_playback_wait, + test_bit(PLAYBACK_URB_COMPLETED, &ua->states) || + !test_bit(USB_PLAYBACK_RUNNING, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return -EIO; + + substream->runtime->delay = 0; + ua->playback.period_pos = 0; + ua->playback.buffer_pos = 0; + return 0; +} + +static int capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ua101 *ua = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return -EIO; + set_bit(ALSA_CAPTURE_RUNNING, &ua->states); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + clear_bit(ALSA_CAPTURE_RUNNING, &ua->states); + return 0; + default: + return -EINVAL; + } +} + +static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ua101 *ua = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return -EIO; + set_bit(ALSA_PLAYBACK_RUNNING, &ua->states); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + clear_bit(ALSA_PLAYBACK_RUNNING, &ua->states); + return 0; + default: + return -EINVAL; + } +} + +static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua, + struct ua101_stream *stream) +{ + unsigned long flags; + unsigned int pos; + + spin_lock_irqsave(&ua->lock, flags); + pos = stream->buffer_pos; + spin_unlock_irqrestore(&ua->lock, flags); + return pos; +} + +static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs) +{ + struct ua101 *ua = subs->private_data; + + return ua101_pcm_pointer(ua, &ua->capture); +} + +static snd_pcm_uframes_t playback_pcm_pointer(struct snd_pcm_substream *subs) +{ + struct ua101 *ua = subs->private_data; + + return ua101_pcm_pointer(ua, &ua->playback); +} + +static struct snd_pcm_ops capture_pcm_ops = { + .open = capture_pcm_open, + .close = capture_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = capture_pcm_hw_params, + .hw_free = ua101_pcm_hw_free, + .prepare = capture_pcm_prepare, + .trigger = capture_pcm_trigger, + .pointer = capture_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static struct snd_pcm_ops playback_pcm_ops = { + .open = playback_pcm_open, + .close = playback_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = playback_pcm_hw_params, + .hw_free = ua101_pcm_hw_free, + .prepare = playback_pcm_prepare, + .trigger = playback_pcm_trigger, + .pointer = playback_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static const struct uac_format_type_i_discrete_descriptor * +find_format_descriptor(struct usb_interface *interface) +{ + struct usb_host_interface *alt; + u8 *extra; + int extralen; + + if (interface->num_altsetting != 2) { + dev_err(&interface->dev, "invalid num_altsetting\n"); + return NULL; + } + + alt = &interface->altsetting[0]; + if (alt->desc.bNumEndpoints != 0) { + dev_err(&interface->dev, "invalid bNumEndpoints\n"); + return NULL; + } + + alt = &interface->altsetting[1]; + if (alt->desc.bNumEndpoints != 1) { + dev_err(&interface->dev, "invalid bNumEndpoints\n"); + return NULL; + } + + extra = alt->extra; + extralen = alt->extralen; + while (extralen >= sizeof(struct usb_descriptor_header)) { + struct uac_format_type_i_discrete_descriptor *desc; + + desc = (struct uac_format_type_i_discrete_descriptor *)extra; + if (desc->bLength > extralen) { + dev_err(&interface->dev, "descriptor overflow\n"); + return NULL; + } + if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) && + desc->bDescriptorType == USB_DT_CS_INTERFACE && + desc->bDescriptorSubtype == UAC_FORMAT_TYPE) { + if (desc->bFormatType != UAC_FORMAT_TYPE_I_PCM || + desc->bSamFreqType != 1) { + dev_err(&interface->dev, + "invalid format type\n"); + return NULL; + } + return desc; + } + extralen -= desc->bLength; + extra += desc->bLength; + } + dev_err(&interface->dev, "sample format descriptor not found\n"); + return NULL; +} + +static int detect_usb_format(struct ua101 *ua) +{ + const struct uac_format_type_i_discrete_descriptor *fmt_capture; + const struct uac_format_type_i_discrete_descriptor *fmt_playback; + const struct usb_endpoint_descriptor *epd; + unsigned int rate2; + + fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]); + fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]); + if (!fmt_capture || !fmt_playback) + return -ENXIO; + + switch (fmt_capture->bSubframeSize) { + case 3: + ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE; + break; + case 4: + ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n"); + return -ENXIO; + } + if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) { + dev_err(&ua->dev->dev, + "playback/capture sample widths do not match\n"); + return -ENXIO; + } + + if (fmt_capture->bBitResolution != 24 || + fmt_playback->bBitResolution != 24) { + dev_err(&ua->dev->dev, "sample width is not 24 bits\n"); + return -ENXIO; + } + + ua->rate = combine_triple(fmt_capture->tSamFreq[0]); + rate2 = combine_triple(fmt_playback->tSamFreq[0]); + if (ua->rate != rate2) { + dev_err(&ua->dev->dev, + "playback/capture rates do not match: %u/%u\n", + rate2, ua->rate); + return -ENXIO; + } + + switch (ua->dev->speed) { + case USB_SPEED_FULL: + ua->packets_per_second = 1000; + break; + case USB_SPEED_HIGH: + ua->packets_per_second = 8000; + break; + default: + dev_err(&ua->dev->dev, "unknown device speed\n"); + return -ENXIO; + } + + ua->capture.channels = fmt_capture->bNrChannels; + ua->playback.channels = fmt_playback->bNrChannels; + ua->capture.frame_bytes = + fmt_capture->bSubframeSize * ua->capture.channels; + ua->playback.frame_bytes = + fmt_playback->bSubframeSize * ua->playback.channels; + + epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc; + if (!usb_endpoint_is_isoc_in(epd)) { + dev_err(&ua->dev->dev, "invalid capture endpoint\n"); + return -ENXIO; + } + ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); + ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + + epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; + if (!usb_endpoint_is_isoc_out(epd)) { + dev_err(&ua->dev->dev, "invalid playback endpoint\n"); + return -ENXIO; + } + ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); + ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + return 0; +} + +static int alloc_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int remaining_packets, packets, packets_per_page, i; + size_t size; + + stream->queue_length = queue_length; + stream->queue_length = max(stream->queue_length, + (unsigned int)MIN_QUEUE_LENGTH); + stream->queue_length = min(stream->queue_length, + (unsigned int)MAX_QUEUE_LENGTH); + + /* + * The cache pool sizes used by usb_buffer_alloc() (128, 512, 2048) are + * quite bad when used with the packet sizes of this device (e.g. 280, + * 520, 624). Therefore, we allocate and subdivide entire pages, using + * a smaller buffer only for the last chunk. + */ + remaining_packets = stream->queue_length; + packets_per_page = PAGE_SIZE / stream->max_packet_bytes; + for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) { + packets = min(remaining_packets, packets_per_page); + size = packets * stream->max_packet_bytes; + stream->buffers[i].addr = + usb_buffer_alloc(ua->dev, size, GFP_KERNEL, + &stream->buffers[i].dma); + if (!stream->buffers[i].addr) + return -ENOMEM; + stream->buffers[i].size = size; + remaining_packets -= packets; + if (!remaining_packets) + break; + } + if (remaining_packets) { + dev_err(&ua->dev->dev, "too many packets\n"); + return -ENXIO; + } + return 0; +} + +static void free_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) + usb_buffer_free(ua->dev, + stream->buffers[i].size, + stream->buffers[i].addr, + stream->buffers[i].dma); +} + +static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, + void (*urb_complete)(struct urb *)) +{ + unsigned max_packet_size = stream->max_packet_bytes; + struct ua101_urb *urb; + unsigned int b, u = 0; + + for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) { + unsigned int size = stream->buffers[b].size; + u8 *addr = stream->buffers[b].addr; + dma_addr_t dma = stream->buffers[b].dma; + + while (size >= max_packet_size) { + if (u >= stream->queue_length) + goto bufsize_error; + urb = kmalloc(sizeof(*urb), GFP_KERNEL); + if (!urb) + return -ENOMEM; + usb_init_urb(&urb->urb); + urb->urb.dev = ua->dev; + urb->urb.pipe = stream->usb_pipe; + urb->urb.transfer_flags = URB_ISO_ASAP | + URB_NO_TRANSFER_DMA_MAP; + urb->urb.transfer_buffer = addr; + urb->urb.transfer_dma = dma; + urb->urb.transfer_buffer_length = max_packet_size; + urb->urb.number_of_packets = 1; + urb->urb.interval = 1; + urb->urb.context = ua; + urb->urb.complete = urb_complete; + urb->urb.iso_frame_desc[0].offset = 0; + urb->urb.iso_frame_desc[0].length = max_packet_size; + stream->urbs[u++] = urb; + size -= max_packet_size; + addr += max_packet_size; + dma += max_packet_size; + } + } + if (u == stream->queue_length) + return 0; +bufsize_error: + dev_err(&ua->dev->dev, "internal buffer size error\n"); + return -ENXIO; +} + +static void free_stream_urbs(struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) + kfree(stream->urbs[i]); +} + +static void free_usb_related_resources(struct ua101 *ua, + struct usb_interface *interface) +{ + unsigned int i; + + free_stream_urbs(&ua->capture); + free_stream_urbs(&ua->playback); + free_stream_buffers(ua, &ua->capture); + free_stream_buffers(ua, &ua->playback); + + for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) + if (ua->intf[i]) { + usb_set_intfdata(ua->intf[i], NULL); + if (ua->intf[i] != interface) + usb_driver_release_interface(&ua101_driver, + ua->intf[i]); + } +} + +static void ua101_card_free(struct snd_card *card) +{ + struct ua101 *ua = card->private_data; + + mutex_destroy(&ua->mutex); +} + +static int ua101_probe(struct usb_interface *interface, + const struct usb_device_id *usb_id) +{ + static const struct snd_usb_midi_endpoint_info midi_ep = { + .out_cables = 0x0001, + .in_cables = 0x0001 + }; + static const struct snd_usb_audio_quirk midi_quirk = { + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &midi_ep + }; + struct snd_card *card; + struct ua101 *ua; + unsigned int card_index, i; + char usb_path[32]; + int err; + + if (interface->altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + + mutex_lock(&devices_mutex); + + for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) + if (enable[card_index] && !(devices_used & (1 << card_index))) + break; + if (card_index >= SNDRV_CARDS) { + mutex_unlock(&devices_mutex); + return -ENOENT; + } + err = snd_card_create(index[card_index], id[card_index], THIS_MODULE, + sizeof(*ua), &card); + if (err < 0) { + mutex_unlock(&devices_mutex); + return err; + } + card->private_free = ua101_card_free; + ua = card->private_data; + ua->dev = interface_to_usbdev(interface); + ua->card = card; + ua->card_index = card_index; + INIT_LIST_HEAD(&ua->midi_list); + spin_lock_init(&ua->lock); + mutex_init(&ua->mutex); + INIT_LIST_HEAD(&ua->ready_playback_urbs); + tasklet_init(&ua->playback_tasklet, + playback_tasklet, (unsigned long)ua); + init_waitqueue_head(&ua->alsa_capture_wait); + init_waitqueue_head(&ua->rate_feedback_wait); + init_waitqueue_head(&ua->alsa_playback_wait); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { + ua->intf[2] = interface; + ua->intf[0] = usb_ifnum_to_if(ua->dev, 1); + ua->intf[1] = usb_ifnum_to_if(ua->dev, 2); + usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua); + usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua); + } else { +#endif + ua->intf[0] = interface; + for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) { + ua->intf[i] = usb_ifnum_to_if(ua->dev, i); + if (!ua->intf[i]) { + dev_err(&ua->dev->dev, "interface %u not found\n", i); + err = -ENXIO; + goto probe_error; + } + err = usb_driver_claim_interface(&ua101_driver, + ua->intf[i], ua); + if (err < 0) { + ua->intf[i] = NULL; + err = -EBUSY; + goto probe_error; + } + } +#ifdef UA1A_HACK + } +#endif + + snd_card_set_dev(card, &interface->dev); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { + ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE; + ua->rate = 44100; + ua->packets_per_second = 1000; + ua->capture.channels = 2; + ua->playback.channels = 2; + ua->capture.frame_bytes = 4; + ua->playback.frame_bytes = 4; + ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2); + ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1); + ua->capture.max_packet_bytes = 192; + ua->playback.max_packet_bytes = 192; + } else { +#endif + err = detect_usb_format(ua); + if (err < 0) + goto probe_error; +#ifdef UA1A_HACK + } +#endif + + strcpy(card->driver, "UA-101"); + strcpy(card->shortname, "UA-101"); + usb_make_path(ua->dev, usb_path, sizeof(usb_path)); + snprintf(ua->card->longname, sizeof(ua->card->longname), + "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed", + ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path, + ua->dev->speed == USB_SPEED_HIGH ? "high" : "full"); + + err = alloc_stream_buffers(ua, &ua->capture); + if (err < 0) + goto probe_error; + err = alloc_stream_buffers(ua, &ua->playback); + if (err < 0) + goto probe_error; + + err = alloc_stream_urbs(ua, &ua->capture, capture_urb_complete); + if (err < 0) + goto probe_error; + err = alloc_stream_urbs(ua, &ua->playback, playback_urb_complete); + if (err < 0) + goto probe_error; + + err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm); + if (err < 0) + goto probe_error; + ua->pcm->private_data = ua; + strcpy(ua->pcm->name, "UA-101"); + snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); + snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) { +#endif + err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], + &ua->midi_list, &midi_quirk); + if (err < 0) + goto probe_error; +#ifdef UA1A_HACK + } +#endif + + err = snd_card_register(card); + if (err < 0) + goto probe_error; + + usb_set_intfdata(interface, ua); + devices_used |= 1 << card_index; + + mutex_unlock(&devices_mutex); + return 0; + +probe_error: + free_usb_related_resources(ua, interface); + snd_card_free(card); + mutex_unlock(&devices_mutex); + return err; +} + +static void ua101_disconnect(struct usb_interface *interface) +{ + struct ua101 *ua = usb_get_intfdata(interface); + struct list_head *midi; + + if (!ua) + return; + + mutex_lock(&devices_mutex); + + set_bit(DISCONNECTED, &ua->states); + wake_up(&ua->rate_feedback_wait); + + /* make sure that userspace cannot create new requests */ + snd_card_disconnect(ua->card); + + /* make sure that there are no pending USB requests */ + __list_for_each(midi, &ua->midi_list) + snd_usbmidi_disconnect(midi); + abort_alsa_playback(ua); + abort_alsa_capture(ua); + mutex_lock(&ua->mutex); + stop_usb_playback(ua); + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + + free_usb_related_resources(ua, interface); + + devices_used &= ~(1 << ua->card_index); + + snd_card_free_when_closed(ua->card); + + mutex_unlock(&devices_mutex); +} + +static struct usb_device_id ua101_ids[] = { +#ifdef UA1A_HACK + { USB_DEVICE(0x0582, 0x0018) }, +#endif + { USB_DEVICE(0x0582, 0x007d) }, + { USB_DEVICE(0x0582, 0x008d) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ua101_ids); + +static struct usb_driver ua101_driver = { + .name = "snd-ua101", + .id_table = ua101_ids, + .probe = ua101_probe, + .disconnect = ua101_disconnect, +#if 0 + .suspend = ua101_suspend, + .resume = ua101_resume, +#endif +}; + +static int __init alsa_card_ua101_init(void) +{ + return usb_register(&ua101_driver); +} + +static void __exit alsa_card_ua101_exit(void) +{ + usb_deregister(&ua101_driver); + mutex_destroy(&devices_mutex); +} + +module_init(alsa_card_ua101_init); +module_exit(alsa_card_ua101_exit); diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index b074a594c595..f352141cf8ee 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3142,59 +3142,6 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, return 0; } -/* - * Create a stream for an Edirol UA-101 interface. - * Copy, paste and modify from Edirol UA-1000 - */ -static int create_ua101_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk) -{ - static const struct audioformat ua101_format = { - .format = SNDRV_PCM_FORMAT_S32_LE, - .fmt_type = USB_FORMAT_TYPE_I, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - }; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct audioformat *fp; - int stream, err; - - if (iface->num_altsetting != 2) - return -ENXIO; - alts = &iface->altsetting[1]; - altsd = get_iface_desc(alts); - if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || - altsd->bNumEndpoints != 1) - return -ENXIO; - - fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->channels = alts->extra[11]; - fp->iface = altsd->bInterfaceNumber; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = parse_datainterval(chip, alts); - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); - - stream = (fp->endpoint & USB_DIR_IN) - ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = add_audio_endpoint(chip, stream, fp); - if (err < 0) { - kfree(fp); - return err; - } - /* FIXME: playback must be synchronized to capture */ - usb_set_interface(chip->dev, fp->iface, 0); - return 0; -} - static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, const struct snd_usb_audio_quirk *quirk); @@ -3406,7 +3353,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, - [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk }; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 40ba8115fb81..9826337c76b8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -159,7 +159,6 @@ enum quirk_type { QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, - QUIRK_AUDIO_EDIROL_UA101, QUIRK_AUDIO_EDIROL_UAXX, QUIRK_TYPE_COUNT diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a892bda03df9..bd6706c2d534 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1266,37 +1266,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -/* Roland UA-101 in High-Speed Mode only */ -{ - USB_DEVICE(0x0582, 0x007d), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "UA-101", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, { /* has ID 0x0081 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0080), -- GitLab From 5b0cb1d850c26893b1468b3a519433a1b7a176be Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 8 Dec 2009 16:13:32 +0100 Subject: [PATCH 0037/3892] ALSA: hda - add more NID->Control mapping This set of changes add missing NID values to some static control elemenents. Also, it handles all "Capture Source" or "Input Source" controls. Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 64 +++++++- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_generic.c | 3 +- sound/pci/hda/hda_local.h | 5 + sound/pci/hda/hda_proc.c | 23 +-- sound/pci/hda/patch_analog.c | 31 ++++ sound/pci/hda/patch_cirrus.c | 4 + sound/pci/hda/patch_cmedia.c | 12 +- sound/pci/hda/patch_realtek.c | 120 ++++++++++++++- sound/pci/hda/patch_si3054.c | 1 + sound/pci/hda/patch_via.c | 273 +++++++++++++++++++++------------- 11 files changed, 415 insertions(+), 122 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9cfdb771928c..20100b1548e1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) #endif list_del(&codec->list); snd_array_free(&codec->mixers); + snd_array_free(&codec->nids); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr mutex_init(&codec->control_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); - snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); + snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); + snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); if (codec->bus->modelname) { @@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); /** - * snd_hda_ctl-add - Add a control element and assign to the codec + * snd_hda_ctl_add - Add a control element and assign to the codec * @codec: HD-audio codec * @nid: corresponding NID (optional) * @kctl: the control element to assign @@ -1746,6 +1748,35 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_ctl_add); +/** + * snd_hda_add_nid - Assign a NID to a control element + * @codec: HD-audio codec + * @nid: corresponding NID (optional) + * @kctl: the control element to assign + * @index: index to kctl + * + * Add the given control element to an array inside the codec instance. + * This function is used when #snd_hda_ctl_add cannot be used for 1:1 + * NID:KCTL mapping - for example "Capture Source" selector. + */ +int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, + unsigned int index, hda_nid_t nid) +{ + struct hda_nid_item *item; + + if (nid > 0) { + item = snd_array_new(&codec->nids); + if (!item) + return -ENOMEM; + item->kctl = kctl; + item->index = index; + item->nid = nid; + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL_HDA(snd_hda_add_nid); + /** * snd_hda_ctls_clear - Clear all controls assigned to the given codec * @codec: HD-audio codec @@ -1757,6 +1788,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->bus->card, items[i].kctl); snd_array_free(&codec->mixers); + snd_array_free(&codec->nids); } /* pseudo device locking @@ -3476,6 +3508,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) for (; knew->name; knew++) { struct snd_kcontrol *kctl; + if (knew->iface == -1) /* skip this codec private value */ + continue; kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; @@ -3496,6 +3530,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); +/** + * snd_hda_add_nids - assign nids to controls from the array + * @codec: the HDA codec + * @kctl: struct snd_kcontrol + * @index: index to kctl + * @nids: the array of hda_nid_t + * @size: count of hda_nid_t items + * + * This helper function assigns NIDs in the given array to a control element. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, + unsigned int index, hda_nid_t *nids, unsigned int size) +{ + int err; + + for ( ; size > 0; size--, nids++) { + err = snd_hda_add_nid(codec, kctl, index, *nids); + if (err < 0) + return err; + } + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_add_nids); + #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1d541b7f5547..0d08ad5bd898 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -789,6 +789,7 @@ struct hda_codec { u32 *wcaps; struct snd_array mixers; /* list of assigned mixer elements */ + struct snd_array nids; /* list of mapped mixer elements */ struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 092c6a7c2ff3..5ea21285ee1f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ - err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec)); + err = snd_hda_ctl_add(codec, spec->adc_node->nid, + snd_ctl_new1(&cap_sel, codec)); if (err < 0) return err; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5778ae882b83..98cf3f4f3755 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -342,6 +342,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); +int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, + unsigned int index, hda_nid_t *nids, unsigned int size); /* * unsolicited event handler @@ -466,11 +468,14 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); struct hda_nid_item { struct snd_kcontrol *kctl; + unsigned int index; hda_nid_t nid; }; int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, struct snd_kcontrol *kctl); +int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, + unsigned int index, hda_nid_t nid); void snd_hda_ctls_clear(struct hda_codec *codec); /* diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c9afc04adac8..2e27d6a8b446 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -61,18 +61,21 @@ static const char *get_wid_type_name(unsigned int wid_value) return "UNKNOWN Widget"; } -static void print_nid_mixers(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) +static void print_nid_array(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid, + struct snd_array *array) { int i; - struct hda_nid_item *items = codec->mixers.list; + struct hda_nid_item *items = array->list, *item; struct snd_kcontrol *kctl; - for (i = 0; i < codec->mixers.used; i++) { - if (items[i].nid == nid) { - kctl = items[i].kctl; + for (i = 0; i < array->used; i++) { + item = &items[i]; + if (item->nid == nid) { + kctl = item->kctl; snd_iprintf(buffer, " Control: name=\"%s\", index=%i, device=%i\n", - kctl->id.name, kctl->id.index, kctl->id.device); + kctl->id.name, kctl->id.index + item->index, + kctl->id.device); } } } @@ -528,7 +531,8 @@ static void print_gpio(struct snd_info_buffer *buffer, (data & (1<mixers); + print_nid_array(buffer, codec, nid, &codec->nids); } static void print_codec_info(struct snd_info_entry *entry, @@ -608,7 +612,8 @@ static void print_codec_info(struct snd_info_entry *entry, snd_iprintf(buffer, " CP"); snd_iprintf(buffer, "\n"); - print_nid_mixers(buffer, codec, nid); + print_nid_array(buffer, codec, nid, &codec->mixers); + print_nid_array(buffer, codec, nid, &codec->nids); print_nid_pcms(buffer, codec, nid); /* volume knob is a special widget that always have connection diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 447eda1f6770..d418842373fd 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; + struct snd_kcontrol *kctl; unsigned int i; int err; @@ -239,6 +240,28 @@ static int ad198x_build_controls(struct hda_codec *codec) } ad198x_free_kctls(codec); /* no longer needed */ + + /* assign Capture Source enums to NID */ + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + if (!kctl) + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, + spec->input_mux->num_items); + if (err < 0) + return err; + } + + /* assign IEC958 enums to NID */ + kctl = snd_hda_find_mixer_ctl(codec, + SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); + if (kctl) { + err = snd_hda_add_nid(codec, kctl, 0, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + return 0; } @@ -701,6 +724,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "External Amplifier", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, .info = ad198x_eapd_info, .get = ad198x_eapd_get, .put = ad198x_eapd_put, @@ -808,6 +832,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1a, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1986a_hp_master_sw_put, @@ -1608,6 +1633,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, .name = "Master Playback Switch", .info = ad198x_eapd_info, .get = ad198x_eapd_get, @@ -2121,6 +2147,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "External Amplifier", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, .info = ad198x_eapd_info, .get = ad198x_eapd_get, .put = ad198x_eapd_put, @@ -2242,6 +2269,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC958 Playback Source", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, .info = ad1988_spdif_playback_source_info, .get = ad1988_spdif_playback_source_get, .put = ad1988_spdif_playback_source_put, @@ -3728,6 +3756,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -3756,6 +3785,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -4097,6 +4127,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, .name = "Master Playback Switch", .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 4b200da1bd18..d0b8c6dc7322 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -759,6 +759,10 @@ static int build_input(struct hda_codec *codec) err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; + err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid, + spec->num_inputs); + if (err < 0) + return err; } if (spec->num_inputs > 1 && !spec->mic_detect) { diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a45c1169762b..cc1c22370a60 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = { static int cmi9880_build_controls(struct hda_codec *codec) { struct cmi_spec *spec = codec->spec; - int err; + struct snd_kcontrol *kctl; + int i, err; err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); if (err < 0) @@ -340,6 +341,15 @@ static int cmi9880_build_controls(struct hda_codec *codec) if (err < 0) return err; } + + /* assign Capture Source enums to NID */ + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids, + spec->input_mux->num_items); + if (err < 0) + return err; + } return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 888b6313eeca..6b0b8728f6b7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -627,6 +627,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, #define ALC_PIN_MODE(xname, nid, dir) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_pin_mode_info, \ .get = alc_pin_mode_get, \ .put = alc_pin_mode_put, \ @@ -678,6 +679,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, } #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_gpio_data_info, \ .get = alc_gpio_data_get, \ .put = alc_gpio_data_put, \ @@ -732,6 +734,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, } #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_spdif_ctrl_info, \ .get = alc_spdif_ctrl_get, \ .put = alc_spdif_ctrl_put, \ @@ -785,6 +788,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_eapd_ctrl_info, \ .get = alc_eapd_ctrl_get, \ .put = alc_eapd_ctrl_put, \ @@ -2410,6 +2414,15 @@ static const char *alc_slave_sws[] = { * build control elements */ +#define NID_MAPPING (-1) + +#define SUBDEV_SPEAKER_ (0 << 6) +#define SUBDEV_HP_ (1 << 6) +#define SUBDEV_LINE_ (2 << 6) +#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) +#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) +#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) + static void alc_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -2424,8 +2437,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = { static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int err; - int i; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new *knew; + int i, j, err; + unsigned int u; + hda_nid_t nid; for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); @@ -2494,6 +2510,73 @@ static int alc_build_controls(struct hda_codec *codec) } alc_free_kctls(codec); /* no longer needed */ + + /* assign Capture Source enums to NID */ + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + if (!kctl) + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, + spec->input_mux->num_items); + if (err < 0) + return err; + } + if (spec->cap_mixer) { + const char *kname = kctl ? kctl->id.name : NULL; + for (knew = spec->cap_mixer; knew->name; knew++) { + if (kname && strcmp(knew->name, kname) == 0) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nid(codec, kctl, i, + spec->adc_nids[i]); + if (err < 0) + return err; + } + } + } + + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + u = knew->subdevice; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0x3f; + if (nid == 0) + continue; + switch (u & 0xc0) { + case SUBDEV_SPEAKER_: + nid = spec->autocfg.speaker_pins[nid]; + break; + case SUBDEV_LINE_: + nid = spec->autocfg.line_out_pins[nid]; + break; + case SUBDEV_HP_: + nid = spec->autocfg.hp_pins[nid]; + break; + default: + continue; + } + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + u = knew->private_value; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0xff; + if (nid == 0) + continue; + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + } + } return 0; } @@ -3781,6 +3864,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, #define PIN_CTL_TEST(xname,nid) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_test_pin_ctl_info, \ .get = alc_test_pin_ctl_get, \ .put = alc_test_pin_ctl_put, \ @@ -3790,6 +3874,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, #define PIN_SRC_TEST(xname,nid) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ .info = alc_test_pin_src_info, \ .get = alc_test_pin_src_get, \ .put = alc_test_pin_src_put, \ @@ -5080,6 +5165,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, @@ -5118,6 +5204,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, @@ -10188,8 +10275,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, .info = snd_ctl_boolean_mono_info, \ .get = alc262_hp_master_sw_get, \ .put = alc262_hp_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ } + static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -10347,6 +10440,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, .info = snd_ctl_boolean_mono_info, \ .get = alc262_hippo_master_sw_get, \ .put = alc262_hippo_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ + (SUBDEV_SPEAKER(0) << 16), \ } static struct snd_kcontrol_new alc262_hippo_mixer[] = { @@ -10820,11 +10919,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_fujitsu_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, + { + .iface = NID_MAPPING, + .name = "Master Playback Switch", + .private_value = 0x1b, + }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), @@ -10855,6 +10960,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_lenovo_3000_master_sw_put, @@ -11009,6 +11115,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { .get = alc_mux_enum_get, .put = alc262_ultra_mux_enum_put, }, + { + .iface = NID_MAPPING, + .name = "Capture Source", + .private_value = 0x15, + }, { } /* end */ }; @@ -12026,6 +12137,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12041,6 +12153,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12058,6 +12171,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13010,6 +13124,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13030,6 +13145,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 43b436c5d01b..f419ee8d75f0 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, #define SI3054_KCONTROL(kname,reg,mask) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = kname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | reg, \ .info = si3054_switch_info, \ .get = si3054_switch_get, \ .put = si3054_switch_put, \ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b70e26ad263f..64995e8e3a72 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -54,6 +54,8 @@ #include "hda_codec.h" #include "hda_local.h" +#define NID_MAPPING (-1) + /* amp values */ #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) @@ -157,6 +159,19 @@ struct via_spec { #endif }; +static struct via_spec * via_new_spec(struct hda_codec *codec) +{ + struct via_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return NULL; + + codec->spec = spec; + spec->codec = codec; + return spec; +} + static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) { u32 vendor_id = codec->vendor_id; @@ -448,6 +463,22 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, return 0; } +static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, + struct snd_kcontrol_new *tmpl) +{ + struct snd_kcontrol_new *knew; + + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *tmpl; + knew->name = kstrdup(tmpl->name, GFP_KERNEL); + if (!knew->name) + return NULL; + return 0; +} + static void via_free_kctls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - hda_nid_t nid; + hda_nid_t nid = kcontrol->private_value; unsigned int pinsel; - switch (spec->codec_type) { - case VT1718S: - nid = 0x34; - break; - case VT2002P: - nid = 0x35; - break; - case VT1812: - nid = 0x3d; - break; - default: - nid = spec->autocfg.hp_pins[0]; - break; - } /* use !! to translate conn sel 2 for VT1718S */ pinsel = !!snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, @@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active) } } +static hda_nid_t side_mute_channel(struct via_spec *spec) +{ + switch (spec->codec_type) { + case VT1708: return 0x1b; + case VT1709_10CH: return 0x29; + case VT1708B_8CH: /* fall thru */ + case VT1708S: return 0x27; + default: return 0; + } +} + static int update_side_mute_status(struct hda_codec *codec) { /* mute side channel */ struct via_spec *spec = codec->spec; unsigned int parm = spec->hp_independent_mode ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; - hda_nid_t sw3; - - switch (spec->codec_type) { - case VT1708: - sw3 = 0x1b; - break; - case VT1709_10CH: - sw3 = 0x29; - break; - case VT1708B_8CH: - case VT1708S: - sw3 = 0x27; - break; - default: - sw3 = 0; - break; - } + hda_nid_t sw3 = side_mute_channel(spec); if (sw3) snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - hda_nid_t nid = spec->autocfg.hp_pins[0]; + hda_nid_t nid = kcontrol->private_value; unsigned int pinsel = ucontrol->value.enumerated.item[0]; /* Get Independent Mode index of headphone pin widget */ spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel ? 1 : 0; - - switch (spec->codec_type) { - case VT1718S: - nid = 0x34; - pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ - spec->multiout.num_dacs = 4; - break; - case VT2002P: - nid = 0x35; - break; - case VT1812: - nid = 0x3d; - break; - default: - nid = spec->autocfg.hp_pins[0]; - break; - } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); if (spec->multiout.hp_nid && spec->multiout.hp_nid @@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new via_hp_mixer[] = { +static struct snd_kcontrol_new via_hp_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Independent HP", - .count = 1, .info = via_independent_hp_info, .get = via_independent_hp_get, .put = via_independent_hp_put, }, - { } /* end */ + { + .iface = NID_MAPPING, + .name = "Independent HP", + }, }; +static int via_hp_build(struct via_spec *spec) +{ + struct snd_kcontrol_new *knew; + hda_nid_t nid; + + knew = via_clone_control(spec, &via_hp_mixer[0]); + if (knew == NULL) + return -ENOMEM; + + switch (spec->codec_type) { + case VT1718S: + nid = 0x34; + break; + case VT2002P: + nid = 0x35; + break; + case VT1812: + nid = 0x3d; + break; + default: + nid = spec->autocfg.hp_pins[0]; + break; + } + + knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; + knew->private_value = nid; + + knew = via_clone_control(spec, &via_hp_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = side_mute_channel(spec); + + return 0; +} + static void notify_aa_path_ctls(struct hda_codec *codec) { int i; @@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new via_smart51_mixer[] = { +static struct snd_kcontrol_new via_smart51_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Smart 5.1", @@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = { .get = via_smart51_get, .put = via_smart51_put, }, - {} /* end */ + { + .iface = NID_MAPPING, + .name = "Smart 5.1", + } }; +static int via_smart51_build(struct via_spec *spec) +{ + struct snd_kcontrol_new *knew; + int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; + hda_nid_t nid; + int i; + + knew = via_clone_control(spec, &via_smart51_mixer[0]); + if (knew == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(index); i++) { + nid = spec->autocfg.input_pins[index[i]]; + if (nid) { + knew = via_clone_control(spec, &via_smart51_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = nid; + } + } + + return 0; +} + /* capture mixer elements */ static struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), @@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = { static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - int err; - int i; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new *knew; + int err, i; for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); @@ -1845,6 +1904,28 @@ static int via_build_controls(struct hda_codec *codec) return err; } + /* assign Capture Source enums to NID */ + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids, + spec->input_mux->num_items); + if (err < 0) + return err; + } + + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + err = snd_hda_add_nid(codec, kctl, 0, + knew->subdevice); + } + } + /* init power states */ set_jack_power_state(codec); analog_low_current_mode(codec, 1); @@ -2481,9 +2562,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -2554,12 +2635,10 @@ static int patch_vt1708(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1708_parse_auto_config(codec); if (err < 0) { @@ -2597,7 +2676,6 @@ static int patch_vt1708(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1708_loopbacks; #endif - spec->codec = codec; INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } @@ -3010,9 +3088,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -3032,12 +3110,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - err = vt1709_parse_auto_config(codec); if (err < 0) { via_free(codec); @@ -3126,12 +3202,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - err = vt1709_parse_auto_config(codec); if (err < 0) { via_free(codec); @@ -3581,9 +3655,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -3605,12 +3679,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) if (get_codec_type(codec) == VT1708BCE) return patch_vt1708S(codec); /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1708B_parse_auto_config(codec); if (err < 0) { @@ -3657,12 +3729,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1708B_parse_auto_config(codec); if (err < 0) { @@ -4071,9 +4141,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -4103,12 +4173,10 @@ static int patch_vt1708S(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1708S_parse_auto_config(codec); if (err < 0) { @@ -4443,7 +4511,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); return 1; } @@ -4464,12 +4532,10 @@ static int patch_vt1702(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1702_parse_auto_config(codec); if (err < 0) { @@ -4865,9 +4931,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -4888,12 +4954,10 @@ static int patch_vt1718S(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1718S_parse_auto_config(codec); if (err < 0) { @@ -5014,6 +5078,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Mic Capture Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, .count = 1, .info = vt1716s_dmic_info, .get = vt1716s_dmic_get, @@ -5361,9 +5426,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); - spec->mixers[spec->num_mixers++] = via_smart51_mixer; + via_smart51_build(spec); return 1; } @@ -5384,12 +5449,10 @@ static int patch_vt1716S(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1716S_parse_auto_config(codec); if (err < 0) { @@ -5719,7 +5782,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); return 1; } @@ -5741,12 +5804,10 @@ static int patch_vt2002P(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt2002P_parse_auto_config(codec); if (err < 0) { @@ -6070,7 +6131,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - spec->mixers[spec->num_mixers++] = via_hp_mixer; + via_hp_build(spec); return 1; } @@ -6092,12 +6153,10 @@ static int patch_vt1812(struct hda_codec *codec) int err; /* create a codec specific record */ - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - codec->spec = spec; - /* automatic parse from the BIOS config */ err = vt1812_parse_auto_config(codec); if (err < 0) { -- GitLab From 9e3fd8719f624a43575b56a4777b1552399a8be8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 8 Dec 2009 17:45:25 +0100 Subject: [PATCH 0038/3892] ALSA: hda - introduce HDA_SUBDEV_AMP_FLAG (ControlAmp in proc) The purpose of this changeset is to show information about amplifier setting in the codec proc file. Something like: Control: name="Front Playback Volume", index=0, device=0 ControlAmp: chs=3, dir=Out, idx=0, ofs=0 Control: name="Front Playback Switch", index=0, device=0 ControlAmp: chs=3, dir=In, idx=2, ofs=0 Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 14 +++++++++----- sound/pci/hda/hda_local.h | 11 ++++++++--- sound/pci/hda/hda_proc.c | 8 ++++++++ sound/pci/hda/patch_analog.c | 12 +++++++----- sound/pci/hda/patch_cirrus.c | 2 ++ sound/pci/hda/patch_conexant.c | 1 + sound/pci/hda/patch_realtek.c | 18 ++++++++++-------- sound/pci/hda/patch_sigmatel.c | 3 ++- sound/pci/hda/patch_via.c | 4 +++- 9 files changed, 50 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 20100b1548e1..c9af15ed7f10 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1723,19 +1723,22 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); * * snd_hda_ctl_add() checks the control subdev id field whether * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower - * bits value is taken as the NID to assign. + * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit + * specifies if kctl->private_value is a HDA amplifier value. */ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, struct snd_kcontrol *kctl) { int err; + unsigned short flags = 0; struct hda_nid_item *item; - if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { - if (nid == 0) - nid = kctl->id.subdevice & 0xffff; + if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) + flags |= HDA_NID_ITEM_AMP; + if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) + nid = kctl->id.subdevice & 0xffff; + if (kctl->id.subdevice & 0xf0000000) kctl->id.subdevice = 0; - } err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; @@ -1744,6 +1747,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, return -ENOMEM; item->kctl = kctl; item->nid = nid; + item->flags = flags; return 0; } EXPORT_SYMBOL_HDA(snd_hda_ctl_add); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 98cf3f4f3755..0a256471f812 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -31,6 +31,7 @@ * in snd_hda_ctl_add(), so that this value won't appear in the outside. */ #define HDA_SUBDEV_NID_FLAG (1U << 31) +#define HDA_SUBDEV_AMP_FLAG (1U << 30) /* * for mixer controls @@ -42,7 +43,7 @@ /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ @@ -63,7 +64,7 @@ /* mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put, \ @@ -81,7 +82,7 @@ /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put_beep, \ @@ -466,10 +467,14 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); +/* flags for hda_nid_item */ +#define HDA_NID_ITEM_AMP (1<<0) + struct hda_nid_item { struct snd_kcontrol *kctl; unsigned int index; hda_nid_t nid; + unsigned short flags; }; int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 2e27d6a8b446..f97d35de66c4 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -76,6 +76,14 @@ static void print_nid_array(struct snd_info_buffer *buffer, " Control: name=\"%s\", index=%i, device=%i\n", kctl->id.name, kctl->id.index + item->index, kctl->id.device); + if (item->flags & HDA_NID_ITEM_AMP) + snd_iprintf(buffer, + " ControlAmp: chs=%lu, dir=%s, " + "idx=%lu, ofs=%lu\n", + get_amp_channels(kctl), + get_amp_direction(kctl) ? "Out" : "In", + get_amp_index(kctl), + get_amp_offset(kctl)); } } } diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d418842373fd..5e2bb181a149 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -832,7 +832,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1a, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x1a, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1986a_hp_master_sw_put, @@ -2602,7 +2602,9 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, if (! knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | + HDA_SUBDEV_AMP_FLAG | + get_amp_nid_(val); knew->private_value = val; return 0; } @@ -3756,7 +3758,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -3785,7 +3787,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -4127,7 +4129,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_NID_FLAG | 0x21, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, .name = "Master Playback Switch", .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d0b8c6dc7322..e51f6658aa2c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -500,6 +500,7 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, knew.private_value = pval; snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); + (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); } @@ -513,6 +514,7 @@ static int add_volume(struct hda_codec *codec, const char *name, knew.private_value = pval; snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); + (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); } diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index a09c03c3f62b..b68650af40a9 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2178,6 +2178,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x10, .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = snd_hda_mixer_amp_volume_put, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6b0b8728f6b7..87bf7bd6292a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4414,7 +4414,9 @@ static int add_control(struct alc_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | + HDA_SUBDEV_AMP_FLAG | + get_amp_nid_(val); knew->private_value = val; return 0; } @@ -10919,7 +10921,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_fujitsu_master_sw_put, @@ -10960,7 +10962,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x1b, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_lenovo_3000_master_sw_put, @@ -12137,7 +12139,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12153,7 +12155,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12171,7 +12173,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13124,7 +13126,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13145,7 +13147,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3d59f8325848..1ee586b65b63 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2702,7 +2702,8 @@ stac_control_new(struct sigmatel_spec *spec, return NULL; } if (nid) - knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; + knew->subdevice = HDA_SUBDEV_NID_FLAG | + HDA_SUBDEV_AMP_FLAG | nid; return knew; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 64995e8e3a72..b94cdee5eb53 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -458,7 +458,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | + HDA_SUBDEV_AMP_FLAG | + get_amp_nid_(val); knew->private_value = val; return 0; } -- GitLab From 5e26dfd0615868872cb44842f1e1428c7b414ab0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 10 Dec 2009 13:57:01 +0100 Subject: [PATCH 0039/3892] ALSA: hda - simplify usage of HDA_SUBDEV_AMP_FLAG The HDA_SUBDEV_NID_FLAG is duplicate for amplifier control elements. Move get_amp_nid_() call to the snd_hda_ctl_add() function. Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 7 +++++-- sound/pci/hda/hda_local.h | 6 +++--- sound/pci/hda/patch_analog.c | 16 ++++++---------- sound/pci/hda/patch_cirrus.c | 4 ++-- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_realtek.c | 21 +++++++++------------ sound/pci/hda/patch_sigmatel.c | 8 +++----- sound/pci/hda/patch_via.c | 4 +--- 8 files changed, 30 insertions(+), 38 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c9af15ed7f10..c848ec0f085e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1733,11 +1733,14 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, unsigned short flags = 0; struct hda_nid_item *item; - if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) + if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { flags |= HDA_NID_ITEM_AMP; + if (nid == 0) + nid = get_amp_nid_(kctl->private_value); + } if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) nid = kctl->id.subdevice & 0xffff; - if (kctl->id.subdevice & 0xf0000000) + if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) kctl->id.subdevice = 0; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 0a256471f812..d505d052972e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -43,7 +43,7 @@ /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ @@ -64,7 +64,7 @@ /* mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put, \ @@ -82,7 +82,7 @@ /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | (nid), \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put_beep, \ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 5e2bb181a149..e75b5e5a1d55 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -209,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec) if (!kctl) return -ENOMEM; kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, - get_amp_nid_(spec->beep_amp), - kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } @@ -832,7 +830,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x1a, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1986a_hp_master_sw_put, @@ -2602,9 +2600,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, if (! knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | - HDA_SUBDEV_AMP_FLAG | - get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; return 0; } @@ -3758,7 +3754,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -3787,7 +3783,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = ad1884a_mobile_master_sw_put, @@ -4129,7 +4125,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x21, + .subdevice = HDA_SUBDEV_AMP_FLAG, .name = "Master Playback Switch", .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index e51f6658aa2c..eeb91f6a06c2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -501,7 +501,7 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); + return snd_hda_ctl_add(codec, 0, *kctlp); } static int add_volume(struct hda_codec *codec, const char *name, @@ -515,7 +515,7 @@ static int add_volume(struct hda_codec *codec, const char *name, snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); + return snd_hda_ctl_add(codec, 0, *kctlp); } static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b68650af40a9..1ab2958a290b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2178,7 +2178,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x10, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_volume_info, .get = snd_hda_mixer_amp_volume_get, .put = snd_hda_mixer_amp_volume_put, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87bf7bd6292a..cb7679551bdc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2482,8 +2482,7 @@ static int alc_build_controls(struct hda_codec *codec) if (!kctl) return -ENOMEM; kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, - get_amp_nid_(spec->beep_amp), kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } @@ -4414,9 +4413,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | - HDA_SUBDEV_AMP_FLAG | - get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; return 0; } @@ -10921,7 +10918,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_fujitsu_master_sw_put, @@ -10962,7 +10959,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x1b, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc262_lenovo_3000_master_sw_put, @@ -12139,7 +12136,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12155,7 +12152,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -12173,7 +12170,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13126,7 +13123,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, @@ -13147,7 +13144,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | HDA_SUBDEV_AMP_FLAG | 0x14, + .subdevice = HDA_SUBDEV_AMP_FLAG, .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, .put = alc268_acer_master_sw_put, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1ee586b65b63..0bafea9d5106 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2685,7 +2685,7 @@ static struct snd_kcontrol_new * stac_control_new(struct sigmatel_spec *spec, struct snd_kcontrol_new *ktemp, const char *name, - hda_nid_t nid) + unsigned int subdev) { struct snd_kcontrol_new *knew; @@ -2701,9 +2701,7 @@ stac_control_new(struct sigmatel_spec *spec, spec->kctls.alloced--; return NULL; } - if (nid) - knew->subdevice = HDA_SUBDEV_NID_FLAG | - HDA_SUBDEV_AMP_FLAG | nid; + knew->subdevice = subdev; return knew; } @@ -2713,7 +2711,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, unsigned long val) { struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, - get_amp_nid_(val)); + HDA_SUBDEV_AMP_FLAG); if (!knew) return -ENOMEM; knew->index = idx; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b94cdee5eb53..de4839e46762 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -458,9 +458,7 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_NID_FLAG | - HDA_SUBDEV_AMP_FLAG | - get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; return 0; } -- GitLab From 926a01ce1ef5e27281af0270e4476979c0522954 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 16 Dec 2009 16:15:00 +0100 Subject: [PATCH 0040/3892] ALSA: Release v1.0.22 Signed-off-by: Jaroslav Kysela --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index 22939142dd23..1f5d4872d623 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.21" +#define CONFIG_SND_VERSION "1.0.22" #define CONFIG_SND_DATE "" -- GitLab From 283375cefbf4f91ce51d93d010634c48d0d39044 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 Dec 2009 18:09:03 +0000 Subject: [PATCH 0041/3892] ASoC: Push registers out of mixer power decision No need for the mixers to know about this, and it allows for virtual controls. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-dapm.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 846678aa3d35..4cf58911f3b3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1262,8 +1262,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, /* test and update the power status of a mixer or switch widget */ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int reg, - int val_mask, int val, int invert) + struct snd_kcontrol *kcontrol, int connect) { struct snd_soc_dapm_path *path; int found = 0; @@ -1273,9 +1272,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, widget->id != snd_soc_dapm_switch) return -ENODEV; - if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) - return 0; - /* find dapm widget path assoc with kcontrol */ list_for_each_entry(path, &widget->codec->dapm_paths, list) { if (path->kcontrol != kcontrol) @@ -1283,12 +1279,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, /* found, now check type */ found = 1; - if (val) - /* new connection */ - path->connect = invert ? 0:1; - else - /* old connection must be powered down */ - path->connect = invert ? 1:0; + path->connect = connect; break; } @@ -1695,6 +1686,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned int val, val2, val_mask; + int connect; int ret; val = (ucontrol->value.integer.value[0] & mask); @@ -1721,7 +1713,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, return 1; } - dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); + if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { + if (val) + /* new connection */ + connect = invert ? 0:1; + else + /* old connection must be powered down */ + connect = invert ? 1:0; + + dapm_mixer_update_power(widget, kcontrol, connect); + } + if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, kcontrol, -- GitLab From d207c68dd92455a3d618c37b5a9f0dc598723fd6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 Dec 2009 17:13:55 +0000 Subject: [PATCH 0042/3892] ASoC: Sort DAPM sequences by CODEC as well In preparation for multiple device support. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-dapm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4cf58911f3b3..de22c2f1842e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -739,6 +739,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, struct snd_soc_dapm_widget *b, int sort[]) { + if (a->codec != b->codec) + return (unsigned long)a - (unsigned long)b; if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->reg != b->reg) -- GitLab From cce2e9db718d823f33ac846c019763cdc84e8658 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 8 Dec 2009 21:50:01 +0000 Subject: [PATCH 0043/3892] ASoC: Register the CODEC in WM8727 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8727.c | 66 +++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index d8ffbd641d71..63a254e293ca 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -44,23 +44,16 @@ struct snd_soc_dai wm8727_dai = { }; EXPORT_SYMBOL_GPL(wm8727_dai); +static struct snd_soc_codec *wm8727_codec; + static int wm8727_soc_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; int ret = 0; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - mutex_init(&codec->mutex); - codec->name = "WM8727"; - codec->owner = THIS_MODULE; - codec->dai = &wm8727_dai; - codec->num_dai = 1; - socdev->card->codec = codec; - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + BUG_ON(!wm8727_codec); + + socdev->card->codec = wm8727_codec; /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); @@ -80,12 +73,9 @@ pcm_err: static int wm8727_soc_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - if (codec == NULL) - return 0; snd_soc_free_pcms(socdev); - kfree(codec); + return 0; } @@ -98,13 +88,55 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727); static __devinit int wm8727_platform_probe(struct platform_device *pdev) { + struct snd_soc_codec *codec; + int ret; + + if (wm8727_codec) { + dev_err(&pdev->dev, "Another WM8727 is registered\n"); + return -EBUSY; + } + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + wm8727_codec = codec; + + platform_set_drvdata(pdev, codec); + + mutex_init(&codec->mutex); + codec->dev = &pdev->dev; + codec->name = "WM8727"; + codec->owner = THIS_MODULE; + codec->dai = &wm8727_dai; + codec->num_dai = 1; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + wm8727_dai.dev = &pdev->dev; - return snd_soc_register_dai(&wm8727_dai); + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8727_dai); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(codec); + return ret; } static int __devexit wm8727_platform_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&wm8727_dai); + snd_soc_unregister_codec(platform_get_drvdata(pdev)); return 0; } -- GitLab From 168db50d967e09133feda8247d4dcb3c73437766 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 9 Dec 2009 13:29:20 +0900 Subject: [PATCH 0044/3892] ASoC: S3C64XX: Remove unnecessary header includes Removed redundant header includes which make no difference to compilation. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index cc7edb5f792d..8feb029b99fe 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -15,16 +15,10 @@ #include #include #include -#include #include -#include #include #include -#include -#include -#include -#include #include #include -- GitLab From 0fe692292a26f57b6522fe859cc8b2549ec0cd97 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 9 Dec 2009 13:29:25 +0900 Subject: [PATCH 0045/3892] ASoC: S3C64XX: Compress and generalize the CPU driver The driver can be 'generalized' a bit by not hardcoding '2'(the number of I2Sv3 controllers that the driver can handle) at many places, instead we define a macro for it. That makes it easier to increase number of controllers by changing the parameter at just one place, this will be useful when there is support for newer SoCs, which have the same controller, only more in number. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 114 ++++++++++++-------------------- 1 file changed, 41 insertions(+), 73 deletions(-) diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 8feb029b99fe..93ed3aad1631 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -32,6 +32,11 @@ #include "s3c-dma.h" #include "s3c64xx-i2s.h" +/* The value should be set to maximum of the total number + * of I2Sv3 controllers that any supported SoC has. + */ +#define MAX_I2SV3 2 + static struct s3c2410_dma_client s3c64xx_dma_client_out = { .name = "I2S PCM Stereo out" }; @@ -40,37 +45,12 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { - [0] = { - .channel = DMACH_I2S0_OUT, - .client = &s3c64xx_dma_client_out, - .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD, - .dma_size = 4, - }, - [1] = { - .channel = DMACH_I2S1_OUT, - .client = &s3c64xx_dma_client_out, - .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD, - .dma_size = 4, - }, -}; - -static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { - [0] = { - .channel = DMACH_I2S0_IN, - .client = &s3c64xx_dma_client_in, - .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD, - .dma_size = 4, - }, - [1] = { - .channel = DMACH_I2S1_IN, - .client = &s3c64xx_dma_client_in, - .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD, - .dma_size = 4, - }, -}; +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3]; +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3]; +static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3]; -static struct s3c_i2sv2_info s3c64xx_i2s[2]; +struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3]; +EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) { @@ -163,55 +143,13 @@ static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { .set_sysclk = s3c64xx_i2s_set_sysclk, }; -struct snd_soc_dai s3c64xx_i2s_dai[] = { - { - .name = "s3c64xx-i2s", - .id = 0, - .probe = s3c64xx_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .ops = &s3c64xx_i2s_dai_ops, - .symmetric_rates = 1, - }, - { - .name = "s3c64xx-i2s", - .id = 1, - .probe = s3c64xx_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .ops = &s3c64xx_i2s_dai_ops, - .symmetric_rates = 1, - }, -}; -EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); - static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) { struct s3c_i2sv2_info *i2s; struct snd_soc_dai *dai; int ret; - if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { + if (pdev->id >= MAX_I2SV3) { dev_err(&pdev->dev, "id %d out of range\n", pdev->id); return -EINVAL; } @@ -219,10 +157,40 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) i2s = &s3c64xx_i2s[pdev->id]; dai = &s3c64xx_i2s_dai[pdev->id]; dai->dev = &pdev->dev; + dai->name = "s3c64xx-i2s"; + dai->id = pdev->id; + dai->symmetric_rates = 1; + dai->playback.channels_min = 2; + dai->playback.channels_max = 2; + dai->playback.rates = S3C64XX_I2S_RATES; + dai->playback.formats = S3C64XX_I2S_FMTS; + dai->capture.channels_min = 2; + dai->capture.channels_max = 2; + dai->capture.rates = S3C64XX_I2S_RATES; + dai->capture.formats = S3C64XX_I2S_FMTS; + dai->probe = s3c64xx_i2s_probe; + dai->ops = &s3c64xx_i2s_dai_ops; i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; + if (pdev->id == 0) { + i2s->dma_capture->channel = DMACH_I2S0_IN; + i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD; + i2s->dma_playback->channel = DMACH_I2S0_OUT; + i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD; + } else { + i2s->dma_capture->channel = DMACH_I2S1_IN; + i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD; + i2s->dma_playback->channel = DMACH_I2S1_OUT; + i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD; + } + + i2s->dma_capture->client = &s3c64xx_dma_client_in; + i2s->dma_capture->dma_size = 4; + i2s->dma_playback->client = &s3c64xx_dma_client_out; + i2s->dma_playback->dma_size = 4; + i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); if (IS_ERR(i2s->iis_cclk)) { dev_err(&pdev->dev, "failed to get audio-bus\n"); -- GitLab From 7c4e6492205b677a5786b85bcf72ce7c8f4adf15 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Wed, 9 Dec 2009 12:05:50 +0200 Subject: [PATCH 0046/3892] ASoC: tpa6130a2: Add support for regulator framework Take the regulator framework in use for managing the power sources Signed-off-by: Ilkka Koskinen Acked-by: Peter Ujfalusi Acked-by: Eduardo Valentin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 87 +++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6b650c1aa3d1..0eb33d49942e 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,10 +35,17 @@ static struct i2c_client *tpa6130a2_client; +#define TPA6130A2_NUM_SUPPLIES 2 +static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { + "CPVSS", + "Vdd", +}; + /* This struct is used to save the context */ struct tpa6130a2_data { struct mutex mutex; unsigned char regs[TPA6130A2_CACHEREGNUM]; + struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; int power_gpio; unsigned char power_state; }; @@ -106,10 +114,11 @@ static void tpa6130a2_initialize(void) tpa6130a2_i2c_write(i, data->regs[i]); } -static void tpa6130a2_power(int power) +static int tpa6130a2_power(int power) { struct tpa6130a2_data *data; u8 val; + int ret; BUG_ON(tpa6130a2_client == NULL); data = i2c_get_clientdata(tpa6130a2_client); @@ -117,11 +126,20 @@ static void tpa6130a2_power(int power) mutex_lock(&data->mutex); if (power) { /* Power on */ - if (data->power_gpio >= 0) { + if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 1); - data->power_state = 1; - tpa6130a2_initialize(); + + ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), + data->supplies); + if (ret != 0) { + dev_err(&tpa6130a2_client->dev, + "Failed to enable supplies: %d\n", ret); + goto exit; } + + data->power_state = 1; + tpa6130a2_initialize(); + /* Clear SWS */ val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val &= ~TPA6130A2_SWS; @@ -131,13 +149,25 @@ static void tpa6130a2_power(int power) val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val |= TPA6130A2_SWS; tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); + /* Power off */ - if (data->power_gpio >= 0) { + if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 0); - data->power_state = 0; + + ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), + data->supplies); + if (ret != 0) { + dev_err(&tpa6130a2_client->dev, + "Failed to disable supplies: %d\n", ret); + goto exit; } + + data->power_state = 0; } + +exit: mutex_unlock(&data->mutex); + return ret; } static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, @@ -299,15 +329,17 @@ static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w, static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + int ret = 0; + switch (event) { case SND_SOC_DAPM_POST_PMU: - tpa6130a2_power(1); + ret = tpa6130a2_power(1); break; case SND_SOC_DAPM_POST_PMD: - tpa6130a2_power(0); + ret = tpa6130a2_power(0); break; } - return 0; + return ret; } static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { @@ -352,7 +384,7 @@ static int tpa6130a2_probe(struct i2c_client *client, struct device *dev; struct tpa6130a2_data *data; struct tpa6130a2_platform_data *pdata; - int ret; + int i, ret; dev = &client->dev; @@ -387,15 +419,25 @@ static int tpa6130a2_probe(struct i2c_client *client, if (ret < 0) { dev_err(dev, "Failed to request power GPIO (%d)\n", data->power_gpio); - goto fail; + goto err_gpio; } gpio_direction_output(data->power_gpio, 0); - } else { - data->power_state = 1; - tpa6130a2_initialize(); } - tpa6130a2_power(1); + for (i = 0; i < ARRAY_SIZE(data->supplies); i++) + data->supplies[i].supply = tpa6130a2_supply_names[i]; + + ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), + data->supplies); + if (ret != 0) { + dev_err(dev, "Failed to request supplies: %d\n", ret); + goto err_regulator; + } + + ret = tpa6130a2_power(1); + if (ret != 0) + goto err_power; + /* Read version */ ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & @@ -404,10 +446,18 @@ static int tpa6130a2_probe(struct i2c_client *client, dev_warn(dev, "UNTESTED version detected (%d)\n", ret); /* Disable the chip */ - tpa6130a2_power(0); + ret = tpa6130a2_power(0); + if (ret != 0) + goto err_power; return 0; -fail: + +err_power: + regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); +err_regulator: + if (data->power_gpio >= 0) + gpio_free(data->power_gpio); +err_gpio: kfree(data); i2c_set_clientdata(tpa6130a2_client, NULL); tpa6130a2_client = NULL; @@ -423,6 +473,9 @@ static int tpa6130a2_remove(struct i2c_client *client) if (data->power_gpio >= 0) gpio_free(data->power_gpio); + + regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); + kfree(data); tpa6130a2_client = NULL; -- GitLab From 98615454f66175e923f239ab1d1bd85cd618363e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 14 Dec 2009 13:21:56 +0900 Subject: [PATCH 0047/3892] ASoC: Add DA7210 codec device support for ALSA This original driver was created by Dialog Semiconductor, and cleanuped by Kuninori Morimoto. Special thanks to David Chen. This became very simple ASoC codec driver, and it is tested by EcoVec24 board. Signed-off-by: David Chen Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/da7210.c | 586 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/da7210.h | 24 ++ 4 files changed, 616 insertions(+) create mode 100644 sound/soc/codecs/da7210.c create mode 100644 sound/soc/codecs/da7210.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 011d3ab7e64a..691abe7df087 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4671 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_MAX9877 if I2C + select SND_SOC_DA7210 if I2C select SND_SOC_PCM3008 select SND_SOC_SPDIF select SND_SOC_SSM2602 if I2C @@ -113,6 +114,9 @@ config SND_SOC_AK4671 config SND_SOC_CS4270 tristate +config SND_SOC_DA7210 + tristate + # Cirrus Logic CS4270 Codec VD = 3.3V Errata # Select if you are affected by the errata where the part will not function # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0471d9044205..b328f293be65 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -10,6 +10,7 @@ snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o snd-soc-cs4270-objs := cs4270.o snd-soc-cx20442-objs := cx20442.o +snd-soc-da7210-objs := da7210.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-spdif-objs := spdif_transciever.o @@ -67,6 +68,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o +obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c new file mode 100644 index 000000000000..14f5f344b1d5 --- /dev/null +++ b/sound/soc/codecs/da7210.c @@ -0,0 +1,586 @@ +/* + * DA7210 ALSA Soc codec driver + * + * Copyright (c) 2009 Dialog Semiconductor + * Written by David Chen + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Cleanups by Kuninori Morimoto + * + * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "da7210.h" + +/* DA7210 register space */ +#define DA7210_STATUS 0x02 +#define DA7210_STARTUP1 0x03 +#define DA7210_MIC_L 0x07 +#define DA7210_MIC_R 0x08 +#define DA7210_INMIX_L 0x0D +#define DA7210_INMIX_R 0x0E +#define DA7210_ADC_HPF 0x0F +#define DA7210_ADC 0x10 +#define DA7210_DAC_HPF 0x14 +#define DA7210_DAC_L 0x15 +#define DA7210_DAC_R 0x16 +#define DA7210_DAC_SEL 0x17 +#define DA7210_OUTMIX_L 0x1C +#define DA7210_OUTMIX_R 0x1D +#define DA7210_HP_L_VOL 0x21 +#define DA7210_HP_R_VOL 0x22 +#define DA7210_HP_CFG 0x23 +#define DA7210_DAI_SRC_SEL 0x25 +#define DA7210_DAI_CFG1 0x26 +#define DA7210_DAI_CFG3 0x28 +#define DA7210_PLL_DIV3 0x2B +#define DA7210_PLL 0x2C + +/* STARTUP1 bit fields */ +#define DA7210_SC_MST_EN (1 << 0) + +/* MIC_L bit fields */ +#define DA7210_MICBIAS_EN (1 << 6) +#define DA7210_MIC_L_EN (1 << 7) + +/* MIC_R bit fields */ +#define DA7210_MIC_R_EN (1 << 7) + +/* INMIX_L bit fields */ +#define DA7210_IN_L_EN (1 << 7) + +/* INMIX_R bit fields */ +#define DA7210_IN_R_EN (1 << 7) + +/* ADC_HPF bit fields */ +#define DA7210_ADC_VOICE_EN (1 << 7) + +/* ADC bit fields */ +#define DA7210_ADC_L_EN (1 << 3) +#define DA7210_ADC_R_EN (1 << 7) + +/* DAC_SEL bit fields */ +#define DA7210_DAC_L_SRC_DAI_L (4 << 0) +#define DA7210_DAC_L_EN (1 << 3) +#define DA7210_DAC_R_SRC_DAI_R (5 << 4) +#define DA7210_DAC_R_EN (1 << 7) + +/* OUTMIX_L bit fields */ +#define DA7210_OUT_L_EN (1 << 7) + +/* OUTMIX_R bit fields */ +#define DA7210_OUT_R_EN (1 << 7) + +/* HP_CFG bit fields */ +#define DA7210_HP_2CAP_MODE (1 << 1) +#define DA7210_HP_SENSE_EN (1 << 2) +#define DA7210_HP_L_EN (1 << 3) +#define DA7210_HP_MODE (1 << 6) +#define DA7210_HP_R_EN (1 << 7) + +/* DAI_SRC_SEL bit fields */ +#define DA7210_DAI_OUT_L_SRC (6 << 0) +#define DA7210_DAI_OUT_R_SRC (7 << 4) + +/* DAI_CFG1 bit fields */ +#define DA7210_DAI_WORD_S16_LE (0 << 0) +#define DA7210_DAI_WORD_S24_LE (2 << 0) +#define DA7210_DAI_FLEN_64BIT (1 << 2) +#define DA7210_DAI_MODE_MASTER (1 << 7) + +/* DAI_CFG3 bit fields */ +#define DA7210_DAI_FORMAT_I2SMODE (0 << 0) +#define DA7210_DAI_OE (1 << 3) +#define DA7210_DAI_EN (1 << 7) + +/*PLL_DIV3 bit fields */ +#define DA7210_MCLK_RANGE_10_20_MHZ (1 << 4) +#define DA7210_PLL_BYP (1 << 6) + +/* PLL bit fields */ +#define DA7210_PLL_FS_48000 (11 << 0) + +#define DA7210_VERSION "0.0.1" + +/* Codec private data */ +struct da7210_priv { + struct snd_soc_codec codec; +}; + +static struct snd_soc_codec *da7210_codec; + +/* + * Register cache + */ +static const u8 da7210_reg[] = { + 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R0 - R7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* R8 - RF */ + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54, /* R10 - R17 */ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R18 - R1F */ + 0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, /* R20 - R27 */ + 0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00, /* R28 - R2F */ + 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, /* R30 - R37 */ + 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, /* R38 - R3F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R40 - R4F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R48 - R4F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R50 - R57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R58 - R5F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R60 - R67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R68 - R6F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R70 - R77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00, /* R78 - R7F */ + 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* R80 - R87 */ + 0x00, /* R88 */ +}; + +/* + * Read da7210 register cache + */ +static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg) +{ + u8 *cache = codec->reg_cache; + BUG_ON(reg > ARRAY_SIZE(da7210_reg)); + return cache[reg]; +} + +/* + * Write to the da7210 register space + */ +static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value) +{ + u8 *cache = codec->reg_cache; + u8 data[2]; + + BUG_ON(codec->volatile_register); + + data[0] = reg & 0xff; + data[1] = value & 0xff; + + if (reg >= codec->reg_cache_size) + return -EIO; + + if (2 != codec->hw_write(codec->control_data, data, 2)) + return -EIO; + + cache[reg] = value; + return 0; +} + +/* + * Read from the da7210 register space. + */ +static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg) +{ + if (DA7210_STATUS == reg) + return i2c_smbus_read_byte_data(codec->control_data, reg); + + return da7210_read_reg_cache(codec, reg); +} + +static int da7210_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_codec *codec = dai->codec; + + if (is_play) { + /* PlayBack Volume 40 */ + snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40); + snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40); + + /* Enable Out */ + snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); + snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); + + } else { + /* Volume 7 */ + snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7); + snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7); + + /* Enable Mic */ + snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1); + snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1); + } + + return 0; +} + +/* + * Set PCM DAI word length. + */ +static int da7210_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + u32 dai_cfg1; + u32 reg, mask; + + /* set DAI source to Left and Right ADC */ + da7210_write(codec, DA7210_DAI_SRC_SEL, + DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC); + + /* Enable DAI */ + da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN); + + dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dai_cfg1 |= DA7210_DAI_WORD_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dai_cfg1 |= DA7210_DAI_WORD_S24_LE; + break; + default: + return -EINVAL; + } + + da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); + + /* FIXME + * + * It support 48K only now + */ + switch (params_rate(params)) { + case 48000: + if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { + reg = DA7210_DAC_HPF; + mask = DA7210_DAC_VOICE_EN; + } else { + reg = DA7210_ADC_HPF; + mask = DA7210_ADC_VOICE_EN; + } + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, reg, mask, 0); + + return 0; +} + +/* + * Set DAI mode and Format + */ +static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 dai_cfg1; + u32 dai_cfg3; + + dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1); + dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + dai_cfg1 |= DA7210_DAI_MODE_MASTER; + break; + default: + return -EINVAL; + } + + /* FIXME + * + * It support I2S only now + */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE; + break; + default: + return -EINVAL; + } + + /* FIXME + * + * It support 64bit data transmission only now + */ + dai_cfg1 |= DA7210_DAI_FLEN_64BIT; + + da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); + da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3); + + return 0; +} + +#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +/* DAI operations */ +static struct snd_soc_dai_ops da7210_dai_ops = { + .startup = da7210_startup, + .hw_params = da7210_hw_params, + .set_fmt = da7210_set_dai_fmt, +}; + +struct snd_soc_dai da7210_dai = { + .name = "DA7210 IIS", + .id = 0, + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7210_FORMATS, + }, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7210_FORMATS, + }, + .ops = &da7210_dai_ops, +}; +EXPORT_SYMBOL_GPL(da7210_dai); + +/* + * Initialize the DA7210 driver + * register the mixer and dsp interfaces with the kernel + */ +static int da7210_init(struct da7210_priv *da7210) +{ + struct snd_soc_codec *codec = &da7210->codec; + int ret = 0; + + if (da7210_codec) { + dev_err(codec->dev, "Another da7210 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = da7210; + codec->name = "DA7210"; + codec->owner = THIS_MODULE; + codec->read = da7210_read; + codec->write = da7210_write; + codec->dai = &da7210_dai; + codec->num_dai = 1; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->reg_cache_size = ARRAY_SIZE(da7210_reg); + codec->reg_cache = kmemdup(da7210_reg, + sizeof(da7210_reg), GFP_KERNEL); + + if (!codec->reg_cache) + return -ENOMEM; + + da7210_dai.dev = codec->dev; + da7210_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register CODEC: %d\n", ret); + goto init_err; + } + + ret = snd_soc_register_dai(&da7210_dai); + if (ret) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + goto init_err; + } + + /* FIXME + * + * This driver use fixed value here + */ + + /* + * ADC settings + */ + + /* Enable Left & Right MIC PGA and Mic Bias */ + da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN); + da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN); + + /* Enable Left and Right input PGA */ + da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN); + da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN); + + /* Enable Left and Right ADC */ + da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN); + + /* + * DAC settings + */ + + /* Enable Left and Right DAC */ + da7210_write(codec, DA7210_DAC_SEL, + DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN | + DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN); + + /* Enable Left and Right out PGA */ + da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN); + da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN); + + /* Enable Left and Right HeadPhone PGA */ + da7210_write(codec, DA7210_HP_CFG, + DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN | + DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN); + + /* Diable PLL and bypass it */ + da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000); + + /* Bypass PLL and set MCLK freq rang to 10-20MHz */ + da7210_write(codec, DA7210_PLL_DIV3, + DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP); + + /* Activate all enabled subsystem */ + da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN); + + return ret; + +init_err: + kfree(codec->reg_cache); + codec->reg_cache = NULL; + + return ret; + +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static int da7210_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da7210_priv *da7210; + struct snd_soc_codec *codec; + int ret; + + da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL); + if (!da7210) + return -ENOMEM; + + codec = &da7210->codec; + codec->dev = &i2c->dev; + + i2c_set_clientdata(i2c, da7210); + codec->control_data = i2c; + + ret = da7210_init(da7210); + if (ret < 0) + pr_err("Failed to initialise da7210 audio codec\n"); + + return ret; +} + +static int da7210_i2c_remove(struct i2c_client *client) +{ + struct da7210_priv *da7210 = i2c_get_clientdata(client); + + snd_soc_unregister_dai(&da7210_dai); + kfree(da7210->codec.reg_cache); + kfree(da7210); + da7210_codec = NULL; + + return 0; +} + +static const struct i2c_device_id da7210_i2c_id[] = { + { "da7210", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7210_i2c_id); + +/* I2C codec control layer */ +static struct i2c_driver da7210_i2c_driver = { + .driver = { + .name = "DA7210 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = da7210_i2c_probe, + .remove = __devexit_p(da7210_i2c_remove), + .id_table = da7210_i2c_id, +}; +#endif + +static int da7210_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret; + + if (!da7210_codec) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = da7210_codec; + codec = da7210_codec; + + /* Register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) + goto pcm_err; + + dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); + +pcm_err: + return ret; +} + +static int da7210_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_da7210 = { + .probe = da7210_probe, + .remove = da7210_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_da7210); + +static int __init da7210_modinit(void) +{ + int ret = 0; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&da7210_i2c_driver); +#endif + return ret; +} +module_init(da7210_modinit); + +static void __exit da7210_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&da7210_i2c_driver); +#endif +} +module_exit(da7210_exit); + +MODULE_DESCRIPTION("ASoC DA7210 driver"); +MODULE_AUTHOR("David Chen, Kuninori Morimoto"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h new file mode 100644 index 000000000000..390d621eb742 --- /dev/null +++ b/sound/soc/codecs/da7210.h @@ -0,0 +1,24 @@ +/* + * da7210.h -- audio driver for da7210 + * + * Copyright (c) 2009 Dialog Semiconductor + * Written by David Chen + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Cleanups by Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _DA7210_H +#define _DA7210_H + +extern struct snd_soc_dai da7210_dai; +extern struct snd_soc_codec_device soc_codec_dev_da7210; + +#endif + -- GitLab From 038494059f795849012a96adba2ab73e65b94ba5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 14 Dec 2009 13:22:00 +0900 Subject: [PATCH 0048/3892] ASoC: Add FSI-DA7210 sound support for SuperH Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 8 ++++ sound/soc/sh/Makefile | 2 + sound/soc/sh/fsi-da7210.c | 83 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 sound/soc/sh/fsi-da7210.c diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 9e6976586554..8072a6d1c4db 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -47,4 +47,12 @@ config SND_FSI_AK4642 This option enables generic sound support for the FSI - AK4642 unit +config SND_FSI_DA7210 + bool "FSI-DA7210 sound support" + depends on SND_SOC_SH4_FSI + select SND_SOC_DA7210 + help + This option enables generic sound support for the + FSI - DA7210 unit + endmenu diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index a6997872f24e..1d0ec0af74b7 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o ## boards snd-soc-sh7760-ac97-objs := sh7760-ac97.o snd-soc-fsi-ak4642-objs := fsi-ak4642.o +snd-soc-fsi-da7210-objs := fsi-da7210.o obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o +obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c new file mode 100644 index 000000000000..33b4d177f466 --- /dev/null +++ b/sound/soc/sh/fsi-da7210.c @@ -0,0 +1,83 @@ +/* + * fsi-da7210.c + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../codecs/da7210.h" + +static int fsi_da7210_init(struct snd_soc_codec *codec) +{ + return snd_soc_dai_set_fmt(&da7210_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); +} + +static struct snd_soc_dai_link fsi_da7210_dai = { + .name = "DA7210", + .stream_name = "DA7210", + .cpu_dai = &fsi_soc_dai[1], /* FSI B */ + .codec_dai = &da7210_dai, + .init = fsi_da7210_init, +}; + +static struct snd_soc_card fsi_soc_card = { + .name = "FSI", + .platform = &fsi_soc_platform, + .dai_link = &fsi_da7210_dai, + .num_links = 1, +}; + +static struct snd_soc_device fsi_da7210_snd_devdata = { + .card = &fsi_soc_card, + .codec_dev = &soc_codec_dev_da7210, +}; + +static struct platform_device *fsi_da7210_snd_device; + +static int __init fsi_da7210_sound_init(void) +{ + int ret; + + fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1); + if (!fsi_da7210_snd_device) + return -ENOMEM; + + platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata); + fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev; + ret = platform_device_add(fsi_da7210_snd_device); + if (ret) + platform_device_put(fsi_da7210_snd_device); + + return ret; +} + +static void __exit fsi_da7210_sound_exit(void) +{ + platform_device_unregister(fsi_da7210_snd_device); +} + +module_init(fsi_da7210_sound_init); +module_exit(fsi_da7210_sound_exit); + +/* Module information */ +MODULE_DESCRIPTION("ALSA SoC FSI DA2710"); +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_LICENSE("GPL"); -- GitLab From 3497b91946a3df42830c826939424d98251a3b0d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 15 Dec 2009 20:58:56 +0000 Subject: [PATCH 0049/3892] ASoC: Fix sorting of codecs Makefile entries Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b328f293be65..c0fd3c86edad 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -96,11 +96,11 @@ obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o -obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o -obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o +obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o +obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o -- GitLab From 255173b40db448ce063a2caa680a552fb637ad20 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Mon, 14 Dec 2009 14:44:56 +0100 Subject: [PATCH 0050/3892] ASoC: PLL computation in TLV320AIC3x SoC driver fix precision of PLL computation for TLV320AIC3x SoC driver, test results are at http://pmeerw.net/clk Signed-off-by: Peter Meerwald Acked-by: Vladimir Barinov Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 75 ++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 2b4dc2b0b017..5a8f53ce2250 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -765,9 +765,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct aic3x_priv *aic3x = codec->private_data; int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; - u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; - u16 pll_d = 1; + u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; + u16 d, pll_d = 1; u8 reg; + int clk; /* select data word length */ data = @@ -833,48 +834,70 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, if (bypass_pll) return 0; - /* Use PLL - * find an apropriate setup for j, d, r and p by iterating over - * p and r - j and d are calculated for each fraction. - * Up to 128 values are probed, the closest one wins the game. + /* Use PLL, compute apropriate setup for j, d, r and p, the closest + * one wins the game. Try with d==0 first, next with d!=0. + * Constraints for j are according to the datasheet. * The sysclk is divided by 1000 to prevent integer overflows. */ + codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); for (r = 1; r <= 16; r++) for (p = 1; p <= 8; p++) { - int clk, tmp = (codec_clk * pll_r * 10) / pll_p; - u8 j = tmp / 10000; - u16 d = tmp % 10000; + for (j = 4; j <= 55; j++) { + /* This is actually 1000*((j+(d/10000))*r)/p + * The term had to be converted to get + * rid of the division by 10000; d = 0 here + */ + int clk = (1000 * j * r) / p; + + /* Check whether this values get closer than + * the best ones we had before + */ + if (abs(codec_clk - clk) < + abs(codec_clk - last_clk)) { + pll_j = j; pll_d = 0; + pll_r = r; pll_p = p; + last_clk = clk; + } + + /* Early exit for exact matches */ + if (clk == codec_clk) + goto found; + } + } - if (j > 63) - continue; + /* try with d != 0 */ + for (p = 1; p <= 8; p++) { + j = codec_clk * p / 1000; - if (d != 0 && aic3x->sysclk < 10000000) - continue; + if (j < 4 || j > 11) + continue; - /* This is actually 1000 * ((j + (d/10000)) * r) / p - * The term had to be converted to get rid of the - * division by 10000 */ - clk = ((10000 * j * r) + (d * r)) / (10 * p); + /* do not use codec_clk here since we'd loose precision */ + d = ((2048 * p * fsref) - j * aic3x->sysclk) + * 100 / (aic3x->sysclk/100); - /* check whether this values get closer than the best - * ones we had before */ - if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { - pll_j = j; pll_d = d; pll_r = r; pll_p = p; - last_clk = clk; - } + clk = (10000 * j + d) / (10 * p); - /* Early exit for exact matches */ - if (clk == codec_clk) - break; + /* check whether this values get closer than the best + * ones we had before */ + if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { + pll_j = j; pll_d = d; pll_r = 1; pll_p = p; + last_clk = clk; } + /* Early exit for exact matches */ + if (clk == codec_clk) + goto found; + } + if (last_clk == 0) { printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); return -EINVAL; } +found: data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); -- GitLab From c2151433847e88ba05c6bb539d9397ea90d755e6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 16 Dec 2009 20:36:37 +0000 Subject: [PATCH 0051/3892] ASoC: Fix build of DA7210 DAC_VOICE_EN was not defined - looks to have been overly enthusiastically deleted from a previous revision of the patch, pull the value from v1. Signed-off-by: Mark Brown --- sound/soc/codecs/da7210.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 14f5f344b1d5..fbf3ab482015 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -81,6 +81,9 @@ #define DA7210_ADC_L_EN (1 << 3) #define DA7210_ADC_R_EN (1 << 7) +/* DAC_HPF fields */ +#define DA7210_DAC_VOICE_EN (1 << 7) + /* DAC_SEL bit fields */ #define DA7210_DAC_L_SRC_DAI_L (4 << 0) #define DA7210_DAC_L_EN (1 << 3) -- GitLab From b73c806341cfc7492ede6a2ce713cb579547d0ab Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 25 Nov 2009 22:00:08 +0000 Subject: [PATCH 0052/3892] sh: Abstract the number of page table levels Keep the dimensions of the page tables in a separate header file in preparation for allowing a three level page table structure. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/include/asm/pgalloc.h | 24 +++-------------------- arch/sh/include/asm/pgalloc_nopmd.h | 30 +++++++++++++++++++++++++++++ arch/sh/include/asm/pgtable.h | 18 +---------------- arch/sh/include/asm/pgtable_nopmd.h | 22 +++++++++++++++++++++ 4 files changed, 56 insertions(+), 38 deletions(-) create mode 100644 arch/sh/include/asm/pgalloc_nopmd.h create mode 100644 arch/sh/include/asm/pgtable_nopmd.h diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h index 63ca37bd9a95..fe9f037ac5fd 100644 --- a/arch/sh/include/asm/pgalloc.h +++ b/arch/sh/include/asm/pgalloc.h @@ -4,9 +4,10 @@ #include #include -#define QUICK_PGD 0 /* We preserve special mappings over free */ #define QUICK_PT 1 /* Other page table pages that are zero on free */ +#include + static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) { @@ -20,28 +21,9 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, } #define pmd_pgtable(pmd) pmd_page(pmd) -static inline void pgd_ctor(void *x) -{ - pgd_t *pgd = x; - - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); -} - /* * Allocate and free page tables. */ -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor); -} - -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - quicklist_free(QUICK_PGD, NULL, pgd); -} - static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { @@ -81,7 +63,7 @@ do { \ static inline void check_pgt_cache(void) { - quicklist_trim(QUICK_PGD, NULL, 25, 16); + __check_pgt_cache(); quicklist_trim(QUICK_PT, NULL, 25, 16); } diff --git a/arch/sh/include/asm/pgalloc_nopmd.h b/arch/sh/include/asm/pgalloc_nopmd.h new file mode 100644 index 000000000000..e4b344c37e74 --- /dev/null +++ b/arch/sh/include/asm/pgalloc_nopmd.h @@ -0,0 +1,30 @@ +#ifndef __ASM_SH_PGALLOC_NOPMD_H +#define __ASM_SH_PGALLOC_NOPMD_H + +#define QUICK_PGD 0 /* We preserve special mappings over free */ + +static inline void pgd_ctor(void *x) +{ + pgd_t *pgd = x; + + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); +} + +static inline pgd_t *pgd_alloc(struct mm_struct *mm) +{ + return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor); +} + +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + quicklist_free(QUICK_PGD, NULL, pgd); +} + +static inline void __check_pgt_cache(void) +{ + quicklist_trim(QUICK_PGD, NULL, 25, 16); +} + +#endif /* __ASM_SH_PGALLOC_NOPMD_H */ diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index ba3046e4f06f..9a0f66c1134c 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -12,7 +12,7 @@ #ifndef __ASM_SH_PGTABLE_H #define __ASM_SH_PGTABLE_H -#include +#include #include #ifndef __ASSEMBLY__ @@ -51,28 +51,12 @@ static inline unsigned long long neff_sign_extend(unsigned long val) #define NPHYS_SIGN (1LL << (NPHYS - 1)) #define NPHYS_MASK (-1LL << NPHYS) -/* - * traditional two-level paging structure - */ -/* PTE bits */ -#if defined(CONFIG_X2TLB) || defined(CONFIG_SUPERH64) -# define PTE_MAGNITUDE 3 /* 64-bit PTEs on extended mode SH-X2 TLB */ -#else -# define PTE_MAGNITUDE 2 /* 32-bit PTEs */ -#endif -#define PTE_SHIFT PAGE_SHIFT -#define PTE_BITS (PTE_SHIFT - PTE_MAGNITUDE) - -/* PGD bits */ -#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) /* Entries per level */ #define PTRS_PER_PTE (PAGE_SIZE / (1 << PTE_MAGNITUDE)) -#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t)) -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_ADDRESS 0 #define PHYS_ADDR_MASK29 0x1fffffff diff --git a/arch/sh/include/asm/pgtable_nopmd.h b/arch/sh/include/asm/pgtable_nopmd.h new file mode 100644 index 000000000000..f0b525b3cb4a --- /dev/null +++ b/arch/sh/include/asm/pgtable_nopmd.h @@ -0,0 +1,22 @@ +#ifndef __ASM_SH_PGTABLE_NOPMD_H +#define __ASM_SH_PGTABLE_NOPMD_H + +#include + +/* + * traditional two-level paging structure + */ + +/* PTE bits */ +#define PTE_MAGNITUDE 2 /* 32-bit PTEs */ + +#define PTE_SHIFT PAGE_SHIFT +#define PTE_BITS (PTE_SHIFT - PTE_MAGNITUDE) + +/* PGD bits */ +#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) + +#define PTRS_PER_PGD (PAGE_SIZE / (1 << PTE_MAGNITUDE)) +#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) + +#endif /* __ASM_SH_PGTABLE_NOPMD_H */ -- GitLab From 5d9b4b19f118abfb75e352841f7bf74580d7e427 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 13 Dec 2009 14:38:50 +0000 Subject: [PATCH 0053/3892] sh: Definitions for 3-level page table layout If using 64-bit PTEs and 4K pages then each page table has 512 entries (as opposed to 1024 entries with 32-bit PTEs). Unlike MIPS, SH follows the convention that all structures in the page table (pgd_t, pmd_t, pgprot_t, etc) must be the same size. Therefore, 64-bit PTEs require 64-bit PGD entries, etc. Using 2-levels of page tables and 64-bit PTEs it is only possible to map 1GB of virtual address space. In order to map all 4GB of virtual address space we need to adopt a 3-level page table layout. This actually works out better for CONFIG_SUPERH32 because we only waste 2 PGD entries on the P1 and P2 areas (which are untranslated) instead of 256. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/include/asm/pgalloc.h | 4 +++ arch/sh/include/asm/pgalloc_pmd.h | 41 +++++++++++++++++++++++ arch/sh/include/asm/pgtable.h | 4 +++ arch/sh/include/asm/pgtable_pmd.h | 55 +++++++++++++++++++++++++++++++ arch/sh/mm/Kconfig | 24 ++++++++++++-- arch/sh/mm/fault_32.c | 3 ++ arch/sh/mm/init.c | 6 ++++ 7 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 arch/sh/include/asm/pgalloc_pmd.h create mode 100644 arch/sh/include/asm/pgtable_pmd.h diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h index fe9f037ac5fd..4ea27855c3b5 100644 --- a/arch/sh/include/asm/pgalloc.h +++ b/arch/sh/include/asm/pgalloc.h @@ -6,7 +6,11 @@ #define QUICK_PT 1 /* Other page table pages that are zero on free */ +#ifdef CONFIG_PGTABLE_LEVELS_3 +#include +#else #include +#endif static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) diff --git a/arch/sh/include/asm/pgalloc_pmd.h b/arch/sh/include/asm/pgalloc_pmd.h new file mode 100644 index 000000000000..20f75cc4eb09 --- /dev/null +++ b/arch/sh/include/asm/pgalloc_pmd.h @@ -0,0 +1,41 @@ +#ifndef __ASM_SH_PGALLOC_PMD_H +#define __ASM_SH_PGALLOC_PMD_H + +static inline pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *pgd; + int i; + + pgd = kzalloc(sizeof(*pgd) * PTRS_PER_PGD, GFP_KERNEL | __GFP_REPEAT); + + for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) + pgd[i] = swapper_pg_dir[i]; + + return pgd; +} + +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + kfree(pgd); +} + +static inline void __check_pgt_cache(void) +{ +} + +static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + set_pud(pud, __pud((unsigned long)pmd)); +} + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); +} + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) +{ + quicklist_free(QUICK_PT, NULL, pmd); +} + +#endif /* __ASM_SH_PGALLOC_PMD_H */ diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 9a0f66c1134c..9effcc3b0d10 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -12,7 +12,11 @@ #ifndef __ASM_SH_PGTABLE_H #define __ASM_SH_PGTABLE_H +#ifdef CONFIG_PGTABLE_LEVELS_3 +#include +#else #include +#endif #include #ifndef __ASSEMBLY__ diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable_pmd.h new file mode 100644 index 000000000000..78dc36e1c2dd --- /dev/null +++ b/arch/sh/include/asm/pgtable_pmd.h @@ -0,0 +1,55 @@ +#ifndef __ASM_SH_PGTABLE_PMD_H +#define __ASM_SH_PGTABLE_PMD_H + +#include + +/* + * Some cores need a 3-level page table layout, for example when using + * 64-bit PTEs and 4K pages. + */ + +#define PTE_MAGNITUDE 3 /* 64-bit PTEs on extended mode SH-X2 TLB */ + +/* PGD bits */ +#define PGDIR_SHIFT 30 + +#define PTRS_PER_PGD 4 +#define USER_PTRS_PER_PGD 2 + +/* PMD bits */ +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t)) + +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e)) + +typedef struct { unsigned long long pmd; } pmd_t; +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) + +static inline unsigned long pud_page_vaddr(pud_t pud) +{ + return pud_val(pud); +} + +#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) +{ + return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address); +} + +#define pud_none(x) (!pud_val(x)) +#define pud_present(x) (pud_val(x)) +#define pud_clear(xp) do { set_pud(xp, __pud(0)); } while (0) +#define pud_bad(x) (pud_val(x) & ~PAGE_MASK) + +/* + * (puds are folded into pgds so this doesn't get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while(0) + +#endif /* __ASM_SH_PGTABLE_PMD_H */ diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 0e7ba8e891cf..b3f6c1a30b22 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -189,6 +189,24 @@ config ARCH_MEMORY_PROBE def_bool y depends on MEMORY_HOTPLUG +choice + prompt "Page table layout" + default PGTABLE_LEVELS_3 if X2TLB + default PGTABLE_LEVELS_2 + +config PGTABLE_LEVELS_2 + bool "2 Levels" + help + This is the default page table layout for all SuperH CPUs. + +config PGTABLE_LEVELS_3 + bool "3 Levels" + depends on X2TLB + help + This enables a 3 level page table structure. + +endchoice + choice prompt "Kernel page size" default PAGE_SIZE_8KB if X2TLB @@ -196,13 +214,13 @@ choice config PAGE_SIZE_4KB bool "4kB" - depends on !MMU || !X2TLB + depends on !MMU || !X2TLB || PGTABLE_LEVELS_3 help This is the default page size used by all SuperH CPUs. config PAGE_SIZE_8KB bool "8kB" - depends on !MMU || X2TLB + depends on !MMU || X2TLB && !PGTABLE_LEVELS_3 help This enables 8kB pages as supported by SH-X2 and later MMUs. @@ -214,7 +232,7 @@ config PAGE_SIZE_16KB config PAGE_SIZE_64KB bool "64kB" - depends on !MMU || CPU_SH4 || CPU_SH5 + depends on !MMU || CPU_SH4 && !PGTABLE_LEVELS_3 || CPU_SH5 help This enables support for 64kB pages, possible on all SH-4 CPUs and later. diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 47530104e0ad..28e22839c665 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -53,6 +53,9 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) if (!pud_present(*pud_k)) return NULL; + if (!pud_present(*pud)) + set_pud(pud, *pud_k); + pmd = pmd_offset(pud, address); pmd_k = pmd_offset(pud_k, address); if (!pmd_present(*pmd_k)) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 432acd07e76a..761910d142f8 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -120,7 +120,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end, for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { pud = (pud_t *)pgd; for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { +#ifdef __PAGETABLE_PMD_FOLDED pmd = (pmd_t *)pud; +#else + pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); + pud_populate(&init_mm, pud, pmd); + pmd += k; +#endif for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { if (pmd_none(*pmd)) { pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); -- GitLab From 6c941c8556dd9269be621cd8159fc60e955a91b3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 16 Dec 2009 16:15:00 +0100 Subject: [PATCH 0054/3892] ALSA: Release v1.0.22 Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index 22939142dd23..1f5d4872d623 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.21" +#define CONFIG_SND_VERSION "1.0.22" #define CONFIG_SND_DATE "" -- GitLab From d1409ae4cecb4af260759bdfdf88fafca23a9940 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2009 15:01:31 +0100 Subject: [PATCH 0055/3892] ALSA: hda - Fix NULL dereference in kctl-NID mapping in patch_realtek.c capsrc_nids can be NULL, and adc_nids should be taken as fallback. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 36556b10357a..012435212e58 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2517,7 +2517,10 @@ static int alc_build_controls(struct hda_codec *codec) if (!kctl) kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, + hda_nid_t *nids = spec->capsrc_nids; + if (!nids) + nids = spec->adc_nids; + err = snd_hda_add_nids(codec, kctl, i, nids, spec->input_mux->num_items); if (err < 0) return err; -- GitLab From b76365a18f7593c9df32a74bf2b4a39741b67bc6 Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Thu, 17 Dec 2009 10:53:25 -0600 Subject: [PATCH 0056/3892] x86, uv: Add serial number parameter to uv_bios_get_sn_info() Add system_serial_number to the information returned by uv_bios_get_sn_info() UV BIOS call. Signed-off-by: Russ Anderson LKML-Reference: <20091217165323.GA30774@sgi.com> Cc: Jack Steiner Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/uv/bios.h | 7 ++++--- arch/x86/kernel/apic/x2apic_uv_x.c | 6 +++--- arch/x86/kernel/bios_uv.c | 20 ++++++++++++++------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/uv/bios.h b/arch/x86/include/asm/uv/bios.h index 2751f3075d8b..3fbc1f348a7d 100644 --- a/arch/x86/include/asm/uv/bios.h +++ b/arch/x86/include/asm/uv/bios.h @@ -18,8 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (c) Russ Anderson + * Copyright (c) 2008-2009 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Russ Anderson */ #include @@ -89,7 +89,7 @@ extern s64 uv_bios_call(enum uv_bios_cmd, u64, u64, u64, u64, u64); extern s64 uv_bios_call_irqsave(enum uv_bios_cmd, u64, u64, u64, u64, u64); 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_get_sn_info(int, int *, long *, long *, long *, long *); extern s64 uv_bios_freq_base(u64, u64 *); extern int uv_bios_mq_watchlist_alloc(unsigned long, unsigned int, unsigned long *); @@ -104,6 +104,7 @@ extern int uv_type; extern long sn_partition_id; extern long sn_coherency_id; extern long sn_region_size; +extern long system_serial_number; #define partition_coherence_id() (sn_coherency_id) extern struct kobject *sgi_uv_kobj; /* /sys/firmware/sgi_uv */ diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index b684bb303cbf..af5d103bb533 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -5,7 +5,7 @@ * * SGI UV APIC functions (note: not an Intel compatible APIC) * - * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2009 Silicon Graphics, Inc. All rights reserved. */ #include #include @@ -627,8 +627,8 @@ void __init uv_system_init(void) } uv_bios_init(); - uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, - &sn_coherency_id, &sn_region_size); + uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id, + &sn_region_size, &system_serial_number); uv_rtc_init(); for_each_present_cpu(cpu) { diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c index b0206a211b09..c918ebab52ab 100644 --- a/arch/x86/kernel/bios_uv.c +++ b/arch/x86/kernel/bios_uv.c @@ -15,8 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (c) Russ Anderson + * Copyright (c) 2008-2009 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Russ Anderson */ #include @@ -30,6 +30,7 @@ static struct uv_systab uv_systab; s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) { struct uv_systab *tab = &uv_systab; + s64 ret; if (!tab->function) /* @@ -37,9 +38,11 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) */ return BIOS_STATUS_UNIMPLEMENTED; - return efi_call6((void *)__va(tab->function), - (u64)which, a1, a2, a3, a4, a5); + ret = efi_call6((void *)__va(tab->function), (u64)which, + a1, a2, a3, a4, a5); + return ret; } +EXPORT_SYMBOL_GPL(uv_bios_call); s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) @@ -73,11 +76,14 @@ long sn_coherency_id; EXPORT_SYMBOL_GPL(sn_coherency_id); long sn_region_size; EXPORT_SYMBOL_GPL(sn_region_size); +long system_serial_number; +EXPORT_SYMBOL_GPL(system_serial_number); int uv_type; +EXPORT_SYMBOL_GPL(uv_type); s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, - long *region) + long *region, long *ssn) { s64 ret; u64 v0, v1; @@ -97,8 +103,11 @@ s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, *coher = part.coherence_id; if (region) *region = part.region_size; + if (ssn) + *ssn = v1; return ret; } +EXPORT_SYMBOL_GPL(uv_bios_get_sn_info); int uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size, @@ -185,4 +194,3 @@ void uv_bios_init(void) void uv_bios_init(void) { } #endif - -- GitLab From 681b84e17747e1c208e8e1acc54cc5e612da84d1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:29:00 +0100 Subject: [PATCH 0057/3892] sound: pcm: add vmalloc buffer helper functions There are now five copies of the code to allocate a PCM buffer using vmalloc(). Add a sixth in the core so that the others can be removed. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 38 +++++++++++++++++++++++++++++ sound/core/pcm_memory.c | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c83a4a79f16b..0ad2d28f2360 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -905,6 +905,44 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); +int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, + size_t size, gfp_t gfp_flags); +int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream); +struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, + unsigned long offset); +#if 0 /* for kernel-doc */ +/** + * snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer + * @substream: the substream to allocate the buffer to + * @size: the requested buffer size, in bytes + * + * Allocates the PCM substream buffer using vmalloc(), i.e., the memory is + * contiguous in kernel virtual space, but not in physical memory. Use this + * if the buffer is accessed by kernel code but not by device DMA. + * + * Returns 1 if the buffer was changed, 0 if not changed, or a negative error + * code. + */ +static int snd_pcm_lib_alloc_vmalloc_buffer + (struct snd_pcm_substream *substream, size_t size); +/** + * snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer + * @substream: the substream to allocate the buffer to + * @size: the requested buffer size, in bytes + * + * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses + * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory. + */ +static int snd_pcm_lib_alloc_vmalloc_32_buffer + (struct snd_pcm_substream *substream, size_t size); +#endif +#define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \ + _snd_pcm_lib_alloc_vmalloc_buffer \ + (subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO) +#define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \ + _snd_pcm_lib_alloc_vmalloc_buffer \ + (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO) + #ifdef CONFIG_SND_DMA_SGBUF /* * SG-buffer handling diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index caa7796bc2f5..d9727c74b2e1 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -434,3 +434,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_pcm_lib_free_pages); + +int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, + size_t size, gfp_t gfp_flags) +{ + struct snd_pcm_runtime *runtime; + + if (PCM_RUNTIME_CHECK(substream)) + return -EINVAL; + runtime = substream->runtime; + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL); + if (!runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 1; +} +EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer); + +/** + * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer + * @substream: the substream with a buffer allocated by + * snd_pcm_lib_alloc_vmalloc_buffer() + */ +int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + + if (PCM_RUNTIME_CHECK(substream)) + return -EINVAL; + runtime = substream->runtime; + vfree(runtime->dma_area); + runtime->dma_area = NULL; + return 0; +} +EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer); + +/** + * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct + * @substream: the substream with a buffer allocated by + * snd_pcm_lib_alloc_vmalloc_buffer() + * @offset: offset in the buffer + * + * This function is to be used as the page callback in the PCM ops. + */ +struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + return vmalloc_to_page(substream->runtime->dma_area + offset); +} +EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page); -- GitLab From d20fb5dc076a4cf0fdd00ab5a4e752ea3611e484 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:29:49 +0100 Subject: [PATCH 0058/3892] sound: pdaudiocf: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 51 ++------------------------ 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 5cfa608823f7..0afa683c900e 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -21,56 +21,12 @@ */ #include -#include #include #include #include #include "pdaudiocf.h" -/* - * we use a vmalloc'ed (sg-)buffer - */ - -/* get the physical page pointer on the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * hw_params callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already enough large */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_32_user(size); - if (! runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* - * hw_free callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - /* * clear the SRAM contents */ @@ -147,7 +103,8 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_32_buffer + (subs, params_buffer_bytes(hw_params)); } /* @@ -155,7 +112,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, */ static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_vmalloc_buffer(subs); } /* @@ -319,7 +276,7 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { .prepare = pdacf_pcm_prepare, .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- GitLab From 6cedf8696d6a01bba391bdae06231243cfe2f48a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:30:24 +0100 Subject: [PATCH 0059/3892] sound: sgio2audio: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f1d9d16b5486..9b486beeb932 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_pcm_runtime *runtime = substream->runtime; - int size = params_buffer_bytes(hw_params); - - /* alloc virtual 'dma' area */ - if (runtime->dma_area) - vfree(runtime->dma_area); - runtime->dma_area = vmalloc_user(size); - if (runtime->dma_area == NULL) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } /* hw_free callback */ static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) { - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - return 0; + return snd_pcm_lib_free_vmalloc_buffer(substream); } /* prepare callback */ @@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) chip->channel[chan->idx].pos); } -/* get the physical page pointer on the given offset */ -static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - return vmalloc_to_page(substream->runtime->dma_area + offset); -} - /* operators */ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .open = snd_sgio2audio_playback1_open, @@ -709,7 +690,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -721,7 +702,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -733,7 +714,7 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; /* -- GitLab From 149feef54bf543448dd4ec5820ef8ae178021c3a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:30:55 +0100 Subject: [PATCH 0060/3892] sound: vx: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 59 ++++----------------------------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 6644d0034fba..c8385d26a16f 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -46,7 +46,6 @@ */ #include -#include #include #include #include @@ -55,55 +54,6 @@ #include "vx_cmd.h" -/* - * we use a vmalloc'ed (sg-)buffer - */ - -/* get the physical page pointer on the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * allocate a buffer via vmalloc_32(). - * called from hw_params - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - /* already allocated */ - if (runtime->dma_bytes >= size) - return 0; /* already enough large */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_32(size); - if (! runtime->dma_area) - return -ENOMEM; - memset(runtime->dma_area, 0, size); - runtime->dma_bytes = size; - return 1; /* changed */ -} - -/* - * free the buffer. - * called from hw_free callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - - /* * read three pending pcm bytes via inb() */ @@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs) static int vx_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_32_buffer + (subs, params_buffer_bytes(hw_params)); } /* @@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs, */ static int vx_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_vmalloc_buffer(subs); } /* @@ -953,7 +904,7 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; @@ -1173,7 +1124,7 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- GitLab From c55675e348d9630c1ca69a190529bed1108c649d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:31:31 +0100 Subject: [PATCH 0061/3892] sound: usb-audio: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 46 +++++--------------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index af8869a8a79e..31b63ea098b7 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -735,41 +734,6 @@ static void snd_complete_sync_urb(struct urb *urb) } -/* get the physical page pointer at the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* allocate virtual buffer; may be called more than once */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already large enough */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_user(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* free virtual buffer; may be called more than once */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - - /* * unlink active urbs. */ @@ -1449,8 +1413,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, unsigned int channels, rate, format; int ret, changed; - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); if (ret < 0) return ret; @@ -1507,7 +1471,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->period_bytes = 0; if (!subs->stream->chip->shutdown) release_substream_urbs(subs, 0); - return snd_pcm_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_vmalloc_buffer(substream); } /* @@ -1973,7 +1937,7 @@ static struct snd_pcm_ops snd_usb_playback_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_usb_capture_ops = { @@ -1985,7 +1949,7 @@ static struct snd_pcm_ops snd_usb_capture_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- GitLab From 5b4b2a41a1a80f5560364b7ef001486cd8fb5230 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:32:00 +0100 Subject: [PATCH 0062/3892] sound: ua101: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/ua101.c | 52 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c index ab9f8a2e1938..16dc7bd5e120 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/ua101.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -145,42 +144,6 @@ static struct usb_driver ua101_driver; static void abort_alsa_playback(struct ua101 *ua); static void abort_alsa_capture(struct ua101 *ua); -/* allocate virtual buffer; may be called more than once */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already large enough */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_user(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* free virtual buffer; may be called more than once */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - -/* get the physical page pointer at the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - static const char *usb_error_string(int err) { switch (err) { @@ -791,8 +754,8 @@ static int capture_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } static int playback_pcm_hw_params(struct snd_pcm_substream *substream, @@ -809,14 +772,13 @@ static int playback_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) { - snd_pcm_free_vmalloc_buffer(substream); - return 0; + return snd_pcm_lib_free_vmalloc_buffer(substream); } static int capture_pcm_prepare(struct snd_pcm_substream *substream) @@ -948,7 +910,7 @@ static struct snd_pcm_ops capture_pcm_ops = { .prepare = capture_pcm_prepare, .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops playback_pcm_ops = { @@ -960,7 +922,7 @@ static struct snd_pcm_ops playback_pcm_ops = { .prepare = playback_pcm_prepare, .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static const struct uac_format_type_i_discrete_descriptor * -- GitLab From b35a28af0a64a1e8e389bc009b76253256d8fe7b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 18 Dec 2009 12:00:22 +0000 Subject: [PATCH 0063/3892] ASoC: Add initial WM8955 CODEC driver The WM8955 is a low power, high quality stereo DAC with integrated headphone and loudspeaker amplifiers, designed to reduce external component requirements in portable digital audio applications. This is an initial driver implementing support for the majority of the functionality in the device, currently OUT3 is not supported. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/wm8955.h | 26 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8955.c | 1151 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8955.h | 489 ++++++++++++++++ 5 files changed, 1672 insertions(+) create mode 100644 include/sound/wm8955.h create mode 100644 sound/soc/codecs/wm8955.c create mode 100644 sound/soc/codecs/wm8955.h diff --git a/include/sound/wm8955.h b/include/sound/wm8955.h new file mode 100644 index 000000000000..5074ef499f40 --- /dev/null +++ b/include/sound/wm8955.h @@ -0,0 +1,26 @@ +/* + * Platform data for WM8955 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __WM8955_PDATA_H__ +#define __WM8955_PDATA_H__ + +struct wm8955_pdata { + /* Configure LOUT2/ROUT2 to drive a speaker */ + unsigned int out2_speaker:1; + + /* Configure MONOIN+/- in differential mode */ + unsigned int monoin_diff:1; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 691abe7df087..62ff26a08a2f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -52,6 +52,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C select SND_SOC_WM8940 if I2C + select SND_SOC_WM8955 if I2C select SND_SOC_WM8960 if I2C select SND_SOC_WM8961 if I2C select SND_SOC_WM8971 if I2C @@ -214,6 +215,9 @@ config SND_SOC_WM8904 config SND_SOC_WM8940 tristate +config SND_SOC_WM8955 + tristate + config SND_SOC_WM8960 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c0fd3c86edad..ea9835412e6a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -39,6 +39,7 @@ snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8904-objs := wm8904.o snd-soc-wm8940-objs := wm8940.o +snd-soc-wm8955-objs := wm8955.o snd-soc-wm8960-objs := wm8960.o snd-soc-wm8961-objs := wm8961.o snd-soc-wm8971-objs := wm8971.o @@ -97,6 +98,7 @@ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o +obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c new file mode 100644 index 000000000000..615dab2b62ef --- /dev/null +++ b/sound/soc/codecs/wm8955.c @@ -0,0 +1,1151 @@ +/* + * wm8955.c -- WM8955 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8955.h" + +static struct snd_soc_codec *wm8955_codec; +struct snd_soc_codec_device soc_codec_dev_wm8955; + +#define WM8955_NUM_SUPPLIES 4 +static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "HPVDD", + "AVDD", +}; + +/* codec private data */ +struct wm8955_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8955_MAX_REGISTER + 1]; + + unsigned int mclk_rate; + + int deemph; + int fs; + + struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; + + struct wm8955_pdata *pdata; +}; + +static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { + 0x0000, /* R0 */ + 0x0000, /* R1 */ + 0x0079, /* R2 - LOUT1 volume */ + 0x0079, /* R3 - ROUT1 volume */ + 0x0000, /* R4 */ + 0x0008, /* R5 - DAC Control */ + 0x0000, /* R6 */ + 0x000A, /* R7 - Audio Interface */ + 0x0000, /* R8 - Sample Rate */ + 0x0000, /* R9 */ + 0x00FF, /* R10 - Left DAC volume */ + 0x00FF, /* R11 - Right DAC volume */ + 0x000F, /* R12 - Bass control */ + 0x000F, /* R13 - Treble control */ + 0x0000, /* R14 */ + 0x0000, /* R15 - Reset */ + 0x0000, /* R16 */ + 0x0000, /* R17 */ + 0x0000, /* R18 */ + 0x0000, /* R19 */ + 0x0000, /* R20 */ + 0x0000, /* R21 */ + 0x0000, /* R22 */ + 0x00C1, /* R23 - Additional control (1) */ + 0x0000, /* R24 - Additional control (2) */ + 0x0000, /* R25 - Power Management (1) */ + 0x0000, /* R26 - Power Management (2) */ + 0x0000, /* R27 - Additional Control (3) */ + 0x0000, /* R28 */ + 0x0000, /* R29 */ + 0x0000, /* R30 */ + 0x0000, /* R31 */ + 0x0000, /* R32 */ + 0x0000, /* R33 */ + 0x0050, /* R34 - Left out Mix (1) */ + 0x0050, /* R35 - Left out Mix (2) */ + 0x0050, /* R36 - Right out Mix (1) */ + 0x0050, /* R37 - Right Out Mix (2) */ + 0x0050, /* R38 - Mono out Mix (1) */ + 0x0050, /* R39 - Mono out Mix (2) */ + 0x0079, /* R40 - LOUT2 volume */ + 0x0079, /* R41 - ROUT2 volume */ + 0x0079, /* R42 - MONOOUT volume */ + 0x0000, /* R43 - Clocking / PLL */ + 0x0103, /* R44 - PLL Control 1 */ + 0x0024, /* R45 - PLL Control 2 */ + 0x01BA, /* R46 - PLL Control 3 */ + 0x0000, /* R47 */ + 0x0000, /* R48 */ + 0x0000, /* R49 */ + 0x0000, /* R50 */ + 0x0000, /* R51 */ + 0x0000, /* R52 */ + 0x0000, /* R53 */ + 0x0000, /* R54 */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x0000, /* R58 */ + 0x0000, /* R59 - PLL Control 4 */ +}; + +static int wm8955_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, WM8955_RESET, 0); +} + +struct pll_factors { + int n; + int k; + int outdiv; +}; + +/* The size in bits of the FLL divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 22) * 10) + +static int wm8995_pll_factors(struct device *dev, + int Fref, int Fout, struct pll_factors *pll) +{ + u64 Kpart; + unsigned int K, Ndiv, Nmod, target; + + dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout); + + /* The oscilator should run at should be 90-100MHz, and + * there's a divide by 4 plus an optional divide by 2 in the + * output path to generate the system clock. The clock table + * is sortd so we should always generate a suitable target. */ + target = Fout * 4; + if (target < 90000000) { + pll->outdiv = 1; + target *= 2; + } else { + pll->outdiv = 0; + } + + WARN_ON(target < 90000000 || target > 100000000); + + dev_dbg(dev, "Fvco=%dHz\n", target); + + /* Now, calculate N.K */ + Ndiv = target / Fref; + + pll->n = Ndiv; + Nmod = target % Fref; + dev_dbg(dev, "Nmod=%d\n", Nmod); + + /* Calculate fractional part - scale up so we can round. */ + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + + do_div(Kpart, Fref); + + K = Kpart & 0xFFFFFFFF; + + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + pll->k = K / 10; + + dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv); + + return 0; +} + +/* Lookup table specifiying SRATE (table 25 in datasheet); some of the + * output frequencies have been rounded to the standard frequencies + * they are intended to match where the error is slight. */ +static struct { + int mclk; + int fs; + int usb; + int sr; +} clock_cfgs[] = { + { 18432000, 8000, 0, 3, }, + { 18432000, 12000, 0, 9, }, + { 18432000, 16000, 0, 11, }, + { 18432000, 24000, 0, 29, }, + { 18432000, 32000, 0, 13, }, + { 18432000, 48000, 0, 1, }, + { 18432000, 96000, 0, 15, }, + + { 16934400, 8018, 0, 19, }, + { 16934400, 11025, 0, 25, }, + { 16934400, 22050, 0, 27, }, + { 16934400, 44100, 0, 17, }, + { 16934400, 88200, 0, 31, }, + + { 12000000, 8000, 1, 2, }, + { 12000000, 11025, 1, 25, }, + { 12000000, 12000, 1, 8, }, + { 12000000, 16000, 1, 10, }, + { 12000000, 22050, 1, 27, }, + { 12000000, 24000, 1, 28, }, + { 12000000, 32000, 1, 12, }, + { 12000000, 44100, 1, 17, }, + { 12000000, 48000, 1, 0, }, + { 12000000, 88200, 1, 31, }, + { 12000000, 96000, 1, 14, }, + + { 12288000, 8000, 0, 2, }, + { 12288000, 12000, 0, 8, }, + { 12288000, 16000, 0, 10, }, + { 12288000, 24000, 0, 28, }, + { 12288000, 32000, 0, 12, }, + { 12288000, 48000, 0, 0, }, + { 12288000, 96000, 0, 14, }, + + { 12289600, 8018, 0, 18, }, + { 12289600, 11025, 0, 24, }, + { 12289600, 22050, 0, 26, }, + { 11289600, 44100, 0, 16, }, + { 11289600, 88200, 0, 31, }, +}; + +static int wm8955_configure_clocking(struct snd_soc_codec *codec) +{ + struct wm8955_priv *wm8955 = codec->private_data; + int i, ret, val; + int clocking = 0; + int srate = 0; + int sr = -1; + struct pll_factors pll; + + /* If we're not running a sample rate currently just pick one */ + if (wm8955->fs == 0) + wm8955->fs = 8000; + + /* Can we generate an exact output? */ + for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) { + if (wm8955->fs != clock_cfgs[i].fs) + continue; + sr = i; + + if (wm8955->mclk_rate == clock_cfgs[i].mclk) + break; + } + + /* We should never get here with an unsupported sample rate */ + if (sr == -1) { + dev_err(codec->dev, "Sample rate %dHz unsupported\n", + wm8955->fs); + WARN_ON(sr == -1); + return -EINVAL; + } + + if (i == ARRAY_SIZE(clock_cfgs)) { + /* If we can't generate the right clock from MCLK then + * we should configure the PLL to supply us with an + * appropriate clock. + */ + clocking |= WM8955_MCLKSEL; + + /* Use the last divider configuration we saw for the + * sample rate. */ + ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate, + clock_cfgs[sr].mclk, &pll); + if (ret != 0) { + dev_err(codec->dev, + "Unable to generate %dHz from %dHz MCLK\n", + wm8955->fs, wm8955->mclk_rate); + return -EINVAL; + } + + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1, + WM8955_N_MASK | WM8955_K_21_18_MASK, + (pll.n << WM8955_N_SHIFT) | + pll.k >> 18); + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, + WM8955_K_17_9_MASK, + (pll.k >> 9) & WM8955_K_17_9_MASK); + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, + WM8955_K_8_0_MASK, + pll.k & WM8955_K_8_0_MASK); + if (pll.k) + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4, + WM8955_KEN, WM8955_KEN); + else + snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4, + WM8955_KEN, 0); + + if (pll.outdiv) + val = WM8955_PLL_RB | WM8955_PLLOUTDIV2; + else + val = WM8955_PLL_RB; + + /* Now start the PLL running */ + snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, + WM8955_PLL_RB | WM8955_PLLOUTDIV2, val); + snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, + WM8955_PLLEN, WM8955_PLLEN); + } + + srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT); + + snd_soc_update_bits(codec, WM8955_SAMPLE_RATE, + WM8955_USB | WM8955_SR_MASK, srate); + snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, + WM8955_MCLKSEL, clocking); + + return 0; +} + +static int wm8955_sysclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + int ret = 0; + + /* Always disable the clocks - if we're doing reconfiguration this + * avoids misclocking. + */ + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_DIGENB, 0); + snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, + WM8955_PLL_RB | WM8955_PLLEN, 0); + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + break; + case SND_SOC_DAPM_PRE_PMU: + ret = wm8955_configure_clocking(codec); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int wm8955_set_deemph(struct snd_soc_codec *codec) +{ + struct wm8955_priv *wm8955 = codec->private_data; + int val, i, best; + + /* If we're using deemphasis select the nearest available sample + * rate. + */ + if (wm8955->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - wm8955->fs) < + abs(deemph_settings[best] - wm8955->fs)) + best = i; + } + + val = best << WM8955_DEEMPH_SHIFT; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, WM8955_DAC_CONTROL, + WM8955_DEEMPH_MASK, val); +} + +static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8955_priv *wm8955 = codec->private_data; + + return wm8955->deemph; +} + +static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8955_priv *wm8955 = codec->private_data; + int deemph = ucontrol->value.enumerated.item[0]; + + if (deemph > 1) + return -EINVAL; + + wm8955->deemph = deemph; + + return wm8955_set_deemph(codec); +} + +static const char *bass_mode_text[] = { + "Linear", "Adaptive", +}; + +static const struct soc_enum bass_mode = + SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text); + +static const char *bass_cutoff_text[] = { + "Low", "High" +}; + +static const struct soc_enum bass_cutoff = + SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text); + +static const char *treble_cutoff_text[] = { + "High", "Low" +}; + +static const struct soc_enum treble_cutoff = + SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); +static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0); +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); +static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1); + +static const struct snd_kcontrol_new wm8955_snd_controls[] = { +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME, + WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv), +SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1, + atten_tlv), +SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + wm8955_get_deemph, wm8955_put_deemph), + +SOC_ENUM("Bass Mode", bass_mode), +SOC_ENUM("Bass Cutoff", bass_cutoff), +SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1), + +SOC_ENUM("Treble Cutoff", treble_cutoff), +SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv), + +SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1, + bypass_tlv), + +SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1, + bypass_tlv), + +/* Not a stereo pair so they line up with the DAPM switches */ +SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1, + mono_tlv), +SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1, + mono_tlv), + +SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME, + WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv), +SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME, + WM8955_ROUT1_VOLUME, 7, 1, 0), + +SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME, + WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv), +SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME, + WM8955_ROUT2_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv), +SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0), +}; + +static const struct snd_kcontrol_new lmixer[] = { +SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0), +SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0), +SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0), +}; + +static const struct snd_kcontrol_new rmixer[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0), +SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0), +SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0), +SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0), +}; + +static const struct snd_kcontrol_new mmixer[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("MONOIN-"), +SND_SOC_DAPM_INPUT("MONOIN+"), +SND_SOC_DAPM_INPUT("LINEINR"), +SND_SOC_DAPM_INPUT("LINEINL"), + +SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0), + +SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0), +SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0), + +SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0), +SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0), + +/* The names are chosen to make the control names nice */ +SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0, + lmixer, ARRAY_SIZE(lmixer)), +SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0, + rmixer, ARRAY_SIZE(rmixer)), +SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0, + mmixer, ARRAY_SIZE(mmixer)), + +SND_SOC_DAPM_OUTPUT("LOUT1"), +SND_SOC_DAPM_OUTPUT("ROUT1"), +SND_SOC_DAPM_OUTPUT("LOUT2"), +SND_SOC_DAPM_OUTPUT("ROUT2"), +SND_SOC_DAPM_OUTPUT("MONOOUT"), +SND_SOC_DAPM_OUTPUT("OUT3"), +}; + +static const struct snd_soc_dapm_route wm8955_intercon[] = { + { "DACL", NULL, "SYSCLK" }, + { "DACR", NULL, "SYSCLK" }, + + { "Mono Input", NULL, "MONOIN-" }, + { "Mono Input", NULL, "MONOIN+" }, + + { "Left", "Playback Switch", "DACL" }, + { "Left", "Right Playback Switch", "DACR" }, + { "Left", "Bypass Switch", "LINEINL" }, + { "Left", "Mono Switch", "Mono Input" }, + + { "Right", "Playback Switch", "DACR" }, + { "Right", "Left Playback Switch", "DACL" }, + { "Right", "Bypass Switch", "LINEINR" }, + { "Right", "Mono Switch", "Mono Input" }, + + { "Mono", "Left Playback Switch", "DACL" }, + { "Mono", "Right Playback Switch", "DACR" }, + { "Mono", "Left Bypass Switch", "LINEINL" }, + { "Mono", "Right Bypass Switch", "LINEINR" }, + + { "LOUT1 PGA", NULL, "Left" }, + { "LOUT1", NULL, "TSDEN" }, + { "LOUT1", NULL, "LOUT1 PGA" }, + + { "ROUT1 PGA", NULL, "Right" }, + { "ROUT1", NULL, "TSDEN" }, + { "ROUT1", NULL, "ROUT1 PGA" }, + + { "LOUT2 PGA", NULL, "Left" }, + { "LOUT2", NULL, "TSDEN" }, + { "LOUT2", NULL, "LOUT2 PGA" }, + + { "ROUT2 PGA", NULL, "Right" }, + { "ROUT2", NULL, "TSDEN" }, + { "ROUT2", NULL, "ROUT2 PGA" }, + + { "MOUT PGA", NULL, "Mono" }, + { "MONOOUT", NULL, "MOUT PGA" }, + + /* OUT3 not currently implemented */ + { "OUT3", NULL, "OUT3 PGA" }, +}; + +static int wm8955_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_add_controls(codec, wm8955_snd_controls, + ARRAY_SIZE(wm8955_snd_controls)); + + snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets, + ARRAY_SIZE(wm8955_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, wm8955_intercon, + ARRAY_SIZE(wm8955_intercon)); + + return 0; +} + +static int wm8955_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8955_priv *wm8955 = codec->private_data; + int ret; + int wl; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wl = 0; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wl = 0x4; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wl = 0x8; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wl = 0xc; + break; + default: + return -EINVAL; + } + snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE, + WM8955_WL_MASK, wl); + + wm8955->fs = params_rate(params); + wm8955_set_deemph(codec); + + /* If the chip is clocked then disable the clocks and force a + * reconfiguration, otherwise DAPM will power up the + * clocks for us later. */ + ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1); + if (ret < 0) + return ret; + if (ret & WM8955_DIGENB) { + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_DIGENB, 0); + snd_soc_update_bits(codec, WM8955_CLOCKING_PLL, + WM8955_PLL_RB | WM8955_PLLEN, 0); + + wm8955_configure_clocking(codec); + } + + return 0; +} + + +static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8955_priv *priv = codec->private_data; + int div; + + switch (clk_id) { + case WM8955_CLK_MCLK: + if (freq > 15000000) { + priv->mclk_rate = freq /= 2; + div = WM8955_MCLKDIV2; + } else { + priv->mclk_rate = freq; + div = 0; + } + + snd_soc_update_bits(codec, WM8955_SAMPLE_RATE, + WM8955_MCLKDIV2, div); + break; + + default: + return -EINVAL; + } + + dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); + + return 0; +} + +static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + u16 aif = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + aif |= WM8955_MS; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif |= WM8955_LRP; + case SND_SOC_DAIFMT_DSP_A: + aif |= 0x3; + break; + case SND_SOC_DAIFMT_I2S: + aif |= 0x2; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif |= 0x1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif |= WM8955_BCLKINV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif |= WM8955_BCLKINV | WM8955_LRP; + break; + case SND_SOC_DAIFMT_IB_NF: + aif |= WM8955_BCLKINV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif |= WM8955_LRP; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE, + WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV | + WM8955_LRP, aif); + + return 0; +} + + +static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int val; + + if (mute) + val = WM8955_DACMU; + else + val = 0; + + snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val); + + return 0; +} + +static int wm8955_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8955_priv *wm8955 = codec->private_data; + int ret, i; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VMID resistance 2*50k */ + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_VMIDSEL_MASK, + 0x1 << WM8955_VMIDSEL_SHIFT); + + /* Default bias current */ + snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1, + WM8955_VSEL_MASK, + 0x2 << WM8955_VSEL_SHIFT); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), + wm8955->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + + /* Sync back cached values if they're + * different from the hardware default. + */ + for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) { + if (i == WM8955_RESET) + continue; + + if (wm8955->reg_cache[i] == wm8955_reg[i]) + continue; + + snd_soc_write(codec, i, wm8955->reg_cache[i]); + } + + /* Enable VREF and VMID */ + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_VREF | + WM8955_VMIDSEL_MASK, + WM8955_VREF | + 0x3 << WM8955_VREF_SHIFT); + + /* Let VMID ramp */ + msleep(500); + + /* High resistance VROI to maintain outputs */ + snd_soc_update_bits(codec, + WM8955_ADDITIONAL_CONTROL_3, + WM8955_VROI, WM8955_VROI); + } + + /* Maintain VMID with 2*250k */ + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_VMIDSEL_MASK, + 0x2 << WM8955_VMIDSEL_SHIFT); + + /* Minimum bias current */ + snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1, + WM8955_VSEL_MASK, 0); + break; + + case SND_SOC_BIAS_OFF: + /* Low resistance VROI to help discharge */ + snd_soc_update_bits(codec, + WM8955_ADDITIONAL_CONTROL_3, + WM8955_VROI, 0); + + /* Turn off VMID and VREF */ + snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, + WM8955_VREF | + WM8955_VMIDSEL_MASK, 0); + + regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), + wm8955->supplies); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8955_RATES SNDRV_PCM_RATE_8000_96000 + +#define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8955_dai_ops = { + .set_sysclk = wm8955_set_sysclk, + .set_fmt = wm8955_set_fmt, + .hw_params = wm8955_hw_params, + .digital_mute = wm8955_digital_mute, +}; + +struct snd_soc_dai wm8955_dai = { + .name = "WM8955", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8955_RATES, + .formats = WM8955_FORMATS, + }, + .ops = &wm8955_dai_ops, +}; +EXPORT_SYMBOL_GPL(wm8955_dai); + +#ifdef CONFIG_PM +static int wm8955_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8955_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm8955_suspend NULL +#define wm8955_resume NULL +#endif + +static int wm8955_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8955_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8955_codec; + codec = wm8955_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + wm8955_add_widgets(codec); + + return ret; + +pcm_err: + return ret; +} + +static int wm8955_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8955 = { + .probe = wm8955_probe, + .remove = wm8955_remove, + .suspend = wm8955_suspend, + .resume = wm8955_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955); + +static int wm8955_register(struct wm8955_priv *wm8955, + enum snd_soc_control_type control) +{ + int ret; + struct snd_soc_codec *codec = &wm8955->codec; + int i; + + if (wm8955_codec) { + dev_err(codec->dev, "Another WM8955 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8955; + codec->name = "WM8955"; + codec->owner = THIS_MODULE; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8955_set_bias_level; + codec->dai = &wm8955_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8955_MAX_REGISTER; + codec->reg_cache = &wm8955->reg_cache; + + memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg)); + + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++) + wm8955->supplies[i].supply = wm8955_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies), + wm8955->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), + wm8955->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + + ret = wm8955_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + goto err_enable; + } + + wm8955_dai.dev = codec->dev; + + /* Change some default settings - latch VU and enable ZC */ + wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU; + wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU; + wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC; + wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC; + wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC; + wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC; + wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC; + + /* Also enable adaptive bass boost by default */ + wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB; + + /* Set platform data values */ + if (wm8955->pdata) { + if (wm8955->pdata->out2_speaker) + wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2] + |= WM8955_ROUT2INV; + + if (wm8955->pdata->monoin_diff) + wm8955->reg_cache[WM8955_MONO_OUT_MIX_1] + |= WM8955_DMEN; + } + + wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Bias level configuration will have done an extra enable */ + regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); + + wm8955_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8955_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); +err: + kfree(wm8955); + return ret; +} + +static void wm8955_unregister(struct wm8955_priv *wm8955) +{ + wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF); + regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); + snd_soc_unregister_dai(&wm8955_dai); + snd_soc_unregister_codec(&wm8955->codec); + kfree(wm8955); + wm8955_codec = NULL; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8955_priv *wm8955; + struct snd_soc_codec *codec; + + wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL); + if (wm8955 == NULL) + return -ENOMEM; + + codec = &wm8955->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8955); + codec->control_data = i2c; + wm8955->pdata = i2c->dev.platform_data; + + codec->dev = &i2c->dev; + + return wm8955_register(wm8955, SND_SOC_I2C); +} + +static __devexit int wm8955_i2c_remove(struct i2c_client *client) +{ + struct wm8955_priv *wm8955 = i2c_get_clientdata(client); + wm8955_unregister(wm8955); + return 0; +} + +static const struct i2c_device_id wm8955_i2c_id[] = { + { "wm8955", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id); + +static struct i2c_driver wm8955_i2c_driver = { + .driver = { + .name = "wm8955", + .owner = THIS_MODULE, + }, + .probe = wm8955_i2c_probe, + .remove = __devexit_p(wm8955_i2c_remove), + .id_table = wm8955_i2c_id, +}; +#endif + +static int __init wm8955_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8955_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", + ret); + } +#endif + return 0; +} +module_init(wm8955_modinit); + +static void __exit wm8955_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8955_i2c_driver); +#endif +} +module_exit(wm8955_exit); + +MODULE_DESCRIPTION("ASoC WM8955 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h new file mode 100644 index 000000000000..ae349c8531f6 --- /dev/null +++ b/sound/soc/codecs/wm8955.h @@ -0,0 +1,489 @@ +/* + * wm8955.h -- WM8904 ASoC driver + * + * Copyright 2009 Wolfson Microelectronics, plc + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8955_H +#define _WM8955_H + +#define WM8955_CLK_MCLK 1 + +extern struct snd_soc_dai wm8955_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8955; + +/* + * Register values. + */ +#define WM8955_LOUT1_VOLUME 0x02 +#define WM8955_ROUT1_VOLUME 0x03 +#define WM8955_DAC_CONTROL 0x05 +#define WM8955_AUDIO_INTERFACE 0x07 +#define WM8955_SAMPLE_RATE 0x08 +#define WM8955_LEFT_DAC_VOLUME 0x0A +#define WM8955_RIGHT_DAC_VOLUME 0x0B +#define WM8955_BASS_CONTROL 0x0C +#define WM8955_TREBLE_CONTROL 0x0D +#define WM8955_RESET 0x0F +#define WM8955_ADDITIONAL_CONTROL_1 0x17 +#define WM8955_ADDITIONAL_CONTROL_2 0x18 +#define WM8955_POWER_MANAGEMENT_1 0x19 +#define WM8955_POWER_MANAGEMENT_2 0x1A +#define WM8955_ADDITIONAL_CONTROL_3 0x1B +#define WM8955_LEFT_OUT_MIX_1 0x22 +#define WM8955_LEFT_OUT_MIX_2 0x23 +#define WM8955_RIGHT_OUT_MIX_1 0x24 +#define WM8955_RIGHT_OUT_MIX_2 0x25 +#define WM8955_MONO_OUT_MIX_1 0x26 +#define WM8955_MONO_OUT_MIX_2 0x27 +#define WM8955_LOUT2_VOLUME 0x28 +#define WM8955_ROUT2_VOLUME 0x29 +#define WM8955_MONOOUT_VOLUME 0x2A +#define WM8955_CLOCKING_PLL 0x2B +#define WM8955_PLL_CONTROL_1 0x2C +#define WM8955_PLL_CONTROL_2 0x2D +#define WM8955_PLL_CONTROL_3 0x2E +#define WM8955_PLL_CONTROL_4 0x3B + +#define WM8955_REGISTER_COUNT 29 +#define WM8955_MAX_REGISTER 0x3B + +/* + * Field Definitions. + */ + +/* + * R2 (0x02) - LOUT1 volume + */ +#define WM8955_LO1VU 0x0100 /* LO1VU */ +#define WM8955_LO1VU_MASK 0x0100 /* LO1VU */ +#define WM8955_LO1VU_SHIFT 8 /* LO1VU */ +#define WM8955_LO1VU_WIDTH 1 /* LO1VU */ +#define WM8955_LO1ZC 0x0080 /* LO1ZC */ +#define WM8955_LO1ZC_MASK 0x0080 /* LO1ZC */ +#define WM8955_LO1ZC_SHIFT 7 /* LO1ZC */ +#define WM8955_LO1ZC_WIDTH 1 /* LO1ZC */ +#define WM8955_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ +#define WM8955_LOUTVOL_SHIFT 0 /* LOUTVOL - [6:0] */ +#define WM8955_LOUTVOL_WIDTH 7 /* LOUTVOL - [6:0] */ + +/* + * R3 (0x03) - ROUT1 volume + */ +#define WM8955_RO1VU 0x0100 /* RO1VU */ +#define WM8955_RO1VU_MASK 0x0100 /* RO1VU */ +#define WM8955_RO1VU_SHIFT 8 /* RO1VU */ +#define WM8955_RO1VU_WIDTH 1 /* RO1VU */ +#define WM8955_RO1ZC 0x0080 /* RO1ZC */ +#define WM8955_RO1ZC_MASK 0x0080 /* RO1ZC */ +#define WM8955_RO1ZC_SHIFT 7 /* RO1ZC */ +#define WM8955_RO1ZC_WIDTH 1 /* RO1ZC */ +#define WM8955_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ +#define WM8955_ROUTVOL_SHIFT 0 /* ROUTVOL - [6:0] */ +#define WM8955_ROUTVOL_WIDTH 7 /* ROUTVOL - [6:0] */ + +/* + * R5 (0x05) - DAC Control + */ +#define WM8955_DAT 0x0080 /* DAT */ +#define WM8955_DAT_MASK 0x0080 /* DAT */ +#define WM8955_DAT_SHIFT 7 /* DAT */ +#define WM8955_DAT_WIDTH 1 /* DAT */ +#define WM8955_DACMU 0x0008 /* DACMU */ +#define WM8955_DACMU_MASK 0x0008 /* DACMU */ +#define WM8955_DACMU_SHIFT 3 /* DACMU */ +#define WM8955_DACMU_WIDTH 1 /* DACMU */ +#define WM8955_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ +#define WM8955_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ +#define WM8955_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ + +/* + * R7 (0x07) - Audio Interface + */ +#define WM8955_BCLKINV 0x0080 /* BCLKINV */ +#define WM8955_BCLKINV_MASK 0x0080 /* BCLKINV */ +#define WM8955_BCLKINV_SHIFT 7 /* BCLKINV */ +#define WM8955_BCLKINV_WIDTH 1 /* BCLKINV */ +#define WM8955_MS 0x0040 /* MS */ +#define WM8955_MS_MASK 0x0040 /* MS */ +#define WM8955_MS_SHIFT 6 /* MS */ +#define WM8955_MS_WIDTH 1 /* MS */ +#define WM8955_LRSWAP 0x0020 /* LRSWAP */ +#define WM8955_LRSWAP_MASK 0x0020 /* LRSWAP */ +#define WM8955_LRSWAP_SHIFT 5 /* LRSWAP */ +#define WM8955_LRSWAP_WIDTH 1 /* LRSWAP */ +#define WM8955_LRP 0x0010 /* LRP */ +#define WM8955_LRP_MASK 0x0010 /* LRP */ +#define WM8955_LRP_SHIFT 4 /* LRP */ +#define WM8955_LRP_WIDTH 1 /* LRP */ +#define WM8955_WL_MASK 0x000C /* WL - [3:2] */ +#define WM8955_WL_SHIFT 2 /* WL - [3:2] */ +#define WM8955_WL_WIDTH 2 /* WL - [3:2] */ +#define WM8955_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */ +#define WM8955_FORMAT_SHIFT 0 /* FORMAT - [1:0] */ +#define WM8955_FORMAT_WIDTH 2 /* FORMAT - [1:0] */ + +/* + * R8 (0x08) - Sample Rate + */ +#define WM8955_BCLKDIV2 0x0080 /* BCLKDIV2 */ +#define WM8955_BCLKDIV2_MASK 0x0080 /* BCLKDIV2 */ +#define WM8955_BCLKDIV2_SHIFT 7 /* BCLKDIV2 */ +#define WM8955_BCLKDIV2_WIDTH 1 /* BCLKDIV2 */ +#define WM8955_MCLKDIV2 0x0040 /* MCLKDIV2 */ +#define WM8955_MCLKDIV2_MASK 0x0040 /* MCLKDIV2 */ +#define WM8955_MCLKDIV2_SHIFT 6 /* MCLKDIV2 */ +#define WM8955_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ +#define WM8955_SR_MASK 0x003E /* SR - [5:1] */ +#define WM8955_SR_SHIFT 1 /* SR - [5:1] */ +#define WM8955_SR_WIDTH 5 /* SR - [5:1] */ +#define WM8955_USB 0x0001 /* USB */ +#define WM8955_USB_MASK 0x0001 /* USB */ +#define WM8955_USB_SHIFT 0 /* USB */ +#define WM8955_USB_WIDTH 1 /* USB */ + +/* + * R10 (0x0A) - Left DAC volume + */ +#define WM8955_LDVU 0x0100 /* LDVU */ +#define WM8955_LDVU_MASK 0x0100 /* LDVU */ +#define WM8955_LDVU_SHIFT 8 /* LDVU */ +#define WM8955_LDVU_WIDTH 1 /* LDVU */ +#define WM8955_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */ +#define WM8955_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */ +#define WM8955_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */ + +/* + * R11 (0x0B) - Right DAC volume + */ +#define WM8955_RDVU 0x0100 /* RDVU */ +#define WM8955_RDVU_MASK 0x0100 /* RDVU */ +#define WM8955_RDVU_SHIFT 8 /* RDVU */ +#define WM8955_RDVU_WIDTH 1 /* RDVU */ +#define WM8955_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */ +#define WM8955_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */ +#define WM8955_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */ + +/* + * R12 (0x0C) - Bass control + */ +#define WM8955_BB 0x0080 /* BB */ +#define WM8955_BB_MASK 0x0080 /* BB */ +#define WM8955_BB_SHIFT 7 /* BB */ +#define WM8955_BB_WIDTH 1 /* BB */ +#define WM8955_BC 0x0040 /* BC */ +#define WM8955_BC_MASK 0x0040 /* BC */ +#define WM8955_BC_SHIFT 6 /* BC */ +#define WM8955_BC_WIDTH 1 /* BC */ +#define WM8955_BASS_MASK 0x000F /* BASS - [3:0] */ +#define WM8955_BASS_SHIFT 0 /* BASS - [3:0] */ +#define WM8955_BASS_WIDTH 4 /* BASS - [3:0] */ + +/* + * R13 (0x0D) - Treble control + */ +#define WM8955_TC 0x0040 /* TC */ +#define WM8955_TC_MASK 0x0040 /* TC */ +#define WM8955_TC_SHIFT 6 /* TC */ +#define WM8955_TC_WIDTH 1 /* TC */ +#define WM8955_TRBL_MASK 0x000F /* TRBL - [3:0] */ +#define WM8955_TRBL_SHIFT 0 /* TRBL - [3:0] */ +#define WM8955_TRBL_WIDTH 4 /* TRBL - [3:0] */ + +/* + * R15 (0x0F) - Reset + */ +#define WM8955_RESET_MASK 0x01FF /* RESET - [8:0] */ +#define WM8955_RESET_SHIFT 0 /* RESET - [8:0] */ +#define WM8955_RESET_WIDTH 9 /* RESET - [8:0] */ + +/* + * R23 (0x17) - Additional control (1) + */ +#define WM8955_TSDEN 0x0100 /* TSDEN */ +#define WM8955_TSDEN_MASK 0x0100 /* TSDEN */ +#define WM8955_TSDEN_SHIFT 8 /* TSDEN */ +#define WM8955_TSDEN_WIDTH 1 /* TSDEN */ +#define WM8955_VSEL_MASK 0x00C0 /* VSEL - [7:6] */ +#define WM8955_VSEL_SHIFT 6 /* VSEL - [7:6] */ +#define WM8955_VSEL_WIDTH 2 /* VSEL - [7:6] */ +#define WM8955_DMONOMIX_MASK 0x0030 /* DMONOMIX - [5:4] */ +#define WM8955_DMONOMIX_SHIFT 4 /* DMONOMIX - [5:4] */ +#define WM8955_DMONOMIX_WIDTH 2 /* DMONOMIX - [5:4] */ +#define WM8955_DACINV 0x0002 /* DACINV */ +#define WM8955_DACINV_MASK 0x0002 /* DACINV */ +#define WM8955_DACINV_SHIFT 1 /* DACINV */ +#define WM8955_DACINV_WIDTH 1 /* DACINV */ +#define WM8955_TOEN 0x0001 /* TOEN */ +#define WM8955_TOEN_MASK 0x0001 /* TOEN */ +#define WM8955_TOEN_SHIFT 0 /* TOEN */ +#define WM8955_TOEN_WIDTH 1 /* TOEN */ + +/* + * R24 (0x18) - Additional control (2) + */ +#define WM8955_OUT3SW_MASK 0x0180 /* OUT3SW - [8:7] */ +#define WM8955_OUT3SW_SHIFT 7 /* OUT3SW - [8:7] */ +#define WM8955_OUT3SW_WIDTH 2 /* OUT3SW - [8:7] */ +#define WM8955_ROUT2INV 0x0010 /* ROUT2INV */ +#define WM8955_ROUT2INV_MASK 0x0010 /* ROUT2INV */ +#define WM8955_ROUT2INV_SHIFT 4 /* ROUT2INV */ +#define WM8955_ROUT2INV_WIDTH 1 /* ROUT2INV */ +#define WM8955_DACOSR 0x0001 /* DACOSR */ +#define WM8955_DACOSR_MASK 0x0001 /* DACOSR */ +#define WM8955_DACOSR_SHIFT 0 /* DACOSR */ +#define WM8955_DACOSR_WIDTH 1 /* DACOSR */ + +/* + * R25 (0x19) - Power Management (1) + */ +#define WM8955_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */ +#define WM8955_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */ +#define WM8955_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */ +#define WM8955_VREF 0x0040 /* VREF */ +#define WM8955_VREF_MASK 0x0040 /* VREF */ +#define WM8955_VREF_SHIFT 6 /* VREF */ +#define WM8955_VREF_WIDTH 1 /* VREF */ +#define WM8955_DIGENB 0x0001 /* DIGENB */ +#define WM8955_DIGENB_MASK 0x0001 /* DIGENB */ +#define WM8955_DIGENB_SHIFT 0 /* DIGENB */ +#define WM8955_DIGENB_WIDTH 1 /* DIGENB */ + +/* + * R26 (0x1A) - Power Management (2) + */ +#define WM8955_DACL 0x0100 /* DACL */ +#define WM8955_DACL_MASK 0x0100 /* DACL */ +#define WM8955_DACL_SHIFT 8 /* DACL */ +#define WM8955_DACL_WIDTH 1 /* DACL */ +#define WM8955_DACR 0x0080 /* DACR */ +#define WM8955_DACR_MASK 0x0080 /* DACR */ +#define WM8955_DACR_SHIFT 7 /* DACR */ +#define WM8955_DACR_WIDTH 1 /* DACR */ +#define WM8955_LOUT1 0x0040 /* LOUT1 */ +#define WM8955_LOUT1_MASK 0x0040 /* LOUT1 */ +#define WM8955_LOUT1_SHIFT 6 /* LOUT1 */ +#define WM8955_LOUT1_WIDTH 1 /* LOUT1 */ +#define WM8955_ROUT1 0x0020 /* ROUT1 */ +#define WM8955_ROUT1_MASK 0x0020 /* ROUT1 */ +#define WM8955_ROUT1_SHIFT 5 /* ROUT1 */ +#define WM8955_ROUT1_WIDTH 1 /* ROUT1 */ +#define WM8955_LOUT2 0x0010 /* LOUT2 */ +#define WM8955_LOUT2_MASK 0x0010 /* LOUT2 */ +#define WM8955_LOUT2_SHIFT 4 /* LOUT2 */ +#define WM8955_LOUT2_WIDTH 1 /* LOUT2 */ +#define WM8955_ROUT2 0x0008 /* ROUT2 */ +#define WM8955_ROUT2_MASK 0x0008 /* ROUT2 */ +#define WM8955_ROUT2_SHIFT 3 /* ROUT2 */ +#define WM8955_ROUT2_WIDTH 1 /* ROUT2 */ +#define WM8955_MONO 0x0004 /* MONO */ +#define WM8955_MONO_MASK 0x0004 /* MONO */ +#define WM8955_MONO_SHIFT 2 /* MONO */ +#define WM8955_MONO_WIDTH 1 /* MONO */ +#define WM8955_OUT3 0x0002 /* OUT3 */ +#define WM8955_OUT3_MASK 0x0002 /* OUT3 */ +#define WM8955_OUT3_SHIFT 1 /* OUT3 */ +#define WM8955_OUT3_WIDTH 1 /* OUT3 */ + +/* + * R27 (0x1B) - Additional Control (3) + */ +#define WM8955_VROI 0x0040 /* VROI */ +#define WM8955_VROI_MASK 0x0040 /* VROI */ +#define WM8955_VROI_SHIFT 6 /* VROI */ +#define WM8955_VROI_WIDTH 1 /* VROI */ + +/* + * R34 (0x22) - Left out Mix (1) + */ +#define WM8955_LD2LO 0x0100 /* LD2LO */ +#define WM8955_LD2LO_MASK 0x0100 /* LD2LO */ +#define WM8955_LD2LO_SHIFT 8 /* LD2LO */ +#define WM8955_LD2LO_WIDTH 1 /* LD2LO */ +#define WM8955_LI2LO 0x0080 /* LI2LO */ +#define WM8955_LI2LO_MASK 0x0080 /* LI2LO */ +#define WM8955_LI2LO_SHIFT 7 /* LI2LO */ +#define WM8955_LI2LO_WIDTH 1 /* LI2LO */ +#define WM8955_LI2LOVOL_MASK 0x0070 /* LI2LOVOL - [6:4] */ +#define WM8955_LI2LOVOL_SHIFT 4 /* LI2LOVOL - [6:4] */ +#define WM8955_LI2LOVOL_WIDTH 3 /* LI2LOVOL - [6:4] */ + +/* + * R35 (0x23) - Left out Mix (2) + */ +#define WM8955_RD2LO 0x0100 /* RD2LO */ +#define WM8955_RD2LO_MASK 0x0100 /* RD2LO */ +#define WM8955_RD2LO_SHIFT 8 /* RD2LO */ +#define WM8955_RD2LO_WIDTH 1 /* RD2LO */ +#define WM8955_RI2LO 0x0080 /* RI2LO */ +#define WM8955_RI2LO_MASK 0x0080 /* RI2LO */ +#define WM8955_RI2LO_SHIFT 7 /* RI2LO */ +#define WM8955_RI2LO_WIDTH 1 /* RI2LO */ +#define WM8955_RI2LOVOL_MASK 0x0070 /* RI2LOVOL - [6:4] */ +#define WM8955_RI2LOVOL_SHIFT 4 /* RI2LOVOL - [6:4] */ +#define WM8955_RI2LOVOL_WIDTH 3 /* RI2LOVOL - [6:4] */ + +/* + * R36 (0x24) - Right out Mix (1) + */ +#define WM8955_LD2RO 0x0100 /* LD2RO */ +#define WM8955_LD2RO_MASK 0x0100 /* LD2RO */ +#define WM8955_LD2RO_SHIFT 8 /* LD2RO */ +#define WM8955_LD2RO_WIDTH 1 /* LD2RO */ +#define WM8955_LI2RO 0x0080 /* LI2RO */ +#define WM8955_LI2RO_MASK 0x0080 /* LI2RO */ +#define WM8955_LI2RO_SHIFT 7 /* LI2RO */ +#define WM8955_LI2RO_WIDTH 1 /* LI2RO */ +#define WM8955_LI2ROVOL_MASK 0x0070 /* LI2ROVOL - [6:4] */ +#define WM8955_LI2ROVOL_SHIFT 4 /* LI2ROVOL - [6:4] */ +#define WM8955_LI2ROVOL_WIDTH 3 /* LI2ROVOL - [6:4] */ + +/* + * R37 (0x25) - Right Out Mix (2) + */ +#define WM8955_RD2RO 0x0100 /* RD2RO */ +#define WM8955_RD2RO_MASK 0x0100 /* RD2RO */ +#define WM8955_RD2RO_SHIFT 8 /* RD2RO */ +#define WM8955_RD2RO_WIDTH 1 /* RD2RO */ +#define WM8955_RI2RO 0x0080 /* RI2RO */ +#define WM8955_RI2RO_MASK 0x0080 /* RI2RO */ +#define WM8955_RI2RO_SHIFT 7 /* RI2RO */ +#define WM8955_RI2RO_WIDTH 1 /* RI2RO */ +#define WM8955_RI2ROVOL_MASK 0x0070 /* RI2ROVOL - [6:4] */ +#define WM8955_RI2ROVOL_SHIFT 4 /* RI2ROVOL - [6:4] */ +#define WM8955_RI2ROVOL_WIDTH 3 /* RI2ROVOL - [6:4] */ + +/* + * R38 (0x26) - Mono out Mix (1) + */ +#define WM8955_LD2MO 0x0100 /* LD2MO */ +#define WM8955_LD2MO_MASK 0x0100 /* LD2MO */ +#define WM8955_LD2MO_SHIFT 8 /* LD2MO */ +#define WM8955_LD2MO_WIDTH 1 /* LD2MO */ +#define WM8955_LI2MO 0x0080 /* LI2MO */ +#define WM8955_LI2MO_MASK 0x0080 /* LI2MO */ +#define WM8955_LI2MO_SHIFT 7 /* LI2MO */ +#define WM8955_LI2MO_WIDTH 1 /* LI2MO */ +#define WM8955_LI2MOVOL_MASK 0x0070 /* LI2MOVOL - [6:4] */ +#define WM8955_LI2MOVOL_SHIFT 4 /* LI2MOVOL - [6:4] */ +#define WM8955_LI2MOVOL_WIDTH 3 /* LI2MOVOL - [6:4] */ +#define WM8955_DMEN 0x0001 /* DMEN */ +#define WM8955_DMEN_MASK 0x0001 /* DMEN */ +#define WM8955_DMEN_SHIFT 0 /* DMEN */ +#define WM8955_DMEN_WIDTH 1 /* DMEN */ + +/* + * R39 (0x27) - Mono out Mix (2) + */ +#define WM8955_RD2MO 0x0100 /* RD2MO */ +#define WM8955_RD2MO_MASK 0x0100 /* RD2MO */ +#define WM8955_RD2MO_SHIFT 8 /* RD2MO */ +#define WM8955_RD2MO_WIDTH 1 /* RD2MO */ +#define WM8955_RI2MO 0x0080 /* RI2MO */ +#define WM8955_RI2MO_MASK 0x0080 /* RI2MO */ +#define WM8955_RI2MO_SHIFT 7 /* RI2MO */ +#define WM8955_RI2MO_WIDTH 1 /* RI2MO */ +#define WM8955_RI2MOVOL_MASK 0x0070 /* RI2MOVOL - [6:4] */ +#define WM8955_RI2MOVOL_SHIFT 4 /* RI2MOVOL - [6:4] */ +#define WM8955_RI2MOVOL_WIDTH 3 /* RI2MOVOL - [6:4] */ + +/* + * R40 (0x28) - LOUT2 volume + */ +#define WM8955_LO2VU 0x0100 /* LO2VU */ +#define WM8955_LO2VU_MASK 0x0100 /* LO2VU */ +#define WM8955_LO2VU_SHIFT 8 /* LO2VU */ +#define WM8955_LO2VU_WIDTH 1 /* LO2VU */ +#define WM8955_LO2ZC 0x0080 /* LO2ZC */ +#define WM8955_LO2ZC_MASK 0x0080 /* LO2ZC */ +#define WM8955_LO2ZC_SHIFT 7 /* LO2ZC */ +#define WM8955_LO2ZC_WIDTH 1 /* LO2ZC */ +#define WM8955_LOUT2VOL_MASK 0x007F /* LOUT2VOL - [6:0] */ +#define WM8955_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [6:0] */ +#define WM8955_LOUT2VOL_WIDTH 7 /* LOUT2VOL - [6:0] */ + +/* + * R41 (0x29) - ROUT2 volume + */ +#define WM8955_RO2VU 0x0100 /* RO2VU */ +#define WM8955_RO2VU_MASK 0x0100 /* RO2VU */ +#define WM8955_RO2VU_SHIFT 8 /* RO2VU */ +#define WM8955_RO2VU_WIDTH 1 /* RO2VU */ +#define WM8955_RO2ZC 0x0080 /* RO2ZC */ +#define WM8955_RO2ZC_MASK 0x0080 /* RO2ZC */ +#define WM8955_RO2ZC_SHIFT 7 /* RO2ZC */ +#define WM8955_RO2ZC_WIDTH 1 /* RO2ZC */ +#define WM8955_ROUT2VOL_MASK 0x007F /* ROUT2VOL - [6:0] */ +#define WM8955_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [6:0] */ +#define WM8955_ROUT2VOL_WIDTH 7 /* ROUT2VOL - [6:0] */ + +/* + * R42 (0x2A) - MONOOUT volume + */ +#define WM8955_MOZC 0x0080 /* MOZC */ +#define WM8955_MOZC_MASK 0x0080 /* MOZC */ +#define WM8955_MOZC_SHIFT 7 /* MOZC */ +#define WM8955_MOZC_WIDTH 1 /* MOZC */ +#define WM8955_MOUTVOL_MASK 0x007F /* MOUTVOL - [6:0] */ +#define WM8955_MOUTVOL_SHIFT 0 /* MOUTVOL - [6:0] */ +#define WM8955_MOUTVOL_WIDTH 7 /* MOUTVOL - [6:0] */ + +/* + * R43 (0x2B) - Clocking / PLL + */ +#define WM8955_MCLKSEL 0x0100 /* MCLKSEL */ +#define WM8955_MCLKSEL_MASK 0x0100 /* MCLKSEL */ +#define WM8955_MCLKSEL_SHIFT 8 /* MCLKSEL */ +#define WM8955_MCLKSEL_WIDTH 1 /* MCLKSEL */ +#define WM8955_PLLOUTDIV2 0x0020 /* PLLOUTDIV2 */ +#define WM8955_PLLOUTDIV2_MASK 0x0020 /* PLLOUTDIV2 */ +#define WM8955_PLLOUTDIV2_SHIFT 5 /* PLLOUTDIV2 */ +#define WM8955_PLLOUTDIV2_WIDTH 1 /* PLLOUTDIV2 */ +#define WM8955_PLL_RB 0x0010 /* PLL_RB */ +#define WM8955_PLL_RB_MASK 0x0010 /* PLL_RB */ +#define WM8955_PLL_RB_SHIFT 4 /* PLL_RB */ +#define WM8955_PLL_RB_WIDTH 1 /* PLL_RB */ +#define WM8955_PLLEN 0x0008 /* PLLEN */ +#define WM8955_PLLEN_MASK 0x0008 /* PLLEN */ +#define WM8955_PLLEN_SHIFT 3 /* PLLEN */ +#define WM8955_PLLEN_WIDTH 1 /* PLLEN */ + +/* + * R44 (0x2C) - PLL Control 1 + */ +#define WM8955_N_MASK 0x01E0 /* N - [8:5] */ +#define WM8955_N_SHIFT 5 /* N - [8:5] */ +#define WM8955_N_WIDTH 4 /* N - [8:5] */ +#define WM8955_K_21_18_MASK 0x000F /* K(21:18) - [3:0] */ +#define WM8955_K_21_18_SHIFT 0 /* K(21:18) - [3:0] */ +#define WM8955_K_21_18_WIDTH 4 /* K(21:18) - [3:0] */ + +/* + * R45 (0x2D) - PLL Control 2 + */ +#define WM8955_K_17_9_MASK 0x01FF /* K(17:9) - [8:0] */ +#define WM8955_K_17_9_SHIFT 0 /* K(17:9) - [8:0] */ +#define WM8955_K_17_9_WIDTH 9 /* K(17:9) - [8:0] */ + +/* + * R46 (0x2E) - PLL Control 3 + */ +#define WM8955_K_8_0_MASK 0x01FF /* K(8:0) - [8:0] */ +#define WM8955_K_8_0_SHIFT 0 /* K(8:0) - [8:0] */ +#define WM8955_K_8_0_WIDTH 9 /* K(8:0) - [8:0] */ + +/* + * R59 (0x3B) - PLL Control 4 + */ +#define WM8955_KEN 0x0080 /* KEN */ +#define WM8955_KEN_MASK 0x0080 /* KEN */ +#define WM8955_KEN_SHIFT 7 /* KEN */ +#define WM8955_KEN_WIDTH 1 /* KEN */ + +#endif -- GitLab From 56927eb054abd2c7371c769f359cc49a04ab488e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 18 Dec 2009 13:11:12 +0000 Subject: [PATCH 0064/3892] ASoC: Set AIF word length for WM8904 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8904.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 8310e5d14b83..e44ee31c2184 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1503,6 +1503,23 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream, wm8904->bclk = snd_soc_params_to_bclk(params); } + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + aif1 |= 0x40; + break; + case SNDRV_PCM_FORMAT_S24_LE: + aif1 |= 0x80; + break; + case SNDRV_PCM_FORMAT_S32_LE: + aif1 |= 0xc0; + break; + default: + return -EINVAL; + } + + dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk); ret = wm8904_configure_clocking(codec); -- GitLab From 18240b67c8ca5efbbb2e8bb11942cc3db033fb16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 18 Dec 2009 14:20:35 +0000 Subject: [PATCH 0065/3892] ASoC: Host clock2 read up in WM8904 FLL configuration Avoids skipping over the read for disable cases. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index e44ee31c2184..992a7f23df5c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1893,6 +1893,8 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source, Fout == wm8904->fll_fout) return 0; + clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); + if (Fout == 0) { dev_dbg(codec->dev, "FLL disabled\n"); @@ -1936,7 +1938,6 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source, /* Save current state then disable the FLL and SYSCLK to avoid * misclocking */ - clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2); fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1); snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2, WM8904_CLK_SYS_ENA, 0); -- GitLab From 0c2fd1bf4c6cb6095d8b3088d285167e66c12147 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Dec 2009 16:41:39 +0100 Subject: [PATCH 0066/3892] ALSA: hda - Check class to identify Nvidia controller chips Instead of listing all individual PCI IDs, check the matching with the PCI class together with the vendor id for Nvidia. This simplifies the pci id entries. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9b56f937913e..93eaf4fc39be 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2694,32 +2694,10 @@ static struct pci_device_id azx_ids[] = { /* ULI M5461 */ { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, /* NVIDIA MCP */ - { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, /* Creative X-Fi (CA0110-IBG) */ -- GitLab From bc85b25e5de17d714e8001cb3dc0feb66eac2750 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Sat, 19 Dec 2009 19:45:43 +0800 Subject: [PATCH 0067/3892] hwrng: nomadik - Add hardware RNG driver The hardware random number generator by ST is used in both the Nomadik 8815 SoC and the U8500. It returns 16 bits every 400ns with automatic delay if a read is issued too early. It depends on PLAT_NOMADIK. Signed-off-by: Alessandro Rubini Acked-by: Andrea Gallo Acked-by: Matt Mackall Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 12 ++++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/nomadik-rng.c | 103 +++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 drivers/char/hw_random/nomadik-rng.c diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 87060266ef91..6ea1014697d1 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -186,3 +186,15 @@ config HW_RANDOM_MXC_RNGA module will be called mxc-rnga. If unsure, say Y. + +config HW_RANDOM_NOMADIK + tristate "ST-Ericsson Nomadik Random Number Generator support" + depends on HW_RANDOM && PLAT_NOMADIK + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on ST-Ericsson SoCs (8815 and 8500). + + To compile this driver as a module, choose M here: the + module will be called nomadik-rng. + + If unsure, say Y. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 5eeb1303f0d0..4273308aa1e3 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o +obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c new file mode 100644 index 000000000000..a8b4c4010144 --- /dev/null +++ b/drivers/char/hw_random/nomadik-rng.c @@ -0,0 +1,103 @@ +/* + * Nomadik RNG support + * Copyright 2009 Alessandro Rubini + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + void __iomem *base = (void __iomem *)rng->priv; + + /* + * The register is 32 bits and gives 16 random bits (low half). + * A subsequent read will delay the core for 400ns, so we just read + * once and accept the very unlikely very small delay, even if wait==0. + */ + *(u16 *)data = __raw_readl(base + 8) & 0xffff; + return 2; +} + +/* we have at most one RNG per machine, granted */ +static struct hwrng nmk_rng = { + .name = "nomadik", + .read = nmk_rng_read, +}; + +static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id) +{ + void __iomem *base; + int ret; + + ret = amba_request_regions(dev, dev->dev.init_name); + if (ret) + return ret; + ret = -ENOMEM; + base = ioremap(dev->res.start, resource_size(&dev->res)); + if (!base) + goto out_release; + nmk_rng.priv = (unsigned long)base; + ret = hwrng_register(&nmk_rng); + if (ret) + goto out_unmap; + return 0; + +out_unmap: + iounmap(base); +out_release: + amba_release_regions(dev); + return ret; +} + +static int nmk_rng_remove(struct amba_device *dev) +{ + void __iomem *base = (void __iomem *)nmk_rng.priv; + hwrng_unregister(&nmk_rng); + iounmap(base); + amba_release_regions(dev); + return 0; +} + +static struct amba_id nmk_rng_ids[] = { + { + .id = 0x000805e1, + .mask = 0x000fffff, /* top bits are rev and cfg: accept all */ + }, + {0, 0}, +}; + +static struct amba_driver nmk_rng_driver = { + .drv = { + .owner = THIS_MODULE, + .name = "rng", + }, + .probe = nmk_rng_probe, + .remove = nmk_rng_remove, + .id_table = nmk_rng_ids, +}; + +static int __init nmk_rng_init(void) +{ + return amba_driver_register(&nmk_rng_driver); +} + +static void __devexit nmk_rng_exit(void) +{ + amba_driver_unregister(&nmk_rng_driver); +} + +module_init(nmk_rng_init); +module_exit(nmk_rng_exit); + +MODULE_LICENSE("GPL"); -- GitLab From d2392ba06a477cf1876ce3d505b7cd77e295cfd4 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Sat, 19 Dec 2009 19:46:33 +0800 Subject: [PATCH 0068/3892] hwrng: nomadik - Add platform device for rng in cpu-8815 Signed-off-by: Alessandro Rubini Acked-by: Andrea Gallo Acked-by: Matt Mackall Signed-off-by: Herbert Xu --- arch/arm/mach-nomadik/cpu-8815.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c index f93c59634191..9bf33b30a025 100644 --- a/arch/arm/mach-nomadik/cpu-8815.c +++ b/arch/arm/mach-nomadik/cpu-8815.c @@ -86,11 +86,19 @@ static struct amba_device cpu8815_amba_gpio[] = { }, }; +static struct amba_device cpu8815_amba_rng = { + .dev = { + .init_name = "rng", + }, + __MEM_4K_RESOURCE(NOMADIK_RNG_BASE), +}; + static struct amba_device *amba_devs[] __initdata = { cpu8815_amba_gpio + 0, cpu8815_amba_gpio + 1, cpu8815_amba_gpio + 2, cpu8815_amba_gpio + 3, + &cpu8815_amba_rng }; static int __init cpu8815_init(void) -- GitLab From a28b460ec7968f430a2d6ea2809b249ee9fe1d28 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 21 Dec 2009 15:56:24 +0900 Subject: [PATCH 0069/3892] sh: Fix up hw-breakpoints build for API changes. The event callback handling has been removed in favour of going through a generic event handler to handle overflows. Follows the x86 change. Signed-off-by: Paul Mundt --- arch/sh/kernel/hw_breakpoint.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c index ff3cb3d7df8f..75b8c471120f 100644 --- a/arch/sh/kernel/hw_breakpoint.c +++ b/arch/sh/kernel/hw_breakpoint.c @@ -302,8 +302,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, return ret; } - if (bp->callback) - ret = arch_store_info(bp); + ret = arch_store_info(bp); if (ret < 0) return ret; @@ -368,7 +367,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) break; } - (bp->callback)(bp, args->regs); + perf_bp_event(bp, args->regs); rcu_read_unlock(); } -- GitLab From 6c0ee6a4bba0e21eb0fb4de5bdac03c11b74242d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 21 Dec 2009 17:35:00 +0900 Subject: [PATCH 0070/3892] sh: hw-breakpoint support requires perf events. This follows the x86 change to select perf events when hw_breakpoint support is enabled. This fixes up build issues where perf events can otherwise be disabled on their own. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 185e9af251cf..fa76d6264dff 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -43,6 +43,7 @@ config SUPERH32 select HAVE_FUNCTION_GRAPH_TRACER select HAVE_ARCH_KGDB select HAVE_HW_BREAKPOINT if CPU_SH4A + select PERF_EVENTS if HAVE_HW_BREAKPOINT select ARCH_HIBERNATION_POSSIBLE if MMU config SUPERH64 -- GitLab From ad8decb7f5dfd556e4a8400e37b127cd20d8e4c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 20 Dec 2009 19:01:50 +0100 Subject: [PATCH 0071/3892] ALSA: jazz16: Add support for Media Vision Jazz16 chipset This is one of Sound Blaster Pro compatible chipsets which is supported by Linux OSS driver and was missing native supoort for ALSA. The Jazz16 audio codec is Crystal CS4216 which is capable of playback and recording up to 48 kHz stereo. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- include/sound/sb.h | 1 + sound/isa/Kconfig | 16 ++ sound/isa/sb/Makefile | 2 + sound/isa/sb/jazz16.c | 385 +++++++++++++++++++++++++++++++++++++++ sound/isa/sb/sb8_main.c | 117 ++++++++++-- sound/isa/sb/sb_common.c | 3 + sound/isa/sb/sb_mixer.c | 3 + 7 files changed, 511 insertions(+), 16 deletions(-) create mode 100644 sound/isa/sb/jazz16.c diff --git a/include/sound/sb.h b/include/sound/sb.h index 4e62ee1e4115..95353542256a 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -33,6 +33,7 @@ enum sb_hw_type { SB_HW_20, SB_HW_201, SB_HW_PRO, + SB_HW_JAZZ16, /* Media Vision Jazz16 */ SB_HW_16, SB_HW_16CSP, /* SB16 with CSP chip */ SB_HW_ALS100, /* Avance Logic ALS100 chip */ diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 194af3b01e13..755a0a5f0e3f 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -239,6 +239,22 @@ config SND_INTERWAVE_STB To compile this driver as a module, choose M here: the module will be called snd-interwave-stb. +config SND_JAZZ16 + tristate "Media Vision Jazz16 card and compatibles" + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_SB8_DSP + help + Say Y here to include support for soundcards based on the + Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16), + codec MVA416 (CS4216) and mixer MVA514 (ICS2514). + Media Vision's Jazz16 cards were sold under names Pro Sonic 16, + Premium 3-D and Pro 3-D. There were also OEMs cards with the + Jazz16 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-jazz16. + config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" select SND_OPL3_LIB diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index faeffceb01b7..af3669681788 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile @@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o snd-sbawe-objs := sbawe.o emu8000.o snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o snd-es968-objs := es968.o +snd-jazz16-objs := jazz16.o # Toplevel Module Dependency obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o @@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o obj-$(CONFIG_SND_SB16) += snd-sb16.o obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o obj-$(CONFIG_SND_ES968) += snd-es968.o +obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c new file mode 100644 index 000000000000..d52966b75846 --- /dev/null +++ b/sound/isa/sb/jazz16.c @@ -0,0 +1,385 @@ + +/* + * jazz16.c - driver for Media Vision Jazz16 based soundcards. + * Copyright (C) 2009 Krzysztof Helt + * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman. + * Based on OSS Sound Blaster driver. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include + +#define PFX "jazz16: " + +MODULE_DESCRIPTION("Media Vision Jazz16"); +MODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," + "{RTL,RTL3000}}"); + +MODULE_AUTHOR("Krzysztof Helt "); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ +static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard."); +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for jazz16 driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver."); +module_param_array(dma8, int, NULL, 0444); +MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver."); +module_param_array(dma16, int, NULL, 0444); +MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver."); + +#define SB_JAZZ16_WAKEUP 0xaf +#define SB_JAZZ16_SET_PORTS 0x50 +#define SB_DSP_GET_JAZZ_BRD_REV 0xfa +#define SB_JAZZ16_SET_DMAINTR 0xfb +#define SB_DSP_GET_JAZZ_MODEL 0xfe + +struct snd_card_jazz16 { + struct snd_sb *chip; +}; + +static irqreturn_t jazz16_interrupt(int irq, void *chip) +{ + return snd_sb8dsp_interrupt(chip); +} + +static int __devinit jazz16_configure_ports(unsigned long port, + unsigned long mpu_port, int idx) +{ + unsigned char val; + + if (!request_region(0x201, 1, "jazz16 config")) { + snd_printk(KERN_ERR "config port region is already in use.\n"); + return -EBUSY; + } + outb(SB_JAZZ16_WAKEUP - idx, 0x201); + udelay(100); + outb(SB_JAZZ16_SET_PORTS + idx, 0x201); + udelay(100); + val = port & 0x70; + val |= (mpu_port & 0x30) >> 4; + outb(val, 0x201); + + release_region(0x201, 1); + return 0; +} + +static int __devinit jazz16_detect_board(unsigned long port, + unsigned long mpu_port) +{ + int err; + int val; + struct snd_sb chip; + + if (!request_region(port, 0x10, "jazz16")) { + snd_printk(KERN_ERR "I/O port region is already in use.\n"); + return -EBUSY; + } + /* just to call snd_sbdsp_command/reset/get_byte() */ + chip.port = port; + + err = snd_sbdsp_reset(&chip); + if (err < 0) + for (val = 0; val < 4; val++) { + err = jazz16_configure_ports(port, mpu_port, val); + if (err < 0) + break; + + err = snd_sbdsp_reset(&chip); + if (!err) + break; + } + if (err < 0) { + err = -ENODEV; + goto err_unmap; + } + if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) { + err = -EBUSY; + goto err_unmap; + } + val = snd_sbdsp_get_byte(&chip); + if (val >= 0x30) + snd_sbdsp_get_byte(&chip); + + if ((val & 0xf0) != 0x10) { + err = -ENODEV; + goto err_unmap; + } + if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) { + err = -EBUSY; + goto err_unmap; + } + snd_sbdsp_get_byte(&chip); + err = snd_sbdsp_get_byte(&chip); + snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n", + val, err); + + err = 0; + +err_unmap: + release_region(port, 0x10); + return err; +} + +static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) +{ + static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, + 0, 2, 5, 0, 0, 0, 0, 6 }; + static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; + + if (jazz_dma_bits[chip->dma8] == 0 || + jazz_dma_bits[chip->dma16] == 0 || + jazz_irq_bits[chip->irq] == 0) + return -EINVAL; + + if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR)) + return -EBUSY; + + if (!snd_sbdsp_command(chip, + jazz_dma_bits[chip->dma8] | + (jazz_dma_bits[chip->dma16] << 4))) + return -EBUSY; + + if (!snd_sbdsp_command(chip, + jazz_irq_bits[chip->irq] | + (jazz_irq_bits[mpu_irq] << 4))) + return -EBUSY; + + return 0; +} + +static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) +{ + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please specify port\n"); + return 0; + } + if (dma16[dev] != SNDRV_AUTO_DMA && + dma16[dev] != 5 && dma16[dev] != 7) { + snd_printk(KERN_ERR "dma16 must be 5 or 7"); + return 0; + } + return 1; +} + +static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) +{ + struct snd_card *card; + struct snd_card_jazz16 *jazz16; + struct snd_sb *chip; + struct snd_opl3 *opl3; + static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1}; + static int possible_dmas8[] = {1, 3, -1}; + static int possible_dmas16[] = {5, 7, -1}; + int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq; + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_card_jazz16), &card); + if (err < 0) + return err; + + jazz16 = card->private_data; + + xirq = irq[dev]; + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + err = -EBUSY; + goto err_free; + } + } + xdma8 = dma8[dev]; + if (xdma8 == SNDRV_AUTO_DMA) { + xdma8 = snd_legacy_find_free_dma(possible_dmas8); + if (xdma8 < 0) { + snd_printk(KERN_ERR "unable to find a free DMA8\n"); + err = -EBUSY; + goto err_free; + } + } + xdma16 = dma16[dev]; + if (xdma16 == SNDRV_AUTO_DMA) { + xdma16 = snd_legacy_find_free_dma(possible_dmas16); + if (xdma16 < 0) { + snd_printk(KERN_ERR "unable to find a free DMA16\n"); + err = -EBUSY; + goto err_free; + } + } + + xmpu_port = mpu_port[dev]; + if (xmpu_port == SNDRV_AUTO_PORT) + xmpu_port = 0; + err = jazz16_detect_board(port[dev], xmpu_port); + if (err < 0) { + printk(KERN_ERR "Media Vision Jazz16 board not detected\n"); + goto err_free; + } + err = snd_sbdsp_create(card, port[dev], irq[dev], + jazz16_interrupt, + dma8[dev], dma16[dev], + SB_HW_JAZZ16, + &chip); + if (err < 0) + goto err_free; + + xmpu_irq = mpu_irq[dev]; + if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT) + xmpu_irq = 0; + err = jazz16_configure_board(chip, xmpu_irq); + if (err < 0) { + printk(KERN_ERR "Media Vision Jazz16 configuration failed\n"); + goto err_free; + } + + jazz16->chip = chip; + + strcpy(card->driver, "jazz16"); + strcpy(card->shortname, "Media Vision Jazz16"); + sprintf(card->longname, + "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", + port[dev], xirq, xdma8, xdma16); + + err = snd_sb8dsp_pcm(chip, 0, NULL); + if (err < 0) + goto err_free; + err = snd_sbmixer_new(chip); + if (err < 0) + goto err_free; + + err = snd_opl3_create(card, chip->port, chip->port + 2, + OPL3_HW_AUTO, 1, &opl3); + if (err < 0) + snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", + chip->port, chip->port + 2); + else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto err_free; + } + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + + if (snd_mpu401_uart_new(card, 0, + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, + NULL) < 0) + snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", + mpu_port[dev]); + } + + snd_card_set_dev(card, devptr); + + err = snd_card_register(card); + if (err < 0) + goto err_free; + + dev_set_drvdata(devptr, card); + return 0; + +err_free: + snd_card_free(card); + return err; +} + +static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev) +{ + struct snd_card *card = dev_get_drvdata(devptr); + + dev_set_drvdata(devptr, NULL); + snd_card_free(card); + return 0; +} + +#ifdef CONFIG_PM +static int snd_jazz16_suspend(struct device *pdev, unsigned int n, + pm_message_t state) +{ + struct snd_card *card = dev_get_drvdata(pdev); + struct snd_card_jazz16 *acard = card->private_data; + struct snd_sb *chip = acard->chip; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + snd_pcm_suspend_all(chip->pcm); + snd_sbmixer_suspend(chip); + return 0; +} + +static int snd_jazz16_resume(struct device *pdev, unsigned int n) +{ + struct snd_card *card = dev_get_drvdata(pdev); + struct snd_card_jazz16 *acard = card->private_data; + struct snd_sb *chip = acard->chip; + + snd_sbdsp_reset(chip); + snd_sbmixer_resume(chip); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + +static struct isa_driver snd_jazz16_driver = { + .match = snd_jazz16_match, + .probe = snd_jazz16_probe, + .remove = __devexit_p(snd_jazz16_remove), +#ifdef CONFIG_PM + .suspend = snd_jazz16_suspend, + .resume = snd_jazz16_resume, +#endif + .driver = { + .name = "jazz16" + }, +}; + +static int __init alsa_card_jazz16_init(void) +{ + return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_jazz16_exit(void) +{ + isa_unregister_driver(&snd_jazz16_driver); +} + +module_init(alsa_card_jazz16_init) +module_exit(alsa_card_jazz16_exit) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 658d55769c9c..3222aed5fac6 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; + unsigned char format; + unsigned char stereo = runtime->channels > 1; + int dma; rate = runtime->rate; switch (chip->hardware) { + case SB_HW_JAZZ16: + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + if (chip->mode & SB_MODE_CAPTURE_16) + return -EBUSY; + else + chip->mode |= SB_MODE_PLAYBACK_16; + } + chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; + break; case SB_HW_PRO: if (runtime->channels > 1) { if (snd_BUG_ON(rate != SB8_RATE(11025) && @@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) default: return -EINVAL; } + if (chip->mode & SB_MODE_PLAYBACK_16) { + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + dma = chip->dma16; + } else { + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + chip->mode |= SB_MODE_PLAYBACK_8; + dma = chip->dma8; + } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); - if (runtime->channels > 1) { + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) { /* set playback stereo mode */ spin_lock(&chip->mixer_lock); mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); @@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) /* Soundblaster hardware programming reference guide, 3-23 */ snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); runtime->dma_area[0] = 0x80; - snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE); + snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); /* force interrupt */ - chip->mode = SB_MODE_HALT; snd_sbdsp_command(chip, SB_DSP_OUTPUT); snd_sbdsp_command(chip, 0); snd_sbdsp_command(chip, 0); } snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (runtime->channels > 1) { + if (stereo) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); spin_lock(&chip->mixer_lock); /* save output filter status and turn it off */ @@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->playback_format != SB_DSP_OUTPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0; } @@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } spin_unlock_irqrestore(&chip->reg_lock, flags); - chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT; return 0; } @@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; + unsigned char format; + unsigned char stereo = runtime->channels > 1; + int dma; rate = runtime->rate; switch (chip->hardware) { + case SB_HW_JAZZ16: + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + if (chip->mode & SB_MODE_PLAYBACK_16) + return -EBUSY; + else + chip->mode |= SB_MODE_CAPTURE_16; + } + chip->capture_format = SB_DSP_LO_INPUT_AUTO; + break; case SB_HW_PRO: if (runtime->channels > 1) { if (snd_BUG_ON(rate != SB8_RATE(11025) && @@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) default: return -EINVAL; } + if (chip->mode & SB_MODE_CAPTURE_16) { + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + dma = chip->dma16; + } else { + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + chip->mode |= SB_MODE_CAPTURE_8; + dma = chip->dma8; + } size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); - if (runtime->channels > 1) + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (runtime->channels > 1) { + if (stereo) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); spin_lock(&chip->mixer_lock); /* save input filter status and turn it off */ @@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->capture_format != SB_DSP_INPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); return 0; } @@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } spin_unlock_irqrestore(&chip->reg_lock, flags); - chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT; return 0; } @@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) snd_sb_ack_8bit(chip); switch (chip->mode) { - case SB_MODE_PLAYBACK_8: /* ok.. playback is active */ + case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ + if (chip->hardware != SB_HW_JAZZ16) + break; + /* fallthru */ + case SB_MODE_PLAYBACK_8: substream = chip->playback_substream; runtime = substream->runtime; if (chip->playback_format == SB_DSP_OUTPUT) snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); snd_pcm_period_elapsed(substream); break; + case SB_MODE_CAPTURE_16: + if (chip->hardware != SB_HW_JAZZ16) + break; + /* fallthru */ case SB_MODE_CAPTURE_8: substream = chip->capture_substream; runtime = substream->runtime; @@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma; - if (chip->mode != SB_MODE_PLAYBACK_8) + if (chip->mode & SB_MODE_PLAYBACK_8) + dma = chip->dma8; + else if (chip->mode & SB_MODE_PLAYBACK_16) + dma = chip->dma16; + else return 0; - ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size); + ptr = snd_dma_pointer(dma, chip->p_dma_size); return bytes_to_frames(substream->runtime, ptr); } @@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma; - if (chip->mode != SB_MODE_CAPTURE_8) + if (chip->mode & SB_MODE_CAPTURE_8) + dma = chip->dma8; + else if (chip->mode & SB_MODE_CAPTURE_16) + dma = chip->dma16; + else return 0; - ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size); + ptr = snd_dma_pointer(dma, chip->c_dma_size); return bytes_to_frames(substream->runtime, ptr); } @@ -446,6 +509,13 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) runtime->hw = snd_sb8_capture; } switch (chip->hardware) { + case SB_HW_JAZZ16: + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; + runtime->hw.rate_min = 4000; + runtime->hw.rate_max = 50000; + runtime->hw.channels_max = 2; + break; case SB_HW_PRO: runtime->hw.rate_max = 44100; runtime->hw.channels_max = 2; @@ -468,6 +538,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) } snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clock); + if (chip->dma8 > 3 || chip->dma16 >= 0) { + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); + runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; + runtime->hw.period_bytes_max = 128 * 1024 * 1024; + } return 0; } @@ -480,6 +558,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream) chip->capture_substream = NULL; spin_lock_irqsave(&chip->open_lock, flags); chip->open &= ~SB_OPEN_PCM; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + chip->mode &= ~SB_MODE_PLAYBACK; + else + chip->mode &= ~SB_MODE_CAPTURE; spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } @@ -515,6 +597,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; + size_t max_prealloc = 64 * 1024; if (rpcm) *rpcm = NULL; @@ -527,9 +610,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); + if (chip->dma8 > 3 || chip->dma16 >= 0) + max_prealloc = 128 * 1024; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), - 64*1024, 64*1024); + 64*1024, max_prealloc); if (rpcm) *rpcm = pcm; diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 27a651502251..eae6c1c0eff9 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip) case SB_HW_CS5530: str = "16 (CS5530)"; break; + case SB_HW_JAZZ16: + str = "Pro (Jazz16)"; + break; default: return -ENODEV; } diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 8cfc41fbe368..6496822c1808 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -779,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; case SB_HW_PRO: + case SB_HW_JAZZ16: if ((err = snd_sbmixer_init(chip, snd_sbpro_controls, ARRAY_SIZE(snd_sbpro_controls), @@ -929,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip) save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: @@ -955,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip) restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: -- GitLab From ee7c343c0134bf126b4235e65c407711b77174da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 21 Dec 2009 12:41:37 +0100 Subject: [PATCH 0072/3892] ALSA: pcm - Add missing inclusion of linux/vmalloc.h Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index d9727c74b2e1..d6d49d6651f9 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include -- GitLab From 254416aae70ab2e6b57fd79782c8a67196234d02 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 9 Dec 2009 16:43:52 -0500 Subject: [PATCH 0073/3892] wireless: report reasonable bitrate for MCS rates through wext Previously, cfg80211 had reported "0" for MCS (i.e. 802.11n) bitrates through the wireless extensions interface. However, nl80211 was converting MCS rates into a reasonable bitrate number. This patch moves the nl80211 code to cfg80211 where it is now shared between both the nl80211 interface and the wireless extensions interface. Signed-off-by: John W. Linville --- net/wireless/core.h | 2 ++ net/wireless/nl80211.c | 37 ++----------------------------------- net/wireless/util.c | 33 +++++++++++++++++++++++++++++++++ net/wireless/wext-compat.c | 5 +---- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/net/wireless/core.h b/net/wireless/core.h index 4ef3efc94106..35b712127143 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -378,6 +378,8 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type); +u16 cfg80211_calculate_bitrate(struct rate_info *rate); + #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a6028433e3a0..7cb0d647fc34 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1637,39 +1637,6 @@ static int parse_station_flags(struct genl_info *info, return 0; } -static u16 nl80211_calculate_bitrate(struct rate_info *rate) -{ - int modulation, streams, bitrate; - - if (!(rate->flags & RATE_INFO_FLAGS_MCS)) - return rate->legacy; - - /* the formula below does only work for MCS values smaller than 32 */ - if (rate->mcs >= 32) - return 0; - - modulation = rate->mcs & 7; - streams = (rate->mcs >> 3) + 1; - - bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? - 13500000 : 6500000; - - if (modulation < 4) - bitrate *= (modulation + 1); - else if (modulation == 4) - bitrate *= (modulation + 2); - else - bitrate *= (modulation + 3); - - bitrate *= streams; - - if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) - bitrate = (bitrate / 9) * 10; - - /* do NOT round down here */ - return (bitrate + 50000) / 100000; -} - static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, u8 *mac_addr, struct station_info *sinfo) @@ -1716,8 +1683,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (!txrate) goto nla_put_failure; - /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ - bitrate = nl80211_calculate_bitrate(&sinfo->txrate); + /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = cfg80211_calculate_bitrate(&sinfo->txrate); if (bitrate > 0) NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); diff --git a/net/wireless/util.c b/net/wireless/util.c index 59361fdcb5d0..a3c841a255db 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -720,3 +720,36 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return err; } + +u16 cfg80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 584eb4826e02..2fa8de1140e9 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1256,10 +1256,7 @@ int cfg80211_wext_giwrate(struct net_device *dev, if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) return -EOPNOTSUPP; - rate->value = 0; - - if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) - rate->value = 100000 * sinfo.txrate.legacy; + rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); return 0; } -- GitLab From 15920d8afc87861672e16fa95ae2764b065d6dd3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 30 Aug 2009 20:18:41 -0600 Subject: [PATCH 0074/3892] wireless: hostap, fix oops due to early probing interrupt BugLink: https://bugs.launchpad.net/ubuntu/+bug/254837 Spurious shared interrupts or early probing interrupts can cause the hostap interrupt handler to oops before the driver has fully configured the IO base port addresses. In some cases the oops can be because the hardware shares an interrupt line, on other cases it is due to a race condition between probing for the hardware and configuring the IO base port. The latter occurs because the probing is required to determin the hardware port address which is only determined when the probe can interrupt the hardware (catch 22). This patch catches this pre-configured condition to avoid the oops. Signed-off-by: Colin Ian King Signed-off-by: Stefan Bader Acked-by: Tim Gardner Acked-by: Stefan Bader Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index ff9b5c882184..d70732819423 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) int events = 0; u16 ev; + /* Detect early interrupt before driver is fully configued */ + if (!dev->base_addr) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", + dev->name); + } + return IRQ_HANDLED; + } + iface = netdev_priv(dev); local = iface->local; -- GitLab From abe60632f311d515b082b450504ee24006023951 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 17:46:18 +0100 Subject: [PATCH 0075/3892] mac80211: make station management completely depend on vif The station management currently uses the virtual interface, but you cannot add the same station to multiple virtual interfaces if you're communicating with it in multiple ways. This restriction should be lifted so that in the future we can, for instance, support bluetooth 3 with an access point that mac80211 is already associated to. We can do that by requiring all sta_info_get users to provide the virtual interface and making the RX code aware that an address may match more than one station struct. Thanks to the previous patches this one isn't all that large and except for the RX and TX status paths changes has low complexity. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 3 +- net/mac80211/agg-tx.c | 4 +- net/mac80211/cfg.c | 25 ++++---- net/mac80211/ibss.c | 2 +- net/mac80211/key.c | 2 +- net/mac80211/mesh_hwmp.c | 2 +- net/mac80211/mesh_plink.c | 4 +- net/mac80211/mlme.c | 10 ++-- net/mac80211/rx.c | 119 ++++++++++++++++++++------------------ net/mac80211/sta_info.c | 18 +++--- net/mac80211/sta_info.h | 29 +++++++++- net/mac80211/status.c | 8 ++- net/mac80211/tx.c | 9 ++- 13 files changed, 134 insertions(+), 101 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 51c7dc3c4c3b..f16d49d474b4 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -83,12 +83,11 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 initiator, u16 reason) { - struct ieee80211_local *local = sdata->local; struct sta_info *sta; rcu_read_lock(); - sta = sta_info_get(local, ra); + sta = sta_info_get(sdata, ra); if (!sta) { rcu_read_unlock(); return; diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5e3a7eccef5a..b05de532c379 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -441,7 +441,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) } rcu_read_lock(); - sta = sta_info_get(local, ra); + sta = sta_info_get(sdata, ra); if (!sta) { rcu_read_unlock(); #ifdef CONFIG_MAC80211_HT_DEBUG @@ -564,7 +564,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) #endif /* CONFIG_MAC80211_HT_DEBUG */ rcu_read_lock(); - sta = sta_info_get(local, ra); + sta = sta_info_get(sdata, ra); if (!sta) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Could not find station: %pM\n", ra); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 93ee1fd5c08d..14e1f4015a72 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -150,7 +150,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get(sdata->local, mac_addr); + sta = sta_info_get(sdata, mac_addr); if (!sta) { ieee80211_key_free(key); err = -ENOENT; @@ -181,7 +181,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (mac_addr) { ret = -ENOENT; - sta = sta_info_get(sdata->local, mac_addr); + sta = sta_info_get(sdata, mac_addr); if (!sta) goto out_unlock; @@ -228,7 +228,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get(sdata->local, mac_addr); + sta = sta_info_get(sdata, mac_addr); if (!sta) goto out; @@ -414,15 +414,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; int ret = -ENOENT; rcu_read_lock(); - /* XXX: verify sta->dev == dev */ - - sta = sta_info_get(local, mac); + sta = sta_info_get(sdata, mac); if (sta) { ret = 0; sta_set_sinfo(sta, sinfo); @@ -778,8 +776,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, if (mac) { rcu_read_lock(); - /* XXX: get sta belonging to dev */ - sta = sta_info_get(local, mac); + sta = sta_info_get(sdata, mac); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -800,14 +797,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, u8 *mac, struct station_parameters *params) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; struct ieee80211_sub_if_data *vlansdata; rcu_read_lock(); - /* XXX: get sta belonging to dev */ - sta = sta_info_get(local, mac); + sta = sta_info_get(sdata, mac); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -846,7 +843,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { - struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; @@ -855,7 +851,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); rcu_read_lock(); - sta = sta_info_get(local, next_hop); + sta = sta_info_get(sdata, next_hop); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -894,7 +890,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { - struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; @@ -903,7 +898,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, rcu_read_lock(); - sta = sta_info_get(local, next_hop); + sta = sta_info_get(sdata, next_hop); if (!sta) { rcu_read_unlock(); return -ENOENT; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 10d13856f86c..1925be9b82fb 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -252,7 +252,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, mgmt->sa); + sta = sta_info_get(sdata, mgmt->sa); if (sta) { u32 prev_rates; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 659a42d529e3..ac1a777674f6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key, */ /* same here, the AP could be using QoS */ - ap = sta_info_get(key->local, key->sdata->u.mgd.bssid); + ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); if (ap) { if (test_sta_flags(ap, WLAN_STA_WME)) key->conf.flags |= diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 833b2f3670c5..b836892f0ba9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, bool process = true; rcu_read_lock(); - sta = sta_info_get(local, mgmt->sa); + sta = sta_info_get(sdata, mgmt->sa); if (!sta) { rcu_read_unlock(); return 0; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0f7c6e6a4248..8fcf56ee7743 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -234,7 +234,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data rcu_read_lock(); - sta = sta_info_get(local, hw_addr); + sta = sta_info_get(sdata, hw_addr); if (!sta) { sta = mesh_plink_alloc(sdata, hw_addr, rates); if (!sta) { @@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m rcu_read_lock(); - sta = sta_info_get(local, mgmt->sa); + sta = sta_info_get(sdata, mgmt->sa); if (!sta && ftype != PLINK_OPEN) { mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); rcu_read_unlock(); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6dc7b5ad9a41..c16667a7c8df 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -202,7 +202,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); rcu_read_lock(); - sta = sta_info_get(local, bssid); + sta = sta_info_get(sdata, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED); @@ -1070,7 +1070,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, netif_carrier_off(sdata->dev); rcu_read_lock(); - sta = sta_info_get(local, bssid); + sta = sta_info_get(sdata, bssid); if (sta) ieee80211_sta_tear_down_BA_sessions(sta); rcu_read_unlock(); @@ -1109,7 +1109,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, bssid); + sta = sta_info_get(sdata, bssid); if (!sta) { rcu_read_unlock(); return; @@ -1489,7 +1489,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); /* Add STA entry for the AP */ - sta = sta_info_get(local, wk->bss->cbss.bssid); + sta = sta_info_get(sdata, wk->bss->cbss.bssid); if (!sta) { newsta = true; @@ -1857,7 +1857,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, bssid); + sta = sta_info_get(sdata, bssid); if (WARN_ON(!sta)) { rcu_read_unlock(); return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f237df408378..5bae28693da8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1472,7 +1472,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; struct net_device *dev = sdata->dev; - struct ieee80211_local *local = rx->local; struct sk_buff *skb, *xmit_skb; struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; struct sta_info *dsta; @@ -1495,8 +1494,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) printk(KERN_DEBUG "%s: failed to clone " "multicast frame\n", dev->name); } else { - dsta = sta_info_get(local, skb->data); - if (dsta && dsta->sdata->dev == dev) { + dsta = sta_info_get(sdata, skb->data); + if (dsta) { /* * The destination station is associated to * this AP (in this VLAN), so send the frame @@ -2363,6 +2362,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, int prepares; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; + struct sta_info *sta, *tmp; + bool found_sta = false; hdr = (struct ieee80211_hdr *)skb->data; memset(&rx, 0, sizeof(rx)); @@ -2379,68 +2380,76 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); - rx.sta = sta_info_get(local, hdr->addr2); - if (rx.sta) - rx.sdata = rx.sta->sdata; - - if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(rx.sdata, &rx, hdr); - if (prepares) { - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - } else - prev = rx.sdata; + if (ieee80211_is_data(hdr->frame_control)) { + for_each_sta_info(local, hdr->addr2, sta, tmp) { + rx.sta = sta; + found_sta = true; + rx.sdata = sta->sdata; + + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + if (prepares) { + if (status->flag & RX_FLAG_MMIC_ERROR) { + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + } else + prev = rx.sdata; + } } - } else list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) - continue; + } + if (!found_sta) { + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; - if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - continue; + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(sdata, &rx, hdr); + rx.sta = sta_info_get(sdata, hdr->addr2); - if (!prepares) - continue; + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(sdata, &rx, hdr); - if (status->flag & RX_FLAG_MMIC_ERROR) { - rx.sdata = sdata; - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - continue; - } + if (!prepares) + continue; - /* - * frame is destined for this interface, but if it's not - * also for the previous one we handle that after the - * loop to avoid copying the SKB once too much - */ + if (status->flag & RX_FLAG_MMIC_ERROR) { + rx.sdata = sdata; + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, + &rx); + continue; + } - if (!prev) { - prev = sdata; - continue; - } + /* + * frame is destined for this interface, but if it's + * not also for the previous one we handle that after + * the loop to avoid copying the SKB once too much + */ - /* - * frame was destined for the previous interface - * so invoke RX handlers for it - */ + if (!prev) { + prev = sdata; + continue; + } - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s\n", - wiphy_name(local->hw.wiphy), - prev->dev->name); - continue; + /* + * frame was destined for the previous interface + * so invoke RX handlers for it + */ + + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s\n", + wiphy_name(local->hw.wiphy), + prev->dev->name); + continue; + } + ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); + prev = sdata; } - ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); - prev = sdata; } if (prev) ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 71f370dd24bc..c58a23eea58c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -103,13 +103,16 @@ static int sta_info_hash_del(struct ieee80211_local *local, } /* protected by RCU */ -struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr) +struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, + const u8 *addr) { + struct ieee80211_local *local = sdata->local; struct sta_info *sta; sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); while (sta) { - if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) + if (sta->sdata == sdata && + memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) break; sta = rcu_dereference(sta->hnext); } @@ -377,7 +380,7 @@ int sta_info_insert(struct sta_info *sta) spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ - if (sta_info_get(local, sta->sta.addr)) { + if (sta_info_get(sdata, sta->sta.addr)) { spin_unlock_irqrestore(&local->sta_lock, flags); err = -EEXIST; goto out_free; @@ -843,11 +846,12 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, const u8 *addr) { - struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); + struct sta_info *sta, *nxt; - if (!sta) - return NULL; - return &sta->sta; + /* Just return a random station ... first in list ... */ + for_each_sta_info(hw_to_local(hw), addr, sta, nxt) + return &sta->sta; + return NULL; } EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b4810f6aa94f..c8208236e896 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -403,9 +403,34 @@ static inline u32 get_sta_flags(struct sta_info *sta) #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) /* - * Get a STA info, must have be under RCU read lock. + * Get a STA info, must be under RCU read lock. */ -struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr); +struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, + const u8 *addr); + +static inline +void for_each_sta_info_type_check(struct ieee80211_local *local, + const u8 *addr, + struct sta_info *sta, + struct sta_info *nxt) +{ +} + +#define for_each_sta_info(local, _addr, sta, nxt) \ + for ( /* initialise loop */ \ + sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ + nxt = sta ? rcu_dereference(sta->hnext) : NULL; \ + /* typecheck */ \ + for_each_sta_info_type_check(local, (_addr), sta, nxt), \ + /* continue condition */ \ + sta; \ + /* advance loop */ \ + sta = nxt, \ + nxt = sta ? rcu_dereference(sta->hnext) : NULL \ + ) \ + /* compare address and run code only if it matches */ \ + if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0) + /* * Get STA info by index, BROKEN! */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d78f36c64c7b..32fe327acf4e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -146,7 +146,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - struct sta_info *sta; + struct sta_info *sta, *tmp; int retry_count = -1, i; bool injected; @@ -166,9 +166,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) sband = local->hw.wiphy->bands[info->band]; - sta = sta_info_get(local, hdr->addr1); + for_each_sta_info(local, hdr->addr1, sta, tmp) { + /* skip wrong virtual interface */ + if (memcmp(hdr->addr2, sta->sdata->dev->dev_addr, ETH_ALEN)) + continue; - if (sta) { if (!(info->flags & IEEE80211_TX_STAT_ACK) && test_sta_flags(sta, WLAN_STA_PS_STA)) { /* diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8834cc93c716..b913bfc34a9f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1055,7 +1055,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) tx->sta = rcu_dereference(sdata->u.vlan.sta); if (!tx->sta) - tx->sta = sta_info_get(local, hdr->addr1); + tx->sta = sta_info_get(sdata, hdr->addr1); if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { @@ -1761,9 +1761,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ if (!is_multicast_ether_addr(hdr.addr1)) { rcu_read_lock(); - sta = sta_info_get(local, hdr.addr1); - /* XXX: in the future, use sdata to look up the sta */ - if (sta && sta->sdata == sdata) + sta = sta_info_get(sdata, hdr.addr1); + if (sta) sta_flags = get_sta_flags(sta); rcu_read_unlock(); } @@ -1922,7 +1921,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, ieee80211_tx(sdata, skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; - sta = sta_info_get(local, hdr->addr1); + sta = sta_info_get(sdata, hdr->addr1); ret = __ieee80211_tx(local, &skb, sta, true); if (ret != IEEE80211_TX_OK) -- GitLab From 47846c9b0c10808d9337d2e7d09361f3e0a0a71a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 17:46:19 +0100 Subject: [PATCH 0076/3892] mac80211: reduce reliance on netdev For bluetooth 3, we will most likely not have a netdev for a virtual interface (sdata), so prepare for that by reducing the reliance on having a netdev. This patch moves the name and address fields into the sdata struct and uses them from there all over. Some work is needed to keep them sync'ed, but that's not a lot of work and in slow paths anyway. In doing so, this also reduces the number of pointer dereferences in many places, because of things like sdata->dev->dev_addr becoming sdata->vif.addr. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 ++ net/mac80211/agg-rx.c | 6 ++-- net/mac80211/agg-tx.c | 14 ++++---- net/mac80211/cfg.c | 2 +- net/mac80211/debugfs_key.c | 2 +- net/mac80211/debugfs_netdev.c | 55 +++---------------------------- net/mac80211/debugfs_netdev.h | 9 ++--- net/mac80211/debugfs_sta.c | 2 +- net/mac80211/driver-ops.h | 4 +-- net/mac80211/driver-trace.h | 12 +++---- net/mac80211/ht.c | 6 ++-- net/mac80211/ibss.c | 32 +++++++++--------- net/mac80211/ieee80211_i.h | 5 ++- net/mac80211/iface.c | 62 +++++++++++++++++++++++++++++++++-- net/mac80211/main.c | 17 +++++++--- net/mac80211/mesh.c | 4 +-- net/mac80211/mesh_hwmp.c | 18 +++++----- net/mac80211/mesh_pathtbl.c | 6 ++-- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 62 +++++++++++++++++------------------ net/mac80211/pm.c | 2 +- net/mac80211/rx.c | 43 ++++++++++++------------ net/mac80211/scan.c | 2 +- net/mac80211/spectmgmt.c | 4 +-- net/mac80211/sta_info.c | 8 ++--- net/mac80211/status.c | 2 +- net/mac80211/tx.c | 33 +++++++++---------- net/mac80211/util.c | 14 ++++---- 28 files changed, 223 insertions(+), 207 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2aff4906b2ae..e94cc526b0f6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -659,12 +659,14 @@ struct ieee80211_conf { * @type: type of this virtual interface * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to + * @addr: address of this interface * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *). */ struct ieee80211_vif { enum nl80211_iftype type; struct ieee80211_bss_conf bss_conf; + u8 addr[ETH_ALEN]; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index f16d49d474b4..37ecdeddd5ac 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -135,7 +135,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer " - "for addba resp frame\n", sdata->dev->name); + "for addba resp frame\n", sdata->name); return; } @@ -143,10 +143,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b05de532c379..209be60564ce 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " - "for addba request frame\n", sdata->dev->name); + "for addba request frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); @@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer for " - "bar frame\n", sdata->dev->name); + "bar frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); memcpy(bar->ra, ra, ETH_ALEN); - memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); + memcpy(bar->ta, sdata->vif.addr, ETH_ALEN); bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; bar_control |= (u16)(tid << 12); @@ -489,7 +489,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " - "dropping start BA session", skb->dev->name); + "dropping start BA session", sdata->name); #endif return; } @@ -621,7 +621,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " - "dropping stop BA session", skb->dev->name); + "dropping stop BA session", sdata->name); #endif return; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 14e1f4015a72..fcfa1bf776a7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -729,7 +729,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } else sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (compare_ether_addr(mac, dev->dev_addr) == 0) + if (compare_ether_addr(mac, sdata->vif.addr) == 0) return -EINVAL; if (is_multicast_ether_addr(mac)) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index e0f5224630da..d12e743cb4e1 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D); KEY_CONF_FILE(hw_key_idx, D); KEY_FILE(flags, X); KEY_FILE(tx_rx_count, D); -KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n"); +KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n"); KEY_OPS(ifindex); static ssize_t key_algorithm_read(struct file *file, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 472b2039906c..5d9c797635a9 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -280,16 +280,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) } } -static int notif_registered; - void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) { char buf[10+IFNAMSIZ]; - if (!notif_registered) - return; - - sprintf(buf, "netdev:%s", sdata->dev->name); + sprintf(buf, "netdev:%s", sdata->name); sdata->debugfs.dir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); add_files(sdata); @@ -304,58 +299,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) sdata->debugfs.dir = NULL; } -static int netdev_notify(struct notifier_block *nb, - unsigned long state, - void *ndev) +void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) { - struct net_device *dev = ndev; struct dentry *dir; - struct ieee80211_sub_if_data *sdata; - char buf[10+IFNAMSIZ]; - - if (state != NETDEV_CHANGENAME) - return 0; - - if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) - return 0; - - if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) - return 0; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + char buf[10 + IFNAMSIZ]; dir = sdata->debugfs.dir; if (!dir) - return 0; + return; - sprintf(buf, "netdev:%s", dev->name); + sprintf(buf, "netdev:%s", sdata->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " "dir to %s\n", buf); - - return 0; -} - -static struct notifier_block mac80211_debugfs_netdev_notifier = { - .notifier_call = netdev_notify, -}; - -void ieee80211_debugfs_netdev_init(void) -{ - int err; - - err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); - if (err) { - printk(KERN_ERR - "mac80211: failed to install netdev notifier," - " disabling per-netdev debugfs!\n"); - } else - notif_registered = 1; -} - -void ieee80211_debugfs_netdev_exit(void) -{ - unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); - notif_registered = 0; } diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h index 7af731f0b731..79025e79f4d6 100644 --- a/net/mac80211/debugfs_netdev.h +++ b/net/mac80211/debugfs_netdev.h @@ -6,8 +6,7 @@ #ifdef CONFIG_MAC80211_DEBUGFS void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); -void ieee80211_debugfs_netdev_init(void); -void ieee80211_debugfs_netdev_exit(void); +void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata); #else static inline void ieee80211_debugfs_add_netdev( struct ieee80211_sub_if_data *sdata) @@ -15,10 +14,8 @@ static inline void ieee80211_debugfs_add_netdev( static inline void ieee80211_debugfs_remove_netdev( struct ieee80211_sub_if_data *sdata) {} -static inline void ieee80211_debugfs_netdev_init(void) -{} - -static inline void ieee80211_debugfs_netdev_exit(void) +static inline void ieee80211_debugfs_rename_netdev( + struct ieee80211_sub_if_data *sdata) {} #endif diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 3f41608c8081..374ff6f98a9c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_OPS(name) STA_FILE(aid, sta.aid, D); -STA_FILE(dev, sdata->dev->name, S); +STA_FILE(dev, sdata->name, S); STA_FILE(rx_packets, rx_packets, LU); STA_FILE(tx_packets, tx_packets, LU); STA_FILE(rx_bytes, rx_bytes, LU); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 921dd9c9ff62..a4002657dac5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -39,7 +39,7 @@ static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { int ret = local->ops->add_interface(&local->hw, conf); - trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret); + trace_drv_add_interface(local, conf->vif, ret); return ret; } @@ -47,7 +47,7 @@ static inline void drv_remove_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { local->ops->remove_interface(&local->hw, conf); - trace_drv_remove_interface(local, conf->mac_addr, conf->vif); + trace_drv_remove_interface(local, conf->vif); } static inline int drv_config(struct ieee80211_local *local, u32 changed) diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index ee94ea0c67e9..7b155b947209 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -70,11 +70,10 @@ TRACE_EVENT(drv_stop, TRACE_EVENT(drv_add_interface, TP_PROTO(struct ieee80211_local *local, - const u8 *addr, struct ieee80211_vif *vif, int ret), - TP_ARGS(local, addr, vif, ret), + TP_ARGS(local, vif, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -86,7 +85,7 @@ TRACE_EVENT(drv_add_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, addr, 6); + memcpy(__entry->addr, vif->addr, 6); __entry->ret = ret; ), @@ -97,10 +96,9 @@ TRACE_EVENT(drv_add_interface, ); TRACE_EVENT(drv_remove_interface, - TP_PROTO(struct ieee80211_local *local, - const u8 *addr, struct ieee80211_vif *vif), + TP_PROTO(struct ieee80211_local *local, struct ieee80211_vif *vif), - TP_ARGS(local, addr, vif), + TP_ARGS(local, vif), TP_STRUCT__entry( LOCAL_ENTRY @@ -111,7 +109,7 @@ TRACE_EVENT(drv_remove_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, addr, 6); + memcpy(__entry->addr, vif->addr, 6); ), TP_printk( diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 3787455fb696..45ebd062a2fb 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -106,7 +106,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " - "for delba frame\n", sdata->dev->name); + "for delba frame\n", sdata->name); return; } @@ -114,10 +114,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1925be9b82fb..ef6c6b2401d1 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); @@ -266,7 +266,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: updated supp_rates set " "for %pM based on beacon info (0x%llx | " "0x%llx -> 0x%llx)\n", - sdata->dev->name, + sdata->name, sta->sta.addr, (unsigned long long) prev_rates, (unsigned long long) supp_rates, @@ -364,7 +364,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %pM\n", - sdata->dev->name, mgmt->bssid); + sdata->name, mgmt->bssid); #endif ieee80211_sta_join_ibss(sdata, bss); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); @@ -393,7 +393,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", - sdata->dev->name, addr); + sdata->name, addr); return NULL; } @@ -402,7 +402,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", - wiphy_name(local->hw.wiphy), addr, sdata->dev->name); + wiphy_name(local->hw.wiphy), addr, sdata->name); #endif sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); @@ -466,7 +466,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " - "IBSS networks with same SSID (merge)\n", sdata->dev->name); + "IBSS networks with same SSID (merge)\n", sdata->name); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); } @@ -488,13 +488,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) * random number generator get different BSSID. */ get_random_bytes(bssid, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++) - bssid[i] ^= sdata->dev->dev_addr[i]; + bssid[i] ^= sdata->vif.addr[i]; bssid[0] &= ~0x01; bssid[0] |= 0x02; } printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", - sdata->dev->name, bssid); + sdata->name, bssid); sband = local->hw.wiphy->bands[ifibss->channel->band]; @@ -523,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) active_ibss = ieee80211_sta_active_ibss(sdata); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", - sdata->dev->name, active_ibss); + sdata->name, active_ibss); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (active_ibss) @@ -552,7 +552,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", - sdata->dev->name, bss->cbss.bssid); + sdata->name, bss->cbss.bssid); ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); @@ -571,7 +571,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) } else if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " - "join\n", sdata->dev->name); + "join\n", sdata->name); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); @@ -585,7 +585,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) return; } printk(KERN_DEBUG "%s: IBSS not allowed on" - " %d MHz\n", sdata->dev->name, + " %d MHz\n", sdata->name, local->hw.conf.channel->center_freq); /* No IBSS found - decrease scan interval and continue @@ -619,7 +619,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" " (tx_last_beacon=%d)\n", - sdata->dev->name, mgmt->sa, mgmt->da, + sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ @@ -637,7 +637,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " "from %pM\n", - sdata->dev->name, mgmt->sa); + sdata->name, mgmt->sa); #endif return; } @@ -657,7 +657,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", - sdata->dev->name, resp->da); + sdata->name, resp->da); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -671,7 +671,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, size_t baselen; struct ieee802_11_elems elems; - if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 419f186cfcf0..178e329f9257 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -140,7 +140,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; struct ieee80211_tx_data { struct sk_buff *skb; - struct net_device *dev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; @@ -433,6 +432,8 @@ struct ieee80211_sub_if_data { int drop_unencrypted; + char name[IFNAMSIZ]; + /* * keep track of whether the HT opmode (stored in * vif.bss_info.ht_operation_mode) is valid. @@ -937,6 +938,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); /* interface handling */ +int ieee80211_iface_init(void); +void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct net_device **new_dev, enum nl80211_iftype type, struct vif_params *params); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 80c16f6e2af6..a6e6da3cab70 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -60,6 +60,22 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static int ieee80211_change_mac(struct net_device *dev, void *addr) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int ret; + + if (netif_running(dev)) + return -EBUSY; + + ret = eth_mac_addr(dev, addr); + + if (ret == 0) + memcpy(sdata->vif.addr, addr, ETH_ALEN); + + return ret; +} + static inline int identical_mac_addr_allowed(int type1, int type2) { return type1 == NL80211_IFTYPE_MONITOR || @@ -234,7 +250,7 @@ static int ieee80211_open(struct net_device *dev) default: conf.vif = &sdata->vif; conf.type = sdata->vif.type; - conf.mac_addr = dev->dev_addr; + conf.mac_addr = sdata->vif.addr; res = drv_add_interface(local, &conf); if (res) goto err_stop; @@ -514,7 +530,7 @@ static int ieee80211_stop(struct net_device *dev) conf.vif = &sdata->vif; conf.type = sdata->vif.type; - conf.mac_addr = dev->dev_addr; + conf.mac_addr = sdata->vif.addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); drv_remove_interface(local, &conf); @@ -651,7 +667,7 @@ static const struct net_device_ops ieee80211_dataif_ops = { .ndo_start_xmit = ieee80211_subif_start_xmit, .ndo_set_multicast_list = ieee80211_set_multicast_list, .ndo_change_mtu = ieee80211_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = ieee80211_change_mac, }; static const struct net_device_ops ieee80211_monitorif_ops = { @@ -794,6 +810,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); ndev->ieee80211_ptr = &sdata->wdev; + memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); + memcpy(sdata->name, ndev->name, IFNAMSIZ); /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; @@ -945,3 +963,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) if (chg) ieee80211_hw_config(local, chg); } + +static int netdev_notify(struct notifier_block *nb, + unsigned long state, + void *ndev) +{ + struct net_device *dev = ndev; + struct ieee80211_sub_if_data *sdata; + + if (state != NETDEV_CHANGENAME) + return 0; + + if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) + return 0; + + if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + memcpy(sdata->name, sdata->name, IFNAMSIZ); + + ieee80211_debugfs_rename_netdev(sdata); + return 0; +} + +static struct notifier_block mac80211_netdev_notifier = { + .notifier_call = netdev_notify, +}; + +int ieee80211_iface_init(void) +{ + return register_netdevice_notifier(&mac80211_netdev_notifier); +} + +void ieee80211_iface_exit(void) +{ + unregister_netdevice_notifier(&mac80211_netdev_notifier); +} diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8116d1a96a4a..dbf05b4dd003 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -32,7 +32,6 @@ #include "led.h" #include "cfg.h" #include "debugfs.h" -#include "debugfs_netdev.h" void ieee80211_configure_filter(struct ieee80211_local *local) { @@ -173,7 +172,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; else if (sdata->vif.type == NL80211_IFTYPE_AP) - sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; + sdata->vif.bss_conf.bssid = sdata->vif.addr; else if (ieee80211_vif_is_mesh(&sdata->vif)) { sdata->vif.bss_conf.bssid = zero; } else { @@ -672,11 +671,19 @@ static int __init ieee80211_init(void) ret = rc80211_pid_init(); if (ret) - return ret; + goto err_pid; - ieee80211_debugfs_netdev_init(); + ret = ieee80211_iface_init(); + if (ret) + goto err_netdev; return 0; + err_netdev: + rc80211_pid_exit(); + err_pid: + rc80211_minstrel_exit(); + + return ret; } static void __exit ieee80211_exit(void) @@ -693,7 +700,7 @@ static void __exit ieee80211_exit(void) if (mesh_allocated) ieee80211s_stop(); - ieee80211_debugfs_netdev_exit(); + ieee80211_iface_exit(); } diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c0fe46493f71..63299b72a7b0 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: running mesh housekeeping\n", - sdata->dev->name); + sdata->name); #endif ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); @@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, /* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && - compare_ether_addr(mgmt->da, sdata->dev->dev_addr)) + compare_ether_addr(mgmt->da, sdata->vif.addr)) return; baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index b836892f0ba9..664f5cc2b273 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); /* BSSID == SA */ - memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; @@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, ra, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; @@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, new_metric = MAX_METRIC; exp_time = TU_TO_EXP_TIME(orig_lifetime); - if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { + if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) { /* This MP is the originator, we are not interested in this * frame, except for updating transmitter's path info. */ @@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, mhwmp_dbg("received PREQ from %pM\n", orig_addr); - if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { + if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) { mhwmp_dbg("PREQ is for us\n"); forward = false; reply = true; @@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, * replies */ target_addr = PREP_IE_TARGET_ADDR(prep_elem); - if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) + if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) /* destination, no forwarding required */ return; @@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) target_flags = MP_F_RF; spin_unlock_bh(&mpath->state_lock); - mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, + mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, cpu_to_le32(mpath->sn), broadcast_addr, 0, ttl, cpu_to_le32(lifetime), 0, @@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, if (time_after(jiffies, mpath->exp_time + msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && - !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) && + !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) && !(mpath->flags & MESH_PATH_RESOLVING) && !(mpath->flags & MESH_PATH_FIXED)) { mesh_queue_preq(mpath, @@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, + mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, cpu_to_le32(++ifmsh->sn), 0, NULL, 0, broadcast_addr, 0, MESH_TTL, 0, 0, 0, sdata); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a8da23905c70..fbef678f64c8 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) + if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) + if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, struct mesh_path *mpath; u32 sn = 0; - if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { + if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) { u8 *ra, *da; da = hdr->addr3; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8fcf56ee7743..7985e5150898 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PLINK_CATEGORY; mgmt->u.action.u.plink_action.action_code = action; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c16667a7c8df..cd5dcc3d8c2b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -248,7 +248,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, wk->ssid_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " - "frame\n", sdata->dev->name); + "frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -282,7 +282,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); if (!is_zero_ether_addr(wk->prev_bssid)) { @@ -443,7 +443,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for " - "deauth/disassoc frame\n", sdata->dev->name); + "deauth/disassoc frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -451,7 +451,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); skb_put(skb, 2); @@ -484,7 +484,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for " - "pspoll frame\n", sdata->dev->name); + "pspoll frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -499,7 +499,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); - memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); + memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -519,7 +519,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "frame\n", sdata->dev->name); + "frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -532,7 +532,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, fc |= cpu_to_le16(IEEE80211_FCTL_PM); nullfunc->frame_control = fc; memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; @@ -948,7 +948,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, wk->tries++; if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->dev->name, wk->bss->cbss.bssid); + sdata->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the @@ -966,7 +966,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", - sdata->dev->name, wk->bss->cbss.bssid, + sdata->name, wk->bss->cbss.bssid, wk->tries); /* @@ -993,7 +993,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: authentication with AP %pM" " timed out\n", - sdata->dev->name, wk->bss->cbss.bssid); + sdata->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the @@ -1011,7 +1011,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", - sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + sdata->name, wk->bss->cbss.bssid, wk->tries); ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, wk->bss->cbss.bssid, NULL, 0, 0); @@ -1133,7 +1133,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { printk(KERN_DEBUG "%s: association with AP %pM" " timed out\n", - sdata->dev->name, wk->bss->cbss.bssid); + sdata->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the @@ -1151,7 +1151,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", - sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + sdata->name, wk->bss->cbss.bssid, wk->tries); ieee80211_send_assoc(sdata, wk); wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; @@ -1212,7 +1212,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (beacon && net_ratelimit()) printk(KERN_DEBUG "%s: detected beacon loss from AP " - "- sending probe request\n", sdata->dev->name); + "- sending probe request\n", sdata->name); #endif /* @@ -1269,7 +1269,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_work *wk) { wk->state = IEEE80211_MGD_STATE_IDLE; - printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: authenticated\n", sdata->name); } @@ -1366,7 +1366,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", - sdata->dev->name, bssid, reason_code); + sdata->name, bssid, reason_code); if (!wk) { ieee80211_set_disassoc(sdata, true); @@ -1400,7 +1400,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", - sdata->dev->name, mgmt->sa, reason_code); + sdata->name, mgmt->sa, reason_code); ieee80211_set_disassoc(sdata, false); return RX_MGMT_CFG80211_DISASSOC; @@ -1444,7 +1444,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " "status=%d aid=%d)\n", - sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, + sdata->name, reassoc ? "Rea" : "A", mgmt->sa, capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); pos = mgmt->u.assoc_resp.variable; @@ -1458,7 +1458,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ms = tu * 1024 / 1000; printk(KERN_DEBUG "%s: AP rejected association temporarily; " "comeback duration %u TU (%u ms)\n", - sdata->dev->name, tu, ms); + sdata->name, tu, ms); wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); @@ -1467,23 +1467,23 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", - sdata->dev->name, status_code); + sdata->name, status_code); wk->state = IEEE80211_MGD_STATE_IDLE; return RX_MGMT_CFG80211_ASSOC; } if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " - "set\n", sdata->dev->name, aid); + "set\n", sdata->name, aid); aid &= ~(BIT(15) | BIT(14)); if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", - sdata->dev->name); + sdata->name); return RX_MGMT_NONE; } - printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: associated\n", sdata->name); ifmgd->aid = aid; rcu_read_lock(); @@ -1498,7 +1498,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" - " the AP\n", sdata->dev->name); + " the AP\n", sdata->name); return RX_MGMT_NONE; } @@ -1576,7 +1576,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, int err = sta_info_insert(sta); if (err) { printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->dev->name, err); + " the AP (error %d)\n", sdata->name, err); rcu_read_unlock(); return RX_MGMT_NONE; } @@ -1671,7 +1671,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); - if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -1686,7 +1686,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, /* direct probe may be part of the association flow */ if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { printk(KERN_DEBUG "%s: direct probe responded\n", - sdata->dev->name); + sdata->name); wk->tries = 0; wk->state = IEEE80211_MGD_STATE_AUTH; WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); @@ -1779,7 +1779,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: cancelling probereq poll due " - "to a received beacon\n", sdata->dev->name); + "to a received beacon\n", sdata->name); } #endif ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; @@ -2554,7 +2554,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", - sdata->dev->name, bssid, req->reason_code); + sdata->name, bssid, req->reason_code); ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, req->reason_code, @@ -2583,7 +2583,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", - sdata->dev->name, req->bss->bssid, req->reason_code); + sdata->name, req->bss->bssid, req->reason_code); ieee80211_set_disassoc(sdata, false); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e535f1c988fe..05ccaadb6a0e 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) conf.vif = &sdata->vif; conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; + conf.mac_addr = sdata->vif.addr; drv_remove_interface(local, &conf); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5bae28693da8..d0136e3da487 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -283,15 +283,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, skb->protocol = htons(ETH_P_802_2); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) - continue; - if (sdata->vif.type != NL80211_IFTYPE_MONITOR) continue; if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) continue; + if (!netif_running(sdata->dev)) + continue; + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { @@ -476,7 +476,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); - char *dev_addr = rx->sdata->dev->dev_addr; + char *dev_addr = rx->sdata->vif.addr; if (ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr1)) { @@ -1024,7 +1024,7 @@ static void ap_sta_ps_start(struct sta_info *sta) drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", - sdata->dev->name, sta->sta.addr, sta->sta.aid); + sdata->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -1038,13 +1038,13 @@ static void ap_sta_ps_end(struct sta_info *sta) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", - sdata->dev->name, sta->sta.addr, sta->sta.aid); + sdata->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", - sdata->dev->name, sta->sta.addr, sta->sta.aid); + sdata->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ return; } @@ -1156,7 +1156,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " "addr1=%pM addr2=%pM\n", - sdata->dev->name, idx, + sdata->name, idx, jiffies - entry->first_frag_time, entry->seq, entry->last_frag, hdr->addr1, hdr->addr2); #endif @@ -1424,7 +1424,6 @@ static int __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; - struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; if (ieee80211_has_a4(hdr->frame_control) && @@ -1436,7 +1435,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) return -1; - return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); + return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); } /* @@ -1453,7 +1452,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) * of whether the frame was encrypted or not. */ if (ehdr->h_proto == htons(ETH_P_PAE) && - (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 || + (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) return true; @@ -1721,7 +1720,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* Frame has reached destination. Don't forward */ if (!is_multicast_ether_addr(hdr->addr1) && - compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0) + compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0) return RX_CONTINUE; mesh_hdr->ttl--; @@ -1738,10 +1737,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) if (!fwd_skb && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone mesh frame\n", - sdata->dev->name); + sdata->name); fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; @@ -1870,7 +1869,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *resp; - if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) { + if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) { /* Not to own unicast address */ return; } @@ -1894,7 +1893,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, resp = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(resp, 0, 24); memcpy(resp->da, mgmt->sa, ETH_ALEN); - memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(resp->sa, sdata->vif.addr, ETH_ALEN); memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); @@ -2274,7 +2273,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!bssid && !sdata->u.mgd.use_4addr) return 0; if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { + compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; @@ -2291,7 +2290,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, + compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; @@ -2308,7 +2307,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_MESH_POINT: if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, + compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; @@ -2319,11 +2318,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP: if (!bssid) { - if (compare_ether_addr(sdata->dev->dev_addr, + if (compare_ether_addr(sdata->vif.addr, hdr->addr1)) return 0; } else if (!ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) { + sdata->vif.addr)) { if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; @@ -2444,7 +2443,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, printk(KERN_DEBUG "%s: failed to copy " "multicast frame for %s\n", wiphy_name(local->hw.wiphy), - prev->dev->name); + prev->name); continue; } ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4cf387c944bf..d3381ba5f457 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -147,7 +147,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) presp = ieee80211_is_probe_resp(fc); if (presp) { /* ignore ProbeResp to foreign address */ - if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) return RX_DROP_MONITOR; presp = true; diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index aa743a895cf9..7733f66ee2c4 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer for " - "measurement report frame\n", sdata->dev->name); + "measurement report frame\n", sdata->name); return; } @@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); memset(msr_report, 0, 24); memcpy(msr_report->da, da, ETH_ALEN); - memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN); memcpy(msr_report->bssid, bssid, ETH_ALEN); msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c58a23eea58c..294f1b8b1545 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -372,7 +372,7 @@ int sta_info_insert(struct sta_info *sta) goto out_free; } - if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 || + if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || is_multicast_ether_addr(sta->sta.addr))) { err = -EINVAL; goto out_free; @@ -831,7 +831,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, if (time_after(jiffies, sta->last_rx + exp_time)) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", - sdata->dev->name, sta->sta.addr); + sdata->name, sta->sta.addr); #endif __sta_info_unlink(&sta); if (sta) @@ -889,7 +889,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " - "since STA not sleeping anymore\n", sdata->dev->name, + "since STA not sleeping anymore\n", sdata->name, sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -948,7 +948,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) */ printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " "though there are no buffered frames for it\n", - sdata->dev->name, sta->sta.addr); + sdata->name, sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } } diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 32fe327acf4e..b4608f11a40f 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -168,7 +168,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) for_each_sta_info(local, hdr->addr1, sta, tmp) { /* skip wrong virtual interface */ - if (memcmp(hdr->addr2, sta->sdata->dev->dev_addr, ETH_ALEN)) + if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) continue; if (!(info->flags & IEEE80211_TX_STAT_ACK) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b913bfc34a9f..ac48c86ae6b3 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -223,7 +223,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: dropped data frame to not " "associated station %pM\n", - tx->dev->name, hdr->addr1); + tx->sdata->name, hdr->addr1); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TX_DROP; @@ -331,7 +331,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", - tx->dev->name); + tx->sdata->name); #endif dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); } else @@ -391,7 +391,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (net_ratelimit()) { printk(KERN_DEBUG "%s: STA %pM TX " "buffer full - dropping oldest frame\n", - tx->dev->name, sta->sta.addr); + tx->sdata->name, sta->sta.addr); } #endif dev_kfree_skb(old); @@ -416,7 +416,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(staflags & WLAN_STA_PS_STA)) { printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " - "set -> send frame\n", tx->dev->name, + "set -> send frame\n", tx->sdata->name, sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -549,7 +549,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) "%s: Dropped data frame as no usable bitrate found while " "scanning and associated. Target station: " "%pM on %d GHz band\n", - tx->dev->name, hdr->addr1, + tx->sdata->name, hdr->addr1, tx->channel->band ? 5 : 2)) return TX_DROP; @@ -1021,7 +1021,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, memset(tx, 0, sizeof(*tx)); tx->skb = skb; - tx->dev = sdata->dev; /* use original interface */ tx->local = local; tx->sdata = sdata; tx->channel = local->hw.conf.channel; @@ -1474,7 +1473,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, continue; if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; - if (compare_ether_addr(tmp_sdata->dev->dev_addr, + if (compare_ether_addr(tmp_sdata->vif.addr, hdr->addr2) == 0) { sdata = tmp_sdata; break; @@ -1638,7 +1637,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1652,7 +1651,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; break; @@ -1660,7 +1659,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1674,8 +1673,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - if (compare_ether_addr(dev->dev_addr, - skb->data + ETH_ALEN) == 0) { + if (compare_ether_addr(sdata->vif.addr, + skb->data + ETH_ALEN) == 0) { hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, skb->data, skb->data + ETH_ALEN); meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, @@ -1705,7 +1704,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, } } hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, - mesh_da, dev->dev_addr); + mesh_da, sdata->vif.addr); rcu_read_unlock(); if (is_mesh_mcast) meshhdrlen = @@ -1730,7 +1729,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1781,7 +1780,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, unlikely(!is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && - compare_ether_addr(dev->dev_addr, + compare_ether_addr(sdata->vif.addr, skb->data + ETH_ALEN) == 0))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) @@ -2145,8 +2144,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d09f78bb2442..d45760eae6c7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -469,7 +469,7 @@ void ieee80211_iterate_active_interfaces( break; } if (netif_running(sdata->dev)) - iterator(data, sdata->dev->dev_addr, + iterator(data, sdata->vif.addr, &sdata->vif); } @@ -503,7 +503,7 @@ void ieee80211_iterate_active_interfaces_atomic( break; } if (netif_running(sdata->dev)) - iterator(data, sdata->dev->dev_addr, + iterator(data, sdata->vif.addr, &sdata->vif); } @@ -848,7 +848,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, sizeof(*mgmt) + 6 + extra_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for auth " - "frame\n", sdata->dev->name); + "frame\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -858,7 +858,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); memcpy(mgmt->da, bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); @@ -949,7 +949,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, ie_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "request\n", sdata->dev->name); + "request\n", sdata->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -958,7 +958,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, memset(mgmt, 0, 24); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); - memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); if (dst) { memcpy(mgmt->da, dst, ETH_ALEN); memcpy(mgmt->bssid, dst, ETH_ALEN); @@ -1051,7 +1051,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) netif_running(sdata->dev)) { conf.vif = &sdata->vif; conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; + conf.mac_addr = sdata->vif.addr; res = drv_add_interface(local, &conf); } } -- GitLab From 12375ef933fa8271396ed0c1e318cb1bd2e2689d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 20:30:31 +0100 Subject: [PATCH 0077/3892] mac80211: trace interface name It's not all that useful to have the vif/sdata pointer, we'd rather refer to the interfaces by their name. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 6 ++---- net/mac80211/agg-tx.c | 7 +++---- net/mac80211/driver-ops.h | 29 ++++++++++++++-------------- net/mac80211/driver-trace.h | 38 +++++++++++++++++++------------------ net/mac80211/key.c | 4 ++-- net/mac80211/main.c | 3 +-- net/mac80211/pm.c | 2 +- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 6 +++--- net/mac80211/util.c | 2 +- 10 files changed, 49 insertions(+), 50 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 37ecdeddd5ac..a978e666ed6f 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -41,8 +41,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (drv_ampdu_action(local, &sta->sdata->vif, - IEEE80211_AMPDU_RX_STOP, + if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -280,8 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - ret = drv_ampdu_action(local, &sta->sdata->vif, - IEEE80211_AMPDU_RX_START, + ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 209be60564ce..ceda36618d3c 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = drv_ampdu_action(local, &sta->sdata->vif, + ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_STOP, &sta->sta, tid, NULL); @@ -303,8 +303,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = drv_ampdu_action(local, &sdata->vif, - IEEE80211_AMPDU_TX_START, + ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, pubsta, tid, &start_seq_num); if (ret) { @@ -420,7 +419,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - drv_ampdu_action(local, &sta->sdata->vif, + drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_OPERATIONAL, &sta->sta, tid, NULL); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index a4002657dac5..727e4cf7b8a6 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -39,7 +39,7 @@ static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { int ret = local->ops->add_interface(&local->hw, conf); - trace_drv_add_interface(local, conf->vif, ret); + trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret); return ret; } @@ -47,7 +47,7 @@ static inline void drv_remove_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { local->ops->remove_interface(&local->hw, conf); - trace_drv_remove_interface(local, conf->vif); + trace_drv_remove_interface(local, vif_to_sdata(conf->vif)); } static inline int drv_config(struct ieee80211_local *local, u32 changed) @@ -58,13 +58,13 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed) } static inline void drv_bss_info_changed(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *info, u32 changed) { if (local->ops->bss_info_changed) - local->ops->bss_info_changed(&local->hw, vif, info, changed); - trace_drv_bss_info_changed(local, vif, info, changed); + local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); + trace_drv_bss_info_changed(local, sdata, info, changed); } static inline u64 drv_prepare_multicast(struct ieee80211_local *local, @@ -106,12 +106,13 @@ static inline int drv_set_tim(struct ieee80211_local *local, } static inline int drv_set_key(struct ieee80211_local *local, - enum set_key_cmd cmd, struct ieee80211_vif *vif, + enum set_key_cmd cmd, + struct ieee80211_sub_if_data *sdata, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key); - trace_drv_set_key(local, cmd, vif, sta, key, ret); + int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); + trace_drv_set_key(local, cmd, sdata, sta, key, ret); return ret; } @@ -179,13 +180,13 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, } static inline void drv_sta_notify(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { if (local->ops->sta_notify) - local->ops->sta_notify(&local->hw, vif, cmd, sta); - trace_drv_sta_notify(local, vif, cmd, sta); + local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); + trace_drv_sta_notify(local, sdata, cmd, sta); } static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, @@ -239,16 +240,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) } static inline int drv_ampdu_action(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, vif, action, + ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, sta, tid, ssn); - trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); + trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret); return ret; } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 7b155b947209..ee2d19a25ce1 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -25,10 +25,12 @@ static inline void trace_ ## name(proto) {} #define STA_PR_FMT " sta:%pM" #define STA_PR_ARG __entry->sta_addr -#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif) -#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif -#define VIF_PR_FMT " vif:%p(%d)" -#define VIF_PR_ARG __entry->vif, __entry->vif_type +#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ + __string(vif_name, sdata->dev ? sdata->dev->name : "") +#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ + __assign_str(vif_name, sdata->dev ? sdata->dev->name : "") +#define VIF_PR_FMT " vif:%s(%d)" +#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type TRACE_EVENT(drv_start, TP_PROTO(struct ieee80211_local *local, int ret), @@ -70,10 +72,10 @@ TRACE_EVENT(drv_stop, TRACE_EVENT(drv_add_interface, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, int ret), - TP_ARGS(local, vif, ret), + TP_ARGS(local, sdata, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -85,7 +87,7 @@ TRACE_EVENT(drv_add_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, vif->addr, 6); + memcpy(__entry->addr, sdata->vif.addr, 6); __entry->ret = ret; ), @@ -96,9 +98,9 @@ TRACE_EVENT(drv_add_interface, ); TRACE_EVENT(drv_remove_interface, - TP_PROTO(struct ieee80211_local *local, struct ieee80211_vif *vif), + TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), - TP_ARGS(local, vif), + TP_ARGS(local, sdata), TP_STRUCT__entry( LOCAL_ENTRY @@ -109,7 +111,7 @@ TRACE_EVENT(drv_remove_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, vif->addr, 6); + memcpy(__entry->addr, sdata->vif.addr, 6); ), TP_printk( @@ -163,11 +165,11 @@ TRACE_EVENT(drv_config, TRACE_EVENT(drv_bss_info_changed, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *info, u32 changed), - TP_ARGS(local, vif, info, changed), + TP_ARGS(local, sdata, info, changed), TP_STRUCT__entry( LOCAL_ENTRY @@ -291,11 +293,11 @@ TRACE_EVENT(drv_set_tim, TRACE_EVENT(drv_set_key, TP_PROTO(struct ieee80211_local *local, - enum set_key_cmd cmd, struct ieee80211_vif *vif, + enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, int ret), - TP_ARGS(local, cmd, vif, sta, key, ret), + TP_ARGS(local, cmd, sdata, sta, key, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -489,11 +491,11 @@ TRACE_EVENT(drv_set_rts_threshold, TRACE_EVENT(drv_sta_notify, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, enum sta_notify_cmd cmd, struct ieee80211_sta *sta), - TP_ARGS(local, vif, cmd, sta), + TP_ARGS(local, sdata, cmd, sta), TP_STRUCT__entry( LOCAL_ENTRY @@ -654,12 +656,12 @@ TRACE_EVENT(drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_vif *vif, + struct ieee80211_sub_if_data *sdata, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, int ret), - TP_ARGS(local, vif, action, sta, tid, ssn, ret), + TP_ARGS(local, sdata, action, sta, tid, ssn, ret), TP_STRUCT__entry( LOCAL_ENTRY diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ac1a777674f6..32ee6d0ee34d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); + ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); if (!ret) { spin_lock_bh(&todo_lock); @@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif, + ret = drv_set_key(key->local, DISABLE_KEY, sdata, sta, &key->conf); if (ret) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dbf05b4dd003..98320a94c270 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -222,8 +222,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } } - drv_bss_info_changed(local, &sdata->vif, - &sdata->vif.bss_conf, changed); + drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 05ccaadb6a0e..05e161c3cbc5 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -65,7 +65,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct ieee80211_sub_if_data, u.ap); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, &sta->sta); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d0136e3da487..ebab696def5b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1021,7 +1021,7 @@ static void ap_sta_ps_start(struct sta_info *sta) atomic_inc(&sdata->bss->num_sta_ps); set_sta_flags(sta, WLAN_STA_PS_STA); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); + drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", sdata->name, sta->sta.addr, sta->sta.aid); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 294f1b8b1545..d1a77e79d7a9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -397,7 +397,7 @@ int sta_info_insert(struct sta_info *sta) struct ieee80211_sub_if_data, u.ap); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); + drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta); sdata = sta->sdata; } @@ -537,7 +537,7 @@ static void __sta_info_unlink(struct sta_info **sta) struct ieee80211_sub_if_data, u.ap); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, &(*sta)->sta); sdata = (*sta)->sdata; } @@ -876,7 +876,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) struct ieee80211_local *local = sdata->local; int sent, buffered; - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); + drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d45760eae6c7..d54dbe8e09ba 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1066,7 +1066,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct ieee80211_sub_if_data, u.ap); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, + drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta); } spin_unlock_irqrestore(&local->sta_lock, flags); -- GitLab From 411132628f95dd3d51b84e0e2d8ff8f4f2d09cdb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 25 Nov 2009 21:00:30 -0500 Subject: [PATCH 0078/3892] ath9k_hw: remove unused ath9k_hw_devname() and ath9k_hw_probe() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 30 ----------------------------- 1 file changed, 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2ec61f08cfdb..917f70f7a28e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -343,30 +343,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) return true; } -static const char *ath9k_hw_devname(u16 devid) -{ - switch (devid) { - case AR5416_DEVID_PCI: - return "Atheros 5416"; - case AR5416_DEVID_PCIE: - return "Atheros 5418"; - case AR9160_DEVID_PCI: - return "Atheros 9160"; - case AR5416_AR9100_DEVID: - return "Atheros 9100"; - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - return "Atheros 9280"; - case AR9285_DEVID_PCIE: - return "Atheros 9285"; - case AR5416_DEVID_AR9287_PCI: - case AR5416_DEVID_AR9287_PCIE: - return "Atheros 9287"; - } - - return NULL; -} - static void ath9k_hw_init_config(struct ath_hw *ah) { int i; @@ -1266,12 +1242,6 @@ static void ath9k_hw_init_user_settings(struct ath_hw *ah) ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); } -const char *ath9k_hw_probe(u16 vendorid, u16 devid) -{ - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; -} - void ath9k_hw_detach(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); -- GitLab From 5e0ec316522e0372b633407c903b88f58859303f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 29 Nov 2009 00:51:54 +0100 Subject: [PATCH 0079/3892] ar9170: remove dead definitions This patch removes dead infrastructure which was meant for an out-of-tree rate control algorithm. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 -- drivers/net/wireless/ath/ar9170/main.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 9f9459860d82..d95a7d47af04 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; -#define AR9170_NUM_MAX_BA_RETRY 5 #define AR9170_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE) @@ -143,7 +142,6 @@ struct ar9170_sta_tid { u16 tid; enum ar9170_tid_state state; bool active; - u8 retry; }; #define AR9170_QUEUE_TIMEOUT 64 diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index f9d6db8d013e..cbf59b1590bf 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2366,7 +2366,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; sta_info->agg[i].active = false; sta_info->agg[i].ssn = 0; - sta_info->agg[i].retry = 0; sta_info->agg[i].tid = i; INIT_LIST_HEAD(&sta_info->agg[i].list); skb_queue_head_init(&sta_info->agg[i].queue); -- GitLab From 53a76b58b66e77164c4a79c38da49b808d67477e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 29 Nov 2009 00:52:51 +0100 Subject: [PATCH 0080/3892] ar9170: improve network latency AR9170 has the bad habit of choking when traffic builds up. Tests have shown that this can partially be attributed to a huge buildup of backlogged frames. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 ++ drivers/net/wireless/ath/ar9170/main.c | 34 +++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index d95a7d47af04..44c54b834a00 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -152,6 +152,8 @@ struct ar9170_sta_tid { #define AR9170_NUM_TX_STATUS 128 #define AR9170_NUM_TX_AGG_MAX 30 +#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH +#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) struct ar9170 { struct ieee80211_hw *hw; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index cbf59b1590bf..3cec2f16c657 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -430,7 +430,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) spin_lock_irqsave(&ar->tx_stats_lock, flags); ar->tx_stats[queue].len--; - if (skb_queue_empty(&ar->tx_pending[queue])) { + if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { #ifdef AR9170_QUEUE_STOP_DEBUG printk(KERN_DEBUG "%s: wake queue %d\n", wiphy_name(ar->hw->wiphy), queue); @@ -1716,6 +1716,21 @@ static void ar9170_tx(struct ar9170 *ar) for (i = 0; i < __AR9170_NUM_TXQ; i++) { spin_lock_irqsave(&ar->tx_stats_lock, flags); + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; + } + + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: queue %d full\n", @@ -1733,25 +1748,8 @@ static void ar9170_tx(struct ar9170 *ar) __ar9170_dump_txstats(ar); #endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_stop_queue(ar->hw, i); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - continue; - } - - frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, - skb_queue_len(&ar->tx_pending[i])); - - if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: tx quota reached queue:%d, " - "remaining slots:%d, needed:%d\n", - wiphy_name(ar->hw->wiphy), i, remaining_space, - frames); -#endif /* AR9170_QUEUE_DEBUG */ - frames = remaining_space; } - ar->tx_stats[i].len += frames; - ar->tx_stats[i].count += frames; spin_unlock_irqrestore(&ar->tx_stats_lock, flags); if (!frames) -- GitLab From 15b098bbf79f06a09d3a15b911eb43295979deed Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 29 Nov 2009 00:56:55 +0100 Subject: [PATCH 0081/3892] ar9170: remove redundant frame flags The flags in question were once useful for debugging. Time has passed and now they do nothing more than duplicating txinfo->flags. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 5 --- drivers/net/wireless/ath/ar9170/main.c | 55 ++++++++++-------------- 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 44c54b834a00..b99a8c2053d8 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -248,13 +248,8 @@ struct ar9170_sta_info { unsigned int ampdu_max_len; }; -#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) -#define AR9170_TX_FLAG_NO_ACK BIT(1) -#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) - struct ar9170_tx_info { unsigned long timeout; - unsigned int flags; }; #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 3cec2f16c657..d8ecf8554d01 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -213,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d " + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d " "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr), + ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), jiffies_to_msecs(arinfo->timeout - jiffies)); } @@ -440,22 +440,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) } spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { - ar9170_tx_ampdu_callback(ar, skb); - } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - - skb_queue_tail(&ar->tx_status[queue], skb); - } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); } else { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: unsupported frame flags!\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - dev_kfree_skb_any(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + ar9170_tx_ampdu_callback(ar, skb); + } else { + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + + skb_queue_tail(&ar->tx_status[queue], skb); + } } if (!ar->tx_stats[queue].len && @@ -1407,17 +1402,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - if (unlikely(!info->control.sta)) - goto err_out; - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; - - goto out; - } - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); /* * WARNING: * Putting the QoS queue bits into an unexplored territory is @@ -1431,12 +1415,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; - } else { - arinfo->flags = AR9170_TX_FLAG_NO_ACK; + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + } else { + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + } } -out: return 0; err_out: @@ -1771,7 +1760,7 @@ static void ar9170_tx(struct ar9170 *ar) arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); - if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + if (info->flags & IEEE80211_TX_CTL_AMPDU) atomic_inc(&ar->tx_ampdu_pending); #ifdef AR9170_QUEUE_DEBUG @@ -1782,7 +1771,7 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { - if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + if (info->flags & IEEE80211_TX_CTL_AMPDU) atomic_dec(&ar->tx_ampdu_pending); frames_failed++; -- GitLab From 07bc54575b413688d1586407a73793df8f68d115 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 29 Nov 2009 00:59:48 +0100 Subject: [PATCH 0082/3892] ar9170: small misc changes This patch aggregates a bunch of small random changes that won't fit really anywhere else properly. 1. move tid-locating macro into a separate function. 2. remove redundant NULL check. 3. add modulation mask definition Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/hw.h | 1 + drivers/net/wireless/ath/ar9170/main.c | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 701ddb7d8400..0a1d4c28e68a 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -276,6 +276,7 @@ struct ar9170_tx_control { #define AR9170_TX_MAC_RATE_PROBE 0x8000 /* either-or */ +#define AR9170_TX_PHY_MOD_MASK 0x00000003 #define AR9170_TX_PHY_MOD_CCK 0x00000000 #define AR9170_TX_PHY_MOD_OFDM 0x00000001 #define AR9170_TX_PHY_MOD_HT 0x00000002 diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index d8ecf8554d01..20f04ab2b13e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb) return ar9170_get_seq_h((void *) txc->frame_data); } +static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + static inline u16 ar9170_get_tid(struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - - return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; + return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data); } #define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff) @@ -1660,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar) * tell the FW/HW that this is the last frame, * that way it will wait for the immediate block ack. */ - if (likely(skb_peek_tail(&agg))) - ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); + ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); #ifdef AR9170_TXAGG_DEBUG printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", -- GitLab From 7dffb55b8a73228499ee65a3439f82112f4391c7 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 29 Nov 2009 01:01:14 +0100 Subject: [PATCH 0083/3892] ar9170: fix AC_VIDEO txop parameter This patch fixes a rather embarrassing typo. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index ddc8c09dc79e..857e86104295 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar) ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, ar->edcf[0].txop | ar->edcf[1].txop << 16); ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[1].txop | ar->edcf[3].txop << 16); + ar->edcf[2].txop | ar->edcf[3].txop << 16); ar9170_regwrite_finish(); -- GitLab From b7339b1de0f7b6b8c95a6df87ea2221521328d11 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:17:38 +0200 Subject: [PATCH 0084/3892] wl1251: add tx queue status to debugfs Sometimes when debugging the state is good info. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 1 + drivers/net/wireless/wl12xx/wl1251_debugfs.c | 23 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 054533f7a124..6301578d1565 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -247,6 +247,7 @@ struct wl1251_debugfs { struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; struct dentry *tx_queue_len; + struct dentry *tx_queue_status; struct dentry *retry_count; struct dentry *excessive_retries; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index a00723059f83..0ccba57fb9fb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = { .open = wl1251_open_file_generic, }; +static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1251 *wl = file->private_data; + char buf[3], status; + int len; + + if (wl->tx_queue_stopped) + status = 's'; + else + status = 'r'; + + len = scnprintf(buf, sizeof(buf), "%c\n", status); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations tx_queue_status_ops = { + .read = tx_queue_status_read, + .open = wl1251_open_file_generic, +}; + static void wl1251_debugfs_delete_files(struct wl1251 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl) DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(tx_queue_status); DEBUGFS_DEL(retry_count); DEBUGFS_DEL(excessive_retries); } @@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl) DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); -- GitLab From d67e261829d405ed19a6c2e648f224e352012f52 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:17:45 +0200 Subject: [PATCH 0085/3892] wl1251: print a debug message when tx_queue is full This debug message was missing and caused incomplete log messages. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index ff4be7bf5d36..0417745d7fc4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * the queue here, otherwise the queue will get too long. */ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { + wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); ieee80211_stop_queues(wl->hw); /* -- GitLab From 478fdf2bcef73747eb99bc6dd3565f093942647a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:17:52 +0200 Subject: [PATCH 0086/3892] wl1251: fix error handling in wl1251_op_config() Not all return values were checked and one exit from function didn't put firmware sleep after the error. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 0417745d7fc4..24050d56a9de 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -645,20 +645,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) * through the bss_info_changed() hook. */ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + goto out_sleep; } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { wl1251_debug(DEBUG_PSM, "psm disabled"); wl->psm_requested = false; - if (wl->psm) + if (wl->psm) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + } } if (conf->power_level != wl->power_level) { ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) - goto out; + goto out_sleep; wl->power_level = conf->power_level; } -- GitLab From b5a167942cb388cc5f1a6085cb3506d5bf47517d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:17:59 +0200 Subject: [PATCH 0087/3892] wl1251: reduce ELP wakeup timeout The original TI driver uses 100 ms timeout ELP wakeup timeout, better to use the same. Otherwise problems with wakeup might get unnoticed. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_ps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 9931b197ff77..54a27200f3b6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -26,7 +26,8 @@ #include "wl1251_cmd.h" #include "wl1251_io.h" -#define WL1251_WAKEUP_TIMEOUT 2000 +/* in ms */ +#define WL1251_WAKEUP_TIMEOUT 100 void wl1251_elp_work(struct work_struct *work) { -- GitLab From 7fa6282a1775bd41508220e65ba0cb92235b67d4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:06 +0200 Subject: [PATCH 0088/3892] wl1251: simplify ELP wakeup time calculation The wakeup time calculation was too complicated, simplify it. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_ps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 54a27200f3b6..851dfb65e474 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -68,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) int wl1251_ps_elp_wakeup(struct wl1251 *wl) { - unsigned long timeout; + unsigned long timeout, start; u32 elp_reg; if (!wl->elp) @@ -76,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) wl1251_debug(DEBUG_PSM, "waking up chip from elp"); + start = jiffies; timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); @@ -96,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) } wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); + jiffies_to_msecs(jiffies - start)); wl->elp = false; -- GitLab From cdd1e9a91ea55594cbcc9847dbb9392e341cbefd Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:12 +0200 Subject: [PATCH 0089/3892] wl1251: use __dev_alloc_skb() on RX RX is handled in a workqueue therefore allocating for GFP_ATOMIC is overkill and not required. Based on a patch for wl1271 by Luis R. Rodriguez. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index f84cc89cbffc..b56732226cc0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - skb = dev_alloc_skb(length); + skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1251_error("Couldn't allocate RX frame"); return; -- GitLab From 86dff7a7955f1e14c1f2c142312462fae70ea7e4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:19 +0200 Subject: [PATCH 0090/3892] wl1251: implement acx_ac_cfg to configure hardware queues Needed for WMM. Signed-off-by: Kalle Valo Reviewed-by: Janne Ylalehto Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 33 ++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 32 +++++++++++++++ drivers/net/wireless/wl12xx/wl1251_init.c | 5 +++ drivers/net/wireless/wl12xx/wl1251_init.h | 47 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_main.c | 27 +++++++++++++ drivers/net/wireless/wl12xx/wl1251_tx.h | 20 ++++++++++ 6 files changed, 164 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index acfa086dbfc5..b409c75499dd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -976,3 +976,36 @@ out: kfree(acx); return ret; } + +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifs, u16 txop) +{ + struct wl1251_acx_ac_cfg *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " + "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ac = ac; + acx->cw_min = cw_min; + acx->cw_max = cw_max; + acx->aifsn = aifs; + acx->txop_limit = txop; + + ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("acx ac cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 652371432cd8..56793245b287 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1166,6 +1166,36 @@ struct wl1251_acx_wr_tbtt_and_dtim { u8 padding; } __attribute__ ((packed)); +struct wl1251_acx_ac_cfg { + struct acx_header header; + + /* + * Access Category - The TX queue's access category + * (refer to AccessCategory_enum) + */ + u8 ac; + + /* + * The contention window minimum size (in slots) for + * the access class. + */ + u8 cw_min; + + /* + * The contention window maximum size (in slots) for + * the access class. + */ + u16 cw_max; + + /* The AIF value (in slots) for the access class. */ + u8 aifsn; + + u8 reserved; + + /* The TX Op Limit (in microseconds) for the access class. */ + u16 txop_limit; +} __attribute__ ((packed)); + /************************************************************************* Host Interrupt Register (WiLink -> Host) @@ -1322,5 +1352,7 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); int wl1251_acx_rate_policies(struct wl1251 *wl); int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, + u8 aifs, u16 txop); #endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 5cb573383eeb..5aad56ea7153 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) goto out; } + wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); + wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); + wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); + wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); + out: kfree(config); return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index b3b25ec885ea..269cefb3e7d4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -26,6 +26,53 @@ #include "wl1251.h" +enum { + /* best effort/legacy */ + AC_BE = 0, + + /* background */ + AC_BK = 1, + + /* video */ + AC_VI = 2, + + /* voice */ + AC_VO = 3, + + /* broadcast dummy access category */ + AC_BCAST = 4, + + NUM_ACCESS_CATEGORIES = 4 +}; + +/* following are defult values for the IE fields*/ +#define CWMIN_BK 15 +#define CWMIN_BE 15 +#define CWMIN_VI 7 +#define CWMIN_VO 3 +#define CWMAX_BK 1023 +#define CWMAX_BE 63 +#define CWMAX_VI 15 +#define CWMAX_VO 7 + +/* slot number setting to start transmission at PIFS interval */ +#define AIFS_PIFS 1 + +/* + * slot number setting to start transmission at DIFS interval - normal DCF + * access + */ +#define AIFS_DIFS 2 + +#define AIFSN_BK 7 +#define AIFSN_BE 3 +#define AIFSN_VI AIFS_PIFS +#define AIFSN_VO AIFS_PIFS +#define TXOP_BK 0 +#define TXOP_BE 0 +#define TXOP_VI 3008 +#define TXOP_VO 1504 + int wl1251_hw_init_hwenc_config(struct wl1251 *wl); int wl1251_hw_init_templates_config(struct wl1251 *wl); int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 24050d56a9de..c1c7cb5aea2b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1285,6 +1285,32 @@ static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 13, .center_freq = 2472}, }; +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct wl1251 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop); + + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1251_band_2ghz = { .channels = wl1251_channels, @@ -1305,6 +1331,7 @@ static const struct ieee80211_ops wl1251_ops = { .hw_scan = wl1251_op_hw_scan, .bss_info_changed = wl1251_op_bss_info_changed, .set_rts_threshold = wl1251_op_set_rts_threshold, + .conf_tx = wl1251_op_conf_tx, }; static int wl1251_register_hw(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index 7c1c1665c810..b7bead8b0aeb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -26,6 +26,7 @@ #define __WL1251_TX_H__ #include +#include "wl1251_acx.h" /* * @@ -209,6 +210,25 @@ struct tx_result { u8 done_2; } __attribute__ ((packed)); +static inline int wl1251_tx_get_queue(int queue) +{ + /* FIXME: use best effort until WMM is enabled */ + return QOS_AC_BE; + + switch (queue) { + case 0: + return QOS_AC_VO; + case 1: + return QOS_AC_VI; + case 2: + return QOS_AC_BE; + case 3: + return QOS_AC_BK; + default: + return QOS_AC_BE; + } +} + void wl1251_tx_work(struct work_struct *work); void wl1251_tx_complete(struct wl1251 *wl); void wl1251_tx_flush(struct wl1251 *wl); -- GitLab From 27336f1c0cd68fb9ae45493321f0d6980144230e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:27 +0200 Subject: [PATCH 0091/3892] wl1251: implement wl1251_acx_tid_cfg() Needed for WMM. Signed-off-by: Kalle Valo Reviewed-by: Janne Ylalehto Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 36 +++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 55 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_main.c | 11 +++++ 3 files changed, 102 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index b409c75499dd..beff084040b5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -1009,3 +1009,39 @@ out: kfree(acx); return ret; } + +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, + enum wl1251_acx_channel_type type, + u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, + enum wl1251_acx_ack_policy ack_policy) +{ + struct wl1251_acx_tid_cfg *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " + "ps_scheme %d ack_policy %d", queue, type, tsid, + ps_scheme, ack_policy); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->queue = queue; + acx->type = type; + acx->tsid = tsid; + acx->ps_scheme = ps_scheme; + acx->ack_policy = ack_policy; + + ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("acx tid cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 56793245b287..26160c45784c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1196,6 +1196,57 @@ struct wl1251_acx_ac_cfg { u16 txop_limit; } __attribute__ ((packed)); + +enum wl1251_acx_channel_type { + CHANNEL_TYPE_DCF = 0, + CHANNEL_TYPE_EDCF = 1, + CHANNEL_TYPE_HCCA = 2, +}; + +enum wl1251_acx_ps_scheme { + /* regular ps: simple sending of packets */ + WL1251_ACX_PS_SCHEME_LEGACY = 0, + + /* sending a packet triggers a unscheduled apsd downstream */ + WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, + + /* a pspoll packet will be sent before every data packet */ + WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, + + /* scheduled apsd mode */ + WL1251_ACX_PS_SCHEME_SAPSD = 3, +}; + +enum wl1251_acx_ack_policy { + WL1251_ACX_ACK_POLICY_LEGACY = 0, + WL1251_ACX_ACK_POLICY_NO_ACK = 1, + WL1251_ACX_ACK_POLICY_BLOCK = 2, +}; + +struct wl1251_acx_tid_cfg { + struct acx_header header; + + /* tx queue id number (0-7) */ + u8 queue; + + /* channel access type for the queue, enum wl1251_acx_channel_type */ + u8 type; + + /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ + u8 tsid; + + /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ + u8 ps_scheme; + + /* the tx queue ack policy, enum wl1251_acx_ack_policy */ + u8 ack_policy; + + u8 padding[3]; + + /* not supported */ + u32 apsdconf[2]; +} __attribute__ ((packed)); + /************************************************************************* Host Interrupt Register (WiLink -> Host) @@ -1354,5 +1405,9 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifs, u16 txop); +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, + enum wl1251_acx_channel_type type, + u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, + enum wl1251_acx_ack_policy ack_policy); #endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index c1c7cb5aea2b..74770ada37de 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1302,7 +1302,18 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), params->cw_min, params->cw_max, params->aifs, params->txop); + if (ret < 0) + goto out_sleep; + + ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), + CHANNEL_TYPE_DCF, + wl1251_tx_get_queue(queue), + WL1251_ACX_PS_SCHEME_LEGACY, + WL1251_ACX_ACK_POLICY_LEGACY); + if (ret < 0) + goto out_sleep; +out_sleep: wl1251_ps_elp_sleep(wl); out: -- GitLab From 49e1b9faed736b20ad9a785638919341b567a595 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:33 +0200 Subject: [PATCH 0092/3892] wl1251: implement WMM Now that necessary commands for WMM are implemented, implement queue handling for WMM. But WMM is not enabled yet, only one queue is used. Signed-off-by: Kalle Valo Reviewed-by: Janne Ylalehto Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- drivers/net/wireless/wl12xx/wl1251_tx.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 74770ada37de..563c84fc575c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1306,7 +1306,7 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, goto out_sleep; ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), - CHANNEL_TYPE_DCF, + CHANNEL_TYPE_EDCF, wl1251_tx_get_queue(queue), WL1251_ACX_PS_SCHEME_LEGACY, WL1251_ACX_ACK_POLICY_LEGACY); diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index f85970615849..faa23efd05a1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, tx_hdr->expiry_time = cpu_to_le32(1 << 16); tx_hdr->id = id; - /* FIXME: how to get the correct queue id? */ - tx_hdr->xmit_queue = 0; + tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); wl1251_tx_control(tx_hdr, control, fc); wl1251_tx_frag_block_num(tx_hdr); @@ -237,8 +236,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, wl1251_mem_write(wl, addr, skb->data, len); - wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", - tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); + wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " + "queue %d", tx_hdr->id, skb, tx_hdr->length, + tx_hdr->rate, tx_hdr->xmit_queue); return 0; } -- GitLab From 46cb35f5e761306b031029af2061ea263359a764 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:40 +0200 Subject: [PATCH 0093/3892] wl1251: update tx_hdr when aliging skb in tx Before transmission when aligning the buffer to 4-byte bounday, tx_hdr needs to be updated. Otherwise debug logs print false data. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index faa23efd05a1..c8223185efd2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -219,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, /* align the buffer on a 4-byte boundary */ skb_reserve(skb, offset); memmove(skb->data, src, skb->len); + tx_hdr = (struct tx_double_buffer_desc *) skb->data; } else { wl1251_info("No handler, fixme!"); return -EINVAL; -- GitLab From da2fb4e9c215b8f0f8954818691549f8a34135be Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 30 Nov 2009 10:18:47 +0200 Subject: [PATCH 0094/3892] wl1251: enable WMM Everything is ready now and we can enable WMM in mac80211. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 ++ drivers/net/wireless/wl12xx/wl1251_tx.h | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 563c84fc575c..63511ca131b1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1388,6 +1388,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; + wl->hw->queues = 4; + ret = wl1251_register_hw(wl); if (ret) goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index b7bead8b0aeb..55856c6bb97a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -212,9 +212,6 @@ struct tx_result { static inline int wl1251_tx_get_queue(int queue) { - /* FIXME: use best effort until WMM is enabled */ - return QOS_AC_BE; - switch (queue) { case 0: return QOS_AC_VO; -- GitLab From cef6e91280b724e93b0fb8a9fd3e6bf072f54c81 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Mon, 30 Nov 2009 21:50:07 +0200 Subject: [PATCH 0095/3892] rndis_wlan: move copy of module parameters to separate function Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2ecbedb26e15..8dd9224c2d4e 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2594,23 +2594,9 @@ end: /* * driver/device initialization */ -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) +static void rndis_copy_module_params(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ priv->param_country[0] = modparam_country[0]; priv->param_country[1] = modparam_country[1]; @@ -2652,6 +2638,27 @@ static int bcm4320b_early_init(struct usbnet *usbdev) priv->param_workaround_interval = 500; else priv->param_workaround_interval = modparam_workaround_interval; +} + +static int bcm4320a_early_init(struct usbnet *usbdev) +{ + /* bcm4320a doesn't handle configuration parameters well. Try + * set any and you get partially zeroed mac and broken device. + */ + + return 0; +} + +static int bcm4320b_early_init(struct usbnet *usbdev) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + char buf[8]; + + rndis_copy_module_params(usbdev); + + /* Early initialization settings, setting these won't have effect + * if called after generic_rndis_bind(). + */ rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); rndis_set_config_parameter_str(usbdev, "FrameBursting", -- GitLab From 6e850af58f93be8f1b4b79eb9c79d06788f38e78 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Mon, 30 Nov 2009 21:50:13 +0200 Subject: [PATCH 0096/3892] rndis_wlan: copy module parameters for bcm4320a devices too rndis_wlan didn't copy module parameters for bcm4320a to private structure. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8dd9224c2d4e..305c106fdc1c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2642,6 +2642,11 @@ static void rndis_copy_module_params(struct usbnet *usbdev) static int bcm4320a_early_init(struct usbnet *usbdev) { + /* copy module parameters for bcm4320a so that iwconfig reports txpower + * and workaround parameter is copied to private structure correctly. + */ + rndis_copy_module_params(usbdev); + /* bcm4320a doesn't handle configuration parameters well. Try * set any and you get partially zeroed mac and broken device. */ -- GitLab From 4a40ccf8140d6b973d8b02dd5467b1fd876c0654 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 12 Dec 2009 18:04:46 -0600 Subject: [PATCH 0097/3892] rtl8180: Remove usage of deprecated 'qual' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building rtl8180, the following warning occurs: CC [M] drivers/net/wireless/rtl818x/rtl8180_dev.o drivers/net/wireless/rtl818x/rtl8180_dev.c: In function ‘rtl8180_handle_rx’: drivers/net/wireless/rtl818x/rtl8180_dev.c:135: warning: ‘qual’ is deprecated (declared at include/net/mac80211.h:562) Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index a1a3dd15c664..8a40a1439984 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -132,7 +132,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ - rx_status.qual = flags2 & 0xFF; rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; -- GitLab From 59d9cb071d6209f2e8df2d16228cfdc7bab1f2d1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 17 Dec 2009 13:54:57 +0100 Subject: [PATCH 0098/3892] mac80211: remove payload alignment warning The payload alignment warning enabled by MAC80211_DEBUG_PACKET_ALIGNMENT is difficult. To fix it, a firmware change is needed but in most cases that's very difficult. So the benefit from the warning is low and most probably it just creates more confusion for people who just enable all warnings (like it did for me). Remove the unaligned IP payload warning and the kconfig option. But leave the unaligned packet warning, it will be enabled with MAC80211_VERBOSE_DEBUG. Signed-off-by: Kalle Valo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 12 ------------ net/mac80211/rx.c | 27 +++++++-------------------- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a10d508b07e1..a952b7f8c648 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -96,18 +96,6 @@ menuconfig MAC80211_DEBUG_MENU ---help--- This option collects various mac80211 debug settings. -config MAC80211_DEBUG_PACKET_ALIGNMENT - bool "Enable packet alignment debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - This option is recommended for driver authors and strongly - discouraged for everybody else, it will trigger a warning - when a driver hands mac80211 a buffer that is aligned in - a way that will cause problems with the IP stack on some - architectures. - - Say N unless you're writing a mac80211 based driver. - config MAC80211_NOINLINE bool "Do not inline TX/RX handlers" depends on MAC80211_DEBUG_MENU diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ebab696def5b..dbfd684e3e2e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -361,7 +361,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) * boundary. In the case of regular frames, this simply means aligning the * payload to a four-byte boundary (because either the IP header is directly * contained, or IV/RFC1042 headers that have a length divisible by four are - * in front of it). + * in front of it). If the payload data is not properly aligned and the + * architecture doesn't support efficient unaligned operations, mac80211 + * will align the data. * * With A-MSDU frames, however, the payload data address must yield two modulo * four because there are 14-byte 802.3 headers within the A-MSDU frames that @@ -375,25 +377,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) */ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - int hdrlen; - -#ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT - return; +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + WARN_ONCE((unsigned long)rx->skb->data & 1, + "unaligned packet at 0x%p\n", rx->skb->data); #endif - - if (WARN_ONCE((unsigned long)rx->skb->data & 1, - "unaligned packet at 0x%p\n", rx->skb->data)) - return; - - if (!ieee80211_is_data_present(hdr->frame_control)) - return; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (rx->flags & IEEE80211_RX_AMSDU) - hdrlen += ETH_HLEN; - WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3, - "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen); } @@ -1510,7 +1497,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if (skb) { int align __maybe_unused; -#if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS /* * 'align' will only take the values 0 or 2 here * since all frames are required to be aligned -- GitLab From 3b377ea9d4efc94dc52fe41b4dfdb463635ab298 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 18 Dec 2009 17:59:01 -0500 Subject: [PATCH 0099/3892] wireless: support internal statically compiled regulatory database This patch provides infrastructure for machine translation of the regulatory rules database used by CRDA into a C data structure. It includes code for searching that database as an alternative to dynamic regulatory rules updates via CRDA. Most people should use CRDA instead of this infrastructure, but it provides a better alternative than the WIRELESS_OLD_REGULATORY infrastructure (which can now be removed). Signed-off-by: John W. Linville --- Documentation/networking/regulatory.txt | 24 +++++ net/wireless/.gitignore | 1 + net/wireless/Kconfig | 16 ++++ net/wireless/Makefile | 6 ++ net/wireless/db.txt | 17 ++++ net/wireless/genregdb.awk | 118 +++++++++++++++++++++++ net/wireless/reg.c | 120 +++++++++++++++++++----- net/wireless/regdb.h | 7 ++ 8 files changed, 285 insertions(+), 24 deletions(-) create mode 100644 net/wireless/.gitignore create mode 100644 net/wireless/db.txt create mode 100644 net/wireless/genregdb.awk create mode 100644 net/wireless/regdb.h diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index ee31369e9e5b..9551622d0a7b 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -188,3 +188,27 @@ Then in some part of your code after your wiphy has been registered: &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); regulatory_struct_hint(rd); + +Statically compiled regulatory database +--------------------------------------- + +In most situations the userland solution using CRDA as described +above is the preferred solution. However in some cases a set of +rules built into the kernel itself may be desirable. To account +for this situation, a configuration option has been provided +(i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled, +the wireless database information contained in net/wireless/db.txt is +used to generate a data structure encoded in net/wireless/regdb.c. +That option also enables code in net/wireless/reg.c which queries +the data in regdb.c as an alternative to using CRDA. + +The file net/wireless/db.txt should be kept up-to-date with the db.txt +file available in the git repository here: + + git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git + +Again, most users in most situations should be using the CRDA package +provided with their distribution, and in most other situations users +should be building and using CRDA on their own rather than using +this option. If you are not absolutely sure that you should be using +CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_. diff --git a/net/wireless/.gitignore b/net/wireless/.gitignore new file mode 100644 index 000000000000..c33451b896d9 --- /dev/null +++ b/net/wireless/.gitignore @@ -0,0 +1 @@ +regdb.c diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 90e93a5701aa..8419971f07c5 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -109,6 +109,22 @@ config WIRELESS_OLD_REGULATORY Say N and if you say Y, please tell us why. The default is N. +config CFG80211_INTERNAL_REGDB + bool "use statically compiled regulatory rules database" if EMBEDDED + default n + depends on CFG80211 + ---help--- + This option generates an internal data structure representing + the wireless regulatory rules described in net/wireless/db.txt + and includes code to query that database. This is an alternative + to using CRDA for defining regulatory rules for the kernel. + + For details see: + + http://wireless.kernel.org/en/developers/Regulatory + + Most distributions have a CRDA package. So if unsure, say N. + config CFG80211_WEXT bool "cfg80211 wireless extensions compatibility" depends on CFG80211 diff --git a/net/wireless/Makefile b/net/wireless/Makefile index f07c8dc7aab2..e77e508126fa 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -13,5 +13,11 @@ cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o +cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o ccflags-y += -D__CHECK_ENDIAN__ + +$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk + @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@ + +clean-files := regdb.c diff --git a/net/wireless/db.txt b/net/wireless/db.txt new file mode 100644 index 000000000000..a2fc3a09ccdc --- /dev/null +++ b/net/wireless/db.txt @@ -0,0 +1,17 @@ +# +# This file is a placeholder to prevent accidental build breakage if someone +# enables CONFIG_CFG80211_INTERNAL_REGDB. Almost no one actually needs to +# enable that build option. +# +# You should be using CRDA instead. It is even better if you use the CRDA +# package provided by your distribution, since they will probably keep it +# up-to-date on your behalf. +# +# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will +# need to replace this file with one containing appropriately formatted +# regulatory rules that cover the regulatory domains you will be using. Your +# best option is to extract the db.txt file from the wireless-regdb git +# repository: +# +# git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git +# diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk new file mode 100644 index 000000000000..8316cf075ce9 --- /dev/null +++ b/net/wireless/genregdb.awk @@ -0,0 +1,118 @@ +#!/usr/bin/awk -f +# +# genregdb.awk -- generate regdb.c from db.txt +# +# Actually, it reads from stdin (presumed to be db.txt) and writes +# to stdout (presumed to be regdb.c), but close enough... +# +# Copyright 2009 John W. Linville +# +# 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. +# + +BEGIN { + active = 0 + rules = 0; + print "/*" + print " * DO NOT EDIT -- file generated from data in db.txt" + print " */" + print "" + print "#include " + print "#include " + print "" + regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" +} + +/^[ \t]*#/ { + /* Ignore */ +} + +!active && /^[ \t]*$/ { + /* Ignore */ +} + +!active && /country/ { + country=$2 + sub(/:/, "", country) + printf "static const struct ieee80211_regdomain regdom_%s = {\n", country + printf "\t.alpha2 = \"%s\",\n", country + printf "\t.reg_rules = {\n" + active = 1 + regdb = regdb "\t®dom_" country ",\n" +} + +active && /^[ \t]*\(/ { + start = $1 + sub(/\(/, "", start) + end = $3 + bw = $5 + sub(/\),/, "", bw) + gain = $6 + sub(/\(/, "", gain) + sub(/,/, "", gain) + power = $7 + sub(/\)/, "", power) + sub(/,/, "", power) + # power might be in mW... + units = $8 + sub(/\)/, "", units) + sub(/,/, "", units) + if (units == "mW") { + if (power == 100) { + power = 20 + } else if (power == 200) { + power = 23 + } else if (power == 500) { + power = 27 + } else if (power == 1000) { + power = 30 + } else { + print "Unknown power value in database!" + } + } + flagstr = "" + for (i=8; i<=NF; i++) + flagstr = flagstr $i + split(flagstr, flagarray, ",") + flags = "" + for (arg in flagarray) { + if (flagarray[arg] == "NO-OFDM") { + flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | " + } else if (flagarray[arg] == "NO-CCK") { + flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | " + } else if (flagarray[arg] == "NO-INDOOR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | " + } else if (flagarray[arg] == "NO-OUTDOOR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | " + } else if (flagarray[arg] == "DFS") { + flags = flags "\n\t\t\tNL80211_RRF_DFS | " + } else if (flagarray[arg] == "PTP-ONLY") { + flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | " + } else if (flagarray[arg] == "PTMP-ONLY") { + flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " + } else if (flagarray[arg] == "PASSIVE-SCAN") { + flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " + } else if (flagarray[arg] == "NO-IBSS") { + flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " + } + } + flags = flags "0" + printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags + rules++ +} + +active && /^[ \t]*$/ { + active = 0 + printf "\t},\n" + printf "\t.n_reg_rules = %d\n", rules + printf "};\n\n" + rules = 0; +} + +END { + print regdb "};" + print "" + print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" +} diff --git a/net/wireless/reg.c b/net/wireless/reg.c index c01470e7de15..65f86264f7bb 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -40,6 +40,7 @@ #include #include "core.h" #include "reg.h" +#include "regdb.h" #include "nl80211.h" /* Receipt of information from last regulatory request */ @@ -360,6 +361,98 @@ static bool country_ie_integrity_changes(u32 checksum) return false; } +static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, + const struct ieee80211_regdomain *src_regd) +{ + struct ieee80211_regdomain *regd; + int size_of_regd = 0; + unsigned int i; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + regd = kzalloc(size_of_regd, GFP_KERNEL); + if (!regd) + return -ENOMEM; + + memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); + + for (i = 0; i < src_regd->n_reg_rules; i++) + memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + + *dst_regd = regd; + return 0; +} + +#ifdef CONFIG_CFG80211_INTERNAL_REGDB +struct reg_regdb_search_request { + char alpha2[2]; + struct list_head list; +}; + +static LIST_HEAD(reg_regdb_search_list); +static DEFINE_SPINLOCK(reg_regdb_search_lock); + +static void reg_regdb_search(struct work_struct *work) +{ + struct reg_regdb_search_request *request; + const struct ieee80211_regdomain *curdom, *regdom; + int i, r; + + spin_lock(®_regdb_search_lock); + while (!list_empty(®_regdb_search_list)) { + request = list_first_entry(®_regdb_search_list, + struct reg_regdb_search_request, + list); + list_del(&request->list); + + for (i=0; ialpha2, curdom->alpha2, 2)) { + r = reg_copy_regd(®dom, curdom); + if (r) + break; + spin_unlock(®_regdb_search_lock); + mutex_lock(&cfg80211_mutex); + set_regdom(regdom); + mutex_unlock(&cfg80211_mutex); + spin_lock(®_regdb_search_lock); + break; + } + } + + kfree(request); + } + spin_unlock(®_regdb_search_lock); +} + +static DECLARE_WORK(reg_regdb_work, reg_regdb_search); + +static void reg_regdb_query(const char *alpha2) +{ + struct reg_regdb_search_request *request; + + if (!alpha2) + return; + + request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); + if (!request) + return; + + memcpy(request->alpha2, alpha2, 2); + + spin_lock(®_regdb_search_lock); + list_add_tail(&request->list, ®_regdb_search_list); + spin_unlock(®_regdb_search_lock); + + schedule_work(®_regdb_work); +} +#else +static inline void reg_regdb_query(const char *alpha2) {} +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + /* * This lets us keep regulatory code which is updated on a regulatory * basis in userspace. @@ -379,6 +472,9 @@ static int call_crda(const char *alpha2) printk(KERN_INFO "cfg80211: Calling CRDA to update world " "regulatory domain\n"); + /* query internal regulatory database (if it exists) */ + reg_regdb_query(alpha2); + country_env[8] = alpha2[0]; country_env[9] = alpha2[1]; @@ -1367,30 +1463,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); -static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, - const struct ieee80211_regdomain *src_regd) -{ - struct ieee80211_regdomain *regd; - int size_of_regd = 0; - unsigned int i; - - size_of_regd = sizeof(struct ieee80211_regdomain) + - ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); - - regd = kzalloc(size_of_regd, GFP_KERNEL); - if (!regd) - return -ENOMEM; - - memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); - - for (i = 0; i < src_regd->n_reg_rules; i++) - memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], - sizeof(struct ieee80211_reg_rule)); - - *dst_regd = regd; - return 0; -} - /* * Return value which can be used by ignore_request() to indicate * it has been determined we should intersect two regulatory domains diff --git a/net/wireless/regdb.h b/net/wireless/regdb.h new file mode 100644 index 000000000000..818222c92513 --- /dev/null +++ b/net/wireless/regdb.h @@ -0,0 +1,7 @@ +#ifndef __REGDB_H__ +#define __REGDB_H__ + +extern const struct ieee80211_regdomain *reg_regdb[]; +extern int reg_regdb_size; + +#endif /* __REGDB_H__ */ -- GitLab From 3a41bbd515d449604f3488c5f8dd62802f09d19b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Dec 2009 14:37:24 -0800 Subject: [PATCH 0100/3892] iwlwifi: log CT_CARD_DISABLED flag Change name from RF_CARD_DISABLED to CT_CARD_DISABLED to match the indication from uCode, also log the debug message when the condition detected in iwl_rx_card_state_notif() Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +++++++----- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b8377efb3ba7..954b8ae2c880 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -689,12 +689,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", + IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + (flags & SW_CARD_DISABLED) ? "Kill" : "On", + (flags & CT_CARD_DISABLED) ? + "Reached" : "Not reached"); if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | - RF_CARD_DISABLED)) { + CT_CARD_DISABLED)) { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); @@ -708,10 +710,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } - if (flags & RF_CARD_DISABLED) + if (flags & CT_CARD_DISABLED) iwl_tt_enter_ct_kill(priv); } - if (!(flags & RF_CARD_DISABLED)) + if (!(flags & CT_CARD_DISABLED)) iwl_tt_exit_ct_kill(priv); if (flags & HW_CARD_DISABLED) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e91507531923..28f3800c560e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2510,7 +2510,7 @@ struct iwl_card_state_notif { #define HW_CARD_DISABLED 0x01 #define SW_CARD_DISABLED 0x02 -#define RF_CARD_DISABLED 0x04 +#define CT_CARD_DISABLED 0x04 #define RXON_CARD_DISABLED 0x10 struct iwl_ct_kill_config { -- GitLab From 696bdee3ba216186e21997d20a839b76158346e6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Dec 2009 14:37:25 -0800 Subject: [PATCH 0101/3892] iwlwifi: dump "Control and Status Register" when detect uCode HW/SW error When uCode HW/SW error detected, dumping important CSR (Control and Status Registers) values. Also add "csr" debugfs file to dump the current values of CSR defined in CSR table to syslog. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 2 + drivers/net/wireless/iwlwifi/iwl-6000.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 73 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 25 ++++++++ 7 files changed, 105 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8414178bcff4..9d4fdd7a1134 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = { .load_ucode = iwl5000_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .dump_csr = iwl_dump_csr, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e2f8615c8c9b..5a277cdffd07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1465,6 +1465,7 @@ struct iwl_lib_ops iwl5000_lib = { .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .dump_csr = iwl_dump_csr, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, @@ -1517,6 +1518,7 @@ static struct iwl_lib_ops iwl5150_lib = { .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .dump_csr = iwl_dump_csr, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 74e571049273..fec43771c49e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = { .load_ucode = iwl5000_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .dump_csr = iwl_dump_csr, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 574d36658702..47ece91e4505 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1363,6 +1363,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); priv->cfg->ops->lib->dump_nic_error_log(priv); + if (priv->cfg->ops->lib->dump_csr) + priv->cfg->ops->lib->dump_csr(priv); priv->cfg->ops->lib->dump_nic_event_log(priv, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) @@ -3191,6 +3193,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) EXPORT_SYMBOL(iwl_update_stats); #endif +const static char *get_csr_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CSR_HW_IF_CONFIG_REG); + IWL_CMD(CSR_INT_COALESCING); + IWL_CMD(CSR_INT); + IWL_CMD(CSR_INT_MASK); + IWL_CMD(CSR_FH_INT_STATUS); + IWL_CMD(CSR_GPIO_IN); + IWL_CMD(CSR_RESET); + IWL_CMD(CSR_GP_CNTRL); + IWL_CMD(CSR_HW_REV); + IWL_CMD(CSR_EEPROM_REG); + IWL_CMD(CSR_EEPROM_GP); + IWL_CMD(CSR_OTP_GP_REG); + IWL_CMD(CSR_GIO_REG); + IWL_CMD(CSR_GP_UCODE_REG); + IWL_CMD(CSR_GP_DRIVER_REG); + IWL_CMD(CSR_UCODE_DRV_GP1); + IWL_CMD(CSR_UCODE_DRV_GP2); + IWL_CMD(CSR_LED_REG); + IWL_CMD(CSR_DRAM_INT_TBL_REG); + IWL_CMD(CSR_GIO_CHICKEN_BITS); + IWL_CMD(CSR_ANA_PLL_CFG); + IWL_CMD(CSR_HW_REV_WA_REG); + IWL_CMD(CSR_DBG_HPET_MEM_REG); + default: + return "UNKNOWN"; + + } +} + +void iwl_dump_csr(struct iwl_priv *priv) +{ + int i; + u32 csr_tbl[] = { + CSR_HW_IF_CONFIG_REG, + CSR_INT_COALESCING, + CSR_INT, + CSR_INT_MASK, + CSR_FH_INT_STATUS, + CSR_GPIO_IN, + CSR_RESET, + CSR_GP_CNTRL, + CSR_HW_REV, + CSR_EEPROM_REG, + CSR_EEPROM_GP, + CSR_OTP_GP_REG, + CSR_GIO_REG, + CSR_GP_UCODE_REG, + CSR_GP_DRIVER_REG, + CSR_UCODE_DRV_GP1, + CSR_UCODE_DRV_GP2, + CSR_LED_REG, + CSR_DRAM_INT_TBL_REG, + CSR_GIO_CHICKEN_BITS, + CSR_ANA_PLL_CFG, + CSR_HW_REV_WA_REG, + CSR_DBG_HPET_MEM_REG + }; + IWL_ERR(priv, "CSR values:\n"); + IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " + "CSR_INT_PERIODIC_REG)\n"); + for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { + IWL_ERR(priv, " %25s: 0X%08x\n", + get_csr_string(csr_tbl[i]), + iwl_read32(priv, csr_tbl[i])); + } +} +EXPORT_SYMBOL(iwl_dump_csr); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 675b7df632fc..f5e79cf0a318 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -171,6 +171,7 @@ struct iwl_lib_ops { int (*load_ucode)(struct iwl_priv *priv); void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); void (*dump_nic_error_log)(struct iwl_priv *priv); + void (*dump_csr)(struct iwl_priv *priv); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ struct iwl_apm_ops apm_ops; @@ -582,6 +583,7 @@ int iwl_pci_resume(struct pci_dev *pdev); ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); +void iwl_dump_csr(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d61293ab67c9..86a67672598d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -109,6 +109,7 @@ struct iwl_debugfs { struct dentry *file_power_save_status; struct dentry *file_clear_ucode_statistics; struct dentry *file_clear_traffic_statistics; + struct dentry *file_csr; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 21e0f6699daf..2be3549be01d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1845,6 +1845,28 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_csr_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int csr; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &csr) != 1) + return -EFAULT; + + if (priv->cfg->ops->lib->dump_csr) + priv->cfg->ops->lib->dump_csr(priv); + + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1859,6 +1881,7 @@ DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); +DEBUGFS_WRITE_FILE_OPS(csr); /* * Create the debugfs files and directories @@ -1909,6 +1932,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); + DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); @@ -1966,6 +1990,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) file_clear_ucode_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_clear_traffic_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); -- GitLab From a9e1cb6a78ea8a74c49bf76726a2942f636a833b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Dec 2009 14:37:26 -0800 Subject: [PATCH 0102/3892] iwlwifi: add continuous uCode event log capability In order to help uCode debugging, adding the capability to provide continuous uCode event logging function. uCode events is located in round-robin event queue and filled by uCode, by enable continuous event logging, driver check the write pointer and log the newly added events in iwl_bg_ucode_trace() timer function. There is still possibility of missing events if event queue being wrapped before next event dump; but with this capability, we can have much better understanding of the uCode behavior during runtime; it can help to debug the uCode related issues. Methods to enable/disable the continuous event log: step 1: enable ucode trace timer "echo 1 > /sys/kernel/debug/ieee80211/phyX/iwlagn/debug/ucode_tracing" step 2: start ftrace sudo ./trace-cmd record -e iwlwifi_ucode:* sleep 1d step 3: stop ftrace sudo ./trace-cmd report trace.dat step 4: disable ucode trace timer "echo 0 > /sys/kernel/debug/ieee80211/phyX/iwlagn/debug/ucode_tracing" use "ucode_tracing" debugfs file to display number of event queue wrapped when driver attempt the continuous event logging. If event queue being wrapped more than once when driver has opportunity to log the event; it indicated there are events missing in the event log trace. This continuous event log function only available for 4965 and newer NICs. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 130 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 56 +++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 29 +++++ drivers/net/wireless/iwlwifi/iwl-devtrace.c | 2 + drivers/net/wireless/iwlwifi/iwl-devtrace.h | 44 +++++++ 6 files changed, 262 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 954b8ae2c880..4d85c28e38e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data) iwl_send_statistics_request(priv, CMD_ASYNC, false); } + +static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, + u32 start_idx, u32 num_events, + u32 mode) +{ + u32 i; + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + unsigned long reg_flags; + + if (mode == 0) + ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32)); + else + ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); + + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (iwl_grab_nic_access(priv)) { + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return; + } + + /* Set starting address; reads will auto-increment */ + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + + /* + * "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. + */ + for (i = 0; i < num_events; i++) { + ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + if (mode == 0) { + trace_iwlwifi_dev_ucode_cont_event(priv, + 0, time, ev); + } else { + data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + trace_iwlwifi_dev_ucode_cont_event(priv, + time, data, ev); + } + } + /* Allow device to power down */ + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +} + +void iwl_continuous_event_trace(struct iwl_priv *priv) +{ + u32 capacity; /* event log capacity in # entries */ + u32 base; /* SRAM byte address of event log header */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + capacity = iwl_read_targ_mem(priv, base); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + } else + return; + + if (num_wraps == priv->event_log.num_wraps) { + iwl_print_cont_event_trace(priv, + base, priv->event_log.next_entry, + next_entry - priv->event_log.next_entry, + mode); + priv->event_log.non_wraps_count++; + } else { + if ((num_wraps - priv->event_log.num_wraps) > 1) + priv->event_log.wraps_more_count++; + else + priv->event_log.wraps_once_count++; + trace_iwlwifi_dev_ucode_wrap_event(priv, + num_wraps - priv->event_log.num_wraps, + next_entry, priv->event_log.next_entry); + if (next_entry < priv->event_log.next_entry) { + iwl_print_cont_event_trace(priv, base, + priv->event_log.next_entry, + capacity - priv->event_log.next_entry, + mode); + + iwl_print_cont_event_trace(priv, base, 0, + next_entry, mode); + } else { + iwl_print_cont_event_trace(priv, base, + next_entry, capacity - next_entry, + mode); + + iwl_print_cont_event_trace(priv, base, 0, + next_entry, mode); + } + } + priv->event_log.num_wraps = num_wraps; + priv->event_log.next_entry = next_entry; +} + +/** + * iwl_bg_ucode_trace - Timer callback to log ucode event + * + * The timer is continually set to execute every + * UCODE_TRACE_PERIOD milliseconds after the last timer expired + * this function is to perform continuous uCode event logging operation + * if enabled + */ +static void iwl_bg_ucode_trace(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (priv->event_log.ucode_trace) { + iwl_continuous_event_trace(priv); + /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */ + mod_timer(&priv->ucode_trace, + jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); + } +} + static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -3128,6 +3253,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl_bg_statistics_periodic; + init_timer(&priv->ucode_trace); + priv->ucode_trace.data = (unsigned long)priv; + priv->ucode_trace.function = iwl_bg_ucode_trace; + if (!priv->cfg->use_isr_legacy) tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) iwl_irq_tasklet, (unsigned long)priv); @@ -3146,6 +3275,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); + del_timer_sync(&priv->ucode_trace); } static void iwl_init_hw_rates(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 86a67672598d..58e0462cafa3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -110,6 +110,7 @@ struct iwl_debugfs { struct dentry *file_clear_ucode_statistics; struct dentry *file_clear_traffic_statistics; struct dentry *file_csr; + struct dentry *file_ucode_tracing; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2be3549be01d..822de46e4f34 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1867,6 +1867,58 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char buf[128]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n", + priv->event_log.ucode_trace ? "On" : "Off"); + pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n", + priv->event_log.non_wraps_count); + pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n", + priv->event_log.wraps_once_count); + pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n", + priv->event_log.wraps_more_count); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int trace; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &trace) != 1) + return -EFAULT; + + if (trace) { + priv->event_log.ucode_trace = true; + /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */ + mod_timer(&priv->ucode_trace, + jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); + } else { + priv->event_log.ucode_trace = false; + del_timer_sync(&priv->ucode_trace); + } + + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1882,6 +1934,7 @@ DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); DEBUGFS_WRITE_FILE_OPS(csr); +DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); /* * Create the debugfs files and directories @@ -1939,6 +1992,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR); } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -2002,6 +2056,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) file_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_chain_noise); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_tracing); } DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2673e9a4db92..b3a29c7cdbc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -984,6 +984,32 @@ struct iwl_switch_rxon { __le16 channel; }; +/* + * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds + * to perform continuous uCode event logging operation if enabled + */ +#define UCODE_TRACE_PERIOD (100) + +/* + * iwl_event_log: current uCode event log position + * + * @ucode_trace: enable/disable ucode continuous trace timer + * @num_wraps: how many times the event buffer wraps + * @next_entry: the entry just before the next one that uCode would fill + * @non_wraps_count: counter for no wrap detected when dump ucode events + * @wraps_once_count: counter for wrap once detected when dump ucode events + * @wraps_more_count: counter for wrap more than once detected + * when dump ucode events + */ +struct iwl_event_log { + bool ucode_trace; + u32 num_wraps; + u32 next_entry; + int non_wraps_count; + int wraps_once_count; + int wraps_more_count; +}; + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1261,6 +1287,7 @@ struct iwl_priv { u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; + struct timer_list ucode_trace; bool hw_ready; /*For 3945*/ #define IWL_DEFAULT_TX_POWER 0x0F @@ -1268,6 +1295,8 @@ struct iwl_priv { struct iwl3945_notif_statistics statistics_39; u32 sta_supp_rates; + + struct iwl_event_log event_log; }; /*iwl_priv */ static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index e7d88d1da15d..bf46308b17fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -11,4 +11,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 21361968ab7e..0819f990be6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -64,6 +64,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) ); +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi_ucode + +TRACE_EVENT(iwlwifi_dev_ucode_cont_event, + TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev), + TP_ARGS(priv, time, data, ev), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(u32, time) + __field(u32, data) + __field(u32, ev) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->time = time; + __entry->data = data; + __entry->ev = ev; + ), + TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u", + __entry->priv, __entry->time, __entry->data, __entry->ev) +); + +TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, + TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry), + TP_ARGS(priv, wraps, n_entry, p_entry), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(u32, wraps) + __field(u32, n_entry) + __field(u32, p_entry) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->wraps = wraps; + __entry->n_entry = n_entry; + __entry->p_entry = p_entry; + ), + TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X", + __entry->priv, __entry->wraps, __entry->n_entry, + __entry->p_entry) +); + #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi -- GitLab From b03d7d0fd3d23b7cf130fa702f4ae3b1bc827d4b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 14 Dec 2009 14:12:20 -0800 Subject: [PATCH 0103/3892] iwlwifi: on-screen event log dump This feature enables the on-screen uCode event log dump. The original method will append the event log to syslog; with this capability, we also enable the user to write script to capture the events which provide additional flexibility to help uCode debugging Method 1) change to debugfs directory (sys/kernel/debug/phyX/iwlagn/data) 2) #cat log_event Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 3 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 104 ++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 24 ++++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 101 +++++++++++++------ 6 files changed, 171 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ecc23ec1f6a4..28f6eb5f2cba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -227,7 +227,8 @@ extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); -extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log); +extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, + char **buf, bool display); extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv); /* diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4d85c28e38e2..0b3669f317a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1832,8 +1832,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) * iwl_print_event_log - Dump error event log to syslog * */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) +static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode, + int pos, char **buf, size_t bufsz) { u32 i; u32 base; /* SRAM byte address of event log header */ @@ -1843,7 +1844,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, unsigned long reg_flags; if (num_events == 0) - return; + return pos; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); else @@ -1871,27 +1872,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ - trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); - IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOG:0x%08x:%04u\n", + time, ev); + } else { + trace_iwlwifi_dev_ucode_event(priv, 0, + time, ev); + IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", + time, ev); + } } else { data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } else { + IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, + data, ev); + } } } /* Allow device to power down */ iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return pos; } /** * iwl_print_last_event_logs - Dump the newest # of event log to syslog */ -static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, - u32 num_wraps, u32 next_entry, - u32 size, u32 mode) +static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode, + int pos, char **buf, size_t bufsz) { /* * display the newest DEFAULT_LOG_ENTRIES entries @@ -1899,21 +1917,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, */ if (num_wraps) { if (next_entry < size) { - iwl_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode); - iwl_print_event_log(priv, 0, - next_entry, mode); + pos = iwl_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode, + pos, buf, bufsz); + pos = iwl_print_event_log(priv, 0, + next_entry, mode, + pos, buf, bufsz); } else - iwl_print_event_log(priv, next_entry - size, - size, mode); + pos = iwl_print_event_log(priv, next_entry - size, + size, mode, pos, buf, bufsz); } else { - if (next_entry < size) - iwl_print_event_log(priv, 0, next_entry, mode); - else - iwl_print_event_log(priv, next_entry - size, - size, mode); + if (next_entry < size) { + pos = iwl_print_event_log(priv, 0, next_entry, + mode, pos, buf, bufsz); + } else { + pos = iwl_print_event_log(priv, next_entry - size, + size, mode, pos, buf, bufsz); + } } + return pos; } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ @@ -1921,7 +1944,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) -void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) +int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, + char **buf, bool display) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1929,6 +1953,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ + int pos = 0; + size_t bufsz = 0; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); @@ -1939,7 +1965,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); - return; + return pos; } /* event log header */ @@ -1965,7 +1991,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return; + return pos; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -1980,6 +2006,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) size); #ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + if (full_log) + bufsz = capacity * 48; + else + bufsz = size * 48; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return pos; + } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* * if uCode has wrapped back to top of log, @@ -1987,17 +2022,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) * i.e the next one that uCode would fill. */ if (num_wraps) - iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode); + pos = iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode, + pos, buf, bufsz); /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); + pos = iwl_print_event_log(priv, 0, + next_entry, mode, pos, buf, bufsz); } else - iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode); + pos = iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); #else - iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode); + pos = iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); #endif + return pos; } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 47ece91e4505..c3c31dc9fd4d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1365,7 +1365,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) priv->cfg->ops->lib->dump_nic_error_log(priv); if (priv->cfg->ops->lib->dump_csr) priv->cfg->ops->lib->dump_csr(priv); - priv->cfg->ops->lib->dump_nic_event_log(priv, false); + priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f5e79cf0a318..650d3808d24a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -169,7 +169,8 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); + int (*dump_nic_event_log)(struct iwl_priv *priv, + bool full_log, char **buf, bool display); void (*dump_nic_error_log)(struct iwl_priv *priv); void (*dump_csr)(struct iwl_priv *priv); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); @@ -582,7 +583,8 @@ int iwl_pci_resume(struct pci_dev *pdev); * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); -void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); +int iwl_dump_nic_event_log(struct iwl_priv *priv, + bool full_log, char **buf, bool display); void iwl_dump_csr(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 822de46e4f34..ee5aed12a4b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -420,6 +420,23 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_log_event_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char *buf; + int pos = 0; + ssize_t ret = -ENOMEM; + + pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true); + if (pos && buf) { + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + } + return ret; +} + static ssize_t iwl_dbgfs_log_event_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -436,7 +453,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv, true); + priv->cfg->ops->lib->dump_nic_event_log(priv, true, + NULL, false); return count; } @@ -859,7 +877,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, } DEBUGFS_READ_WRITE_FILE_OPS(sram); -DEBUGFS_WRITE_FILE_OPS(log_event); +DEBUGFS_READ_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(channels); @@ -1965,7 +1983,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); DEBUGFS_ADD_FILE(nvm, data, S_IRUSR); DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(log_event, data, S_IWUSR); + DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(stations, data, S_IRUSR); DEBUGFS_ADD_FILE(channels, data, S_IRUSR); DEBUGFS_ADD_FILE(status, data, S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2a28a1f8b1fe..f7c7ff4264fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1560,8 +1560,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv) * iwl3945_print_event_log - Dump error event log to syslog * */ -static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) +static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode, + int pos, char **buf, size_t bufsz) { u32 i; u32 base; /* SRAM byte address of event log header */ @@ -1571,7 +1572,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, unsigned long reg_flags; if (num_events == 0) - return; + return pos; base = le32_to_cpu(priv->card_alive.log_event_table_ptr); @@ -1597,26 +1598,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ - IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); - trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "0x%08x:%04u\n", + time, ev); + } else { + IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); + trace_iwlwifi_dev_ucode_event(priv, 0, + time, ev); + } } else { data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, data, ev); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "%010u:0x%08x:%04u\n", + time, data, ev); + } else { + IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", + time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, + data, ev); + } } } /* Allow device to power down */ iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return pos; } /** * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog */ -static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, +static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, u32 num_wraps, u32 next_entry, - u32 size, u32 mode) + u32 size, u32 mode, + int pos, char **buf, size_t bufsz) { /* * display the newest DEFAULT_LOG_ENTRIES entries @@ -1624,21 +1642,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, */ if (num_wraps) { if (next_entry < size) { - iwl3945_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode); - iwl3945_print_event_log(priv, 0, - next_entry, mode); + pos = iwl3945_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode, + pos, buf, bufsz); + pos = iwl3945_print_event_log(priv, 0, + next_entry, mode, + pos, buf, bufsz); } else - iwl3945_print_event_log(priv, next_entry - size, - size, mode); + pos = iwl3945_print_event_log(priv, next_entry - size, + size, mode, + pos, buf, bufsz); } else { if (next_entry < size) - iwl3945_print_event_log(priv, 0, next_entry, mode); + pos = iwl3945_print_event_log(priv, 0, + next_entry, mode, + pos, buf, bufsz); else - iwl3945_print_event_log(priv, next_entry - size, - size, mode); + pos = iwl3945_print_event_log(priv, next_entry - size, + size, mode, + pos, buf, bufsz); } + return pos; } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ @@ -1646,7 +1671,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) -void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) +int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, + char **buf, bool display) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1654,11 +1680,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ + int pos = 0; + size_t bufsz = 0; base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return; + return pos; } /* event log header */ @@ -1684,7 +1712,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return; + return pos; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -1700,25 +1728,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) size); #ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + if (full_log) + bufsz = capacity * 48; + else + bufsz = size * 48; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return pos; + } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* if uCode has wrapped back to top of log, * start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) - iwl3945_print_event_log(priv, next_entry, - capacity - next_entry, mode); + pos = iwl3945_print_event_log(priv, next_entry, + capacity - next_entry, mode, + pos, buf, bufsz); /* (then/else) start at top of log */ - iwl3945_print_event_log(priv, 0, next_entry, mode); + pos = iwl3945_print_event_log(priv, 0, next_entry, mode, + pos, buf, bufsz); } else - iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode); + pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); #else - iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode); + pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); #endif - + return pos; } static void iwl3945_irq_tasklet(struct iwl_priv *priv) -- GitLab From 4309af2735825115a982acf4c2c868b5c5671e7f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 14 Dec 2009 14:12:21 -0800 Subject: [PATCH 0104/3892] iwlwifi: remove extra error msg on sensitivity calibration Do not need to log error when fail the sensitivity command, driver will send sensitivity write command to uCode after each sensitivity calibration if station is associated with AP. It is a normal case when user unload the module or shutdown the system while still associated with the AP, since uCode already on the way down, it will not reply the sensitivity write request; report error in this case will give misleading information, remove the error checking here to provide a clean shutdown if no other error detected. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-calib.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 95a57b36a7ea..dc61906290e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ static int iwl_sensitivity_write(struct iwl_priv *priv) { - int ret = 0; struct iwl_sensitivity_cmd cmd ; struct iwl_sensitivity_data *data = NULL; struct iwl_host_cmd cmd_out = { @@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - ret = iwl_send_cmd(priv, &cmd_out); - if (ret) - IWL_ERR(priv, "SENSITIVITY_CMD failed\n"); - - return ret; + return iwl_send_cmd(priv, &cmd_out); } void iwl_init_sensitivity(struct iwl_priv *priv) -- GitLab From 050e8a47dc8b056c880f380ffd01055669f8fe68 Mon Sep 17 00:00:00 2001 From: Kenichi HORIO Date: Fri, 4 Dec 2009 23:46:56 +0100 Subject: [PATCH 0105/3892] rt73usb: add WLI-U2-H54HP Signed-off-by: Kenichi HORIO Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ced3b6ab5e16..6ce88d3c3b65 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2354,6 +2354,7 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, -- GitLab From c70762f9acad654002704f1e53436a0ba3356c31 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Fri, 4 Dec 2009 23:46:57 +0100 Subject: [PATCH 0106/3892] rt2x00 : bail out of regbusy_read if device is removed. platform rfkill is async thus we may try to read while the device is already off. Signed-off-by: Alban Browaeys Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 0feb4d0e4668..801be436cf1d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, { unsigned int i; + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, offset, reg); if (!rt2x00_get_field32(*reg, field)) -- GitLab From 6a325d856bc4509f29164fe42501b6909cf57dcf Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Fri, 4 Dec 2009 23:46:58 +0100 Subject: [PATCH 0107/3892] rt2x00 : modify padding location. The padding is to be added between header and payload for the only header need padding case. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Alban Browaeys Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 239afc7a9c0b..842c4e3c83ca 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -197,7 +197,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) * the payload is already properly aligned. */ skb_push(skb, header_align); - memmove(skb->data, skb->data + header_align, frame_length); + memmove(skb->data, skb->data + header_align, header_length); skbdesc->flags |= SKBDESC_L2_PADDED; } else { /* -- GitLab From e81e0aef32bfa7f593b14479b9c7eaa7196798ac Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Fri, 4 Dec 2009 23:46:59 +0100 Subject: [PATCH 0108/3892] rt2x00 : avoid timestamp for monitor injected frame. Do not include timestamp for a frame that has been injected through a monitor interface. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Alban Browaeys Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 842c4e3c83ca..b8f09547787d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -387,10 +387,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. + * to be inserted into the frame, except for a frame that has been injected + * through a monitor interface. This latter is needed for testing a + * monitor interface. */ - if (ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) + if ((ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) && + (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED))) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); /* -- GitLab From 1398d4580eff2656f3a808ec24744ce5a842db35 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Fri, 4 Dec 2009 23:47:00 +0100 Subject: [PATCH 0109/3892] rt2x00 : trim the skb after having the l2pad removed. Otherwise we end up truncating the skb before removing the l2pad thus we might have the truncated part become garbage while getting it back in remove_l2pad. For the same issue: remove the skb_trim from the rt2800 fill_rxdone (it is done after l2pad removal in rt2x00lib_rxdone). Signed-off-by: Alban Browaeys Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 1 - drivers/net/wireless/rt2x00/rt2800usb.c | 1 - drivers/net/wireless/rt2x00/rt2x00dev.c | 6 +++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index dfc886fcb44d..6fcb2bb840b2 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -927,7 +927,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, * Remove TXWI descriptor from start of buffer. */ skb_pull(entry->skb, RXWI_DESC_SIZE); - skb_trim(entry->skb, rxdesc->size); } /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index af85d18cdbe7..1db8667a6ff1 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -663,7 +663,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, * Remove RXWI descriptor from start of buffer. */ skb_pull(entry->skb, skbdesc->desc_len); - skb_trim(entry->skb, rxdesc->size); } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 06c43ca39bf8..cc6bcc5a20c7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - /* Trim buffer to correct size */ - skb_trim(entry->skb, rxdesc.size); - /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. @@ -409,6 +406,9 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, else rt2x00queue_align_payload(entry->skb, header_length); + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); + /* * Check if the frame was received using HT. In that case, * the rate is the MCS index and should be passed to mac80211 -- GitLab From 77e73d1849c860d22ebba8826ad162ccfda4c535 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:47:01 +0100 Subject: [PATCH 0110/3892] rt2x00: Further L2 padding fixes. Fix a couple of more bugs in the L2 padding code: 1. Compute the amount of L2 padding correctly (in 3 places). 2. Trim the skb correctly when the L2 padding has been applied. Also introduce a central macro the compute the L2 padding size. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 6 ++++++ drivers/net/wireless/rt2x00/rt2x00queue.c | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4d841c07c970..194dae01d0c3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -103,6 +103,12 @@ #define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) +/* + * Determine the number of L2 padding bytes required between the header and + * the payload. + */ +#define L2PAD_SIZE(__hdrlen) (-(__hdrlen) & 3) + /* * Determine the alignment requirement, * to make sure the 802.11 payload is padded to a 4-byte boundrary diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index b8f09547787d..21d58769a1a7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -181,7 +181,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) unsigned int frame_length = skb->len; unsigned int header_align = ALIGN_SIZE(skb, 0); unsigned int payload_align = ALIGN_SIZE(skb, header_length); - unsigned int l2pad = 4 - (payload_align - header_align); + unsigned int l2pad = L2PAD_SIZE(header_length); if (header_align == payload_align) { /* @@ -216,6 +216,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) memmove(skb->data + header_length + l2pad, skb->data + header_length + l2pad + payload_align, frame_length - header_length); + skb_trim(skb, frame_length + l2pad); skbdesc->flags |= SKBDESC_L2_PADDED; } } @@ -223,7 +224,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int l2pad = 4 - (header_length & 3); + unsigned int l2pad = L2PAD_SIZE(header_length); if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) return; @@ -346,7 +347,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Header and alignment information. */ txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + txdesc->l2pad = L2PAD_SIZE(txdesc->header_length); /* * Check whether this frame is to be acked. -- GitLab From 354e39dbb19f29ef28a9c2db9e55ff2a7435b35a Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:47:02 +0100 Subject: [PATCH 0111/3892] rt2x00: Remove SKBDESC_L2_PADDED flag. With the improved L2 padding code, this flag is no longer necessary, as the rt2x00queue_remove_l2pad is capable of detecting by itself if L2 padding is applied. For received frames the RX descriptor flag is still being checked. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +--- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +----- drivers/net/wireless/rt2x00/rt2x00queue.h | 5 +---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6fcb2bb840b2..458378c4e500 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -835,7 +835,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *rxd = entry_priv->desc; __le32 *rxwi = (__le32 *)entry->skb->data; @@ -883,10 +882,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) { + if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) rxdesc->dev_flags |= RXDONE_L2PAD; - skbdesc->flags |= SKBDESC_L2_PADDED; - } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 1db8667a6ff1..13baec485eb6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -625,10 +625,8 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) { + if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) rxdesc->dev_flags |= RXDONE_L2PAD; - skbdesc->flags |= SKBDESC_L2_PADDED; - } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 21d58769a1a7..719f4aebcaf6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -177,7 +177,6 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int frame_length = skb->len; unsigned int header_align = ALIGN_SIZE(skb, 0); unsigned int payload_align = ALIGN_SIZE(skb, header_length); @@ -198,7 +197,6 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) */ skb_push(skb, header_align); memmove(skb->data, skb->data + header_align, header_length); - skbdesc->flags |= SKBDESC_L2_PADDED; } else { /* * @@ -217,16 +215,14 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) skb->data + header_length + l2pad + payload_align, frame_length - header_length); skb_trim(skb, frame_length + l2pad); - skbdesc->flags |= SKBDESC_L2_PADDED; } } void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int l2pad = L2PAD_SIZE(header_length); - if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) + if (!l2pad) return; memmove(skb->data + l2pad, skb->data, header_length); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 70775e5ba1ac..c1e482bb37b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -92,8 +92,6 @@ enum data_queue_qid { * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by * mac80211 but was stripped for processing by the driver. - * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, - * the padded bytes are located between header and payload. * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211, * don't try to pass it back. */ @@ -101,8 +99,7 @@ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, SKBDESC_IV_STRIPPED = 1 << 2, - SKBDESC_L2_PADDED = 1 << 3, - SKBDESC_NOT_MAC80211 = 1 << 4, + SKBDESC_NOT_MAC80211 = 1 << 3, }; /** -- GitLab From 2e331462fcb3d897921d8a0af4fca1b08c1b7269 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:47:03 +0100 Subject: [PATCH 0112/3892] rt2x00: Reorganize L2 padding inserting function. Simplify the rt2x00queue_insert_l2pad function by handling the alignment operations one by one. Do not special case special circumstances. Basically first perform header alignment, and then perform payload alignment (if any payload does exist). This results in a properly aligned skb. The end result is better readable code, with better results, as now L2 padding is inserted only when a payload is actually present in the frame. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 60 ++++++++++------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 719f4aebcaf6..7452fa850a0f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -177,45 +177,38 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { - unsigned int frame_length = skb->len; + unsigned int payload_length = skb->len - header_length; unsigned int header_align = ALIGN_SIZE(skb, 0); unsigned int payload_align = ALIGN_SIZE(skb, header_length); unsigned int l2pad = L2PAD_SIZE(header_length); - if (header_align == payload_align) { - /* - * Both header and payload must be moved the same - * amount of bytes to align them properly. This means - * we don't use the L2 padding but just move the entire - * frame. - */ - rt2x00queue_align_frame(skb); - } else if (!payload_align) { - /* - * Simple L2 padding, only the header needs to be moved, - * the payload is already properly aligned. - */ - skb_push(skb, header_align); - memmove(skb->data, skb->data + header_align, header_length); - } else { - /* - * - * Complicated L2 padding, both header and payload need - * to be moved. By default we only move to the start - * of the buffer, so our header alignment needs to be - * increased if there is not enough room for the header - * to be moved. - */ - if (payload_align > header_align) - header_align += 4; + /* + * Adjust the header alignment if the payload needs to be moved more + * than the header. + */ + if (payload_align > header_align) + header_align += 4; + + /* There is nothing to do if no alignment is needed */ + if (!header_align) + return; - skb_push(skb, header_align); - memmove(skb->data, skb->data + header_align, header_length); + /* Reserve the amount of space needed in front of the frame */ + skb_push(skb, header_align); + + /* + * Move the header. + */ + memmove(skb->data, skb->data + header_align, header_length); + + /* Move the payload, if present and if required */ + if (payload_length && payload_align) memmove(skb->data + header_length + l2pad, skb->data + header_length + l2pad + payload_align, - frame_length - header_length); - skb_trim(skb, frame_length + l2pad); - } + payload_length); + + /* Trim the skb to the correct size */ + skb_trim(skb, header_length + l2pad + payload_length); } void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) @@ -343,7 +336,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Header and alignment information. */ txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) && + (entry->skb->len > txdesc->header_length)) txdesc->l2pad = L2PAD_SIZE(txdesc->header_length); /* -- GitLab From b734083349d1f1aab1edc810cef02e8046251b48 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:47:04 +0100 Subject: [PATCH 0113/3892] rt2x00: Only remove L2 padding in received frames if there is payload. L2 padding will only be present when there is actual payload present. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index cc6bcc5a20c7..d7711e4d4751 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -401,7 +401,9 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, (rxdesc.flags & RX_FLAG_IV_STRIPPED)) rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); - else if (rxdesc.dev_flags & RXDONE_L2PAD) + else if (header_length && + (rxdesc.size > header_length) && + (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); else rt2x00queue_align_payload(entry->skb, header_length); -- GitLab From 9c8427d9deca1c0c2415c8da0e731e13fc89d111 Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Fri, 4 Dec 2009 23:47:05 +0100 Subject: [PATCH 0114/3892] rt2x00: Disable RX aggregation for rt2800usb RX aggregation is a way to receive multiple 802.11 frames in one RX buffer. However, we don't know yet how to handle this case in rt2800usb_fill_rxdone and this has probably no impact on RX performance as well, so we disable it Signed-off-by: Benoit Papillault Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 13baec485eb6..9c4412b42e5b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -295,9 +295,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); - /* Don't use bulk in aggregation when working with USB 1.1 */ - rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, - (rt2x00dev->rx->usb_maxpacket == 512)); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); /* * Total room for RX frames in kilobytes, PBF might still exceed -- GitLab From 5de42f9eeafa7d54ffb833e0526d4828e194fddb Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Fri, 4 Dec 2009 23:47:06 +0100 Subject: [PATCH 0115/3892] rt2x00: Fix rt2800usb RX frame format and as such L2PAD According to Ralink source code, the RX frame format is RXINFO + RXWI + 802.11 frame + RXD, including various padding. Before this patch, we were using RXD + RXWI + 802.11 frame, so RXD was not correct. Doing this, we fix the L2PAD bit which is now correctly set on received frames. Signed-off-by: Benoit Papillault Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 38 ++++++++--- drivers/net/wireless/rt2x00/rt2800usb.h | 90 +++++++++++++++++++------ 2 files changed, 97 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9c4412b42e5b..40295b454ff6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -571,41 +571,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - __le32 *rxd = (__le32 *)entry->skb->data; + __le32 *rxi = (__le32 *)entry->skb->data; __le32 *rxwi; - u32 rxd0; + __le32 *rxd; + u32 rxi0; u32 rxwi0; u32 rxwi1; u32 rxwi2; u32 rxwi3; + u32 rxd0; + int rx_pkt_len; + + /* + * RX frame format is : + * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad | + * |<------------ rx_pkt_len -------------->| + */ + rt2x00_desc_read(rxi, 0, &rxi0); + rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN); + + rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE); + + /* + * FIXME : we need to check for rx_pkt_len validity + */ + rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len); /* * Copy descriptor to the skbdesc->desc buffer, making it safe from * moving of frame data in rt2x00usb. */ - memcpy(skbdesc->desc, rxd, skbdesc->desc_len); - rxd = (__le32 *)skbdesc->desc; - rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)]; + memcpy(skbdesc->desc, rxi, skbdesc->desc_len); /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &rxd0); rt2x00_desc_read(rxwi, 0, &rxwi0); rt2x00_desc_read(rxwi, 1, &rxwi1); rt2x00_desc_read(rxwi, 2, &rxwi2); rt2x00_desc_read(rxwi, 3, &rxwi3); + rt2x00_desc_read(rxd, 0, &rxd0); - if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR)) + if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); rxdesc->cipher_status = - rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR); + rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); } - if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) { + if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { /* * Hardware has stripped IV/EIV data from 802.11 frame during * decryption. Unfortunately the descriptor doesn't contain @@ -620,10 +636,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_MMIC_ERROR; } - if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) + if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) rxdesc->dev_flags |= RXDONE_L2PAD; if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 1e4340a182ef..d1d8ae94b4d4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -79,6 +79,8 @@ */ #define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) #define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) +#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 1 * sizeof(__le32) ) /* * TX Info structure @@ -100,6 +102,54 @@ #define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000) #define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000) +/* + * RX Info structure + */ + +/* + * Word 0 + */ + +#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) +#define RXWI_W0_BSSID FIELD32(0x00001c00) +#define RXWI_W0_UDF FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define RXWI_W0_TID FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) +#define RXWI_W1_MCS FIELD32(0x007f0000) +#define RXWI_W1_BW FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI FIELD32(0x01000000) +#define RXWI_W1_STBC FIELD32(0x06000000) +#define RXWI_W1_PHYMODE FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0 FIELD32(0x000000ff) +#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0 FIELD32(0x000000ff) +#define RXWI_W3_SNR1 FIELD32(0x0000ff00) + /* * RX descriptor format for RX Ring. */ @@ -115,25 +165,25 @@ * AMSDU: rx with 802.3 header, not 802.11 header. */ -#define RXINFO_W0_BA FIELD32(0x00000001) -#define RXINFO_W0_DATA FIELD32(0x00000002) -#define RXINFO_W0_NULLDATA FIELD32(0x00000004) -#define RXINFO_W0_FRAG FIELD32(0x00000008) -#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010) -#define RXINFO_W0_MULTICAST FIELD32(0x00000020) -#define RXINFO_W0_BROADCAST FIELD32(0x00000040) -#define RXINFO_W0_MY_BSS FIELD32(0x00000080) -#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100) -#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600) -#define RXINFO_W0_AMSDU FIELD32(0x00000800) -#define RXINFO_W0_HTC FIELD32(0x00001000) -#define RXINFO_W0_RSSI FIELD32(0x00002000) -#define RXINFO_W0_L2PAD FIELD32(0x00004000) -#define RXINFO_W0_AMPDU FIELD32(0x00008000) -#define RXINFO_W0_DECRYPTED FIELD32(0x00010000) -#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000) -#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000) -#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000) -#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000) +#define RXD_W0_BA FIELD32(0x00000001) +#define RXD_W0_DATA FIELD32(0x00000002) +#define RXD_W0_NULLDATA FIELD32(0x00000004) +#define RXD_W0_FRAG FIELD32(0x00000008) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) +#define RXD_W0_MULTICAST FIELD32(0x00000020) +#define RXD_W0_BROADCAST FIELD32(0x00000040) +#define RXD_W0_MY_BSS FIELD32(0x00000080) +#define RXD_W0_CRC_ERROR FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) +#define RXD_W0_AMSDU FIELD32(0x00000800) +#define RXD_W0_HTC FIELD32(0x00001000) +#define RXD_W0_RSSI FIELD32(0x00002000) +#define RXD_W0_L2PAD FIELD32(0x00004000) +#define RXD_W0_AMPDU FIELD32(0x00008000) +#define RXD_W0_DECRYPTED FIELD32(0x00010000) +#define RXD_W0_PLCP_RSSI FIELD32(0x00020000) +#define RXD_W0_CIPHER_ALG FIELD32(0x00040000) +#define RXD_W0_LAST_AMSDU FIELD32(0x00080000) +#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) #endif /* RT2800USB_H */ -- GitLab From e54be4e7356c0612b48407d3b0647a29cb82e254 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 4 Dec 2009 23:47:07 +0100 Subject: [PATCH 0116/3892] rt2x00: Fix trimming of L2 padded frames. Ensure that frames without payload are properly trimmed in rt2x00queue_insert_l2pad. This should fix the bug reported by Benoit Papillault in: http://marc.info/?l=linux-wireless&m=125974773006734&w=2 Signed-off-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7452fa850a0f..3d8fb684b4eb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -180,7 +180,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) unsigned int payload_length = skb->len - header_length; unsigned int header_align = ALIGN_SIZE(skb, 0); unsigned int payload_align = ALIGN_SIZE(skb, header_length); - unsigned int l2pad = L2PAD_SIZE(header_length); + unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; /* * Adjust the header alignment if the payload needs to be moved more -- GitLab From b74ab703b1326aafadb5604ff6200da62c61df49 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 22 Dec 2009 12:40:38 +0900 Subject: [PATCH 0117/3892] sh: Don't NOTIFY_STOP for non-UBC breakpoint traps. Presently the hw_breakpoint code is the primary notifier dispatch for breakpoint traps, although it's only UBC traps that are of particular interest there. This patches in a check to allow non-UBC generated breakpoints to pass through down the remainder of the notifier chain, giving things like kgdb a chance at getting notified. Signed-off-by: Paul Mundt --- arch/sh/kernel/hw_breakpoint.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c index 75b8c471120f..022d8ed66bd6 100644 --- a/arch/sh/kernel/hw_breakpoint.c +++ b/arch/sh/kernel/hw_breakpoint.c @@ -398,9 +398,18 @@ BUILD_TRAP_HANDLER(breakpoint) int __kprobes hw_breakpoint_exceptions_notify(struct notifier_block *unused, unsigned long val, void *data) { + struct die_args *args = data; + if (val != DIE_BREAKPOINT) return NOTIFY_DONE; + /* + * If the breakpoint hasn't been triggered by the UBC, it's + * probably from a debugger, so don't do anything more here. + */ + if (args->trapnr != 0x1e0) + return NOTIFY_DONE; + return hw_breakpoint_handler(data); } -- GitLab From 22648735405f73299b717bb5933767e9a9c335ca Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 22 Dec 2009 12:44:14 +0900 Subject: [PATCH 0118/3892] sh: kgdb: Rework breakpoint handling on top of notifier chain. This kills off kgdb's breakpoint handler and ties in to the notifier chain instead. Signed-off-by: Paul Mundt --- arch/sh/kernel/debugtraps.S | 1 - arch/sh/kernel/kgdb.c | 46 +++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S index 591741383ee6..7a1b46fec0f4 100644 --- a/arch/sh/kernel/debugtraps.S +++ b/arch/sh/kernel/debugtraps.S @@ -13,7 +13,6 @@ #include #if !defined(CONFIG_KGDB) -#define breakpoint_trap_handler debug_trap_handler #define singlestep_trap_handler debug_trap_handler #endif diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c index 3e532d0d4a5c..70c69659b846 100644 --- a/arch/sh/kernel/kgdb.c +++ b/arch/sh/kernel/kgdb.c @@ -1,7 +1,7 @@ /* * SuperH KGDB support * - * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 - 2009 Paul Mundt * * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel. * @@ -251,24 +251,60 @@ BUILD_TRAP_HANDLER(singlestep) local_irq_restore(flags); } +static int __kgdb_notify(struct die_args *args, unsigned long cmd) +{ + int ret; + + switch (cmd) { + case DIE_BREAKPOINT: + /* + * This means a user thread is single stepping + * a system call which should be ignored + */ + if (test_thread_flag(TIF_SINGLESTEP)) + return NOTIFY_DONE; + + ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr, + args->err, args->regs); + if (ret) + return NOTIFY_DONE; + + break; + } -BUILD_TRAP_HANDLER(breakpoint) + return NOTIFY_STOP; +} + +static int +kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) { unsigned long flags; - TRAP_HANDLER_DECL; + int ret; local_irq_save(flags); - kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs); + ret = __kgdb_notify(ptr, cmd); local_irq_restore(flags); + + return ret; } +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, + + /* + * Lowest-prio notifier priority, we want to be notified last: + */ + .priority = -INT_MAX, +}; + int kgdb_arch_init(void) { - return 0; + return register_die_notifier(&kgdb_notifier); } void kgdb_arch_exit(void) { + unregister_die_notifier(&kgdb_notifier); } struct kgdb_arch arch_kgdb_ops = { -- GitLab From 8374e24c23448cabf6e78db2c83841c56c5df1e1 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 21 Dec 2009 17:07:08 +0100 Subject: [PATCH 0119/3892] ALSA: refine rate selection in snd_interval_ratnum() Refine the rate selection by choosing the rate closer to the requested one in case of selecting single frequency. Previously, the higher rate was always selected. Also, fix problem with the best_diff unsigned int value wrapping (turning negative). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a27545b23ee9..b07cc361afb1 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -745,10 +745,13 @@ int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, struct snd_ratnum *rats, unsigned int *nump, unsigned int *denp) { - unsigned int best_num, best_diff, best_den; + unsigned int best_num, best_den; + int best_diff; unsigned int k; struct snd_interval t; int err; + unsigned int result_num, result_den; + int result_diff; best_num = best_den = best_diff = 0; for (k = 0; k < rats_count; ++k) { @@ -770,6 +773,8 @@ int snd_interval_ratnum(struct snd_interval *i, den -= r; } diff = num - q * den; + if (diff < 0) + diff = -diff; if (best_num == 0 || diff * best_den < best_diff * den) { best_diff = diff; @@ -784,6 +789,9 @@ int snd_interval_ratnum(struct snd_interval *i, t.min = div_down(best_num, best_den); t.openmin = !!(best_num % best_den); + result_num = best_num; + result_diff = best_diff; + result_den = best_den; best_num = best_den = best_diff = 0; for (k = 0; k < rats_count; ++k) { unsigned int num = rats[k].num; @@ -806,6 +814,8 @@ int snd_interval_ratnum(struct snd_interval *i, den += rats[k].den_step - r; } diff = q * den - num; + if (diff < 0) + diff = -diff; if (best_num == 0 || diff * best_den < best_diff * den) { best_diff = diff; @@ -825,10 +835,14 @@ int snd_interval_ratnum(struct snd_interval *i, return err; if (snd_interval_single(i)) { + if (best_diff * result_den < result_diff * best_den) { + result_num = best_num; + result_den = best_den; + } if (nump) - *nump = best_num; + *nump = result_num; if (denp) - *denp = best_den; + *denp = result_den; } return err; } -- GitLab From 41116e926cb92292fa4fcbe888ae8133fa0038e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Dec 2009 09:00:14 +0100 Subject: [PATCH 0120/3892] ALSA: cs46xx - Fix suspend/resume with new DSP Fix the basic suspend/resume of snd-cs46xx drivers with new DSP. References: https://bugzilla.redhat.com/show_bug.cgi?id=498287 https://bugzilla.redhat.com/show_bug.cgi?id=160751 Tested-by: Florian Zumbiehl Signed-off-by: Takashi Iwai --- include/sound/cs46xx_dsp_spos.h | 6 +++-- sound/pci/cs46xx/cs46xx_lib.c | 2 +- sound/pci/cs46xx/dsp_spos.c | 42 ++++++++++++++++++++++++++--- sound/pci/cs46xx/dsp_spos.h | 4 +++ sound/pci/cs46xx/dsp_spos_scb_lib.c | 33 +++++++++++------------ 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h index 7c44667e79a6..49b03c9e5e55 100644 --- a/include/sound/cs46xx_dsp_spos.h +++ b/include/sound/cs46xx_dsp_spos.h @@ -118,9 +118,11 @@ struct dsp_scb_descriptor { struct snd_info_entry *proc_info; int ref_count; - spinlock_t lock; - int deleted; + u16 volume[2]; + unsigned int deleted :1; + unsigned int updated :1; + unsigned int volume_set :1; }; struct dsp_task_descriptor { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 1be96ead4244..e6b4a879ae2e 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = { #ifdef CONFIG_PM static unsigned int saved_regs[] = { BA0_ACOSV, - BA0_ASER_FADDR, + /*BA0_ASER_FADDR,*/ BA0_ASER_MASTER, BA1_PVOL, BA1_CVOL, diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f4f0c8f5dad7..3e5ca8fb519f 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); +#ifdef CONFIG_PM + kfree(ins->scbs[i].data); +#endif } kfree(ins->code.data); @@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam index = find_free_scb_index (ins); + memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); strcpy(ins->scbs[index].scb_name, name); ins->scbs[index].address = dest; ins->scbs[index].index = index; - ins->scbs[index].proc_info = NULL; ins->scbs[index].ref_count = 1; - ins->scbs[index].deleted = 0; - spin_lock_init(&ins->scbs[index].lock); desc = (ins->scbs + index); ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); @@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) return desc; } +#define SCB_BYTES (0x10 * 4) + struct dsp_scb_descriptor * cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) { struct dsp_scb_descriptor * desc; +#ifdef CONFIG_PM + /* copy the data for resume */ + scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL); + if (!scb_data) + return NULL; +#endif + desc = _map_scb (chip,name,dest); if (desc) { desc->data = scb_data; _dsp_create_scb(chip,scb_data,dest); } else { snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); +#ifdef CONFIG_PM + kfree(scb_data); +#endif } return desc; @@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip) continue; _dsp_create_scb(chip, s->data, s->address); } - + for (i = 0; i < ins->nscb; i++) { + struct dsp_scb_descriptor *s = &ins->scbs[i]; + if (s->deleted) + continue; + if (s->updated) + cs46xx_dsp_spos_update_scb(chip, s); + if (s->volume_set) + cs46xx_dsp_scb_set_volume(chip, s, + s->volume[0], s->volume[1]); + } + if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { + cs46xx_dsp_enable_spdif_hw(chip); + snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2, + (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10); + if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) + cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV, + ins->spdif_csuv_stream); + } + if (chip->dsp_spos_instance->spdif_status_in) { + cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005); + cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff); + } return 0; } #endif diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index f9e169d33c03..ca47a8114c7f 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h @@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip, (scb->address + SCBsubListPtr) << 2, (scb->sub_list_ptr->address << 0x10) | (scb->next_scb_ptr->address)); + scb->updated = 1; } static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, @@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); + scb->volume_set = 1; + scb->volume[0] = left; + scb->volume[1] = right; } #endif /* __DSP_SPOS_H__ */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */ diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index dd7c41b037b4..00b148a10239 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - unsigned long flags; if ( scb->parent_scb_ptr ) { /* unlink parent SCB */ @@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor scb->next_scb_ptr = ins->the_null_scb; } - spin_lock_irqsave(&chip->reg_lock, flags); - /* update parent first entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); @@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor cs46xx_dsp_spos_update_scb(chip,scb); scb->parent_scb_ptr = NULL; - spin_unlock_irqrestore(&chip->reg_lock, flags); } } @@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * goto _end; #endif - spin_lock_irqsave(&scb->lock, flags); + spin_lock_irqsave(&chip->reg_lock, flags); _dsp_unlink_scb (chip,scb); - spin_unlock_irqrestore(&scb->lock, flags); + spin_unlock_irqrestore(&chip->reg_lock, flags); cs46xx_dsp_proc_free_scb_desc(scb); if (snd_BUG_ON(!scb->scb_symbol)) @@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * remove_symbol (chip,scb->scb_symbol); ins->scbs[scb->index].deleted = 1; +#ifdef CONFIG_PM + kfree(ins->scbs[scb->index].data); + ins->scbs[scb->index].data = NULL; +#endif if (scb->index < ins->scb_highest_frag_index) ins->scb_highest_frag_index = scb->index; @@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip, chip->dsp_spos_instance->npcm_channels <= 0)) return -EIO; - spin_lock(&pcm_channel->src_scb->lock); - + spin_lock_irqsave(&chip->reg_lock, flags); if (pcm_channel->unlinked) { - spin_unlock(&pcm_channel->src_scb->lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return -EIO; } - spin_lock_irqsave(&chip->reg_lock, flags); pcm_channel->unlinked = 1; - spin_unlock_irqrestore(&chip->reg_lock, flags); _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); + spin_unlock_irqrestore(&chip->reg_lock, flags); - spin_unlock(&pcm_channel->src_scb->lock); return 0; } @@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; unsigned long flags; - spin_lock(&pcm_channel->src_scb->lock); + spin_lock_irqsave(&chip->reg_lock, flags); if (pcm_channel->unlinked == 0) { - spin_unlock(&pcm_channel->src_scb->lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return -EIO; } @@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; - spin_lock_irqsave(&chip->reg_lock, flags); - /* update SCB entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); @@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, pcm_channel->unlinked = 0; spin_unlock_irqrestore(&chip->reg_lock, flags); - - spin_unlock(&pcm_channel->src_scb->lock); return 0; } @@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) { + unsigned long flags; + if (snd_BUG_ON(!src->parent_scb_ptr)) return -EINVAL; /* mute SCB */ cs46xx_dsp_scb_set_volume (chip,src,0,0); + spin_lock_irqsave(&chip->reg_lock, flags); _dsp_unlink_scb (chip,src); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -- GitLab From 75d1aeb9d6899b10420d10284e8ea894b2794224 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Dec 2009 11:56:32 +0100 Subject: [PATCH 0121/3892] ALSA: hda - Add Bass Speaker switch for HP dv7 The bass speaker is controlled via GPIO5. Tested-by: Wael Nasreddine Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0bafea9d5106..a4526d008042 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5402,6 +5402,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, return 0; } +/* HP dv7 bass switch - GPIO5 */ +#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info +static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); + return 0; +} + +static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int gpio_data; + + gpio_data = (spec->gpio_data & ~0x20) | + (ucontrol->value.integer.value[0] ? 0x20 : 0); + if (gpio_data == spec->gpio_data) + return 0; + spec->gpio_data = gpio_data; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); + return 1; +} + +static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = stac_hp_bass_gpio_info, + .get = stac_hp_bass_gpio_get, + .put = stac_hp_bass_gpio_put, +}; + +static int stac_add_hp_bass_switch(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, + "Bass Speaker Playback Switch", 0)) + return -ENOMEM; + + spec->gpio_mask |= 0x20; + spec->gpio_dir |= 0x20; + spec->gpio_data |= 0x20; + return 0; +} + static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5642,6 +5690,15 @@ again: return err; } + /* enable bass on HP dv7 */ + if (spec->board_config == STAC_HP_DV5) { + unsigned int cap; + cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); + cap &= AC_GPIO_IO_COUNT; + if (cap >= 6) + stac_add_hp_bass_switch(codec); + } + codec->proc_widget_hook = stac92hd7x_proc_hook; return 0; -- GitLab From ca99861d5421c91f5a8fd3a77acb4b7be14f119d Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Wed, 9 Dec 2009 23:25:05 +0100 Subject: [PATCH 0122/3892] mac80211 : fix a race with update_tkip_key The mac80211 tkip code won't call update_tkip_key, if rx packets are received without KEY_FLAG_UPLOADED_TO_HARDWARE. This can happen on first packet because the hardware key stuff is called asynchronously with todo workqueue. This patch workaround that by tracking if we sent the key to the driver. Signed-off-by: Gregor Kowski Signed-off-by: John W. Linville --- net/mac80211/key.h | 8 +++++++- net/mac80211/tkip.c | 38 ++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/net/mac80211/key.h b/net/mac80211/key.h index a49f93b79e92..bdc2968c2bbe 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -59,11 +59,17 @@ enum ieee80211_internal_key_flags { KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), }; +enum ieee80211_internal_tkip_state { + TKIP_STATE_NOT_INIT, + TKIP_STATE_PHASE1_DONE, + TKIP_STATE_PHASE1_HW_UPLOADED, +}; + struct tkip_ctx { u32 iv32; u16 iv16; u16 p1k[5]; - int initialized; + enum ieee80211_internal_tkip_state state; }; struct ieee80211_key { diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 4921d724b6c7..b73454a507f9 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -100,7 +100,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; } - ctx->initialized = 1; + ctx->state = TKIP_STATE_PHASE1_DONE; } static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, @@ -183,7 +183,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, /* Update the p1k only when the iv16 in the packet wraps around, this * might occur after the wrap around of iv16 in the key in case of * fragmented packets. */ - if (iv16 == 0 || !ctx->initialized) + if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); if (type == IEEE80211_TKIP_P1_KEY) { @@ -209,7 +209,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; /* Calculate per-packet key */ - if (ctx->iv16 == 0 || !ctx->initialized) + if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); @@ -259,7 +259,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (key->u.tkip.rx[queue].initialized && + if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && (iv32 < key->u.tkip.rx[queue].iv32 || (iv32 == key->u.tkip.rx[queue].iv32 && iv16 <= key->u.tkip.rx[queue].iv16))) { @@ -275,11 +275,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (only_iv) { res = TKIP_DECRYPT_OK; - key->u.tkip.rx[queue].initialized = 1; + key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; goto done; } - if (!key->u.tkip.rx[queue].initialized || + if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT || key->u.tkip.rx[queue].iv32 != iv32) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); @@ -299,18 +299,20 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("\n"); } #endif - if (key->local->ops->update_tkip_key && - key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - static const u8 bcast[ETH_ALEN] = - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - const u8 *sta_addr = key->sta->sta.addr; - - if (is_multicast_ether_addr(ra)) - sta_addr = bcast; - - drv_update_tkip_key(key->local, &key->conf, sta_addr, - iv32, key->u.tkip.rx[queue].p1k); - } + } + if (key->local->ops->update_tkip_key && + key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && + key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { + static const u8 bcast[ETH_ALEN] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *sta_addr = key->sta->sta.addr; + + if (is_multicast_ether_addr(ra)) + sta_addr = bcast; + + drv_update_tkip_key(key->local, &key->conf, sta_addr, + iv32, key->u.tkip.rx[queue].p1k); + key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; } tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); -- GitLab From eaf85ca7fecb218fc41ff57c1642ca73b097aabb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Dec 2009 10:18:37 +0800 Subject: [PATCH 0123/3892] wireless: add ieee80211_amsdu_to_8023s Move the A-MSDU handling code from mac80211 to cfg80211 so that more drivers can use it. The new created function ieee80211_amsdu_to_8023s converts an A-MSDU frame to a list of 802.3 frames. Cc: Johannes Berg Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- include/net/cfg80211.h | 22 ++++++++- net/mac80211/rx.c | 106 ++++++++--------------------------------- net/wireless/util.c | 99 +++++++++++++++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 90 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0884b9a0f778..542a477a94da 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1578,7 +1578,7 @@ unsigned int ieee80211_hdrlen(__le16 fc); * @addr: the device MAC address * @iftype: the virtual interface type */ -int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype); /** @@ -1589,9 +1589,27 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, * @bssid: the network bssid (used only for iftype STATION and ADHOC) * @qos: build 802.11 QoS data frame */ -int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, +int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype, u8 *bssid, bool qos); +/** + * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame + * + * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of + * 802.3 frames. The @list will be empty if the decode fails. The + * @skb is consumed after the function returns. + * + * @skb: The input IEEE 802.11n A-MSDU frame. + * @list: The output list of 802.3 frames. It must be allocated and + * initialized by by the caller. + * @addr: The device MAC address. + * @iftype: The device interface type. + * @extra_headroom: The hardware extra headroom for SKBs in the @list. + */ +void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, + const u8 *addr, enum nl80211_iftype iftype, + const unsigned int extra_headroom); + /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame * @skb: the data frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dbfd684e3e2e..a182e423109b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1541,16 +1541,10 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->sdata->dev; - struct ieee80211_local *local = rx->local; - u16 ethertype; - u8 *payload; - struct sk_buff *skb = rx->skb, *frame = NULL; + struct sk_buff *skb = rx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - const struct ethhdr *eth; - int remaining, err; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; + struct sk_buff_head frame_list; if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -1561,94 +1555,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; - err = __ieee80211_data_to_8023(rx); - if (unlikely(err)) + if (ieee80211_has_a4(hdr->frame_control) && + rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + !rx->sdata->u.vlan.sta) return RX_DROP_UNUSABLE; - skb->dev = dev; - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - /* skip the wrapping header */ - eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); - if (!eth) + if (is_multicast_ether_addr(hdr->addr1) && + ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + rx->sdata->u.vlan.sta) || + (rx->sdata->vif.type == NL80211_IFTYPE_STATION && + rx->sdata->u.mgd.use_4addr))) return RX_DROP_UNUSABLE; - while (skb != frame) { - u8 padding; - __be16 len = eth->h_proto; - unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); - - remaining = skb->len; - memcpy(dst, eth->h_dest, ETH_ALEN); - memcpy(src, eth->h_source, ETH_ALEN); + skb->dev = dev; + __skb_queue_head_init(&frame_list); - padding = ((4 - subframe_len) & 0x3); - /* the last MSDU has no padding */ - if (subframe_len > remaining) - return RX_DROP_UNUSABLE; + ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, + rx->sdata->vif.type, + rx->local->hw.extra_tx_headroom); - skb_pull(skb, sizeof(struct ethhdr)); - /* if last subframe reuse skb */ - if (remaining <= subframe_len + padding) - frame = skb; - else { - /* - * Allocate and reserve two bytes more for payload - * alignment since sizeof(struct ethhdr) is 14. - */ - frame = dev_alloc_skb( - ALIGN(local->hw.extra_tx_headroom, 4) + - subframe_len + 2); - - if (frame == NULL) - return RX_DROP_UNUSABLE; - - skb_reserve(frame, - ALIGN(local->hw.extra_tx_headroom, 4) + - sizeof(struct ethhdr) + 2); - memcpy(skb_put(frame, ntohs(len)), skb->data, - ntohs(len)); - - eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + - padding); - if (!eth) { - dev_kfree_skb(frame); - return RX_DROP_UNUSABLE; - } - } - - skb_reset_network_header(frame); - frame->dev = dev; - frame->priority = skb->priority; - rx->skb = frame; - - payload = frame->data; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, - bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel - * encapsulation and replace EtherType */ - skb_pull(frame, 6); - memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); - } else { - memcpy(skb_push(frame, sizeof(__be16)), - &len, sizeof(__be16)); - memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); - } + while (!skb_queue_empty(&frame_list)) { + rx->skb = __skb_dequeue(&frame_list); if (!ieee80211_frame_allowed(rx, fc)) { - if (skb == frame) /* last frame */ - return RX_DROP_UNUSABLE; - dev_kfree_skb(frame); + dev_kfree_skb(rx->skb); continue; } + dev->stats.rx_packets++; + dev->stats.rx_bytes += rx->skb->len; ieee80211_deliver_skb(rx); } diff --git a/net/wireless/util.c b/net/wireless/util.c index a3c841a255db..23557c1d0a9c 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -285,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) } } -int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -383,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, } EXPORT_SYMBOL(ieee80211_data_to_8023); -int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, +int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype, u8 *bssid, bool qos) { struct ieee80211_hdr hdr; @@ -497,6 +497,101 @@ int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, } EXPORT_SYMBOL(ieee80211_data_from_8023); + +void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, + const u8 *addr, enum nl80211_iftype iftype, + const unsigned int extra_headroom) +{ + struct sk_buff *frame = NULL; + u16 ethertype; + u8 *payload; + const struct ethhdr *eth; + int remaining, err; + u8 dst[ETH_ALEN], src[ETH_ALEN]; + + err = ieee80211_data_to_8023(skb, addr, iftype); + if (err) + goto out; + + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) + goto out; + + while (skb != frame) { + u8 padding; + __be16 len = eth->h_proto; + unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); + + remaining = skb->len; + memcpy(dst, eth->h_dest, ETH_ALEN); + memcpy(src, eth->h_source, ETH_ALEN); + + padding = (4 - subframe_len) & 0x3; + /* the last MSDU has no padding */ + if (subframe_len > remaining) + goto purge; + + skb_pull(skb, sizeof(struct ethhdr)); + /* reuse skb for the last subframe */ + if (remaining <= subframe_len + padding) + frame = skb; + else { + unsigned int hlen = ALIGN(extra_headroom, 4); + /* + * Allocate and reserve two bytes more for payload + * alignment since sizeof(struct ethhdr) is 14. + */ + frame = dev_alloc_skb(hlen + subframe_len + 2); + if (!frame) + goto purge; + + skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); + memcpy(skb_put(frame, ntohs(len)), skb->data, + ntohs(len)); + + eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + + padding); + if (!eth) { + dev_kfree_skb(frame); + goto purge; + } + } + + skb_reset_network_header(frame); + frame->dev = skb->dev; + frame->priority = skb->priority; + + payload = frame->data; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, + bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel + * encapsulation and replace EtherType */ + skb_pull(frame, 6); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } else { + memcpy(skb_push(frame, sizeof(__be16)), &len, + sizeof(__be16)); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } + __skb_queue_tail(list, frame); + } + + return; + + purge: + __skb_queue_purge(list); + out: + dev_kfree_skb(skb); +} +EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); + /* Given a data frame determine the 802.1p/1d tag to use. */ unsigned int cfg80211_classify8021d(struct sk_buff *skb) { -- GitLab From 18974b5b0b5e758d416c550553b143e5c8038281 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Dec 2009 10:18:38 +0800 Subject: [PATCH 0124/3892] iwmc3200wifi: rx aggregation support When the device receives an A-MSDU frame (indicated by flag IWM_RX_TICKET_AMSDU_MSK), use ieee80211_amsdu_to_8023s to convert it to a list of 802.3 frames and handled them to upper layer. Cc: Johannes Berg Acked-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 46 +++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 72c27a3e5528..6bd253ac533f 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1534,6 +1534,33 @@ static void classify8023(struct sk_buff *skb) } } +static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) +{ + struct wireless_dev *wdev = iwm_to_wdev(iwm); + struct net_device *ndev = iwm_to_ndev(iwm); + struct sk_buff_head list; + struct sk_buff *frame; + + IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); + + __skb_queue_head_init(&list); + ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0); + + while ((frame = __skb_dequeue(&list))) { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += frame->len; + + frame->protocol = eth_type_trans(frame, ndev); + frame->ip_summed = CHECKSUM_NONE; + memset(frame->cb, 0, sizeof(frame->cb)); + + if (netif_rx_ni(frame) == NET_RX_DROP) { + IWM_ERR(iwm, "Packet dropped\n"); + ndev->stats.rx_dropped++; + } + } +} + static void iwm_rx_process_packet(struct iwm_priv *iwm, struct iwm_rx_packet *packet, struct iwm_rx_ticket_node *ticket_node) @@ -1548,25 +1575,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, switch (le16_to_cpu(ticket_node->ticket->action)) { case IWM_RX_TICKET_RELEASE: IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); - classify8023(skb); + iwm_rx_adjust_packet(iwm, packet, ticket_node); + skb->dev = iwm_to_ndev(iwm); + classify8023(skb); + + if (le16_to_cpu(ticket_node->ticket->flags) & + IWM_RX_TICKET_AMSDU_MSK) { + iwm_rx_process_amsdu(iwm, skb); + break; + } + ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); if (ret < 0) { IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " "%d\n", ret); + kfree_skb(packet->skb); break; } IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); - skb->dev = iwm_to_ndev(iwm); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, ndev); skb->ip_summed = CHECKSUM_NONE; memset(skb->cb, 0, sizeof(skb->cb)); - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; - if (netif_rx_ni(skb) == NET_RX_DROP) { IWM_ERR(iwm, "Packet dropped\n"); ndev->stats.rx_dropped++; -- GitLab From 0f78231bffb868a30e8533aace142213266bb811 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 1 Dec 2009 13:37:02 +0100 Subject: [PATCH 0125/3892] mac80211: enable spatial multiplexing powersave Enable spatial multiplexing in mac80211 by telling the driver what to do and, where necessary, sending action frames to the AP to update the requested SMPS mode. Also includes a trivial implementation for hwsim that just logs the requested mode. For now, the userspace interface is in debugfs only, and let you toggle the requested mode at any time. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 24 +++++- include/linux/ieee80211.h | 25 +++++- include/net/mac80211.h | 59 ++++++++++++++ net/mac80211/cfg.c | 49 ++++++++++++ net/mac80211/debugfs_netdev.c | 111 +++++++++++++++++++++++++- net/mac80211/driver-trace.h | 2 + net/mac80211/ht.c | 47 +++++++++++ net/mac80211/ieee80211_i.h | 14 ++++ net/mac80211/main.c | 24 ++++++ net/mac80211/mlme.c | 63 ++++++++++++++- net/mac80211/status.c | 38 +++++++++ net/mac80211/util.c | 74 +++++++++++++++++ 12 files changed, 518 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 88e41176e7fd..92c669ebb358 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -618,12 +618,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - - printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", + static const char *chantypes[4] = { + [NL80211_CHAN_NO_HT] = "noht", + [NL80211_CHAN_HT20] = "ht20", + [NL80211_CHAN_HT40MINUS] = "ht40-", + [NL80211_CHAN_HT40PLUS] = "ht40+", + }; + static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { + [IEEE80211_SMPS_AUTOMATIC] = "auto", + [IEEE80211_SMPS_OFF] = "off", + [IEEE80211_SMPS_STATIC] = "static", + [IEEE80211_SMPS_DYNAMIC] = "dynamic", + }; + + printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", wiphy_name(hw->wiphy), __func__, conf->channel->center_freq, + chantypes[conf->channel_type], !!(conf->flags & IEEE80211_CONF_IDLE), - !!(conf->flags & IEEE80211_CONF_PS)); + !!(conf->flags & IEEE80211_CONF_PS), + smps_modes[conf->smps_mode]); data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); @@ -1082,7 +1096,9 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_MESH_POINT); hw->flags = IEEE80211_HW_MFP_CAPABLE | - IEEE80211_HW_SIGNAL_DBM; + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_STATIC_SMPS | + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d9724a28c0c2..e8d43d0ff2c3 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -707,6 +707,10 @@ struct ieee80211_mgmt { u8 action; u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } __attribute__ ((packed)) sa_query; + struct { + u8 action; + u8 smps_control; + } __attribute__ ((packed)) ht_smps; } u; } __attribute__ ((packed)) action; } u; @@ -824,6 +828,7 @@ struct ieee80211_ht_cap { #define IEEE80211_HT_CAP_LDPC_CODING 0x0001 #define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 #define IEEE80211_HT_CAP_SM_PS 0x000C +#define IEEE80211_HT_CAP_SM_PS_SHIFT 2 #define IEEE80211_HT_CAP_GRN_FLD 0x0010 #define IEEE80211_HT_CAP_SGI_20 0x0020 #define IEEE80211_HT_CAP_SGI_40 0x0040 @@ -839,6 +844,7 @@ struct ieee80211_ht_cap { /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C +#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 /* * Maximum length of AMPDU that the STA can receive. @@ -922,12 +928,17 @@ struct ieee80211_ht_info { #define IEEE80211_MAX_AMPDU_BUF 0x40 -/* Spatial Multiplexing Power Save Modes */ +/* Spatial Multiplexing Power Save Modes (for capability) */ #define WLAN_HT_CAP_SM_PS_STATIC 0 #define WLAN_HT_CAP_SM_PS_DYNAMIC 1 #define WLAN_HT_CAP_SM_PS_INVALID 2 #define WLAN_HT_CAP_SM_PS_DISABLED 3 +/* for SM power control field lower two bits */ +#define WLAN_HT_SMPS_CONTROL_DISABLED 0 +#define WLAN_HT_SMPS_CONTROL_STATIC 1 +#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -1150,6 +1161,18 @@ enum ieee80211_spectrum_mgmt_actioncode { WLAN_ACTION_SPCT_CHL_SWITCH = 4, }; +/* HT action codes */ +enum ieee80211_ht_actioncode { + WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0, + WLAN_HT_ACTION_SMPS = 1, + WLAN_HT_ACTION_PSMP = 2, + WLAN_HT_ACTION_PCO_PHASE = 3, + WLAN_HT_ACTION_CSI = 4, + WLAN_HT_ACTION_NONCOMPRESSED_BF = 5, + WLAN_HT_ACTION_COMPRESSED_BF = 6, + WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, +}; + /* Security key length */ enum ieee80211_key_len { WLAN_KEY_LEN_WEP40 = 5, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e94cc526b0f6..e6b6bf81d5b9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -597,8 +597,10 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed + * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed */ enum ieee80211_conf_changed { + IEEE80211_CONF_CHANGE_SMPS = BIT(1), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_MONITOR = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -608,6 +610,21 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; +/** + * enum ieee80211_smps_mode - spatial multiplexing power save mode + * + * @ + */ +enum ieee80211_smps_mode { + IEEE80211_SMPS_AUTOMATIC, + IEEE80211_SMPS_OFF, + IEEE80211_SMPS_STATIC, + IEEE80211_SMPS_DYNAMIC, + + /* keep last */ + IEEE80211_SMPS_NUM_MODES, +}; + /** * struct ieee80211_conf - configuration of the device * @@ -636,6 +653,10 @@ enum ieee80211_conf_changed { * @short_frame_max_tx_count: Maximum number of transmissions for a "short" * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the * number of transmissions not the number of retries + * + * @smps_mode: spatial multiplexing powersave mode; note that + * %IEEE80211_SMPS_STATIC is used when the device is not + * configured for an HT channel */ struct ieee80211_conf { u32 flags; @@ -648,6 +669,7 @@ struct ieee80211_conf { struct ieee80211_channel *channel; enum nl80211_channel_type channel_type; + enum ieee80211_smps_mode smps_mode; }; /** @@ -930,6 +952,16 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_BEACON_FILTER: * Hardware supports dropping of irrelevant beacon frames to * avoid waking up cpu. + * + * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: + * Hardware supports static spatial multiplexing powersave, + * ie. can turn off all but one chain even on HT connections + * that should be using more chains. + * + * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS: + * Hardware supports dynamic spatial multiplexing powersave, + * ie. can turn off all but one chain and then wake the rest + * up as required after, for example, rts/cts handshake. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -947,6 +979,8 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, IEEE80211_HW_MFP_CAPABLE = 1<<13, IEEE80211_HW_BEACON_FILTER = 1<<14, + IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, }; /** @@ -1214,6 +1248,31 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * signal strength threshold checking. */ +/** + * DOC: Spatial multiplexing power save + * + * SMPS (Spatial multiplexing power save) is a mechanism to conserve + * power in an 802.11n implementation. For details on the mechanism + * and rationale, please refer to 802.11 (as amended by 802.11n-2009) + * "11.2.3 SM power save". + * + * The mac80211 implementation is capable of sending action frames + * to update the AP about the station's SMPS mode, and will instruct + * the driver to enter the specific mode. It will also announce the + * requested SMPS mode during the association handshake. Hardware + * support for this feature is required, and can be indicated by + * hardware flags. + * + * The default mode will be "automatic", which nl80211/cfg80211 + * defines to be dynamic SMPS in (regular) powersave, and SMPS + * turned off otherwise. + * + * To support this feature, the driver must set the appropriate + * hardware support flags, and handle the SMPS flag to the config() + * operation. It will then with this mechanism be instructed to + * enter the requested SMPS mode while associated to an HT AP. + */ + /** * DOC: Frame filtering * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fcfa1bf776a7..8c35418d1c96 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1318,6 +1318,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) } #endif +int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode) +{ + const u8 *ap; + enum ieee80211_smps_mode old_req; + int err; + + old_req = sdata->u.mgd.req_smps; + sdata->u.mgd.req_smps = smps_mode; + + if (old_req == smps_mode && + smps_mode != IEEE80211_SMPS_AUTOMATIC) + return 0; + + /* + * If not associated, or current association is not an HT + * association, there's no need to send an action frame. + */ + if (!sdata->u.mgd.associated || + sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_smps(sdata->local, sdata); + mutex_unlock(&sdata->local->iflist_mtx); + return 0; + } + + ap = sdata->u.mgd.associated->cbss.bssid; + + if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { + if (sdata->u.mgd.powersave) + smps_mode = IEEE80211_SMPS_DYNAMIC; + else + smps_mode = IEEE80211_SMPS_OFF; + } + + /* send SM PS frame to AP */ + err = ieee80211_send_smps_action(sdata, smps_mode, + ap, ap); + if (err) + sdata->u.mgd.req_smps = old_req; + + return err; +} + static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { @@ -1335,6 +1379,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.powersave = enabled; conf->dynamic_ps_timeout = timeout; + /* no change, but if automatic follow powersave */ + mutex_lock(&sdata->u.mgd.mtx); + __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); + mutex_unlock(&sdata->u.mgd.mtx); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 5d9c797635a9..355983503885 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read( return ret; } +static ssize_t ieee80211_if_write( + struct ieee80211_sub_if_data *sdata, + const char __user *userbuf, + size_t count, loff_t *ppos, + ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int)) +{ + u8 *buf; + ssize_t ret = -ENODEV; + + buf = kzalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + + rtnl_lock(); + if (sdata->dev->reg_state == NETREG_REGISTERED) + ret = (*write)(sdata, buf, count); + rtnl_unlock(); + + return ret; +} + #define IEEE80211_IF_FMT(name, field, format_string) \ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ @@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name( \ return scnprintf(buf, buflen, "%pM\n", sdata->field); \ } -#define __IEEE80211_IF_FILE(name) \ +#define __IEEE80211_IF_FILE(name, _write) \ static ssize_t ieee80211_if_read_##name(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -82,12 +106,24 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ } \ static const struct file_operations name##_ops = { \ .read = ieee80211_if_read_##name, \ + .write = (_write), \ .open = mac80211_open_file_generic, \ } +#define __IEEE80211_IF_FILE_W(name) \ +static ssize_t ieee80211_if_write_##name(struct file *file, \ + const char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + return ieee80211_if_write(file->private_data, userbuf, count, \ + ppos, ieee80211_if_parse_##name); \ +} \ +__IEEE80211_IF_FILE(name, ieee80211_if_write_##name) + + #define IEEE80211_IF_FILE(name, field, format) \ IEEE80211_IF_FMT_##format(name, field) \ - __IEEE80211_IF_FILE(name) + __IEEE80211_IF_FILE(name, NULL) /* common attributes */ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); @@ -99,6 +135,70 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); +static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode) +{ + struct ieee80211_local *local = sdata->local; + int err; + + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && + smps_mode == IEEE80211_SMPS_STATIC) + return -EINVAL; + + /* auto should be dynamic if in PS mode */ + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && + (smps_mode == IEEE80211_SMPS_DYNAMIC || + smps_mode == IEEE80211_SMPS_AUTOMATIC)) + return -EINVAL; + + /* supported only on managed interfaces for now */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + mutex_lock(&local->iflist_mtx); + err = __ieee80211_request_smps(sdata, smps_mode); + mutex_unlock(&local->iflist_mtx); + + return err; +} + +static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { + [IEEE80211_SMPS_AUTOMATIC] = "auto", + [IEEE80211_SMPS_OFF] = "off", + [IEEE80211_SMPS_STATIC] = "static", + [IEEE80211_SMPS_DYNAMIC] = "dynamic", +}; + +static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, + char *buf, int buflen) +{ + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + return snprintf(buf, buflen, "request: %s\nused: %s\n", + smps_modes[sdata->u.mgd.req_smps], + smps_modes[sdata->u.mgd.ap_smps]); +} + +static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, + const char *buf, int buflen) +{ + enum ieee80211_smps_mode mode; + + for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) { + if (strncmp(buf, smps_modes[mode], buflen) == 0) { + int err = ieee80211_set_smps(sdata, mode); + if (!err) + return buflen; + return err; + } + } + + return -EINVAL; +} + +__IEEE80211_IF_FILE_W(smps); + /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); @@ -109,7 +209,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( return scnprintf(buf, buflen, "%u\n", skb_queue_len(&sdata->u.ap.ps_bc_buf)); } -__IEEE80211_IF_FILE(num_buffered_multicast); +__IEEE80211_IF_FILE(num_buffered_multicast, NULL); /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); @@ -158,6 +258,10 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ sdata, &name##_ops); +#define DEBUGFS_ADD_MODE(name, mode) \ + debugfs_create_file(#name, mode, sdata->debugfs.dir, \ + sdata, &name##_ops); + static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, sta); @@ -167,6 +271,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(aid, sta); DEBUGFS_ADD(capab, sta); + DEBUGFS_ADD_MODE(smps, 0600); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index ee2d19a25ce1..7a849b920165 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -140,6 +140,7 @@ TRACE_EVENT(drv_config, __field(u8, short_frame_max_tx_count) __field(int, center_freq) __field(int, channel_type) + __field(int, smps) ), TP_fast_assign( @@ -155,6 +156,7 @@ TRACE_EVENT(drv_config, __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; __entry->center_freq = local->hw.conf.channel->center_freq; __entry->channel_type = local->hw.conf.channel_type; + __entry->smps = local->hw.conf.smps_mode; ), TP_printk( diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 45ebd062a2fb..63b8f86b7f16 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -166,3 +166,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&sta->lock); } } + +int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps, const u8 *da, + const u8 *bssid) +{ + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom); + action_frame = (void *)skb_put(skb, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_NUM_MODES: + WARN_ON(1); + case IEEE80211_SMPS_OFF: + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED; + break; + case IEEE80211_SMPS_STATIC: + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC; + break; + case IEEE80211_SMPS_DYNAMIC: + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC; + break; + } + + /* we'll do more on status of this frame */ + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + ieee80211_tx_skb(sdata, skb); + + return 0; +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 178e329f9257..e63aecbddfbe 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -297,6 +297,8 @@ struct ieee80211_if_managed { unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ + enum ieee80211_smps_mode req_smps, /* requested smps mode */ + ap_smps; /* smps mode AP thinks we're in */ unsigned long request; @@ -587,6 +589,9 @@ struct ieee80211_local { /* used for uploading changed mc list */ struct work_struct reconfig_filter; + /* used to reconfigure hardware SM PS */ + struct work_struct recalc_smps; + /* aggregated multicast list */ struct dev_addr_list *mc_list; int mc_count; @@ -760,6 +765,8 @@ struct ieee80211_local { int user_power_level; /* in dBm */ int power_constr_level; /* in dBm */ + enum ieee80211_smps_mode smps_mode; + struct work_struct restart_work; #ifdef CONFIG_MAC80211_DEBUGFS @@ -978,6 +985,9 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, u16 initiator, u16 reason_code); +int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps, const u8 *da, + const u8 *bssid); void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, u16 initiator, u16 reason); @@ -1088,6 +1098,10 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, u32 ieee80211_sta_get_rates(struct ieee80211_local *local, struct ieee802_11_elems *elems, enum ieee80211_band band); +int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, + enum ieee80211_smps_mode smps_mode); +void ieee80211_recalc_smps(struct ieee80211_local *local, + struct ieee80211_sub_if_data *forsdata); #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 98320a94c270..e1293e8ed83a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -113,6 +113,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) changed |= IEEE80211_CONF_CHANGE_CHANNEL; } + if (!conf_is_ht(&local->hw.conf)) { + /* + * mac80211.h documents that this is only valid + * when the channel is set to an HT type, and + * that otherwise STATIC is used. + */ + local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; + } else if (local->hw.conf.smps_mode != local->smps_mode) { + local->hw.conf.smps_mode = local->smps_mode; + changed |= IEEE80211_CONF_CHANGE_SMPS; + } + if (scan_chan) power = chan->max_power; else @@ -297,6 +309,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_restart_hw); +static void ieee80211_recalc_smps_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, recalc_smps); + + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_smps(local, NULL); + mutex_unlock(&local->iflist_mtx); +} + struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -370,6 +392,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); + local->smps_mode = IEEE80211_SMPS_OFF; INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cd5dcc3d8c2b..0a762a9ba4df 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -398,6 +398,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, __le16 tmp; u32 flags = local->hw.conf.channel->flags; + /* determine capability flags */ + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (flags & IEEE80211_CHAN_NO_HT40PLUS) { @@ -413,17 +415,64 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, break; } - tmp = cpu_to_le16(cap); - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); + /* set SM PS mode properly */ + cap &= ~IEEE80211_HT_CAP_SM_PS; + /* new association always uses requested smps mode */ + if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { + if (ifmgd->powersave) + ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; + else + ifmgd->ap_smps = IEEE80211_SMPS_OFF; + } else + ifmgd->ap_smps = ifmgd->req_smps; + + switch (ifmgd->ap_smps) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_NUM_MODES: + WARN_ON(1); + case IEEE80211_SMPS_OFF: + cap |= WLAN_HT_CAP_SM_PS_DISABLED << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_STATIC: + cap |= WLAN_HT_CAP_SM_PS_STATIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_DYNAMIC: + cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + } + + /* reserve and fill IE */ + + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + + /* capability flags */ + tmp = cpu_to_le16(cap); memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); - /* TODO: needs a define here for << 2 */ + + /* AMPDU parameters */ *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << 2); + (sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + + /* MCS set */ memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + pos += sizeof(sband->ht_cap.mcs); + + /* extended capabilities */ + pos += sizeof(__le16); + + /* BF capabilities */ + pos += sizeof(__le32); + + /* antenna selection */ + pos += sizeof(u8); } IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; @@ -932,6 +981,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local, -1); + ieee80211_recalc_smps(local, sdata); mutex_unlock(&local->iflist_mtx); netif_start_queue(sdata->dev); @@ -2327,6 +2377,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; mutex_init(&ifmgd->mtx); + + if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) + ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; + else + ifmgd->req_smps = IEEE80211_SMPS_OFF; } /* scan finished notification */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b4608f11a40f..0c0850d37dda 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -134,6 +134,40 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, dev_kfree_skb(skb); } +static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (void *) skb->data; + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; + + if (ieee80211_is_action(mgmt->frame_control) && + sdata->vif.type == NL80211_IFTYPE_STATION && + mgmt->u.action.category == WLAN_CATEGORY_HT && + mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) { + /* + * This update looks racy, but isn't -- if we come + * here we've definitely got a station that we're + * talking to, and on a managed interface that can + * only be the AP. And the only other place updating + * this variable is before we're associated. + */ + switch (mgmt->u.action.u.ht_smps.smps_control) { + case WLAN_HT_SMPS_CONTROL_DYNAMIC: + sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC; + break; + case WLAN_HT_SMPS_CONTROL_STATIC: + sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC; + break; + case WLAN_HT_SMPS_CONTROL_DISABLED: + default: /* shouldn't happen since we don't send that */ + sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF; + break; + } + + ieee80211_queue_work(&local->hw, &local->recalc_smps); + } +} + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; @@ -210,6 +244,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rate_control_tx_status(local, sband, sta, skb); if (ieee80211_vif_is_mesh(&sta->sdata->vif)) ieee80211s_update_metric(local, sta, skb); + + if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && + (info->flags & IEEE80211_TX_STAT_ACK)) + ieee80211_frame_acked(sta, skb); } rcu_read_unlock(); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d54dbe8e09ba..086ef6257b4b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1170,3 +1170,77 @@ int ieee80211_reconfig(struct ieee80211_local *local) return 0; } +static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, + enum ieee80211_smps_mode *smps_mode) +{ + if (ifmgd->associated) { + *smps_mode = ifmgd->ap_smps; + + if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { + if (ifmgd->powersave) + *smps_mode = IEEE80211_SMPS_DYNAMIC; + else + *smps_mode = IEEE80211_SMPS_OFF; + } + + return 1; + } + + return 0; +} + +/* must hold iflist_mtx */ +void ieee80211_recalc_smps(struct ieee80211_local *local, + struct ieee80211_sub_if_data *forsdata) +{ + struct ieee80211_sub_if_data *sdata; + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; + int count = 0; + + if (forsdata) + WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); + + WARN_ON(!mutex_is_locked(&local->iflist_mtx)); + + /* + * This function could be improved to handle multiple + * interfaces better, but right now it makes any + * non-station interfaces force SM PS to be turned + * off. If there are multiple station interfaces it + * could also use the best possible mode, e.g. if + * one is in static and the other in dynamic then + * dynamic is ok. + */ + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + if (sdata->vif.type != NL80211_IFTYPE_STATION) + goto set; + if (sdata != forsdata) { + /* + * This nested is ok -- we are holding the iflist_mtx + * so can't get here twice or so. But it's required + * since normally we acquire it first and then the + * iflist_mtx. + */ + mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); + count += check_mgd_smps(&sdata->u.mgd, &smps_mode); + mutex_unlock(&sdata->u.mgd.mtx); + } else + count += check_mgd_smps(&sdata->u.mgd, &smps_mode); + + if (count > 1) { + smps_mode = IEEE80211_SMPS_OFF; + break; + } + } + + if (smps_mode == local->smps_mode) + return; + + set: + local->smps_mode = smps_mode; + /* changed flag is auto-detected for this */ + ieee80211_hw_config(local, 0); +} -- GitLab From 8b73d13a21ae889e747cac180ff27c5a0a88e6a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 1 Dec 2009 14:24:24 +0100 Subject: [PATCH 0126/3892] mac80211_hwsim: implement ampdu action Not that we actually ever aggregate anything, but it could potentially be useful anyhow to simulate aggregation sessions. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 92c669ebb358..89f527ee1a10 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -841,6 +841,31 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, } #endif +static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + switch (action) { + case IEEE80211_AMPDU_TX_START: + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + break; + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -855,6 +880,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .set_tim = mac80211_hwsim_set_tim, .conf_tx = mac80211_hwsim_conf_tx, CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) + .ampdu_action = mac80211_hwsim_ampdu_action, }; -- GitLab From f38fd12fa7b7b98e158a9b31d388da34eef25c22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 1 Dec 2009 18:29:42 +0100 Subject: [PATCH 0127/3892] mac80211: allow disabling 40MHz on 2.4GHz In some situations it is required that a system be configured with no support for 40 MHz channels in the 2.4 GHz band. Rather than imposing any such restrictions on everybody, allow configuration a system like that with a module parameter. It is writable at runtime but only takes effect at the time of the next association. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/main.c | 6 ++++++ net/mac80211/mlme.c | 6 ++++++ net/mac80211/util.c | 14 +++++++++++--- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e63aecbddfbe..6fb3f7181536 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -881,6 +881,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); +extern bool ieee80211_disable_40mhz_24ghz; + /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e1293e8ed83a..25f52098b636 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -33,6 +33,12 @@ #include "cfg.h" #include "debugfs.h" + +bool ieee80211_disable_40mhz_24ghz; +module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); +MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, + "Disable 40MHz support in the 2.4GHz band"); + void ieee80211_configure_filter(struct ieee80211_local *local) { u64 mc; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0a762a9ba4df..a7472c979c63 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -400,6 +400,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, /* determine capability flags */ + if (ieee80211_disable_40mhz_24ghz && + sband->band == IEEE80211_BAND_2GHZ) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (flags & IEEE80211_CHAN_NO_HT40PLUS) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 086ef6257b4b..acb6626ad0a4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -908,16 +908,24 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, } if (sband->ht_cap.ht_supported) { - __le16 tmp = cpu_to_le16(sband->ht_cap.cap); + u16 cap = sband->ht_cap.cap; + __le16 tmp; + + if (ieee80211_disable_40mhz_24ghz && + sband->band == IEEE80211_BAND_2GHZ) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + tmp = cpu_to_le16(cap); memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); - /* TODO: needs a define here for << 2 */ *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << 2); + (sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); pos += sizeof(sband->ht_cap.mcs); pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ -- GitLab From 5fba4af32ceeb935b3926714df9a64a33c2c9cf5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 Dec 2009 12:43:42 +0100 Subject: [PATCH 0128/3892] cfg80211: avoid sending spurious deauth to userspace Before commit ca9034592823e8179511e48a78731f95bfdd766c Author: Holger Schurig Date: Tue Oct 13 13:45:28 2009 +0200 cfg80211: remove warning in deauth case we assumed that drivers never give us spurious deauth frames because they filter them out based on the auth state they keep track of. This turned out to be racy, because userspace might deauth while the AP is also sending a deauth frame, so the warning was removed. However, in that case we should not tell userspace about the AP's frame if it requested deauth "first", where "first" means it came to cfg80211 first. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/mlme.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1001db4912f7..acaeaa784d68 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -137,22 +137,23 @@ void __cfg80211_send_deauth(struct net_device *dev, struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; int i; + bool found = false; ASSERT_WDEV_LOCK(wdev); - nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); - if (wdev->current_bss && memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; + found = true; } else for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { cfg80211_unhold_bss(wdev->auth_bsses[i]); cfg80211_put_bss(&wdev->auth_bsses[i]->pub); wdev->auth_bsses[i] = NULL; + found = true; break; } if (wdev->authtry_bsses[i] && @@ -160,10 +161,16 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_unhold_bss(wdev->authtry_bsses[i]); cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); wdev->authtry_bsses[i] = NULL; + found = true; break; } } + if (!found) + return; + + nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); + if (wdev->sme_state == CFG80211_SME_CONNECTED) { u16 reason_code; bool from_ap; -- GitLab From 5d1ec85f00e999dba61bdcbd959d62439d418e56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 Dec 2009 12:43:43 +0100 Subject: [PATCH 0129/3892] mac80211: dont try to use existing sta for AP Clean out some cruft that could use an already existing sta_info struct -- that case cannot happen. Also, there's a bug there -- if allocation/insertion fails then it is possible that we are left in a lingering state where mac80211 waits for the AP, cfg80211 waits for mac80211, but the AP has already replied. Since there's no way to indicate an internal error, pretend there was a timeout, i.e. that the AP never responded. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 57 +++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a7472c979c63..5174bfc5710d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -75,6 +75,9 @@ enum rx_mgmt_action { /* caller must call cfg80211_send_disassoc() */ RX_MGMT_CFG80211_DISASSOC, + /* caller must tell cfg80211 about internal error */ + RX_MGMT_CFG80211_ASSOC_ERROR, + /* caller must call cfg80211_auth_timeout() & free work */ RX_MGMT_CFG80211_AUTH_TO, @@ -1479,8 +1482,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; u8 *pos; u32 changed = 0; - int i, j; - bool have_higher_than_11mbit = false, newsta = false; + int i, j, err; + bool have_higher_than_11mbit = false; u16 ap_ht_cap_flags; /* @@ -1542,30 +1545,18 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: associated\n", sdata->name); ifmgd->aid = aid; - rcu_read_lock(); - - /* Add STA entry for the AP */ - sta = sta_info_get(sdata, wk->bss->cbss.bssid); + sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); if (!sta) { - newsta = true; - - rcu_read_unlock(); - - sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); - if (!sta) { - printk(KERN_DEBUG "%s: failed to alloc STA entry for" - " the AP\n", sdata->name); - return RX_MGMT_NONE; - } - - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_ASSOC_AP); - if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - set_sta_flags(sta, WLAN_STA_AUTHORIZED); - - rcu_read_lock(); + printk(KERN_DEBUG "%s: failed to alloc STA entry for" + " the AP\n", sdata->name); + return RX_MGMT_CFG80211_ASSOC_ERROR; } + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); + rates = 0; basic_rates = 0; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; @@ -1628,18 +1619,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.wmm_param) set_sta_flags(sta, WLAN_STA_WME); - if (newsta) { - int err = sta_info_insert(sta); - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->name, err); - rcu_read_unlock(); - return RX_MGMT_NONE; - } + err = sta_info_insert(sta); + sta = NULL; + if (err) { + printk(KERN_DEBUG "%s: failed to insert STA entry for" + " the AP (error %d)\n", sdata->name, err); + return RX_MGMT_CFG80211_ASSOC_ERROR; } - rcu_read_unlock(); - if (elems.wmm_param) ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, elems.wmm_param_len); @@ -2084,6 +2071,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, case RX_MGMT_CFG80211_DEAUTH: cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; + case RX_MGMT_CFG80211_ASSOC_ERROR: + /* an internal error -- pretend timeout for now */ + cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); + break; default: WARN(1, "unexpected: %d", rma); } -- GitLab From c24ef46e6b1597e54f185e0b48eb9073ef155a8c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:25:56 +0100 Subject: [PATCH 0130/3892] libertas: use priv->mesh_tlv instead of priv->mesh_fw_ver Both variables contained the same information (no mesh, old mesh, new mesh). So we can get rid of one variable. Also move the mesh-version test from cmd.c into mesh.c. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 13 ------------- drivers/net/wireless/libertas/defs.h | 7 ------- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/mesh.c | 23 ++++++++++++++++------- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b9b371bfa30f..dd69191f24eb 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", cmd.hwifversion, cmd.version); - /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ - /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ - /* 5.110.22 have mesh command with 0xa3 command id */ - /* 10.0.0.p0 FW brings in mesh config command with different id */ - /* Check FW version MSB and initialize mesh_fw_ver */ - if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) - priv->mesh_fw_ver = MESH_FW_OLD; - else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && - (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) - priv->mesh_fw_ver = MESH_FW_NEW; - else - priv->mesh_fw_ver = MESH_NONE; - /* Clamp region code to 8-bit since FW spec indicates that it should * only ever be 8-bit, even though the field size is 16-bit. Some firmware * returns non-zero high 8 bits here. diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 6b6ea9f7bf5b..ea3f10ef4e00 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -397,13 +397,6 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; -/** mesh_fw_ver */ -enum _mesh_fw_ver { - MESH_NONE = 0, /* MESH is not supported */ - MESH_FW_OLD, /* MESH is supported in FW V5 */ - MESH_FW_NEW, /* MESH is supported in FW V10 and newer */ -}; - /* Default values for fwt commands. */ #define FWT_DEFAULT_METRIC 0 #define FWT_DEFAULT_DIR 1 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6a8d2b291d8c..505b8feaa8b4 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -42,7 +42,6 @@ struct lbs_private { u32 mesh_connect_status; struct lbs_mesh_stats mstats; int mesh_open; - int mesh_fw_ver; int mesh_autostart_enabled; uint16_t mesh_tlv; u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 2f91c9b808af..1d94f7d4efc8 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -196,7 +196,12 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); - if (priv->mesh_fw_ver == MESH_FW_OLD) { + /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ + /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ + /* 5.110.22 have mesh command with 0xa3 command id */ + /* 10.0.0.p0 FW brings in mesh config command with different id */ + /* Check FW version MSB and initialize mesh_fw_ver */ + if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX @@ -218,7 +223,9 @@ int lbs_init_mesh(struct lbs_private *priv) priv->channel)) priv->mesh_tlv = 0; } - } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + } else + if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && + (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) { /* 10.0.0.pXX new firmwares should succeed with TLV * 0x100+37; Do not invoke command with old TLV. */ @@ -227,6 +234,8 @@ int lbs_init_mesh(struct lbs_private *priv) priv->channel)) priv->mesh_tlv = 0; } + + if (priv->mesh_tlv) { lbs_add_mesh(priv); @@ -416,10 +425,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv, struct net_device *dev, struct rxpd *rxpd) { if (priv->mesh_dev) { - if (priv->mesh_fw_ver == MESH_FW_OLD) { + if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) { if (rxpd->rx_control & RxPD_MESH_FRAME) dev = priv->mesh_dev; - } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) { if (rxpd->u.bss.bss_num == MESH_IFACE_ID) dev = priv->mesh_dev; } @@ -432,9 +441,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, struct net_device *dev, struct txpd *txpd) { if (dev == priv->mesh_dev) { - if (priv->mesh_fw_ver == MESH_FW_OLD) + if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); - else if (priv->mesh_fw_ver == MESH_FW_NEW) + else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) txpd->u.bss.bss_num = MESH_IFACE_ID; } } @@ -538,7 +547,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12. */ - if (priv->mesh_fw_ver == MESH_FW_NEW) + if (priv->mesh_tlv == TLV_TYPE_MESH_ID) command = CMD_MESH_CONFIG | (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); -- GitLab From d6ede678c138061f5202b519f8f8d6372e2cb5bb Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:25:57 +0100 Subject: [PATCH 0131/3892] libertas: remove mesh_autostart_enabled and sync_channel mesh_autostart_enabled was nowhere set. Rumor is that this is used in the OLPC tree, but they never did submit their code upstream. After removing this code, it turned out that the sync_channel stuff is now also unused, so get rid of that as well. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 16 ++-------------- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 13 ------------- 3 files changed, 2 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 21d57690c20a..0334a58820ee 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -485,20 +485,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - /* Ignore spurious autostart events if autostart is disabled */ - if (!priv->mesh_autostart_enabled) { - lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); - break; - } - lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); - priv->mesh_connect_status = LBS_CONNECTED; - if (priv->mesh_open) { - netif_carrier_on(priv->mesh_dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->mesh_dev); - } - priv->mode = IW_MODE_ADHOC; - schedule_work(&priv->sync_channel); + /* Ignore spurious autostart events */ + lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; default: diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 505b8feaa8b4..159de3ec9c44 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -42,11 +42,9 @@ struct lbs_private { u32 mesh_connect_status; struct lbs_mesh_stats mstats; int mesh_open; - int mesh_autostart_enabled; uint16_t mesh_tlv; u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 mesh_ssid_len; - struct work_struct sync_channel; /* Monitor mode */ struct net_device *rtap_net_dev; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index db38a5a719fa..b0799e347ba2 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -806,18 +806,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv) return 0; } -static void lbs_sync_channel_worker(struct work_struct *work) -{ - struct lbs_private *priv = container_of(work, struct lbs_private, - sync_channel); - - lbs_deb_enter(LBS_DEB_MAIN); - if (lbs_update_channel(priv)) - lbs_pr_info("Channel synchronization failed."); - lbs_deb_leave(LBS_DEB_MAIN); -} - - static int lbs_init_adapter(struct lbs_private *priv) { size_t bufsize; @@ -997,7 +985,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); - INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); priv->mesh_open = 0; sprintf(priv->mesh_ssid, "mesh"); -- GitLab From 55e1ff924414111a6afbfde00375a1302aef9353 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:25:58 +0100 Subject: [PATCH 0132/3892] libertas: move mesh-related definitions into mesh.h Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.h | 12 ------------ drivers/net/wireless/libertas/mesh.h | 9 +++++++++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 2862748aef70..cb4138a55fdf 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); -/* Mesh related */ - -int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, - struct cmd_ds_mesh_access *cmd); - -int lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type); - -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); - - /* Commands only used in wext.c, assoc. and scan.c */ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index fea9b5d005fc..b642d5d11699 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -46,11 +46,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, /* Command handling */ struct cmd_ds_command; +struct cmd_ds_mesh_access; +struct cmd_ds_mesh_config; int lbs_cmd_bt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf); int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf); +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd); +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type); +int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); + /* Persistent configuration */ -- GitLab From cd74468b8c56c1a809d9b7f913f11d8181c3a0b2 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:25:59 +0100 Subject: [PATCH 0133/3892] libertas: decouple mesh and rtap While it's might be technically true that only MESH-enabled firmwares are also RTAP-enabled, I like to have this decoupled. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b0799e347ba2..ad3434011897 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1062,6 +1062,17 @@ void lbs_remove_card(struct lbs_private *priv) EXPORT_SYMBOL_GPL(lbs_remove_card); +static int lbs_rtap_supported(struct lbs_private *priv) +{ + if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) + return 1; + + /* newer firmware use a capability mask */ + return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && + (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)); +} + + int lbs_start_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; @@ -1081,12 +1092,14 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); + lbs_init_mesh(priv); + /* * While rtap isn't related to mesh, only mesh-enabled * firmware implements the rtap functionality via * CMD_802_11_MONITOR_MODE. */ - if (lbs_init_mesh(priv)) { + if (lbs_rtap_supported(priv)) { if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) lbs_pr_err("cannot register lbs_rtap attribute\n"); } @@ -1120,7 +1133,9 @@ void lbs_stop_card(struct lbs_private *priv) netif_carrier_off(dev); lbs_debugfs_remove_one(priv); - if (lbs_deinit_mesh(priv)) + lbs_deinit_mesh(priv); + + if (lbs_rtap_supported(priv)) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); /* Delete the timeout of the currently processing command */ -- GitLab From e4da1a81a967c05dfde6f0498cff1f6fe6683f52 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:26:00 +0100 Subject: [PATCH 0134/3892] libertas: move mesh SSID initialization into mesh.c Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 4 ---- drivers/net/wireless/libertas/mesh.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ad3434011897..127b7f60c320 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -986,10 +986,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); - priv->mesh_open = 0; - sprintf(priv->mesh_ssid, "mesh"); - priv->mesh_ssid_len = 4; - priv->wol_criteria = 0xffffffff; priv->wol_gpio = 0xff; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 1d94f7d4efc8..4f67c8b62edc 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -237,6 +237,9 @@ int lbs_init_mesh(struct lbs_private *priv) if (priv->mesh_tlv) { + sprintf(priv->mesh_ssid, "mesh"); + priv->mesh_ssid_len = 4; + lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) -- GitLab From 602114ae595af6c89eab149cf9f939e3f7ef4a34 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:26:01 +0100 Subject: [PATCH 0135/3892] libertas: add access functions for mesh open/connect status Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/main.c | 5 ++--- drivers/net/wireless/libertas/mesh.c | 3 ++- drivers/net/wireless/libertas/mesh.h | 6 ++++++ drivers/net/wireless/libertas/scan.c | 2 +- drivers/net/wireless/libertas/tx.c | 2 +- drivers/net/wireless/libertas/wext.c | 6 +++--- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index dd69191f24eb..4a198113f9be 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1304,7 +1304,7 @@ int lbs_execute_next_command(struct lbs_private *priv) if ((priv->psmode != LBS802_11POWERMODECAM) && (priv->psstate == PS_STATE_FULL_POWER) && ((priv->connect_status == LBS_CONNECTED) || - (priv->mesh_connect_status == LBS_CONNECTED))) { + lbs_mesh_connected(priv))) { if (priv->secinfo.WPAenabled || priv->secinfo.WPA2enabled) { /* check for valid WPA group keys */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 127b7f60c320..64b327d4548b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->monitormode == monitor_mode) return strlen(buf); if (!priv->monitormode) { - if (priv->infra_open || priv->mesh_open) + if (priv->infra_open || lbs_mesh_open(priv)) return -EBUSY; if (priv->mode == IW_MODE_INFRA) lbs_cmd_80211_deauthenticate(priv, @@ -619,7 +619,7 @@ static int lbs_thread(void *data) if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); if (priv->mesh_dev && - priv->mesh_connect_status == LBS_CONNECTED) + lbs_mesh_connected(priv)) netif_wake_queue(priv->mesh_dev); } } @@ -833,7 +833,6 @@ static int lbs_init_adapter(struct lbs_private *priv) memset(priv->current_addr, 0xff, ETH_ALEN); priv->connect_status = LBS_DISCONNECTED; - priv->mesh_connect_status = LBS_DISCONNECTED; priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; priv->channel = DEFAULT_AD_HOC_CHANNEL; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 4f67c8b62edc..954cd00f7452 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -196,6 +195,8 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); + priv->mesh_connect_status = LBS_DISCONNECTED; + /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ /* 5.110.22 have mesh command with 0xa3 command id */ diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index b642d5d11699..388c39281b7d 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -84,4 +84,10 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *s); +/* Accessors */ + +#define lbs_mesh_open(priv) (priv->mesh_open) +#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED) + + #endif diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index c6a6c042b82f..4a0c3e3cd3b1 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -640,7 +640,7 @@ out: if (!priv->tx_pending_len) netif_wake_queue(priv->dev); } - if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { + if (priv->mesh_dev && lbs_mesh_connected(priv)) { netif_carrier_on(priv->mesh_dev); if (!priv->tx_pending_len) netif_wake_queue(priv->mesh_dev); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 315d1ce286ca..52d244ea3d97 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); - if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) + if (priv->mesh_dev && lbs_mesh_connected(priv)) netif_wake_queue(priv->mesh_dev); } EXPORT_SYMBOL_GPL(lbs_send_tx_feedback); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index a8eb9e1fcf36..c0c7bc40b109 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates) lbs_deb_enter(LBS_DEB_WEXT); if ((priv->connect_status != LBS_CONNECTED) && - (priv->mesh_connect_status != LBS_CONNECTED)) + !lbs_mesh_connected(priv)) memcpy(rates, lbs_bg_rates, MAX_RATES); else memcpy(rates, priv->curbssparams.rates, MAX_RATES); @@ -307,7 +307,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, /* Use nickname to indicate that mesh is on */ - if (priv->mesh_connect_status == LBS_CONNECTED) { + if (lbs_mesh_connected(priv)) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; dwrq->length = strlen(extra); @@ -863,7 +863,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) /* If we're not associated, all quality values are meaningless */ if ((priv->connect_status != LBS_CONNECTED) && - (priv->mesh_connect_status != LBS_CONNECTED)) + !lbs_mesh_connected(priv)) goto out; /* Quality by RSSI */ -- GitLab From 4143a23de096910e3ceb0939f41de6ffb8c59475 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:26:02 +0100 Subject: [PATCH 0136/3892] libertas: make mesh configurable Mostly for the embedded people that know beforehand that they don't need MESH at all and want to save some bytes, but also helpful for the upcoming cfg80211 transition. text data bss dec hex filename 114264 2308 140 116712 1c7e8 libertas.ko with mesh 105026 2000 140 107166 1a29e libertas.ko without mesh -------------------------------------------------- -9238 -308 -9546 Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Kconfig | 6 ++++++ drivers/net/wireless/libertas/Makefile | 2 +- drivers/net/wireless/libertas/cmd.c | 4 ++++ drivers/net/wireless/libertas/dev.h | 2 ++ drivers/net/wireless/libertas/ethtool.c | 2 ++ drivers/net/wireless/libertas/mesh.h | 17 +++++++++++++++++ drivers/net/wireless/libertas/wext.c | 20 +++++++++++++++----- 7 files changed, 47 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 30aa9d48d67e..0485c9957575 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -37,3 +37,9 @@ config LIBERTAS_DEBUG depends on LIBERTAS ---help--- Debugging support. + +config LIBERTAS_MESH + bool "Enable mesh support" + depends on LIBERTAS + help + This enables Libertas' MESH support, used by e.g. the OLPC people. diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index b188cd97a053..45e870e33117 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -5,11 +5,11 @@ libertas-y += cmdresp.o libertas-y += debugfs.o libertas-y += ethtool.o libertas-y += main.o -libertas-y += mesh.o libertas-y += rx.o libertas-y += scan.o libertas-y += tx.o libertas-y += wext.o +libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 4a198113f9be..4a0d8f4188ca 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -998,6 +998,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = 0; break; +#ifdef CONFIG_LIBERTAS_MESH + case CMD_BT_ACCESS: ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf); break; @@ -1006,6 +1008,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf); break; +#endif + case CMD_802_11_BEACON_CTRL: ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 159de3ec9c44..7330ab8521cc 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -39,12 +39,14 @@ struct lbs_private { /* Mesh */ struct net_device *mesh_dev; /* Virtual device */ +#ifdef CONFIG_LIBERTAS_MESH u32 mesh_connect_status; struct lbs_mesh_stats mstats; int mesh_open; uint16_t mesh_tlv; u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 mesh_ssid_len; +#endif /* Monitor mode */ struct net_device *rtap_net_dev; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 63d020374c2b..3804a58d7f4e 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = { .get_drvinfo = lbs_ethtool_get_drvinfo, .get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom_len = lbs_ethtool_get_eeprom_len, +#ifdef CONFIG_LIBERTAS_MESH .get_sset_count = lbs_mesh_ethtool_get_sset_count, .get_ethtool_stats = lbs_mesh_ethtool_get_stats, .get_strings = lbs_mesh_ethtool_get_strings, +#endif .get_wol = lbs_ethtool_get_wol, .set_wol = lbs_ethtool_set_wol, }; diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index 388c39281b7d..e2573303a328 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -9,6 +9,8 @@ #include +#ifdef CONFIG_LIBERTAS_MESH + /* Mesh statistics */ struct lbs_mesh_stats { u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ @@ -89,5 +91,20 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, #define lbs_mesh_open(priv) (priv->mesh_open) #define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED) +#else + +#define lbs_init_mesh(priv) +#define lbs_deinit_mesh(priv) +#define lbs_add_mesh(priv) +#define lbs_remove_mesh(priv) +#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) +#define lbs_mesh_set_txpd(priv, dev, txpd) +#define lbs_mesh_config(priv, enable, chan) +#define lbs_mesh_open(priv) (0) +#define lbs_mesh_connected(priv) (0) + +#endif + + #endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index c0c7bc40b109..f07ba0b6c5f1 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, return 0; } +#ifdef CONFIG_LIBERTAS_MESH static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { @@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, lbs_deb_leave(LBS_DEB_WEXT); return 0; } +#endif static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) @@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev, return 0; } +#ifdef CONFIG_LIBERTAS_MESH static int mesh_wlan_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) @@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev, lbs_deb_leave(LBS_DEB_WEXT); return 0; } +#endif static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, @@ -1010,6 +1014,7 @@ out: return ret; } +#ifdef CONFIG_LIBERTAS_MESH static int lbs_mesh_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) @@ -1061,6 +1066,7 @@ out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } +#endif static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) @@ -2110,6 +2116,7 @@ out: return ret; } +#ifdef CONFIG_LIBERTAS_MESH static int lbs_mesh_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) @@ -2163,6 +2170,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } +#endif /** * @brief Connect to the AP or Ad-hoc Network with specific bssid @@ -2269,7 +2277,13 @@ static const iw_handler lbs_handler[] = { (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; +struct iw_handler_def lbs_handler_def = { + .num_standard = ARRAY_SIZE(lbs_handler), + .standard = (iw_handler *) lbs_handler, + .get_wireless_stats = lbs_get_wireless_stats, +}; +#ifdef CONFIG_LIBERTAS_MESH static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ (iw_handler) lbs_get_name, /* SIOCGIWNAME */ @@ -2327,14 +2341,10 @@ static const iw_handler mesh_wlan_handler[] = { (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; -struct iw_handler_def lbs_handler_def = { - .num_standard = ARRAY_SIZE(lbs_handler), - .standard = (iw_handler *) lbs_handler, - .get_wireless_stats = lbs_get_wireless_stats, -}; struct iw_handler_def mesh_handler_def = { .num_standard = ARRAY_SIZE(mesh_wlan_handler), .standard = (iw_handler *) mesh_wlan_handler, .get_wireless_stats = lbs_get_wireless_stats, }; +#endif -- GitLab From 0e78ff8fcc6dabeda313719deb751afbd20bea41 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:26:03 +0100 Subject: [PATCH 0137/3892] libertas: remove priv->capability This variable was once set to WLAN_CAPABILITY_SHORT_PREAMBLE and there's no code that could change the variable to something else. Therefore it seems this is not necessary :-) Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 13 +++---------- drivers/net/wireless/libertas/cmd.c | 3 --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 1 - 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 751067369ba8..5f58ae33405b 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -807,8 +807,7 @@ static int lbs_try_associate(struct lbs_private *priv, } /* Use short preamble only when both the BSS and firmware support it */ - if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && - (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) preamble = RADIO_PREAMBLE_SHORT; ret = lbs_set_radio(priv, preamble, 1); @@ -939,8 +938,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, } /* Use short preamble only when both the BSS and firmware support it */ - if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && - (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { + if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocJoin: Short preamble\n"); preamble = RADIO_PREAMBLE_SHORT; } @@ -1049,7 +1047,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { struct cmd_ds_802_11_ad_hoc_start cmd; - u8 preamble = RADIO_PREAMBLE_LONG; + u8 preamble = RADIO_PREAMBLE_SHORT; size_t ratesize = 0; u16 tmpcap = 0; int ret = 0; @@ -1057,11 +1055,6 @@ static int lbs_adhoc_start(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); - if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("ADHOC_START: Will use short preamble\n"); - preamble = RADIO_PREAMBLE_SHORT; - } - ret = lbs_set_radio(priv, preamble, 1); if (ret) goto out; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 4a0d8f4188ca..42051f7cad6d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -842,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) if (priv->fwrelease < 0x09000000) { switch (preamble) { case RADIO_PREAMBLE_SHORT: - if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - goto out; - /* Fall through */ case RADIO_PREAMBLE_AUTO: case RADIO_PREAMBLE_LONG: cmd.control = cpu_to_le16(preamble); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 7330ab8521cc..cf47cf53458f 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -175,7 +175,6 @@ struct lbs_private { struct bss_descriptor *networks; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; - u16 capability; uint16_t enablehwauto; uint16_t ratebitmap; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 64b327d4548b..f9f195f7b17c 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -839,7 +839,6 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radio_on = 1; priv->enablehwauto = 1; - priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; priv->is_deep_sleep = 0; -- GitLab From 48631de9218a4563a6632e105676f42db3849c57 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 2 Dec 2009 15:26:04 +0100 Subject: [PATCH 0138/3892] libertas: remove priv->ratebitmap Used to be a write-only-variable :-) Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 4 +--- drivers/net/wireless/libertas/dev.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5f58ae33405b..5e650f358415 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); - if (!ret && cmd_action == CMD_ACT_GET) { - priv->ratebitmap = le16_to_cpu(cmd.bitmap); + if (!ret && cmd_action == CMD_ACT_GET) priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); - } lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cf47cf53458f..d5a9dcae4059 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -176,7 +176,6 @@ struct lbs_private { struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; uint16_t enablehwauto; - uint16_t ratebitmap; /* ADHOC */ u16 beacon_period; -- GitLab From d80050c4c321a74cea28c6ef9695d8427a928417 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 2 Dec 2009 20:56:11 -0800 Subject: [PATCH 0139/3892] iwmc3200wifi: Avoid an offset calculation for each management frame. Determine the offset at compile time. Signed-off-by: Joe Perches Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 6bd253ac533f..0619d6a1103c 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, struct iwm_umac_notif_mgt_frame *mgt_frame = (struct iwm_umac_notif_mgt_frame *)buf; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; - u8 *ie; IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, le16_to_cpu(mgt_frame->len)); if (ieee80211_is_assoc_req(mgt->frame_control)) { - ie = mgt->u.assoc_req.variable;; - iwm->req_ie_len = - le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + iwm->req_ie_len = le16_to_cpu(mgt_frame->len) + - offsetof(struct ieee80211_mgmt, + u.assoc_req.variable); kfree(iwm->req_ie); iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { - ie = mgt->u.reassoc_req.variable;; - iwm->req_ie_len = - le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + iwm->req_ie_len = le16_to_cpu(mgt_frame->len) + - offsetof(struct ieee80211_mgmt, + u.reassoc_req.variable); kfree(iwm->req_ie); iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { - ie = mgt->u.assoc_resp.variable;; - iwm->resp_ie_len = - le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) + - offsetof(struct ieee80211_mgmt, + u.assoc_resp.variable); kfree(iwm->resp_ie); iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { - ie = mgt->u.reassoc_resp.variable;; - iwm->resp_ie_len = - le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) + - offsetof(struct ieee80211_mgmt, + u.reassoc_resp.variable); kfree(iwm->resp_ie); iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); -- GitLab From 2c7e6bc9ac7cb518cf037495932d80f71a1596f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Dec 2009 09:26:38 +0100 Subject: [PATCH 0140/3892] mac80211: disallow fixing bitrates with hw rate control When hw rate control is used, these parameters have no meaning because the hardware cannot get at them right now, so disallow setting them. Also clean up the function a bit. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8c35418d1c96..f07c4abefe56 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1399,15 +1399,25 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i, err = -EINVAL; + int i; u32 target_rate; struct ieee80211_supported_band *sband; + /* + * This _could_ be supported by providing a hook for + * drivers for this function, but at this point it + * doesn't seem worth bothering. + */ + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) + return -EOPNOTSUPP; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + /* + * target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X - * target_rate = X, rate->fixed = 0 means all rates <= X */ + * target_rate = X, rate->fixed = 0 means all rates <= X + */ sdata->max_ratectrl_rateidx = -1; sdata->force_unicast_rateidx = -1; @@ -1418,20 +1428,18 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, else return 0; - for (i=0; i< sband->n_bitrates; i++) { - struct ieee80211_rate *brate = &sband->bitrates[i]; - int this_rate = brate->bitrate; + for (i = 0; i< sband->n_bitrates; i++) { + if (target_rate != sband->bitrates[i].bitrate) + continue; - if (target_rate == this_rate) { - sdata->max_ratectrl_rateidx = i; - if (mask->fixed) - sdata->force_unicast_rateidx = i; - err = 0; - break; - } + /* requested bitrate found */ + sdata->max_ratectrl_rateidx = i; + if (mask->fixed) + sdata->force_unicast_rateidx = i; + return 0; } - return err; + return -EINVAL; } struct cfg80211_ops mac80211_config_ops = { -- GitLab From 265dc7f0964e4df95ab57a9d1618689301d39a55 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 4 Dec 2009 19:10:34 +0200 Subject: [PATCH 0141/3892] mac80211_hwsim: Check all local addresses for TX Ack status Since mac80211_hwsim supports multiple virtual interfaces, we need to iterate through all active interfaces when figuring out whether there is a match during TX Ack status checking. This fixes TX status reporting for cases where secondary interfaces are used. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 35 +++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 89f527ee1a10..718a5f198c30 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -436,6 +436,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, } +struct mac80211_hwsim_addr_match_data { + bool ret; + const u8 *addr; +}; + +static void mac80211_hwsim_addr_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_addr_match_data *md = data; + if (memcmp(mac, md->addr, ETH_ALEN) == 0) + md->ret = true; +} + + +static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, + const u8 *addr) +{ + struct mac80211_hwsim_addr_match_data md; + + if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) + return true; + + md.ret = false; + md.addr = addr; + ieee80211_iterate_active_interfaces_atomic(data->hw, + mac80211_hwsim_addr_iter, + &md); + + return md.ret; +} + + static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -488,8 +520,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (nskb == NULL) continue; - if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, - ETH_ALEN) == 0) + if (mac80211_hwsim_addr_match(data2, hdr->addr1)) ack = true; memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(data2->hw, nskb); -- GitLab From c755ad34ab233afaaacd3d67190a8b74186f9fe8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Dec 2009 12:38:41 -0500 Subject: [PATCH 0142/3892] ath9k: add MCS rate index back to debufs rcstat Speaking of 802.11n rates in terms of Mbps doesn't really developers and is just useful for users. To aid debugging add the MCS index back and an HT20/HT40 mode. New screenshot: HT MCS Rate Success Retries XRetries PER 6.0: 0 0 0 0 9.0: 0 0 0 0 12.0: 26 260 0 49 18.0: 80 804 2 58 24.0: 0 0 0 0 36.0: 0 0 0 0 48.0: 0 0 0 0 54.0: 0 0 0 0 HT20 0 6.5: 1368 13660 0 48 HT20 1 13.0: 0 0 0 0 HT20 2 19.5: 0 0 0 0 HT20 3 26.0: 0 0 0 0 HT20 4 39.0: 0 0 0 0 HT20 5 52.0: 55 578 14 43 HT20 6 58.5: 29 306 8 69 HT20 7 65.0: 21 210 0 67 HT20 8 13.0: 21 210 0 56 HT20 9 26.0: 0 0 0 0 HT20 10 39.0: 0 0 0 0 HT20 11 52.0: 0 0 0 0 HT20 12 78.0: 0 0 0 0 HT20 13 104.0: 0 0 0 0 HT20 14 117.0: 0 0 0 0 HT20 15 130.0: 27 290 10 55 HT40 0 13.5: 79 687 16 17 HT40 1 27.5: 60 409 10 17 HT40 2 40.5: 56 381 21 25 HT40 3 54.0: 44 302 21 18 HT40 4 81.5: 19 171 2 14 HT40 5 108.0: 0 0 0 0 HT40 6 121.5: 0 0 0 0 HT40 7 135.0: 0 0 0 0 HT40 7 150.0: 0 0 0 0 HT40 8 27.0: 0 0 0 0 HT40 9 54.0: 0 0 0 0 HT40 10 81.0: 0 0 0 0 HT40 11 108.0: 11 100 0 18 HT40 12 162.0: 23 200 0 22 HT40 13 216.0: 61 580 0 35 HT40 14 243.0: 37 271 0 66 HT40 15 270.0: 65 217 2 73 HT40 15 300.0: 0 0 0 0 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 38 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/rc.h | 4 +++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index b66f72dbf7b9..592f1b70f55a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -289,23 +289,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, if (sc->cur_rate_table == NULL) return 0; - max = 80 + sc->cur_rate_table->rate_cnt * 64; + max = 80 + sc->cur_rate_table->rate_cnt * 1024; buf = kmalloc(max + 1, GFP_KERNEL); if (buf == NULL) return 0; buf[max] = 0; - len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", - "Retries", "XRetries", "PER"); + len += sprintf(buf, "%6s %6s %6s " + "%10s %10s %10s %10s\n", + "HT", "MCS", "Rate", + "Success", "Retries", "XRetries", "PER"); for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; + char mcs[5]; + char htmode[5]; + int used_mcs = 0, used_htmode = 0; + + if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) { + used_mcs = snprintf(mcs, 5, "%d", + sc->cur_rate_table->info[i].ratecode); + + if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy)) + used_htmode = snprintf(htmode, 5, "HT40"); + else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy)) + used_htmode = snprintf(htmode, 5, "HT20"); + else + used_htmode = snprintf(htmode, 5, "????"); + } + + mcs[used_mcs] = '\0'; + htmode[used_htmode] = '\0'; len += snprintf(buf + len, max - len, - "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, - (ratekbps % 1000) / 100, stats->success, - stats->retries, stats->xretries, + "%6s %6s %3u.%d: " + "%10u %10u %10u %10u\n", + htmode, + mcs, + ratekbps / 1000, + (ratekbps % 1000) / 100, + stats->success, + stats->retries, + stats->xretries, stats->per); } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 9eb96f506998..4f6d6fd442f4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -57,6 +57,10 @@ enum { || (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \ + || (_phy == WLAN_RC_PHY_HT_20_DS) \ + || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI)) #define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ -- GitLab From cb136f54ee11f9ead716b5ad0b10fa1c1b05271d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Dec 2009 14:01:28 -0500 Subject: [PATCH 0143/3892] mac80211: make debugfs mcs set entry reflect 16 bits The MCS set is 16 bits so when debugging ensure the full 16 bits are represented. Current reading would make you think its only 8 bits. Cc: johannes@sipsolutions.net Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 374ff6f98a9c..9a1d1e40eca8 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -168,7 +168,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n", htc->ht_supported ? "" : "not "); if (htc->ht_supported) { - p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap); + p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap); p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", htc->ampdu_factor, htc->ampdu_density); p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); -- GitLab From 7db94e210351e8578d4a98fed3edd4df5f10ae9d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Dec 2009 14:54:45 -0500 Subject: [PATCH 0144/3892] mac80211: parse the HT capabilities info through debugfs When debugging you want to be lazy and not have to parse bits yourself so let mac80211 debugfs do the parsing for you. This is what I get against my WRT610N: root@tux:~# cat /sys/kernel/debug/ieee80211/phy0/stations/00\:22\:6b\:aa\:bb\:01/ht_capa ht supported cap: 0x000e HT20/HT40 SM Power Save disabled No RX STBC Max AMSDU length: 7935 bytes No DSSS/CCK HT40 ampdu factor/density: 2/6 MCS mask: ff ff 00 00 00 00 00 00 00 00 MCS rx highest: 0 MCS tx params: 0 Cc: johannes@sipsolutions.net Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 9a1d1e40eca8..c833b6ce9902 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -160,7 +160,12 @@ STA_OPS(agg_status); static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[200], *p = buf; +#define PRINT_HT_CAP(_cond, _str) \ + do { \ + if (_cond) \ + p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ + } while (0) + char buf[1024], *p = buf; int i; struct sta_info *sta = file->private_data; struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; @@ -169,6 +174,47 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, htc->ht_supported ? "" : "not "); if (htc->ht_supported) { p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap); + + PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP"); + PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40"); + PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20"); + + PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save"); + PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save"); + PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled"); + + PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield"); + PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI"); + PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI"); + PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC"); + + PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC"); + PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream"); + PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams"); + PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams"); + + PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); + + PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " + "3839 bytes"); + PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " + "7935 bytes"); + + /* + * For beacons and probe response this would mean the BSS + * does or does not allow the usage of DSSS/CCK HT40. + * Otherwise it means the STA does or does not use + * DSSS/CCK HT40. + */ + PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40"); + PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40"); + + /* BIT(13) is reserved */ + + PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant"); + + PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection"); + p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", htc->ampdu_factor, htc->ampdu_density); p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); -- GitLab From 9da3e068142ec7856b2f13261dcf0660fad32b61 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Dec 2009 15:57:50 -0500 Subject: [PATCH 0145/3892] mac80211: only bother printing highest data rate on debugfs if its set IEEE-802.11n spec says the RX highest data rate field does not specify the highest supported RX data rate if its not set. Ignore it if not set then. Refer to section 7.3.56.4 Cc: johannes@sipsolutions.net Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 5 ++++- net/mac80211/debugfs_sta.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e8d43d0ff2c3..098bedcde9bb 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -775,7 +775,10 @@ struct ieee80211_bar { /** * struct ieee80211_mcs_info - MCS information * @rx_mask: RX mask - * @rx_highest: highest supported RX rate + * @rx_highest: highest supported RX rate. If set represents + * the highest supported RX data rate in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. * @tx_params: TX parameters */ struct ieee80211_mcs_info { diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c833b6ce9902..0d4a759ba72c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -218,11 +218,19 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", htc->ampdu_factor, htc->ampdu_density); p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) p += scnprintf(p, sizeof(buf)+buf-p, " %.2x", htc->mcs.rx_mask[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n", - le16_to_cpu(htc->mcs.rx_highest)); + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + + /* If not set this is meaningless */ + if (le16_to_cpu(htc->mcs.rx_highest)) { + p += scnprintf(p, sizeof(buf)+buf-p, + "MCS rx highest: %d Mbps\n", + le16_to_cpu(htc->mcs.rx_highest)); + } + p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n", htc->mcs.tx_params); } -- GitLab From 5b6e2f12edd6c46e87a2775321f1912d19be4b35 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Tue, 8 Dec 2009 15:21:34 +0100 Subject: [PATCH 0146/3892] ar9170usb: add Sphairon Homelink 1202 USB ID Signed-off-by: Stefan Seyfried Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index e0799d924057..0f361186b78f 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cde, 0x0023) }, /* Z-Com UB82 ABG */ { USB_DEVICE(0x0cde, 0x0026) }, + /* Sphairon Homelink 1202 */ + { USB_DEVICE(0x0cde, 0x0027) }, /* Arcadyan WN7512 */ { USB_DEVICE(0x083a, 0xf522) }, /* Planex GWUS300 */ -- GitLab From 11466f1342a3400dd5e03da3d8c45aa4149c62d4 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Tue, 8 Dec 2009 15:21:35 +0100 Subject: [PATCH 0147/3892] zd1211rw: improve ejecting of fake CDROM The zd1211rw always assumed that the storage device is at endpoint 1, but there are devices (Spairon Homelink 1202) that are at endpoint 0. Try both, starting with 1 to make sure to not break existing setups. Signed-off-by: Stefan Seyfried Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ac19ecd19cfe..4daf1c94ec04 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1078,11 +1078,15 @@ static int eject_installer(struct usb_interface *intf) int r; /* Find bulk out endpoint */ - endpoint = &iface_desc->endpoint[1].desc; - if (usb_endpoint_dir_out(endpoint) && - usb_endpoint_xfer_bulk(endpoint)) { - bulk_out_ep = endpoint->bEndpointAddress; - } else { + for (r = 1; r >= 0; r--) { + endpoint = &iface_desc->endpoint[r].desc; + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + bulk_out_ep = endpoint->bEndpointAddress; + break; + } + } + if (r == -1) { dev_err(&udev->dev, "zd1211rw: Could not find bulk out endpoint\n"); return -ENODEV; -- GitLab From ba37a3d0395a66b3c9164c4f4d1318317da32e96 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 Dec 2009 14:37:27 -0800 Subject: [PATCH 0148/3892] iwlwifi: use new mac80211 SMPS Instead of hard-coding the SM PS mode per hardware, this makes iwlwifi support the new mac80211 API for controlling the SM PS mode. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 - drivers/net/wireless/iwlwifi/iwl-4965.c | 1 - drivers/net/wireless/iwlwifi/iwl-5000.c | 4 -- drivers/net/wireless/iwlwifi/iwl-6000.c | 3 -- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 53 ++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 8 files changed, 32 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9d4fdd7a1134..5759f91343a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -174,7 +174,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl1000_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 386513b601f5..34778cf120fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2239,7 +2239,6 @@ struct iwl_cfg iwl4965_agn_cfg = { .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5a277cdffd07..3236315c75be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1600,7 +1600,6 @@ struct iwl_cfg iwl5300_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5100_bgn_cfg = { @@ -1669,7 +1668,6 @@ struct iwl_cfg iwl5100_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1693,7 +1691,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1717,7 +1714,6 @@ struct iwl_cfg iwl5150_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_abg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index fec43771c49e..788457ae25a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -307,7 +307,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -396,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -456,7 +454,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0b3669f317a4..904b5d8da860 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2623,6 +2623,10 @@ static int iwl_setup_mac(struct iwl_priv *priv) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + if (priv->cfg->sku & IWL_SKU_N) + hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_SUPPORTS_STATIC_SMPS; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -3361,6 +3365,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; + priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c3c31dc9fd4d..e3b96b48b7fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -450,8 +450,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->cfg->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (priv->cfg->sm_ps_mode << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -636,7 +634,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag); static bool is_single_rx_stream(struct iwl_priv *priv) { - return !priv->current_ht_config.is_ht || + return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || priv->current_ht_config.single_chain_sufficient; } @@ -1003,28 +1001,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - int idle_cnt = active_cnt; - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - - /* # Rx chains when idling and maybe trying to save power */ - switch (priv->cfg->sm_ps_mode) { - case WLAN_HT_CAP_SM_PS_STATIC: - idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - break; - case WLAN_HT_CAP_SM_PS_INVALID: + /* # Rx chains when idling, depending on SMPS mode */ + switch (priv->current_ht_config.smps) { + case IEEE80211_SMPS_STATIC: + case IEEE80211_SMPS_DYNAMIC: + return IWL_NUM_IDLE_CHAINS_SINGLE; + case IEEE80211_SMPS_OFF: + return active_cnt; default: - IWL_ERR(priv, "invalid sm_ps mode %u\n", - priv->cfg->sm_ps_mode); - WARN_ON(1); - break; + WARN(1, "invalid SMPS mode %d", + priv->current_ht_config.smps); + return active_cnt; } - return idle_cnt; } /* up to 4 chains */ @@ -2686,6 +2674,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); } + if (changed & (IEEE80211_CONF_CHANGE_SMPS | + IEEE80211_CONF_CHANGE_CHANNEL)) { + /* mac80211 uses static for non-HT which is what we want */ + priv->current_ht_config.smps = conf->smps_mode; + + /* + * Recalculate chain counts. + * + * If monitor mode is enabled then mac80211 will + * set up the SM PS mode to OFF if an HT channel is + * configured. + */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + } /* during scanning mac80211 will delay channel setting until * scan finish with changed = 0 @@ -2782,10 +2785,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_tx_power(priv, conf->power_level, false); } - /* call to ensure that 4965 rx_chain is set properly in monitor mode */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 650d3808d24a..f7acbb32900a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -232,7 +232,6 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition - * @sm_ps_mode: spatial multiplexing power save mode * @support_wimax_coexist: support wimax/wifi co-exist * * We enable the driver to be backward compatible wrt API version. The @@ -289,7 +288,6 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; - u8 sm_ps_mode; const bool support_wimax_coexist; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b3a29c7cdbc0..1e12e7340c90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -512,6 +512,7 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; + enum ieee80211_smps_mode smps; /* current smps mode */ /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; -- GitLab From 45d5d805988f1f3c0b24dac59fbba771b1f106a8 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Mon, 14 Dec 2009 00:59:53 +0100 Subject: [PATCH 0149/3892] iwlwifi: Constify struct iwl_ops Signed-off-by: Emese Revfy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5759f91343a5..0db1fda94a65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -141,7 +141,7 @@ static struct iwl_lib_ops iwl1000_lib = { }, }; -static struct iwl_ops iwl1000_ops = { +static const struct iwl_ops iwl1000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7da1dab933d9..3708b5c204e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2811,7 +2811,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, }; -static struct iwl_ops iwl3945_ops = { +static const struct iwl_ops iwl3945_ops = { .ucode = &iwl3945_ucode, .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 34778cf120fc..a5e3384d56b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2208,7 +2208,7 @@ static struct iwl_lib_ops iwl4965_lib = { }, }; -static struct iwl_ops iwl4965_ops = { +static const struct iwl_ops iwl4965_ops = { .ucode = &iwl4965_ucode, .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3236315c75be..f2b1915530e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1556,7 +1556,7 @@ static struct iwl_lib_ops iwl5150_lib = { }, }; -static struct iwl_ops iwl5000_ops = { +static const struct iwl_ops iwl5000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, @@ -1564,7 +1564,7 @@ static struct iwl_ops iwl5000_ops = { .led = &iwlagn_led_ops, }; -static struct iwl_ops iwl5150_ops = { +static const struct iwl_ops iwl5150_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 788457ae25a8..a5a0ed4817a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -253,7 +253,7 @@ static struct iwl_lib_ops iwl6000_lib = { }, }; -static struct iwl_ops iwl6000_ops = { +static const struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, @@ -268,7 +268,7 @@ static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = { .calc_rssi = iwl5000_calc_rssi, }; -static struct iwl_ops iwl6050_ops = { +static const struct iwl_ops iwl6050_ops = { .ucode = &iwl5000_ucode, .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, -- GitLab From 0ce024cbcd5837596bc82861f1d3074d53e956f6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 14:57:00 +0530 Subject: [PATCH 0150/3892] ath9k: Clarify Interrupt mitigation ath9k currently supports only RX interrupt mitigation. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 10 +++++----- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 917f70f7a28e..9474f9f6d400 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -368,7 +368,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - ah->config.intr_mitigation = true; + ah->config.rx_intr_mitigation = true; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -1160,7 +1160,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ah->config.intr_mitigation) + if (ah->config.rx_intr_mitigation) ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else ah->mask_reg |= AR_IMR_RXOK; @@ -2091,7 +2091,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_OBS, 8); - if (ah->config.intr_mitigation) { + if (ah->config.rx_intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); } @@ -2751,7 +2751,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ah->config.intr_mitigation) { + if (ah->config.rx_intr_mitigation) { if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -2884,7 +2884,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_RX) { mask |= AR_IMR_RXERR; - if (ah->config.intr_mitigation) + if (ah->config.rx_intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e2b0c73a616f..8849450dc591 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -212,7 +212,7 @@ struct ath9k_ops_config { u32 cck_trig_low; u32 enable_ani; int serialize_regmode; - bool intr_mitigation; + bool rx_intr_mitigation; #define SPUR_DISABLE 0 #define SPUR_ENABLE_IOCTL 1 #define SPUR_ENABLE_EEPROM 2 -- GitLab From 05c78d6d3ec5a8325398b3866e7e6bb88940d4fd Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 14:57:04 +0530 Subject: [PATCH 0151/3892] ath9k: Remove ANI lock Cancel/restart the ANI timer directly. With this patch, the ANI lock can be removed. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 19 ++++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e2cef2ff5d8f..9f1f523e02eb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -453,7 +453,6 @@ struct ath_softc { int irq; spinlock_t sc_resetlock; spinlock_t sc_serial_rw; - spinlock_t ani_lock; spinlock_t sc_pm_lock; struct mutex mutex; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c48743452515..adb0edf2c8b0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -363,14 +363,6 @@ static void ath_ani_calibrate(unsigned long data) short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; - /* - * don't calibrate when we're scanning. - * we are most likely not on our home channel. - */ - spin_lock(&sc->ani_lock); - if (sc->sc_flags & SC_OP_SCANNING) - goto set_timer; - /* Only calibrate if awake */ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) goto set_timer; @@ -437,7 +429,6 @@ static void ath_ani_calibrate(unsigned long data) ath9k_ps_restore(sc); set_timer: - spin_unlock(&sc->ani_lock); /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, @@ -1610,7 +1601,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); - spin_lock_init(&sc->ani_lock); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); @@ -3113,6 +3103,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); if (ath9k_wiphy_scanning(sc)) { @@ -3128,10 +3119,8 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_SCAN; ath9k_wiphy_pause_all_forced(sc, aphy); - - spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; - spin_unlock_bh(&sc->ani_lock); + del_timer_sync(&common->ani.timer); mutex_unlock(&sc->mutex); } @@ -3139,13 +3128,13 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); - spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; - spin_unlock_bh(&sc->ani_lock); + ath_start_ani(common); ath_beacon_config(sc, NULL); mutex_unlock(&sc->mutex); } -- GitLab From b6ce5c33001b1dc83e6a1a6f30c5dccccea651b6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 14 Dec 2009 14:57:06 +0530 Subject: [PATCH 0152/3892] ath9k: Fix TX poll routine Disable the TX hang monitoring routine when doing a scan. Monitoring for a hung situation is not really necessary during a scan run. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index adb0edf2c8b0..6401b3521049 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -3121,6 +3121,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) ath9k_wiphy_pause_all_forced(sc, aphy); sc->sc_flags |= SC_OP_SCANNING; del_timer_sync(&common->ani.timer); + cancel_delayed_work_sync(&sc->tx_complete_work); mutex_unlock(&sc->mutex); } @@ -3135,6 +3136,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; ath_start_ani(common); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ath_beacon_config(sc, NULL); mutex_unlock(&sc->mutex); } -- GitLab From b6353f4f36f03a12edaf3fa5365b475a28106035 Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Tue, 22 Dec 2009 23:04:17 +0100 Subject: [PATCH 0153/3892] HID: Support for 3M multitouch panel Add support for 3M multitouch panels. Signed-off-by: Stephane Chatty [jkosina@suse.cz: fix build failure because of inconsistent 3M/MMM defines] Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 + drivers/hid/Makefile | 1 + drivers/hid/hid-3m-pct.c | 291 +++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + 5 files changed, 303 insertions(+) create mode 100644 drivers/hid/hid-3m-pct.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 24d90ea246ce..a05133f645bc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -55,6 +55,13 @@ source "drivers/hid/usbhid/Kconfig" menu "Special HID drivers" depends on HID +config HID_3M_PCT + tristate "3M PCT" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for 3M PCT touch screens. + config HID_A4TECH tristate "A4 tech" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0de2dff5542c..1bdfb97910f1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -19,6 +19,7 @@ ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-objs += hid-lg2ff.o endif +obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c new file mode 100644 index 000000000000..6d11e3dbbbff --- /dev/null +++ b/drivers/hid/hid-3m-pct.c @@ -0,0 +1,291 @@ +/* + * HID driver for 3M PCT multitouch panels + * + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +MODULE_VERSION("0.6"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("3M PCT multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct mmm_finger { + __s32 x, y; + __u8 rank; + bool touch, valid; +}; + +struct mmm_data { + struct mmm_finger f[10]; + __u8 curid, num; + bool touch, valid; +}; + +static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_BUTTON: + return -1; + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + /* we do not want to map these: no input-oriented meaning */ + case 0x14: + case 0x23: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_INRANGE: + case HID_DG_CONFIDENCE: + return -1; + case HID_DG_TIPSWITCH: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + } + /* let hid-input decide for the others */ + return 0; + + case 0xff000000: + /* we do not want to map these: no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole packet has been received and processed, + * so that it can decide what to send to the input layer. + */ +static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) +{ + struct mmm_finger *oldest = 0; + bool pressed = false, released = false; + int i; + + /* + * we need to iterate on all fingers to decide if we have a press + * or a release event in our touchscreen emulation. + */ + for (i = 0; i < 10; ++i) { + struct mmm_finger *f = &md->f[i]; + if (!f->valid) { + /* this finger is just placeholder data, ignore */ + } else if (f->touch) { + /* this finger is on the screen */ + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); + input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); + input_mt_sync(input); + /* + * touchscreen emulation: maintain the age rank + * of this finger, decide if we have a press + */ + if (f->rank == 0) { + f->rank = ++(md->num); + if (f->rank == 1) + pressed = true; + } + if (f->rank == 1) + oldest = f; + } else { + /* this finger took off the screen */ + /* touchscreen emulation: maintain age rank of others */ + int j; + + for (j = 0; j < 10; ++j) { + struct mmm_finger *g = &md->f[j]; + if (g->rank > f->rank) { + g->rank--; + if (g->rank == 1) + oldest = g; + } + } + f->rank = 0; + --(md->num); + if (md->num == 0) + released = true; + } + f->valid = 0; + } + + /* touchscreen emulation */ + if (oldest) { + if (pressed) + input_event(input, EV_KEY, BTN_TOUCH, 1); + input_event(input, EV_ABS, ABS_X, oldest->x); + input_event(input, EV_ABS, ABS_Y, oldest->y); + } else if (released) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + } +} + +/* + * this function is called upon all reports + * so that we can accumulate contact point information, + * and call input_mt_sync after each point. + */ +static int mmm_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mmm_data *md = hid_get_drvdata(hid); + /* + * strangely, this function can be called before + * field->hidinput is initialized! + */ + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + switch (usage->hid) { + case HID_DG_TIPSWITCH: + md->touch = value; + break; + case HID_DG_CONFIDENCE: + md->valid = value; + break; + case HID_DG_CONTACTID: + if (md->valid) { + md->curid = value; + md->f[value].touch = md->touch; + md->f[value].valid = 1; + } + break; + case HID_GD_X: + if (md->valid) + md->f[md->curid].x = value; + break; + case HID_GD_Y: + if (md->valid) + md->f[md->curid].y = value; + break; + case HID_DG_CONTACTCOUNT: + mmm_filter_event(md, input); + break; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mmm_data *md; + + md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL); + if (!md) { + dev_err(&hdev->dev, "cannot allocate 3M data\n"); + return -ENOMEM; + } + hid_set_drvdata(hdev, md); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(md); + return ret; +} + +static void mmm_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mmm_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mmm_devices); + +static const struct hid_usage_id mmm_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mmm_driver = { + .name = "3m-pct", + .id_table = mmm_devices, + .probe = mmm_probe, + .remove = mmm_remove, + .input_mapping = mmm_input_mapping, + .input_mapped = mmm_input_mapped, + .usage_table = mmm_grabbed_usages, + .event = mmm_event, +}; + +static int __init mmm_init(void) +{ + return hid_register_driver(&mmm_driver); +} + +static void __exit mmm_exit(void) +{ + hid_unregister_driver(&mmm_driver); +} + +module_init(mmm_init); +module_exit(mmm_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 80792d38d25c..70c25a056205 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1248,6 +1248,7 @@ EXPORT_SYMBOL_GPL(hid_disconnect); /* a list of devices for which there is a specialized driver on HID bus */ static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3839340e293a..3d55f983dbaf 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -18,6 +18,9 @@ #ifndef HID_IDS_H_FILE #define HID_IDS_H_FILE +#define USB_VENDOR_ID_3M 0x0596 +#define USB_DEVICE_ID_3M1968 0x0500 + #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_X5_005D 0x000a -- GitLab From 21949f00a022e090a7e8bc9a01dfca88273c6146 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Dec 2009 08:31:59 +0100 Subject: [PATCH 0154/3892] ALSA: hda - Fix NID association for capture mixers Fix the wrong implementation of NID <-> kctl mapping for capture mixers introduced by the ocmmit 5b0cb1d850c26893b1468b3a519433a1b7a176be. So far, the driver returns an error at probe. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 26 -------------------------- sound/pci/hda/hda_local.h | 2 -- sound/pci/hda/patch_analog.c | 3 +-- sound/pci/hda/patch_cirrus.c | 12 ++++++++---- sound/pci/hda/patch_cmedia.c | 3 +-- sound/pci/hda/patch_realtek.c | 3 +-- sound/pci/hda/patch_via.c | 3 +-- 7 files changed, 12 insertions(+), 40 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c848ec0f085e..29c90d748c91 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3537,32 +3537,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); -/** - * snd_hda_add_nids - assign nids to controls from the array - * @codec: the HDA codec - * @kctl: struct snd_kcontrol - * @index: index to kctl - * @nids: the array of hda_nid_t - * @size: count of hda_nid_t items - * - * This helper function assigns NIDs in the given array to a control element. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, - unsigned int index, hda_nid_t *nids, unsigned int size) -{ - int err; - - for ( ; size > 0; size--, nids++) { - err = snd_hda_add_nid(codec, kctl, index, *nids); - if (err < 0) - return err; - } - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_add_nids); - #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d505d052972e..7cee364976ff 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -343,8 +343,6 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl, - unsigned int index, hda_nid_t *nids, unsigned int size); /* * unsolicited event handler diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 92b72d4f3984..45ee352df329 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -244,8 +244,7 @@ static int ad198x_build_controls(struct hda_codec *codec) if (!kctl) kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids, - spec->input_mux->num_items); + err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 093cfbb55e9e..7de782a5b8f4 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -753,6 +753,7 @@ static int build_input(struct hda_codec *codec) spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); for (i = 0; i < 2; i++) { struct snd_kcontrol *kctl; + int n; if (!spec->capture_bind[i]) return -ENOMEM; kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); @@ -762,10 +763,13 @@ static int build_input(struct hda_codec *codec) err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; - err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid, - spec->num_inputs); - if (err < 0) - return err; + for (n = 0; n < AUTO_PIN_LAST; n++) { + if (!spec->adc_nid[n]) + continue; + err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]); + if (err < 0) + return err; + } } if (spec->num_inputs > 1 && !spec->mic_detect) { diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index cc1c22370a60..ff60908f4554 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -345,8 +345,7 @@ static int cmi9880_build_controls(struct hda_codec *codec) /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids, - spec->input_mux->num_items); + err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e7cdc6a7d61d..a45199014986 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2551,8 +2551,7 @@ static int alc_build_controls(struct hda_codec *codec) hda_nid_t *nids = spec->capsrc_nids; if (!nids) nids = spec->adc_nids; - err = snd_hda_add_nids(codec, kctl, i, nids, - spec->input_mux->num_items); + err = snd_hda_add_nid(codec, kctl, i, nids[i]); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index de4839e46762..9ddc37300f6b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1907,8 +1907,7 @@ static int via_build_controls(struct hda_codec *codec) /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids, - spec->input_mux->num_items); + err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); if (err < 0) return err; } -- GitLab From 863b557a88f8c033f7419fabafef4712a5055f85 Mon Sep 17 00:00:00 2001 From: "Youquan, Song" Date: Wed, 23 Dec 2009 19:45:20 +0800 Subject: [PATCH 0155/3892] crypto: testmgr - Fix complain about lack test for internal used algorithm When load aesni-intel and ghash_clmulni-intel driver,kernel will complain no test for some internal used algorithm. The strange information as following: alg: No test for __aes-aesni (__driver-aes-aesni) alg: No test for __ecb-aes-aesni (__driver-ecb-aes-aesni) alg: No test for __cbc-aes-aesni (__driver-cbc-aes-aesni) alg: No test for __ecb-aes-aesni (cryptd(__driver-ecb-aes-aesni) alg: No test for __ghash (__ghash-pclmulqdqni) alg: No test for __ghash (cryptd(__ghash-pclmulqdqni)) This patch add NULL test entries for these algorithm and driver. Signed-off-by: Youquan, Song Signed-off-by: Ying, Huang Signed-off-by: Herbert Xu --- crypto/testmgr.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 7620bfce92f2..c494d7610be1 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1477,9 +1477,54 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, return err; } +static int alg_test_null(const struct alg_test_desc *desc, + const char *driver, u32 type, u32 mask) +{ + return 0; +} + /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { + .alg = "__driver-cbc-aes-aesni", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "__driver-ecb-aes-aesni", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "__ghash-pclmulqdqni", + .test = alg_test_null, + .suite = { + .hash = { + .vecs = NULL, + .count = 0 + } + } + }, { .alg = "ansi_cprng", .test = alg_test_cprng, .fips_allowed = 1, @@ -1622,6 +1667,30 @@ static const struct alg_test_desc alg_test_descs[] = { .count = CRC32C_TEST_VECTORS } } + }, { + .alg = "cryptd(__driver-ecb-aes-aesni)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "cryptd(__ghash-pclmulqdqni)", + .test = alg_test_null, + .suite = { + .hash = { + .vecs = NULL, + .count = 0 + } + } }, { .alg = "ctr(aes)", .test = alg_test_skcipher, @@ -1668,6 +1737,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "ecb(__aes-aesni)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "ecb(aes)", .test = alg_test_skcipher, -- GitLab From 4b186f72033611c2b526c7341534e71ee4afd222 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 23 Dec 2009 13:12:32 +0100 Subject: [PATCH 0156/3892] HID: make 3M PCT touchscreen driver standalone config option The point behind 'default !EMBEDDED' for certain HID drivers that simple and straightforward quirks for HID devices (which are implemented as drivers on HID bus) wouldn't have to be enabled separately, if the device is otherwise more-or-less HID standard compliant. But this driver is rather standalone driver, so we'd want to have it normally selectable. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a05133f645bc..0c8ce3a68d27 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -56,9 +56,8 @@ menu "Special HID drivers" depends on HID config HID_3M_PCT - tristate "3M PCT" if EMBEDDED + tristate "3M PCT" depends on USB_HID - default !EMBEDDED ---help--- Support for 3M PCT touch screens. -- GitLab From bc86fcbac0a86a93ee65cc31769c4e83e6ff2295 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 8 Dec 2009 20:40:54 +0000 Subject: [PATCH 0157/3892] netxen: minor suspend resume fixes o pci device should be disable at the end and it should be enable first. o Interface should be attached(netif_device_attach()) irrespective of its state. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 6cae26a5bd67..41cb0af4b556 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1448,14 +1448,14 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 1); } - pci_disable_device(pdev); - return 0; } static void netxen_nic_shutdown(struct pci_dev *pdev) { if (__netxen_nic_shutdown(pdev)) return; + + pci_disable_device(pdev); } #ifdef CONFIG_PM static int @@ -1468,6 +1468,8 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) return retval; pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_disable_device(pdev); return 0; } @@ -1478,13 +1480,14 @@ netxen_nic_resume(struct pci_dev *pdev) struct net_device *netdev = adapter->netdev; int err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); if (err) return err; + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_restore_state(pdev); + adapter->ahw.crb_win = -1; adapter->ahw.ocm_win = -1; @@ -1503,11 +1506,10 @@ netxen_nic_resume(struct pci_dev *pdev) if (err) goto err_out_detach; - netif_device_attach(netdev); - netxen_config_indev_addr(netdev, NETDEV_UP); } + netif_device_attach(netdev); netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); return 0; -- GitLab From 6a808c6c02fb9f0ffa24ac7cca6cfc323cf98b21 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 8 Dec 2009 20:40:55 +0000 Subject: [PATCH 0158/3892] netxen: fix tx timeout recovery o In case of tx timeout, firmare may be healthy, but some pci-func may see no response from it. Force firmware reset, if some pci-func explicitly requests so. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 3 +++ drivers/net/netxen/netxen_nic_main.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 02f8d4b4db63..ba62411f3532 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -778,6 +778,9 @@ netxen_need_fw_reset(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 1; + if (adapter->need_fw_reset) + return 1; + /* last attempt had failed */ if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED) return 1; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 41cb0af4b556..1aca6260909a 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2284,8 +2284,10 @@ netxen_check_health(struct netxen_adapter *adapter) } state = NXRD32(adapter, NX_CRB_DEV_STATE); - if (state == NX_DEV_NEED_RESET) + if (state == NX_DEV_NEED_RESET) { + adapter->need_fw_reset = 1; goto detach; + } if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; -- GitLab From e87ad5539343366e7c634c940a930157b6fa2aae Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 8 Dec 2009 20:40:56 +0000 Subject: [PATCH 0159/3892] netxen: support pci error handlers o Support pci error detection and recovery. o Refactor suspend and resume code, to share with io_error_detected, and slot_reset callbacks o NX_NEED_AER device state added, to synchronize with firmware recovery. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_hdr.h | 3 +- drivers/net/netxen/netxen_nic_main.c | 193 ++++++++++++++++++++------- 2 files changed, 150 insertions(+), 46 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index d138fc22927a..638369024908 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -969,7 +969,8 @@ enum { #define NX_DEV_READY 3 #define NX_DEV_NEED_RESET 4 #define NX_DEV_NEED_QUISCENT 5 -#define NX_DEV_FAILED 6 +#define NX_DEV_NEED_AER 6 +#define NX_DEV_FAILED 7 #define NX_RCODE_DRIVER_INFO 0x20000000 #define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1aca6260909a..f13a07f717c7 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -35,6 +35,7 @@ #include #include #include +#include MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -84,6 +85,7 @@ static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); static void netxen_create_diag_entries(struct netxen_adapter *adapter); static void netxen_remove_diag_entries(struct netxen_adapter *adapter); +static int nx_dev_request_aer(struct netxen_adapter *adapter); static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); static int netxen_can_start_firmware(struct netxen_adapter *adapter); @@ -1262,6 +1264,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((err = pci_request_regions(pdev, netxen_nic_driver_name))) goto err_out_disable_pdev; + if (NX_IS_REVISION_P3(pdev->revision)) + pci_enable_pcie_error_reporting(pdev); + pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct netxen_adapter)); @@ -1409,17 +1414,19 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_release_firmware(adapter); + if (NX_IS_REVISION_P3(pdev->revision)) + pci_disable_pcie_error_reporting(pdev); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(netdev); } -static int __netxen_nic_shutdown(struct pci_dev *pdev) + +static void netxen_nic_detach_func(struct netxen_adapter *adapter) { - struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - int retval; netif_device_detach(netdev); @@ -1438,43 +1445,9 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) nx_decr_dev_ref_cnt(adapter); clear_bit(__NX_RESETTING, &adapter->state); - - retval = pci_save_state(pdev); - if (retval) - return retval; - - if (netxen_nic_wol_supported(adapter)) { - pci_enable_wake(pdev, PCI_D3cold, 1); - pci_enable_wake(pdev, PCI_D3hot, 1); - } - - return 0; -} -static void netxen_nic_shutdown(struct pci_dev *pdev) -{ - if (__netxen_nic_shutdown(pdev)) - return; - - pci_disable_device(pdev); -} -#ifdef CONFIG_PM -static int -netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) -{ - int retval; - - retval = __netxen_nic_shutdown(pdev); - if (retval) - return retval; - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - pci_disable_device(pdev); - return 0; } -static int -netxen_nic_resume(struct pci_dev *pdev) +static int netxen_nic_attach_func(struct pci_dev *pdev) { struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; @@ -1519,6 +1492,85 @@ err_out: nx_decr_dev_ref_cnt(adapter); return err; } + +static pci_ers_result_t netxen_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (nx_dev_request_aer(adapter)) + return PCI_ERS_RESULT_RECOVERED; + + netxen_nic_detach_func(adapter); + + pci_disable_device(pdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev) +{ + int err = 0; + + err = netxen_nic_attach_func(pdev); + + return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; +} + +static void netxen_io_resume(struct pci_dev *pdev) +{ + pci_cleanup_aer_uncorrect_error_status(pdev); +} + +static void netxen_nic_shutdown(struct pci_dev *pdev) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + + netxen_nic_detach_func(adapter); + + if (pci_save_state(pdev)) + return; + + if (netxen_nic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int +netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + int retval; + + netxen_nic_detach_func(adapter); + + retval = pci_save_state(pdev); + if (retval) + return retval; + + if (netxen_nic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int +netxen_nic_resume(struct pci_dev *pdev) +{ + return netxen_nic_attach_func(pdev); +} #endif static int netxen_nic_open(struct net_device *netdev) @@ -2110,20 +2162,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) return count; } -static void +static int +nx_dev_request_aer(struct netxen_adapter *adapter) +{ + u32 state; + int ret = -EINVAL; + + if (netxen_api_lock(adapter)) + return ret; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + + if (state == NX_DEV_NEED_AER) + ret = 0; + else if (state == NX_DEV_READY) { + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER); + ret = 0; + } + + netxen_api_unlock(adapter); + return ret; +} + +static int nx_dev_request_reset(struct netxen_adapter *adapter) { u32 state; + int ret = -EINVAL; if (netxen_api_lock(adapter)) - return; + return ret; state = NXRD32(adapter, NX_CRB_DEV_STATE); - if (state != NX_DEV_INITALIZING) + if (state == NX_DEV_NEED_RESET) + ret = 0; + else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) { NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); + ret = 0; + } netxen_api_unlock(adapter); + + return ret; } static int @@ -2275,18 +2356,28 @@ netxen_check_health(struct netxen_adapter *adapter) u32 state, heartbit; struct net_device *netdev = adapter->netdev; + state = NXRD32(adapter, NX_CRB_DEV_STATE); + if (state == NX_DEV_NEED_AER) + return 0; + if (netxen_nic_check_temp(adapter)) goto detach; if (adapter->need_fw_reset) { - nx_dev_request_reset(adapter); + if (nx_dev_request_reset(adapter)) + return 0; goto detach; } - state = NXRD32(adapter, NX_CRB_DEV_STATE); + /* NX_DEV_NEED_RESET, this state can be marked in two cases + * 1. Tx timeout 2. Fw hang + * Send request to destroy context in case of tx timeout only + * and doesn't required in case of Fw hang + */ if (state == NX_DEV_NEED_RESET) { adapter->need_fw_reset = 1; - goto detach; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + goto detach; } if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) @@ -2296,12 +2387,17 @@ netxen_check_health(struct netxen_adapter *adapter) if (heartbit != adapter->heartbit) { adapter->heartbit = heartbit; adapter->fw_fail_cnt = 0; + if (adapter->need_fw_reset) + goto detach; return 0; } if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) return 0; + if (nx_dev_request_reset(adapter)) + return 0; + clear_bit(__NX_FW_ATTACHED, &adapter->state); dev_info(&netdev->dev, "firmware hang detected\n"); @@ -2731,6 +2827,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) { } #endif +static struct pci_error_handlers netxen_err_handler = { + .error_detected = netxen_io_error_detected, + .slot_reset = netxen_io_slot_reset, + .resume = netxen_io_resume, +}; + static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, .id_table = netxen_pci_tbl, @@ -2740,7 +2842,8 @@ static struct pci_driver netxen_driver = { .suspend = netxen_nic_suspend, .resume = netxen_nic_resume, #endif - .shutdown = netxen_nic_shutdown + .shutdown = netxen_nic_shutdown, + .err_handler = &netxen_err_handler }; static int __init netxen_init_module(void) -- GitLab From 7ef8a2127a64d131c4dbe5b843e5708f6e75552b Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 8 Dec 2009 20:40:57 +0000 Subject: [PATCH 0160/3892] netxen: fix unified fw size check o Unified firmware image size can be < 1 MB Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 76cd1f3e9fc8..c1223c92d566 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -420,7 +420,7 @@ struct status_desc { } __attribute__ ((aligned(16))); /* UNIFIED ROMIMAGE *************************/ -#define NX_UNI_FW_MIN_SIZE 0x3eb000 +#define NX_UNI_FW_MIN_SIZE 0xc8000 #define NX_UNI_DIR_SECT_PRODUCT_TBL 0x0 #define NX_UNI_DIR_SECT_BOOTLD 0x6 #define NX_UNI_DIR_SECT_FW 0x7 -- GitLab From 12d50c46dc0f7fd2e625c4befaa5fa5740a7a594 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Tue, 8 Dec 2009 22:26:13 +0000 Subject: [PATCH 0161/3892] tcp: Remove check in __tcp_push_pending_frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcp_push checks tcp_send_head and calls __tcp_push_pending_frames, which again checks tcp_send_head, and this unnecessary check is done for every other caller of __tcp_push_pending_frames. Remove tcp_send_head check in __tcp_push_pending_frames and add the check to tcp_push_pending_frames. Other functions call __tcp_push_pending_frames only when tcp_send_head would evaluate to true. Signed-off-by: Krishna Kumar Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 16 +++++++++------- net/ipv4/tcp_output.c | 5 ----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 34f5cc24d903..185e22baecb1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -856,13 +856,6 @@ static inline void tcp_check_probe_timer(struct sock *sk) icsk->icsk_rto, TCP_RTO_MAX); } -static inline void tcp_push_pending_frames(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle); -} - static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq) { tp->snd_wl1 = seq; @@ -1342,6 +1335,15 @@ static inline int tcp_write_queue_empty(struct sock *sk) return skb_queue_empty(&sk->sk_write_queue); } +static inline void tcp_push_pending_frames(struct sock *sk) +{ + if (tcp_send_head(sk)) { + struct tcp_sock *tp = tcp_sk(sk); + + __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle); + } +} + /* Start sequence of the highest skb with SACKed bit, valid only if * sacked > 0 or when the caller has ensured validity by itself. */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 383ce237640f..12b2af36eab8 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1794,11 +1794,6 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, int nonagle) { - struct sk_buff *skb = tcp_send_head(sk); - - if (!skb) - return; - /* If we are closed, the bytes will have to remain here. * In time closedown will finish, we empty the write queue and * all will be happy. -- GitLab From afeca340c078e17ca233b3c68c3c3a70c56bfe1d Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 10 Dec 2009 07:16:52 +0000 Subject: [PATCH 0162/3892] tcp: Remove unrequired operations in tcp_push() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unrequired operations in tcp_push() Changelog: Removed a temporary skb variable from tcp_push() Signed-off-by: Krishna Kumar Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b0a26bb25e2e..8a3f05adb39b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -536,8 +536,7 @@ static inline void skb_entail(struct sock *sk, struct sk_buff *skb) tp->nonagle &= ~TCP_NAGLE_PUSH; } -static inline void tcp_mark_urg(struct tcp_sock *tp, int flags, - struct sk_buff *skb) +static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) { if (flags & MSG_OOB) tp->snd_up = tp->write_seq; @@ -546,13 +545,13 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags, static inline void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle) { - struct tcp_sock *tp = tcp_sk(sk); - if (tcp_send_head(sk)) { - struct sk_buff *skb = tcp_write_queue_tail(sk); + struct tcp_sock *tp = tcp_sk(sk); + if (!(flags & MSG_MORE) || forced_push(tp)) - tcp_mark_push(tp, skb); - tcp_mark_urg(tp, flags, skb); + tcp_mark_push(tp, tcp_write_queue_tail(sk)); + + tcp_mark_urg(tp, flags); __tcp_push_pending_frames(sk, mss_now, (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle); } -- GitLab From def87cf42069a6d4fd42a2ede8f19c620a292568 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 10 Dec 2009 07:16:59 +0000 Subject: [PATCH 0163/3892] tcp: Slightly optimize tcp_sendmsg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slightly optimize tcp_sendmsg since NETIF_F_SG is used many times iteratively in the loop. The only other modification is to change: } else if (i == MAX_SKB_FRAGS || (!i && !(sk->sk_route_caps & NETIF_F_SG))) { to: } else if (i == MAX_SKB_FRAGS || !sg) { The reason why this change is correct: this code (other than the MAX_SKB_FRAGS case) executes only due to the else part of: "if (skb_tailroom(skb) > 0) {" - i.e. there was no space in the skb to put the data inline. Hence SG is false is a sufficient condition, and there is no way a fragment can be added to the skb. Changelog: - Added the above explanation for the change Signed-off-by: Krishna Kumar Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8a3f05adb39b..d5d69ea8f249 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -876,12 +876,12 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, #define TCP_PAGE(sk) (sk->sk_sndmsg_page) #define TCP_OFF(sk) (sk->sk_sndmsg_off) -static inline int select_size(struct sock *sk) +static inline int select_size(struct sock *sk, int sg) { struct tcp_sock *tp = tcp_sk(sk); int tmp = tp->mss_cache; - if (sk->sk_route_caps & NETIF_F_SG) { + if (sg) { if (sk_can_gso(sk)) tmp = 0; else { @@ -905,7 +905,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, struct sk_buff *skb; int iovlen, flags; int mss_now, size_goal; - int err, copied; + int sg, err, copied; long timeo; lock_sock(sk); @@ -933,6 +933,8 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto out_err; + sg = sk->sk_route_caps & NETIF_F_SG; + while (--iovlen >= 0) { int seglen = iov->iov_len; unsigned char __user *from = iov->iov_base; @@ -958,8 +960,9 @@ new_segment: if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; - skb = sk_stream_alloc_skb(sk, select_size(sk), - sk->sk_allocation); + skb = sk_stream_alloc_skb(sk, + select_size(sk, sg), + sk->sk_allocation); if (!skb) goto wait_for_memory; @@ -996,9 +999,7 @@ new_segment: /* We can extend the last page * fragment. */ merge = 1; - } else if (i == MAX_SKB_FRAGS || - (!i && - !(sk->sk_route_caps & NETIF_F_SG))) { + } else if (i == MAX_SKB_FRAGS || !sg) { /* Need to add new fragment and cannot * do this because interface is non-SG, * or because all the page slots are -- GitLab From 068a2de57ddf4f472e32e7af868613c574ad1d88 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 9 Dec 2009 20:59:58 +0000 Subject: [PATCH 0164/3892] net: release dst entry while cache-hot for GSO case too Non-GSO code drops dst entry for performance reasons, but the same is missing for GSO code. Drop dst while cache-hot for GSO case too. Signed-off-by: Krishna Kumar Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index be9924f60ec3..a8d68cdedbbe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1853,6 +1853,14 @@ gso: skb->next = nskb->next; nskb->next = NULL; + + /* + * If device doesnt need nskb->dst, release it right now while + * its hot in this cpu cache + */ + if (dev->priv_flags & IFF_XMIT_DST_RELEASE) + skb_dst_drop(nskb); + rc = ops->ndo_start_xmit(nskb, dev); if (unlikely(rc != NETDEV_TX_OK)) { if (rc & ~NETDEV_TX_MASK) -- GitLab From 31d12926e37291970dd4f6e9940df3897766a81d Mon Sep 17 00:00:00 2001 From: laurent chavey Date: Tue, 15 Dec 2009 11:15:28 +0000 Subject: [PATCH 0165/3892] net: Add rtnetlink init_rcvwnd to set the TCP initial receive window Add rtnetlink init_rcvwnd to set the TCP initial receive window size advertised by passive and active TCP connections. The current Linux TCP implementation limits the advertised TCP initial receive window to the one prescribed by slow start. For short lived TCP connections used for transaction type of traffic (i.e. http requests), bounding the advertised TCP initial receive window results in increased latency to complete the transaction. Support for setting initial congestion window is already supported using rtnetlink init_cwnd, but the feature is useless without the ability to set a larger TCP initial receive window. The rtnetlink init_rcvwnd allows increasing the TCP initial receive window, allowing TCP connection to advertise larger TCP receive window than the ones bounded by slow start. Signed-off-by: Laurent Chavey Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 ++ include/net/dst.h | 2 -- include/net/tcp.h | 3 ++- net/ipv4/syncookies.c | 3 ++- net/ipv4/tcp_output.c | 17 +++++++++++++---- net/ipv6/syncookies.c | 3 ++- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 05330fc5b436..9590364fe8b5 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -362,6 +362,8 @@ enum { #define RTAX_FEATURES RTAX_FEATURES RTAX_RTO_MIN, #define RTAX_RTO_MIN RTAX_RTO_MIN + RTAX_INITRWND, +#define RTAX_INITRWND RTAX_INITRWND __RTAX_MAX }; diff --git a/include/net/dst.h b/include/net/dst.h index 39c4a5963e12..ce078cda6b74 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -83,8 +83,6 @@ struct dst_entry { * (L1_CACHE_SIZE would be too much) */ #ifdef CONFIG_64BIT - long __pad_to_align_refcnt[2]; -#else long __pad_to_align_refcnt[1]; #endif /* diff --git a/include/net/tcp.h b/include/net/tcp.h index 185e22baecb1..788c99f98597 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -965,7 +965,8 @@ static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) /* Determine a window scaling and initial window to offer. */ extern void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, __u32 *window_clamp, - int wscale_ok, __u8 *rcv_wscale); + int wscale_ok, __u8 *rcv_wscale, + __u32 init_rcv_wnd); static inline int tcp_win_from_space(int space) { diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 66fd80ef2473..5c24db4a3c91 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -358,7 +358,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp, - ireq->wscale_ok, &rcv_wscale); + ireq->wscale_ok, &rcv_wscale, + dst_metric(&rt->u.dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 12b2af36eab8..4a1605d3f909 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -183,7 +183,8 @@ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) */ void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, __u32 *window_clamp, - int wscale_ok, __u8 *rcv_wscale) + int wscale_ok, __u8 *rcv_wscale, + __u32 init_rcv_wnd) { unsigned int space = (__space < 0 ? 0 : __space); @@ -232,7 +233,13 @@ void tcp_select_initial_window(int __space, __u32 mss, init_cwnd = 2; else if (mss > 1460) init_cwnd = 3; - if (*rcv_wnd > init_cwnd * mss) + /* when initializing use the value from init_rcv_wnd + * rather than the default from above + */ + if (init_rcv_wnd && + (*rcv_wnd > init_rcv_wnd * mss)) + *rcv_wnd = init_rcv_wnd * mss; + else if (*rcv_wnd > init_cwnd * mss) *rcv_wnd = init_cwnd * mss; } @@ -2417,7 +2424,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, &req->rcv_wnd, &req->window_clamp, ireq->wscale_ok, - &rcv_wscale); + &rcv_wscale, + dst_metric(dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; } @@ -2544,7 +2552,8 @@ static void tcp_connect_init(struct sock *sk) &tp->rcv_wnd, &tp->window_clamp, sysctl_tcp_window_scaling, - &rcv_wscale); + &rcv_wscale, + dst_metric(dst, RTAX_INITRWND)); tp->rx_opt.rcv_wscale = rcv_wscale; tp->rcv_ssthresh = tp->rcv_wnd; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 7208a06576c6..34d1f0690d7e 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -269,7 +269,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp, - ireq->wscale_ok, &rcv_wscale); + ireq->wscale_ok, &rcv_wscale, + dst_metric(dst, RTAX_INITRWND)); ireq->rcv_wscale = rcv_wscale; -- GitLab From 9fa4d67c6e4d678271798f006ca1d945e8b2bd5c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 16 Dec 2009 04:26:24 +0000 Subject: [PATCH 0166/3892] iwmc3200top: clean up fw_download 1. removed redundant NULL-pointers checks in iwmct_fw_load as release_firmware and kfree are NULL pointer friendly 2. remove redundant memset of the parser since the structure is fully initialized in iwmct_fw_parser_init function Signed-off-by: Tomas Winkler Signed-off-by: David S. Miller --- drivers/misc/iwmc3200top/fw-download.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c index 50d431e469f5..474be9228904 100644 --- a/drivers/misc/iwmc3200top/fw-download.c +++ b/drivers/misc/iwmc3200top/fw-download.c @@ -50,8 +50,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, parser->file = file; parser->file_size = file_size; parser->cur_pos = 0; - parser->buf = NULL; - + parser->entry_point = 0; parser->buf = kzalloc(block_size, GFP_KERNEL); if (!parser->buf) { LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); @@ -298,8 +297,6 @@ int iwmct_fw_load(struct iwmct_priv *priv) __le32 addr; int ret; - /* clear parser struct */ - memset(&priv->parser, 0, sizeof(struct iwmct_parser)); /* get the firmware */ ret = request_firmware(&raw, fw_name, &priv->func->dev); @@ -317,6 +314,7 @@ int iwmct_fw_load(struct iwmct_priv *priv) LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); + /* clear parser struct */ ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); if (ret < 0) { LOG_ERROR(priv, FW_DOWNLOAD, @@ -324,7 +322,6 @@ int iwmct_fw_load(struct iwmct_priv *priv) goto exit; } - /* checksum */ if (!iwmct_checksum(priv)) { LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); ret = -EINVAL; @@ -333,23 +330,18 @@ int iwmct_fw_load(struct iwmct_priv *priv) /* download firmware to device */ while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { - if (iwmct_download_section(priv, pdata, len, addr)) { + ret = iwmct_download_section(priv, pdata, len, addr); + if (ret) { LOG_ERROR(priv, FW_DOWNLOAD, "%s download section failed\n", fw_name); - ret = -EIO; goto exit; } } - iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); + ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); exit: kfree(priv->parser.buf); - - if (raw) - release_firmware(raw); - - raw = NULL; - + release_firmware(raw); return ret; } -- GitLab From 0df828f670b1fd8c469f3d60472ddca0d0f51fcf Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 16 Dec 2009 04:26:25 +0000 Subject: [PATCH 0167/3892] iwmc3200top: cleanup log messages 1. add TRACE level 2. use TRACE where needed to reduce the noise 3 don't INFOEX from driver 4. add DUMP level for packets dumps 5. use correct context for the log messages Signed-off-by: Tomas Winkler Signed-off-by: David S. Miller --- drivers/misc/iwmc3200top/fw-download.c | 26 ++++++++++++++------- drivers/misc/iwmc3200top/log.h | 31 ++++++++++++++++++-------- drivers/misc/iwmc3200top/main.c | 25 +++++++-------------- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c index 474be9228904..07055afef858 100644 --- a/drivers/misc/iwmc3200top/fw-download.c +++ b/drivers/misc/iwmc3200top/fw-download.c @@ -43,7 +43,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, struct iwmct_parser *parser = &priv->parser; struct iwmct_fw_hdr *fw_hdr = &parser->versions; - LOG_INFOEX(priv, INIT, "-->\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); @@ -69,7 +69,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, parser->cur_pos += sizeof(struct iwmct_fw_hdr); - LOG_INFOEX(priv, INIT, "<--\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); return 0; } @@ -112,7 +112,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, struct iwmct_dbg *dbg = &priv->dbg; struct iwmct_fw_sec_hdr *sec_hdr; - LOG_INFOEX(priv, INIT, "-->\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) <= parser->file_size) { @@ -151,7 +151,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, "finished with section cur_pos=%zd\n", parser->cur_pos); } - LOG_INFOEX(priv, INIT, "<--\n"); + LOG_TRACE(priv, INIT, "<--\n"); return 0; } @@ -166,7 +166,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, int ret = 0; u32 cmd = 0; - LOG_INFOEX(priv, INIT, "-->\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", addr, sec_size); @@ -250,7 +250,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, if (sent < sec_size) ret = -EINVAL; exit: - LOG_INFOEX(priv, INIT, "<--\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); return ret; } @@ -261,7 +261,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) int ret; u32 cmd; - LOG_INFOEX(priv, INIT, "-->\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); memset(parser->buf, 0, parser->buf_size); cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; @@ -284,7 +284,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) if (ret) LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); - LOG_INFOEX(priv, INIT, "<--\n"); + LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); return 0; } @@ -298,6 +298,16 @@ int iwmct_fw_load(struct iwmct_priv *priv) int ret; + LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n", + priv->barker); + LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n", + (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); + LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n", + (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); + LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n", + (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); + + /* get the firmware */ ret = request_firmware(&raw, fw_name, &priv->func->dev); if (ret < 0) { diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h index aba8121f978c..4434bb16cea7 100644 --- a/drivers/misc/iwmc3200top/log.h +++ b/drivers/misc/iwmc3200top/log.h @@ -37,13 +37,26 @@ #define LOG_SEV_INFO 3 #define LOG_SEV_INFOEX 4 -#define LOG_SEV_FILTER_ALL \ - (BIT(LOG_SEV_CRITICAL) | \ - BIT(LOG_SEV_ERROR) | \ - BIT(LOG_SEV_WARNING) | \ - BIT(LOG_SEV_INFO) | \ +/* Log levels not defined for FW */ +#define LOG_SEV_TRACE 5 +#define LOG_SEV_DUMP 6 + +#define LOG_SEV_FW_FILTER_ALL \ + (BIT(LOG_SEV_CRITICAL) | \ + BIT(LOG_SEV_ERROR) | \ + BIT(LOG_SEV_WARNING) | \ + BIT(LOG_SEV_INFO) | \ BIT(LOG_SEV_INFOEX)) +#define LOG_SEV_FILTER_ALL \ + (BIT(LOG_SEV_CRITICAL) | \ + BIT(LOG_SEV_ERROR) | \ + BIT(LOG_SEV_WARNING) | \ + BIT(LOG_SEV_INFO) | \ + BIT(LOG_SEV_INFOEX) | \ + BIT(LOG_SEV_TRACE) | \ + BIT(LOG_SEV_DUMP)) + /* log source */ #define LOG_SRC_INIT 0 #define LOG_SRC_DEBUGFS 1 @@ -104,16 +117,16 @@ do { \ __func__, __LINE__, ##args); \ } while (0) -#define LOG_INFOEX(priv, src, fmt, args...) \ +#define LOG_TRACE(priv, src, fmt, args...) \ do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \ + if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \ dev_dbg(priv2dev(priv), "%s %d: " fmt, \ __func__, __LINE__, ##args); \ } while (0) #define LOG_HEXDUMP(src, ptr, len) \ do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \ + if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ 16, 1, ptr, len, false); \ } while (0) @@ -142,7 +155,7 @@ ssize_t store_iwmct_log_level_fw(struct device *d, #define LOG_ERROR(priv, src, fmt, args...) #define LOG_WARNING(priv, src, fmt, args...) #define LOG_INFO(priv, src, fmt, args...) -#define LOG_INFOEX(priv, src, fmt, args...) +#define LOG_TRACE(priv, src, fmt, args...) #define LOG_HEXDUMP(src, ptr, len) static inline void iwmct_log_top_message(struct iwmct_priv *priv, diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index fafcaa481d74..38627949ff54 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -66,7 +66,7 @@ static void iwmct_rescan_worker(struct work_struct *ws) ret = bus_rescan_devices(priv->func->dev.bus); if (ret < 0) - LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n"); + LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n"); } static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) @@ -137,7 +137,7 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) int ret; u8 *buf; - LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n"); + LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n"); /* add padding to 256 for IWMC */ ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; @@ -192,7 +192,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) priv = container_of(ws, struct iwmct_priv, isr_worker); - LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); + LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); /* --------------------- Handshake with device -------------------- */ sdio_claim_host(priv->func); @@ -292,15 +292,6 @@ static void iwmct_irq_read_worker(struct work_struct *ws) sdio_release_host(priv->func); - - LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker); - LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); - LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); - LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); - if (priv->dbg.fw_download) iwmct_fw_load(priv); else @@ -312,7 +303,7 @@ exit_release: sdio_release_host(priv->func); exit: kfree(buf); - LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n"); + LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n"); } static void iwmct_irq(struct sdio_func *func) @@ -325,12 +316,12 @@ static void iwmct_irq(struct sdio_func *func) priv = sdio_get_drvdata(func); - LOG_INFO(priv, IRQ, "enter iwmct_irq\n"); + LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); /* read the function's status register */ val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); - LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); + LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); if (!val) { LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); @@ -372,7 +363,7 @@ static void iwmct_irq(struct sdio_func *func) queue_work(priv->wq, &priv->isr_worker); - LOG_INFO(priv, IRQ, "exit iwmct_irq\n"); + LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); return; @@ -660,7 +651,7 @@ static int __init iwmct_init(void) /* Default log filter settings */ iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); - iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL); + iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL); iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); rc = sdio_register_driver(&iwmct_driver); -- GitLab From fe45332ed289d91e57eca11bfd1ca75d6e420ab4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 16 Dec 2009 04:26:26 +0000 Subject: [PATCH 0168/3892] iwmc3200top: simplify imwct_tx 1. remove address argument since we use same address IWMC_SDIO_DATA_ADDR in all cases 2. add __iwmct_tx - non locking tx function for already locked contexts Signed-off-by: Tomas Winkler Signed-off-by: David S. Miller --- drivers/misc/iwmc3200top/fw-download.c | 4 +-- drivers/misc/iwmc3200top/iwmc3200top.h | 4 +-- drivers/misc/iwmc3200top/main.c | 34 ++++++++++++-------------- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c index 07055afef858..9dbaeb574e63 100644 --- a/drivers/misc/iwmc3200top/fw-download.c +++ b/drivers/misc/iwmc3200top/fw-download.c @@ -228,7 +228,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, hdr->cmd = cpu_to_le32(cmd); /* send it down */ /* TODO: add more proper sending and error checking */ - ret = iwmct_tx(priv, 0, parser->buf, trans_size); + ret = iwmct_tx(priv, parser->buf, trans_size); if (ret != 0) { LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d\n", ret); @@ -280,7 +280,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); /* send it down */ /* TODO: add more proper sending and error checking */ - ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE); + ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE); if (ret) LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h index 43bd510e1872..740ff0738ea8 100644 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ b/drivers/misc/iwmc3200top/iwmc3200top.h @@ -196,9 +196,7 @@ struct iwmct_priv { struct list_head read_req_list; }; -extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr, - void *src, int count); - +extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count); extern int iwmct_fw_load(struct iwmct_priv *priv); extern void iwmct_dbg_init_params(struct iwmct_priv *drv); diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index 38627949ff54..dd0a3913bf6d 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -49,6 +49,20 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_COPYRIGHT); MODULE_FIRMWARE(FW_NAME(FW_API_VER)); + +static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count) +{ + return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count); + +} +int iwmct_tx(struct iwmct_priv *priv, void *src, int count) +{ + int ret; + sdio_claim_host(priv->func); + ret = __iwmct_tx(priv, src, count); + sdio_release_host(priv->func); + return ret; +} /* * This workers main task is to wait for OP_OPR_ALIVE * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. @@ -158,27 +172,12 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) } memcpy(buf, cmd, len); - - sdio_claim_host(priv->func); - ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf, - FW_HCMD_BLOCK_SIZE); - sdio_release_host(priv->func); + ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE); kfree(buf); return ret; } -int iwmct_tx(struct iwmct_priv *priv, unsigned int addr, - void *src, int count) -{ - int ret; - - sdio_claim_host(priv->func); - ret = sdio_memcpy_toio(priv->func, addr, src, count); - sdio_release_host(priv->func); - - return ret; -} static void iwmct_irq_read_worker(struct work_struct *ws) { @@ -273,8 +272,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) if (barker & BARKER_DNLOAD_SYNC_MSK) { /* Send the same barker back */ - ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, - buf, iosize); + ret = __iwmct_tx(priv, buf, iosize); if (ret) { LOG_ERROR(priv, IRQ, "error %d echoing barker\n", ret); -- GitLab From b3d18d191bb805f3effdfc083c4ce79789470b46 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:30 +0000 Subject: [PATCH 0169/3892] enic: Bug fix: use safe queue shutdown in dev->stop Fix dev->stop shutdown bug where driver was stopping xmit queue and then disabling intrs. Fix is to disable intrs first and then stop the xmit queue, otherwise an interrupt could cause the queue to be rewoken. Also, no need to explicitly do queue servicing because queues are cleaned and reset back to initial state at end of dev->stop. Servicing queues also had the side-effect of also rewakening the xmit queue, which is not what we want. Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 2 +- drivers/net/enic/enic_main.c | 62 +++++++++++++++--------------------- drivers/net/enic/vnic_intr.h | 1 + 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index e1c2076228ba..8dd0105a8d9c 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -34,7 +34,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "1.1.0.100" +#define DRV_VERSION "1.1.0.241a" #define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" #define PFX DRV_NAME ": " diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index f875751af15e..b4a11befb3b3 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1084,34 +1084,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, return 0; } -static void enic_rq_drop_buf(struct vnic_rq *rq, - struct cq_desc *cq_desc, struct vnic_rq_buf *buf, - int skipped, void *opaque) -{ - struct enic *enic = vnic_dev_priv(rq->vdev); - struct sk_buff *skb = buf->os_buf; - - if (skipped) - return; - - pci_unmap_single(enic->pdev, buf->dma_addr, - buf->len, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_any(skb); -} - -static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc, - u8 type, u16 q_number, u16 completed_index, void *opaque) -{ - struct enic *enic = vnic_dev_priv(vdev); - - vnic_rq_service(&enic->rq[q_number], cq_desc, - completed_index, VNIC_RQ_RETURN_DESC, - enic_rq_drop_buf, opaque); - - return 0; -} - static int enic_poll(struct napi_struct *napi, int budget) { struct enic *enic = container_of(napi, struct enic, napi); @@ -1304,6 +1276,24 @@ static int enic_request_intr(struct enic *enic) return err; } +static void enic_synchronize_irqs(struct enic *enic) +{ + unsigned int i; + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_INTX: + case VNIC_DEV_INTR_MODE_MSI: + synchronize_irq(enic->pdev->irq); + break; + case VNIC_DEV_INTR_MODE_MSIX: + for (i = 0; i < enic->intr_count; i++) + synchronize_irq(enic->msix_entry[i].vector); + break; + default: + break; + } +} + static int enic_notify_set(struct enic *enic) { int err; @@ -1409,16 +1399,19 @@ static int enic_stop(struct net_device *netdev) unsigned int i; int err; + for (i = 0; i < enic->intr_count; i++) + vnic_intr_mask(&enic->intr[i]); + + enic_synchronize_irqs(enic); + del_timer_sync(&enic->notify_timer); spin_lock(&enic->devcmd_lock); vnic_dev_disable(enic->vdev); spin_unlock(&enic->devcmd_lock); napi_disable(&enic->napi); - netif_stop_queue(netdev); - - for (i = 0; i < enic->intr_count; i++) - vnic_intr_mask(&enic->intr[i]); + netif_carrier_off(netdev); + netif_tx_disable(netdev); for (i = 0; i < enic->wq_count; i++) { err = vnic_wq_disable(&enic->wq[i]); @@ -1436,11 +1429,6 @@ static int enic_stop(struct net_device *netdev) spin_unlock(&enic->devcmd_lock); enic_free_intr(enic); - (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ], - -1, enic_rq_service_drop, NULL); - (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ], - -1, enic_wq_service, NULL); - for (i = 0; i < enic->wq_count; i++) vnic_wq_clean(&enic->wq[i], enic_free_wq_buf); for (i = 0; i < enic->rq_count; i++) diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index 9a53604edce6..f79a722b6a03 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -61,6 +61,7 @@ static inline void vnic_intr_unmask(struct vnic_intr *intr) static inline void vnic_intr_mask(struct vnic_intr *intr) { iowrite32(1, &intr->ctrl->mask); + (void)ioread32(&intr->ctrl->mask); } static inline void vnic_intr_return_credits(struct vnic_intr *intr, -- GitLab From 2d6ddced5c99cf79c06b9b6ec1366ab63b970ea9 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:38 +0000 Subject: [PATCH 0170/3892] enic: Bug fix: try harder to fill Rx ring on skb allocation failures During dev->open(), make sure we get at least one skb on the Rx ring. Otherwise abort the interface load. Also, if we get skb allocation failures in NAPI poll while trying to replenish the ring, try again later so we don't end up starving out the Rx ring completely. Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 54 ++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index b4a11befb3b3..452a6b747e3e 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1091,6 +1091,7 @@ static int enic_poll(struct napi_struct *napi, int budget) unsigned int rq_work_to_do = budget; unsigned int wq_work_to_do = -1; /* no limit */ unsigned int work_done, rq_work_done, wq_work_done; + int err; /* Service RQ (first) and WQ */ @@ -1114,16 +1115,19 @@ static int enic_poll(struct napi_struct *napi, int budget) 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - if (rq_work_done > 0) { + err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); - /* Replenish RQ - */ + /* Buffer allocation failed. Stay in polling + * mode so we can try to fill the ring again. + */ - vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); + if (err) + rq_work_done = rq_work_to_do; - } else { + if (rq_work_done < rq_work_to_do) { - /* If no work done, flush all LROs and exit polling + /* Some work done, but not enough to stay in polling, + * flush all LROs and exit polling */ if (netdev->features & NETIF_F_LRO) @@ -1142,6 +1146,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) struct net_device *netdev = enic->netdev; unsigned int work_to_do = budget; unsigned int work_done; + int err; /* Service RQ */ @@ -1149,25 +1154,30 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ], work_to_do, enic_rq_service, NULL); - if (work_done > 0) { - - /* Replenish RQ - */ - - vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); - - /* Return intr event credits for this polling - * cycle. An intr event is the completion of a - * RQ packet. - */ + /* Return intr event credits for this polling + * cycle. An intr event is the completion of a + * RQ packet. + */ + if (work_done > 0) vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ], work_done, 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - } else { - /* If no work done, flush all LROs and exit polling + err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); + + /* Buffer allocation failed. Stay in polling mode + * so we can try to fill the ring again. + */ + + if (err) + work_done = work_to_do; + + if (work_done < work_to_do) { + + /* Some work done, but not enough to stay in polling, + * flush all LROs and exit polling */ if (netdev->features & NETIF_F_LRO) @@ -1350,11 +1360,13 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->rq_count; i++) { - err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf); - if (err) { + vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf); + /* Need at least one buffer on ring to get going */ + if (vnic_rq_desc_used(&enic->rq[i]) == 0) { printk(KERN_ERR PFX "%s: Unable to alloc receive buffers.\n", netdev->name); + err = -ENOMEM; goto err_out_notify_unset; } } -- GitLab From 9959a18556c73ebf2936b8df183ea7b41f38d933 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:43 +0000 Subject: [PATCH 0171/3892] enic: minimize pkt filter updates to firmware In set_multicast(), only push pkt filter changes down to firmware if pkt filter actually changes. Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 1 + drivers/net/enic/enic_main.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 8dd0105a8d9c..b090d65ad0c8 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -89,6 +89,7 @@ struct enic { spinlock_t devcmd_lock; u8 mac_addr[ETH_ALEN]; u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; + unsigned int flags; unsigned int mc_count; int csum_rx_enabled; u32 port_mtu; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 452a6b747e3e..019b1480cc0c 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -771,6 +771,7 @@ static void enic_set_multicast_list(struct net_device *netdev) int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; int allmulti = (netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); + unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; unsigned int mc_count = netdev->mc_count; unsigned int i, j; @@ -780,8 +781,11 @@ static void enic_set_multicast_list(struct net_device *netdev) spin_lock(&enic->devcmd_lock); - vnic_dev_packet_filter(enic->vdev, directed, - multicast, broadcast, promisc, allmulti); + if (enic->flags != flags) { + enic->flags = flags; + vnic_dev_packet_filter(enic->vdev, directed, + multicast, broadcast, promisc, allmulti); + } /* Is there an easier way? Trying to minimize to * calls to add/del multicast addrs. We keep the -- GitLab From bd2496229e702b2eb50eab5589858a3cdb7847b2 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:48 +0000 Subject: [PATCH 0172/3892] enic: Bug fix: align desc ring sizes to 32 descs Previous driver was aligning ring sizes to 16 descs, but hardware actually wants desc ring sizes to be aligned to 32 descs. Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 32111144efc9..a605da1475c6 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -74,13 +74,13 @@ int enic_get_vnic_config(struct enic *enic) min_t(u32, ENIC_MAX_WQ_DESCS, max_t(u32, ENIC_MIN_WQ_DESCS, c->wq_desc_count)); - c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */ + c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */ c->rq_desc_count = min_t(u32, ENIC_MAX_RQ_DESCS, max_t(u32, ENIC_MIN_RQ_DESCS, c->rq_desc_count)); - c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */ + c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */ if (c->mtu == 0) c->mtu = 1500; -- GitLab From 7c8445991172cc17eaca9f7de0a300c02caaa49d Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:54 +0000 Subject: [PATCH 0173/3892] enic: feature add: add ethtool -c/C support Only rx_usec and tx_usec options for ethtool -C are settable as those are the only settings that make sense to HW. Adds driver reporting of intr coalescing timer value in usec units rather than HW units. Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 2 ++ drivers/net/enic/enic_main.c | 63 +++++++++++++++++++++++++++++++++++- drivers/net/enic/enic_res.c | 12 ++++--- drivers/net/enic/vnic_enet.h | 5 +++ drivers/net/enic/vnic_intr.c | 8 ++++- drivers/net/enic/vnic_intr.h | 2 ++ 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index b090d65ad0c8..ee01f5a6d0d4 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -93,6 +93,8 @@ struct enic { unsigned int mc_count; int csum_rx_enabled; u32 port_mtu; + u32 rx_coalesce_usecs; + u32 tx_coalesce_usecs; /* work queue cache line section */ ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 019b1480cc0c..e56f41672b37 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value) enic->msg_enable = value; } +static int enic_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ecmd) +{ + struct enic *enic = netdev_priv(netdev); + + ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; + ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; + + return 0; +} + +static int enic_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ecmd) +{ + struct enic *enic = netdev_priv(netdev); + u32 tx_coalesce_usecs; + u32 rx_coalesce_usecs; + + tx_coalesce_usecs = min_t(u32, + INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), + ecmd->tx_coalesce_usecs); + rx_coalesce_usecs = min_t(u32, + INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), + ecmd->rx_coalesce_usecs); + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_INTX: + if (tx_coalesce_usecs != rx_coalesce_usecs) + return -EINVAL; + + vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ], + INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); + break; + case VNIC_DEV_INTR_MODE_MSI: + if (tx_coalesce_usecs != rx_coalesce_usecs) + return -EINVAL; + + vnic_intr_coalescing_timer_set(&enic->intr[0], + INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); + break; + case VNIC_DEV_INTR_MODE_MSIX: + vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ], + INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); + vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ], + INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs)); + break; + default: + break; + } + + enic->tx_coalesce_usecs = tx_coalesce_usecs; + enic->rx_coalesce_usecs = rx_coalesce_usecs; + + return 0; +} + static const struct ethtool_ops enic_ethtool_ops = { .get_settings = enic_get_settings, .get_drvinfo = enic_get_drvinfo, @@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = enic_set_tso, + .get_coalesce = enic_get_coalesce, + .set_coalesce = enic_set_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = ethtool_op_set_flags, }; @@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic) u32 mtu = vnic_dev_mtu(enic->vdev); if (mtu && mtu != enic->port_mtu) { + enic->port_mtu = mtu; if (mtu < enic->netdev->mtu) printk(KERN_WARNING PFX "%s: interface MTU (%d) set higher " "than switch port MTU (%d)\n", enic->netdev->name, enic->netdev->mtu, mtu); - enic->port_mtu = mtu; } } @@ -1990,6 +2048,9 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_dev_deinit; } + enic->tx_coalesce_usecs = enic->config.intr_timer_usec; + enic->rx_coalesce_usecs = enic->tx_coalesce_usecs; + netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index a605da1475c6..02839bf0fe8b 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -66,9 +66,9 @@ int enic_get_vnic_config(struct enic *enic) GET_CONFIG(wq_desc_count); GET_CONFIG(rq_desc_count); GET_CONFIG(mtu); - GET_CONFIG(intr_timer); GET_CONFIG(intr_timer_type); GET_CONFIG(intr_mode); + GET_CONFIG(intr_timer_usec); c->wq_desc_count = min_t(u32, ENIC_MAX_WQ_DESCS, @@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic) max_t(u16, ENIC_MIN_MTU, c->mtu)); - c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); + c->intr_timer_usec = min_t(u32, + INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), + c->intr_timer_usec); printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", enic->mac_addr, c->wq_desc_count, c->rq_desc_count); printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " - "intr timer %d\n", + "intr timer %d usec\n", c->mtu, ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO), - ENIC_SETTING(enic, LRO), c->intr_timer); + ENIC_SETTING(enic, LRO), c->intr_timer_usec); return 0; } @@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic) for (i = 0; i < enic->intr_count; i++) { vnic_intr_init(&enic->intr[i], - enic->config.intr_timer, + INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec), enic->config.intr_timer_type, mask_on_assertion); } diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h index 6332ac9391b8..8eeb6758491b 100644 --- a/drivers/net/enic/vnic_enet.h +++ b/drivers/net/enic/vnic_enet.h @@ -20,6 +20,10 @@ #ifndef _VNIC_ENIC_H_ #define _VNIC_ENIC_H_ +/* Hardware intr coalesce timer is in units of 1.5us */ +#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3) +#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2) + /* Device-specific region: enet configuration */ struct vnic_enet_config { u32 flags; @@ -30,6 +34,7 @@ struct vnic_enet_config { u8 intr_timer_type; u8 intr_mode; char devname[16]; + u32 intr_timer_usec; }; #define VENETF_TSO 0x1 /* TSO enabled */ diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c index 1f8786d7195e..3934309a9498 100644 --- a/drivers/net/enic/vnic_intr.c +++ b/drivers/net/enic/vnic_intr.c @@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, unsigned int coalescing_type, unsigned int mask_on_assertion) { - iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); + vnic_intr_coalescing_timer_set(intr, coalescing_timer); iowrite32(coalescing_type, &intr->ctrl->coalescing_type); iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); iowrite32(0, &intr->ctrl->int_credits); } +void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, + unsigned int coalescing_timer) +{ + iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); +} + void vnic_intr_clean(struct vnic_intr *intr) { iowrite32(0, &intr->ctrl->int_credits); diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index f79a722b6a03..2fe6c6339e3c 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -102,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, unsigned int index); void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, unsigned int coalescing_type, unsigned int mask_on_assertion); +void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, + unsigned int coalescing_timer); void vnic_intr_clean(struct vnic_intr *intr); #endif /* _VNIC_INTR_H_ */ -- GitLab From d87fd25d5ac4cd044e21b749a8f6cac90f093c71 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 23 Dec 2009 13:27:59 +0000 Subject: [PATCH 0174/3892] enic: whitespace cleanup; #define cleanup; more verbose err msg Some misc changes to cleanup whitespace issues and fix/remove some #define HW defintions. 1) fix some whitespace issues 2) more verbose err msg when resources aren't available to configure vnic 3) remove unused #define 4) fix RSS #define rss hash types Signed-off-by: Vasanthy Kolluri Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 5 +++-- drivers/net/enic/vnic_dev.c | 1 - drivers/net/enic/vnic_nic.h | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e56f41672b37..d87935ad1130 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -731,7 +731,7 @@ static inline void enic_queue_wq_skb(struct enic *enic, /* netif_tx_lock held, process context with BHs disabled, or BH */ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, - struct net_device *netdev) + struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); struct vnic_wq *wq = &enic->wq[0]; @@ -1824,7 +1824,8 @@ int enic_dev_init(struct enic *enic) err = enic_set_intr_mode(enic); if (err) { printk(KERN_ERR PFX - "Failed to set intr mode, aborting.\n"); + "Failed to set intr mode based on resource " + "counts and system capabilities, aborting.\n"); return err; } diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 29a48e8b59d3..69b9b70c7da0 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -36,7 +36,6 @@ struct vnic_res { }; #define VNIC_DEV_CAP_INIT 0x0001 -#define VNIC_DEV_CAP_PERBI 0x0002 struct vnic_dev { void *priv; diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h index eeaf329945d8..cf80ab46d582 100644 --- a/drivers/net/enic/vnic_nic.h +++ b/drivers/net/enic/vnic_nic.h @@ -41,12 +41,12 @@ #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 -#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 0) -#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 1) -#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 2) -#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 3) -#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 4) -#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 5) +#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 1) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 2) +#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 3) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 4) +#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 5) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 6) static inline void vnic_set_nic_cfg(u32 *nic_cfg, u8 rss_default_cpu, u8 rss_hash_type, -- GitLab From 44eba3e82b35ae796826a65d8040001582adc10a Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 23 Dec 2009 18:02:41 +0100 Subject: [PATCH 0175/3892] ALSA: jazz16: refine dma and irq selection Narrow the dma and irq selection after the DOS driver. Add ALSA configuration description as well. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 15 +++++++++++++ sound/isa/sb/jazz16.c | 21 ++++++++++++++++++- sound/isa/sb/sb8_main.c | 3 ++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7a0a4a9dc18d..c540637eb16a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1123,6 +1123,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards, autoprobe and ISA PnP. + Module snd-jazz16 + ------------------- + + Module for Media Vision Jazz16 chipset. The chipset consists of 3 chips: + MVD1216 + MVA416 + MVA514. + + port - port # for SB DSP chip (0x210,0x220,0x230,0x240,0x250,0x260) + irq - IRQ # for SB DSP chip (3,5,7,9,10,15) + dma8 - DMA # for SB DSP chip (1,3) + dma16 - DMA # for SB DSP chip (5,7) + mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330) + mpu_irq - MPU-401 irq # (2,3,5,7) + + This module supports multiple cards. + Module snd-korg1212 ------------------- diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index d52966b75846..8d21a3feda3a 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -189,10 +189,29 @@ static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR "please specify port\n"); return 0; + } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) { + snd_printk(KERN_ERR "incorrect port specified\n"); + return 0; + } + if (dma8[dev] != SNDRV_AUTO_DMA && + dma8[dev] != 1 && dma8[dev] != 3) { + snd_printk(KERN_ERR "dma8 must be 1 or 3\n"); + return 0; } if (dma16[dev] != SNDRV_AUTO_DMA && dma16[dev] != 5 && dma16[dev] != 7) { - snd_printk(KERN_ERR "dma16 must be 5 or 7"); + snd_printk(KERN_ERR "dma16 must be 5 or 7\n"); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x030) != 0x300) { + snd_printk(KERN_ERR "incorrect mpu_port specified\n"); + return 0; + } + if (mpu_irq[dev] != SNDRV_AUTO_DMA && + mpu_irq[dev] != 2 && mpu_irq[dev] != 3 && + mpu_irq[dev] != 5 && mpu_irq[dev] != 7) { + snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n"); return 0; } return 1; diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 3222aed5fac6..7d84c9f34dc9 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -510,7 +510,8 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) } switch (chip->hardware) { case SB_HW_JAZZ16: - runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (chip->dma16 == 5 || chip->dma16 == 7) + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; runtime->hw.rate_min = 4000; runtime->hw.rate_max = 50000; -- GitLab From f83d664eef180478c2dc0a0099e9d7bc1c8177ff Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 25 Dec 2009 16:35:43 -0800 Subject: [PATCH 0176/3892] wireless: fix comments in genregdb.awk Apparently some awk versions choke on C-style comments -- who knew? :-) Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/wireless/genregdb.awk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 8316cf075ce9..3cc9e69880a8 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -26,11 +26,11 @@ BEGIN { } /^[ \t]*#/ { - /* Ignore */ + # Ignore } !active && /^[ \t]*$/ { - /* Ignore */ + # Ignore } !active && /country/ { -- GitLab From 043958e602ac2cbf918c0dab1e4e2a7f9751ebf6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 26 Dec 2009 10:36:12 +0100 Subject: [PATCH 0177/3892] ALSA: hda - Add more hints for GPIO setup of IDT/STAC codecs gpio_led, gpio_led_polarity and gpio_mute are added now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 247be19e17b8..69dd5a4e52f2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4184,9 +4184,23 @@ static void stac_store_hints(struct hda_codec *codec) p = snd_hda_get_hint(codec, "eapd_mask"); if (p) spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask; + p = snd_hda_get_hint(codec, "gpio_mute"); + if (p) + spec->gpio_mute = simple_strtoul(p, NULL, 0) & spec->gpio_mask; val = snd_hda_get_bool_hint(codec, "eapd_switch"); if (val >= 0) spec->eapd_switch = val; + p = snd_hda_get_hint(codec, "gpio_led_polarity"); + if (p) + spec->gpio_led_polarity = simple_strtoul(p, NULL, 0); + p = snd_hda_get_hint(codec, "gpio_led"); + if (p) { + spec->gpio_led = simple_strtoul(p, NULL, 0); + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + if (spec->gpio_led_polarity) + spec->gpio_data |= spec->gpio_led; + } } static int stac92xx_init(struct hda_codec *codec) -- GitLab From bf9ae5386bca8836c16e69ab8fdbe46767d7452a Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:50:59 +0000 Subject: [PATCH 0178/3892] llc: use dev_hard_header Using dev_hard_header allows us to use LLC with VLANs and potentially other Ethernet/TokernRing specific encapsulations. It also removes code duplication between LLC and Ethernet/TokenRing core code. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- drivers/net/myri_sbus.c | 6 +++--- net/8021q/vlan_dev.c | 7 +++---- net/ethernet/eth.c | 6 +++--- net/llc/llc_output.c | 45 ++++++++--------------------------------- 4 files changed, 17 insertions(+), 47 deletions(-) diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index b3513ad3b703..8b4313085359 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -716,10 +716,10 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, pad[0] = MYRI_PAD_LEN; pad[1] = 0xab; - /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length - * in here instead. It is up to the 802.2 layer to carry protocol information. + /* Set the protocol type. For a packet of type ETH_P_802_3/2 we put the + * length in here instead. */ - if (type != ETH_P_802_3) + if (type != ETH_P_802_3 && type != ETH_P_802_2) eth->h_proto = htons(type); else eth->h_proto = htons(len); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index b7889782047e..77a49ffdd0ef 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -263,11 +263,10 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, vhdr->h_vlan_TCI = htons(vlan_tci); /* - * Set the protocol type. For a packet of type ETH_P_802_3 we - * put the length in here instead. It is up to the 802.2 - * layer to carry protocol information. + * Set the protocol type. For a packet of type ETH_P_802_3/2 we + * put the length in here instead. */ - if (type != ETH_P_802_3) + if (type != ETH_P_802_3 && type != ETH_P_802_2) vhdr->h_vlan_encapsulated_proto = htons(type); else vhdr->h_vlan_encapsulated_proto = htons(len); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index dd3db88f8f0a..205a1c12f3c0 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -73,8 +73,8 @@ __setup("ether=", netdev_boot_setup); * @len: packet length (<= skb->len) * * - * Set the protocol type. For a packet of type ETH_P_802_3 we put the length - * in here instead. It is up to the 802.2 layer to carry protocol information. + * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length + * in here instead. */ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, @@ -82,7 +82,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, { struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); - if (type != ETH_P_802_3) + if (type != ETH_P_802_3 && type != ETH_P_802_2) eth->h_proto = htons(type); else eth->h_proto = htons(len); diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c index 754f4fedc852..b38a1079a98e 100644 --- a/net/llc/llc_output.c +++ b/net/llc/llc_output.c @@ -33,48 +33,19 @@ int llc_mac_hdr_init(struct sk_buff *skb, const unsigned char *sa, const unsigned char *da) { - int rc = 0; + int rc = -EINVAL; switch (skb->dev->type) { -#ifdef CONFIG_TR - case ARPHRD_IEEE802_TR: { - struct net_device *dev = skb->dev; - struct trh_hdr *trh; - - skb_push(skb, sizeof(*trh)); - skb_reset_mac_header(skb); - trh = tr_hdr(skb); - trh->ac = AC; - trh->fc = LLC_FRAME; - if (sa) - memcpy(trh->saddr, sa, dev->addr_len); - else - memset(trh->saddr, 0, dev->addr_len); - if (da) { - memcpy(trh->daddr, da, dev->addr_len); - tr_source_route(skb, trh, dev); - skb_reset_mac_header(skb); - } - break; - } -#endif + case ARPHRD_IEEE802_TR: case ARPHRD_ETHER: - case ARPHRD_LOOPBACK: { - unsigned short len = skb->len; - struct ethhdr *eth; - - skb_push(skb, sizeof(*eth)); - skb_reset_mac_header(skb); - eth = eth_hdr(skb); - eth->h_proto = htons(len); - memcpy(eth->h_dest, da, ETH_ALEN); - memcpy(eth->h_source, sa, ETH_ALEN); + case ARPHRD_LOOPBACK: + rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa, + skb->len); + if (rc > 0) + rc = 0; break; - } default: - printk(KERN_WARNING "device type not supported: %d\n", - skb->dev->type); - rc = -EINVAL; + WARN(1, "device type not supported: %d\n", skb->dev->type); } return rc; } -- GitLab From e5cd6fe391aa8c93560bb7ffdfe334cf4d0a02e4 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:00 +0000 Subject: [PATCH 0179/3892] llc: add support for LLC_OPT_PKTINFO Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/linux/llc.h | 7 +++++++ include/net/llc_conn.h | 1 + net/llc/af_llc.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/include/linux/llc.h b/include/linux/llc.h index 7733585603f1..ad7074ba81af 100644 --- a/include/linux/llc.h +++ b/include/linux/llc.h @@ -36,6 +36,7 @@ enum llc_sockopts { LLC_OPT_BUSY_TMR_EXP, /* busy state expire time (secs). */ LLC_OPT_TX_WIN, /* tx window size. */ LLC_OPT_RX_WIN, /* rx window size. */ + LLC_OPT_PKTINFO, /* ancillary packet information. */ LLC_OPT_MAX }; @@ -70,6 +71,12 @@ enum llc_sockopts { #define LLC_SAP_RM 0xD4 /* Resource Management */ #define LLC_SAP_GLOBAL 0xFF /* Global SAP. */ +struct llc_pktinfo { + int lpi_ifindex; + unsigned char lpi_sap; + unsigned char lpi_mac[IFHWADDRLEN]; +}; + #ifdef __KERNEL__ #define LLC_SAP_DYN_START 0xC0 #define LLC_SAP_DYN_STOP 0xDE diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index e2374e34989f..fe982fd94c4a 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -76,6 +76,7 @@ struct llc_sock { u32 rx_pdu_hdr; /* used for saving header of last pdu received and caused sending FRMR. Used for resending FRMR */ + u32 cmsg_flags; }; static inline struct llc_sock *llc_sk(const struct sock *sk) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 3a66546cad06..ac691fe08076 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -47,6 +47,10 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout); #define dprintk(args...) #endif +/* Maybe we'll add some more in the future. */ +#define LLC_CMSG_PKTINFO 1 + + /** * llc_ui_next_link_no - return the next unused link number for a sap * @sap: Address of sap to get link number from. @@ -591,6 +595,20 @@ static int llc_wait_data(struct sock *sk, long timeo) return rc; } +static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb) +{ + struct llc_sock *llc = llc_sk(skb->sk); + + if (llc->cmsg_flags & LLC_CMSG_PKTINFO) { + struct llc_pktinfo info; + + info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex; + llc_pdu_decode_dsap(skb, &info.lpi_sap); + llc_pdu_decode_da(skb, info.lpi_mac); + put_cmsg(msg, SOL_LLC, LLC_OPT_PKTINFO, sizeof(info), &info); + } +} + /** * llc_ui_accept - accept a new incoming connection. * @sock: Socket which connections arrive on. @@ -812,6 +830,8 @@ copy_uaddr: memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); } + if (llc_sk(sk)->cmsg_flags) + llc_cmsg_rcv(msg, skb); goto out; } @@ -1030,6 +1050,12 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, goto out; llc->rw = opt; break; + case LLC_OPT_PKTINFO: + if (opt) + llc->cmsg_flags |= LLC_CMSG_PKTINFO; + else + llc->cmsg_flags &= ~LLC_CMSG_PKTINFO; + break; default: rc = -ENOPROTOOPT; goto out; @@ -1083,6 +1109,9 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, val = llc->k; break; case LLC_OPT_RX_WIN: val = llc->rw; break; + case LLC_OPT_PKTINFO: + val = (llc->cmsg_flags & LLC_CMSG_PKTINFO) != 0; + break; default: rc = -ENOPROTOOPT; goto out; -- GitLab From abf9d537fea225af60762640361af7fb233b3103 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:01 +0000 Subject: [PATCH 0180/3892] llc: add support for SO_BINDTODEVICE Using bind(MAC address) with LLC sockets has O(n) complexity, where n is the number of interfaces. To overcome this, we add support for SO_BINDTODEVICE which drops the complexity to O(1). Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/llc/af_llc.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index ac691fe08076..c4d1a1da813c 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -259,7 +259,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) if (!sock_flag(sk, SOCK_ZAPPED)) goto out; rc = -ENODEV; - llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); + if (sk->sk_bound_dev_if) { + llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + if (llc->dev && addr->sllc_arphrd != llc->dev->type) { + dev_put(llc->dev); + llc->dev = NULL; + } + } else + llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); if (!llc->dev) goto out; rc = -EUSERS; @@ -310,7 +317,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out; rc = -ENODEV; rtnl_lock(); - llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); + if (sk->sk_bound_dev_if) { + llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + if (llc->dev) { + if (!addr->sllc_arphrd) + addr->sllc_arphrd = llc->dev->type; + if (llc_mac_null(addr->sllc_mac)) + memcpy(addr->sllc_mac, llc->dev->dev_addr, + IFHWADDRLEN); + if (addr->sllc_arphrd != llc->dev->type || + !llc_mac_match(addr->sllc_mac, + llc->dev->dev_addr)) { + rc = -EINVAL; + dev_put(llc->dev); + llc->dev = NULL; + } + } + } else + llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, + addr->sllc_mac); rtnl_unlock(); if (!llc->dev) goto out; -- GitLab From b76f5a8427ac2928c07fa4ff2144bb8db072c240 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:02 +0000 Subject: [PATCH 0181/3892] llc: convert the socket list to RCU locking For the reclamation phase we use the SLAB_DESTROY_BY_RCU mechanism, which require some extra checks in the lookup code: a) If the current socket was released, reallocated & inserted in another list it will short circuit the iteration for the current list, thus we need to restart the lookup. b) If the current socket was released, reallocated & inserted in the same list we just need to recheck it matches the look-up criteria and if not we can skip to the next element. In this case there is no need to restart the lookup, since sockets are inserted at the start of the list and the worst that will happen is that we will iterate throught some of the list elements more then once. Note that the /proc and multicast delivery was not yet converted to RCU, it still uses spinlocks for protection. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/llc.h | 7 ++-- net/llc/af_llc.c | 1 + net/llc/llc_conn.c | 93 ++++++++++++++++++++++++++++++---------------- net/llc/llc_core.c | 5 ++- net/llc/llc_proc.c | 22 +++++------ net/llc/llc_sap.c | 66 ++++++++++++++++++++------------ 6 files changed, 123 insertions(+), 71 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index 7940da1606e7..1559cf10e874 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -53,10 +54,8 @@ struct llc_sap { struct net_device *orig_dev); struct llc_addr laddr; struct list_head node; - struct { - rwlock_t lock; - struct hlist_head list; - } sk_list; + spinlock_t sk_lock; + struct hlist_nulls_head sk_list; }; #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c4d1a1da813c..f49f3dd6fbd3 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -140,6 +140,7 @@ static struct proto llc_proto = { .name = "LLC", .owner = THIS_MODULE, .obj_size = sizeof(struct llc_sock), + .slab_flags = SLAB_DESTROY_BY_RCU, }; /** diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index c6bab39b018e..77bb3816655e 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk, return rc; } +static inline bool llc_estab_match(const struct llc_sap *sap, + const struct llc_addr *daddr, + const struct llc_addr *laddr, + const struct sock *sk) +{ + struct llc_sock *llc = llc_sk(sk); + + return llc->laddr.lsap == laddr->lsap && + llc->daddr.lsap == daddr->lsap && + llc_mac_match(llc->laddr.mac, laddr->mac) && + llc_mac_match(llc->daddr.mac, daddr->mac); +} + /** * __llc_lookup_established - Finds connection for the remote/local sap/mac * @sap: SAP @@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap, struct llc_addr *laddr) { struct sock *rc; - struct hlist_node *node; - - read_lock(&sap->sk_list.lock); - sk_for_each(rc, node, &sap->sk_list.list) { - struct llc_sock *llc = llc_sk(rc); - - if (llc->laddr.lsap == laddr->lsap && - llc->daddr.lsap == daddr->lsap && - llc_mac_match(llc->laddr.mac, laddr->mac) && - llc_mac_match(llc->daddr.mac, daddr->mac)) { - sock_hold(rc); + struct hlist_nulls_node *node; + + rcu_read_lock(); +again: + sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + if (llc_estab_match(sap, daddr, laddr, rc)) { + /* Extra checks required by SLAB_DESTROY_BY_RCU */ + if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) + goto again; + if (unlikely(llc_sk(rc)->sap != sap || + !llc_estab_match(sap, daddr, laddr, rc))) { + sock_put(rc); + continue; + } goto found; } } rc = NULL; found: - read_unlock(&sap->sk_list.lock); + rcu_read_unlock(); return rc; } @@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap, return sk; } +static inline bool llc_listener_match(const struct llc_sap *sap, + const struct llc_addr *laddr, + const struct sock *sk) +{ + struct llc_sock *llc = llc_sk(sk); + + return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN && + llc->laddr.lsap == laddr->lsap && + (llc_mac_match(llc->laddr.mac, laddr->mac) || + llc_mac_null(llc->laddr.mac)); +} + /** * llc_lookup_listener - Finds listener for local MAC + SAP * @sap: SAP @@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr) { struct sock *rc; - struct hlist_node *node; - - read_lock(&sap->sk_list.lock); - sk_for_each(rc, node, &sap->sk_list.list) { - struct llc_sock *llc = llc_sk(rc); - - if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && - llc->laddr.lsap == laddr->lsap && - (llc_mac_match(llc->laddr.mac, laddr->mac) || - llc_mac_null(llc->laddr.mac))) { - sock_hold(rc); + struct hlist_nulls_node *node; + + rcu_read_lock(); +again: + sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + if (llc_listener_match(sap, laddr, rc)) { + /* Extra checks required by SLAB_DESTROY_BY_RCU */ + if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) + goto again; + if (unlikely(llc_sk(rc)->sap != sap || + !llc_listener_match(sap, laddr, rc))) { + sock_put(rc); + continue; + } goto found; } } rc = NULL; found: - read_unlock(&sap->sk_list.lock); + rcu_read_unlock(); return rc; } @@ -652,10 +683,10 @@ static int llc_find_offset(int state, int ev_type) void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) { llc_sap_hold(sap); - write_lock_bh(&sap->sk_list.lock); + spin_lock_bh(&sap->sk_lock); llc_sk(sk)->sap = sap; - sk_add_node(sk, &sap->sk_list.list); - write_unlock_bh(&sap->sk_list.lock); + sk_nulls_add_node_rcu(sk, &sap->sk_list); + spin_unlock_bh(&sap->sk_lock); } /** @@ -663,14 +694,14 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) * @sap: SAP * @sk: socket * - * This function removes a connection from sk_list.list of a SAP if + * This function removes a connection from sk_list of a SAP if * the connection was in this list. */ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) { - write_lock_bh(&sap->sk_list.lock); - sk_del_node_init(sk); - write_unlock_bh(&sap->sk_list.lock); + spin_lock_bh(&sap->sk_lock); + sk_nulls_del_node_init_rcu(sk); + spin_unlock_bh(&sap->sk_lock); llc_sap_put(sap); } diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index ff4c0ab96a69..5276b9722077 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -37,7 +37,8 @@ static struct llc_sap *llc_sap_alloc(void) if (sap) { /* sap->laddr.mac - leave as a null, it's filled by bind */ sap->state = LLC_SAP_STATE_ACTIVE; - rwlock_init(&sap->sk_list.lock); + spin_lock_init(&sap->sk_lock); + INIT_HLIST_NULLS_HEAD(&sap->sk_list, 0); atomic_set(&sap->refcnt, 1); } return sap; @@ -142,7 +143,7 @@ out: */ void llc_sap_close(struct llc_sap *sap) { - WARN_ON(!hlist_empty(&sap->sk_list.list)); + WARN_ON(!hlist_nulls_empty(&sap->sk_list)); llc_del_sap(sap); kfree(sap); } diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index be47ac427f6b..6b3d033b3236 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -34,19 +34,19 @@ static struct sock *llc_get_sk_idx(loff_t pos) { struct list_head *sap_entry; struct llc_sap *sap; - struct hlist_node *node; + struct hlist_nulls_node *node; struct sock *sk = NULL; list_for_each(sap_entry, &llc_sap_list) { sap = list_entry(sap_entry, struct llc_sap, node); - read_lock_bh(&sap->sk_list.lock); - sk_for_each(sk, node, &sap->sk_list.list) { + spin_lock_bh(&sap->sk_lock); + sk_nulls_for_each(sk, node, &sap->sk_list) { if (!pos) goto found; --pos; } - read_unlock_bh(&sap->sk_list.lock); + spin_unlock_bh(&sap->sk_lock); } sk = NULL; found: @@ -73,25 +73,25 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) goto out; } sk = v; - next = sk_next(sk); + next = sk_nulls_next(sk); if (next) { sk = next; goto out; } llc = llc_sk(sk); sap = llc->sap; - read_unlock_bh(&sap->sk_list.lock); + spin_unlock_bh(&sap->sk_lock); sk = NULL; for (;;) { if (sap->node.next == &llc_sap_list) break; sap = list_entry(sap->node.next, struct llc_sap, node); - read_lock_bh(&sap->sk_list.lock); - if (!hlist_empty(&sap->sk_list.list)) { - sk = sk_head(&sap->sk_list.list); + spin_lock_bh(&sap->sk_lock); + if (!hlist_nulls_empty(&sap->sk_list)) { + sk = sk_nulls_head(&sap->sk_list); break; } - read_unlock_bh(&sap->sk_list.lock); + spin_unlock_bh(&sap->sk_lock); } out: return sk; @@ -104,7 +104,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v) struct llc_sock *llc = llc_sk(sk); struct llc_sap *sap = llc->sap; - read_unlock_bh(&sap->sk_list.lock); + spin_unlock_bh(&sap->sk_lock); } read_unlock_bh(&llc_sap_list_lock); } diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 008de1fc42ca..39760d013ce2 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb, llc_sap_state_process(sap, skb); } +static inline bool llc_dgram_match(const struct llc_sap *sap, + const struct llc_addr *laddr, + const struct sock *sk) +{ + struct llc_sock *llc = llc_sk(sk); + + return sk->sk_type == SOCK_DGRAM && + llc->laddr.lsap == laddr->lsap && + llc_mac_match(llc->laddr.mac, laddr->mac); +} + /** * llc_lookup_dgram - Finds dgram socket for the local sap/mac * @sap: SAP @@ -309,25 +320,41 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap, const struct llc_addr *laddr) { struct sock *rc; - struct hlist_node *node; - - read_lock_bh(&sap->sk_list.lock); - sk_for_each(rc, node, &sap->sk_list.list) { - struct llc_sock *llc = llc_sk(rc); - - if (rc->sk_type == SOCK_DGRAM && - llc->laddr.lsap == laddr->lsap && - llc_mac_match(llc->laddr.mac, laddr->mac)) { - sock_hold(rc); + struct hlist_nulls_node *node; + + rcu_read_lock_bh(); +again: + sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + if (llc_dgram_match(sap, laddr, rc)) { + /* Extra checks required by SLAB_DESTROY_BY_RCU */ + if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) + goto again; + if (unlikely(llc_sk(rc)->sap != sap || + !llc_dgram_match(sap, laddr, rc))) { + sock_put(rc); + continue; + } goto found; } } rc = NULL; found: - read_unlock_bh(&sap->sk_list.lock); + rcu_read_unlock_bh(); return rc; } +static inline bool llc_mcast_match(const struct llc_sap *sap, + const struct llc_addr *laddr, + const struct sk_buff *skb, + const struct sock *sk) +{ + struct llc_sock *llc = llc_sk(sk); + + return sk->sk_type == SOCK_DGRAM && + llc->laddr.lsap == laddr->lsap && + llc->dev == skb->dev; +} + /** * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. * @sap: SAP @@ -341,20 +368,13 @@ static void llc_sap_mcast(struct llc_sap *sap, struct sk_buff *skb) { struct sock *sk; - struct hlist_node *node; + struct hlist_nulls_node *node; - read_lock_bh(&sap->sk_list.lock); - sk_for_each(sk, node, &sap->sk_list.list) { - struct llc_sock *llc = llc_sk(sk); + spin_lock_bh(&sap->sk_lock); + sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { struct sk_buff *skb1; - if (sk->sk_type != SOCK_DGRAM) - continue; - - if (llc->laddr.lsap != laddr->lsap) - continue; - - if (llc->dev != skb->dev) + if (!llc_mcast_match(sap, laddr, skb, sk)) continue; skb1 = skb_clone(skb, GFP_ATOMIC); @@ -365,7 +385,7 @@ static void llc_sap_mcast(struct llc_sap *sap, llc_sap_rcv(sap, skb1, sk); sock_put(sk); } - read_unlock_bh(&sap->sk_list.lock); + spin_unlock_bh(&sap->sk_lock); } -- GitLab From 0f7b67dd9e1192976f5e5a78934c7a339ff7c45f Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:03 +0000 Subject: [PATCH 0182/3892] llc: optimize multicast delivery Optimize multicast delivery by doing the actual delivery without holding the lock. Based on the same approach used in UDP code. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/llc/llc_sap.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 39760d013ce2..94790e60d072 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -355,6 +355,24 @@ static inline bool llc_mcast_match(const struct llc_sap *sap, llc->dev == skb->dev; } +static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb, + struct sock **stack, int count) +{ + struct sk_buff *skb1; + int i; + + for (i = 0; i < count; i++) { + skb1 = skb_clone(skb, GFP_ATOMIC); + if (!skb1) { + sock_put(stack[i]); + continue; + } + + llc_sap_rcv(sap, skb1, stack[i]); + sock_put(stack[i]); + } +} + /** * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. * @sap: SAP @@ -367,25 +385,27 @@ static void llc_sap_mcast(struct llc_sap *sap, const struct llc_addr *laddr, struct sk_buff *skb) { - struct sock *sk; + int i = 0, count = 256 / sizeof(struct sock *); + struct sock *sk, *stack[count]; struct hlist_nulls_node *node; spin_lock_bh(&sap->sk_lock); sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { - struct sk_buff *skb1; if (!llc_mcast_match(sap, laddr, skb, sk)) continue; - skb1 = skb_clone(skb, GFP_ATOMIC); - if (!skb1) - break; - sock_hold(sk); - llc_sap_rcv(sap, skb1, sk); - sock_put(sk); + if (i < count) + stack[i++] = sk; + else { + llc_do_mcast(sap, skb, stack, i); + i = 0; + } } spin_unlock_bh(&sap->sk_lock); + + llc_do_mcast(sap, skb, stack, i); } -- GitLab From 6d2e3ea284463d5ab34e9cf2a41d0b8627b95d02 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:04 +0000 Subject: [PATCH 0183/3892] llc: use a device based hash table to speed up multicast delivery This patch adds a per SAP device based hash table to solve the multicast delivery scalability issue when we have large number of interfaces and a large number of sockets bound to the same SAP. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/llc.h | 11 +++++++++++ include/net/llc_conn.h | 1 + net/llc/llc_conn.c | 10 +++++++++- net/llc/llc_sap.c | 8 ++++++-- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index 1559cf10e874..dbef5917905b 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -32,6 +32,9 @@ struct llc_addr { #define LLC_SAP_STATE_INACTIVE 1 #define LLC_SAP_STATE_ACTIVE 2 +#define LLC_SK_DEV_HASH_BITS 6 +#define LLC_SK_DEV_HASH_ENTRIES (1<sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES]; +} + + #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ #define LLC_DEST_SAP 1 /* Type 1 goes here */ #define LLC_DEST_CONN 2 /* Type 2 goes here */ diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index fe982fd94c4a..2f97d8ddce92 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -77,6 +77,7 @@ struct llc_sock { received and caused sending FRMR. Used for resending FRMR */ u32 cmsg_flags; + struct hlist_node dev_hash_node; }; static inline struct llc_sock *llc_sk(const struct sock *sk) diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 77bb3816655e..10cdfe2db830 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -682,10 +682,15 @@ static int llc_find_offset(int state, int ev_type) */ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) { + struct llc_sock *llc = llc_sk(sk); + struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex); + llc_sap_hold(sap); - spin_lock_bh(&sap->sk_lock); llc_sk(sk)->sap = sap; + + spin_lock_bh(&sap->sk_lock); sk_nulls_add_node_rcu(sk, &sap->sk_list); + hlist_add_head(&llc->dev_hash_node, dev_hb); spin_unlock_bh(&sap->sk_lock); } @@ -699,8 +704,11 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) */ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) { + struct llc_sock *llc = llc_sk(sk); + spin_lock_bh(&sap->sk_lock); sk_nulls_del_node_init_rcu(sk); + hlist_del(&llc->dev_hash_node); spin_unlock_bh(&sap->sk_lock); llc_sap_put(sap); } diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 94790e60d072..94cb706f6cc4 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -387,10 +387,14 @@ static void llc_sap_mcast(struct llc_sap *sap, { int i = 0, count = 256 / sizeof(struct sock *); struct sock *sk, *stack[count]; - struct hlist_nulls_node *node; + struct hlist_node *node; + struct llc_sock *llc; + struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex); spin_lock_bh(&sap->sk_lock); - sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { + hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) { + + sk = &llc->sk; if (!llc_mcast_match(sap, laddr, skb, sk)) continue; -- GitLab From 52d58aef5ee460fedd7f250f05e79081019f2c79 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:05 +0000 Subject: [PATCH 0184/3892] llc: replace the socket list with a local address based hash For the cases where a lot of interfaces are used in conjunction with a lot of LLC sockets bound to the same SAP, the iteration of the socket list becomes prohibitively expensive. Replacing the list with a a local address based hash significantly improves the bind and listener lookup operations as well as the datagram delivery. Connected sockets delivery is also improved, but this patch does not address the case where we have lots of sockets with the same local address connected to different remote addresses. In order to keep the socket sanity checks alive and fast a socket counter was added to the SAP structure. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/llc.h | 21 +++++++++++++- net/llc/llc_conn.c | 70 +++++++++++++++++++++++++++++++++------------- net/llc/llc_core.c | 6 ++-- net/llc/llc_proc.c | 44 +++++++++++++++++++---------- net/llc/llc_sap.c | 11 +++++++- 5 files changed, 115 insertions(+), 37 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index dbef5917905b..709a9b37e239 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -35,6 +37,9 @@ struct llc_addr { #define LLC_SK_DEV_HASH_BITS 6 #define LLC_SK_DEV_HASH_ENTRIES (1<sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES]; } +static inline +u32 llc_sk_laddr_hashfn(struct llc_sap *sap, const struct llc_addr *laddr) +{ + return hash_32(jhash(laddr->mac, sizeof(laddr->mac), 0), + LLC_SK_LADDR_HASH_BITS); +} + +static inline +struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap, + const struct llc_addr *laddr) +{ + return &sap->sk_laddr_hash[llc_sk_laddr_hashfn(sap, laddr)]; +} #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ #define LLC_DEST_SAP 1 /* Type 1 goes here */ diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 10cdfe2db830..a8dde9b010da 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -498,10 +498,12 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap, { struct sock *rc; struct hlist_nulls_node *node; + int slot = llc_sk_laddr_hashfn(sap, laddr); + struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; rcu_read_lock(); again: - sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_estab_match(sap, daddr, laddr, rc)) { /* Extra checks required by SLAB_DESTROY_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) @@ -515,6 +517,13 @@ again: } } rc = NULL; + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (unlikely(get_nulls_value(node) != slot)) + goto again; found: rcu_read_unlock(); return rc; @@ -540,29 +549,20 @@ static inline bool llc_listener_match(const struct llc_sap *sap, return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN && llc->laddr.lsap == laddr->lsap && - (llc_mac_match(llc->laddr.mac, laddr->mac) || - llc_mac_null(llc->laddr.mac)); + llc_mac_match(llc->laddr.mac, laddr->mac); } -/** - * llc_lookup_listener - Finds listener for local MAC + SAP - * @sap: SAP - * @laddr: address of local LLC (MAC + SAP) - * - * Search connection list of the SAP and finds connection listening on - * local mac, and local sap. Returns pointer for parent socket found, - * %NULL otherwise. - * Caller has to make sure local_bh is disabled. - */ -static struct sock *llc_lookup_listener(struct llc_sap *sap, - struct llc_addr *laddr) +static struct sock *__llc_lookup_listener(struct llc_sap *sap, + struct llc_addr *laddr) { struct sock *rc; struct hlist_nulls_node *node; + int slot = llc_sk_laddr_hashfn(sap, laddr); + struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; rcu_read_lock(); again: - sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_listener_match(sap, laddr, rc)) { /* Extra checks required by SLAB_DESTROY_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) @@ -576,11 +576,40 @@ again: } } rc = NULL; + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (unlikely(get_nulls_value(node) != slot)) + goto again; found: rcu_read_unlock(); return rc; } +/** + * llc_lookup_listener - Finds listener for local MAC + SAP + * @sap: SAP + * @laddr: address of local LLC (MAC + SAP) + * + * Search connection list of the SAP and finds connection listening on + * local mac, and local sap. Returns pointer for parent socket found, + * %NULL otherwise. + * Caller has to make sure local_bh is disabled. + */ +static struct sock *llc_lookup_listener(struct llc_sap *sap, + struct llc_addr *laddr) +{ + static struct llc_addr null_addr; + struct sock *rc = __llc_lookup_listener(sap, laddr); + + if (!rc) + rc = __llc_lookup_listener(sap, &null_addr); + + return rc; +} + static struct sock *__llc_lookup(struct llc_sap *sap, struct llc_addr *daddr, struct llc_addr *laddr) @@ -678,18 +707,20 @@ static int llc_find_offset(int state, int ev_type) * @sap: SAP * @sk: socket * - * This function adds a socket to sk_list of a SAP. + * This function adds a socket to the hash tables of a SAP. */ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) { struct llc_sock *llc = llc_sk(sk); struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex); + struct hlist_nulls_head *laddr_hb = llc_sk_laddr_hash(sap, &llc->laddr); llc_sap_hold(sap); llc_sk(sk)->sap = sap; spin_lock_bh(&sap->sk_lock); - sk_nulls_add_node_rcu(sk, &sap->sk_list); + sap->sk_count++; + sk_nulls_add_node_rcu(sk, laddr_hb); hlist_add_head(&llc->dev_hash_node, dev_hb); spin_unlock_bh(&sap->sk_lock); } @@ -699,7 +730,7 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) * @sap: SAP * @sk: socket * - * This function removes a connection from sk_list of a SAP if + * This function removes a connection from the hash tables of a SAP if * the connection was in this list. */ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) @@ -709,6 +740,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) spin_lock_bh(&sap->sk_lock); sk_nulls_del_node_init_rcu(sk); hlist_del(&llc->dev_hash_node); + sap->sk_count--; spin_unlock_bh(&sap->sk_lock); llc_sap_put(sap); } diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 5276b9722077..0c9ef8bc7655 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -33,12 +33,14 @@ DEFINE_RWLOCK(llc_sap_list_lock); static struct llc_sap *llc_sap_alloc(void) { struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC); + int i; if (sap) { /* sap->laddr.mac - leave as a null, it's filled by bind */ sap->state = LLC_SAP_STATE_ACTIVE; spin_lock_init(&sap->sk_lock); - INIT_HLIST_NULLS_HEAD(&sap->sk_list, 0); + for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) + INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i); atomic_set(&sap->refcnt, 1); } return sap; @@ -143,7 +145,7 @@ out: */ void llc_sap_close(struct llc_sap *sap) { - WARN_ON(!hlist_nulls_empty(&sap->sk_list)); + WARN_ON(sap->sk_count); llc_del_sap(sap); kfree(sap); } diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 6b3d033b3236..09dec6307206 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -34,17 +34,22 @@ static struct sock *llc_get_sk_idx(loff_t pos) { struct list_head *sap_entry; struct llc_sap *sap; - struct hlist_nulls_node *node; struct sock *sk = NULL; + int i; list_for_each(sap_entry, &llc_sap_list) { sap = list_entry(sap_entry, struct llc_sap, node); spin_lock_bh(&sap->sk_lock); - sk_nulls_for_each(sk, node, &sap->sk_list) { - if (!pos) - goto found; - --pos; + for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) { + struct hlist_nulls_head *head = &sap->sk_laddr_hash[i]; + struct hlist_nulls_node *node; + + sk_nulls_for_each(sk, node, head) { + if (!pos) + goto found; /* keep the lock */ + --pos; + } } spin_unlock_bh(&sap->sk_lock); } @@ -61,6 +66,19 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos) return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; } +static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket) +{ + struct hlist_nulls_node *node; + struct sock *sk = NULL; + + while (++bucket < LLC_SK_LADDR_HASH_ENTRIES) + sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket]) + goto out; + +out: + return sk; +} + static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct sock* sk, *next; @@ -80,17 +98,15 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) } llc = llc_sk(sk); sap = llc->sap; + sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr)); + if (sk) + goto out; spin_unlock_bh(&sap->sk_lock); - sk = NULL; - for (;;) { - if (sap->node.next == &llc_sap_list) - break; - sap = list_entry(sap->node.next, struct llc_sap, node); + list_for_each_entry_continue(sap, &llc_sap_list, node) { spin_lock_bh(&sap->sk_lock); - if (!hlist_nulls_empty(&sap->sk_list)) { - sk = sk_nulls_head(&sap->sk_list); - break; - } + sk = laddr_hash_next(sap, -1); + if (sk) + break; /* keep the lock */ spin_unlock_bh(&sap->sk_lock); } out: diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 94cb706f6cc4..ad6e6e1cf22f 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -321,10 +321,12 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap, { struct sock *rc; struct hlist_nulls_node *node; + int slot = llc_sk_laddr_hashfn(sap, laddr); + struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; rcu_read_lock_bh(); again: - sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { + sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_dgram_match(sap, laddr, rc)) { /* Extra checks required by SLAB_DESTROY_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) @@ -338,6 +340,13 @@ again: } } rc = NULL; + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (unlikely(get_nulls_value(node) != slot)) + goto again; found: rcu_read_unlock_bh(); return rc; -- GitLab From 8beb9ab6c2df203e8d68cb1f48cf42604a6bed86 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:06 +0000 Subject: [PATCH 0185/3892] llc: convert llc_sap_list to RCU Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/llc.h | 2 +- net/llc/llc_core.c | 46 ++++++++++++++-------------------------------- net/llc/llc_proc.c | 11 ++++------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index 709a9b37e239..5503b74ab170 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -93,7 +93,7 @@ struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap, #define LLC_DEST_CONN 2 /* Type 2 goes here */ extern struct list_head llc_sap_list; -extern rwlock_t llc_sap_list_lock; +extern spinlock_t llc_sap_list_lock; extern int llc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 0c9ef8bc7655..78167e81dfeb 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -23,7 +23,7 @@ #include LIST_HEAD(llc_sap_list); -DEFINE_RWLOCK(llc_sap_list_lock); +DEFINE_SPINLOCK(llc_sap_list_lock); /** * llc_sap_alloc - allocates and initializes sap. @@ -46,30 +46,6 @@ static struct llc_sap *llc_sap_alloc(void) return sap; } -/** - * llc_add_sap - add sap to station list - * @sap: Address of the sap - * - * Adds a sap to the LLC's station sap list. - */ -static void llc_add_sap(struct llc_sap *sap) -{ - list_add_tail(&sap->node, &llc_sap_list); -} - -/** - * llc_del_sap - del sap from station list - * @sap: Address of the sap - * - * Removes a sap to the LLC's station sap list. - */ -static void llc_del_sap(struct llc_sap *sap) -{ - write_lock_bh(&llc_sap_list_lock); - list_del(&sap->node); - write_unlock_bh(&llc_sap_list_lock); -} - static struct llc_sap *__llc_sap_find(unsigned char sap_value) { struct llc_sap* sap; @@ -93,13 +69,13 @@ out: */ struct llc_sap *llc_sap_find(unsigned char sap_value) { - struct llc_sap* sap; + struct llc_sap *sap; - read_lock_bh(&llc_sap_list_lock); + rcu_read_lock_bh(); sap = __llc_sap_find(sap_value); if (sap) llc_sap_hold(sap); - read_unlock_bh(&llc_sap_list_lock); + rcu_read_unlock_bh(); return sap; } @@ -120,7 +96,7 @@ struct llc_sap *llc_sap_open(unsigned char lsap, { struct llc_sap *sap = NULL; - write_lock_bh(&llc_sap_list_lock); + spin_lock_bh(&llc_sap_list_lock); if (__llc_sap_find(lsap)) /* SAP already exists */ goto out; sap = llc_sap_alloc(); @@ -128,9 +104,9 @@ struct llc_sap *llc_sap_open(unsigned char lsap, goto out; sap->laddr.lsap = lsap; sap->rcv_func = func; - llc_add_sap(sap); + list_add_tail_rcu(&sap->node, &llc_sap_list); out: - write_unlock_bh(&llc_sap_list_lock); + spin_unlock_bh(&llc_sap_list_lock); return sap; } @@ -146,7 +122,13 @@ out: void llc_sap_close(struct llc_sap *sap) { WARN_ON(sap->sk_count); - llc_del_sap(sap); + + spin_lock_bh(&llc_sap_list_lock); + list_del_rcu(&sap->node); + spin_unlock_bh(&llc_sap_list_lock); + + synchronize_rcu(); + kfree(sap); } diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 09dec6307206..7af1ff2d1f19 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -32,14 +32,11 @@ static void llc_ui_format_mac(struct seq_file *seq, u8 *addr) static struct sock *llc_get_sk_idx(loff_t pos) { - struct list_head *sap_entry; struct llc_sap *sap; struct sock *sk = NULL; int i; - list_for_each(sap_entry, &llc_sap_list) { - sap = list_entry(sap_entry, struct llc_sap, node); - + list_for_each_entry_rcu(sap, &llc_sap_list, node) { spin_lock_bh(&sap->sk_lock); for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) { struct hlist_nulls_head *head = &sap->sk_laddr_hash[i]; @@ -62,7 +59,7 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos) { loff_t l = *pos; - read_lock_bh(&llc_sap_list_lock); + rcu_read_lock_bh(); return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; } @@ -102,7 +99,7 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (sk) goto out; spin_unlock_bh(&sap->sk_lock); - list_for_each_entry_continue(sap, &llc_sap_list, node) { + list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) { spin_lock_bh(&sap->sk_lock); sk = laddr_hash_next(sap, -1); if (sk) @@ -122,7 +119,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v) spin_unlock_bh(&sap->sk_lock); } - read_unlock_bh(&llc_sap_list_lock); + rcu_read_unlock_bh(); } static int llc_seq_socket_show(struct seq_file *seq, void *v) -- GitLab From 3100aa9d74db9c6d8d9a3b6421721fc1aef4728f Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 26 Dec 2009 11:51:08 +0000 Subject: [PATCH 0186/3892] llc: fix SAP reference counting w.r.t. socket handling The SAP ref counter gets decremented twice when deleting a socket, although for all but the first socket of a SAP the SAP ref counter was incremented only once. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/llc/af_llc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index f49f3dd6fbd3..e35d907fba2c 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -197,10 +197,8 @@ static int llc_ui_release(struct socket *sock) llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); - if (!sock_flag(sk, SOCK_ZAPPED)) { - llc_sap_put(llc->sap); + if (!sock_flag(sk, SOCK_ZAPPED)) llc_sap_remove_socket(llc->sap, sk); - } release_sock(sk); if (llc->dev) dev_put(llc->dev); @@ -352,7 +350,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) rc = -EBUSY; /* some other network layer is using the sap */ if (!sap) goto out; - llc_sap_hold(sap); } else { struct llc_addr laddr, daddr; struct sock *ask; -- GitLab From 92ee6162c48fab24f0676969f0f147fc12f8f21c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 11:18:59 +0100 Subject: [PATCH 0187/3892] ALSA: hda - Add snd_hda_shutup_pins() helper function Add a common helper function for clearing pin controls before suspend. Use the pincfg array instead of looking through all widget tree. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 19 +++++++++++++++++++ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_sigmatel.c | 12 +----------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b3554df740ff..94ae69f20925 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -899,6 +899,25 @@ static void restore_pincfgs(struct hda_codec *codec) } } +/** + * snd_hda_shutup_pins - Shut up all pins + * @codec: the HDA codec + * + * Clear all pin controls to shup up before suspend for avoiding click noise. + * The controls aren't cached so that they can be resumed properly. + */ +void snd_hda_shutup_pins(struct hda_codec *codec) +{ + int i; + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + /* use read here for syncing after issuing each verb */ + snd_hda_codec_read(codec, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } +} +EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); + static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 0d08ad5bd898..11c4aa8ee996 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -898,6 +898,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, unsigned int cfg); int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg); /* for hwdep */ +void snd_hda_shutup_pins(struct hda_codec *codec); /* * Mixer diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 69dd5a4e52f2..dc1d9f124578 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4385,18 +4385,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec) static void stac92xx_shutup(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i; - hda_nid_t nid; - /* reset each pin before powering down DAC/ADC to avoid click noise */ - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int wid_type = get_wcaps_type(wcaps); - if (wid_type == AC_WID_PIN) - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } + snd_hda_shutup_pins(codec); if (spec->eapd_mask) stac_gpio_set(codec, spec->gpio_mask, -- GitLab From a4e09aa3cf592d9f084ff4ceb216be40c4c265dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 11:22:24 +0100 Subject: [PATCH 0188/3892] ALSA: hda - Fix click noises at suspend/free with Realtek codecs Call snd_hda_shutup_pins() at suspend and free for avoiding click noises. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6361e6b3c9c5..cd6d139b4fd5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3693,6 +3693,11 @@ static int alc_build_pcms(struct hda_codec *codec) return 0; } +static inline void alc_shutup(struct hda_codec *codec) +{ + snd_hda_shutup_pins(codec); +} + static void alc_free_kctls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -3713,6 +3718,7 @@ static void alc_free(struct hda_codec *codec) if (!spec) return; + alc_shutup(codec); alc_free_kctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); @@ -3722,6 +3728,7 @@ static void alc_free(struct hda_codec *codec) static int alc_suspend(struct hda_codec *codec, pm_message_t state) { struct alc_spec *spec = codec->spec; + alc_shutup(codec); if (spec && spec->power_hook) spec->power_hook(codec, 0); return 0; -- GitLab From b82855a0d76ebda1cc14c00040560d77bfa042ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 11:24:56 +0100 Subject: [PATCH 0189/3892] ALSA: hda - Add sanity check for storing the user-defined pin configs Check whether the given NID is a pin widget before storing the user-defined pin configs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 94ae69f20925..d02ea8926e7e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, struct hda_pincfg *pin; unsigned int oldcfg; + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + return -EINVAL; + oldcfg = snd_hda_codec_get_pincfg(codec, nid); pin = look_up_pincfg(codec, list, nid); if (!pin) { -- GitLab From 014c41fce1bd5cec381e70fc6f58fdfc96cdaf69 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 13:53:24 +0100 Subject: [PATCH 0190/3892] ALSA: hda - Use strict_strtoul() Rewrite the codes to use strict_strtoul() instead of simple_strtoul(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_hwdep.c | 7 +++-- sound/pci/hda/patch_sigmatel.c | 48 ++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 40ccb419b6e9..b36919c0d363 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \ { \ struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ struct hda_codec *codec = hwdep->private_data; \ - char *after; \ - codec->type = simple_strtoul(buf, &after, 0); \ + unsigned long val; \ + int err = strict_strtoul(buf, 0, &val); \ + if (err < 0) \ + return err; \ + codec->type = val; \ return count; \ } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index dc1d9f124578..e28c810bc00c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4159,43 +4159,47 @@ static void stac92xx_power_down(struct hda_codec *codec) static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, int enable); +static inline int get_int_hint(struct hda_codec *codec, const char *key, + int *valp) +{ + const char *p; + p = snd_hda_get_hint(codec, key); + if (p) { + unsigned long val; + if (!strict_strtoul(p, 0, &val)) { + *valp = val; + return 1; + } + } + return 0; +} + /* override some hints from the hwdep entry */ static void stac_store_hints(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - const char *p; int val; val = snd_hda_get_bool_hint(codec, "hp_detect"); if (val >= 0) spec->hp_detect = val; - p = snd_hda_get_hint(codec, "gpio_mask"); - if (p) { - spec->gpio_mask = simple_strtoul(p, NULL, 0); + if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { spec->eapd_mask = spec->gpio_dir = spec->gpio_data = spec->gpio_mask; } - p = snd_hda_get_hint(codec, "gpio_dir"); - if (p) - spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask; - p = snd_hda_get_hint(codec, "gpio_data"); - if (p) - spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask; - p = snd_hda_get_hint(codec, "eapd_mask"); - if (p) - spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask; - p = snd_hda_get_hint(codec, "gpio_mute"); - if (p) - spec->gpio_mute = simple_strtoul(p, NULL, 0) & spec->gpio_mask; + if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) + spec->gpio_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) + spec->gpio_dir &= spec->gpio_mask; + if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) + spec->eapd_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) + spec->gpio_mute &= spec->gpio_mask; val = snd_hda_get_bool_hint(codec, "eapd_switch"); if (val >= 0) spec->eapd_switch = val; - p = snd_hda_get_hint(codec, "gpio_led_polarity"); - if (p) - spec->gpio_led_polarity = simple_strtoul(p, NULL, 0); - p = snd_hda_get_hint(codec, "gpio_led"); - if (p) { - spec->gpio_led = simple_strtoul(p, NULL, 0); + get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); + if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { spec->gpio_mask |= spec->gpio_led; spec->gpio_dir |= spec->gpio_led; if (spec->gpio_led_polarity) -- GitLab From 3912f2abc942a002ef611fc973add5e5eadb3432 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Mon, 14 Dec 2009 03:23:56 -0500 Subject: [PATCH 0191/3892] perf: Use format string of printf to align strings Instead of filling whitespaces to do alignment, use printf's format string. This simplifies the code a bit. Signed-off-by: WANG Cong Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <20091214082700.4224.57640.sendpatchset@localhost.localdomain> Signed-off-by: Ingo Molnar --- tools/perf/builtin-help.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 9f810b17c25c..e427d6965e0c 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -286,8 +286,7 @@ void list_common_cmds_help(void) puts(" The most commonly used perf commands are:"); for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - printf(" %s ", common_cmds[i].name); - mput_char(' ', longest - strlen(common_cmds[i].name)); + printf(" %-*s ", longest, common_cmds[i].name); puts(common_cmds[i].help); } } -- GitLab From 06aae590033d1ae3c35b2920ef950cfc603e2a2d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:36:59 -0200 Subject: [PATCH 0192/3892] perf session: Move the event processing routines to session.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for an extra "data_map" file since the routines there operate mainly on a perf_session instance. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 - tools/perf/util/data_map.c | 252 ------------------------------------- tools/perf/util/session.c | 245 ++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 253 deletions(-) delete mode 100644 tools/perf/util/data_map.c diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 652a470b5f74..4172c3b0e4a7 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -423,7 +423,6 @@ LIB_OBJS += util/trace-event-perl.o LIB_OBJS += util/svghelper.o LIB_OBJS += util/sort.o LIB_OBJS += util/hist.o -LIB_OBJS += util/data_map.o LIB_OBJS += util/probe-event.o BUILTIN_OBJS += builtin-annotate.o diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c deleted file mode 100644 index b557b836de3d..000000000000 --- a/tools/perf/util/data_map.c +++ /dev/null @@ -1,252 +0,0 @@ -#include "symbol.h" -#include "util.h" -#include "debug.h" -#include "thread.h" -#include "session.h" - -static int process_event_stub(event_t *event __used, - struct perf_session *session __used) -{ - dump_printf(": unhandled!\n"); - return 0; -} - -static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) -{ - if (!handler->process_sample_event) - handler->process_sample_event = process_event_stub; - if (!handler->process_mmap_event) - handler->process_mmap_event = process_event_stub; - if (!handler->process_comm_event) - handler->process_comm_event = process_event_stub; - if (!handler->process_fork_event) - handler->process_fork_event = process_event_stub; - if (!handler->process_exit_event) - handler->process_exit_event = process_event_stub; - if (!handler->process_lost_event) - handler->process_lost_event = process_event_stub; - if (!handler->process_read_event) - handler->process_read_event = process_event_stub; - if (!handler->process_throttle_event) - handler->process_throttle_event = process_event_stub; - if (!handler->process_unthrottle_event) - handler->process_unthrottle_event = process_event_stub; -} - -static const char *event__name[] = { - [0] = "TOTAL", - [PERF_RECORD_MMAP] = "MMAP", - [PERF_RECORD_LOST] = "LOST", - [PERF_RECORD_COMM] = "COMM", - [PERF_RECORD_EXIT] = "EXIT", - [PERF_RECORD_THROTTLE] = "THROTTLE", - [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", - [PERF_RECORD_FORK] = "FORK", - [PERF_RECORD_READ] = "READ", - [PERF_RECORD_SAMPLE] = "SAMPLE", -}; - -unsigned long event__total[PERF_RECORD_MAX]; - -void event__print_totals(void) -{ - int i; - for (i = 0; i < PERF_RECORD_MAX; ++i) - pr_info("%10s events: %10ld\n", - event__name[i], event__total[i]); -} - -static int process_event(event_t *event, struct perf_session *session, - struct perf_event_ops *ops, - unsigned long offset, unsigned long head) -{ - trace_event(event); - - if (event->header.type < PERF_RECORD_MAX) { - dump_printf("%p [%p]: PERF_RECORD_%s", - (void *)(offset + head), - (void *)(long)(event->header.size), - event__name[event->header.type]); - ++event__total[0]; - ++event__total[event->header.type]; - } - - switch (event->header.type) { - case PERF_RECORD_SAMPLE: - return ops->process_sample_event(event, session); - case PERF_RECORD_MMAP: - return ops->process_mmap_event(event, session); - case PERF_RECORD_COMM: - return ops->process_comm_event(event, session); - case PERF_RECORD_FORK: - return ops->process_fork_event(event, session); - case PERF_RECORD_EXIT: - return ops->process_exit_event(event, session); - case PERF_RECORD_LOST: - return ops->process_lost_event(event, session); - case PERF_RECORD_READ: - return ops->process_read_event(event, session); - case PERF_RECORD_THROTTLE: - return ops->process_throttle_event(event, session); - case PERF_RECORD_UNTHROTTLE: - return ops->process_unthrottle_event(event, session); - default: - ops->total_unknown++; - return -1; - } -} - -int perf_header__read_build_ids(int input, u64 offset, u64 size) -{ - struct build_id_event bev; - char filename[PATH_MAX]; - u64 limit = offset + size; - int err = -1; - - while (offset < limit) { - struct dso *dso; - ssize_t len; - - if (read(input, &bev, sizeof(bev)) != sizeof(bev)) - goto out; - - len = bev.header.size - sizeof(bev); - if (read(input, filename, len) != len) - goto out; - - dso = dsos__findnew(filename); - if (dso != NULL) - dso__set_build_id(dso, &bev.build_id); - - offset += bev.header.size; - } - err = 0; -out: - return err; -} - -static struct thread *perf_session__register_idle_thread(struct perf_session *self) -{ - struct thread *thread = perf_session__findnew(self, 0); - - if (!thread || thread__set_comm(thread, "swapper")) { - pr_err("problem inserting idle task.\n"); - thread = NULL; - } - - return thread; -} - -int perf_session__process_events(struct perf_session *self, - struct perf_event_ops *ops) -{ - int err; - unsigned long head, shift; - unsigned long offset = 0; - size_t page_size; - event_t *event; - uint32_t size; - char *buf; - - if (perf_session__register_idle_thread(self) == NULL) - return -ENOMEM; - - perf_event_ops__fill_defaults(ops); - - page_size = getpagesize(); - - head = self->header.data_offset; - self->sample_type = perf_header__sample_type(&self->header); - - err = -EINVAL; - if (ops->sample_type_check && ops->sample_type_check(self) < 0) - goto out_err; - - if (!ops->full_paths) { - char bf[PATH_MAX]; - - if (getcwd(bf, sizeof(bf)) == NULL) { - err = -errno; -out_getcwd_err: - pr_err("failed to get the current directory\n"); - goto out_err; - } - self->cwd = strdup(bf); - if (self->cwd == NULL) { - err = -ENOMEM; - goto out_getcwd_err; - } - self->cwdlen = strlen(self->cwd); - } - - shift = page_size * (head / page_size); - offset += shift; - head -= shift; - -remap: - buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, - MAP_SHARED, self->fd, offset); - if (buf == MAP_FAILED) { - pr_err("failed to mmap file\n"); - err = -errno; - goto out_err; - } - -more: - event = (event_t *)(buf + head); - - size = event->header.size; - if (!size) - size = 8; - - if (head + event->header.size >= page_size * self->mmap_window) { - int munmap_ret; - - shift = page_size * (head / page_size); - - munmap_ret = munmap(buf, page_size * self->mmap_window); - assert(munmap_ret == 0); - - offset += shift; - head -= shift; - goto remap; - } - - size = event->header.size; - - dump_printf("\n%p [%p]: event: %d\n", - (void *)(offset + head), - (void *)(long)event->header.size, - event->header.type); - - if (!size || process_event(event, self, ops, offset, head) < 0) { - - dump_printf("%p [%p]: skipping unknown header type: %d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.type); - - /* - * assume we lost track of the stream, check alignment, and - * increment a single u64 in the hope to catch on again 'soon'. - */ - - if (unlikely(head & 7)) - head &= ~7ULL; - - size = 8; - } - - head += size; - - if (offset + head >= self->header.data_offset + self->header.data_size) - goto done; - - if (offset + head < self->size) - goto more; - -done: - err = 0; -out_err: - return err; -} diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ce3a6c8abe76..736d4fda9272 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -148,3 +148,248 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, return syms; } + +static int process_event_stub(event_t *event __used, + struct perf_session *session __used) +{ + dump_printf(": unhandled!\n"); + return 0; +} + +static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) +{ + if (handler->process_sample_event == NULL) + handler->process_sample_event = process_event_stub; + if (handler->process_mmap_event == NULL) + handler->process_mmap_event = process_event_stub; + if (handler->process_comm_event == NULL) + handler->process_comm_event = process_event_stub; + if (handler->process_fork_event == NULL) + handler->process_fork_event = process_event_stub; + if (handler->process_exit_event == NULL) + handler->process_exit_event = process_event_stub; + if (handler->process_lost_event == NULL) + handler->process_lost_event = process_event_stub; + if (handler->process_read_event == NULL) + handler->process_read_event = process_event_stub; + if (handler->process_throttle_event == NULL) + handler->process_throttle_event = process_event_stub; + if (handler->process_unthrottle_event == NULL) + handler->process_unthrottle_event = process_event_stub; +} + +static const char *event__name[] = { + [0] = "TOTAL", + [PERF_RECORD_MMAP] = "MMAP", + [PERF_RECORD_LOST] = "LOST", + [PERF_RECORD_COMM] = "COMM", + [PERF_RECORD_EXIT] = "EXIT", + [PERF_RECORD_THROTTLE] = "THROTTLE", + [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", + [PERF_RECORD_FORK] = "FORK", + [PERF_RECORD_READ] = "READ", + [PERF_RECORD_SAMPLE] = "SAMPLE", +}; + +unsigned long event__total[PERF_RECORD_MAX]; + +void event__print_totals(void) +{ + int i; + for (i = 0; i < PERF_RECORD_MAX; ++i) + pr_info("%10s events: %10ld\n", + event__name[i], event__total[i]); +} + +static int perf_session__process_event(struct perf_session *self, + event_t *event, + struct perf_event_ops *ops, + unsigned long offset, unsigned long head) +{ + trace_event(event); + + if (event->header.type < PERF_RECORD_MAX) { + dump_printf("%p [%p]: PERF_RECORD_%s", + (void *)(offset + head), + (void *)(long)(event->header.size), + event__name[event->header.type]); + ++event__total[0]; + ++event__total[event->header.type]; + } + + switch (event->header.type) { + case PERF_RECORD_SAMPLE: + return ops->process_sample_event(event, self); + case PERF_RECORD_MMAP: + return ops->process_mmap_event(event, self); + case PERF_RECORD_COMM: + return ops->process_comm_event(event, self); + case PERF_RECORD_FORK: + return ops->process_fork_event(event, self); + case PERF_RECORD_EXIT: + return ops->process_exit_event(event, self); + case PERF_RECORD_LOST: + return ops->process_lost_event(event, self); + case PERF_RECORD_READ: + return ops->process_read_event(event, self); + case PERF_RECORD_THROTTLE: + return ops->process_throttle_event(event, self); + case PERF_RECORD_UNTHROTTLE: + return ops->process_unthrottle_event(event, self); + default: + ops->total_unknown++; + return -1; + } +} + +int perf_header__read_build_ids(int input, u64 offset, u64 size) +{ + struct build_id_event bev; + char filename[PATH_MAX]; + u64 limit = offset + size; + int err = -1; + + while (offset < limit) { + struct dso *dso; + ssize_t len; + + if (read(input, &bev, sizeof(bev)) != sizeof(bev)) + goto out; + + len = bev.header.size - sizeof(bev); + if (read(input, filename, len) != len) + goto out; + + dso = dsos__findnew(filename); + if (dso != NULL) + dso__set_build_id(dso, &bev.build_id); + + offset += bev.header.size; + } + err = 0; +out: + return err; +} + +static struct thread *perf_session__register_idle_thread(struct perf_session *self) +{ + struct thread *thread = perf_session__findnew(self, 0); + + if (thread == NULL || thread__set_comm(thread, "swapper")) { + pr_err("problem inserting idle task.\n"); + thread = NULL; + } + + return thread; +} + +int perf_session__process_events(struct perf_session *self, + struct perf_event_ops *ops) +{ + int err; + unsigned long head, shift; + unsigned long offset = 0; + size_t page_size; + event_t *event; + uint32_t size; + char *buf; + + if (perf_session__register_idle_thread(self) == NULL) + return -ENOMEM; + + perf_event_ops__fill_defaults(ops); + + page_size = getpagesize(); + + head = self->header.data_offset; + self->sample_type = perf_header__sample_type(&self->header); + + err = -EINVAL; + if (ops->sample_type_check && ops->sample_type_check(self) < 0) + goto out_err; + + if (!ops->full_paths) { + char bf[PATH_MAX]; + + if (getcwd(bf, sizeof(bf)) == NULL) { + err = -errno; +out_getcwd_err: + pr_err("failed to get the current directory\n"); + goto out_err; + } + self->cwd = strdup(bf); + if (self->cwd == NULL) { + err = -ENOMEM; + goto out_getcwd_err; + } + self->cwdlen = strlen(self->cwd); + } + + shift = page_size * (head / page_size); + offset += shift; + head -= shift; + +remap: + buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, + MAP_SHARED, self->fd, offset); + if (buf == MAP_FAILED) { + pr_err("failed to mmap file\n"); + err = -errno; + goto out_err; + } + +more: + event = (event_t *)(buf + head); + + size = event->header.size; + if (size == 0) + size = 8; + + if (head + event->header.size >= page_size * self->mmap_window) { + int munmap_ret; + + shift = page_size * (head / page_size); + + munmap_ret = munmap(buf, page_size * self->mmap_window); + assert(munmap_ret == 0); + + offset += shift; + head -= shift; + goto remap; + } + + size = event->header.size; + + dump_printf("\n%p [%p]: event: %d\n", + (void *)(offset + head), + (void *)(long)event->header.size, + event->header.type); + + if (size == 0 || + perf_session__process_event(self, event, ops, offset, head) < 0) { + dump_printf("%p [%p]: skipping unknown header type: %d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type); + /* + * assume we lost track of the stream, check alignment, and + * increment a single u64 in the hope to catch on again 'soon'. + */ + if (unlikely(head & 7)) + head &= ~7ULL; + + size = 8; + } + + head += size; + + if (offset + head >= self->header.data_offset + self->header.data_size) + goto done; + + if (offset + head < self->size) + goto more; +done: + err = 0; +out_err: + return err; +} -- GitLab From 4a58e61161074776aa34187ea369414ce4852394 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:00 -0200 Subject: [PATCH 0193/3892] perf tools: Move the map class definition to a separate header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And this resulted in the need for adding some missing includes in some places that were getting the definitions needed out of sheer luck. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 + tools/perf/util/debug.c | 1 + tools/perf/util/event.h | 65 ++---------------------------- tools/perf/util/map.h | 73 ++++++++++++++++++++++++++++++++++ tools/perf/util/probe-finder.h | 2 + 5 files changed, 80 insertions(+), 62 deletions(-) create mode 100644 tools/perf/util/map.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 4172c3b0e4a7..fafea0b6f323 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -357,6 +357,7 @@ LIB_H += util/event.h LIB_H += util/exec_cmd.h LIB_H += util/types.h LIB_H += util/levenshtein.h +LIB_H += util/map.h LIB_H += util/parse-options.h LIB_H += util/parse-events.h LIB_H += util/quote.h diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 28d520d5a1fb..0905600c3851 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -9,6 +9,7 @@ #include "color.h" #include "event.h" #include "debug.h" +#include "util.h" int verbose = 0; int dump_trace = 0; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 690a96d0467c..80fb3653c809 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -1,10 +1,10 @@ #ifndef __PERF_RECORD_H #define __PERF_RECORD_H +#include + #include "../perf.h" -#include "util.h" -#include -#include +#include "map.h" /* * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * @@ -101,67 +101,8 @@ struct events_stats { void event__print_totals(void); -enum map_type { - MAP__FUNCTION = 0, - MAP__VARIABLE, -}; - -#define MAP__NR_TYPES (MAP__VARIABLE + 1) - -struct map { - union { - struct rb_node rb_node; - struct list_head node; - }; - u64 start; - u64 end; - enum map_type type; - u64 pgoff; - u64 (*map_ip)(struct map *, u64); - u64 (*unmap_ip)(struct map *, u64); - struct dso *dso; -}; - -static inline u64 map__map_ip(struct map *map, u64 ip) -{ - return ip - map->start + map->pgoff; -} - -static inline u64 map__unmap_ip(struct map *map, u64 ip) -{ - return ip + map->start - map->pgoff; -} - -static inline u64 identity__map_ip(struct map *map __used, u64 ip) -{ - return ip; -} - -struct symbol; - -typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); - -void map__init(struct map *self, enum map_type type, - u64 start, u64 end, u64 pgoff, struct dso *dso); -struct map *map__new(struct mmap_event *event, enum map_type, - char *cwd, int cwdlen); -void map__delete(struct map *self); -struct map *map__clone(struct map *self); -int map__overlap(struct map *l, struct map *r); -size_t map__fprintf(struct map *self, FILE *fp); - struct perf_session; -int map__load(struct map *self, struct perf_session *session, - symbol_filter_t filter); -struct symbol *map__find_symbol(struct map *self, struct perf_session *session, - u64 addr, symbol_filter_t filter); -struct symbol *map__find_symbol_by_name(struct map *self, const char *name, - struct perf_session *session, - symbol_filter_t filter); -void map__fixup_start(struct map *self); -void map__fixup_end(struct map *self); - int event__synthesize_thread(pid_t pid, int (*process)(event_t *event, struct perf_session *session), diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h new file mode 100644 index 000000000000..72f0b6ab5ea5 --- /dev/null +++ b/tools/perf/util/map.h @@ -0,0 +1,73 @@ +#ifndef __PERF_MAP_H +#define __PERF_MAP_H + +#include +#include +#include +#include + +enum map_type { + MAP__FUNCTION = 0, + MAP__VARIABLE, +}; + +#define MAP__NR_TYPES (MAP__VARIABLE + 1) + +struct dso; + +struct map { + union { + struct rb_node rb_node; + struct list_head node; + }; + u64 start; + u64 end; + enum map_type type; + u64 pgoff; + u64 (*map_ip)(struct map *, u64); + u64 (*unmap_ip)(struct map *, u64); + struct dso *dso; +}; + +static inline u64 map__map_ip(struct map *map, u64 ip) +{ + return ip - map->start + map->pgoff; +} + +static inline u64 map__unmap_ip(struct map *map, u64 ip) +{ + return ip + map->start - map->pgoff; +} + +static inline u64 identity__map_ip(struct map *map __used, u64 ip) +{ + return ip; +} + +struct symbol; +struct mmap_event; + +typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); + +void map__init(struct map *self, enum map_type type, + u64 start, u64 end, u64 pgoff, struct dso *dso); +struct map *map__new(struct mmap_event *event, enum map_type, + char *cwd, int cwdlen); +void map__delete(struct map *self); +struct map *map__clone(struct map *self); +int map__overlap(struct map *l, struct map *r); +size_t map__fprintf(struct map *self, FILE *fp); + +struct perf_session; + +int map__load(struct map *self, struct perf_session *session, + symbol_filter_t filter); +struct symbol *map__find_symbol(struct map *self, struct perf_session *session, + u64 addr, symbol_filter_t filter); +struct symbol *map__find_symbol_by_name(struct map *self, const char *name, + struct perf_session *session, + symbol_filter_t filter); +void map__fixup_start(struct map *self); +void map__fixup_end(struct map *self); + +#endif /* __PERF_MAP_H */ diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index a4086aaddb73..e3f396806e6e 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -1,6 +1,8 @@ #ifndef _PROBE_FINDER_H #define _PROBE_FINDER_H +#include "util.h" + #define MAX_PATH_LEN 256 #define MAX_PROBE_BUFFER 1024 #define MAX_PROBES 128 -- GitLab From 27295592c22e71bbd38110c302da8dbb43912a60 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:01 -0200 Subject: [PATCH 0194/3892] perf session: Share the common trace sample_check routine as perf_session__has_traces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-5-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 14 +------------- tools/perf/builtin-sched.c | 14 +------------- tools/perf/builtin-timechart.c | 13 +------------ tools/perf/builtin-trace.c | 14 +------------- tools/perf/util/session.c | 11 +++++++++++ tools/perf/util/session.h | 2 ++ 6 files changed, 17 insertions(+), 51 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index fc21ad79dd83..a85936f09f3e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -342,22 +342,10 @@ static int process_sample_event(event_t *event, struct perf_session *session) return 0; } -static int sample_type_check(struct perf_session *session) -{ - if (!(session->sample_type & PERF_SAMPLE_RAW)) { - fprintf(stderr, - "No trace sample to read. Did you call perf record " - "without -R?"); - return -1; - } - - return 0; -} - static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, - .sample_type_check = sample_type_check, + .sample_type_check = perf_session__has_traces, }; static double fragmentation(unsigned long n_req, unsigned long n_alloc) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 80209df6cfe8..d65098c42990 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1653,23 +1653,11 @@ static int process_lost_event(event_t *event __used, return 0; } -static int sample_type_check(struct perf_session *session __used) -{ - if (!(session->sample_type & PERF_SAMPLE_RAW)) { - fprintf(stderr, - "No trace sample to read. Did you call perf record " - "without -R?"); - return -1; - } - - return 0; -} - static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, .process_lost_event = process_lost_event, - .sample_type_check = sample_type_check, + .sample_type_check = perf_session__has_traces, }; static int read_events(void) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index a589a43112d6..b42f337c17d9 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1029,23 +1029,12 @@ static void process_samples(struct perf_session *session) } } -static int sample_type_check(struct perf_session *session) -{ - if (!(session->sample_type & PERF_SAMPLE_RAW)) { - fprintf(stderr, "No trace samples found in the file.\n" - "Have you used 'perf timechart record' to record it?\n"); - return -1; - } - - return 0; -} - static struct perf_event_ops event_ops = { .process_comm_event = process_comm_event, .process_fork_event = process_fork_event, .process_exit_event = process_exit_event, .process_sample_event = queue_sample_event, - .sample_type_check = sample_type_check, + .sample_type_check = perf_session__has_traces, }; static int __cmd_timechart(void) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 574a215e800b..b0ba2ac37e2c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -103,22 +103,10 @@ static int process_sample_event(event_t *event, struct perf_session *session) return 0; } -static int sample_type_check(struct perf_session *session) -{ - if (!(session->sample_type & PERF_SAMPLE_RAW)) { - fprintf(stderr, - "No trace sample to read. Did you call perf record " - "without -R?"); - return -1; - } - - return 0; -} - static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, - .sample_type_check = sample_type_check, + .sample_type_check = perf_session__has_traces, }; static int __cmd_trace(struct perf_session *session) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 736d4fda9272..60eab8b3ff34 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -393,3 +393,14 @@ done: out_err: return err; } + +int perf_session__has_traces(struct perf_session *self) +{ + if (!(self->sample_type & PERF_SAMPLE_RAW)) { + pr_err("No trace sample to read. Did you call perf record " + "without -R?"); + return -1; + } + + return 0; +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 32eaa1bada06..a6951d2f700f 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -56,6 +56,8 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, struct ip_callchain *chain, struct symbol **parent); +int perf_session__has_traces(struct perf_session *self); + int perf_header__read_build_ids(int input, u64 offset, u64 file_size); #endif /* __PERF_SESSION_H */ -- GitLab From d549c7690190d9739005e19604faad6da4b802ac Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:02 -0200 Subject: [PATCH 0195/3892] perf session: Remove sample_type_check from event_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is really something tools need to do before asking for the events to be processed, leaving perf_session__process_events to do just that, process events. Also add a msg parameter to perf_session__has_traces() so that the right message can be printed, fixing a regression added by me in the previous cset (right timechart message) and also fixing 'perf kmem', that was not asking if 'perf kmem record' was ran. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-6-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 6 ++++-- tools/perf/builtin-report.c | 16 +++++++++------- tools/perf/builtin-sched.c | 7 ++++--- tools/perf/builtin-timechart.c | 6 ++++-- tools/perf/builtin-trace.c | 4 +++- tools/perf/util/session.c | 16 ++++++---------- tools/perf/util/session.h | 3 +-- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index a85936f09f3e..73b065022e27 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -345,7 +345,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, - .sample_type_check = perf_session__has_traces, }; static double fragmentation(unsigned long n_req, unsigned long n_alloc) @@ -492,11 +491,14 @@ static void sort_result(void) static int __cmd_kmem(void) { - int err; + int err = -EINVAL; struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); if (session == NULL) return -ENOMEM; + if (!perf_session__has_traces(session, "kmem record")) + goto out_delete; + setup_pager(); err = perf_session__process_events(session, &event_ops); if (err != 0) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index db10c0e8ecae..08259184cedb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -156,14 +156,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use return 0; } -static int sample_type_check(struct perf_session *session) +static int perf_session__setup_sample_type(struct perf_session *self) { - if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) { + if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { fprintf(stderr, "selected --sort parent, but no" " callchain data. Did you call" " perf record without -g?\n"); - return -1; + return -EINVAL; } if (symbol_conf.use_callchain) { fprintf(stderr, "selected -g but no callchain data." @@ -176,7 +176,7 @@ static int sample_type_check(struct perf_session *session) if (register_callchain_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" " params\n"); - return -1; + return -EINVAL; } } @@ -191,13 +191,11 @@ static struct perf_event_ops event_ops = { .process_fork_event = event__process_task, .process_lost_event = event__process_lost, .process_read_event = process_read_event, - .sample_type_check = sample_type_check, }; - static int __cmd_report(void) { - int ret; + int ret = -EINVAL; struct perf_session *session; session = perf_session__new(input_name, O_RDONLY, force); @@ -207,6 +205,10 @@ static int __cmd_report(void) if (show_threads) perf_read_values_init(&show_threads_values); + ret = perf_session__setup_sample_type(session); + if (ret) + goto out_delete; + ret = perf_session__process_events(session, &event_ops); if (ret) goto out_delete; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index d65098c42990..e862e71f4e68 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1657,17 +1657,18 @@ static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, .process_lost_event = process_lost_event, - .sample_type_check = perf_session__has_traces, }; static int read_events(void) { - int err; + int err = -EINVAL; struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); if (session == NULL) return -ENOMEM; - err = perf_session__process_events(session, &event_ops); + if (perf_session__has_traces(session, "record -R")) + err = perf_session__process_events(session, &event_ops); + perf_session__delete(session); return err; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index b42f337c17d9..825283794985 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1034,17 +1034,19 @@ static struct perf_event_ops event_ops = { .process_fork_event = process_fork_event, .process_exit_event = process_exit_event, .process_sample_event = queue_sample_event, - .sample_type_check = perf_session__has_traces, }; static int __cmd_timechart(void) { struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); - int ret; + int ret = -EINVAL; if (session == NULL) return -ENOMEM; + if (!perf_session__has_traces(session, "timechart record")) + goto out_delete; + ret = perf_session__process_events(session, &event_ops); if (ret) goto out_delete; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b0ba2ac37e2c..e94f34631585 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -106,7 +106,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) static struct perf_event_ops event_ops = { .process_sample_event = process_sample_event, .process_comm_event = event__process_comm, - .sample_type_check = perf_session__has_traces, }; static int __cmd_trace(struct perf_session *session) @@ -580,6 +579,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) if (session == NULL) return -ENOMEM; + if (!perf_session__has_traces(session, "record -R")) + return -EINVAL; + if (generate_script_lang) { struct stat perf_stat; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 60eab8b3ff34..bc84a5217955 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -73,6 +73,8 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc if (mode == O_RDONLY && perf_session__open(self, force) < 0) goto out_delete; + + self->sample_type = perf_header__sample_type(&self->header); out: return self; out_free: @@ -302,11 +304,6 @@ int perf_session__process_events(struct perf_session *self, page_size = getpagesize(); head = self->header.data_offset; - self->sample_type = perf_header__sample_type(&self->header); - - err = -EINVAL; - if (ops->sample_type_check && ops->sample_type_check(self) < 0) - goto out_err; if (!ops->full_paths) { char bf[PATH_MAX]; @@ -394,13 +391,12 @@ out_err: return err; } -int perf_session__has_traces(struct perf_session *self) +bool perf_session__has_traces(struct perf_session *self, const char *msg) { if (!(self->sample_type & PERF_SAMPLE_RAW)) { - pr_err("No trace sample to read. Did you call perf record " - "without -R?"); - return -1; + pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); + return false; } - return 0; + return true; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index a6951d2f700f..5771ccb3fe03 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -40,7 +40,6 @@ struct perf_event_ops { event_op process_read_event; event_op process_throttle_event; event_op process_unthrottle_event; - int (*sample_type_check)(struct perf_session *session); unsigned long total_unknown; bool full_paths; }; @@ -56,7 +55,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, struct ip_callchain *chain, struct symbol **parent); -int perf_session__has_traces(struct perf_session *self); +bool perf_session__has_traces(struct perf_session *self, const char *msg); int perf_header__read_build_ids(int input, u64 offset, u64 file_size); -- GitLab From 31d337c4ee3152b7271897eae576251643f5a3b5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:03 -0200 Subject: [PATCH 0196/3892] perf session: Move total_unknown to perf_session->unknown events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As this is a session property, not belonging to perf_event_ops, that can be shared by many perf_session instances. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-7-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/session.c | 3 ++- tools/perf/util/session.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index bc84a5217955..4ca427f73994 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -66,6 +66,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc self->mmap_window = 32; self->cwd = NULL; self->cwdlen = 0; + self->unknown_events = 0; map_groups__init(&self->kmaps); if (perf_session__create_kernel_maps(self) < 0) @@ -239,7 +240,7 @@ static int perf_session__process_event(struct perf_session *self, case PERF_RECORD_UNTHROTTLE: return ops->process_unthrottle_event(event, self); default: - ops->total_unknown++; + self->unknown_events++; return -1; } } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5771ccb3fe03..585937b6f9ee 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -20,6 +20,7 @@ struct perf_session { struct thread *last_match; struct events_stats events_stats; unsigned long event_total[PERF_RECORD_MAX]; + unsigned long unknown_events; struct rb_root hists; u64 sample_type; int fd; @@ -40,7 +41,6 @@ struct perf_event_ops { event_op process_read_event; event_op process_throttle_event; event_op process_unthrottle_event; - unsigned long total_unknown; bool full_paths; }; -- GitLab From f7d87444e6ee6f4a19634e5412664c1c529a2370 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:04 -0200 Subject: [PATCH 0197/3892] perf session: Move full_paths config to symbol_conf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now perf_event_ops has just that, event handlers. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-8-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 1 - tools/perf/util/symbol.h | 3 ++- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index bd71b8ceafb7..e164b3d45cd4 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -204,7 +204,7 @@ static const struct option options[] = { OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, + OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, "Don't shorten the pathnames taking into account the cwd"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 08259184cedb..f695084910c0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -321,7 +321,7 @@ static const struct option options[] = { "pretty printing style key: normal raw"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), - OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, + OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, "Don't shorten the pathnames taking into account the cwd"), OPT_STRING('p', "parent", &parent_pattern, "regex", "regex filter to identify parent, see: '--sort parent'"), diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4ca427f73994..4f2eeb584da8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -306,7 +306,7 @@ int perf_session__process_events(struct perf_session *self, head = self->header.data_offset; - if (!ops->full_paths) { + if (!symbol_conf.full_paths) { char bf[PATH_MAX]; if (getcwd(bf, sizeof(bf)) == NULL) { diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 585937b6f9ee..2ff77fea06ef 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -41,7 +41,6 @@ struct perf_event_ops { event_op process_read_event; event_op process_throttle_event; event_op process_unthrottle_event; - bool full_paths; }; struct perf_session *perf_session__new(const char *filename, int mode, bool force); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8aded2356f79..9eabd60f819d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -58,7 +58,8 @@ struct symbol_conf { sort_by_name, show_nr_samples, use_callchain, - exclude_other; + exclude_other, + full_paths; const char *vmlinux_name, *field_sep; char *dso_list_str, -- GitLab From 55aa640f54280da25046acd2075842d464f451e6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:05 -0200 Subject: [PATCH 0198/3892] perf session: Remove redundant prefix & suffix from perf_event_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since now all that we have are perf event handlers, leave just the name of the event. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-9-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 8 ++--- tools/perf/builtin-diff.c | 12 ++++---- tools/perf/builtin-kmem.c | 4 +-- tools/perf/builtin-report.c | 14 ++++----- tools/perf/builtin-sched.c | 6 ++-- tools/perf/builtin-timechart.c | 8 ++--- tools/perf/builtin-trace.c | 4 +-- tools/perf/util/session.c | 54 +++++++++++++++++----------------- tools/perf/util/session.h | 18 ++++++------ 9 files changed, 64 insertions(+), 64 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 593ff25006de..117bbae844bf 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -451,10 +451,10 @@ static void perf_session__find_annotations(struct perf_session *self) } static struct perf_event_ops event_ops = { - .process_sample_event = process_sample_event, - .process_mmap_event = event__process_mmap, - .process_comm_event = event__process_comm, - .process_fork_event = event__process_task, + .sample = process_sample_event, + .mmap = event__process_mmap, + .comm = event__process_comm, + .fork = event__process_task, }; static int __cmd_annotate(void) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e164b3d45cd4..1cbecaf029fa 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -66,12 +66,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi } static struct perf_event_ops event_ops = { - .process_sample_event = diff__process_sample_event, - .process_mmap_event = event__process_mmap, - .process_comm_event = event__process_comm, - .process_exit_event = event__process_task, - .process_fork_event = event__process_task, - .process_lost_event = event__process_lost, + .sample = diff__process_sample_event, + .mmap = event__process_mmap, + .comm = event__process_comm, + .exit = event__process_task, + .fork = event__process_task, + .lost = event__process_lost, }; static void perf_session__insert_hist_entry_by_name(struct rb_root *root, diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 73b065022e27..4c06828fe39d 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -343,8 +343,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) } static struct perf_event_ops event_ops = { - .process_sample_event = process_sample_event, - .process_comm_event = event__process_comm, + .sample = process_sample_event, + .comm = event__process_comm, }; static double fragmentation(unsigned long n_req, unsigned long n_alloc) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f695084910c0..508934b0140a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -184,13 +184,13 @@ static int perf_session__setup_sample_type(struct perf_session *self) } static struct perf_event_ops event_ops = { - .process_sample_event = process_sample_event, - .process_mmap_event = event__process_mmap, - .process_comm_event = event__process_comm, - .process_exit_event = event__process_task, - .process_fork_event = event__process_task, - .process_lost_event = event__process_lost, - .process_read_event = process_read_event, + .sample = process_sample_event, + .mmap = event__process_mmap, + .comm = event__process_comm, + .exit = event__process_task, + .fork = event__process_task, + .lost = event__process_lost, + .read = process_read_event, }; static int __cmd_report(void) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index e862e71f4e68..702322f8fec1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1654,9 +1654,9 @@ static int process_lost_event(event_t *event __used, } static struct perf_event_ops event_ops = { - .process_sample_event = process_sample_event, - .process_comm_event = event__process_comm, - .process_lost_event = process_lost_event, + .sample = process_sample_event, + .comm = event__process_comm, + .lost = process_lost_event, }; static int read_events(void) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 825283794985..5b68d81d93a1 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1030,10 +1030,10 @@ static void process_samples(struct perf_session *session) } static struct perf_event_ops event_ops = { - .process_comm_event = process_comm_event, - .process_fork_event = process_fork_event, - .process_exit_event = process_exit_event, - .process_sample_event = queue_sample_event, + .comm = process_comm_event, + .fork = process_fork_event, + .exit = process_exit_event, + .sample = queue_sample_event, }; static int __cmd_timechart(void) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e94f34631585..1831434aa938 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -104,8 +104,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) } static struct perf_event_ops event_ops = { - .process_sample_event = process_sample_event, - .process_comm_event = event__process_comm, + .sample = process_sample_event, + .comm = event__process_comm, }; static int __cmd_trace(struct perf_session *session) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4f2eeb584da8..7f0537d1add8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -161,24 +161,24 @@ static int process_event_stub(event_t *event __used, static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) { - if (handler->process_sample_event == NULL) - handler->process_sample_event = process_event_stub; - if (handler->process_mmap_event == NULL) - handler->process_mmap_event = process_event_stub; - if (handler->process_comm_event == NULL) - handler->process_comm_event = process_event_stub; - if (handler->process_fork_event == NULL) - handler->process_fork_event = process_event_stub; - if (handler->process_exit_event == NULL) - handler->process_exit_event = process_event_stub; - if (handler->process_lost_event == NULL) - handler->process_lost_event = process_event_stub; - if (handler->process_read_event == NULL) - handler->process_read_event = process_event_stub; - if (handler->process_throttle_event == NULL) - handler->process_throttle_event = process_event_stub; - if (handler->process_unthrottle_event == NULL) - handler->process_unthrottle_event = process_event_stub; + if (handler->sample == NULL) + handler->sample = process_event_stub; + if (handler->mmap == NULL) + handler->mmap = process_event_stub; + if (handler->comm == NULL) + handler->comm = process_event_stub; + if (handler->fork == NULL) + handler->fork = process_event_stub; + if (handler->exit == NULL) + handler->exit = process_event_stub; + if (handler->lost == NULL) + handler->lost = process_event_stub; + if (handler->read == NULL) + handler->read = process_event_stub; + if (handler->throttle == NULL) + handler->throttle = process_event_stub; + if (handler->unthrottle == NULL) + handler->unthrottle = process_event_stub; } static const char *event__name[] = { @@ -222,23 +222,23 @@ static int perf_session__process_event(struct perf_session *self, switch (event->header.type) { case PERF_RECORD_SAMPLE: - return ops->process_sample_event(event, self); + return ops->sample(event, self); case PERF_RECORD_MMAP: - return ops->process_mmap_event(event, self); + return ops->mmap(event, self); case PERF_RECORD_COMM: - return ops->process_comm_event(event, self); + return ops->comm(event, self); case PERF_RECORD_FORK: - return ops->process_fork_event(event, self); + return ops->fork(event, self); case PERF_RECORD_EXIT: - return ops->process_exit_event(event, self); + return ops->exit(event, self); case PERF_RECORD_LOST: - return ops->process_lost_event(event, self); + return ops->lost(event, self); case PERF_RECORD_READ: - return ops->process_read_event(event, self); + return ops->read(event, self); case PERF_RECORD_THROTTLE: - return ops->process_throttle_event(event, self); + return ops->throttle(event, self); case PERF_RECORD_UNTHROTTLE: - return ops->process_unthrottle_event(event, self); + return ops->unthrottle(event, self); default: self->unknown_events++; return -1; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 2ff77fea06ef..77c5ee2993c2 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -32,15 +32,15 @@ struct perf_session { typedef int (*event_op)(event_t *self, struct perf_session *session); struct perf_event_ops { - event_op process_sample_event; - event_op process_mmap_event; - event_op process_comm_event; - event_op process_fork_event; - event_op process_exit_event; - event_op process_lost_event; - event_op process_read_event; - event_op process_throttle_event; - event_op process_unthrottle_event; + event_op sample, + mmap, + comm, + fork, + exit, + lost, + read, + throttle, + unthrottle; }; struct perf_session *perf_session__new(const char *filename, int mode, bool force); -- GitLab From 4cf40131a5cf4918e83b3756e58a1fc9e984f8ef Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 27 Dec 2009 21:37:06 -0200 Subject: [PATCH 0199/3892] perf record: Introduce a symtab cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now a cache will be created in a ~/.debug debuginfo like hierarchy, so that at the end of a 'perf record' session all the binaries (with build-ids) involved get collected and indexed by their build-ids, so that perf report can find them. This is interesting when developing software where you want to do a 'perf diff' with the previous build and opens avenues for lots more interesting tools, like a 'perf diff --graph' that takes more than two binaries into account. Tunables for collecting just the symtabs can be added if one doesn't want to have the full binary, but having the full binary allows things like 'perf rerecord' or other tools that can re-run the tests by having access to the exact binary in some perf.data file, so it may well be interesting to keep the full binary there. Space consumption is minimised by trying to use hard links, a 'perf cache' tool to manage the space used, a la ccache is required to purge older entries. With this in place it will be possible also to introduce new commands, 'perf archive' and 'perf restore' (or some more suitable and future proof names) to create a cpio/tar file with the perf data and the files in the cache that _had_ perf hits of interest. There are more aspects to polish, like finding the right vmlinux file to cache, etc, but this is enough for a first step. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1261957026-15580-10-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 + tools/perf/util/header.c | 82 +++++++++++++++++++++++++++++++++++++--- tools/perf/util/symbol.c | 17 +++++++-- tools/perf/util/symbol.h | 2 + tools/perf/util/util.c | 69 +++++++++++++++++++++++++++++++++ tools/perf/util/util.h | 3 ++ 6 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 tools/perf/util/util.c diff --git a/tools/perf/Makefile b/tools/perf/Makefile index fafea0b6f323..7c846424aebf 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -425,6 +425,7 @@ LIB_OBJS += util/svghelper.o LIB_OBJS += util/sort.o LIB_OBJS += util/hist.o LIB_OBJS += util/probe-event.o +LIB_OBJS += util/util.o BUILTIN_OBJS += builtin-annotate.o diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8a0bca55106f..df237c3a041b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -169,20 +169,23 @@ static int do_write(int fd, const void *buf, size_t size) return 0; } +#define dsos__for_each_with_build_id(pos, head) \ + list_for_each_entry(pos, head, node) \ + if (!pos->has_build_id) \ + continue; \ + else + static int __dsos__write_buildid_table(struct list_head *head, int fd) { #define NAME_ALIGN 64 struct dso *pos; static const char zero_buf[NAME_ALIGN]; - list_for_each_entry(pos, head, node) { + dsos__for_each_with_build_id(pos, head) { int err; struct build_id_event b; - size_t len; + size_t len = pos->long_name_len + 1; - if (!pos->has_build_id) - continue; - len = pos->long_name_len + 1; len = ALIGN(len, NAME_ALIGN); memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); @@ -209,6 +212,74 @@ static int dsos__write_buildid_table(int fd) return err; } +static int dso__cache_build_id(struct dso *self, const char *debugdir) +{ + const size_t size = PATH_MAX; + char *filename = malloc(size), + *linkname = malloc(size), *targetname, *sbuild_id; + int len, err = -1; + + if (filename == NULL || linkname == NULL) + goto out_free; + + len = snprintf(filename, size, "%s%s", debugdir, self->long_name); + if (mkdir_p(filename, 0755)) + goto out_free; + + len += snprintf(filename + len, sizeof(filename) - len, "/"); + sbuild_id = filename + len; + build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); + + if (access(filename, F_OK) && link(self->long_name, filename) && + copyfile(self->long_name, filename)) + goto out_free; + + len = snprintf(linkname, size, "%s/.build-id/%.2s", + debugdir, sbuild_id); + + if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) + goto out_free; + + snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); + targetname = filename + strlen(debugdir) - 5; + memcpy(targetname, "../..", 5); + + if (symlink(targetname, linkname) == 0) + err = 0; +out_free: + free(filename); + free(linkname); + return err; +} + +static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) +{ + struct dso *pos; + int err = 0; + + dsos__for_each_with_build_id(pos, head) + if (dso__cache_build_id(pos, debugdir)) + err = -1; + + return err; +} + +static int dsos__cache_build_ids(void) +{ + int err_kernel, err_user; + char debugdir[PATH_MAX]; + + snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), + DEBUG_CACHE_DIR); + + if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) + return -1; + + err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir); + err_user = __dsos__cache_build_ids(&dsos__user, debugdir); + return err_kernel || err_user ? -1 : 0; +} + static int perf_header__adds_write(struct perf_header *self, int fd) { int nr_sections; @@ -258,6 +329,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) goto out_free; } buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; + dsos__cache_build_ids(); } lseek(fd, sec_start, SEEK_SET); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ab92763edb03..79ca6a099f96 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -22,6 +22,7 @@ enum dso_origin { DSO__ORIG_KERNEL = 0, DSO__ORIG_JAVA_JIT, + DSO__ORIG_BUILD_ID_CACHE, DSO__ORIG_FEDORA, DSO__ORIG_UBUNTU, DSO__ORIG_BUILDID, @@ -1191,6 +1192,7 @@ char dso__symtab_origin(const struct dso *self) static const char origin[] = { [DSO__ORIG_KERNEL] = 'k', [DSO__ORIG_JAVA_JIT] = 'j', + [DSO__ORIG_BUILD_ID_CACHE] = 'B', [DSO__ORIG_FEDORA] = 'f', [DSO__ORIG_UBUNTU] = 'u', [DSO__ORIG_BUILDID] = 'b', @@ -1209,6 +1211,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session, int size = PATH_MAX; char *name; u8 build_id[BUILD_ID_SIZE]; + char build_id_hex[BUILD_ID_SIZE * 2 + 1]; int ret = -1; int fd; @@ -1230,8 +1233,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session, return ret; } - self->origin = DSO__ORIG_FEDORA - 1; + self->origin = DSO__ORIG_BUILD_ID_CACHE; + if (self->has_build_id) { + build_id__sprintf(self->build_id, sizeof(self->build_id), + build_id_hex); + snprintf(name, size, "%s/%s/.build-id/%.2s/%s", + getenv("HOME"), DEBUG_CACHE_DIR, + build_id_hex, build_id_hex + 2); + goto open_file; + } more: do { self->origin++; @@ -1247,8 +1258,6 @@ more: case DSO__ORIG_BUILDID: if (filename__read_build_id(self->long_name, build_id, sizeof(build_id))) { - char build_id_hex[BUILD_ID_SIZE * 2 + 1]; - build_id__sprintf(build_id, sizeof(build_id), build_id_hex); snprintf(name, size, @@ -1276,7 +1285,7 @@ compare_build_id: if (!dso__build_id_equal(self, build_id)) goto more; } - +open_file: fd = open(name, O_RDONLY); } while (fd < 0); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 9eabd60f819d..f27e158943e9 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -8,6 +8,8 @@ #include #include "event.h" +#define DEBUG_CACHE_DIR ".debug" + #ifdef HAVE_CPLUS_DEMANGLE extern char *cplus_demangle(const char *, int); diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c new file mode 100644 index 000000000000..f3c0798a5e78 --- /dev/null +++ b/tools/perf/util/util.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include "util.h" + +int mkdir_p(char *path, mode_t mode) +{ + struct stat st; + int err; + char *d = path; + + if (*d != '/') + return -1; + + if (stat(path, &st) == 0) + return 0; + + while (*++d == '/'); + + while ((d = strchr(d, '/'))) { + *d = '\0'; + err = stat(path, &st) && mkdir(path, mode); + *d++ = '/'; + if (err) + return -1; + while (*d == '/') + ++d; + } + return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; +} + +int copyfile(const char *from, const char *to) +{ + int fromfd, tofd; + struct stat st; + void *addr; + int err = -1; + + if (stat(from, &st)) + goto out; + + fromfd = open(from, O_RDONLY); + if (fromfd < 0) + goto out; + + tofd = creat(to, 0755); + if (tofd < 0) + goto out_close_from; + + addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); + if (addr == MAP_FAILED) + goto out_close_to; + + if (write(tofd, addr, st.st_size) == st.st_size) + err = 0; + + munmap(addr, st.st_size); +out_close_to: + close(tofd); + if (err) + unlink(to); +out_close_from: + close(fromfd); +out: + return err; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c673d8825883..0f5b2a6f1080 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size, #endif #endif +int mkdir_p(char *path, mode_t mode); +int copyfile(const char *from, const char *to); + #endif -- GitLab From 49f474331e563a6ecf3b1e87ec27ec5482b3e4f1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 27 Dec 2009 11:51:52 +0100 Subject: [PATCH 0200/3892] perf events: Remove arg from perf sched hooks Since we only ever schedule the local cpu, there is no need to pass the cpu number to the perf sched hooks. This micro-optimizes things a bit. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 12 ++++++------ kernel/perf_event.c | 27 ++++++++++++++------------- kernel/sched.c | 6 +++--- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index c66b34f75eea..a494e7501292 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -746,10 +746,10 @@ extern int perf_max_events; extern const struct pmu *hw_perf_event_init(struct perf_event *event); -extern void perf_event_task_sched_in(struct task_struct *task, int cpu); +extern void perf_event_task_sched_in(struct task_struct *task); extern void perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next, int cpu); -extern void perf_event_task_tick(struct task_struct *task, int cpu); + struct task_struct *next); +extern void perf_event_task_tick(struct task_struct *task); extern int perf_event_init_task(struct task_struct *child); extern void perf_event_exit_task(struct task_struct *child); extern void perf_event_free_task(struct task_struct *task); @@ -870,12 +870,12 @@ extern void perf_event_enable(struct perf_event *event); extern void perf_event_disable(struct perf_event *event); #else static inline void -perf_event_task_sched_in(struct task_struct *task, int cpu) { } +perf_event_task_sched_in(struct task_struct *task) { } static inline void perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next, int cpu) { } + struct task_struct *next) { } static inline void -perf_event_task_tick(struct task_struct *task, int cpu) { } +perf_event_task_tick(struct task_struct *task) { } static inline int perf_event_init_task(struct task_struct *child) { return 0; } static inline void perf_event_exit_task(struct task_struct *child) { } static inline void perf_event_free_task(struct task_struct *task) { } diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 03cc061398d1..099bd662daa6 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1170,9 +1170,9 @@ static void perf_event_sync_stat(struct perf_event_context *ctx, * not restart the event. */ void perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next, int cpu) + struct task_struct *next) { - struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); struct perf_event_context *ctx = task->perf_event_ctxp; struct perf_event_context *next_ctx; struct perf_event_context *parent; @@ -1252,8 +1252,9 @@ static void perf_event_cpu_sched_out(struct perf_cpu_context *cpuctx) static void __perf_event_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx, int cpu) + struct perf_cpu_context *cpuctx) { + int cpu = smp_processor_id(); struct perf_event *event; int can_add_hw = 1; @@ -1326,24 +1327,24 @@ __perf_event_sched_in(struct perf_event_context *ctx, * accessing the event control register. If a NMI hits, then it will * keep the event running. */ -void perf_event_task_sched_in(struct task_struct *task, int cpu) +void perf_event_task_sched_in(struct task_struct *task) { - struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); struct perf_event_context *ctx = task->perf_event_ctxp; if (likely(!ctx)) return; if (cpuctx->task_ctx == ctx) return; - __perf_event_sched_in(ctx, cpuctx, cpu); + __perf_event_sched_in(ctx, cpuctx); cpuctx->task_ctx = ctx; } -static void perf_event_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu) +static void perf_event_cpu_sched_in(struct perf_cpu_context *cpuctx) { struct perf_event_context *ctx = &cpuctx->ctx; - __perf_event_sched_in(ctx, cpuctx, cpu); + __perf_event_sched_in(ctx, cpuctx); } #define MAX_INTERRUPTS (~0ULL) @@ -1461,7 +1462,7 @@ static void rotate_ctx(struct perf_event_context *ctx) raw_spin_unlock(&ctx->lock); } -void perf_event_task_tick(struct task_struct *curr, int cpu) +void perf_event_task_tick(struct task_struct *curr) { struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; @@ -1469,7 +1470,7 @@ void perf_event_task_tick(struct task_struct *curr, int cpu) if (!atomic_read(&nr_events)) return; - cpuctx = &per_cpu(perf_cpu_context, cpu); + cpuctx = &__get_cpu_var(perf_cpu_context); ctx = curr->perf_event_ctxp; perf_ctx_adjust_freq(&cpuctx->ctx); @@ -1484,9 +1485,9 @@ void perf_event_task_tick(struct task_struct *curr, int cpu) if (ctx) rotate_ctx(ctx); - perf_event_cpu_sched_in(cpuctx, cpu); + perf_event_cpu_sched_in(cpuctx); if (ctx) - perf_event_task_sched_in(curr, cpu); + perf_event_task_sched_in(curr); } /* @@ -1527,7 +1528,7 @@ static void perf_event_enable_on_exec(struct task_struct *task) raw_spin_unlock(&ctx->lock); - perf_event_task_sched_in(task, smp_processor_id()); + perf_event_task_sched_in(task); out: local_irq_restore(flags); } diff --git a/kernel/sched.c b/kernel/sched.c index 18cceeecce35..d6527ac0f6e7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2752,7 +2752,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) */ prev_state = prev->state; finish_arch_switch(prev); - perf_event_task_sched_in(current, cpu_of(rq)); + perf_event_task_sched_in(current); finish_lock_switch(rq, prev); fire_sched_in_preempt_notifiers(current); @@ -5266,7 +5266,7 @@ void scheduler_tick(void) curr->sched_class->task_tick(rq, curr, 0); raw_spin_unlock(&rq->lock); - perf_event_task_tick(curr, cpu); + perf_event_task_tick(curr); #ifdef CONFIG_SMP rq->idle_at_tick = idle_cpu(cpu); @@ -5480,7 +5480,7 @@ need_resched_nonpreemptible: if (likely(prev != next)) { sched_info_switch(prev, next); - perf_event_task_sched_out(prev, next, cpu); + perf_event_task_sched_out(prev, next); rq->nr_switches++; rq->curr = next; -- GitLab From fd2a50a0240f5f5b59070474eabd83a85720a406 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Thu, 24 Dec 2009 01:54:47 +0000 Subject: [PATCH 0201/3892] x86, perfctr: Remove unused func avail_to_resrv_perfctr_nmi() avail_to_resrv_perfctr_nmi() is neither EXPORT'd, nor used in the file. So remove it. Signed-off-by: Naga Chumbalkar Acked-by: Cyrill Gorcunov Cc: oprofile-list@lists.sf.net LKML-Reference: <20091224015441.6005.4408.sendpatchset@localhost.localdomain> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/nmi.h | 1 - arch/x86/kernel/cpu/perfctr-watchdog.c | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index 139d4c1a33a7..93da9c3f3341 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -19,7 +19,6 @@ extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); extern int check_nmi_watchdog(void); extern int nmi_watchdog_enabled; extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); -extern int avail_to_resrv_perfctr_nmi(unsigned int); extern int reserve_perfctr_nmi(unsigned int); extern void release_perfctr_nmi(unsigned int); extern int reserve_evntsel_nmi(unsigned int); diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index 898df9719afb..74f4e85a5727 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c @@ -115,17 +115,6 @@ int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) return !test_bit(counter, perfctr_nmi_owner); } - -/* checks the an msr for availability */ -int avail_to_resrv_perfctr_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_perfctr_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - return !test_bit(counter, perfctr_nmi_owner); -} EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit); int reserve_perfctr_nmi(unsigned int msr) -- GitLab From 34d0b5af50a063cded842716633501b38ff815fb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 28 Dec 2009 17:53:47 +0900 Subject: [PATCH 0202/3892] sh: Convert ptrace to hw_breakpoint API. This is the initial step for converting singlestep handling via ptrace over to hw_breakpoints. Signed-off-by: Paul Mundt --- arch/sh/include/asm/ptrace.h | 6 ++++ arch/sh/kernel/hw_breakpoint.c | 15 ++++++++-- arch/sh/kernel/ptrace_32.c | 53 +++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index 1dc12cb44a2d..201d11ef211f 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h @@ -124,6 +124,12 @@ struct task_struct; extern void user_enable_single_step(struct task_struct *); extern void user_disable_single_step(struct task_struct *); +struct perf_event; +struct perf_sample_data; + +extern void ptrace_triggered(struct perf_event *bp, int nmi, + struct perf_sample_data *data, struct pt_regs *regs); + #define task_pt_regs(task) \ ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1) diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c index 022d8ed66bd6..c515a3ecf562 100644 --- a/arch/sh/kernel/hw_breakpoint.c +++ b/arch/sh/kernel/hw_breakpoint.c @@ -20,6 +20,7 @@ #include #include #include +#include struct ubc_context { unsigned long pc; @@ -372,7 +373,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_unlock(); } - if (bp) { + if (bp && bp->overflow_handler != ptrace_triggered) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0); @@ -387,9 +388,19 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) BUILD_TRAP_HANDLER(breakpoint) { unsigned long ex = lookup_exception_vector(); + siginfo_t info; + int err; TRAP_HANDLER_DECL; - notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); + err = notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); + if (err == NOTIFY_STOP) + return; + + /* Deliver the signal to userspace */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + force_sig_info(SIGTRAP, &info, current); } /* diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index bdb10446cbac..8e094c4c7bb4 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -2,7 +2,7 @@ * SuperH process tracing * * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka - * Copyright (C) 2002 - 2008 Paul Mundt + * Copyright (C) 2002 - 2009 Paul Mundt * * Audit support by Yuichi Nakamura * @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,59 @@ static inline int put_stack_long(struct task_struct *task, int offset, return 0; } +void ptrace_triggered(struct perf_event *bp, int nmi, + struct perf_sample_data *data, struct pt_regs *regs) +{ + struct perf_event_attr attr; + + /* + * Disable the breakpoint request here since ptrace has defined a + * one-shot behaviour for breakpoint exceptions. + */ + attr = bp->attr; + attr.disabled = true; + modify_user_hw_breakpoint(bp, &attr); +} + +static int set_single_step(struct task_struct *tsk, unsigned long addr) +{ + struct thread_struct *thread = &tsk->thread; + struct perf_event *bp; + struct perf_event_attr attr; + + bp = thread->ptrace_bps[0]; + if (!bp) { + hw_breakpoint_init(&attr); + + attr.bp_addr = addr; + attr.bp_len = HW_BREAKPOINT_LEN_2; + attr.bp_type = HW_BREAKPOINT_R; + + bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); + if (IS_ERR(bp)) + return PTR_ERR(bp); + + thread->ptrace_bps[0] = bp; + } else { + int err; + + attr = bp->attr; + attr.bp_addr = addr; + err = modify_user_hw_breakpoint(bp, &attr); + if (unlikely(err)) + return err; + } + + return 0; +} + void user_enable_single_step(struct task_struct *child) { + unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc)); + set_tsk_thread_flag(child, TIF_SINGLESTEP); + + set_single_step(child, pc); } void user_disable_single_step(struct task_struct *child) -- GitLab From 659d8cfbb225f1fa5a4f8671a847ef3ab5a89660 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 19 Dec 2009 16:40:28 -0500 Subject: [PATCH 0203/3892] perf tools: Do a few more directory handling optimizations A few more optimizations for perf when dealing with directories. Some of them significantly cut down the work which has to be done. d_type should always be set; otherwise fix the kernel code. And there are functions available to parse fstab-like files, so use them. Signed-off-by: Ulrich Drepper Acked-by: Pekka Enberg Cc: a.p.zijlstra@chello.nl Cc: acme@redhat.com Cc: eranian@google.com Cc: fweisbec@gmail.com Cc: lizf@cn.fujitsu.com Cc: paulus@samba.org Cc: xiaoguangrong@cn.fujitsu.com LKML-Reference: <200912192140.nBJLeSfA028905@hs20-bc2-1.build.redhat.com> [ v2: two small stylistic fixlets ] Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 17 ++++------ tools/perf/util/trace-event-info.c | 50 ++++++++++++++---------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 4c06828fe39d..05dc5a735039 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -92,23 +92,18 @@ static void setup_cpunode_map(void) if (!dir1) return; - while (true) { - dent1 = readdir(dir1); - if (!dent1) - break; - - if (sscanf(dent1->d_name, "node%u", &mem) < 1) + while ((dent1 = readdir(dir1)) != NULL) { + if (dent1->d_type != DT_DIR || + sscanf(dent1->d_name, "node%u", &mem) < 1) continue; snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); dir2 = opendir(buf); if (!dir2) continue; - while (true) { - dent2 = readdir(dir2); - if (!dent2) - break; - if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1) + while ((dent2 = readdir(dir2)) != NULL) { + if (dent2->d_type != DT_LNK || + sscanf(dent2->d_name, "cpu%u", &cpu) < 1) continue; cpunode_map[cpu] = mem; } diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index cace35595530..dfef238ce158 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -20,6 +20,7 @@ */ #define _GNU_SOURCE #include +#include #include #include #include @@ -103,28 +104,28 @@ static const char *find_debugfs(void) { static char debugfs[MAX_PATH+1]; static int debugfs_found; - char type[100]; FILE *fp; + struct mntent *m; if (debugfs_found) return debugfs; - if ((fp = fopen("/proc/mounts","r")) == NULL) + fp = setmntent("/proc/mounts", "r"); + if (!fp) die("Can't open /proc/mounts for read"); - while (fscanf(fp, "%*s %" - STR(MAX_PATH) - "s %99s %*s %*d %*d\n", - debugfs, type) == 2) { - if (strcmp(type, "debugfs") == 0) + while ((m = getmntent(fp)) != NULL) { + if (strcmp(m->mnt_type, "debugfs") == 0) { + strcpy(debugfs, m->mnt_dir); + debugfs_found = 1; break; + } } - fclose(fp); - if (strcmp(type, "debugfs") != 0) - die("debugfs not mounted, please mount"); + endmntent(fp); - debugfs_found = 1; + if (!debugfs_found) + die("debugfs not mounted, please mount"); return debugfs; } @@ -317,7 +318,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) die("can't read directory '%s'", sys); while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || + if (dent->d_type != DT_DIR || + strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || !name_in_tp_list(dent->d_name, tps)) continue; @@ -334,7 +336,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) rewinddir(dir); while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || + if (dent->d_type != DT_DIR || + strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || !name_in_tp_list(dent->d_name, tps)) continue; @@ -394,26 +397,21 @@ static void read_event_files(struct tracepoint_path *tps) die("can't read directory '%s'", path); while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || + if (dent->d_type != DT_DIR || + strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "ftrace") == 0 || !system_in_tp_list(dent->d_name, tps)) continue; - sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); - sprintf(sys, "%s/%s", path, dent->d_name); - ret = stat(sys, &st); - free(sys); - if (ret < 0) - continue; - if (S_ISDIR(st.st_mode)) - count++; + count++; } write_or_die(&count, 4); rewinddir(dir); while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || + if (dent->d_type != DT_DIR || + strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "ftrace") == 0 || !system_in_tp_list(dent->d_name, tps)) @@ -422,10 +420,8 @@ static void read_event_files(struct tracepoint_path *tps) sprintf(sys, "%s/%s", path, dent->d_name); ret = stat(sys, &st); if (ret >= 0) { - if (S_ISDIR(st.st_mode)) { - write_or_die(dent->d_name, strlen(dent->d_name) + 1); - copy_event_system(sys, tps); - } + write_or_die(dent->d_name, strlen(dent->d_name) + 1); + copy_event_system(sys, tps); } free(sys); } -- GitLab From 07b139c8c81b97bbe55c68daf0cbeca8b1c609ca Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 21 Dec 2009 14:27:35 +0800 Subject: [PATCH 0204/3892] perf events: Remove CONFIG_EVENT_PROFILE Quoted from Ingo: | This reminds me - i think we should eliminate CONFIG_EVENT_PROFILE - | it's an unnecessary Kconfig complication. If both PERF_EVENTS and | EVENT_TRACING is enabled we should expose generic tracepoints. | | Nor is it limited to event 'profiling', so it has become a misnomer as | well. Signed-off-by: Li Zefan Cc: Frederic Weisbecker Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <4B2F1557.2050705@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- include/linux/ftrace_event.h | 2 +- include/linux/perf_event.h | 2 +- include/linux/syscalls.h | 4 ++-- include/trace/ftrace.h | 12 ++++++------ include/trace/syscall.h | 4 ++-- init/Kconfig | 13 ------------- kernel/perf_event.c | 4 ++-- kernel/trace/Makefile | 4 +++- kernel/trace/trace_events_filter.c | 4 ++-- kernel/trace/trace_kprobe.c | 14 +++++++------- kernel/trace/trace_syscalls.c | 5 ++--- 11 files changed, 28 insertions(+), 40 deletions(-) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 2233c98d80df..0a09e758c7d3 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -188,7 +188,7 @@ do { \ __trace_printk(ip, fmt, ##args); \ } while (0) -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS struct perf_event; extern int ftrace_profile_enable(int event_id); extern void ftrace_profile_disable(int event_id); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index a494e7501292..9a1d276db754 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -658,7 +658,7 @@ struct perf_event { perf_overflow_handler_t overflow_handler; -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_EVENT_TRACING struct event_filter *filter; #endif diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 65793e90d6f6..b7c7fcf7790b 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -99,7 +99,7 @@ struct perf_event_attr; #define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) #define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS #define TRACE_SYS_ENTER_PROFILE_INIT(sname) \ .profile_enable = prof_sysenter_enable, \ @@ -113,7 +113,7 @@ struct perf_event_attr; #define TRACE_SYS_ENTER_PROFILE_INIT(sname) #define TRACE_SYS_EXIT_PROFILE(sname) #define TRACE_SYS_EXIT_PROFILE_INIT(sname) -#endif +#endif /* CONFIG_PERF_EVENTS */ #ifdef CONFIG_FTRACE_SYSCALLS #define __SC_STR_ADECL1(t, a) #a diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 73523151a731..2fdd36df41f6 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -498,7 +498,7 @@ static inline int ftrace_get_offsets_##call( \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS /* * Generate the functions needed for tracepoint perf_event support. @@ -541,7 +541,7 @@ static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#endif +#endif /* CONFIG_PERF_EVENTS */ /* * Stage 4 of the trace events. @@ -626,7 +626,7 @@ static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ * */ -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS #define _TRACE_PROFILE_INIT(call) \ .profile_enable = ftrace_profile_enable_##call, \ @@ -634,7 +634,7 @@ static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ #else #define _TRACE_PROFILE_INIT(call) -#endif +#endif /* CONFIG_PERF_EVENTS */ #undef __entry #define __entry entry @@ -834,7 +834,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ * } */ -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS #undef __perf_addr #define __perf_addr(a) __addr = (a) @@ -926,7 +926,7 @@ static void ftrace_profile_##call(proto) \ DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#endif /* CONFIG_EVENT_PROFILE */ +#endif /* CONFIG_PERF_EVENTS */ #undef _TRACE_PROFILE_INIT diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 961fda3556bb..3d463dcef298 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -49,12 +49,12 @@ ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif -#ifdef CONFIG_EVENT_PROFILE + +#ifdef CONFIG_PERF_EVENTS int prof_sysenter_enable(struct ftrace_event_call *call); void prof_sysenter_disable(struct ftrace_event_call *call); int prof_sysexit_enable(struct ftrace_event_call *call); void prof_sysexit_disable(struct ftrace_event_call *call); - #endif #endif /* _TRACE_SYSCALL_H */ diff --git a/init/Kconfig b/init/Kconfig index a23da9f01803..06dab27c18d9 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -966,19 +966,6 @@ config PERF_EVENTS Say Y if unsure. -config EVENT_PROFILE - bool "Tracepoint profiling sources" - depends on PERF_EVENTS && EVENT_TRACING - default y - help - Allow the use of tracepoints as software performance events. - - When this is enabled, you can create perf events based on - tracepoints using PERF_TYPE_TRACEPOINT and the tracepoint ID - found in debugfs://tracing/events/*/*/id. (The -e/--events - option to the perf tool can parse and interpret symbolic - tracepoints, in the subsystem:tracepoint_name format.) - config PERF_COUNTERS bool "Kernel performance counters (old config option)" depends on HAVE_PERF_EVENTS diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 099bd662daa6..5b987b4a98a8 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -4177,7 +4177,7 @@ static const struct pmu perf_ops_task_clock = { .read = task_clock_perf_event_read, }; -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_EVENT_TRACING void perf_tp_event(int event_id, u64 addr, u64 count, void *record, int entry_size) @@ -4282,7 +4282,7 @@ static void perf_event_free_filter(struct perf_event *event) { } -#endif /* CONFIG_EVENT_PROFILE */ +#endif /* CONFIG_EVENT_TRACING */ #ifdef CONFIG_HAVE_HW_BREAKPOINT static void bp_perf_event_destroy(struct perf_event *event) diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index cd9ecd89ec77..d00c6fe23f54 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -51,7 +51,9 @@ endif obj-$(CONFIG_EVENT_TRACING) += trace_events.o obj-$(CONFIG_EVENT_TRACING) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o -obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o +ifeq ($(CONFIG_PERF_EVENTS),y) +obj-$(CONFIG_EVENT_TRACING) += trace_event_profile.o +endif obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 50504cb228de..74563d7e102e 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1360,7 +1360,7 @@ out_unlock: return err; } -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS void ftrace_profile_free_filter(struct perf_event *event) { @@ -1428,5 +1428,5 @@ out_unlock: return err; } -#endif /* CONFIG_EVENT_PROFILE */ +#endif /* CONFIG_PERF_EVENTS */ diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 375f81a568dc..75d75dec226a 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1249,7 +1249,7 @@ static int kretprobe_event_show_format(struct ftrace_event_call *call, ", REC->" FIELD_STRING_RETIP); } -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS /* Kprobe profile handler */ static __kprobes int kprobe_profile_func(struct kprobe *kp, @@ -1407,7 +1407,7 @@ static void probe_profile_disable(struct ftrace_event_call *call) disable_kprobe(&tp->rp.kp); } } -#endif /* CONFIG_EVENT_PROFILE */ +#endif /* CONFIG_PERF_EVENTS */ static __kprobes @@ -1417,10 +1417,10 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) if (tp->flags & TP_FLAG_TRACE) kprobe_trace_func(kp, regs); -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS if (tp->flags & TP_FLAG_PROFILE) kprobe_profile_func(kp, regs); -#endif /* CONFIG_EVENT_PROFILE */ +#endif return 0; /* We don't tweek kernel, so just return 0 */ } @@ -1431,10 +1431,10 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) if (tp->flags & TP_FLAG_TRACE) kretprobe_trace_func(ri, regs); -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS if (tp->flags & TP_FLAG_PROFILE) kretprobe_profile_func(ri, regs); -#endif /* CONFIG_EVENT_PROFILE */ +#endif return 0; /* We don't tweek kernel, so just return 0 */ } @@ -1463,7 +1463,7 @@ static int register_probe_event(struct trace_probe *tp) call->regfunc = probe_event_enable; call->unregfunc = probe_event_disable; -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS call->profile_enable = probe_profile_enable; call->profile_disable = probe_profile_disable; #endif diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 75289f372dd2..f694f66d75b0 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -421,7 +421,7 @@ int __init init_ftrace_syscalls(void) } core_initcall(init_ftrace_syscalls); -#ifdef CONFIG_EVENT_PROFILE +#ifdef CONFIG_PERF_EVENTS static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_prof_exit_syscalls, NR_syscalls); @@ -626,6 +626,5 @@ void prof_sysexit_disable(struct ftrace_event_call *call) mutex_unlock(&syscall_trace_lock); } -#endif - +#endif /* CONFIG_PERF_EVENTS */ -- GitLab From 29c52aa2300173dd45df04dae1f5acc81a2c93b1 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Mon, 28 Dec 2009 16:47:12 +0800 Subject: [PATCH 0205/3892] perf tools: Mount debugfs automatically Mount debugfs filesystem under '/sys/kernel/debug', if it's not mounted. Signed-off-by: Xiao Guangrong Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Clark Williams Cc: John Kacur LKML-Reference: <4B387090.7080407@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- tools/perf/perf.c | 2 +- tools/perf/util/debugfs.c | 16 +++++++--------- tools/perf/util/debugfs.h | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 873e55fab375..fc89005c3e51 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -388,7 +388,7 @@ static int run_argv(int *argcp, const char ***argv) /* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ static void get_debugfs_mntpt(void) { - const char *path = debugfs_find_mountpoint(); + const char *path = debugfs_mount(NULL); if (path) strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c index 06b73ee02c49..1f805fde5fd4 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/perf/util/debugfs.c @@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path) return 0; } -/* mount the debugfs somewhere */ +/* mount the debugfs somewhere if it's not mounted */ -int debugfs_mount(const char *mountpoint) +char *debugfs_mount(const char *mountpoint) { - char mountcmd[128]; - /* see if it's already mounted */ if (debugfs_find_mountpoint()) { debugfs_premounted = 1; - return 0; + return debugfs_mountpoint; } /* if not mounted and no argument */ @@ -127,13 +125,13 @@ int debugfs_mount(const char *mountpoint) mountpoint = "/sys/kernel/debug"; } + if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) + return NULL; + /* save the mountpoint */ strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); - /* mount it */ - snprintf(mountcmd, sizeof(mountcmd), - "/bin/mount -t debugfs debugfs %s", mountpoint); - return system(mountcmd); + return debugfs_mountpoint; } /* umount the debugfs */ diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h index 3cd14f9ae784..83a02879745f 100644 --- a/tools/perf/util/debugfs.h +++ b/tools/perf/util/debugfs.h @@ -15,7 +15,7 @@ extern const char *debugfs_find_mountpoint(void); extern int debugfs_valid_mountpoint(const char *debugfs); extern int debugfs_valid_entry(const char *path); -extern int debugfs_mount(const char *mountpoint); +extern char *debugfs_mount(const char *mountpoint); extern int debugfs_umount(void); extern int debugfs_write(const char *entry, const char *value); extern int debugfs_read(const char *entry, char *buffer, size_t size); -- GitLab From 61be3e59ba7a6dbd39f92fd1f107285a0caeb008 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Mon, 28 Dec 2009 16:48:30 +0800 Subject: [PATCH 0206/3892] perf trace: Clean up find_debugfs() Remove redundant code for 'perf trace' Signed-off-by: Xiao Guangrong Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Clark Williams Cc: John Kacur LKML-Reference: <4B3870DE.7090500@cn.fujitsu.com> [ v2: resolved conflicts with recent changes ] Signed-off-by: Ingo Molnar --- tools/perf/util/debugfs.c | 1 + tools/perf/util/trace-event-info.c | 29 +++++------------------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c index 1f805fde5fd4..a88fefc0cc0a 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/perf/util/debugfs.c @@ -130,6 +130,7 @@ char *debugfs_mount(const char *mountpoint) /* save the mountpoint */ strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); + debugfs_found = 1; return debugfs_mountpoint; } diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index dfef238ce158..535176dc95b6 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -38,6 +38,7 @@ #include "../perf.h" #include "trace-event.h" +#include "debugfs.h" #define VERSION "0.5" @@ -102,32 +103,12 @@ void *malloc_or_die(unsigned int size) static const char *find_debugfs(void) { - static char debugfs[MAX_PATH+1]; - static int debugfs_found; - FILE *fp; - struct mntent *m; - - if (debugfs_found) - return debugfs; - - fp = setmntent("/proc/mounts", "r"); - if (!fp) - die("Can't open /proc/mounts for read"); - - while ((m = getmntent(fp)) != NULL) { - if (strcmp(m->mnt_type, "debugfs") == 0) { - strcpy(debugfs, m->mnt_dir); - debugfs_found = 1; - break; - } - } - - endmntent(fp); + const char *path = debugfs_mount(NULL); - if (!debugfs_found) - die("debugfs not mounted, please mount"); + if (!path) + die("Your kernel not support debugfs filesystem"); - return debugfs; + return path; } /* -- GitLab From 9967411e5b324a908e344d6ce66b77bd5d372c3e Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Mon, 28 Dec 2009 16:49:38 +0800 Subject: [PATCH 0207/3892] perf trace: Fix forgotten close of file/dir Signed-off-by: Xiao Guangrong Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Clark Williams Cc: John Kacur LKML-Reference: <4B387122.7090801@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-info.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 535176dc95b6..407fd65b6cdb 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -253,6 +253,8 @@ static void read_header_files(void) write_or_die("header_page", 12); write_or_die(&size, 8); check_size = copy_file_fd(fd); + close(fd); + if (size != check_size) die("wrong size for '%s' size=%lld read=%lld", path, size, check_size); @@ -271,6 +273,7 @@ static void read_header_files(void) if (size != check_size) die("wrong size for '%s'", path); put_tracing_file(path); + close(fd); } static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) @@ -337,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) free(format); } + closedir(dir); } static void read_ftrace_files(struct tracepoint_path *tps) @@ -407,6 +411,7 @@ static void read_event_files(struct tracepoint_path *tps) free(sys); } + closedir(dir); put_tracing_file(path); } -- GitLab From 39d997b514e12d5aff0dca206eb8996b3957927e Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 21 Dec 2009 16:20:16 -0800 Subject: [PATCH 0208/3892] x86, core: Optimize hweight32() Optimize hweight32 by using the same technique in hweight64. The proof of this technique can be found in the commit log for f9b4192923fa6e38331e88214b1fe5fc21583fcc ("bitops: hweight() speedup"). The userspace benchmark on x86_32 showed 20% speedup with bitmap_weight() which uses hweight32 to count bits for each unsigned long on 32bit architectures. int main(void) { #define SZ (1024 * 1024 * 512) static DECLARE_BITMAP(bitmap, SZ) = { [0 ... 100] = 1, }; return bitmap_weight(bitmap, SZ); } Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Cc: Linus Torvalds LKML-Reference: <1258603932-4590-1-git-send-email-akinobu.mita@gmail.com> [ only x86 sets ARCH_HAS_FAST_MULTIPLIER so we do this via the x86 tree] Signed-off-by: Ingo Molnar --- lib/hweight.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/hweight.c b/lib/hweight.c index 389424ecb129..63ee4eb1228d 100644 --- a/lib/hweight.c +++ b/lib/hweight.c @@ -11,11 +11,18 @@ unsigned int hweight32(unsigned int w) { +#ifdef ARCH_HAS_FAST_MULTIPLIER + w -= (w >> 1) & 0x55555555; + w = (w & 0x33333333) + ((w >> 2) & 0x33333333); + w = (w + (w >> 4)) & 0x0f0f0f0f; + return (w * 0x01010101) >> 24; +#else unsigned int res = w - ((w >> 1) & 0x55555555); res = (res & 0x33333333) + ((res >> 2) & 0x33333333); res = (res + (res >> 4)) & 0x0F0F0F0F; res = res + (res >> 8); return (res + (res >> 16)) & 0x000000FF; +#endif } EXPORT_SYMBOL(hweight32); -- GitLab From d894837f23f491aa7ed167aae767fc07cfe6e6e6 Mon Sep 17 00:00:00 2001 From: Simon Kagstrom Date: Wed, 23 Dec 2009 11:08:18 +0100 Subject: [PATCH 0209/3892] sched: might_sleep(): Make file parameter const char * Fixes a warning when building with g++: warning: deprecated conversion from string constant to 'char*' And the file parameter use is constant, so mark it as such. Signed-off-by: Simon Kagstrom Cc: peterz@infradead.org LKML-Reference: <20091223110818.442d848e@marrow.netinsight.se> Signed-off-by: Ingo Molnar --- include/linux/kernel.h | 5 +++-- kernel/sched.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3fc9f5aab5f8..785d7d1099d4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -124,7 +124,7 @@ extern int _cond_resched(void); #endif #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP - void __might_sleep(char *file, int line, int preempt_offset); + void __might_sleep(const char *file, int line, int preempt_offset); /** * might_sleep - annotation for functions that can sleep * @@ -138,7 +138,8 @@ extern int _cond_resched(void); # define might_sleep() \ do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0) #else - static inline void __might_sleep(char *file, int line, int preempt_offset) { } + static inline void __might_sleep(const char *file, int line, + int preempt_offset) { } # define might_sleep() do { might_resched(); } while (0) #endif diff --git a/kernel/sched.c b/kernel/sched.c index c535cc4f6428..64298a52eaa6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -9694,7 +9694,7 @@ static inline int preempt_count_equals(int preempt_offset) return (nested == PREEMPT_INATOMIC_BASE + preempt_offset); } -void __might_sleep(char *file, int line, int preempt_offset) +void __might_sleep(const char *file, int line, int preempt_offset) { #ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ -- GitLab From ea52bf260ecbb175339af3178c15788df21b7516 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 27 Dec 2009 18:48:29 -0500 Subject: [PATCH 0210/3892] ALSA: hda: Add powerdown for Analog Devices HDA codecs This patch ports powerdown fixes to AD198x. Currently we only turn off Front and HP for suspend, but this is easily extended for additional nids. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 45ee352df329..cecd3c108990 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -441,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec) return 0; } +static inline void ad198x_shutup(struct hda_codec *codec) +{ + snd_hda_shutup_pins(codec); +} + static void ad198x_free_kctls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -454,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec) snd_array_free(&spec->kctls); } +static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, + hda_nid_t hp) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, + !spec->inv_eapd ? 0x00 : 0x02); + snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, + !spec->inv_eapd ? 0x00 : 0x02); +} + +static void ad198x_power_eapd(struct hda_codec *codec) +{ + /* We currently only handle front, HP */ + switch (codec->vendor_id) { + case 0x11d41882: + case 0x11d4882a: + case 0x11d41884: + case 0x11d41984: + case 0x11d41883: + case 0x11d4184a: + case 0x11d4194a: + case 0x11d4194b: + ad198x_power_eapd_write(codec, 0x12, 0x11); + break; + case 0x11d41981: + case 0x11d41983: + ad198x_power_eapd_write(codec, 0x05, 0x06); + break; + case 0x11d41986: + ad198x_power_eapd_write(codec, 0x1b, 0x1a); + break; + case 0x11d41988: + case 0x11d4198b: + case 0x11d4989a: + case 0x11d4989b: + ad198x_power_eapd_write(codec, 0x29, 0x22); + break; + } +} + static void ad198x_free(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -461,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec) if (!spec) return; + ad198x_shutup(codec); ad198x_free_kctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); } +#ifdef SND_HDA_NEEDS_RESUME +static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) +{ + ad198x_shutup(codec); + ad198x_power_eapd(codec); + return 0; +} + +static int ad198x_resume(struct hda_codec *codec) +{ + ad198x_init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + return 0; +} +#endif + static struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, @@ -474,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = { #ifdef CONFIG_SND_HDA_POWER_SAVE .check_power_status = ad198x_check_power_status, #endif +#ifdef SND_HDA_NEEDS_RESUME + .suspend = ad198x_suspend, + .resume = ad198x_resume, +#endif + .reboot_notify = ad198x_shutup, }; -- GitLab From c97259df3f2e163c72f4d0685c61fb2e026dc989 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 27 Dec 2009 18:52:08 -0500 Subject: [PATCH 0211/3892] ALSA: hda: Refactor powerdown for Realtek HDA codecs This patch converts the alc889 Aspire-specific powerdown to a generic one. Like the previous effort, it currently only handles Front and PCM but can be easily extended to cover other nids. The existing hook for alc889 Aspire-specific remains enabled. Upon further testing, I've added its use for ALC861_AUTO as well. Following patches will enable them for other quirks. Tested-by: Dr. David Alan Gilbert Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 60 ++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cd6d139b4fd5..141ff446104a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -338,7 +338,7 @@ struct alc_spec { void (*init_hook)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); #ifdef CONFIG_SND_HDA_POWER_SAVE - void (*power_hook)(struct hda_codec *codec, int power); + void (*power_hook)(struct hda_codec *codec); #endif /* for pin sensing */ @@ -391,7 +391,7 @@ struct alc_config_preset { void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_amp_list *loopbacks; - void (*power_hook)(struct hda_codec *codec, int power); + void (*power_hook)(struct hda_codec *codec); #endif }; @@ -1835,16 +1835,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x1b; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static void alc889_power_eapd(struct hda_codec *codec, int power) -{ - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); -} -#endif - /* * ALC880 3-stack model * @@ -3725,12 +3715,40 @@ static void alc_free(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE +static void alc_power_eapd(struct hda_codec *codec) +{ + /* We currently only handle front, HP */ + switch (codec->vendor_id) { + case 0x10ec0260: + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0862: + case 0x10ec0889: + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + break; + } +} + static int alc_suspend(struct hda_codec *codec, pm_message_t state) { struct alc_spec *spec = codec->spec; alc_shutup(codec); if (spec && spec->power_hook) - spec->power_hook(codec, 0); + spec->power_hook(codec); return 0; } #endif @@ -3738,16 +3756,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) #ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { -#ifdef CONFIG_SND_HDA_POWER_SAVE - struct alc_spec *spec = codec->spec; -#endif codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (spec && spec->power_hook) - spec->power_hook(codec, 1); -#endif return 0; } #endif @@ -3767,6 +3778,7 @@ static struct hda_codec_ops alc_patch_ops = { .suspend = alc_suspend, .check_power_status = alc_check_power_status, #endif + .reboot_notify = alc_shutup, }; @@ -9547,7 +9559,7 @@ static struct alc_config_preset alc882_presets[] = { .setup = alc889_acer_aspire_8930g_setup, .init_hook = alc_automute_amp, #ifdef CONFIG_SND_HDA_POWER_SAVE - .power_hook = alc889_power_eapd, + .power_hook = alc_power_eapd, #endif }, [ALC888_ACER_ASPIRE_7730G] = { @@ -14984,8 +14996,12 @@ static int patch_alc861(struct hda_codec *codec) spec->vmaster_nid = 0x03; codec->patch_ops = alc_patch_ops; - if (board_config == ALC861_AUTO) + if (board_config == ALC861_AUTO) { spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = alc_power_eapd; +#endif + } #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; -- GitLab From 7d2b451e65d255427c108e990507964ac39c13ee Mon Sep 17 00:00:00 2001 From: Sergiy Kovalchuk Date: Sun, 27 Dec 2009 09:13:41 -0800 Subject: [PATCH 0212/3892] ALSA: usb-audio - Added functionality for E-mu 0404USB/0202USB/TrackerPre Added functionality: 1) Extension Units support (all XU settings now available at alsamixer, kmix, etc): - "AnalogueIn soft limiter" switch; - "Sample rate" selector (values 0,1,2,3,4,5 corresponds to 44.1 48 ... 192 kHz); - "DigitalIn CLK source" selector (internal/external) (**); - "DigitalOut format SPDIF/AC3" switch (**); (**)E-mu-0404usb only. 2) Automatic device sample rate adjustment depending on substream samplerate for both capture and playback substream. [minor coding-style fixes by tiwai] Signed-off-by: Sergiy Kovalchuk Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 49 +++++++++++++++++++++++++++++ sound/usb/usbaudio.h | 13 ++++++++ sound/usb/usbmixer.c | 75 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 133 insertions(+), 4 deletions(-) diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 31b63ea098b7..286fa14e48bd 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1270,6 +1270,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, return 0; } +/* + * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, + * not for interface. + */ +static void set_format_emu_quirk(struct snd_usb_substream *subs, + struct audioformat *fmt) +{ + unsigned char emu_samplerate_id = 0; + + /* When capture is active + * sample rate shouldn't be changed + * by playback substream + */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) + return; + } + + switch (fmt->rate_min) { + case 48000: + emu_samplerate_id = EMU_QUIRK_SR_48000HZ; + break; + case 88200: + emu_samplerate_id = EMU_QUIRK_SR_88200HZ; + break; + case 96000: + emu_samplerate_id = EMU_QUIRK_SR_96000HZ; + break; + case 176400: + emu_samplerate_id = EMU_QUIRK_SR_176400HZ; + break; + case 192000: + emu_samplerate_id = EMU_QUIRK_SR_192000HZ; + break; + default: + emu_samplerate_id = EMU_QUIRK_SR_44100HZ; + break; + } + snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +} + /* * find a matching format and set up the interface */ @@ -1383,6 +1424,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) subs->cur_audiofmt = fmt; + switch (subs->stream->chip->usb_id) { + case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ + case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ + case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ + set_format_emu_quirk(subs, fmt); + break; + } + #if 0 printk(KERN_DEBUG "setting done: format = %d, rate = %d..%d, channels = %d\n", diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 9826337c76b8..152216738cce 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -208,6 +208,16 @@ struct snd_usb_midi_endpoint_info { /* */ +/*E-mu USB samplerate control quirk*/ +enum { + EMU_QUIRK_SR_44100HZ = 0, + EMU_QUIRK_SR_48000HZ, + EMU_QUIRK_SR_88200HZ, + EMU_QUIRK_SR_96000HZ, + EMU_QUIRK_SR_176400HZ, + EMU_QUIRK_SR_192000HZ +}; + #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) @@ -233,6 +243,9 @@ void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id); + /* * retrieve usb_interface descriptor from the host interface * (conditional for compatibility with the older API) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220b99c6..f5596cfdbde1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -186,6 +186,21 @@ enum { USB_PROC_DCR_RELEASE = 6, }; +/*E-mu 0202(0404) eXtension Unit(XU) control*/ +enum { + USB_XU_CLOCK_RATE = 0xe301, + USB_XU_CLOCK_SOURCE = 0xe302, + USB_XU_DIGITAL_IO_STATUS = 0xe303, + USB_XU_DEVICE_OPTIONS = 0xe304, + USB_XU_DIRECT_MONITORING = 0xe305, + USB_XU_METERING = 0xe306 +}; +enum { + USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ + USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ + USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ + USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ +}; /* * manual mapping of mixer names @@ -1330,7 +1345,32 @@ static struct procunit_info procunits[] = { { USB_PROC_DCR, "DCR", dcr_proc_info }, { 0 }, }; - +/* + * predefined data for extension units + */ +static struct procunit_value_info clock_rate_xu_info[] = { + { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, + { 0 } +}; +static struct procunit_value_info clock_source_xu_info[] = { + { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info spdif_format_xu_info[] = { + { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info soft_limit_xu_info[] = { + { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_info extunits[] = { + { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, + { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, + { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, + { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, + { 0 } +}; /* * build a processing/extension unit */ @@ -1391,8 +1431,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned cval->max = dsc[15]; cval->res = 1; cval->initialized = 1; - } else - get_min_max(cval, valinfo->min_value); + } else { + if (type == USB_XU_CLOCK_RATE) { + /* E-Mu USB 0404/0202/TrackerPre + * samplerate control quirk + */ + cval->min = 0; + cval->max = 5; + cval->res = 1; + cval->initialized = 1; + } else + get_min_max(cval, valinfo->min_value); + } kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { @@ -1433,7 +1483,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) { - return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); + return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); } @@ -2109,6 +2159,23 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) return 0; } +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id) +{ + struct usb_mixer_interface *mixer; + struct usb_mixer_elem_info *cval; + int unitid = 12; /* SamleRate ExtensionUnit ID */ + + list_for_each_entry(mixer, &chip->mixer_list, list) { + cval = mixer->id_elems[unitid]; + if (cval) { + set_cur_ctl_value(cval, cval->control << 8, samplerate_id); + snd_usb_mixer_notify_id(mixer, unitid); + } + break; + } +} + int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error) { -- GitLab From adc8d31326c32a2a1e145ab80accbc3c6570b117 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 27 Dec 2009 12:19:57 -0500 Subject: [PATCH 0213/3892] ALSA: usb-audio: make buffer pointer based on bytes instead on frames Since there are devices that do not align the size of their data packets to frame boundaries, the driver needs to be able to keep track of partial frames. This patch prepares for support for such devices by changing the hwptr_done variable from a frame counter to a byte counter. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 76 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 286fa14e48bd..8fcb5d5a94b6 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -173,7 +173,7 @@ struct snd_usb_substream { unsigned int running: 1; /* running status */ - unsigned int hwptr_done; /* processed frame position in the buffer */ + unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ @@ -342,7 +342,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs, unsigned long flags; unsigned char *cp; int i; - unsigned int stride, len, oldptr; + unsigned int stride, frames, bytes, oldptr; int period_elapsed = 0; stride = runtime->frame_bits >> 3; @@ -353,29 +353,28 @@ static int retire_capture_urb(struct snd_usb_substream *subs, snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } - len = urb->iso_frame_desc[i].actual_length / stride; - if (! len) - continue; + frames = urb->iso_frame_desc[i].actual_length / stride; + bytes = frames * stride; /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; - subs->hwptr_done += len; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - subs->transfer_done += len; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; period_elapsed = 1; } spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ - if (oldptr + len > runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - oldptr; - unsigned int blen = cnt * stride; - memcpy(runtime->dma_area + oldptr * stride, cp, blen); - memcpy(runtime->dma_area, cp + blen, len * stride - blen); + if (oldptr + bytes > runtime->buffer_size * stride) { + unsigned int bytes1 = + runtime->buffer_size * stride - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); } else { - memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); + memcpy(runtime->dma_area + oldptr, cp, bytes); } } if (period_elapsed) @@ -562,24 +561,24 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { - int i, stride, offs; - unsigned int counts; + int i, stride; + unsigned int counts, frames, bytes; unsigned long flags; int period_elapsed = 0; struct snd_urb_ctx *ctx = urb->context; stride = runtime->frame_bits >> 3; - offs = 0; + frames = 0; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); for (i = 0; i < ctx->packets; i++) { counts = snd_usb_audio_next_packet_size(subs); /* set up descriptor */ - urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].offset = frames * stride; urb->iso_frame_desc[i].length = counts * stride; - offs += counts; + frames += counts; urb->number_of_packets++; subs->transfer_done += counts; if (subs->transfer_done >= runtime->period_size) { @@ -589,7 +588,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (subs->transfer_done > 0) { /* FIXME: fill-max mode is not * supported yet */ - offs -= subs->transfer_done; + frames -= subs->transfer_done; counts -= subs->transfer_done; urb->iso_frame_desc[i].length = counts * stride; @@ -599,7 +598,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (i < ctx->packets) { /* add a transfer delimiter */ urb->iso_frame_desc[i].offset = - offs * stride; + frames * stride; urb->iso_frame_desc[i].length = 0; urb->number_of_packets++; } @@ -609,26 +608,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (period_elapsed) /* finish at the period boundary */ break; } - if (subs->hwptr_done + offs > runtime->buffer_size) { + bytes = frames * stride; + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { /* err, the transferred area goes over buffer boundary. */ - unsigned int len = runtime->buffer_size - subs->hwptr_done; + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - len * stride); - memcpy(urb->transfer_buffer + len * stride, - runtime->dma_area, - (offs - len) * stride); + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + bytes1, + runtime->dma_area, bytes - bytes1); } else { memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - offs * stride); + runtime->dma_area + subs->hwptr_done, bytes); } - subs->hwptr_done += offs; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - runtime->delay += offs; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + runtime->delay += frames; spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer_length = offs * stride; + urb->transfer_buffer_length = bytes; if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); return 0; @@ -901,18 +899,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs) /* - * return the current pcm pointer. just return the hwptr_done value. + * return the current pcm pointer. just based on the hwptr_done value. */ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs; - snd_pcm_uframes_t hwptr_done; + unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; spin_unlock(&subs->lock); - return hwptr_done; + return hwptr_done / (substream->runtime->frame_bits >> 3); } -- GitLab From 98e89f606c38a310a20342f90e0c453e6afadf18 Mon Sep 17 00:00:00 2001 From: "John S. Gruber" Date: Sun, 27 Dec 2009 12:19:58 -0500 Subject: [PATCH 0214/3892] ALSA: usb-audio: relax urb data align. restriction HVR-950Q and HVR-850 only Addressing audio quality problem. In sound/usb/usbaudio.c, for the Hauppage HVR-950Q and HVR-850 only, change retire_capture_urb to allow transfers on audio sub-slot boundaries rather than audio slots boundaries. With these devices the left and right channel samples can be split between two different urbs. Throwing away extra channel samples causes a sound quality problem for stereo streams as the left and right channels are swapped repeatedly, perhaps many times per second. Urbs unaligned on sub-slot boundaries are still truncated to the next lowest stride (audio slot) to retain synchronization on samples even though left/right channel synchronization may be lost in this case. Detect the quirk using a case statement in snd_usb_audio_probe. BugLink: https://bugs.launchpad.net/ubuntu/+bug/495745 Signed-off-by: John S. Gruber Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 31 +++++++++++++++++++++++++++++-- sound/usb/usbaudio.h | 1 + 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8fcb5d5a94b6..617515f6ec7b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -169,6 +169,7 @@ struct snd_usb_substream { unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ + unsigned int txfr_quirk:1; /* allow sub-frame alignment */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int running: 1; /* running status */ @@ -353,14 +354,25 @@ static int retire_capture_urb(struct snd_usb_substream *subs, snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } - frames = urb->iso_frame_desc[i].actual_length / stride; - bytes = frames * stride; + bytes = urb->iso_frame_desc[i].actual_length; + frames = bytes / stride; + if (!subs->txfr_quirk) + bytes = frames * stride; + if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + int oldbytes = bytes; +#endif + bytes = frames * stride; + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", + oldbytes, bytes); + } /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; subs->hwptr_done += bytes; if (subs->hwptr_done >= runtime->buffer_size * stride) subs->hwptr_done -= runtime->buffer_size * stride; + frames = (bytes + (oldptr % stride)) / stride; subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; @@ -2238,6 +2250,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo subs->stream = as; subs->direction = stream; subs->dev = as->chip->dev; + subs->txfr_quirk = as->chip->txfr_quirk; if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { subs->ops = audio_urb_ops[stream]; } else { @@ -3618,6 +3631,20 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } + switch (chip->usb_id) { + case USB_ID(0x2040, 0x7200): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7221): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7222): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7223): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7224): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7225): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7230): /* Hauppage hvr850 */ + case USB_ID(0x2040, 0x7250): /* Hauppage hvr950Q */ + chip->txfr_quirk = 1; + break; + default: + chip->txfr_quirk = 0; + } err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 152216738cce..d180554b81f0 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -125,6 +125,7 @@ struct snd_usb_audio { struct snd_card *card; u32 usb_id; int shutdown; + unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ int num_interfaces; int num_suspended_intf; -- GitLab From 52a7a5835173af61b9f6c3038212370d9717526f Mon Sep 17 00:00:00 2001 From: "John S. Gruber" Date: Sun, 27 Dec 2009 12:19:59 -0500 Subject: [PATCH 0215/3892] ALSA: usb-audio: use usbquirk.h for detection of HVR-950Q/850 Detect the HVR-950Q HVR-850 urb data alignment quirk using usbquirk.h rather than using a case statement in snd_usb_audio_probe. Signed-off-by: John S. Gruber Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 30 +++++------ sound/usb/usbaudio.h | 1 + sound/usb/usbquirks.h | 114 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 15 deletions(-) diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 617515f6ec7b..4ada98e16309 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3203,6 +3203,18 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip, return 0; } +/* + * Allow alignment on audio sub-slot (channel samples) rather than + * on audio slots (audio frames) + */ +static int create_align_transfer_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) +{ + chip->txfr_quirk = 1; + return 1; /* Continue with creating streams and mixer */ +} + /* * boot quirks @@ -3377,7 +3389,8 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, - [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk + [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, + [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -3631,20 +3644,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } - switch (chip->usb_id) { - case USB_ID(0x2040, 0x7200): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7221): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7222): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7223): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7224): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7225): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7230): /* Hauppage hvr850 */ - case USB_ID(0x2040, 0x7250): /* Hauppage hvr950Q */ - chip->txfr_quirk = 1; - break; - default: - chip->txfr_quirk = 0; - } + chip->txfr_quirk = 0; err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index d180554b81f0..9d8cea48fc5f 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -161,6 +161,7 @@ enum quirk_type { QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, QUIRK_AUDIO_EDIROL_UAXX, + QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_TYPE_COUNT }; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index bd6706c2d534..65bbd22f2e0c 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -2074,6 +2074,120 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Hauppauge HVR-950Q and HVR-850 */ +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-850", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, -- GitLab From 4757968dbff3d43f373f08de973014a9bd41ef0a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Dec 2009 16:15:03 +0100 Subject: [PATCH 0216/3892] ALSA: Release v1.0.22.1 Signed-off-by: Jaroslav Kysela --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index 1f5d4872d623..7fed23442db8 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.22" +#define CONFIG_SND_VERSION "1.0.22.1" #define CONFIG_SND_DATE "" -- GitLab From 55489b6ed6801a42636fc3d4594b77dda9c409f2 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:31:33 +0100 Subject: [PATCH 0217/3892] mwl8k: firmware command code cleanup Sort firmware commands by command code, get rid of the 802_11 substring in all command names, and make sure that the command functions match the firmware command names. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 647 +++++++++++++++++------------------ 1 file changed, 323 insertions(+), 324 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 59d49159cf2a..b543defdde8a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -221,7 +221,7 @@ struct mwl8k_vif { u8 bssid[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; - /* Index into station database.Returned by update_sta_db call */ + /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; /* Non AMPDU sequence number assigned by driver */ @@ -1897,9 +1897,9 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, } /* - * CMD_802_11_GET_STAT. + * CMD_GET_STAT. */ -struct mwl8k_cmd_802_11_get_stat { +struct mwl8k_cmd_get_stat { struct mwl8k_cmd_pkt header; __le32 stats[64]; } __attribute__((packed)); @@ -1909,10 +1909,10 @@ struct mwl8k_cmd_802_11_get_stat { #define MWL8K_STAT_FCS_ERROR 24 #define MWL8K_STAT_RTS_SUCCESS 11 -static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { - struct mwl8k_cmd_802_11_get_stat *cmd; + struct mwl8k_cmd_get_stat *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -1939,9 +1939,9 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw, } /* - * CMD_802_11_RADIO_CONTROL. + * CMD_RADIO_CONTROL. */ -struct mwl8k_cmd_802_11_radio_control { +struct mwl8k_cmd_radio_control { struct mwl8k_cmd_pkt header; __le16 action; __le16 control; @@ -1949,10 +1949,10 @@ struct mwl8k_cmd_802_11_radio_control { } __attribute__((packed)); static int -mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) +mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_802_11_radio_control *cmd; + struct mwl8k_cmd_radio_control *cmd; int rc; if (enable == priv->radio_on && !force) @@ -1977,14 +1977,14 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) return rc; } -static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw) +static int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw) { - return mwl8k_cmd_802_11_radio_control(hw, 0, 0); + return mwl8k_cmd_radio_control(hw, 0, 0); } -static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw) +static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) { - return mwl8k_cmd_802_11_radio_control(hw, 1, 0); + return mwl8k_cmd_radio_control(hw, 1, 0); } static int @@ -1998,15 +1998,15 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) priv->radio_short_preamble = short_preamble; - return mwl8k_cmd_802_11_radio_control(hw, 1, 1); + return mwl8k_cmd_radio_control(hw, 1, 1); } /* - * CMD_802_11_RF_TX_POWER. + * CMD_RF_TX_POWER. */ #define MWL8K_TX_POWER_LEVEL_TOTAL 8 -struct mwl8k_cmd_802_11_rf_tx_power { +struct mwl8k_cmd_rf_tx_power { struct mwl8k_cmd_pkt header; __le16 action; __le16 support_level; @@ -2015,9 +2015,9 @@ struct mwl8k_cmd_802_11_rf_tx_power { __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; } __attribute__((packed)); -static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm) +static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) { - struct mwl8k_cmd_802_11_rf_tx_power *cmd; + struct mwl8k_cmd_rf_tx_power *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2159,85 +2159,61 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, } /* - * CMD_SET_SLOT. + * CMD_SET_AID. */ -struct mwl8k_cmd_set_slot { - struct mwl8k_cmd_pkt header; - __le16 action; - __u8 short_slot; -} __attribute__((packed)); - -static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) -{ - struct mwl8k_cmd_set_slot *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->short_slot = short_slot_time; - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); +#define MWL8K_FRAME_PROT_DISABLED 0x00 +#define MWL8K_FRAME_PROT_11G 0x07 +#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 +#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 - return rc; -} +struct mwl8k_cmd_update_set_aid { + struct mwl8k_cmd_pkt header; + __le16 aid; -/* - * CMD_MIMO_CONFIG. - */ -struct mwl8k_cmd_mimo_config { - struct mwl8k_cmd_pkt header; - __le32 action; - __u8 rx_antenna_map; - __u8 tx_antenna_map; + /* AP's MAC address (BSSID) */ + __u8 bssid[ETH_ALEN]; + __le16 protection_mode; + __u8 supp_rates[14]; } __attribute__((packed)); -static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) +static int +mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mwl8k_cmd_mimo_config *cmd; + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); + struct ieee80211_bss_conf *info = &mv_vif->bss_info; + struct mwl8k_cmd_update_set_aid *cmd; + u16 prot_mode; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); - cmd->rx_antenna_map = rx; - cmd->tx_antenna_map = tx; - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); - - return rc; -} - -/* - * CMD_ENABLE_SNIFFER. - */ -struct mwl8k_cmd_enable_sniffer { - struct mwl8k_cmd_pkt header; - __le32 action; -} __attribute__((packed)); + cmd->aid = cpu_to_le16(info->aid); -static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) -{ - struct mwl8k_cmd_enable_sniffer *cmd; - int rc; + memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; + if (info->use_cts_prot) { + prot_mode = MWL8K_FRAME_PROT_11G; + } else { + switch (info->ht_operation_mode & + IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; + break; + default: + prot_mode = MWL8K_FRAME_PROT_DISABLED; + break; + } + } + cmd->protection_mode = cpu_to_le16(prot_mode); - cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(!!enable); + memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2246,37 +2222,30 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) } /* - * CMD_SET_MAC_ADDR. + * CMD_SET_RATE. */ -struct mwl8k_cmd_set_mac_addr { - struct mwl8k_cmd_pkt header; - union { - struct { - __le16 mac_type; - __u8 mac_addr[ETH_ALEN]; - } mbss; - __u8 mac_addr[ETH_ALEN]; - }; +struct mwl8k_cmd_set_rate { + struct mwl8k_cmd_pkt header; + __u8 legacy_rates[14]; + + /* Bitmap for supported MCS codes. */ + __u8 mcs_set[16]; + __u8 reserved[16]; } __attribute__((packed)); -static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) +static int +mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_set_mac_addr *cmd; + struct mwl8k_cmd_set_rate *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - if (priv->ap_fw) { - cmd->mbss.mac_type = 0; - memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); - } else { - memcpy(cmd->mac_addr, mac, ETH_ALEN); - } + memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2284,29 +2253,40 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) return rc; } - /* - * CMD_SET_RATEADAPT_MODE. + * CMD_FINALIZE_JOIN. */ -struct mwl8k_cmd_set_rate_adapt_mode { +#define MWL8K_FJ_BEACON_MAXLEN 128 + +struct mwl8k_cmd_finalize_join { struct mwl8k_cmd_pkt header; - __le16 action; - __le16 mode; + __le32 sleep_interval; /* Number of beacon periods to sleep */ + __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; } __attribute__((packed)); -static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode) +static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, + int framelen, int dtim) { - struct mwl8k_cmd_set_rate_adapt_mode *cmd; + struct mwl8k_cmd_finalize_join *cmd; + struct ieee80211_mgmt *payload = frame; + int payload_len; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->mode = cpu_to_le16(mode); + cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); + + payload_len = framelen - ieee80211_hdrlen(payload->frame_control); + if (payload_len < 0) + payload_len = 0; + else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) + payload_len = MWL8K_FJ_BEACON_MAXLEN; + + memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2315,59 +2295,57 @@ static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode) } /* - * CMD_SET_WMM_MODE. + * CMD_SET_RTS_THRESHOLD. */ -struct mwl8k_cmd_set_wmm { +struct mwl8k_cmd_set_rts_threshold { struct mwl8k_cmd_pkt header; __le16 action; + __le16 threshold; } __attribute__((packed)); -static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable) +static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, + u16 action, u16 threshold) { - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_set_wmm *cmd; + struct mwl8k_cmd_set_rts_threshold *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); + cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(!!enable); + cmd->action = cpu_to_le16(action); + cmd->threshold = cpu_to_le16(threshold); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); - if (!rc) - priv->wmm_enabled = enable; - return rc; } /* - * CMD_SET_RTS_THRESHOLD. + * CMD_SET_SLOT. */ -struct mwl8k_cmd_rts_threshold { +struct mwl8k_cmd_set_slot { struct mwl8k_cmd_pkt header; __le16 action; - __le16 threshold; + __u8 short_slot; } __attribute__((packed)); -static int mwl8k_rts_threshold(struct ieee80211_hw *hw, - u16 action, u16 threshold) +static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) { - struct mwl8k_cmd_rts_threshold *cmd; + struct mwl8k_cmd_set_slot *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(action); - cmd->threshold = cpu_to_le16(threshold); + cmd->action = cpu_to_le16(MWL8K_CMD_SET); + cmd->short_slot = short_slot_time; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2426,9 +2404,9 @@ struct mwl8k_cmd_set_edca_params { MWL8K_SET_EDCA_AIFS) static int -mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, - __u16 cw_min, __u16 cw_max, - __u8 aifs, __u16 txop) +mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, + __u16 cw_min, __u16 cw_max, + __u8 aifs, __u16 txop) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_set_edca_params *cmd; @@ -2467,202 +2445,60 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, } /* - * CMD_FINALIZE_JOIN. + * CMD_SET_WMM_MODE. */ -#define MWL8K_FJ_BEACON_MAXLEN 128 - -struct mwl8k_cmd_finalize_join { +struct mwl8k_cmd_set_wmm_mode { struct mwl8k_cmd_pkt header; - __le32 sleep_interval; /* Number of beacon periods to sleep */ - __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; + __le16 action; } __attribute__((packed)); -static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, - int framelen, int dtim) +static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) { - struct mwl8k_cmd_finalize_join *cmd; - struct ieee80211_mgmt *payload = frame; - int payload_len; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_set_wmm_mode *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); - - payload_len = framelen - ieee80211_hdrlen(payload->frame_control); - if (payload_len < 0) - payload_len = 0; - else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) - payload_len = MWL8K_FJ_BEACON_MAXLEN; - - memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); + cmd->action = cpu_to_le16(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); - return rc; -} - -/* - * CMD_UPDATE_STADB. - */ -struct mwl8k_cmd_update_sta_db { - struct mwl8k_cmd_pkt header; - - /* See STADB_ACTION_TYPE */ - __le32 action; - - /* Peer MAC address */ - __u8 peer_addr[ETH_ALEN]; - - __le32 reserved; - - /* Peer info - valid during add/update. */ - struct peer_capability_info peer_info; -} __attribute__((packed)); - -static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, __u32 action) -{ - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - struct ieee80211_bss_conf *info = &mv_vif->bss_info; - struct mwl8k_cmd_update_sta_db *cmd; - struct peer_capability_info *peer_info; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - - cmd->action = cpu_to_le32(action); - peer_info = &cmd->peer_info; - memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); - - switch (action) { - case MWL8K_STA_DB_ADD_ENTRY: - case MWL8K_STA_DB_MODIFY_ENTRY: - /* Build peer_info block */ - peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; - peer_info->basic_caps = cpu_to_le16(info->assoc_capability); - memcpy(peer_info->legacy_rates, mwl8k_rateids, - sizeof(mwl8k_rateids)); - peer_info->interop = 1; - peer_info->amsdu_enabled = 0; - - rc = mwl8k_post_cmd(hw, &cmd->header); - if (rc == 0) - mv_vif->peer_id = peer_info->station_id; - - break; - - case MWL8K_STA_DB_DEL_ENTRY: - case MWL8K_STA_DB_FLUSH: - default: - rc = mwl8k_post_cmd(hw, &cmd->header); - if (rc == 0) - mv_vif->peer_id = 0; - break; - } - kfree(cmd); - - return rc; -} - -/* - * CMD_SET_AID. - */ -#define MWL8K_FRAME_PROT_DISABLED 0x00 -#define MWL8K_FRAME_PROT_11G 0x07 -#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 -#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 - -struct mwl8k_cmd_update_set_aid { - struct mwl8k_cmd_pkt header; - __le16 aid; - - /* AP's MAC address (BSSID) */ - __u8 bssid[ETH_ALEN]; - __le16 protection_mode; - __u8 supp_rates[14]; -} __attribute__((packed)); - -static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - struct ieee80211_bss_conf *info = &mv_vif->bss_info; - struct mwl8k_cmd_update_set_aid *cmd; - u16 prot_mode; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(info->aid); - - memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - - if (info->use_cts_prot) { - prot_mode = MWL8K_FRAME_PROT_11G; - } else { - switch (info->ht_operation_mode & - IEEE80211_HT_OP_MODE_PROTECTION) { - case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: - prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; - break; - case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: - prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; - break; - default: - prot_mode = MWL8K_FRAME_PROT_DISABLED; - break; - } - } - cmd->protection_mode = cpu_to_le16(prot_mode); - - memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); + if (!rc) + priv->wmm_enabled = enable; return rc; } /* - * CMD_SET_RATE. + * CMD_MIMO_CONFIG. */ -struct mwl8k_cmd_update_rateset { - struct mwl8k_cmd_pkt header; - __u8 legacy_rates[14]; - - /* Bitmap for supported MCS codes. */ - __u8 mcs_set[16]; - __u8 reserved[16]; +struct mwl8k_cmd_mimo_config { + struct mwl8k_cmd_pkt header; + __le32 action; + __u8 rx_antenna_map; + __u8 tx_antenna_map; } __attribute__((packed)); -static int mwl8k_update_rateset(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) { - struct mwl8k_cmd_update_rateset *cmd; + struct mwl8k_cmd_mimo_config *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); + cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); + cmd->rx_antenna_map = rx; + cmd->tx_antenna_map = tx; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2755,6 +2591,169 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, return rc; } +/* + * CMD_ENABLE_SNIFFER. + */ +struct mwl8k_cmd_enable_sniffer { + struct mwl8k_cmd_pkt header; + __le32 action; +} __attribute__((packed)); + +static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) +{ + struct mwl8k_cmd_enable_sniffer *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(!!enable); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + +/* + * CMD_SET_MAC_ADDR. + */ +struct mwl8k_cmd_set_mac_addr { + struct mwl8k_cmd_pkt header; + union { + struct { + __le16 mac_type; + __u8 mac_addr[ETH_ALEN]; + } mbss; + __u8 mac_addr[ETH_ALEN]; + }; +} __attribute__((packed)); + +static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) +{ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_set_mac_addr *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + if (priv->ap_fw) { + cmd->mbss.mac_type = 0; + memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); + } else { + memcpy(cmd->mac_addr, mac, ETH_ALEN); + } + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + +/* + * CMD_SET_RATEADAPT_MODE. + */ +struct mwl8k_cmd_set_rate_adapt_mode { + struct mwl8k_cmd_pkt header; + __le16 action; + __le16 mode; +} __attribute__((packed)); + +static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) +{ + struct mwl8k_cmd_set_rate_adapt_mode *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le16(MWL8K_CMD_SET); + cmd->mode = cpu_to_le16(mode); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + +/* + * CMD_UPDATE_STADB. + */ +struct mwl8k_cmd_update_stadb { + struct mwl8k_cmd_pkt header; + + /* See STADB_ACTION_TYPE */ + __le32 action; + + /* Peer MAC address */ + __u8 peer_addr[ETH_ALEN]; + + __le32 reserved; + + /* Peer info - valid during add/update. */ + struct peer_capability_info peer_info; +} __attribute__((packed)); + +static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, __u32 action) +{ + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); + struct ieee80211_bss_conf *info = &mv_vif->bss_info; + struct mwl8k_cmd_update_stadb *cmd; + struct peer_capability_info *peer_info; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(action); + peer_info = &cmd->peer_info; + memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); + + switch (action) { + case MWL8K_STA_DB_ADD_ENTRY: + case MWL8K_STA_DB_MODIFY_ENTRY: + /* Build peer_info block */ + peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; + peer_info->basic_caps = cpu_to_le16(info->assoc_capability); + memcpy(peer_info->legacy_rates, mwl8k_rateids, + sizeof(mwl8k_rateids)); + peer_info->interop = 1; + peer_info->amsdu_enabled = 0; + + rc = mwl8k_post_cmd(hw, &cmd->header); + if (rc == 0) + mv_vif->peer_id = peer_info->station_id; + + break; + + case MWL8K_STA_DB_DEL_ENTRY: + case MWL8K_STA_DB_FLUSH: + default: + rc = mwl8k_post_cmd(hw, &cmd->header); + if (rc == 0) + mv_vif->peer_id = 0; + break; + } + kfree(cmd); + + return rc; +} + /* * Interrupt handling. @@ -2836,11 +2835,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = mwl8k_fw_lock(hw); if (!rc) { - rc = mwl8k_cmd_802_11_radio_enable(hw); + rc = mwl8k_cmd_radio_enable(hw); if (!priv->ap_fw) { if (!rc) - rc = mwl8k_enable_sniffer(hw, 0); + rc = mwl8k_cmd_enable_sniffer(hw, 0); if (!rc) rc = mwl8k_cmd_set_pre_scan(hw); @@ -2851,10 +2850,10 @@ static int mwl8k_start(struct ieee80211_hw *hw) } if (!rc) - rc = mwl8k_cmd_setrateadaptmode(hw, 0); + rc = mwl8k_cmd_set_rateadapt_mode(hw, 0); if (!rc) - rc = mwl8k_set_wmm(hw, 0); + rc = mwl8k_cmd_set_wmm_mode(hw, 0); mwl8k_fw_unlock(hw); } @@ -2873,7 +2872,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int i; - mwl8k_cmd_802_11_radio_disable(hw); + mwl8k_cmd_radio_disable(hw); ieee80211_stop_queues(hw); @@ -2929,7 +2928,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); /* Set and save the mac address */ - mwl8k_set_mac_addr(hw, conf->mac_addr); + mwl8k_cmd_set_mac_addr(hw, conf->mac_addr); memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); /* Back pointer to parent config block */ @@ -2952,7 +2951,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, if (priv->vif == NULL) return; - mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); priv->vif = NULL; } @@ -2964,7 +2963,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) int rc; if (conf->flags & IEEE80211_CONF_IDLE) { - mwl8k_cmd_802_11_radio_disable(hw); + mwl8k_cmd_radio_disable(hw); priv->current_channel = NULL; return 0; } @@ -2973,7 +2972,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) return rc; - rc = mwl8k_cmd_802_11_radio_enable(hw); + rc = mwl8k_cmd_radio_enable(hw); if (rc) goto out; @@ -2985,7 +2984,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (conf->power_level > 18) conf->power_level = 18; - rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level); + rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); if (rc) goto out; @@ -3028,7 +3027,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); /* Install rates */ - rc = mwl8k_update_rateset(hw, vif); + rc = mwl8k_cmd_set_rate(hw, vif); if (rc) goto out; @@ -3049,7 +3048,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, goto out; /* Update peer rate info */ - rc = mwl8k_cmd_update_sta_db(hw, vif, + rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_MODIFY_ENTRY); if (rc) goto out; @@ -3066,7 +3065,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { - rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); + rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); memset(mwl8k_vif->bssid, 0, ETH_ALEN); @@ -3114,7 +3113,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, } if (!priv->sniffer_enabled) { - if (mwl8k_enable_sniffer(hw, 1)) + if (mwl8k_cmd_enable_sniffer(hw, 1)) return 0; priv->sniffer_enabled = true; } @@ -3161,7 +3160,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, return; if (priv->sniffer_enabled) { - mwl8k_enable_sniffer(hw, 0); + mwl8k_cmd_enable_sniffer(hw, 0); priv->sniffer_enabled = false; } @@ -3211,7 +3210,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); + return mwl8k_cmd_set_rts_threshold(hw, MWL8K_CMD_SET, value); } static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, @@ -3223,14 +3222,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { if (!priv->wmm_enabled) - rc = mwl8k_set_wmm(hw, 1); + rc = mwl8k_cmd_set_wmm_mode(hw, 1); if (!rc) - rc = mwl8k_set_edca_params(hw, queue, - params->cw_min, - params->cw_max, - params->aifs, - params->txop); + rc = mwl8k_cmd_set_edca_params(hw, queue, + params->cw_min, + params->cw_max, + params->aifs, + params->txop); mwl8k_fw_unlock(hw); } @@ -3259,7 +3258,7 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, static int mwl8k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - return mwl8k_cmd_802_11_get_stat(hw, stats); + return mwl8k_cmd_get_stat(hw, stats); } static const struct ieee80211_ops mwl8k_ops = { @@ -3302,7 +3301,7 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct sk_buff *skb = priv->beacon_skb; u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; - mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim); + mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim); dev_kfree_skb(skb); priv->beacon_skb = NULL; @@ -3531,14 +3530,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Turn radio off */ - rc = mwl8k_cmd_802_11_radio_disable(hw); + rc = mwl8k_cmd_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy)); goto err_stop_firmware; } /* Clear MAC address */ - rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + rc = mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); if (rc) { printk(KERN_ERR "%s: Cannot clear MAC address\n", wiphy_name(hw->wiphy)); -- GitLab From 99200a992e365a73dc67a6570524e5f3af4386dd Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:31:40 +0100 Subject: [PATCH 0218/3892] mwl8k: hw is never NULL in mwl8k_set_radio_preamble() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b543defdde8a..aba45ca43da7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1990,11 +1990,7 @@ static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) static int mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) { - struct mwl8k_priv *priv; - - if (hw == NULL || hw->priv == NULL) - return -EINVAL; - priv = hw->priv; + struct mwl8k_priv *priv = hw->priv; priv->radio_short_preamble = short_preamble; -- GitLab From 74726e729291131ac2b9ab7e0bd2e18b7b03970d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:31:52 +0100 Subject: [PATCH 0219/3892] mwl8k: get rid of the AMSDU check in the transmit path Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index aba45ca43da7..18542fba1f43 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -677,14 +677,6 @@ static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy) return (qos & qos_mask) | ((ack_policy & val_mask) << shift); } -static inline u16 mwl8k_qos_setbit_amsdu(u16 qos) -{ - u16 val_mask = 1 << 7; - - /* AMSDU present Bit 7 */ - return qos | val_mask; -} - static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len) { u16 val_mask = 0xff; @@ -1474,9 +1466,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) else qos = mwl8k_qos_setbit_ack(qos, MWL8K_TXD_ACK_POLICY_NORMAL); - - if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - qos = mwl8k_qos_setbit_amsdu(qos); } dma = pci_map_single(priv->pdev, skb->data, -- GitLab From e0493a8dd6351a114b53790dda6bd855ae73a85c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:00 +0100 Subject: [PATCH 0220/3892] mwl8k: inline qos field manipulation functions Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 51 +++++++----------------------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 18542fba1f43..8cbb52cc4269 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -658,35 +658,6 @@ struct peer_capability_info { __le16 amsdu_enabled; } __attribute__((packed)); -/* Inline functions to manipulate QoS field in data descriptor. */ -static inline u16 mwl8k_qos_setbit_eosp(u16 qos) -{ - u16 val_mask = 1 << 4; - - /* End of Service Period Bit 4 */ - return qos | val_mask; -} - -static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy) -{ - u16 val_mask = 0x3; - u8 shift = 5; - u16 qos_mask = ~(val_mask << shift); - - /* Ack Policy Bit 5-6 */ - return (qos & qos_mask) | ((ack_policy & val_mask) << shift); -} - -static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len) -{ - u16 val_mask = 0xff; - u8 shift = 8; - u16 qos_mask = ~(val_mask << shift); - - /* Queue Length Bits 8-15 */ - return (qos & qos_mask) | ((len & val_mask) << shift); -} - /* DMA header used by firmware and hardware. */ struct mwl8k_dma_data { __le16 fwlen; @@ -1145,16 +1116,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) * Packet transmission. */ -/* Transmit packet ACK policy */ -#define MWL8K_TXD_ACK_POLICY_NORMAL 0 -#define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 - #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 #define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 #define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 +#define MWL8K_QOS_QLEN_UNSPEC 0xff00 +#define MWL8K_QOS_ACK_POLICY_MASK 0x0060 +#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000 +#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060 +#define MWL8K_QOS_EOSP 0x0010 + struct mwl8k_tx_desc { __le32 status; __u8 data_rate; @@ -1451,21 +1424,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (ieee80211_is_mgmt(wh->frame_control) || ieee80211_is_ctl(wh->frame_control)) { txdatarate = 0; - qos = mwl8k_qos_setbit_eosp(qos); - /* Set Queue size to unspecified */ - qos = mwl8k_qos_setbit_qlen(qos, 0xff); + qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP; } else if (ieee80211_is_data(wh->frame_control)) { txdatarate = 1; if (is_multicast_ether_addr(wh->addr1)) txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; - /* Send pkt in an aggregate if AMPDU frame. */ + qos &= ~MWL8K_QOS_ACK_POLICY_MASK; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_BLOCKACK); + qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK; else - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); + qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } dma = pci_map_single(priv->pdev, skb->data, -- GitLab From 49eb691c8f48a29adfdfbdeb82433f1f8cb6524d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:13 +0100 Subject: [PATCH 0221/3892] mwl8k: initialize the mwl8k_info_tbl table using the MWL* enums Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8cbb52cc4269..5c849aa86139 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3267,14 +3267,14 @@ enum { }; static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { - { + [MWL8687] = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", .fw_image = "mwl8k/fmimage_8687.fw", .rxd_ops = &rxd_8687_ops, .modes = BIT(NL80211_IFTYPE_STATION), }, - { + [MWL8366] = { .part_name = "88w8366", .helper_image = "mwl8k/helper_8366.fw", .fw_image = "mwl8k/fmimage_8366.fw", -- GitLab From 647ca6b01a5289948e970ea7c1f656f9d90b0a27 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:20 +0100 Subject: [PATCH 0222/3892] mwl8k: add 2.4GHz channels 12, 13 and 14 Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5c849aa86139..c54f8305df18 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -242,6 +242,9 @@ static const struct ieee80211_channel mwl8k_channels[] = { { .center_freq = 2452, .hw_value = 9, }, { .center_freq = 2457, .hw_value = 10, }, { .center_freq = 2462, .hw_value = 11, }, + { .center_freq = 2467, .hw_value = 12, }, + { .center_freq = 2472, .hw_value = 13, }, + { .center_freq = 2484, .hw_value = 14, }, }; static const struct ieee80211_rate mwl8k_rates[] = { -- GitLab From 22be40d9c53faa10d03a679160e0854ad115b610 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:38 +0100 Subject: [PATCH 0223/3892] mwl8k: get rid of the struct mwl8k_firmware abstraction Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c54f8305df18..19fe7124d93a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -126,15 +126,6 @@ struct mwl8k_tx_queue { struct sk_buff **skb; }; -/* Pointers to the firmware data and meta information about it. */ -struct mwl8k_firmware { - /* Boot helper code */ - struct firmware *helper; - - /* Microcode */ - struct firmware *ucode; -}; - struct mwl8k_priv { void __iomem *sram; void __iomem *regs; @@ -147,7 +138,8 @@ struct mwl8k_priv { struct rxd_ops *rxd_ops; /* firmware files and meta data */ - struct mwl8k_firmware fw; + struct firmware *fw_helper; + struct firmware *fw_ucode; /* firmware access */ struct mutex fw_mutex; @@ -358,8 +350,8 @@ static void mwl8k_release_fw(struct firmware **fw) static void mwl8k_release_firmware(struct mwl8k_priv *priv) { - mwl8k_release_fw(&priv->fw.ucode); - mwl8k_release_fw(&priv->fw.helper); + mwl8k_release_fw(&priv->fw_ucode); + mwl8k_release_fw(&priv->fw_helper); } /* Request fw image */ @@ -380,7 +372,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) int rc; if (di->helper_image != NULL) { - rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper); + rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper); if (rc) { printk(KERN_ERR "%s: Error requesting helper " "firmware file %s\n", pci_name(priv->pdev), @@ -389,11 +381,11 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) } } - rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode); + rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode); if (rc) { printk(KERN_ERR "%s: Error requesting firmware file %s\n", pci_name(priv->pdev), di->fw_image); - mwl8k_release_fw(&priv->fw.helper); + mwl8k_release_fw(&priv->fw_helper); return rc; } @@ -554,13 +546,13 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, static int mwl8k_load_firmware(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; - struct firmware *fw = priv->fw.ucode; + struct firmware *fw = priv->fw_ucode; struct mwl8k_device_info *di = priv->device_info; int rc; int loops; if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { - struct firmware *helper = priv->fw.helper; + struct firmware *helper = priv->fw_helper; if (helper == NULL) { printk(KERN_ERR "%s: helper image needed but none " -- GitLab From be695fc4f0a7ff9c9f91d59536b029b781cfea62 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:46 +0100 Subject: [PATCH 0224/3892] mwl8k: do rx/tx ring initialisation after loading firmware Whether the firmware we have loaded is AP or STA firmware decides which receive descriptor format we have to use. Therefore, move rx/tx ring initialisation to be after firmware loading. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 104 +++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 19fe7124d93a..0ae56cb6b0b3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -127,20 +127,22 @@ struct mwl8k_tx_queue { }; struct mwl8k_priv { - void __iomem *sram; - void __iomem *regs; struct ieee80211_hw *hw; - struct pci_dev *pdev; struct mwl8k_device_info *device_info; - bool ap_fw; - struct rxd_ops *rxd_ops; - /* firmware files and meta data */ + void __iomem *sram; + void __iomem *regs; + + /* firmware */ struct firmware *fw_helper; struct firmware *fw_ucode; + /* hardware/firmware parameters */ + bool ap_fw; + struct rxd_ops *rxd_ops; + /* firmware access */ struct mutex fw_mutex; struct task_struct *fw_mutex_owner; @@ -547,7 +549,6 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct firmware *fw = priv->fw_ucode; - struct mwl8k_device_info *di = priv->device_info; int rc; int loops; @@ -579,7 +580,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) return rc; } - if (di->modes & BIT(NL80211_IFTYPE_AP)) + if (priv->device_info->modes & BIT(NL80211_IFTYPE_AP)) iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR); else iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); @@ -3300,6 +3301,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, printed_version = 1; } + rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "%s: Cannot enable new PCI device\n", @@ -3316,6 +3318,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, pci_set_master(pdev); + hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); if (hw == NULL) { printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); @@ -3323,17 +3326,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_reg; } + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + priv = hw->priv; priv->hw = hw; priv->pdev = pdev; priv->device_info = &mwl8k_info_tbl[id->driver_data]; - priv->rxd_ops = priv->device_info->rxd_ops; - priv->sniffer_enabled = false; - priv->wmm_enabled = false; - priv->pending_tx_pkts = 0; - SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); priv->sram = pci_iomap(pdev, 0, 0x10000); if (priv->sram == NULL) { @@ -3356,6 +3356,37 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } } + + /* Reset firmware and hardware */ + mwl8k_hw_reset(priv); + + /* Ask userland hotplug daemon for the device firmware */ + rc = mwl8k_request_firmware(priv); + if (rc) { + printk(KERN_ERR "%s: Firmware files not found\n", + wiphy_name(hw->wiphy)); + goto err_stop_firmware; + } + + /* Load firmware into hardware */ + rc = mwl8k_load_firmware(hw); + if (rc) { + printk(KERN_ERR "%s: Cannot start firmware\n", + wiphy_name(hw->wiphy)); + goto err_stop_firmware; + } + + /* Reclaim memory once firmware is successfully loaded */ + mwl8k_release_firmware(priv); + + + priv->rxd_ops = priv->device_info->rxd_ops; + + priv->sniffer_enabled = false; + priv->wmm_enabled = false; + priv->pending_tx_pkts = 0; + + memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); priv->band.band = IEEE80211_BAND_2GHZ; priv->band.channels = priv->channels; @@ -3400,11 +3431,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Power management cookie */ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); if (priv->cookie == NULL) - goto err_iounmap; + goto err_stop_firmware; rc = mwl8k_rxq_init(hw, 0); if (rc) - goto err_iounmap; + goto err_free_cookie; rxq_refill(hw, 0, INT_MAX); mutex_init(&priv->fw_mutex); @@ -3435,28 +3466,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_queues; } - /* Reset firmware and hardware */ - mwl8k_hw_reset(priv); - - /* Ask userland hotplug daemon for the device firmware */ - rc = mwl8k_request_firmware(priv); - if (rc) { - printk(KERN_ERR "%s: Firmware files not found\n", - wiphy_name(hw->wiphy)); - goto err_free_irq; - } - - /* Load firmware into hardware */ - rc = mwl8k_load_firmware(hw); - if (rc) { - printk(KERN_ERR "%s: Cannot start firmware\n", - wiphy_name(hw->wiphy)); - goto err_stop_firmware; - } - - /* Reclaim memory once firmware is successfully loaded */ - mwl8k_release_firmware(priv); - /* * Temporarily enable interrupts. Initial firmware host * commands use interrupts and avoids polling. Disable @@ -3475,14 +3484,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", wiphy_name(hw->wiphy)); - goto err_stop_firmware; + goto err_free_irq; } /* Turn radio off */ rc = mwl8k_cmd_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy)); - goto err_stop_firmware; + goto err_free_irq; } /* Clear MAC address */ @@ -3490,7 +3499,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot clear MAC address\n", wiphy_name(hw->wiphy)); - goto err_stop_firmware; + goto err_free_irq; } /* Disable interrupts */ @@ -3501,7 +3510,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot register device\n", wiphy_name(hw->wiphy)); - goto err_stop_firmware; + goto err_free_irq; } printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", @@ -3513,10 +3522,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, return 0; -err_stop_firmware: - mwl8k_hw_reset(priv); - mwl8k_release_firmware(priv); - err_free_irq: iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); @@ -3526,11 +3531,16 @@ err_free_queues: mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); -err_iounmap: +err_free_cookie: if (priv->cookie != NULL) pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); +err_stop_firmware: + mwl8k_hw_reset(priv); + mwl8k_release_firmware(priv); + +err_iounmap: if (priv->regs != NULL) pci_iounmap(pdev, priv->regs); -- GitLab From 89a91f4f4cdae92daf3693d4852ae4958abb6c58 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:32:54 +0100 Subject: [PATCH 0225/3892] mwl8k: fix up AP vs. STA firmware image receive descriptor handling The receive descriptor ops that are currently marked as being for 8687 only are actually used for all STA firmware images, whereas the receive descriptor ops marked as 8366 are only used on 8366 when an AP firmware image is in use. Rename the receive descriptor ops to reflect this, use the STA ops unconditionally if the firmware image loaded reported the STA ready code, and rename the mwl8k_device_info::rxd_ops member to ap_rxd_ops to indicate that it should only be used if we are running on AP firmware. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 124 +++++++++++++++++------------------ 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 0ae56cb6b0b3..b20820a015cc 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -92,8 +92,7 @@ struct mwl8k_device_info { char *part_name; char *helper_image; char *fw_image; - struct rxd_ops *rxd_ops; - u16 modes; + struct rxd_ops *ap_rxd_ops; }; struct mwl8k_rx_queue { @@ -580,10 +579,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) return rc; } - if (priv->device_info->modes & BIT(NL80211_IFTYPE_AP)) - iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR); - else - iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); + iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); loops = 500000; do { @@ -720,9 +716,9 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) /* - * Packet reception for 88w8366. + * Packet reception for 88w8366 AP firmware. */ -struct mwl8k_rxd_8366 { +struct mwl8k_rxd_8366_ap { __le16 pkt_len; __u8 sq2; __u8 rate; @@ -740,23 +736,23 @@ struct mwl8k_rxd_8366 { __u8 rx_ctrl; } __attribute__((packed)); -#define MWL8K_8366_RATE_INFO_MCS_FORMAT 0x80 -#define MWL8K_8366_RATE_INFO_40MHZ 0x40 -#define MWL8K_8366_RATE_INFO_RATEID(x) ((x) & 0x3f) +#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80 +#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40 +#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f) -#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST 0x80 +#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 -static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr) +static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) { - struct mwl8k_rxd_8366 *rxd = _rxd; + struct mwl8k_rxd_8366_ap *rxd = _rxd; rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); - rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST; + rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST; } -static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len) +static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) { - struct mwl8k_rxd_8366 *rxd = _rxd; + struct mwl8k_rxd_8366_ap *rxd = _rxd; rxd->pkt_len = cpu_to_le16(len); rxd->pkt_phys_addr = cpu_to_le32(addr); @@ -765,12 +761,12 @@ static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len) } static int -mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status, - __le16 *qos) +mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, + __le16 *qos) { - struct mwl8k_rxd_8366 *rxd = _rxd; + struct mwl8k_rxd_8366_ap *rxd = _rxd; - if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST)) + if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST)) return -1; rmb(); @@ -779,11 +775,11 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status, status->signal = -rxd->rssi; status->noise = -rxd->noise_floor; - if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) { + if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) { status->flag |= RX_FLAG_HT; - if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ) + if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ) status->flag |= RX_FLAG_40MHZ; - status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate); + status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate); } else { int i; @@ -803,17 +799,17 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status, return le16_to_cpu(rxd->pkt_len); } -static struct rxd_ops rxd_8366_ops = { - .rxd_size = sizeof(struct mwl8k_rxd_8366), - .rxd_init = mwl8k_rxd_8366_init, - .rxd_refill = mwl8k_rxd_8366_refill, - .rxd_process = mwl8k_rxd_8366_process, +static struct rxd_ops rxd_8366_ap_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_8366_ap), + .rxd_init = mwl8k_rxd_8366_ap_init, + .rxd_refill = mwl8k_rxd_8366_ap_refill, + .rxd_process = mwl8k_rxd_8366_ap_process, }; /* - * Packet reception for 88w8687. + * Packet reception for STA firmware. */ -struct mwl8k_rxd_8687 { +struct mwl8k_rxd_sta { __le16 pkt_len; __u8 link_quality; __u8 noise_level; @@ -830,26 +826,26 @@ struct mwl8k_rxd_8687 { __u8 pad2[2]; } __attribute__((packed)); -#define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000 -#define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) -#define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) -#define MWL8K_8687_RATE_INFO_40MHZ 0x0004 -#define MWL8K_8687_RATE_INFO_SHORTGI 0x0002 -#define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001 +#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000 +#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) +#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) +#define MWL8K_STA_RATE_INFO_40MHZ 0x0004 +#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002 +#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 -#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02 +#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 -static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr) +static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) { - struct mwl8k_rxd_8687 *rxd = _rxd; + struct mwl8k_rxd_sta *rxd = _rxd; rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); - rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST; + rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST; } -static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len) +static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) { - struct mwl8k_rxd_8687 *rxd = _rxd; + struct mwl8k_rxd_sta *rxd = _rxd; rxd->pkt_len = cpu_to_le16(len); rxd->pkt_phys_addr = cpu_to_le32(addr); @@ -858,13 +854,13 @@ static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len) } static int -mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status, +mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, __le16 *qos) { - struct mwl8k_rxd_8687 *rxd = _rxd; + struct mwl8k_rxd_sta *rxd = _rxd; u16 rate_info; - if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST)) + if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST)) return -1; rmb(); @@ -874,16 +870,16 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status, status->signal = -rxd->rssi; status->noise = -rxd->noise_level; - status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info); - status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info); + status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info); + status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); - if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE) + if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) status->flag |= RX_FLAG_SHORTPRE; - if (rate_info & MWL8K_8687_RATE_INFO_40MHZ) + if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) status->flag |= RX_FLAG_40MHZ; - if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI) + if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) status->flag |= RX_FLAG_SHORT_GI; - if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT) + if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) status->flag |= RX_FLAG_HT; status->band = IEEE80211_BAND_2GHZ; @@ -894,11 +890,11 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status, return le16_to_cpu(rxd->pkt_len); } -static struct rxd_ops rxd_8687_ops = { - .rxd_size = sizeof(struct mwl8k_rxd_8687), - .rxd_init = mwl8k_rxd_8687_init, - .rxd_refill = mwl8k_rxd_8687_refill, - .rxd_process = mwl8k_rxd_8687_process, +static struct rxd_ops rxd_sta_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_sta), + .rxd_init = mwl8k_rxd_sta_init, + .rxd_refill = mwl8k_rxd_sta_refill, + .rxd_process = mwl8k_rxd_sta_process, }; @@ -3267,15 +3263,12 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", .fw_image = "mwl8k/fmimage_8687.fw", - .rxd_ops = &rxd_8687_ops, - .modes = BIT(NL80211_IFTYPE_STATION), }, [MWL8366] = { .part_name = "88w8366", .helper_image = "mwl8k/helper_8366.fw", .fw_image = "mwl8k/fmimage_8366.fw", - .rxd_ops = &rxd_8366_ops, - .modes = 0, + .ap_rxd_ops = &rxd_8366_ap_ops, }, }; @@ -3380,7 +3373,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mwl8k_release_firmware(priv); - priv->rxd_ops = priv->device_info->rxd_ops; + if (priv->ap_fw) + priv->rxd_ops = priv->device_info->ap_rxd_ops; + else + priv->rxd_ops = &rxd_sta_ops; priv->sniffer_enabled = false; priv->wmm_enabled = false; @@ -3409,8 +3405,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; - hw->wiphy->interface_modes = priv->device_info->modes; - /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); @@ -3480,6 +3474,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_cmd_set_hw_spec(hw); } else { rc = mwl8k_cmd_get_hw_spec_sta(hw); + + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); } if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", -- GitLab From 97474782959af87f5dc8049fca3bd3b25eb68308 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:33:04 +0100 Subject: [PATCH 0226/3892] mwl8k: remove unused mwl8k_vif::priv Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b20820a015cc..6fa2bde5b618 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -204,9 +204,6 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { - /* backpointer to parent config block */ - struct mwl8k_priv *priv; - /* BSS config of AP or IBSS from mac80211*/ struct ieee80211_bss_conf bss_info; @@ -2877,9 +2874,6 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_cmd_set_mac_addr(hw, conf->mac_addr); memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); - /* Back pointer to parent config block */ - mwl8k_vif->priv = priv; - /* Set Initial sequence number to zero */ mwl8k_vif->seqno = 0; -- GitLab From 7dc6a7a7635365b140af969e972900866d0bf34b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 30 Nov 2009 18:33:09 +0100 Subject: [PATCH 0227/3892] mwl8k: remove duplicate local per-vif copy of ieee80211_bss_conf Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 38 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6fa2bde5b618..97a95decf9a8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -204,12 +204,11 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { - /* BSS config of AP or IBSS from mac80211*/ - struct ieee80211_bss_conf bss_info; + /* Local MAC address. */ + u8 mac_addr[ETH_ALEN]; - /* BSSID of AP or IBSS */ - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; + /* BSSID of AP. */ + u8 bssid[ETH_ALEN]; /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; @@ -2123,7 +2122,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - struct ieee80211_bss_conf *info = &mv_vif->bss_info; struct mwl8k_cmd_update_set_aid *cmd; u16 prot_mode; int rc; @@ -2134,14 +2132,14 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(info->aid); + cmd->aid = cpu_to_le16(vif->bss_conf.aid); memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - if (info->use_cts_prot) { + if (vif->bss_conf.use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; } else { - switch (info->ht_operation_mode & + switch (vif->bss_conf.ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) { case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; @@ -2651,7 +2649,6 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, struct ieee80211_vif *vif, __u32 action) { struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - struct ieee80211_bss_conf *info = &mv_vif->bss_info; struct mwl8k_cmd_update_stadb *cmd; struct peer_capability_info *peer_info; int rc; @@ -2672,7 +2669,8 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, case MWL8K_STA_DB_MODIFY_ENTRY: /* Build peer_info block */ peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; - peer_info->basic_caps = cpu_to_le16(info->assoc_capability); + peer_info->basic_caps = + cpu_to_le16(vif->bss_conf.assoc_capability); memcpy(peer_info->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); peer_info->interop = 1; @@ -2960,11 +2958,8 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, if (rc) return; - if (info->assoc) { - memcpy(&mwl8k_vif->bss_info, info, - sizeof(struct ieee80211_bss_conf)); - - memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); + if (vif->bss_conf.assoc) { + memcpy(mwl8k_vif->bssid, vif->bss_conf.bssid, ETH_ALEN); /* Install rates */ rc = mwl8k_cmd_set_rate(hw, vif); @@ -2978,12 +2973,13 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, goto out; /* Set radio preamble */ - rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble); + rc = mwl8k_set_radio_preamble(hw, + vif->bss_conf.use_short_preamble); if (rc) goto out; /* Set slot time */ - rc = mwl8k_cmd_set_slot(hw, info->use_short_slot); + rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); if (rc) goto out; @@ -3006,8 +3002,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, priv->capture_beacon = true; } else { rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_DEL_ENTRY); - memset(&mwl8k_vif->bss_info, 0, - sizeof(struct ieee80211_bss_conf)); memset(mwl8k_vif->bssid, 0, ETH_ALEN); } @@ -3239,9 +3233,9 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; - mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim); + mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, + priv->vif->bss_conf.dtim_period); dev_kfree_skb(skb); priv->beacon_skb = NULL; -- GitLab From b02914af4d7020828ce921a572589dd793517c09 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 10 Dec 2009 17:35:01 -0600 Subject: [PATCH 0228/3892] b43: Allow PIO mode to be selected at module load If userencounter the "Fatal DMA Problem" with a BCM43XX device, and still wish to use b43 as the driver, their only option is to rebuild the kernel with CONFIG_B43_FORCE_PIO. This patch removes this option and allows PIO mode to be selected with a load-time parameter for the module. Note that the configuration variable CONFIG_B43_PIO is also removed. Once the DMA problem with the BCM4312 devices is solved, this patch will likely be reverted. Signed-off-by: Larry Finger Tested-by: John Daiker Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 17 +------------ drivers/net/wireless/b43/Makefile | 2 +- drivers/net/wireless/b43/b43.h | 13 ---------- drivers/net/wireless/b43/dma.c | 2 -- drivers/net/wireless/b43/main.c | 9 ++++--- drivers/net/wireless/b43/pio.h | 40 ------------------------------- 6 files changed, 8 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 64c12e1bced3..073be566d05e 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -3,6 +3,7 @@ config B43 depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER + select SSB_BLOCKIO ---help--- b43 is a driver for the Broadcom 43xx series wireless devices. @@ -78,14 +79,6 @@ config B43_SDIO If unsure, say N. -# Data transfers to the device via PIO -# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. -config B43_PIO - bool - depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) - select SSB_BLOCKIO - default y - config B43_NPHY bool "Pre IEEE 802.11n support (BROKEN)" depends on B43 && EXPERIMENTAL && BROKEN @@ -137,12 +130,4 @@ config B43_DEBUG for production use. Only say Y, if you are debugging a problem in the b43 driver sourcecode. -config B43_FORCE_PIO - bool "Force usage of PIO instead of DMA" - depends on B43 && B43_DEBUG - ---help--- - This will disable DMA and always enable PIO instead. - Say N! - This is only for debugging the PIO engine code. You do - _NOT_ want to enable this. diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 84772a2542dc..5e83b6f0a3a0 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -12,7 +12,7 @@ b43-y += xmit.o b43-y += lo.o b43-y += wa.o b43-y += dma.o -b43-$(CONFIG_B43_PIO) += pio.o +b43-y += pio.o b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index fe3bf9491997..2f12a750bc98 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -821,11 +821,9 @@ struct b43_wl { /* The device LEDs. */ struct b43_leds leds; -#ifdef CONFIG_B43_PIO /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */ u8 pio_scratchspace[110] __attribute__((__aligned__(8))); u8 pio_tailspace[4] __attribute__((__aligned__(8))); -#endif /* CONFIG_B43_PIO */ }; static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) @@ -876,20 +874,9 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) static inline bool b43_using_pio_transfers(struct b43_wldev *dev) { -#ifdef CONFIG_B43_PIO return dev->__using_pio_transfers; -#else - return 0; -#endif } -#ifdef CONFIG_B43_FORCE_PIO -# define B43_FORCE_PIO 1 -#else -# define B43_FORCE_PIO 0 -#endif - - /* Message printing */ void b43info(struct b43_wl *wl, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 027be275e035..5dd8a210ac21 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1760,7 +1760,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } -#ifdef CONFIG_B43_PIO static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type, u16 mmio_base, bool enable) { @@ -1794,4 +1793,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev, mmio_base = b43_dmacontroller_base(type, engine_index); direct_fifo_rx(dev, type, mmio_base, enable); } -#endif /* CONFIG_B43_PIO */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 19b4eae47b59..b0b5ce950008 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -102,6 +102,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; module_param_named(verbose, b43_modparam_verbose, int, 0644); MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug"); +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), @@ -1786,8 +1789,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) dma_reason[4], dma_reason[5]); b43err(dev->wl, "This device does not support DMA " "on your system. Please use PIO instead.\n"); - b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in " - "your kernel configuration.\n"); + b43err(dev->wl, "Unload the b43 module and reload " + "with 'pio=1'\n"); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { @@ -4353,7 +4356,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || - B43_FORCE_PIO) { + modparam_pio) { dev->__using_pio_transfers = 1; err = b43_pio_init(dev); } else { diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 7dd649c9ddad..7b3c42f93a16 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -55,8 +55,6 @@ #define B43_PIO_MAX_NR_TXPACKETS 32 -#ifdef CONFIG_B43_PIO - struct b43_pio_txpacket { /* Pointer to the TX queue we belong to. */ struct b43_pio_txqueue *queue; @@ -169,42 +167,4 @@ void b43_pio_rx(struct b43_pio_rxqueue *q); void b43_pio_tx_suspend(struct b43_wldev *dev); void b43_pio_tx_resume(struct b43_wldev *dev); - -#else /* CONFIG_B43_PIO */ - - -static inline int b43_pio_init(struct b43_wldev *dev) -{ - return 0; -} -static inline void b43_pio_free(struct b43_wldev *dev) -{ -} -static inline void b43_pio_stop(struct b43_wldev *dev) -{ -} -static inline int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb) -{ - return 0; -} -static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ -} -static inline void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ -} -static inline void b43_pio_rx(struct b43_pio_rxqueue *q) -{ -} -static inline void b43_pio_tx_suspend(struct b43_wldev *dev) -{ -} -static inline void b43_pio_tx_resume(struct b43_wldev *dev) -{ -} - -#endif /* CONFIG_B43_PIO */ #endif /* B43_PIO_H_ */ -- GitLab From 937a67e75a93b63f0b5d33612901906b8eb2a688 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:40 +0200 Subject: [PATCH 0229/3892] wl1271: updated radio parameters structure for newer firmwares In revision 6.1.0.0.288 the radio parameters structure has changed. This patch updates the driver code accordingly. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index b4fa4acb9229..de23c08738a0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -458,11 +458,12 @@ struct wl1271_radio_parms_cmd { /* Dynamic radio parameters */ /* 2.4GHz */ __le16 tx_ref_pd_voltage; - s8 tx_ref_power; + u8 tx_ref_power; s8 tx_offset_db; s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; @@ -471,15 +472,19 @@ struct wl1271_radio_parms_cmd { u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; u8 rx_fem_insertion_loss; - u8 padding2; + u8 degraded_low_to_normal_threshold; + u8 degraded_normal_to_high_threshold; + + u8 padding1; /* our own padding, not in ref driver */ /* 5GHz */ __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; @@ -488,7 +493,10 @@ struct wl1271_radio_parms_cmd { s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 padding3[2]; + u8 degraded_low_to_normal_threshold_5; + u8 degraded_normal_to_high_threshold_5; + + u8 padding2[2]; } __attribute__ ((packed)); struct wl1271_cmd_cal_channel_tune { -- GitLab From 76c0f8d396bd306111d349cfe770e1c4fcf70248 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:41 +0200 Subject: [PATCH 0230/3892] wl1271: updated general parameters structure for newer firmwares In revision 6.1.0.0.288 the general parameters structure has changed. This patch updates the driver code accordingly. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 20 ++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 15 +++++++++++++++ drivers/net/wireless/wl12xx/wl1271_conf.h | 17 +++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 13 +++++++++++++ 4 files changed, 65 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 886a9bc39cc1..fe9b187f476e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -209,6 +209,26 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; gen_parms->settings = g->settings; + gen_parms->sr_state = g->sr_state; + + memcpy(gen_parms->srf1, + g->srf1, + CONF_MAX_SMART_REFLEX_PARAMS); + memcpy(gen_parms->srf2, + g->srf2, + CONF_MAX_SMART_REFLEX_PARAMS); + memcpy(gen_parms->srf3, + g->srf3, + CONF_MAX_SMART_REFLEX_PARAMS); + memcpy(gen_parms->sr_debug_table, + g->sr_debug_table, + CONF_MAX_SMART_REFLEX_PARAMS); + + gen_parms->sr_sen_n_p = g->sr_sen_n_p; + gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain; + gen_parms->sr_sen_nrn = g->sr_sen_nrn; + gen_parms->sr_sen_prn = g->sr_sen_prn; + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); if (ret < 0) wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index de23c08738a0..057f925db2aa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -437,6 +437,21 @@ struct wl1271_general_parms_cmd { u8 tx_bip_fem_autodetect; u8 tx_bip_fem_manufacturer; u8 settings; + + u8 sr_state; + + s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; + s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; + s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; + + s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; + + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + + u8 padding[3]; } __attribute__ ((packed)); struct wl1271_radio_parms_cmd { diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 565373ede265..5e36cd90d0c6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -759,6 +759,9 @@ enum single_dual_band_enum { CONF_DUAL_BAND }; + +#define CONF_MAX_SMART_REFLEX_PARAMS 16 + struct conf_general_parms { /* * RF Reference Clock type / speed @@ -815,6 +818,20 @@ struct conf_general_parms { * Range: Unknown */ u8 settings; + + /* Smart reflex settings */ + u8 sr_state; + + s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; + s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; + s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; + + s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; + + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; }; #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b62c00ff42fe..7ab45c446ab8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -259,6 +259,19 @@ static struct conf_drv_settings default_conf = { .tx_bip_fem_autodetect = 0, .tx_bip_fem_manufacturer = 1, .settings = 1, + .sr_state = 1, + .srf1 = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .srf2 = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .srf3 = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .sr_sen_n_p = 0, + .sr_sen_n_p_gain = 0, + .sr_sen_nrn = 0, + .sr_sen_prn = 0, }, .radioparam = { .rx_trace_loss = 10, -- GitLab From a3e84847b042f10262f8ef66db66a0e527a00cff Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:42 +0200 Subject: [PATCH 0231/3892] wl1271: update radio and general parameters values There were some changes in the values we have to use for these settings. This patches updates them. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7ab45c446ab8..1d5b73ca23b7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -256,7 +256,7 @@ static struct conf_drv_settings default_conf = { .clk_valid_on_wakeup = 0, .dc2dcmode = 0, .single_dual_band = CONF_SINGLE_BAND, - .tx_bip_fem_autodetect = 0, + .tx_bip_fem_autodetect = 1, .tx_bip_fem_manufacturer = 1, .settings = 1, .sr_state = 1, @@ -274,8 +274,8 @@ static struct conf_drv_settings default_conf = { .sr_sen_prn = 0, }, .radioparam = { - .rx_trace_loss = 10, - .tx_trace_loss = 10, + .rx_trace_loss = 0x24, + .tx_trace_loss = 0x0, .rx_rssi_and_proc_compens = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, @@ -286,13 +286,13 @@ static struct conf_drv_settings default_conf = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_ref_pd_voltage = 0x24e, - .tx_ref_power = 0x78, + .tx_ref_pd_voltage = 0x1a9, + .tx_ref_power = 0x80, .tx_offset_db = 0x0, .tx_rate_limits_normal = { - 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, + 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 }, .tx_rate_limits_degraded = { - 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, + 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 }, .tx_channel_limits_11b = { 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, @@ -302,10 +302,10 @@ static struct conf_drv_settings default_conf = { 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, 0x20, 0x50 }, .tx_pdv_rate_offsets = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 }, .tx_ibias = { - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, - .rx_fem_insertion_loss = 0x14, + 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f }, + .rx_fem_insertion_loss = 0x0e, .tx_ref_pd_voltage_5 = { 0x0190, 0x01a4, 0x01c3, 0x01d8, 0x020a, 0x021c }, -- GitLab From cf18be4467b5aca1ccf3b5a72b67fc33a0b30c59 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:43 +0200 Subject: [PATCH 0232/3892] wl1271: added radio parameters configuration values newer firmwares Add new radio parameters for new structures based on firmware revision 6.1.0.0.288. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 13 +++++++++++++ drivers/net/wireless/wl12xx/wl1271_conf.h | 17 +++++++++++++---- drivers/net/wireless/wl12xx/wl1271_main.c | 10 +++++++++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index fe9b187f476e..57c21454e543 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -273,6 +273,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) CONF_NUMBER_OF_RATE_GROUPS); memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme, + CONF_NUMBER_OF_RATE_GROUPS); memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, CONF_NUMBER_OF_CHANNELS_2_4); @@ -283,6 +285,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; + radio_parms->degraded_low_to_normal_threshold = + r->degraded_low_to_normal_threshold; + radio_parms->degraded_normal_to_high_threshold = + r->degraded_normal_to_high_threshold; + for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) radio_parms->tx_ref_pd_voltage_5[i] = @@ -295,6 +302,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); memcpy(radio_parms->tx_rate_limits_degraded_5, r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_extreme_5, + r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS); memcpy(radio_parms->tx_channel_limits_ofdm_5, r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, @@ -303,6 +312,10 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) CONF_NUMBER_OF_RATE_GROUPS); memcpy(radio_parms->rx_fem_insertion_loss_5, r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); + radio_parms->degraded_low_to_normal_threshold_5 = + r->degraded_low_to_normal_threshold_5; + radio_parms->degraded_normal_to_high_threshold_5 = + r->degraded_normal_to_high_threshold_5; wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 5e36cd90d0c6..a4bd35b0f9fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -864,12 +864,13 @@ struct conf_radio_parms { * * Range: unknown */ - s16 tx_ref_pd_voltage; - s8 tx_ref_power; + u16 tx_ref_pd_voltage; + u8 tx_ref_power; s8 tx_offset_db; s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; @@ -878,17 +879,22 @@ struct conf_radio_parms { u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; u8 rx_fem_insertion_loss; + u8 degraded_low_to_normal_threshold; + u8 degraded_normal_to_high_threshold; + + /* * Dynamic radio parameters for 5GHz * * Range: unknown */ - s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; @@ -896,6 +902,9 @@ struct conf_radio_parms { /* FIXME: this is inconsistent with the types for 2.4GHz */ s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + u8 degraded_low_to_normal_threshold_5; + u8 degraded_normal_to_high_threshold_5; }; #define CONF_SR_ERR_TBL_COUNT 3 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 1d5b73ca23b7..f1cb7cbd7c1c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -293,6 +293,8 @@ static struct conf_drv_settings default_conf = { 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 }, .tx_rate_limits_degraded = { 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 }, + .tx_rate_limits_extreme = { + 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, .tx_channel_limits_11b = { 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, @@ -306,6 +308,8 @@ static struct conf_drv_settings default_conf = { .tx_ibias = { 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f }, .rx_fem_insertion_loss = 0x0e, + .degraded_low_to_normal_threshold = 0x1e, + .degraded_normal_to_high_threshold = 0x2d, .tx_ref_pd_voltage_5 = { 0x0190, 0x01a4, 0x01c3, 0x01d8, 0x020a, 0x021c }, @@ -317,6 +321,8 @@ static struct conf_drv_settings default_conf = { 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, .tx_rate_limits_degraded_5 = { 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, + .tx_rate_limits_extreme_5 = { + 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, .tx_channel_limits_ofdm_5 = { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, @@ -328,7 +334,9 @@ static struct conf_drv_settings default_conf = { .tx_ibias_5 = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, .rx_fem_insertion_loss_5 = { - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, + .degraded_low_to_normal_threshold_5 = 0x00, + .degraded_normal_to_high_threshold_5 = 0x00 } } }; -- GitLab From c7f43e451ba40e66a89d51e63bc21a57824592f2 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:44 +0200 Subject: [PATCH 0233/3892] wl1271: use join command with dummy BSSID When we need to change the channel before association, we have to send a join command with a valid BSSID. With this patch we use 0baddeadbeef as the BSSID. There are ongoing discussions with TI to get this done in a cleaner way. When we go back to idle, we issue a CMD_DISCONNECT to make sure the firmware stops listening to the channel and cleans things up internally. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 75 ++++++++++++++++++++--- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index f1cb7cbd7c1c..f6d42e613a56 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1130,6 +1130,47 @@ out: } #endif +static int wl1271_join_channel(struct wl1271 *wl, int channel) +{ + int ret; + /* we need to use a dummy BSSID for now */ + static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, + 0xad, 0xbe, 0xef }; + + /* disable mac filter, so we hear everything */ + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + + wl->channel = channel; + memcpy(wl->bssid, dummy_bssid, ETH_ALEN); + + ret = wl1271_cmd_join(wl); + if (ret < 0) + goto out; + + wl->joined = true; + +out: + return ret; +} + +static int wl1271_unjoin_channel(struct wl1271 *wl) +{ + int ret; + + /* to stop listening to a channel, we disconnect */ + ret = wl1271_cmd_disconnect(wl); + if (ret < 0) + goto out; + + wl->joined = false; + wl->channel = 0; + memset(wl->bssid, 0, ETH_ALEN); + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + +out: + return ret; +} + static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1271 *wl = hw->priv; @@ -1138,10 +1179,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level); + conf->power_level, + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); mutex_lock(&wl->mutex); @@ -1151,16 +1193,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (ret < 0) goto out; - if (channel != wl->channel) { - /* - * We assume that the stack will configure the right channel - * before associating, so we don't need to send a join - * command here. We will join the right channel when the - * BSSID changes - */ - wl->channel = channel; + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (conf->flags & IEEE80211_CONF_IDLE && wl->joined) + wl1271_unjoin_channel(wl); + else + wl1271_join_channel(wl, channel); } + /* if the channel changes while joined, join again */ + if (channel != wl->channel && wl->joined) + wl1271_join_channel(wl, channel); + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { wl1271_info("psm enabled"); @@ -1494,6 +1537,18 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; + if ((changed & BSS_CHANGED_BSSID) && + /* + * Now we know the correct bssid, so we send a new join command + * and enable the BSSID filter + */ + memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + wl1271_cmd_join(wl); + wl->joined = true; + } + if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; -- GitLab From 9cf25fed6a3b1c0792cbab3e934a4e2b6736d284 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:45 +0200 Subject: [PATCH 0234/3892] wl1271: remove workaround for disconnection Now we're using a the idle information coming from mac80211 to decide when to disconnect. If we have joined (ie. we're listening to a channel), whenever the interface goes to idle, we will issue a disconnect command. So the workaround to send a disconnect command before joining is not needed anymore. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 57c21454e543..ceb1ca63c43a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -344,19 +344,6 @@ int wl1271_cmd_join(struct wl1271 *wl) do_cal = false; } - /* FIXME: This is a workaround, because with the current stack, we - * cannot know when we have disassociated. So, if we have already - * joined, we disconnect before joining again. */ - if (wl->joined) { - ret = wl1271_cmd_disconnect(wl); - if (ret < 0) { - wl1271_error("failed to disconnect before rejoining"); - goto out; - } - - wl->joined = false; - } - join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; @@ -421,8 +408,6 @@ int wl1271_cmd_join(struct wl1271 *wl) goto out_free; } - wl->joined = true; - /* * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now -- GitLab From a2d0e3f13037fa7dc4094c47e0378800a064ee26 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:46 +0200 Subject: [PATCH 0235/3892] wl1271: limit TX power to 25dBm for every channel The wl1271 firmware supports maximun 25.5dBm, so the driver was returning -EINVALID to anything above that. This patch uses the channel max_power option to limit the TX power to 25dBm. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index f6d42e613a56..7f164e532211 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1675,19 +1675,19 @@ static struct ieee80211_rate wl1271_rates[] = { /* can't be const, mac80211 writes to this */ static struct ieee80211_channel wl1271_channels[] = { - { .hw_value = 1, .center_freq = 2412}, - { .hw_value = 2, .center_freq = 2417}, - { .hw_value = 3, .center_freq = 2422}, - { .hw_value = 4, .center_freq = 2427}, - { .hw_value = 5, .center_freq = 2432}, - { .hw_value = 6, .center_freq = 2437}, - { .hw_value = 7, .center_freq = 2442}, - { .hw_value = 8, .center_freq = 2447}, - { .hw_value = 9, .center_freq = 2452}, - { .hw_value = 10, .center_freq = 2457}, - { .hw_value = 11, .center_freq = 2462}, - { .hw_value = 12, .center_freq = 2467}, - { .hw_value = 13, .center_freq = 2472}, + { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, }; /* can't be const, mac80211 writes to this */ -- GitLab From cd264769f7a571fc2a61765757ed85c56f02e9d3 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:47 +0200 Subject: [PATCH 0236/3892] wl1271: check result code from the join command We were not checking the return value from the call to wl1271_cmd_join(). Added a check to make things more reliable. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7f164e532211..bf1d0fd93bcc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1545,7 +1545,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { wl->rx_config |= CFG_BSSID_FILTER_EN; memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - wl1271_cmd_join(wl); + ret = wl1271_cmd_join(wl); + if (ret < 0) { + wl1271_warning("cmd join failed %d", ret); + goto out_sleep; + } wl->joined = true; } -- GitLab From bdcbbb947be9778f740797a2bfc69c44a0d54776 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:48 +0200 Subject: [PATCH 0237/3892] wl1271: set null data template when BSSID is known The call to wl1271_cmd_build_null_data() was missing when we got associated, this was causing PS to fail. This patch adds the call and now PS seems to work. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index bf1d0fd93bcc..64f8623e0325 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1545,6 +1545,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { wl->rx_config |= CFG_BSSID_FILTER_EN; memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) { + wl1271_warning("cmd buld null data failed %d", + ret); + goto out_sleep; + } ret = wl1271_cmd_join(wl); if (ret < 0) { wl1271_warning("cmd join failed %d", ret); -- GitLab From ac9b40fac6983ab30e8b5019a5d2abda200c89d5 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:49 +0200 Subject: [PATCH 0238/3892] wl1271: use the correct macro when setting the basic rates We were using CONF_TX_RATE_MASK_ALL when calling wl1271_acx_rate_policies() during init. We should use WL1271_DEFAULT_BASIC_RATE_SET instead. The values are the same, but the latter is just the correct macro to use. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 11249b436cf1..d72ccc68b855 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -280,7 +280,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL); + ret = wl1271_acx_rate_policies(wl, WL1271_DEFAULT_BASIC_RATE_SET); if (ret < 0) goto out_free_memmap; -- GitLab From 6e92b416b0aa6a59629cc32ee2b27129d73b98b8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:50 +0200 Subject: [PATCH 0239/3892] wl1271: implement dco itrim parameters setting Newer firmwares require the dco itrim parameters to be set during initialization. This patch implements the new ACX function and calls it. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 29 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 10 ++++++++ drivers/net/wireless/wl12xx/wl1271_conf.h | 9 +++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 4 ++++ drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++++ 5 files changed, 56 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 5cc89bbdac7a..a38a967ba78a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -390,6 +390,35 @@ out: return ret; } +int wl1271_acx_dco_itrim_params(struct wl1271 *wl) +{ + struct acx_dco_itrim_params *dco; + struct conf_itrim_settings *c = &wl->conf.itrim; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); + + dco = kzalloc(sizeof(*dco), GFP_KERNEL); + if (!dco) { + ret = -ENOMEM; + goto out; + } + + dco->enable = c->enable; + dco->timeout = cpu_to_le32(c->timeout); + + ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, + dco, sizeof(*dco)); + if (ret < 0) { + wl1271_warning("failed to set dco itrim parameters: %d", ret); + goto out; + } + +out: + kfree(dco); + return ret; +} + int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) { struct acx_beacon_filter_option *beacon_filter = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 2ce0a8128542..fa5d9539440d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -434,6 +434,14 @@ struct acx_smart_reflex_config_params { struct smart_reflex_err_table error_table[3]; } __attribute__ ((packed)); +struct acx_dco_itrim_params { + struct acx_header header; + + u8 enable; + u8 padding[3]; + __le32 timeout; +} __attribute__ ((packed)); + #define PTA_ANTENNA_TYPE_DEF (0) #define PTA_BT_HP_MAXTIME_DEF (2000) #define PTA_WLAN_HP_MAX_TIME_DEF (5000) @@ -1029,6 +1037,7 @@ enum { ACX_SET_SMART_REFLEX_DEBUG = 0x005A, ACX_SET_SMART_REFLEX_STATE = 0x005B, ACX_SET_SMART_REFLEX_PARAMS = 0x005F, + ACX_SET_DCO_ITRIM_PARAMS = 0x0061, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, @@ -1056,6 +1065,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_dco_itrim_params(struct wl1271 *wl); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index a4bd35b0f9fd..905d4287915b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -934,12 +934,21 @@ struct conf_init_settings { }; +struct conf_itrim_settings { + /* enable dco itrim */ + u8 enable; + + /* moderation timeout in microsecs from the last TX */ + u32 timeout; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; struct conf_tx_settings tx; struct conf_conn_settings conn; struct conf_init_settings init; + struct conf_itrim_settings itrim; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index d72ccc68b855..39f01d875703 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -229,6 +229,10 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + ret = wl1271_acx_dco_itrim_params(wl); + if (ret < 0) + goto out_free_memmap; + /* Initialize connection monitoring thresholds */ ret = wl1271_acx_conn_monit_params(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 64f8623e0325..8c44f4cd688d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -338,6 +338,10 @@ static struct conf_drv_settings default_conf = { .degraded_low_to_normal_threshold_5 = 0x00, .degraded_normal_to_high_threshold_5 = 0x00 } + }, + .itrim = { + .enable = false, + .timeout = 50000, } }; -- GitLab From 1b38ea8858fd169064683e27add43511308e521a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:51 +0200 Subject: [PATCH 0240/3892] wl1271: fix one typo in the rx_rssi_and_proc_compens values There was a typo in one of the values in the rx_rssi_and_proc_compens elemt of the Radio Parameters struct. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8c44f4cd688d..147aab222354 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -278,7 +278,7 @@ static struct conf_drv_settings default_conf = { .tx_trace_loss = 0x0, .rx_rssi_and_proc_compens = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, - 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, + 0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }, .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, -- GitLab From 98b2a68473ae975bc4abdeb66cd719ccfdad9d4a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:52 +0200 Subject: [PATCH 0241/3892] wl1271: add gpio_power file in debugfs to power the chip on and off Some debugging tools require the chip to be powered on before they can work. With these tools, we shouldn't upload the firmware nor boot the firmware ourselves, so this debufs file is provided. It always contains the gpio power setting (0 = off, 1 = on). To change the power setting, just write 0 or 1 to the file. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Reviewed-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 ++ drivers/net/wireless/wl12xx/wl1271_debugfs.c | 55 ++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++ 3 files changed, 61 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 94359b1a861f..3bec6f3b1c7f 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -276,6 +276,7 @@ struct wl1271_debugfs { struct dentry *retry_count; struct dentry *excessive_retries; + struct dentry *gpio_power; }; #define NUM_TX_QUEUES 4 @@ -442,6 +443,8 @@ struct wl1271 { struct conf_drv_settings conf; struct list_head list; + + bool gpio_power; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index c1805e5f8964..4eaf40c57567 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -237,6 +237,57 @@ static const struct file_operations tx_queue_len_ops = { .open = wl1271_open_file_generic, }; +static ssize_t gpio_power_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "%d\n", wl->gpio_power); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t gpio_power_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + mutex_lock(&wl->mutex); + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + ret = -EFAULT; + goto out; + } + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in gpio_power"); + goto out; + } + + wl->set_power(!!value); + wl->gpio_power = !!value; + +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations gpio_power_ops = { + .read = gpio_power_read, + .write = gpio_power_write, + .open = wl1271_open_file_generic +}; + static void wl1271_debugfs_delete_files(struct wl1271 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -333,6 +384,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl) DEBUGFS_DEL(tx_queue_len); DEBUGFS_DEL(retry_count); DEBUGFS_DEL(excessive_retries); + + DEBUGFS_DEL(gpio_power); } static int wl1271_debugfs_add_files(struct wl1271 *wl) @@ -434,6 +487,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); + out: if (ret < 0) wl1271_debugfs_delete_files(wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 147aab222354..b33bdcc1eb4e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -399,11 +399,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl) static void wl1271_power_off(struct wl1271 *wl) { wl->set_power(false); + wl->gpio_power = false; } static void wl1271_power_on(struct wl1271 *wl) { wl->set_power(true); + wl->gpio_power = true; } static void wl1271_fw_status(struct wl1271 *wl, @@ -1923,6 +1925,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; wl->joined = false; + wl->gpio_power = false; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; -- GitLab From 8cf5e8e509950237fa0982235a703348d8b6e670 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:53 +0200 Subject: [PATCH 0242/3892] wl1271: upload only the first 468 bytes from the NVS file We were uploading the whole NVS file, but that is wrong, because the same file also contains the initialization values. For the latest firmwares, we should upload only the initial 468 bytes from the file. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_boot.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 3bec6f3b1c7f..8dfc9ec9590d 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -111,6 +111,7 @@ enum { #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" +#define WL1271_NVS_LEN 468 /* * Enable/disable 802.11a support for WL1273 diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b7c96454cca3..e803b876f3f0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (nvs == NULL) return -ENODEV; + if (wl->nvs_len < WL1271_NVS_LEN) + return -EINVAL; + nvs_ptr = nvs; - nvs_len = wl->nvs_len; + /* only the first part of the NVS needs to be uploaded */ + nvs_len = WL1271_NVS_LEN; + + /* FIXME: read init settings from the remaining part of the NVS */ /* Update the device MAC address into the nvs */ nvs[11] = wl->mac_addr[0]; -- GitLab From 3ed8f2c61466f10d99585365fd2aaafaf2d4c949 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:54 +0200 Subject: [PATCH 0243/3892] wl1271: some new configuration values according to new reference In the new reference driver, some of the firmware configuration values have been changed. This patch changes them in the wl1271 driver accordingly. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.h | 4 ++-- drivers/net/wireless/wl12xx/wl1271_main.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index fa5d9539440d..dcd64b7919eb 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -885,8 +885,8 @@ struct acx_tx_config_options { __le16 tx_compl_threshold; /* number of packets */ } __attribute__ ((packed)); -#define ACX_RX_MEM_BLOCKS 64 -#define ACX_TX_MIN_MEM_BLOCKS 64 +#define ACX_RX_MEM_BLOCKS 70 +#define ACX_TX_MIN_MEM_BLOCKS 40 #define ACX_TX_DESCRIPTORS 32 #define ACX_NUM_SSID_PROFILES 1 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b33bdcc1eb4e..fb2221749f7b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -67,10 +67,10 @@ static struct conf_drv_settings default_conf = { .ps_poll_timeout = 15, .upsd_timeout = 15, .rts_threshold = 2347, - .rx_cca_threshold = 0xFFEF, - .irq_blk_threshold = 0, - .irq_pkt_threshold = USHORT_MAX, - .irq_timeout = 5, + .rx_cca_threshold = 0, + .irq_blk_threshold = 0xFFFF, + .irq_pkt_threshold = 0, + .irq_timeout = 600, .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, }, .tx = { @@ -172,8 +172,8 @@ static struct conf_drv_settings default_conf = { } }, .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .tx_compl_timeout = 5, - .tx_compl_threshold = 5 + .tx_compl_timeout = 700, + .tx_compl_threshold = 4 }, .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, @@ -186,12 +186,12 @@ static struct conf_drv_settings default_conf = { .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, } }, - .synch_fail_thold = 5, + .synch_fail_thold = 10, .bss_lose_timeout = 100, .beacon_rx_timeout = 10000, .broadcast_timeout = 20000, .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 4, + .ps_poll_threshold = 20, .sig_trigger_count = 2, .sig_trigger = { [0] = { -- GitLab From 94210897e2b7df8446fdecd360342149e5b4a400 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 11 Dec 2009 15:40:55 +0200 Subject: [PATCH 0244/3892] wl1271: use channel 1 when configuring the data path In the data path configuration, one of the parameters is the channel. We have been setting it to wl->channel, which is not correct in this case. This channel has nothing to do with the channel we're currently tuned to, since it is only used for calibration during this phase. Hardcoded the channel to 1, according to the reference driver. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 13 +++++++------ drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index ceb1ca63c43a..20f3e67c8e48 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -505,7 +505,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) return 0; } -int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) { struct cmd_enabledisable_path *cmd; int ret; @@ -519,7 +519,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) goto out; } - cmd->channel = channel; + /* the channel here is only used for calibration, so hardcoded to 1 */ + cmd->channel = 1; if (enable) { cmd_rx = CMD_ENABLE_RX; @@ -532,22 +533,22 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); + enable ? "start" : "stop", cmd->channel); goto out; } wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", channel); + enable ? "start" : "stop", cmd->channel); ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); + enable ? "start" : "stop", cmd->channel); return ret; } wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); + enable ? "start" : "stop", cmd->channel); out: kfree(cmd); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 057f925db2aa..09fe91297acf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -37,7 +37,7 @@ int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 39f01d875703..bdd4a968b37d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -289,7 +289,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Enable data path */ - ret = wl1271_cmd_data_path(wl, wl->channel, 1); + ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index fb2221749f7b..55a45d339184 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -384,7 +384,7 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_cmd_data_path(wl, wl->channel, 1); + ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) return ret; -- GitLab From 149e38789f3fea74b581f8ebb7eb947d3c6d8a4e Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:40:56 +0200 Subject: [PATCH 0245/3892] wl1271: Configure smart-reflex paramter values. Configure correct values to be used with the smart-reflex configuration of the firmware. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 55a45d339184..b0f4c6efa415 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -260,12 +260,12 @@ static struct conf_drv_settings default_conf = { .tx_bip_fem_manufacturer = 1, .settings = 1, .sr_state = 1, - .srf1 = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, - .srf2 = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, - .srf3 = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, + 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, + .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, + 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, + .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, + 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .sr_sen_n_p = 0, -- GitLab From 018b171c40b613da867e054f9b6b258ae9298133 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:40:57 +0200 Subject: [PATCH 0246/3892] wl1271: Remove smart reflex ACX Remove the smart-reflex ACX - the associated parameters are now configured in the radio parameters config. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 53 ----------------------- drivers/net/wireless/wl12xx/wl1271_acx.h | 21 --------- drivers/net/wireless/wl12xx/wl1271_conf.h | 39 ----------------- drivers/net/wireless/wl12xx/wl1271_init.c | 5 --- drivers/net/wireless/wl12xx/wl1271_main.c | 24 ---------- 5 files changed, 142 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index a38a967ba78a..ea6427ad1bcb 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1041,59 +1041,6 @@ out: return ret; } -int wl1271_acx_smart_reflex(struct wl1271 *wl) -{ - struct acx_smart_reflex_state *sr_state = NULL; - struct acx_smart_reflex_config_params *sr_param = NULL; - int i, ret; - - wl1271_debug(DEBUG_ACX, "acx smart reflex"); - - sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL); - if (!sr_param) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) { - struct conf_mart_reflex_err_table *e = - &(wl->conf.init.sr_err_tbl[i]); - - sr_param->error_table[i].len = e->len; - sr_param->error_table[i].upper_limit = e->upper_limit; - memcpy(sr_param->error_table[i].values, e->values, e->len); - } - - ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS, - sr_param, sizeof(*sr_param)); - if (ret < 0) { - wl1271_warning("failed to set smart reflex params: %d", ret); - goto out; - } - - sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL); - if (!sr_state) { - ret = -ENOMEM; - goto out; - } - - /* enable smart reflex */ - sr_state->enable = wl->conf.init.sr_enable; - - ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE, - sr_state, sizeof(*sr_state)); - if (ret < 0) { - wl1271_warning("failed to set smart reflex params: %d", ret); - goto out; - } - -out: - kfree(sr_state); - kfree(sr_param); - return ret; - -} - int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) { struct wl1271_acx_bet_enable *acx = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index dcd64b7919eb..6640ebfb6162 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -415,25 +415,6 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __attribute__ ((packed)); -struct acx_smart_reflex_state { - struct acx_header header; - - u8 enable; - u8 padding[3]; -} __attribute__ ((packed)); - -struct smart_reflex_err_table { - u8 len; - s8 upper_limit; - s8 values[14]; -} __attribute__ ((packed)); - -struct acx_smart_reflex_config_params { - struct acx_header header; - - struct smart_reflex_err_table error_table[3]; -} __attribute__ ((packed)); - struct acx_dco_itrim_params { struct acx_header header; @@ -1035,8 +1016,6 @@ enum { ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, ACX_SET_SMART_REFLEX_DEBUG = 0x005A, - ACX_SET_SMART_REFLEX_STATE = 0x005B, - ACX_SET_SMART_REFLEX_PARAMS = 0x005F, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 905d4287915b..c87ae56ce42a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -722,31 +722,6 @@ struct conf_conn_settings { u8 psm_entry_retries; }; -#define CONF_SR_ERR_TBL_MAX_VALUES 14 - -struct conf_mart_reflex_err_table { - /* - * Length of the error table values table. - * - * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES - */ - u8 len; - - /* - * Smart Reflex error table upper limit. - * - * Range: s8 - */ - s8 upper_limit; - - /* - * Smart Reflex error table values. - * - * Range: s8 - */ - s8 values[CONF_SR_ERR_TBL_MAX_VALUES]; -}; - enum { CONF_REF_CLK_19_2_E, CONF_REF_CLK_26_E, @@ -907,21 +882,7 @@ struct conf_radio_parms { u8 degraded_normal_to_high_threshold_5; }; -#define CONF_SR_ERR_TBL_COUNT 3 - struct conf_init_settings { - /* - * Configure Smart Reflex error table values. - */ - struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT]; - - /* - * Smart Reflex enable flag. - * - * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled - */ - u8 sr_enable; - /* * Configure general parameters. */ diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index bdd4a968b37d..7bfd6c6a4c77 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -303,11 +303,6 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Configure smart reflex */ - ret = wl1271_acx_smart_reflex(wl); - if (ret < 0) - goto out_free_memmap; - return 0; out_free_memmap: diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b0f4c6efa415..5a6e4d446962 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -226,30 +226,6 @@ static struct conf_drv_settings default_conf = { .psm_entry_retries = 3 }, .init = { - .sr_err_tbl = { - [0] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, - 0x00 } - }, - [1] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8, - 0x00 } - }, - [2] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, - 0x00 } - } - }, - .sr_enable = 1, .genparam = { .ref_clk = CONF_REF_CLK_38_4_E, .settling_time = 5, -- GitLab From a6fe231361e35e3d068a63bbfd2318fa4e961ec5 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:40:58 +0200 Subject: [PATCH 0247/3892] wl1271: Use slow rates for association messages While not associated, default the data rates to 1 and 2mbps, so that only those rates will be used for association related message transfer. Once associated, configure the full rate-set supported by the AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 2 -- drivers/net/wireless/wl12xx/wl1271_conf.h | 3 ++- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 8 ++++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 8dfc9ec9590d..4b5ddba96f0b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -107,8 +107,6 @@ enum { CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) -#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL) - #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" #define WL1271_NVS_LEN 468 diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index c87ae56ce42a..5d1b5b6493e9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -258,7 +258,8 @@ struct conf_rx_settings { #define CONF_TX_MAX_RATE_CLASSES 8 #define CONF_TX_RATE_MASK_UNSPECIFIED 0 -#define CONF_TX_RATE_MASK_ALL 0x1eff +#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS) #define CONF_TX_RATE_RETRY_LIMIT 10 struct conf_tx_rate_class { diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 7bfd6c6a4c77..c67889dd18fc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, WL1271_DEFAULT_BASIC_RATE_SET); + ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5a6e4d446962..272a8fa677ef 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1180,6 +1180,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_unjoin_channel(wl); else wl1271_join_channel(wl, channel); + + if (conf->flags & IEEE80211_CONF_IDLE) { + wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + } } /* if the channel changes while joined, join again */ @@ -1568,7 +1573,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ - wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->aid = 0; } @@ -1897,7 +1901,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; + wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; wl->joined = false; -- GitLab From 13f2dc52c69bcca074cd12d4806953b2af45c386 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:40:59 +0200 Subject: [PATCH 0248/3892] wl1271: Fix event acknowledging functionality In reference source, events are acknowledged separately - fix the driver to do the same. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 6 ++---- drivers/net/wireless/wl12xx/wl1271_event.h | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index d13fdd99c85c..227caa14cbc5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -184,7 +184,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl) wl->mbox_ptr[0], wl->mbox_ptr[1]); } -int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) { struct event_mailbox mbox; int ret; @@ -204,9 +204,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) return ret; /* then we let the firmware know it can go on...*/ - if (do_ack) - wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, - INTR_TRIG_EVENT_ACK); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h index 4e3f55ebb1a8..278f9206aa56 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -112,6 +112,6 @@ struct event_mailbox { int wl1271_event_unmask(struct wl1271 *wl); void wl1271_event_mbox_config(struct wl1271 *wl); -int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox); #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 272a8fa677ef..d507dae19e17 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -450,14 +450,13 @@ static void wl1271_irq_work(struct work_struct *work) intr &= WL1271_INTR_MASK; if (intr & WL1271_ACX_INTR_EVENT_A) { - bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true; wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); - wl1271_event_handle(wl, 0, do_ack); + wl1271_event_handle(wl, 0); } if (intr & WL1271_ACX_INTR_EVENT_B) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); - wl1271_event_handle(wl, 1, true); + wl1271_event_handle(wl, 1); } if (intr & WL1271_ACX_INTR_INIT_COMPLETE) -- GitLab From af5e084b3200ab6e3033068a34fe16fd139be17b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:00 +0200 Subject: [PATCH 0249/3892] wl1271: prevent power save entry while not associated The mac80211 sometimes requests power save entry while not associated - this will cause problems, so prevent it if not associated. Go to powersave once association is complete. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4b5ddba96f0b..81e1c9531a3a 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -416,6 +416,7 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; + bool associated; /* retry counter for PSM entries */ u8 psm_entry_retry; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d507dae19e17..d07f03565196 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -978,6 +978,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->psm_entry_retry = 0; + wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1191,8 +1192,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_join_channel(wl, channel); if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1271_info("psm enabled"); - wl->psm_requested = true; /* @@ -1200,7 +1199,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (wl->associated) { + wl1271_info("psm enabled"); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { wl1271_info("psm disabled"); @@ -1548,6 +1550,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; + wl->associated = true; /* * with wl1271, we don't need to update the @@ -1572,6 +1575,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ + wl->associated = false; wl->aid = 0; } @@ -1898,6 +1902,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm = 0; wl->psm_requested = false; wl->psm_entry_retry = 0; + wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; -- GitLab From 9ccd921792e5b6719ff9e561438e095cba757727 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:01 +0200 Subject: [PATCH 0250/3892] wl1271: Implement chipset boot retry The wl1271 has a hardware bug which causes it to randomly (very infrequently) to fail powering up properly. This patch implements retry for the chipset boot sequence, to work around the hardware problem. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 130 +++++++++++++--------- 1 file changed, 77 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d07f03565196..0795bf3c60da 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -47,6 +47,8 @@ #include "wl1271_cmd.h" #include "wl1271_boot.h" +#define WL1271_BOOT_RETRIES 3 + static struct conf_drv_settings default_conf = { .sg = { .per_threshold = 7500, @@ -645,7 +647,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out_power_off; + goto out; break; case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", @@ -653,38 +655,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out_power_off; + goto out; break; default: - wl1271_error("unsupported chip id: 0x%x", wl->chip.id); + wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; - goto out_power_off; + goto out; } if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) - goto out_power_off; + goto out; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { ret = wl1271_fetch_nvs(wl); if (ret < 0) - goto out_power_off; + goto out; } - goto out; - -out_power_off: - wl1271_power_off(wl); - out: return ret; } int wl1271_plt_start(struct wl1271 *wl) { + int retries = WL1271_BOOT_RETRIES; int ret; mutex_lock(&wl->mutex); @@ -698,35 +696,48 @@ int wl1271_plt_start(struct wl1271 *wl) goto out; } - wl->state = WL1271_STATE_PLT; - - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_boot(wl); - if (ret < 0) - goto out_power_off; - - wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + while (retries) { + retries--; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto power_off; - ret = wl1271_plt_init(wl); - if (ret < 0) - goto out_irq_disable; + ret = wl1271_boot(wl); + if (ret < 0) + goto power_off; - /* Make sure power saving is disabled */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - goto out_irq_disable; + ret = wl1271_plt_init(wl); + if (ret < 0) + goto irq_disable; - goto out; + /* Make sure power saving is disabled */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto irq_disable; -out_irq_disable: - wl1271_disable_interrupts(wl); + wl->state = WL1271_STATE_PLT; + wl1271_notice("firmware booted in PLT mode (%s)", + wl->chip.fw_ver); + goto out; -out_power_off: - wl1271_power_off(wl); +irq_disable: + wl1271_disable_interrupts(wl); + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + cancel_work_sync(&wl->irq_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + wl1271_error("firmware boot in PLT mode failed despite %d retries", + WL1271_BOOT_RETRIES); out: mutex_unlock(&wl->mutex); @@ -882,6 +893,7 @@ static struct notifier_block wl1271_dev_notifier = { static int wl1271_op_start(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; + int retries = WL1271_BOOT_RETRIES; int ret = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -895,30 +907,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw) goto out; } - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_boot(wl); - if (ret < 0) - goto out_power_off; - - ret = wl1271_hw_init(wl); - if (ret < 0) - goto out_irq_disable; - - wl->state = WL1271_STATE_ON; + while (retries) { + retries--; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto power_off; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + ret = wl1271_boot(wl); + if (ret < 0) + goto power_off; - goto out; + ret = wl1271_hw_init(wl); + if (ret < 0) + goto irq_disable; -out_irq_disable: - wl1271_disable_interrupts(wl); + wl->state = WL1271_STATE_ON; + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + goto out; -out_power_off: - wl1271_power_off(wl); +irq_disable: + wl1271_disable_interrupts(wl); + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + cancel_work_sync(&wl->irq_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + wl1271_error("firmware boot failed despite %d retries", + WL1271_BOOT_RETRIES); out: mutex_unlock(&wl->mutex); -- GitLab From 01ac17ecb6292ceab9bfc498145491b78552b239 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:02 +0200 Subject: [PATCH 0251/3892] wl1271: Add pre-power-on sleep This patch adds a short delay before powering on the wl1271. Normally, it is not needed, but if the wl1271 has been powered off shortly before, for reliable firmware-booting this small stabilization delay is required. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 4 +++- drivers/net/wireless/wl12xx/wl1271_main.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 81e1c9531a3a..c965c4a718f3 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -458,7 +458,9 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_TX_QUEUE_MAX_LENGTH 20 -/* WL1271 needs a 200ms sleep after power on */ +/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power + on in case is has been shut down shortly before */ +#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ static inline bool wl1271_11a_enabled(void) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0795bf3c60da..0520b38e8e72 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -618,6 +618,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) struct wl1271_partition_set partition; int ret = 0; + msleep(WL1271_PRE_POWER_ON_SLEEP); wl1271_power_on(wl); msleep(WL1271_POWER_ON_SLEEP); wl1271_spi_reset(wl); -- GitLab From 26a63f6af58144818d4979cce1cbb8e49329f732 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:03 +0200 Subject: [PATCH 0252/3892] wl1271: Remove beacon-loss-ind from PSM entry failure handling Remove the beacon-loss indication to stack from PSM entry failure handling - this will cause more problems than it will solve due to the design of the mac80211. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 227caa14cbc5..8d0c18dec2cd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -89,7 +89,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, } else { wl1271_error("PSM entry failed, giving up.\n"); wl->psm_entry_retry = 0; - *beacon_loss = true; } break; case EVENT_ENTER_POWER_SAVE_SUCCESS: -- GitLab From e0d8bbf0d23e6b82f13b29f39593d5d13d923b2b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:04 +0200 Subject: [PATCH 0253/3892] wl1271: Add rudimentary ad-hoc support This patch adds rudimentary a-hoc support for the driver. It will allow setting up ad-hoc, and for other devices to scan and join. The beacon and probe response template setting is slightly dirty, and need to be properly implemented with support from mac80211. Also, the SSID is not configured to the firmware - the FW will not be able to respond to probe requests autonomously. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 45 ++++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0520b38e8e72..d7b1bb3e08a8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1139,11 +1139,15 @@ out: static int wl1271_join_channel(struct wl1271 *wl, int channel) { - int ret; + int ret = 0; /* we need to use a dummy BSSID for now */ static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, 0xad, 0xbe, 0xef }; + /* the dummy join is not required for ad-hoc */ + if (wl->bss_type == BSS_TYPE_IBSS) + goto out; + /* disable mac filter, so we hear everything */ wl->rx_config &= ~CFG_BSSID_FILTER_EN; @@ -1572,6 +1576,42 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, wl->joined = true; } + if (wl->bss_type == BSS_TYPE_IBSS) { + /* FIXME: This implements rudimentary ad-hoc support - + proper templates are on the wish list and notification + on when they change. This patch will update the templates + on every call to this function. Also, the firmware will not + answer to probe-requests as it does not have the proper + SSID set in the JOIN command. The probe-response template + is set nevertheless, as the FW will ASSERT without it */ + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) { + struct ieee80211_hdr *hdr; + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, + beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out_sleep; + } + + hdr = (struct ieee80211_hdr *) beacon->data; + hdr->frame_control = cpu_to_le16( + IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len); + dev_kfree_skb(beacon); + if (ret < 0) + goto out_sleep; + } + } + if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; @@ -1857,7 +1897,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_SUPPORTS_PS; - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; -- GitLab From ec078d943b89c03e55ac9c8b28f39256d4d4045e Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:05 +0200 Subject: [PATCH 0254/3892] wl1271: Change rates configured for templates Previously a "firmware chooses" value was used for the rates of all control message templates set to the firmware. This resulted in a too high rate to be chosen to transmit those messages. Change this by configuring a fixed low rate for the templates. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d7b1bb3e08a8..7a73aaadd04c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -78,7 +78,8 @@ static struct conf_drv_settings default_conf = { .tx = { .tx_energy_detection = 0, .rc_conf = { - .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED, + .enabled_rates = CONF_HW_BIT_RATE_1MBPS | + CONF_HW_BIT_RATE_2MBPS, .short_retry_limit = 10, .long_retry_limit = 10, .aflags = 0 -- GitLab From 830fb67b8e37fb03cf703b4e1217fe30ce32d579 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:06 +0200 Subject: [PATCH 0255/3892] wl1271: Fix supported rate management Previously, only basic rates were used for data transmission - resulting in reduced transfer rates. This patch takes enables the firmware to take advantage of the full set of data rates supported by the AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 7 ++- drivers/net/wireless/wl12xx/wl1271_acx.c | 24 ++++++--- drivers/net/wireless/wl12xx/wl1271_acx.h | 5 +- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 59 ++++++++++------------- drivers/net/wireless/wl12xx/wl1271_tx.c | 37 ++++++++++++++ 6 files changed, 90 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index c965c4a718f3..9290c92522b4 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -322,6 +322,10 @@ struct wl1271 { enum wl1271_state state; struct mutex mutex; +#define WL1271_FLAG_STA_RATES_CHANGED (0) +#define WL1271_FLAG_STA_ASSOCIATED (1) + unsigned long flags; + struct wl1271_partition_set part; struct wl1271_chip chip; @@ -394,7 +398,9 @@ struct wl1271 { u16 aid; /* currently configured rate set */ + u32 sta_rate_set; u32 basic_rate_set; + u32 rate_set; /* The current band */ enum ieee80211_band band; @@ -416,7 +422,6 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; - bool associated; /* retry counter for PSM entries */ u8 psm_entry_retry; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index ea6427ad1bcb..0ea1a48c45fa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -787,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) +int wl1271_acx_rate_policies(struct wl1271 *wl) { struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; + int idx = 0; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); @@ -802,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) goto out; } - /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = cpu_to_le32(1); - acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); - acx->rate_class[0].short_retry_limit = c->short_retry_limit; - acx->rate_class[0].long_retry_limit = c->long_retry_limit; - acx->rate_class[0].aflags = c->aflags; + /* configure one basic rate class */ + idx = ACX_TX_BASIC_RATE; + acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set); + acx->rate_class[idx].short_retry_limit = c->short_retry_limit; + acx->rate_class[idx].long_retry_limit = c->long_retry_limit; + acx->rate_class[idx].aflags = c->aflags; + + /* configure one AP supported rate class */ + idx = ACX_TX_AP_FULL_RATE; + acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); + acx->rate_class[idx].short_retry_limit = c->short_retry_limit; + acx->rate_class[idx].long_retry_limit = c->long_retry_limit; + acx->rate_class[idx].aflags = c->aflags; + + acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 6640ebfb6162..b6a473f60658 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -826,6 +826,9 @@ struct acx_rate_class { u8 reserved; }; +#define ACX_TX_BASIC_RATE 0 +#define ACX_TX_AP_FULL_RATE 1 +#define ACX_TX_RATE_POLICY_CNT 2 struct acx_rate_policy { struct acx_header header; @@ -1058,7 +1061,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); +int wl1271_acx_rate_policies(struct wl1271 *wl); int wl1271_acx_ac_cfg(struct wl1271 *wl); int wl1271_acx_tid_cfg(struct wl1271 *wl); int wl1271_acx_frag_threshold(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index c67889dd18fc..3b4ed070f439 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + ret = wl1271_acx_rate_policies(wl); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7a73aaadd04c..775b1e82ca81 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -777,7 +777,20 @@ out: static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = txinfo->control.sta; + unsigned long flags; + /* peek into the rates configured in the STA entry */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { + wl->sta_rate_set = sta->supp_rates[conf->channel->band]; + set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); + } + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* queue the packet */ skb_queue_tail(&wl->tx_queue, skb); /* @@ -1004,7 +1017,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->psm_entry_retry = 0; - wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1016,6 +1028,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->time_offset = 0; wl->session_counter = 0; wl->joined = false; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl->flags = 0; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1212,8 +1227,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_join_channel(wl, channel); if (conf->flags & IEEE80211_CONF_IDLE) { - wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; + wl1271_acx_rate_policies(wl); } } @@ -1229,7 +1245,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - if (wl->associated) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { wl1271_info("psm enabled"); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } @@ -1522,22 +1538,6 @@ out: return ret; } -static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set) -{ - struct ieee80211_supported_band *band; - u32 enabled_rates = 0; - int bit; - - band = wl->hw->wiphy->bands[wl->band]; - for (bit = 0; bit < band->n_bitrates; bit++) { - if (basic_rate_set & 0x1) - enabled_rates |= band->bitrates[bit].hw_value; - basic_rate_set >>= 1; - } - - return enabled_rates; -} - static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1616,7 +1616,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; - wl->associated = true; + set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); /* * with wl1271, we don't need to update the @@ -1641,7 +1641,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ - wl->associated = false; + clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; } @@ -1676,17 +1676,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BASIC_RATES) { - wl->basic_rate_set = wl1271_enabled_rates_get( - wl, bss_conf->basic_rates); - - ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); - if (ret < 0) { - wl1271_warning("Set rate policies failed %d", ret); - goto out_sleep; - } - } - out_sleep: wl1271_ps_elp_sleep(wl); @@ -1969,14 +1958,16 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm = 0; wl->psm_requested = false; wl->psm_entry_retry = 0; - wl->associated = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->sta_rate_set = 0; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; wl->joined = false; wl->gpio_power = false; + wl->flags = 0; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 00af065c77c2..75f532706332 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, pad = pad - skb->len; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + /* if the packets are destined for AP (have a STA entry) send them + with AP rate policies, otherwise use default basic rates */ + if (control->control.sta) + tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; + desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); @@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) return ret; } +static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) +{ + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = wl->hw->wiphy->bands[wl->band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + rate_set >>= 1; + } + + return enabled_rates; +} + void wl1271_tx_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, tx_work); struct sk_buff *skb; bool woken_up = false; + u32 sta_rates = 0; int ret; + /* check if the rates supported by the AP have changed */ + if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, + &wl->flags))) { + unsigned long flags; + spin_lock_irqsave(&wl->wl_lock, flags); + sta_rates = wl->sta_rate_set; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; + /* if rates have changed, re-configure the rate policy */ + if (unlikely(sta_rates)) { + wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); + wl1271_acx_rate_policies(wl); + } + while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); -- GitLab From 71449f8d7059b69e6e45063997d225d8202221a2 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:07 +0200 Subject: [PATCH 0256/3892] wl1271: Change booleans in struct wl1271 into a flags bitmask For cleaner implementation, change the bunch of booleans in the struct wl1271 structure into a flags bitmask. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 23 +++------- drivers/net/wireless/wl12xx/wl1271_cmd.c | 6 +-- drivers/net/wireless/wl12xx/wl1271_debugfs.c | 13 ++++-- drivers/net/wireless/wl12xx/wl1271_event.c | 11 ++--- drivers/net/wireless/wl12xx/wl1271_main.c | 45 ++++++++------------ drivers/net/wireless/wl12xx/wl1271_ps.c | 15 ++++--- drivers/net/wireless/wl12xx/wl1271_tx.c | 6 +-- 7 files changed, 55 insertions(+), 64 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 9290c92522b4..d0938db043b3 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -324,6 +324,13 @@ struct wl1271 { #define WL1271_FLAG_STA_RATES_CHANGED (0) #define WL1271_FLAG_STA_ASSOCIATED (1) +#define WL1271_FLAG_JOINED (2) +#define WL1271_FLAG_GPIO_POWER (3) +#define WL1271_FLAG_TX_QUEUE_STOPPED (4) +#define WL1271_FLAG_SCANNING (5) +#define WL1271_FLAG_IN_ELP (6) +#define WL1271_FLAG_PSM (7) +#define WL1271_FLAG_PSM_REQUESTED (8) unsigned long flags; struct wl1271_partition_set part; @@ -363,7 +370,6 @@ struct wl1271 { /* Frames scheduled for transmission, not handled yet */ struct sk_buff_head tx_queue; - bool tx_queue_stopped; struct work_struct tx_work; @@ -391,7 +397,6 @@ struct wl1271 { u32 mbox_ptr[2]; /* Are we currently scanning */ - bool scanning; struct wl1271_scan scan; /* Our association ID */ @@ -411,18 +416,9 @@ struct wl1271 { unsigned int rx_config; unsigned int rx_filter; - /* is firmware in elp mode */ - bool elp; - struct completion *elp_compl; struct delayed_work elp_work; - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - /* retry counter for PSM entries */ u8 psm_entry_retry; @@ -441,15 +437,10 @@ struct wl1271 { struct ieee80211_vif *vif; - /* Used for a workaround to send disconnect before rejoining */ - bool joined; - /* Current chipset configuration */ struct conf_drv_settings conf; struct list_head list; - - bool gpio_power; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 20f3e67c8e48..b5eb9edc63aa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -655,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, channels = wl->hw->wiphy->bands[ieee_band]->channels; n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; - if (wl->scanning) + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) return -EINVAL; params = kzalloc(sizeof(*params), GFP_KERNEL); @@ -730,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - wl->scanning = true; + set_bit(WL1271_FLAG_SCANNING, &wl->flags); if (wl1271_11a_enabled()) { wl->scan.state = band; if (band == WL1271_SCAN_BAND_DUAL) { @@ -748,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); if (ret < 0) { wl1271_error("SCAN failed"); - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 4eaf40c57567..8d7588ca68fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -241,10 +241,12 @@ static ssize_t gpio_power_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; + bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + int res; char buf[10]; - res = scnprintf(buf, sizeof(buf), "%d\n", wl->gpio_power); + res = scnprintf(buf, sizeof(buf), "%d\n", state); return simple_read_from_buffer(user_buf, count, ppos, buf, res); } @@ -274,8 +276,13 @@ static ssize_t gpio_power_write(struct file *file, goto out; } - wl->set_power(!!value); - wl->gpio_power = !!value; + if (value) { + wl->set_power(true); + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + } else { + wl->set_power(false); + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + } out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 8d0c18dec2cd..6ff535d5c7ee 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); - if (wl->scanning) { + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); @@ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.active, wl->scan.high_prio, @@ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); - wl->scanning = false; + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); } } return 0; @@ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: - if (!wl->psm) { + if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { wl->psm_entry_retry = 0; break; } @@ -135,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. */ - if (vector & BSS_LOSE_EVENT_ID && wl->psm) { + if (vector & BSS_LOSE_EVENT_ID && + test_bit(WL1271_FLAG_PSM, &wl->flags)) { wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 775b1e82ca81..90a60c1147a8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -378,13 +378,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl) static void wl1271_power_off(struct wl1271 *wl) { wl->set_power(false); - wl->gpio_power = false; + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_power_on(struct wl1271 *wl) { wl->set_power(true); - wl->gpio_power = true; + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_fw_status(struct wl1271 *wl, @@ -812,7 +812,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * protected. Maybe fix this by removing the stupid * variable altogether and checking the real queue state? */ - wl->tx_queue_stopped = true; + set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); } return NETDEV_TX_OK; @@ -985,11 +985,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) WARN_ON(wl->state != WL1271_STATE_ON); - if (wl->scanning) { + if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); mutex_lock(&wl->mutex); - wl->scanning = false; } wl->state = WL1271_STATE_OFF; @@ -1014,10 +1013,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; - wl->elp = false; - wl->psm = 0; wl->psm_entry_retry = 0; - wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; wl->tx_results_count = 0; @@ -1027,7 +1023,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_security_seq_32 = 0; wl->time_offset = 0; wl->session_counter = 0; - wl->joined = false; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->sta_rate_set = 0; wl->flags = 0; @@ -1174,7 +1169,7 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel) if (ret < 0) goto out; - wl->joined = true; + set_bit(WL1271_FLAG_JOINED, &wl->flags); out: return ret; @@ -1189,7 +1184,7 @@ static int wl1271_unjoin_channel(struct wl1271 *wl) if (ret < 0) goto out; - wl->joined = false; + clear_bit(WL1271_FLAG_JOINED, &wl->flags); wl->channel = 0; memset(wl->bssid, 0, ETH_ALEN); wl->rx_config = WL1271_DEFAULT_RX_CONFIG; @@ -1221,7 +1216,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (changed & IEEE80211_CONF_CHANGE_IDLE) { - if (conf->flags & IEEE80211_CONF_IDLE && wl->joined) + if (conf->flags & IEEE80211_CONF_IDLE && + test_bit(WL1271_FLAG_JOINED, &wl->flags)) wl1271_unjoin_channel(wl); else wl1271_join_channel(wl, channel); @@ -1234,11 +1230,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) } /* if the channel changes while joined, join again */ - if (channel != wl->channel && wl->joined) + if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags)) wl1271_join_channel(wl, channel); - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl->psm_requested = true; + if (conf->flags & IEEE80211_CONF_PS && + !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { + set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); /* * We enter PSM only if we're already associated. @@ -1250,12 +1247,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { + test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { wl1271_info("psm disabled"); - wl->psm_requested = false; + clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); - if (wl->psm) + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); } @@ -1574,7 +1571,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, wl1271_warning("cmd join failed %d", ret); goto out_sleep; } - wl->joined = true; + set_bit(WL1271_FLAG_JOINED, &wl->flags); } if (wl->bss_type == BSS_TYPE_IBSS) { @@ -1633,7 +1630,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, goto out_sleep; /* If we want to go in PSM but we're not there yet */ - if (wl->psm_requested && !wl->psm) { + if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && + !test_bit(WL1271_FLAG_PSM, &wl->flags)) { mode = STATION_POWER_SAVE_MODE; ret = wl1271_ps_set_mode(wl, mode); if (ret < 0) @@ -1949,24 +1947,17 @@ static int __devinit wl1271_probe(struct spi_device *spi) INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); wl->channel = WL1271_DEFAULT_CHANNEL; - wl->scanning = false; wl->default_key = 0; wl->rx_counter = 0; wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; wl->psm_entry_retry = 0; - wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->sta_rate_set = 0; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; - wl->joined = false; - wl->gpio_power = false; wl->flags = 0; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 507cd91d7eed..e407790f6771 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->elp || !wl->psm) + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || + !test_bit(WL1271_FLAG_PSM, &wl->flags)) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; + set_bit(WL1271_FLAG_IN_ELP, &wl->flags); out: mutex_unlock(&wl->mutex); @@ -55,7 +56,7 @@ out: /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (wl->psm) { + if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(ELP_ENTRY_DELAY)); @@ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) u32 start_time = jiffies; bool pending = false; - if (!wl->elp) + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; wl1271_debug(DEBUG_PSM, "waking up chip from elp"); @@ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) } } - wl->elp = false; + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start_time)); @@ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; - wl->psm = 1; + set_bit(WL1271_FLAG_PSM, &wl->flags); break; case STATION_ACTIVE_MODE: default: @@ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; - wl->psm = 0; + clear_bit(WL1271_FLAG_PSM, &wl->flags); break; } diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 75f532706332..a288cc317d7b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -277,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work) wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " "stop queues"); ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; + set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); skb_queue_head(&wl->tx_queue, skb); goto out; } else if (ret < 0) { dev_kfree_skb(skb); goto out; - } else if (wl->tx_queue_stopped) { + } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, + &wl->flags)) { /* firmware buffer has space, restart queues */ wl1271_debug(DEBUG_TX, "complete_packet: waking queues"); ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; } } -- GitLab From 38ad2d87d42ba847c100ef132e8e363513982c8b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:08 +0200 Subject: [PATCH 0257/3892] wl1271: Add support for acx_pm_config This acx configures host clock parameters in correspondence with the clock request line - the settling time of the clock, and whether fast wake-up is supported. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 28 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 9 ++++++++ drivers/net/wireless/wl12xx/wl1271_conf.h | 17 ++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 5 ++++ drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++++ 5 files changed, 63 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 0ea1a48c45fa..0b3434843476 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1118,3 +1118,31 @@ out: kfree(acx); return ret; } + +int wl1271_acx_pm_config(struct wl1271 *wl) +{ + struct wl1271_acx_pm_config *acx = NULL; + struct conf_pm_config_settings *c = &wl->conf.pm_config; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx pm config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); + acx->host_fast_wakeup_support = c->host_fast_wakeup_support; + + ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx pm config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index b6a473f60658..1bb63af64f0e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -961,6 +961,13 @@ struct wl1271_acx_arp_filter { used. */ } __attribute__((packed)); +struct wl1271_acx_pm_config { + struct acx_header header; + + __le32 host_clk_settling_time; + u8 host_fast_wakeup_support; + u8 padding[3]; +} __attribute__ ((packed)); enum { ACX_WAKE_UP_CONDITIONS = 0x0002, @@ -1025,6 +1032,7 @@ enum { DOT11_RX_DOT11_MODE = 0x1012, DOT11_RTS_THRESHOLD = 0x1013, DOT11_GROUP_ADDRESS_TBL = 0x1014, + ACX_PM_CONFIG = 0x1016, MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, @@ -1073,5 +1081,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, u8 version); +int wl1271_acx_pm_config(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 5d1b5b6493e9..1993d63c214e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -904,6 +904,22 @@ struct conf_itrim_settings { u32 timeout; }; +struct conf_pm_config_settings { + /* + * Host clock settling time + * + * Range: 0 - 30000 us + */ + u32 host_clk_settling_time; + + /* + * Host fast wakeup support + * + * Range: true, false + */ + bool host_fast_wakeup_support; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -911,6 +927,7 @@ struct conf_drv_settings { struct conf_conn_settings conn; struct conf_init_settings init; struct conf_itrim_settings itrim; + struct conf_pm_config_settings pm_config; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 3b4ed070f439..c9848eecb767 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -303,6 +303,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 90a60c1147a8..7e6b500dfb6f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -321,6 +321,10 @@ static struct conf_drv_settings default_conf = { .itrim = { .enable = false, .timeout = 50000, + }, + .pm_config = { + .host_clk_settling_time = 5000, + .host_fast_wakeup_support = false } }; -- GitLab From 04477bf095afd008b73717f7a4ea1fdf18b1b5e2 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:09 +0200 Subject: [PATCH 0258/3892] wl1271: Check vif for NULL when indicating beacon-loss Because the interface is started and the vif are created and destroyed separately, there is a slim possibility beacon-loss indications occur while there is no vif - causing a kernel-oops unless checked. Add checking for the vif. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 6ff535d5c7ee..0a145afc9905 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -150,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) return ret; } - if (beacon_loss) { + if (wl->vif && beacon_loss) { /* Obviously, it's dangerous to release the mutex while we are holding many of the variables in the wl struct. That's why it's done last in the function, and care must -- GitLab From 8f648c00039a42e67a9dff034c77d41502dab1f3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 11 Dec 2009 15:41:10 +0200 Subject: [PATCH 0259/3892] wl1271: Prevent performing "join" before association There is a minor bug in the code causing a "join" to be performed before there is an intention to associate. Fix this. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7e6b500dfb6f..4a997381a8d0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1223,7 +1223,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->flags & IEEE80211_CONF_IDLE && test_bit(WL1271_FLAG_JOINED, &wl->flags)) wl1271_unjoin_channel(wl); - else + else if (!(conf->flags & IEEE80211_CONF_IDLE)) wl1271_join_channel(wl, channel); if (conf->flags & IEEE80211_CONF_IDLE) { -- GitLab From baeb66fe2306783e3b9a492b03882f2e249b2eeb Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 18 Dec 2009 17:59:02 -0500 Subject: [PATCH 0260/3892] wireless: remove CONFIG_WIRELESS_OLD_REGULATORY This is no longer needed with the availability of CONFIG_CFG80211_INTERNAL_REGDB. Signed-off-by: John W. Linville --- Documentation/feature-removal-schedule.txt | 21 ----- net/wireless/Kconfig | 15 ---- net/wireless/nl80211.c | 6 -- net/wireless/reg.c | 89 +--------------------- 4 files changed, 2 insertions(+), 129 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 591e94448e63..86f2ec90af87 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -88,27 +88,6 @@ Who: Luis R. Rodriguez --------------------------- -What: CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information -When: March 2010 / desktop catchup - -Why: The old regulatory infrastructure has been replaced with a new one - which does not require statically defined regulatory domains. We do - not want to keep static regulatory domains in the kernel due to the - the dynamic nature of regulatory law and localization. We kept around - the old static definitions for the regulatory domains of: - - * US - * JP - * EU - - and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was - set. We will remove this option once the standard Linux desktop catches - up with the new userspace APIs we have implemented. - -Who: Luis R. Rodriguez - ---------------------------- - What: dev->power.power_state When: July 2007 Why: Broken design for runtime control over driver power states, confusing diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 8419971f07c5..d0ee29063e5d 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -94,21 +94,6 @@ config CFG80211_DEBUGFS If unsure, say N. -config WIRELESS_OLD_REGULATORY - bool "Old wireless static regulatory definitions" - default n - depends on CFG80211 - ---help--- - This option enables the old static regulatory information - and uses it within the new framework. This option is available - for historical reasons and it is advised to leave it off. - - For details see: - - http://wireless.kernel.org/en/developers/Regulatory - - Say N and if you say Y, please tell us why. The default is N. - config CFG80211_INTERNAL_REGDB bool "use statically compiled regulatory rules database" if EMBEDDED default n diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7cb0d647fc34..60f854377f90 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2550,12 +2550,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); -#ifdef CONFIG_WIRELESS_OLD_REGULATORY - /* We ignore world regdom requests with the old regdom setup */ - if (is_world_regdom(data)) - return -EINVAL; -#endif - r = regulatory_hint_user(data); return r; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index dc13c3ffeca6..87ea60d84c3c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -129,78 +129,6 @@ static char *ieee80211_regdom = "00"; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -#ifdef CONFIG_WIRELESS_OLD_REGULATORY -/* - * We assume 40 MHz bandwidth for the old regulatory work. - * We make emphasis we are using the exact same frequencies - * as before - */ - -static const struct ieee80211_regdomain us_regdom = { - .n_reg_rules = 6, - .alpha2 = "US", - .reg_rules = { - /* IEEE 802.11b/g, channels 1..11 */ - REG_RULE(2412-10, 2462+10, 40, 6, 27, 0), - /* IEEE 802.11a, channel 36..48 */ - REG_RULE(5180-10, 5240+10, 40, 6, 17, 0), - /* IEEE 802.11a, channels 48..64 */ - REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), - /* IEEE 802.11a, channels 100..124 */ - REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS), - /* IEEE 802.11a, channels 132..144 */ - REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS), - /* IEEE 802.11a, channels 149..165, outdoor */ - REG_RULE(5745-10, 5825+10, 40, 6, 30, 0), - } -}; - -static const struct ieee80211_regdomain jp_regdom = { - .n_reg_rules = 6, - .alpha2 = "JP", - .reg_rules = { - /* IEEE 802.11b/g, channels 1..11 */ - REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), - /* IEEE 802.11b/g, channels 12..13 */ - REG_RULE(2467-10, 2472+10, 20, 6, 20, 0), - /* IEEE 802.11b/g, channel 14 */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM), - /* IEEE 802.11a, channels 36..48 */ - REG_RULE(5180-10, 5240+10, 40, 6, 20, 0), - /* IEEE 802.11a, channels 52..64 */ - REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), - /* IEEE 802.11a, channels 100..144 */ - REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS), - } -}; - -static const struct ieee80211_regdomain *static_regdom(char *alpha2) -{ - if (alpha2[0] == 'U' && alpha2[1] == 'S') - return &us_regdom; - if (alpha2[0] == 'J' && alpha2[1] == 'P') - return &jp_regdom; - /* Use world roaming rules for "EU", since it was a pseudo - domain anyway... */ - if (alpha2[0] == 'E' && alpha2[1] == 'U') - return &world_regdom; - /* Default, world roaming rules */ - return &world_regdom; -} - -static bool is_old_static_regdom(const struct ieee80211_regdomain *rd) -{ - if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom) - return true; - return false; -} -#else -static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd) -{ - return false; -} -#endif - static void reset_regdomains(void) { /* avoid freeing static information or freeing something twice */ @@ -210,8 +138,6 @@ static void reset_regdomains(void) cfg80211_world_regdom = NULL; if (cfg80211_regdomain == &world_regdom) cfg80211_regdomain = NULL; - if (is_old_static_regdom(cfg80211_regdomain)) - cfg80211_regdomain = NULL; kfree(cfg80211_regdomain); kfree(cfg80211_world_regdom); @@ -1490,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy, return REG_INTERSECT; case NL80211_REGDOM_SET_BY_DRIVER: if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { - if (is_old_static_regdom(cfg80211_regdomain)) - return 0; if (regdom_changes(pending_request->alpha2)) return 0; return -EALREADY; @@ -1528,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy, return -EAGAIN; } - if (!is_old_static_regdom(cfg80211_regdomain) && - !regdom_changes(pending_request->alpha2)) + if (!regdom_changes(pending_request->alpha2)) return -EALREADY; return 0; @@ -2111,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * If someone else asked us to change the rd lets only bother * checking if the alpha2 changes if CRDA was already called */ - if (!is_old_static_regdom(cfg80211_regdomain) && - !regdom_changes(rd->alpha2)) + if (!regdom_changes(rd->alpha2)) return -EINVAL; } @@ -2311,15 +2233,8 @@ int regulatory_init(void) spin_lock_init(®_requests_lock); spin_lock_init(®_pending_beacons_lock); -#ifdef CONFIG_WIRELESS_OLD_REGULATORY - cfg80211_regdomain = static_regdom(ieee80211_regdom); - - printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); - print_regdomain_info(cfg80211_regdomain); -#else cfg80211_regdomain = cfg80211_world_regdom; -#endif /* We always try to get an update for the static regdomain */ err = regulatory_hint_core(cfg80211_regdomain->alpha2); if (err) { -- GitLab From 00e23ce219a9ac6c5f764342ca13f8ac1bab0382 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 23 Dec 2009 00:03:22 +0100 Subject: [PATCH 0261/3892] rt2x00: Fix checks for rt2800 SOC support. Fix checking for SOC support in rt2800pci. The wrong config (an unexisting one) was checked. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 458378c4e500..96e024477b2f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -52,8 +52,8 @@ #define CONFIG_RT2800PCI_PCI #endif -#ifdef CONFIG_RT2800PCI_WISOC_MODULE -#define CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC_MODULE +#define CONFIG_RT2800PCI_SOC #endif /* @@ -87,7 +87,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } -#ifdef CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ @@ -98,7 +98,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { } -#endif /* CONFIG_RT2800PCI_WISOC */ +#endif /* CONFIG_RT2800PCI_SOC */ #ifdef CONFIG_RT2800PCI_PCI static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -1251,7 +1251,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); #endif /* CONFIG_RT2800PCI_PCI */ MODULE_LICENSE("GPL"); -#ifdef CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC #if defined(CONFIG_RALINK_RT288X) __rt2x00soc_probe(RT2880, &rt2800pci_ops); #elif defined(CONFIG_RALINK_RT305X) @@ -1269,7 +1269,7 @@ static struct platform_driver rt2800soc_driver = { .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, }; -#endif /* CONFIG_RT2800PCI_WISOC */ +#endif /* CONFIG_RT2800PCI_SOC */ #ifdef CONFIG_RT2800PCI_PCI static struct pci_driver rt2800pci_driver = { @@ -1286,7 +1286,7 @@ static int __init rt2800pci_init(void) { int ret = 0; -#ifdef CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC ret = platform_driver_register(&rt2800soc_driver); if (ret) return ret; @@ -1294,7 +1294,7 @@ static int __init rt2800pci_init(void) #ifdef CONFIG_RT2800PCI_PCI ret = pci_register_driver(&rt2800pci_driver); if (ret) { -#ifdef CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC platform_driver_unregister(&rt2800soc_driver); #endif return ret; @@ -1309,7 +1309,7 @@ static void __exit rt2800pci_exit(void) #ifdef CONFIG_RT2800PCI_PCI pci_unregister_driver(&rt2800pci_driver); #endif -#ifdef CONFIG_RT2800PCI_WISOC +#ifdef CONFIG_RT2800PCI_SOC platform_driver_unregister(&rt2800soc_driver); #endif } -- GitLab From ac394917f5138f9bb2774718312dec179164f3dc Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 23 Dec 2009 00:03:23 +0100 Subject: [PATCH 0262/3892] rt2x00: Let rt2800lib check CONFIG_RT2X00_LIB_USB instead of CONFIG_RT2800USB rt2800lib currently checks whether RT2800USB is enabled in the configuration. Strictly speaking this is not necessary, it only needs to know whether the generic rt2x00usb library functions are available. Therefore check for RT2X00_LIB_USB instead. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 27bf887f1453..a654551b7325 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -37,7 +37,7 @@ #include #include "rt2x00.h" -#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) +#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) #include "rt2x00usb.h" #endif #include "rt2800lib.h" @@ -1121,7 +1121,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); -#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) +#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); #endif -- GitLab From 73a2f1259ebb49f9768aa12eee2a1071345eb7f2 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 23 Dec 2009 00:03:24 +0100 Subject: [PATCH 0263/3892] rt2x00: convert RT2800PCI_PCI and RT2800PCI_SOC Kconfig symbols to booleans. There is no need for Kconfig symbols RT2800PCI_PCI and RT2800PCI_SOC to be tristates, as they are only used to check whether RT2800 PCI or SOC support is to be compiled in. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 4 ++-- drivers/net/wireless/rt2x00/rt2800pci.c | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index bf60689aaabb..3ca824a91ad9 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -54,12 +54,12 @@ config RT61PCI When compiled as a module, this driver will be called rt61pci. config RT2800PCI_PCI - tristate + boolean depends on PCI default y config RT2800PCI_SOC - tristate + boolean depends on RALINK_RT288X || RALINK_RT305X default y diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 96e024477b2f..2f9deddaf75b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -48,14 +48,6 @@ #include "rt2800.h" #include "rt2800pci.h" -#ifdef CONFIG_RT2800PCI_PCI_MODULE -#define CONFIG_RT2800PCI_PCI -#endif - -#ifdef CONFIG_RT2800PCI_SOC_MODULE -#define CONFIG_RT2800PCI_SOC -#endif - /* * Allow hardware encryption to be disabled. */ -- GitLab From 5122d8986232ef2a761f5cf70c31666c4d65c3e4 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 23 Dec 2009 00:03:25 +0100 Subject: [PATCH 0264/3892] rt2x00: Cleanup chip handling helper functions. Let each of them take a struct rt2x00_dev pointer as argument instead of a mixture of struct rt2x00_chip and struct rt2x00_dev pointers. Preparation for further clean ups in the rt2x00 chip handling, especially for rt2800 devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +- drivers/net/wireless/rt2x00/rt2500pci.c | 39 ++++++----- drivers/net/wireless/rt2x00/rt2500usb.c | 38 +++++------ drivers/net/wireless/rt2x00/rt2800lib.c | 90 ++++++++++++------------- drivers/net/wireless/rt2x00/rt2800pci.c | 3 +- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +- drivers/net/wireless/rt2x00/rt2x00.h | 24 +++---- drivers/net/wireless/rt2x00/rt61pci.c | 29 ++++---- drivers/net/wireless/rt2x00/rt73usb.c | 36 +++++----- 9 files changed, 125 insertions(+), 143 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e7f46405a418..d86d233c6810 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * RF2420 chipset don't need any additional actions. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2420)) + if (rt2x00_rf(rt2x00dev, RF2420)) return; /* @@ -1343,8 +1343,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip_rf(rt2x00dev, value, reg); rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && - !rt2x00_rf(&rt2x00dev->chip, RF2421)) { + if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 408fcfc120f5..46cbc6ef66ab 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E and RT5222 need to flip TX I/Q */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || - rt2x00_rf(&rt2x00dev->chip, RF5222)) { + if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); @@ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E does not need RX I/Q Flip. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + if (rt2x00_rf(rt2x00dev, RF2525E)) rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); } else { rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); @@ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * Switch on tuning bits. * For RT2523 devices we do not need to update the R1 register. */ - if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) + if (!rt2x00_rf(rt2x00dev, RF2523)) rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); /* * For RT2525 we should first set the channel to half band higher. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + if (rt2x00_rf(rt2x00dev, RF2525)) { static const u32 vals[] = { 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a, 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a, @@ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * Switch off tuning bits. * For RT2523 devices we do not need to update the R1 register. */ - if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { + if (!rt2x00_rf(rt2x00dev, RF2523)) { rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); } @@ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, * up to version C the link tuning should halt after 20 * seconds while being associated. */ - if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && + if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D && rt2x00dev->intf_associated && count > 20) return; @@ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, * should go straight to dynamic CCA tuning when they * are not associated. */ - if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D || + if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D || !rt2x00dev->intf_associated) goto dynamic_cca_tune; @@ -1507,12 +1506,12 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip_rf(rt2x00dev, value, reg); rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && - !rt2x00_rf(&rt2x00dev->chip, RF2523) && - !rt2x00_rf(&rt2x00dev->chip, RF2524) && - !rt2x00_rf(&rt2x00dev->chip, RF2525) && - !rt2x00_rf(&rt2x00dev->chip, RF2525E) && - !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + if (!rt2x00_rf(rt2x00dev, RF2522) && + !rt2x00_rf(rt2x00dev, RF2523) && + !rt2x00_rf(rt2x00dev, RF2524) && + !rt2x00_rf(rt2x00dev, RF2525) && + !rt2x00_rf(rt2x00dev, RF2525E) && + !rt2x00_rf(rt2x00dev, RF5222)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + if (rt2x00_rf(rt2x00dev, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); spec->channels = rf_vals_bg_2522; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + } else if (rt2x00_rf(rt2x00dev, RF2523)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); spec->channels = rf_vals_bg_2523; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + } else if (rt2x00_rf(rt2x00dev, RF2524)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); spec->channels = rf_vals_bg_2524; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + } else if (rt2x00_rf(rt2x00dev, RF2525)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); spec->channels = rf_vals_bg_2525; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + } else if (rt2x00_rf(rt2x00dev, RF2525E)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; - } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + } else if (rt2x00_rf(rt2x00dev, RF5222)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 83f2592c59de..9e6f865c57f2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E and RT5222 need to flip TX I/Q */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || - rt2x00_rf(&rt2x00dev->chip, RF5222)) { + if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1); rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1); @@ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E does not need RX I/Q Flip. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + if (rt2x00_rf(rt2x00dev, RF2525E)) rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); } else { rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0); @@ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, /* * For RT2525E we should first set the channel to half band higher. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + if (rt2x00_rf(rt2x00dev, RF2525E)) { static const u32 vals[] = { 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, @@ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { + if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) { rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); rt2x00_set_field16(®, PHY_CSR2_LNA, 0); } else { @@ -1411,19 +1410,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip(rt2x00dev, RT2570, value, reg); rt2x00_print_chip(rt2x00dev); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || - rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { - + if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) || + rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } - if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && - !rt2x00_rf(&rt2x00dev->chip, RF2523) && - !rt2x00_rf(&rt2x00dev->chip, RF2524) && - !rt2x00_rf(&rt2x00dev->chip, RF2525) && - !rt2x00_rf(&rt2x00dev->chip, RF2525E) && - !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + if (!rt2x00_rf(rt2x00dev, RF2522) && + !rt2x00_rf(rt2x00dev, RF2523) && + !rt2x00_rf(rt2x00dev, RF2524) && + !rt2x00_rf(rt2x00dev, RF2525) && + !rt2x00_rf(rt2x00dev, RF2525E) && + !rt2x00_rf(rt2x00dev, RF5222)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -1667,22 +1665,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + if (rt2x00_rf(rt2x00dev, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); spec->channels = rf_vals_bg_2522; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + } else if (rt2x00_rf(rt2x00dev, RF2523)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); spec->channels = rf_vals_bg_2523; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + } else if (rt2x00_rf(rt2x00dev, RF2524)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); spec->channels = rf_vals_bg_2524; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + } else if (rt2x00_rf(rt2x00dev, RF2525)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); spec->channels = rf_vals_bg_2525; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + } else if (rt2x00_rf(rt2x00dev, RF2525E)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; - } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + } else if (rt2x00_rf(rt2x00dev, RF5222)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a654551b7325..8ff7db853286 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -220,8 +220,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, /* * RT2880 and RT3052 don't support MCU requests. */ - if (rt2x00_rt(&rt2x00dev->chip, RT2880) || - rt2x00_rt(&rt2x00dev->chip, RT3052)) + if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052)) return; mutex_lock(&rt2x00dev->csr_mutex); @@ -806,12 +805,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; - if ((rt2x00_rt(&rt2x00dev->chip, RT3070) || - rt2x00_rt(&rt2x00dev->chip, RT3090)) && - (rt2x00_rf(&rt2x00dev->chip, RF2020) || - rt2x00_rf(&rt2x00dev->chip, RF3020) || - rt2x00_rf(&rt2x00dev->chip, RF3021) || - rt2x00_rf(&rt2x00dev->chip, RF3022))) + if ((rt2x00_rt(rt2x00dev, RT3070) || + rt2x00_rt(rt2x00dev, RT3090)) && + (rt2x00_rf(rt2x00dev, RF2020) || + rt2x00_rf(rt2x00dev, RF3020) || + rt2x00_rf(rt2x00dev, RF3021) || + rt2x00_rf(rt2x00dev, RF3022))) rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); else rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); @@ -878,7 +877,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); rt2800_bbp_write(rt2x00dev, 3, bbp); - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { if (conf_is_ht40(conf)) { rt2800_bbp_write(rt2x00dev, 69, 0x1a); rt2800_bbp_write(rt2x00dev, 70, 0x0a); @@ -1041,7 +1040,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) + rt2x00_rev(rt2x00dev) == RT3070_VERSION) return 0x1c + (2 * rt2x00dev->lna_gain); else return 0x2e + rt2x00dev->lna_gain; @@ -1072,7 +1071,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count) { - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) + if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) return; /* @@ -1158,7 +1157,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2x00_rev(rt2x00dev) == RT3070_VERSION) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); @@ -1185,8 +1184,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); - if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && - rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) + if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION && + rt2x00_rev(rt2x00dev) < RT3070_VERSION) rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); else rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); @@ -1465,22 +1464,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 103, 0x00); rt2800_bbp_write(rt2x00dev, 105, 0x05); - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { rt2800_bbp_write(rt2x00dev, 69, 0x16); rt2800_bbp_write(rt2x00dev, 73, 0x12); } - if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) + if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION) rt2800_bbp_write(rt2x00dev, 84, 0x19); if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2x00_rev(rt2x00dev) == RT3070_VERSION) { rt2800_bbp_write(rt2x00dev, 70, 0x0a); rt2800_bbp_write(rt2x00dev, 84, 0x99); rt2800_bbp_write(rt2x00dev, 105, 0x05); } - if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { + if (rt2x00_rt(rt2x00dev, RT3052)) { rt2800_bbp_write(rt2x00dev, 31, 0x08); rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); @@ -1566,13 +1565,13 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 bbp; if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + rt2x00_rev(rt2x00dev) != RT3070_VERSION) return 0; if (rt2x00_intf_is_pci(rt2x00dev)) { - if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)) + if (!rt2x00_rf(rt2x00dev, RF3020) && + !rt2x00_rf(rt2x00dev, RF3021) && + !rt2x00_rf(rt2x00dev, RF3022)) return 0; } @@ -1737,7 +1736,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); - } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { + } else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) { /* * There is a max of 2 RX streams for RT28x0 series */ @@ -1839,17 +1838,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip_rf(rt2x00dev, value, reg); if (rt2x00_intf_is_usb(rt2x00dev)) { - struct rt2x00_chip *chip = &rt2x00dev->chip; - /* * The check for rt2860 is not a typo, some rt2870 hardware * identifies itself as rt2860 in the CSR register. */ - if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) || - rt2x00_check_rev(chip, 0xfff00000, 0x28700000) || - rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) { + if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) || + rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) || + rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) { rt2x00_set_chip_rt(rt2x00dev, RT2870); - } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + } else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) { rt2x00_set_chip_rt(rt2x00dev, RT3070); } else { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); @@ -1858,14 +1855,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) } rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && - !rt2x00_rf(&rt2x00dev->chip, RF2850) && - !rt2x00_rf(&rt2x00dev->chip, RF2720) && - !rt2x00_rf(&rt2x00dev->chip, RF2750) && - !rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF2020) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)) { + if (!rt2x00_rf(rt2x00dev, RF2820) && + !rt2x00_rf(rt2x00dev, RF2850) && + !rt2x00_rf(rt2x00dev, RF2720) && + !rt2x00_rf(rt2x00dev, RF2750) && + !rt2x00_rf(rt2x00dev, RF3020) && + !rt2x00_rf(rt2x00dev, RF2020) && + !rt2x00_rf(rt2x00dev, RF3021) && + !rt2x00_rf(rt2x00dev, RF3022)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2013,7 +2010,6 @@ static const struct rf_channel rf_vals_302x[] = { int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { - struct rt2x00_chip *chip = &rt2x00dev->chip; struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; char *tx_power1; @@ -2049,19 +2045,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(chip, RF2820) || - rt2x00_rf(chip, RF2720) || - (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) { + if (rt2x00_rf(rt2x00dev, RF2820) || + rt2x00_rf(rt2x00dev, RF2720) || + (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) { spec->num_channels = 14; spec->channels = rf_vals; - } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) { + } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals); spec->channels = rf_vals; - } else if (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF2020) || - rt2x00_rf(chip, RF3021) || - rt2x00_rf(chip, RF3022)) { + } else if (rt2x00_rf(rt2x00dev, RF3020) || + rt2x00_rf(rt2x00dev, RF2020) || + rt2x00_rf(rt2x00dev, RF3021) || + rt2x00_rf(rt2x00dev, RF3022)) { spec->num_channels = ARRAY_SIZE(rf_vals_302x); spec->channels = rf_vals_302x; } @@ -2069,7 +2065,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize HT information. */ - if (!rt2x00_rf(chip, RF2020)) + if (!rt2x00_rf(rt2x00dev, RF2020)) spec->ht.ht_supported = true; else spec->ht.ht_supported = false; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 2f9deddaf75b..b93eabb4fbe1 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1121,8 +1121,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware. */ - if (!rt2x00_rt(&rt2x00dev->chip, RT2880) && - !rt2x00_rt(&rt2x00dev->chip, RT3052)) + if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052)) __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 40295b454ff6..411655ecaf3a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -92,7 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len) static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len) { - u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; size_t offset = 0; /* @@ -138,7 +138,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, u32 reg; u32 offset; u32 length; - u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; /* * Check which section of the firmware we need. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 194dae01d0c3..a664a999b2b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -937,25 +937,25 @@ static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); } -static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) +static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt) { - return (chipset->rt == chip); + return (rt2x00dev->chip.rt == rt); } -static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip) +static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf) { - return (chipset->rf == chip); + return (rt2x00dev->chip.rf == rf); } -static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset) +static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev) { - return chipset->rev; + return rt2x00dev->chip.rev; } -static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, +static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev, const u32 mask, const u32 rev) { - return ((chipset->rev & mask) == rev); + return ((rt2x00dev->chip.rev & mask) == rev); } static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, @@ -964,20 +964,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, rt2x00dev->chip.intf = intf; } -static inline bool rt2x00_intf(const struct rt2x00_chip *chipset, +static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev, enum rt2x00_chip_intf intf) { - return (chipset->intf == intf); + return (rt2x00dev->chip.intf == intf); } static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev) { - return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI); + return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); } static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev) { - return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB); + return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); } /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0ca589306d71..c353b497a65d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, - rt2x00_rf(&rt2x00dev->chip, RF5325)); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); /* * Configure the RX antenna. @@ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, - rt2x00_rf(&rt2x00dev->chip, RF2529)); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); @@ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF5325)) + if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) rt61pci_config_antenna_5x(rt2x00dev, ant); - else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) + else if (rt2x00_rf(rt2x00dev, RF2527)) rt61pci_config_antenna_2x(rt2x00dev, ant); - else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { + else if (rt2x00_rf(rt2x00dev, RF2529)) { if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) rt61pci_config_antenna_2x(rt2x00dev, ant); else @@ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); + smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); rt61pci_bbp_read(rt2x00dev, 3, &r3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); @@ -2302,10 +2298,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip_rf(rt2x00dev, value, reg); rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && - !rt2x00_rf(&rt2x00dev->chip, RF5325) && - !rt2x00_rf(&rt2x00dev->chip, RF2527) && - !rt2x00_rf(&rt2x00dev->chip, RF2529)) { + if (!rt2x00_rf(rt2x00dev, RF5225) && + !rt2x00_rf(rt2x00dev, RF5325) && + !rt2x00_rf(rt2x00dev, RF2527) && + !rt2x00_rf(rt2x00dev, RF2529)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2360,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * the antenna settings should be gathered from the NIC * eeprom word. */ - if (rt2x00_rf(&rt2x00dev->chip, RF2529) && + if (rt2x00_rf(rt2x00dev, RF2529) && !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { rt2x00dev->default_ant.rx = ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); @@ -2571,8 +2567,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals_seq; } - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF5325)) { + if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_seq); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6ce88d3c3b65..a02691294395 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, * all others contain 20 bits. */ rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527))); + 20 + (rt2x00_rf(rt2x00dev, RF5225) || + rt2x00_rf(rt2x00dev, RF2527))); rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); @@ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); - if (rt2x00_rf(&rt2x00dev->chip, RF5226) || - rt2x00_rf(&rt2x00dev->chip, RF5225)) + if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225)) rt73usb_config_antenna_5x(rt2x00dev, ant); - else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || - rt2x00_rf(&rt2x00dev->chip, RF2527)) + else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527)) rt73usb_config_antenna_2x(rt2x00dev, ant); } @@ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); + smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); rt73usb_bbp_read(rt2x00dev, 3, &r3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); @@ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); reg = 0x000023b0; - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)) + if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)) rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); @@ -1827,16 +1823,16 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip(rt2x00dev, RT2571, value, reg); rt2x00_print_chip(rt2x00dev); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || - rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { + if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) || + rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } - if (!rt2x00_rf(&rt2x00dev->chip, RF5226) && - !rt2x00_rf(&rt2x00dev->chip, RF2528) && - !rt2x00_rf(&rt2x00dev->chip, RF5225) && - !rt2x00_rf(&rt2x00dev->chip, RF2527)) { + if (!rt2x00_rf(rt2x00dev, RF5226) && + !rt2x00_rf(rt2x00dev, RF2528) && + !rt2x00_rf(rt2x00dev, RF5225) && + !rt2x00_rf(rt2x00dev, RF2527)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2081,17 +2077,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { + if (rt2x00_rf(rt2x00dev, RF2528)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); spec->channels = rf_vals_bg_2528; - } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { + } else if (rt2x00_rf(rt2x00dev, RF5226)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5226); spec->channels = rf_vals_5226; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { + } else if (rt2x00_rf(rt2x00dev, RF2527)) { spec->num_channels = 14; spec->channels = rf_vals_5225_2527; - } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { + } else if (rt2x00_rf(rt2x00dev, RF5225)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); spec->channels = rf_vals_5225_2527; -- GitLab From 643aab6733799586c798a7b54b85c34d587b25e3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 22 Dec 2009 18:13:04 -0500 Subject: [PATCH 0265/3892] rtl8180: remove priv->mode It is only checked in add_interface, and there it is easily replaced with a check of priv->vif. If that information should become necessary, it is available in vif->type anyway. Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180.h | 1 - drivers/net/wireless/rtl818x/rtl8180_dev.c | 14 +++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h index 8721282a8185..de3844fe06d8 100644 --- a/drivers/net/wireless/rtl818x/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180.h @@ -60,7 +60,6 @@ struct rtl8180_priv { struct rtl818x_csr __iomem *map; const struct rtl818x_rf_ops *rf; struct ieee80211_vif *vif; - int mode; /* rtl8180 driver specific */ spinlock_t lock; diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 8a40a1439984..f01f1ef9e3be 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { }; - - void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8180_priv *priv = dev->priv; @@ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); - priv->mode = NL80211_IFTYPE_MONITOR; return 0; err_free_rings: @@ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev) u8 reg; int i; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); reg = rtl818x_ioread8(priv, &priv->map->CMD); @@ -661,12 +656,14 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, { struct rtl8180_priv *priv = dev->priv; - if (priv->mode != NL80211_IFTYPE_MONITOR) - return -EOPNOTSUPP; + /* + * We only support one active interface at a time. + */ + if (priv->vif) + return -EBUSY; switch (conf->type) { case NL80211_IFTYPE_STATION: - priv->mode = conf->type; break; default: return -EOPNOTSUPP; @@ -688,7 +685,6 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; - priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; } -- GitLab From d30506e0357e5448c7d38bb3739c451dbe4c174e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 22 Dec 2009 18:13:05 -0500 Subject: [PATCH 0266/3892] rtl8187: remove priv->mode It is checked in add_interface, but there it is easily replaced with a check of priv->vif. If that information should become necessary, it is available in vif->type anyway. It is also checked in led_turn_on and led_turn_off, where I made the substitutions as described above. Of course, these checks seem to have been incorrect since the driver was using NL80211_IFTYPE_MONITOR to indicate no interface rather than NL80211_IFTYPE_UNSPECIFIED. Anyway, I think these checks may be extraneous...? Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187.h | 2 +- drivers/net/wireless/rtl818x/rtl8187_dev.c | 5 +---- drivers/net/wireless/rtl818x/rtl8187_leds.c | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index 6af0f3f71f3a..6bb32112e65c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -92,7 +92,7 @@ struct rtl8187_priv { struct rtl818x_csr *map; const struct rtl818x_rf_ops *rf; struct ieee80211_vif *vif; - int mode; + /* The mutex protects the TX loopback state. * Any attempt to set channels concurrently locks the device. */ diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index bc5726dd5fe4..1cb0eff46223 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1025,12 +1025,11 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, int ret = -EOPNOTSUPP; mutex_lock(&priv->conf_mutex); - if (priv->mode != NL80211_IFTYPE_MONITOR) + if (priv->vif) goto exit; switch (conf->type) { case NL80211_IFTYPE_STATION: - priv->mode = conf->type; break; default: goto exit; @@ -1055,7 +1054,6 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, { struct rtl8187_priv *priv = dev->priv; mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; mutex_unlock(&priv->conf_mutex); } @@ -1365,7 +1363,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS; diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index ded44c045eb2..f82aa8b4bdde 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work) struct rtl8187_led *led = &priv->led_tx; /* Don't change the LED, when the device is down. */ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) return ; /* Skip if the LED is not registered. */ @@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work) struct rtl8187_led *led = &priv->led_tx; /* Don't change the LED, when the device is down. */ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) return ; /* Skip if the LED is not registered. */ -- GitLab From 9607e6b66a0d25ca63b70d54a4283fa13d8f7c9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:31 +0100 Subject: [PATCH 0267/3892] mac80211: add ieee80211_sdata_running Instead of always using netif_running(sdata->dev) use ieee80211_sdata_running(sdata) now which is just an inline containing netif_running() for now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 ++---- net/mac80211/ibss.c | 4 ++-- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/iface.c | 10 +++++----- net/mac80211/key.c | 4 ++-- net/mac80211/main.c | 2 +- net/mac80211/mesh.c | 2 +- net/mac80211/mlme.c | 8 ++++---- net/mac80211/pm.c | 2 +- net/mac80211/rx.c | 6 +++--- net/mac80211/scan.c | 12 ++++++------ net/mac80211/sta_info.c | 2 +- net/mac80211/status.c | 2 +- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 10 +++++----- 15 files changed, 40 insertions(+), 37 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 63843e3e576a..fdac1bcbfcc0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret; - if (netif_running(dev)) + if (ieee80211_sdata_running(sdata)) return -EBUSY; if (!nl80211_params_check(type, params)) return -EINVAL; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - ret = ieee80211_if_change_type(sdata, type); if (ret) return ret; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ef6c6b2401d1..3a61f3ba85c9 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -744,7 +744,7 @@ static void ieee80211_ibss_work(struct work_struct *work) if (WARN_ON(local->suspended)) return; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; if (local->scanning) @@ -827,7 +827,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type != NL80211_IFTYPE_ADHOC) continue; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 88b0ba6c7484..adeae03c26a3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -960,6 +960,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); u32 __ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); +static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) +{ + return netif_running(sdata->dev); +} + /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a6e6da3cab70..1ceca14331d4 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -65,7 +65,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret; - if (netif_running(dev)) + if (ieee80211_sdata_running(sdata)) return -EBUSY; ret = eth_mac_addr(dev, addr); @@ -111,7 +111,7 @@ static int ieee80211_open(struct net_device *dev) list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; - if (ndev != dev && netif_running(ndev)) { + if (ndev != dev && ieee80211_sdata_running(nsdata)) { /* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution @@ -197,7 +197,7 @@ static int ieee80211_open(struct net_device *dev) struct net_device *ndev = nsdata->dev; /* - * No need to check netif_running since we do not allow + * No need to check running since we do not allow * it to start up with this invalid address. */ if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { @@ -756,7 +756,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, * and goes into the requested mode. */ - if (netif_running(sdata->dev)) + if (ieee80211_sdata_running(sdata)) return -EBUSY; /* Purge and reset type-dependent state. */ @@ -930,7 +930,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) return ieee80211_idle_off(local, "scanning"); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 32ee6d0ee34d..8160d9c5372e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key, add_todo(old_key, KEY_FLAG_TODO_DELETE); add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); - if (netif_running(sdata->dev)) + if (ieee80211_sdata_running(sdata)) add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); spin_unlock_irqrestore(&sdata->local->key_lock, flags); @@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) { ASSERT_RTNL(); - if (WARN_ON(!netif_running(sdata->dev))) + if (WARN_ON(!ieee80211_sdata_running(sdata))) return; ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d4426748ab10..e93bc558d785 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -212,7 +212,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->quiescing || !netif_running(sdata->dev) || + if (local->quiescing || !ieee80211_sdata_running(sdata) || test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e0bd85e3d4b6..61080c5fad50 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct sk_buff *skb; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; if (local->scanning) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2f9ed8b9c3f0..7f9909340c09 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -604,7 +604,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; mutex_lock(&ifmgd->mtx); @@ -750,7 +750,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type != NL80211_IFTYPE_STATION) continue; @@ -1263,7 +1263,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool already = false; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; if (sdata->local->scanning) @@ -2118,7 +2118,7 @@ static void ieee80211_sta_work(struct work_struct *work) enum rx_mgmt_action rma; bool anybusy = false; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; if (local->scanning) diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 05e161c3cbc5..913dc7e3b29e 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -93,7 +93,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) break; } - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; /* disable beaconing */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6cbf1a7b3157..f60dfca52196 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -289,7 +289,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) continue; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (prev_dev) { @@ -2056,7 +2056,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, skb->protocol = htons(ETH_P_802_2); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type != NL80211_IFTYPE_MONITOR || @@ -2318,7 +2318,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } if (!found_sta) { list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type == NL80211_IFTYPE_MONITOR || diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 66da0ab1d8fa..ae1830056521 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -346,7 +346,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; /* Tell AP we're back */ @@ -396,7 +396,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; /* disable beaconing */ @@ -526,7 +526,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, /* check if at least one STA interface is associated */ mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { @@ -571,7 +571,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca */ mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { @@ -603,7 +603,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca */ mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; /* Tell AP we're back */ @@ -727,7 +727,7 @@ void ieee80211_scan_work(struct work_struct *work) /* * Avoid re-scheduling when the sdata is going away. */ - if (!netif_running(sdata->dev)) { + if (!ieee80211_sdata_running(sdata)) { ieee80211_scan_completed(&local->hw, true); return; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d1a77e79d7a9..f039e761aec1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -367,7 +367,7 @@ int sta_info_insert(struct sta_info *sta) * something inserts a STA (on one CPU) without holding the RTNL * and another CPU turns off the net device. */ - if (unlikely(!netif_running(sdata->dev))) { + if (unlikely(!ieee80211_sdata_running(sdata))) { err = -ENETDOWN; goto out_free; } diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 0c0850d37dda..0ebcdda24200 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -351,7 +351,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ac48c86ae6b3..1593a2ffd67a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1469,7 +1469,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { - if (!netif_running(tmp_sdata->dev)) + if (!ieee80211_sdata_running(tmp_sdata)) continue; if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b01972579c7c..5ffe9e831b66 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces( case NL80211_IFTYPE_MESH_POINT: break; } - if (netif_running(sdata->dev)) + if (ieee80211_sdata_running(sdata)) iterator(data, sdata->vif.addr, &sdata->vif); } @@ -502,7 +502,7 @@ void ieee80211_iterate_active_interfaces_atomic( case NL80211_IFTYPE_MESH_POINT: break; } - if (netif_running(sdata->dev)) + if (ieee80211_sdata_running(sdata)) iterator(data, sdata->vif.addr, &sdata->vif); } @@ -1056,7 +1056,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_MONITOR && - netif_running(sdata->dev)) { + ieee80211_sdata_running(sdata)) { conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = sdata->vif.addr; @@ -1103,7 +1103,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { u32 changed = ~0; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) continue; switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: @@ -1131,7 +1131,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* add back keys */ list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) + if (ieee80211_sdata_running(sdata)) ieee80211_enable_keys(sdata); ieee80211_wake_queues_by_reason(hw, -- GitLab From a80f7c0b088187c8471b441d461e937991870661 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:32 +0100 Subject: [PATCH 0268/3892] mac80211: introduce flush operation We've long lacked a good confirmation that frames have really gone out, e.g. before going off-channel for a scan. Add a flush() operation that drivers can implement to provide that confirmation, and use it in a few places: * before scanning sends the nullfunc frames * after scanning sends the nullfunc frames, if any * when going idle, to send any pending frames Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 11 +++++++++++ include/net/mac80211.h | 5 +++++ net/mac80211/driver-ops.h | 7 +++++++ net/mac80211/driver-trace.h | 21 +++++++++++++++++++++ net/mac80211/iface.c | 2 ++ net/mac80211/scan.c | 13 +++++++++++-- 6 files changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 718a5f198c30..4dee69a38c1d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, return 0; } +static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) +{ + /* + * In this special case, there's nothing we need to + * do because hwsim does transmission synchronously. + * In the future, when it does transmissions via + * userspace, we may need to do something. + */ +} + static const struct ieee80211_ops mac80211_hwsim_ops = { @@ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .conf_tx = mac80211_hwsim_conf_tx, CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) .ampdu_action = mac80211_hwsim_ampdu_action, + .flush = mac80211_hwsim_flush, }; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 494ac69ff477..77ea34b03285 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1545,6 +1545,10 @@ enum ieee80211_ampdu_mlme_action { * and need to call wiphy_rfkill_set_hw_state() in the callback. * * @testmode_cmd: Implement a cfg80211 test mode command. + * + * @flush: Flush all pending frames from the hardware queue, making sure + * that the hardware queues are empty. If the parameter @drop is set + * to %true, pending frames may be dropped. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1601,6 +1605,7 @@ struct ieee80211_ops { #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); #endif + void (*flush)(struct ieee80211_hw *hw, bool drop); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 727e4cf7b8a6..cbe133bcdf34 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -259,4 +259,11 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local) if (local->ops->rfkill_poll) local->ops->rfkill_poll(&local->hw); } + +static inline void drv_flush(struct ieee80211_local *local, bool drop) +{ + trace_drv_flush(local, drop); + if (local->ops->flush) + local->ops->flush(&local->hw, drop); +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 7a849b920165..977cc7528bc6 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action, LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); + +TRACE_EVENT(drv_flush, + TP_PROTO(struct ieee80211_local *local, bool drop), + + TP_ARGS(local, drop), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(bool, drop) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->drop = drop; + ), + + TP_printk( + LOCAL_PR_FMT " drop:%d", + LOCAL_PR_ARG, __entry->drop + ) +); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1ceca14331d4..389dc8d880f3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -917,6 +917,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) wiphy_name(local->hw.wiphy)); #endif + drv_flush(local, false); + local->hw.conf.flags |= IEEE80211_CONF_IDLE; return IEEE80211_CONF_CHANGE_IDLE; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ae1830056521..d98c45e5528b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -418,9 +418,10 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; + drv_flush(local, false); + ieee80211_configure_filter(local); - /* TODO: start scan as soon as all nullfunc frames are ACKed */ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, IEEE80211_CHANNEL_TIME); @@ -584,8 +585,16 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca __set_bit(SCAN_OFF_CHANNEL, &local->scanning); + /* + * What if the nullfunc frames didn't arrive? + */ + drv_flush(local, false); + if (local->ops->flush) + *next_delay = 0; + else + *next_delay = HZ / 10; + /* advance to the next channel to be scanned */ - *next_delay = HZ / 10; local->next_scan_state = SCAN_SET_CHANNEL; } -- GitLab From 63f170e0c80a131cdd549fab7afb5036009944fc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:33 +0100 Subject: [PATCH 0269/3892] mac80211: let cfg80211 manage auth state mac80211 currently hangs on to the auth state by keeping it on the work list. That can lead to confusing behaviour like rejecting scans while authenticated to any AP (but not yet associated.) It also means that it needs to keep track of the work struct while associated for when it gets disassociated (or disassociates.) Change this to free the work struct after the authentication completed successfully and allocate a new one for associating, thereby letting cfg80211 manage the auth state. Another change necessary for this is to tell cfg80211 about all unicast deauth frames sent to mac80211 since now it can no longer check the auth state, but that check was racy anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/mlme.c | 173 +++++++++++++++---------------------- 2 files changed, 73 insertions(+), 103 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index adeae03c26a3..e21e0301548b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,7 +228,7 @@ struct mesh_preq_queue { }; enum ieee80211_mgd_state { - IEEE80211_MGD_STATE_IDLE, + IEEE80211_MGD_STATE_INVALID, IEEE80211_MGD_STATE_PROBE, IEEE80211_MGD_STATE_AUTH, IEEE80211_MGD_STATE_ASSOC, @@ -285,7 +285,6 @@ struct ieee80211_if_managed { struct mutex mtx; struct ieee80211_bss *associated; - struct ieee80211_mgd_work *old_associate_work; struct list_head work_list; u8 bssid[ETH_ALEN]; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7f9909340c09..f060bc616203 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -949,11 +949,10 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, + struct ieee80211_bss *bss, u32 bss_info_changed) { struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss = wk->bss; bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ @@ -966,7 +965,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); sdata->u.mgd.associated = bss; - sdata->u.mgd.old_associate_work = wk; memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); /* just to be sure */ @@ -1090,8 +1088,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool deauth) +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1109,16 +1106,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); - if (deauth) { - kfree(ifmgd->old_associate_work); - ifmgd->old_associate_work = NULL; - } else { - struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; - - wk->state = IEEE80211_MGD_STATE_IDLE; - list_add(&wk->list, &ifmgd->work_list); - } - /* * we need to commit the associated = NULL change because the * scan code uses that to determine whether this iface should @@ -1333,7 +1320,8 @@ EXPORT_SYMBOL(ieee80211_beacon_loss); static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_work *wk) { - wk->state = IEEE80211_MGD_STATE_IDLE; + list_del(&wk->list); + kfree(wk); printk(KERN_DEBUG "%s: authenticated\n", sdata->name); } @@ -1411,7 +1399,6 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1423,23 +1410,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); - if (wk) - bssid = wk->bss->cbss.bssid; - else - bssid = ifmgd->associated->cbss.bssid; + bssid = ifmgd->associated->cbss.bssid; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", sdata->name, bssid, reason_code); - if (!wk) { - ieee80211_set_disassoc(sdata, true); - ieee80211_recalc_idle(sdata->local); - } else { - list_del(&wk->list); - kfree(wk); - } + ieee80211_set_disassoc(sdata); + ieee80211_recalc_idle(sdata->local); return RX_MGMT_CFG80211_DEAUTH; } @@ -1468,7 +1447,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", sdata->name, mgmt->sa, reason_code); - ieee80211_set_disassoc(sdata, false); + ieee80211_set_disassoc(sdata); ieee80211_recalc_idle(sdata->local); return RX_MGMT_CFG80211_DISASSOC; } @@ -1484,6 +1463,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; + struct ieee80211_bss *bss = wk->bss; u32 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; @@ -1502,7 +1482,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (len < 24 + 6) return RX_MGMT_NONE; - if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + if (memcmp(bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) return RX_MGMT_NONE; capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); @@ -1532,10 +1512,17 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } + /* + * Here the association was either successful or not. + */ + + /* delete work item -- must be before set_associated for PS */ + list_del(&wk->list); + kfree(wk); + if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->name, status_code); - wk->state = IEEE80211_MGD_STATE_IDLE; return RX_MGMT_CFG80211_ASSOC; } @@ -1553,7 +1540,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: associated\n", sdata->name); ifmgd->aid = aid; - sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); + sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" " the AP\n", sdata->name); @@ -1645,18 +1632,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, - wk->bss->cbss.bssid, + bss->cbss.bssid, ap_ht_cap_flags); - /* delete work item -- must be before set_associated for PS */ - list_del(&wk->list); - /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - /* this will take ownership of wk */ - ieee80211_set_associated(sdata, wk, changed); + ieee80211_set_associated(sdata, bss, changed); /* * Start timer to probe the connection to the AP now. @@ -1999,8 +1982,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, skb->len, rx_status); break; case IEEE80211_STYPE_DEAUTH: - rma = ieee80211_rx_mgmt_deauth(sdata, NULL, - mgmt, skb->len); + rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); break; case IEEE80211_STYPE_DISASSOC: rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); @@ -2051,8 +2033,15 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, skb->len, true); break; case IEEE80211_STYPE_DEAUTH: - rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, - skb->len); + if (skb->len >= 24 + 2 /* mgmt + deauth reason */) { + /* + * We get here if we get deauth while + * trying to auth/assoc. Telling cfg80211 + * is handled below, unconditionally. + */ + list_del(&wk->list); + kfree(wk); + } break; } /* @@ -2066,6 +2055,12 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); + if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { + WARN_ON(rma != RX_MGMT_NONE); + rma = RX_MGMT_CFG80211_DEAUTH; + } + switch (rma) { case RX_MGMT_NONE: /* no action */ @@ -2116,7 +2111,6 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_mgd_work *wk, *tmp; LIST_HEAD(free_work); enum rx_mgmt_action rma; - bool anybusy = false; if (!ieee80211_sdata_running(sdata)) return; @@ -2171,7 +2165,7 @@ static void ieee80211_sta_work(struct work_struct *work) printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata); ieee80211_recalc_idle(local); mutex_unlock(&ifmgd->mtx); /* @@ -2203,8 +2197,6 @@ static void ieee80211_sta_work(struct work_struct *work) switch (wk->state) { default: WARN_ON(1); - /* fall through */ - case IEEE80211_MGD_STATE_IDLE: /* nothing */ rma = RX_MGMT_NONE; break; @@ -2227,20 +2219,19 @@ static void ieee80211_sta_work(struct work_struct *work) case RX_MGMT_CFG80211_ASSOC_TO: list_del(&wk->list); list_add(&wk->list, &free_work); - wk->tries = rma; /* small abuse but only local */ + /* + * small abuse but only local -- keep the + * action type in wk->timeout while the item + * is on the cleanup list + */ + wk->timeout = rma; break; default: WARN(1, "unexpected: %d", rma); } } - list_for_each_entry(wk, &ifmgd->work_list, list) { - if (wk->state != IEEE80211_MGD_STATE_IDLE) { - anybusy = true; - break; - } - } - if (!anybusy && + if (list_empty(&ifmgd->work_list) && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -2249,7 +2240,8 @@ static void ieee80211_sta_work(struct work_struct *work) mutex_unlock(&ifmgd->mtx); list_for_each_entry_safe(wk, tmp, &free_work, list) { - switch (wk->tries) { + /* see above how we're using wk->timeout */ + switch (wk->timeout) { case RX_MGMT_CFG80211_AUTH_TO: cfg80211_send_auth_timeout(sdata->dev, wk->bss->cbss.bssid); @@ -2259,7 +2251,7 @@ static void ieee80211_sta_work(struct work_struct *work) wk->bss->cbss.bssid); break; default: - WARN(1, "unexpected: %d", wk->tries); + WARN(1, "unexpected: %lu", wk->timeout); } list_del(&wk->list); @@ -2487,35 +2479,18 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_mgd_work *wk, *found = NULL; + struct ieee80211_mgd_work *wk; + const u8 *ssid; int i, err; mutex_lock(&ifmgd->mtx); - list_for_each_entry(wk, &ifmgd->work_list, list) { - if (&wk->bss->cbss == req->bss && - wk->state == IEEE80211_MGD_STATE_IDLE) { - found = wk; - break; - } - } - - if (!found) { - err = -ENOLINK; - goto out; - } - - list_del(&found->list); - - wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); + wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); if (!wk) { - list_add(&found->list, &ifmgd->work_list); err = -ENOMEM; goto out; } - list_add(&wk->list, &ifmgd->work_list); - ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) @@ -2524,8 +2499,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); @@ -2533,11 +2506,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else wk->ie_len = 0; + wk->bss = (void *)req->bss; + + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + memcpy(wk->ssid, ssid + 2, ssid[1]); + wk->ssid_len = ssid[1]; + if (req->prev_bssid) memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); wk->state = IEEE80211_MGD_STATE_ASSOC; - wk->tries = 0; wk->timeout = jiffies; /* run right away */ if (req->use_mfp) { @@ -2553,6 +2531,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, else ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + list_add(&wk->list, &ifmgd->work_list); ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); err = 0; @@ -2568,23 +2550,23 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_work *wk; - const u8 *bssid = NULL; + const u8 *bssid = req->bss->bssid; bool not_auth_yet = false; mutex_lock(&ifmgd->mtx); if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata); } else list_for_each_entry(wk, &ifmgd->work_list, list) { - if (&wk->bss->cbss == req->bss) { - bssid = req->bss->bssid; - if (wk->state == IEEE80211_MGD_STATE_PROBE) - not_auth_yet = true; - list_del(&wk->list); - kfree(wk); - break; - } + if (wk->state != IEEE80211_MGD_STATE_PROBE) + continue; + if (req->bss != &wk->bss->cbss) + continue; + not_auth_yet = true; + list_del(&wk->list); + kfree(wk); + break; } /* @@ -2601,17 +2583,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, return 0; } - /* - * cfg80211 should catch this ... but it's racy since - * we can receive a deauth frame, process it, hand it - * to cfg80211 while that's in a locked section already - * trying to tell us that the user wants to disconnect. - */ - if (!bssid) { - mutex_unlock(&ifmgd->mtx); - return -ENOLINK; - } - mutex_unlock(&ifmgd->mtx); printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", @@ -2648,7 +2619,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", sdata->name, req->bss->bssid, req->reason_code); - ieee80211_set_disassoc(sdata, false); + ieee80211_set_disassoc(sdata); mutex_unlock(&ifmgd->mtx); -- GitLab From f679f65d417c3ea3f91b4bbfb68e3951c9eb8f04 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:34 +0100 Subject: [PATCH 0270/3892] mac80211: generalise management work a bit As a first step of generalising management work, this renames a few things and puts more information directly into the struct so that auth/assoc need not access the BSS pointer as often -- in fact it can be removed from auth completely. Also since the previous patch made sure a new work item is used for association, we can make the different data a union. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 53 ++++++--- net/mac80211/mlme.c | 226 ++++++++++++++++++++++--------------- 2 files changed, 172 insertions(+), 107 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e21e0301548b..0339e909e0c4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -227,31 +227,48 @@ struct mesh_preq_queue { u8 flags; }; -enum ieee80211_mgd_state { - IEEE80211_MGD_STATE_INVALID, - IEEE80211_MGD_STATE_PROBE, - IEEE80211_MGD_STATE_AUTH, - IEEE80211_MGD_STATE_ASSOC, +enum ieee80211_work_type { + IEEE80211_WORK_AUTH_PROBE, + IEEE80211_WORK_AUTH, + IEEE80211_WORK_ASSOC, }; -struct ieee80211_mgd_work { +struct ieee80211_work { struct list_head list; - struct ieee80211_bss *bss; - int ie_len; - u8 prev_bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - unsigned long timeout; - enum ieee80211_mgd_state state; - u16 auth_alg, auth_transaction; - int tries; + struct ieee80211_channel *chan; + /* XXX: chan type? -- right now not really needed */ + unsigned long timeout; + enum ieee80211_work_type type; - u8 key[WLAN_KEY_LEN_WEP104]; - u8 key_len, key_idx; + union { + struct { + int tries; + u16 algorithm, transaction; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + u8 bssid[ETH_ALEN]; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 key_len, key_idx; + bool privacy; + } auth; + struct { + struct ieee80211_bss *bss; + const u8 *supp_rates; + const u8 *ht_information_ie; + int tries; + u16 capability; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + u8 supp_rates_len; + bool wmm_used; + } assoc; + }; + int ie_len; /* must be last */ - u8 ie[0]; /* for auth or assoc frame, not probe */ + u8 ie[0]; }; /* flags used in struct ieee80211_if_managed.flags */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f060bc616203..c65225f29bb6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -125,15 +125,15 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } -static int ieee80211_compatible_rates(struct ieee80211_bss *bss, +static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, struct ieee80211_supported_band *sband, u32 *rates) { int i, j, count; *rates = 0; count = 0; - for (i = 0; i < bss->supp_rates_len; i++) { - int rate = (bss->supp_rates[i] & 0x7F) * 5; + for (i = 0; i < supp_rates_len; i++) { + int rate = (supp_rates[i] & 0x7F) * 5; for (j = 0; j < sband->n_bitrates; j++) if (sband->bitrates[j].bitrate == rate) { @@ -232,7 +232,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk) + struct ieee80211_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -248,7 +248,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + wk->ie_len + - wk->ssid_len); + wk->assoc.ssid_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " "frame\n", sdata->name); @@ -267,35 +267,37 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) + if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - if (wk->bss->wmm_used) + if (wk->assoc.wmm_used) wmm = 1; /* get all rates supported by the device and the AP as * some APs don't like getting a superset of their rates * in the association request (e.g. D-Link DAP 1353 in * b-only mode) */ - rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); + rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, + wk->assoc.supp_rates_len, + sband, &rates); - if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); + memcpy(mgmt->da, wk->assoc.bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); + memcpy(mgmt->bssid, wk->assoc.bssid, ETH_ALEN); - if (!is_zero_ether_addr(wk->prev_bssid)) { + if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); mgmt->u.reassoc_req.listen_interval = cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, + memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, ETH_ALEN); } else { skb_put(skb, 4); @@ -307,10 +309,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } /* SSID */ - ies = pos = skb_put(skb, 2 + wk->ssid_len); + ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); *pos++ = WLAN_EID_SSID; - *pos++ = wk->ssid_len; - memcpy(pos, wk->ssid, wk->ssid_len); + *pos++ = wk->assoc.ssid_len; + memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); /* add all rates which were marked to be used above */ supp_rates_len = rates_len; @@ -392,7 +394,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = wk->assoc.ht_information_ie) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = @@ -1003,23 +1005,43 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_carrier_on(sdata->dev); } +static void ieee80211_remove_auth_bss(struct ieee80211_local *local, + struct ieee80211_work *wk) +{ + struct cfg80211_bss *cbss; + u16 capa_val = WLAN_CAPABILITY_ESS; + + if (wk->auth.privacy) + capa_val |= WLAN_CAPABILITY_PRIVACY; + + cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->auth.bssid, + wk->auth.ssid, wk->auth.ssid_len, + WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, + capa_val); + if (!cbss) + return; + + cfg80211_unlink_bss(local->hw.wiphy, cbss); + cfg80211_put_bss(cbss); +} + static enum rx_mgmt_action __must_check ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk) + struct ieee80211_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - wk->tries++; - if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { + wk->auth.tries++; + if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->name, wk->bss->cbss.bssid); + sdata->name, wk->auth.bssid); /* * Most likely AP is not in the range so remove the * bss struct for that AP. */ - cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + ieee80211_remove_auth_bss(local, wk); /* * We might have a pending scan which had no chance to run yet @@ -1031,14 +1053,14 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", - sdata->name, wk->bss->cbss.bssid, - wk->tries); + sdata->name, wk->auth.bssid, wk->auth.tries); /* * Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ - ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); + ieee80211_send_probe_req(sdata, NULL, wk->auth.ssid, wk->auth.ssid_len, + NULL, 0); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; run_again(ifmgd, wk->timeout); @@ -1049,22 +1071,21 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, static enum rx_mgmt_action __must_check ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk) + struct ieee80211_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - wk->tries++; - if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { + wk->auth.tries++; + if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: authentication with AP %pM" - " timed out\n", - sdata->name, wk->bss->cbss.bssid); + " timed out\n", sdata->name, wk->auth.bssid); /* * Most likely AP is not in the range so remove the * bss struct for that AP. */ - cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + ieee80211_remove_auth_bss(local, wk); /* * We might have a pending scan which had no chance to run yet @@ -1076,11 +1097,11 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", - sdata->name, wk->bss->cbss.bssid, wk->tries); + sdata->name, wk->auth.bssid, wk->auth.tries); - ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, - wk->bss->cbss.bssid, NULL, 0, 0); - wk->auth_transaction = 2; + ieee80211_send_auth(sdata, 1, wk->auth.algorithm, wk->ie, wk->ie_len, + wk->auth.bssid, NULL, 0, 0); + wk->auth.transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; run_again(ifmgd, wk->timeout); @@ -1176,22 +1197,22 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) static enum rx_mgmt_action __must_check ieee80211_associate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk) + struct ieee80211_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - wk->tries++; - if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { + wk->assoc.tries++; + if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { printk(KERN_DEBUG "%s: association with AP %pM" " timed out\n", - sdata->name, wk->bss->cbss.bssid); + sdata->name, wk->assoc.bssid); /* * Most likely AP is not in the range so remove the * bss struct for that AP. */ - cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + cfg80211_unlink_bss(local->hw.wiphy, &wk->assoc.bss->cbss); /* * We might have a pending scan which had no chance to run yet @@ -1203,7 +1224,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, } printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", - sdata->name, wk->bss->cbss.bssid, wk->tries); + sdata->name, wk->assoc.bssid, wk->assoc.tries); ieee80211_send_assoc(sdata, wk); wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; @@ -1318,7 +1339,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) EXPORT_SYMBOL(ieee80211_beacon_loss); static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk) + struct ieee80211_work *wk) { list_del(&wk->list); kfree(wk); @@ -1327,7 +1348,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, + struct ieee80211_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1338,38 +1359,38 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.challenge) return; - ieee80211_send_auth(sdata, 3, wk->auth_alg, + ieee80211_send_auth(sdata, 3, wk->auth.algorithm, elems.challenge - 2, elems.challenge_len + 2, - wk->bss->cbss.bssid, - wk->key, wk->key_len, wk->key_idx); - wk->auth_transaction = 4; + wk->auth.bssid, wk->auth.key, wk->auth.key_len, + wk->auth.key_idx); + wk->auth.transaction = 4; } static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, + struct ieee80211_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { u16 auth_alg, auth_transaction, status_code; - if (wk->state != IEEE80211_MGD_STATE_AUTH) + if (wk->type != IEEE80211_WORK_AUTH) return RX_MGMT_NONE; if (len < 24 + 6) return RX_MGMT_NONE; - if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + if (memcmp(wk->auth.bssid, mgmt->sa, ETH_ALEN) != 0) return RX_MGMT_NONE; - if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + if (memcmp(wk->auth.bssid, mgmt->bssid, ETH_ALEN) != 0) return RX_MGMT_NONE; auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - if (auth_alg != wk->auth_alg || - auth_transaction != wk->auth_transaction) + if (auth_alg != wk->auth.algorithm || + auth_transaction != wk->auth.transaction) return RX_MGMT_NONE; if (status_code != WLAN_STATUS_SUCCESS) { @@ -1378,14 +1399,14 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_CFG80211_AUTH; } - switch (wk->auth_alg) { + switch (wk->auth.algorithm) { case WLAN_AUTH_OPEN: case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: ieee80211_auth_completed(sdata, wk); return RX_MGMT_CFG80211_AUTH; case WLAN_AUTH_SHARED_KEY: - if (wk->auth_transaction == 4) { + if (wk->auth.transaction == 4) { ieee80211_auth_completed(sdata, wk); return RX_MGMT_CFG80211_AUTH; } else @@ -1455,7 +1476,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, + struct ieee80211_work *wk, struct ieee80211_mgmt *mgmt, size_t len, bool reassoc) { @@ -1463,7 +1484,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; - struct ieee80211_bss *bss = wk->bss; + struct ieee80211_bss *bss = wk->assoc.bss; u32 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; @@ -1693,7 +1714,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgd_work *wk, + struct ieee80211_work *wk, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { @@ -1718,11 +1739,11 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); /* direct probe may be part of the association flow */ - if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { + if (wk && wk->type == IEEE80211_WORK_AUTH_PROBE) { printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); - wk->tries = 0; - wk->state = IEEE80211_MGD_STATE_AUTH; + wk->auth.tries = 0; + wk->type = IEEE80211_WORK_AUTH; WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); } @@ -1959,7 +1980,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; - struct ieee80211_mgd_work *wk; + struct ieee80211_work *wk; enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; @@ -2013,7 +2034,20 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, } list_for_each_entry(wk, &ifmgd->work_list, list) { - if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + const u8 *bssid = NULL; + + switch (wk->type) { + case IEEE80211_WORK_AUTH_PROBE: + case IEEE80211_WORK_AUTH: + bssid = wk->auth.bssid; + break; + case IEEE80211_WORK_ASSOC: + bssid = wk->assoc.bssid; + break; + default: + continue; + } + if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) continue; switch (fc & IEEE80211_FCTL_STYPE) { @@ -2108,7 +2142,7 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd; struct sk_buff *skb; - struct ieee80211_mgd_work *wk, *tmp; + struct ieee80211_work *wk, *tmp; LIST_HEAD(free_work); enum rx_mgmt_action rma; @@ -2194,19 +2228,19 @@ static void ieee80211_sta_work(struct work_struct *work) continue; } - switch (wk->state) { + switch (wk->type) { default: WARN_ON(1); /* nothing */ rma = RX_MGMT_NONE; break; - case IEEE80211_MGD_STATE_PROBE: + case IEEE80211_WORK_AUTH_PROBE: rma = ieee80211_direct_probe(sdata, wk); break; - case IEEE80211_MGD_STATE_AUTH: + case IEEE80211_WORK_AUTH: rma = ieee80211_authenticate(sdata, wk); break; - case IEEE80211_MGD_STATE_ASSOC: + case IEEE80211_WORK_ASSOC: rma = ieee80211_associate(sdata, wk); break; } @@ -2243,12 +2277,11 @@ static void ieee80211_sta_work(struct work_struct *work) /* see above how we're using wk->timeout */ switch (wk->timeout) { case RX_MGMT_CFG80211_AUTH_TO: - cfg80211_send_auth_timeout(sdata->dev, - wk->bss->cbss.bssid); + cfg80211_send_auth_timeout(sdata->dev, wk->auth.bssid); break; case RX_MGMT_CFG80211_ASSOC_TO: cfg80211_send_assoc_timeout(sdata->dev, - wk->bss->cbss.bssid); + wk->assoc.bssid); break; default: WARN(1, "unexpected: %lu", wk->timeout); @@ -2415,7 +2448,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - struct ieee80211_mgd_work *wk; + struct ieee80211_work *wk; u16 auth_alg; switch (req->auth_type) { @@ -2439,7 +2472,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (!wk) return -ENOMEM; - wk->bss = (void *)req->bss; + memcpy(wk->auth.bssid, req->bss->bssid, ETH_ALEN);; if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); @@ -2447,22 +2480,27 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, } if (req->key && req->key_len) { - wk->key_len = req->key_len; - wk->key_idx = req->key_idx; - memcpy(wk->key, req->key, req->key_len); + wk->auth.key_len = req->key_len; + wk->auth.key_idx = req->key_idx; + memcpy(wk->auth.key, req->key, req->key_len); } ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->ssid, ssid + 2, ssid[1]); - wk->ssid_len = ssid[1]; + memcpy(wk->auth.ssid, ssid + 2, ssid[1]); + wk->auth.ssid_len = ssid[1]; + + wk->auth.algorithm = auth_alg; + wk->auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; - wk->state = IEEE80211_MGD_STATE_PROBE; - wk->auth_alg = auth_alg; + wk->type = IEEE80211_WORK_AUTH_PROBE; wk->timeout = jiffies; /* run right away */ + wk->chan = req->bss->channel; /* * XXX: if still associated need to tell AP that we're going * to sleep and then change channel etc. + * For now switch channel here, later will be handled + * by submitting this as an off-channel work item. */ sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); @@ -2479,7 +2517,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_mgd_work *wk; + struct ieee80211_work *wk; const u8 *ssid; int i, err; @@ -2506,17 +2544,27 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else wk->ie_len = 0; - wk->bss = (void *)req->bss; + wk->assoc.bss = (void *)req->bss; + + memcpy(wk->assoc.bssid, req->bss->bssid, ETH_ALEN); + + wk->assoc.capability = req->bss->capability; + wk->assoc.wmm_used = wk->assoc.bss->wmm_used; + wk->assoc.supp_rates = wk->assoc.bss->supp_rates; + wk->assoc.supp_rates_len = wk->assoc.bss->supp_rates_len; + wk->assoc.ht_information_ie = + ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->ssid, ssid + 2, ssid[1]); - wk->ssid_len = ssid[1]; + memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); + wk->assoc.ssid_len = ssid[1]; if (req->prev_bssid) - memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); + memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); - wk->state = IEEE80211_MGD_STATE_ASSOC; + wk->type = IEEE80211_WORK_ASSOC; wk->timeout = jiffies; /* run right away */ + wk->chan = req->bss->channel; if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -2549,7 +2597,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, void *cookie) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_mgd_work *wk; + struct ieee80211_work *wk; const u8 *bssid = req->bss->bssid; bool not_auth_yet = false; @@ -2559,9 +2607,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, bssid = req->bss->bssid; ieee80211_set_disassoc(sdata); } else list_for_each_entry(wk, &ifmgd->work_list, list) { - if (wk->state != IEEE80211_MGD_STATE_PROBE) + if (wk->type != IEEE80211_WORK_AUTH_PROBE) continue; - if (req->bss != &wk->bss->cbss) + if (memcmp(req->bss->bssid, wk->auth.bssid, ETH_ALEN)) continue; not_auth_yet = true; list_del(&wk->list); -- GitLab From af6b63741cc4e4dfd575d06beb333b11a8a6e0c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:35 +0100 Subject: [PATCH 0271/3892] mac80211: generalise work handling In order to use auth/assoc for different purposes other than MLME, it needs to be split up. For other purposes, a generic work handling (potentially on another channel) will be useful. To achieve that, this patch moves much of the MLME work handling out of mlme into a new work API. The API can currently handle probing a specific AP, authentication and association. The MLME previously handled probe/authentication as one step and will continue to do so, but they are separate in the new work handling. Work items are RCU-managed to be able to check for existence of an item for a specific frame in the RX path, but they can be re-used which the MLME right now will do for its combined probe/auth step. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Makefile | 2 +- net/mac80211/debugfs_netdev.c | 2 - net/mac80211/ieee80211_i.h | 59 ++- net/mac80211/iface.c | 11 +- net/mac80211/main.c | 2 + net/mac80211/mlme.c | 956 ++++++---------------------------- net/mac80211/rx.c | 5 + net/mac80211/scan.c | 8 +- net/mac80211/work.c | 902 ++++++++++++++++++++++++++++++++ 9 files changed, 1112 insertions(+), 835 deletions(-) create mode 100644 net/mac80211/work.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 298cfcc1bf8d..5a1f57df7cd6 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -9,7 +9,7 @@ mac80211-y := \ scan.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ - mlme.o \ + mlme.o work.o \ iface.o \ rate.o \ michael.o \ diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 355983503885..59f6e3bcbd09 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); -IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode) @@ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(aid, sta); - DEBUGFS_ADD(capab, sta); DEBUGFS_ADD_MODE(smps, 0600); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0339e909e0c4..97b6076b492e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,41 +228,63 @@ struct mesh_preq_queue { }; enum ieee80211_work_type { - IEEE80211_WORK_AUTH_PROBE, + IEEE80211_WORK_DIRECT_PROBE, IEEE80211_WORK_AUTH, IEEE80211_WORK_ASSOC, }; +/** + * enum work_done_result - indicates what to do after work was done + * + * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. + * @WORK_DONE_REQUEUE: This work item was reset to be reused, and + * should be requeued. + */ +enum work_done_result { + WORK_DONE_DESTROY, + WORK_DONE_REQUEUE, +}; + struct ieee80211_work { struct list_head list; + struct rcu_head rcu_head; + + struct ieee80211_sub_if_data *sdata; + + enum work_done_result (*done)(struct ieee80211_work *wk, + struct sk_buff *skb); + struct ieee80211_channel *chan; /* XXX: chan type? -- right now not really needed */ + unsigned long timeout; enum ieee80211_work_type type; + u8 filter_ta[ETH_ALEN]; + union { struct { int tries; u16 algorithm, transaction; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; - u8 bssid[ETH_ALEN]; u8 key[WLAN_KEY_LEN_WEP104]; u8 key_len, key_idx; bool privacy; - } auth; + } probe_auth; struct { struct ieee80211_bss *bss; const u8 *supp_rates; const u8 *ht_information_ie; + enum ieee80211_smps_mode smps; int tries; u16 capability; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 prev_bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; u8 supp_rates_len; - bool wmm_used; + bool wmm_used, use_11n; } assoc; }; @@ -276,17 +298,11 @@ enum ieee80211_sta_flags { IEEE80211_STA_BEACON_POLL = BIT(0), IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONTROL_PORT = BIT(2), - IEEE80211_STA_WMM_ENABLED = BIT(3), IEEE80211_STA_DISABLE_11N = BIT(4), IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), }; -/* flags for MLME request */ -enum ieee80211_sta_request { - IEEE80211_STA_REQ_SCAN, -}; - struct ieee80211_if_managed { struct timer_list timer; struct timer_list conn_mon_timer; @@ -302,12 +318,10 @@ struct ieee80211_if_managed { struct mutex mtx; struct ieee80211_bss *associated; - struct list_head work_list; u8 bssid[ETH_ALEN]; u16 aid; - u16 capab; struct sk_buff_head skb_queue; @@ -316,8 +330,6 @@ struct ieee80211_if_managed { enum ieee80211_smps_mode req_smps, /* requested smps mode */ ap_smps; /* smps mode AP thinks we're in */ - unsigned long request; - unsigned int flags; u32 beacon_crc; @@ -583,6 +595,15 @@ struct ieee80211_local { const struct ieee80211_ops *ops; + /* + * work stuff, potentially off-channel (in the future) + */ + struct mutex work_mtx; + struct list_head work_list; + struct timer_list work_timer; + struct work_struct work_work; + struct sk_buff_head work_skb_queue; + /* * private workqueue to mac80211. mac80211 makes this accessible * via ieee80211_queue_work() @@ -1127,6 +1148,14 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, void ieee80211_recalc_smps(struct ieee80211_local *local, struct ieee80211_sub_if_data *forsdata); +/* internal work items */ +void ieee80211_work_init(struct ieee80211_local *local); +void ieee80211_add_work(struct ieee80211_work *wk); +void free_work(struct ieee80211_work *wk); +void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); +ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb); + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 389dc8d880f3..7d410f15281a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -361,6 +361,11 @@ static int ieee80211_stop(struct net_device *dev) */ netif_stop_queue(dev); + /* + * Purge work for this interface. + */ + ieee80211_work_purge(sdata); + /* * Now delete all active aggregation sessions. */ @@ -928,6 +933,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; int count = 0; + if (!list_empty(&local->work_list)) + return ieee80211_idle_off(local, "working"); + if (local->scanning) return ieee80211_idle_off(local, "scanning"); @@ -936,8 +944,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated && - list_empty(&sdata->u.mgd.work_list)) + !sdata->u.mgd.associated) continue; /* do not count unused IBSS interfaces */ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e93bc558d785..d35023ce7fa1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -395,6 +395,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); + ieee80211_work_init(local); + INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c65225f29bb6..7c1f91bcc834 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -77,12 +77,6 @@ enum rx_mgmt_action { /* caller must tell cfg80211 about internal error */ RX_MGMT_CFG80211_ASSOC_ERROR, - - /* caller must call cfg80211_auth_timeout() & free work */ - RX_MGMT_CFG80211_AUTH_TO, - - /* caller must call cfg80211_assoc_timeout() & free work */ - RX_MGMT_CFG80211_ASSOC_TO, }; /* utils */ @@ -125,27 +119,6 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } -static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, - struct ieee80211_supported_band *sband, - u32 *rates) -{ - int i, j, count; - *rates = 0; - count = 0; - for (i = 0; i < supp_rates_len; i++) { - int rate = (supp_rates[i] & 0x7F) * 5; - - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == rate) { - *rates |= BIT(j); - count++; - break; - } - } - - return count; -} - /* * ieee80211_enable_ht should be called only after the operating band * has been determined as ht configuration depends on the hw's @@ -231,266 +204,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u8 *pos; - const u8 *ies, *ht_ie; - int i, len, count, rates_len, supp_rates_len; - u16 capab; - int wmm = 0; - struct ieee80211_supported_band *sband; - u32 rates = 0; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + wk->ie_len + - wk->assoc.ssid_len); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " - "frame\n", sdata->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - capab = ifmgd->capab; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - } - - if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (wk->assoc.wmm_used) - wmm = 1; - - /* get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode) */ - rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, - wk->assoc.supp_rates_len, - sband, &rates); - - if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, wk->assoc.bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, wk->assoc.bssid, ETH_ALEN); - - if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { - skb_put(skb, 10); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, - ETH_ALEN); - } else { - skb_put(skb, 4); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.assoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - } - - /* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = wk->assoc.ssid_len; - memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); - - /* add all rates which were marked to be used above */ - supp_rates_len = rates_len; - if (supp_rates_len > 8) - supp_rates_len = 8; - - len = sband->n_bitrates; - pos = skb_put(skb, supp_rates_len + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - - count = 0; - for (i = 0; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - if (++count == 8) - break; - } - } - - if (rates_len > count) { - pos = skb_put(skb, rates_len - count + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates_len - count; - - for (i++; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - } - } - - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { - /* 1. power capabilities */ - pos = skb_put(skb, 4); - *pos++ = WLAN_EID_PWR_CAPABILITY; - *pos++ = 2; - *pos++ = 0; /* min tx power */ - *pos++ = local->hw.conf.channel->max_power; /* max tx power */ - - /* 2. supported channels */ - /* TODO: get this in reg domain format */ - pos = skb_put(skb, 2 * sband->n_channels + 2); - *pos++ = WLAN_EID_SUPPORTED_CHANNELS; - *pos++ = 2 * sband->n_channels; - for (i = 0; i < sband->n_channels; i++) { - *pos++ = ieee80211_frequency_to_channel( - sband->channels[i].center_freq); - *pos++ = 1; /* one channel in the subband*/ - } - } - - if (wk->ie_len && wk->ie) { - pos = skb_put(skb, wk->ie_len); - memcpy(pos, wk->ie, wk->ie_len); - } - - if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = 0; - } - - /* wmm support is a must to HT */ - /* - * IEEE802.11n does not allow TKIP/WEP as pairwise - * ciphers in HT mode. We still associate in non-ht - * mode (11a/b/g) if any one of these ciphers is - * configured as pairwise. - */ - if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && - sband->ht_cap.ht_supported && - (ht_ie = wk->assoc.ht_information_ie) && - ht_ie[1] >= sizeof(struct ieee80211_ht_info) && - (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { - struct ieee80211_ht_info *ht_info = - (struct ieee80211_ht_info *)(ht_ie + 2); - u16 cap = sband->ht_cap.cap; - __le16 tmp; - u32 flags = local->hw.conf.channel->flags; - - /* determine capability flags */ - - if (ieee80211_disable_40mhz_24ghz && - sband->band == IEEE80211_BAND_2GHZ) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - - switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_HT40PLUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_HT40MINUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - } - - /* set SM PS mode properly */ - cap &= ~IEEE80211_HT_CAP_SM_PS; - /* new association always uses requested smps mode */ - if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { - if (ifmgd->powersave) - ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; - else - ifmgd->ap_smps = IEEE80211_SMPS_OFF; - } else - ifmgd->ap_smps = ifmgd->req_smps; - - switch (ifmgd->ap_smps) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_NUM_MODES: - WARN_ON(1); - case IEEE80211_SMPS_OFF: - cap |= WLAN_HT_CAP_SM_PS_DISABLED << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_STATIC: - cap |= WLAN_HT_CAP_SM_PS_STATIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_DYNAMIC: - cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - } - - /* reserve and fill IE */ - - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - - /* capability flags */ - tmp = cpu_to_le16(cap); - memcpy(pos, &tmp, sizeof(u16)); - pos += sizeof(u16); - - /* AMPDU parameters */ - *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); - - /* MCS set */ - memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); - pos += sizeof(sband->ht_cap.mcs); - - /* extended capabilities */ - pos += sizeof(__le16); - - /* BF capabilities */ - pos += sizeof(__le32); - - /* antenna selection */ - pos += sizeof(u8); - } - - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - ieee80211_tx_skb(sdata, skb); -} - - static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, u16 reason, void *cookie) @@ -751,6 +464,11 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) return; } + if (!list_empty(&local->work_list)) { + local->ps_sdata = NULL; + goto change; + } + list_for_each_entry(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; @@ -761,7 +479,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && + found->u.mgd.associated && !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL))) { s32 beaconint_us; @@ -789,6 +507,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) local->ps_sdata = NULL; } + change: ieee80211_change_ps(local); } @@ -848,7 +567,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, int count; u8 *pos; - if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) + if (local->hw.queues < 4) return; if (!wmm_param) @@ -1005,110 +724,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_carrier_on(sdata->dev); } -static void ieee80211_remove_auth_bss(struct ieee80211_local *local, - struct ieee80211_work *wk) -{ - struct cfg80211_bss *cbss; - u16 capa_val = WLAN_CAPABILITY_ESS; - - if (wk->auth.privacy) - capa_val |= WLAN_CAPABILITY_PRIVACY; - - cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->auth.bssid, - wk->auth.ssid, wk->auth.ssid_len, - WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, - capa_val); - if (!cbss) - return; - - cfg80211_unlink_bss(local->hw.wiphy, cbss); - cfg80211_put_bss(cbss); -} - -static enum rx_mgmt_action __must_check -ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - - wk->auth.tries++; - if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->name, wk->auth.bssid); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &ifmgd->work); - return RX_MGMT_CFG80211_AUTH_TO; - } - - printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", - sdata->name, wk->auth.bssid, wk->auth.tries); - - /* - * Direct probe is sent to broadcast address as some APs - * will not answer to direct packet in unassociated state. - */ - ieee80211_send_probe_req(sdata, NULL, wk->auth.ssid, wk->auth.ssid_len, - NULL, 0); - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(ifmgd, wk->timeout); - - return RX_MGMT_NONE; -} - - -static enum rx_mgmt_action __must_check -ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - - wk->auth.tries++; - if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP %pM" - " timed out\n", sdata->name, wk->auth.bssid); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &ifmgd->work); - return RX_MGMT_CFG80211_AUTH_TO; - } - - printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", - sdata->name, wk->auth.bssid, wk->auth.tries); - - ieee80211_send_auth(sdata, 1, wk->auth.algorithm, wk->ie, wk->ie_len, - wk->auth.bssid, NULL, 0, 0); - wk->auth.transaction = 2; - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(ifmgd, wk->timeout); - - return RX_MGMT_NONE; -} - static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1195,44 +810,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) sta_info_destroy(sta); } -static enum rx_mgmt_action __must_check -ieee80211_associate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - - wk->assoc.tries++; - if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP %pM" - " timed out\n", - sdata->name, wk->assoc.bssid); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - cfg80211_unlink_bss(local->hw.wiphy, &wk->assoc.bss->cbss); - - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &ifmgd->work); - return RX_MGMT_CFG80211_ASSOC_TO; - } - - printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", - sdata->name, wk->assoc.bssid, wk->assoc.tries); - ieee80211_send_assoc(sdata, wk); - - wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - run_again(ifmgd, wk->timeout); - - return RX_MGMT_NONE; -} - void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr) { @@ -1338,86 +915,6 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_beacon_loss); -static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - list_del(&wk->list); - kfree(wk); - printk(KERN_DEBUG "%s: authenticated\n", sdata->name); -} - - -static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - u8 *pos; - struct ieee802_11_elems elems; - - pos = mgmt->u.auth.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) - return; - ieee80211_send_auth(sdata, 3, wk->auth.algorithm, - elems.challenge - 2, elems.challenge_len + 2, - wk->auth.bssid, wk->auth.key, wk->auth.key_len, - wk->auth.key_idx); - wk->auth.transaction = 4; -} - -static enum rx_mgmt_action __must_check -ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len) -{ - u16 auth_alg, auth_transaction, status_code; - - if (wk->type != IEEE80211_WORK_AUTH) - return RX_MGMT_NONE; - - if (len < 24 + 6) - return RX_MGMT_NONE; - - if (memcmp(wk->auth.bssid, mgmt->sa, ETH_ALEN) != 0) - return RX_MGMT_NONE; - - if (memcmp(wk->auth.bssid, mgmt->bssid, ETH_ALEN) != 0) - return RX_MGMT_NONE; - - auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); - auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); - - if (auth_alg != wk->auth.algorithm || - auth_transaction != wk->auth.transaction) - return RX_MGMT_NONE; - - if (status_code != WLAN_STATUS_SUCCESS) { - list_del(&wk->list); - kfree(wk); - return RX_MGMT_CFG80211_AUTH; - } - - switch (wk->auth.algorithm) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - case WLAN_AUTH_FT: - ieee80211_auth_completed(sdata, wk); - return RX_MGMT_CFG80211_AUTH; - case WLAN_AUTH_SHARED_KEY: - if (wk->auth.transaction == 4) { - ieee80211_auth_completed(sdata, wk); - return RX_MGMT_CFG80211_AUTH; - } else - ieee80211_auth_challenge(sdata, wk, mgmt, len); - break; - } - - return RX_MGMT_NONE; -} - - static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) @@ -1474,98 +971,51 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } -static enum rx_mgmt_action __must_check -ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - bool reassoc) +static bool ieee80211_assoc_success(struct ieee80211_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) { + struct ieee80211_sub_if_data *sdata = wk->sdata; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; struct ieee80211_bss *bss = wk->assoc.bss; + u8 *pos; u32 rates, basic_rates; - u16 capab_info, status_code, aid; + u16 capab_info, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - u8 *pos; u32 changed = 0; int i, j, err; bool have_higher_than_11mbit = false; u16 ap_ht_cap_flags; - /* - * AssocResp and ReassocResp have identical structure, so process both - * of them in this function. - */ - - if (len < 24 + 6) - return RX_MGMT_NONE; + /* AssocResp and ReassocResp have identical structure */ - if (memcmp(bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) - return RX_MGMT_NONE; - - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - - printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " - "status=%d aid=%d)\n", - sdata->name, reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - - pos = mgmt->u.assoc_resp.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && - elems.timeout_int && elems.timeout_int_len == 5 && - elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { - u32 tu, ms; - tu = get_unaligned_le32(elems.timeout_int + 1); - ms = tu * 1024 / 1000; - printk(KERN_DEBUG "%s: AP rejected association temporarily; " - "comeback duration %u TU (%u ms)\n", - sdata->name, tu, ms); - wk->timeout = jiffies + msecs_to_jiffies(ms); - if (ms > IEEE80211_ASSOC_TIMEOUT) - run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); - return RX_MGMT_NONE; - } - - /* - * Here the association was either successful or not. - */ - - /* delete work item -- must be before set_associated for PS */ - list_del(&wk->list); - kfree(wk); - - if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", - sdata->name, status_code); - return RX_MGMT_CFG80211_ASSOC; - } + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " "set\n", sdata->name, aid); aid &= ~(BIT(15) | BIT(14)); + pos = mgmt->u.assoc_resp.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", sdata->name); - return RX_MGMT_NONE; + return false; } - printk(KERN_DEBUG "%s: associated\n", sdata->name); ifmgd->aid = aid; sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" " the AP\n", sdata->name); - return RX_MGMT_CFG80211_ASSOC_ERROR; + return false; } set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | @@ -1650,7 +1100,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_set_wmm_default(sdata); if (elems.ht_info_elem && elems.wmm_param && - (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && + (sdata->local->hw.queues >= 4) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, bss->cbss.bssid, @@ -1669,7 +1119,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - return RX_MGMT_CFG80211_ASSOC; + return true; } @@ -1714,12 +1164,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) + struct sk_buff *skb) { + struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_if_managed *ifmgd; - size_t baselen; + struct ieee80211_rx_status *rx_status = (void *) skb->cb; + size_t baselen, len = skb->len; struct ieee802_11_elems elems; ifmgd = &sdata->u.mgd; @@ -1738,15 +1188,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); - /* direct probe may be part of the association flow */ - if (wk && wk->type == IEEE80211_WORK_AUTH_PROBE) { - printk(KERN_DEBUG "%s: direct probe responded\n", - sdata->name); - wk->auth.tries = 0; - wk->type = IEEE80211_WORK_AUTH; - WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); - } - if (ifmgd->associated && memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && ifmgd->flags & (IEEE80211_STA_BEACON_POLL | @@ -1960,9 +1401,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: case IEEE80211_STYPE_ACTION: @@ -1980,7 +1418,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; - struct ieee80211_work *wk; enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; @@ -1999,8 +1436,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, rx_status); break; case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, - skb->len, rx_status); + ieee80211_rx_mgmt_probe_resp(sdata, skb); break; case IEEE80211_STYPE_DEAUTH: rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); @@ -2033,88 +1469,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, goto out; } - list_for_each_entry(wk, &ifmgd->work_list, list) { - const u8 *bssid = NULL; - - switch (wk->type) { - case IEEE80211_WORK_AUTH_PROBE: - case IEEE80211_WORK_AUTH: - bssid = wk->auth.bssid; - break; - case IEEE80211_WORK_ASSOC: - bssid = wk->assoc.bssid; - break; - default: - continue; - } - if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) - continue; - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_AUTH: - rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, - skb->len, false); - break; - case IEEE80211_STYPE_REASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, - skb->len, true); - break; - case IEEE80211_STYPE_DEAUTH: - if (skb->len >= 24 + 2 /* mgmt + deauth reason */) { - /* - * We get here if we get deauth while - * trying to auth/assoc. Telling cfg80211 - * is handled below, unconditionally. - */ - list_del(&wk->list); - kfree(wk); - } - break; - } - /* - * We've processed this frame for that work, so it can't - * belong to another work struct. - * NB: this is also required for correctness because the - * called functions can free 'wk', and for 'rma'! - */ - break; - } - mutex_unlock(&ifmgd->mtx); if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { - WARN_ON(rma != RX_MGMT_NONE); - rma = RX_MGMT_CFG80211_DEAUTH; - } - - switch (rma) { - case RX_MGMT_NONE: - /* no action */ - break; - case RX_MGMT_CFG80211_AUTH: - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); - break; - case RX_MGMT_CFG80211_ASSOC: - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); - break; - case RX_MGMT_CFG80211_DEAUTH: + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - break; - case RX_MGMT_CFG80211_ASSOC_ERROR: - /* an internal error -- pretend timeout for now */ - cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); - break; - default: - WARN(1, "unexpected: %d", rma); - } out: kfree_skb(skb); @@ -2142,9 +1501,6 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd; struct sk_buff *skb; - struct ieee80211_work *wk, *tmp; - LIST_HEAD(free_work); - enum rx_mgmt_action rma; if (!ieee80211_sdata_running(sdata)) return; @@ -2214,84 +1570,7 @@ static void ieee80211_sta_work(struct work_struct *work) } } - - ieee80211_recalc_idle(local); - - list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { - if (time_is_after_jiffies(wk->timeout)) { - /* - * This work item isn't supposed to be worked on - * right now, but take care to adjust the timer - * properly. - */ - run_again(ifmgd, wk->timeout); - continue; - } - - switch (wk->type) { - default: - WARN_ON(1); - /* nothing */ - rma = RX_MGMT_NONE; - break; - case IEEE80211_WORK_AUTH_PROBE: - rma = ieee80211_direct_probe(sdata, wk); - break; - case IEEE80211_WORK_AUTH: - rma = ieee80211_authenticate(sdata, wk); - break; - case IEEE80211_WORK_ASSOC: - rma = ieee80211_associate(sdata, wk); - break; - } - - switch (rma) { - case RX_MGMT_NONE: - /* no action required */ - break; - case RX_MGMT_CFG80211_AUTH_TO: - case RX_MGMT_CFG80211_ASSOC_TO: - list_del(&wk->list); - list_add(&wk->list, &free_work); - /* - * small abuse but only local -- keep the - * action type in wk->timeout while the item - * is on the cleanup list - */ - wk->timeout = rma; - break; - default: - WARN(1, "unexpected: %d", rma); - } - } - - if (list_empty(&ifmgd->work_list) && - test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) - ieee80211_queue_delayed_work(&local->hw, - &local->scan_work, - round_jiffies_relative(0)); - mutex_unlock(&ifmgd->mtx); - - list_for_each_entry_safe(wk, tmp, &free_work, list) { - /* see above how we're using wk->timeout */ - switch (wk->timeout) { - case RX_MGMT_CFG80211_AUTH_TO: - cfg80211_send_auth_timeout(sdata->dev, wk->auth.bssid); - break; - case RX_MGMT_CFG80211_ASSOC_TO: - cfg80211_send_assoc_timeout(sdata->dev, - wk->assoc.bssid); - break; - default: - WARN(1, "unexpected: %lu", wk->timeout); - } - - list_del(&wk->list); - kfree(wk); - } - - ieee80211_recalc_idle(local); } static void ieee80211_sta_bcn_mon_timer(unsigned long data) @@ -2400,12 +1679,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); - INIT_LIST_HEAD(&ifmgd->work_list); - - ifmgd->capab = WLAN_CAPABILITY_ESS; ifmgd->flags = 0; - if (sdata->local->hw.queues >= 4) - ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; mutex_init(&ifmgd->mtx); @@ -2443,10 +1717,32 @@ int ieee80211_max_network_latency(struct notifier_block *nb, } /* config hooks */ +static enum work_done_result +ieee80211_probe_auth_done(struct ieee80211_work *wk, + struct sk_buff *skb) +{ + if (!skb) { + cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); + return WORK_DONE_DESTROY; + } + + if (wk->type == IEEE80211_WORK_AUTH) { + cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); + return WORK_DONE_DESTROY; + } + + mutex_lock(&wk->sdata->u.mgd.mtx); + ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); + mutex_unlock(&wk->sdata->u.mgd.mtx); + + wk->type = IEEE80211_WORK_AUTH; + wk->probe_auth.tries = 0; + return WORK_DONE_REQUEUE; +} + int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct cfg80211_auth_request *req) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; struct ieee80211_work *wk; u16 auth_alg; @@ -2472,7 +1768,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (!wk) return -ENOMEM; - memcpy(wk->auth.bssid, req->bss->bssid, ETH_ALEN);; + memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); @@ -2480,21 +1776,22 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, } if (req->key && req->key_len) { - wk->auth.key_len = req->key_len; - wk->auth.key_idx = req->key_idx; - memcpy(wk->auth.key, req->key, req->key_len); + wk->probe_auth.key_len = req->key_len; + wk->probe_auth.key_idx = req->key_idx; + memcpy(wk->probe_auth.key, req->key, req->key_len); } ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->auth.ssid, ssid + 2, ssid[1]); - wk->auth.ssid_len = ssid[1]; + memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); + wk->probe_auth.ssid_len = ssid[1]; - wk->auth.algorithm = auth_alg; - wk->auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; + wk->probe_auth.algorithm = auth_alg; + wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; - wk->type = IEEE80211_WORK_AUTH_PROBE; - wk->timeout = jiffies; /* run right away */ + wk->type = IEEE80211_WORK_DIRECT_PROBE; wk->chan = req->bss->channel; + wk->sdata = sdata; + wk->done = ieee80211_probe_auth_done; /* * XXX: if still associated need to tell AP that we're going @@ -2505,29 +1802,58 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - mutex_lock(&ifmgd->mtx); - list_add(&wk->list, &sdata->u.mgd.work_list); - mutex_unlock(&ifmgd->mtx); - - ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); + ieee80211_add_work(wk); return 0; } +static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, + struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt; + u16 status; + + if (!skb) { + cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); + return WORK_DONE_DESTROY; + } + + mgmt = (void *)skb->data; + status = le16_to_cpu(mgmt->u.assoc_resp.status_code); + + if (status == WLAN_STATUS_SUCCESS) { + mutex_lock(&wk->sdata->u.mgd.mtx); + if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { + mutex_unlock(&wk->sdata->u.mgd.mtx); + /* oops -- internal error -- send timeout for now */ + cfg80211_send_assoc_timeout(wk->sdata->dev, + wk->filter_ta); + return WORK_DONE_DESTROY; + } + mutex_unlock(&wk->sdata->u.mgd.mtx); + } + + cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); + return WORK_DONE_DESTROY; +} + int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_work *wk; const u8 *ssid; - int i, err; + int i; mutex_lock(&ifmgd->mtx); + if (ifmgd->associated) { + mutex_unlock(&ifmgd->mtx); + return -EALREADY; + } + mutex_unlock(&ifmgd->mtx); wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); - if (!wk) { - err = -ENOMEM; - goto out; - } + if (!wk) + return -ENOMEM; ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; @@ -2546,8 +1872,19 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, wk->assoc.bss = (void *)req->bss; - memcpy(wk->assoc.bssid, req->bss->bssid, ETH_ALEN); + memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); + /* new association always uses requested smps mode */ + if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { + if (ifmgd->powersave) + ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; + else + ifmgd->ap_smps = IEEE80211_SMPS_OFF; + } else + ifmgd->ap_smps = ifmgd->req_smps; + + wk->assoc.smps = ifmgd->ap_smps; + wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); wk->assoc.capability = req->bss->capability; wk->assoc.wmm_used = wk->assoc.bss->wmm_used; wk->assoc.supp_rates = wk->assoc.bss->supp_rates; @@ -2563,8 +1900,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); wk->type = IEEE80211_WORK_ASSOC; - wk->timeout = jiffies; /* run right away */ wk->chan = req->bss->channel; + wk->sdata = sdata; + wk->done = ieee80211_assoc_done; if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -2582,56 +1920,56 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - list_add(&wk->list, &ifmgd->work_list); - ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); - - err = 0; - - out: - mutex_unlock(&ifmgd->mtx); - return err; + ieee80211_add_work(wk); + return 0; } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct cfg80211_deauth_request *req, void *cookie) { + struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_work *wk; const u8 *bssid = req->bss->bssid; - bool not_auth_yet = false; mutex_lock(&ifmgd->mtx); if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; ieee80211_set_disassoc(sdata); - } else list_for_each_entry(wk, &ifmgd->work_list, list) { - if (wk->type != IEEE80211_WORK_AUTH_PROBE) - continue; - if (memcmp(req->bss->bssid, wk->auth.bssid, ETH_ALEN)) - continue; - not_auth_yet = true; - list_del(&wk->list); - kfree(wk); - break; - } + mutex_unlock(&ifmgd->mtx); + } else { + bool not_auth_yet = false; - /* - * If somebody requests authentication and we haven't - * sent out an auth frame yet there's no need to send - * out a deauth frame either. If the state was PROBE, - * then this is the case. If it's AUTH we have sent a - * frame, and if it's IDLE we have completed the auth - * process already. - */ - if (not_auth_yet) { mutex_unlock(&ifmgd->mtx); - __cfg80211_auth_canceled(sdata->dev, bssid); - return 0; - } - mutex_unlock(&ifmgd->mtx); + mutex_lock(&local->work_mtx); + list_for_each_entry(wk, &local->work_list, list) { + if (wk->type != IEEE80211_WORK_DIRECT_PROBE) + continue; + if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) + continue; + not_auth_yet = true; + list_del(&wk->list); + free_work(wk); + break; + } + mutex_unlock(&local->work_mtx); + + /* + * If somebody requests authentication and we haven't + * sent out an auth frame yet there's no need to send + * out a deauth frame either. If the state was PROBE, + * then this is the case. If it's AUTH we have sent a + * frame, and if it's IDLE we have completed the auth + * process already. + */ + if (not_auth_yet) { + __cfg80211_auth_canceled(sdata->dev, bssid); + return 0; + } + } printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", sdata->name, bssid, req->reason_code); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f60dfca52196..bfcf09eb64b4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; + ieee80211_rx_result rxs; if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_MONITOR; @@ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) return RX_DROP_MONITOR; + rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); + if (rxs != RX_CONTINUE) + return rxs; + if (ieee80211_vif_is_mesh(&sdata->vif)) return ieee80211_mesh_rx_mgmt(sdata, rx->skb); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index d98c45e5528b..fb89e4c0fbfd 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -434,7 +434,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) { struct ieee80211_local *local = sdata->local; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int rc; if (local->scan_req) @@ -464,11 +463,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->scan_req = req; local->scan_sdata = sdata; - if (req != local->int_scan_req && - sdata->vif.type == NL80211_IFTYPE_STATION && - !list_empty(&ifmgd->work_list)) { - /* actually wait for the work it's doing to finish/time out */ - set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); + if (!list_empty(&local->work_list)) { + /* wait for the work to finish/time out */ return 0; } diff --git a/net/mac80211/work.c b/net/mac80211/work.c new file mode 100644 index 000000000000..8b8961d806ab --- /dev/null +++ b/net/mac80211/work.c @@ -0,0 +1,902 @@ +/* + * mac80211 work implementation + * + * Copyright 2003-2008, Jouni Malinen + * Copyright 2004, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007, Michael Wu + * Copyright 2009, Johannes Berg + * + * 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 +#include +#include + +#include "ieee80211_i.h" +#include "rate.h" + +#define IEEE80211_AUTH_TIMEOUT (HZ / 5) +#define IEEE80211_AUTH_MAX_TRIES 3 +#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) +#define IEEE80211_ASSOC_MAX_TRIES 3 +#define IEEE80211_MAX_PROBE_TRIES 5 + +enum work_action { + WORK_ACT_NONE, + WORK_ACT_TIMEOUT, + WORK_ACT_DONE, +}; + + +/* utils */ +static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) +{ + WARN_ON(!mutex_is_locked(&local->work_mtx)); +} + +/* + * We can have multiple work items (and connection probing) + * scheduling this timer, but we need to take care to only + * reschedule it when it should fire _earlier_ than it was + * asked for before, or if it's not pending right now. This + * function ensures that. Note that it then is required to + * run this function for all timeouts after the first one + * has happened -- the work that runs from this timer will + * do that. + */ +static void run_again(struct ieee80211_local *local, + unsigned long timeout) +{ + ASSERT_WORK_MTX(local); + + if (!timer_pending(&local->work_timer) || + time_before(timeout, local->work_timer.expires)) + mod_timer(&local->work_timer, timeout); +} + +static void work_free_rcu(struct rcu_head *head) +{ + struct ieee80211_work *wk = + container_of(head, struct ieee80211_work, rcu_head); + + kfree(wk); +} + +void free_work(struct ieee80211_work *wk) +{ + call_rcu(&wk->rcu_head, work_free_rcu); +} + +static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, + struct ieee80211_supported_band *sband, + u32 *rates) +{ + int i, j, count; + *rates = 0; + count = 0; + for (i = 0; i < supp_rates_len; i++) { + int rate = (supp_rates[i] & 0x7F) * 5; + + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == rate) { + *rates |= BIT(j); + count++; + break; + } + } + + return count; +} + +/* frame sending functions */ + +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_work *wk) +{ + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos; + const u8 *ies, *ht_ie; + int i, len, count, rates_len, supp_rates_len; + u16 capab; + struct ieee80211_supported_band *sband; + u32 rates = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + 200 + wk->ie_len + + wk->assoc.ssid_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " + "frame\n", sdata->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + sband = local->hw.wiphy->bands[wk->chan->band]; + + capab = WLAN_CAPABILITY_ESS; + + if (sband->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + + /* + * Get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode)... + */ + rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, + wk->assoc.supp_rates_len, + sband, &rates); + + if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, wk->filter_ta, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN); + + if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { + skb_put(skb, 10); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_REASSOC_REQ); + mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.reassoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, + ETH_ALEN); + } else { + skb_put(skb, 4); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ASSOC_REQ); + mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.assoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + } + + /* SSID */ + ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = wk->assoc.ssid_len; + memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); + + /* add all rates which were marked to be used above */ + supp_rates_len = rates_len; + if (supp_rates_len > 8) + supp_rates_len = 8; + + len = sband->n_bitrates; + pos = skb_put(skb, supp_rates_len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = supp_rates_len; + + count = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + if (++count == 8) + break; + } + } + + if (rates_len > count) { + pos = skb_put(skb, rates_len - count + 2); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates_len - count; + + for (i++; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + } + + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { + /* 1. power capabilities */ + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_PWR_CAPABILITY; + *pos++ = 2; + *pos++ = 0; /* min tx power */ + *pos++ = local->hw.conf.channel->max_power; /* max tx power */ + + /* 2. supported channels */ + /* TODO: get this in reg domain format */ + pos = skb_put(skb, 2 * sband->n_channels + 2); + *pos++ = WLAN_EID_SUPPORTED_CHANNELS; + *pos++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + *pos++ = ieee80211_frequency_to_channel( + sband->channels[i].center_freq); + *pos++ = 1; /* one channel in the subband*/ + } + } + + if (wk->ie_len && wk->ie) { + pos = skb_put(skb, wk->ie_len); + memcpy(pos, wk->ie, wk->ie_len); + } + + if (wk->assoc.wmm_used && local->hw.queues >= 4) { + pos = skb_put(skb, 9); + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 7; /* len */ + *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *pos++ = 0x50; + *pos++ = 0xf2; + *pos++ = 2; /* WME */ + *pos++ = 0; /* WME info */ + *pos++ = 1; /* WME ver */ + *pos++ = 0; + } + + /* wmm support is a must to HT */ + /* + * IEEE802.11n does not allow TKIP/WEP as pairwise + * ciphers in HT mode. We still associate in non-ht + * mode (11a/b/g) if any one of these ciphers is + * configured as pairwise. + */ + if (wk->assoc.use_11n && wk->assoc.wmm_used && + (local->hw.queues >= 4) && + sband->ht_cap.ht_supported && + (ht_ie = wk->assoc.ht_information_ie) && + ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { + struct ieee80211_ht_info *ht_info = + (struct ieee80211_ht_info *)(ht_ie + 2); + u16 cap = sband->ht_cap.cap; + __le16 tmp; + u32 flags = local->hw.conf.channel->flags; + + /* determine capability flags */ + + if (ieee80211_disable_40mhz_24ghz && + sband->band == IEEE80211_BAND_2GHZ) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + /* set SM PS mode properly */ + cap &= ~IEEE80211_HT_CAP_SM_PS; + switch (wk->assoc.smps) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_NUM_MODES: + WARN_ON(1); + case IEEE80211_SMPS_OFF: + cap |= WLAN_HT_CAP_SM_PS_DISABLED << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_STATIC: + cap |= WLAN_HT_CAP_SM_PS_STATIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_DYNAMIC: + cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + } + + /* reserve and fill IE */ + + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + + /* capability flags */ + tmp = cpu_to_le16(cap); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + + /* AMPDU parameters */ + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + + /* MCS set */ + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + pos += sizeof(sband->ht_cap.mcs); + + /* extended capabilities */ + pos += sizeof(__le16); + + /* BF capabilities */ + pos += sizeof(__le32); + + /* antenna selection */ + pos += sizeof(u8); + } + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); +} + +static void ieee80211_remove_auth_bss(struct ieee80211_local *local, + struct ieee80211_work *wk) +{ + struct cfg80211_bss *cbss; + u16 capa_val = WLAN_CAPABILITY_ESS; + + if (wk->probe_auth.privacy) + capa_val |= WLAN_CAPABILITY_PRIVACY; + + cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta, + wk->probe_auth.ssid, wk->probe_auth.ssid_len, + WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, + capa_val); + if (!cbss) + return; + + cfg80211_unlink_bss(local->hw.wiphy, cbss); + cfg80211_put_bss(cbss); +} + +static enum work_action __must_check +ieee80211_direct_probe(struct ieee80211_work *wk) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + + wk->probe_auth.tries++; + if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", + sdata->name, wk->filter_ta); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + ieee80211_remove_auth_bss(local, wk); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &local->work_work); + return WORK_ACT_TIMEOUT; + } + + printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + sdata->name, wk->filter_ta, wk->probe_auth.tries); + + /* + * Direct probe is sent to broadcast address as some APs + * will not answer to direct packet in unassociated state. + */ + ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, + wk->probe_auth.ssid_len, NULL, 0); + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + run_again(local, wk->timeout); + + return WORK_ACT_NONE; +} + + +static enum work_action __must_check +ieee80211_authenticate(struct ieee80211_work *wk) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + + wk->probe_auth.tries++; + if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: authentication with AP %pM" + " timed out\n", sdata->name, wk->filter_ta); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + ieee80211_remove_auth_bss(local, wk); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &local->work_work); + return WORK_ACT_TIMEOUT; + } + + printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + sdata->name, wk->filter_ta, wk->probe_auth.tries); + + ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, + wk->ie_len, wk->filter_ta, NULL, 0, 0); + wk->probe_auth.transaction = 2; + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + run_again(local, wk->timeout); + + return WORK_ACT_NONE; +} + +static enum work_action __must_check +ieee80211_associate(struct ieee80211_work *wk) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + + wk->assoc.tries++; + if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { + printk(KERN_DEBUG "%s: association with AP %pM" + " timed out\n", + sdata->name, wk->filter_ta); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + if (wk->assoc.bss) + cfg80211_unlink_bss(local->hw.wiphy, + &wk->assoc.bss->cbss); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &local->work_work); + return WORK_ACT_TIMEOUT; + } + + printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", + sdata->name, wk->filter_ta, wk->assoc.tries); + ieee80211_send_assoc(sdata, wk); + + wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + run_again(local, wk->timeout); + + return WORK_ACT_NONE; +} + +static void ieee80211_auth_challenge(struct ieee80211_work *wk, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + u8 *pos; + struct ieee802_11_elems elems; + + pos = mgmt->u.auth.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (!elems.challenge) + return; + ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, + elems.challenge - 2, elems.challenge_len + 2, + wk->filter_ta, wk->probe_auth.key, + wk->probe_auth.key_len, wk->probe_auth.key_idx); + wk->probe_auth.transaction = 4; +} + +static enum work_action __must_check +ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) +{ + u16 auth_alg, auth_transaction, status_code; + + if (wk->type != IEEE80211_WORK_AUTH) + return WORK_ACT_NONE; + + if (len < 24 + 6) + return WORK_ACT_NONE; + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + status_code = le16_to_cpu(mgmt->u.auth.status_code); + + if (auth_alg != wk->probe_auth.algorithm || + auth_transaction != wk->probe_auth.transaction) + return WORK_ACT_NONE; + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", + wk->sdata->name, mgmt->sa, status_code); + return WORK_ACT_DONE; + } + + switch (wk->probe_auth.algorithm) { + case WLAN_AUTH_OPEN: + case WLAN_AUTH_LEAP: + case WLAN_AUTH_FT: + break; + case WLAN_AUTH_SHARED_KEY: + if (wk->probe_auth.transaction != 4) { + ieee80211_auth_challenge(wk, mgmt, len); + /* need another frame */ + return WORK_ACT_NONE; + } + break; + default: + WARN_ON(1); + return WORK_ACT_NONE; + } + + printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name); + return WORK_ACT_DONE; +} + +static enum work_action __must_check +ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + bool reassoc) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + u16 capab_info, status_code, aid; + struct ieee802_11_elems elems; + u8 *pos; + + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ + + if (len < 24 + 6) + return WORK_ACT_NONE; + + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); + + printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " + "status=%d aid=%d)\n", + sdata->name, reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + + pos = mgmt->u.assoc_resp.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && + elems.timeout_int && elems.timeout_int_len == 5 && + elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; + tu = get_unaligned_le32(elems.timeout_int + 1); + ms = tu * 1024 / 1000; + printk(KERN_DEBUG "%s: AP rejected association temporarily; " + "comeback duration %u TU (%u ms)\n", + sdata->name, tu, ms); + wk->timeout = jiffies + msecs_to_jiffies(ms); + if (ms > IEEE80211_ASSOC_TIMEOUT) + run_again(local, wk->timeout); + return WORK_ACT_NONE; + } + + if (status_code != WLAN_STATUS_SUCCESS) + printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", + sdata->name, status_code); + else + printk(KERN_DEBUG "%s: associated\n", sdata->name); + + return WORK_ACT_DONE; +} + +static enum work_action __must_check +ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + size_t baselen; + + ASSERT_WORK_MTX(local); + + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; + if (baselen > len) + return WORK_ACT_NONE; + + printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); + return WORK_ACT_DONE; +} + +static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + struct ieee80211_work *wk; + enum work_action rma = WORK_ACT_NONE; + u16 fc; + + rx_status = (struct ieee80211_rx_status *) skb->cb; + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); + + mutex_lock(&local->work_mtx); + + list_for_each_entry(wk, &local->work_list, list) { + const u8 *bssid = NULL; + + switch (wk->type) { + case IEEE80211_WORK_DIRECT_PROBE: + case IEEE80211_WORK_AUTH: + case IEEE80211_WORK_ASSOC: + bssid = wk->filter_ta; + break; + default: + continue; + } + + /* + * Before queuing, we already verified mgmt->sa, + * so this is needed just for matching. + */ + if (compare_ether_addr(bssid, mgmt->bssid)) + continue; + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_AUTH: + rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, + skb->len, false); + break; + case IEEE80211_STYPE_REASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, + skb->len, true); + break; + default: + WARN_ON(1); + } + /* + * We've processed this frame for that work, so it can't + * belong to another work struct. + * NB: this is also required for correctness for 'rma'! + */ + break; + } + + switch (rma) { + case WORK_ACT_NONE: + break; + case WORK_ACT_DONE: + list_del_rcu(&wk->list); + break; + default: + WARN(1, "unexpected: %d", rma); + } + + mutex_unlock(&local->work_mtx); + + if (rma != WORK_ACT_DONE) + goto out; + + switch (wk->done(wk, skb)) { + case WORK_DONE_DESTROY: + free_work(wk); + break; + case WORK_DONE_REQUEUE: + synchronize_rcu(); + wk->timeout = jiffies; /* run again directly */ + mutex_lock(&local->work_mtx); + list_add_tail(&wk->list, &local->work_list); + mutex_unlock(&local->work_mtx); + } + + out: + kfree_skb(skb); +} + +static void ieee80211_work_timer(unsigned long data) +{ + struct ieee80211_local *local = (void *) data; + + if (local->quiescing) + return; + + ieee80211_queue_work(&local->hw, &local->work_work); +} + +static void ieee80211_work_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, work_work); + struct sk_buff *skb; + struct ieee80211_work *wk, *tmp; + LIST_HEAD(free_work); + enum work_action rma; + + if (local->scanning) + return; + + /* + * ieee80211_queue_work() should have picked up most cases, + * here we'll pick the the rest. + */ + if (WARN(local->suspended, "work scheduled while going to suspend\n")) + return; + + /* first process frames to avoid timing out while a frame is pending */ + while ((skb = skb_dequeue(&local->work_skb_queue))) + ieee80211_work_rx_queued_mgmt(local, skb); + + ieee80211_recalc_idle(local); + + mutex_lock(&local->work_mtx); + + list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + if (time_is_after_jiffies(wk->timeout)) { + /* + * This work item isn't supposed to be worked on + * right now, but take care to adjust the timer + * properly. + */ + run_again(local, wk->timeout); + continue; + } + + switch (wk->type) { + default: + WARN_ON(1); + /* nothing */ + rma = WORK_ACT_NONE; + break; + case IEEE80211_WORK_DIRECT_PROBE: + rma = ieee80211_direct_probe(wk); + break; + case IEEE80211_WORK_AUTH: + rma = ieee80211_authenticate(wk); + break; + case IEEE80211_WORK_ASSOC: + rma = ieee80211_associate(wk); + break; + } + + switch (rma) { + case WORK_ACT_NONE: + /* no action required */ + break; + case WORK_ACT_TIMEOUT: + list_del_rcu(&wk->list); + synchronize_rcu(); + list_add(&wk->list, &free_work); + break; + default: + WARN(1, "unexpected: %d", rma); + } + } + + if (list_empty(&local->work_list) && local->scan_req) + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); + + mutex_unlock(&local->work_mtx); + + list_for_each_entry_safe(wk, tmp, &free_work, list) { + wk->done(wk, NULL); + list_del(&wk->list); + kfree(wk); + } +} + +void ieee80211_add_work(struct ieee80211_work *wk) +{ + struct ieee80211_local *local; + + if (WARN_ON(!wk->chan)) + return; + + if (WARN_ON(!wk->sdata)) + return; + + if (WARN_ON(!wk->done)) + return; + + wk->timeout = jiffies; + + local = wk->sdata->local; + mutex_lock(&local->work_mtx); + list_add_tail(&wk->list, &local->work_list); + mutex_unlock(&local->work_mtx); + + ieee80211_queue_work(&local->hw, &local->work_work); +} + +void ieee80211_work_init(struct ieee80211_local *local) +{ + mutex_init(&local->work_mtx); + INIT_LIST_HEAD(&local->work_list); + setup_timer(&local->work_timer, ieee80211_work_timer, + (unsigned long)local); + INIT_WORK(&local->work_work, ieee80211_work_work); + skb_queue_head_init(&local->work_skb_queue); +} + +void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_work *wk, *tmp; + + mutex_lock(&local->work_mtx); + list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + if (wk->sdata != sdata) + continue; + list_del(&wk->list); + free_work(wk); + } + mutex_unlock(&local->work_mtx); +} + +ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgmt *mgmt; + struct ieee80211_work *wk; + u16 fc; + + if (skb->len < 24) + return RX_DROP_MONITOR; + + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); + + list_for_each_entry_rcu(wk, &local->work_list, list) { + if (sdata != wk->sdata) + continue; + if (compare_ether_addr(wk->filter_ta, mgmt->sa)) + continue; + if (compare_ether_addr(wk->filter_ta, mgmt->bssid)) + continue; + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_DISASSOC: + skb_queue_tail(&local->work_skb_queue, skb); + ieee80211_queue_work(&local->hw, &local->work_work); + return RX_QUEUED; + } + } + + return RX_CONTINUE; +} -- GitLab From 7d3a1c3b03c3a571a2c8c393b75558a5f4a7532a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:36 +0100 Subject: [PATCH 0272/3892] mac80211: rewrite a few work messages The station we're authenticating/associating with may not always be an AP in the sense that word is mostly understood, so print only the MAC address of the peer instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/work.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 8b8961d806ab..874345918e83 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -376,7 +376,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk) wk->probe_auth.tries++; if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", + printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", sdata->name, wk->filter_ta); /* @@ -394,7 +394,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk) return WORK_ACT_TIMEOUT; } - printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", sdata->name, wk->filter_ta, wk->probe_auth.tries); /* @@ -419,7 +419,7 @@ ieee80211_authenticate(struct ieee80211_work *wk) wk->probe_auth.tries++; if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP %pM" + printk(KERN_DEBUG "%s: authentication with %pM" " timed out\n", sdata->name, wk->filter_ta); /* @@ -437,7 +437,7 @@ ieee80211_authenticate(struct ieee80211_work *wk) return WORK_ACT_TIMEOUT; } - printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n", sdata->name, wk->filter_ta, wk->probe_auth.tries); ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, @@ -458,7 +458,7 @@ ieee80211_associate(struct ieee80211_work *wk) wk->assoc.tries++; if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP %pM" + printk(KERN_DEBUG "%s: association with %pM" " timed out\n", sdata->name, wk->filter_ta); @@ -479,7 +479,7 @@ ieee80211_associate(struct ieee80211_work *wk) return WORK_ACT_TIMEOUT; } - printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", + printk(KERN_DEBUG "%s: associate with %pM (try %d)\n", sdata->name, wk->filter_ta, wk->assoc.tries); ieee80211_send_assoc(sdata, wk); @@ -592,9 +592,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, u32 tu, ms; tu = get_unaligned_le32(elems.timeout_int + 1); ms = tu * 1024 / 1000; - printk(KERN_DEBUG "%s: AP rejected association temporarily; " + printk(KERN_DEBUG "%s: %pM rejected association temporarily; " "comeback duration %u TU (%u ms)\n", - sdata->name, tu, ms); + sdata->name, mgmt->sa, tu, ms); wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) run_again(local, wk->timeout); @@ -602,8 +602,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, } if (status_code != WLAN_STATUS_SUCCESS) - printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", - sdata->name, status_code); + printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", + sdata->name, mgmt->sa, status_code); else printk(KERN_DEBUG "%s: associated\n", sdata->name); -- GitLab From 77c8144ad3ee7fae834e13cb7e83f5b7c8c5329e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:37 +0100 Subject: [PATCH 0273/3892] mac80211: refactor association Refactor the code to reserve an skb of the right size (instead of hoping 200 bytes are enough forever), and also put HT IE generation into an own function. Additionally, put the HT IE before the vendor-specific WMM IE. This still leaves things not quite ordered correctly, due to user-specified IEs, add a note about that for now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 7 ++ net/mac80211/work.c | 239 ++++++++++++++++++++++++-------------------- 2 files changed, 137 insertions(+), 109 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7c1f91bcc834..ea434b5a779e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1884,6 +1884,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->ap_smps = ifmgd->req_smps; wk->assoc.smps = ifmgd->ap_smps; + /* + * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. + * We still associate in non-HT mode (11a/b/g) if any one of these + * ciphers is configured as pairwise. + * We can set this to true for non-11n hardware, that'll be checked + * separately along with the peer capabilities. + */ wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); wk->assoc.capability = req->bss->capability; wk->assoc.wmm_used = wk->assoc.bss->wmm_used; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 874345918e83..c03c22d5bca3 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -100,6 +100,102 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, /* frame sending functions */ +static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, + struct ieee80211_supported_band *sband, + struct ieee80211_channel *channel, + enum ieee80211_smps_mode smps) +{ + struct ieee80211_ht_info *ht_info; + u8 *pos; + u32 flags = channel->flags; + u16 cap = sband->ht_cap.cap; + __le16 tmp; + + if (!sband->ht_cap.ht_supported) + return; + + if (!ht_info_ie) + return; + + if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) + return; + + ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); + + /* determine capability flags */ + + if (ieee80211_disable_40mhz_24ghz && + sband->band == IEEE80211_BAND_2GHZ) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + /* set SM PS mode properly */ + cap &= ~IEEE80211_HT_CAP_SM_PS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_NUM_MODES: + WARN_ON(1); + case IEEE80211_SMPS_OFF: + cap |= WLAN_HT_CAP_SM_PS_DISABLED << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_STATIC: + cap |= WLAN_HT_CAP_SM_PS_STATIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_DYNAMIC: + cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + } + + /* reserve and fill IE */ + + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + + /* capability flags */ + tmp = cpu_to_le16(cap); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + + /* AMPDU parameters */ + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + + /* MCS set */ + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + pos += sizeof(sband->ht_cap.mcs); + + /* extended capabilities */ + pos += sizeof(__le16); + + /* BF capabilities */ + pos += sizeof(__le32); + + /* antenna selection */ + pos += sizeof(u8); +} + static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_work *wk) { @@ -107,15 +203,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos; - const u8 *ies, *ht_ie; + const u8 *ies; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + wk->ie_len + - wk->assoc.ssid_len); + sband = local->hw.wiphy->bands[wk->chan->band]; + + /* + * Get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode)... + */ + rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, + wk->assoc.supp_rates_len, + sband, &rates); + + skb = alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + /* bit too much but doesn't matter */ + 2 + wk->assoc.ssid_len + /* SSID */ + 4 + rates_len + /* (extended) rates */ + 4 + /* power capability */ + 2 + 2 * sband->n_channels + /* supported channels */ + 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ + wk->ie_len + /* extra IEs */ + 9, /* WMM */ + GFP_KERNEL); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " "frame\n", sdata->name); @@ -123,8 +238,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } skb_reserve(skb, local->hw.extra_tx_headroom); - sband = local->hw.wiphy->bands[wk->chan->band]; - capab = WLAN_CAPABILITY_ESS; if (sband->band == IEEE80211_BAND_2GHZ) { @@ -137,16 +250,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - /* - * Get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode)... - */ - rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, - wk->assoc.supp_rates_len, - sband, &rates); - if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; @@ -220,7 +323,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, *pos++ = WLAN_EID_PWR_CAPABILITY; *pos++ = 2; *pos++ = 0; /* min tx power */ - *pos++ = local->hw.conf.channel->max_power; /* max tx power */ + *pos++ = wk->chan->max_power; /* max tx power */ /* 2. supported channels */ /* TODO: get this in reg domain format */ @@ -234,11 +337,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } } + /* + * XXX: These IEs could contain (vendor-specified) + * IEs that belong after HT -- the buffer may + * need to be split up. + */ if (wk->ie_len && wk->ie) { pos = skb_put(skb, wk->ie_len); memcpy(pos, wk->ie, wk->ie_len); } + if (wk->assoc.use_11n && wk->assoc.wmm_used && + local->hw.queues >= 4) + ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, + sband, wk->chan, wk->assoc.smps); + if (wk->assoc.wmm_used && local->hw.queues >= 4) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; @@ -252,98 +365,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, *pos++ = 0; } - /* wmm support is a must to HT */ - /* - * IEEE802.11n does not allow TKIP/WEP as pairwise - * ciphers in HT mode. We still associate in non-ht - * mode (11a/b/g) if any one of these ciphers is - * configured as pairwise. - */ - if (wk->assoc.use_11n && wk->assoc.wmm_used && - (local->hw.queues >= 4) && - sband->ht_cap.ht_supported && - (ht_ie = wk->assoc.ht_information_ie) && - ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { - struct ieee80211_ht_info *ht_info = - (struct ieee80211_ht_info *)(ht_ie + 2); - u16 cap = sband->ht_cap.cap; - __le16 tmp; - u32 flags = local->hw.conf.channel->flags; - - /* determine capability flags */ - - if (ieee80211_disable_40mhz_24ghz && - sband->band == IEEE80211_BAND_2GHZ) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - - switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_HT40PLUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_HT40MINUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - } - - /* set SM PS mode properly */ - cap &= ~IEEE80211_HT_CAP_SM_PS; - switch (wk->assoc.smps) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_NUM_MODES: - WARN_ON(1); - case IEEE80211_SMPS_OFF: - cap |= WLAN_HT_CAP_SM_PS_DISABLED << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_STATIC: - cap |= WLAN_HT_CAP_SM_PS_STATIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_DYNAMIC: - cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - } - - /* reserve and fill IE */ - - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - - /* capability flags */ - tmp = cpu_to_le16(cap); - memcpy(pos, &tmp, sizeof(u16)); - pos += sizeof(u16); - - /* AMPDU parameters */ - *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); - - /* MCS set */ - memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); - pos += sizeof(sband->ht_cap.mcs); - - /* extended capabilities */ - pos += sizeof(__le16); - - /* BF capabilities */ - pos += sizeof(__le32); - - /* antenna selection */ - pos += sizeof(u8); - } - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } -- GitLab From 8e664fb3fd2b04e3ac5fad7f046000ba54e0e275 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:38 +0100 Subject: [PATCH 0274/3892] mac80211: split up and insert custom IEs correctly Currently, we insert all user-specified IEs before the HT IE for association, and after the HT IE for probe requests. For association, that's correct only if the user-specified IEs are RSN only, incorrect in all other cases including WPA. Change this to split apart the user-specified IEs in two places for association: before the HT IE (e.g. RSN), after the HT IE (generally empty right now I think?) and after WMM (all other vendor-specific IEs). For probes, split the IEs in different places to be correct according to the spec. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 39 ++++++++--- net/mac80211/ieee80211_i.h | 4 ++ net/mac80211/util.c | 134 +++++++++++++++++++++++++++++++------ net/mac80211/work.c | 43 ++++++++++-- 4 files changed, 184 insertions(+), 36 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d62edc7df3ae..aeea282bd2fe 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1085,12 +1085,12 @@ enum ieee80211_eid { WLAN_EID_TIM = 5, WLAN_EID_IBSS_PARAMS = 6, WLAN_EID_CHALLENGE = 16, - /* 802.11d */ + WLAN_EID_COUNTRY = 7, WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, - /* 802.11e */ + WLAN_EID_QBSS_LOAD = 11, WLAN_EID_EDCA_PARAM_SET = 12, WLAN_EID_TSPEC = 13, @@ -1113,7 +1113,7 @@ enum ieee80211_eid { WLAN_EID_PREP = 69, WLAN_EID_PERR = 70, WLAN_EID_RANN = 49, /* compatible with FreeBSD */ - /* 802.11h */ + WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, WLAN_EID_TPC_REQUEST = 34, @@ -1124,20 +1124,41 @@ enum ieee80211_eid { WLAN_EID_MEASURE_REPORT = 39, WLAN_EID_QUIET = 40, WLAN_EID_IBSS_DFS = 41, - /* 802.11g */ + WLAN_EID_ERP_INFO = 42, WLAN_EID_EXT_SUPP_RATES = 50, - /* 802.11n */ + WLAN_EID_HT_CAPABILITY = 45, WLAN_EID_HT_INFORMATION = 61, - /* 802.11i */ + WLAN_EID_RSN = 48, - WLAN_EID_TIMEOUT_INTERVAL = 56, - WLAN_EID_MMIE = 76 /* 802.11w */, + WLAN_EID_MMIE = 76, WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, - WLAN_EID_QOS_PARAMETER = 222 + WLAN_EID_QOS_PARAMETER = 222, + + WLAN_EID_AP_CHAN_REPORT = 51, + WLAN_EID_NEIGHBOR_REPORT = 52, + WLAN_EID_RCPI = 53, + WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, + WLAN_EID_ANTENNA_INFO = 64, + WLAN_EID_RSNI = 65, + WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, + WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, + WLAN_EID_BSS_AC_ACCESS_DELAY = 68, + WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, + WLAN_EID_MULTIPLE_BSSID = 71, + + WLAN_EID_MOBILITY_DOMAIN = 54, + WLAN_EID_FAST_BSS_TRANSITION = 55, + WLAN_EID_TIMEOUT_INTERVAL = 56, + WLAN_EID_RIC_DATA = 57, + WLAN_EID_RIC_DESCRIPTOR = 75, + + WLAN_EID_DSE_REGISTERED_LOCATION = 58, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, + WLAN_EID_EXT_CHANSWITCH_ANN = 60, }; /* Action category code */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 97b6076b492e..6ea4ffbf84d8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1148,6 +1148,10 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, void ieee80211_recalc_smps(struct ieee80211_local *local, struct ieee80211_sub_if_data *forsdata); +size_t ieee80211_ie_split(const u8 *ies, size_t ielen, + const u8 *ids, int n_ids, size_t offset); +size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); + /* internal work items */ void ieee80211_work_init(struct ieee80211_local *local); void ieee80211_add_work(struct ieee80211_work *wk); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5ffe9e831b66..1fdb80ff9241 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -881,30 +881,66 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, enum ieee80211_band band) { struct ieee80211_supported_band *sband; - u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; - int i; + u8 *pos; + size_t offset = 0, noffset; + int supp_rates_len, i; sband = local->hw.wiphy->bands[band]; pos = buffer; + supp_rates_len = min_t(int, sband->n_bitrates, 8); + *pos++ = WLAN_EID_SUPP_RATES; - supp_rates_len = pos; - *pos++ = 0; - - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - - if (esupp_rates_len) { - *esupp_rates_len += 1; - } else if (*supp_rates_len == 8) { - *pos++ = WLAN_EID_EXT_SUPP_RATES; - esupp_rates_len = pos; - *pos++ = 1; - } else - *supp_rates_len += 1; + *pos++ = supp_rates_len; - *pos++ = rate->bitrate / 5; + for (i = 0; i < supp_rates_len; i++) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + + /* insert "request information" if in custom IEs */ + if (ie && ie_len) { + static const u8 before_extrates[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_REQUEST, + }; + noffset = ieee80211_ie_split(ie, ie_len, + before_extrates, + ARRAY_SIZE(before_extrates), + offset); + memcpy(pos, ie + offset, noffset - offset); + pos += noffset - offset; + offset = noffset; + } + + if (sband->n_bitrates > i) { + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = sband->n_bitrates - i; + + for (; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + + /* insert custom IEs that go before HT */ + if (ie && ie_len) { + static const u8 before_ht[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_REQUEST, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_DS_PARAMS, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + }; + noffset = ieee80211_ie_split(ie, ie_len, + before_ht, ARRAY_SIZE(before_ht), + offset); + memcpy(pos, ie + offset, noffset - offset); + pos += noffset - offset; + offset = noffset; } if (sband->ht_cap.ht_supported) { @@ -936,9 +972,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, * that calculates local->scan_ies_len. */ - if (ie) { - memcpy(pos, ie, ie_len); - pos += ie_len; + /* add any remaining custom IEs */ + if (ie && ie_len) { + noffset = ie_len; + memcpy(pos, ie + offset, noffset - offset); + pos += noffset - offset; } return pos - buffer; @@ -1252,3 +1290,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, /* changed flag is auto-detected for this */ ieee80211_hw_config(local, 0); } + +static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) +{ + int i; + + for (i = 0; i < n_ids; i++) + if (ids[i] == id) + return true; + return false; +} + +/** + * ieee80211_ie_split - split an IE buffer according to ordering + * + * @ies: the IE buffer + * @ielen: the length of the IE buffer + * @ids: an array with element IDs that are allowed before + * the split + * @n_ids: the size of the element ID array + * @offset: offset where to start splitting in the buffer + * + * This function splits an IE buffer by updating the @offset + * variable to point to the location where the buffer should be + * split. + * + * It assumes that the given IE buffer is well-formed, this + * has to be guaranteed by the caller! + * + * It also assumes that the IEs in the buffer are ordered + * correctly, if not the result of using this function will not + * be ordered correctly either, i.e. it does no reordering. + * + * The function returns the offset where the next part of the + * buffer starts, which may be @ielen if the entire (remainder) + * of the buffer should be used. + */ +size_t ieee80211_ie_split(const u8 *ies, size_t ielen, + const u8 *ids, int n_ids, size_t offset) +{ + size_t pos = offset; + + while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) + pos += 2 + ies[pos + 1]; + + return pos; +} + +size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) +{ + size_t pos = offset; + + while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) + pos += 2 + ies[pos + 1]; + + return pos; +} diff --git a/net/mac80211/work.c b/net/mac80211/work.c index c03c22d5bca3..affdd10b67ad 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -204,6 +204,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u8 *pos; const u8 *ies; + size_t offset = 0, noffset; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; @@ -337,14 +338,26 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } } - /* - * XXX: These IEs could contain (vendor-specified) - * IEs that belong after HT -- the buffer may - * need to be split up. - */ + /* if present, add any custom IEs that go before HT */ if (wk->ie_len && wk->ie) { - pos = skb_put(skb, wk->ie_len); - memcpy(pos, wk->ie, wk->ie_len); + static const u8 before_ht[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_PWR_CAPABILITY, + WLAN_EID_SUPPORTED_CHANNELS, + WLAN_EID_RSN, + WLAN_EID_QOS_CAPA, + WLAN_EID_RRM_ENABLED_CAPABILITIES, + WLAN_EID_MOBILITY_DOMAIN, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + }; + noffset = ieee80211_ie_split(wk->ie, wk->ie_len, + before_ht, ARRAY_SIZE(before_ht), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, wk->ie + offset, noffset - offset); + offset = noffset; } if (wk->assoc.use_11n && wk->assoc.wmm_used && @@ -352,6 +365,15 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, sband, wk->chan, wk->assoc.smps); + /* if present, add any custom non-vendor IEs that go after HT */ + if (wk->ie_len && wk->ie) { + noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len, + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, wk->ie + offset, noffset - offset); + offset = noffset; + } + if (wk->assoc.wmm_used && local->hw.queues >= 4) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; @@ -365,6 +387,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, *pos++ = 0; } + /* add any remaining custom (i.e. vendor specific here) IEs */ + if (wk->ie_len && wk->ie) { + noffset = wk->ie_len; + pos = skb_put(skb, noffset - offset); + memcpy(pos, wk->ie + offset, noffset - offset); + } + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } -- GitLab From 0c1ad2cac1cb54db38fd4cc1822965071ee83f6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:39 +0100 Subject: [PATCH 0275/3892] mac80211: proper bss private data handling cfg80211 offers private data for each BSS struct, which mac80211 uses. However, mac80211 uses internal and external (cfg80211) BSS pointers interchangeably and has a hack to put the cfg80211 bss struct into the private struct. Remove this hack, properly converting between the pointers wherever necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- net/mac80211/ibss.c | 45 ++++++++++++++++----------- net/mac80211/ieee80211_i.h | 7 ++--- net/mac80211/main.c | 4 +-- net/mac80211/mlme.c | 64 ++++++++++++++++++++------------------ net/mac80211/scan.c | 29 ++++++++++------- net/mac80211/work.c | 3 +- 7 files changed, 82 insertions(+), 72 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fdac1bcbfcc0..ea862dfc08ed 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1343,7 +1343,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, return 0; } - ap = sdata->u.mgd.associated->cbss.bssid; + ap = sdata->u.mgd.associated->bssid; if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { if (sdata->u.mgd.powersave) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3a61f3ba85c9..621a54c0573a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss) { + struct cfg80211_bss *cbss = + container_of((void *)bss, struct cfg80211_bss, priv); struct ieee80211_supported_band *sband; u32 basic_rates; int i, j; - u16 beacon_int = bss->cbss.beacon_interval; + u16 beacon_int = cbss->beacon_interval; if (beacon_int < 10) beacon_int = 10; - sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; + sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; basic_rates = 0; @@ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } } - __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, + __ieee80211_sta_join_ibss(sdata, cbss->bssid, beacon_int, - bss->cbss.channel, + cbss->channel, basic_rates, - bss->cbss.capability, - bss->cbss.tsf); + cbss->capability, + cbss->tsf); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, @@ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; int freq; + struct cfg80211_bss *cbss; struct ieee80211_bss *bss; struct sta_info *sta; struct ieee80211_channel *channel; @@ -283,8 +286,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (!bss) return; + cbss = container_of((void *)bss, struct cfg80211_bss, priv); + /* was just updated in ieee80211_bss_info_update */ - beacon_timestamp = bss->cbss.tsf; + beacon_timestamp = cbss->tsf; /* check if we need to merge IBSS */ @@ -297,11 +302,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* not an IBSS */ - if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) + if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) goto put_bss; /* different channel */ - if (bss->cbss.channel != local->oper_channel) + if (cbss->channel != local->oper_channel) goto put_bss; /* different SSID */ @@ -311,7 +316,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* same BSSID */ - if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) + if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) goto put_bss; if (rx_status->flag & RX_FLAG_TSFT) { @@ -514,7 +519,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss; + struct cfg80211_bss *cbss; struct ieee80211_channel *chan = NULL; const u8 *bssid = NULL; int active_ibss; @@ -538,21 +543,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) chan = ifibss->channel; if (!is_zero_ether_addr(ifibss->bssid)) bssid = ifibss->bssid; - bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, - ifibss->ssid, ifibss->ssid_len, - WLAN_CAPABILITY_IBSS | - WLAN_CAPABILITY_PRIVACY, - capability); + cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, + ifibss->ssid, ifibss->ssid_len, + WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, + capability); + + if (cbss) { + struct ieee80211_bss *bss; - if (bss) { + bss = (void *)cbss->priv; #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG " sta_find_ibss: selected %pM current " - "%pM\n", bss->cbss.bssid, ifibss->bssid); + "%pM\n", cbss->bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", - sdata->name, bss->cbss.bssid); + sdata->name, cbss->bssid); ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6ea4ffbf84d8..de068ad6223b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -71,9 +71,6 @@ struct ieee80211_fragment_entry { struct ieee80211_bss { - /* Yes, this is a hack */ - struct cfg80211_bss cbss; - /* don't want to look up all the time */ size_t ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -274,7 +271,7 @@ struct ieee80211_work { bool privacy; } probe_auth; struct { - struct ieee80211_bss *bss; + struct cfg80211_bss *bss; const u8 *supp_rates; const u8 *ht_information_ie; enum ieee80211_smps_mode smps; @@ -317,7 +314,7 @@ struct ieee80211_if_managed { int probe_send_count; struct mutex mtx; - struct ieee80211_bss *associated; + struct cfg80211_bss *associated; u8 bssid[ETH_ALEN]; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d35023ce7fa1..5fcd3548417e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -359,9 +359,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, WIPHY_FLAG_4ADDR_STATION; wiphy->privid = mac80211_wiphy_privid; - /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ - wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - - sizeof(struct cfg80211_bss); + wiphy->bss_priv_size = sizeof(struct ieee80211_bss); local = wiphy_priv(wiphy); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ea434b5a779e..e44f1ed0b0da 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -330,7 +330,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); /* XXX: shouldn't really modify cfg80211-owned data! */ - ifmgd->associated->cbss.channel = sdata->local->oper_channel; + ifmgd->associated->channel = sdata->local->oper_channel; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -357,6 +357,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_sw_ie *sw_elem, struct ieee80211_bss *bss) { + struct cfg80211_bss *cbss = + container_of((void *)bss, struct cfg80211_bss, priv); struct ieee80211_channel *new_ch; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); @@ -390,7 +392,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, mod_timer(&ifmgd->chswitch_timer, jiffies + msecs_to_jiffies(sw_elem->count * - bss->cbss.beacon_interval)); + cbss->beacon_interval)); } } @@ -670,23 +672,24 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss, + struct cfg80211_bss *cbss, u32 bss_info_changed) { + struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_local *local = sdata->local; bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ - sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; - sdata->vif.bss_conf.timestamp = bss->cbss.tsf; + sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; + sdata->vif.bss_conf.timestamp = cbss->tsf; sdata->vif.bss_conf.dtim_period = bss->dtim_period; bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, - bss->cbss.capability, bss->has_erp_value, bss->erp_value); + cbss->capability, bss->has_erp_value, bss->erp_value); - sdata->u.mgd.associated = bss; - memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); + sdata->u.mgd.associated = cbss; + memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); /* just to be sure */ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | @@ -737,7 +740,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) if (WARN_ON(!ifmgd->associated)) return; - memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); @@ -833,8 +836,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, + ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, ssid + 2, ssid[1], NULL, 0); ifmgd->probe_send_count++; @@ -928,7 +931,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); - bssid = ifmgd->associated->cbss.bssid; + bssid = ifmgd->associated->bssid; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); @@ -957,7 +960,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->associated)) return RX_MGMT_NONE; - if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) + if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); @@ -979,7 +982,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; - struct ieee80211_bss *bss = wk->assoc.bss; + struct cfg80211_bss *cbss = wk->assoc.bss; u8 *pos; u32 rates, basic_rates; u16 capab_info, aid; @@ -1011,7 +1014,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, ifmgd->aid = aid; - sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL); + sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" " the AP\n", sdata->name); @@ -1103,14 +1106,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, (sdata->local->hw.queues >= 4) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, - bss->cbss.bssid, - ap_ht_cap_flags); + cbss->bssid, ap_ht_cap_flags); /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, bss, changed); + ieee80211_set_associated(sdata, cbss, changed); /* * Start timer to probe the connection to the AP now. @@ -1154,7 +1156,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, return; if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && - (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, + (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; @@ -1189,7 +1191,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); if (ifmgd->associated && - memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && ifmgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL)) { ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | @@ -1262,7 +1264,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (!ifmgd->associated) return; - bssid = ifmgd->associated->cbss.bssid; + bssid = ifmgd->associated->bssid; /* * And in theory even frames from a different AP we were just @@ -1428,8 +1430,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); if (ifmgd->associated && - memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, - ETH_ALEN) == 0) { + memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, @@ -1448,7 +1449,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* XXX: differentiate, can only happen for CSA now! */ ieee80211_sta_process_chanswitch(sdata, &mgmt->u.action.u.chan_switch.sw_elem, - ifmgd->associated); + (void *)ifmgd->associated->priv); break; } mutex_unlock(&ifmgd->mtx); @@ -1533,7 +1534,7 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd->associated) { u8 bssid[ETH_ALEN]; - memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); @@ -1840,6 +1841,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_work *wk; const u8 *ssid; int i; @@ -1870,7 +1872,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else wk->ie_len = 0; - wk->assoc.bss = (void *)req->bss; + wk->assoc.bss = req->bss; memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); @@ -1893,9 +1895,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, */ wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); wk->assoc.capability = req->bss->capability; - wk->assoc.wmm_used = wk->assoc.bss->wmm_used; - wk->assoc.supp_rates = wk->assoc.bss->supp_rates; - wk->assoc.supp_rates_len = wk->assoc.bss->supp_rates_len; + wk->assoc.wmm_used = bss->wmm_used; + wk->assoc.supp_rates = bss->supp_rates; + wk->assoc.supp_rates_len = bss->supp_rates_len; wk->assoc.ht_information_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); @@ -1942,7 +1944,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); - if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { + if (ifmgd->associated == req->bss) { bssid = req->bss->bssid; ieee80211_set_disassoc(sdata); mutex_unlock(&ifmgd->mtx); @@ -2004,7 +2006,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, * to cfg80211 while that's in a locked section already * trying to tell us that the user wants to disconnect. */ - if (&ifmgd->associated->cbss != req->bss) { + if (ifmgd->associated != req->bss) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index fb89e4c0fbfd..2a2d7f6005af 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -29,16 +29,19 @@ struct ieee80211_bss * ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { - return (void *)cfg80211_get_bss(local->hw.wiphy, - ieee80211_get_channel(local->hw.wiphy, - freq), - bssid, ssid, ssid_len, - 0, 0); + struct cfg80211_bss *cbss; + + cbss = cfg80211_get_bss(local->hw.wiphy, + ieee80211_get_channel(local->hw.wiphy, freq), + bssid, ssid, ssid_len, 0, 0); + if (!cbss) + return NULL; + return (void *)cbss->priv; } static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) { - struct ieee80211_bss *bss = (void *)cbss; + struct ieee80211_bss *bss = (void *)cbss->priv; kfree(bss_mesh_id(bss)); kfree(bss_mesh_cfg(bss)); @@ -47,7 +50,9 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss) { - cfg80211_put_bss((struct cfg80211_bss *)bss); + if (!bss) + return; + cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); } struct ieee80211_bss * @@ -59,6 +64,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_channel *channel, bool beacon) { + struct cfg80211_bss *cbss; struct ieee80211_bss *bss; int clen; s32 signal = 0; @@ -68,13 +74,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) signal = (rx_status->signal * 100) / local->hw.max_signal; - bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, - mgmt, len, signal, GFP_ATOMIC); + cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, + mgmt, len, signal, GFP_ATOMIC); - if (!bss) + if (!cbss) return NULL; - bss->cbss.free_priv = ieee80211_rx_bss_free; + cbss->free_priv = ieee80211_rx_bss_free; + bss = (void *)cbss->priv; /* save the ERP value so that it is available at association time */ if (elems->erp_info && elems->erp_info_len >= 1) { diff --git a/net/mac80211/work.c b/net/mac80211/work.c index affdd10b67ad..0b8c31c600aa 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -517,8 +517,7 @@ ieee80211_associate(struct ieee80211_work *wk) * bss struct for that AP. */ if (wk->assoc.bss) - cfg80211_unlink_bss(local->hw.wiphy, - &wk->assoc.bss->cbss); + cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); /* * We might have a pending scan which had no chance to run yet -- GitLab From b203ffc3a447eb8d9e6120b783ddee081b143061 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 23 Dec 2009 13:15:40 +0100 Subject: [PATCH 0276/3892] mac80211: Generalize off-channel operation helpers from scan code The off-channel operations for going into power save mode (station mode) or stop beaconing (AP/IBSS) are not limited to scanning. Move these into a separate file and allow them to be used for other purposes, too. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Makefile | 2 +- net/mac80211/ieee80211_i.h | 8 +- net/mac80211/offchannel.c | 164 +++++++++++++++++++++++++++++++++++++ net/mac80211/scan.c | 156 ++--------------------------------- 4 files changed, 178 insertions(+), 152 deletions(-) create mode 100644 net/mac80211/offchannel.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 5a1f57df7cd6..04420291e7ad 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -6,7 +6,7 @@ mac80211-y := \ sta_info.o \ wep.o \ wpa.o \ - scan.o \ + scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ mlme.o work.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index de068ad6223b..fd912eb5309e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -786,7 +786,7 @@ struct ieee80211_local { unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ bool pspolling; - bool scan_ps_enabled; + bool offchannel_ps_enabled; /* * PS can only be enabled when we have exactly one managed * interface (and monitors) in PS, this then points there. @@ -981,6 +981,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); +/* off-channel helpers */ +void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); +void ieee80211_offchannel_stop_station(struct ieee80211_local *local); +void ieee80211_offchannel_return(struct ieee80211_local *local, + bool enable_beaconing); + /* interface handling */ int ieee80211_iface_init(void); void ieee80211_iface_exit(void); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c new file mode 100644 index 000000000000..2cd880e444d1 --- /dev/null +++ b/net/mac80211/offchannel.c @@ -0,0 +1,164 @@ +/* + * Off-channel operation helpers + * + * Copyright 2003, Jouni Malinen + * Copyright 2004, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007, Michael Wu + * Copyright 2009 Johannes Berg + * + * 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 "ieee80211_i.h" + +/* + * inform AP that we will go to sleep so that it will buffer the frames + * while we scan + */ +static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + + local->offchannel_ps_enabled = false; + + /* FIXME: what to do when local->pspolling is true? */ + + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->offchannel_ps_enabled = true; + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + if (!(local->offchannel_ps_enabled) || + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) + /* + * If power save was enabled, no need to send a nullfunc + * frame because AP knows that we are sleeping. But if the + * hardware is creating the nullfunc frame for power save + * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not + * enabled) and power save was enabled, the firmware just + * sent a null frame with power save disabled. So we need + * to send a new nullfunc frame to inform the AP that we + * are again sleeping. + */ + ieee80211_send_nullfunc(local, sdata, 1); +} + +/* inform AP that we are awake again, unless power save is enabled */ +static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + + if (!local->ps_sdata) + ieee80211_send_nullfunc(local, sdata, 0); + else if (local->offchannel_ps_enabled) { + /* + * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware + * will send a nullfunc frame with the powersave bit set + * even though the AP already knows that we are sleeping. + * This could be avoided by sending a null frame with power + * save bit disabled before enabling the power save, but + * this doesn't gain anything. + * + * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need + * to send a nullfunc frame because AP already knows that + * we are sleeping, let's just enable power save mode in + * hardware. + */ + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } else if (local->hw.conf.dynamic_ps_timeout > 0) { + /* + * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer + * had been running before leaving the operating channel, + * restart the timer now and send a nullfunc frame to inform + * the AP that we are awake. + */ + ieee80211_send_nullfunc(local, sdata, 0); + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + } +} + +void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; + + /* disable beaconing */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); + + /* + * only handle non-STA interfaces here, STA interfaces + * are handled in ieee80211_offchannel_stop_station(), + * e.g., from the background scan state machine + */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) + netif_stop_queue(sdata->dev); + } + mutex_unlock(&local->iflist_mtx); +} + +void ieee80211_offchannel_stop_station(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * notify the AP about us leaving the channel and stop all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + netif_stop_queue(sdata->dev); + if (sdata->u.mgd.associated) + ieee80211_offchannel_ps_enable(sdata); + } + } + mutex_unlock(&local->iflist_mtx); +} + +void ieee80211_offchannel_return(struct ieee80211_local *local, + bool enable_beaconing) +{ + struct ieee80211_sub_if_data *sdata; + + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) + ieee80211_offchannel_ps_disable(sdata); + netif_wake_queue(sdata->dev); + } + + /* re-enable beaconing */ + if (enable_beaconing && + (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); + } + mutex_unlock(&local->iflist_mtx); +} diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 2a2d7f6005af..365f40975511 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -227,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) return true; } -/* - * inform AP that we will go to sleep so that it will buffer the frames - * while we scan - */ -static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - - local->scan_ps_enabled = false; - - /* FIXME: what to do when local->pspolling is true? */ - - del_timer_sync(&local->dynamic_ps_timer); - cancel_work_sync(&local->dynamic_ps_enable_work); - - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->scan_ps_enabled = true; - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - - if (!(local->scan_ps_enabled) || - !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) - /* - * If power save was enabled, no need to send a nullfunc - * frame because AP knows that we are sleeping. But if the - * hardware is creating the nullfunc frame for power save - * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not - * enabled) and power save was enabled, the firmware just - * sent a null frame with power save disabled. So we need - * to send a new nullfunc frame to inform the AP that we - * are again sleeping. - */ - ieee80211_send_nullfunc(local, sdata, 1); -} - -/* inform AP that we are awake again, unless power save is enabled */ -static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - - if (!local->ps_sdata) - ieee80211_send_nullfunc(local, sdata, 0); - else if (local->scan_ps_enabled) { - /* - * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware - * will send a nullfunc frame with the powersave bit set - * even though the AP already knows that we are sleeping. - * This could be avoided by sending a null frame with power - * save bit disabled before enabling the power save, but - * this doesn't gain anything. - * - * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need - * to send a nullfunc frame because AP already knows that - * we are sleeping, let's just enable power save mode in - * hardware. - */ - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } else if (local->hw.conf.dynamic_ps_timeout > 0) { - /* - * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer - * had been running before leaving the operating channel, - * restart the timer now and send a nullfunc frame to inform - * the AP that we are awake. - */ - ieee80211_send_nullfunc(local, sdata, 0); - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - } -} - void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; bool was_hw_scan; mutex_lock(&local->scan_mtx); @@ -351,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) drv_sw_scan_complete(local); - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - /* Tell AP we're back */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) { - ieee80211_scan_ps_disable(sdata); - netif_wake_queue(sdata->dev); - } - } else - netif_wake_queue(sdata->dev); - - /* re-enable beaconing */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); - } - mutex_unlock(&local->iflist_mtx); + ieee80211_offchannel_return(local, true); done: ieee80211_recalc_idle(local); @@ -384,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed); static int ieee80211_start_sw_scan(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata; - /* * Hardware/driver doesn't support hw_scan, so use software * scanning instead. First send a nullfunc frame with power save @@ -401,26 +305,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) */ drv_sw_scan_start(local); - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - /* disable beaconing */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); - - /* - * only handle non-STA interfaces here, STA interfaces - * are handled in the scan state machine - */ - if (sdata->vif.type != NL80211_IFTYPE_STATION) - netif_stop_queue(sdata->dev); - } - mutex_unlock(&local->iflist_mtx); + ieee80211_offchannel_stop_beaconing(local); local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; @@ -568,23 +453,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, unsigned long *next_delay) { - struct ieee80211_sub_if_data *sdata; - - /* - * notify the AP about us leaving the channel and stop all STA interfaces - */ - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - netif_stop_queue(sdata->dev); - if (sdata->u.mgd.associated) - ieee80211_scan_ps_enable(sdata); - } - } - mutex_unlock(&local->iflist_mtx); + ieee80211_offchannel_stop_station(local); __set_bit(SCAN_OFF_CHANNEL, &local->scanning); @@ -604,28 +473,15 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, unsigned long *next_delay) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - /* switch back to the operating channel */ local->scan_channel = NULL; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); /* - * notify the AP about us being back and restart all STA interfaces + * Only re-enable station mode interface now; beaconing will be + * re-enabled once the full scan has been completed. */ - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - /* Tell AP we're back */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) - ieee80211_scan_ps_disable(sdata); - netif_wake_queue(sdata->dev); - } - } - mutex_unlock(&local->iflist_mtx); + ieee80211_offchannel_return(local, false); __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); -- GitLab From 9588bbd5529461a3dacd435bf239c84c3508f569 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 23 Dec 2009 13:15:41 +0100 Subject: [PATCH 0277/3892] cfg80211: add remain-on-channel command Add new commands for requesting the driver to remain awake on a specified channel for the specified amount of time (and another command to cancel such an operation). This can be used to implement userspace-controlled off-channel operations, like Public Action frame exchange on another channel than the operation channel. The off-channel operation should behave similarly to scan, i.e. the local station (if associated) moves into power save mode to request the AP to buffer frames for it and then moves to the other channel to allow the off-channel operation to be completed. The duration parameter can be used to request enough time to receive a response from the target station. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 36 +++++++ include/net/cfg80211.h | 47 +++++++++ net/wireless/chan.c | 41 +++++--- net/wireless/core.h | 3 + net/wireless/mlme.c | 27 +++++ net/wireless/nl80211.c | 218 +++++++++++++++++++++++++++++++++++++++- net/wireless/nl80211.h | 11 ++ 7 files changed, 368 insertions(+), 15 deletions(-) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index da8ea2e19273..2bfbe88837ef 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -270,6 +270,31 @@ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices * associated with this wiphy must be down and will follow. * + * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified + * channel for the specified amount of time. This can be used to do + * off-channel operations like transmit a Public Action frame and wait for + * a response while being associated to an AP on another channel. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which + * radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the + * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be + * optionally used to specify additional channel parameters. + * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds + * to remain on the channel. This command is also used as an event to + * notify when the requested duration starts (it may take a while for the + * driver to schedule this time due to other concurrent needs for the + * radio). + * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) + * that will be included with any events pertaining to this request; + * the cookie is also used to cancel the request. + * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a + * pending remain-on-channel duration if the desired operation has been + * completed prior to expiration of the originally requested duration. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the + * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to + * uniquely identify the request. + * This command is also used as an event to notify when a requested + * remain-on-channel duration has expired. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -353,6 +378,9 @@ enum nl80211_commands { NL80211_CMD_DEL_PMKSA, NL80211_CMD_FLUSH_PMKSA, + NL80211_CMD_REMAIN_ON_CHANNEL, + NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -606,6 +634,10 @@ enum nl80211_commands { * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can * cache, a wiphy attribute. * + * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. + * + * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -743,6 +775,10 @@ enum nl80211_attrs { NL80211_ATTR_PMKID, NL80211_ATTR_MAX_NUM_PMKIDS, + NL80211_ATTR_DURATION, + + NL80211_ATTR_COOKIE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 542a477a94da..b66beb052054 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -988,6 +988,15 @@ struct cfg80211_pmksa { * * @dump_survey: get site survey information. * + * @remain_on_channel: Request the driver to remain awake on the specified + * channel for the specified duration to complete an off-channel + * operation (e.g., public action frame exchange). When the driver is + * ready on the requested channel, it must indicate this with an event + * notification by calling cfg80211_ready_on_channel(). + * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. + * This allows the operation to be terminated prior to timeout based on + * the duration value. + * * @testmode_cmd: run a test mode command * * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac @@ -1123,6 +1132,16 @@ struct cfg80211_ops { struct cfg80211_pmksa *pmksa); int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); + int (*remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie); + int (*cancel_remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); @@ -2147,5 +2166,33 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, void cfg80211_disconnected(struct net_device *dev, u16 reason, u8 *ie, size_t ie_len, gfp_t gfp); +/** + * cfg80211_ready_on_channel - notification of remain_on_channel start + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @duration: Duration in milliseconds that the driver intents to remain on the + * channel + * @gfp: allocation flags + */ +void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp); + +/** + * cfg80211_remain_on_channel_expired - remain_on_channel duration expired + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @gfp: allocation flags + */ +void cfg80211_remain_on_channel_expired(struct net_device *dev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + gfp_t gfp); #endif /* __NET_CFG80211_H */ diff --git a/net/wireless/chan.c b/net/wireless/chan.c index a46ac6c9b365..bf1737fc9a7e 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -41,44 +41,57 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev, return result; } -int rdev_set_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *for_wdev, +struct ieee80211_channel * +rdev_freq_to_chan(struct cfg80211_registered_device *rdev, int freq, enum nl80211_channel_type channel_type) { struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; - int result; - - if (rdev_fixed_channel(rdev, for_wdev)) - return -EBUSY; - - if (!rdev->ops->set_channel) - return -EOPNOTSUPP; chan = ieee80211_get_channel(&rdev->wiphy, freq); /* Primary channel not allowed */ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - return -EINVAL; + return NULL; if (channel_type == NL80211_CHAN_HT40MINUS && chan->flags & IEEE80211_CHAN_NO_HT40MINUS) - return -EINVAL; + return NULL; else if (channel_type == NL80211_CHAN_HT40PLUS && chan->flags & IEEE80211_CHAN_NO_HT40PLUS) - return -EINVAL; + return NULL; ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; if (channel_type != NL80211_CHAN_NO_HT) { if (!ht_cap->ht_supported) - return -EINVAL; + return NULL; if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) - return -EINVAL; + return NULL; } + return chan; +} + +int rdev_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev, + int freq, enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *chan; + int result; + + if (rdev_fixed_channel(rdev, for_wdev)) + return -EBUSY; + + if (!rdev->ops->set_channel) + return -EOPNOTSUPP; + + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (!chan) + return -EINVAL; + result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); if (result) return result; diff --git a/net/wireless/core.h b/net/wireless/core.h index 35b712127143..30ec95f05b52 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -374,6 +374,9 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); struct ieee80211_channel * rdev_fixed_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev); +struct ieee80211_channel * +rdev_freq_to_chan(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type); int rdev_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index acaeaa784d68..11f6469b3f98 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -680,3 +680,30 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, } } } + +void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, + duration, gfp); +} +EXPORT_SYMBOL(cfg80211_ready_on_channel); + +void cfg80211_remain_on_channel_expired(struct net_device *dev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, + channel_type, gfp); +} +EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 60f854377f90..ff857f10cb85 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, + [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, }; /* policy for the attributes */ @@ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(set_pmksa, SET_PMKSA); CMD(del_pmksa, DEL_PMKSA); CMD(flush_pmksa, FLUSH_PMKSA); + CMD(remain_on_channel, REMAIN_ON_CHANNEL); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -4283,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) } +static int nl80211_remain_on_channel(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + struct ieee80211_channel *chan; + struct sk_buff *msg; + void *hdr; + u64 cookie; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + u32 freq, duration; + int err; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_DURATION]) + return -EINVAL; + + duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); + + /* + * We should be on that channel for at least one jiffie, + * and more than 5 seconds seems excessive. + */ + if (!duration || !msecs_to_jiffies(duration) || duration > 5000) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + if (!rdev->ops->remain_on_channel) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + err = -EINVAL; + goto out; + } + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (chan == NULL) { + err = -EINVAL; + goto out; + } + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto out; + } + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_REMAIN_ON_CHANNEL); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto free_msg; + } + + err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, + channel_type, duration, &cookie); + + if (err) + goto free_msg; + + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + genlmsg_end(msg, hdr); + err = genlmsg_reply(msg, info); + goto out; + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); + unlock_rtnl: + rtnl_unlock(); + return err; +} + +static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + u64 cookie; + int err; + + if (!info->attrs[NL80211_ATTR_COOKIE]) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + if (!rdev->ops->cancel_remain_on_channel) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); + + err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); + + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); + unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4545,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, - + { + .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, + .doit = nl80211_remain_on_channel, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + .doit = nl80211_cancel_remain_on_channel, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; + static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", }; @@ -5134,6 +5286,70 @@ nla_put_failure: nlmsg_free(msg); } +static void nl80211_send_remain_on_chan_event( + int cmd, struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) + NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, + rdev, netdev, cookie, chan, + channel_type, duration, gfp); +} + +void nl80211_send_remain_on_channel_cancel( + struct cfg80211_registered_device *rdev, struct net_device *netdev, + u64 cookie, struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, gfp_t gfp) +{ + nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + rdev, netdev, cookie, chan, + channel_type, 0, gfp); +} + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 44cc2a76a1b0..a5e2de419b7a 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -59,4 +59,15 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, gfp_t gfp); +void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp); +void nl80211_send_remain_on_channel_cancel( + struct cfg80211_registered_device *rdev, struct net_device *netdev, + u64 cookie, struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, gfp_t gfp); + #endif /* __NET_WIRELESS_NL80211_H */ -- GitLab From b8bc4b0aa9bfba755c64b11b8f60e6cfab25dc9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:42 +0100 Subject: [PATCH 0278/3892] mac80211: support remain-on-channel command This implements the new remain-on-channel cfg80211 command in mac80211, extending the work interface. Also change the work purge code to be able to clean up events properly (pretending they timed out.) Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 24 +++++++ net/mac80211/ieee80211_i.h | 15 +++++ net/mac80211/main.c | 3 + net/mac80211/mlme.c | 3 + net/mac80211/offchannel.c | 8 ++- net/mac80211/work.c | 134 +++++++++++++++++++++++++++++++++++-- 6 files changed, 181 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ea862dfc08ed..2e5e841e9b7b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1441,6 +1441,28 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, return -EINVAL; } +static int ieee80211_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, + duration, cookie); +} + +static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1487,4 +1509,6 @@ struct cfg80211_ops mac80211_config_ops = { CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, .set_bitrate_mask = ieee80211_set_bitrate_mask, + .remain_on_channel = ieee80211_remain_on_channel, + .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fd912eb5309e..23547ebacf3d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -225,9 +225,11 @@ struct mesh_preq_queue { }; enum ieee80211_work_type { + IEEE80211_WORK_ABORT, IEEE80211_WORK_DIRECT_PROBE, IEEE80211_WORK_AUTH, IEEE80211_WORK_ASSOC, + IEEE80211_WORK_REMAIN_ON_CHANNEL, }; /** @@ -283,6 +285,9 @@ struct ieee80211_work { u8 supp_rates_len; bool wmm_used, use_11n; } assoc; + struct { + unsigned long timeout; + } remain; }; int ie_len; @@ -729,6 +734,10 @@ struct ieee80211_local { enum nl80211_channel_type oper_channel_type; struct ieee80211_channel *oper_channel, *csa_channel; + /* Temporary remain-on-channel for off-channel operations */ + struct ieee80211_channel *tmp_channel; + enum nl80211_channel_type tmp_channel_type; + /* SNMP counters */ /* dot11CountersTable */ u32 dot11TransmittedFragmentCount; @@ -1162,6 +1171,12 @@ void free_work(struct ieee80211_work *wk); void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie); +int ieee80211_wk_cancel_remain_on_channel( + struct ieee80211_sub_if_data *sdata, u64 cookie); #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5fcd3548417e..d0a14d953f08 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -107,6 +107,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) if (scan_chan) { chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; + } else if (local->tmp_channel) { + chan = scan_chan = local->tmp_channel; + channel_type = local->tmp_channel_type; } else { chan = local->oper_channel; channel_type = local->oper_channel_type; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e44f1ed0b0da..32d6e6614f9f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -857,6 +857,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (sdata->local->scanning) return; + if (sdata->local->tmp_channel) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 2cd880e444d1..a7bbfc40a648 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -106,9 +106,13 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) /* * only handle non-STA interfaces here, STA interfaces * are handled in ieee80211_offchannel_stop_station(), - * e.g., from the background scan state machine + * e.g., from the background scan state machine. + * + * In addition, do not stop monitor interface to allow it to be + * used from user space controlled off-channel operations. */ - if (sdata->vif.type != NL80211_IFTYPE_STATION) + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_MONITOR) netif_stop_queue(sdata->dev); } mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0b8c31c600aa..0acea7cf714a 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -538,6 +538,44 @@ ieee80211_associate(struct ieee80211_work *wk) return WORK_ACT_NONE; } +static enum work_action __must_check +ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) +{ + struct ieee80211_sub_if_data *sdata = wk->sdata; + struct ieee80211_local *local = sdata->local; + + /* + * First time we run, do nothing -- the generic code will + * have switched to the right channel etc. + */ + if (wk->timeout != wk->remain.timeout) { + wk->timeout = wk->remain.timeout; + return WORK_ACT_NONE; + } + + /* + * We are done serving the remain-on-channel command; kill the work + * item to allow idle state to be entered again. In addition, clear the + * temporary channel information to allow operational channel to be + * used. + */ + list_del(&wk->list); + free_work(wk); + + if (local->tmp_channel) { + cfg80211_remain_on_channel_expired(sdata->dev, (u64)wk, + local->tmp_channel, + local->tmp_channel_type, + GFP_KERNEL); + + local->tmp_channel = NULL; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + ieee80211_offchannel_return(local, true); + } + + return WORK_ACT_NONE; +} + static void ieee80211_auth_challenge(struct ieee80211_work *wk, struct ieee80211_mgmt *mgmt, size_t len) @@ -825,6 +863,8 @@ static void ieee80211_work_work(struct work_struct *work) /* nothing */ rma = WORK_ACT_NONE; break; + case IEEE80211_WORK_ABORT: + rma = WORK_ACT_TIMEOUT; case IEEE80211_WORK_DIRECT_PROBE: rma = ieee80211_direct_probe(wk); break; @@ -834,6 +874,9 @@ static void ieee80211_work_work(struct work_struct *work) case IEEE80211_WORK_ASSOC: rma = ieee80211_associate(wk); break; + case IEEE80211_WORK_REMAIN_ON_CHANNEL: + rma = ieee80211_remain_on_channel_timeout(wk); + break; } switch (rma) { @@ -900,14 +943,25 @@ void ieee80211_work_init(struct ieee80211_local *local) void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk, *tmp; + struct ieee80211_work *wk; mutex_lock(&local->work_mtx); - list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + list_for_each_entry(wk, &local->work_list, list) { if (wk->sdata != sdata) continue; - list_del(&wk->list); - free_work(wk); + wk->type = IEEE80211_WORK_ABORT; + } + mutex_unlock(&local->work_mtx); + + /* run cleanups etc. */ + ieee80211_work_work(&local->work_work); + + mutex_lock(&local->work_mtx); + list_for_each_entry(wk, &local->work_list, list) { + if (wk->sdata != sdata) + continue; + WARN_ON(1); + break; } mutex_unlock(&local->work_mtx); } @@ -949,3 +1003,75 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, return RX_CONTINUE; } + +int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_work *wk; + + wk = kzalloc(sizeof(*wk), GFP_KERNEL); + if (!wk) + return -ENOMEM; + + wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; + wk->chan = chan; + wk->sdata = sdata; + + wk->remain.timeout = jiffies + msecs_to_jiffies(duration); + + *cookie = (u64)wk; + + ieee80211_add_work(wk); + + /* + * TODO: could optimize this by leaving the station vifs in awake mode + * if they happen to be on the same channel as the requested channel + */ + ieee80211_offchannel_stop_beaconing(local); + ieee80211_offchannel_stop_station(local); + + sdata->local->tmp_channel = chan; + sdata->local->tmp_channel_type = channel_type; + ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); + + cfg80211_ready_on_channel(sdata->dev, (u64)wk, chan, channel_type, + duration, GFP_KERNEL); + + return 0; +} + +int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, + u64 cookie) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_work *wk, *tmp; + bool found = false; + + mutex_lock(&local->work_mtx); + list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + if ((u64)wk == cookie) { + found = true; + list_del(&wk->list); + free_work(wk); + break; + } + } + mutex_unlock(&local->work_mtx); + + if (!found) + return -ENOENT; + + if (sdata->local->tmp_channel) { + sdata->local->tmp_channel = NULL; + ieee80211_hw_config(sdata->local, + IEEE80211_CONF_CHANGE_CHANNEL); + ieee80211_offchannel_return(sdata->local, true); + } + + ieee80211_recalc_idle(local); + + return 0; +} -- GitLab From e4da8c37af626001ff704fb29ea14eb58f5f7208 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:43 +0100 Subject: [PATCH 0279/3892] mac80211: make off-channel work generic This changes mac80211 to allow being off-channel for any type of work, not just the 'remain-on-channel' work. This also helps fast transition to a BSS on a different channel. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 7 +- net/mac80211/mlme.c | 14 +--- net/mac80211/work.c | 135 ++++++++++++++++++++++--------------- 3 files changed, 88 insertions(+), 68 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 23547ebacf3d..a27921ee6e63 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -255,13 +255,15 @@ struct ieee80211_work { struct sk_buff *skb); struct ieee80211_channel *chan; - /* XXX: chan type? -- right now not really needed */ + enum nl80211_channel_type chan_type; unsigned long timeout; enum ieee80211_work_type type; u8 filter_ta[ETH_ALEN]; + bool started; + union { struct { int tries; @@ -286,7 +288,8 @@ struct ieee80211_work { bool wmm_used, use_11n; } assoc; struct { - unsigned long timeout; + u32 duration; + bool started; } remain; }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 32d6e6614f9f..72920ee07885 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1105,6 +1105,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, else ieee80211_set_wmm_default(sdata); + local->oper_channel = wk->chan; + if (elems.ht_info_elem && elems.wmm_param && (sdata->local->hw.queues >= 4) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) @@ -1797,15 +1799,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->sdata = sdata; wk->done = ieee80211_probe_auth_done; - /* - * XXX: if still associated need to tell AP that we're going - * to sleep and then change channel etc. - * For now switch channel here, later will be handled - * by submitting this as an off-channel work item. - */ - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - ieee80211_add_work(wk); return 0; } @@ -1929,9 +1922,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, else ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - ieee80211_add_work(wk); return 0; } diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0acea7cf714a..0bffb6a42534 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -541,39 +541,22 @@ ieee80211_associate(struct ieee80211_work *wk) static enum work_action __must_check ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) { - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - /* * First time we run, do nothing -- the generic code will * have switched to the right channel etc. */ - if (wk->timeout != wk->remain.timeout) { - wk->timeout = wk->remain.timeout; - return WORK_ACT_NONE; - } + if (!wk->remain.started) { + wk->remain.started = true; + wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); - /* - * We are done serving the remain-on-channel command; kill the work - * item to allow idle state to be entered again. In addition, clear the - * temporary channel information to allow operational channel to be - * used. - */ - list_del(&wk->list); - free_work(wk); + cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan, + wk->chan_type, wk->remain.duration, + GFP_KERNEL); - if (local->tmp_channel) { - cfg80211_remain_on_channel_expired(sdata->dev, (u64)wk, - local->tmp_channel, - local->tmp_channel_type, - GFP_KERNEL); - - local->tmp_channel = NULL; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - ieee80211_offchannel_return(local, true); + return WORK_ACT_NONE; } - return WORK_ACT_NONE; + return WORK_ACT_TIMEOUT; } static void ieee80211_auth_challenge(struct ieee80211_work *wk, @@ -799,7 +782,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, break; case WORK_DONE_REQUEUE: synchronize_rcu(); - wk->timeout = jiffies; /* run again directly */ + wk->started = false; /* restart */ mutex_lock(&local->work_mtx); list_add_tail(&wk->list, &local->work_list); mutex_unlock(&local->work_mtx); @@ -827,6 +810,7 @@ static void ieee80211_work_work(struct work_struct *work) struct ieee80211_work *wk, *tmp; LIST_HEAD(free_work); enum work_action rma; + bool remain_off_channel = false; if (local->scanning) return; @@ -847,6 +831,34 @@ static void ieee80211_work_work(struct work_struct *work) mutex_lock(&local->work_mtx); list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + /* mark work as started if it's on the current off-channel */ + if (!wk->started && local->tmp_channel && + wk->chan == local->tmp_channel && + wk->chan_type == local->tmp_channel_type) { + wk->started = true; + } + + if (!wk->started && !local->tmp_channel) { + /* + * TODO: could optimize this by leaving the + * station vifs in awake mode if they + * happen to be on the same channel as + * the requested channel + */ + ieee80211_offchannel_stop_beaconing(local); + ieee80211_offchannel_stop_station(local); + + local->tmp_channel = wk->chan; + local->tmp_channel_type = wk->chan_type; + ieee80211_hw_config(local, 0); + wk->started = true; + wk->timeout = jiffies; + } + + /* don't try to work with items that aren't started */ + if (!wk->started) + continue; + if (time_is_after_jiffies(wk->timeout)) { /* * This work item isn't supposed to be worked on @@ -881,7 +893,8 @@ static void ieee80211_work_work(struct work_struct *work) switch (rma) { case WORK_ACT_NONE: - /* no action required */ + /* might have changed the timeout */ + run_again(local, wk->timeout); break; case WORK_ACT_TIMEOUT: list_del_rcu(&wk->list); @@ -893,6 +906,24 @@ static void ieee80211_work_work(struct work_struct *work) } } + list_for_each_entry(wk, &local->work_list, list) { + if (!wk->started) + continue; + if (wk->chan != local->tmp_channel) + continue; + if (wk->chan_type != local->tmp_channel_type) + continue; + remain_off_channel = true; + } + + if (!remain_off_channel && local->tmp_channel) { + local->tmp_channel = NULL; + ieee80211_hw_config(local, 0); + ieee80211_offchannel_return(local, true); + /* give connection some time to breathe */ + run_again(local, jiffies + HZ/2); + } + if (list_empty(&local->work_list) && local->scan_req) ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -900,6 +931,8 @@ static void ieee80211_work_work(struct work_struct *work) mutex_unlock(&local->work_mtx); + ieee80211_recalc_idle(local); + list_for_each_entry_safe(wk, tmp, &free_work, list) { wk->done(wk, NULL); list_del(&wk->list); @@ -920,7 +953,7 @@ void ieee80211_add_work(struct ieee80211_work *wk) if (WARN_ON(!wk->done)) return; - wk->timeout = jiffies; + wk->started = false; local = wk->sdata->local; mutex_lock(&local->work_mtx); @@ -950,6 +983,8 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) if (wk->sdata != sdata) continue; wk->type = IEEE80211_WORK_ABORT; + wk->started = true; + wk->timeout = jiffies; } mutex_unlock(&local->work_mtx); @@ -1004,12 +1039,24 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, return RX_CONTINUE; } +static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, + struct sk_buff *skb) +{ + /* + * We are done serving the remain-on-channel command. + */ + cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk, + wk->chan, wk->chan_type, + GFP_KERNEL); + + return WORK_DONE_DESTROY; +} + int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ieee80211_local *local = sdata->local; struct ieee80211_work *wk; wk = kzalloc(sizeof(*wk), GFP_KERNEL); @@ -1018,28 +1065,16 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; wk->chan = chan; + wk->chan_type = channel_type; wk->sdata = sdata; + wk->done = ieee80211_remain_done; - wk->remain.timeout = jiffies + msecs_to_jiffies(duration); + wk->remain.duration = duration; *cookie = (u64)wk; ieee80211_add_work(wk); - /* - * TODO: could optimize this by leaving the station vifs in awake mode - * if they happen to be on the same channel as the requested channel - */ - ieee80211_offchannel_stop_beaconing(local); - ieee80211_offchannel_stop_station(local); - - sdata->local->tmp_channel = chan; - sdata->local->tmp_channel_type = channel_type; - ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); - - cfg80211_ready_on_channel(sdata->dev, (u64)wk, chan, channel_type, - duration, GFP_KERNEL); - return 0; } @@ -1053,9 +1088,8 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->work_mtx); list_for_each_entry_safe(wk, tmp, &local->work_list, list) { if ((u64)wk == cookie) { + wk->timeout = jiffies; found = true; - list_del(&wk->list); - free_work(wk); break; } } @@ -1064,14 +1098,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, if (!found) return -ENOENT; - if (sdata->local->tmp_channel) { - sdata->local->tmp_channel = NULL; - ieee80211_hw_config(sdata->local, - IEEE80211_CONF_CHANGE_CHANNEL); - ieee80211_offchannel_return(sdata->local, true); - } - - ieee80211_recalc_idle(local); + ieee80211_queue_work(&local->hw, &local->work_work); return 0; } -- GitLab From 98b6218388e345064c3f2d3c161383a18274c638 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:44 +0100 Subject: [PATCH 0280/3892] mac80211/cfg80211: add station events When, for instance, a new IBSS peer is found, userspace wants to be notified. Add events for all new stations that mac80211 learns about. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 12 ++++++++++++ net/mac80211/sta_info.c | 5 +++++ net/wireless/mlme.c | 10 ++++++++++ net/wireless/nl80211.c | 21 ++++++++++++++++++++- net/wireless/nl80211.h | 4 ++++ 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b66beb052054..add79930f47d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2195,4 +2195,16 @@ void cfg80211_remain_on_channel_expired(struct net_device *dev, enum nl80211_channel_type channel_type, gfp_t gfp); + +/** + * cfg80211_new_sta - notify userspace about station + * + * @dev: the netdev + * @mac_addr: the station's address + * @sinfo: the station information + * @gfp: allocation flags + */ +void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); + #endif /* __NET_CFG80211_H */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f039e761aec1..47da552ce8a6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -359,6 +359,7 @@ int sta_info_insert(struct sta_info *sta) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; + struct station_info sinfo; unsigned long flags; int err = 0; @@ -408,6 +409,10 @@ int sta_info_insert(struct sta_info *sta) spin_unlock_irqrestore(&local->sta_lock, flags); + sinfo.filled = 0; + sinfo.generation = local->sta_generation; + cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC); + #ifdef CONFIG_MAC80211_DEBUGFS /* * Debugfs entry adding might sleep, so schedule process diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 11f6469b3f98..3dba19e17271 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -707,3 +707,13 @@ void cfg80211_remain_on_channel_expired(struct net_device *dev, channel_type, gfp); } EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); + +void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); +} +EXPORT_SYMBOL(cfg80211_new_sta); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ff857f10cb85..e3bee3cecdfa 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1642,7 +1642,7 @@ static int parse_station_flags(struct genl_info *info, static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, - u8 *mac_addr, struct station_info *sinfo) + const u8 *mac_addr, struct station_info *sinfo) { void *hdr; struct nlattr *sinfoattr, *txrate; @@ -5350,6 +5350,25 @@ void nl80211_send_remain_on_channel_cancel( channel_type, 0, gfp); } +void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); +} + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index a5e2de419b7a..14855b8fb430 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -70,4 +70,8 @@ void nl80211_send_remain_on_channel_cancel( u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp); +void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); + #endif /* __NET_WIRELESS_NL80211_H */ -- GitLab From 1ed32e4fc8cfc9656cc1101e7f9617d485fcbe7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:45 +0100 Subject: [PATCH 0281/3892] mac80211: remove struct ieee80211_if_init_conf All its members (vif, mac_addr, type) are now available in the vif struct directly, so we can pass that instead of the conf struct. I generated this patch (except the mac80211 and header file changes) with this semantic patch: @@ identifier conf, fn, hw; type tp; @@ tp fn(struct ieee80211_hw *hw, -struct ieee80211_if_init_conf *conf) +struct ieee80211_vif *vif) { <... ( -conf->type +vif->type | -conf->mac_addr +vif->addr | -conf->vif +vif ) ...> } Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 12 ++--- drivers/net/wireless/at76c50x-usb.c | 6 +-- drivers/net/wireless/ath/ar9170/main.c | 8 +-- drivers/net/wireless/ath/ath5k/base.c | 18 +++---- drivers/net/wireless/ath/ath9k/main.c | 28 +++++------ drivers/net/wireless/b43/main.c | 26 +++++----- drivers/net/wireless/b43legacy/main.c | 24 ++++----- drivers/net/wireless/iwlwifi/iwl-core.c | 20 ++++---- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +- drivers/net/wireless/libertas_tf/main.c | 10 ++-- drivers/net/wireless/mac80211_hwsim.c | 18 +++---- drivers/net/wireless/mwl8k.c | 14 +++--- drivers/net/wireless/p54/main.c | 12 ++--- drivers/net/wireless/rt2x00/rt2x00.h | 4 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 26 +++++----- drivers/net/wireless/rtl818x/rtl8180_dev.c | 12 ++--- drivers/net/wireless/rtl818x/rtl8187_dev.c | 10 ++-- drivers/net/wireless/wl12xx/wl1251_main.c | 14 +++--- drivers/net/wireless/wl12xx/wl1271_main.c | 10 ++-- drivers/net/wireless/zd1211rw/zd_mac.c | 10 ++-- include/net/mac80211.h | 57 ++++++---------------- net/mac80211/driver-ops.h | 12 ++--- net/mac80211/iface.c | 14 ++---- net/mac80211/pm.c | 6 +-- net/mac80211/util.c | 9 +--- 25 files changed, 170 insertions(+), 214 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 39410016b4ff..e1f04bb437e3 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1400,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, } static int adm8211_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct adm8211_priv *priv = dev->priv; if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: - priv->mode = conf->type; + priv->mode = vif->type; break; default: return -EOPNOTSUPP; @@ -1416,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, ADM8211_IDLE(); - ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); - ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); + ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr)); + ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4))); adm8211_update_mode(dev); @@ -1427,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, } static void adm8211_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct adm8211_priv *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 2517364d3ebe..0fb419936dff 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) } static int at76_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct at76_priv *priv = hw->priv; int ret = 0; @@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mtx); - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: priv->iw_mode = IW_MODE_INFRA; break; @@ -1814,7 +1814,7 @@ exit: } static void at76_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { at76_dbg(DBG_MAC80211, "%s()", __func__); } diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 20f04ab2b13e..4d27f7f67c76 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1939,7 +1939,7 @@ err_free: } static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ar9170 *ar = hw->priv; struct ath_common *common = &ar->common; @@ -1952,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, goto unlock; } - ar->vif = conf->vif; - memcpy(common->macaddr, conf->mac_addr, ETH_ALEN); + ar->vif = vif; + memcpy(common->macaddr, vif->addr, ETH_ALEN); if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { ar->rx_software_decryption = true; @@ -1973,7 +1973,7 @@ unlock: } static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ar9170 *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a4c086f069b1..20c7e5b450aa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list); @@ -2785,7 +2785,7 @@ static void ath5k_stop(struct ieee80211_hw *hw) } static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ath5k_softc *sc = hw->priv; int ret; @@ -2796,22 +2796,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, goto end; } - sc->vif = conf->vif; + sc->vif = vif; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: - sc->opmode = conf->type; + sc->opmode = vif->type; break; default: ret = -EOPNOTSUPP; goto end; } - ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); + ath5k_hw_set_lladdr(sc->ah, vif->addr); ath5k_mode_setup(sc); ret = 0; @@ -2822,13 +2822,13 @@ end: static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ath5k_softc *sc = hw->priv; u8 mac[ETH_ALEN] = {}; mutex_lock(&sc->lock); - if (sc->vif != conf->vif) + if (sc->vif != vif) goto end; ath5k_hw_set_lladdr(sc->ah, mac); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3f5b887d0fcd..446bd23756e5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2534,12 +2534,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) } static int ath9k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)conf->vif->drv_priv; + struct ath_vif *avp = (void *)vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; int ret = 0; @@ -2551,7 +2551,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, goto out; } - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: ic_opmode = NL80211_IFTYPE_STATION; break; @@ -2562,11 +2562,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ret = -ENOBUFS; goto out; } - ic_opmode = conf->type; + ic_opmode = vif->type; break; default: ath_print(common, ATH_DBG_FATAL, - "Interface type %d not yet supported\n", conf->type); + "Interface type %d not yet supported\n", vif->type); ret = -EOPNOTSUPP; goto out; } @@ -2598,18 +2598,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. */ - if ((conf->type == NL80211_IFTYPE_STATION) || - (conf->type == NL80211_IFTYPE_ADHOC) || - (conf->type == NL80211_IFTYPE_MESH_POINT)) { + if ((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { sc->imask |= ATH9K_INT_MIB; sc->imask |= ATH9K_INT_TSFOOR; } ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (conf->type == NL80211_IFTYPE_AP || - conf->type == NL80211_IFTYPE_ADHOC || - conf->type == NL80211_IFTYPE_MONITOR) + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MONITOR) ath_start_ani(common); out: @@ -2618,12 +2618,12 @@ out: } static void ath9k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)conf->vif->drv_priv; + struct ath_vif *avp = (void *)vif->drv_priv; int i; ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); @@ -2644,7 +2644,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_BEACONS; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - if (sc->beacon.bslot[i] == conf->vif) { + if (sc->beacon.bslot[i] == vif) { printk(KERN_DEBUG "%s: vif had allocated beacon " "slot\n", __func__); sc->beacon.bslot[i] = NULL; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b0b5ce950008..6634a77fc766 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4391,7 +4391,7 @@ err_busdown: } static int b43_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -4399,24 +4399,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != NL80211_IFTYPE_AP && - conf->type != NL80211_IFTYPE_MESH_POINT && - conf->type != NL80211_IFTYPE_STATION && - conf->type != NL80211_IFTYPE_WDS && - conf->type != NL80211_IFTYPE_ADHOC) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_MESH_POINT && + vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_WDS && + vif->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); if (wl->operating) goto out_mutex_unlock; - b43dbg(wl, "Adding Interface type %d\n", conf->type); + b43dbg(wl, "Adding Interface type %d\n", vif->type); dev = wl->current_dev; wl->operating = 1; - wl->vif = conf->vif; - wl->if_type = conf->type; - memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + wl->vif = vif; + wl->if_type = vif->type; + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); b43_adjust_opmode(dev); b43_set_pretbtt(dev); @@ -4431,17 +4431,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, } static void b43_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43dbg(wl, "Removing Interface type %d\n", conf->type); + b43dbg(wl, "Removing Interface type %d\n", vif->type); mutex_lock(&wl->mutex); B43_WARN_ON(!wl->operating); - B43_WARN_ON(wl->vif != conf->vif); + B43_WARN_ON(wl->vif != vif); wl->vif = NULL; wl->operating = 0; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ab6a18c2e9d9..494017e4fcc9 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3361,7 +3361,7 @@ err_kfree_lo_control: } static int b43legacy_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -3370,23 +3370,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != NL80211_IFTYPE_AP && - conf->type != NL80211_IFTYPE_STATION && - conf->type != NL80211_IFTYPE_WDS && - conf->type != NL80211_IFTYPE_ADHOC) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_WDS && + vif->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); if (wl->operating) goto out_mutex_unlock; - b43legacydbg(wl, "Adding Interface type %d\n", conf->type); + b43legacydbg(wl, "Adding Interface type %d\n", vif->type); dev = wl->current_dev; wl->operating = 1; - wl->vif = conf->vif; - wl->if_type = conf->type; - memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + wl->vif = vif; + wl->if_type = vif->type; + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); spin_lock_irqsave(&wl->irq_lock, flags); b43legacy_adjust_opmode(dev); @@ -3403,18 +3403,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, } static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; - b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + b43legacydbg(wl, "Removing Interface type %d\n", vif->type); mutex_lock(&wl->mutex); B43legacy_WARN_ON(!wl->operating); - B43legacy_WARN_ON(wl->vif != conf->vif); + B43legacy_WARN_ON(wl->vif != vif); wl->vif = NULL; wl->operating = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e3b96b48b7fe..14f482960d7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2584,12 +2584,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) EXPORT_SYMBOL(iwl_set_mode); int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; unsigned long flags; - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); + IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type); if (priv->vif) { IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); @@ -2597,19 +2597,19 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, } spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - priv->iw_mode = conf->type; + priv->vif = vif; + priv->iw_mode = vif->type; spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); - if (conf->mac_addr) { - IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + if (vif->addr) { + IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr); + memcpy(priv->mac_addr, vif->addr, ETH_ALEN); } - if (iwl_set_mode(priv, conf->type) == -EAGAIN) + if (iwl_set_mode(priv, vif->type) == -EAGAIN) /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); @@ -2621,7 +2621,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, EXPORT_SYMBOL(iwl_mac_add_interface); void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; @@ -2634,7 +2634,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); } - if (priv->vif == conf->vif) { + if (priv->vif == vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f7acbb32900a..1728f961dcba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -332,9 +332,9 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); int iwl_commit_rxon(struct iwl_priv *priv); int iwl_set_mode(struct iwl_priv *priv, int mode); int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 019431d2f8a9..15a367680f59 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw) } static int lbtf_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct lbtf_private *priv = hw->priv; if (priv->vif != NULL) return -EOPNOTSUPP; - priv->vif = conf->vif; - switch (conf->type) { + priv->vif = vif; + switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: lbtf_set_mode(priv, LBTF_AP_MODE); @@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw, priv->vif = NULL; return -EOPNOTSUPP; } - lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); + lbtf_set_mac_address(priv, (u8 *) vif->addr); return 0; } static void lbtf_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct lbtf_private *priv = hw->priv; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4dee69a38c1d..84df3fcf37b3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -584,24 +584,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", - wiphy_name(hw->wiphy), __func__, conf->type, - conf->mac_addr); - hwsim_set_magic(conf->vif); + wiphy_name(hw->wiphy), __func__, vif->type, + vif->addr); + hwsim_set_magic(vif); return 0; } static void mac80211_hwsim_remove_interface( - struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) + struct ieee80211_hw *hw, struct ieee80211_vif *vif) { printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", - wiphy_name(hw->wiphy), __func__, conf->type, - conf->mac_addr); - hwsim_check_magic(conf->vif); - hwsim_clear_magic(conf->vif); + wiphy_name(hw->wiphy), __func__, vif->type, + vif->addr); + hwsim_check_magic(vif); + hwsim_clear_magic(vif); } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 97a95decf9a8..c1c6ecd0c5b3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2835,7 +2835,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) } static int mwl8k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif; @@ -2849,7 +2849,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* * We only support managed interfaces for now. */ - if (conf->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION) return -EINVAL; /* @@ -2865,24 +2865,24 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, } /* Clean out driver private area */ - mwl8k_vif = MWL8K_VIF(conf->vif); + mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); /* Set and save the mac address */ - mwl8k_cmd_set_mac_addr(hw, conf->mac_addr); - memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); + mwl8k_cmd_set_mac_addr(hw, vif->addr); + memcpy(mwl8k_vif->mac_addr, vif->addr, ETH_ALEN); /* Set Initial sequence number to zero */ mwl8k_vif->seqno = 0; - priv->vif = conf->vif; + priv->vif = vif; priv->current_channel = NULL; return 0; } static void mwl8k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct mwl8k_priv *priv = hw->priv; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 18012dbfb45d..26428e4c9c60 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -216,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev) } static int p54_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct p54_common *priv = dev->priv; @@ -226,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } - priv->vif = conf->vif; + priv->vif = vif; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - priv->mode = conf->type; + priv->mode = vif->type; break; default: mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + memcpy(priv->mac_addr, vif->addr, ETH_ALEN); p54_setup_mac(priv); mutex_unlock(&priv->conf_mutex); return 0; } static void p54_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a664a999b2b0..b4c6e0a6d7e0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1019,9 +1019,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int rt2x00mac_start(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw); int rt2x00mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index de549c244ed8..00f1f939f1bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) EXPORT_SYMBOL_GPL(rt2x00mac_stop); int rt2x00mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(conf->vif); + struct rt2x00_intf *intf = vif_to_intf(vif); struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); struct queue_entry *entry = NULL; unsigned int i; @@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_AP: /* * We don't support mixed combinations of @@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * increase interface count and start initialization. */ - if (conf->type == NL80211_IFTYPE_AP) + if (vif->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; @@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; - if (conf->type == NL80211_IFTYPE_AP) - memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); - memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); + if (vif->type == NL80211_IFTYPE_AP) + memcpy(&intf->bssid, vif->addr, ETH_ALEN); + memcpy(&intf->mac, vif->addr, ETH_ALEN); /* * The MAC adddress must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. */ - rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL); + rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL); /* * Some filters depend on the current working mode. We can force @@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(conf->vif); + struct rt2x00_intf *intf = vif_to_intf(vif); /* * Don't allow interfaces to be remove while @@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * no interface is present. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || - (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) + (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || + (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) return; - if (conf->type == NL80211_IFTYPE_AP) + if (vif->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count--; else rt2x00dev->intf_sta_count--; diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index f01f1ef9e3be..5a2b7199f5d5 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -652,7 +652,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev) } static int rtl8180_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rtl8180_priv *priv = dev->priv; @@ -662,27 +662,27 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, if (priv->vif) return -EBUSY; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: break; default: return -EOPNOTSUPP; } - priv->vif = conf->vif; + priv->vif = vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], - le32_to_cpu(*(__le32 *)conf->mac_addr)); + le32_to_cpu(*(__le32 *)vif->addr)); rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], - le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); + le16_to_cpu(*(__le16 *)(vif->addr + 4))); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; } static void rtl8180_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rtl8180_priv *priv = dev->priv; priv->vif = NULL; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 1cb0eff46223..f336c63053c1 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1018,7 +1018,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) } static int rtl8187_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rtl8187_priv *priv = dev->priv; int i; @@ -1028,7 +1028,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, if (priv->vif) goto exit; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: break; default: @@ -1036,12 +1036,12 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, } ret = 0; - priv->vif = conf->vif; + priv->vif = vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->MAC[i], - ((u8 *)conf->mac_addr)[i]); + ((u8 *)vif->addr)[i]); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); exit: @@ -1050,7 +1050,7 @@ exit: } static void rtl8187_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct rtl8187_priv *priv = dev->priv; mutex_lock(&priv->conf_mutex); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 6aeffbe9e401..4e373f3dbc43 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -511,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) } static int wl1251_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct wl1251 *wl = hw->priv; int ret = 0; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - conf->type, conf->mac_addr); + vif->type, vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -525,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, goto out; } - wl->vif = conf->vif; + wl->vif = vif; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; break; @@ -539,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, goto out; } - if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { - memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { + memcpy(wl->mac_addr, vif->addr, ETH_ALEN); SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); ret = wl1251_acx_station_id(wl); if (ret < 0) @@ -553,7 +553,7 @@ out: } static void wl1251_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct wl1251 *wl = hw->priv; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 4a997381a8d0..e4867b895c43 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1039,13 +1039,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) } static int wl1271_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; int ret = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - conf->type, conf->mac_addr); + vif->type, vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -1053,9 +1053,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - wl->vif = conf->vif; + wl->vif = vif; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; break; @@ -1075,7 +1075,7 @@ out: } static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 8a243732c519..c4f41d0016c5 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -872,7 +872,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } static int zd_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct zd_mac *mac = zd_hw_mac(hw); @@ -880,22 +880,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, if (mac->type != NL80211_IFTYPE_UNSPECIFIED) return -EOPNOTSUPP; - switch (conf->type) { + switch (vif->type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - mac->type = conf->type; + mac->type = vif->type; break; default: return -EOPNOTSUPP; } - return zd_write_mac_addr(&mac->chip, conf->mac_addr); + return zd_write_mac_addr(&mac->chip, vif->addr); } static void zd_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { struct zd_mac *mac = zd_hw_mac(hw); mac->type = NL80211_IFTYPE_UNSPECIFIED; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 77ea34b03285..08d41357dcbe 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -701,33 +701,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) return false; } -/** - * struct ieee80211_if_init_conf - initial configuration of an interface - * - * @vif: pointer to a driver-use per-interface structure. The pointer - * itself is also used for various functions including - * ieee80211_beacon_get() and ieee80211_get_buffered_bc(). - * @type: one of &enum nl80211_iftype constants. Determines the type of - * added/removed interface. - * @mac_addr: pointer to MAC address of the interface. This pointer is valid - * until the interface is removed (i.e. it cannot be used after - * remove_interface() callback was called for this interface). - * - * This structure is used in add_interface() and remove_interface() - * callbacks of &struct ieee80211_hw. - * - * When you allow multiple interfaces to be added to your PHY, take care - * that the hardware can actually handle multiple MAC addresses. However, - * also take care that when there's no interface left with mac_addr != %NULL - * you remove the MAC address from the device to avoid acknowledging packets - * in pure monitor mode. - */ -struct ieee80211_if_init_conf { - enum nl80211_iftype type; - struct ieee80211_vif *vif; - void *mac_addr; -}; - /** * enum ieee80211_key_alg - key algorithm * @ALG_WEP: WEP40 or WEP104 @@ -1555,9 +1528,9 @@ struct ieee80211_ops { int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); int (*add_interface)(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); void (*remove_interface)(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); + struct ieee80211_vif *vif); int (*config)(struct ieee80211_hw *hw, u32 changed); void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1845,7 +1818,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, /** * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @tim_offset: pointer to variable that will receive the TIM IE offset. * Set to 0 if invalid (in non-AP modes). * @tim_length: pointer to variable that will receive the TIM IE length, @@ -1873,7 +1846,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, /** * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * See ieee80211_beacon_get_tim(). */ @@ -1886,7 +1859,7 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_info of the frame. @@ -1905,7 +1878,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /** * ieee80211_rts_duration - Get the duration field for an RTS frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @frame_len: the length of the frame that is going to be protected by the RTS. * @frame_txctl: &struct ieee80211_tx_info of the frame. * @@ -1920,7 +1893,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_get - CTS-to-self frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_info of the frame. @@ -1940,7 +1913,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. * @frame_txctl: &struct ieee80211_tx_info of the frame. * @@ -1956,7 +1929,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @frame_len: the length of the frame. * @rate: the rate at which the frame is going to be transmitted. * @@ -1971,7 +1944,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, /** * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * Function for accessing buffered broadcast and multicast frames. If * hardware/firmware does not implement buffering of broadcast/multicast @@ -2139,7 +2112,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); /** * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf + * @vif: &struct ieee80211_vif pointer from the add_interface callback * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2150,7 +2123,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); /** * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf + * @vif: &struct ieee80211_vif pointer from the add_interface callback * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2178,7 +2151,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, /** * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf + * @vif: &struct ieee80211_vif pointer from the add_interface callback * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2189,7 +2162,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); /** * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf + * @vif: &struct ieee80211_vif pointer from the add_interface callback * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2268,7 +2241,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, /** * ieee80211_beacon_loss - inform hardware does not receive beacons * - * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and * IEEE80211_CONF_PS is set, the driver needs to inform whenever the diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index cbe133bcdf34..bc7c8f55487a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -36,18 +36,18 @@ static inline void drv_stop(struct ieee80211_local *local) } static inline int drv_add_interface(struct ieee80211_local *local, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { - int ret = local->ops->add_interface(&local->hw, conf); - trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret); + int ret = local->ops->add_interface(&local->hw, vif); + trace_drv_add_interface(local, vif_to_sdata(vif), ret); return ret; } static inline void drv_remove_interface(struct ieee80211_local *local, - struct ieee80211_if_init_conf *conf) + struct ieee80211_vif *vif) { - local->ops->remove_interface(&local->hw, conf); - trace_drv_remove_interface(local, vif_to_sdata(conf->vif)); + local->ops->remove_interface(&local->hw, vif); + trace_drv_remove_interface(local, vif_to_sdata(vif)); } static inline int drv_config(struct ieee80211_local *local, u32 changed) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7d410f15281a..00a1f4ccdaf1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -96,7 +96,6 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_sub_if_data *nsdata; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - struct ieee80211_if_init_conf conf; u32 changed = 0; int res; u32 hw_reconf_flags = 0; @@ -248,10 +247,7 @@ static int ieee80211_open(struct net_device *dev) ieee80211_configure_filter(local); break; default: - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->vif.addr; - res = drv_add_interface(local, &conf); + res = drv_add_interface(local, &sdata->vif); if (res) goto err_stop; @@ -334,7 +330,7 @@ static int ieee80211_open(struct net_device *dev) return 0; err_del_interface: - drv_remove_interface(local, &conf); + drv_remove_interface(local, &sdata->vif); err_stop: if (!local->open_count) drv_stop(local); @@ -349,7 +345,6 @@ static int ieee80211_stop(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - struct ieee80211_if_init_conf conf; struct sta_info *sta; unsigned long flags; struct sk_buff *skb, *tmp; @@ -533,12 +528,9 @@ static int ieee80211_stop(struct net_device *dev) BSS_CHANGED_BEACON_ENABLED); } - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->vif.addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); - drv_remove_interface(local, &conf); + drv_remove_interface(local, &sdata->vif); } sdata->bss = NULL; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 913dc7e3b29e..47f818959ad7 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -10,7 +10,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_init_conf conf; struct sta_info *sta; unsigned long flags; @@ -100,10 +99,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->vif.addr; - drv_remove_interface(local, &conf); + drv_remove_interface(local, &sdata->vif); } /* stop hardware - this must stop RX */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1fdb80ff9241..4b930308b1fb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1075,7 +1075,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_init_conf conf; struct sta_info *sta; unsigned long flags; int res; @@ -1094,12 +1093,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_MONITOR && - ieee80211_sdata_running(sdata)) { - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->vif.addr; - res = drv_add_interface(local, &conf); - } + ieee80211_sdata_running(sdata)) + res = drv_add_interface(local, &sdata->vif); } /* add STAs back */ -- GitLab From 095d5ef608b58ece49f4131925700d27314ecdd8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:46 +0100 Subject: [PATCH 0282/3892] mac80211: remove requeue from work There's no need to be requeueing the work struct since we check for the scan after removing items due to possible timeouts. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/work.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0bffb6a42534..ea89ed70734d 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -435,12 +435,6 @@ ieee80211_direct_probe(struct ieee80211_work *wk) */ ieee80211_remove_auth_bss(local, wk); - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &local->work_work); return WORK_ACT_TIMEOUT; } @@ -478,12 +472,6 @@ ieee80211_authenticate(struct ieee80211_work *wk) */ ieee80211_remove_auth_bss(local, wk); - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &local->work_work); return WORK_ACT_TIMEOUT; } @@ -519,12 +507,6 @@ ieee80211_associate(struct ieee80211_work *wk) if (wk->assoc.bss) cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); - /* - * We might have a pending scan which had no chance to run yet - * due to work needing to be done. Hence, queue the STAs work - * again for that. - */ - ieee80211_queue_work(&local->hw, &local->work_work); return WORK_ACT_TIMEOUT; } -- GitLab From e1781ed33a8809c58ad6c3b6d432d656446efa43 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 23 Dec 2009 13:15:47 +0100 Subject: [PATCH 0283/3892] mac80211: annotate sleeping driver ops To make it easier to notice cases of calling sleeping ops in atomic context, annotate driver-ops.h with appropiate might_sleep() calls. At the same time, also document in mac80211.h the op functions with missing contexts. mac80211 doesn't seem to use get_tx_stats anywhere currently. Just to be on the safe side, I documented it to be atomic, but hopefully the op can be removed in the future. Compile-tested only. Signed-off-by: Kalle Valo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 43 ++++++++++++++++++++-------- net/mac80211/driver-ops.h | 60 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 08d41357dcbe..5ee666ae4c88 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1383,7 +1383,7 @@ enum ieee80211_ampdu_mlme_action { * When the device is started it should not have a MAC address * to avoid acknowledging frames before a non-monitor device * is added. - * Must be implemented. + * Must be implemented and can sleep. * * @stop: Called after last netdevice attached to the hardware * is disabled. This should turn off the hardware (at least @@ -1391,7 +1391,7 @@ enum ieee80211_ampdu_mlme_action { * May be called right after add_interface if that rejects * an interface. If you added any work onto the mac80211 workqueue * you should ensure to cancel it on this callback. - * Must be implemented. + * Must be implemented and can sleep. * * @add_interface: Called when a netdevice attached to the hardware is * enabled. Because it is not called for monitor mode devices, @start @@ -1401,7 +1401,7 @@ enum ieee80211_ampdu_mlme_action { * interface is given in the conf parameter. * The callback may refuse to add an interface by returning a * negative error code (which will be seen in userspace.) - * Must be implemented. + * Must be implemented and can sleep. * * @remove_interface: Notifies a driver that an interface is going down. * The @stop callback is called after this if it is the last interface @@ -1410,19 +1410,20 @@ enum ieee80211_ampdu_mlme_action { * must be cleared so the device no longer acknowledges packets, * the mac_addr member of the conf structure is, however, set to the * MAC address of the device going away. - * Hence, this callback must be implemented. + * Hence, this callback must be implemented. It can sleep. * * @config: Handler for configuration requests. IEEE 802.11 code calls this * function to change hardware configuration, e.g., channel. * This function should never fail but returns a negative error code - * if it does. + * if it does. The callback can sleep. * * @bss_info_changed: Handler for configuration requests related to BSS * parameters that may vary during BSS's lifespan, and may affect low * level driver (e.g. assoc/disassoc status, erp parameters). * This function should not be used if no BSS has been set, unless * for association indication. The @changed parameter indicates which - * of the bss parameters has changed when a call is made. + * of the bss parameters has changed when a call is made. The callback + * can sleep. * * @prepare_multicast: Prepare for multicast filter configuration. * This callback is optional, and its return value is passed @@ -1430,20 +1431,22 @@ enum ieee80211_ampdu_mlme_action { * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. - * This callback must be implemented. + * This callback must be implemented and can sleep. * * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit * must be set or cleared for a given STA. Must be atomic. * * @set_key: See the section "Hardware crypto acceleration" - * This callback can sleep, and is only called between add_interface - * and remove_interface calls, i.e. while the given virtual interface + * This callback is only called between add_interface and + * remove_interface calls, i.e. while the given virtual interface * is enabled. * Returns a negative error code if the key can't be added. + * The callback can sleep. * * @update_tkip_key: See the section "Hardware crypto acceleration" * This callback will be called in the context of Rx. Called for drivers * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. + * The callback can sleep. * * @hw_scan: Ask the hardware to service the scan request, no need to start * the scan state machine in stack. The scan must honour the channel @@ -1457,21 +1460,28 @@ enum ieee80211_ampdu_mlme_action { * When the scan finishes, ieee80211_scan_completed() must be called; * note that it also must be called when the scan cannot finish due to * any error unless this callback returned a negative error code. + * The callback can sleep. * * @sw_scan_start: Notifier function that is called just before a software scan * is started. Can be NULL, if the driver doesn't need this notification. + * The callback can sleep. * - * @sw_scan_complete: Notifier function that is called just after a software scan - * finished. Can be NULL, if the driver doesn't need this notification. + * @sw_scan_complete: Notifier function that is called just after a + * software scan finished. Can be NULL, if the driver doesn't need + * this notification. + * The callback can sleep. * * @get_stats: Return low-level statistics. * Returns zero if statistics are available. + * The callback can sleep. * * @get_tkip_seq: If your device implements TKIP encryption in hardware this * callback should be provided to read the TKIP transmit IVs (both IV32 * and IV16) for the given key from hardware. + * The callback must be atomic. * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) + * The callback can sleep. * * @sta_notify: Notifies low level driver about addition, removal or power * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. @@ -1480,30 +1490,36 @@ enum ieee80211_ampdu_mlme_action { * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. * Returns a negative error code on failure. + * The callback can sleep. * * @get_tx_stats: Get statistics of the current TX queue status. This is used * to get number of currently queued packets (queue length), maximum queue * size (limit), and total number of packets sent using each TX queue * (count). The 'stats' pointer points to an array that has hw->queues * items. + * The callback must be atomic. * * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, * this is only used for IBSS mode BSSID merging and debugging. Is not a * required function. + * The callback can sleep. * * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware. * Currently, this is only used for IBSS mode debugging. Is not a * required function. + * The callback can sleep. * * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize * with other STAs in the IBSS. This is only used in IBSS mode. This * function is optional if the firmware/hardware takes full care of * TSF synchronization. + * The callback can sleep. * * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. * This is needed only for IBSS mode and the result of this function is * used to determine whether to reply to Probe Requests. * Returns non-zero if this device sent the last beacon. + * The callback can sleep. * * @ampdu_action: Perform a certain A-MPDU action * The RA/TID combination determines the destination and TID we want @@ -1512,16 +1528,19 @@ enum ieee80211_ampdu_mlme_action { * is the first frame we expect to perform the action on. Notice * that TX/RX_STOP can pass NULL for this parameter. * Returns a negative error code on failure. + * The callback must be atomic. * * @rfkill_poll: Poll rfkill hardware state. If you need this, you also * need to set wiphy->rfkill_poll to %true before registration, * and need to call wiphy_rfkill_set_hw_state() in the callback. + * The callback can sleep. * * @testmode_cmd: Implement a cfg80211 test mode command. + * The callback can sleep. * * @flush: Flush all pending frames from the hardware queue, making sure * that the hardware queues are empty. If the parameter @drop is set - * to %true, pending frames may be dropped. + * to %true, pending frames may be dropped. The callback can sleep. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index bc7c8f55487a..8757ea73d544 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local) { int ret; + might_sleep(); + local->started = true; smp_mb(); ret = local->ops->start(&local->hw); @@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local) static inline void drv_stop(struct ieee80211_local *local) { + might_sleep(); + local->ops->stop(&local->hw); trace_drv_stop(local); @@ -38,7 +42,11 @@ static inline void drv_stop(struct ieee80211_local *local) static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_vif *vif) { - int ret = local->ops->add_interface(&local->hw, vif); + int ret; + + might_sleep(); + + ret = local->ops->add_interface(&local->hw, vif); trace_drv_add_interface(local, vif_to_sdata(vif), ret); return ret; } @@ -46,13 +54,19 @@ static inline int drv_add_interface(struct ieee80211_local *local, static inline void drv_remove_interface(struct ieee80211_local *local, struct ieee80211_vif *vif) { + might_sleep(); + local->ops->remove_interface(&local->hw, vif); trace_drv_remove_interface(local, vif_to_sdata(vif)); } static inline int drv_config(struct ieee80211_local *local, u32 changed) { - int ret = local->ops->config(&local->hw, changed); + int ret; + + might_sleep(); + + ret = local->ops->config(&local->hw, changed); trace_drv_config(local, changed, ret); return ret; } @@ -62,6 +76,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, struct ieee80211_bss_conf *info, u32 changed) { + might_sleep(); + if (local->ops->bss_info_changed) local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); trace_drv_bss_info_changed(local, sdata, info, changed); @@ -111,7 +127,11 @@ static inline int drv_set_key(struct ieee80211_local *local, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); + int ret; + + might_sleep(); + + ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); trace_drv_set_key(local, cmd, sdata, sta, key, ret); return ret; } @@ -121,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, const u8 *address, u32 iv32, u16 *phase1key) { + might_sleep(); + if (local->ops->update_tkip_key) local->ops->update_tkip_key(&local->hw, conf, address, iv32, phase1key); @@ -130,13 +152,19 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, static inline int drv_hw_scan(struct ieee80211_local *local, struct cfg80211_scan_request *req) { - int ret = local->ops->hw_scan(&local->hw, req); + int ret; + + might_sleep(); + + ret = local->ops->hw_scan(&local->hw, req); trace_drv_hw_scan(local, req, ret); return ret; } static inline void drv_sw_scan_start(struct ieee80211_local *local) { + might_sleep(); + if (local->ops->sw_scan_start) local->ops->sw_scan_start(&local->hw); trace_drv_sw_scan_start(local); @@ -144,6 +172,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local) static inline void drv_sw_scan_complete(struct ieee80211_local *local) { + might_sleep(); + if (local->ops->sw_scan_complete) local->ops->sw_scan_complete(&local->hw); trace_drv_sw_scan_complete(local); @@ -154,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local, { int ret = -EOPNOTSUPP; + might_sleep(); + if (local->ops->get_stats) ret = local->ops->get_stats(&local->hw, stats); trace_drv_get_stats(local, stats, ret); @@ -173,6 +205,9 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, u32 value) { int ret = 0; + + might_sleep(); + if (local->ops->set_rts_threshold) ret = local->ops->set_rts_threshold(&local->hw, value); trace_drv_set_rts_threshold(local, value, ret); @@ -193,6 +228,9 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, const struct ieee80211_tx_queue_params *params) { int ret = -EOPNOTSUPP; + + might_sleep(); + if (local->ops->conf_tx) ret = local->ops->conf_tx(&local->hw, queue, params); trace_drv_conf_tx(local, queue, params, ret); @@ -210,6 +248,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local, static inline u64 drv_get_tsf(struct ieee80211_local *local) { u64 ret = -1ULL; + + might_sleep(); + if (local->ops->get_tsf) ret = local->ops->get_tsf(&local->hw); trace_drv_get_tsf(local, ret); @@ -218,6 +259,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local) static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) { + might_sleep(); + if (local->ops->set_tsf) local->ops->set_tsf(&local->hw, tsf); trace_drv_set_tsf(local, tsf); @@ -225,6 +268,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) static inline void drv_reset_tsf(struct ieee80211_local *local) { + might_sleep(); + if (local->ops->reset_tsf) local->ops->reset_tsf(&local->hw); trace_drv_reset_tsf(local); @@ -233,6 +278,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local) static inline int drv_tx_last_beacon(struct ieee80211_local *local) { int ret = 1; + + might_sleep(); + if (local->ops->tx_last_beacon) ret = local->ops->tx_last_beacon(&local->hw); trace_drv_tx_last_beacon(local, ret); @@ -256,12 +304,16 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, static inline void drv_rfkill_poll(struct ieee80211_local *local) { + might_sleep(); + if (local->ops->rfkill_poll) local->ops->rfkill_poll(&local->hw); } static inline void drv_flush(struct ieee80211_local *local, bool drop) { + might_sleep(); + trace_drv_flush(local, drop); if (local->ops->flush) local->ops->flush(&local->hw, drop); -- GitLab From 557b0bbd62389ab438424e9f895197607666ea4d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:01:46 -0800 Subject: [PATCH 0284/3892] drivers/net/lib82596.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. The only difference in the output is that the MAC address is shown in the usual colon-separated hex notation instead of space-separated. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/lib82596.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index b117f7f8b194..b60efd4bd017 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1094,11 +1094,9 @@ static int __devinit i82596_probe(struct net_device *dev) return i; }; - DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,", - dev->name, dev->base_addr)); - for (i = 0; i < 6; i++) - DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i])); - DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq)); + DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n", + dev->name, dev->base_addr, dev->dev_addr, + dev->irq)); DEB(DEB_INIT, printk(KERN_INFO "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n", dev->name, dma, (int)sizeof(struct i596_dma), -- GitLab From 753cdc3304f0612766a81cddab9d8af01fcf8218 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:02:29 -0800 Subject: [PATCH 0285/3892] drivers/net/igbvf/netdev.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/igbvf/netdev.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index e9dd95f136aa..1326232c1d32 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2608,11 +2608,7 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter) struct pci_dev *pdev = adapter->pdev; dev_info(&pdev->dev, "Intel(R) 82576 Virtual Function\n"); - dev_info(&pdev->dev, "Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - /* MAC address */ - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr); dev_info(&pdev->dev, "MAC: %d\n", hw->mac.type); } @@ -2777,11 +2773,8 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { - dev_err(&pdev->dev, "Invalid MAC Address: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + dev_err(&pdev->dev, "Invalid MAC Address: %pM\n", + netdev->dev_addr); err = -EIO; goto err_hw_init; } -- GitLab From d649a2844e49ece6309cf28cb941ef64eb69228f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:03:28 -0800 Subject: [PATCH 0286/3892] drivers/net/usb/rtl8150.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/usb/rtl8150.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index f14d225404da..dfc7e9fec3ea 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -313,20 +313,17 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p) { struct sockaddr *addr = p; rtl8150_t *dev = netdev_priv(netdev); - int i; if (netif_running(netdev)) return -EBUSY; memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - dbg("%s: Setting MAC address to ", netdev->name); - for (i = 0; i < 5; i++) - dbg("%02X:", netdev->dev_addr[i]); - dbg("%02X\n", netdev->dev_addr[i]); + dbg("%s: Setting MAC address to %pM\n", netdev->name, netdev->dev_addr); /* Set the IDR registers. */ set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr); #ifdef EEPROM_WRITE { + int i; u8 cr; /* Get the CR contents. */ get_registers(dev, CR, 1, &cr); -- GitLab From aa7c68a5f75cf04e79348e8baca67c7393d8f7e4 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:04:14 -0800 Subject: [PATCH 0287/3892] drivers/net/via-velocity.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4ceb441f2687..cee8fa2d2a9f 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2702,10 +2702,8 @@ static void __devinit velocity_print_info(struct velocity_info *vptr) struct net_device *dev = vptr->dev; printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); - printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: Ethernet Address: %pM\n", + dev->name, dev->dev_addr); } static u32 velocity_get_link(struct net_device *dev) -- GitLab From 5491f3a5623129f3d4e0c62e691c2a5e56c75d41 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:04:53 -0800 Subject: [PATCH 0288/3892] drivers/net/xilinx_emaclite.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/xilinx_emaclite.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 8c777ba4e2b3..f7fe1aa03b42 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -925,11 +925,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev, /* Set the MAC address in the EmacLite device */ xemaclite_set_mac_address(lp, ndev->dev_addr); - dev_info(dev, - "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n", - ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], - ndev->dev_addr[4], ndev->dev_addr[5]); + dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr); ndev->netdev_ops = &xemaclite_netdev_ops; ndev->flags &= ~IFF_MULTICAST; -- GitLab From d998ab0bd737fad9c8e3c88eb6f52c43e90fda9a Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:05:37 -0800 Subject: [PATCH 0289/3892] drivers/s390/net/qeth_l2_main.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 0b763396d5d1..038299ae3feb 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -486,22 +486,14 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, case IPA_RC_L2_DUP_MAC: case IPA_RC_L2_DUP_LAYER3_MAC: dev_warn(&card->gdev->dev, - "MAC address " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "already exists\n", - card->dev->dev_addr[0], card->dev->dev_addr[1], - card->dev->dev_addr[2], card->dev->dev_addr[3], - card->dev->dev_addr[4], card->dev->dev_addr[5]); + "MAC address %pM already exists\n", + card->dev->dev_addr); break; case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: dev_warn(&card->gdev->dev, - "MAC address " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "is not authorized\n", - card->dev->dev_addr[0], card->dev->dev_addr[1], - card->dev->dev_addr[2], card->dev->dev_addr[3], - card->dev->dev_addr[4], card->dev->dev_addr[5]); + "MAC address %pM is not authorized\n", + card->dev->dev_addr); break; default: break; @@ -512,12 +504,8 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, OSA_ADDR_LEN); dev_info(&card->gdev->dev, - "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "successfully registered on device %s\n", - card->dev->dev_addr[0], card->dev->dev_addr[1], - card->dev->dev_addr[2], card->dev->dev_addr[3], - card->dev->dev_addr[4], card->dev->dev_addr[5], - card->dev->name); + "MAC address %pM successfully registered on device %s\n", + card->dev->dev_addr, card->dev->name); } return 0; } -- GitLab From 3b8dff3622a813d093a8601dc90fb6f12183f87c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:06:45 -0800 Subject: [PATCH 0290/3892] drivers/net/usb/catc.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/usb/catc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 22b87e64a810..7d3fa06980c1 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -897,11 +897,9 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id f5u011_rxmode(catc, catc->rxmode); } dbg("Init done."); - printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ", + printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, %pM.\n", netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", - usbdev->bus->bus_name, usbdev->devpath); - for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); - printk("%2.2x.\n", netdev->dev_addr[i]); + usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr); usb_set_intfdata(intf, catc); SET_NETDEV_DEV(netdev, &intf->dev); -- GitLab From b18fe4777f1cf7095fbe78652b72c076e300eaee Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:07:27 -0800 Subject: [PATCH 0291/3892] drivers/net/sunvnet.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/sunvnet.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index bc74db0d12f3..d65764ea1d83 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1062,10 +1062,7 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac) goto err_out_free_dev; } - printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: Sun LDOM vnet %pM\n", dev->name, dev->dev_addr); list_add(&vp->list, &vnet_list); -- GitLab From fa876b474aa15cd1448790502a5a13f81f923446 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:08:09 -0800 Subject: [PATCH 0292/3892] drivers/net/smc911x.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/smc911x.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 44ebbaa7457b..3c5a4f52345c 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -2017,10 +2017,8 @@ static int __devinit smc911x_probe(struct net_device *dev) "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ - printk("%s: Ethernet addr: ", dev->name); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[5]); + printk("%s: Ethernet addr: %pM\n", + dev->name, dev->dev_addr); } if (lp->phy_type == 0) { -- GitLab From e583482091d207265953f501564056bd2c90b985 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:09:07 -0800 Subject: [PATCH 0293/3892] drivers/net/octeon/octeon_mgmt.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/octeon/octeon_mgmt.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c index 050538bf155a..6fd8789ef487 100644 --- a/drivers/net/octeon/octeon_mgmt.c +++ b/drivers/net/octeon/octeon_mgmt.c @@ -1119,11 +1119,8 @@ static int __init octeon_mgmt_probe(struct platform_device *pdev) if (p->port >= octeon_bootinfo->mac_addr_count) dev_err(&pdev->dev, - "Error %s: Using MAC outside of the assigned range: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name, - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + "Error %s: Using MAC outside of the assigned range: %pM\n", + netdev->name, netdev->dev_addr); if (register_netdev(netdev)) goto err; -- GitLab From 30a6ae8d477dc90254eb785d8ccff6dfe7d9082e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:10:01 -0800 Subject: [PATCH 0294/3892] drivers/net/r8169.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/r8169.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 60f96c468a24..c403ce0a3d3a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3188,15 +3188,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (netif_msg_probe(tp)) { u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff; - printk(KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "XID %08x IRQ %d\n", + printk(KERN_INFO "%s: %s at 0x%lx, %pM, XID %08x IRQ %d\n", dev->name, rtl_chip_info[tp->chipset].name, - dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq); + dev->base_addr, dev->dev_addr, xid, dev->irq); } rtl8169_init_phy(dev, tp); -- GitLab From 6cd9b49d7328c4656bfc17fcb47fb814955d40d2 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 29 Dec 2009 20:10:35 -0800 Subject: [PATCH 0295/3892] Subject: drivers/net/sh_eth.c: use %pM to shown MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/net/sh_eth.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index ca6285016dfd..ed52c0063a65 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1473,13 +1473,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev) if (ret) goto out_unregister; - /* pritnt device infomation */ - pr_info("Base address at 0x%x, ", - (u32)ndev->base_addr); - - for (i = 0; i < 5; i++) - printk("%02X:", ndev->dev_addr[i]); - printk("%02X, IRQ %d.\n", ndev->dev_addr[i], ndev->irq); + /* print device infomation */ + pr_info("Base address at 0x%x, %pM, IRQ %d.\n", + (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); platform_set_drvdata(pdev, ndev); -- GitLab From b45d44e7e00c1726dac9437b66c05d3d27acb3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C3=A9veill=C3=A9?= Date: Tue, 29 Dec 2009 20:39:05 -0800 Subject: [PATCH 0296/3892] Input: xpad - allow using triggers as buttons rather than axes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Certain devices implement triggers as buttons rather than axes. In particular, arcade sticks such as the HORI Real Arcade Pro.EX do not have analog buttons. These devices are now setup to present buttons rather than axes for triggers. User-space applications often also have problems with axes-as-buttons. Activating MAP_TRIGGERS_TO_BUTTONS for a device removes the artificial difference between buttons and triggers. Signed-off-by: Nicolas Léveillé Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 200 ++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 79 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 482cb1204e43..5483fb9bd819 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -86,9 +86,8 @@ /* xbox d-pads should map to buttons, as is required for DDR pads but we map them to axes when possible to simplify things */ -#define MAP_DPAD_TO_BUTTONS 0 -#define MAP_DPAD_TO_AXES 1 -#define MAP_DPAD_UNKNOWN 2 +#define MAP_DPAD_TO_BUTTONS (1 << 0) +#define MAP_TRIGGERS_TO_BUTTONS (1 << 1) #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 @@ -99,57 +98,61 @@ static int dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); +static int triggers_to_buttons; +module_param(triggers_to_buttons, bool, S_IRUGO); +MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads"); + static const struct xpad_device { u16 idVendor; u16 idProduct; char *name; - u8 dpad_mapping; + u8 mapping; u8 xtype; } xpad_device[] = { - { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, + { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, + { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, + { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, - { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, + { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, + { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, + { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, + { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, + { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX }, + { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX }, + { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, + { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX }, { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, - { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, + { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, - { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, + { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, + { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, + { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, + { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX }, + { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX }, + { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, + { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, + { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, + { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, + { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, + { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, + { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, - { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, + { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, - { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } + { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, + { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; /* buttons shared with xbox and xbox360 */ @@ -165,13 +168,20 @@ static const signed short xpad_btn[] = { -1 /* terminating entry */ }; -/* only used if MAP_DPAD_TO_BUTTONS */ +/* used when dpad is mapped to nuttons */ static const signed short xpad_btn_pad[] = { BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ BTN_0, BTN_1, /* d-pad up, down (XXX names??) */ -1 /* terminating entry */ }; +/* used when triggers are mapped to buttons */ +static const signed short xpad_btn_triggers[] = { + BTN_TL2, BTN_TR2, /* triggers left/right */ + -1 +}; + + static const signed short xpad360_btn[] = { /* buttons for x360 controller */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X button */ @@ -181,16 +191,21 @@ static const signed short xpad360_btn[] = { /* buttons for x360 controller */ static const signed short xpad_abs[] = { ABS_X, ABS_Y, /* left stick */ ABS_RX, ABS_RY, /* right stick */ - ABS_Z, ABS_RZ, /* triggers left/right */ -1 /* terminating entry */ }; -/* only used if MAP_DPAD_TO_AXES */ +/* used when dpad is mapped to axes */ static const signed short xpad_abs_pad[] = { ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ -1 /* terminating entry */ }; +/* used when triggers are mapped to axes */ +static const signed short xpad_abs_triggers[] = { + ABS_Z, ABS_RZ, /* triggers left/right */ + -1 +}; + /* Xbox 360 has a vendor-specific class, so we cannot match it with only * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we * match against vendor id as well. Wired Xbox 360 devices have protocol 1, @@ -246,7 +261,7 @@ struct usb_xpad { char phys[64]; /* physical device path */ - int dpad_mapping; /* map d-pad to buttons or to axes */ + int mapping; /* map d-pad to buttons or to axes */ int xtype; /* type of xbox device */ }; @@ -277,20 +292,25 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d ~(__s16) le16_to_cpup((__le16 *)(data + 18))); /* triggers left/right */ - input_report_abs(dev, ABS_Z, data[10]); - input_report_abs(dev, ABS_RZ, data[11]); + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + input_report_key(dev, BTN_TL2, data[10]); + input_report_key(dev, BTN_TR2, data[11]); + } else { + input_report_abs(dev, ABS_Z, data[10]); + input_report_abs(dev, ABS_RZ, data[11]); + } /* digital pad */ - if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { - input_report_abs(dev, ABS_HAT0X, - !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, - !!(data[2] & 0x02) - !!(data[2] & 0x01)); - } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { input_report_key(dev, BTN_LEFT, data[2] & 0x04); input_report_key(dev, BTN_RIGHT, data[2] & 0x08); input_report_key(dev, BTN_0, data[2] & 0x01); /* up */ input_report_key(dev, BTN_1, data[2] & 0x02); /* down */ + } else { + input_report_abs(dev, ABS_HAT0X, + !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[2] & 0x02) - !!(data[2] & 0x01)); } /* start/back buttons and stick press left/right */ @@ -328,17 +348,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev = xpad->dev; /* digital pad */ - if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { - input_report_abs(dev, ABS_HAT0X, - !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, - !!(data[2] & 0x02) - !!(data[2] & 0x01)); - } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) { + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (right, left, down, up) */ input_report_key(dev, BTN_LEFT, data[2] & 0x04); input_report_key(dev, BTN_RIGHT, data[2] & 0x08); input_report_key(dev, BTN_0, data[2] & 0x01); /* up */ input_report_key(dev, BTN_1, data[2] & 0x02); /* down */ + } else { + input_report_abs(dev, ABS_HAT0X, + !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[2] & 0x02) - !!(data[2] & 0x01)); } /* start/back buttons */ @@ -371,8 +391,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad, ~(__s16) le16_to_cpup((__le16 *)(data + 12))); /* triggers left/right */ - input_report_abs(dev, ABS_Z, data[4]); - input_report_abs(dev, ABS_RZ, data[5]); + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + input_report_key(dev, BTN_TL2, data[4]); + input_report_key(dev, BTN_TR2, data[5]); + } else { + input_report_abs(dev, ABS_Z, data[4]); + input_report_abs(dev, ABS_RZ, data[5]); + } input_sync(dev); } @@ -712,11 +737,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); break; case ABS_Z: - case ABS_RZ: /* the triggers */ + case ABS_RZ: /* the triggers (if mapped to axes) */ input_set_abs_params(input_dev, abs, 0, 255, 0, 0); break; case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */ + case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */ input_set_abs_params(input_dev, abs, -1, 1, 0, 0); break; } @@ -752,10 +777,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail2; xpad->udev = udev; - xpad->dpad_mapping = xpad_device[i].dpad_mapping; + xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; - if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) - xpad->dpad_mapping = !dpad_to_buttons; + if (xpad->xtype == XTYPE_UNKNOWN) { if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) @@ -764,7 +788,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->xtype = XTYPE_XBOX360; } else xpad->xtype = XTYPE_XBOX; + + if (dpad_to_buttons) + xpad->mapping |= MAP_DPAD_TO_BUTTONS; + if (triggers_to_buttons) + xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS; } + xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -781,25 +811,37 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - /* set up buttons */ + /* set up standard buttons and axes */ for (i = 0; xpad_common_btn[i] >= 0; i++) - set_bit(xpad_common_btn[i], input_dev->keybit); - if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W)) - for (i = 0; xpad360_btn[i] >= 0; i++) - set_bit(xpad360_btn[i], input_dev->keybit); - else - for (i = 0; xpad_btn[i] >= 0; i++) - set_bit(xpad_btn[i], input_dev->keybit); - if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) - for (i = 0; xpad_btn_pad[i] >= 0; i++) - set_bit(xpad_btn_pad[i], input_dev->keybit); + __set_bit(xpad_common_btn[i], input_dev->keybit); - /* set up axes */ for (i = 0; xpad_abs[i] >= 0; i++) xpad_set_up_abs(input_dev, xpad_abs[i]); - if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) + + /* Now set up model-specific ones */ + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) { + for (i = 0; xpad360_btn[i] >= 0; i++) + __set_bit(xpad360_btn[i], input_dev->keybit); + } else { + for (i = 0; xpad_btn[i] >= 0; i++) + __set_bit(xpad_btn[i], input_dev->keybit); + } + + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { + for (i = 0; xpad_btn_pad[i] >= 0; i++) + __set_bit(xpad_btn_pad[i], input_dev->keybit); + } else { for (i = 0; xpad_abs_pad[i] >= 0; i++) xpad_set_up_abs(input_dev, xpad_abs_pad[i]); + } + + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + for (i = 0; xpad_btn_triggers[i] >= 0; i++) + __set_bit(xpad_btn_triggers[i], input_dev->keybit); + } else { + for (i = 0; xpad_abs_triggers[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); + } error = xpad_init_output(intf, xpad); if (error) -- GitLab From 499a5f1efa0b0ac56ec5d060412aed84ae68e63e Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 18 Dec 2009 16:05:51 +0000 Subject: [PATCH 0297/3892] x86: Lift restriction on the location of FIX_BTMAP_* The early ioremap fixmap entries cover half (or for 32-bit non-PAE, a quarter) of a page table, yet they got uncondtitionally aligned so far to a 256-entry boundary. This is not necessary if the range of page table entries anyway falls into a single page table. This buys back, for (theoretically) 50% of all configurations (25% of all non-PAE ones), at least some of the lowmem necessarily lost with commit e621bd18958ef5dbace3129ebe17a0a475e127d9. Signed-off-by: Jan Beulich Cc: Linus Torvalds Cc: Andrew Morton LKML-Reference: <4B2BB66F0200007800026AD6@vpn.id2.novell.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/fixmap.h | 16 +++++++++++----- arch/x86/mm/ioremap.c | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 14f9890eb495..635f03bb4995 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -118,14 +118,20 @@ enum fixed_addresses { * 256 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * We round it up to the next 256 pages boundary so that we - * can have a single pgd entry and a single pte table: + * If necessary we round it up to the next 256 pages boundary so + * that we can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 #define FIX_BTMAPS_SLOTS 4 - FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - - (__end_of_permanent_fixed_addresses & 255), - FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1, +#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) + FIX_BTMAP_END = + (__end_of_permanent_fixed_addresses ^ + (__end_of_permanent_fixed_addresses + TOTAL_FIX_BTMAPS - 1)) & + -PTRS_PER_PTE + ? __end_of_permanent_fixed_addresses + TOTAL_FIX_BTMAPS - + (__end_of_permanent_fixed_addresses & (TOTAL_FIX_BTMAPS - 1)) + : __end_of_permanent_fixed_addresses, + FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT FIX_OHCI1394_BASE, #endif diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index c246d259822d..03c75ffd5c2a 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -422,6 +422,10 @@ void __init early_ioremap_init(void) * The boot-ioremap range spans multiple pmds, for which * we are not prepared: */ +#define __FIXADDR_TOP (-PAGE_SIZE) + BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) + != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); +#undef __FIXADDR_TOP if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) { WARN_ON(1); printk(KERN_WARNING "pmd %p != %p\n", -- GitLab From 1b1d9258181bae199dc940f4bd0298126b9a73d9 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 18 Dec 2009 16:12:56 +0000 Subject: [PATCH 0298/3892] x86-64: Modify copy_user_generic() alternatives mechanism In order to avoid unnecessary chains of branches, rather than implementing copy_user_generic() as a function consisting of just a single (possibly patched) branch, instead properly deal with patching call instructions in the alternative instructions framework, and move the patching into the callers. As a follow-on, one could also introduce something like __EXPORT_SYMBOL_ALT() to avoid patching call sites in modules. Signed-off-by: Jan Beulich Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton LKML-Reference: <4B2BB8180200007800026AE7@vpn.id2.novell.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/alternative.h | 7 ++++++- arch/x86/include/asm/uaccess_64.h | 21 ++++++++++++++++++++- arch/x86/kernel/alternative.c | 4 +++- arch/x86/kernel/x8664_ksyms_64.c | 3 ++- arch/x86/lib/copy_user_64.S | 6 ------ 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 69b74a7b877f..3b5b828767b6 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -125,11 +125,16 @@ static inline void alternatives_smp_switch(int smp) {} asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ : output : "i" (0), ## input) +/* Like alternative_io, but for replacing a direct call with another one. */ +#define alternative_call(oldfunc, newfunc, feature, output, input...) \ + asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \ + : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) + /* * use this macro(s) if you need more than one output parameter * in alternative_io */ -#define ASM_OUTPUT2(a, b) a, b +#define ASM_OUTPUT2(a...) a struct paravirt_patch_site; #ifdef CONFIG_PARAVIRT diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 46324c6a4f6e..a78c40305447 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include /* @@ -16,7 +18,24 @@ /* Handles exceptions in both to and from, but doesn't do access_ok */ __must_check unsigned long -copy_user_generic(void *to, const void *from, unsigned len); +copy_user_generic_string(void *to, const void *from, unsigned len); +__must_check unsigned long +copy_user_generic_unrolled(void *to, const void *from, unsigned len); + +static __always_inline __must_check unsigned long +copy_user_generic(void *to, const void *from, unsigned len) +{ + unsigned ret; + + alternative_call(copy_user_generic_unrolled, + copy_user_generic_string, + X86_FEATURE_REP_GOOD, + ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), + "=d" (len)), + "1" (to), "2" (from), "3" (len) + : "memory", "rcx", "r8", "r9", "r10", "r11"); + return ret; +} __must_check unsigned long _copy_to_user(void __user *to, const void *from, unsigned len); diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index de7353c0ce9c..2589ea4c60ce 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -205,7 +205,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; - char insnbuf[MAX_PATCH_LEN]; + u8 insnbuf[MAX_PATCH_LEN]; DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); for (a = start; a < end; a++) { @@ -223,6 +223,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start, } #endif memcpy(insnbuf, a->replacement, a->replacementlen); + if (*insnbuf == 0xe8 && a->replacementlen == 5) + *(s32 *)(insnbuf + 1) += a->replacement - a->instr; add_nops(insnbuf + a->replacementlen, a->instrlen - a->replacementlen); text_poke_early(instr, insnbuf, a->instrlen); diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index 619f7f88b8cc..693920b22496 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c @@ -26,7 +26,8 @@ EXPORT_SYMBOL(__put_user_2); EXPORT_SYMBOL(__put_user_4); EXPORT_SYMBOL(__put_user_8); -EXPORT_SYMBOL(copy_user_generic); +EXPORT_SYMBOL(copy_user_generic_string); +EXPORT_SYMBOL(copy_user_generic_unrolled); EXPORT_SYMBOL(__copy_user_nocache); EXPORT_SYMBOL(_copy_from_user); EXPORT_SYMBOL(_copy_to_user); diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index cf889d4e076a..71100c98e337 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -90,12 +90,6 @@ ENTRY(_copy_from_user) CFI_ENDPROC ENDPROC(_copy_from_user) -ENTRY(copy_user_generic) - CFI_STARTPROC - ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string - CFI_ENDPROC -ENDPROC(copy_user_generic) - .section .fixup,"ax" /* must zero dest */ ENTRY(bad_from_user) -- GitLab From 7269e8812a59f74fb1ce134465d0bcf5683b93a1 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 18 Dec 2009 16:16:03 +0000 Subject: [PATCH 0299/3892] x86-64: Modify memcpy()/memset() alternatives mechanism In order to avoid unnecessary chains of branches, rather than implementing memcpy()/memset()'s access to their alternative implementations via a jump, patch the (larger) original function directly. The memcpy() part of this is slightly subtle: while alternative instruction patching does itself use memcpy(), with the replacement block being less than 64-bytes in size the main loop of the original function doesn't get used for copying memcpy_c() over memcpy(), and hence we can safely write over its beginning. Also note that the CFI annotations are fine for both variants of each of the functions. Signed-off-by: Jan Beulich Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton LKML-Reference: <4B2BB8D30200007800026AF2@vpn.id2.novell.com> Signed-off-by: Ingo Molnar --- arch/x86/lib/memcpy_64.S | 23 ++++++++--------------- arch/x86/lib/memset_64.S | 18 ++++++------------ 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index ad5441ed1b57..f82e884928af 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -20,12 +20,11 @@ /* * memcpy_c() - fast string ops (REP MOVSQ) based variant. * - * Calls to this get patched into the kernel image via the + * This gets patched over the unrolled variant (below) via the * alternative instructions framework: */ - ALIGN -memcpy_c: - CFI_STARTPROC + .section .altinstr_replacement, "ax", @progbits +.Lmemcpy_c: movq %rdi, %rax movl %edx, %ecx @@ -35,8 +34,8 @@ memcpy_c: movl %edx, %ecx rep movsb ret - CFI_ENDPROC -ENDPROC(memcpy_c) +.Lmemcpy_e: + .previous ENTRY(__memcpy) ENTRY(memcpy) @@ -128,16 +127,10 @@ ENDPROC(__memcpy) * It is also a lot simpler. Use this when possible: */ - .section .altinstr_replacement, "ax" -1: .byte 0xeb /* jmp */ - .byte (memcpy_c - memcpy) - (2f - 1b) /* offset */ -2: - .previous - .section .altinstructions, "a" .align 8 .quad memcpy - .quad 1b + .quad .Lmemcpy_c .byte X86_FEATURE_REP_GOOD /* @@ -145,6 +138,6 @@ ENDPROC(__memcpy) * so it is silly to overwrite itself with nops - reboot is the * only outcome... */ - .byte 2b - 1b - .byte 2b - 1b + .byte .Lmemcpy_e - .Lmemcpy_c + .byte .Lmemcpy_e - .Lmemcpy_c .previous diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 2c5948116bd2..e88d3b81644a 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -12,9 +12,8 @@ * * rax original destination */ - ALIGN -memset_c: - CFI_STARTPROC + .section .altinstr_replacement, "ax", @progbits +.Lmemset_c: movq %rdi,%r9 movl %edx,%r8d andl $7,%r8d @@ -29,8 +28,8 @@ memset_c: rep stosb movq %r9,%rax ret - CFI_ENDPROC -ENDPROC(memset_c) +.Lmemset_e: + .previous ENTRY(memset) ENTRY(__memset) @@ -118,16 +117,11 @@ ENDPROC(__memset) #include - .section .altinstr_replacement,"ax" -1: .byte 0xeb /* jmp */ - .byte (memset_c - memset) - (2f - 1b) /* offset */ -2: - .previous .section .altinstructions,"a" .align 8 .quad memset - .quad 1b + .quad .Lmemset_c .byte X86_FEATURE_REP_GOOD .byte .Lfinal - memset - .byte 2b - 1b + .byte .Lmemset_e - .Lmemset_c .previous -- GitLab From 41bdcb23dab22bf27361c5f2d89fe895d8904915 Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Tue, 29 Dec 2009 16:37:07 +0800 Subject: [PATCH 0300/3892] perf tools: Unify event type description make event type description to a unified array and the array index consistent to perf_type_id. Signed-off-by: Liming Wang Cc: Frederic Weisbecker Cc: Masami Hiramatsu Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1262075829-16257-1-git-send-email-liming.wang@windriver.com> Signed-off-by: Ingo Molnar --- tools/perf/util/parse-events.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index e5bc0fb016b2..dc585a835cab 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -835,11 +835,12 @@ int parse_filter(const struct option *opt __used, const char *str, } static const char * const event_type_descriptors[] = { - "", "Hardware event", "Software event", "Tracepoint event", "Hardware cache event", + "Raw hardware event descriptor", + "Hardware breakpoint", }; /* @@ -872,7 +873,7 @@ static void print_tracepoint_events(void) snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); printf(" %-42s [%s]\n", evt_path, - event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); + event_type_descriptors[PERF_TYPE_TRACEPOINT]); } closedir(evt_dir); } @@ -892,9 +893,7 @@ void print_events(void) printf("List of pre-defined events (to be used in -e):\n"); for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { - type = syms->type + 1; - if (type >= ARRAY_SIZE(event_type_descriptors)) - type = 0; + type = syms->type; if (type != prev_type) printf("\n"); @@ -919,17 +918,19 @@ void print_events(void) for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { printf(" %-42s [%s]\n", event_cache_name(type, op, i), - event_type_descriptors[4]); + event_type_descriptors[PERF_TYPE_HW_CACHE]); } } } printf("\n"); - printf(" %-42s [raw hardware event descriptor]\n", - "rNNN"); + printf(" %-42s [%s]\n", + "rNNN", event_type_descriptors[PERF_TYPE_RAW]); printf("\n"); - printf(" %-42s [hardware breakpoint]\n", "mem:[:access]"); + printf(" %-42s [%s]\n", + "mem:[:access]", + event_type_descriptors[PERF_TYPE_BREAKPOINT]); printf("\n"); print_tracepoint_events(); -- GitLab From 63bbd5e2d539c9290b229c832f62d42aac23db94 Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Tue, 29 Dec 2009 16:37:09 +0800 Subject: [PATCH 0301/3892] perf probe: Change CONFIG_KPROBE_TRACER to CONFIG_KPROBE_EVENT make the config name consistent Signed-off-by: Liming Wang Acked-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1262075829-16257-3-git-send-email-liming.wang@windriver.com> Signed-off-by: Ingo Molnar --- tools/perf/util/probe-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 29465d440043..8e532d9824f0 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -368,7 +368,7 @@ static int open_kprobe_events(int flags, int mode) if (ret < 0) { if (errno == ENOENT) die("kprobe_events file does not exist -" - " please rebuild with CONFIG_KPROBE_TRACER."); + " please rebuild with CONFIG_KPROBE_EVENT."); else die("Could not open kprobe_events file: %s", strerror(errno)); -- GitLab From 769885f372300a7fcfb9e54e4e2990718d40b529 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Dec 2009 22:48:32 -0200 Subject: [PATCH 0302/3892] perf header: Do_read shouldn't die MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate the errors instead, its callers already propagate other errors. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262047716-23171-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index df237c3a041b..6b3cb94e8a2b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -432,19 +432,19 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) return 0; } -static void do_read(int fd, void *buf, size_t size) +static int do_read(int fd, void *buf, size_t size) { while (size) { int ret = read(fd, buf, size); - if (ret < 0) - die("failed to read"); - if (ret == 0) - die("failed to read: missing data"); + if (ret <= 0) + return -1; size -= ret; buf += ret; } + + return 0; } int perf_header__process_sections(struct perf_header *self, int fd, @@ -455,7 +455,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, int nr_sections; int sec_size; int idx = 0; - int err = 0, feat = 1; + int err = -1, feat = 1; nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); if (!nr_sections) @@ -469,8 +469,10 @@ int perf_header__process_sections(struct perf_header *self, int fd, lseek(fd, self->data_offset + self->data_size, SEEK_SET); - do_read(fd, feat_sec, sec_size); + if (do_read(fd, feat_sec, sec_size)) + goto out_free; + err = 0; while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { if (perf_header__has_feat(self, feat)) { struct perf_file_section *sec = &feat_sec[idx++]; @@ -481,18 +483,18 @@ int perf_header__process_sections(struct perf_header *self, int fd, } ++feat; } - +out_free: free(feat_sec); return err; -}; +} int perf_file_header__read(struct perf_file_header *self, struct perf_header *ph, int fd) { lseek(fd, 0, SEEK_SET); - do_read(fd, self, sizeof(*self)); - if (self->magic != PERF_MAGIC || + if (do_read(fd, self, sizeof(*self)) || + self->magic != PERF_MAGIC || self->attr_size != sizeof(struct perf_file_attr)) return -1; @@ -558,7 +560,8 @@ int perf_header__read(struct perf_header *self, int fd) struct perf_header_attr *attr; off_t tmp; - do_read(fd, &f_attr, sizeof(f_attr)); + if (do_read(fd, &f_attr, sizeof(f_attr))) + goto out_errno; tmp = lseek(fd, 0, SEEK_CUR); attr = perf_header_attr__new(&f_attr.attr); @@ -569,7 +572,8 @@ int perf_header__read(struct perf_header *self, int fd) lseek(fd, f_attr.ids.offset, SEEK_SET); for (j = 0; j < nr_ids; j++) { - do_read(fd, &f_id, sizeof(f_id)); + if (do_read(fd, &f_id, sizeof(f_id))) + goto out_errno; if (perf_header_attr__add_id(attr, f_id) < 0) { perf_header_attr__delete(attr); @@ -589,7 +593,8 @@ int perf_header__read(struct perf_header *self, int fd) events = malloc(f_header.event_types.size); if (events == NULL) return -ENOMEM; - do_read(fd, events, f_header.event_types.size); + if (do_read(fd, events, f_header.event_types.size)) + goto out_errno; event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } @@ -599,6 +604,8 @@ int perf_header__read(struct perf_header *self, int fd) self->frozen = 1; return 0; +out_errno: + return -errno; } u64 perf_header__sample_type(struct perf_header *header) -- GitLab From ae99fb2c335ef018520950ddc9692faacab39cf2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Dec 2009 22:48:33 -0200 Subject: [PATCH 0303/3892] perf header: perf_header__push_event() shouldn't die MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just propagate eventual errors. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262047716-23171-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 16 ++++++++++------ tools/perf/util/header.h | 2 +- tools/perf/util/parse-events.c | 18 +++++++++++------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6b3cb94e8a2b..709e3252f049 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -105,24 +105,28 @@ struct perf_trace_event_type { static int event_count; static struct perf_trace_event_type *events; -void perf_header__push_event(u64 id, const char *name) +int perf_header__push_event(u64 id, const char *name) { if (strlen(name) > MAX_EVENT_NAME) pr_warning("Event %s will be truncated\n", name); if (!events) { events = malloc(sizeof(struct perf_trace_event_type)); - if (!events) - die("nomem"); + if (events == NULL) + return -ENOMEM; } else { - events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); - if (!events) - die("nomem"); + struct perf_trace_event_type *nevents; + + nevents = realloc(events, (event_count + 1) * sizeof(*events)); + if (nevents == NULL) + return -ENOMEM; + events = nevents; } memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); events[event_count].event_id = id; strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); event_count++; + return 0; } char *perf_header__find_event(u64 id) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index d118d05d3abe..2b69aab67e35 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -64,7 +64,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit); int perf_header__add_attr(struct perf_header *self, struct perf_header_attr *attr); -void perf_header__push_event(u64 id, const char *name); +int perf_header__push_event(u64 id, const char *name); char *perf_header__find_event(u64 id); struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index dc585a835cab..609d5a9470c5 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -753,11 +753,11 @@ modifier: return ret; } -static void store_event_type(const char *orgname) +static int store_event_type(const char *orgname) { char filename[PATH_MAX], *c; FILE *file; - int id; + int id, n; sprintf(filename, "%s/", debugfs_path); strncat(filename, orgname, strlen(orgname)); @@ -769,11 +769,14 @@ static void store_event_type(const char *orgname) file = fopen(filename, "r"); if (!file) - return; - if (fscanf(file, "%i", &id) < 1) - die("cannot store event ID"); + return 0; + n = fscanf(file, "%i", &id); fclose(file); - perf_header__push_event(id, orgname); + if (n < 1) { + pr_err("cannot store event ID\n"); + return -EINVAL; + } + return perf_header__push_event(id, orgname); } int parse_events(const struct option *opt __used, const char *str, int unset __used) @@ -782,7 +785,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u enum event_result ret; if (strchr(str, ':')) - store_event_type(str); + if (store_event_type(str) < 0) + return -1; for (;;) { if (nr_counters == MAX_COUNTERS) -- GitLab From 71289be7630fb97f2de6bb2e18a50289dc869f9d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Dec 2009 22:48:34 -0200 Subject: [PATCH 0304/3892] perf report: Add --hide-unresolved/-U command line option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful to match the 'overhead' column in 'perf report' with the 'baseline' one in 'perf diff'. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262047716-23171-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-report.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 508934b0140a..4292d7afcd60 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -34,6 +34,7 @@ static char const *input_name = "perf.data"; static int force; +static bool hide_unresolved; static int show_threads; static struct perf_read_values show_threads_values; @@ -121,7 +122,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) return -1; } - if (al.filtered) + if (al.filtered || (hide_unresolved && al.sym == NULL)) return 0; if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { @@ -342,6 +343,8 @@ static const struct option options[] = { OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), + OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, + "Only display entries resolved to a symbol"), OPT_END() }; -- GitLab From cdbae31408cf39372402076cf2e189ec693daa71 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Dec 2009 22:48:35 -0200 Subject: [PATCH 0305/3892] perf diff: Don't add the period for unresolved symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we don't add histograms buckets for them, this way the sum of baselines should be 100%. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262047716-23171-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 1cbecaf029fa..876a4b981be8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -51,12 +51,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi return -1; } - if (al.filtered) + if (al.filtered || al.sym == NULL) return 0; event__parse_sample(event, session->sample_type, &data); - if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) { + if (perf_session__add_hist_entry(session, &al, data.period)) { pr_warning("problem incrementing symbol count, skipping event\n"); return -1; } -- GitLab From 9c443dfdd31eddea6cbe6ee0ca469fbcc4e1dc3b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Dec 2009 22:48:36 -0200 Subject: [PATCH 0306/3892] perf diff: Fix support for all --sort combinations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we finish creating the hist_entries we _already_ have them sorted "by name", in fact by what is in --sort, that is exactly how we can find the pairs in perf_session__match_hists as 'comm', 'dso' & 'symbol' all are strings we need to find the matches in the baseline session. So only do the sort by hits followed by a resort by --sort if we need to find the position for shwowing the --displacement of hist entries. Now all these modes work correctly: Example is a simple 'perf record -f find / > /dev/null' ran twice then followed by the following commands: $ perf diff -f --sort comm # Baseline Delta Command # ........ .......... ....... # 0.00% +100.00% find $ perf diff -f --sort dso # Baseline Delta Shared Object # ........ .......... .................. # 59.97% -0.44% [kernel] 21.17% +0.28% libc-2.5.so 18.49% +0.16% [ext3] 0.37% find $ perf diff -f --sort symbol | head -8 # Baseline Delta Symbol # ........ .......... ...... # 6.21% +0.36% [k] ext3fs_dirhash 3.43% +0.41% [.] __GI_strlen 3.53% +0.16% [k] __kmalloc 3.17% +0.49% [k] system_call 3.06% +0.37% [k] ext3_htree_store_dirent $ perf diff -f --sort dso,symbol | head -8 # Baseline Delta Shared Object Symbol # ........ .......... .................. ...... # 6.21% +0.36% [ext3] [k] ext3fs_dirhash 3.43% +0.41% libc-2.5.so [.] __GI_strlen 3.53% +0.16% [kernel] [k] __kmalloc 3.17% +0.49% [kernel] [k] system_call 3.06% +0.37% [ext3] [k] ext3_htree_store_dirent $ And we don't have to do two expensive resorts in the common, non --displacement case. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262047716-23171-5-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-diff.c | 52 ++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 876a4b981be8..924bfb77a6ab 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -82,29 +82,19 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root, struct hist_entry *iter; while (*p != NULL) { - int cmp; parent = *p; iter = rb_entry(parent, struct hist_entry, rb_node); - - cmp = strcmp(he->map->dso->name, iter->map->dso->name); - if (cmp > 0) + if (hist_entry__cmp(he, iter) < 0) p = &(*p)->rb_left; - else if (cmp < 0) + else p = &(*p)->rb_right; - else { - cmp = strcmp(he->sym->name, iter->sym->name); - if (cmp > 0) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } } rb_link_node(&he->rb_node, parent, p); rb_insert_color(&he->rb_node, root); } -static void perf_session__resort_by_name(struct perf_session *self) +static void perf_session__resort_hist_entries(struct perf_session *self) { unsigned long position = 1; struct rb_root tmp = RB_ROOT; @@ -122,29 +112,28 @@ static void perf_session__resort_by_name(struct perf_session *self) self->hists = tmp; } +static void perf_session__set_hist_entries_positions(struct perf_session *self) +{ + perf_session__output_resort(self, self->events_stats.total); + perf_session__resort_hist_entries(self); +} + static struct hist_entry * -perf_session__find_hist_entry_by_name(struct perf_session *self, - struct hist_entry *he) +perf_session__find_hist_entry(struct perf_session *self, + struct hist_entry *he) { struct rb_node *n = self->hists.rb_node; while (n) { struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); - int cmp = strcmp(he->map->dso->name, iter->map->dso->name); + int64_t cmp = hist_entry__cmp(he, iter); - if (cmp > 0) + if (cmp < 0) n = n->rb_left; - else if (cmp < 0) + else if (cmp > 0) n = n->rb_right; - else { - cmp = strcmp(he->sym->name, iter->sym->name); - if (cmp > 0) - n = n->rb_left; - else if (cmp < 0) - n = n->rb_right; - else - return iter; - } + else + return iter; } return NULL; @@ -155,11 +144,9 @@ static void perf_session__match_hists(struct perf_session *old_session, { struct rb_node *nd; - perf_session__resort_by_name(old_session); - for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) { struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); - pos->pair = perf_session__find_hist_entry_by_name(old_session, pos); + pos->pair = perf_session__find_hist_entry(old_session, pos); } } @@ -177,9 +164,12 @@ static int __cmd_diff(void) ret = perf_session__process_events(session[i], &event_ops); if (ret) goto out_delete; - perf_session__output_resort(session[i], session[i]->events_stats.total); } + perf_session__output_resort(session[1], session[1]->events_stats.total); + if (show_displacement) + perf_session__set_hist_entries_positions(session[0]); + perf_session__match_hists(session[0], session[1]); perf_session__fprintf_hists(session[1], session[0], show_displacement, stdout); -- GitLab From afe1c2cd71eb4e0fade720b5709722e7124f29c0 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 25 Dec 2009 14:10:06 +0800 Subject: [PATCH 0307/3892] ASoC: ad1836: reset and restore clock control mode in suspend/resume entry Tests show frequent suspend/resume(frequent poweroff/on ad1836 internal components) maybe make ad1836 clock mode wrong sometimes after wakeup. This patch reset/restore ad1836 clock mode while executing PM, then ad1836 can always resume to right clock status. Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2c18e3d1b71e..83add2f3afba 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -223,6 +223,36 @@ static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, return reg_cache[reg]; } +#ifdef CONFIG_PM +static int ad1836_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + /* reset clock control mode */ + u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); +} + +static int ad1836_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + /* restore clock control mode */ + u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 |= AD1836_ADC_AUX; + + return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); +} +#else +#define ad1836_soc_suspend NULL +#define ad1836_soc_resume NULL +#endif + static int __devinit ad1836_spi_probe(struct spi_device *spi) { struct snd_soc_codec *codec; @@ -404,6 +434,8 @@ static int ad1836_remove(struct platform_device *pdev) struct snd_soc_codec_device soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, + .suspend = ad1836_soc_suspend, + .resume = ad1836_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); -- GitLab From 08ba864e2789a94c259b8d0aee13a5a183edd46e Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 25 Dec 2009 14:10:07 +0800 Subject: [PATCH 0308/3892] ASoC: ad1938: fix typo, rename mask to rx_mask for ad1938_set_tdm_slot Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1938.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 5d489186c05b..735c3562d20d 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -145,7 +145,7 @@ static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) } static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, - unsigned int mask, int slots, int width) + unsigned int rx_mask, int slots, int width) { struct snd_soc_codec *codec = dai->codec; int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); -- GitLab From 5b61735534193ab357636d5b56c098f0bbe8bac8 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 25 Dec 2009 14:10:08 +0800 Subject: [PATCH 0309/3892] ASoC: ad1938: let soc-core dapm handle PLL power PM architecture of ad1938 is simple, we don't need a bundle of functions like ad1938_pll_powerctrl, ad1938_set_bias_level for only PLL. A dapm supply will handle on/off of PLL. Since soc-core can poweron/off PLL on-demand, we don't need to poweron/off PLL in suspend/resume entries too. Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1938.c | 62 ++------------------------------------- 1 file changed, 3 insertions(+), 59 deletions(-) diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 735c3562d20d..47d9ac0ec9d9 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -97,6 +97,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = { static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_OUTPUT("DAC1OUT"), SND_SOC_DAPM_OUTPUT("DAC2OUT"), @@ -107,6 +108,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { }; static const struct snd_soc_dapm_route audio_paths[] = { + { "DAC", NULL, "PLL_PWR" }, + { "ADC", NULL, "PLL_PWR" }, { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, { "DAC1OUT", "DAC1 Switch", "DAC" }, @@ -134,16 +137,6 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) return 0; } -static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) -{ - int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0); - reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | - AD1938_PLL_POWERDOWN; - codec->write(codec, AD1938_PLL_CLK_CTRL0, reg); - - return 0; -} - static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int width) { @@ -306,24 +299,6 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ad1938_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - ad1938_pll_powerctrl(codec, 1); - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_OFF: - ad1938_pll_powerctrl(codec, 0); - break; - } - codec->bias_level = level; - return 0; -} - /* * interface to read/write ad1938 register */ @@ -514,7 +489,6 @@ static int ad1938_register(struct ad1938_priv *ad1938) codec->num_dai = 1; codec->write = ad1938_write_reg; codec->read = ad1938_read_reg_cache; - codec->set_bias_level = ad1938_set_bias_level; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); @@ -559,7 +533,6 @@ static int ad1938_register(struct ad1938_priv *ad1938) static void ad1938_unregister(struct ad1938_priv *ad1938) { - ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF); snd_soc_unregister_dai(&ad1938_dai); snd_soc_unregister_codec(&ad1938->codec); kfree(ad1938); @@ -593,7 +566,6 @@ static int ad1938_probe(struct platform_device *pdev) ARRAY_SIZE(ad1938_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); pcm_err: return ret; @@ -610,37 +582,9 @@ static int ad1938_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int ad1938_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int ad1938_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) - ad1938_set_bias_level(codec, SND_SOC_BIAS_ON); - - return 0; -} -#else -#define ad1938_suspend NULL -#define ad1938_resume NULL -#endif - struct snd_soc_codec_device soc_codec_dev_ad1938 = { .probe = ad1938_probe, .remove = ad1938_remove, - .suspend = ad1938_suspend, - .resume = ad1938_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); -- GitLab From 1c418d1f623438147a485db987de296ab372e0f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:05 +0900 Subject: [PATCH 0310/3892] ASoC: fsi: Add over_period flag to prevent the misunderstanding Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 7506ef6d287a..b311a9eaf021 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -373,14 +373,16 @@ static int fsi_data_push(struct fsi_priv *fsi) int fifo_free; int width; u8 *start; - int i; + int i, over_period; if (!fsi || !fsi->substream || !fsi->substream->runtime) return -EINVAL; - runtime = fsi->substream->runtime; + over_period = 0; + substream = fsi->substream; + runtime = substream->runtime; /* FSI FIFO has limit. * So, this driver can not send periods data at a time @@ -388,7 +390,7 @@ static int fsi_data_push(struct fsi_priv *fsi) if (fsi->byte_offset >= fsi->period_len * (fsi->periods + 1)) { - substream = fsi->substream; + over_period = 1; fsi->periods = (fsi->periods + 1) % runtime->periods; if (0 == fsi->periods) @@ -429,7 +431,7 @@ static int fsi_data_push(struct fsi_priv *fsi) fsi_irq_enable(fsi, 1); - if (substream) + if (over_period) snd_pcm_period_elapsed(substream); return 0; @@ -443,14 +445,16 @@ static int fsi_data_pop(struct fsi_priv *fsi) int fifo_fill; int width; u8 *start; - int i; + int i, over_period; if (!fsi || !fsi->substream || !fsi->substream->runtime) return -EINVAL; - runtime = fsi->substream->runtime; + over_period = 0; + substream = fsi->substream; + runtime = substream->runtime; /* FSI FIFO has limit. * So, this driver can not send periods data at a time @@ -458,7 +462,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) if (fsi->byte_offset >= fsi->period_len * (fsi->periods + 1)) { - substream = fsi->substream; + over_period = 1; fsi->periods = (fsi->periods + 1) % runtime->periods; if (0 == fsi->periods) @@ -498,7 +502,7 @@ static int fsi_data_pop(struct fsi_priv *fsi) fsi_irq_enable(fsi, 0); - if (substream) + if (over_period) snd_pcm_period_elapsed(substream); return 0; -- GitLab From 142e8174b3c493f40469d3ecee0e404645e9c483 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:11 +0900 Subject: [PATCH 0311/3892] ASoC: fsi: Add fsi_get_dai to get snd_soc_dai Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index b311a9eaf021..d078151e1de6 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -210,11 +210,17 @@ static int fsi_is_port_a(struct fsi_priv *fsi) return fsi->master->base == fsi->base; } -static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_dai *dai = machine->cpu_dai; + + return machine->cpu_dai; +} + +static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = fsi_get_dai(substream); return dai->private_data; } -- GitLab From 59c3b003ddd3c815de1aa015920710a9e4bf195b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Dec 2009 14:09:16 +0900 Subject: [PATCH 0312/3892] ASoC: fsi: Add over/under run error settlement Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index d078151e1de6..123cd6f45e0c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -67,6 +67,7 @@ /* DOFF_ST */ #define ERR_OVER 0x00000010 #define ERR_UNDER 0x00000001 +#define ST_ERR (ERR_OVER | ERR_UNDER) /* CLK_RST */ #define B_CLK 0x00000010 @@ -375,11 +376,12 @@ static int fsi_data_push(struct fsi_priv *fsi) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; + u32 status; int send; int fifo_free; int width; u8 *start; - int i, over_period; + int i, ret, over_period; if (!fsi || !fsi->substream || @@ -435,23 +437,33 @@ static int fsi_data_push(struct fsi_priv *fsi) fsi->byte_offset += send * width; + ret = 0; + status = fsi_reg_read(fsi, DOFF_ST); + if (status & ERR_OVER) { + struct snd_soc_dai *dai = fsi_get_dai(substream); + dev_err(dai->dev, "over run error\n"); + fsi_reg_write(fsi, DOFF_ST, status & ~ST_ERR); + ret = -EIO; + } + fsi_irq_enable(fsi, 1); if (over_period) snd_pcm_period_elapsed(substream); - return 0; + return ret; } static int fsi_data_pop(struct fsi_priv *fsi) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; + u32 status; int free; int fifo_fill; int width; u8 *start; - int i, over_period; + int i, ret, over_period; if (!fsi || !fsi->substream || @@ -506,12 +518,21 @@ static int fsi_data_pop(struct fsi_priv *fsi) fsi->byte_offset += fifo_fill * width; + ret = 0; + status = fsi_reg_read(fsi, DIFF_ST); + if (status & ERR_UNDER) { + struct snd_soc_dai *dai = fsi_get_dai(substream); + dev_err(dai->dev, "under run error\n"); + fsi_reg_write(fsi, DIFF_ST, status & ~ST_ERR); + ret = -EIO; + } + fsi_irq_enable(fsi, 0); if (over_period) snd_pcm_period_elapsed(substream); - return 0; + return ret; } static irqreturn_t fsi_interrupt(int irq, void *data) -- GitLab From 8998c89907f84f7e25536c1c670a134c831e682f Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 31 Dec 2009 10:30:34 +0800 Subject: [PATCH 0313/3892] ASoC: soc-cache: cleanup training whitespace and coding style Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index d2505e8b06c9..02c235711bb8 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -182,7 +182,7 @@ static struct { { .addr_bits = 7, .data_bits = 9, .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, - .spi_write = snd_soc_7_9_spi_write + .spi_write = snd_soc_7_9_spi_write, }, { .addr_bits = 8, .data_bits = 8, -- GitLab From 7427b4b9a63fd7e051d642ff0f12ef8337c08bb3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Dec 2009 10:30:19 +0200 Subject: [PATCH 0314/3892] ASoC: tlv320dac33: Change nsample switch to FIFO mode enum In order to have support for more FIFO modes supported by tlv320dac33, the switch for enabling/disabling the FIFO use has to be replaced with an enum. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 49 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 5037454974b6..b67961dd2a12 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -59,6 +59,12 @@ enum dac33_state { DAC33_FLUSH, }; +enum dac33_fifo_modes { + DAC33_FIFO_BYPASS = 0, + DAC33_FIFO_MODE1, + DAC33_FIFO_LAST_MODE, +}; + #define DAC33_NUM_SUPPLIES 3 static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = { "AVDD", @@ -82,7 +88,7 @@ struct tlv320dac33_priv { * this */ unsigned int nsample_max; /* nsample should not be higher than * this */ - unsigned int nsample_switch; /* Use FIFO or bypass FIFO switch */ + enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ unsigned int nsample; /* burst read amount from host */ enum dac33_state state; @@ -381,39 +387,48 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol, return ret; } -static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol, +static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct tlv320dac33_priv *dac33 = codec->private_data; - ucontrol->value.integer.value[0] = dac33->nsample_switch; + ucontrol->value.integer.value[0] = dac33->fifo_mode; return 0; } -static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol, +static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct tlv320dac33_priv *dac33 = codec->private_data; int ret = 0; - if (dac33->nsample_switch == ucontrol->value.integer.value[0]) + if (dac33->fifo_mode == ucontrol->value.integer.value[0]) return 0; /* Do not allow changes while stream is running*/ if (codec->active) return -EPERM; if (ucontrol->value.integer.value[0] < 0 || - ucontrol->value.integer.value[0] > 1) + ucontrol->value.integer.value[0] >= DAC33_FIFO_LAST_MODE) ret = -EINVAL; else - dac33->nsample_switch = ucontrol->value.integer.value[0]; + dac33->fifo_mode = ucontrol->value.integer.value[0]; return ret; } +/* Codec operation modes */ +static const char *dac33_fifo_mode_texts[] = { + "Bypass", "Mode 1" +}; + +static const struct soc_enum dac33_fifo_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts), + dac33_fifo_mode_texts); + /* * DACL/R digital volume control: * from 0 dB to -63.5 in 0.5 dB steps @@ -436,8 +451,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = { static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, dac33_get_nsample, dac33_set_nsample), - SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0, - dac33_get_nsample_switch, dac33_set_nsample_switch), + SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, + dac33_get_fifo_mode, dac33_set_fifo_mode), }; /* Analog bypass */ @@ -586,7 +601,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream, unsigned int pwr_ctrl; /* Stop pending workqueue */ - if (dac33->nsample_switch) + if (dac33->fifo_mode) cancel_work_sync(&dac33->work); mutex_lock(&dac33->mutex); @@ -714,7 +729,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_oscwait(codec); - if (dac33->nsample_switch) { + if (dac33->fifo_mode) { /* 50-51 : ASRC Control registers */ dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ @@ -734,7 +749,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ } - if (dac33->nsample_switch) + if (dac33->fifo_mode) fifoctrl_a &= ~DAC33_FBYPAS; else fifoctrl_a |= DAC33_FBYPAS; @@ -742,13 +757,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); - if (dac33->nsample_switch) + if (dac33->fifo_mode) reg_tmp &= ~DAC33_BCLKON; else reg_tmp |= DAC33_BCLKON; dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp); - if (dac33->nsample_switch) { + if (dac33->fifo_mode) { /* 20: BCLK divide ratio */ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); @@ -828,7 +843,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (dac33->nsample_switch) { + if (dac33->fifo_mode) { dac33->state = DAC33_PREFILL; queue_work(dac33->dac33_wq, &dac33->work); } @@ -836,7 +851,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (dac33->nsample_switch) { + if (dac33->fifo_mode) { dac33->state = DAC33_FLUSH; queue_work(dac33->dac33_wq, &dac33->work); } @@ -1125,7 +1140,7 @@ static int dac33_i2c_probe(struct i2c_client *client, dac33->irq = client->irq; dac33->nsample = NSAMPLE_MAX; /* Disable FIFO use by default */ - dac33->nsample_switch = 0; + dac33->fifo_mode = DAC33_FIFO_BYPASS; tlv320dac33_codec = codec; -- GitLab From d4f102d437c069a64f3a4c7a6cd50360e034541f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Dec 2009 10:30:20 +0200 Subject: [PATCH 0315/3892] ASoC: tlv320dac33: Introduce prefill and playback state handlers Ensure that the code is going to be readable, when new FIFO modes are introduced later. Move the prefill and playback state handling to inlined functions. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 46 +++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index b67961dd2a12..f7c7bbceb3db 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -543,6 +543,44 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, return 0; } +static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) +{ + struct snd_soc_codec *codec; + + codec = &dac33->codec; + + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: + dac33_write16(codec, DAC33_NSAMPLE_MSB, + DAC33_THRREG(dac33->nsample)); + dac33_write16(codec, DAC33_PREFILL_MSB, + DAC33_THRREG(dac33->alarm_threshold)); + break; + default: + dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", + dac33->fifo_mode); + break; + } +} + +static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) +{ + struct snd_soc_codec *codec; + + codec = &dac33->codec; + + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: + dac33_write16(codec, DAC33_NSAMPLE_MSB, + DAC33_THRREG(dac33->nsample)); + break; + default: + dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", + dac33->fifo_mode); + break; + } +} + static void dac33_work(struct work_struct *work) { struct snd_soc_codec *codec; @@ -556,14 +594,10 @@ static void dac33_work(struct work_struct *work) switch (dac33->state) { case DAC33_PREFILL: dac33->state = DAC33_PLAYBACK; - dac33_write16(codec, DAC33_NSAMPLE_MSB, - DAC33_THRREG(dac33->nsample)); - dac33_write16(codec, DAC33_PREFILL_MSB, - DAC33_THRREG(dac33->alarm_threshold)); + dac33_prefill_handler(dac33); break; case DAC33_PLAYBACK: - dac33_write16(codec, DAC33_NSAMPLE_MSB, - DAC33_THRREG(dac33->nsample)); + dac33_playback_handler(dac33); break; case DAC33_IDLE: break; -- GitLab From aec242dc3719e19bd7c1561f8a56a4eb37bb3987 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Dec 2009 10:30:21 +0200 Subject: [PATCH 0316/3892] ASoC: tlv320dac33: Clean up the hardware configuration code Use switch instead of if statements to configure FIFO bypass and mode1. With this change adding new FIFO mode is going to be easier, and cleaner. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 61 +++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index f7c7bbceb3db..c684aa23bd51 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -707,7 +707,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) struct snd_soc_codec *codec = socdev->card->codec; struct tlv320dac33_priv *dac33 = codec->private_data; unsigned int oscset, ratioset, pwr_ctrl, reg_tmp; - u8 aictrl_a, fifoctrl_a; + u8 aictrl_a, aictrl_b, fifoctrl_a; switch (substream->runtime->rate) { case 44100: @@ -764,6 +764,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_oscwait(codec); if (dac33->fifo_mode) { + /* Generic for all FIFO modes */ /* 50-51 : ASRC Control registers */ dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ @@ -773,38 +774,66 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) /* Set interrupts to high active */ dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH); - - dac33_write(codec, DAC33_FIFO_IRQ_MODE_B, - DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); - dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); } else { + /* FIFO bypass mode */ /* 50-51 : ASRC Control registers */ dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP); dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ } - if (dac33->fifo_mode) + /* Interrupt behaviour configuration */ + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: + dac33_write(codec, DAC33_FIFO_IRQ_MODE_B, + DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); + dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); + break; + default: + /* in FIFO bypass mode, the interrupts are not used */ + break; + } + + aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); + + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: + /* + * For mode1: + * Disable the FIFO bypass (Enable the use of FIFO) + * Select nSample mode + * BCLK is only running when data is needed by DAC33 + */ fifoctrl_a &= ~DAC33_FBYPAS; - else + fifoctrl_a &= ~DAC33_FAUTO; + aictrl_b &= ~DAC33_BCLKON; + break; + default: + /* + * For FIFO bypass mode: + * Enable the FIFO bypass (Disable the FIFO use) + * Set the BCLK as continous + */ fifoctrl_a |= DAC33_FBYPAS; - dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); + aictrl_b |= DAC33_BCLKON; + break; + } + dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); - reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); - if (dac33->fifo_mode) - reg_tmp &= ~DAC33_BCLKON; - else - reg_tmp |= DAC33_BCLKON; - dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp); + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b); - if (dac33->fifo_mode) { + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: /* 20: BCLK divide ratio */ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); dac33_write16(codec, DAC33_ATHR_MSB, DAC33_THRREG(dac33->alarm_threshold)); - } else { + break; + default: + /* BYPASS mode */ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); + break; } mutex_unlock(&dac33->mutex); -- GitLab From 28e05d987028023b09652bfe3ac597de6dba5e60 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Dec 2009 10:30:22 +0200 Subject: [PATCH 0317/3892] ASoC: tlv320dac33: Add new FIFO mode: mode 7 Mode 7 of tlv320dac33 operates in the following way: The codec is in master mode. Host configures upper and lower thresholds in tlv320dac33 During playback the codec will clock in the data until the upper threshold is reached in FIFO. At this point the codec stops the colocks on the serial bus. When the FIFO fill is reaching the lower threshold limit the codec will enable the clocks on the serial bus, and clocks in data till the upper threshold is reached. In this mode, we can also request interrupts for threshold events (upper, lower and alarm), which could be used for power management. At this point the interrupts are not enabled for this mode, but it can be taken into use in the future, when the surrounding code makes it possible to use it. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index c684aa23bd51..bc35f3ff8717 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -62,6 +62,7 @@ enum dac33_state { enum dac33_fifo_modes { DAC33_FIFO_BYPASS = 0, DAC33_FIFO_MODE1, + DAC33_FIFO_MODE7, DAC33_FIFO_LAST_MODE, }; @@ -422,7 +423,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, /* Codec operation modes */ static const char *dac33_fifo_mode_texts[] = { - "Bypass", "Mode 1" + "Bypass", "Mode 1", "Mode 7" }; static const struct soc_enum dac33_fifo_mode_enum = @@ -556,6 +557,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) dac33_write16(codec, DAC33_PREFILL_MSB, DAC33_THRREG(dac33->alarm_threshold)); break; + case DAC33_FIFO_MODE7: + dac33_write16(codec, DAC33_PREFILL_MSB, + DAC33_THRREG(20)); + break; default: dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", dac33->fifo_mode); @@ -574,6 +579,9 @@ static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) dac33_write16(codec, DAC33_NSAMPLE_MSB, DAC33_THRREG(dac33->nsample)); break; + case DAC33_FIFO_MODE7: + /* At the moment we are not using interrupts in mode7 */ + break; default: dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", dac33->fifo_mode); @@ -788,6 +796,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); break; + case DAC33_FIFO_MODE7: + /* Disable all interrupts */ + dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0); + break; default: /* in FIFO bypass mode, the interrupts are not used */ break; @@ -807,6 +819,17 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) fifoctrl_a &= ~DAC33_FAUTO; aictrl_b &= ~DAC33_BCLKON; break; + case DAC33_FIFO_MODE7: + /* + * For mode1: + * Disable the FIFO bypass (Enable the use of FIFO) + * Select Threshold mode + * BCLK is only running when data is needed by DAC33 + */ + fifoctrl_a &= ~DAC33_FBYPAS; + fifoctrl_a |= DAC33_FAUTO; + aictrl_b &= ~DAC33_BCLKON; + break; default: /* * For FIFO bypass mode: @@ -830,6 +853,16 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_write16(codec, DAC33_ATHR_MSB, DAC33_THRREG(dac33->alarm_threshold)); break; + case DAC33_FIFO_MODE7: + /* + * Configure the threshold levels, and leave 10 sample space + * at the bottom, and also at the top of the FIFO + */ + dac33_write16(codec, DAC33_UTHR_MSB, + DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10)); + dac33_write16(codec, DAC33_LTHR_MSB, + DAC33_THRREG(10)); + break; default: /* BYPASS mode */ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); -- GitLab From adcb8bc02d86259c117a03b54e9918e5ad3121af Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Dec 2009 10:30:23 +0200 Subject: [PATCH 0318/3892] ASoC: tlv320dac33: Safety check for codec slave mode The currently available FIFO modes (mode1 and mode7) require master mode from the codec. Do not allow the slave configuration when the FIFO is in use. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index bc35f3ff8717..3ef3255cd1e7 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -993,6 +993,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; + struct tlv320dac33_priv *dac33 = codec->private_data; u8 aictrl_a, aictrl_b; aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); @@ -1005,7 +1006,11 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, break; case SND_SOC_DAIFMT_CBS_CFS: /* Codec Slave */ - aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); + if (dac33->fifo_mode) { + dev_err(codec->dev, "FIFO mode requires master mode\n"); + return -EINVAL; + } else + aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); break; default: return -EINVAL; -- GitLab From 633154d3a7bbd542465b905392bf76b780f00b4f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 24 Dec 2009 13:42:43 +0000 Subject: [PATCH 0319/3892] ASoC: Remove unneeded suspend checks from CODEC drivers Better integration of the core with the device model means that we now no longer get the ASoC suspend and resume callbacks without the card having been set up. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8753.c | 8 -------- sound/soc/codecs/wm8990.c | 8 -------- 2 files changed, 16 deletions(-) diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d6850dacda29..c2444e7c8480 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1507,10 +1507,6 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - /* we only need to suspend if we are a valid card */ - if (!codec->card) - return 0; - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1523,10 +1519,6 @@ static int wm8753_resume(struct platform_device *pdev) u8 data[2]; u16 *cache = codec->reg_cache; - /* we only need to resume if we are a valid card */ - if (!codec->card) - return 0; - /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { if (i + 1 == WM8753_RESET) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 341481e0e830..a54dc77b7f34 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1319,10 +1319,6 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - /* we only need to suspend if we are a valid card */ - if (!codec->card) - return 0; - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1335,10 +1331,6 @@ static int wm8990_resume(struct platform_device *pdev) u8 data[2]; u16 *cache = codec->reg_cache; - /* we only need to resume if we are a valid card */ - if (!codec->card) - return 0; - /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { if (i + 1 == WM8990_RESET) -- GitLab From 40ca114265a281d51b261771df551a373fc8ff3c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 24 Dec 2009 13:44:28 +0000 Subject: [PATCH 0320/3892] ASoC: Use snprintf() when generating stream names Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8b900a842677..9b36c5eec75c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1276,8 +1276,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = card->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, - num); + snprintf(new_name, sizeof(new_name), "%s %s-%d", + dai_link->stream_name, codec_dai->name, num); if (codec_dai->playback.channels_min) playback = 1; -- GitLab From e591a517230a97e93f5edd19e7bef7ec8d22ac2b Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sun, 13 Dec 2009 22:18:09 +0000 Subject: [PATCH 0321/3892] sh: Remove unused functions Apply some TLC to the SH64 header files and remove some functions that are not used anymore. Signed-off-by: Matt Fleming --- arch/sh/include/asm/pgtable_64.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h index 17cdbecc3adc..dd381588c695 100644 --- a/arch/sh/include/asm/pgtable_64.h +++ b/arch/sh/include/asm/pgtable_64.h @@ -43,11 +43,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) } #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) -static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep) -{ - pmd_val(*pmdp) = (unsigned long) ptep; -} - /* * PGD defines. Top level. */ @@ -202,12 +197,6 @@ static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep) #define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE) #define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd_kernel(pmd_t * pmd); -#define __handle_bad_pmd(x) __handle_bad_pmd_kernel(x) - /* * PTE level access routines. * -- GitLab From 3f5ab768164df9a44721660b96e0accb92eb2c24 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 24 Dec 2009 20:38:45 +0000 Subject: [PATCH 0322/3892] sh: Correct the PTRS_PER_PMD and PMD_SHIFT values The previous expressions were wrong which made free_pmd_range() explode when using anything other than 4KB pages (which is why 8KB and 64KB pages were disabled with the 3-level page table layout). The problem was that pmd_offset() was returning an index of non-zero when it should have been returning 0. This non-zero offset was used to calculate the address of the pmd table to free in free_pmd_range(), which ended up trying to free an object that was not aligned on a page boundary. Now 3-level page tables should work with 4KB, 8KB and 64KB pages. Signed-off-by: Matt Fleming --- arch/sh/include/asm/pgtable_pmd.h | 4 ++-- arch/sh/mm/Kconfig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable_pmd.h index 78dc36e1c2dd..42a180e534a8 100644 --- a/arch/sh/include/asm/pgtable_pmd.h +++ b/arch/sh/include/asm/pgtable_pmd.h @@ -17,11 +17,11 @@ #define USER_PTRS_PER_PGD 2 /* PMD bits */ -#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PTE_MAGNITUDE)) #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) -#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t)) +#define PTRS_PER_PMD ((1 << PGDIR_SHIFT) / PMD_SIZE) #define pmd_ERROR(e) \ printk("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e)) diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index b3f6c1a30b22..1b4364871899 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -220,7 +220,7 @@ config PAGE_SIZE_4KB config PAGE_SIZE_8KB bool "8kB" - depends on !MMU || X2TLB && !PGTABLE_LEVELS_3 + depends on !MMU || X2TLB help This enables 8kB pages as supported by SH-X2 and later MMUs. @@ -232,7 +232,7 @@ config PAGE_SIZE_16KB config PAGE_SIZE_64KB bool "64kB" - depends on !MMU || CPU_SH4 && !PGTABLE_LEVELS_3 || CPU_SH5 + depends on !MMU || CPU_SH4 || CPU_SH5 help This enables support for 64kB pages, possible on all SH-4 CPUs and later. -- GitLab From b4c892762373c5e59c7e8db35f5f9a7658602bda Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 24 Dec 2009 22:17:35 +0000 Subject: [PATCH 0323/3892] sh: Optimise flush_dcache_page() on SH4 If the page is not mapped into any process's address space then aliases cannot exist in the cache. So reduce the amount of flushing we perform. Signed-off-by: Matt Fleming --- arch/sh/mm/cache-sh4.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 560ddb6bc8a7..a2301daeefa3 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -109,6 +109,7 @@ static inline void flush_cache_one(unsigned long start, unsigned long phys) static void sh4_flush_dcache_page(void *arg) { struct page *page = arg; + unsigned long addr = (unsigned long)page_address(page); #ifndef CONFIG_SMP struct address_space *mapping = page_mapping(page); @@ -116,16 +117,8 @@ static void sh4_flush_dcache_page(void *arg) set_bit(PG_dcache_dirty, &page->flags); else #endif - { - unsigned long phys = page_to_phys(page); - unsigned long addr = CACHE_OC_ADDRESS_ARRAY; - int i, n; - - /* Loop all the D-cache */ - n = boot_cpu_data.dcache.n_aliases; - for (i = 0; i < n; i++, addr += PAGE_SIZE) - flush_cache_one(addr, phys); - } + flush_cache_one(CACHE_OC_ADDRESS_ARRAY | + (addr & shm_align_mask), page_to_phys(page)); wmb(); } -- GitLab From 2a5eacca85d39d8b6dffae821d7d260f05584dc7 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 31 Dec 2009 12:19:24 +0000 Subject: [PATCH 0324/3892] sh: Move page table allocation out of line We also switched away from quicklists and instead moved to slab caches. After benchmarking both implementations the difference is negligible. The slab caches suit us better though because the size of a pgd table is just 4 entries when we're using a 3-level page table layout and quicklists always deal with pages. Signed-off-by: Matt Fleming --- arch/sh/include/asm/pgalloc.h | 10 +++-- arch/sh/include/asm/pgalloc_nopmd.h | 30 --------------- arch/sh/include/asm/pgalloc_pmd.h | 41 --------------------- arch/sh/include/asm/pgtable.h | 4 +- arch/sh/mm/Makefile | 2 +- arch/sh/mm/pgtable.c | 57 +++++++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 78 deletions(-) delete mode 100644 arch/sh/include/asm/pgalloc_nopmd.h delete mode 100644 arch/sh/include/asm/pgalloc_pmd.h create mode 100644 arch/sh/mm/pgtable.c diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h index 4ea27855c3b5..e106474996b2 100644 --- a/arch/sh/include/asm/pgalloc.h +++ b/arch/sh/include/asm/pgalloc.h @@ -6,10 +6,13 @@ #define QUICK_PT 1 /* Other page table pages that are zero on free */ +extern pgd_t *pgd_alloc(struct mm_struct *); +extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); + #ifdef CONFIG_PGTABLE_LEVELS_3 -#include -#else -#include +extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd); +extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address); +extern void pmd_free(struct mm_struct *mm, pmd_t *pmd); #endif static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, @@ -67,7 +70,6 @@ do { \ static inline void check_pgt_cache(void) { - __check_pgt_cache(); quicklist_trim(QUICK_PT, NULL, 25, 16); } diff --git a/arch/sh/include/asm/pgalloc_nopmd.h b/arch/sh/include/asm/pgalloc_nopmd.h deleted file mode 100644 index e4b344c37e74..000000000000 --- a/arch/sh/include/asm/pgalloc_nopmd.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __ASM_SH_PGALLOC_NOPMD_H -#define __ASM_SH_PGALLOC_NOPMD_H - -#define QUICK_PGD 0 /* We preserve special mappings over free */ - -static inline void pgd_ctor(void *x) -{ - pgd_t *pgd = x; - - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); -} - -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor); -} - -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - quicklist_free(QUICK_PGD, NULL, pgd); -} - -static inline void __check_pgt_cache(void) -{ - quicklist_trim(QUICK_PGD, NULL, 25, 16); -} - -#endif /* __ASM_SH_PGALLOC_NOPMD_H */ diff --git a/arch/sh/include/asm/pgalloc_pmd.h b/arch/sh/include/asm/pgalloc_pmd.h deleted file mode 100644 index 20f75cc4eb09..000000000000 --- a/arch/sh/include/asm/pgalloc_pmd.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __ASM_SH_PGALLOC_PMD_H -#define __ASM_SH_PGALLOC_PMD_H - -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *pgd; - int i; - - pgd = kzalloc(sizeof(*pgd) * PTRS_PER_PGD, GFP_KERNEL | __GFP_REPEAT); - - for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) - pgd[i] = swapper_pg_dir[i]; - - return pgd; -} - -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - kfree(pgd); -} - -static inline void __check_pgt_cache(void) -{ -} - -static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) -{ - set_pud(pud, __pud((unsigned long)pmd)); -} - -static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) -{ - return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); -} - -static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) -{ - quicklist_free(QUICK_PT, NULL, pmd); -} - -#endif /* __ASM_SH_PGALLOC_PMD_H */ diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 9effcc3b0d10..78598ec33d0a 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -141,9 +141,9 @@ typedef pte_t *pte_addr_t; #define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT))) /* - * No page table caches to initialise + * Initialise the page table caches */ -#define pgtable_cache_init() do { } while (0) +extern void pgtable_cache_init(void); struct vm_area_struct; diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 8a70535fa7ce..dd5010c708e0 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -15,7 +15,7 @@ obj-y += $(cacheops-y) mmu-y := nommu.o extable_32.o mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o \ - ioremap_$(BITS).o kmap.o tlbflush_$(BITS).o + ioremap_$(BITS).o kmap.o pgtable.o tlbflush_$(BITS).o obj-y += $(mmu-y) obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o diff --git a/arch/sh/mm/pgtable.c b/arch/sh/mm/pgtable.c new file mode 100644 index 000000000000..e1bc5483cc07 --- /dev/null +++ b/arch/sh/mm/pgtable.c @@ -0,0 +1,57 @@ +#include + +#define PGALLOC_GFP GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO + +static struct kmem_cache *pgd_cachep; + +#ifdef CONFIG_PGTABLE_LEVELS_3 +static struct kmem_cache *pmd_cachep; +#endif + +void pgd_ctor(void *x) +{ + pgd_t *pgd = x; + + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); +} + +void pgtable_cache_init(void) +{ + pgd_cachep = kmem_cache_create("pgd_cache", + PTRS_PER_PGD * (1< Date: Mon, 14 Dec 2009 10:48:58 +0000 Subject: [PATCH 0325/3892] bonding: allow arp_ip_targets on separate vlans to use arp validation This allows a bond device to specify an arp_ip_target as a host that is not on the same vlan as the base bond device and still use arp validation. A configuration like this, now works: BONDING_OPTS="mode=active-backup arp_interval=1000 arp_ip_target=10.0.100.1 arp_validate=3" 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth1: mtu 1500 qdisc pfifo_fast master bond0 qlen 1000 link/ether 00:13:21:be:33:e9 brd ff:ff:ff:ff:ff:ff 3: eth0: mtu 1500 qdisc pfifo_fast master bond0 qlen 1000 link/ether 00:13:21:be:33:e9 brd ff:ff:ff:ff:ff:ff 8: bond0: mtu 1500 qdisc noqueue link/ether 00:13:21:be:33:e9 brd ff:ff:ff:ff:ff:ff inet6 fe80::213:21ff:febe:33e9/64 scope link valid_lft forever preferred_lft forever 9: bond0.100@bond0: mtu 1500 qdisc noqueue link/ether 00:13:21:be:33:e9 brd ff:ff:ff:ff:ff:ff inet 10.0.100.2/24 brd 10.0.100.255 scope global bond0.100 inet6 fe80::213:21ff:febe:33e9/64 scope link valid_lft forever preferred_lft forever Ethernet Channel Bonding Driver: v3.6.0 (September 26, 2009) Bonding Mode: fault-tolerance (active-backup) Primary Slave: None Currently Active Slave: eth1 MII Status: up MII Polling Interval (ms): 0 Up Delay (ms): 0 Down Delay (ms): 0 ARP Polling Interval (ms): 1000 ARP IP target/s (n.n.n.n form): 10.0.100.1 Slave Interface: eth1 MII Status: up Link Failure Count: 1 Permanent HW addr: 00:40:05:30:ff:30 Slave Interface: eth0 MII Status: up Link Failure Count: 0 Permanent HW addr: 00:13:21:be:33:e9 Signed-off-by: Andy Gospodarek Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 11 +++++++++++ net/8021q/vlan_core.c | 2 ++ net/core/dev.c | 20 +++++++++++++++++--- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3f0071cfe56b..6a42a1453afa 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2615,6 +2615,17 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; __be32 sip, tip; + if (dev->priv_flags & IFF_802_1Q_VLAN) { + /* + * When using VLANS and bonding, dev and oriv_dev may be + * incorrect if the physical interface supports VLAN + * acceleration. With this change ARP validation now + * works for hosts only reachable on the VLAN interface. + */ + dev = vlan_dev_real_dev(dev); + orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif); + } + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index e75a2f3b10af..c0316e0ca6e8 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -14,6 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, if (skb_bond_should_drop(skb)) goto drop; + skb->skb_iif = skb->dev->ifindex; __vlan_hwaccel_put_tag(skb, vlan_tci); skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); @@ -85,6 +86,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, if (skb_bond_should_drop(skb)) goto drop; + skb->skb_iif = skb->dev->ifindex; __vlan_hwaccel_put_tag(skb, vlan_tci); skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); diff --git a/net/core/dev.c b/net/core/dev.c index a8d68cdedbbe..f9aa699ab6cb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2495,12 +2495,26 @@ ncls: if (!skb) goto out; + /* + * Make sure frames received on VLAN interfaces stacked on + * bonding interfaces still make their way to any base bonding + * device that may have registered for a specific ptype. The + * handler may have to adjust skb->dev and orig_dev. + * + * null_or_orig can be overloaded since it will not be set when + * using VLANs on top of bonding. Putting it here prevents + * disturbing the ptype_all handlers above. + */ + if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) && + (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) { + null_or_orig = vlan_dev_real_dev(skb->dev); + } + type = skb->protocol; list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { - if (ptype->type == type && - (ptype->dev == null_or_orig || ptype->dev == skb->dev || - ptype->dev == orig_dev)) { + if (ptype->type == type && (ptype->dev == null_or_orig || + ptype->dev == skb->dev || ptype->dev == orig_dev)) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; -- GitLab From 75ed0a897208c3273fd8dc0f71e1417dba5a049b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 18 Dec 2009 21:16:52 +0000 Subject: [PATCH 0326/3892] drivers/net/cxgb3: Use kzalloc for allocating only one thing Use kzalloc rather than kcalloc(1,...) The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ @@ - kcalloc(1, + kzalloc( ...) // Signed-off-by: Julia Lawall Acked-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 75064eea1d87..9498361119d6 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1252,7 +1252,7 @@ int cxgb3_offload_activate(struct adapter *adapter) struct mtutab mtutab; unsigned int l2t_capacity; - t = kcalloc(1, sizeof(*t), GFP_KERNEL); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (!t) return -ENOMEM; -- GitLab From 20dd3850bcf860561496827b711fa10fecf6e787 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 25 Dec 2009 06:47:47 +0000 Subject: [PATCH 0327/3892] can: Speed up CAN frame receiption by using ml_priv this patch removes the hlist that contains the CAN receiver filter lists. It uses the 'midlayer private' pointer ml_priv and links the filters directly to the CAN netdevice, which allows to omit the walk through the complete CAN devices hlist for each received CAN frame. This patch is tested and does not remove any locking. Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/can/af_can.c | 118 ++++++++++++++--------------------------------- net/can/af_can.h | 4 +- net/can/proc.c | 93 ++++++++++++++++++++++++------------- 3 files changed, 96 insertions(+), 119 deletions(-) diff --git a/net/can/af_can.c b/net/can/af_can.c index 51adc4c2b860..bc18b084ffdb 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -77,8 +77,8 @@ static int stats_timer __read_mostly = 1; module_param(stats_timer, int, S_IRUGO); MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)"); -HLIST_HEAD(can_rx_dev_list); -static struct dev_rcv_lists can_rx_alldev_list; +/* receive filters subscribed for 'all' CAN devices */ +struct dev_rcv_lists can_rx_alldev_list; static DEFINE_SPINLOCK(can_rcvlists_lock); static struct kmem_cache *rcv_cache __read_mostly; @@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send); static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) { - struct dev_rcv_lists *d = NULL; - struct hlist_node *n; - - /* - * find receive list for this device - * - * The hlist_for_each_entry*() macros curse through the list - * using the pointer variable n and set d to the containing - * struct in each list iteration. Therefore, after list - * iteration, d is unmodified when the list is empty, and it - * points to last list element, when the list is non-empty - * but no match in the loop body is found. I.e. d is *not* - * NULL when no match is found. We can, however, use the - * cursor variable n to decide if a match was found. - */ - - hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { - if (d->dev == dev) - break; - } - - return n ? d : NULL; + if (!dev) + return &can_rx_alldev_list; + else + return (struct dev_rcv_lists *)dev->ml_priv; } /** @@ -467,16 +449,6 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, } EXPORT_SYMBOL(can_rx_register); -/* - * can_rx_delete_device - rcu callback for dev_rcv_lists structure removal - */ -static void can_rx_delete_device(struct rcu_head *rp) -{ - struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu); - - kfree(d); -} - /* * can_rx_delete_receiver - rcu callback for single receiver entry removal */ @@ -541,7 +513,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, "dev %s, id %03X, mask %03X\n", DNAME(dev), can_id, mask); r = NULL; - d = NULL; goto out; } @@ -552,10 +523,10 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, can_pstats.rcv_entries--; /* remove device structure requested by NETDEV_UNREGISTER */ - if (d->remove_on_zero_entries && !d->entries) - hlist_del_rcu(&d->list); - else - d = NULL; + if (d->remove_on_zero_entries && !d->entries) { + kfree(d); + dev->ml_priv = NULL; + } out: spin_unlock(&can_rcvlists_lock); @@ -563,10 +534,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, /* schedule the receiver item for deletion */ if (r) call_rcu(&r->rcu, can_rx_delete_receiver); - - /* schedule the device structure for deletion */ - if (d) - call_rcu(&d->rcu, can_rx_delete_device); } EXPORT_SYMBOL(can_rx_unregister); @@ -780,48 +747,35 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, case NETDEV_REGISTER: - /* - * create new dev_rcv_lists for this device - * - * N.B. zeroing the struct is the correct initialization - * for the embedded hlist_head structs. - * Another list type, e.g. list_head, would require - * explicit initialization. - */ - + /* create new dev_rcv_lists for this device */ d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) { printk(KERN_ERR "can: allocation of receive list failed\n"); return NOTIFY_DONE; } - d->dev = dev; - - spin_lock(&can_rcvlists_lock); - hlist_add_head_rcu(&d->list, &can_rx_dev_list); - spin_unlock(&can_rcvlists_lock); + BUG_ON(dev->ml_priv); + dev->ml_priv = d; break; case NETDEV_UNREGISTER: spin_lock(&can_rcvlists_lock); - d = find_dev_rcv_lists(dev); + d = dev->ml_priv; if (d) { - if (d->entries) { + if (d->entries) d->remove_on_zero_entries = 1; - d = NULL; - } else - hlist_del_rcu(&d->list); + else { + kfree(d); + dev->ml_priv = NULL; + } } else printk(KERN_ERR "can: notifier: receive list not " "found for dev %s\n", dev->name); spin_unlock(&can_rcvlists_lock); - if (d) - call_rcu(&d->rcu, can_rx_delete_device); - break; } @@ -853,21 +807,13 @@ static __init int can_init(void) { printk(banner); + memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list)); + rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), 0, 0, NULL); if (!rcv_cache) return -ENOMEM; - /* - * Insert can_rx_alldev_list for reception on all devices. - * This struct is zero initialized which is correct for the - * embedded hlist heads, the dev pointer, and the entries counter. - */ - - spin_lock(&can_rcvlists_lock); - hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list); - spin_unlock(&can_rcvlists_lock); - if (stats_timer) { /* the statistics are updated every second (timer triggered) */ setup_timer(&can_stattimer, can_stat_update, 0); @@ -887,8 +833,7 @@ static __init int can_init(void) static __exit void can_exit(void) { - struct dev_rcv_lists *d; - struct hlist_node *n, *next; + struct net_device *dev; if (stats_timer) del_timer(&can_stattimer); @@ -900,14 +845,19 @@ static __exit void can_exit(void) unregister_netdevice_notifier(&can_netdev_notifier); sock_unregister(PF_CAN); - /* remove can_rx_dev_list */ - spin_lock(&can_rcvlists_lock); - hlist_del(&can_rx_alldev_list.list); - hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) { - hlist_del(&d->list); - kfree(d); + /* remove created dev_rcv_lists from still registered CAN devices */ + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { + if (dev->type == ARPHRD_CAN && dev->ml_priv){ + + struct dev_rcv_lists *d = dev->ml_priv; + + BUG_ON(d->entries); + kfree(d); + dev->ml_priv = NULL; + } } - spin_unlock(&can_rcvlists_lock); + rcu_read_unlock(); rcu_barrier(); /* Wait for completion of call_rcu()'s */ diff --git a/net/can/af_can.h b/net/can/af_can.h index 18f91e37cc30..34253b84e30f 100644 --- a/net/can/af_can.h +++ b/net/can/af_can.h @@ -63,10 +63,8 @@ struct receiver { enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; +/* per device receive filters linked at dev->ml_priv */ struct dev_rcv_lists { - struct hlist_node list; - struct rcu_head rcu; - struct net_device *dev; struct hlist_head rx[RX_MAX]; struct hlist_head rx_sff[0x800]; int remove_on_zero_entries; diff --git a/net/can/proc.c b/net/can/proc.c index 9b9ad29be567..f4265cc9c3fb 100644 --- a/net/can/proc.c +++ b/net/can/proc.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "af_can.h" @@ -84,6 +85,9 @@ static const char rx_list_name[][8] = { [RX_EFF] = "rx_eff", }; +/* receive filters subscribed for 'all' CAN devices */ +extern struct dev_rcv_lists can_rx_alldev_list; + /* * af_can statistics stuff */ @@ -190,10 +194,6 @@ void can_stat_update(unsigned long data) /* * proc read functions - * - * From known use-cases we expect about 10 entries in a receive list to be - * printed in the proc_fs. So PAGE_SIZE is definitely enough space here. - * */ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, @@ -202,7 +202,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, struct receiver *r; struct hlist_node *n; - rcu_read_lock(); hlist_for_each_entry_rcu(r, n, rx_list, list) { char *fmt = (r->can_id & CAN_EFF_FLAG)? " %-5s %08X %08x %08x %08x %8ld %s\n" : @@ -212,7 +211,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, (unsigned long)r->func, (unsigned long)r->data, r->matches, r->ident); } - rcu_read_unlock(); } static void can_print_recv_banner(struct seq_file *m) @@ -346,24 +344,39 @@ static const struct file_operations can_version_proc_fops = { .release = single_release, }; +static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx, + struct net_device *dev, + struct dev_rcv_lists *d) +{ + if (!hlist_empty(&d->rx[idx])) { + can_print_recv_banner(m); + can_print_rcvlist(m, &d->rx[idx], dev); + } else + seq_printf(m, " (%s: no entry)\n", DNAME(dev)); + +} + static int can_rcvlist_proc_show(struct seq_file *m, void *v) { /* double cast to prevent GCC warning */ int idx = (int)(long)m->private; + struct net_device *dev; struct dev_rcv_lists *d; - struct hlist_node *n; seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); rcu_read_lock(); - hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { - if (!hlist_empty(&d->rx[idx])) { - can_print_recv_banner(m); - can_print_rcvlist(m, &d->rx[idx], d->dev); - } else - seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); + /* receive list for 'all' CAN devices (dev == NULL) */ + d = &can_rx_alldev_list; + can_rcvlist_proc_show_one(m, idx, NULL, d); + + /* receive list for registered CAN devices */ + for_each_netdev_rcu(&init_net, dev) { + if (dev->type == ARPHRD_CAN && dev->ml_priv) + can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv); } + rcu_read_unlock(); seq_putc(m, '\n'); @@ -383,34 +396,50 @@ static const struct file_operations can_rcvlist_proc_fops = { .release = single_release, }; +static inline void can_rcvlist_sff_proc_show_one(struct seq_file *m, + struct net_device *dev, + struct dev_rcv_lists *d) +{ + int i; + int all_empty = 1; + + /* check wether at least one list is non-empty */ + for (i = 0; i < 0x800; i++) + if (!hlist_empty(&d->rx_sff[i])) { + all_empty = 0; + break; + } + + if (!all_empty) { + can_print_recv_banner(m); + for (i = 0; i < 0x800; i++) { + if (!hlist_empty(&d->rx_sff[i])) + can_print_rcvlist(m, &d->rx_sff[i], dev); + } + } else + seq_printf(m, " (%s: no entry)\n", DNAME(dev)); +} + static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) { + struct net_device *dev; struct dev_rcv_lists *d; - struct hlist_node *n; /* RX_SFF */ seq_puts(m, "\nreceive list 'rx_sff':\n"); rcu_read_lock(); - hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { - int i, all_empty = 1; - /* check wether at least one list is non-empty */ - for (i = 0; i < 0x800; i++) - if (!hlist_empty(&d->rx_sff[i])) { - all_empty = 0; - break; - } - - if (!all_empty) { - can_print_recv_banner(m); - for (i = 0; i < 0x800; i++) { - if (!hlist_empty(&d->rx_sff[i])) - can_print_rcvlist(m, &d->rx_sff[i], - d->dev); - } - } else - seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); + + /* sff receive list for 'all' CAN devices (dev == NULL) */ + d = &can_rx_alldev_list; + can_rcvlist_sff_proc_show_one(m, NULL, d); + + /* sff receive list for registered CAN devices */ + for_each_netdev_rcu(&init_net, dev) { + if (dev->type == ARPHRD_CAN && dev->ml_priv) + can_rcvlist_sff_proc_show_one(m, dev, dev->ml_priv); } + rcu_read_unlock(); seq_putc(m, '\n'); -- GitLab From c1c5523dd1517250cac8b15a4acbc237c24a67d4 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 23 Dec 2009 01:27:48 +0000 Subject: [PATCH 0328/3892] can/netlink: add CAN_CTRLMODE_ONE_SHOT This patch adds the flag CAN_CTRLMODE_ONE_SHOT. It is used as mask or flag in the "struct can_ctrlmode". It allows userspace via netlink to set a CAN controller into the special "one-shot" mode. In this mode, if supported by the CAN controller, it tries only once to deliver a CAN frame and aborts it if an error (e.g.: arbitration lost) happens. Signed-off-by: Marc Kleine-Budde Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- include/linux/can/netlink.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h index 9ecbb7871c0e..c818335fbb13 100644 --- a/include/linux/can/netlink.h +++ b/include/linux/can/netlink.h @@ -80,6 +80,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_LOOPBACK 0x1 /* Loopback mode */ #define CAN_CTRLMODE_LISTENONLY 0x2 /* Listen-only mode */ #define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */ +#define CAN_CTRLMODE_ONE_SHOT 0x8 /* One-Shot mode */ /* * CAN device statistics -- GitLab From ee983ac76865797a5553597a9412c835c2710f51 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 24 Dec 2009 17:26:48 +0000 Subject: [PATCH 0329/3892] tipc: use kconfig to limit numeric ranges We can rely on kconfig to limit these numbers, no need to limit them at compile time/run time. Users who modify these numbers manually should be responsible for themself. :) Signed-off-by: WANG Cong Cc: Per Liden Cc: Jon Maloy Cc: Allan Stephens Cc: David S. Miller Signed-off-by: David S. Miller --- net/tipc/Kconfig | 8 ++++++-- net/tipc/core.c | 10 +++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index 3b30d1130b61..dafbd533067c 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig @@ -33,6 +33,7 @@ config TIPC_ADVANCED config TIPC_ZONES int "Maximum number of zones in network" depends on TIPC_ADVANCED + range 1 255 default "3" help Max number of zones inside TIPC network. Max supported value @@ -44,10 +45,10 @@ config TIPC_ZONES config TIPC_CLUSTERS int "Maximum number of clusters in a zone" depends on TIPC_ADVANCED + range 1 1 default "1" help - ***Only 1 (one cluster in a zone) is supported by current code. - Any value set here will be overridden.*** + ***Only 1 (one cluster in a zone) is supported by current code.*** (Max number of clusters inside TIPC zone. Max supported value is 4095 clusters, minimum is 1. @@ -59,6 +60,7 @@ config TIPC_CLUSTERS config TIPC_NODES int "Maximum number of nodes in cluster" depends on TIPC_ADVANCED + range 8 2047 default "255" help Maximum number of nodes inside a TIPC cluster. Maximum @@ -70,6 +72,7 @@ config TIPC_NODES config TIPC_SLAVE_NODES int "Maximum number of slave nodes in cluster" depends on TIPC_ADVANCED + range 0 2047 default "0" help ***This capability is not supported by current code.*** @@ -83,6 +86,7 @@ config TIPC_SLAVE_NODES config TIPC_PORTS int "Maximum number of ports in a node" depends on TIPC_ADVANCED + range 217 65536 default "8191" help Maximum number of ports within a node. Maximum diff --git a/net/tipc/core.c b/net/tipc/core.c index 3256bd7d398f..52c571fedbe0 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -189,11 +189,11 @@ static int __init tipc_init(void) tipc_remote_management = 1; tipc_max_publications = 10000; tipc_max_subscriptions = 2000; - tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536); - tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255); - tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1); - tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047); - tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047); + tipc_max_ports = CONFIG_TIPC_PORTS; + tipc_max_zones = CONFIG_TIPC_ZONES; + tipc_max_clusters = CONFIG_TIPC_CLUSTERS; + tipc_max_nodes = CONFIG_TIPC_NODES; + tipc_max_slaves = CONFIG_TIPC_SLAVE_NODES; tipc_net_id = 4711; if ((res = tipc_core_start())) -- GitLab From ceba0b29e002e6151b6b5ead8db9c664b58d8d21 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Mon, 28 Dec 2009 15:17:24 +0000 Subject: [PATCH 0330/3892] axnet_cs: remove unnecessary spin_unlock_irqrestore axnet_cs: remove unnecessary spin_unlock_irqrestore,spin_lock_irqsave. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/axnet_cs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index d431b59e7d11..2ee57bd52a01 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1065,14 +1065,11 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&ei_local->page_lock, flags); outb_p(0x00, e8390_base + EN0_IMR); - spin_unlock_irqrestore(&ei_local->page_lock, flags); /* * Slow phase with lock held. */ - spin_lock_irqsave(&ei_local->page_lock, flags); - ei_local->irqlock = 1; send_length = max(length, ETH_ZLEN); -- GitLab From d3fb5454a8474d5d22c8f8fe4d043b05732d91d5 Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Mon, 4 Jan 2010 12:04:08 +0100 Subject: [PATCH 0331/3892] HID: add support for Stantum multitouch panel Added support for the Stantum multitouch panel. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-stantum.c | 283 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 294 insertions(+) create mode 100644 drivers/hid/hid-stantum.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 0c8ce3a68d27..84272c690310 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -247,6 +247,12 @@ config HID_SONY ---help--- Support for Sony PS3 controller. +config HID_STANTUM + tristate "Stantum" if EMBEDDED + depends on USB_HID + ---help--- + Support for Stantum multitouch panel. + config HID_SUNPLUS tristate "Sunplus" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1bdfb97910f1..f8dc5bac79bd 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o +obj-$(CONFIG_HID_STANTUM) += hid-stantum.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 70c25a056205..6462c923805f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1339,6 +1339,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3d55f983dbaf..07e056b0e188 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -393,6 +393,9 @@ #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 +#define USB_VENDOR_ID_STANTUM 0x1f87 +#define USB_DEVICE_ID_MTP 0x0002 + #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c new file mode 100644 index 000000000000..add965dab932 --- /dev/null +++ b/drivers/hid/hid-stantum.c @@ -0,0 +1,283 @@ +/* + * HID driver for Stantum multitouch panels + * + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +MODULE_VERSION("0.6"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("Stantum HID multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct stantum_data { + __s32 x, y, z, w, h; /* x, y, pressure, width, height */ + __u16 id; /* touch id */ + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* first finger in the HID packet? */ + bool activity; /* at least one active finger so far? */ +}; + +static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_INRANGE: + case HID_DG_CONFIDENCE: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + return -1; + + case HID_DG_TIPSWITCH: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + + case HID_DG_WIDTH: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MAJOR); + return 1; + case HID_DG_HEIGHT: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MINOR); + input_set_abs_params(hi->input, ABS_MT_ORIENTATION, + 1, 1, 0, 0); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + + } + return 0; + + case 0xff000000: + /* no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void stantum_filter_event(struct stantum_data *sd, + struct input_dev *input) +{ + bool wide; + + if (!sd->valid) { + /* + * touchscreen emulation: if the first finger is not valid and + * there previously was finger activity, this is a release + */ + if (sd->first && sd->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + sd->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y); + + wide = (sd->w > sd->h); + input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); + +#if 0 + /* MT_PRESSURE does not exist yet */ + input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); +#endif + + input_mt_sync(input); + sd->valid = false; + sd->first = false; + + /* touchscreen emulation */ + if (sd->first) { + if (!sd->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + sd->activity = true; + } + input_event(input, EV_ABS, ABS_X, sd->x); + input_event(input, EV_ABS, ABS_Y, sd->y); + } +} + + +static int stantum_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct stantum_data *sd = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + + switch (usage->hid) { + case HID_DG_INRANGE: + /* this is the last field in a finger */ + stantum_filter_event(sd, input); + break; + case HID_DG_WIDTH: + sd->w = value; + break; + case HID_DG_HEIGHT: + sd->h = value; + break; + case HID_GD_X: + sd->x = value; + break; + case HID_GD_Y: + sd->y = value; + break; + case HID_DG_TIPPRESSURE: + sd->z = value; + break; + case HID_DG_CONTACTID: + sd->id = value; + break; + case HID_DG_CONFIDENCE: + sd->valid = !!value; + break; + case 0xff000002: + /* this comes only before the first finger */ + sd->first = true; + break; + + default: + /* ignore the others */ + return 1; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int stantum_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct stantum_data *sd; + + sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL); + if (!sd) { + dev_err(&hdev->dev, "cannot allocate Stantum data\n"); + return -ENOMEM; + } + sd->valid = false; + sd->first = false; + sd->activity = false; + hid_set_drvdata(hdev, sd); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(sd); + + return ret; +} + +static void stantum_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id stantum_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, + { } +}; +MODULE_DEVICE_TABLE(hid, stantum_devices); + +static const struct hid_usage_id stantum_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver stantum_driver = { + .name = "stantum", + .id_table = stantum_devices, + .probe = stantum_probe, + .remove = stantum_remove, + .input_mapping = stantum_input_mapping, + .input_mapped = stantum_input_mapped, + .usage_table = stantum_grabbed_usages, + .event = stantum_event, +}; + +static int __init stantum_init(void) +{ + return hid_register_driver(&stantum_driver); +} + +static void __exit stantum_exit(void) +{ + hid_unregister_driver(&stantum_driver); +} + +module_init(stantum_init); +module_exit(stantum_exit); + -- GitLab From 92688c0c3c1c9e2daf705d307e8fda1b5a180d26 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 4 Jan 2010 12:04:59 +0100 Subject: [PATCH 0332/3892] HID: make Stantum driver standalone config option Analogically to commit "HID: make 3M PCT touchscreen driver standalone config option", remove the dependency of Stantum driver on CONFIG_EMBEDDED, as it is a standalone driver rather than device quirk. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 84272c690310..5f73774164d8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -248,7 +248,7 @@ config HID_SONY Support for Sony PS3 controller. config HID_STANTUM - tristate "Stantum" if EMBEDDED + tristate "Stantum" depends on USB_HID ---help--- Support for Stantum multitouch panel. -- GitLab From cf2f765f1896064e34c6f0f2ef896ff058dd5c06 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 4 Jan 2010 12:20:56 +0100 Subject: [PATCH 0333/3892] HID: handle joysticks with large number of buttons Current HID code doesn't properly handle HID joysticks which have larger number of buttons than what fits into current range reserved for BTN_JOYSTICK. One such joystick reported to not work properly is Saitek X52 Pro Flight System. We can't extend the range to fit more buttons in, because of backwards compatibility reasons. Therefore this patch introduces a new BTN_TRIGGER_HAPPY range, and uses these to map the buttons which are over BTN_JOYSTICK limit. Acked-by: Dmitry Torokhov [for the input.h part] Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 7 ++++++- include/linux/input.h | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 5862b0f3b55d..dad7aae9c975 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -198,7 +198,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel switch (field->application) { case HID_GD_MOUSE: case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; + case HID_GD_JOYSTICK: + if (code <= 0xf) + code += BTN_JOYSTICK; + else + code += BTN_TRIGGER_HAPPY; + break; case HID_GD_GAMEPAD: code += 0x130; break; default: switch (field->physical) { diff --git a/include/linux/input.h b/include/linux/input.h index 7be8a6537b57..97f98ca9b040 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -597,6 +597,48 @@ struct input_absinfo { #define KEY_CAMERA_FOCUS 0x210 +#define BTN_TRIGGER_HAPPY 0x2c0 +#define BTN_TRIGGER_HAPPY1 0x2c0 +#define BTN_TRIGGER_HAPPY2 0x2c1 +#define BTN_TRIGGER_HAPPY3 0x2c2 +#define BTN_TRIGGER_HAPPY4 0x2c3 +#define BTN_TRIGGER_HAPPY5 0x2c4 +#define BTN_TRIGGER_HAPPY6 0x2c5 +#define BTN_TRIGGER_HAPPY7 0x2c6 +#define BTN_TRIGGER_HAPPY8 0x2c7 +#define BTN_TRIGGER_HAPPY9 0x2c8 +#define BTN_TRIGGER_HAPPY10 0x2c9 +#define BTN_TRIGGER_HAPPY11 0x2ca +#define BTN_TRIGGER_HAPPY12 0x2cb +#define BTN_TRIGGER_HAPPY13 0x2cc +#define BTN_TRIGGER_HAPPY14 0x2cd +#define BTN_TRIGGER_HAPPY15 0x2ce +#define BTN_TRIGGER_HAPPY16 0x2cf +#define BTN_TRIGGER_HAPPY17 0x2d0 +#define BTN_TRIGGER_HAPPY18 0x2d1 +#define BTN_TRIGGER_HAPPY19 0x2d2 +#define BTN_TRIGGER_HAPPY20 0x2d3 +#define BTN_TRIGGER_HAPPY21 0x2d4 +#define BTN_TRIGGER_HAPPY22 0x2d5 +#define BTN_TRIGGER_HAPPY23 0x2d6 +#define BTN_TRIGGER_HAPPY24 0x2d7 +#define BTN_TRIGGER_HAPPY25 0x2d8 +#define BTN_TRIGGER_HAPPY26 0x2d9 +#define BTN_TRIGGER_HAPPY27 0x2da +#define BTN_TRIGGER_HAPPY28 0x2db +#define BTN_TRIGGER_HAPPY29 0x2dc +#define BTN_TRIGGER_HAPPY30 0x2dd +#define BTN_TRIGGER_HAPPY31 0x2de +#define BTN_TRIGGER_HAPPY32 0x2df +#define BTN_TRIGGER_HAPPY33 0x2e0 +#define BTN_TRIGGER_HAPPY34 0x2e1 +#define BTN_TRIGGER_HAPPY35 0x2e2 +#define BTN_TRIGGER_HAPPY36 0x2e3 +#define BTN_TRIGGER_HAPPY37 0x2e4 +#define BTN_TRIGGER_HAPPY38 0x2e5 +#define BTN_TRIGGER_HAPPY39 0x2e6 +#define BTN_TRIGGER_HAPPY40 0x2e7 + /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x2ff -- GitLab From 71c3ebfdb27b50dcaef38b6f70da82b9142c5fb6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Jan 2010 15:21:31 +0100 Subject: [PATCH 0334/3892] netfilter: SNMP NAT: correct the size argument to kzalloc obj has type struct snmp_object **, not struct snmp_object *. But indeed it is not even clear why kmalloc is needed. The memory is freed by the end of the function, so the local variable of pointer type should be sufficient. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @disable sizeof_type_expr@ type T; T **x; @@ x = <+...sizeof( - T + *x )...+> // Signed-off-by: Julia Lawall Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_snmp_basic.c | 31 +++++++++----------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index d9521f6f9ed0..0b9c7ce3d6c5 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -1038,7 +1038,7 @@ static int snmp_parse_mangle(unsigned char *msg, unsigned int cls, con, tag, vers, pdutype; struct asn1_ctx ctx; struct asn1_octstr comm; - struct snmp_object **obj; + struct snmp_object *obj; if (debug > 1) hex_dump(msg, len); @@ -1148,43 +1148,34 @@ static int snmp_parse_mangle(unsigned char *msg, if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) return 0; - obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); - if (obj == NULL) { - if (net_ratelimit()) - printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__); - return 0; - } - while (!asn1_eoc_decode(&ctx, eoc)) { unsigned int i; - if (!snmp_object_decode(&ctx, obj)) { - if (*obj) { - kfree((*obj)->id); - kfree(*obj); + if (!snmp_object_decode(&ctx, &obj)) { + if (obj) { + kfree(obj->id); + kfree(obj); } - kfree(obj); return 0; } if (debug > 1) { printk(KERN_DEBUG "bsalg: object: "); - for (i = 0; i < (*obj)->id_len; i++) { + for (i = 0; i < obj->id_len; i++) { if (i > 0) printk("."); - printk("%lu", (*obj)->id[i]); + printk("%lu", obj->id[i]); } - printk(": type=%u\n", (*obj)->type); + printk(": type=%u\n", obj->type); } - if ((*obj)->type == SNMP_IPADDR) + if (obj->type == SNMP_IPADDR) mangle_address(ctx.begin, ctx.pointer - 4 , map, check); - kfree((*obj)->id); - kfree(*obj); + kfree(obj->id); + kfree(obj); } - kfree(obj); if (!asn1_eoc_decode(&ctx, eoc)) return 0; -- GitLab From 89bc7a0f64de7bed2e0bc68a23d75699a610cd37 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 4 Jan 2010 16:26:03 +0100 Subject: [PATCH 0335/3892] netfilter: xt_recent: save 8 bytes per htable Moving rnd_inited into the hole after the uint8 lets go of the uint32 rnd_inited was using, plus the padding that would follow the int group. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index dd16e404424f..5bdc1fbf3ad7 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -81,13 +81,13 @@ struct xt_hashlimit_htable { struct hlist_node node; /* global list of all htables */ atomic_t use; u_int8_t family; + bool rnd_initialized; struct hashlimit_cfg1 cfg; /* config */ /* used internally */ spinlock_t lock; /* lock for list_head */ u_int32_t rnd; /* random seed for hash */ - int rnd_initialized; unsigned int count; /* number entries in table */ struct timer_list timer; /* timer for gc */ @@ -150,7 +150,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, * the first hashtable entry */ if (!ht->rnd_initialized) { get_random_bytes(&ht->rnd, sizeof(ht->rnd)); - ht->rnd_initialized = 1; + ht->rnd_initialized = true; } if (ht->cfg.max && ht->count >= ht->cfg.max) { @@ -235,7 +235,7 @@ static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family) atomic_set(&hinfo->use, 1); hinfo->count = 0; hinfo->family = family; - hinfo->rnd_initialized = 0; + hinfo->rnd_initialized = false; spin_lock_init(&hinfo->lock); hinfo->pde = proc_create_data(minfo->name, 0, (family == NFPROTO_IPV4) ? @@ -296,7 +296,7 @@ static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) atomic_set(&hinfo->use, 1); hinfo->count = 0; hinfo->family = family; - hinfo->rnd_initialized = 0; + hinfo->rnd_initialized = false; spin_lock_init(&hinfo->lock); hinfo->pde = proc_create_data(minfo->name, 0, -- GitLab From 5191d50192ec1281e51cbcb5248cb2667ff4d896 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 4 Jan 2010 16:27:25 +0100 Subject: [PATCH 0336/3892] netfilter: xtables: do not grab random bytes at __init "It is deliberately not done in the init function, since we might not have sufficient random while booting." Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/netfilter/xt_NFQUEUE.c | 6 +++++- net/netfilter/xt_RATEEST.c | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index f28f6a5fc02d..12dcd7007c3e 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -28,6 +28,7 @@ MODULE_ALIAS("ip6t_NFQUEUE"); MODULE_ALIAS("arpt_NFQUEUE"); static u32 jhash_initval __read_mostly; +static bool rnd_inited __read_mostly; static unsigned int nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) @@ -90,6 +91,10 @@ static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) const struct xt_NFQ_info_v1 *info = par->targinfo; u32 maxid; + if (unlikely(!rnd_inited)) { + get_random_bytes(&jhash_initval, sizeof(jhash_initval)); + rnd_inited = true; + } if (info->queues_total == 0) { pr_err("NFQUEUE: number of total queues is 0\n"); return false; @@ -135,7 +140,6 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = { static int __init nfqueue_tg_init(void) { - get_random_bytes(&jhash_initval, sizeof(jhash_initval)); return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); } diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c index d80b8192e0d4..87ae97e5516f 100644 --- a/net/netfilter/xt_RATEEST.c +++ b/net/netfilter/xt_RATEEST.c @@ -23,6 +23,7 @@ static DEFINE_MUTEX(xt_rateest_mutex); #define RATEEST_HSIZE 16 static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly; static unsigned int jhash_rnd __read_mostly; +static bool rnd_inited __read_mostly; static unsigned int xt_rateest_hash(const char *name) { @@ -93,6 +94,11 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) struct gnet_estimator est; } cfg; + if (unlikely(!rnd_inited)) { + get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); + rnd_inited = true; + } + est = xt_rateest_lookup(info->name); if (est) { /* @@ -164,7 +170,6 @@ static int __init xt_rateest_tg_init(void) for (i = 0; i < ARRAY_SIZE(rateest_hash); i++) INIT_HLIST_HEAD(&rateest_hash[i]); - get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); return xt_register_target(&xt_rateest_tg_reg); } -- GitLab From 294188ae32f984a072c64c959354b2f6f52f80a7 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 4 Jan 2010 16:28:38 +0100 Subject: [PATCH 0337/3892] netfilter: xtables: obtain random bytes earlier, in checkentry We can initialize the random hash bytes on checkentry. This is preferable since it is outside the hot path. Reference: http://bugzilla.netfilter.org/show_bug.cgi?id=621 Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/netfilter/xt_connlimit.c | 17 ++++++----------- net/netfilter/xt_recent.c | 20 ++++++++------------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 38f03f75a636..8103bef78e44 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -40,15 +40,11 @@ struct xt_connlimit_data { spinlock_t lock; }; -static u_int32_t connlimit_rnd; -static bool connlimit_rnd_inited; +static u_int32_t connlimit_rnd __read_mostly; +static bool connlimit_rnd_inited __read_mostly; static inline unsigned int connlimit_iphash(__be32 addr) { - if (unlikely(!connlimit_rnd_inited)) { - get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); - connlimit_rnd_inited = true; - } return jhash_1word((__force __u32)addr, connlimit_rnd) & 0xFF; } @@ -59,11 +55,6 @@ connlimit_iphash6(const union nf_inet_addr *addr, union nf_inet_addr res; unsigned int i; - if (unlikely(!connlimit_rnd_inited)) { - get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); - connlimit_rnd_inited = true; - } - for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i) res.ip6[i] = addr->ip6[i] & mask->ip6[i]; @@ -226,6 +217,10 @@ static bool connlimit_mt_check(const struct xt_mtchk_param *par) struct xt_connlimit_info *info = par->matchinfo; unsigned int i; + if (unlikely(!connlimit_rnd_inited)) { + get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); + connlimit_rnd_inited = true; + } if (nf_ct_l3proto_try_module_get(par->family) < 0) { printk(KERN_WARNING "cannot load conntrack support for " "address family %u\n", par->family); diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index fc70a49c0afd..768d01ff1fea 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -90,25 +90,17 @@ static struct proc_dir_entry *recent_proc_dir; static const struct file_operations recent_old_fops, recent_mt_fops; #endif -static u_int32_t hash_rnd; -static bool hash_rnd_initted; +static u_int32_t hash_rnd __read_mostly; +static bool hash_rnd_inited __read_mostly; -static unsigned int recent_entry_hash4(const union nf_inet_addr *addr) +static inline unsigned int recent_entry_hash4(const union nf_inet_addr *addr) { - if (!hash_rnd_initted) { - get_random_bytes(&hash_rnd, sizeof(hash_rnd)); - hash_rnd_initted = true; - } return jhash_1word((__force u32)addr->ip, hash_rnd) & (ip_list_hash_size - 1); } -static unsigned int recent_entry_hash6(const union nf_inet_addr *addr) +static inline unsigned int recent_entry_hash6(const union nf_inet_addr *addr) { - if (!hash_rnd_initted) { - get_random_bytes(&hash_rnd, sizeof(hash_rnd)); - hash_rnd_initted = true; - } return jhash2((u32 *)addr->ip6, ARRAY_SIZE(addr->ip6), hash_rnd) & (ip_list_hash_size - 1); } @@ -287,6 +279,10 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) unsigned i; bool ret = false; + if (unlikely(!hash_rnd_inited)) { + get_random_bytes(&hash_rnd, sizeof(hash_rnd)); + hash_rnd_inited = true; + } if (hweight8(info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE | XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1) -- GitLab From a126fd5691e6cd680758b72e6ea288bb83b9deb6 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Mon, 4 Jan 2010 14:30:03 +0200 Subject: [PATCH 0338/3892] ASoc: tpa6130a2: Remove unnecessary variable Signed-off-by: Ilkka Koskinen Acked-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 0eb33d49942e..8e98ccfab75c 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -267,12 +267,8 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { */ static void tpa6130a2_channel_enable(u8 channel, int enable) { - struct tpa6130a2_data *data; u8 val; - BUG_ON(tpa6130a2_client == NULL); - data = i2c_get_clientdata(tpa6130a2_client); - if (enable) { /* Enable channel */ /* Enable amplifier */ -- GitLab From 51633632ef614ef045f25d76fc7f0133d7cc60c6 Mon Sep 17 00:00:00 2001 From: Juha Leppanen Date: Mon, 4 Jan 2010 15:52:50 -0500 Subject: [PATCH 0339/3892] wl1271: fix timeout in wl1271_top_reg_read I noticed a timeout bug in /drivers/net/wireless/wl12xx/wl1271_spi.c In the current code you cannot tell why you exited the "poll for data ready" do-while loop if exiting was done after the last possible loop. Then timeout==0 regardless of (val & OCP_READY_MASK) or !(val & OCP_READY_MASK), leading to possible false timeout... Simple correction could be decreasing timeout after checking for !(val & OCP_READY_MASK), not before (Manually converted from email to an actual patch by me. -- JWL) Reported-by: "Juha Leppanen" Signed-off-by: "Juha Leppanen" Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 02978a16e732..ee9564aa6ecc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -397,8 +397,7 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) /* poll for data ready */ do { val = wl1271_spi_read32(wl, OCP_DATA_READ); - timeout--; - } while (!(val & OCP_READY_MASK) && timeout); + } while (!(val & OCP_READY_MASK) && --timeout); if (!timeout) { wl1271_warning("Top register access timed out."); -- GitLab From e5eb8bd9429ebd04cf906156d1fe40b52f88e82f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 4 Jan 2010 15:58:03 -0500 Subject: [PATCH 0340/3892] mac80211: fix typo added by "mac80211: fix propagation of failed..." 'Typo: it's "Hardware", not "Harware". Hmm, sometimes it's hairware :-)"' -- Holger Schurig Reported-by: Holger Schurig Signed-off-by: John W. Linville --- net/mac80211/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7e38858a9280..29e1acca207c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1094,7 +1094,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (res) { WARN(local->suspended, "Harware became unavailable " "upon resume. This is could be a software issue" - "prior to suspend or a harware issue\n"); + "prior to suspend or a hardware issue\n"); return res; } -- GitLab From 5baf831541c61546c00e8d6f294cb10ed5d25e7d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Jan 2010 13:13:42 +0000 Subject: [PATCH 0341/3892] ASoC: Fix variable shadowing warning in TLV320AIC3x Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/tlv320aic3x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5a8f53ce2250..e4b946a19ea3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -849,20 +849,20 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, * The term had to be converted to get * rid of the division by 10000; d = 0 here */ - int clk = (1000 * j * r) / p; + int tmp_clk = (1000 * j * r) / p; /* Check whether this values get closer than * the best ones we had before */ - if (abs(codec_clk - clk) < + if (abs(codec_clk - tmp_clk) < abs(codec_clk - last_clk)) { pll_j = j; pll_d = 0; pll_r = r; pll_p = p; - last_clk = clk; + last_clk = tmp_clk; } /* Early exit for exact matches */ - if (clk == codec_clk) + if (tmp_clk == codec_clk) goto found; } } -- GitLab From d11c5ab186310389b8e573be00279bab0a565d30 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Jan 2010 13:14:07 +0000 Subject: [PATCH 0342/3892] ASoC: Only restore non-default registers for WM8731 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8731.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 3a497810f939..5a2619dbf283 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -456,6 +456,9 @@ static int wm8731_resume(struct platform_device *pdev) /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { + if (cache[i] == wm8731_reg[i]) + continue; + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); data[1] = cache[i] & 0x00ff; codec->hw_write(codec->control_data, data, 2); -- GitLab From e0fb28e079b50f891b6c9db1c2bb25fef3268cf4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Jan 2010 13:14:23 +0000 Subject: [PATCH 0343/3892] ASoC: Only restore non-default registers for WM8776 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8776.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ab2c0da18091..44e7d9d82f87 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -406,6 +406,8 @@ static int wm8776_resume(struct platform_device *pdev) /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) { + if (cache[i] == wm8776_reg[i]) + continue; data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); data[1] = cache[i] & 0x00ff; codec->hw_write(codec->control_data, data, 2); -- GitLab From 10505634bfa74871118a21eef8617acad00e4019 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Jan 2010 13:14:45 +0000 Subject: [PATCH 0344/3892] ASoC: Only restore non-default registers for WM8961 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8961.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a8007d58813f..d2342c5e0425 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1022,6 +1022,9 @@ static int wm8961_resume(struct platform_device *pdev) int i; for (i = 0; i < codec->reg_cache_size; i++) { + if (reg_cache[i] == wm8961_reg_defaults[i]) + continue; + if (i == WM8961_SOFTWARE_RESET) continue; -- GitLab From 53242c68333570631a15a69842851b458eca3d99 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Jan 2010 13:15:56 +0000 Subject: [PATCH 0345/3892] ASoC: Implement suspend and resume for WM8993 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 5e32f2ed5fc2..cd2bc05f78cc 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -227,6 +227,7 @@ struct wm8993_priv { int class_w_users; unsigned int fll_fref; unsigned int fll_fout; + int fll_src; }; static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg) @@ -506,6 +507,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, wm8993->fll_fref = Fref; wm8993->fll_fout = Fout; + wm8993->fll_src = source; return 0; } @@ -1480,9 +1482,74 @@ static int wm8993_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int wm8993_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8993_priv *wm8993 = codec->private_data; + int fll_fout = wm8993->fll_fout; + int fll_fref = wm8993->fll_fref; + int ret; + + /* Stop the FLL in an orderly fashion */ + ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to stop FLL\n"); + return ret; + } + + wm8993->fll_fout = fll_fout; + wm8993->fll_fref = fll_fref; + + wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8993_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8993_priv *wm8993 = codec->private_data; + u16 *cache = wm8993->reg_cache; + int i, ret; + + /* Restore the register settings */ + for (i = 1; i < WM8993_MAX_REGISTER; i++) { + if (cache[i] == wm8993_reg_defaults[i]) + continue; + snd_soc_write(codec, i, cache[i]); + } + + wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Restart the FLL? */ + if (wm8993->fll_fout) { + int fll_fout = wm8993->fll_fout; + int fll_fref = wm8993->fll_fref; + + wm8993->fll_fref = 0; + wm8993->fll_fout = 0; + + ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src, + fll_fref, fll_fout); + if (ret != 0) + dev_err(codec->dev, "Failed to restart FLL\n"); + } + + return 0; +} +#else +#define wm8993_suspend NULL +#define wm8993_resume NULL +#endif + struct snd_soc_codec_device soc_codec_dev_wm8993 = { .probe = wm8993_probe, .remove = wm8993_remove, + .suspend = wm8993_suspend, + .resume = wm8993_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993); -- GitLab From 0176bd3dab4fe522bfb6ceab9e3c441fe0305738 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 5 Jan 2010 12:35:00 +0900 Subject: [PATCH 0346/3892] sh: Drop down to a single quicklist. We previously had 2 quicklists, one for the PGD case and one for PTEs. Now that the PGD/PMD cases are handled through slab caches due to the multi-level configurability, only the PTE quicklist remains. As such, reduce NR_QUICK to its appropriate size and bump down the PTE quicklist index. Signed-off-by: Paul Mundt --- arch/sh/include/asm/pgalloc.h | 2 +- mm/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h index e106474996b2..f8982f4e0405 100644 --- a/arch/sh/include/asm/pgalloc.h +++ b/arch/sh/include/asm/pgalloc.h @@ -4,7 +4,7 @@ #include #include -#define QUICK_PT 1 /* Other page table pages that are zero on free */ +#define QUICK_PT 0 /* Other page table pages that are zero on free */ extern pgd_t *pgd_alloc(struct mm_struct *); extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); diff --git a/mm/Kconfig b/mm/Kconfig index 17b8947aa7da..d34c2b971032 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -195,7 +195,7 @@ config BOUNCE config NR_QUICK int depends on QUICKLIST - default "2" if SUPERH || AVR32 + default "2" if AVR32 default "1" config VIRT_TO_BUS -- GitLab From c4761815ab49feca904776dec464046bc7138d3a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 5 Jan 2010 12:44:02 +0900 Subject: [PATCH 0347/3892] sh: Fix up breakpoint trap handler patching on SH-2A. SH-2A was referencing the old handler that no longer exists, fix it up. Signed-off-by: Paul Mundt --- arch/sh/kernel/traps_32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 86639beac3a2..706c1c18a2f2 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -956,7 +956,7 @@ void __init trap_init(void) #endif #ifdef TRAP_UBC - set_exception_table_vec(TRAP_UBC, break_point_trap); + set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler); #endif /* Setup VBR for boot cpu */ -- GitLab From 6f7edb4881bf51300060e89915926e070ace8c4d Mon Sep 17 00:00:00 2001 From: "Catalin(ux) M. BOIE" Date: Tue, 5 Jan 2010 05:50:24 +0100 Subject: [PATCH 0348/3892] IPVS: Allow boot time change of hash size I was very frustrated about the fact that I have to recompile the kernel to change the hash size. So, I created this patch. If IPVS is built-in you can append ip_vs.conn_tab_bits=?? to kernel command line, or, if you built IPVS as modules, you can add options ip_vs conn_tab_bits=??. To keep everything backward compatible, you still can select the size at compile time, and that will be used as default. It has been about a year since this patch was originally posted and subsequently dropped on the basis of insufficient test data. Mark Bergsma has provided the following test results which seem to strongly support the need for larger hash table sizes: We do however run into the same problem with the default setting (212 = 4096 entries), as most of our LVS balancers handle around a million connections/SLAB entries at any point in time (around 100-150 kpps load). With only 4096 hash table entries this implies that each entry consists of a linked list of 256 connections *on average*. To provide some statistics, I did an oprofile run on an 2.6.31 kernel, with both the default 4096 table size, and the same kernel recompiled with IP_VS_CONN_TAB_BITS set to 18 (218 = 262144 entries). I built a quick test setup with a part of Wikimedia/Wikipedia's live traffic mirrored by the switch to the test host. With the default setting, at ~ 120 kpps packet load we saw a typical %si CPU usage of around 30-35%, and oprofile reported a hot spot in ip_vs_conn_in_get: samples % image name app name symbol name 1719761 42.3741 ip_vs.ko ip_vs.ko ip_vs_conn_in_get 302577 7.4554 bnx2 bnx2 /bnx2 181984 4.4840 vmlinux vmlinux __ticket_spin_lock 128636 3.1695 vmlinux vmlinux ip_route_input 74345 1.8318 ip_vs.ko ip_vs.ko ip_vs_conn_out_get 68482 1.6874 vmlinux vmlinux mwait_idle After loading the recompiled kernel with 218 entries, %si CPU usage dropped in half to around 12-18%, and oprofile looks much healthier, with only 7% spent in ip_vs_conn_in_get: samples % image name app name symbol name 265641 14.4616 bnx2 bnx2 /bnx2 143251 7.7986 vmlinux vmlinux __ticket_spin_lock 140661 7.6576 ip_vs.ko ip_vs.ko ip_vs_conn_in_get 94364 5.1372 vmlinux vmlinux mwait_idle 86267 4.6964 vmlinux vmlinux ip_route_input [ horms@verge.net.au: trivial up-port and minor style fixes ] Signed-off-by: Catalin(ux) M. BOIE Cc: Mark Bergsma Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy --- include/net/ip_vs.h | 16 ++++--------- net/netfilter/ipvs/Kconfig | 4 ++++ net/netfilter/ipvs/ip_vs_conn.c | 42 ++++++++++++++++++++++++--------- net/netfilter/ipvs/ip_vs_ctl.c | 8 +++---- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 8dc3296b7bea..a816c37417bb 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -26,6 +26,11 @@ #include /* for struct ipv6hdr */ #include /* for ipv6_addr_copy */ + +/* Connections' size value needed by ip_vs_ctl.c */ +extern int ip_vs_conn_tab_size; + + struct ip_vs_iphdr { int len; __u8 protocol; @@ -592,17 +597,6 @@ extern void ip_vs_init_hash_table(struct list_head *table, int rows); * (from ip_vs_conn.c) */ -/* - * IPVS connection entry hash table - */ -#ifndef CONFIG_IP_VS_TAB_BITS -#define CONFIG_IP_VS_TAB_BITS 12 -#endif - -#define IP_VS_CONN_TAB_BITS CONFIG_IP_VS_TAB_BITS -#define IP_VS_CONN_TAB_SIZE (1 << IP_VS_CONN_TAB_BITS) -#define IP_VS_CONN_TAB_MASK (IP_VS_CONN_TAB_SIZE - 1) - enum { IP_VS_DIR_INPUT = 0, IP_VS_DIR_OUTPUT, diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index 79a698052218..c71e543d2549 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig @@ -68,6 +68,10 @@ config IP_VS_TAB_BITS each hash entry uses 8 bytes, so you can estimate how much memory is needed for your box. + You can overwrite this number setting conn_tab_bits module parameter + or by appending ip_vs.conn_tab_bits=? to the kernel command line + if IP VS was compiled built-in. + comment "IPVS transport protocol load balancing support" config IP_VS_PROTO_TCP diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 27c30cf933da..60bb41a8d8d4 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -40,6 +40,21 @@ #include +#ifndef CONFIG_IP_VS_TAB_BITS +#define CONFIG_IP_VS_TAB_BITS 12 +#endif + +/* + * Connection hash size. Default is what was selected at compile time. +*/ +int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; +module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444); +MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size"); + +/* size and mask values */ +int ip_vs_conn_tab_size; +int ip_vs_conn_tab_mask; + /* * Connection hash table: for input and output packets lookups of IPVS */ @@ -125,11 +140,11 @@ static unsigned int ip_vs_conn_hashkey(int af, unsigned proto, if (af == AF_INET6) return jhash_3words(jhash(addr, 16, ip_vs_conn_rnd), (__force u32)port, proto, ip_vs_conn_rnd) - & IP_VS_CONN_TAB_MASK; + & ip_vs_conn_tab_mask; #endif return jhash_3words((__force u32)addr->ip, (__force u32)port, proto, ip_vs_conn_rnd) - & IP_VS_CONN_TAB_MASK; + & ip_vs_conn_tab_mask; } @@ -760,7 +775,7 @@ static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos) int idx; struct ip_vs_conn *cp; - for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) { + for (idx = 0; idx < ip_vs_conn_tab_size; idx++) { ct_read_lock_bh(idx); list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) { if (pos-- == 0) { @@ -797,7 +812,7 @@ static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos) idx = l - ip_vs_conn_tab; ct_read_unlock_bh(idx); - while (++idx < IP_VS_CONN_TAB_SIZE) { + while (++idx < ip_vs_conn_tab_size) { ct_read_lock_bh(idx); list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) { seq->private = &ip_vs_conn_tab[idx]; @@ -976,8 +991,8 @@ void ip_vs_random_dropentry(void) /* * Randomly scan 1/32 of the whole table every second */ - for (idx = 0; idx < (IP_VS_CONN_TAB_SIZE>>5); idx++) { - unsigned hash = net_random() & IP_VS_CONN_TAB_MASK; + for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) { + unsigned hash = net_random() & ip_vs_conn_tab_mask; /* * Lock is actually needed in this loop. @@ -1029,7 +1044,7 @@ static void ip_vs_conn_flush(void) struct ip_vs_conn *cp; flush_again: - for (idx=0; idx Date: Tue, 5 Jan 2010 19:06:45 +0900 Subject: [PATCH 0349/3892] sh: Abstracted SH-4A UBC support on hw-breakpoint core. This is the next big chunk of hw_breakpoint support. This decouples the SH-4A support from the core and moves it out in to its own stub, following many of the conventions established with the perf events layering. In addition to extending SH-4A support to encapsulate the remainder of the UBC channels, clock framework support for handling the UBC interface clock is added as well, allowing for dynamic clock gating. This also fixes up a regression introduced by the SIGTRAP handling that broke the ksym_tracer, to the extent that the current support works well with all of the ksym_tracer/ptrace/kgdb. The kprobes singlestep code will follow in turn. With this in place, the remaining UBC variants (SH-2A and SH-4) can now be trivially plugged in. Signed-off-by: Paul Mundt --- arch/sh/include/asm/hw_breakpoint.h | 22 +++- arch/sh/include/asm/processor_32.h | 4 +- arch/sh/kernel/cpu/sh4a/Makefile | 9 +- arch/sh/kernel/cpu/sh4a/ubc.c | 133 ++++++++++++++++++++++ arch/sh/kernel/hw_breakpoint.c | 164 ++++++++++++++++------------ 5 files changed, 254 insertions(+), 78 deletions(-) create mode 100644 arch/sh/kernel/cpu/sh4a/ubc.c diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h index 0f4a00f60058..7295d6290249 100644 --- a/arch/sh/include/asm/hw_breakpoint.h +++ b/arch/sh/include/asm/hw_breakpoint.h @@ -3,7 +3,6 @@ #include #include -#include #ifdef __KERNEL__ #define __ARCH_HW_BREAKPOINT_H @@ -11,7 +10,6 @@ struct arch_hw_breakpoint { char *name; /* Contains name of the symbol to set bkpt */ unsigned long address; - unsigned long asid; u16 len; u16 type; }; @@ -27,13 +25,28 @@ enum { SH_BREAKPOINT_LEN_8 = (1 << 14), }; -/* Total number of available UBC channels */ -#define HBP_NUM 1 /* XXX */ +struct sh_ubc { + const char *name; + unsigned int num_events; + unsigned int trap_nr; + void (*enable)(struct arch_hw_breakpoint *, int); + void (*disable)(struct arch_hw_breakpoint *, int); + void (*enable_all)(unsigned long); + void (*disable_all)(void); + unsigned long (*active_mask)(void); + unsigned long (*triggered_mask)(void); + void (*clear_triggered_mask)(unsigned long); + struct clk *clk; /* optional interface clock / MSTP bit */ +}; struct perf_event; struct task_struct; struct pmu; +/* Maximum number of UBC channels */ +#define HBP_NUM 2 + +/* arch/sh/kernel/hw_breakpoint.c */ extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len); extern int arch_validate_hwbkpt_settings(struct perf_event *bp, struct task_struct *tsk); @@ -46,6 +59,7 @@ void hw_breakpoint_pmu_read(struct perf_event *bp); void hw_breakpoint_pmu_unthrottle(struct perf_event *bp); extern void arch_fill_perf_breakpoint(struct perf_event *bp); +extern int register_sh_ubc(struct sh_ubc *); extern struct pmu perf_ops_bp; diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index d60b28271a05..259112cecbdf 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include /* * Default implementation of macro that returns current @@ -102,7 +102,7 @@ struct thread_struct { unsigned long pc; /* Save middle states of ptrace breakpoints */ - struct perf_event *ptrace_bps[NR_UBC_CHANNELS]; + struct perf_event *ptrace_bps[HBP_NUM]; /* floating point info */ union sh_fpu_union fpu; diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index 33bab477d2e2..b144e8af89dc 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile @@ -41,7 +41,8 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o -obj-y += $(clock-y) -obj-$(CONFIG_SMP) += $(smp-y) -obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) -obj-$(CONFIG_PERF_EVENTS) += perf_event.o +obj-y += $(clock-y) +obj-$(CONFIG_SMP) += $(smp-y) +obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) +obj-$(CONFIG_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += ubc.o diff --git a/arch/sh/kernel/cpu/sh4a/ubc.c b/arch/sh/kernel/cpu/sh4a/ubc.c new file mode 100644 index 000000000000..efb2745bcb36 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/ubc.c @@ -0,0 +1,133 @@ +/* + * arch/sh/kernel/cpu/sh4a/ubc.c + * + * On-chip UBC support for SH-4A CPUs. + * + * Copyright (C) 2009 - 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +#define UBC_CBR(idx) (0xff200000 + (0x20 * idx)) +#define UBC_CRR(idx) (0xff200004 + (0x20 * idx)) +#define UBC_CAR(idx) (0xff200008 + (0x20 * idx)) +#define UBC_CAMR(idx) (0xff20000c + (0x20 * idx)) + +#define UBC_CCMFR 0xff200600 +#define UBC_CBCR 0xff200620 + +/* CRR */ +#define UBC_CRR_PCB (1 << 1) +#define UBC_CRR_BIE (1 << 0) + +/* CBR */ +#define UBC_CBR_CE (1 << 0) + +static struct sh_ubc sh4a_ubc; + +static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx) +{ + __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx)); + __raw_writel(info->address, UBC_CAR(idx)); +} + +static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx) +{ + __raw_writel(0, UBC_CBR(idx)); + __raw_writel(0, UBC_CAR(idx)); +} + +static void sh4a_ubc_enable_all(unsigned long mask) +{ + int i; + + for (i = 0; i < sh4a_ubc.num_events; i++) + if (mask & (1 << i)) + __raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE, + UBC_CBR(i)); +} + +static void sh4a_ubc_disable_all(void) +{ + int i; + + for (i = 0; i < sh4a_ubc.num_events; i++) + __raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE, + UBC_CBR(i)); +} + +static unsigned long sh4a_ubc_active_mask(void) +{ + unsigned long active = 0; + int i; + + for (i = 0; i < sh4a_ubc.num_events; i++) + if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE) + active |= (1 << i); + + return active; +} + +static unsigned long sh4a_ubc_triggered_mask(void) +{ + return __raw_readl(UBC_CCMFR); +} + +static void sh4a_ubc_clear_triggered_mask(unsigned long mask) +{ + __raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR); +} + +static struct sh_ubc sh4a_ubc = { + .name = "SH-4A", + .num_events = 2, + .trap_nr = 0x1e0, + .enable = sh4a_ubc_enable, + .disable = sh4a_ubc_disable, + .enable_all = sh4a_ubc_enable_all, + .disable_all = sh4a_ubc_disable_all, + .active_mask = sh4a_ubc_active_mask, + .triggered_mask = sh4a_ubc_triggered_mask, + .clear_triggered_mask = sh4a_ubc_clear_triggered_mask, +}; + +static int __init sh4a_ubc_init(void) +{ + struct clk *ubc_iclk = clk_get(NULL, "ubc0"); + int i; + + /* + * The UBC MSTP bit is optional, as not all platforms will have + * it. Just ignore it if we can't find it. + */ + if (IS_ERR(ubc_iclk)) + ubc_iclk = NULL; + + clk_enable(ubc_iclk); + + __raw_writel(0, UBC_CBCR); + + for (i = 0; i < sh4a_ubc.num_events; i++) { + __raw_writel(0, UBC_CAMR(i)); + __raw_writel(0, UBC_CBR(i)); + + __raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i)); + + /* dummy read for write posting */ + (void)__raw_readl(UBC_CRR(i)); + } + + clk_disable(ubc_iclk); + + sh4a_ubc.clk = ubc_iclk; + + return register_sh_ubc(&sh4a_ubc); +} +arch_initcall(sh4a_ubc_init); diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c index c515a3ecf562..e2f1753d275c 100644 --- a/arch/sh/kernel/hw_breakpoint.c +++ b/arch/sh/kernel/hw_breakpoint.c @@ -3,7 +3,7 @@ * * Unified kernel/user-space hardware breakpoint facility for the on-chip UBC. * - * Copyright (C) 2009 Paul Mundt + * Copyright (C) 2009 - 2010 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -18,38 +18,24 @@ #include #include #include +#include #include #include #include -struct ubc_context { - unsigned long pc; - unsigned long state; -}; - -/* Per cpu ubc channel state */ -static DEFINE_PER_CPU(struct ubc_context, ubc_ctx[HBP_NUM]); - /* * Stores the breakpoints currently in use on each breakpoint address * register for each cpus */ static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]); -static int __init ubc_init(void) -{ - __raw_writel(0, UBC_CAMR0); - __raw_writel(0, UBC_CBR0); - __raw_writel(0, UBC_CBCR); - - __raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR0); - - /* dummy read for write posting */ - (void)__raw_readl(UBC_CRR0); +/* + * A dummy placeholder for early accesses until the CPUs get a chance to + * register their UBCs later in the boot process. + */ +static struct sh_ubc ubc_dummy = { .num_events = 0 }; - return 0; -} -arch_initcall(ubc_init); +static struct sh_ubc *sh_ubc __read_mostly = &ubc_dummy; /* * Install a perf counter breakpoint. @@ -62,10 +48,9 @@ arch_initcall(ubc_init); int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); - struct ubc_context *ubc_ctx; int i; - for (i = 0; i < HBP_NUM; i++) { + for (i = 0; i < sh_ubc->num_events; i++) { struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); if (!*slot) { @@ -74,16 +59,11 @@ int arch_install_hw_breakpoint(struct perf_event *bp) } } - if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot")) + if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot")) return -EBUSY; - ubc_ctx = &__get_cpu_var(ubc_ctx[i]); - - ubc_ctx->pc = info->address; - ubc_ctx->state = info->len | info->type; - - __raw_writel(UBC_CBR_CE | ubc_ctx->state, UBC_CBR0); - __raw_writel(ubc_ctx->pc, UBC_CAR0); + clk_enable(sh_ubc->clk); + sh_ubc->enable(info, i); return 0; } @@ -100,10 +80,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp) void arch_uninstall_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); - struct ubc_context *ubc_ctx; int i; - for (i = 0; i < HBP_NUM; i++) { + for (i = 0; i < sh_ubc->num_events; i++) { struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); if (*slot == bp) { @@ -112,15 +91,11 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) } } - if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot")) + if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot")) return; - ubc_ctx = &__get_cpu_var(ubc_ctx[i]); - ubc_ctx->pc = 0; - ubc_ctx->state &= ~(info->len | info->type); - - __raw_writel(ubc_ctx->pc, UBC_CBR0); - __raw_writel(ubc_ctx->state, UBC_CAR0); + sh_ubc->disable(info, i); + clk_disable(sh_ubc->clk); } static int get_hbp_len(u16 hbp_len) @@ -182,10 +157,8 @@ static int arch_store_info(struct perf_event *bp) */ if (info->name) info->address = (unsigned long)kallsyms_lookup_name(info->name); - if (info->address) { - info->asid = get_asid(); + if (info->address) return 0; - } return -EINVAL; } @@ -335,7 +308,7 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk) int i; struct thread_struct *t = &tsk->thread; - for (i = 0; i < HBP_NUM; i++) { + for (i = 0; i < sh_ubc->num_events; i++) { unregister_hw_breakpoint(t->ptrace_bps[i]); t->ptrace_bps[i] = NULL; } @@ -345,13 +318,32 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) { int cpu, i, rc = NOTIFY_STOP; struct perf_event *bp; - unsigned long val; + unsigned int cmf, resume_mask; + + /* + * Do an early return if none of the channels triggered. + */ + cmf = sh_ubc->triggered_mask(); + if (unlikely(!cmf)) + return NOTIFY_DONE; + + /* + * By default, resume all of the active channels. + */ + resume_mask = sh_ubc->active_mask(); - val = __raw_readl(UBC_CBR0); - __raw_writel(val & ~UBC_CBR_CE, UBC_CBR0); + /* + * Disable breakpoints during exception handling. + */ + sh_ubc->disable_all(); cpu = get_cpu(); - for (i = 0; i < HBP_NUM; i++) { + for (i = 0; i < sh_ubc->num_events; i++) { + unsigned long event_mask = (1 << i); + + if (likely(!(cmf & event_mask))) + continue; + /* * The counter may be concurrently released but that can only * occur from a call_rcu() path. We can then safely fetch @@ -361,24 +353,52 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_lock(); bp = per_cpu(bp_per_reg[i], cpu); - if (bp) { + if (bp) rc = NOTIFY_DONE; - } else { + + /* + * Reset the condition match flag to denote completion of + * exception handling. + */ + sh_ubc->clear_triggered_mask(event_mask); + + /* + * bp can be NULL due to concurrent perf counter + * removing. + */ + if (!bp) { rcu_read_unlock(); break; } + /* + * Don't restore the channel if the breakpoint is from + * ptrace, as it always operates in one-shot mode. + */ + if (bp->overflow_handler == ptrace_triggered) + resume_mask &= ~(1 << i); + perf_bp_event(bp, args->regs); + /* Deliver the signal to userspace */ + if (arch_check_va_in_userspace(bp->attr.bp_addr, + bp->attr.bp_len)) { + siginfo_t info; + + info.si_signo = args->signr; + info.si_errno = notifier_to_errno(rc); + info.si_code = TRAP_HWBKPT; + + force_sig_info(args->signr, &info, current); + } + rcu_read_unlock(); } - if (bp && bp->overflow_handler != ptrace_triggered) { - struct arch_hw_breakpoint *info = counter_arch_bp(bp); + if (cmf == 0) + rc = NOTIFY_DONE; - __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0); - __raw_writel(info->address, UBC_CAR0); - } + sh_ubc->enable_all(resume_mask); put_cpu(); @@ -388,19 +408,9 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) BUILD_TRAP_HANDLER(breakpoint) { unsigned long ex = lookup_exception_vector(); - siginfo_t info; - int err; TRAP_HANDLER_DECL; - err = notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); - if (err == NOTIFY_STOP) - return; - - /* Deliver the signal to userspace */ - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_HWBKPT; - force_sig_info(SIGTRAP, &info, current); + notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); } /* @@ -417,8 +427,12 @@ int __kprobes hw_breakpoint_exceptions_notify(struct notifier_block *unused, /* * If the breakpoint hasn't been triggered by the UBC, it's * probably from a debugger, so don't do anything more here. + * + * This also permits the UBC interface clock to remain off for + * non-UBC breakpoints, as we don't need to check the triggered + * or active channel masks. */ - if (args->trapnr != 0x1e0) + if (args->trapnr != sh_ubc->trap_nr) return NOTIFY_DONE; return hw_breakpoint_handler(data); @@ -433,3 +447,17 @@ void hw_breakpoint_pmu_unthrottle(struct perf_event *bp) { /* TODO */ } + +int register_sh_ubc(struct sh_ubc *ubc) +{ + /* Bail if it's already assigned */ + if (sh_ubc != &ubc_dummy) + return -EBUSY; + sh_ubc = ubc; + + pr_info("HW Breakpoints: %s UBC support registered\n", ubc->name); + + WARN_ON(ubc->num_events > HBP_NUM); + + return 0; +} -- GitLab From 7025bec9125b0a02edcaf22c2dce753bf2c95480 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 5 Jan 2010 19:16:35 +0900 Subject: [PATCH 0350/3892] sh: Kill off dead UBC headers. Nothing is using these now, so kill them all off. Signed-off-by: Paul Mundt --- arch/sh/include/asm/ubc.h | 70 ------------------------------- arch/sh/include/cpu-sh2/cpu/ubc.h | 32 -------------- arch/sh/include/cpu-sh3/cpu/ubc.h | 42 ------------------- arch/sh/include/cpu-sh4/cpu/ubc.h | 64 ---------------------------- arch/sh/kernel/cpu/init.c | 20 ++++----- arch/sh/kernel/process_32.c | 1 - 6 files changed, 8 insertions(+), 221 deletions(-) delete mode 100644 arch/sh/include/asm/ubc.h delete mode 100644 arch/sh/include/cpu-sh2/cpu/ubc.h delete mode 100644 arch/sh/include/cpu-sh3/cpu/ubc.h delete mode 100644 arch/sh/include/cpu-sh4/cpu/ubc.h diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h deleted file mode 100644 index e3c2968b04d3..000000000000 --- a/arch/sh/include/asm/ubc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * include/asm-sh/ubc.h - * - * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2002, 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#ifndef __ASM_SH_UBC_H -#define __ASM_SH_UBC_H - -#ifdef __KERNEL__ -#include - -/* User Break Controller */ -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -#define UBC_TYPE_SH7729 (current_cpu_data.type == CPU_SH7729) -#else -#define UBC_TYPE_SH7729 0 -#endif - -#define BAMR_ASID (1 << 2) -#define BAMR_NONE 0 -#define BAMR_10 0x1 -#define BAMR_12 0x2 -#define BAMR_ALL 0x3 -#define BAMR_16 0x8 -#define BAMR_20 0x9 - -#define BBR_INST (1 << 4) -#define BBR_DATA (2 << 4) -#define BBR_READ (1 << 2) -#define BBR_WRITE (2 << 2) -#define BBR_BYTE 0x1 -#define BBR_HALF 0x2 -#define BBR_LONG 0x3 -#define BBR_QUAD (1 << 6) /* SH7750 */ -#define BBR_CPU (1 << 6) /* SH7709A,SH7729 */ -#define BBR_DMA (2 << 6) /* SH7709A,SH7729 */ - -#define BRCR_CMFA (1 << 15) -#define BRCR_CMFB (1 << 14) - -#if defined CONFIG_CPU_SH2A -#define BRCR_CMFCA (1 << 15) -#define BRCR_CMFCB (1 << 14) -#define BRCR_CMFDA (1 << 13) -#define BRCR_CMFDB (1 << 12) -#define BRCR_PCBB (1 << 6) /* 1: after execution */ -#define BRCR_PCBA (1 << 5) /* 1: after execution */ -#define BRCR_PCTE 0 -#else -#define BRCR_PCTE (1 << 11) -#define BRCR_PCBA (1 << 10) /* 1: after execution */ -#define BRCR_DBEB (1 << 7) -#define BRCR_PCBB (1 << 6) -#define BRCR_SEQ (1 << 3) -#define BRCR_UBDE (1 << 0) -#endif - -/* - * All SH parts have 2 UBC channels. I defy any hardware designer to - * invalidate this assertion. - */ -#define NR_UBC_CHANNELS 2 - -#endif /* __KERNEL__ */ -#endif /* __ASM_SH_UBC_H */ diff --git a/arch/sh/include/cpu-sh2/cpu/ubc.h b/arch/sh/include/cpu-sh2/cpu/ubc.h deleted file mode 100644 index ba0e87f19c7a..000000000000 --- a/arch/sh/include/cpu-sh2/cpu/ubc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * include/asm-sh/cpu-sh2/ubc.h - * - * Copyright (C) 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#ifndef __ASM_CPU_SH2_UBC_H -#define __ASM_CPU_SH2_UBC_H - -#define UBC_BARA 0xffffff40 -#define UBC_BAMRA 0xffffff44 -#define UBC_BBRA 0xffffff48 -#define UBC_BARB 0xffffff60 -#define UBC_BAMRB 0xffffff64 -#define UBC_BBRB 0xffffff68 -#define UBC_BDRB 0xffffff70 -#define UBC_BDMRB 0xffffff74 -#define UBC_BRCR 0xffffff78 - -/* - * We don't have any ASID changes to make in the UBC on the SH-2. - * - * Make these purposely invalid to track misuse. - */ -#define UBC_BASRA 0x00000000 -#define UBC_BASRB 0x00000000 - -#endif /* __ASM_CPU_SH2_UBC_H */ - diff --git a/arch/sh/include/cpu-sh3/cpu/ubc.h b/arch/sh/include/cpu-sh3/cpu/ubc.h deleted file mode 100644 index 4e6381d5ff7a..000000000000 --- a/arch/sh/include/cpu-sh3/cpu/ubc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * include/asm-sh/cpu-sh3/ubc.h - * - * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#ifndef __ASM_CPU_SH3_UBC_H -#define __ASM_CPU_SH3_UBC_H - -#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) -#define UBC_BARA 0xa4ffffb0 -#define UBC_BAMRA 0xa4ffffb4 -#define UBC_BBRA 0xa4ffffb8 -#define UBC_BASRA 0xffffffe4 -#define UBC_BARB 0xa4ffffa0 -#define UBC_BAMRB 0xa4ffffa4 -#define UBC_BBRB 0xa4ffffa8 -#define UBC_BASRB 0xffffffe8 -#define UBC_BDRB 0xa4ffff90 -#define UBC_BDMRB 0xa4ffff94 -#define UBC_BRCR 0xa4ffff98 -#else -#define UBC_BARA 0xffffffb0 -#define UBC_BAMRA 0xffffffb4 -#define UBC_BBRA 0xffffffb8 -#define UBC_BASRA 0xffffffe4 -#define UBC_BARB 0xffffffa0 -#define UBC_BAMRB 0xffffffa4 -#define UBC_BBRB 0xffffffa8 -#define UBC_BASRB 0xffffffe8 -#define UBC_BDRB 0xffffff90 -#define UBC_BDMRB 0xffffff94 -#define UBC_BRCR 0xffffff98 -#endif - -#endif /* __ASM_CPU_SH3_UBC_H */ diff --git a/arch/sh/include/cpu-sh4/cpu/ubc.h b/arch/sh/include/cpu-sh4/cpu/ubc.h deleted file mode 100644 index c86e17050935..000000000000 --- a/arch/sh/include/cpu-sh4/cpu/ubc.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * include/asm-sh/cpu-sh4/ubc.h - * - * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt - * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#ifndef __ASM_CPU_SH4_UBC_H -#define __ASM_CPU_SH4_UBC_H - -#if defined(CONFIG_CPU_SH4A) -#define UBC_CBR0 0xff200000 -#define UBC_CRR0 0xff200004 -#define UBC_CAR0 0xff200008 -#define UBC_CAMR0 0xff20000c -#define UBC_CBR1 0xff200020 -#define UBC_CRR1 0xff200024 -#define UBC_CAR1 0xff200028 -#define UBC_CAMR1 0xff20002c -#define UBC_CDR1 0xff200030 -#define UBC_CDMR1 0xff200034 -#define UBC_CETR1 0xff200038 -#define UBC_CCMFR 0xff200600 -#define UBC_CBCR 0xff200620 - -/* CBR */ -#define UBC_CBR_AIE (0x01<<30) -#define UBC_CBR_ID_INST (0x01<<4) -#define UBC_CBR_RW_READ (0x01<<1) -#define UBC_CBR_CE (0x01) - -#define UBC_CBR_AIV_MASK (0x00FF0000) -#define UBC_CBR_AIV_SHIFT (16) -#define UBC_CBR_AIV_SET(asid) (((asid)< #include #include -#ifdef CONFIG_SUPERH32 -#include -#endif /* * Generic wrapper for command line arguments to disable on-chip @@ -252,20 +249,19 @@ static void __init dsp_init(void) /** * sh_cpu_init * - * This is our initial entry point for each CPU, and is invoked on the boot - * CPU prior to calling start_kernel(). For SMP, a combination of this and - * start_secondary() will bring up each processor to a ready state prior - * to hand forking the idle loop. + * This is our initial entry point for each CPU, and is invoked on the + * boot CPU prior to calling start_kernel(). For SMP, a combination of + * this and start_secondary() will bring up each processor to a ready + * state prior to hand forking the idle loop. * - * We do all of the basic processor init here, including setting up the - * caches, FPU, DSP, kicking the UBC, etc. By the time start_kernel() is - * hit (and subsequently platform_setup()) things like determining the - * CPU subtype and initial configuration will all be done. + * We do all of the basic processor init here, including setting up + * the caches, FPU, DSP, etc. By the time start_kernel() is hit (and + * subsequently platform_setup()) things like determining the CPU + * subtype and initial configuration will all be done. * * Each processor family is still responsible for doing its own probing * and cache configuration in detect_cpu_and_cache_system(). */ - asmlinkage void __init sh_cpu_init(void) { current_thread_info()->cpu = hard_smp_processor_id(); diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 7399d78fc8ed..b94f9d96ac95 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include -- GitLab From 9fae4fb3ce38cc657ff0aba570ae875aae2806d4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 5 Jan 2010 19:30:18 +0900 Subject: [PATCH 0351/3892] sh: Reclaim TIF_DEBUG. This was used by the old hw-breakpoints API, but now there is nothing is using it anymore, so just kill it off. Signed-off-by: Paul Mundt --- arch/sh/include/asm/thread_info.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index e0856b205c4e..1f3d927e2265 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -118,7 +118,6 @@ extern void free_thread_info(struct thread_info *ti); #define TIF_SECCOMP 6 /* secure computing */ #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ #define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ -#define TIF_DEBUG 9 /* uses UBC */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 18 #define TIF_FREEZE 19 /* Freezing for suspend */ @@ -131,7 +130,6 @@ extern void free_thread_info(struct thread_info *ti); #define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) -#define _TIF_DEBUG (1 << TIF_DEBUG) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_FREEZE (1 << TIF_FREEZE) -- GitLab From 722612cd51cf1b574c89dff57cc5dbedf1f645bb Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 5 Jan 2010 11:45:52 +0100 Subject: [PATCH 0352/3892] HID: fix parsing of local delimiter with size 0 Acording to HID standard 1.11, value 0 allows for size being 0. Local delimiter tag has has 0 one of the possible values. Therefore we need to handle this case properly, to be fully compliant with the specification. Reported-by: Marcin Tolysz Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6462c923805f..a4b496c68259 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -387,7 +387,8 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) __u32 data; unsigned n; - if (item->size == 0) { + /* Local delimiter could have value 0, which allows size to be 0 */ + if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) { dbg_hid("item data expected for local item\n"); return -1; } -- GitLab From 61b91c1ea31d0d3ae5f848f7f7eab53dd691f8d0 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 24 Dec 2009 15:31:10 +0800 Subject: [PATCH 0353/3892] iwlwifi: remove linux/utsrelease.h dependency Commit 250cce26d5d03337aec4ff8405121f026adb4a89 uses UTS_RELEASE as the the in-tree iwlwifi driver version. However the inclusion of generated/utsrelease.h makes it a unpleasant behaviour to recompile the driver everytime when utsrelease.h is updated. In fact, the driver module is already built with the UTS_RELEASE information via vermagic of modinfo. Mark the in-tree driver with the version string "in-tree" to distinguish with those old out-of-tree drivers. Reported-by: David Miller Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1728f961dcba..8deb83bfe182 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -63,8 +63,6 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ -#include - /************************ * forward declarations * ************************/ @@ -72,7 +70,7 @@ struct iwl_host_cmd; struct iwl_cmd; -#define IWLWIFI_VERSION UTS_RELEASE "-k" +#define IWLWIFI_VERSION "in-tree:" #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" -- GitLab From 29401f6630c02ce996561bf2667d84ecdfacb823 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 29 Dec 2009 12:43:58 +0200 Subject: [PATCH 0354/3892] mac80211: No need to include WEXT headers here Remove the forgotten linux/wireless.h inclusion from mac80211. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/main.c | 1 - net/mac80211/scan.c | 1 - net/mac80211/util.c | 1 - 3 files changed, 3 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d0a14d953f08..468829143991 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 365f40975511..a4c63d4e6845 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -12,7 +12,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 29e1acca207c..4635d4e5af9e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- GitLab From 1990ca6113399be9249433d5ab377a2a444f1dd8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 30 Dec 2009 14:42:20 +0200 Subject: [PATCH 0355/3892] mac80211: fix a warning related to pointer conversion to u64 cookie On a 32 bit system (in this case an omap 3430 system) gcc warned about pointer conversion: net/mac80211/work.c: In function 'ieee80211_remain_on_channel_timeout': net/mac80211/work.c:534: warning: cast from pointer to integer of different size net/mac80211/work.c: In function 'ieee80211_remain_done': net/mac80211/work.c:1030: warning: cast from pointer to integer of different size net/mac80211/work.c: In function 'ieee80211_wk_remain_on_channel': net/mac80211/work.c:1056: warning: cast from pointer to integer of different size net/mac80211/work.c: In function 'ieee80211_wk_cancel_remain_on_channel': net/mac80211/work.c:1072: warning: cast from pointer to integer of different size Fix it by casting the pointers to unsigned long instead. This makes the compiler happy again. Compile-tested only. Cc: Johannes Berg Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/work.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index ea89ed70734d..5ba75990c9fd 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -531,9 +531,9 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) wk->remain.started = true; wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); - cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan, - wk->chan_type, wk->remain.duration, - GFP_KERNEL); + cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, + wk->chan, wk->chan_type, + wk->remain.duration, GFP_KERNEL); return WORK_ACT_NONE; } @@ -1027,7 +1027,7 @@ static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, /* * We are done serving the remain-on-channel command. */ - cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk, + cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, wk->chan, wk->chan_type, GFP_KERNEL); @@ -1053,7 +1053,7 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, wk->remain.duration = duration; - *cookie = (u64)wk; + *cookie = (unsigned long) wk; ieee80211_add_work(wk); @@ -1069,7 +1069,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->work_mtx); list_for_each_entry_safe(wk, tmp, &local->work_list, list) { - if ((u64)wk == cookie) { + if ((unsigned long) wk == cookie) { wk->timeout = jiffies; found = true; break; -- GitLab From fc5f75773c0b3c5b44785e4efcc54c5f496211a9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 30 Dec 2009 15:54:03 +0200 Subject: [PATCH 0356/3892] mac80211: fix ieee80211_change_mac() to use struct sockaddr Setting the mac address from user space was buggy. For example, when executing this command: ip link set wlan0 address 00:1f:df:88:cd:55 mac80211 used the address 01:00:00:1f:df:88 instead. It was shifted two bytes. The reason was that the addr (type of void *) provided to ieee80211_change_mac() is actually of type struct sockaddr, not just the mac address array. Also the call to eth_mac_addr() expects the address to be struct sockaddr. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/iface.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 00a1f4ccdaf1..72189661fc49 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -63,15 +63,16 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) static int ieee80211_change_mac(struct net_device *dev, void *addr) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sockaddr *sa = addr; int ret; if (ieee80211_sdata_running(sdata)) return -EBUSY; - ret = eth_mac_addr(dev, addr); + ret = eth_mac_addr(dev, sa); if (ret == 0) - memcpy(sdata->vif.addr, addr, ETH_ALEN); + memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); return ret; } -- GitLab From 6976b665fc2b19900659b964bba3b55de08f264f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 2 Jan 2010 10:31:50 +0100 Subject: [PATCH 0357/3892] mwl8k: update version number to 0.11 Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c1c6ecd0c5b3..9545ff8d6422 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -26,7 +26,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.10" +#define MWL8K_VERSION "0.11" /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 -- GitLab From 4113f75187bfebccc54bf13c0ed09593023b53ca Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 4 Jan 2010 11:50:11 -0500 Subject: [PATCH 0358/3892] cfg80211: add a regulatory debug print Instead of sprinkling code with ifdef's define REG_DBG_PRINT() instead. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 87ea60d84c3c..ab29a6135d22 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -43,6 +43,15 @@ #include "regdb.h" #include "nl80211.h" +#ifdef CONFIG_CFG80211_REG_DEBUG +#define REG_DBG_PRINT(args...) \ + do { \ + printk(KERN_DEBUG args); \ + } while (0) +#else +#define REG_DBG_PRINT(args) +#endif + /* Receipt of information from last regulatory request */ static struct regulatory_request *last_request; @@ -972,25 +981,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, if (r == -ERANGE && last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { -#ifdef CONFIG_CFG80211_REG_DEBUG - printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz " + REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " "intact on %s - no rule found in band on " "Country IE\n", - chan->center_freq, wiphy_name(wiphy)); -#endif + chan->center_freq, wiphy_name(wiphy)); } else { /* * In this case we know the country IE has at least one reg rule * for the band so we respect its band definitions */ -#ifdef CONFIG_CFG80211_REG_DEBUG if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) - printk(KERN_DEBUG "cfg80211: Disabling " + REG_DBG_PRINT("cfg80211: Disabling " "channel %d MHz on %s due to " "Country IE\n", chan->center_freq, wiphy_name(wiphy)); -#endif flags |= IEEE80211_CHAN_DISABLED; chan->flags = flags; } @@ -1870,13 +1875,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, if (!reg_beacon) return -ENOMEM; -#ifdef CONFIG_CFG80211_REG_DEBUG - printk(KERN_DEBUG "cfg80211: Found new beacon on " - "frequency: %d MHz (Ch %d) on %s\n", - beacon_chan->center_freq, - ieee80211_frequency_to_channel(beacon_chan->center_freq), - wiphy_name(wiphy)); -#endif + REG_DBG_PRINT("cfg80211: Found new beacon on " + "frequency: %d MHz (Ch %d) on %s\n", + beacon_chan->center_freq, + ieee80211_frequency_to_channel(beacon_chan->center_freq), + wiphy_name(wiphy)); + memcpy(®_beacon->chan, beacon_chan, sizeof(struct ieee80211_channel)); -- GitLab From 91942230689c1758685499e82e53769d5e7f32eb Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:53:54 +0100 Subject: [PATCH 0359/3892] mwl8k: bail out if there is no AP firmware image support for this chip Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9545ff8d6422..bfaa7911b336 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3361,10 +3361,17 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mwl8k_release_firmware(priv); - if (priv->ap_fw) + if (priv->ap_fw) { priv->rxd_ops = priv->device_info->ap_rxd_ops; - else + if (priv->rxd_ops == NULL) { + printk(KERN_ERR "%s: Driver does not have AP " + "firmware image support for this hardware\n", + wiphy_name(hw->wiphy)); + goto err_stop_firmware; + } + } else { priv->rxd_ops = &rxd_sta_ops; + } priv->sniffer_enabled = false; priv->wmm_enabled = false; -- GitLab From 153458ff7ed5949cd5b07a2355a34aad9891ad98 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:54:08 +0100 Subject: [PATCH 0360/3892] mwl8k: prevent freeing free IRQ if ieee80211_register_hw() fails Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index bfaa7911b336..2c286d18bae3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3501,7 +3501,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot register device\n", wiphy_name(hw->wiphy)); - goto err_free_irq; + goto err_free_queues; } printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", -- GitLab From 9a2303b93039d0f3dd578cd75fe20ebaf075f1cb Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:54:25 +0100 Subject: [PATCH 0361/3892] mwl8k: make the tx ring drain status messages somewhat more friendly Old: > phy0: timeout waiting for tx rings to drain (9 -> 5 pkts), retrying > phy0: timeout waiting for tx rings to drain (5 -> 2 pkts), retrying > phy0: tx rings drained New: > phy0: waiting for tx rings to drain (9 -> 5 pkts) > phy0: waiting for tx rings to drain (5 -> 2 pkts) > phy0: tx rings drained Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 2c286d18bae3..46a5cf214a20 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1269,8 +1269,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) } if (priv->pending_tx_pkts < oldcount) { - printk(KERN_NOTICE "%s: timeout waiting for tx " - "rings to drain (%d -> %d pkts), retrying\n", + printk(KERN_NOTICE "%s: waiting for tx rings " + "to drain (%d -> %d pkts)\n", wiphy_name(hw->wiphy), oldcount, priv->pending_tx_pkts); retry = 1; -- GitLab From 25d81b1e1a0cca41a71a08468a7d3a4c751c8565 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:54:41 +0100 Subject: [PATCH 0362/3892] mwl8k: move struct peer_capability_info to its only user Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 91 +++++++++++++++++------------------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 46a5cf214a20..3dbdea904833 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -598,54 +598,6 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) } -/* - * Defines shared between transmission and reception. - */ -/* HT control fields for firmware */ -struct ewc_ht_info { - __le16 control1; - __le16 control2; - __le16 control3; -} __attribute__((packed)); - -/* Firmware Station database operations */ -#define MWL8K_STA_DB_ADD_ENTRY 0 -#define MWL8K_STA_DB_MODIFY_ENTRY 1 -#define MWL8K_STA_DB_DEL_ENTRY 2 -#define MWL8K_STA_DB_FLUSH 3 - -/* Peer Entry flags - used to define the type of the peer node */ -#define MWL8K_PEER_TYPE_ACCESSPOINT 2 - -struct peer_capability_info { - /* Peer type - AP vs. STA. */ - __u8 peer_type; - - /* Basic 802.11 capabilities from assoc resp. */ - __le16 basic_caps; - - /* Set if peer supports 802.11n high throughput (HT). */ - __u8 ht_support; - - /* Valid if HT is supported. */ - __le16 ht_caps; - __u8 extended_ht_caps; - struct ewc_ht_info ewc_info; - - /* Legacy rate table. Intersection of our rates and peer rates. */ - __u8 legacy_rates[12]; - - /* HT rate table. Intersection of our rates and peer rates. */ - __u8 ht_rates[16]; - __u8 pad[16]; - - /* If set, interoperability mode, no proprietary extensions. */ - __u8 interop; - __u8 pad2; - __u8 station_id; - __le16 amsdu_enabled; -} __attribute__((packed)); - /* DMA header used by firmware and hardware. */ struct mwl8k_dma_data { __le16 fwlen; @@ -2630,6 +2582,49 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) /* * CMD_UPDATE_STADB. */ +#define MWL8K_STA_DB_ADD_ENTRY 0 +#define MWL8K_STA_DB_MODIFY_ENTRY 1 +#define MWL8K_STA_DB_DEL_ENTRY 2 +#define MWL8K_STA_DB_FLUSH 3 + +/* Peer Entry flags - used to define the type of the peer node */ +#define MWL8K_PEER_TYPE_ACCESSPOINT 2 + +struct ewc_ht_info { + __le16 control1; + __le16 control2; + __le16 control3; +} __attribute__((packed)); + +struct peer_capability_info { + /* Peer type - AP vs. STA. */ + __u8 peer_type; + + /* Basic 802.11 capabilities from assoc resp. */ + __le16 basic_caps; + + /* Set if peer supports 802.11n high throughput (HT). */ + __u8 ht_support; + + /* Valid if HT is supported. */ + __le16 ht_caps; + __u8 extended_ht_caps; + struct ewc_ht_info ewc_info; + + /* Legacy rate table. Intersection of our rates and peer rates. */ + __u8 legacy_rates[12]; + + /* HT rate table. Intersection of our rates and peer rates. */ + __u8 ht_rates[16]; + __u8 pad[16]; + + /* If set, interoperability mode, no proprietary extensions. */ + __u8 interop; + __u8 pad2; + __u8 station_id; + __le16 amsdu_enabled; +} __attribute__((packed)); + struct mwl8k_cmd_update_stadb { struct mwl8k_cmd_pkt header; -- GitLab From bbfd9128d3b4a80bea017ebdd47b31a80dc7eadf Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:55:12 +0100 Subject: [PATCH 0363/3892] mwl8k: handle station database update for AP's sta entry via ->sta_notify() Inserting and removing a hardware station database entry for the AP when we are in managed mode is currently done in ->bss_info_changed(). To prepare for adding AP mode support, implement the ->sta_notify() driver method, and let that handle inserting and removing the hardware station database entry for our AP instead. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 82 ++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3dbdea904833..df0596ca710d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -185,6 +185,10 @@ struct mwl8k_priv { bool sniffer_enabled; bool wmm_enabled; + struct work_struct sta_notify_worker; + spinlock_t sta_notify_list_lock; + struct list_head sta_notify_list; + /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; u8 capture_bssid[ETH_ALEN]; @@ -2641,7 +2645,7 @@ struct mwl8k_cmd_update_stadb { } __attribute__((packed)); static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, __u32 action) + struct ieee80211_vif *vif, __u32 action, u8 *addr) { struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); struct mwl8k_cmd_update_stadb *cmd; @@ -2657,7 +2661,7 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, cmd->action = cpu_to_le32(action); peer_info = &cmd->peer_info; - memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); + memcpy(cmd->peer_addr, addr, ETH_ALEN); switch (action) { case MWL8K_STA_DB_ADD_ENTRY: @@ -2978,12 +2982,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, if (rc) goto out; - /* Update peer rate info */ - rc = mwl8k_cmd_update_stadb(hw, vif, - MWL8K_STA_DB_MODIFY_ENTRY); - if (rc) - goto out; - /* Set AID */ rc = mwl8k_cmd_set_aid(hw, vif); if (rc) @@ -2996,7 +2994,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { - rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(mwl8k_vif->bssid, 0, ETH_ALEN); } @@ -3142,6 +3139,67 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return mwl8k_cmd_set_rts_threshold(hw, MWL8K_CMD_SET, value); } +struct mwl8k_sta_notify_item +{ + struct list_head list; + struct ieee80211_vif *vif; + enum sta_notify_cmd cmd; + u8 addr[ETH_ALEN]; +}; + +static void mwl8k_sta_notify_worker(struct work_struct *work) +{ + struct mwl8k_priv *priv = + container_of(work, struct mwl8k_priv, sta_notify_worker); + + spin_lock_bh(&priv->sta_notify_list_lock); + while (!list_empty(&priv->sta_notify_list)) { + struct mwl8k_sta_notify_item *s; + int action; + + s = list_entry(priv->sta_notify_list.next, + struct mwl8k_sta_notify_item, list); + list_del(&s->list); + + spin_unlock_bh(&priv->sta_notify_list_lock); + + if (s->cmd == STA_NOTIFY_ADD) + action = MWL8K_STA_DB_MODIFY_ENTRY; + else + action = MWL8K_STA_DB_DEL_ENTRY; + mwl8k_cmd_update_stadb(priv->hw, s->vif, action, s->addr); + + kfree(s); + + spin_lock_bh(&priv->sta_notify_list_lock); + } + spin_unlock_bh(&priv->sta_notify_list_lock); +} + +static void +mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +{ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_sta_notify_item *s; + + if (cmd != STA_NOTIFY_ADD && cmd != STA_NOTIFY_REMOVE) + return; + + s = kmalloc(sizeof(*s), GFP_ATOMIC); + if (s != NULL) { + s->vif = vif; + s->cmd = cmd; + memcpy(s->addr, sta->addr, ETH_ALEN); + + spin_lock(&priv->sta_notify_list_lock); + list_add_tail(&s->list, &priv->sta_notify_list); + spin_unlock(&priv->sta_notify_list_lock); + + ieee80211_queue_work(hw, &priv->sta_notify_worker); + } +} + static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -3201,6 +3259,7 @@ static const struct ieee80211_ops mwl8k_ops = { .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, + .sta_notify = mwl8k_sta_notify, .conf_tx = mwl8k_conf_tx, .get_tx_stats = mwl8k_get_tx_stats, .get_stats = mwl8k_get_stats, @@ -3404,6 +3463,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->radio_on = 0; priv->radio_short_preamble = 0; + /* Station database handling */ + INIT_WORK(&priv->sta_notify_worker, mwl8k_sta_notify_worker); + spin_lock_init(&priv->sta_notify_list_lock); + INIT_LIST_HEAD(&priv->sta_notify_list); + /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); -- GitLab From 0a11dfc36604d9b24deda17461b7ea69851846aa Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:55:21 +0100 Subject: [PATCH 0364/3892] mwl8k: remove mwl8k_vif::bssid, which is now useless Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index df0596ca710d..ed666b7e7e41 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -211,9 +211,6 @@ struct mwl8k_vif { /* Local MAC address. */ u8 mac_addr[ETH_ALEN]; - /* BSSID of AP. */ - u8 bssid[ETH_ALEN]; - /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; @@ -2001,7 +1998,7 @@ struct mwl8k_cmd_set_post_scan { } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -2077,7 +2074,6 @@ struct mwl8k_cmd_update_set_aid { static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); struct mwl8k_cmd_update_set_aid *cmd; u16 prot_mode; int rc; @@ -2090,7 +2086,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->aid = cpu_to_le16(vif->bss_conf.aid); - memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); + memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); if (vif->bss_conf.use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; @@ -2945,7 +2941,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); int rc; if ((changed & BSS_CHANGED_ASSOC) == 0) @@ -2958,8 +2953,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, return; if (vif->bss_conf.assoc) { - memcpy(mwl8k_vif->bssid, vif->bss_conf.bssid, ETH_ALEN); - /* Install rates */ rc = mwl8k_cmd_set_rate(hw, vif); if (rc) @@ -2991,10 +2984,8 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, * Finalize the join. Tell rx handler to process * next beacon from our BSSID. */ - memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); + memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); priv->capture_beacon = true; - } else { - memset(mwl8k_vif->bssid, 0, ETH_ALEN); } out: @@ -3097,7 +3088,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, */ mwl8k_cmd_set_pre_scan(hw); } else { - u8 *bssid; + const u8 *bssid; /* * Enable the BSS filter. @@ -3109,7 +3100,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, */ bssid = "\x01\x00\x00\x00\x00\x00"; if (priv->vif != NULL) - bssid = MWL8K_VIF(priv->vif)->bssid; + bssid = priv->vif->bss_conf.bssid; mwl8k_cmd_set_post_scan(hw, bssid); } -- GitLab From a680400e8ac32adda81b5e2d7f23dfac63e064fe Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:55:42 +0100 Subject: [PATCH 0365/3892] mwl8k: move ->peer_id from mwl8k_vif to mwl8k_sta For STA firmware, move the per-peer hardware station ID to the driver-private part of struct ieee80211_sta, where it belongs. (Since issuing a hardware station database maintenance command sleeps, we can't hold a reference to the ieee80211_sta * across the command, and since we won't know the station ID until after the command completes, we need to re-lookup the sta when the command is done to write the returned station ID back to its driver-private part.) Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 119 ++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ed666b7e7e41..5b5cf9357dbf 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -211,15 +211,17 @@ struct mwl8k_vif { /* Local MAC address. */ u8 mac_addr[ETH_ALEN]; - /* Index into station database. Returned by UPDATE_STADB. */ - u8 peer_id; - /* Non AMPDU sequence number assigned by driver */ - u16 seqno; + u16 seqno; }; - #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) +struct mwl8k_sta { + /* Index into station database. Returned by UPDATE_STADB. */ + u8 peer_id; +}; +#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) + static const struct ieee80211_channel mwl8k_channels[] = { { .center_freq = 2412, .hw_value = 1, }, { .center_freq = 2417, .hw_value = 2, }, @@ -1402,7 +1404,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); tx->rate_info = 0; - tx->peer_id = mwl8k_vif->peer_id; + if (!priv->ap_fw && tx_info->control.sta != NULL) + tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; + else + tx->peer_id = 0; wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); @@ -2582,14 +2587,6 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) /* * CMD_UPDATE_STADB. */ -#define MWL8K_STA_DB_ADD_ENTRY 0 -#define MWL8K_STA_DB_MODIFY_ENTRY 1 -#define MWL8K_STA_DB_DEL_ENTRY 2 -#define MWL8K_STA_DB_FLUSH 3 - -/* Peer Entry flags - used to define the type of the peer node */ -#define MWL8K_PEER_TYPE_ACCESSPOINT 2 - struct ewc_ht_info { __le16 control1; __le16 control2; @@ -2640,12 +2637,17 @@ struct mwl8k_cmd_update_stadb { struct peer_capability_info peer_info; } __attribute__((packed)); -static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, __u32 action, u8 *addr) +#define MWL8K_STA_DB_MODIFY_ENTRY 1 +#define MWL8K_STA_DB_DEL_ENTRY 2 + +/* Peer Entry flags - used to define the type of the peer node */ +#define MWL8K_PEER_TYPE_ACCESSPOINT 2 + +static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u8 *addr) { - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); struct mwl8k_cmd_update_stadb *cmd; - struct peer_capability_info *peer_info; + struct peer_capability_info *p; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2654,37 +2656,38 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); + memcpy(cmd->peer_addr, addr, ETH_ALEN); - cmd->action = cpu_to_le32(action); - peer_info = &cmd->peer_info; + p = &cmd->peer_info; + p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; + p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); + memcpy(p->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + p->interop = 1; + p->amsdu_enabled = 0; + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc ? rc : p->station_id; +} + +static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u8 *addr) +{ + struct mwl8k_cmd_update_stadb *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); memcpy(cmd->peer_addr, addr, ETH_ALEN); - switch (action) { - case MWL8K_STA_DB_ADD_ENTRY: - case MWL8K_STA_DB_MODIFY_ENTRY: - /* Build peer_info block */ - peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; - peer_info->basic_caps = - cpu_to_le16(vif->bss_conf.assoc_capability); - memcpy(peer_info->legacy_rates, mwl8k_rateids, - sizeof(mwl8k_rateids)); - peer_info->interop = 1; - peer_info->amsdu_enabled = 0; - - rc = mwl8k_post_cmd(hw, &cmd->header); - if (rc == 0) - mv_vif->peer_id = peer_info->station_id; - - break; - - case MWL8K_STA_DB_DEL_ENTRY: - case MWL8K_STA_DB_FLUSH: - default: - rc = mwl8k_post_cmd(hw, &cmd->header); - if (rc == 0) - mv_vif->peer_id = 0; - break; - } + rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); return rc; @@ -3142,11 +3145,11 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) { struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, sta_notify_worker); + struct ieee80211_hw *hw = priv->hw; spin_lock_bh(&priv->sta_notify_list_lock); while (!list_empty(&priv->sta_notify_list)) { struct mwl8k_sta_notify_item *s; - int action; s = list_entry(priv->sta_notify_list.next, struct mwl8k_sta_notify_item, list); @@ -3154,11 +3157,22 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) spin_unlock_bh(&priv->sta_notify_list_lock); - if (s->cmd == STA_NOTIFY_ADD) - action = MWL8K_STA_DB_MODIFY_ENTRY; - else - action = MWL8K_STA_DB_DEL_ENTRY; - mwl8k_cmd_update_stadb(priv->hw, s->vif, action, s->addr); + if (s->cmd == STA_NOTIFY_ADD) { + int rc; + + rc = mwl8k_cmd_update_stadb_add(hw, s->vif, s->addr); + if (rc >= 0) { + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(s->vif, s->addr); + if (sta != NULL) + MWL8K_STA(sta)->peer_id = rc; + rcu_read_unlock(); + } + } else { + mwl8k_cmd_update_stadb_del(hw, s->vif, s->addr); + } kfree(s); @@ -3448,6 +3462,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); + hw->sta_data_size = sizeof(struct mwl8k_sta); priv->vif = NULL; /* Set default radio state and preamble */ -- GitLab From c6e9601071173fed2a77f9c435c41f3b33d1018f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:55:52 +0100 Subject: [PATCH 0366/3892] mwl8k: honor peer rate set When calling SET_RATE, SET_AID, or when creating a station database entry for our AP, pass in the AP's rate set instead of just blindly enabling all legacy rates, so as to end up doing the right thing when talking to 11b-only APs. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 57 +++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5b5cf9357dbf..d8eff68978f1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -256,10 +256,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 720, .hw_value = 144, }, }; -static const u8 mwl8k_rateids[12] = { - 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, -}; - /* Set or get info from Firmware */ #define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 @@ -2076,8 +2072,25 @@ struct mwl8k_cmd_update_set_aid { __u8 supp_rates[14]; } __attribute__((packed)); +static void legacy_rate_mask_to_array(u8 *rates, u32 mask) +{ + int i; + int j; + + /* + * Clear nonstandard rates 4 and 13. + */ + mask &= 0x1fef; + + for (i = 0, j = 0; i < 14; i++) { + if (mask & (1 << i)) + rates[j++] = mwl8k_rates[i].hw_value; + } +} + static int -mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +mwl8k_cmd_set_aid(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u32 legacy_rate_mask) { struct mwl8k_cmd_update_set_aid *cmd; u16 prot_mode; @@ -2090,7 +2103,6 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->aid = cpu_to_le16(vif->bss_conf.aid); - memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); if (vif->bss_conf.use_cts_prot) { @@ -2111,7 +2123,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } cmd->protection_mode = cpu_to_le16(prot_mode); - memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2132,7 +2144,8 @@ struct mwl8k_cmd_set_rate { } __attribute__((packed)); static int -mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 legacy_rate_mask) { struct mwl8k_cmd_set_rate *cmd; int rc; @@ -2143,7 +2156,7 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2644,7 +2657,8 @@ struct mwl8k_cmd_update_stadb { #define MWL8K_PEER_TYPE_ACCESSPOINT 2 static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u8 *addr) + struct ieee80211_vif *vif, + u8 *addr, u32 legacy_rate_mask) { struct mwl8k_cmd_update_stadb *cmd; struct peer_capability_info *p; @@ -2662,7 +2676,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, p = &cmd->peer_info; p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); - memcpy(p->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + legacy_rate_mask_to_array(p->legacy_rates, legacy_rate_mask); p->interop = 1; p->amsdu_enabled = 0; @@ -2956,8 +2970,20 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, return; if (vif->bss_conf.assoc) { + struct ieee80211_sta *ap; + u32 legacy_rate_mask; + + rcu_read_lock(); + ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (ap != NULL) + legacy_rate_mask = ap->supp_rates[IEEE80211_BAND_2GHZ]; + rcu_read_unlock(); + + if (ap == NULL) + goto out; + /* Install rates */ - rc = mwl8k_cmd_set_rate(hw, vif); + rc = mwl8k_cmd_set_rate(hw, vif, legacy_rate_mask); if (rc) goto out; @@ -2979,7 +3005,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, goto out; /* Set AID */ - rc = mwl8k_cmd_set_aid(hw, vif); + rc = mwl8k_cmd_set_aid(hw, vif, legacy_rate_mask); if (rc) goto out; @@ -3139,6 +3165,7 @@ struct mwl8k_sta_notify_item struct ieee80211_vif *vif; enum sta_notify_cmd cmd; u8 addr[ETH_ALEN]; + u32 legacy_rate_mask; }; static void mwl8k_sta_notify_worker(struct work_struct *work) @@ -3160,7 +3187,8 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) if (s->cmd == STA_NOTIFY_ADD) { int rc; - rc = mwl8k_cmd_update_stadb_add(hw, s->vif, s->addr); + rc = mwl8k_cmd_update_stadb_add(hw, s->vif, + s->addr, s->legacy_rate_mask); if (rc >= 0) { struct ieee80211_sta *sta; @@ -3196,6 +3224,7 @@ mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, s->vif = vif; s->cmd = cmd; memcpy(s->addr, sta->addr, ETH_ALEN); + s->legacy_rate_mask = sta->supp_rates[IEEE80211_BAND_2GHZ]; spin_lock(&priv->sta_notify_list_lock); list_add_tail(&s->list, &priv->sta_notify_list); -- GitLab From c3cbbe8a5cd2886e13e9c93e059d9761f3715665 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:56:07 +0100 Subject: [PATCH 0367/3892] mwl8k: fix changed flags handling in mwl8k_bss_info_changed() Previously, mwl8k_bss_info_changed() would refuse to do anything if the 'changed' argument indicated that the association status hadn't changed. Fix this up so that it will allow changing things like the preamble type, the slot time and the CTS-to-self protection method without having to reassociate. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 52 +++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d8eff68978f1..fa7b4fe074f5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2958,57 +2958,71 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct mwl8k_priv *priv = hw->priv; + u32 ap_legacy_rates; int rc; - if ((changed & BSS_CHANGED_ASSOC) == 0) + if (mwl8k_fw_lock(hw)) return; - priv->capture_beacon = false; - - rc = mwl8k_fw_lock(hw); - if (rc) - return; + /* + * No need to capture a beacon if we're no longer associated. + */ + if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) + priv->capture_beacon = false; + /* + * Get the AP's legacy rates. + */ + ap_legacy_rates = 0; if (vif->bss_conf.assoc) { struct ieee80211_sta *ap; - u32 legacy_rate_mask; rcu_read_lock(); - ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (ap != NULL) - legacy_rate_mask = ap->supp_rates[IEEE80211_BAND_2GHZ]; - rcu_read_unlock(); - if (ap == NULL) + ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (ap == NULL) { + rcu_read_unlock(); goto out; + } - /* Install rates */ - rc = mwl8k_cmd_set_rate(hw, vif, legacy_rate_mask); + ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; + + rcu_read_unlock(); + } + + if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { + rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates); if (rc) goto out; - /* Turn on rate adaptation */ rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, MWL8K_UCAST_RATE, NULL); if (rc) goto out; + } - /* Set radio preamble */ + if (changed & BSS_CHANGED_ERP_PREAMBLE) { rc = mwl8k_set_radio_preamble(hw, vif->bss_conf.use_short_preamble); if (rc) goto out; + } - /* Set slot time */ + if (changed & BSS_CHANGED_ERP_SLOT) { rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); if (rc) goto out; + } - /* Set AID */ - rc = mwl8k_cmd_set_aid(hw, vif, legacy_rate_mask); + if (((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) || + (changed & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))) { + rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); if (rc) goto out; + } + if (vif->bss_conf.assoc && + (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { /* * Finalize the join. Tell rx handler to process * next beacon from our BSSID. -- GitLab From 9e1b17ead81e72d3db37b4cf15cde1f613603822 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:56:19 +0100 Subject: [PATCH 0368/3892] mwl8k: add support for 88w8363 in STA mode Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index fa7b4fe074f5..de74c111d967 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3344,11 +3344,17 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) } enum { - MWL8687 = 0, + MWL8363 = 0, + MWL8687, MWL8366, }; static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { + [MWL8363] = { + .part_name = "88w8363", + .helper_image = "mwl8k/helper_8363.fw", + .fw_image = "mwl8k/fmimage_8363.fw", + }, [MWL8687] = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", @@ -3363,6 +3369,8 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { }; static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { + { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, + { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, -- GitLab From 610677d2f0415570a7590790e8be376a946cd08b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:56:46 +0100 Subject: [PATCH 0369/3892] mwl8k: allow setting HT channels Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index de74c111d967..2ae6c363f374 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2030,8 +2030,9 @@ struct mwl8k_cmd_set_rf_channel { } __attribute__((packed)); static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, - struct ieee80211_channel *channel) + struct ieee80211_conf *conf) { + struct ieee80211_channel *channel = conf->channel; struct mwl8k_cmd_set_rf_channel *cmd; int rc; @@ -2043,10 +2044,17 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); cmd->current_channel = channel->hw_value; + if (channel->band == IEEE80211_BAND_2GHZ) - cmd->channel_flags = cpu_to_le32(0x00000081); - else - cmd->channel_flags = cpu_to_le32(0x00000000); + cmd->channel_flags |= cpu_to_le32(0x00000001); + + if (conf->channel_type == NL80211_CHAN_NO_HT || + conf->channel_type == NL80211_CHAN_HT20) + cmd->channel_flags |= cpu_to_le32(0x00000080); + else if (conf->channel_type == NL80211_CHAN_HT40MINUS) + cmd->channel_flags |= cpu_to_le32(0x000001900); + else if (conf->channel_type == NL80211_CHAN_HT40PLUS) + cmd->channel_flags |= cpu_to_le32(0x000000900); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2926,7 +2934,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) goto out; - rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); + rc = mwl8k_cmd_set_rf_channel(hw, conf); if (rc) goto out; -- GitLab From 13935e2cf39b124c9a2ff0349b294e0b1e2e3aef Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:57:59 +0100 Subject: [PATCH 0370/3892] mwl8k: pass in HT capabilities and rates when associating Pass the AP's MCS rate mask to SET_RATE when associating, and make UPDATE_STADB pass in the peer's HT caps and rates when adding a new hardware station database entry. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 2ae6c363f374..e0301b6310f9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2153,7 +2153,7 @@ struct mwl8k_cmd_set_rate { static int mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 legacy_rate_mask) + u32 legacy_rate_mask, u8 *mcs_rates) { struct mwl8k_cmd_set_rate *cmd; int rc; @@ -2165,6 +2165,7 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); + memcpy(cmd->mcs_set, mcs_rates, 16); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2666,7 +2667,7 @@ struct mwl8k_cmd_update_stadb { static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u8 *addr, u32 legacy_rate_mask) + struct ieee80211_sta *sta) { struct mwl8k_cmd_update_stadb *cmd; struct peer_capability_info *p; @@ -2679,12 +2680,18 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); - memcpy(cmd->peer_addr, addr, ETH_ALEN); + memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); p = &cmd->peer_info; p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); - legacy_rate_mask_to_array(p->legacy_rates, legacy_rate_mask); + p->ht_support = sta->ht_cap.ht_supported; + p->ht_caps = sta->ht_cap.cap; + p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | + ((sta->ht_cap.ampdu_density & 7) << 2); + legacy_rate_mask_to_array(p->legacy_rates, + sta->supp_rates[IEEE80211_BAND_2GHZ]); + memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); p->interop = 1; p->amsdu_enabled = 0; @@ -2967,6 +2974,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; u32 ap_legacy_rates; + u8 ap_mcs_rates[16]; int rc; if (mwl8k_fw_lock(hw)) @@ -2979,12 +2987,11 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, priv->capture_beacon = false; /* - * Get the AP's legacy rates. + * Get the AP's legacy and MCS rates. */ ap_legacy_rates = 0; if (vif->bss_conf.assoc) { struct ieee80211_sta *ap; - rcu_read_lock(); ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); @@ -2994,12 +3001,13 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, } ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; + memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); rcu_read_unlock(); } if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { - rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates); + rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); if (rc) goto out; @@ -3186,8 +3194,7 @@ struct mwl8k_sta_notify_item struct list_head list; struct ieee80211_vif *vif; enum sta_notify_cmd cmd; - u8 addr[ETH_ALEN]; - u32 legacy_rate_mask; + struct ieee80211_sta sta; }; static void mwl8k_sta_notify_worker(struct work_struct *work) @@ -3209,19 +3216,18 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) if (s->cmd == STA_NOTIFY_ADD) { int rc; - rc = mwl8k_cmd_update_stadb_add(hw, s->vif, - s->addr, s->legacy_rate_mask); + rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta); if (rc >= 0) { struct ieee80211_sta *sta; rcu_read_lock(); - sta = ieee80211_find_sta(s->vif, s->addr); + sta = ieee80211_find_sta(s->vif, s->sta.addr); if (sta != NULL) MWL8K_STA(sta)->peer_id = rc; rcu_read_unlock(); } } else { - mwl8k_cmd_update_stadb_del(hw, s->vif, s->addr); + mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr); } kfree(s); @@ -3245,8 +3251,7 @@ mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (s != NULL) { s->vif = vif; s->cmd = cmd; - memcpy(s->addr, sta->addr, ETH_ALEN); - s->legacy_rate_mask = sta->supp_rates[IEEE80211_BAND_2GHZ]; + s->sta = *sta; spin_lock(&priv->sta_notify_list_lock); list_add_tail(&s->list, &priv->sta_notify_list); -- GitLab From a2292d83b5dcb7f378956a124854d2b17fa53aa3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:58:12 +0100 Subject: [PATCH 0371/3892] mwl8k: trivial rx-only ampdu implementation AMPDU receive doesn't need any special handling, so let's enable this before tackling the transmit side. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index e0301b6310f9..57ced0db910a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3309,6 +3309,22 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw, return mwl8k_cmd_get_stat(hw, stats); } +static int +mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + switch (action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + return -ENOTSUPP; + return 0; + default: + return -ENOTSUPP; + } +} + static const struct ieee80211_ops mwl8k_ops = { .tx = mwl8k_tx, .start = mwl8k_start, @@ -3324,6 +3340,7 @@ static const struct ieee80211_ops mwl8k_ops = { .conf_tx = mwl8k_conf_tx, .get_tx_stats = mwl8k_get_tx_stats, .get_stats = mwl8k_get_stats, + .ampdu_action = mwl8k_ampdu_action, }; static void mwl8k_tx_reclaim_handler(unsigned long data) -- GitLab From 341c97918ab7e84a155ea8b18759425304d213b6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 4 Jan 2010 21:58:40 +0100 Subject: [PATCH 0372/3892] mwl8k: pass GET_HW_SPEC capability bitmask up the stack This enables HT association and AMPDU in the receive direction for STA firmware images on hardware that supports it. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 57ced0db910a..23a5a3442623 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1578,6 +1578,68 @@ struct mwl8k_cmd_get_hw_spec_sta { __le32 total_rxd; } __attribute__((packed)); +#define MWL8K_CAP_MAX_AMSDU 0x20000000 +#define MWL8K_CAP_GREENFIELD 0x08000000 +#define MWL8K_CAP_AMPDU 0x04000000 +#define MWL8K_CAP_RX_STBC 0x01000000 +#define MWL8K_CAP_TX_STBC 0x00800000 +#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 +#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 +#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 +#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 +#define MWL8K_CAP_DELAY_BA 0x00003000 +#define MWL8K_CAP_MIMO 0x00000200 +#define MWL8K_CAP_40MHZ 0x00000100 + +static void mwl8k_set_ht_caps(struct ieee80211_hw *hw, u32 cap) +{ + struct mwl8k_priv *priv = hw->priv; + int rx_streams; + int tx_streams; + + priv->band.ht_cap.ht_supported = 1; + + if (cap & MWL8K_CAP_MAX_AMSDU) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; + if (cap & MWL8K_CAP_GREENFIELD) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; + if (cap & MWL8K_CAP_AMPDU) { + hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + priv->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + priv->band.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_NONE; + } + if (cap & MWL8K_CAP_RX_STBC) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; + if (cap & MWL8K_CAP_TX_STBC) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; + if (cap & MWL8K_CAP_SHORTGI_40MHZ) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + if (cap & MWL8K_CAP_SHORTGI_20MHZ) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; + if (cap & MWL8K_CAP_DELAY_BA) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; + if (cap & MWL8K_CAP_40MHZ) + priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); + tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); + + priv->band.ht_cap.mcs.rx_mask[0] = 0xff; + if (rx_streams >= 2) + priv->band.ht_cap.mcs.rx_mask[1] = 0xff; + if (rx_streams >= 3) + priv->band.ht_cap.mcs.rx_mask[2] = 0xff; + priv->band.ht_cap.mcs.rx_mask[4] = 0x01; + priv->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + if (rx_streams != tx_streams) { + priv->band.ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + priv->band.ht_cap.mcs.tx_params |= (tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + } +} + static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; @@ -1608,6 +1670,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; + if (cmd->caps & cpu_to_le32(MWL8K_CAP_MIMO)) + mwl8k_set_ht_caps(hw, le32_to_cpu(cmd->caps)); } kfree(cmd); -- GitLab From f3f66b69c8ff08b46975d9e99c7ecb92a8b12eda Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 4 Jan 2010 00:52:56 +0100 Subject: [PATCH 0373/3892] mac80211: fix ampdu_action tx_start ssn The start_seq_num is taken from the station's tid_seq[tid]. This is fine, except tid_seq sequence counter is shifted by 4 bits to accommodate for frame fragmentation. Both (iwlagn & ath9k) were unaffected by this minor glitch, because they don't read the *ssn for the AMPDU_TX_START action. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ceda36618d3c..5aa8f4a3ed17 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -301,7 +301,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) * call back right away, it must see that the flow has begun */ *state |= HT_ADDBA_REQUESTED_MSK; - start_seq_num = sta->tid_seq[tid]; + start_seq_num = sta->tid_seq[tid] >> 4; ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, pubsta, tid, &start_seq_num); -- GitLab From 8271195e38d01f3551bb10b1c7de856cd8507882 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 5 Jan 2010 17:57:20 -0500 Subject: [PATCH 0374/3892] wireless: fix build breakage when CONFIG_CFG80211_REG_DEBUG not set Bad macro definition in "cfg80211: add a regulatory debug print"... Signed-off-by: John W. Linville --- net/wireless/reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 89c3e68a1cc6..f79d6613c5ff 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -44,12 +44,12 @@ #include "nl80211.h" #ifdef CONFIG_CFG80211_REG_DEBUG -#define REG_DBG_PRINT(args...) \ +#define REG_DBG_PRINT(format, args...) \ do { \ - printk(KERN_DEBUG args); \ + printk(KERN_DEBUG format , ## args); \ } while (0) #else -#define REG_DBG_PRINT(args) +#define REG_DBG_PRINT(args...) #endif /* Receipt of information from last regulatory request */ -- GitLab From 56d45b62ce622a003da972428fdbba2b42102efb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 6 Jan 2010 14:45:14 +0900 Subject: [PATCH 0375/3892] sh: Fix up nommu build for out-of-line pgtable changes. pgtable_cache_init() has been moved out-of-line, so we also need a dummy definition for it on nommu to fix up the build. Signed-off-by: Paul Mundt --- arch/sh/mm/nommu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c index ac16c05917ef..7694f50c9034 100644 --- a/arch/sh/mm/nommu.c +++ b/arch/sh/mm/nommu.c @@ -94,3 +94,7 @@ void __init page_table_range_init(unsigned long start, unsigned long end, void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) { } + +void pgtable_cache_init(void) +{ +} -- GitLab From 6fbfe8d7cd7e71ceb281c5a1b9de6e5e0dfbf1c8 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 6 Jan 2010 15:46:53 +0900 Subject: [PATCH 0376/3892] sh: select HAVE_HW_BREAKPOINT for all SUPERH32 CPUs. All SH CPUs (with the exception of sh64) support the UBC, so select HW_BREAKPOINT support by default. This fixes up the build for non-SH4A targets. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index fa76d6264dff..f971cb74dd62 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -42,7 +42,7 @@ config SUPERH32 select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE select HAVE_FUNCTION_GRAPH_TRACER select HAVE_ARCH_KGDB - select HAVE_HW_BREAKPOINT if CPU_SH4A + select HAVE_HW_BREAKPOINT select PERF_EVENTS if HAVE_HW_BREAKPOINT select ARCH_HIBERNATION_POSSIBLE if MMU -- GitLab From 386d8772980be01b94bd463ea1e745732d7eb502 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:03 -0800 Subject: [PATCH 0377/3892] Input: serio - use device core to create 'id' attribute group Instead of creating 'id' sysfs attribute group by ourselves rely on device core to do that for us. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 0236f0d5fd91..0a278f9f1d3a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -452,6 +452,11 @@ static struct attribute_group serio_id_attr_group = { .attrs = serio_device_id_attrs, }; +static const struct attribute_group *serio_device_attr_groups[] = { + &serio_id_attr_group, + NULL +}; + static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); @@ -539,6 +544,7 @@ static void serio_init_port(struct serio *serio) (long)atomic_inc_return(&serio_no) - 1); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; + serio->dev.groups = serio_device_attr_groups; if (serio->parent) { serio->dev.parent = &serio->parent->dev; serio->depth = serio->parent->depth + 1; @@ -562,21 +568,17 @@ static void serio_add_port(struct serio *serio) } list_add_tail(&serio->node, &serio_list); + if (serio->start) serio->start(serio); + error = device_add(&serio->dev); if (error) printk(KERN_ERR "serio: device_add() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); - else { + else serio->registered = true; - error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); - if (error) - printk(KERN_ERR - "serio: sysfs_create_group() failed for %s (%s), error: %d\n", - serio->phys, serio->name, error); - } } /* @@ -604,7 +606,6 @@ static void serio_destroy_port(struct serio *serio) } if (serio->registered) { - sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); device_del(&serio->dev); serio->registered = false; } -- GitLab From ddf1ffbd40c92ff1e58c45fa96d309788f7beb60 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:04 -0800 Subject: [PATCH 0378/3892] Input: serio - let device core tell us if device was registered No need to keep track of it by ourselves. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 8 ++------ include/linux/serio.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 0a278f9f1d3a..d89880450f77 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -577,8 +577,6 @@ static void serio_add_port(struct serio *serio) printk(KERN_ERR "serio: device_add() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); - else - serio->registered = true; } /* @@ -605,10 +603,8 @@ static void serio_destroy_port(struct serio *serio) serio->parent = NULL; } - if (serio->registered) { + if (device_is_registered(&serio->dev)) device_del(&serio->dev); - serio->registered = false; - } list_del_init(&serio->node); serio_remove_pending_events(serio); @@ -995,7 +991,7 @@ irqreturn_t serio_interrupt(struct serio *serio, if (likely(serio->drv)) { ret = serio->drv->interrupt(serio, data, dfl); - } else if (!dfl && serio->registered) { + } else if (!dfl && device_is_registered(&serio->dev)) { serio_rescan(serio); ret = IRQ_HANDLED; } diff --git a/include/linux/serio.h b/include/linux/serio.h index e2f3044d4a4a..d0fb702059cd 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -30,7 +30,6 @@ struct serio { char phys[32]; bool manual_bind; - bool registered; /* port has been fully registered with driver core */ struct serio_device_id id; -- GitLab From 4516c8183213b59c3645d810ccb04b70c2606743 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:04 -0800 Subject: [PATCH 0379/3892] Input: serio - use list_first_entry() helper Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index d89880450f77..7fbf7670ae09 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -230,14 +230,12 @@ static void serio_free_event(struct serio_event *event) static void serio_remove_duplicate_events(struct serio_event *event) { - struct list_head *node, *next; - struct serio_event *e; + struct serio_event *e, *next; unsigned long flags; spin_lock_irqsave(&serio_event_lock, flags); - list_for_each_safe(node, next, &serio_event_list) { - e = list_entry(node, struct serio_event, node); + list_for_each_entry_safe(e, next, &serio_event_list, node) { if (event->object == e->object) { /* * If this event is of different type we should not @@ -247,7 +245,7 @@ static void serio_remove_duplicate_events(struct serio_event *event) if (event->type != e->type) break; - list_del_init(node); + list_del_init(&e->node); serio_free_event(e); } } @@ -258,23 +256,18 @@ static void serio_remove_duplicate_events(struct serio_event *event) static struct serio_event *serio_get_event(void) { - struct serio_event *event; - struct list_head *node; + struct serio_event *event = NULL; unsigned long flags; spin_lock_irqsave(&serio_event_lock, flags); - if (list_empty(&serio_event_list)) { - spin_unlock_irqrestore(&serio_event_lock, flags); - return NULL; + if (!list_empty(&serio_event_list)) { + event = list_first_entry(&serio_event_list, + struct serio_event, node); + list_del_init(&event->node); } - node = serio_event_list.next; - event = list_entry(node, struct serio_event, node); - list_del_init(node); - spin_unlock_irqrestore(&serio_event_lock, flags); - return event; } @@ -331,16 +324,14 @@ static void serio_handle_event(void) */ static void serio_remove_pending_events(void *object) { - struct list_head *node, *next; - struct serio_event *event; + struct serio_event *event, *next; unsigned long flags; spin_lock_irqsave(&serio_event_lock, flags); - list_for_each_safe(node, next, &serio_event_list) { - event = list_entry(node, struct serio_event, node); + list_for_each_entry_safe(event, next, &serio_event_list, node) { if (event->object == object) { - list_del_init(node); + list_del_init(&event->node); serio_free_event(event); } } -- GitLab From cac9169bf75ea8cbaab75be9dbe5eb79a2bad6f5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:04 -0800 Subject: [PATCH 0380/3892] Input: serio - use pr_xxx() and dev_xxx() helpers pr_xxx() and dev_xxx() helpers ensure that all messages emitted by the module have consistent prefixes, so let's use them. Also fix some formatting issues. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 77 +++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 7fbf7670ae09..ee69ec399e08 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -26,6 +26,8 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -119,11 +121,10 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) error = device_bind_driver(&serio->dev); if (error) { - printk(KERN_WARNING - "serio: device_bind_driver() failed " - "for %s (%s) and %s, error: %d\n", - serio->phys, serio->name, - drv->description, error); + dev_warn(&serio->dev, + "device_bind_driver() failed for %s (%s) and %s, error: %d\n", + serio->phys, serio->name, + drv->description, error); serio_disconnect_driver(serio); serio->dev.driver = NULL; return error; @@ -138,9 +139,9 @@ static void serio_find_driver(struct serio *serio) error = device_attach(&serio->dev); if (error < 0) - printk(KERN_WARNING - "serio: device_attach() failed for %s (%s), error: %d\n", - serio->phys, serio->name, error); + dev_warn(&serio->dev, + "device_attach() failed for %s (%s), error: %d\n", + serio->phys, serio->name, error); } @@ -194,17 +195,14 @@ static int serio_queue_event(void *object, struct module *owner, event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); if (!event) { - printk(KERN_ERR - "serio: Not enough memory to queue event %d\n", - event_type); + pr_err("Not enough memory to queue event %d\n", event_type); retval = -ENOMEM; goto out; } if (!try_module_get(owner)) { - printk(KERN_WARNING - "serio: Can't get module reference, dropping event %d\n", - event_type); + pr_warning("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; @@ -286,29 +284,27 @@ static void serio_handle_event(void) if ((event = serio_get_event())) { switch (event->type) { - case SERIO_REGISTER_PORT: - serio_add_port(event->object); - break; - case SERIO_RECONNECT_PORT: - serio_reconnect_port(event->object); - break; + case SERIO_REGISTER_PORT: + serio_add_port(event->object); + break; - case SERIO_RESCAN_PORT: - serio_disconnect_port(event->object); - serio_find_driver(event->object); - break; + case SERIO_RECONNECT_PORT: + serio_reconnect_port(event->object); + break; - case SERIO_RECONNECT_CHAIN: - serio_reconnect_chain(event->object); - break; + case SERIO_RESCAN_PORT: + serio_disconnect_port(event->object); + serio_find_driver(event->object); + break; - case SERIO_ATTACH_DRIVER: - serio_attach_driver(event->object); - break; + case SERIO_RECONNECT_CHAIN: + serio_reconnect_chain(event->object); + break; - default: - break; + case SERIO_ATTACH_DRIVER: + serio_attach_driver(event->object); + break; } serio_remove_duplicate_events(event); @@ -378,7 +374,6 @@ static int serio_thread(void *nothing) kthread_should_stop() || !list_empty(&serio_event_list)); } while (!kthread_should_stop()); - printk(KERN_DEBUG "serio: kseriod exiting\n"); return 0; } @@ -565,8 +560,8 @@ static void serio_add_port(struct serio *serio) error = device_add(&serio->dev); if (error) - printk(KERN_ERR - "serio: device_add() failed for %s (%s), error: %d\n", + dev_err(&serio->dev, + "device_add() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); } @@ -793,9 +788,8 @@ static void serio_attach_driver(struct serio_driver *drv) error = driver_attach(&drv->driver); if (error) - printk(KERN_WARNING - "serio: driver_attach() failed for %s with error %d\n", - drv->driver.name, error); + pr_warning("driver_attach() failed for %s with error %d\n", + drv->driver.name, error); } int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) @@ -815,8 +809,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons error = driver_register(&drv->driver); if (error) { - printk(KERN_ERR - "serio: driver_register() failed for %s, error: %d\n", + pr_err("driver_register() failed for %s, error: %d\n", drv->driver.name, error); return error; } @@ -1013,7 +1006,7 @@ static int __init serio_init(void) error = bus_register(&serio_bus); if (error) { - printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error); + pr_err("Failed to register serio bus, error: %d\n", error); return error; } @@ -1021,7 +1014,7 @@ static int __init serio_init(void) if (IS_ERR(serio_task)) { bus_unregister(&serio_bus); error = PTR_ERR(serio_task); - printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error); + pr_err("Failed to start kseriod, error: %d\n", error); return error; } -- GitLab From 361b7b5b032338361ea88412f1fc45479fdd5859 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:03 -0800 Subject: [PATCH 0381/3892] Input: gameport - let device core tell us if device was registered No need to keep track of it by ourselves. Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 6 +----- include/linux/gameport.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index ac11be08585e..f9e5f8e1690b 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -561,8 +561,6 @@ static void gameport_add_port(struct gameport *gameport) printk(KERN_ERR "gameport: device_add() failed for %s (%s), error: %d\n", gameport->phys, gameport->name, error); - else - gameport->registered = 1; } /* @@ -584,10 +582,8 @@ static void gameport_destroy_port(struct gameport *gameport) gameport->parent = NULL; } - if (gameport->registered) { + if (device_is_registered(&gameport->dev)) device_del(&gameport->dev); - gameport->registered = 0; - } list_del_init(&gameport->node); diff --git a/include/linux/gameport.h b/include/linux/gameport.h index 1bc08541c2b9..48e68da097f6 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -46,7 +46,6 @@ struct gameport { struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ struct device dev; - unsigned int registered; /* port has been fully registered with driver core */ struct list_head node; }; -- GitLab From d621af473079851caac873adc5431a05c9d78dfd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:03 -0800 Subject: [PATCH 0382/3892] Input: gameport - make use of list_first_entry() helper Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index f9e5f8e1690b..953a20bf26e8 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -298,14 +298,12 @@ static void gameport_free_event(struct gameport_event *event) static void gameport_remove_duplicate_events(struct gameport_event *event) { - struct list_head *node, *next; - struct gameport_event *e; + struct gameport_event *e, *next; unsigned long flags; spin_lock_irqsave(&gameport_event_lock, flags); - list_for_each_safe(node, next, &gameport_event_list) { - e = list_entry(node, struct gameport_event, node); + list_for_each_entry_safe(e, next, &gameport_event_list, node) { if (event->object == e->object) { /* * If this event is of different type we should not @@ -315,7 +313,7 @@ static void gameport_remove_duplicate_events(struct gameport_event *event) if (event->type != e->type) break; - list_del_init(node); + list_del_init(&e->node); gameport_free_event(e); } } @@ -325,21 +323,17 @@ static void gameport_remove_duplicate_events(struct gameport_event *event) static struct gameport_event *gameport_get_event(void) { - struct gameport_event *event; - struct list_head *node; + struct gameport_event *event = NULL; unsigned long flags; spin_lock_irqsave(&gameport_event_lock, flags); - if (list_empty(&gameport_event_list)) { - spin_unlock_irqrestore(&gameport_event_lock, flags); - return NULL; + if (!list_empty(&gameport_event_list)) { + event = list_first_entry(&gameport_event_list, + struct gameport_event, node); + list_del_init(&event->node); } - node = gameport_event_list.next; - event = list_entry(node, struct gameport_event, node); - list_del_init(node); - spin_unlock_irqrestore(&gameport_event_lock, flags); return event; @@ -385,16 +379,14 @@ static void gameport_handle_event(void) */ static void gameport_remove_pending_events(void *object) { - struct list_head *node, *next; - struct gameport_event *event; + struct gameport_event *event, *next; unsigned long flags; spin_lock_irqsave(&gameport_event_lock, flags); - list_for_each_safe(node, next, &gameport_event_list) { - event = list_entry(node, struct gameport_event, node); + list_for_each_entry_safe(event, next, &gameport_event_list, node) { if (event->object == object) { - list_del_init(node); + list_del_init(&event->node); gameport_free_event(event); } } -- GitLab From fc99ec6f4b6116305bca56a781b8b3b2ac054d27 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:03 -0800 Subject: [PATCH 0383/3892] Input: gameport - switch to using pr_xxx() and dev_xxx() pr_xxx() and dev_xxx() helpers ensure that all messages emitted by the module have consistent prefixes, so let's use them. Also fix some formatting issues. Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 62 ++++++++++++++----------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 953a20bf26e8..7e18bcf05a66 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -11,6 +11,8 @@ * the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -190,9 +192,8 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive error = device_bind_driver(&gameport->dev); if (error) { - printk(KERN_WARNING - "gameport: device_bind_driver() failed " - "for %s (%s) and %s, error: %d\n", + dev_warn(&gameport->dev, + "device_bind_driver() failed for %s (%s) and %s, error: %d\n", gameport->phys, gameport->name, drv->description, error); drv->disconnect(gameport); @@ -209,9 +210,9 @@ static void gameport_find_driver(struct gameport *gameport) error = device_attach(&gameport->dev); if (error < 0) - printk(KERN_WARNING - "gameport: device_attach() failed for %s (%s), error: %d\n", - gameport->phys, gameport->name, error); + dev_warn(&gameport->dev, + "device_attach() failed for %s (%s), error: %d\n", + gameport->phys, gameport->name, error); } @@ -262,17 +263,14 @@ static int gameport_queue_event(void *object, struct module *owner, event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC); if (!event) { - printk(KERN_ERR - "gameport: Not enough memory to queue event %d\n", - event_type); + pr_err("Not enough memory to queue event %d\n", event_type); retval = -ENOMEM; goto out; } if (!try_module_get(owner)) { - printk(KERN_WARNING - "gameport: Can't get module reference, dropping event %d\n", - event_type); + pr_warning("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; @@ -335,7 +333,6 @@ static struct gameport_event *gameport_get_event(void) } spin_unlock_irqrestore(&gameport_event_lock, flags); - return event; } @@ -354,16 +351,14 @@ static void gameport_handle_event(void) if ((event = gameport_get_event())) { switch (event->type) { - case GAMEPORT_REGISTER_PORT: - gameport_add_port(event->object); - break; - case GAMEPORT_ATTACH_DRIVER: - gameport_attach_driver(event->object); - break; + case GAMEPORT_REGISTER_PORT: + gameport_add_port(event->object); + break; - default: - break; + case GAMEPORT_ATTACH_DRIVER: + gameport_attach_driver(event->object); + break; } gameport_remove_duplicate_events(event); @@ -433,7 +428,6 @@ static int gameport_thread(void *nothing) kthread_should_stop() || !list_empty(&gameport_event_list)); } while (!kthread_should_stop()); - printk(KERN_DEBUG "gameport: kgameportd exiting\n"); return 0; } @@ -445,6 +439,7 @@ static int gameport_thread(void *nothing) static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf) { struct gameport *gameport = to_gameport_port(dev); + return sprintf(buf, "%s\n", gameport->name); } @@ -513,7 +508,8 @@ static void gameport_init_port(struct gameport *gameport) mutex_init(&gameport->drv_mutex); device_initialize(&gameport->dev); - dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); + dev_set_name(&gameport->dev, "gameport%lu", + (unsigned long)atomic_inc_return(&gameport_no) - 1); gameport->dev.bus = &gameport_bus; gameport->dev.release = gameport_release_port; if (gameport->parent) @@ -542,16 +538,16 @@ static void gameport_add_port(struct gameport *gameport) list_add_tail(&gameport->node, &gameport_list); if (gameport->io) - printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n", - gameport->name, gameport->phys, gameport->io, gameport->speed); + dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n", + gameport->name, gameport->phys, gameport->io, gameport->speed); else - printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n", + dev_info(&gameport->dev, "%s is %s, speed %dkHz\n", gameport->name, gameport->phys, gameport->speed); error = device_add(&gameport->dev); if (error) - printk(KERN_ERR - "gameport: device_add() failed for %s (%s), error: %d\n", + dev_err(&gameport->dev, + "device_add() failed for %s (%s), error: %d\n", gameport->phys, gameport->name, error); } @@ -693,8 +689,7 @@ static void gameport_attach_driver(struct gameport_driver *drv) error = driver_attach(&drv->driver); if (error) - printk(KERN_ERR - "gameport: driver_attach() failed for %s, error: %d\n", + pr_err("driver_attach() failed for %s, error: %d\n", drv->driver.name, error); } @@ -715,8 +710,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner error = driver_register(&drv->driver); if (error) { - printk(KERN_ERR - "gameport: driver_register() failed for %s, error: %d\n", + pr_err("driver_register() failed for %s, error: %d\n", drv->driver.name, error); return error; } @@ -816,7 +810,7 @@ static int __init gameport_init(void) error = bus_register(&gameport_bus); if (error) { - printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error); + pr_err("failed to register gameport bus, error: %d\n", error); return error; } @@ -824,7 +818,7 @@ static int __init gameport_init(void) if (IS_ERR(gameport_task)) { bus_unregister(&gameport_bus); error = PTR_ERR(gameport_task); - printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error); + pr_err("Failed to start kgameportd, error: %d\n", error); return error; } -- GitLab From 4f93df40859cf471774f6ef3ec7f2870c2e8e260 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:00 -0800 Subject: [PATCH 0384/3892] Input: automatically reset KEY_RESERVED bit for all input devices KEY_RESERVED is not supposed to be reported to userspace but rather to mark unused entries in keymaps. Acked-by: Henrique de Moraes Holschuh Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index ab060710688f..910d7be06eff 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -613,12 +613,12 @@ static int input_default_setkeycode(struct input_dev *dev, } } - clear_bit(old_keycode, dev->keybit); - set_bit(keycode, dev->keybit); + __clear_bit(old_keycode, dev->keybit); + __set_bit(keycode, dev->keybit); for (i = 0; i < dev->keycodemax; i++) { if (input_fetch_keycode(dev, i) == old_keycode) { - set_bit(old_keycode, dev->keybit); + __set_bit(old_keycode, dev->keybit); break; /* Setting the bit twice is useless, so break */ } } @@ -676,6 +676,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode) if (retval) goto out; + /* Make sure KEY_RESERVED did not get enabled. */ + __clear_bit(KEY_RESERVED, dev->keybit); + /* * Simulate keyup event if keycode is not present * in the keymap anymore @@ -1513,13 +1516,16 @@ int input_register_device(struct input_dev *dev) const char *path; int error; + /* Every input device generates EV_SYN/SYN_REPORT events. */ __set_bit(EV_SYN, dev->evbit); + /* KEY_RESERVED is not supposed to be transmitted to userspace. */ + __clear_bit(KEY_RESERVED, dev->keybit); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. */ - init_timer(&dev->timer); if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { dev->timer.data = (long) dev; -- GitLab From 92a3a58788790645c6143b5353ef065fd26110bb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Jan 2010 17:56:01 -0800 Subject: [PATCH 0385/3892] Input: cleanse capabilities bits before registering device To avoid showing garbage in capability bits, zero out bitmasks absent from dev->evbit in case driver inadvertently leaves some garbage there. Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/input/input.c b/drivers/input/input.c index 910d7be06eff..a31394c1eca8 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1497,6 +1497,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +#define INPUT_CLEANSE_BITMASK(dev, type, bits) \ + do { \ + if (!test_bit(EV_##type, dev->evbit)) \ + memset(dev->bits##bit, 0, \ + sizeof(dev->bits##bit)); \ + } while (0) + +static void input_cleanse_bitmasks(struct input_dev *dev) +{ + INPUT_CLEANSE_BITMASK(dev, KEY, key); + INPUT_CLEANSE_BITMASK(dev, REL, rel); + INPUT_CLEANSE_BITMASK(dev, ABS, abs); + INPUT_CLEANSE_BITMASK(dev, MSC, msc); + INPUT_CLEANSE_BITMASK(dev, LED, led); + INPUT_CLEANSE_BITMASK(dev, SND, snd); + INPUT_CLEANSE_BITMASK(dev, FF, ff); + INPUT_CLEANSE_BITMASK(dev, SW, sw); +} + /** * input_register_device - register device with input core * @dev: device to be registered @@ -1522,6 +1541,9 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); + /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ + input_cleanse_bitmasks(dev); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. -- GitLab From 3032458e38b583c92842818871e85c0f936b8645 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 6 Jan 2010 00:33:07 -0800 Subject: [PATCH 0386/3892] Input: psmouse - remove unused 'autocal' parameter from hgpk protocol Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index b146237266d8..29dc6aade766 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -68,10 +68,6 @@ module_param(post_interrupt_delay, int, 0644); MODULE_PARM_DESC(post_interrupt_delay, "delay (ms) before recal after recal interrupt detected"); -static int autorecal = 1; -module_param(autorecal, int, 0644); -MODULE_PARM_DESC(autorecal, "enable recalibration in the driver"); - /* * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" * above the pad and still have it send packets. This causes a jump cursor -- GitLab From 16295bec6398a3eedc9377e1af6ff4c71b98c300 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 6 Jan 2010 19:47:10 +1100 Subject: [PATCH 0387/3892] padata: Generic parallelization/serialization interface This patch introduces an interface to process data objects in parallel. The parallelized objects return after serialization in the same order as they were before the parallelization. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu --- include/linux/padata.h | 88 ++++++ init/Kconfig | 4 + kernel/Makefile | 1 + kernel/padata.c | 690 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 783 insertions(+) create mode 100644 include/linux/padata.h create mode 100644 kernel/padata.c diff --git a/include/linux/padata.h b/include/linux/padata.h new file mode 100644 index 000000000000..51611da9c498 --- /dev/null +++ b/include/linux/padata.h @@ -0,0 +1,88 @@ +/* + * padata.h - header for the padata parallelization interface + * + * Copyright (C) 2008, 2009 secunet Security Networks AG + * Copyright (C) 2008, 2009 Steffen Klassert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PADATA_H +#define PADATA_H + +#include +#include +#include + +struct padata_priv { + struct list_head list; + struct parallel_data *pd; + int cb_cpu; + int seq_nr; + int info; + void (*parallel)(struct padata_priv *padata); + void (*serial)(struct padata_priv *padata); +}; + +struct padata_list { + struct list_head list; + spinlock_t lock; +}; + +struct padata_queue { + struct padata_list parallel; + struct padata_list reorder; + struct padata_list serial; + struct work_struct pwork; + struct work_struct swork; + struct parallel_data *pd; + atomic_t num_obj; + int cpu_index; +}; + +struct parallel_data { + struct padata_instance *pinst; + struct padata_queue *queue; + atomic_t seq_nr; + atomic_t reorder_objects; + atomic_t refcnt; + unsigned int max_seq_nr; + cpumask_var_t cpumask; + spinlock_t lock; +}; + +struct padata_instance { + struct notifier_block cpu_notifier; + struct workqueue_struct *wq; + struct parallel_data *pd; + cpumask_var_t cpumask; + struct mutex lock; + u8 flags; +#define PADATA_INIT 1 +#define PADATA_RESET 2 +}; + +extern struct padata_instance *padata_alloc(const struct cpumask *cpumask, + struct workqueue_struct *wq); +extern void padata_free(struct padata_instance *pinst); +extern int padata_do_parallel(struct padata_instance *pinst, + struct padata_priv *padata, int cb_cpu); +extern void padata_do_serial(struct padata_priv *padata); +extern int padata_set_cpumask(struct padata_instance *pinst, + cpumask_var_t cpumask); +extern int padata_add_cpu(struct padata_instance *pinst, int cpu); +extern int padata_remove_cpu(struct padata_instance *pinst, int cpu); +extern void padata_start(struct padata_instance *pinst); +extern void padata_stop(struct padata_instance *pinst); +#endif diff --git a/init/Kconfig b/init/Kconfig index a23da9f01803..9fd23bcc1709 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1252,4 +1252,8 @@ source "block/Kconfig" config PREEMPT_NOTIFIERS bool +config PADATA + depends on SMP + bool + source "kernel/Kconfig.locks" diff --git a/kernel/Makefile b/kernel/Makefile index 864ff75d65f2..6aebdeb2aa34 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o +obj-$(CONFIG_PADATA) += padata.o ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff --git a/kernel/padata.c b/kernel/padata.c new file mode 100644 index 000000000000..6f9bcb8313d6 --- /dev/null +++ b/kernel/padata.c @@ -0,0 +1,690 @@ +/* + * padata.c - generic interface to process data streams in parallel + * + * Copyright (C) 2008, 2009 secunet Security Networks AG + * Copyright (C) 2008, 2009 Steffen Klassert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SEQ_NR INT_MAX - NR_CPUS +#define MAX_OBJ_NUM 10000 * NR_CPUS + +static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) +{ + int cpu, target_cpu; + + target_cpu = cpumask_first(pd->cpumask); + for (cpu = 0; cpu < cpu_index; cpu++) + target_cpu = cpumask_next(target_cpu, pd->cpumask); + + return target_cpu; +} + +static int padata_cpu_hash(struct padata_priv *padata) +{ + int cpu_index; + struct parallel_data *pd; + + pd = padata->pd; + + /* + * Hash the sequence numbers to the cpus by taking + * seq_nr mod. number of cpus in use. + */ + cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask); + + return padata_index_to_cpu(pd, cpu_index); +} + +static void padata_parallel_worker(struct work_struct *work) +{ + struct padata_queue *queue; + struct parallel_data *pd; + struct padata_instance *pinst; + LIST_HEAD(local_list); + + local_bh_disable(); + queue = container_of(work, struct padata_queue, pwork); + pd = queue->pd; + pinst = pd->pinst; + + spin_lock(&queue->parallel.lock); + list_replace_init(&queue->parallel.list, &local_list); + spin_unlock(&queue->parallel.lock); + + while (!list_empty(&local_list)) { + struct padata_priv *padata; + + padata = list_entry(local_list.next, + struct padata_priv, list); + + list_del_init(&padata->list); + + padata->parallel(padata); + } + + local_bh_enable(); +} + +/* + * padata_do_parallel - padata parallelization function + * + * @pinst: padata instance + * @padata: object to be parallelized + * @cb_cpu: cpu the serialization callback function will run on, + * must be in the cpumask of padata. + * + * The parallelization callback function will run with BHs off. + * Note: Every object which is parallelized by padata_do_parallel + * must be seen by padata_do_serial. + */ +int padata_do_parallel(struct padata_instance *pinst, + struct padata_priv *padata, int cb_cpu) +{ + int target_cpu, err; + struct padata_queue *queue; + struct parallel_data *pd; + + rcu_read_lock_bh(); + + pd = rcu_dereference(pinst->pd); + + err = 0; + if (!(pinst->flags & PADATA_INIT)) + goto out; + + err = -EBUSY; + if ((pinst->flags & PADATA_RESET)) + goto out; + + if (atomic_read(&pd->refcnt) >= MAX_OBJ_NUM) + goto out; + + err = -EINVAL; + if (!cpumask_test_cpu(cb_cpu, pd->cpumask)) + goto out; + + err = -EINPROGRESS; + atomic_inc(&pd->refcnt); + padata->pd = pd; + padata->cb_cpu = cb_cpu; + + if (unlikely(atomic_read(&pd->seq_nr) == pd->max_seq_nr)) + atomic_set(&pd->seq_nr, -1); + + padata->seq_nr = atomic_inc_return(&pd->seq_nr); + + target_cpu = padata_cpu_hash(padata); + queue = per_cpu_ptr(pd->queue, target_cpu); + + spin_lock(&queue->parallel.lock); + list_add_tail(&padata->list, &queue->parallel.list); + spin_unlock(&queue->parallel.lock); + + queue_work_on(target_cpu, pinst->wq, &queue->pwork); + +out: + rcu_read_unlock_bh(); + + return err; +} +EXPORT_SYMBOL(padata_do_parallel); + +static struct padata_priv *padata_get_next(struct parallel_data *pd) +{ + int cpu, num_cpus, empty, calc_seq_nr; + int seq_nr, next_nr, overrun, next_overrun; + struct padata_queue *queue, *next_queue; + struct padata_priv *padata; + struct padata_list *reorder; + + empty = 0; + next_nr = -1; + next_overrun = 0; + next_queue = NULL; + + num_cpus = cpumask_weight(pd->cpumask); + + for_each_cpu(cpu, pd->cpumask) { + queue = per_cpu_ptr(pd->queue, cpu); + reorder = &queue->reorder; + + /* + * Calculate the seq_nr of the object that should be + * next in this queue. + */ + overrun = 0; + calc_seq_nr = (atomic_read(&queue->num_obj) * num_cpus) + + queue->cpu_index; + + if (unlikely(calc_seq_nr > pd->max_seq_nr)) { + calc_seq_nr = calc_seq_nr - pd->max_seq_nr - 1; + overrun = 1; + } + + if (!list_empty(&reorder->list)) { + padata = list_entry(reorder->list.next, + struct padata_priv, list); + + seq_nr = padata->seq_nr; + BUG_ON(calc_seq_nr != seq_nr); + } else { + seq_nr = calc_seq_nr; + empty++; + } + + if (next_nr < 0 || seq_nr < next_nr + || (next_overrun && !overrun)) { + next_nr = seq_nr; + next_overrun = overrun; + next_queue = queue; + } + } + + padata = NULL; + + if (empty == num_cpus) + goto out; + + reorder = &next_queue->reorder; + + if (!list_empty(&reorder->list)) { + padata = list_entry(reorder->list.next, + struct padata_priv, list); + + if (unlikely(next_overrun)) { + for_each_cpu(cpu, pd->cpumask) { + queue = per_cpu_ptr(pd->queue, cpu); + atomic_set(&queue->num_obj, 0); + } + } + + spin_lock(&reorder->lock); + list_del_init(&padata->list); + atomic_dec(&pd->reorder_objects); + spin_unlock(&reorder->lock); + + atomic_inc(&next_queue->num_obj); + + goto out; + } + + if (next_nr % num_cpus == next_queue->cpu_index) { + padata = ERR_PTR(-ENODATA); + goto out; + } + + padata = ERR_PTR(-EINPROGRESS); +out: + return padata; +} + +static void padata_reorder(struct parallel_data *pd) +{ + struct padata_priv *padata; + struct padata_queue *queue; + struct padata_instance *pinst = pd->pinst; + +try_again: + if (!spin_trylock_bh(&pd->lock)) + goto out; + + while (1) { + padata = padata_get_next(pd); + + if (!padata || PTR_ERR(padata) == -EINPROGRESS) + break; + + if (PTR_ERR(padata) == -ENODATA) { + spin_unlock_bh(&pd->lock); + goto out; + } + + queue = per_cpu_ptr(pd->queue, padata->cb_cpu); + + spin_lock(&queue->serial.lock); + list_add_tail(&padata->list, &queue->serial.list); + spin_unlock(&queue->serial.lock); + + queue_work_on(padata->cb_cpu, pinst->wq, &queue->swork); + } + + spin_unlock_bh(&pd->lock); + + if (atomic_read(&pd->reorder_objects)) + goto try_again; + +out: + return; +} + +static void padata_serial_worker(struct work_struct *work) +{ + struct padata_queue *queue; + struct parallel_data *pd; + LIST_HEAD(local_list); + + local_bh_disable(); + queue = container_of(work, struct padata_queue, swork); + pd = queue->pd; + + spin_lock(&queue->serial.lock); + list_replace_init(&queue->serial.list, &local_list); + spin_unlock(&queue->serial.lock); + + while (!list_empty(&local_list)) { + struct padata_priv *padata; + + padata = list_entry(local_list.next, + struct padata_priv, list); + + list_del_init(&padata->list); + + padata->serial(padata); + atomic_dec(&pd->refcnt); + } + local_bh_enable(); +} + +/* + * padata_do_serial - padata serialization function + * + * @padata: object to be serialized. + * + * padata_do_serial must be called for every parallelized object. + * The serialization callback function will run with BHs off. + */ +void padata_do_serial(struct padata_priv *padata) +{ + int cpu; + struct padata_queue *queue; + struct parallel_data *pd; + + pd = padata->pd; + + cpu = get_cpu(); + queue = per_cpu_ptr(pd->queue, cpu); + + spin_lock(&queue->reorder.lock); + atomic_inc(&pd->reorder_objects); + list_add_tail(&padata->list, &queue->reorder.list); + spin_unlock(&queue->reorder.lock); + + put_cpu(); + + padata_reorder(pd); +} +EXPORT_SYMBOL(padata_do_serial); + +static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst, + const struct cpumask *cpumask) +{ + int cpu, cpu_index, num_cpus; + struct padata_queue *queue; + struct parallel_data *pd; + + cpu_index = 0; + + pd = kzalloc(sizeof(struct parallel_data), GFP_KERNEL); + if (!pd) + goto err; + + pd->queue = alloc_percpu(struct padata_queue); + if (!pd->queue) + goto err_free_pd; + + if (!alloc_cpumask_var(&pd->cpumask, GFP_KERNEL)) + goto err_free_queue; + + for_each_possible_cpu(cpu) { + queue = per_cpu_ptr(pd->queue, cpu); + + queue->pd = pd; + + if (cpumask_test_cpu(cpu, cpumask) + && cpumask_test_cpu(cpu, cpu_active_mask)) { + queue->cpu_index = cpu_index; + cpu_index++; + } else + queue->cpu_index = -1; + + INIT_LIST_HEAD(&queue->reorder.list); + INIT_LIST_HEAD(&queue->parallel.list); + INIT_LIST_HEAD(&queue->serial.list); + spin_lock_init(&queue->reorder.lock); + spin_lock_init(&queue->parallel.lock); + spin_lock_init(&queue->serial.lock); + + INIT_WORK(&queue->pwork, padata_parallel_worker); + INIT_WORK(&queue->swork, padata_serial_worker); + atomic_set(&queue->num_obj, 0); + } + + cpumask_and(pd->cpumask, cpumask, cpu_active_mask); + + num_cpus = cpumask_weight(pd->cpumask); + pd->max_seq_nr = (MAX_SEQ_NR / num_cpus) * num_cpus - 1; + + atomic_set(&pd->seq_nr, -1); + atomic_set(&pd->reorder_objects, 0); + atomic_set(&pd->refcnt, 0); + pd->pinst = pinst; + spin_lock_init(&pd->lock); + + return pd; + +err_free_queue: + free_percpu(pd->queue); +err_free_pd: + kfree(pd); +err: + return NULL; +} + +static void padata_free_pd(struct parallel_data *pd) +{ + free_cpumask_var(pd->cpumask); + free_percpu(pd->queue); + kfree(pd); +} + +static void padata_replace(struct padata_instance *pinst, + struct parallel_data *pd_new) +{ + struct parallel_data *pd_old = pinst->pd; + + pinst->flags |= PADATA_RESET; + + rcu_assign_pointer(pinst->pd, pd_new); + + synchronize_rcu(); + + while (atomic_read(&pd_old->refcnt) != 0) + yield(); + + flush_workqueue(pinst->wq); + + padata_free_pd(pd_old); + + pinst->flags &= ~PADATA_RESET; +} + +/* + * padata_set_cpumask - set the cpumask that padata should use + * + * @pinst: padata instance + * @cpumask: the cpumask to use + */ +int padata_set_cpumask(struct padata_instance *pinst, + cpumask_var_t cpumask) +{ + struct parallel_data *pd; + int err = 0; + + might_sleep(); + + mutex_lock(&pinst->lock); + + pd = padata_alloc_pd(pinst, cpumask); + if (!pd) { + err = -ENOMEM; + goto out; + } + + cpumask_copy(pinst->cpumask, cpumask); + + padata_replace(pinst, pd); + +out: + mutex_unlock(&pinst->lock); + + return err; +} +EXPORT_SYMBOL(padata_set_cpumask); + +static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +{ + struct parallel_data *pd; + + if (cpumask_test_cpu(cpu, cpu_active_mask)) { + pd = padata_alloc_pd(pinst, pinst->cpumask); + if (!pd) + return -ENOMEM; + + padata_replace(pinst, pd); + } + + return 0; +} + +/* + * padata_add_cpu - add a cpu to the padata cpumask + * + * @pinst: padata instance + * @cpu: cpu to add + */ +int padata_add_cpu(struct padata_instance *pinst, int cpu) +{ + int err; + + might_sleep(); + + mutex_lock(&pinst->lock); + + cpumask_set_cpu(cpu, pinst->cpumask); + err = __padata_add_cpu(pinst, cpu); + + mutex_unlock(&pinst->lock); + + return err; +} +EXPORT_SYMBOL(padata_add_cpu); + +static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +{ + struct parallel_data *pd; + + if (cpumask_test_cpu(cpu, cpu_online_mask)) { + pd = padata_alloc_pd(pinst, pinst->cpumask); + if (!pd) + return -ENOMEM; + + padata_replace(pinst, pd); + } + + return 0; +} + +/* + * padata_remove_cpu - remove a cpu from the padata cpumask + * + * @pinst: padata instance + * @cpu: cpu to remove + */ +int padata_remove_cpu(struct padata_instance *pinst, int cpu) +{ + int err; + + might_sleep(); + + mutex_lock(&pinst->lock); + + cpumask_clear_cpu(cpu, pinst->cpumask); + err = __padata_remove_cpu(pinst, cpu); + + mutex_unlock(&pinst->lock); + + return err; +} +EXPORT_SYMBOL(padata_remove_cpu); + +/* + * padata_start - start the parallel processing + * + * @pinst: padata instance to start + */ +void padata_start(struct padata_instance *pinst) +{ + might_sleep(); + + mutex_lock(&pinst->lock); + pinst->flags |= PADATA_INIT; + mutex_unlock(&pinst->lock); +} +EXPORT_SYMBOL(padata_start); + +/* + * padata_stop - stop the parallel processing + * + * @pinst: padata instance to stop + */ +void padata_stop(struct padata_instance *pinst) +{ + might_sleep(); + + mutex_lock(&pinst->lock); + pinst->flags &= ~PADATA_INIT; + mutex_unlock(&pinst->lock); +} +EXPORT_SYMBOL(padata_stop); + +static int __cpuinit padata_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + int err; + struct padata_instance *pinst; + int cpu = (unsigned long)hcpu; + + pinst = container_of(nfb, struct padata_instance, cpu_notifier); + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + if (!cpumask_test_cpu(cpu, pinst->cpumask)) + break; + mutex_lock(&pinst->lock); + err = __padata_add_cpu(pinst, cpu); + mutex_unlock(&pinst->lock); + if (err) + return NOTIFY_BAD; + break; + + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + if (!cpumask_test_cpu(cpu, pinst->cpumask)) + break; + mutex_lock(&pinst->lock); + err = __padata_remove_cpu(pinst, cpu); + mutex_unlock(&pinst->lock); + if (err) + return NOTIFY_BAD; + break; + + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + if (!cpumask_test_cpu(cpu, pinst->cpumask)) + break; + mutex_lock(&pinst->lock); + __padata_remove_cpu(pinst, cpu); + mutex_unlock(&pinst->lock); + + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: + if (!cpumask_test_cpu(cpu, pinst->cpumask)) + break; + mutex_lock(&pinst->lock); + __padata_add_cpu(pinst, cpu); + mutex_unlock(&pinst->lock); + } + + return NOTIFY_OK; +} + +/* + * padata_alloc - allocate and initialize a padata instance + * + * @cpumask: cpumask that padata uses for parallelization + * @wq: workqueue to use for the allocated padata instance + */ +struct padata_instance *padata_alloc(const struct cpumask *cpumask, + struct workqueue_struct *wq) +{ + int err; + struct padata_instance *pinst; + struct parallel_data *pd; + + pinst = kzalloc(sizeof(struct padata_instance), GFP_KERNEL); + if (!pinst) + goto err; + + pd = padata_alloc_pd(pinst, cpumask); + if (!pd) + goto err_free_inst; + + rcu_assign_pointer(pinst->pd, pd); + + pinst->wq = wq; + + cpumask_copy(pinst->cpumask, cpumask); + + pinst->flags = 0; + + pinst->cpu_notifier.notifier_call = padata_cpu_callback; + pinst->cpu_notifier.priority = 0; + err = register_hotcpu_notifier(&pinst->cpu_notifier); + if (err) + goto err_free_pd; + + mutex_init(&pinst->lock); + + return pinst; + +err_free_pd: + padata_free_pd(pd); +err_free_inst: + kfree(pinst); +err: + return NULL; +} +EXPORT_SYMBOL(padata_alloc); + +/* + * padata_free - free a padata instance + * + * @ padata_inst: padata instance to free + */ +void padata_free(struct padata_instance *pinst) +{ + padata_stop(pinst); + + synchronize_rcu(); + + while (atomic_read(&pinst->pd->refcnt) != 0) + yield(); + + unregister_hotcpu_notifier(&pinst->cpu_notifier); + padata_free_pd(pinst->pd); + kfree(pinst); +} +EXPORT_SYMBOL(padata_free); -- GitLab From 54a6593d65e638ad7e1e8cc986159d76054dab4b Mon Sep 17 00:00:00 2001 From: Stefan Glasenhardt Date: Tue, 5 Jan 2010 23:30:30 +0100 Subject: [PATCH 0388/3892] HID: allow disabling hard-coded ISO-layout for Apple keyboards This patch adds a new option named "iso_layout" to the driver "hid-apple.ko", to allow disabling of the hard-coded ISO-layout. Disabling the hard-coded layout solves the problem that the kernel-module only works perfectly for the english/american version of the Apple aluminum keyboard. Other versions have swapped keys, e.g. the "<"-key is swapped with "^"-key on the german keyboard. There is a very long bug-entry on Launchpad to this problem: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/214786 Signed-off-by: Stefan Glasenhardt Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 4b96e7a898cf..1433cbbaa99f 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -40,6 +40,11 @@ module_param(fnmode, uint, 0644); MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " "[1] = fkeyslast, 2 = fkeysfirst)"); +static unsigned int iso_layout = 1; +module_param(iso_layout, uint, 0644); +MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. " + "(0 = disabled, [1] = enabled)"); + struct apple_sc { unsigned long quirks; unsigned int fn_on; @@ -199,11 +204,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } } - if (asc->quirks & APPLE_ISO_KEYBOARD) { - trans = apple_find_translation(apple_iso_keyboard, usage->code); - if (trans) { - input_event(input, usage->type, trans->to, value); - return 1; + if (iso_layout) { + if (asc->quirks & APPLE_ISO_KEYBOARD) { + trans = apple_find_translation(apple_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } } } -- GitLab From 17263baf958b7ab1d8c60445f412a1080362c88c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Jan 2010 16:43:08 -0500 Subject: [PATCH 0389/3892] kconfig: Create include/generated for localmodconfig If someone downloads a brand new kernel and runs localmodconfig or localyesconfig, the ending result will report: *** Error during update of the kernel configuration. This is because localmodconfig and localyesconfig must create the include/generated directory to place the autoconf.h file. Signed-off-by: Steven Rostedt --- scripts/kconfig/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 999e8a7d5bf7..006c96f5fcb5 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -31,6 +31,7 @@ silentoldconfig: $(obj)/conf $< -s $(Kconfig) localmodconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ @@ -45,6 +46,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)rm -f .tmp.config localyesconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ -- GitLab From 13d7e9385644d376a0816ad663ba3dfc45359f2f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Jan 2010 17:56:12 -0500 Subject: [PATCH 0390/3892] kconfig: Check for if conditions in Kconfig for localmodconfig The streamline_config.pl misses the if conditions for checking dependencies. For Kconfigs with the following construct: if MEDIA_SUPPORT config VIDEO_DEV [...] If VIDEO_DEV was enabled, the script will miss the fact that MEDIA_SUPPORT is also needed. This patch changes streamline_config.pl to include if conditions into the dependencies of configs. Reported-by: Anton Blanchard Tested-by: Anton Blanchard Signed-off-by: Steven Rostedt --- scripts/kconfig/streamline_config.pl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 0d800820c3cd..9e66fa8dc52e 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -121,6 +121,8 @@ my %prompts; my %objects; my $var; my $cont = 0; +my $iflevel = 0; +my @ifdeps; # prevent recursion my %read_kconfigs; @@ -146,6 +148,15 @@ sub read_kconfig { $state = "NEW"; $config = $1; + for (my $i = 0; $i < $iflevel; $i++) { + if ($i) { + $depends{$config} .= " " . $ifdeps[$i]; + } else { + $depends{$config} = $ifdeps[$i]; + } + $state = "DEP"; + } + # collect the depends for the config } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { $state = "DEP"; @@ -166,6 +177,21 @@ sub read_kconfig { # note if the config has a prompt $prompt{$config} = 1; + # Check for if statements + } elsif (/^if\s+(.*\S)\s*$/) { + my $deps = $1; + # remove beginning and ending non text + $deps =~ s/^[^a-zA-Z0-9_]*//; + $deps =~ s/[^a-zA-Z0-9_]*$//; + + my @deps = split /[^a-zA-Z0-9_]+/, $deps; + + $ifdeps[$iflevel++] = join ':', @deps; + + } elsif (/^endif/) { + + $iflevel-- if ($iflevel); + # stop on "help" } elsif (/^\s*help\s*$/) { $state = "NONE"; -- GitLab From c32bbff81c04096c7888aed3946ee90fdbfbc3a3 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Thu, 31 Dec 2009 00:49:43 +0000 Subject: [PATCH 0391/3892] sky2: Refactor sky2_get_regs into two functions Separate code deciding which registers can be accessed out of sky2_get_regs in preparation for adding more conditions into it. Signed-off-by: Mike McCormack Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 94 +++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1c01b96c9611..faa48410195e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3837,6 +3837,50 @@ static int sky2_get_regs_len(struct net_device *dev) return 0x4000; } +static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b) +{ + /* This complicated switch statement is to make sure and + * only access regions that are unreserved. + * Some blocks are only valid on dual port cards. + */ + switch (b) { + /* second port */ + case 5: /* Tx Arbiter 2 */ + case 9: /* RX2 */ + case 14 ... 15: /* TX2 */ + case 17: case 19: /* Ram Buffer 2 */ + case 22 ... 23: /* Tx Ram Buffer 2 */ + case 25: /* Rx MAC Fifo 1 */ + case 27: /* Tx MAC Fifo 2 */ + case 31: /* GPHY 2 */ + case 40 ... 47: /* Pattern Ram 2 */ + case 52: case 54: /* TCP Segmentation 2 */ + case 112 ... 116: /* GMAC 2 */ + return hw->ports > 1; + + case 0: /* Control */ + case 2: /* Mac address */ + case 4: /* Tx Arbiter 1 */ + case 7: /* PCI express reg */ + case 8: /* RX1 */ + case 12 ... 13: /* TX1 */ + case 16: case 18:/* Rx Ram Buffer 1 */ + case 20 ... 21: /* Tx Ram Buffer 1 */ + case 24: /* Rx MAC Fifo 1 */ + case 26: /* Tx MAC Fifo 1 */ + case 28 ... 29: /* Descriptor and status unit */ + case 30: /* GPHY 1*/ + case 32 ... 39: /* Pattern Ram 1 */ + case 48: case 50: /* TCP Segmentation 1 */ + case 56 ... 60: /* PCI space */ + case 80 ... 84: /* GMAC 1 */ + return 1; + + default: + return 0; + } +} + /* * Returns copy of control register region * Note: ethtool_get_regs always provides full size (16k) buffer @@ -3851,55 +3895,13 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, regs->version = 1; for (b = 0; b < 128; b++) { - /* This complicated switch statement is to make sure and - * only access regions that are unreserved. - * Some blocks are only valid on dual port cards. - * and block 3 has some special diagnostic registers that - * are poison. - */ - switch (b) { - case 3: - /* skip diagnostic ram region */ + /* skip poisonous diagnostic ram region in block 3 */ + if (b == 3) memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10); - break; - - /* dual port cards only */ - case 5: /* Tx Arbiter 2 */ - case 9: /* RX2 */ - case 14 ... 15: /* TX2 */ - case 17: case 19: /* Ram Buffer 2 */ - case 22 ... 23: /* Tx Ram Buffer 2 */ - case 25: /* Rx MAC Fifo 1 */ - case 27: /* Tx MAC Fifo 2 */ - case 31: /* GPHY 2 */ - case 40 ... 47: /* Pattern Ram 2 */ - case 52: case 54: /* TCP Segmentation 2 */ - case 112 ... 116: /* GMAC 2 */ - if (sky2->hw->ports == 1) - goto reserved; - /* fall through */ - case 0: /* Control */ - case 2: /* Mac address */ - case 4: /* Tx Arbiter 1 */ - case 7: /* PCI express reg */ - case 8: /* RX1 */ - case 12 ... 13: /* TX1 */ - case 16: case 18:/* Rx Ram Buffer 1 */ - case 20 ... 21: /* Tx Ram Buffer 1 */ - case 24: /* Rx MAC Fifo 1 */ - case 26: /* Tx MAC Fifo 1 */ - case 28 ... 29: /* Descriptor and status unit */ - case 30: /* GPHY 1*/ - case 32 ... 39: /* Pattern Ram 1 */ - case 48: case 50: /* TCP Segmentation 1 */ - case 56 ... 60: /* PCI space */ - case 80 ... 84: /* GMAC 1 */ + else if (sky2_reg_access_ok(sky2->hw, b)) memcpy_fromio(p, io, 128); - break; - default: -reserved: + else memset(p, 0, 128); - } p += 128; io += 128; -- GitLab From c36531b9b2e00d9715c3a0f5788ac5311435e078 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Thu, 31 Dec 2009 00:55:31 +0000 Subject: [PATCH 0392/3892] sky2: Lock transmit queue while disabling device netif_device_detach() does not take the tx_lock, so it's possible that a call to sky2_xmit_frame is still in progress after netif_device_detach() is complete. Take netif_tx_lock() to make sure all transmits have stopped while we're disabling the devices and that no other CPU is still transmitting a frame after we've disabling the device. Proposed fix for "sky2 panic under load" reported by Berck E. Nash. Signed-off-by: Mike McCormack Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index faa48410195e..8ae8520baaf3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3176,7 +3176,9 @@ static void sky2_reset(struct sky2_hw *hw) static void sky2_detach(struct net_device *dev) { if (netif_running(dev)) { + netif_tx_lock(dev); netif_device_detach(dev); /* stop txq */ + netif_tx_unlock(dev); sky2_down(dev); } } -- GitLab From 572c526fb19a9a24098de814ab0601c1ce1bac82 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sat, 2 Jan 2010 10:37:42 +0000 Subject: [PATCH 0393/3892] qlge: Turn on RX header split based on platform. Using 4-byte aligned headers is problematic for some architectures. Since qlge uses 4-byte aligned rx buffers we split headers for these architectures into a separate buffer and then recopy to align on 2-byte boundary. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 19 +++++++++++++++---- drivers/net/qlge/qlge_main.c | 6 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 862c1aaf3860..ee0e2bd4842f 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -54,12 +54,8 @@ #define RX_RING_SHADOW_SPACE (sizeof(u64) + \ MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) -#define SMALL_BUFFER_SIZE 512 -#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2) #define LARGE_BUFFER_MAX_SIZE 8192 #define LARGE_BUFFER_MIN_SIZE 2048 -#define MAX_SPLIT_SIZE 1023 -#define QLGE_SB_PAD 32 #define MAX_CQ 128 #define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */ @@ -737,6 +733,21 @@ enum { PRB_MX_DATA = 0xfc, /* Use semaphore */ }; +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +#define SMALL_BUFFER_SIZE 256 +#define SMALL_BUF_MAP_SIZE SMALL_BUFFER_SIZE +#define SPLT_SETTING FSC_DBRST_1024 +#define SPLT_LEN 0 +#define QLGE_SB_PAD 0 +#else +#define SMALL_BUFFER_SIZE 512 +#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2) +#define SPLT_SETTING FSC_SH +#define SPLT_LEN (SPLT_HDR_EP | \ + min(SMALL_BUF_MAP_SIZE, 1023)) +#define QLGE_SB_PAD 32 +#endif + /* * CAM output format. */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 707b391afa02..c3034786965d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3332,15 +3332,15 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) /* Enable the function, set pagesize, enable error checking. */ value = FSC_FE | FSC_EPC_INBOUND | FSC_EPC_OUTBOUND | - FSC_EC | FSC_VM_PAGE_4K | FSC_SH; + FSC_EC | FSC_VM_PAGE_4K; + value |= SPLT_SETTING; /* Set/clear header splitting. */ mask = FSC_VM_PAGESIZE_MASK | FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16); ql_write32(qdev, FSC, mask | value); - ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP | - min(SMALL_BUF_MAP_SIZE, MAX_SPLIT_SIZE)); + ql_write32(qdev, SPLT_HDR, SPLT_LEN); /* Set RX packet routing to use port/pci function on which the * packet arrived on in addition to usual frame routing. -- GitLab From 4f848c0a9c265cb3457fbf842dbffd28e82a44fd Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sat, 2 Jan 2010 10:37:43 +0000 Subject: [PATCH 0394/3892] qlge: Add RX frame handlers for non-split frames. New handlers are added here to handle: 1) Small frames (<256 bytes) in a single small buffer. Allocate a new skb and copy the frame. 2) Large frame (>256 bytes) in a page chunk. Allocate an skb, tack it on frags, post to napi_gro_receive(). Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 261 ++++++++++++++++++++++++++++++++++- 1 file changed, 257 insertions(+), 4 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c3034786965d..109bd0abe9b4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1433,6 +1433,209 @@ map_error: return NETDEV_TX_BUSY; } +/* Process an inbound completion from an rx ring. */ +static void ql_process_mac_rx_page(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp, + u32 length, + u16 vlan_id) +{ + struct net_device *ndev = qdev->ndev; + struct sk_buff *skb = NULL; + void *addr; + struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); + struct napi_struct *napi = &rx_ring->napi; + + skb = netdev_alloc_skb(ndev, length); + if (!skb) { + QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, " + "need to unwind!.\n"); + rx_ring->rx_dropped++; + put_page(lbq_desc->p.pg_chunk.page); + return; + } + + addr = lbq_desc->p.pg_chunk.va; + prefetch(addr); + + + /* Frame error, so drop the packet. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { + QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", + ib_mac_rsp->flags2); + rx_ring->rx_errors++; + goto err_out; + } + + /* The max framesize filter on this chip is set higher than + * MTU since FCoE uses 2k frames. + */ + if (skb->len > ndev->mtu + ETH_HLEN) { + QPRINTK(qdev, DRV, ERR, "Segment too small, dropping.\n"); + rx_ring->rx_dropped++; + goto err_out; + } + memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN); + QPRINTK(qdev, RX_STATUS, DEBUG, + "%d bytes of headers and data in large. Chain " + "page to new skb and pull tail.\n", length); + skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page, + lbq_desc->p.pg_chunk.offset+ETH_HLEN, + length-ETH_HLEN); + skb->len += length-ETH_HLEN; + skb->data_len += length-ETH_HLEN; + skb->truesize += length-ETH_HLEN; + + rx_ring->rx_packets++; + rx_ring->rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + if (qdev->rx_csum && + !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { + /* TCP frame. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && + (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { + /* Unfragmented ipv4 UDP frame. */ + struct iphdr *iph = (struct iphdr *) skb->data; + if (!(iph->frag_off & + cpu_to_be16(IP_MF|IP_OFFSET))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + } + } + } + + skb_record_rx_queue(skb, rx_ring->cq_id); + if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (qdev->vlgrp && (vlan_id != 0xffff)) + vlan_gro_receive(napi, qdev->vlgrp, vlan_id, skb); + else + napi_gro_receive(napi, skb); + } else { + if (qdev->vlgrp && (vlan_id != 0xffff)) + vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id); + else + netif_receive_skb(skb); + } + return; +err_out: + dev_kfree_skb_any(skb); + put_page(lbq_desc->p.pg_chunk.page); +} + +/* Process an inbound completion from an rx ring. */ +static void ql_process_mac_rx_skb(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp, + u32 length, + u16 vlan_id) +{ + struct net_device *ndev = qdev->ndev; + struct sk_buff *skb = NULL; + struct sk_buff *new_skb = NULL; + struct bq_desc *sbq_desc = ql_get_curr_sbuf(rx_ring); + + skb = sbq_desc->p.skb; + /* Allocate new_skb and copy */ + new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN); + if (new_skb == NULL) { + QPRINTK(qdev, PROBE, ERR, + "No skb available, drop the packet.\n"); + rx_ring->rx_dropped++; + return; + } + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(skb_put(new_skb, length), skb->data, length); + skb = new_skb; + + /* Frame error, so drop the packet. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { + QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", + ib_mac_rsp->flags2); + dev_kfree_skb_any(skb); + rx_ring->rx_errors++; + return; + } + + /* loopback self test for ethtool */ + if (test_bit(QL_SELFTEST, &qdev->flags)) { + ql_check_lb_frame(qdev, skb); + dev_kfree_skb_any(skb); + return; + } + + /* The max framesize filter on this chip is set higher than + * MTU since FCoE uses 2k frames. + */ + if (skb->len > ndev->mtu + ETH_HLEN) { + dev_kfree_skb_any(skb); + rx_ring->rx_dropped++; + return; + } + + prefetch(skb->data); + skb->dev = ndev; + if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { + QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_REG ? "Registered" : "", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); + } + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) + QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); + + rx_ring->rx_packets++; + rx_ring->rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + /* If rx checksum is on, and there are no + * csum or frame errors. + */ + if (qdev->rx_csum && + !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { + /* TCP frame. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && + (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { + /* Unfragmented ipv4 UDP frame. */ + struct iphdr *iph = (struct iphdr *) skb->data; + if (!(iph->frag_off & + cpu_to_be16(IP_MF|IP_OFFSET))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + } + } + } + + skb_record_rx_queue(skb, rx_ring->cq_id); + if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (qdev->vlgrp && (vlan_id != 0xffff)) + vlan_gro_receive(&rx_ring->napi, qdev->vlgrp, + vlan_id, skb); + else + napi_gro_receive(&rx_ring->napi, skb); + } else { + if (qdev->vlgrp && (vlan_id != 0xffff)) + vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id); + else + netif_receive_skb(skb); + } +} + static void ql_realign_skb(struct sk_buff *skb, int len) { void *temp_addr = skb->data; @@ -1646,14 +1849,13 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, } /* Process an inbound completion from an rx ring. */ -static void ql_process_mac_rx_intr(struct ql_adapter *qdev, +static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, struct rx_ring *rx_ring, - struct ib_mac_iocb_rsp *ib_mac_rsp) + struct ib_mac_iocb_rsp *ib_mac_rsp, + u16 vlan_id) { struct net_device *ndev = qdev->ndev; struct sk_buff *skb = NULL; - u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) & - IB_MAC_IOCB_RSP_VLAN_MASK) QL_DUMP_IB_MAC_RSP(ib_mac_rsp); @@ -1753,6 +1955,57 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, } } +/* Process an inbound completion from an rx ring. */ +static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp) +{ + u32 length = le32_to_cpu(ib_mac_rsp->data_len); + u16 vlan_id = (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? + ((le16_to_cpu(ib_mac_rsp->vlan_id) & + IB_MAC_IOCB_RSP_VLAN_MASK)) : 0xffff; + + QL_DUMP_IB_MAC_RSP(ib_mac_rsp); + + if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) { + /* The data and headers are split into + * separate buffers. + */ + ql_process_mac_split_rx_intr(qdev, rx_ring, ib_mac_rsp, + vlan_id); + } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) { + /* The data fit in a single small buffer. + * Allocate a new skb, copy the data and + * return the buffer to the free pool. + */ + ql_process_mac_rx_skb(qdev, rx_ring, ib_mac_rsp, + length, vlan_id); + } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) { + /* Non-TCP packet in a page chunk. Allocate an + * skb, tack it on frags, and send it up. + */ + ql_process_mac_rx_page(qdev, rx_ring, ib_mac_rsp, + length, vlan_id); + } else { + struct bq_desc *lbq_desc; + + /* Free small buffer that holds the IAL */ + lbq_desc = ql_get_curr_sbuf(rx_ring); + QPRINTK(qdev, RX_ERR, ERR, "Dropping frame, len %d > mtu %d\n", + length, qdev->ndev->mtu); + + /* Unwind the large buffers for this frame. */ + while (length > 0) { + lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); + length -= (length < rx_ring->lbq_buf_size) ? + length : rx_ring->lbq_buf_size; + put_page(lbq_desc->p.pg_chunk.page); + } + } + + return (unsigned long)length; +} + /* Process an outbound completion from an rx ring. */ static void ql_process_mac_tx_intr(struct ql_adapter *qdev, struct ob_mac_iocb_rsp *mac_rsp) -- GitLab From 635267130855e91f4681df5e4d26ca9ce908447f Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sat, 2 Jan 2010 10:37:44 +0000 Subject: [PATCH 0395/3892] qlge: Add napi gro frags interface. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 109bd0abe9b4..e9d6481ed9eb 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1433,6 +1433,51 @@ map_error: return NETDEV_TX_BUSY; } +/* Process an inbound completion from an rx ring. */ +static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev, + struct rx_ring *rx_ring, + struct ib_mac_iocb_rsp *ib_mac_rsp, + u32 length, + u16 vlan_id) +{ + struct sk_buff *skb; + struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); + struct skb_frag_struct *rx_frag; + int nr_frags; + struct napi_struct *napi = &rx_ring->napi; + + napi->dev = qdev->ndev; + + skb = napi_get_frags(napi); + if (!skb) { + QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, exiting.\n"); + rx_ring->rx_dropped++; + put_page(lbq_desc->p.pg_chunk.page); + return; + } + prefetch(lbq_desc->p.pg_chunk.va); + rx_frag = skb_shinfo(skb)->frags; + nr_frags = skb_shinfo(skb)->nr_frags; + rx_frag += nr_frags; + rx_frag->page = lbq_desc->p.pg_chunk.page; + rx_frag->page_offset = lbq_desc->p.pg_chunk.offset; + rx_frag->size = length; + + skb->len += length; + skb->data_len += length; + skb->truesize += length; + skb_shinfo(skb)->nr_frags++; + + rx_ring->rx_packets++; + rx_ring->rx_bytes += length; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(skb, rx_ring->cq_id); + if (qdev->vlgrp && (vlan_id != 0xffff)) + vlan_gro_frags(&rx_ring->napi, qdev->vlgrp, vlan_id); + else + napi_gro_frags(napi); +} + /* Process an inbound completion from an rx ring. */ static void ql_process_mac_rx_page(struct ql_adapter *qdev, struct rx_ring *rx_ring, @@ -1980,6 +2025,14 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev, */ ql_process_mac_rx_skb(qdev, rx_ring, ib_mac_rsp, length, vlan_id); + } else if ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) && + !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK) && + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T)) { + /* TCP packet in a page chunk that's been checksummed. + * Tack it on to our GRO skb and let it go. + */ + ql_process_mac_rx_gro_page(qdev, rx_ring, ib_mac_rsp, + length, vlan_id); } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) { /* Non-TCP packet in a page chunk. Allocate an * skb, tack it on frags, and send it up. -- GitLab From 698244ace8b63896565022143ab19f141bc48993 Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Wed, 6 Jan 2010 20:35:14 -0800 Subject: [PATCH 0396/3892] phy: SMSC device Energy Detect power-down mode SMSC Ethernet Transceivers (LAN88710, LAN8710, LAN8720, LAN8187, LAN8700, LAN83C185) provide a mechanism to conserve power when the device is not connected to an active link partner (Energy Detect Mode). So this patch enables the Energy Detect power-down mode for these Transceivers. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 5123bb954dd7..ed2644a57500 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -25,6 +25,7 @@ #define MII_LAN83C185_ISF 29 /* Interrupt Source Flags */ #define MII_LAN83C185_IM 30 /* Interrupt Mask */ +#define MII_LAN83C185_CTRL_STATUS 17 /* Mode/Status Register */ #define MII_LAN83C185_ISF_INT1 (1<<1) /* Auto-Negotiation Page Received */ #define MII_LAN83C185_ISF_INT2 (1<<2) /* Parallel Detection Fault */ @@ -37,8 +38,10 @@ #define MII_LAN83C185_ISF_INT_ALL (0x0e) #define MII_LAN83C185_ISF_INT_PHYLIB_EVENTS \ - (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4) + (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4 | \ + MII_LAN83C185_ISF_INT7) +#define MII_LAN83C185_EDPWRDOWN (1 << 13) /* EDPWRDOWN */ static int smsc_phy_config_intr(struct phy_device *phydev) { @@ -59,9 +62,23 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev) { + int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); + if (rc < 0) + return rc; + + /* Enable energy detect mode for this SMSC Transceivers */ + rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, + rc | MII_LAN83C185_EDPWRDOWN); + if (rc < 0) + return rc; + return smsc_phy_ack_interrupt (phydev); } +static int lan911x_config_init(struct phy_device *phydev) +{ + return smsc_phy_ack_interrupt(phydev); +} static struct phy_driver lan83c185_driver = { .phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */ @@ -147,7 +164,7 @@ static struct phy_driver lan911x_int_driver = { /* basic functions */ .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .config_init = smsc_phy_config_init, + .config_init = lan911x_config_init, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, -- GitLab From 35076402a9936fa8a73b57a1f97fecbeceeec34a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Jan 2010 11:52:59 +0000 Subject: [PATCH 0397/3892] drivers/net/mac8390.c: Indent case labels Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 252 +++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 126 deletions(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index f8fa0c3f0f64..6b6f375440a2 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -164,70 +164,70 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count); static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) { switch (dev->dr_sw) { - case NUBUS_DRSW_3COM: - switch (dev->dr_hw) { - case NUBUS_DRHW_APPLE_SONIC_NB: - case NUBUS_DRHW_APPLE_SONIC_LC: - case NUBUS_DRHW_SONNET: - return MAC8390_NONE; - break; - default: - return MAC8390_APPLE; - break; - } + case NUBUS_DRSW_3COM: + switch (dev->dr_hw) { + case NUBUS_DRHW_APPLE_SONIC_NB: + case NUBUS_DRHW_APPLE_SONIC_LC: + case NUBUS_DRHW_SONNET: + return MAC8390_NONE; break; - - case NUBUS_DRSW_APPLE: - switch (dev->dr_hw) { - case NUBUS_DRHW_ASANTE_LC: - return MAC8390_NONE; - break; - case NUBUS_DRHW_CABLETRON: - return MAC8390_CABLETRON; - break; - default: - return MAC8390_APPLE; - break; - } + default: + return MAC8390_APPLE; break; + } + break; - case NUBUS_DRSW_ASANTE: - return MAC8390_ASANTE; + case NUBUS_DRSW_APPLE: + switch (dev->dr_hw) { + case NUBUS_DRHW_ASANTE_LC: + return MAC8390_NONE; break; - - case NUBUS_DRSW_TECHWORKS: - case NUBUS_DRSW_DAYNA2: - case NUBUS_DRSW_DAYNA_LC: - if (dev->dr_hw == NUBUS_DRHW_CABLETRON) - return MAC8390_CABLETRON; - else - return MAC8390_APPLE; + case NUBUS_DRHW_CABLETRON: + return MAC8390_CABLETRON; break; - - case NUBUS_DRSW_FARALLON: - return MAC8390_FARALLON; + default: + return MAC8390_APPLE; break; + } + break; - case NUBUS_DRSW_KINETICS: - switch (dev->dr_hw) { - case NUBUS_DRHW_INTERLAN: - return MAC8390_INTERLAN; - break; - default: - return MAC8390_KINETICS; - break; - } - break; + case NUBUS_DRSW_ASANTE: + return MAC8390_ASANTE; + break; + + case NUBUS_DRSW_TECHWORKS: + case NUBUS_DRSW_DAYNA2: + case NUBUS_DRSW_DAYNA_LC: + if (dev->dr_hw == NUBUS_DRHW_CABLETRON) + return MAC8390_CABLETRON; + else + return MAC8390_APPLE; + break; + + case NUBUS_DRSW_FARALLON: + return MAC8390_FARALLON; + break; - case NUBUS_DRSW_DAYNA: - // These correspond to Dayna Sonic cards - // which use the macsonic driver - if (dev->dr_hw == NUBUS_DRHW_SMC9194 || - dev->dr_hw == NUBUS_DRHW_INTERLAN ) - return MAC8390_NONE; - else - return MAC8390_DAYNA; + case NUBUS_DRSW_KINETICS: + switch (dev->dr_hw) { + case NUBUS_DRHW_INTERLAN: + return MAC8390_INTERLAN; break; + default: + return MAC8390_KINETICS; + break; + } + break; + + case NUBUS_DRSW_DAYNA: + // These correspond to Dayna Sonic cards + // which use the macsonic driver + if (dev->dr_hw == NUBUS_DRHW_SMC9194 || + dev->dr_hw == NUBUS_DRHW_INTERLAN ) + return MAC8390_NONE; + else + return MAC8390_DAYNA; + break; } return MAC8390_NONE; } @@ -373,54 +373,54 @@ struct net_device * __init mac8390_probe(int unit) dev->mem_end = dev->mem_start + offset; } else { switch (cardtype) { - case MAC8390_KINETICS: - case MAC8390_DAYNA: /* it's the same */ - dev->base_addr = - (int)(ndev->board->slot_addr + - DAYNA_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - DAYNA_8390_MEM); - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - case MAC8390_INTERLAN: - dev->base_addr = - (int)(ndev->board->slot_addr + - INTERLAN_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - INTERLAN_8390_MEM); - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - case MAC8390_CABLETRON: - dev->base_addr = - (int)(ndev->board->slot_addr + - CABLETRON_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - CABLETRON_8390_MEM); - /* The base address is unreadable if 0x00 - * has been written to the command register - * Reset the chip by writing E8390_NODMA + - * E8390_PAGE0 + E8390_STOP just to be - * sure - */ - i = (void *)dev->base_addr; - *i = 0x21; - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - - default: - printk(KERN_ERR "Card type %s is" - " unsupported, sorry\n", - ndev->board->name); - continue; + case MAC8390_KINETICS: + case MAC8390_DAYNA: /* it's the same */ + dev->base_addr = + (int)(ndev->board->slot_addr + + DAYNA_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + DAYNA_8390_MEM); + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + case MAC8390_INTERLAN: + dev->base_addr = + (int)(ndev->board->slot_addr + + INTERLAN_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + INTERLAN_8390_MEM); + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + case MAC8390_CABLETRON: + dev->base_addr = + (int)(ndev->board->slot_addr + + CABLETRON_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + CABLETRON_8390_MEM); + /* The base address is unreadable if 0x00 + * has been written to the command register + * Reset the chip by writing E8390_NODMA + + * E8390_PAGE0 + E8390_STOP just to be + * sure + */ + i = (void *)dev->base_addr; + *i = 0x21; + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + + default: + printk(KERN_ERR "Card type %s is" + " unsupported, sorry\n", + ndev->board->name); + continue; } } @@ -540,33 +540,33 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd } /* Fill in model-specific information and functions */ - switch(type) { + switch (type) { case MAC8390_FARALLON: case MAC8390_APPLE: - switch(mac8390_testio(dev->mem_start)) { - case ACCESS_UNKNOWN: - printk("Don't know how to access card memory!\n"); - return -ENODEV; - break; + switch (mac8390_testio(dev->mem_start)) { + case ACCESS_UNKNOWN: + printk("Don't know how to access card memory!\n"); + return -ENODEV; + break; - case ACCESS_16: - /* 16 bit card, register map is reversed */ - ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; + case ACCESS_16: + /* 16 bit card, register map is reversed */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; - case ACCESS_32: - /* 32 bit card, register map is reversed */ - ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - access_bitmode = 1; - break; + case ACCESS_32: + /* 32 bit card, register map is reversed */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + access_bitmode = 1; + break; } break; -- GitLab From 5c7fffd0e3b57cb63f50bbd710868f012d67654f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Jan 2010 11:53:00 +0000 Subject: [PATCH 0398/3892] drivers/net/mac8390.c: Remove useless memcpy casting Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 6b6f375440a2..517cee45c086 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -237,14 +237,14 @@ static enum mac8390_access __init mac8390_testio(volatile unsigned long membase) unsigned long outdata = 0xA5A0B5B0; unsigned long indata = 0x00000000; /* Try writing 32 bits */ - memcpy((char *)membase, (char *)&outdata, 4); + memcpy(membase, &outdata, 4); /* Now compare them */ if (memcmp((char *)&outdata, (char *)membase, 4) == 0) return ACCESS_32; /* Write 16 bit output */ - word_memcpy_tocard((char *)membase, (char *)&outdata, 4); + word_memcpy_tocard(membase, &outdata, 4); /* Now read it back */ - word_memcpy_fromcard((char *)&indata, (char *)membase, 4); + word_memcpy_fromcard(&indata, membase, 4); if (outdata == indata) return ACCESS_16; return ACCESS_UNKNOWN; @@ -759,7 +759,7 @@ static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); + dayna_memcpy_fromcard(dev, hdr, hdr_start, 4); /* Fix endianness */ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); } @@ -801,7 +801,7 @@ static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4); + word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4); /* Register endianism - fix here rather than 8390.c */ hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8); } @@ -816,16 +816,17 @@ static void slow_sane_block_input(struct net_device *dev, int count, struct sk_b { /* We must wrap the input move. */ int semi_count = ei_status.rmem_end - xfer_start; - word_memcpy_fromcard(skb->data, (char *)dev->mem_start + - xfer_base, semi_count); + word_memcpy_fromcard(skb->data, + (char *)dev->mem_start + xfer_base, + semi_count); count -= semi_count; word_memcpy_fromcard(skb->data + semi_count, (char *)ei_status.rmem_start, count); } else { - word_memcpy_fromcard(skb->data, (char *)dev->mem_start + - xfer_base, count); + word_memcpy_fromcard(skb->data, + (char *)dev->mem_start + xfer_base, count); } } -- GitLab From 18c0019102228875cb0f6f252dad5148491e96b2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Jan 2010 11:53:01 +0000 Subject: [PATCH 0399/3892] drivers/net/mac8390.c: Convert printk(KERN_ to pr_( Use printk_once Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Convert printks without KERN_ to pr_info and pr_cont Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 57 +++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 517cee45c086..8bd09e280c9e 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -17,6 +17,8 @@ /* 2002-12-30: Try to support more cards, some clues from NetBSD driver */ /* 2003-12-26: Make sure Asante cards always work. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -42,7 +44,7 @@ #include static char version[] = - "mac8390.c: v0.4 2001-05-15 David Huggins-Daines and others\n"; + "v0.4 2001-05-15 David Huggins-Daines and others\n"; #define EI_SHIFT(x) (ei_local->reg_offset[x]) #define ei_inb(port) in_8(port) @@ -288,7 +290,6 @@ struct net_device * __init mac8390_probe(int unit) { struct net_device *dev; volatile unsigned short *i; - int version_disp = 0; struct nubus_dev * ndev = NULL; int err = -ENODEV; @@ -320,10 +321,7 @@ struct net_device * __init mac8390_probe(int unit) if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) continue; - if (version_disp == 0) { - version_disp = 1; - printk(version); - } + printk_once(KERN_INFO pr_fmt(version)); dev->irq = SLOT2IRQ(ndev->board->slot); /* This is getting to be a habit */ @@ -333,16 +331,14 @@ struct net_device * __init mac8390_probe(int unit) of where its memory and registers are. */ if (nubus_get_func_dir(ndev, &dir) == -1) { - printk(KERN_ERR "%s: Unable to get Nubus functional" - " directory for slot %X!\n", + pr_err("%s: Unable to get Nubus functional directory for slot %X!\n", dev->name, ndev->board->slot); continue; } /* Get the MAC address */ if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) { - printk(KERN_INFO "%s: Couldn't get MAC address!\n", - dev->name); + pr_info("%s: Couldn't get MAC address!\n", dev->name); continue; } else { nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); @@ -351,8 +347,7 @@ struct net_device * __init mac8390_probe(int unit) if (useresources[cardtype] == 1) { nubus_rewinddir(&dir); if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) { - printk(KERN_ERR "%s: Memory offset resource" - " for slot %X not found!\n", + pr_err("%s: Memory offset resource for slot %X not found!\n", dev->name, ndev->board->slot); continue; } @@ -362,10 +357,8 @@ struct net_device * __init mac8390_probe(int unit) dev->base_addr = dev->mem_start + 0x10000; nubus_rewinddir(&dir); if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) { - printk(KERN_INFO "%s: Memory length resource" - " for slot %X not found" - ", probing\n", - dev->name, ndev->board->slot); + pr_info("%s: Memory length resource for slot %X not found, probing\n", + dev->name, ndev->board->slot); offset = mac8390_memsize(dev->mem_start); } else { nubus_get_rsrc_mem(&offset, &ent, 4); @@ -417,8 +410,7 @@ struct net_device * __init mac8390_probe(int unit) break; default: - printk(KERN_ERR "Card type %s is" - " unsupported, sorry\n", + pr_err("Card type %s is unsupported, sorry\n", ndev->board->name); continue; } @@ -458,7 +450,7 @@ int init_module(void) dev_mac890[i] = dev; } if (!i) { - printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n"); + pr_notice("No useable cards found, driver NOT installed.\n"); return -ENODEV; } return 0; @@ -545,7 +537,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd case MAC8390_APPLE: switch (mac8390_testio(dev->mem_start)) { case ACCESS_UNKNOWN: - printk("Don't know how to access card memory!\n"); + pr_info("Don't know how to access card memory!\n"); return -ENODEV; break; @@ -612,20 +604,21 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd break; default: - printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name); + pr_err("Card type %s is unsupported, sorry\n", + ndev->board->name); return -ENODEV; } __NS8390_init(dev, 0); /* Good, done, now spit out some messages */ - printk(KERN_INFO "%s: %s in slot %X (type %s)\n", - dev->name, ndev->board->name, ndev->board->slot, cardname[type]); - printk(KERN_INFO - "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", - dev->dev_addr, dev->irq, - (unsigned int)(dev->mem_end - dev->mem_start) >> 10, - dev->mem_start, access_bitmode ? 32 : 16); + pr_info("%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, + cardname[type]); + pr_info("MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", + dev->dev_addr, dev->irq, + (unsigned int)(dev->mem_end - dev->mem_start) >> 10, + dev->mem_start, access_bitmode ? 32 : 16); return 0; } @@ -633,7 +626,7 @@ static int mac8390_open(struct net_device *dev) { __ei_open(dev); if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) { - printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } return 0; @@ -650,7 +643,7 @@ static void mac8390_no_reset(struct net_device *dev) { ei_status.txing = 0; if (ei_debug > 1) - printk("reset not supported\n"); + pr_info("reset not supported\n"); return; } @@ -658,11 +651,11 @@ static void interlan_reset(struct net_device *dev) { unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); if (ei_debug > 1) - printk("Need to reset the NS8390 t=%lu...", jiffies); + pr_info("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; target[0xC0000] = 0; if (ei_debug > 1) - printk("reset complete\n"); + pr_cont("reset complete\n"); return; } -- GitLab From 8e4d9696b45d966c7af5b2aeb6f98ff687c58964 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Jan 2010 11:53:02 +0000 Subject: [PATCH 0400/3892] drivers/net/mac8390.c: Checkpatch cleanups Use #include Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 229 ++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 107 deletions(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 8bd09e280c9e..8f168893caa9 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -36,9 +36,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -47,20 +47,25 @@ static char version[] = "v0.4 2001-05-15 David Huggins-Daines and others\n"; #define EI_SHIFT(x) (ei_local->reg_offset[x]) -#define ei_inb(port) in_8(port) -#define ei_outb(val,port) out_8(port,val) -#define ei_inb_p(port) in_8(port) -#define ei_outb_p(val,port) out_8(port,val) +#define ei_inb(port) in_8(port) +#define ei_outb(val, port) out_8(port, val) +#define ei_inb_p(port) in_8(port) +#define ei_outb_p(val, port) out_8(port, val) #include "lib8390.c" #define WD_START_PG 0x00 /* First page of TX buffer */ #define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ #define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ -#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG + /* First page of TX buffer */ -/* Unfortunately it seems we have to hardcode these for the moment */ -/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */ +/* + * Unfortunately it seems we have to hardcode these for the moment + * Shouldn't the card know about this? + * Does anyone know where to read it off the card? + * Do we trust the data provided by the card? + */ #define DAYNA_8390_BASE 0x80000 #define DAYNA_8390_MEM 0x00000 @@ -82,7 +87,7 @@ enum mac8390_type { MAC8390_KINETICS, }; -static const char * cardname[] = { +static const char *cardname[] = { "apple", "asante", "farallon", @@ -92,7 +97,7 @@ static const char * cardname[] = { "kinetics", }; -static int word16[] = { +static const int word16[] = { 1, /* apple */ 1, /* asante */ 1, /* farallon */ @@ -103,7 +108,7 @@ static int word16[] = { }; /* on which cards do we use NuBus resources? */ -static int useresources[] = { +static const int useresources[] = { 1, /* apple */ 1, /* asante */ 1, /* farallon */ @@ -119,22 +124,22 @@ enum mac8390_access { ACCESS_16, }; -extern int mac8390_memtest(struct net_device * dev); -static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, +extern int mac8390_memtest(struct net_device *dev); +static int mac8390_initdev(struct net_device *dev, struct nubus_dev *ndev, enum mac8390_type type); -static int mac8390_open(struct net_device * dev); -static int mac8390_close(struct net_device * dev); +static int mac8390_open(struct net_device *dev); +static int mac8390_close(struct net_device *dev); static void mac8390_no_reset(struct net_device *dev); static void interlan_reset(struct net_device *dev); /* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/ static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); -static void sane_block_input(struct net_device * dev, int count, - struct sk_buff * skb, int ring_offset); -static void sane_block_output(struct net_device * dev, int count, - const unsigned char * buf, const int start_page); +static void sane_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void sane_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page); /* dayna_memcpy to and from card */ static void dayna_memcpy_fromcard(struct net_device *dev, void *to, @@ -150,8 +155,8 @@ static void dayna_block_input(struct net_device *dev, int count, static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) +#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c)) +#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c)) /* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */ static void slow_sane_get_8390_hdr(struct net_device *dev, @@ -222,10 +227,12 @@ static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) break; case NUBUS_DRSW_DAYNA: - // These correspond to Dayna Sonic cards - // which use the macsonic driver + /* + * These correspond to Dayna Sonic cards + * which use the macsonic driver + */ if (dev->dr_hw == NUBUS_DRHW_SMC9194 || - dev->dr_hw == NUBUS_DRHW_INTERLAN ) + dev->dr_hw == NUBUS_DRHW_INTERLAN) return MAC8390_NONE; else return MAC8390_DAYNA; @@ -260,7 +267,7 @@ static int __init mac8390_memsize(unsigned long membase) local_irq_save(flags); /* Check up to 32K in 4K increments */ for (i = 0; i < 8; i++) { - volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000)); + volatile unsigned short *m = (unsigned short *)(membase + (i * 0x1000)); /* Unwriteable - we have a fully decoded card and the RAM end located */ @@ -275,22 +282,24 @@ static int __init mac8390_memsize(unsigned long membase) /* check for partial decode and wrap */ for (j = 0; j < i; j++) { - volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000)); + volatile unsigned short *p = (unsigned short *)(membase + (j * 0x1000)); if (*p != (0xA5A0 | j)) break; - } - } + } + } local_irq_restore(flags); - /* in any case, we stopped once we tried one block too many, - or once we reached 32K */ - return i * 0x1000; + /* + * in any case, we stopped once we tried one block too many, + * or once we reached 32K + */ + return i * 0x1000; } struct net_device * __init mac8390_probe(int unit) { struct net_device *dev; volatile unsigned short *i; - struct nubus_dev * ndev = NULL; + struct nubus_dev *ndev = NULL; int err = -ENODEV; struct nubus_dir dir; @@ -312,20 +321,23 @@ struct net_device * __init mac8390_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, + ndev))) { /* Have we seen it already? */ if (slots & (1<board->slot)) continue; slots |= 1<board->slot; - if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + cardtype = mac8390_ident(ndev); + if (cardtype == MAC8390_NONE) continue; printk_once(KERN_INFO pr_fmt(version)); dev->irq = SLOT2IRQ(ndev->board->slot); /* This is getting to be a habit */ - dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20); + dev->base_addr = (ndev->board->slot_addr | + ((ndev->board->slot & 0xf) << 20)); /* Get some Nubus info - we will trust the card's idea of where its memory and registers are. */ @@ -337,7 +349,7 @@ struct net_device * __init mac8390_probe(int unit) } /* Get the MAC address */ - if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) { + if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) { pr_info("%s: Couldn't get MAC address!\n", dev->name); continue; } else { @@ -346,7 +358,8 @@ struct net_device * __init mac8390_probe(int unit) if (useresources[cardtype] == 1) { nubus_rewinddir(&dir); - if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) { + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, + &ent) == -1) { pr_err("%s: Memory offset resource for slot %X not found!\n", dev->name, ndev->board->slot); continue; @@ -356,7 +369,8 @@ struct net_device * __init mac8390_probe(int unit) /* yes, this is how the Apple driver does it */ dev->base_addr = dev->mem_start + 0x10000; nubus_rewinddir(&dir); - if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) { + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, + &ent) == -1) { pr_info("%s: Memory length resource for slot %X not found, probing\n", dev->name, ndev->board->slot); offset = mac8390_memsize(dev->mem_start); @@ -485,22 +499,23 @@ static const struct net_device_ops mac8390_netdev_ops = { #endif }; -static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, - enum mac8390_type type) +static int __init mac8390_initdev(struct net_device *dev, + struct nubus_dev *ndev, + enum mac8390_type type) { - static u32 fwrd4_offsets[16]={ + static u32 fwrd4_offsets[16] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60 }; - static u32 back4_offsets[16]={ + static u32 back4_offsets[16] = { 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0 }; - static u32 fwrd2_offsets[16]={ + static u32 fwrd2_offsets[16] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, @@ -518,17 +533,17 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Cabletron's TX/RX buffers are backwards */ if (type == MAC8390_CABLETRON) { - ei_status.tx_start_page = CABLETRON_TX_START_PG; - ei_status.rx_start_page = CABLETRON_RX_START_PG; - ei_status.stop_page = CABLETRON_RX_STOP_PG; - ei_status.rmem_start = dev->mem_start; - ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + ei_status.rmem_start = dev->mem_start; + ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; } else { - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - ei_status.rmem_start = dev->mem_start + TX_PAGES*256; - ei_status.rmem_end = dev->mem_end; + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + ei_status.rmem_start = dev->mem_start + TX_PAGES*256; + ei_status.rmem_end = dev->mem_end; } /* Fill in model-specific information and functions */ @@ -600,8 +615,8 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd ei_status.block_input = &slow_sane_block_input; ei_status.block_output = &slow_sane_block_output; ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = fwrd4_offsets; - break; + ei_status.reg_offset = fwrd4_offsets; + break; default: pr_err("Card type %s is unsupported, sorry\n", @@ -649,7 +664,7 @@ static void mac8390_no_reset(struct net_device *dev) static void interlan_reset(struct net_device *dev) { - unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); + unsigned char *target = nubus_slot_addr(IRQ2SLOT(dev->irq)); if (ei_debug > 1) pr_info("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; @@ -661,54 +676,53 @@ static void interlan_reset(struct net_device *dev) /* dayna_memcpy_fromio/dayna_memcpy_toio */ /* directly from daynaport.c by Alan Cox */ -static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) +static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, + int count) { volatile unsigned char *ptr; - unsigned char *target=to; - from<<=1; /* word, skip overhead */ - ptr=(unsigned char *)(dev->mem_start+from); + unsigned char *target = to; + from <<= 1; /* word, skip overhead */ + ptr = (unsigned char *)(dev->mem_start+from); /* Leading byte? */ - if (from&2) { + if (from & 2) { *target++ = ptr[-1]; ptr += 2; count--; } - while(count>=2) - { + while (count >= 2) { *(unsigned short *)target = *(unsigned short volatile *)ptr; ptr += 4; /* skip cruft */ target += 2; - count-=2; + count -= 2; } /* Trailing byte? */ - if(count) + if (count) *target = *ptr; } -static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count) +static void dayna_memcpy_tocard(struct net_device *dev, int to, + const void *from, int count) { volatile unsigned short *ptr; - const unsigned char *src=from; - to<<=1; /* word, skip overhead */ - ptr=(unsigned short *)(dev->mem_start+to); + const unsigned char *src = from; + to <<= 1; /* word, skip overhead */ + ptr = (unsigned short *)(dev->mem_start+to); /* Leading byte? */ - if (to&2) { /* avoid a byte write (stomps on other data) */ + if (to & 2) { /* avoid a byte write (stomps on other data) */ ptr[-1] = (ptr[-1]&0xFF00)|*src++; ptr++; count--; } - while(count>=2) - { - *ptr++=*(unsigned short *)src; /* Copy and */ + while (count >= 2) { + *ptr++ = *(unsigned short *)src; /* Copy and */ ptr++; /* skip cruft */ src += 2; - count-=2; + count -= 2; } /* Trailing byte? */ - if(count) - { + if (count) { /* card doesn't like byte writes */ - *ptr=(*ptr&0x00FF)|(*src << 8); + *ptr = (*ptr & 0x00FF) | (*src << 8); } } @@ -731,11 +745,14 @@ static void sane_block_input(struct net_device *dev, int count, if (xfer_start + count > ei_status.rmem_end) { /* We must wrap the input move. */ int semi_count = ei_status.rmem_end - xfer_start; - memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count); + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, + semi_count); count -= semi_count; - memcpy_toio(skb->data + semi_count, (char *)ei_status.rmem_start, count); + memcpy_toio(skb->data + semi_count, + (char *)ei_status.rmem_start, count); } else { - memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count); + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, + count); } } @@ -748,16 +765,18 @@ static void sane_block_output(struct net_device *dev, int count, } /* dayna block input/output */ -static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +static void dayna_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; dayna_memcpy_fromcard(dev, hdr, hdr_start, 4); /* Fix endianness */ - hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); + hdr->count = (hdr->count & 0xFF) << 8 | (hdr->count >> 8); } -static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) +static void dayna_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) { unsigned long xfer_base = ring_offset - (WD_START_PG<<8); unsigned long xfer_start = xfer_base+dev->mem_start; @@ -765,8 +784,7 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff /* Note the offset math is done in card memory space which is word per long onto our space. */ - if (xfer_start + count > ei_status.rmem_end) - { + if (xfer_start + count > ei_status.rmem_end) { /* We must wrap the input move. */ int semi_count = ei_status.rmem_end - xfer_start; dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); @@ -774,15 +792,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff dayna_memcpy_fromcard(dev, skb->data + semi_count, ei_status.rmem_start - dev->mem_start, count); - } - else - { + } else { dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); } } -static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) +static void dayna_block_output(struct net_device *dev, int count, + const unsigned char *buf, + int start_page) { long shmem = (start_page - WD_START_PG)<<8; @@ -790,8 +807,9 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned } /* Cabletron block I/O */ -static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page) +static void slow_sane_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, + int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4); @@ -799,14 +817,13 @@ static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8); } -static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, - int ring_offset) +static void slow_sane_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) { unsigned long xfer_base = ring_offset - (WD_START_PG<<8); unsigned long xfer_start = xfer_base+dev->mem_start; - if (xfer_start + count > ei_status.rmem_end) - { + if (xfer_start + count > ei_status.rmem_end) { /* We must wrap the input move. */ int semi_count = ei_status.rmem_end - xfer_start; word_memcpy_fromcard(skb->data, @@ -815,16 +832,14 @@ static void slow_sane_block_input(struct net_device *dev, int count, struct sk_b count -= semi_count; word_memcpy_fromcard(skb->data + semi_count, (char *)ei_status.rmem_start, count); - } - else - { + } else { word_memcpy_fromcard(skb->data, (char *)dev->mem_start + xfer_base, count); } } -static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) +static void slow_sane_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page) { long shmem = (start_page - WD_START_PG)<<8; @@ -837,10 +852,10 @@ static void word_memcpy_tocard(void *tp, const void *fp, int count) const unsigned short *from = fp; count++; - count/=2; + count /= 2; - while(count--) - *to++=*from++; + while (count--) + *to++ = *from++; } static void word_memcpy_fromcard(void *tp, const void *fp, int count) @@ -849,10 +864,10 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count) const volatile unsigned short *from = fp; count++; - count/=2; + count /= 2; - while(count--) - *to++=*from++; + while (count--) + *to++ = *from++; } -- GitLab From f6de7acc42de909ccc7f00916ddb4d2064f42b67 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Jan 2010 11:53:03 +0000 Subject: [PATCH 0401/3892] drivers/net/mac8390.c: Add mac8390_init function Reduce indentation, make code a little neater. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 207 +++++++++++++++++++++--------------------- 1 file changed, 105 insertions(+), 102 deletions(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 8f168893caa9..c70bd6888c89 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -295,16 +295,114 @@ static int __init mac8390_memsize(unsigned long membase) return i * 0x1000; } +static bool __init mac8390_init(struct net_device *dev, struct nubus_dev *ndev, + enum mac8390_type cardtype) +{ + struct nubus_dir dir; + struct nubus_dirent ent; + int offset; + volatile unsigned short *i; + + printk_once(KERN_INFO pr_fmt(version)); + + dev->irq = SLOT2IRQ(ndev->board->slot); + /* This is getting to be a habit */ + dev->base_addr = (ndev->board->slot_addr | + ((ndev->board->slot & 0xf) << 20)); + + /* + * Get some Nubus info - we will trust the card's idea + * of where its memory and registers are. + */ + + if (nubus_get_func_dir(ndev, &dir) == -1) { + pr_err("%s: Unable to get Nubus functional directory for slot %X!\n", + dev->name, ndev->board->slot); + return false; + } + + /* Get the MAC address */ + if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) { + pr_info("%s: Couldn't get MAC address!\n", dev->name); + return false; + } + + nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); + + if (useresources[cardtype] == 1) { + nubus_rewinddir(&dir); + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, + &ent) == -1) { + pr_err("%s: Memory offset resource for slot %X not found!\n", + dev->name, ndev->board->slot); + return false; + } + nubus_get_rsrc_mem(&offset, &ent, 4); + dev->mem_start = dev->base_addr + offset; + /* yes, this is how the Apple driver does it */ + dev->base_addr = dev->mem_start + 0x10000; + nubus_rewinddir(&dir); + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, + &ent) == -1) { + pr_info("%s: Memory length resource for slot %X not found, probing\n", + dev->name, ndev->board->slot); + offset = mac8390_memsize(dev->mem_start); + } else { + nubus_get_rsrc_mem(&offset, &ent, 4); + } + dev->mem_end = dev->mem_start + offset; + } else { + switch (cardtype) { + case MAC8390_KINETICS: + case MAC8390_DAYNA: /* it's the same */ + dev->base_addr = (int)(ndev->board->slot_addr + + DAYNA_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr + + DAYNA_8390_MEM); + dev->mem_end = dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + case MAC8390_INTERLAN: + dev->base_addr = (int)(ndev->board->slot_addr + + INTERLAN_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr + + INTERLAN_8390_MEM); + dev->mem_end = dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + case MAC8390_CABLETRON: + dev->base_addr = (int)(ndev->board->slot_addr + + CABLETRON_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr + + CABLETRON_8390_MEM); + /* The base address is unreadable if 0x00 + * has been written to the command register + * Reset the chip by writing E8390_NODMA + + * E8390_PAGE0 + E8390_STOP just to be + * sure + */ + i = (void *)dev->base_addr; + *i = 0x21; + dev->mem_end = dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + + default: + pr_err("Card type %s is unsupported, sorry\n", + ndev->board->name); + return false; + } + } + + return true; +} + struct net_device * __init mac8390_probe(int unit) { struct net_device *dev; - volatile unsigned short *i; struct nubus_dev *ndev = NULL; int err = -ENODEV; - struct nubus_dir dir; - struct nubus_dirent ent; - int offset; static unsigned int slots; enum mac8390_type cardtype; @@ -324,111 +422,16 @@ struct net_device * __init mac8390_probe(int unit) while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { /* Have we seen it already? */ - if (slots & (1<board->slot)) + if (slots & (1 << ndev->board->slot)) continue; - slots |= 1<board->slot; + slots |= 1 << ndev->board->slot; cardtype = mac8390_ident(ndev); if (cardtype == MAC8390_NONE) continue; - printk_once(KERN_INFO pr_fmt(version)); - - dev->irq = SLOT2IRQ(ndev->board->slot); - /* This is getting to be a habit */ - dev->base_addr = (ndev->board->slot_addr | - ((ndev->board->slot & 0xf) << 20)); - - /* Get some Nubus info - we will trust the card's idea - of where its memory and registers are. */ - - if (nubus_get_func_dir(ndev, &dir) == -1) { - pr_err("%s: Unable to get Nubus functional directory for slot %X!\n", - dev->name, ndev->board->slot); - continue; - } - - /* Get the MAC address */ - if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) { - pr_info("%s: Couldn't get MAC address!\n", dev->name); + if (!mac8390_init(dev, ndev, cardtype)) continue; - } else { - nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); - } - - if (useresources[cardtype] == 1) { - nubus_rewinddir(&dir); - if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, - &ent) == -1) { - pr_err("%s: Memory offset resource for slot %X not found!\n", - dev->name, ndev->board->slot); - continue; - } - nubus_get_rsrc_mem(&offset, &ent, 4); - dev->mem_start = dev->base_addr + offset; - /* yes, this is how the Apple driver does it */ - dev->base_addr = dev->mem_start + 0x10000; - nubus_rewinddir(&dir); - if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, - &ent) == -1) { - pr_info("%s: Memory length resource for slot %X not found, probing\n", - dev->name, ndev->board->slot); - offset = mac8390_memsize(dev->mem_start); - } else { - nubus_get_rsrc_mem(&offset, &ent, 4); - } - dev->mem_end = dev->mem_start + offset; - } else { - switch (cardtype) { - case MAC8390_KINETICS: - case MAC8390_DAYNA: /* it's the same */ - dev->base_addr = - (int)(ndev->board->slot_addr + - DAYNA_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - DAYNA_8390_MEM); - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - case MAC8390_INTERLAN: - dev->base_addr = - (int)(ndev->board->slot_addr + - INTERLAN_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - INTERLAN_8390_MEM); - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - case MAC8390_CABLETRON: - dev->base_addr = - (int)(ndev->board->slot_addr + - CABLETRON_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - CABLETRON_8390_MEM); - /* The base address is unreadable if 0x00 - * has been written to the command register - * Reset the chip by writing E8390_NODMA + - * E8390_PAGE0 + E8390_STOP just to be - * sure - */ - i = (void *)dev->base_addr; - *i = 0x21; - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; - - default: - pr_err("Card type %s is unsupported, sorry\n", - ndev->board->name); - continue; - } - } /* Do the nasty 8390 stuff */ if (!mac8390_initdev(dev, ndev, cardtype)) -- GitLab From 5068c7a883d1694f0fb3631b664827644153cd08 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 7 Jan 2010 15:57:19 +1100 Subject: [PATCH 0402/3892] crypto: pcrypt - Add pcrypt crypto parallelization wrapper This patch adds a parallel crypto template that takes a crypto algorithm and converts it to process the crypto transforms in parallel. For the moment only aead algorithms are supported. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu --- crypto/Kconfig | 10 + crypto/Makefile | 1 + crypto/pcrypt.c | 445 ++++++++++++++++++++++++++++++++++++++++ include/crypto/pcrypt.h | 51 +++++ 4 files changed, 507 insertions(+) create mode 100644 crypto/pcrypt.c create mode 100644 include/crypto/pcrypt.h diff --git a/crypto/Kconfig b/crypto/Kconfig index 81c185a6971f..6a2e295ee227 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -114,6 +114,16 @@ config CRYPTO_NULL help These are 'Null' algorithms, used by IPsec, which do nothing. +config CRYPTO_PCRYPT + tristate "Parallel crypto engine (EXPERIMENTAL)" + depends on SMP && EXPERIMENTAL + select PADATA + select CRYPTO_MANAGER + select CRYPTO_AEAD + help + This converts an arbitrary crypto algorithm into a parallel + algorithm that executes in kernel threads. + config CRYPTO_WORKQUEUE tristate diff --git a/crypto/Makefile b/crypto/Makefile index 9e8f61908cb5..d7e6441df7fe 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CTR) += ctr.o obj-$(CONFIG_CRYPTO_GCM) += gcm.o obj-$(CONFIG_CRYPTO_CCM) += ccm.o +obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des_generic.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c new file mode 100644 index 000000000000..b9527d05e17d --- /dev/null +++ b/crypto/pcrypt.c @@ -0,0 +1,445 @@ +/* + * pcrypt - Parallel crypto wrapper. + * + * Copyright (C) 2009 secunet Security Networks AG + * Copyright (C) 2009 Steffen Klassert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct padata_instance *pcrypt_enc_padata; +static struct padata_instance *pcrypt_dec_padata; +static struct workqueue_struct *encwq; +static struct workqueue_struct *decwq; + +struct pcrypt_instance_ctx { + struct crypto_spawn spawn; + unsigned int tfm_count; +}; + +struct pcrypt_aead_ctx { + struct crypto_aead *child; + unsigned int cb_cpu; +}; + +static int pcrypt_do_parallel(struct padata_priv *padata, unsigned int *cb_cpu, + struct padata_instance *pinst) +{ + unsigned int cpu_index, cpu, i; + + cpu = *cb_cpu; + + if (cpumask_test_cpu(cpu, cpu_active_mask)) + goto out; + + cpu_index = cpu % cpumask_weight(cpu_active_mask); + + cpu = cpumask_first(cpu_active_mask); + for (i = 0; i < cpu_index; i++) + cpu = cpumask_next(cpu, cpu_active_mask); + + *cb_cpu = cpu; + +out: + return padata_do_parallel(pinst, padata, cpu); +} + +static int pcrypt_aead_setkey(struct crypto_aead *parent, + const u8 *key, unsigned int keylen) +{ + struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(parent); + + return crypto_aead_setkey(ctx->child, key, keylen); +} + +static int pcrypt_aead_setauthsize(struct crypto_aead *parent, + unsigned int authsize) +{ + struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(parent); + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +static void pcrypt_aead_serial(struct padata_priv *padata) +{ + struct pcrypt_request *preq = pcrypt_padata_request(padata); + struct aead_request *req = pcrypt_request_ctx(preq); + + aead_request_complete(req->base.data, padata->info); +} + +static void pcrypt_aead_giv_serial(struct padata_priv *padata) +{ + struct pcrypt_request *preq = pcrypt_padata_request(padata); + struct aead_givcrypt_request *req = pcrypt_request_ctx(preq); + + aead_request_complete(req->areq.base.data, padata->info); +} + +static void pcrypt_aead_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + struct pcrypt_request *preq = aead_request_ctx(req); + struct padata_priv *padata = pcrypt_request_padata(preq); + + padata->info = err; + req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + padata_do_serial(padata); +} + +static void pcrypt_aead_enc(struct padata_priv *padata) +{ + struct pcrypt_request *preq = pcrypt_padata_request(padata); + struct aead_request *req = pcrypt_request_ctx(preq); + + padata->info = crypto_aead_encrypt(req); + + if (padata->info) + return; + + padata_do_serial(padata); +} + +static int pcrypt_aead_encrypt(struct aead_request *req) +{ + int err; + struct pcrypt_request *preq = aead_request_ctx(req); + struct aead_request *creq = pcrypt_request_ctx(preq); + struct padata_priv *padata = pcrypt_request_padata(preq); + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead); + u32 flags = aead_request_flags(req); + + memset(padata, 0, sizeof(struct padata_priv)); + + padata->parallel = pcrypt_aead_enc; + padata->serial = pcrypt_aead_serial; + + aead_request_set_tfm(creq, ctx->child); + aead_request_set_callback(creq, flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, + pcrypt_aead_done, req); + aead_request_set_crypt(creq, req->src, req->dst, + req->cryptlen, req->iv); + aead_request_set_assoc(creq, req->assoc, req->assoclen); + + err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata); + if (err) + return err; + else + err = crypto_aead_encrypt(creq); + + return err; +} + +static void pcrypt_aead_dec(struct padata_priv *padata) +{ + struct pcrypt_request *preq = pcrypt_padata_request(padata); + struct aead_request *req = pcrypt_request_ctx(preq); + + padata->info = crypto_aead_decrypt(req); + + if (padata->info) + return; + + padata_do_serial(padata); +} + +static int pcrypt_aead_decrypt(struct aead_request *req) +{ + int err; + struct pcrypt_request *preq = aead_request_ctx(req); + struct aead_request *creq = pcrypt_request_ctx(preq); + struct padata_priv *padata = pcrypt_request_padata(preq); + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead); + u32 flags = aead_request_flags(req); + + memset(padata, 0, sizeof(struct padata_priv)); + + padata->parallel = pcrypt_aead_dec; + padata->serial = pcrypt_aead_serial; + + aead_request_set_tfm(creq, ctx->child); + aead_request_set_callback(creq, flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, + pcrypt_aead_done, req); + aead_request_set_crypt(creq, req->src, req->dst, + req->cryptlen, req->iv); + aead_request_set_assoc(creq, req->assoc, req->assoclen); + + err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_dec_padata); + if (err) + return err; + else + err = crypto_aead_decrypt(creq); + + return err; +} + +static void pcrypt_aead_givenc(struct padata_priv *padata) +{ + struct pcrypt_request *preq = pcrypt_padata_request(padata); + struct aead_givcrypt_request *req = pcrypt_request_ctx(preq); + + padata->info = crypto_aead_givencrypt(req); + + if (padata->info) + return; + + padata_do_serial(padata); +} + +static int pcrypt_aead_givencrypt(struct aead_givcrypt_request *req) +{ + int err; + struct aead_request *areq = &req->areq; + struct pcrypt_request *preq = aead_request_ctx(areq); + struct aead_givcrypt_request *creq = pcrypt_request_ctx(preq); + struct padata_priv *padata = pcrypt_request_padata(preq); + struct crypto_aead *aead = aead_givcrypt_reqtfm(req); + struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead); + u32 flags = aead_request_flags(areq); + + memset(padata, 0, sizeof(struct padata_priv)); + + padata->parallel = pcrypt_aead_givenc; + padata->serial = pcrypt_aead_giv_serial; + + aead_givcrypt_set_tfm(creq, ctx->child); + aead_givcrypt_set_callback(creq, flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, + pcrypt_aead_done, areq); + aead_givcrypt_set_crypt(creq, areq->src, areq->dst, + areq->cryptlen, areq->iv); + aead_givcrypt_set_assoc(creq, areq->assoc, areq->assoclen); + aead_givcrypt_set_giv(creq, req->giv, req->seq); + + err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata); + if (err) + return err; + else + err = crypto_aead_givencrypt(creq); + + return err; +} + +static int pcrypt_aead_init_tfm(struct crypto_tfm *tfm) +{ + int cpu, cpu_index; + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); + struct pcrypt_instance_ctx *ictx = crypto_instance_ctx(inst); + struct pcrypt_aead_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aead *cipher; + + ictx->tfm_count++; + + cpu_index = ictx->tfm_count % cpumask_weight(cpu_active_mask); + + ctx->cb_cpu = cpumask_first(cpu_active_mask); + for (cpu = 0; cpu < cpu_index; cpu++) + ctx->cb_cpu = cpumask_next(ctx->cb_cpu, cpu_active_mask); + + cipher = crypto_spawn_aead(crypto_instance_ctx(inst)); + + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + tfm->crt_aead.reqsize = sizeof(struct pcrypt_request) + + sizeof(struct aead_givcrypt_request) + + crypto_aead_reqsize(cipher); + + return 0; +} + +static void pcrypt_aead_exit_tfm(struct crypto_tfm *tfm) +{ + struct pcrypt_aead_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static struct crypto_instance *pcrypt_alloc_instance(struct crypto_alg *alg) +{ + struct crypto_instance *inst; + struct pcrypt_instance_ctx *ctx; + int err; + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + if (!inst) { + inst = ERR_PTR(-ENOMEM); + goto out; + } + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "pcrypt(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto out_free_inst; + + memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); + + ctx = crypto_instance_ctx(inst); + err = crypto_init_spawn(&ctx->spawn, alg, inst, + CRYPTO_ALG_TYPE_MASK); + if (err) + goto out_free_inst; + + inst->alg.cra_priority = alg->cra_priority + 100; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + +out: + return inst; + +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_instance *pcrypt_alloc_aead(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + struct crypto_attr_type *algt; + + algt = crypto_get_attr_type(tb); + + alg = crypto_get_attr_alg(tb, algt->type, + (algt->mask & CRYPTO_ALG_TYPE_MASK)); + if (IS_ERR(alg)) + return ERR_CAST(alg); + + inst = pcrypt_alloc_instance(alg); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + inst->alg.cra_type = &crypto_aead_type; + + inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize; + inst->alg.cra_aead.geniv = alg->cra_aead.geniv; + inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize; + + inst->alg.cra_ctxsize = sizeof(struct pcrypt_aead_ctx); + + inst->alg.cra_init = pcrypt_aead_init_tfm; + inst->alg.cra_exit = pcrypt_aead_exit_tfm; + + inst->alg.cra_aead.setkey = pcrypt_aead_setkey; + inst->alg.cra_aead.setauthsize = pcrypt_aead_setauthsize; + inst->alg.cra_aead.encrypt = pcrypt_aead_encrypt; + inst->alg.cra_aead.decrypt = pcrypt_aead_decrypt; + inst->alg.cra_aead.givencrypt = pcrypt_aead_givencrypt; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static struct crypto_instance *pcrypt_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + + algt = crypto_get_attr_type(tb); + if (IS_ERR(algt)) + return ERR_CAST(algt); + + switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AEAD: + return pcrypt_alloc_aead(tb); + } + + return ERR_PTR(-EINVAL); +} + +static void pcrypt_free(struct crypto_instance *inst) +{ + struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_spawn(&ctx->spawn); + kfree(inst); +} + +static struct crypto_template pcrypt_tmpl = { + .name = "pcrypt", + .alloc = pcrypt_alloc, + .free = pcrypt_free, + .module = THIS_MODULE, +}; + +static int __init pcrypt_init(void) +{ + encwq = create_workqueue("pencrypt"); + if (!encwq) + goto err; + + decwq = create_workqueue("pdecrypt"); + if (!decwq) + goto err_destroy_encwq; + + + pcrypt_enc_padata = padata_alloc(cpu_possible_mask, encwq); + if (!pcrypt_enc_padata) + goto err_destroy_decwq; + + pcrypt_dec_padata = padata_alloc(cpu_possible_mask, decwq); + if (!pcrypt_dec_padata) + goto err_free_padata; + + padata_start(pcrypt_enc_padata); + padata_start(pcrypt_dec_padata); + + return crypto_register_template(&pcrypt_tmpl); + +err_free_padata: + padata_free(pcrypt_enc_padata); + +err_destroy_decwq: + destroy_workqueue(decwq); + +err_destroy_encwq: + destroy_workqueue(encwq); + +err: + return -ENOMEM; +} + +static void __exit pcrypt_exit(void) +{ + padata_stop(pcrypt_enc_padata); + padata_stop(pcrypt_dec_padata); + + destroy_workqueue(encwq); + destroy_workqueue(decwq); + + padata_free(pcrypt_enc_padata); + padata_free(pcrypt_dec_padata); + + crypto_unregister_template(&pcrypt_tmpl); +} + +module_init(pcrypt_init); +module_exit(pcrypt_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steffen Klassert "); +MODULE_DESCRIPTION("Parallel crypto wrapper"); diff --git a/include/crypto/pcrypt.h b/include/crypto/pcrypt.h new file mode 100644 index 000000000000..d7d8bd8c6edc --- /dev/null +++ b/include/crypto/pcrypt.h @@ -0,0 +1,51 @@ +/* + * pcrypt - Parallel crypto engine. + * + * Copyright (C) 2009 secunet Security Networks AG + * Copyright (C) 2009 Steffen Klassert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CRYPTO_PCRYPT_H +#define _CRYPTO_PCRYPT_H + +#include +#include +#include + +struct pcrypt_request { + struct padata_priv padata; + void *data; + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + +static inline void *pcrypt_request_ctx(struct pcrypt_request *req) +{ + return req->__ctx; +} + +static inline +struct padata_priv *pcrypt_request_padata(struct pcrypt_request *req) +{ + return &req->padata; +} + +static inline +struct pcrypt_request *pcrypt_padata_request(struct padata_priv *padata) +{ + return container_of(padata, struct pcrypt_request, padata); +} + +#endif -- GitLab From a9a1f9c315c27fe7a260cd453167981cd680dae8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 6 Jan 2010 23:51:47 -0800 Subject: [PATCH 0403/3892] Input: atkbd - switch to dev_err() and friends dev_err(), dev_warn() and dev_dbg() ensure consistency in driver messages. Also switch to using bool where appropriate and fix some formatting issues. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 283 +++++++++++++++++---------------- 1 file changed, 146 insertions(+), 137 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index a3573570c52f..7c235013dba3 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -40,26 +40,26 @@ module_param_named(set, atkbd_set, int, 0); MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) -static int atkbd_reset; +static bool atkbd_reset; #else -static int atkbd_reset = 1; +static bool atkbd_reset = true; #endif module_param_named(reset, atkbd_reset, bool, 0); MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); -static int atkbd_softrepeat; +static bool atkbd_softrepeat; module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); -static int atkbd_softraw = 1; +static bool atkbd_softraw = true; module_param_named(softraw, atkbd_softraw, bool, 0); MODULE_PARM_DESC(softraw, "Use software generated rawmode"); -static int atkbd_scroll; +static bool atkbd_scroll; module_param_named(scroll, atkbd_scroll, bool, 0); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); -static int atkbd_extra; +static bool atkbd_extra; module_param_named(extra, atkbd_extra, bool, 0); MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); @@ -205,18 +205,18 @@ struct atkbd { unsigned short keycode[ATKBD_KEYMAP_SIZE]; DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); unsigned char set; - unsigned char translated; - unsigned char extra; - unsigned char write; - unsigned char softrepeat; - unsigned char softraw; - unsigned char scroll; - unsigned char enabled; + bool translated; + bool extra; + bool write; + bool softrepeat; + bool softraw; + bool scroll; + bool enabled; /* Accessed only from interrupt */ unsigned char emul; - unsigned char resend; - unsigned char release; + bool resend; + bool release; unsigned long xl_bit; unsigned int last; unsigned long time; @@ -298,18 +298,18 @@ static const unsigned int xl_table[] = { * Checks if we should mangle the scancode to extract 'release' bit * in translated mode. */ -static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code) +static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) { int i; if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) - return 0; + return false; for (i = 0; i < ARRAY_SIZE(xl_table); i++) if (code == xl_table[i]) return test_bit(i, &xl_bit); - return 1; + return true; } /* @@ -356,7 +356,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code */ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) + unsigned int flags) { struct atkbd *atkbd = serio_get_drvdata(serio); struct input_dev *dev = atkbd->dev; @@ -365,20 +365,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, int value; unsigned short keycode; -#ifdef ATKBD_DEBUG - printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); -#endif + dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); #if !defined(__i386__) && !defined (__x86_64__) if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); + dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); - atkbd->resend = 1; + atkbd->resend = true; goto out; } if (!flags && data == ATKBD_RET_ACK) - atkbd->resend = 0; + atkbd->resend = false; #endif if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) @@ -409,32 +407,32 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, } switch (code) { - case ATKBD_RET_BAT: - atkbd->enabled = 0; - serio_reconnect(atkbd->ps2dev.serio); - goto out; - case ATKBD_RET_EMUL0: - atkbd->emul = 1; - goto out; - case ATKBD_RET_EMUL1: - atkbd->emul = 2; - goto out; - case ATKBD_RET_RELEASE: - atkbd->release = 1; - goto out; - case ATKBD_RET_ACK: - case ATKBD_RET_NAK: - if (printk_ratelimit()) - printk(KERN_WARNING "atkbd.c: Spurious %s on %s. " - "Some program might be trying access hardware directly.\n", - data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); - goto out; - case ATKBD_RET_ERR: - atkbd->err_count++; -#ifdef ATKBD_DEBUG - printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); -#endif - goto out; + case ATKBD_RET_BAT: + atkbd->enabled = false; + serio_reconnect(atkbd->ps2dev.serio); + goto out; + case ATKBD_RET_EMUL0: + atkbd->emul = 1; + goto out; + case ATKBD_RET_EMUL1: + atkbd->emul = 2; + goto out; + case ATKBD_RET_RELEASE: + atkbd->release = true; + goto out; + case ATKBD_RET_ACK: + case ATKBD_RET_NAK: + if (printk_ratelimit()) + dev_warn(&serio->dev, + "Spurious %s on %s. " + "Some program might be trying access hardware directly.\n", + data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); + goto out; + case ATKBD_RET_ERR: + atkbd->err_count++; + dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n", + serio->phys); + goto out; } code = atkbd_compat_scancode(atkbd, code); @@ -448,71 +446,72 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, input_event(dev, EV_MSC, MSC_SCAN, code); switch (keycode) { - case ATKBD_KEY_NULL: - break; - case ATKBD_KEY_UNKNOWN: - printk(KERN_WARNING - "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", - atkbd->release ? "released" : "pressed", - atkbd->translated ? "translated" : "raw", - atkbd->set, code, serio->phys); - printk(KERN_WARNING - "atkbd.c: Use 'setkeycodes %s%02x ' to make it known.\n", - code & 0x80 ? "e0" : "", code & 0x7f); - input_sync(dev); - break; - case ATKBD_SCR_1: - scroll = 1 - atkbd->release * 2; - break; - case ATKBD_SCR_2: - scroll = 2 - atkbd->release * 4; - break; - case ATKBD_SCR_4: - scroll = 4 - atkbd->release * 8; - break; - case ATKBD_SCR_8: - scroll = 8 - atkbd->release * 16; - break; - case ATKBD_SCR_CLICK: - click = !atkbd->release; - break; - case ATKBD_SCR_LEFT: - hscroll = -1; - break; - case ATKBD_SCR_RIGHT: - hscroll = 1; - break; - default: - if (atkbd->release) { - value = 0; - atkbd->last = 0; - } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { - /* Workaround Toshiba laptop multiple keypress */ - value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; - } else { - value = 1; - atkbd->last = code; - atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; - } - - input_event(dev, EV_KEY, keycode, value); - input_sync(dev); + case ATKBD_KEY_NULL: + break; + case ATKBD_KEY_UNKNOWN: + dev_warn(&serio->dev, + "Unknown key %s (%s set %d, code %#x on %s).\n", + atkbd->release ? "released" : "pressed", + atkbd->translated ? "translated" : "raw", + atkbd->set, code, serio->phys); + dev_warn(&serio->dev, + "Use 'setkeycodes %s%02x ' to make it known.\n", + code & 0x80 ? "e0" : "", code & 0x7f); + input_sync(dev); + break; + case ATKBD_SCR_1: + scroll = 1; + break; + case ATKBD_SCR_2: + scroll = 2; + break; + case ATKBD_SCR_4: + scroll = 4; + break; + case ATKBD_SCR_8: + scroll = 8; + break; + case ATKBD_SCR_CLICK: + click = !atkbd->release; + break; + case ATKBD_SCR_LEFT: + hscroll = -1; + break; + case ATKBD_SCR_RIGHT: + hscroll = 1; + break; + default: + if (atkbd->release) { + value = 0; + atkbd->last = 0; + } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { + /* Workaround Toshiba laptop multiple keypress */ + value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; + } else { + value = 1; + atkbd->last = code; + atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; + } + + input_event(dev, EV_KEY, keycode, value); + input_sync(dev); - if (value && test_bit(code, atkbd->force_release_mask)) { - input_report_key(dev, keycode, 0); - input_sync(dev); - } + if (value && test_bit(code, atkbd->force_release_mask)) { + input_report_key(dev, keycode, 0); + input_sync(dev); + } } if (atkbd->scroll) { if (click != -1) input_report_key(dev, BTN_MIDDLE, click); - input_report_rel(dev, REL_WHEEL, scroll); + input_report_rel(dev, REL_WHEEL, + atkbd->release ? -scroll : scroll); input_report_rel(dev, REL_HWHEEL, hscroll); input_sync(dev); } - atkbd->release = 0; + atkbd->release = false; out: return IRQ_HANDLED; } @@ -631,17 +630,18 @@ static int atkbd_event(struct input_dev *dev, switch (type) { - case EV_LED: - atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); - return 0; + case EV_LED: + atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); + return 0; - case EV_REP: - if (!atkbd->softrepeat) - atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT); - return 0; - } + case EV_REP: + if (!atkbd->softrepeat) + atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT); + return 0; - return -1; + default: + return -1; + } } /* @@ -652,7 +652,7 @@ static int atkbd_event(struct input_dev *dev, static inline void atkbd_enable(struct atkbd *atkbd) { serio_pause_rx(atkbd->ps2dev.serio); - atkbd->enabled = 1; + atkbd->enabled = true; serio_continue_rx(atkbd->ps2dev.serio); } @@ -664,7 +664,7 @@ static inline void atkbd_enable(struct atkbd *atkbd) static inline void atkbd_disable(struct atkbd *atkbd) { serio_pause_rx(atkbd->ps2dev.serio); - atkbd->enabled = 0; + atkbd->enabled = false; serio_continue_rx(atkbd->ps2dev.serio); } @@ -685,7 +685,9 @@ static int atkbd_probe(struct atkbd *atkbd) if (atkbd_reset) if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) - printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys); + dev_warn(&ps2dev->serio->dev, + "keyboard reset failed on %s\n", + ps2dev->serio->phys); /* * Then we check the keyboard ID. We should get 0xab83 under normal conditions. @@ -715,8 +717,9 @@ static int atkbd_probe(struct atkbd *atkbd) atkbd->id = (param[0] << 8) | param[1]; if (atkbd->id == 0xaca1 && atkbd->translated) { - printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n"); - printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n"); + dev_err(&ps2dev->serio->dev, + "NCD terminal keyboards are only supported on non-translating controlelrs. " + "Use i8042.direct=1 to disable translation.\n"); return -1; } @@ -734,7 +737,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra struct ps2dev *ps2dev = &atkbd->ps2dev; unsigned char param[2]; - atkbd->extra = 0; + atkbd->extra = false; /* * For known special keyboards we can go ahead and set the correct set. * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and @@ -753,7 +756,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra if (allow_extra) { param[0] = 0x71; if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { - atkbd->extra = 1; + atkbd->extra = true; return 2; } } @@ -818,7 +821,8 @@ static int atkbd_activate(struct atkbd *atkbd) */ if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { - printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", + dev_err(&ps2dev->serio->dev, + "Failed to enable keyboard on %s\n", ps2dev->serio->phys); return -1; } @@ -1090,12 +1094,14 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) switch (serio->id.type) { - case SERIO_8042_XL: - atkbd->translated = 1; - case SERIO_8042: - if (serio->write) - atkbd->write = 1; - break; + case SERIO_8042_XL: + atkbd->translated = true; + /* Fall through */ + + case SERIO_8042: + if (serio->write) + atkbd->write = true; + break; } atkbd->softraw = atkbd_softraw; @@ -1103,7 +1109,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->scroll = atkbd_scroll; if (atkbd->softrepeat) - atkbd->softraw = 1; + atkbd->softraw = true; serio_set_drvdata(serio, atkbd); @@ -1161,7 +1167,8 @@ static int atkbd_reconnect(struct serio *serio) struct serio_driver *drv = serio->drv; if (!atkbd || !drv) { - printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); + dev_dbg(&serio->dev, + "reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -1288,7 +1295,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun struct input_dev *old_dev, *new_dev; unsigned long value; int err; - unsigned char old_extra, old_set; + bool old_extra; + unsigned char old_set; if (!atkbd->write) return -EIO; @@ -1371,7 +1379,7 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou struct input_dev *old_dev, *new_dev; unsigned long value; int err; - unsigned char old_scroll; + bool old_scroll; if (strict_strtoul(buf, 10, &value) || value > 1) return -EINVAL; @@ -1415,7 +1423,8 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) struct input_dev *old_dev, *new_dev; unsigned long value; int err; - unsigned char old_set, old_extra; + unsigned char old_set; + bool old_extra; if (!atkbd->write) return -EIO; @@ -1465,7 +1474,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t struct input_dev *old_dev, *new_dev; unsigned long value; int err; - unsigned char old_softrepeat, old_softraw; + bool old_softrepeat, old_softraw; if (!atkbd->write) return -EIO; @@ -1485,7 +1494,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t atkbd->dev = new_dev; atkbd->softrepeat = value; if (atkbd->softrepeat) - atkbd->softraw = 1; + atkbd->softraw = true; atkbd_set_device_attrs(atkbd); err = input_register_device(atkbd->dev); @@ -1515,7 +1524,7 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co struct input_dev *old_dev, *new_dev; unsigned long value; int err; - unsigned char old_softraw; + bool old_softraw; if (strict_strtoul(buf, 10, &value) || value > 1) return -EINVAL; -- GitLab From 8cab9ba10493cea164ac8bbbc733c21a528e6fe5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 6 Jan 2010 23:52:12 -0800 Subject: [PATCH 0404/3892] Input: elo - switch to using dev_xxx() when printing messages Also fix formatting of "switch" statements. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elo.c | 225 +++++++++++++++++--------------- 1 file changed, 120 insertions(+), 105 deletions(-) diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 8f38c5e55ce6..486d31ba9c09 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -72,45 +72,49 @@ static void elo_process_data_10(struct elo *elo, unsigned char data) struct input_dev *dev = elo->dev; elo->data[elo->idx] = data; - switch (elo->idx++) { - case 0: - elo->csum = 0xaa; - if (data != ELO10_LEAD_BYTE) { - pr_debug("elo: unsynchronized data: 0x%02x\n", data); - elo->idx = 0; - } - break; - case 9: + switch (elo->idx++) { + case 0: + elo->csum = 0xaa; + if (data != ELO10_LEAD_BYTE) { + dev_dbg(&elo->serio->dev, + "unsynchronized data: 0x%02x\n", data); elo->idx = 0; - if (data != elo->csum) { - pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n", - data, elo->csum); - break; - } - if (elo->data[1] != elo->expected_packet) { - if (elo->data[1] != ELO10_TOUCH_PACKET) - pr_debug("elo: unexpected packet: 0x%02x\n", - elo->data[1]); - break; - } - if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { - input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); - input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); - if (elo->data[2] & ELO10_PRESSURE) - input_report_abs(dev, ABS_PRESSURE, - (elo->data[8] << 8) | elo->data[7]); - input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); - input_sync(dev); - } else if (elo->data[1] == ELO10_ACK_PACKET) { - if (elo->data[2] == '0') - elo->expected_packet = ELO10_TOUCH_PACKET; - complete(&elo->cmd_done); - } else { - memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); - elo->expected_packet = ELO10_ACK_PACKET; - } + } + break; + + case 9: + elo->idx = 0; + if (data != elo->csum) { + dev_dbg(&elo->serio->dev, + "bad checksum: 0x%02x, expected 0x%02x\n", + data, elo->csum); + break; + } + if (elo->data[1] != elo->expected_packet) { + if (elo->data[1] != ELO10_TOUCH_PACKET) + dev_dbg(&elo->serio->dev, + "unexpected packet: 0x%02x\n", + elo->data[1]); break; + } + if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { + input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); + input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); + if (elo->data[2] & ELO10_PRESSURE) + input_report_abs(dev, ABS_PRESSURE, + (elo->data[8] << 8) | elo->data[7]); + input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); + input_sync(dev); + } else if (elo->data[1] == ELO10_ACK_PACKET) { + if (elo->data[2] == '0') + elo->expected_packet = ELO10_TOUCH_PACKET; + complete(&elo->cmd_done); + } else { + memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); + elo->expected_packet = ELO10_ACK_PACKET; + } + break; } elo->csum += data; } @@ -123,42 +127,53 @@ static void elo_process_data_6(struct elo *elo, unsigned char data) switch (elo->idx++) { - case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break; - case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break; - case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break; - - case 3: - if (data & 0xc0) { - elo->idx = 0; - break; - } + case 0: + if ((data & 0xc0) != 0xc0) + elo->idx = 0; + break; - input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); - input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); + case 1: + if ((data & 0xc0) != 0x80) + elo->idx = 0; + break; - if (elo->id == 2) { - input_report_key(dev, BTN_TOUCH, 1); - input_sync(dev); - elo->idx = 0; - } + case 2: + if ((data & 0xc0) != 0x40) + elo->idx = 0; + break; + case 3: + if (data & 0xc0) { + elo->idx = 0; break; + } - case 4: - if (data) { - input_sync(dev); - elo->idx = 0; - } - break; + input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); + input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); - case 5: - if ((data & 0xf0) == 0) { - input_report_abs(dev, ABS_PRESSURE, elo->data[5]); - input_report_key(dev, BTN_TOUCH, !!elo->data[5]); - } + if (elo->id == 2) { + input_report_key(dev, BTN_TOUCH, 1); input_sync(dev); elo->idx = 0; - break; + } + + break; + + case 4: + if (data) { + input_sync(dev); + elo->idx = 0; + } + break; + + case 5: + if ((data & 0xf0) == 0) { + input_report_abs(dev, ABS_PRESSURE, elo->data[5]); + input_report_key(dev, BTN_TOUCH, !!elo->data[5]); + } + input_sync(dev); + elo->idx = 0; + break; } } @@ -170,17 +185,17 @@ static void elo_process_data_3(struct elo *elo, unsigned char data) switch (elo->idx++) { - case 0: - if ((data & 0x7f) != 0x01) - elo->idx = 0; - break; - case 2: - input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); - input_report_abs(dev, ABS_X, elo->data[1]); - input_report_abs(dev, ABS_Y, elo->data[2]); - input_sync(dev); + case 0: + if ((data & 0x7f) != 0x01) elo->idx = 0; - break; + break; + case 2: + input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); + input_report_abs(dev, ABS_X, elo->data[1]); + input_report_abs(dev, ABS_Y, elo->data[2]); + input_sync(dev); + elo->idx = 0; + break; } } @@ -189,19 +204,19 @@ static irqreturn_t elo_interrupt(struct serio *serio, { struct elo *elo = serio_get_drvdata(serio); - switch(elo->id) { - case 0: - elo_process_data_10(elo, data); - break; - - case 1: - case 2: - elo_process_data_6(elo, data); - break; - - case 3: - elo_process_data_3(elo, data); - break; + switch (elo->id) { + case 0: + elo_process_data_10(elo, data); + break; + + case 1: + case 2: + elo_process_data_6(elo, data); + break; + + case 3: + elo_process_data_3(elo, data); + break; } return IRQ_HANDLED; @@ -261,10 +276,10 @@ static int elo_setup_10(struct elo *elo) if (packet[3] & ELO10_PRESSURE) input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, " - "features: 0x%02x, controller: 0x%02x\n", - elo_types[(packet[1] -'0') & 0x03], - packet[5], packet[4], packet[3], packet[7]); + dev_info(&elo->serio->dev, + "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n", + elo_types[(packet[1] -'0') & 0x03], + packet[5], packet[4], packet[3], packet[7]); return 0; } @@ -330,24 +345,24 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) switch (elo->id) { - case 0: /* 10-byte protocol */ - if (elo_setup_10(elo)) - goto fail3; + case 0: /* 10-byte protocol */ + if (elo_setup_10(elo)) + goto fail3; - break; + break; - case 1: /* 6-byte protocol */ - input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); + case 1: /* 6-byte protocol */ + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); - case 2: /* 4-byte protocol */ - input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); - input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); - break; + case 2: /* 4-byte protocol */ + input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); + break; - case 3: /* 3-byte protocol */ - input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); - input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); - break; + case 3: /* 3-byte protocol */ + input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); + break; } err = input_register_device(elo->dev); -- GitLab From fc6a110754476362f9f4fa3199a637f2331c5993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 4 Jan 2010 02:02:47 +0000 Subject: [PATCH 0405/3892] Phonet: zero-copy aligned GPRS RX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer Nokia cellular modems can use aligned payload for their GPRS pipe. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/pep.h | 1 + net/phonet/pep-gprs.c | 4 ++-- net/phonet/pep.c | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index 4c61cdce4e5f..c37162547a93 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h @@ -77,6 +77,7 @@ static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb) enum { PNS_PIPE_DATA = 0x20, + PNS_PIPE_ALIGNED_DATA, PNS_PEP_CONNECT_REQ = 0x40, PNS_PEP_CONNECT_RESP, diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index d183509d3fa6..d01208968c83 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -96,11 +96,11 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb) goto drop; } - if (likely(skb_headroom(skb) & 3)) { + if (skb_headroom(skb) & 3) { struct sk_buff *rskb, *fs; int flen = 0; - /* Phonet Pipe data header is misaligned (3 bytes), + /* Phonet Pipe data header may be misaligned (3 bytes), * so wrap the IP packet as a single fragment of an head-less * socket buffer. The network stack will pull what it needs, * but at least, the whole IP payload is not memcpy'd. */ diff --git a/net/phonet/pep.c b/net/phonet/pep.c index b6356f3832f6..e23e30907d34 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -354,6 +354,9 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) queue = &pn->ctrlreq_queue; goto queue; + case PNS_PIPE_ALIGNED_DATA: + __skb_pull(skb, 1); + /* fall through */ case PNS_PIPE_DATA: __skb_pull(skb, 3); /* Pipe data header */ if (!pn_flow_safe(pn->rx_fc)) { -- GitLab From fea93ecef619b5779ca6984568517b1685079b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 4 Jan 2010 02:02:48 +0000 Subject: [PATCH 0406/3892] Phonet: zero-copy GPRS TX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Send aligned pipe payload if requested to do so. Then, the socket buffer needs not be fragmented anymore. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/pep.h | 2 ++ net/phonet/pep.c | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index c37162547a93..35672b1cf44a 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h @@ -44,6 +44,7 @@ struct pep_sock { u8 rx_fc; /* RX flow control */ u8 tx_fc; /* TX flow control */ u8 init_enable; /* auto-enable at creation */ + u8 aligned; }; static inline struct pep_sock *pep_sk(struct sock *sk) @@ -139,6 +140,7 @@ enum { PN_PIPE_SB_NEGOTIATED_FC, PN_PIPE_SB_REQUIRED_FC_TX, PN_PIPE_SB_PREFERRED_FC_RX, + PN_PIPE_SB_ALIGNED_DATA, }; /* Phonet pipe flow control models */ diff --git a/net/phonet/pep.c b/net/phonet/pep.c index e23e30907d34..72db27e3fc06 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -444,6 +444,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) struct sockaddr_pn dst; u16 peer_type; u8 pipe_handle, enabled, n_sb; + u8 aligned = 0; if (!pskb_pull(skb, sizeof(*hdr) + 4)) return -EINVAL; @@ -482,6 +483,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) return -EINVAL; peer_type = (peer_type & 0xff00) | data[0]; break; + case PN_PIPE_SB_ALIGNED_DATA: + aligned = data[0] != 0; + break; } n_sb--; } @@ -513,6 +517,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) newpn->rx_credits = 0; newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; newpn->init_enable = enabled; + newpn->aligned = aligned; BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); skb_queue_head(&newsk->sk_receive_queue, skb); @@ -832,11 +837,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) return -ENOBUFS; } - skb_push(skb, 3); + skb_push(skb, 3 + pn->aligned); skb_reset_transport_header(skb); ph = pnp_hdr(skb); ph->utid = 0; - ph->message_id = PNS_PIPE_DATA; + if (pn->aligned) { + ph->message_id = PNS_PIPE_ALIGNED_DATA; + ph->data[0] = 0; /* padding */ + } else + ph->message_id = PNS_PIPE_DATA; ph->pipe_handle = pn->pipe_handle; return pn_skb_send(sk, skb, &pipe_srv); @@ -930,6 +939,9 @@ int pep_write(struct sock *sk, struct sk_buff *skb) struct sk_buff *rskb, *fs; int flen = 0; + if (pep_sk(sk)->aligned) + return pipe_skb_send(sk, skb); + rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); if (!rskb) { kfree_skb(skb); -- GitLab From 82ecbcb9c6b5257929968d5b0ed536772a9b4ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 4 Jan 2010 02:02:49 +0000 Subject: [PATCH 0407/3892] Phonet: reject unsupported sendmsg/recvmsg flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/datagram.c | 6 ++++-- net/phonet/pep.c | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index 67f072e94d00..387197b579b1 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c @@ -75,7 +75,8 @@ static int pn_sendmsg(struct kiocb *iocb, struct sock *sk, struct sk_buff *skb; int err; - if (msg->msg_flags & MSG_OOB) + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL| + MSG_CMSG_COMPAT)) return -EOPNOTSUPP; if (msg->msg_name == NULL) @@ -119,7 +120,8 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, int rval = -EOPNOTSUPP; int copylen; - if (flags & MSG_OOB) + if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL| + MSG_CMSG_COMPAT)) goto out_nofree; if (addr_len) diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 72db27e3fc06..360cf377693e 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -860,7 +860,9 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, int flags = msg->msg_flags; int err, done; - if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR)) + if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL| + MSG_CMSG_COMPAT)) || + !(msg->msg_flags & MSG_EOR)) return -EOPNOTSUPP; skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, @@ -981,6 +983,10 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, struct sk_buff *skb; int err; + if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL| + MSG_NOSIGNAL|MSG_CMSG_COMPAT)) + return -EOPNOTSUPP; + if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) return -ENOTCONN; @@ -988,6 +994,8 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, /* Dequeue and acknowledge control request */ struct pep_sock *pn = pep_sk(sk); + if (flags & MSG_PEEK) + return -EOPNOTSUPP; skb = skb_dequeue(&pn->ctrlreq_queue); if (skb) { pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, -- GitLab From d160439e7753aa19092bb12d8f4c6c918f8267e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Mon, 4 Jan 2010 13:03:02 +0000 Subject: [PATCH 0408/3892] 8139too: make PCI device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct pci_driver is constant in so it is worth to make pci_device_id also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: David S. Miller --- drivers/net/8139too.c | 2 +- drivers/net/pci-skeleton.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 25f7339daabd..907f2d583db8 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -231,7 +231,7 @@ static const struct { }; -static struct pci_device_id rtl8139_pci_tbl[] = { +static const struct pci_device_id rtl8139_pci_tbl[] = { {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 480af402affd..8ff5536a3757 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -211,7 +211,7 @@ static struct { }; -static struct pci_device_id netdrv_pci_tbl[] = { +static const struct pci_device_id netdrv_pci_tbl[] = { {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB }, {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX }, -- GitLab From ca8d9ea30bc79b2965a1d169dcb2f48f02af4d2d Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Wed, 6 Jan 2010 12:56:37 +0000 Subject: [PATCH 0409/3892] fix bonding: allow arp_ip_targets on separate vlans to use arp validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Wed, Jan 06, 2010 at 10:10:03PM +0100, Eric Dumazet wrote: > Le 06/01/2010 19:38, Eric Dumazet a écrit : > > > > (net-next-2.6 doesnt work well on my bond/vlan setup, I suspect I need a bisection) > > David, I had to revert 1f3c8804acba841b5573b953f5560d2683d2db0d > (bonding: allow arp_ip_targets on separate vlans to use arp validation) > > Or else, my vlan devices dont work (unfortunatly I dont have much time > these days to debug the thing) > > My config : > > +---------+ > vlan.103 -----+ bond0 +--- eth1 (bnx2) > | + > vlan.825 -----+ +--- eth2 (tg3) > +---------+ > > $ cat /proc/net/bonding/bond0 > Ethernet Channel Bonding Driver: v3.6.0 (September 26, 2009) > > Bonding Mode: fault-tolerance (active-backup) > Primary Slave: None > Currently Active Slave: eth2 > MII Status: up > MII Polling Interval (ms): 100 > Up Delay (ms): 0 > Down Delay (ms): 0 > > Slave Interface: eth1 (bnx2) > MII Status: down > Link Failure Count: 1 > Permanent HW addr: 00:1e:0b:ec:d3:d2 > > Slave Interface: eth2 (tg3) > MII Status: up > Link Failure Count: 0 > Permanent HW addr: 00:1e:0b:92:78:50 > This patch fixes up a problem with found with commit 1f3c8804acba841b5573b953f5560d2683d2db0d. The original change overloaded null_or_orig, but doing that prevented any packet handlers that were not tied to a specific device (i.e. ptype->dev == NULL) from ever receiving any frames. The null_or_orig variable cannot be overloaded, and must be kept as NULL to prevent the frame from being ignored by packet handlers designed to accept frames on any interface. Signed-off-by: Andy Gospodarek Signed-off-by: Jay Vosburgh Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index f9aa699ab6cb..d9ab9be0c323 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2430,6 +2430,7 @@ int netif_receive_skb(struct sk_buff *skb) struct packet_type *ptype, *pt_prev; struct net_device *orig_dev; struct net_device *null_or_orig; + struct net_device *null_or_bond; int ret = NET_RX_DROP; __be16 type; @@ -2500,21 +2501,19 @@ ncls: * bonding interfaces still make their way to any base bonding * device that may have registered for a specific ptype. The * handler may have to adjust skb->dev and orig_dev. - * - * null_or_orig can be overloaded since it will not be set when - * using VLANs on top of bonding. Putting it here prevents - * disturbing the ptype_all handlers above. */ + null_or_bond = NULL; if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) && (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) { - null_or_orig = vlan_dev_real_dev(skb->dev); + null_or_bond = vlan_dev_real_dev(skb->dev); } type = skb->protocol; list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { if (ptype->type == type && (ptype->dev == null_or_orig || - ptype->dev == skb->dev || ptype->dev == orig_dev)) { + ptype->dev == skb->dev || ptype->dev == orig_dev || + ptype->dev == null_or_bond)) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; -- GitLab From 65324144b50bc7022cc9b6ca8f4a536a957019e3 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 5 Jan 2010 05:50:47 +0000 Subject: [PATCH 0410/3892] net: RFC3069, private VLAN proxy arp support This is to be used together with switch technologies, like RFC3069, that where the individual ports are not allowed to communicate with each other, but they are allowed to talk to the upstream router. As described in RFC 3069, it is possible to allow these hosts to communicate through the upstream router by proxy_arp'ing. This patch basically allow proxy arp replies back to the same interface (from which the ARP request/solicitation was received). Tunable per device via proc "proxy_arp_pvlan": /proc/sys/net/ipv4/conf/*/proxy_arp_pvlan This switch technology is known by different vendor names: - In RFC 3069 it is called VLAN Aggregation. - Cisco and Allied Telesyn call it Private VLAN. - Hewlett-Packard call it Source-Port filtering or port-isolation. - Ericsson call it MAC-Forced Forwarding (RFC Draft). Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 19 ++++++++++ include/linux/inetdevice.h | 1 + include/linux/sysctl.h | 1 + net/ipv4/arp.c | 52 ++++++++++++++++++++++++-- net/ipv4/devinet.c | 1 + net/ipv4/route.c | 7 +++- 6 files changed, 76 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 006b39dec87d..c532884f4fec 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -692,6 +692,25 @@ proxy_arp - BOOLEAN conf/{all,interface}/proxy_arp is set to TRUE, it will be disabled otherwise +proxy_arp_pvlan - BOOLEAN + Private VLAN proxy arp. + Basically allow proxy arp replies back to the same interface + (from which the ARP request/solicitation was received). + + This is done to support (ethernet) switch features, like RFC + 3069, where the individual ports are NOT allowed to + communicate with each other, but they are allowed to talk to + the upstream router. As described in RFC 3069, it is possible + to allow these hosts to communicate through the upstream + router by proxy_arp'ing. Don't need to be used together with + proxy_arp. + + This technology is known by different names: + In RFC 3069 it is called VLAN Aggregation. + Cisco and Allied Telesyn call it Private VLAN. + Hewlett-Packard call it Source-Port filtering or port-isolation. + Ericsson call it MAC-Forced Forwarding (RFC Draft). + shared_media - BOOLEAN Send(router) or accept(host) RFC1620 shared media redirects. Overrides ip_secure_redirects. diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 699e85c01a4d..9a8c57467d3d 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -88,6 +88,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) #define IN_DEV_LOG_MARTIANS(in_dev) IN_DEV_ORCONF((in_dev), LOG_MARTIANS) #define IN_DEV_PROXY_ARP(in_dev) IN_DEV_ORCONF((in_dev), PROXY_ARP) +#define IN_DEV_PROXY_ARP_PVLAN(in_dev) IN_DEV_CONF_GET(in_dev, PROXY_ARP_PVLAN) #define IN_DEV_SHARED_MEDIA(in_dev) IN_DEV_ORCONF((in_dev), SHARED_MEDIA) #define IN_DEV_TX_REDIRECTS(in_dev) IN_DEV_ORCONF((in_dev), SEND_REDIRECTS) #define IN_DEV_SEC_REDIRECTS(in_dev) IN_DEV_ORCONF((in_dev), \ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 877ba039e6a4..24ff7e3a0d59 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -482,6 +482,7 @@ enum NET_IPV4_CONF_ARP_ACCEPT=21, NET_IPV4_CONF_ARP_NOTIFY=22, NET_IPV4_CONF_ACCEPT_LOCAL=23, + NET_IPV4_CONF_PROXY_ARP_PVLAN=24, __NET_IPV4_CONF_MAX }; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index c95cd93acf29..078709233bc4 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -70,6 +70,7 @@ * bonding can change the skb before * sending (e.g. insert 8021q tag). * Harald Welte : convert to make use of jenkins hash + * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. */ #include @@ -524,12 +525,15 @@ int arp_bind_neighbour(struct dst_entry *dst) /* * Check if we can use proxy ARP for this path */ - -static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) +static inline int arp_fwd_proxy(struct in_device *in_dev, + struct net_device *dev, struct rtable *rt) { struct in_device *out_dev; int imi, omi = -1; + if (rt->u.dst.dev == dev) + return 0; + if (!IN_DEV_PROXY_ARP(in_dev)) return 0; @@ -547,6 +551,43 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) return (omi != imi && omi != -1); } +/* + * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) + * + * RFC3069 supports proxy arp replies back to the same interface. This + * is done to support (ethernet) switch features, like RFC 3069, where + * the individual ports are not allowed to communicate with each + * other, BUT they are allowed to talk to the upstream router. As + * described in RFC 3069, it is possible to allow these hosts to + * communicate through the upstream router, by proxy_arp'ing. + * + * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" + * + * This technology is known by different names: + * In RFC 3069 it is called VLAN Aggregation. + * Cisco and Allied Telesyn call it Private VLAN. + * Hewlett-Packard call it Source-Port filtering or port-isolation. + * Ericsson call it MAC-Forced Forwarding (RFC Draft). + * + */ +static inline int arp_fwd_pvlan(struct in_device *in_dev, + struct net_device *dev, struct rtable *rt, + __be32 sip, __be32 tip) +{ + /* Private VLAN is only concerned about the same ethernet segment */ + if (rt->u.dst.dev != dev) + return 0; + + /* Don't reply on self probes (often done by windowz boxes)*/ + if (sip == tip) + return 0; + + if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) + return 1; + else + return 0; +} + /* * Interface to link layer: send routine and receive handler. */ @@ -833,8 +874,11 @@ static int arp_process(struct sk_buff *skb) } goto out; } else if (IN_DEV_FORWARD(in_dev)) { - if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && - (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { + if (addr_type == RTN_UNICAST && + (arp_fwd_proxy(in_dev, dev, rt) || + arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || + pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) + { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) neigh_release(n); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5cdbc102a418..0715f4cac391 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1407,6 +1407,7 @@ static struct devinet_sysctl_table { DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"), DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"), + DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"), DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e446496f564f..1cc339441e7d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1988,8 +1988,13 @@ static int __mkroute_input(struct sk_buff *skb, if (skb->protocol != htons(ETH_P_IP)) { /* Not IP (i.e. ARP). Do not create route, if it is * invalid for proxy arp. DNAT routes are always valid. + * + * Proxy arp feature have been extended to allow, ARP + * replies back to the same interface, to support + * Private VLAN switch technologies. See arp.c. */ - if (out_dev == in_dev) { + if (out_dev == in_dev && + IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) { err = -EINVAL; goto cleanup; } -- GitLab From 2d13bafeba24f732e89b818b8c66b07893457570 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 5 Jan 2010 05:50:52 +0000 Subject: [PATCH 0411/3892] net: Make it easier to parse /proc/net/dev contents. The contents of /proc/net/dev is annoying to parse, because it changes whether there is a space after the "ethX:" or not. It depends upon the size of the "Receive bytes" counter, if the number is below 7 digits, then there is whitespaces else if the number is 8 digits or above there is no space between the ":" and the number. This patch changes the output to assure there is always a space between the ":" and the number. Given that all existing userspace application already need to handle the whitespaces, I see no breakage of existing tools. Signed-off-by: Jesper Dangaard Brouer Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index d9ab9be0c323..a008f6987a95 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3206,7 +3206,7 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) { const struct net_device_stats *stats = dev_get_stats(dev); - seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " + seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, -- GitLab From 1154b299e7924f2ae8bb3ca479a6942e1edd78fc Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:28:08 +0000 Subject: [PATCH 0412/3892] drivers/atm/nicstar.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/atm/nicstar.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 3da804b1627d..50838407b117 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -807,9 +807,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) } } - printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, - card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], - card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); + printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi); card->atmdev->dev_data = card; card->atmdev->ci_range.vpi_bits = card->vpibits; -- GitLab From ce7194d889996fb8f724148bc85a0c2c79da7b8e Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:56:52 +0000 Subject: [PATCH 0413/3892] drivers/net/ixgbe/ixgbe_common.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. The only difference in the output is that the MAC address is shown in the usual colon-separated hex notation. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_common.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 688b8ca5da32..1cedb9af63dc 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1278,19 +1278,11 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) /* Get the MAC address from the RAR0 for later reference */ hw->mac.ops.get_mac_addr(hw, hw->mac.addr); - hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ", - hw->mac.addr[0], hw->mac.addr[1], - hw->mac.addr[2]); - hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], - hw->mac.addr[4], hw->mac.addr[5]); + hw_dbg(hw, " Keeping Current RAR0 Addr =%pM\n", hw->mac.addr); } else { /* Setup the receive address. */ hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); - hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ", - hw->mac.addr[0], hw->mac.addr[1], - hw->mac.addr[2]); - hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], - hw->mac.addr[4], hw->mac.addr[5]); + hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr); hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); } -- GitLab From aaa09ee7287d31f57f4dc8b4acca5cd59c1595f5 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:24:23 +0000 Subject: [PATCH 0414/3892] drivers/atm/idt77252.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/atm/idt77252.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index e33ae0025b12..01f36c08cb52 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -3557,10 +3557,7 @@ init_card(struct atm_dev *dev) if (tmp) { memcpy(card->atmdev->esi, tmp->dev_addr, 6); - printk("%s: ESI %02x:%02x:%02x:%02x:%02x:%02x\n", - card->name, card->atmdev->esi[0], card->atmdev->esi[1], - card->atmdev->esi[2], card->atmdev->esi[3], - card->atmdev->esi[4], card->atmdev->esi[5]); + printk("%s: ESI %pM\n", card->name, card->atmdev->esi); } /* * XXX: -- GitLab From 2c35294853b2e977bdfc9e401b7b6d881fcaa69b Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:37:43 +0000 Subject: [PATCH 0415/3892] drivers/firmware/iscsi_ibft.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Also, remove the 'mac' variable and use nic->mac directly. Signed-off-by: H Hartley Sweeten Acked-by: Peter Jones Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/firmware/iscsi_ibft.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 051d1ebbd287..5aeb3b541c80 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -380,7 +380,6 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, struct ibft_nic *nic = entry->nic; void *ibft_loc = entry->header; char *str = buf; - char *mac; int val; if (!nic) @@ -421,10 +420,7 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, str += sprintf(str, "%d\n", nic->vlan); break; case ibft_eth_mac: - mac = nic->mac; - str += sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (u8)mac[0], (u8)mac[1], (u8)mac[2], - (u8)mac[3], (u8)mac[4], (u8)mac[5]); + str += sprintf(str, "%pM\n", nic->mac); break; case ibft_eth_hostname: str += sprintf_string(str, nic->hostname_len, -- GitLab From 3008ab36e23623cbe7a53bff2d495eca5426a9ce Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:22:20 +0000 Subject: [PATCH 0416/3892] drivers/atm/fore200e.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index bc53fed89b1e..f7d6ebaa0418 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2064,12 +2064,10 @@ fore200e_get_esi(struct fore200e* fore200e) return -EBUSY; } - printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", + printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %pM\n", fore200e->name, (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ - prom->serial_number & 0xFFFF, - prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], - prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); + prom->serial_number & 0xFFFF, &prom->mac_addr[2]); for (i = 0; i < ESI_LEN; i++) { fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; @@ -2845,13 +2843,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " interrupt line:\t\t%s\n" " physical base address:\t0x%p\n" " virtual base address:\t0x%p\n" - " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n" + " factory address (ESI):\t%pM\n" " board serial number:\t\t%d\n\n", fore200e_irq_itoa(fore200e->irq), (void*)fore200e->phys_base, fore200e->virt_base, - fore200e->esi[0], fore200e->esi[1], fore200e->esi[2], - fore200e->esi[3], fore200e->esi[4], fore200e->esi[5], + fore200e->esi, fore200e->esi[4] * 256 + fore200e->esi[5]); return len; -- GitLab From 8d9ded23b3259c7f6883e97284e949af7afd4e40 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:26:49 +0000 Subject: [PATCH 0417/3892] drivers/atm/lanai.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/atm/lanai.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index cf97c34cbaf1..7fe7c324e7ef 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -998,9 +998,7 @@ static int __devinit eeprom_validate(struct lanai_dev *lanai) (unsigned int) e[EEPROM_MAC_REV + i]); return -EIO; } - DPRINTK("eeprom: MAC address = %02X:%02X:%02X:%02X:%02X:%02X\n", - e[EEPROM_MAC + 0], e[EEPROM_MAC + 1], e[EEPROM_MAC + 2], - e[EEPROM_MAC + 3], e[EEPROM_MAC + 4], e[EEPROM_MAC + 5]); + DPRINTK("eeprom: MAC address = %pM\n", &e[EEPROM_MAC]); /* Verify serial number */ lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL); v = eeprom_be4(lanai, EEPROM_SERIAL_REV); @@ -2483,14 +2481,8 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) return sprintf(page, "revision: board=%d, pci_if=%d\n", lanai->board_rev, (int) lanai->pci->revision); if (left-- == 0) - return sprintf(page, "EEPROM ESI: " - "%02X:%02X:%02X:%02X:%02X:%02X\n", - lanai->eeprom[EEPROM_MAC + 0], - lanai->eeprom[EEPROM_MAC + 1], - lanai->eeprom[EEPROM_MAC + 2], - lanai->eeprom[EEPROM_MAC + 3], - lanai->eeprom[EEPROM_MAC + 4], - lanai->eeprom[EEPROM_MAC + 5]); + return sprintf(page, "EEPROM ESI: %pM\n", + &lanai->eeprom[EEPROM_MAC]); if (left-- == 0) return sprintf(page, "status: SOOL=%d, LOCD=%d, LED=%d, " "GPIN=%d\n", (lanai->status & STATUS_SOOL) ? 1 : 0, -- GitLab From 0e05a613f40a1210a050ebd1ecfd5434420ae5b2 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:45:21 +0000 Subject: [PATCH 0418/3892] drivers/media/dvb/dvb-core/dvb_net.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address and mask. The only difference in the output is that the output is shown in the usual colon-separated hex notation. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/media/dvb/dvb-core/dvb_net.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8b8558fcb042..da6552d32cfe 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -949,11 +949,8 @@ static int dvb_net_filter_sec_set(struct net_device *dev, (*secfilter)->filter_mask[10] = mac_mask[1]; (*secfilter)->filter_mask[11]=mac_mask[0]; - dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n", - dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n", - dev->name, mac_mask[0], mac_mask[1], mac_mask[2], - mac_mask[3], mac_mask[4], mac_mask[5]); + dprintk("%s: filter mac=%pM\n", dev->name, mac); + dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); return 0; } -- GitLab From bf54e73691158a634ff72ebc139f38c4fa7b83f0 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:59:23 +0000 Subject: [PATCH 0419/3892] drivers/net/vxge/vxge-main.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index f1c4b2a1e867..5f0e7ea0d493 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4297,10 +4297,8 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter", vdev->ndev->name, ll_config.device_hw_info.product_desc); - vxge_debug_init(VXGE_TRACE, - "%s: MAC ADDR: %02X:%02X:%02X:%02X:%02X:%02X", - vdev->ndev->name, macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); + vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM", + vdev->ndev->name, macaddr); vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d", vdev->ndev->name, vxge_hw_device_link_width_get(hldev)); -- GitLab From 829911725f4bb72c30480aab756704d588c7cd1e Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:54:01 +0000 Subject: [PATCH 0420/3892] drivers/net/atl1c/atl1c_main.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. The only difference in the output is that the MAC address is shown in the usual colon-separated hex notation. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/atl1c/atl1c_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 2f4be59b9c0b..77cde859620c 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2596,11 +2596,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); if (netif_msg_probe(adapter)) - dev_dbg(&pdev->dev, - "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n", - adapter->hw.mac_addr[0], adapter->hw.mac_addr[1], - adapter->hw.mac_addr[2], adapter->hw.mac_addr[3], - adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]); + dev_dbg(&pdev->dev, "mac address : %pM\n", + adapter->hw.mac_addr); atl1c_hw_set_mac_addr(&adapter->hw); INIT_WORK(&adapter->common_task, atl1c_common_task); -- GitLab From 595acf270e098ee3af92890253c5db41bc85de88 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 07:01:54 +0000 Subject: [PATCH 0421/3892] drivers/net/wimax/i2400m/fw.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/fw.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 64cdfeb299ca..e803a7dc6502 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -1041,21 +1041,14 @@ int i2400m_read_mac_addr(struct i2400m *i2400m) dev_err(dev, "BM: read mac addr failed: %d\n", result); goto error_read_mac; } - d_printf(2, dev, - "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n", - ack_buf.ack_pl[0], ack_buf.ack_pl[1], - ack_buf.ack_pl[2], ack_buf.ack_pl[3], - ack_buf.ack_pl[4], ack_buf.ack_pl[5]); + d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl); if (i2400m->bus_bm_mac_addr_impaired == 1) { ack_buf.ack_pl[0] = 0x00; ack_buf.ack_pl[1] = 0x16; ack_buf.ack_pl[2] = 0xd3; get_random_bytes(&ack_buf.ack_pl[3], 3); dev_err(dev, "BM is MAC addr impaired, faking MAC addr to " - "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n", - ack_buf.ack_pl[0], ack_buf.ack_pl[1], - ack_buf.ack_pl[2], ack_buf.ack_pl[3], - ack_buf.ack_pl[4], ack_buf.ack_pl[5]); + "mac addr is %pM\n", ack_buf.ack_pl); result = 0; } net_dev->addr_len = ETH_ALEN; -- GitLab From 1b8e664d34f2f551fd6c2d40033d29c13551292c Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:55:40 +0000 Subject: [PATCH 0422/3892] drivers/net/atl1e/atl1e_main.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. The only difference in the output is that the MAC address is shown in the usual colon-separated hex notation. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/atl1e/atl1e_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 08f8c0969e9b..2080d444068b 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2378,10 +2378,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - dev_dbg(&pdev->dev, "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n", - adapter->hw.mac_addr[0], adapter->hw.mac_addr[1], - adapter->hw.mac_addr[2], adapter->hw.mac_addr[3], - adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]); + dev_dbg(&pdev->dev, "mac address : %pM\n", adapter->hw.mac_addr); INIT_WORK(&adapter->reset_task, atl1e_reset_task); INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task); -- GitLab From fcb635e8c6d68bf06531603a1caa6e59ba7e356d Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 06:58:12 +0000 Subject: [PATCH 0423/3892] drivers/net/qlge/qlge_main.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index e9d6481ed9eb..25561fbdb203 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -452,9 +452,7 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set) if (set) { addr = &qdev->ndev->dev_addr[0]; QPRINTK(qdev, IFUP, DEBUG, - "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n", - addr[0], addr[1], addr[2], addr[3], - addr[4], addr[5]); + "Set Mac addr %pM\n", addr); } else { memset(zero_mac_addr, 0, ETH_ALEN); addr = &zero_mac_addr[0]; -- GitLab From 4754b3de93f893e85d811031ff742fc7a4f53db4 Mon Sep 17 00:00:00 2001 From: hartleys Date: Tue, 5 Jan 2010 07:00:57 +0000 Subject: [PATCH 0424/3892] drivers/net/wimax/i2400m/driver.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/driver.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 96a615fe09de..6cead321bc15 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -301,24 +301,15 @@ int i2400m_check_mac_addr(struct i2400m *i2400m) /* Extract MAC addresss */ ddi = (void *) skb->data; BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address)); - d_printf(2, dev, "GET DEVICE INFO: mac addr " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - ddi->mac_address[0], ddi->mac_address[1], - ddi->mac_address[2], ddi->mac_address[3], - ddi->mac_address[4], ddi->mac_address[5]); + d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n", + ddi->mac_address); if (!memcmp(net_dev->perm_addr, ddi->mac_address, sizeof(ddi->mac_address))) goto ok; dev_warn(dev, "warning: device reports a different MAC address " "to that of boot mode's\n"); - dev_warn(dev, "device reports %02x:%02x:%02x:%02x:%02x:%02x\n", - ddi->mac_address[0], ddi->mac_address[1], - ddi->mac_address[2], ddi->mac_address[3], - ddi->mac_address[4], ddi->mac_address[5]); - dev_warn(dev, "boot mode reported %02x:%02x:%02x:%02x:%02x:%02x\n", - net_dev->perm_addr[0], net_dev->perm_addr[1], - net_dev->perm_addr[2], net_dev->perm_addr[3], - net_dev->perm_addr[4], net_dev->perm_addr[5]); + dev_warn(dev, "device reports %pM\n", ddi->mac_address); + dev_warn(dev, "boot mode reported %pM\n", net_dev->perm_addr); if (!memcmp(zeromac, ddi->mac_address, sizeof(zeromac))) dev_err(dev, "device reports an invalid MAC address, " "not updating\n"); -- GitLab From eacc4d6a7dc447ec4fc219af129e0fe50d21d8f7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Thu, 7 Jan 2010 01:17:27 -0800 Subject: [PATCH 0425/3892] drivers/infiniband/hw/cxgb3/iwch_cm.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. The only difference in the output is that the MAC address is shown in the usual colon-separated hex notation. Signed-off-by: H Hartley Sweeten Acked-by: Steve Wise Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 66b41351910a..d94388b81a40 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1371,15 +1371,8 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) tim.mac_addr = req->dst_mac; tim.vlan_tag = ntohs(req->vlan_tag); if (tdev->ctl(tdev, GET_IFF_FROM_MAC, &tim) < 0 || !tim.dev) { - printk(KERN_ERR - "%s bad dst mac %02x %02x %02x %02x %02x %02x\n", - __func__, - req->dst_mac[0], - req->dst_mac[1], - req->dst_mac[2], - req->dst_mac[3], - req->dst_mac[4], - req->dst_mac[5]); + printk(KERN_ERR "%s bad dst mac %pM\n", + __func__, req->dst_mac); goto reject; } -- GitLab From cf30273bea4a9d368a31869ccc6ad618e4413b66 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Thu, 7 Jan 2010 01:18:23 -0800 Subject: [PATCH 0426/3892] drivers/message/i2o/i2o_proc.c: use %pM to show MAC address Use the %pM kernel extension to display the MAC address. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- drivers/message/i2o/i2o_proc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 7045c45da9b1..949a648f8e2e 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -111,10 +111,7 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) break; case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ - seq_printf(seq, - "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", - serialno[2], serialno[3], - serialno[4], serialno[5], serialno[6], serialno[7]); + seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]); break; case I2O_SNFORMAT_WAN: /* WAN MAC Address */ @@ -126,10 +123,8 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ /* FIXME: Figure out what a LAN-64 address really looks like?? */ seq_printf(seq, - "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", - serialno[8], serialno[9], - serialno[2], serialno[3], - serialno[4], serialno[5], serialno[6], serialno[7]); + "LAN-64 MAC address @ [?:%02X:%02X:?] %pM", + serialno[8], serialno[9], &serialno[2]); break; case I2O_SNFORMAT_DDM: /* I2O DDM */ -- GitLab From 741b20cfb9109760937f403d18d731bfde31f56f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 17 Dec 2009 17:34:39 +0100 Subject: [PATCH 0427/3892] ALSA: pcm_lib.c - convert second xrun_debug() parameter to use defines To increase code readability, convert send xrun_debug() argument to use defines. Signed-off-by: Jaroslav Kysela --- sound/core/pcm_lib.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 30f410832a25..9621236b2fef 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -126,15 +126,22 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } } +#define XRUN_DEBUG_BASIC (1<<0) +#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ +#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ +#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ +#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ + #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) +#define xrun_debug(substream, mask) \ + ((substream)->pstr->xrun_debug & (mask)) #else #define xrun_debug(substream, mask) 0 #endif -#define dump_stack_on_xrun(substream) do { \ - if (xrun_debug(substream, 2)) \ - dump_stack(); \ +#define dump_stack_on_xrun(substream) do { \ + if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ + dump_stack(); \ } while (0) static void pcm_debug_name(struct snd_pcm_substream *substream, @@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - if (xrun_debug(substream, 1)) { + if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { char name[16]; pcm_debug_name(substream, name, sizeof(name)); snd_printd(KERN_DEBUG "XRUN: %s\n", name); @@ -215,7 +222,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, #define hw_ptr_error(substream, fmt, args...) \ do { \ - if (xrun_debug(substream, 1)) { \ + if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ if (printk_ratelimit()) { \ snd_printd("PCM: " fmt, ##args); \ } \ @@ -237,7 +244,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) xrun(substream); return -EPIPE; } - if (xrun_debug(substream, 8)) { + if (xrun_debug(substream, XRUN_DEBUG_PERIODUPDATE)) { char name[16]; pcm_debug_name(substream, name, sizeof(name)); snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " @@ -290,7 +297,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, 4)) + if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) goto no_jiffies_check; /* Skip the jiffies check for hardwares with BATCH flag. @@ -369,7 +376,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) xrun(substream); return -EPIPE; } - if (xrun_debug(substream, 16)) { + if (xrun_debug(substream, XRUN_DEBUG_HWPTRUPDATE)) { char name[16]; pcm_debug_name(substream, name, sizeof(name)); snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " @@ -403,7 +410,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) new_hw_ptr = hw_base + pos; } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, 4)) + if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) goto no_jiffies_check; if (delta < runtime->delay) goto no_jiffies_check; -- GitLab From 4d96eb255c53ab5e39b37fd4d484ea3dc39ab456 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 20 Dec 2009 11:47:57 +0100 Subject: [PATCH 0428/3892] ALSA: pcm_lib - add possibility to log last 10 DMA ring buffer positions In some debug cases, it might be usefull to see previous ring buffer positions to determine position problems from the lowlevel drivers. Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 6 ++ sound/core/pcm.c | 4 ++ sound/core/pcm_lib.c | 140 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 127 insertions(+), 23 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c83a4a79f16b..4e18a6dbe690 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -262,6 +262,8 @@ struct snd_pcm_hw_constraint_list { unsigned int mask; }; +struct snd_pcm_hwptr_log; + struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; @@ -340,6 +342,10 @@ struct snd_pcm_runtime { /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; #endif + +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + struct snd_pcm_hwptr_log *hwptr_log; +#endif }; struct snd_pcm_group { /* keep linked substreams */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 6884ae031f6f..df57a0e30bf2 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -921,6 +921,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + if (runtime->hwptr_log) + kfree(runtime->hwptr_log); +#endif kfree(runtime); substream->runtime = NULL; put_pid(substream->pid); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9621236b2fef..1990afb8a735 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -126,34 +126,34 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } } +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) +{ + snprintf(name, len, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} + #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ +#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ +#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ #ifdef CONFIG_SND_PCM_XRUN_DEBUG + #define xrun_debug(substream, mask) \ ((substream)->pstr->xrun_debug & (mask)) -#else -#define xrun_debug(substream, mask) 0 -#endif #define dump_stack_on_xrun(substream) do { \ if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ dump_stack(); \ } while (0) -static void pcm_debug_name(struct snd_pcm_substream *substream, - char *name, size_t len) -{ - snprintf(name, len, "pcmC%dD%d%c:%d", - substream->pcm->card->number, - substream->pcm->device, - substream->stream ? 'c' : 'p', - substream->number); -} - static void xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -169,6 +169,102 @@ static void xrun(struct snd_pcm_substream *substream) } } +#define hw_ptr_error(substream, fmt, args...) \ + do { \ + if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ + if (printk_ratelimit()) { \ + snd_printd("PCM: " fmt, ##args); \ + } \ + dump_stack_on_xrun(substream); \ + } \ + } while (0) + +#define XRUN_LOG_CNT 10 + +struct hwptr_log_entry { + unsigned long jiffies; + snd_pcm_uframes_t pos; + snd_pcm_uframes_t period_size; + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t old_hw_ptr; + snd_pcm_uframes_t hw_ptr_base; + snd_pcm_uframes_t hw_ptr_interrupt; +}; + +struct snd_pcm_hwptr_log { + unsigned int idx; + unsigned int hit: 1; + struct hwptr_log_entry entries[XRUN_LOG_CNT]; +}; + +static void xrun_log(struct snd_pcm_substream *substream, + snd_pcm_uframes_t pos) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hwptr_log *log = runtime->hwptr_log; + struct hwptr_log_entry *entry; + + if (log == NULL) { + log = kzalloc(sizeof(*log), GFP_ATOMIC); + if (log == NULL) + return; + runtime->hwptr_log = log; + } else { + if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) + return; + } + entry = &log->entries[log->idx]; + entry->jiffies = jiffies; + entry->pos = pos; + entry->period_size = runtime->period_size; + entry->buffer_size = runtime->buffer_size;; + entry->old_hw_ptr = runtime->status->hw_ptr; + entry->hw_ptr_base = runtime->hw_ptr_base; + entry->hw_ptr_interrupt = runtime->hw_ptr_interrupt;; + log->idx = (log->idx + 1) % XRUN_LOG_CNT; +} + +static void xrun_log_show(struct snd_pcm_substream *substream) +{ + struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; + struct hwptr_log_entry *entry; + char name[16]; + unsigned int idx; + int cnt; + + if (log == NULL) + return; + if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) + return; + pcm_debug_name(substream, name, sizeof(name)); + for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { + entry = &log->entries[idx]; + if (entry->period_size == 0) + break; + snd_printd("hwptr log: %s: j=%lu, pos=0x%lx/0x%lx/0x%lx, " + "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + name, entry->jiffies, (unsigned long)entry->pos, + (unsigned long)entry->period_size, + (unsigned long)entry->buffer_size, + (unsigned long)entry->old_hw_ptr, + (unsigned long)entry->hw_ptr_base, + (unsigned long)entry->hw_ptr_interrupt); + idx++; + idx %= XRUN_LOG_CNT; + } + log->hit = 1; +} + +#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ + +#define xrun_debug(substream, mask) 0 +#define xrun(substream) do { } while (0) +#define hw_ptr_error(substream, fmt, args...) do { } while (0) +#define xrun_log(substream, pos) do { } while (0) +#define xrun_log_show(substream) do { } while (0) + +#endif + static snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime) @@ -182,6 +278,7 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, if (printk_ratelimit()) { char name[16]; pcm_debug_name(substream, name, sizeof(name)); + xrun_log_show(substream); snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " "buffer size = 0x%lx, period size = 0x%lx\n", name, pos, runtime->buffer_size, @@ -190,6 +287,8 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, pos = 0; } pos -= pos % runtime->min_align; + if (xrun_debug(substream, XRUN_DEBUG_LOG)) + xrun_log(substream, pos); return pos; } @@ -220,16 +319,6 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, return 0; } -#define hw_ptr_error(substream, fmt, args...) \ - do { \ - if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ - if (printk_ratelimit()) { \ - snd_printd("PCM: " fmt, ##args); \ - } \ - dump_stack_on_xrun(substream); \ - } \ - } while (0) - static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -270,6 +359,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) delta += runtime->buffer_size; if (delta < 0) { + xrun_log_show(substream); hw_ptr_error(substream, "Unexpected hw_pointer value " "(stream=%i, pos=%ld, intr_ptr=%ld)\n", @@ -315,6 +405,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) delta = jdelta / (((runtime->period_size * HZ) / runtime->rate) + HZ/100); + xrun_log_show(substream); hw_ptr_error(substream, "hw_ptr skipping! [Q] " "(pos=%ld, delta=%ld, period=%ld, " @@ -334,6 +425,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { + xrun_log_show(substream); hw_ptr_error(substream, "Lost interrupts? " "(stream=%i, delta=%ld, intr_ptr=%ld)\n", @@ -397,6 +489,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) if (delta < 0) { delta += runtime->buffer_size; if (delta < 0) { + xrun_log_show(substream); hw_ptr_error(substream, "Unexpected hw_pointer value [2] " "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", @@ -416,6 +509,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) goto no_jiffies_check; delta -= runtime->delay; if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { + xrun_log_show(substream); hw_ptr_error(substream, "hw_ptr skipping! " "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", -- GitLab From f240406babfe1526998e10583ea5eccc2676a433 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 5 Jan 2010 17:19:34 +0100 Subject: [PATCH 0429/3892] ALSA: pcm_lib - cleanup & merge hw_ptr update functions Do general cleanup in snd_pcm_update_hw_ptr*() routines and merge them. The main change is hw_ptr_interrupt variable removal to simplify code logic. This variable can be computed directly from hw_ptr. Ensure that updated hw_ptr is not lower than previous one (it was possible with old code in some obscure situations when interrupt was delayed or the lowlevel driver returns wrong ring buffer position value). Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 1 - include/sound/pcm_oss.h | 2 +- sound/core/oss/pcm_oss.c | 32 +++-- sound/core/pcm_lib.c | 279 ++++++++++++++------------------------- sound/core/pcm_native.c | 2 - 5 files changed, 121 insertions(+), 195 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 4e18a6dbe690..fe1b131842be 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -271,7 +271,6 @@ struct snd_pcm_runtime { int overrange; snd_pcm_uframes_t avail_max; snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ - snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index cc4e226f35fd..760c969d885d 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h @@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime { struct snd_pcm_plugin *plugin_first; struct snd_pcm_plugin *plugin_last; #endif - unsigned int prev_hw_ptr_interrupt; + unsigned int prev_hw_ptr_period; }; struct snd_pcm_oss_file { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d9c96353121a..255ad910077a 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -632,6 +632,13 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); } +static inline +snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime) +{ + snd_pcm_uframes_t ptr = runtime->status->hw_ptr; + return ptr - (ptr % runtime->period_size); +} + /* define extended formats in the recent OSS versions (if any) */ /* linear formats */ #define AFMT_S32_LE 0x00001000 @@ -1102,7 +1109,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) return err; } runtime->oss.prepare = 0; - runtime->oss.prev_hw_ptr_interrupt = 0; + runtime->oss.prev_hw_ptr_period = 0; runtime->oss.period_ptr = 0; runtime->oss.buffer_used = 0; @@ -1950,7 +1957,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file) return result; } -static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) +static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, + snd_pcm_uframes_t hw_ptr) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr; @@ -1986,7 +1994,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr if (runtime->oss.trigger) goto _skip1; if (atomic_read(&psubstream->mmap_count)) - snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); + snd_pcm_oss_simulate_fill(psubstream, + get_hw_ptr_period(runtime)); runtime->oss.trigger = 1; runtime->start_threshold = 1; cmd = SNDRV_PCM_IOCTL_START; @@ -2105,11 +2114,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); if (atomic_read(&substream->mmap_count)) { snd_pcm_sframes_t n; - n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; + delay = get_hw_ptr_period(runtime); + n = delay - runtime->oss.prev_hw_ptr_period; if (n < 0) n += runtime->boundary; info.blocks = n / runtime->period_size; - runtime->oss.prev_hw_ptr_interrupt = delay; + runtime->oss.prev_hw_ptr_period = delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_oss_simulate_fill(substream, delay); info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; @@ -2673,18 +2683,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) - return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; + return runtime->oss.prev_hw_ptr_period != + get_hw_ptr_period(runtime); else - return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; + return snd_pcm_playback_avail(runtime) >= + runtime->oss.period_frames; } static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) - return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; + return runtime->oss.prev_hw_ptr_period != + get_hw_ptr_period(runtime); else - return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; + return snd_pcm_capture_avail(runtime) >= + runtime->oss.period_frames; } static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 1990afb8a735..70a4f7428d78 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -172,6 +172,7 @@ static void xrun(struct snd_pcm_substream *substream) #define hw_ptr_error(substream, fmt, args...) \ do { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ + xrun_log_show(substream); \ if (printk_ratelimit()) { \ snd_printd("PCM: " fmt, ##args); \ } \ @@ -188,7 +189,6 @@ struct hwptr_log_entry { snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t old_hw_ptr; snd_pcm_uframes_t hw_ptr_base; - snd_pcm_uframes_t hw_ptr_interrupt; }; struct snd_pcm_hwptr_log { @@ -220,7 +220,6 @@ static void xrun_log(struct snd_pcm_substream *substream, entry->buffer_size = runtime->buffer_size;; entry->old_hw_ptr = runtime->status->hw_ptr; entry->hw_ptr_base = runtime->hw_ptr_base; - entry->hw_ptr_interrupt = runtime->hw_ptr_interrupt;; log->idx = (log->idx + 1) % XRUN_LOG_CNT; } @@ -241,14 +240,13 @@ static void xrun_log_show(struct snd_pcm_substream *substream) entry = &log->entries[idx]; if (entry->period_size == 0) break; - snd_printd("hwptr log: %s: j=%lu, pos=0x%lx/0x%lx/0x%lx, " - "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " + "hwptr=%ld/%ld\n", name, entry->jiffies, (unsigned long)entry->pos, (unsigned long)entry->period_size, (unsigned long)entry->buffer_size, (unsigned long)entry->old_hw_ptr, - (unsigned long)entry->hw_ptr_base, - (unsigned long)entry->hw_ptr_interrupt); + (unsigned long)entry->hw_ptr_base); idx++; idx %= XRUN_LOG_CNT; } @@ -265,33 +263,6 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #endif -static snd_pcm_uframes_t -snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) -{ - snd_pcm_uframes_t pos; - - pos = substream->ops->pointer(substream); - if (pos == SNDRV_PCM_POS_XRUN) - return pos; /* XRUN */ - if (pos >= runtime->buffer_size) { - if (printk_ratelimit()) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - xrun_log_show(substream); - snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " - "buffer size = 0x%lx, period size = 0x%lx\n", - name, pos, runtime->buffer_size, - runtime->period_size); - } - pos = 0; - } - pos -= pos % runtime->min_align; - if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos); - return pos; -} - static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime) { @@ -319,72 +290,88 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, return 0; } -static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) +static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, + unsigned int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; + snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; snd_pcm_sframes_t hdelta, delta; unsigned long jdelta; old_hw_ptr = runtime->status->hw_ptr; - pos = snd_pcm_update_hw_ptr_pos(substream, runtime); + pos = substream->ops->pointer(substream); if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); return -EPIPE; } - if (xrun_debug(substream, XRUN_DEBUG_PERIODUPDATE)) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " - "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", - name, (unsigned int)pos, - (unsigned int)runtime->period_size, - (unsigned int)runtime->buffer_size, - (unsigned long)old_hw_ptr, - (unsigned long)runtime->hw_ptr_base, - (unsigned long)runtime->hw_ptr_interrupt); + if (pos >= runtime->buffer_size) { + if (printk_ratelimit()) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + xrun_log_show(substream); + snd_printd(KERN_ERR "BUG: %s, pos = %ld, " + "buffer size = %ld, period size = %ld\n", + name, pos, runtime->buffer_size, + runtime->period_size); + } + pos = 0; } + pos -= pos % runtime->min_align; + if (xrun_debug(substream, XRUN_DEBUG_LOG)) + xrun_log(substream, pos); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; - hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; - delta = new_hw_ptr - hw_ptr_interrupt; - if (hw_ptr_interrupt >= runtime->boundary) { - hw_ptr_interrupt -= runtime->boundary; - if (hw_base < runtime->boundary / 2) - /* hw_base was already lapped; recalc delta */ - delta = new_hw_ptr - hw_ptr_interrupt; - } - if (delta < 0) { - if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) - delta += runtime->buffer_size; - if (delta < 0) { - xrun_log_show(substream); - hw_ptr_error(substream, - "Unexpected hw_pointer value " - "(stream=%i, pos=%ld, intr_ptr=%ld)\n", - substream->stream, (long)pos, - (long)hw_ptr_interrupt); -#if 1 - /* simply skipping the hwptr update seems more - * robust in some cases, e.g. on VMware with - * inaccurate timer source - */ - return 0; /* skip this update */ -#else - /* rebase to interrupt position */ - hw_base = new_hw_ptr = hw_ptr_interrupt; - /* align hw_base to buffer_size */ - hw_base -= hw_base % runtime->buffer_size; - delta = 0; -#endif - } else { + if (in_interrupt) { + /* we know that one period was processed */ + /* delta = "expected next hw_ptr" for in_interrupt != 0 */ + delta = old_hw_ptr - (old_hw_ptr % runtime->period_size) + + runtime->period_size; + if (delta > new_hw_ptr) { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) hw_base = 0; new_hw_ptr = hw_base + pos; + goto __delta; } } + /* new_hw_ptr might be lower than old_hw_ptr in case when */ + /* pointer crosses the end of the ring buffer */ + if (new_hw_ptr < old_hw_ptr) { + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + } + __delta: + delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary; + if (xrun_debug(substream, in_interrupt ? + XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd("%s_update: %s: pos=%u/%u/%u, " + "hwptr=%ld/%ld/%ld/%ld\n", + in_interrupt ? "period" : "hwptr", + name, + (unsigned int)pos, + (unsigned int)runtime->period_size, + (unsigned int)runtime->buffer_size, + (unsigned long)delta, + (unsigned long)old_hw_ptr, + (unsigned long)new_hw_ptr, + (unsigned long)runtime->hw_ptr_base); + } + /* something must be really wrong */ + if (delta >= runtime->buffer_size) { + hw_ptr_error(substream, + "Unexpected hw_pointer value %s" + "(stream=%i, pos=%ld, new_hw_ptr=%ld, " + "old_hw_ptr=%ld)\n", + in_interrupt ? "[Q] " : "[P]", + substream->stream, (long)pos, + (long)new_hw_ptr, (long)old_hw_ptr); + return 0; + } /* Do jiffies check only in xrun_debug mode */ if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) @@ -396,7 +383,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) */ if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) goto no_jiffies_check; - hdelta = new_hw_ptr - old_hw_ptr; + hdelta = delta; if (hdelta < runtime->delay) goto no_jiffies_check; hdelta -= runtime->delay; @@ -405,45 +392,49 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) delta = jdelta / (((runtime->period_size * HZ) / runtime->rate) + HZ/100); - xrun_log_show(substream); + /* move new_hw_ptr according jiffies not pos variable */ + new_hw_ptr = old_hw_ptr; + /* use loop to avoid checks for delta overflows */ + /* the delta value is small or zero in most cases */ + while (delta > 0) { + new_hw_ptr += runtime->period_size; + if (new_hw_ptr >= runtime->boundary) + new_hw_ptr -= runtime->boundary; + delta--; + } + /* align hw_base to buffer_size */ + hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); + delta = 0; hw_ptr_error(substream, - "hw_ptr skipping! [Q] " + "hw_ptr skipping! %s" "(pos=%ld, delta=%ld, period=%ld, " - "jdelta=%lu/%lu/%lu)\n", + "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", + in_interrupt ? "[Q] " : "", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, - ((hdelta * HZ) / runtime->rate), delta); - hw_ptr_interrupt = runtime->hw_ptr_interrupt + - runtime->period_size * delta; - if (hw_ptr_interrupt >= runtime->boundary) - hw_ptr_interrupt -= runtime->boundary; - /* rebase to interrupt position */ - hw_base = new_hw_ptr = hw_ptr_interrupt; - /* align hw_base to buffer_size */ - hw_base -= hw_base % runtime->buffer_size; - delta = 0; + ((hdelta * HZ) / runtime->rate), delta, + (unsigned long)old_hw_ptr, + (unsigned long)new_hw_ptr); } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { - xrun_log_show(substream); hw_ptr_error(substream, - "Lost interrupts? " - "(stream=%i, delta=%ld, intr_ptr=%ld)\n", + "Lost interrupts? %s" + "(stream=%i, delta=%ld, new_hw_ptr=%ld, " + "old_hw_ptr=%ld)\n", + in_interrupt ? "[Q] " : "", substream->stream, (long)delta, - (long)hw_ptr_interrupt); - /* rebase hw_ptr_interrupt */ - hw_ptr_interrupt = - new_hw_ptr - new_hw_ptr % runtime->period_size; + (long)new_hw_ptr, + (long)old_hw_ptr); } - runtime->hw_ptr_interrupt = hw_ptr_interrupt; + + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); - if (runtime->status->hw_ptr == new_hw_ptr) - return 0; - runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; @@ -456,83 +447,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) /* CAUTION: call it with irq disabled */ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; - snd_pcm_sframes_t delta; - unsigned long jdelta; - - old_hw_ptr = runtime->status->hw_ptr; - pos = snd_pcm_update_hw_ptr_pos(substream, runtime); - if (pos == SNDRV_PCM_POS_XRUN) { - xrun(substream); - return -EPIPE; - } - if (xrun_debug(substream, XRUN_DEBUG_HWPTRUPDATE)) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " - "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", - name, (unsigned int)pos, - (unsigned int)runtime->period_size, - (unsigned int)runtime->buffer_size, - (unsigned long)old_hw_ptr, - (unsigned long)runtime->hw_ptr_base, - (unsigned long)runtime->hw_ptr_interrupt); - } - - hw_base = runtime->hw_ptr_base; - new_hw_ptr = hw_base + pos; - - delta = new_hw_ptr - old_hw_ptr; - jdelta = jiffies - runtime->hw_ptr_jiffies; - if (delta < 0) { - delta += runtime->buffer_size; - if (delta < 0) { - xrun_log_show(substream); - hw_ptr_error(substream, - "Unexpected hw_pointer value [2] " - "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", - substream->stream, (long)pos, - (long)old_hw_ptr, jdelta); - return 0; - } - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - } - /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) - goto no_jiffies_check; - if (delta < runtime->delay) - goto no_jiffies_check; - delta -= runtime->delay; - if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { - xrun_log_show(substream); - hw_ptr_error(substream, - "hw_ptr skipping! " - "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", - (long)pos, (long)delta, - (long)runtime->period_size, jdelta, - ((delta * HZ) / runtime->rate)); - return 0; - } - no_jiffies_check: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - runtime->silence_size > 0) - snd_pcm_playback_silence(substream, new_hw_ptr); - - if (runtime->status->hw_ptr == new_hw_ptr) - return 0; - - runtime->hw_ptr_base = hw_base; - runtime->status->hw_ptr = new_hw_ptr; - runtime->hw_ptr_jiffies = jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - - return snd_pcm_update_hw_ptr_post(substream, runtime); + return snd_pcm_update_hw_ptr0(substream, 0); } /** @@ -1744,7 +1659,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) snd_pcm_stream_lock_irqsave(substream, flags); if (!snd_pcm_running(substream) || - snd_pcm_update_hw_ptr_interrupt(substream) < 0) + snd_pcm_update_hw_ptr0(substream, 1) < 0) goto _end; if (substream->timer_running) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 29ab46a12e11..8e777f71717c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1247,8 +1247,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) if (err < 0) return err; runtime->hw_ptr_base = 0; - runtime->hw_ptr_interrupt = runtime->status->hw_ptr - - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; return 0; -- GitLab From 1250932e48d3b698415b1f04775433cf1da688d6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 7 Jan 2010 15:36:31 +0100 Subject: [PATCH 0430/3892] ALSA: pcm_lib - optimize wake_up() calls for PCM I/O As noted by pl bossart , the PCM I/O routines (snd_pcm_lib_write1, snd_pcm_lib_read1) should block wake_up() calls until all samples are not processed. Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 3 +++ sound/core/pcm_lib.c | 30 ++++++++++++++++++++---------- sound/core/pcm_native.c | 6 ++++-- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index fe1b131842be..e26fb3c58037 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -311,6 +311,7 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ + unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ wait_queue_head_t sleep; struct fasync_struct *fasync; @@ -839,6 +840,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 70a4f7428d78..a63226232ef4 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -263,8 +263,8 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #endif -static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) { snd_pcm_uframes_t avail; @@ -285,7 +285,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, return -EPIPE; } } - if (avail >= runtime->control->avail_min) + if (!runtime->nowake && avail >= runtime->control->avail_min) wake_up(&runtime->sleep); return 0; } @@ -441,7 +441,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - return snd_pcm_update_hw_ptr_post(substream, runtime); + return snd_pcm_update_state(substream, runtime); } /* CAUTION: call it with irq disabled */ @@ -1792,6 +1792,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1813,15 +1814,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) - goto _end; + err = transfer(substream, appl_ofs, data, offset, frames); snd_pcm_stream_lock_irq(substream); + if (err < 0) + goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -1850,8 +1853,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } } _end_unlock: + runtime->nowake = 0; + if (xfer > 0 && err >= 0) + snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); - _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } @@ -2009,6 +2014,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2037,15 +2043,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) - goto _end; + err = transfer(substream, appl_ofs, data, offset, frames); snd_pcm_stream_lock_irq(substream); + if (err < 0) + goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2068,8 +2076,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, xfer += frames; } _end_unlock: + runtime->nowake = 0; + if (xfer > 0 && err >= 0) + snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); - _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8e777f71717c..27284f628361 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -516,6 +516,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, struct snd_pcm_sw_params *params) { struct snd_pcm_runtime *runtime; + int err; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; @@ -540,6 +541,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (params->silence_threshold > runtime->buffer_size) return -EINVAL; } + err = 0; snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; runtime->period_step = params->period_step; @@ -553,10 +555,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - wake_up(&runtime->sleep); + err = snd_pcm_update_state(substream, runtime); } snd_pcm_stream_unlock_irq(substream); - return 0; + return err; } static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, -- GitLab From 1a3b1d89eded68d64e5ea409ad37827310059441 Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Thu, 7 Jan 2010 11:53:33 -0500 Subject: [PATCH 0431/3892] x86: Split atomic64_t functions into seperate headers Split atomic64_t functions out into separate headers, since they will not be practical to merge between 32 and 64 bits. Signed-off-by: Brian Gerst LKML-Reference: <1262883215-4034-2-git-send-email-brgerst@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/atomic64_32.h | 160 +++++++++++++++++++++ arch/x86/include/asm/atomic64_64.h | 224 +++++++++++++++++++++++++++++ arch/x86/include/asm/atomic_32.h | 152 +------------------- arch/x86/include/asm/atomic_64.h | 217 +--------------------------- 4 files changed, 386 insertions(+), 367 deletions(-) create mode 100644 arch/x86/include/asm/atomic64_32.h create mode 100644 arch/x86/include/asm/atomic64_64.h diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h new file mode 100644 index 000000000000..03027bf28de5 --- /dev/null +++ b/arch/x86/include/asm/atomic64_32.h @@ -0,0 +1,160 @@ +#ifndef _ASM_X86_ATOMIC64_32_H +#define _ASM_X86_ATOMIC64_32_H + +#include +#include +#include +//#include + +/* An 64bit atomic type */ + +typedef struct { + u64 __aligned(8) counter; +} atomic64_t; + +#define ATOMIC64_INIT(val) { (val) } + +extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val); + +/** + * atomic64_xchg - xchg atomic64 variable + * @ptr: pointer to type atomic64_t + * @new_val: value to assign + * + * Atomically xchgs the value of @ptr to @new_val and returns + * the old value. + */ +extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val); + +/** + * atomic64_set - set atomic64 variable + * @ptr: pointer to type atomic64_t + * @new_val: value to assign + * + * Atomically sets the value of @ptr to @new_val. + */ +extern void atomic64_set(atomic64_t *ptr, u64 new_val); + +/** + * atomic64_read - read atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically reads the value of @ptr and returns it. + */ +static inline u64 atomic64_read(atomic64_t *ptr) +{ + u64 res; + + /* + * Note, we inline this atomic64_t primitive because + * it only clobbers EAX/EDX and leaves the others + * untouched. We also (somewhat subtly) rely on the + * fact that cmpxchg8b returns the current 64-bit value + * of the memory location we are touching: + */ + asm volatile( + "mov %%ebx, %%eax\n\t" + "mov %%ecx, %%edx\n\t" + LOCK_PREFIX "cmpxchg8b %1\n" + : "=&A" (res) + : "m" (*ptr) + ); + + return res; +} + +extern u64 atomic64_read(atomic64_t *ptr); + +/** + * atomic64_add_return - add and return + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns @delta + *@ptr + */ +extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr); + +/* + * Other variants with different arithmetic operators: + */ +extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr); +extern u64 atomic64_inc_return(atomic64_t *ptr); +extern u64 atomic64_dec_return(atomic64_t *ptr); + +/** + * atomic64_add - add integer to atomic64 variable + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr. + */ +extern void atomic64_add(u64 delta, atomic64_t *ptr); + +/** + * atomic64_sub - subtract the atomic64 variable + * @delta: integer value to subtract + * @ptr: pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr. + */ +extern void atomic64_sub(u64 delta, atomic64_t *ptr); + +/** + * atomic64_sub_and_test - subtract value from variable and test result + * @delta: integer value to subtract + * @ptr: pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr and returns + * true if the result is zero, or false for all + * other cases. + */ +extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr); + +/** + * atomic64_inc - increment atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1. + */ +extern void atomic64_inc(atomic64_t *ptr); + +/** + * atomic64_dec - decrement atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1. + */ +extern void atomic64_dec(atomic64_t *ptr); + +/** + * atomic64_dec_and_test - decrement and test + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +extern int atomic64_dec_and_test(atomic64_t *ptr); + +/** + * atomic64_inc_and_test - increment and test + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +extern int atomic64_inc_and_test(atomic64_t *ptr); + +/** + * atomic64_add_negative - add and test if negative + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +extern int atomic64_add_negative(u64 delta, atomic64_t *ptr); + +#endif /* _ASM_X86_ATOMIC64_32_H */ diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h new file mode 100644 index 000000000000..51c5b4056929 --- /dev/null +++ b/arch/x86/include/asm/atomic64_64.h @@ -0,0 +1,224 @@ +#ifndef _ASM_X86_ATOMIC64_64_H +#define _ASM_X86_ATOMIC64_64_H + +#include +#include +#include + +/* The 64-bit atomic type */ + +#define ATOMIC64_INIT(i) { (i) } + +/** + * atomic64_read - read atomic64 variable + * @v: pointer of type atomic64_t + * + * Atomically reads the value of @v. + * Doesn't imply a read memory barrier. + */ +static inline long atomic64_read(const atomic64_t *v) +{ + return v->counter; +} + +/** + * atomic64_set - set atomic64 variable + * @v: pointer to type atomic64_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic64_set(atomic64_t *v, long i) +{ + v->counter = i; +} + +/** + * atomic64_add - add integer to atomic64 variable + * @i: integer value to add + * @v: pointer to type atomic64_t + * + * Atomically adds @i to @v. + */ +static inline void atomic64_add(long i, atomic64_t *v) +{ + asm volatile(LOCK_PREFIX "addq %1,%0" + : "=m" (v->counter) + : "er" (i), "m" (v->counter)); +} + +/** + * atomic64_sub - subtract the atomic64 variable + * @i: integer value to subtract + * @v: pointer to type atomic64_t + * + * Atomically subtracts @i from @v. + */ +static inline void atomic64_sub(long i, atomic64_t *v) +{ + asm volatile(LOCK_PREFIX "subq %1,%0" + : "=m" (v->counter) + : "er" (i), "m" (v->counter)); +} + +/** + * atomic64_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer to type atomic64_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic64_sub_and_test(long i, atomic64_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "subq %2,%0; sete %1" + : "=m" (v->counter), "=qm" (c) + : "er" (i), "m" (v->counter) : "memory"); + return c; +} + +/** + * atomic64_inc - increment atomic64 variable + * @v: pointer to type atomic64_t + * + * Atomically increments @v by 1. + */ +static inline void atomic64_inc(atomic64_t *v) +{ + asm volatile(LOCK_PREFIX "incq %0" + : "=m" (v->counter) + : "m" (v->counter)); +} + +/** + * atomic64_dec - decrement atomic64 variable + * @v: pointer to type atomic64_t + * + * Atomically decrements @v by 1. + */ +static inline void atomic64_dec(atomic64_t *v) +{ + asm volatile(LOCK_PREFIX "decq %0" + : "=m" (v->counter) + : "m" (v->counter)); +} + +/** + * atomic64_dec_and_test - decrement and test + * @v: pointer to type atomic64_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic64_dec_and_test(atomic64_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "decq %0; sete %1" + : "=m" (v->counter), "=qm" (c) + : "m" (v->counter) : "memory"); + return c != 0; +} + +/** + * atomic64_inc_and_test - increment and test + * @v: pointer to type atomic64_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic64_inc_and_test(atomic64_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "incq %0; sete %1" + : "=m" (v->counter), "=qm" (c) + : "m" (v->counter) : "memory"); + return c != 0; +} + +/** + * atomic64_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer to type atomic64_t + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic64_add_negative(long i, atomic64_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "addq %2,%0; sets %1" + : "=m" (v->counter), "=qm" (c) + : "er" (i), "m" (v->counter) : "memory"); + return c; +} + +/** + * atomic64_add_return - add and return + * @i: integer value to add + * @v: pointer to type atomic64_t + * + * Atomically adds @i to @v and returns @i + @v + */ +static inline long atomic64_add_return(long i, atomic64_t *v) +{ + long __i = i; + asm volatile(LOCK_PREFIX "xaddq %0, %1;" + : "+r" (i), "+m" (v->counter) + : : "memory"); + return i + __i; +} + +static inline long atomic64_sub_return(long i, atomic64_t *v) +{ + return atomic64_add_return(-i, v); +} + +#define atomic64_inc_return(v) (atomic64_add_return(1, (v))) +#define atomic64_dec_return(v) (atomic64_sub_return(1, (v))) + +static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) +{ + return cmpxchg(&v->counter, old, new); +} + +static inline long atomic64_xchg(atomic64_t *v, long new) +{ + return xchg(&v->counter, new); +} + +/** + * atomic64_add_unless - add unless the number is a given value + * @v: pointer of type atomic64_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * Atomically adds @a to @v, so long as it was not @u. + * Returns non-zero if @v was not @u, and zero otherwise. + */ +static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +{ + long c, old; + c = atomic64_read(v); + for (;;) { + if (unlikely(c == (u))) + break; + old = atomic64_cmpxchg((v), c, c + (a)); + if (likely(old == c)) + break; + c = old; + } + return c != (u); +} + +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) + +#endif /* _ASM_X86_ATOMIC64_64_H */ diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h index dc5a667ff791..e128ae988cc9 100644 --- a/arch/x86/include/asm/atomic_32.h +++ b/arch/x86/include/asm/atomic_32.h @@ -260,156 +260,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -/* An 64bit atomic type */ - -typedef struct { - u64 __aligned(8) counter; -} atomic64_t; - -#define ATOMIC64_INIT(val) { (val) } - -extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val); - -/** - * atomic64_xchg - xchg atomic64 variable - * @ptr: pointer to type atomic64_t - * @new_val: value to assign - * - * Atomically xchgs the value of @ptr to @new_val and returns - * the old value. - */ -extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val); - -/** - * atomic64_set - set atomic64 variable - * @ptr: pointer to type atomic64_t - * @new_val: value to assign - * - * Atomically sets the value of @ptr to @new_val. - */ -extern void atomic64_set(atomic64_t *ptr, u64 new_val); - -/** - * atomic64_read - read atomic64 variable - * @ptr: pointer to type atomic64_t - * - * Atomically reads the value of @ptr and returns it. - */ -static inline u64 atomic64_read(atomic64_t *ptr) -{ - u64 res; - - /* - * Note, we inline this atomic64_t primitive because - * it only clobbers EAX/EDX and leaves the others - * untouched. We also (somewhat subtly) rely on the - * fact that cmpxchg8b returns the current 64-bit value - * of the memory location we are touching: - */ - asm volatile( - "mov %%ebx, %%eax\n\t" - "mov %%ecx, %%edx\n\t" - LOCK_PREFIX "cmpxchg8b %1\n" - : "=&A" (res) - : "m" (*ptr) - ); - - return res; -} - -extern u64 atomic64_read(atomic64_t *ptr); - -/** - * atomic64_add_return - add and return - * @delta: integer value to add - * @ptr: pointer to type atomic64_t - * - * Atomically adds @delta to @ptr and returns @delta + *@ptr - */ -extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr); - -/* - * Other variants with different arithmetic operators: - */ -extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr); -extern u64 atomic64_inc_return(atomic64_t *ptr); -extern u64 atomic64_dec_return(atomic64_t *ptr); - -/** - * atomic64_add - add integer to atomic64 variable - * @delta: integer value to add - * @ptr: pointer to type atomic64_t - * - * Atomically adds @delta to @ptr. - */ -extern void atomic64_add(u64 delta, atomic64_t *ptr); - -/** - * atomic64_sub - subtract the atomic64 variable - * @delta: integer value to subtract - * @ptr: pointer to type atomic64_t - * - * Atomically subtracts @delta from @ptr. - */ -extern void atomic64_sub(u64 delta, atomic64_t *ptr); - -/** - * atomic64_sub_and_test - subtract value from variable and test result - * @delta: integer value to subtract - * @ptr: pointer to type atomic64_t - * - * Atomically subtracts @delta from @ptr and returns - * true if the result is zero, or false for all - * other cases. - */ -extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr); - -/** - * atomic64_inc - increment atomic64 variable - * @ptr: pointer to type atomic64_t - * - * Atomically increments @ptr by 1. - */ -extern void atomic64_inc(atomic64_t *ptr); - -/** - * atomic64_dec - decrement atomic64 variable - * @ptr: pointer to type atomic64_t - * - * Atomically decrements @ptr by 1. - */ -extern void atomic64_dec(atomic64_t *ptr); - -/** - * atomic64_dec_and_test - decrement and test - * @ptr: pointer to type atomic64_t - * - * Atomically decrements @ptr by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -extern int atomic64_dec_and_test(atomic64_t *ptr); - -/** - * atomic64_inc_and_test - increment and test - * @ptr: pointer to type atomic64_t - * - * Atomically increments @ptr by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -extern int atomic64_inc_and_test(atomic64_t *ptr); - -/** - * atomic64_add_negative - add and test if negative - * @delta: integer value to add - * @ptr: pointer to type atomic64_t - * - * Atomically adds @delta to @ptr and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -extern int atomic64_add_negative(u64 delta, atomic64_t *ptr); - +#include #include #endif /* _ASM_X86_ATOMIC_32_H */ diff --git a/arch/x86/include/asm/atomic_64.h b/arch/x86/include/asm/atomic_64.h index d605dc268e79..042c33100c69 100644 --- a/arch/x86/include/asm/atomic_64.h +++ b/arch/x86/include/asm/atomic_64.h @@ -187,196 +187,6 @@ static inline int atomic_sub_return(int i, atomic_t *v) #define atomic_inc_return(v) (atomic_add_return(1, v)) #define atomic_dec_return(v) (atomic_sub_return(1, v)) -/* The 64-bit atomic type */ - -#define ATOMIC64_INIT(i) { (i) } - -/** - * atomic64_read - read atomic64 variable - * @v: pointer of type atomic64_t - * - * Atomically reads the value of @v. - * Doesn't imply a read memory barrier. - */ -static inline long atomic64_read(const atomic64_t *v) -{ - return v->counter; -} - -/** - * atomic64_set - set atomic64 variable - * @v: pointer to type atomic64_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic64_set(atomic64_t *v, long i) -{ - v->counter = i; -} - -/** - * atomic64_add - add integer to atomic64 variable - * @i: integer value to add - * @v: pointer to type atomic64_t - * - * Atomically adds @i to @v. - */ -static inline void atomic64_add(long i, atomic64_t *v) -{ - asm volatile(LOCK_PREFIX "addq %1,%0" - : "=m" (v->counter) - : "er" (i), "m" (v->counter)); -} - -/** - * atomic64_sub - subtract the atomic64 variable - * @i: integer value to subtract - * @v: pointer to type atomic64_t - * - * Atomically subtracts @i from @v. - */ -static inline void atomic64_sub(long i, atomic64_t *v) -{ - asm volatile(LOCK_PREFIX "subq %1,%0" - : "=m" (v->counter) - : "er" (i), "m" (v->counter)); -} - -/** - * atomic64_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer to type atomic64_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static inline int atomic64_sub_and_test(long i, atomic64_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "subq %2,%0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "er" (i), "m" (v->counter) : "memory"); - return c; -} - -/** - * atomic64_inc - increment atomic64 variable - * @v: pointer to type atomic64_t - * - * Atomically increments @v by 1. - */ -static inline void atomic64_inc(atomic64_t *v) -{ - asm volatile(LOCK_PREFIX "incq %0" - : "=m" (v->counter) - : "m" (v->counter)); -} - -/** - * atomic64_dec - decrement atomic64 variable - * @v: pointer to type atomic64_t - * - * Atomically decrements @v by 1. - */ -static inline void atomic64_dec(atomic64_t *v) -{ - asm volatile(LOCK_PREFIX "decq %0" - : "=m" (v->counter) - : "m" (v->counter)); -} - -/** - * atomic64_dec_and_test - decrement and test - * @v: pointer to type atomic64_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static inline int atomic64_dec_and_test(atomic64_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "decq %0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "m" (v->counter) : "memory"); - return c != 0; -} - -/** - * atomic64_inc_and_test - increment and test - * @v: pointer to type atomic64_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static inline int atomic64_inc_and_test(atomic64_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "incq %0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "m" (v->counter) : "memory"); - return c != 0; -} - -/** - * atomic64_add_negative - add and test if negative - * @i: integer value to add - * @v: pointer to type atomic64_t - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static inline int atomic64_add_negative(long i, atomic64_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "addq %2,%0; sets %1" - : "=m" (v->counter), "=qm" (c) - : "er" (i), "m" (v->counter) : "memory"); - return c; -} - -/** - * atomic64_add_return - add and return - * @i: integer value to add - * @v: pointer to type atomic64_t - * - * Atomically adds @i to @v and returns @i + @v - */ -static inline long atomic64_add_return(long i, atomic64_t *v) -{ - long __i = i; - asm volatile(LOCK_PREFIX "xaddq %0, %1;" - : "+r" (i), "+m" (v->counter) - : : "memory"); - return i + __i; -} - -static inline long atomic64_sub_return(long i, atomic64_t *v) -{ - return atomic64_add_return(-i, v); -} - -#define atomic64_inc_return(v) (atomic64_add_return(1, (v))) -#define atomic64_dec_return(v) (atomic64_sub_return(1, (v))) - -static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) -{ - return cmpxchg(&v->counter, old, new); -} - -static inline long atomic64_xchg(atomic64_t *v, long new) -{ - return xchg(&v->counter, new); -} - static inline long atomic_cmpxchg(atomic_t *v, int old, int new) { return cmpxchg(&v->counter, old, new); @@ -413,30 +223,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -/** - * atomic64_add_unless - add unless the number is a given value - * @v: pointer of type atomic64_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) -{ - long c, old; - c = atomic64_read(v); - for (;;) { - if (unlikely(c == (u))) - break; - old = atomic64_cmpxchg((v), c, c + (a)); - if (likely(old == c)) - break; - c = old; - } - return c != (u); -} - /** * atomic_inc_short - increment of a short integer * @v: pointer to type int @@ -463,8 +249,6 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2) asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); } -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) - /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ asm volatile(LOCK_PREFIX "andl %0,%1" \ @@ -481,5 +265,6 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() +#include #include #endif /* _ASM_X86_ATOMIC_64_H */ -- GitLab From 3ce59bb8352e1c53446bef1ead1c63956dfef64a Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Thu, 7 Jan 2010 11:53:34 -0500 Subject: [PATCH 0432/3892] x86: Sync asm/atomic_32.h and asm/atomic_64.h Prepare for merging into asm/atomic.h. Signed-off-by: Brian Gerst LKML-Reference: <1262883215-4034-3-git-send-email-brgerst@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/atomic_32.h | 42 ++++++++++++++--- arch/x86/include/asm/atomic_64.h | 81 +++++++++++++++++++++----------- 2 files changed, 89 insertions(+), 34 deletions(-) diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h index e128ae988cc9..036962ef8203 100644 --- a/arch/x86/include/asm/atomic_32.h +++ b/arch/x86/include/asm/atomic_32.h @@ -4,6 +4,7 @@ #include #include #include +#include #include /* @@ -145,8 +146,8 @@ static inline int atomic_inc_and_test(atomic_t *v) /** * atomic_add_negative - add and test if negative - * @v: pointer of type atomic_t * @i: integer value to add + * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns true * if the result is negative, or false when @@ -164,8 +165,8 @@ static inline int atomic_add_negative(int i, atomic_t *v) /** * atomic_add_return - add integer and return - * @v: pointer of type atomic_t * @i: integer value to add + * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns @i + @v */ @@ -206,6 +207,9 @@ static inline int atomic_sub_return(int i, atomic_t *v) return atomic_add_return(-i, v); } +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) + static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { return cmpxchg(&v->counter, old, new); @@ -242,8 +246,33 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#define atomic_inc_return(v) (atomic_add_return(1, v)) -#define atomic_dec_return(v) (atomic_sub_return(1, v)) +/** + * atomic_inc_short - increment of a short integer + * @v: pointer to type int + * + * Atomically adds 1 to @v + * Returns the new value of @u + */ +static inline short int atomic_inc_short(short int *v) +{ + asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); + return *v; +} + +#ifdef CONFIG_X86_64 +/** + * atomic_or_long - OR of two long integers + * @v1: pointer to type unsigned long + * @v2: pointer to type unsigned long + * + * Atomically ORs @v1 and @v2 + * Returns the result of the OR + */ +static inline void atomic_or_long(unsigned long *v1, unsigned long v2) +{ + asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); +} +#endif /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ @@ -251,8 +280,9 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) : : "r" (~(mask)), "m" (*(addr)) : "memory") #define atomic_set_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "orl %0,%1" \ - : : "r" (mask), "m" (*(addr)) : "memory") + asm volatile(LOCK_PREFIX "orl %0,%1" \ + : : "r" ((unsigned)(mask)), "m" (*(addr)) \ + : "memory") /* Atomic operations are already serializing on x86 */ #define smp_mb__before_atomic_dec() barrier() diff --git a/arch/x86/include/asm/atomic_64.h b/arch/x86/include/asm/atomic_64.h index 042c33100c69..77407887cfcd 100644 --- a/arch/x86/include/asm/atomic_64.h +++ b/arch/x86/include/asm/atomic_64.h @@ -1,7 +1,9 @@ #ifndef _ASM_X86_ATOMIC_64_H #define _ASM_X86_ATOMIC_64_H +#include #include +#include #include #include @@ -45,12 +47,12 @@ static inline void atomic_set(atomic_t *v, int i) static inline void atomic_add(int i, atomic_t *v) { asm volatile(LOCK_PREFIX "addl %1,%0" - : "=m" (v->counter) - : "ir" (i), "m" (v->counter)); + : "+m" (v->counter) + : "ir" (i)); } /** - * atomic_sub - subtract the atomic variable + * atomic_sub - subtract integer from atomic variable * @i: integer value to subtract * @v: pointer of type atomic_t * @@ -59,8 +61,8 @@ static inline void atomic_add(int i, atomic_t *v) static inline void atomic_sub(int i, atomic_t *v) { asm volatile(LOCK_PREFIX "subl %1,%0" - : "=m" (v->counter) - : "ir" (i), "m" (v->counter)); + : "+m" (v->counter) + : "ir" (i)); } /** @@ -77,8 +79,8 @@ static inline int atomic_sub_and_test(int i, atomic_t *v) unsigned char c; asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "ir" (i), "m" (v->counter) : "memory"); + : "+m" (v->counter), "=qm" (c) + : "ir" (i) : "memory"); return c; } @@ -91,8 +93,7 @@ static inline int atomic_sub_and_test(int i, atomic_t *v) static inline void atomic_inc(atomic_t *v) { asm volatile(LOCK_PREFIX "incl %0" - : "=m" (v->counter) - : "m" (v->counter)); + : "+m" (v->counter)); } /** @@ -104,8 +105,7 @@ static inline void atomic_inc(atomic_t *v) static inline void atomic_dec(atomic_t *v) { asm volatile(LOCK_PREFIX "decl %0" - : "=m" (v->counter) - : "m" (v->counter)); + : "+m" (v->counter)); } /** @@ -121,8 +121,8 @@ static inline int atomic_dec_and_test(atomic_t *v) unsigned char c; asm volatile(LOCK_PREFIX "decl %0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "m" (v->counter) : "memory"); + : "+m" (v->counter), "=qm" (c) + : : "memory"); return c != 0; } @@ -139,8 +139,8 @@ static inline int atomic_inc_and_test(atomic_t *v) unsigned char c; asm volatile(LOCK_PREFIX "incl %0; sete %1" - : "=m" (v->counter), "=qm" (c) - : "m" (v->counter) : "memory"); + : "+m" (v->counter), "=qm" (c) + : : "memory"); return c != 0; } @@ -158,13 +158,13 @@ static inline int atomic_add_negative(int i, atomic_t *v) unsigned char c; asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" - : "=m" (v->counter), "=qm" (c) - : "ir" (i), "m" (v->counter) : "memory"); + : "+m" (v->counter), "=qm" (c) + : "ir" (i) : "memory"); return c; } /** - * atomic_add_return - add and return + * atomic_add_return - add integer and return * @i: integer value to add * @v: pointer of type atomic_t * @@ -172,13 +172,36 @@ static inline int atomic_add_negative(int i, atomic_t *v) */ static inline int atomic_add_return(int i, atomic_t *v) { - int __i = i; + int __i; +#ifdef CONFIG_M386 + unsigned long flags; + if (unlikely(boot_cpu_data.x86 <= 3)) + goto no_xadd; +#endif + /* Modern 486+ processor */ + __i = i; asm volatile(LOCK_PREFIX "xaddl %0, %1" : "+r" (i), "+m" (v->counter) : : "memory"); return i + __i; + +#ifdef CONFIG_M386 +no_xadd: /* Legacy 386 processor */ + local_irq_save(flags); + __i = atomic_read(v); + atomic_set(v, i + __i); + local_irq_restore(flags); + return i + __i; +#endif } +/** + * atomic_sub_return - subtract integer and return + * @v: pointer of type atomic_t + * @i: integer value to subtract + * + * Atomically subtracts @i from @v and returns @v - @i + */ static inline int atomic_sub_return(int i, atomic_t *v) { return atomic_add_return(-i, v); @@ -187,23 +210,23 @@ static inline int atomic_sub_return(int i, atomic_t *v) #define atomic_inc_return(v) (atomic_add_return(1, v)) #define atomic_dec_return(v) (atomic_sub_return(1, v)) -static inline long atomic_cmpxchg(atomic_t *v, int old, int new) +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { return cmpxchg(&v->counter, old, new); } -static inline long atomic_xchg(atomic_t *v, int new) +static inline int atomic_xchg(atomic_t *v, int new) { return xchg(&v->counter, new); } /** - * atomic_add_unless - add unless the number is a given value + * atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t * @a: the amount to add to v... * @u: ...unless v is equal to u. * - * Atomically adds @a to @v, so long as it was not @u. + * Atomically adds @a to @v, so long as @v was not already @u. * Returns non-zero if @v was not @u, and zero otherwise. */ static inline int atomic_add_unless(atomic_t *v, int a, int u) @@ -236,6 +259,7 @@ static inline short int atomic_inc_short(short int *v) return *v; } +#ifdef CONFIG_X86_64 /** * atomic_or_long - OR of two long integers * @v1: pointer to type unsigned long @@ -248,15 +272,16 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2) { asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); } +#endif /* These are x86-specific, used by some header files */ -#define atomic_clear_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "andl %0,%1" \ +#define atomic_clear_mask(mask, addr) \ + asm volatile(LOCK_PREFIX "andl %0,%1" \ : : "r" (~(mask)), "m" (*(addr)) : "memory") -#define atomic_set_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "orl %0,%1" \ - : : "r" ((unsigned)(mask)), "m" (*(addr)) \ +#define atomic_set_mask(mask, addr) \ + asm volatile(LOCK_PREFIX "orl %0,%1" \ + : : "r" ((unsigned)(mask)), "m" (*(addr)) \ : "memory") /* Atomic operations are already serializing on x86 */ -- GitLab From 5abbbbf0b0cd4abf5898136d0c345dc99b859c8c Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Thu, 7 Jan 2010 11:53:35 -0500 Subject: [PATCH 0433/3892] x86: Merge asm/atomic_{32,64}.h Merge the now identical code from asm/atomic_32.h and asm/atomic_64.h into asm/atomic.h. Signed-off-by: Brian Gerst LKML-Reference: <1262883215-4034-4-git-send-email-brgerst@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/atomic.h | 299 ++++++++++++++++++++++++++++++- arch/x86/include/asm/atomic_32.h | 295 ------------------------------ arch/x86/include/asm/atomic_64.h | 295 ------------------------------ 3 files changed, 297 insertions(+), 592 deletions(-) delete mode 100644 arch/x86/include/asm/atomic_32.h delete mode 100644 arch/x86/include/asm/atomic_64.h diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 4e1b8873c474..8baaa719fa7f 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -1,5 +1,300 @@ +#ifndef _ASM_X86_ATOMIC_H +#define _ASM_X86_ATOMIC_H + +#include +#include +#include +#include +#include + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +#define ATOMIC_INIT(i) { (i) } + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const atomic_t *v) +{ + return v->counter; +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(atomic_t *v, int i) +{ + v->counter = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, atomic_t *v) +{ + asm volatile(LOCK_PREFIX "addl %1,%0" + : "+m" (v->counter) + : "ir" (i)); +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, atomic_t *v) +{ + asm volatile(LOCK_PREFIX "subl %1,%0" + : "+m" (v->counter) + : "ir" (i)); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, atomic_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" + : "+m" (v->counter), "=qm" (c) + : "ir" (i) : "memory"); + return c; +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(atomic_t *v) +{ + asm volatile(LOCK_PREFIX "incl %0" + : "+m" (v->counter)); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(atomic_t *v) +{ + asm volatile(LOCK_PREFIX "decl %0" + : "+m" (v->counter)); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(atomic_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "decl %0; sete %1" + : "+m" (v->counter), "=qm" (c) + : : "memory"); + return c != 0; +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(atomic_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "incl %0; sete %1" + : "+m" (v->counter), "=qm" (c) + : : "memory"); + return c != 0; +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, atomic_t *v) +{ + unsigned char c; + + asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" + : "+m" (v->counter), "=qm" (c) + : "ir" (i) : "memory"); + return c; +} + +/** + * atomic_add_return - add integer and return + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v and returns @i + @v + */ +static inline int atomic_add_return(int i, atomic_t *v) +{ + int __i; +#ifdef CONFIG_M386 + unsigned long flags; + if (unlikely(boot_cpu_data.x86 <= 3)) + goto no_xadd; +#endif + /* Modern 486+ processor */ + __i = i; + asm volatile(LOCK_PREFIX "xaddl %0, %1" + : "+r" (i), "+m" (v->counter) + : : "memory"); + return i + __i; + +#ifdef CONFIG_M386 +no_xadd: /* Legacy 386 processor */ + local_irq_save(flags); + __i = atomic_read(v); + atomic_set(v, i + __i); + local_irq_restore(flags); + return i + __i; +#endif +} + +/** + * atomic_sub_return - subtract integer and return + * @v: pointer of type atomic_t + * @i: integer value to subtract + * + * Atomically subtracts @i from @v and returns @v - @i + */ +static inline int atomic_sub_return(int i, atomic_t *v) +{ + return atomic_add_return(-i, v); +} + +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) + +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + return cmpxchg(&v->counter, old, new); +} + +static inline int atomic_xchg(atomic_t *v, int new) +{ + return xchg(&v->counter, new); +} + +/** + * atomic_add_unless - add unless the number is already a given value + * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. + * + * Atomically adds @a to @v, so long as @v was not already @u. + * Returns non-zero if @v was not @u, and zero otherwise. + */ +static inline int atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + c = atomic_read(v); + for (;;) { + if (unlikely(c == (u))) + break; + old = atomic_cmpxchg((v), c, c + (a)); + if (likely(old == c)) + break; + c = old; + } + return c != (u); +} + +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +/** + * atomic_inc_short - increment of a short integer + * @v: pointer to type int + * + * Atomically adds 1 to @v + * Returns the new value of @u + */ +static inline short int atomic_inc_short(short int *v) +{ + asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); + return *v; +} + +#ifdef CONFIG_X86_64 +/** + * atomic_or_long - OR of two long integers + * @v1: pointer to type unsigned long + * @v2: pointer to type unsigned long + * + * Atomically ORs @v1 and @v2 + * Returns the result of the OR + */ +static inline void atomic_or_long(unsigned long *v1, unsigned long v2) +{ + asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); +} +#endif + +/* These are x86-specific, used by some header files */ +#define atomic_clear_mask(mask, addr) \ + asm volatile(LOCK_PREFIX "andl %0,%1" \ + : : "r" (~(mask)), "m" (*(addr)) : "memory") + +#define atomic_set_mask(mask, addr) \ + asm volatile(LOCK_PREFIX "orl %0,%1" \ + : : "r" ((unsigned)(mask)), "m" (*(addr)) \ + : "memory") + +/* Atomic operations are already serializing on x86 */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #ifdef CONFIG_X86_32 -# include "atomic_32.h" +# include "atomic64_32.h" #else -# include "atomic_64.h" +# include "atomic64_64.h" #endif + +#include +#endif /* _ASM_X86_ATOMIC_H */ diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h deleted file mode 100644 index 036962ef8203..000000000000 --- a/arch/x86/include/asm/atomic_32.h +++ /dev/null @@ -1,295 +0,0 @@ -#ifndef _ASM_X86_ATOMIC_32_H -#define _ASM_X86_ATOMIC_32_H - -#include -#include -#include -#include -#include - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - */ - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return v->counter; -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static inline void atomic_add(int i, atomic_t *v) -{ - asm volatile(LOCK_PREFIX "addl %1,%0" - : "+m" (v->counter) - : "ir" (i)); -} - -/** - * atomic_sub - subtract integer from atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static inline void atomic_sub(int i, atomic_t *v) -{ - asm volatile(LOCK_PREFIX "subl %1,%0" - : "+m" (v->counter) - : "ir" (i)); -} - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static inline int atomic_sub_and_test(int i, atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" - : "+m" (v->counter), "=qm" (c) - : "ir" (i) : "memory"); - return c; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - asm volatile(LOCK_PREFIX "incl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static inline void atomic_dec(atomic_t *v) -{ - asm volatile(LOCK_PREFIX "decl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static inline int atomic_dec_and_test(atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "decl %0; sete %1" - : "+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static inline int atomic_inc_and_test(atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "incl %0; sete %1" - : "+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_add_negative - add and test if negative - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static inline int atomic_add_negative(int i, atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" - : "+m" (v->counter), "=qm" (c) - : "ir" (i) : "memory"); - return c; -} - -/** - * atomic_add_return - add integer and return - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns @i + @v - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - int __i; -#ifdef CONFIG_M386 - unsigned long flags; - if (unlikely(boot_cpu_data.x86 <= 3)) - goto no_xadd; -#endif - /* Modern 486+ processor */ - __i = i; - asm volatile(LOCK_PREFIX "xaddl %0, %1" - : "+r" (i), "+m" (v->counter) - : : "memory"); - return i + __i; - -#ifdef CONFIG_M386 -no_xadd: /* Legacy 386 processor */ - local_irq_save(flags); - __i = atomic_read(v); - atomic_set(v, i + __i); - local_irq_restore(flags); - return i + __i; -#endif -} - -/** - * atomic_sub_return - subtract integer and return - * @v: pointer of type atomic_t - * @i: integer value to subtract - * - * Atomically subtracts @i from @v and returns @v - @i - */ -static inline int atomic_sub_return(int i, atomic_t *v) -{ - return atomic_add_return(-i, v); -} - -#define atomic_inc_return(v) (atomic_add_return(1, v)) -#define atomic_dec_return(v) (atomic_sub_return(1, v)) - -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - return cmpxchg(&v->counter, old, new); -} - -static inline int atomic_xchg(atomic_t *v, int new) -{ - return xchg(&v->counter, new); -} - -/** - * atomic_add_unless - add unless the number is already a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as @v was not already @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - c = atomic_read(v); - for (;;) { - if (unlikely(c == (u))) - break; - old = atomic_cmpxchg((v), c, c + (a)); - if (likely(old == c)) - break; - c = old; - } - return c != (u); -} - -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -/** - * atomic_inc_short - increment of a short integer - * @v: pointer to type int - * - * Atomically adds 1 to @v - * Returns the new value of @u - */ -static inline short int atomic_inc_short(short int *v) -{ - asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); - return *v; -} - -#ifdef CONFIG_X86_64 -/** - * atomic_or_long - OR of two long integers - * @v1: pointer to type unsigned long - * @v2: pointer to type unsigned long - * - * Atomically ORs @v1 and @v2 - * Returns the result of the OR - */ -static inline void atomic_or_long(unsigned long *v1, unsigned long v2) -{ - asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); -} -#endif - -/* These are x86-specific, used by some header files */ -#define atomic_clear_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "andl %0,%1" \ - : : "r" (~(mask)), "m" (*(addr)) : "memory") - -#define atomic_set_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "orl %0,%1" \ - : : "r" ((unsigned)(mask)), "m" (*(addr)) \ - : "memory") - -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - -#include -#include -#endif /* _ASM_X86_ATOMIC_32_H */ diff --git a/arch/x86/include/asm/atomic_64.h b/arch/x86/include/asm/atomic_64.h deleted file mode 100644 index 77407887cfcd..000000000000 --- a/arch/x86/include/asm/atomic_64.h +++ /dev/null @@ -1,295 +0,0 @@ -#ifndef _ASM_X86_ATOMIC_64_H -#define _ASM_X86_ATOMIC_64_H - -#include -#include -#include -#include -#include - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - */ - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return v->counter; -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static inline void atomic_add(int i, atomic_t *v) -{ - asm volatile(LOCK_PREFIX "addl %1,%0" - : "+m" (v->counter) - : "ir" (i)); -} - -/** - * atomic_sub - subtract integer from atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static inline void atomic_sub(int i, atomic_t *v) -{ - asm volatile(LOCK_PREFIX "subl %1,%0" - : "+m" (v->counter) - : "ir" (i)); -} - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns - * true if the result is zero, or false for all - * other cases. - */ -static inline int atomic_sub_and_test(int i, atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" - : "+m" (v->counter), "=qm" (c) - : "ir" (i) : "memory"); - return c; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - asm volatile(LOCK_PREFIX "incl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static inline void atomic_dec(atomic_t *v) -{ - asm volatile(LOCK_PREFIX "decl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static inline int atomic_dec_and_test(atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "decl %0; sete %1" - : "+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -static inline int atomic_inc_and_test(atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "incl %0; sete %1" - : "+m" (v->counter), "=qm" (c) - : : "memory"); - return c != 0; -} - -/** - * atomic_add_negative - add and test if negative - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns true - * if the result is negative, or false when - * result is greater than or equal to zero. - */ -static inline int atomic_add_negative(int i, atomic_t *v) -{ - unsigned char c; - - asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" - : "+m" (v->counter), "=qm" (c) - : "ir" (i) : "memory"); - return c; -} - -/** - * atomic_add_return - add integer and return - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns @i + @v - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - int __i; -#ifdef CONFIG_M386 - unsigned long flags; - if (unlikely(boot_cpu_data.x86 <= 3)) - goto no_xadd; -#endif - /* Modern 486+ processor */ - __i = i; - asm volatile(LOCK_PREFIX "xaddl %0, %1" - : "+r" (i), "+m" (v->counter) - : : "memory"); - return i + __i; - -#ifdef CONFIG_M386 -no_xadd: /* Legacy 386 processor */ - local_irq_save(flags); - __i = atomic_read(v); - atomic_set(v, i + __i); - local_irq_restore(flags); - return i + __i; -#endif -} - -/** - * atomic_sub_return - subtract integer and return - * @v: pointer of type atomic_t - * @i: integer value to subtract - * - * Atomically subtracts @i from @v and returns @v - @i - */ -static inline int atomic_sub_return(int i, atomic_t *v) -{ - return atomic_add_return(-i, v); -} - -#define atomic_inc_return(v) (atomic_add_return(1, v)) -#define atomic_dec_return(v) (atomic_sub_return(1, v)) - -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - return cmpxchg(&v->counter, old, new); -} - -static inline int atomic_xchg(atomic_t *v, int new) -{ - return xchg(&v->counter, new); -} - -/** - * atomic_add_unless - add unless the number is already a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as @v was not already @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - c = atomic_read(v); - for (;;) { - if (unlikely(c == (u))) - break; - old = atomic_cmpxchg((v), c, c + (a)); - if (likely(old == c)) - break; - c = old; - } - return c != (u); -} - -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -/** - * atomic_inc_short - increment of a short integer - * @v: pointer to type int - * - * Atomically adds 1 to @v - * Returns the new value of @u - */ -static inline short int atomic_inc_short(short int *v) -{ - asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); - return *v; -} - -#ifdef CONFIG_X86_64 -/** - * atomic_or_long - OR of two long integers - * @v1: pointer to type unsigned long - * @v2: pointer to type unsigned long - * - * Atomically ORs @v1 and @v2 - * Returns the result of the OR - */ -static inline void atomic_or_long(unsigned long *v1, unsigned long v2) -{ - asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); -} -#endif - -/* These are x86-specific, used by some header files */ -#define atomic_clear_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "andl %0,%1" \ - : : "r" (~(mask)), "m" (*(addr)) : "memory") - -#define atomic_set_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "orl %0,%1" \ - : : "r" ((unsigned)(mask)), "m" (*(addr)) \ - : "memory") - -/* Atomic operations are already serializing on x86 */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - -#include -#include -#endif /* _ASM_X86_ATOMIC_64_H */ -- GitLab From e1e0138d7d10fd447c71cc70f367eac514bd3ce4 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Thu, 7 Jan 2010 10:12:40 -0600 Subject: [PATCH 0434/3892] x86, uv: uv_global_gru_mmr_address() macro fix Fix bug in uv_global_gru_mmr_address macro. Macro failed to cast an int value to a long prior to a left shift > 32. Signed-off-by: Jack Steiner LKML-Reference: <20100107161240.GA2610@sgi.com> Cc: Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/uv/uv_hub.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 811bfabc80b7..7a81d9db57b9 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -335,7 +335,8 @@ static inline unsigned long uv_read_global_mmr64(int pnode, */ 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); + return UV_GLOBAL_GRU_MMR_BASE | offset | + ((unsigned long)pnode << uv_hub_info->m_val); } /* -- GitLab From 99659a929d653d0c9ce458091870544768add871 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 7 Jan 2010 15:35:42 +0100 Subject: [PATCH 0435/3892] x86, uv: Remove recursion in uv_heartbeat_enable() The recursion is not needed and does not improve readability. Signed-off-by: Roel Kluin LKML-Reference: <4B45F13E.3040202@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/apic/x2apic_uv_x.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index af5d103bb533..d199dc34f54a 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -475,7 +475,7 @@ static void uv_heartbeat(unsigned long ignored) static void __cpuinit uv_heartbeat_enable(int cpu) { - if (!uv_cpu_hub_info(cpu)->scir.enabled) { + while (!uv_cpu_hub_info(cpu)->scir.enabled) { struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer; uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); @@ -483,11 +483,10 @@ static void __cpuinit uv_heartbeat_enable(int cpu) timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; add_timer_on(timer, cpu); uv_cpu_hub_info(cpu)->scir.enabled = 1; - } - /* check boot cpu */ - if (!uv_cpu_hub_info(0)->scir.enabled) - uv_heartbeat_enable(0); + /* also ensure that boot cpu is enabled */ + cpu = 0; + } } #ifdef CONFIG_HOTPLUG_CPU -- GitLab From bc7259a2ce764ea16200eb9e53f6e136e918d065 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 7 Jan 2010 11:43:50 +0000 Subject: [PATCH 0436/3892] lib/vsprintf.c: Add %pMF to format FDDI bit reversed MAC addresses On Mon, 2010-01-04 at 23:43 +0000, Maciej W. Rozycki wrote: > The example below shows an address, and the sequence of bits or symbols > that would be transmitted when the address is used in the Source Address > or Destination Address fields on the MAC header. The transmission line > shows the address bits in the order transmitted, from left to right. For > IEEE 802 LANs these correspond to actual bits on the medium. The FDDI > symbols line shows how the FDDI PHY sends the address bits as encoded > symbols. > > MSB: 35:7B:12:00:00:01 > Canonical: AC-DE-48-00-00-80 > Transmission: 00110101 01111011 00010010 00000000 00000000 00000001 > FDDI Symbols: 35 7B 12 00 00 01" > > Please note that this address has its group bit clear. > > This notation is also defined in the "FDDI MEDIA ACCESS CONTROL-2 > (MAC-2)" (X3T9/92-120) document although that book does not have a need > to use the MSB form and it's skipped. Adds 6 bytes to object size for x86 New: $ size lib/vsprintf.o text data bss dec hex filename 8664 0 2 8666 21da lib/vsprintf.o $ size lib/vsprintf.o text data bss dec hex filename 8658 0 2 8660 21d4 lib/vsprintf.o Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- lib/vsprintf.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d4996cf46eb6..dc48d2b32ebd 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include /* for PAGE_SIZE */ @@ -681,11 +682,21 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; char *p = mac_addr; int i; + bool bitrev; + char separator; + + if (fmt[1] == 'F') { /* FDDI canonical format */ + bitrev = true; + separator = '-'; + } else { + bitrev = false; + separator = ':'; + } for (i = 0; i < 6; i++) { - p = pack_hex_byte(p, addr[i]); + p = pack_hex_byte(p, bitrev ? bitrev8(addr[i]) : addr[i]); if (fmt[0] == 'M' && i != 5) - *p++ = ':'; + *p++ = separator; } *p = '\0'; @@ -896,6 +907,10 @@ static char *uuid_string(char *buf, char *end, const u8 *addr, * - 'M' For a 6-byte MAC address, it prints the address in the * usual colon-separated hex notation * - 'm' For a 6-byte MAC address, it prints the hex address without colons + * - 'MF' For a 6-byte MAC FDDI address, it prints the address + * with a dash-separated hex notation with bit reversed bytes + * - 'mF' For a 6-byte MAC FDDI address, it prints the address + * in hex notation without separators with bit reversed bytes * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) * IPv6 uses colon separated network-order 16 bit hex with leading 0's @@ -939,6 +954,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, return resource_string(buf, end, ptr, spec, fmt); case 'M': /* Colon separated: 00:01:02:03:04:05 */ case 'm': /* Contiguous: 000102030405 */ + /* [mM]F (FDDI, bit reversed) */ return mac_address_string(buf, end, ptr, spec, fmt); case 'I': /* Formatted IP supported * 4: 1.2.3.4 -- GitLab From 69d279eaf8f23c7d7cfc0e879c629a92bfc3e3e0 Mon Sep 17 00:00:00 2001 From: hartleys Date: Thu, 7 Jan 2010 13:24:19 +0000 Subject: [PATCH 0437/3892] drivers/net/defxx.c: use %pMF to show MAC address Use the %pMF kernel extension to display the MAC address. The address will still be displayed in the FDDI Canonical format. Signed-off-by: H Hartley Sweeten Cc: Maciej W. Rozycki Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/defxx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 6a6ea038d7a3..e4eac4bcdf83 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -1052,12 +1052,9 @@ static int __devinit dfx_driver_init(struct net_device *dev, board_name = "DEFEA"; if (dfx_bus_pci) board_name = "DEFPA"; - pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", print_name, board_name, dfx_use_mmio ? "" : "I/O ", - (long long)bar_start, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + (long long)bar_start, dev->irq, dev->dev_addr); /* * Get memory for descriptor block, consumer block, and other buffers -- GitLab From 596a530bb3af746d33ea2910a0569b9825279979 Mon Sep 17 00:00:00 2001 From: hartleys Date: Thu, 7 Jan 2010 13:27:46 +0000 Subject: [PATCH 0438/3892] drivers/net/skfp/skfddi.c: use %pMF to show MAC address Use the %pMF kernel extension to display the MAC address. The address will still be displayed in the FDDI Canonical format. Signed-off-by: H Hartley Sweeten Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/skfp/skfddi.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index db216a728503..1f9698c0fb64 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -435,13 +435,7 @@ static int skfp_driver_init(struct net_device *dev) goto fail; } read_address(smc, NULL); - pr_debug(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", - smc->hw.fddi_canon_addr.a[0], - smc->hw.fddi_canon_addr.a[1], - smc->hw.fddi_canon_addr.a[2], - smc->hw.fddi_canon_addr.a[3], - smc->hw.fddi_canon_addr.a[4], - smc->hw.fddi_canon_addr.a[5]); + pr_debug(KERN_INFO "HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a); memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); smt_reset_defaults(smc, 0); @@ -890,15 +884,8 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) (struct fddi_addr *)dmi->dmi_addr, 1); - pr_debug(KERN_INFO "ENABLE MC ADDRESS:"); - pr_debug(" %02x %02x %02x ", - dmi->dmi_addr[0], - dmi->dmi_addr[1], - dmi->dmi_addr[2]); - pr_debug("%02x %02x %02x\n", - dmi->dmi_addr[3], - dmi->dmi_addr[4], - dmi->dmi_addr[5]); + pr_debug(KERN_INFO "ENABLE MC ADDRESS: %pMF\n", + dmi->dmi_addr); dmi = dmi->next; } // for -- GitLab From 109cdd66485b639b2fbfcbf59ae7ef1286520705 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:11 +0000 Subject: [PATCH 0439/3892] stmmac: use MII_BUS_ID_SIZE instead of BUS_ID_SIZE Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 508fba8fa07f..79a938117878 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -305,8 +305,8 @@ static int stmmac_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; /* PHY to connect */ - char bus_id[BUS_ID_SIZE]; + char phy_id[MII_BUS_ID_SIZE + 3]; + char bus_id[MII_BUS_ID_SIZE]; priv->oldlink = 0; priv->speed = 0; @@ -318,7 +318,8 @@ static int stmmac_init_phy(struct net_device *dev) } snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id); - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, bus_id, priv->phy_addr); + snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, + priv->phy_addr); pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, -- GitLab From 609634799eba48bb9e80ce56dfd87930f17bf6fa Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:12 +0000 Subject: [PATCH 0440/3892] stmmac: convert unicast addr list to list_head This patch converts unicast address list to standard list_head using previously introduced struct netdev_hw_addr. Note: this patch also removes a debug printk used for displaying the mac addresses. Indeed, it's is possible to dump the registers with ethtool. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/gmac.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c index 52586ee68953..982875646725 100644 --- a/drivers/net/stmmac/gmac.c +++ b/drivers/net/stmmac/gmac.c @@ -435,7 +435,7 @@ static void gmac_set_filter(struct net_device *dev) unsigned int value = 0; DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", - __func__, dev->mc_count, dev->uc_count); + __func__, dev->mc_count, dev->uc.count); if (dev->flags & IFF_PROMISC) value = GMAC_FRAME_FILTER_PR; @@ -469,25 +469,17 @@ static void gmac_set_filter(struct net_device *dev) } /* Handle multiple unicast addresses (perfect filtering)*/ - if (dev->uc_count > GMAC_MAX_UNICAST_ADDRESSES) + if (dev->uc.count > GMAC_MAX_UNICAST_ADDRESSES) /* Switch to promiscuous mode is more than 16 addrs are required */ value |= GMAC_FRAME_FILTER_PR; else { - int i; - struct dev_addr_list *uc_ptr = dev->uc_list; - - for (i = 0; i < dev->uc_count; i++) { - gmac_set_umac_addr(ioaddr, uc_ptr->da_addr, - i + 1); - - DBG(KERN_INFO "\t%d " - "- Unicast addr %02x:%02x:%02x:%02x:%02x:" - "%02x\n", i + 1, - uc_ptr->da_addr[0], uc_ptr->da_addr[1], - uc_ptr->da_addr[2], uc_ptr->da_addr[3], - uc_ptr->da_addr[4], uc_ptr->da_addr[5]); - uc_ptr = uc_ptr->next; + int reg = 1; + struct netdev_hw_addr *ha; + + list_for_each_entry(ha, &dev->uc.list, list) { + gmac_set_umac_addr(ioaddr, ha->addr, reg); + reg++; } } -- GitLab From 3c9732c06879d85f2fdf7ec69198c1d78da42a98 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:13 +0000 Subject: [PATCH 0441/3892] stmmac: add the new Header file for stmmac platform data Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- include/linux/stmmac.h | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 include/linux/stmmac.h diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h new file mode 100644 index 000000000000..32bfd1a8a48d --- /dev/null +++ b/include/linux/stmmac.h @@ -0,0 +1,53 @@ +/******************************************************************************* + + Header file for stmmac platform data + + Copyright (C) 2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#ifndef __STMMAC_PLATFORM_DATA +#define __STMMAC_PLATFORM_DATA + +/* platfrom data for platfrom device structure's platfrom_data field */ + +/* Private data for the STM on-board ethernet driver */ +struct plat_stmmacenet_data { + int bus_id; + int pbl; + int has_gmac; + void (*fix_mac_speed)(void *priv, unsigned int speed); + void (*bus_setup)(unsigned long ioaddr); +#ifdef CONFIG_STM_DRIVERS + struct stm_pad_config *pad_config; +#endif + void *bsp_priv; +}; + +struct plat_stmmacphy_data { + int bus_id; + int phy_addr; + unsigned int phy_mask; + int interface; + int (*phy_reset)(void *priv); + void *priv; +}; +#endif + -- GitLab From ee7946a77858f417227cf57cd647729d0dd75761 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:14 +0000 Subject: [PATCH 0442/3892] stmmac: rewiew platform data This patch rewiews and reorganises all the data come from the platform removing any dependency from the stm code. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac.h | 24 ++++++++++++++++++++++++ drivers/net/stmmac/stmmac_main.c | 16 +++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h index 6d2eae3040e5..0d5529fa579a 100644 --- a/drivers/net/stmmac/stmmac.h +++ b/drivers/net/stmmac/stmmac.h @@ -21,6 +21,7 @@ *******************************************************************************/ #define DRV_MODULE_VERSION "Oct_09" +#include #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define STMMAC_VLAN_TAG_USED @@ -69,6 +70,7 @@ struct stmmac_priv { int phy_mask; int (*phy_reset) (void *priv); void (*fix_mac_speed) (void *priv, unsigned int speed); + void (*bus_setup)(unsigned long ioaddr); void *bsp_priv; int phy_irq; @@ -93,6 +95,28 @@ struct stmmac_priv { #endif }; +#ifdef CONFIG_STM_DRIVERS +#include +static inline int stmmac_claim_resource(struct platform_device *pdev) +{ + int ret = 0; + struct plat_stmmacenet_data *plat_dat = pdev->dev.platform_data; + + /* Pad routing setup */ + if (IS_ERR(devm_stm_pad_claim(&pdev->dev, plat_dat->pad_config, + dev_name(&pdev->dev)))) { + printk(KERN_ERR "%s: Failed to request pads!\n", __func__); + ret = -ENODEV; + } + return ret; +} +#else +static inline int stmmac_claim_resource(struct platform_device *pdev) +{ + return 0; +} +#endif + extern int stmmac_mdio_unregister(struct net_device *ndev); extern int stmmac_mdio_register(struct net_device *ndev); extern void stmmac_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 79a938117878..d50fe6f171ef 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -45,7 +45,6 @@ #include #include #include -#include #include "stmmac.h" #define STMMAC_RESOURCE_NAME "stmmaceth" @@ -1798,8 +1797,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) static int stmmacphy_dvr_probe(struct platform_device *pdev) { - struct plat_stmmacphy_data *plat_dat; - plat_dat = (struct plat_stmmacphy_data *)((pdev->dev).platform_data); + struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data; pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n", plat_dat->bus_id); @@ -1831,9 +1829,7 @@ static struct platform_driver stmmacphy_driver = { static int stmmac_associate_phy(struct device *dev, void *data) { struct stmmac_priv *priv = (struct stmmac_priv *)data; - struct plat_stmmacphy_data *plat_dat; - - plat_dat = (struct plat_stmmacphy_data *)(dev->platform_data); + struct plat_stmmacphy_data *plat_dat = dev->platform_data; DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__, plat_dat->bus_id); @@ -1923,7 +1919,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->device = &(pdev->dev); priv->dev = ndev; - plat_dat = (struct plat_stmmacenet_data *)((pdev->dev).platform_data); + plat_dat = pdev->dev.platform_data; priv->bus_id = plat_dat->bus_id; priv->pbl = plat_dat->pbl; /* TLI */ priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */ @@ -1933,6 +1929,11 @@ static int stmmac_dvr_probe(struct platform_device *pdev) /* Set the I/O base addr */ ndev->base_addr = (unsigned long)addr; + /* Verify embedded resource for the platform */ + ret = stmmac_claim_resource(pdev); + if (ret < 0) + goto out; + /* MAC HW revice detection */ ret = stmmac_mac_device_setup(ndev); if (ret < 0) @@ -1953,6 +1954,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev) } priv->fix_mac_speed = plat_dat->fix_mac_speed; + priv->bus_setup = plat_dat->bus_setup; priv->bsp_priv = plat_dat->bsp_priv; pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" -- GitLab From ca5f12c1a82cf72ce73617dfc8ef56faf6fec30a Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:15 +0000 Subject: [PATCH 0443/3892] stmmac: perform hw bus configuration On some platforms it can be required a different configuration of the bus. This can be done by invoking the bus_setup. It is defined for all the platforms that needs this kind of configuration. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/gmac.c | 3 --- drivers/net/stmmac/stmmac_main.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c index 982875646725..c1278876ef25 100644 --- a/drivers/net/stmmac/gmac.c +++ b/drivers/net/stmmac/gmac.c @@ -400,9 +400,6 @@ static void gmac_core_init(unsigned long ioaddr) value |= GMAC_CORE_INIT; writel(value, ioaddr + GMAC_CONTROL); - /* STBus Bridge Configuration */ - /*writel(0xc5608, ioaddr + 0x00007000);*/ - /* Freeze MMC counters */ writel(0x8, ioaddr + GMAC_MMC_CTRL); /* Mask GMAC interrupts */ diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index d50fe6f171ef..a02006d57a59 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1067,6 +1067,9 @@ static int stmmac_open(struct net_device *dev) /* Copy the MAC addr into the HW */ priv->mac_type->ops->set_umac_addr(ioaddr, dev->dev_addr, 0); + /* If required, perform hw setup of the bus. */ + if (priv->bus_setup) + priv->bus_setup(ioaddr); /* Initialize the MAC Core */ priv->mac_type->ops->core_init(ioaddr); -- GitLab From 65818fa744e70a58d230083dda1f1cd8e5c5e2ee Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:16 +0000 Subject: [PATCH 0444/3892] stmmac: do not call fix_mac_speed if NULL On some platforms, fix_mac_speed is used for configuring some sysconf registers according to the working speed. This patch fixes the fix_mac_speed invocation that cannot be done if it is a NULL pointer. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index a02006d57a59..82ebbc0c8839 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -258,8 +258,9 @@ static void stmmac_adjust_link(struct net_device *dev) } else { ctrl &= ~priv->mac_type->hw.link.port; } - priv->fix_mac_speed(priv->bsp_priv, - phydev->speed); + if (likely(priv->fix_mac_speed)) + priv->fix_mac_speed(priv->bsp_priv, + phydev->speed); break; default: if (netif_msg_link(priv)) -- GitLab From db98a0b001df79ffcdd4f231c3516411786a1113 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:17 +0000 Subject: [PATCH 0445/3892] stmmac: reorganise class operations. This patch reorganises the internal stmmac ops structure. The stmmac_ops has been splitted into other three structures named: stmmac_ops stmmac_dma_ops stmmac_desc_ops This makes the code more clear and also helps the next work to make the driver more generic. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/common.h | 64 +++++++------ drivers/net/stmmac/gmac.c | 43 +++++---- drivers/net/stmmac/mac100.c | 43 +++++---- drivers/net/stmmac/stmmac.h | 2 +- drivers/net/stmmac/stmmac_ethtool.c | 8 +- drivers/net/stmmac/stmmac_main.c | 138 +++++++++++++--------------- drivers/net/stmmac/stmmac_mdio.c | 10 +- 7 files changed, 162 insertions(+), 146 deletions(-) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index e49e5188e887..95782ccf44b4 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -239,25 +239,11 @@ static inline void stmmac_get_mac_addr(unsigned long ioaddr, return; } -struct stmmac_ops { - /* MAC core initialization */ - void (*core_init) (unsigned long ioaddr) ____cacheline_aligned; - /* DMA core initialization */ - int (*dma_init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx); - /* Dump MAC registers */ - void (*dump_mac_regs) (unsigned long ioaddr); - /* Dump DMA registers */ - void (*dump_dma_regs) (unsigned long ioaddr); - /* Set tx/rx threshold in the csr6 register - * An invalid value enables the store-and-forward mode */ - void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode); - /* To track extra statistic (if supported) */ - void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, - unsigned long ioaddr); - /* RX descriptor ring initialization */ +struct stmmac_desc_ops { + /* DMA RX descriptor ring initialization */ void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size, - int disable_rx_ic); - /* TX descriptor ring initialization */ + int disable_rx_ic); + /* DMA TX descriptor ring initialization */ void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size); /* Invoked by the xmit function to prepare the tx descriptor */ @@ -281,7 +267,6 @@ struct stmmac_ops { /* Get the buffer size from the descriptor */ int (*get_tx_len) (struct dma_desc *p); /* Handle extra events on specific interrupts hw dependent */ - void (*host_irq_status) (unsigned long ioaddr); int (*get_rx_owner) (struct dma_desc *p); void (*set_rx_owner) (struct dma_desc *p); /* Get the receive frame size */ @@ -289,6 +274,28 @@ struct stmmac_ops { /* Return the reception status looking at the RDES1 */ int (*rx_status) (void *data, struct stmmac_extra_stats *x, struct dma_desc *p); +}; + +struct stmmac_dma_ops { + /* DMA core initialization */ + int (*init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx); + /* Dump DMA registers */ + void (*dump_regs) (unsigned long ioaddr); + /* Set tx/rx threshold in the csr6 register + * An invalid value enables the store-and-forward mode */ + void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode); + /* To track extra statistic (if supported) */ + void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, + unsigned long ioaddr); +}; + +struct stmmac_ops { + /* MAC core initialization */ + void (*core_init) (unsigned long ioaddr) ____cacheline_aligned; + /* Dump MAC registers */ + void (*dump_regs) (unsigned long ioaddr); + /* Handle extra events on specific interrupts hw dependent */ + void (*host_irq_status) (unsigned long ioaddr); /* Multicast filter setting */ void (*set_filter) (struct net_device *dev); /* Flow control setting */ @@ -298,9 +305,9 @@ struct stmmac_ops { void (*pmt) (unsigned long ioaddr, unsigned long mode); /* Set/Get Unicast MAC addresses */ void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr, - unsigned int reg_n); + unsigned int reg_n); void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr, - unsigned int reg_n); + unsigned int reg_n); }; struct mac_link { @@ -314,16 +321,13 @@ struct mii_regs { unsigned int data; /* MII Data */ }; -struct hw_cap { - unsigned int version; /* Core Version register (GMAC) */ - unsigned int pmt; /* Power-Down mode (GMAC) */ - struct mac_link link; - struct mii_regs mii; -}; - struct mac_device_info { - struct hw_cap hw; - struct stmmac_ops *ops; + struct stmmac_ops *mac; + struct stmmac_desc_ops *desc; + struct stmmac_dma_ops *dma; + unsigned int pmt; /* support Power-Down */ + struct mii_regs mii; /* MII register Addresses */ + struct mac_link link; }; struct mac_device_info *gmac_setup(unsigned long addr); diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c index c1278876ef25..cf199d969227 100644 --- a/drivers/net/stmmac/gmac.c +++ b/drivers/net/stmmac/gmac.c @@ -630,19 +630,28 @@ static int gmac_get_rx_frame_len(struct dma_desc *p) return p->des01.erx.frame_length; } -struct stmmac_ops gmac_driver = { +struct stmmac_ops gmac_ops = { .core_init = gmac_core_init, - .dump_mac_regs = gmac_dump_regs, - .dma_init = gmac_dma_init, - .dump_dma_regs = gmac_dump_dma_regs, + .dump_regs = gmac_dump_regs, + .host_irq_status = gmac_irq_status, + .set_filter = gmac_set_filter, + .flow_ctrl = gmac_flow_ctrl, + .pmt = gmac_pmt, + .set_umac_addr = gmac_set_umac_addr, + .get_umac_addr = gmac_get_umac_addr, +}; + +struct stmmac_dma_ops gmac_dma_ops = { + .init = gmac_dma_init, + .dump_regs = gmac_dump_dma_regs, .dma_mode = gmac_dma_operation_mode, .dma_diagnostic_fr = gmac_dma_diagnostic_fr, +}; + +struct stmmac_desc_ops gmac_desc_ops = { .tx_status = gmac_get_tx_frame_status, .rx_status = gmac_get_rx_frame_status, .get_tx_len = gmac_get_tx_len, - .set_filter = gmac_set_filter, - .flow_ctrl = gmac_flow_ctrl, - .pmt = gmac_pmt, .init_rx_desc = gmac_init_rx_desc, .init_tx_desc = gmac_init_tx_desc, .get_tx_owner = gmac_get_tx_owner, @@ -655,9 +664,6 @@ struct stmmac_ops gmac_driver = { .set_tx_owner = gmac_set_tx_owner, .set_rx_owner = gmac_set_rx_owner, .get_rx_frame_len = gmac_get_rx_frame_len, - .host_irq_status = gmac_irq_status, - .set_umac_addr = gmac_set_umac_addr, - .get_umac_addr = gmac_get_umac_addr, }; struct mac_device_info *gmac_setup(unsigned long ioaddr) @@ -670,13 +676,16 @@ struct mac_device_info *gmac_setup(unsigned long ioaddr) mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); - mac->ops = &gmac_driver; - mac->hw.pmt = PMT_SUPPORTED; - mac->hw.link.port = GMAC_CONTROL_PS; - mac->hw.link.duplex = GMAC_CONTROL_DM; - mac->hw.link.speed = GMAC_CONTROL_FES; - mac->hw.mii.addr = GMAC_MII_ADDR; - mac->hw.mii.data = GMAC_MII_DATA; + mac->mac = &gmac_ops; + mac->desc = &gmac_desc_ops; + mac->dma = &gmac_dma_ops; + + mac->pmt = PMT_SUPPORTED; + mac->link.port = GMAC_CONTROL_PS; + mac->link.duplex = GMAC_CONTROL_DM; + mac->link.speed = GMAC_CONTROL_FES; + mac->mii.addr = GMAC_MII_ADDR; + mac->mii.data = GMAC_MII_DATA; return mac; } diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/mac100.c index 625171b6062b..45d0457ddb6e 100644 --- a/drivers/net/stmmac/mac100.c +++ b/drivers/net/stmmac/mac100.c @@ -467,19 +467,28 @@ static int mac100_get_rx_frame_len(struct dma_desc *p) return p->des01.rx.frame_length; } -struct stmmac_ops mac100_driver = { +struct stmmac_ops mac100_ops = { .core_init = mac100_core_init, - .dump_mac_regs = mac100_dump_mac_regs, - .dma_init = mac100_dma_init, - .dump_dma_regs = mac100_dump_dma_regs, + .dump_regs = mac100_dump_mac_regs, + .host_irq_status = mac100_irq_status, + .set_filter = mac100_set_filter, + .flow_ctrl = mac100_flow_ctrl, + .pmt = mac100_pmt, + .set_umac_addr = mac100_set_umac_addr, + .get_umac_addr = mac100_get_umac_addr, +}; + +struct stmmac_dma_ops mac100_dma_ops = { + .init = mac100_dma_init, + .dump_regs = mac100_dump_dma_regs, .dma_mode = mac100_dma_operation_mode, .dma_diagnostic_fr = mac100_dma_diagnostic_fr, +}; + +struct stmmac_desc_ops mac100_desc_ops = { .tx_status = mac100_get_tx_frame_status, .rx_status = mac100_get_rx_frame_status, .get_tx_len = mac100_get_tx_len, - .set_filter = mac100_set_filter, - .flow_ctrl = mac100_flow_ctrl, - .pmt = mac100_pmt, .init_rx_desc = mac100_init_rx_desc, .init_tx_desc = mac100_init_tx_desc, .get_tx_owner = mac100_get_tx_owner, @@ -492,9 +501,6 @@ struct stmmac_ops mac100_driver = { .set_tx_owner = mac100_set_tx_owner, .set_rx_owner = mac100_set_rx_owner, .get_rx_frame_len = mac100_get_rx_frame_len, - .host_irq_status = mac100_irq_status, - .set_umac_addr = mac100_set_umac_addr, - .get_umac_addr = mac100_get_umac_addr, }; struct mac_device_info *mac100_setup(unsigned long ioaddr) @@ -505,13 +511,16 @@ struct mac_device_info *mac100_setup(unsigned long ioaddr) pr_info("\tMAC 10/100\n"); - mac->ops = &mac100_driver; - mac->hw.pmt = PMT_NOT_SUPPORTED; - mac->hw.link.port = MAC_CONTROL_PS; - mac->hw.link.duplex = MAC_CONTROL_F; - mac->hw.link.speed = 0; - mac->hw.mii.addr = MAC_MII_ADDR; - mac->hw.mii.data = MAC_MII_DATA; + mac->mac = &mac100_ops; + mac->desc = &mac100_desc_ops; + mac->dma = &mac100_dma_ops; + + mac->pmt = PMT_NOT_SUPPORTED; + mac->link.port = MAC_CONTROL_PS; + mac->link.duplex = MAC_CONTROL_F; + mac->link.speed = 0; + mac->mii.addr = MAC_MII_ADDR; + mac->mii.data = MAC_MII_DATA; return mac; } diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h index 0d5529fa579a..44421d9667a8 100644 --- a/drivers/net/stmmac/stmmac.h +++ b/drivers/net/stmmac/stmmac.h @@ -58,7 +58,7 @@ struct stmmac_priv { int rx_csum; unsigned int dma_buf_sz; struct device *device; - struct mac_device_info *mac_type; + struct mac_device_info *hw; struct stmmac_extra_stats xstats; struct napi_struct napi; diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 694ebe6a0758..9c7ce1ea3aea 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -268,8 +268,8 @@ stmmac_set_pauseparam(struct net_device *netdev, } } else { unsigned long ioaddr = netdev->base_addr; - priv->mac_type->ops->flow_ctrl(ioaddr, phy->duplex, - priv->flow_ctrl, priv->pause); + priv->hw->mac->flow_ctrl(ioaddr, phy->duplex, + priv->flow_ctrl, priv->pause); } spin_unlock(&priv->lock); return ret; @@ -283,8 +283,8 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, int i; /* Update HW stats if supported */ - priv->mac_type->ops->dma_diagnostic_fr(&dev->stats, &priv->xstats, - ioaddr); + priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats, + ioaddr); for (i = 0; i < STMMAC_STATS_LEN; i++) { char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 82ebbc0c8839..86e910300969 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -225,38 +225,34 @@ static void stmmac_adjust_link(struct net_device *dev) if (phydev->duplex != priv->oldduplex) { new_state = 1; if (!(phydev->duplex)) - ctrl &= ~priv->mac_type->hw.link.duplex; + ctrl &= ~priv->hw->link.duplex; else - ctrl |= priv->mac_type->hw.link.duplex; + ctrl |= priv->hw->link.duplex; priv->oldduplex = phydev->duplex; } /* Flow Control operation */ if (phydev->pause) - priv->mac_type->ops->flow_ctrl(ioaddr, phydev->duplex, - fc, pause_time); + priv->hw->mac->flow_ctrl(ioaddr, phydev->duplex, + fc, pause_time); if (phydev->speed != priv->speed) { new_state = 1; switch (phydev->speed) { case 1000: if (likely(priv->is_gmac)) - ctrl &= ~priv->mac_type->hw.link.port; + ctrl &= ~priv->hw->link.port; break; case 100: case 10: if (priv->is_gmac) { - ctrl |= priv->mac_type->hw.link.port; + ctrl |= priv->hw->link.port; if (phydev->speed == SPEED_100) { - ctrl |= - priv->mac_type->hw.link. - speed; + ctrl |= priv->hw->link.speed; } else { - ctrl &= - ~(priv->mac_type->hw. - link.speed); + ctrl &= ~(priv->hw->link.speed); } } else { - ctrl &= ~priv->mac_type->hw.link.port; + ctrl &= ~priv->hw->link.port; } if (likely(priv->fix_mac_speed)) priv->fix_mac_speed(priv->bsp_priv, @@ -509,8 +505,8 @@ static void init_dma_desc_rings(struct net_device *dev) priv->cur_tx = 0; /* Clear the Rx/Tx descriptors */ - priv->mac_type->ops->init_rx_desc(priv->dma_rx, rxsize, dis_ic); - priv->mac_type->ops->init_tx_desc(priv->dma_tx, txsize); + priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic); + priv->hw->desc->init_tx_desc(priv->dma_tx, txsize); if (netif_msg_hw(priv)) { pr_info("RX descriptor ring:\n"); @@ -545,8 +541,8 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv) struct dma_desc *p = priv->dma_tx + i; if (p->des2) dma_unmap_single(priv->device, p->des2, - priv->mac_type->ops->get_tx_len(p), - DMA_TO_DEVICE); + priv->hw->desc->get_tx_len(p), + DMA_TO_DEVICE); dev_kfree_skb_any(priv->tx_skbuff[i]); priv->tx_skbuff[i] = NULL; } @@ -630,18 +626,18 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) { if (!priv->is_gmac) { /* MAC 10/100 */ - priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc, 0); + priv->hw->dma->dma_mode(priv->dev->base_addr, tc, 0); priv->tx_coe = NO_HW_CSUM; } else { if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) { - priv->mac_type->ops->dma_mode(priv->dev->base_addr, - SF_DMA_MODE, SF_DMA_MODE); + priv->hw->dma->dma_mode(priv->dev->base_addr, + SF_DMA_MODE, SF_DMA_MODE); tc = SF_DMA_MODE; priv->tx_coe = HW_CSUM; } else { /* Checksum computation is performed in software. */ - priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc, - SF_DMA_MODE); + priv->hw->dma->dma_mode(priv->dev->base_addr, tc, + SF_DMA_MODE); priv->tx_coe = NO_HW_CSUM; } } @@ -749,16 +745,16 @@ static void stmmac_tx(struct stmmac_priv *priv) struct dma_desc *p = priv->dma_tx + entry; /* Check if the descriptor is owned by the DMA. */ - if (priv->mac_type->ops->get_tx_owner(p)) + if (priv->hw->desc->get_tx_owner(p)) break; /* Verify tx error by looking at the last segment */ - last = priv->mac_type->ops->get_tx_ls(p); + last = priv->hw->desc->get_tx_ls(p); if (likely(last)) { int tx_error = - priv->mac_type->ops->tx_status(&priv->dev->stats, - &priv->xstats, - p, ioaddr); + priv->hw->desc->tx_status(&priv->dev->stats, + &priv->xstats, p, + ioaddr); if (likely(tx_error == 0)) { priv->dev->stats.tx_packets++; priv->xstats.tx_pkt_n++; @@ -770,7 +766,7 @@ static void stmmac_tx(struct stmmac_priv *priv) if (likely(p->des2)) dma_unmap_single(priv->device, p->des2, - priv->mac_type->ops->get_tx_len(p), + priv->hw->desc->get_tx_len(p), DMA_TO_DEVICE); if (unlikely(p->des3)) p->des3 = 0; @@ -791,7 +787,7 @@ static void stmmac_tx(struct stmmac_priv *priv) priv->tx_skbuff[entry] = NULL; } - priv->mac_type->ops->release_tx_desc(p); + priv->hw->desc->release_tx_desc(p); entry = (++priv->dirty_tx) % txsize; } @@ -833,7 +829,7 @@ static int stmmac_has_work(struct stmmac_priv *priv) unsigned int has_work = 0; int rxret, tx_work = 0; - rxret = priv->mac_type->ops->get_rx_owner(priv->dma_rx + + rxret = priv->hw->desc->get_rx_owner(priv->dma_rx + (priv->cur_rx % priv->dma_rx_size)); if (priv->dirty_tx != priv->cur_tx) @@ -886,7 +882,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv) stmmac_dma_stop_tx(priv->dev->base_addr); dma_free_tx_skbufs(priv); - priv->mac_type->ops->init_tx_desc(priv->dma_tx, priv->dma_tx_size); + priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); priv->dirty_tx = 0; priv->cur_tx = 0; stmmac_dma_start_tx(priv->dev->base_addr); @@ -926,8 +922,8 @@ static void stmmac_dma_interrupt(struct net_device *dev) if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { /* Try to bump up the threshold */ tc += 64; - priv->mac_type->ops->dma_mode(ioaddr, tc, - SF_DMA_MODE); + priv->hw->dma->dma_mode(ioaddr, tc, + SF_DMA_MODE); priv->xstats.threshold = tc; } stmmac_tx_err(priv); @@ -1059,20 +1055,20 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - if (unlikely(priv->mac_type->ops->dma_init(ioaddr, - priv->pbl, priv->dma_tx_phy, priv->dma_rx_phy) < 0)) { + if (unlikely(priv->hw->dma->init(ioaddr, priv->pbl, priv->dma_tx_phy, + priv->dma_rx_phy) < 0)) { pr_err("%s: DMA initialization failed\n", __func__); return -1; } /* Copy the MAC addr into the HW */ - priv->mac_type->ops->set_umac_addr(ioaddr, dev->dev_addr, 0); + priv->hw->mac->set_umac_addr(ioaddr, dev->dev_addr, 0); /* If required, perform hw setup of the bus. */ if (priv->bus_setup) priv->bus_setup(ioaddr); /* Initialize the MAC Core */ - priv->mac_type->ops->core_init(ioaddr); + priv->hw->mac->core_init(ioaddr); priv->shutdown = 0; @@ -1101,8 +1097,8 @@ static int stmmac_open(struct net_device *dev) #endif /* Dump DMA/MAC registers */ if (netif_msg_hw(priv)) { - priv->mac_type->ops->dump_mac_regs(ioaddr); - priv->mac_type->ops->dump_dma_regs(ioaddr); + priv->hw->mac->dump_regs(ioaddr); + priv->hw->dma->dump_regs(ioaddr); } if (priv->phydev) @@ -1218,8 +1214,8 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, desc->des2 = dma_map_single(priv->device, skb->data, BUF_SIZE_8KiB, DMA_TO_DEVICE); desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->mac_type->ops->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB, - csum_insertion); + priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB, + csum_insertion); entry = (++priv->cur_tx) % txsize; desc = priv->dma_tx + entry; @@ -1228,16 +1224,17 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, skb->data + BUF_SIZE_8KiB, buf2_size, DMA_TO_DEVICE); desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->mac_type->ops->prepare_tx_desc(desc, 0, - buf2_size, csum_insertion); - priv->mac_type->ops->set_tx_owner(desc); + priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size, + csum_insertion); + priv->hw->desc->set_tx_owner(desc); + priv->tx_skbuff[entry] = NULL; } else { desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE); desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len, - csum_insertion); + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, + csum_insertion); } return entry; } @@ -1305,8 +1302,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int nopaged_len = skb_headlen(skb); desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE); - priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len, - csum_insertion); + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, + csum_insertion); } for (i = 0; i < nfrags; i++) { @@ -1321,21 +1318,20 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) frag->page_offset, len, DMA_TO_DEVICE); priv->tx_skbuff[entry] = NULL; - priv->mac_type->ops->prepare_tx_desc(desc, 0, len, - csum_insertion); - priv->mac_type->ops->set_tx_owner(desc); + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); + priv->hw->desc->set_tx_owner(desc); } /* Interrupt on completition only for the latest segment */ - priv->mac_type->ops->close_tx_desc(desc); + priv->hw->desc->close_tx_desc(desc); #ifdef CONFIG_STMMAC_TIMER /* Clean IC while using timer */ if (likely(priv->tm->enable)) - priv->mac_type->ops->clear_tx_ic(desc); + priv->hw->desc->clear_tx_ic(desc); #endif /* To avoid raise condition */ - priv->mac_type->ops->set_tx_owner(first); + priv->hw->desc->set_tx_owner(first); priv->cur_tx++; @@ -1395,7 +1391,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) } RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); } - priv->mac_type->ops->set_rx_owner(p + entry); + priv->hw->desc->set_rx_owner(p + entry); } return; } @@ -1416,7 +1412,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) } #endif count = 0; - while (!priv->mac_type->ops->get_rx_owner(p)) { + while (!priv->hw->desc->get_rx_owner(p)) { int status; if (count >= limit) @@ -1429,15 +1425,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) prefetch(p_next); /* read the status of the incoming frame */ - status = (priv->mac_type->ops->rx_status(&priv->dev->stats, - &priv->xstats, p)); + status = (priv->hw->desc->rx_status(&priv->dev->stats, + &priv->xstats, p)); if (unlikely(status == discard_frame)) priv->dev->stats.rx_errors++; else { struct sk_buff *skb; /* Length should omit the CRC */ - int frame_len = - priv->mac_type->ops->get_rx_frame_len(p) - 4; + int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4; #ifdef STMMAC_RX_DEBUG if (frame_len > ETH_FRAME_LEN) @@ -1573,7 +1568,7 @@ static void stmmac_multicast_list(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); - priv->mac_type->ops->set_filter(dev); + priv->hw->mac->set_filter(dev); spin_unlock(&priv->lock); return; } @@ -1627,7 +1622,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) if (priv->is_gmac) { unsigned long ioaddr = dev->base_addr; /* To handle GMAC own interrupts */ - priv->mac_type->ops->host_irq_status(ioaddr); + priv->hw->mac->host_irq_status(ioaddr); } stmmac_dma_interrupt(dev); @@ -1748,7 +1743,7 @@ static int stmmac_probe(struct net_device *dev) netif_napi_add(dev, &priv->napi, stmmac_poll, 64); /* Get the MAC address */ - priv->mac_type->ops->get_umac_addr(dev->base_addr, dev->dev_addr, 0); + priv->hw->mac->get_umac_addr(dev->base_addr, dev->dev_addr, 0); if (!is_valid_ether_addr(dev->dev_addr)) pr_warning("\tno valid MAC address;" @@ -1790,9 +1785,9 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (!device) return -ENOMEM; - priv->mac_type = device; + priv->hw = device; - priv->wolenabled = priv->mac_type->hw.pmt; /* PMT supported */ + priv->wolenabled = priv->hw->pmt; /* PMT supported */ if (priv->wolenabled == PMT_SUPPORTED) priv->wolopts = WAKE_MAGIC; /* Magic Frame */ @@ -2048,18 +2043,17 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) stmmac_dma_stop_tx(dev->base_addr); stmmac_dma_stop_rx(dev->base_addr); /* Clear the Rx/Tx descriptors */ - priv->mac_type->ops->init_rx_desc(priv->dma_rx, - priv->dma_rx_size, dis_ic); - priv->mac_type->ops->init_tx_desc(priv->dma_tx, - priv->dma_tx_size); + priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, + dis_ic); + priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); stmmac_mac_disable_tx(dev->base_addr); if (device_may_wakeup(&(pdev->dev))) { /* Enable Power down mode by programming the PMT regs */ if (priv->wolenabled == PMT_SUPPORTED) - priv->mac_type->ops->pmt(dev->base_addr, - priv->wolopts); + priv->hw->mac->pmt(dev->base_addr, + priv->wolopts); } else { stmmac_mac_disable_rx(dev->base_addr); } @@ -2100,7 +2094,7 @@ static int stmmac_resume(struct platform_device *pdev) * from another devices (e.g. serial console). */ if (device_may_wakeup(&(pdev->dev))) if (priv->wolenabled == PMT_SUPPORTED) - priv->mac_type->ops->pmt(dev->base_addr, 0); + priv->hw->mac->pmt(dev->base_addr, 0); netif_device_attach(dev); diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c index 8498552a22fc..131e0a603711 100644 --- a/drivers/net/stmmac/stmmac_mdio.c +++ b/drivers/net/stmmac/stmmac_mdio.c @@ -48,8 +48,8 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); unsigned long ioaddr = ndev->base_addr; - unsigned int mii_address = priv->mac_type->hw.mii.addr; - unsigned int mii_data = priv->mac_type->hw.mii.data; + unsigned int mii_address = priv->hw->mii.addr; + unsigned int mii_data = priv->hw->mii.data; int data; u16 regValue = (((phyaddr << 11) & (0x0000F800)) | @@ -80,8 +80,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); unsigned long ioaddr = ndev->base_addr; - unsigned int mii_address = priv->mac_type->hw.mii.addr; - unsigned int mii_data = priv->mac_type->hw.mii.data; + unsigned int mii_address = priv->hw->mii.addr; + unsigned int mii_data = priv->hw->mii.data; u16 value = (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0))) @@ -112,7 +112,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus) struct net_device *ndev = bus->priv; struct stmmac_priv *priv = netdev_priv(ndev); unsigned long ioaddr = ndev->base_addr; - unsigned int mii_address = priv->mac_type->hw.mii.addr; + unsigned int mii_address = priv->hw->mii.addr; if (priv->phy_reset) { pr_debug("stmmac_mdio_reset: calling phy_reset\n"); -- GitLab From aec7ff278145280c2c78377aeb98feed02c8b636 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:18 +0000 Subject: [PATCH 0446/3892] stmmac: move the dma out from the main This patch moves the dma related functions (interrupt, start, stop etc.) out from the main driver code. This will help to support new DMA engines. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/Makefile | 2 +- drivers/net/stmmac/common.h | 209 ++++++---------------- drivers/net/stmmac/dwmac_dma.h | 107 +++++++++++ drivers/net/stmmac/dwmac_lib.c | 263 +++++++++++++++++++++++++++ drivers/net/stmmac/gmac.c | 9 + drivers/net/stmmac/mac100.c | 9 + drivers/net/stmmac/stmmac_ethtool.c | 1 + drivers/net/stmmac/stmmac_main.c | 268 ++++------------------------ 8 files changed, 481 insertions(+), 387 deletions(-) create mode 100644 drivers/net/stmmac/dwmac_dma.h create mode 100644 drivers/net/stmmac/dwmac_lib.c diff --git a/drivers/net/stmmac/Makefile b/drivers/net/stmmac/Makefile index b2d7a5564dfa..c8f499a71251 100644 --- a/drivers/net/stmmac/Makefile +++ b/drivers/net/stmmac/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o -stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ +stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o dwmac_lib.o \ mac100.o gmac.o $(stmmac-y) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index 95782ccf44b4..6f8fe64dd226 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -25,131 +25,6 @@ #include "descs.h" #include -/* ********************************************* - DMA CRS Control and Status Register Mapping - * *********************************************/ -#define DMA_BUS_MODE 0x00001000 /* Bus Mode */ -#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */ -#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */ -#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */ -#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */ -#define DMA_STATUS 0x00001014 /* Status Register */ -#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */ -#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */ -#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ -#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ -#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ - -/* ******************************** - DMA Control register defines - * ********************************/ -#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ -#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ - -/* ************************************** - DMA Interrupt Enable register defines - * **************************************/ -/**** NORMAL INTERRUPT ****/ -#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */ -#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */ -#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */ -#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */ -#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */ - -#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \ - DMA_INTR_ENA_TIE) - -/**** ABNORMAL INTERRUPT ****/ -#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */ -#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */ -#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */ -#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */ -#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */ -#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */ -#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */ -#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */ -#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */ -#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */ - -#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \ - DMA_INTR_ENA_UNE) - -/* DMA default interrupt mask */ -#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) - -/* **************************** - * DMA Status register defines - * ****************************/ -#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */ -#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ -#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int. */ -#define DMA_STATUS_GMI 0x08000000 -#define DMA_STATUS_GLI 0x04000000 -#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ -#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ -#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ -#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ -#define DMA_STATUS_TS_SHIFT 20 -#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ -#define DMA_STATUS_RS_SHIFT 17 -#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ -#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ -#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ -#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ -#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ -#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ -#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ -#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ -#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ -#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ -#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ -#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ -#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ -#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ -#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ - -/* Other defines */ -#define HASH_TABLE_SIZE 64 -#define PAUSE_TIME 0x200 - -/* Flow Control defines */ -#define FLOW_OFF 0 -#define FLOW_RX 1 -#define FLOW_TX 2 -#define FLOW_AUTO (FLOW_TX | FLOW_RX) - -/* DMA STORE-AND-FORWARD Operation Mode */ -#define SF_DMA_MODE 1 - -#define HW_CSUM 1 -#define NO_HW_CSUM 0 - -/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ -#define BUF_SIZE_16KiB 16384 -#define BUF_SIZE_8KiB 8192 -#define BUF_SIZE_4KiB 4096 -#define BUF_SIZE_2KiB 2048 - -/* Power Down and WOL */ -#define PMT_NOT_SUPPORTED 0 -#define PMT_SUPPORTED 1 - -/* Common MAC defines */ -#define MAC_CTRL_REG 0x00000000 /* MAC Control */ -#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ -#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */ - -/* MAC Management Counters register */ -#define MMC_CONTROL 0x00000100 /* MMC Control */ -#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */ -#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */ -#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */ -#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */ - -#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */ -#define MMC_CONTROL_MAX_FRM_SHIFT 3 -#define MMC_CONTROL_MAX_FRAME 0x7FF - struct stmmac_extra_stats { /* Transmit errors */ unsigned long tx_underflow ____cacheline_aligned; @@ -198,46 +73,56 @@ struct stmmac_extra_stats { unsigned long normal_irq_n; }; -/* GMAC core can compute the checksums in HW. */ -enum rx_frame_status { +#define HASH_TABLE_SIZE 64 +#define PAUSE_TIME 0x200 + +/* Flow Control defines */ +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + +#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +#define HW_CSUM 1 +#define NO_HW_CSUM 0 +enum rx_frame_status { /* IPC status */ good_frame = 0, discard_frame = 1, csum_none = 2, }; -static inline void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6], - unsigned int high, unsigned int low) -{ - unsigned long data; - - data = (addr[5] << 8) | addr[4]; - writel(data, ioaddr + high); - data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - writel(data, ioaddr + low); +enum tx_dma_irq_status { + tx_hard_error = 1, + tx_hard_error_bump_tc = 2, + handle_tx_rx = 3, +}; - return; -} +/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ +#define BUF_SIZE_16KiB 16384 +#define BUF_SIZE_8KiB 8192 +#define BUF_SIZE_4KiB 4096 +#define BUF_SIZE_2KiB 2048 -static inline void stmmac_get_mac_addr(unsigned long ioaddr, - unsigned char *addr, unsigned int high, - unsigned int low) -{ - unsigned int hi_addr, lo_addr; +/* Power Down and WOL */ +#define PMT_NOT_SUPPORTED 0 +#define PMT_SUPPORTED 1 - /* Read the MAC address from the hardware */ - hi_addr = readl(ioaddr + high); - lo_addr = readl(ioaddr + low); +/* Common MAC defines */ +#define MAC_CTRL_REG 0x00000000 /* MAC Control */ +#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ +#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */ - /* Extract the MAC address from the high and low words */ - addr[0] = lo_addr & 0xff; - addr[1] = (lo_addr >> 8) & 0xff; - addr[2] = (lo_addr >> 16) & 0xff; - addr[3] = (lo_addr >> 24) & 0xff; - addr[4] = hi_addr & 0xff; - addr[5] = (hi_addr >> 8) & 0xff; +/* MAC Management Counters register */ +#define MMC_CONTROL 0x00000100 /* MMC Control */ +#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */ +#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */ +#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */ +#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */ - return; -} +#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */ +#define MMC_CONTROL_MAX_FRM_SHIFT 3 +#define MMC_CONTROL_MAX_FRAME 0x7FF struct stmmac_desc_ops { /* DMA RX descriptor ring initialization */ @@ -287,6 +172,15 @@ struct stmmac_dma_ops { /* To track extra statistic (if supported) */ void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, unsigned long ioaddr); + void (*enable_dma_transmission) (unsigned long ioaddr); + void (*enable_dma_irq) (unsigned long ioaddr); + void (*disable_dma_irq) (unsigned long ioaddr); + void (*start_tx) (unsigned long ioaddr); + void (*stop_tx) (unsigned long ioaddr); + void (*start_rx) (unsigned long ioaddr); + void (*stop_rx) (unsigned long ioaddr); + int (*dma_interrupt) (unsigned long ioaddr, + struct stmmac_extra_stats *x); }; struct stmmac_ops { @@ -332,3 +226,8 @@ struct mac_device_info { struct mac_device_info *gmac_setup(unsigned long addr); struct mac_device_info *mac100_setup(unsigned long addr); + +extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6], + unsigned int high, unsigned int low); +extern void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr, + unsigned int high, unsigned int low); diff --git a/drivers/net/stmmac/dwmac_dma.h b/drivers/net/stmmac/dwmac_dma.h new file mode 100644 index 000000000000..de848d9f6060 --- /dev/null +++ b/drivers/net/stmmac/dwmac_dma.h @@ -0,0 +1,107 @@ +/******************************************************************************* + DWMAC DMA Header file. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +/* DMA CRS Control and Status Register Mapping */ +#define DMA_BUS_MODE 0x00001000 /* Bus Mode */ +#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */ +#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */ +#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */ +#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */ +#define DMA_STATUS 0x00001014 /* Status Register */ +#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */ +#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */ +#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ +#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ +#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ + +/* DMA Control register defines */ +#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ +#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ + +/* DMA Normal interrupt */ +#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */ +#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */ +#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */ +#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */ +#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */ + +#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \ + DMA_INTR_ENA_TIE) + +/* DMA Abnormal interrupt */ +#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */ +#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */ +#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */ +#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */ +#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */ +#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */ +#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */ +#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */ +#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */ + +#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \ + DMA_INTR_ENA_UNE) + +/* DMA default interrupt mask */ +#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) + +/* DMA Status register defines */ +#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */ +#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ +#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ +#define DMA_STATUS_GMI 0x08000000 +#define DMA_STATUS_GLI 0x04000000 +#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ +#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ +#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +#define DMA_STATUS_TS_SHIFT 20 +#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +#define DMA_STATUS_RS_SHIFT 17 +#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ +#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ +#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ +#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ +#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ +#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ +#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ +#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ +#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ +#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ +#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ +#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ + +extern void dwmac_enable_dma_transmission(unsigned long ioaddr); +extern void dwmac_enable_dma_irq(unsigned long ioaddr); +extern void dwmac_disable_dma_irq(unsigned long ioaddr); +extern void dwmac_dma_start_tx(unsigned long ioaddr); +extern void dwmac_dma_stop_tx(unsigned long ioaddr); +extern void dwmac_dma_start_rx(unsigned long ioaddr); +extern void dwmac_dma_stop_rx(unsigned long ioaddr); +extern int dwmac_dma_interrupt(unsigned long ioaddr, + struct stmmac_extra_stats *x); diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c new file mode 100644 index 000000000000..d4adb1eaa447 --- /dev/null +++ b/drivers/net/stmmac/dwmac_lib.c @@ -0,0 +1,263 @@ +/******************************************************************************* + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "common.h" +#include "dwmac_dma.h" + +#undef DWMAC_DMA_DEBUG +#ifdef DWMAC_DMA_DEBUG +#define DBG(fmt, args...) printk(fmt, ## args) +#else +#define DBG(fmt, args...) do { } while (0) +#endif + +/* CSR1 enables the transmit DMA to check for new descriptor */ +void dwmac_enable_dma_transmission(unsigned long ioaddr) +{ + writel(1, ioaddr + DMA_XMT_POLL_DEMAND); +} + +void dwmac_enable_dma_irq(unsigned long ioaddr) +{ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); +} + +void dwmac_disable_dma_irq(unsigned long ioaddr) +{ + writel(0, ioaddr + DMA_INTR_ENA); +} + +void dwmac_dma_start_tx(unsigned long ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value |= DMA_CONTROL_ST; + writel(value, ioaddr + DMA_CONTROL); + return; +} + +void dwmac_dma_stop_tx(unsigned long ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value &= ~DMA_CONTROL_ST; + writel(value, ioaddr + DMA_CONTROL); + return; +} + +void dwmac_dma_start_rx(unsigned long ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value |= DMA_CONTROL_SR; + writel(value, ioaddr + DMA_CONTROL); + + return; +} + +void dwmac_dma_stop_rx(unsigned long ioaddr) +{ + u32 value = readl(ioaddr + DMA_CONTROL); + value &= ~DMA_CONTROL_SR; + writel(value, ioaddr + DMA_CONTROL); + + return; +} + +#ifdef DWMAC_DMA_DEBUG +static void show_tx_process_state(unsigned int status) +{ + unsigned int state; + state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT; + + switch (state) { + case 0: + pr_info("- TX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- TX (Running):Fetching the Tx desc\n"); + break; + case 2: + pr_info("- TX (Running): Waiting for end of tx\n"); + break; + case 3: + pr_info("- TX (Running): Reading the data " + "and queuing the data into the Tx buf\n"); + break; + case 6: + pr_info("- TX (Suspended): Tx Buff Underflow " + "or an unavailable Transmit descriptor\n"); + break; + case 7: + pr_info("- TX (Running): Closing Tx descriptor\n"); + break; + default: + break; + } + return; +} + +static void show_rx_process_state(unsigned int status) +{ + unsigned int state; + state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT; + + switch (state) { + case 0: + pr_info("- RX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- RX (Running): Fetching the Rx desc\n"); + break; + case 2: + pr_info("- RX (Running):Checking for end of pkt\n"); + break; + case 3: + pr_info("- RX (Running): Waiting for Rx pkt\n"); + break; + case 4: + pr_info("- RX (Suspended): Unavailable Rx buf\n"); + break; + case 5: + pr_info("- RX (Running): Closing Rx descriptor\n"); + break; + case 6: + pr_info("- RX(Running): Flushing the current frame" + " from the Rx buf\n"); + break; + case 7: + pr_info("- RX (Running): Queuing the Rx frame" + " from the Rx buf into memory\n"); + break; + default: + break; + } + return; +} +#endif + +int dwmac_dma_interrupt(unsigned long ioaddr, + struct stmmac_extra_stats *x) +{ + int ret = 0; + /* read the status register (CSR5) */ + u32 intr_status = readl(ioaddr + DMA_STATUS); + + DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status); +#ifdef DWMAC_DMA_DEBUG + /* It displays the DMA process states (CSR5 register) */ + show_tx_process_state(intr_status); + show_rx_process_state(intr_status); +#endif + /* ABNORMAL interrupts */ + if (unlikely(intr_status & DMA_STATUS_AIS)) { + DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: "); + if (unlikely(intr_status & DMA_STATUS_UNF)) { + DBG(INFO, "transmit underflow\n"); + ret = tx_hard_error_bump_tc; + x->tx_undeflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TJT)) { + DBG(INFO, "transmit jabber\n"); + x->tx_jabber_irq++; + } + if (unlikely(intr_status & DMA_STATUS_OVF)) { + DBG(INFO, "recv overflow\n"); + x->rx_overflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RU)) { + DBG(INFO, "receive buffer unavailable\n"); + x->rx_buf_unav_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RPS)) { + DBG(INFO, "receive process stopped\n"); + x->rx_process_stopped_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RWT)) { + DBG(INFO, "receive watchdog\n"); + x->rx_watchdog_irq++; + } + if (unlikely(intr_status & DMA_STATUS_ETI)) { + DBG(INFO, "transmit early interrupt\n"); + x->tx_early_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TPS)) { + DBG(INFO, "transmit process stopped\n"); + x->tx_process_stopped_irq++; + ret = tx_hard_error; + } + if (unlikely(intr_status & DMA_STATUS_FBI)) { + DBG(INFO, "fatal bus error\n"); + x->fatal_bus_error_irq++; + ret = tx_hard_error; + } + } + /* TX/RX NORMAL interrupts */ + if (intr_status & DMA_STATUS_NIS) { + x->normal_irq_n++; + if (likely((intr_status & DMA_STATUS_RI) || + (intr_status & (DMA_STATUS_TI)))) + ret = handle_tx_rx; + } + /* Optional hardware blocks, interrupts should be disabled */ + if (unlikely(intr_status & + (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI))) + pr_info("%s: unexpected status %08x\n", __func__, intr_status); + /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ + writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); + + DBG(INFO, "\n\n"); + return ret; +} + + +void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6], + unsigned int high, unsigned int low) +{ + unsigned long data; + + data = (addr[5] << 8) | addr[4]; + writel(data, ioaddr + high); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, ioaddr + low); + + return; +} + +void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr, + unsigned int high, unsigned int low) +{ + unsigned int hi_addr, lo_addr; + + /* Read the MAC address from the hardware */ + hi_addr = readl(ioaddr + high); + lo_addr = readl(ioaddr + low); + + /* Extract the MAC address from the high and low words */ + addr[0] = lo_addr & 0xff; + addr[1] = (lo_addr >> 8) & 0xff; + addr[2] = (lo_addr >> 16) & 0xff; + addr[3] = (lo_addr >> 24) & 0xff; + addr[4] = hi_addr & 0xff; + addr[5] = (hi_addr >> 8) & 0xff; + + return; +} + diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c index cf199d969227..07880922ff46 100644 --- a/drivers/net/stmmac/gmac.c +++ b/drivers/net/stmmac/gmac.c @@ -31,6 +31,7 @@ #include "stmmac.h" #include "gmac.h" +#include "dwmac_dma.h" #undef GMAC_DEBUG /*#define GMAC_DEBUG*/ @@ -646,6 +647,14 @@ struct stmmac_dma_ops gmac_dma_ops = { .dump_regs = gmac_dump_dma_regs, .dma_mode = gmac_dma_operation_mode, .dma_diagnostic_fr = gmac_dma_diagnostic_fr, + .enable_dma_transmission = dwmac_enable_dma_transmission, + .enable_dma_irq = dwmac_enable_dma_irq, + .disable_dma_irq = dwmac_disable_dma_irq, + .start_tx = dwmac_dma_start_tx, + .stop_tx = dwmac_dma_stop_tx, + .start_rx = dwmac_dma_start_rx, + .stop_rx = dwmac_dma_stop_rx, + .dma_interrupt = dwmac_dma_interrupt, }; struct stmmac_desc_ops gmac_desc_ops = { diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/mac100.c index 45d0457ddb6e..b675f7c67f6e 100644 --- a/drivers/net/stmmac/mac100.c +++ b/drivers/net/stmmac/mac100.c @@ -33,6 +33,7 @@ #include "common.h" #include "mac100.h" +#include "dwmac_dma.h" #undef MAC100_DEBUG /*#define MAC100_DEBUG*/ @@ -483,6 +484,14 @@ struct stmmac_dma_ops mac100_dma_ops = { .dump_regs = mac100_dump_dma_regs, .dma_mode = mac100_dma_operation_mode, .dma_diagnostic_fr = mac100_dma_diagnostic_fr, + .enable_dma_transmission = dwmac_enable_dma_transmission, + .enable_dma_irq = dwmac_enable_dma_irq, + .disable_dma_irq = dwmac_disable_dma_irq, + .start_tx = dwmac_dma_start_tx, + .stop_tx = dwmac_dma_stop_tx, + .start_rx = dwmac_dma_start_rx, + .stop_rx = dwmac_dma_stop_rx, + .dma_interrupt = dwmac_dma_interrupt, }; struct stmmac_desc_ops mac100_desc_ops = { diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 9c7ce1ea3aea..0abeff6193a1 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -28,6 +28,7 @@ #include #include "stmmac.h" +#include "dwmac_dma.h" #define REG_SPACE_SIZE 0x1054 #define MAC100_ETHTOOL_NAME "st_mac100" diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 86e910300969..e6c5a3cf4af2 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -571,50 +571,6 @@ static void free_dma_desc_resources(struct stmmac_priv *priv) return; } -/** - * stmmac_dma_start_tx - * @ioaddr: device I/O address - * Description: this function starts the DMA tx process. - */ -static void stmmac_dma_start_tx(unsigned long ioaddr) -{ - u32 value = readl(ioaddr + DMA_CONTROL); - value |= DMA_CONTROL_ST; - writel(value, ioaddr + DMA_CONTROL); - return; -} - -static void stmmac_dma_stop_tx(unsigned long ioaddr) -{ - u32 value = readl(ioaddr + DMA_CONTROL); - value &= ~DMA_CONTROL_ST; - writel(value, ioaddr + DMA_CONTROL); - return; -} - -/** - * stmmac_dma_start_rx - * @ioaddr: device I/O address - * Description: this function starts the DMA rx process. - */ -static void stmmac_dma_start_rx(unsigned long ioaddr) -{ - u32 value = readl(ioaddr + DMA_CONTROL); - value |= DMA_CONTROL_SR; - writel(value, ioaddr + DMA_CONTROL); - - return; -} - -static void stmmac_dma_stop_rx(unsigned long ioaddr) -{ - u32 value = readl(ioaddr + DMA_CONTROL); - value &= ~DMA_CONTROL_SR; - writel(value, ioaddr + DMA_CONTROL); - - return; -} - /** * stmmac_dma_operation_mode - HW DMA operation mode * @priv : pointer to the private device structure. @@ -646,88 +602,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) return; } -#ifdef STMMAC_DEBUG -/** - * show_tx_process_state - * @status: tx descriptor status field - * Description: it shows the Transmit Process State for CSR5[22:20] - */ -static void show_tx_process_state(unsigned int status) -{ - unsigned int state; - state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT; - - switch (state) { - case 0: - pr_info("- TX (Stopped): Reset or Stop command\n"); - break; - case 1: - pr_info("- TX (Running):Fetching the Tx desc\n"); - break; - case 2: - pr_info("- TX (Running): Waiting for end of tx\n"); - break; - case 3: - pr_info("- TX (Running): Reading the data " - "and queuing the data into the Tx buf\n"); - break; - case 6: - pr_info("- TX (Suspended): Tx Buff Underflow " - "or an unavailable Transmit descriptor\n"); - break; - case 7: - pr_info("- TX (Running): Closing Tx descriptor\n"); - break; - default: - break; - } - return; -} - -/** - * show_rx_process_state - * @status: rx descriptor status field - * Description: it shows the Receive Process State for CSR5[19:17] - */ -static void show_rx_process_state(unsigned int status) -{ - unsigned int state; - state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT; - - switch (state) { - case 0: - pr_info("- RX (Stopped): Reset or Stop command\n"); - break; - case 1: - pr_info("- RX (Running): Fetching the Rx desc\n"); - break; - case 2: - pr_info("- RX (Running):Checking for end of pkt\n"); - break; - case 3: - pr_info("- RX (Running): Waiting for Rx pkt\n"); - break; - case 4: - pr_info("- RX (Suspended): Unavailable Rx buf\n"); - break; - case 5: - pr_info("- RX (Running): Closing Rx descriptor\n"); - break; - case 6: - pr_info("- RX(Running): Flushing the current frame" - " from the Rx buf\n"); - break; - case 7: - pr_info("- RX (Running): Queuing the Rx frame" - " from the Rx buf into memory\n"); - break; - default: - break; - } - return; -} -#endif - /** * stmmac_tx: * @priv: private driver structure @@ -811,7 +685,7 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv) priv->tm->timer_start(tmrate); else #endif - writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA); + priv->hw->dma->enable_dma_irq(priv->dev->base_addr); } static inline void stmmac_disable_irq(struct stmmac_priv *priv) @@ -821,7 +695,7 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv) priv->tm->timer_stop(); else #endif - writel(0, priv->dev->base_addr + DMA_INTR_ENA); + priv->hw->dma->disable_dma_irq(priv->dev->base_addr); } static int stmmac_has_work(struct stmmac_priv *priv) @@ -880,12 +754,12 @@ static void stmmac_tx_err(struct stmmac_priv *priv) { netif_stop_queue(priv->dev); - stmmac_dma_stop_tx(priv->dev->base_addr); + priv->hw->dma->stop_tx(priv->dev->base_addr); dma_free_tx_skbufs(priv); priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); priv->dirty_tx = 0; priv->cur_tx = 0; - stmmac_dma_start_tx(priv->dev->base_addr); + priv->hw->dma->start_tx(priv->dev->base_addr); priv->dev->stats.tx_errors++; netif_wake_queue(priv->dev); @@ -893,95 +767,27 @@ static void stmmac_tx_err(struct stmmac_priv *priv) return; } -/** - * stmmac_dma_interrupt - Interrupt handler for the driver - * @dev: net device structure - * Description: Interrupt handler for the driver (DMA). - */ -static void stmmac_dma_interrupt(struct net_device *dev) -{ - unsigned long ioaddr = dev->base_addr; - struct stmmac_priv *priv = netdev_priv(dev); - /* read the status register (CSR5) */ - u32 intr_status = readl(ioaddr + DMA_STATUS); - - DBG(intr, INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status); -#ifdef STMMAC_DEBUG - /* It displays the DMA transmit process state (CSR5 register) */ - if (netif_msg_tx_done(priv)) - show_tx_process_state(intr_status); - if (netif_msg_rx_status(priv)) - show_rx_process_state(intr_status); -#endif - /* ABNORMAL interrupts */ - if (unlikely(intr_status & DMA_STATUS_AIS)) { - DBG(intr, INFO, "CSR5[15] DMA ABNORMAL IRQ: "); - if (unlikely(intr_status & DMA_STATUS_UNF)) { - DBG(intr, INFO, "transmit underflow\n"); - if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { - /* Try to bump up the threshold */ - tc += 64; - priv->hw->dma->dma_mode(ioaddr, tc, - SF_DMA_MODE); - priv->xstats.threshold = tc; - } - stmmac_tx_err(priv); - priv->xstats.tx_undeflow_irq++; - } - if (unlikely(intr_status & DMA_STATUS_TJT)) { - DBG(intr, INFO, "transmit jabber\n"); - priv->xstats.tx_jabber_irq++; - } - if (unlikely(intr_status & DMA_STATUS_OVF)) { - DBG(intr, INFO, "recv overflow\n"); - priv->xstats.rx_overflow_irq++; - } - if (unlikely(intr_status & DMA_STATUS_RU)) { - DBG(intr, INFO, "receive buffer unavailable\n"); - priv->xstats.rx_buf_unav_irq++; - } - if (unlikely(intr_status & DMA_STATUS_RPS)) { - DBG(intr, INFO, "receive process stopped\n"); - priv->xstats.rx_process_stopped_irq++; - } - if (unlikely(intr_status & DMA_STATUS_RWT)) { - DBG(intr, INFO, "receive watchdog\n"); - priv->xstats.rx_watchdog_irq++; - } - if (unlikely(intr_status & DMA_STATUS_ETI)) { - DBG(intr, INFO, "transmit early interrupt\n"); - priv->xstats.tx_early_irq++; - } - if (unlikely(intr_status & DMA_STATUS_TPS)) { - DBG(intr, INFO, "transmit process stopped\n"); - priv->xstats.tx_process_stopped_irq++; - stmmac_tx_err(priv); - } - if (unlikely(intr_status & DMA_STATUS_FBI)) { - DBG(intr, INFO, "fatal bus error\n"); - priv->xstats.fatal_bus_error_irq++; - stmmac_tx_err(priv); +static void stmmac_dma_interrupt(struct stmmac_priv *priv) +{ + unsigned long ioaddr = priv->dev->base_addr; + int status; + + status = priv->hw->dma->dma_interrupt(priv->dev->base_addr, + &priv->xstats); + if (likely(status == handle_tx_rx)) + _stmmac_schedule(priv); + + else if (unlikely(status == tx_hard_error_bump_tc)) { + /* Try to bump up the dma threshold on this failure */ + if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { + tc += 64; + priv->hw->dma->dma_mode(ioaddr, tc, SF_DMA_MODE); + priv->xstats.threshold = tc; } - } - - /* TX/RX NORMAL interrupts */ - if (intr_status & DMA_STATUS_NIS) { - priv->xstats.normal_irq_n++; - if (likely((intr_status & DMA_STATUS_RI) || - (intr_status & (DMA_STATUS_TI)))) - _stmmac_schedule(priv); - } - - /* Optional hardware blocks, interrupts should be disabled */ - if (unlikely(intr_status & - (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI))) - pr_info("%s: unexpected status %08x\n", __func__, intr_status); - - /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ - writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); - - DBG(intr, INFO, "\n\n"); + stmmac_tx_err(priv); + } else if (unlikely(status == tx_hard_error)) + stmmac_tx_err(priv); return; } @@ -1089,8 +895,8 @@ static int stmmac_open(struct net_device *dev) /* Start the ball rolling... */ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); - stmmac_dma_start_tx(ioaddr); - stmmac_dma_start_rx(ioaddr); + priv->hw->dma->start_tx(ioaddr); + priv->hw->dma->start_rx(ioaddr); #ifdef CONFIG_STMMAC_TIMER priv->tm->timer_start(tmrate); @@ -1142,8 +948,8 @@ static int stmmac_release(struct net_device *dev) free_irq(dev->irq, dev); /* Stop TX/RX DMA and clear the descriptors */ - stmmac_dma_stop_tx(dev->base_addr); - stmmac_dma_stop_rx(dev->base_addr); + priv->hw->dma->stop_tx(dev->base_addr); + priv->hw->dma->stop_rx(dev->base_addr); /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv); @@ -1227,7 +1033,6 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size, csum_insertion); priv->hw->desc->set_tx_owner(desc); - priv->tx_skbuff[entry] = NULL; } else { desc->des2 = dma_map_single(priv->device, skb->data, @@ -1353,8 +1158,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; - /* CSR1 enables the transmit DMA to check for new descriptor */ - writel(1, dev->base_addr + DMA_XMT_POLL_DEMAND); + priv->hw->dma->enable_dma_transmission(dev->base_addr); return NETDEV_TX_OK; } @@ -1624,7 +1428,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) /* To handle GMAC own interrupts */ priv->hw->mac->host_irq_status(ioaddr); } - stmmac_dma_interrupt(dev); + + stmmac_dma_interrupt(priv); return IRQ_HANDLED; } @@ -1988,12 +1793,13 @@ out: static int stmmac_dvr_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); struct resource *res; pr_info("%s:\n\tremoving driver", __func__); - stmmac_dma_stop_rx(ndev->base_addr); - stmmac_dma_stop_tx(ndev->base_addr); + priv->hw->dma->stop_rx(ndev->base_addr); + priv->hw->dma->stop_tx(ndev->base_addr); stmmac_mac_disable_rx(ndev->base_addr); stmmac_mac_disable_tx(ndev->base_addr); @@ -2040,8 +1846,8 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) napi_disable(&priv->napi); /* Stop TX/RX DMA */ - stmmac_dma_stop_tx(dev->base_addr); - stmmac_dma_stop_rx(dev->base_addr); + priv->hw->dma->stop_tx(dev->base_addr); + priv->hw->dma->stop_rx(dev->base_addr); /* Clear the Rx/Tx descriptors */ priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, dis_ic); @@ -2101,8 +1907,8 @@ static int stmmac_resume(struct platform_device *pdev) /* Enable the MAC and DMA */ stmmac_mac_enable_rx(ioaddr); stmmac_mac_enable_tx(ioaddr); - stmmac_dma_start_tx(ioaddr); - stmmac_dma_start_rx(ioaddr); + priv->hw->dma->start_tx(ioaddr); + priv->hw->dma->start_rx(ioaddr); #ifdef CONFIG_STMMAC_TIMER priv->tm->timer_start(tmrate); -- GitLab From 7e848ae113ca7442ba6b44168fa2238224f37e8a Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:19 +0000 Subject: [PATCH 0447/3892] stmmac: rename mac100 as dwmac100 and fix spare coding style This patch renames the mac100.[ch] as dwmac100.[ch]; this looks more specific and appropriate for these chip series. The patch also fixes some spare coding style issues. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/Makefile | 2 +- drivers/net/stmmac/common.h | 2 +- drivers/net/stmmac/{mac100.c => dwmac100.c} | 179 ++++++++++---------- drivers/net/stmmac/{mac100.h => dwmac100.h} | 0 drivers/net/stmmac/stmmac_main.c | 2 +- 5 files changed, 95 insertions(+), 90 deletions(-) rename drivers/net/stmmac/{mac100.c => dwmac100.c} (73%) rename drivers/net/stmmac/{mac100.h => dwmac100.h} (100%) diff --git a/drivers/net/stmmac/Makefile b/drivers/net/stmmac/Makefile index c8f499a71251..2ed83859fd59 100644 --- a/drivers/net/stmmac/Makefile +++ b/drivers/net/stmmac/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o dwmac_lib.o \ - mac100.o gmac.o $(stmmac-y) + dwmac100.o gmac.o $(stmmac-y) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index 6f8fe64dd226..987faaaa1920 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -225,7 +225,7 @@ struct mac_device_info { }; struct mac_device_info *gmac_setup(unsigned long addr); -struct mac_device_info *mac100_setup(unsigned long addr); +struct mac_device_info *dwmac100_setup(unsigned long addr); extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6], unsigned int high, unsigned int low); diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/dwmac100.c similarity index 73% rename from drivers/net/stmmac/mac100.c rename to drivers/net/stmmac/dwmac100.c index b675f7c67f6e..010c8b206359 100644 --- a/drivers/net/stmmac/mac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -32,18 +32,18 @@ #include #include "common.h" -#include "mac100.h" +#include "dwmac100.h" #include "dwmac_dma.h" -#undef MAC100_DEBUG -/*#define MAC100_DEBUG*/ -#ifdef MAC100_DEBUG +#undef DWMAC100_DEBUG +/*#define DWMAC100_DEBUG*/ +#ifdef DWMAC100_DEBUG #define DBG(fmt, args...) printk(fmt, ## args) #else #define DBG(fmt, args...) do { } while (0) #endif -static void mac100_core_init(unsigned long ioaddr) +static void dwmac100_core_init(unsigned long ioaddr) { u32 value = readl(ioaddr + MAC_CONTROL); @@ -55,43 +55,43 @@ static void mac100_core_init(unsigned long ioaddr) return; } -static void mac100_dump_mac_regs(unsigned long ioaddr) +static void dwmac100_dump_mac_regs(unsigned long ioaddr) { pr_info("\t----------------------------------------------\n" - "\t MAC100 CSR (base addr = 0x%8x)\n" - "\t----------------------------------------------\n", - (unsigned int)ioaddr); + "\t DWMAC 100 CSR (base addr = 0x%8x)\n" + "\t----------------------------------------------\n", + (unsigned int)ioaddr); pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL, - readl(ioaddr + MAC_CONTROL)); + readl(ioaddr + MAC_CONTROL)); pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH, - readl(ioaddr + MAC_ADDR_HIGH)); + readl(ioaddr + MAC_ADDR_HIGH)); pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW, - readl(ioaddr + MAC_ADDR_LOW)); + readl(ioaddr + MAC_ADDR_LOW)); pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n", - MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH)); + MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH)); pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n", - MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW)); + MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW)); pr_info("\tflow control (offset 0x%x): 0x%08x\n", MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL)); pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1, - readl(ioaddr + MAC_VLAN1)); + readl(ioaddr + MAC_VLAN1)); pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2, - readl(ioaddr + MAC_VLAN2)); + readl(ioaddr + MAC_VLAN2)); pr_info("\n\tMAC management counter registers\n"); pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n", - MMC_CONTROL, readl(ioaddr + MMC_CONTROL)); + MMC_CONTROL, readl(ioaddr + MMC_CONTROL)); pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n", - MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR)); + MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR)); pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n", - MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR)); + MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR)); pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n", - MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK)); + MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK)); pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n", - MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK)); + MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK)); return; } -static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, +static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx) { u32 value = readl(ioaddr + DMA_BUS_MODE); @@ -118,7 +118,7 @@ static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, /* Store and Forward capability is not used at all.. * The transmit threshold can be programmed by * setting the TTC bits in the DMA control register.*/ -static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode, +static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode, int rxmode) { u32 csr6 = readl(ioaddr + DMA_CONTROL); @@ -135,11 +135,11 @@ static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode, return; } -static void mac100_dump_dma_regs(unsigned long ioaddr) +static void dwmac100_dump_dma_regs(unsigned long ioaddr) { int i; - DBG(KERN_DEBUG "MAC100 DMA CSR \n"); + DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n"); for (i = 0; i < 9; i++) pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i, (DMA_BUS_MODE + i * 4), @@ -152,8 +152,9 @@ static void mac100_dump_dma_regs(unsigned long ioaddr) } /* DMA controller has two counters to track the number of - the receive missed frames. */ -static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x, + * the receive missed frames. */ +static void dwmac100_dma_diagnostic_fr(void *data, + struct stmmac_extra_stats *x, unsigned long ioaddr) { struct net_device_stats *stats = (struct net_device_stats *)data; @@ -182,7 +183,8 @@ static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x, return; } -static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, +static int dwmac100_get_tx_frame_status(void *data, + struct stmmac_extra_stats *x, struct dma_desc *p, unsigned long ioaddr) { int ret = 0; @@ -218,7 +220,7 @@ static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, return ret; } -static int mac100_get_tx_len(struct dma_desc *p) +static int dwmac100_get_tx_len(struct dma_desc *p) { return p->des01.tx.buffer1_size; } @@ -227,14 +229,15 @@ static int mac100_get_tx_len(struct dma_desc *p) * and, if required, updates the multicast statistics. * In case of success, it returns csum_none becasue the device * is not able to compute the csum in HW. */ -static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x, +static int dwmac100_get_rx_frame_status(void *data, + struct stmmac_extra_stats *x, struct dma_desc *p) { int ret = csum_none; struct net_device_stats *stats = (struct net_device_stats *)data; if (unlikely(p->des01.rx.last_descriptor == 0)) { - pr_warning("mac100 Error: Oversized Ethernet " + pr_warning("dwmac100 Error: Oversized Ethernet " "frame spanned multiple buffers\n"); stats->rx_length_errors++; return discard_frame; @@ -277,24 +280,24 @@ static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x, return ret; } -static void mac100_irq_status(unsigned long ioaddr) +static void dwmac100_irq_status(unsigned long ioaddr) { return; } -static void mac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr, +static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr, unsigned int reg_n) { stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void mac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr, +static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr, unsigned int reg_n) { stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void mac100_set_filter(struct net_device *dev) +static void dwmac100_set_filter(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; u32 value = readl(ioaddr + MAC_CONTROL); @@ -320,8 +323,8 @@ static void mac100_set_filter(struct net_device *dev) /* Perfect filter mode for physical address and Hash filter for multicast */ value |= MAC_CONTROL_HP; - value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF - | MAC_CONTROL_HO); + value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | + MAC_CONTROL_IF | MAC_CONTROL_HO); memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; @@ -348,7 +351,7 @@ static void mac100_set_filter(struct net_device *dev) return; } -static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex, +static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex, unsigned int fc, unsigned int pause_time) { unsigned int flow = MAC_FLOW_CTRL_ENABLE; @@ -360,13 +363,15 @@ static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex, return; } -/* No PMT module supported in our SoC for the Ethernet Controller. */ -static void mac100_pmt(unsigned long ioaddr, unsigned long mode) +/* No PMT module supported for this Ethernet Controller. + * Tested on ST platforms only. + */ +static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode) { return; } -static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size, +static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size, int disable_rx_ic) { int i; @@ -382,7 +387,7 @@ static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size, return; } -static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size) +static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size) { int i; for (i = 0; i < ring_size; i++) { @@ -394,32 +399,32 @@ static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size) return; } -static int mac100_get_tx_owner(struct dma_desc *p) +static int dwmac100_get_tx_owner(struct dma_desc *p) { return p->des01.tx.own; } -static int mac100_get_rx_owner(struct dma_desc *p) +static int dwmac100_get_rx_owner(struct dma_desc *p) { return p->des01.rx.own; } -static void mac100_set_tx_owner(struct dma_desc *p) +static void dwmac100_set_tx_owner(struct dma_desc *p) { p->des01.tx.own = 1; } -static void mac100_set_rx_owner(struct dma_desc *p) +static void dwmac100_set_rx_owner(struct dma_desc *p) { p->des01.rx.own = 1; } -static int mac100_get_tx_ls(struct dma_desc *p) +static int dwmac100_get_tx_ls(struct dma_desc *p) { return p->des01.tx.last_segment; } -static void mac100_release_tx_desc(struct dma_desc *p) +static void dwmac100_release_tx_desc(struct dma_desc *p) { int ter = p->des01.tx.end_ring; @@ -445,45 +450,45 @@ static void mac100_release_tx_desc(struct dma_desc *p) return; } -static void mac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, +static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, int csum_flag) { p->des01.tx.first_segment = is_fs; p->des01.tx.buffer1_size = len; } -static void mac100_clear_tx_ic(struct dma_desc *p) +static void dwmac100_clear_tx_ic(struct dma_desc *p) { p->des01.tx.interrupt = 0; } -static void mac100_close_tx_desc(struct dma_desc *p) +static void dwmac100_close_tx_desc(struct dma_desc *p) { p->des01.tx.last_segment = 1; p->des01.tx.interrupt = 1; } -static int mac100_get_rx_frame_len(struct dma_desc *p) +static int dwmac100_get_rx_frame_len(struct dma_desc *p) { return p->des01.rx.frame_length; } -struct stmmac_ops mac100_ops = { - .core_init = mac100_core_init, - .dump_regs = mac100_dump_mac_regs, - .host_irq_status = mac100_irq_status, - .set_filter = mac100_set_filter, - .flow_ctrl = mac100_flow_ctrl, - .pmt = mac100_pmt, - .set_umac_addr = mac100_set_umac_addr, - .get_umac_addr = mac100_get_umac_addr, +struct stmmac_ops dwmac100_ops = { + .core_init = dwmac100_core_init, + .dump_regs = dwmac100_dump_mac_regs, + .host_irq_status = dwmac100_irq_status, + .set_filter = dwmac100_set_filter, + .flow_ctrl = dwmac100_flow_ctrl, + .pmt = dwmac100_pmt, + .set_umac_addr = dwmac100_set_umac_addr, + .get_umac_addr = dwmac100_get_umac_addr, }; -struct stmmac_dma_ops mac100_dma_ops = { - .init = mac100_dma_init, - .dump_regs = mac100_dump_dma_regs, - .dma_mode = mac100_dma_operation_mode, - .dma_diagnostic_fr = mac100_dma_diagnostic_fr, +struct stmmac_dma_ops dwmac100_dma_ops = { + .init = dwmac100_dma_init, + .dump_regs = dwmac100_dump_dma_regs, + .dma_mode = dwmac100_dma_operation_mode, + .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr, .enable_dma_transmission = dwmac_enable_dma_transmission, .enable_dma_irq = dwmac_enable_dma_irq, .disable_dma_irq = dwmac_disable_dma_irq, @@ -494,35 +499,35 @@ struct stmmac_dma_ops mac100_dma_ops = { .dma_interrupt = dwmac_dma_interrupt, }; -struct stmmac_desc_ops mac100_desc_ops = { - .tx_status = mac100_get_tx_frame_status, - .rx_status = mac100_get_rx_frame_status, - .get_tx_len = mac100_get_tx_len, - .init_rx_desc = mac100_init_rx_desc, - .init_tx_desc = mac100_init_tx_desc, - .get_tx_owner = mac100_get_tx_owner, - .get_rx_owner = mac100_get_rx_owner, - .release_tx_desc = mac100_release_tx_desc, - .prepare_tx_desc = mac100_prepare_tx_desc, - .clear_tx_ic = mac100_clear_tx_ic, - .close_tx_desc = mac100_close_tx_desc, - .get_tx_ls = mac100_get_tx_ls, - .set_tx_owner = mac100_set_tx_owner, - .set_rx_owner = mac100_set_rx_owner, - .get_rx_frame_len = mac100_get_rx_frame_len, +struct stmmac_desc_ops dwmac100_desc_ops = { + .tx_status = dwmac100_get_tx_frame_status, + .rx_status = dwmac100_get_rx_frame_status, + .get_tx_len = dwmac100_get_tx_len, + .init_rx_desc = dwmac100_init_rx_desc, + .init_tx_desc = dwmac100_init_tx_desc, + .get_tx_owner = dwmac100_get_tx_owner, + .get_rx_owner = dwmac100_get_rx_owner, + .release_tx_desc = dwmac100_release_tx_desc, + .prepare_tx_desc = dwmac100_prepare_tx_desc, + .clear_tx_ic = dwmac100_clear_tx_ic, + .close_tx_desc = dwmac100_close_tx_desc, + .get_tx_ls = dwmac100_get_tx_ls, + .set_tx_owner = dwmac100_set_tx_owner, + .set_rx_owner = dwmac100_set_rx_owner, + .get_rx_frame_len = dwmac100_get_rx_frame_len, }; -struct mac_device_info *mac100_setup(unsigned long ioaddr) +struct mac_device_info *dwmac100_setup(unsigned long ioaddr) { struct mac_device_info *mac; mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); - pr_info("\tMAC 10/100\n"); + pr_info("\tDWMAC100\n"); - mac->mac = &mac100_ops; - mac->desc = &mac100_desc_ops; - mac->dma = &mac100_dma_ops; + mac->mac = &dwmac100_ops; + mac->desc = &dwmac100_desc_ops; + mac->dma = &dwmac100_dma_ops; mac->pmt = PMT_NOT_SUPPORTED; mac->link.port = MAC_CONTROL_PS; diff --git a/drivers/net/stmmac/mac100.h b/drivers/net/stmmac/dwmac100.h similarity index 100% rename from drivers/net/stmmac/mac100.h rename to drivers/net/stmmac/dwmac100.h diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index e6c5a3cf4af2..e79e00b6f147 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1585,7 +1585,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (priv->is_gmac) device = gmac_setup(ioaddr); else - device = mac100_setup(ioaddr); + device = dwmac100_setup(ioaddr); if (!device) return -ENOMEM; -- GitLab From 21d437cc66dcfd0119a4905214fbbe19f3e276dc Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:20 +0000 Subject: [PATCH 0448/3892] stmmac: rename the gmac as dwmac1000 and split core and dma parts Use dwmac1000 naming instead of gmac. The patch also splits the gmac.c file in two new ones: dwmac1000_core.c and dwmac1000_dma.c. This could actually help on some architectures where different DMA engines are used. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/Makefile | 5 +- drivers/net/stmmac/common.h | 2 +- drivers/net/stmmac/descs.h | 4 +- drivers/net/stmmac/{gmac.h => dwmac1000.h} | 19 +- drivers/net/stmmac/dwmac1000_core.c | 245 +++++++++++++ .../net/stmmac/{gmac.c => dwmac1000_dma.c} | 334 +++--------------- drivers/net/stmmac/stmmac_main.c | 2 +- 7 files changed, 324 insertions(+), 287 deletions(-) rename drivers/net/stmmac/{gmac.h => dwmac1000.h} (94%) create mode 100644 drivers/net/stmmac/dwmac1000_core.c rename drivers/net/stmmac/{gmac.c => dwmac1000_dma.c} (55%) diff --git a/drivers/net/stmmac/Makefile b/drivers/net/stmmac/Makefile index 2ed83859fd59..c776af15fe1a 100644 --- a/drivers/net/stmmac/Makefile +++ b/drivers/net/stmmac/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o -stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o dwmac_lib.o \ - dwmac100.o gmac.o $(stmmac-y) +stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ + dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ + dwmac100.o $(stmmac-y) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index 987faaaa1920..25b53d411516 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -224,7 +224,7 @@ struct mac_device_info { struct mac_link link; }; -struct mac_device_info *gmac_setup(unsigned long addr); +struct mac_device_info *dwmac1000_setup(unsigned long addr); struct mac_device_info *dwmac100_setup(unsigned long addr); extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6], diff --git a/drivers/net/stmmac/descs.h b/drivers/net/stmmac/descs.h index 6d2a0b2f5e57..63a03e264694 100644 --- a/drivers/net/stmmac/descs.h +++ b/drivers/net/stmmac/descs.h @@ -1,6 +1,6 @@ /******************************************************************************* - Header File to describe the DMA descriptors - Use enhanced descriptors in case of GMAC Cores. + Header File to describe the DMA descriptors. + Enhanced descriptors have been in case of DWMAC1000 Cores. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/stmmac/gmac.h b/drivers/net/stmmac/dwmac1000.h similarity index 94% rename from drivers/net/stmmac/gmac.h rename to drivers/net/stmmac/dwmac1000.h index 2e82d6c9a148..3d54d6c99129 100644 --- a/drivers/net/stmmac/gmac.h +++ b/drivers/net/stmmac/dwmac1000.h @@ -20,6 +20,10 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#include +#include +#include "common.h" + #define GMAC_CONTROL 0x00000000 /* Configuration */ #define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */ #define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */ @@ -32,7 +36,7 @@ #define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */ #define GMAC_INT_STATUS 0x00000038 /* interrupt status register */ -enum gmac_irq_status { +enum dwmac1000_irq_status { time_stamp_irq = 0x0200, mmc_rx_csum_offload_irq = 0x0080, mmc_tx_irq = 0x0040, @@ -202,3 +206,16 @@ enum rtc_control { #define GMAC_MMC_RX_INTR 0x104 #define GMAC_MMC_TX_INTR 0x108 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 + +#undef DWMAC1000_DEBUG +/* #define DWMAC1000__DEBUG */ +#undef FRAME_FILTER_DEBUG +/* #define FRAME_FILTER_DEBUG */ +#ifdef DWMAC1000__DEBUG +#define DBG(fmt, args...) printk(fmt, ## args) +#else +#define DBG(fmt, args...) do { } while (0) +#endif + +extern struct stmmac_dma_ops dwmac1000_dma_ops; +extern struct stmmac_desc_ops dwmac1000_desc_ops; diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c new file mode 100644 index 000000000000..928eac05b912 --- /dev/null +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -0,0 +1,245 @@ +/******************************************************************************* + This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. + DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for + developing this code. + + This only implements the mac core functions for this chip. + + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "dwmac1000.h" + +static void dwmac1000_core_init(unsigned long ioaddr) +{ + u32 value = readl(ioaddr + GMAC_CONTROL); + value |= GMAC_CORE_INIT; + writel(value, ioaddr + GMAC_CONTROL); + + /* STBus Bridge Configuration */ + /*writel(0xc5608, ioaddr + 0x00007000);*/ + + /* Freeze MMC counters */ + writel(0x8, ioaddr + GMAC_MMC_CTRL); + /* Mask GMAC interrupts */ + writel(0x207, ioaddr + GMAC_INT_MASK); + +#ifdef STMMAC_VLAN_TAG_USED + /* Tag detection without filtering */ + writel(0x0, ioaddr + GMAC_VLAN_TAG); +#endif + return; +} + +static void dwmac1000_dump_regs(unsigned long ioaddr) +{ + int i; + pr_info("\tDWMAC1000 regs (base addr = 0x%8x)\n", (unsigned int)ioaddr); + + for (i = 0; i < 55; i++) { + int offset = i * 4; + pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i, + offset, readl(ioaddr + offset)); + } + return; +} + +static void dwmac1000_set_umac_addr(unsigned long ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_set_filter(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int value = 0; + + DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", + __func__, dev->mc_count, dev->uc.count); + + if (dev->flags & IFF_PROMISC) + value = GMAC_FRAME_FILTER_PR; + else if ((dev->mc_count > HASH_TABLE_SIZE) + || (dev->flags & IFF_ALLMULTI)) { + value = GMAC_FRAME_FILTER_PM; /* pass all multi */ + writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); + writel(0xffffffff, ioaddr + GMAC_HASH_LOW); + } else if (dev->mc_count > 0) { + int i; + u32 mc_filter[2]; + struct dev_mc_list *mclist; + + /* Hash filter for multicast */ + value = GMAC_FRAME_FILTER_HMC; + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; + mclist && i < dev->mc_count; i++, mclist = mclist->next) { + /* The upper 6 bits of the calculated CRC are used to + index the contens of the hash table */ + int bit_nr = + bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26; + /* The most significant bit determines the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); + writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); + } + + /* Handle multiple unicast addresses (perfect filtering)*/ + if (dev->uc.count > GMAC_MAX_UNICAST_ADDRESSES) + /* Switch to promiscuous mode is more than 16 addrs + are required */ + value |= GMAC_FRAME_FILTER_PR; + else { + int reg = 1; + struct netdev_hw_addr *ha; + + list_for_each_entry(ha, &dev->uc.list, list) { + dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); + reg++; + } + } + +#ifdef FRAME_FILTER_DEBUG + /* Enable Receive all mode (to debug filtering_fail errors) */ + value |= GMAC_FRAME_FILTER_RA; +#endif + writel(value, ioaddr + GMAC_FRAME_FILTER); + + DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: " + "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER), + readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); + + return; +} + +static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + unsigned int flow = 0; + + DBG(KERN_DEBUG "GMAC Flow-Control:\n"); + if (fc & FLOW_RX) { + DBG(KERN_DEBUG "\tReceive Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_RFE; + } + if (fc & FLOW_TX) { + DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_TFE; + } + + if (duplex) { + DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time); + flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT); + } + + writel(flow, ioaddr + GMAC_FLOW_CTRL); + return; +} + +static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode) +{ + unsigned int pmt = 0; + + if (mode == WAKE_MAGIC) { + DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); + pmt |= power_down | magic_pkt_en; + } else if (mode == WAKE_UCAST) { + DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); + pmt |= global_unicast; + } + + writel(pmt, ioaddr + GMAC_PMT); + return; +} + + +static void dwmac1000_irq_status(unsigned long ioaddr) +{ + u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); + + /* Not used events (e.g. MMC interrupts) are not handled. */ + if ((intr_status & mmc_tx_irq)) + DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_TX_INTR)); + if (unlikely(intr_status & mmc_rx_irq)) + DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_INTR)); + if (unlikely(intr_status & mmc_rx_csum_offload_irq)) + DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD)); + if (unlikely(intr_status & pmt_irq)) { + DBG(KERN_DEBUG "GMAC: received Magic frame\n"); + /* clear the PMT bits 5 and 6 by reading the PMT + * status register. */ + readl(ioaddr + GMAC_PMT); + } + + return; +} + +struct stmmac_ops dwmac1000_ops = { + .core_init = dwmac1000_core_init, + .dump_regs = dwmac1000_dump_regs, + .host_irq_status = dwmac1000_irq_status, + .set_filter = dwmac1000_set_filter, + .flow_ctrl = dwmac1000_flow_ctrl, + .pmt = dwmac1000_pmt, + .set_umac_addr = dwmac1000_set_umac_addr, + .get_umac_addr = dwmac1000_get_umac_addr, +}; + +struct mac_device_info *dwmac1000_setup(unsigned long ioaddr) +{ + struct mac_device_info *mac; + u32 uid = readl(ioaddr + GMAC_VERSION); + + pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n", + ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff)); + + mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); + + mac->mac = &dwmac1000_ops; + mac->desc = &dwmac1000_desc_ops; + mac->dma = &dwmac1000_dma_ops; + + mac->pmt = PMT_SUPPORTED; + mac->link.port = GMAC_CONTROL_PS; + mac->link.duplex = GMAC_CONTROL_DM; + mac->link.speed = GMAC_CONTROL_FES; + mac->mii.addr = GMAC_MII_ADDR; + mac->mii.data = GMAC_MII_DATA; + + return mac; +} diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/dwmac1000_dma.c similarity index 55% rename from drivers/net/stmmac/gmac.c rename to drivers/net/stmmac/dwmac1000_dma.c index 07880922ff46..68245508e2de 100644 --- a/drivers/net/stmmac/gmac.c +++ b/drivers/net/stmmac/dwmac1000_dma.c @@ -3,6 +3,8 @@ DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for developing this code. + This contains the functions to handle the dma and descriptors. + Copyright (C) 2007-2009 STMicroelectronics Ltd This program is free software; you can redistribute it and/or modify it @@ -24,42 +26,11 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#include -#include -#include -#include - -#include "stmmac.h" -#include "gmac.h" +#include "dwmac1000.h" #include "dwmac_dma.h" -#undef GMAC_DEBUG -/*#define GMAC_DEBUG*/ -#undef FRAME_FILTER_DEBUG -/*#define FRAME_FILTER_DEBUG*/ -#ifdef GMAC_DEBUG -#define DBG(fmt, args...) printk(fmt, ## args) -#else -#define DBG(fmt, args...) do { } while (0) -#endif - -static void gmac_dump_regs(unsigned long ioaddr) -{ - int i; - pr_info("\t----------------------------------------------\n" - "\t GMAC registers (base addr = 0x%8x)\n" - "\t----------------------------------------------\n", - (unsigned int)ioaddr); - - for (i = 0; i < 55; i++) { - int offset = i * 4; - pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i, - offset, readl(ioaddr + offset)); - } - return; -} - -static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx) +static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, + u32 dma_rx) { u32 value = readl(ioaddr + DMA_BUS_MODE); /* DMA SW reset */ @@ -88,7 +59,7 @@ static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx) } /* Transmit FIFO flush operation */ -static void gmac_flush_tx_fifo(unsigned long ioaddr) +static void dwmac1000_flush_tx_fifo(unsigned long ioaddr) { u32 csr6 = readl(ioaddr + DMA_CONTROL); writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL); @@ -96,7 +67,7 @@ static void gmac_flush_tx_fifo(unsigned long ioaddr) do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF)); } -static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode, +static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode, int rxmode) { u32 csr6 = readl(ioaddr + DMA_CONTROL); @@ -149,13 +120,13 @@ static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode, } /* Not yet implemented --- no RMON module */ -static void gmac_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x, - unsigned long ioaddr) +static void dwmac1000_dma_diagnostic_fr(void *data, + struct stmmac_extra_stats *x, unsigned long ioaddr) { return; } -static void gmac_dump_dma_regs(unsigned long ioaddr) +static void dwmac1000_dump_dma_regs(unsigned long ioaddr) { int i; pr_info(" DMA registers\n"); @@ -170,8 +141,9 @@ static void gmac_dump_dma_regs(unsigned long ioaddr) return; } -static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, - struct dma_desc *p, unsigned long ioaddr) +static int dwmac1000_get_tx_frame_status(void *data, + struct stmmac_extra_stats *x, + struct dma_desc *p, unsigned long ioaddr) { int ret = 0; struct net_device_stats *stats = (struct net_device_stats *)data; @@ -186,7 +158,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, if (unlikely(p->des01.etx.frame_flushed)) { DBG(KERN_ERR "\tframe_flushed error\n"); x->tx_frame_flushed++; - gmac_flush_tx_fifo(ioaddr); + dwmac1000_flush_tx_fifo(ioaddr); } if (unlikely(p->des01.etx.loss_carrier)) { @@ -214,7 +186,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, if (unlikely(p->des01.etx.underflow_error)) { DBG(KERN_ERR "\tunderflow error\n"); - gmac_flush_tx_fifo(ioaddr); + dwmac1000_flush_tx_fifo(ioaddr); x->tx_underflow++; } @@ -226,7 +198,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, if (unlikely(p->des01.etx.payload_error)) { DBG(KERN_ERR "\tAddr/Payload csum error\n"); x->tx_payload_error++; - gmac_flush_tx_fifo(ioaddr); + dwmac1000_flush_tx_fifo(ioaddr); } ret = -1; @@ -246,12 +218,12 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x, return ret; } -static int gmac_get_tx_len(struct dma_desc *p) +static int dwmac1000_get_tx_len(struct dma_desc *p) { return p->des01.etx.buffer1_size; } -static int gmac_coe_rdes0(int ipc_err, int type, int payload_err) +static int dwmac1000_coe_rdes0(int ipc_err, int type, int payload_err) { int ret = good_frame; u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7; @@ -294,8 +266,8 @@ static int gmac_coe_rdes0(int ipc_err, int type, int payload_err) return ret; } -static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x, - struct dma_desc *p) +static int dwmac1000_get_rx_frame_status(void *data, + struct stmmac_extra_stats *x, struct dma_desc *p) { int ret = good_frame; struct net_device_stats *stats = (struct net_device_stats *)data; @@ -340,7 +312,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x, * It doesn't match with the information reported into the databook. * At any rate, we need to understand if the CSUM hw computation is ok * and report this info to the upper layers. */ - ret = gmac_coe_rdes0(p->des01.erx.ipc_csum_error, + ret = dwmac1000_coe_rdes0(p->des01.erx.ipc_csum_error, p->des01.erx.frame_type, p->des01.erx.payload_csum_error); if (unlikely(p->des01.erx.dribbling)) { @@ -371,170 +343,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x, return ret; } -static void gmac_irq_status(unsigned long ioaddr) -{ - u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); - - /* Not used events (e.g. MMC interrupts) are not handled. */ - if ((intr_status & mmc_tx_irq)) - DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n", - readl(ioaddr + GMAC_MMC_TX_INTR)); - if (unlikely(intr_status & mmc_rx_irq)) - DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n", - readl(ioaddr + GMAC_MMC_RX_INTR)); - if (unlikely(intr_status & mmc_rx_csum_offload_irq)) - DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n", - readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD)); - if (unlikely(intr_status & pmt_irq)) { - DBG(KERN_DEBUG "GMAC: received Magic frame\n"); - /* clear the PMT bits 5 and 6 by reading the PMT - * status register. */ - readl(ioaddr + GMAC_PMT); - } - - return; -} - -static void gmac_core_init(unsigned long ioaddr) -{ - u32 value = readl(ioaddr + GMAC_CONTROL); - value |= GMAC_CORE_INIT; - writel(value, ioaddr + GMAC_CONTROL); - - /* Freeze MMC counters */ - writel(0x8, ioaddr + GMAC_MMC_CTRL); - /* Mask GMAC interrupts */ - writel(0x207, ioaddr + GMAC_INT_MASK); - -#ifdef STMMAC_VLAN_TAG_USED - /* Tag detection without filtering */ - writel(0x0, ioaddr + GMAC_VLAN_TAG); -#endif - return; -} - -static void gmac_set_umac_addr(unsigned long ioaddr, unsigned char *addr, - unsigned int reg_n) -{ - stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), - GMAC_ADDR_LOW(reg_n)); -} - -static void gmac_get_umac_addr(unsigned long ioaddr, unsigned char *addr, - unsigned int reg_n) -{ - stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), - GMAC_ADDR_LOW(reg_n)); -} - -static void gmac_set_filter(struct net_device *dev) -{ - unsigned long ioaddr = dev->base_addr; - unsigned int value = 0; - - DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", - __func__, dev->mc_count, dev->uc.count); - - if (dev->flags & IFF_PROMISC) - value = GMAC_FRAME_FILTER_PR; - else if ((dev->mc_count > HASH_TABLE_SIZE) - || (dev->flags & IFF_ALLMULTI)) { - value = GMAC_FRAME_FILTER_PM; /* pass all multi */ - writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); - writel(0xffffffff, ioaddr + GMAC_HASH_LOW); - } else if (dev->mc_count > 0) { - int i; - u32 mc_filter[2]; - struct dev_mc_list *mclist; - - /* Hash filter for multicast */ - value = GMAC_FRAME_FILTER_HMC; - - memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; - mclist && i < dev->mc_count; i++, mclist = mclist->next) { - /* The upper 6 bits of the calculated CRC are used to - index the contens of the hash table */ - int bit_nr = - bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26; - /* The most significant bit determines the register to - * use (H/L) while the other 5 bits determine the bit - * within the register. */ - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - } - writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); - writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); - } - - /* Handle multiple unicast addresses (perfect filtering)*/ - if (dev->uc.count > GMAC_MAX_UNICAST_ADDRESSES) - /* Switch to promiscuous mode is more than 16 addrs - are required */ - value |= GMAC_FRAME_FILTER_PR; - else { - int reg = 1; - struct netdev_hw_addr *ha; - - list_for_each_entry(ha, &dev->uc.list, list) { - gmac_set_umac_addr(ioaddr, ha->addr, reg); - reg++; - } - } - -#ifdef FRAME_FILTER_DEBUG - /* Enable Receive all mode (to debug filtering_fail errors) */ - value |= GMAC_FRAME_FILTER_RA; -#endif - writel(value, ioaddr + GMAC_FRAME_FILTER); - - DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: " - "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER), - readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); - - return; -} - -static void gmac_flow_ctrl(unsigned long ioaddr, unsigned int duplex, - unsigned int fc, unsigned int pause_time) -{ - unsigned int flow = 0; - - DBG(KERN_DEBUG "GMAC Flow-Control:\n"); - if (fc & FLOW_RX) { - DBG(KERN_DEBUG "\tReceive Flow-Control ON\n"); - flow |= GMAC_FLOW_CTRL_RFE; - } - if (fc & FLOW_TX) { - DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n"); - flow |= GMAC_FLOW_CTRL_TFE; - } - - if (duplex) { - DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time); - flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT); - } - - writel(flow, ioaddr + GMAC_FLOW_CTRL); - return; -} - -static void gmac_pmt(unsigned long ioaddr, unsigned long mode) -{ - unsigned int pmt = 0; - - if (mode == WAKE_MAGIC) { - DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); - pmt |= power_down | magic_pkt_en; - } else if (mode == WAKE_UCAST) { - DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); - pmt |= global_unicast; - } - - writel(pmt, ioaddr + GMAC_PMT); - return; -} - -static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size, +static void dwmac1000_init_rx_desc(struct dma_desc *p, unsigned int ring_size, int disable_rx_ic) { int i; @@ -552,7 +361,7 @@ static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size, return; } -static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size) +static void dwmac1000_init_tx_desc(struct dma_desc *p, unsigned int ring_size) { int i; @@ -566,32 +375,32 @@ static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size) return; } -static int gmac_get_tx_owner(struct dma_desc *p) +static int dwmac1000_get_tx_owner(struct dma_desc *p) { return p->des01.etx.own; } -static int gmac_get_rx_owner(struct dma_desc *p) +static int dwmac1000_get_rx_owner(struct dma_desc *p) { return p->des01.erx.own; } -static void gmac_set_tx_owner(struct dma_desc *p) +static void dwmac1000_set_tx_owner(struct dma_desc *p) { p->des01.etx.own = 1; } -static void gmac_set_rx_owner(struct dma_desc *p) +static void dwmac1000_set_rx_owner(struct dma_desc *p) { p->des01.erx.own = 1; } -static int gmac_get_tx_ls(struct dma_desc *p) +static int dwmac1000_get_tx_ls(struct dma_desc *p) { return p->des01.etx.last_segment; } -static void gmac_release_tx_desc(struct dma_desc *p) +static void dwmac1000_release_tx_desc(struct dma_desc *p) { int ter = p->des01.etx.end_ring; @@ -601,7 +410,7 @@ static void gmac_release_tx_desc(struct dma_desc *p) return; } -static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, +static void dwmac1000_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, int csum_flag) { p->des01.etx.first_segment = is_fs; @@ -615,38 +424,27 @@ static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, p->des01.etx.checksum_insertion = cic_full; } -static void gmac_clear_tx_ic(struct dma_desc *p) +static void dwmac1000_clear_tx_ic(struct dma_desc *p) { p->des01.etx.interrupt = 0; } -static void gmac_close_tx_desc(struct dma_desc *p) +static void dwmac1000_close_tx_desc(struct dma_desc *p) { p->des01.etx.last_segment = 1; p->des01.etx.interrupt = 1; } -static int gmac_get_rx_frame_len(struct dma_desc *p) +static int dwmac1000_get_rx_frame_len(struct dma_desc *p) { return p->des01.erx.frame_length; } -struct stmmac_ops gmac_ops = { - .core_init = gmac_core_init, - .dump_regs = gmac_dump_regs, - .host_irq_status = gmac_irq_status, - .set_filter = gmac_set_filter, - .flow_ctrl = gmac_flow_ctrl, - .pmt = gmac_pmt, - .set_umac_addr = gmac_set_umac_addr, - .get_umac_addr = gmac_get_umac_addr, -}; - -struct stmmac_dma_ops gmac_dma_ops = { - .init = gmac_dma_init, - .dump_regs = gmac_dump_dma_regs, - .dma_mode = gmac_dma_operation_mode, - .dma_diagnostic_fr = gmac_dma_diagnostic_fr, +struct stmmac_dma_ops dwmac1000_dma_ops = { + .init = dwmac1000_dma_init, + .dump_regs = dwmac1000_dump_dma_regs, + .dma_mode = dwmac1000_dma_operation_mode, + .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr, .enable_dma_transmission = dwmac_enable_dma_transmission, .enable_dma_irq = dwmac_enable_dma_irq, .disable_dma_irq = dwmac_disable_dma_irq, @@ -657,44 +455,20 @@ struct stmmac_dma_ops gmac_dma_ops = { .dma_interrupt = dwmac_dma_interrupt, }; -struct stmmac_desc_ops gmac_desc_ops = { - .tx_status = gmac_get_tx_frame_status, - .rx_status = gmac_get_rx_frame_status, - .get_tx_len = gmac_get_tx_len, - .init_rx_desc = gmac_init_rx_desc, - .init_tx_desc = gmac_init_tx_desc, - .get_tx_owner = gmac_get_tx_owner, - .get_rx_owner = gmac_get_rx_owner, - .release_tx_desc = gmac_release_tx_desc, - .prepare_tx_desc = gmac_prepare_tx_desc, - .clear_tx_ic = gmac_clear_tx_ic, - .close_tx_desc = gmac_close_tx_desc, - .get_tx_ls = gmac_get_tx_ls, - .set_tx_owner = gmac_set_tx_owner, - .set_rx_owner = gmac_set_rx_owner, - .get_rx_frame_len = gmac_get_rx_frame_len, +struct stmmac_desc_ops dwmac1000_desc_ops = { + .tx_status = dwmac1000_get_tx_frame_status, + .rx_status = dwmac1000_get_rx_frame_status, + .get_tx_len = dwmac1000_get_tx_len, + .init_rx_desc = dwmac1000_init_rx_desc, + .init_tx_desc = dwmac1000_init_tx_desc, + .get_tx_owner = dwmac1000_get_tx_owner, + .get_rx_owner = dwmac1000_get_rx_owner, + .release_tx_desc = dwmac1000_release_tx_desc, + .prepare_tx_desc = dwmac1000_prepare_tx_desc, + .clear_tx_ic = dwmac1000_clear_tx_ic, + .close_tx_desc = dwmac1000_close_tx_desc, + .get_tx_ls = dwmac1000_get_tx_ls, + .set_tx_owner = dwmac1000_set_tx_owner, + .set_rx_owner = dwmac1000_set_rx_owner, + .get_rx_frame_len = dwmac1000_get_rx_frame_len, }; - -struct mac_device_info *gmac_setup(unsigned long ioaddr) -{ - struct mac_device_info *mac; - u32 uid = readl(ioaddr + GMAC_VERSION); - - pr_info("\tGMAC - user ID: 0x%x, Synopsys ID: 0x%x\n", - ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff)); - - mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); - - mac->mac = &gmac_ops; - mac->desc = &gmac_desc_ops; - mac->dma = &gmac_dma_ops; - - mac->pmt = PMT_SUPPORTED; - mac->link.port = GMAC_CONTROL_PS; - mac->link.duplex = GMAC_CONTROL_DM; - mac->link.speed = GMAC_CONTROL_FES; - mac->mii.addr = GMAC_MII_ADDR; - mac->mii.data = GMAC_MII_DATA; - - return mac; -} diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index e79e00b6f147..16d4e1cecf8f 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1583,7 +1583,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) struct mac_device_info *device; if (priv->is_gmac) - device = gmac_setup(ioaddr); + device = dwmac1000_setup(ioaddr); else device = dwmac100_setup(ioaddr); -- GitLab From 5e33c791233b7da47b5403344a915c1b7edaaad8 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:21 +0000 Subject: [PATCH 0449/3892] stmmac: include netdevice.h into the common.h header Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/common.h | 2 +- drivers/net/stmmac/dwmac100.c | 1 - drivers/net/stmmac/dwmac1000.h | 1 - drivers/net/stmmac/stmmac_main.c | 1 - drivers/net/stmmac/stmmac_mdio.c | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index 25b53d411516..7267bcd43d06 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -23,7 +23,7 @@ *******************************************************************************/ #include "descs.h" -#include +#include struct stmmac_extra_stats { /* Transmit errors */ diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c index 010c8b206359..82dde774d4c5 100644 --- a/drivers/net/stmmac/dwmac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -26,7 +26,6 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#include #include #include #include diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/stmmac/dwmac1000.h index 3d54d6c99129..62dca0e384e7 100644 --- a/drivers/net/stmmac/dwmac1000.h +++ b/drivers/net/stmmac/dwmac1000.h @@ -20,7 +20,6 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#include #include #include "common.h" diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 16d4e1cecf8f..a6733612d64a 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c index 131e0a603711..fffe1d037fe6 100644 --- a/drivers/net/stmmac/stmmac_mdio.c +++ b/drivers/net/stmmac/stmmac_mdio.c @@ -24,7 +24,6 @@ Maintainer: Giuseppe Cavallaro *******************************************************************************/ -#include #include #include -- GitLab From 7187c1ad1a2a005fa24aa14fa5b0e4c8322c0cd2 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:22 +0000 Subject: [PATCH 0450/3892] stmmac: improve Kconfig help Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/Kconfig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/stmmac/Kconfig index 35eaa5251d7f..fb287649a305 100644 --- a/drivers/net/stmmac/Kconfig +++ b/drivers/net/stmmac/Kconfig @@ -4,8 +4,9 @@ config STMMAC_ETH select PHYLIB depends on NETDEVICES && CPU_SUBTYPE_ST40 help - This is the driver for the ST MAC 10/100/1000 on-chip Ethernet - controllers. ST Ethernet IPs are built around a Synopsys IP Core. + This is the driver for the Ethernet IPs are built around a + Synopsys IP Core and fully tested on the STMicroelectronics + platforms. if STMMAC_ETH @@ -32,7 +33,8 @@ config STMMAC_TIMER default n help Use an external timer for mitigating the number of network - interrupts. + interrupts. Currently, for SH architectures, it is possible + to use the TMU channel 2 and the SH-RTC device. choice prompt "Select Timer device" -- GitLab From 108316c1bd0a75ba855ce4a6540c530e1562bfb0 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 6 Jan 2010 23:07:23 +0000 Subject: [PATCH 0451/3892] stmmac: update the driver's module version Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h index 44421d9667a8..ba35e6943cf4 100644 --- a/drivers/net/stmmac/stmmac.h +++ b/drivers/net/stmmac/stmmac.h @@ -20,7 +20,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#define DRV_MODULE_VERSION "Oct_09" +#define DRV_MODULE_VERSION "Jan_2010" #include #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -- GitLab From d7ac769068df87ca8c7f72d99cf67ead16739f18 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 8 Jan 2010 14:18:34 +1100 Subject: [PATCH 0452/3892] crypto: aes_s390 - access .cip instead of .blk in cipher mode The fallback code in cipher mode touch the union fallback.blk instead of fallback.cip. This is wrong because we use the cipher and not the blockcipher. This did not show any side effects yet because both types / structs contain the same element right now. Signed-off-by: Roel Kluin Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 6118890c946d..9ed05bcd19b0 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -78,14 +78,14 @@ static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key, struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); int ret; - sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags & + sctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + sctx->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len); if (ret) { tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags & + tfm->crt_flags |= (sctx->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK); } return ret; -- GitLab From faad98f29606d9d3c6bddae7c88693be37d2fb43 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 8 Jan 2010 14:19:21 +1100 Subject: [PATCH 0453/3892] crypto: geode-aes - access .cip instead of .blk in cipher mode The fallback code in cipher mode touch the union fallback.blk instead of fallback.cip. This is wrong because we use the cipher and not the blockcipher. This did not show any side effects yet because both types / structs contain the same element right now. Signed-off-by: Roel Kluin Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Herbert Xu --- drivers/crypto/geode-aes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 4801162919d9..03e71b1a5128 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -135,8 +135,8 @@ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, /* * The requested key size is not supported by HW, do a fallback */ - op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); ret = crypto_cipher_setkey(op->fallback.cip, key, len); if (ret) { @@ -263,7 +263,7 @@ static int fallback_init_cip(struct crypto_tfm *tfm) if (IS_ERR(op->fallback.cip)) { printk(KERN_ERR "Error allocating fallback algo %s\n", name); - return PTR_ERR(op->fallback.blk); + return PTR_ERR(op->fallback.cip); } return 0; -- GitLab From 7b3a177b0d4f92b3431b8dca777313a07533a710 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 8 Jan 2010 08:43:01 +0100 Subject: [PATCH 0454/3892] ALSA: pcm_lib: fix "something must be really wrong" condition When runtime->periods == 1 or when pointer crosses end of ring buffer, the delta might be greater than buffer_size. Signed-off-by: Jaroslav Kysela --- sound/core/pcm_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a63226232ef4..c7b35b20e659 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -362,7 +362,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)runtime->hw_ptr_base); } /* something must be really wrong */ - if (delta >= runtime->buffer_size) { + if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, "Unexpected hw_pointer value %s" "(stream=%i, pos=%ld, new_hw_ptr=%ld, " -- GitLab From dd3533eca859a6debb1565503ec03e68354e08e0 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 1 Jan 2010 19:05:43 +0100 Subject: [PATCH 0455/3892] ALSA: ac97_codec: merge WM9703 and WM9705 ops The WM9705 and WM9703 ops are the same actually so use the same code for both. Signed-off-by: Krzysztof Helt Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 139cf3b2b9d7..e288a5595f34 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97) return 0; } -static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) -{ - int err, i; - for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) - return err; - } - snd_ac97_write_cache(ac97, 0x72, 0x0808); - return 0; -} - -static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { - .build_specific = patch_wolfson_wm9705_specific, -}; - static int patch_wolfson05(struct snd_ac97 * ac97) { /* WM9705, WM9710 */ - ac97->build_ops = &patch_wolfson_wm9705_ops; + ac97->build_ops = &patch_wolfson_wm9703_ops; #ifdef CONFIG_TOUCHSCREEN_WM9705 /* WM9705 touchscreen uses AUX and VIDEO for touch */ ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; -- GitLab From a3aa18842a5303fc28fcc4d57dbd16618bd830a0 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 7 Jan 2010 11:58:11 +0000 Subject: [PATCH 0456/3892] drivers/net/: use DEFINE_PCI_DEVICE_TABLE() Use DEFINE_PCI_DEVICE_TABLE() so we get place PCI ids table into correct section in every case. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 2 +- drivers/net/8139cp.c | 2 +- drivers/net/8139too.c | 2 +- drivers/net/acenic.c | 2 +- drivers/net/amd8111e.c | 2 +- drivers/net/arcnet/com20020-pci.c | 2 +- drivers/net/atl1c/atl1c_main.c | 2 +- drivers/net/atl1e/atl1e_main.c | 2 +- drivers/net/atlx/atl1.c | 2 +- drivers/net/atlx/atl2.c | 2 +- drivers/net/b44.c | 2 +- drivers/net/bnx2x_main.c | 2 +- drivers/net/can/sja1000/ems_pci.c | 2 +- drivers/net/can/sja1000/kvaser_pci.c | 2 +- drivers/net/cassini.c | 2 +- drivers/net/chelsio/common.h | 2 +- drivers/net/chelsio/subr.c | 2 +- drivers/net/cxgb3/cxgb3_main.c | 2 +- drivers/net/defxx.c | 2 +- drivers/net/dl2k.h | 2 +- drivers/net/e100.c | 2 +- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/e1000e/netdev.c | 2 +- drivers/net/enic/enic_main.c | 2 +- drivers/net/epic100.c | 2 +- drivers/net/fealnx.c | 2 +- drivers/net/forcedeth.c | 2 +- drivers/net/hamachi.c | 2 +- drivers/net/hp100.c | 2 +- drivers/net/igb/igb_main.c | 2 +- drivers/net/igbvf/netdev.c | 2 +- drivers/net/ioc3-eth.c | 2 +- drivers/net/ipg.c | 2 +- drivers/net/irda/donauboe.c | 2 +- drivers/net/irda/via-ircc.c | 2 +- drivers/net/irda/vlsi_ir.c | 2 +- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/ixgbe/ixgbe_main.c | 2 +- drivers/net/jme.c | 2 +- drivers/net/mlx4/main.c | 2 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/natsemi.c | 2 +- drivers/net/ne2k-pci.c | 2 +- drivers/net/netxen/netxen_nic_main.c | 2 +- drivers/net/niu.c | 2 +- drivers/net/ns83820.c | 2 +- drivers/net/pasemi_mac.c | 2 +- drivers/net/pci-skeleton.c | 2 +- drivers/net/pcnet32.c | 2 +- drivers/net/qla3xxx.c | 2 +- drivers/net/qlge/qlge_main.c | 2 +- drivers/net/r6040.c | 2 +- drivers/net/r8169.c | 2 +- drivers/net/rrunner.c | 2 +- drivers/net/s2io.c | 2 +- drivers/net/sc92031.c | 2 +- drivers/net/sfc/efx.c | 2 +- drivers/net/sis190.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/skfp/skfddi.c | 2 +- drivers/net/skge.c | 2 +- drivers/net/smsc9420.c | 2 +- drivers/net/spider_net.c | 2 +- drivers/net/starfire.c | 2 +- drivers/net/sundance.c | 2 +- drivers/net/sungem.c | 2 +- drivers/net/sunhme.c | 2 +- drivers/net/tc35815.c | 2 +- drivers/net/tehuti.c | 2 +- drivers/net/tg3.c | 2 +- drivers/net/tlan.c | 2 +- drivers/net/tokenring/3c359.c | 2 +- drivers/net/tokenring/abyss.c | 2 +- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tokenring/olympic.c | 2 +- drivers/net/tokenring/tmspci.c | 2 +- drivers/net/tulip/de2104x.c | 2 +- drivers/net/tulip/dmfe.c | 2 +- drivers/net/tulip/tulip_core.c | 2 +- drivers/net/tulip/uli526x.c | 2 +- drivers/net/tulip/winbond-840.c | 2 +- drivers/net/tulip/xircom_cb.c | 2 +- drivers/net/typhoon.c | 2 +- drivers/net/via-rhine.c | 2 +- drivers/net/via-velocity.c | 2 +- drivers/net/vmxnet3/vmxnet3_drv.c | 2 +- drivers/net/vxge/vxge-main.c | 2 +- drivers/net/wan/dscc4.c | 2 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/lmc/lmc_main.c | 2 +- drivers/net/wan/pc300_drv.c | 2 +- drivers/net/wan/pc300too.c | 2 +- drivers/net/wan/pci200syn.c | 2 +- drivers/net/wan/wanxl.c | 2 +- drivers/net/wireless/adm8211.c | 2 +- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath9k/pci.c | 2 +- drivers/net/wireless/atmel_pci.c | 2 +- drivers/net/wireless/hostap/hostap_pci.c | 2 +- drivers/net/wireless/hostap/hostap_plx.c | 2 +- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/ipw2x00/ipw2200.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/orinoco/orinoco_nortel.c | 2 +- drivers/net/wireless/orinoco/orinoco_pci.c | 2 +- drivers/net/wireless/orinoco/orinoco_plx.c | 2 +- drivers/net/wireless/orinoco/orinoco_tmd.c | 2 +- drivers/net/wireless/p54/p54pci.c | 2 +- drivers/net/wireless/prism54/islpci_hotplug.c | 2 +- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2800pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rtl818x/rtl8180_dev.c | 2 +- drivers/net/yellowfin.c | 2 +- 118 files changed, 118 insertions(+), 118 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 39db0e96815d..5df46c230b07 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -375,7 +375,7 @@ static struct vortex_chip_info { }; -static struct pci_device_id vortex_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(vortex_pci_tbl) = { { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 }, { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 }, diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 3f452bcbfb9e..9d59654748b1 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -394,7 +394,7 @@ static int cp_get_eeprom(struct net_device *dev, static int cp_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data); -static struct pci_device_id cp_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(cp_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), }, { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), }, { }, diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 907f2d583db8..321e73aabb2b 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -231,7 +231,7 @@ static const struct { }; -static const struct pci_device_id rtl8139_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rtl8139_pci_tbl) = { {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index d82a9a994753..ec624ab03e88 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -134,7 +134,7 @@ #define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif -static struct pci_device_id acenic_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(acenic_pci_tbl) = { { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER, diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 766aabfdfc75..545c791f477e 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -113,7 +113,7 @@ MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0 module_param_array(dynamic_ipg, bool, NULL, 0); MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable"); -static struct pci_device_id amd8111e_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = { { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index dbf4de39754d..b68e1eb405ff 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -144,7 +144,7 @@ static void __devexit com20020pci_remove(struct pci_dev *pdev) free_netdev(dev); } -static struct pci_device_id com20020pci_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(com20020pci_id_table) = { { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 77cde859620c..d98095df05be 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -35,7 +35,7 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION; * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ -static struct pci_device_id atl1c_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)}, {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)}, /* required last entry */ diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 2080d444068b..d59f8e89c65d 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -35,7 +35,7 @@ char atl1e_driver_version[] = DRV_VERSION; * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ -static struct pci_device_id atl1e_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(atl1e_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)}, {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)}, /* required last entry */ diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index b6cf3263127c..9ba547069db3 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -232,7 +232,7 @@ static void __devinit atl1_check_options(struct atl1_adapter *adapter) /* * atl1_pci_tbl - PCI Device ID Table */ -static const struct pci_device_id atl1_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(atl1_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)}, /* required last entry */ {0,} diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index c0451d75cdcf..255e4e7ea0ee 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -63,7 +63,7 @@ MODULE_VERSION(ATL2_DRV_VERSION); /* * atl2_pci_tbl - PCI Device ID Table */ -static struct pci_device_id atl2_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)}, /* required last entry */ {0,} diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 4869adb69586..44b66be38134 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -102,7 +102,7 @@ MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); #ifdef CONFIG_B44_PCI -static const struct pci_device_id b44_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(b44_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) }, diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 77ba13520d87..0bfdf30ea4d1 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -140,7 +140,7 @@ static struct { }; -static const struct pci_device_id bnx2x_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = { { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E }, diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index fd04789d3370..87300606abb9 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -102,7 +102,7 @@ struct ems_pci_card { #define EMS_PCI_BASE_SIZE 4096 /* size of controller area */ -static struct pci_device_id ems_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ems_pci_tbl) = { /* CPC-PCI v1 */ {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,}, /* CPC-PCI v2 */ diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 7dd7769b9713..441e776a7f59 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -109,7 +109,7 @@ struct kvaser_pci { #define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */ #define KVASER_PCI_DEVICE_ID2 0x0008 -static struct pci_device_id kvaser_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(kvaser_pci_tbl) = { {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,}, {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,}, { 0,} diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f857afe8e488..b3a038c23af1 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -236,7 +236,7 @@ static u16 link_modes[] __devinitdata = { CAS_BMCR_SPEED1000|BMCR_FULLDPLX /* 5 : 1000bt full duplex */ }; -static struct pci_device_id cas_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(cas_pci_tbl) = { { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_CASSINI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SATURN, diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 699d22c5fe09..f6462b54f823 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -334,7 +334,7 @@ static inline int t1_is_asic(const adapter_t *adapter) return adapter->params.is_asic; } -extern struct pci_device_id t1_pci_tbl[]; +extern const struct pci_device_id t1_pci_tbl[]; static inline int adapter_matches_type(const adapter_t *adapter, int version, int revision) diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 17720c6e5bfe..2402d372c886 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -528,7 +528,7 @@ static const struct board_info t1_board[] = { }; -struct pci_device_id t1_pci_tbl[] = { +DEFINE_PCI_DEVICE_TABLE(t1_pci_tbl) = { CH_DEVICE(8, 0, CH_BRD_T110_1CU), CH_DEVICE(8, 1, CH_BRD_T110_1CU), CH_DEVICE(7, 0, CH_BRD_N110_1F), diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 89bec9c3c141..73622f5312cb 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -80,7 +80,7 @@ enum { #define CH_DEVICE(devid, idx) \ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } -static const struct pci_device_id cxgb3_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = { CH_DEVICE(0x20, 0), /* PE9000 */ CH_DEVICE(0x21, 1), /* T302E */ CH_DEVICE(0x22, 2), /* T310E */ diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index e4eac4bcdf83..98da085445e6 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3628,7 +3628,7 @@ static int __devinit dfx_pci_register(struct pci_dev *, const struct pci_device_id *); static void __devexit dfx_pci_unregister(struct pci_dev *); -static struct pci_device_id dfx_pci_table[] = { +static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, { } }; diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 266ec8777ca8..7caab3d26a9e 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -537,7 +537,7 @@ struct netdev_private { driver_data Data private to the driver. */ -static const struct pci_device_id rio_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rio_pci_tbl) = { {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, }, { } diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 839fb2b136d3..5c7a155e849a 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -208,7 +208,7 @@ MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } -static struct pci_device_id e100_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(e100_id_table) = { INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7e855f9bbd97..9ec7480be1d8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -42,7 +42,7 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation * Macro expands to... * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ -static struct pci_device_id e1000_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { INTEL_E1000_ETHERNET_DEVICE(0x1000), INTEL_E1000_ETHERNET_DEVICE(0x1001), INTEL_E1000_ETHERNET_DEVICE(0x1004), diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 762b697ce731..9ccb9010dc5b 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -5325,7 +5325,7 @@ static struct pci_error_handlers e1000_err_handler = { .resume = e1000_io_resume, }; -static struct pci_device_id e1000_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index d87935ad1130..c81bc4b1816f 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -51,7 +51,7 @@ #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ /* Supported devices */ -static struct pci_device_id enic_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = { { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, { 0, } /* end of table */ }; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 41494f7b2ec8..1f8b11449fad 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -167,7 +167,7 @@ static const struct epic_chip_info pci_id_tbl[] = { }; -static struct pci_device_id epic_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = { { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 }, { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 }, { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index dac4e595589e..e6a98129d787 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1941,7 +1941,7 @@ static int netdev_close(struct net_device *dev) return 0; } -static struct pci_device_id fealnx_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(fealnx_pci_tbl) = { {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3c340489804a..3eb713b014f9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -6198,7 +6198,7 @@ static void nv_shutdown(struct pci_dev *pdev) #define nv_resume NULL #endif /* CONFIG_PM */ -static struct pci_device_id pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = { { /* nForce Ethernet Controller */ PCI_DEVICE(0x10DE, 0x01C3), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index ea85075a89a2..dd72c5025e6a 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1990,7 +1990,7 @@ static void __devexit hamachi_remove_one (struct pci_dev *pdev) } } -static struct pci_device_id hamachi_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(hamachi_pci_tbl) = { { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 90f890e7c5e1..0c2f2e8b1c47 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -210,7 +210,7 @@ MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); #endif #ifdef CONFIG_PCI -static struct pci_device_id hp100_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(hp100_pci_tbl) = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 78963a0e128d..484fbc83739f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -60,7 +60,7 @@ static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, }; -static struct pci_device_id igb_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 }, diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 1326232c1d32..ca0d1906e83e 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2876,7 +2876,7 @@ static struct pci_error_handlers igbvf_err_handler = { .resume = igbvf_io_resume, }; -static struct pci_device_id igbvf_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(igbvf_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), board_vf }, { } /* terminate list */ }; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 8ec15ab8c8c2..81a4c5d30733 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1383,7 +1383,7 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev) */ } -static struct pci_device_id ioc3_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ioc3_pci_tbl) = { { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID }, { 0 } }; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index ba8d246d05a0..49f35e2ed19f 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -92,7 +92,7 @@ static const char *ipg_brand_name[] = { "D-Link NIC IP1000A" }; -static struct pci_device_id ipg_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = { { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, { PCI_VDEVICE(SUNDANCE, 0x1021), 2 }, diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 2d7b5c1d5572..b7e6625ca75e 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -184,7 +184,7 @@ #define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC #define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX -static struct pci_device_id toshoboe_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(toshoboe_pci_tbl) = { { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index fddb4efd5453..6533c010cf5c 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -121,7 +121,7 @@ static void iodelay(int udelay) } } -static struct pci_device_id via_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(via_pci_tbl) = { { PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 }, { PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 }, { PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 }, diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index bd3c6b5ee76a..209d4bcfaced 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -59,7 +59,7 @@ MODULE_LICENSE("GPL"); static /* const */ char drivername[] = DRIVER_NAME; -static struct pci_device_id vlsi_irda_table [] = { +static DEFINE_PCI_DEVICE_TABLE(vlsi_irda_table) = { { .class = PCI_CLASS_WIRELESS_IRDA << 8, .class_mask = PCI_CLASS_SUBCLASS_MASK << 8, diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index bcd0f01d5feb..6c2d9366fe5e 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -50,7 +50,7 @@ MODULE_PARM_DESC(copybreak, * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ -static struct pci_device_id ixgb_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ixgb_pci_tbl) = { {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_CX4, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index bd64387563f0..b2f11d45e225 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -67,7 +67,7 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = { * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ -static struct pci_device_id ixgbe_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598), board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 792b88fc3574..26eed49d3208 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2994,7 +2994,7 @@ jme_resume(struct pci_dev *pdev) } #endif -static struct pci_device_id jme_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = { { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) }, { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) }, { } diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 291a505fd4fc..58f7f979cd2b 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1271,7 +1271,7 @@ int mlx4_restart_one(struct pci_dev *pdev) return __mlx4_init_one(pdev, NULL); } -static struct pci_device_id mlx4_pci_table[] = { +static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = { { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */ { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */ { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */ diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 3fcb1c356e0d..c0884a9cba3c 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -4085,7 +4085,7 @@ static void myri10ge_remove(struct pci_dev *pdev) #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008 #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009 -static struct pci_device_id myri10ge_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(myri10ge_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)}, {PCI_DEVICE (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)}, diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 797fe164ce27..2d7b3bbfed01 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -247,7 +247,7 @@ static struct { { "NatSemi DP8381[56]", 0, 24 }, }; -static struct pci_device_id natsemi_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(natsemi_pci_tbl) = { { PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 }, { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { } /* terminate list */ diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 3fcebb70151c..85aec4f10131 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -136,7 +136,7 @@ static struct { }; -static struct pci_device_id ne2k_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ne2k_pci_tbl) = { { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 }, { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 }, { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 }, diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index f13a07f717c7..3fdfc9b7c5b2 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -100,7 +100,7 @@ static void netxen_config_indev_addr(struct net_device *dev, unsigned long); {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} -static struct pci_device_id netxen_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(netxen_pci_tbl) = { ENTRY(PCI_DEVICE_ID_NX2031_10GXSR), ENTRY(PCI_DEVICE_ID_NX2031_10GCX4), ENTRY(PCI_DEVICE_ID_NX2031_4GCU), diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 8ce58c4c7dd3..920f0ecf7a0a 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -58,7 +58,7 @@ static void writeq(u64 val, void __iomem *reg) } #endif -static struct pci_device_id niu_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(niu_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)}, {} }; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 1f6327d41536..a3b6aa0f375d 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -2292,7 +2292,7 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); } -static struct pci_device_id ns83820_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(ns83820_pci_tbl) = { { 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, }, { 0, }, }; diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 1673eb045e1e..d44d4a208bbf 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1875,7 +1875,7 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev) free_netdev(netdev); } -static struct pci_device_id pasemi_mac_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(pasemi_mac_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) }, { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) }, { }, diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 8ff5536a3757..20273832bfce 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -211,7 +211,7 @@ static struct { }; -static const struct pci_device_id netdrv_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(netdrv_pci_tbl) = { {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB }, {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX }, diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index dcc67a35e8f2..ed62ac6d9c0e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -58,7 +58,7 @@ static const char *const version = /* * PCI device identifiers for "new style" Linux PCI Device Drivers */ -static struct pci_device_id pcnet32_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(pcnet32_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), }, diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index dd35066a7f8d..f922294fd349 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -61,7 +61,7 @@ static int msi; module_param(msi, int, 0); MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts."); -static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ql3xxx_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)}, /* required last entry */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 25561fbdb203..167a3dab2f18 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -73,7 +73,7 @@ static int qlge_irq_type = MSIX_IRQ; module_param(qlge_irq_type, int, MSIX_IRQ); MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); -static struct pci_device_id qlge_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, /* required last entry */ diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index f03e2e4a15a8..d68ba7a58631 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1222,7 +1222,7 @@ static void __devexit r6040_remove_one(struct pci_dev *pdev) } -static struct pci_device_id r6040_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(r6040_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) }, { 0 } }; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c403ce0a3d3a..c1bb24cf0793 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -168,7 +168,7 @@ static void rtl_hw_start_8169(struct net_device *); static void rtl_hw_start_8168(struct net_device *); static void rtl_hw_start_8101(struct net_device *); -static struct pci_device_id rtl8169_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 20a71749154a..085f4ec896d3 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1688,7 +1688,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } -static struct pci_device_id rr_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rr_pci_tbl) = { { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, PCI_ANY_ID, PCI_ANY_ID, }, { 0,} diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index cc4218667cba..ac6189005c79 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -523,7 +523,7 @@ module_param_array(rts_frm_len, uint, NULL, 0); * S2IO device table. * This table lists all the devices that this driver supports. */ -static struct pci_device_id s2io_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(s2io_tbl) = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index e35050322f97..fd8cb506a2bb 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1589,7 +1589,7 @@ out: return 0; } -static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) }, { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) }, { PCI_DEVICE(0x1088, 0x2031) }, diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f983e3b507cc..3591cc9c39c8 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1940,7 +1940,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) **************************************************************************/ /* PCI device ID table */ -static struct pci_device_id efx_pci_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = { {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), .driver_data = (unsigned long) &falcon_a1_nic_type}, {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 31233b4c44a0..626de766443a 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -334,7 +334,7 @@ static const struct { { "SiS 191 PCI Gigabit Ethernet adapter" }, }; -static struct pci_device_id sis190_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(sis190_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 }, { 0, }, diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 7360d4bbf75e..20c5ce474891 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -106,7 +106,7 @@ static const char * card_names[] = { "SiS 900 PCI Fast Ethernet", "SiS 7016 PCI Fast Ethernet" }; -static struct pci_device_id sis900_pci_tbl [] = { +static DEFINE_PCI_DEVICE_TABLE(sis900_pci_tbl) = { {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900}, {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 1f9698c0fb64..6b955a4f19b2 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -149,7 +149,7 @@ extern void mac_drv_rx_mode(struct s_smc *smc, int mode); extern void mac_drv_clear_rx_queue(struct s_smc *smc); extern void enable_tx_irq(struct s_smc *smc, u_short queue); -static struct pci_device_id skfddi_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(skfddi_pci_tbl) = { { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 379a3dc00163..5ff46eb18d0c 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -78,7 +78,7 @@ static int debug = -1; /* defaults above */ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -static const struct pci_device_id skge_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(skge_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) }, { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 12f0f5d74e3c..1495a5dd4b46 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -80,7 +80,7 @@ struct smsc9420_pdata { int last_carrier; }; -static const struct pci_device_id smsc9420_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = { { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 218524857bfc..16191998ac67 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -72,7 +72,7 @@ MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \ char spider_net_driver_name[] = "spidernet"; -static struct pci_device_id spider_net_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(spider_net_pci_tbl) = { { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 95db60adde41..c81252d9a57c 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -301,7 +301,7 @@ enum chipset { CH_6915 = 0, }; -static struct pci_device_id starfire_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = { { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, { 0, } }; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d58e1891ca60..0c972e560cf3 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -206,7 +206,7 @@ IVc. Errata #define USE_IO_OPS 1 #endif -static const struct pci_device_id sundance_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(sundance_pci_tbl) = { { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 }, { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 }, { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 }, diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index b571a1babab9..b55ceb88d93f 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -107,7 +107,7 @@ MODULE_LICENSE("GPL"); #define GEM_MODULE_NAME "gem" #define PFX GEM_MODULE_NAME ": " -static struct pci_device_id gem_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(gem_pci_tbl) = { { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 6762f1c6ec8a..76ccd31cbf50 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3211,7 +3211,7 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev) dev_set_drvdata(&pdev->dev, NULL); } -static struct pci_device_id happymeal_pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(happymeal_pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) }, { } /* Terminating entry */ }; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 75a669d48e5e..033408f589fb 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -65,7 +65,7 @@ static const struct { { "TOSHIBA TC35815/TX4939" }, }; -static const struct pci_device_id tc35815_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(tc35815_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF }, {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU }, {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 }, diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 80b404f2b938..b907bee31fd5 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -64,7 +64,7 @@ #include "tehuti.h" -static struct pci_device_id __devinitdata bdx_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(bdx_pci_tbl) = { {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3a74d2168598..b0630cd093a3 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -174,7 +174,7 @@ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ module_param(tg3_debug, int, 0); MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); -static struct pci_device_id tg3_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)}, diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index fabaeffb3155..613943eb6e75 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -254,7 +254,7 @@ static struct board { { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ }; -static struct pci_device_id tlan_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(tlan_pci_tbl) = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100, diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index cf552d1d9629..b0d7db9d8bb4 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -117,7 +117,7 @@ MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ; * will be stuck with 1555 lines of hex #'s in the code. */ -static struct pci_device_id xl_pci_tbl[] = +static DEFINE_PCI_DEVICE_TABLE(xl_pci_tbl) = { {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, { } /* terminate list */ diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index b9db1b5a58a3..515f122777ab 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -45,7 +45,7 @@ static char version[] __devinitdata = #define ABYSS_IO_EXTENT 64 -static struct pci_device_id abyss_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(abyss_pci_tbl) = { { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, }, { } /* Terminating entry */ diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index d6ccd59c7d07..3f9d5a25562e 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -146,7 +146,7 @@ static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n" " v0.5.3 11/13/02 - Kent Yoder"; -static struct pci_device_id streamer_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(streamer_pci_tbl) = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, {} /* terminating entry */ }; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index df32025c5132..f010a4dc5f19 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -172,7 +172,7 @@ module_param_array(message_level, int, NULL, 0) ; static int network_monitor[OLYMPIC_MAX_ADAPTERS] = {0,}; module_param_array(network_monitor, int, NULL, 0); -static struct pci_device_id olympic_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(olympic_pci_tbl) = { {PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_TR_WAKE,PCI_ANY_ID,PCI_ANY_ID,}, { } /* Terminating Entry */ }; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index f92fe86fdcae..d4c7c0c0a3d6 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -57,7 +57,7 @@ static struct card_info card_info_table[] = { { {0x03, 0x01}, "3Com Token Link Velocity"}, }; -static struct pci_device_id tmspci_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(tmspci_pci_tbl) = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d4255d44cb75..87ea39e2037d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -337,7 +337,7 @@ static void de21041_media_timer (unsigned long data); static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media); -static struct pci_device_id de_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(de_pci_tbl) = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index ad63621913c3..8153fdd0af91 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -2068,7 +2068,7 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db) -static struct pci_device_id dmfe_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(dmfe_pci_tbl) = { { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID }, diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 0fa3140d65bf..64aa2d6af08b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -207,7 +207,7 @@ struct tulip_chip_table tulip_tbl[] = { }; -static struct pci_device_id tulip_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(tulip_pci_tbl) = { { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index fa019cabc355..d549042a01df 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -1783,7 +1783,7 @@ static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id) } -static struct pci_device_id uli526x_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(uli526x_pci_tbl) = { { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID }, { 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID }, { 0, } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 869a7a0005f9..23395e1ff238 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -218,7 +218,7 @@ enum chip_capability_flags { CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8, }; -static const struct pci_device_id w840_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(w840_pci_tbl) = { { 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 }, { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 9924c4c7e2d6..c84123fd635c 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -144,7 +144,7 @@ static int link_status(struct xircom_private *card); -static struct pci_device_id xircom_pci_table[] = { +static DEFINE_PCI_DEVICE_TABLE(xircom_pci_table) = { {0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 39f1fc650be6..6e4f754c4baf 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -215,7 +215,7 @@ static struct typhoon_card_info typhoon_card_info[] __devinitdata = { * bit 8 indicates if this is a (0) copper or (1) fiber card * bits 12-16 indicate card type: (0) client and (1) server */ -static struct pci_device_id typhoon_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(typhoon_pci_tbl) = { { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990, PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95, diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 593e01f64e9b..6bc924cd4583 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -266,7 +266,7 @@ enum rhine_quirks { /* Beware of PCI posted writes */ #define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0) -static const struct pci_device_id rhine_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rhine_pci_tbl) = { { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */ { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */ { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */ diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index cee8fa2d2a9f..83fc3a8dd254 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -361,7 +361,7 @@ static struct velocity_info_tbl chip_info_table[] = { * Describe the PCI device identifiers that we support in this * device driver. Used for hotplug autoloading. */ -static const struct pci_device_id velocity_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(velocity_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) }, { } }; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 9cc438282d77..b896f9386110 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -35,7 +35,7 @@ char vmxnet3_driver_name[] = "vmxnet3"; * PCI Device ID Table * Last entry must be all 0s */ -static const struct pci_device_id vmxnet3_pciid_table[] = { +static DEFINE_PCI_DEVICE_TABLE(vmxnet3_pciid_table) = { {PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_VMXNET3)}, {0} }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 5f0e7ea0d493..6466bc840e6d 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -54,7 +54,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O" "Virtualized Server Adapter"); -static struct pci_device_id vxge_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(vxge_id_table) = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID, diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 3f759daf3ca4..f88c07c13197 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -2050,7 +2050,7 @@ static int __init dscc4_setup(char *str) __setup("dscc4.setup=", dscc4_setup); #endif -static struct pci_device_id dscc4_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(dscc4_pci_tbl) = { { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4, PCI_ANY_ID, PCI_ANY_ID, }, { 0,} diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 9bc2e3649157..40d724a8e020 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -528,7 +528,7 @@ static int fst_debug_mask = { FST_DEBUG }; /* * PCI ID lookup table */ -static struct pci_device_id fst_pci_dev_id[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(fst_pci_dev_id) = { {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FST_TYPE_T2P}, diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 4b6f27e7c820..b27850377121 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -77,7 +77,7 @@ static int LMC_PKT_BUF_SZ = 1542; -static struct pci_device_id lmc_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(lmc_pci_tbl) = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, PCI_VENDOR_ID_LMC, PCI_ANY_ID }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index aec4d3955420..f4f1c00d0d23 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -251,7 +251,7 @@ static char rcsid[] = #undef PC300_DEBUG_RX #undef PC300_DEBUG_OTHER -static struct pci_device_id cpc_pci_dev_id[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(cpc_pci_dev_id) = { /* PC300/RSV or PC300/X21, 2 chan */ {0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300}, /* PC300/RSV or PC300/X21, 1 chan */ diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index 60ece54bdd94..c7ab3becd261 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -481,7 +481,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, -static struct pci_device_id pc300_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(pc300_pci_tbl) = { { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID, diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index f1340faaf022..e2cff64a446a 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -417,7 +417,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, -static struct pci_device_id pci200_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(pci200_pci_tbl) = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 }, { 0, } diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index daee8a0624ee..541c700dceef 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -814,7 +814,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, return 0; } -static struct pci_device_id wanxl_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(wanxl_pci_tbl) = { { PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL200, PCI_ANY_ID, diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e1f04bb437e3..e6ca3eb4c0d3 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -39,7 +39,7 @@ static unsigned int rx_ring_size __read_mostly = 16; module_param(tx_ring_size, uint, 0); module_param(rx_ring_size, uint, 0); -static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(adm8211_pci_id_table) = { /* ADMtek ADM8211 */ { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */ { PCI_DEVICE(0x1200, 0x8201) }, /* ? */ diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 4331d675fcc6..37e4ab737f2a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -57,7 +57,7 @@ #define DRV_NAME "airo" #ifdef CONFIG_PCI -static struct pci_device_id card_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(card_ids) = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fdfaf0f618f1..72e5ed51c0af 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -83,7 +83,7 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); /* Known PCI ids */ -static const struct pci_device_id ath5k_pci_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */ { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */ { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/ diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f7af5ea54753..ee617205cb4a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -18,7 +18,7 @@ #include #include "ath9k.h" -static struct pci_device_id ath_pci_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c index 92f87fbe750f..9ab1192004c0 100644 --- a/drivers/net/wireless/atmel_pci.c +++ b/drivers/net/wireless/atmel_pci.c @@ -31,7 +31,7 @@ MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.") MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("Atmel at76c506 PCI wireless cards"); -static struct pci_device_id card_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(card_ids) = { { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, { 0, } }; diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 8fdd41f4b4f2..4d97ae37499b 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -39,7 +39,7 @@ struct hostap_pci_priv { /* FIX: do we need mb/wmb/rmb with memory operations? */ -static struct pci_device_id prism2_pci_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(prism2_pci_id_table) = { /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 0e5d51086a44..fc04ccdc5bef 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -60,7 +60,7 @@ struct hostap_plx_priv { #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } -static struct pci_device_id prism2_plx_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(prism2_plx_id_table) = { PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), PLXDEV(0x126c, 0x8030, "Nortel emobility"), diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 56afcf041f81..9b72c45a7748 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6585,7 +6585,7 @@ static void ipw2100_shutdown(struct pci_dev *pci_dev) #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } -static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = { IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 09ddd3e6bedc..63c2a7ade5fb 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11524,7 +11524,7 @@ out: } /* PCI driver stuff */ -static struct pci_device_id card_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(card_ids) = { {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0}, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 28ffe4c826d8..6cde661ce0bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2849,7 +2849,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .broken_powersave = true, }; -struct pci_device_id iwl3945_hw_card_ids[] = { +DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)}, {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)}, {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 3ec2fe370b58..bc532ff4f883 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -37,7 +37,7 @@ #include /* Hardware specific file defines the PCI IDs table for that hardware module */ -extern struct pci_device_id iwl3945_hw_card_ids[]; +extern const struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-csr.h" #include "iwl-prph.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 771b03c1c7c5..c8fec626b714 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3766,7 +3766,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) *****************************************************************************/ /* Hardware specific file defines the PCI IDs table for that hardware module */ -static struct pci_device_id iwl_hw_card_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { #ifdef CONFIG_IWL4965 {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index c13a4c383410..075f446b3139 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -274,7 +274,7 @@ static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id orinoco_nortel_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(orinoco_nortel_id_table) = { /* Nortel emobility PCI */ {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, /* Symbol LA-4123 PCI */ diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index fea7781948e7..bda5317cc596 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -212,7 +212,7 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id orinoco_pci_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(orinoco_pci_id_table) = { /* Intersil Prism 3 */ {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, /* Intersil Prism 2.5 */ diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 3f2942a1e4f5..e0d5874ab42f 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -310,7 +310,7 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id orinoco_plx_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(orinoco_plx_id_table) = { {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index d3452548cc71..88cbc7902aa0 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -203,7 +203,7 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id orinoco_tmd_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(orinoco_tmd_id_table) = { {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ {0,}, }; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index a15962a19b2a..fab41f507bd3 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -31,7 +31,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54pci"); MODULE_FIRMWARE("isl3886pci"); -static struct pci_device_id p54p_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(p54p_table) = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ { PCI_DEVICE(0x1260, 0x3890) }, /* 3COM 3CRWE154G72 Wireless LAN adapter */ diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index e4f2bb7368f2..dc14420a9adc 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -39,7 +39,7 @@ module_param(init_pcitm, int, 0); * driver_data * If you have an update for this please contact prism54-devel@prism54.org * The latest list can be found at http://prism54.org/supported_cards.php */ -static const struct pci_device_id prism54_id_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(prism54_id_tbl) = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ { 0x1260, 0x3890, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d86d233c6810..aa579eb8723f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1642,7 +1642,7 @@ static const struct rt2x00_ops rt2400pci_ops = { /* * RT2400pci module information. */ -static struct pci_device_id rt2400pci_device_table[] = { +static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = { { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, { 0, } }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 46cbc6ef66ab..77ee1df7933f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1940,7 +1940,7 @@ static const struct rt2x00_ops rt2500pci_ops = { /* * RT2500pci module information. */ -static struct pci_device_id rt2500pci_device_table[] = { +static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = { { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, { 0, } }; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b93eabb4fbe1..99095e1ee13b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1208,7 +1208,7 @@ static const struct rt2x00_ops rt2800pci_ops = { /* * RT2800pci module information. */ -static struct pci_device_id rt2800pci_device_table[] = { +static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c353b497a65d..1f97a797bc41 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2807,7 +2807,7 @@ static const struct rt2x00_ops rt61pci_ops = { /* * RT61pci module information. */ -static struct pci_device_id rt61pci_device_table[] = { +static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = { /* RT2561s */ { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, /* RT2561 v2 */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 5a2b7199f5d5..b9192bfcc557 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -33,7 +33,7 @@ MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); MODULE_LICENSE("GPL"); -static struct pci_device_id rtl8180_table[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = { /* rtl8185 */ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 0f773a9a3ff2..8b231b30fd12 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -237,7 +237,7 @@ static const struct pci_id_info pci_id_tbl[] = { { } }; -static const struct pci_device_id yellowfin_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(yellowfin_pci_tbl) = { { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { } -- GitLab From 8c0b8139c87cfe8b95c6e763b4ca3190aa9b1ad0 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 8 Jan 2010 17:02:17 +0900 Subject: [PATCH 0457/3892] sh: consolidate atomic_cmpxchg()/atomic_add_unless() definitions. The LL/SC and IRQ versions were using generic stubs while the GRB version was just reimplementing what it already had for the standard cmpxchg() code. As we have optimized cmpxchg() implementations that are decoupled from the atomic code, simply falling back on the generic wrapper does the right thing. With this in place the GRB case is unaffected while the LL/SC case gets to use its optimized cmpxchg(). Signed-off-by: Paul Mundt --- arch/sh/include/asm/atomic-grb.h | 46 ------------------- arch/sh/include/asm/atomic-llsc.h | 27 ------------ arch/sh/include/asm/atomic.h | 73 ++++++++++++------------------- 3 files changed, 29 insertions(+), 117 deletions(-) diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index 4c5b7dbfcedb..a273c88578fc 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h @@ -120,50 +120,4 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) : "memory" , "r0", "r1"); } -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - int ret; - - __asm__ __volatile__ ( - " .align 2 \n\t" - " mova 1f, r0 \n\t" - " nop \n\t" - " mov r15, r1 \n\t" - " mov #-8, r15 \n\t" - " mov.l @%1, %0 \n\t" - " cmp/eq %2, %0 \n\t" - " bf 1f \n\t" - " mov.l %3, @%1 \n\t" - "1: mov r1, r15 \n\t" - : "=&r" (ret) - : "r" (v), "r" (old), "r" (new) - : "memory" , "r0", "r1" , "t"); - - return ret; -} - -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - int ret; - unsigned long tmp; - - __asm__ __volatile__ ( - " .align 2 \n\t" - " mova 1f, r0 \n\t" - " nop \n\t" - " mov r15, r1 \n\t" - " mov #-12, r15 \n\t" - " mov.l @%2, %1 \n\t" - " mov %1, %0 \n\t" - " cmp/eq %4, %0 \n\t" - " bt/s 1f \n\t" - " add %3, %1 \n\t" - " mov.l %1, @%2 \n\t" - "1: mov r1, r15 \n\t" - : "=&r" (ret), "=&r" (tmp) - : "r" (v), "r" (a), "r" (u) - : "memory" , "r0", "r1" , "t"); - - return ret != u; -} #endif /* __ASM_SH_ATOMIC_GRB_H */ diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h index b040e1e08610..4b00b78e3f4f 100644 --- a/arch/sh/include/asm/atomic-llsc.h +++ b/arch/sh/include/asm/atomic-llsc.h @@ -104,31 +104,4 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) : "t"); } -#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) - -/** - * atomic_add_unless - add unless the number is a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - c = atomic_read(v); - for (;;) { - if (unlikely(c == (u))) - break; - old = atomic_cmpxchg((v), c, c + (a)); - if (likely(old == c)) - break; - c = old; - } - - return c != (u); -} - #endif /* __ASM_SH_ATOMIC_LLSC_H */ diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index b16388d71954..275a448ae8c2 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,58 +25,43 @@ #endif #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#define atomic_dec_return(v) atomic_sub_return(1,(v)) -#define atomic_inc_return(v) atomic_add_return(1,(v)) +#define atomic_inc(v) atomic_add(1, (v)) +#define atomic_dec(v) atomic_sub(1, (v)) -/* - * atomic_inc_and_test - increment and test +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) + +/** + * atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...unless v is equal to u. * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. + * Atomically adds @a to @v, so long as it was not @u. + * Returns non-zero if @v was not @u, and zero otherwise. */ -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - -#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) -#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) - -#define atomic_inc(v) atomic_add(1,(v)) -#define atomic_dec(v) atomic_sub(1,(v)) - -#if !defined(CONFIG_GUSA_RB) && !defined(CONFIG_CPU_SH4A) -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - int ret; - unsigned long flags; - - local_irq_save(flags); - ret = v->counter; - if (likely(ret == old)) - v->counter = new; - local_irq_restore(flags); - - return ret; -} - static inline int atomic_add_unless(atomic_t *v, int a, int u) { - int ret; - unsigned long flags; - - local_irq_save(flags); - ret = v->counter; - if (ret != u) - v->counter += a; - local_irq_restore(flags); - - return ret != u; + int c, old; + c = atomic_read(v); + for (;;) { + if (unlikely(c == (u))) + break; + old = atomic_cmpxchg((v), c, c + (a)); + if (likely(old == c)) + break; + c = old; + } + + return c != (u); } -#endif /* !CONFIG_GUSA_RB && !CONFIG_CPU_SH4A */ - -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() -- GitLab From 368c0ca2f0a69b0818fbc1796d8e21ff02a61b4c Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Fri, 8 Jan 2010 00:07:27 -0800 Subject: [PATCH 0458/3892] be2net: implements ethtool function to read eeprom data. The patch implements a firmware command to fetch the eeprom data. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 30 +++++++++++++++++++++++ drivers/net/benet/be_cmds.h | 16 ++++++++++++ drivers/net/benet/be_ethtool.c | 45 ++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1b68bd98dc0c..b748c197408f 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1571,3 +1571,33 @@ err: spin_unlock_bh(&adapter->mcc_lock); return status; } + +extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_seeprom_read *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_SEEPROM_READ); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SEEPROM_READ, sizeof(*req)); + + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + status = be_mcc_notify_wait(adapter); + + spin_unlock_bh(&adapter->mcc_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 92b87ef156ed..6eed512bb6d4 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -124,6 +124,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_CQ_CREATE 12 #define OPCODE_COMMON_EQ_CREATE 13 #define OPCODE_COMMON_MCC_CREATE 21 +#define OPCODE_COMMON_SEEPROM_READ 30 #define OPCODE_COMMON_NTWK_RX_FILTER 34 #define OPCODE_COMMON_GET_FW_VERSION 35 #define OPCODE_COMMON_SET_FLOW_CONTROL 36 @@ -840,6 +841,19 @@ struct be_cmd_resp_ddrdma_test { u8 rcv_buff[4096]; }; +/*********************** SEEPROM Read ***********************/ + +#define BE_READ_SEEPROM_LEN 1024 +struct be_cmd_req_seeprom_read { + struct be_cmd_req_hdr hdr; + u8 rsvd0[BE_READ_SEEPROM_LEN]; +}; + +struct be_cmd_resp_seeprom_read { + struct be_cmd_req_hdr hdr; + u8 seeprom_data[BE_READ_SEEPROM_LEN]; +}; + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -912,3 +926,5 @@ extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, u32 num_pkts, u64 pattern); extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, u32 byte_cnt, struct be_dma_mem *cmd); +extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 298b92cbd689..c5afc0286d4d 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -536,12 +536,57 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) return be_load_fw(adapter, file_name); } +static int +be_get_eeprom_len(struct net_device *netdev) +{ + return BE_READ_SEEPROM_LEN; +} + +static int +be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, + uint8_t *data) +{ + struct be_adapter *adapter = netdev_priv(netdev); + struct be_dma_mem eeprom_cmd; + struct be_cmd_resp_seeprom_read *resp; + int status; + + if (!eeprom->len) + return -EINVAL; + + eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16); + + memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); + eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read); + eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size, + &eeprom_cmd.dma); + + if (!eeprom_cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure. Could not read eeprom\n"); + return -ENOMEM; + } + + status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd); + + if (!status) { + resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va; + memcpy(data, resp->seeprom_data, eeprom->len); + } + pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va, + eeprom_cmd.dma); + + return status; +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, .get_wol = be_get_wol, .set_wol = be_set_wol, .get_link = ethtool_op_get_link, + .get_eeprom_len = be_get_eeprom_len, + .get_eeprom = be_read_eeprom, .get_coalesce = be_get_coalesce, .set_coalesce = be_set_coalesce, .get_ringparam = be_get_ringparam, -- GitLab From cd9d95a55550555da8e587ead9cbba5f98a371a3 Mon Sep 17 00:00:00 2001 From: Ken Prox Date: Fri, 8 Jan 2010 09:01:47 +0100 Subject: [PATCH 0459/3892] ALSA: hda - conexant - Fixed microphone mixer for HP Compaq Presario F700 Added patch for Hewlett-Packard Company Device Subsystem id - 103c:30ea. Signed-off-by: Ken Prox Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_conexant.c | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1ab2958a290b..b20c640f7502 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1720,6 +1720,22 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { {} }; +static struct snd_kcontrol_new cxt5051_f700_mixers[] = { + HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = cxt_eapd_info, + .get = cxt_eapd_get, + .put = cxt5051_hp_master_sw_put, + .private_value = 0x1a, + }, + + {} +}; + static struct hda_verb cxt5051_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, @@ -1810,6 +1826,32 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { { } /* end */ }; +static struct hda_verb cxt5051_f700_init_verbs[] = { + /* Line in, Mic */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, + /* SPK */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP, Amp */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Record selector: Int mic */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* SPDIF route: PCM */ + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* EAPD */ + {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, + { } /* end */ +}; + /* initialize jack-sensing, too */ static int cxt5051_init(struct hda_codec *codec) { @@ -1829,6 +1871,7 @@ enum { CXT5051_HP, /* no docking */ CXT5051_HP_DV6736, /* HP without mic switch */ CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ + CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_MODELS }; @@ -1837,6 +1880,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", [CXT5051_LENOVO_X200] = "lenovo-x200", + [CXT5051_F700] = "hp 700" }; static struct snd_pci_quirk cxt5051_cfg_tbl[] = { @@ -1846,6 +1890,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), + SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), {} }; @@ -1896,6 +1941,11 @@ static int patch_cxt5051(struct hda_codec *codec) case CXT5051_LENOVO_X200: spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; break; + case CXT5051_F700: + spec->init_verbs[0] = cxt5051_f700_init_verbs; + spec->mixers[0] = cxt5051_f700_mixers; + spec->no_auto_mic = 1; + break; } return 0; -- GitLab From 75f8991d0e6969407d51501d5a0537f104075c99 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 7 Jan 2010 13:46:25 +0100 Subject: [PATCH 0460/3892] ALSA: hda - Configure XO-1.5 microphones at capture time The XO-1.5 has a microphone LED designed to indicate to the user when something is being recorded. This light is controlled by the microphone bias voltage and it is currently coming on all the time. This patch defers the microphone port configuration until when recording is actually taking place, fixing the behaviour of the LED. Signed-off-by: Daniel Drake Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_conexant.c | 125 ++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 01e46ba72690..3521f33d43c3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -111,8 +111,12 @@ struct conexant_spec { unsigned int dell_automute; unsigned int port_d_mode; - unsigned char ext_mic_bias; unsigned int dell_vostro; + + unsigned int ext_mic_present; + unsigned int recording; + void (*capture_prepare)(struct hda_codec *codec); + void (*capture_cleanup)(struct hda_codec *codec); }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -185,6 +189,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct conexant_spec *spec = codec->spec; + if (spec->capture_prepare) + spec->capture_prepare(codec); snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], stream_tag, 0, format); return 0; @@ -196,6 +202,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct conexant_spec *spec = codec->spec; snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); + if (spec->capture_cleanup) + spec->capture_cleanup(codec); return 0; } @@ -2016,53 +2024,53 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } -/* toggle input of built-in and mic jack appropriately */ -static void cxt5066_automic(struct hda_codec *codec) +/* OLPC defers mic widget control until when capture is started because the + * microphone LED comes on as soon as these settings are put in place. if we + * did this before recording, it would give the false indication that recording + * is happening when it is not. */ +static void cxt5066_olpc_select_mic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, + if (!spec->recording) + return; - /* disable internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* external mic, port B */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); - /* switch to internal mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, + /* internal mic, port C */ + snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->ext_mic_present ? 0 : PIN_VREF80); +} - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; +/* toggle input of built-in and mic jack appropriately */ +static void cxt5066_olpc_automic(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; unsigned int present; - present = snd_hda_jack_detect(codec, 0x1a); - if (present) { + present = snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + if (present) snd_printdd("CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { + else snd_printdd("CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } + + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, + present ? 0 : 1); + spec->ext_mic_present = !!present; + + cxt5066_olpc_select_mic(codec); } /* toggle input of built-in digital mic and mic jack appropriately */ static void cxt5066_vostro_automic(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; unsigned int present; struct hda_verb ext_mic_present[] = { /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* switch to external mic input */ {0x17, AC_VERB_SET_CONNECT_SEL, 0}, @@ -2113,7 +2121,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec) } /* unsolicited event for jack sensing */ -static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) +static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) { snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); switch (res >> 26) { @@ -2121,7 +2129,7 @@ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) cxt5066_hp_automute(codec); break; case CONEXANT_MIC_EVENT: - cxt5066_automic(codec); + cxt5066_olpc_automic(codec); break; } } @@ -2197,6 +2205,31 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, return 1; } +static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + /* mark as recording and configure the microphone widget so that the + * recording LED comes on. */ + spec->recording = 1; + cxt5066_olpc_select_mic(codec); +} + +static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + const struct hda_verb disable_mics[] = { + /* disable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* disble internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {}, + }; + + snd_hda_sequence_write(codec, disable_mics); + spec->recording = 0; +} + static struct hda_input_mux cxt5066_capture_source = { .num_items = 4, .items = { @@ -2347,10 +2380,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, /* Port C: internal microphone */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, /* Port D: unused */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -2479,12 +2512,19 @@ static int cxt5066_init(struct hda_codec *codec) cxt5066_hp_automute(codec); if (spec->dell_vostro) cxt5066_vostro_automic(codec); - else - cxt5066_automic(codec); } return 0; } +static int cxt5066_olpc_init(struct hda_codec *codec) +{ + snd_printdd("CXT5066: init\n"); + conexant_init(codec); + cxt5066_hp_automute(codec); + cxt5066_olpc_automic(codec); + return 0; +} + enum { CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ @@ -2521,7 +2561,7 @@ static int patch_cxt5066(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = cxt5066_init; + codec->patch_ops.init = conexant_init; spec->dell_automute = 0; spec->multiout.max_channels = 2; @@ -2534,7 +2574,6 @@ static int patch_cxt5066(struct hda_codec *codec) spec->input_mux = &cxt5066_capture_source; spec->port_d_mode = PIN_HP; - spec->ext_mic_bias = PIN_VREF80; spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5066_init_verbs; @@ -2561,20 +2600,26 @@ static int patch_cxt5066(struct hda_codec *codec) spec->dell_automute = 1; break; case CXT5066_OLPC_XO_1_5: - codec->patch_ops.unsol_event = cxt5066_unsol_event; + codec->patch_ops.init = cxt5066_olpc_init; + codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; spec->init_verbs[0] = cxt5066_init_verbs_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->port_d_mode = 0; - spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; /* input source automatically selected */ spec->input_mux = NULL; + + /* our capture hooks which allow us to turn on the microphone LED + * at the right time */ + spec->capture_prepare = cxt5066_olpc_capture_prepare; + spec->capture_cleanup = cxt5066_olpc_capture_cleanup; break; case CXT5066_DELL_VOSTO: + codec->patch_ops.init = cxt5066_init; codec->patch_ops.unsol_event = cxt5066_vostro_event; spec->init_verbs[0] = cxt5066_init_verbs_vostro; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; -- GitLab From c4cfe66c4c2d5a91b3734ffb4e2bad0badd5c874 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 7 Jan 2010 13:47:04 +0100 Subject: [PATCH 0461/3892] ALSA: hda - support OLPC XO-1.5 DC input The XO's audio hardware is wired up to allow DC sensors (e.g. light sensors, thermistors, etc) to be plugged in through the microphone jack. Add sound mixer controls to allow this mode to be enabled and tweaked. Signed-off-by: Daniel Drake Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_conexant.c | 213 +++++++++++++++++++++++++++++---- 1 file changed, 190 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3521f33d43c3..685015a53292 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -117,6 +117,16 @@ struct conexant_spec { unsigned int recording; void (*capture_prepare)(struct hda_codec *codec); void (*capture_cleanup)(struct hda_codec *codec); + + /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) + * through the microphone jack. + * When the user enables this through a mixer switch, both internal and + * external microphones are disabled. Gain is fixed at 0dB. In this mode, + * we also allow the bias to be configured through a separate mixer + * control. */ + unsigned int dc_enable; + unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ + unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -2024,6 +2034,26 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } +static const struct hda_input_mux cxt5066_olpc_dc_bias = { + .num_items = 3, + .items = { + { "Off", PIN_IN }, + { "50%", PIN_VREF50 }, + { "80%", PIN_VREF80 }, + }, +}; + +static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + /* Even though port F is the DC input, the bias is controlled on port B. + * we also leave that port as an active input (but unselected) in DC mode + * just in case that is necessary to make the bias setting take effect. */ + return snd_hda_codec_write_cache(codec, 0x1a, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); +} + /* OLPC defers mic widget control until when capture is started because the * microphone LED comes on as soon as these settings are put in place. if we * did this before recording, it would give the false indication that recording @@ -2034,6 +2064,27 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec) if (!spec->recording) return; + if (spec->dc_enable) { + /* in DC mode we ignore presence detection and just use the jack + * through our special DC port */ + const struct hda_verb enable_dc_mode[] = { + /* disble internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* enable DC capture, port F */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {}, + }; + + snd_hda_sequence_write(codec, enable_dc_mode); + /* port B input disabled (and bias set) through the following call */ + cxt5066_set_olpc_dc_bias(codec); + return; + } + + /* disable DC (port F) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + /* external mic, port B */ snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); @@ -2049,6 +2100,9 @@ static void cxt5066_olpc_automic(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int present; + if (spec->dc_enable) /* don't do presence detection in DC mode */ + return; + present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; if (present) @@ -2123,13 +2177,16 @@ static void cxt5066_hp_automute(struct hda_codec *codec) /* unsolicited event for jack sensing */ static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) { + struct conexant_spec *spec = codec->spec; snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); switch (res >> 26) { case CONEXANT_HP_EVENT: cxt5066_hp_automute(codec); break; case CONEXANT_MIC_EVENT: - cxt5066_olpc_automic(codec); + /* ignore mic events in DC mode; we're always using the jack */ + if (!spec->dc_enable) + cxt5066_olpc_automic(codec); break; } } @@ -2159,6 +2216,15 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { }, }; +static int cxt5066_set_mic_boost(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | + cxt5066_analog_mic_boost.items[spec->mic_boost].index); +} + static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2169,15 +2235,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int val; - hda_nid_t nid = kcontrol->private_value & 0xff; - int inout = (kcontrol->private_value & 0x100) ? - AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; - - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_AMP_GAIN_MUTE, inout); - - ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; + struct conexant_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->mic_boost; return 0; } @@ -2185,23 +2244,101 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; unsigned int idx; - hda_nid_t nid = kcontrol->private_value & 0xff; - int inout = (kcontrol->private_value & 0x100) ? - AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + + spec->mic_boost = idx; + if (!spec->dc_enable) + cxt5066_set_mic_boost(codec); + return 1; +} + +static void cxt5066_enable_dc(struct hda_codec *codec) +{ + const struct hda_verb enable_dc_mode[] = { + /* disable gain */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* switch to DC input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 3}, + {} + }; + + /* configure as input source */ + snd_hda_sequence_write(codec, enable_dc_mode); + cxt5066_olpc_select_mic(codec); /* also sets configured bias */ +} + +static void cxt5066_disable_dc(struct hda_codec *codec) +{ + /* reconfigure input source */ + cxt5066_set_mic_boost(codec); + /* automic also selects the right mic if we're recording */ + cxt5066_olpc_automic(codec); +} + +static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + ucontrol->value.integer.value[0] = spec->dc_enable; + return 0; +} - if (!imux->num_items) +static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int dc_enable = !!ucontrol->value.integer.value[0]; + + if (dc_enable == spec->dc_enable) return 0; + + spec->dc_enable = dc_enable; + if (dc_enable) + cxt5066_enable_dc(codec); + else + cxt5066_disable_dc(codec); + + return 1; +} + +static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); +} + +static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->dc_input_bias; + return 0; +} + +static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; + unsigned int idx; + idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | - imux->items[idx].index); - + spec->dc_input_bias = idx; + if (spec->dc_enable) + cxt5066_set_olpc_dc_bias(codec); return 1; } @@ -2223,6 +2360,9 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) /* disble internal mic, port C */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* disable DC capture, port F */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {}, }; @@ -2282,6 +2422,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { {} }; +static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Mode Enable Switch", + .info = snd_ctl_boolean_mono_info, + .get = cxt5066_olpc_dc_get, + .put = cxt5066_olpc_dc_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Input Bias Enum", + .info = cxt5066_olpc_dc_bias_enum_info, + .get = cxt5066_olpc_dc_bias_enum_get, + .put = cxt5066_olpc_dc_bias_enum_put, + }, + {} +}; + static struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2294,11 +2452,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Ext Mic Boost Capture Enum", + .name = "Analog Mic Boost Capture Enum", .info = cxt5066_mic_boost_mux_enum_info, .get = cxt5066_mic_boost_mux_enum_get, .put = cxt5066_mic_boost_mux_enum_put, - .private_value = 0x17, }, HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), @@ -2392,7 +2549,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - /* Port F: unused */ + /* Port F: external DC input through microphone port */ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, /* Port G: internal speakers */ @@ -2513,15 +2670,22 @@ static int cxt5066_init(struct hda_codec *codec) if (spec->dell_vostro) cxt5066_vostro_automic(codec); } + cxt5066_set_mic_boost(codec); return 0; } static int cxt5066_olpc_init(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; snd_printdd("CXT5066: init\n"); conexant_init(codec); cxt5066_hp_automute(codec); - cxt5066_olpc_automic(codec); + if (!spec->dc_enable) { + cxt5066_set_mic_boost(codec); + cxt5066_olpc_automic(codec); + } else { + cxt5066_enable_dc(codec); + } return 0; } @@ -2604,8 +2768,10 @@ static int patch_cxt5066(struct hda_codec *codec) codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; spec->init_verbs[0] = cxt5066_init_verbs_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->port_d_mode = 0; + spec->mic_boost = 3; /* default 30dB gain */ /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; @@ -2627,6 +2793,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; spec->port_d_mode = 0; spec->dell_vostro = 1; + spec->mic_boost = 3; /* default 30dB gain */ snd_hda_attach_beep_device(codec, 0x13); /* no S/PDIF out */ -- GitLab From e2eb8e38592f28d8be4a518f44d3385272dedddb Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Fri, 8 Jan 2010 00:51:21 -0800 Subject: [PATCH 0462/3892] bnx2: Flush the register writes which setup the MSI-X table The MSI-X table size needs to be properly set before pci_enable_msix() is called. But on certain machines, the writes are delayed and the MSI-X table size is incorrectly read. By reading the BNX2_PCI_MSIX_CONTROL register, the writes are flushed and now ensure that the MSI-X table is set correctly before MSI-X is enable on the device. This patch was originally diagnosed and authored by Kalyan Ram Chintalapati . Signed-off-by: Benjamin Li Signed-off-by: Kalyan Ram Chintalapati Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 65df1de447e4..b1c20e5f7de8 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6145,6 +6145,10 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE); REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE); + /* Need to flush the previous three writes to ensure MSI-X + * is setup properly */ + REG_RD(bp, BNX2_PCI_MSIX_CONTROL); + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { msix_ent[i].entry = i; msix_ent[i].vector = 0; -- GitLab From df2f7ec8c09ce879245c3309d859218188123ef1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 8 Jan 2010 00:53:03 -0800 Subject: [PATCH 0463/3892] ep93xx_eth.c general cleanup General cleanup of the ep93xx_eth driver. 1) Use pr_fmt() to prefix the module name and __func__ to the error messages. 2) instead of 3) instead of and 4) Move the ep93xx_mdio_read (and ep93xx_mdio_write) function to eliminate the function prototype. 5) Change all the printk( messages to pr_ and remove the __func__ argument. 6) Use platform_get_{resource/irq} to get the platform resources and add an error check. 7) Use resource_size() for request_mem_region() and ioremap(). 8) Use %pM to print the MAC address at the end of the probe. 9) Use dev->dev_addr not data->dev_addr for the MAC argument because a random address could be used if the platform does not supply one. The message at the end of the probe is left as a printk since it displays cleaner without the function name that would be displayed with pr_info(). Signed-off-by: H Hartley Sweeten Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/arm/ep93xx_eth.c | 140 +++++++++++++++++------------------ 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index b25467ac895c..bf72d57a0afd 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -9,6 +9,8 @@ * (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include @@ -20,9 +22,9 @@ #include #include #include -#include -#include -#include +#include + +#include #define DRV_MODULE_NAME "ep93xx-eth" #define DRV_MODULE_VERSION "0.1" @@ -185,7 +187,47 @@ struct ep93xx_priv #define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) #define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) -static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg); +static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int data; + int i; + + wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); + + for (i = 0; i < 10; i++) { + if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) + break; + msleep(1); + } + + if (i == 10) { + pr_info("mdio read timed out\n"); + data = 0xffff; + } else { + data = rdl(ep, REG_MIIDATA); + } + + return data; +} + +static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int i; + + wrl(ep, REG_MIIDATA, data); + wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); + + for (i = 0; i < 10; i++) { + if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) + break; + msleep(1); + } + + if (i == 10) + pr_info("mdio write timed out\n"); +} static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) { @@ -217,14 +259,11 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) rstat->rstat1 = 0; if (!(rstat0 & RSTAT0_EOF)) - printk(KERN_CRIT "ep93xx_rx: not end-of-frame " - " %.8x %.8x\n", rstat0, rstat1); + pr_crit("not end-of-frame %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_EOB)) - printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " - " %.8x %.8x\n", rstat0, rstat1); + pr_crit("not end-of-buffer %.8x %.8x\n", rstat0, rstat1); if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) - printk(KERN_CRIT "ep93xx_rx: entry mismatch " - " %.8x %.8x\n", rstat0, rstat1); + pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1); if (!(rstat0 & RSTAT0_RWE)) { ep->stats.rx_errors++; @@ -241,8 +280,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) length = rstat1 & RSTAT1_FRAME_LENGTH; if (length > MAX_PKT_SIZE) { - printk(KERN_NOTICE "ep93xx_rx: invalid length " - " %.8x %.8x\n", rstat0, rstat1); + pr_notice("invalid length %.8x %.8x\n", rstat0, rstat1); goto err; } @@ -371,11 +409,9 @@ static void ep93xx_tx_complete(struct net_device *dev) tstat->tstat0 = 0; if (tstat0 & TSTAT0_FA) - printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " - " %.8x\n", tstat0); + pr_crit("frame aborted %.8x\n", tstat0); if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry) - printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch " - " %.8x\n", tstat0); + pr_crit("entry mismatch %.8x\n", tstat0); if (tstat0 & TSTAT0_TXWE) { int length = ep->descs->tdesc[entry].tdesc1 & 0xfff; @@ -536,7 +572,7 @@ static int ep93xx_start_hw(struct net_device *dev) } if (i == 10) { - printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n"); + pr_crit("hw failed to reset\n"); return 1; } @@ -581,7 +617,7 @@ static int ep93xx_start_hw(struct net_device *dev) } if (i == 10) { - printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n"); + pr_crit("hw failed to start\n"); return 1; } @@ -617,7 +653,7 @@ static void ep93xx_stop_hw(struct net_device *dev) } if (i == 10) - printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n"); + pr_crit("hw failed to reset\n"); } static int ep93xx_open(struct net_device *dev) @@ -681,48 +717,6 @@ static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return generic_mii_ioctl(&ep->mii, data, cmd, NULL); } -static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int data; - int i; - - wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); - - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) - break; - msleep(1); - } - - if (i == 10) { - printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n"); - data = 0xffff; - } else { - data = rdl(ep, REG_MIIDATA); - } - - return data; -} - -static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int i; - - wrl(ep, REG_MIIDATA, data); - wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); - - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) - break; - msleep(1); - } - - if (i == 10) - printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n"); -} - static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strcpy(info->driver, DRV_MODULE_NAME); @@ -825,12 +819,19 @@ static int ep93xx_eth_probe(struct platform_device *pdev) struct ep93xx_eth_data *data; struct net_device *dev; struct ep93xx_priv *ep; + struct resource *mem; + int irq; int err; if (pdev == NULL) return -ENODEV; data = pdev->dev.platform_data; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!mem || irq < 0) + return -ENXIO; + dev = ep93xx_dev_alloc(data); if (dev == NULL) { err = -ENOMEM; @@ -842,23 +843,21 @@ static int ep93xx_eth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - ep->res = request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1, - dev_name(&pdev->dev)); + ep->res = request_mem_region(mem->start, resource_size(mem), + dev_name(&pdev->dev)); if (ep->res == NULL) { dev_err(&pdev->dev, "Could not reserve memory region\n"); err = -ENOMEM; goto err_out; } - ep->base_addr = ioremap(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start); + ep->base_addr = ioremap(mem->start, resource_size(mem)); if (ep->base_addr == NULL) { dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); err = -EIO; goto err_out; } - ep->irq = pdev->resource[1].start; + ep->irq = irq; ep->mii.phy_id = data->phy_id; ep->mii.phy_id_mask = 0x1f; @@ -877,11 +876,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev) goto err_out; } - printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, " - "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, - ep->irq, data->dev_addr[0], data->dev_addr[1], - data->dev_addr[2], data->dev_addr[3], - data->dev_addr[4], data->dev_addr[5]); + printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, %pM\n", + dev->name, ep->irq, dev->dev_addr); return 0; -- GitLab From 5856b606e69d3e4dc2d718b475e216eb30ee2006 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 8 Jan 2010 00:59:52 -0800 Subject: [PATCH 0464/3892] net/ipv6/tcp_ipv6.c: Use compressed IPv6 address Use "[compressed ipv6]:port" form suggested by: http://tools.ietf.org/id/draft-ietf-6man-text-addr-representation-03.txt Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index febfd595a40d..1c832bf198b3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -876,7 +876,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", + printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", genhash ? "failed" : "mismatch", &ip6h->saddr, ntohs(th->source), &ip6h->daddr, ntohs(th->dest)); -- GitLab From 2d4b6faf7d1818e9a52ae9f068ab4ffd9c3be923 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Thu, 7 Jan 2010 09:43:06 +0000 Subject: [PATCH 0465/3892] can: mscan: fix improper return if dlc < 8 in start_xmit function The start_xmit function of the MSCAN Driver did return improperly if the CAN dlc check failed (skb not freed and invalid return code). This patch adds a proper check of the frame lenght and data size and returns now correctly. The invalid skb packets are dropped silently as suggested by David Miller in the thread "[RFC] ndo_validate_skb: Let the netdev check a valid skb content" on the netdev mailing list. Furthermore, a typo has been fixed. Signed-off-by: Wolfgang Grandegger Reviewed-by: Wolfram Sang Signed-off-by: David S. Miller --- drivers/net/can/mscan/mscan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 07346f880ca6..0dcbe8cfab64 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -4,7 +4,7 @@ * Copyright (C) 2005-2006 Andrey Volkov , * Varma Electronics Oy * Copyright (C) 2008-2009 Wolfgang Grandegger - * Copytight (C) 2008-2009 Pengutronix + * Copyright (C) 2008-2009 Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the version 2 of the GNU General Public License @@ -177,8 +177,11 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) int i, rtr, buf_id; u32 can_id; - if (frame->can_dlc > 8) - return -EINVAL; + if (skb->len != sizeof(*frame) || frame->can_dlc > 8) { + kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } out_8(®s->cantier, 0); -- GitLab From bf3af54732bea5894ccc2cbde3ab566f0af7da56 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Thu, 7 Jan 2010 09:43:07 +0000 Subject: [PATCH 0466/3892] can: mscan-mpc5xxx: add support for the MPC512x processor The main differences compared to the MSCAN on the MPC5200 are: - More flexibility in choosing the CAN source clock and frequency: Three different clock sources can be selected: "ip", "ref" or "sys". For the latter two, a clock divider can be defined as well. If the clock source is not specified by the device tree, we first try to find an optimal CAN source clock based on the system clock. If that is not possible, the reference clock will be used. - The behavior of bus-off recovery is configurable: To comply with the usual handling of Socket-CAN bus-off recovery, "recovery on request" is selected (instead of automatic recovery). Note that only MPC5121 Rev. 2 and later is supported. Signed-off-by: Wolfgang Grandegger Reviewed-by: Wolfram Sang Signed-off-by: David S. Miller --- drivers/net/can/mscan/Kconfig | 7 +- drivers/net/can/mscan/mpc5xxx_can.c | 246 +++++++++++++++++++++++----- drivers/net/can/mscan/mscan.c | 51 ++++-- drivers/net/can/mscan/mscan.h | 86 +++++----- 4 files changed, 295 insertions(+), 95 deletions(-) diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig index cd0f2d6f375d..27d1d398e25e 100644 --- a/drivers/net/can/mscan/Kconfig +++ b/drivers/net/can/mscan/Kconfig @@ -11,12 +11,13 @@ if CAN_MSCAN config CAN_MPC5XXX tristate "Freescale MPC5xxx onboard CAN controller" - depends on PPC_MPC52xx + depends on (PPC_MPC52xx || PPC_MPC512x) ---help--- If you say yes here you get support for Freescale's MPC5xxx - onboard CAN controller. + onboard CAN controller. Currently, the MPC5200, MPC5200B and + MPC5121 (Rev. 2 and later) are supported. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called mscan-mpc5xxx.ko. endif diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 1de6f6349b16..f73487f723b8 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -36,22 +37,21 @@ #define DRV_NAME "mpc5xxx_can" -static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = { +struct mpc5xxx_can_data { + unsigned int type; + u32 (*get_clock)(struct of_device *ofdev, const char *clock_name, + int *mscan_clksrc); +}; + +#ifdef CONFIG_PPC_MPC5200 +static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = { { .compatible = "fsl,mpc5200-cdm", }, {} }; -/* - * Get frequency of the MSCAN clock source - * - * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK) - * can be selected. According to the MPC5200 user's manual, the oscillator - * clock is the better choice as it has less jitter but due to a hardware - * bug, it can not be selected for the old MPC5200 Rev. A chips. - */ - -static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of, - int clock_src) +static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, + const char *clock_name, + int *mscan_clksrc) { unsigned int pvr; struct mpc52xx_cdm __iomem *cdm; @@ -61,11 +61,24 @@ static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of, pvr = mfspr(SPRN_PVR); - freq = mpc5xxx_get_bus_frequency(of->node); + /* + * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock + * (IP_CLK) can be selected as MSCAN clock source. According to + * the MPC5200 user's manual, the oscillator clock is the better + * choice as it has less jitter. For this reason, it is selected + * by default. Unfortunately, it can not be selected for the old + * MPC5200 Rev. A chips due to a hardware bug (check errata). + */ + if (clock_name && strcmp(clock_name, "ip") == 0) + *mscan_clksrc = MSCAN_CLKSRC_BUS; + else + *mscan_clksrc = MSCAN_CLKSRC_XTAL; + + freq = mpc5xxx_get_bus_frequency(ofdev->node); if (!freq) return 0; - if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011) + if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011) return freq; /* Determine SYS_XTAL_IN frequency from the clock domain settings */ @@ -75,7 +88,6 @@ static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of, return 0; } cdm = of_iomap(np_cdm, 0); - of_node_put(np_cdm); if (in_8(&cdm->ipb_clk_sel) & 0x1) freq *= 2; @@ -84,26 +96,174 @@ static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of, freq *= (val & (1 << 5)) ? 8 : 4; freq /= (val & (1 << 6)) ? 12 : 16; + of_node_put(np_cdm); iounmap(cdm); return freq; } +#else /* !CONFIG_PPC_MPC5200 */ +static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, + const char *clock_name, + int *mscan_clksrc) +{ + return 0; +} +#endif /* CONFIG_PPC_MPC5200 */ + +#ifdef CONFIG_PPC_MPC512x +struct mpc512x_clockctl { + u32 spmr; /* System PLL Mode Reg */ + u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ + u32 scfr1; /* System Clk Freq Reg 1 */ + u32 scfr2; /* System Clk Freq Reg 2 */ + u32 reserved; + u32 bcr; /* Bread Crumb Reg */ + u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */ + u32 spccr; /* SPDIF Clk Ctrl Reg */ + u32 cccr; /* CFM Clk Ctrl Reg */ + u32 dccr; /* DIU Clk Cnfg Reg */ + u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */ +}; + +static struct of_device_id __devinitdata mpc512x_clock_ids[] = { + { .compatible = "fsl,mpc5121-clock", }, + {} +}; + +static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev, + const char *clock_name, + int *mscan_clksrc) +{ + struct mpc512x_clockctl __iomem *clockctl; + struct device_node *np_clock; + struct clk *sys_clk, *ref_clk; + int plen, clockidx, clocksrc = -1; + u32 sys_freq, val, clockdiv = 1, freq = 0; + const u32 *pval; + + np_clock = of_find_matching_node(NULL, mpc512x_clock_ids); + if (!np_clock) { + dev_err(&ofdev->dev, "couldn't find clock node\n"); + return -ENODEV; + } + clockctl = of_iomap(np_clock, 0); + if (!clockctl) { + dev_err(&ofdev->dev, "couldn't map clock registers\n"); + return 0; + } + + /* Determine the MSCAN device index from the physical address */ + pval = of_get_property(ofdev->node, "reg", &plen); + BUG_ON(!pval || plen < sizeof(*pval)); + clockidx = (*pval & 0x80) ? 1 : 0; + if (*pval & 0x2000) + clockidx += 2; + + /* + * Clock source and divider selection: 3 different clock sources + * can be selected: "ip", "ref" or "sys". For the latter two, a + * clock divider can be defined as well. If the clock source is + * not specified by the device tree, we first try to find an + * optimal CAN source clock based on the system clock. If that + * is not posslible, the reference clock will be used. + */ + if (clock_name && !strcmp(clock_name, "ip")) { + *mscan_clksrc = MSCAN_CLKSRC_IPS; + freq = mpc5xxx_get_bus_frequency(ofdev->node); + } else { + *mscan_clksrc = MSCAN_CLKSRC_BUS; + + pval = of_get_property(ofdev->node, + "fsl,mscan-clock-divider", &plen); + if (pval && plen == sizeof(*pval)) + clockdiv = *pval; + if (!clockdiv) + clockdiv = 1; + + if (!clock_name || !strcmp(clock_name, "sys")) { + sys_clk = clk_get(&ofdev->dev, "sys_clk"); + if (!sys_clk) { + dev_err(&ofdev->dev, "couldn't get sys_clk\n"); + goto exit_unmap; + } + /* Get and round up/down sys clock rate */ + sys_freq = 1000000 * + ((clk_get_rate(sys_clk) + 499999) / 1000000); + + if (!clock_name) { + /* A multiple of 16 MHz would be optimal */ + if ((sys_freq % 16000000) == 0) { + clocksrc = 0; + clockdiv = sys_freq / 16000000; + freq = sys_freq / clockdiv; + } + } else { + clocksrc = 0; + freq = sys_freq / clockdiv; + } + } + + if (clocksrc < 0) { + ref_clk = clk_get(&ofdev->dev, "ref_clk"); + if (!ref_clk) { + dev_err(&ofdev->dev, "couldn't get ref_clk\n"); + goto exit_unmap; + } + clocksrc = 1; + freq = clk_get_rate(ref_clk) / clockdiv; + } + } + + /* Disable clock */ + out_be32(&clockctl->mccr[clockidx], 0x0); + if (clocksrc >= 0) { + /* Set source and divider */ + val = (clocksrc << 14) | ((clockdiv - 1) << 17); + out_be32(&clockctl->mccr[clockidx], val); + /* Enable clock */ + out_be32(&clockctl->mccr[clockidx], val | 0x10000); + } + + /* Enable MSCAN clock domain */ + val = in_be32(&clockctl->sccr[1]); + if (!(val & (1 << 25))) + out_be32(&clockctl->sccr[1], val | (1 << 25)); + + dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n", + *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" : + clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv); + +exit_unmap: + of_node_put(np_clock); + iounmap(clockctl); + + return freq; +} +#else /* !CONFIG_PPC_MPC512x */ +static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev, + const char *clock_name, + int *mscan_clksrc) +{ + return 0; +} +#endif /* CONFIG_PPC_MPC512x */ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev, const struct of_device_id *id) { + struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data; struct device_node *np = ofdev->node; struct net_device *dev; struct mscan_priv *priv; void __iomem *base; - const char *clk_src; - int err, irq, clock_src; + const char *clock_name = NULL; + int irq, mscan_clksrc = 0; + int err = -ENOMEM; - base = of_iomap(ofdev->node, 0); + base = of_iomap(np, 0); if (!base) { dev_err(&ofdev->dev, "couldn't ioremap\n"); - err = -ENOMEM; - goto exit_release_mem; + return err; } irq = irq_of_parse_and_map(np, 0); @@ -114,37 +274,27 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev, } dev = alloc_mscandev(); - if (!dev) { - err = -ENOMEM; + if (!dev) goto exit_dispose_irq; - } priv = netdev_priv(dev); priv->reg_base = base; dev->irq = irq; - /* - * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock - * (IP_CLK) can be selected as MSCAN clock source. According to - * the MPC5200 user's manual, the oscillator clock is the better - * choice as it has less jitter. For this reason, it is selected - * by default. - */ - clk_src = of_get_property(np, "fsl,mscan-clock-source", NULL); - if (clk_src && strcmp(clk_src, "ip") == 0) - clock_src = MSCAN_CLKSRC_BUS; - else - clock_src = MSCAN_CLKSRC_XTAL; - priv->can.clock.freq = mpc52xx_can_clock_freq(ofdev, clock_src); + clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL); + + BUG_ON(!data); + priv->type = data->type; + priv->can.clock.freq = data->get_clock(ofdev, clock_name, + &mscan_clksrc); if (!priv->can.clock.freq) { - dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n"); - err = -ENODEV; + dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n"); goto exit_free_mscan; } SET_NETDEV_DEV(dev, &ofdev->dev); - err = register_mscandev(dev, clock_src); + err = register_mscandev(dev, mscan_clksrc); if (err) { dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", DRV_NAME, err); @@ -164,7 +314,7 @@ exit_dispose_irq: irq_dispose_mapping(irq); exit_unmap_mem: iounmap(base); -exit_release_mem: + return err; } @@ -225,8 +375,20 @@ static int mpc5xxx_can_resume(struct of_device *ofdev) } #endif +static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = { + .type = MSCAN_TYPE_MPC5200, + .get_clock = mpc52xx_can_get_clock, +}; + +static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = { + .type = MSCAN_TYPE_MPC5121, + .get_clock = mpc512x_can_get_clock, +}; + static struct of_device_id __devinitdata mpc5xxx_can_table[] = { - {.compatible = "fsl,mpc5200-mscan"}, + { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, }, + /* Note that only MPC5121 Rev. 2 (and later) is supported */ + { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, }, {}, }; @@ -255,5 +417,5 @@ static void __exit mpc5xxx_can_exit(void) module_exit(mpc5xxx_can_exit); MODULE_AUTHOR("Wolfgang Grandegger "); -MODULE_DESCRIPTION("Freescale MPC5200 CAN driver"); +MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 0dcbe8cfab64..500d18918bd5 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -152,6 +152,12 @@ static int mscan_start(struct net_device *dev) priv->shadow_canrier = 0; priv->flags = 0; + if (priv->type == MSCAN_TYPE_MPC5121) { + /* Clear pending bus-off condition */ + if (in_8(®s->canmisc) & MSCAN_BOHOLD) + out_8(®s->canmisc, MSCAN_BOHOLD); + } + err = mscan_set_mode(dev, MSCAN_NORMAL_MODE); if (err) return err; @@ -163,8 +169,29 @@ static int mscan_start(struct net_device *dev) out_8(®s->cantier, 0); /* Enable receive interrupts. */ - out_8(®s->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | - MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0); + out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); + + return 0; +} + +static int mscan_restart(struct net_device *dev) +{ + struct mscan_priv *priv = netdev_priv(dev); + + if (priv->type == MSCAN_TYPE_MPC5121) { + struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + WARN(!(in_8(®s->canmisc) & MSCAN_BOHOLD), + "bus-off state expected"); + out_8(®s->canmisc, MSCAN_BOHOLD); + /* Re-enable receive interrupts. */ + out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); + } else { + if (priv->can.state <= CAN_STATE_BUS_OFF) + mscan_set_mode(dev, MSCAN_INIT_MODE); + return mscan_start(dev); + } return 0; } @@ -362,9 +389,12 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame, * automatically. To avoid that we stop the chip doing * a light-weight stop (we are in irq-context). */ - out_8(®s->cantier, 0); - out_8(®s->canrier, 0); - setbits8(®s->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ); + if (priv->type != MSCAN_TYPE_MPC5121) { + out_8(®s->cantier, 0); + out_8(®s->canrier, 0); + setbits8(®s->canctl0, + MSCAN_SLPRQ | MSCAN_INITRQ); + } can_bus_off(dev); break; default: @@ -494,9 +524,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode) switch (mode) { case CAN_MODE_START: - if (priv->can.state <= CAN_STATE_BUS_OFF) - mscan_set_mode(dev, MSCAN_INIT_MODE); - ret = mscan_start(dev); + ret = mscan_restart(dev); if (ret) break; if (netif_queue_stopped(dev)) @@ -595,18 +623,21 @@ static const struct net_device_ops mscan_netdev_ops = { .ndo_start_xmit = mscan_start_xmit, }; -int register_mscandev(struct net_device *dev, int clock_src) +int register_mscandev(struct net_device *dev, int mscan_clksrc) { struct mscan_priv *priv = netdev_priv(dev); struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; u8 ctl1; ctl1 = in_8(®s->canctl1); - if (clock_src) + if (mscan_clksrc) ctl1 |= MSCAN_CLKSRC; else ctl1 &= ~MSCAN_CLKSRC; + if (priv->type == MSCAN_TYPE_MPC5121) + ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */ + ctl1 |= MSCAN_CANE; out_8(®s->canctl1, ctl1); udelay(100); diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h index 00fc4aaf1ed8..4ff966473bc9 100644 --- a/drivers/net/can/mscan/mscan.h +++ b/drivers/net/can/mscan/mscan.h @@ -38,18 +38,20 @@ #define MSCAN_CLKSRC 0x40 #define MSCAN_LOOPB 0x20 #define MSCAN_LISTEN 0x10 +#define MSCAN_BORM 0x08 #define MSCAN_WUPM 0x04 #define MSCAN_SLPAK 0x02 #define MSCAN_INITAK 0x01 -/* Use the MPC5200 MSCAN variant? */ +/* Use the MPC5XXX MSCAN variant? */ #ifdef CONFIG_PPC -#define MSCAN_FOR_MPC5200 +#define MSCAN_FOR_MPC5XXX #endif -#ifdef MSCAN_FOR_MPC5200 +#ifdef MSCAN_FOR_MPC5XXX #define MSCAN_CLKSRC_BUS 0 #define MSCAN_CLKSRC_XTAL MSCAN_CLKSRC +#define MSCAN_CLKSRC_IPS MSCAN_CLKSRC #else #define MSCAN_CLKSRC_BUS MSCAN_CLKSRC #define MSCAN_CLKSRC_XTAL 0 @@ -136,7 +138,7 @@ #define MSCAN_EFF_RTR_SHIFT 0 #define MSCAN_EFF_FLAGS 0x18 /* IDE + SRR */ -#ifdef MSCAN_FOR_MPC5200 +#ifdef MSCAN_FOR_MPC5XXX #define _MSCAN_RESERVED_(n, num) u8 _res##n[num] #define _MSCAN_RESERVED_DSR_SIZE 2 #else @@ -165,67 +167,66 @@ struct mscan_regs { u8 cantbsel; /* + 0x14 0x0a */ u8 canidac; /* + 0x15 0x0b */ u8 reserved; /* + 0x16 0x0c */ - _MSCAN_RESERVED_(6, 5); /* + 0x17 */ -#ifndef MSCAN_FOR_MPC5200 - u8 canmisc; /* 0x0d */ -#endif + _MSCAN_RESERVED_(6, 2); /* + 0x17 */ + u8 canmisc; /* + 0x19 0x0d */ + _MSCAN_RESERVED_(7, 2); /* + 0x1a */ u8 canrxerr; /* + 0x1c 0x0e */ u8 cantxerr; /* + 0x1d 0x0f */ - _MSCAN_RESERVED_(7, 2); /* + 0x1e */ + _MSCAN_RESERVED_(8, 2); /* + 0x1e */ u16 canidar1_0; /* + 0x20 0x10 */ - _MSCAN_RESERVED_(8, 2); /* + 0x22 */ + _MSCAN_RESERVED_(9, 2); /* + 0x22 */ u16 canidar3_2; /* + 0x24 0x12 */ - _MSCAN_RESERVED_(9, 2); /* + 0x26 */ + _MSCAN_RESERVED_(10, 2); /* + 0x26 */ u16 canidmr1_0; /* + 0x28 0x14 */ - _MSCAN_RESERVED_(10, 2); /* + 0x2a */ + _MSCAN_RESERVED_(11, 2); /* + 0x2a */ u16 canidmr3_2; /* + 0x2c 0x16 */ - _MSCAN_RESERVED_(11, 2); /* + 0x2e */ + _MSCAN_RESERVED_(12, 2); /* + 0x2e */ u16 canidar5_4; /* + 0x30 0x18 */ - _MSCAN_RESERVED_(12, 2); /* + 0x32 */ + _MSCAN_RESERVED_(13, 2); /* + 0x32 */ u16 canidar7_6; /* + 0x34 0x1a */ - _MSCAN_RESERVED_(13, 2); /* + 0x36 */ + _MSCAN_RESERVED_(14, 2); /* + 0x36 */ u16 canidmr5_4; /* + 0x38 0x1c */ - _MSCAN_RESERVED_(14, 2); /* + 0x3a */ + _MSCAN_RESERVED_(15, 2); /* + 0x3a */ u16 canidmr7_6; /* + 0x3c 0x1e */ - _MSCAN_RESERVED_(15, 2); /* + 0x3e */ + _MSCAN_RESERVED_(16, 2); /* + 0x3e */ struct { u16 idr1_0; /* + 0x40 0x20 */ - _MSCAN_RESERVED_(16, 2); /* + 0x42 */ + _MSCAN_RESERVED_(17, 2); /* + 0x42 */ u16 idr3_2; /* + 0x44 0x22 */ - _MSCAN_RESERVED_(17, 2); /* + 0x46 */ + _MSCAN_RESERVED_(18, 2); /* + 0x46 */ u16 dsr1_0; /* + 0x48 0x24 */ - _MSCAN_RESERVED_(18, 2); /* + 0x4a */ + _MSCAN_RESERVED_(19, 2); /* + 0x4a */ u16 dsr3_2; /* + 0x4c 0x26 */ - _MSCAN_RESERVED_(19, 2); /* + 0x4e */ + _MSCAN_RESERVED_(20, 2); /* + 0x4e */ u16 dsr5_4; /* + 0x50 0x28 */ - _MSCAN_RESERVED_(20, 2); /* + 0x52 */ + _MSCAN_RESERVED_(21, 2); /* + 0x52 */ u16 dsr7_6; /* + 0x54 0x2a */ - _MSCAN_RESERVED_(21, 2); /* + 0x56 */ + _MSCAN_RESERVED_(22, 2); /* + 0x56 */ u8 dlr; /* + 0x58 0x2c */ - u8:8; /* + 0x59 0x2d */ - _MSCAN_RESERVED_(22, 2); /* + 0x5a */ + u8 reserved; /* + 0x59 0x2d */ + _MSCAN_RESERVED_(23, 2); /* + 0x5a */ u16 time; /* + 0x5c 0x2e */ } rx; - _MSCAN_RESERVED_(23, 2); /* + 0x5e */ + _MSCAN_RESERVED_(24, 2); /* + 0x5e */ struct { u16 idr1_0; /* + 0x60 0x30 */ - _MSCAN_RESERVED_(24, 2); /* + 0x62 */ + _MSCAN_RESERVED_(25, 2); /* + 0x62 */ u16 idr3_2; /* + 0x64 0x32 */ - _MSCAN_RESERVED_(25, 2); /* + 0x66 */ + _MSCAN_RESERVED_(26, 2); /* + 0x66 */ u16 dsr1_0; /* + 0x68 0x34 */ - _MSCAN_RESERVED_(26, 2); /* + 0x6a */ + _MSCAN_RESERVED_(27, 2); /* + 0x6a */ u16 dsr3_2; /* + 0x6c 0x36 */ - _MSCAN_RESERVED_(27, 2); /* + 0x6e */ + _MSCAN_RESERVED_(28, 2); /* + 0x6e */ u16 dsr5_4; /* + 0x70 0x38 */ - _MSCAN_RESERVED_(28, 2); /* + 0x72 */ + _MSCAN_RESERVED_(29, 2); /* + 0x72 */ u16 dsr7_6; /* + 0x74 0x3a */ - _MSCAN_RESERVED_(29, 2); /* + 0x76 */ + _MSCAN_RESERVED_(30, 2); /* + 0x76 */ u8 dlr; /* + 0x78 0x3c */ u8 tbpr; /* + 0x79 0x3d */ - _MSCAN_RESERVED_(30, 2); /* + 0x7a */ + _MSCAN_RESERVED_(31, 2); /* + 0x7a */ u16 time; /* + 0x7c 0x3e */ } tx; - _MSCAN_RESERVED_(31, 2); /* + 0x7e */ + _MSCAN_RESERVED_(32, 2); /* + 0x7e */ } __attribute__ ((packed)); #undef _MSCAN_RESERVED_ @@ -237,6 +238,15 @@ struct mscan_regs { #define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ) #define MSCAN_SET_MODE_RETRIES 255 #define MSCAN_ECHO_SKB_MAX 3 +#define MSCAN_RX_INTS_ENABLE (MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | \ + MSCAN_RSTATE1 | MSCAN_RSTATE0 | \ + MSCAN_TSTATE1 | MSCAN_TSTATE0) + +/* MSCAN type variants */ +enum { + MSCAN_TYPE_MPC5200, + MSCAN_TYPE_MPC5121 +}; #define BTR0_BRP_MASK 0x3f #define BTR0_SJW_SHIFT 6 @@ -270,6 +280,7 @@ struct tx_queue_entry { struct mscan_priv { struct can_priv can; /* must be the first member */ + unsigned int type; /* MSCAN type variants */ long open_time; unsigned long flags; void __iomem *reg_base; /* ioremap'ed address to registers */ @@ -285,12 +296,7 @@ struct mscan_priv { }; extern struct net_device *alloc_mscandev(void); -/* - * clock_src: - * 1 = The MSCAN clock source is the onchip Bus Clock. - * 0 = The MSCAN clock source is the chip Oscillator Clock. - */ -extern int register_mscandev(struct net_device *dev, int clock_src); +extern int register_mscandev(struct net_device *dev, int mscan_clksrc); extern void unregister_mscandev(struct net_device *dev); #endif /* __MSCAN_H__ */ -- GitLab From 959d20bfe8b90023c862dec3956054027a5a0912 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Thu, 7 Jan 2010 09:43:08 +0000 Subject: [PATCH 0467/3892] powerpc/mpc5xxx: add OF platform binding doc for FSL MSCAN devices This patch adds documentation for the MSCAN OF device bindings for the MPC512x and moves the one for the MPC5200 to the new common file "Documentation/powerpc/dts-bindings/fsl/can.txt". Signed-off-by: Wolfgang Grandegger Reviewed-by: Wolfram Sang Signed-off-by: David S. Miller --- .../powerpc/dts-bindings/fsl/can.txt | 53 +++++++++++++++++++ .../powerpc/dts-bindings/fsl/mpc5200.txt | 9 +--- 2 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 Documentation/powerpc/dts-bindings/fsl/can.txt diff --git a/Documentation/powerpc/dts-bindings/fsl/can.txt b/Documentation/powerpc/dts-bindings/fsl/can.txt new file mode 100644 index 000000000000..2fa4fcd38fd6 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/fsl/can.txt @@ -0,0 +1,53 @@ +CAN Device Tree Bindings +------------------------ + +(c) 2006-2009 Secret Lab Technologies Ltd +Grant Likely + +fsl,mpc5200-mscan nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source shall be used for the controller: + +- fsl,mscan-clock-source : a string describing the clock source. Valid values + are: "ip" for ip bus clock + "ref" for reference clock (XTAL) + "ref" is default in case this property is not + present. + +fsl,mpc5121-mscan nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source and divider shall be used for the controller: + +- fsl,mscan-clock-source : a string describing the clock source. Valid values + are: "ip" for ip bus clock + "ref" for reference clock + "sys" for system clock + If this property is not present, an optimal CAN + clock source and frequency based on the system + clock will be selected. If this is not possible, + the reference clock will be used. + +- fsl,mscan-clock-divider: for the reference and system clock, an additional + clock divider can be specified. By default, a + value of 1 is used. + +Note that the MPC5121 Rev. 1 processor is not supported. + +Examples: + can@1300 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <12 0x8>; + interrupt-parent = <&ipic>; + reg = <0x1300 0x80>; + }; + + can@1380 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <13 0x8>; + interrupt-parent = <&ipic>; + reg = <0x1380 0x80>; + fsl,mscan-clock-source = "ref"; + fsl,mscan-clock-divider = <3>; + }; diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt index 5c6602dbfdc2..4ccb2cd5df94 100644 --- a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt +++ b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt @@ -195,11 +195,4 @@ External interrupts: fsl,mpc5200-mscan nodes ----------------------- -In addition to the required compatible-, reg- and interrupt-properites, you can -also specify which clock source shall be used for the controller: - -- fsl,mscan-clock-source- a string describing the clock source. Valid values - are: "ip" for ip bus clock - "ref" for reference clock (XTAL) - "ref" is default in case this property is not - present. +See file can.txt in this directory. -- GitLab From 7f081d405adb5f905db11c6449319ab7c670722e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 7 Jan 2010 17:41:00 +0000 Subject: [PATCH 0468/3892] igb: add support for device reset interrupt This patch adds support for the global device reset interrupt. Without this change the drivers will report tx hangs on all ports when a global device reset occurs. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 484fbc83739f..e959b88be314 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4110,6 +4110,9 @@ static irqreturn_t igb_msix_other(int irq, void *data) u32 icr = rd32(E1000_ICR); /* reading ICR causes bit 31 of EICR to be cleared */ + if (icr & E1000_ICR_DRSTA) + schedule_work(&adapter->reset_task); + if (icr & E1000_ICR_DOUTSYNC) { /* HW is reporting DMA is out of sync */ adapter->stats.doosync++; @@ -4733,6 +4736,9 @@ static irqreturn_t igb_intr_msi(int irq, void *data) igb_write_itr(q_vector); + if (icr & E1000_ICR_DRSTA) + schedule_work(&adapter->reset_task); + if (icr & E1000_ICR_DOUTSYNC) { /* HW is reporting DMA is out of sync */ adapter->stats.doosync++; @@ -4772,6 +4778,9 @@ static irqreturn_t igb_intr(int irq, void *data) if (!(icr & E1000_ICR_INT_ASSERTED)) return IRQ_NONE; + if (icr & E1000_ICR_DRSTA) + schedule_work(&adapter->reset_task); + if (icr & E1000_ICR_DOUTSYNC) { /* HW is reporting DMA is out of sync */ adapter->stats.doosync++; -- GitLab From 51f5300682f5925a11edfddfd47ed47376871974 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 9 Jan 2010 23:00:32 -0800 Subject: [PATCH 0469/3892] mac8390: Fix build breakage commit 18c0019102228875cb0f6f252dad5148491e96b2 ("drivers/net/mac8390.c: Convert printk(KERN_ to pr_(") broke the build: | drivers/net/mac8390.c:306: error: expected ')' before 'version' as "version" is not a string literal, but a variable. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/mac8390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index c70bd6888c89..a8768672dc5a 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -303,7 +303,7 @@ static bool __init mac8390_init(struct net_device *dev, struct nubus_dev *ndev, int offset; volatile unsigned short *i; - printk_once(KERN_INFO pr_fmt(version)); + printk_once(KERN_INFO pr_fmt("%s"), version); dev->irq = SLOT2IRQ(ndev->board->slot); /* This is getting to be a habit */ -- GitLab From ce7b39a181571ed5a87f3ca62d4cffe4835c6ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sat, 9 Jan 2010 23:23:02 -0800 Subject: [PATCH 0470/3892] Input: make i2c device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct i2c_driver is defined as constant in so it makes sense to mark the initialization data also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt2160.c | 2 +- drivers/input/misc/apanel.c | 2 +- drivers/input/touchscreen/tsc2007.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 191cc51d6cf8..31f30087b591 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -362,7 +362,7 @@ static int __devexit qt2160_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id qt2160_idtable[] = { +static const struct i2c_device_id qt2160_idtable[] = { { "qt2160", 0, }, { } }; diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index 71b82434264d..a8d2b8db4e35 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -149,7 +149,7 @@ static void apanel_shutdown(struct i2c_client *client) apanel_remove(client); } -static struct i2c_device_id apanel_id[] = { +static const struct i2c_device_id apanel_id[] = { { "fujitsu_apanel", 0 }, { } }; diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 7ef0d1420d3c..be23780e8a3e 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -358,7 +358,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id tsc2007_idtable[] = { +static const struct i2c_device_id tsc2007_idtable[] = { { "tsc2007", 0 }, { } }; -- GitLab From ef9a16f15dccba6630d8860a964a4adef1a4ab98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sat, 9 Jan 2010 23:23:02 -0800 Subject: [PATCH 0471/3892] Input: xilinx_ps2 - make Open Firmware device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The match_table field of the struct of_device_id is constant in so it makes sense to mark xps2_of_match also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/serio/xilinx_ps2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index ebb22f88c842..78c64fb8a4b0 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -354,7 +354,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev) } /* Match table for of_platform binding */ -static struct of_device_id xps2_of_match[] __devinitdata = { +static const struct of_device_id xps2_of_match[] __devinitconst = { { .compatible = "xlnx,xps-ps2-1.00.a", }, { /* end of list */ }, }; -- GitLab From a9844b18502bde376284e4ad83b04fa20eb5afa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sat, 9 Jan 2010 23:23:58 -0800 Subject: [PATCH 0472/3892] Input: make PCI device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct pci_driver is constant in so it makes sense to mark initialization data also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/emu10k1-gp.c | 2 +- drivers/input/gameport/fm801-gp.c | 2 +- drivers/input/serio/pcips2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index b04930f7ea7d..7392992da424 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -46,7 +46,7 @@ struct emu { int size; }; -static struct pci_device_id emu_tbl[] = { +static const struct pci_device_id emu_tbl[] = { { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 8a1810f88b9e..14d3f3e208a2 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -140,7 +140,7 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci) } } -static struct pci_device_id fm801_gp_id_table[] = { +static const struct pci_device_id fm801_gp_id_table[] = { { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 } }; diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 1dacbe0d9348..797314be7af2 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -186,7 +186,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev) pci_disable_device(dev); } -static struct pci_device_id pcips2_ids[] = { +static const struct pci_device_id pcips2_ids[] = { { .vendor = 0x14f2, /* MOBILITY */ .device = 0x0123, /* Keyboard */ -- GitLab From 35c4b918a696f20cb775f1a65955c8ed0fe7c052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sat, 9 Jan 2010 23:24:48 -0800 Subject: [PATCH 0473/3892] Input: ns558 - make pnp device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct pnp_driver is constant in so it makes sense to mark pnp_devids also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/ns558.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index db556b71ddda..7c217848613e 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -166,7 +166,7 @@ static int ns558_isa_probe(int io) #ifdef CONFIG_PNP -static struct pnp_device_id pnp_devids[] = { +static const struct pnp_device_id pnp_devids[] = { { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */ { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */ { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */ -- GitLab From c6d5709384090de541158a6bba8d4ae50242ff94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sat, 9 Jan 2010 23:25:44 -0800 Subject: [PATCH 0474/3892] Input: xen-kbdfront - make xenbus device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ids field of the struct xenbus_device_id is constant in so it makes sense to mark xenkbd_ids also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/xen-kbdfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index c721c0a23eb8..d30436fee476 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -321,7 +321,7 @@ InitWait: } } -static struct xenbus_device_id xenkbd_ids[] = { +static const struct xenbus_device_id xenkbd_ids[] = { { "vkbd" }, { "" } }; -- GitLab From c3f6c21d6e60e39c81c27f18ebad9c7615eff545 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Jan 2010 00:43:03 +0000 Subject: [PATCH 0475/3892] NET: ipv6, remove unnecessary check Stanse found a potential null dereference in snmp6_unregister_dev. There is a check for idev being NULL, but it is dereferenced earlier. But idev cannot be NULL when passed to snmp6_unregister_dev, so remove the test. Signed-off-by: Jiri Slaby Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: "Pekka Savola (ipv6)" Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- net/ipv6/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index c9605c3ad91f..7b197b7132e0 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -259,7 +259,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) struct net *net = dev_net(idev->dev); if (!net->mib.proc_net_devsnmp6) return -ENOENT; - if (!idev || !idev->stats.proc_dir_entry) + if (!idev->stats.proc_dir_entry) return -EINVAL; remove_proc_entry(idev->stats.proc_dir_entry->name, net->mib.proc_net_devsnmp6); -- GitLab From c026ca581f22497c42cbe7a2004fa0d5f1bd6c42 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Jan 2010 01:17:34 +0000 Subject: [PATCH 0476/3892] NET: irda, remove unnecessary checks Stanse found a potential null dereference in ircomm_tty_close and ircomm_tty_hangup. There is a check for tty being NULL, but it is dereferenced earlier. But it is bogus, the tty cannot be NULL, so remove the !tty checks. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: "David S. Miller" Cc: Alan Cox Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- net/irda/ircomm/ircomm_tty.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 811984d9324b..8b85d774e47f 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -496,9 +496,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) IRDA_DEBUG(0, "%s()\n", __func__ ); - if (!tty) - return; - IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -1007,9 +1004,6 @@ static void ircomm_tty_hangup(struct tty_struct *tty) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - if (!tty) - return; - /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); -- GitLab From 50d9c84ee522ce6f61cd6a7dfce1b82a260edd3c Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:23:11 +0000 Subject: [PATCH 0477/3892] ixgbevf: Macros, data structures, useful defines and registers These two headers define the commonly used macros, data structures, register bits and register offsets used by the ixgbevf driver on the 82599 virtual function device Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/defines.h | 292 ++++++++++++++++++++++++++++++++++ drivers/net/ixgbevf/regs.h | 85 ++++++++++ 2 files changed, 377 insertions(+) create mode 100644 drivers/net/ixgbevf/defines.h create mode 100644 drivers/net/ixgbevf/regs.h diff --git a/drivers/net/ixgbevf/defines.h b/drivers/net/ixgbevf/defines.h new file mode 100644 index 000000000000..c44fdb05447a --- /dev/null +++ b/drivers/net/ixgbevf/defines.h @@ -0,0 +1,292 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBEVF_DEFINES_H_ +#define _IXGBEVF_DEFINES_H_ + +/* Device IDs */ +#define IXGBE_DEV_ID_82599_VF 0x10ED + +#define IXGBE_VF_IRQ_CLEAR_MASK 7 +#define IXGBE_VF_MAX_TX_QUEUES 1 +#define IXGBE_VF_MAX_RX_QUEUES 1 +#define IXGBE_ETH_LENGTH_OF_ADDRESS 6 + +/* Link speed */ +typedef u32 ixgbe_link_speed; +#define IXGBE_LINK_SPEED_1GB_FULL 0x0020 +#define IXGBE_LINK_SPEED_10GB_FULL 0x0080 + +#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ +#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ +#define IXGBE_LINKS_UP 0x40000000 +#define IXGBE_LINKS_SPEED 0x20000000 + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024 + +/* Interrupt Vector Allocation Registers */ +#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */ + +#define IXGBE_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */ + +/* Receive Config masks */ +#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ +#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ +#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ + +/* DCA Control */ +#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ + +/* PSRTYPE bit definitions */ +#define IXGBE_PSRTYPE_TCPHDR 0x00000010 +#define IXGBE_PSRTYPE_UDPHDR 0x00000020 +#define IXGBE_PSRTYPE_IPV4HDR 0x00000100 +#define IXGBE_PSRTYPE_IPV6HDR 0x00000200 +#define IXGBE_PSRTYPE_L2HDR 0x00001000 + +/* SRRCTL bit definitions */ +#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +#define IXGBE_SRRCTL_RDMTS_SHIFT 22 +#define IXGBE_SRRCTL_RDMTS_MASK 0x01C00000 +#define IXGBE_SRRCTL_DROP_EN 0x10000000 +#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 +#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 +#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000 + +/* Receive Descriptor bit definitions */ +#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IXGBE_RXD_STAT_FLM 0x04 /* FDir Match */ +#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define IXGBE_RXDADV_NEXTP_MASK 0x000FFFF0 /* Next Descriptor Index */ +#define IXGBE_RXDADV_NEXTP_SHIFT 0x00000004 +#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ +#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ +#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ +#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define IXGBE_RXD_STAT_TS 0x10000 /* Time Stamp */ +#define IXGBE_RXD_STAT_SECP 0x20000 /* Security Processing */ +#define IXGBE_RXD_STAT_LB 0x40000 /* Loopback Status */ +#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */ +#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */ +#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */ +#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */ +#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ +#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ +#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ +#define IXGBE_RXDADV_ERR_MASK 0xFFF00000 /* RDESC.ERRORS mask */ +#define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ +#define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */ +#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ +#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ +#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ +#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */ +#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */ +#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */ +#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */ +#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define IXGBE_RXD_PRI_SHIFT 13 +#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define IXGBE_RXD_CFI_SHIFT 12 + +#define IXGBE_RXDADV_STAT_DD IXGBE_RXD_STAT_DD /* Done */ +#define IXGBE_RXDADV_STAT_EOP IXGBE_RXD_STAT_EOP /* End of Packet */ +#define IXGBE_RXDADV_STAT_FLM IXGBE_RXD_STAT_FLM /* FDir Match */ +#define IXGBE_RXDADV_STAT_VP IXGBE_RXD_STAT_VP /* IEEE VLAN Pkt */ +#define IXGBE_RXDADV_STAT_MASK 0x000FFFFF /* Stat/NEXTP: bit 0-19 */ +#define IXGBE_RXDADV_STAT_FCEOFS 0x00000040 /* FCoE EOF/SOF Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT 0x00000030 /* FCoE Pkt Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT_NOMTCH 0x00000000 /* 00: No Ctxt Match */ +#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ +#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ +#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ + +#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F +#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 +#define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0 +#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 +#define IXGBE_RXDADV_RSCCNT_SHIFT 17 +#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 +#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 +#define IXGBE_RXDADV_SPH 0x8000 + +#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXD_ERR_CE | \ + IXGBE_RXD_ERR_LE | \ + IXGBE_RXD_ERR_PE | \ + IXGBE_RXD_ERR_OSE | \ + IXGBE_RXD_ERR_USE) + +#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXDADV_ERR_CE | \ + IXGBE_RXDADV_ERR_LE | \ + IXGBE_RXDADV_ERR_PE | \ + IXGBE_RXDADV_ERR_OSE | \ + IXGBE_RXDADV_ERR_USE) + +#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */ + +/* Transmit Descriptor - Advanced */ +union ixgbe_adv_tx_desc { + struct { + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; + } read; + struct { + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; + } wb; +}; + +/* Receive Descriptor - Advanced */ +union ixgbe_adv_rx_desc { + struct { + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + union { + __le32 data; + struct { + __le16 pkt_info; /* RSS, Pkt type */ + __le16 hdr_info; /* Splithdr, hdrlen */ + } hs_rss; + } lo_dword; + union { + __le32 rss; /* RSS Hash */ + struct { + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +/* Context descriptors */ +struct ixgbe_adv_tx_context_desc { + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; +}; + +/* Adv Transmit Descriptor Config Masks */ +#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ +#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ +#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ +#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ +#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ +#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ +#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ +#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ +#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ +#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +/* Interrupt register bitmasks */ + +/* Extended Interrupt Cause Read */ +#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ +#define IXGBE_EICR_MAILBOX 0x00080000 /* VF to PF Mailbox Interrupt */ +#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ + +/* Extended Interrupt Cause Set */ +#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EICS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */ +#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Set */ +#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */ +#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Clear */ +#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMC_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */ +#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +#define IXGBE_EIMS_ENABLE_MASK ( \ + IXGBE_EIMS_RTX_QUEUE | \ + IXGBE_EIMS_MAILBOX | \ + IXGBE_EIMS_OTHER) + +#define IXGBE_EITR_CNT_WDIS 0x80000000 + +/* Error Codes */ +#define IXGBE_ERR_INVALID_MAC_ADDR -1 +#define IXGBE_ERR_RESET_FAILED -2 + +#endif /* _IXGBEVF_DEFINES_H_ */ diff --git a/drivers/net/ixgbevf/regs.h b/drivers/net/ixgbevf/regs.h new file mode 100644 index 000000000000..12f75960aec1 --- /dev/null +++ b/drivers/net/ixgbevf/regs.h @@ -0,0 +1,85 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBEVF_REGS_H_ +#define _IXGBEVF_REGS_H_ + +#define IXGBE_VFCTRL 0x00000 +#define IXGBE_VFSTATUS 0x00008 +#define IXGBE_VFLINKS 0x00010 +#define IXGBE_VFRTIMER 0x00048 +#define IXGBE_VFRXMEMWRAP 0x03190 +#define IXGBE_VTEICR 0x00100 +#define IXGBE_VTEICS 0x00104 +#define IXGBE_VTEIMS 0x00108 +#define IXGBE_VTEIMC 0x0010C +#define IXGBE_VTEIAC 0x00110 +#define IXGBE_VTEIAM 0x00114 +#define IXGBE_VTEITR(x) (0x00820 + (4 * x)) +#define IXGBE_VTIVAR(x) (0x00120 + (4 * x)) +#define IXGBE_VTIVAR_MISC 0x00140 +#define IXGBE_VTRSCINT(x) (0x00180 + (4 * x)) +#define IXGBE_VFRDBAL(x) (0x01000 + (0x40 * x)) +#define IXGBE_VFRDBAH(x) (0x01004 + (0x40 * x)) +#define IXGBE_VFRDLEN(x) (0x01008 + (0x40 * x)) +#define IXGBE_VFRDH(x) (0x01010 + (0x40 * x)) +#define IXGBE_VFRDT(x) (0x01018 + (0x40 * x)) +#define IXGBE_VFRXDCTL(x) (0x01028 + (0x40 * x)) +#define IXGBE_VFSRRCTL(x) (0x01014 + (0x40 * x)) +#define IXGBE_VFRSCCTL(x) (0x0102C + (0x40 * x)) +#define IXGBE_VFPSRTYPE 0x00300 +#define IXGBE_VFTDBAL(x) (0x02000 + (0x40 * x)) +#define IXGBE_VFTDBAH(x) (0x02004 + (0x40 * x)) +#define IXGBE_VFTDLEN(x) (0x02008 + (0x40 * x)) +#define IXGBE_VFTDH(x) (0x02010 + (0x40 * x)) +#define IXGBE_VFTDT(x) (0x02018 + (0x40 * x)) +#define IXGBE_VFTXDCTL(x) (0x02028 + (0x40 * x)) +#define IXGBE_VFTDWBAL(x) (0x02038 + (0x40 * x)) +#define IXGBE_VFTDWBAH(x) (0x0203C + (0x40 * x)) +#define IXGBE_VFDCA_RXCTRL(x) (0x0100C + (0x40 * x)) +#define IXGBE_VFDCA_TXCTRL(x) (0x0200c + (0x40 * x)) +#define IXGBE_VFGPRC 0x0101C +#define IXGBE_VFGPTC 0x0201C +#define IXGBE_VFGORC_LSB 0x01020 +#define IXGBE_VFGORC_MSB 0x01024 +#define IXGBE_VFGOTC_LSB 0x02020 +#define IXGBE_VFGOTC_MSB 0x02024 +#define IXGBE_VFMPRC 0x01034 + +#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) + +#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg)) + +#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + writel((value), ((a)->hw_addr + (reg) + ((offset) << 2)))) + +#define IXGBE_READ_REG_ARRAY(a, reg, offset) ( \ + readl((a)->hw_addr + (reg) + ((offset) << 2))) + +#define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS)) + +#endif /* _IXGBEVF_REGS_H_ */ -- GitLab From 3047f90bd515b38e62094eff90b299f379ab7243 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:23:31 +0000 Subject: [PATCH 0478/3892] ixgbevf: 82599 Virtual Function core functions and header This module and header file contain the core functions for the 82599 virtual function device. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/vf.c | 387 +++++++++++++++++++++++++++++++++++++++ drivers/net/ixgbevf/vf.h | 168 +++++++++++++++++ 2 files changed, 555 insertions(+) create mode 100644 drivers/net/ixgbevf/vf.c create mode 100644 drivers/net/ixgbevf/vf.h diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c new file mode 100644 index 000000000000..4b5dec0ec140 --- /dev/null +++ b/drivers/net/ixgbevf/vf.c @@ -0,0 +1,387 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "vf.h" + +/** + * ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +static s32 ixgbevf_start_hw_vf(struct ixgbe_hw *hw) +{ + /* Clear adapter stopped flag */ + hw->adapter_stopped = false; + + return 0; +} + +/** + * ixgbevf_init_hw_vf - virtual function hardware initialization + * @hw: pointer to hardware structure + * + * Initialize the hardware by resetting the hardware and then starting + * the hardware + **/ +static s32 ixgbevf_init_hw_vf(struct ixgbe_hw *hw) +{ + s32 status = hw->mac.ops.start_hw(hw); + + hw->mac.ops.get_mac_addr(hw, hw->mac.addr); + + return status; +} + +/** + * ixgbevf_reset_hw_vf - Performs hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by reseting the transmit and receive units, masks and + * clears all interrupts. + **/ +static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 timeout = IXGBE_VF_INIT_TIMEOUT; + s32 ret_val = IXGBE_ERR_INVALID_MAC_ADDR; + u32 msgbuf[IXGBE_VF_PERMADDR_MSG_LEN]; + u8 *addr = (u8 *)(&msgbuf[1]); + + /* Call adapter stop to disable tx/rx and clear interrupts */ + hw->mac.ops.stop_adapter(hw); + + IXGBE_WRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST); + IXGBE_WRITE_FLUSH(hw); + + /* we cannot reset while the RSTI / RSTD bits are asserted */ + while (!mbx->ops.check_for_rst(hw) && timeout) { + timeout--; + udelay(5); + } + + if (!timeout) + return IXGBE_ERR_RESET_FAILED; + + /* mailbox timeout can now become active */ + mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; + + msgbuf[0] = IXGBE_VF_RESET; + mbx->ops.write_posted(hw, msgbuf, 1); + + msleep(10); + + /* set our "perm_addr" based on info provided by PF */ + /* also set up the mc_filter_type which is piggy backed + * on the mac address in word 3 */ + ret_val = mbx->ops.read_posted(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN); + if (ret_val) + return ret_val; + + if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK)) + return IXGBE_ERR_INVALID_MAC_ADDR; + + memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD]; + + return 0; +} + +/** + * ixgbevf_stop_hw_vf - Generic stop Tx/Rx units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +static s32 ixgbevf_stop_hw_vf(struct ixgbe_hw *hw) +{ + u32 number_of_queues; + u32 reg_val; + u16 i; + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = true; + + /* Disable the receive unit by stopped each queue */ + number_of_queues = hw->mac.max_rx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); + if (reg_val & IXGBE_RXDCTL_ENABLE) { + reg_val &= ~IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), reg_val); + } + } + + IXGBE_WRITE_FLUSH(hw); + + /* Clear interrupt mask to stop from interrupts being generated */ + IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK); + + /* Clear any pending interrupts */ + IXGBE_READ_REG(hw, IXGBE_VTEICR); + + /* Disable the transmit unit. Each queue must be disabled. */ + number_of_queues = hw->mac.max_tx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); + if (reg_val & IXGBE_TXDCTL_ENABLE) { + reg_val &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), reg_val); + } + } + + return 0; +} + +/** + * ixgbevf_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the MCSTCTRL. The MO field is set during initialization + * to mc_filter_type. + **/ +static s32 ixgbevf_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * ixgbevf_get_mac_addr_vf - Read device MAC address + * @hw: pointer to the HW structure + * @mac_addr: pointer to storage for retrieved MAC address + **/ +static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr) +{ + memcpy(mac_addr, hw->mac.perm_addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + + return 0; +} + +/** + * ixgbevf_set_rar_vf - set device MAC address + * @hw: pointer to hardware structure + * @index: Receive address register to write + * @addr: Address to put into receive address register + * @vmdq: Unused in this implementation + **/ +static s32 ixgbevf_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr, + u32 vmdq) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 msgbuf[3]; + u8 *msg_addr = (u8 *)(&msgbuf[1]); + s32 ret_val; + + memset(msgbuf, 0, sizeof(msgbuf)); + msgbuf[0] = IXGBE_VF_SET_MAC_ADDR; + memcpy(msg_addr, addr, 6); + ret_val = mbx->ops.write_posted(hw, msgbuf, 3); + + if (!ret_val) + ret_val = mbx->ops.read_posted(hw, msgbuf, 3); + + msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; + + /* if nacked the address was rejected, use "perm_addr" */ + if (!ret_val && + (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK))) + ixgbevf_get_mac_addr_vf(hw, hw->mac.addr); + + return ret_val; +} + +/** + * ixgbevf_update_mc_addr_list_vf - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @next: caller supplied function to return next address in list + * + * Updates the Multicast Table Array. + **/ +static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, + ixgbe_mc_addr_itr next) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 msgbuf[IXGBE_VFMAILBOX_SIZE]; + u16 *vector_list = (u16 *)&msgbuf[1]; + u32 vector; + u32 cnt, i; + u32 vmdq; + + /* Each entry in the list uses 1 16 bit word. We have 30 + * 16 bit words available in our HW msg buffer (minus 1 for the + * msg type). That's 30 hash values if we pack 'em right. If + * there are more than 30 MC addresses to add then punt the + * extras for now and then add code to handle more than 30 later. + * It would be unusual for a server to request that many multi-cast + * addresses except for in large enterprise network environments. + */ + + cnt = (mc_addr_count > 30) ? 30 : mc_addr_count; + msgbuf[0] = IXGBE_VF_SET_MULTICAST; + msgbuf[0] |= cnt << IXGBE_VT_MSGINFO_SHIFT; + + for (i = 0; i < cnt; i++) { + vector = ixgbevf_mta_vector(hw, next(hw, &mc_addr_list, &vmdq)); + vector_list[i] = vector; + } + + mbx->ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE); + + return 0; +} + +/** + * ixgbevf_set_vfta_vf - Set/Unset vlan filter table address + * @hw: pointer to the HW structure + * @vlan: 12 bit VLAN ID + * @vind: unused by VF drivers + * @vlan_on: if true then set bit, else clear bit + **/ +static s32 ixgbevf_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 msgbuf[2]; + + msgbuf[0] = IXGBE_VF_SET_VLAN; + msgbuf[1] = vlan; + /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */ + msgbuf[0] |= vlan_on << IXGBE_VT_MSGINFO_SHIFT; + + return mbx->ops.write_posted(hw, msgbuf, 2); +} + +/** + * ixgbevf_setup_mac_link_vf - Setup MAC link settings + * @hw: pointer to hardware structure + * @speed: Unused in this implementation + * @autoneg: Unused in this implementation + * @autoneg_wait_to_complete: Unused in this implementation + * + * Do nothing and return success. VF drivers are not allowed to change + * global settings. Maintained for driver compatibility. + **/ +static s32 ixgbevf_setup_mac_link_vf(struct ixgbe_hw *hw, + ixgbe_link_speed speed, bool autoneg, + bool autoneg_wait_to_complete) +{ + return 0; +} + +/** + * ixgbevf_check_mac_link_vf - Get link/speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true is link is up, false otherwise + * @autoneg_wait_to_complete: true when waiting for completion is needed + * + * Reads the links register to determine if link is up and the current speed + **/ +static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up, + bool autoneg_wait_to_complete) +{ + u32 links_reg; + + if (!(hw->mbx.ops.check_for_rst(hw))) { + *link_up = false; + *speed = 0; + return -1; + } + + links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS); + + if (links_reg & IXGBE_LINKS_UP) + *link_up = true; + else + *link_up = false; + + if (links_reg & IXGBE_LINKS_SPEED) + *speed = IXGBE_LINK_SPEED_10GB_FULL; + else + *speed = IXGBE_LINK_SPEED_1GB_FULL; + + return 0; +} + +struct ixgbe_mac_operations ixgbevf_mac_ops = { + .init_hw = ixgbevf_init_hw_vf, + .reset_hw = ixgbevf_reset_hw_vf, + .start_hw = ixgbevf_start_hw_vf, + .get_mac_addr = ixgbevf_get_mac_addr_vf, + .stop_adapter = ixgbevf_stop_hw_vf, + .setup_link = ixgbevf_setup_mac_link_vf, + .check_link = ixgbevf_check_mac_link_vf, + .set_rar = ixgbevf_set_rar_vf, + .update_mc_addr_list = ixgbevf_update_mc_addr_list_vf, + .set_vfta = ixgbevf_set_vfta_vf, +}; + +struct ixgbevf_info ixgbevf_vf_info = { + .mac = ixgbe_mac_82599_vf, + .mac_ops = &ixgbevf_mac_ops, +}; + diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h new file mode 100644 index 000000000000..799600e92700 --- /dev/null +++ b/drivers/net/ixgbevf/vf.h @@ -0,0 +1,168 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef __IXGBE_VF_H__ +#define __IXGBE_VF_H__ + +#include +#include +#include +#include + +#include "defines.h" +#include "regs.h" +#include "mbx.h" + +struct ixgbe_hw; + +/* iterator type for walking multicast address lists */ +typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, + u32 *vmdq); +struct ixgbe_mac_operations { + s32 (*init_hw)(struct ixgbe_hw *); + s32 (*reset_hw)(struct ixgbe_hw *); + s32 (*start_hw)(struct ixgbe_hw *); + s32 (*clear_hw_cntrs)(struct ixgbe_hw *); + enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); + u32 (*get_supported_physical_layer)(struct ixgbe_hw *); + s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*stop_adapter)(struct ixgbe_hw *); + s32 (*get_bus_info)(struct ixgbe_hw *); + + /* Link */ + s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); + s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, + bool *); + + /* RAR, Multicast, VLAN */ + s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32); + s32 (*init_rx_addrs)(struct ixgbe_hw *); + s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, + ixgbe_mc_addr_itr); + s32 (*enable_mc)(struct ixgbe_hw *); + s32 (*disable_mc)(struct ixgbe_hw *); + s32 (*clear_vfta)(struct ixgbe_hw *); + s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool); +}; + +enum ixgbe_mac_type { + ixgbe_mac_unknown = 0, + ixgbe_mac_82599_vf, + ixgbe_num_macs +}; + +struct ixgbe_mac_info { + struct ixgbe_mac_operations ops; + u8 addr[6]; + u8 perm_addr[6]; + + enum ixgbe_mac_type type; + + s32 mc_filter_type; + + bool get_link_status; + u32 max_tx_queues; + u32 max_rx_queues; + u32 max_msix_vectors; +}; + +struct ixgbe_mbx_operations { + s32 (*init_params)(struct ixgbe_hw *hw); + s32 (*read)(struct ixgbe_hw *, u32 *, u16); + s32 (*write)(struct ixgbe_hw *, u32 *, u16); + s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16); + s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16); + s32 (*check_for_msg)(struct ixgbe_hw *); + s32 (*check_for_ack)(struct ixgbe_hw *); + s32 (*check_for_rst)(struct ixgbe_hw *); +}; + +struct ixgbe_mbx_stats { + u32 msgs_tx; + u32 msgs_rx; + + u32 acks; + u32 reqs; + u32 rsts; +}; + +struct ixgbe_mbx_info { + struct ixgbe_mbx_operations ops; + struct ixgbe_mbx_stats stats; + u32 timeout; + u32 udelay; + u32 v2p_mailbox; + u16 size; +}; + +struct ixgbe_hw { + void *back; + + u8 __iomem *hw_addr; + u8 *flash_address; + unsigned long io_base; + + struct ixgbe_mac_info mac; + struct ixgbe_mbx_info mbx; + + u16 device_id; + u16 subsystem_vendor_id; + u16 subsystem_device_id; + u16 vendor_id; + + u8 revision_id; + bool adapter_stopped; +}; + +struct ixgbevf_hw_stats { + u64 base_vfgprc; + u64 base_vfgptc; + u64 base_vfgorc; + u64 base_vfgotc; + u64 base_vfmprc; + + u64 last_vfgprc; + u64 last_vfgptc; + u64 last_vfgorc; + u64 last_vfgotc; + u64 last_vfmprc; + + u64 vfgprc; + u64 vfgptc; + u64 vfgorc; + u64 vfgotc; + u64 vfmprc; +}; + +struct ixgbevf_info { + enum ixgbe_mac_type mac; + struct ixgbe_mac_operations *mac_ops; +}; + +#endif /* __IXGBE_VF_H__ */ + -- GitLab From cbf698dbba25741ee1b2e734a6dd4f3070a1706f Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:23:50 +0000 Subject: [PATCH 0479/3892] ixgbevf: Mailbox communication The 82599 virtual function device and the master 82599 physical function device implement a mailbox utility for communication between the devices using some SRAM scratch memory and a doorbell/answering mechanism enabled via interrupt and/or polling. This C module and accompanying header file implement the base functions for use of this feature. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/mbx.c | 341 ++++++++++++++++++++++++++++++++++++++ drivers/net/ixgbevf/mbx.h | 100 +++++++++++ 2 files changed, 441 insertions(+) create mode 100644 drivers/net/ixgbevf/mbx.c create mode 100644 drivers/net/ixgbevf/mbx.h diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ixgbevf/mbx.c new file mode 100644 index 000000000000..b8143501e6fc --- /dev/null +++ b/drivers/net/ixgbevf/mbx.c @@ -0,0 +1,341 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "mbx.h" + +/** + * ixgbevf_poll_for_msg - Wait for message notification + * @hw: pointer to the HW structure + * + * returns 0 if it successfully received a message notification + **/ +static s32 ixgbevf_poll_for_msg(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; + + while (countdown && mbx->ops.check_for_msg(hw)) { + countdown--; + udelay(mbx->udelay); + } + + /* if we failed, all future posted messages fail until reset */ + if (!countdown) + mbx->timeout = 0; + + return countdown ? 0 : IXGBE_ERR_MBX; +} + +/** + * ixgbevf_poll_for_ack - Wait for message acknowledgement + * @hw: pointer to the HW structure + * + * returns 0 if it successfully received a message acknowledgement + **/ +static s32 ixgbevf_poll_for_ack(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; + + while (countdown && mbx->ops.check_for_ack(hw)) { + countdown--; + udelay(mbx->udelay); + } + + /* if we failed, all future posted messages fail until reset */ + if (!countdown) + mbx->timeout = 0; + + return countdown ? 0 : IXGBE_ERR_MBX; +} + +/** + * ixgbevf_read_posted_mbx - Wait for message notification and receive message + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * + * returns 0 if it successfully received a message notification and + * copied it into the receive buffer. + **/ +static s32 ixgbevf_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + ret_val = ixgbevf_poll_for_msg(hw); + + /* if ack received read message, otherwise we timed out */ + if (!ret_val) + ret_val = mbx->ops.read(hw, msg, size); + + return ret_val; +} + +/** + * ixgbevf_write_posted_mbx - Write a message to the mailbox, wait for ack + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * + * returns 0 if it successfully copied message into the buffer and + * received an ack to that message within delay * timeout period + **/ +static s32 ixgbevf_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val; + + /* send msg */ + ret_val = mbx->ops.write(hw, msg, size); + + /* if msg sent wait until we receive an ack */ + if (!ret_val) + ret_val = ixgbevf_poll_for_ack(hw); + + return ret_val; +} + +/** + * ixgbevf_read_v2p_mailbox - read v2p mailbox + * @hw: pointer to the HW structure + * + * This function is used to read the v2p mailbox without losing the read to + * clear status bits. + **/ +static u32 ixgbevf_read_v2p_mailbox(struct ixgbe_hw *hw) +{ + u32 v2p_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX); + + v2p_mailbox |= hw->mbx.v2p_mailbox; + hw->mbx.v2p_mailbox |= v2p_mailbox & IXGBE_VFMAILBOX_R2C_BITS; + + return v2p_mailbox; +} + +/** + * ixgbevf_check_for_bit_vf - Determine if a status bit was set + * @hw: pointer to the HW structure + * @mask: bitmask for bits to be tested and cleared + * + * This function is used to check for the read to clear bits within + * the V2P mailbox. + **/ +static s32 ixgbevf_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask) +{ + u32 v2p_mailbox = ixgbevf_read_v2p_mailbox(hw); + s32 ret_val = IXGBE_ERR_MBX; + + if (v2p_mailbox & mask) + ret_val = 0; + + hw->mbx.v2p_mailbox &= ~mask; + + return ret_val; +} + +/** + * ixgbevf_check_for_msg_vf - checks to see if the PF has sent mail + * @hw: pointer to the HW structure + * + * returns 0 if the PF has set the Status bit or else ERR_MBX + **/ +static s32 ixgbevf_check_for_msg_vf(struct ixgbe_hw *hw) +{ + s32 ret_val = IXGBE_ERR_MBX; + + if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) { + ret_val = 0; + hw->mbx.stats.reqs++; + } + + return ret_val; +} + +/** + * ixgbevf_check_for_ack_vf - checks to see if the PF has ACK'd + * @hw: pointer to the HW structure + * + * returns 0 if the PF has set the ACK bit or else ERR_MBX + **/ +static s32 ixgbevf_check_for_ack_vf(struct ixgbe_hw *hw) +{ + s32 ret_val = IXGBE_ERR_MBX; + + if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) { + ret_val = 0; + hw->mbx.stats.acks++; + } + + return ret_val; +} + +/** + * ixgbevf_check_for_rst_vf - checks to see if the PF has reset + * @hw: pointer to the HW structure + * + * returns true if the PF has set the reset done bit or else false + **/ +static s32 ixgbevf_check_for_rst_vf(struct ixgbe_hw *hw) +{ + s32 ret_val = IXGBE_ERR_MBX; + + if (!ixgbevf_check_for_bit_vf(hw, (IXGBE_VFMAILBOX_RSTD | + IXGBE_VFMAILBOX_RSTI))) { + ret_val = 0; + hw->mbx.stats.rsts++; + } + + return ret_val; +} + +/** + * ixgbevf_obtain_mbx_lock_vf - obtain mailbox lock + * @hw: pointer to the HW structure + * + * return 0 if we obtained the mailbox lock + **/ +static s32 ixgbevf_obtain_mbx_lock_vf(struct ixgbe_hw *hw) +{ + s32 ret_val = IXGBE_ERR_MBX; + + /* Take ownership of the buffer */ + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_VFU); + + /* reserve mailbox for vf use */ + if (ixgbevf_read_v2p_mailbox(hw) & IXGBE_VFMAILBOX_VFU) + ret_val = 0; + + return ret_val; +} + +/** + * ixgbevf_write_mbx_vf - Write a message to the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * + * returns 0 if it successfully copied message into the buffer + **/ +static s32 ixgbevf_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size) +{ + s32 ret_val; + u16 i; + + + /* lock the mailbox to prevent pf/vf race condition */ + ret_val = ixgbevf_obtain_mbx_lock_vf(hw); + if (ret_val) + goto out_no_write; + + /* flush msg and acks as we are overwriting the message buffer */ + ixgbevf_check_for_msg_vf(hw); + ixgbevf_check_for_ack_vf(hw); + + /* copy the caller specified message to the mailbox memory buffer */ + for (i = 0; i < size; i++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]); + + /* update stats */ + hw->mbx.stats.msgs_tx++; + + /* Drop VFU and interrupt the PF to tell it a message has been sent */ + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ); + +out_no_write: + return ret_val; +} + +/** + * ixgbevf_read_mbx_vf - Reads a message from the inbox intended for vf + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * + * returns 0 if it successfuly read message from buffer + **/ +static s32 ixgbevf_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size) +{ + s32 ret_val = 0; + u16 i; + + /* lock the mailbox to prevent pf/vf race condition */ + ret_val = ixgbevf_obtain_mbx_lock_vf(hw); + if (ret_val) + goto out_no_read; + + /* copy the message from the mailbox memory buffer */ + for (i = 0; i < size; i++) + msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i); + + /* Acknowledge receipt and release mailbox, then we're done */ + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_ACK); + + /* update stats */ + hw->mbx.stats.msgs_rx++; + +out_no_read: + return ret_val; +} + +/** + * ixgbevf_init_mbx_params_vf - set initial values for vf mailbox + * @hw: pointer to the HW structure + * + * Initializes the hw->mbx struct to correct values for vf mailbox + */ +s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + + /* start mailbox as timed out and let the reset_hw call set the timeout + * value to begin communications */ + mbx->timeout = 0; + mbx->udelay = IXGBE_VF_MBX_INIT_DELAY; + + mbx->size = IXGBE_VFMAILBOX_SIZE; + + mbx->stats.msgs_tx = 0; + mbx->stats.msgs_rx = 0; + mbx->stats.reqs = 0; + mbx->stats.acks = 0; + mbx->stats.rsts = 0; + + return 0; +} + +struct ixgbe_mbx_operations ixgbevf_mbx_ops = { + .init_params = ixgbevf_init_mbx_params_vf, + .read = ixgbevf_read_mbx_vf, + .write = ixgbevf_write_mbx_vf, + .read_posted = ixgbevf_read_posted_mbx, + .write_posted = ixgbevf_write_posted_mbx, + .check_for_msg = ixgbevf_check_for_msg_vf, + .check_for_ack = ixgbevf_check_for_ack_vf, + .check_for_rst = ixgbevf_check_for_rst_vf, +}; + diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h new file mode 100644 index 000000000000..1b0e0bf4c0f5 --- /dev/null +++ b/drivers/net/ixgbevf/mbx.h @@ -0,0 +1,100 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_MBX_H_ +#define _IXGBE_MBX_H_ + +#include "vf.h" + +#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */ +#define IXGBE_ERR_MBX -100 + +#define IXGBE_VFMAILBOX 0x002FC +#define IXGBE_VFMBMEM 0x00200 + +/* Define mailbox register bits */ +#define IXGBE_VFMAILBOX_REQ 0x00000001 /* Request for PF Ready bit */ +#define IXGBE_VFMAILBOX_ACK 0x00000002 /* Ack PF message received */ +#define IXGBE_VFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */ +#define IXGBE_VFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */ +#define IXGBE_VFMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */ +#define IXGBE_VFMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */ +#define IXGBE_VFMAILBOX_RSTI 0x00000040 /* PF has reset indication */ +#define IXGBE_VFMAILBOX_RSTD 0x00000080 /* PF has indicated reset done */ +#define IXGBE_VFMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */ + +#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x)) +#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn)) + +#define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */ +#define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */ +#define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */ +#define IXGBE_PFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */ +#define IXGBE_PFMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */ + +#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */ +#define IXGBE_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */ +#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */ +#define IXGBE_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */ + + +/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the + * PF. The reverse is true if it is IXGBE_PF_*. + * Message ACK's are the value or'd with 0xF0000000 + */ +#define IXGBE_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with + * this are the ACK */ +#define IXGBE_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with + * this are the NACK */ +#define IXGBE_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still + * clear to send requests */ +#define IXGBE_VT_MSGINFO_SHIFT 16 +/* bits 23:16 are used for exra info for certain messages */ +#define IXGBE_VT_MSGINFO_MASK (0xFF << IXGBE_VT_MSGINFO_SHIFT) + +#define IXGBE_VF_RESET 0x01 /* VF requests reset */ +#define IXGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */ +#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ +#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ +#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ + +/* length of permanent address message returned from PF */ +#define IXGBE_VF_PERMADDR_MSG_LEN 4 +/* word in permanent address message with the current multicast type */ +#define IXGBE_VF_MC_TYPE_WORD 3 + +#define IXGBE_PF_CONTROL_MSG 0x0100 /* PF control message */ + +#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ +#define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */ + +/* forward declaration of the HW struct */ +struct ixgbe_hw; + +s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *); + +#endif /* _IXGBE_MBX_H_ */ -- GitLab From 92915f71201b43762fbe05dbfb1a1a0de9c8adb9 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:24:10 +0000 Subject: [PATCH 0480/3892] ixgbevf: Driver main and ethool interface module and main header These modules and header contain the Linux OS network interface code and core interrupt and network send/receive handlers. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ethtool.c | 716 ++++++ drivers/net/ixgbevf/ixgbevf.h | 318 +++ drivers/net/ixgbevf/ixgbevf_main.c | 3571 ++++++++++++++++++++++++++++ 3 files changed, 4605 insertions(+) create mode 100644 drivers/net/ixgbevf/ethtool.c create mode 100644 drivers/net/ixgbevf/ixgbevf.h create mode 100644 drivers/net/ixgbevf/ixgbevf_main.c diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c new file mode 100644 index 000000000000..399be0c34c36 --- /dev/null +++ b/drivers/net/ixgbevf/ethtool.c @@ -0,0 +1,716 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for ixgbevf */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbevf.h" + +#define IXGBE_ALL_RAR_ENTRIES 16 + +#ifdef ETHTOOL_GSTATS +struct ixgbe_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; + int base_stat_offset; +}; + +#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \ + offsetof(struct ixgbevf_adapter, m), \ + offsetof(struct ixgbevf_adapter, b) +static struct ixgbe_stats ixgbe_gstrings_stats[] = { + {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)}, + {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)}, + {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)}, + {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)}, + {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)}, + {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)}, + {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)}, + {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)}, + {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)}, + {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)}, +}; + +#define IXGBE_QUEUE_STATS_LEN 0 +#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) + +#define IXGBEVF_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) +#endif /* ETHTOOL_GSTATS */ +#ifdef ETHTOOL_TEST +static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", + "Link test (on/offline)" +}; +#define IXGBE_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN) +#endif /* ETHTOOL_TEST */ + +static int ixgbevf_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = 0; + bool link_up; + + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->autoneg = AUTONEG_DISABLE; + ecmd->transceiver = XCVR_DUMMY1; + ecmd->port = -1; + + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + + if (link_up) { + ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + SPEED_10000 : SPEED_1000; + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + return 0; +} + +static u32 ixgbevf_get_rx_csum(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED; +} + +static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + if (data) + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) { + if (!adapter->dev_closed) + ixgbevf_reinit_locked(adapter); + } else { + ixgbevf_reset(adapter); + } + + return 0; +} + +static int ixgbevf_set_tso(struct net_device *netdev, u32 data) +{ + if (data) { + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + } else { + netif_tx_stop_all_queues(netdev); + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + netif_tx_start_all_queues(netdev); + } + return 0; +} + +static u32 ixgbevf_get_msglevel(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_) + +static char *ixgbevf_reg_names[] = { + "IXGBE_VFCTRL", + "IXGBE_VFSTATUS", + "IXGBE_VFLINKS", + "IXGBE_VFRXMEMWRAP", + "IXGBE_VFRTIMER", + "IXGBE_VTEICR", + "IXGBE_VTEICS", + "IXGBE_VTEIMS", + "IXGBE_VTEIMC", + "IXGBE_VTEIAC", + "IXGBE_VTEIAM", + "IXGBE_VTEITR", + "IXGBE_VTIVAR", + "IXGBE_VTIVAR_MISC", + "IXGBE_VFRDBAL0", + "IXGBE_VFRDBAL1", + "IXGBE_VFRDBAH0", + "IXGBE_VFRDBAH1", + "IXGBE_VFRDLEN0", + "IXGBE_VFRDLEN1", + "IXGBE_VFRDH0", + "IXGBE_VFRDH1", + "IXGBE_VFRDT0", + "IXGBE_VFRDT1", + "IXGBE_VFRXDCTL0", + "IXGBE_VFRXDCTL1", + "IXGBE_VFSRRCTL0", + "IXGBE_VFSRRCTL1", + "IXGBE_VFPSRTYPE", + "IXGBE_VFTDBAL0", + "IXGBE_VFTDBAL1", + "IXGBE_VFTDBAH0", + "IXGBE_VFTDBAH1", + "IXGBE_VFTDLEN0", + "IXGBE_VFTDLEN1", + "IXGBE_VFTDH0", + "IXGBE_VFTDH1", + "IXGBE_VFTDT0", + "IXGBE_VFTDT1", + "IXGBE_VFTXDCTL0", + "IXGBE_VFTXDCTL1", + "IXGBE_VFTDWBAL0", + "IXGBE_VFTDWBAL1", + "IXGBE_VFTDWBAH0", + "IXGBE_VFTDWBAH1" +}; + + +static int ixgbevf_get_regs_len(struct net_device *netdev) +{ + return (ARRAY_SIZE(ixgbevf_reg_names)) * sizeof(u32); +} + +static void ixgbevf_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, + void *p) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u32 regs_len = ixgbevf_get_regs_len(netdev); + u8 i; + + memset(p, 0, regs_len); + + regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id; + + /* General Registers */ + regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL); + regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS); + regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_VFLINKS); + regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_VFRXMEMWRAP); + regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_VFRTIMER); + + /* Interrupt */ + /* don't read EICR because it can clear interrupt causes, instead + * read EICS which is a shadow but doesn't clear EICR */ + regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_VTEICS); + regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_VTEICS); + regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_VTEIMS); + regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_VTEIMC); + regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_VTEIAC); + regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_VTEIAM); + regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_VTEITR(0)); + regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_VTIVAR(0)); + regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC); + + /* Receive DMA */ + for (i = 0; i < 2; i++) + regs_buff[14 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAL(i)); + for (i = 0; i < 2; i++) + regs_buff[16 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAH(i)); + for (i = 0; i < 2; i++) + regs_buff[18 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDLEN(i)); + for (i = 0; i < 2; i++) + regs_buff[20 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDH(i)); + for (i = 0; i < 2; i++) + regs_buff[22 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDT(i)); + for (i = 0; i < 2; i++) + regs_buff[24 + i] = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); + for (i = 0; i < 2; i++) + regs_buff[26 + i] = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i)); + + /* Receive */ + regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_VFPSRTYPE); + + /* Transmit */ + for (i = 0; i < 2; i++) + regs_buff[29 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAL(i)); + for (i = 0; i < 2; i++) + regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAH(i)); + for (i = 0; i < 2; i++) + regs_buff[33 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDLEN(i)); + for (i = 0; i < 2; i++) + regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDH(i)); + for (i = 0; i < 2; i++) + regs_buff[37 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDT(i)); + for (i = 0; i < 2; i++) + regs_buff[39 + i] = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); + for (i = 0; i < 2; i++) + regs_buff[41 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAL(i)); + for (i = 0; i < 2; i++) + regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAH(i)); + + for (i = 0; i < ARRAY_SIZE(ixgbevf_reg_names); i++) + hw_dbg(hw, "%s\t%8.8x\n", ixgbevf_reg_names[i], regs_buff[i]); +} + +static void ixgbevf_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + strlcpy(drvinfo->driver, ixgbevf_driver_name, 32); + strlcpy(drvinfo->version, ixgbevf_driver_version, 32); + + strlcpy(drvinfo->fw_version, "N/A", 4); + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); +} + +static void ixgbevf_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbevf_ring *tx_ring = adapter->tx_ring; + struct ixgbevf_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = IXGBEVF_MAX_RXD; + ring->tx_max_pending = IXGBEVF_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int ixgbevf_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL; + int i, err; + u32 new_rx_count, new_tx_count; + bool need_tx_update = false; + bool need_rx_update = false; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + new_rx_count = max(ring->rx_pending, (u32)IXGBEVF_MIN_RXD); + new_rx_count = min(new_rx_count, (u32)IXGBEVF_MAX_RXD); + new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE); + + new_tx_count = max(ring->tx_pending, (u32)IXGBEVF_MIN_TXD); + new_tx_count = min(new_tx_count, (u32)IXGBEVF_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); + + if ((new_tx_count == adapter->tx_ring->count) && + (new_rx_count == adapter->rx_ring->count)) { + /* nothing to do */ + return 0; + } + + while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) + msleep(1); + + if (new_tx_count != adapter->tx_ring_count) { + tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbevf_ring), GFP_KERNEL); + if (!tx_ring) { + err = -ENOMEM; + goto err_setup; + } + memcpy(tx_ring, adapter->tx_ring, + adapter->num_tx_queues * sizeof(struct ixgbevf_ring)); + for (i = 0; i < adapter->num_tx_queues; i++) { + tx_ring[i].count = new_tx_count; + err = ixgbevf_setup_tx_resources(adapter, + &tx_ring[i]); + if (err) { + while (i) { + i--; + ixgbevf_free_tx_resources(adapter, + &tx_ring[i]); + } + kfree(tx_ring); + goto err_setup; + } + tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; + } + need_tx_update = true; + } + + if (new_rx_count != adapter->rx_ring_count) { + rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbevf_ring), GFP_KERNEL); + if ((!rx_ring) && (need_tx_update)) { + err = -ENOMEM; + goto err_rx_setup; + } + memcpy(rx_ring, adapter->rx_ring, + adapter->num_rx_queues * sizeof(struct ixgbevf_ring)); + for (i = 0; i < adapter->num_rx_queues; i++) { + rx_ring[i].count = new_rx_count; + err = ixgbevf_setup_rx_resources(adapter, + &rx_ring[i]); + if (err) { + while (i) { + i--; + ixgbevf_free_rx_resources(adapter, + &rx_ring[i]); + } + kfree(rx_ring); + goto err_rx_setup; + } + rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; + } + need_rx_update = true; + } + +err_rx_setup: + /* if rings need to be updated, here's the place to do it in one shot */ + if (need_tx_update || need_rx_update) { + if (netif_running(netdev)) + ixgbevf_down(adapter); + } + + /* tx */ + if (need_tx_update) { + kfree(adapter->tx_ring); + adapter->tx_ring = tx_ring; + tx_ring = NULL; + adapter->tx_ring_count = new_tx_count; + } + + /* rx */ + if (need_rx_update) { + kfree(adapter->rx_ring); + adapter->rx_ring = rx_ring; + rx_ring = NULL; + adapter->rx_ring_count = new_rx_count; + } + + /* success! */ + err = 0; + if (netif_running(netdev)) + ixgbevf_up(adapter); + +err_setup: + clear_bit(__IXGBEVF_RESETTING, &adapter->state); + return err; +} + +static int ixgbevf_get_sset_count(struct net_device *dev, int stringset) +{ + switch (stringset) { + case ETH_SS_TEST: + return IXGBE_TEST_LEN; + case ETH_SS_STATS: + return IXGBE_GLOBAL_STATS_LEN; + default: + return -EINVAL; + } +} + +static void ixgbevf_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + int i; + + ixgbevf_update_stats(adapter); + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter + + ixgbe_gstrings_stats[i].stat_offset; + char *b = (char *)adapter + + ixgbe_gstrings_stats[i].base_stat_offset; + data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p) - + ((ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)b : *(u32 *)b); + } +} + +static void ixgbevf_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + char *p = (char *)data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *ixgbe_gstrings_test, + IXGBE_TEST_LEN * ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + memcpy(p, ixgbe_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int ixgbevf_link_test(struct ixgbevf_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + bool link_up; + u32 link_speed = 0; + *data = 0; + + hw->mac.ops.check_link(hw, &link_speed, &link_up, true); + if (!link_up) + *data = 1; + + return *data; +} + +/* ethtool register test data */ +struct ixgbevf_reg_test { + u16 reg; + u8 array_len; + u8 test_type; + u32 mask; + u32 write; +}; + +/* In the hardware, registers are laid out either singly, in arrays + * spaced 0x40 bytes apart, or in contiguous tables. We assume + * most tests take place on arrays or single registers (handled + * as a single-element array) and special-case the tables. + * Table tests are always pattern tests. + * + * We also make provision for some required setup steps by specifying + * registers to be written without any read-back testing. + */ + +#define PATTERN_TEST 1 +#define SET_READ_TEST 2 +#define WRITE_NO_TEST 3 +#define TABLE32_TEST 4 +#define TABLE64_TEST_LO 5 +#define TABLE64_TEST_HI 6 + +/* default VF register test */ +static struct ixgbevf_reg_test reg_test_vf[] = { + { IXGBE_VFRDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, + { IXGBE_VFRDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VFRDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + { IXGBE_VFRDT(0), 2, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, 0 }, + { IXGBE_VFTDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_VFTDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VFTDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, + { 0, 0, 0, 0 } +}; + +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + u32 pat, val, before; \ + const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \ + before = readl(adapter->hw.hw_addr + R); \ + writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if (val != (_test[pat] & W & M)) { \ + hw_dbg(&adapter->hw, \ + "pattern test reg %04X failed: got " \ + "0x%08X expected 0x%08X\n", \ + R, val, (_test[pat] & W & M)); \ + *data = R; \ + writel(before, adapter->hw.hw_addr + R); \ + return 1; \ + } \ + writel(before, adapter->hw.hw_addr + R); \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 val, before; \ + before = readl(adapter->hw.hw_addr + R); \ + writel((W & M), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if ((W & M) != (val & M)) { \ + printk(KERN_ERR "set/check reg %04X test failed: got 0x%08X " \ + "expected 0x%08X\n", R, (val & M), (W & M)); \ + *data = R; \ + writel(before, (adapter->hw.hw_addr + R)); \ + return 1; \ + } \ + writel(before, (adapter->hw.hw_addr + R)); \ +} + +static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data) +{ + struct ixgbevf_reg_test *test; + u32 i; + + test = reg_test_vf; + + /* + * Perform the register test, looping through the test table + * until we either fail or reach the null entry. + */ + while (test->reg) { + for (i = 0; i < test->array_len; i++) { + switch (test->test_type) { + case PATTERN_TEST: + REG_PATTERN_TEST(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case SET_READ_TEST: + REG_SET_AND_CHECK(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case WRITE_NO_TEST: + writel(test->write, + (adapter->hw.hw_addr + test->reg) + + (i * 0x40)); + break; + case TABLE32_TEST: + REG_PATTERN_TEST(test->reg + (i * 4), + test->mask, + test->write); + break; + case TABLE64_TEST_LO: + REG_PATTERN_TEST(test->reg + (i * 8), + test->mask, + test->write); + break; + case TABLE64_TEST_HI: + REG_PATTERN_TEST((test->reg + 4) + (i * 8), + test->mask, + test->write); + break; + } + } + test++; + } + + *data = 0; + return *data; +} + +static void ixgbevf_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + bool if_running = netif_running(netdev); + + set_bit(__IXGBEVF_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + hw_dbg(&adapter->hw, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (ixgbevf_link_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + ixgbevf_reset(adapter); + + hw_dbg(&adapter->hw, "register testing starting\n"); + if (ixgbevf_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbevf_reset(adapter); + + clear_bit(__IXGBEVF_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + hw_dbg(&adapter->hw, "online testing starting\n"); + /* Online tests */ + if (ixgbevf_link_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + + clear_bit(__IXGBEVF_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} + +static int ixgbevf_nway_reset(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + if (netif_running(netdev)) { + if (!adapter->dev_closed) + ixgbevf_reinit_locked(adapter); + } + + return 0; +} + +static struct ethtool_ops ixgbevf_ethtool_ops = { + .get_settings = ixgbevf_get_settings, + .get_drvinfo = ixgbevf_get_drvinfo, + .get_regs_len = ixgbevf_get_regs_len, + .get_regs = ixgbevf_get_regs, + .nway_reset = ixgbevf_nway_reset, + .get_link = ethtool_op_get_link, + .get_ringparam = ixgbevf_get_ringparam, + .set_ringparam = ixgbevf_set_ringparam, + .get_rx_csum = ixgbevf_get_rx_csum, + .set_rx_csum = ixgbevf_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_ipv6_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_msglevel = ixgbevf_get_msglevel, + .set_msglevel = ixgbevf_set_msglevel, + .get_tso = ethtool_op_get_tso, + .set_tso = ixgbevf_set_tso, + .self_test = ixgbevf_diag_test, + .get_sset_count = ixgbevf_get_sset_count, + .get_strings = ixgbevf_get_strings, + .get_ethtool_stats = ixgbevf_get_ethtool_stats, +}; + +void ixgbevf_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops); +} diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h new file mode 100644 index 000000000000..f7015efbff05 --- /dev/null +++ b/drivers/net/ixgbevf/ixgbevf.h @@ -0,0 +1,318 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBEVF_H_ +#define _IXGBEVF_H_ + +#include +#include +#include +#include + +#include "vf.h" + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct ixgbevf_tx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + unsigned long time_stamp; + u16 length; + u16 next_to_watch; + u16 mapped_as_page; +}; + +struct ixgbevf_rx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + struct page *page; + dma_addr_t page_dma; + unsigned int page_offset; +}; + +struct ixgbevf_ring { + struct ixgbevf_adapter *adapter; /* backlink */ + void *desc; /* descriptor ring memory */ + dma_addr_t dma; /* phys. address of descriptor ring */ + unsigned int size; /* length in bytes */ + unsigned int count; /* amount of descriptors */ + unsigned int next_to_use; + unsigned int next_to_clean; + + int queue_index; /* needed for multiqueue queue management */ + union { + struct ixgbevf_tx_buffer *tx_buffer_info; + struct ixgbevf_rx_buffer *rx_buffer_info; + }; + + u16 head; + u16 tail; + + unsigned int total_bytes; + unsigned int total_packets; + + u16 reg_idx; /* holds the special value that gets the hardware register + * offset associated with this ring, which is different + * for DCB and RSS modes */ + +#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + /* cpu for tx queue */ + int cpu; +#endif + + u64 v_idx; /* maps directly to the index for this ring in the hardware + * vector array, can also be used for finding the bit in EICR + * and friends that represents the vector for this ring */ + + u16 work_limit; /* max work per interrupt */ + u16 rx_buf_len; +}; + +enum ixgbevf_ring_f_enum { + RING_F_NONE = 0, + RING_F_ARRAY_SIZE /* must be last in enum set */ +}; + +struct ixgbevf_ring_feature { + int indices; + int mask; +}; + +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define IXGBEVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define MAX_RX_QUEUES 1 +#define MAX_TX_QUEUES 1 + +#define IXGBEVF_DEFAULT_TXD 1024 +#define IXGBEVF_DEFAULT_RXD 512 +#define IXGBEVF_MAX_TXD 4096 +#define IXGBEVF_MIN_TXD 64 +#define IXGBEVF_MAX_RXD 4096 +#define IXGBEVF_MIN_RXD 64 + +/* Supported Rx Buffer Sizes */ +#define IXGBEVF_RXBUFFER_64 64 /* Used for packet split */ +#define IXGBEVF_RXBUFFER_128 128 /* Used for packet split */ +#define IXGBEVF_RXBUFFER_256 256 /* Used for packet split */ +#define IXGBEVF_RXBUFFER_2048 2048 +#define IXGBEVF_MAX_RXBUFFER 16384 /* largest size for single descriptor */ + +#define IXGBEVF_RX_HDR_SIZE IXGBEVF_RXBUFFER_256 + +#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) + +#define IXGBE_TX_FLAGS_CSUM (u32)(1) +#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) +#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) +#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) +#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4) +#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5) +#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 +#define IXGBE_TX_FLAGS_VLAN_SHIFT 16 + +/* MAX_MSIX_Q_VECTORS of these are allocated, + * but we only use one per queue-specific vector. + */ +struct ixgbevf_q_vector { + struct ixgbevf_adapter *adapter; + struct napi_struct napi; + DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */ + DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ + u8 rxr_count; /* Rx ring count assigned to this vector */ + u8 txr_count; /* Tx ring count assigned to this vector */ + u8 tx_itr; + u8 rx_itr; + u32 eitr; + int v_idx; /* vector index in list */ +}; + +/* Helper macros to switch between ints/sec and what the register uses. + * And yes, it's the same math going both ways. The lowest value + * supported by all of the ixgbe hardware is 8. + */ +#define EITR_INTS_PER_SEC_TO_REG(_eitr) \ + ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8) +#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG + +#define IXGBE_DESC_UNUSED(R) \ + ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ + (R)->next_to_clean - (R)->next_to_use - 1) + +#define IXGBE_RX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_rx_desc *)((R).desc))[i])) +#define IXGBE_TX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_tx_desc *)((R).desc))[i])) +#define IXGBE_TX_CTXTDESC_ADV(R, i) \ + (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) + +#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 + +#define OTHER_VECTOR 1 +#define NON_Q_VECTORS (OTHER_VECTOR) + +#define MAX_MSIX_Q_VECTORS 2 +#define MAX_MSIX_COUNT 2 + +#define MIN_MSIX_Q_VECTORS 2 +#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NON_Q_VECTORS) + +/* board specific private data structure */ +struct ixgbevf_adapter { + struct timer_list watchdog_timer; +#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; +#endif + u16 bd_number; + struct work_struct reset_task; + struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; + char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; + + /* Interrupt Throttle Rate */ + u32 itr_setting; + u16 eitr_low; + u16 eitr_high; + + /* TX */ + struct ixgbevf_ring *tx_ring; /* One per active queue */ + int num_tx_queues; + u64 restart_queue; + u64 hw_csum_tx_good; + u64 lsc_int; + u64 hw_tso_ctxt; + u64 hw_tso6_ctxt; + u32 tx_timeout_count; + bool detect_tx_hung; + + /* RX */ + struct ixgbevf_ring *rx_ring; /* One per active queue */ + int num_rx_queues; + int num_rx_pools; /* == num_rx_queues in 82598 */ + int num_rx_queues_per_pool; /* 1 if 82598, can be many if 82599 */ + u64 hw_csum_rx_error; + u64 hw_rx_no_dma_resources; + u64 hw_csum_rx_good; + u64 non_eop_descs; + int num_msix_vectors; + int max_msix_q_vectors; /* true count of q_vectors for device */ + struct ixgbevf_ring_feature ring_feature[RING_F_ARRAY_SIZE]; + struct msix_entry *msix_entries; + + u64 rx_hdr_split; + u32 alloc_rx_page_failed; + u32 alloc_rx_buff_failed; + + /* Some features need tri-state capability, + * thus the additional *_CAPABLE flags. + */ + u32 flags; +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) +#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 2) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4) +#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 5) +#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 6) +#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) +#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 8) + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in ixgbe_vf.h */ + struct ixgbe_hw hw; + u16 msg_enable; + struct ixgbevf_hw_stats stats; + u64 zero_base; + /* Interrupt Throttle Rate */ + u32 eitr_param; + + unsigned long state; + u32 *config_space; + u64 tx_busy; + unsigned int tx_ring_count; + unsigned int rx_ring_count; + + u32 link_speed; + bool link_up; + unsigned long link_check_timeout; + + struct work_struct watchdog_task; + bool netdev_registered; + bool dev_closed; +}; + +enum ixbgevf_state_t { + __IXGBEVF_TESTING, + __IXGBEVF_RESETTING, + __IXGBEVF_DOWN +}; + +enum ixgbevf_boards { + board_82599_vf, +}; + +extern struct ixgbevf_info ixgbevf_vf_info; +extern struct ixgbe_mac_operations ixgbevf_mbx_ops; + +/* needed by ethtool.c */ +extern char ixgbevf_driver_name[]; +extern const char ixgbevf_driver_version[]; + +extern int ixgbevf_up(struct ixgbevf_adapter *adapter); +extern void ixgbevf_down(struct ixgbevf_adapter *adapter); +extern void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter); +extern void ixgbevf_reset(struct ixgbevf_adapter *adapter); +extern void ixgbevf_set_ethtool_ops(struct net_device *netdev); +extern int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *, + struct ixgbevf_ring *); +extern int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *, + struct ixgbevf_ring *); +extern void ixgbevf_free_rx_resources(struct ixgbevf_adapter *, + struct ixgbevf_ring *); +extern void ixgbevf_free_tx_resources(struct ixgbevf_adapter *, + struct ixgbevf_ring *); +extern void ixgbevf_update_stats(struct ixgbevf_adapter *adapter); + +#ifdef ETHTOOL_OPS_COMPAT +extern int ethtool_ioctl(struct ifreq *ifr); + +#endif +extern void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter); +extern void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter); + +#ifdef DEBUG +extern char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw); +#define hw_dbg(hw, format, arg...) \ + printk(KERN_DEBUG "%s: " format, ixgbevf_get_hw_dev_name(hw), ##arg) +#else +#define hw_dbg(hw, format, arg...) do {} while (0) +#endif + +#endif /* _IXGBEVF_H_ */ diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c new file mode 100644 index 000000000000..39544afdc57f --- /dev/null +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -0,0 +1,3571 @@ +/******************************************************************************* + + Intel 82599 Virtual Function driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +/****************************************************************************** + Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbevf.h" + +char ixgbevf_driver_name[] = "ixgbevf"; +static const char ixgbevf_driver_string[] = + "Intel(R) 82599 Virtual Function"; + +#define DRV_VERSION "1.0.0-k0" +const char ixgbevf_driver_version[] = DRV_VERSION; +static char ixgbevf_copyright[] = "Copyright (c) 2009 Intel Corporation."; + +static const struct ixgbevf_info *ixgbevf_info_tbl[] = { + [board_82599_vf] = &ixgbevf_vf_info, +}; + +/* ixgbevf_pci_tbl - PCI Device ID Table + * + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, private data (not used) } + */ +static struct pci_device_id ixgbevf_pci_tbl[] = { + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF), + board_82599_vf}, + + /* required last entry */ + {0, } +}; +MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl); + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +#define DEFAULT_DEBUG_LEVEL_SHIFT 3 + +/* forward decls */ +static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector); +static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx, + u32 itr_reg); + +static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw, + struct ixgbevf_ring *rx_ring, + u32 val) +{ + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rx_ring->reg_idx), val); +} + +/* + * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors + * @adapter: pointer to adapter struct + * @direction: 0 for Rx, 1 for Tx, -1 for other causes + * @queue: queue to map the corresponding interrupt to + * @msix_vector: the vector to map to the corresponding queue + * + */ +static void ixgbevf_set_ivar(struct ixgbevf_adapter *adapter, s8 direction, + u8 queue, u8 msix_vector) +{ + u32 ivar, index; + struct ixgbe_hw *hw = &adapter->hw; + if (direction == -1) { + /* other causes */ + msix_vector |= IXGBE_IVAR_ALLOC_VAL; + ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC); + ivar &= ~0xFF; + ivar |= msix_vector; + IXGBE_WRITE_REG(hw, IXGBE_VTIVAR_MISC, ivar); + } else { + /* tx or rx causes */ + msix_vector |= IXGBE_IVAR_ALLOC_VAL; + index = ((16 * (queue & 1)) + (8 * direction)); + ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR(queue >> 1)); + ivar &= ~(0xFF << index); + ivar |= (msix_vector << index); + IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(queue >> 1), ivar); + } +} + +static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter, + struct ixgbevf_tx_buffer + *tx_buffer_info) +{ + if (tx_buffer_info->dma) { + if (tx_buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, + PCI_DMA_TODEVICE); + tx_buffer_info->dma = 0; + } + if (tx_buffer_info->skb) { + dev_kfree_skb_any(tx_buffer_info->skb); + tx_buffer_info->skb = NULL; + } + tx_buffer_info->time_stamp = 0; + /* tx_buffer_info must be completely set up in the transmit path */ +} + +static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring, + unsigned int eop) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 head, tail; + + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of eop */ + head = readl(hw->hw_addr + tx_ring->head); + tail = readl(hw->hw_addr + tx_ring->tail); + adapter->detect_tx_hung = false; + if ((head != tail) && + tx_ring->tx_buffer_info[eop].time_stamp && + time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ)) { + /* detected Tx unit hang */ + union ixgbe_adv_tx_desc *tx_desc; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + printk(KERN_ERR "Detected Tx Unit Hang\n" + " Tx Queue <%d>\n" + " TDH, TDT <%x>, <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" + " jiffies <%lx>\n", + tx_ring->queue_index, + head, tail, + tx_ring->next_to_use, eop, + tx_ring->tx_buffer_info[eop].time_stamp, jiffies); + return true; + } + + return false; +} + +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ + (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) +#ifdef MAX_SKB_FRAGS +#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ +#else +#define DESC_NEEDED TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) +#endif + +static void ixgbevf_tx_timeout(struct net_device *netdev); + +/** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + * @tx_ring: tx ring to clean + **/ +static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring) +{ + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + union ixgbe_adv_tx_desc *tx_desc, *eop_desc; + struct ixgbevf_tx_buffer *tx_buffer_info; + unsigned int i, eop, count = 0; + unsigned int total_bytes = 0, total_packets = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + + while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) && + (count < tx_ring->work_limit)) { + bool cleaned = false; + for ( ; !cleaned; count++) { + struct sk_buff *skb; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + cleaned = (i == eop); + skb = tx_buffer_info->skb; + + if (cleaned && skb) { + unsigned int segs, bytecount; + + /* gso_segs is currently only valid for tcp */ + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_packets += segs; + total_bytes += bytecount; + } + + ixgbevf_unmap_and_free_tx_resource(adapter, + tx_buffer_info); + + tx_desc->wb.status = 0; + + i++; + if (i == tx_ring->count) + i = 0; + } + + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + } + + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) + if (unlikely(count && netif_carrier_ok(netdev) && + (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); +#ifdef HAVE_TX_MQ + if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && + !test_bit(__IXGBEVF_DOWN, &adapter->state)) { + netif_wake_subqueue(netdev, tx_ring->queue_index); + ++adapter->restart_queue; + } +#else + if (netif_queue_stopped(netdev) && + !test_bit(__IXGBEVF_DOWN, &adapter->state)) { + netif_wake_queue(netdev); + ++adapter->restart_queue; + } +#endif + } + + if (adapter->detect_tx_hung) { + if (ixgbevf_check_tx_hang(adapter, tx_ring, i)) { + /* schedule immediate reset if we believe we hung */ + printk(KERN_INFO + "tx hang %d detected, resetting adapter\n", + adapter->tx_timeout_count + 1); + ixgbevf_tx_timeout(adapter->netdev); + } + } + + /* re-arm the interrupt */ + if ((count >= tx_ring->work_limit) && + (!test_bit(__IXGBEVF_DOWN, &adapter->state))) { + IXGBE_WRITE_REG(hw, IXGBE_VTEICS, tx_ring->v_idx); + } + + tx_ring->total_bytes += total_bytes; + tx_ring->total_packets += total_packets; + + adapter->net_stats.tx_bytes += total_bytes; + adapter->net_stats.tx_packets += total_packets; + + return (count < tx_ring->work_limit); +} + +/** + * ixgbevf_receive_skb - Send a completed packet up the stack + * @q_vector: structure containing interrupt and ring information + * @skb: packet to send up + * @status: hardware indication of status of receive + * @rx_ring: rx descriptor ring (for a specific queue) to setup + * @rx_desc: rx descriptor + **/ +static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector, + struct sk_buff *skb, u8 status, + struct ixgbevf_ring *ring, + union ixgbe_adv_rx_desc *rx_desc) +{ + struct ixgbevf_adapter *adapter = q_vector->adapter; + bool is_vlan = (status & IXGBE_RXD_STAT_VP); + u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); + int ret; + + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { + if (adapter->vlgrp && is_vlan) + vlan_gro_receive(&q_vector->napi, + adapter->vlgrp, + tag, skb); + else + napi_gro_receive(&q_vector->napi, skb); + } else { + if (adapter->vlgrp && is_vlan) + ret = vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + ret = netif_rx(skb); + } +} + +/** + * ixgbevf_rx_checksum - indicate in skb if hw indicated a good cksum + * @adapter: address of board private structure + * @status_err: hardware indication of status of receive + * @skb: skb currently being received and modified + **/ +static inline void ixgbevf_rx_checksum(struct ixgbevf_adapter *adapter, + u32 status_err, struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + /* Rx csum disabled */ + if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + return; + + /* if IP and error */ + if ((status_err & IXGBE_RXD_STAT_IPCS) && + (status_err & IXGBE_RXDADV_ERR_IPE)) { + adapter->hw_csum_rx_error++; + return; + } + + if (!(status_err & IXGBE_RXD_STAT_L4CS)) + return; + + if (status_err & IXGBE_RXDADV_ERR_TCPE) { + adapter->hw_csum_rx_error++; + return; + } + + /* It must be a TCP or UDP packet with a valid checksum */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_rx_good++; +} + +/** + * ixgbevf_alloc_rx_buffers - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *rx_ring, + int cleaned_count) +{ + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbevf_rx_buffer *bi; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + bi = &rx_ring->rx_buffer_info[i]; + + while (cleaned_count--) { + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + + if (!bi->page_dma && + (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { + if (!bi->page) { + bi->page = netdev_alloc_page(adapter->netdev); + if (!bi->page) { + adapter->alloc_rx_page_failed++; + goto no_buffers; + } + bi->page_offset = 0; + } else { + /* use a half page if we're re-using */ + bi->page_offset ^= (PAGE_SIZE / 2); + } + + bi->page_dma = pci_map_page(pdev, bi->page, + bi->page_offset, + (PAGE_SIZE / 2), + PCI_DMA_FROMDEVICE); + } + + skb = bi->skb; + if (!skb) { + skb = netdev_alloc_skb(adapter->netdev, + bufsz); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + bi->skb = skb; + } + if (!bi->dma) { + bi->dma = pci_map_single(pdev, skb->data, + rx_ring->rx_buf_len, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't change because + * each write-back erases this info. */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma); + rx_desc->read.hdr_addr = cpu_to_le64(bi->dma); + } else { + rx_desc->read.pkt_addr = cpu_to_le64(bi->dma); + } + + i++; + if (i == rx_ring->count) + i = 0; + bi = &rx_ring->rx_buffer_info[i]; + } + +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i-- == 0) + i = (rx_ring->count - 1); + + ixgbevf_release_rx_desc(&adapter->hw, rx_ring, i); + } +} + +static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter, + u64 qmask) +{ + u32 mask; + struct ixgbe_hw *hw = &adapter->hw; + + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); +} + +static inline u16 ixgbevf_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc) +{ + return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info; +} + +static inline u16 ixgbevf_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc) +{ + return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; +} + +static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + struct ixgbevf_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct ixgbevf_adapter *adapter = q_vector->adapter; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc, *next_rxd; + struct ixgbevf_rx_buffer *rx_buffer_info, *next_buffer; + struct sk_buff *skb; + unsigned int i; + u32 len, staterr; + u16 hdr_info; + bool cleaned = false; + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + + while (staterr & IXGBE_RXD_STAT_DD) { + u32 upper_len = 0; + if (*work_done >= work_to_do) + break; + (*work_done)++; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + hdr_info = le16_to_cpu(ixgbevf_get_hdr_info(rx_desc)); + len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> + IXGBE_RXDADV_HDRBUFLEN_SHIFT; + if (hdr_info & IXGBE_RXDADV_SPH) + adapter->rx_hdr_split++; + if (len > IXGBEVF_RX_HDR_SIZE) + len = IXGBEVF_RX_HDR_SIZE; + upper_len = le16_to_cpu(rx_desc->wb.upper.length); + } else { + len = le16_to_cpu(rx_desc->wb.upper.length); + } + cleaned = true; + skb = rx_buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + rx_buffer_info->skb = NULL; + + if (rx_buffer_info->dma) { + pci_unmap_single(pdev, rx_buffer_info->dma, + rx_ring->rx_buf_len, + PCI_DMA_FROMDEVICE); + rx_buffer_info->dma = 0; + skb_put(skb, len); + } + + if (upper_len) { + pci_unmap_page(pdev, rx_buffer_info->page_dma, + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, + rx_buffer_info->page, + rx_buffer_info->page_offset, + upper_len); + + if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) || + (page_count(rx_buffer_info->page) != 1)) + rx_buffer_info->page = NULL; + else + get_page(rx_buffer_info->page); + + skb->len += upper_len; + skb->data_len += upper_len; + skb->truesize += upper_len; + } + + i++; + if (i == rx_ring->count) + i = 0; + + next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i); + prefetch(next_rxd); + cleaned_count++; + + next_buffer = &rx_ring->rx_buffer_info[i]; + + if (!(staterr & IXGBE_RXD_STAT_EOP)) { + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + next_buffer->dma = 0; + } else { + skb->next = next_buffer->skb; + skb->next->prev = skb; + } + adapter->non_eop_descs++; + goto next_desc; + } + + /* ERR_MASK will only have valid bits if EOP set */ + if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + ixgbevf_rx_checksum(adapter, staterr, skb); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* + * Work around issue of some types of VM to VM loop back + * packets not getting split correctly + */ + if (staterr & IXGBE_RXD_STAT_LB) { + u32 header_fixup_len = skb->len - skb->data_len; + if (header_fixup_len < 14) + skb_push(skb, header_fixup_len); + } + skb->protocol = eth_type_trans(skb, adapter->netdev); + + ixgbevf_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); + adapter->netdev->last_rx = jiffies; + +next_desc: + rx_desc->wb.upper.status_error = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IXGBEVF_RX_BUFFER_WRITE) { + ixgbevf_alloc_rx_buffers(adapter, rx_ring, + cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + } + + rx_ring->next_to_clean = i; + cleaned_count = IXGBE_DESC_UNUSED(rx_ring); + + if (cleaned_count) + ixgbevf_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + + rx_ring->total_packets += total_rx_packets; + rx_ring->total_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + + return cleaned; +} + +/** + * ixgbevf_clean_rxonly - msix (aka one shot) rx clean routine + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * + * This function is optimized for cleaning one queue only on a single + * q_vector!!! + **/ +static int ixgbevf_clean_rxonly(struct napi_struct *napi, int budget) +{ + struct ixgbevf_q_vector *q_vector = + container_of(napi, struct ixgbevf_q_vector, napi); + struct ixgbevf_adapter *adapter = q_vector->adapter; + struct ixgbevf_ring *rx_ring = NULL; + int work_done = 0; + long r_idx; + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + rx_ring = &(adapter->rx_ring[r_idx]); + + ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget); + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + napi_complete(napi); + if (adapter->itr_setting & 1) + ixgbevf_set_itr_msix(q_vector); + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) + ixgbevf_irq_enable_queues(adapter, rx_ring->v_idx); + } + + return work_done; +} + +/** + * ixgbevf_clean_rxonly_many - msix (aka one shot) rx clean routine + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * + * This function will clean more than one rx queue associated with a + * q_vector. + **/ +static int ixgbevf_clean_rxonly_many(struct napi_struct *napi, int budget) +{ + struct ixgbevf_q_vector *q_vector = + container_of(napi, struct ixgbevf_q_vector, napi); + struct ixgbevf_adapter *adapter = q_vector->adapter; + struct ixgbevf_ring *rx_ring = NULL; + int work_done = 0, i; + long r_idx; + u64 enable_mask = 0; + + /* attempt to distribute budget to each queue fairly, but don't allow + * the budget to go below 1 because we'll exit polling */ + budget /= (q_vector->rxr_count ?: 1); + budget = max(budget, 1); + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); + ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget); + enable_mask |= rx_ring->v_idx; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + +#ifndef HAVE_NETDEV_NAPI_LIST + if (!netif_running(adapter->netdev)) + work_done = 0; + +#endif + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + rx_ring = &(adapter->rx_ring[r_idx]); + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + napi_complete(napi); + if (adapter->itr_setting & 1) + ixgbevf_set_itr_msix(q_vector); + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) + ixgbevf_irq_enable_queues(adapter, enable_mask); + } + + return work_done; +} + + +/** + * ixgbevf_configure_msix - Configure MSI-X hardware + * @adapter: board private structure + * + * ixgbevf_configure_msix sets up the hardware to properly generate MSI-X + * interrupts. + **/ +static void ixgbevf_configure_msix(struct ixgbevf_adapter *adapter) +{ + struct ixgbevf_q_vector *q_vector; + struct ixgbe_hw *hw = &adapter->hw; + int i, j, q_vectors, v_idx, r_idx; + u32 mask; + + q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + /* + * Populate the IVAR table and set the ITR values to the + * corresponding register. + */ + for (v_idx = 0; v_idx < q_vectors; v_idx++) { + q_vector = adapter->q_vector[v_idx]; + /* XXX for_each_bit(...) */ + r_idx = find_first_bit(q_vector->rxr_idx, + adapter->num_rx_queues); + + for (i = 0; i < q_vector->rxr_count; i++) { + j = adapter->rx_ring[r_idx].reg_idx; + ixgbevf_set_ivar(adapter, 0, j, v_idx); + r_idx = find_next_bit(q_vector->rxr_idx, + adapter->num_rx_queues, + r_idx + 1); + } + r_idx = find_first_bit(q_vector->txr_idx, + adapter->num_tx_queues); + + for (i = 0; i < q_vector->txr_count; i++) { + j = adapter->tx_ring[r_idx].reg_idx; + ixgbevf_set_ivar(adapter, 1, j, v_idx); + r_idx = find_next_bit(q_vector->txr_idx, + adapter->num_tx_queues, + r_idx + 1); + } + + /* if this is a tx only vector halve the interrupt rate */ + if (q_vector->txr_count && !q_vector->rxr_count) + q_vector->eitr = (adapter->eitr_param >> 1); + else if (q_vector->rxr_count) + /* rx only */ + q_vector->eitr = adapter->eitr_param; + + ixgbevf_write_eitr(adapter, v_idx, q_vector->eitr); + } + + ixgbevf_set_ivar(adapter, -1, 1, v_idx); + + /* set up to autoclear timer, and the vectors */ + mask = IXGBE_EIMS_ENABLE_MASK; + mask &= ~IXGBE_EIMS_OTHER; + IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask); +} + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; + +/** + * ixgbevf_update_itr - update the dynamic ITR value based on statistics + * @adapter: pointer to adapter + * @eitr: eitr setting (ints per sec) to give last timeslice + * @itr_setting: current throttle rate in ints/second + * @packets: the number of packets during this measurement interval + * @bytes: the number of bytes during this measurement interval + * + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + **/ +static u8 ixgbevf_update_itr(struct ixgbevf_adapter *adapter, + u32 eitr, u8 itr_setting, + int packets, int bytes) +{ + unsigned int retval = itr_setting; + u32 timepassed_us; + u64 bytes_perint; + + if (packets == 0) + goto update_itr_done; + + + /* simple throttlerate management + * 0-20MB/s lowest (100000 ints/s) + * 20-100MB/s low (20000 ints/s) + * 100-1249MB/s bulk (8000 ints/s) + */ + /* what was last interrupt timeslice? */ + timepassed_us = 1000000/eitr; + bytes_perint = bytes / timepassed_us; /* bytes/usec */ + + switch (itr_setting) { + case lowest_latency: + if (bytes_perint > adapter->eitr_low) + retval = low_latency; + break; + case low_latency: + if (bytes_perint > adapter->eitr_high) + retval = bulk_latency; + else if (bytes_perint <= adapter->eitr_low) + retval = lowest_latency; + break; + case bulk_latency: + if (bytes_perint <= adapter->eitr_high) + retval = low_latency; + break; + } + +update_itr_done: + return retval; +} + +/** + * ixgbevf_write_eitr - write VTEITR register in hardware specific way + * @adapter: pointer to adapter struct + * @v_idx: vector index into q_vector array + * @itr_reg: new value to be written in *register* format, not ints/s + * + * This function is made to be called by ethtool and by the driver + * when it needs to update VTEITR registers at runtime. Hardware + * specific quirks/differences are taken care of here. + */ +static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx, + u32 itr_reg) +{ + struct ixgbe_hw *hw = &adapter->hw; + + itr_reg = EITR_INTS_PER_SEC_TO_REG(itr_reg); + + /* + * set the WDIS bit to not clear the timer bits and cause an + * immediate assertion of the interrupt + */ + itr_reg |= IXGBE_EITR_CNT_WDIS; + + IXGBE_WRITE_REG(hw, IXGBE_VTEITR(v_idx), itr_reg); +} + +static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector) +{ + struct ixgbevf_adapter *adapter = q_vector->adapter; + u32 new_itr; + u8 current_itr, ret_itr; + int i, r_idx, v_idx = q_vector->v_idx; + struct ixgbevf_ring *rx_ring, *tx_ring; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + tx_ring = &(adapter->tx_ring[r_idx]); + ret_itr = ixgbevf_update_itr(adapter, q_vector->eitr, + q_vector->tx_itr, + tx_ring->total_packets, + tx_ring->total_bytes); + /* if the result for this queue would decrease interrupt + * rate for this vector then use that result */ + q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ? + q_vector->tx_itr - 1 : ret_itr); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); + ret_itr = ixgbevf_update_itr(adapter, q_vector->eitr, + q_vector->rx_itr, + rx_ring->total_packets, + rx_ring->total_bytes); + /* if the result for this queue would decrease interrupt + * rate for this vector then use that result */ + q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ? + q_vector->rx_itr - 1 : ret_itr); + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + + current_itr = max(q_vector->rx_itr, q_vector->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = 100000; + break; + case low_latency: + new_itr = 20000; /* aka hwitr = ~200 */ + break; + case bulk_latency: + default: + new_itr = 8000; + break; + } + + if (new_itr != q_vector->eitr) { + u32 itr_reg; + + /* save the algorithm value here, not the smoothed one */ + q_vector->eitr = new_itr; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); + itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); + ixgbevf_write_eitr(adapter, v_idx, itr_reg); + } + + return; +} + +static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) +{ + struct net_device *netdev = data; + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr; + + eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS); + IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr); + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data) +{ + struct ixgbevf_q_vector *q_vector = data; + struct ixgbevf_adapter *adapter = q_vector->adapter; + struct ixgbevf_ring *tx_ring; + int i, r_idx; + + if (!q_vector->txr_count) + return IRQ_HANDLED; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + tx_ring = &(adapter->tx_ring[r_idx]); + tx_ring->total_bytes = 0; + tx_ring->total_packets = 0; + ixgbevf_clean_tx_irq(adapter, tx_ring); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } + + if (adapter->itr_setting & 1) + ixgbevf_set_itr_msix(q_vector); + + return IRQ_HANDLED; +} + +/** + * ixgbe_msix_clean_rx - single unshared vector rx clean (all queues) + * @irq: unused + * @data: pointer to our q_vector struct for this interrupt vector + **/ +static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data) +{ + struct ixgbevf_q_vector *q_vector = data; + struct ixgbevf_adapter *adapter = q_vector->adapter; + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbevf_ring *rx_ring; + int r_idx; + int i; + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); + rx_ring->total_bytes = 0; + rx_ring->total_packets = 0; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + + if (!q_vector->rxr_count) + return IRQ_HANDLED; + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + rx_ring = &(adapter->rx_ring[r_idx]); + /* disable interrupts on this vector only */ + IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, rx_ring->v_idx); + napi_schedule(&q_vector->napi); + + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbevf_msix_clean_many(int irq, void *data) +{ + ixgbevf_msix_clean_rx(irq, data); + ixgbevf_msix_clean_tx(irq, data); + + return IRQ_HANDLED; +} + +static inline void map_vector_to_rxq(struct ixgbevf_adapter *a, int v_idx, + int r_idx) +{ + struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(r_idx, q_vector->rxr_idx); + q_vector->rxr_count++; + a->rx_ring[r_idx].v_idx = 1 << v_idx; +} + +static inline void map_vector_to_txq(struct ixgbevf_adapter *a, int v_idx, + int t_idx) +{ + struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(t_idx, q_vector->txr_idx); + q_vector->txr_count++; + a->tx_ring[t_idx].v_idx = 1 << v_idx; +} + +/** + * ixgbevf_map_rings_to_vectors - Maps descriptor rings to vectors + * @adapter: board private structure to initialize + * + * This function maps descriptor rings to the queue-specific vectors + * we were allotted through the MSI-X enabling code. Ideally, we'd have + * one vector per ring/queue, but on a constrained vector budget, we + * group the rings as "efficiently" as possible. You would add new + * mapping configurations in here. + **/ +static int ixgbevf_map_rings_to_vectors(struct ixgbevf_adapter *adapter) +{ + int q_vectors; + int v_start = 0; + int rxr_idx = 0, txr_idx = 0; + int rxr_remaining = adapter->num_rx_queues; + int txr_remaining = adapter->num_tx_queues; + int i, j; + int rqpv, tqpv; + int err = 0; + + q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + /* + * The ideal configuration... + * We have enough vectors to map one per queue. + */ + if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) { + for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++) + map_vector_to_rxq(adapter, v_start, rxr_idx); + + for (; txr_idx < txr_remaining; v_start++, txr_idx++) + map_vector_to_txq(adapter, v_start, txr_idx); + goto out; + } + + /* + * If we don't have enough vectors for a 1-to-1 + * mapping, we'll have to group them so there are + * multiple queues per vector. + */ + /* Re-adjusting *qpv takes care of the remainder. */ + for (i = v_start; i < q_vectors; i++) { + rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i); + for (j = 0; j < rqpv; j++) { + map_vector_to_rxq(adapter, i, rxr_idx); + rxr_idx++; + rxr_remaining--; + } + } + for (i = v_start; i < q_vectors; i++) { + tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i); + for (j = 0; j < tqpv; j++) { + map_vector_to_txq(adapter, i, txr_idx); + txr_idx++; + txr_remaining--; + } + } + +out: + return err; +} + +/** + * ixgbevf_request_msix_irqs - Initialize MSI-X interrupts + * @adapter: board private structure + * + * ixgbevf_request_msix_irqs allocates MSI-X vectors and requests + * interrupts from the kernel. + **/ +static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + irqreturn_t (*handler)(int, void *); + int i, vector, q_vectors, err; + int ri = 0, ti = 0; + + /* Decrement for Other and TCP Timer vectors */ + q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + +#define SET_HANDLER(_v) (((_v)->rxr_count && (_v)->txr_count) \ + ? &ixgbevf_msix_clean_many : \ + (_v)->rxr_count ? &ixgbevf_msix_clean_rx : \ + (_v)->txr_count ? &ixgbevf_msix_clean_tx : \ + NULL) + for (vector = 0; vector < q_vectors; vector++) { + handler = SET_HANDLER(adapter->q_vector[vector]); + + if (handler == &ixgbevf_msix_clean_rx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "rx", ri++); + } else if (handler == &ixgbevf_msix_clean_tx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "tx", ti++); + } else if (handler == &ixgbevf_msix_clean_many) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "TxRx", vector); + } else { + /* skip this unused q_vector */ + continue; + } + err = request_irq(adapter->msix_entries[vector].vector, + handler, 0, adapter->name[vector], + adapter->q_vector[vector]); + if (err) { + hw_dbg(&adapter->hw, + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); + goto free_queue_irqs; + } + } + + sprintf(adapter->name[vector], "%s:mbx", netdev->name); + err = request_irq(adapter->msix_entries[vector].vector, + &ixgbevf_msix_mbx, 0, adapter->name[vector], netdev); + if (err) { + hw_dbg(&adapter->hw, + "request_irq for msix_mbx failed: %d\n", err); + goto free_queue_irqs; + } + + return 0; + +free_queue_irqs: + for (i = vector - 1; i >= 0; i--) + free_irq(adapter->msix_entries[--vector].vector, + &(adapter->q_vector[i])); + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + return err; +} + +static inline void ixgbevf_reset_q_vectors(struct ixgbevf_adapter *adapter) +{ + int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + for (i = 0; i < q_vectors; i++) { + struct ixgbevf_q_vector *q_vector = adapter->q_vector[i]; + bitmap_zero(q_vector->rxr_idx, MAX_RX_QUEUES); + bitmap_zero(q_vector->txr_idx, MAX_TX_QUEUES); + q_vector->rxr_count = 0; + q_vector->txr_count = 0; + q_vector->eitr = adapter->eitr_param; + } +} + +/** + * ixgbevf_request_irq - initialize interrupts + * @adapter: board private structure + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static int ixgbevf_request_irq(struct ixgbevf_adapter *adapter) +{ + int err = 0; + + err = ixgbevf_request_msix_irqs(adapter); + + if (err) + hw_dbg(&adapter->hw, + "request_irq failed, Error %d\n", err); + + return err; +} + +static void ixgbevf_free_irq(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i, q_vectors; + + q_vectors = adapter->num_msix_vectors; + + i = q_vectors - 1; + + free_irq(adapter->msix_entries[i].vector, netdev); + i--; + + for (; i >= 0; i--) { + free_irq(adapter->msix_entries[i].vector, + adapter->q_vector[i]); + } + + ixgbevf_reset_q_vectors(adapter); +} + +/** + * ixgbevf_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ +static inline void ixgbevf_irq_disable(struct ixgbevf_adapter *adapter) +{ + int i; + struct ixgbe_hw *hw = &adapter->hw; + + IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, ~0); + + IXGBE_WRITE_FLUSH(hw); + + for (i = 0; i < adapter->num_msix_vectors; i++) + synchronize_irq(adapter->msix_entries[i].vector); +} + +/** + * ixgbevf_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ +static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter, + bool queues, bool flush) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 mask; + u64 qmask; + + mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); + qmask = ~0; + + IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); + + if (queues) + ixgbevf_irq_enable_queues(adapter, qmask); + + if (flush) + IXGBE_WRITE_FLUSH(hw); +} + +/** + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) +{ + u64 tdba; + struct ixgbe_hw *hw = &adapter->hw; + u32 i, j, tdlen, txctrl; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->tx_ring[i]; + j = ring->reg_idx; + tdba = ring->dma; + tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc); + IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(j), + (tdba & DMA_BIT_MASK(32))); + IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(j), (tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), tdlen); + IXGBE_WRITE_REG(hw, IXGBE_VFTDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFTDT(j), 0); + adapter->tx_ring[i].head = IXGBE_VFTDH(j); + adapter->tx_ring[i].tail = IXGBE_VFTDT(j); + /* Disable Tx Head Writeback RO bit, since this hoses + * bookkeeping if things aren't delivered in order. + */ + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); + } +} + +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 + +static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index) +{ + struct ixgbevf_ring *rx_ring; + struct ixgbe_hw *hw = &adapter->hw; + u32 srrctl; + + rx_ring = &adapter->rx_ring[index]; + + srrctl = IXGBE_SRRCTL_DROP_EN; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + u16 bufsz = IXGBEVF_RXBUFFER_2048; + /* grow the amount we can receive on large page machines */ + if (bufsz < (PAGE_SIZE / 2)) + bufsz = (PAGE_SIZE / 2); + /* cap the bufsz at our largest descriptor size */ + bufsz = min((u16)IXGBEVF_MAX_RXBUFFER, bufsz); + + srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + srrctl |= ((IXGBEVF_RX_HDR_SIZE << + IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK); + } else { + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + + if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) + srrctl |= IXGBEVF_RXBUFFER_2048 >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= rx_ring->rx_buf_len >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } + IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(index), srrctl); +} + +/** + * ixgbevf_configure_rx - Configure 82599 VF Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) +{ + u64 rdba; + struct ixgbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + int i, j; + u32 rdlen; + int rx_buf_len; + + /* Decide whether to use packet split mode or not */ + if (netdev->mtu > ETH_DATA_LEN) { + if (adapter->flags & IXGBE_FLAG_RX_PS_CAPABLE) + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + } else { + if (adapter->flags & IXGBE_FLAG_RX_1BUF_CAPABLE) + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + else + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + } + + /* Set the RX buffer length according to the mode */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + /* PSRTYPE must be initialized in 82599 */ + u32 psrtype = IXGBE_PSRTYPE_TCPHDR | + IXGBE_PSRTYPE_UDPHDR | + IXGBE_PSRTYPE_IPV4HDR | + IXGBE_PSRTYPE_IPV6HDR | + IXGBE_PSRTYPE_L2HDR; + IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype); + rx_buf_len = IXGBEVF_RX_HDR_SIZE; + } else { + IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0); + if (netdev->mtu <= ETH_DATA_LEN) + rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; + else + rx_buf_len = ALIGN(max_frame, 1024); + } + + rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rdba = adapter->rx_ring[i].dma; + j = adapter->rx_ring[i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j), + (rdba & DMA_BIT_MASK(32))); + IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), rdlen); + IXGBE_WRITE_REG(hw, IXGBE_VFRDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0); + adapter->rx_ring[i].head = IXGBE_VFRDH(j); + adapter->rx_ring[i].tail = IXGBE_VFRDT(j); + adapter->rx_ring[i].rx_buf_len = rx_buf_len; + + ixgbevf_configure_srrctl(adapter, j); + } +} + +static void ixgbevf_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int i, j; + u32 ctrl; + + adapter->vlgrp = grp; + + for (i = 0; i < adapter->num_rx_queues; i++) { + j = adapter->rx_ring[i].reg_idx; + ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)); + ctrl |= IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), ctrl); + } +} + +static void ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + struct net_device *v_netdev; + + /* add VID to filter table */ + if (hw->mac.ops.set_vfta) + hw->mac.ops.set_vfta(hw, vid, 0, true); + /* + * Copy feature flags from netdev to the vlan netdev for this vid. + * This allows things like TSO to bubble down to our vlan device. + */ + v_netdev = vlan_group_get_device(adapter->vlgrp, vid); + v_netdev->features |= adapter->netdev->features; + vlan_group_set_device(adapter->vlgrp, vid, v_netdev); +} + +static void ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) + ixgbevf_irq_disable(adapter); + + vlan_group_set_device(adapter->vlgrp, vid, NULL); + + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) + ixgbevf_irq_enable(adapter, true, true); + + /* remove VID from filter table */ + if (hw->mac.ops.set_vfta) + hw->mac.ops.set_vfta(hw, vid, 0, false); +} + +static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter) +{ + ixgbevf_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + ixgbevf_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +static u8 *ixgbevf_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, + u32 *vmdq) +{ + struct dev_mc_list *mc_ptr; + u8 *addr = *mc_addr_ptr; + *vmdq = 0; + + mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]); + if (mc_ptr->next) + *mc_addr_ptr = mc_ptr->next->dmi_addr; + else + *mc_addr_ptr = NULL; + + return addr; +} + +/** + * ixgbevf_set_rx_mode - Multicast set + * @netdev: network interface device structure + * + * The set_rx_method entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast mode. + **/ +static void ixgbevf_set_rx_mode(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u8 *addr_list = NULL; + int addr_count = 0; + + /* reprogram multicast list */ + addr_count = netdev->mc_count; + if (addr_count) + addr_list = netdev->mc_list->dmi_addr; + if (hw->mac.ops.update_mc_addr_list) + hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, + ixgbevf_addr_list_itr); +} + +static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter) +{ + int q_idx; + struct ixgbevf_q_vector *q_vector; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + for (q_idx = 0; q_idx < q_vectors; q_idx++) { + struct napi_struct *napi; + q_vector = adapter->q_vector[q_idx]; + if (!q_vector->rxr_count) + continue; + napi = &q_vector->napi; + if (q_vector->rxr_count > 1) + napi->poll = &ixgbevf_clean_rxonly_many; + + napi_enable(napi); + } +} + +static void ixgbevf_napi_disable_all(struct ixgbevf_adapter *adapter) +{ + int q_idx; + struct ixgbevf_q_vector *q_vector; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + + for (q_idx = 0; q_idx < q_vectors; q_idx++) { + q_vector = adapter->q_vector[q_idx]; + if (!q_vector->rxr_count) + continue; + napi_disable(&q_vector->napi); + } +} + +static void ixgbevf_configure(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + ixgbevf_set_rx_mode(netdev); + + ixgbevf_restore_vlan(adapter); + + ixgbevf_configure_tx(adapter); + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; + ixgbevf_alloc_rx_buffers(adapter, ring, ring->count); + ring->next_to_use = ring->count - 1; + writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail); + } +} + +#define IXGBE_MAX_RX_DESC_POLL 10 +static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, + int rxr) +{ + struct ixgbe_hw *hw = &adapter->hw; + int j = adapter->rx_ring[rxr].reg_idx; + int k; + + for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) { + if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)) & IXGBE_RXDCTL_ENABLE) + break; + else + msleep(1); + } + if (k >= IXGBE_MAX_RX_DESC_POLL) { + hw_dbg(hw, "RXDCTL.ENABLE on Rx queue %d " + "not set within the polling period\n", rxr); + } + + ixgbevf_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr], + (adapter->rx_ring[rxr].count - 1)); +} + +static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + int i, j = 0; + int num_rx_rings = adapter->num_rx_queues; + u32 txdctl, rxdctl; + + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); + /* enable WTHRESH=8 descriptors, to encourage burst writeback */ + txdctl |= (8 << 16); + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl); + } + + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); + txdctl |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl); + } + + for (i = 0; i < num_rx_rings; i++) { + j = adapter->rx_ring[i].reg_idx; + rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)); + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), rxdctl); + ixgbevf_rx_desc_queue_enable(adapter, i); + } + + ixgbevf_configure_msix(adapter); + + if (hw->mac.ops.set_rar) { + if (is_valid_ether_addr(hw->mac.addr)) + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0); + else + hw->mac.ops.set_rar(hw, 0, hw->mac.perm_addr, 0); + } + + clear_bit(__IXGBEVF_DOWN, &adapter->state); + ixgbevf_napi_enable_all(adapter); + + /* enable transmits */ + netif_tx_start_all_queues(netdev); + + /* bring the link up in the watchdog, this could race with our first + * link up interrupt but shouldn't be a problem */ + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; +} + +int ixgbevf_up(struct ixgbevf_adapter *adapter) +{ + int err; + struct ixgbe_hw *hw = &adapter->hw; + + ixgbevf_configure(adapter); + + err = ixgbevf_up_complete(adapter); + + /* clear any pending interrupts, may auto mask */ + IXGBE_READ_REG(hw, IXGBE_VTEICR); + + ixgbevf_irq_enable(adapter, true, true); + + return err; +} + +/** + * ixgbevf_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + * @rx_ring: ring to free buffers from + **/ +static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbevf_rx_buffer *rx_buffer_info; + + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + if (rx_buffer_info->dma) { + pci_unmap_single(pdev, rx_buffer_info->dma, + rx_ring->rx_buf_len, + PCI_DMA_FROMDEVICE); + rx_buffer_info->dma = 0; + } + if (rx_buffer_info->skb) { + struct sk_buff *skb = rx_buffer_info->skb; + rx_buffer_info->skb = NULL; + do { + struct sk_buff *this = skb; + skb = skb->prev; + dev_kfree_skb(this); + } while (skb); + } + if (!rx_buffer_info->page) + continue; + pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2, + PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + put_page(rx_buffer_info->page); + rx_buffer_info->page = NULL; + rx_buffer_info->page_offset = 0; + } + + size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count; + memset(rx_ring->rx_buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + if (rx_ring->head) + writel(0, adapter->hw.hw_addr + rx_ring->head); + if (rx_ring->tail) + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * ixgbevf_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + * @tx_ring: ring to be cleaned + **/ +static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring) +{ + struct ixgbevf_tx_buffer *tx_buffer_info; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + + for (i = 0; i < tx_ring->count; i++) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info); + } + + size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + if (tx_ring->head) + writel(0, adapter->hw.hw_addr + tx_ring->head); + if (tx_ring->tail) + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * ixgbevf_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbevf_clean_all_rx_rings(struct ixgbevf_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbevf_clean_rx_ring(adapter, &adapter->rx_ring[i]); +} + +/** + * ixgbevf_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbevf_clean_all_tx_rings(struct ixgbevf_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbevf_clean_tx_ring(adapter, &adapter->tx_ring[i]); +} + +void ixgbevf_down(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + u32 txdctl; + int i, j; + + /* signal that we are down to the interrupt handler */ + set_bit(__IXGBEVF_DOWN, &adapter->state); + /* disable receives */ + + netif_tx_disable(netdev); + + msleep(10); + + netif_tx_stop_all_queues(netdev); + + ixgbevf_irq_disable(adapter); + + ixgbevf_napi_disable_all(adapter); + + del_timer_sync(&adapter->watchdog_timer); + /* can't call flush scheduled work here because it can deadlock + * if linkwatch_event tries to acquire the rtnl_lock which we are + * holding */ + while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK) + msleep(1); + + /* disable transmits in the hardware now that interrupts are off */ + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), + (txdctl & ~IXGBE_TXDCTL_ENABLE)); + } + + netif_carrier_off(netdev); + + if (!pci_channel_offline(adapter->pdev)) + ixgbevf_reset(adapter); + + ixgbevf_clean_all_tx_rings(adapter); + ixgbevf_clean_all_rx_rings(adapter); +} + +void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) + msleep(1); + + ixgbevf_down(adapter); + ixgbevf_up(adapter); + + clear_bit(__IXGBEVF_RESETTING, &adapter->state); +} + +void ixgbevf_reset(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + + if (hw->mac.ops.reset_hw(hw)) + hw_dbg(hw, "PF still resetting\n"); + else + hw->mac.ops.init_hw(hw); + + if (is_valid_ether_addr(adapter->hw.mac.addr)) { + memcpy(netdev->dev_addr, adapter->hw.mac.addr, + netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac.addr, + netdev->addr_len); + } +} + +static void ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, + int vectors) +{ + int err, vector_threshold; + + /* We'll want at least 3 (vector_threshold): + * 1) TxQ[0] Cleanup + * 2) RxQ[0] Cleanup + * 3) Other (Link Status Change, etc.) + */ + vector_threshold = MIN_MSIX_COUNT; + + /* The more we get, the more we will assign to Tx/Rx Cleanup + * for the separate queues...where Rx Cleanup >= Tx Cleanup. + * Right now, we simply care about how many we'll get; we'll + * set them up later while requesting irq's. + */ + while (vectors >= vector_threshold) { + err = pci_enable_msix(adapter->pdev, adapter->msix_entries, + vectors); + if (!err) /* Success in acquiring all requested vectors. */ + break; + else if (err < 0) + vectors = 0; /* Nasty failure, quit now */ + else /* err == number of vectors we should try again with */ + vectors = err; + } + + if (vectors < vector_threshold) { + /* Can't allocate enough MSI-X interrupts? Oh well. + * This just means we'll go with either a single MSI + * vector or fall back to legacy interrupts. + */ + hw_dbg(&adapter->hw, + "Unable to allocate MSI-X interrupts\n"); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + } else { + /* + * Adjust for only the vectors we'll use, which is minimum + * of max_msix_q_vectors + NON_Q_VECTORS, or the number of + * vectors we were allocated. + */ + adapter->num_msix_vectors = vectors; + } +} + +/* + * ixgbe_set_num_queues: Allocate queues for device, feature dependant + * @adapter: board private structure to initialize + * + * This is the top level queue allocation routine. The order here is very + * important, starting with the "most" number of features turned on at once, + * and ending with the smallest set of features. This way large combinations + * can be allocated if they're turned on, and smaller combinations are the + * fallthrough conditions. + * + **/ +static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter) +{ + /* Start with base case */ + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; + adapter->num_rx_pools = adapter->num_rx_queues; + adapter->num_rx_queues_per_pool = 1; +} + +/** + * ixgbevf_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ +static int ixgbevf_alloc_queues(struct ixgbevf_adapter *adapter) +{ + int i; + + adapter->tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbevf_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err_tx_ring_allocation; + + adapter->rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbevf_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err_rx_ring_allocation; + + for (i = 0; i < adapter->num_tx_queues; i++) { + adapter->tx_ring[i].count = adapter->tx_ring_count; + adapter->tx_ring[i].queue_index = i; + adapter->tx_ring[i].reg_idx = i; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->rx_ring[i].count = adapter->rx_ring_count; + adapter->rx_ring[i].queue_index = i; + adapter->rx_ring[i].reg_idx = i; + } + + return 0; + +err_rx_ring_allocation: + kfree(adapter->tx_ring); +err_tx_ring_allocation: + return -ENOMEM; +} + +/** + * ixgbevf_set_interrupt_capability - set MSI-X or FAIL if not supported + * @adapter: board private structure to initialize + * + * Attempt to configure the interrupts using the best available + * capabilities of the hardware and the kernel. + **/ +static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter) +{ + int err = 0; + int vector, v_budget; + + /* + * It's easy to be greedy for MSI-X vectors, but it really + * doesn't do us much good if we have a lot more vectors + * than CPU's. So let's be conservative and only ask for + * (roughly) twice the number of vectors as there are CPU's. + */ + v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues, + (int)(num_online_cpus() * 2)) + NON_Q_VECTORS; + + /* A failure in MSI-X entry allocation isn't fatal, but it does + * mean we disable MSI-X capabilities of the adapter. */ + adapter->msix_entries = kcalloc(v_budget, + sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) { + err = -ENOMEM; + goto out; + } + + for (vector = 0; vector < v_budget; vector++) + adapter->msix_entries[vector].entry = vector; + + ixgbevf_acquire_msix_vectors(adapter, v_budget); + +out: + return err; +} + +/** + * ixgbevf_alloc_q_vectors - Allocate memory for interrupt vectors + * @adapter: board private structure to initialize + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + **/ +static int ixgbevf_alloc_q_vectors(struct ixgbevf_adapter *adapter) +{ + int q_idx, num_q_vectors; + struct ixgbevf_q_vector *q_vector; + int napi_vectors; + int (*poll)(struct napi_struct *, int); + + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + napi_vectors = adapter->num_rx_queues; + poll = &ixgbevf_clean_rxonly; + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + q_vector = kzalloc(sizeof(struct ixgbevf_q_vector), GFP_KERNEL); + if (!q_vector) + goto err_out; + q_vector->adapter = adapter; + q_vector->v_idx = q_idx; + q_vector->eitr = adapter->eitr_param; + if (q_idx < napi_vectors) + netif_napi_add(adapter->netdev, &q_vector->napi, + (*poll), 64); + adapter->q_vector[q_idx] = q_vector; + } + + return 0; + +err_out: + while (q_idx) { + q_idx--; + q_vector = adapter->q_vector[q_idx]; + netif_napi_del(&q_vector->napi); + kfree(q_vector); + adapter->q_vector[q_idx] = NULL; + } + return -ENOMEM; +} + +/** + * ixgbevf_free_q_vectors - Free memory allocated for interrupt vectors + * @adapter: board private structure to initialize + * + * This function frees the memory allocated to the q_vectors. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + **/ +static void ixgbevf_free_q_vectors(struct ixgbevf_adapter *adapter) +{ + int q_idx, num_q_vectors; + int napi_vectors; + + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + napi_vectors = adapter->num_rx_queues; + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + struct ixgbevf_q_vector *q_vector = adapter->q_vector[q_idx]; + + adapter->q_vector[q_idx] = NULL; + if (q_idx < napi_vectors) + netif_napi_del(&q_vector->napi); + kfree(q_vector); + } +} + +/** + * ixgbevf_reset_interrupt_capability - Reset MSIX setup + * @adapter: board private structure + * + **/ +static void ixgbevf_reset_interrupt_capability(struct ixgbevf_adapter *adapter) +{ + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + + return; +} + +/** + * ixgbevf_init_interrupt_scheme - Determine if MSIX is supported and init + * @adapter: board private structure to initialize + * + **/ +static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter) +{ + int err; + + /* Number of supported queues */ + ixgbevf_set_num_queues(adapter); + + err = ixgbevf_set_interrupt_capability(adapter); + if (err) { + hw_dbg(&adapter->hw, + "Unable to setup interrupt capabilities\n"); + goto err_set_interrupt; + } + + err = ixgbevf_alloc_q_vectors(adapter); + if (err) { + hw_dbg(&adapter->hw, "Unable to allocate memory for queue " + "vectors\n"); + goto err_alloc_q_vectors; + } + + err = ixgbevf_alloc_queues(adapter); + if (err) { + printk(KERN_ERR "Unable to allocate memory for queues\n"); + goto err_alloc_queues; + } + + hw_dbg(&adapter->hw, "Multiqueue %s: Rx Queue count = %u, " + "Tx Queue count = %u\n", + (adapter->num_rx_queues > 1) ? "Enabled" : + "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); + + set_bit(__IXGBEVF_DOWN, &adapter->state); + + return 0; +err_alloc_queues: + ixgbevf_free_q_vectors(adapter); +err_alloc_q_vectors: + ixgbevf_reset_interrupt_capability(adapter); +err_set_interrupt: + return err; +} + +/** + * ixgbevf_sw_init - Initialize general software structures + * (struct ixgbevf_adapter) + * @adapter: board private structure to initialize + * + * ixgbevf_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + int err; + + /* PCI config space info */ + + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + hw->mbx.ops.init_params(hw); + hw->mac.max_tx_queues = MAX_TX_QUEUES; + hw->mac.max_rx_queues = MAX_RX_QUEUES; + err = hw->mac.ops.reset_hw(hw); + if (err) { + dev_info(&pdev->dev, + "PF still in reset state, assigning new address\n"); + random_ether_addr(hw->mac.addr); + } else { + err = hw->mac.ops.init_hw(hw); + if (err) { + printk(KERN_ERR "init_shared_code failed: %d\n", err); + goto out; + } + } + + /* Enable dynamic interrupt throttling rates */ + adapter->eitr_param = 20000; + adapter->itr_setting = 1; + + /* set defaults for eitr in MegaBytes */ + adapter->eitr_low = 10; + adapter->eitr_high = 20; + + /* set default ring sizes */ + adapter->tx_ring_count = IXGBEVF_DEFAULT_TXD; + adapter->rx_ring_count = IXGBEVF_DEFAULT_RXD; + + /* enable rx csum by default */ + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + + set_bit(__IXGBEVF_DOWN, &adapter->state); + +out: + return err; +} + +static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); + adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); + adapter->stats.last_vfgorc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); + adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); + adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); + adapter->stats.last_vfgotc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); + adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); + + adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; + adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; + adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; + adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; + adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; +} + +#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \ + { \ + u32 current_counter = IXGBE_READ_REG(hw, reg); \ + if (current_counter < last_counter) \ + counter += 0x100000000LL; \ + last_counter = current_counter; \ + counter &= 0xFFFFFFFF00000000LL; \ + counter |= current_counter; \ + } + +#define UPDATE_VF_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \ + { \ + u64 current_counter_lsb = IXGBE_READ_REG(hw, reg_lsb); \ + u64 current_counter_msb = IXGBE_READ_REG(hw, reg_msb); \ + u64 current_counter = (current_counter_msb << 32) | \ + current_counter_lsb; \ + if (current_counter < last_counter) \ + counter += 0x1000000000LL; \ + last_counter = current_counter; \ + counter &= 0xFFFFFFF000000000LL; \ + counter |= current_counter; \ + } +/** + * ixgbevf_update_stats - Update the board statistics counters. + * @adapter: board private structure + **/ +void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc, + adapter->stats.vfgprc); + UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc, + adapter->stats.vfgptc); + UPDATE_VF_COUNTER_36bit(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB, + adapter->stats.last_vfgorc, + adapter->stats.vfgorc); + UPDATE_VF_COUNTER_36bit(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB, + adapter->stats.last_vfgotc, + adapter->stats.vfgotc); + UPDATE_VF_COUNTER_32bit(IXGBE_VFMPRC, adapter->stats.last_vfmprc, + adapter->stats.vfmprc); + + /* Fill out the OS statistics structure */ + adapter->net_stats.multicast = adapter->stats.vfmprc - + adapter->stats.base_vfmprc; +} + +/** + * ixgbevf_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void ixgbevf_watchdog(unsigned long data) +{ + struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data; + struct ixgbe_hw *hw = &adapter->hw; + u64 eics = 0; + int i; + + /* + * Do the watchdog outside of interrupt context due to the lovely + * delays that some of the newer hardware requires + */ + + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + goto watchdog_short_circuit; + + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbevf_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= (1 << i); + } + + IXGBE_WRITE_REG(hw, IXGBE_VTEICS, (u32)eics); + +watchdog_short_circuit: + schedule_work(&adapter->watchdog_task); +} + +/** + * ixgbevf_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void ixgbevf_tx_timeout(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} + +static void ixgbevf_reset_task(struct work_struct *work) +{ + struct ixgbevf_adapter *adapter; + adapter = container_of(work, struct ixgbevf_adapter, reset_task); + + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; + + adapter->tx_timeout_count++; + + ixgbevf_reinit_locked(adapter); +} + +/** + * ixgbevf_watchdog_task - worker thread to bring link up + * @work: pointer to work_struct containing our data + **/ +static void ixgbevf_watchdog_task(struct work_struct *work) +{ + struct ixgbevf_adapter *adapter = container_of(work, + struct ixgbevf_adapter, + watchdog_task); + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; + + adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; + + /* + * Always check the link on the watchdog because we have + * no LSC interrupt + */ + if (hw->mac.ops.check_link) { + if ((hw->mac.ops.check_link(hw, &link_speed, + &link_up, false)) != 0) { + adapter->link_up = link_up; + adapter->link_speed = link_speed; + schedule_work(&adapter->reset_task); + goto pf_has_reset; + } + } else { + /* always assume link is up, if no check link + * function */ + link_speed = IXGBE_LINK_SPEED_10GB_FULL; + link_up = true; + } + adapter->link_up = link_up; + adapter->link_speed = link_speed; + + if (link_up) { + if (!netif_carrier_ok(netdev)) { + hw_dbg(&adapter->hw, "NIC Link is Up %s, ", + ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + "10 Gbps" : "1 Gbps")); + netif_carrier_on(netdev); + netif_tx_wake_all_queues(netdev); + } else { + /* Force detection of hung controller */ + adapter->detect_tx_hung = true; + } + } else { + adapter->link_up = false; + adapter->link_speed = 0; + if (netif_carrier_ok(netdev)) { + hw_dbg(&adapter->hw, "NIC Link is Down\n"); + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); + } + } + +pf_has_reset: + ixgbevf_update_stats(adapter); + + /* Force detection of hung controller every watchdog period */ + adapter->detect_tx_hung = true; + + /* Reset the timer */ + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + (2 * HZ))); + + adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; +} + +/** + * ixgbevf_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ +void ixgbevf_free_tx_resources(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + + ixgbevf_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * ixgbevf_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ +static void ixgbevf_free_all_tx_resources(struct ixgbevf_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + if (adapter->tx_ring[i].desc) + ixgbevf_free_tx_resources(adapter, + &adapter->tx_ring[i]); + +} + +/** + * ixgbevf_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * @tx_ring: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + **/ +int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count; + tx_ring->tx_buffer_info = vmalloc(size); + if (!tx_ring->tx_buffer_info) + goto err; + memset(tx_ring->tx_buffer_info, 0, size); + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma); + if (!tx_ring->desc) + goto err; + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + tx_ring->work_limit = tx_ring->count; + return 0; + +err: + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + hw_dbg(&adapter->hw, "Unable to allocate memory for the transmit " + "descriptor ring\n"); + return -ENOMEM; +} + +/** + * ixgbevf_setup_all_tx_resources - allocate all queues Tx resources + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ +static int ixgbevf_setup_all_tx_resources(struct ixgbevf_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = ixgbevf_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (!err) + continue; + hw_dbg(&adapter->hw, + "Allocation for Tx Queue %u failed\n", i); + break; + } + + return err; +} + +/** + * ixgbevf_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * @rx_ring: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + **/ +int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count; + rx_ring->rx_buffer_info = vmalloc(size); + if (!rx_ring->rx_buffer_info) { + hw_dbg(&adapter->hw, + "Unable to vmalloc buffer memory for " + "the receive descriptor ring\n"); + goto alloc_failed; + } + memset(rx_ring->rx_buffer_info, 0, size); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); + rx_ring->size = ALIGN(rx_ring->size, 4096); + + rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma); + + if (!rx_ring->desc) { + hw_dbg(&adapter->hw, + "Unable to allocate memory for " + "the receive descriptor ring\n"); + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + goto alloc_failed; + } + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + return 0; +alloc_failed: + return -ENOMEM; +} + +/** + * ixgbevf_setup_all_rx_resources - allocate all queues Rx resources + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ +static int ixgbevf_setup_all_rx_resources(struct ixgbevf_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = ixgbevf_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (!err) + continue; + hw_dbg(&adapter->hw, + "Allocation for Rx Queue %u failed\n", i); + break; + } + return err; +} + +/** + * ixgbevf_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * @rx_ring: ring to clean the resources from + * + * Free all receive software resources + **/ +void ixgbevf_free_rx_resources(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ixgbevf_clean_rx_ring(adapter, rx_ring); + + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); + + rx_ring->desc = NULL; +} + +/** + * ixgbevf_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ +static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + if (adapter->rx_ring[i].desc) + ixgbevf_free_rx_resources(adapter, + &adapter->rx_ring[i]); +} + +/** + * ixgbevf_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int ixgbevf_open(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int err; + + /* disallow open during test */ + if (test_bit(__IXGBEVF_TESTING, &adapter->state)) + return -EBUSY; + + if (hw->adapter_stopped) { + ixgbevf_reset(adapter); + /* if adapter is still stopped then PF isn't up and + * the vf can't start. */ + if (hw->adapter_stopped) { + err = IXGBE_ERR_MBX; + printk(KERN_ERR "Unable to start - perhaps the PF" + "Driver isn't up yet\n"); + goto err_setup_reset; + } + } + + /* allocate transmit descriptors */ + err = ixgbevf_setup_all_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = ixgbevf_setup_all_rx_resources(adapter); + if (err) + goto err_setup_rx; + + ixgbevf_configure(adapter); + + /* + * Map the Tx/Rx rings to the vectors we were allotted. + * if request_irq will be called in this function map_rings + * must be called *before* up_complete + */ + ixgbevf_map_rings_to_vectors(adapter); + + err = ixgbevf_up_complete(adapter); + if (err) + goto err_up; + + /* clear any pending interrupts, may auto mask */ + IXGBE_READ_REG(hw, IXGBE_VTEICR); + err = ixgbevf_request_irq(adapter); + if (err) + goto err_req_irq; + + ixgbevf_irq_enable(adapter, true, true); + + return 0; + +err_req_irq: + ixgbevf_down(adapter); +err_up: + ixgbevf_free_irq(adapter); +err_setup_rx: + ixgbevf_free_all_rx_resources(adapter); +err_setup_tx: + ixgbevf_free_all_tx_resources(adapter); + ixgbevf_reset(adapter); + +err_setup_reset: + + return err; +} + +/** + * ixgbevf_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int ixgbevf_close(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + ixgbevf_down(adapter); + ixgbevf_free_irq(adapter); + + ixgbevf_free_all_tx_resources(adapter); + ixgbevf_free_all_rx_resources(adapter); + + return 0; +} + +static int ixgbevf_tso(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags, u8 *hdr_len) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + int err; + struct ixgbevf_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl; + u32 mss_l4len_idx, l4len; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + l4len = tcp_hdrlen(skb); + *hdr_len += l4len; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + adapter->hw_tso_ctxt++; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + adapter->hw_tso6_ctxt++; + } + + i = tx_ring->next_to_use; + + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + /* VLAN MACLEN IPLEN */ + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= ((skb_network_offset(skb)) << + IXGBE_ADVTXD_MACLEN_SHIFT); + *hdr_len += skb_network_offset(skb); + vlan_macip_lens |= + (skb_transport_header(skb) - skb_network_header(skb)); + *hdr_len += + (skb_transport_header(skb) - skb_network_header(skb)); + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ + type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->protocol == htons(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + + /* MSS L4LEN IDX */ + mss_l4len_idx = + (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT); + /* use index 1 for TSO */ + mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + + return false; +} + +static bool ixgbevf_tx_csum(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + struct ixgbevf_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL || + (tx_flags & IXGBE_TX_FLAGS_VLAN)) { + i = tx_ring->next_to_use; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= (tx_flags & + IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= (skb_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT); + if (skb->ip_summed == CHECKSUM_PARTIAL) + vlan_macip_lens |= (skb_transport_header(skb) - + skb_network_header(skb)); + + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; + case __constant_htons(ETH_P_IPV6): + /* XXX what about other V6 headers?? */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; + default: + if (unlikely(net_ratelimit())) { + printk(KERN_WARNING + "partial checksum but " + "proto=%x!\n", + skb->protocol); + } + break; + } + } + + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + /* use index zero for tx checksum offload */ + context_desc->mss_l4len_idx = 0; + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + adapter->hw_csum_tx_good++; + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + + return false; +} + +static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags, + unsigned int first) +{ + struct pci_dev *pdev = adapter->pdev; + struct ixgbevf_tx_buffer *tx_buffer_info; + unsigned int len; + unsigned int total = skb->len; + unsigned int offset = 0, size, count = 0, i; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int f; + + i = tx_ring->next_to_use; + + len = min(skb_headlen(skb), total); + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->mapped_as_page = false; + tx_buffer_info->dma = pci_map_single(adapter->pdev, + skb->data + offset, + size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, tx_buffer_info->dma)) + goto dma_error; + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + total -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = min((unsigned int)frag->size, total); + offset = frag->page_offset; + + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_page(adapter->pdev, + frag->page, + offset, + size, + PCI_DMA_TODEVICE); + tx_buffer_info->mapped_as_page = true; + if (pci_dma_mapping_error(pdev, tx_buffer_info->dma)) + goto dma_error; + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + total -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + if (total == 0) + break; + } + + if (i == 0) + i = tx_ring->count - 1; + else + i = i - 1; + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[first].next_to_watch = i; + + return count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + + /* clear timestamp and dma mappings for failed tx_buffer_info map */ + tx_buffer_info->dma = 0; + tx_buffer_info->time_stamp = 0; + tx_buffer_info->next_to_watch = 0; + count--; + + /* clear timestamp and dma mappings for remaining portion of packet */ + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info); + } + + return count; +} + +static void ixgbevf_tx_queue(struct ixgbevf_adapter *adapter, + struct ixgbevf_ring *tx_ring, int tx_flags, + int count, u32 paylen, u8 hdr_len) +{ + union ixgbe_adv_tx_desc *tx_desc = NULL; + struct ixgbevf_tx_buffer *tx_buffer_info; + u32 olinfo_status = 0, cmd_type_len = 0; + unsigned int i; + + u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS; + + cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; + + cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT; + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; + + if (tx_flags & IXGBE_TX_FLAGS_TSO) { + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + /* use index 1 context for tso */ + olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + if (tx_flags & IXGBE_TX_FLAGS_IPV4) + olinfo_status |= IXGBE_TXD_POPTS_IXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + } else if (tx_flags & IXGBE_TX_FLAGS_CSUM) + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); + + i = tx_ring->next_to_use; + while (count--) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma); + tx_desc->read.cmd_type_len = + cpu_to_le32(cmd_type_len | tx_buffer_info->length); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); +} + +static int __ixgbevf_maybe_stop_tx(struct net_device *netdev, + struct ixgbevf_ring *tx_ring, int size) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + netif_stop_subqueue(netdev, tx_ring->queue_index); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (likely(IXGBE_DESC_UNUSED(tx_ring) < size)) + return -EBUSY; + + /* A reprieve! - use start_queue because it doesn't call schedule */ + netif_start_subqueue(netdev, tx_ring->queue_index); + ++adapter->restart_queue; + return 0; +} + +static int ixgbevf_maybe_stop_tx(struct net_device *netdev, + struct ixgbevf_ring *tx_ring, int size) +{ + if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size)) + return 0; + return __ixgbevf_maybe_stop_tx(netdev, tx_ring, size); +} + +static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbevf_ring *tx_ring; + unsigned int first; + unsigned int tx_flags = 0; + u8 hdr_len = 0; + int r_idx = 0, tso; + int count = 0; + + unsigned int f; + + tx_ring = &adapter->tx_ring[r_idx]; + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= vlan_tx_tag_get(skb); + tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IXGBE_TX_FLAGS_VLAN; + } + + /* four things can cause us to need a context descriptor */ + if (skb_is_gso(skb) || + (skb->ip_summed == CHECKSUM_PARTIAL) || + (tx_flags & IXGBE_TX_FLAGS_VLAN)) + count++; + + count += TXD_USE_COUNT(skb_headlen(skb)); + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); + + if (ixgbevf_maybe_stop_tx(netdev, tx_ring, count)) { + adapter->tx_busy++; + return NETDEV_TX_BUSY; + } + + first = tx_ring->next_to_use; + + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; + tso = ixgbevf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbevf_tx_csum(adapter, tx_ring, skb, tx_flags) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; + + ixgbevf_tx_queue(adapter, tx_ring, tx_flags, + ixgbevf_tx_map(adapter, tx_ring, skb, tx_flags, first), + skb->len, hdr_len); + + netdev->trans_start = jiffies; + + ixgbevf_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); + + return NETDEV_TX_OK; +} + +/** + * ixgbevf_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *ixgbevf_get_stats(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * ixgbevf_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int ixgbevf_set_mac(struct net_device *netdev, void *p) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); + + if (hw->mac.ops.set_rar) + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0); + + return 0; +} + +/** + * ixgbevf_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + /* MTU < 68 is an error and causes problems on some kernels */ + if ((new_mtu < 68) || (max_frame > MAXIMUM_ETHERNET_VLAN_SIZE)) + return -EINVAL; + + hw_dbg(&adapter->hw, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); + /* must set new MTU before calling down or up */ + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + ixgbevf_reinit_locked(adapter); + + return 0; +} + +static void ixgbevf_shutdown(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + ixgbevf_down(adapter); + ixgbevf_free_irq(adapter); + ixgbevf_free_all_tx_resources(adapter); + ixgbevf_free_all_rx_resources(adapter); + } + +#ifdef CONFIG_PM + pci_save_state(pdev); +#endif + + pci_disable_device(pdev); +} + +#ifdef HAVE_NET_DEVICE_OPS +static const struct net_device_ops ixgbe_netdev_ops = { + .ndo_open = &ixgbevf_open, + .ndo_stop = &ixgbevf_close, + .ndo_start_xmit = &ixgbevf_xmit_frame, + .ndo_get_stats = &ixgbevf_get_stats, + .ndo_set_rx_mode = &ixgbevf_set_rx_mode, + .ndo_set_multicast_list = &ixgbevf_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = &ixgbevf_set_mac, + .ndo_change_mtu = &ixgbevf_change_mtu, + .ndo_tx_timeout = &ixgbevf_tx_timeout, + .ndo_vlan_rx_register = &ixgbevf_vlan_rx_register, + .ndo_vlan_rx_add_vid = &ixgbevf_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = &ixgbevf_vlan_rx_kill_vid, +}; +#endif /* HAVE_NET_DEVICE_OPS */ + +static void ixgbevf_assign_netdev_ops(struct net_device *dev) +{ + struct ixgbevf_adapter *adapter; + adapter = netdev_priv(dev); +#ifdef HAVE_NET_DEVICE_OPS + dev->netdev_ops = &ixgbe_netdev_ops; +#else /* HAVE_NET_DEVICE_OPS */ + dev->open = &ixgbevf_open; + dev->stop = &ixgbevf_close; + + dev->hard_start_xmit = &ixgbevf_xmit_frame; + + dev->get_stats = &ixgbevf_get_stats; + dev->set_multicast_list = &ixgbevf_set_rx_mode; + dev->set_mac_address = &ixgbevf_set_mac; + dev->change_mtu = &ixgbevf_change_mtu; + dev->tx_timeout = &ixgbevf_tx_timeout; + dev->vlan_rx_register = &ixgbevf_vlan_rx_register; + dev->vlan_rx_add_vid = &ixgbevf_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = &ixgbevf_vlan_rx_kill_vid; +#endif /* HAVE_NET_DEVICE_OPS */ + ixgbevf_set_ethtool_ops(dev); + dev->watchdog_timeo = 5 * HZ; +} + +/** + * ixgbevf_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in ixgbevf_pci_tbl + * + * Returns 0 on success, negative on failure + * + * ixgbevf_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit ixgbevf_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct ixgbevf_adapter *adapter = NULL; + struct ixgbe_hw *hw = NULL; + const struct ixgbevf_info *ii = ixgbevf_info_tbl[ent->driver_data]; + static int cards_found; + int err, pci_using_dac; + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && + !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + err = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + pci_using_dac = 0; + } + + err = pci_request_regions(pdev, ixgbevf_driver_name); + if (err) { + dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); + goto err_pci_reg; + } + + pci_set_master(pdev); + +#ifdef HAVE_TX_MQ + netdev = alloc_etherdev_mq(sizeof(struct ixgbevf_adapter), + MAX_TX_QUEUES); +#else + netdev = alloc_etherdev(sizeof(struct ixgbevf_adapter)); +#endif + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + + adapter->netdev = netdev; + adapter->pdev = pdev; + hw = &adapter->hw; + hw->back = adapter; + adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + + /* + * call save state here in standalone driver because it relies on + * adapter struct to exist, and needs to call netdev_priv + */ + pci_save_state(pdev); + + hw->hw_addr = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!hw->hw_addr) { + err = -EIO; + goto err_ioremap; + } + + ixgbevf_assign_netdev_ops(netdev); + + adapter->bd_number = cards_found; + + /* Setup hw api */ + memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); + hw->mac.type = ii->mac; + + memcpy(&hw->mbx.ops, &ixgbevf_mbx_ops, + sizeof(struct ixgbe_mac_operations)); + + adapter->flags &= ~IXGBE_FLAG_RX_PS_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + adapter->flags |= IXGBE_FLAG_RX_1BUF_CAPABLE; + + /* setup the private structure */ + err = ixgbevf_sw_init(adapter); + + ixgbevf_init_last_counter_stats(adapter); + +#ifdef MAX_SKB_FRAGS + netdev->features = NETIF_F_SG | + NETIF_F_IP_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_IPV6_CSUM; + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_SG; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + +#endif /* MAX_SKB_FRAGS */ + + /* The HW MAC address was set and/or determined in sw_init */ + memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + printk(KERN_ERR "invalid MAC address\n"); + err = -EIO; + goto err_sw_init; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &ixgbevf_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + INIT_WORK(&adapter->reset_task, ixgbevf_reset_task); + INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task); + + err = ixgbevf_init_interrupt_scheme(adapter); + if (err) + goto err_sw_init; + + /* pick up the PCI bus settings for reporting later */ + if (hw->mac.ops.get_bus_info) + hw->mac.ops.get_bus_info(hw); + + + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); + + strcpy(netdev->name, "eth%d"); + + err = register_netdev(netdev); + if (err) + goto err_register; + + adapter->netdev_registered = true; + + /* print the MAC address */ + hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + netdev->dev_addr[0], + netdev->dev_addr[1], + netdev->dev_addr[2], + netdev->dev_addr[3], + netdev->dev_addr[4], + netdev->dev_addr[5]); + + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "LRO is disabled \n"); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); + cards_found++; + return 0; + +err_register: +err_sw_init: + ixgbevf_reset_interrupt_capability(adapter); + iounmap(hw->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * ixgbevf_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * ixgbevf_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit ixgbevf_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); + + cancel_work_sync(&adapter->watchdog_task); + + flush_scheduled_work(); + + if (adapter->netdev_registered) { + unregister_netdev(netdev); + adapter->netdev_registered = false; + } + + ixgbevf_reset_interrupt_capability(adapter); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); + + hw_dbg(&adapter->hw, "Remove complete\n"); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +static struct pci_driver ixgbevf_driver = { + .name = ixgbevf_driver_name, + .id_table = ixgbevf_pci_tbl, + .probe = ixgbevf_probe, + .remove = __devexit_p(ixgbevf_remove), + .shutdown = ixgbevf_shutdown, +}; + +/** + * ixgbe_init_module - Driver Registration Routine + * + * ixgbe_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init ixgbevf_init_module(void) +{ + int ret; + printk(KERN_INFO "ixgbevf: %s - version %s\n", ixgbevf_driver_string, + ixgbevf_driver_version); + + printk(KERN_INFO "%s\n", ixgbevf_copyright); + + ret = pci_register_driver(&ixgbevf_driver); + return ret; +} + +module_init(ixgbevf_init_module); + +/** + * ixgbe_exit_module - Driver Exit Cleanup Routine + * + * ixgbe_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit ixgbevf_exit_module(void) +{ + pci_unregister_driver(&ixgbevf_driver); +} + +#ifdef DEBUG +/** + * ixgbe_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw) +{ + struct ixgbevf_adapter *adapter = hw->back; + return adapter->netdev->name; +} + +#endif +module_exit(ixgbevf_exit_module); + +/* ixgbevf_main.c */ -- GitLab From 0d3592fa28965a3083d670b430bb59c19efb6abe Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:24:31 +0000 Subject: [PATCH 0481/3892] ixgbevf: Driver Makefile 82599 Virtual Function Device Driver Makefile Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/Makefile | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 drivers/net/ixgbevf/Makefile diff --git a/drivers/net/ixgbevf/Makefile b/drivers/net/ixgbevf/Makefile new file mode 100644 index 000000000000..dd4e0d27e8cc --- /dev/null +++ b/drivers/net/ixgbevf/Makefile @@ -0,0 +1,38 @@ +################################################################################ +# +# Intel 82599 Virtual Function driver +# Copyright(c) 1999 - 2009 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) 82599 VF ethernet driver +# + +obj-$(CONFIG_IXGBEVF) += ixgbevf.o + +ixgbevf-objs := vf.o \ + mbx.o \ + ethtool.o \ + ixgbevf_main.o + -- GitLab From ecc6703cbb2bb648c7345c652a704f7af56322b8 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:24:50 +0000 Subject: [PATCH 0482/3892] ixgbevf: Kconfig, Makefile and Documentation Modifications for the Kconfig and network device Makefile to add the ixgbevf driver module to the kernel plus basic driver documentation. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- Documentation/networking/ixgbevf.txt | 90 ++++++++++++++++++++++++++++ drivers/net/Kconfig | 22 +++++++ drivers/net/Makefile | 1 + 3 files changed, 113 insertions(+) create mode 100755 Documentation/networking/ixgbevf.txt diff --git a/Documentation/networking/ixgbevf.txt b/Documentation/networking/ixgbevf.txt new file mode 100755 index 000000000000..19015de6725f --- /dev/null +++ b/Documentation/networking/ixgbevf.txt @@ -0,0 +1,90 @@ +Linux* Base Driver for Intel(R) Network Connection +================================================== + +November 24, 2009 + +Contents +======== + +- In This Release +- Identifying Your Adapter +- Known Issues/Troubleshooting +- Support + +In This Release +=============== + +This file describes the ixgbevf Linux* Base Driver for Intel Network +Connection. + +The ixgbevf driver supports 82599-based virtual function devices that can only +be activated on kernels with CONFIG_PCI_IOV enabled. + +The ixgbevf driver supports virtual functions generated by the ixgbe driver +with a max_vfs value of 1 or greater. + +The guest OS loading the ixgbevf driver must support MSI-X interrupts. + +VLANs: There is a limit of a total of 32 shared VLANs to 1 or more VFs. + +Identifying Your Adapter +======================== + +For more information on how to identify your adapter, go to the Adapter & +Driver ID Guide at: + + http://support.intel.com/support/network/sb/CS-008441.htm + +Known Issues/Troubleshooting +============================ + + Unloading Physical Function (PF) Driver Causes System Reboots When VM is + Running and VF is Loaded on the VM + ------------------------------------------------------------------------ + Do not unload the PF driver (ixgbe) while VFs are assigned to guests. + +Support +======= + +For general information, go to the Intel support website at: + + http://support.intel.com + +or the Intel Wired Networking project hosted by Sourceforge at: + + http://sourceforge.net/projects/e1000 + +If an issue is identified with the released source code on the supported +kernel with a supported adapter, email the specific information related +to the issue to e1000-devel@lists.sf.net + +License +======= + +Intel 10 Gigabit Linux driver. +Copyright(c) 1999 - 2009 Intel Corporation. + +This program is free software; you can redistribute it and/or modify it +under the terms and conditions of the GNU General Public License, +version 2, as published by the Free Software Foundation. + +This program is distributed in the hope it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + +The full GNU General Public License is included in this distribution in +the file called "COPYING". + +Trademarks +========== + +Intel, Itanium, and Pentium are trademarks or registered trademarks of +Intel Corporation or its subsidiaries in the United States and other +countries. + +* Other names and brands may be claimed as the property of others. diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dd9a09c72dff..5be6a2376f4f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2618,6 +2618,28 @@ config IXGBE_DCB If unsure, say N. +config IXGBEVF + tristate "Intel(R) 82599 Virtual Function Ethernet support" + depends on PCI_MSI + ---help--- + This driver supports Intel(R) 82599 virtual functions. For more + information on how to identify your adapter, go to the Adapter & + Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module + will be called ixgbevf. MSI-X interrupt support is required + for this driver to work correctly. + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ad1346dd9da9..6746e8b8bdfc 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ obj-$(CONFIG_IGB) += igb/ obj-$(CONFIG_IGBVF) += igbvf/ obj-$(CONFIG_IXGBE) += ixgbe/ +obj-$(CONFIG_IXGBEVF) += ixgbevf/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IP1000) += ipg.o obj-$(CONFIG_CHELSIO_T1) += chelsio/ -- GitLab From 10ca132c41ecc1b55bc22667493ab75c4f6eec0d Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:25:10 +0000 Subject: [PATCH 0483/3892] ixgbe: Mailbox header and code module The 82599 virtual function device and the master 82599 physical function device implement a mailbox utility for communication between the devices using some SRAM scratch memory and a doorbell/answering mechanism enabled via interrupt and/or polling. This C module and accompanying header file implement the base functions for use of this feature. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_mbx.c | 479 ++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_mbx.h | 96 +++++++ 2 files changed, 575 insertions(+) create mode 100644 drivers/net/ixgbe/ixgbe_mbx.c create mode 100644 drivers/net/ixgbe/ixgbe_mbx.h diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c new file mode 100644 index 000000000000..d75f9148eb1f --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_mbx.c @@ -0,0 +1,479 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include "ixgbe_type.h" +#include "ixgbe_common.h" +#include "ixgbe_mbx.h" + +/** + * ixgbe_read_mbx - Reads a message from the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to read + * + * returns SUCCESS if it successfuly read message from buffer + **/ +s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + /* limit read to size of mailbox */ + if (size > mbx->size) + size = mbx->size; + + if (mbx->ops.read) + ret_val = mbx->ops.read(hw, msg, size, mbx_id); + + return ret_val; +} + +/** + * ixgbe_write_mbx - Write a message to the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully copied message into the buffer + **/ +s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = 0; + + if (size > mbx->size) + ret_val = IXGBE_ERR_MBX; + + else if (mbx->ops.write) + ret_val = mbx->ops.write(hw, msg, size, mbx_id); + + return ret_val; +} + +/** + * ixgbe_check_for_msg - checks to see if someone sent us mail + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to check + * + * returns SUCCESS if the Status bit was found or else ERR_MBX + **/ +s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + if (mbx->ops.check_for_msg) + ret_val = mbx->ops.check_for_msg(hw, mbx_id); + + return ret_val; +} + +/** + * ixgbe_check_for_ack - checks to see if someone sent us ACK + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to check + * + * returns SUCCESS if the Status bit was found or else ERR_MBX + **/ +s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + if (mbx->ops.check_for_ack) + ret_val = mbx->ops.check_for_ack(hw, mbx_id); + + return ret_val; +} + +/** + * ixgbe_check_for_rst - checks to see if other side has reset + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to check + * + * returns SUCCESS if the Status bit was found or else ERR_MBX + **/ +s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + if (mbx->ops.check_for_rst) + ret_val = mbx->ops.check_for_rst(hw, mbx_id); + + return ret_val; +} + +/** + * ixgbe_poll_for_msg - Wait for message notification + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully received a message notification + **/ +static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; + + if (!countdown || !mbx->ops.check_for_msg) + goto out; + + while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) { + countdown--; + if (!countdown) + break; + udelay(mbx->usec_delay); + } + + /* if we failed, all future posted messages fail until reset */ + if (!countdown) + mbx->timeout = 0; +out: + return countdown ? 0 : IXGBE_ERR_MBX; +} + +/** + * ixgbe_poll_for_ack - Wait for message acknowledgement + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully received a message acknowledgement + **/ +static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; + + if (!countdown || !mbx->ops.check_for_ack) + goto out; + + while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) { + countdown--; + if (!countdown) + break; + udelay(mbx->usec_delay); + } + + /* if we failed, all future posted messages fail until reset */ + if (!countdown) + mbx->timeout = 0; +out: + return countdown ? 0 : IXGBE_ERR_MBX; +} + +/** + * ixgbe_read_posted_mbx - Wait for message notification and receive message + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully received a message notification and + * copied it into the receive buffer. + **/ +s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + if (!mbx->ops.read) + goto out; + + ret_val = ixgbe_poll_for_msg(hw, mbx_id); + + /* if ack received read message, otherwise we timed out */ + if (!ret_val) + ret_val = mbx->ops.read(hw, msg, size, mbx_id); +out: + return ret_val; +} + +/** + * ixgbe_write_posted_mbx - Write a message to the mailbox, wait for ack + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully copied message into the buffer and + * received an ack to that message within delay * timeout period + **/ +s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val = IXGBE_ERR_MBX; + + /* exit if either we can't write or there isn't a defined timeout */ + if (!mbx->ops.write || !mbx->timeout) + goto out; + + /* send msg */ + ret_val = mbx->ops.write(hw, msg, size, mbx_id); + + /* if msg sent wait until we receive an ack */ + if (!ret_val) + ret_val = ixgbe_poll_for_ack(hw, mbx_id); +out: + return ret_val; +} + +/** + * ixgbe_init_mbx_ops_generic - Initialize MB function pointers + * @hw: pointer to the HW structure + * + * Setup the mailbox read and write message function pointers + **/ +void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + + mbx->ops.read_posted = ixgbe_read_posted_mbx; + mbx->ops.write_posted = ixgbe_write_posted_mbx; +} + +static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) +{ + u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index)); + s32 ret_val = IXGBE_ERR_MBX; + + if (mbvficr & mask) { + ret_val = 0; + IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask); + } + + return ret_val; +} + +/** + * ixgbe_check_for_msg_pf - checks to see if the VF has sent mail + * @hw: pointer to the HW structure + * @vf_number: the VF index + * + * returns SUCCESS if the VF has set the Status bit or else ERR_MBX + **/ +static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) +{ + s32 ret_val = IXGBE_ERR_MBX; + s32 index = IXGBE_MBVFICR_INDEX(vf_number); + u32 vf_bit = vf_number % 16; + + if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit, + index)) { + ret_val = 0; + hw->mbx.stats.reqs++; + } + + return ret_val; +} + +/** + * ixgbe_check_for_ack_pf - checks to see if the VF has ACKed + * @hw: pointer to the HW structure + * @vf_number: the VF index + * + * returns SUCCESS if the VF has set the Status bit or else ERR_MBX + **/ +static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) +{ + s32 ret_val = IXGBE_ERR_MBX; + s32 index = IXGBE_MBVFICR_INDEX(vf_number); + u32 vf_bit = vf_number % 16; + + if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit, + index)) { + ret_val = 0; + hw->mbx.stats.acks++; + } + + return ret_val; +} + +/** + * ixgbe_check_for_rst_pf - checks to see if the VF has reset + * @hw: pointer to the HW structure + * @vf_number: the VF index + * + * returns SUCCESS if the VF has set the Status bit or else ERR_MBX + **/ +static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) +{ + u32 reg_offset = (vf_number < 32) ? 0 : 1; + u32 vf_shift = vf_number % 32; + u32 vflre = 0; + s32 ret_val = IXGBE_ERR_MBX; + + if (hw->mac.type == ixgbe_mac_82599EB) + vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset)); + + if (vflre & (1 << vf_shift)) { + ret_val = 0; + IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), (1 << vf_shift)); + hw->mbx.stats.rsts++; + } + + return ret_val; +} + +/** + * ixgbe_obtain_mbx_lock_pf - obtain mailbox lock + * @hw: pointer to the HW structure + * @vf_number: the VF index + * + * return SUCCESS if we obtained the mailbox lock + **/ +static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) +{ + s32 ret_val = IXGBE_ERR_MBX; + u32 p2v_mailbox; + + /* Take ownership of the buffer */ + IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_PFU); + + /* reserve mailbox for vf use */ + p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number)); + if (p2v_mailbox & IXGBE_PFMAILBOX_PFU) + ret_val = 0; + + return ret_val; +} + +/** + * ixgbe_write_mbx_pf - Places a message in the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @vf_number: the VF index + * + * returns SUCCESS if it successfully copied message into the buffer + **/ +static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 vf_number) +{ + s32 ret_val; + u16 i; + + /* lock the mailbox to prevent pf/vf race condition */ + ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); + if (ret_val) + goto out_no_write; + + /* flush msg and acks as we are overwriting the message buffer */ + ixgbe_check_for_msg_pf(hw, vf_number); + ixgbe_check_for_ack_pf(hw, vf_number); + + /* copy the caller specified message to the mailbox memory buffer */ + for (i = 0; i < size; i++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i, msg[i]); + + /* Interrupt VF to tell it a message has been sent and release buffer*/ + IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_STS); + + /* update stats */ + hw->mbx.stats.msgs_tx++; + +out_no_write: + return ret_val; + +} + +/** + * ixgbe_read_mbx_pf - Read a message from the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @vf_number: the VF index + * + * This function copies a message from the mailbox buffer to the caller's + * memory buffer. The presumption is that the caller knows that there was + * a message due to a VF request so no polling for message is needed. + **/ +static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 vf_number) +{ + s32 ret_val; + u16 i; + + /* lock the mailbox to prevent pf/vf race condition */ + ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); + if (ret_val) + goto out_no_read; + + /* copy the message to the mailbox memory buffer */ + for (i = 0; i < size; i++) + msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i); + + /* Acknowledge the message and release buffer */ + IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_ACK); + + /* update stats */ + hw->mbx.stats.msgs_rx++; + +out_no_read: + return ret_val; +} + +/** + * ixgbe_init_mbx_params_pf - set initial values for pf mailbox + * @hw: pointer to the HW structure + * + * Initializes the hw->mbx struct to correct values for pf mailbox + */ +void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + + if (hw->mac.type != ixgbe_mac_82599EB) + return; + + mbx->timeout = 0; + mbx->usec_delay = 0; + + mbx->size = IXGBE_VFMAILBOX_SIZE; + + mbx->stats.msgs_tx = 0; + mbx->stats.msgs_rx = 0; + mbx->stats.reqs = 0; + mbx->stats.acks = 0; + mbx->stats.rsts = 0; +} + +struct ixgbe_mbx_operations mbx_ops_82599 = { + .read = ixgbe_read_mbx_pf, + .write = ixgbe_write_mbx_pf, + .read_posted = ixgbe_read_posted_mbx, + .write_posted = ixgbe_write_posted_mbx, + .check_for_msg = ixgbe_check_for_msg_pf, + .check_for_ack = ixgbe_check_for_ack_pf, + .check_for_rst = ixgbe_check_for_rst_pf, +}; + diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h new file mode 100644 index 000000000000..be7ab3309ab7 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_mbx.h @@ -0,0 +1,96 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_MBX_H_ +#define _IXGBE_MBX_H_ + +#include "ixgbe_type.h" + +#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */ +#define IXGBE_ERR_MBX -100 + +#define IXGBE_VFMAILBOX 0x002FC +#define IXGBE_VFMBMEM 0x00200 + +#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x)) +#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn)) + +#define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */ +#define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */ +#define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */ +#define IXGBE_PFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */ +#define IXGBE_PFMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */ + +#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */ +#define IXGBE_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */ +#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */ +#define IXGBE_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */ + + +/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the + * PF. The reverse is true if it is IXGBE_PF_*. + * Message ACK's are the value or'd with 0xF0000000 + */ +#define IXGBE_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with + * this are the ACK */ +#define IXGBE_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with + * this are the NACK */ +#define IXGBE_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still + clear to send requests */ +#define IXGBE_VT_MSGINFO_SHIFT 16 +/* bits 23:16 are used for exra info for certain messages */ +#define IXGBE_VT_MSGINFO_MASK (0xFF << IXGBE_VT_MSGINFO_SHIFT) + +#define IXGBE_VF_RESET 0x01 /* VF requests reset */ +#define IXGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */ +#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ +#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ +#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ + +/* length of permanent address message returned from PF */ +#define IXGBE_VF_PERMADDR_MSG_LEN 4 +/* word in permanent address message with the current multicast type */ +#define IXGBE_VF_MC_TYPE_WORD 3 + +#define IXGBE_PF_CONTROL_MSG 0x0100 /* PF control message */ + +#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ +#define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */ + +s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16); +s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); +s32 ixgbe_read_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16); +s32 ixgbe_write_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16); +s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16); +s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16); +s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16); +void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw); +void ixgbe_init_mbx_params_pf(struct ixgbe_hw *); + +extern struct ixgbe_mbx_operations mbx_ops_82599; + +#endif /* _IXGBE_MBX_H_ */ -- GitLab From 7f870475c8f102469df44a86387a03cb23e79b90 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:25:29 +0000 Subject: [PATCH 0484/3892] ixgbe: Add SR-IOV register, structure and bit defines This patch adds register definitions, bit definitions and structures used by the driver to support SR-IOV features of the 82599 controller. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 31 ++++++++++++++++++-- drivers/net/ixgbe/ixgbe_main.c | 2 +- drivers/net/ixgbe/ixgbe_type.h | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 8da8eb535084..ed735857695c 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -98,6 +98,23 @@ #define IXGBE_MAX_RSC_INT_RATE 162760 +#define IXGBE_MAX_VF_MC_ENTRIES 30 +#define IXGBE_MAX_VF_FUNCTIONS 64 +#define IXGBE_MAX_VFTA_ENTRIES 128 +#define MAX_EMULATION_MAC_ADDRS 16 +#define VMDQ_P(p) ((p) + adapter->num_vfs) + +struct vf_data_storage { + unsigned char vf_mac_addresses[ETH_ALEN]; + u16 vf_mc_hashes[IXGBE_MAX_VF_MC_ENTRIES]; + u16 num_vf_mc_hashes; + u16 default_vf_vlan_id; + u16 vlans_enabled; + unsigned char em_mac_addresses[MAX_EMULATION_MAC_ADDRS * ETH_ALEN]; + bool clear_to_send; + int rar; +}; + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbe_tx_buffer { @@ -171,7 +188,7 @@ struct ixgbe_ring { enum ixgbe_ring_f_enum { RING_F_NONE = 0, RING_F_DCB, - RING_F_VMDQ, + RING_F_VMDQ, /* SR-IOV uses the same ring feature */ RING_F_RSS, RING_F_FDIR, #ifdef IXGBE_FCOE @@ -183,7 +200,7 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 -#define IXGBE_MAX_VMDQ_INDICES 16 +#define IXGBE_MAX_VMDQ_INDICES 64 #define IXGBE_MAX_FDIR_INDICES 64 #ifdef IXGBE_FCOE #define IXGBE_MAX_FCOE_INDICES 8 @@ -288,6 +305,8 @@ struct ixgbe_adapter { /* RX */ struct ixgbe_ring *rx_ring ____cacheline_aligned_in_smp; /* One per active queue */ int num_rx_queues; + int num_rx_pools; /* == num_rx_queues in 82598 */ + int num_rx_queues_per_pool; /* 1 if 82598, can be many if 82599 */ u64 hw_csum_rx_error; u64 hw_rx_no_dma_resources; u64 non_eop_descs; @@ -330,6 +349,8 @@ struct ixgbe_adapter { #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) #define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 28) #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) +#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 30) +#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 31) u32 flags2; #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) @@ -379,6 +400,11 @@ struct ixgbe_adapter { u64 rsc_total_flush; u32 wol; u16 eeprom_version; + + /* SR-IOV */ + DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS); + unsigned int num_vfs; + struct vf_data_storage *vfinfo; }; enum ixbge_state_t { @@ -440,6 +466,7 @@ extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte); extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type); +extern void ixgbe_set_rx_mode(struct net_device *netdev); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b2f11d45e225..233c3917427e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2409,7 +2409,7 @@ static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq) * responsible for configuring the hardware for proper unicast, multicast and * promiscuous mode. **/ -static void ixgbe_set_rx_mode(struct net_device *netdev) +void ixgbe_set_rx_mode(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 84650c6ebe03..ec8ad182e2f5 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -277,6 +277,7 @@ #define IXGBE_DTXCTL 0x07E00 #define IXGBE_DMATXCTL 0x04A80 +#define IXGBE_PFDTXGSWC 0x08220 #define IXGBE_DTXMXSZRQ 0x08100 #define IXGBE_DTXTCPFLGL 0x04A88 #define IXGBE_DTXTCPFLGH 0x04A8C @@ -287,6 +288,8 @@ #define IXGBE_DMATXCTL_NS 0x2 /* No Snoop LSO hdr buffer */ #define IXGBE_DMATXCTL_GDV 0x8 /* Global Double VLAN */ #define IXGBE_DMATXCTL_VT_SHIFT 16 /* VLAN EtherType */ + +#define IXGBE_PFDTXGSWC_VT_LBEN 0x1 /* Local L2 VT switch enable */ #define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ /* Tx DCA Control register : 128 of these (0-127) */ #define IXGBE_DCA_TXCTRL_82599(_i) (0x0600C + ((_i) * 0x40)) @@ -497,6 +500,7 @@ /* DCB registers */ #define IXGBE_RTRPCS 0x02430 #define IXGBE_RTTDCS 0x04900 +#define IXGBE_RTTDCS_ARBDIS 0x00000040 /* DCB arbiter disable */ #define IXGBE_RTTPCS 0x0CD00 #define IXGBE_RTRUP2TC 0x03020 #define IXGBE_RTTUP2TC 0x0C800 @@ -730,6 +734,13 @@ #define IXGBE_GCR_CMPL_TMOUT_RESEND 0x00010000 #define IXGBE_GCR_CAP_VER2 0x00040000 +#define IXGBE_GCR_EXT_MSIX_EN 0x80000000 +#define IXGBE_GCR_EXT_VT_MODE_16 0x00000001 +#define IXGBE_GCR_EXT_VT_MODE_32 0x00000002 +#define IXGBE_GCR_EXT_VT_MODE_64 0x00000003 +#define IXGBE_GCR_EXT_SRIOV (IXGBE_GCR_EXT_MSIX_EN | \ + IXGBE_GCR_EXT_VT_MODE_64) + /* Time Sync Registers */ #define IXGBE_TSYNCRXCTL 0x05188 /* Rx Time Sync Control register - RW */ #define IXGBE_TSYNCTXCTL 0x08C00 /* Tx Time Sync Control register - RW */ @@ -1065,6 +1076,8 @@ /* VFRE bitmask */ #define IXGBE_VFRE_ENABLE_ALL 0xFFFFFFFF +#define IXGBE_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */ + /* RDHMPN and TDHMPN bitmasks */ #define IXGBE_RDHMPN_RDICADDR 0x007FF800 #define IXGBE_RDHMPN_RDICRDREQ 0x00800000 @@ -1295,6 +1308,7 @@ /* VLAN pool filtering masks */ #define IXGBE_VLVF_VIEN 0x80000000 /* filter is valid */ #define IXGBE_VLVF_ENTRIES 64 +#define IXGBE_VLVF_VLANID_MASK 0x00000FFF #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ @@ -1843,6 +1857,12 @@ #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT +/* SR-IOV specific macros */ +#define IXGBE_MBVFICR_INDEX(vf_number) (vf_number >> 4) +#define IXGBE_MBVFICR(_i) (0x00710 + (_i * 4)) +#define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600)) +#define IXGBE_VFLREC(_i) (0x00700 + (_i * 4)) + /* Little Endian defines */ #ifndef __le32 #define __le32 u32 @@ -2463,6 +2483,37 @@ struct ixgbe_phy_info { bool multispeed_fiber; }; +#include "ixgbe_mbx.h" + +struct ixgbe_mbx_operations { + s32 (*init_params)(struct ixgbe_hw *hw); + s32 (*read)(struct ixgbe_hw *, u32 *, u16, u16); + s32 (*write)(struct ixgbe_hw *, u32 *, u16, u16); + s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16); + s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16); + s32 (*check_for_msg)(struct ixgbe_hw *, u16); + s32 (*check_for_ack)(struct ixgbe_hw *, u16); + s32 (*check_for_rst)(struct ixgbe_hw *, u16); +}; + +struct ixgbe_mbx_stats { + u32 msgs_tx; + u32 msgs_rx; + + u32 acks; + u32 reqs; + u32 rsts; +}; + +struct ixgbe_mbx_info { + struct ixgbe_mbx_operations ops; + struct ixgbe_mbx_stats stats; + u32 timeout; + u32 usec_delay; + u32 v2p_mailbox; + u16 size; +}; + struct ixgbe_hw { u8 __iomem *hw_addr; void *back; @@ -2472,6 +2523,7 @@ struct ixgbe_hw { struct ixgbe_phy_info phy; struct ixgbe_eeprom_info eeprom; struct ixgbe_bus_info bus; + struct ixgbe_mbx_info mbx; u16 device_id; u16 vendor_id; u16 subsystem_device_id; @@ -2486,6 +2538,7 @@ struct ixgbe_info { struct ixgbe_mac_operations *mac_ops; struct ixgbe_eeprom_operations *eeprom_ops; struct ixgbe_phy_operations *phy_ops; + struct ixgbe_mbx_operations *mbx_ops; }; -- GitLab From 17367270b1d7f529f5d72e8f2cf76672829eb335 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:25:48 +0000 Subject: [PATCH 0485/3892] ixgbe: Add SR-IOV specific features This module and header file add functions to support SR-IOV features of the 82599 10Gbe controller. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_sriov.c | 336 ++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_sriov.h | 45 +++++ 2 files changed, 381 insertions(+) create mode 100644 drivers/net/ixgbe/ixgbe_sriov.c create mode 100644 drivers/net/ixgbe/ixgbe_sriov.h diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c new file mode 100644 index 000000000000..74bca74d57c1 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -0,0 +1,336 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NETIF_F_HW_VLAN_TX +#include +#endif + +#include "ixgbe.h" + +#include "ixgbe_sriov.h" + +int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, + int entries, u16 *hash_list, u32 vf) +{ + struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; + int i; + + /* only so many hash values supported */ + entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES); + + /* + * salt away the number of multi cast addresses assigned + * to this VF for later use to restore when the PF multi cast + * list changes + */ + vfinfo->num_vf_mc_hashes = entries; + + /* + * VFs are limited to using the MTA hash table for their multicast + * addresses + */ + for (i = 0; i < entries; i++) { + vfinfo->vf_mc_hashes[i] = hash_list[i];; + } + + /* Flush and reset the mta with the new values */ + ixgbe_set_rx_mode(adapter->netdev); + + return 0; +} + +void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct vf_data_storage *vfinfo; + int i, j; + u32 vector_bit; + u32 vector_reg; + u32 mta_reg; + + for (i = 0; i < adapter->num_vfs; i++) { + vfinfo = &adapter->vfinfo[i]; + for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) { + hw->addr_ctrl.mta_in_use++; + vector_reg = (vfinfo->vf_mc_hashes[j] >> 5) & 0x7F; + vector_bit = vfinfo->vf_mc_hashes[j] & 0x1F; + mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg)); + mta_reg |= (1 << vector_bit); + IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); + } + } +} + +int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf) +{ + u32 ctrl; + + /* Check if global VLAN already set, if not set it */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); + if (!(ctrl & IXGBE_VLNCTRL_VFE)) { + /* enable VLAN tag insert/strip */ + ctrl |= IXGBE_VLNCTRL_VFE; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); + } + + return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add); +} + + +void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf) +{ + u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf)); + vmolr |= (IXGBE_VMOLR_AUPE | + IXGBE_VMOLR_ROMPE | + IXGBE_VMOLR_ROPE | + IXGBE_VMOLR_BAM); + IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr); +} + +inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) +{ + struct ixgbe_hw *hw = &adapter->hw; + + /* reset offloads to defaults */ + ixgbe_set_vmolr(hw, vf); + + + /* reset multicast table array for vf */ + adapter->vfinfo[vf].num_vf_mc_hashes = 0; + + /* Flush and reset the mta with the new values */ + ixgbe_set_rx_mode(adapter->netdev); + + if (adapter->vfinfo[vf].rar > 0) { + adapter->hw.mac.ops.clear_rar(&adapter->hw, + adapter->vfinfo[vf].rar); + adapter->vfinfo[vf].rar = -1; + } +} + +int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, + int vf, unsigned char *mac_addr) +{ + struct ixgbe_hw *hw = &adapter->hw; + + adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr, + vf, IXGBE_RAH_AV); + if (adapter->vfinfo[vf].rar < 0) { + DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf); + return -1; + } + + memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6); + + return 0; +} + +int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) +{ + unsigned char vf_mac_addr[6]; + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + unsigned int vfn = (event_mask & 0x3f); + + bool enable = ((event_mask & 0x10000000U) != 0); + + if (enable) { + random_ether_addr(vf_mac_addr); + DPRINTK(PROBE, INFO, "IOV: VF %d is enabled " + "mac %02X:%02X:%02X:%02X:%02X:%02X\n", + vfn, + vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2], + vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]); + /* + * Store away the VF "permananet" MAC address, it will ask + * for it later. + */ + memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6); + } + + return 0; +} + +inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reg; + u32 reg_offset, vf_shift; + + vf_shift = vf % 32; + reg_offset = vf / 32; + + /* enable transmit and receive for vf */ + reg = IXGBE_READ_REG(hw, IXGBE_VFTE(reg_offset)); + reg |= (reg | (1 << vf_shift)); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg); + + reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset)); + reg |= (reg | (1 << vf_shift)); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg); + + ixgbe_vf_reset_event(adapter, vf); +} + +static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) +{ + u32 mbx_size = IXGBE_VFMAILBOX_SIZE; + u32 msgbuf[mbx_size]; + struct ixgbe_hw *hw = &adapter->hw; + s32 retval; + int entries; + u16 *hash_list; + int add, vid; + + retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf); + + if (retval) + printk(KERN_ERR "Error receiving message from VF\n"); + + /* this is a message we already processed, do nothing */ + if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK)) + return retval; + + /* + * until the vf completes a virtual function reset it should not be + * allowed to start any configuration. + */ + + if (msgbuf[0] == IXGBE_VF_RESET) { + unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses; + u8 *addr = (u8 *)(&msgbuf[1]); + DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf); + adapter->vfinfo[vf].clear_to_send = false; + ixgbe_vf_reset_msg(adapter, vf); + adapter->vfinfo[vf].clear_to_send = true; + + /* reply to reset with ack and vf mac address */ + msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK; + memcpy(addr, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS); + /* + * Piggyback the multicast filter type so VF can compute the + * correct vectors + */ + msgbuf[3] = hw->mac.mc_filter_type; + ixgbe_write_mbx(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN, vf); + + return retval; + } + + if (!adapter->vfinfo[vf].clear_to_send) { + msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK; + ixgbe_write_mbx(hw, msgbuf, 1, vf); + return retval; + } + + switch ((msgbuf[0] & 0xFFFF)) { + case IXGBE_VF_SET_MAC_ADDR: + { + u8 *new_mac = ((u8 *)(&msgbuf[1])); + if (is_valid_ether_addr(new_mac)) + ixgbe_set_vf_mac(adapter, vf, new_mac); + else + retval = -1; + } + break; + case IXGBE_VF_SET_MULTICAST: + entries = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) + >> IXGBE_VT_MSGINFO_SHIFT; + hash_list = (u16 *)&msgbuf[1]; + retval = ixgbe_set_vf_multicasts(adapter, entries, + hash_list, vf); + break; + case IXGBE_VF_SET_LPE: + WARN_ON((msgbuf[0] & 0xFFFF) == IXGBE_VF_SET_LPE); + break; + case IXGBE_VF_SET_VLAN: + add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) + >> IXGBE_VT_MSGINFO_SHIFT; + vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK); + retval = ixgbe_set_vf_vlan(adapter, add, vid, vf); + break; + default: + DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]); + retval = IXGBE_ERR_MBX; + break; + } + + /* notify the VF of the results of what it sent us */ + if (retval) + msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK; + else + msgbuf[0] |= IXGBE_VT_MSGTYPE_ACK; + + msgbuf[0] |= IXGBE_VT_MSGTYPE_CTS; + + ixgbe_write_mbx(hw, msgbuf, 1, vf); + + return retval; +} + +static void ixgbe_rcv_ack_from_vf(struct ixgbe_adapter *adapter, u32 vf) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 msg = IXGBE_VT_MSGTYPE_NACK; + + /* if device isn't clear to send it shouldn't be reading either */ + if (!adapter->vfinfo[vf].clear_to_send) + ixgbe_write_mbx(hw, &msg, 1, vf); +} + +void ixgbe_msg_task(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 vf; + + for (vf = 0; vf < adapter->num_vfs; vf++) { + /* process any reset requests */ + if (!ixgbe_check_for_rst(hw, vf)) + ixgbe_vf_reset_event(adapter, vf); + + /* process any messages pending */ + if (!ixgbe_check_for_msg(hw, vf)) + ixgbe_rcv_msg_from_vf(adapter, vf); + + /* process any acks */ + if (!ixgbe_check_for_ack(hw, vf)) + ixgbe_rcv_ack_from_vf(adapter, vf); + } +} + diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ixgbe/ixgbe_sriov.h new file mode 100644 index 000000000000..664b237eacb9 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_sriov.h @@ -0,0 +1,45 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_SRIOV_H_ +#define _IXGBE_SRIOV_H_ + +int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, + int entries, u16 *hash_list, u32 vf); +void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter); +int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf); +void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf); +void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf); +void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf); +void ixgbe_msg_task(struct ixgbe_adapter *adapter); +int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, + int vf, unsigned char *mac_addr); +int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask); +void ixgbe_dump_registers(struct ixgbe_adapter *adapter); + +#endif /* _IXGBE_SRIOV_H_ */ + -- GitLab From 92ed72d536445334829af65c63516557fd50f554 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:26:07 +0000 Subject: [PATCH 0486/3892] ixgbe: Add SR-IOV specific modules to driver Makefile Add the mailbox and SR-IOV feature modules to the ixgbe driver Makefile. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile index 21b41f42b61c..1dd867df2967 100644 --- a/drivers/net/ixgbe/Makefile +++ b/drivers/net/ixgbe/Makefile @@ -33,7 +33,8 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ - ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o + ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ + ixgbe_mbx.o ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o -- GitLab From 096a58fdec72335d9cbee94bd10b312c5f14f8af Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:26:26 +0000 Subject: [PATCH 0487/3892] ixgbe: Add SR-IOV feature enablement code Adds code to the core 82599 module to support SR-IOV features of the 82599 network controller Signed-off-by: Greg Rose Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82599.c | 126 +++++++++++++++++--------------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 538340527aa6..9ec296cf4c40 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -31,6 +31,7 @@ #include "ixgbe.h" #include "ixgbe_phy.h" +#include "ixgbe_mbx.h" #define IXGBE_82599_MAX_TX_QUEUES 128 #define IXGBE_82599_MAX_RX_QUEUES 128 @@ -951,8 +952,6 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) msleep(50); - - /* * Store the original AUTOC/AUTOC2 values if they have not been * stored off yet. Otherwise restore the stored original @@ -1095,9 +1094,11 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on) { u32 regindex; + u32 vlvf_index; u32 bitindex; u32 bits; u32 first_empty_slot; + u32 vt_ctl; if (vlan > 4095) return IXGBE_ERR_PARAM; @@ -1124,76 +1125,84 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, /* Part 2 - * If the vind is set + * If VT mode is set * Either vlan_on * make sure the vlan is in VLVF * set the vind bit in the matching VLVFB * Or !vlan_on * clear the pool bit and possibly the vind */ - if (vind) { - /* find the vlanid or the first empty slot */ - first_empty_slot = 0; - - for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) { - bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex)); - if (!bits && !first_empty_slot) - first_empty_slot = regindex; - else if ((bits & 0x0FFF) == vlan) - break; - } + vt_ctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); + if (!(vt_ctl & IXGBE_VT_CTL_VT_ENABLE)) + goto out; - if (regindex >= IXGBE_VLVF_ENTRIES) { - if (first_empty_slot) - regindex = first_empty_slot; - else { - hw_dbg(hw, "No space in VLVF.\n"); - goto out; - } + /* find the vlanid or the first empty slot */ + first_empty_slot = 0; + + for (vlvf_index = 1; vlvf_index < IXGBE_VLVF_ENTRIES; vlvf_index++) { + bits = IXGBE_READ_REG(hw, IXGBE_VLVF(vlvf_index)); + if (!bits && !first_empty_slot) + first_empty_slot = vlvf_index; + else if ((bits & 0x0FFF) == vlan) + break; + } + + if (vlvf_index >= IXGBE_VLVF_ENTRIES) { + if (first_empty_slot) + vlvf_index = first_empty_slot; + else { + hw_dbg(hw, "No space in VLVF.\n"); + goto out; } + } - if (vlan_on) { - /* set the pool bit */ - if (vind < 32) { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex * 2)); - bits |= (1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(regindex * 2), bits); - } else { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex * 2) + 1)); - bits |= (1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((regindex * 2) + 1), bits); - } + if (vlan_on) { + /* set the pool bit */ + if (vind < 32) { + bits = IXGBE_READ_REG(hw, + IXGBE_VLVFB(vlvf_index * 2)); + bits |= (1 << vind); + IXGBE_WRITE_REG(hw, + IXGBE_VLVFB(vlvf_index * 2), bits); } else { - /* clear the pool bit */ - if (vind < 32) { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex * 2)); + bits = IXGBE_READ_REG(hw, + IXGBE_VLVFB((vlvf_index * 2) + 1)); + bits |= (1 << (vind - 32)); + IXGBE_WRITE_REG(hw, + IXGBE_VLVFB((vlvf_index * 2) + 1), bits); + } + } else { + /* clear the pool bit */ + if (vind < 32) { + bits = IXGBE_READ_REG(hw, + IXGBE_VLVFB(vlvf_index * 2)); bits &= ~(1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(regindex * 2), bits); - bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex * 2) + 1)); - } else { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex * 2) + 1)); - bits &= ~(1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((regindex * 2) + 1), bits); - bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex * 2)); - } + IXGBE_WRITE_REG(hw, + IXGBE_VLVFB(vlvf_index * 2), bits); + bits |= IXGBE_READ_REG(hw, + IXGBE_VLVFB((vlvf_index * 2) + 1)); + } else { + bits = IXGBE_READ_REG(hw, + IXGBE_VLVFB((vlvf_index * 2) + 1)); + bits &= ~(1 << (vind - 32)); + IXGBE_WRITE_REG(hw, + IXGBE_VLVFB((vlvf_index * 2) + 1), bits); + bits |= IXGBE_READ_REG(hw, + IXGBE_VLVFB(vlvf_index * 2)); } + } - if (bits) - IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), - (IXGBE_VLVF_VIEN | vlan)); - else - IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), 0); + if (bits) { + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), + (IXGBE_VLVF_VIEN | vlan)); + /* if bits is non-zero then some pools/VFs are still + * using this VLAN ID. Force the VFTA entry to on */ + bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); + bits |= (1 << bitindex); + IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits); } + else + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0); out: return 0; @@ -2655,4 +2664,5 @@ struct ixgbe_info ixgbe_82599_info = { .mac_ops = &mac_ops_82599, .eeprom_ops = &eeprom_ops_82599, .phy_ops = &phy_ops_82599, + .mbx_ops = &mbx_ops_82599, }; -- GitLab From 1cdd1ec8784399eef55a60887a45f3f46a1c240a Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:26:46 +0000 Subject: [PATCH 0488/3892] ixgbe: Add SR-IOV features to main module Adds SR-IOV features supported by the 82599 controller to the main driver module. If the CONFIG_PCI_IOV kernel option is selected then the SR-IOV features are enabled. Use the max_vfs module option to allocate up to 63 virtual functions per physical port. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 278 +++++++++++++++++++++++++++++++-- 1 file changed, 268 insertions(+), 10 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 233c3917427e..a938dba7bdfe 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -45,6 +45,7 @@ #include "ixgbe.h" #include "ixgbe_common.h" #include "ixgbe_dcb_82599.h" +#include "ixgbe_sriov.h" char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = @@ -124,6 +125,13 @@ static struct notifier_block dca_notifier = { }; #endif +#ifdef CONFIG_PCI_IOV +static unsigned int max_vfs; +module_param(max_vfs, uint, 0); +MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate " + "per physical function"); +#endif /* CONFIG_PCI_IOV */ + MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); MODULE_LICENSE("GPL"); @@ -131,6 +139,41 @@ MODULE_VERSION(DRV_VERSION); #define DEFAULT_DEBUG_LEVEL_SHIFT 3 +static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 gcr; + u32 gpie; + u32 vmdctl; + +#ifdef CONFIG_PCI_IOV + /* disable iov and allow time for transactions to clear */ + pci_disable_sriov(adapter->pdev); +#endif + + /* turn off device IOV mode */ + gcr = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); + gcr &= ~(IXGBE_GCR_EXT_SRIOV); + IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr); + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + gpie &= ~IXGBE_GPIE_VTMODE_MASK; + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + + /* set default pool back to 0 */ + vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); + vmdctl &= ~IXGBE_VT_CTL_POOL_MASK; + IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl); + + /* take a breather then clean up driver data */ + msleep(100); + if (adapter->vfinfo) + kfree(adapter->vfinfo); + adapter->vfinfo = NULL; + + adapter->num_vfs = 0; + adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; +} + static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter) { u32 ctrl_ext; @@ -1020,7 +1063,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) /* set up to autoclear timer, and the vectors */ mask = IXGBE_EIMS_ENABLE_MASK; - mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); + if (adapter->num_vfs) + mask &= ~(IXGBE_EIMS_OTHER | + IXGBE_EIMS_MAILBOX | + IXGBE_EIMS_LSC); + else + mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask); } @@ -1249,6 +1297,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (eicr & IXGBE_EICR_LSC) ixgbe_check_lsc(adapter); + if (eicr & IXGBE_EICR_MAILBOX) + ixgbe_msg_task(adapter); + if (hw->mac.type == ixgbe_mac_82598EB) ixgbe_check_fan_failure(adapter, eicr); @@ -1763,6 +1814,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) mask |= IXGBE_EIMS_ECC; mask |= IXGBE_EIMS_GPI_SDP1; mask |= IXGBE_EIMS_GPI_SDP2; + if (adapter->num_vfs) + mask |= IXGBE_EIMS_MAILBOX; } if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) @@ -1771,6 +1824,11 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); ixgbe_irq_enable_queues(adapter, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); + + if (adapter->num_vfs > 32) { + u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, eitrsel); + } } /** @@ -1900,6 +1958,8 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); + if (adapter->num_vfs > 32) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0); } IXGBE_WRITE_FLUSH(&adapter->hw); if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -1984,18 +2044,32 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) if (hw->mac.type == ixgbe_mac_82599EB) { u32 rttdcs; + u32 mask; /* disable the arbiter while setting MTQC */ rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); rttdcs |= IXGBE_RTTDCS_ARBDIS; IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); - /* We enable 8 traffic classes, DCB only */ - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) - IXGBE_WRITE_REG(hw, IXGBE_MTQC, (IXGBE_MTQC_RT_ENA | - IXGBE_MTQC_8TC_8TQ)); - else + /* set transmit pool layout */ + mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED); + switch (adapter->flags & mask) { + + case (IXGBE_FLAG_SRIOV_ENABLED): + IXGBE_WRITE_REG(hw, IXGBE_MTQC, + (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF)); + break; + + case (IXGBE_FLAG_DCB_ENABLED): + /* We enable 8 traffic classes, DCB only */ + IXGBE_WRITE_REG(hw, IXGBE_MTQC, + (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ)); + break; + + default: IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); + break; + } /* re-eable the arbiter */ rttdcs &= ~IXGBE_RTTDCS_ARBDIS; @@ -2054,12 +2128,16 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) #ifdef CONFIG_IXGBE_DCB | IXGBE_FLAG_DCB_ENABLED #endif + | IXGBE_FLAG_SRIOV_ENABLED ); switch (mask) { case (IXGBE_FLAG_RSS_ENABLED): mrqc = IXGBE_MRQC_RSSEN; break; + case (IXGBE_FLAG_SRIOV_ENABLED): + mrqc = IXGBE_MRQC_VMDQEN; + break; #ifdef CONFIG_IXGBE_DCB case (IXGBE_FLAG_DCB_ENABLED): mrqc = IXGBE_MRQC_RT8TCEN; @@ -2140,7 +2218,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) int rx_buf_len; /* Decide whether to use packet split mode or not */ - adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + /* Do not use packet split if we're in SR-IOV Mode */ + if (!adapter->num_vfs) + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; /* Set the RX buffer length according to the mode */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { @@ -2152,7 +2232,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR | IXGBE_PSRTYPE_L2HDR; - IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); + IXGBE_WRITE_REG(hw, + IXGBE_PSRTYPE(adapter->num_vfs), + psrtype); } } else { if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) && @@ -2238,6 +2320,30 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); } + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + u32 vt_reg_bits; + u32 reg_offset, vf_shift; + u32 vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); + vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN + | IXGBE_VT_CTL_REPLEN; + vt_reg_bits |= (adapter->num_vfs << + IXGBE_VT_CTL_POOL_SHIFT); + IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits); + IXGBE_WRITE_REG(hw, IXGBE_MRQC, 0); + + vf_shift = adapter->num_vfs % 32; + reg_offset = adapter->num_vfs / 32; + IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0); + /* Enable only the PF's pool for Tx/Rx */ + IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift)); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift)); + IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); + ixgbe_set_vmolr(hw, adapter->num_vfs); + } + /* Program MRQC for the distribution of queues */ mrqc = ixgbe_setup_mrqc(adapter); @@ -2269,6 +2375,20 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) } IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); + if (adapter->num_vfs) { + u32 reg; + + /* Map PF MAC address in RAR Entry 0 to first pool + * following VFs */ + hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs); + + /* Set up VF register offsets for selected VT Mode, i.e. + * 64 VFs for SR-IOV */ + reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); + reg |= IXGBE_GCR_EXT_SRIOV; + IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, reg); + } + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); if (adapter->flags & IXGBE_FLAG_RSS_ENABLED || @@ -2449,6 +2569,8 @@ void ixgbe_set_rx_mode(struct net_device *netdev) addr_list = netdev->mc_list->dmi_addr; hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, ixgbe_addr_list_itr); + if (adapter->num_vfs) + ixgbe_restore_vf_multicasts(adapter); } static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) @@ -2709,6 +2831,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) /* MSI only */ gpie = 0; } + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + gpie &= ~IXGBE_GPIE_VTMODE_MASK; + gpie |= IXGBE_GPIE_VTMODE_64; + } /* XXX: to interrupt immediately for EICS writes, enable this */ /* gpie |= IXGBE_GPIE_EIMEN; */ IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); @@ -2783,6 +2909,18 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); txdctl |= IXGBE_TXDCTL_ENABLE; IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); + if (hw->mac.type == ixgbe_mac_82599EB) { + int wait_loop = 10; + /* poll for Tx Enable ready */ + do { + msleep(1); + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); + } while (--wait_loop && + !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + DPRINTK(DRV, ERR, "Could not enable " + "Tx Queue %d\n", j); + } } for (i = 0; i < num_rx_rings; i++) { @@ -2918,7 +3056,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) } /* reprogram the RAR[0] in case user changed it. */ - hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, + IXGBE_RAH_AV); } /** @@ -3286,6 +3425,19 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) } #endif /* IXGBE_FCOE */ +/** + * ixgbe_set_sriov_queues: Allocate queues for IOV use + * @adapter: board private structure to initialize + * + * IOV doesn't actually use anything, so just NAK the + * request for now and let the other queue routines + * figure out what to do. + */ +static inline bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter) +{ + return false; +} + /* * ixgbe_set_num_queues: Allocate queues for device, feature dependant * @adapter: board private structure to initialize @@ -3299,6 +3451,15 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) **/ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { + /* Start with base case */ + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; + adapter->num_rx_pools = adapter->num_rx_queues; + adapter->num_rx_queues_per_pool = 1; + + if (ixgbe_set_sriov_queues(adapter)) + return; + #ifdef IXGBE_FCOE if (ixgbe_set_fcoe_queues(adapter)) goto done; @@ -3569,6 +3730,24 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) } #endif /* IXGBE_FCOE */ +/** + * ixgbe_cache_ring_sriov - Descriptor ring to register mapping for sriov + * @adapter: board private structure to initialize + * + * SR-IOV doesn't use any descriptor rings but changes the default if + * no other mapping is used. + * + */ +static inline bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter) +{ + adapter->rx_ring[0].reg_idx = adapter->num_vfs * 2; + adapter->tx_ring[0].reg_idx = adapter->num_vfs * 2; + if (adapter->num_vfs) + return true; + else + return false; +} + /** * ixgbe_cache_ring_register - Descriptor ring to register mapping * @adapter: board private structure to initialize @@ -3586,6 +3765,9 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) adapter->rx_ring[0].reg_idx = 0; adapter->tx_ring[0].reg_idx = 0; + if (ixgbe_cache_ring_sriov(adapter)) + return; + #ifdef IXGBE_FCOE if (ixgbe_cache_ring_fcoe(adapter)) return; @@ -3695,6 +3877,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; adapter->atr_sample_rate = 0; + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + ixgbe_disable_sriov(adapter); + ixgbe_set_num_queues(adapter); err = pci_enable_msi(adapter->pdev); @@ -5474,7 +5659,8 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); - hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, + IXGBE_RAH_AV); return 0; } @@ -5607,6 +5793,61 @@ static const struct net_device_ops ixgbe_netdev_ops = { #endif /* IXGBE_FCOE */ }; +static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, + const struct ixgbe_info *ii) +{ +#ifdef CONFIG_PCI_IOV + struct ixgbe_hw *hw = &adapter->hw; + int err; + + if (hw->mac.type != ixgbe_mac_82599EB || !max_vfs) + return; + + /* The 82599 supports up to 64 VFs per physical function + * but this implementation limits allocation to 63 so that + * basic networking resources are still available to the + * physical function + */ + adapter->num_vfs = (max_vfs > 63) ? 63 : max_vfs; + adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED; + err = pci_enable_sriov(adapter->pdev, adapter->num_vfs); + if (err) { + DPRINTK(PROBE, ERR, + "Failed to enable PCI sriov: %d\n", err); + goto err_novfs; + } + /* If call to enable VFs succeeded then allocate memory + * for per VF control structures. + */ + adapter->vfinfo = + kcalloc(adapter->num_vfs, + sizeof(struct vf_data_storage), GFP_KERNEL); + if (adapter->vfinfo) { + /* Now that we're sure SR-IOV is enabled + * and memory allocated set up the mailbox parameters + */ + ixgbe_init_mbx_params_pf(hw); + memcpy(&hw->mbx.ops, ii->mbx_ops, + sizeof(hw->mbx.ops)); + + /* Disable RSC when in SR-IOV mode */ + adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE | + IXGBE_FLAG2_RSC_ENABLED); + return; + } + + /* Oh oh */ + DPRINTK(PROBE, ERR, + "Unable to allocate memory for VF " + "Data Storage - SRIOV disabled\n"); + pci_disable_sriov(adapter->pdev); + +err_novfs: + adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; + adapter->num_vfs = 0; +#endif /* CONFIG_PCI_IOV */ +} + /** * ixgbe_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -5781,6 +6022,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_sw_init; } + ixgbe_probe_vf(adapter, ii); + netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | @@ -5801,6 +6044,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + adapter->flags &= ~(IXGBE_FLAG_RSS_ENABLED | + IXGBE_FLAG_DCB_ENABLED); if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; @@ -5927,6 +6173,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ixgbe_setup_dca(adapter); } #endif + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n", + adapter->num_vfs); + for (i = 0; i < adapter->num_vfs; i++) + ixgbe_vf_configuration(pdev, (i | 0x10000000)); + } + /* add san mac addr to netdev */ ixgbe_add_sanmac_netdev(netdev); @@ -5939,6 +6192,8 @@ err_register: ixgbe_clear_interrupt_scheme(adapter); err_sw_init: err_eeprom: + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + ixgbe_disable_sriov(adapter); clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->sfp_timer); cancel_work_sync(&adapter->sfp_task); @@ -6007,6 +6262,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + ixgbe_disable_sriov(adapter); + ixgbe_clear_interrupt_scheme(adapter); ixgbe_release_hw_control(adapter); -- GitLab From bdbec4b86ee99b020e159f9bd604003a3ae3b0ab Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 9 Jan 2010 02:27:05 +0000 Subject: [PATCH 0489/3892] ixgbe: Fix ethtool diag test for VT mode operation Skip MAC loopback test when the adapter is set to a VT mode such as SR-IOV or VMDq Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_ethtool.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 0bd49d3b9f65..a0107b5a28e7 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1867,11 +1867,22 @@ static void ixgbe_diag_test(struct net_device *netdev, if (ixgbe_intr_test(adapter, &data[2])) eth_test->flags |= ETH_TEST_FL_FAILED; + /* If SRIOV or VMDq is enabled then skip MAC + * loopback diagnostic. */ + if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED | + IXGBE_FLAG_VMDQ_ENABLED)) { + DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT " + "mode\n"); + data[3] = 0; + goto skip_loopback; + } + ixgbe_reset(adapter); DPRINTK(HW, INFO, "loopback testing starting\n"); if (ixgbe_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; +skip_loopback: ixgbe_reset(adapter); clear_bit(__IXGBE_TESTING, &adapter->state); -- GitLab From 9cb3ce52ca45d089d5be90d2f34005296fc5a34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 23:59:05 -0800 Subject: [PATCH 0490/3892] Input: make USB device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct usb_device_id is constant in so it makes sense to mark the initialization data also constant. Signed-off-by: Márton Németh Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/gtco.c | 2 +- drivers/input/touchscreen/usbtouchscreen.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 3d32d3f4e486..866a9ee1af1a 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -92,7 +92,7 @@ Scott Hill shill@gtcocalcomp.com /* DATA STRUCTURES */ /* Device table */ -static struct usb_device_id gtco_usbid_table [] = { +static const struct usb_device_id gtco_usbid_table[] = { { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 09a5e7341bd5..b1b99e931f80 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -144,7 +144,7 @@ enum { .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE -static struct usb_device_id usbtouch_devices[] = { +static const struct usb_device_id usbtouch_devices[] = { #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX /* ignore the HID capable devices, handled by usbhid */ {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE}, -- GitLab From c8e000604bce02a87742240a9b716a0f1b680c0b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 11 Jan 2010 00:44:14 -0800 Subject: [PATCH 0491/3892] lib: Kill bit-reversed FDDI MAC output case, it's bogus. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- lib/vsprintf.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index dc48d2b32ebd..e83e3e79a989 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include /* for PAGE_SIZE */ @@ -682,19 +681,16 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; char *p = mac_addr; int i; - bool bitrev; char separator; if (fmt[1] == 'F') { /* FDDI canonical format */ - bitrev = true; separator = '-'; } else { - bitrev = false; separator = ':'; } for (i = 0; i < 6; i++) { - p = pack_hex_byte(p, bitrev ? bitrev8(addr[i]) : addr[i]); + p = pack_hex_byte(p, addr[i]); if (fmt[0] == 'M' && i != 5) *p++ = separator; } @@ -908,9 +904,7 @@ static char *uuid_string(char *buf, char *end, const u8 *addr, * usual colon-separated hex notation * - 'm' For a 6-byte MAC address, it prints the hex address without colons * - 'MF' For a 6-byte MAC FDDI address, it prints the address - * with a dash-separated hex notation with bit reversed bytes - * - 'mF' For a 6-byte MAC FDDI address, it prints the address - * in hex notation without separators with bit reversed bytes + * with a dash-separated hex notation * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) * IPv6 uses colon separated network-order 16 bit hex with leading 0's -- GitLab From c299bd53aa2616e6afc304b4f848186af3b3a881 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 11 Jan 2010 11:49:51 +0100 Subject: [PATCH 0492/3892] netfilter: nf_nat_ftp: remove (*mangle[]) array and functions, use %pI4 These functions merely exist to format a buffer and call nf_nat_mangle_tcp_packet. Format the buffer and perform the call in nf_nat_ftp instead. Use %pI4 for the IP address. Saves ~600 bytes of text old: $ size net/ipv4/netfilter/nf_nat_ftp.o text data bss dec hex filename 2187 160 408 2755 ac3 net/ipv4/netfilter/nf_nat_ftp.o new: $ size net/ipv4/netfilter/nf_nat_ftp.o text data bss dec hex filename 1532 112 288 1932 78c net/ipv4/netfilter/nf_nat_ftp.o Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_ftp.c | 105 +++++++++++--------------------- 1 file changed, 35 insertions(+), 70 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c index a1d5d58a58bf..86e0e84ff0a0 100644 --- a/net/ipv4/netfilter/nf_nat_ftp.c +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -27,76 +27,29 @@ MODULE_ALIAS("ip_nat_ftp"); /* FIXME: Time out? --RR */ -static int -mangle_rfc959_packet(struct sk_buff *skb, - __be32 newip, - u_int16_t port, - unsigned int matchoff, - unsigned int matchlen, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo) +static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type, + char *buffer, size_t buflen, + __be32 addr, u16 port) { - char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; - - sprintf(buffer, "%u,%u,%u,%u,%u,%u", - NIPQUAD(newip), port>>8, port&0xFF); - - pr_debug("calling nf_nat_mangle_tcp_packet\n"); - - return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff, - matchlen, buffer, strlen(buffer)); -} - -/* |1|132.235.1.2|6275| */ -static int -mangle_eprt_packet(struct sk_buff *skb, - __be32 newip, - u_int16_t port, - unsigned int matchoff, - unsigned int matchlen, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo) -{ - char buffer[sizeof("|1|255.255.255.255|65535|")]; - - sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); - - pr_debug("calling nf_nat_mangle_tcp_packet\n"); - - return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff, - matchlen, buffer, strlen(buffer)); -} - -/* |1|132.235.1.2|6275| */ -static int -mangle_epsv_packet(struct sk_buff *skb, - __be32 newip, - u_int16_t port, - unsigned int matchoff, - unsigned int matchlen, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo) -{ - char buffer[sizeof("|||65535|")]; - - sprintf(buffer, "|||%u|", port); - - pr_debug("calling nf_nat_mangle_tcp_packet\n"); + switch (type) { + case NF_CT_FTP_PORT: + case NF_CT_FTP_PASV: + return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u", + ((unsigned char *)&addr)[0], + ((unsigned char *)&addr)[1], + ((unsigned char *)&addr)[2], + ((unsigned char *)&addr)[3], + port >> 8, + port & 0xFF); + case NF_CT_FTP_EPRT: + return snprintf(buffer, buflen, "|1|%pI4|%u|", &addr, port); + case NF_CT_FTP_EPSV: + return snprintf(buffer, buflen, "|||%u|", port); + } - return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff, - matchlen, buffer, strlen(buffer)); + return 0; } -static int (*mangle[])(struct sk_buff *, __be32, u_int16_t, - unsigned int, unsigned int, struct nf_conn *, - enum ip_conntrack_info) -= { - [NF_CT_FTP_PORT] = mangle_rfc959_packet, - [NF_CT_FTP_PASV] = mangle_rfc959_packet, - [NF_CT_FTP_EPRT] = mangle_eprt_packet, - [NF_CT_FTP_EPSV] = mangle_epsv_packet -}; - /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int nf_nat_ftp(struct sk_buff *skb, @@ -110,6 +63,8 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, u_int16_t port; int dir = CTINFO2DIR(ctinfo); struct nf_conn *ct = exp->master; + char buffer[sizeof("|1|255.255.255.255|65535|")]; + unsigned int buflen; pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); @@ -132,11 +87,21 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, if (port == 0) return NF_DROP; - if (!mangle[type](skb, newip, port, matchoff, matchlen, ct, ctinfo)) { - nf_ct_unexpect_related(exp); - return NF_DROP; - } + buflen = nf_nat_ftp_fmt_cmd(type, buffer, sizeof(buffer), newip, port); + if (!buflen) + goto out; + + pr_debug("calling nf_nat_mangle_tcp_packet\n"); + + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff, + matchlen, buffer, buflen)) + goto out; + return NF_ACCEPT; + +out: + nf_ct_unexpect_related(exp); + return NF_DROP; } static void __exit nf_nat_ftp_fini(void) -- GitLab From a79e7ac4ad77e1833e8f69e99113204d03018255 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 11 Jan 2010 11:53:31 +0100 Subject: [PATCH 0493/3892] ipvs: use standardized format in sprintf Use the same format string as net/ipv4/netfilter/nf_nat_ftp.c to encode an ipv4 address and port. Both uses should be a single common function. Signed-off-by: Joe Perches Acked-by: Simon Horman Signed-off-by: Patrick McHardy --- net/netfilter/ipvs/ip_vs_ftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 33e2c799cba7..73f38ea98f25 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -208,7 +208,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, */ from.ip = n_cp->vaddr.ip; port = n_cp->vport; - sprintf(buf, "%d,%d,%d,%d,%d,%d", NIPQUAD(from.ip), + sprintf(buf, "%u,%u,%u,%u,%u,%u", NIPQUAD(from.ip), (ntohs(port)>>8)&255, ntohs(port)&255); buf_len = strlen(buf); -- GitLab From 7f635d0d1bf84ad7a0032cbce9d902b9384c48b7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 11 Jan 2010 11:55:36 +0100 Subject: [PATCH 0494/3892] netfilter: xt_osf: change %pi4 to %pI4 commit 8a27f7c90ffcb791eed7574922b51fb60b08fc89 changed the output style of %pi4 to use fixed width leading zero IP addresses "001.002.003.004". It's useful when printing multiple lines of addresses, but was a change in output style for some existing uses. Using %pI4 restores the previous output style. Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy --- net/netfilter/xt_osf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 4d1a41bbd5d7..4169e200588d 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -334,7 +334,7 @@ static bool xt_osf_match_packet(const struct sk_buff *skb, if (info->flags & XT_OSF_LOG) nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL, - "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n", + "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n", f->genre, f->version, f->subtype, &ip->saddr, ntohs(tcp->source), &ip->daddr, ntohs(tcp->dest), @@ -349,7 +349,7 @@ static bool xt_osf_match_packet(const struct sk_buff *skb, if (!fcount && (info->flags & XT_OSF_LOG)) nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL, - "Remote OS is not known: %pi4:%u -> %pi4:%u\n", + "Remote OS is not known: %pI4:%u -> %pI4:%u\n", &ip->saddr, ntohs(tcp->source), &ip->daddr, ntohs(tcp->dest)); -- GitLab From e03a72e13648ac6277bf2bab6b8324d51f89c0fa Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 11 Jan 2010 03:21:51 -0500 Subject: [PATCH 0495/3892] block: Stop using byte offsets All callers of the stacking functions use 512-byte sector units rather than byte offsets. Simplify the code so the stacking functions take sectors when specifying data offsets. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe --- block/blk-settings.c | 26 +++++++++----------------- fs/partitions/check.c | 7 ++++--- include/linux/blkdev.h | 17 +++++------------ 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index 5eeb9e0d256e..78549c723783 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -507,7 +507,7 @@ static unsigned int lcm(unsigned int a, unsigned int b) * blk_stack_limits - adjust queue_limits for stacked devices * @t: the stacking driver limits (top device) * @b: the underlying queue limits (bottom, component device) - * @offset: offset to beginning of data within component device + * @start: first data sector within component device * * Description: * This function is used by stacking drivers like MD and DM to ensure @@ -525,10 +525,9 @@ static unsigned int lcm(unsigned int a, unsigned int b) * the alignment_offset is undefined. */ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, - sector_t offset) + sector_t start) { - sector_t alignment; - unsigned int top, bottom, ret = 0; + unsigned int top, bottom, alignment, ret = 0; t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); @@ -548,7 +547,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->misaligned |= b->misaligned; - alignment = queue_limit_alignment_offset(b, offset); + alignment = queue_limit_alignment_offset(b, start); /* Bottom device has different alignment. Check that it is * compatible with the current top alignment. @@ -611,11 +610,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, /* Discard alignment and granularity */ if (b->discard_granularity) { - unsigned int granularity = b->discard_granularity; - offset &= granularity - 1; - - alignment = (granularity + b->discard_alignment - offset) - & (granularity - 1); + alignment = queue_limit_discard_alignment(b, start); if (t->discard_granularity != 0 && t->discard_alignment != alignment) { @@ -657,7 +652,7 @@ int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, start += get_start_sect(bdev); - return blk_stack_limits(t, &bq->limits, start << 9); + return blk_stack_limits(t, &bq->limits, start); } EXPORT_SYMBOL(bdev_stack_limits); @@ -668,9 +663,8 @@ EXPORT_SYMBOL(bdev_stack_limits); * @offset: offset to beginning of data within component device * * Description: - * Merges the limits for two queues. Returns 0 if alignment - * didn't change. Returns -1 if adding the bottom device caused - * misalignment. + * Merges the limits for a top level gendisk and a bottom level + * block_device. */ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, sector_t offset) @@ -678,9 +672,7 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, struct request_queue *t = disk->queue; struct request_queue *b = bdev_get_queue(bdev); - offset += get_start_sect(bdev) << 9; - - if (blk_stack_limits(&t->limits, &b->limits, offset) < 0) { + if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) { char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE]; disk_name(disk, 0, top); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 64bc8998ac9a..e8865c11777f 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -412,9 +412,10 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, pdev = part_to_dev(p); p->start_sect = start; - p->alignment_offset = queue_sector_alignment_offset(disk->queue, start); - p->discard_alignment = queue_sector_discard_alignment(disk->queue, - start); + p->alignment_offset = + queue_limit_alignment_offset(&disk->queue->limits, start); + p->discard_alignment = + queue_limit_discard_alignment(&disk->queue->limits, start); p->nr_sects = len; p->partno = partno; p->policy = get_disk_ro(disk); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5c8018977efa..ffb13ad35716 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1112,18 +1112,13 @@ static inline int queue_alignment_offset(struct request_queue *q) return q->limits.alignment_offset; } -static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t offset) +static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t sector) { unsigned int granularity = max(lim->physical_block_size, lim->io_min); + unsigned int alignment = (sector << 9) & (granularity - 1); - offset &= granularity - 1; - return (granularity + lim->alignment_offset - offset) & (granularity - 1); -} - -static inline int queue_sector_alignment_offset(struct request_queue *q, - sector_t sector) -{ - return queue_limit_alignment_offset(&q->limits, sector << 9); + return (granularity + lim->alignment_offset - alignment) + & (granularity - 1); } static inline int bdev_alignment_offset(struct block_device *bdev) @@ -1147,10 +1142,8 @@ static inline int queue_discard_alignment(struct request_queue *q) return q->limits.discard_alignment; } -static inline int queue_sector_discard_alignment(struct request_queue *q, - sector_t sector) +static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector_t sector) { - struct queue_limits *lim = &q->limits; unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1); return (lim->discard_granularity + lim->discard_alignment - alignment) -- GitLab From 3d447ec0e30043a2acd52704f5ed1da07a6f2d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 13:39:29 +0100 Subject: [PATCH 0496/3892] block: make PCI device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct pci_driver is constant in so it is worth to make the initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jens Axboe --- drivers/block/DAC960.c | 2 +- drivers/block/sx8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index ce1fa923c414..7412b5d4f5f3 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -7134,7 +7134,7 @@ static struct DAC960_privdata DAC960_P_privdata = { .MemoryWindowSize = DAC960_PD_RegisterWindowSize, }; -static struct pci_device_id DAC960_id_table[] = { +static const struct pci_device_id DAC960_id_table[] = { { .vendor = PCI_VENDOR_ID_MYLEX, .device = PCI_DEVICE_ID_MYLEX_DAC960_GEM, diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index a7c4184f4a63..7bd7b2f83116 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -409,7 +409,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static void carm_remove_one (struct pci_dev *pdev); static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo); -static struct pci_device_id carm_pci_tbl[] = { +static const struct pci_device_id carm_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, { } /* terminate list */ -- GitLab From 577cdf0cf5afa5f350fbaddf77bbacdb9f76d2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 13:39:39 +0100 Subject: [PATCH 0497/3892] block: make USB device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct usb_device_id is constant in so it is worth to make ub_usb_ids also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jens Axboe --- drivers/block/ub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index c739b203fe91..d86d1357ccef 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -393,7 +393,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum); #define ub_usb_ids usb_storage_usb_ids #else -static struct usb_device_id ub_usb_ids[] = { +static const struct usb_device_id ub_usb_ids[] = { { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, { } }; -- GitLab From 5cccfd9b3a9ca06b6245ea2c4af052b7db0105a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 13:39:46 +0100 Subject: [PATCH 0498/3892] block: make Open Firmware device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The match_table field of the struct of_device_id is constant in so it is worth to make ace_of_match also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index e5c5415eb45e..e1c95e208a66 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1227,7 +1227,7 @@ static int __devexit ace_of_remove(struct of_device *op) } /* Match table for of_platform binding */ -static struct of_device_id ace_of_match[] __devinitdata = { +static const struct of_device_id ace_of_match[] __devinitconst = { { .compatible = "xlnx,opb-sysace-1.00.b", }, { .compatible = "xlnx,opb-sysace-1.00.c", }, { .compatible = "xlnx,xps-sysace-1.00.a", }, -- GitLab From ec9c42ec793d428e99fdd219867b31932034b138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 13:39:52 +0100 Subject: [PATCH 0499/3892] block: make xenbus device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ids field of the struct xenbus_device_id is constant in so it is worth to make blkfront_ids also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jens Axboe --- drivers/block/xen-blkfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 05a31e55d278..a84702d1a35e 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1050,7 +1050,7 @@ static const struct block_device_operations xlvbd_block_fops = }; -static struct xenbus_device_id blkfront_ids[] = { +static const struct xenbus_device_id blkfront_ids[] = { { "vbd" }, { "" } }; -- GitLab From 47483e25205f1f8d79784f0f7c733941bc080ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 13:40:02 +0100 Subject: [PATCH 0500/3892] block: make virtio device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct virtio_driver is constant in so it is worth to make id_table also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jens Axboe --- drivers/block/virtio_blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 51042f0ba7e1..c17e622f85ee 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -404,7 +404,7 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) kfree(vblk); } -static struct virtio_device_id id_table[] = { +static const struct virtio_device_id id_table[] = { { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID }, { 0 }, }; -- GitLab From 2138301e1687bd4f22aa2b4df4829b6ffdae19bc Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Fri, 8 Jan 2010 17:48:31 +0200 Subject: [PATCH 0501/3892] ASoC: tpa6130a2: Support for tpa6140's regulators tpa6140a2 uses different names for the regulators. Signed-off-by: Ilkka Koskinen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- include/sound/tpa6130a2-plat.h | 6 ++++++ sound/soc/codecs/tpa6130a2.c | 22 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/sound/tpa6130a2-plat.h b/include/sound/tpa6130a2-plat.h index e8c901e749d8..e29fde6b5cbe 100644 --- a/include/sound/tpa6130a2-plat.h +++ b/include/sound/tpa6130a2-plat.h @@ -23,7 +23,13 @@ #ifndef TPA6130A2_PLAT_H #define TPA6130A2_PLAT_H +enum tpa_model { + TPA6130A2, + TPA6140A2, +}; + struct tpa6130a2_platform_data { + enum tpa_model id; int power_gpio; }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 8e98ccfab75c..8b27281e62a1 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -41,6 +41,11 @@ static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { "Vdd", }; +static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { + "HPVdd", + "AVdd", +}; + /* This struct is used to save the context */ struct tpa6130a2_data { struct mutex mutex; @@ -420,8 +425,21 @@ static int tpa6130a2_probe(struct i2c_client *client, gpio_direction_output(data->power_gpio, 0); } - for (i = 0; i < ARRAY_SIZE(data->supplies); i++) - data->supplies[i].supply = tpa6130a2_supply_names[i]; + switch (pdata->id) { + case TPA6130A2: + for (i = 0; i < ARRAY_SIZE(data->supplies); i++) + data->supplies[i].supply = tpa6130a2_supply_names[i]; + break; + case TPA6140A2: + for (i = 0; i < ARRAY_SIZE(data->supplies); i++) + data->supplies[i].supply = tpa6140a2_supply_names[i];; + break; + default: + dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", + pdata->id); + for (i = 0; i < ARRAY_SIZE(data->supplies); i++) + data->supplies[i].supply = tpa6130a2_supply_names[i]; + } ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies); -- GitLab From d218d11133d888f9745802146a50255a4781d37a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Jan 2010 16:28:01 -0800 Subject: [PATCH 0502/3892] tcp: Generalized TTL Security Mechanism This patch adds the kernel portions needed to implement RFC 5082 Generalized TTL Security Mechanism (GTSM). It is a lightweight security measure against forged packets causing DoS attacks (for BGP). This is already implemented the same way in BSD kernels. For the necessary Quagga patch http://www.gossamer-threads.com/lists/quagga/dev/17389 Description from Cisco http://www.cisco.com/en/US/docs/ios/12_3t/12_3t7/feature/guide/gt_btsh.html It does add one byte to each socket structure, but I did a little rearrangement to reuse a hole (on 64 bit), but it does grow the structure on 32 bit This should be documented on ip(4) man page and the Glibc in.h file also needs update. IPV6_MINHOPLIMIT should also be added (although BSD doesn't support that). Only TCP is supported, but could also be added to UDP, DCCP, SCTP if desired. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/in.h | 2 ++ include/net/inet_sock.h | 4 +++- net/ipv4/ip_sockglue.c | 14 +++++++++++++- net/ipv4/tcp_ipv4.c | 3 +++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/linux/in.h b/include/linux/in.h index b615649db129..583c76f9c30f 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -84,6 +84,8 @@ struct in_addr { #define IP_ORIGDSTADDR 20 #define IP_RECVORIGDSTADDR IP_ORIGDSTADDR +#define IP_MINTTL 21 + /* IP_MTU_DISCOVER values */ #define IP_PMTUDISC_DONT 0 /* Never send DF frames */ #define IP_PMTUDISC_WANT 1 /* Use per route hints */ diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index bd4c53f75ac0..83fd34437cf1 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -122,10 +122,12 @@ struct inet_sock { __be32 inet_saddr; __s16 uc_ttl; __u16 cmsg_flags; - struct ip_options *opt; __be16 inet_sport; __u16 inet_id; + + struct ip_options *opt; __u8 tos; + __u8 min_ttl; __u8 mc_ttl; __u8 pmtudisc; __u8 recverr:1, diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index cafad9baff03..644dc43a55de 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -451,7 +451,8 @@ static int do_ip_setsockopt(struct sock *sk, int level, (1<transparent = !!val; break; + case IP_MINTTL: + if (optlen < 1) + goto e_inval; + if (val < 0 || val > 255) + goto e_inval; + inet->min_ttl = val; + break; + default: err = -ENOPROTOOPT; break; @@ -1198,6 +1207,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_TRANSPARENT: val = inet->transparent; break; + case IP_MINTTL: + val = inet->min_ttl; + break; default: release_sock(sk); return -ENOPROTOOPT; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 65b8ebfd078a..382f667238ec 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1649,6 +1649,9 @@ int tcp_v4_rcv(struct sk_buff *skb) if (!sk) goto no_tcp_socket; + if (iph->ttl < inet_sk(sk)->min_ttl) + goto discard_and_relse; + process: if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait; -- GitLab From 53e6d8e0060fe2bb9b11238f8250fdfbb0589425 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 13:37:04 +0900 Subject: [PATCH 0503/3892] sh: mach-se: Convert SE7343 FPGA to dynamic IRQ allocation. This gets rid of the arbitrary set of vectors used by the SE7722 FPGA interrupt controller and switches over to a completely dynamic set. No assumptions regarding a contiguous range are made, and the platform resources themselves need to be filled in lazily. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-se/7343/irq.c | 35 ++++++++++-------- arch/sh/boards/mach-se/7343/setup.c | 16 +++++---- arch/sh/include/mach-se/mach/se7343.h | 52 ++++++++++++--------------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c index 051c29d4eae0..c60fd13608d0 100644 --- a/arch/sh/boards/mach-se/7343/irq.c +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -16,15 +16,17 @@ #include #include +unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, }; + static void disable_se7343_irq(unsigned int irq) { - unsigned int bit = irq - SE7343_FPGA_IRQ_BASE; + unsigned int bit = (unsigned int)get_irq_chip_data(irq); ctrl_outw(ctrl_inw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK); } static void enable_se7343_irq(unsigned int irq) { - unsigned int bit = irq - SE7343_FPGA_IRQ_BASE; + unsigned int bit = (unsigned int)get_irq_chip_data(irq); ctrl_outw(ctrl_inw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK); } @@ -38,18 +40,15 @@ static struct irq_chip se7343_irq_chip __read_mostly = { static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) { unsigned short intv = ctrl_inw(PA_CPLD_ST); - struct irq_desc *ext_desc; - unsigned int ext_irq = SE7343_FPGA_IRQ_BASE; + unsigned int ext_irq = 0; intv &= (1 << SE7343_FPGA_IRQ_NR) - 1; - while (intv) { - if (intv & 1) { - ext_desc = irq_desc + ext_irq; - handle_level_irq(ext_irq, ext_desc); - } - intv >>= 1; - ext_irq++; + for (; intv; intv >>= 1, ext_irq++) { + if (!(intv & 1)) + continue; + + generic_handle_irq(se7343_fpga_irq[ext_irq]); } } @@ -58,16 +57,24 @@ static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) */ void __init init_7343se_IRQ(void) { - int i; + int i, irq; ctrl_outw(0, PA_CPLD_IMSK); /* disable all irqs */ ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ - for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) - set_irq_chip_and_handler_name(SE7343_FPGA_IRQ_BASE + i, + for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) { + irq = create_irq(); + if (irq < 0) + return; + se7343_fpga_irq[i] = irq; + + set_irq_chip_and_handler_name(se7343_fpga_irq[i], &se7343_irq_chip, handle_level_irq, "level"); + set_irq_chip_data(se7343_fpga_irq[i], (void *)i); + } + set_irq_chained_handler(IRQ0_IRQ, se7343_irq_demux); set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); set_irq_chained_handler(IRQ1_IRQ, se7343_irq_demux); diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c index 4de56f35f419..292cc47d853f 100644 --- a/arch/sh/boards/mach-se/7343/setup.c +++ b/arch/sh/boards/mach-se/7343/setup.c @@ -82,7 +82,6 @@ static struct plat_serial8250_port serial_platform_data[] = { .mapbase = 0x16000000, .regshift = 1, .flags = ST16C2550C_FLAGS, - .irq = UARTA_IRQ, .uartclk = 7372800, }, [1] = { @@ -90,7 +89,6 @@ static struct plat_serial8250_port serial_platform_data[] = { .mapbase = 0x17000000, .regshift = 1, .flags = ST16C2550C_FLAGS, - .irq = UARTB_IRQ, .uartclk = 7372800, }, { }, @@ -121,7 +119,7 @@ static struct resource usb_resources[] = { .flags = IORESOURCE_MEM, }, [2] = { - .start = USB_IRQ, + /* Filled in later */ .flags = IORESOURCE_IRQ, }, }; @@ -138,8 +136,8 @@ static struct isp116x_platform_data usb_platform_data = { static struct platform_device usb_device = { .name = "isp116x-hcd", .id = -1, - .num_resources = ARRAY_SIZE(usb_resources), - .resource = usb_resources, + .num_resources = ARRAY_SIZE(usb_resources), + .resource = usb_resources, .dev = { .platform_data = &usb_platform_data, }, @@ -155,6 +153,13 @@ static struct platform_device *sh7343se_platform_devices[] __initdata = { static int __init sh7343se_devices_setup(void) { + /* Wire-up dynamic vectors */ + serial_platform_data[0].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTA]; + serial_platform_data[1].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTB]; + + usb_resources[2].start = usb_resources[2].end = + se7343_fpga_irq[SE7343_FPGA_IRQ_USB]; + return platform_add_devices(sh7343se_platform_devices, ARRAY_SIZE(sh7343se_platform_devices)); } @@ -179,6 +184,5 @@ static void __init sh7343se_setup(char **cmdline_p) static struct sh_machine_vector mv_7343se __initmv = { .mv_name = "SolutionEngine 7343", .mv_setup = sh7343se_setup, - .mv_nr_irqs = SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_NR, .mv_init_irq = init_7343se_IRQ, }; diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h index 749914b400fb..8d8170d6cc43 100644 --- a/arch/sh/include/mach-se/mach/se7343.h +++ b/arch/sh/include/mach-se/mach/se7343.h @@ -94,26 +94,26 @@ #define PORT_DRVCR 0xA4050180 -#define PORT_PADR 0xA4050120 -#define PORT_PBDR 0xA4050122 -#define PORT_PCDR 0xA4050124 -#define PORT_PDDR 0xA4050126 -#define PORT_PEDR 0xA4050128 -#define PORT_PFDR 0xA405012A -#define PORT_PGDR 0xA405012C -#define PORT_PHDR 0xA405012E -#define PORT_PJDR 0xA4050130 -#define PORT_PKDR 0xA4050132 -#define PORT_PLDR 0xA4050134 -#define PORT_PMDR 0xA4050136 -#define PORT_PNDR 0xA4050138 -#define PORT_PQDR 0xA405013A -#define PORT_PRDR 0xA405013C -#define PORT_PTDR 0xA4050160 -#define PORT_PUDR 0xA4050162 -#define PORT_PVDR 0xA4050164 -#define PORT_PWDR 0xA4050166 -#define PORT_PYDR 0xA4050168 +#define PORT_PADR 0xA4050120 +#define PORT_PBDR 0xA4050122 +#define PORT_PCDR 0xA4050124 +#define PORT_PDDR 0xA4050126 +#define PORT_PEDR 0xA4050128 +#define PORT_PFDR 0xA405012A +#define PORT_PGDR 0xA405012C +#define PORT_PHDR 0xA405012E +#define PORT_PJDR 0xA4050130 +#define PORT_PKDR 0xA4050132 +#define PORT_PLDR 0xA4050134 +#define PORT_PMDR 0xA4050136 +#define PORT_PNDR 0xA4050138 +#define PORT_PQDR 0xA405013A +#define PORT_PRDR 0xA405013C +#define PORT_PTDR 0xA4050160 +#define PORT_PUDR 0xA4050162 +#define PORT_PVDR 0xA4050164 +#define PORT_PWDR 0xA4050166 +#define PORT_PYDR 0xA4050168 #define FPGA_IN 0xb1400000 #define FPGA_OUT 0xb1400002 @@ -133,18 +133,10 @@ #define SE7343_FPGA_IRQ_UARTB 11 #define SE7343_FPGA_IRQ_NR 12 -#define SE7343_FPGA_IRQ_BASE 120 - -#define MRSHPC_IRQ3 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC3) -#define MRSHPC_IRQ2 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC2) -#define MRSHPC_IRQ1 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC1) -#define MRSHPC_IRQ0 (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC0) -#define SMC_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_SMC) -#define USB_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_USB) -#define UARTA_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTA) -#define UARTB_IRQ (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTB) /* arch/sh/boards/se/7343/irq.c */ +extern unsigned int se7343_fpga_irq[]; + void init_7343se_IRQ(void); #endif /* __ASM_SH_HITACHI_SE7343_H */ -- GitLab From ee2760ea58d81fc00bcc2137232ed9bc28202aec Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 13:48:27 +0900 Subject: [PATCH 0504/3892] sh: default to sparseirq. As SH has a very sparse IRQ map by default, all new CPUs and boards benefit from using sparseirq by default. Despite this, there are still a few stragglers (mostly due to using a fixed IRQ range for their FPGA IRQ mappings), and these still need to be converted over one by one. As these are now in the minority, and we do not want to encourage this sort of brain-damage in newer board ports, we force sparseirq on. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 2121fbb2ff4c..ae6c73689036 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -726,8 +726,9 @@ config GUSA_RB disabling interrupts around the atomic sequence. config SPARSE_IRQ - bool "Support sparse irq numbering" - depends on EXPERIMENTAL + def_bool y + depends on SUPERH32 && !SH_DREAMCAST && !SH_HIGHLANDER && \ + !SH_RTS7751R2D && !HD64461 && !SH_7724_SOLUTION_ENGINE help This enables support for sparse irqs. This is useful in general as most CPUs have a fairly sparse array of IRQ vectors, which -- GitLab From 191d0d24b632eb69767705acded5cbf7449ad457 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 14:50:43 +0900 Subject: [PATCH 0505/3892] sh: Tidy up the sh bios VBR handling. This moves the VBR handling out of the main trap handling code and in to the sh-bios helper code. A couple of accessors are added in order to permit other kernel code to get at the VBR value for state save/restore paths. Signed-off-by: Paul Mundt --- arch/sh/include/asm/sh_bios.h | 14 +++++++++++-- arch/sh/kernel/machine_kexec.c | 8 ++------ arch/sh/kernel/sh_bios.c | 37 ++++++++++++++++++++++++++++++++++ arch/sh/kernel/traps_32.c | 29 ++++---------------------- 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/arch/sh/include/asm/sh_bios.h b/arch/sh/include/asm/sh_bios.h index d9c96d7cf6c7..d8a67a17777c 100644 --- a/arch/sh/include/asm/sh_bios.h +++ b/arch/sh/include/asm/sh_bios.h @@ -1,13 +1,13 @@ #ifndef __ASM_SH_BIOS_H #define __ASM_SH_BIOS_H +#ifdef CONFIG_SH_STANDARD_BIOS + /* * Copyright (C) 2000 Greg Banks, Mitch Davis * C API to interface to the standard LinuxSH BIOS * usually from within the early stages of kernel boot. */ - - extern void sh_bios_console_write(const char *buf, unsigned int len); extern void sh_bios_char_out(char ch); extern void sh_bios_gdb_detach(void); @@ -15,4 +15,14 @@ extern void sh_bios_gdb_detach(void); extern void sh_bios_get_node_addr(unsigned char *node_addr); extern void sh_bios_shutdown(unsigned int how); +extern void sh_bios_vbr_init(void); +extern void sh_bios_vbr_reload(void); + +#else + +static inline void sh_bios_vbr_init(void) { } +static inline void sh_bios_vbr_reload(void) { } + +#endif /* CONFIG_SH_STANDARD_BIOS */ + #endif /* __ASM_SH_BIOS_H */ diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index 76f280223ebd..f52d8ed69e12 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -21,6 +21,7 @@ #include #include #include +#include typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, unsigned long reboot_code_buffer, @@ -28,7 +29,6 @@ typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; -extern void *gdb_vbr_vector; extern void *vbr_base; void machine_shutdown(void) @@ -117,11 +117,7 @@ void machine_kexec(struct kimage *image) kexec_info(image); flush_cache_all(); -#if defined(CONFIG_SH_STANDARD_BIOS) - asm volatile("ldc %0, vbr" : - : "r" (((unsigned long) gdb_vbr_vector) - 0x100) - : "memory"); -#endif + sh_bios_vbr_reload(); /* now call it */ rnk = (relocate_new_kernel_t) reboot_code_buffer; diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c index c852f7805728..2a5f2e0d505d 100644 --- a/arch/sh/kernel/sh_bios.c +++ b/arch/sh/kernel/sh_bios.c @@ -55,3 +55,40 @@ void sh_bios_shutdown(unsigned int how) { sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0); } + +void *gdb_vbr_vector = NULL; + +/* + * Read the old value of the VBR register to initialise the vector + * through which debug and BIOS traps are delegated by the Linux trap + * handler. + */ +void sh_bios_vbr_init(void) +{ + unsigned long vbr; + + if (unlikely(gdb_vbr_vector)) + return; + + __asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr)); + + gdb_vbr_vector = (void *)(vbr + 0x100); + printk(KERN_NOTICE "Setting GDB trap vector to %p\n", gdb_vbr_vector); +} + +/** + * sh_bios_vbr_reload - Re-load the system VBR from the BIOS vector. + * + * This can be used by save/restore code to reinitialize the system VBR + * from the fixed BIOS VBR. A no-op if no BIOS VBR is known. + */ +void sh_bios_vbr_reload(void) +{ + if (gdb_vbr_vector) + __asm__ __volatile__ ( + "ldc %0, vbr" + : + : "r" (((unsigned long) gdb_vbr_vector) - 0x100) + : "memory" + ); +} diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 86639beac3a2..efcbdfe52f52 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_CPU_SH2 # define TRAP_RESERVED_INST 4 @@ -876,35 +877,10 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, die_if_kernel("exception", regs, ex); } -#if defined(CONFIG_SH_STANDARD_BIOS) -void *gdb_vbr_vector; - -static inline void __init gdb_vbr_init(void) -{ - register unsigned long vbr; - - /* - * Read the old value of the VBR register to initialise - * the vector through which debug and BIOS traps are - * delegated by the Linux trap handler. - */ - asm volatile("stc vbr, %0" : "=r" (vbr)); - - gdb_vbr_vector = (void *)(vbr + 0x100); - printk("Setting GDB trap vector to 0x%08lx\n", - (unsigned long)gdb_vbr_vector); -} -#endif - void __cpuinit per_cpu_trap_init(void) { extern void *vbr_base; -#ifdef CONFIG_SH_STANDARD_BIOS - if (raw_smp_processor_id() == 0) - gdb_vbr_init(); -#endif - /* NOTE: The VBR value should be at P1 (or P2, virtural "fixed" address space). It's definitely should not in physical address. */ @@ -959,6 +935,9 @@ void __init trap_init(void) set_exception_table_vec(TRAP_UBC, break_point_trap); #endif + /* Save off the BIOS VBR, if there is one */ + sh_bios_vbr_init(); + /* Setup VBR for boot cpu */ per_cpu_trap_init(); } -- GitLab From 65fedbbef8404be5e1dbd18bdad252616b49a24b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 15:22:26 +0900 Subject: [PATCH 0506/3892] sh64: Fix up early serial fixmap. This was conditionalized on CONFIG_EARLY_PRINTK, which has subsequently gone away. Now that the serial driver always supports the early console, make sure we always establish the mapping. Signed-off-by: Paul Mundt --- arch/sh/kernel/head_64.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/sh/kernel/head_64.S b/arch/sh/kernel/head_64.S index 3ea765844c74..defd851abefa 100644 --- a/arch/sh/kernel/head_64.S +++ b/arch/sh/kernel/head_64.S @@ -220,7 +220,6 @@ clear_DTLB: add.l r22, r63, r22 /* Sign extend */ putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */ -#ifdef CONFIG_EARLY_PRINTK /* * Setup a DTLB translation for SCIF phys. */ @@ -231,7 +230,6 @@ clear_DTLB: movi 0xfa03, r22 /* 0xfa030000, fixed SCIF virt */ shori 0x0003, r22 putcfg r21, 0, r22 /* PTEH last */ -#endif /* * Set cache behaviours. -- GitLab From b9303a79567d4a45b015dff7e71dd24923332d8d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 15:26:11 +0900 Subject: [PATCH 0507/3892] sh: Kill off more unused sh_bios callbacks. sh_bios_char_out() is not used by anything in-tree these days, so just get rid of it. Signed-off-by: Paul Mundt --- arch/sh/include/asm/sh_bios.h | 1 - arch/sh/kernel/sh_bios.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/arch/sh/include/asm/sh_bios.h b/arch/sh/include/asm/sh_bios.h index d8a67a17777c..95714c28422b 100644 --- a/arch/sh/include/asm/sh_bios.h +++ b/arch/sh/include/asm/sh_bios.h @@ -9,7 +9,6 @@ * usually from within the early stages of kernel boot. */ extern void sh_bios_console_write(const char *buf, unsigned int len); -extern void sh_bios_char_out(char ch); extern void sh_bios_gdb_detach(void); extern void sh_bios_get_node_addr(unsigned char *node_addr); diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c index 2a5f2e0d505d..2a9c6d50d2c0 100644 --- a/arch/sh/kernel/sh_bios.c +++ b/arch/sh/kernel/sh_bios.c @@ -34,11 +34,6 @@ void sh_bios_console_write(const char *buf, unsigned int len) sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0); } -void sh_bios_char_out(char ch) -{ - sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0); -} - void sh_bios_gdb_detach(void) { sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0); -- GitLab From 776258df925acd0563f471ee4b3f19bbffb3c04f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 15:31:20 +0900 Subject: [PATCH 0508/3892] sh: Consolidate the sh_bios earlyprintk code. Now that the sh-sci earlyprintk is taken care of by the sh-sci driver directly, there's no longer any reason for having a split-out early_printk framework. sh_bios is the only other thing that uses it, so we just migrate the leftovers in to there. As it's possible to have multiple early_param()'s for the same string, there's not much point in having this split out anymore anyways, particularly since the sh_bios dependencies are still special-cased within sh-sci itself. Signed-off-by: Paul Mundt --- arch/sh/include/asm/setup.h | 1 - arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/early_printk.c | 85 ----------------------------------- arch/sh/kernel/sh_bios.c | 80 ++++++++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 89 deletions(-) delete mode 100644 arch/sh/kernel/early_printk.c diff --git a/arch/sh/include/asm/setup.h b/arch/sh/include/asm/setup.h index ce3743599b27..4758325bb24a 100644 --- a/arch/sh/include/asm/setup.h +++ b/arch/sh/include/asm/setup.h @@ -18,7 +18,6 @@ /* ... */ #define COMMAND_LINE ((char *) (PARAM+0x100)) -int setup_early_printk(char *); void sh_mv_setup(void); #endif /* __KERNEL__ */ diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 0d587da1ef12..5bec10c8bd74 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -22,7 +22,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o \ obj-y += cpu/ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o early_printk.o +obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c deleted file mode 100644 index f8bb50c6e050..000000000000 --- a/arch/sh/kernel/early_printk.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * arch/sh/kernel/early_printk.c - * - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2002 M. R. Brown - * Copyright (C) 2004 - 2007 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include -#include - -#include - -/* - * Print a string through the BIOS - */ -static void sh_console_write(struct console *co, const char *s, - unsigned count) -{ - sh_bios_console_write(s, count); -} - -/* - * Setup initial baud/bits/parity. We do two things here: - * - construct a cflag setting for the first rs_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init sh_console_setup(struct console *co, char *options) -{ - int cflag = CREAD | HUPCL | CLOCAL; - - /* - * Now construct a cflag setting. - * TODO: this is a totally bogus cflag, as we have - * no idea what serial settings the BIOS is using, or - * even if its using the serial port at all. - */ - cflag |= B115200 | CS8 | /*no parity*/0; - - co->cflag = cflag; - - return 0; -} - -static struct console bios_console = { - .name = "bios", - .write = sh_console_write, - .setup = sh_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static struct console *early_console; - -static int __init setup_early_printk(char *buf) -{ - int keep_early = 0; - - if (!buf) - return 0; - - if (strstr(buf, "keep")) - keep_early = 1; - - if (!strncmp(buf, "bios", 4)) - early_console = &bios_console; - - if (likely(early_console)) { - if (keep_early) - early_console->flags &= ~CON_BOOT; - else - early_console->flags |= CON_BOOT; - register_console(early_console); - } - - return 0; -} -early_param("earlyprintk", setup_early_printk); diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c index 2a9c6d50d2c0..29cd2526e5c4 100644 --- a/arch/sh/kernel/sh_bios.c +++ b/arch/sh/kernel/sh_bios.c @@ -1,17 +1,26 @@ /* - * linux/arch/sh/kernel/sh_bios.c * C interface for trapping into the standard LinuxSH BIOS. * * Copyright (C) 2000 Greg Banks, Mitch Davis + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2002 M. R. Brown + * Copyright (C) 2004 - 2010 Paul Mundt * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. */ #include +#include +#include +#include +#include +#include #include #define BIOS_CALL_CONSOLE_WRITE 0 #define BIOS_CALL_ETH_NODE_ADDR 10 #define BIOS_CALL_SHUTDOWN 11 -#define BIOS_CALL_CHAR_OUT 0x1f /* TODO: hack */ #define BIOS_CALL_GDB_DETACH 0xff static inline long sh_bios_call(long func, long arg0, long arg1, long arg2, @@ -87,3 +96,70 @@ void sh_bios_vbr_reload(void) : "memory" ); } + +/* + * Print a string through the BIOS + */ +static void sh_console_write(struct console *co, const char *s, + unsigned count) +{ + sh_bios_console_write(s, count); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init sh_console_setup(struct console *co, char *options) +{ + int cflag = CREAD | HUPCL | CLOCAL; + + /* + * Now construct a cflag setting. + * TODO: this is a totally bogus cflag, as we have + * no idea what serial settings the BIOS is using, or + * even if its using the serial port at all. + */ + cflag |= B115200 | CS8 | /*no parity*/0; + + co->cflag = cflag; + + return 0; +} + +static struct console bios_console = { + .name = "bios", + .write = sh_console_write, + .setup = sh_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static struct console *early_console; + +static int __init setup_early_printk(char *buf) +{ + int keep_early = 0; + + if (!buf) + return 0; + + if (strstr(buf, "keep")) + keep_early = 1; + + if (!strncmp(buf, "bios", 4)) + early_console = &bios_console; + + if (likely(early_console)) { + if (keep_early) + early_console->flags &= ~CON_BOOT; + else + early_console->flags |= CON_BOOT; + register_console(early_console); + } + + return 0; +} +early_param("earlyprintk", setup_early_printk); -- GitLab From a99eae5417a09e0be66bf574a9a79a2a7388c967 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 16:12:25 +0900 Subject: [PATCH 0509/3892] sh: Split out the unaligned counters and user bits. This splits out the unaligned access counters and userspace bits in to their own generic interface, which will allow them to be wired up on sh64 too. Signed-off-by: Paul Mundt --- arch/sh/include/asm/alignment.h | 21 +++++ arch/sh/kernel/traps_32.c | 151 ++++-------------------------- arch/sh/mm/Makefile | 2 +- arch/sh/mm/alignment.c | 159 ++++++++++++++++++++++++++++++++ 4 files changed, 198 insertions(+), 135 deletions(-) create mode 100644 arch/sh/include/asm/alignment.h create mode 100644 arch/sh/mm/alignment.c diff --git a/arch/sh/include/asm/alignment.h b/arch/sh/include/asm/alignment.h new file mode 100644 index 000000000000..b12efecf5294 --- /dev/null +++ b/arch/sh/include/asm/alignment.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_ALIGNMENT_H +#define __ASM_SH_ALIGNMENT_H + +#include + +extern void inc_unaligned_byte_access(void); +extern void inc_unaligned_word_access(void); +extern void inc_unaligned_dword_access(void); +extern void inc_unaligned_multi_access(void); +extern void inc_unaligned_user_access(void); +extern void inc_unaligned_kernel_access(void); + +#define UM_WARN (1 << 0) +#define UM_FIXUP (1 << 1) +#define UM_SIGNAL (1 << 2) + +extern unsigned int unaligned_user_action(void); + +extern void unaligned_fixups_notify(struct task_struct *, insn_size_t, struct pt_regs *); + +#endif /* __ASM_SH_ALIGNMENT_H */ diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index efcbdfe52f52..204def6ecb6a 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -24,11 +24,10 @@ #include #include #include -#include -#include #include +#include #include -#include +#include #include #include #include @@ -48,73 +47,6 @@ #define TRAP_ILLEGAL_SLOT_INST 13 #endif -static unsigned long se_user; -static unsigned long se_sys; -static unsigned long se_half; -static unsigned long se_word; -static unsigned long se_dword; -static unsigned long se_multi; -/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not - valid! */ -static int se_usermode = 3; -/* 0: no warning 1: print a warning message, disabled by default */ -static int se_kernmode_warn; - -#ifdef CONFIG_PROC_FS -static const char *se_usermode_action[] = { - "ignored", - "warn", - "fixup", - "fixup+warn", - "signal", - "signal+warn" -}; - -static int alignment_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "User:\t\t%lu\n", se_user); - seq_printf(m, "System:\t\t%lu\n", se_sys); - seq_printf(m, "Half:\t\t%lu\n", se_half); - seq_printf(m, "Word:\t\t%lu\n", se_word); - seq_printf(m, "DWord:\t\t%lu\n", se_dword); - seq_printf(m, "Multi:\t\t%lu\n", se_multi); - seq_printf(m, "User faults:\t%i (%s)\n", se_usermode, - se_usermode_action[se_usermode]); - seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, - se_kernmode_warn ? "+warn" : ""); - return 0; -} - -static int alignment_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, alignment_proc_show, NULL); -} - -static ssize_t alignment_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - int *data = PDE(file->f_path.dentry->d_inode)->data; - char mode; - - if (count > 0) { - if (get_user(mode, buffer)) - return -EFAULT; - if (mode >= '0' && mode <= '5') - *data = mode - '0'; - } - return count; -} - -static const struct file_operations alignment_proc_fops = { - .owner = THIS_MODULE, - .open = alignment_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = alignment_proc_write, -}; -#endif - static void dump_mem(const char *str, unsigned long bottom, unsigned long top) { unsigned long p; @@ -266,10 +198,10 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, count = 1<<(instruction&3); switch (count) { - case 1: se_half += 1; break; - case 2: se_word += 1; break; - case 4: se_dword += 1; break; - case 8: se_multi += 1; break; /* ??? */ + case 1: inc_unaligned_byte_access(); break; + case 2: inc_unaligned_word_access(); break; + case 4: inc_unaligned_dword_access(); break; + case 8: inc_unaligned_multi_access(); break; } ret = -EFAULT; @@ -453,18 +385,8 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, rm = regs->regs[index]; /* shout about fixups */ - if (!expected) { - if (user_mode(regs) && (se_usermode & 1) && printk_ratelimit()) - pr_notice("Fixing up unaligned userspace access " - "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", - current->comm, task_pid_nr(current), - (void *)regs->pc, instruction); - else if (se_kernmode_warn && printk_ratelimit()) - pr_notice("Fixing up unaligned kernel access " - "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", - current->comm, task_pid_nr(current), - (void *)regs->pc, instruction); - } + if (!expected) + unaligned_fixups_notify(current, instruction, regs); ret = -EFAULT; switch (instruction&0xF000) { @@ -617,10 +539,10 @@ asmlinkage void do_address_error(struct pt_regs *regs, if (user_mode(regs)) { int si_code = BUS_ADRERR; + unsigned int user_action; local_irq_enable(); - - se_user += 1; + inc_unaligned_user_access(); set_fs(USER_DS); if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), @@ -631,16 +553,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, set_fs(oldfs); /* shout about userspace fixups */ - if (se_usermode & 1) - printk(KERN_NOTICE "Unaligned userspace access " - "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", - current->comm, current->pid, (void *)regs->pc, - instruction); + unaligned_fixups_notify(current, instruction, regs); - if (se_usermode & 2) + user_action = unaligned_user_action(); + if (user_action & UM_FIXUP) goto fixup; - - if (se_usermode & 4) + if (user_action & UM_SIGNAL) goto uspace_segv; else { /* ignore */ @@ -660,7 +578,7 @@ fixup: &user_mem_access, 0); set_fs(oldfs); - if (tmp==0) + if (tmp == 0) return; /* sorted */ uspace_segv: printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " @@ -673,7 +591,7 @@ uspace_segv: info.si_addr = (void __user *)address; force_sig_info(SIGBUS, &info, current); } else { - se_sys += 1; + inc_unaligned_kernel_access(); if (regs->pc & 1) die("unaligned program counter", regs, error_code); @@ -688,11 +606,7 @@ uspace_segv: die("insn faulting in do_address_error", regs, 0); } - if (se_kernmode_warn) - printk(KERN_NOTICE "Unaligned kernel access " - "on behalf of \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", - current->comm, current->pid, (void *)regs->pc, - instruction); + unaligned_fixups_notify(current, instruction, regs); handle_unaligned_access(instruction, regs, &user_mem_access, 0); @@ -964,34 +878,3 @@ void dump_stack(void) show_stack(NULL, NULL); } EXPORT_SYMBOL(dump_stack); - -#ifdef CONFIG_PROC_FS -/* - * This needs to be done after sysctl_init, otherwise sys/ will be - * overwritten. Actually, this shouldn't be in sys/ at all since - * it isn't a sysctl, and it doesn't contain sysctl information. - * We now locate it in /proc/cpu/alignment instead. - */ -static int __init alignment_init(void) -{ - struct proc_dir_entry *dir, *res; - - dir = proc_mkdir("cpu", NULL); - if (!dir) - return -ENOMEM; - - res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir, - &alignment_proc_fops, &se_usermode); - if (!res) - return -ENOMEM; - - res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir, - &alignment_proc_fops, &se_kernmode_warn); - if (!res) - return -ENOMEM; - - return 0; -} - -fs_initcall(alignment_init); -#endif diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index dd5010c708e0..9fa11d655044 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux SuperH-specific parts of the memory manager. # -obj-y := cache.o init.o consistent.o mmap.o +obj-y := alignment.o cache.o init.o consistent.o mmap.o cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c new file mode 100644 index 000000000000..e615151eac3b --- /dev/null +++ b/arch/sh/mm/alignment.c @@ -0,0 +1,159 @@ +/* + * Alignment access counters and corresponding user-space interfaces. + * + * Copyright (C) 2009 ST Microelectronics + * Copyright (C) 2009 - 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +static unsigned long se_user; +static unsigned long se_sys; +static unsigned long se_half; +static unsigned long se_word; +static unsigned long se_dword; +static unsigned long se_multi; +/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not + valid! */ +static int se_usermode = UM_WARN | UM_FIXUP; +/* 0: no warning 1: print a warning message, disabled by default */ +static int se_kernmode_warn; + +void inc_unaligned_byte_access(void) +{ + se_half++; +} + +void inc_unaligned_word_access(void) +{ + se_word++; +} + +void inc_unaligned_dword_access(void) +{ + se_dword++; +} + +void inc_unaligned_multi_access(void) +{ + se_multi++; +} + +void inc_unaligned_user_access(void) +{ + se_user++; +} + +void inc_unaligned_kernel_access(void) +{ + se_sys++; +} + +unsigned int unaligned_user_action(void) +{ + return se_usermode; +} + +void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn, + struct pt_regs *regs) +{ + if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit()) + pr_notice("Fixing up unaligned userspace access " + "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + tsk->comm, task_pid_nr(tsk), + (void *)regs->pc, insn); + else if (se_kernmode_warn && printk_ratelimit()) + pr_notice("Fixing up unaligned kernel access " + "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + tsk->comm, task_pid_nr(tsk), + (void *)regs->pc, insn); +} + +static const char *se_usermode_action[] = { + "ignored", + "warn", + "fixup", + "fixup+warn", + "signal", + "signal+warn" +}; + +static int alignment_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "User:\t\t%lu\n", se_user); + seq_printf(m, "System:\t\t%lu\n", se_sys); + seq_printf(m, "Half:\t\t%lu\n", se_half); + seq_printf(m, "Word:\t\t%lu\n", se_word); + seq_printf(m, "DWord:\t\t%lu\n", se_dword); + seq_printf(m, "Multi:\t\t%lu\n", se_multi); + seq_printf(m, "User faults:\t%i (%s)\n", se_usermode, + se_usermode_action[se_usermode]); + seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, + se_kernmode_warn ? "+warn" : ""); + return 0; +} + +static int alignment_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, alignment_proc_show, NULL); +} + +static ssize_t alignment_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) +{ + int *data = PDE(file->f_path.dentry->d_inode)->data; + char mode; + + if (count > 0) { + if (get_user(mode, buffer)) + return -EFAULT; + if (mode >= '0' && mode <= '5') + *data = mode - '0'; + } + return count; +} + +static const struct file_operations alignment_proc_fops = { + .owner = THIS_MODULE, + .open = alignment_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = alignment_proc_write, +}; + +/* + * This needs to be done after sysctl_init, otherwise sys/ will be + * overwritten. Actually, this shouldn't be in sys/ at all since + * it isn't a sysctl, and it doesn't contain sysctl information. + * We now locate it in /proc/cpu/alignment instead. + */ +static int __init alignment_init(void) +{ + struct proc_dir_entry *dir, *res; + + dir = proc_mkdir("cpu", NULL); + if (!dir) + return -ENOMEM; + + res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir, + &alignment_proc_fops, &se_usermode); + if (!res) + return -ENOMEM; + + res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir, + &alignment_proc_fops, &se_kernmode_warn); + if (!res) + return -ENOMEM; + + return 0; +} +fs_initcall(alignment_init); -- GitLab From 6b98515a620592636d2f8e0d3e2942d1cb4847ec Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Jan 2010 16:22:59 +0000 Subject: [PATCH 0510/3892] sound_oss: remove use of old BKL ioctl path Signed-off-by: Alan Cox Signed-off-by: Takashi Iwai --- sound/oss/soundcard.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 61aaedae6b7e..6c3267bf05d0 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); } -static int sound_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int len = 0, dtype; - int dev = iminor(inode); + int dev = iminor(file->f_dentry->d_inode); + long ret = -EINVAL; void __user *p = (void __user *)arg; if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { @@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file, if (cmd == OSS_GETVERSION) return __put_user(SOUND_VERSION, (int __user *)p); + lock_kernel(); if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; @@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file, case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, + ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, cmd, p); - + break; default: - return sound_mixer_ioctl(dev >> 4, cmd, p); + ret = sound_mixer_ioctl(dev >> 4, cmd, p); + break; } + unlock_kernel(); + return ret; } + switch (dev & 0x0f) { case SND_DEV_CTL: if (cmd == SOUND_MIXER_GETLEVELS) - return get_mixer_levels(p); - if (cmd == SOUND_MIXER_SETLEVELS) - return set_mixer_levels(p); - return sound_mixer_ioctl(dev >> 4, cmd, p); + ret = get_mixer_levels(p); + else if (cmd == SOUND_MIXER_SETLEVELS) + ret = set_mixer_levels(p); + else + ret = sound_mixer_ioctl(dev >> 4, cmd, p); + break; case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_ioctl(dev, file, cmd, p); + ret = sequencer_ioctl(dev, file, cmd, p); + break; case SND_DEV_DSP: case SND_DEV_DSP16: @@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file, break; } - return -EINVAL; + unlock_kernel(); + return ret; } static unsigned int sound_poll(struct file *file, poll_table * wait) @@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = { .read = sound_read, .write = sound_write, .poll = sound_poll, - .ioctl = sound_ioctl, + .unlocked_ioctl = sound_ioctl, .mmap = sound_mmap, .open = sound_open, .release = sound_release, -- GitLab From 94cd049522136c2f3bbe063d2e98b2b8d4286fd3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 18:42:52 +0900 Subject: [PATCH 0511/3892] sh: sh_bios detection. This adds some VBR sanity checks in the sh_bios code to ensure that the BIOS VBR is in range before blindly trapping in to it. This permits boards with varying boot loader configurations to always leave support for sh-bios enabled and it will just be disabled at run-time if not found. Signed-off-by: Paul Mundt --- arch/sh/kernel/sh_bios.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c index 29cd2526e5c4..47475cca068a 100644 --- a/arch/sh/kernel/sh_bios.c +++ b/arch/sh/kernel/sh_bios.c @@ -23,6 +23,8 @@ #define BIOS_CALL_SHUTDOWN 11 #define BIOS_CALL_GDB_DETACH 0xff +void *gdb_vbr_vector = NULL; + static inline long sh_bios_call(long func, long arg0, long arg1, long arg2, long arg3) { @@ -32,6 +34,9 @@ static inline long sh_bios_call(long func, long arg0, long arg1, long arg2, register long r6 __asm__("r6") = arg2; register long r7 __asm__("r7") = arg3; + if (!gdb_vbr_vector) + return -ENOSYS; + __asm__ __volatile__("trapa #0x3f":"=z"(r0) :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7) :"memory"); @@ -60,8 +65,6 @@ void sh_bios_shutdown(unsigned int how) sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0); } -void *gdb_vbr_vector = NULL; - /* * Read the old value of the VBR register to initialise the vector * through which debug and BIOS traps are delegated by the Linux trap @@ -76,8 +79,12 @@ void sh_bios_vbr_init(void) __asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr)); - gdb_vbr_vector = (void *)(vbr + 0x100); - printk(KERN_NOTICE "Setting GDB trap vector to %p\n", gdb_vbr_vector); + if (vbr) { + gdb_vbr_vector = (void *)(vbr + 0x100); + printk(KERN_NOTICE "Setting GDB trap vector to %p\n", + gdb_vbr_vector); + } else + printk(KERN_NOTICE "SH-BIOS not detected\n"); } /** -- GitLab From 70e068eef97d05c97c3512f82352f39fdadfa8cb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 18:52:00 +0900 Subject: [PATCH 0512/3892] sh: Move start_thread() out of line. start_thread() will become a bit heavier with the xstate freeing to be added in, so move it out-of-line in preparation. Signed-off-by: Paul Mundt --- arch/sh/include/asm/processor_32.h | 13 ++----------- arch/sh/kernel/process_32.c | 12 ++++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 1f3d6fab660c..50b8c9c3fa4c 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -119,19 +119,10 @@ extern int ubc_usercnt; .sp = sizeof(init_stack) + (long) &init_stack, \ } -/* - * Do necessary setup to start up a newly executed thread. - */ -#define start_thread(_regs, new_pc, new_sp) \ - set_fs(USER_DS); \ - _regs->pr = 0; \ - _regs->sr = SR_FD; /* User mode. */ \ - _regs->pc = new_pc; \ - _regs->regs[15] = new_sp - /* Forward declaration, a strange C thing */ struct task_struct; -struct mm_struct; + +extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned long new_sp); /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index d8af889366a4..c4361402ec5e 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -147,6 +147,18 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) } EXPORT_SYMBOL(kernel_thread); +void start_thread(struct pt_regs *regs, unsigned long new_pc, + unsigned long new_sp) +{ + set_fs(USER_DS); + + regs->pr = 0; + regs->sr = SR_FD; + regs->pc = new_pc; + regs->regs[15] = new_sp; +} +EXPORT_SYMBOL(start_thread); + /* * Free current thread data structures etc.. */ -- GitLab From 3ccd4c6167d3b39d52631767ebbf8b5677c5855d Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 12 Jan 2010 02:00:46 -0800 Subject: [PATCH 0513/3892] can: Unify droping of invalid tx skbs and netdev stats To prevent the CAN drivers to operate on invalid socketbuffers the skbs are now checked and silently dropped at the xmit-function consistently. Also the netdev stats are consistently using the CAN data length code (dlc) for [rx|tx]_bytes now. Signed-off-by: Oliver Hartkopp Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/at91_can.c | 3 +++ drivers/net/can/bfin_can.c | 3 +++ drivers/net/can/mcp251x.c | 6 +----- drivers/net/can/mscan/mscan.c | 5 +---- drivers/net/can/sja1000/sja1000.c | 3 +++ drivers/net/can/ti_hecc.c | 4 +++- drivers/net/can/usb/ems_usb.c | 3 +++ drivers/net/can/vcan.c | 12 +++++++++--- include/linux/can/dev.h | 15 +++++++++++++++ 9 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 166cc7e579c0..f7287497ba6e 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int mb, prio; u32 reg_mid, reg_mcr; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + mb = get_tx_next_mb(priv); prio = get_tx_next_prio(priv); diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 0ec1524523cc..7e1926e79e98 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -318,6 +318,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev) u16 val; int i; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + netif_stop_queue(dev); /* fill id */ diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 1a72ca066a17..afa2fa45fed9 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -494,12 +494,8 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (skb->len != sizeof(struct can_frame)) { - dev_err(&spi->dev, "dropping packet - bad length\n"); - dev_kfree_skb(skb); - net->stats.tx_dropped++; + if (can_dropped_invalid_skb(net, skb)) return NETDEV_TX_OK; - } netif_stop_queue(net); priv->tx_skb = skb; diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 500d18918bd5..40827c128b65 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -204,11 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) int i, rtr, buf_id; u32 can_id; - if (skb->len != sizeof(*frame) || frame->can_dlc > 8) { - kfree_skb(skb); - dev->stats.tx_dropped++; + if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; - } out_8(®s->cantier, 0); diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 542a4f7255b4..345304d779b9 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -249,6 +249,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, uint8_t dreg; int i; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + netif_stop_queue(dev); fi = dlc = cf->can_dlc; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 5c993c2da528..7d370e32a7a8 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -477,6 +477,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) u32 mbxno, mbx_mask, data; unsigned long flags; + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + mbxno = get_tx_head_mb(priv); mbx_mask = BIT(mbxno); spin_lock_irqsave(&priv->mbx_lock, flags); @@ -491,7 +494,6 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&priv->mbx_lock, flags); /* Prepare mailbox for transmission */ - data = min_t(u8, cf->can_dlc, 8); if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */ data |= HECC_CANMCF_RTR; data |= get_tx_head_prio(priv) << 8; diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index efbb05c71bf4..ddb17e256656 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -767,6 +767,9 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN + sizeof(struct cpc_can_msg); + if (can_dropped_invalid_skb(netdev, skb)) + return NETDEV_TX_OK; + /* create a URB, and a buffer for it, and copy the data to the URB */ urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 80ac56313981..d124d837ae58 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -47,6 +47,7 @@ #include #include #include +#include #include static __initdata const char banner[] = @@ -70,10 +71,11 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)"); static void vcan_rx(struct sk_buff *skb, struct net_device *dev) { + struct can_frame *cf = (struct can_frame *)skb->data; struct net_device_stats *stats = &dev->stats; stats->rx_packets++; - stats->rx_bytes += skb->len; + stats->rx_bytes += cf->can_dlc; skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; @@ -85,11 +87,15 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) { + struct can_frame *cf = (struct can_frame *)skb->data; struct net_device_stats *stats = &dev->stats; int loop; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + stats->tx_packets++; - stats->tx_bytes += skb->len; + stats->tx_bytes += cf->can_dlc; /* set flag whether this packet has to be looped back */ loop = skb->pkt_type == PACKET_LOOPBACK; @@ -103,7 +109,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) * CAN core already did the echo for us */ stats->rx_packets++; - stats->rx_bytes += skb->len; + stats->rx_bytes += cf->can_dlc; } kfree_skb(skb); return NETDEV_TX_OK; diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 3db7767d2a17..7e7c98a3e908 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -60,6 +60,21 @@ struct can_priv { */ #define get_can_dlc(i) (min_t(__u8, (i), 8)) +/* Drop a given socketbuffer if it does not contain a valid CAN frame. */ +static inline int can_dropped_invalid_skb(struct net_device *dev, + struct sk_buff *skb) +{ + const struct can_frame *cf = (struct can_frame *)skb->data; + + if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) { + kfree_skb(skb); + dev->stats.tx_dropped++; + return 1; + } + + return 0; +} + struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max); void free_candev(struct net_device *dev); -- GitLab From cbf6b1ba7ae12b3f7cb6b0d060b88d44649f9eda Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 19:01:11 +0900 Subject: [PATCH 0514/3892] sh: Always provide thread_info allocators. Presently the thread_info allocators are special cased, depending on THREAD_SHIFT < PAGE_SHIFT. This provides a sensible definition for them regardless of configuration, in preparation for extended CPU state. Signed-off-by: Paul Mundt --- arch/sh/include/asm/thread_info.h | 6 ++-- arch/sh/kernel/Makefile | 4 +-- arch/sh/kernel/process.c | 47 +++++++++++++++++++++++++++++++ arch/sh/mm/init.c | 29 ------------------- 4 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 arch/sh/kernel/process.c diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index 1f3d927e2265..2c5b48edeab9 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -93,14 +93,12 @@ static inline struct thread_info *current_thread_info(void) #define THREAD_SIZE_ORDER (THREAD_SHIFT - PAGE_SHIFT) -#else /* THREAD_SHIFT < PAGE_SHIFT */ - -#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR +#endif extern struct thread_info *alloc_thread_info(struct task_struct *tsk); extern void free_thread_info(struct thread_info *ti); -#endif /* THREAD_SHIFT < PAGE_SHIFT */ +#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR #endif /* __ASSEMBLY__ */ diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 5bec10c8bd74..379053c008f7 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -13,8 +13,8 @@ CFLAGS_REMOVE_return_address.o = -pg obj-y := debugtraps.o dma-nommu.o dumpstack.o \ idle.o io.o io_generic.o irq.o \ - irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \ - ptrace_$(BITS).o return_address.o \ + irq_$(BITS).o machvec.o nmi_debug.o process.o \ + process_$(BITS).o ptrace_$(BITS).o return_address.o \ setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ syscalls_$(BITS).o time.o topology.o traps.o \ traps_$(BITS).o unwinder.o diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c new file mode 100644 index 000000000000..b2bda83baeef --- /dev/null +++ b/arch/sh/kernel/process.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#if THREAD_SHIFT < PAGE_SHIFT +static struct kmem_cache *thread_info_cache; + +struct thread_info *alloc_thread_info(struct task_struct *tsk) +{ + struct thread_info *ti; + + ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL); + if (unlikely(ti == NULL)) + return NULL; +#ifdef CONFIG_DEBUG_STACK_USAGE + memset(ti, 0, THREAD_SIZE); +#endif + return ti; +} + +void free_thread_info(struct thread_info *ti) +{ + kmem_cache_free(thread_info_cache, ti); +} + +void thread_info_cache_init(void) +{ + thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, + THREAD_SIZE, 0, NULL); + BUG_ON(thread_info_cache == NULL); +} +#else +struct thread_info *alloc_thread_info(struct task_struct *tsk) +{ +#ifdef CONFIG_DEBUG_STACK_USAGE + gfp_t mask = GFP_KERNEL | __GFP_ZERO; +#else + gfp_t mask = GFP_KERNEL; +#endif + return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER); +} + +void free_thread_info(struct thread_info *ti) +{ + free_pages((unsigned long)ti, THREAD_SIZE_ORDER); +} +#endif /* THREAD_SHIFT < PAGE_SHIFT */ diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 761910d142f8..d5fb014279ad 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -283,35 +283,6 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif -#if THREAD_SHIFT < PAGE_SHIFT -static struct kmem_cache *thread_info_cache; - -struct thread_info *alloc_thread_info(struct task_struct *tsk) -{ - struct thread_info *ti; - - ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL); - if (unlikely(ti == NULL)) - return NULL; -#ifdef CONFIG_DEBUG_STACK_USAGE - memset(ti, 0, THREAD_SIZE); -#endif - return ti; -} - -void free_thread_info(struct thread_info *ti) -{ - kmem_cache_free(thread_info_cache, ti); -} - -void thread_info_cache_init(void) -{ - thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, - THREAD_SIZE, 0, NULL); - BUG_ON(thread_info_cache == NULL); -} -#endif /* THREAD_SHIFT < PAGE_SHIFT */ - #ifdef CONFIG_MEMORY_HOTPLUG int arch_add_memory(int nid, u64 start, u64 size) { -- GitLab From a3705799e2cc5fb69d88ad6a7f317a8f5597f18d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 12 Jan 2010 19:10:06 +0900 Subject: [PATCH 0515/3892] sh: Use SLAB_PANIC for thread_info slab cache. Presently this has a BUG_ON() for failure cases, as powerpc does. Switch this over to a SLAB_PANIC instead. Signed-off-by: Paul Mundt --- arch/sh/kernel/process.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index b2bda83baeef..077e06e1a889 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -26,8 +26,7 @@ void free_thread_info(struct thread_info *ti) void thread_info_cache_init(void) { thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, - THREAD_SIZE, 0, NULL); - BUG_ON(thread_info_cache == NULL); + THREAD_SIZE, SLAB_PANIC, NULL); } #else struct thread_info *alloc_thread_info(struct task_struct *tsk) -- GitLab From 99acbb90c2440155d6b978e654ea875c8282d67b Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 11 Jan 2010 18:30:41 +0100 Subject: [PATCH 0516/3892] ARM: 5875/1: ep93xx: use pr_fmt in clock.c Use pr_fmt to prefix kernel output with the module name and change all printk messages to pr_ format. Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- arch/arm/mach-ep93xx/clock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 1d0f9d8aff2e..07a58d03ae8c 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -10,6 +10,8 @@ * your option) any later version. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include #include #include @@ -468,9 +470,9 @@ static int __init ep93xx_clock_init(void) } clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); - printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n", + pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n", clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); - printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", + pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); -- GitLab From f3f1882ca7bc6b26bcf66ef206eec0c66d823ed3 Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 11 Jan 2010 18:36:02 +0100 Subject: [PATCH 0517/3892] ARM: 5876/1: ep93xx: use pr_fmt in dma-m2p.c Use pr_fmt to prefix kernel output with the module name. Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- arch/arm/mach-ep93xx/dma-m2p.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-ep93xx/dma-m2p.c b/arch/arm/mach-ep93xx/dma-m2p.c index dbcac9c40a28..8904ca4e2e24 100644 --- a/arch/arm/mach-ep93xx/dma-m2p.c +++ b/arch/arm/mach-ep93xx/dma-m2p.c @@ -28,6 +28,8 @@ * with this implementation. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include #include #include @@ -173,7 +175,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id) switch (m2p_channel_state(ch)) { case STATE_IDLE: - pr_crit("m2p_irq: dma interrupt without a dma buffer\n"); + pr_crit("dma interrupt without a dma buffer\n"); BUG(); break; @@ -197,7 +199,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id) break; case STATE_NEXT: - pr_crit("m2p_irq: dma interrupt while next\n"); + pr_crit("dma interrupt while next\n"); BUG(); break; } -- GitLab From 64d6882d02b0e5f74dd5572039e88517e40edb50 Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 11 Jan 2010 19:33:16 +0100 Subject: [PATCH 0518/3892] ARM: 5877/1: ep93xx: use pr_fmt in core.c Use pr_fmt to prefix kernel output with the module name. Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- arch/arm/mach-ep93xx/core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 1f0d66561bbe..41064bd63e38 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -14,6 +14,8 @@ * your option) any later version. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include #include #include @@ -318,8 +320,7 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) desc->handle_irq = handle_edge_irq; break; default: - pr_err("ep93xx: failed to set irq type %d for gpio %d\n", - type, gpio); + pr_err("failed to set irq type %d for gpio %d\n", type, gpio); return -EINVAL; } @@ -572,9 +573,9 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, * CMOS driver. */ if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) - pr_warning("ep93xx: sda != EEDAT, open drain has no effect\n"); + pr_warning("sda != EEDAT, open drain has no effect\n"); if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) - pr_warning("ep93xx: scl != EECLK, open drain has no effect\n"); + pr_warning("scl != EECLK, open drain has no effect\n"); __raw_writel((data->sda_is_open_drain << 1) | (data->scl_is_open_drain << 0), -- GitLab From 1fbd972ad0f97253ebfbb04881dc4ad95541153c Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 11 Jan 2010 21:38:00 +0100 Subject: [PATCH 0519/3892] ARM: 5878/1: ep93xx: register the pwm devices on the edb93xx dev boards Add the platform init code to register the pwm devices that exist on the various edb93xx development boards. Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- arch/arm/mach-ep93xx/edb93xx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index a4a7be308000..d22d67ac8b99 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -118,12 +118,33 @@ static void __init edb93xx_register_i2c(void) } } + +/************************************************************************* + * EDB93xx pwm + *************************************************************************/ +static void __init edb93xx_register_pwm(void) +{ + if (machine_is_edb9301() || + machine_is_edb9302() || machine_is_edb9302a()) { + /* EP9301 and EP9302 only have pwm.1 (EGPIO14) */ + ep93xx_register_pwm(0, 1); + } else if (machine_is_edb9307() || machine_is_edb9307a()) { + /* EP9307 only has pwm.0 (PWMOUT) */ + ep93xx_register_pwm(1, 0); + } else { + /* EP9312 and EP9315 have both */ + ep93xx_register_pwm(1, 1); + } +} + + static void __init edb93xx_init_machine(void) { ep93xx_init_devices(); edb93xx_register_flash(); ep93xx_register_eth(&edb93xx_eth_data, 1); edb93xx_register_i2c(); + edb93xx_register_pwm(); } -- GitLab From 346e34abb2c56695ee4bd6af924141c97a0babfb Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 11 Jan 2010 21:41:29 +0100 Subject: [PATCH 0520/3892] ARM: 5879/1: ep93xx: define magic numbers for pll1 and pll2 Add defines for the pll register magic numbers that determine if the pll's are bypassed and if pll2 is enabled. Rename the clock set registers to more closely match the datasheet. Also, remove the unnecessary braces since each conditional statement is a single statement. Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- arch/arm/mach-ep93xx/clock.c | 20 +++++++++++-------- .../mach-ep93xx/include/mach/ep93xx-regs.h | 7 +++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 07a58d03ae8c..27e335131799 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -449,25 +449,29 @@ static int __init ep93xx_clock_init(void) u32 value; int i; - value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); - if (!(value & 0x00800000)) { /* PLL1 bypassed? */ + /* Determine the bootloader configured pll1 rate */ + value = __raw_readl(EP93XX_SYSCON_CLKSET1); + if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1)) clk_pll1.rate = clk_xtali.rate; - } else { + else clk_pll1.rate = calc_pll_rate(value); - } + + /* Initialize the pll1 derived clocks */ clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; ep93xx_dma_clock_init(); + /* Determine the bootloader configured pll2 rate */ value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); - if (!(value & 0x00080000)) { /* PLL2 bypassed? */ + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2)) clk_pll2.rate = clk_xtali.rate; - } else if (value & 0x00040000) { /* PLL2 enabled? */ + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN) clk_pll2.rate = calc_pll_rate(value); - } else { + else clk_pll2.rate = 0; - } + + /* Initialize the pll2 derived clocks */ clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n", diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index d55194a4c093..cd359120c1f5 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h @@ -167,8 +167,11 @@ #define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16) #define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) #define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) -#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) -#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24) +#define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20) +#define EP93XX_SYSCON_CLKSET1_NBYP1 (1<<23) +#define EP93XX_SYSCON_CLKSET2 EP93XX_SYSCON_REG(0x24) +#define EP93XX_SYSCON_CLKSET2_NBYP2 (1<<19) +#define EP93XX_SYSCON_CLKSET2_PLL2_EN (1<<18) #define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80) #define EP93XX_SYSCON_DEVCFG_SWRST (1<<31) #define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30) -- GitLab From d67dec5b2cc208215de21dc7806945bf6a6e85d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 10 Jan 2010 17:59:22 +0100 Subject: [PATCH 0521/3892] HID: make USB device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct usb_device_id is constant in so it is worth to make the initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 0258289f3b3e..e72751d6e3e7 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1342,7 +1342,7 @@ static int hid_reset_resume(struct usb_interface *intf) #endif /* CONFIG_PM */ -static struct usb_device_id hid_usb_ids [] = { +static const struct usb_device_id hid_usb_ids[] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_INTERFACE_CLASS_HID }, { } /* Terminating entry */ -- GitLab From 03e7a35c0ef7a462385fb6a301dfc1b287cac6de Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 12 Jan 2010 14:01:19 +0000 Subject: [PATCH 0522/3892] Revert "ASoC: ad1836: reset and restore clock control mode in suspend/resume entry" This reverts commit afe1c2cd71eb4e0fade720b5709722e7124f29c0 since it doesn't build. --- sound/soc/codecs/ad1836.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 83add2f3afba..2c18e3d1b71e 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -223,36 +223,6 @@ static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, return reg_cache[reg]; } -#ifdef CONFIG_PM -static int ad1836_soc_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - /* reset clock control mode */ - u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); - adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; - - return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); -} - -static int ad1836_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - /* restore clock control mode */ - u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); - adc_ctrl2 |= AD1836_ADC_AUX; - - return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); -} -#else -#define ad1836_soc_suspend NULL -#define ad1836_soc_resume NULL -#endif - static int __devinit ad1836_spi_probe(struct spi_device *spi) { struct snd_soc_codec *codec; @@ -434,8 +404,6 @@ static int ad1836_remove(struct platform_device *pdev) struct snd_soc_codec_device soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, - .suspend = ad1836_soc_suspend, - .resume = ad1836_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); -- GitLab From 735fe4cfbc3cedea41bd0ed31955054dae6beb46 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 12 Jan 2010 14:13:00 +0000 Subject: [PATCH 0523/3892] ASoC: Add missing __devexit and __devinit annotations Signed-off-by: Mark Brown --- sound/soc/codecs/da7210.c | 6 +++--- sound/soc/codecs/tlv320dac33.c | 6 +++--- sound/soc/codecs/tpa6130a2.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index fbf3ab482015..cf2975a7294a 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -471,8 +471,8 @@ init_err: } #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static int da7210_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int __devinit da7210_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct da7210_priv *da7210; struct snd_soc_codec *codec; @@ -495,7 +495,7 @@ static int da7210_i2c_probe(struct i2c_client *i2c, return ret; } -static int da7210_i2c_remove(struct i2c_client *client) +static int __devexit da7210_i2c_remove(struct i2c_client *client) { struct da7210_priv *da7210 = i2c_get_clientdata(client); diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 3ef3255cd1e7..2df9c20b7d52 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1191,8 +1191,8 @@ struct snd_soc_dai dac33_dai = { }; EXPORT_SYMBOL_GPL(dac33_dai); -static int dac33_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int __devinit dac33_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; @@ -1345,7 +1345,7 @@ error_reg: return ret; } -static int dac33_i2c_remove(struct i2c_client *client) +static int __devexit dac33_i2c_remove(struct i2c_client *client) { struct tlv320dac33_priv *dac33; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 8b27281e62a1..958d49c969ac 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -379,8 +379,8 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); -static int tpa6130a2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int __devinit tpa6130a2_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct device *dev; struct tpa6130a2_data *data; @@ -479,7 +479,7 @@ err_gpio: return ret; } -static int tpa6130a2_remove(struct i2c_client *client) +static int __devexit tpa6130a2_remove(struct i2c_client *client) { struct tpa6130a2_data *data = i2c_get_clientdata(client); -- GitLab From 14acdde6e527950f66c084dbf19bad6fbfcaeedc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 18 Dec 2009 11:26:04 -0500 Subject: [PATCH 0524/3892] ath9k: re-enable ps by default for new single chip families The newer single chip hardware family of chipsets have not been experiencing issues with power saving set by default with recent fixes merged (even into stable). The remaining issues are only reported with AR5416 and since enabling PS by default can increase power savings considerably best to take advantage of that feature as this has been tested properly. For more details on this issue see the bug report: http://bugzilla.kernel.org/show_bug.cgi?id=14267 We leave AR5416 with PS disabled by default, that seems to require some more work. Cc: stable@kernel.org Cc: Peter Stuge Cc: Justin P. Mattock Cc: Kristoffer Ericson Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 79fbbda15493..3777b8449789 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1838,6 +1838,8 @@ bad_free_hw: void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { + struct ath_hw *ah = sc->sc_ah; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | @@ -1855,7 +1857,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + if (AR_SREV_5416(ah)) + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->queues = 4; hw->max_rates = 4; -- GitLab From 81077e82c3f591578625805dd6464a27a9ff56ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Turek?= <8an@praha12.net> Date: Mon, 21 Dec 2009 22:50:47 +0100 Subject: [PATCH 0525/3892] nl80211: Add new WIPHY attribute COVERAGE_CLASS The new attribute NL80211_ATTR_WIPHY_COVERAGE_CLASS sets IEEE 802.11 Coverage Class, which depends on maximum distance of nodes in a wireless network. It's required for long distance links (more than a few hundred meters). The attribute is now ignored by two non-mac80211 drivers, rndis and iwmc3200wifi, together with WIPHY_PARAM_RETRY_SHORT and WIPHY_PARAM_RETRY_LONG. If it turns out to be a problem, we could split set_wiphy_params callback or add new capability bits. Signed-off-by: Lukas Turek <8an@praha12.net> Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 2 ++ net/wireless/core.c | 1 + net/wireless/nl80211.c | 15 +++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2bfbe88837ef..d4c556de7170 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -430,6 +430,8 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length * larger than or equal to this use RTS/CTS handshake); allowed range: * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 + * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 + * section 7.3.2.9; dot11CoverageClass; u8 * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name @@ -779,6 +781,8 @@ enum nl80211_attrs { NL80211_ATTR_COOKIE, + NL80211_ATTR_WIPHY_COVERAGE_CLASS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index add79930f47d..a8d5d04314b9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -837,6 +837,7 @@ enum wiphy_params_flags { WIPHY_PARAM_RETRY_LONG = 1 << 1, WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, + WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, }; /** @@ -1236,6 +1237,7 @@ struct wiphy { u8 retry_long; u32 frag_threshold; u32 rts_threshold; + u8 coverage_class; char fw_version[ETHTOOL_BUSINFO_LEN]; u32 hw_version; diff --git a/net/wireless/core.c b/net/wireless/core.c index c2a2c563d21a..0a545bb6ed05 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.retry_long = 4; rdev->wiphy.frag_threshold = (u32) -1; rdev->wiphy.rts_threshold = (u32) -1; + rdev->wiphy.coverage_class = 0; return &rdev->wiphy; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3bee3cecdfa..c09fbcd278fb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -444,6 +445,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, dev->wiphy.frag_threshold); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, dev->wiphy.rts_threshold); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, + dev->wiphy.coverage_class); NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); @@ -684,6 +687,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) u32 changed; u8 retry_short = 0, retry_long = 0; u32 frag_threshold = 0, rts_threshold = 0; + u8 coverage_class = 0; rtnl_lock(); @@ -806,9 +810,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) changed |= WIPHY_PARAM_RTS_THRESHOLD; } + if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { + coverage_class = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); + changed |= WIPHY_PARAM_COVERAGE_CLASS; + } + if (changed) { u8 old_retry_short, old_retry_long; u32 old_frag_threshold, old_rts_threshold; + u8 old_coverage_class; if (!rdev->ops->set_wiphy_params) { result = -EOPNOTSUPP; @@ -819,6 +830,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) old_retry_long = rdev->wiphy.retry_long; old_frag_threshold = rdev->wiphy.frag_threshold; old_rts_threshold = rdev->wiphy.rts_threshold; + old_coverage_class = rdev->wiphy.coverage_class; if (changed & WIPHY_PARAM_RETRY_SHORT) rdev->wiphy.retry_short = retry_short; @@ -828,6 +840,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev->wiphy.frag_threshold = frag_threshold; if (changed & WIPHY_PARAM_RTS_THRESHOLD) rdev->wiphy.rts_threshold = rts_threshold; + if (changed & WIPHY_PARAM_COVERAGE_CLASS) + rdev->wiphy.coverage_class = coverage_class; result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); if (result) { @@ -835,6 +849,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev->wiphy.retry_long = old_retry_long; rdev->wiphy.frag_threshold = old_frag_threshold; rdev->wiphy.rts_threshold = old_rts_threshold; + rdev->wiphy.coverage_class = old_coverage_class; } } -- GitLab From 310bc676e314e92c18257bfc916951879451ee32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Turek?= <8an@praha12.net> Date: Mon, 21 Dec 2009 22:50:48 +0100 Subject: [PATCH 0526/3892] mac80211: Add new callback set_coverage_class Mac80211 callback to driver set_coverage_class() sets slot time and ACK timeout for given IEEE 802.11 coverage class. The callback is optional, but it's essential for long distance links. Signed-off-by: Lukas Turek <8an@praha12.net> Signed-off-by: John W. Linville --- include/net/mac80211.h | 5 +++++ net/mac80211/cfg.c | 7 +++++++ net/mac80211/driver-ops.h | 15 +++++++++++++++ net/mac80211/driver-trace.h | 23 +++++++++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f073a2a50574..ad4b70034e77 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1533,6 +1533,10 @@ enum ieee80211_ampdu_mlme_action { * and need to call wiphy_rfkill_set_hw_state() in the callback. * The callback can sleep. * + * @set_coverage_class: Set slot time for given coverage class as specified + * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout + * accordingly. This callback is not required and may sleep. + * * @testmode_cmd: Implement a cfg80211 test mode command. * The callback can sleep. * @@ -1592,6 +1596,7 @@ struct ieee80211_ops { struct ieee80211_sta *sta, u16 tid, u16 *ssn); void (*rfkill_poll)(struct ieee80211_hw *hw); + void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); #endif diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e5e841e9b7b..976014c5e742 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1230,6 +1230,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct ieee80211_local *local = wiphy_priv(wiphy); int err; + if (changed & WIPHY_PARAM_COVERAGE_CLASS) { + err = drv_set_coverage_class(local, wiphy->coverage_class); + + if (err) + return err; + } + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { err = drv_set_rts_threshold(local, wiphy->rts_threshold); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8757ea73d544..de91d39e0276 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -214,6 +214,21 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, return ret; } +static inline int drv_set_coverage_class(struct ieee80211_local *local, + u8 value) +{ + int ret = 0; + might_sleep(); + + if (local->ops->set_coverage_class) + local->ops->set_coverage_class(&local->hw, value); + else + ret = -EOPNOTSUPP; + + trace_drv_set_coverage_class(local, value, ret); + return ret; +} + static inline void drv_sta_notify(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, enum sta_notify_cmd cmd, diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 977cc7528bc6..0ea258123b8e 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -491,6 +491,29 @@ TRACE_EVENT(drv_set_rts_threshold, ) ); +TRACE_EVENT(drv_set_coverage_class, + TP_PROTO(struct ieee80211_local *local, u8 value, int ret), + + TP_ARGS(local, value, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u8, value) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + __entry->value = value; + ), + + TP_printk( + LOCAL_PR_FMT " value:%d ret:%d", + LOCAL_PR_ARG, __entry->value, __entry->ret + ) +); + TRACE_EVENT(drv_sta_notify, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, -- GitLab From e1aa369ec8fb981ef78bc5be3b3c58de7c5ff769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Turek?= <8an@praha12.net> Date: Mon, 21 Dec 2009 22:50:49 +0100 Subject: [PATCH 0527/3892] ath5k: Fix functions for getting/setting slot time Functions ath5k_hw_get_slot_time and ath5k_hw_set_slot_time were converting microseconds to clocks only for AR5210, although it's needed for all supported devices. The conversion was moved outside the hardware-specific branches. The original code also limited minimum slot time to 9, while turbo modes use 6, this was fixed too. Signed-off-by: Lukas Turek <8an@praha12.net> Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/qcu.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index eeebb9aef206..e322a104e7fe 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -520,12 +520,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) */ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) { + unsigned int slot_time_clock; + ATH5K_TRACE(ah->ah_sc); + if (ah->ah_version == AR5K_AR5210) - return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, - AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); + slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME); else - return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; + slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT); + + return ath5k_hw_clocktoh(slot_time_clock & 0xffff, ah->ah_turbo); } /* @@ -533,15 +537,17 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) */ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) { + u32 slot_time_clock = ath5k_hw_htoclock(slot_time, ah->ah_turbo); + ATH5K_TRACE(ah->ah_sc); - if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) + + if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) return -EINVAL; if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, - ah->ah_turbo), AR5K_SLOT_TIME); + ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); else - ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); + ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); return 0; } -- GitLab From 3578e6ebb305e6bf7519f6e86741772892f4d51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Turek?= <8an@praha12.net> Date: Mon, 21 Dec 2009 22:50:50 +0100 Subject: [PATCH 0528/3892] ath5k: Reimplement clock rate to usec conversion The original code was correct in 802.11a mode only, 802.11b/g uses different clock rates. The new code uses values taken from FreeBSD HAL and should be correct for all modes including turbo modes. The former rate calculation was used by slope coefficient calculation function ath5k_hw_write_ofdm_timings. However, this function requires the 802.11a values even in 802.11g mode. Thus the use of ath5k_hw_htoclock was replaced by hardcoded values. Possibly the slope coefficient calculation is not related to clock rate at all. Signed-off-by: Lukas Turek <8an@praha12.net> Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 22 ++------- drivers/net/wireless/ath/ath5k/pcu.c | 64 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath5k/qcu.c | 4 +- drivers/net/wireless/ath/ath5k/reset.c | 5 +- 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6a2a96761111..ae311d2dcc16 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1231,6 +1231,10 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); +/* Clock rate related functions */ +unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); +unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); +unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); /* Key table (WEP) functions */ extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); @@ -1310,24 +1314,6 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); * Functions used internaly */ -/* - * Translate usec to hw clock units - * TODO: Half/quarter rate - */ -static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) -{ - return turbo ? (usec * 80) : (usec * 40); -} - -/* - * Translate hw clock units to usec - * TODO: Half/quarter rate - */ -static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) -{ - return turbo ? (clock / 80) : (clock / 40); -} - static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) { return &ah->common; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 64fc1eb9b6d9..b601ff9865fd 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); + return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_ACK)); } /** @@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), - ah->ah_turbo) <= timeout) + if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) + <= timeout) return -EINVAL; AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); + ath5k_hw_htoclock(ah, timeout)); return 0; } @@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); + return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); } /** @@ -231,16 +231,60 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), - ah->ah_turbo) <= timeout) + if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) + <= timeout) return -EINVAL; AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); + ath5k_hw_htoclock(ah, timeout)); return 0; } +/** + * ath5k_hw_htoclock - Translate usec to hw clock units + * + * @ah: The &struct ath5k_hw + * @usec: value in microseconds + */ +unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) +{ + return usec * ath5k_hw_get_clockrate(ah); +} + +/** + * ath5k_hw_clocktoh - Translate hw clock units to usec + * @clock: value in hw clock units + */ +unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) +{ + return clock / ath5k_hw_get_clockrate(ah); +} + +/** + * ath5k_hw_get_clockrate - Get the clock rate for current mode + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) +{ + struct ieee80211_channel *channel = ah->ah_current_channel; + int clock; + + if (channel->hw_value & CHANNEL_5GHZ) + clock = 40; /* 802.11a */ + else if (channel->hw_value & CHANNEL_CCK) + clock = 22; /* 802.11b */ + else + clock = 44; /* 802.11g */ + + /* Clock rate in turbo modes is twice the normal rate */ + if (channel->hw_value & CHANNEL_TURBO) + clock *= 2; + + return clock; +} + /** * ath5k_hw_set_lladdr - Set station id * diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index e322a104e7fe..abe36c0d139c 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -529,7 +529,7 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) else slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT); - return ath5k_hw_clocktoh(slot_time_clock & 0xffff, ah->ah_turbo); + return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff); } /* @@ -537,7 +537,7 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) */ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) { - u32 slot_time_clock = ath5k_hw_htoclock(slot_time, ah->ah_turbo); + u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); ATH5K_TRACE(ah->ah_sc); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 62954fc77869..299b33a03979 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -60,12 +60,11 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, !(channel->hw_value & CHANNEL_OFDM)); /* Get coefficient - * ALGO: coef = (5 * clock * carrier_freq) / 2) + * ALGO: coef = (5 * clock / carrier_freq) / 2 * we scale coef by shifting clock value by 24 for * better precision since we use integers */ /* TODO: Half/quarter rate */ - clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO); - + clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40; coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; /* Get exponent -- GitLab From 6e08d228b6d8e93d7b25b3573c6da7da179c2ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Turek?= <8an@praha12.net> Date: Mon, 21 Dec 2009 22:50:51 +0100 Subject: [PATCH 0529/3892] ath5k: Implement mac80211 callback set_coverage_class The callback sets slot time as specified in IEEE 802.11-2007 section 17.3.8.6 (for 20MHz channels only for now) and raises ACK and CTS timeouts accordingly. The values are persistent, they are restored after device reset. Signed-off-by: Lukas Turek <8an@praha12.net> Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 + drivers/net/wireless/ath/ath5k/base.c | 22 ++++++++++ drivers/net/wireless/ath/ath5k/pcu.c | 57 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath5k/reset.c | 4 ++ 4 files changed, 85 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ae311d2dcc16..66bcb506a112 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1063,6 +1063,7 @@ struct ath5k_hw { u32 ah_cw_min; u32 ah_cw_max; u32 ah_limit_tx_retries; + u8 ah_coverage_class; /* Antenna Control */ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; @@ -1200,6 +1201,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); /* Protocol Control Unit Functions */ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); +extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); /* BSSID Functions */ extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); extern void ath5k_hw_set_associd(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fdfaf0f618f1..b5015376d4ba 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -254,6 +254,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, u32 changes); static void ath5k_sw_scan_start(struct ieee80211_hw *hw); static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); +static void ath5k_set_coverage_class(struct ieee80211_hw *hw, + u8 coverage_class); static const struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -274,6 +276,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { .bss_info_changed = ath5k_bss_info_changed, .sw_scan_start = ath5k_sw_scan_start, .sw_scan_complete = ath5k_sw_scan_complete, + .set_coverage_class = ath5k_set_coverage_class, }; /* @@ -3262,3 +3265,22 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) ath5k_hw_set_ledstate(sc->ah, sc->assoc ? AR5K_LED_ASSOC : AR5K_LED_INIT); } + +/** + * ath5k_set_coverage_class - Set IEEE 802.11 coverage class + * + * @hw: struct ieee80211_hw pointer + * @coverage_class: IEEE 802.11 coverage class number + * + * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given + * coverage class. The values are persistent, they are restored after device + * reset. + */ +static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +{ + struct ath5k_softc *sc = hw->priv; + + mutex_lock(&sc->lock); + ath5k_hw_set_coverage_class(sc->ah, coverage_class); + mutex_unlock(&sc->lock); +} diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index b601ff9865fd..aefe84f9c04b 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -285,6 +285,42 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) return clock; } +/** + * ath5k_hw_get_default_slottime - Get the default slot time for current mode + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) +{ + struct ieee80211_channel *channel = ah->ah_current_channel; + + if (channel->hw_value & CHANNEL_TURBO) + return 6; /* both turbo modes */ + + if (channel->hw_value & CHANNEL_CCK) + return 20; /* 802.11b */ + + return 9; /* 802.11 a/g */ +} + +/** + * ath5k_hw_get_default_sifs - Get the default SIFS for current mode + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) +{ + struct ieee80211_channel *channel = ah->ah_current_channel; + + if (channel->hw_value & CHANNEL_TURBO) + return 8; /* both turbo modes */ + + if (channel->hw_value & CHANNEL_5GHZ) + return 16; /* 802.11a */ + + return 10; /* 802.11 b/g */ +} + /** * ath5k_hw_set_lladdr - Set station id * @@ -1094,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) return 0; } +/** + * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class + * + * @ah: The &struct ath5k_hw + * @coverage_class: IEEE 802.11 coverage class number + * + * Sets slot time, ACK timeout and CTS timeout for given coverage class. + */ +void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) +{ + /* As defined by IEEE 802.11-2007 17.3.8.6 */ + int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; + int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; + int cts_timeout = ack_timeout; + + ath5k_hw_set_slot_time(ah, slot_time); + ath5k_hw_set_ack_timeout(ah, ack_timeout); + ath5k_hw_set_cts_timeout(ah, cts_timeout); + + ah->ah_coverage_class = coverage_class; +} diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 299b33a03979..6690923fd78c 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1316,6 +1316,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Restore antenna mode */ ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); + /* Restore slot time and ACK timeouts */ + if (ah->ah_coverage_class > 0) + ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); + /* * Configure QCUs/DCUs */ -- GitLab From 3dc1de0bf23816ed557ac8addf680cd5ee57e805 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 28 Dec 2009 16:57:15 +0800 Subject: [PATCH 0530/3892] mac80211: quit addba_resp_timer if Tx BA session is torn down Make addba_resp_timer aware the HT_AGG_STATE_REQ_STOP_BA_MSK mask so that when ___ieee80211_stop_tx_ba_session() is issued the timer will quit. Otherwise when suspend happens before the timer expired, the timer handler will be called immediately after resume and messes up driver status. Signed-off-by: Zhu Yi Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5aa8f4a3ed17..718fbcff84d2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data) /* check if the TID waits for addBA response */ spin_lock_bh(&sta->lock); - if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != + if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | + HT_AGG_STATE_REQ_STOP_BA_MSK)) != HT_ADDBA_REQUESTED_MSK) { spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; -- GitLab From e00cfce0cb2a397859607bf515c6de9ce064b64a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 29 Dec 2009 12:59:19 +0200 Subject: [PATCH 0531/3892] mac80211: Select lowest rate based on basic rate set in AP mode If the basic rate set is configured to not include the lowest rate (e.g., basic rate set = 6, 12, 24 Mbps in IEEE 802.11g mode), the AP should not send out broadcast frames at 1 Mbps. This type of configuration can be used to optimize channel usage in cases where there is no need for backwards compatibility with IEEE 802.11b-only devices. In AP mode, mac80211 was unconditionally using the lowest rate for Beacon frames and similarly, with all rate control algorithms that use rate_control_send_low(), the lowest rate ended up being used for all broadcast frames (and all unicast frames that are sent before association). Change this to take into account the basic rate configuration in AP mode, i.e., use the lowest rate in the basic rate set instead of the lowest supported rate when selecting the rate. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 ++ net/mac80211/rate.c | 25 +++++++++++++++++++++++++ net/mac80211/tx.c | 24 +++++++++++++----------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ad4b70034e77..39c516c352be 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2299,6 +2299,7 @@ enum rate_control_changed { * @max_rate_idx: user-requested maximum rate (not MCS for now) * @skb: the skb that will be transmitted, the control information in it needs * to be filled in + * @ap: whether this frame is sent out in AP mode */ struct ieee80211_tx_rate_control { struct ieee80211_hw *hw; @@ -2308,6 +2309,7 @@ struct ieee80211_tx_rate_control { struct ieee80211_tx_rate reported_rate; bool rts, short_preamble; u8 max_rate_idx; + bool ap; }; struct rate_control_ops { diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b9007f80cb92..6349e7f4dcae 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); } +static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) +{ + u8 i; + + if (basic_rates == 0) + return; /* assume basic rates unknown and accept rate */ + if (*idx < 0) + return; + if (basic_rates & (1 << *idx)) + return; /* selected rate is a basic rate */ + + for (i = *idx + 1; i <= max_rate_idx; i++) { + if (basic_rates & (1 << i)) { + *idx = i; + return; + } + } + + /* could not find a basic rate; use original selection */ +} + bool rate_control_send_low(struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) @@ -218,6 +239,10 @@ bool rate_control_send_low(struct ieee80211_sta *sta, info->control.rates[0].count = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 1 : txrc->hw->max_rate_tries; + if (!sta && txrc->ap) + rc_send_low_broadcast(&info->control.rates[0].idx, + txrc->bss_conf->basic_rates, + txrc->sband->n_bitrates); return true; } return false; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 140da4a7f13d..4961168f5091 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -520,6 +520,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.skb = tx->skb; txrc.reported_rate.idx = -1; txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; + txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; /* set up RTS protection if desired */ if (len > tx->local->hw.wiphy->rts_threshold) { @@ -2060,6 +2061,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct beacon_data *beacon; struct ieee80211_supported_band *sband; enum ieee80211_band band = local->hw.conf.channel->band; + struct ieee80211_tx_rate_control txrc; sband = local->hw.wiphy->bands[band]; @@ -2167,21 +2169,21 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + info->flags |= IEEE80211_TX_CTL_NO_ACK; info->band = band; - /* - * XXX: For now, always use the lowest rate - */ - info->control.rates[0].idx = 0; - info->control.rates[0].count = 1; - info->control.rates[1].idx = -1; - info->control.rates[2].idx = -1; - info->control.rates[3].idx = -1; - info->control.rates[4].idx = -1; - BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); + + memset(&txrc, 0, sizeof(txrc)); + txrc.hw = hw; + txrc.sband = sband; + txrc.bss_conf = &sdata->vif.bss_conf; + txrc.skb = skb; + txrc.reported_rate.idx = -1; + txrc.max_rate_idx = sdata->max_ratectrl_rateidx; + txrc.ap = true; + rate_control_get_rate(sdata, NULL, &txrc); info->control.vif = vif; - info->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; out: -- GitLab From 37eb0b164cf9fa9f70c8500926f5cde7c652f48e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 6 Jan 2010 13:09:08 +0200 Subject: [PATCH 0532/3892] cfg80211/mac80211: Use more generic bitrate mask for rate control Extend struct cfg80211_bitrate_mask to actually use a bitfield mask instead of just a single fixed or maximum rate index. This change itself does not modify the behavior (except for debugfs files), but it prepares cfg80211 and mac80211 for a new nl80211 command for setting which rates can be used in TX rate control. Since frames are now going through the rate control algorithm unconditionally, the internal IEEE80211_TX_INTFL_RCALGO flag can now be removed. The RC implementations can use the rate_idx_mask value to optimize their behavior if only a single rate is enabled. The old max_rate_idx in struct ieee80211_tx_rate_control is maintained (but commented as deprecated) for backwards compatibility with existing RC implementations. Once these implementations have been updated to use the more generic rate_idx_mask, the max_rate_idx value can be removed. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- include/net/cfg80211.h | 13 ++------ include/net/mac80211.h | 8 ++--- net/mac80211/cfg.c | 32 ++---------------- net/mac80211/debugfs_netdev.c | 22 ++++++------ net/mac80211/ieee80211_i.h | 4 +-- net/mac80211/iface.c | 8 +++-- net/mac80211/rate.c | 63 +++++++++++++++++++++++++++++------ net/mac80211/rate.h | 5 +-- net/mac80211/tx.c | 12 +++++-- net/wireless/wext-compat.c | 34 ++++++++++++++++--- 10 files changed, 122 insertions(+), 79 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a8d5d04314b9..22e062afb5a1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -857,20 +857,11 @@ enum tx_power_setting { * cfg80211_bitrate_mask - masks for bitrate control */ struct cfg80211_bitrate_mask { -/* - * As discussed in Berlin, this struct really - * should look like this: - struct { u32 legacy; - u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; + /* TODO: add support for masking MCS rates; e.g.: */ + /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ } control[IEEE80211_NUM_BANDS]; - - * Since we can always fix in-kernel users, let's keep - * it simpler for now: - */ - u32 fixed; /* fixed bitrate, 0 == not fixed */ - u32 maxrate; /* in kbps, 0 == no limit */ }; /** * struct cfg80211_pmksa - PMK Security Association diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 39c516c352be..7e5af6d90b93 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -255,9 +255,6 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be * set by rate control algorithms to indicate probe rate, will * be cleared for fragmented frames (except on the last fragment) - * @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or - * set this flag in the driver; indicates that the rate control - * algorithm was used and should be notified of TX status * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, * used to indicate that a pending frame requires TX processing before * it can be sent out. @@ -287,7 +284,6 @@ enum mac80211_tx_control_flags { IEEE80211_TX_STAT_AMPDU = BIT(10), IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), - IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), @@ -2297,6 +2293,9 @@ enum rate_control_changed { * @short_preamble: whether mac80211 will request short-preamble transmission * if the selected rate supports it * @max_rate_idx: user-requested maximum rate (not MCS for now) + * (deprecated; this will be removed once drivers get updated to use + * rate_idx_mask) + * @rate_idx_mask: user-requested rate mask (not MCS for now) * @skb: the skb that will be transmitted, the control information in it needs * to be filled in * @ap: whether this frame is sent out in AP mode @@ -2309,6 +2308,7 @@ struct ieee80211_tx_rate_control { struct ieee80211_tx_rate reported_rate; bool rts, short_preamble; u8 max_rate_idx; + u32 rate_idx_mask; bool ap; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 976014c5e742..e5dda6fb8dff 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1406,8 +1406,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int i; - u32 target_rate; - struct ieee80211_supported_band *sband; /* * This _could_ be supported by providing a hook for @@ -1417,35 +1415,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) return -EOPNOTSUPP; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* - * target_rate = -1, rate->fixed = 0 means auto only, so use all rates - * target_rate = X, rate->fixed = 1 means only rate X - * target_rate = X, rate->fixed = 0 means all rates <= X - */ - sdata->max_ratectrl_rateidx = -1; - sdata->force_unicast_rateidx = -1; - if (mask->fixed) - target_rate = mask->fixed / 100; - else if (mask->maxrate) - target_rate = mask->maxrate / 100; - else - return 0; + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + sdata->rc_rateidx_mask[i] = mask->control[i].legacy; - for (i = 0; i< sband->n_bitrates; i++) { - if (target_rate != sband->bitrates[i].bitrate) - continue; - - /* requested bitrate found */ - sdata->max_ratectrl_rateidx = i; - if (mask->fixed) - sdata->force_unicast_rateidx = i; - return 0; - } - - return -EINVAL; + return 0; } static int ieee80211_remain_on_channel(struct wiphy *wiphy, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 59f6e3bcbd09..1481049f0f71 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -127,8 +127,10 @@ __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) /* common attributes */ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); -IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); -IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); +IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], + HEX); +IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], + HEX); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); @@ -264,8 +266,8 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(force_unicast_rateidx, sta); - DEBUGFS_ADD(max_ratectrl_rateidx, sta); + DEBUGFS_ADD(rc_rateidx_mask_2ghz, sta); + DEBUGFS_ADD(rc_rateidx_mask_5ghz, sta); DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(aid, sta); @@ -275,8 +277,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) static void add_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, ap); - DEBUGFS_ADD(force_unicast_rateidx, ap); - DEBUGFS_ADD(max_ratectrl_rateidx, ap); + DEBUGFS_ADD(rc_rateidx_mask_2ghz, ap); + DEBUGFS_ADD(rc_rateidx_mask_5ghz, ap); DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(dtim_count, ap); @@ -286,8 +288,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(force_unicast_rateidx, wds); - DEBUGFS_ADD(max_ratectrl_rateidx, wds); + DEBUGFS_ADD(rc_rateidx_mask_2ghz, wds); + DEBUGFS_ADD(rc_rateidx_mask_5ghz, wds); DEBUGFS_ADD(peer, wds); } @@ -295,8 +297,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(force_unicast_rateidx, vlan); - DEBUGFS_ADD(max_ratectrl_rateidx, vlan); + DEBUGFS_ADD(rc_rateidx_mask_2ghz, vlan); + DEBUGFS_ADD(rc_rateidx_mask_5ghz, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a27921ee6e63..3e4ac3f30857 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -494,8 +494,8 @@ struct ieee80211_sub_if_data { */ struct ieee80211_if_ap *bss; - int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ - int max_ratectrl_rateidx; /* max TX rateidx for rate control */ + /* bitmap of allowed (non-MCS) rate indexes for rate control */ + u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; union { struct ieee80211_if_ap ap; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 264a6c975f8b..fe140bf033f9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -856,8 +856,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, INIT_LIST_HEAD(&sdata->key_list); - sdata->force_unicast_rateidx = -1; - sdata->max_ratectrl_rateidx = -1; + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + struct ieee80211_supported_band *sband; + sband = local->hw.wiphy->bands[i]; + sdata->rc_rateidx_mask[i] = + sband ? (1 << sband->n_bitrates) - 1 : 0; + } /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 6349e7f4dcae..c74b7c85403c 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -249,6 +249,38 @@ bool rate_control_send_low(struct ieee80211_sta *sta, } EXPORT_SYMBOL(rate_control_send_low); +static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, + int n_bitrates, u32 mask) +{ + int j; + + /* See whether the selected rate or anything below it is allowed. */ + for (j = rate->idx; j >= 0; j--) { + if (mask & (1 << j)) { + /* Okay, found a suitable rate. Use it. */ + rate->idx = j; + return; + } + } + + /* Try to find a higher rate that would be allowed */ + for (j = rate->idx + 1; j < n_bitrates; j++) { + if (mask & (1 << j)) { + /* Okay, found a suitable rate. Use it. */ + rate->idx = j; + return; + } + } + + /* + * Uh.. No suitable rate exists. This should not really happen with + * sane TX rate mask configurations. However, should someone manage to + * configure supported rates and TX rate mask in incompatible way, + * allow the frame to be transmitted with whatever the rate control + * selected. + */ +} + void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc) @@ -258,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta *ista = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); int i; + u32 mask; if (sta) { ista = &sta->sta; @@ -270,23 +303,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, info->control.rates[i].count = 1; } - if (sta && sdata->force_unicast_rateidx > -1) { - info->control.rates[0].idx = sdata->force_unicast_rateidx; - } else { - ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); - info->flags |= IEEE80211_TX_INTFL_RCALGO; - } + ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); /* - * try to enforce the maximum rate the user wanted + * Try to enforce the rateidx mask the user wanted. skip this if the + * default mask (allow all rates) is used to save some processing for + * the common case. */ - if (sdata->max_ratectrl_rateidx > -1) + mask = sdata->rc_rateidx_mask[info->band]; + if (mask != (1 << txrc->sband->n_bitrates) - 1) { + if (sta) { + /* Filter out rates that the STA does not support */ + mask &= sta->sta.supp_rates[info->band]; + } + /* + * Make sure the rate index selected for each TX rate is + * included in the configured mask and change the rate indexes + * if needed. + */ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* Rate masking supports only legacy rates for now */ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) continue; - info->control.rates[i].idx = - min_t(s8, info->control.rates[i].idx, - sdata->max_ratectrl_rateidx); + rate_idx_match_mask(&info->control.rates[i], + txrc->sband->n_bitrates, mask); + } } BUG_ON(info->control.rates[0].idx < 0); diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index cb9bd1f65e27..669dddd40521 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -44,10 +44,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) - ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); + ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4961168f5091..d3a44812f8bf 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -519,7 +519,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.bss_conf = &tx->sdata->vif.bss_conf; txrc.skb = tx->skb; txrc.reported_rate.idx = -1; - txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; + txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; + if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) + txrc.max_rate_idx = -1; + else + txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; /* set up RTS protection if desired */ @@ -2178,7 +2182,11 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, txrc.bss_conf = &sdata->vif.bss_conf; txrc.skb = skb; txrc.reported_rate.idx = -1; - txrc.max_rate_idx = sdata->max_ratectrl_rateidx; + txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; + if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) + txrc.max_rate_idx = -1; + else + txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; txrc.ap = true; rate_control_get_rate(sdata, NULL, &txrc); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4198243a3dff..966d2f01beac 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev, struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_bitrate_mask mask; + u32 fixed, maxrate; + struct ieee80211_supported_band *sband; + int band, ridx; + bool match = false; if (!rdev->ops->set_bitrate_mask) return -EOPNOTSUPP; - mask.fixed = 0; - mask.maxrate = 0; + memset(&mask, 0, sizeof(mask)); + fixed = 0; + maxrate = 0; if (rate->value < 0) { /* nothing */ } else if (rate->fixed) { - mask.fixed = rate->value / 1000; /* kbps */ + fixed = rate->value / 100000; } else { - mask.maxrate = rate->value / 1000; /* kbps */ + maxrate = rate->value / 100000; + } + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wdev->wiphy->bands[band]; + if (sband == NULL) + continue; + for (ridx = 0; ridx < sband->n_bitrates; ridx++) { + struct ieee80211_rate *srate = &sband->bitrates[ridx]; + if (fixed == srate->bitrate) { + mask.control[band].legacy = 1 << ridx; + match = true; + break; + } + if (srate->bitrate <= maxrate) { + mask.control[band].legacy |= 1 << ridx; + match = true; + } + } } + if (!match) + return -EINVAL; + return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); } EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); -- GitLab From 13ae75b103e07304a34ab40c9136e9f53e06475c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 29 Dec 2009 12:59:45 +0200 Subject: [PATCH 0533/3892] nl80211: New command for setting TX rate mask for rate control Add a new NL80211_CMD_SET_TX_BITRATE_MASK command and related attributes to provide support for setting TX rate mask for rate control. This uses the existing cfg80211 set_bitrate_mask operation that was previously used only with WEXT compat code (SIOCSIWRATE). The nl80211 command allows more generic configuration of allowed rates as a mask instead of fixed/max rate. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 44 ++++++++++++++++ include/net/cfg80211.h | 4 +- net/wireless/nl80211.c | 111 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index d4c556de7170..7a1c8c145b22 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -295,6 +295,10 @@ * This command is also used as an event to notify when a requested * remain-on-channel duration has expired. * + * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX + * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface + * and @NL80211_ATTR_TX_RATES the set of allowed rates. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -381,6 +385,8 @@ enum nl80211_commands { NL80211_CMD_REMAIN_ON_CHANNEL, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + NL80211_CMD_SET_TX_BITRATE_MASK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -640,6 +646,13 @@ enum nl80211_commands { * * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. * + * @NL80211_ATTR_TX_RATES: Nested set of attributes + * (enum nl80211_tx_rate_attributes) describing TX rates per band. The + * enum nl80211_band value is used as the index (nla_type() of the nested + * data. If a band is not included, it will be configured to allow all + * rates based on negotiated supported rates information. This attribute + * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -783,6 +796,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_COVERAGE_CLASS, + NL80211_ATTR_TX_RATES, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1482,4 +1497,33 @@ enum nl80211_key_attributes { NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 }; +/** + * enum nl80211_tx_rate_attributes - TX rate set attributes + * @__NL80211_TXRATE_INVALID: invalid + * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection + * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with + * 1 = 500 kbps) but without the IE length restriction (at most + * %NL80211_MAX_SUPP_RATES in a single array). + * @__NL80211_TXRATE_AFTER_LAST: internal + * @NL80211_TXRATE_MAX: highest TX rate attribute + */ +enum nl80211_tx_rate_attributes { + __NL80211_TXRATE_INVALID, + NL80211_TXRATE_LEGACY, + + /* keep last */ + __NL80211_TXRATE_AFTER_LAST, + NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band - Frequency band + * @NL80211_BAND_2GHZ - 2.4 GHz ISM band + * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz) + */ +enum nl80211_band { + NL80211_BAND_2GHZ, + NL80211_BAND_5GHZ, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 22e062afb5a1..0d734413b5fb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -39,8 +39,8 @@ * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) */ enum ieee80211_band { - IEEE80211_BAND_2GHZ, - IEEE80211_BAND_5GHZ, + IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, /* keep last */ IEEE80211_NUM_BANDS diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c09fbcd278fb..b804062e0179 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -144,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { .len = WLAN_PMKID_LEN }, [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, + [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, }; /* policy for the attributes */ @@ -575,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(del_pmksa, DEL_PMKSA); CMD(flush_pmksa, FLUSH_PMKSA); CMD(remain_on_channel, REMAIN_ON_CHANNEL); + CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -4438,6 +4440,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, return err; } +static u32 rateset_to_mask(struct ieee80211_supported_band *sband, + u8 *rates, u8 rates_len) +{ + u8 i; + u32 mask = 0; + + for (i = 0; i < rates_len; i++) { + int rate = (rates[i] & 0x7f) * 5; + int ridx; + for (ridx = 0; ridx < sband->n_bitrates; ridx++) { + struct ieee80211_rate *srate = + &sband->bitrates[ridx]; + if (rate == srate->bitrate) { + mask |= 1 << ridx; + break; + } + } + if (ridx == sband->n_bitrates) + return 0; /* rate not found */ + } + + return mask; +} + +static struct nla_policy +nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { + [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, +}; + +static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *tb[NL80211_TXRATE_MAX + 1]; + struct cfg80211_registered_device *rdev; + struct cfg80211_bitrate_mask mask; + int err, rem, i; + struct net_device *dev; + struct nlattr *tx_rates; + struct ieee80211_supported_band *sband; + + if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + if (!rdev->ops->set_bitrate_mask) { + err = -EOPNOTSUPP; + goto unlock; + } + + memset(&mask, 0, sizeof(mask)); + /* Default to all rates enabled */ + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + sband = rdev->wiphy.bands[i]; + mask.control[i].legacy = + sband ? (1 << sband->n_bitrates) - 1 : 0; + } + + /* + * The nested attribute uses enum nl80211_band as the index. This maps + * directly to the enum ieee80211_band values used in cfg80211. + */ + nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) + { + enum ieee80211_band band = nla_type(tx_rates); + if (band < 0 || band >= IEEE80211_NUM_BANDS) { + err = -EINVAL; + goto unlock; + } + sband = rdev->wiphy.bands[band]; + if (sband == NULL) { + err = -EINVAL; + goto unlock; + } + nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), + nla_len(tx_rates), nl80211_txattr_policy); + if (tb[NL80211_TXRATE_LEGACY]) { + mask.control[band].legacy = rateset_to_mask( + sband, + nla_data(tb[NL80211_TXRATE_LEGACY]), + nla_len(tb[NL80211_TXRATE_LEGACY])); + if (mask.control[band].legacy == 0) { + err = -EINVAL; + goto unlock; + } + } + } + + err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); + + unlock: + dev_put(dev); + cfg80211_unlock_rdev(rdev); + unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4712,6 +4817,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, + .doit = nl80211_set_tx_bitrate_mask, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { -- GitLab From 6c0fe26581406bff3d15fd6051453e80cfe70fd6 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 30 Dec 2009 11:36:31 +0100 Subject: [PATCH 0534/3892] rt2x00: RF3052 is a valid RF chipset for USB devices as well. The RF3052 chipset is now also being integrated onto USB devices, so allow the RF chipset and don't treat it as PCI/SOC only. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 126899091707..d300ff84b717 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1862,7 +1862,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(rt2x00dev, RF3020) && !rt2x00_rf(rt2x00dev, RF2020) && !rt2x00_rf(rt2x00dev, RF3021) && - !rt2x00_rf(rt2x00dev, RF3022)) { + !rt2x00_rf(rt2x00dev, RF3022) && + !rt2x00_rf(rt2x00dev, RF3052)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2047,7 +2048,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) if (rt2x00_rf(rt2x00dev, RF2820) || rt2x00_rf(rt2x00dev, RF2720) || - (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) { + rt2x00_rf(rt2x00dev, RF3052)) { spec->num_channels = 14; spec->channels = rf_vals; } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { -- GitLab From 67a4c1e24d58e0d88ed88539641631f6fc8a0cfd Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 30 Dec 2009 11:36:32 +0100 Subject: [PATCH 0535/3892] rt2x00: Unify rt2800 WPDMA ready waiting functions. The rt2800pci_wait_wpdma_ready and rt2800usb_wait_wpdma_ready functions are exactly the same, so unify them into rt200lib. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 19 +++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 1 + drivers/net/wireless/rt2x00/rt2800pci.c | 24 +++--------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 22 ++-------------------- 4 files changed, 25 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d300ff84b717..ca700a402e64 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -245,6 +245,25 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_mcu_request); +int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} +EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready); + #ifdef CONFIG_RT2X00_LIB_DEBUGFS const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 535ce22f2ac8..9adb3431374d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -139,6 +139,7 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); +int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b93eabb4fbe1..daea0b7c416e 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -453,24 +453,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); } -static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u32 reg; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && - !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) - return 0; - - msleep(1); - } - - ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); - return -EACCES; -} - static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -479,10 +461,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) || + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || rt2800pci_init_queues(rt2x00dev) || rt2800_init_registers(rt2x00dev) || - rt2800pci_wait_wpdma_ready(rt2x00dev) || + rt2800_wait_wpdma_ready(rt2x00dev) || rt2800_init_bbp(rt2x00dev) || rt2800_init_rfcsr(rt2x00dev))) return -EIO; @@ -562,7 +544,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); /* Wait for DMA, ignore error */ - rt2800pci_wait_wpdma_ready(rt2x00dev); + rt2800_wait_wpdma_ready(rt2x00dev); } static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0510f020dcf5..82755cf8b73e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -248,24 +248,6 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } -static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u32 reg; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && - !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) - return 0; - - msleep(1); - } - - ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); - return -EACCES; -} - static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -274,7 +256,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || rt2800_init_registers(rt2x00dev) || rt2800_init_bbp(rt2x00dev) || rt2800_init_rfcsr(rt2x00dev))) @@ -344,7 +326,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); /* Wait for DMA, ignore error */ - rt2800usb_wait_wpdma_ready(rt2x00dev); + rt2800_wait_wpdma_ready(rt2x00dev); rt2x00usb_disable_radio(rt2x00dev); } -- GitLab From b3579d6adcf7b24464274967a96d12467cfb11a7 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 30 Dec 2009 11:36:34 +0100 Subject: [PATCH 0536/3892] rt2x00: Make rt2800_init_led static and don't export it. It is only used within the rt2800lib module itself. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 3 +-- drivers/net/wireless/rt2x00/rt2800lib.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ca700a402e64..529a37364eb0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -366,7 +366,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev, return 0; } -void rt2800_init_led(struct rt2x00_dev *rt2x00dev, +static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, struct rt2x00_led *led, enum led_type type) { led->rt2x00dev = rt2x00dev; @@ -375,7 +375,6 @@ void rt2800_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2800_blink_set; led->flags = LED_INITIALIZED; } -EXPORT_SYMBOL_GPL(rt2800_init_led); #endif /* CONFIG_RT2X00_LIB_LEDS */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 9adb3431374d..ebabeae62d1b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -114,8 +114,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, extern const struct rt2x00debug rt2800_rt2x00debug; int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev); -void rt2800_init_led(struct rt2x00_dev *rt2x00dev, - struct rt2x00_led *led, enum led_type type); int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); -- GitLab From 7044cc565b45a898c140fb185174a66f2d68a163 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:19 +0200 Subject: [PATCH 0537/3892] mac80211: add functions to create PS Poll and Nullfunc templates Some hardware, for example wl1251 and wl1271, handle the transmission of power save related frames in hardware, but the driver is responsible for creating the templates. It's better to create the templates in mac80211, that way all drivers can benefit from this. Add two new functions, ieee80211_pspoll_get() and ieee80211_nullfunc_get() which drivers need to call to get the frame. Drivers are also responsible for updating the templates after each association. Also new struct ieee80211_hdr_3addr is added to ieee80211.h to make it easy to calculate length of the Nullfunc frame. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 9 +++++ include/net/mac80211.h | 30 +++++++++++++++ net/mac80211/tx.c | 78 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index aeea282bd2fe..602c0692c3fc 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -130,6 +130,15 @@ struct ieee80211_hdr { u8 addr4[6]; } __attribute__ ((packed)); +struct ieee80211_hdr_3addr { + __le16 frame_control; + __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; +} __attribute__ ((packed)); + /** * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set * @fc: frame control bytes in little-endian byteorder diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7e5af6d90b93..75f46e26ad60 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1874,6 +1874,36 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); } +/** + * ieee80211_pspoll_get - retrieve a PS Poll template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a PS Poll a template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * AID, BSSID and MAC address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit. + */ +struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_nullfunc_get - retrieve a nullfunc template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Nullfunc template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * BSSID and address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. + */ +struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d3a44812f8bf..055b45b146d9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2200,6 +2200,84 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_beacon_get_tim); +struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_managed *ifmgd; + struct ieee80211_pspoll *pspoll; + struct ieee80211_local *local; + struct sk_buff *skb; + + if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) + return NULL; + + sdata = vif_to_sdata(vif); + ifmgd = &sdata->u.mgd; + local = sdata->local; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for " + "pspoll template\n", sdata->name); + return NULL; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); + memset(pspoll, 0, sizeof(*pspoll)); + pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_PSPOLL); + pspoll->aid = cpu_to_le16(ifmgd->aid); + + /* aid in PS-Poll has its two MSBs each set to 1 */ + pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); + + memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(pspoll->ta, vif->addr, ETH_ALEN); + + return skb; +} +EXPORT_SYMBOL(ieee80211_pspoll_get); + +struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ieee80211_hdr_3addr *nullfunc; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_managed *ifmgd; + struct ieee80211_local *local; + struct sk_buff *skb; + + if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) + return NULL; + + sdata = vif_to_sdata(vif); + ifmgd = &sdata->u.mgd; + local = sdata->local; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "template\n", sdata->name); + return NULL; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb, + sizeof(*nullfunc)); + memset(nullfunc, 0, sizeof(*nullfunc)); + nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); + memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); + memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); + + return skb; +} +EXPORT_SYMBOL(ieee80211_nullfunc_get); + void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_info *frame_txctl, -- GitLab From d8cd189e9b1e050629f545e76b21a321f62c29bf Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:26 +0200 Subject: [PATCH 0538/3892] mac80211: use PS Poll and Nullfunc templates when sending such frames To avoid duplicate code, use ieee80211_[pspoll|nullfunc]_get() to get templates for PS Poll and Nullfunc frames in mlme.c. Compile-tested only. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 48 +++++++++------------------------------------ 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 97bcf2278bdb..5484cf930a87 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -249,30 +249,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_pspoll *pspoll; struct sk_buff *skb; - u16 fc; - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for " - "pspoll frame\n", sdata->name); + skb = ieee80211_pspoll_get(&local->hw, &sdata->vif); + if (!skb) return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); - memset(pspoll, 0, sizeof(*pspoll)); - fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; - pspoll->frame_control = cpu_to_le16(fc); - pspoll->aid = cpu_to_le16(ifmgd->aid); - /* aid in PS-Poll has its two MSBs each set to 1 */ - pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); - - memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); - memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN); + pspoll = (struct ieee80211_pspoll *) skb->data; + pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -283,30 +268,15 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, int powersave) { struct sk_buff *skb; - struct ieee80211_hdr *nullfunc; - __le16 fc; + struct ieee80211_hdr_3addr *nullfunc; - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); + if (!skb) return; - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "frame\n", sdata->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(nullfunc, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); + nullfunc = (struct ieee80211_hdr_3addr *) skb->data; if (powersave) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - nullfunc->frame_control = fc; - memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); - memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); + nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); -- GitLab From f7f70579340dba1e551c0e52349fde0370592174 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:32 +0200 Subject: [PATCH 0539/3892] wl1251: get PS Poll and Nullfunc templates from mac80211 Now that mac80211 creates templates for PS Poll and Nullfunc frames, use them instead of creating our own. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 58 +++++++---------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 4e373f3dbc43..6cce86462fac 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -563,45 +563,6 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int wl1251_build_null_data(struct wl1251 *wl) -{ - struct wl12xx_null_data_template template; - - if (!is_zero_ether_addr(wl->bssid)) { - memcpy(template.header.da, wl->bssid, ETH_ALEN); - memcpy(template.header.bssid, wl->bssid, ETH_ALEN); - } else { - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - } - - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - - return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, - sizeof(template)); - -} - -static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) -{ - struct wl12xx_ps_poll_template template; - - memcpy(template.bssid, wl->bssid, ETH_ALEN); - memcpy(template.ta, wl->mac_addr, ETH_ALEN); - - /* aid in PS-Poll has its two MSBs each set to 1 */ - template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); - - template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - - return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, - sizeof(template)); - -} - static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1251 *wl = hw->priv; @@ -1101,7 +1062,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, { enum wl1251_cmd_ps_mode mode; struct wl1251 *wl = hw->priv; - struct sk_buff *beacon; + struct sk_buff *beacon, *skb; int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); @@ -1115,7 +1076,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - ret = wl1251_build_null_data(wl); + skb = ieee80211_nullfunc_get(wl->hw, wl->vif); + if (!skb) + goto out_sleep; + + ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, + skb->data, skb->len); + dev_kfree_skb(skb); if (ret < 0) goto out; @@ -1136,7 +1103,14 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, wl->dtim_period); wl->aid = bss_conf->aid; - ret = wl1251_build_ps_poll(wl, wl->aid); + skb = ieee80211_pspoll_get(wl->hw, wl->vif); + if (!skb) + goto out_sleep; + + ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, + skb->data, + skb->len); + dev_kfree_skb(skb); if (ret < 0) goto out_sleep; -- GitLab From 05e54ea6cce400ac34528d705179b45244f61074 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:38 +0200 Subject: [PATCH 0540/3892] mac80211: create Probe Request template Certain type of hardware, for example wl1251 and wl1271, need a template for the Probe Request. Create a function ieee80211_probereq_get() which creates the template and drivers send it to hardware. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/net/mac80211.h | 17 ++++++++++++++ net/mac80211/tx.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 75f46e26ad60..e1e73c6abeff 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1904,6 +1904,23 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +/** + * ieee80211_probereq_get - retrieve a Probe Request template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ssid: SSID buffer + * @ssid_len: length of SSID + * @ie: buffer containing all IEs except SSID for the template + * @ie_len: length of the IE buffer + * + * Creates a Probe Request template which can, for example, be uploaded to + * hardware. + */ +struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); + /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 055b45b146d9..0661e696a1dd 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2278,6 +2278,56 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_nullfunc_get); +struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; + struct ieee80211_hdr_3addr *hdr; + struct sk_buff *skb; + size_t ie_ssid_len; + u8 *pos; + + sdata = vif_to_sdata(vif); + local = sdata->local; + ie_ssid_len = 2 + ssid_len; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + + ie_ssid_len + ie_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for probe " + "request template\n", sdata->name); + return NULL; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + + hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_REQ); + memset(hdr->addr1, 0xff, ETH_ALEN); + memcpy(hdr->addr2, vif->addr, ETH_ALEN); + memset(hdr->addr3, 0xff, ETH_ALEN); + + pos = skb_put(skb, ie_ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ssid_len; + if (ssid) + memcpy(pos, ssid, ssid_len); + pos += ssid_len; + + if (ie) { + pos = skb_put(skb, ie_len); + memcpy(pos, ie, ie_len); + } + + return skb; +} +EXPORT_SYMBOL(ieee80211_probereq_get); + void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_info *frame_txctl, -- GitLab From 7c12ce8b854df346388ea56d684784e3484012cf Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:44 +0200 Subject: [PATCH 0541/3892] mac80211: use Probe Request template when sending a direct scan As mac80211 now has a separate function for creating Probe Request templates, better to use it when sending direct Probe Requests to an AP. Only the bssid needs to be updated in the template before sending it. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/util.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index bc73904d561c..72a98e844718 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1000,37 +1000,29 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + - ie_len); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "request\n", sdata->name); + size_t buf_len; + u8 *buf; + + /* FIXME: come up with a proper value */ + buf = kmalloc(200 + ie_len, GFP_KERNEL); + if (!buf) { + printk(KERN_DEBUG "%s: failed to allocate temporary IE " + "buffer\n", sdata->name); return; } - skb_reserve(skb, local->hw.extra_tx_headroom); - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_REQ); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, + local->hw.conf.channel->band); + + skb = ieee80211_probereq_get(&local->hw, &sdata->vif, + ssid, ssid_len, + buf, buf_len); + if (dst) { + mgmt = (struct ieee80211_mgmt *) skb->data; memcpy(mgmt->da, dst, ETH_ALEN); memcpy(mgmt->bssid, dst, ETH_ALEN); - } else { - memset(mgmt->da, 0xff, ETH_ALEN); - memset(mgmt->bssid, 0xff, ETH_ALEN); } - pos = skb_put(skb, 2 + ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - memcpy(pos, ssid, ssid_len); - pos += ssid_len; - - skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, - local->hw.conf.channel->band)); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); -- GitLab From 3a98c30f3e8bb1f32b5bcb74a39647b3670de275 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:51 +0200 Subject: [PATCH 0542/3892] wl1251: cleanup scanning code The current scanning code wasn't following the preferred style. Move code related to scan and trigger scan to commans to wl1251_cmd.c. Because there's now less code in wl1251_hw_scan(), the function can be now merged with wl1251_op_hw_scan(). Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 82 ++++++++++++++ drivers/net/wireless/wl12xx/wl1251_cmd.h | 17 +-- drivers/net/wireless/wl12xx/wl1251_main.c | 125 +++++----------------- 3 files changed, 117 insertions(+), 107 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 770f260726bd..fcbfbd7585f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -410,3 +410,85 @@ out: kfree(cmd); return ret; } + +int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + unsigned int n_channels, unsigned int n_probes) +{ + struct wl1251_cmd_scan *cmd; + int i, ret = 0; + + wl1251_debug(DEBUG_CMD, "cmd scan"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | + CFG_RX_MGMT_EN | + CFG_RX_BCN_EN); + cmd->params.scan_options = 0; + cmd->params.num_channels = n_channels; + cmd->params.num_probe_requests = n_probes; + cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + cmd->params.tid_trigger = 0; + + for (i = 0; i < n_channels; i++) { + cmd->channels[i].min_duration = + cpu_to_le32(WL1251_SCAN_MIN_DURATION); + cmd->channels[i].max_duration = + cpu_to_le32(WL1251_SCAN_MAX_DURATION); + memset(&cmd->channels[i].bssid_lsb, 0xff, 4); + memset(&cmd->channels[i].bssid_msb, 0xff, 2); + cmd->channels[i].early_termination = 0; + cmd->channels[i].tx_power_att = 0; + cmd->channels[i].channel = i + 1; + } + + cmd->params.ssid_len = ssid_len; + if (ssid) + memcpy(cmd->params.ssid, ssid, ssid_len); + + ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("cmd scan failed: %d", ret); + goto out; + } + + wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) { + wl1251_error("cmd scan status wasn't success: %d", + cmd->header.status); + ret = -EIO; + goto out; + } + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) +{ + struct wl1251_cmd_trigger_scan_to *cmd; + int ret; + + wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->timeout = timeout; + + ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1251_error("cmd trigger scan to failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index dff798ad0ef5..63ae3193f7c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -43,6 +43,9 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); +int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + unsigned int n_channels, unsigned int n_probes); +int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); /* unit ms */ #define WL1251_COMMAND_TIMEOUT 2000 @@ -163,8 +166,10 @@ struct cmd_read_write_memory { #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 +#define WL1251_SCAN_MIN_DURATION 30000 +#define WL1251_SCAN_MAX_DURATION 60000 -struct basic_scan_parameters { +struct wl1251_scan_parameters { u32 rx_config_options; u32 rx_filter_options; @@ -189,11 +194,11 @@ struct basic_scan_parameters { u8 tid_trigger; u8 ssid_len; - u32 ssid[8]; + u8 ssid[32]; } __attribute__ ((packed)); -struct basic_scan_channel_parameters { +struct wl1251_scan_ch_parameters { u32 min_duration; /* in TU */ u32 max_duration; /* in TU */ u32 bssid_lsb; @@ -213,11 +218,11 @@ struct basic_scan_channel_parameters { /* SCAN parameters */ #define SCAN_MAX_NUM_OF_CHANNELS 16 -struct cmd_scan { +struct wl1251_cmd_scan { struct wl1251_cmd_header header; - struct basic_scan_parameters params; - struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; + struct wl1251_scan_parameters params; + struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; } __attribute__ ((packed)); enum { diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 6cce86462fac..e038707294a5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -903,111 +903,13 @@ static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) size); } -static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, - u8 active_scan, u8 high_prio, u8 num_channels, - u8 probe_requests) -{ - struct wl1251_cmd_trigger_scan_to *trigger = NULL; - struct cmd_scan *params = NULL; - int i, ret; - u16 scan_options = 0; - - if (wl->scanning) - return -EINVAL; - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - params->params.rx_filter_options = - cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - - /* High priority scan */ - if (!active_scan) - scan_options |= SCAN_PASSIVE; - if (high_prio) - scan_options |= SCAN_PRIORITY_HIGH; - params->params.scan_options = scan_options; - - params->params.num_channels = num_channels; - params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - params->params.tid_trigger = 0; - - for (i = 0; i < num_channels; i++) { - params->channels[i].min_duration = cpu_to_le32(30000); - params->channels[i].max_duration = cpu_to_le32(60000); - memset(¶ms->channels[i].bssid_lsb, 0xff, 4); - memset(¶ms->channels[i].bssid_msb, 0xff, 2); - params->channels[i].early_termination = 0; - params->channels[i].tx_power_att = 0; - params->channels[i].channel = i + 1; - memset(params->channels[i].pad, 0, 3); - } - - for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) - memset(¶ms->channels[i], 0, - sizeof(struct basic_scan_channel_parameters)); - - if (len && ssid) { - params->params.ssid_len = len; - memcpy(params->params.ssid, ssid, len); - } else { - params->params.ssid_len = 0; - memset(params->params.ssid, 0, 32); - } - - ret = wl1251_build_probe_req(wl, ssid, len); - if (ret < 0) { - wl1251_error("PROBE request template failed"); - goto out; - } - - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!trigger) - goto out; - - trigger->timeout = 0; - - ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger)); - if (ret < 0) { - wl1251_error("trigger scan to failed for hw scan"); - goto out; - } - - wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - - wl->scanning = true; - - ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); - if (ret < 0) - wl1251_error("SCAN failed"); - - wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - - if (params->header.status != CMD_STATUS_SUCCESS) { - wl1251_error("TEST command answer error: %d", - params->header.status); - wl->scanning = false; - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; - -} - static int wl1251_op_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct wl1251 *wl = hw->priv; - int ret; - u8 *ssid = NULL; size_t ssid_len = 0; + u8 *ssid = NULL; + int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); @@ -1018,12 +920,33 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); + if (wl->scanning) { + wl1251_debug(DEBUG_SCAN, "scan already in progress"); + ret = -EINVAL; + goto out; + } + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + ret = wl1251_build_probe_req(wl, ssid, ssid_len); + if (ret < 0) + wl1251_error("probe request template build failed"); + + ret = wl1251_cmd_trigger_scan_to(wl, 0); + if (ret < 0) + goto out_sleep; + + wl->scanning = true; + ret = wl1251_cmd_scan(wl, ssid, ssid_len, 13, 3); + if (ret < 0) { + wl->scanning = false; + goto out_sleep; + } + +out_sleep: wl1251_ps_elp_sleep(wl); out: -- GitLab From e477c56e852c4c6db1f7665c642c9f45f76616a9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:16:57 +0200 Subject: [PATCH 0543/3892] wl1251: get probe request template from mac80211 Instead of creating the template in driver, get it from mac80211 instead. Thanks to this, three functions can be now removed. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 86 ++++------------------- 1 file changed, 12 insertions(+), 74 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index e038707294a5..1db97229af47 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -831,82 +831,11 @@ out: return ret; } -static int wl1251_build_basic_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - - return index; -} - -static int wl1251_build_extended_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_OFDM_RATE_6MB; - rates[index++] = IEEE80211_OFDM_RATE_9MB; - rates[index++] = IEEE80211_OFDM_RATE_12MB; - rates[index++] = IEEE80211_OFDM_RATE_18MB; - rates[index++] = IEEE80211_OFDM_RATE_24MB; - rates[index++] = IEEE80211_OFDM_RATE_36MB; - rates[index++] = IEEE80211_OFDM_RATE_48MB; - rates[index++] = IEEE80211_OFDM_RATE_54MB; - - return index; -} - - -static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) -{ - struct wl12xx_probe_req_template template; - struct wl12xx_ie_rates *rates; - char *ptr; - u16 size; - - ptr = (char *)&template; - size = sizeof(struct ieee80211_header); - - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - - /* IEs */ - /* SSID */ - template.ssid.header.id = WLAN_EID_SSID; - template.ssid.header.len = ssid_len; - if (ssid_len && ssid) - memcpy(template.ssid.ssid, ssid, ssid_len); - size += sizeof(struct wl12xx_ie_header) + ssid_len; - ptr += size; - - /* Basic Rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl1251_build_basic_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; - - /* Extended rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl1251_build_extended_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - - wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - - return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, - size); -} - static int wl1251_op_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { struct wl1251 *wl = hw->priv; + struct sk_buff *skb; size_t ssid_len = 0; u8 *ssid = NULL; int ret; @@ -930,9 +859,18 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_build_probe_req(wl, ssid, ssid_len); + skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, + req->ie, req->ie_len); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, + skb->len); + dev_kfree_skb(skb); if (ret < 0) - wl1251_error("probe request template build failed"); + goto out_sleep; ret = wl1251_cmd_trigger_scan_to(wl, 0); if (ret < 0) -- GitLab From dc52f0a8e50303eb67ff8856cd8d1b461462ceec Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:17:03 +0200 Subject: [PATCH 0544/3892] wl1251: use mac80211 provided channel parameters in scanning The number of channels to be used in scan was hard coded in wl1251. The proper way is to use the channels array provided by mac80211. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 3 ++- drivers/net/wireless/wl12xx/wl1251_cmd.h | 5 +++++ drivers/net/wireless/wl12xx/wl1251_main.c | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index fcbfbd7585f8..0320b478bb3f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -412,6 +412,7 @@ out: } int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + struct ieee80211_channel *channels[], unsigned int n_channels, unsigned int n_probes) { struct wl1251_cmd_scan *cmd; @@ -442,7 +443,7 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, memset(&cmd->channels[i].bssid_msb, 0xff, 2); cmd->channels[i].early_termination = 0; cmd->channels[i].tx_power_att = 0; - cmd->channels[i].channel = i + 1; + cmd->channels[i].channel = channels[i]->hw_value; } cmd->params.ssid_len = ssid_len; diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index 63ae3193f7c6..4ad67cae94d2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -27,6 +27,8 @@ #include "wl1251.h" +#include + struct acx_header; int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); @@ -44,6 +46,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, + struct ieee80211_channel *channels[], unsigned int n_channels, unsigned int n_probes); int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); @@ -169,6 +172,8 @@ struct cmd_read_write_memory { #define WL1251_SCAN_MIN_DURATION 30000 #define WL1251_SCAN_MAX_DURATION 60000 +#define WL1251_SCAN_NUM_PROBES 3 + struct wl1251_scan_parameters { u32 rx_config_options; u32 rx_filter_options; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 1db97229af47..4728983b4383 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -878,7 +878,8 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, wl->scanning = true; - ret = wl1251_cmd_scan(wl, ssid, ssid_len, 13, 3); + ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, + req->n_channels, WL1251_SCAN_NUM_PROBES); if (ret < 0) { wl->scanning = false; goto out_sleep; -- GitLab From 80a112ffe8dbada25f3780ecc4beebf23451d755 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 5 Jan 2010 20:17:10 +0200 Subject: [PATCH 0545/3892] wl1251: fix sleep related error paths in wl1251_op_bss_info_changed() In various cases wl1251_op_bss_info_changed() did not call elp_sleep() after an error was noticed. Fix it by using correct goto label. The bug was a theoretical one, in practise it doesn't matter because if commands start returning errors there will be lots of other problems. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 4728983b4383..f17ce06b6c24 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -946,7 +946,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, skb->data, skb->len); dev_kfree_skb(skb); if (ret < 0) - goto out; + goto out_sleep; if (wl->bss_type != BSS_TYPE_IBSS) { ret = wl1251_join(wl, wl->bss_type, wl->channel, @@ -1018,7 +1018,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { wl1251_warning("Set ctsprotect failed %d", ret); - goto out; + goto out_sleep; } } @@ -1029,7 +1029,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) { dev_kfree_skb(beacon); - goto out; + goto out_sleep; } ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, @@ -1038,13 +1038,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, dev_kfree_skb(beacon); if (ret < 0) - goto out; + goto out_sleep; ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, wl->channel, wl->dtim_period); if (ret < 0) - goto out; + goto out_sleep; } out_sleep: -- GitLab From 34a6eddbabd704b3c7dae9362234552267573be2 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 6 Jan 2010 16:19:24 +0200 Subject: [PATCH 0546/3892] cfg80211: Store IEs from both Beacon and Probe Response frames Store information elements from Beacon and Probe Response frames in separate buffers to allow both sets to be made available through nl80211. This allows user space applications to get access to IEs from Beacon frames even if we have received Probe Response frames from the BSS. Previously, the IEs from Probe Response frames would have overridden the IEs from Beacon frames. This feature is of somewhat limited use since most protocols include the same (or extended) information in Probe Response frames. However, there are couple of exceptions where the IEs from Beacon frames could be of some use: TIM IE is only included in Beacon frames (and it would be needed to figure out the DTIM period used in the BSS) and at least some implementations of Wireless Provisioning Services seem to include the full IE only in Beacon frames). The new BSS attribute for scan results is added to allow both the IE sets to be delivered. This is done in a way that maintains the previously used behavior for applications that are not aware of the new NL80211_BSS_BEACON_IES attribute. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 10 +++- include/net/cfg80211.h | 12 +++- net/wireless/core.h | 3 +- net/wireless/nl80211.c | 4 ++ net/wireless/scan.c | 120 ++++++++++++++++++++++++++++++---------- 5 files changed, 116 insertions(+), 33 deletions(-) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 7a1c8c145b22..127a73015760 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1378,13 +1378,20 @@ enum nl80211_channel_type { * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the - * raw information elements from the probe response/beacon (bin) + * raw information elements from the probe response/beacon (bin); + * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are + * from a Probe Response frame; otherwise they are from a Beacon frame. + * However, if the driver does not indicate the source of the IEs, these + * IEs may be from either frame subtype. * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) * @NL80211_BSS_STATUS: status, if this BSS is "used" * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms + * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information + * elements from a Beacon frame (bin); not present if no Beacon frame has + * yet been received * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -1400,6 +1407,7 @@ enum nl80211_bss { NL80211_BSS_SIGNAL_UNSPEC, NL80211_BSS_STATUS, NL80211_BSS_SEEN_MS_AGO, + NL80211_BSS_BEACON_IES, /* keep last */ __NL80211_BSS_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0d734413b5fb..2af52704e670 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -626,8 +626,14 @@ enum cfg80211_signal_type { * @beacon_interval: the beacon interval as from the frame * @capability: the capability field in host byte order * @information_elements: the information elements (Note that there - * is no guarantee that these are well-formed!) + * is no guarantee that these are well-formed!); this is a pointer to + * either the beacon_ies or proberesp_ies depending on whether Probe + * Response frame has been received * @len_information_elements: total length of the information elements + * @beacon_ies: the information elements from the last Beacon frame + * @len_beacon_ies: total length of the beacon_ies + * @proberesp_ies: the information elements from the last Probe Response frame + * @len_proberesp_ies: total length of the proberesp_ies * @signal: signal strength value (type depends on the wiphy's signal_type) * @free_priv: function pointer to free private data * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes @@ -641,6 +647,10 @@ struct cfg80211_bss { u16 capability; u8 *information_elements; size_t len_information_elements; + u8 *beacon_ies; + size_t len_beacon_ies; + u8 *proberesp_ies; + size_t len_proberesp_ies; s32 signal; diff --git a/net/wireless/core.h b/net/wireless/core.h index 30ec95f05b52..2d6a6b9c0c43 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -111,7 +111,8 @@ struct cfg80211_internal_bss { unsigned long ts; struct kref ref; atomic_t hold; - bool ies_allocated; + bool beacon_ies_allocated; + bool proberesp_ies_allocated; /* must be last because of priv member */ struct cfg80211_bss pub; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b804062e0179..4af7991a9ec8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3163,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, res->len_information_elements, res->information_elements); + if (res->beacon_ies && res->len_beacon_ies && + res->beacon_ies != res->information_elements) + NLA_PUT(msg, NL80211_BSS_BEACON_IES, + res->len_beacon_ies, res->beacon_ies); if (res->tsf) NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); if (res->beacon_interval) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0c2cbbebca95..06b0231ee5e3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -100,8 +100,10 @@ static void bss_release(struct kref *ref) if (bss->pub.free_priv) bss->pub.free_priv(&bss->pub); - if (bss->ies_allocated) - kfree(bss->pub.information_elements); + if (bss->beacon_ies_allocated) + kfree(bss->pub.beacon_ies); + if (bss->proberesp_ies_allocated) + kfree(bss->pub.proberesp_ies); BUG_ON(atomic_read(&bss->hold)); @@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, static struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *res, - bool overwrite) + struct cfg80211_internal_bss *res) { struct cfg80211_internal_bss *found = NULL; const u8 *meshid, *meshcfg; @@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, found->pub.capability = res->pub.capability; found->ts = res->ts; - /* overwrite IEs */ - if (overwrite) { + /* Update IEs */ + if (res->pub.proberesp_ies) { size_t used = dev->wiphy.bss_priv_size + sizeof(*res); - size_t ielen = res->pub.len_information_elements; + size_t ielen = res->pub.len_proberesp_ies; + + if (found->pub.proberesp_ies && + !found->proberesp_ies_allocated && + ksize(found) >= used + ielen) { + memcpy(found->pub.proberesp_ies, + res->pub.proberesp_ies, ielen); + found->pub.len_proberesp_ies = ielen; + } else { + u8 *ies = found->pub.proberesp_ies; + + if (found->proberesp_ies_allocated) + ies = krealloc(ies, ielen, GFP_ATOMIC); + else + ies = kmalloc(ielen, GFP_ATOMIC); + + if (ies) { + memcpy(ies, res->pub.proberesp_ies, + ielen); + found->proberesp_ies_allocated = true; + found->pub.proberesp_ies = ies; + found->pub.len_proberesp_ies = ielen; + } + } - if (!found->ies_allocated && ksize(found) >= used + ielen) { - memcpy(found->pub.information_elements, - res->pub.information_elements, ielen); - found->pub.len_information_elements = ielen; + /* Override possible earlier Beacon frame IEs */ + found->pub.information_elements = + found->pub.proberesp_ies; + found->pub.len_information_elements = + found->pub.len_proberesp_ies; + } + if (res->pub.beacon_ies) { + size_t used = dev->wiphy.bss_priv_size + sizeof(*res); + size_t ielen = res->pub.len_beacon_ies; + + if (found->pub.beacon_ies && + !found->beacon_ies_allocated && + ksize(found) >= used + ielen) { + memcpy(found->pub.beacon_ies, + res->pub.beacon_ies, ielen); + found->pub.len_beacon_ies = ielen; } else { - u8 *ies = found->pub.information_elements; + u8 *ies = found->pub.beacon_ies; - if (found->ies_allocated) + if (found->beacon_ies_allocated) ies = krealloc(ies, ielen, GFP_ATOMIC); else ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { - memcpy(ies, res->pub.information_elements, ielen); - found->ies_allocated = true; - found->pub.information_elements = ies; - found->pub.len_information_elements = ielen; + memcpy(ies, res->pub.beacon_ies, + ielen); + found->beacon_ies_allocated = true; + found->pub.beacon_ies = ies; + found->pub.len_beacon_ies = ielen; } } } @@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy, res->pub.tsf = timestamp; res->pub.beacon_interval = beacon_interval; res->pub.capability = capability; - /* point to after the private area */ - res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; - memcpy(res->pub.information_elements, ie, ielen); - res->pub.len_information_elements = ielen; + /* + * Since we do not know here whether the IEs are from a Beacon or Probe + * Response frame, we need to pick one of the options and only use it + * with the driver that does not provide the full Beacon/Probe Response + * frame. Use Beacon frame pointer to avoid indicating that this should + * override the information_elements pointer should we have received an + * earlier indication of Probe Response data. + * + * The initial buffer for the IEs is allocated with the BSS entry and + * is located after the private area. + */ + res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.beacon_ies, ie, ielen); + res->pub.len_beacon_ies = ielen; + res->pub.information_elements = res->pub.beacon_ies; + res->pub.len_information_elements = res->pub.len_beacon_ies; kref_init(&res->ref); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); if (!res) return NULL; @@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct cfg80211_internal_bss *res; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - bool overwrite; size_t privsz = wiphy->bss_priv_size; if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && @@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); - /* point to after the private area */ - res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; - memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); - res->pub.len_information_elements = ielen; + /* + * The initial buffer for the IEs is allocated with the BSS entry and + * is located after the private area. + */ + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; + memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, + ielen); + res->pub.len_proberesp_ies = ielen; + res->pub.information_elements = res->pub.proberesp_ies; + res->pub.len_information_elements = res->pub.len_proberesp_ies; + } else { + res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; + memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); + res->pub.len_beacon_ies = ielen; + res->pub.information_elements = res->pub.beacon_ies; + res->pub.len_information_elements = res->pub.len_beacon_ies; + } kref_init(&res->ref); - overwrite = ieee80211_is_probe_resp(mgmt->frame_control); - - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); if (!res) return NULL; -- GitLab From 81ac3462d346ee7aaf037a35156b0a7a354e98cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jan 2010 15:30:58 +0100 Subject: [PATCH 0547/3892] mac80211: fix a few work bugs Kalle and Lennert reported problems with the new work code, and at least Kalle's problem I was able to trace to a missing jiffies initialisation. I also ran into a problem where occasionally I couldn't connect, which seems fixed with kicking the work items after scanning. Finally, also add some sanity checking code to verify that we're not adding work items while an interface is down -- that case could lead to something similar to what Lennert was seeing. There still seems to be a race condition that we're trying to figure out separately. Signed-off-by: Johannes Berg Tested-by: Lennert Buytenhek Tested-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/scan.c | 1 + net/mac80211/work.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a4c63d4e6845..30cb62bb45b3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -284,6 +284,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); + ieee80211_queue_work(&local->hw, &local->work_work); } EXPORT_SYMBOL(ieee80211_scan_completed); diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 5ba75990c9fd..7c5d95b1bc04 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -818,6 +818,7 @@ static void ieee80211_work_work(struct work_struct *work) wk->chan == local->tmp_channel && wk->chan_type == local->tmp_channel_type) { wk->started = true; + wk->timeout = jiffies; } if (!wk->started && !local->tmp_channel) { @@ -935,6 +936,9 @@ void ieee80211_add_work(struct ieee80211_work *wk) if (WARN_ON(!wk->done)) return; + if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) + return; + wk->started = false; local = wk->sdata->local; -- GitLab From 81f14df0b3909875902b0253d7059e8a73dd0c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Jan 2010 14:09:27 +0100 Subject: [PATCH 0548/3892] b43: LP-PHY: note and explain specs inconsistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 3e046ec1ff86..eb4fb4581edb 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -80,6 +80,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ static void lpphy_read_band_sprom(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -101,6 +102,12 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) maxpwr = bus->sprom.maxpwr_bg; lpphy->max_tx_pwr_med_band = maxpwr; cckpo = bus->sprom.cck2gpo; + /* + * We don't read SPROM's opo as specs say. On rev8 SPROMs + * opo == ofdm2gpo and we don't know any SSB with LP-PHY + * and SPROM rev below 8. + */ + B43_WARN_ON(bus->sprom.revision < 8); ofdmpo = bus->sprom.ofdm2gpo; if (cckpo) { for (i = 0; i < 4; i++) { -- GitLab From b74d12e116528fadc35f305eb6e9525a3a2b62b1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 7 Jan 2010 17:24:54 -0500 Subject: [PATCH 0549/3892] cfg80211: add debug print when we drop a bogus country IE Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f79d6613c5ff..389247cb7059 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1806,8 +1806,10 @@ void regulatory_hint_11d(struct wiphy *wiphy, goto out; rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); - if (!rd) + if (!rd) { + REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); goto out; + } /* * This will not happen right now but we leave it here for the -- GitLab From 08030db6e5275dda19ea1b3ab8a41c992799db4a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 7 Jan 2010 17:24:56 -0500 Subject: [PATCH 0550/3892] cfg80211: process the max power on a country IE The max power from each country IE triplet was being ignored. This fix isn't critical as CRDA was always being used for the lower limit, but we should process it in case the AP still wants to decrease power output even more for whatever reason. Reported-by: Benoit PAPILLAULT Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 389247cb7059..77d0bb6f6e7a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -680,7 +680,7 @@ static struct ieee80211_regdomain *country_ie_2_rd( */ freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); power_rule->max_antenna_gain = DBI_TO_MBI(100); - power_rule->max_eirp = DBM_TO_MBM(100); + power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); country_ie += 3; country_ie_len -= 3; -- GitLab From cc5d8a3772ee4e2ed29558ba548b4747959ba971 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 7 Jan 2010 17:24:57 -0500 Subject: [PATCH 0551/3892] cfg80211: Fix country IE parsing for single channel triplets This enhances the way we parse country IEs to minimize the number of regulatory rules that we create. It also fixes our current implementation which treated country IE triplets with only one channel as one independed regulatory rule even though adjecent rules were also being provided. Without this patch APs which send country IE information with a channel triplet for each individual channel will force cfg80211 to deny HT40 operation as a regulatory rule would have been created independently for each channel and as such configured only for 20 MHz operation. Although 802.11n APs which send country IEs triplets in this fassion are likely rare Benoit reports this against the Ubiquity NanoStation M5, with Country "FR" and HT40 enabled. Since we now have a helper which parses the triplets in intermediate steps we now take care extra care to process padding. Reported-by: Benoit PAPILLAULT Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 225 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 4 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 77d0bb6f6e7a..a5c2d3a6cbb2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -484,6 +484,178 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, #undef ONE_GHZ_IN_KHZ } +/* + * Some APs may send a country IE triplet for each channel they + * support and while this is completely overkill and silly we still + * need to support it. We avoid making a single rule for each channel + * though and to help us with this we use this helper to find the + * actual subband end channel. These type of country IE triplet + * scenerios are handled then, all yielding two regulaotry rules from + * parsing a country IE: + * + * [1] + * [2] + * [36] + * [40] + * + * [1] + * [2-4] + * [5-12] + * [36] + * [40-44] + * + * [1-4] + * [5-7] + * [36-44] + * [48-64] + * + * [36-36] + * [40-40] + * [44-44] + * [48-48] + * [52-52] + * [56-56] + * [60-60] + * [64-64] + * [100-100] + * [104-104] + * [108-108] + * [112-112] + * [116-116] + * [120-120] + * [124-124] + * [128-128] + * [132-132] + * [136-136] + * [140-140] + * + * Returns 0 if the IE has been found to be invalid in the middle + * somewhere. + */ +static int max_subband_chan(int orig_cur_chan, + int orig_end_channel, + s8 orig_max_power, + u8 **country_ie, + u8 *country_ie_len) +{ + u8 *triplets_start = *country_ie; + u8 len_at_triplet = *country_ie_len; + int end_subband_chan = orig_end_channel; + enum ieee80211_band band; + + /* + * We'll deal with padding for the caller unless + * its not immediate and we don't process any channels + */ + if (*country_ie_len == 1) { + *country_ie += 1; + *country_ie_len -= 1; + return orig_end_channel; + } + + /* Move to the next triplet and then start search */ + *country_ie += 3; + *country_ie_len -= 3; + + if (orig_cur_chan <= 14) + band = IEEE80211_BAND_2GHZ; + else + band = IEEE80211_BAND_5GHZ; + + while (*country_ie_len >= 3) { + int end_channel = 0; + struct ieee80211_country_ie_triplet *triplet = + (struct ieee80211_country_ie_triplet *) *country_ie; + int cur_channel = 0, next_expected_chan; + enum ieee80211_band next_band = IEEE80211_BAND_2GHZ; + + /* means last triplet is completely unrelated to this one */ + if (triplet->ext.reg_extension_id >= + IEEE80211_COUNTRY_EXTENSION_ID) { + *country_ie -= 3; + *country_ie_len += 3; + break; + } + + if (triplet->chans.first_channel == 0) { + *country_ie += 1; + *country_ie_len -= 1; + if (*country_ie_len != 0) + return 0; + break; + } + + /* Monitonically increasing channel order */ + if (triplet->chans.first_channel <= end_subband_chan) + return 0; + + /* 2 GHz */ + if (triplet->chans.first_channel <= 14) { + end_channel = triplet->chans.first_channel + + triplet->chans.num_channels - 1; + } + else { + end_channel = triplet->chans.first_channel + + (4 * (triplet->chans.num_channels - 1)); + next_band = IEEE80211_BAND_5GHZ; + } + + if (band != next_band) { + *country_ie -= 3; + *country_ie_len += 3; + break; + } + + if (orig_max_power != triplet->chans.max_power) { + *country_ie -= 3; + *country_ie_len += 3; + break; + } + + cur_channel = triplet->chans.first_channel; + + /* The key is finding the right next expected channel */ + if (band == IEEE80211_BAND_2GHZ) + next_expected_chan = end_subband_chan + 1; + else + next_expected_chan = end_subband_chan + 4; + + if (cur_channel != next_expected_chan) { + *country_ie -= 3; + *country_ie_len += 3; + break; + } + + end_subband_chan = end_channel; + + /* Move to the next one */ + *country_ie += 3; + *country_ie_len -= 3; + + /* + * Padding needs to be dealt with if we processed + * some channels. + */ + if (*country_ie_len == 1) { + *country_ie += 1; + *country_ie_len -= 1; + break; + } + + /* If seen, the IE is invalid */ + if (*country_ie_len == 2) + return 0; + } + + if (end_subband_chan == orig_end_channel) { + *country_ie = triplets_start; + *country_ie_len = len_at_triplet; + return orig_end_channel; + } + + return end_subband_chan; +} + /* * Converts a country IE to a regulatory domain. A regulatory domain * structure has a lot of information which the IE doesn't yet have, @@ -552,6 +724,19 @@ static struct ieee80211_regdomain *country_ie_2_rd( continue; } + /* + * APs can add padding to make length divisible + * by two, required by the spec. + */ + if (triplet->chans.first_channel == 0) { + country_ie++; + country_ie_len--; + /* This is expected to be at the very end only */ + if (country_ie_len != 0) + return NULL; + break; + } + /* 2 GHz */ if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + @@ -570,6 +755,20 @@ static struct ieee80211_regdomain *country_ie_2_rd( (4 * (triplet->chans.num_channels - 1)); cur_channel = triplet->chans.first_channel; + + /* + * Enhancement for APs that send a triplet for every channel + * or for whatever reason sends triplets with multiple channels + * separated when in fact they should be together. + */ + end_channel = max_subband_chan(cur_channel, + end_channel, + triplet->chans.max_power, + &country_ie, + &country_ie_len); + if (!end_channel) + return NULL; + cur_sub_max_channel = end_channel; /* Basic sanity check */ @@ -600,10 +799,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( last_sub_max_channel = cur_sub_max_channel; - country_ie += 3; - country_ie_len -= 3; num_rules++; + if (country_ie_len >= 3) { + country_ie += 3; + country_ie_len -= 3; + } + /* * Note: this is not a IEEE requirement but * simply a memory requirement @@ -646,6 +848,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( continue; } + if (triplet->chans.first_channel == 0) { + country_ie++; + country_ie_len--; + break; + } + reg_rule = &rd->reg_rules[i]; freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; @@ -660,6 +868,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1)); + end_channel = max_subband_chan(triplet->chans.first_channel, + end_channel, + triplet->chans.max_power, + &country_ie, + &country_ie_len); + /* * The +10 is since the regulatory domain expects * the actual band edge, not the center of freq for @@ -682,10 +896,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( power_rule->max_antenna_gain = DBI_TO_MBI(100); power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); - country_ie += 3; - country_ie_len -= 3; i++; + if (country_ie_len >= 3) { + country_ie += 3; + country_ie_len -= 3; + } + BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); } -- GitLab From 0fca65c1c0569d6a143e978b6f4974c519033e63 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:00 +0530 Subject: [PATCH 0552/3892] ath9k: Add a new file for GPIO Move all LED/RFKILL/BTCOEX related code to gpio.c Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 15 + drivers/net/wireless/ath/ath9k/gpio.c | 428 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 406 ---------------------- 4 files changed, 444 insertions(+), 406 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/gpio.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 4985b2b1b0a9..332d6f20c6b6 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,4 +1,5 @@ ath9k-y += beacon.o \ + gpio.o \ main.o \ recv.o \ xmit.o \ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9efebac5ed0e..bbdca5edcfbf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -341,6 +341,10 @@ int ath_beaconq_config(struct ath_softc *sc); #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ +/**********/ +/* BTCOEX */ +/**********/ + /* Defines the BT AR_BT_COEX_WGHT used */ enum ath_stomp_type { ATH_BTCOEX_NO_STOMP, @@ -361,6 +365,10 @@ struct ath_btcoex { struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ }; +int ath_init_btcoex_timer(struct ath_softc *sc); +void ath9k_btcoex_timer_resume(struct ath_softc *sc); +void ath9k_btcoex_timer_pause(struct ath_softc *sc); + /********************/ /* LED Control */ /********************/ @@ -385,6 +393,9 @@ struct ath_led { bool registered; }; +void ath_init_leds(struct ath_softc *sc); +void ath_deinit_leds(struct ath_softc *sc); + /********************/ /* Main driver core */ /********************/ @@ -582,4 +593,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); + +void ath_start_rfkill_poll(struct ath_softc *sc); +extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); + #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c new file mode 100644 index 000000000000..e204bd25ff65 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_blink_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + ath_led_blink_work.work); + + if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) + return; + + if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || + (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); + else + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, + (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); + + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); + + sc->led_on_duration = sc->led_on_cnt ? + max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : + ATH_LED_ON_DURATION_IDLE; + sc->led_off_duration = sc->led_off_cnt ? + max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : + ATH_LED_OFF_DURATION_IDLE; + sc->led_on_cnt = sc->led_off_cnt = 0; + if (sc->sc_flags & SC_OP_LED_ON) + sc->sc_flags &= ~SC_OP_LED_ON; + else + sc->sc_flags |= SC_OP_LED_ON; +} + +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; + + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, + (led->led_type == ATH_LED_RADIO)); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + if (led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ON; + } else { + sc->led_off_cnt++; + } + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) { + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, 0); + } else if (led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); + sc->sc_flags |= SC_OP_LED_ON; + } else { + sc->led_on_cnt++; + } + break; + default: + break; + } +} + +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; + + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; + + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} + +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +void ath_deinit_leds(struct ath_softc *sc) +{ + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); +} + +void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; + + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + + INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); + + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + return; + +fail: + cancel_delayed_work_sync(&sc->ath_led_blink_work); + ath_deinit_leds(sc); +} + +/*******************/ +/* Rfkill */ +/*******************/ + +static bool ath_is_rfkill_set(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == + ah->rfkill_polarity; +} + +void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + bool blocked = !!ath_is_rfkill_set(sc); + + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +} + +void ath_start_rfkill_poll(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + wiphy_rfkill_start_polling(sc->hw->wiphy); +} + +/******************/ +/* BTCOEX */ +/******************/ + +/* + * Detects if there is any priority bt traffic + */ +static void ath_detect_bt_priority(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) + btcoex->bt_priority_cnt++; + + if (time_after(jiffies, btcoex->bt_priority_time + + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { + if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, + "BT priority traffic detected"); + sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; + } else { + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + } + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + } +} + +/* + * Configures appropriate weight based on stomp type. + */ +static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, + enum ath_stomp_type stomp_type) +{ + struct ath_hw *ah = sc->sc_ah; + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} + +static void ath9k_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, + u32 timer_period) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + + if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_set_interrupts(ah, 0); + sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); + } +} + +static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + ath9k_hw_gen_timer_stop(ah, timer); + + /* if no timer is enabled, turn off interrupt mask */ + if (timer_table->timer_mask.val == 0) { + ath9k_hw_set_interrupts(ah, 0); + sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); + } +} + +/* + * This is the master bt coex timer which runs for every + * 45ms, bt traffic will be given priority during 55% of this + * period while wlan gets remaining 45% + */ +static void ath_btcoex_period_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + + ath_detect_bt_priority(sc); + + spin_lock_bh(&btcoex->btcoex_lock); + + ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); + + spin_unlock_bh(&btcoex->btcoex_lock); + + if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); + + ath9k_gen_timer_start(ah, + btcoex->no_stomp_timer, + (ath9k_hw_gettsf32(ah) + + btcoex->btcoex_no_stomp), + btcoex->btcoex_no_stomp * 10); + btcoex->hw_timer_enabled = true; + } + + mod_timer(&btcoex->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); +} + +/* + * Generic tsf based hw timer which configures weight + * registers to time slice between wlan and bt traffic + */ +static void ath_btcoex_no_stomp_timer(void *arg) +{ + struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "no stomp timer running \n"); + + spin_lock_bh(&btcoex->btcoex_lock); + + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_bh(&btcoex->btcoex_lock); +} + +int ath_init_btcoex_timer(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + + btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex->btcoex_period / 100; + + setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, + (unsigned long) sc); + + spin_lock_init(&btcoex->btcoex_lock); + + btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, + ath_btcoex_no_stomp_timer, + ath_btcoex_no_stomp_timer, + (void *) sc, AR_FIRST_NDP_TIMER); + + if (!btcoex->no_stomp_timer) + return -ENOMEM; + + return 0; +} + +/* + * (Re)start btcoex timers + */ +void ath9k_btcoex_timer_resume(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Starting btcoex timers"); + + /* make sure duty cycle timer is also stopped when resuming */ + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + + mod_timer(&btcoex->period_timer, jiffies); +} + + +/* + * Pause btcoex timer and bt duty cycle timer + */ +void ath9k_btcoex_timer_pause(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + del_timer_sync(&btcoex->period_timer); + + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); + + btcoex->hw_timer_enabled = false; +} diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3777b8449789..31a33cf762da 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1000,174 +1000,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } } -/********************************/ -/* LED functions */ -/********************************/ - -static void ath_led_blink_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - ath_led_blink_work.work); - - if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) - return; - - if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); - else - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, - (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); - - ieee80211_queue_delayed_work(sc->hw, - &sc->ath_led_blink_work, - (sc->sc_flags & SC_OP_LED_ON) ? - msecs_to_jiffies(sc->led_off_duration) : - msecs_to_jiffies(sc->led_on_duration)); - - sc->led_on_duration = sc->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - sc->led_off_duration = sc->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - sc->led_on_cnt = sc->led_off_cnt = 0; - if (sc->sc_flags & SC_OP_LED_ON) - sc->sc_flags &= ~SC_OP_LED_ON; - else - sc->sc_flags |= SC_OP_LED_ON; -} - -static void ath_led_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath_softc *sc = led->sc; - - switch (brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, - (led->led_type == ATH_LED_RADIO)); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - sc->sc_flags &= ~SC_OP_LED_ON; - } else { - sc->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - sc->sc_flags |= SC_OP_LED_ASSOCIATED; - ieee80211_queue_delayed_work(sc->hw, - &sc->ath_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); - sc->sc_flags |= SC_OP_LED_ON; - } else { - sc->led_on_cnt++; - } - break; - default: - break; - } -} - -static int ath_register_led(struct ath_softc *sc, struct ath_led *led, - char *trigger) -{ - int ret; - - led->sc = sc; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath_led_brightness; - - ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); - if (ret) - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, - "Failed to register led:%s", led->name); - else - led->registered = 1; - return ret; -} - -static void ath_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } -} - -static void ath_deinit_leds(struct ath_softc *sc) -{ - ath_unregister_led(&sc->assoc_led); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - ath_unregister_led(&sc->tx_led); - ath_unregister_led(&sc->rx_led); - ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); -} - -static void ath_init_leds(struct ath_softc *sc) -{ - char *trigger; - int ret; - - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; - - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); - - INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); - - trigger = ieee80211_get_radio_led_name(sc->hw); - snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), - "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->radio_led, trigger); - sc->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; - - trigger = ieee80211_get_assoc_led_name(sc->hw); - snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), - "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->assoc_led, trigger); - sc->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; - - trigger = ieee80211_get_tx_led_name(sc->hw); - snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), - "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->tx_led, trigger); - sc->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; - - trigger = ieee80211_get_rx_led_name(sc->hw); - snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), - "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->rx_led, trigger); - sc->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; - - return; - -fail: - cancel_delayed_work_sync(&sc->ath_led_blink_work); - ath_deinit_leds(sc); -} - void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -1252,35 +1084,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); } -/*******************/ -/* Rfkill */ -/*******************/ - -static bool ath_is_rfkill_set(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == - ah->rfkill_polarity; -} - -static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - bool blocked = !!ath_is_rfkill_set(sc); - - wiphy_rfkill_set_hw_state(hw->wiphy, blocked); -} - -static void ath_start_rfkill_poll(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - wiphy_rfkill_start_polling(sc->hw->wiphy); -} - static void ath9k_uninit_hw(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -1364,177 +1167,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, return ath_reg_notifier_apply(wiphy, request, reg); } -/* - * Detects if there is any priority bt traffic - */ -static void ath_detect_bt_priority(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) - btcoex->bt_priority_cnt++; - - if (time_after(jiffies, btcoex->bt_priority_time + - msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, - "BT priority traffic detected"); - sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; - } else { - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; - } - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - } -} - -/* - * Configures appropriate weight based on stomp type. - */ -static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, - enum ath_stomp_type stomp_type) -{ - struct ath_hw *ah = sc->sc_ah; - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(ah); -} - -static void ath9k_gen_timer_start(struct ath_hw *ah, - struct ath_gen_timer *timer, - u32 timer_next, - u32 timer_period) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); - - if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { - ath9k_hw_set_interrupts(ah, 0); - sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); - } -} - -static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - - ath9k_hw_gen_timer_stop(ah, timer); - - /* if no timer is enabled, turn off interrupt mask */ - if (timer_table->timer_mask.val == 0) { - ath9k_hw_set_interrupts(ah, 0); - sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); - } -} - -/* - * This is the master bt coex timer which runs for every - * 45ms, bt traffic will be given priority during 55% of this - * period while wlan gets remaining 45% - */ -static void ath_btcoex_period_timer(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *) data; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - - ath_detect_bt_priority(sc); - - spin_lock_bh(&btcoex->btcoex_lock); - - ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); - - spin_unlock_bh(&btcoex->btcoex_lock); - - if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - ath9k_gen_timer_start(ah, - btcoex->no_stomp_timer, - (ath9k_hw_gettsf32(ah) + - btcoex->btcoex_no_stomp), - btcoex->btcoex_no_stomp * 10); - btcoex->hw_timer_enabled = true; - } - - mod_timer(&btcoex->period_timer, jiffies + - msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); -} - -/* - * Generic tsf based hw timer which configures weight - * registers to time slice between wlan and bt traffic - */ -static void ath_btcoex_no_stomp_timer(void *arg) -{ - struct ath_softc *sc = (struct ath_softc *)arg; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "no stomp timer running \n"); - - spin_lock_bh(&btcoex->btcoex_lock); - - if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) - ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); - else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); - - spin_unlock_bh(&btcoex->btcoex_lock); -} - -static int ath_init_btcoex_timer(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; - btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * - btcoex->btcoex_period / 100; - - setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, - (unsigned long) sc); - - spin_lock_init(&btcoex->btcoex_lock); - - btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, - ath_btcoex_no_stomp_timer, - ath_btcoex_no_stomp_timer, - (void *) sc, AR_FIRST_NDP_TIMER); - - if (!btcoex->no_stomp_timer) - return -ENOMEM; - - return 0; -} - /* * Read and write, they both share the same lock. We do this to serialize * reads and writes on Atheros 802.11n PCI devices only. This is required @@ -2213,28 +1845,6 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, /* mac80211 callbacks */ /**********************/ -/* - * (Re)start btcoex timers - */ -static void ath9k_btcoex_timer_resume(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "Starting btcoex timers"); - - /* make sure duty cycle timer is also stopped when resuming */ - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; - - mod_timer(&btcoex->period_timer, jiffies); -} - static int ath9k_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -2461,22 +2071,6 @@ exit: return 0; } -/* - * Pause btcoex timer and bt duty cycle timer - */ -static void ath9k_btcoex_timer_pause(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - del_timer_sync(&btcoex->period_timer); - - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - btcoex->hw_timer_enabled = false; -} - static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; -- GitLab From 556242049cc3992d0ee625e9f15c4b00ea4baac8 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:02 +0530 Subject: [PATCH 0553/3892] ath9k: Add new file init.c Move initialization/de-initialization related code to this file. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 5 + drivers/net/wireless/ath/ath9k/init.c | 856 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 842 +---------------------- 4 files changed, 865 insertions(+), 839 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/init.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 332d6f20c6b6..6b50d5eb9ec3 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,5 +1,6 @@ ath9k-y += beacon.o \ gpio.o \ + init.o \ main.o \ recv.o \ xmit.o \ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bbdca5edcfbf..68a423054e6c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -341,6 +341,8 @@ int ath_beaconq_config(struct ath_softc *sc); #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ +void ath_ani_calibrate(unsigned long data); + /**********/ /* BTCOEX */ /**********/ @@ -519,6 +521,7 @@ struct ath_wiphy { int chan_is_ht; }; +void ath9k_tasklet(unsigned long data); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); @@ -535,6 +538,7 @@ static inline void ath_bus_cleanup(struct ath_common *common) } extern struct ieee80211_ops ath9k_ops; +extern int modparam_nohwcrypt; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); @@ -552,6 +556,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); +bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); #ifdef CONFIG_PCI int ath_pci_init(void); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c new file mode 100644 index 000000000000..2bea0892918e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -0,0 +1,856 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static char *dev_info = "ath9k"; + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +static unsigned int ath9k_debug = ATH_DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); +MODULE_PARM_DESC(debug, "Debugging mask"); + +int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +/* We use the hw_value as an index into our private channel structure */ + +#define CHAN2G(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, 0), + RATE(90, 0x0f, 0), + RATE(120, 0x0a, 0), + RATE(180, 0x0e, 0), + RATE(240, 0x09, 0), + RATE(360, 0x0d, 0), + RATE(480, 0x08, 0), + RATE(540, 0x0c, 0), +}; + +static void ath9k_uninit_hw(struct ath_softc *sc); + +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. + */ + +static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&sc->sc_serial_rw, flags); + iowrite32(val, sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + } else + iowrite32(val, sc->mem + reg_offset); +} + +static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&sc->sc_serial_rw, flags); + val = ioread32(sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + } else + val = ioread32(sc->mem + reg_offset); + return val; +} + +static const struct ath_ops ath9k_common_ops = { + .read = ath9k_ioread32, + .write = ath9k_iowrite32, +}; + +/**************************/ +/* Initialization */ +/**************************/ + +static void setup_ht_cap(struct ath_softc *sc, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u8 tx_streams, rx_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? + 1 : 2; + rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? + 1 : 2; + + if (tx_streams != rx_streams) { + ath_print(common, ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + ht_info->mcs.rx_mask[0] = 0xff; + if (rx_streams >= 2) + ht_info->mcs.rx_mask[1] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} + +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); + + return ath_reg_notifier_apply(wiphy, request, reg); +} + +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); + + INIT_LIST_HEAD(head); + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + ath_print(common, ATH_DBG_FATAL, + "ath_desc not DWORD aligned\n"); + BUG_ON((sizeof(struct ath_desc) % 4) != 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; + + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; + + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; + } + + /* allocate descriptors */ + dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kzalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + dd->dd_bufptr = bf; + + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + BUG_ON((caddr_t) bf->bf_desc >= + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); + } + return 0; +fail2: + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} + +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) +{ + struct ath_hw *ah = NULL; + struct ath_common *common; + int r = 0, i; + int csz = 0; + int qnum; + + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; + + spin_lock_init(&sc->wiphy_lock); + spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->sc_pm_lock); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, + (unsigned long)sc); + + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) + return -ENOMEM; + + ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; + sc->sc_ah = ah; + + common = ath9k_hw_common(ah); + common->ops = &ath9k_common_ops; + common->bus_ops = bus_ops; + common->ah = ah; + common->hw = sc->hw; + common->priv = sc; + common->debug_mask = ath9k_debug; + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(common, &csz); + /* XXX assert csz is non-zero */ + common->cachelsz = csz << 2; /* convert to bytes */ + + r = ath9k_hw_init(ah); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", r); + goto bad_free_hw; + } + + if (ath9k_init_debug(ah) < 0) { + ath_print(common, ATH_DBG_FATAL, + "Unable to create debugfs files\n"); + goto bad_free_hw; + } + + /* Get the hardware key cache size. */ + common->keymax = ah->caps.keycache_size; + if (common->keymax > ATH_KEYMAX) { + ath_print(common, ATH_DBG_ANY, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, common->keymax); + common->keymax = ATH_KEYMAX; + } + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < common->keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + + /* default to MONITOR mode */ + sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); + r = -EIO; + goto bad2; + } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); + r = -EIO; + goto bad2; + } + + sc->config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + r = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + r = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + r = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + r = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + common->splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->config.txpowlimit = ATH_TXPOWER_MAX; + + /* 11n Capabilities */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + common->tx_chainmask = ah->caps.tx_chainmask; + common->rx_chainmask = ah->caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(ah); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } + + /* setup channels and rates */ + + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + + switch (ah->btcoex_hw.scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(ah); + r = ath_init_btcoex_timer(sc); + if (r) + goto bad2; + qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + ath9k_hw_init_btcoex_hw(ah, qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + break; + default: + WARN_ON(1); + break; + } + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + +bad_free_hw: + ath9k_uninit_hw(sc); + return r; +} + +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_SPECTRUM_MGMT; + + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + hw->queues = 4; + hw->max_rates = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; + /* Hardware supports 10 but we use 4 */ + hw->max_rate_tries = 4; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vif); + + hw->rate_control_algorithm = "ath9k_rate_control"; + + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; +} + +/* Device driver core initialization */ +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_common *common; + struct ath_hw *ah; + int error = 0, i; + struct ath_regulatory *reg; + + dev_dbg(sc->dev, "Attach ATH hw\n"); + + error = ath_init_softc(devid, sc, subsysid, bus_ops); + if (error != 0) + return error; + + ah = sc->sc_ah; + common = ath9k_hw_common(ah); + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + ath_set_hw_capab(sc, hw); + + error = ath_regd_init(&common->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); + if (error) + return error; + + reg = &common->regulatory; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto error_attach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto error_attach; + + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(500); + + error = ieee80211_register_hw(hw); + + if (!ath_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); + if (error) + goto error_attach; + } + + /* Initialize LED control */ + ath_init_leds(sc); + + ath_start_rfkill_poll(sc); + + return 0; + +error_attach: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_uninit_hw(sc); + + return error; +} + +/*****************************/ +/* De-Initialization */ +/*****************************/ + +static void ath9k_uninit_hw(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + BUG_ON(!ah); + + ath9k_exit_debug(ah); + ath9k_hw_detach(ah); + sc->sc_ah = NULL; +} + +static void ath_clean_core(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + int i = 0; + + ath9k_ps_wakeup(sc); + + dev_dbg(sc->dev, "Detach ATH hw\n"); + + ath_deinit_leds(sc); + wiphy_rfkill_stop_polling(sc->hw->wiphy); + + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + sc->sec_wiphy[i] = NULL; + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + } + ieee80211_unregister_hw(hw); + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); + + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); + + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_setpower(sc, ATH9K_PM_AWAKE); + + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + if ((sc->btcoex.no_stomp_timer) && + ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); +} + +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); + + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} + +void ath_detach(struct ath_softc *sc) +{ + ath_clean_core(sc); + ath9k_uninit_hw(sc); +} + +void ath_cleanup(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + ath_clean_core(sc); + free_irq(sc->irq, sc); + ath_bus_cleanup(common); + kfree(sc->sec_wiphy); + ieee80211_free_hw(sc->hw); + + ath9k_uninit_hw(sc); +} + +/************************/ +/* Module Hooks */ +/************************/ + +static int __init ath9k_init(void) +{ + int error; + + /* Register rate control algorithm */ + error = ath_rate_control_register(); + if (error != 0) { + printk(KERN_ERR + "ath9k: Unable to register rate control " + "algorithm: %d\n", + error); + goto err_out; + } + + error = ath9k_debug_create_root(); + if (error) { + printk(KERN_ERR + "ath9k: Unable to create debugfs root: %d\n", + error); + goto err_rate_unregister; + } + + error = ath_pci_init(); + if (error < 0) { + printk(KERN_ERR + "ath9k: No PCI devices found, driver not installed.\n"); + error = -ENODEV; + goto err_remove_root; + } + + error = ath_ahb_init(); + if (error < 0) { + error = -ENODEV; + goto err_pci_exit; + } + + return 0; + + err_pci_exit: + ath_pci_exit(); + + err_remove_root: + ath9k_debug_remove_root(); + err_rate_unregister: + ath_rate_control_unregister(); + err_out: + return error; +} +module_init(ath9k_init); + +static void __exit ath9k_exit(void) +{ + ath_ahb_exit(); + ath_pci_exit(); + ath9k_debug_remove_root(); + ath_rate_control_unregister(); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} +module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 31a33cf762da..48bd5d50f4d6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -18,118 +18,6 @@ #include "ath9k.h" #include "btcoex.h" -static char *dev_info = "ath9k"; - -MODULE_AUTHOR("Atheros Communications"); -MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); -MODULE_LICENSE("Dual BSD/GPL"); - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); - -static unsigned int ath9k_debug = ATH_DBG_DEFAULT; -module_param_named(debug, ath9k_debug, uint, 0); -MODULE_PARM_DESC(debug, "Debugging mask"); - -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; - static void ath_cache_conf_rate(struct ath_softc *sc, struct ieee80211_conf *conf) { @@ -221,7 +109,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, return channel; } -static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) +bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; bool ret; @@ -349,7 +237,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, * When the task is complete, it reschedules itself depending on the * appropriate interval that was calculated. */ -static void ath_ani_calibrate(unsigned long data) +void ath_ani_calibrate(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; @@ -504,7 +392,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_tx_node_cleanup(sc, an); } -static void ath9k_tasklet(unsigned long data) +void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; @@ -924,44 +812,6 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf } } -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 tx_streams, rx_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? - 1 : 2; - rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? - 1 : 2; - - if (tx_streams != rx_streams) { - ath_print(common, ATH_DBG_CONFIG, - "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - ht_info->mcs.rx_mask[0] = 0xff; - if (rx_streams >= 2) - ht_info->mcs.rx_mask[1] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) @@ -1084,513 +934,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); } -static void ath9k_uninit_hw(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - BUG_ON(!ah); - - ath9k_exit_debug(ah); - ath9k_hw_detach(ah); - sc->sc_ah = NULL; -} - -static void ath_clean_core(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_hw *ah = sc->sc_ah; - int i = 0; - - ath9k_ps_wakeup(sc); - - dev_dbg(sc->dev, "Detach ATH hw\n"); - - ath_deinit_leds(sc); - wiphy_rfkill_stop_polling(sc->hw->wiphy); - - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - sc->sec_wiphy[i] = NULL; - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - } - ieee80211_unregister_hw(hw); - ath_rx_cleanup(sc); - ath_tx_cleanup(sc); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_setpower(sc, ATH9K_PM_AWAKE); - - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - if ((sc->btcoex.no_stomp_timer) && - ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); -} - -void ath_detach(struct ath_softc *sc) -{ - ath_clean_core(sc); - ath9k_uninit_hw(sc); -} - -void ath_cleanup(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - ath_clean_core(sc); - free_irq(sc->irq, sc); - ath_bus_cleanup(common); - kfree(sc->sec_wiphy); - ieee80211_free_hw(sc->hw); - - ath9k_uninit_hw(sc); -} - -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); - - return ath_reg_notifier_apply(wiphy, request, reg); -} - -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) -{ - struct ath_hw *ah = (struct ath_hw *) hw_priv; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&sc->sc_serial_rw, flags); - iowrite32(val, sc->mem + reg_offset); - spin_unlock_irqrestore(&sc->sc_serial_rw, flags); - } else - iowrite32(val, sc->mem + reg_offset); -} - -static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) -{ - struct ath_hw *ah = (struct ath_hw *) hw_priv; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - u32 val; - - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&sc->sc_serial_rw, flags); - val = ioread32(sc->mem + reg_offset); - spin_unlock_irqrestore(&sc->sc_serial_rw, flags); - } else - val = ioread32(sc->mem + reg_offset); - return val; -} - -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_ioread32, - .write = ath9k_iowrite32, -}; - -/* - * Initialize and fill ath_softc, ath_sofct is the - * "Software Carrier" struct. Historically it has existed - * to allow the separation between hardware specific - * variables (now in ath_hw) and driver specific variables. - */ -static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, - const struct ath_bus_ops *bus_ops) -{ - struct ath_hw *ah = NULL; - struct ath_common *common; - int r = 0, i; - int csz = 0; - int qnum; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - - spin_lock_init(&sc->wiphy_lock); - spin_lock_init(&sc->sc_resetlock); - spin_lock_init(&sc->sc_serial_rw); - spin_lock_init(&sc->sc_pm_lock); - mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, - (unsigned long)sc); - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (!ah) - return -ENOMEM; - - ah->hw_version.devid = devid; - ah->hw_version.subsysid = subsysid; - sc->sc_ah = ah; - - common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; - common->bus_ops = bus_ops; - common->ah = ah; - common->hw = sc->hw; - common->priv = sc; - common->debug_mask = ath9k_debug; - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - ath_read_cachesize(common, &csz); - /* XXX assert csz is non-zero */ - common->cachelsz = csz << 2; /* convert to bytes */ - - r = ath9k_hw_init(ah); - if (r) { - ath_print(common, ATH_DBG_FATAL, - "Unable to initialize hardware; " - "initialization status: %d\n", r); - goto bad_free_hw; - } - - if (ath9k_init_debug(ah) < 0) { - ath_print(common, ATH_DBG_FATAL, - "Unable to create debugfs files\n"); - goto bad_free_hw; - } - - /* Get the hardware key cache size. */ - common->keymax = ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_print(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < common->keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); - - /* default to MONITOR mode */ - sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. - */ - sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); - if (sc->beacon.beaconq == -1) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup a beacon xmit queue\n"); - r = -EIO; - goto bad2; - } - sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->beacon.cabq == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup CAB xmit queue\n"); - r = -EIO; - goto bad2; - } - - sc->config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) - sc->tx.hwq_map[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BK traffic\n"); - r = -EIO; - goto bad2; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BE traffic\n"); - r = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VI traffic\n"); - r = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VO traffic\n"); - r = -EIO; - goto bad2; - } - - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - - common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); - - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - common->splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); - - sc->config.txpowlimit = ATH_TXPOWER_MAX; - - /* 11n Capabilities */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - common->tx_chainmask = ah->caps.tx_chainmask; - common->rx_chainmask = ah->caps.rx_chainmask; - - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->rx.defant = ath9k_hw_getdefantenna(ah); - - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - - sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ - - /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } - - /* setup channels and rates */ - - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } - - switch (ah->btcoex_hw.scheme) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_2WIRE: - ath9k_hw_btcoex_init_2wire(ah); - break; - case ATH_BTCOEX_CFG_3WIRE: - ath9k_hw_btcoex_init_3wire(ah); - r = ath_init_btcoex_timer(sc); - if (r) - goto bad2; - qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - ath9k_hw_init_btcoex_hw(ah, qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - default: - WARN_ON(1); - break; - } - - return 0; -bad2: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - -bad_free_hw: - ath9k_uninit_hw(sc); - return r; -} - -void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -{ - struct ath_hw *ah = sc->sc_ah; - - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_SPECTRUM_MGMT; - - if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - - if (AR_SREV_5416(ah)) - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - - hw->queues = 4; - hw->max_rates = 4; - hw->channel_change_time = 5000; - hw->max_listen_interval = 10; - /* Hardware supports 10 but we use 4 */ - hw->max_rate_tries = 4; - hw->sta_data_size = sizeof(struct ath_node); - hw->vif_data_size = sizeof(struct ath_vif); - - hw->rate_control_algorithm = "ath9k_rate_control"; - - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; -} - -/* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, - const struct ath_bus_ops *bus_ops) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_common *common; - struct ath_hw *ah; - int error = 0, i; - struct ath_regulatory *reg; - - dev_dbg(sc->dev, "Attach ATH hw\n"); - - error = ath_init_softc(devid, sc, subsysid, bus_ops); - if (error != 0) - return error; - - ah = sc->sc_ah; - common = ath9k_hw_common(ah); - - /* get mac address from hardware and set in mac80211 */ - - SET_IEEE80211_PERM_ADDR(hw, common->macaddr); - - ath_set_hw_capab(sc, hw); - - error = ath_regd_init(&common->regulatory, sc->hw->wiphy, - ath9k_reg_notifier); - if (error) - return error; - - reg = &common->regulatory; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) - setup_ht_cap(sc, - &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) - setup_ht_cap(sc, - &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } - - /* initialize tx/rx engine */ - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto error_attach; - - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto error_attach; - - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); - - error = ieee80211_register_hw(hw); - - if (!ath_is_world_regd(reg)) { - error = regulatory_hint(hw->wiphy, reg->alpha2); - if (error) - goto error_attach; - } - - /* Initialize LED control */ - ath_init_leds(sc); - - ath_start_rfkill_poll(sc); - - return 0; - -error_attach: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - ath9k_uninit_hw(sc); - - return error; -} - int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; @@ -1648,125 +991,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } -/* - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ -int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head, const char *name, - int nbuf, int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", - name, nbuf, ndesc); - - INIT_LIST_HEAD(head); - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - ath_print(common, ATH_DBG_FATAL, - "ath_desc not DWORD aligned\n"); - BUG_ON((sizeof(struct ath_desc) % 4) != 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, - &dd->dd_desc_paddr, GFP_KERNEL); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kzalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - dd->dd_bufptr = bf; - - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - BUG_ON((caddr_t) bf->bf_desc >= - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) { int qnum; @@ -2778,63 +2002,3 @@ struct ieee80211_ops ath9k_ops = { .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, }; - -static int __init ath9k_init(void) -{ - int error; - - /* Register rate control algorithm */ - error = ath_rate_control_register(); - if (error != 0) { - printk(KERN_ERR - "ath9k: Unable to register rate control " - "algorithm: %d\n", - error); - goto err_out; - } - - error = ath9k_debug_create_root(); - if (error) { - printk(KERN_ERR - "ath9k: Unable to create debugfs root: %d\n", - error); - goto err_rate_unregister; - } - - error = ath_pci_init(); - if (error < 0) { - printk(KERN_ERR - "ath9k: No PCI devices found, driver not installed.\n"); - error = -ENODEV; - goto err_remove_root; - } - - error = ath_ahb_init(); - if (error < 0) { - error = -ENODEV; - goto err_pci_exit; - } - - return 0; - - err_pci_exit: - ath_pci_exit(); - - err_remove_root: - ath9k_debug_remove_root(); - err_rate_unregister: - ath_rate_control_unregister(); - err_out: - return error; -} -module_init(ath9k_init); - -static void __exit ath9k_exit(void) -{ - ath_ahb_exit(); - ath_pci_exit(); - ath9k_debug_remove_root(); - ath_rate_control_unregister(); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); -} -module_exit(ath9k_exit); -- GitLab From 1b04b9308ebc7f6accb319cf51c9b8ec29f79707 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:05 +0530 Subject: [PATCH 0554/3892] ath9k: Cleanup Powersave flags sc_flags has slowly become a kitchen sink over time. Move powersave related flags to a separate variable. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 43 ++++++++++++++------------ drivers/net/wireless/ath/ath9k/main.c | 36 ++++++++++----------- drivers/net/wireless/ath/ath9k/recv.c | 36 ++++++++++----------- drivers/net/wireless/ath/ath9k/xmit.c | 18 +++++------ 4 files changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 68a423054e6c..f4645a45ef3c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -416,26 +416,28 @@ void ath_deinit_leds(struct ath_softc *sc); #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_RATE_DUMMY_MARKER 0 -#define SC_OP_INVALID BIT(0) -#define SC_OP_BEACONS BIT(1) -#define SC_OP_RXAGGR BIT(2) -#define SC_OP_TXAGGR BIT(3) -#define SC_OP_FULL_RESET BIT(4) -#define SC_OP_PREAMBLE_SHORT BIT(5) -#define SC_OP_PROTECT_ENABLE BIT(6) -#define SC_OP_RXFLUSH BIT(7) -#define SC_OP_LED_ASSOCIATED BIT(8) -#define SC_OP_WAIT_FOR_BEACON BIT(12) -#define SC_OP_LED_ON BIT(13) -#define SC_OP_SCANNING BIT(14) -#define SC_OP_TSF_RESET BIT(15) -#define SC_OP_WAIT_FOR_CAB BIT(16) -#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) -#define SC_OP_WAIT_FOR_TX_ACK BIT(18) -#define SC_OP_BEACON_SYNC BIT(19) -#define SC_OP_BT_PRIORITY_DETECTED BIT(21) -#define SC_OP_NULLFUNC_COMPLETED BIT(22) -#define SC_OP_PS_ENABLED BIT(23) +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_FULL_RESET BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_LED_ON BIT(9) +#define SC_OP_SCANNING BIT(10) +#define SC_OP_TSF_RESET BIT(11) +#define SC_OP_BT_PRIORITY_DETECTED BIT(12) + +/* Powersave flags */ +#define PS_WAIT_FOR_BEACON BIT(0) +#define PS_WAIT_FOR_CAB BIT(1) +#define PS_WAIT_FOR_PSPOLL_DATA BIT(2) +#define PS_WAIT_FOR_TX_ACK BIT(3) +#define PS_BEACON_SYNC BIT(4) +#define PS_NULLFUNC_COMPLETED BIT(5) +#define PS_ENABLED BIT(6) struct ath_wiphy; struct ath_rate_table; @@ -471,6 +473,7 @@ struct ath_softc { u32 intrstatus; u32 sc_flags; /* SC_OP_* */ + u16 ps_flags; /* PS_* */ u16 curtxpow; u8 nbcnvifs; u16 nvifs; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 48bd5d50f4d6..974de2056b4a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -144,10 +144,10 @@ void ath9k_ps_restore(struct ath_softc *sc) goto unlock; if (sc->ps_enabled && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) + !(sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK))) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: @@ -424,7 +424,7 @@ void ath9k_tasklet(unsigned long data) */ ath_print(common, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; } if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) @@ -525,7 +525,7 @@ irqreturn_t ath_isr(int irq, void *dev) * receive frames */ ath9k_setpower(sc, ATH9K_PM_AWAKE); ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; + sc->ps_flags |= PS_WAIT_FOR_BEACON; } chip_reset: @@ -833,7 +833,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, * on the receipt of the first Beacon frame (i.e., * after time sync with the AP). */ - sc->sc_flags |= SC_OP_BEACON_SYNC; + sc->ps_flags |= PS_BEACON_SYNC; /* Configure the beacon */ ath_beacon_config(sc, vif); @@ -1238,11 +1238,11 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (ieee80211_is_pspoll(hdr->frame_control)) { ath_print(common, ATH_DBG_PS, "Sending PS-Poll to pick a buffered frame\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; + sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; } else { ath_print(common, ATH_DBG_PS, "Wake up to complete TX\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; + sc->ps_flags |= PS_WAIT_FOR_TX_ACK; } /* * The actual restore operation will happen only after @@ -1538,7 +1538,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) */ if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { - sc->sc_flags |= SC_OP_PS_ENABLED; + sc->ps_flags |= PS_ENABLED; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { @@ -1551,23 +1551,23 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * At this point we know hardware has received an ACK * of a previously sent null data frame. */ - if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { - sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) { + sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; sc->ps_enabled = true; ath9k_hw_setrxabort(sc->sc_ah, 1); } } else { sc->ps_enabled = false; - sc->sc_flags &= ~(SC_OP_PS_ENABLED | - SC_OP_NULLFUNC_COMPLETED); + sc->ps_flags &= ~(PS_ENABLED | + PS_NULLFUNC_COMPLETED); ath9k_setpower(sc, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK); + sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK); if (sc->imask & ATH9K_INT_TIM_TIMER) { sc->imask &= ~ATH9K_INT_TIM_TIMER; ath9k_hw_set_interrupts(sc->sc_ah, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 477365e5ae69..17b0a6dd8caf 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + sc->ps_flags &= ~PS_WAIT_FOR_BEACON; - if (sc->sc_flags & SC_OP_BEACON_SYNC) { - sc->sc_flags &= ~SC_OP_BEACON_SYNC; + if (sc->ps_flags & PS_BEACON_SYNC) { + sc->ps_flags &= ~PS_BEACON_SYNC; ath_print(common, ATH_DBG_PS, "Reconfigure Beacon timers based on " "timestamp from the AP\n"); @@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) */ ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating " "buffered broadcast/multicast frame(s)\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; + sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON; return; } - if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { + if (sc->ps_flags & PS_WAIT_FOR_CAB) { /* * This can happen if a broadcast frame is dropped or the AP * fails to send a frame indicating that all CAB frames have * been delivered. */ - sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; + sc->ps_flags &= ~PS_WAIT_FOR_CAB; ath_print(common, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } @@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; /* Process Beacon and CAB receive in PS state */ - if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && + if ((sc->ps_flags & PS_WAIT_FOR_BEACON) && ieee80211_is_beacon(hdr->frame_control)) ath_rx_ps_beacon(sc, skb); - else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && + else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && @@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) * No more broadcast/multicast frames to be received at this * point. */ - sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; + sc->ps_flags &= ~PS_WAIT_FOR_CAB; ath_print(common, ATH_DBG_PS, "All PS CAB frames received, back to sleep\n"); - } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && + } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { - sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; + sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; ath_print(common, ATH_DBG_PS, "Going back to sleep after having received " "PS-Poll data (0x%x)\n", - sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK)); + sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK)); } } @@ -631,9 +631,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.rxotherant = 0; } - if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA))) + if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA))) ath_rx_ps(sc, skb); ath_rx_send_to_mac80211(hw, sc, skb, rxs); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fa12b9060b0b..a821bb687b3b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1648,7 +1648,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, /* tag if this is a nullfunc frame to enable PS when AP acks it */ if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { bf->bf_isnullfunc = true; - sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; } else bf->bf_isnullfunc = false; @@ -1858,15 +1858,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } - if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { - sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; + if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) { + sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; ath_print(common, ATH_DBG_PS, "Going back to sleep after having " "received TX status (0x%x)\n", - sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK)); + sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK)); } if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) @@ -2053,11 +2053,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) */ if (bf->bf_isnullfunc && (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { - if ((sc->sc_flags & SC_OP_PS_ENABLED)) { + if ((sc->ps_flags & PS_ENABLED)) { sc->ps_enabled = true; ath9k_hw_setrxabort(sc->sc_ah, 1); } else - sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; + sc->ps_flags |= PS_NULLFUNC_COMPLETED; } /* -- GitLab From 285f2ddae03ca207877262f5a9dbd9cddd8b3913 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:07 +0530 Subject: [PATCH 0555/3892] ath9k: Cleanup init/deinit routines The device initialization and termination functions were messy and convoluted. Introduce helper functions to clarify init_softc() and simplify things in general. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 20 +- drivers/net/wireless/ath/ath9k/ath9k.h | 7 +- drivers/net/wireless/ath/ath9k/hw.c | 4 +- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/init.c | 515 ++++++++++++----------- drivers/net/wireless/ath/ath9k/pci.c | 57 +-- drivers/net/wireless/ath/ath9k/virtual.c | 2 +- 7 files changed, 309 insertions(+), 298 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 329e6bc137ab..f24b1f4c3e29 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -121,16 +121,16 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { - dev_err(&pdev->dev, "failed to initialize device\n"); + dev_err(&pdev->dev, "request_irq failed\n"); goto err_free_hw; } - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); + ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); if (ret) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto err_detach; + dev_err(&pdev->dev, "failed to initialize device\n"); + goto err_irq; } ah = sc->sc_ah; @@ -143,8 +143,8 @@ static int ath_ahb_probe(struct platform_device *pdev) return 0; - err_detach: - ath_detach(sc); + err_irq: + free_irq(irq, sc); err_free_hw: ieee80211_free_hw(hw); platform_set_drvdata(pdev, NULL); @@ -161,8 +161,12 @@ static int ath_ahb_remove(struct platform_device *pdev) if (hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_cleanup(sc); + ath9k_deinit_device(sc); + free_irq(sc->irq, sc); + ieee80211_free_hw(sc->hw); + ath_bus_cleanup(common); platform_set_drvdata(pdev, NULL); } diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f4645a45ef3c..bf3d4c4bfa52 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -544,13 +544,12 @@ extern struct ieee80211_ops ath9k_ops; extern int modparam_nohwcrypt; irqreturn_t ath_isr(int irq, void *dev); -void ath_cleanup(struct ath_softc *sc); -int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, +int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops); -void ath_detach(struct ath_softc *sc); +void ath9k_deinit_device(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); -void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *ichan); void ath_update_chainmask(struct ath_softc *sc, int is_ht); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9474f9f6d400..2311fe7a0bf2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1242,7 +1242,7 @@ static void ath9k_hw_init_user_settings(struct ath_hw *ah) ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); } -void ath9k_hw_detach(struct ath_hw *ah) +void ath9k_hw_deinit(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1260,7 +1260,7 @@ free_hw: kfree(ah); ah = NULL; } -EXPORT_SYMBOL(ath9k_hw_detach); +EXPORT_SYMBOL(ath9k_hw_deinit); /*******/ /* INI */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 8849450dc591..3f0f055ea39b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -616,7 +616,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) /* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); -void ath9k_hw_detach(struct ath_hw *ah); +void ath9k_hw_deinit(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2bea0892918e..16d1efb4b8b2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -128,7 +128,7 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { RATE(540, 0x0c, 0), }; -static void ath9k_uninit_hw(struct ath_softc *sc); +static void ath9k_deinit_softc(struct ath_softc *sc); /* * Read and write, they both share the same lock. We do this to serialize @@ -333,67 +333,13 @@ fail: #undef DS2PHYS } -static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, - const struct ath_bus_ops *bus_ops) +static void ath9k_init_crypto(struct ath_softc *sc) { - struct ath_hw *ah = NULL; - struct ath_common *common; - int r = 0, i; - int csz = 0; - int qnum; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - - spin_lock_init(&sc->wiphy_lock); - spin_lock_init(&sc->sc_resetlock); - spin_lock_init(&sc->sc_serial_rw); - spin_lock_init(&sc->sc_pm_lock); - mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, - (unsigned long)sc); - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (!ah) - return -ENOMEM; - - ah->hw_version.devid = devid; - ah->hw_version.subsysid = subsysid; - sc->sc_ah = ah; - - common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; - common->bus_ops = bus_ops; - common->ah = ah; - common->hw = sc->hw; - common->priv = sc; - common->debug_mask = ath9k_debug; - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - ath_read_cachesize(common, &csz); - /* XXX assert csz is non-zero */ - common->cachelsz = csz << 2; /* convert to bytes */ - - r = ath9k_hw_init(ah); - if (r) { - ath_print(common, ATH_DBG_FATAL, - "Unable to initialize hardware; " - "initialization status: %d\n", r); - goto bad_free_hw; - } - - if (ath9k_init_debug(ah) < 0) { - ath_print(common, ATH_DBG_FATAL, - "Unable to create debugfs files\n"); - goto bad_free_hw; - } + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int i = 0; /* Get the hardware key cache size. */ - common->keymax = ah->caps.keycache_size; + common->keymax = sc->sc_ah->caps.keycache_size; if (common->keymax > ATH_KEYMAX) { ath_print(common, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", @@ -406,185 +352,273 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, * reset the contents on initial power up. */ for (i = 0; i < common->keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); + ath9k_hw_keyreset(sc->sc_ah, (u16) i); - /* default to MONITOR mode */ - sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); + } /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. */ - sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); + if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + common->splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, + 1, 1, NULL); + +} + +static int ath9k_init_btcoex(struct ath_softc *sc) +{ + int r, qnum; + + switch (sc->sc_ah->btcoex_hw.scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(sc->sc_ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(sc->sc_ah); + r = ath_init_btcoex_timer(sc); + if (r) + return -1; + qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + break; + default: + WARN_ON(1); + break; + } + + return 0; +} + +static int ath9k_init_queues(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int i = 0; + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); if (sc->beacon.beaconq == -1) { ath_print(common, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); - r = -EIO; - goto bad2; + goto err; } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { ath_print(common, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); - r = -EIO; - goto bad2; + goto err; } sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) - sc->tx.hwq_map[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for BK traffic\n"); - r = -EIO; - goto bad2; + goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for BE traffic\n"); - r = -EIO; - goto bad2; + goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for VI traffic\n"); - r = -EIO; - goto bad2; + goto err; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { ath_print(common, ATH_DBG_FATAL, "Unable to setup xmit queue for VO traffic\n"); - r = -EIO; - goto bad2; + goto err; } - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ + return 0; - common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); +err: + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); + return -EIO; +} + +static void ath9k_init_channels_rates(struct ath_softc *sc) +{ + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); } - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - common->splitmic = 1; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } +} - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); +static void ath9k_init_misc(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int i = 0; + + common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); sc->config.txpowlimit = ATH_TXPOWER_MAX; - /* 11n Capabilities */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { sc->sc_flags |= SC_OP_TXAGGR; sc->sc_flags |= SC_OP_RXAGGR; } - common->tx_chainmask = ah->caps.tx_chainmask; - common->rx_chainmask = ah->caps.rx_chainmask; + common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; + common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->rx.defant = ath9k_hw_getdefantenna(ah); + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + sc->beacon.slottime = ATH9K_SLOT_TIME_9; - /* initialize beacon slots */ for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { sc->beacon.bslot[i] = NULL; sc->beacon.bslot_aphy[i] = NULL; } +} - /* setup channels and rates */ +static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) +{ + struct ath_hw *ah = NULL; + struct ath_common *common; + int ret = 0, i; + int csz = 0; - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } + sc->sc_flags |= SC_OP_INVALID; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) + return -ENOMEM; + + ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; + sc->sc_ah = ah; + + common = ath9k_hw_common(ah); + common->ops = &ath9k_common_ops; + common->bus_ops = bus_ops; + common->ah = ah; + common->hw = sc->hw; + common->priv = sc; + common->debug_mask = ath9k_debug; + + spin_lock_init(&sc->wiphy_lock); + spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->sc_pm_lock); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, + (unsigned long)sc); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(common, &csz); + common->cachelsz = csz << 2; /* convert to bytes */ + + ret = ath9k_hw_init(ah); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", ret); + goto err_hw; } - switch (ah->btcoex_hw.scheme) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_2WIRE: - ath9k_hw_btcoex_init_2wire(ah); - break; - case ATH_BTCOEX_CFG_3WIRE: - ath9k_hw_btcoex_init_3wire(ah); - r = ath_init_btcoex_timer(sc); - if (r) - goto bad2; - qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - ath9k_hw_init_btcoex_hw(ah, qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - default: - WARN_ON(1); - break; + ret = ath9k_init_debug(ah); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to create debugfs files\n"); + goto err_debug; } + ret = ath9k_init_queues(sc); + if (ret) + goto err_queues; + + ret = ath9k_init_btcoex(sc); + if (ret) + goto err_btcoex; + + ath9k_init_crypto(sc); + ath9k_init_channels_rates(sc); + ath9k_init_misc(sc); + return 0; -bad2: - /* cleanup tx queues */ + +err_btcoex: for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); +err_queues: + ath9k_exit_debug(ah); +err_debug: + ath9k_hw_deinit(ah); +err_hw: + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); -bad_free_hw: - ath9k_uninit_hw(sc); - return r; + kfree(ah); + sc->sc_ah = NULL; + + return ret; } -void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | @@ -621,85 +655,85 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } -/* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, +int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; struct ath_common *common; struct ath_hw *ah; - int error = 0, i; + int error = 0; struct ath_regulatory *reg; - dev_dbg(sc->dev, "Attach ATH hw\n"); - - error = ath_init_softc(devid, sc, subsysid, bus_ops); + /* Bring up device */ + error = ath9k_init_softc(devid, sc, subsysid, bus_ops); if (error != 0) - return error; + goto error_init; ah = sc->sc_ah; common = ath9k_hw_common(ah); + ath9k_set_hw_capab(sc, hw); - /* get mac address from hardware and set in mac80211 */ - - SET_IEEE80211_PERM_ADDR(hw, common->macaddr); - - ath_set_hw_capab(sc, hw); - + /* Initialize regulatory */ error = ath_regd_init(&common->regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) - return error; + goto error_regd; reg = &common->regulatory; - if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) - setup_ht_cap(sc, - &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) - setup_ht_cap(sc, - &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } - - /* initialize tx/rx engine */ + /* Setup TX DMA */ error = ath_tx_init(sc, ATH_TXBUF); if (error != 0) - goto error_attach; + goto error_tx; + /* Setup RX DMA */ error = ath_rx_init(sc, ATH_RXBUF); if (error != 0) - goto error_attach; - - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); + goto error_rx; + /* Register with mac80211 */ error = ieee80211_register_hw(hw); + if (error) + goto error_register; + /* Handle world regulatory */ if (!ath_is_world_regd(reg)) { error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) - goto error_attach; + goto error_world; } - /* Initialize LED control */ - ath_init_leds(sc); + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(500); + ath_init_leds(sc); ath_start_rfkill_poll(sc); return 0; -error_attach: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - ath9k_uninit_hw(sc); - +error_world: + ieee80211_unregister_hw(hw); +error_register: + ath_rx_cleanup(sc); +error_rx: + ath_tx_cleanup(sc); +error_tx: + /* Nothing */ +error_regd: + ath9k_deinit_softc(sc); +error_init: return error; } @@ -707,29 +741,34 @@ error_attach: /* De-Initialization */ /*****************************/ -static void ath9k_uninit_hw(struct ath_softc *sc) +static void ath9k_deinit_softc(struct ath_softc *sc) { - struct ath_hw *ah = sc->sc_ah; + int i = 0; - BUG_ON(!ah); + if ((sc->btcoex.no_stomp_timer) && + sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - ath9k_exit_debug(ah); - ath9k_hw_detach(ah); - sc->sc_ah = NULL; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_exit_debug(sc->sc_ah); + ath9k_hw_deinit(sc->sc_ah); + + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); } -static void ath_clean_core(struct ath_softc *sc) +void ath9k_deinit_device(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; - struct ath_hw *ah = sc->sc_ah; int i = 0; ath9k_ps_wakeup(sc); - dev_dbg(sc->dev, "Detach ATH hw\n"); - - ath_deinit_leds(sc); wiphy_rfkill_stop_polling(sc->hw->wiphy); + ath_deinit_leds(sc); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; @@ -739,24 +778,12 @@ static void ath_clean_core(struct ath_softc *sc) ieee80211_unregister_hw(aphy->hw); ieee80211_free_hw(aphy->hw); } + kfree(sc->sec_wiphy); + ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath_tx_cleanup(sc); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_setpower(sc, ATH9K_PM_AWAKE); - - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - if ((sc->btcoex.no_stomp_timer) && - ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); + ath9k_deinit_softc(sc); } void ath_descdma_cleanup(struct ath_softc *sc, @@ -771,26 +798,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, memset(dd, 0, sizeof(*dd)); } -void ath_detach(struct ath_softc *sc) -{ - ath_clean_core(sc); - ath9k_uninit_hw(sc); -} - -void ath_cleanup(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - ath_clean_core(sc); - free_irq(sc->irq, sc); - ath_bus_cleanup(common); - kfree(sc->sec_wiphy); - ieee80211_free_hw(sc->hw); - - ath9k_uninit_hw(sc); -} - /************************/ /* Module Hooks */ /************************/ diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f7af5ea54753..95b9a07597ef 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -113,25 +113,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) u16 subsysid; u32 val; int ret = 0; - struct ath_hw *ah; char hw_name[64]; if (pci_enable_device(pdev)) return -EIO; ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); - goto bad; + goto err_dma; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA consistent " "DMA enable failed\n"); - goto bad; + goto err_dma; } /* @@ -171,22 +168,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); ret = -ENODEV; - goto bad; + goto err_region; } mem = pci_iomap(pdev, 0, 0); if (!mem) { printk(KERN_ERR "PCI memory map error\n") ; ret = -EIO; - goto bad1; + goto err_iomap; } hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + sizeof(struct ath_softc), &ath9k_ops); if (!hw) { - dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); ret = -ENOMEM; - goto bad2; + goto err_alloc_hw; } SET_IEEE80211_DEV(hw, &pdev->dev); @@ -201,25 +198,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->dev = &pdev->dev; sc->mem = mem; - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); - ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); - if (ret) { - dev_err(&pdev->dev, "failed to initialize device\n"); - goto bad3; - } - - /* setup interrupt service routine */ - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); - goto bad4; + goto err_irq; } sc->irq = pdev->irq; - ah = sc->sc_ah; - ath9k_hw_name(ah, hw_name, sizeof(hw_name)); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); + ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize device\n"); + goto err_init; + } + + ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); printk(KERN_INFO "%s: %s mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), @@ -227,15 +221,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) (unsigned long)mem, pdev->irq); return 0; -bad4: - ath_detach(sc); -bad3: + +err_init: + free_irq(sc->irq, sc); +err_irq: ieee80211_free_hw(hw); -bad2: +err_alloc_hw: pci_iounmap(pdev, mem); -bad1: +err_iomap: pci_release_region(pdev, 0); -bad: +err_region: + /* Nothing */ +err_dma: pci_disable_device(pdev); return ret; } @@ -245,8 +242,12 @@ static void ath_pci_remove(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_cleanup(sc); + ath9k_deinit_device(sc); + free_irq(sc->irq, sc); + ieee80211_free_hw(sc->hw); + ath_bus_cleanup(common); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index cd26caaf44e7..a43fbf84dab9 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) SET_IEEE80211_PERM_ADDR(hw, addr); - ath_set_hw_capab(sc, hw); + ath9k_set_hw_capab(sc, hw); error = ieee80211_register_hw(hw); -- GitLab From cc9c378aa57817003a094e4bb9a953337ebf035a Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:09 +0530 Subject: [PATCH 0556/3892] ath9k: Fix queue handling The TX queues have to be stopped during an internal reset. Not handling this would result in packet loss - fix this. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 974de2056b4a..1f7222aef89f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -944,6 +944,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Stop ANI */ del_timer_sync(&common->ani.timer); + ieee80211_stop_queues(hw); + ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); ath_stoprecv(sc); @@ -985,6 +987,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } } + ieee80211_wake_queues(hw); + /* Start ANI */ ath_start_ani(common); -- GitLab From 1395d3f00a4164caae168b041855d48e0fa9ea4c Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:11 +0530 Subject: [PATCH 0557/3892] ath9k: Add debugfs file for RX errors This file can be used to track frame reception errors. PHY error counts are also added. Location: ath9k/phy#/recv Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 118 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 32 +++++++ drivers/net/wireless/ath/ath9k/mac.h | 34 +++++++ drivers/net/wireless/ath/ath9k/recv.c | 2 + 4 files changed, 186 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 592f1b70f55a..9489b6b25b5f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -580,6 +580,116 @@ static const struct file_operations fops_xmit = { .owner = THIS_MODULE }; +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PHY_ERR(s, p) \ + len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \ + sc->debug.stats.rxstats.phy_err_stats[p]); + + struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, size = 1152; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return 0; + + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "CRC ERR", + sc->debug.stats.rxstats.crc_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "DECRYPT CRC ERR", + sc->debug.stats.rxstats.decrypt_crc_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "PHY ERR", + sc->debug.stats.rxstats.phy_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "MIC ERR", + sc->debug.stats.rxstats.mic_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "PRE-DELIM CRC ERR", + sc->debug.stats.rxstats.pre_delim_crc_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "POST-DELIM CRC ERR", + sc->debug.stats.rxstats.post_delim_crc_err); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "DECRYPT BUSY ERR", + sc->debug.stats.rxstats.decrypt_busy_err); + + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PHY_ERR +} + +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf) +{ +#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ +#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ + + struct ath_desc *ds = bf->bf_desc; + u32 phyerr; + + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + RX_STAT_INC(crc_err); + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) + RX_STAT_INC(decrypt_crc_err); + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) + RX_STAT_INC(mic_err); + if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE) + RX_STAT_INC(pre_delim_crc_err); + if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST) + RX_STAT_INC(post_delim_crc_err); + if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY) + RX_STAT_INC(decrypt_busy_err); + + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { + RX_STAT_INC(phy_err); + phyerr = ds->ds_rxstat.rs_phyerr & 0x24; + RX_PHY_ERR_INC(phyerr); + } + +#undef RX_STAT_INC +#undef RX_PHY_ERR_INC +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -632,6 +742,13 @@ int ath9k_init_debug(struct ath_hw *ah) if (!sc->debug.debugfs_xmit) goto err; + sc->debug.debugfs_recv = debugfs_create_file("recv", + S_IRUSR, + sc->debug.debugfs_phy, + sc, &fops_recv); + if (!sc->debug.debugfs_recv) + goto err; + return 0; err: ath9k_exit_debug(ah); @@ -643,6 +760,7 @@ void ath9k_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; + debugfs_remove(sc->debug.debugfs_recv); debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_rcstat); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 536663e3ee11..86780e68b31e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -116,10 +116,35 @@ struct ath_tx_stats { u32 delim_underrun; }; +/** + * struct ath_rx_stats - RX Statistics + * @crc_err: No. of frames with incorrect CRC value + * @decrypt_crc_err: No. of frames whose CRC check failed after + decryption process completed + * @phy_err: No. of frames whose reception failed because the PHY + encountered an error + * @mic_err: No. of frames with incorrect TKIP MIC verification failure + * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections + * @post_delim_crc_err: Post-Frame delimiter CRC error detections + * @decrypt_busy_err: Decryption interruptions counter + * @phy_err_stats: Individual PHY error statistics + */ +struct ath_rx_stats { + u32 crc_err; + u32 decrypt_crc_err; + u32 phy_err; + u32 mic_err; + u32 pre_delim_crc_err; + u32 post_delim_crc_err; + u32 decrypt_busy_err; + u32 phy_err_stats[ATH9K_PHYERR_MAX]; +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; + struct ath_rx_stats rxstats; }; struct ath9k_debug { @@ -130,6 +155,7 @@ struct ath9k_debug { struct dentry *debugfs_rcstat; struct dentry *debugfs_wiphy; struct dentry *debugfs_xmit; + struct dentry *debugfs_recv; struct ath_stats stats; }; @@ -142,6 +168,7 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf); +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -181,6 +208,11 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, { } +static inline void ath_debug_stat_rx(struct ath_softc *sc, + struct ath_buf *bf) +{ +} + static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index e185479e295e..29851e6376a9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -167,6 +167,40 @@ struct ath_rx_status { #define ATH9K_RXKEYIX_INVALID ((u8)-1) #define ATH9K_TXKEYIX_INVALID ((u32)-1) +enum ath9k_phyerr { + ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */ + ATH9K_PHYERR_TIMING = 1, /* Timing error */ + ATH9K_PHYERR_PARITY = 2, /* Illegal parity */ + ATH9K_PHYERR_RATE = 3, /* Illegal rate */ + ATH9K_PHYERR_LENGTH = 4, /* Illegal length */ + ATH9K_PHYERR_RADAR = 5, /* Radar detect */ + ATH9K_PHYERR_SERVICE = 6, /* Illegal service */ + ATH9K_PHYERR_TOR = 7, /* Transmit override receive */ + + ATH9K_PHYERR_OFDM_TIMING = 17, + ATH9K_PHYERR_OFDM_SIGNAL_PARITY = 18, + ATH9K_PHYERR_OFDM_RATE_ILLEGAL = 19, + ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL = 20, + ATH9K_PHYERR_OFDM_POWER_DROP = 21, + ATH9K_PHYERR_OFDM_SERVICE = 22, + ATH9K_PHYERR_OFDM_RESTART = 23, + ATH9K_PHYERR_FALSE_RADAR_EXT = 24, + + ATH9K_PHYERR_CCK_TIMING = 25, + ATH9K_PHYERR_CCK_HEADER_CRC = 26, + ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27, + ATH9K_PHYERR_CCK_SERVICE = 30, + ATH9K_PHYERR_CCK_RESTART = 31, + ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32, + ATH9K_PHYERR_CCK_POWER_DROP = 33, + + ATH9K_PHYERR_HT_CRC_ERROR = 34, + ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, + ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, + + ATH9K_PHYERR_MAX = 37, +}; + struct ath_desc { u32 ds_link; u32 ds_data; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 17b0a6dd8caf..40b5d05edcce 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -571,6 +571,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hw = ath_get_virt_hw(sc, hdr); rx_stats = &ds->ds_rxstat; + ath_debug_stat_rx(sc, bf); + /* * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. -- GitLab From 199afd9d89b18e8b530734ed73788518e19bed9b Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 8 Jan 2010 10:36:13 +0530 Subject: [PATCH 0558/3892] ath9k: Fix monitor mode handling mac80211 passes appropriate flags indicating whether monitor mode is being used. Use this to set the HW opmode. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1f7222aef89f..b39c7bc41143 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1581,6 +1581,14 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (conf->flags & IEEE80211_CONF_MONITOR) { + ath_print(common, ATH_DBG_CONFIG, + "HW opmode set to Monitor mode\n"); + sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + } + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; -- GitLab From d524215f6cad245249df8def19125ae6fd0bcc9b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Jan 2010 18:06:26 +0100 Subject: [PATCH 0559/3892] mac80211: use nullfunc frames for 4-addr sta detection To detect incoming 4-addr stations, hostapd needs to receive a 4-addr data frame from the remote station, so that it can create the AP VLAN for it. With this patch, the mlme code emits a 4-addr nullfunc frame immediately after assoc. On the AP side it also drops 4-addr nullfunc frames to the cooked monitor mode interface, if the interface hasn't been fully set up to receive 4-addr data frames yet. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 39 +++++++++++++++++++++++++++++++++++++++ net/mac80211/rx.c | 12 ++++++++++++ 2 files changed, 51 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5484cf930a87..0336dbb45ac5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -282,6 +282,38 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, ieee80211_tx_skb(sdata, skb); } +static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + struct sk_buff *skb; + struct ieee80211_hdr *nullfunc; + __le16 fc; + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + return; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr " + "nullfunc frame\n", sdata->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30); + memset(nullfunc, 0, 30); + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; + memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); + memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); +} + /* spectrum management related things */ static void ieee80211_chswitch_work(struct work_struct *work) { @@ -1089,6 +1121,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, bss_conf->assoc_capability = capab_info; ieee80211_set_associated(sdata, cbss, changed); + /* + * If we're using 4-addr mode, let the AP know that we're + * doing so, so that it can create the STA VLAN on its side + */ + if (ifmgd->use_4addr) + ieee80211_send_4addr_nullfunc(local, sdata); + /* * Start timer to probe the connection to the AP now. * Also start the timer that will detect beacon loss. diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e12f39a96460..efa6d3689c5e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1111,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); + + /* + * If we receive a 4-addr nullfunc frame from a STA + * that was not moved to a 4-addr STA vlan yet, drop + * the frame to the monitor interface, to make sure + * that hostapd sees it + */ + if (ieee80211_has_a4(hdr->frame_control) && + (rx->sdata->vif.type == NL80211_IFTYPE_AP || + (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + !rx->sdata->u.vlan.sta))) + return RX_DROP_MONITOR; /* * Update counter and free packet here to avoid * counting this as a dropped packed. -- GitLab From 0e5ded5a87c097760abd68521b86f1025dedc7d7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Jan 2010 18:10:58 +0100 Subject: [PATCH 0560/3892] mac80211: allow station updates on ap interfaces for vlan stations Since the per-vif station changes, sta_info_get on the ap sdata no longer returns entries for stations on ap vlans. This causes issues with hostapd, which currently always passes the ap interface name to nl80211 calls. This patch provides bug compatibility with the earlier versions until hostapd is fixed. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 12 ++++++------ net/mac80211/sta_info.c | 21 +++++++++++++++++++++ net/mac80211/sta_info.h | 3 +++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e5dda6fb8dff..dc12e9466ffd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -148,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get(sdata, mac_addr); + sta = sta_info_get_bss(sdata, mac_addr); if (!sta) { ieee80211_key_free(key); err = -ENOENT; @@ -179,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (mac_addr) { ret = -ENOENT; - sta = sta_info_get(sdata, mac_addr); + sta = sta_info_get_bss(sdata, mac_addr); if (!sta) goto out_unlock; @@ -226,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get(sdata, mac_addr); + sta = sta_info_get_bss(sdata, mac_addr); if (!sta) goto out; @@ -419,7 +419,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); - sta = sta_info_get(sdata, mac); + sta = sta_info_get_bss(sdata, mac); if (sta) { ret = 0; sta_set_sinfo(sta, sinfo); @@ -775,7 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, if (mac) { rcu_read_lock(); - sta = sta_info_get(sdata, mac); + sta = sta_info_get_bss(sdata, mac); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -803,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, rcu_read_lock(); - sta = sta_info_get(sdata, mac); + sta = sta_info_get_bss(sdata, mac); if (!sta) { rcu_read_unlock(); return -ENOENT; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 47da552ce8a6..f735826f055c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -119,6 +119,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, return sta; } +/* + * Get sta info either from the specified interface + * or from one of its vlans + */ +struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, + const u8 *addr) +{ + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + + sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); + while (sta) { + if ((sta->sdata == sdata || + sta->sdata->bss == sdata->bss) && + memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) + break; + sta = rcu_dereference(sta->hnext); + } + return sta; +} + struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, int idx) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c8208236e896..6f79bba5706e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -408,6 +408,9 @@ static inline u32 get_sta_flags(struct sta_info *sta) struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, const u8 *addr); +struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, + const u8 *addr); + static inline void for_each_sta_info_type_check(struct ieee80211_local *local, const u8 *addr, -- GitLab From 3f0e0b220f80075ce15483b20458192c0ac27426 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Jan 2010 18:15:13 +0100 Subject: [PATCH 0561/3892] mac80211: do not transmit frames on unconfigured 4-addr vlan interfaces If frames are transmitted on 4-addr ap vlan interfaces with no station, they end up being transmitted unencrypted, even if the ap interface uses WPA. This patch add some sanity checking to make sure that this does not happen. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0661e696a1dd..47ca59e52e71 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1056,8 +1056,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, hdr = (struct ieee80211_hdr *) skb->data; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { tx->sta = rcu_dereference(sdata->u.vlan.sta); + if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) + return TX_DROP; + } if (!tx->sta) tx->sta = sta_info_get(sdata, hdr->addr1); -- GitLab From c2c2b12a8b6cd23d4abbc086642647c656bf406c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:27:59 +0100 Subject: [PATCH 0562/3892] mwl8k: minor cleanups Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a04863633d1a..cc160418e6c5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -208,10 +208,7 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { - /* Local MAC address. */ - u8 mac_addr[ETH_ALEN]; - - /* Non AMPDU sequence number assigned by driver */ + /* Non AMPDU sequence number assigned by driver. */ u16 seqno; }; #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) @@ -2287,8 +2284,8 @@ struct mwl8k_cmd_set_rts_threshold { __le16 threshold; } __attribute__((packed)); -static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, - u16 action, u16 threshold) +static int +mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) { struct mwl8k_cmd_set_rts_threshold *cmd; int rc; @@ -2299,8 +2296,8 @@ static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(action); - cmd->threshold = cpu_to_le16(threshold); + cmd->action = cpu_to_le16(MWL8K_CMD_SET); + cmd->threshold = cpu_to_le16(rts_thresh); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2955,14 +2952,13 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, return -EINVAL; } + /* Set the mac address. */ + mwl8k_cmd_set_mac_addr(hw, vif->addr); + /* Clean out driver private area */ mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); - /* Set and save the mac address */ - mwl8k_cmd_set_mac_addr(hw, vif->addr); - memcpy(mwl8k_vif->mac_addr, vif->addr, ETH_ALEN); - /* Set Initial sequence number to zero */ mwl8k_vif->seqno = 0; @@ -2977,9 +2973,6 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; - if (priv->vif == NULL) - return; - mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); priv->vif = NULL; @@ -3252,7 +3245,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - return mwl8k_cmd_set_rts_threshold(hw, MWL8K_CMD_SET, value); + return mwl8k_cmd_set_rts_threshold(hw, value); } struct mwl8k_sta_notify_item @@ -3669,7 +3662,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* * Temporarily enable interrupts. Initial firmware host - * commands use interrupts and avoids polling. Disable + * commands use interrupts and avoid polling. Disable * interrupts when done. */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); -- GitLab From b569e924a9ea7c6f03dcf9b8a98d78d341925b87 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:28:14 +0100 Subject: [PATCH 0563/3892] mwl8k: undo transmit queue 0/1 swapping in mwl8k_cmd_set_edca_params() The comment and code in mwl8k_cmd_set_edca_params() suggest that the mapping between SET_EDCA_PARAMS queue numbers and transmit rings isn't actually 1:1, while tests show that the mapping is in fact 1:1. So, get rid of the transmit queue 0/1 swapping. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cc160418e6c5..3f5fdb69a2be 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2397,12 +2397,6 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, if (cmd == NULL) return -ENOMEM; - /* - * Queues 0 (BE) and 1 (BK) are swapped in hardware for - * this call. - */ - qnum ^= !(qnum >> 1); - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); -- GitLab From 62abd3cfb2f1a0ab1963ac4c4087c477da6b1f2a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:28:34 +0100 Subject: [PATCH 0564/3892] mwl8k: bump the transmit wait timeout to 5 seconds While it is reasonable to expect that at least one transmit ring entry will be processed per second while we are waiting for the transmit rings to drain, the firmware can end up doing batching of transmit ring status writeback, which means that the transmit rings can appear stuck for more than a second at a time. Bump the TX drain wait timeout up from 1 to 5 seconds to account for this. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3f5fdb69a2be..8f5f7c9f75f7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1173,7 +1173,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) /* * Must be called with priv->fw_mutex held and tx queues stopped. */ -#define MWL8K_TX_WAIT_TIMEOUT_MS 1000 +#define MWL8K_TX_WAIT_TIMEOUT_MS 5000 static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { -- GitLab From b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:30:16 +0100 Subject: [PATCH 0565/3892] mwl8k: simplify mwl8k_cmd_use_fixed_rate() As we always use the auto rate adaptation feature and never pass in a rate table, USE_FIXED_RATE can be simplified somewhat. While we're at it, rename it to *_sta, as this is the STA version of the command. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 88 +++++++++--------------------------- 1 file changed, 22 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8f5f7c9f75f7..20e7cf2e266c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2482,49 +2482,30 @@ static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) } /* - * CMD_USE_FIXED_RATE. + * CMD_USE_FIXED_RATE (STA version). */ -#define MWL8K_RATE_TABLE_SIZE 8 -#define MWL8K_UCAST_RATE 0 -#define MWL8K_USE_AUTO_RATE 0x0002 - -struct mwl8k_rate_entry { - /* Set to 1 if HT rate, 0 if legacy. */ - __le32 is_ht_rate; - - /* Set to 1 to use retry_count field. */ - __le32 enable_retry; - - /* Specified legacy rate or MCS. */ - __le32 rate; - - /* Number of allowed retries. */ - __le32 retry_count; -} __attribute__((packed)); - -struct mwl8k_rate_table { - /* 1 to allow specified rate and below */ - __le32 allow_rate_drop; - __le32 num_rates; - struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE]; +struct mwl8k_cmd_use_fixed_rate_sta { + struct mwl8k_cmd_pkt header; + __le32 action; + __le32 allow_rate_drop; + __le32 num_rates; + struct { + __le32 is_ht_rate; + __le32 enable_retry; + __le32 rate; + __le32 retry_count; + } rate_entry[8]; + __le32 rate_type; + __le32 reserved1; + __le32 reserved2; } __attribute__((packed)); -struct mwl8k_cmd_use_fixed_rate { - struct mwl8k_cmd_pkt header; - __le32 action; - struct mwl8k_rate_table rate_table; - - /* Unicast, Broadcast or Multicast */ - __le32 rate_type; - __le32 reserved1; - __le32 reserved2; -} __attribute__((packed)); +#define MWL8K_USE_AUTO_RATE 0x0002 +#define MWL8K_UCAST_RATE 0 -static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, - u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table) +static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) { - struct mwl8k_cmd_use_fixed_rate *cmd; - int count; + struct mwl8k_cmd_use_fixed_rate_sta *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2533,32 +2514,8 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - - cmd->action = cpu_to_le32(action); - cmd->rate_type = cpu_to_le32(rate_type); - - if (rate_table != NULL) { - /* - * Copy over each field manually so that endian - * conversion can be done. - */ - cmd->rate_table.allow_rate_drop = - cpu_to_le32(rate_table->allow_rate_drop); - cmd->rate_table.num_rates = - cpu_to_le32(rate_table->num_rates); - - for (count = 0; count < rate_table->num_rates; count++) { - struct mwl8k_rate_entry *dst = - &cmd->rate_table.rate_entry[count]; - struct mwl8k_rate_entry *src = - &rate_table->rate_entry[count]; - - dst->is_ht_rate = cpu_to_le32(src->is_ht_rate); - dst->enable_retry = cpu_to_le32(src->enable_retry); - dst->rate = cpu_to_le32(src->rate); - dst->retry_count = cpu_to_le32(src->retry_count); - } - } + cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); + cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -3062,8 +3019,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, if (rc) goto out; - rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, - MWL8K_UCAST_RATE, NULL); + rc = mwl8k_cmd_use_fixed_rate_sta(hw); if (rc) goto out; } -- GitLab From 088aab8b62666a002907c912cd346ae6dc9f42b7 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:30:36 +0100 Subject: [PATCH 0566/3892] mwl8k: add the AP version of USE_FIXED_RATE As with the STA version, unicast will use auto rate adaptation, but the AP version allows setting the rates to be used for management and multicast transmissions, which can be set based on the BSS basic rate set. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 20e7cf2e266c..ec79033801ab 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2523,6 +2523,47 @@ static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) return rc; } +/* + * CMD_USE_FIXED_RATE (AP version). + */ +struct mwl8k_cmd_use_fixed_rate_ap { + struct mwl8k_cmd_pkt header; + __le32 action; + __le32 allow_rate_drop; + __le32 num_rates; + struct mwl8k_rate_entry_ap { + __le32 is_ht_rate; + __le32 enable_retry; + __le32 rate; + __le32 retry_count; + } rate_entry[4]; + u8 multicast_rate; + u8 multicast_rate_type; + u8 management_rate; +} __attribute__((packed)); + +static int +mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) +{ + struct mwl8k_cmd_use_fixed_rate_ap *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); + cmd->multicast_rate = mcast; + cmd->management_rate = mgmt; + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_ENABLE_SNIFFER. */ -- GitLab From 3f5610ff560aeaccf051a6f93f25535c219599a0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:30:58 +0100 Subject: [PATCH 0567/3892] mwl8k: implement AP firmware station database maintenance STA firmware uses UPDATE_STADB to manipulate the hardware station database, whereas AP firmware uses SET_NEW_STN -- this implements the latter, and hooks it into mwl8k_sta_notify(), to be used if we're running on AP firmware. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 134 ++++++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ec79033801ab..f0026f33232d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -281,6 +281,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 #define MWL8K_CMD_SET_MAC_ADDR 0x0202 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 +#define MWL8K_CMD_SET_NEW_STN 0x1111 #define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) @@ -313,6 +314,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(ENABLE_SNIFFER); MWL8K_CMDNAME(SET_MAC_ADDR); MWL8K_CMDNAME(SET_RATEADAPT_MODE); + MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); @@ -2659,6 +2661,90 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) return rc; } +/* + * CMD_SET_NEW_STN. + */ +struct mwl8k_cmd_set_new_stn { + struct mwl8k_cmd_pkt header; + __le16 aid; + __u8 mac_addr[6]; + __le16 stn_id; + __le16 action; + __le16 rsvd; + __le32 legacy_rates; + __u8 ht_rates[4]; + __le16 cap_info; + __le16 ht_capabilities_info; + __u8 mac_ht_param_info; + __u8 rev; + __u8 control_channel; + __u8 add_channel; + __le16 op_mode; + __le16 stbc; + __u8 add_qos_info; + __u8 is_qos_sta; + __le32 fw_sta_ptr; +} __attribute__((packed)); + +#define MWL8K_STA_ACTION_ADD 0 +#define MWL8K_STA_ACTION_REMOVE 2 + +static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mwl8k_cmd_set_new_stn *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->aid = cpu_to_le16(sta->aid); + memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); + cmd->stn_id = cpu_to_le16(sta->aid); + cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); + cmd->legacy_rates = cpu_to_le32(sta->supp_rates[IEEE80211_BAND_2GHZ]); + if (sta->ht_cap.ht_supported) { + cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; + cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; + cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; + cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; + cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); + cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | + ((sta->ht_cap.ampdu_density & 7) << 2); + cmd->is_qos_sta = 1; + } + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + +static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u8 *addr) +{ + struct mwl8k_cmd_set_new_stn *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + memcpy(cmd->mac_addr, addr, ETH_ALEN); + cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_UPDATE_STADB. */ @@ -3247,6 +3333,36 @@ struct mwl8k_sta_notify_item struct ieee80211_sta sta; }; +static void +mwl8k_do_sta_notify(struct ieee80211_hw *hw, struct mwl8k_sta_notify_item *s) +{ + struct mwl8k_priv *priv = hw->priv; + + /* + * STA firmware uses UPDATE_STADB, AP firmware uses SET_NEW_STN. + */ + if (!priv->ap_fw && s->cmd == STA_NOTIFY_ADD) { + int rc; + + rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta); + if (rc >= 0) { + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(s->vif, s->sta.addr); + if (sta != NULL) + MWL8K_STA(sta)->peer_id = rc; + rcu_read_unlock(); + } + } else if (!priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) { + mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr); + } else if (priv->ap_fw && s->cmd == STA_NOTIFY_ADD) { + mwl8k_cmd_set_new_stn_add(hw, s->vif, &s->sta); + } else if (priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) { + mwl8k_cmd_set_new_stn_del(hw, s->vif, s->sta.addr); + } +} + static void mwl8k_sta_notify_worker(struct work_struct *work) { struct mwl8k_priv *priv = @@ -3263,23 +3379,7 @@ static void mwl8k_sta_notify_worker(struct work_struct *work) spin_unlock_bh(&priv->sta_notify_list_lock); - if (s->cmd == STA_NOTIFY_ADD) { - int rc; - - rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta); - if (rc >= 0) { - struct ieee80211_sta *sta; - - rcu_read_lock(); - sta = ieee80211_find_sta(s->vif, s->sta.addr); - if (sta != NULL) - MWL8K_STA(sta)->peer_id = rc; - rcu_read_unlock(); - } - } else { - mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr); - } - + mwl8k_do_sta_notify(hw, s); kfree(s); spin_lock_bh(&priv->sta_notify_list_lock); -- GitLab From a9e00b151ec2121b7ae09d84a2b5a68b6461e98a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:31:30 +0100 Subject: [PATCH 0568/3892] mwl8k: correctly set the mac_type field for AP SET_MAC_ADDR Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f0026f33232d..428575beb8d0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2607,6 +2607,9 @@ struct mwl8k_cmd_set_mac_addr { }; } __attribute__((packed)); +#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 +#define MWL8K_MAC_TYPE_PRIMARY_AP 2 + static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) { struct mwl8k_priv *priv = hw->priv; @@ -2620,7 +2623,7 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); cmd->header.length = cpu_to_le16(sizeof(*cmd)); if (priv->ap_fw) { - cmd->mbss.mac_type = 0; + cmd->mbss.mac_type = cpu_to_le16(MWL8K_MAC_TYPE_PRIMARY_AP); memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); } else { memcpy(cmd->mac_addr, mac, ETH_ALEN); -- GitLab From b64fe619e371fc17d8d686d6d44aef1b41317880 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:31:39 +0100 Subject: [PATCH 0569/3892] mwl8k: basic AP interface support Add support for creating AP interfaces, and enabling beaconing. This allows running a basic AP (11b/g mode only for now). Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 171 ++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 428575beb8d0..759c94fb8e77 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -266,6 +266,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_RF_ANTENNA 0x0020 +#define MWL8K_CMD_SET_BEACON 0x0100 #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 #define MWL8K_CMD_SET_RF_CHANNEL 0x010a @@ -281,6 +282,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 #define MWL8K_CMD_SET_MAC_ADDR 0x0202 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 +#define MWL8K_CMD_BSS_START 0x1100 #define MWL8K_CMD_SET_NEW_STN 0x1111 #define MWL8K_CMD_UPDATE_STADB 0x1123 @@ -299,6 +301,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(RADIO_CONTROL); MWL8K_CMDNAME(RF_TX_POWER); MWL8K_CMDNAME(RF_ANTENNA); + MWL8K_CMDNAME(SET_BEACON); MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); @@ -314,6 +317,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(ENABLE_SNIFFER); MWL8K_CMDNAME(SET_MAC_ADDR); MWL8K_CMDNAME(SET_RATEADAPT_MODE); + MWL8K_CMDNAME(BSS_START); MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_STADB); default: @@ -1769,7 +1773,9 @@ struct mwl8k_cmd_set_hw_spec { __le32 total_rxd; } __attribute__((packed)); -#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 +#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 +#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 +#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) { @@ -1790,7 +1796,9 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); for (i = 0; i < MWL8K_TX_QUEUES; i++) cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); - cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); + cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -2027,6 +2035,35 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) return rc; } +/* + * CMD_SET_BEACON. + */ +struct mwl8k_cmd_set_beacon { + struct mwl8k_cmd_pkt header; + __le16 beacon_len; + __u8 beacon[0]; +}; + +static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, u8 *beacon, int len) +{ + struct mwl8k_cmd_set_beacon *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); + cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); + cmd->beacon_len = cpu_to_le16(len); + memcpy(cmd->beacon, beacon, len); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_SET_PRE_SCAN. */ @@ -2664,6 +2701,33 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) return rc; } +/* + * CMD_BSS_START. + */ +struct mwl8k_cmd_bss_start { + struct mwl8k_cmd_pkt header; + __le32 enable; +} __attribute__((packed)); + +static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, int enable) +{ + struct mwl8k_cmd_bss_start *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->enable = cpu_to_le32(enable); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_SET_NEW_STN. */ @@ -2727,6 +2791,26 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, return rc; } +static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mwl8k_cmd_set_new_stn *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 *addr) { @@ -3015,16 +3099,10 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, if (priv->vif != NULL) return -EBUSY; - /* - * We only support managed interfaces for now. - */ - if (vif->type != NL80211_IFTYPE_STATION) - return -EINVAL; - /* * Reject interface creation if sniffer mode is active, as * STA operation is mutually exclusive with hardware sniffer - * mode. + * mode. (Sniffer mode is only used on STA firmware.) */ if (priv->sniffer_enabled) { printk(KERN_INFO "%s: unable to create STA " @@ -3036,6 +3114,9 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* Set the mac address. */ mwl8k_cmd_set_mac_addr(hw, vif->addr); + if (priv->ap_fw) + mwl8k_cmd_set_new_stn_add_self(hw, vif); + /* Clean out driver private area */ mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); @@ -3054,6 +3135,9 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; + if (priv->ap_fw) + mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); + mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); priv->vif = NULL; @@ -3105,10 +3189,9 @@ out: return rc; } -static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) +static void +mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) { struct mwl8k_priv *priv = hw->priv; u32 ap_legacy_rates; @@ -3188,6 +3271,66 @@ out: mwl8k_fw_unlock(hw); } +static void +mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + int rc; + + if (mwl8k_fw_lock(hw)) + return; + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + rc = mwl8k_set_radio_preamble(hw, + vif->bss_conf.use_short_preamble); + if (rc) + goto out; + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + int idx; + int rate; + + /* + * Use lowest supported basic rate for multicasts + * and management frames (such as probe responses -- + * beacons will always go out at 1 Mb/s). + */ + idx = ffs(vif->bss_conf.basic_rates); + rate = idx ? mwl8k_rates[idx - 1].hw_value : 2; + + mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); + } + + if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { + struct sk_buff *skb; + + skb = ieee80211_beacon_get(hw, vif); + if (skb != NULL) { + mwl8k_cmd_set_beacon(hw, skb->data, skb->len); + kfree_skb(skb); + } + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) + mwl8k_cmd_bss_start(hw, info->enable_beacon); + +out: + mwl8k_fw_unlock(hw); +} + +static void +mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mwl8k_priv *priv = hw->priv; + + if (!priv->ap_fw) + mwl8k_bss_info_changed_sta(hw, vif, info, changed); + else + mwl8k_bss_info_changed_ap(hw, vif, info, changed); +} + static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) { @@ -3766,6 +3909,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_cmd_get_hw_spec_ap(hw); if (!rc) rc = mwl8k_cmd_set_hw_spec(hw); + + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP); } else { rc = mwl8k_cmd_get_hw_spec_sta(hw); -- GitLab From efb7c49a68cf206f35793d7799608e1d69a209f9 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:31:47 +0100 Subject: [PATCH 0570/3892] mwl8k: allow limiting the amount of transmit reclaim done Add a limit argument to mwl8k_txq_reclaim(), to allow limiting the number of packets that it will reclaim, and make it return the number of packets that it reclaimed. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 759c94fb8e77..6598efcda5cc 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1249,13 +1249,15 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) -static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) +static int +mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; - int wake = 0; + int processed; - while (txq->stats.len > 0) { + processed = 0; + while (txq->stats.len > 0 && limit--) { int tx; struct mwl8k_tx_desc *tx_desc; unsigned long addr; @@ -1302,11 +1304,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ieee80211_tx_status_irqsafe(hw, skb); - wake = 1; + processed++; } - if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) + if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); + + return processed; } /* must be called only when the card's transmit is completely halted */ @@ -1315,7 +1319,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; - mwl8k_txq_reclaim(hw, index, 1); + mwl8k_txq_reclaim(hw, index, INT_MAX, 1); kfree(txq->skb); txq->skb = NULL; @@ -3084,7 +3088,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, 1); + mwl8k_txq_reclaim(hw, i, INT_MAX, 1); } static int mwl8k_add_interface(struct ieee80211_hw *hw, @@ -3647,7 +3651,7 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) spin_lock_bh(&priv->tx_lock); for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, 0); + mwl8k_txq_reclaim(hw, i, INT_MAX, 0); if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { complete(priv->tx_wait); @@ -4021,7 +4025,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, 1); + mwl8k_txq_reclaim(hw, i, INT_MAX, 1); for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_deinit(hw, i); -- GitLab From 1e9f9de3b17db3aa358f39d6932662324178350d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:32:01 +0100 Subject: [PATCH 0571/3892] mwl8k: keep TX_DONE interrupt masked while transmit reclaim is running By making use of the CLEAR_SEL feature of the mwl8k host interface interrupt controller, we can keep the TX_DONE interrupt source masked while the transmit reclaim tasklet is running (NAPI style) without having to touch the interrupt controller's interrupt mask register when entering or exiting polling mode, and without having to do any more register reads/writes than we do now. When CLEAR_SEL is enabled on the TX_DONE interrupt source, reading the interrupt status register will clear the TX_DONE status bit if it was set, allowing it to be set again if a new TX_DONE event arrives while we are running the TX reclaim tasklet, but such a new event will then not trigger another PCI interrupt until a zero is written to the TX_DONE interrupt status register bit. I.e., if we write a zero to the TX_DONE interrupt source bit in the interrupt status register when the TX reclaim tasklet thinks it's done, a PCI interrupt will be triggered if a new TX_DONE event arrived from the hardware between us deciding that there is no more work to do and re-enabling the TX_DONE interrupt source, thereby avoiding the classic NAPI poll mode exit race that would otherwise occur. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 77 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6598efcda5cc..3f55aa0c8db3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -202,8 +202,8 @@ struct mwl8k_priv { */ struct work_struct finalize_join_worker; - /* Tasklet to reclaim TX descriptors and buffers after tx */ - struct tasklet_struct tx_reclaim_task; + /* Tasklet to perform TX reclaim. */ + struct tasklet_struct poll_tx_task; }; /* Per interface specific private data */ @@ -2963,13 +2963,16 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) u32 status; status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (!status) return IRQ_NONE; - if (status & MWL8K_A2H_INT_TX_DONE) - tasklet_schedule(&priv->tx_reclaim_task); + if (status & MWL8K_A2H_INT_TX_DONE) { + status &= ~MWL8K_A2H_INT_TX_DONE; + tasklet_schedule(&priv->poll_tx_task); + } + + if (status) + iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); if (status & MWL8K_A2H_INT_RX_READY) { while (rxq_process(hw, 0, 1)) @@ -2990,6 +2993,35 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void mwl8k_tx_poll(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct mwl8k_priv *priv = hw->priv; + int limit; + int i; + + limit = 32; + + spin_lock_bh(&priv->tx_lock); + + for (i = 0; i < MWL8K_TX_QUEUES; i++) + limit -= mwl8k_txq_reclaim(hw, i, limit, 0); + + if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { + complete(priv->tx_wait); + priv->tx_wait = NULL; + } + + spin_unlock_bh(&priv->tx_lock); + + if (limit) { + writel(~MWL8K_A2H_INT_TX_DONE, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + } else { + tasklet_schedule(&priv->poll_tx_task); + } +} + /* * Core driver operations. @@ -3026,7 +3058,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) } /* Enable tx reclaim tasklet */ - tasklet_enable(&priv->tx_reclaim_task); + tasklet_enable(&priv->poll_tx_task); /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); @@ -3059,7 +3091,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (rc) { iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); - tasklet_disable(&priv->tx_reclaim_task); + tasklet_disable(&priv->poll_tx_task); } return rc; @@ -3084,7 +3116,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) dev_kfree_skb(priv->beacon_skb); /* Stop tx reclaim tasklet */ - tasklet_disable(&priv->tx_reclaim_task); + tasklet_disable(&priv->poll_tx_task); /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) @@ -3643,23 +3675,6 @@ static const struct ieee80211_ops mwl8k_ops = { .ampdu_action = mwl8k_ampdu_action, }; -static void mwl8k_tx_reclaim_handler(unsigned long data) -{ - int i; - struct ieee80211_hw *hw = (struct ieee80211_hw *) data; - struct mwl8k_priv *priv = hw->priv; - - spin_lock_bh(&priv->tx_lock); - for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, INT_MAX, 0); - - if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { - complete(priv->tx_wait); - priv->tx_wait = NULL; - } - spin_unlock_bh(&priv->tx_lock); -} - static void mwl8k_finalize_join_worker(struct work_struct *work) { struct mwl8k_priv *priv = @@ -3859,9 +3874,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); /* TX reclaim tasklet */ - tasklet_init(&priv->tx_reclaim_task, - mwl8k_tx_reclaim_handler, (unsigned long)hw); - tasklet_disable(&priv->tx_reclaim_task); + tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); + tasklet_disable(&priv->poll_tx_task); /* Power management cookie */ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); @@ -3890,7 +3904,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); + iowrite32(MWL8K_A2H_INT_TX_DONE, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = request_irq(priv->pdev->irq, mwl8k_interrupt, @@ -4018,7 +4033,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) ieee80211_unregister_hw(hw); /* Remove tx reclaim tasklet */ - tasklet_kill(&priv->tx_reclaim_task); + tasklet_kill(&priv->poll_tx_task); /* Stop hardware */ mwl8k_hw_reset(priv); -- GitLab From 67e2eb27958cae758ccbc86443c360ec285acc3e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 8 Jan 2010 18:32:18 +0100 Subject: [PATCH 0572/3892] mwl8k: move receive processing to tasklet Like how TX reclaim is done in a tasklet, move receive processing to tasklet context as well. This can have nice benefits for CPU utilisation and throughput, especially at 3-stream rates. (Use the same CLEAR_SEL trick as the TX reclaim tasklet does, to avoid having to touch the interrupt mask registers.) Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 47 ++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3f55aa0c8db3..13b0e32b051a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -204,6 +204,9 @@ struct mwl8k_priv { /* Tasklet to perform TX reclaim. */ struct tasklet_struct poll_tx_task; + + /* Tasklet to perform RX. */ + struct tasklet_struct poll_rx_task; }; /* Per interface specific private data */ @@ -2971,14 +2974,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) tasklet_schedule(&priv->poll_tx_task); } - if (status) - iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (status & MWL8K_A2H_INT_RX_READY) { - while (rxq_process(hw, 0, 1)) - rxq_refill(hw, 0, 1); + status &= ~MWL8K_A2H_INT_RX_READY; + tasklet_schedule(&priv->poll_rx_task); } + if (status) + iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + if (status & MWL8K_A2H_INT_OPC_DONE) { if (priv->hostcmd_wait != NULL) complete(priv->hostcmd_wait); @@ -3022,6 +3025,24 @@ static void mwl8k_tx_poll(unsigned long data) } } +static void mwl8k_rx_poll(unsigned long data) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + struct mwl8k_priv *priv = hw->priv; + int limit; + + limit = 32; + limit -= rxq_process(hw, 0, limit); + limit -= rxq_refill(hw, 0, limit); + + if (limit) { + writel(~MWL8K_A2H_INT_RX_READY, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + } else { + tasklet_schedule(&priv->poll_rx_task); + } +} + /* * Core driver operations. @@ -3057,8 +3078,9 @@ static int mwl8k_start(struct ieee80211_hw *hw) return -EIO; } - /* Enable tx reclaim tasklet */ + /* Enable TX reclaim and RX tasklets. */ tasklet_enable(&priv->poll_tx_task); + tasklet_enable(&priv->poll_rx_task); /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); @@ -3092,6 +3114,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); tasklet_disable(&priv->poll_tx_task); + tasklet_disable(&priv->poll_rx_task); } return rc; @@ -3115,8 +3138,9 @@ static void mwl8k_stop(struct ieee80211_hw *hw) if (priv->beacon_skb != NULL) dev_kfree_skb(priv->beacon_skb); - /* Stop tx reclaim tasklet */ + /* Stop TX reclaim and RX tasklets. */ tasklet_disable(&priv->poll_tx_task); + tasklet_disable(&priv->poll_rx_task); /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) @@ -3873,9 +3897,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); - /* TX reclaim tasklet */ + /* TX reclaim and RX tasklets. */ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); tasklet_disable(&priv->poll_tx_task); + tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); + tasklet_disable(&priv->poll_rx_task); /* Power management cookie */ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); @@ -3904,7 +3930,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(MWL8K_A2H_INT_TX_DONE, + iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -4032,8 +4058,9 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) ieee80211_unregister_hw(hw); - /* Remove tx reclaim tasklet */ + /* Remove TX reclaim and RX tasklets. */ tasklet_kill(&priv->poll_tx_task); + tasklet_kill(&priv->poll_rx_task); /* Stop hardware */ mwl8k_hw_reset(priv); -- GitLab From 90be561b119a9e5439733f09cc70bd4ce9ec8022 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 Jan 2010 19:01:07 +0100 Subject: [PATCH 0573/3892] mac80211: fix return from ieee80211_assoc_success sparse pointed out that I made a mistake converting the return value of ieee80211_assoc_success to bool, this place should return false instead of one of the enum values (which would be true). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0336dbb45ac5..8045fd63616b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1098,7 +1098,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, if (err) { printk(KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n", sdata->name, err); - return RX_MGMT_CFG80211_ASSOC_ERROR; + return false; } if (elems.wmm_param) -- GitLab From f05279711b9a59ac10e0b6e5f3a7447886c72704 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Jan 2010 10:04:41 -0800 Subject: [PATCH 0574/3892] iwlwifi: add IEEE80211_AMPDU_TX_OPERATIONAL mac80211 do not check the return code now, what if mac80211 does start using the return code? IEEE80211_AMPDU_TX_OPERATIONAL is a valid action, just iwlwifi driver do not need to take any action for it; so instead of return "-EINVAL", it is a good program practice to return "-EOPNOTSUPP" to make sure mac80211 will not get wrong impression. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 771b03c1c7c5..c78063312ea9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2955,6 +2955,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return 0; else return ret; + case IEEE80211_AMPDU_TX_OPERATIONAL: + /* do nothing */ + return -EOPNOTSUPP; default: IWL_DEBUG_HT(priv, "unknown\n"); return -EINVAL; -- GitLab From f0118a4575d45ce3074c830660de938bc6e17bda Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Jan 2010 10:04:42 -0800 Subject: [PATCH 0575/3892] iwlwifi: ucode statistics data structure update Update data structure to match latest statistics report from uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 28f3800c560e..6bfc63f54b5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2984,7 +2984,7 @@ struct statistics_rx_ht_phy { __le32 agg_crc32_good; __le32 agg_mpdu_cnt; __le32 agg_cnt; - __le32 reserved2; + __le32 unsupport_mcs; } __attribute__ ((packed)); #define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1) @@ -3087,8 +3087,8 @@ struct statistics_div { } __attribute__ ((packed)); struct statistics_general { - __le32 temperature; - __le32 temperature_m; + __le32 temperature; /* radio temperature */ + __le32 temperature_m; /* for 5000 and up, this is radio voltage */ struct statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ee5aed12a4b1..510bad918f20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1387,6 +1387,9 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, accum_ht->agg_mpdu_cnt); pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->unsupport_mcs), + accum_ht->unsupport_mcs); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); -- GitLab From c15867f15f98e5ecbdbee5993db7f6f4b7100481 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Jan 2010 10:04:43 -0800 Subject: [PATCH 0576/3892] iwlwifi: remove obsoleted host command "RADAR_NOTIFICATION" host command is not used and not supported by uCode, remove it from driver code. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 - drivers/net/wireless/iwlwifi/iwl-hcmd.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6bfc63f54b5e..3320cce3d57b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -120,7 +120,6 @@ enum { CALIBRATION_COMPLETE_NOTIFICATION = 0x67, /* 802.11h related */ - RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ REPLY_CHANNEL_SWITCH = 0x72, CHANNEL_SWITCH_NOTIFICATION = 0x73, diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 30e9ea6d54ec..87d684efe110 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -58,7 +58,6 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(COEX_PRIORITY_TABLE_CMD); IWL_CMD(COEX_MEDIUM_NOTIFICATION); IWL_CMD(COEX_EVENT_CMD); - IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); -- GitLab From 8ce1ef4a914aef8b9b90a2a2c670494168a2cca9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Jan 2010 10:04:44 -0800 Subject: [PATCH 0577/3892] iwlwifi: fix bug in tx byte count table When setting invalid byte count in txq byte count table, read pointer should be used instead of write pointer. Reported-by: Guo, Chaohong Signed-off-by: Wey-Yi Guy Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ec6b27689fa8..c3f8ec0a38b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -781,7 +781,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; - if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) scd_bc_tbl[txq_id]. tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } @@ -800,12 +800,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, if (txq_id != IWL_CMD_QUEUE_NUM) sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; - bc_ent = cpu_to_le16(1 | (sta_id << 12)); + bc_ent = cpu_to_le16(1 | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; - if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) scd_bc_tbl[txq_id]. - tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, -- GitLab From 28f63a4bb744ea81030219aba2337fddb10b380b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 8 Jan 2010 16:14:10 -0700 Subject: [PATCH 0578/3892] iwl-debugfs.c: remove unnecessary casts of void * void pointers do not need to be cast to other pointer types. Signed-off-by: H Hartley Sweeten Acked-by: Zhu Yi Cc: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 46 +++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 510bad918f20..4a2ac9311ba8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -125,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char *buf; int pos = 0; @@ -184,7 +184,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char *buf; int pos = 0; int cnt; @@ -232,7 +232,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, ssize_t ret; int i; int pos = 0; - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; size_t bufsz; /* default is to dump the entire data segment */ @@ -306,7 +306,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; struct iwl_station_entry *station; int max_sta = priv->hw_params.max_stations; char *buf; @@ -376,7 +376,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, loff_t *ppos) { ssize_t ret; - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0, ofs = 0, buf_size = 0; const u8 *ptr; char *buf; @@ -464,7 +464,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; struct ieee80211_channel *channels = NULL; const struct ieee80211_supported_band *supp_band = NULL; int pos = 0, i, bufsz = PAGE_SIZE; @@ -537,7 +537,7 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[512]; int pos = 0; const size_t bufsz = sizeof(buf); @@ -585,7 +585,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -672,7 +672,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0, i; char buf[256]; const size_t bufsz = sizeof(buf); @@ -695,7 +695,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; char buf[256]; const size_t bufsz = sizeof(buf); @@ -721,7 +721,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; char buf[100]; @@ -781,7 +781,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[100]; int pos = 0; const size_t bufsz = sizeof(buf); @@ -838,7 +838,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[10]; int pos, value; const size_t bufsz = sizeof(buf); @@ -856,7 +856,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[200]; int pos = 0, i; const size_t bufsz = sizeof(buf); @@ -994,7 +994,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; struct iwl_tx_queue *txq; struct iwl_queue *q; char *buf; @@ -1040,7 +1040,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; struct iwl_rx_queue *rxq = &priv->rxq; char buf[256]; int pos = 0; @@ -1086,7 +1086,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; int bufsz = sizeof(struct statistics_rx_phy) * 20 + @@ -1400,7 +1400,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; int bufsz = (sizeof(struct statistics_tx) * 24) + 250; @@ -1542,7 +1542,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; int bufsz = sizeof(struct statistics_general) * 4 + 250; @@ -1633,7 +1633,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -1714,7 +1714,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -1772,7 +1772,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[128]; int pos = 0; ssize_t ret; @@ -1823,7 +1823,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_priv *priv = file->private_data; char buf[60]; int pos = 0; const size_t bufsz = sizeof(buf); -- GitLab From 5e124bd5e00fcf54df555b368c2dafe6886f1df2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 8 Jan 2010 22:33:38 -0800 Subject: [PATCH 0579/3892] net/mac80211/mlme.c: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8045fd63616b..86f025bc9456 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1783,7 +1783,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (!wk) return -ENOMEM; - memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; + memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); -- GitLab From 678f415fdc534c0a806fce992e4c62df0eff19d2 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 10 Jan 2010 14:07:53 +0100 Subject: [PATCH 0580/3892] mac80211: flush workqueue before calling driver ->stop() method Since commit "mwl8k: handle station database update for AP's sta entry via ->sta_notify()", mwl8k every now and then gets a command timeout when ifconfig'ing a STA interface down. This turns out to be due to mwl8k_stop() being called while the work queue item that was scheduled by mwl8k_sta_notify() to remove the STA entry for the associated AP is still queued, and the former disables interrupts so that when the latter eventually runs, a command completion interrupt is never seen. Fix this by changing ieee80211_stop_device() so that the workqueue is flushed before drv_stop() is called, instead of doing it the other way around as is done now. (As ->stop() is allowed to sleep, there isn't any reason for drivers to queue work from within it.) Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- net/mac80211/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 72a98e844718..a2ba6e29bd9a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1069,9 +1069,9 @@ void ieee80211_stop_device(struct ieee80211_local *local) ieee80211_led_radio(local, false); cancel_work_sync(&local->reconfig_filter); - drv_stop(local); flush_workqueue(local->workqueue); + drv_stop(local); } int ieee80211_reconfig(struct ieee80211_local *local) -- GitLab From 2d46d7c121436f1dafe91b0a8d9b99e534cfa5f8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 10 Jan 2010 17:12:41 +0100 Subject: [PATCH 0581/3892] mac80211: remove unused type argument The type argument to DEBUGFS_ADD() isn't used and can be removed, it's around from before the conversion to debugfs_remove_recursive(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 1481049f0f71..9affe2cd185f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -255,7 +255,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, #endif -#define DEBUGFS_ADD(name, type) \ +#define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ sdata, &name##_ops); @@ -265,40 +265,40 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, static void add_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(rc_rateidx_mask_2ghz, sta); - DEBUGFS_ADD(rc_rateidx_mask_5ghz, sta); + DEBUGFS_ADD(drop_unencrypted); + DEBUGFS_ADD(rc_rateidx_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mask_5ghz); - DEBUGFS_ADD(bssid, sta); - DEBUGFS_ADD(aid, sta); + DEBUGFS_ADD(bssid); + DEBUGFS_ADD(aid); DEBUGFS_ADD_MODE(smps, 0600); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted, ap); - DEBUGFS_ADD(rc_rateidx_mask_2ghz, ap); - DEBUGFS_ADD(rc_rateidx_mask_5ghz, ap); + DEBUGFS_ADD(drop_unencrypted); + DEBUGFS_ADD(rc_rateidx_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mask_5ghz); - DEBUGFS_ADD(num_sta_ps, ap); - DEBUGFS_ADD(dtim_count, ap); - DEBUGFS_ADD(num_buffered_multicast, ap); + DEBUGFS_ADD(num_sta_ps); + DEBUGFS_ADD(dtim_count); + DEBUGFS_ADD(num_buffered_multicast); } static void add_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(rc_rateidx_mask_2ghz, wds); - DEBUGFS_ADD(rc_rateidx_mask_5ghz, wds); + DEBUGFS_ADD(drop_unencrypted); + DEBUGFS_ADD(rc_rateidx_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mask_5ghz); - DEBUGFS_ADD(peer, wds); + DEBUGFS_ADD(peer); } static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(rc_rateidx_mask_2ghz, vlan); - DEBUGFS_ADD(rc_rateidx_mask_5ghz, vlan); + DEBUGFS_ADD(drop_unencrypted); + DEBUGFS_ADD(rc_rateidx_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mask_5ghz); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) -- GitLab From ab13315af97919fae0e014748105fdc2e30afb2d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:42:31 +0200 Subject: [PATCH 0582/3892] mac80211: add U-APSD client support Add Unscheduled Automatic Power-Save Delivery (U-APSD) client support. The idea is that the data frames from the client trigger AP to send the buffered frames with ACs which have U-APSD enabled. This decreases latency and makes it possible to save even more power. Driver needs to use IEEE80211_HW_UAPSD to enable the feature. The current implementation assumes that firmware takes care of the wakeup and hardware needing IEEE80211_HW_PS_NULLFUNC_STACK is not yet supported. Tested with wl1251 on a Nokia N900 and Cisco Aironet 1231G AP and running various test traffic with ping. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 18 ++++++++++++++++++ include/net/mac80211.h | 7 +++++++ net/mac80211/cfg.c | 7 +++++++ net/mac80211/ieee80211_i.h | 13 ++++++++++++- net/mac80211/main.c | 4 ++++ net/mac80211/mlme.c | 31 ++++++++++++++++++++++++++++--- net/mac80211/scan.c | 18 ++++++++++++++++++ net/mac80211/util.c | 2 ++ net/mac80211/work.c | 12 ++++++++++-- 9 files changed, 106 insertions(+), 6 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 602c0692c3fc..a8c6069a0d9f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -120,6 +120,24 @@ #define IEEE80211_QOS_CTL_TID_MASK 0x000F #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 +/* U-APSD queue for WMM IEs sent by AP */ +#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) + +/* U-APSD queues for WMM IEs sent by STA */ +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO (1<<0) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI (1<<1) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK (1<<2) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE (1<<3) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f + +/* U-APSD max SP length for WMM IEs sent by STA */ +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x01 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 + struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e1e73c6abeff..f313a3cbabda 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -113,6 +113,7 @@ struct ieee80211_tx_queue_params { u16 cw_min; u16 cw_max; u8 aifs; + bool uapsd; }; /** @@ -929,6 +930,11 @@ enum ieee80211_tkip_key_type { * Hardware supports dynamic spatial multiplexing powersave, * ie. can turn off all but one chain and then wake the rest * up as required after, for example, rts/cts handshake. + * + * @IEEE80211_HW_SUPPORTS_UAPSD: + * Hardware supports Unscheduled Automatic Power Save Delivery + * (U-APSD) in managed mode. The mode is configured with + * conf_tx() operation. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -948,6 +954,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_BEACON_FILTER = 1<<14, IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, + IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dc12e9466ffd..8286df5822d5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1128,6 +1128,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.cw_max = params->cwmax; p.cw_min = params->cwmin; p.txop = params->txop; + + /* + * Setting tx queue params disables u-apsd because it's only + * called in master mode. + */ + p.uapsd = false; + if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " "parameters for queue %d\n", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3e4ac3f30857..3468e378509a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -58,6 +58,15 @@ struct ieee80211_local; #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) +#define IEEE80211_DEFAULT_UAPSD_QUEUES \ + (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + +#define IEEE80211_DEFAULT_MAX_SP_LEN \ + IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL + struct ieee80211_fragment_entry { unsigned long first_frag_time; unsigned int seq; @@ -78,6 +87,7 @@ struct ieee80211_bss { u8 dtim_period; bool wmm_used; + bool uapsd_supported; unsigned long last_probe_resp; @@ -285,7 +295,7 @@ struct ieee80211_work { u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; u8 supp_rates_len; - bool wmm_used, use_11n; + bool wmm_used, use_11n, uapsd_used; } assoc; struct { u32 duration; @@ -306,6 +316,7 @@ enum ieee80211_sta_flags { IEEE80211_STA_DISABLE_11N = BIT(4), IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), + IEEE80211_STA_UAPSD_ENABLED = BIT(7), }; struct ieee80211_if_managed { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 468829143991..0054bba08ce1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -491,6 +491,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) + && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), + "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); + /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86f025bc9456..39c27d83a4f2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -569,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_tx_queue_params params; size_t left; int count; - u8 *pos; + u8 *pos, uapsd_queues = 0; if (local->hw.queues < 4) return; @@ -579,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) return; + + if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) + uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) return; @@ -593,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, for (; left >= 4; left -= 4, pos += 4) { int aci = (pos[0] >> 5) & 0x03; int acm = (pos[0] >> 4) & 0x01; + bool uapsd = false; int queue; switch (aci) { @@ -600,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, queue = 3; if (acm) local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) + uapsd = true; break; case 2: /* AC_VI */ queue = 1; if (acm) local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) + uapsd = true; break; case 3: /* AC_VO */ queue = 0; if (acm) local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + uapsd = true; break; case 0: /* AC_BE */ default: queue = 2; if (acm) local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) + uapsd = true; break; } @@ -623,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); params.cw_min = ecw2cw(pos[1] & 0x0f); params.txop = get_unaligned_le16(pos + 2); + params.uapsd = uapsd; + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d txop=%d\n", + "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", wiphy_name(local->hw.wiphy), queue, aci, acm, - params.aifs, params.cw_min, params.cw_max, params.txop); + params.aifs, params.cw_min, params.cw_max, params.txop, + params.uapsd); #endif if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " @@ -1906,6 +1922,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, wk->assoc.ht_information_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); + if (bss->wmm_used && bss->uapsd_supported && + (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { + wk->assoc.uapsd_used = true; + ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; + } else { + wk->assoc.uapsd_used = false; + ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; + } + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); wk->assoc.ssid_len = ssid[1]; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 30cb62bb45b3..9afe2f9885dc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -54,6 +54,23 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); } +static bool is_uapsd_supported(struct ieee802_11_elems *elems) +{ + u8 qos_info; + + if (elems->wmm_info && elems->wmm_info_len == 7 + && elems->wmm_info[5] == 1) + qos_info = elems->wmm_info[6]; + else if (elems->wmm_param && elems->wmm_param_len == 24 + && elems->wmm_param[5] == 1) + qos_info = elems->wmm_param[6]; + else + /* no valid wmm information or parameter element found */ + return false; + + return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; +} + struct ieee80211_bss * ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_rx_status *rx_status, @@ -117,6 +134,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, } bss->wmm_used = elems->wmm_param || elems->wmm_info; + bss->uapsd_supported = is_uapsd_supported(elems); if (!beacon) bss->last_probe_resp = jiffies; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a2ba6e29bd9a..e278f97c8305 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -792,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) break; } + qparam.uapsd = false; + drv_conf_tx(local, queue, &qparam); } } diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 7c5d95b1bc04..a74fd6ee0083 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -202,7 +202,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos; + u8 *pos, qos_info; const u8 *ies; size_t offset = 0, noffset; int i, len, count, rates_len, supp_rates_len; @@ -375,6 +375,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } if (wk->assoc.wmm_used && local->hw.queues >= 4) { + if (wk->assoc.uapsd_used) { + qos_info = IEEE80211_DEFAULT_UAPSD_QUEUES; + qos_info |= (IEEE80211_DEFAULT_MAX_SP_LEN << + IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); + } else { + qos_info = 0; + } + pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 7; /* len */ @@ -384,7 +392,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, *pos++ = 2; /* WME */ *pos++ = 0; /* WME info */ *pos++ = 1; /* WME ver */ - *pos++ = 0; + *pos++ = qos_info; } /* add any remaining custom (i.e. vendor specific here) IEs */ -- GitLab From 50ae0cf15c3da2f6a8e4558de5010923e84736b2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:42:39 +0200 Subject: [PATCH 0583/3892] mac80211: add debugfs interface for U-APSD queue configuration Because it's not yet decided how to configure which queues are U-APSD enabled, add a debugfs interface for testing purposes. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/debugfs.c | 94 ++++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 14 ++++++ net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 +- net/mac80211/work.c | 4 +- 5 files changed, 113 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e4b54093d41b..b3bc32b62a5a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -158,6 +158,98 @@ static const struct file_operations noack_ops = { .open = mac80211_open_file_generic }; +static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t uapsd_queues_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + unsigned long val; + char buf[10]; + size_t len; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &val); + + if (ret) + return -EINVAL; + + if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) + return -ERANGE; + + local->uapsd_queues = val; + + return count; +} + +static const struct file_operations uapsd_queues_ops = { + .read = uapsd_queues_read, + .write = uapsd_queues_write, + .open = mac80211_open_file_generic +}; + +static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t uapsd_max_sp_len_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + unsigned long val; + char buf[10]; + size_t len; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &val); + + if (ret) + return -EINVAL; + + if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) + return -ERANGE; + + local->uapsd_max_sp_len = val; + + return count; +} + +static const struct file_operations uapsd_max_sp_len_ops = { + .read = uapsd_max_sp_len_read, + .write = uapsd_max_sp_len_write, + .open = mac80211_open_file_generic +}; + static ssize_t queues_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -314,6 +406,8 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); DEBUGFS_ADD(noack); + DEBUGFS_ADD(uapsd_queues); + DEBUGFS_ADD(uapsd_max_sp_len); statsd = debugfs_create_dir("statistics", phyd); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3468e378509a..c18f576f1848 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -808,6 +808,20 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ + /* + * Bitmask of enabled u-apsd queues, + * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association + * to take effect. + */ + unsigned int uapsd_queues; + + /* + * Maximum number of buffered frames AP can deliver during a + * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. + * Needs a new association to take effect. + */ + unsigned int uapsd_max_sp_len; + bool pspolling; bool offchannel_ps_enabled; /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0054bba08ce1..ec8f767ba95b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -384,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->user_power_level = -1; + local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; INIT_LIST_HEAD(&local->interfaces); mutex_init(&local->iflist_mtx); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39c27d83a4f2..2746391248d3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -581,7 +581,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, return; if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) - uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + uapsd_queues = local->uapsd_queues; count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index a74fd6ee0083..81bd5d592bb4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -376,8 +376,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (wk->assoc.wmm_used && local->hw.queues >= 4) { if (wk->assoc.uapsd_used) { - qos_info = IEEE80211_DEFAULT_UAPSD_QUEUES; - qos_info |= (IEEE80211_DEFAULT_MAX_SP_LEN << + qos_info = local->uapsd_queues; + qos_info |= (local->uapsd_max_sp_len << IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); } else { qos_info = 0; -- GitLab From 5c1b98a52c3af1044c2d3842af8bae9a89502ca9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:42:46 +0200 Subject: [PATCH 0584/3892] mac80211: create tx handler for dynamic ps Currently dynamic ps check is in ieee80211_xmit(), but it's cleaner to have a separate tx handler for this. Also this is a prerequisite for U-APSD client mode which needs to know the queue frame is in. Also need_dynamic_ps() function is embedded to the tx handler. No functional changes expect that the code is run in a later phase than originally. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/tx.c | 81 ++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 47ca59e52e71..6fcc85a2806a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -180,6 +180,46 @@ static int inline is_ieee80211_device(struct ieee80211_local *local, } /* tx handlers */ +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) +{ + struct ieee80211_local *local = tx->local; + + /* driver doesn't support power save */ + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return TX_CONTINUE; + + /* hardware does dynamic power save */ + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + return TX_CONTINUE; + + /* dynamic power save disabled */ + if (local->hw.conf.dynamic_ps_timeout <= 0) + return TX_CONTINUE; + + /* we are scanning, don't enable power save */ + if (local->scanning) + return TX_CONTINUE; + + if (!local->ps_sdata) + return TX_CONTINUE; + + /* No point if we're going to suspend */ + if (local->quiescing) + return TX_CONTINUE; + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + ieee80211_stop_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); + ieee80211_queue_work(&local->hw, + &local->dynamic_ps_disable_work); + } + + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + + return TX_CONTINUE; +} static ieee80211_tx_result debug_noinline ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) @@ -1223,6 +1263,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) goto txh_done; \ } while (0) + CALL_TXH(ieee80211_tx_h_dynamic_ps); CALL_TXH(ieee80211_tx_h_check_assoc); CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_select_key); @@ -1405,34 +1446,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } -static bool need_dynamic_ps(struct ieee80211_local *local) -{ - /* driver doesn't support power save */ - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) - return false; - - /* hardware does dynamic power save */ - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - return false; - - /* dynamic power save disabled */ - if (local->hw.conf.dynamic_ps_timeout <= 0) - return false; - - /* we are scanning, don't enable power save */ - if (local->scanning) - return false; - - if (!local->ps_sdata) - return false; - - /* No point if we're going to suspend */ - if (local->quiescing) - return false; - - return true; -} - static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -1443,18 +1456,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, int headroom; bool may_encrypt; - if (need_dynamic_ps(local)) { - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_QUEUE_STOP_REASON_PS); - ieee80211_queue_work(&local->hw, - &local->dynamic_ps_disable_work); - } - - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - } - rcu_read_lock(); if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { -- GitLab From 0c74211d19d83729c209ddcd4dc026c2aedeb29e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:42:53 +0200 Subject: [PATCH 0585/3892] mac80211: check uapsd state for dynamic power save To make U-APSD client mode effective, we must not wake up from dynamic power save when transmitting frames. So if dynamic power save is enabled, it needs check the queue the transmitted packet is in and decide if we need to wake up or not. In a perfect world, where all packets would have correct QoS tags, U-APSD enabled queues should not trigger wakeup from power save. But in the real world, where very few packets have correct QoS tags, this won't work. For example, if only voip class has U-APSD enabled and we send a packet in voip class, but the packets we receive are in best effort class, we would receive the packets with the legacy power save method. And that would increase latencies too much from a voip application point of view. The workaround is to enable U-APSD for all qeueus and still use dynamic ps wakeup for all other queues except voip. That way we can still save power with a voip application and not sacrifice latency. Normal traffic (in background, best effort or video class) would still trigger wakeup from dynamic power save. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/tx.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6fcc85a2806a..daf81048c1f7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -184,6 +184,7 @@ static ieee80211_tx_result debug_noinline ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) { struct ieee80211_local *local = tx->local; + struct ieee80211_if_managed *ifmgd; /* driver doesn't support power save */ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) @@ -208,6 +209,30 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) if (local->quiescing) return TX_CONTINUE; + /* dynamic ps is supported only in managed mode */ + if (tx->sdata->vif.type != NL80211_IFTYPE_STATION) + return TX_CONTINUE; + + ifmgd = &tx->sdata->u.mgd; + + /* + * Don't wakeup from power save if u-apsd is enabled, voip ac has + * u-apsd enabled and the frame is in voip class. This effectively + * means that even if all access categories have u-apsd enabled, in + * practise u-apsd is only used with the voip ac. This is a + * workaround for the case when received voip class packets do not + * have correct qos tag for some reason, due the network or the + * peer application. + * + * Note: local->uapsd_queues access is racy here. If the value is + * changed via debugfs, user needs to reassociate manually to have + * everything in sync. + */ + if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) + && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + && skb_get_queue_mapping(tx->skb) == 0) + return TX_CONTINUE; + if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- GitLab From 558a6669d7cb407fbb0b5aec184b5c3b9a893d30 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:43:00 +0200 Subject: [PATCH 0586/3892] ieee80211: add struct ieee80211_hdr_qos The header can be used to create qos nullfunc frames, for example. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a8c6069a0d9f..842701906ae9 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -157,6 +157,16 @@ struct ieee80211_hdr_3addr { __le16 seq_ctrl; } __attribute__ ((packed)); +struct ieee80211_qos_hdr { + __le16 frame_control; + __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; + __le16 qos_ctrl; +} __attribute__ ((packed)); + /** * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set * @fc: frame control bytes in little-endian byteorder -- GitLab From 8f8ff91652fcf62b9fced5387956b4b269fde634 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:43:07 +0200 Subject: [PATCH 0587/3892] wl1251: create qos null data template The qos null data template is needed for U-APSD. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index f17ce06b6c24..d469d3dcd054 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -563,6 +563,27 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } +static int wl1251_build_qos_null_data(struct wl1251 *wl) +{ + struct ieee80211_qos_hdr template; + + memset(&template, 0, sizeof(template)); + + memcpy(template.addr1, wl->bssid, ETH_ALEN); + memcpy(template.addr2, wl->mac_addr, ETH_ALEN); + memcpy(template.addr3, wl->bssid, ETH_ALEN); + + template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_QOS_NULLFUNC | + IEEE80211_FCTL_TODS); + + /* FIXME: not sure what priority to use here */ + template.qos_ctrl = cpu_to_le16(0); + + return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, + sizeof(template)); +} + static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1251 *wl = hw->priv; @@ -948,6 +969,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; + ret = wl1251_build_qos_null_data(wl); + if (ret < 0) + goto out; + if (wl->bss_type != BSS_TYPE_IBSS) { ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); -- GitLab From 4ff6ffa107ba1c6ba9a1cc75a1f304eaa79e8bf4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 12 Jan 2010 10:43:15 +0200 Subject: [PATCH 0588/3892] wl1251: add U-APSD support wl1251 firmware supports U-APSD just with a simple queue configuration change so enable it. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index d469d3dcd054..595f0f94d16e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1143,6 +1143,7 @@ static struct ieee80211_channel wl1251_channels[] = { static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { + enum wl1251_acx_ps_scheme ps_scheme; struct wl1251 *wl = hw->priv; int ret; @@ -1160,10 +1161,14 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, if (ret < 0) goto out_sleep; + if (params->uapsd) + ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; + else + ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; + ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), CHANNEL_TYPE_EDCF, - wl1251_tx_get_queue(queue), - WL1251_ACX_PS_SCHEME_LEGACY, + wl1251_tx_get_queue(queue), ps_scheme, WL1251_ACX_ACK_POLICY_LEGACY); if (ret < 0) goto out_sleep; @@ -1237,7 +1242,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_BEACON_FILTER; + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_SUPPORTS_UAPSD; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; -- GitLab From c92d4edecf489dbcbb2e5dd3c513790e57e2ea0e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:47:22 +0100 Subject: [PATCH 0589/3892] mwl8k: update MODULE_FIRMWARE tags Add MODULE_FIRMWARE tags for the mwl8k firmware images that don't have them yet, and move them to where the firmware image names are declared. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 13b0e32b051a..01cababfefa8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -394,9 +394,6 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) return 0; } -MODULE_FIRMWARE("mwl8k/helper_8687.fw"); -MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); - struct mwl8k_cmd_pkt { __le16 code; __le16 length; @@ -3737,6 +3734,13 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { }, }; +MODULE_FIRMWARE("mwl8k/helper_8363.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); +MODULE_FIRMWARE("mwl8k/helper_8687.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); +MODULE_FIRMWARE("mwl8k/helper_8366.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); + static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, -- GitLab From 9189c10087a738c764046fa27651d332594cd8e6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:47:32 +0100 Subject: [PATCH 0590/3892] mwl8k: remove (mostly) write-only variable priv->current_channel Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 01cababfefa8..f2c4524888a8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -156,8 +156,6 @@ struct mwl8k_priv { struct ieee80211_vif *vif; - struct ieee80211_channel *current_channel; - /* power management status cookie from firmware */ u32 *cookie; dma_addr_t cookie_dma; @@ -3050,7 +3048,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) int index = skb_get_queue_mapping(skb); int rc; - if (priv->current_channel == NULL) { + if (!priv->radio_on) { printk(KERN_DEBUG "%s: dropped TX frame since radio " "disabled\n", wiphy_name(hw->wiphy)); dev_kfree_skb(skb); @@ -3182,7 +3180,6 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif->seqno = 0; priv->vif = vif; - priv->current_channel = NULL; return 0; } @@ -3208,7 +3205,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (conf->flags & IEEE80211_CONF_IDLE) { mwl8k_cmd_radio_disable(hw); - priv->current_channel = NULL; return 0; } @@ -3224,8 +3220,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) goto out; - priv->current_channel = conf->channel; - if (conf->power_level > 18) conf->power_level = 18; rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); -- GitLab From c97470dd253831e880c72ea5d022ed7f3aee45c3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:47:37 +0100 Subject: [PATCH 0591/3892] mwl8k: don't call SET_AID if we're not associated Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f2c4524888a8..67ee3da33264 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3261,9 +3261,9 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* * Get the AP's legacy and MCS rates. */ - ap_legacy_rates = 0; if (vif->bss_conf.assoc) { struct ieee80211_sta *ap; + rcu_read_lock(); ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); @@ -3301,8 +3301,9 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if (((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) || - (changed & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))) { + if (vif->bss_conf.assoc && + (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_HT))) { rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); if (rc) goto out; -- GitLab From 657232b625890f202867ede0ed67ecf15827ff80 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:47:47 +0100 Subject: [PATCH 0592/3892] mwl8k: simplify sequence number assignment By storing the sequence counter in << 4 format, like other drivers do. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 67ee3da33264..7d165befb0d7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1355,11 +1355,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) mwl8k_vif = MWL8K_VIF(tx_info->control.vif); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - u16 seqno = mwl8k_vif->seqno; - wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - wh->seq_ctrl |= cpu_to_le16(seqno << 4); - mwl8k_vif->seqno = seqno++ % 4096; + wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); + mwl8k_vif->seqno += 0x10; } /* Setup firmware control bit fields for each frame type. */ -- GitLab From ca66527c60385dcec878ebd90749d1fdc43bc870 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:47:53 +0100 Subject: [PATCH 0593/3892] mwl8k: add another 88w8366 PCI ID 0x2a43 is a single-band (2.4GHz only) 88w8366 mini-PCIe card. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7d165befb0d7..76da583df321 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3740,6 +3740,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, + { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, { }, }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); -- GitLab From 777ad375d5960e0d2a945a34032b182eb2952d45 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:48:04 +0100 Subject: [PATCH 0594/3892] mwl8k: rename 2.4 GHz band/channels/rates related variables from FOO to FOO_24 To prepare for adding 5 GHz band/channels/rates. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 76 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 76da583df321..37cbfbf21567 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -141,6 +141,9 @@ struct mwl8k_priv { /* hardware/firmware parameters */ bool ap_fw; struct rxd_ops *rxd_ops; + struct ieee80211_supported_band band_24; + struct ieee80211_channel channels_24[14]; + struct ieee80211_rate rates_24[14]; /* firmware access */ struct mutex fw_mutex; @@ -173,11 +176,6 @@ struct mwl8k_priv { struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; - /* PHY parameters */ - struct ieee80211_supported_band band; - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[14]; - bool radio_on; bool radio_short_preamble; bool sniffer_enabled; @@ -220,7 +218,7 @@ struct mwl8k_sta { }; #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) -static const struct ieee80211_channel mwl8k_channels[] = { +static const struct ieee80211_channel mwl8k_channels_24[] = { { .center_freq = 2412, .hw_value = 1, }, { .center_freq = 2417, .hw_value = 2, }, { .center_freq = 2422, .hw_value = 3, }, @@ -237,7 +235,7 @@ static const struct ieee80211_channel mwl8k_channels[] = { { .center_freq = 2484, .hw_value = 14, }, }; -static const struct ieee80211_rate mwl8k_rates[] = { +static const struct ieee80211_rate mwl8k_rates_24[] = { { .bitrate = 10, .hw_value = 2, }, { .bitrate = 20, .hw_value = 4, }, { .bitrate = 55, .hw_value = 11, }, @@ -731,8 +729,8 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, } else { int i; - for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) { - if (mwl8k_rates[i].hw_value == rxd->rate) { + for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { + if (mwl8k_rates_24[i].hw_value == rxd->rate) { status->rate_idx = i; break; } @@ -1597,48 +1595,48 @@ struct mwl8k_cmd_get_hw_spec_sta { static void mwl8k_set_ht_caps(struct ieee80211_hw *hw, u32 cap) { struct mwl8k_priv *priv = hw->priv; + struct ieee80211_supported_band *band = &priv->band_24; int rx_streams; int tx_streams; - priv->band.ht_cap.ht_supported = 1; + band->ht_cap.ht_supported = 1; if (cap & MWL8K_CAP_MAX_AMSDU) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; + band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; if (cap & MWL8K_CAP_GREENFIELD) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; + band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; if (cap & MWL8K_CAP_AMPDU) { hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; - priv->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - priv->band.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_NONE; + band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; } if (cap & MWL8K_CAP_RX_STBC) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; + band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; if (cap & MWL8K_CAP_TX_STBC) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; + band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; if (cap & MWL8K_CAP_SHORTGI_40MHZ) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; if (cap & MWL8K_CAP_SHORTGI_20MHZ) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; if (cap & MWL8K_CAP_DELAY_BA) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; + band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; if (cap & MWL8K_CAP_40MHZ) - priv->band.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); - priv->band.ht_cap.mcs.rx_mask[0] = 0xff; + band->ht_cap.mcs.rx_mask[0] = 0xff; if (rx_streams >= 2) - priv->band.ht_cap.mcs.rx_mask[1] = 0xff; + band->ht_cap.mcs.rx_mask[1] = 0xff; if (rx_streams >= 3) - priv->band.ht_cap.mcs.rx_mask[2] = 0xff; - priv->band.ht_cap.mcs.rx_mask[4] = 0x01; - priv->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + band->ht_cap.mcs.rx_mask[2] = 0xff; + band->ht_cap.mcs.rx_mask[4] = 0x01; + band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; if (rx_streams != tx_streams) { - priv->band.ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - priv->band.ht_cap.mcs.tx_params |= (tx_streams - 1) << + band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + band->ht_cap.mcs.tx_params |= (tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; } } @@ -2192,7 +2190,7 @@ static void legacy_rate_mask_to_array(u8 *rates, u32 mask) for (i = 0, j = 0; i < 14; i++) { if (mask & (1 << i)) - rates[j++] = mwl8k_rates[i].hw_value; + rates[j++] = mwl8k_rates_24[i].hw_value; } } @@ -3347,7 +3345,7 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * beacons will always go out at 1 Mb/s). */ idx = ffs(vif->bss_conf.basic_rates); - rate = idx ? mwl8k_rates[idx - 1].hw_value : 2; + rate = idx ? mwl8k_rates_24[idx - 1].hw_value : 2; mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); } @@ -3855,16 +3853,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->pending_tx_pkts = 0; - memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); - priv->band.band = IEEE80211_BAND_2GHZ; - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(mwl8k_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates); - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); + priv->band_24.band = IEEE80211_BAND_2GHZ; + priv->band_24.channels = priv->channels_24; + priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); + priv->band_24.bitrates = priv->rates_24; + priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; - BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates)); - memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates)); + BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); + memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); /* * Extra headroom is the size of the required DMA header -- GitLab From 1349ad2f06f86f41415cf7ffa9e068fd4f89be87 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:48:17 +0100 Subject: [PATCH 0595/3892] mwl8k: move responsibility for initialising wiphy bands to GET_HW_SPEC So that we can make 2.4 GHz and 5 GHz band registration conditional on the capability bitmask returned by the firmware. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 37cbfbf21567..a17111f40266 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1557,6 +1557,28 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) return rc; } +/* + * Setup code shared between STA and AP firmware images. + */ +static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); + memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); + + BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); + memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); + + priv->band_24.band = IEEE80211_BAND_2GHZ; + priv->band_24.channels = priv->channels_24; + priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); + priv->band_24.bitrates = priv->rates_24; + priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; +} + /* * CMD_GET_HW_SPEC (STA version). */ @@ -1671,6 +1693,7 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; + mwl8k_setup_2ghz_band(hw); if (cmd->caps & cpu_to_le32(MWL8K_CAP_MIMO)) mwl8k_set_ht_caps(hw, le32_to_cpu(cmd->caps)); } @@ -1726,6 +1749,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; + mwl8k_setup_2ghz_band(hw); off = le32_to_cpu(cmd->wcbbase0) & 0xffff; iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); @@ -3853,17 +3877,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->pending_tx_pkts = 0; - memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); - priv->band_24.band = IEEE80211_BAND_2GHZ; - priv->band_24.channels = priv->channels_24; - priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); - priv->band_24.bitrates = priv->rates_24; - priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; - - BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); - memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); - /* * Extra headroom is the size of the required DMA header * minus the size of the smallest 802.11 frame (CTS frame). -- GitLab From 4eae9edd38c0a9ce34e39100ccc69ff520bc1224 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:48:32 +0100 Subject: [PATCH 0596/3892] mwl8k: add 5 GHz band channels and rates Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a17111f40266..13dded49323e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -144,6 +144,9 @@ struct mwl8k_priv { struct ieee80211_supported_band band_24; struct ieee80211_channel channels_24[14]; struct ieee80211_rate rates_24[14]; + struct ieee80211_supported_band band_50; + struct ieee80211_channel channels_50[4]; + struct ieee80211_rate rates_50[9]; /* firmware access */ struct mutex fw_mutex; @@ -252,6 +255,25 @@ static const struct ieee80211_rate mwl8k_rates_24[] = { { .bitrate = 720, .hw_value = 144, }, }; +static const struct ieee80211_channel mwl8k_channels_50[] = { + { .center_freq = 5180, .hw_value = 36, }, + { .center_freq = 5200, .hw_value = 40, }, + { .center_freq = 5220, .hw_value = 44, }, + { .center_freq = 5240, .hw_value = 48, }, +}; + +static const struct ieee80211_rate mwl8k_rates_50[] = { + { .bitrate = 60, .hw_value = 12, }, + { .bitrate = 90, .hw_value = 18, }, + { .bitrate = 120, .hw_value = 24, }, + { .bitrate = 180, .hw_value = 36, }, + { .bitrate = 240, .hw_value = 48, }, + { .bitrate = 360, .hw_value = 72, }, + { .bitrate = 480, .hw_value = 96, }, + { .bitrate = 540, .hw_value = 108, }, + { .bitrate = 720, .hw_value = 144, }, +}; + /* Set or get info from Firmware */ #define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 @@ -1579,6 +1601,25 @@ static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; } +static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); + memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); + + BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); + memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); + + priv->band_50.band = IEEE80211_BAND_5GHZ; + priv->band_50.channels = priv->channels_50; + priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); + priv->band_50.bitrates = priv->rates_50; + priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); + + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; +} + /* * CMD_GET_HW_SPEC (STA version). */ -- GitLab From 854783444bab0024556c0aefdb0a860f2f1da286 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:48:56 +0100 Subject: [PATCH 0597/3892] mwl8k: properly set receive status rate index on 5 GHz receive The mwl8k firmware uses indices into the 2.4 GHz band rate table for the receive descriptor channel field even if the packet was received on a 5 GHz channel, while mac80211 expects an index into the 5 GHz band rate table when packets are received on the 5 GHz band, which presents a mismatch as the 5 GHz band rate table lacks the five non-OFDM rates that the 2.4 GHz rate table starts with. To handle this properly, we need to substract 5 from the rate index field if the packet was received on a 5 GHz channel (and was not received at an MCS rate). Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 13dded49323e..cc2ce61b7992 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -759,7 +759,13 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, } } - status->band = IEEE80211_BAND_2GHZ; + if (rxd->channel > 14) { + status->band = IEEE80211_BAND_5GHZ; + if (!(status->flag & RX_FLAG_HT)) + status->rate_idx -= 5; + } else { + status->band = IEEE80211_BAND_2GHZ; + } status->freq = ieee80211_channel_to_frequency(rxd->channel); *qos = rxd->qos_control; @@ -850,7 +856,13 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) status->flag |= RX_FLAG_HT; - status->band = IEEE80211_BAND_2GHZ; + if (rxd->channel > 14) { + status->band = IEEE80211_BAND_5GHZ; + if (!(status->flag & RX_FLAG_HT)) + status->rate_idx -= 5; + } else { + status->band = IEEE80211_BAND_2GHZ; + } status->freq = ieee80211_channel_to_frequency(rxd->channel); *qos = rxd->qos_control; -- GitLab From 8707d0262585423cdc053bf8db0912e53915e5e4 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:49:15 +0100 Subject: [PATCH 0598/3892] mwl8k: handle 5 GHz legacy rate bitmaps in firmware commands Whenever mac80211 gives us a legacy rate bitmap in the context of the 5 GHz band, we need to remember to shift the bitmap left by 5 positions before giving it to the firmware, as the firmware follows the bitmap bit assignment of the 2.4 GHz rate table even if we're on the 5 GHz band, and the 2.4 GHz rate table includes five non-OFDM rates at the start that are not valid in the 5 GHz band. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cc2ce61b7992..e370245b3901 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2836,6 +2836,7 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct mwl8k_cmd_set_new_stn *cmd; + u32 rates; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2848,7 +2849,11 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); cmd->stn_id = cpu_to_le16(sta->aid); cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); - cmd->legacy_rates = cpu_to_le32(sta->supp_rates[IEEE80211_BAND_2GHZ]); + if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) + rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; + else + rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; + cmd->legacy_rates = cpu_to_le32(rates); if (sta->ht_cap.ht_supported) { cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; @@ -2972,6 +2977,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, { struct mwl8k_cmd_update_stadb *cmd; struct peer_capability_info *p; + u32 rates; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2990,8 +2996,11 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, p->ht_caps = sta->ht_cap.cap; p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | ((sta->ht_cap.ampdu_density & 7) << 2); - legacy_rate_mask_to_array(p->legacy_rates, - sta->supp_rates[IEEE80211_BAND_2GHZ]); + if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) + rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; + else + rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; + legacy_rate_mask_to_array(p->legacy_rates, rates); memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); p->interop = 1; p->amsdu_enabled = 0; @@ -3345,7 +3354,12 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; + if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { + ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; + } else { + ap_legacy_rates = + ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; + } memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); rcu_read_unlock(); @@ -3422,7 +3436,13 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * beacons will always go out at 1 Mb/s). */ idx = ffs(vif->bss_conf.basic_rates); - rate = idx ? mwl8k_rates_24[idx - 1].hw_value : 2; + if (idx) + idx--; + + if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) + rate = mwl8k_rates_24[idx].hw_value; + else + rate = mwl8k_rates_50[idx].hw_value; mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); } -- GitLab From 42574ea2274ec0a2a9c58ab01be91b65e60a2291 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:49:18 +0100 Subject: [PATCH 0599/3892] mwl8k: allow selecting 5 GHz channels Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index e370245b3901..6e8c126aa5e0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2222,6 +2222,8 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, if (channel->band == IEEE80211_BAND_2GHZ) cmd->channel_flags |= cpu_to_le32(0x00000001); + else if (channel->band == IEEE80211_BAND_5GHZ) + cmd->channel_flags |= cpu_to_le32(0x00000004); if (conf->channel_type == NL80211_CHAN_NO_HT || conf->channel_type == NL80211_CHAN_HT20) -- GitLab From 06953235f48c696b22c5ed45570680fb070f7277 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:49:41 +0100 Subject: [PATCH 0600/3892] mwl8k: use firmware capability field to decide which bands to register Make the decision about whether to register the 2.4 and 5 GHz bands with mac80211 by looking at the capability field in GET_HW_SPEC (STA firmware only for now). This enables 5 GHz STA operation. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6e8c126aa5e0..382ef4305a3e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1666,11 +1666,14 @@ struct mwl8k_cmd_get_hw_spec_sta { #define MWL8K_CAP_DELAY_BA 0x00003000 #define MWL8K_CAP_MIMO 0x00000200 #define MWL8K_CAP_40MHZ 0x00000100 +#define MWL8K_CAP_BAND_MASK 0x00000007 +#define MWL8K_CAP_5GHZ 0x00000004 +#define MWL8K_CAP_2GHZ4 0x00000001 -static void mwl8k_set_ht_caps(struct ieee80211_hw *hw, u32 cap) +static void +mwl8k_set_ht_caps(struct ieee80211_hw *hw, + struct ieee80211_supported_band *band, u32 cap) { - struct mwl8k_priv *priv = hw->priv; - struct ieee80211_supported_band *band = &priv->band_24; int rx_streams; int tx_streams; @@ -1716,6 +1719,24 @@ static void mwl8k_set_ht_caps(struct ieee80211_hw *hw, u32 cap) } } +static void +mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) +{ + struct mwl8k_priv *priv = hw->priv; + + if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { + mwl8k_setup_2ghz_band(hw); + if (caps & MWL8K_CAP_MIMO) + mwl8k_set_ht_caps(hw, &priv->band_24, caps); + } + + if (caps & MWL8K_CAP_5GHZ) { + mwl8k_setup_5ghz_band(hw); + if (caps & MWL8K_CAP_MIMO) + mwl8k_set_ht_caps(hw, &priv->band_50, caps); + } +} + static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; @@ -1746,9 +1767,7 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); - if (cmd->caps & cpu_to_le32(MWL8K_CAP_MIMO)) - mwl8k_set_ht_caps(hw, le32_to_cpu(cmd->caps)); + mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); } kfree(cmd); -- GitLab From f5bb87cfba5ae9dd3724b846ac2fa7e033425c1c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:49:51 +0100 Subject: [PATCH 0601/3892] mwl8k: convert the priv->vif pointer to a list of vifs To prepare for adding multi-BSS support. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 51 +++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 382ef4305a3e..ee7d8a6329f8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -160,7 +160,8 @@ struct mwl8k_priv { /* TX quiesce completion, protected by fw_mutex and tx_lock */ struct completion *tx_wait; - struct ieee80211_vif *vif; + /* List of interfaces. */ + struct list_head vif_list; /* power management status cookie from firmware */ u32 *cookie; @@ -210,6 +211,9 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { + struct list_head list; + struct ieee80211_vif *vif; + /* Non AMPDU sequence number assigned by driver. */ u16 seqno; }; @@ -3246,7 +3250,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) } static int mwl8k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif; @@ -3254,7 +3258,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* * We only support one active interface at a time. */ - if (priv->vif != NULL) + if (!list_empty(&priv->vif_list)) return -EBUSY; /* @@ -3275,14 +3279,13 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, if (priv->ap_fw) mwl8k_cmd_set_new_stn_add_self(hw, vif); - /* Clean out driver private area */ + /* Setup driver private area. */ mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); - - /* Set Initial sequence number to zero */ + mwl8k_vif->vif = vif; mwl8k_vif->seqno = 0; - priv->vif = vif; + list_add_tail(&mwl8k_vif->list, &priv->vif_list); return 0; } @@ -3291,13 +3294,14 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mwl8k_priv *priv = hw->priv; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); if (priv->ap_fw) mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); - priv->vif = NULL; + list_del(&mwl8k_vif->list); } static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) @@ -3526,7 +3530,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, * operation, so refuse to enable sniffer mode if a STA * interface is active. */ - if (priv->vif != NULL) { + if (!list_empty(&priv->vif_list)) { if (net_ratelimit()) printk(KERN_INFO "%s: not enabling sniffer " "mode because STA interface is active\n", @@ -3547,6 +3551,14 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, return 1; } +static struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) +{ + if (!list_empty(&priv->vif_list)) + return list_entry(priv->vif_list.next, struct mwl8k_vif, list); + + return NULL; +} + static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -3595,6 +3607,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, */ mwl8k_cmd_set_pre_scan(hw); } else { + struct mwl8k_vif *mwl8k_vif; const u8 *bssid; /* @@ -3605,9 +3618,11 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, * (where the OUI part needs to be nonzero for * the BSSID to be accepted by POST_SCAN). */ - bssid = "\x01\x00\x00\x00\x00\x00"; - if (priv->vif != NULL) - bssid = priv->vif->bss_conf.bssid; + mwl8k_vif = mwl8k_first_vif(priv); + if (mwl8k_vif != NULL) + bssid = mwl8k_vif->vif->bss_conf.bssid; + else + bssid = "\x01\x00\x00\x00\x00\x00"; mwl8k_cmd_set_post_scan(hw, bssid); } @@ -3810,11 +3825,14 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; + struct mwl8k_vif *mwl8k_vif; - mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, - priv->vif->bss_conf.dtim_period); - dev_kfree_skb(skb); + mwl8k_vif = mwl8k_first_vif(priv); + if (mwl8k_vif != NULL) + mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, + mwl8k_vif->vif->bss_conf.dtim_period); + dev_kfree_skb(skb); priv->beacon_skb = NULL; } @@ -3986,7 +4004,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); hw->sta_data_size = sizeof(struct mwl8k_sta); - priv->vif = NULL; + + INIT_LIST_HEAD(&priv->vif_list); /* Set default radio state and preamble */ priv->radio_on = 0; -- GitLab From f57ca9c1af3c1e30a40ad99d75940176d8c3ff3a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:50:14 +0100 Subject: [PATCH 0602/3892] mwl8k: prepare for posting per-vif firmware commands One of the bytes in the mwl8k firmware command header is the 'macid' byte, which for per-vif commands indicates which of the BSSes this command is intended for. (For commands that are not per-vif commands, this byte can just be 0.) This patch adds mwl8k_post_pervif_cmd(), which will take the macid assigned to this interface (to be done in ->add_interface()), copy it into the command packet macid field, and post the command as usual. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ee7d8a6329f8..ea39ef64defe 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -214,6 +214,9 @@ struct mwl8k_vif { struct list_head list; struct ieee80211_vif *vif; + /* Firmware macid for this vif. */ + int macid; + /* Non AMPDU sequence number assigned by driver. */ u16 seqno; }; @@ -419,7 +422,8 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) struct mwl8k_cmd_pkt { __le16 code; __le16 length; - __le16 seq_num; + __u8 seq_num; + __u8 macid; __le16 result; char payload[0]; } __attribute__((packed)); @@ -477,6 +481,7 @@ static int mwl8k_load_fw_image(struct mwl8k_priv *priv, cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); cmd->seq_num = 0; + cmd->macid = 0; cmd->result = 0; done = 0; @@ -1595,6 +1600,15 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) return rc; } +static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct mwl8k_cmd_pkt *cmd) +{ + if (vif != NULL) + cmd->macid = MWL8K_VIF(vif)->macid; + return mwl8k_post_cmd(hw, cmd); +} + /* * Setup code shared between STA and AP firmware images. */ @@ -3283,6 +3297,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); mwl8k_vif->vif = vif; + mwl8k_vif->macid = 0; mwl8k_vif->seqno = 0; list_add_tail(&mwl8k_vif->list, &priv->vif_list); -- GitLab From aa21d0f69a5ca28d33f584b8952cca154115fd26 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:50:36 +0100 Subject: [PATCH 0603/3892] mwl8k: post per-vif firmware commands as per-vif commands SET_BEACON, SET_MAC_ADDR, BSS_START and SET_NEW_STN are the currently supported firmware commands that are actually per-vif commands. Use mwl8k_post_pervif_cmd() for these commands, so that the macid of the vif they operate on gets passed down into the firmware. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 49 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ea39ef64defe..d8cf43853de1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -294,7 +294,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_RF_ANTENNA 0x0020 -#define MWL8K_CMD_SET_BEACON 0x0100 +#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 #define MWL8K_CMD_SET_RF_CHANNEL 0x010a @@ -308,10 +308,10 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_MIMO_CONFIG 0x0125 #define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 -#define MWL8K_CMD_SET_MAC_ADDR 0x0202 +#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 -#define MWL8K_CMD_BSS_START 0x1100 -#define MWL8K_CMD_SET_NEW_STN 0x1111 +#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ +#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) @@ -2156,7 +2156,8 @@ struct mwl8k_cmd_set_beacon { __u8 beacon[0]; }; -static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, u8 *beacon, int len) +static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u8 *beacon, int len) { struct mwl8k_cmd_set_beacon *cmd; int rc; @@ -2170,7 +2171,7 @@ static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, u8 *beacon, int len) cmd->beacon_len = cpu_to_le16(len); memcpy(cmd->beacon, beacon, len); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -2761,7 +2762,8 @@ struct mwl8k_cmd_set_mac_addr { #define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 #define MWL8K_MAC_TYPE_PRIMARY_AP 2 -static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) +static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u8 *mac) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_set_mac_addr *cmd; @@ -2780,7 +2782,7 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) memcpy(cmd->mac_addr, mac, ETH_ALEN); } - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -2823,7 +2825,8 @@ struct mwl8k_cmd_bss_start { __le32 enable; } __attribute__((packed)); -static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, int enable) +static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int enable) { struct mwl8k_cmd_bss_start *cmd; int rc; @@ -2836,7 +2839,7 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, int enable) cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->enable = cpu_to_le32(enable); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -2904,7 +2907,7 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, cmd->is_qos_sta = 1; } - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -2924,7 +2927,7 @@ static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -2945,7 +2948,7 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, memcpy(cmd->mac_addr, addr, ETH_ALEN); cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); - rc = mwl8k_post_cmd(hw, &cmd->header); + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; @@ -3287,12 +3290,6 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, return -EINVAL; } - /* Set the mac address. */ - mwl8k_cmd_set_mac_addr(hw, vif->addr); - - if (priv->ap_fw) - mwl8k_cmd_set_new_stn_add_self(hw, vif); - /* Setup driver private area. */ mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); @@ -3300,6 +3297,12 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif->macid = 0; mwl8k_vif->seqno = 0; + /* Set the mac address. */ + mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); + + if (priv->ap_fw) + mwl8k_cmd_set_new_stn_add_self(hw, vif); + list_add_tail(&mwl8k_vif->list, &priv->vif_list); return 0; @@ -3314,7 +3317,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, if (priv->ap_fw) mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); - mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); list_del(&mwl8k_vif->list); } @@ -3492,13 +3495,13 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, skb = ieee80211_beacon_get(hw, vif); if (skb != NULL) { - mwl8k_cmd_set_beacon(hw, skb->data, skb->len); + mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); kfree_skb(skb); } } if (changed & BSS_CHANGED_BEACON_ENABLED) - mwl8k_cmd_bss_start(hw, info->enable_beacon); + mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); out: mwl8k_fw_unlock(hw); @@ -4112,7 +4115,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Clear MAC address */ - rc = mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); if (rc) { printk(KERN_ERR "%s: Cannot clear MAC address\n", wiphy_name(hw->wiphy)); -- GitLab From ee0ddf1865954f44ee929d963e2c968eb377f447 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:51:30 +0100 Subject: [PATCH 0604/3892] mwl8k: enable multi-BSS AP operation As follows: - GET_HW_SPEC is now responsible for setting priv->{ap,sta}_macids_supported, which are bitmasks of supported macids for AP and STA mode. (Typically, STA firmware images will support only one macid, #0, in STA mode, and AP firmware images will support macids #0-7, in AP mode.) - Our wiphy ->interfaces_modes is now set based on the non-zero-ness of these two bitmasks. - We main priv->macids_used, a bitmask of which macids are currently in use. ->add_interface() will assign the lowest free macid for this interface type as it is created, or bail out if there are no more free macids to assign. ->delete_interface() will mark the macid as being free again. This enables the multi-BSS code added in the previous commits. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 70 ++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d8cf43853de1..06dc7a0978a0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -147,6 +147,8 @@ struct mwl8k_priv { struct ieee80211_supported_band band_50; struct ieee80211_channel channels_50[4]; struct ieee80211_rate rates_50[9]; + u32 ap_macids_supported; + u32 sta_macids_supported; /* firmware access */ struct mutex fw_mutex; @@ -161,6 +163,7 @@ struct mwl8k_priv { struct completion *tx_wait; /* List of interfaces. */ + u32 macids_used; struct list_head vif_list; /* power management status cookie from firmware */ @@ -1786,6 +1789,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); + priv->ap_macids_supported = 0x00000000; + priv->sta_macids_supported = 0x00000001; } kfree(cmd); @@ -1840,6 +1845,8 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; mwl8k_setup_2ghz_band(hw); + priv->ap_macids_supported = 0x000000ff; + priv->sta_macids_supported = 0x00000000; off = le32_to_cpu(cmd->wcbbase0) & 0xffff; iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); @@ -2759,16 +2766,33 @@ struct mwl8k_cmd_set_mac_addr { }; } __attribute__((packed)); -#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 -#define MWL8K_MAC_TYPE_PRIMARY_AP 2 +#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 +#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 +#define MWL8K_MAC_TYPE_PRIMARY_AP 2 +#define MWL8K_MAC_TYPE_SECONDARY_AP 3 static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 *mac) { struct mwl8k_priv *priv = hw->priv; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); struct mwl8k_cmd_set_mac_addr *cmd; + int mac_type; int rc; + mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; + if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { + if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) + mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; + else + mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; + } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { + if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) + mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; + else + mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; + } + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -2776,7 +2800,7 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); cmd->header.length = cpu_to_le16(sizeof(*cmd)); if (priv->ap_fw) { - cmd->mbss.mac_type = cpu_to_le16(MWL8K_MAC_TYPE_PRIMARY_AP); + cmd->mbss.mac_type = cpu_to_le16(mac_type); memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); } else { memcpy(cmd->mac_addr, mac, ETH_ALEN); @@ -3271,12 +3295,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif; - - /* - * We only support one active interface at a time. - */ - if (!list_empty(&priv->vif_list)) - return -EBUSY; + u32 macids_supported; + int macid; /* * Reject interface creation if sniffer mode is active, as @@ -3290,11 +3310,27 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, return -EINVAL; } + + switch (vif->type) { + case NL80211_IFTYPE_AP: + macids_supported = priv->ap_macids_supported; + break; + case NL80211_IFTYPE_STATION: + macids_supported = priv->sta_macids_supported; + break; + default: + return -EINVAL; + } + + macid = ffs(macids_supported & ~priv->macids_used); + if (!macid--) + return -EBUSY; + /* Setup driver private area. */ mwl8k_vif = MWL8K_VIF(vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); mwl8k_vif->vif = vif; - mwl8k_vif->macid = 0; + mwl8k_vif->macid = macid; mwl8k_vif->seqno = 0; /* Set the mac address. */ @@ -3303,6 +3339,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, if (priv->ap_fw) mwl8k_cmd_set_new_stn_add_self(hw, vif); + priv->macids_used |= 1 << mwl8k_vif->macid; list_add_tail(&mwl8k_vif->list, &priv->vif_list); return 0; @@ -3319,6 +3356,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); + priv->macids_used &= ~(1 << mwl8k_vif->macid); list_del(&mwl8k_vif->list); } @@ -4023,6 +4061,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->vif_data_size = sizeof(struct mwl8k_vif); hw->sta_data_size = sizeof(struct mwl8k_sta); + priv->macids_used = 0; INIT_LIST_HEAD(&priv->vif_list); /* Set default radio state and preamble */ @@ -4094,12 +4133,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_cmd_get_hw_spec_ap(hw); if (!rc) rc = mwl8k_cmd_set_hw_spec(hw); - - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP); } else { rc = mwl8k_cmd_get_hw_spec_sta(hw); - - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); } if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", @@ -4107,6 +4142,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_irq; } + hw->wiphy->interface_modes = 0; + if (priv->ap_macids_supported) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); + if (priv->sta_macids_supported) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); + + /* Turn radio off */ rc = mwl8k_cmd_radio_disable(hw); if (rc) { -- GitLab From a5fb297d634ba20bd53a7d6fecd611bbfd342e78 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 12 Jan 2010 13:51:38 +0100 Subject: [PATCH 0605/3892] mwl8k: update version number (to 0.12) and copyright Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 06dc7a0978a0..68546ca0ba37 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2,7 +2,7 @@ * drivers/net/wireless/mwl8k.c * Driver for Marvell TOPDOG 802.11 Wireless cards * - * Copyright (C) 2008-2009 Marvell Semiconductor Inc. + * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -26,7 +26,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.11" +#define MWL8K_VERSION "0.12" /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 -- GitLab From 74f292ca8c7a2b9370f80d97a49e48174f4c7635 Mon Sep 17 00:00:00 2001 From: Gary Stein Date: Wed, 13 Jan 2010 00:25:58 +0100 Subject: [PATCH 0606/3892] HID: add driver for the Logitech Flight System G940 Implements a new USB-HID for Force Feedback based on the normal Logitech Force Feedback code and FF-Memless. Currently only supports the FF_CONSTANT effect although the joystick appears to support additional non-standard ones. Signed-off-by: Gary Stein Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 8 ++ drivers/hid/Makefile | 3 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-lg.c | 7 +- drivers/hid/hid-lg.h | 6 ++ drivers/hid/hid-lg3ff.c | 176 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-lgff.c | 1 + 8 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 drivers/hid/hid-lg3ff.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 5f73774164d8..317049b80c35 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -189,6 +189,14 @@ config LOGIRUMBLEPAD2_FF Say Y here if you want to enable force feedback support for Logitech Rumblepad 2 devices. +config LOGIG940_FF + bool "Logitech Flight System G940 force feedback support" + depends on HID_LOGITECH + select INPUT_FF_MEMLESS + help + Say Y here if you want to enable force feedback support for Logitech + Flight System G940 devices. + config HID_MICROSOFT tristate "Microsoft" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index f8dc5bac79bd..ce6c8da28486 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -18,6 +18,9 @@ endif ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-objs += hid-lg2ff.o endif +ifdef CONFIG_LOGIG940_FF + hid-logitech-objs += hid-lg3ff.o +endif obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a4b496c68259..a0c0c49dec09 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1323,6 +1323,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 07e056b0e188..c7c9cbf8132c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -300,6 +300,7 @@ #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 +#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 9fcd3d017ab3..3677c9037a11 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -34,6 +34,7 @@ #define LG_FF 0x200 #define LG_FF2 0x400 #define LG_RDESC_REL_ABS 0x800 +#define LG_FF3 0x1000 /* * Certain Logitech keyboards send in report #3 keys which are far @@ -266,7 +267,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - if (quirks & (LG_FF | LG_FF2)) + if (quirks & (LG_FF | LG_FF2 | LG_FF3)) connect_mask &= ~HID_CONNECT_FF; ret = hid_hw_start(hdev, connect_mask); @@ -279,6 +280,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) lgff_init(hdev); if (quirks & LG_FF2) lg2ff_init(hdev); + if (quirks & LG_FF3) + lg3ff_init(hdev); return 0; err_free: @@ -331,6 +334,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), .driver_data = LG_FF2 }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), + .driver_data = LG_FF3 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), .driver_data = LG_RDESC_REL_ABS }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER), diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h index 27ae750ca878..8069c3e8b64a 100644 --- a/drivers/hid/hid-lg.h +++ b/drivers/hid/hid-lg.h @@ -15,4 +15,10 @@ int lg2ff_init(struct hid_device *hdev); static inline int lg2ff_init(struct hid_device *hdev) { return -1; } #endif +#ifdef CONFIG_LOGIG940_FF +int lg3ff_init(struct hid_device *hdev); +#else +static inline int lg3ff_init(struct hid_device *hdev) { return -1; } +#endif + #endif diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c new file mode 100644 index 000000000000..4002832ee4af --- /dev/null +++ b/drivers/hid/hid-lg3ff.c @@ -0,0 +1,176 @@ +/* + * Force feedback support for Logitech Flight System G940 + * + * Copyright (c) 2009 Gary Stein + */ + +/* + * 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 "usbhid/usbhid.h" +#include "hid-lg.h" + +/* + * G940 Theory of Operation (from experimentation) + * + * There are 63 fields (only 3 of them currently used) + * 0 - seems to be command field + * 1 - 30 deal with the x axis + * 31 -60 deal with the y axis + * + * Field 1 is x axis constant force + * Field 31 is y axis constant force + * + * other interesting fields 1,2,3,4 on x axis + * (same for 31,32,33,34 on y axis) + * + * 0 0 127 127 makes the joystick autocenter hard + * + * 127 0 127 127 makes the joystick loose on the right, + * but stops all movemnt left + * + * -127 0 -127 -127 makes the joystick loose on the left, + * but stops all movement right + * + * 0 0 -127 -127 makes the joystick rattle very hard + * + * I'm sure these are effects that I don't know enough about them + */ + +struct lg3ff_device { + struct hid_report *report; +}; + +static int hid_lg3ff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + int x, y; + +/* + * Maxusage should always be 63 (maximum fields) + * likely a better way to ensure this data is clean + */ + memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage); + + switch (effect->type) { + case FF_CONSTANT: +/* + * Already clamped in ff_memless + * 0 is center (different then other logitech) + */ + x = effect->u.ramp.start_level; + y = effect->u.ramp.end_level; + + /* send command byte */ + report->field[0]->value[0] = 0x51; + +/* + * Sign backwards from other Force3d pro + * which get recast here in two's complement 8 bits + */ + report->field[0]->value[1] = (unsigned char)(-x); + report->field[0]->value[31] = (unsigned char)(-y); + + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + } + return 0; +} +static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + +/* + * Auto Centering probed from device + * NOTE: deadman's switch on G940 must be covered + * for effects to work + */ + report->field[0]->value[0] = 0x51; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = 0x00; + report->field[0]->value[3] = 0x7F; + report->field[0]->value[4] = 0x7F; + report->field[0]->value[31] = 0x00; + report->field[0]->value[32] = 0x00; + report->field[0]->value[33] = 0x7F; + report->field[0]->value[34] = 0x7F; + + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + + +static const signed short ff3_joystick_ac[] = { + FF_CONSTANT, + FF_AUTOCENTER, + -1 +}; + +int lg3ff_init(struct hid_device *hid) +{ + struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + struct hid_report *report; + struct hid_field *field; + const signed short *ff_bits = ff3_joystick_ac; + int error; + int i; + + /* Find the report to use */ + if (list_empty(report_list)) { + err_hid("No output report found"); + return -1; + } + + /* Check that the report looks ok */ + report = list_entry(report_list->next, struct hid_report, list); + if (!report) { + err_hid("NULL output report"); + return -1; + } + + field = report->field[0]; + if (!field) { + err_hid("NULL field"); + return -1; + } + + /* Assume single fixed device G940 */ + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); + + error = input_ff_create_memless(dev, NULL, hid_lg3ff_play); + if (error) + return error; + + if (test_bit(FF_AUTOCENTER, dev->ffbit)) + dev->ff->set_autocenter = hid_lg3ff_set_autocenter; + + dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by " + "Gary Stein \n"); + return 0; +} + diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 987abebe0829..61142b76a9b1 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -67,6 +67,7 @@ static const struct dev_type devices[] = { { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, { 0x046d, 0xc286, ff_joystick_ac }, + { 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, -- GitLab From 49e4739a0cf681cbfe08c72232c1dcc130b66dde Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Wed, 13 Jan 2010 00:29:16 +0100 Subject: [PATCH 0607/3892] HID: add support for Acer T230H multitouch Add support for the Quanta Optical Touch dual-touch panel, present in the Acer T230H monitor, HP L2105tm, and Packard-Bell Video 200t. Signed-off-by: Stephane Chatty Tested-by: Jerome Vidal Tested-by: Cedric Berthier Acked-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-quanta.c | 259 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 270 insertions(+) create mode 100644 drivers/hid/hid-quanta.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 317049b80c35..38e969207636 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -241,6 +241,12 @@ config HID_PETALYNX ---help--- Support for Petalynx Maxter remote control. +config HID_QUANTA + tristate "Quanta Optical Touch" + depends on USB_HID + ---help--- + Support for Quanta Optical Touch dual-touch panels. + config HID_SAMSUNG tristate "Samsung" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ce6c8da28486..15541c47b172 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o +obj-$(CONFIG_HID_QUANTA) += hid-quanta.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a0c0c49dec09..056384cf05e4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1338,6 +1338,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c7c9cbf8132c..b009fd68deae 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -383,6 +383,9 @@ #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 +#define USB_VENDOR_ID_QUANTA 0x0408 +#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 + #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c new file mode 100644 index 000000000000..244d61c18a47 --- /dev/null +++ b/drivers/hid/hid-quanta.c @@ -0,0 +1,259 @@ +/* + * HID driver for Quanta Optical Touch dual-touch panels + * + * Copyright (c) 2009-2010 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +MODULE_VERSION("1.00"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("Quanta dual-touch panel"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct quanta_data { + __u16 x, y; + __u8 id; + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* is this the first finger in this frame? */ + bool activity_now; /* at least one active finger in this frame? */ + bool activity; /* at least one active finger previously? */ +}; + +static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + return -1; + case HID_DG_INRANGE: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + } + return 0; + + case 0xff000000: + /* ignore vendor-specific features */ + return -1; + } + + return 0; +} + +static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void quanta_filter_event(struct quanta_data *td, struct input_dev *input) +{ + + td->first = !td->first; /* touchscreen emulation */ + + if (!td->valid) { + /* + * touchscreen emulation: if no finger in this frame is valid + * and there previously was finger activity, this is a release + */ + if (!td->first && !td->activity_now && td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + td->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); + + input_mt_sync(input); + td->valid = false; + + /* touchscreen emulation: if first active finger in this frame... */ + if (!td->activity_now) { + /* if there was no previous activity, emit touch event */ + if (!td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + td->activity = true; + } + td->activity_now = true; + /* and in any case this is our preferred finger */ + input_event(input, EV_ABS, ABS_X, td->x); + input_event(input, EV_ABS, ABS_Y, td->y); + } +} + + +static int quanta_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct quanta_data *td = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + + switch (usage->hid) { + case HID_DG_INRANGE: + td->valid = !!value; + break; + case HID_GD_X: + td->x = value; + break; + case HID_GD_Y: + td->y = value; + quanta_filter_event(td, input); + break; + case HID_DG_CONTACTID: + td->id = value; + break; + case HID_DG_CONTACTCOUNT: + /* touch emulation: this is the last field in a frame */ + td->first = false; + td->activity_now = false; + break; + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + /* avoid interference from generic hidinput handling */ + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct quanta_data *td; + + td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n"); + return -ENOMEM; + } + td->valid = false; + td->activity = false; + td->activity_now = false; + td->first = false; + hid_set_drvdata(hdev, td); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree(td); + + return ret; +} + +static void quanta_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id quanta_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, + USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { } +}; +MODULE_DEVICE_TABLE(hid, quanta_devices); + +static const struct hid_usage_id quanta_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver quanta_driver = { + .name = "quanta-touch", + .id_table = quanta_devices, + .probe = quanta_probe, + .remove = quanta_remove, + .input_mapping = quanta_input_mapping, + .input_mapped = quanta_input_mapped, + .usage_table = quanta_grabbed_usages, + .event = quanta_event, +}; + +static int __init quanta_init(void) +{ + return hid_register_driver(&quanta_driver); +} + +static void __exit quanta_exit(void) +{ + hid_unregister_driver(&quanta_driver); +} + +module_init(quanta_init); +module_exit(quanta_exit); + -- GitLab From 0ea820cf9bf58f735ed40ec67947159c4f170012 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 12:51:40 +0900 Subject: [PATCH 0608/3892] sh: Move over to dynamically allocated FPU context. This follows the x86 xstate changes and implements a task_xstate slab cache that is dynamically sized to match one of hard FP/soft FP/FPU-less. This also tidies up and consolidates some of the SH-2A/SH-4 FPU fragmentation. Now fpu state restorers are commonly defined, with the init_fpu()/fpu_init() mess reworked to follow the x86 convention. The fpu_init() register initialization has been replaced by xstate setup followed by writing out to hardware via the standard restore path. As init_fpu() now performs a slab allocation a secondary lighterweight restorer is also introduced for the context switch. In the future the DSP state will be rolled in here, too. More work remains for math emulation and the SH-5 FPU, which presently uses its own special (UP-only) interfaces. Signed-off-by: Paul Mundt --- arch/sh/include/asm/fpu.h | 35 +++---- arch/sh/include/asm/processor_32.h | 16 +-- arch/sh/include/asm/thread_info.h | 4 + arch/sh/kernel/cpu/Makefile | 2 + arch/sh/kernel/cpu/fpu.c | 82 +++++++++++++++ arch/sh/kernel/cpu/init.c | 80 +++++++++------ arch/sh/kernel/cpu/sh2a/fpu.c | 111 +++++--------------- arch/sh/kernel/cpu/sh4/fpu.c | 159 +++++++---------------------- arch/sh/kernel/process.c | 54 ++++++++++ arch/sh/kernel/process_32.c | 6 +- arch/sh/kernel/ptrace_32.c | 12 +-- arch/sh/kernel/signal_32.c | 4 +- arch/sh/math-emu/math.c | 12 +-- 13 files changed, 292 insertions(+), 285 deletions(-) create mode 100644 arch/sh/kernel/cpu/fpu.c diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h index fb6bbb9b1cc8..06c4281aab65 100644 --- a/arch/sh/include/asm/fpu.h +++ b/arch/sh/include/asm/fpu.h @@ -2,8 +2,8 @@ #define __ASM_SH_FPU_H #ifndef __ASSEMBLY__ -#include -#include + +struct task_struct; #ifdef CONFIG_SH_FPU static inline void release_fpu(struct pt_regs *regs) @@ -16,22 +16,23 @@ static inline void grab_fpu(struct pt_regs *regs) regs->sr &= ~SR_FD; } -struct task_struct; - extern void save_fpu(struct task_struct *__tsk); -void fpu_state_restore(struct pt_regs *regs); +extern void restore_fpu(struct task_struct *__tsk); +extern void fpu_state_restore(struct pt_regs *regs); +extern void __fpu_state_restore(void); #else - -#define save_fpu(tsk) do { } while (0) -#define release_fpu(regs) do { } while (0) -#define grab_fpu(regs) do { } while (0) -#define fpu_state_restore(regs) do { } while (0) - +#define save_fpu(tsk) do { } while (0) +#define restore_fpu(tsk) do { } while (0) +#define release_fpu(regs) do { } while (0) +#define grab_fpu(regs) do { } while (0) +#define fpu_state_restore(regs) do { } while (0) +#define __fpu_state_restore(regs) do { } while (0) #endif struct user_regset; extern int do_fpu_inst(unsigned short, struct pt_regs *); +extern int init_fpu(struct task_struct *); extern int fpregs_get(struct task_struct *target, const struct user_regset *regset, @@ -65,18 +66,6 @@ static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) preempt_enable(); } -static inline int init_fpu(struct task_struct *tsk) -{ - if (tsk_used_math(tsk)) { - if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current) - unlazy_fpu(tsk, task_pt_regs(tsk)); - return 0; - } - - set_stopped_child_used_math(tsk); - return 0; -} - #endif /* __ASSEMBLY__ */ #endif /* __ASM_SH_FPU_H */ diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 50b8c9c3fa4c..a359898206e8 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -90,11 +90,15 @@ struct sh_fpu_soft_struct { unsigned long entry_pc; }; -union sh_fpu_union { - struct sh_fpu_hard_struct hard; - struct sh_fpu_soft_struct soft; +union thread_xstate { + struct sh_fpu_hard_struct hardfpu; + struct sh_fpu_soft_struct softfpu; }; +extern unsigned int xstate_size; +extern void free_thread_xstate(struct task_struct *); +extern struct kmem_cache *task_xstate_cachep; + struct thread_struct { /* Saved registers when thread is descheduled */ unsigned long sp; @@ -103,13 +107,13 @@ struct thread_struct { /* Hardware debugging registers */ unsigned long ubc_pc; - /* floating point info */ - union sh_fpu_union fpu; - #ifdef CONFIG_SH_DSP /* Dsp status information */ struct sh_dsp_struct dsp_status; #endif + + /* Extended processor state */ + union thread_xstate *xstate; }; /* Count of active tasks with UBC settings */ diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index 2c5b48edeab9..55a36fef6875 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h @@ -97,6 +97,10 @@ static inline struct thread_info *current_thread_info(void) extern struct thread_info *alloc_thread_info(struct task_struct *tsk); extern void free_thread_info(struct thread_info *ti); +extern void arch_task_cache_init(void); +#define arch_task_cache_init arch_task_cache_init +extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); +extern void init_thread_xstate(void); #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index d97c803719ec..0e48bc61c272 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile @@ -17,5 +17,7 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/ obj-$(CONFIG_SH_ADC) += adc.o obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o +obj-$(CONFIG_SH_FPU) += fpu.o +obj-$(CONFIG_SH_FPU_EMU) += fpu.o obj-y += irq/ init.o clock.o hwblk.o diff --git a/arch/sh/kernel/cpu/fpu.c b/arch/sh/kernel/cpu/fpu.c new file mode 100644 index 000000000000..c23e6727002a --- /dev/null +++ b/arch/sh/kernel/cpu/fpu.c @@ -0,0 +1,82 @@ +#include +#include +#include + +int init_fpu(struct task_struct *tsk) +{ + if (tsk_used_math(tsk)) { + if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current) + unlazy_fpu(tsk, task_pt_regs(tsk)); + return 0; + } + + /* + * Memory allocation at the first usage of the FPU and other state. + */ + if (!tsk->thread.xstate) { + tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep, + GFP_KERNEL); + if (!tsk->thread.xstate) + return -ENOMEM; + } + + if (boot_cpu_data.flags & CPU_HAS_FPU) { + struct sh_fpu_hard_struct *fp = &tsk->thread.xstate->hardfpu; + memset(fp, 0, xstate_size); + fp->fpscr = FPSCR_INIT; + } else { + struct sh_fpu_soft_struct *fp = &tsk->thread.xstate->softfpu; + memset(fp, 0, xstate_size); + fp->fpscr = FPSCR_INIT; + } + + set_stopped_child_used_math(tsk); + return 0; +} + +#ifdef CONFIG_SH_FPU +void __fpu_state_restore(void) +{ + struct task_struct *tsk = current; + + restore_fpu(tsk); + + task_thread_info(tsk)->status |= TS_USEDFPU; + tsk->fpu_counter++; +} + +void fpu_state_restore(struct pt_regs *regs) +{ + struct task_struct *tsk = current; + + if (unlikely(!user_mode(regs))) { + printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); + BUG(); + return; + } + + if (!tsk_used_math(tsk)) { + /* + * does a slab alloc which can sleep + */ + if (init_fpu(tsk)) { + /* + * ran out of memory! + */ + do_group_exit(SIGKILL); + return; + } + } + + grab_fpu(regs); + + __fpu_state_restore(); +} + +BUILD_TRAP_HANDLER(fpu_state_restore) +{ + TRAP_HANDLER_DECL; + + fpu_state_restore(regs); +} +#endif /* CONFIG_SH_FPU */ diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 89b4b76c0d76..2e23422280a7 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -28,18 +28,30 @@ #include #endif +#ifdef CONFIG_SH_FPU +#define cpu_has_fpu 1 +#else +#define cpu_has_fpu 0 +#endif + +#ifdef CONFIG_SH_DSP +#define cpu_has_dsp 1 +#else +#define cpu_has_dsp 0 +#endif + /* * Generic wrapper for command line arguments to disable on-chip * peripherals (nofpu, nodsp, and so forth). */ -#define onchip_setup(x) \ -static int x##_disabled __initdata = 0; \ - \ -static int __init x##_setup(char *opts) \ -{ \ - x##_disabled = 1; \ - return 1; \ -} \ +#define onchip_setup(x) \ +static int x##_disabled __initdata = !cpu_has_##x; \ + \ +static int __init x##_setup(char *opts) \ +{ \ + x##_disabled = 1; \ + return 1; \ +} \ __setup("no" __stringify(x), x##_setup); onchip_setup(fpu); @@ -207,6 +219,18 @@ static void detect_cache_shape(void) l2_cache_shape = -1; /* No S-cache */ } +static void __init fpu_init(void) +{ + /* Disable the FPU */ + if (fpu_disabled && (current_cpu_data.flags & CPU_HAS_FPU)) { + printk("FPU Disabled\n"); + current_cpu_data.flags &= ~CPU_HAS_FPU; + } + + disable_fpu(); + clear_used_math(); +} + #ifdef CONFIG_SH_DSP static void __init release_dsp(void) { @@ -244,9 +268,17 @@ static void __init dsp_init(void) if (sr & SR_DSP) current_cpu_data.flags |= CPU_HAS_DSP; + /* Disable the DSP */ + if (dsp_disabled && (current_cpu_data.flags & CPU_HAS_DSP)) { + printk("DSP Disabled\n"); + current_cpu_data.flags &= ~CPU_HAS_DSP; + } + /* Now that we've determined the DSP status, clear the DSP bit. */ release_dsp(); } +#else +static inline void __init dsp_init(void) { } #endif /* CONFIG_SH_DSP */ /** @@ -302,18 +334,8 @@ asmlinkage void __init sh_cpu_init(void) detect_cache_shape(); } - /* Disable the FPU */ - if (fpu_disabled) { - printk("FPU Disabled\n"); - current_cpu_data.flags &= ~CPU_HAS_FPU; - } - - /* FPU initialization */ - disable_fpu(); - if ((current_cpu_data.flags & CPU_HAS_FPU)) { - current_thread_info()->status &= ~TS_USEDFPU; - clear_used_math(); - } + fpu_init(); + dsp_init(); /* * Initialize the per-CPU ASID cache very early, since the @@ -321,18 +343,12 @@ asmlinkage void __init sh_cpu_init(void) */ current_cpu_data.asid_cache = NO_CONTEXT; -#ifdef CONFIG_SH_DSP - /* Probe for DSP */ - dsp_init(); - - /* Disable the DSP */ - if (dsp_disabled) { - printk("DSP Disabled\n"); - current_cpu_data.flags &= ~CPU_HAS_DSP; - release_dsp(); - } -#endif - speculative_execution_init(); expmask_init(); + + /* + * Boot processor to setup the FP and extended state context info. + */ + if (raw_smp_processor_id() == 0) + init_thread_xstate(); } diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c index d395ce5740e7..488d24e0cdf0 100644 --- a/arch/sh/kernel/cpu/sh2a/fpu.c +++ b/arch/sh/kernel/cpu/sh2a/fpu.c @@ -26,8 +26,7 @@ /* * Save FPU registers onto task structure. */ -void -save_fpu(struct task_struct *tsk) +void save_fpu(struct task_struct *tsk) { unsigned long dummy; @@ -52,7 +51,7 @@ save_fpu(struct task_struct *tsk) "fmov.s fr0, @-%0\n\t" "lds %3, fpscr\n\t" : "=r" (dummy) - : "0" ((char *)(&tsk->thread.fpu.hard.status)), + : "0" ((char *)(&tsk->thread.xstate->hardfpu.status)), "r" (FPSCR_RCHG), "r" (FPSCR_INIT) : "memory"); @@ -60,8 +59,7 @@ save_fpu(struct task_struct *tsk) disable_fpu(); } -static void -restore_fpu(struct task_struct *tsk) +void restore_fpu(struct task_struct *tsk) { unsigned long dummy; @@ -85,44 +83,11 @@ restore_fpu(struct task_struct *tsk) "lds.l @%0+, fpscr\n\t" "lds.l @%0+, fpul\n\t" : "=r" (dummy) - : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG) + : "0" (tsk->thread.xstate), "r" (FPSCR_RCHG) : "memory"); disable_fpu(); } -/* - * Load the FPU with signalling NANS. This bit pattern we're using - * has the property that no matter wether considered as single or as - * double precission represents signaling NANS. - */ - -static void -fpu_init(void) -{ - enable_fpu(); - asm volatile("lds %0, fpul\n\t" - "fsts fpul, fr0\n\t" - "fsts fpul, fr1\n\t" - "fsts fpul, fr2\n\t" - "fsts fpul, fr3\n\t" - "fsts fpul, fr4\n\t" - "fsts fpul, fr5\n\t" - "fsts fpul, fr6\n\t" - "fsts fpul, fr7\n\t" - "fsts fpul, fr8\n\t" - "fsts fpul, fr9\n\t" - "fsts fpul, fr10\n\t" - "fsts fpul, fr11\n\t" - "fsts fpul, fr12\n\t" - "fsts fpul, fr13\n\t" - "fsts fpul, fr14\n\t" - "fsts fpul, fr15\n\t" - "lds %2, fpscr\n\t" - : /* no output */ - : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT)); - disable_fpu(); -} - /* * Emulate arithmetic ops on denormalized number for some FPU insns. */ @@ -490,9 +455,9 @@ ieee_fpe_handler (struct pt_regs *regs) if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ struct task_struct *tsk = current; - if ((tsk->thread.fpu.hard.fpscr & FPSCR_FPU_ERROR)) { + if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) { /* FPU error */ - denormal_to_double (&tsk->thread.fpu.hard, + denormal_to_double (&tsk->thread.xstate->hardfpu, (finsn >> 8) & 0xf); } else return 0; @@ -507,9 +472,9 @@ ieee_fpe_handler (struct pt_regs *regs) n = (finsn >> 8) & 0xf; m = (finsn >> 4) & 0xf; - hx = tsk->thread.fpu.hard.fp_regs[n]; - hy = tsk->thread.fpu.hard.fp_regs[m]; - fpscr = tsk->thread.fpu.hard.fpscr; + hx = tsk->thread.xstate->hardfpu.fp_regs[n]; + hy = tsk->thread.xstate->hardfpu.fp_regs[m]; + fpscr = tsk->thread.xstate->hardfpu.fpscr; prec = fpscr & (1 << 19); if ((fpscr & FPSCR_FPU_ERROR) @@ -519,15 +484,15 @@ ieee_fpe_handler (struct pt_regs *regs) /* FPU error because of denormal */ llx = ((long long) hx << 32) - | tsk->thread.fpu.hard.fp_regs[n+1]; + | tsk->thread.xstate->hardfpu.fp_regs[n+1]; lly = ((long long) hy << 32) - | tsk->thread.fpu.hard.fp_regs[m+1]; + | tsk->thread.xstate->hardfpu.fp_regs[m+1]; if ((hx & 0x7fffffff) >= 0x00100000) llx = denormal_muld(lly, llx); else llx = denormal_muld(llx, lly); - tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; - tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff; + tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; + tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; } else if ((fpscr & FPSCR_FPU_ERROR) && (!prec && ((hx & 0x7fffffff) < 0x00800000 || (hy & 0x7fffffff) < 0x00800000))) { @@ -536,7 +501,7 @@ ieee_fpe_handler (struct pt_regs *regs) hx = denormal_mulf(hy, hx); else hx = denormal_mulf(hx, hy); - tsk->thread.fpu.hard.fp_regs[n] = hx; + tsk->thread.xstate->hardfpu.fp_regs[n] = hx; } else return 0; @@ -550,9 +515,9 @@ ieee_fpe_handler (struct pt_regs *regs) n = (finsn >> 8) & 0xf; m = (finsn >> 4) & 0xf; - hx = tsk->thread.fpu.hard.fp_regs[n]; - hy = tsk->thread.fpu.hard.fp_regs[m]; - fpscr = tsk->thread.fpu.hard.fpscr; + hx = tsk->thread.xstate->hardfpu.fp_regs[n]; + hy = tsk->thread.xstate->hardfpu.fp_regs[m]; + fpscr = tsk->thread.xstate->hardfpu.fpscr; prec = fpscr & (1 << 19); if ((fpscr & FPSCR_FPU_ERROR) @@ -562,15 +527,15 @@ ieee_fpe_handler (struct pt_regs *regs) /* FPU error because of denormal */ llx = ((long long) hx << 32) - | tsk->thread.fpu.hard.fp_regs[n+1]; + | tsk->thread.xstate->hardfpu.fp_regs[n+1]; lly = ((long long) hy << 32) - | tsk->thread.fpu.hard.fp_regs[m+1]; + | tsk->thread.xstate->hardfpu.fp_regs[m+1]; if ((finsn & 0xf00f) == 0xf000) llx = denormal_addd(llx, lly); else llx = denormal_addd(llx, lly ^ (1LL << 63)); - tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; - tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff; + tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; + tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; } else if ((fpscr & FPSCR_FPU_ERROR) && (!prec && ((hx & 0x7fffffff) < 0x00800000 || (hy & 0x7fffffff) < 0x00800000))) { @@ -579,7 +544,7 @@ ieee_fpe_handler (struct pt_regs *regs) hx = denormal_addf(hx, hy); else hx = denormal_addf(hx, hy ^ 0x80000000); - tsk->thread.fpu.hard.fp_regs[n] = hx; + tsk->thread.xstate->hardfpu.fp_regs[n] = hx; } else return 0; @@ -597,7 +562,7 @@ BUILD_TRAP_HANDLER(fpu_error) __unlazy_fpu(tsk, regs); if (ieee_fpe_handler(regs)) { - tsk->thread.fpu.hard.fpscr &= + tsk->thread.xstate->hardfpu.fpscr &= ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); grab_fpu(regs); restore_fpu(tsk); @@ -607,33 +572,3 @@ BUILD_TRAP_HANDLER(fpu_error) force_sig(SIGFPE, tsk); } - -void fpu_state_restore(struct pt_regs *regs) -{ - struct task_struct *tsk = current; - - grab_fpu(regs); - if (unlikely(!user_mode(regs))) { - printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); - BUG(); - return; - } - - if (likely(used_math())) { - /* Using the FPU again. */ - restore_fpu(tsk); - } else { - /* First time FPU user. */ - fpu_init(); - set_used_math(); - } - task_thread_info(tsk)->status |= TS_USEDFPU; - tsk->fpu_counter++; -} - -BUILD_TRAP_HANDLER(fpu_state_restore) -{ - TRAP_HANDLER_DECL; - - fpu_state_restore(regs); -} diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index e97857aec8a0..447482d7f65e 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c @@ -85,14 +85,14 @@ void save_fpu(struct task_struct *tsk) "fmov.s fr1, @-%0\n\t" "fmov.s fr0, @-%0\n\t" "lds %3, fpscr\n\t":"=r" (dummy) - :"0"((char *)(&tsk->thread.fpu.hard.status)), + :"0"((char *)(&tsk->thread.xstate->hardfpu.status)), "r"(FPSCR_RCHG), "r"(FPSCR_INIT) :"memory"); disable_fpu(); } -static void restore_fpu(struct task_struct *tsk) +void restore_fpu(struct task_struct *tsk) { unsigned long dummy; @@ -135,62 +135,11 @@ static void restore_fpu(struct task_struct *tsk) "lds.l @%0+, fpscr\n\t" "lds.l @%0+, fpul\n\t" :"=r" (dummy) - :"0"(&tsk->thread.fpu), "r"(FPSCR_RCHG) + :"0" (tsk->thread.xstate), "r" (FPSCR_RCHG) :"memory"); disable_fpu(); } -/* - * Load the FPU with signalling NANS. This bit pattern we're using - * has the property that no matter wether considered as single or as - * double precision represents signaling NANS. - */ - -static void fpu_init(void) -{ - enable_fpu(); - asm volatile ( "lds %0, fpul\n\t" - "lds %1, fpscr\n\t" - "fsts fpul, fr0\n\t" - "fsts fpul, fr1\n\t" - "fsts fpul, fr2\n\t" - "fsts fpul, fr3\n\t" - "fsts fpul, fr4\n\t" - "fsts fpul, fr5\n\t" - "fsts fpul, fr6\n\t" - "fsts fpul, fr7\n\t" - "fsts fpul, fr8\n\t" - "fsts fpul, fr9\n\t" - "fsts fpul, fr10\n\t" - "fsts fpul, fr11\n\t" - "fsts fpul, fr12\n\t" - "fsts fpul, fr13\n\t" - "fsts fpul, fr14\n\t" - "fsts fpul, fr15\n\t" - "frchg\n\t" - "fsts fpul, fr0\n\t" - "fsts fpul, fr1\n\t" - "fsts fpul, fr2\n\t" - "fsts fpul, fr3\n\t" - "fsts fpul, fr4\n\t" - "fsts fpul, fr5\n\t" - "fsts fpul, fr6\n\t" - "fsts fpul, fr7\n\t" - "fsts fpul, fr8\n\t" - "fsts fpul, fr9\n\t" - "fsts fpul, fr10\n\t" - "fsts fpul, fr11\n\t" - "fsts fpul, fr12\n\t" - "fsts fpul, fr13\n\t" - "fsts fpul, fr14\n\t" - "fsts fpul, fr15\n\t" - "frchg\n\t" - "lds %2, fpscr\n\t" - : /* no output */ - :"r" (0), "r"(FPSCR_RCHG), "r"(FPSCR_INIT)); - disable_fpu(); -} - /** * denormal_to_double - Given denormalized float number, * store double float @@ -282,9 +231,9 @@ static int ieee_fpe_handler(struct pt_regs *regs) /* fcnvsd */ struct task_struct *tsk = current; - if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) + if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR)) /* FPU error */ - denormal_to_double(&tsk->thread.fpu.hard, + denormal_to_double(&tsk->thread.xstate->hardfpu, (finsn >> 8) & 0xf); else return 0; @@ -300,9 +249,9 @@ static int ieee_fpe_handler(struct pt_regs *regs) n = (finsn >> 8) & 0xf; m = (finsn >> 4) & 0xf; - hx = tsk->thread.fpu.hard.fp_regs[n]; - hy = tsk->thread.fpu.hard.fp_regs[m]; - fpscr = tsk->thread.fpu.hard.fpscr; + hx = tsk->thread.xstate->hardfpu.fp_regs[n]; + hy = tsk->thread.xstate->hardfpu.fp_regs[m]; + fpscr = tsk->thread.xstate->hardfpu.fpscr; prec = fpscr & FPSCR_DBL_PRECISION; if ((fpscr & FPSCR_CAUSE_ERROR) @@ -312,18 +261,18 @@ static int ieee_fpe_handler(struct pt_regs *regs) /* FPU error because of denormal (doubles) */ llx = ((long long)hx << 32) - | tsk->thread.fpu.hard.fp_regs[n + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[n + 1]; lly = ((long long)hy << 32) - | tsk->thread.fpu.hard.fp_regs[m + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[m + 1]; llx = float64_mul(llx, lly); - tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; - tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff; + tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; + tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff; } else if ((fpscr & FPSCR_CAUSE_ERROR) && (!prec && ((hx & 0x7fffffff) < 0x00800000 || (hy & 0x7fffffff) < 0x00800000))) { /* FPU error because of denormal (floats) */ hx = float32_mul(hx, hy); - tsk->thread.fpu.hard.fp_regs[n] = hx; + tsk->thread.xstate->hardfpu.fp_regs[n] = hx; } else return 0; @@ -338,9 +287,9 @@ static int ieee_fpe_handler(struct pt_regs *regs) n = (finsn >> 8) & 0xf; m = (finsn >> 4) & 0xf; - hx = tsk->thread.fpu.hard.fp_regs[n]; - hy = tsk->thread.fpu.hard.fp_regs[m]; - fpscr = tsk->thread.fpu.hard.fpscr; + hx = tsk->thread.xstate->hardfpu.fp_regs[n]; + hy = tsk->thread.xstate->hardfpu.fp_regs[m]; + fpscr = tsk->thread.xstate->hardfpu.fpscr; prec = fpscr & FPSCR_DBL_PRECISION; if ((fpscr & FPSCR_CAUSE_ERROR) @@ -350,15 +299,15 @@ static int ieee_fpe_handler(struct pt_regs *regs) /* FPU error because of denormal (doubles) */ llx = ((long long)hx << 32) - | tsk->thread.fpu.hard.fp_regs[n + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[n + 1]; lly = ((long long)hy << 32) - | tsk->thread.fpu.hard.fp_regs[m + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[m + 1]; if ((finsn & 0xf00f) == 0xf000) llx = float64_add(llx, lly); else llx = float64_sub(llx, lly); - tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; - tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff; + tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; + tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff; } else if ((fpscr & FPSCR_CAUSE_ERROR) && (!prec && ((hx & 0x7fffffff) < 0x00800000 || (hy & 0x7fffffff) < 0x00800000))) { @@ -367,7 +316,7 @@ static int ieee_fpe_handler(struct pt_regs *regs) hx = float32_add(hx, hy); else hx = float32_sub(hx, hy); - tsk->thread.fpu.hard.fp_regs[n] = hx; + tsk->thread.xstate->hardfpu.fp_regs[n] = hx; } else return 0; @@ -382,9 +331,9 @@ static int ieee_fpe_handler(struct pt_regs *regs) n = (finsn >> 8) & 0xf; m = (finsn >> 4) & 0xf; - hx = tsk->thread.fpu.hard.fp_regs[n]; - hy = tsk->thread.fpu.hard.fp_regs[m]; - fpscr = tsk->thread.fpu.hard.fpscr; + hx = tsk->thread.xstate->hardfpu.fp_regs[n]; + hy = tsk->thread.xstate->hardfpu.fp_regs[m]; + fpscr = tsk->thread.xstate->hardfpu.fpscr; prec = fpscr & FPSCR_DBL_PRECISION; if ((fpscr & FPSCR_CAUSE_ERROR) @@ -394,20 +343,20 @@ static int ieee_fpe_handler(struct pt_regs *regs) /* FPU error because of denormal (doubles) */ llx = ((long long)hx << 32) - | tsk->thread.fpu.hard.fp_regs[n + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[n + 1]; lly = ((long long)hy << 32) - | tsk->thread.fpu.hard.fp_regs[m + 1]; + | tsk->thread.xstate->hardfpu.fp_regs[m + 1]; llx = float64_div(llx, lly); - tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; - tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff; + tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; + tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff; } else if ((fpscr & FPSCR_CAUSE_ERROR) && (!prec && ((hx & 0x7fffffff) < 0x00800000 || (hy & 0x7fffffff) < 0x00800000))) { /* FPU error because of denormal (floats) */ hx = float32_div(hx, hy); - tsk->thread.fpu.hard.fp_regs[n] = hx; + tsk->thread.xstate->hardfpu.fp_regs[n] = hx; } else return 0; @@ -420,17 +369,17 @@ static int ieee_fpe_handler(struct pt_regs *regs) unsigned int hx; m = (finsn >> 8) & 0x7; - hx = tsk->thread.fpu.hard.fp_regs[m]; + hx = tsk->thread.xstate->hardfpu.fp_regs[m]; - if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR) + if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR) && ((hx & 0x7fffffff) < 0x00100000)) { /* subnormal double to float conversion */ long long llx; - llx = ((long long)tsk->thread.fpu.hard.fp_regs[m] << 32) - | tsk->thread.fpu.hard.fp_regs[m + 1]; + llx = ((long long)tsk->thread.xstate->hardfpu.fp_regs[m] << 32) + | tsk->thread.xstate->hardfpu.fp_regs[m + 1]; - tsk->thread.fpu.hard.fpul = float64_to_float32(llx); + tsk->thread.xstate->hardfpu.fpul = float64_to_float32(llx); } else return 0; @@ -449,7 +398,7 @@ void float_raise(unsigned int flags) int float_rounding_mode(void) { struct task_struct *tsk = current; - int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.fpu.hard.fpscr); + int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.xstate->hardfpu.fpscr); return roundingMode; } @@ -461,16 +410,16 @@ BUILD_TRAP_HANDLER(fpu_error) __unlazy_fpu(tsk, regs); fpu_exception_flags = 0; if (ieee_fpe_handler(regs)) { - tsk->thread.fpu.hard.fpscr &= + tsk->thread.xstate->hardfpu.fpscr &= ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); - tsk->thread.fpu.hard.fpscr |= fpu_exception_flags; + tsk->thread.xstate->hardfpu.fpscr |= fpu_exception_flags; /* Set the FPSCR flag as well as cause bits - simply * replicate the cause */ - tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); + tsk->thread.xstate->hardfpu.fpscr |= (fpu_exception_flags >> 10); grab_fpu(regs); restore_fpu(tsk); task_thread_info(tsk)->status |= TS_USEDFPU; - if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & + if ((((tsk->thread.xstate->hardfpu.fpscr & FPSCR_ENABLE_MASK) >> 7) & (fpu_exception_flags >> 2)) == 0) { return; } @@ -478,33 +427,3 @@ BUILD_TRAP_HANDLER(fpu_error) force_sig(SIGFPE, tsk); } - -void fpu_state_restore(struct pt_regs *regs) -{ - struct task_struct *tsk = current; - - grab_fpu(regs); - if (unlikely(!user_mode(regs))) { - printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); - BUG(); - return; - } - - if (likely(used_math())) { - /* Using the FPU again. */ - restore_fpu(tsk); - } else { - /* First time FPU user. */ - fpu_init(); - set_used_math(); - } - task_thread_info(tsk)->status |= TS_USEDFPU; - tsk->fpu_counter++; -} - -BUILD_TRAP_HANDLER(fpu_state_restore) -{ - TRAP_HANDLER_DECL; - - fpu_state_restore(regs); -} diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 077e06e1a889..81add9b9ea6e 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -2,6 +2,32 @@ #include #include +struct kmem_cache *task_xstate_cachep = NULL; +unsigned int xstate_size; + +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) +{ + *dst = *src; + + if (src->thread.xstate) { + dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep, + GFP_KERNEL); + if (!dst->thread.xstate) + return -ENOMEM; + memcpy(dst->thread.xstate, src->thread.xstate, xstate_size); + } + + return 0; +} + +void free_thread_xstate(struct task_struct *tsk) +{ + if (tsk->thread.xstate) { + kmem_cache_free(task_xstate_cachep, tsk->thread.xstate); + tsk->thread.xstate = NULL; + } +} + #if THREAD_SHIFT < PAGE_SHIFT static struct kmem_cache *thread_info_cache; @@ -20,6 +46,7 @@ struct thread_info *alloc_thread_info(struct task_struct *tsk) void free_thread_info(struct thread_info *ti) { + free_thread_xstate(ti->task); kmem_cache_free(thread_info_cache, ti); } @@ -41,6 +68,33 @@ struct thread_info *alloc_thread_info(struct task_struct *tsk) void free_thread_info(struct thread_info *ti) { + free_thread_xstate(ti->task); free_pages((unsigned long)ti, THREAD_SIZE_ORDER); } #endif /* THREAD_SHIFT < PAGE_SHIFT */ + +void arch_task_cache_init(void) +{ + if (!xstate_size) + return; + + task_xstate_cachep = kmem_cache_create("task_xstate", xstate_size, + __alignof__(union thread_xstate), + SLAB_PANIC | SLAB_NOTRACK, NULL); +} + +#ifdef CONFIG_SH_FPU_EMU +# define HAVE_SOFTFP 1 +#else +# define HAVE_SOFTFP 0 +#endif + +void init_thread_xstate(void) +{ + if (boot_cpu_data.flags & CPU_HAS_FPU) + xstate_size = sizeof(struct sh_fpu_hard_struct); + else if (HAVE_SOFTFP) + xstate_size = sizeof(struct sh_fpu_soft_struct); + else + xstate_size = 0; +} diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index c4361402ec5e..03de6573aa76 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -156,6 +156,8 @@ void start_thread(struct pt_regs *regs, unsigned long new_pc, regs->sr = SR_FD; regs->pc = new_pc; regs->regs[15] = new_sp; + + free_thread_xstate(current); } EXPORT_SYMBOL(start_thread); @@ -316,7 +318,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next) /* we're going to use this soon, after a few expensive things */ if (next->fpu_counter > 5) - prefetch(&next_t->fpu.hard); + prefetch(next_t->xstate); #ifdef CONFIG_MMU /* @@ -353,7 +355,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next) * chances of needing FPU soon are obviously high now */ if (next->fpu_counter > 5) - fpu_state_restore(task_pt_regs(next)); + __fpu_state_restore(); return prev; } diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 9be35f348093..be9b5dcb4021 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -163,10 +163,10 @@ int fpregs_get(struct task_struct *target, if ((boot_cpu_data.flags & CPU_HAS_FPU)) return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.hard, 0, -1); + &target->thread.xstate->hardfpu, 0, -1); return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.soft, 0, -1); + &target->thread.xstate->softfpu, 0, -1); } static int fpregs_set(struct task_struct *target, @@ -184,10 +184,10 @@ static int fpregs_set(struct task_struct *target, if ((boot_cpu_data.flags & CPU_HAS_FPU)) return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.hard, 0, -1); + &target->thread.xstate->hardfpu, 0, -1); return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.soft, 0, -1); + &target->thread.xstate->softfpu, 0, -1); } static int fpregs_active(struct task_struct *target, @@ -333,7 +333,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) else tmp = 0; } else - tmp = ((long *)&child->thread.fpu) + tmp = ((long *)child->thread.xstate) [(addr - (long)&dummy->fpu) >> 2]; } else if (addr == (long) &dummy->u_fpvalid) tmp = !!tsk_used_math(child); @@ -362,7 +362,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) else if (addr >= (long) &dummy->fpu && addr < (long) &dummy->u_fpvalid) { set_stopped_child_used_math(child); - ((long *)&child->thread.fpu) + ((long *)child->thread.xstate) [(addr - (long)&dummy->fpu) >> 2] = data; ret = 0; } else if (addr == (long) &dummy->u_fpvalid) { diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 12815ce01ecd..6a7cce79eb4e 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -150,7 +150,7 @@ static inline int restore_sigcontext_fpu(struct sigcontext __user *sc) return 0; set_used_math(); - return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0], + return __copy_from_user(&tsk->thread.xstate->hardfpu, &sc->sc_fpregs[0], sizeof(long)*(16*2+2)); } @@ -175,7 +175,7 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc, clear_used_math(); unlazy_fpu(tsk, regs); - return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard, + return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.xstate->hardfpu, sizeof(long)*(16*2+2)); } #endif /* CONFIG_SH_FPU */ diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index d6c15cae0912..1fcdb1220975 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c @@ -471,10 +471,10 @@ static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_reg * denormal_to_double - Given denormalized float number, * store double float * - * @fpu: Pointer to sh_fpu_hard structure + * @fpu: Pointer to sh_fpu_soft structure * @n: Index to FP register */ -static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n) +static void denormal_to_double(struct sh_fpu_soft_struct *fpu, int n) { unsigned long du, dl; unsigned long x = fpu->fpul; @@ -552,11 +552,11 @@ static int ieee_fpe_handler(struct pt_regs *regs) if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ struct task_struct *tsk = current; - if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) { + if ((tsk->thread.xstate->softfpu.fpscr & (1 << 17))) { /* FPU error */ - denormal_to_double (&tsk->thread.fpu.hard, + denormal_to_double (&tsk->thread.xstate->softfpu, (finsn >> 8) & 0xf); - tsk->thread.fpu.hard.fpscr &= + tsk->thread.xstate->softfpu.fpscr &= ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); task_thread_info(tsk)->status |= TS_USEDFPU; } else { @@ -617,7 +617,7 @@ static void fpu_init(struct sh_fpu_soft_struct *fpu) int do_fpu_inst(unsigned short inst, struct pt_regs *regs) { struct task_struct *tsk = current; - struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft); + struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu); if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { /* initialize once. */ -- GitLab From 6430a5987f8bb9a7c5187b343956aa8ef404d571 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 13 Jan 2010 12:59:24 +0900 Subject: [PATCH 0609/3892] sh: Don't perform an icbi on a P2 address The legacy P2 area may not always be mapped (for example when using PMB). So perform an icbi on an address that we know will always be mapped. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/include/asm/system.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index c15415b4b169..b74d2532cc27 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -32,7 +32,7 @@ #define mb() __asm__ __volatile__ ("synco": : :"memory") #define rmb() mb() #define wmb() __asm__ __volatile__ ("synco": : :"memory") -#define ctrl_barrier() __icbi(0xa8000000) +#define ctrl_barrier() __icbi(PAGE_OFFSET) #define read_barrier_depends() do { } while(0) #else #define mb() __asm__ __volatile__ ("": : :"memory") -- GitLab From c7b16efb7d0c7fce218b2cdafa2432c5fbf57314 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 13:29:19 +0900 Subject: [PATCH 0610/3892] sh: Add support for LZO-compressed kernels. Plugs in LZO along with the others. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 1 + arch/sh/Makefile | 5 +++-- arch/sh/boot/Makefile | 21 +++++++++++++++------ arch/sh/boot/compressed/Makefile | 3 +++ arch/sh/boot/compressed/misc.c | 4 ++++ 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 4eaf3401a15e..5ac0115c9e20 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -22,6 +22,7 @@ config SUPERH select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_LZMA + select HAVE_KERNEL_LZO select HAVE_SYSCALL_TRACEPOINTS select RTC_LIB select GENERIC_ATOMIC64 diff --git a/arch/sh/Makefile b/arch/sh/Makefile index db91925c79d1..fd57676115e6 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -203,8 +203,8 @@ endif libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) -BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec uImage.bin \ - zImage vmlinux.srec romImage +BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.lzo \ + uImage.srec uImage.bin zImage vmlinux.srec romImage PHONY += $(BOOT_TARGETS) all: $(KBUILD_IMAGE) @@ -231,4 +231,5 @@ define archhelp @echo '* uImage.gz - Kernel-only image for U-Boot (gzip)' @echo ' uImage.bz2 - Kernel-only image for U-Boot (bzip2)' @echo ' uImage.lzma - Kernel-only image for U-Boot (lzma)' + @echo ' uImage.lzo - Kernel-only image for U-Boot (lzo)' endef diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile index cb8cf5572e79..743ce0c8d98d 100644 --- a/arch/sh/boot/Makefile +++ b/arch/sh/boot/Makefile @@ -21,12 +21,15 @@ CONFIG_ZERO_PAGE_OFFSET ?= 0x00001000 CONFIG_ENTRY_OFFSET ?= 0x00001000 suffix-y := bin -suffix-$(CONFIG_KERNEL_GZIP) := gz -suffix-$(CONFIG_KERNEL_BZIP2) := bz2 -suffix-$(CONFIG_KERNEL_LZMA) := lzma - -targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz uImage.bz2 uImage.lzma uImage.bin -extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma +suffix-$(CONFIG_KERNEL_GZIP) := gz +suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZMA) := lzma +suffix-$(CONFIG_KERNEL_LZO) := lzo + +targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \ + uImage.bz2 uImage.lzma uImage.lzo uImage.bin +extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ + vmlinux.bin.lzo subdir- := compressed romimage $(obj)/zImage: $(obj)/compressed/vmlinux FORCE @@ -80,6 +83,9 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE $(call if_changed,lzma) +$(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.bin FORCE + $(call if_changed,lzo) + $(obj)/uImage.bz2: $(obj)/vmlinux.bin.bz2 $(call if_changed,uimage,bzip2) @@ -89,6 +95,9 @@ $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma $(call if_changed,uimage,lzma) +$(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo + $(call if_changed,uimage,lzo) + $(obj)/uImage.bin: $(obj)/vmlinux.bin $(call if_changed,uimage,none) diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index 6182eca5180a..6b95a2a48267 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -6,6 +6,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz \ vmlinux.bin.bz2 vmlinux.bin.lzma \ + vmlinux.bin.lzo \ head_$(BITS).o misc.o piggy.o OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o @@ -47,6 +48,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE $(call if_changed,bzip2) $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzma) +$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE + $(call if_changed,lzo) OBJCOPYFLAGS += -R .empty_zero_page diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index b51b1fc4baae..4b319e9e4f88 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c @@ -62,6 +62,10 @@ static unsigned long free_mem_end_ptr; #include "../../../../lib/decompress_unlzma.c" #endif +#ifdef CONFIG_KERNEL_LZO +#include "../../../../lib/decompress_unlzo.c" +#endif + #ifdef CONFIG_SH_STANDARD_BIOS size_t strlen(const char *s) { -- GitLab From 59c33fa7791e9948ba467c2b83e307a0d087ab49 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Jan 2010 16:21:09 -0800 Subject: [PATCH 0611/3892] x86-32: clean up rwsem inline asm statements This makes gcc use the right register names and instruction operand sizes automatically for the rwsem inline asm statements. So instead of using "(%%eax)" to specify the memory address that is the semaphore, we use "(%1)" or similar. And instead of forcing the operation to always be 32-bit, we use "%z0", taking the size from the actual semaphore data structure itself. This doesn't actually matter on x86-32, but if we want to use the same inline asm for x86-64, we'll need to have the compiler generate the proper 64-bit names for the registers (%rax instead of %eax), and if we want to use a 64-bit counter too (in order to avoid the 15-bit limit on the write counter that limits concurrent users to 32767 threads), we'll need to be able to generate instructions with "q" accesses rather than "l". Since this header currently isn't enabled on x86-64, none of that matters, but we do want to use the xadd version of the semaphores rather than have to take spinlocks to do a rwsem. The mm->mmap_sem can be heavily contended when you have lots of threads all taking page faults, and the fallback rwsem code that uses a spinlock performs abysmally badly in that case. [ hpa: modified the patch to skip size suffixes entirely when they are redundant due to register operands. ] Signed-off-by: Linus Torvalds LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/rwsem.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index ca7517d33776..413620024768 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -105,7 +105,7 @@ do { \ static inline void __down_read(struct rw_semaphore *sem) { asm volatile("# beginning down_read\n\t" - LOCK_PREFIX " incl (%%eax)\n\t" + LOCK_PREFIX " inc%z0 (%1)\n\t" /* adds 0x00000001, returns the old value */ " jns 1f\n" " call call_rwsem_down_read_failed\n" @@ -123,12 +123,12 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) { __s32 result, tmp; asm volatile("# beginning __down_read_trylock\n\t" - " movl %0,%1\n\t" + " mov %0,%1\n\t" "1:\n\t" - " movl %1,%2\n\t" - " addl %3,%2\n\t" + " mov %1,%2\n\t" + " add %3,%2\n\t" " jle 2f\n\t" - LOCK_PREFIX " cmpxchgl %2,%0\n\t" + LOCK_PREFIX " cmpxchg %2,%0\n\t" " jnz 1b\n\t" "2:\n\t" "# ending __down_read_trylock\n\t" @@ -147,9 +147,9 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) tmp = RWSEM_ACTIVE_WRITE_BIAS; asm volatile("# beginning down_write\n\t" - LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" + LOCK_PREFIX " xadd %1,(%2)\n\t" /* subtract 0x0000ffff, returns the old value */ - " testl %%edx,%%edx\n\t" + " test %1,%1\n\t" /* was the count 0 before? */ " jz 1f\n" " call call_rwsem_down_write_failed\n" @@ -185,7 +185,7 @@ static inline void __up_read(struct rw_semaphore *sem) { __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; asm volatile("# beginning __up_read\n\t" - LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" + LOCK_PREFIX " xadd %1,(%2)\n\t" /* subtracts 1, returns the old value */ " jns 1f\n\t" " call call_rwsem_wake\n" @@ -201,18 +201,18 @@ static inline void __up_read(struct rw_semaphore *sem) */ static inline void __up_write(struct rw_semaphore *sem) { + unsigned long tmp; asm volatile("# beginning __up_write\n\t" - " movl %2,%%edx\n\t" - LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" + LOCK_PREFIX " xadd %1,(%2)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */ " jz 1f\n" " call call_rwsem_wake\n" "1:\n\t" "# ending __up_write\n" - : "+m" (sem->count) - : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS) - : "memory", "cc", "edx"); + : "+m" (sem->count), "=d" (tmp) + : "a" (sem), "1" (-RWSEM_ACTIVE_WRITE_BIAS) + : "memory", "cc"); } /* @@ -221,7 +221,7 @@ static inline void __up_write(struct rw_semaphore *sem) static inline void __downgrade_write(struct rw_semaphore *sem) { asm volatile("# beginning __downgrade_write\n\t" - LOCK_PREFIX " addl %2,(%%eax)\n\t" + LOCK_PREFIX " add%z0 %2,(%1)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ " jns 1f\n\t" " call call_rwsem_downgrade_wake\n" @@ -237,7 +237,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem) */ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) { - asm volatile(LOCK_PREFIX "addl %1,%0" + asm volatile(LOCK_PREFIX "add%z0 %1,%0" : "+m" (sem->count) : "ir" (delta)); } -- GitLab From ed69c6a8eef679f2783848ed624897a937a434ac Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 13 Jan 2010 08:12:31 +0100 Subject: [PATCH 0612/3892] ALSA: pcm_lib - fix wrong delta print for jiffies check The previous jiffies delta was 0 in all cases. Use hw_ptr variable to store and print original value. Signed-off-by: Jaroslav Kysela --- sound/core/pcm_lib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 0ee7e807c964..5417f7dce834 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -394,6 +394,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, + HZ/100); /* move new_hw_ptr according jiffies not pos variable */ new_hw_ptr = old_hw_ptr; + hw_base = delta; /* use loop to avoid checks for delta overflows */ /* the delta value is small or zero in most cases */ while (delta > 0) { @@ -403,8 +404,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta--; } /* align hw_base to buffer_size */ - hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); - delta = 0; hw_ptr_error(substream, "hw_ptr skipping! %s" "(pos=%ld, delta=%ld, period=%ld, " @@ -412,9 +411,12 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, in_interrupt ? "[Q] " : "", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, - ((hdelta * HZ) / runtime->rate), delta, + ((hdelta * HZ) / runtime->rate), hw_base, (unsigned long)old_hw_ptr, (unsigned long)new_hw_ptr); + /* reset values to proper state */ + delta = 0; + hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { -- GitLab From eca50f14b88315bd31183a17c89e53534f2ed2fa Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 16:28:47 +0900 Subject: [PATCH 0613/3892] sh: Add a vmlinux.bin target. This makes vmlinux.bin generation an explicit make target, as opposed to just a dependency for some of the other targets. Signed-off-by: Paul Mundt --- arch/sh/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/sh/Makefile b/arch/sh/Makefile index fd57676115e6..f7d5f42b00a7 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -204,7 +204,8 @@ libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.lzo \ - uImage.srec uImage.bin zImage vmlinux.srec romImage + uImage.srec uImage.bin zImage vmlinux.bin vmlinux.srec \ + romImage PHONY += $(BOOT_TARGETS) all: $(KBUILD_IMAGE) @@ -225,6 +226,7 @@ define archhelp @echo ' zImage - Compressed kernel image' @echo ' romImage - Compressed ROM image, if supported' @echo ' vmlinux.srec - Create an ELF S-record' + @echo ' vmlinux.bin - Create an uncompressed binary image' @echo '* uImage - Alias to bootable U-Boot image' @echo ' uImage.srec - Create an S-record for U-Boot' @echo ' uImage.bin - Kernel-only image for U-Boot (bin)' -- GitLab From d2f2fcd2541bae004db7f4798ffd9d2cb75ae817 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Tue, 12 Jan 2010 17:03:35 -0800 Subject: [PATCH 0614/3892] ALSA: hda_intel: ALSA HD Audio patch for Intel Cougar Point DeviceIDs This patch adds the Intel Cougar Point (PCH) HD Audio Controller DeviceIDs. Signed-off-by: Seth Heasley Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1f516e668d88..6d331c4cf185 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -125,6 +125,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH9}," "{Intel, ICH10}," "{Intel, PCH}," + "{Intel, CPT}," "{Intel, SCH}," "{ATI, SB450}," "{ATI, SB600}," @@ -2677,6 +2678,8 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, /* PCH */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, + /* CPT */ + { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_ICH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, /* ATI SB 450/600 */ -- GitLab From 7f33306ee57bce9c79825e89c457a91025aa5aad Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 13 Jan 2010 16:35:58 +0900 Subject: [PATCH 0615/3892] sh: PVR detection for 2nd cut SH7786. The mass produced cuts use an updated PVR value, add them to the list. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4/probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index d36f0c45f55f..75189c4691da 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -124,6 +124,7 @@ int __init detect_cpu_and_cache_system(void) boot_cpu_data.type = CPU_SH7785; break; case 0x4004: + case 0x4005: boot_cpu_data.type = CPU_SH7786; boot_cpu_data.flags |= CPU_HAS_PTEAEX | CPU_HAS_L2_CACHE; break; -- GitLab From 2ca49b2fcf5813571663c3c4c894b78148c43690 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 4 Jan 2010 09:47:35 -0500 Subject: [PATCH 0616/3892] x86: Macroise x86 cache descriptors Use a macro to define the cache sizes when cachesize > 1 MB. This is less typing, and less prone to introducing bugs like we saw in e02e0e1a130b9ca37c5186d38ad4b3aaf58bb149, and means we don't have to do maths when adding new non-power-of-2 updates like those seen recently. Signed-off-by: Dave Jones LKML-Reference: <20100104144735.GA18390@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/intel_cacheinfo.c | 84 ++++++++++++++------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index fc6c8ef92dcc..c2b722d5a722 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -31,6 +31,8 @@ struct _cache_table { short size; }; +#define MB(x) ((x) * 1024) + /* All the cache descriptor types we care about (no TLB or trace cache entries) */ @@ -44,9 +46,9 @@ static const struct _cache_table __cpuinitconst cache_table[] = { 0x0d, LVL_1_DATA, 16 }, /* 4-way set assoc, 64 byte line size */ { 0x21, LVL_2, 256 }, /* 8-way set assoc, 64 byte line size */ { 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */ - { 0x23, LVL_3, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x25, LVL_3, 2048 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x29, LVL_3, 4096 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x23, LVL_3, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x25, LVL_3, MB(2) }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x29, LVL_3, MB(4) }, /* 8-way set assoc, sectored cache, 64 byte line size */ { 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */ { 0x30, LVL_1_INST, 32 }, /* 8-way set assoc, 64 byte line size */ { 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */ @@ -59,16 +61,16 @@ static const struct _cache_table __cpuinitconst cache_table[] = { 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */ { 0x42, LVL_2, 256 }, /* 4-way set assoc, 32 byte line size */ { 0x43, LVL_2, 512 }, /* 4-way set assoc, 32 byte line size */ - { 0x44, LVL_2, 1024 }, /* 4-way set assoc, 32 byte line size */ - { 0x45, LVL_2, 2048 }, /* 4-way set assoc, 32 byte line size */ - { 0x46, LVL_3, 4096 }, /* 4-way set assoc, 64 byte line size */ - { 0x47, LVL_3, 8192 }, /* 8-way set assoc, 64 byte line size */ - { 0x49, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */ - { 0x4a, LVL_3, 6144 }, /* 12-way set assoc, 64 byte line size */ - { 0x4b, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */ - { 0x4c, LVL_3, 12288 }, /* 12-way set assoc, 64 byte line size */ - { 0x4d, LVL_3, 16384 }, /* 16-way set assoc, 64 byte line size */ - { 0x4e, LVL_2, 6144 }, /* 24-way set assoc, 64 byte line size */ + { 0x44, LVL_2, MB(1) }, /* 4-way set assoc, 32 byte line size */ + { 0x45, LVL_2, MB(2) }, /* 4-way set assoc, 32 byte line size */ + { 0x46, LVL_3, MB(4) }, /* 4-way set assoc, 64 byte line size */ + { 0x47, LVL_3, MB(8) }, /* 8-way set assoc, 64 byte line size */ + { 0x49, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */ + { 0x4a, LVL_3, MB(6) }, /* 12-way set assoc, 64 byte line size */ + { 0x4b, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */ + { 0x4c, LVL_3, MB(12) }, /* 12-way set assoc, 64 byte line size */ + { 0x4d, LVL_3, MB(16) }, /* 16-way set assoc, 64 byte line size */ + { 0x4e, LVL_2, MB(6) }, /* 24-way set assoc, 64 byte line size */ { 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */ { 0x66, LVL_1_DATA, 8 }, /* 4-way set assoc, sectored cache, 64 byte line size */ { 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */ @@ -77,34 +79,34 @@ static const struct _cache_table __cpuinitconst cache_table[] = { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */ { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */ { 0x73, LVL_TRACE, 64 }, /* 8-way set assoc */ - { 0x78, LVL_2, 1024 }, /* 4-way set assoc, 64 byte line size */ - { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x7c, LVL_2, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */ - { 0x7d, LVL_2, 2048 }, /* 8-way set assoc, 64 byte line size */ - { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */ - { 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */ - { 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */ - { 0x84, LVL_2, 1024 }, /* 8-way set assoc, 32 byte line size */ - { 0x85, LVL_2, 2048 }, /* 8-way set assoc, 32 byte line size */ - { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */ - { 0x87, LVL_2, 1024 }, /* 8-way set assoc, 64 byte line size */ - { 0xd0, LVL_3, 512 }, /* 4-way set assoc, 64 byte line size */ - { 0xd1, LVL_3, 1024 }, /* 4-way set assoc, 64 byte line size */ - { 0xd2, LVL_3, 2048 }, /* 4-way set assoc, 64 byte line size */ - { 0xd6, LVL_3, 1024 }, /* 8-way set assoc, 64 byte line size */ - { 0xd7, LVL_3, 2048 }, /* 8-way set assoc, 64 byte line size */ - { 0xd8, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ - { 0xdc, LVL_3, 2048 }, /* 12-way set assoc, 64 byte line size */ - { 0xdd, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ - { 0xde, LVL_3, 8192 }, /* 12-way set assoc, 64 byte line size */ - { 0xe2, LVL_3, 2048 }, /* 16-way set assoc, 64 byte line size */ - { 0xe3, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */ - { 0xe4, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */ - { 0xea, LVL_3, 12288 }, /* 24-way set assoc, 64 byte line size */ - { 0xeb, LVL_3, 18432 }, /* 24-way set assoc, 64 byte line size */ - { 0xec, LVL_3, 24576 }, /* 24-way set assoc, 64 byte line size */ + { 0x78, LVL_2, MB(1) }, /* 4-way set assoc, 64 byte line size */ + { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7c, LVL_2, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */ + { 0x7d, LVL_2, MB(2) }, /* 8-way set assoc, 64 byte line size */ + { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */ + { 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */ + { 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */ + { 0x84, LVL_2, MB(1) }, /* 8-way set assoc, 32 byte line size */ + { 0x85, LVL_2, MB(2) }, /* 8-way set assoc, 32 byte line size */ + { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */ + { 0x87, LVL_2, MB(1) }, /* 8-way set assoc, 64 byte line size */ + { 0xd0, LVL_3, 512 }, /* 4-way set assoc, 64 byte line size */ + { 0xd1, LVL_3, MB(1) }, /* 4-way set assoc, 64 byte line size */ + { 0xd2, LVL_3, MB(2) }, /* 4-way set assoc, 64 byte line size */ + { 0xd6, LVL_3, MB(1) }, /* 8-way set assoc, 64 byte line size */ + { 0xd7, LVL_3, MB(2) }, /* 8-way set assoc, 64 byte line size */ + { 0xd8, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */ + { 0xdc, LVL_3, MB(2) }, /* 12-way set assoc, 64 byte line size */ + { 0xdd, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */ + { 0xde, LVL_3, MB(8) }, /* 12-way set assoc, 64 byte line size */ + { 0xe2, LVL_3, MB(2) }, /* 16-way set assoc, 64 byte line size */ + { 0xe3, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */ + { 0xe4, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */ + { 0xea, LVL_3, MB(12) }, /* 24-way set assoc, 64 byte line size */ + { 0xeb, LVL_3, MB(18) }, /* 24-way set assoc, 64 byte line size */ + { 0xec, LVL_3, MB(24) }, /* 24-way set assoc, 64 byte line size */ { 0x00, 0, 0} }; -- GitLab From f96e9232e04856c781d4f71923a46dd3f7b429fa Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:00 -0800 Subject: [PATCH 0617/3892] rcu: Adjust force_quiescent_state() locking, step 1 This causes rnp->lock to be held on entry to force_quiescent_state()'s switch statement. This is a first step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465501455-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 53ae9598f798..eae331da6bee 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1204,7 +1204,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) } if (relaxed && (long)(rsp->jiffies_force_qs - jiffies) >= 0) - goto unlock_ret; /* no emergency and done recently. */ + goto unlock_fqs_ret; /* no emergency and done recently. */ rsp->n_force_qs++; spin_lock(&rnp->lock); lastcomp = rsp->gpnum - 1; @@ -1213,31 +1213,32 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) if(!rcu_gp_in_progress(rsp)) { rsp->n_force_qs_ngp++; spin_unlock(&rnp->lock); - goto unlock_ret; /* no GP in progress, time updated. */ + goto unlock_fqs_ret; /* no GP in progress, time updated. */ } - spin_unlock(&rnp->lock); switch (signaled) { case RCU_GP_IDLE: case RCU_GP_INIT: + spin_unlock(&rnp->lock); break; /* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK: + spin_unlock(&rnp->lock); if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ if (rcu_process_dyntick(rsp, lastcomp, dyntick_save_progress_counter)) - goto unlock_ret; + goto unlock_fqs_ret; + spin_lock(&rnp->lock); /* fall into next case. */ case RCU_SAVE_COMPLETED: /* Update state, record completion counter. */ forcenow = 0; - spin_lock(&rnp->lock); if (lastcomp + 1 == rsp->gpnum && lastcomp == rsp->completed && rsp->signaled == signaled) { @@ -1245,23 +1246,31 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled == RCU_SAVE_COMPLETED; } - spin_unlock(&rnp->lock); - if (!forcenow) + if (!forcenow) { + spin_unlock(&rnp->lock); break; + } /* fall into next case. */ case RCU_FORCE_QS: /* Check dyntick-idle state, send IPI to laggarts. */ + spin_unlock(&rnp->lock); if (rcu_process_dyntick(rsp, rsp->completed_fqs, rcu_implicit_dynticks_qs)) - goto unlock_ret; + goto unlock_fqs_ret; /* Leave state in case more forcing is required. */ break; + + default: + + spin_unlock(&rnp->lock); + WARN_ON_ONCE(1); + break; } -unlock_ret: +unlock_fqs_ret: spin_unlock_irqrestore(&rsp->fqslock, flags); } -- GitLab From 559569acf94f538b56bd6eead80b439d6a78cdff Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:01 -0800 Subject: [PATCH 0618/3892] rcu: Adjust force_quiescent_state() locking, step 2 This patch releases rnp->lock after the end of force_quiescent_state()'s switch statement. This is a second step towards prohibiting starting grace periods while force_quiescent_state() is executing, which will reduce the number and complexity of races that force_quiescent_state() is involved in. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465501994-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index eae331da6bee..d42ad30c4d70 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1219,7 +1219,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) case RCU_GP_IDLE: case RCU_GP_INIT: - spin_unlock(&rnp->lock); break; /* grace period idle or initializing, ignore. */ case RCU_SAVE_DYNTICK: @@ -1246,10 +1245,8 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->completed_fqs = lastcomp; forcenow = signaled == RCU_SAVE_COMPLETED; } - if (!forcenow) { - spin_unlock(&rnp->lock); + if (!forcenow) break; - } /* fall into next case. */ case RCU_FORCE_QS: @@ -1262,14 +1259,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Leave state in case more forcing is required. */ - break; - - default: - - spin_unlock(&rnp->lock); - WARN_ON_ONCE(1); + spin_lock(&rnp->lock); break; } + spin_unlock(&rnp->lock); unlock_fqs_ret: spin_unlock_irqrestore(&rsp->fqslock, flags); } -- GitLab From 07079d5357a4d53c2b13126c4a38fb40e6e04966 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:02 -0800 Subject: [PATCH 0619/3892] rcu: Prohibit starting new grace periods while forcing quiescent states Reduce the number and variety of race conditions by prohibiting the start of a new grace period while force_quiescent_state() is active. A new fqs_active flag in the rcu_state structure is used to trace whether or not force_quiescent_state() is active, and this new flag is tested by rcu_start_gp(). If the CPU that closed out the last grace period needs another grace period, this new grace period may be delayed up to one scheduling-clock tick, but it will eventually get started. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <126264655052-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 31 +++++++++++++++++-------------- kernel/rcutree.h | 2 ++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d42ad30c4d70..41688ff60e07 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -659,7 +659,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) struct rcu_data *rdp = rsp->rda[smp_processor_id()]; struct rcu_node *rnp = rcu_get_root(rsp); - if (!cpu_needs_another_gp(rsp, rdp)) { + if (!cpu_needs_another_gp(rsp, rdp) || rsp->fqs_active) { if (rnp->completed == rsp->completed) { spin_unlock_irqrestore(&rnp->lock, flags); return; @@ -1195,6 +1195,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) struct rcu_node *rnp = rcu_get_root(rsp); u8 signaled; u8 forcenow; + u8 gpdone; if (!rcu_gp_in_progress(rsp)) return; /* No grace period in progress, nothing to force. */ @@ -1206,15 +1207,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) (long)(rsp->jiffies_force_qs - jiffies) >= 0) goto unlock_fqs_ret; /* no emergency and done recently. */ rsp->n_force_qs++; - spin_lock(&rnp->lock); + spin_lock(&rnp->lock); /* irqs already disabled */ lastcomp = rsp->gpnum - 1; signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; if(!rcu_gp_in_progress(rsp)) { rsp->n_force_qs_ngp++; - spin_unlock(&rnp->lock); + spin_unlock(&rnp->lock); /* irqs remain disabled */ goto unlock_fqs_ret; /* no GP in progress, time updated. */ } + rsp->fqs_active = 1; switch (signaled) { case RCU_GP_IDLE: case RCU_GP_INIT: @@ -1223,15 +1225,16 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) case RCU_SAVE_DYNTICK: - spin_unlock(&rnp->lock); + spin_unlock(&rnp->lock); /* irqs remain disabled */ if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - if (rcu_process_dyntick(rsp, lastcomp, - dyntick_save_progress_counter)) - goto unlock_fqs_ret; - spin_lock(&rnp->lock); + gpdone = rcu_process_dyntick(rsp, lastcomp, + dyntick_save_progress_counter); + spin_lock(&rnp->lock); /* irqs already disabled */ + if (gpdone) + break; /* fall into next case. */ case RCU_SAVE_COMPLETED: @@ -1252,17 +1255,17 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) case RCU_FORCE_QS: /* Check dyntick-idle state, send IPI to laggarts. */ - spin_unlock(&rnp->lock); - if (rcu_process_dyntick(rsp, rsp->completed_fqs, - rcu_implicit_dynticks_qs)) - goto unlock_fqs_ret; + spin_unlock(&rnp->lock); /* irqs remain disabled */ + gpdone = rcu_process_dyntick(rsp, rsp->completed_fqs, + rcu_implicit_dynticks_qs); /* Leave state in case more forcing is required. */ - spin_lock(&rnp->lock); + spin_lock(&rnp->lock); /* irqs already disabled */ break; } - spin_unlock(&rnp->lock); + rsp->fqs_active = 0; + spin_unlock(&rnp->lock); /* irqs remain disabled */ unlock_fqs_ret: spin_unlock_irqrestore(&rsp->fqslock, flags); } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index d2a0046f63b2..dc386a7c634f 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -277,6 +277,8 @@ struct rcu_state { u8 signaled ____cacheline_internodealigned_in_smp; /* Force QS state. */ + u8 fqs_active; /* force_quiescent_state() */ + /* is running. */ long gpnum; /* Current gp number. */ long completed; /* # of last completed gp. */ -- GitLab From f3a8b5c6aa543bd87764418d63632eb65b80e2f6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:03 -0800 Subject: [PATCH 0620/3892] rcu: Eliminate local variable signaled from force_quiescent_state() Because the root rcu_node lock is held across entry to the switch statement in force_quiescent_state(), it is no longer necessary to snapshot rsp->signaled to a local variable. Eliminate both the snapshotting and the local variable. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1262646550602-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 41688ff60e07..1d8cfb1711fd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1193,7 +1193,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) unsigned long flags; long lastcomp; struct rcu_node *rnp = rcu_get_root(rsp); - u8 signaled; u8 forcenow; u8 gpdone; @@ -1209,7 +1208,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) rsp->n_force_qs++; spin_lock(&rnp->lock); /* irqs already disabled */ lastcomp = rsp->gpnum - 1; - signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; if(!rcu_gp_in_progress(rsp)) { rsp->n_force_qs_ngp++; @@ -1217,7 +1215,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret; /* no GP in progress, time updated. */ } rsp->fqs_active = 1; - switch (signaled) { + switch (rsp->signaled) { case RCU_GP_IDLE: case RCU_GP_INIT: @@ -1242,11 +1240,10 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Update state, record completion counter. */ forcenow = 0; if (lastcomp + 1 == rsp->gpnum && - lastcomp == rsp->completed && - rsp->signaled == signaled) { + lastcomp == rsp->completed) { + forcenow = rsp->signaled == RCU_SAVE_COMPLETED; rsp->signaled = RCU_FORCE_QS; rsp->completed_fqs = lastcomp; - forcenow = signaled == RCU_SAVE_COMPLETED; } if (!forcenow) break; -- GitLab From 39c0bbfc07c6e28db7346d0e11106f2d045d3035 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:04 -0800 Subject: [PATCH 0621/3892] rcu: Eliminate local variable lastcomp from force_quiescent_state() Because rsp->fqs_active is set to 1 across force_quiescent_state()'s switch statement, rcu_start_gp() will refrain from starting a new grace period during this time. Therefore, rsp->gpnum is constant, and can be propagated to all uses of lastcomp, eliminating this local variable. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465502985-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 10 +++------- kernel/rcutree.h | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 1d8cfb1711fd..62b64332effb 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1191,7 +1191,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, static void force_quiescent_state(struct rcu_state *rsp, int relaxed) { unsigned long flags; - long lastcomp; struct rcu_node *rnp = rcu_get_root(rsp); u8 forcenow; u8 gpdone; @@ -1207,7 +1206,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_fqs_ret; /* no emergency and done recently. */ rsp->n_force_qs++; spin_lock(&rnp->lock); /* irqs already disabled */ - lastcomp = rsp->gpnum - 1; rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; if(!rcu_gp_in_progress(rsp)) { rsp->n_force_qs_ngp++; @@ -1228,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone = rcu_process_dyntick(rsp, lastcomp, + gpdone = rcu_process_dyntick(rsp, rsp->gpnum - 1, dyntick_save_progress_counter); spin_lock(&rnp->lock); /* irqs already disabled */ if (gpdone) @@ -1239,11 +1237,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Update state, record completion counter. */ forcenow = 0; - if (lastcomp + 1 == rsp->gpnum && - lastcomp == rsp->completed) { + if (rsp->gpnum - 1 == rsp->completed) { forcenow = rsp->signaled == RCU_SAVE_COMPLETED; rsp->signaled = RCU_FORCE_QS; - rsp->completed_fqs = lastcomp; } if (!forcenow) break; @@ -1253,7 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock(&rnp->lock); /* irqs remain disabled */ - gpdone = rcu_process_dyntick(rsp, rsp->completed_fqs, + gpdone = rcu_process_dyntick(rsp, rsp->gpnum - 1, rcu_implicit_dynticks_qs); /* Leave state in case more forcing is required. */ diff --git a/kernel/rcutree.h b/kernel/rcutree.h index dc386a7c634f..534856121b06 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -296,8 +296,6 @@ struct rcu_state { long orphan_qlen; /* Number of orphaned cbs. */ spinlock_t fqslock; /* Only one task forcing */ /* quiescent states. */ - long completed_fqs; /* Value of completed @ snap. */ - /* Protected by fqslock. */ unsigned long jiffies_force_qs; /* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs; /* Number of calls to */ -- GitLab From eb1ba45f1e7f6e626fefc063b340c7cbec9bd8c7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:05 -0800 Subject: [PATCH 0622/3892] rcu: Eliminate second argument of rcu_process_dyntick() At this point, the second argument to all calls to rcu_process_dyntick() is a function of the same field of the structure passed in as the first argument, namely, rsp->gpnum-1. So propagate rsp->gpnum-1 to all uses of the second argument within rcu_process_dyntick() and then eliminate the second argument. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465503786-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 62b64332effb..c7d00700fc4e 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1147,7 +1147,7 @@ void rcu_check_callbacks(int cpu, int user) * Returns 1 if the current grace period ends while scanning (possibly * because we made it end). */ -static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, +static int rcu_process_dyntick(struct rcu_state *rsp, int (*f)(struct rcu_data *)) { unsigned long bit; @@ -1159,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, rcu_for_each_leaf_node(rsp, rnp) { mask = 0; spin_lock_irqsave(&rnp->lock, flags); - if (rnp->completed != lastcomp) { + if (rnp->completed != rsp->gpnum - 1) { spin_unlock_irqrestore(&rnp->lock, flags); return 1; } @@ -1173,7 +1173,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu])) mask |= bit; } - if (mask != 0 && rnp->completed == lastcomp) { + if (mask != 0 && rnp->completed == rsp->gpnum - 1) { /* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp(mask, rsp, rnp, flags); @@ -1226,7 +1226,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone = rcu_process_dyntick(rsp, rsp->gpnum - 1, + gpdone = rcu_process_dyntick(rsp, dyntick_save_progress_counter); spin_lock(&rnp->lock); /* irqs already disabled */ if (gpdone) @@ -1249,8 +1249,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock(&rnp->lock); /* irqs remain disabled */ - gpdone = rcu_process_dyntick(rsp, rsp->gpnum - 1, - rcu_implicit_dynticks_qs); + gpdone = rcu_process_dyntick(rsp, rcu_implicit_dynticks_qs); /* Leave state in case more forcing is required. */ -- GitLab From 0f10dc826646134dce3e5751512b87d30f3903e4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:06 -0800 Subject: [PATCH 0623/3892] rcu: Eliminate rcu_process_dyntick() return value Because a new grace period cannot start while we are executing within the force_quiescent_state() function's switch statement, if any test within that switch statement or within any function called from that switch statement shows that the current grace period has ended, we can safely re-do that test any time before we leave the switch statement. This means that we no longer need a return value from rcu_process_dyntick(), as we can simply invoke rcu_gp_in_progress() to check whether the old grace period has finished -- there is no longer any need to worry about whether or not a new grace period has been started. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465501857-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index c7d00700fc4e..e4971192fa9c 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1144,11 +1144,9 @@ void rcu_check_callbacks(int cpu, int user) /* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. - * Returns 1 if the current grace period ends while scanning (possibly - * because we made it end). */ -static int rcu_process_dyntick(struct rcu_state *rsp, - int (*f)(struct rcu_data *)) +static void rcu_process_dyntick(struct rcu_state *rsp, + int (*f)(struct rcu_data *)) { unsigned long bit; int cpu; @@ -1161,7 +1159,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, spin_lock_irqsave(&rnp->lock, flags); if (rnp->completed != rsp->gpnum - 1) { spin_unlock_irqrestore(&rnp->lock, flags); - return 1; + return; } if (rnp->qsmask == 0) { spin_unlock_irqrestore(&rnp->lock, flags); @@ -1181,7 +1179,6 @@ static int rcu_process_dyntick(struct rcu_state *rsp, } spin_unlock_irqrestore(&rnp->lock, flags); } - return 0; } /* @@ -1193,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) unsigned long flags; struct rcu_node *rnp = rcu_get_root(rsp); u8 forcenow; - u8 gpdone; if (!rcu_gp_in_progress(rsp)) return; /* No grace period in progress, nothing to force. */ @@ -1226,10 +1222,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - gpdone = rcu_process_dyntick(rsp, - dyntick_save_progress_counter); + rcu_process_dyntick(rsp, dyntick_save_progress_counter); spin_lock(&rnp->lock); /* irqs already disabled */ - if (gpdone) + if (!rcu_gp_in_progress(rsp)) break; /* fall into next case. */ @@ -1249,7 +1244,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock(&rnp->lock); /* irqs remain disabled */ - gpdone = rcu_process_dyntick(rsp, rcu_implicit_dynticks_qs); + rcu_process_dyntick(rsp, rcu_implicit_dynticks_qs); /* Leave state in case more forcing is required. */ -- GitLab From ee47eb9f4da6f44af965d6d049e77ee8c8a4b822 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:07 -0800 Subject: [PATCH 0624/3892] rcu: Remove leg of force_quiescent_state() switch statement The comparisons of rsp->gpnum nad rsp->completed in rcu_process_dyntick() and force_quiescent_state() can be replaced by the much more clear rcu_gp_in_progress() predicate function. After doing this, it becomes clear that the RCU_SAVE_COMPLETED leg of the force_quiescent_state() function's switch statement is almost completely a no-op. A small change to the RCU_SAVE_DYNTICK leg renders it a complete no-op, after which it can be removed. Doing so also eliminates the forcenow local variable from force_quiescent_state(). Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465501781-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 22 +++++----------------- kernel/rcutree.h | 5 ++--- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index e4971192fa9c..6268f37adfc4 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1144,6 +1144,7 @@ void rcu_check_callbacks(int cpu, int user) /* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. + * The caller must have suppressed start of new grace periods. */ static void rcu_process_dyntick(struct rcu_state *rsp, int (*f)(struct rcu_data *)) @@ -1157,7 +1158,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp, rcu_for_each_leaf_node(rsp, rnp) { mask = 0; spin_lock_irqsave(&rnp->lock, flags); - if (rnp->completed != rsp->gpnum - 1) { + if (!rcu_gp_in_progress(rsp)) { spin_unlock_irqrestore(&rnp->lock, flags); return; } @@ -1171,7 +1172,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp, if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu])) mask |= bit; } - if (mask != 0 && rnp->completed == rsp->gpnum - 1) { + if (mask != 0 && rcu_gp_in_progress(rsp)) { /* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp(mask, rsp, rnp, flags); @@ -1189,7 +1190,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) { unsigned long flags; struct rcu_node *rnp = rcu_get_root(rsp); - u8 forcenow; if (!rcu_gp_in_progress(rsp)) return; /* No grace period in progress, nothing to force. */ @@ -1224,21 +1224,9 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Record dyntick-idle state. */ rcu_process_dyntick(rsp, dyntick_save_progress_counter); spin_lock(&rnp->lock); /* irqs already disabled */ - if (!rcu_gp_in_progress(rsp)) - break; - /* fall into next case. */ - - case RCU_SAVE_COMPLETED: - - /* Update state, record completion counter. */ - forcenow = 0; - if (rsp->gpnum - 1 == rsp->completed) { - forcenow = rsp->signaled == RCU_SAVE_COMPLETED; + if (rcu_gp_in_progress(rsp)) rsp->signaled = RCU_FORCE_QS; - } - if (!forcenow) - break; - /* fall into next case. */ + break; case RCU_FORCE_QS: diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 534856121b06..edb6fae0fa94 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -237,12 +237,11 @@ struct rcu_data { #define RCU_GP_IDLE 0 /* No grace period in progress. */ #define RCU_GP_INIT 1 /* Grace period being initialized. */ #define RCU_SAVE_DYNTICK 2 /* Need to scan dyntick state. */ -#define RCU_SAVE_COMPLETED 3 /* Need to save rsp->completed. */ -#define RCU_FORCE_QS 4 /* Need to force quiescent state. */ +#define RCU_FORCE_QS 3 /* Need to force quiescent state. */ #ifdef CONFIG_NO_HZ #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK #else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT RCU_SAVE_COMPLETED +#define RCU_SIGNAL_INIT RCU_FORCE_QS #endif /* #else #ifdef CONFIG_NO_HZ */ #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ -- GitLab From 45f014c52eef022873b19d6a20eb0ec9668f2b09 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:08 -0800 Subject: [PATCH 0625/3892] rcu: Remove redundant grace-period check The rcu_process_dyntick() function checks twice for the end of the current grace period. However, it holds the current rcu_node structure's ->lock field throughout, and doesn't get to the second call to rcu_gp_in_progress() unless there is at least one CPU corresponding to this rcu_node structure that has not yet checked in for the current grace period, which would prevent the current grace period from ending. So the current grace period cannot have ended, and the second check is redundant, so remove it. Also, given that this function is used even with !CONFIG_NO_HZ, its name is quite misleading. Change from rcu_process_dyntick() to force_qs_rnp(). Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1262646550562-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 6268f37adfc4..d9202857d3ad 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1146,8 +1146,7 @@ void rcu_check_callbacks(int cpu, int user) * have not yet encountered a quiescent state, using the function specified. * The caller must have suppressed start of new grace periods. */ -static void rcu_process_dyntick(struct rcu_state *rsp, - int (*f)(struct rcu_data *)) +static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) { unsigned long bit; int cpu; @@ -1172,7 +1171,7 @@ static void rcu_process_dyntick(struct rcu_state *rsp, if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu])) mask |= bit; } - if (mask != 0 && rcu_gp_in_progress(rsp)) { + if (mask != 0) { /* rcu_report_qs_rnp() releases rnp->lock. */ rcu_report_qs_rnp(mask, rsp, rnp, flags); @@ -1222,7 +1221,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) break; /* So gcc recognizes the dead code. */ /* Record dyntick-idle state. */ - rcu_process_dyntick(rsp, dyntick_save_progress_counter); + force_qs_rnp(rsp, dyntick_save_progress_counter); spin_lock(&rnp->lock); /* irqs already disabled */ if (rcu_gp_in_progress(rsp)) rsp->signaled = RCU_FORCE_QS; @@ -1232,7 +1231,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Check dyntick-idle state, send IPI to laggarts. */ spin_unlock(&rnp->lock); /* irqs remain disabled */ - rcu_process_dyntick(rsp, rcu_implicit_dynticks_qs); + force_qs_rnp(rsp, rcu_implicit_dynticks_qs); /* Leave state in case more forcing is required. */ -- GitLab From 46a1e34eda805501a8b32f26394faa435149f6d1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:09 -0800 Subject: [PATCH 0626/3892] rcu: Make force_quiescent_state() start grace period if needed Grace periods cannot be started while force_quiescent_state() is active. This is OK in that the affected CPUs will try again later, but it does induce needless grace-period delays. This patch causes rcu_start_gp() to record a failed attempt to start a grace period. When force_quiescent_state() prepares to return, it then starts the grace period if there was such a failed attempt. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626465501854-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 8 ++++++++ kernel/rcutree.h | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d9202857d3ad..55e8f6ef8195 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -660,6 +660,8 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) struct rcu_node *rnp = rcu_get_root(rsp); if (!cpu_needs_another_gp(rsp, rdp) || rsp->fqs_active) { + if (cpu_needs_another_gp(rsp, rdp)) + rsp->fqs_need_gp = 1; if (rnp->completed == rsp->completed) { spin_unlock_irqrestore(&rnp->lock, flags); return; @@ -1239,6 +1241,12 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) break; } rsp->fqs_active = 0; + if (rsp->fqs_need_gp) { + spin_unlock(&rsp->fqslock); /* irqs remain disabled */ + rsp->fqs_need_gp = 0; + rcu_start_gp(rsp, flags); /* releases rnp->lock */ + return; + } spin_unlock(&rnp->lock); /* irqs remain disabled */ unlock_fqs_ret: spin_unlock_irqrestore(&rsp->fqslock, flags); diff --git a/kernel/rcutree.h b/kernel/rcutree.h index edb6fae0fa94..bd5d78ad1c48 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -278,6 +278,11 @@ struct rcu_state { /* Force QS state. */ u8 fqs_active; /* force_quiescent_state() */ /* is running. */ + u8 fqs_need_gp; /* A CPU was prevented from */ + /* starting a new grace */ + /* period because */ + /* force_quiescent_state() */ + /* was running. */ long gpnum; /* Current gp number. */ long completed; /* # of last completed gp. */ -- GitLab From bf66f18e79e34c421bbd8f6511e2c556b779df2f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 15:09:10 -0800 Subject: [PATCH 0627/3892] rcu: Add force_quiescent_state() testing to rcutorture Add force_quiescent_state() testing to rcutorture, with a separate thread that repeatedly invokes force_quiescent_state() in bursts. This can greatly increase the probability of encountering certain types of race conditions. Suggested-by: Josh Triplett Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1262646551116-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/rcutiny.h | 12 +++++++ include/linux/rcutree.h | 3 ++ kernel/rcutorture.c | 80 +++++++++++++++++++++++++++++++++++++++-- kernel/rcutree.c | 18 ++++++++++ kernel/rcutree_plugin.h | 19 ++++++++++ 5 files changed, 130 insertions(+), 2 deletions(-) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 96cc307ed9f4..2b70d4e37383 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -62,6 +62,18 @@ static inline long rcu_batches_completed_bh(void) extern int rcu_expedited_torture_stats(char *page); +static inline void rcu_force_quiescent_state(void) +{ +} + +static inline void rcu_bh_force_quiescent_state(void) +{ +} + +static inline void rcu_sched_force_quiescent_state(void) +{ +} + #define synchronize_rcu synchronize_sched static inline void synchronize_rcu_expedited(void) diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 8044b1b94333..704a010f686c 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -99,6 +99,9 @@ extern void rcu_check_callbacks(int cpu, int user); extern long rcu_batches_completed(void); extern long rcu_batches_completed_bh(void); extern long rcu_batches_completed_sched(void); +extern void rcu_force_quiescent_state(void); +extern void rcu_bh_force_quiescent_state(void); +extern void rcu_sched_force_quiescent_state(void); #ifdef CONFIG_NO_HZ void rcu_enter_nohz(void); diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 9bb52177af02..adda92bfafac 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -61,6 +61,9 @@ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ static int stutter = 5; /* Start/stop testing interval (in sec) */ static int irqreader = 1; /* RCU readers from irq (timers). */ +static int fqs_duration = 0; /* Duration of bursts (us), 0 to disable. */ +static int fqs_holdoff = 0; /* Hold time within burst (us). */ +static int fqs_stutter = 3; /* Wait time between bursts (s). */ static char *torture_type = "rcu"; /* What RCU implementation to torture. */ module_param(nreaders, int, 0444); @@ -79,6 +82,12 @@ module_param(stutter, int, 0444); MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); module_param(irqreader, int, 0444); MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers"); +module_param(fqs_duration, int, 0444); +MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)"); +module_param(fqs_holdoff, int, 0444); +MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); +module_param(fqs_stutter, int, 0444); +MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); @@ -99,6 +108,7 @@ static struct task_struct **reader_tasks; static struct task_struct *stats_task; static struct task_struct *shuffler_task; static struct task_struct *stutter_task; +static struct task_struct *fqs_task; #define RCU_TORTURE_PIPE_LEN 10 @@ -263,6 +273,7 @@ struct rcu_torture_ops { void (*deferred_free)(struct rcu_torture *p); void (*sync)(void); void (*cb_barrier)(void); + void (*fqs)(void); int (*stats)(char *page); int irq_capable; char *name; @@ -347,6 +358,7 @@ static struct rcu_torture_ops rcu_ops = { .deferred_free = rcu_torture_deferred_free, .sync = synchronize_rcu, .cb_barrier = rcu_barrier, + .fqs = rcu_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "rcu" @@ -388,6 +400,7 @@ static struct rcu_torture_ops rcu_sync_ops = { .deferred_free = rcu_sync_torture_deferred_free, .sync = synchronize_rcu, .cb_barrier = NULL, + .fqs = rcu_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "rcu_sync" @@ -403,6 +416,7 @@ static struct rcu_torture_ops rcu_expedited_ops = { .deferred_free = rcu_sync_torture_deferred_free, .sync = synchronize_rcu_expedited, .cb_barrier = NULL, + .fqs = rcu_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "rcu_expedited" @@ -465,6 +479,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .deferred_free = rcu_bh_torture_deferred_free, .sync = rcu_bh_torture_synchronize, .cb_barrier = rcu_barrier_bh, + .fqs = rcu_bh_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "rcu_bh" @@ -480,6 +495,7 @@ static struct rcu_torture_ops rcu_bh_sync_ops = { .deferred_free = rcu_sync_torture_deferred_free, .sync = rcu_bh_torture_synchronize, .cb_barrier = NULL, + .fqs = rcu_bh_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "rcu_bh_sync" @@ -621,6 +637,7 @@ static struct rcu_torture_ops sched_ops = { .deferred_free = rcu_sched_torture_deferred_free, .sync = sched_torture_synchronize, .cb_barrier = rcu_barrier_sched, + .fqs = rcu_sched_force_quiescent_state, .stats = NULL, .irq_capable = 1, .name = "sched" @@ -636,6 +653,7 @@ static struct rcu_torture_ops sched_sync_ops = { .deferred_free = rcu_sync_torture_deferred_free, .sync = sched_torture_synchronize, .cb_barrier = NULL, + .fqs = rcu_sched_force_quiescent_state, .stats = NULL, .name = "sched_sync" }; @@ -650,11 +668,44 @@ static struct rcu_torture_ops sched_expedited_ops = { .deferred_free = rcu_sync_torture_deferred_free, .sync = synchronize_sched_expedited, .cb_barrier = NULL, + .fqs = rcu_sched_force_quiescent_state, .stats = rcu_expedited_torture_stats, .irq_capable = 1, .name = "sched_expedited" }; +/* + * RCU torture force-quiescent-state kthread. Repeatedly induces + * bursts of calls to force_quiescent_state(), increasing the probability + * of occurrence of some important types of race conditions. + */ +static int +rcu_torture_fqs(void *arg) +{ + unsigned long fqs_resume_time; + int fqs_burst_remaining; + + VERBOSE_PRINTK_STRING("rcu_torture_fqs task started"); + do { + fqs_resume_time = jiffies + fqs_stutter * HZ; + while (jiffies - fqs_resume_time > LONG_MAX) { + schedule_timeout_interruptible(1); + } + fqs_burst_remaining = fqs_duration; + while (fqs_burst_remaining > 0) { + cur_ops->fqs(); + udelay(fqs_holdoff); + fqs_burst_remaining -= fqs_holdoff; + } + rcu_stutter_wait("rcu_torture_fqs"); + } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping"); + rcutorture_shutdown_absorb("rcu_torture_fqs"); + while (!kthread_should_stop()) + schedule_timeout_uninterruptible(1); + return 0; +} + /* * RCU torture writer kthread. Repeatedly substitutes a new structure * for that pointed to by rcu_torture_current, freeing the old structure @@ -1030,10 +1081,11 @@ rcu_torture_print_module_parms(char *tag) printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d nfakewriters=%d " "stat_interval=%d verbose=%d test_no_idle_hz=%d " - "shuffle_interval=%d stutter=%d irqreader=%d\n", + "shuffle_interval=%d stutter=%d irqreader=%d " + "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d\n", torture_type, tag, nrealreaders, nfakewriters, stat_interval, verbose, test_no_idle_hz, shuffle_interval, - stutter, irqreader); + stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter); } static struct notifier_block rcutorture_nb = { @@ -1109,6 +1161,12 @@ rcu_torture_cleanup(void) } stats_task = NULL; + if (fqs_task) { + VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task"); + kthread_stop(fqs_task); + } + fqs_task = NULL; + /* Wait for all RCU callbacks to fire. */ if (cur_ops->cb_barrier != NULL) @@ -1154,6 +1212,11 @@ rcu_torture_init(void) mutex_unlock(&fullstop_mutex); return -EINVAL; } + if (cur_ops->fqs == NULL && fqs_duration != 0) { + printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero " + "fqs_duration, fqs disabled.\n"); + fqs_duration = 0; + } if (cur_ops->init) cur_ops->init(); /* no "goto unwind" prior to this point!!! */ @@ -1282,6 +1345,19 @@ rcu_torture_init(void) goto unwind; } } + if (fqs_duration < 0) + fqs_duration = 0; + if (fqs_duration) { + /* Create the stutter thread */ + fqs_task = kthread_run(rcu_torture_fqs, NULL, + "rcu_torture_fqs"); + if (IS_ERR(fqs_task)) { + firsterr = PTR_ERR(fqs_task); + VERBOSE_PRINTK_ERRSTRING("Failed to create fqs"); + fqs_task = NULL; + goto unwind; + } + } register_reboot_notifier(&rcutorture_nb); mutex_unlock(&fullstop_mutex); return 0; diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 55e8f6ef8195..0a4c32879398 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -156,6 +156,24 @@ long rcu_batches_completed_bh(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); +/* + * Force a quiescent state for RCU BH. + */ +void rcu_bh_force_quiescent_state(void) +{ + force_quiescent_state(&rcu_bh_state, 0); +} +EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state); + +/* + * Force a quiescent state for RCU-sched. + */ +void rcu_sched_force_quiescent_state(void) +{ + force_quiescent_state(&rcu_sched_state, 0); +} +EXPORT_SYMBOL_GPL(rcu_sched_force_quiescent_state); + /* * Does the CPU have callbacks ready to be invoked? */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 37fbccdf41d5..f11ebd44b454 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -61,6 +61,15 @@ long rcu_batches_completed(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed); +/* + * Force a quiescent state for preemptible RCU. + */ +void rcu_force_quiescent_state(void) +{ + force_quiescent_state(&rcu_preempt_state, 0); +} +EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); + /* * Record a preemptable-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is @@ -712,6 +721,16 @@ long rcu_batches_completed(void) } EXPORT_SYMBOL_GPL(rcu_batches_completed); +/* + * Force a quiescent state for RCU, which, because there is no preemptible + * RCU, becomes the same as rcu-sched. + */ +void rcu_force_quiescent_state(void) +{ + rcu_sched_force_quiescent_state(); +} +EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); + /* * Because preemptable RCU does not exist, we never have to check for * CPUs being in quiescent states. -- GitLab From f9094d8e5587cf21091a9516628147c0b55e4264 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 16:04:00 -0800 Subject: [PATCH 0628/3892] rcu: Make MAINTAINERS file match new RCU reality Both rcutorture and RCU are supported. Also, update the files to match the new layout. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626498422334-git-send-email-> Signed-off-by: Ingo Molnar --- MAINTAINERS | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c8f47bf154f4..175da7c0803f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4509,7 +4509,7 @@ F: drivers/net/wireless/ray* RCUTORTURE MODULE M: Josh Triplett M: "Paul E. McKenney" -S: Maintained +S: Supported F: Documentation/RCU/torture.txt F: kernel/rcutorture.c @@ -4534,11 +4534,12 @@ M: Dipankar Sarma M: "Paul E. McKenney" W: http://www.rdrop.com/users/paulmck/rclock/ S: Supported -F: Documentation/RCU/rcu.txt -F: Documentation/RCU/rcuref.txt -F: include/linux/rcupdate.h -F: include/linux/srcu.h -F: kernel/rcupdate.c +F: Documentation/RCU/ +F: include/linux/rcu* +F: include/linux/srcu* +F: kernel/rcu* +F: kernel/srcu* +X: kernel/rcutorture.c REAL TIME CLOCK DRIVER M: Paul Gortmaker -- GitLab From cba8244a0f1c277b6b1e48ed6504fa434119e24d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 16:04:01 -0800 Subject: [PATCH 0629/3892] rcu: Add debug check for too many rcu_read_unlock() TREE_PREEMPT_RCU maintains an rcu_read_lock_nesting counter in the task structure, which happens to be a signed int. So this patch adds a check for this counter being negative at the end of __rcu_read_unlock(). This check is under CONFIG_PROVE_LOCKING, so can be thought of as being part of lockdep. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626498423064-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree_plugin.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index f11ebd44b454..e77cdf321e13 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -304,6 +304,9 @@ void __rcu_read_unlock(void) if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) rcu_read_unlock_special(t); +#ifdef CONFIG_PROVE_LOCKING + WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0); +#endif /* #ifdef CONFIG_PROVE_LOCKING */ } EXPORT_SYMBOL_GPL(__rcu_read_unlock); -- GitLab From b6407e863934965cdc66cbc244d811ceeb6f4d77 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 4 Jan 2010 16:04:02 -0800 Subject: [PATCH 0630/3892] rcu: Give different levels of the rcu_node hierarchy distinct lockdep names Previously, each level of the rcu_node hierarchy had the same rather unimaginative name: "&rcu_node_class[i]". This makes lockdep diagnostics involving these lockdep classes less helpful than would be nice. This patch fixes this by giving each level of the rcu_node hierarchy a distinct name: "rcu_node_level_0", "rcu_node_level_1", and so on. This version of the patch includes improved diagnostics suggested by Josh Triplett and Peter Zijlstra. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12626498421830-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 0a4c32879398..3b13d64b010b 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1811,11 +1811,17 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp) */ static void __init rcu_init_one(struct rcu_state *rsp) { + static char *buf[] = { "rcu_node_level_0", + "rcu_node_level_1", + "rcu_node_level_2", + "rcu_node_level_3" }; /* Match MAX_RCU_LVLS */ int cpustride = 1; int i; int j; struct rcu_node *rnp; + BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf)); /* Fix buf[] init! */ + /* Initialize the level-tracking arrays. */ for (i = 1; i < NUM_RCU_LVLS; i++) @@ -1829,7 +1835,8 @@ static void __init rcu_init_one(struct rcu_state *rsp) rnp = rsp->level[i]; for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) { spin_lock_init(&rnp->lock); - lockdep_set_class(&rnp->lock, &rcu_node_class[i]); + lockdep_set_class_and_name(&rnp->lock, + &rcu_node_class[i], buf[i]); rnp->gpnum = 0; rnp->qsmask = 0; rnp->qsmaskinit = 0; -- GitLab From 3920ab0ae729e73bbcb5b3d0358c048ff9163629 Mon Sep 17 00:00:00 2001 From: Tai-hwa Liang Date: Wed, 13 Jan 2010 00:22:29 -0800 Subject: [PATCH 0631/3892] Input: update Sentelic protocol documentation iSigned-off-by: Tai-hwa Liang Signed-off-by: Dmitry Torokhov --- Documentation/input/sentelic.txt | 124 +++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 14 deletions(-) diff --git a/Documentation/input/sentelic.txt b/Documentation/input/sentelic.txt index f7160a2fb6a2..b35affd5c649 100644 --- a/Documentation/input/sentelic.txt +++ b/Documentation/input/sentelic.txt @@ -1,5 +1,5 @@ -Copyright (C) 2002-2008 Sentelic Corporation. -Last update: Oct-31-2008 +Copyright (C) 2002-2010 Sentelic Corporation. +Last update: Jan-13-2010 ============================================================================== * Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons) @@ -44,7 +44,7 @@ B) MSID 6: Horizontal and Vertical scrolling. Packet 1 Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| - 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|l|r|u|d| + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|r|l|u|d| |---------------| |---------------| |---------------| |---------------| Byte 1: Bit7 => Y overflow @@ -59,15 +59,15 @@ Byte 2: X Movement(9-bit 2's complement integers) Byte 3: Y Movement(9-bit 2's complement integers) Byte 4: Bit0 => the Vertical scrolling movement downward. Bit1 => the Vertical scrolling movement upward. - Bit2 => the Vertical scrolling movement rightward. - Bit3 => the Vertical scrolling movement leftward. + Bit2 => the Horizontal scrolling movement leftward. + Bit3 => the Horizontal scrolling movement rightward. Bit4 => 1 = 4th mouse button is pressed, Forward one page. 0 = 4th mouse button is not pressed. Bit5 => 1 = 5th mouse button is pressed, Backward one page. 0 = 5th mouse button is not pressed. C) MSID 7: -# FSP uses 2 packets(8 Bytes) data to represent Absolute Position +# FSP uses 2 packets (8 Bytes) to represent Absolute Position. so we have PACKET NUMBER to identify packets. If PACKET NUMBER is 0, the packet is Packet 1. If PACKET NUMBER is 1, the packet is Packet 2. @@ -129,7 +129,7 @@ Byte 3: Message Type => 0x00 (Disabled) Byte 4: Bit7~Bit0 => Don't Care ============================================================================== -* Absolute position for STL3888-A0. +* Absolute position for STL3888-Ax. ============================================================================== Packet 1 (ABSOLUTE POSITION) Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 @@ -179,14 +179,14 @@ Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) Bit5~Bit4 => y2_g Bit7~Bit6 => x2_g -Notify Packet for STL3888-A0 +Notify Packet for STL3888-Ax Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| 1 |1|0|1|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|d|u|0|0|0|0| |---------------| |---------------| |---------------| |---------------| Byte 1: Bit7~Bit6 => 00, Normal data packet - => 01, Absolute coordination packet + => 01, Absolute coordinates packet => 10, Notify packet Bit5 => 1 Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1): @@ -205,15 +205,106 @@ Byte 4: Bit7 => scroll right button Bit6 => scroll left button Bit5 => scroll down button Bit4 => scroll up button - * Note that if gesture and additional button (Bit4~Bit7) - happen at the same time, the button information will not - be sent. + * Note that if gesture and additional buttoni (Bit4~Bit7) + happen at the same time, the button information will not + be sent. + Bit3~Bit0 => Reserved + +Sample sequence of Multi-finger, Multi-coordinate mode: + + notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1, + abs pkt 2, ..., notify packet (valid bit == 0) + +============================================================================== +* Absolute position for STL3888-B0. +============================================================================== +Packet 1(ABSOLUTE POSITION) + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |0|1|V|F|1|0|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|u|d|X|X|Y|Y| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordinates packet + => 10, Notify packet + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. + When both fingers are up, the last two reports have zero valid + bit. + Bit4 => finger up/down information. 1: finger down, 0: finger up. + Bit3 => 1 + Bit2 => finger index, 0 is the first finger, 1 is the second finger. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: X coordinate (xpos[9:2]) +Byte 3: Y coordinate (ypos[9:2]) +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) + Bit3~Bit2 => X coordinate (ypos[1:0]) + Bit4 => scroll down button + Bit5 => scroll up button + Bit6 => scroll left button + Bit7 => scroll right button + +Packet 2 (ABSOLUTE POSITION) + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |0|1|V|F|1|1|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|u|d|X|X|Y|Y| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. + When both fingers are up, the last two reports have zero valid + bit. + Bit4 => finger up/down information. 1: finger down, 0: finger up. + Bit3 => 1 + Bit2 => finger index, 0 is the first finger, 1 is the second finger. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: X coordinate (xpos[9:2]) +Byte 3: Y coordinate (ypos[9:2]) +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) + Bit3~Bit2 => X coordinate (ypos[1:0]) + Bit4 => scroll down button + Bit5 => scroll up button + Bit6 => scroll left button + Bit7 => scroll right button + +Notify Packet for STL3888-B0 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |1|0|1|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|u|d|0|0|0|0| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => 1 + Bit4 => when in absolute coordinate mode (valid when EN_PKT_GO is 1): + 0: left button is generated by the on-pad command + 1: left button is generated by the external button + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode) +Byte 3: Bit7~Bit6 => Don't care + Bit5~Bit4 => Number of fingers + Bit3~Bit1 => Reserved + Bit0 => 1: enter gesture mode; 0: leaving gesture mode +Byte 4: Bit7 => scroll right button + Bit6 => scroll left button + Bit5 => scroll up button + Bit4 => scroll down button + * Note that if gesture and additional button(Bit4~Bit7) + happen at the same time, the button information will not + be sent. Bit3~Bit0 => Reserved Sample sequence of Multi-finger, Multi-coordinate mode: notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1, - abs pkt 2, ..., notify packet(valid bit == 0) + abs pkt 2, ..., notify packet (valid bit == 0) ============================================================================== * FSP Enable/Disable packet @@ -409,7 +500,8 @@ offset width default r/w name 0: read only, 1: read/write enable (Note that following registers does not require clock gating being enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e - 40 41 42 43.) + 40 41 42 43. In addition to that, this bit must be 1 when gesture + mode is enabled) 0x31 RW on-pad command detection bit7 0 RW on-pad command left button down tag @@ -463,6 +555,10 @@ offset width default r/w name absolute coordinates; otherwise, host only receives packets with relative coordinate.) + bit7 0 RW EN_PS2_F2: PS/2 gesture mode 2nd + finger packet enable + 0: disable, 1: enable + 0x43 RW on-pad control bit0 0 RW on-pad control enable 0: disable, 1: enable -- GitLab From a5abd95cc0b35034186a9f76b0f2b83458425f47 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 13 Jan 2010 00:34:12 -0800 Subject: [PATCH 0632/3892] Input: ep93xx_keypad - cleanup and use matrix_keypad helpers Use struct matrix_keymap_data to supply the keymap from the platform code and matrix_keypad_build_keymap() to initialize the keymap. Signed-off-by: H Hartley Sweeten Signed-off-by: Dmitry Torokhov --- .../mach-ep93xx/include/mach/ep93xx_keypad.h | 14 +++---- drivers/input/keyboard/ep93xx_keypad.c | 40 +++++++------------ 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h index 62d17421e48c..1e2f4e97f428 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h @@ -5,6 +5,8 @@ #ifndef __ASM_ARCH_EP93XX_KEYPAD_H #define __ASM_ARCH_EP93XX_KEYPAD_H +struct matrix_keymap_data; + /* flags for the ep93xx_keypad driver */ #define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ @@ -15,15 +17,13 @@ /** * struct ep93xx_keypad_platform_data - platform specific device structure - * @matrix_key_map: array of keycodes defining the keypad matrix - * @matrix_key_map_size: ARRAY_SIZE(matrix_key_map) - * @debounce: debounce start count; terminal count is 0xff - * @prescale: row/column counter pre-scaler load value - * @flags: see above + * @keymap_data: pointer to &matrix_keymap_data + * @debounce: debounce start count; terminal count is 0xff + * @prescale: row/column counter pre-scaler load value + * @flags: see above */ struct ep93xx_keypad_platform_data { - unsigned int *matrix_key_map; - int matrix_key_map_size; + struct matrix_keymap_data *keymap_data; unsigned int debounce; unsigned int prescale; unsigned int flags; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index e45740429f7e..bd25a3af1664 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -69,7 +69,7 @@ struct ep93xx_keypad { void __iomem *mmio_base; - unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE]; + unsigned short keycodes[EP93XX_MATRIX_SIZE]; int key1; int key2; @@ -79,24 +79,6 @@ struct ep93xx_keypad { bool enabled; }; -static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) -{ - struct ep93xx_keypad_platform_data *pdata = keypad->pdata; - struct input_dev *input_dev = keypad->input_dev; - unsigned int *key; - int i; - - key = &pdata->matrix_key_map[0]; - for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { - int row = KEY_ROW(*key); - int col = KEY_COL(*key); - int code = KEY_VAL(*key); - - keypad->matrix_keycodes[(row << 3) + col] = code; - __set_bit(code, input_dev->keybit); - } -} - static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) { struct ep93xx_keypad *keypad = dev_id; @@ -107,10 +89,10 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) status = __raw_readl(keypad->mmio_base + KEY_REG); keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; - key1 = keypad->matrix_keycodes[keycode]; + key1 = keypad->keycodes[keycode]; keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; - key2 = keypad->matrix_keycodes[keycode]; + key2 = keypad->keycodes[keycode]; if (status & KEY_REG_2KEYS) { if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) @@ -256,6 +238,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev) static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) { struct ep93xx_keypad *keypad; + const struct matrix_keymap_data *keymap_data; struct input_dev *input_dev; struct resource *res; int err; @@ -270,6 +253,12 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) goto failed_free; } + keymap_data = keypad->pdata->keymap_data; + if (!keymap_data) { + err = -EINVAL; + goto failed_free; + } + keypad->irq = platform_get_irq(pdev, 0); if (!keypad->irq) { err = -ENXIO; @@ -317,9 +306,9 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) input_dev->open = ep93xx_keypad_open; input_dev->close = ep93xx_keypad_close; input_dev->dev.parent = &pdev->dev; - input_dev->keycode = keypad->matrix_keycodes; - input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); - input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); + input_dev->keycode = keypad->keycodes; + input_dev->keycodesize = sizeof(keypad->keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); input_set_drvdata(input_dev, keypad); @@ -327,7 +316,8 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) input_dev->evbit[0] |= BIT_MASK(EV_REP); - ep93xx_keypad_build_keycode(keypad); + matrix_keypad_build_keymap(keymap_data, 3, + input_dev->keycode, input_dev->keybit); platform_set_drvdata(pdev, keypad); err = request_irq(keypad->irq, ep93xx_keypad_irq_handler, -- GitLab From 0fb8ee48d9dfff6a0913ceb0be2068d8be203763 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 31 Dec 2009 05:53:03 +0100 Subject: [PATCH 0633/3892] perf: Drop useless check for ignored frame The check that ignores the debug and nmi stack frames is useless now that we have a frame pointer that makes us start at the right place. We don't anymore have to deal with these. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras LKML-Reference: <1262235183-5320-2-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/stacktrace.h | 2 -- arch/x86/kernel/cpu/perf_event.c | 8 -------- arch/x86/kernel/dumpstack_32.c | 5 ----- arch/x86/kernel/dumpstack_64.c | 5 ----- 4 files changed, 20 deletions(-) diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 35e89122a42f..4dab78edbad9 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h @@ -3,8 +3,6 @@ extern int kstack_depth_to_print; -int x86_is_stack_id(int id, char *name); - struct thread_info; struct stacktrace_ops; diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index d616c06e99b4..b1bb8c550526 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -2297,7 +2297,6 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip) static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry); -static DEFINE_PER_CPU(int, in_ignored_frame); static void @@ -2313,10 +2312,6 @@ static void backtrace_warning(void *data, char *msg) static int backtrace_stack(void *data, char *name) { - per_cpu(in_ignored_frame, smp_processor_id()) = - x86_is_stack_id(NMI_STACK, name) || - x86_is_stack_id(DEBUG_STACK, name); - return 0; } @@ -2324,9 +2319,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) { struct perf_callchain_entry *entry = data; - if (per_cpu(in_ignored_frame, smp_processor_id())) - return; - if (reliable) callchain_store(entry, addr); } diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index ae775ca47b25..11540a189d93 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -18,11 +18,6 @@ #include "dumpstack.h" -/* Just a stub for now */ -int x86_is_stack_id(int id, char *name) -{ - return 0; -} void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, unsigned long bp, diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 0ad9597073f5..676bc051252e 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -33,11 +33,6 @@ static char x86_stack_ids[][8] = { #endif }; -int x86_is_stack_id(int id, char *name) -{ - return x86_stack_ids[id - 1] == name; -} - static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, unsigned *usedp, char **idp) { -- GitLab From 60666c630bdb33983a894b050b588b663f38f368 Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Thu, 31 Dec 2009 16:05:50 +0800 Subject: [PATCH 0634/3892] perf tools: Fix --pid option for stat current pid option doesn't work for perf stat. Change it to what perf record --pid acts as. Signed-off-by: Liming Wang Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1262246750-2191-1-git-send-email-liming.wang@windriver.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-stat.c | 106 ++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c70d72003557..e8c85d5aec41 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -44,6 +44,7 @@ #include "util/parse-events.h" #include "util/event.h" #include "util/debug.h" +#include "util/header.h" #include #include @@ -79,6 +80,8 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS]; static int event_scaled[MAX_COUNTERS]; +static volatile int done = 0; + struct stats { double n, mean, M2; @@ -247,61 +250,64 @@ static int run_perf_stat(int argc __used, const char **argv) unsigned long long t0, t1; int status = 0; int counter; - int pid; + int pid = target_pid; int child_ready_pipe[2], go_pipe[2]; + const bool forks = (target_pid == -1 && argc > 0); char buf; if (!system_wide) nr_cpus = 1; - if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { + if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { perror("failed to create pipes"); exit(1); } - if ((pid = fork()) < 0) - perror("failed to fork"); + if (forks) { + if ((pid = fork()) < 0) + perror("failed to fork"); + + if (!pid) { + close(child_ready_pipe[0]); + close(go_pipe[1]); + fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); + + /* + * Do a dummy execvp to get the PLT entry resolved, + * so we avoid the resolver overhead on the real + * execvp call. + */ + execvp("", (char **)argv); + + /* + * Tell the parent we're ready to go + */ + close(child_ready_pipe[1]); + + /* + * Wait until the parent tells us to go. + */ + if (read(go_pipe[0], &buf, 1) == -1) + perror("unable to read pipe"); + + execvp(argv[0], (char **)argv); + + perror(argv[0]); + exit(-1); + } - if (!pid) { - close(child_ready_pipe[0]); - close(go_pipe[1]); - fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); + child_pid = pid; /* - * Do a dummy execvp to get the PLT entry resolved, - * so we avoid the resolver overhead on the real - * execvp call. - */ - execvp("", (char **)argv); - - /* - * Tell the parent we're ready to go + * Wait for the child to be ready to exec. */ close(child_ready_pipe[1]); - - /* - * Wait until the parent tells us to go. - */ - if (read(go_pipe[0], &buf, 1) == -1) + close(go_pipe[0]); + if (read(child_ready_pipe[0], &buf, 1) == -1) perror("unable to read pipe"); - - execvp(argv[0], (char **)argv); - - perror(argv[0]); - exit(-1); + close(child_ready_pipe[0]); } - child_pid = pid; - - /* - * Wait for the child to be ready to exec. - */ - close(child_ready_pipe[1]); - close(go_pipe[0]); - if (read(child_ready_pipe[0], &buf, 1) == -1) - perror("unable to read pipe"); - close(child_ready_pipe[0]); - for (counter = 0; counter < nr_counters; counter++) create_perf_stat_counter(counter, pid); @@ -310,8 +316,12 @@ static int run_perf_stat(int argc __used, const char **argv) */ t0 = rdclock(); - close(go_pipe[1]); - wait(&status); + if (forks) { + close(go_pipe[1]); + wait(&status); + } else { + while(!done); + } t1 = rdclock(); @@ -417,10 +427,13 @@ static void print_stat(int argc, const char **argv) fflush(stdout); fprintf(stderr, "\n"); - fprintf(stderr, " Performance counter stats for \'%s", argv[0]); - - for (i = 1; i < argc; i++) - fprintf(stderr, " %s", argv[i]); + fprintf(stderr, " Performance counter stats for "); + if(target_pid == -1) { + fprintf(stderr, "\'%s", argv[0]); + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + }else + fprintf(stderr, "task pid \'%d", target_pid); fprintf(stderr, "\'"); if (run_count > 1) @@ -445,6 +458,9 @@ static volatile int signr = -1; static void skip_signal(int signo) { + if(target_pid != -1) + done = 1; + signr = signo; } @@ -461,7 +477,7 @@ static void sig_atexit(void) } static const char * const stat_usage[] = { - "perf stat [] ", + "perf stat [] []", NULL }; @@ -492,7 +508,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc) + if (!argc && target_pid == -1) usage_with_options(stat_usage, options); if (run_count <= 0) usage_with_options(stat_usage, options); -- GitLab From 682b335a5bccf9e5b7e74380784aa2f145d04444 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jan 2010 16:19:26 -0200 Subject: [PATCH 0635/3892] perf symbols: Generalise the kallsyms parsing routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will be used to find an specific symbol by name on 'perf record' to support relocation reference symbols to support relocatable kernels. Still have to conver the perf trace tools to use it instead of their current reimplementation. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262629169-22797-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 74 ++++++++++++++++++++++++++-------------- tools/perf/util/symbol.h | 2 ++ 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 79ca6a099f96..b9e0da57d84b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -383,16 +383,12 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) return ret; } -/* - * Loads the function entries in /proc/kallsyms into kernel_map->dso, - * so that we can in the next step set the symbol ->end address and then - * call kernel_maps__split_kallsyms. - */ -static int dso__load_all_kallsyms(struct dso *self, struct map *map) +int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, + char type, u64 start)) { char *line = NULL; size_t n; - struct rb_root *root = &self->symbols[map->type]; + int err = 0; FILE *file = fopen("/proc/kallsyms", "r"); if (file == NULL) @@ -400,7 +396,6 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map) while (!feof(file)) { u64 start; - struct symbol *sym; int line_len, len; char symbol_type; char *symbol_name; @@ -421,35 +416,62 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map) continue; symbol_type = toupper(line[len]); - if (!symbol_type__is_a(symbol_type, map->type)) - continue; - symbol_name = line + len + 2; - /* - * Will fix up the end later, when we have all symbols sorted. - */ - sym = symbol__new(start, 0, symbol_name); - if (sym == NULL) - goto out_delete_line; - /* - * We will pass the symbols to the filter later, in - * map__split_kallsyms, when we have split the maps per module - */ - symbols__insert(root, sym); + err = process_symbol(arg, symbol_name, symbol_type, start); + if (err) + break; } free(line); fclose(file); + return err; - return 0; - -out_delete_line: - free(line); out_failure: return -1; } +struct process_kallsyms_args { + struct map *map; + struct dso *dso; +}; + +static int map__process_kallsym_symbol(void *arg, const char *name, + char type, u64 start) +{ + struct symbol *sym; + struct process_kallsyms_args *a = arg; + struct rb_root *root = &a->dso->symbols[a->map->type]; + + if (!symbol_type__is_a(type, a->map->type)) + return 0; + + /* + * Will fix up the end later, when we have all symbols sorted. + */ + sym = symbol__new(start, 0, name); + + if (sym == NULL) + return -ENOMEM; + /* + * We will pass the symbols to the filter later, in + * map__split_kallsyms, when we have split the maps per module + */ + symbols__insert(root, sym); + return 0; +} + +/* + * Loads the function entries in /proc/kallsyms into kernel_map->dso, + * so that we can in the next step set the symbol ->end address and then + * call kernel_maps__split_kallsyms. + */ +static int dso__load_all_kallsyms(struct dso *self, struct map *map) +{ + struct process_kallsyms_args args = { .map = map, .dso = self, }; + return kallsyms__parse(&args, map__process_kallsym_symbol); +} + /* * Split the symbols into maps, making sure there are no overlaps, i.e. the * kernel range is broken in several maps, named [kernel].N, as we don't have diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f27e158943e9..21313e87c37b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -135,6 +135,8 @@ int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); +int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, + char type, u64 start)); int symbol__init(void); int perf_session__create_kernel_maps(struct perf_session *self); -- GitLab From 36a3e6461a0dac8e84b8c94877365324010c151b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jan 2010 16:19:27 -0200 Subject: [PATCH 0636/3892] perf symbols: Export symbol_type__is_a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will be needed by the new HEADER_DSO_INFO feature that will be a HEADER_BUILD_ID superset, replacing it. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262629169-22797-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 2 +- tools/perf/util/symbol.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b9e0da57d84b..5dffcd132d15 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -64,7 +64,7 @@ static void dso__set_sorted_by_name(struct dso *self, enum map_type type) self->sorted_by_name |= (1 << type); } -static bool symbol_type__is_a(char symbol_type, enum map_type map_type) +bool symbol_type__is_a(char symbol_type, enum map_type map_type) { switch (map_type) { case MAP__FUNCTION: diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 21313e87c37b..b2b5330a82a0 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -139,6 +139,8 @@ int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name char type, u64 start)); int symbol__init(void); +bool symbol_type__is_a(char symbol_type, enum map_type map_type); + int perf_session__create_kernel_maps(struct perf_session *self); extern struct list_head dsos__user, dsos__kernel; -- GitLab From f92cb24c78a7c853435e46a20d1bd5c894378132 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jan 2010 16:19:28 -0200 Subject: [PATCH 0637/3892] perf tools: Create write_padded routine out of __dsos__write_buildid_table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will be used by other options where padding is needed. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262629169-22797-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 709e3252f049..942f7da8bf84 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -173,6 +173,20 @@ static int do_write(int fd, const void *buf, size_t size) return 0; } +#define NAME_ALIGN 64 + +static int write_padded(int fd, const void *bf, size_t count, + size_t count_aligned) +{ + static const char zero_buf[NAME_ALIGN]; + int err = do_write(fd, bf, count); + + if (!err) + err = do_write(fd, zero_buf, count_aligned - count); + + return err; +} + #define dsos__for_each_with_build_id(pos, head) \ list_for_each_entry(pos, head, node) \ if (!pos->has_build_id) \ @@ -181,9 +195,7 @@ static int do_write(int fd, const void *buf, size_t size) static int __dsos__write_buildid_table(struct list_head *head, int fd) { -#define NAME_ALIGN 64 struct dso *pos; - static const char zero_buf[NAME_ALIGN]; dsos__for_each_with_build_id(pos, head) { int err; @@ -197,10 +209,8 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) err = do_write(fd, &b, sizeof(b)); if (err < 0) return err; - err = do_write(fd, pos->long_name, pos->long_name_len + 1); - if (err < 0) - return err; - err = do_write(fd, zero_buf, len - pos->long_name_len - 1); + err = write_padded(fd, pos->long_name, + pos->long_name_len + 1, len); if (err < 0) return err; } -- GitLab From de1764892a61a3ed212973cc028c80dd083179dd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jan 2010 16:19:29 -0200 Subject: [PATCH 0638/3892] perf session: Keep pointers to the vmlinux maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that tools such as 'perf probe' don't have to lookup '[kernel.kallsyms]' but instead access them directly after perf_session__create_kernel_maps or map_groups__create_kernel_maps. Signed-off-by: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262629169-22797-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-probe.c | 4 +--- tools/perf/util/session.h | 1 + tools/perf/util/symbol.c | 29 +++++++++++++---------------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c1e6774fd3ed..ffdd3fe87b4a 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -235,9 +235,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) session.psession = perf_session__new(NULL, O_WRONLY, false); if (session.psession == NULL) die("Failed to init perf_session."); - session.kmap = map_groups__find_by_name(&session.psession->kmaps, - MAP__FUNCTION, - "[kernel.kallsyms]"); + session.kmap = session.psession->vmlinux_maps[MAP__FUNCTION]; if (!session.kmap) die("Could not find kernel map.\n"); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 77c5ee2993c2..8db37bbf0e62 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -18,6 +18,7 @@ struct perf_session { struct map_groups kmaps; struct rb_root threads; struct thread *last_match; + struct map *vmlinux_maps[MAP__NR_TYPES]; struct events_stats events_stats; unsigned long event_total[PERF_RECORD_MAX]; unsigned long unknown_events; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 5dffcd132d15..e290429e9c00 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1662,7 +1662,7 @@ size_t dsos__fprintf_buildid(FILE *fp) __dsos__fprintf_buildid(&dsos__user, fp)); } -static struct dso *dsos__create_kernel( const char *vmlinux) +static struct dso *dsos__create_kernel(const char *vmlinux) { struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); @@ -1691,29 +1691,26 @@ out_delete_kernel_dso: return NULL; } -static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) +static int map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES], + const char *vmlinux) { - struct map *functions, *variables; struct dso *kernel = dsos__create_kernel(vmlinux); + enum map_type type; if (kernel == NULL) return -1; - functions = map__new2(0, kernel, MAP__FUNCTION); - if (functions == NULL) - return -1; + for (type = 0; type < MAP__NR_TYPES; ++type) { + vmlinux_maps[type] = map__new2(0, kernel, type); + if (vmlinux_maps[type] == NULL) + return -1; - variables = map__new2(0, kernel, MAP__VARIABLE); - if (variables == NULL) { - map__delete(functions); - return -1; + vmlinux_maps[type]->map_ip = + vmlinux_maps[type]->unmap_ip = identity__map_ip; + map_groups__insert(self, vmlinux_maps[type]); } - functions->map_ip = functions->unmap_ip = - variables->map_ip = variables->unmap_ip = identity__map_ip; - map_groups__insert(self, functions); - map_groups__insert(self, variables); - return 0; } @@ -1824,7 +1821,7 @@ out_free_comm_list: int perf_session__create_kernel_maps(struct perf_session *self) { - if (map_groups__create_kernel_maps(&self->kmaps, + if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps, symbol_conf.vmlinux_name) < 0) return -1; -- GitLab From b9a63b9b56d6910a25e3d4905525aef150420a9b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jan 2010 11:54:45 -0200 Subject: [PATCH 0639/3892] perf report: Fix --no-call-chain option handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid the funny: [root@doppio ~]# perf record -a -f sleep 2s [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.334 MB perf.data (~14572 samples) ] [root@doppio ~]# perf report --no-call-graph selected -g but no callchain data. Did you call perf record without -g? And fix the bug reported by peterz when we do indeed record with callchains and then ask for a report without: [root@doppio ~]# perf record -a -g -f sleep 2s [root@doppio ~]# perf report --no-call-graph Segmentation fault [root@doppio ~]# Reported-by: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262699685-27820-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-report.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4292d7afcd60..80d691a4191f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -35,6 +35,7 @@ static char const *input_name = "perf.data"; static int force; static bool hide_unresolved; +static bool dont_use_callchains; static int show_threads; static struct perf_read_values show_threads_values; @@ -172,7 +173,8 @@ static int perf_session__setup_sample_type(struct perf_session *self) " -g?\n"); return -1; } - } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { + } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && + !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (register_callchain_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" @@ -246,11 +248,19 @@ out_delete: static int parse_callchain_opt(const struct option *opt __used, const char *arg, - int unset __used) + int unset) { char *tok; char *endptr; + /* + * --no-call-graph + */ + if (unset) { + dont_use_callchains = true; + return 0; + } + symbol_conf.use_callchain = true; if (!arg) -- GitLab From 56b03f3c4d641dbdbce2e52a2969712e85b0e030 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jan 2010 16:50:31 -0200 Subject: [PATCH 0640/3892] perf tools: Handle relocatable kernels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DSOs don't have this problem because the kernel emits a PERF_MMAP for each new executable mapping it performs on monitored threads. To fix the kernel case we simulate the same behaviour, by having 'perf record' to synthesize a PERF_MMAP for the kernel, encoded like this: [root@doppio ~]# perf record -a -f sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.344 MB perf.data (~15038 samples) ] [root@doppio ~]# perf report -D | head -10 0xd0 [0x40]: event: 1 . . ... raw event: size 64 bytes . 0000: 01 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 ......@........ . 0010: 00 00 00 81 ff ff ff ff 00 00 00 00 00 00 00 00 ............... . 0020: 00 00 00 00 00 00 00 00 5b 6b 65 72 6e 65 6c 2e ........ [kernel . 0030: 6b 61 6c 6c 73 79 6d 73 2e 5f 74 65 78 74 5d 00 kallsyms._text] . 0xd0 [0x40]: PERF_RECORD_MMAP 0/0: [0xffffffff81000000((nil)) @ (nil)]: [kernel.kallsyms._text] I.e. we identify such event as having: .pid = 0 .filename = [kernel.kallsyms.REFNAME] .start = REFNAME addr in /proc/kallsyms at 'perf record' time and use now a hardcoded value of '.text' for REFNAME. Then, later, in 'perf report', if there are any kernel hits and thus we need to resolve kernel symbols, we search for REFNAME and if its address changed, relocation happened and we thus must change the kernel mapping routines to one that uses .pgoff as the relocation to apply. This way we use the same mechanism used for the other DSOs and don't have to do a two pass in all the kernel symbols. Reported-by: Xiao Guangrong Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: "H. Peter Anvin" Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Xiao Guangrong LKML-Reference: <1262717431-1246-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 7 ++++ tools/perf/util/event.c | 64 +++++++++++++++++++++++++++++++++++-- tools/perf/util/event.h | 4 +++ tools/perf/util/session.c | 46 ++++++++++++++++++++++++++ tools/perf/util/session.h | 10 ++++++ tools/perf/util/symbol.c | 7 ++-- 6 files changed, 133 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 265425322734..8f88420e066b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -551,6 +551,13 @@ static int __cmd_record(int argc, const char **argv) return err; } + err = event__synthesize_kernel_mmap(process_synthesized_event, + session, "_text"); + if (err < 0) { + pr_err("Couldn't record kernel reference relocation symbol.\n"); + return err; + } + if (!system_wide && profile_cpu == -1) event__synthesize_thread(pid, process_synthesized_event, session); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bb0fd6da2d56..1a31feb9999f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -189,6 +189,50 @@ void event__synthesize_threads(int (*process)(event_t *event, closedir(proc); } +struct process_symbol_args { + const char *name; + u64 start; +}; + +static int find_symbol_cb(void *arg, const char *name, char type, u64 start) +{ + struct process_symbol_args *args = arg; + + if (!symbol_type__is_a(type, MAP__FUNCTION) || strcmp(name, args->name)) + return 0; + + args->start = start; + return 1; +} + +int event__synthesize_kernel_mmap(int (*process)(event_t *event, + struct perf_session *session), + struct perf_session *session, + const char *symbol_name) +{ + size_t size; + event_t ev = { + .header = { .type = PERF_RECORD_MMAP }, + }; + /* + * We should get this from /sys/kernel/sections/.text, but till that is + * available use this, and after it is use this as a fallback for older + * kernels. + */ + struct process_symbol_args args = { .name = symbol_name, }; + + if (kallsyms__parse(&args, find_symbol_cb) <= 0) + return -ENOENT; + + size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), + "[kernel.kallsyms.%s]", symbol_name) + 1; + size = ALIGN(size, sizeof(u64)); + ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); + ev.mmap.start = args.start; + + return process(&ev, session); +} + static void thread__comm_adjust(struct thread *self) { char *comm = self->comm; @@ -240,9 +284,9 @@ int event__process_lost(event_t *self, struct perf_session *session) int event__process_mmap(event_t *self, struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, self->mmap.pid); - struct map *map = map__new(&self->mmap, MAP__FUNCTION, - session->cwd, session->cwdlen); + struct thread *thread; + struct map *map; + static const char kmmap_prefix[] = "[kernel.kallsyms."; dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", self->mmap.pid, self->mmap.tid, @@ -251,6 +295,20 @@ int event__process_mmap(event_t *self, struct perf_session *session) (void *)(long)self->mmap.pgoff, self->mmap.filename); + if (self->mmap.pid == 0 && + memcmp(self->mmap.filename, kmmap_prefix, + sizeof(kmmap_prefix) - 1) == 0) { + const char *symbol_name = (self->mmap.filename + + sizeof(kmmap_prefix) - 1); + perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, + self->mmap.start); + return 0; + } + + thread = perf_session__findnew(session, self->mmap.pid); + map = map__new(&self->mmap, MAP__FUNCTION, + session->cwd, session->cwdlen); + if (thread == NULL || map == NULL) dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); else diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 80fb3653c809..61fc0dc658c2 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -110,6 +110,10 @@ int event__synthesize_thread(pid_t pid, void event__synthesize_threads(int (*process)(event_t *event, struct perf_session *session), struct perf_session *session); +int event__synthesize_kernel_mmap(int (*process)(event_t *event, + struct perf_session *session), + struct perf_session *session, + const char *symbol_name); int event__process_comm(event_t *self, struct perf_session *session); int event__process_lost(event_t *self, struct perf_session *session); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7f0537d1add8..e0e6a075489e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -401,3 +401,49 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) return true; } + +int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, + const char *symbol_name, + u64 addr) +{ + char *bracket; + + self->ref_reloc_sym.name = strdup(symbol_name); + if (self->ref_reloc_sym.name == NULL) + return -ENOMEM; + + bracket = strchr(self->ref_reloc_sym.name, ']'); + if (bracket) + *bracket = '\0'; + + self->ref_reloc_sym.addr = addr; + return 0; +} + +static u64 map__reloc_map_ip(struct map *map, u64 ip) +{ + return ip + (s64)map->pgoff; +} + +static u64 map__reloc_unmap_ip(struct map *map, u64 ip) +{ + return ip - (s64)map->pgoff; +} + +void perf_session__reloc_vmlinux_maps(struct perf_session *self, + u64 unrelocated_addr) +{ + enum map_type type; + s64 reloc = unrelocated_addr - self->ref_reloc_sym.addr; + + if (!reloc) + return; + + for (type = 0; type < MAP__NR_TYPES; ++type) { + struct map *map = self->vmlinux_maps[type]; + + map->map_ip = map__reloc_map_ip; + map->unmap_ip = map__reloc_unmap_ip; + map->pgoff = reloc; + } +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8db37bbf0e62..d4a9d20f8d44 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -24,6 +24,10 @@ struct perf_session { unsigned long unknown_events; struct rb_root hists; u64 sample_type; + struct { + const char *name; + u64 addr; + } ref_reloc_sym; int fd; int cwdlen; char *cwd; @@ -59,4 +63,10 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg); int perf_header__read_build_ids(int input, u64 offset, u64 file_size); +int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, + const char *symbol_name, + u64 addr); +void perf_session__reloc_vmlinux_maps(struct perf_session *self, + u64 unrelocated_addr); + #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e290429e9c00..da2f07f1af8f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -956,11 +956,15 @@ static int dso__load_sym(struct dso *self, struct map *map, elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { struct symbol *f; - const char *elf_name; + const char *elf_name = elf_sym__name(&sym, symstrs); char *demangled = NULL; int is_label = elf_sym__is_label(&sym); const char *section_name; + if (kernel && session->ref_reloc_sym.name != NULL && + strcmp(elf_name, session->ref_reloc_sym.name) == 0) + perf_session__reloc_vmlinux_maps(session, sym.st_value); + if (!is_label && !elf_sym__is_a(&sym, map->type)) continue; @@ -973,7 +977,6 @@ static int dso__load_sym(struct dso *self, struct map *map, if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) continue; - elf_name = elf_sym__name(&sym, symstrs); section_name = elf_sec__name(&shdr, secstrs); if (kernel || kmodule) { -- GitLab From ec3a9039601af210fca4650d229621fe5a21df0b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:46:41 -0500 Subject: [PATCH 0641/3892] tracing/kprobe: Update example output in documentation Update example output in documentation according to current implementation. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <20100105224641.19431.34967.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- Documentation/trace/kprobetrace.txt | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index 47aabeebbdf6..c3eff6ff945f 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -97,23 +97,24 @@ recording return value as "myretprobe" event. cat /sys/kernel/debug/tracing/events/kprobes/myprobe/format name: myprobe -ID: 75 +ID: 780 format: - field:unsigned short common_type; offset:0; size:2; - field:unsigned char common_flags; offset:2; size:1; - field:unsigned char common_preempt_count; offset:3; size:1; - field:int common_pid; offset:4; size:4; - field:int common_tgid; offset:8; size:4; - - field: unsigned long ip; offset:16;tsize:8; - field: int nargs; offset:24;tsize:4; - field: unsigned long dfd; offset:32;tsize:8; - field: unsigned long filename; offset:40;tsize:8; - field: unsigned long flags; offset:48;tsize:8; - field: unsigned long mode; offset:56;tsize:8; - -print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->ip, REC->dfd, REC->filename, REC->flags, REC->mode - + field:unsigned short common_type; offset:0; size:2; signed:0; + field:unsigned char common_flags; offset:2; size:1; signed:0; + field:unsigned char common_preempt_count; offset:3; size:1;signed:0; + field:int common_pid; offset:4; size:4; signed:1; + field:int common_lock_depth; offset:8; size:4; signed:1; + + field:unsigned long __probe_ip; offset:12; size:4; signed:0; + field:int __probe_nargs; offset:16; size:4; signed:1; + field:unsigned long dfd; offset:20; size:4; signed:0; + field:unsigned long filename; offset:24; size:4; signed:0; + field:unsigned long flags; offset:28; size:4; signed:0; + field:unsigned long mode; offset:32; size:4; signed:0; + + +print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->__probe_ip, +REC->dfd, REC->filename, REC->flags, REC->mode You can see that the event has 4 arguments as in the expressions you specified. -- GitLab From 14640106f243a3b29944d7198569090fa6546f2d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:46:48 -0500 Subject: [PATCH 0642/3892] tracing/kprobe: Drop function argument access syntax Drop function argument access syntax, because the function arguments depend on not only architecture but also compile-options and function API. And now, we have perf-probe for finding register/memory assigned to each argument. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Steven Rostedt Cc: Roland McGrath Cc: Oleg Nesterov Cc: Mahesh Salgaonkar Cc: Benjamin Herrenschmidt Cc: Michael Neuling Cc: linuxppc-dev@ozlabs.org LKML-Reference: <20100105224648.19431.52309.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- Documentation/trace/kprobetrace.txt | 21 ++++++++++----------- kernel/trace/trace_kprobe.c | 18 +----------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index c3eff6ff945f..f30978e001f8 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -37,15 +37,12 @@ Synopsis of kprobe_events @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) $stackN : Fetch Nth entry of stack (N >= 0) $stack : Fetch stack address. - $argN : Fetch function argument. (N >= 0)(*) - $retval : Fetch return value.(**) - +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(***) + $retval : Fetch return value.(*) + +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) NAME=FETCHARG: Set NAME as the argument name of FETCHARG. - (*) aN may not correct on asmlinkaged functions and at the middle of - function body. - (**) only for return probe. - (***) this is useful for fetching a field of data structures. + (*) only for return probe. + (**) this is useful for fetching a field of data structures. Per-Probe Event Filtering @@ -82,11 +79,14 @@ Usage examples To add a probe as a new event, write a new definition to kprobe_events as below. - echo p:myprobe do_sys_open dfd=$arg0 filename=$arg1 flags=$arg2 mode=$arg3 > /sys/kernel/debug/tracing/kprobe_events + echo p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack) > /sys/kernel/debug/tracing/kprobe_events This sets a kprobe on the top of do_sys_open() function with recording -1st to 4th arguments as "myprobe" event. As this example shows, users can -choose more familiar names for each arguments. +1st to 4th arguments as "myprobe" event. Note, which register/stack entry is +assigned to each function argument depends on arch-specific ABI. If you unsure +the ABI, please try to use probe subcommand of perf-tools (you can find it +under tools/perf/). +As this example shows, users can choose more familiar names for each arguments. echo r:myretprobe do_sys_open $retval >> /sys/kernel/debug/tracing/kprobe_events @@ -147,4 +147,3 @@ events, you need to enable it. returns from SYMBOL(e.g. "sys_open+0x1b/0x1d <- do_sys_open" means kernel returns from do_sys_open to sys_open+0x1b). - diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 47f54ab57b68..7ac728ded964 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -91,11 +91,6 @@ static __kprobes unsigned long fetch_memory(struct pt_regs *regs, void *addr) return retval; } -static __kprobes unsigned long fetch_argument(struct pt_regs *regs, void *num) -{ - return regs_get_argument_nth(regs, (unsigned int)((unsigned long)num)); -} - static __kprobes unsigned long fetch_retvalue(struct pt_regs *regs, void *dummy) { @@ -231,9 +226,7 @@ static int probe_arg_string(char *buf, size_t n, struct fetch_func *ff) { int ret = -EINVAL; - if (ff->func == fetch_argument) - ret = snprintf(buf, n, "$arg%lu", (unsigned long)ff->data); - else if (ff->func == fetch_register) { + if (ff->func == fetch_register) { const char *name; name = regs_query_register_name((unsigned int)((long)ff->data)); ret = snprintf(buf, n, "%%%s", name); @@ -489,14 +482,6 @@ static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return) } } else ret = -EINVAL; - } else if (strncmp(arg, "arg", 3) == 0 && isdigit(arg[3])) { - ret = strict_strtoul(arg + 3, 10, ¶m); - if (ret || param > PARAM_MAX_ARGS) - ret = -EINVAL; - else { - ff->func = fetch_argument; - ff->data = (void *)param; - } } else ret = -EINVAL; return ret; @@ -611,7 +596,6 @@ static int create_trace_probe(int argc, char **argv) * - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS] * - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS] * Fetch args: - * $argN : fetch Nth of function argument. (N:0-) * $retval : fetch return value * $stack : fetch stack address * $stackN : fetch Nth of stack (N:0-) -- GitLab From aa5add93e92019018e905146f8c3d3f8e3c08300 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:46:56 -0500 Subject: [PATCH 0643/3892] x86/ptrace: Remove unused regs_get_argument_nth API Because of dropping function argument syntax from kprobe-tracer, we don't need this API anymore. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Roland McGrath Cc: Oleg Nesterov Cc: Mahesh Salgaonkar Cc: Benjamin Herrenschmidt Cc: Michael Neuling Cc: Steven Rostedt Cc: linuxppc-dev@ozlabs.org LKML-Reference: <20100105224656.19431.92588.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/ptrace.h | 4 ---- arch/x86/kernel/ptrace.c | 24 ------------------------ 2 files changed, 28 deletions(-) diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 9d369f680321..20102808b191 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -274,10 +274,6 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, return 0; } -/* Get Nth argument at function call */ -extern unsigned long regs_get_argument_nth(struct pt_regs *regs, - unsigned int n); - /* * These are defined as per linux/ptrace.h, which see. */ diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 017d937639fe..73554a3aae8c 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -140,30 +140,6 @@ static const int arg_offs_table[] = { #endif }; -/** - * regs_get_argument_nth() - get Nth argument at function call - * @regs: pt_regs which contains registers at function entry. - * @n: argument number. - * - * regs_get_argument_nth() returns @n th argument of a function call. - * Since usually the kernel stack will be changed right after function entry, - * you must use this at function entry. If the @n th entry is NOT in the - * kernel stack or pt_regs, this returns 0. - */ -unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n) -{ - if (n < ARRAY_SIZE(arg_offs_table)) - return *(unsigned long *)((char *)regs + arg_offs_table[n]); - else { - /* - * The typical case: arg n is on the stack. - * (Note: stack[0] = return address, so skip it) - */ - n -= ARRAY_SIZE(arg_offs_table); - return regs_get_kernel_stack_nth(regs, 1 + n); - } -} - /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. -- GitLab From bbaa46fac6d1c652bfa6282420d36a44bdc53b64 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:47:03 -0500 Subject: [PATCH 0644/3892] perf probe: Remove newline from die() Remove newline from die(), because it is automatically added. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20100105224703.19431.42475.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/util/probe-finder.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 4b852c0d16a5..6402798337c8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -402,11 +402,11 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) } else if (op == DW_OP_regx) { regn = loc->lr_number; } else - die("Dwarf_OP %d is not supported.\n", op); + die("Dwarf_OP %d is not supported.", op); regs = get_arch_regstr(regn); if (!regs) - die("%lld exceeds max register number.\n", regn); + die("%lld exceeds max register number.", regn); if (deref) ret = snprintf(pf->buf, pf->len, @@ -438,7 +438,7 @@ static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) return ; error: die("Failed to find the location of %s at this address.\n" - " Perhaps, it has been optimized out.\n", pf->var); + " Perhaps, it has been optimized out.", pf->var); } static int variable_callback(struct die_link *dlink, void *data) @@ -476,7 +476,7 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) /* Search child die for local variables and parameters. */ ret = search_die_from_children(sp_die, variable_callback, pf); if (!ret) - die("Failed to find '%s' in this function.\n", pf->var); + die("Failed to find '%s' in this function.", pf->var); } /* Get a frame base on the address */ @@ -602,7 +602,7 @@ static void find_by_line(struct probe_finder *pf) ret = search_die_from_children(pf->cu_die, probeaddr_callback, pf); if (ret == 0) - die("Probe point is not found in subprograms.\n"); + die("Probe point is not found in subprograms."); /* Continuing, because target line might be inlined. */ } dwarf_srclines_dealloc(__dw_debug, lines, cnt); @@ -661,7 +661,7 @@ static int probefunc_callback(struct die_link *dlink, void *data) !die_inlined_subprogram(lk->die)) goto found; } - die("Failed to find real subprogram.\n"); + die("Failed to find real subprogram."); found: /* Get offset from subprogram */ ret = die_within_subprogram(lk->die, pf->addr, &offs); -- GitLab From 72041334b8c75ae7e1da2f17ba2b7afee8f2abd7 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:47:10 -0500 Subject: [PATCH 0645/3892] perf probe: Show probe list in pager Show probe list in pager, because the list can be longer than a page. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20100105224710.19431.61542.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/util/probe-event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8e532d9824f0..a22141a773bc 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -37,6 +37,7 @@ #include "string.h" #include "strlist.h" #include "debug.h" +#include "cache.h" #include "parse-events.h" /* For debugfs_path */ #include "probe-event.h" @@ -455,6 +456,8 @@ void show_perf_probe_events(void) struct strlist *rawlist; struct str_node *ent; + setup_pager(); + fd = open_kprobe_events(O_RDONLY, 0); rawlist = get_trace_kprobe_event_rawlist(fd); close(fd); -- GitLab From fb1d2edf7ee25a26ad0b238d0ee335a3b28b7aa3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:47:17 -0500 Subject: [PATCH 0646/3892] perf tools: Support tracepoint glob matching Support glob wildcard when selecting tracepoint events by -e option. Without this patch, perf-tools supports 'GROUP:*:record' syntax for selecting all tracepoints under GROUP group. With this patch, user can choose tracepoints more flexibly by using partial wildcards, e.g. 'block:*bio*:record'. Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20100105224717.19431.68972.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/util/parse-events.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 609d5a9470c5..05d0c5c2030c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -450,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name, /* sys + ':' + event + ':' + flags*/ #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) static enum event_result -parse_subsystem_tracepoint_event(char *sys_name, char *flags) +parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, + char *flags) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; @@ -474,6 +475,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags) || !strcmp(evt_ent->d_name, "filter")) continue; + if (!strglobmatch(evt_ent->d_name, evt_exp)) + continue; + len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, evt_ent->d_name, flags ? ":" : "", flags ?: ""); @@ -522,9 +526,10 @@ static enum event_result parse_tracepoint_event(const char **strp, if (evt_length >= MAX_EVENT_LENGTH) return EVT_FAILED; - if (!strcmp(evt_name, "*")) { + if (strpbrk(evt_name, "*?")) { *strp = evt_name + evt_length; - return parse_subsystem_tracepoint_event(sys_name, flags); + return parse_multiple_tracepoint_event(sys_name, evt_name, + flags); } else return parse_single_tracepoint_event(sys_name, evt_name, evt_length, flags, -- GitLab From 6964cd2c8efe6e048401f1fe3952a06c563c34c1 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 5 Jan 2010 17:47:24 -0500 Subject: [PATCH 0647/3892] perf tools: Enhance glob string matching Enhance strglobmatch() for supporting character classes([CHARS], complementation and ranges are also supported) and escaped special characters (\*, \? etc). Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20100105224724.19431.56271.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/util/string.c | 65 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 5352d7dccc61..c397d4f6f748 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -227,16 +227,73 @@ fail: return NULL; } -/* Glob expression pattern matching */ +/* Character class matching */ +static bool __match_charclass(const char *pat, char c, const char **npat) +{ + bool complement = false, ret = true; + + if (*pat == '!') { + complement = true; + pat++; + } + if (*pat++ == c) /* First character is special */ + goto end; + + while (*pat && *pat != ']') { /* Matching */ + if (*pat == '-' && *(pat + 1) != ']') { /* Range */ + if (*(pat - 1) <= c && c <= *(pat + 1)) + goto end; + if (*(pat - 1) > *(pat + 1)) + goto error; + pat += 2; + } else if (*pat++ == c) + goto end; + } + if (!*pat) + goto error; + ret = false; + +end: + while (*pat && *pat != ']') /* Searching closing */ + pat++; + if (!*pat) + goto error; + *npat = pat + 1; + return complement ? !ret : ret; + +error: + return false; +} + +/** + * strglobmatch - glob expression pattern matching + * @str: the target string to match + * @pat: the pattern string to match + * + * This returns true if the @str matches @pat. @pat can includes wildcards + * ('*','?') and character classes ([CHARS], complementation and ranges are + * also supported). Also, this supports escape character ('\') to use special + * characters as normal character. + * + * Note: if @pat syntax is broken, this always returns false. + */ bool strglobmatch(const char *str, const char *pat) { while (*str && *pat && *pat != '*') { - if (*pat == '?') { + if (*pat == '?') { /* Matches any single character */ str++; pat++; - } else - if (*str++ != *pat++) + continue; + } else if (*pat == '[') /* Character classes/Ranges */ + if (__match_charclass(pat + 1, *str, &pat)) { + str++; + continue; + } else return false; + else if (*pat == '\\') /* Escaped char match as normal char */ + pat++; + if (*str++ != *pat++) + return false; } /* Check wild card */ if (*pat == '*') { -- GitLab From 631c9def804b2c92b5cca04fb9ff7b5df9e35094 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 6 Jan 2010 09:45:34 -0500 Subject: [PATCH 0648/3892] perf probe: Support --line option to show probable source-code lines Add --line option to support showing probable source-code lines. perf probe --line SRC:LN[-LN|+NUM] or perf probe --line FUNC[:LN[-LN|+NUM]] This option shows source-code with line number if the line can be probed. Lines without line number (and blue color) means that the line can not be probed, because debuginfo doesn't have the information of those lines. The argument specifies the range of lines, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. e.g. # ./perf probe --line kernel/sched.c:1080 * * called with rq->lock held and irqs disabled */ static void hrtick_start(struct rq *rq, u64 delay) { struct hrtimer *timer = &rq->hrtick_timer; 1086 ktime_t time = ktime_add_ns(timer->base->get_time(), delay); hrtimer_set_expires(timer, time); 1090 if (rq == this_rq()) { 1091 hrtimer_restart(timer); 1092 } else if (!rq->hrtick_csd_pending) { 1093 __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 1094 rq->hrtick_csd_pending = 1; If you specifying function name, this shows function-relative line number. # ./perf probe --line schedule asmlinkage void __sched schedule(void) 1 { struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; need_resched: preempt_disable(); 9 cpu = smp_processor_id(); 10 rq = cpu_rq(cpu); 11 rcu_sched_qs(cpu); 12 prev = rq->curr; 13 switch_count = &prev->nivcsw; Signed-off-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: systemtap Cc: DLE Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20100106144534.27218.77939.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf-probe.txt | 20 +++ tools/perf/builtin-probe.c | 76 ++++++++-- tools/perf/util/probe-event.c | 100 +++++++++++++ tools/perf/util/probe-event.h | 2 + tools/perf/util/probe-finder.c | 191 +++++++++++++++++++++++- tools/perf/util/probe-finder.h | 31 ++++ 6 files changed, 402 insertions(+), 18 deletions(-) diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 250e391b4bc8..2de34075f6a4 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -15,6 +15,8 @@ or 'perf probe' [options] --del='[GROUP:]EVENT' [...] or 'perf probe' --list +or +'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' DESCRIPTION ----------- @@ -45,6 +47,11 @@ OPTIONS --list:: List up current probe events. +-L:: +--line=:: + Show source code lines which can be probed. This needs an argument + which specifies a range of the source code. + PROBE SYNTAX ------------ Probe points are defined by following syntax. @@ -56,6 +63,19 @@ Probe points are defined by following syntax. It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). +LINE SYNTAX +----------- +Line range is descripted by following syntax. + + "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]" + +FUNC specifies the function name of showing lines. 'RLN' is the start line +number from function entry line, and 'RLN2' is the end line number. As same as +probe syntax, 'SRC' means the source file path, 'ALN' is start line number, +and 'ALN2' is end line number in the file. It is also possible to specify how +many lines to show by using 'NUM'. +So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. + SEE ALSO -------- linkperf:perf-trace[1], linkperf:perf-record[1] diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index ffdd3fe87b4a..1d3a99ea5ce1 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -55,11 +55,13 @@ static struct { bool need_dwarf; bool list_events; bool force_add; + bool show_lines; int nr_probe; struct probe_point probes[MAX_PROBES]; struct strlist *dellist; struct perf_session *psession; struct map *kmap; + struct line_range line_range; } session; @@ -116,6 +118,15 @@ static int opt_del_probe_event(const struct option *opt __used, return 0; } +static int opt_show_lines(const struct option *opt __used, + const char *str, int unset __used) +{ + if (str) + parse_line_range_desc(str, &session.line_range); + INIT_LIST_HEAD(&session.line_range.line_list); + session.show_lines = true; + return 0; +} /* Currently just checking function name from symbol map */ static void evaluate_probe_point(struct probe_point *pp) { @@ -144,6 +155,7 @@ static const char * const probe_usage[] = { "perf probe [] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", "perf probe [] --del '[GROUP:]EVENT' ...", "perf probe --list", + "perf probe --line 'LINEDESC'", NULL }; @@ -182,9 +194,32 @@ static const struct option options[] = { opt_add_probe_event), OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" " with existing name"), +#ifndef NO_LIBDWARF + OPT_CALLBACK('L', "line", NULL, + "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", + "Show source code lines.", opt_show_lines), +#endif OPT_END() }; +/* Initialize symbol maps for vmlinux */ +static void init_vmlinux(void) +{ + symbol_conf.sort_by_name = true; + if (symbol_conf.vmlinux_name == NULL) + symbol_conf.try_vmlinux_path = true; + else + pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); + if (symbol__init() < 0) + die("Failed to init symbol map."); + session.psession = perf_session__new(NULL, O_WRONLY, false); + if (session.psession == NULL) + die("Failed to init perf_session."); + session.kmap = session.psession->vmlinux_maps[MAP__FUNCTION]; + if (!session.kmap) + die("Could not find kernel map.\n"); +} + int cmd_probe(int argc, const char **argv, const char *prefix __used) { int i, ret; @@ -203,7 +238,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) parse_probe_event_argv(argc, argv); } - if ((!session.nr_probe && !session.dellist && !session.list_events)) + if ((!session.nr_probe && !session.dellist && !session.list_events && + !session.show_lines)) usage_with_options(probe_usage, options); if (debugfs_valid_mountpoint(debugfs_path) < 0) @@ -215,10 +251,34 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) " --add/--del.\n"); usage_with_options(probe_usage, options); } + if (session.show_lines) { + pr_warning(" Error: Don't use --list with --line.\n"); + usage_with_options(probe_usage, options); + } show_perf_probe_events(); return 0; } +#ifndef NO_LIBDWARF + if (session.show_lines) { + if (session.nr_probe != 0 || session.dellist) { + pr_warning(" Error: Don't use --line with" + " --add/--del.\n"); + usage_with_options(probe_usage, options); + } + init_vmlinux(); + fd = open_vmlinux(); + if (fd < 0) + die("Could not open debuginfo file."); + ret = find_line_range(fd, &session.line_range); + if (ret <= 0) + die("Source line is not found.\n"); + close(fd); + show_line_range(&session.line_range); + return 0; + } +#endif + if (session.dellist) { del_trace_kprobe_events(session.dellist); strlist__delete(session.dellist); @@ -226,18 +286,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) return 0; } - /* Initialize symbol maps for vmlinux */ - symbol_conf.sort_by_name = true; - if (symbol_conf.vmlinux_name == NULL) - symbol_conf.try_vmlinux_path = true; - if (symbol__init() < 0) - die("Failed to init symbol map."); - session.psession = perf_session__new(NULL, O_WRONLY, false); - if (session.psession == NULL) - die("Failed to init perf_session."); - session.kmap = session.psession->vmlinux_maps[MAP__FUNCTION]; - if (!session.kmap) - die("Could not find kernel map.\n"); + /* Add probes */ + init_vmlinux(); if (session.need_dwarf) #ifdef NO_LIBDWARF diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a22141a773bc..71b0dd590a37 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -38,6 +38,7 @@ #include "strlist.h" #include "debug.h" #include "cache.h" +#include "color.h" #include "parse-events.h" /* For debugfs_path */ #include "probe-event.h" @@ -63,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) return ret; } +void parse_line_range_desc(const char *arg, struct line_range *lr) +{ + const char *ptr; + char *tmp; + /* + * + * SRC:SLN[+NUM|-ELN] + * FUNC[:SLN[+NUM|-ELN]] + */ + ptr = strchr(arg, ':'); + if (ptr) { + lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); + if (*tmp == '+') + lr->end = lr->start + (unsigned int)strtoul(tmp + 1, + &tmp, 0); + else if (*tmp == '-') + lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); + else + lr->end = 0; + pr_debug("Line range is %u to %u\n", lr->start, lr->end); + if (lr->end && lr->start > lr->end) + semantic_error("Start line must be smaller" + " than end line."); + if (*tmp != '\0') + semantic_error("Tailing with invalid character '%d'.", + *tmp); + tmp = strndup(arg, (ptr - arg)); + } else + tmp = strdup(arg); + + if (strchr(tmp, '.')) + lr->file = tmp; + else + lr->function = tmp; +} + /* Check the name is good for event/group */ static bool check_event_name(const char *name) { @@ -678,3 +715,66 @@ void del_trace_kprobe_events(struct strlist *dellist) close(fd); } +#define LINEBUF_SIZE 256 + +static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) +{ + char buf[LINEBUF_SIZE]; + const char *color = PERF_COLOR_BLUE; + + if (fgets(buf, LINEBUF_SIZE, fp) == NULL) + goto error; + if (!skip) { + if (show_num) + fprintf(stdout, "%7u %s", l, buf); + else + color_fprintf(stdout, color, " %s", buf); + } + + while (strlen(buf) == LINEBUF_SIZE - 1 && + buf[LINEBUF_SIZE - 2] != '\n') { + if (fgets(buf, LINEBUF_SIZE, fp) == NULL) + goto error; + if (!skip) { + if (show_num) + fprintf(stdout, "%s", buf); + else + color_fprintf(stdout, color, "%s", buf); + } + } + return; +error: + if (feof(fp)) + die("Source file is shorter than expected."); + else + die("File read error: %s", strerror(errno)); +} + +void show_line_range(struct line_range *lr) +{ + unsigned int l = 1; + struct line_node *ln; + FILE *fp; + + setup_pager(); + + if (lr->function) + fprintf(stdout, "<%s:%d>\n", lr->function, + lr->start - lr->offset); + else + fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); + + fp = fopen(lr->path, "r"); + if (fp == NULL) + die("Failed to open %s: %s", lr->path, strerror(errno)); + /* Skip to starting line number */ + while (l < lr->start) + show_one_line(fp, l++, true, false); + + list_for_each_entry(ln, &lr->line_list, list) { + while (ln->line > l) + show_one_line(fp, (l++) - lr->offset, false, false); + show_one_line(fp, (l++) - lr->offset, false, true); + } + fclose(fp); +} diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 7f1d499118c0..711287d4baea 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -5,6 +5,7 @@ #include "probe-finder.h" #include "strlist.h" +extern void parse_line_range_desc(const char *arg, struct line_range *lr); extern void parse_perf_probe_event(const char *str, struct probe_point *pp, bool *need_dwarf); extern int synthesize_perf_probe_point(struct probe_point *pp); @@ -15,6 +16,7 @@ extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, bool force_add); extern void del_trace_kprobe_events(struct strlist *dellist); extern void show_perf_probe_events(void); +extern void show_line_range(struct line_range *lr); /* Maximum index number of event-name postfix */ #define MAX_EVENT_INDEX 1024 diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 6402798337c8..1b2124d12f68 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -140,6 +140,31 @@ static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) return found; } +static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) +{ + Dwarf_Signed cnt, i; + char **srcs; + int ret = 0; + + if (!buf || !fno) + return -EINVAL; + + ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); + if (ret == DW_DLV_OK) { + if ((Dwarf_Unsigned)cnt > fno - 1) { + *buf = strdup(srcs[fno - 1]); + ret = 0; + pr_debug("found filename: %s\n", *buf); + } else + ret = -ENOENT; + for (i = 0; i < cnt; i++) + dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); + dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); + } else + ret = -EINVAL; + return ret; +} + /* Compare diename and tname */ static int die_compare_name(Dwarf_Die dw_die, const char *tname) { @@ -567,7 +592,7 @@ static int probeaddr_callback(struct die_link *dlink, void *data) } /* Find probe point from its line number */ -static void find_by_line(struct probe_finder *pf) +static void find_probe_point_by_line(struct probe_finder *pf) { Dwarf_Signed cnt, i, clm; Dwarf_Line *lines; @@ -626,7 +651,7 @@ static int probefunc_callback(struct die_link *dlink, void *data) pf->fno = die_get_decl_file(dlink->die); pf->lno = die_get_decl_line(dlink->die) + pp->line; - find_by_line(pf); + find_probe_point_by_line(pf); return 1; } if (die_inlined_subprogram(dlink->die)) { @@ -673,7 +698,7 @@ found: return 0; } -static void find_by_func(struct probe_finder *pf) +static void find_probe_point_by_func(struct probe_finder *pf) { search_die_from_children(pf->cu_die, probefunc_callback, pf); } @@ -714,10 +739,10 @@ int find_probepoint(int fd, struct probe_point *pp) if (ret == DW_DLV_NO_ENTRY) pf.cu_base = 0; if (pp->function) - find_by_func(&pf); + find_probe_point_by_func(&pf); else { pf.lno = pp->line; - find_by_line(&pf); + find_probe_point_by_line(&pf); } } dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); @@ -728,3 +753,159 @@ int find_probepoint(int fd, struct probe_point *pp) return pp->found; } + +static void line_range_add_line(struct line_range *lr, unsigned int line) +{ + struct line_node *ln; + struct list_head *p; + + /* Reverse search, because new line will be the last one */ + list_for_each_entry_reverse(ln, &lr->line_list, list) { + if (ln->line < line) { + p = &ln->list; + goto found; + } else if (ln->line == line) /* Already exist */ + return ; + } + /* List is empty, or the smallest entry */ + p = &lr->line_list; +found: + pr_debug("Debug: add a line %u\n", line); + ln = zalloc(sizeof(struct line_node)); + DIE_IF(ln == NULL); + ln->line = line; + INIT_LIST_HEAD(&ln->list); + list_add(&ln->list, p); +} + +/* Find line range from its line number */ +static void find_line_range_by_line(struct line_finder *lf) +{ + Dwarf_Signed cnt, i; + Dwarf_Line *lines; + Dwarf_Unsigned lineno = 0; + Dwarf_Unsigned fno; + Dwarf_Addr addr; + int ret; + + ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + + for (i = 0; i < cnt; i++) { + ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + if (fno != lf->fno) + continue; + + ret = dwarf_lineno(lines[i], &lineno, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + if (lf->lno_s > lineno || lf->lno_e < lineno) + continue; + + /* Filter line in the function address range */ + if (lf->addr_s && lf->addr_e) { + ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + if (lf->addr_s > addr || lf->addr_e <= addr) + continue; + } + line_range_add_line(lf->lr, (unsigned int)lineno); + } + dwarf_srclines_dealloc(__dw_debug, lines, cnt); + if (!list_empty(&lf->lr->line_list)) + lf->found = 1; +} + +/* Search function from function name */ +static int linefunc_callback(struct die_link *dlink, void *data) +{ + struct line_finder *lf = (struct line_finder *)data; + struct line_range *lr = lf->lr; + Dwarf_Half tag; + int ret; + + ret = dwarf_tag(dlink->die, &tag, &__dw_error); + DIE_IF(ret == DW_DLV_ERROR); + if (tag == DW_TAG_subprogram && + die_compare_name(dlink->die, lr->function) == 0) { + /* Get the address range of this function */ + ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error); + if (ret == DW_DLV_OK) + ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error); + DIE_IF(ret == DW_DLV_ERROR); + if (ret == DW_DLV_NO_ENTRY) { + lf->addr_s = 0; + lf->addr_e = 0; + } + + lf->fno = die_get_decl_file(dlink->die); + lr->offset = die_get_decl_line(dlink->die);; + lf->lno_s = lr->offset + lr->start; + if (!lr->end) + lf->lno_e = (Dwarf_Unsigned)-1; + else + lf->lno_e = lr->offset + lr->end; + lr->start = lf->lno_s; + lr->end = lf->lno_e; + find_line_range_by_line(lf); + /* If we find a target function, this should be end. */ + lf->found = 1; + return 1; + } + return 0; +} + +static void find_line_range_by_func(struct line_finder *lf) +{ + search_die_from_children(lf->cu_die, linefunc_callback, lf); +} + +int find_line_range(int fd, struct line_range *lr) +{ + Dwarf_Half addr_size = 0; + Dwarf_Unsigned next_cuh = 0; + int ret; + struct line_finder lf = {.lr = lr}; + + ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); + if (ret != DW_DLV_OK) + return -ENOENT; + + while (!lf.found) { + /* Search CU (Compilation Unit) */ + ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, + &addr_size, &next_cuh, &__dw_error); + DIE_IF(ret == DW_DLV_ERROR); + if (ret == DW_DLV_NO_ENTRY) + break; + + /* Get the DIE(Debugging Information Entry) of this CU */ + ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + + /* Check if target file is included. */ + if (lr->file) + lf.fno = cu_find_fileno(lf.cu_die, lr->file); + + if (!lr->file || lf.fno) { + if (lr->function) + find_line_range_by_func(&lf); + else { + lf.lno_s = lr->start; + if (!lr->end) + lf.lno_e = (Dwarf_Unsigned)-1; + else + lf.lno_e = lr->end; + find_line_range_by_line(&lf); + } + /* Get the real file path */ + if (lf.found) + cu_get_filename(lf.cu_die, lf.fno, &lr->path); + } + dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE); + } + ret = dwarf_finish(__dw_debug, &__dw_error); + DIE_IF(ret != DW_DLV_OK); + return lf.found; +} + diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index e3f396806e6e..972b386116f1 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -34,8 +34,26 @@ struct probe_point { char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ }; +/* Line number container */ +struct line_node { + struct list_head list; + unsigned int line; +}; + +/* Line range */ +struct line_range { + char *file; /* File name */ + char *function; /* Function name */ + unsigned int start; /* Start line number */ + unsigned int end; /* End line number */ + unsigned int offset; /* Start line offset */ + char *path; /* Real path name */ + struct list_head line_list; /* Visible lines */ +}; + #ifndef NO_LIBDWARF extern int find_probepoint(int fd, struct probe_point *pp); +extern int find_line_range(int fd, struct line_range *lr); /* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ #ifndef _MIPS_SZLONG @@ -62,6 +80,19 @@ struct probe_finder { char *buf; /* Current output buffer */ int len; /* Length of output buffer */ }; + +struct line_finder { + struct line_range *lr; /* Target line range */ + + Dwarf_Unsigned fno; /* File number */ + Dwarf_Unsigned lno_s; /* Start line number */ + Dwarf_Unsigned lno_e; /* End line number */ + Dwarf_Addr addr_s; /* Start address */ + Dwarf_Addr addr_e; /* End address */ + Dwarf_Die cu_die; /* Current CU */ + int found; +}; + #endif /* NO_LIBDWARF */ #endif /*_PROBE_FINDER_H */ -- GitLab From 8d9e503928638fc95317be42c416fb7907322aff Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 7 Jan 2010 19:40:47 +0300 Subject: [PATCH 0649/3892] perf: Fix memory leak: counterwidth Signed-off-by: Alexander Beregalov Cc: a.p.zijlstra@chello.nl Cc: paulus@samba.org LKML-Reference: <1262882447-23776-2-git-send-email-a.beregalov@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/values.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 1c15e39f99e3..cfa55d686e3b 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp, counterwidth[j], values->value[i][j]); fprintf(fp, "\n"); } + free(counterwidth); } static void perf_read_values__display_raw(FILE *fp, -- GitLab From fed5af61dc0d9402d26e7fb8fb9731a60a8e05ca Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jan 2010 19:59:38 -0200 Subject: [PATCH 0650/3892] perf buildid-list: No need to process the header sections again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it is already processed by: perf_session__new perf_session__open perf_session__read This was harmless, because we use dsos__findnew, that would already find it, but is unnecessary work and removing it makes builtin-buildid-list.c even shorter. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262901583-8074-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-buildid-list.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 1e99ac806913..4229c2c213cc 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -31,26 +31,6 @@ static const struct option options[] = { OPT_END() }; -static int perf_file_section__process_buildids(struct perf_file_section *self, - int feat, int fd) -{ - if (feat != HEADER_BUILD_ID) - return 0; - - if (lseek(fd, self->offset, SEEK_SET) < 0) { - pr_warning("Failed to lseek to %Ld offset for buildids!\n", - self->offset); - return -1; - } - - if (perf_header__read_build_ids(fd, self->offset, self->size)) { - pr_warning("Failed to read buildids!\n"); - return -1; - } - - return 0; -} - static int __cmd_buildid_list(void) { int err = -1; @@ -60,10 +40,7 @@ static int __cmd_buildid_list(void) if (session == NULL) return -1; - err = perf_header__process_sections(&session->header, session->fd, - perf_file_section__process_buildids); - if (err >= 0) - dsos__fprintf_buildid(stdout); + dsos__fprintf_buildid(stdout); perf_session__delete(session); return err; -- GitLab From a89e5abe3efcc7facc666d3985769278937f86b0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jan 2010 19:59:39 -0200 Subject: [PATCH 0651/3892] perf symbols: Record the domain of DSOs in HEADER_BUILD_ID header table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that we can restore them to the right DSO list (either dsos__kernel or dsos__user). We do that just like the kernel does for the other events, encoding PERF_RECORD_MISC_{KERNEL,USER} in perf_event_header. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262901583-8074-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 9 ++++++--- tools/perf/util/session.c | 6 +++++- tools/perf/util/symbol.c | 6 +++--- tools/perf/util/symbol.h | 11 +++++++++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 942f7da8bf84..ec96321eb9e4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -193,7 +193,7 @@ static int write_padded(int fd, const void *bf, size_t count, continue; \ else -static int __dsos__write_buildid_table(struct list_head *head, int fd) +static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) { struct dso *pos; @@ -205,6 +205,7 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) len = ALIGN(len, NAME_ALIGN); memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); + b.header.misc = misc; b.header.size = sizeof(b) + len; err = do_write(fd, &b, sizeof(b)); if (err < 0) @@ -220,9 +221,11 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) static int dsos__write_buildid_table(int fd) { - int err = __dsos__write_buildid_table(&dsos__kernel, fd); + int err = __dsos__write_buildid_table(&dsos__kernel, + PERF_RECORD_MISC_KERNEL, fd); if (err == 0) - err = __dsos__write_buildid_table(&dsos__user, fd); + err = __dsos__write_buildid_table(&dsos__user, + PERF_RECORD_MISC_USER, fd); return err; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e0e6a075489e..378ac5422bcf 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -255,6 +255,7 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) while (offset < limit) { struct dso *dso; ssize_t len; + struct list_head *head = &dsos__user; if (read(input, &bev, sizeof(bev)) != sizeof(bev)) goto out; @@ -263,7 +264,10 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) if (read(input, filename, len) != len) goto out; - dso = dsos__findnew(filename); + if (bev.header.misc & PERF_RECORD_MISC_KERNEL) + head = &dsos__kernel; + + dso = __dsos__findnew(head, filename); if (dso != NULL) dso__set_build_id(dso, &bev.build_id); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index da2f07f1af8f..8e6627e6b778 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1615,14 +1615,14 @@ static struct dso *dsos__find(struct list_head *head, const char *name) return NULL; } -struct dso *dsos__findnew(const char *name) +struct dso *__dsos__findnew(struct list_head *head, const char *name) { - struct dso *dso = dsos__find(&dsos__user, name); + struct dso *dso = dsos__find(head, name); if (!dso) { dso = dso__new(name); if (dso != NULL) { - dsos__add(&dsos__user, dso); + dsos__add(head, dso); dso__set_basename(dso); } } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b2b5330a82a0..ee0b4593db7b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -115,9 +115,17 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type); void dso__sort_by_name(struct dso *self, enum map_type type); +extern struct list_head dsos__user, dsos__kernel; + +struct dso *__dsos__findnew(struct list_head *head, const char *name); + +static inline struct dso *dsos__findnew(const char *name) +{ + return __dsos__findnew(&dsos__user, name); +} + struct perf_session; -struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, struct perf_session *session, symbol_filter_t filter); void dsos__fprintf(FILE *fp); @@ -143,6 +151,5 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type); int perf_session__create_kernel_maps(struct perf_session *self); -extern struct list_head dsos__user, dsos__kernel; extern struct dso *vdso; #endif /* __PERF_SYMBOL */ -- GitLab From cf5531148ff34938840d6da775c0a4ace442d573 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jan 2010 19:59:40 -0200 Subject: [PATCH 0652/3892] perf tools: Create typedef for common event synthesizing callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1262901583-8074-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 16 +++++----------- tools/perf/util/event.h | 12 +++++------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1a31feb9999f..bfb3d872b9f5 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -8,8 +8,7 @@ #include "thread.h" static pid_t event__synthesize_comm(pid_t pid, int full, - int (*process)(event_t *event, - struct perf_session *session), + event__handler_t process, struct perf_session *session) { event_t ev; @@ -91,8 +90,7 @@ out_failure: } static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, - int (*process)(event_t *event, - struct perf_session *session), + event__handler_t process, struct perf_session *session) { char filename[PATH_MAX]; @@ -156,9 +154,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, return 0; } -int event__synthesize_thread(pid_t pid, - int (*process)(event_t *event, - struct perf_session *session), +int event__synthesize_thread(pid_t pid, event__handler_t process, struct perf_session *session) { pid_t tgid = event__synthesize_comm(pid, 1, process, session); @@ -167,8 +163,7 @@ int event__synthesize_thread(pid_t pid, return event__synthesize_mmap_events(pid, tgid, process, session); } -void event__synthesize_threads(int (*process)(event_t *event, - struct perf_session *session), +void event__synthesize_threads(event__handler_t process, struct perf_session *session) { DIR *proc; @@ -205,8 +200,7 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start) return 1; } -int event__synthesize_kernel_mmap(int (*process)(event_t *event, - struct perf_session *session), +int event__synthesize_kernel_mmap(event__handler_t process, struct perf_session *session, const char *symbol_name) { diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 61fc0dc658c2..80356da8216c 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -103,15 +103,13 @@ void event__print_totals(void); struct perf_session; -int event__synthesize_thread(pid_t pid, - int (*process)(event_t *event, - struct perf_session *session), +typedef int (*event__handler_t)(event_t *event, struct perf_session *session); + +int event__synthesize_thread(pid_t pid, event__handler_t process, struct perf_session *session); -void event__synthesize_threads(int (*process)(event_t *event, - struct perf_session *session), +void event__synthesize_threads(event__handler_t process, struct perf_session *session); -int event__synthesize_kernel_mmap(int (*process)(event_t *event, - struct perf_session *session), +int event__synthesize_kernel_mmap(event__handler_t process, struct perf_session *session, const char *symbol_name); -- GitLab From a0ab36689a36e583b6e736f1c99ac8c9aebdad59 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 18:31:48 +0900 Subject: [PATCH 0653/3892] sh: fixed PMB mode refactoring. This introduces some much overdue chainsawing of the fixed PMB support. fixed PMB was introduced initially to work around the fact that dynamic PMB mode was relatively broken, though they were never intended to converge. The main areas where there are differences are whether the system is booted in 29-bit mode or 32-bit mode, and whether legacy mappings are to be preserved. Any system booting in true 32-bit mode will not care about legacy mappings, so these are roughly decoupled. Regardless of the entry point, PMB and 32BIT are directly related as far as the kernel is concerned, so we also switch back to having one select the other. With legacy mappings iterated through and applied in the initialization path it's now possible to finally merge the two implementations and permit dynamic remapping overtop of remaining entries regardless of whether boot mappings are crafted by hand or inherited from the boot loader. Signed-off-by: Paul Mundt --- arch/sh/boot/Makefile | 9 +-- arch/sh/include/asm/addrspace.h | 4 +- arch/sh/include/asm/io.h | 27 +++++--- arch/sh/include/asm/mmu.h | 18 ++++++ arch/sh/include/asm/page.h | 2 +- arch/sh/kernel/head_32.S | 4 +- arch/sh/kernel/setup.c | 3 - arch/sh/kernel/vmlinux.lds.S | 15 +++-- arch/sh/mm/Kconfig | 24 ++------ arch/sh/mm/Makefile | 2 +- arch/sh/mm/pmb.c | 106 ++++++++++++++++++-------------- 11 files changed, 117 insertions(+), 97 deletions(-) diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile index 743ce0c8d98d..1ce63624c9b9 100644 --- a/arch/sh/boot/Makefile +++ b/arch/sh/boot/Makefile @@ -46,15 +46,8 @@ $(obj)/romImage: $(obj)/romimage/vmlinux FORCE $(obj)/romimage/vmlinux: $(obj)/zImage FORCE $(Q)$(MAKE) $(build)=$(obj)/romimage $@ -KERNEL_MEMORY := 0x00000000 -ifeq ($(CONFIG_PMB_FIXED),y) -KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \ +KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \ $$[$(CONFIG_MEMORY_START) & 0x1fffffff]') -endif -ifeq ($(CONFIG_29BIT),y) -KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \ - $$[$(CONFIG_MEMORY_START)]') -endif KERNEL_LOAD := $(shell /bin/bash -c 'printf "0x%08x" \ $$[$(CONFIG_PAGE_OFFSET) + \ diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h index 99d6b3ecbe22..bcd7d4d78f6b 100644 --- a/arch/sh/include/asm/addrspace.h +++ b/arch/sh/include/asm/addrspace.h @@ -28,7 +28,7 @@ /* Returns the privileged segment base of a given address */ #define PXSEG(a) (((unsigned long)(a)) & 0xe0000000) -#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED) +#ifdef CONFIG_29BIT /* * Map an address to a certain privileged segment */ @@ -40,7 +40,7 @@ ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG)) #define P4SEGADDR(a) \ ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG)) -#endif /* 29BIT || PMB_FIXED */ +#endif /* 29BIT */ #endif /* P1SEG */ /* Check if an address can be reached in 29 bits */ diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 026dd659a640..f4314d8b05b8 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -244,18 +244,11 @@ __ioremap(unsigned long offset, unsigned long size, unsigned long flags) } static inline void __iomem * -__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) +__ioremap_29bit(unsigned long offset, unsigned long size, unsigned long flags) { -#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB) +#ifdef CONFIG_29BIT unsigned long last_addr = offset + size - 1; -#endif - void __iomem *ret; - ret = __ioremap_trapped(offset, size); - if (ret) - return ret; - -#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB) /* * For P1 and P2 space this is trivial, as everything is already * mapped. Uncached access for P1 addresses are done through P2. @@ -274,6 +267,22 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) return (void __iomem *)P4SEGADDR(offset); #endif + return NULL; +} + +static inline void __iomem * +__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) +{ + void __iomem *ret; + + ret = __ioremap_trapped(offset, size); + if (ret) + return ret; + + ret = __ioremap_29bit(offset, size, flags); + if (ret) + return ret; + return __ioremap(offset, size, flags); } #else diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index c7426ad9926e..4b0882bf5183 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h @@ -65,11 +65,29 @@ struct pmb_entry { struct pmb_entry *link; }; +#ifdef CONFIG_PMB /* arch/sh/mm/pmb.c */ long pmb_remap(unsigned long virt, unsigned long phys, unsigned long size, unsigned long flags); void pmb_unmap(unsigned long addr); int pmb_init(void); +#else +static inline long pmb_remap(unsigned long virt, unsigned long phys, + unsigned long size, unsigned long flags) +{ + return -EINVAL +} + +static inline void pmb_unmap(unsigned long addr) +{ +} + +static inline int pmb_init(void) +{ + return -ENODEV; +} +#endif /* CONFIG_PMB */ + #endif /* __ASSEMBLY__ */ #endif /* __MMU_H */ diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index 81bffc0d6860..a86c0f1d05d4 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -127,7 +127,7 @@ typedef struct page *pgtable_t; * is not visible (it is part of the PMB mapping) and so needs to be * added or subtracted as required. */ -#if defined(CONFIG_PMB_FIXED) +#if defined(CONFIG_PMB_LEGACY) /* phys = virt - PAGE_OFFSET - (__MEMORY_START & 0xe0000000) */ #define PMB_OFFSET (PAGE_OFFSET - PXSEG(__MEMORY_START)) #define __pa(x) ((unsigned long)(x) - PMB_OFFSET) diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 1151ecdffa71..e5d421db4c83 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -13,6 +13,8 @@ #include #include #include +#include +#include #ifdef CONFIG_CPU_SH4A #define SYNCO() synco @@ -33,7 +35,7 @@ ENTRY(empty_zero_page) .long 1 /* LOADER_TYPE */ .long 0x00000000 /* INITRD_START */ .long 0x00000000 /* INITRD_SIZE */ -#if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED) +#ifdef CONFIG_32BIT .long 0x53453f00 + 32 /* "SE?" = 32 bit */ #else .long 0x53453f00 + 29 /* "SE?" = 29 bit */ diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 8b0e69792cf4..f79ebe32a24a 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -455,10 +455,7 @@ void __init setup_arch(char **cmdline_p) sh_mv.mv_setup(cmdline_p); paging_init(); - -#ifdef CONFIG_PMB_ENABLE pmb_init(); -#endif #ifdef CONFIG_SMP plat_smp_setup(); diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index a1e4ec24f1f5..9e5a5878eeae 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -14,17 +14,16 @@ OUTPUT_ARCH(sh) #include #include +#if defined(CONFIG_32BIT) && !defined(CONFIG_PMB_LEGACY) +#define MEMORY_OFFSET 0 +#else +#define MEMORY_OFFSET (CONFIG_MEMORY_START & 0x1fffffff) +#endif + ENTRY(_start) SECTIONS { -#ifdef CONFIG_PMB_FIXED - . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) + - CONFIG_ZERO_PAGE_OFFSET; -#elif defined(CONFIG_32BIT) - . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET; -#else - . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET; -#endif + . = CONFIG_PAGE_OFFSET + MEMORY_OFFSET + CONFIG_ZERO_PAGE_OFFSET; _text = .; /* Text and read-only data */ diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 358c860aeb9b..860cd24b4205 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -80,30 +80,18 @@ config 32BIT bool default y if CPU_SH5 -config PMB_ENABLE - bool "Support 32-bit physical addressing through PMB" - depends on MMU && EXPERIMENTAL && CPU_SH4A && !CPU_SH4AL_DSP - help - If you say Y here, physical addressing will be extended to - 32-bits through the SH-4A PMB. If this is not set, legacy - 29-bit physical addressing will be used. - -choice - prompt "PMB handling type" - depends on PMB_ENABLE - default PMB_FIXED - config PMB - bool "PMB" + bool "Support 32-bit physical addressing through PMB" depends on MMU && EXPERIMENTAL && CPU_SH4A && !CPU_SH4AL_DSP + select 32BIT help If you say Y here, physical addressing will be extended to 32-bits through the SH-4A PMB. If this is not set, legacy 29-bit physical addressing will be used. -config PMB_FIXED - bool "fixed PMB" - depends on MMU && EXPERIMENTAL && CPU_SH4A && !CPU_SH4AL_DSP +config PMB_LEGACY + bool "Support legacy boot mappings for PMB" + depends on PMB select 32BIT help If this option is enabled, fixed PMB mappings are inherited @@ -111,8 +99,6 @@ config PMB_FIXED management. This is the closest to legacy 29-bit physical mode, and allows systems to support up to 512MiB of system memory. -endchoice - config X2TLB bool "Enable extended TLB mode" depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 9fa11d655044..edde8bdd681d 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -33,7 +33,7 @@ obj-y += $(tlb-y) endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PMB_ENABLE) += pmb.o +obj-$(CONFIG_PMB) += pmb.o obj-$(CONFIG_NUMA) += numa.o # Special flags for fault_64.o. This puts restrictions on the number of diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 280f6a166035..8f7dbf183fb0 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -3,7 +3,7 @@ * * Privileged Space Mapping Buffer (PMB) Support. * - * Copyright (C) 2005, 2006, 2007 Paul Mundt + * Copyright (C) 2005 - 2010 Paul Mundt * * P1/P2 Section mapping definitions from map32.h, which was: * @@ -279,51 +279,12 @@ static void __pmb_unmap(struct pmb_entry *pmbe) } while (pmbe); } -#ifdef CONFIG_PMB -int __uses_jump_to_uncached pmb_init(void) -{ - unsigned int i; - long size, ret; - - jump_to_uncached(); - - /* - * Insert PMB entries for the P1 and P2 areas so that, after - * we've switched the MMU to 32-bit mode, the semantics of P1 - * and P2 are the same as in 29-bit mode, e.g. - * - * P1 - provides a cached window onto physical memory - * P2 - provides an uncached window onto physical memory - */ - size = __MEMORY_START + __MEMORY_SIZE; - - ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C); - BUG_ON(ret != size); - - ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB); - BUG_ON(ret != size); - - ctrl_outl(0, PMB_IRMCR); - - /* PMB.SE and UB[7] */ - ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR); - - /* Flush out the TLB */ - i = ctrl_inl(MMUCR); - i |= MMUCR_TI; - ctrl_outl(i, MMUCR); - - back_to_cached(); - - return 0; -} -#else -int __uses_jump_to_uncached pmb_init(void) +#ifdef CONFIG_PMB_LEGACY +static int pmb_apply_legacy_mappings(void) { int i; unsigned long addr, data; - - jump_to_uncached(); + unsigned int applied = 0; for (i = 0; i < PMB_ENTRY_MAX; i++) { struct pmb_entry *pmbe; @@ -357,13 +318,69 @@ int __uses_jump_to_uncached pmb_init(void) pmbe = pmb_alloc(vpn, ppn, flags, i); WARN_ON(IS_ERR(pmbe)); + + applied++; + } + + return (applied == 0); +} +#else +static inline int pmb_apply_legacy_mappings(void) +{ + return 1; +} +#endif + +int __uses_jump_to_uncached pmb_init(void) +{ + unsigned int i; + unsigned long size, ret; + + jump_to_uncached(); + + /* + * Attempt to apply the legacy boot mappings if configured. If + * this is successful then we simply carry on with those and + * don't bother establishing additional memory mappings. Dynamic + * device mappings through pmb_remap() can still be bolted on + * after this. + */ + ret = pmb_apply_legacy_mappings(); + if (ret == 0) { + back_to_cached(); + return 0; } + /* + * Insert PMB entries for the P1 and P2 areas so that, after + * we've switched the MMU to 32-bit mode, the semantics of P1 + * and P2 are the same as in 29-bit mode, e.g. + * + * P1 - provides a cached window onto physical memory + * P2 - provides an uncached window onto physical memory + */ + size = (unsigned long)__MEMORY_START + __MEMORY_SIZE; + + ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C); + BUG_ON(ret != size); + + ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB); + BUG_ON(ret != size); + + ctrl_outl(0, PMB_IRMCR); + + /* PMB.SE and UB[7] */ + ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR); + + /* Flush out the TLB */ + i = ctrl_inl(MMUCR); + i |= MMUCR_TI; + ctrl_outl(i, MMUCR); + back_to_cached(); return 0; } -#endif /* CONFIG_PMB */ static int pmb_seq_show(struct seq_file *file, void *iter) { @@ -462,6 +479,5 @@ static int __init pmb_sysdev_init(void) { return sysdev_driver_register(&cpu_sysdev_class, &pmb_sysdev_driver); } - subsys_initcall(pmb_sysdev_init); #endif -- GitLab From 88f73d22853cb080432e91d68759323477a8b835 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 18:37:19 +0900 Subject: [PATCH 0654/3892] sh: Fix up L2 cache comment typo. Valid sizes include 256kB, not 258kB. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 75189c4691da..21371f8cf010 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -228,7 +228,7 @@ int __init detect_cpu_and_cache_system(void) * Size calculation is much more sensible * than it is for the L1. * - * Sizes are 128KB, 258KB, 512KB, and 1MB. + * Sizes are 128KB, 256KB, 512KB, and 1MB. */ size = (cvr & 0xf) << 17; -- GitLab From 8381f65d097dad90416808314737dd7d3ae38ea9 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Fri, 8 Jan 2010 15:27:33 +0000 Subject: [PATCH 0655/3892] sched/perf: Make sure irqs are disabled for perf_event_task_sched_in() perf_event_task_sched_in() expects interrupts to be disabled, but on architectures with __ARCH_WANT_INTERRUPTS_ON_CTXSW defined, this isn't true. If this is defined, disable irqs around the call in finish_task_switch(). Signed-off-by: Jamie Iles Acked-by: Peter Zijlstra Cc: Russell King - ARM Linux LKML-Reference: <1262964453-27370-1-git-send-email-jamie.iles@picochip.com> Signed-off-by: Ingo Molnar --- kernel/sched.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sched.c b/kernel/sched.c index e507af086b42..c3ad3427a2a5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2783,7 +2783,13 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) */ prev_state = prev->state; finish_arch_switch(prev); +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + local_irq_disable(); +#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ perf_event_task_sched_in(current); +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + local_irq_enable(); +#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ finish_lock_switch(rq, prev); fire_sched_in_preempt_notifiers(current); -- GitLab From 206582c3161f165f5bf49ececa962c5f95fdf0a3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 18:45:12 +0900 Subject: [PATCH 0656/3892] sh: Make all PxSEGADDR() calls fatal for non-legacy configs. This stubs out all of the PxSEGADDR() wrappers for non-legacy code. 29-bit will continue to work with these, while 32-bit code will now blow up on compile rather than at runtime. The vast majority of the in-tree offenders are gone, with the only remaining culprits being unable to support 32-bit mode. Hopefully this will prevent anyone from ever using these again. Signed-off-by: Paul Mundt --- arch/sh/include/asm/addrspace.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h index bcd7d4d78f6b..268efd62ed21 100644 --- a/arch/sh/include/asm/addrspace.h +++ b/arch/sh/include/asm/addrspace.h @@ -40,7 +40,15 @@ ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG)) #define P4SEGADDR(a) \ ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG)) -#endif /* 29BIT */ +#else +/* + * These will never work in 32-bit, don't even bother. + */ +#define P1SEGADDR(a) __futile_remapping_attempt +#define P2SEGADDR(a) __futile_remapping_attempt +#define P3SEGADDR(a) __futile_remapping_attempt +#define P4SEGADDR(a) __futile_remapping_attempt +#endif #endif /* P1SEG */ /* Check if an address can be reached in 29 bits */ -- GitLab From 9ca94d7c016130f9ed77f142424ace9c19742809 Mon Sep 17 00:00:00 2001 From: John Kacur Date: Mon, 11 Jan 2010 21:21:06 +0100 Subject: [PATCH 0657/3892] plist: Fix grammar mistake, and c-style mistake Signed-off-by: John Kacur Acked-by: Peter Zijlstra LKML-Reference: <1263241267-25204-2-git-send-email-jkacur@redhat.com> Signed-off-by: Ingo Molnar --- include/linux/plist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/plist.h b/include/linux/plist.h index 8227f717c70f..6898985e7b38 100644 --- a/include/linux/plist.h +++ b/include/linux/plist.h @@ -45,7 +45,7 @@ * the insertion of new nodes. There are no nodes with duplicate * priorites on the list. * - * The nodes on the node_list is ordered by priority and can contain + * The nodes on the node_list are ordered by priority and can contain * entries which have the same priority. Those entries are ordered * FIFO * @@ -265,7 +265,7 @@ static inline int plist_node_empty(const struct plist_node *node) * * Assumes the plist is _not_ empty. */ -static inline struct plist_node* plist_first(const struct plist_head *head) +static inline struct plist_node *plist_first(const struct plist_head *head) { return list_entry(head->node_list.next, struct plist_node, plist.node_list); -- GitLab From ff314d3903c2843de65c2148f66f277f2440ed26 Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Wed, 13 Jan 2010 17:01:38 +0800 Subject: [PATCH 0658/3892] perf: Make cmd_to_page() function more compact Remove branch for is_perf_command. Signed-off-by: Wenji Huang Cc: fweisbec@gmail.com Cc: jkacur@redhat.com Cc: acme@redhat.com LKML-Reference: <1263373298-13282-1-git-send-email-wenji.huang@oracle.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-help.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index e427d6965e0c..215b584007b1 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -313,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd) return "perf"; else if (!prefixcmp(perf_cmd, "perf")) return perf_cmd; - else if (is_perf_command(perf_cmd)) - return prepend("perf-", perf_cmd); else return prepend("perf-", perf_cmd); } -- GitLab From 782bb5a532f883540bf403afb19f735a4eefd95b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 19:11:14 +0900 Subject: [PATCH 0659/3892] sh: default to extended TLB support. All SH-X2 and SH-X3 parts support an extended TLB mode, which has been left as experimental since support was originally merged. Now that it's had some time to stabilize and get some exposure to various platforms, we can drop it as an option and default enable it across the board. This is also good future proofing for newer parts that will drop support for the legacy TLB mode completely. This will also force 3-level page tables for all newer parts, which is necessary both for the varying page sizes and larger memories. Signed-off-by: Paul Mundt --- arch/sh/include/asm/pgalloc.h | 2 +- arch/sh/include/asm/pgtable.h | 2 +- arch/sh/include/asm/pgtable_nopmd.h | 11 ++++++----- arch/sh/include/asm/pgtable_pmd.h | 5 +++-- arch/sh/mm/Kconfig | 29 ++--------------------------- arch/sh/mm/pgtable.c | 9 ++++----- 6 files changed, 17 insertions(+), 41 deletions(-) diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h index f8982f4e0405..8c00785c60d5 100644 --- a/arch/sh/include/asm/pgalloc.h +++ b/arch/sh/include/asm/pgalloc.h @@ -9,7 +9,7 @@ extern pgd_t *pgd_alloc(struct mm_struct *); extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); -#ifdef CONFIG_PGTABLE_LEVELS_3 +#if PAGETABLE_LEVELS > 2 extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd); extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address); extern void pmd_free(struct mm_struct *mm, pmd_t *pmd); diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 78598ec33d0a..856ece07d31b 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -12,7 +12,7 @@ #ifndef __ASM_SH_PGTABLE_H #define __ASM_SH_PGTABLE_H -#ifdef CONFIG_PGTABLE_LEVELS_3 +#ifdef CONFIG_X2TLB #include #else #include diff --git a/arch/sh/include/asm/pgtable_nopmd.h b/arch/sh/include/asm/pgtable_nopmd.h index f0b525b3cb4a..b8355e4057cf 100644 --- a/arch/sh/include/asm/pgtable_nopmd.h +++ b/arch/sh/include/asm/pgtable_nopmd.h @@ -6,17 +6,18 @@ /* * traditional two-level paging structure */ +#define PAGETABLE_LEVELS 2 /* PTE bits */ -#define PTE_MAGNITUDE 2 /* 32-bit PTEs */ +#define PTE_MAGNITUDE 2 /* 32-bit PTEs */ -#define PTE_SHIFT PAGE_SHIFT -#define PTE_BITS (PTE_SHIFT - PTE_MAGNITUDE) +#define PTE_SHIFT PAGE_SHIFT +#define PTE_BITS (PTE_SHIFT - PTE_MAGNITUDE) /* PGD bits */ -#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) +#define PGDIR_SHIFT (PTE_SHIFT + PTE_BITS) -#define PTRS_PER_PGD (PAGE_SIZE / (1 << PTE_MAGNITUDE)) +#define PTRS_PER_PGD (PAGE_SIZE / (1 << PTE_MAGNITUDE)) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #endif /* __ASM_SH_PGTABLE_NOPMD_H */ diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable_pmd.h index 42a180e534a8..587b05e1d04f 100644 --- a/arch/sh/include/asm/pgtable_pmd.h +++ b/arch/sh/include/asm/pgtable_pmd.h @@ -7,11 +7,12 @@ * Some cores need a 3-level page table layout, for example when using * 64-bit PTEs and 4K pages. */ +#define PAGETABLE_LEVELS 3 -#define PTE_MAGNITUDE 3 /* 64-bit PTEs on extended mode SH-X2 TLB */ +#define PTE_MAGNITUDE 3 /* 64-bit PTEs on SH-X2 TLB */ /* PGD bits */ -#define PGDIR_SHIFT 30 +#define PGDIR_SHIFT 30 #define PTRS_PER_PGD 4 #define USER_PTRS_PER_PGD 2 diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 860cd24b4205..7a4ebc8cbadd 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -100,13 +100,8 @@ config PMB_LEGACY and allows systems to support up to 512MiB of system memory. config X2TLB - bool "Enable extended TLB mode" - depends on (CPU_SHX2 || CPU_SHX3) && MMU && EXPERIMENTAL - help - Selecting this option will enable the extended mode of the SH-X2 - TLB. For legacy SH-X behaviour and interoperability, say N. For - all of the fun new features and a willingless to submit bug reports, - say Y. + def_bool y + depends on (CPU_SHX2 || CPU_SHX3) && MMU config VSYSCALL bool "Support vsyscall page" @@ -174,32 +169,12 @@ config ARCH_MEMORY_PROBE def_bool y depends on MEMORY_HOTPLUG -choice - prompt "Page table layout" - default PGTABLE_LEVELS_3 if X2TLB - default PGTABLE_LEVELS_2 - -config PGTABLE_LEVELS_2 - bool "2 Levels" - help - This is the default page table layout for all SuperH CPUs. - -config PGTABLE_LEVELS_3 - bool "3 Levels" - depends on X2TLB - help - This enables a 3 level page table structure. - -endchoice - choice prompt "Kernel page size" - default PAGE_SIZE_8KB if X2TLB default PAGE_SIZE_4KB config PAGE_SIZE_4KB bool "4kB" - depends on !MMU || !X2TLB || PGTABLE_LEVELS_3 help This is the default page size used by all SuperH CPUs. diff --git a/arch/sh/mm/pgtable.c b/arch/sh/mm/pgtable.c index e1bc5483cc07..6f21fb1d8726 100644 --- a/arch/sh/mm/pgtable.c +++ b/arch/sh/mm/pgtable.c @@ -3,8 +3,7 @@ #define PGALLOC_GFP GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO static struct kmem_cache *pgd_cachep; - -#ifdef CONFIG_PGTABLE_LEVELS_3 +#if PAGETABLE_LEVELS > 2 static struct kmem_cache *pmd_cachep; #endif @@ -22,7 +21,7 @@ void pgtable_cache_init(void) pgd_cachep = kmem_cache_create("pgd_cache", PTRS_PER_PGD * (1< 2 pmd_cachep = kmem_cache_create("pmd_cache", PTRS_PER_PMD * (1< 2 void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) { set_pud(pud, __pud((unsigned long)pmd)); @@ -54,4 +53,4 @@ void pmd_free(struct mm_struct *mm, pmd_t *pmd) { kmem_cache_free(pmd_cachep, pmd); } -#endif /* CONFIG_PGTABLE_LEVELS_3 */ +#endif /* PAGETABLE_LEVELS > 2 */ -- GitLab From 599faa0e264fe2e7f563f87b4aad8c83e9dc46d1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:29:58 +0000 Subject: [PATCH 0660/3892] genirq: Fix documentation of default chip disable() The documentation says that by default disable() will be chip->mask but in fact default_disable() is a noop. Signed-off-by: Mark Brown LKML-Reference: <1262698198-30392-1-git-send-email-broonie@opensource.wolfsonmicro.com> Signed-off-by: Ingo Molnar --- include/linux/irq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 451481c082b5..d13492df57a1 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -90,7 +90,7 @@ struct msi_desc; * @startup: start up the interrupt (defaults to ->enable if NULL) * @shutdown: shut down the interrupt (defaults to ->disable if NULL) * @enable: enable the interrupt (defaults to chip->unmask if NULL) - * @disable: disable the interrupt (defaults to chip->mask if NULL) + * @disable: disable the interrupt * @ack: start of a new interrupt * @mask: mask an interrupt source * @mask_ack: ack and mask an interrupt source -- GitLab From e44d6c4010a4c84369013932eea4721d16cbc08d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 Jan 2010 19:18:39 +0900 Subject: [PATCH 0661/3892] sh: Rename split-level pgtable headers. These were originally named _nopmd and _pmd to follow their asm-generic counterparts, but we rename them to -2level and -3level for general consistency. Signed-off-by: Paul Mundt --- arch/sh/include/asm/{pgtable_nopmd.h => pgtable-2level.h} | 6 +++--- arch/sh/include/asm/{pgtable_pmd.h => pgtable-3level.h} | 6 +++--- arch/sh/include/asm/pgtable.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename arch/sh/include/asm/{pgtable_nopmd.h => pgtable-2level.h} (79%) rename arch/sh/include/asm/{pgtable_pmd.h => pgtable-3level.h} (92%) diff --git a/arch/sh/include/asm/pgtable_nopmd.h b/arch/sh/include/asm/pgtable-2level.h similarity index 79% rename from arch/sh/include/asm/pgtable_nopmd.h rename to arch/sh/include/asm/pgtable-2level.h index b8355e4057cf..19bd89db17e7 100644 --- a/arch/sh/include/asm/pgtable_nopmd.h +++ b/arch/sh/include/asm/pgtable-2level.h @@ -1,5 +1,5 @@ -#ifndef __ASM_SH_PGTABLE_NOPMD_H -#define __ASM_SH_PGTABLE_NOPMD_H +#ifndef __ASM_SH_PGTABLE_2LEVEL_H +#define __ASM_SH_PGTABLE_2LEVEL_H #include @@ -20,4 +20,4 @@ #define PTRS_PER_PGD (PAGE_SIZE / (1 << PTE_MAGNITUDE)) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#endif /* __ASM_SH_PGTABLE_NOPMD_H */ +#endif /* __ASM_SH_PGTABLE_2LEVEL_H */ diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable-3level.h similarity index 92% rename from arch/sh/include/asm/pgtable_pmd.h rename to arch/sh/include/asm/pgtable-3level.h index 587b05e1d04f..249a985d9648 100644 --- a/arch/sh/include/asm/pgtable_pmd.h +++ b/arch/sh/include/asm/pgtable-3level.h @@ -1,5 +1,5 @@ -#ifndef __ASM_SH_PGTABLE_PMD_H -#define __ASM_SH_PGTABLE_PMD_H +#ifndef __ASM_SH_PGTABLE_3LEVEL_H +#define __ASM_SH_PGTABLE_3LEVEL_H #include @@ -53,4 +53,4 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) */ #define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while(0) -#endif /* __ASM_SH_PGTABLE_PMD_H */ +#endif /* __ASM_SH_PGTABLE_3LEVEL_H */ diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 856ece07d31b..aab76528abb9 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -13,9 +13,9 @@ #define __ASM_SH_PGTABLE_H #ifdef CONFIG_X2TLB -#include +#include #else -#include +#include #endif #include -- GitLab From 4bb9508bbbb06f10bc3e249dd34375b4a4d6bfc0 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 23 Dec 2009 14:13:46 +0100 Subject: [PATCH 0662/3892] HID: remove TENX iBuddy from blacklist There were multiple reports which indicate that vendor messed up horribly and the same VID/PID combination is used for completely different devices, some of them requiring the blacklist entry and other not. Remove the blacklist entry for this combination of VID/PID completely, and let the user decide and unbind the driver via sysfs eventually, if needed. Proper fix would be fixing the vendor. References: http://lkml.org/lkml/2009/2/10/434 http://bugzilla.kernel.org/show_bug.cgi?id=13411 Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 -- drivers/hid/hid-ids.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 056384cf05e4..116a3460e75a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1662,8 +1662,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b009fd68deae..064c09a221ef 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -406,10 +406,6 @@ #define USB_VENDOR_ID_SUNPLUS 0x04fc #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 -#define USB_VENDOR_ID_TENX 0x1130 -#define USB_DEVICE_ID_TENX_IBUDDY1 0x0001 -#define USB_DEVICE_ID_TENX_IBUDDY2 0x0002 - #define USB_VENDOR_ID_THRUSTMASTER 0x044f #define USB_VENDOR_ID_TOPMAX 0x0663 -- GitLab From fd63df2264f2518fa67dca596d493a330537494d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 13 Jan 2010 12:37:49 +0200 Subject: [PATCH 0663/3892] ASoC: TWL4030: Replace comma with semicolon in probe function The codec structure initialization statements should be separated by semicolons. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 2a27f7b56726..74f0d65f0784 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2192,7 +2192,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) codec->write = twl4030_write; codec->set_bias_level = twl4030_set_bias_level; codec->dai = twl4030_dai; - codec->num_dai = ARRAY_SIZE(twl4030_dai), + codec->num_dai = ARRAY_SIZE(twl4030_dai); codec->reg_cache_size = sizeof(twl4030_reg); codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), GFP_KERNEL); -- GitLab From 617b14c50eb95b36360b2b3232c6cf20b910e2f8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 13 Jan 2010 11:25:05 +0100 Subject: [PATCH 0664/3892] ASoC: ak4104: allow more sample rates The transmitter supports all sample rates up to 192KHz, so the driver should not give a limit. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/ak4104.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 3a14c6fc4f5e..b9ef7e45891d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -185,9 +185,7 @@ struct snd_soc_dai ak4104_dai = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_32000, + .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE -- GitLab From cd8c20b650f49354722b8cc1f03320b004815a0a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 13 Jan 2010 16:02:14 +0100 Subject: [PATCH 0665/3892] netfilter: nfnetlink: netns support Make nfnl socket per-petns. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink.h | 8 ++-- include/net/net_namespace.h | 2 + net/netfilter/nf_conntrack_netlink.c | 13 +++--- net/netfilter/nfnetlink.c | 65 ++++++++++++++++++---------- net/netfilter/nfnetlink_log.c | 3 +- net/netfilter/nfnetlink_queue.c | 2 +- 6 files changed, 58 insertions(+), 35 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 49d321f3ccd2..53923868c9bd 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -73,11 +73,11 @@ struct nfnetlink_subsystem { extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); -extern int nfnetlink_has_listeners(unsigned int group); -extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, +extern int nfnetlink_has_listeners(struct net *net, unsigned int group); +extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo, gfp_t flags); -extern void nfnetlink_set_err(u32 pid, u32 group, int error); -extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); +extern void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); +extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags); extern void nfnl_lock(void); extern void nfnl_unlock(void); diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index f307e133d14c..82b7be4db89a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -81,6 +81,8 @@ struct net { #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; #endif + struct sock *nfnl; + struct sock *nfnl_stash; #endif #ifdef CONFIG_XFRM struct netns_xfrm xfrm; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 59d8064eb522..d4c5d06677f9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -482,7 +482,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) } else return 0; - if (!item->report && !nfnetlink_has_listeners(group)) + if (!item->report && !nfnetlink_has_listeners(&init_net, group)) return 0; skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); @@ -559,7 +559,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) rcu_read_unlock(); nlmsg_end(skb, nlh); - err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); + err = nfnetlink_send(skb, &init_net, item->pid, group, item->report, + GFP_ATOMIC); if (err == -ENOBUFS || err == -EAGAIN) return -ENOBUFS; @@ -571,7 +572,7 @@ nla_put_failure: nlmsg_failure: kfree_skb(skb); errout: - nfnetlink_set_err(0, group, -ENOBUFS); + nfnetlink_set_err(&init_net, 0, group, -ENOBUFS); return 0; } #endif /* CONFIG_NF_CONNTRACK_EVENTS */ @@ -1539,7 +1540,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) return 0; if (!item->report && - !nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) + !nfnetlink_has_listeners(&init_net, NFNLGRP_CONNTRACK_EXP_NEW)) return 0; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); @@ -1562,7 +1563,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) rcu_read_unlock(); nlmsg_end(skb, nlh); - nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, + nfnetlink_send(skb, &init_net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report, GFP_ATOMIC); return 0; @@ -1572,7 +1573,7 @@ nla_put_failure: nlmsg_failure: kfree_skb(skb); errout: - nfnetlink_set_err(0, 0, -ENOBUFS); + nfnetlink_set_err(&init_net, 0, 0, -ENOBUFS); return 0; } #endif diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index eedc0c1ac7a4..8eb0cc23ada3 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -40,7 +40,6 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); static char __initdata nfversion[] = "0.30"; -static struct sock *nfnl = NULL; static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; static DEFINE_MUTEX(nfnl_mutex); @@ -101,34 +100,35 @@ nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss) return &ss->cb[cb_id]; } -int nfnetlink_has_listeners(unsigned int group) +int nfnetlink_has_listeners(struct net *net, unsigned int group) { - return netlink_has_listeners(nfnl, group); + return netlink_has_listeners(net->nfnl, group); } EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); -int nfnetlink_send(struct sk_buff *skb, u32 pid, +int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo, gfp_t flags) { - return nlmsg_notify(nfnl, skb, pid, group, echo, flags); + return nlmsg_notify(net->nfnl, skb, pid, group, echo, flags); } EXPORT_SYMBOL_GPL(nfnetlink_send); -void nfnetlink_set_err(u32 pid, u32 group, int error) +void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error) { - netlink_set_err(nfnl, pid, group, error); + netlink_set_err(net->nfnl, pid, group, error); } EXPORT_SYMBOL_GPL(nfnetlink_set_err); -int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) +int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags) { - return netlink_unicast(nfnl, skb, pid, flags); + return netlink_unicast(net->nfnl, skb, pid, flags); } EXPORT_SYMBOL_GPL(nfnetlink_unicast); /* Process one complete nfnetlink message. */ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { + struct net *net = sock_net(skb->sk); const struct nfnl_callback *nc; const struct nfnetlink_subsystem *ss; int type, err; @@ -170,7 +170,7 @@ replay: if (err < 0) return err; - err = nc->call(nfnl, skb, nlh, (const struct nlattr **)cda); + err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda); if (err == -EAGAIN) goto replay; return err; @@ -184,26 +184,45 @@ static void nfnetlink_rcv(struct sk_buff *skb) nfnl_unlock(); } -static void __exit nfnetlink_exit(void) +static int __net_init nfnetlink_net_init(struct net *net) { - printk("Removing netfilter NETLINK layer.\n"); - netlink_kernel_release(nfnl); - return; + struct sock *nfnl; + + nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, NFNLGRP_MAX, + nfnetlink_rcv, NULL, THIS_MODULE); + if (!nfnl) + return -ENOMEM; + net->nfnl_stash = nfnl; + rcu_assign_pointer(net->nfnl, nfnl); + return 0; } -static int __init nfnetlink_init(void) +static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list) { - printk("Netfilter messages via NETLINK v%s.\n", nfversion); + struct net *net; - nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX, - nfnetlink_rcv, NULL, THIS_MODULE); - if (!nfnl) { - printk(KERN_ERR "cannot initialize nfnetlink!\n"); - return -ENOMEM; - } + list_for_each_entry(net, net_exit_list, exit_list) + rcu_assign_pointer(net->nfnl, NULL); + synchronize_net(); + list_for_each_entry(net, net_exit_list, exit_list) + netlink_kernel_release(net->nfnl_stash); +} - return 0; +static struct pernet_operations nfnetlink_net_ops = { + .init = nfnetlink_net_init, + .exit_batch = nfnetlink_net_exit_batch, +}; + +static int __init nfnetlink_init(void) +{ + printk("Netfilter messages via NETLINK v%s.\n", nfversion); + return register_pernet_subsys(&nfnetlink_net_ops); } +static void __exit nfnetlink_exit(void) +{ + printk("Removing netfilter NETLINK layer.\n"); + unregister_pernet_subsys(&nfnetlink_net_ops); +} module_init(nfnetlink_init); module_exit(nfnetlink_exit); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 9de0470d557e..285e9029a9ff 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -323,7 +323,8 @@ __nfulnl_send(struct nfulnl_instance *inst) NLMSG_DONE, sizeof(struct nfgenmsg)); - status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT); + status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_pid, + MSG_DONTWAIT); inst->qlen = 0; inst->skb = NULL; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 7e3fa410641e..5c589b27d6eb 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -420,7 +420,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) } /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, queue->peer_pid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; -- GitLab From 9592a5c01e79dbc59eb56fa26b124e94ffcd0962 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 13 Jan 2010 16:04:18 +0100 Subject: [PATCH 0666/3892] netfilter: ctnetlink: netns support Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_netlink.c | 65 +++++++++++++++++----------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d4c5d06677f9..79478dfba27e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -456,6 +457,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct) static int ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) { + struct net *net; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; @@ -482,7 +484,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) } else return 0; - if (!item->report && !nfnetlink_has_listeners(&init_net, group)) + net = nf_ct_net(ct); + if (!item->report && !nfnetlink_has_listeners(net, group)) return 0; skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); @@ -559,7 +562,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) rcu_read_unlock(); nlmsg_end(skb, nlh); - err = nfnetlink_send(skb, &init_net, item->pid, group, item->report, + err = nfnetlink_send(skb, net, item->pid, group, item->report, GFP_ATOMIC); if (err == -ENOBUFS || err == -EAGAIN) return -ENOBUFS; @@ -572,7 +575,7 @@ nla_put_failure: nlmsg_failure: kfree_skb(skb); errout: - nfnetlink_set_err(&init_net, 0, group, -ENOBUFS); + nfnetlink_set_err(net, 0, group, -ENOBUFS); return 0; } #endif /* CONFIG_NF_CONNTRACK_EVENTS */ @@ -587,6 +590,7 @@ static int ctnetlink_done(struct netlink_callback *cb) static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = sock_net(skb->sk); struct nf_conn *ct, *last; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; @@ -597,7 +601,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) last = (struct nf_conn *)cb->args[1]; for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { restart: - hlist_nulls_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[cb->args[0]], hnnode) { if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) continue; @@ -769,6 +773,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; struct nf_conn *ct; @@ -782,7 +787,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { /* Flush the whole table */ - nf_conntrack_flush_report(&init_net, + nf_conntrack_flush_report(net, NETLINK_CB(skb).pid, nlmsg_report(nlh)); return 0; @@ -791,7 +796,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(&init_net, &tuple); + h = nf_conntrack_find_get(net, &tuple); if (!h) return -ENOENT; @@ -829,6 +834,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; struct nf_conn *ct; @@ -851,7 +857,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(&init_net, &tuple); + h = nf_conntrack_find_get(net, &tuple); if (!h) return -ENOENT; @@ -1176,7 +1182,8 @@ ctnetlink_change_conntrack(struct nf_conn *ct, } static struct nf_conn * -ctnetlink_create_conntrack(const struct nlattr * const cda[], +ctnetlink_create_conntrack(struct net *net, + const struct nlattr * const cda[], struct nf_conntrack_tuple *otuple, struct nf_conntrack_tuple *rtuple, u8 u3) @@ -1185,7 +1192,7 @@ ctnetlink_create_conntrack(const struct nlattr * const cda[], int err = -EINVAL; struct nf_conntrack_helper *helper; - ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); + ct = nf_conntrack_alloc(net, otuple, rtuple, GFP_ATOMIC); if (IS_ERR(ct)) return ERR_PTR(-ENOMEM); @@ -1286,7 +1293,7 @@ ctnetlink_create_conntrack(const struct nlattr * const cda[], if (err < 0) goto err2; - master_h = nf_conntrack_find_get(&init_net, &master); + master_h = nf_conntrack_find_get(net, &master); if (master_h == NULL) { err = -ENOENT; goto err2; @@ -1314,6 +1321,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple_hash *h = NULL; struct nfgenmsg *nfmsg = nlmsg_data(nlh); @@ -1334,9 +1342,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, spin_lock_bh(&nf_conntrack_lock); if (cda[CTA_TUPLE_ORIG]) - h = __nf_conntrack_find(&init_net, &otuple); + h = __nf_conntrack_find(net, &otuple); else if (cda[CTA_TUPLE_REPLY]) - h = __nf_conntrack_find(&init_net, &rtuple); + h = __nf_conntrack_find(net, &rtuple); if (h == NULL) { err = -ENOENT; @@ -1344,7 +1352,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conn *ct; enum ip_conntrack_events events; - ct = ctnetlink_create_conntrack(cda, &otuple, + ct = ctnetlink_create_conntrack(net, cda, &otuple, &rtuple, u3); if (IS_ERR(ct)) { err = PTR_ERR(ct); @@ -1526,9 +1534,10 @@ nla_put_failure: static int ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) { + struct nf_conntrack_expect *exp = item->exp; + struct net *net = nf_ct_exp_net(exp); struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nf_conntrack_expect *exp = item->exp; struct sk_buff *skb; unsigned int type; int flags = 0; @@ -1540,7 +1549,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) return 0; if (!item->report && - !nfnetlink_has_listeners(&init_net, NFNLGRP_CONNTRACK_EXP_NEW)) + !nfnetlink_has_listeners(net, NFNLGRP_CONNTRACK_EXP_NEW)) return 0; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); @@ -1563,7 +1572,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) rcu_read_unlock(); nlmsg_end(skb, nlh); - nfnetlink_send(skb, &init_net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, + nfnetlink_send(skb, net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report, GFP_ATOMIC); return 0; @@ -1573,7 +1582,7 @@ nla_put_failure: nlmsg_failure: kfree_skb(skb); errout: - nfnetlink_set_err(&init_net, 0, 0, -ENOBUFS); + nfnetlink_set_err(net, 0, 0, -ENOBUFS); return 0; } #endif @@ -1587,7 +1596,7 @@ static int ctnetlink_exp_done(struct netlink_callback *cb) static int ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = &init_net; + struct net *net = sock_net(skb->sk); struct nf_conntrack_expect *exp, *last; struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); struct hlist_node *n; @@ -1640,6 +1649,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; struct sk_buff *skb2; @@ -1661,7 +1671,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = nf_ct_expect_find_get(&init_net, &tuple); + exp = nf_ct_expect_find_get(net, &tuple); if (!exp) return -ENOENT; @@ -1701,6 +1711,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; struct nf_conntrack_helper *h; @@ -1717,7 +1728,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = nf_ct_expect_find_get(&init_net, &tuple); + exp = nf_ct_expect_find_get(net, &tuple); if (!exp) return -ENOENT; @@ -1747,7 +1758,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, } for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, n, next, - &init_net.ct.expect_hash[i], + &net->ct.expect_hash[i], hnode) { m_help = nfct_help(exp->master); if (m_help->helper == h @@ -1763,7 +1774,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, spin_lock_bh(&nf_conntrack_lock); for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, n, next, - &init_net.ct.expect_hash[i], + &net->ct.expect_hash[i], hnode) { if (del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); @@ -1784,7 +1795,8 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, } static int -ctnetlink_create_expect(const struct nlattr * const cda[], u_int8_t u3, +ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[], + u_int8_t u3, u32 pid, int report) { struct nf_conntrack_tuple tuple, mask, master_tuple; @@ -1806,7 +1818,7 @@ ctnetlink_create_expect(const struct nlattr * const cda[], u_int8_t u3, return err; /* Look for master conntrack of this expectation */ - h = nf_conntrack_find_get(&init_net, &master_tuple); + h = nf_conntrack_find_get(net, &master_tuple); if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); @@ -1846,6 +1858,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const cda[]) { + struct net *net = sock_net(ctnl); struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; struct nfgenmsg *nfmsg = nlmsg_data(nlh); @@ -1862,13 +1875,13 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, return err; spin_lock_bh(&nf_conntrack_lock); - exp = __nf_ct_expect_find(&init_net, &tuple); + exp = __nf_ct_expect_find(net, &tuple); if (!exp) { spin_unlock_bh(&nf_conntrack_lock); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) { - err = ctnetlink_create_expect(cda, + err = ctnetlink_create_expect(net, cda, u3, NETLINK_CB(skb).pid, nlmsg_report(nlh)); -- GitLab From b7cece76783c68fb391f9882235b4b0c9c300c46 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 13 Jan 2010 13:22:17 -0200 Subject: [PATCH 0667/3892] perf tools: Encode kernel module mappings in perf.data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were always looking at the running machine /proc/modules, even when processing a perf.data file, which only makes sense when we're doing 'perf record' and 'perf report' on the same machine, and in close sucession, or if we don't use modules at all, right Peter? ;-) Now, at 'perf record' time we read /proc/modules, find the long path for modules, and put them as PERF_MMAP events, just like we did to encode the reloc reference symbol for vmlinux. Talking about that now it is encoded in .pgoff, so that we can use .{start,len} to store the address boundaries for the kernel so that when we reconstruct the kmaps tree we can do lookups right away, without having to fixup the end of the kernel maps like we did in the past (and now only in perf record). One more step in the 'perf archive' direction when we'll finally be able to collect data in one machine and analyse in another. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263396139-4798-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 5 ++ tools/perf/builtin-record.c | 11 ++++ tools/perf/builtin-top.c | 5 ++ tools/perf/util/event.c | 106 ++++++++++++++++++++++++++++---- tools/perf/util/event.h | 2 + tools/perf/util/session.c | 8 +-- tools/perf/util/symbol.c | 116 ++++++++++++++++++++++++++---------- tools/perf/util/symbol.h | 3 + tools/perf/util/thread.h | 4 ++ 9 files changed, 212 insertions(+), 48 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 88c570c18e3e..4af7199c5af7 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -494,6 +494,11 @@ static int __cmd_kmem(void) if (!perf_session__has_traces(session, "kmem record")) goto out_delete; + if (perf_session__create_kernel_maps(session) < 0) { + pr_err("Problems creating kernel maps\n"); + return -1; + } + setup_pager(); err = perf_session__process_events(session, &event_ops); if (err != 0) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8f88420e066b..c130df2676f1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -465,6 +465,11 @@ static int __cmd_record(int argc, const char **argv) return -1; } + if (perf_session__create_kernel_maps(session) < 0) { + pr_err("Problems creating kernel maps\n"); + return -1; + } + if (!file_new) { err = perf_header__read(&session->header, output); if (err < 0) @@ -558,6 +563,12 @@ static int __cmd_record(int argc, const char **argv) return err; } + err = event__synthesize_modules(process_synthesized_event, session); + if (err < 0) { + pr_err("Couldn't record kernel reference relocation symbol.\n"); + return err; + } + if (!system_wide && profile_cpu == -1) event__synthesize_thread(pid, process_synthesized_event, session); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ddc584b64871..6822b44ca4f9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1165,6 +1165,11 @@ static int __cmd_top(void) if (session == NULL) return -ENOMEM; + if (perf_session__create_kernel_maps(session) < 0) { + pr_err("Problems creating kernel maps\n"); + return -1; + } + if (target_pid != -1) event__synthesize_thread(target_pid, event__process, session); else diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bfb3d872b9f5..4f3e7ef33b83 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -154,6 +154,36 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, return 0; } +int event__synthesize_modules(event__handler_t process, + struct perf_session *session) +{ + struct rb_node *nd; + + for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]); + nd; nd = rb_next(nd)) { + event_t ev; + size_t size; + struct map *pos = rb_entry(nd, struct map, rb_node); + + if (pos->dso->kernel) + continue; + + size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); + memset(&ev, 0, sizeof(ev)); + ev.mmap.header.type = PERF_RECORD_MMAP; + ev.mmap.header.size = (sizeof(ev.mmap) - + (sizeof(ev.mmap.filename) - size)); + ev.mmap.start = pos->start; + ev.mmap.len = pos->end - pos->start; + + memcpy(ev.mmap.filename, pos->dso->long_name, + pos->dso->long_name_len + 1); + process(&ev, session); + } + + return 0; +} + int event__synthesize_thread(pid_t pid, event__handler_t process, struct perf_session *session) { @@ -222,7 +252,9 @@ int event__synthesize_kernel_mmap(event__handler_t process, "[kernel.kallsyms.%s]", symbol_name) + 1; size = ALIGN(size, sizeof(u64)); ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); - ev.mmap.start = args.start; + ev.mmap.pgoff = args.start; + ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start; + ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ; return process(&ev, session); } @@ -280,7 +312,6 @@ int event__process_mmap(event_t *self, struct perf_session *session) { struct thread *thread; struct map *map; - static const char kmmap_prefix[] = "[kernel.kallsyms."; dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", self->mmap.pid, self->mmap.tid, @@ -289,13 +320,61 @@ int event__process_mmap(event_t *self, struct perf_session *session) (void *)(long)self->mmap.pgoff, self->mmap.filename); - if (self->mmap.pid == 0 && - memcmp(self->mmap.filename, kmmap_prefix, - sizeof(kmmap_prefix) - 1) == 0) { - const char *symbol_name = (self->mmap.filename + - sizeof(kmmap_prefix) - 1); - perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, - self->mmap.start); + if (self->mmap.pid == 0) { + static const char kmmap_prefix[] = "[kernel.kallsyms."; + + if (self->mmap.filename[0] == '/') { + char short_module_name[1024]; + char *name = strrchr(self->mmap.filename, '/'), *dot; + + if (name == NULL) + goto out_problem; + + ++name; /* skip / */ + dot = strrchr(name, '.'); + if (dot == NULL) + goto out_problem; + + snprintf(short_module_name, sizeof(short_module_name), + "[%.*s]", (int)(dot - name), name); + strxfrchar(short_module_name, '-', '_'); + + map = perf_session__new_module_map(session, + self->mmap.start, + short_module_name); + if (map == NULL) + goto out_problem; + + name = strdup(self->mmap.filename); + if (name == NULL) + goto out_problem; + + dso__set_long_name(map->dso, name); + map->end = map->start + self->mmap.len; + } else if (memcmp(self->mmap.filename, kmmap_prefix, + sizeof(kmmap_prefix) - 1) == 0) { + const char *symbol_name = (self->mmap.filename + + sizeof(kmmap_prefix) - 1); + /* + * Should be there already, from the build-id table in + * the header. + */ + struct dso *kernel = __dsos__findnew(&dsos__kernel, + "[kernel.kallsyms]"); + if (kernel == NULL) + goto out_problem; + + if (__map_groups__create_kernel_maps(&session->kmaps, + session->vmlinux_maps, + kernel) < 0) + goto out_problem; + + session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; + session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; + + perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, + self->mmap.pgoff); + } return 0; } @@ -304,10 +383,13 @@ int event__process_mmap(event_t *self, struct perf_session *session) session->cwd, session->cwdlen); if (thread == NULL || map == NULL) - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - else - thread__insert_map(thread, map); + goto out_problem; + + thread__insert_map(thread, map); + return 0; +out_problem: + dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 80356da8216c..50a7132887f5 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -112,6 +112,8 @@ void event__synthesize_threads(event__handler_t process, int event__synthesize_kernel_mmap(event__handler_t process, struct perf_session *session, const char *symbol_name); +int event__synthesize_modules(event__handler_t process, + struct perf_session *session); int event__process_comm(event_t *self, struct perf_session *session); int event__process_lost(event_t *self, struct perf_session *session); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 378ac5422bcf..fd1c5a39a5bb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -69,9 +69,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc self->unknown_events = 0; map_groups__init(&self->kmaps); - if (perf_session__create_kernel_maps(self) < 0) - goto out_delete; - if (mode == O_RDONLY && perf_session__open(self, force) < 0) goto out_delete; @@ -268,8 +265,11 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) head = &dsos__kernel; dso = __dsos__findnew(head, filename); - if (dso != NULL) + if (dso != NULL) { dso__set_build_id(dso, &bev.build_id); + if (head == &dsos__kernel && filename[0] == '[') + dso->kernel = 1; + } offset += bev.header.size; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8e6627e6b778..381999dd5c1f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -161,7 +161,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp) self->start, self->end, self->name); } -static void dso__set_long_name(struct dso *self, char *name) +void dso__set_long_name(struct dso *self, char *name) { if (name == NULL) return; @@ -176,7 +176,7 @@ static void dso__set_basename(struct dso *self) struct dso *dso__new(const char *name) { - struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); + struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1); if (self != NULL) { int i; @@ -500,13 +500,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, *module++ = '\0'; - if (strcmp(self->name, module)) { + if (strcmp(curr_map->dso->short_name, module)) { curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); if (curr_map == NULL) { pr_debug("/proc/{kallsyms,modules} " - "inconsistency!\n"); + "inconsistency while looking " + "for \"%s\" module!\n", module); return -1; } + + if (curr_map->dso->loaded) + goto discard_symbol; } /* * So that we look just like we get from .ko files, @@ -1343,13 +1347,33 @@ struct map *map_groups__find_by_name(struct map_groups *self, for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); - if (map->dso && strcmp(map->dso->name, name) == 0) + if (map->dso && strcmp(map->dso->short_name, name) == 0) return map; } return NULL; } +static int dso__kernel_module_get_build_id(struct dso *self) +{ + char filename[PATH_MAX]; + /* + * kernel module short names are of the form "[module]" and + * we need just "module" here. + */ + const char *name = self->short_name + 1; + + snprintf(filename, sizeof(filename), + "/sys/module/%.*s/notes/.note.gnu.build-id", + (int)strlen(name - 1), name); + + if (sysfs__read_build_id(filename, self->build_id, + sizeof(self->build_id)) == 0) + self->has_build_id = true; + + return 0; +} + static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) { struct dirent *dent; @@ -1395,6 +1419,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d if (long_name == NULL) goto failure; dso__set_long_name(map->dso, long_name); + dso__kernel_module_get_build_id(map->dso); } } @@ -1437,6 +1462,24 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) return self; } +struct map *perf_session__new_module_map(struct perf_session *self, u64 start, + const char *filename) +{ + struct map *map; + struct dso *dso = __dsos__findnew(&dsos__kernel, filename); + + if (dso == NULL) + return NULL; + + map = map__new2(start, dso, MAP__FUNCTION); + if (map == NULL) + return NULL; + + dso->origin = DSO__ORIG_KMODULE; + map_groups__insert(&self->kmaps, map); + return map; +} + static int perf_session__create_module_maps(struct perf_session *self) { char *line = NULL; @@ -1450,7 +1493,6 @@ static int perf_session__create_module_maps(struct perf_session *self) while (!feof(file)) { char name[PATH_MAX]; u64 start; - struct dso *dso; char *sep; int line_len; @@ -1476,26 +1518,10 @@ static int perf_session__create_module_maps(struct perf_session *self) *sep = '\0'; snprintf(name, sizeof(name), "[%s]", line); - dso = dso__new(name); - - if (dso == NULL) - goto out_delete_line; - - map = map__new2(start, dso, MAP__FUNCTION); - if (map == NULL) { - dso__delete(dso); + map = perf_session__new_module_map(self, start, name); + if (map == NULL) goto out_delete_line; - } - - snprintf(name, sizeof(name), - "/sys/module/%s/notes/.note.gnu.build-id", line); - if (sysfs__read_build_id(name, dso->build_id, - sizeof(dso->build_id)) == 0) - dso->has_build_id = true; - - dso->origin = DSO__ORIG_KMODULE; - map_groups__insert(&self->kmaps, map); - dsos__add(&dsos__kernel, dso); + dso__kernel_module_get_build_id(map->dso); } free(line); @@ -1573,10 +1599,28 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } } + /* + * Say the kernel DSO was created when processing the build-id header table, + * we have a build-id, so check if it is the same as the running kernel, + * using it if it is. + */ + if (self->has_build_id) { + u8 kallsyms_build_id[BUILD_ID_SIZE]; + + if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, + sizeof(kallsyms_build_id)) == 0) + + is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); + if (is_kallsyms) + goto do_kallsyms; + goto do_vmlinux; + } + is_kallsyms = self->long_name[0] == '['; if (is_kallsyms) goto do_kallsyms; +do_vmlinux: err = dso__load_vmlinux(self, map, session, self->long_name, filter); if (err <= 0) { pr_info("The file %s cannot be used, " @@ -1694,16 +1738,12 @@ out_delete_kernel_dso: return NULL; } -static int map_groups__create_kernel_maps(struct map_groups *self, - struct map *vmlinux_maps[MAP__NR_TYPES], - const char *vmlinux) +int __map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES], + struct dso *kernel) { - struct dso *kernel = dsos__create_kernel(vmlinux); enum map_type type; - if (kernel == NULL) - return -1; - for (type = 0; type < MAP__NR_TYPES; ++type) { vmlinux_maps[type] = map__new2(0, kernel, type); if (vmlinux_maps[type] == NULL) @@ -1717,6 +1757,18 @@ static int map_groups__create_kernel_maps(struct map_groups *self, return 0; } +static int map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES], + const char *vmlinux) +{ + struct dso *kernel = dsos__create_kernel(vmlinux); + + if (kernel == NULL) + return -1; + + return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel); +} + static void vmlinux_path__exit(void) { while (--vmlinux_path__nr_entries >= 0) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ee0b4593db7b..594156e43b10 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -134,6 +134,7 @@ size_t dsos__fprintf_buildid(FILE *fp); size_t dso__fprintf_buildid(struct dso *self, FILE *fp); size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); char dso__symtab_origin(const struct dso *self); +void dso__set_long_name(struct dso *self, char *name); void dso__set_build_id(struct dso *self, void *build_id); struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, @@ -151,5 +152,7 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type); int perf_session__create_kernel_maps(struct perf_session *self); +struct map *perf_session__new_module_map(struct perf_session *self, u64 start, + const char *filename); extern struct dso *vdso; #endif /* __PERF_SYMBOL */ diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index c206f72c8881..c06c13535a70 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -67,4 +67,8 @@ map_groups__find_function(struct map_groups *self, struct perf_session *session, struct map *map_groups__find_by_name(struct map_groups *self, enum map_type type, const char *name); + +int __map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES], + struct dso *kernel); #endif /* __PERF_THREAD_H */ -- GitLab From 0895cf0a823e03ea6d79736611e90186006c805e Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Wed, 13 Jan 2010 13:22:18 -0200 Subject: [PATCH 0668/3892] perf: Fix few typos + cosmetics Signed-off-by: Kirill Smelkov Signed-off-by: Arnaldo Carvalho de Melo LKML-Reference: <1263396139-4798-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf.txt | 2 +- tools/perf/design.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 69c832557199..0eeb247dc7d2 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt @@ -12,7 +12,7 @@ SYNOPSIS DESCRIPTION ----------- -Performance counters for Linux are are a new kernel-based subsystem +Performance counters for Linux are a new kernel-based subsystem that provide a framework for all things performance analysis. It covers hardware level (CPU/PMU, Performance Monitoring Unit) features and software features (software counters, tracepoints) as well. diff --git a/tools/perf/design.txt b/tools/perf/design.txt index 8d0de5130db3..bd0bb1b1279b 100644 --- a/tools/perf/design.txt +++ b/tools/perf/design.txt @@ -101,10 +101,10 @@ enum hw_event_ids { */ PERF_COUNT_HW_CPU_CYCLES = 0, PERF_COUNT_HW_INSTRUCTIONS = 1, - PERF_COUNT_HW_CACHE_REFERENCES = 2, + PERF_COUNT_HW_CACHE_REFERENCES = 2, PERF_COUNT_HW_CACHE_MISSES = 3, PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, - PERF_COUNT_HW_BRANCH_MISSES = 5, + PERF_COUNT_HW_BRANCH_MISSES = 5, PERF_COUNT_HW_BUS_CYCLES = 6, }; @@ -131,8 +131,8 @@ software events, selected by 'event_id': */ enum sw_event_ids { PERF_COUNT_SW_CPU_CLOCK = 0, - PERF_COUNT_SW_TASK_CLOCK = 1, - PERF_COUNT_SW_PAGE_FAULTS = 2, + PERF_COUNT_SW_TASK_CLOCK = 1, + PERF_COUNT_SW_PAGE_FAULTS = 2, PERF_COUNT_SW_CONTEXT_SWITCHES = 3, PERF_COUNT_SW_CPU_MIGRATIONS = 4, PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, -- GitLab From 66aeb6d5cb701aedd508187e08612bfd1e108e2e Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Wed, 13 Jan 2010 13:22:19 -0200 Subject: [PATCH 0669/3892] perf top: Fix code typo in prompt_symbol() sym_filter is what was (if ever) passed with -s option. What was typed by user, and what we were looking for, is in buf. Signed-off-by: Kirill Smelkov Signed-off-by: Arnaldo Carvalho de Melo LKML-Reference: <1263396139-4798-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6822b44ca4f9..7a8a77ec2c9d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -667,7 +667,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) } if (!found) { - fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); + fprintf(stderr, "Sorry, %s is not active.\n", buf); sleep(1); return; } else -- GitLab From 3bef444797f7624f8fbd27f4e0334ce96a108725 Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Wed, 13 Jan 2010 10:45:55 -0500 Subject: [PATCH 0670/3892] x86: Merge show_regs() Using kernel_stack_pointer() allows 32-bit and 64-bit versions to be merged. This is more correct for 64-bit, since the old %rsp is always saved on the stack. Signed-off-by: Brian Gerst LKML-Reference: <1263397555-27695-1-git-send-email-brgerst@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/process.c | 7 +++++++ arch/x86/kernel/process_32.c | 6 ------ arch/x86/kernel/process_64.c | 6 ------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 98c2cdeb599e..cf1e04b2ad65 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -92,6 +92,13 @@ void exit_thread(void) } } +void show_regs(struct pt_regs *regs) +{ + show_registers(regs); + show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), + regs->bp); +} + void show_regs_common(void) { const char *board, *product; diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 9c517b5858f0..fe6a34e42bde 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -174,12 +174,6 @@ void __show_regs(struct pt_regs *regs, int all) d6, d7); } -void show_regs(struct pt_regs *regs) -{ - show_registers(regs); - show_trace(NULL, regs, ®s->sp, regs->bp); -} - void release_thread(struct task_struct *dead_task) { BUG_ON(dead_task->mm); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 52fbd0c60198..418f860880a2 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -211,12 +211,6 @@ void __show_regs(struct pt_regs *regs, int all) printk(KERN_INFO "DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7); } -void show_regs(struct pt_regs *regs) -{ - show_registers(regs); - show_trace(NULL, regs, (void *)(regs + 1), regs->bp); -} - void release_thread(struct task_struct *dead_task) { if (dead_task->mm) { -- GitLab From 0159f24ee764927bf44c1a25473bd4517febd21c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 13 Jan 2010 20:23:30 -0800 Subject: [PATCH 0671/3892] lib/vsprintf.c: Add IPV4 options %pI4[hnbl] for host, network, big and little endian This should allow the removal of the #defines and uses of NIPQUAD and NIPQUAD_FMT Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- lib/vsprintf.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e83e3e79a989..add0446dd921 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -699,13 +699,37 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, return string(buf, end, mac_addr, spec); } -static char *ip4_string(char *p, const u8 *addr, bool leading_zeros) +static char *ip4_string(char *p, const u8 *addr, const char *fmt) { int i; - + bool leading_zeros = (fmt[0] == 'i'); + int index; + int step; + + switch (fmt[2]) { + case 'h': +#ifdef __BIG_ENDIAN + index = 0; + step = 1; +#else + index = 3; + step = -1; +#endif + break; + case 'l': + index = 3; + step = -1; + break; + case 'n': + case 'b': + default: + index = 0; + step = 1; + break; + } for (i = 0; i < 4; i++) { char temp[3]; /* hold each IP quad in reverse order */ - int digits = put_dec_trunc(temp, addr[i]) - temp; + int digits = put_dec_trunc(temp, addr[index]) - temp; if (leading_zeros) { if (digits < 3) *p++ = '0'; @@ -717,6 +741,7 @@ static char *ip4_string(char *p, const u8 *addr, bool leading_zeros) *p++ = temp[digits]; if (i < 3) *p++ = '.'; + index += step; } *p = '\0'; @@ -796,7 +821,7 @@ static char *ip6_compressed_string(char *p, const char *addr) if (useIPv4) { if (needcolon) *p++ = ':'; - p = ip4_string(p, &in6.s6_addr[12], false); + p = ip4_string(p, &in6.s6_addr[12], "I4"); } *p = '\0'; @@ -836,7 +861,7 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr, { char ip4_addr[sizeof("255.255.255.255")]; - ip4_string(ip4_addr, addr, fmt[0] == 'i'); + ip4_string(ip4_addr, addr, fmt); return string(buf, end, ip4_addr, spec); } @@ -911,6 +936,7 @@ static char *uuid_string(char *buf, char *end, const u8 *addr, * - 'i' [46] for 'raw' IPv4/IPv6 addresses * IPv6 omits the colons (01020304...0f) * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) + * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order * - 'I6c' for IPv6 addresses printed as specified by * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form -- GitLab From 608f8a0d014db6cd18d4f535934d4b5d556e3013 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 13 Jan 2010 02:04:58 +0000 Subject: [PATCH 0672/3892] e1000e: use alternate MAC address on ESB2 if available Similar to 82571/2/3 parts that already do this, if ESB2/80003es2lan parts have an alternate MAC address provided in the EEPROM use it instead of the default MAC address. This patch makes the the actual code that does this generic so that it can be better used by both MAC families. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 33 +++++++++- drivers/net/e1000e/defines.h | 2 + drivers/net/e1000e/e1000.h | 11 +++- drivers/net/e1000e/es2lan.c | 28 +++++++- drivers/net/e1000e/hw.h | 5 +- drivers/net/e1000e/lib.c | 124 +++++++++++++++++++++-------------- drivers/net/e1000e/netdev.c | 2 +- 7 files changed, 147 insertions(+), 58 deletions(-) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 02d67d047d96..d1a45143c2aa 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -922,9 +922,12 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(IMC, 0xffffffff); icr = er32(ICR); - if (hw->mac.type == e1000_82571 && - hw->dev_spec.e82571.alt_mac_addr_is_present) - e1000e_set_laa_state_82571(hw, true); + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + return ret_val; + + e1000e_set_laa_state_82571(hw, true); /* Reinitialize the 82571 serdes link state machine */ if (hw->phy.media_type == e1000_media_type_internal_serdes) @@ -1620,6 +1623,29 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) return 0; } +/** + * e1000_read_mac_addr_82571 - Read device MAC address + * @hw: pointer to the HW structure + **/ +static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + + ret_val = e1000_read_mac_addr_generic(hw); + +out: + return ret_val; +} + /** * e1000_power_down_phy_copper_82571 - Remove link during PHY power down * @hw: pointer to the HW structure @@ -1706,6 +1732,7 @@ static struct e1000_mac_operations e82571_mac_ops = { .setup_link = e1000_setup_link_82571, /* .setup_physical_interface: media type dependent */ .setup_led = e1000e_setup_led_generic, + .read_mac_addr = e1000_read_mac_addr_82571, }; static struct e1000_phy_operations e82_phy_ops_igp = { diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index e02e38221ed4..db05ec355749 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -460,6 +460,8 @@ */ #define E1000_RAR_ENTRIES 15 #define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ +#define E1000_RAL_MAC_ADDR_LEN 4 +#define E1000_RAH_MAC_ADDR_LEN 2 /* Error Codes */ #define E1000_ERR_NVM 1 diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index cebbd9079d53..7c91e4bdd361 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -529,6 +529,7 @@ extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); extern s32 e1000e_blink_led(struct e1000_hw *hw); extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); +extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); extern void e1000e_reset_adaptive(struct e1000_hw *hw); extern void e1000e_update_adaptive(struct e1000_hw *hw); @@ -629,7 +630,15 @@ extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw); extern void e1000e_release_nvm(struct e1000_hw *hw); extern void e1000e_reload_nvm(struct e1000_hw *hw); -extern s32 e1000e_read_mac_addr(struct e1000_hw *hw); +extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); + +static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw) +{ + if (hw->mac.ops.read_mac_addr) + return hw->mac.ops.read_mac_addr(hw); + + return e1000_read_mac_addr_generic(hw); +} static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index e2aa3b788564..4bb9d88ad976 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -814,7 +814,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ew32(IMC, 0xffffffff); icr = er32(ICR); - return 0; + ret_val = e1000_check_alt_mac_addr_generic(hw); + + return ret_val; } /** @@ -1339,6 +1341,29 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, return ret_val; } +/** + * e1000_read_mac_addr_80003es2lan - Read device MAC address + * @hw: pointer to the HW structure + **/ +static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + + ret_val = e1000_read_mac_addr_generic(hw); + +out: + return ret_val; +} + /** * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down * @hw: pointer to the HW structure @@ -1403,6 +1428,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) } static struct e1000_mac_operations es2_mac_ops = { + .read_mac_addr = e1000_read_mac_addr_80003es2lan, .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index eccf29b75c41..127e6a226da1 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -389,6 +389,9 @@ enum e1e_registers { #define E1000_FUNC_1 1 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 +#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 + enum e1000_mac_type { e1000_82571, e1000_82572, @@ -756,6 +759,7 @@ struct e1000_mac_operations { s32 (*setup_physical_interface)(struct e1000_hw *); s32 (*setup_led)(struct e1000_hw *); void (*write_vfta)(struct e1000_hw *, u32, u32); + s32 (*read_mac_addr)(struct e1000_hw *); }; /* Function pointers for the PHY. */ @@ -897,7 +901,6 @@ struct e1000_fc_info { struct e1000_dev_spec_82571 { bool laa_is_present; - bool alt_mac_addr_is_present; u32 smb_counter; }; diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 2fa9b36a2c5a..547542428edc 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -138,6 +138,68 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) e1000e_rar_set(hw, mac_addr, i); } +/** + * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr + * @hw: pointer to the HW structure + * + * Checks the nvm for an alternate MAC address. An alternate MAC address + * can be setup by pre-boot software and must be treated like a permanent + * address and must override the actual permanent MAC address. If an + * alternate MAC address is found it is programmed into RAR0, replacing + * the permanent address that was installed into RAR0 by the Si on reset. + * This function will return SUCCESS unless it encounters an error while + * reading the EEPROM. + **/ +s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) +{ + u32 i; + s32 ret_val = 0; + u16 offset, nvm_alt_mac_addr_offset, nvm_data; + u8 alt_mac_addr[ETH_ALEN]; + + ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, + &nvm_alt_mac_addr_offset); + if (ret_val) { + e_dbg("NVM Read Error\n"); + goto out; + } + + if (nvm_alt_mac_addr_offset == 0xFFFF) { + /* There is no Alternate MAC Address */ + goto out; + } + + if (hw->bus.func == E1000_FUNC_1) + nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; + for (i = 0; i < ETH_ALEN; i += 2) { + offset = nvm_alt_mac_addr_offset + (i >> 1); + ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); + if (ret_val) { + e_dbg("NVM Read Error\n"); + goto out; + } + + alt_mac_addr[i] = (u8)(nvm_data & 0xFF); + alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); + } + + /* if multicast bit is set, the alternate address will not be used */ + if (alt_mac_addr[0] & 0x01) { + e_dbg("Ignoring Alternate Mac Address with MC bit set\n"); + goto out; + } + + /* + * We have a valid alternate MAC address, and we want to treat it the + * same as the normal permanent MAC address stored by the HW into the + * RAR. Do this by mapping this address into RAR0. + */ + e1000e_rar_set(hw, alt_mac_addr, 0); + +out: + return ret_val; +} + /** * e1000e_rar_set - Set receive address register * @hw: pointer to the HW structure @@ -2072,67 +2134,27 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) } /** - * e1000e_read_mac_addr - Read device MAC address + * e1000_read_mac_addr_generic - Read device MAC address * @hw: pointer to the HW structure * * Reads the device MAC address from the EEPROM and stores the value. * Since devices with two ports use the same EEPROM, we increment the * last bit in the MAC address for the second port. **/ -s32 e1000e_read_mac_addr(struct e1000_hw *hw) +s32 e1000_read_mac_addr_generic(struct e1000_hw *hw) { - s32 ret_val; - u16 offset, nvm_data, i; - u16 mac_addr_offset = 0; - - if (hw->mac.type == e1000_82571) { - /* Check for an alternate MAC address. An alternate MAC - * address can be setup by pre-boot software and must be - * treated like a permanent address and must override the - * actual permanent MAC address.*/ - ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, - &mac_addr_offset); - if (ret_val) { - e_dbg("NVM Read Error\n"); - return ret_val; - } - if (mac_addr_offset == 0xFFFF) - mac_addr_offset = 0; - - if (mac_addr_offset) { - if (hw->bus.func == E1000_FUNC_1) - mac_addr_offset += ETH_ALEN/sizeof(u16); - - /* make sure we have a valid mac address here - * before using it */ - ret_val = e1000_read_nvm(hw, mac_addr_offset, 1, - &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - return ret_val; - } - if (nvm_data & 0x0001) - mac_addr_offset = 0; - } + u32 rar_high; + u32 rar_low; + u16 i; - if (mac_addr_offset) - hw->dev_spec.e82571.alt_mac_addr_is_present = 1; - } + rar_high = er32(RAH(0)); + rar_low = er32(RAL(0)); - for (i = 0; i < ETH_ALEN; i += 2) { - offset = mac_addr_offset + (i >> 1); - ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - return ret_val; - } - hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); - hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); - } + for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8)); - /* Flip last bit of mac address if we're on second port */ - if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1) - hw->mac.perm_addr[5] ^= 1; + for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8)); for (i = 0; i < ETH_ALEN; i++) hw->mac.addr[i] = hw->mac.perm_addr[i]; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index c3745c9d21aa..0d5ef4c5c6db 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -5135,7 +5135,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, e1000_eeprom_checks(adapter); - /* copy the MAC address out of the NVM */ + /* copy the MAC address */ if (e1000e_read_mac_addr(&adapter->hw)) e_err("NVM Read Error while reading MAC address\n"); -- GitLab From f4d2dd4cd4d001f5dc20fc76c780c0c20c000c23 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 13 Jan 2010 02:05:18 +0000 Subject: [PATCH 0673/3892] e1000e: provide MAC-family-specific function to set LAN ID Provide MAC-specific function pointer to determine the LAN ID (PCI func). The LAN ID is used internally by the driver to determine which h/w lock to use to protect accessing the PHY on ESB2 as well as help to determine the alternate MAC address on some parts. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 7 ++++++ drivers/net/e1000e/e1000.h | 2 ++ drivers/net/e1000e/es2lan.c | 4 +++ drivers/net/e1000e/hw.h | 1 + drivers/net/e1000e/ich8lan.c | 1 + drivers/net/e1000e/lib.c | 48 +++++++++++++++++++++++++++--------- 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index d1a45143c2aa..7674a91824bc 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -267,8 +267,14 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) } switch (hw->mac.type) { + case e1000_82573: + func->set_lan_id = e1000_set_lan_id_single_port; + func->check_mng_mode = e1000e_check_mng_mode_generic; + func->led_on = e1000e_led_on_generic; + break; case e1000_82574: case e1000_82583: + func->set_lan_id = e1000_set_lan_id_single_port; func->check_mng_mode = e1000_check_mng_mode_82574; func->led_on = e1000_led_on_82574; break; @@ -1721,6 +1727,7 @@ static struct e1000_mac_operations e82571_mac_ops = { .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, .get_bus_info = e1000e_get_bus_info_pcie, + .set_lan_id = e1000_set_lan_id_multi_port_pcie, /* .get_link_up_info: media type dependent */ /* .led_on: mac type dependent */ .led_off = e1000e_led_off_generic, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 7c91e4bdd361..8b311ce0400e 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -502,6 +502,8 @@ extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); extern s32 e1000e_led_on_generic(struct e1000_hw *hw); extern s32 e1000e_led_off_generic(struct e1000_hw *hw); extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw); +extern void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw); +extern void e1000_set_lan_id_single_port(struct e1000_hw *hw); extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex); extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 4bb9d88ad976..27d21589a69a 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -246,6 +246,9 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter) break; } + /* set lan id for port to determine which phy lock to use */ + hw->mac.ops.set_lan_id(hw); + return 0; } @@ -1435,6 +1438,7 @@ static struct e1000_mac_operations es2_mac_ops = { .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan, .get_bus_info = e1000e_get_bus_info_pcie, + .set_lan_id = e1000_set_lan_id_multi_port_pcie, .get_link_up_info = e1000_get_link_up_info_80003es2lan, .led_on = e1000e_led_on_generic, .led_off = e1000e_led_off_generic, diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 127e6a226da1..9cac5d9b94b8 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -749,6 +749,7 @@ struct e1000_mac_operations { void (*clear_hw_cntrs)(struct e1000_hw *); void (*clear_vfta)(struct e1000_hw *); s32 (*get_bus_info)(struct e1000_hw *); + void (*set_lan_id)(struct e1000_hw *); s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); s32 (*led_on)(struct e1000_hw *); s32 (*led_off)(struct e1000_hw *); diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index ad08cf3f40c0..061cd100aac2 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -3302,6 +3302,7 @@ static struct e1000_mac_operations ich8_mac_ops = { /* cleanup_led dependent on mac type */ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, .get_bus_info = e1000_get_bus_info_ich8lan, + .set_lan_id = e1000_set_lan_id_single_port, .get_link_up_info = e1000_get_link_up_info_ich8lan, /* led_on dependent on mac type */ /* led_off dependent on mac type */ diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 547542428edc..5f6b17148d34 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -51,10 +51,10 @@ enum e1000_mng_mode { **/ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) { + struct e1000_mac_info *mac = &hw->mac; struct e1000_bus_info *bus = &hw->bus; struct e1000_adapter *adapter = hw->adapter; - u32 status; - u16 pcie_link_status, pci_header_type, cap_offset; + u16 pcie_link_status, cap_offset; cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); if (!cap_offset) { @@ -68,19 +68,45 @@ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) PCIE_LINK_WIDTH_SHIFT); } - pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER, - &pci_header_type); - if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { - status = er32(STATUS); - bus->func = (status & E1000_STATUS_FUNC_MASK) - >> E1000_STATUS_FUNC_SHIFT; - } else { - bus->func = 0; - } + mac->ops.set_lan_id(hw); return 0; } +/** + * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices + * + * @hw: pointer to the HW structure + * + * Determines the LAN function id by reading memory-mapped registers + * and swaps the port value if requested. + **/ +void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + u32 reg; + + /* + * The status register reports the correct function number + * for the device regardless of function swap state. + */ + reg = er32(STATUS); + bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; +} + +/** + * e1000_set_lan_id_single_port - Set LAN id for a single port device + * @hw: pointer to the HW structure + * + * Sets the LAN function id to zero for a single port device. + **/ +void e1000_set_lan_id_single_port(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + + bus->func = 0; +} + /** * e1000_clear_vfta_generic - Clear VLAN filter table * @hw: pointer to the HW structure -- GitLab From ab8932f3e8e07df92d6ce3fa41f5af0dda865429 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 13 Jan 2010 02:05:38 +0000 Subject: [PATCH 0674/3892] e1000e: genericize the update multicast address list Make updating the multicast address list generic for all families and enforce the requirement to update the entire multicast table array all at once instead of piecemeal which causes problems on some parts. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 28 +----------------- drivers/net/e1000e/e1000.h | 4 +-- drivers/net/e1000e/hw.h | 6 +++- drivers/net/e1000e/lib.c | 58 ++++++++++--------------------------- drivers/net/e1000e/netdev.c | 20 ++++--------- 5 files changed, 27 insertions(+), 89 deletions(-) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 7674a91824bc..3c95acb3a87d 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -1233,32 +1233,6 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw) return 0; } -/** - * e1000_update_mc_addr_list_82571 - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers - * - * Updates the Receive Address Registers and Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. - **/ -static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, - u8 *mc_addr_list, - u32 mc_addr_count, - u32 rar_used_count, - u32 rar_count) -{ - if (e1000e_get_laa_state_82571(hw)) - rar_count--; - - e1000e_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count, - rar_used_count, rar_count); -} - /** * e1000_setup_link_82571 - Setup flow control and link settings * @hw: pointer to the HW structure @@ -1731,7 +1705,7 @@ static struct e1000_mac_operations e82571_mac_ops = { /* .get_link_up_info: media type dependent */ /* .led_on: mac type dependent */ .led_off = e1000e_led_off_generic, - .update_mc_addr_list = e1000_update_mc_addr_list_82571, + .update_mc_addr_list = e1000e_update_mc_addr_list_generic, .write_vfta = e1000_write_vfta_generic, .clear_vfta = e1000_clear_vfta_82571, .reset_hw = e1000_reset_hw_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 8b311ce0400e..aec378e7441d 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -518,9 +518,7 @@ extern void e1000_clear_vfta_generic(struct e1000_hw *hw); extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count, - u32 rar_used_count, - u32 rar_count); + u32 mc_addr_count); extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 9cac5d9b94b8..8bdcd5f24eff 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -753,7 +753,7 @@ struct e1000_mac_operations { s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); s32 (*led_on)(struct e1000_hw *); s32 (*led_off)(struct e1000_hw *); - void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32); + void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32); s32 (*reset_hw)(struct e1000_hw *); s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); @@ -819,6 +819,10 @@ struct e1000_mac_info { u16 ifs_ratio; u16 ifs_step_size; u16 mta_reg_count; + + /* Maximum size of the MTA register table in all supported adapters */ + #define MAX_MTA_REG 128 + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 5f6b17148d34..2425ed11d5cc 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -340,62 +340,34 @@ static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers * - * Updates the Receive Address Registers and Multicast Table Array. + * Updates entire Multicast Table Array. * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. **/ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count) + u8 *mc_addr_list, u32 mc_addr_count) { - u32 i; - u32 *mcarray = kzalloc(hw->mac.mta_reg_count * sizeof(u32), GFP_ATOMIC); + u32 hash_value, hash_bit, hash_reg; + int i; - if (!mcarray) { - printk(KERN_ERR "multicast array memory allocation failed\n"); - return; - } + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); - /* - * Load the first set of multicast addresses into the exact - * filters (RAR). If there are not enough to fill the RAR - * array, clear the filters. - */ - for (i = rar_used_count; i < rar_count; i++) { - if (mc_addr_count) { - e1000e_rar_set(hw, mc_addr_list, i); - mc_addr_count--; - mc_addr_list += ETH_ALEN; - } else { - E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); - e1e_flush(); - E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); - e1e_flush(); - } - } - - /* Load any remaining multicast addresses into the hash table. */ - for (; mc_addr_count > 0; mc_addr_count--) { - u32 hash_value, hash_reg, hash_bit, mta; + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32) i < mc_addr_count; i++) { hash_value = e1000_hash_mc_addr(hw, mc_addr_list); - e_dbg("Hash value = 0x%03X\n", hash_value); + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); hash_bit = hash_value & 0x1F; - mta = (1 << hash_bit); - mcarray[hash_reg] |= mta; - mc_addr_list += ETH_ALEN; - } - /* write the hash table completely */ - for (i = 0; i < hw->mac.mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, mcarray[i]); + hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); + mc_addr_list += (ETH_ALEN); + } + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]); e1e_flush(); - kfree(mcarray); } /** diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 0d5ef4c5c6db..3d57ca5482f4 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2536,22 +2536,14 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) * @hw: pointer to the HW structure * @mc_addr_list: array of multicast addresses to program * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers * - * Updates the Receive Address Registers and Multicast Table Array. + * Updates the Multicast Table Array. * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. Currently no func pointer - * exists and all implementations are handled in the generic version of this - * function. **/ static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count, u32 rar_used_count, - u32 rar_count) + u32 mc_addr_count) { - hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count, - rar_used_count, rar_count); + hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count); } /** @@ -2567,7 +2559,6 @@ static void e1000_set_multi(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct e1000_mac_info *mac = &hw->mac; struct dev_mc_list *mc_ptr; u8 *mta_list; u32 rctl; @@ -2609,15 +2600,14 @@ static void e1000_set_multi(struct net_device *netdev) mc_ptr = mc_ptr->next; } - e1000_update_mc_addr_list(hw, mta_list, i, 1, - mac->rar_entry_count); + e1000_update_mc_addr_list(hw, mta_list, i); kfree(mta_list); } else { /* * if we're called from probe, we might not have * anything to do here, so clear out the list */ - e1000_update_mc_addr_list(hw, NULL, 0, 1, mac->rar_entry_count); + e1000_update_mc_addr_list(hw, NULL, 0); } } -- GitLab From 76b11f8e270f04851774ff64b16e29e5a43d3a1a Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 11 Jan 2010 02:50:50 +0000 Subject: [PATCH 0675/3892] qeth: HiperSockets Network Traffic Analyzer New feature to trace HiperSockets network traffic for debugging purposes. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 5 +- drivers/s390/net/qeth_core_main.c | 130 ++++++++++++---------- drivers/s390/net/qeth_core_mpc.h | 44 +++++++- drivers/s390/net/qeth_core_sys.c | 8 +- drivers/s390/net/qeth_l2_main.c | 3 +- drivers/s390/net/qeth_l3.h | 2 + drivers/s390/net/qeth_l3_main.c | 174 +++++++++++++++++++++++++----- drivers/s390/net/qeth_l3_sys.c | 56 ++++++++++ 8 files changed, 336 insertions(+), 86 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index b232693378cd..a3ac4456e0b1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -649,6 +649,7 @@ struct qeth_card_options { int performance_stats; int rx_sg_cb; enum qeth_ipa_isolation_modes isolation; + int sniffer; }; /* @@ -737,6 +738,7 @@ struct qeth_card { struct qeth_discipline discipline; atomic_t force_alloc_skb; struct service_level qeth_service_level; + struct qdio_ssqd_desc ssqd; }; struct qeth_card_list_struct { @@ -811,7 +813,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, enum qeth_ipa_cmds, enum qeth_prot_versions); int qeth_query_setadapterparms(struct qeth_card *); -int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *); +int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *, + unsigned int, const char *); void qeth_queue_input_buffer(struct qeth_card *, int); struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, struct qdio_buffer *, struct qdio_buffer_element **, int *, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d34804d5ece1..2c8e9da8753f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) card->qdio.init_pool.buf_count = bufcnt; return qeth_alloc_buffer_pool(card); } +EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); static int qeth_issue_next_read(struct qeth_card *card) { @@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, if (IS_IPA(iob->data)) { cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); if (IS_IPA_REPLY(cmd)) { - if (cmd->hdr.command < IPA_CMD_SETCCID || - cmd->hdr.command > IPA_CMD_MODCCID) + if (cmd->hdr.command != IPA_CMD_SETCCID && + cmd->hdr.command != IPA_CMD_DELCCID && + cmd->hdr.command != IPA_CMD_MODCCID && + cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card); return cmd; @@ -1100,11 +1103,6 @@ static int qeth_setup_card(struct qeth_card *card) card->thread_running_mask = 0; INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); INIT_LIST_HEAD(&card->ip_list); - card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); - if (!card->ip_tbd_list) { - QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); - return -ENOMEM; - } INIT_LIST_HEAD(card->ip_tbd_list); INIT_LIST_HEAD(&card->cmd_waiter_list); init_waitqueue_head(&card->wait_q); @@ -1138,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void) QETH_DBF_TEXT(SETUP, 2, "alloccrd"); card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); if (!card) - return NULL; + goto out; QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); - if (qeth_setup_channel(&card->read)) { - kfree(card); - return NULL; - } - if (qeth_setup_channel(&card->write)) { - qeth_clean_channel(&card->read); - kfree(card); - return NULL; + card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!card->ip_tbd_list) { + QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); + goto out_card; } + if (qeth_setup_channel(&card->read)) + goto out_ip; + if (qeth_setup_channel(&card->write)) + goto out_channel; card->options.layer2 = -1; card->qeth_service_level.seq_print = qeth_core_sl_print; register_service_level(&card->qeth_service_level); return card; + +out_channel: + qeth_clean_channel(&card->read); +out_ip: + kfree(card->ip_tbd_list); +out_card: + kfree(card); +out: + return NULL; } static int qeth_determine_card_type(struct qeth_card *card) @@ -2573,8 +2580,8 @@ int qeth_query_setadapterparms(struct qeth_card *card) } EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); -int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, - const char *dbftext) +int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, + unsigned int qdio_error, const char *dbftext) { if (qdio_error) { QETH_DBF_TEXT(TRACE, 2, dbftext); @@ -2584,7 +2591,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, QETH_DBF_TEXT_(QERR, 2, " F14=%02X", buf->element[14].flags & 0xff); QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); - return 1; + if ((buf->element[15].flags & 0xff) == 0x12) { + card->stats.rx_dropped++; + return 0; + } else + return 1; } return 0; } @@ -2667,7 +2678,7 @@ static int qeth_handle_send_error(struct qeth_card *card, qdio_err = 1; } } - qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); + qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr"); if (!qdio_err) return QETH_SEND_ERROR_NONE; @@ -3509,6 +3520,7 @@ void qeth_tx_timeout(struct net_device *dev) { struct qeth_card *card; + QETH_DBF_TEXT(TRACE, 4, "txtimeo"); card = dev->ml_priv; card->stats.tx_errors++; qeth_schedule_recovery(card); @@ -3847,9 +3859,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, int qeth_core_hardsetup_card(struct qeth_card *card) { - struct qdio_ssqd_desc *ssqd; int retries = 0; - int mpno = 0; int rc; QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); @@ -3882,31 +3892,6 @@ retriable: else goto retry; } - - rc = qeth_get_unitaddr(card); - if (rc) { - QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); - return rc; - } - - ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); - if (!ssqd) { - rc = -ENOMEM; - goto out; - } - rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); - if (rc == 0) - mpno = ssqd->pcnt; - kfree(ssqd); - - if (mpno) - mpno = min(mpno - 1, QETH_MAX_PORTNO); - if (card->info.portno > mpno) { - QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d" - "\n.", CARD_BUS_ID(card), card->info.portno); - rc = -ENODEV; - goto out; - } qeth_init_tokens(card); qeth_init_func_level(card); rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); @@ -3990,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, struct qdio_buffer_element *element = *__element; int offset = *__offset; struct sk_buff *skb = NULL; - int skb_len; + int skb_len = 0; void *data_ptr; int data_len; int headroom = 0; @@ -4009,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, *hdr = element->addr + offset; offset += sizeof(struct qeth_hdr); - if (card->options.layer2) { - if (card->info.type == QETH_CARD_TYPE_OSN) { - skb_len = (*hdr)->hdr.osn.pdu_length; - headroom = sizeof(struct qeth_hdr); - } else { - skb_len = (*hdr)->hdr.l2.pkt_length; - } - } else { + switch ((*hdr)->hdr.l2.id) { + case QETH_HEADER_TYPE_LAYER2: + skb_len = (*hdr)->hdr.l2.pkt_length; + break; + case QETH_HEADER_TYPE_LAYER3: skb_len = (*hdr)->hdr.l3.length; if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || (card->info.link_type == QETH_LINK_TYPE_HSTR)) headroom = TR_HLEN; else headroom = ETH_HLEN; + break; + case QETH_HEADER_TYPE_OSN: + skb_len = (*hdr)->hdr.osn.pdu_length; + headroom = sizeof(struct qeth_hdr); + break; + default: + break; } if (!skb_len) @@ -4177,6 +4166,33 @@ void qeth_core_free_discipline(struct qeth_card *card) card->discipline.ccwgdriver = NULL; } +static void qeth_determine_capabilities(struct qeth_card *card) +{ + int rc; + + QETH_DBF_TEXT(SETUP, 2, "detcapab"); + rc = ccw_device_set_online(CARD_DDEV(card)); + if (rc) { + QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); + goto out; + } + + rc = qeth_get_unitaddr(card); + if (rc) { + QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); + goto out_offline; + } + + rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); + if (rc) + QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); + +out_offline: + ccw_device_set_offline(CARD_DDEV(card)); +out: + return; +} + static int qeth_core_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card; @@ -4242,6 +4258,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) write_lock_irqsave(&qeth_core_card_list.rwlock, flags); list_add_tail(&card->list, &qeth_core_card_list.list); write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); + + qeth_determine_capabilities(card); return 0; err_card: diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 1ba51152f667..104a3351e02b 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -156,6 +156,8 @@ enum qeth_ipa_return_codes { IPA_RC_IP_TABLE_FULL = 0x0002, IPA_RC_UNKNOWN_ERROR = 0x0003, IPA_RC_UNSUPPORTED_COMMAND = 0x0004, + IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005, + IPA_RC_INVALID_FORMAT = 0x0006, IPA_RC_DUP_IPV6_REMOTE = 0x0008, IPA_RC_DUP_IPV6_HOME = 0x0010, IPA_RC_UNREGISTERED_ADDR = 0x0011, @@ -196,6 +198,11 @@ enum qeth_ipa_return_codes { IPA_RC_INVALID_IP_VERSION2 = 0xf001, IPA_RC_FFFF = 0xffff }; +/* for DELIP */ +#define IPA_RC_IP_ADDRESS_NOT_DEFINED IPA_RC_PRIMARY_ALREADY_DEFINED +/* for SET_DIAGNOSTIC_ASSIST */ +#define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL +#define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR /* IPA function flags; each flag marks availability of respective function */ enum qeth_ipa_funcs { @@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd { IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, + IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L, IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, }; enum qeth_ipa_mac_ops { @@ -424,6 +432,40 @@ struct qeth_create_destroy_address { __u8 unique_id[8]; } __attribute__ ((packed)); +/* SET DIAGNOSTIC ASSIST IPA Command: *************************************/ + +enum qeth_diags_cmds { + QETH_DIAGS_CMD_QUERY = 0x0001, + QETH_DIAGS_CMD_TRAP = 0x0002, + QETH_DIAGS_CMD_TRACE = 0x0004, + QETH_DIAGS_CMD_NOLOG = 0x0008, + QETH_DIAGS_CMD_DUMP = 0x0010, +}; + +enum qeth_diags_trace_types { + QETH_DIAGS_TYPE_HIPERSOCKET = 0x02, +}; + +enum qeth_diags_trace_cmds { + QETH_DIAGS_CMD_TRACE_ENABLE = 0x0001, + QETH_DIAGS_CMD_TRACE_DISABLE = 0x0002, + QETH_DIAGS_CMD_TRACE_MODIFY = 0x0004, + QETH_DIAGS_CMD_TRACE_REPLACE = 0x0008, + QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, +}; + +struct qeth_ipacmd_diagass { + __u32 host_tod2; + __u32:32; + __u16 subcmd_len; + __u16:16; + __u32 subcmd; + __u8 type; + __u8 action; + __u16 options; + __u32:32; +} __attribute__ ((packed)); + /* Header for each IPA command */ struct qeth_ipacmd_hdr { __u8 command; @@ -452,6 +494,7 @@ struct qeth_ipa_cmd { struct qeth_create_destroy_address create_destroy_addr; struct qeth_ipacmd_setadpparms setadapterparms; struct qeth_set_routing setrtg; + struct qeth_ipacmd_diagass diagass; } data; } __attribute__ ((packed)); @@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes { QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, }; - extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 9ff2b36fdc43..ac2239a4f133 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -118,7 +118,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev, { struct qeth_card *card = dev_get_drvdata(dev); char *tmp; - unsigned int portno; + unsigned int portno, limit; if (!card) return -EINVAL; @@ -128,9 +128,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev, return -EPERM; portno = simple_strtoul(buf, &tmp, 16); - if (portno > QETH_MAX_PORTNO) { + if (portno > QETH_MAX_PORTNO) + return -EINVAL; + limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); + if (portno > limit) return -EINVAL; - } card->info.portno = portno; return count; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 038299ae3feb..74ba388a159f 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -769,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, index = i % QDIO_MAX_BUFFERS_PER_Q; buffer = &card->qdio.in_q->bufs[index]; if (!(qdio_err && - qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr"))) + qeth_check_qdio_errors(card, buffer->buffer, qdio_err, + "qinerr"))) qeth_l2_process_inbound_buffer(card, buffer, index); /* clear buffer and give back to hardware */ qeth_put_buffer_pool_entry(card, buffer->pool_entry); diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 321988fa9f7d..8447d233d0b3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -13,6 +13,8 @@ #include "qeth_core.h" +#define QETH_SNIFF_AVAIL 0x0008 + struct qeth_ipaddr { struct list_head entry; enum qeth_ip_types type; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fd1b6ed3721f..337d03fb045d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -242,6 +242,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *tmp, *t; int found = 0; + if (card->options.sniffer) + return 0; list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) @@ -457,6 +459,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 2, "sdiplist"); QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); + if (card->options.sniffer) + return; spin_lock_irqsave(&card->ip_lock, flags); tbd_list = card->ip_tbd_list; card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); @@ -495,7 +499,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) spin_unlock_irqrestore(&card->ip_lock, flags); rc = qeth_l3_deregister_addr_entry(card, addr); spin_lock_irqsave(&card->ip_lock, flags); - if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED)) + if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED)) kfree(addr); else list_add_tail(&addr->entry, &card->ip_list); @@ -513,6 +517,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, unsigned long flags; QETH_DBF_TEXT(TRACE, 4, "clearip"); + if (recover && card->options.sniffer) + return; spin_lock_irqsave(&card->ip_lock, flags); /* clear todo list */ list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { @@ -1674,6 +1680,76 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) return rc; } +static int +qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u16 rc; + + QETH_DBF_TEXT(SETUP, 2, "diastrcb"); + + cmd = (struct qeth_ipa_cmd *)data; + rc = cmd->hdr.return_code; + if (rc) { + QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); + if (cmd->data.diagass.action == QETH_DIAGS_CMD_TRACE_ENABLE) { + switch (rc) { + case IPA_RC_HARDWARE_AUTH_ERROR: + dev_warn(&card->gdev->dev, "The device is not " + "authorized to run as a HiperSockets " + "network traffic analyzer\n"); + break; + case IPA_RC_TRACE_ALREADY_ACTIVE: + dev_warn(&card->gdev->dev, "A HiperSockets " + "network traffic analyzer is already " + "active in the HiperSockets LAN\n"); + break; + default: + break; + } + } + return 0; + } + + switch (cmd->data.diagass.action) { + case QETH_DIAGS_CMD_TRACE_QUERY: + break; + case QETH_DIAGS_CMD_TRACE_DISABLE: + card->info.promisc_mode = SET_PROMISC_MODE_OFF; + dev_info(&card->gdev->dev, "The HiperSockets network traffic " + "analyzer is deactivated\n"); + break; + case QETH_DIAGS_CMD_TRACE_ENABLE: + card->info.promisc_mode = SET_PROMISC_MODE_ON; + dev_info(&card->gdev->dev, "The HiperSockets network traffic " + "analyzer is activated\n"); + break; + default: + QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", + cmd->data.diagass.action, QETH_CARD_IFNAME(card)); + } + + return 0; +} + +static int +qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "diagtrac"); + + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.diagass.subcmd_len = 16; + cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; + cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; + cmd->data.diagass.action = diags_cmd; + return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); +} + static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) { @@ -1951,7 +2027,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, case QETH_CAST_ANYCAST: case QETH_CAST_NOCAST: default: - skb->pkt_type = PACKET_HOST; + if (card->options.sniffer) + skb->pkt_type = PACKET_OTHERHOST; + else + skb->pkt_type = PACKET_HOST; memcpy(tg_addr, card->dev->dev_addr, card->dev->addr_len); } @@ -2007,7 +2086,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, int offset; __u16 vlan_tag = 0; unsigned int len; - /* get first element of current buffer */ element = (struct qdio_buffer_element *)&buf->buffer->element[0]; offset = 0; @@ -2026,7 +2104,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, case QETH_HEADER_TYPE_LAYER3: vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); len = skb->len; - if (vlan_tag) + if (vlan_tag && !card->options.sniffer) if (card->vlangrp) vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); @@ -2037,6 +2115,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, else netif_rx(skb); break; + case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, skb->dev); + if (card->options.checksum_type == NO_CHECKSUMMING) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + len = skb->len; + netif_receive_skb(skb); + break; default: dev_kfree_skb_any(skb); QETH_DBF_TEXT(TRACE, 3, "inbunkno"); @@ -2118,6 +2206,9 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); qeth_set_allowed_threads(card, 0, 1); + if (card->options.sniffer && + (card->info.promisc_mode == SET_PROMISC_MODE_ON)) + qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); if (card->read.state == CH_STATE_UP && card->write.state == CH_STATE_UP && (card->state == CARD_STATE_UP)) { @@ -2162,6 +2253,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) return rc; } +/* + * test for and Switch promiscuous mode (on or off) + * either for guestlan or HiperSocket Sniffer + */ +static void +qeth_l3_handle_promisc_mode(struct qeth_card *card) +{ + struct net_device *dev = card->dev; + + if (((dev->flags & IFF_PROMISC) && + (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || + (!(dev->flags & IFF_PROMISC) && + (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) + return; + + if (card->info.guestlan) { /* Guestlan trace */ + if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) + qeth_setadp_promisc_mode(card); + } else if (card->options.sniffer && /* HiperSockets trace */ + qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { + if (dev->flags & IFF_PROMISC) { + QETH_DBF_TEXT(TRACE, 3, "+promisc"); + qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE); + } else { + QETH_DBF_TEXT(TRACE, 3, "-promisc"); + qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); + } + } +} + static void qeth_l3_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; @@ -2170,15 +2291,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) if (qeth_threads_running(card, QETH_RECOVER_THREAD) && (card->state != CARD_STATE_UP)) return; - qeth_l3_delete_mc_addresses(card); - qeth_l3_add_multicast_ipv4(card); + if (!card->options.sniffer) { + qeth_l3_delete_mc_addresses(card); + qeth_l3_add_multicast_ipv4(card); #ifdef CONFIG_QETH_IPV6 - qeth_l3_add_multicast_ipv6(card); + qeth_l3_add_multicast_ipv6(card); #endif - qeth_l3_set_ip_addr_list(card); - if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) - return; - qeth_setadp_promisc_mode(card); + qeth_l3_set_ip_addr_list(card); + if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) + return; + } + qeth_l3_handle_promisc_mode(card); } static const char *qeth_l3_arp_get_error_cause(int *rc) @@ -2778,8 +2901,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int nr_frags; if ((card->info.type == QETH_CARD_TYPE_IQD) && - (skb->protocol != htons(ETH_P_IPV6)) && - (skb->protocol != htons(ETH_P_IP))) + (((skb->protocol != htons(ETH_P_IPV6)) && + (skb->protocol != htons(ETH_P_IP))) || + card->options.sniffer)) goto tx_drop; if ((card->state != CARD_STATE_UP) || !card->lan_online) { @@ -3155,7 +3279,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, index = i % QDIO_MAX_BUFFERS_PER_Q; buffer = &card->qdio.in_q->bufs[index]; if (!(qdio_err && - qeth_check_qdio_errors(buffer->buffer, + qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qinerr"))) qeth_l3_process_inbound_buffer(card, buffer, index); /* clear buffer and give back to hardware */ @@ -3250,20 +3374,22 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } else card->lan_online = 1; - qeth_l3_set_large_send(card, card->options.large_send); rc = qeth_l3_setadapter_parms(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); - rc = qeth_l3_start_ipassists(card); - if (rc) - QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); - rc = qeth_l3_setrouting_v4(card); - if (rc) - QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); - rc = qeth_l3_setrouting_v6(card); - if (rc) - QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); + if (!card->options.sniffer) { + rc = qeth_l3_start_ipassists(card); + if (rc) + QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); + qeth_l3_set_large_send(card, card->options.large_send); + rc = qeth_l3_setrouting_v4(card); + if (rc) + QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); + rc = qeth_l3_setrouting_v6(card); + if (rc) + QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); + } netif_tx_disable(card->dev); rc = qeth_init_qdio_queues(card); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 3360b0941aa1..3f08b11274ae 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -319,6 +319,61 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev, static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, qeth_l3_dev_checksum_store); +static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + + if (!card) + return -EINVAL; + + return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0); +} + +static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int ret; + unsigned long i; + + if (!card) + return -EINVAL; + + if (card->info.type != QETH_CARD_TYPE_IQD) + return -EPERM; + + if ((card->state != CARD_STATE_DOWN) && + (card->state != CARD_STATE_RECOVER)) + return -EPERM; + + ret = strict_strtoul(buf, 16, &i); + if (ret) + return -EINVAL; + switch (i) { + case 0: + card->options.sniffer = i; + break; + case 1: + ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); + if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) { + card->options.sniffer = i; + if (card->qdio.init_pool.buf_count != + QETH_IN_BUF_COUNT_MAX) + qeth_realloc_buffer_pool(card, + QETH_IN_BUF_COUNT_MAX); + break; + } else + return -EPERM; + default: /* fall through */ + return -EINVAL; + } + return count; +} + +static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, + qeth_l3_dev_sniffer_store); + static ssize_t qeth_l3_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -373,6 +428,7 @@ static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_broadcast_mode.attr, &dev_attr_canonical_macaddr.attr, &dev_attr_checksumming.attr, + &dev_attr_sniffer.attr, &dev_attr_large_send.attr, NULL, }; -- GitLab From 84b66683dba002f4cce2aaf78bf45debfaf22795 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 11 Jan 2010 02:50:51 +0000 Subject: [PATCH 0676/3892] qeth: avoid recovery during device online setting If a qeth device is set online, several initialisation steps are performed. If a failure in one of these steps occurs, the qeth device is reset into DOWN state. If due to the failure a qeth recovery is scheduled and started in another thread, this might cause all kinds of conflicts, even a kernel panic. The patch forbids scheduling of a qeth recovery while online processing is performed till the card is in state SOFTSETUP. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 1 - drivers/s390/net/qeth_l3_main.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 74ba388a159f..c3258b0dd649 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -927,7 +927,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) QETH_DBF_TEXT(SETUP, 2, "setonlin"); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); - qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); recover_flag = card->state; rc = qeth_core_hardsetup_card(card); if (rc) { diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 337d03fb045d..5475834ab916 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3338,8 +3338,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) QETH_DBF_TEXT(SETUP, 2, "setonlin"); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); - qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); - recover_flag = card->state; rc = qeth_core_hardsetup_card(card); if (rc) { -- GitLab From a60389abaab92213c79790e074ff6bc36ac0ebe5 Mon Sep 17 00:00:00 2001 From: Einar Lueck Date: Mon, 11 Jan 2010 02:50:52 +0000 Subject: [PATCH 0677/3892] qeth: default BLKT values for new OSA/3 hardware Set default BLKT values for new OSA/3 hardware. Signed-off-by: Einar Lueck Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 41 ++++++++++++++++++++----------- drivers/s390/net/qeth_core_sys.c | 6 ++--- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 2c8e9da8753f..fa8a519218ac 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1362,26 +1362,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer, return ret; } -static int qeth_get_unitaddr(struct qeth_card *card) +static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) { - int length; - char *prcd; - int rc; - - QETH_DBF_TEXT(SETUP, 2, "getunit"); - rc = qeth_read_conf_data(card, (void **) &prcd, &length); - if (rc) { - QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", - dev_name(&card->gdev->dev), rc); - return rc; - } + QETH_DBF_TEXT(SETUP, 2, "cfgunit"); card->info.chpid = prcd[30]; card->info.unit_addr2 = prcd[31]; card->info.cula = prcd[63]; card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && (prcd[0x11] == _ascebc['M'])); - kfree(prcd); - return 0; +} + +static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) +{ + QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); + + if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) { + card->info.blkt.time_total = 250; + card->info.blkt.inter_packet = 5; + card->info.blkt.inter_packet_jumbo = 15; + } else { + card->info.blkt.time_total = 0; + card->info.blkt.inter_packet = 0; + card->info.blkt.inter_packet_jumbo = 0; + } } static void qeth_init_tokens(struct qeth_card *card) @@ -4169,6 +4172,8 @@ void qeth_core_free_discipline(struct qeth_card *card) static void qeth_determine_capabilities(struct qeth_card *card) { int rc; + int length; + char *prcd; QETH_DBF_TEXT(SETUP, 2, "detcapab"); rc = ccw_device_set_online(CARD_DDEV(card)); @@ -4177,11 +4182,17 @@ static void qeth_determine_capabilities(struct qeth_card *card) goto out; } - rc = qeth_get_unitaddr(card); + + rc = qeth_read_conf_data(card, (void **) &prcd, &length); if (rc) { + QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", + dev_name(&card->gdev->dev), rc); QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); goto out_offline; } + qeth_configure_unitaddr(card, prcd); + qeth_configure_blkt_default(card, prcd); + kfree(prcd); rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); if (rc) diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index ac2239a4f133..88ae4357136a 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -539,7 +539,7 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); return qeth_dev_blkt_store(card, buf, count, - &card->info.blkt.time_total, 1000); + &card->info.blkt.time_total, 5000); } @@ -561,7 +561,7 @@ static ssize_t qeth_dev_blkt_inter_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); return qeth_dev_blkt_store(card, buf, count, - &card->info.blkt.inter_packet, 100); + &card->info.blkt.inter_packet, 1000); } static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, @@ -582,7 +582,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); return qeth_dev_blkt_store(card, buf, count, - &card->info.blkt.inter_packet_jumbo, 100); + &card->info.blkt.inter_packet_jumbo, 1000); } static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, -- GitLab From 37fce430dd66a6251bde6ef0004a1da69b26c028 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Jan 2010 20:59:13 +0000 Subject: [PATCH 0678/3892] drivers/net/tlan: Remove TRUE/FALSE defines, use bool Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tlan.c | 28 ++++++++++++++-------------- drivers/net/tlan.h | 3 --- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 613943eb6e75..3ec31dce99f9 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -338,7 +338,7 @@ static int TLan_PhyInternalService( struct net_device * ); static int TLan_PhyDp83840aCheck( struct net_device * ); */ -static int TLan_MiiReadReg( struct net_device *, u16, u16, u16 * ); +static bool TLan_MiiReadReg( struct net_device *, u16, u16, u16 * ); static void TLan_MiiSendData( u16, u32, unsigned ); static void TLan_MiiSync( u16 ); static void TLan_MiiWriteReg( struct net_device *, u16, u16, u16 ); @@ -2204,7 +2204,7 @@ TLan_ResetAdapter( struct net_device *dev ) u32 data; u8 data8; - priv->tlanFullDuplex = FALSE; + priv->tlanFullDuplex = false; priv->phyOnline=0; netif_carrier_off(dev); @@ -2259,7 +2259,7 @@ TLan_ResetAdapter( struct net_device *dev ) TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a ); } else if ( priv->duplex == TLAN_DUPLEX_FULL ) { TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 ); - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; } else { TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); } @@ -2651,14 +2651,14 @@ static void TLan_PhyStartLink( struct net_device *dev ) TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { @@ -2695,7 +2695,7 @@ static void TLan_PhyStartLink( struct net_device *dev ) tctl &= ~TLAN_TC_AUISEL; if ( priv->duplex == TLAN_DUPLEX_FULL ) { control |= MII_GC_DUPLEX; - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; } if ( priv->speed == TLAN_SPEED_100 ) { control |= MII_GC_SPEEDSEL; @@ -2750,9 +2750,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = true; } if ( ( ! ( mode & 0x0180 ) ) && @@ -2855,8 +2855,8 @@ void TLan_PhyMonitor( struct net_device *dev ) * TLan_MiiReadReg * * Returns: - * 0 if ack received ok - * 1 otherwise. + * false if ack received ok + * true if no ack received or other error * * Parms: * dev The device structure containing @@ -2875,17 +2875,17 @@ void TLan_PhyMonitor( struct net_device *dev ) * **************************************************************/ -static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) +static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) { u8 nack; u16 sio, tmp; u32 i; - int err; + bool err; int minten; TLanPrivateInfo *priv = netdev_priv(dev); unsigned long flags = 0; - err = FALSE; + err = false; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; @@ -2918,7 +2918,7 @@ static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) TLan_SetBit(TLAN_NET_SIO_MCLK, sio); } tmp = 0xffff; - err = TRUE; + err = true; } else { /* ACK, so read data */ for (tmp = 0, i = 0x8000; i; i >>= 1) { TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 4b82f283e985..d13ff12d7500 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -31,9 +31,6 @@ * ****************************************************************/ -#define FALSE 0 -#define TRUE 1 - #define TLAN_MIN_FRAME_SIZE 64 #define TLAN_MAX_FRAME_SIZE 1600 -- GitLab From e1d5a010729a7a495a8a8de85727f3f0d62f06a0 Mon Sep 17 00:00:00 2001 From: Samir Bellabes Date: Thu, 7 Jan 2010 22:10:56 +0000 Subject: [PATCH 0679/3892] genetlink: optimize ctrl_dumpfamily() there is a unnecessary test which can be replaced by a good initialization in the 'for' statement Noticed by Serge E. Hallyn Signed-off-by: Samir Bellabes Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index d07ecda0a92d..a4b6e148c5de 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -681,9 +681,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) int chains_to_skip = cb->args[0]; int fams_to_skip = cb->args[1]; - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { - if (i < chains_to_skip) - continue; + for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { n = 0; list_for_each_entry(rt, genl_family_chain(i), family_list) { if (!rt->netnsok && !net_eq(net, &init_net)) -- GitLab From 508e14b4a4fb1a824a14f2c5b8d7df67b313f8e4 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Jan 2010 14:27:30 +0000 Subject: [PATCH 0680/3892] netpoll: allow execution of multiple rx_hooks per interface Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/netpoll.h | 11 ++- net/core/netpoll.c | 169 +++++++++++++++++++++++++--------------- 2 files changed, 114 insertions(+), 66 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 2524267210d3..a765ea898549 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -21,15 +21,20 @@ struct netpoll { __be32 local_ip, remote_ip; u16 local_port, remote_port; u8 remote_mac[ETH_ALEN]; + + struct list_head rx; /* rx_np list element */ }; struct netpoll_info { atomic_t refcnt; + int rx_flags; spinlock_t rx_lock; - struct netpoll *rx_np; /* netpoll that registered an rx_hook */ + struct list_head rx_np; /* netpolls that registered an rx_hook */ + struct sk_buff_head arp_tx; /* list of arp requests to reply to */ struct sk_buff_head txq; + struct delayed_work tx_work; }; @@ -51,7 +56,7 @@ static inline int netpoll_rx(struct sk_buff *skb) unsigned long flags; int ret = 0; - if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) + if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags)) return 0; spin_lock_irqsave(&npinfo->rx_lock, flags); @@ -67,7 +72,7 @@ static inline int netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = skb->dev->npinfo; - return npinfo && (npinfo->rx_np || npinfo->rx_flags); + return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags); } static inline int netpoll_receive_skb(struct sk_buff *skb) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0b4d0d35ef40..7aa697253765 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb) __be32 sip, tip; unsigned char *sha; struct sk_buff *send_skb; - struct netpoll *np = NULL; + struct netpoll *np, *tmp; + unsigned long flags; + int hits = 0; + + if (list_empty(&npinfo->rx_np)) + return; + + /* Before checking the packet, we do some early + inspection whether this is interesting at all */ + spin_lock_irqsave(&npinfo->rx_lock, flags); + list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { + if (np->dev == skb->dev) + hits++; + } + spin_unlock_irqrestore(&npinfo->rx_lock, flags); - if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) - np = npinfo->rx_np; - if (!np) + /* No netpoll struct is using this dev */ + if (!hits) return; /* No arp on this interface */ @@ -437,77 +450,91 @@ static void arp_reply(struct sk_buff *skb) arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); arp_ptr += 4; - /* if we actually cared about dst hw addr, it would get copied here */ + /* If we actually cared about dst hw addr, + it would get copied here */ arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ - if (tip != np->local_ip || - ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) + if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; size = arp_hdr_len(skb->dev); - send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), - LL_RESERVED_SPACE(np->dev)); - if (!send_skb) - return; - - skb_reset_network_header(send_skb); - arp = (struct arphdr *) skb_put(send_skb, size); - send_skb->dev = skb->dev; - send_skb->protocol = htons(ETH_P_ARP); + spin_lock_irqsave(&npinfo->rx_lock, flags); + list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { + if (tip != np->local_ip) + continue; - /* Fill the device header for the ARP frame */ - if (dev_hard_header(send_skb, skb->dev, ptype, - sha, np->dev->dev_addr, - send_skb->len) < 0) { - kfree_skb(send_skb); - return; - } + send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), + LL_RESERVED_SPACE(np->dev)); + if (!send_skb) + continue; - /* - * Fill out the arp protocol part. - * - * we only support ethernet device type, - * which (according to RFC 1390) should always equal 1 (Ethernet). - */ + skb_reset_network_header(send_skb); + arp = (struct arphdr *) skb_put(send_skb, size); + send_skb->dev = skb->dev; + send_skb->protocol = htons(ETH_P_ARP); - arp->ar_hrd = htons(np->dev->type); - arp->ar_pro = htons(ETH_P_IP); - arp->ar_hln = np->dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(type); + /* Fill the device header for the ARP frame */ + if (dev_hard_header(send_skb, skb->dev, ptype, + sha, np->dev->dev_addr, + send_skb->len) < 0) { + kfree_skb(send_skb); + continue; + } - arp_ptr=(unsigned char *)(arp + 1); - memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); - arp_ptr += np->dev->addr_len; - memcpy(arp_ptr, &tip, 4); - arp_ptr += 4; - memcpy(arp_ptr, sha, np->dev->addr_len); - arp_ptr += np->dev->addr_len; - memcpy(arp_ptr, &sip, 4); + /* + * Fill out the arp protocol part. + * + * we only support ethernet device type, + * which (according to RFC 1390) should + * always equal 1 (Ethernet). + */ - netpoll_send_skb(np, send_skb); + arp->ar_hrd = htons(np->dev->type); + arp->ar_pro = htons(ETH_P_IP); + arp->ar_hln = np->dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr = (unsigned char *)(arp + 1); + memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &tip, 4); + arp_ptr += 4; + memcpy(arp_ptr, sha, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &sip, 4); + + netpoll_send_skb(np, send_skb); + + /* If there are several rx_hooks for the same address, + we're fine by sending a single reply */ + break; + } + spin_unlock_irqrestore(&npinfo->rx_lock, flags); } int __netpoll_rx(struct sk_buff *skb) { int proto, len, ulen; + int hits = 0; struct iphdr *iph; struct udphdr *uh; - struct netpoll_info *npi = skb->dev->npinfo; - struct netpoll *np = npi->rx_np; + struct netpoll_info *npinfo = skb->dev->npinfo; + struct netpoll *np, *tmp; - if (!np) + if (list_empty(&npinfo->rx_np)) goto out; + if (skb->dev->type != ARPHRD_ETHER) goto out; /* check if netpoll clients need ARP */ if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) { - skb_queue_tail(&npi->arp_tx, skb); + skb_queue_tail(&npinfo->arp_tx, skb); return 1; } @@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb) goto out; if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) goto out; - if (np->local_ip && np->local_ip != iph->daddr) - goto out; - if (np->remote_ip && np->remote_ip != iph->saddr) - goto out; - if (np->local_port && np->local_port != ntohs(uh->dest)) - goto out; - np->rx_hook(np, ntohs(uh->source), - (char *)(uh+1), - ulen - sizeof(struct udphdr)); + list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { + if (np->local_ip && np->local_ip != iph->daddr) + continue; + if (np->remote_ip && np->remote_ip != iph->saddr) + continue; + if (np->local_port && np->local_port != ntohs(uh->dest)) + continue; + + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), + ulen - sizeof(struct udphdr)); + hits++; + } + + if (!hits) + goto out; kfree_skb(skb); return 1; @@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np) struct net_device *ndev = NULL; struct in_device *in_dev; struct netpoll_info *npinfo; + struct netpoll *npe, *tmp; unsigned long flags; int err; @@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np) } npinfo->rx_flags = 0; - npinfo->rx_np = NULL; + INIT_LIST_HEAD(&npinfo->rx_np); spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); @@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np) if (np->rx_hook) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_flags |= NETPOLL_RX_ENABLED; - npinfo->rx_np = np; + list_add_tail(&np->rx, &npinfo->rx_np); spin_unlock_irqrestore(&npinfo->rx_lock, flags); } @@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np) return 0; release: - if (!ndev->npinfo) + if (!ndev->npinfo) { + spin_lock_irqsave(&npinfo->rx_lock, flags); + list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { + npe->dev = NULL; + } + spin_unlock_irqrestore(&npinfo->rx_lock, flags); + kfree(npinfo); - np->dev = NULL; + } + dev_put(ndev); return err; } @@ -823,10 +865,11 @@ void netpoll_cleanup(struct netpoll *np) if (np->dev) { npinfo = np->dev->npinfo; if (npinfo) { - if (npinfo->rx_np == np) { + if (!list_empty(&npinfo->rx_np)) { spin_lock_irqsave(&npinfo->rx_lock, flags); - npinfo->rx_np = NULL; - npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; + list_del(&np->rx); + if (list_empty(&npinfo->rx_np)) + npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; spin_unlock_irqrestore(&npinfo->rx_lock, flags); } -- GitLab From 5d0b7235d83eefdafda300656e97d368afcafc9a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Jan 2010 17:57:35 -0800 Subject: [PATCH 0681/3892] x86: clean up rwsem type system The fast version of the rwsems (the code that uses xadd) has traditionally only worked on x86-32, and as a result it mixes different kinds of types wildly - they just all happen to be 32-bit. We have "long", we have "__s32", and we have "int". To make it work on x86-64, the types suddenly matter a lot more. It can be either a 32-bit or 64-bit signed type, and both work (with the caveat that a 32-bit counter will only have 15 bits of effective write counters, so it's limited to 32767 users). But whatever type you choose, it needs to be used consistently. This makes a new 'rwsem_counter_t', that is a 32-bit signed type. For a 64-bit type, you'd need to also update the BIAS values. Signed-off-by: Linus Torvalds LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/rwsem.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 413620024768..5f9af3081d66 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -55,6 +55,9 @@ extern asmregparm struct rw_semaphore * /* * the semaphore definition + * + * The bias values and the counter type needs to be extended to 64 bits + * if we want to have more than 32767 potential readers/writers */ #define RWSEM_UNLOCKED_VALUE 0x00000000 @@ -64,8 +67,10 @@ extern asmregparm struct rw_semaphore * #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) +typedef signed int rwsem_count_t; + struct rw_semaphore { - signed long count; + rwsem_count_t count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -121,7 +126,7 @@ static inline void __down_read(struct rw_semaphore *sem) */ static inline int __down_read_trylock(struct rw_semaphore *sem) { - __s32 result, tmp; + rwsem_count_t result, tmp; asm volatile("# beginning __down_read_trylock\n\t" " mov %0,%1\n\t" "1:\n\t" @@ -143,7 +148,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - int tmp; + rwsem_count_t tmp; tmp = RWSEM_ACTIVE_WRITE_BIAS; asm volatile("# beginning down_write\n\t" @@ -170,9 +175,9 @@ static inline void __down_write(struct rw_semaphore *sem) */ static inline int __down_write_trylock(struct rw_semaphore *sem) { - signed long ret = cmpxchg(&sem->count, - RWSEM_UNLOCKED_VALUE, - RWSEM_ACTIVE_WRITE_BIAS); + rwsem_count_t ret = cmpxchg(&sem->count, + RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); if (ret == RWSEM_UNLOCKED_VALUE) return 1; return 0; @@ -183,7 +188,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) */ static inline void __up_read(struct rw_semaphore *sem) { - __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; + rwsem_count_t tmp = -RWSEM_ACTIVE_READ_BIAS; asm volatile("# beginning __up_read\n\t" LOCK_PREFIX " xadd %1,(%2)\n\t" /* subtracts 1, returns the old value */ @@ -201,7 +206,7 @@ static inline void __up_read(struct rw_semaphore *sem) */ static inline void __up_write(struct rw_semaphore *sem) { - unsigned long tmp; + rwsem_count_t tmp; asm volatile("# beginning __up_write\n\t" LOCK_PREFIX " xadd %1,(%2)\n\t" /* tries to transition @@ -245,9 +250,9 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) /* * implement exchange and add functionality */ -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline rwsem_count_t rwsem_atomic_update(int delta, struct rw_semaphore *sem) { - int tmp = delta; + rwsem_count_t tmp = delta; asm volatile(LOCK_PREFIX "xadd %0,%1" : "+r" (tmp), "+m" (sem->count) -- GitLab From bafaecd11df15ad5b1e598adc7736afcd38ee13d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Jan 2010 18:16:42 -0800 Subject: [PATCH 0682/3892] x86-64: support native xadd rwsem implementation This one is much faster than the spinlock based fallback rwsem code, with certain artifical benchmarks having shown 300%+ improvement on threaded page faults etc. Again, note the 32767-thread limit here. So this really does need that whole "make rwsem_count_t be 64-bit and fix the BIAS values to match" extension on top of it, but that is conceptually a totally independent issue. NOT TESTED! The original patch that this all was based on were tested by KAMEZAWA Hiroyuki, but maybe I screwed up something when I created the cleaned-up series, so caveat emptor.. Also note that it _may_ be a good idea to mark some more registers clobbered on x86-64 in the inline asms instead of saving/restoring them. They are inline functions, but they are only used in places where there are not a lot of live registers _anyway_, so doing for example the clobbers of %r8-%r11 in the asm wouldn't make the fast-path code any worse, and would make the slow-path code smaller. (Not that the slow-path really matters to that degree. Saving a few unnecessary registers is the _least_ of our problems when we hit the slow path. The instruction/cycle counting really only matters in the fast path). Signed-off-by: Linus Torvalds LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/x86/Kconfig.cpu | 2 +- arch/x86/lib/Makefile | 1 + arch/x86/lib/rwsem_64.S | 81 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/rwsem_64.S diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 08e442bc3ab9..9d38a13b4ceb 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -319,7 +319,7 @@ config X86_L1_CACHE_SHIFT config X86_XADD def_bool y - depends on X86_32 && !M386 + depends on X86_64 || !M386 config X86_PPRO_FENCE bool "PentiumPro memory ordering errata workaround" diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index cffd754f3039..c80245131fdc 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -39,4 +39,5 @@ else lib-y += thunk_64.o clear_page_64.o copy_page_64.o lib-y += memmove_64.o memset_64.o lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o + lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem_64.o endif diff --git a/arch/x86/lib/rwsem_64.S b/arch/x86/lib/rwsem_64.S new file mode 100644 index 000000000000..15acecf0d7aa --- /dev/null +++ b/arch/x86/lib/rwsem_64.S @@ -0,0 +1,81 @@ +/* + * x86-64 rwsem wrappers + * + * This interfaces the inline asm code to the slow-path + * C routines. We need to save the call-clobbered regs + * that the asm does not mark as clobbered, and move the + * argument from %rax to %rdi. + * + * NOTE! We don't need to save %rax, because the functions + * will always return the semaphore pointer in %rax (which + * is also the input argument to these helpers) + * + * The following can clobber %rdx because the asm clobbers it: + * call_rwsem_down_write_failed + * call_rwsem_wake + * but %rdi, %rsi, %rcx, %r8-r11 always need saving. + */ + +#include +#include +#include +#include +#include + +#define save_common_regs \ + pushq %rdi; \ + pushq %rsi; \ + pushq %rcx; \ + pushq %r8; \ + pushq %r9; \ + pushq %r10; \ + pushq %r11 + +#define restore_common_regs \ + popq %r11; \ + popq %r10; \ + popq %r9; \ + popq %r8; \ + popq %rcx; \ + popq %rsi; \ + popq %rdi + +/* Fix up special calling conventions */ +ENTRY(call_rwsem_down_read_failed) + save_common_regs + pushq %rdx + movq %rax,%rdi + call rwsem_down_read_failed + popq %rdx + restore_common_regs + ret + ENDPROC(call_rwsem_down_read_failed) + +ENTRY(call_rwsem_down_write_failed) + save_common_regs + movq %rax,%rdi + call rwsem_down_write_failed + restore_common_regs + ret + ENDPROC(call_rwsem_down_write_failed) + +ENTRY(call_rwsem_wake) + decw %dx /* do nothing if still outstanding active readers */ + jnz 1f + save_common_regs + movq %rax,%rdi + call rwsem_wake + restore_common_regs +1: ret + ENDPROC(call_rwsem_wake) + +/* Fix up special calling conventions */ +ENTRY(call_rwsem_downgrade_wake) + save_common_regs + pushq %rdx + movq %rax,%rdi + call rwsem_downgrade_wake + popq %rdx + restore_common_regs + ret + ENDPROC(call_rwsem_downgrade_wake) -- GitLab From d1458279bf9c575a52fd22818ca19c463f380aba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2010 09:16:52 +0100 Subject: [PATCH 0683/3892] ALSA: Add snd_pci_quirk_lookup_id() Added a new function to look up a quirk entry with the given PCI SSID instead of a pci device pointer. This can be used when the searched ID is overridden for debugging or such a purpose. Signed-off-by: Takashi Iwai --- include/sound/core.h | 3 +++ sound/core/misc.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index a61499c22b0b..89e0ac17f44a 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -458,5 +458,8 @@ struct snd_pci_quirk { const struct snd_pci_quirk * snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); +const struct snd_pci_quirk * +snd_pci_quirk_lookup_id(u16 vendor, u16 device, + const struct snd_pci_quirk *list); #endif /* __SOUND_CORE_H */ diff --git a/sound/core/misc.c b/sound/core/misc.c index 23a032c6d487..3da4f92427d8 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -101,8 +101,9 @@ EXPORT_SYMBOL_GPL(__snd_printk); #ifdef CONFIG_PCI #include /** - * snd_pci_quirk_lookup - look up a PCI SSID quirk list - * @pci: pci_dev handle + * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list + * @vendor: PCI SSV id + * @device: PCI SSD id * @list: quirk list, terminated by a null entry * * Look through the given quirk list and finds a matching entry @@ -112,18 +113,39 @@ EXPORT_SYMBOL_GPL(__snd_printk); * Returns the matched entry pointer, or NULL if nothing matched. */ const struct snd_pci_quirk * -snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +snd_pci_quirk_lookup_id(u16 vendor, u16 device, + const struct snd_pci_quirk *list) { const struct snd_pci_quirk *q; for (q = list; q->subvendor; q++) { - if (q->subvendor != pci->subsystem_vendor) + if (q->subvendor != vendor) continue; if (!q->subdevice || - (pci->subsystem_device & q->subdevice_mask) == q->subdevice) + (device & q->subdevice_mask) == q->subdevice) return q; } return NULL; } +EXPORT_SYMBOL(snd_pci_quirk_lookup_id); + +/** + * snd_pci_quirk_lookup - look up a PCI SSID quirk list + * @pci: pci_dev handle + * @list: quirk list, terminated by a null entry + * + * Look through the given quirk list and finds a matching entry + * with the same PCI SSID. When subdevice is 0, all subdevice + * values may match. + * + * Returns the matched entry pointer, or NULL if nothing matched. + */ +const struct snd_pci_quirk * +snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +{ + return snd_pci_quirk_lookup_id(pci->subsystem_vendor, + pci->subsystem_device, + list); +} EXPORT_SYMBOL(snd_pci_quirk_lookup); #endif -- GitLab From 408bffd01cfcda2907b07fb86b3666e3db86fd82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2010 09:19:46 +0100 Subject: [PATCH 0684/3892] ALSA: ctxfi - Add subsystem option Added a new option "subsystem" to override the PCI SSID for identifying the card type. Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 3 +++ sound/pci/ctxfi/ctatc.c | 23 ++++++++++++------- sound/pci/ctxfi/ctatc.h | 2 +- sound/pci/ctxfi/xfi.c | 5 +++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index c540637eb16a..c83fd7b64201 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -482,6 +482,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. reference_rate - reference sample rate, 44100 or 48000 (default) multiple - multiple to ref. sample rate, 1 or 2 (default) + subsystem - override the PCI SSID for probing; the value + consists of SSVID << 16 | SSDID. The default is + zero, which means no override. This module supports multiple cards. diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index cb65bd0dd35b..903594e6ed79 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1225,10 +1225,11 @@ static int atc_dev_free(struct snd_device *dev) return ct_atc_destroy(atc); } -static int __devinit atc_identify_card(struct ct_atc *atc) +static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) { const struct snd_pci_quirk *p; const struct snd_pci_quirk *list; + u16 vendor_id, device_id; switch (atc->chip_type) { case ATC20K1: @@ -1242,13 +1243,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc) default: return -ENOENT; } - p = snd_pci_quirk_lookup(atc->pci, list); + if (ssid) { + vendor_id = ssid >> 16; + device_id = ssid & 0xffff; + } else { + vendor_id = atc->pci->subsystem_vendor; + device_id = atc->pci->subsystem_device; + } + p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { printk(KERN_ERR "ctxfi: " "Device %04x:%04x is black-listed\n", - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); + vendor_id, device_id); return -ENOENT; } atc->model = p->value; @@ -1261,8 +1268,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc) atc->model_name = ct_subsys_name[atc->model]; snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", atc->chip_name, atc->model_name, - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); + vendor_id, device_id); return 0; } @@ -1636,7 +1642,8 @@ static struct ct_atc atc_preset __devinitdata = { int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, unsigned int rsr, unsigned int msr, - int chip_type, struct ct_atc **ratc) + int chip_type, unsigned int ssid, + struct ct_atc **ratc) { struct ct_atc *atc; static struct snd_device_ops ops = { @@ -1662,7 +1669,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, mutex_init(&atc->atc_mutex); /* Find card model */ - err = atc_identify_card(atc); + err = atc_identify_card(atc, ssid); if (err < 0) { printk(KERN_ERR "ctatc: Card not recognised\n"); goto error1; diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 9fd8a5708943..7167c0185d52 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -148,7 +148,7 @@ struct ct_atc { int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, unsigned int rsr, unsigned int msr, int chip_type, - struct ct_atc **ratc); + unsigned int subsysid, struct ct_atc **ratc); int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); #endif /* CTATC_H */ diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 76541748e7bc..ed44ed788b60 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static unsigned int subsystem[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); @@ -39,6 +40,8 @@ module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); +module_param_array(subsystem, int, NULL, 0444); +MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); static struct pci_device_id ct_pci_dev_ids[] = { /* only X-Fi is supported, so... */ @@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, - pci_id->driver_data, &atc); + pci_id->driver_data, subsystem[dev], &atc); if (err < 0) goto error; -- GitLab From 738ada47cf60830d37bb70ffb0b0281d19fc4c7f Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 12 Jan 2010 17:07:18 +0100 Subject: [PATCH 0685/3892] ASoC: TWL4030: Fix typo in comment in header file Signed-off-by: Thomas Weber Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index dd6396ec9c79..f206d242ca31 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -25,7 +25,7 @@ /* Register descriptions are here */ #include -/* Sgadow register used by the audio driver */ +/* Shadow register used by the audio driver */ #define TWL4030_REG_SW_SHADOW 0x4A #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) -- GitLab From 9a58a80a701bdb2d220cdab4914218df5b48d781 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 14 Jan 2010 03:10:54 -0800 Subject: [PATCH 0686/3892] proc_fops: convert drivers/isdn/ to seq_file Convert code away from ->read_proc/->write_proc interfaces. Switch to proc_create()/proc_create_data() which make addition of proc entries reliable wrt NULL ->proc_fops, NULL ->data and so on. Problem with ->read_proc et al is described here commit 786d7e1612f0b0adb6046f19b906609e4fe8b1ba "Fix rmmod/read/write races in /proc entries" [akpm@linux-foundation.org: CONFIG_PROC_FS=n build fix] Signed-off-by: Alexey Dobriyan Signed-off-by: Tilman Schmidt Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- Documentation/isdn/INTERFACE.CAPI | 9 +- drivers/isdn/capi/capi.c | 99 +++++------- drivers/isdn/capi/capidrv.c | 55 ++----- drivers/isdn/capi/kcapi.c | 8 +- drivers/isdn/gigaset/capi.c | 75 +++++---- drivers/isdn/hardware/avm/avmcard.h | 6 +- drivers/isdn/hardware/avm/b1.c | 54 ++++--- drivers/isdn/hardware/avm/b1dma.c | 71 +++++---- drivers/isdn/hardware/avm/b1isa.c | 2 +- drivers/isdn/hardware/avm/b1pci.c | 4 +- drivers/isdn/hardware/avm/b1pcmcia.c | 2 +- drivers/isdn/hardware/avm/c4.c | 53 ++++--- drivers/isdn/hardware/avm/t1isa.c | 2 +- drivers/isdn/hardware/avm/t1pci.c | 2 +- drivers/isdn/hardware/eicon/capimain.c | 40 +++-- drivers/isdn/hardware/eicon/diva_didd.c | 45 +++--- drivers/isdn/hardware/eicon/divasi.c | 48 +++--- drivers/isdn/hardware/eicon/divasproc.c | 198 +++++++++++------------- drivers/isdn/hysdn/hycapi.c | 56 +++---- include/linux/isdn/capilli.h | 3 +- net/bluetooth/cmtp/capi.c | 37 +++-- 21 files changed, 411 insertions(+), 458 deletions(-) diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI index 5fe8de5cc727..f172091fb7cd 100644 --- a/Documentation/isdn/INTERFACE.CAPI +++ b/Documentation/isdn/INTERFACE.CAPI @@ -149,10 +149,11 @@ char *(*procinfo)(struct capi_ctr *ctrlr) pointer to a callback function returning the entry for the device in the CAPI controller info table, /proc/capi/controller -read_proc_t *ctr_read_proc - pointer to the read_proc callback function for the device's proc file - system entry, /proc/capi/controllers/; will be called with a - pointer to the device's capi_ctr structure as the last (data) argument +const struct file_operations *proc_fops + pointers to callback functions for the device's proc file + system entry, /proc/capi/controllers/; pointer to the device's + capi_ctr structure is available from struct proc_dir_entry::data + which is available from struct inode. Note: Callback functions except send_message() are never called in interrupt context. diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 65bf91e16a42..79f9364aded6 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -33,6 +33,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include #include +#include #include #include #include @@ -1407,114 +1408,84 @@ static void capinc_tty_exit(void) * /proc/capi/capi20: * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */ -static int proc_capidev_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capi20_proc_show(struct seq_file *m, void *v) { struct capidev *cdev; struct list_head *l; - int len = 0; read_lock(&capidev_list_lock); list_for_each(l, &capidev_list) { cdev = list_entry(l, struct capidev, list); - len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n", + seq_printf(m, "0 %d %lu %lu %lu %lu\n", cdev->ap.applid, cdev->ap.nrecvctlpkt, cdev->ap.nrecvdatapkt, cdev->ap.nsentctlpkt, cdev->ap.nsentdatapkt); - if (len <= off) { - off -= len; - len = 0; - } else { - if (len-off > count) - goto endloop; - } } - -endloop: read_unlock(&capidev_list_lock); - if (len < count) - *eof = 1; - if (len > count) len = count; - if (len < 0) len = 0; - return len; + return 0; } +static int capi20_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, capi20_proc_show, NULL); +} + +static const struct file_operations capi20_proc_fops = { + .owner = THIS_MODULE, + .open = capi20_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * /proc/capi/capi20ncci: * applid ncci */ -static int proc_capincci_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capi20ncci_proc_show(struct seq_file *m, void *v) { struct capidev *cdev; struct capincci *np; struct list_head *l; - int len = 0; read_lock(&capidev_list_lock); list_for_each(l, &capidev_list) { cdev = list_entry(l, struct capidev, list); for (np=cdev->nccis; np; np = np->next) { - len += sprintf(page+len, "%d 0x%x\n", + seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci); - if (len <= off) { - off -= len; - len = 0; - } else { - if (len-off > count) - goto endloop; - } } } -endloop: read_unlock(&capidev_list_lock); - *start = page+off; - if (len < count) - *eof = 1; - if (len>count) len = count; - if (len<0) len = 0; - return len; + return 0; } -static struct procfsentries { - char *name; - mode_t mode; - int (*read_proc)(char *page, char **start, off_t off, - int count, int *eof, void *data); - struct proc_dir_entry *procent; -} procfsentries[] = { - /* { "capi", S_IFDIR, 0 }, */ - { "capi/capi20", 0 , proc_capidev_read_proc }, - { "capi/capi20ncci", 0 , proc_capincci_read_proc }, +static int capi20ncci_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, capi20ncci_proc_show, NULL); +} + +static const struct file_operations capi20ncci_proc_fops = { + .owner = THIS_MODULE, + .open = capi20ncci_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static void __init proc_init(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=0; i < nelem; i++) { - struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, NULL); - if (p->procent) p->procent->read_proc = p->read_proc; - } + proc_create("capi/capi20", 0, NULL, &capi20_proc_fops); + proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops); } static void __exit proc_exit(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=nelem-1; i >= 0; i--) { - struct procfsentries *p = procfsentries + i; - if (p->procent) { - remove_proc_entry(p->name, NULL); - p->procent = NULL; - } - } + remove_proc_entry("capi/capi20", NULL); + remove_proc_entry("capi/capi20ncci", NULL); } /* -------- init function and module interface ---------------------- */ diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 66b7d7a86474..bb450152fb74 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2229,59 +2230,37 @@ static void lower_callback(unsigned int cmd, u32 contr, void *data) * /proc/capi/capidrv: * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */ -static int proc_capidrv_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int capidrv_proc_show(struct seq_file *m, void *v) { - int len = 0; - - len += sprintf(page+len, "%lu %lu %lu %lu\n", + seq_printf(m, "%lu %lu %lu %lu\n", global.ap.nrecvctlpkt, global.ap.nrecvdatapkt, global.ap.nsentctlpkt, global.ap.nsentdatapkt); - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + return 0; +} + +static int capidrv_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, capidrv_proc_show, NULL); } -static struct procfsentries { - char *name; - mode_t mode; - int (*read_proc)(char *page, char **start, off_t off, - int count, int *eof, void *data); - struct proc_dir_entry *procent; -} procfsentries[] = { - /* { "capi", S_IFDIR, 0 }, */ - { "capi/capidrv", 0 , proc_capidrv_read_proc }, +static const struct file_operations capidrv_proc_fops = { + .owner = THIS_MODULE, + .open = capidrv_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static void __init proc_init(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=0; i < nelem; i++) { - struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, NULL); - if (p->procent) p->procent->read_proc = p->read_proc; - } + proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops); } static void __exit proc_exit(void) { - int nelem = ARRAY_SIZE(procfsentries); - int i; - - for (i=nelem-1; i >= 0; i--) { - struct procfsentries *p = procfsentries + i; - if (p->procent) { - remove_proc_entry(p->name, NULL); - p->procent = NULL; - } - } + remove_proc_entry("capi/capidrv", NULL); } static int __init capidrv_init(void) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index dc506ab99cac..b0bacf377c18 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -490,13 +490,7 @@ attach_capi_ctr(struct capi_ctr *card) card->traceflag = showcapimsgs; sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_entry(card->procfn, 0, NULL); - if (card->procent) { - card->procent->read_proc = - (int (*)(char *,char **,off_t,int,int *,void *)) - card->ctr_read_proc; - card->procent->data = card; - } + card->procent = proc_create_data(card->procfn, 0, NULL, card->proc_fops, card); ncards++; printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n", diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 3f5cd06af104..6f0ae32906bf 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -13,6 +13,8 @@ #include "gigaset.h" #include +#include +#include #include #include #include @@ -2106,35 +2108,22 @@ static char *gigaset_procinfo(struct capi_ctr *ctr) return ctr->name; /* ToDo: more? */ } -/** - * gigaset_ctr_read_proc() - build controller proc file entry - * @page: buffer of PAGE_SIZE bytes for receiving the entry. - * @start: unused. - * @off: unused. - * @count: unused. - * @eof: unused. - * @ctr: controller descriptor structure. - * - * Return value: length of generated entry - */ -static int gigaset_ctr_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctr) +static int gigaset_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctr = m->private; struct cardstate *cs = ctr->driverdata; char *s; int i; - int len = 0; - len += sprintf(page+len, "%-16s %s\n", "name", ctr->name); - len += sprintf(page+len, "%-16s %s %s\n", "dev", + + seq_printf(m, "%-16s %s\n", "name", ctr->name); + seq_printf(m, "%-16s %s %s\n", "dev", dev_driver_string(cs->dev), dev_name(cs->dev)); - len += sprintf(page+len, "%-16s %d\n", "id", cs->myid); + seq_printf(m, "%-16s %d\n", "id", cs->myid); if (cs->gotfwver) - len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware", + seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware", cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]); - len += sprintf(page+len, "%-16s %d\n", "channels", - cs->channels); - len += sprintf(page+len, "%-16s %s\n", "onechannel", - cs->onechannel ? "yes" : "no"); + seq_printf(m, "%-16s %d\n", "channels", cs->channels); + seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no"); switch (cs->mode) { case M_UNKNOWN: @@ -2152,7 +2141,7 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off, default: s = "??"; } - len += sprintf(page+len, "%-16s %s\n", "mode", s); + seq_printf(m, "%-16s %s\n", "mode", s); switch (cs->mstate) { case MS_UNINITIALIZED: @@ -2176,25 +2165,21 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off, default: s = "??"; } - len += sprintf(page+len, "%-16s %s\n", "mstate", s); + seq_printf(m, "%-16s %s\n", "mstate", s); - len += sprintf(page+len, "%-16s %s\n", "running", - cs->running ? "yes" : "no"); - len += sprintf(page+len, "%-16s %s\n", "connected", - cs->connected ? "yes" : "no"); - len += sprintf(page+len, "%-16s %s\n", "isdn_up", - cs->isdn_up ? "yes" : "no"); - len += sprintf(page+len, "%-16s %s\n", "cidmode", - cs->cidmode ? "yes" : "no"); + seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no"); + seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no"); + seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no"); + seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no"); for (i = 0; i < cs->channels; i++) { - len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted", + seq_printf(m, "[%d]%-13s %d\n", i, "corrupted", cs->bcs[i].corrupted); - len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down", + seq_printf(m, "[%d]%-13s %d\n", i, "trans_down", cs->bcs[i].trans_down); - len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up", + seq_printf(m, "[%d]%-13s %d\n", i, "trans_up", cs->bcs[i].trans_up); - len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate", + seq_printf(m, "[%d]%-13s %d\n", i, "chstate", cs->bcs[i].chstate); switch (cs->bcs[i].proto2) { case L2_BITSYNC: @@ -2209,11 +2194,23 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off, default: s = "??"; } - len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s); + seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s); } - return len; + return 0; } +static int gigaset_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, gigaset_proc_show, PDE(inode)->data); +} + +static const struct file_operations gigaset_proc_fops = { + .owner = THIS_MODULE, + .open = gigaset_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; static struct capi_driver capi_driver_gigaset = { .name = "gigaset", @@ -2256,7 +2253,7 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid) iif->ctr.release_appl = gigaset_release_appl; iif->ctr.send_message = gigaset_send_message; iif->ctr.procinfo = gigaset_procinfo; - iif->ctr.ctr_read_proc = gigaset_ctr_read_proc; + iif->ctr.proc_fops = &gigaset_proc_fops; INIT_LIST_HEAD(&iif->appls); skb_queue_head_init(&iif->sendqueue); atomic_set(&iif->sendqlen, 0); diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h index d964f07e4a56..a70e8854461d 100644 --- a/drivers/isdn/hardware/avm/avmcard.h +++ b/drivers/isdn/hardware/avm/avmcard.h @@ -556,8 +556,7 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); void b1_parse_version(avmctrl_info *card); irqreturn_t b1_interrupt(int interrupt, void *devptr); -int b1ctl_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl); +extern const struct file_operations b1ctl_proc_fops; avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *, long rsize, long ssize); @@ -577,7 +576,6 @@ void b1dma_register_appl(struct capi_ctr *ctrl, capi_register_params *rp); void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl); u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); -int b1dmactl_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl); +extern const struct file_operations b1dmactl_proc_fops; #endif /* _AVMCARD_H_ */ diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index a7c0083e78a7..c38fa0f4c729 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -634,18 +636,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) } /* ------------------------------------------------------------- */ -int b1ctl_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int b1ctl_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; u8 flag; - int len = 0; char *s; - len += sprintf(page+len, "%-16s %s\n", "name", card->name); - len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); - len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + seq_printf(m, "%-16s %s\n", "name", card->name); + seq_printf(m, "%-16s 0x%x\n", "io", card->port); + seq_printf(m, "%-16s %d\n", "irq", card->irq); switch (card->cardtype) { case avm_b1isa: s = "B1 ISA"; break; case avm_b1pci: s = "B1 PCI"; break; @@ -658,20 +659,20 @@ int b1ctl_read_proc(char *page, char **start, off_t off, case avm_c2: s = "C2"; break; default: s = "???"; break; } - len += sprintf(page+len, "%-16s %s\n", "type", s); + seq_printf(m, "%-16s %s\n", "type", s); if (card->cardtype == avm_t1isa) - len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr); + seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr); if ((s = cinfo->version[VER_DRIVER]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + seq_printf(m, "%-16s %s\n", "ver_driver", s); if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + seq_printf(m, "%-16s %s\n", "ver_cardtype", s); if ((s = cinfo->version[VER_SERIAL]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + seq_printf(m, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[3]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", "protocol", (flag & 0x01) ? " DSS1" : "", (flag & 0x02) ? " CT1" : "", @@ -685,7 +686,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off, if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[5]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s\n", "linetype", (flag & 0x01) ? " point to point" : "", (flag & 0x02) ? " point to multipoint" : "", @@ -693,16 +694,25 @@ int b1ctl_read_proc(char *page, char **start, off_t off, (flag & 0x04) ? " leased line with D-channel" : "" ); } - len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); - - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); + + return 0; +} + +static int b1ctl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, b1ctl_proc_show, PDE(inode)->data); } +const struct file_operations b1ctl_proc_fops = { + .owner = THIS_MODULE, + .open = b1ctl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +EXPORT_SYMBOL(b1ctl_proc_fops); + /* ------------------------------------------------------------- */ #ifdef CONFIG_PCI @@ -781,8 +791,6 @@ EXPORT_SYMBOL(b1_send_message); EXPORT_SYMBOL(b1_parse_version); EXPORT_SYMBOL(b1_interrupt); -EXPORT_SYMBOL(b1ctl_read_proc); - static int __init b1_init(void) { char *p; diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 0e84aaae43fd..124550d0dbf3 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -855,21 +857,20 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) /* ------------------------------------------------------------- */ -int b1dmactl_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int b1dmactl_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; u8 flag; - int len = 0; char *s; u32 txoff, txlen, rxoff, rxlen, csr; unsigned long flags; - len += sprintf(page+len, "%-16s %s\n", "name", card->name); - len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); - len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); - len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); + seq_printf(m, "%-16s %s\n", "name", card->name); + seq_printf(m, "%-16s 0x%x\n", "io", card->port); + seq_printf(m, "%-16s %d\n", "irq", card->irq); + seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase); switch (card->cardtype) { case avm_b1isa: s = "B1 ISA"; break; case avm_b1pci: s = "B1 PCI"; break; @@ -882,18 +883,18 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, case avm_c2: s = "C2"; break; default: s = "???"; break; } - len += sprintf(page+len, "%-16s %s\n", "type", s); + seq_printf(m, "%-16s %s\n", "type", s); if ((s = cinfo->version[VER_DRIVER]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + seq_printf(m, "%-16s %s\n", "ver_driver", s); if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + seq_printf(m, "%-16s %s\n", "ver_cardtype", s); if ((s = cinfo->version[VER_SERIAL]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + seq_printf(m, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[3]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", "protocol", (flag & 0x01) ? " DSS1" : "", (flag & 0x02) ? " CT1" : "", @@ -907,7 +908,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[5]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s\n", "linetype", (flag & 0x01) ? " point to point" : "", (flag & 0x02) ? " point to multipoint" : "", @@ -915,7 +916,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, (flag & 0x04) ? " leased line with D-channel" : "" ); } - len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); spin_lock_irqsave(&card->lock, flags); @@ -930,27 +931,30 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, spin_unlock_irqrestore(&card->lock, flags); - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr (cached)", (unsigned long)card->csr); - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr", (unsigned long)csr); - len += sprintf(page+len, "%-16s %lu\n", - "txoff", (unsigned long)txoff); - len += sprintf(page+len, "%-16s %lu\n", - "txlen", (unsigned long)txlen); - len += sprintf(page+len, "%-16s %lu\n", - "rxoff", (unsigned long)rxoff); - len += sprintf(page+len, "%-16s %lu\n", - "rxlen", (unsigned long)rxlen); - - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr); + seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr); + seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff); + seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen); + seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff); + seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen); + + return 0; +} + +static int b1dmactl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, b1dmactl_proc_show, PDE(inode)->data); } +const struct file_operations b1dmactl_proc_fops = { + .owner = THIS_MODULE, + .open = b1dmactl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +EXPORT_SYMBOL(b1dmactl_proc_fops); + /* ------------------------------------------------------------- */ EXPORT_SYMBOL(b1dma_reset); @@ -963,7 +967,6 @@ EXPORT_SYMBOL(b1dma_reset_ctr); EXPORT_SYMBOL(b1dma_register_appl); EXPORT_SYMBOL(b1dma_release_appl); EXPORT_SYMBOL(b1dma_send_message); -EXPORT_SYMBOL(b1dmactl_read_proc); static int __init b1dma_init(void) { diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c index 6461a32bc838..ff5390546f92 100644 --- a/drivers/isdn/hardware/avm/b1isa.c +++ b/drivers/isdn/hardware/avm/b1isa.c @@ -121,7 +121,7 @@ static int b1isa_probe(struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1isa_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c index 5b314a2c4049..c97e4315079d 100644 --- a/drivers/isdn/hardware/avm/b1pci.c +++ b/drivers/isdn/hardware/avm/b1pci.c @@ -112,7 +112,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1pci_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); cinfo->capi_ctrl.owner = THIS_MODULE; @@ -251,7 +251,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c index 7740403b40e1..d6391e0afeea 100644 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ b/drivers/isdn/hardware/avm/b1pcmcia.c @@ -108,7 +108,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq, cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 6833301a45fc..de6e6b311819 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -1062,19 +1064,18 @@ static char *c4_procinfo(struct capi_ctr *ctrl) return cinfo->infobuf; } -static int c4_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int c4_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; u8 flag; - int len = 0; char *s; - len += sprintf(page+len, "%-16s %s\n", "name", card->name); - len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); - len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); - len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); + seq_printf(m, "%-16s %s\n", "name", card->name); + seq_printf(m, "%-16s 0x%x\n", "io", card->port); + seq_printf(m, "%-16s %d\n", "irq", card->irq); + seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase); switch (card->cardtype) { case avm_b1isa: s = "B1 ISA"; break; case avm_b1pci: s = "B1 PCI"; break; @@ -1087,18 +1088,18 @@ static int c4_read_proc(char *page, char **start, off_t off, case avm_c2: s = "C2"; break; default: s = "???"; break; } - len += sprintf(page+len, "%-16s %s\n", "type", s); + seq_printf(m, "%-16s %s\n", "type", s); if ((s = cinfo->version[VER_DRIVER]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + seq_printf(m, "%-16s %s\n", "ver_driver", s); if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + seq_printf(m, "%-16s %s\n", "ver_cardtype", s); if ((s = cinfo->version[VER_SERIAL]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + seq_printf(m, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[3]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", "protocol", (flag & 0x01) ? " DSS1" : "", (flag & 0x02) ? " CT1" : "", @@ -1112,7 +1113,7 @@ static int c4_read_proc(char *page, char **start, off_t off, if (card->cardtype != avm_m1) { flag = ((u8 *)(ctrl->profile.manu))[5]; if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s\n", + seq_printf(m, "%-16s%s%s%s%s\n", "linetype", (flag & 0x01) ? " point to point" : "", (flag & 0x02) ? " point to multipoint" : "", @@ -1120,16 +1121,24 @@ static int c4_read_proc(char *page, char **start, off_t off, (flag & 0x04) ? " leased line with D-channel" : "" ); } - len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); - - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); + + return 0; } +static int c4_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, c4_proc_show, PDE(inode)->data); +} + +static const struct file_operations c4_proc_fops = { + .owner = THIS_MODULE, + .open = c4_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* ------------------------------------------------------------- */ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, @@ -1201,7 +1210,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, cinfo->capi_ctrl.load_firmware = c4_load_firmware; cinfo->capi_ctrl.reset_ctr = c4_reset_ctr; cinfo->capi_ctrl.procinfo = c4_procinfo; - cinfo->capi_ctrl.ctr_read_proc = c4_read_proc; + cinfo->capi_ctrl.proc_fops = &c4_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 1c53fd49adb6..baeeb3c2a3ee 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -429,7 +429,7 @@ static int t1isa_probe(struct pci_dev *pdev, int cardnr) cinfo->capi_ctrl.load_firmware = t1isa_load_firmware; cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr; cinfo->capi_ctrl.procinfo = t1isa_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c index e6d298d75146..5a3f83098018 100644 --- a/drivers/isdn/hardware/avm/t1pci.c +++ b/drivers/isdn/hardware/avm/t1pci.c @@ -119,7 +119,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; cinfo->capi_ctrl.procinfo = t1pci_procinfo; - cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; + cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c index 98fcdfc7ca55..0f073cd73763 100644 --- a/drivers/isdn/hardware/eicon/capimain.c +++ b/drivers/isdn/hardware/eicon/capimain.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "os_capi.h" @@ -75,25 +76,32 @@ void diva_os_free_message_buffer(diva_os_message_buffer_s * dmb) /* * proc function for controller info */ -static int diva_ctl_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int diva_ctl_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; diva_card *card = (diva_card *) ctrl->driverdata; - int len = 0; - - len += sprintf(page + len, "%s\n", ctrl->name); - len += sprintf(page + len, "Serial No. : %s\n", ctrl->serial); - len += sprintf(page + len, "Id : %d\n", card->Id); - len += sprintf(page + len, "Channels : %d\n", card->d.channels); - - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); + + seq_printf(m, "%s\n", ctrl->name); + seq_printf(m, "Serial No. : %s\n", ctrl->serial); + seq_printf(m, "Id : %d\n", card->Id); + seq_printf(m, "Channels : %d\n", card->d.channels); + + return 0; +} + +static int diva_ctl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, diva_ctl_proc_show, NULL); } +static const struct file_operations diva_ctl_proc_fops = { + .owner = THIS_MODULE, + .open = diva_ctl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * set additional os settings in capi_ctr struct */ @@ -102,7 +110,7 @@ void diva_os_set_controller_struct(struct capi_ctr *ctrl) ctrl->driver_name = DRIVERLNAME; ctrl->load_firmware = NULL; ctrl->reset_ctr = NULL; - ctrl->ctr_read_proc = diva_ctl_read_proc; + ctrl->proc_fops = &diva_ctl_proc_fops; ctrl->owner = THIS_MODULE; } diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index 993b14cf1778..5d06a7437824 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "platform.h" @@ -62,39 +63,41 @@ static char *getrev(const char *revision) return rev; } -static int -proc_read(char *page, char **start, off_t off, int count, int *eof, - void *data) +static int divadidd_proc_show(struct seq_file *m, void *v) { - int len = 0; char tmprev[32]; strcpy(tmprev, main_revision); - len += sprintf(page + len, "%s\n", DRIVERNAME); - len += sprintf(page + len, "name : %s\n", DRIVERLNAME); - len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_DIDD); - len += sprintf(page + len, "build : %s(%s)\n", + seq_printf(m, "%s\n", DRIVERNAME); + seq_printf(m, "name : %s\n", DRIVERLNAME); + seq_printf(m, "release : %s\n", DRIVERRELEASE_DIDD); + seq_printf(m, "build : %s(%s)\n", diva_didd_common_code_build, DIVA_BUILD); - len += sprintf(page + len, "revision : %s\n", getrev(tmprev)); - - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); + seq_printf(m, "revision : %s\n", getrev(tmprev)); + + return 0; } +static int divadidd_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, divadidd_proc_show, NULL); +} + +static const struct file_operations divadidd_proc_fops = { + .owner = THIS_MODULE, + .open = divadidd_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int DIVA_INIT_FUNCTION create_proc(void) { proc_net_eicon = proc_mkdir("eicon", init_net.proc_net); if (proc_net_eicon) { - if ((proc_didd = - create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO, - proc_net_eicon))) { - proc_didd->read_proc = proc_read; - } + proc_didd = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon, + &divadidd_proc_fops); return (1); } return (0); diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index 69e71ebe7841..f577719ab3fa 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -86,39 +87,40 @@ static void diva_um_timer_function(unsigned long data); extern struct proc_dir_entry *proc_net_eicon; static struct proc_dir_entry *um_idi_proc_entry = NULL; -static int -um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof, - void *data) +static int um_idi_proc_show(struct seq_file *m, void *v) { - int len = 0; char tmprev[32]; - len += sprintf(page + len, "%s\n", DRIVERNAME); - len += sprintf(page + len, "name : %s\n", DRIVERLNAME); - len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_IDI); + seq_printf(m, "%s\n", DRIVERNAME); + seq_printf(m, "name : %s\n", DRIVERLNAME); + seq_printf(m, "release : %s\n", DRIVERRELEASE_IDI); strcpy(tmprev, main_revision); - len += sprintf(page + len, "revision : %s\n", getrev(tmprev)); - len += sprintf(page + len, "build : %s\n", DIVA_BUILD); - len += sprintf(page + len, "major : %d\n", major); - - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); + seq_printf(m, "revision : %s\n", getrev(tmprev)); + seq_printf(m, "build : %s\n", DIVA_BUILD); + seq_printf(m, "major : %d\n", major); + + return 0; +} + +static int um_idi_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, um_idi_proc_show, NULL); } +static const struct file_operations um_idi_proc_fops = { + .owner = THIS_MODULE, + .open = um_idi_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int DIVA_INIT_FUNCTION create_um_idi_proc(void) { - um_idi_proc_entry = create_proc_entry(DRIVERLNAME, - S_IFREG | S_IRUGO | S_IWUSR, - proc_net_eicon); + um_idi_proc_entry = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon, + &um_idi_proc_fops); if (!um_idi_proc_entry) return (0); - - um_idi_proc_entry->read_proc = um_idi_proc_read; - return (1); } diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 040827288ec9..46d44a942624 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -141,14 +142,10 @@ void remove_divas_proc(void) } } -/* -** write group_optimization -*/ -static int -write_grp_opt(struct file *file, const char __user *buffer, unsigned long count, - void *data) +static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { @@ -172,14 +169,10 @@ write_grp_opt(struct file *file, const char __user *buffer, unsigned long count, return (-EINVAL); } -/* -** write dynamic_l1_down -*/ -static int -write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count, - void *data) +static ssize_t d_l1_down_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { @@ -203,63 +196,62 @@ write_d_l1_down(struct file *file, const char __user *buffer, unsigned long coun return (-EINVAL); } - -/* -** read dynamic_l1_down -*/ -static int -read_d_l1_down(char *page, char **start, off_t off, int count, int *eof, - void *data) +static int d_l1_down_proc_show(struct seq_file *m, void *v) { - int len = 0; - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = m->private; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; - len += sprintf(page + len, "%s\n", + seq_printf(m, "%s\n", (IoAdapter->capi_cfg. cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" : "0"); + return 0; +} - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); +static int d_l1_down_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, d_l1_down_proc_show, PDE(inode)->data); } -/* -** read group_optimization -*/ -static int -read_grp_opt(char *page, char **start, off_t off, int count, int *eof, - void *data) +static const struct file_operations d_l1_down_proc_fops = { + .owner = THIS_MODULE, + .open = d_l1_down_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = d_l1_down_proc_write, +}; + +static int grp_opt_proc_show(struct seq_file *m, void *v) { - int len = 0; - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = m->private; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; - len += sprintf(page + len, "%s\n", + seq_printf(m, "%s\n", (IoAdapter->capi_cfg. cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? "1" : "0"); + return 0; +} - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); +static int grp_opt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, grp_opt_proc_show, PDE(inode)->data); } -/* -** info write -*/ -static int -info_write(struct file *file, const char __user *buffer, unsigned long count, - void *data) +static const struct file_operations grp_opt_proc_fops = { + .owner = THIS_MODULE, + .open = grp_opt_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = grp_opt_proc_write, +}; + +static ssize_t info_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; char c[4]; @@ -277,63 +269,46 @@ info_write(struct file *file, const char __user *buffer, unsigned long count, return (-EINVAL); } -/* -** info read -*/ -static int -info_read(char *page, char **start, off_t off, int count, int *eof, - void *data) +static int info_proc_show(struct seq_file *m, void *v) { int i = 0; - int len = 0; char *p; char tmpser[16]; - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; + diva_os_xdi_adapter_t *a = m->private; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; - len += - sprintf(page + len, "Name : %s\n", - IoAdapter->Properties.Name); - len += sprintf(page + len, "DSP state : %08x\n", a->dsp_mask); - len += sprintf(page + len, "Channels : %02d\n", - IoAdapter->Properties.Channels); - len += sprintf(page + len, "E. max/used : %03d/%03d\n", + seq_printf(m, "Name : %s\n", IoAdapter->Properties.Name); + seq_printf(m, "DSP state : %08x\n", a->dsp_mask); + seq_printf(m, "Channels : %02d\n", IoAdapter->Properties.Channels); + seq_printf(m, "E. max/used : %03d/%03d\n", IoAdapter->e_max, IoAdapter->e_count); diva_get_vserial_number(IoAdapter, tmpser); - len += sprintf(page + len, "Serial : %s\n", tmpser); - len += - sprintf(page + len, "IRQ : %d\n", - IoAdapter->irq_info.irq_nr); - len += sprintf(page + len, "CardIndex : %d\n", a->CardIndex); - len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal); - len += sprintf(page + len, "Controller : %d\n", a->controller); - len += sprintf(page + len, "Bus-Type : %s\n", + seq_printf(m, "Serial : %s\n", tmpser); + seq_printf(m, "IRQ : %d\n", IoAdapter->irq_info.irq_nr); + seq_printf(m, "CardIndex : %d\n", a->CardIndex); + seq_printf(m, "CardOrdinal : %d\n", a->CardOrdinal); + seq_printf(m, "Controller : %d\n", a->controller); + seq_printf(m, "Bus-Type : %s\n", (a->Bus == DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI"); - len += sprintf(page + len, "Port-Name : %s\n", a->port_name); + seq_printf(m, "Port-Name : %s\n", a->port_name); if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) { - len += - sprintf(page + len, "PCI-bus : %d\n", - a->resources.pci.bus); - len += - sprintf(page + len, "PCI-func : %d\n", - a->resources.pci.func); + seq_printf(m, "PCI-bus : %d\n", a->resources.pci.bus); + seq_printf(m, "PCI-func : %d\n", a->resources.pci.func); for (i = 0; i < 8; i++) { if (a->resources.pci.bar[i]) { - len += - sprintf(page + len, + seq_printf(m, "Mem / I/O %d : 0x%x / mapped : 0x%lx", i, a->resources.pci.bar[i], (unsigned long) a->resources. pci.addr[i]); if (a->resources.pci.length[i]) { - len += - sprintf(page + len, + seq_printf(m, " / length : %d", a->resources.pci. length[i]); } - len += sprintf(page + len, "\n"); + seq_putc(m, '\n'); } } } @@ -353,16 +328,25 @@ info_read(char *page, char **start, off_t off, int count, int *eof, } else { p = "ready"; } - len += sprintf(page + len, "State : %s\n", p); + seq_printf(m, "State : %s\n", p); - if (off + count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len - off) ? count : len - off); + return 0; +} + +static int info_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, info_proc_show, PDE(inode)->data); } +static const struct file_operations info_proc_fops = { + .owner = THIS_MODULE, + .open = info_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = info_proc_write, +}; + /* ** adapter proc init/de-init */ @@ -380,28 +364,20 @@ int create_adapter_proc(diva_os_xdi_adapter_t * a) return (0); a->proc_adapter_dir = (void *) de; - if (!(pe = - create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de))) + pe = proc_create_data(info_proc_name, S_IRUGO | S_IWUSR, de, + &info_proc_fops, a); + if (!pe) return (0); a->proc_info = (void *) pe; - pe->write_proc = info_write; - pe->read_proc = info_read; - pe->data = a; - if ((pe = create_proc_entry(grp_opt_proc_name, - S_IFREG | S_IRUGO | S_IWUSR, de))) { + pe = proc_create_data(grp_opt_proc_name, S_IRUGO | S_IWUSR, de, + &grp_opt_proc_fops, a); + if (pe) a->proc_grp_opt = (void *) pe; - pe->write_proc = write_grp_opt; - pe->read_proc = read_grp_opt; - pe->data = a; - } - if ((pe = create_proc_entry(d_l1_down_proc_name, - S_IFREG | S_IRUGO | S_IWUSR, de))) { + pe = proc_create_data(d_l1_down_proc_name, S_IRUGO | S_IWUSR, de, + &d_l1_down_proc_fops, a); + if (pe) a->proc_d_l1_down = (void *) pe; - pe->write_proc = write_d_l1_down; - pe->read_proc = read_d_l1_down; - pe->data = a; - } DBG_TRC(("proc entry %s created", tmp)); diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 4ffaa14b9fc4..fe874afa4f81 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -11,6 +11,8 @@ */ #include +#include +#include #include #include #include @@ -432,26 +434,16 @@ static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) return retval; } -/********************************************************************* -hycapi_read_proc - -Informations provided in the /proc/capi-entries. - -*********************************************************************/ - -static int hycapi_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int hycapi_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); hysdn_card *card = cinfo->card; - int len = 0; char *s; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_read_proc\n"); -#endif - len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); - len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); - len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + + seq_printf(m, "%-16s %s\n", "name", cinfo->cardname); + seq_printf(m, "%-16s 0x%x\n", "io", card->iobase); + seq_printf(m, "%-16s %d\n", "irq", card->irq); switch (card->brdtype) { case BD_PCCARD: s = "HYSDN Hycard"; break; @@ -461,24 +453,32 @@ static int hycapi_read_proc(char *page, char **start, off_t off, case BD_PLEXUS: s = "HYSDN Plexus30"; break; default: s = "???"; break; } - len += sprintf(page+len, "%-16s %s\n", "type", s); + seq_printf(m, "%-16s %s\n", "type", s); if ((s = cinfo->version[VER_DRIVER]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + seq_printf(m, "%-16s %s\n", "ver_driver", s); if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + seq_printf(m, "%-16s %s\n", "ver_cardtype", s); if ((s = cinfo->version[VER_SERIAL]) != NULL) - len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + seq_printf(m, "%-16s %s\n", "ver_serial", s); - len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); + return 0; +} + +static int hycapi_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, hycapi_proc_show, PDE(inode)->data); } +static const struct file_operations hycapi_proc_fops = { + .owner = THIS_MODULE, + .open = hycapi_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /************************************************************** hycapi_load_firmware @@ -774,7 +774,7 @@ hycapi_capi_create(hysdn_card *card) ctrl->load_firmware = hycapi_load_firmware; ctrl->reset_ctr = hycapi_reset_ctr; ctrl->procinfo = hycapi_procinfo; - ctrl->ctr_read_proc = hycapi_read_proc; + ctrl->proc_fops = &hycapi_proc_fops; strcpy(ctrl->name, cinfo->cardname); ctrl->owner = THIS_MODULE; diff --git a/include/linux/isdn/capilli.h b/include/linux/isdn/capilli.h index 7acb87a44872..d3e5e9da0c82 100644 --- a/include/linux/isdn/capilli.h +++ b/include/linux/isdn/capilli.h @@ -50,8 +50,7 @@ struct capi_ctr { u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb); char *(*procinfo)(struct capi_ctr *); - int (*ctr_read_proc)(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *card); + const struct file_operations *proc_fops; /* filled in before calling ready callback */ u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */ diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 97f8d68d574d..3487cfe74aec 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -21,7 +21,8 @@ */ #include - +#include +#include #include #include #include @@ -516,33 +517,37 @@ static char *cmtp_procinfo(struct capi_ctr *ctrl) return "CAPI Message Transport Protocol"; } -static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl) +static int cmtp_proc_show(struct seq_file *m, void *v) { + struct capi_ctr *ctrl = m->private; struct cmtp_session *session = ctrl->driverdata; struct cmtp_application *app; struct list_head *p, *n; - int len = 0; - len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl)); - len += sprintf(page + len, "addr %s\n", session->name); - len += sprintf(page + len, "ctrl %d\n", session->num); + seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl)); + seq_printf(m, "addr %s\n", session->name); + seq_printf(m, "ctrl %d\n", session->num); list_for_each_safe(p, n, &session->applications) { app = list_entry(p, struct cmtp_application, list); - len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping); + seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping); } - if (off + count >= len) - *eof = 1; - - if (len < off) - return 0; - - *start = page + off; + return 0; +} - return ((count < len - off) ? count : len - off); +static int cmtp_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cmtp_proc_show, PDE(inode)->data); } +static const struct file_operations cmtp_proc_fops = { + .owner = THIS_MODULE, + .open = cmtp_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; int cmtp_attach_device(struct cmtp_session *session) { @@ -582,7 +587,7 @@ int cmtp_attach_device(struct cmtp_session *session) session->ctrl.send_message = cmtp_send_message; session->ctrl.procinfo = cmtp_procinfo; - session->ctrl.ctr_read_proc = cmtp_ctr_read_proc; + session->ctrl.proc_fops = &cmtp_proc_fops; if (attach_capi_ctr(&session->ctrl) < 0) { BT_ERR("Can't attach new controller"); -- GitLab From 02bf6cc72cc2a6258411ddf1649f33a65fc9a06e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 14 Jan 2010 20:58:58 +0900 Subject: [PATCH 0687/3892] sh: Preliminary SDK7786 board support. This stubs in some preliminary board support for the RTE SDK7786. This is quite stunted at the moment, and primarily builds on top of the system FPGA. FPGA IRQs are handled via CPU IRL masking for simplicity, with initial peripheral support restricted to the debug ethernet. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/Makefile | 2 + arch/sh/boards/Kconfig | 7 + arch/sh/boards/mach-sdk7786/Makefile | 1 + arch/sh/boards/mach-sdk7786/setup.c | 219 ++++ arch/sh/configs/sdk7786_defconfig | 1440 ++++++++++++++++++++++++++ arch/sh/tools/mach-types | 1 + 6 files changed, 1670 insertions(+) create mode 100644 arch/sh/boards/mach-sdk7786/Makefile create mode 100644 arch/sh/boards/mach-sdk7786/setup.c create mode 100644 arch/sh/configs/sdk7786_defconfig diff --git a/arch/sh/Makefile b/arch/sh/Makefile index f7d5f42b00a7..30c80fd29058 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -83,6 +83,7 @@ defaultimage-$(CONFIG_SH_AP325RXA) := uImage defaultimage-$(CONFIG_SH_7724_SOLUTION_ENGINE) := uImage defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux +defaultimage-$(CONFIG_SH_SDK7786) := vmlinux.bin # Set some sensible Kbuild defaults KBUILD_IMAGE := $(defaultimage-y) @@ -143,6 +144,7 @@ machdir-$(CONFIG_SH_AP325RXA) += mach-ap325rxa machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09 machdir-$(CONFIG_SH_ECOVEC) += mach-ecovec24 machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780 +machdir-$(CONFIG_SH_SDK7786) += mach-sdk7786 machdir-$(CONFIG_SH_X3PROTO) += mach-x3proto machdir-$(CONFIG_SH_SH7763RDP) += mach-sh7763rdp machdir-$(CONFIG_SH_SH4202_MICRODEV) += mach-microdev diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index aedd9deb5de2..c0a1992bb256 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -150,6 +150,13 @@ config SH_SDK7780 Select SDK7780 if configuring for a Renesas SH7780 SDK7780R3 evaluation board. +config SH_SDK7786 + bool "SDK7786" + depends on CPU_SUBTYPE_SH7786 + help + Select SDK7786 if configuring for a Renesas Technology Europe + SH7786-65nm board. + config SH_HIGHLANDER bool "Highlander" depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile new file mode 100644 index 000000000000..f663768429f0 --- /dev/null +++ b/arch/sh/boards/mach-sdk7786/Makefile @@ -0,0 +1 @@ +obj-y := setup.o diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c new file mode 100644 index 000000000000..b460dcc785c1 --- /dev/null +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -0,0 +1,219 @@ +/* + * Renesas Technology Europe SDK7786 Support. + * + * Copyright (C) 2010 Matt Fleming + * Copyright (C) 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct resource smsc911x_resources[] = { + [0] = { + .name = "smsc911x-memory", + .start = 0x07ffff00, + .end = 0x07ffff00 + SZ_256 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "smsc911x-irq", + .start = evt2irq(0x2c0), + .end = evt2irq(0x2c0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .flags = SMSC911X_USE_32BIT, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +static struct resource smbus_fpga_resource = { + .start = 0x07fff9e0, + .end = 0x07fff9e0 + SZ_32 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device smbus_fpga_device = { + .name = "i2c-sdk7786", + .id = 0, + .num_resources = 1, + .resource = &smbus_fpga_resource, +}; + +static struct resource smbus_pcie_resource = { + .start = 0x07fffc30, + .end = 0x07fffc30 + SZ_32 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device smbus_pcie_device = { + .name = "i2c-sdk7786", + .id = 1, + .num_resources = 1, + .resource = &smbus_pcie_resource, +}; + +static struct i2c_board_info __initdata sdk7786_i2c_devices[] = { + { + I2C_BOARD_INFO("max6900", 0x68), + }, +}; + +static struct platform_device *sh7786_devices[] __initdata = { + &smsc911x_device, + &smbus_fpga_device, + &smbus_pcie_device, +}; + +#define SBCR_REGS_BASE 0x07fff990 + +#define SCBR_I2CMEN (1 << 0) /* FPGA I2C master enable */ +#define SCBR_I2CCEN (1 << 1) /* CPU I2C master enable */ + +static int sdk7786_i2c_setup(void) +{ + void __iomem *sbcr; + unsigned int tmp; + + sbcr = ioremap_nocache(SBCR_REGS_BASE, SZ_16); + + /* + * Hand over I2C control to the FPGA. + */ + tmp = ioread16(sbcr); + tmp &= ~SCBR_I2CCEN; + tmp |= SCBR_I2CMEN; + iowrite16(tmp, sbcr); + + iounmap(sbcr); + + return i2c_register_board_info(0, sdk7786_i2c_devices, + ARRAY_SIZE(sdk7786_i2c_devices)); +} + +static int __init sdk7786_devices_setup(void) +{ + int ret; + + ret = platform_add_devices(sh7786_devices, ARRAY_SIZE(sh7786_devices)); + if (unlikely(ret != 0)) + return ret; + + return sdk7786_i2c_setup(); +} +__initcall(sdk7786_devices_setup); + +#define FPGA_REGS_BASE 0x07fff800 +#define FPGA_REGS_SIZE 1152 + +#define INTASR 0x010 +#define INTAMR 0x020 +#define INTBSR 0x090 +#define INTBMR 0x0a0 +#define INTMSR 0x130 + +#define IASELR1 0x210 +#define IASELR2 0x220 +#define IASELR3 0x230 +#define IASELR4 0x240 +#define IASELR5 0x250 +#define IASELR6 0x260 +#define IASELR7 0x270 +#define IASELR8 0x280 +#define IASELR9 0x290 +#define IASELR10 0x2a0 +#define IASELR11 0x2b0 +#define IASELR12 0x2c0 +#define IASELR13 0x2d0 +#define IASELR14 0x2e0 +#define IASELR15 0x2f0 + +static void __iomem *fpga_regs; + +static u16 fpga_read_reg(unsigned int reg) +{ + return __raw_readw(fpga_regs + reg); +} + +static void fpga_write_reg(u16 val, unsigned int reg) +{ + __raw_writew(val, fpga_regs + reg); +} + +enum { + ATA_IRQ_BIT = 1, + SPI_BUSY_BIT = 2, + LIRQ5_BIT = 3, + LIRQ6_BIT = 4, + LIRQ7_BIT = 5, + LIRQ8_BIT = 6, + KEY_IRQ_BIT = 7, + PEN_IRQ_BIT = 8, + ETH_IRQ_BIT = 9, + RTC_ALARM_BIT = 10, + CRYSTAL_FAIL_BIT = 12, + ETH_PME_BIT = 14, +}; + +static void __init init_sdk7786_IRQ(void) +{ + unsigned int tmp; + + fpga_regs = ioremap_nocache(FPGA_REGS_BASE, FPGA_REGS_SIZE); + if (!fpga_regs) { + printk(KERN_ERR "Couldn't map FPGA registers\n"); + return; + } + + /* Enable priority encoding for all IRLs */ + fpga_write_reg(fpga_read_reg(INTMSR) | 0x0303, INTMSR); + + /* Clear FPGA interrupt status registers */ + fpga_write_reg(0x0000, INTASR); + fpga_write_reg(0x0000, INTBSR); + + /* Unmask FPGA interrupts */ + tmp = fpga_read_reg(INTAMR); + tmp &= ~(1 << ETH_IRQ_BIT); + fpga_write_reg(tmp, INTAMR); + + plat_irq_setup_pins(IRQ_MODE_IRL7654_MASK); + plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK); +} + +/* Initialize the board */ +static void __init sdk7786_setup(char **cmdline_p) +{ + printk(KERN_INFO "Renesas Technology Corp. SDK7786 support.\n"); +} + +/* + * The Machine Vector + */ +static struct sh_machine_vector mv_sdk7786 __initmv = { + .mv_name = "SDK7786", + .mv_setup = sdk7786_setup, + .mv_init_irq = init_sdk7786_IRQ, +}; diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig new file mode 100644 index 000000000000..1721d2c5c7e8 --- /dev/null +++ b/arch/sh/configs/sdk7786_defconfig @@ -0,0 +1,1440 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.33-rc3 +# Thu Jan 14 20:37:44 2010 +# +CONFIG_SUPERH=y +CONFIG_SUPERH32=y +# CONFIG_SUPERH64 is not set +CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig" +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_IRQ_PER_CPU=y +# CONFIG_GENERIC_GPIO is not set +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +# CONFIG_ARCH_SUSPEND_POSSIBLE is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_SYS_SUPPORTS_SMP=y +CONFIG_SYS_SUPPORTS_NUMA=y +CONFIG_SYS_SUPPORTS_TMU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_DMA_COHERENT=y +# CONFIG_DMA_NONCOHERENT is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +CONFIG_RCU_TRACE=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_TREE_RCU_TRACE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_MEM_RES_CTLR=y +# CONFIG_CGROUP_MEM_RES_CTLR_SWAP is not set +CONFIG_MM_OWNER=y +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_EVENT_PROFILE=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +CONFIG_BLK_CGROUP=y +# CONFIG_DEBUG_BLK_CGROUP is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CFQ_GROUP_IOSCHED=y +# CONFIG_DEBUG_CFQ_IOSCHED is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System type +# +CONFIG_CPU_SH4=y +CONFIG_CPU_SH4A=y +CONFIG_CPU_SHX3=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7201 is not set +# CONFIG_CPU_SUBTYPE_SH7203 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set +# CONFIG_CPU_SUBTYPE_MXG is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_SH7723 is not set +# CONFIG_CPU_SUBTYPE_SH7724 is not set +# CONFIG_CPU_SUBTYPE_SH7757 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +CONFIG_CPU_SUBTYPE_SH7786=y +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set +# CONFIG_CPU_SUBTYPE_SH7366 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_MEMORY_START=0x60000000 +CONFIG_MEMORY_SIZE=0x08000000 +# CONFIG_29BIT is not set +CONFIG_32BIT=y +CONFIG_PMB=y +# CONFIG_PMB_LEGACY is not set +CONFIG_X2TLB=y +CONFIG_VSYSCALL=y +# CONFIG_NUMA is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=1 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_ARCH_MEMORY_PROBE=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64K is not set +# CONFIG_HUGETLB_PAGE_SIZE_256K is not set +CONFIG_HUGETLB_PAGE_SIZE_1MB=y +# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=1 +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 + +# +# Cache configuration +# +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +CONFIG_SH_STORE_QUEUES=y +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEAEX=y +CONFIG_CPU_HAS_FPU=y + +# +# Board support +# +CONFIG_SH_SDK7786=y +# CONFIG_SH_URQUELL is not set + +# +# Timer and clock configuration +# +CONFIG_SH_TIMER_TMU=y +CONFIG_SH_PCLK_FREQ=50000000 +CONFIG_SH_CLK_CPG=y +CONFIG_SH_CLK_CPG_LEGACY=y +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_SH_CPU_FREQ=y + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +CONFIG_SECCOMP=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_GUSA=y +CONFIG_SPARSE_IRQ=y + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +CONFIG_ENTRY_OFFSET=0x00001000 +CONFIG_CMDLINE_OVERWRITE=y +# CONFIG_CMDLINE_EXTEND is not set +CONFIG_CMDLINE="console=ttySC1,115200 earlyprintk=sh-sci.1,115200 root=/dev/nfs ip=dhcp" + +# +# Bus options +# +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set +# CONFIG_CPU_IDLE is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_SATA_PMP=y +CONFIG_ATA_SFF=y +# CONFIG_SATA_MV is not set +CONFIG_PATA_PLATFORM=y +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_STNIC is not set +CONFIG_SMC91X=y +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_HOSTAP is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=6 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_SDK7786=y +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_TSL2550 is not set +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +CONFIG_I2C_DEBUG_BUS=y +CONFIG_I2C_DEBUG_CHIP=y +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_SH_MSIOF is not set +# CONFIG_SPI_SH_SCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SH_WDT is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SH_MOBILE_SDHI is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_88PM8607 is not set +# CONFIG_AB4500_CORE is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +CONFIG_USB_R8A66597_HCD=m +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C_HSOTG is not set +# CONFIG_USB_GADGET_IMX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_M66592=y +CONFIG_USB_M66592=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_CI13XXX is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set + +# +# OTG and related infrastructure +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +CONFIG_RTC_DRV_MAX6900=y +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=m +# CONFIG_UIO_PDRV is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_SMX is not set +# CONFIG_UIO_SERCOS3 is not set + +# +# TI VLYNQ +# +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_VM=y +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_BOOT_TRACER is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_KSYM_TRACER=y +# CONFIG_PROFILE_KSYM_TRACER is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_STACK_DEBUG is not set +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_4KSTACKS is not set +CONFIG_DUMP_CODE=y +CONFIG_DWARF_UNWINDER=y +# CONFIG_SH_NO_BSS_INIT is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index 6639b25d8d57..b25aa554ee5e 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -32,6 +32,7 @@ DREAMCAST SH_DREAMCAST SNAPGEAR SH_SECUREEDGE5410 EDOSK7705 SH_EDOSK7705 EDOSK7760 SH_EDOSK7760 +SDK7786 SH_SDK7786 SH4202_MICRODEV SH_SH4202_MICRODEV SH03 SH_SH03 LANDISK SH_LANDISK -- GitLab From 79b6a5110abf6fd4454ba34e0960783a4a2c801a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 14 Jan 2010 17:00:54 -0500 Subject: [PATCH 0688/3892] Revert "iwmc3200wifi: fix array out-of-boundary access" This reverts commit 6c853da3f30c93eae847ecbcd9fdf10ba0da04c2. From Message-ID: <1262663293.551.117.camel@debian> On Sat, 2010-01-02 at 22:09 +0800, Dan Carpenter wrote: > It don't think 6c853da3f30c93 is right. That's the patch > titled "iwmc3200wifi: fix array out-of-boundary access" > > Allocate priv->rx_packets[IWM_RX_ID_HASH + 1] because the max array > index is IWM_RX_ID_HASH according to IWM_RX_ID_GET_HASH(). > > In 2.6.33-rc2 IWM_RX_ID_GET_HASH() doesn't go as high as IWM_RX_ID_HASH > and I don't see any array out-of-bounds. > > #define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) Ah, you are right. I took '%' for '&'. John, would you revert it? Sorry for the false alarm. Thanks, -yi Reported-by: Dan Carpenter Reviewed-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/iwm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 842811142bef..79ffa3b98d73 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -268,7 +268,7 @@ struct iwm_priv { struct sk_buff_head rx_list; struct list_head rx_tickets; - struct list_head rx_packets[IWM_RX_ID_HASH + 1]; + struct list_head rx_packets[IWM_RX_ID_HASH]; struct workqueue_struct *rx_wq; struct work_struct rx_worker; -- GitLab From 46c4e5daea3d5df06e27bf5a49a0c42274db6725 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 15 Jan 2010 08:00:45 +0900 Subject: [PATCH 0689/3892] sh: Fix CONFIG_PMB=n build. The last commit introduced the following breakage arch/sh/include/asm/mmu.h: In function 'pmb_remap': arch/sh/include/asm/mmu.h:79: error: expected ';' before '}' token and... arch/sh/include/asm/mmu.h:78: error: 'EINVAL' undeclared (first use in this function) arch/sh/include/asm/mmu.h:78: error: (Each undeclared identifier is reported only once arch/sh/include/asm/mmu.h:78: error: for each function it appears in.) arch/sh/include/asm/mmu.h: In function 'pmb_init': arch/sh/include/asm/mmu.h:87: error: 'ENODEV' undeclared (first use in this function) Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/include/asm/mmu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index 4b0882bf5183..e5e8f48830ef 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h @@ -30,6 +30,7 @@ #define PMB_NO_ENTRY (-1) #ifndef __ASSEMBLY__ +#include /* Default "unsigned long" context */ typedef unsigned long mm_context_id_t[NR_CPUS]; @@ -75,7 +76,7 @@ int pmb_init(void); static inline long pmb_remap(unsigned long virt, unsigned long phys, unsigned long size, unsigned long flags) { - return -EINVAL + return -EINVAL; } static inline void pmb_unmap(unsigned long addr) -- GitLab From 6021e08db47386507108a475e6c820a7006a4632 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 7 Jan 2010 11:10:38 -0700 Subject: [PATCH 0690/3892] b43: Declare at least one real firmware file using MODULE_FIRMWARE. BugLink: http://bugs.launchpad.net/bugs/488636 Enhances module information with the names of the firmware files that could be used by this driver. This helps tools like Jockey to correctly detect and/or install the firmware files relevant to this driver. Signed-off-by: Tim Gardner Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6634a77fc766..881afff86bd3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -67,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); - +MODULE_FIRMWARE("b43/ucode11.fw"); +MODULE_FIRMWARE("b43/ucode13.fw"); +MODULE_FIRMWARE("b43/ucode14.fw"); +MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode5.fw"); +MODULE_FIRMWARE("b43/ucode9.fw"); static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); -- GitLab From e99c7cd57b2481ee36b2338040e3ce1cd17e0763 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 7 Jan 2010 17:24:55 -0500 Subject: [PATCH 0691/3892] cfg80211: fix 2 GHz subband calculation for country IEs Country IEs triplets are getting an extra channel with the current count. This does not affect regulatory because we always took the intersection between what the AP gave and what CRDA believed is correct. This however does fix processing some Country IEs with multiple sequential 2 GHz triplets. Since our parser and the spec mandates all channels be monitonically increasing we would drop the IE after noticing the second triplet begins on a channel already processed. APs that send these type of country IEs seems rare though. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index a5c2d3a6cbb2..f0859eada758 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -740,7 +740,7 @@ static struct ieee80211_regdomain *country_ie_2_rd( /* 2 GHz */ if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + - triplet->chans.num_channels; + triplet->chans.num_channels - 1; else /* * 5 GHz -- For example in country IEs if the first @@ -863,7 +863,7 @@ static struct ieee80211_regdomain *country_ie_2_rd( /* 2 GHz */ if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + - triplet->chans.num_channels; + triplet->chans.num_channels -1; else end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1)); -- GitLab From c2f4f527edab37f2f2130bd7813cd41db907ab6b Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 12 Jan 2010 12:58:17 -0600 Subject: [PATCH 0692/3892] b43legacy: Declare all possible ucodeX.fw files Enhance module information with the names of the firmware files that could be used by this driver. This helps tools like Jockey to correctly detect and/or install the firmware files relevant to this driver. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 494017e4fcc9..9e268b6240fb 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -61,6 +61,8 @@ MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); +MODULE_FIRMWARE("b43legacy/ucode2.fw"); +MODULE_FIRMWARE("b43legacy/ucode4.fw"); #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) static int modparam_pio; -- GitLab From ececeecee8c60be96368bcc416057f38822012df Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 12 Jan 2010 18:23:04 -0500 Subject: [PATCH 0693/3892] wl1271: remove unused flags These are unused and as with a previous patch 5ef5da for wl1251 this removes some other unused flags. the IRQ_MASK specifically conflicts with include/pcmcia/cs.h when using compat-wireless. Cc: Kalle Valo Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_reg.h | 99 ------------------------ 1 file changed, 99 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index 1f237389d1c7..990960771528 100644 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -62,73 +62,10 @@ #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) -/* - * Interrupt registers. - * 64 bit interrupt sources registers ws ced. - * sme interupts were removed and new ones were added. - * Order was changed. - */ -#define FIQ_MASK (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) -#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) -#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) -#define IRQ_MASK (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) -#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) -#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) -#define ECPU_MASK (REGISTERS_BASE + 0x0448) -#define FIQ_STS_L (REGISTERS_BASE + 0x044C) -#define FIQ_STS_H (REGISTERS_BASE + 0x0450) -#define IRQ_STS_L (REGISTERS_BASE + 0x0454) -#define IRQ_STS_H (REGISTERS_BASE + 0x0458) -#define INT_STS_ND (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) -#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) -#define INT_ACK (REGISTERS_BASE + 0x046C) -#define INT_ACK_L (REGISTERS_BASE + 0x046C) -#define INT_ACK_H (REGISTERS_BASE + 0x0470) -#define INT_TRIG (REGISTERS_BASE + 0x0474) -#define INT_TRIG_L (REGISTERS_BASE + 0x0474) -#define INT_TRIG_H (REGISTERS_BASE + 0x0478) -#define HOST_STS_L (REGISTERS_BASE + 0x045C) -#define HOST_STS_H (REGISTERS_BASE + 0x0460) -#define HOST_MASK (REGISTERS_BASE + 0x0430) -#define HOST_MASK_L (REGISTERS_BASE + 0x0430) -#define HOST_MASK_H (REGISTERS_BASE + 0x0434) -#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) -#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) -/* Host Interrupts*/ -#define HINT_MASK (REGISTERS_BASE + 0x0494) -#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) -#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) -#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) -/*1150 spec calls this HINT_STS_RAW*/ -#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) -#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) -#define HINT_ACK (REGISTERS_BASE + 0x04A8) -#define HINT_TRIG (REGISTERS_BASE + 0x04AC) - /*============================================= Host Interrupt Mask Register - 32bit (RW) ------------------------------------------ @@ -432,16 +369,6 @@ | CFG_RX_PRSP_EN) -/*=============================================== - Phy regs - ===============================================*/ -#define ACX_PHY_ADDR_REG SBB_ADDR -#define ACX_PHY_DATA_REG SBB_DATA -#define ACX_PHY_CTRL_REG SBB_CTL -#define ACX_PHY_REG_WR_MASK 0x00000001ul -#define ACX_PHY_REG_RD_MASK 0x00000002ul - - /*=============================================== EEPROM Read/Write Request 32bit RW ------------------------------------------ @@ -511,28 +438,6 @@ #define ACX_CONT_WIND_MIN_MASK 0x0000007f #define ACX_CONT_WIND_MAX 0x03ff0000 -/* - * Indirect slave register/memory registers - * ---------------------------------------- - */ -#define HW_SLAVE_REG_ADDR_REG 0x00000004 -#define HW_SLAVE_REG_DATA_REG 0x00000008 -#define HW_SLAVE_REG_CTRL_REG 0x0000000c - -#define SLAVE_AUTO_INC 0x00010000 -#define SLAVE_NO_AUTO_INC 0x00000000 -#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 - -#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR -#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA -#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL -#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL - -#define HW_FUNC_EVENT_INT_EN 0x8000 -#define HW_FUNC_EVENT_MASK_REG 0x00000034 - -#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) - /*=============================================== HI_CFG Interface Configuration Register Values ------------------------------------------ @@ -647,10 +552,6 @@ b12-b0 - Supported Rate indicator bits as defined below. ******************************************************************************/ -#define TNETW1251_CHIP_ID_PG1_0 0x07010101 -#define TNETW1251_CHIP_ID_PG1_1 0x07020101 -#define TNETW1251_CHIP_ID_PG1_2 0x07030101 - /************************************************************************* Interrupt Trigger Register (Host -> WiLink) -- GitLab From 2f1f00fc9b477481ad5c63976385c345851fee3d Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Wed, 13 Jan 2010 14:36:24 +0100 Subject: [PATCH 0694/3892] Remove config option B43_LEGACY_RFKILL completely In f41f3f373dd72344c65d801d6381fe83ef3a2c54 the B43 driver was ported to use the cfg80211 API for rfkill and consequently the config option was dropped (RFKILL is now unconditionally enabled). However in the Kernel Info the feature is still checked and reported missing. This patch just removes the conditional and the relevant code blocks while still reporting that feature unconditionally would be another option (it's always there). Signed-off-by: Christoph Egger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 9e268b6240fb..174ac6bde2b1 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3962,7 +3962,7 @@ static struct ssb_driver b43legacy_ssb_driver = { static void b43legacy_print_driverinfo(void) { - const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "", + const char *feat_pci = "", *feat_leds = "", *feat_pio = "", *feat_dma = ""; #ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT @@ -3971,9 +3971,6 @@ static void b43legacy_print_driverinfo(void) #ifdef CONFIG_B43LEGACY_LEDS feat_leds = "L"; #endif -#ifdef CONFIG_B43LEGACY_RFKILL - feat_rfkill = "R"; -#endif #ifdef CONFIG_B43LEGACY_PIO feat_pio = "I"; #endif @@ -3981,9 +3978,9 @@ static void b43legacy_print_driverinfo(void) feat_dma = "D"; #endif printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s, Firmware-ID: " B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", - feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); + feat_pci, feat_leds, feat_pio, feat_dma); } static int __init b43legacy_init(void) -- GitLab From 5e4ea1f0ed256382d6d839fbd7a5c7f1b99b6cb0 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Jan 2010 10:20:57 +0530 Subject: [PATCH 0695/3892] ath9k: Fix panic on driver load The device has to be marked as invalid before registering the ISR. HW initialization takes place after the ISR has been registered, and the invalid flag is eventually cleared in the ->stop() callback. Reported-by: Pavel Roskin Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 3 +++ drivers/net/wireless/ath/ath9k/init.c | 2 -- drivers/net/wireless/ath/ath9k/pci.c | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index f24b1f4c3e29..9e62a569e816 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -121,6 +121,9 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; + /* Will be cleared in ath9k_start() */ + sc->sc_flags |= SC_OP_INVALID; + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 16d1efb4b8b2..5f78d7a5ff22 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -534,8 +534,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, int ret = 0, i; int csz = 0; - sc->sc_flags |= SC_OP_INVALID; - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 95b9a07597ef..4ae7b5f12029 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -198,6 +198,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->dev = &pdev->dev; sc->mem = mem; + /* Will be cleared in ath9k_start() */ + sc->sc_flags |= SC_OP_INVALID; + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); -- GitLab From 9d173fc5dfa8c1b4578b331ac7ff3ce8af27006e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 14 Jan 2010 13:09:14 +0200 Subject: [PATCH 0696/3892] mac80211: fix mac80211.h documentation warnings There were some warnings about missing documentation and a missing reference. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- Documentation/DocBook/mac80211.tmpl | 2 +- include/net/mac80211.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index f3f37f141dbd..971d1c0c83e5 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl @@ -144,7 +144,7 @@ usage should require reading the full document. this though and the recommendation to allow only a single interface in STA mode at first! -!Finclude/net/mac80211.h ieee80211_if_init_conf +!Finclude/net/mac80211.h ieee80211_vif diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f313a3cbabda..bbfa4750092e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -107,6 +107,7 @@ enum ieee80211_max_queues { * 2^n-1 in the range 1..32767] * @cw_max: maximum contention window [like @cw_min] * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled + * @uapsd: is U-APSD mode enabled for the queue */ struct ieee80211_tx_queue_params { u16 txop; @@ -608,7 +609,11 @@ enum ieee80211_conf_changed { /** * enum ieee80211_smps_mode - spatial multiplexing power save mode * - * @ + * @IEEE80211_SMPS_AUTOMATIC: automatic + * @IEEE80211_SMPS_OFF: off + * @IEEE80211_SMPS_STATIC: static + * @IEEE80211_SMPS_DYNAMIC: dynamic + * @IEEE80211_SMPS_NUM_MODES: internal, don't use */ enum ieee80211_smps_mode { IEEE80211_SMPS_AUTOMATIC, -- GitLab From c99445b14054e0c4ed4715df1dad1fc608cbab46 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 14 Jan 2010 13:09:21 +0200 Subject: [PATCH 0697/3892] mac80211: improve powersave documentation There has been some confusion how drivers should implement powersave support. Improve the documentation a bit to make it more clear what drivers need to do. Also mention about U-APSD. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/net/mac80211.h | 75 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bbfa4750092e..c90047de4428 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -569,7 +569,13 @@ struct ieee80211_rx_status { * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this * to determine for example whether to calculate timestamps for packets * or not, do not use instead of filter flags! - * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) + * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only). + * This is the power save mode defined by IEEE 802.11-2007 section 11.2, + * meaning that the hardware still wakes up for beacons, is able to + * transmit frames and receive the possible acknowledgment frames. + * Not to be confused with hardware specific wakeup/sleep states, + * driver is responsible for that. See the section "Powersave support" + * for more. * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set * the driver should be prepared to handle configuration requests but * may turn the device off as much as possible. Typically, this flag will @@ -1138,18 +1144,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * * mac80211 has support for various powersave implementations. * - * First, it can support hardware that handles all powersaving by - * itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS - * hardware flag. In that case, it will be told about the desired - * powersave mode depending on the association status, and the driver - * must take care of sending nullfunc frames when necessary, i.e. when - * entering and leaving powersave mode. The driver is required to look at - * the AID in beacons and signal to the AP that it woke up when it finds - * traffic directed to it. This mode supports dynamic PS by simply - * enabling/disabling PS. - * - * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS - * flag to indicate that it can support dynamic PS mode itself (see below). + * First, it can support hardware that handles all powersaving by itself, + * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware + * flag. In that case, it will be told about the desired powersave mode + * with the %IEEE80211_CONF_PS flag depending on the association status. + * The hardware must take care of sending nullfunc frames when necessary, + * i.e. when entering and leaving powersave mode. The hardware is required + * to look at the AID in beacons and signal to the AP that it woke up when + * it finds traffic directed to it. + * + * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in + * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused + * with hardware wakeup and sleep states. Driver is responsible for waking + * up the hardware before issueing commands to the hardware and putting it + * back to sleep at approriate times. + * + * When PS is enabled, hardware needs to wakeup for beacons and receive the + * buffered multicast/broadcast frames after the beacon. Also it must be + * possible to send frames and receive the acknowledment frame. * * Other hardware designs cannot send nullfunc frames by themselves and also * need software support for parsing the TIM bitmap. This is also supported @@ -1157,14 +1169,35 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still * required to pass up beacons. The hardware is still required to handle * waking up for multicast traffic; if it cannot the driver must handle that - * as best as it can, mac80211 is too slow. - * - * Dynamic powersave mode is an extension to normal powersave mode in which - * the hardware stays awake for a user-specified period of time after sending - * a frame so that reply frames need not be buffered and therefore delayed - * to the next wakeup. This can either be supported by hardware, in which case - * the driver needs to look at the @dynamic_ps_timeout hardware configuration - * value, or by the stack if all nullfunc handling is in the stack. + * as best as it can, mac80211 is too slow to do that. + * + * Dynamic powersave is an extension to normal powersave in which the + * hardware stays awake for a user-specified period of time after sending a + * frame so that reply frames need not be buffered and therefore delayed to + * the next wakeup. It's compromise of getting good enough latency when + * there's data traffic and still saving significantly power in idle + * periods. + * + * Dynamic powersave is supported by simply mac80211 enabling and disabling + * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS + * flag and mac80211 will handle everything automatically. Additionally, + * hardware having support for the dynamic PS feature may set the + * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support + * dynamic PS mode itself. The driver needs to look at the + * @dynamic_ps_timeout hardware configuration value and use it that value + * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable + * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS + * enabled whenever user has enabled powersave. + * + * Driver informs U-APSD client support by enabling + * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the + * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS + * Nullfunc frames and stay awake until the service period has ended. To + * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames + * from that AC are transmitted with powersave enabled. + * + * Note: U-APSD client mode is not yet supported with + * %IEEE80211_HW_PS_NULLFUNC_STACK. */ /** -- GitLab From a0f2e0fca1e72c1de07e834be05b61d33842253e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 14 Jan 2010 13:27:46 -0500 Subject: [PATCH 0698/3892] cfg80211: Ingore country IEs with a zero set of number of channels Previous to this and the last patch, titled, "cfg80211: Fix 2 GHz subband calculation for country IEs" we would end up treating these IEs as single channel units. These are in fact just bogus IE triplets so ignore the entire IE if these are found. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f0859eada758..f3b77f7b8e3d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -585,6 +585,9 @@ static int max_subband_chan(int orig_cur_chan, break; } + if (triplet->chans.num_channels == 0) + return 0; + /* Monitonically increasing channel order */ if (triplet->chans.first_channel <= end_subband_chan) return 0; @@ -737,6 +740,9 @@ static struct ieee80211_regdomain *country_ie_2_rd( break; } + if (triplet->chans.num_channels == 0) + return NULL; + /* 2 GHz */ if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + -- GitLab From b6b1ac69372da996f40863358df41ca77075b249 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 14 Jan 2010 13:13:47 -0600 Subject: [PATCH 0699/3892] Staging: r8187se: Fix compile error from wireless-testing commit 7044cc56 In wireless-testing, commit 7044cc56 added struct ieee80211_hdr_3addr to include/linux/ieee80211.h. This definition collides with one that is in the r8187se driver in staging. The conflict is resolved by changing r8187se to use the definition from include/linuc/ieee80211.h. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- .../staging/rtl8187se/ieee80211/ieee80211.h | 9 ------- .../rtl8187se/ieee80211/ieee80211_softmac.c | 24 +++++++++---------- drivers/staging/rtl8187se/r8180_core.c | 4 ++-- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 3222c22152fb..462578703d07 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -482,15 +482,6 @@ struct ieee80211_header_data { u16 seq_ctrl; }; -struct ieee80211_hdr_3addr { - u16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; -} __attribute__ ((packed)); - struct ieee80211_hdr_4addr { u16 frame_ctl; u16 duration_id; diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 334e4c7ec61b..cc9da3713526 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee enqueue_mgmt(ieee,skb); }else{ - header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee spin_unlock_irqrestore(&ieee->lock, flags); spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); - header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i if(single){ - header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i }else{ - header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb( return NULL; disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); - disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); + disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); disass->header.duration_id = 0; memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); @@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) assoc = (struct ieee80211_assoc_response_frame *) skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); - assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); + assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); memcpy(assoc->header.addr1, dest,ETH_ALEN); memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); - hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | (pwr ? IEEE80211_FCTL_PM:0)); @@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); - hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; + hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ; hdr->header.duration_id= 37; //FIXME memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, tasklet_schedule(&ieee->ps_task); - if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && - WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) + if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP && + WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON) ieee->last_rx_ps_time = jiffies; - switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + switch (WLAN_FC_GET_STYPE(header->frame_control)) { case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: @@ -2064,7 +2064,7 @@ void ieee80211_wake_queue(struct ieee80211_device *ieee) header = (struct ieee80211_hdr_3addr *) skb->data; - header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 53e654d0d4fa..7788bc42e9b4 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1909,7 +1909,7 @@ rate) struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int mode; struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; - short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; + short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS; unsigned long flags; int priority; @@ -2177,7 +2177,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, TxDescDuration = ThisFrameTime + aSifsTime + AckTime; } - if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment + if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) { // ThisFrame-ACK. Duration = aSifsTime + AckTime; } else { // One or more fragments remained. -- GitLab From 10ab92d8c336c25af1fce46113ed85856e02e95d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 12:08:31 +0900 Subject: [PATCH 0700/3892] sh: heartbeat: Support access size specification via resource flags. This permits the resource access size to be handed off through the resource flags, which saves platforms from having to establish platform data only to specify the register width. Signed-off-by: Paul Mundt --- arch/sh/drivers/heartbeat.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c index a9339a6174fc..2acbc793032d 100644 --- a/arch/sh/drivers/heartbeat.c +++ b/arch/sh/drivers/heartbeat.c @@ -1,7 +1,7 @@ /* * Generic heartbeat driver for regular LED banks * - * Copyright (C) 2007 Paul Mundt + * Copyright (C) 2007 - 2010 Paul Mundt * * Most SH reference boards include a number of individual LEDs that can * be independently controlled (either via a pre-defined hardware @@ -27,7 +27,7 @@ #include #define DRV_NAME "heartbeat" -#define DRV_VERSION "0.1.1" +#define DRV_VERSION "0.1.2" static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; @@ -98,7 +98,7 @@ static int heartbeat_drv_probe(struct platform_device *pdev) return -ENOMEM; } - hd->base = ioremap_nocache(res->start, res->end - res->start + 1); + hd->base = ioremap_nocache(res->start, resource_size(res)); if (unlikely(!hd->base)) { dev_err(&pdev->dev, "ioremap failed\n"); @@ -117,8 +117,20 @@ static int heartbeat_drv_probe(struct platform_device *pdev) for (i = 0; i < hd->nr_bits; i++) hd->mask |= (1 << hd->bit_pos[i]); - if (!hd->regsize) - hd->regsize = 8; /* default access size */ + if (!hd->regsize) { + switch (res->flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_32BIT: + hd->regsize = 32; + break; + case IORESOURCE_MEM_16BIT: + hd->regsize = 16; + break; + case IORESOURCE_MEM_8BIT: + default: + hd->regsize = 8; + break; + } + } setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd); platform_set_drvdata(pdev, hd); -- GitLab From 2267c7875b3a3a41b7a8cc9659d75ec934c98ffd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 12:11:30 +0900 Subject: [PATCH 0701/3892] sh: mach-sdk7786: heartbeat support. Hand off the user LEDs to the heartbeat driver. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/setup.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index b460dcc785c1..f2d4b75bf31c 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -15,8 +15,22 @@ #include #include #include +#include #include +static struct resource heartbeat_resource = { + .start = 0x07fff8b0, + .end = 0x07fff8b0 + sizeof(u16) - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = 1, + .resource = &heartbeat_resource, +}; + static struct resource smsc911x_resources[] = { [0] = { .name = "smsc911x-memory", @@ -82,6 +96,7 @@ static struct i2c_board_info __initdata sdk7786_i2c_devices[] = { }; static struct platform_device *sh7786_devices[] __initdata = { + &heartbeat_device, &smsc911x_device, &smbus_fpga_device, &smbus_pcie_device, -- GitLab From a09d2831b3457a92a58d67bddfed370516acfe28 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 12:24:34 +0900 Subject: [PATCH 0702/3892] sh: heartbeat: Update boards for access size hinting. This updates the existing boards that specify the register width through platform data to use the resource flags instead. This eliminates platform data completely in most cases, and permits further improvement in the heartbeat driver as well as shrinking the overall private data size. Signed-off-by: Paul Mundt --- arch/sh/boards/board-polaris.c | 15 ++++++--------- arch/sh/boards/board-sh7785lcr.c | 21 ++++++--------------- arch/sh/boards/board-urquell.c | 21 ++++++--------------- arch/sh/boards/mach-ecovec24/setup.c | 16 +++++++--------- arch/sh/boards/mach-sdk7780/setup.c | 23 +++++++---------------- arch/sh/boards/mach-se/7206/setup.c | 15 ++++++--------- arch/sh/boards/mach-se/7343/setup.c | 21 ++++++--------------- arch/sh/boards/mach-se/770x/setup.c | 15 ++++++--------- arch/sh/boards/mach-se/7721/setup.c | 15 ++++++--------- arch/sh/boards/mach-se/7722/setup.c | 21 ++++++--------------- arch/sh/boards/mach-se/7724/setup.c | 21 ++++++--------------- arch/sh/boards/mach-se/7780/setup.c | 21 ++++++--------------- 12 files changed, 74 insertions(+), 151 deletions(-) diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c index 62607eb51004..5bc126900ce3 100644 --- a/arch/sh/boards/board-polaris.c +++ b/arch/sh/boards/board-polaris.c @@ -59,15 +59,12 @@ static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 }; static struct heartbeat_data heartbeat_data = { .bit_pos = heartbeat_bit_pos, .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), - .regsize = 8, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = PORT_PCDR, - .end = PORT_PCDR, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PORT_PCDR, + .end = PORT_PCDR, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT, }; static struct platform_device heartbeat_device = { @@ -76,8 +73,8 @@ static struct platform_device heartbeat_device = { .dev = { .platform_data = &heartbeat_data, }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; static struct platform_device *polaris_devices[] __initdata = { diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index e5a8a2fde39c..7eea90db6cea 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -32,26 +32,17 @@ * NOTE: This board has 2 physical memory maps. * Please look at include/asm-sh/sh7785lcr.h or hardware manual. */ -static struct resource heartbeat_resources[] = { - [0] = { - .start = PLD_LEDCR, - .end = PLD_LEDCR, - .flags = IORESOURCE_MEM, - }, -}; - -static struct heartbeat_data heartbeat_data = { - .regsize = 8, +static struct resource heartbeat_resource = { + .start = PLD_LEDCR, + .end = PLD_LEDCR, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; static struct mtd_partition nor_flash_partitions[] = { diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c index 36b8bac9b124..268f09e46568 100644 --- a/arch/sh/boards/board-urquell.c +++ b/arch/sh/boards/board-urquell.c @@ -50,26 +50,17 @@ */ /* HeartBeat */ -static struct resource heartbeat_resources[] = { - [0] = { - .start = BOARDREG(SLEDR), - .end = BOARDREG(SLEDR), - .flags = IORESOURCE_MEM, - }, -}; - -static struct heartbeat_data heartbeat_data = { - .regsize = 16, +static struct resource heartbeat_resource = { + .start = BOARDREG(SLEDR), + .end = BOARDREG(SLEDR), + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1 + .resource = &heartbeat_resource, }; /* LAN91C111 */ diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 6a8861b39f05..a6b223332d15 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -64,18 +64,16 @@ /* Heartbeat */ static unsigned char led_pos[] = { 0, 1, 2, 3 }; + static struct heartbeat_data heartbeat_data = { - .regsize = 8, .nr_bits = 4, .bit_pos = led_pos, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = 0xA405012C, /* PTG */ - .end = 0xA405012E - 1, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = 0xA405012C, /* PTG */ + .end = 0xA405012E - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT, }; static struct platform_device heartbeat_device = { @@ -84,8 +82,8 @@ static struct platform_device heartbeat_device = { .dev = { .platform_data = &heartbeat_data, }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; /* MTD */ diff --git a/arch/sh/boards/mach-sdk7780/setup.c b/arch/sh/boards/mach-sdk7780/setup.c index aad94a78dc70..1d04657e992d 100644 --- a/arch/sh/boards/mach-sdk7780/setup.c +++ b/arch/sh/boards/mach-sdk7780/setup.c @@ -20,27 +20,18 @@ #define GPIO_PECR 0xFFEA0008 -//* Heartbeat */ -static struct heartbeat_data heartbeat_data = { - .regsize = 16, -}; - -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +/* Heartbeat */ +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1 + .resource = &heartbeat_resource, }; /* SMC91x */ diff --git a/arch/sh/boards/mach-se/7206/setup.c b/arch/sh/boards/mach-se/7206/setup.c index f5466384972e..8f5c65d43d1d 100644 --- a/arch/sh/boards/mach-se/7206/setup.c +++ b/arch/sh/boards/mach-se/7206/setup.c @@ -50,15 +50,12 @@ static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct heartbeat_data heartbeat_data = { .bit_pos = heartbeat_bit_pos, .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), - .regsize = 32, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }; static struct platform_device heartbeat_device = { @@ -67,8 +64,8 @@ static struct platform_device heartbeat_device = { .dev = { .platform_data = &heartbeat_data, }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; static struct platform_device *se7206_devices[] __initdata = { diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c index 292cc47d853f..3412bb2973ae 100644 --- a/arch/sh/boards/mach-se/7343/setup.c +++ b/arch/sh/boards/mach-se/7343/setup.c @@ -11,26 +11,17 @@ #include #include -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, -}; - -static struct heartbeat_data heartbeat_data = { - .regsize = 16, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; static struct mtd_partition nor_flash_partitions[] = { diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c index 527eb6b12610..66d39d1b0901 100644 --- a/arch/sh/boards/mach-se/770x/setup.c +++ b/arch/sh/boards/mach-se/770x/setup.c @@ -93,15 +93,12 @@ static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct heartbeat_data heartbeat_data = { .bit_pos = heartbeat_bit_pos, .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), - .regsize = 16, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { @@ -110,8 +107,8 @@ static struct platform_device heartbeat_device = { .dev = { .platform_data = &heartbeat_data, }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\ diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c index 55af4c36b43a..460da53b4961 100644 --- a/arch/sh/boards/mach-se/7721/setup.c +++ b/arch/sh/boards/mach-se/7721/setup.c @@ -23,15 +23,12 @@ static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct heartbeat_data heartbeat_data = { .bit_pos = heartbeat_bit_pos, .nr_bits = ARRAY_SIZE(heartbeat_bit_pos), - .regsize = 16, }; -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { @@ -40,8 +37,8 @@ static struct platform_device heartbeat_device = { .dev = { .platform_data = &heartbeat_data, }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; static struct resource cf_ide_resources[] = { diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c index b1cb9425b600..93675418171d 100644 --- a/arch/sh/boards/mach-se/7722/setup.c +++ b/arch/sh/boards/mach-se/7722/setup.c @@ -25,26 +25,17 @@ #include /* Heartbeat */ -static struct heartbeat_data heartbeat_data = { - .regsize = 16, -}; - -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; /* SMC91x */ diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 5d0f70b46c97..cbfba783ee49 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -53,26 +53,17 @@ */ /* Heartbeat */ -static struct heartbeat_data heartbeat_data = { - .regsize = 16, -}; - -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; /* LAN91C111 */ diff --git a/arch/sh/boards/mach-se/7780/setup.c b/arch/sh/boards/mach-se/7780/setup.c index 1d3a867e94e3..f7bfb3f83692 100644 --- a/arch/sh/boards/mach-se/7780/setup.c +++ b/arch/sh/boards/mach-se/7780/setup.c @@ -17,26 +17,17 @@ #include /* Heartbeat */ -static struct heartbeat_data heartbeat_data = { - .regsize = 16, -}; - -static struct resource heartbeat_resources[] = { - [0] = { - .start = PA_LED, - .end = PA_LED, - .flags = IORESOURCE_MEM, - }, +static struct resource heartbeat_resource = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, }; static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .dev = { - .platform_data = &heartbeat_data, - }, - .num_resources = ARRAY_SIZE(heartbeat_resources), - .resource = heartbeat_resources, + .num_resources = 1, + .resource = &heartbeat_resource, }; /* SMC91x */ -- GitLab From a6198a238baceae9d4e0ce3915f6d239c89b5c08 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 14:21:37 +0900 Subject: [PATCH 0703/3892] sh: Guard against early IPIs in flush_cache_all(). flush_cache_all() gets called in to when we do some early ioremapping. Unfortunately on SDK7786 the interrupt controller itself requires ioremapping, leading to a bit of a chicken and egg scenario. For now, don't bother with IPI crosscalls if there aren't any other CPUs online. Signed-off-by: Paul Mundt --- arch/sh/mm/cache.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index b8607fa7ae12..0f4095d7ac8b 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -2,7 +2,7 @@ * arch/sh/mm/cache.c * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2002 - 2009 Paul Mundt + * Copyright (C) 2002 - 2010 Paul Mundt * * Released under the terms of the GNU GPL v2.0. */ @@ -41,8 +41,17 @@ static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info, int wait) { preempt_disable(); - smp_call_function(func, info, wait); + + /* + * It's possible that this gets called early on when IRQs are + * still disabled due to ioremapping by the boot CPU, so don't + * even attempt IPIs unless there are other CPUs online. + */ + if (num_online_cpus() > 1) + smp_call_function(func, info, wait); + func(info); + preempt_enable(); } -- GitLab From f0cb77372c3cf8c0cb17bbfb30a62506ea119286 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 15:13:48 +0900 Subject: [PATCH 0704/3892] sh: Fix up the secondary CPU entry point for 32bit mode. Presently the secondary CPU entry point is only aimed at 29bit phys mode, causing it to point to a stray virtual address in 32bit mode. Fix it up after consulting with our shiny new __in_29bit_mode(). Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4a/smp-shx3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c index 5863e0c4d02f..11bf4c1e25c0 100644 --- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c @@ -78,7 +78,10 @@ void __init plat_prepare_cpus(unsigned int max_cpus) void plat_start_cpu(unsigned int cpu, unsigned long entry_point) { - __raw_writel(entry_point, RESET_REG(cpu)); + if (__in_29bit_mode()) + __raw_writel(entry_point, RESET_REG(cpu)); + else + __raw_writel(virt_to_phys(entry_point), RESET_REG(cpu)); if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) __raw_writel(STBCR_MSTP, STBCR_REG(cpu)); -- GitLab From 6f832e8aab8c4c6d28629e970e4a85e74a8d0be6 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 16:31:04 +0900 Subject: [PATCH 0705/3892] sh: mach-sdk7786: mode pins support. This wires up the mode pins support on the SDK7786. The pins are standard SH7786 pins, and all are fixed in software. Needed for the clock framework, PCIe, and so forth. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/setup.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index f2d4b75bf31c..c38c6cc293b5 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -218,6 +218,23 @@ static void __init init_sdk7786_IRQ(void) plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK); } +#define MODSWR_REGS 0x07fff830 + +static int sdk7786_mode_pins(void) +{ + void __iomem *modswr; + int pin_states; + + modswr = ioremap_nocache(MODSWR_REGS, SZ_16); + if (!modswr) + return -ENXIO; + + pin_states = ioread16(modswr); + iounmap(modswr); + + return pin_states; +} + /* Initialize the board */ static void __init sdk7786_setup(char **cmdline_p) { @@ -230,5 +247,6 @@ static void __init sdk7786_setup(char **cmdline_p) static struct sh_machine_vector mv_sdk7786 __initmv = { .mv_name = "SDK7786", .mv_setup = sdk7786_setup, + .mv_mode_pins = sdk7786_mode_pins, .mv_init_irq = init_sdk7786_IRQ, }; -- GitLab From 4d0392be21d4710121f855c0caf57d32ffd1ced0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 15 Jan 2010 01:08:58 -0800 Subject: [PATCH 0706/3892] net/core/sock.c: quiet sparse noise In sock_getsockopt the symbol 'lv' is declared as an unsigned int type, probably due to sizeof returning a size_t which is really an unsigned int. This produces a sparse warning for SO_PEERNAME due to the sock->ops->getname() call: warning: incorrect type in argument 3 (different signedness) expected int *sockaddr_len got unsigned int * Quiet the warning by changing the type of 'lv' to an int. Signed-off-by: H Hartley Sweeten Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index e1f6f225f012..10b1d3243a72 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -741,7 +741,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, struct timeval tm; } v; - unsigned int lv = sizeof(int); + int lv = sizeof(int); int len; if (get_user(len, optlen)) -- GitLab From 71fceff0ea36d5a6cffecb272b8b3970535fe905 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 15 Jan 2010 01:16:40 -0800 Subject: [PATCH 0707/3892] ipv4: Use less conflicting local var name in change_nexthops() loop macro. As noticed by H Hartley Sweeten, since change_nexthops() uses 'nh' as it's iterator variable, it can conflict with other existing local vars. Use "nexthop_nh" to avoid the conflict and make it easier to figure out where this magic variable comes from. Signed-off-by: David S. Miller --- net/ipv4/fib_semantics.c | 76 +++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index ed19aa6919c2..96b21011a3e4 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -62,8 +62,8 @@ static DEFINE_SPINLOCK(fib_multipath_lock); #define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \ for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) -#define change_nexthops(fi) { int nhsel; struct fib_nh * nh; \ -for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) +#define change_nexthops(fi) { int nhsel; struct fib_nh *nexthop_nh; \ +for (nhsel=0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nexthop_nh++, nhsel++) #else /* CONFIG_IP_ROUTE_MULTIPATH */ @@ -72,7 +72,7 @@ for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, #define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \ for (nhsel=0; nhsel < 1; nhsel++) -#define change_nexthops(fi) { int nhsel = 0; struct fib_nh * nh = (struct fib_nh *)((fi)->fib_nh); \ +#define change_nexthops(fi) { int nhsel = 0; struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \ for (nhsel=0; nhsel < 1; nhsel++) #endif /* CONFIG_IP_ROUTE_MULTIPATH */ @@ -145,9 +145,9 @@ void free_fib_info(struct fib_info *fi) return; } change_nexthops(fi) { - if (nh->nh_dev) - dev_put(nh->nh_dev); - nh->nh_dev = NULL; + if (nexthop_nh->nh_dev) + dev_put(nexthop_nh->nh_dev); + nexthop_nh->nh_dev = NULL; } endfor_nexthops(fi); fib_info_cnt--; release_net(fi->fib_net); @@ -162,9 +162,9 @@ void fib_release_info(struct fib_info *fi) if (fi->fib_prefsrc) hlist_del(&fi->fib_lhash); change_nexthops(fi) { - if (!nh->nh_dev) + if (!nexthop_nh->nh_dev) continue; - hlist_del(&nh->nh_hash); + hlist_del(&nexthop_nh->nh_hash); } endfor_nexthops(fi) fi->fib_dead = 1; fib_info_put(fi); @@ -395,19 +395,20 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, if (!rtnh_ok(rtnh, remaining)) return -EINVAL; - nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; - nh->nh_oif = rtnh->rtnh_ifindex; - nh->nh_weight = rtnh->rtnh_hops + 1; + nexthop_nh->nh_flags = + (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; + nexthop_nh->nh_oif = rtnh->rtnh_ifindex; + nexthop_nh->nh_weight = rtnh->rtnh_hops + 1; attrlen = rtnh_attrlen(rtnh); if (attrlen > 0) { struct nlattr *nla, *attrs = rtnh_attrs(rtnh); nla = nla_find(attrs, attrlen, RTA_GATEWAY); - nh->nh_gw = nla ? nla_get_be32(nla) : 0; + nexthop_nh->nh_gw = nla ? nla_get_be32(nla) : 0; #ifdef CONFIG_NET_CLS_ROUTE nla = nla_find(attrs, attrlen, RTA_FLOW); - nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; + nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; #endif } @@ -738,7 +739,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) fi->fib_nhs = nhs; change_nexthops(fi) { - nh->nh_parent = fi; + nexthop_nh->nh_parent = fi; } endfor_nexthops(fi) if (cfg->fc_mx) { @@ -808,7 +809,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) goto failure; } else { change_nexthops(fi) { - if ((err = fib_check_nh(cfg, fi, nh)) != 0) + if ((err = fib_check_nh(cfg, fi, nexthop_nh)) != 0) goto failure; } endfor_nexthops(fi) } @@ -843,11 +844,11 @@ link_it: struct hlist_head *head; unsigned int hash; - if (!nh->nh_dev) + if (!nexthop_nh->nh_dev) continue; - hash = fib_devindex_hashfn(nh->nh_dev->ifindex); + hash = fib_devindex_hashfn(nexthop_nh->nh_dev->ifindex); head = &fib_info_devhash[hash]; - hlist_add_head(&nh->nh_hash, head); + hlist_add_head(&nexthop_nh->nh_hash, head); } endfor_nexthops(fi) spin_unlock_bh(&fib_info_lock); return fi; @@ -1080,21 +1081,21 @@ int fib_sync_down_dev(struct net_device *dev, int force) prev_fi = fi; dead = 0; change_nexthops(fi) { - if (nh->nh_flags&RTNH_F_DEAD) + if (nexthop_nh->nh_flags&RTNH_F_DEAD) dead++; - else if (nh->nh_dev == dev && - nh->nh_scope != scope) { - nh->nh_flags |= RTNH_F_DEAD; + else if (nexthop_nh->nh_dev == dev && + nexthop_nh->nh_scope != scope) { + nexthop_nh->nh_flags |= RTNH_F_DEAD; #ifdef CONFIG_IP_ROUTE_MULTIPATH spin_lock_bh(&fib_multipath_lock); - fi->fib_power -= nh->nh_power; - nh->nh_power = 0; + fi->fib_power -= nexthop_nh->nh_power; + nexthop_nh->nh_power = 0; spin_unlock_bh(&fib_multipath_lock); #endif dead++; } #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (force > 1 && nh->nh_dev == dev) { + if (force > 1 && nexthop_nh->nh_dev == dev) { dead = fi->fib_nhs; break; } @@ -1144,18 +1145,20 @@ int fib_sync_up(struct net_device *dev) prev_fi = fi; alive = 0; change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD)) { + if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) { alive++; continue; } - if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) + if (nexthop_nh->nh_dev == NULL || + !(nexthop_nh->nh_dev->flags&IFF_UP)) continue; - if (nh->nh_dev != dev || !__in_dev_get_rtnl(dev)) + if (nexthop_nh->nh_dev != dev || + !__in_dev_get_rtnl(dev)) continue; alive++; spin_lock_bh(&fib_multipath_lock); - nh->nh_power = 0; - nh->nh_flags &= ~RTNH_F_DEAD; + nexthop_nh->nh_power = 0; + nexthop_nh->nh_flags &= ~RTNH_F_DEAD; spin_unlock_bh(&fib_multipath_lock); } endfor_nexthops(fi) @@ -1182,9 +1185,9 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res) if (fi->fib_power <= 0) { int power = 0; change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD)) { - power += nh->nh_weight; - nh->nh_power = nh->nh_weight; + if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) { + power += nexthop_nh->nh_weight; + nexthop_nh->nh_power = nexthop_nh->nh_weight; } } endfor_nexthops(fi); fi->fib_power = power; @@ -1204,9 +1207,10 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res) w = jiffies % fi->fib_power; change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { - if ((w -= nh->nh_power) <= 0) { - nh->nh_power--; + if (!(nexthop_nh->nh_flags&RTNH_F_DEAD) && + nexthop_nh->nh_power) { + if ((w -= nexthop_nh->nh_power) <= 0) { + nexthop_nh->nh_power--; fi->fib_power--; res->nh_sel = nhsel; spin_unlock_bh(&fib_multipath_lock); -- GitLab From a03d2451998e09e87eb573a9e04cc41fde2bb77f Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Thu, 14 Jan 2010 01:53:21 +0000 Subject: [PATCH 0708/3892] netxen: fix endianness read mac address In netxen_read_mac_addr, mac_addr should be declared u64 instead of __le64, used by host only. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- drivers/net/netxen/netxen_nic_hw.c | 4 ++-- drivers/net/netxen/netxen_nic_main.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 8264ae0cbf1d..1e9c8fa46c71 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1427,8 +1427,8 @@ static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring) } -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac); -int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac); +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac); +int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac); extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 85e28e60ecf1..0db36f190ba2 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1033,7 +1033,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, return 0; } -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac) { __le32 *pmac = (__le32 *) mac; u32 offset; @@ -1058,7 +1058,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) return 0; } -int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) +int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac) { uint32_t crbaddr, mac_hi, mac_lo; int pci_func = adapter->ahw.pci_func; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index def4a07357d6..b69cb3c7dfb6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -432,7 +432,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) { int i; unsigned char *p; - __le64 mac_addr; + u64 mac_addr; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; -- GitLab From c070395009e1e153395837cd256dffc931dd6f98 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Thu, 14 Jan 2010 01:53:22 +0000 Subject: [PATCH 0709/3892] netxen: fix endianness intr coalesce Before sending Interrupt coalesce parameters to device, convert them in little endian. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_hw.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 0db36f190ba2..9548e5967399 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -777,17 +777,20 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) int netxen_config_intr_coalesce(struct netxen_adapter *adapter) { nx_nic_req_t req; - u64 word; - int rv; + u64 word[6]; + int rv, i; memset(&req, 0, sizeof(nx_nic_req_t)); + memset(word, 0, sizeof(word)); req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); - word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); - req.req_hdr = cpu_to_le64(word); + word[0] = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word[0]); - memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal)); + memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); + for (i = 0; i < 6; i++) + req.words[i] = cpu_to_le64(word[i]); rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) { -- GitLab From 4d21fef426c5cbbdf6da607de4c0adcaa3d4bbb0 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Thu, 14 Jan 2010 01:53:23 +0000 Subject: [PATCH 0710/3892] netxen: fix license header GNU General Public License is in file "COPYING". Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/Makefile | 2 +- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_ctx.c | 2 +- drivers/net/netxen/netxen_nic_ethtool.c | 2 +- drivers/net/netxen/netxen_nic_hdr.h | 2 +- drivers/net/netxen/netxen_nic_hw.c | 2 +- drivers/net/netxen/netxen_nic_hw.h | 2 +- drivers/net/netxen/netxen_nic_init.c | 2 +- drivers/net/netxen/netxen_nic_main.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index 11d94e2434e4..861a0590b1f4 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -18,7 +18,7 @@ # MA 02111-1307, USA. # # The full GNU General Public License is included in this distribution -# in the file called LICENSE. +# in the file called "COPYING". # # diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 1e9c8fa46c71..144d2e880422 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9cb8f6878047..2a8ef5fc9663 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 542f408333ff..f8499e56cbee 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 638369024908..622e4c8be937 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9548e5967399..dd45c7a9122e 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 3fd1dcb3583a..e2c5b6f2df03 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 333bd325f58e..1c63610ead42 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b69cb3c7dfb6..e5bdd4de7731 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ -- GitLab From 1954dc11776ef8c06263ba4cd21bf4d25c79a19c Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Thu, 14 Jan 2010 01:53:24 +0000 Subject: [PATCH 0711/3892] netxen: fix sparse warning Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index e5bdd4de7731..076f826d5a50 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2596,7 +2596,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, return size; } -ssize_t netxen_sysfs_write_mem(struct kobject *kobj, +static ssize_t netxen_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t offset, size_t size) { -- GitLab From ad72c347e56bf3a0231b9d686e17764157d2961c Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Thu, 14 Jan 2010 07:08:34 +0000 Subject: [PATCH 0712/3892] can: Proper ctrlmode handling for CAN devices This patch adds error checking of ctrlmode values for CAN devices. As an example all availabe bits are implemented in the mcp251x driver. Signed-off-by: Christian Pellegrin Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/at91_can.c | 1 + drivers/net/can/bfin_can.c | 1 + drivers/net/can/dev.c | 2 ++ drivers/net/can/mcp251x.c | 11 ++++++++++- drivers/net/can/mscan/mscan.c | 1 + drivers/net/can/sja1000/sja1000.c | 1 + drivers/net/can/ti_hecc.c | 1 + drivers/net/can/usb/ems_usb.c | 1 + include/linux/can/dev.h | 1 + 9 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index f7287497ba6e..a2f29a38798a 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -1073,6 +1073,7 @@ static int __init at91_can_probe(struct platform_device *pdev) priv->can.bittiming_const = &at91_bittiming_const; priv->can.do_set_bittiming = at91_set_bittiming; priv->can.do_set_mode = at91_set_mode; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; priv->reg_base = addr; priv->dev = dev; priv->clk = clk; diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 7e1926e79e98..bf7f9ba2d903 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -603,6 +603,7 @@ struct net_device *alloc_bfin_candev(void) priv->can.bittiming_const = &bfin_can_bittiming_const; priv->can.do_set_bittiming = bfin_can_set_bittiming; priv->can.do_set_mode = bfin_can_set_mode; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; return dev; } diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index c1bb29f0322b..f08f1202ff00 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -592,6 +592,8 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); + if (cm->flags & ~priv->ctrlmode_supported) + return -EOPNOTSUPP; priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= cm->flags; } diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index afa2fa45fed9..bbe186b5a0ed 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -539,9 +539,14 @@ static void mcp251x_set_normal_mode(struct spi_device *spi) if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { /* Put device into loopback mode */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK); + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { + /* Put device into listen-only mode */ + mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY); } else { /* Put device into normal mode */ - mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); + mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL | + (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT ? + CANCTRL_OSM : 0)); /* Wait for the device to enter normal mode */ timeout = jiffies + HZ; @@ -948,6 +953,10 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) priv->can.bittiming_const = &mcp251x_bittiming_const; priv->can.do_set_mode = mcp251x_do_set_mode; priv->can.clock.freq = pdata->oscillator_frequency / 2; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; + if (pdata->model == CAN_MCP251X_MCP2515) + priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; priv->net = net; dev_set_drvdata(&spi->dev, priv); diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 40827c128b65..6b7dd578d417 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -686,6 +686,7 @@ struct net_device *alloc_mscandev(void) priv->can.bittiming_const = &mscan_bittiming_const; priv->can.do_set_bittiming = mscan_do_set_bittiming; priv->can.do_set_mode = mscan_do_set_mode; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; for (i = 0; i < TX_QUEUE_SIZE; i++) { priv->tx_queue[i].id = i; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 345304d779b9..ace103a44833 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -567,6 +567,7 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) priv->can.bittiming_const = &sja1000_bittiming_const; priv->can.do_set_bittiming = sja1000_set_bittiming; priv->can.do_set_mode = sja1000_set_mode; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; if (sizeof_priv) priv->priv = (void *)priv + sizeof(struct sja1000_priv); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 7d370e32a7a8..8332e242b0be 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -909,6 +909,7 @@ static int ti_hecc_probe(struct platform_device *pdev) priv->can.bittiming_const = &ti_hecc_bittiming_const; priv->can.do_set_mode = ti_hecc_do_set_mode; priv->can.do_get_state = ti_hecc_get_state; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; ndev->irq = irq->start; ndev->flags |= IFF_ECHO; diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index ddb17e256656..bfab283ba9b1 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1022,6 +1022,7 @@ static int ems_usb_probe(struct usb_interface *intf, dev->can.bittiming_const = &ems_usb_bittiming_const; dev->can.do_set_bittiming = ems_usb_set_bittiming; dev->can.do_set_mode = ems_usb_set_mode; + dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; netdev->flags |= IFF_ECHO; /* we support local echo */ diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 7e7c98a3e908..c8c660a79f90 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -38,6 +38,7 @@ struct can_priv { enum can_state state; u32 ctrlmode; + u32 ctrlmode_supported; int restart_ms; struct timer_list restart_timer; -- GitLab From 05c2828c72c4eabf62376adfe27bd24797621f62 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 14 Jan 2010 06:17:09 +0000 Subject: [PATCH 0713/3892] tun: export underlying socket Tun device looks similar to a packet socket in that both pass complete frames from/to userspace. This patch fills in enough fields in the socket underlying tun driver to support sendmsg/recvmsg operations, and message flags MSG_TRUNC and MSG_DONTWAIT, and exports access to this socket to modules. Regular read/write behaviour is unchanged. This way, code using raw sockets to inject packets into a physical device, can support injecting packets into host network stack almost without modification. First user of this interface will be vhost virtualization accelerator. Signed-off-by: Michael S. Tsirkin Acked-by: Herbert Xu Acked-by: David S. Miller Signed-off-by: David S. Miller --- drivers/net/tun.c | 101 +++++++++++++++++++++++++++++++++-------- include/linux/if_tun.h | 14 ++++++ 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2834a01bae24..5adb3d150552 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -144,6 +144,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) err = 0; tfile->tun = tun; tun->tfile = tfile; + tun->socket.file = file; dev_hold(tun->dev); sock_hold(tun->socket.sk); atomic_inc(&tfile->count); @@ -158,6 +159,7 @@ static void __tun_detach(struct tun_struct *tun) /* Detach from net device */ netif_tx_lock_bh(tun->dev); tun->tfile = NULL; + tun->socket.file = NULL; netif_tx_unlock_bh(tun->dev); /* Drop read queue */ @@ -387,7 +389,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* Notify and wake up reader process */ if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&tun->socket.wait); + wake_up_interruptible_poll(&tun->socket.wait, POLLIN | + POLLRDNORM | POLLRDBAND); return NETDEV_TX_OK; drop: @@ -743,7 +746,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, len = min_t(int, skb->len, len); skb_copy_datagram_const_iovec(skb, 0, iv, total, len); - total += len; + total += skb->len; tun->dev->stats.tx_packets++; tun->dev->stats.tx_bytes += len; @@ -751,34 +754,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, return total; } -static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, - unsigned long count, loff_t pos) +static ssize_t tun_do_read(struct tun_struct *tun, + struct kiocb *iocb, const struct iovec *iv, + ssize_t len, int noblock) { - struct file *file = iocb->ki_filp; - struct tun_file *tfile = file->private_data; - struct tun_struct *tun = __tun_get(tfile); DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; - ssize_t len, ret = 0; - - if (!tun) - return -EBADFD; + ssize_t ret = 0; DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); - len = iov_length(iv, count); - if (len < 0) { - ret = -EINVAL; - goto out; - } - add_wait_queue(&tun->socket.wait, &wait); while (len) { current->state = TASK_INTERRUPTIBLE; /* Read frames from the queue */ if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) { - if (file->f_flags & O_NONBLOCK) { + if (noblock) { ret = -EAGAIN; break; } @@ -805,6 +797,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, current->state = TASK_RUNNING; remove_wait_queue(&tun->socket.wait, &wait); + return ret; +} + +static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct tun_file *tfile = file->private_data; + struct tun_struct *tun = __tun_get(tfile); + ssize_t len, ret; + + if (!tun) + return -EBADFD; + len = iov_length(iv, count); + if (len < 0) { + ret = -EINVAL; + goto out; + } + + ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK); + ret = min_t(ssize_t, ret, len); out: tun_put(tun); return ret; @@ -847,7 +860,8 @@ static void tun_sock_write_space(struct sock *sk) return; if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); + wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT | + POLLWRNORM | POLLWRBAND); tun = tun_sk(sk)->tun; kill_fasync(&tun->fasync, SIGIO, POLL_OUT); @@ -858,6 +872,37 @@ static void tun_sock_destruct(struct sock *sk) free_netdev(tun_sk(sk)->tun->dev); } +static int tun_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len) +{ + struct tun_struct *tun = container_of(sock, struct tun_struct, socket); + return tun_get_user(tun, m->msg_iov, total_len, + m->msg_flags & MSG_DONTWAIT); +} + +static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len, + int flags) +{ + struct tun_struct *tun = container_of(sock, struct tun_struct, socket); + int ret; + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) + return -EINVAL; + ret = tun_do_read(tun, iocb, m->msg_iov, total_len, + flags & MSG_DONTWAIT); + if (ret > total_len) { + m->msg_flags |= MSG_TRUNC; + ret = flags & MSG_TRUNC ? ret : total_len; + } + return ret; +} + +/* Ops structure to mimic raw sockets with tun */ +static const struct proto_ops tun_socket_ops = { + .sendmsg = tun_sendmsg, + .recvmsg = tun_recvmsg, +}; + static struct proto tun_proto = { .name = "tun", .owner = THIS_MODULE, @@ -986,6 +1031,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_dev; init_waitqueue_head(&tun->socket.wait); + tun->socket.ops = &tun_socket_ops; sock_init_data(&tun->socket, sk); sk->sk_write_space = tun_sock_write_space; sk->sk_sndbuf = INT_MAX; @@ -1525,6 +1571,23 @@ static void tun_cleanup(void) rtnl_link_unregister(&tun_link_ops); } +/* Get an underlying socket object from tun file. Returns error unless file is + * attached to a device. The returned object works like a packet socket, it + * can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for + * holding a reference to the file for as long as the socket is in use. */ +struct socket *tun_get_socket(struct file *file) +{ + struct tun_struct *tun; + if (file->f_op != &tun_fops) + return ERR_PTR(-EINVAL); + tun = tun_get(file); + if (!tun) + return ERR_PTR(-EBADFD); + tun_put(tun); + return &tun->socket; +} +EXPORT_SYMBOL_GPL(tun_get_socket); + module_init(tun_init); module_exit(tun_cleanup); MODULE_DESCRIPTION(DRV_DESCRIPTION); diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 3f5fd523b49d..404abe00162c 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -86,4 +86,18 @@ struct tun_filter { __u8 addr[0][ETH_ALEN]; }; +#ifdef __KERNEL__ +#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) +struct socket *tun_get_socket(struct file *); +#else +#include +#include +struct file; +struct socket; +static inline struct socket *tun_get_socket(struct file *f) +{ + return ERR_PTR(-EINVAL); +} +#endif /* CONFIG_TUN */ +#endif /* __KERNEL__ */ #endif /* __IF_TUN_H */ -- GitLab From 5da779c34ccff5e1e617892b6c8bd8260fb1f04c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 14 Jan 2010 06:17:18 +0000 Subject: [PATCH 0714/3892] mm: export use_mm/unuse_mm to modules vhost net module wants to do copy to/from user from a kernel thread, which needs use_mm. Export it to modules. Acked-by: Andrea Arcangeli Acked-by: Andrew Morton Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- mm/mmu_context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/mmu_context.c b/mm/mmu_context.c index ded9081f4021..0777654147c9 100644 --- a/mm/mmu_context.c +++ b/mm/mmu_context.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -37,6 +38,7 @@ void use_mm(struct mm_struct *mm) if (active_mm != mm) mmdrop(active_mm); } +EXPORT_SYMBOL_GPL(use_mm); /* * unuse_mm @@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm) enter_lazy_tlb(mm, tsk); task_unlock(tsk); } +EXPORT_SYMBOL_GPL(unuse_mm); -- GitLab From 3a4d5c94e959359ece6d6b55045c3f046677f55c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 14 Jan 2010 06:17:27 +0000 Subject: [PATCH 0715/3892] vhost_net: a kernel-level virtio server What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification. There's similarity with vringfd, with some differences and reduced scope - uses eventfd for signalling - structures can be moved around in memory at any time (good for migration, bug work-arounds in userspace) - write logging is supported (good for migration) - support memory table and not just an offset (needed for kvm) common virtio related code has been put in a separate file vhost.c and can be made into a separate module if/when more backends appear. I used Rusty's lguest.c as the source for developing this part : this supplied me with witty comments I wouldn't be able to write myself. What it is not: vhost net is not a bus, and not a generic new system call. No assumptions are made on how guest performs hypercalls. Userspace hypervisors are supported as well as kvm. How it works: Basically, we connect virtio frontend (configured by userspace) to a backend. The backend could be a network device, or a tap device. Backend is also configured by userspace, including vlan/mac etc. Status: This works for me, and I haven't see any crashes. Compared to userspace, people reported improved latency (as I save up to 4 system calls per packet), as well as better bandwidth and CPU utilization. Features that I plan to look at in the future: - mergeable buffers - zero copy - scalability tuning: figure out the best threading model to use Note on RCU usage (this is also documented in vhost.h, near private_pointer which is the value protected by this variant of RCU): what is happening is that the rcu_dereference() is being used in a workqueue item. The role of rcu_read_lock() is taken on by the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue()/flush_work(). In the future we might need to apply some gcc attribute or sparse annotation to the function passed to INIT_WORK(). Paul's ack below is for this RCU usage. (Includes fixes by Alan Cox , David L Stevens , Chris Wright ) Acked-by: Rusty Russell Acked-by: Arnd Bergmann Acked-by: "Paul E. McKenney" Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- MAINTAINERS | 9 + arch/ia64/kvm/Kconfig | 1 + arch/powerpc/kvm/Kconfig | 1 + arch/s390/kvm/Kconfig | 1 + arch/x86/kvm/Kconfig | 1 + drivers/Makefile | 1 + drivers/vhost/Kconfig | 11 + drivers/vhost/Makefile | 2 + drivers/vhost/net.c | 661 ++++++++++++++++++++++ drivers/vhost/vhost.c | 1098 ++++++++++++++++++++++++++++++++++++ drivers/vhost/vhost.h | 161 ++++++ include/linux/Kbuild | 1 + include/linux/miscdevice.h | 1 + include/linux/vhost.h | 130 +++++ 14 files changed, 2079 insertions(+) create mode 100644 drivers/vhost/Kconfig create mode 100644 drivers/vhost/Makefile create mode 100644 drivers/vhost/net.c create mode 100644 drivers/vhost/vhost.c create mode 100644 drivers/vhost/vhost.h create mode 100644 include/linux/vhost.h diff --git a/MAINTAINERS b/MAINTAINERS index 745643b8c344..337dffbe9a47 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5803,6 +5803,15 @@ S: Maintained F: Documentation/filesystems/vfat.txt F: fs/fat/ +VIRTIO HOST (VHOST) +M: "Michael S. Tsirkin" +L: kvm@vger.kernel.org +L: virtualization@lists.osdl.org +L: netdev@vger.kernel.org +S: Maintained +F: drivers/vhost/ +F: include/linux/vhost.h + VIA RHINE NETWORK DRIVER M: Roger Luethi S: Maintained diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig index ef3e7be29caf..01c75797119c 100644 --- a/arch/ia64/kvm/Kconfig +++ b/arch/ia64/kvm/Kconfig @@ -47,6 +47,7 @@ config KVM_INTEL Provides support for KVM on Itanium 2 processors equipped with the VT extensions. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 07703f72330e..e28841fbfb8d 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -75,6 +75,7 @@ config KVM_E500 If unsure, say N. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 6ee55ae84ce2..a7251580891c 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -35,6 +35,7 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 4cd498332466..3c4d0109ad20 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -65,6 +65,7 @@ config KVM_AMD # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/lguest/Kconfig source drivers/virtio/Kconfig diff --git a/drivers/Makefile b/drivers/Makefile index 6ee53c7a57a1..81e36596b1e9 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ +obj-$(CONFIG_VHOST_NET) += vhost/ obj-$(CONFIG_VIRTIO) += virtio/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig new file mode 100644 index 000000000000..9f409f447aea --- /dev/null +++ b/drivers/vhost/Kconfig @@ -0,0 +1,11 @@ +config VHOST_NET + tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)" + depends on NET && EVENTFD && EXPERIMENTAL + ---help--- + This kernel module can be loaded in host kernel to accelerate + guest networking with virtio_net. Not to be confused with virtio_net + module itself which needs to be loaded in guest kernel. + + To compile this driver as a module, choose M here: the module will + be called vhost_net. + diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile new file mode 100644 index 000000000000..72dd02050bb9 --- /dev/null +++ b/drivers/vhost/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_VHOST_NET) += vhost_net.o +vhost_net-y := vhost.o net.o diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c new file mode 100644 index 000000000000..4c8928319e1d --- /dev/null +++ b/drivers/vhost/net.c @@ -0,0 +1,661 @@ +/* Copyright (C) 2009 Red Hat, Inc. + * Author: Michael S. Tsirkin + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * virtio-net server in host kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "vhost.h" + +/* Max number of bytes transferred before requeueing the job. + * Using this limit prevents one virtqueue from starving others. */ +#define VHOST_NET_WEIGHT 0x80000 + +enum { + VHOST_NET_VQ_RX = 0, + VHOST_NET_VQ_TX = 1, + VHOST_NET_VQ_MAX = 2, +}; + +enum vhost_net_poll_state { + VHOST_NET_POLL_DISABLED = 0, + VHOST_NET_POLL_STARTED = 1, + VHOST_NET_POLL_STOPPED = 2, +}; + +struct vhost_net { + struct vhost_dev dev; + struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX]; + struct vhost_poll poll[VHOST_NET_VQ_MAX]; + /* Tells us whether we are polling a socket for TX. + * We only do this when socket buffer fills up. + * Protected by tx vq lock. */ + enum vhost_net_poll_state tx_poll_state; +}; + +/* Pop first len bytes from iovec. Return number of segments used. */ +static int move_iovec_hdr(struct iovec *from, struct iovec *to, + size_t len, int iov_count) +{ + int seg = 0; + size_t size; + while (len && seg < iov_count) { + size = min(from->iov_len, len); + to->iov_base = from->iov_base; + to->iov_len = size; + from->iov_len -= size; + from->iov_base += size; + len -= size; + ++from; + ++to; + ++seg; + } + return seg; +} + +/* Caller must have TX VQ lock */ +static void tx_poll_stop(struct vhost_net *net) +{ + if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED)) + return; + vhost_poll_stop(net->poll + VHOST_NET_VQ_TX); + net->tx_poll_state = VHOST_NET_POLL_STOPPED; +} + +/* Caller must have TX VQ lock */ +static void tx_poll_start(struct vhost_net *net, struct socket *sock) +{ + if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED)) + return; + vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file); + net->tx_poll_state = VHOST_NET_POLL_STARTED; +} + +/* Expects to be always run from workqueue - which acts as + * read-size critical section for our kind of RCU. */ +static void handle_tx(struct vhost_net *net) +{ + struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX]; + unsigned head, out, in, s; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_control = NULL, + .msg_controllen = 0, + .msg_iov = vq->iov, + .msg_flags = MSG_DONTWAIT, + }; + size_t len, total_len = 0; + int err, wmem; + size_t hdr_size; + struct socket *sock = rcu_dereference(vq->private_data); + if (!sock) + return; + + wmem = atomic_read(&sock->sk->sk_wmem_alloc); + if (wmem >= sock->sk->sk_sndbuf) + return; + + use_mm(net->dev.mm); + mutex_lock(&vq->mutex); + vhost_disable_notify(vq); + + if (wmem < sock->sk->sk_sndbuf * 2) + tx_poll_stop(net); + hdr_size = vq->hdr_size; + + for (;;) { + head = vhost_get_vq_desc(&net->dev, vq, vq->iov, + ARRAY_SIZE(vq->iov), + &out, &in, + NULL, NULL); + /* Nothing new? Wait for eventfd to tell us they refilled. */ + if (head == vq->num) { + wmem = atomic_read(&sock->sk->sk_wmem_alloc); + if (wmem >= sock->sk->sk_sndbuf * 3 / 4) { + tx_poll_start(net, sock); + set_bit(SOCK_ASYNC_NOSPACE, &sock->flags); + break; + } + if (unlikely(vhost_enable_notify(vq))) { + vhost_disable_notify(vq); + continue; + } + break; + } + if (in) { + vq_err(vq, "Unexpected descriptor format for TX: " + "out %d, int %d\n", out, in); + break; + } + /* Skip header. TODO: support TSO. */ + s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out); + msg.msg_iovlen = out; + len = iov_length(vq->iov, out); + /* Sanity check */ + if (!len) { + vq_err(vq, "Unexpected header len for TX: " + "%zd expected %zd\n", + iov_length(vq->hdr, s), hdr_size); + break; + } + /* TODO: Check specific error and bomb out unless ENOBUFS? */ + err = sock->ops->sendmsg(NULL, sock, &msg, len); + if (unlikely(err < 0)) { + vhost_discard_vq_desc(vq); + tx_poll_start(net, sock); + break; + } + if (err != len) + pr_err("Truncated TX packet: " + " len %d != %zd\n", err, len); + vhost_add_used_and_signal(&net->dev, vq, head, 0); + total_len += len; + if (unlikely(total_len >= VHOST_NET_WEIGHT)) { + vhost_poll_queue(&vq->poll); + break; + } + } + + mutex_unlock(&vq->mutex); + unuse_mm(net->dev.mm); +} + +/* Expects to be always run from workqueue - which acts as + * read-size critical section for our kind of RCU. */ +static void handle_rx(struct vhost_net *net) +{ + struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; + unsigned head, out, in, log, s; + struct vhost_log *vq_log; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_control = NULL, /* FIXME: get and handle RX aux data. */ + .msg_controllen = 0, + .msg_iov = vq->iov, + .msg_flags = MSG_DONTWAIT, + }; + + struct virtio_net_hdr hdr = { + .flags = 0, + .gso_type = VIRTIO_NET_HDR_GSO_NONE + }; + + size_t len, total_len = 0; + int err; + size_t hdr_size; + struct socket *sock = rcu_dereference(vq->private_data); + if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) + return; + + use_mm(net->dev.mm); + mutex_lock(&vq->mutex); + vhost_disable_notify(vq); + hdr_size = vq->hdr_size; + + vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ? + vq->log : NULL; + + for (;;) { + head = vhost_get_vq_desc(&net->dev, vq, vq->iov, + ARRAY_SIZE(vq->iov), + &out, &in, + vq_log, &log); + /* OK, now we need to know about added descriptors. */ + if (head == vq->num) { + if (unlikely(vhost_enable_notify(vq))) { + /* They have slipped one in as we were + * doing that: check again. */ + vhost_disable_notify(vq); + continue; + } + /* Nothing new? Wait for eventfd to tell us + * they refilled. */ + break; + } + /* We don't need to be notified again. */ + if (out) { + vq_err(vq, "Unexpected descriptor format for RX: " + "out %d, int %d\n", + out, in); + break; + } + /* Skip header. TODO: support TSO/mergeable rx buffers. */ + s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in); + msg.msg_iovlen = in; + len = iov_length(vq->iov, in); + /* Sanity check */ + if (!len) { + vq_err(vq, "Unexpected header len for RX: " + "%zd expected %zd\n", + iov_length(vq->hdr, s), hdr_size); + break; + } + err = sock->ops->recvmsg(NULL, sock, &msg, + len, MSG_DONTWAIT | MSG_TRUNC); + /* TODO: Check specific error and bomb out unless EAGAIN? */ + if (err < 0) { + vhost_discard_vq_desc(vq); + break; + } + /* TODO: Should check and handle checksum. */ + if (err > len) { + pr_err("Discarded truncated rx packet: " + " len %d > %zd\n", err, len); + vhost_discard_vq_desc(vq); + continue; + } + len = err; + err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size); + if (err) { + vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n", + vq->iov->iov_base, err); + break; + } + len += hdr_size; + vhost_add_used_and_signal(&net->dev, vq, head, len); + if (unlikely(vq_log)) + vhost_log_write(vq, vq_log, log, len); + total_len += len; + if (unlikely(total_len >= VHOST_NET_WEIGHT)) { + vhost_poll_queue(&vq->poll); + break; + } + } + + mutex_unlock(&vq->mutex); + unuse_mm(net->dev.mm); +} + +static void handle_tx_kick(struct work_struct *work) +{ + struct vhost_virtqueue *vq; + struct vhost_net *net; + vq = container_of(work, struct vhost_virtqueue, poll.work); + net = container_of(vq->dev, struct vhost_net, dev); + handle_tx(net); +} + +static void handle_rx_kick(struct work_struct *work) +{ + struct vhost_virtqueue *vq; + struct vhost_net *net; + vq = container_of(work, struct vhost_virtqueue, poll.work); + net = container_of(vq->dev, struct vhost_net, dev); + handle_rx(net); +} + +static void handle_tx_net(struct work_struct *work) +{ + struct vhost_net *net; + net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work); + handle_tx(net); +} + +static void handle_rx_net(struct work_struct *work) +{ + struct vhost_net *net; + net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work); + handle_rx(net); +} + +static int vhost_net_open(struct inode *inode, struct file *f) +{ + struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL); + int r; + if (!n) + return -ENOMEM; + n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick; + n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick; + r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX); + if (r < 0) { + kfree(n); + return r; + } + + vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT); + vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN); + n->tx_poll_state = VHOST_NET_POLL_DISABLED; + + f->private_data = n; + + return 0; +} + +static void vhost_net_disable_vq(struct vhost_net *n, + struct vhost_virtqueue *vq) +{ + if (!vq->private_data) + return; + if (vq == n->vqs + VHOST_NET_VQ_TX) { + tx_poll_stop(n); + n->tx_poll_state = VHOST_NET_POLL_DISABLED; + } else + vhost_poll_stop(n->poll + VHOST_NET_VQ_RX); +} + +static void vhost_net_enable_vq(struct vhost_net *n, + struct vhost_virtqueue *vq) +{ + struct socket *sock = vq->private_data; + if (!sock) + return; + if (vq == n->vqs + VHOST_NET_VQ_TX) { + n->tx_poll_state = VHOST_NET_POLL_STOPPED; + tx_poll_start(n, sock); + } else + vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file); +} + +static struct socket *vhost_net_stop_vq(struct vhost_net *n, + struct vhost_virtqueue *vq) +{ + struct socket *sock; + + mutex_lock(&vq->mutex); + sock = vq->private_data; + vhost_net_disable_vq(n, vq); + rcu_assign_pointer(vq->private_data, NULL); + mutex_unlock(&vq->mutex); + return sock; +} + +static void vhost_net_stop(struct vhost_net *n, struct socket **tx_sock, + struct socket **rx_sock) +{ + *tx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_TX); + *rx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_RX); +} + +static void vhost_net_flush_vq(struct vhost_net *n, int index) +{ + vhost_poll_flush(n->poll + index); + vhost_poll_flush(&n->dev.vqs[index].poll); +} + +static void vhost_net_flush(struct vhost_net *n) +{ + vhost_net_flush_vq(n, VHOST_NET_VQ_TX); + vhost_net_flush_vq(n, VHOST_NET_VQ_RX); +} + +static int vhost_net_release(struct inode *inode, struct file *f) +{ + struct vhost_net *n = f->private_data; + struct socket *tx_sock; + struct socket *rx_sock; + + vhost_net_stop(n, &tx_sock, &rx_sock); + vhost_net_flush(n); + vhost_dev_cleanup(&n->dev); + if (tx_sock) + fput(tx_sock->file); + if (rx_sock) + fput(rx_sock->file); + /* We do an extra flush before freeing memory, + * since jobs can re-queue themselves. */ + vhost_net_flush(n); + kfree(n); + return 0; +} + +static struct socket *get_raw_socket(int fd) +{ + struct { + struct sockaddr_ll sa; + char buf[MAX_ADDR_LEN]; + } uaddr; + int uaddr_len = sizeof uaddr, r; + struct socket *sock = sockfd_lookup(fd, &r); + if (!sock) + return ERR_PTR(-ENOTSOCK); + + /* Parameter checking */ + if (sock->sk->sk_type != SOCK_RAW) { + r = -ESOCKTNOSUPPORT; + goto err; + } + + r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, + &uaddr_len, 0); + if (r) + goto err; + + if (uaddr.sa.sll_family != AF_PACKET) { + r = -EPFNOSUPPORT; + goto err; + } + return sock; +err: + fput(sock->file); + return ERR_PTR(r); +} + +static struct socket *get_tun_socket(int fd) +{ + struct file *file = fget(fd); + struct socket *sock; + if (!file) + return ERR_PTR(-EBADF); + sock = tun_get_socket(file); + if (IS_ERR(sock)) + fput(file); + return sock; +} + +static struct socket *get_socket(int fd) +{ + struct socket *sock; + /* special case to disable backend */ + if (fd == -1) + return NULL; + sock = get_raw_socket(fd); + if (!IS_ERR(sock)) + return sock; + sock = get_tun_socket(fd); + if (!IS_ERR(sock)) + return sock; + return ERR_PTR(-ENOTSOCK); +} + +static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) +{ + struct socket *sock, *oldsock; + struct vhost_virtqueue *vq; + int r; + + mutex_lock(&n->dev.mutex); + r = vhost_dev_check_owner(&n->dev); + if (r) + goto err; + + if (index >= VHOST_NET_VQ_MAX) { + r = -ENOBUFS; + goto err; + } + vq = n->vqs + index; + mutex_lock(&vq->mutex); + + /* Verify that ring has been setup correctly. */ + if (!vhost_vq_access_ok(vq)) { + r = -EFAULT; + goto err; + } + sock = get_socket(fd); + if (IS_ERR(sock)) { + r = PTR_ERR(sock); + goto err; + } + + /* start polling new socket */ + oldsock = vq->private_data; + if (sock == oldsock) + goto done; + + vhost_net_disable_vq(n, vq); + rcu_assign_pointer(vq->private_data, sock); + vhost_net_enable_vq(n, vq); + mutex_unlock(&vq->mutex); +done: + if (oldsock) { + vhost_net_flush_vq(n, index); + fput(oldsock->file); + } +err: + mutex_unlock(&n->dev.mutex); + return r; +} + +static long vhost_net_reset_owner(struct vhost_net *n) +{ + struct socket *tx_sock = NULL; + struct socket *rx_sock = NULL; + long err; + mutex_lock(&n->dev.mutex); + err = vhost_dev_check_owner(&n->dev); + if (err) + goto done; + vhost_net_stop(n, &tx_sock, &rx_sock); + vhost_net_flush(n); + err = vhost_dev_reset_owner(&n->dev); +done: + mutex_unlock(&n->dev.mutex); + if (tx_sock) + fput(tx_sock->file); + if (rx_sock) + fput(rx_sock->file); + return err; +} + +static int vhost_net_set_features(struct vhost_net *n, u64 features) +{ + size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ? + sizeof(struct virtio_net_hdr) : 0; + int i; + mutex_lock(&n->dev.mutex); + if ((features & (1 << VHOST_F_LOG_ALL)) && + !vhost_log_access_ok(&n->dev)) { + mutex_unlock(&n->dev.mutex); + return -EFAULT; + } + n->dev.acked_features = features; + smp_wmb(); + for (i = 0; i < VHOST_NET_VQ_MAX; ++i) { + mutex_lock(&n->vqs[i].mutex); + n->vqs[i].hdr_size = hdr_size; + mutex_unlock(&n->vqs[i].mutex); + } + vhost_net_flush(n); + mutex_unlock(&n->dev.mutex); + return 0; +} + +static long vhost_net_ioctl(struct file *f, unsigned int ioctl, + unsigned long arg) +{ + struct vhost_net *n = f->private_data; + void __user *argp = (void __user *)arg; + u64 __user *featurep = argp; + struct vhost_vring_file backend; + u64 features; + int r; + switch (ioctl) { + case VHOST_NET_SET_BACKEND: + r = copy_from_user(&backend, argp, sizeof backend); + if (r < 0) + return r; + return vhost_net_set_backend(n, backend.index, backend.fd); + case VHOST_GET_FEATURES: + features = VHOST_FEATURES; + return copy_to_user(featurep, &features, sizeof features); + case VHOST_SET_FEATURES: + r = copy_from_user(&features, featurep, sizeof features); + if (r < 0) + return r; + if (features & ~VHOST_FEATURES) + return -EOPNOTSUPP; + return vhost_net_set_features(n, features); + case VHOST_RESET_OWNER: + return vhost_net_reset_owner(n); + default: + mutex_lock(&n->dev.mutex); + r = vhost_dev_ioctl(&n->dev, ioctl, arg); + vhost_net_flush(n); + mutex_unlock(&n->dev.mutex); + return r; + } +} + +#ifdef CONFIG_COMPAT +static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl, + unsigned long arg) +{ + return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg)); +} +#endif + +const static struct file_operations vhost_net_fops = { + .owner = THIS_MODULE, + .release = vhost_net_release, + .unlocked_ioctl = vhost_net_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vhost_net_compat_ioctl, +#endif + .open = vhost_net_open, +}; + +static struct miscdevice vhost_net_misc = { + VHOST_NET_MINOR, + "vhost-net", + &vhost_net_fops, +}; + +int vhost_net_init(void) +{ + int r = vhost_init(); + if (r) + goto err_init; + r = misc_register(&vhost_net_misc); + if (r) + goto err_reg; + return 0; +err_reg: + vhost_cleanup(); +err_init: + return r; + +} +module_init(vhost_net_init); + +void vhost_net_exit(void) +{ + misc_deregister(&vhost_net_misc); + vhost_cleanup(); +} +module_exit(vhost_net_exit); + +MODULE_VERSION("0.0.1"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Michael S. Tsirkin"); +MODULE_DESCRIPTION("Host kernel accelerator for virtio net"); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c new file mode 100644 index 000000000000..c8c25dbc5857 --- /dev/null +++ b/drivers/vhost/vhost.c @@ -0,0 +1,1098 @@ +/* Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin + * + * Inspiration, some code, and most witty comments come from + * Documentation/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * Generic code for virtio server in host kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "vhost.h" + +enum { + VHOST_MEMORY_MAX_NREGIONS = 64, + VHOST_MEMORY_F_LOG = 0x1, +}; + +static struct workqueue_struct *vhost_workqueue; + +static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, + poll_table *pt) +{ + struct vhost_poll *poll; + poll = container_of(pt, struct vhost_poll, table); + + poll->wqh = wqh; + add_wait_queue(wqh, &poll->wait); +} + +static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync, + void *key) +{ + struct vhost_poll *poll; + poll = container_of(wait, struct vhost_poll, wait); + if (!((unsigned long)key & poll->mask)) + return 0; + + queue_work(vhost_workqueue, &poll->work); + return 0; +} + +/* Init poll structure */ +void vhost_poll_init(struct vhost_poll *poll, work_func_t func, + unsigned long mask) +{ + INIT_WORK(&poll->work, func); + init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup); + init_poll_funcptr(&poll->table, vhost_poll_func); + poll->mask = mask; +} + +/* Start polling a file. We add ourselves to file's wait queue. The caller must + * keep a reference to a file until after vhost_poll_stop is called. */ +void vhost_poll_start(struct vhost_poll *poll, struct file *file) +{ + unsigned long mask; + mask = file->f_op->poll(file, &poll->table); + if (mask) + vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); +} + +/* Stop polling a file. After this function returns, it becomes safe to drop the + * file reference. You must also flush afterwards. */ +void vhost_poll_stop(struct vhost_poll *poll) +{ + remove_wait_queue(poll->wqh, &poll->wait); +} + +/* Flush any work that has been scheduled. When calling this, don't hold any + * locks that are also used by the callback. */ +void vhost_poll_flush(struct vhost_poll *poll) +{ + flush_work(&poll->work); +} + +void vhost_poll_queue(struct vhost_poll *poll) +{ + queue_work(vhost_workqueue, &poll->work); +} + +static void vhost_vq_reset(struct vhost_dev *dev, + struct vhost_virtqueue *vq) +{ + vq->num = 1; + vq->desc = NULL; + vq->avail = NULL; + vq->used = NULL; + vq->last_avail_idx = 0; + vq->avail_idx = 0; + vq->last_used_idx = 0; + vq->used_flags = 0; + vq->used_flags = 0; + vq->log_used = false; + vq->log_addr = -1ull; + vq->hdr_size = 0; + vq->private_data = NULL; + vq->log_base = NULL; + vq->error_ctx = NULL; + vq->error = NULL; + vq->kick = NULL; + vq->call_ctx = NULL; + vq->call = NULL; +} + +long vhost_dev_init(struct vhost_dev *dev, + struct vhost_virtqueue *vqs, int nvqs) +{ + int i; + dev->vqs = vqs; + dev->nvqs = nvqs; + mutex_init(&dev->mutex); + dev->log_ctx = NULL; + dev->log_file = NULL; + dev->memory = NULL; + dev->mm = NULL; + + for (i = 0; i < dev->nvqs; ++i) { + dev->vqs[i].dev = dev; + mutex_init(&dev->vqs[i].mutex); + vhost_vq_reset(dev, dev->vqs + i); + if (dev->vqs[i].handle_kick) + vhost_poll_init(&dev->vqs[i].poll, + dev->vqs[i].handle_kick, + POLLIN); + } + return 0; +} + +/* Caller should have device mutex */ +long vhost_dev_check_owner(struct vhost_dev *dev) +{ + /* Are you the owner? If not, I don't think you mean to do that */ + return dev->mm == current->mm ? 0 : -EPERM; +} + +/* Caller should have device mutex */ +static long vhost_dev_set_owner(struct vhost_dev *dev) +{ + /* Is there an owner already? */ + if (dev->mm) + return -EBUSY; + /* No owner, become one */ + dev->mm = get_task_mm(current); + return 0; +} + +/* Caller should have device mutex */ +long vhost_dev_reset_owner(struct vhost_dev *dev) +{ + struct vhost_memory *memory; + + /* Restore memory to default empty mapping. */ + memory = kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL); + if (!memory) + return -ENOMEM; + + vhost_dev_cleanup(dev); + + memory->nregions = 0; + dev->memory = memory; + return 0; +} + +/* Caller should have device mutex */ +void vhost_dev_cleanup(struct vhost_dev *dev) +{ + int i; + for (i = 0; i < dev->nvqs; ++i) { + if (dev->vqs[i].kick && dev->vqs[i].handle_kick) { + vhost_poll_stop(&dev->vqs[i].poll); + vhost_poll_flush(&dev->vqs[i].poll); + } + if (dev->vqs[i].error_ctx) + eventfd_ctx_put(dev->vqs[i].error_ctx); + if (dev->vqs[i].error) + fput(dev->vqs[i].error); + if (dev->vqs[i].kick) + fput(dev->vqs[i].kick); + if (dev->vqs[i].call_ctx) + eventfd_ctx_put(dev->vqs[i].call_ctx); + if (dev->vqs[i].call) + fput(dev->vqs[i].call); + vhost_vq_reset(dev, dev->vqs + i); + } + if (dev->log_ctx) + eventfd_ctx_put(dev->log_ctx); + dev->log_ctx = NULL; + if (dev->log_file) + fput(dev->log_file); + dev->log_file = NULL; + /* No one will access memory at this point */ + kfree(dev->memory); + dev->memory = NULL; + if (dev->mm) + mmput(dev->mm); + dev->mm = NULL; +} + +static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) +{ + u64 a = addr / VHOST_PAGE_SIZE / 8; + /* Make sure 64 bit math will not overflow. */ + if (a > ULONG_MAX - (unsigned long)log_base || + a + (unsigned long)log_base > ULONG_MAX) + return -EFAULT; + + return access_ok(VERIFY_WRITE, log_base + a, + (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8); +} + +/* Caller should have vq mutex and device mutex. */ +static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem, + int log_all) +{ + int i; + for (i = 0; i < mem->nregions; ++i) { + struct vhost_memory_region *m = mem->regions + i; + unsigned long a = m->userspace_addr; + if (m->memory_size > ULONG_MAX) + return 0; + else if (!access_ok(VERIFY_WRITE, (void __user *)a, + m->memory_size)) + return 0; + else if (log_all && !log_access_ok(log_base, + m->guest_phys_addr, + m->memory_size)) + return 0; + } + return 1; +} + +/* Can we switch to this memory table? */ +/* Caller should have device mutex but not vq mutex */ +static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, + int log_all) +{ + int i; + for (i = 0; i < d->nvqs; ++i) { + int ok; + mutex_lock(&d->vqs[i].mutex); + /* If ring is inactive, will check when it's enabled. */ + if (d->vqs[i].private_data) + ok = vq_memory_access_ok(d->vqs[i].log_base, mem, + log_all); + else + ok = 1; + mutex_unlock(&d->vqs[i].mutex); + if (!ok) + return 0; + } + return 1; +} + +static int vq_access_ok(unsigned int num, + struct vring_desc __user *desc, + struct vring_avail __user *avail, + struct vring_used __user *used) +{ + return access_ok(VERIFY_READ, desc, num * sizeof *desc) && + access_ok(VERIFY_READ, avail, + sizeof *avail + num * sizeof *avail->ring) && + access_ok(VERIFY_WRITE, used, + sizeof *used + num * sizeof *used->ring); +} + +/* Can we log writes? */ +/* Caller should have device mutex but not vq mutex */ +int vhost_log_access_ok(struct vhost_dev *dev) +{ + return memory_access_ok(dev, dev->memory, 1); +} + +/* Verify access for write logging. */ +/* Caller should have vq mutex and device mutex */ +static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base) +{ + return vq_memory_access_ok(log_base, vq->dev->memory, + vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) && + (!vq->log_used || log_access_ok(log_base, vq->log_addr, + sizeof *vq->used + + vq->num * sizeof *vq->used->ring)); +} + +/* Can we start vq? */ +/* Caller should have vq mutex and device mutex */ +int vhost_vq_access_ok(struct vhost_virtqueue *vq) +{ + return vq_access_ok(vq->num, vq->desc, vq->avail, vq->used) && + vq_log_access_ok(vq, vq->log_base); +} + +static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) +{ + struct vhost_memory mem, *newmem, *oldmem; + unsigned long size = offsetof(struct vhost_memory, regions); + long r; + r = copy_from_user(&mem, m, size); + if (r) + return r; + if (mem.padding) + return -EOPNOTSUPP; + if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS) + return -E2BIG; + newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL); + if (!newmem) + return -ENOMEM; + + memcpy(newmem, &mem, size); + r = copy_from_user(newmem->regions, m->regions, + mem.nregions * sizeof *m->regions); + if (r) { + kfree(newmem); + return r; + } + + if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) + return -EFAULT; + oldmem = d->memory; + rcu_assign_pointer(d->memory, newmem); + synchronize_rcu(); + kfree(oldmem); + return 0; +} + +static int init_used(struct vhost_virtqueue *vq, + struct vring_used __user *used) +{ + int r = put_user(vq->used_flags, &used->flags); + if (r) + return r; + return get_user(vq->last_used_idx, &used->idx); +} + +static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp) +{ + struct file *eventfp, *filep = NULL, + *pollstart = NULL, *pollstop = NULL; + struct eventfd_ctx *ctx = NULL; + u32 __user *idxp = argp; + struct vhost_virtqueue *vq; + struct vhost_vring_state s; + struct vhost_vring_file f; + struct vhost_vring_addr a; + u32 idx; + long r; + + r = get_user(idx, idxp); + if (r < 0) + return r; + if (idx > d->nvqs) + return -ENOBUFS; + + vq = d->vqs + idx; + + mutex_lock(&vq->mutex); + + switch (ioctl) { + case VHOST_SET_VRING_NUM: + /* Resizing ring with an active backend? + * You don't want to do that. */ + if (vq->private_data) { + r = -EBUSY; + break; + } + r = copy_from_user(&s, argp, sizeof s); + if (r < 0) + break; + if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) { + r = -EINVAL; + break; + } + vq->num = s.num; + break; + case VHOST_SET_VRING_BASE: + /* Moving base with an active backend? + * You don't want to do that. */ + if (vq->private_data) { + r = -EBUSY; + break; + } + r = copy_from_user(&s, argp, sizeof s); + if (r < 0) + break; + if (s.num > 0xffff) { + r = -EINVAL; + break; + } + vq->last_avail_idx = s.num; + /* Forget the cached index value. */ + vq->avail_idx = vq->last_avail_idx; + break; + case VHOST_GET_VRING_BASE: + s.index = idx; + s.num = vq->last_avail_idx; + r = copy_to_user(argp, &s, sizeof s); + break; + case VHOST_SET_VRING_ADDR: + r = copy_from_user(&a, argp, sizeof a); + if (r < 0) + break; + if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) { + r = -EOPNOTSUPP; + break; + } + /* For 32bit, verify that the top 32bits of the user + data are set to zero. */ + if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr || + (u64)(unsigned long)a.used_user_addr != a.used_user_addr || + (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) { + r = -EFAULT; + break; + } + if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) || + (a.used_user_addr & (sizeof *vq->used->ring - 1)) || + (a.log_guest_addr & (sizeof *vq->used->ring - 1))) { + r = -EINVAL; + break; + } + + /* We only verify access here if backend is configured. + * If it is not, we don't as size might not have been setup. + * We will verify when backend is configured. */ + if (vq->private_data) { + if (!vq_access_ok(vq->num, + (void __user *)(unsigned long)a.desc_user_addr, + (void __user *)(unsigned long)a.avail_user_addr, + (void __user *)(unsigned long)a.used_user_addr)) { + r = -EINVAL; + break; + } + + /* Also validate log access for used ring if enabled. */ + if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) && + !log_access_ok(vq->log_base, a.log_guest_addr, + sizeof *vq->used + + vq->num * sizeof *vq->used->ring)) { + r = -EINVAL; + break; + } + } + + r = init_used(vq, (struct vring_used __user *)(unsigned long) + a.used_user_addr); + if (r) + break; + vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG)); + vq->desc = (void __user *)(unsigned long)a.desc_user_addr; + vq->avail = (void __user *)(unsigned long)a.avail_user_addr; + vq->log_addr = a.log_guest_addr; + vq->used = (void __user *)(unsigned long)a.used_user_addr; + break; + case VHOST_SET_VRING_KICK: + r = copy_from_user(&f, argp, sizeof f); + if (r < 0) + break; + eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); + if (IS_ERR(eventfp)) + return PTR_ERR(eventfp); + if (eventfp != vq->kick) { + pollstop = filep = vq->kick; + pollstart = vq->kick = eventfp; + } else + filep = eventfp; + break; + case VHOST_SET_VRING_CALL: + r = copy_from_user(&f, argp, sizeof f); + if (r < 0) + break; + eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); + if (IS_ERR(eventfp)) + return PTR_ERR(eventfp); + if (eventfp != vq->call) { + filep = vq->call; + ctx = vq->call_ctx; + vq->call = eventfp; + vq->call_ctx = eventfp ? + eventfd_ctx_fileget(eventfp) : NULL; + } else + filep = eventfp; + break; + case VHOST_SET_VRING_ERR: + r = copy_from_user(&f, argp, sizeof f); + if (r < 0) + break; + eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd); + if (IS_ERR(eventfp)) + return PTR_ERR(eventfp); + if (eventfp != vq->error) { + filep = vq->error; + vq->error = eventfp; + ctx = vq->error_ctx; + vq->error_ctx = eventfp ? + eventfd_ctx_fileget(eventfp) : NULL; + } else + filep = eventfp; + break; + default: + r = -ENOIOCTLCMD; + } + + if (pollstop && vq->handle_kick) + vhost_poll_stop(&vq->poll); + + if (ctx) + eventfd_ctx_put(ctx); + if (filep) + fput(filep); + + if (pollstart && vq->handle_kick) + vhost_poll_start(&vq->poll, vq->kick); + + mutex_unlock(&vq->mutex); + + if (pollstop && vq->handle_kick) + vhost_poll_flush(&vq->poll); + return r; +} + +/* Caller must have device mutex */ +long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct file *eventfp, *filep = NULL; + struct eventfd_ctx *ctx = NULL; + u64 p; + long r; + int i, fd; + + /* If you are not the owner, you can become one */ + if (ioctl == VHOST_SET_OWNER) { + r = vhost_dev_set_owner(d); + goto done; + } + + /* You must be the owner to do anything else */ + r = vhost_dev_check_owner(d); + if (r) + goto done; + + switch (ioctl) { + case VHOST_SET_MEM_TABLE: + r = vhost_set_memory(d, argp); + break; + case VHOST_SET_LOG_BASE: + r = copy_from_user(&p, argp, sizeof p); + if (r < 0) + break; + if ((u64)(unsigned long)p != p) { + r = -EFAULT; + break; + } + for (i = 0; i < d->nvqs; ++i) { + struct vhost_virtqueue *vq; + void __user *base = (void __user *)(unsigned long)p; + vq = d->vqs + i; + mutex_lock(&vq->mutex); + /* If ring is inactive, will check when it's enabled. */ + if (vq->private_data && !vq_log_access_ok(vq, base)) + r = -EFAULT; + else + vq->log_base = base; + mutex_unlock(&vq->mutex); + } + break; + case VHOST_SET_LOG_FD: + r = get_user(fd, (int __user *)argp); + if (r < 0) + break; + eventfp = fd == -1 ? NULL : eventfd_fget(fd); + if (IS_ERR(eventfp)) { + r = PTR_ERR(eventfp); + break; + } + if (eventfp != d->log_file) { + filep = d->log_file; + ctx = d->log_ctx; + d->log_ctx = eventfp ? + eventfd_ctx_fileget(eventfp) : NULL; + } else + filep = eventfp; + for (i = 0; i < d->nvqs; ++i) { + mutex_lock(&d->vqs[i].mutex); + d->vqs[i].log_ctx = d->log_ctx; + mutex_unlock(&d->vqs[i].mutex); + } + if (ctx) + eventfd_ctx_put(ctx); + if (filep) + fput(filep); + break; + default: + r = vhost_set_vring(d, ioctl, argp); + break; + } +done: + return r; +} + +static const struct vhost_memory_region *find_region(struct vhost_memory *mem, + __u64 addr, __u32 len) +{ + struct vhost_memory_region *reg; + int i; + /* linear search is not brilliant, but we really have on the order of 6 + * regions in practice */ + for (i = 0; i < mem->nregions; ++i) { + reg = mem->regions + i; + if (reg->guest_phys_addr <= addr && + reg->guest_phys_addr + reg->memory_size - 1 >= addr) + return reg; + } + return NULL; +} + +/* TODO: This is really inefficient. We need something like get_user() + * (instruction directly accesses the data, with an exception table entry + * returning -EFAULT). See Documentation/x86/exception-tables.txt. + */ +static int set_bit_to_user(int nr, void __user *addr) +{ + unsigned long log = (unsigned long)addr; + struct page *page; + void *base; + int bit = nr + (log % PAGE_SIZE) * 8; + int r; + r = get_user_pages_fast(log, 1, 1, &page); + if (r) + return r; + base = kmap_atomic(page, KM_USER0); + set_bit(bit, base); + kunmap_atomic(base, KM_USER0); + set_page_dirty_lock(page); + put_page(page); + return 0; +} + +static int log_write(void __user *log_base, + u64 write_address, u64 write_length) +{ + int r; + if (!write_length) + return 0; + write_address /= VHOST_PAGE_SIZE; + for (;;) { + u64 base = (u64)(unsigned long)log_base; + u64 log = base + write_address / 8; + int bit = write_address % 8; + if ((u64)(unsigned long)log != log) + return -EFAULT; + r = set_bit_to_user(bit, (void __user *)(unsigned long)log); + if (r < 0) + return r; + if (write_length <= VHOST_PAGE_SIZE) + break; + write_length -= VHOST_PAGE_SIZE; + write_address += VHOST_PAGE_SIZE; + } + return r; +} + +int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, + unsigned int log_num, u64 len) +{ + int i, r; + + /* Make sure data written is seen before log. */ + wmb(); + for (i = 0; i < log_num; ++i) { + u64 l = min(log[i].len, len); + r = log_write(vq->log_base, log[i].addr, l); + if (r < 0) + return r; + len -= l; + if (!len) + return 0; + } + if (vq->log_ctx) + eventfd_signal(vq->log_ctx, 1); + /* Length written exceeds what we have stored. This is a bug. */ + BUG(); + return 0; +} + +int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, + struct iovec iov[], int iov_size) +{ + const struct vhost_memory_region *reg; + struct vhost_memory *mem; + struct iovec *_iov; + u64 s = 0; + int ret = 0; + + rcu_read_lock(); + + mem = rcu_dereference(dev->memory); + while ((u64)len > s) { + u64 size; + if (ret >= iov_size) { + ret = -ENOBUFS; + break; + } + reg = find_region(mem, addr, len); + if (!reg) { + ret = -EFAULT; + break; + } + _iov = iov + ret; + size = reg->memory_size - addr + reg->guest_phys_addr; + _iov->iov_len = min((u64)len, size); + _iov->iov_base = (void *)(unsigned long) + (reg->userspace_addr + addr - reg->guest_phys_addr); + s += size; + addr += size; + ++ret; + } + + rcu_read_unlock(); + return ret; +} + +/* Each buffer in the virtqueues is actually a chain of descriptors. This + * function returns the next descriptor in the chain, + * or -1U if we're at the end. */ +static unsigned next_desc(struct vring_desc *desc) +{ + unsigned int next; + + /* If this descriptor says it doesn't chain, we're done. */ + if (!(desc->flags & VRING_DESC_F_NEXT)) + return -1U; + + /* Check they're not leading us off end of descriptors. */ + next = desc->next; + /* Make sure compiler knows to grab that: we don't want it changing! */ + /* We will use the result as an index in an array, so most + * architectures only need a compiler barrier here. */ + read_barrier_depends(); + + return next; +} + +static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num, + struct vring_desc *indirect) +{ + struct vring_desc desc; + unsigned int i = 0, count, found = 0; + int ret; + + /* Sanity check */ + if (indirect->len % sizeof desc) { + vq_err(vq, "Invalid length in indirect descriptor: " + "len 0x%llx not multiple of 0x%zx\n", + (unsigned long long)indirect->len, + sizeof desc); + return -EINVAL; + } + + ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect, + ARRAY_SIZE(vq->indirect)); + if (ret < 0) { + vq_err(vq, "Translation failure %d in indirect.\n", ret); + return ret; + } + + /* We will use the result as an address to read from, so most + * architectures only need a compiler barrier here. */ + read_barrier_depends(); + + count = indirect->len / sizeof desc; + /* Buffers are chained via a 16 bit next field, so + * we can have at most 2^16 of these. */ + if (count > USHORT_MAX + 1) { + vq_err(vq, "Indirect buffer length too big: %d\n", + indirect->len); + return -E2BIG; + } + + do { + unsigned iov_count = *in_num + *out_num; + if (++found > count) { + vq_err(vq, "Loop detected: last one at %u " + "indirect size %u\n", + i, count); + return -EINVAL; + } + if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect, + sizeof desc)) { + vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", + i, (size_t)indirect->addr + i * sizeof desc); + return -EINVAL; + } + if (desc.flags & VRING_DESC_F_INDIRECT) { + vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n", + i, (size_t)indirect->addr + i * sizeof desc); + return -EINVAL; + } + + ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, + iov_size - iov_count); + if (ret < 0) { + vq_err(vq, "Translation failure %d indirect idx %d\n", + ret, i); + return ret; + } + /* If this is an input descriptor, increment that count. */ + if (desc.flags & VRING_DESC_F_WRITE) { + *in_num += ret; + if (unlikely(log)) { + log[*log_num].addr = desc.addr; + log[*log_num].len = desc.len; + ++*log_num; + } + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (*in_num) { + vq_err(vq, "Indirect descriptor " + "has out after in: idx %d\n", i); + return -EINVAL; + } + *out_num += ret; + } + } while ((i = next_desc(&desc)) != -1); + return 0; +} + +/* This looks in the virtqueue and for the first available buffer, and converts + * it to an iovec for convenient access. Since descriptors consist of some + * number of output then some number of input descriptors, it's actually two + * iovecs, but we pack them into one and note how many of each there were. + * + * This function returns the descriptor number found, or vq->num (which + * is never a valid descriptor number) if none was found. */ +unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num) +{ + struct vring_desc desc; + unsigned int i, head, found = 0; + u16 last_avail_idx; + int ret; + + /* Check it isn't doing very strange things with descriptor numbers. */ + last_avail_idx = vq->last_avail_idx; + if (get_user(vq->avail_idx, &vq->avail->idx)) { + vq_err(vq, "Failed to access avail idx at %p\n", + &vq->avail->idx); + return vq->num; + } + + if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { + vq_err(vq, "Guest moved used index from %u to %u", + last_avail_idx, vq->avail_idx); + return vq->num; + } + + /* If there's nothing new since last we looked, return invalid. */ + if (vq->avail_idx == last_avail_idx) + return vq->num; + + /* Only get avail ring entries after they have been exposed by guest. */ + rmb(); + + /* Grab the next descriptor number they're advertising, and increment + * the index we've seen. */ + if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) { + vq_err(vq, "Failed to read head: idx %d address %p\n", + last_avail_idx, + &vq->avail->ring[last_avail_idx % vq->num]); + return vq->num; + } + + /* If their number is silly, that's an error. */ + if (head >= vq->num) { + vq_err(vq, "Guest says index %u > %u is available", + head, vq->num); + return vq->num; + } + + /* When we start there are none of either input nor output. */ + *out_num = *in_num = 0; + if (unlikely(log)) + *log_num = 0; + + i = head; + do { + unsigned iov_count = *in_num + *out_num; + if (i >= vq->num) { + vq_err(vq, "Desc index is %u > %u, head = %u", + i, vq->num, head); + return vq->num; + } + if (++found > vq->num) { + vq_err(vq, "Loop detected: last one at %u " + "vq size %u head %u\n", + i, vq->num, head); + return vq->num; + } + ret = copy_from_user(&desc, vq->desc + i, sizeof desc); + if (ret) { + vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", + i, vq->desc + i); + return vq->num; + } + if (desc.flags & VRING_DESC_F_INDIRECT) { + ret = get_indirect(dev, vq, iov, iov_size, + out_num, in_num, + log, log_num, &desc); + if (ret < 0) { + vq_err(vq, "Failure detected " + "in indirect descriptor at idx %d\n", i); + return vq->num; + } + continue; + } + + ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count, + iov_size - iov_count); + if (ret < 0) { + vq_err(vq, "Translation failure %d descriptor idx %d\n", + ret, i); + return vq->num; + } + if (desc.flags & VRING_DESC_F_WRITE) { + /* If this is an input descriptor, + * increment that count. */ + *in_num += ret; + if (unlikely(log)) { + log[*log_num].addr = desc.addr; + log[*log_num].len = desc.len; + ++*log_num; + } + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (*in_num) { + vq_err(vq, "Descriptor has out after in: " + "idx %d\n", i); + return vq->num; + } + *out_num += ret; + } + } while ((i = next_desc(&desc)) != -1); + + /* On success, increment avail index. */ + vq->last_avail_idx++; + return head; +} + +/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */ +void vhost_discard_vq_desc(struct vhost_virtqueue *vq) +{ + vq->last_avail_idx--; +} + +/* After we've used one of their buffers, we tell them about it. We'll then + * want to notify the guest, using eventfd. */ +int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len) +{ + struct vring_used_elem *used; + + /* The virtqueue contains a ring of used buffers. Get a pointer to the + * next entry in that used ring. */ + used = &vq->used->ring[vq->last_used_idx % vq->num]; + if (put_user(head, &used->id)) { + vq_err(vq, "Failed to write used id"); + return -EFAULT; + } + if (put_user(len, &used->len)) { + vq_err(vq, "Failed to write used len"); + return -EFAULT; + } + /* Make sure buffer is written before we update index. */ + wmb(); + if (put_user(vq->last_used_idx + 1, &vq->used->idx)) { + vq_err(vq, "Failed to increment used idx"); + return -EFAULT; + } + if (unlikely(vq->log_used)) { + /* Make sure data is seen before log. */ + wmb(); + log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring * + (vq->last_used_idx % vq->num), + sizeof *vq->used->ring); + log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring); + if (vq->log_ctx) + eventfd_signal(vq->log_ctx, 1); + } + vq->last_used_idx++; + return 0; +} + +/* This actually signals the guest, using eventfd. */ +void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq) +{ + __u16 flags = 0; + if (get_user(flags, &vq->avail->flags)) { + vq_err(vq, "Failed to get flags"); + return; + } + + /* If they don't want an interrupt, don't signal, unless empty. */ + if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && + (vq->avail_idx != vq->last_avail_idx || + !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY))) + return; + + /* Signal the Guest tell them we used something up. */ + if (vq->call_ctx) + eventfd_signal(vq->call_ctx, 1); +} + +/* And here's the combo meal deal. Supersize me! */ +void vhost_add_used_and_signal(struct vhost_dev *dev, + struct vhost_virtqueue *vq, + unsigned int head, int len) +{ + vhost_add_used(vq, head, len); + vhost_signal(dev, vq); +} + +/* OK, now we need to know about added descriptors. */ +bool vhost_enable_notify(struct vhost_virtqueue *vq) +{ + u16 avail_idx; + int r; + if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY)) + return false; + vq->used_flags &= ~VRING_USED_F_NO_NOTIFY; + r = put_user(vq->used_flags, &vq->used->flags); + if (r) { + vq_err(vq, "Failed to enable notification at %p: %d\n", + &vq->used->flags, r); + return false; + } + /* They could have slipped one in as we were doing that: make + * sure it's written, then check again. */ + mb(); + r = get_user(avail_idx, &vq->avail->idx); + if (r) { + vq_err(vq, "Failed to check avail idx at %p: %d\n", + &vq->avail->idx, r); + return false; + } + + return avail_idx != vq->last_avail_idx; +} + +/* We don't need to be notified again. */ +void vhost_disable_notify(struct vhost_virtqueue *vq) +{ + int r; + if (vq->used_flags & VRING_USED_F_NO_NOTIFY) + return; + vq->used_flags |= VRING_USED_F_NO_NOTIFY; + r = put_user(vq->used_flags, &vq->used->flags); + if (r) + vq_err(vq, "Failed to enable notification at %p: %d\n", + &vq->used->flags, r); +} + +int vhost_init(void) +{ + vhost_workqueue = create_singlethread_workqueue("vhost"); + if (!vhost_workqueue) + return -ENOMEM; + return 0; +} + +void vhost_cleanup(void) +{ + destroy_workqueue(vhost_workqueue); +} diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h new file mode 100644 index 000000000000..44591ba9b07a --- /dev/null +++ b/drivers/vhost/vhost.h @@ -0,0 +1,161 @@ +#ifndef _VHOST_H +#define _VHOST_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct vhost_device; + +enum { + /* Enough place for all fragments, head, and virtio net header. */ + VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2, +}; + +/* Poll a file (eventfd or socket) */ +/* Note: there's nothing vhost specific about this structure. */ +struct vhost_poll { + poll_table table; + wait_queue_head_t *wqh; + wait_queue_t wait; + /* struct which will handle all actual work. */ + struct work_struct work; + unsigned long mask; +}; + +void vhost_poll_init(struct vhost_poll *poll, work_func_t func, + unsigned long mask); +void vhost_poll_start(struct vhost_poll *poll, struct file *file); +void vhost_poll_stop(struct vhost_poll *poll); +void vhost_poll_flush(struct vhost_poll *poll); +void vhost_poll_queue(struct vhost_poll *poll); + +struct vhost_log { + u64 addr; + u64 len; +}; + +/* The virtqueue structure describes a queue attached to a device. */ +struct vhost_virtqueue { + struct vhost_dev *dev; + + /* The actual ring of buffers. */ + struct mutex mutex; + unsigned int num; + struct vring_desc __user *desc; + struct vring_avail __user *avail; + struct vring_used __user *used; + struct file *kick; + struct file *call; + struct file *error; + struct eventfd_ctx *call_ctx; + struct eventfd_ctx *error_ctx; + struct eventfd_ctx *log_ctx; + + struct vhost_poll poll; + + /* The routine to call when the Guest pings us, or timeout. */ + work_func_t handle_kick; + + /* Last available index we saw. */ + u16 last_avail_idx; + + /* Caches available index value from user. */ + u16 avail_idx; + + /* Last index we used. */ + u16 last_used_idx; + + /* Used flags */ + u16 used_flags; + + /* Log writes to used structure. */ + bool log_used; + u64 log_addr; + + struct iovec indirect[VHOST_NET_MAX_SG]; + struct iovec iov[VHOST_NET_MAX_SG]; + struct iovec hdr[VHOST_NET_MAX_SG]; + size_t hdr_size; + /* We use a kind of RCU to access private pointer. + * All readers access it from workqueue, which makes it possible to + * flush the workqueue instead of synchronize_rcu. Therefore readers do + * not need to call rcu_read_lock/rcu_read_unlock: the beginning of + * work item execution acts instead of rcu_read_lock() and the end of + * work item execution acts instead of rcu_read_lock(). + * Writers use virtqueue mutex. */ + void *private_data; + /* Log write descriptors */ + void __user *log_base; + struct vhost_log log[VHOST_NET_MAX_SG]; +}; + +struct vhost_dev { + /* Readers use RCU to access memory table pointer + * log base pointer and features. + * Writers use mutex below.*/ + struct vhost_memory *memory; + struct mm_struct *mm; + struct mutex mutex; + unsigned acked_features; + struct vhost_virtqueue *vqs; + int nvqs; + struct file *log_file; + struct eventfd_ctx *log_ctx; +}; + +long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs); +long vhost_dev_check_owner(struct vhost_dev *); +long vhost_dev_reset_owner(struct vhost_dev *); +void vhost_dev_cleanup(struct vhost_dev *); +long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg); +int vhost_vq_access_ok(struct vhost_virtqueue *vq); +int vhost_log_access_ok(struct vhost_dev *); + +unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, + struct iovec iov[], unsigned int iov_count, + unsigned int *out_num, unsigned int *in_num, + struct vhost_log *log, unsigned int *log_num); +void vhost_discard_vq_desc(struct vhost_virtqueue *); + +int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); +void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *); +void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *, + unsigned int head, int len); +void vhost_disable_notify(struct vhost_virtqueue *); +bool vhost_enable_notify(struct vhost_virtqueue *); + +int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, + unsigned int log_num, u64 len); + +int vhost_init(void); +void vhost_cleanup(void); + +#define vq_err(vq, fmt, ...) do { \ + pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ + if ((vq)->error_ctx) \ + eventfd_signal((vq)->error_ctx, 1);\ + } while (0) + +enum { + VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | + (1 << VIRTIO_RING_F_INDIRECT_DESC) | + (1 << VHOST_F_LOG_ALL) | + (1 << VHOST_NET_F_VIRTIO_NET_HDR), +}; + +static inline int vhost_has_feature(struct vhost_dev *dev, int bit) +{ + unsigned acked_features = rcu_dereference(dev->acked_features); + return acked_features & (1 << bit); +} + +#endif diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 756f831cbdd5..d93080748a91 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -362,6 +362,7 @@ unifdef-y += uio.h unifdef-y += unistd.h unifdef-y += usbdevice_fs.h unifdef-y += utsname.h +unifdef-y += vhost.h unifdef-y += videodev2.h unifdef-y += videodev.h unifdef-y += virtio_config.h diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index adaf3c15e449..8b5f7cc0fba6 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -30,6 +30,7 @@ #define HPET_MINOR 228 #define FUSE_MINOR 229 #define KVM_MINOR 232 +#define VHOST_NET_MINOR 233 #define MISC_DYNAMIC_MINOR 255 struct device; diff --git a/include/linux/vhost.h b/include/linux/vhost.h new file mode 100644 index 000000000000..e847f1e30756 --- /dev/null +++ b/include/linux/vhost.h @@ -0,0 +1,130 @@ +#ifndef _LINUX_VHOST_H +#define _LINUX_VHOST_H +/* Userspace interface for in-kernel virtio accelerators. */ + +/* vhost is used to reduce the number of system calls involved in virtio. + * + * Existing virtio net code is used in the guest without modification. + * + * This header includes interface used by userspace hypervisor for + * device configuration. + */ + +#include +#include +#include +#include +#include + +struct vhost_vring_state { + unsigned int index; + unsigned int num; +}; + +struct vhost_vring_file { + unsigned int index; + int fd; /* Pass -1 to unbind from file. */ + +}; + +struct vhost_vring_addr { + unsigned int index; + /* Option flags. */ + unsigned int flags; + /* Flag values: */ + /* Whether log address is valid. If set enables logging. */ +#define VHOST_VRING_F_LOG 0 + + /* Start of array of descriptors (virtually contiguous) */ + __u64 desc_user_addr; + /* Used structure address. Must be 32 bit aligned */ + __u64 used_user_addr; + /* Available structure address. Must be 16 bit aligned */ + __u64 avail_user_addr; + /* Logging support. */ + /* Log writes to used structure, at offset calculated from specified + * address. Address must be 32 bit aligned. */ + __u64 log_guest_addr; +}; + +struct vhost_memory_region { + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ + __u64 userspace_addr; + __u64 flags_padding; /* No flags are currently specified. */ +}; + +/* All region addresses and sizes must be 4K aligned. */ +#define VHOST_PAGE_SIZE 0x1000 + +struct vhost_memory { + __u32 nregions; + __u32 padding; + struct vhost_memory_region regions[0]; +}; + +/* ioctls */ + +#define VHOST_VIRTIO 0xAF + +/* Features bitmask for forward compatibility. Transport bits are used for + * vhost specific features. */ +#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64) +#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64) + +/* Set current process as the (exclusive) owner of this file descriptor. This + * must be called before any other vhost command. Further calls to + * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */ +#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01) +/* Give up ownership, and reset the device to default values. + * Allows subsequent call to VHOST_OWNER_SET to succeed. */ +#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02) + +/* Set up/modify memory layout */ +#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory) + +/* Write logging setup. */ +/* Memory writes can optionally be logged by setting bit at an offset + * (calculated from the physical address) from specified log base. + * The bit is set using an atomic 32 bit operation. */ +/* Set base address for logging. */ +#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) +/* Specify an eventfd file descriptor to signal on log write. */ +#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) + +/* Ring setup. */ +/* Set number of descriptors in ring. This parameter can not + * be modified while ring is running (bound to a device). */ +#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state) +/* Set addresses for the ring. */ +#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr) +/* Base value where queue looks for available descriptors */ +#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state) +/* Get accessor: reads index, writes value in num */ +#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) + +/* The following ioctls use eventfd file descriptors to signal and poll + * for events. */ + +/* Set eventfd to poll for added buffers */ +#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file) +/* Set eventfd to signal when buffers have beed used */ +#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file) +/* Set eventfd to signal an error */ +#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file) + +/* VHOST_NET specific defines */ + +/* Attach virtio net ring to a raw socket, or tap device. + * The socket must be already bound to an ethernet device, this device will be + * used for transmit. Pass fd -1 to unbind from the socket and the transmit + * device. This can be used to stop the ring (e.g. for migration). */ +#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file) + +/* Feature bits */ +/* Log all write descriptors. Can be changed while device is active. */ +#define VHOST_F_LOG_ALL 26 +/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ +#define VHOST_NET_F_VIRTIO_NET_HDR 27 + +#endif -- GitLab From c5bab5e94d148aee2c852450374143c89aa56511 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Thu, 14 Jan 2010 01:05:48 +0000 Subject: [PATCH 0716/3892] can: mscan-mpc5xxx: fix broken support for the MPC5200 Due to an invalid "#ifdef CONFIG_PPC_MPC5200", the real clock setup function was not called for the MPC5200. Signed-off-by: Wolfgang Grandegger Acked-by: Wolfram Sang Signed-off-by: David S. Miller --- drivers/net/can/mscan/mpc5xxx_can.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index f73487f723b8..03e7c48465a2 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -43,7 +43,7 @@ struct mpc5xxx_can_data { int *mscan_clksrc); }; -#ifdef CONFIG_PPC_MPC5200 +#ifdef CONFIG_PPC_MPC52xx static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = { { .compatible = "fsl,mpc5200-cdm", }, {} @@ -84,7 +84,7 @@ static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, /* Determine SYS_XTAL_IN frequency from the clock domain settings */ np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids); if (!np_cdm) { - dev_err(&of->dev, "can't get clock node!\n"); + dev_err(&ofdev->dev, "can't get clock node!\n"); return 0; } cdm = of_iomap(np_cdm, 0); @@ -101,14 +101,14 @@ static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, return freq; } -#else /* !CONFIG_PPC_MPC5200 */ +#else /* !CONFIG_PPC_MPC52xx */ static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, const char *clock_name, int *mscan_clksrc) { return 0; } -#endif /* CONFIG_PPC_MPC5200 */ +#endif /* CONFIG_PPC_MPC52xx */ #ifdef CONFIG_PPC_MPC512x struct mpc512x_clockctl { -- GitLab From d86458471aadffe93b741024b5a879ea5dc8df35 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 15 Jan 2010 01:48:22 -0800 Subject: [PATCH 0717/3892] ethoc: Use resource_size Use the resource_size function instead of manually calculating the resource size. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/ethoc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index bd1db92aec1b..f9d5ca078743 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -904,7 +904,7 @@ static int ethoc_probe(struct platform_device *pdev) } mmio = devm_request_mem_region(&pdev->dev, res->start, - res->end - res->start + 1, res->name); + resource_size(res), res->name); if (!mmio) { dev_err(&pdev->dev, "cannot request I/O memory space\n"); ret = -ENXIO; @@ -917,7 +917,7 @@ static int ethoc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { mem = devm_request_mem_region(&pdev->dev, res->start, - res->end - res->start + 1, res->name); + resource_size(res), res->name); if (!mem) { dev_err(&pdev->dev, "cannot request memory space\n"); ret = -ENXIO; @@ -945,7 +945,7 @@ static int ethoc_probe(struct platform_device *pdev) priv->dma_alloc = 0; priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, - mmio->end - mmio->start + 1); + resource_size(mmio)); if (!priv->iobase) { dev_err(&pdev->dev, "cannot remap I/O memory space\n"); ret = -ENXIO; @@ -954,7 +954,7 @@ static int ethoc_probe(struct platform_device *pdev) if (netdev->mem_end) { priv->membase = devm_ioremap_nocache(&pdev->dev, - netdev->mem_start, mem->end - mem->start + 1); + netdev->mem_start, resource_size(mem)); if (!priv->membase) { dev_err(&pdev->dev, "cannot remap memory space\n"); ret = -ENXIO; -- GitLab From 7dcaa8e8e67b2cfbe0097c9bb52e23aed5443b8b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 15 Jan 2010 19:13:56 +0900 Subject: [PATCH 0718/3892] sh: Generalize SH7786 PCIe support. Previously this was only built in for Urquell boards, but the same approach can be used on SDK7786 now that the mode pin reading is supported, so make it generic to SH7786. Signed-off-by: Paul Mundt --- arch/sh/boards/Kconfig | 1 + arch/sh/drivers/pci/Makefile | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index c0a1992bb256..938e87d51482 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -153,6 +153,7 @@ config SH_SDK7780 config SH_SDK7786 bool "SDK7786" depends on CPU_SUBTYPE_SH7786 + select SYS_SUPPORTS_PCI help Select SDK7786 if configuring for a Renesas Technology Europe SH7786-65nm board. diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 08af1f459756..2c458b602beb 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7763) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o -obj-$(CONFIG_CPU_SUBTYPE_SH7786) += ops-sh7786.o +obj-$(CONFIG_CPU_SUBTYPE_SH7786) += pcie-sh7786.o ops-sh7786.o obj-$(CONFIG_CPU_SH5) += pci-sh5.o ops-sh5.o obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ @@ -25,4 +25,3 @@ obj-$(CONFIG_SH_TITAN) += fixups-titan.o obj-$(CONFIG_SH_LANDISK) += fixups-landisk.o obj-$(CONFIG_SH_LBOX_RE2) += fixups-rts7751r2d.o obj-$(CONFIG_SH_CAYMAN) += fixups-cayman.o -obj-$(CONFIG_SH_URQUELL) += pcie-sh7786.o -- GitLab From 62e62da856dba2edb897b672cbd05a69edd4485c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Thu, 14 Jan 2010 19:10:07 -0700 Subject: [PATCH 0719/3892] HID: hid-debug.c: make local symbols static hid-debug.c: make local symbols static The symbols hid_resolv_event and hid_dump_input_mapping are only used locally in this file. Make them static to prevent the following sparse warnings: warning: symbol 'hid_resolv_event' was not declared. Should it be static? warning: symbol 'hid_dump_input_mapping' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 6abd0369aedb..cd4ece6fdfb9 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -864,13 +864,13 @@ static const char **names[EV_MAX + 1] = { [EV_SND] = sounds, [EV_REP] = repeats, }; -void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) { - +static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) +{ seq_printf(f, "%s.%s", events[type] ? events[type] : "?", names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); } -void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) +static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) { int i, j, k; struct hid_report *report; -- GitLab From 6aababdf20bb8892023bb8df136514d7679e4959 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 15 Jan 2010 17:36:48 +0100 Subject: [PATCH 0720/3892] ASoC: cs4270: allow passing freq=0 in set_dai_sysclk() For setups with variable MCLKs, the current logic of limiting the available sampling rates at startup time is not sufficient. We need to be able to change the setting at a later point, and so the codec must offer all possible rates until the hw_params are given. This patches allows that by passing 0 as 'freq' argument to cs4270_set_dai_sysclk(). Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 8b5457542a0e..593bfc7a6986 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -200,6 +200,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { * This function must be called by the machine driver's 'startup' function, * otherwise the list of supported sample rates will not be available in * time for ALSA. + * + * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause + * theoretically possible sample rates to be enabled. Call it again with a + * proper value set one the external clock is set (most probably you would do + * that from a machine's driver 'hw_param' hook. */ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) @@ -213,20 +218,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, cs4270->mclk = freq; - for (i = 0; i < NUM_MCLK_RATIOS; i++) { - unsigned int rate = freq / cs4270_mode_ratios[i].ratio; - rates |= snd_pcm_rate_to_rate_bit(rate); - if (rate < rate_min) - rate_min = rate; - if (rate > rate_max) - rate_max = rate; - } - /* FIXME: soc should support a rate list */ - rates &= ~SNDRV_PCM_RATE_KNOT; + if (cs4270->mclk) { + for (i = 0; i < NUM_MCLK_RATIOS; i++) { + unsigned int rate = freq / cs4270_mode_ratios[i].ratio; + rates |= snd_pcm_rate_to_rate_bit(rate); + if (rate < rate_min) + rate_min = rate; + if (rate > rate_max) + rate_max = rate; + } + /* FIXME: soc should support a rate list */ + rates &= ~SNDRV_PCM_RATE_KNOT; - if (!rates) { - dev_err(codec->dev, "could not find a valid sample rate\n"); - return -EINVAL; + if (!rates) { + dev_err(codec->dev, "could not find a valid sample rate\n"); + return -EINVAL; + } + } else { + /* enable all possible rates */ + rates = SNDRV_PCM_RATE_8000_192000; + rate_min = 8000; + rate_max = 192000; } codec_dai->playback.rates = rates; -- GitLab From a421296840379aee7d00ec4a28ecfe7e697a0a44 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 15 Jan 2010 17:36:49 +0100 Subject: [PATCH 0721/3892] ASoC: support more sample rates on raumfeld devices Add support for sample rates other than 44100Khz on raumfeld audio devices. At startup time, call snd_soc_dai_set_sysclk() with 0 as 'freq' argument so it offers all the sample rates. Later, the function is called again to give proper constraints. Use the external audio clock generator to provide double data rate clocks as the PXA's internal baud generator does anything but what's described in the datasheets. Signed-off-by: Daniel Mack Cc: Mark Brown Cc: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/pxa/raumfeld.c | 61 ++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index acfce1c0f1c9..7e3f41696c41 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -41,7 +41,9 @@ static struct i2c_board_info max9486_hwmon_info = { }; #define MAX9485_MCLK_FREQ_112896 0x22 -#define MAX9485_MCLK_FREQ_122880 0x23 +#define MAX9485_MCLK_FREQ_122880 0x23 +#define MAX9485_MCLK_FREQ_225792 0x32 +#define MAX9485_MCLK_FREQ_245760 0x33 static void set_max9485_clk(char clk) { @@ -71,9 +73,17 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - set_max9485_clk(MAX9485_MCLK_FREQ_112896); + /* set freq to 0 to enable all possible codec sample rates */ + return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); +} - return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0); +static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + /* set freq to 0 to enable all possible codec sample rates */ + snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); } static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, @@ -86,20 +96,24 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, int ret = 0; switch (params_rate(params)) { - case 8000: - case 16000: + case 44100: + set_max9485_clk(MAX9485_MCLK_FREQ_112896); + clk = 11289600; + break; case 48000: - case 96000: set_max9485_clk(MAX9485_MCLK_FREQ_122880); clk = 12288000; break; - case 11025: - case 22050: - case 44100: case 88200: - set_max9485_clk(MAX9485_MCLK_FREQ_112896); - clk = 11289600; + set_max9485_clk(MAX9485_MCLK_FREQ_225792); + clk = 22579200; break; + case 96000: + set_max9485_clk(MAX9485_MCLK_FREQ_245760); + clk = 24576000; + break; + default: + return -EINVAL; } fmt = SND_SOC_DAIFMT_I2S | @@ -128,7 +142,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); if (ret < 0) return ret; @@ -137,6 +151,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, static struct snd_soc_ops raumfeld_cs4270_ops = { .startup = raumfeld_cs4270_startup, + .shutdown = raumfeld_cs4270_shutdown, .hw_params = raumfeld_cs4270_hw_params, }; @@ -181,20 +196,24 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, int fmt, ret = 0, clk = 0; switch (params_rate(params)) { - case 8000: - case 16000: + case 44100: + set_max9485_clk(MAX9485_MCLK_FREQ_112896); + clk = 11289600; + break; case 48000: - case 96000: set_max9485_clk(MAX9485_MCLK_FREQ_122880); clk = 12288000; break; - case 11025: - case 22050: - case 44100: case 88200: - set_max9485_clk(MAX9485_MCLK_FREQ_112896); - clk = 11289600; + set_max9485_clk(MAX9485_MCLK_FREQ_225792); + clk = 22579200; + break; + case 96000: + set_max9485_clk(MAX9485_MCLK_FREQ_245760); + clk = 24576000; break; + default: + return -EINVAL; } fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; @@ -217,7 +236,7 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); if (ret < 0) return ret; -- GitLab From 3a85cd96d3ab3c6dcf88b81fc6eaddb84e565a43 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 14 Jan 2010 01:33:55 +0000 Subject: [PATCH 0722/3892] xfs: add tracing to xfs_swap_extents To be able to diagnose whether the swap extents function is detecting compatible inode data fork configurations for swapping extents, add tracing points to the code to allow us to see the format of the inode forks before and after the swap. Signed-off-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_trace.h | 53 ++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_dfrag.c | 5 ++++ 2 files changed, 58 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index c22a608321a3..3353aef50530 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h @@ -1414,6 +1414,59 @@ TRACE_EVENT(xfs_dir2_leafn_moveents, __entry->count) ); +#define XFS_SWAPEXT_INODES \ + { 0, "target" }, \ + { 1, "temp" } + +#define XFS_INODE_FORMAT_STR \ + { 0, "invalid" }, \ + { 1, "local" }, \ + { 2, "extent" }, \ + { 3, "btree" } + +DECLARE_EVENT_CLASS(xfs_swap_extent_class, + TP_PROTO(struct xfs_inode *ip, int which), + TP_ARGS(ip, which), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(int, which) + __field(xfs_ino_t, ino) + __field(int, format) + __field(int, nex) + __field(int, max_nex) + __field(int, broot_size) + __field(int, fork_off) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->which = which; + __entry->ino = ip->i_ino; + __entry->format = ip->i_d.di_format; + __entry->nex = ip->i_d.di_nextents; + __entry->max_nex = ip->i_df.if_ext_max; + __entry->broot_size = ip->i_df.if_broot_bytes; + __entry->fork_off = XFS_IFORK_BOFF(ip); + ), + TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, " + "Max in-fork extents %d, broot size %d, fork offset %d", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __print_symbolic(__entry->which, XFS_SWAPEXT_INODES), + __print_symbolic(__entry->format, XFS_INODE_FORMAT_STR), + __entry->nex, + __entry->max_nex, + __entry->broot_size, + __entry->fork_off) +) + +#define DEFINE_SWAPEXT_EVENT(name) \ +DEFINE_EVENT(xfs_swap_extent_class, name, \ + TP_PROTO(struct xfs_inode *ip, int which), \ + TP_ARGS(ip, which)) + +DEFINE_SWAPEXT_EVENT(xfs_swap_extent_before); +DEFINE_SWAPEXT_EVENT(xfs_swap_extent_after); + #endif /* _TRACE_XFS_H */ #undef TRACE_INCLUDE_PATH diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 84ca1cf16a1e..f25e54027d10 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -254,6 +254,9 @@ xfs_swap_extents( goto out_unlock; } + trace_xfs_swap_extent_before(ip, 0); + trace_xfs_swap_extent_before(tip, 1); + /* check inode formats now that data is flushed */ error = xfs_swap_extents_check_format(ip, tip); if (error) { @@ -421,6 +424,8 @@ xfs_swap_extents( error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT); + trace_xfs_swap_extent_after(ip, 0); + trace_xfs_swap_extent_after(tip, 1); out: kmem_free(tempifp); return error; -- GitLab From 6bded0f383fd7971b76ad6c194dda7d5b814b871 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 14 Jan 2010 01:33:56 +0000 Subject: [PATCH 0723/3892] xfs: clean up inconsistent variable naming in xfs_swap_extent The swap extent ioctl passes in a target inode and a temporary inode which are clearly named in the ioctl structure. The code then assigns temp to target and vice versa, making it extremely difficult to work out which inode is which later in the code. Make this consistent throughout the code. Also make xfs_swap_extent static as there are no external users of the function. Signed-off-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/xfs_dfrag.c | 38 ++++++++++++++++++++++---------------- fs/xfs/xfs_dfrag.h | 3 --- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index f25e54027d10..cd27c9d6c71f 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -45,15 +45,21 @@ #include "xfs_vnodeops.h" #include "xfs_trace.h" + +static int xfs_swap_extents( + xfs_inode_t *ip, /* target inode */ + xfs_inode_t *tip, /* tmp inode */ + xfs_swapext_t *sxp); + /* - * Syssgi interface for swapext + * ioctl interface for swapext */ int xfs_swapext( xfs_swapext_t *sxp) { xfs_inode_t *ip, *tip; - struct file *file, *target_file; + struct file *file, *tmp_file; int error = 0; /* Pull information for the target fd */ @@ -68,46 +74,46 @@ xfs_swapext( goto out_put_file; } - target_file = fget((int)sxp->sx_fdtmp); - if (!target_file) { + tmp_file = fget((int)sxp->sx_fdtmp); + if (!tmp_file) { error = XFS_ERROR(EINVAL); goto out_put_file; } - if (!(target_file->f_mode & FMODE_WRITE) || - (target_file->f_flags & O_APPEND)) { + if (!(tmp_file->f_mode & FMODE_WRITE) || + (tmp_file->f_flags & O_APPEND)) { error = XFS_ERROR(EBADF); - goto out_put_target_file; + goto out_put_tmp_file; } if (IS_SWAPFILE(file->f_path.dentry->d_inode) || - IS_SWAPFILE(target_file->f_path.dentry->d_inode)) { + IS_SWAPFILE(tmp_file->f_path.dentry->d_inode)) { error = XFS_ERROR(EINVAL); - goto out_put_target_file; + goto out_put_tmp_file; } ip = XFS_I(file->f_path.dentry->d_inode); - tip = XFS_I(target_file->f_path.dentry->d_inode); + tip = XFS_I(tmp_file->f_path.dentry->d_inode); if (ip->i_mount != tip->i_mount) { error = XFS_ERROR(EINVAL); - goto out_put_target_file; + goto out_put_tmp_file; } if (ip->i_ino == tip->i_ino) { error = XFS_ERROR(EINVAL); - goto out_put_target_file; + goto out_put_tmp_file; } if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { error = XFS_ERROR(EIO); - goto out_put_target_file; + goto out_put_tmp_file; } error = xfs_swap_extents(ip, tip, sxp); - out_put_target_file: - fput(target_file); + out_put_tmp_file: + fput(tmp_file); out_put_file: fput(file); out: @@ -186,7 +192,7 @@ xfs_swap_extents_check_format( return 0; } -int +static int xfs_swap_extents( xfs_inode_t *ip, /* target inode */ xfs_inode_t *tip, /* tmp inode */ diff --git a/fs/xfs/xfs_dfrag.h b/fs/xfs/xfs_dfrag.h index 4f55a6306558..20bdd935c121 100644 --- a/fs/xfs/xfs_dfrag.h +++ b/fs/xfs/xfs_dfrag.h @@ -48,9 +48,6 @@ typedef struct xfs_swapext */ int xfs_swapext(struct xfs_swapext *sx); -int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip, - struct xfs_swapext *sxp); - #endif /* __KERNEL__ */ #endif /* __XFS_DFRAG_H__ */ -- GitLab From 5d77c0dc0c05c2c65aee16149fae06831a118730 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 19 Nov 2009 15:52:00 +0000 Subject: [PATCH 0724/3892] xfs: make several more functions static Just minor housekeeping, a lot more functions can be trivially made static; others could if we reordered things a bit... Signed-off-by: Eric Sandeen Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_sync.c | 2 +- fs/xfs/linux-2.6/xfs_sync.h | 1 - fs/xfs/xfs_attr.c | 2 +- fs/xfs/xfs_attr.h | 1 - fs/xfs/xfs_bmap_btree.c | 2 +- fs/xfs/xfs_bmap_btree.h | 1 - fs/xfs/xfs_dir2_node.c | 2 +- fs/xfs/xfs_dir2_node.h | 2 -- fs/xfs/xfs_log_priv.h | 5 ----- fs/xfs/xfs_log_recover.c | 6 +++--- 10 files changed, 7 insertions(+), 17 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 1f5e4bb5e970..0f90bfe2815f 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -351,7 +351,7 @@ xfs_commit_dummy_trans( return error; } -int +STATIC int xfs_sync_fsdata( struct xfs_mount *mp, int flags) diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index ea932b43335d..d480c346cabb 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h @@ -37,7 +37,6 @@ void xfs_syncd_stop(struct xfs_mount *mp); int xfs_sync_attr(struct xfs_mount *mp, int flags); int xfs_sync_data(struct xfs_mount *mp, int flags); -int xfs_sync_fsdata(struct xfs_mount *mp, int flags); int xfs_quiesce_data(struct xfs_mount *mp); void xfs_quiesce_attr(struct xfs_mount *mp); diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index e953b6cfb2a8..9d11ebad43b6 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -197,7 +197,7 @@ xfs_attr_get( /* * Calculate how many blocks we need for the new attribute, */ -int +STATIC int xfs_attr_calc_size( struct xfs_inode *ip, int namelen, diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 59b410ce69a1..9c3a24372914 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -139,7 +139,6 @@ typedef struct xfs_attr_list_context { /* * Overall external interface routines. */ -int xfs_attr_calc_size(struct xfs_inode *, int, int, int *); int xfs_attr_inactive(struct xfs_inode *dp); int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_list_int(struct xfs_attr_list_context *); diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 38751d5fac6f..416e47e54b83 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -334,7 +334,7 @@ xfs_bmbt_disk_set_allf( /* * Set all the fields in a bmap extent record from the uncompressed form. */ -void +STATIC void xfs_bmbt_disk_set_all( xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s) diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index cf07ca7c22e7..0e66c4ea0f85 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -223,7 +223,6 @@ extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_host_t *r, xfs_fsblock_t v); extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v); extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v); -extern void xfs_bmbt_disk_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index ce6e355199b5..78fc4d9ae756 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -65,7 +65,7 @@ static int xfs_dir2_node_addname_int(xfs_da_args_t *args, /* * Log entries from a freespace block. */ -void +STATIC void xfs_dir2_free_log_bests( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* freespace buffer */ diff --git a/fs/xfs/xfs_dir2_node.h b/fs/xfs/xfs_dir2_node.h index dde72db3d695..82dfe7147195 100644 --- a/fs/xfs/xfs_dir2_node.h +++ b/fs/xfs/xfs_dir2_node.h @@ -75,8 +75,6 @@ xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) return ((db) % XFS_DIR2_MAX_FREE_BESTS(mp)); } -extern void xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, - int first, int last); extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_dabuf *lbp); extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count); diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index d55662db7077..fd02a18facd5 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -443,14 +443,9 @@ typedef struct log { /* common routines */ extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); -extern int xlog_find_tail(xlog_t *log, - xfs_daddr_t *head_blk, - xfs_daddr_t *tail_blk); extern int xlog_recover(xlog_t *log); extern int xlog_recover_finish(xlog_t *log); extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); -extern struct xfs_buf *xlog_get_bp(xlog_t *, int); -extern void xlog_put_bp(struct xfs_buf *); extern kmem_zone_t *xfs_log_ticket_zone; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 69ac2e5ef20c..48a7ab1e6311 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -68,7 +68,7 @@ STATIC void xlog_recover_check_summary(xlog_t *); ((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) ) #define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno) ((bno) & ~(log)->l_sectbb_mask) -xfs_buf_t * +STATIC xfs_buf_t * xlog_get_bp( xlog_t *log, int nbblks) @@ -88,7 +88,7 @@ xlog_get_bp( return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp); } -void +STATIC void xlog_put_bp( xfs_buf_t *bp) { @@ -805,7 +805,7 @@ xlog_find_head( * We could speed up search by using current head_blk buffer, but it is not * available. */ -int +STATIC int xlog_find_tail( xlog_t *log, xfs_daddr_t *head_blk, -- GitLab From f0a7695380efa31cd281730917f7e907a724d5cb Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:49:57 +0000 Subject: [PATCH 0725/3892] xfs: Use list_heads for log recovery item lists Remove the roll-your-own linked list operations. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_log_recover.c | 205 +++++++++++++-------------------------- fs/xfs/xfs_log_recover.h | 23 +++-- 2 files changed, 81 insertions(+), 147 deletions(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 48a7ab1e6311..65f1f137d789 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -50,8 +50,6 @@ STATIC int xlog_find_zeroed(xlog_t *, xfs_daddr_t *); STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t); -STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q, - xlog_recover_item_t *item); #if defined(DEBUG) STATIC void xlog_recover_check_summary(xlog_t *); #else @@ -1367,36 +1365,45 @@ xlog_clear_stale_blocks( STATIC xlog_recover_t * xlog_recover_find_tid( - xlog_recover_t *q, + struct hlist_head *head, xlog_tid_t tid) { - xlog_recover_t *p = q; + xlog_recover_t *trans; + struct hlist_node *n; - while (p != NULL) { - if (p->r_log_tid == tid) - break; - p = p->r_next; + hlist_for_each_entry(trans, n, head, r_list) { + if (trans->r_log_tid == tid) + return trans; } - return p; + return NULL; } STATIC void -xlog_recover_put_hashq( - xlog_recover_t **q, - xlog_recover_t *trans) +xlog_recover_new_tid( + struct hlist_head *head, + xlog_tid_t tid, + xfs_lsn_t lsn) { - trans->r_next = *q; - *q = trans; + xlog_recover_t *trans; + + trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); + trans->r_log_tid = tid; + trans->r_lsn = lsn; + INIT_LIST_HEAD(&trans->r_itemq); + + INIT_HLIST_NODE(&trans->r_list); + hlist_add_head(&trans->r_list, head); } STATIC void xlog_recover_add_item( - xlog_recover_item_t **itemq) + struct list_head *head) { xlog_recover_item_t *item; item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); - xlog_recover_insert_item_backq(itemq, item); + INIT_LIST_HEAD(&item->ri_list); + list_add_tail(&item->ri_list, head); } STATIC int @@ -1409,8 +1416,7 @@ xlog_recover_add_to_cont_trans( xfs_caddr_t ptr, old_ptr; int old_len; - item = trans->r_itemq; - if (item == NULL) { + if (list_empty(&trans->r_itemq)) { /* finish copying rest of trans header */ xlog_recover_add_item(&trans->r_itemq); ptr = (xfs_caddr_t) &trans->r_theader + @@ -1418,7 +1424,8 @@ xlog_recover_add_to_cont_trans( memcpy(ptr, dp, len); /* d, s, l */ return 0; } - item = item->ri_prev; + /* take the tail entry */ + item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; old_len = item->ri_buf[item->ri_cnt-1].i_len; @@ -1455,8 +1462,7 @@ xlog_recover_add_to_trans( if (!len) return 0; - item = trans->r_itemq; - if (item == NULL) { + if (list_empty(&trans->r_itemq)) { /* we need to catch log corruptions here */ if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { xlog_warn("XFS: xlog_recover_add_to_trans: " @@ -1474,12 +1480,15 @@ xlog_recover_add_to_trans( memcpy(ptr, dp, len); in_f = (xfs_inode_log_format_t *)ptr; - if (item->ri_prev->ri_total != 0 && - item->ri_prev->ri_total == item->ri_prev->ri_cnt) { + /* take the tail entry */ + item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); + if (item->ri_total != 0 && + item->ri_total == item->ri_cnt) { + /* tail item is in use, get a new one */ xlog_recover_add_item(&trans->r_itemq); + item = list_entry(trans->r_itemq.prev, + xlog_recover_item_t, ri_list); } - item = trans->r_itemq; - item = item->ri_prev; if (item->ri_total == 0) { /* first region to be added */ if (in_f->ilf_size == 0 || @@ -1504,96 +1513,29 @@ xlog_recover_add_to_trans( return 0; } -STATIC void -xlog_recover_new_tid( - xlog_recover_t **q, - xlog_tid_t tid, - xfs_lsn_t lsn) -{ - xlog_recover_t *trans; - - trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); - trans->r_log_tid = tid; - trans->r_lsn = lsn; - xlog_recover_put_hashq(q, trans); -} - -STATIC int -xlog_recover_unlink_tid( - xlog_recover_t **q, - xlog_recover_t *trans) -{ - xlog_recover_t *tp; - int found = 0; - - ASSERT(trans != NULL); - if (trans == *q) { - *q = (*q)->r_next; - } else { - tp = *q; - while (tp) { - if (tp->r_next == trans) { - found = 1; - break; - } - tp = tp->r_next; - } - if (!found) { - xlog_warn( - "XFS: xlog_recover_unlink_tid: trans not found"); - ASSERT(0); - return XFS_ERROR(EIO); - } - tp->r_next = tp->r_next->r_next; - } - return 0; -} - -STATIC void -xlog_recover_insert_item_backq( - xlog_recover_item_t **q, - xlog_recover_item_t *item) -{ - if (*q == NULL) { - item->ri_prev = item->ri_next = item; - *q = item; - } else { - item->ri_next = *q; - item->ri_prev = (*q)->ri_prev; - (*q)->ri_prev = item; - item->ri_prev->ri_next = item; - } -} - -STATIC void -xlog_recover_insert_item_frontq( - xlog_recover_item_t **q, - xlog_recover_item_t *item) -{ - xlog_recover_insert_item_backq(q, item); - *q = item; -} - +/* + * Sort the log items in the transaction. Cancelled buffers need + * to be put first so they are processed before any items that might + * modify the buffers. If they are cancelled, then the modifications + * don't need to be replayed. + */ STATIC int xlog_recover_reorder_trans( xlog_recover_t *trans) { - xlog_recover_item_t *first_item, *itemq, *itemq_next; - xfs_buf_log_format_t *buf_f; - ushort flags = 0; + xlog_recover_item_t *item, *n; + LIST_HEAD(sort_list); + + list_splice_init(&trans->r_itemq, &sort_list); + list_for_each_entry_safe(item, n, &sort_list, ri_list) { + xfs_buf_log_format_t *buf_f; - first_item = itemq = trans->r_itemq; - trans->r_itemq = NULL; - do { - itemq_next = itemq->ri_next; - buf_f = (xfs_buf_log_format_t *)itemq->ri_buf[0].i_addr; + buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; - switch (ITEM_TYPE(itemq)) { + switch (ITEM_TYPE(item)) { case XFS_LI_BUF: - flags = buf_f->blf_flags; - if (!(flags & XFS_BLI_CANCEL)) { - xlog_recover_insert_item_frontq(&trans->r_itemq, - itemq); + if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) { + list_move(&item->ri_list, &trans->r_itemq); break; } case XFS_LI_INODE: @@ -1601,7 +1543,7 @@ xlog_recover_reorder_trans( case XFS_LI_QUOTAOFF: case XFS_LI_EFD: case XFS_LI_EFI: - xlog_recover_insert_item_backq(&trans->r_itemq, itemq); + list_move_tail(&item->ri_list, &trans->r_itemq); break; default: xlog_warn( @@ -1609,8 +1551,8 @@ xlog_recover_reorder_trans( ASSERT(0); return XFS_ERROR(EIO); } - itemq = itemq_next; - } while (first_item != itemq); + } + ASSERT(list_empty(&sort_list)); return 0; } @@ -2814,14 +2756,13 @@ xlog_recover_do_trans( int pass) { int error = 0; - xlog_recover_item_t *item, *first_item; + xlog_recover_item_t *item; error = xlog_recover_reorder_trans(trans); if (error) return error; - first_item = item = trans->r_itemq; - do { + list_for_each_entry(item, &trans->r_itemq, ri_list) { switch (ITEM_TYPE(item)) { case XFS_LI_BUF: error = xlog_recover_do_buffer_trans(log, item, pass); @@ -2854,8 +2795,7 @@ xlog_recover_do_trans( if (error) return error; - item = item->ri_next; - } while (first_item != item); + } return 0; } @@ -2869,21 +2809,18 @@ STATIC void xlog_recover_free_trans( xlog_recover_t *trans) { - xlog_recover_item_t *first_item, *item, *free_item; + xlog_recover_item_t *item, *n; int i; - item = first_item = trans->r_itemq; - do { - free_item = item; - item = item->ri_next; - /* Free the regions in the item. */ - for (i = 0; i < free_item->ri_cnt; i++) { - kmem_free(free_item->ri_buf[i].i_addr); - } + list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) { + /* Free the regions in the item. */ + list_del(&item->ri_list); + for (i = 0; i < item->ri_cnt; i++) + kmem_free(item->ri_buf[i].i_addr); /* Free the item itself */ - kmem_free(free_item->ri_buf); - kmem_free(free_item); - } while (first_item != item); + kmem_free(item->ri_buf); + kmem_free(item); + } /* Free the transaction recover structure */ kmem_free(trans); } @@ -2891,14 +2828,12 @@ xlog_recover_free_trans( STATIC int xlog_recover_commit_trans( xlog_t *log, - xlog_recover_t **q, xlog_recover_t *trans, int pass) { int error; - if ((error = xlog_recover_unlink_tid(q, trans))) - return error; + hlist_del(&trans->r_list); if ((error = xlog_recover_do_trans(log, trans, pass))) return error; xlog_recover_free_trans(trans); /* no error */ @@ -2926,7 +2861,7 @@ xlog_recover_unmount_trans( STATIC int xlog_recover_process_data( xlog_t *log, - xlog_recover_t *rhash[], + struct hlist_head rhash[], xlog_rec_header_t *rhead, xfs_caddr_t dp, int pass) @@ -2960,7 +2895,7 @@ xlog_recover_process_data( } tid = be32_to_cpu(ohead->oh_tid); hash = XLOG_RHASH(tid); - trans = xlog_recover_find_tid(rhash[hash], tid); + trans = xlog_recover_find_tid(&rhash[hash], tid); if (trans == NULL) { /* not found; add new tid */ if (ohead->oh_flags & XLOG_START_TRANS) xlog_recover_new_tid(&rhash[hash], tid, @@ -2978,7 +2913,7 @@ xlog_recover_process_data( switch (flags) { case XLOG_COMMIT_TRANS: error = xlog_recover_commit_trans(log, - &rhash[hash], trans, pass); + trans, pass); break; case XLOG_UNMOUNT_TRANS: error = xlog_recover_unmount_trans(trans); @@ -3517,7 +3452,7 @@ xlog_do_recovery_pass( int error = 0, h_size; int bblks, split_bblks; int hblks, split_hblks, wrapped_hblks; - xlog_recover_t *rhash[XLOG_RHASH_SIZE]; + struct hlist_head rhash[XLOG_RHASH_SIZE]; ASSERT(head_blk != tail_blk); diff --git a/fs/xfs/xfs_log_recover.h b/fs/xfs/xfs_log_recover.h index b22545555301..75d749207258 100644 --- a/fs/xfs/xfs_log_recover.h +++ b/fs/xfs/xfs_log_recover.h @@ -35,22 +35,21 @@ * item headers are in ri_buf[0]. Additional buffers follow. */ typedef struct xlog_recover_item { - struct xlog_recover_item *ri_next; - struct xlog_recover_item *ri_prev; - int ri_type; - int ri_cnt; /* count of regions found */ - int ri_total; /* total regions */ - xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ + struct list_head ri_list; + int ri_type; + int ri_cnt; /* count of regions found */ + int ri_total; /* total regions */ + xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ } xlog_recover_item_t; struct xlog_tid; typedef struct xlog_recover { - struct xlog_recover *r_next; - xlog_tid_t r_log_tid; /* log's transaction id */ - xfs_trans_header_t r_theader; /* trans header for partial */ - int r_state; /* not needed */ - xfs_lsn_t r_lsn; /* xact lsn */ - xlog_recover_item_t *r_itemq; /* q for items */ + struct hlist_node r_list; + xlog_tid_t r_log_tid; /* log's transaction id */ + xfs_trans_header_t r_theader; /* trans header for partial */ + int r_state; /* not needed */ + xfs_lsn_t r_lsn; /* xact lsn */ + struct list_head r_itemq; /* q for items */ } xlog_recover_t; #define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) -- GitLab From 453eac8a9aa417878a38bdfbccafd5f7ce4e8e4e Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:49:58 +0000 Subject: [PATCH 0726/3892] xfs: Don't wake the aild once per second Now that the AIL push algorithm is traversal safe, we don't need a watchdog function in the xfsaild to catch pushes that fail to make progress. Remove the watchdog timeout and make pushes purely driven by demand. This will remove the once-per-second wakeup that is seen when the filesystem is idle and make laptop power misers happy. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_super.c | 7 +++---- fs/xfs/xfs_trans_ail.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 77414db10dc2..9f2e398a5616 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -877,12 +877,11 @@ xfsaild( { struct xfs_ail *ailp = data; xfs_lsn_t last_pushed_lsn = 0; - long tout = 0; + long tout = 0; /* milliseconds */ while (!kthread_should_stop()) { - if (tout) - schedule_timeout_interruptible(msecs_to_jiffies(tout)); - tout = 1000; + schedule_timeout_interruptible(tout ? + msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT); /* swsusp */ try_to_freeze(); diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 2ffc570679be..063dfbdca94b 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -237,14 +237,15 @@ out: } /* - * Function that does the work of pushing on the AIL + * xfsaild_push does the work of pushing on the AIL. Returning a timeout of + * zero indicates that the caller should sleep until woken. */ long xfsaild_push( struct xfs_ail *ailp, xfs_lsn_t *last_lsn) { - long tout = 1000; /* milliseconds */ + long tout = 0; xfs_lsn_t last_pushed_lsn = *last_lsn; xfs_lsn_t target = ailp->xa_target; xfs_lsn_t lsn; @@ -262,7 +263,7 @@ xfsaild_push( */ xfs_trans_ail_cursor_done(ailp, cur); spin_unlock(&ailp->xa_lock); - last_pushed_lsn = 0; + *last_lsn = 0; return tout; } @@ -279,7 +280,6 @@ xfsaild_push( * prevents use from spinning when we can't do anything or there is * lots of contention on the AIL lists. */ - tout = 10; lsn = lip->li_lsn; flush_log = stuck = count = 0; while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { @@ -376,14 +376,14 @@ xfsaild_push( if (!count) { /* We're past our target or empty, so idle */ - tout = 1000; + last_pushed_lsn = 0; } else if (XFS_LSN_CMP(lsn, target) >= 0) { /* * We reached the target so wait a bit longer for I/O to * complete and remove pushed items from the AIL before we * start the next scan from the start of the AIL. */ - tout += 20; + tout = 50; last_pushed_lsn = 0; } else if ((stuck * 100) / count > 90) { /* @@ -395,11 +395,14 @@ xfsaild_push( * Backoff a bit more to allow some I/O to complete before * continuing from where we were. */ - tout += 10; + tout = 20; + } else { + /* more to do, but wait a short while before continuing */ + tout = 10; } *last_lsn = last_pushed_lsn; return tout; -} /* xfsaild_push */ +} /* -- GitLab From c9c129714e71c890bed1bd5b61697a896c3c2d54 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:49:59 +0000 Subject: [PATCH 0727/3892] xfs: Don't wake xfsbufd when idle The xfsbufd wakes every xfsbufd_centisecs (once per second by default) for each filesystem even when the filesystem is idle. If the xfsbufd has nothing to do, put it into a long term sleep and only wake it up when there is work pending (i.e. dirty buffers to flush soon). This will make laptop power misers happy. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 77b8be81c769..18ae3ba8f78a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1595,6 +1595,11 @@ xfs_buf_delwri_queue( list_del(&bp->b_list); } + if (list_empty(dwq)) { + /* start xfsbufd as it is about to have something to do */ + wake_up_process(bp->b_target->bt_task); + } + bp->b_flags |= _XBF_DELWRI_Q; list_add_tail(&bp->b_list, dwq); bp->b_queuetime = jiffies; @@ -1644,6 +1649,8 @@ xfsbufd_wakeup( list_for_each_entry(btp, &xfs_buftarg_list, bt_list) { if (test_bit(XBT_FORCE_SLEEP, &btp->bt_flags)) continue; + if (list_empty(&btp->bt_delwrite_queue)) + continue; set_bit(XBT_FORCE_FLUSH, &btp->bt_flags); wake_up_process(btp->bt_task); } @@ -1708,6 +1715,9 @@ xfsbufd( set_freezable(); do { + long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); + long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10); + if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); refrigerator(); @@ -1715,12 +1725,12 @@ xfsbufd( clear_bit(XBT_FORCE_SLEEP, &target->bt_flags); } - schedule_timeout_interruptible( - xfs_buf_timer_centisecs * msecs_to_jiffies(10)); - - xfs_buf_delwri_split(target, &tmp, - xfs_buf_age_centisecs * msecs_to_jiffies(10)); + /* sleep for a long time if there is nothing to do. */ + if (list_empty(&target->bt_delwrite_queue)) + tout = MAX_SCHEDULE_TIMEOUT; + schedule_timeout_interruptible(tout); + xfs_buf_delwri_split(target, &tmp, age); count = 0; while (!list_empty(&tmp)) { bp = list_entry(tmp.next, xfs_buf_t, b_list); -- GitLab From 5017e97d52628fb8ae56e434e86ac2e72ddaac2b Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:40 +0000 Subject: [PATCH 0728/3892] xfs: rename xfs_get_perag xfs_get_perag is really getting the perag that an inode belongs to based on it's inode number. Convert the use of this function to just get the perag from a provided ag number. Use this new function to obtain the per-ag structure when traversing the per AG inode trees for sync and reclaim. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_sync.c | 22 +++++++++++++--------- fs/xfs/xfs_iget.c | 10 +++++----- fs/xfs/xfs_inode.c | 8 +++++--- fs/xfs/xfs_mount.h | 8 ++++---- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 0f90bfe2815f..cc964faf12e9 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -90,14 +90,13 @@ xfs_inode_ag_lookup( STATIC int xfs_inode_ag_walk( struct xfs_mount *mp, - xfs_agnumber_t ag, + struct xfs_perag *pag, int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), int flags, int tag, int exclusive) { - struct xfs_perag *pag = &mp->m_perag[ag]; uint32_t first_index; int last_error = 0; int skipped; @@ -141,8 +140,6 @@ restart: delay(1); goto restart; } - - xfs_put_perag(mp, pag); return last_error; } @@ -160,10 +157,16 @@ xfs_inode_ag_iterator( xfs_agnumber_t ag; for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { - if (!mp->m_perag[ag].pag_ici_init) + struct xfs_perag *pag; + + pag = xfs_perag_get(mp, ag); + if (!pag->pag_ici_init) { + xfs_perag_put(pag); continue; - error = xfs_inode_ag_walk(mp, ag, execute, flags, tag, + } + error = xfs_inode_ag_walk(mp, pag, execute, flags, tag, exclusive); + xfs_perag_put(pag); if (error) { last_error = error; if (error == EFSCORRUPTED) @@ -690,16 +693,17 @@ void xfs_inode_set_reclaim_tag( xfs_inode_t *ip) { - xfs_mount_t *mp = ip->i_mount; - xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); + struct xfs_mount *mp = ip->i_mount; + struct xfs_perag *pag; + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); read_lock(&pag->pag_ici_lock); spin_lock(&ip->i_flags_lock); __xfs_inode_set_reclaim_tag(pag, ip); __xfs_iflags_set(ip, XFS_IRECLAIMABLE); spin_unlock(&ip->i_flags_lock); read_unlock(&pag->pag_ici_lock); - xfs_put_perag(mp, pag); + xfs_perag_put(pag); } void diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 155e798f30a1..e281eb4a1c49 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -374,7 +374,7 @@ xfs_iget( return EINVAL; /* get the perag structure and ensure that it's inode capable */ - pag = xfs_get_perag(mp, ino); + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino)); if (!pag->pagi_inodeok) return EINVAL; ASSERT(pag->pag_ici_init); @@ -398,7 +398,7 @@ again: if (error) goto out_error_or_again; } - xfs_put_perag(mp, pag); + xfs_perag_put(pag); *ipp = ip; @@ -417,7 +417,7 @@ out_error_or_again: delay(1); goto again; } - xfs_put_perag(mp, pag); + xfs_perag_put(pag); return error; } @@ -488,12 +488,12 @@ xfs_ireclaim( * added to the tree assert that it's been there before to catch * problems with the inode life time early on. */ - pag = xfs_get_perag(mp, ip->i_ino); + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); write_lock(&pag->pag_ici_lock); if (!radix_tree_delete(&pag->pag_ici_root, agino)) ASSERT(0); write_unlock(&pag->pag_ici_lock); - xfs_put_perag(mp, pag); + xfs_perag_put(pag); /* * Here we do an (almost) spurious inode lock in order to coordinate diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ef77fd88c8e3..bd3d81636d51 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1946,8 +1946,9 @@ xfs_ifree_cluster( xfs_inode_t *ip, **ip_found; xfs_inode_log_item_t *iip; xfs_log_item_t *lip; - xfs_perag_t *pag = xfs_get_perag(mp, inum); + struct xfs_perag *pag; + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum)); if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { blks_per_cluster = 1; ninodes = mp->m_sb.sb_inopblock; @@ -2088,7 +2089,7 @@ xfs_ifree_cluster( } kmem_free(ip_found); - xfs_put_perag(mp, pag); + xfs_perag_put(pag); } /* @@ -2675,7 +2676,7 @@ xfs_iflush_cluster( xfs_buf_t *bp) { xfs_mount_t *mp = ip->i_mount; - xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); + struct xfs_perag *pag; unsigned long first_index, mask; unsigned long inodes_per_cluster; int ilist_size; @@ -2686,6 +2687,7 @@ xfs_iflush_cluster( int bufwasdelwri; int i; + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); ASSERT(pag->pagi_inodeok); ASSERT(pag->pag_ici_init); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 1df7e4502967..f8a68a2319b5 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -386,14 +386,14 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) /* * perag get/put wrappers for eventual ref counting */ -static inline xfs_perag_t * -xfs_get_perag(struct xfs_mount *mp, xfs_ino_t ino) +static inline struct xfs_perag * +xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) { - return &mp->m_perag[XFS_INO_TO_AGNO(mp, ino)]; + return &mp->m_perag[agno]; } static inline void -xfs_put_perag(struct xfs_mount *mp, xfs_perag_t *pag) +xfs_perag_put(struct xfs_perag *pag) { /* nothing to see here, move along */ } -- GitLab From a862e0fdcb8862aab2538ec2fc2f0dc07a625c59 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:41 +0000 Subject: [PATCH 0729/3892] xfs: Don't directly reference m_perag in allocation code Start abstracting the perag references so that the indexing of the structures is not directly coded into all the places that uses the perag structures. This will allow us to separate the use of the perag structure and the way it is indexed and hence avoid the known deadlocks related to growing a busy filesystem. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_alloc.c | 82 ++++++++++++++++++++++------------------ fs/xfs/xfs_alloc_btree.c | 9 ++++- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 275b1f4f9430..84070f2e0ba4 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -1662,11 +1662,13 @@ xfs_free_ag_extent( xfs_agf_t *agf; xfs_perag_t *pag; /* per allocation group data */ + pag = xfs_perag_get(mp, agno); + pag->pagf_freeblks += len; + xfs_perag_put(pag); + agf = XFS_BUF_TO_AGF(agbp); - pag = &mp->m_perag[agno]; be32_add_cpu(&agf->agf_freeblks, len); xfs_trans_agblocks_delta(tp, len); - pag->pagf_freeblks += len; XFS_WANT_CORRUPTED_GOTO( be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length), @@ -1969,10 +1971,12 @@ xfs_alloc_get_freelist( xfs_trans_brelse(tp, agflbp); if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) agf->agf_flfirst = 0; - pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)]; + + pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; + xfs_perag_put(pag); logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; if (btreeblk) { @@ -2078,7 +2082,8 @@ xfs_alloc_put_freelist( be32_add_cpu(&agf->agf_fllast, 1); if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) agf->agf_fllast = 0; - pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)]; + + pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; @@ -2089,6 +2094,7 @@ xfs_alloc_put_freelist( pag->pagf_btreeblks--; logflags |= XFS_AGF_BTREEBLKS; } + xfs_perag_put(pag); xfs_alloc_log_agf(tp, agbp, logflags); @@ -2152,7 +2158,6 @@ xfs_read_agf( xfs_trans_brelse(tp, *bpp); return XFS_ERROR(EFSCORRUPTED); } - XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF); return 0; } @@ -2184,7 +2189,7 @@ xfs_alloc_read_agf( ASSERT(!XFS_BUF_GETERROR(*bpp)); agf = XFS_BUF_TO_AGF(*bpp); - pag = &mp->m_perag[agno]; + pag = xfs_perag_get(mp, agno); if (!pag->pagf_init) { pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); @@ -2211,6 +2216,7 @@ xfs_alloc_read_agf( be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); } #endif + xfs_perag_put(pag); return 0; } @@ -2271,7 +2277,7 @@ xfs_alloc_vextent( */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); down_read(&mp->m_peraglock); - args->pag = &mp->m_perag[args->agno]; + args->pag = xfs_perag_get(mp, args->agno); args->minleft = 0; error = xfs_alloc_fix_freelist(args, 0); args->minleft = minleft; @@ -2341,7 +2347,7 @@ xfs_alloc_vextent( */ down_read(&mp->m_peraglock); for (;;) { - args->pag = &mp->m_perag[args->agno]; + args->pag = xfs_perag_get(mp, args->agno); if (no_min) args->minleft = 0; error = xfs_alloc_fix_freelist(args, flags); args->minleft = minleft; @@ -2400,6 +2406,7 @@ xfs_alloc_vextent( } } } + xfs_perag_put(args->pag); } up_read(&mp->m_peraglock); if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { @@ -2427,8 +2434,10 @@ xfs_alloc_vextent( args->len); #endif } + xfs_perag_put(args->pag); return 0; error0: + xfs_perag_put(args->pag); up_read(&mp->m_peraglock); return error; } @@ -2455,7 +2464,7 @@ xfs_free_extent( ASSERT(args.agno < args.mp->m_sb.sb_agcount); args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); down_read(&args.mp->m_peraglock); - args.pag = &args.mp->m_perag[args.agno]; + args.pag = xfs_perag_get(args.mp, args.agno); if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) goto error0; #ifdef DEBUG @@ -2465,6 +2474,7 @@ xfs_free_extent( #endif error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); error0: + xfs_perag_put(args.pag); up_read(&args.mp->m_peraglock); return error; } @@ -2486,15 +2496,15 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, xfs_agblock_t bno, xfs_extlen_t len) { - xfs_mount_t *mp; xfs_perag_busy_t *bsy; + struct xfs_perag *pag; int n; - mp = tp->t_mountp; - spin_lock(&mp->m_perag[agno].pagb_lock); + pag = xfs_perag_get(tp->t_mountp, agno); + spin_lock(&pag->pagb_lock); /* search pagb_list for an open slot */ - for (bsy = mp->m_perag[agno].pagb_list, n = 0; + for (bsy = pag->pagb_list, n = 0; n < XFS_PAGB_NUM_SLOTS; bsy++, n++) { if (bsy->busy_tp == NULL) { @@ -2502,11 +2512,11 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, } } - trace_xfs_alloc_busy(mp, agno, bno, len, n); + trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len, n); if (n < XFS_PAGB_NUM_SLOTS) { - bsy = &mp->m_perag[agno].pagb_list[n]; - mp->m_perag[agno].pagb_count++; + bsy = &pag->pagb_list[n]; + pag->pagb_count++; bsy->busy_start = bno; bsy->busy_length = len; bsy->busy_tp = tp; @@ -2521,7 +2531,8 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, xfs_trans_set_sync(tp); } - spin_unlock(&mp->m_perag[agno].pagb_lock); + spin_unlock(&pag->pagb_lock); + xfs_perag_put(pag); } void @@ -2529,24 +2540,23 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, xfs_agnumber_t agno, int idx) { - xfs_mount_t *mp; + struct xfs_perag *pag; xfs_perag_busy_t *list; - mp = tp->t_mountp; - - spin_lock(&mp->m_perag[agno].pagb_lock); - list = mp->m_perag[agno].pagb_list; - ASSERT(idx < XFS_PAGB_NUM_SLOTS); + pag = xfs_perag_get(tp->t_mountp, agno); + spin_lock(&pag->pagb_lock); + list = pag->pagb_list; - trace_xfs_alloc_unbusy(mp, agno, idx, list[idx].busy_tp == tp); + trace_xfs_alloc_unbusy(tp->t_mountp, agno, idx, list[idx].busy_tp == tp); if (list[idx].busy_tp == tp) { list[idx].busy_tp = NULL; - mp->m_perag[agno].pagb_count--; + pag->pagb_count--; } - spin_unlock(&mp->m_perag[agno].pagb_lock); + spin_unlock(&pag->pagb_lock); + xfs_perag_put(pag); } @@ -2560,17 +2570,15 @@ xfs_alloc_search_busy(xfs_trans_t *tp, xfs_agblock_t bno, xfs_extlen_t len) { - xfs_mount_t *mp; + struct xfs_perag *pag; xfs_perag_busy_t *bsy; xfs_agblock_t uend, bend; xfs_lsn_t lsn = 0; int cnt; - mp = tp->t_mountp; - - spin_lock(&mp->m_perag[agno].pagb_lock); - - uend = bno + len - 1; + pag = xfs_perag_get(tp->t_mountp, agno); + spin_lock(&pag->pagb_lock); + cnt = pag->pagb_count; /* * search pagb_list for this slot, skipping open slots. We have to @@ -2578,8 +2586,9 @@ xfs_alloc_search_busy(xfs_trans_t *tp, * we have to get the most recent LSN for the log force to push out * all the transactions that span the range. */ - for (cnt = 0; cnt < mp->m_perag[agno].pagb_count; cnt++) { - bsy = &mp->m_perag[agno].pagb_list[cnt]; + uend = bno + len - 1; + for (cnt = 0; cnt < pag->pagb_count; cnt++) { + bsy = &pag->pagb_list[cnt]; if (!bsy->busy_tp) continue; @@ -2591,7 +2600,8 @@ xfs_alloc_search_busy(xfs_trans_t *tp, if (XFS_LSN_CMP(bsy->busy_tp->t_commit_lsn, lsn) > 0) lsn = bsy->busy_tp->t_commit_lsn; } - spin_unlock(&mp->m_perag[agno].pagb_lock); + spin_unlock(&pag->pagb_lock); + xfs_perag_put(pag); trace_xfs_alloc_busysearch(tp->t_mountp, agno, bno, len, lsn); /* @@ -2599,5 +2609,5 @@ xfs_alloc_search_busy(xfs_trans_t *tp, * transaction that freed the block */ if (lsn) - xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); + xfs_log_force(tp->t_mountp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); } diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index adbd9141aea1..b726e10d2c1c 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -61,12 +61,14 @@ xfs_allocbt_set_root( struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int btnum = cur->bc_btnum; + struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); ASSERT(ptr->s != 0); agf->agf_roots[btnum] = ptr->s; be32_add_cpu(&agf->agf_levels[btnum], inc); - cur->bc_mp->m_perag[seqno].pagf_levels[btnum] += inc; + pag->pagf_levels[btnum] += inc; + xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); } @@ -150,6 +152,7 @@ xfs_allocbt_update_lastrec( { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); + struct xfs_perag *pag; __be32 len; int numrecs; @@ -193,7 +196,9 @@ xfs_allocbt_update_lastrec( } agf->agf_longest = len; - cur->bc_mp->m_perag[seqno].pagf_longest = be32_to_cpu(len); + pag = xfs_perag_get(cur->bc_mp, seqno); + pag->pagf_longest = be32_to_cpu(len); + xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); } -- GitLab From 4196ac08c023c6dab90c3fa460d9c06deaa304c4 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:42 +0000 Subject: [PATCH 0730/3892] xfs: Convert filestreams code to use per-ag get/put routines Use xfs_perag_get() and xfs_perag_put() in the filestreams code. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_filestream.c | 19 ++++++++++++------- fs/xfs/xfs_filestream.h | 27 ++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index a631e1451abb..e61f2aa088a9 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -140,6 +140,7 @@ _xfs_filestream_pick_ag( int flags, xfs_extlen_t minlen) { + int streams, max_streams; int err, trylock, nscan; xfs_extlen_t longest, free, minfree, maxfree = 0; xfs_agnumber_t ag, max_ag = NULLAGNUMBER; @@ -155,15 +156,15 @@ _xfs_filestream_pick_ag( trylock = XFS_ALLOC_FLAG_TRYLOCK; for (nscan = 0; 1; nscan++) { - - TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag)); - - pag = mp->m_perag + ag; + pag = xfs_perag_get(mp, ag); + TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms)); if (!pag->pagf_init) { err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); - if (err && !trylock) + if (err && !trylock) { + xfs_perag_put(pag); return err; + } } /* Might fail sometimes during the 1st pass with trylock set. */ @@ -173,6 +174,7 @@ _xfs_filestream_pick_ag( /* Keep track of the AG with the most free blocks. */ if (pag->pagf_freeblks > maxfree) { maxfree = pag->pagf_freeblks; + max_streams = atomic_read(&pag->pagf_fstrms); max_ag = ag; } @@ -195,6 +197,8 @@ _xfs_filestream_pick_ag( /* Break out, retaining the reference on the AG. */ free = pag->pagf_freeblks; + streams = atomic_read(&pag->pagf_fstrms); + xfs_perag_put(pag); *agp = ag; break; } @@ -202,6 +206,7 @@ _xfs_filestream_pick_ag( /* Drop the reference on this AG, it's not usable. */ xfs_filestream_put_ag(mp, ag); next_ag: + xfs_perag_put(pag); /* Move to the next AG, wrapping to AG 0 if necessary. */ if (++ag >= mp->m_sb.sb_agcount) ag = 0; @@ -229,6 +234,7 @@ next_ag: if (max_ag != NULLAGNUMBER) { xfs_filestream_get_ag(mp, max_ag); TRACE_AG_PICK1(mp, max_ag, maxfree); + streams = max_streams; free = maxfree; *agp = max_ag; break; @@ -240,8 +246,7 @@ next_ag: return 0; } - TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp), - free, nscan, flags); + TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags); return 0; } diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h index 4aba67c5f64f..58378b2ea033 100644 --- a/fs/xfs/xfs_filestream.h +++ b/fs/xfs/xfs_filestream.h @@ -79,12 +79,21 @@ extern ktrace_t *xfs_filestreams_trace_buf; * the cache that reference per-ag array elements that have since been * reallocated. */ +/* + * xfs_filestream_peek_ag is only used in tracing code + */ static inline int xfs_filestream_peek_ag( xfs_mount_t *mp, xfs_agnumber_t agno) { - return atomic_read(&mp->m_perag[agno].pagf_fstrms); + struct xfs_perag *pag; + int ret; + + pag = xfs_perag_get(mp, agno); + ret = atomic_read(&pag->pagf_fstrms); + xfs_perag_put(pag); + return ret; } static inline int @@ -92,7 +101,13 @@ xfs_filestream_get_ag( xfs_mount_t *mp, xfs_agnumber_t agno) { - return atomic_inc_return(&mp->m_perag[agno].pagf_fstrms); + struct xfs_perag *pag; + int ret; + + pag = xfs_perag_get(mp, agno); + ret = atomic_inc_return(&pag->pagf_fstrms); + xfs_perag_put(pag); + return ret; } static inline int @@ -100,7 +115,13 @@ xfs_filestream_put_ag( xfs_mount_t *mp, xfs_agnumber_t agno) { - return atomic_dec_return(&mp->m_perag[agno].pagf_fstrms); + struct xfs_perag *pag; + int ret; + + pag = xfs_perag_get(mp, agno); + ret = atomic_dec_return(&pag->pagf_fstrms); + xfs_perag_put(pag); + return ret; } /* allocation selection flags */ -- GitLab From 44b56e0a1aed522a10051645e85d300e10926fd3 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:43 +0000 Subject: [PATCH 0731/3892] xfs: convert remaining direct references to m_perag Convert the remaining direct lookups of the per ag structures to use get/put accesses. Ensure that the loops across AGs and prior users of the interface balance gets and puts correctly. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_bmap.c | 8 +++++++- fs/xfs/xfs_ialloc.c | 35 +++++++++++++++++++++++++---------- fs/xfs/xfs_inode.c | 5 ++++- fs/xfs/xfs_mount.c | 9 ++++++--- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 98251cdc52aa..a9b95d9cf2ad 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -2630,11 +2630,12 @@ xfs_bmap_btalloc( startag = ag = 0; notinit = 0; down_read(&mp->m_peraglock); + pag = xfs_perag_get(mp, ag); while (blen < ap->alen) { - pag = &mp->m_perag[ag]; if (!pag->pagf_init && (error = xfs_alloc_pagf_init(mp, args.tp, ag, XFS_ALLOC_FLAG_TRYLOCK))) { + xfs_perag_put(pag); up_read(&mp->m_peraglock); return error; } @@ -2667,6 +2668,7 @@ xfs_bmap_btalloc( break; error = xfs_filestream_new_ag(ap, &ag); + xfs_perag_put(pag); if (error) { up_read(&mp->m_peraglock); return error; @@ -2674,6 +2676,7 @@ xfs_bmap_btalloc( /* loop again to set 'blen'*/ startag = NULLAGNUMBER; + pag = xfs_perag_get(mp, ag); continue; } } @@ -2681,7 +2684,10 @@ xfs_bmap_btalloc( ag = 0; if (ag == startag) break; + xfs_perag_put(pag); + pag = xfs_perag_get(mp, ag); } + xfs_perag_put(pag); up_read(&mp->m_peraglock); /* * Since the above loop did a BUF_TRYLOCK, it is diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index cb907ba69c4c..884ee1367f46 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -253,6 +253,7 @@ xfs_ialloc_ag_alloc( xfs_agino_t thisino; /* current inode number, for loop */ int isaligned = 0; /* inode allocation at stripe unit */ /* boundary */ + struct xfs_perag *pag; args.tp = tp; args.mp = tp->t_mountp; @@ -383,7 +384,9 @@ xfs_ialloc_ag_alloc( be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_freecount, newlen); down_read(&args.mp->m_peraglock); - args.mp->m_perag[agno].pagi_freecount += newlen; + pag = xfs_perag_get(args.mp, agno); + pag->pagi_freecount += newlen; + xfs_perag_put(pag); up_read(&args.mp->m_peraglock); agi->agi_newino = cpu_to_be32(newino); @@ -488,7 +491,7 @@ xfs_ialloc_ag_select( flags = XFS_ALLOC_FLAG_TRYLOCK; down_read(&mp->m_peraglock); for (;;) { - pag = &mp->m_perag[agno]; + pag = xfs_perag_get(mp, agno); if (!pag->pagi_init) { if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { agbp = NULL; @@ -527,6 +530,7 @@ xfs_ialloc_ag_select( agbp = NULL; goto nextag; } + xfs_perag_put(pag); up_read(&mp->m_peraglock); return agbp; } @@ -535,6 +539,7 @@ unlock_nextag: if (agbp) xfs_trans_brelse(tp, agbp); nextag: + xfs_perag_put(pag); /* * No point in iterating over the rest, if we're shutting * down. @@ -672,6 +677,7 @@ xfs_dialloc( xfs_agnumber_t tagno; /* testing allocation group number */ xfs_btree_cur_t *tcur; /* temp cursor */ xfs_inobt_rec_incore_t trec; /* temp inode allocation record */ + struct xfs_perag *pag; if (*IO_agbp == NULL) { @@ -772,11 +778,14 @@ nextag: return noroom ? ENOSPC : 0; } down_read(&mp->m_peraglock); - if (mp->m_perag[tagno].pagi_inodeok == 0) { + pag = xfs_perag_get(mp, tagno); + if (pag->pagi_inodeok == 0) { + xfs_perag_put(pag); up_read(&mp->m_peraglock); goto nextag; } error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); + xfs_perag_put(pag); up_read(&mp->m_peraglock); if (error) goto nextag; @@ -790,6 +799,7 @@ nextag: */ agno = tagno; *IO_agbp = NULL; + pag = xfs_perag_get(mp, agno); restart_pagno: cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); @@ -808,7 +818,6 @@ nextag: * If in the same AG as the parent, try to get near the parent. */ if (pagno == agno) { - xfs_perag_t *pag = &mp->m_perag[agno]; int doneleft; /* done, to the left */ int doneright; /* done, to the right */ int searchdistance = 10; @@ -1007,7 +1016,7 @@ alloc_inode: be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); - mp->m_perag[tagno].pagi_freecount--; + pag->pagi_freecount--; up_read(&mp->m_peraglock); error = xfs_check_agi_freecount(cur, agi); @@ -1016,12 +1025,14 @@ alloc_inode: xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); + xfs_perag_put(pag); *inop = ino; return 0; error1: xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + xfs_perag_put(pag); return error; } @@ -1052,6 +1063,7 @@ xfs_difree( xfs_mount_t *mp; /* mount structure for filesystem */ int off; /* offset of inode in inode chunk */ xfs_inobt_rec_incore_t rec; /* btree record */ + struct xfs_perag *pag; mp = tp->t_mountp; @@ -1158,7 +1170,9 @@ xfs_difree( be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); - mp->m_perag[agno].pagi_freecount -= ilen - 1; + pag = xfs_perag_get(mp, agno); + pag->pagi_freecount -= ilen - 1; + xfs_perag_put(pag); up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); @@ -1189,7 +1203,9 @@ xfs_difree( be32_add_cpu(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); - mp->m_perag[agno].pagi_freecount++; + pag = xfs_perag_get(mp, agno); + pag->pagi_freecount++; + xfs_perag_put(pag); up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); } @@ -1379,7 +1395,6 @@ xfs_imap( XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); return XFS_ERROR(EINVAL); } - return 0; } @@ -1523,8 +1538,7 @@ xfs_ialloc_read_agi( return error; agi = XFS_BUF_TO_AGI(*bpp); - pag = &mp->m_perag[agno]; - + pag = xfs_perag_get(mp, agno); if (!pag->pagi_init) { pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_count = be32_to_cpu(agi->agi_count); @@ -1537,6 +1551,7 @@ xfs_ialloc_read_agi( */ ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); + xfs_perag_put(pag); return 0; } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bd3d81636d51..0317b000ab44 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2695,7 +2695,7 @@ xfs_iflush_cluster( ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); if (!ilist) - return 0; + goto out_put; mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask; @@ -2764,6 +2764,8 @@ xfs_iflush_cluster( out_free: read_unlock(&pag->pag_ici_lock); kmem_free(ilist); +out_put: + xfs_perag_put(pag); return 0; @@ -2807,6 +2809,7 @@ cluster_corrupt_out: */ xfs_iflush_abort(iq); kmem_free(ilist); + xfs_perag_put(pag); return XFS_ERROR(EFSCORRUPTED); } diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index eb403b40e120..9055b60730d0 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -438,18 +438,20 @@ xfs_initialize_perag( } /* This ag is preferred for inodes */ - pag = &mp->m_perag[index]; + pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; xfs_initialize_perag_icache(pag); + xfs_perag_put(pag); } } else { /* Setup default behavior for smaller filesystems */ for (index = 0; index < agcount; index++) { - pag = &mp->m_perag[index]; + pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; xfs_initialize_perag_icache(pag); + xfs_perag_put(pag); } } return index; @@ -731,12 +733,13 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) error = xfs_ialloc_pagi_init(mp, NULL, index); if (error) return error; - pag = &mp->m_perag[index]; + pag = xfs_perag_get(mp, index); ifree += pag->pagi_freecount; ialloc += pag->pagi_count; bfree += pag->pagf_freeblks; bfreelst += pag->pagf_flcount; btree += pag->pagf_btreeblks; + xfs_perag_put(pag); } /* * Overwrite incore superblock counters with just-read data -- GitLab From 1c1c6ebcf5284aee4910f3b906ac90c20e510c82 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:44 +0000 Subject: [PATCH 0732/3892] xfs: Replace per-ag array with a radix tree The use of an array for the per-ag structures requires reallocation of the array when growing the filesystem. This requires locking access to the array to avoid use after free situations, and the locking is difficult to get right. To avoid needing to reallocate an array, change the per-ag structures to an allocated object per ag and index them using a tree structure. The AGs are always densely indexed (hence the use of an array), but the number supported is 2^32 and lookups tend to be random and hence indexing needs to scale. A simple choice is a radix tree - it works well with this sort of index. This change also removes another large contiguous allocation from the mount/growfs path in XFS. The growing process now needs to change to only initialise the new AGs required for the extra space, and as such only needs to exclusively lock the tree for inserts. The rest of the code only needs to lock the tree while doing lookups, and hence this will remove all the deadlocks that currently occur on the m_perag_lock as it is now an innermost lock. The lock is also changed to a spinlock from a read/write lock as the hold time is now extremely short. To complete the picture, the per-ag structures will need to be reference counted to ensure that we don't free/modify them while they are still in use. This will be done in subsequent patch. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_alloc.c | 8 ------ fs/xfs/xfs_bmap.c | 7 +---- fs/xfs/xfs_filestream.c | 13 +++------ fs/xfs/xfs_fsops.c | 42 +++++++++++++-------------- fs/xfs/xfs_ialloc.c | 25 ++-------------- fs/xfs/xfs_itable.c | 4 --- fs/xfs/xfs_mount.c | 63 +++++++++++++++++++++++++++++++---------- fs/xfs/xfs_mount.h | 14 ++++++--- 8 files changed, 86 insertions(+), 90 deletions(-) diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 84070f2e0ba4..4d66bb75579c 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2276,7 +2276,6 @@ xfs_alloc_vextent( * These three force us into a single a.g. */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); - down_read(&mp->m_peraglock); args->pag = xfs_perag_get(mp, args->agno); args->minleft = 0; error = xfs_alloc_fix_freelist(args, 0); @@ -2286,14 +2285,12 @@ xfs_alloc_vextent( goto error0; } if (!args->agbp) { - up_read(&mp->m_peraglock); trace_xfs_alloc_vextent_noagbp(args); break; } args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); if ((error = xfs_alloc_ag_vextent(args))) goto error0; - up_read(&mp->m_peraglock); break; case XFS_ALLOCTYPE_START_BNO: /* @@ -2345,7 +2342,6 @@ xfs_alloc_vextent( * Loop over allocation groups twice; first time with * trylock set, second time without. */ - down_read(&mp->m_peraglock); for (;;) { args->pag = xfs_perag_get(mp, args->agno); if (no_min) args->minleft = 0; @@ -2408,7 +2404,6 @@ xfs_alloc_vextent( } xfs_perag_put(args->pag); } - up_read(&mp->m_peraglock); if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { if (args->agno == sagno) mp->m_agfrotor = (mp->m_agfrotor + 1) % @@ -2438,7 +2433,6 @@ xfs_alloc_vextent( return 0; error0: xfs_perag_put(args->pag); - up_read(&mp->m_peraglock); return error; } @@ -2463,7 +2457,6 @@ xfs_free_extent( args.agno = XFS_FSB_TO_AGNO(args.mp, bno); ASSERT(args.agno < args.mp->m_sb.sb_agcount); args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); - down_read(&args.mp->m_peraglock); args.pag = xfs_perag_get(args.mp, args.agno); if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) goto error0; @@ -2475,7 +2468,6 @@ xfs_free_extent( error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); error0: xfs_perag_put(args.pag); - up_read(&args.mp->m_peraglock); return error; } diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index a9b95d9cf2ad..7c6d9acd7154 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -2629,14 +2629,12 @@ xfs_bmap_btalloc( if (startag == NULLAGNUMBER) startag = ag = 0; notinit = 0; - down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, ag); while (blen < ap->alen) { if (!pag->pagf_init && (error = xfs_alloc_pagf_init(mp, args.tp, ag, XFS_ALLOC_FLAG_TRYLOCK))) { xfs_perag_put(pag); - up_read(&mp->m_peraglock); return error; } /* @@ -2669,10 +2667,8 @@ xfs_bmap_btalloc( error = xfs_filestream_new_ag(ap, &ag); xfs_perag_put(pag); - if (error) { - up_read(&mp->m_peraglock); + if (error) return error; - } /* loop again to set 'blen'*/ startag = NULLAGNUMBER; @@ -2688,7 +2684,6 @@ xfs_bmap_btalloc( pag = xfs_perag_get(mp, ag); } xfs_perag_put(pag); - up_read(&mp->m_peraglock); /* * Since the above loop did a BUF_TRYLOCK, it is * possible that there is space for this request. diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index e61f2aa088a9..914d00d0f119 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -253,8 +253,7 @@ next_ag: /* * Set the allocation group number for a file or a directory, updating inode - * references and per-AG references as appropriate. Must be called with the - * m_peraglock held in read mode. + * references and per-AG references as appropriate. */ static int _xfs_filestream_update_ag( @@ -456,10 +455,10 @@ xfs_filestream_unmount( } /* - * If the mount point's m_perag array is going to be reallocated, all + * If the mount point's m_perag tree is going to be modified, all * outstanding cache entries must be flushed to avoid accessing reference count * addresses that have been freed. The call to xfs_filestream_flush() must be - * made inside the block that holds the m_peraglock in write mode to do the + * made inside the block that holds the m_perag_lock in write mode to do the * reallocation. */ void @@ -531,7 +530,6 @@ xfs_filestream_associate( mp = pip->i_mount; cache = mp->m_filestream; - down_read(&mp->m_peraglock); /* * We have a problem, Houston. @@ -548,10 +546,8 @@ xfs_filestream_associate( * * So, if we can't get the iolock without sleeping then just give up */ - if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) { - up_read(&mp->m_peraglock); + if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) return 1; - } /* If the parent directory is already in the cache, use its AG. */ item = xfs_mru_cache_lookup(cache, pip->i_ino); @@ -606,7 +602,6 @@ exit_did_pick: exit: xfs_iunlock(pip, XFS_IOLOCK_EXCL); - up_read(&mp->m_peraglock); return -err; } diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index a13919a6a364..37a6f62c57b6 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -167,27 +167,14 @@ xfs_growfs_data_private( } new = nb - mp->m_sb.sb_dblocks; oagcount = mp->m_sb.sb_agcount; - if (nagcount > oagcount) { - void *new_perag, *old_perag; - - xfs_filestream_flush(mp); - - new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount, - KM_MAYFAIL); - if (!new_perag) - return XFS_ERROR(ENOMEM); - - down_write(&mp->m_peraglock); - memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount); - old_perag = mp->m_perag; - mp->m_perag = new_perag; - - mp->m_flags |= XFS_MOUNT_32BITINODES; - nagimax = xfs_initialize_perag(mp, nagcount); - up_write(&mp->m_peraglock); - kmem_free(old_perag); + /* allocate the new per-ag structures */ + if (nagcount > oagcount) { + error = xfs_initialize_perag(mp, nagcount, &nagimax); + if (error) + return error; } + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); tp->t_flags |= XFS_TRANS_RESERVE; if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), @@ -196,6 +183,11 @@ xfs_growfs_data_private( return error; } + /* + * Write new AG headers to disk. Non-transactional, but written + * synchronously so they are completed prior to the growfs transaction + * being logged. + */ nfree = 0; for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { /* @@ -359,6 +351,12 @@ xfs_growfs_data_private( goto error0; } } + + /* + * Update changed superblock fields transactionally. These are not + * seen by the rest of the world until the transaction commit applies + * them atomically to the superblock. + */ if (nagcount > oagcount) xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); if (nb > mp->m_sb.sb_dblocks) @@ -369,9 +367,9 @@ xfs_growfs_data_private( if (dpct) xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); error = xfs_trans_commit(tp, 0); - if (error) { + if (error) return error; - } + /* New allocation groups fully initialized, so update mount struct */ if (nagimax) mp->m_maxagi = nagimax; @@ -381,6 +379,8 @@ xfs_growfs_data_private( mp->m_maxicount = icount << mp->m_sb.sb_inopblog; } else mp->m_maxicount = 0; + + /* update secondary superblocks. */ for (agno = 1; agno < nagcount; agno++) { error = xfs_read_buf(mp, mp->m_ddev_targp, XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 884ee1367f46..52c9d006c0e6 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -383,11 +383,9 @@ xfs_ialloc_ag_alloc( newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_freecount, newlen); - down_read(&args.mp->m_peraglock); pag = xfs_perag_get(args.mp, agno); pag->pagi_freecount += newlen; xfs_perag_put(pag); - up_read(&args.mp->m_peraglock); agi->agi_newino = cpu_to_be32(newino); /* @@ -489,7 +487,6 @@ xfs_ialloc_ag_select( */ agno = pagno; flags = XFS_ALLOC_FLAG_TRYLOCK; - down_read(&mp->m_peraglock); for (;;) { pag = xfs_perag_get(mp, agno); if (!pag->pagi_init) { @@ -531,7 +528,6 @@ xfs_ialloc_ag_select( goto nextag; } xfs_perag_put(pag); - up_read(&mp->m_peraglock); return agbp; } } @@ -544,18 +540,14 @@ nextag: * No point in iterating over the rest, if we're shutting * down. */ - if (XFS_FORCED_SHUTDOWN(mp)) { - up_read(&mp->m_peraglock); + if (XFS_FORCED_SHUTDOWN(mp)) return NULL; - } agno++; if (agno >= agcount) agno = 0; if (agno == pagno) { - if (flags == 0) { - up_read(&mp->m_peraglock); + if (flags == 0) return NULL; - } flags = 0; } } @@ -777,16 +769,13 @@ nextag: *inop = NULLFSINO; return noroom ? ENOSPC : 0; } - down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, tagno); if (pag->pagi_inodeok == 0) { xfs_perag_put(pag); - up_read(&mp->m_peraglock); goto nextag; } error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); xfs_perag_put(pag); - up_read(&mp->m_peraglock); if (error) goto nextag; agi = XFS_BUF_TO_AGI(agbp); @@ -1015,9 +1004,7 @@ alloc_inode: goto error0; be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); - down_read(&mp->m_peraglock); pag->pagi_freecount--; - up_read(&mp->m_peraglock); error = xfs_check_agi_freecount(cur, agi); if (error) @@ -1100,9 +1087,7 @@ xfs_difree( /* * Get the allocation group header. */ - down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - up_read(&mp->m_peraglock); if (error) { cmn_err(CE_WARN, "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", @@ -1169,11 +1154,9 @@ xfs_difree( be32_add_cpu(&agi->agi_count, -ilen); be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); - down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, agno); pag->pagi_freecount -= ilen - 1; xfs_perag_put(pag); - up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); @@ -1202,11 +1185,9 @@ xfs_difree( */ be32_add_cpu(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); - down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, agno); pag->pagi_freecount++; xfs_perag_put(pag); - up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); } @@ -1328,9 +1309,7 @@ xfs_imap( xfs_buf_t *agbp; /* agi buffer */ int i; /* temp state */ - down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - up_read(&mp->m_peraglock); if (error) { xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " "xfs_ialloc_read_agi() returned " diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 62efab2f3839..940307a6a60b 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -420,9 +420,7 @@ xfs_bulkstat( while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { cond_resched(); bp = NULL; - down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); - up_read(&mp->m_peraglock); if (error) { /* * Skip this allocation group and go to the next one. @@ -849,9 +847,7 @@ xfs_inumbers( agbp = NULL; while (left > 0 && agno < mp->m_sb.sb_agcount) { if (agbp == NULL) { - down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); - up_read(&mp->m_peraglock); if (error) { /* * If we can't read the AGI of this ag, diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 9055b60730d0..c04dd83cb57c 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -209,13 +209,16 @@ STATIC void xfs_free_perag( xfs_mount_t *mp) { - if (mp->m_perag) { - int agno; + xfs_agnumber_t agno; + struct xfs_perag *pag; - for (agno = 0; agno < mp->m_maxagi; agno++) - if (mp->m_perag[agno].pagb_list) - kmem_free(mp->m_perag[agno].pagb_list); - kmem_free(mp->m_perag); + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + spin_lock(&mp->m_perag_lock); + pag = radix_tree_delete(&mp->m_perag_tree, agno); + spin_unlock(&mp->m_perag_lock); + ASSERT(pag); + kmem_free(pag->pagb_list); + kmem_free(pag); } } @@ -389,10 +392,11 @@ xfs_initialize_perag_icache( } } -xfs_agnumber_t +int xfs_initialize_perag( xfs_mount_t *mp, - xfs_agnumber_t agcount) + xfs_agnumber_t agcount, + xfs_agnumber_t *maxagi) { xfs_agnumber_t index, max_metadata; xfs_perag_t *pag; @@ -405,6 +409,33 @@ xfs_initialize_perag( agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); + /* + * Walk the current per-ag tree so we don't try to initialise AGs + * that already exist (growfs case). Allocate and insert all the + * AGs we don't find ready for initialisation. + */ + for (index = 0; index < agcount; index++) { + pag = xfs_perag_get(mp, index); + if (pag) { + xfs_perag_put(pag); + continue; + } + pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); + if (!pag) + return -ENOMEM; + if (radix_tree_preload(GFP_NOFS)) + return -ENOMEM; + spin_lock(&mp->m_perag_lock); + if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { + BUG(); + spin_unlock(&mp->m_perag_lock); + kmem_free(pag); + return -EEXIST; + } + spin_unlock(&mp->m_perag_lock); + radix_tree_preload_end(); + } + /* Clear the mount flag if no inode can overflow 32 bits * on this filesystem, or if specifically requested.. */ @@ -454,7 +485,9 @@ xfs_initialize_perag( xfs_perag_put(pag); } } - return index; + if (maxagi) + *maxagi = index; + return 0; } void @@ -1155,13 +1188,13 @@ xfs_mountfs( /* * Allocate and initialize the per-ag data. */ - init_rwsem(&mp->m_peraglock); - mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), - KM_MAYFAIL); - if (!mp->m_perag) + spin_lock_init(&mp->m_perag_lock); + INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS); + error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); + if (error) { + cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error); goto out_remove_uuid; - - mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); + } if (!sbp->sb_logblocks) { cmn_err(CE_WARN, "XFS: no log defined"); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f8a68a2319b5..cfa7a5d22e72 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -207,8 +207,8 @@ typedef struct xfs_mount { uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ uint m_in_maxlevels; /* max inobt btree levels. */ - struct xfs_perag *m_perag; /* per-ag accounting info */ - struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ + struct radix_tree_root m_perag_tree; /* per-ag accounting info */ + spinlock_t m_perag_lock; /* lock for m_perag_tree */ struct mutex m_growlock; /* growfs mutex */ int m_fixedfsid[2]; /* unchanged for life of FS */ uint m_dmevmask; /* DMI events for this FS */ @@ -389,7 +389,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) static inline struct xfs_perag * xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) { - return &mp->m_perag[agno]; + struct xfs_perag *pag; + + spin_lock(&mp->m_perag_lock); + pag = radix_tree_lookup(&mp->m_perag_tree, agno); + spin_unlock(&mp->m_perag_lock); + return pag; } static inline void @@ -450,7 +455,8 @@ extern struct xfs_dmops xfs_dmcore_xfs; #endif /* __KERNEL__ */ extern void xfs_mod_sb(struct xfs_trans *, __int64_t); -extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t); +extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, + xfs_agnumber_t *); extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); -- GitLab From aed3bb90abaf0b42e8c8747e192f7bb97f445279 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:45 +0000 Subject: [PATCH 0733/3892] xfs: Reference count per-ag structures Reference count the per-ag structures to ensure that we keep get/put pairs balanced. Assert that the reference counts are zero at unmount time to catch leaks. In future, reference counts will enable us to safely remove perag structures by allowing us to detect when they are no longer in use. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_ag.h | 4 ++-- fs/xfs/xfs_mount.c | 1 + fs/xfs/xfs_mount.h | 11 +++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 6702bd865811..18ae43f4255d 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -196,8 +196,8 @@ typedef struct xfs_perag_busy { #define XFS_PAGB_NUM_SLOTS 128 #endif -typedef struct xfs_perag -{ +typedef struct xfs_perag { + atomic_t pag_ref; /* perag reference count */ char pagf_init; /* this agf's entry is initialized */ char pagi_init; /* this agi's entry is initialized */ char pagf_metadata; /* the agf is preferred to be metadata */ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index c04dd83cb57c..f241fec26070 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -215,6 +215,7 @@ xfs_free_perag( for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { spin_lock(&mp->m_perag_lock); pag = radix_tree_delete(&mp->m_perag_tree, agno); + ASSERT(atomic_read(&pag->pag_ref) == 0); spin_unlock(&mp->m_perag_lock); ASSERT(pag); kmem_free(pag->pagb_list); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index cfa7a5d22e72..16b22120b98f 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -384,7 +384,7 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) } /* - * perag get/put wrappers for eventual ref counting + * perag get/put wrappers for ref counting */ static inline struct xfs_perag * xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) @@ -393,6 +393,12 @@ xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) spin_lock(&mp->m_perag_lock); pag = radix_tree_lookup(&mp->m_perag_tree, agno); + if (pag) { + ASSERT(atomic_read(&pag->pag_ref) >= 0); + /* catch leaks in the positive direction during testing */ + ASSERT(atomic_read(&pag->pag_ref) < 1000); + atomic_inc(&pag->pag_ref); + } spin_unlock(&mp->m_perag_lock); return pag; } @@ -400,7 +406,8 @@ xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) static inline void xfs_perag_put(struct xfs_perag *pag) { - /* nothing to see here, move along */ + ASSERT(atomic_read(&pag->pag_ref) > 0); + atomic_dec(&pag->pag_ref); } /* -- GitLab From 0fa800fbd549736dfdc1d7761f87e33dc8cd973b Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:46 +0000 Subject: [PATCH 0734/3892] xfs: Add trace points for per-ag refcount debugging. Uninline xfs_perag_{get,put} so that tracepoints can be inserted into them to speed debugging of reference count problems. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_trace.h | 27 +++++++++++++++++++++++++++ fs/xfs/xfs_ag.h | 2 ++ fs/xfs/xfs_mount.c | 34 ++++++++++++++++++++++++++++++++++ fs/xfs/xfs_mount.h | 25 ++----------------------- 4 files changed, 65 insertions(+), 23 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index 3353aef50530..1bb09e70b2eb 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h @@ -78,6 +78,33 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class, ) ) +#define DEFINE_PERAG_REF_EVENT(name) \ +TRACE_EVENT(name, \ + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \ + unsigned long caller_ip), \ + TP_ARGS(mp, agno, refcount, caller_ip), \ + TP_STRUCT__entry( \ + __field(dev_t, dev) \ + __field(xfs_agnumber_t, agno) \ + __field(int, refcount) \ + __field(unsigned long, caller_ip) \ + ), \ + TP_fast_assign( \ + __entry->dev = mp->m_super->s_dev; \ + __entry->agno = agno; \ + __entry->refcount = refcount; \ + __entry->caller_ip = caller_ip; \ + ), \ + TP_printk("dev %d:%d agno %u refcount %d caller %pf", \ + MAJOR(__entry->dev), MINOR(__entry->dev), \ + __entry->agno, \ + __entry->refcount, \ + (char *)__entry->caller_ip) \ +); + +DEFINE_PERAG_REF_EVENT(xfs_perag_get) +DEFINE_PERAG_REF_EVENT(xfs_perag_put) + #define DEFINE_ATTR_LIST_EVENT(name) \ DEFINE_EVENT(xfs_attr_list_class, name, \ TP_PROTO(struct xfs_attr_list_context *ctx), \ diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 18ae43f4255d..963bc2700bf7 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -197,6 +197,8 @@ typedef struct xfs_perag_busy { #endif typedef struct xfs_perag { + struct xfs_mount *pag_mount; /* owner filesystem */ + xfs_agnumber_t pag_agno; /* AG this structure belongs to */ atomic_t pag_ref; /* perag reference count */ char pagf_init; /* this agf's entry is initialized */ char pagi_init; /* this agi's entry is initialized */ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index f241fec26070..049dbc71c28e 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -200,6 +200,38 @@ xfs_uuid_unmount( } +/* + * Reference counting access wrappers to the perag structures. + */ +struct xfs_perag * +xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) +{ + struct xfs_perag *pag; + int ref = 0; + + spin_lock(&mp->m_perag_lock); + pag = radix_tree_lookup(&mp->m_perag_tree, agno); + if (pag) { + ASSERT(atomic_read(&pag->pag_ref) >= 0); + /* catch leaks in the positive direction during testing */ + ASSERT(atomic_read(&pag->pag_ref) < 1000); + ref = atomic_inc_return(&pag->pag_ref); + } + spin_unlock(&mp->m_perag_lock); + trace_xfs_perag_get(mp, agno, ref, _RET_IP_); + return pag; +} + +void +xfs_perag_put(struct xfs_perag *pag) +{ + int ref; + + ASSERT(atomic_read(&pag->pag_ref) > 0); + ref = atomic_dec_return(&pag->pag_ref); + trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_); +} + /* * Free up the resources associated with a mount structure. Assume that * the structure was initially zeroed, so we can tell which fields got @@ -433,6 +465,8 @@ xfs_initialize_perag( kmem_free(pag); return -EEXIST; } + pag->pag_agno = index; + pag->pag_mount = mp; spin_unlock(&mp->m_perag_lock); radix_tree_preload_end(); } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 16b22120b98f..e62fd1cde464 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -386,29 +386,8 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) /* * perag get/put wrappers for ref counting */ -static inline struct xfs_perag * -xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - - spin_lock(&mp->m_perag_lock); - pag = radix_tree_lookup(&mp->m_perag_tree, agno); - if (pag) { - ASSERT(atomic_read(&pag->pag_ref) >= 0); - /* catch leaks in the positive direction during testing */ - ASSERT(atomic_read(&pag->pag_ref) < 1000); - atomic_inc(&pag->pag_ref); - } - spin_unlock(&mp->m_perag_lock); - return pag; -} - -static inline void -xfs_perag_put(struct xfs_perag *pag) -{ - ASSERT(atomic_read(&pag->pag_ref) > 0); - atomic_dec(&pag->pag_ref); -} +struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno); +void xfs_perag_put(struct xfs_perag *pag); /* * Per-cpu superblock locking functions -- GitLab From b657fc82a3ca6d7ad16a59e81765f0fb0e86cdbb Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:47 +0000 Subject: [PATCH 0735/3892] xfs: Kill filestreams cache flush The filestreams cache flush is not needed in the sync code as it does not affect data writeback, and it is now not used by the growfs code, either, so kill it. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_sync.c | 3 --- fs/xfs/xfs_filestream.c | 14 -------------- fs/xfs/xfs_filestream.h | 1 - fs/xfs/xfs_mru_cache.c | 2 +- fs/xfs/xfs_mru_cache.h | 1 - 5 files changed, 1 insertion(+), 20 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index cc964faf12e9..b58f8412dfe2 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -451,9 +451,6 @@ xfs_quiesce_data( xfs_sync_data(mp, SYNC_WAIT); xfs_qm_sync(mp, SYNC_WAIT); - /* drop inode references pinned by filestreams */ - xfs_filestream_flush(mp); - /* write superblock and hoover up shutdown errors */ error = xfs_sync_fsdata(mp, SYNC_WAIT); diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 914d00d0f119..390850ee6603 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -454,20 +454,6 @@ xfs_filestream_unmount( xfs_mru_cache_destroy(mp->m_filestream); } -/* - * If the mount point's m_perag tree is going to be modified, all - * outstanding cache entries must be flushed to avoid accessing reference count - * addresses that have been freed. The call to xfs_filestream_flush() must be - * made inside the block that holds the m_perag_lock in write mode to do the - * reallocation. - */ -void -xfs_filestream_flush( - xfs_mount_t *mp) -{ - xfs_mru_cache_flush(mp->m_filestream); -} - /* * Return the AG of the filestream the file or directory belongs to, or * NULLAGNUMBER otherwise. diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h index 58378b2ea033..260f757bbc5d 100644 --- a/fs/xfs/xfs_filestream.h +++ b/fs/xfs/xfs_filestream.h @@ -135,7 +135,6 @@ int xfs_filestream_init(void); void xfs_filestream_uninit(void); int xfs_filestream_mount(struct xfs_mount *mp); void xfs_filestream_unmount(struct xfs_mount *mp); -void xfs_filestream_flush(struct xfs_mount *mp); xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip); int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip); void xfs_filestream_deassociate(struct xfs_inode *ip); diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index 4b0613d99faa..45ce15dc5b2b 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -398,7 +398,7 @@ exit: * guaranteed that all the free functions for all the elements have finished * executing and the reaper is not running. */ -void +static void xfs_mru_cache_flush( xfs_mru_cache_t *mru) { diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h index 5d439f34b0c9..36dd3ec8b4eb 100644 --- a/fs/xfs/xfs_mru_cache.h +++ b/fs/xfs/xfs_mru_cache.h @@ -42,7 +42,6 @@ void xfs_mru_cache_uninit(void); int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms, unsigned int grp_count, xfs_mru_cache_free_func_t free_func); -void xfs_mru_cache_flush(xfs_mru_cache_t *mru); void xfs_mru_cache_destroy(struct xfs_mru_cache *mru); int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key, void *value); -- GitLab From 8b26c5825e023b1bccac7afd174ebe55b8905cb1 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:48 +0000 Subject: [PATCH 0736/3892] xfs: handle ENOMEM correctly during initialisation of perag structures Add proper error handling in case an error occurs while initializing new perag structures for a mount point. The mount structure is restored to its previous state by deleting and freeing any perag structures added during the call. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_mount.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 049dbc71c28e..be643e588067 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -432,11 +432,13 @@ xfs_initialize_perag( xfs_agnumber_t *maxagi) { xfs_agnumber_t index, max_metadata; + xfs_agnumber_t first_initialised = 0; xfs_perag_t *pag; xfs_agino_t agino; xfs_ino_t ino; xfs_sb_t *sbp = &mp->m_sb; xfs_ino_t max_inum = XFS_MAXINUMBER_32; + int error = -ENOMEM; /* Check to see if the filesystem can overflow 32 bit inodes */ agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); @@ -453,17 +455,20 @@ xfs_initialize_perag( xfs_perag_put(pag); continue; } + if (!first_initialised) + first_initialised = index; pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); if (!pag) - return -ENOMEM; + goto out_unwind; if (radix_tree_preload(GFP_NOFS)) - return -ENOMEM; + goto out_unwind; spin_lock(&mp->m_perag_lock); if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { BUG(); spin_unlock(&mp->m_perag_lock); - kmem_free(pag); - return -EEXIST; + radix_tree_preload_end(); + error = -EEXIST; + goto out_unwind; } pag->pag_agno = index; pag->pag_mount = mp; @@ -523,6 +528,14 @@ xfs_initialize_perag( if (maxagi) *maxagi = index; return 0; + +out_unwind: + kmem_free(pag); + for (; index > first_initialised; index--) { + pag = radix_tree_delete(&mp->m_perag_tree, index); + kmem_free(pag); + } + return error; } void -- GitLab From e57336ff7fc7520bec7b3a7741043bdebaf622ea Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 11 Jan 2010 11:47:49 +0000 Subject: [PATCH 0737/3892] xfs: embed the pagb_list array in the perag structure Now that the perag structure is allocated memory rather than held in an array, we don't need to have the busy extent array external to the structure. Embed it into the perag structure to avoid needing an extra allocation when setting up. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_ag.h | 10 ++-------- fs/xfs/xfs_alloc.c | 4 ++-- fs/xfs/xfs_mount.c | 3 +-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 963bc2700bf7..b1a5a1ff88ea 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -187,14 +187,8 @@ typedef struct xfs_perag_busy { /* * Per-ag incore structure, copies of information in agf and agi, * to improve the performance of allocation group selection. - * - * pick sizes which fit in allocation buckets well */ -#if (BITS_PER_LONG == 32) -#define XFS_PAGB_NUM_SLOTS 84 -#elif (BITS_PER_LONG == 64) #define XFS_PAGB_NUM_SLOTS 128 -#endif typedef struct xfs_perag { struct xfs_mount *pag_mount; /* owner filesystem */ @@ -212,8 +206,6 @@ typedef struct xfs_perag { __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ xfs_agino_t pagi_freecount; /* number of free inodes */ xfs_agino_t pagi_count; /* number of allocated inodes */ - int pagb_count; /* pagb slots in use */ - xfs_perag_busy_t *pagb_list; /* unstable blocks */ /* * Inode allocation search lookup optimisation. @@ -232,6 +224,8 @@ typedef struct xfs_perag { rwlock_t pag_ici_lock; /* incore inode lock */ struct radix_tree_root pag_ici_root; /* incore inode cache root */ #endif + int pagb_count; /* pagb slots in use */ + xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */ } xfs_perag_t; /* diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4d66bb75579c..8aa181d6dd7d 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2200,8 +2200,8 @@ xfs_alloc_read_agf( pag->pagf_levels[XFS_BTNUM_CNTi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); spin_lock_init(&pag->pagb_lock); - pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS * - sizeof(xfs_perag_busy_t), KM_SLEEP); + pag->pagb_count = 0; + memset(pag->pagb_list, 0, sizeof(pag->pagb_list)); pag->pagf_init = 1; } #ifdef DEBUG diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index be643e588067..0df5045abd3b 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -247,10 +247,9 @@ xfs_free_perag( for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { spin_lock(&mp->m_perag_lock); pag = radix_tree_delete(&mp->m_perag_tree, agno); + ASSERT(pag); ASSERT(atomic_read(&pag->pag_ref) == 0); spin_unlock(&mp->m_perag_lock); - ASSERT(pag); - kmem_free(pag->pagb_list); kmem_free(pag); } } -- GitLab From 873ff5501d8cd1a21045d6c1da34f0c3876bc235 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jan 2010 22:17:57 +0000 Subject: [PATCH 0738/3892] xfs: clean up log buffer writes Don't bother using XFS_bwrite as it doesn't provide much code for our use case. Instead opencode it and fold xlog_bdstrat_cb into the new xlog_bdstrat helper. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.h | 2 -- fs/xfs/xfs_log.c | 67 +++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index a34c7b54822d..c20a76001867 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -408,8 +408,6 @@ static inline int XFS_bwrite(xfs_buf_t *bp) return error; } -#define XFS_bdstrat(bp) xfs_buf_iorequest(bp) - #define xfs_iowait(bp) xfs_buf_iowait(bp) #define xfs_baread(target, rablkno, ralen) \ diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 600b5b06aaeb..0d17516fbb13 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -50,7 +50,6 @@ kmem_zone_t *xfs_log_ticket_zone; (off) += (bytes);} /* Local miscellaneous function prototypes */ -STATIC int xlog_bdstrat_cb(struct xfs_buf *); STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, xlog_in_core_t **, xfs_lsn_t *); STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, @@ -987,35 +986,6 @@ xlog_iodone(xfs_buf_t *bp) } /* xlog_iodone */ -/* - * The bdstrat callback function for log bufs. This gives us a central - * place to trap bufs in case we get hit by a log I/O error and need to - * shutdown. Actually, in practice, even when we didn't get a log error, - * we transition the iclogs to IOERROR state *after* flushing all existing - * iclogs to disk. This is because we don't want anymore new transactions to be - * started or completed afterwards. - */ -STATIC int -xlog_bdstrat_cb(struct xfs_buf *bp) -{ - xlog_in_core_t *iclog; - - iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); - - if ((iclog->ic_state & XLOG_STATE_IOERROR) == 0) { - /* note for irix bstrat will need struct bdevsw passed - * Fix the following macro if the code ever is merged - */ - XFS_bdstrat(bp); - return 0; - } - - XFS_BUF_ERROR(bp, EIO); - XFS_BUF_STALE(bp); - xfs_biodone(bp); - return XFS_ERROR(EIO); -} - /* * Return size of each in-core log record buffer. * @@ -1158,7 +1128,6 @@ xlog_alloc_log(xfs_mount_t *mp, if (!bp) goto out_free_log; XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); - XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); @@ -1196,7 +1165,6 @@ xlog_alloc_log(xfs_mount_t *mp, if (!XFS_BUF_CPSEMA(bp)) ASSERT(0); XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); - XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); iclog->ic_bp = bp; iclog->ic_data = bp->b_addr; @@ -1343,6 +1311,37 @@ xlog_grant_push_ail(xfs_mount_t *mp, xfs_trans_ail_push(log->l_ailp, threshold_lsn); } /* xlog_grant_push_ail */ +/* + * The bdstrat callback function for log bufs. This gives us a central + * place to trap bufs in case we get hit by a log I/O error and need to + * shutdown. Actually, in practice, even when we didn't get a log error, + * we transition the iclogs to IOERROR state *after* flushing all existing + * iclogs to disk. This is because we don't want anymore new transactions to be + * started or completed afterwards. + */ +STATIC int +xlog_bdstrat( + struct xfs_buf *bp) +{ + struct xlog_in_core *iclog; + + iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); + if (iclog->ic_state & XLOG_STATE_IOERROR) { + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_STALE(bp); + xfs_biodone(bp); + /* + * It would seem logical to return EIO here, but we rely on + * the log state machine to propagate I/O errors instead of + * doing it here. + */ + return 0; + } + + bp->b_flags |= _XBF_RUN_QUEUES; + xfs_buf_iorequest(bp); + return 0; +} /* * Flush out the in-core log (iclog) to the on-disk log in an asynchronous @@ -1462,7 +1461,7 @@ xlog_sync(xlog_t *log, */ XFS_BUF_WRITE(bp); - if ((error = XFS_bwrite(bp))) { + if ((error = xlog_bdstrat(bp))) { xfs_ioerror_alert("xlog_sync", log->l_mp, bp, XFS_BUF_ADDR(bp)); return error; @@ -1502,7 +1501,7 @@ xlog_sync(xlog_t *log, /* account for internal log which doesn't start at block #0 */ XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); XFS_BUF_WRITE(bp); - if ((error = XFS_bwrite(bp))) { + if ((error = xlog_bdstrat(bp))) { xfs_ioerror_alert("xlog_sync (split)", log->l_mp, bp, XFS_BUF_ADDR(bp)); return error; -- GitLab From 64e0bc7d2a6609ad265757a600e2a0d93c8adb47 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jan 2010 22:17:58 +0000 Subject: [PATCH 0739/3892] xfs: clean up xfs_bwrite Fold XFS_bwrite into it's only caller, xfs_bwrite and move it into xfs_buf.c instead of leaving it as a fairly large inline function. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 27 +++++++++++++++++++++++++++ fs/xfs/linux-2.6/xfs_buf.h | 19 +------------------ fs/xfs/xfs_rw.c | 31 ------------------------------- fs/xfs/xfs_rw.h | 1 - 4 files changed, 28 insertions(+), 50 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 18ae3ba8f78a..492465c6e0b4 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1050,6 +1050,33 @@ xfs_buf_ioerror( trace_xfs_buf_ioerror(bp, error, _RET_IP_); } +int +xfs_bwrite( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + int iowait = (bp->b_flags & XBF_ASYNC) == 0; + int error = 0; + + bp->b_strat = xfs_bdstrat_cb; + bp->b_mount = mp; + bp->b_flags |= XBF_WRITE; + if (!iowait) + bp->b_flags |= _XBF_RUN_QUEUES; + + xfs_buf_delwri_dequeue(bp); + xfs_buf_iostrategy(bp); + + if (iowait) { + error = xfs_buf_iowait(bp); + if (error) + xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); + xfs_buf_relse(bp); + } + + return error; +} + int xfs_bawrite( void *mp, diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index c20a76001867..f69b8e714a11 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -232,6 +232,7 @@ extern void xfs_buf_lock(xfs_buf_t *); extern void xfs_buf_unlock(xfs_buf_t *); /* Buffer Read and Write Routines */ +extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); extern int xfs_bawrite(void *mp, xfs_buf_t *bp); extern void xfs_bdwrite(void *mp, xfs_buf_t *bp); extern void xfs_buf_ioend(xfs_buf_t *, int); @@ -390,24 +391,6 @@ static inline void xfs_buf_relse(xfs_buf_t *bp) #define xfs_biozero(bp, off, len) \ xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO) - -static inline int XFS_bwrite(xfs_buf_t *bp) -{ - int iowait = (bp->b_flags & XBF_ASYNC) == 0; - int error = 0; - - if (!iowait) - bp->b_flags |= _XBF_RUN_QUEUES; - - xfs_buf_delwri_dequeue(bp); - xfs_buf_iostrategy(bp); - if (iowait) { - error = xfs_buf_iowait(bp); - xfs_buf_relse(bp); - } - return error; -} - #define xfs_iowait(bp) xfs_buf_iowait(bp) #define xfs_baread(target, rablkno, ralen) \ diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index 5aa07caea5f1..9d933a10d6bb 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c @@ -305,37 +305,6 @@ xfs_read_buf( return (error); } -/* - * Wrapper around bwrite() so that we can trap - * write errors, and act accordingly. - */ -int -xfs_bwrite( - struct xfs_mount *mp, - struct xfs_buf *bp) -{ - int error; - - /* - * XXXsup how does this work for quotas. - */ - XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); - bp->b_mount = mp; - XFS_BUF_WRITE(bp); - - if ((error = XFS_bwrite(bp))) { - ASSERT(mp); - /* - * Cannot put a buftrace here since if the buffer is not - * B_HOLD then we will brelse() the buffer before returning - * from bwrite and we could be tracing a buffer that has - * been reused. - */ - xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); - } - return (error); -} - /* * helper function to extract extent size hint from inode */ diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index 571f2174435c..ff68eb5e738e 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h @@ -40,7 +40,6 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) * Prototypes for functions in xfs_rw.c. */ extern int xfs_write_clear_setuid(struct xfs_inode *ip); -extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); extern int xfs_bioerror(struct xfs_buf *bp); extern int xfs_bioerror_relse(struct xfs_buf *bp); extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp, -- GitLab From 4e23471a3f3aba885ea70100db47ccacb5f069f6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jan 2010 22:17:56 +0000 Subject: [PATCH 0740/3892] xfs: move more buffer helpers into xfs_buf.c Move xfsbdstrat and xfs_bdstrat_cb from xfs_lrw.c and xfs_bioerror and xfs_bioerror_relse from xfs_rw.c into xfs_buf.c. This also means xfs_bioerror and xfs_bioerror_relse can be marked static now. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 120 +++++++++++++++++++++++++++++++++++++ fs/xfs/linux-2.6/xfs_buf.h | 4 ++ fs/xfs/linux-2.6/xfs_lrw.c | 47 --------------- fs/xfs/linux-2.6/xfs_lrw.h | 3 - fs/xfs/xfs_rw.c | 82 ------------------------- fs/xfs/xfs_rw.h | 2 - 6 files changed, 124 insertions(+), 134 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 492465c6e0b4..158fad4550df 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1112,6 +1112,126 @@ xfs_bdwrite( xfs_buf_delwri_queue(bp, 1); } +/* + * Called when we want to stop a buffer from getting written or read. + * We attach the EIO error, muck with its flags, and call biodone + * so that the proper iodone callbacks get called. + */ +STATIC int +xfs_bioerror( + xfs_buf_t *bp) +{ +#ifdef XFSERRORDEBUG + ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone); +#endif + + /* + * No need to wait until the buffer is unpinned, we aren't flushing it. + */ + XFS_BUF_ERROR(bp, EIO); + + /* + * We're calling biodone, so delete XBF_DONE flag. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_UNDONE(bp); + XFS_BUF_STALE(bp); + + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + xfs_biodone(bp); + + return EIO; +} + +/* + * Same as xfs_bioerror, except that we are releasing the buffer + * here ourselves, and avoiding the biodone call. + * This is meant for userdata errors; metadata bufs come with + * iodone functions attached, so that we can track down errors. + */ +STATIC int +xfs_bioerror_relse( + struct xfs_buf *bp) +{ + int64_t fl = XFS_BUF_BFLAGS(bp); + /* + * No need to wait until the buffer is unpinned. + * We aren't flushing it. + * + * chunkhold expects B_DONE to be set, whether + * we actually finish the I/O or not. We don't want to + * change that interface. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_STALE(bp); + XFS_BUF_CLR_IODONE_FUNC(bp); + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + if (!(fl & XFS_B_ASYNC)) { + /* + * Mark b_error and B_ERROR _both_. + * Lot's of chunkcache code assumes that. + * There's no reason to mark error for + * ASYNC buffers. + */ + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_FINISH_IOWAIT(bp); + } else { + xfs_buf_relse(bp); + } + + return EIO; +} + + +/* + * All xfs metadata buffers except log state machine buffers + * get this attached as their b_bdstrat callback function. + * This is so that we can catch a buffer + * after prematurely unpinning it to forcibly shutdown the filesystem. + */ +int +xfs_bdstrat_cb( + struct xfs_buf *bp) +{ + if (XFS_FORCED_SHUTDOWN(bp->b_mount)) { + trace_xfs_bdstrat_shut(bp, _RET_IP_); + /* + * Metadata write that didn't get logged but + * written delayed anyway. These aren't associated + * with a transaction, and can be ignored. + */ + if (!bp->b_iodone && !XFS_BUF_ISREAD(bp)) + return xfs_bioerror_relse(bp); + else + return xfs_bioerror(bp); + } + + xfs_buf_iorequest(bp); + return 0; +} + +/* + * Wrapper around bdstrat so that we can stop data from going to disk in case + * we are shutting down the filesystem. Typically user data goes thru this + * path; one of the exceptions is the superblock. + */ +void +xfsbdstrat( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + if (XFS_FORCED_SHUTDOWN(mp)) { + trace_xfs_bdstrat_shut(bp, _RET_IP_); + xfs_bioerror_relse(bp); + return; + } + + xfs_buf_iorequest(bp); +} + STATIC void _xfs_buf_ioend( xfs_buf_t *bp, diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index f69b8e714a11..9a29d18656ec 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -235,6 +235,10 @@ extern void xfs_buf_unlock(xfs_buf_t *); extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); extern int xfs_bawrite(void *mp, xfs_buf_t *bp); extern void xfs_bdwrite(void *mp, xfs_buf_t *bp); + +extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *); +extern int xfs_bdstrat_cb(struct xfs_buf *); + extern void xfs_buf_ioend(xfs_buf_t *, int); extern void xfs_buf_ioerror(xfs_buf_t *, int); extern int xfs_buf_iorequest(xfs_buf_t *); diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 0d32457abef1..c80fa00d2ad7 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -783,53 +783,6 @@ write_retry: return -error; } -/* - * All xfs metadata buffers except log state machine buffers - * get this attached as their b_bdstrat callback function. - * This is so that we can catch a buffer - * after prematurely unpinning it to forcibly shutdown the filesystem. - */ -int -xfs_bdstrat_cb(struct xfs_buf *bp) -{ - if (XFS_FORCED_SHUTDOWN(bp->b_mount)) { - trace_xfs_bdstrat_shut(bp, _RET_IP_); - /* - * Metadata write that didn't get logged but - * written delayed anyway. These aren't associated - * with a transaction, and can be ignored. - */ - if (XFS_BUF_IODONE_FUNC(bp) == NULL && - (XFS_BUF_ISREAD(bp)) == 0) - return (xfs_bioerror_relse(bp)); - else - return (xfs_bioerror(bp)); - } - - xfs_buf_iorequest(bp); - return 0; -} - -/* - * Wrapper around bdstrat so that we can stop data from going to disk in case - * we are shutting down the filesystem. Typically user data goes thru this - * path; one of the exceptions is the superblock. - */ -void -xfsbdstrat( - struct xfs_mount *mp, - struct xfs_buf *bp) -{ - ASSERT(mp); - if (!XFS_FORCED_SHUTDOWN(mp)) { - xfs_buf_iorequest(bp); - return; - } - - trace_xfs_bdstrat_shut(bp, _RET_IP_); - xfs_bioerror_relse(bp); -} - /* * If the underlying (data/log/rt) device is readonly, there are some * operations that cannot proceed. diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index d1f7789c7ffb..342ae8c0d011 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -22,9 +22,6 @@ struct xfs_mount; struct xfs_inode; struct xfs_buf; -/* errors from xfsbdstrat() must be extracted from the buffer */ -extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *); -extern int xfs_bdstrat_cb(struct xfs_buf *); extern int xfs_dev_is_read_only(struct xfs_mount *, char *); extern int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index 9d933a10d6bb..abb2c458b148 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c @@ -153,88 +153,6 @@ xfs_do_force_shutdown( } } - -/* - * Called when we want to stop a buffer from getting written or read. - * We attach the EIO error, muck with its flags, and call biodone - * so that the proper iodone callbacks get called. - */ -int -xfs_bioerror( - xfs_buf_t *bp) -{ - -#ifdef XFSERRORDEBUG - ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone); -#endif - - /* - * No need to wait until the buffer is unpinned. - * We aren't flushing it. - */ - XFS_BUF_ERROR(bp, EIO); - /* - * We're calling biodone, so delete B_DONE flag. Either way - * we have to call the iodone callback, and calling biodone - * probably is the best way since it takes care of - * GRIO as well. - */ - XFS_BUF_UNREAD(bp); - XFS_BUF_UNDELAYWRITE(bp); - XFS_BUF_UNDONE(bp); - XFS_BUF_STALE(bp); - - XFS_BUF_CLR_BDSTRAT_FUNC(bp); - xfs_biodone(bp); - - return (EIO); -} - -/* - * Same as xfs_bioerror, except that we are releasing the buffer - * here ourselves, and avoiding the biodone call. - * This is meant for userdata errors; metadata bufs come with - * iodone functions attached, so that we can track down errors. - */ -int -xfs_bioerror_relse( - xfs_buf_t *bp) -{ - int64_t fl; - - ASSERT(XFS_BUF_IODONE_FUNC(bp) != xfs_buf_iodone_callbacks); - ASSERT(XFS_BUF_IODONE_FUNC(bp) != xlog_iodone); - - fl = XFS_BUF_BFLAGS(bp); - /* - * No need to wait until the buffer is unpinned. - * We aren't flushing it. - * - * chunkhold expects B_DONE to be set, whether - * we actually finish the I/O or not. We don't want to - * change that interface. - */ - XFS_BUF_UNREAD(bp); - XFS_BUF_UNDELAYWRITE(bp); - XFS_BUF_DONE(bp); - XFS_BUF_STALE(bp); - XFS_BUF_CLR_IODONE_FUNC(bp); - XFS_BUF_CLR_BDSTRAT_FUNC(bp); - if (!(fl & XFS_B_ASYNC)) { - /* - * Mark b_error and B_ERROR _both_. - * Lot's of chunkcache code assumes that. - * There's no reason to mark error for - * ASYNC buffers. - */ - XFS_BUF_ERROR(bp, EIO); - XFS_BUF_FINISH_IOWAIT(bp); - } else { - xfs_buf_relse(bp); - } - return (EIO); -} - /* * Prints out an ALERT message about I/O error. */ diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index ff68eb5e738e..a54c3b7cd376 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h @@ -40,8 +40,6 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) * Prototypes for functions in xfs_rw.c. */ extern int xfs_write_clear_setuid(struct xfs_inode *ip); -extern int xfs_bioerror(struct xfs_buf *bp); -extern int xfs_bioerror_relse(struct xfs_buf *bp); extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp, xfs_daddr_t blkno, int len, uint flags, struct xfs_buf **bpp); -- GitLab From 93895757df4ebe22c98b9128b98ebf8cec972c60 Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Thu, 14 Jan 2010 23:20:31 +0100 Subject: [PATCH 0741/3892] mac80211: Fixed netif_tx_wake_all_queues in IBSS mode When ieee80211_offchannel_return is called, it needs to re-enabled TX queues that have been stopped in ieee80211_offchannel_stop_beaconing or ieee80211_offchannel_stop_station. It happens if we are doing a scan with an IBSS interface. In this case, the interface stopped transmitting. Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- net/mac80211/offchannel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 1facfeb1f79b..c36b1911987a 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -153,9 +153,11 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) ieee80211_offchannel_ps_disable(sdata); - netif_tx_wake_all_queues(sdata->dev); } + if (sdata->vif.type != NL80211_IFTYPE_MONITOR) + netif_tx_wake_all_queues(sdata->dev); + /* re-enable beaconing */ if (enable_beaconing && (sdata->vif.type == NL80211_IFTYPE_AP || -- GitLab From 84920e3e47f654a22b540606fb8c1ab90b870942 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 14 Jan 2010 20:08:20 -0500 Subject: [PATCH 0742/3892] cfg80211: make regulatory_hint_11d() band specific In practice APs do not send country IE channel triplets for channels the AP is not operating on and if they were to do so they would have to use the regulatory extension which we currently do not process. No AP has been seen in practice that does this though so just drop those country IEs. Additionally it has been noted the first series of country IE channels triplets are specific to the band the AP sends. Propagate the band on which the country IE was found on reject the country IE then if the triplets are ever oustide of the band. Although we now won't process country IE information with multiple band information we leave the intersection work as is as it is technically possible for someone to want to eventually process these type of country IEs with regulatory extensions. Cc: Jouni Malinen Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 74 +++++++++++++++++++++++++++++++++------------- net/wireless/reg.h | 11 +++++++ net/wireless/sme.c | 1 + 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f3b77f7b8e3d..5f8071de7950 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -484,6 +484,34 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, #undef ONE_GHZ_IN_KHZ } +/* + * This is a work around for sanity checking ieee80211_channel_to_frequency()'s + * work. ieee80211_channel_to_frequency() can for example currently provide a + * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be + * an AP providing channel 8 on a country IE triplet when it sent this on the + * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz + * channel. + * + * This can be removed once ieee80211_channel_to_frequency() takes in a band. + */ +static bool chan_in_band(int chan, enum ieee80211_band band) +{ + int center_freq = ieee80211_channel_to_frequency(chan); + + switch (band) { + case IEEE80211_BAND_2GHZ: + if (center_freq <= 2484) + return true; + return false; + case IEEE80211_BAND_5GHZ: + if (center_freq >= 5005) + return true; + return false; + default: + return false; + } +} + /* * Some APs may send a country IE triplet for each channel they * support and while this is completely overkill and silly we still @@ -532,7 +560,8 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, * Returns 0 if the IE has been found to be invalid in the middle * somewhere. */ -static int max_subband_chan(int orig_cur_chan, +static int max_subband_chan(enum ieee80211_band band, + int orig_cur_chan, int orig_end_channel, s8 orig_max_power, u8 **country_ie, @@ -541,7 +570,6 @@ static int max_subband_chan(int orig_cur_chan, u8 *triplets_start = *country_ie; u8 len_at_triplet = *country_ie_len; int end_subband_chan = orig_end_channel; - enum ieee80211_band band; /* * We'll deal with padding for the caller unless @@ -557,17 +585,14 @@ static int max_subband_chan(int orig_cur_chan, *country_ie += 3; *country_ie_len -= 3; - if (orig_cur_chan <= 14) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; + if (!chan_in_band(orig_cur_chan, band)) + return 0; while (*country_ie_len >= 3) { int end_channel = 0; struct ieee80211_country_ie_triplet *triplet = (struct ieee80211_country_ie_triplet *) *country_ie; int cur_channel = 0, next_expected_chan; - enum ieee80211_band next_band = IEEE80211_BAND_2GHZ; /* means last triplet is completely unrelated to this one */ if (triplet->ext.reg_extension_id >= @@ -592,6 +617,9 @@ static int max_subband_chan(int orig_cur_chan, if (triplet->chans.first_channel <= end_subband_chan) return 0; + if (!chan_in_band(triplet->chans.first_channel, band)) + return 0; + /* 2 GHz */ if (triplet->chans.first_channel <= 14) { end_channel = triplet->chans.first_channel + @@ -600,14 +628,10 @@ static int max_subband_chan(int orig_cur_chan, else { end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1)); - next_band = IEEE80211_BAND_5GHZ; } - if (band != next_band) { - *country_ie -= 3; - *country_ie_len += 3; - break; - } + if (!chan_in_band(end_channel, band)) + return 0; if (orig_max_power != triplet->chans.max_power) { *country_ie -= 3; @@ -666,6 +690,7 @@ static int max_subband_chan(int orig_cur_chan, * with our userspace regulatory agent to get lower bounds. */ static struct ieee80211_regdomain *country_ie_2_rd( + enum ieee80211_band band, u8 *country_ie, u8 country_ie_len, u32 *checksum) @@ -743,8 +768,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( if (triplet->chans.num_channels == 0) return NULL; + if (!chan_in_band(triplet->chans.first_channel, band)) + return NULL; + /* 2 GHz */ - if (triplet->chans.first_channel <= 14) + if (band == IEEE80211_BAND_2GHZ) end_channel = triplet->chans.first_channel + triplet->chans.num_channels - 1; else @@ -767,7 +795,8 @@ static struct ieee80211_regdomain *country_ie_2_rd( * or for whatever reason sends triplets with multiple channels * separated when in fact they should be together. */ - end_channel = max_subband_chan(cur_channel, + end_channel = max_subband_chan(band, + cur_channel, end_channel, triplet->chans.max_power, &country_ie, @@ -775,6 +804,9 @@ static struct ieee80211_regdomain *country_ie_2_rd( if (!end_channel) return NULL; + if (!chan_in_band(end_channel, band)) + return NULL; + cur_sub_max_channel = end_channel; /* Basic sanity check */ @@ -867,14 +899,15 @@ static struct ieee80211_regdomain *country_ie_2_rd( reg_rule->flags = flags; /* 2 GHz */ - if (triplet->chans.first_channel <= 14) + if (band == IEEE80211_BAND_2GHZ) end_channel = triplet->chans.first_channel + triplet->chans.num_channels -1; else end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1)); - end_channel = max_subband_chan(triplet->chans.first_channel, + end_channel = max_subband_chan(band, + triplet->chans.first_channel, end_channel, triplet->chans.max_power, &country_ie, @@ -1981,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, * therefore cannot iterate over the rdev list here. */ void regulatory_hint_11d(struct wiphy *wiphy, - u8 *country_ie, - u8 country_ie_len) + enum ieee80211_band band, + u8 *country_ie, + u8 country_ie_len) { struct ieee80211_regdomain *rd = NULL; char alpha2[2]; @@ -2028,7 +2062,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, wiphy_idx_valid(last_request->wiphy_idx))) goto out; - rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); + rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); if (!rd) { REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); goto out; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3362c7c069b2..3018508226ab 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, * regulatory_hint_11d - hints a country IE as a regulatory domain * @wiphy: the wireless device giving the hint (used only for reporting * conflicts) + * @band: the band on which the country IE was received on. This determines + * the band we'll process the country IE channel triplets for. * @country_ie: pointer to the country IE * @country_ie_len: length of the country IE * * We will intersect the rd with the what CRDA tells us should apply * for the alpha2 this country IE belongs to, this prevents APs from * sending us incorrect or outdated information against a country. + * + * The AP is expected to provide Country IE channel triplets for the + * band it is on. It is technically possible for APs to send channel + * country IE triplets even for channels outside of the band they are + * in but for that they would have to use the regulatory extension + * in combination with a triplet but this behaviour is currently + * not observed. For this reason if a triplet is seen with channel + * information for a band the BSS is not present in it will be ignored. */ void regulatory_hint_11d(struct wiphy *wiphy, + enum ieee80211_band band, u8 *country_ie, u8 country_ie_len); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2333d78187e4..2ce5e1609a3d 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, * - and country_ie[1] which is the IE length */ regulatory_hint_11d(wdev->wiphy, + bss->channel->band, country_ie + 2, country_ie[1]); } -- GitLab From 43d3534344bbdcfa9c61a6b38490cd4cbb2f6bb6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jan 2010 03:00:48 +0100 Subject: [PATCH 0743/3892] mac80211: force use_short_slot=true for 5GHz Normally 5GHz does not have a concept of long vs short slot time, however the slot time that it ends up using is the same as for 2.4 GHZ and use_short_slot == true Because of that, it makes more sense to force use_short_slot = true whenever 5 GHz is being used, so that this particular check does not have to be in every single driver that uses this flag. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 7 +++++++ net/mac80211/mlme.c | 2 ++ 2 files changed, 9 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8286df5822d5..b0102c538b30 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1085,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, params->use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } + + if (!sdata->vif.bss_conf.use_short_slot && + sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { + sdata->vif.bss_conf.use_short_slot = true; + changed |= BSS_CHANGED_ERP_SLOT; + } + if (params->use_short_slot_time >= 0) { sdata->vif.bss_conf.use_short_slot = params->use_short_slot_time; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2746391248d3..a82564e73d91 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -670,6 +670,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); + if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + use_short_slot = true; if (use_protection != bss_conf->use_cts_prot) { bss_conf->use_cts_prot = use_protection; -- GitLab From 145b6d1a56f224d15c61aa7ecfda9a1171b47b6a Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 15 Jan 2010 21:44:21 +0800 Subject: [PATCH 0744/3892] mac80211: fix memory leak in ieee80211_send_probe_req This patch fixes memory leak in ieee80211_send_probe_req, which is introduced in 7c12ce8b854df346388ea56d684784e3484012cf: mac80211: use Probe Request template when sending a direct scan The patch is against the latest wireless-test tree. Signed-off-by: Ming Lei Reviewed-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e278f97c8305..ca170b417da6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1028,6 +1028,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); + kfree(buf); } u32 ieee80211_sta_get_rates(struct ieee80211_local *local, -- GitLab From 0005baf4a31efe6de6f922f73ccbd3762a110062 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jan 2010 02:33:40 +0100 Subject: [PATCH 0745/3892] ath9k: cleanup slot time and ack/cts timeout handling Previously ath9k left the initialization of slot timing and ACK/CTS timeout to the mode specific initvals. This does not handle short vs long slot in 2.4 GHz and uses a rather strange value for the 2.4 GHz ACK timeout (64 usec). This patch uses the proper ath9k_hw functions for setting slot time and timeouts and also implements the switch between short and long slot time in 2.4 GHz Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 3 +- drivers/net/wireless/ath/ath9k/hw.c | 103 ++++++++---------------- drivers/net/wireless/ath/ath9k/hw.h | 4 +- drivers/net/wireless/ath/ath9k/main.c | 20 +++++ 4 files changed, 55 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1660ef17aaf5..422454fe4ff0 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long data) sc->beacon.updateslot = COMMIT; /* commit next beacon */ sc->beacon.slotupdate = slot; } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { - ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); + ah->slottime = sc->beacon.slottime; + ath9k_hw_init_global_settings(ah); sc->beacon.updateslot = OK; } if (bfaddr != 0) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2311fe7a0bf2..e1fd4cc9fae2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -52,28 +52,6 @@ module_exit(ath9k_exit); /* Helper Functions */ /********************/ -static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - - if (!ah->curchan) /* should really check for CCK instead */ - return clks / ATH9K_CLOCK_RATE_CCK; - if (conf->channel->band == IEEE80211_BAND_2GHZ) - return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; - - return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; -} - -static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - - if (conf_is_ht40(conf)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} - static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; @@ -413,8 +391,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->beacon_interval = 100; ah->enable_32kHz_clock = DONT_USE_32KHZ; ah->slottime = (u32) -1; - ah->acktimeout = (u32) -1; - ah->ctstimeout = (u32) -1; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; } @@ -1180,34 +1156,25 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, } } -static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) +static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, - "bad ack timeout %u\n", us); - ah->acktimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); - ah->acktimeout = us; - return true; - } + u32 val = ath9k_hw_mac_to_clks(ah, us); + val = min(val, (u32) 0xFFFF); + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); } -static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, - "bad cts timeout %u\n", us); - ah->ctstimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); - ah->ctstimeout = us; - return true; - } + u32 val = ath9k_hw_mac_to_clks(ah, us); + val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); + REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); +} + +static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +{ + u32 val = ath9k_hw_mac_to_clks(ah, us); + val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); + REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val); } static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) @@ -1224,23 +1191,32 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) } } -static void ath9k_hw_init_user_settings(struct ath_hw *ah) +void ath9k_hw_init_global_settings(struct ath_hw *ah) { + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + int acktimeout; + int sifstime; + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", ah->misc_mode); if (ah->misc_mode != 0) REG_WRITE(ah, AR_PCU_MISC, REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); - if (ah->slottime != (u32) -1) - ath9k_hw_setslottime(ah, ah->slottime); - if (ah->acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ah->acktimeout); - if (ah->ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); + + if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) + sifstime = 16; + else + sifstime = 10; + + acktimeout = ah->slottime + sifstime; + ath9k_hw_setslottime(ah, ah->slottime); + ath9k_hw_set_ack_timeout(ah, acktimeout); + ath9k_hw_set_cts_timeout(ah, acktimeout); if (ah->globaltxtimeout != (u32) -1) ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); } +EXPORT_SYMBOL(ath9k_hw_init_global_settings); void ath9k_hw_deinit(struct ath_hw *ah) { @@ -2061,7 +2037,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); - ath9k_hw_init_user_settings(ah); + ath9k_hw_init_global_settings(ah); if (AR_SREV_9287_12_OR_LATER(ah)) { REG_WRITE(ah, AR_D_GBL_IFS_SIFS, @@ -3658,21 +3634,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp) } EXPORT_SYMBOL(ath9k_hw_extend_tsf); -bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) -{ - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, - "bad slot time %u\n", us); - ah->slottime = (u32) -1; - return false; - } else { - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ah->slottime = us; - return true; - } -} -EXPORT_SYMBOL(ath9k_hw_setslottime); - void ath9k_hw_set11nmac2040(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3f0f055ea39b..a7ff07537bc4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -553,8 +553,6 @@ struct ath_hw { int16_t txpower_indexoffset; u32 beacon_interval; u32 slottime; - u32 acktimeout; - u32 ctstimeout; u32 globaltxtimeout; /* ANI */ @@ -668,7 +666,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); -bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); +void ath9k_hw_init_global_settings(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b39c7bc41143..580ecca0182c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1789,6 +1789,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; + int slottime; int error; mutex_lock(&sc->mutex); @@ -1824,6 +1825,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_beacon_config(sc, vif); } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + slottime = 9; + else + slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { + /* + * Defer update, so that connected stations can adjust + * their settings at the same time. + * See beacon.c for more details + */ + sc->beacon.slottime = slottime; + sc->beacon.updateslot = UPDATE; + } else { + ah->slottime = slottime; + ath9k_hw_init_global_settings(ah); + } + } + /* Disable transmission of beacons */ if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); -- GitLab From e239d8591843945630521ec85edca08289f1a751 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jan 2010 02:34:58 +0100 Subject: [PATCH 0746/3892] ath9k: implement coverage class support Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 +++++-- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 13 +++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e1fd4cc9fae2..0b1dd10f1d84 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1195,6 +1195,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; int acktimeout; + int slottime; int sifstime; ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", @@ -1209,8 +1210,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) else sifstime = 10; - acktimeout = ah->slottime + sifstime; - ath9k_hw_setslottime(ah, ah->slottime); + /* As defined by IEEE 802.11-2007 17.3.8.6 */ + slottime = ah->slottime + 3 * ah->coverage_class; + acktimeout = slottime + sifstime; + ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); ath9k_hw_set_cts_timeout(ah, acktimeout); if (ah->globaltxtimeout != (u32) -1) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a7ff07537bc4..ab1f1981d857 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -551,6 +551,7 @@ struct ath_hw { u32 *bank6Temp; int16_t txpower_indexoffset; + int coverage_class; u32 beacon_interval; u32 slottime; u32 globaltxtimeout; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 580ecca0182c..c0c571c2e8c4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2014,6 +2014,18 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) mutex_unlock(&sc->mutex); } +static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + + mutex_lock(&sc->mutex); + ah->coverage_class = coverage_class; + ath9k_hw_init_global_settings(ah); + mutex_unlock(&sc->mutex); +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2033,4 +2045,5 @@ struct ieee80211_ops ath9k_ops = { .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, + .set_coverage_class = ath9k_set_coverage_class, }; -- GitLab From 857c0fc490d8474d1a232d9b6568a4b229634bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:01:49 +0100 Subject: [PATCH 0747/3892] b43: use standard fls for finding the most significant bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index eb4fb4581edb..b58d6cf26580 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1710,19 +1710,6 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = { .c0 = 0, }; -static u8 lpphy_nbits(s32 val) -{ - u32 tmp = abs(val); - u8 nbits = 0; - - while (tmp != 0) { - nbits++; - tmp >>= 1; - } - - return nbits; -} - static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) { struct lpphy_iq_est iq_est; @@ -1749,8 +1736,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) goto out; } - prod_msb = lpphy_nbits(prod); - q_msb = lpphy_nbits(qpwr); + prod_msb = fls(abs(prod)); + q_msb = fls(abs(qpwr)); tmp1 = prod_msb - 20; if (tmp1 >= 0) { -- GitLab From 003d6d2792bebb2b66966ce5f1da11849e855180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:10:53 +0100 Subject: [PATCH 0748/3892] b43: add new SSB's core id for BCM4328 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following line shows my BCM4328 detected on SSB. We didn't include 0x0C rev. ssb: Core 1 found: IEEE 802.11 (cc 0x812, rev 0x0C, vendor 0x4243) Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 881afff86bd3..c238468bca7f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -118,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16), -- GitLab From 4772ae107c42cdce1d3864d8d540ea0401eb09d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:18:21 +0100 Subject: [PATCH 0749/3892] b43: N-PHY: clean table init, check PHY rev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move table init to tables_nphy.c, detect newer PHY which use different init. We don't init newer PHYs yet but this at least shows what more is needed. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 38 ++-------- drivers/net/wireless/b43/tables_nphy.c | 100 ++++++++++++++++++------- drivers/net/wireless/b43/tables_nphy.h | 29 +------ 3 files changed, 84 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 992318a78077..6b995b92af7a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -203,38 +203,16 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev) b43_ntab_write(dev, (offset) + i, (data)[i]); \ } while (0) -/* Upload the N-PHY tables. */ +/* + * Upload the N-PHY tables. + * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables + */ static void b43_nphy_tables_init(struct b43_wldev *dev) { - /* Static tables */ - ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); - ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); - ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); - ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); - ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); - ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); - ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); - ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); - ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); - ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); - ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); - ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); - ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); - ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); - - /* Volatile tables */ - ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); - ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); - ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); - ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); - ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); - ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); - ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); - ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); - ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); - ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); - ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); - ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); + if (dev->phy.rev < 3) + b43_nphy_rev0_1_2_tables_init(dev); + else + b43_nphy_rev3plus_tables_init(dev); } static void b43_nphy_workarounds(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 4e2336315545..d0b91b561fb8 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel) } -const u8 b43_ntab_adjustpower0[] = { +static const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, @@ -1355,7 +1355,7 @@ const u8 b43_ntab_adjustpower0[] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, }; -const u8 b43_ntab_adjustpower1[] = { +static const u8 b43_ntab_adjustpower1[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, @@ -1374,11 +1374,11 @@ const u8 b43_ntab_adjustpower1[] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, }; -const u16 b43_ntab_bdi[] = { +static const u16 b43_ntab_bdi[] = { 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, }; -const u32 b43_ntab_channelest[] = { +static const u32 b43_ntab_channelest[] = { 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x10101010, 0x10101010, 0x10101010, 0x10101010, @@ -1405,7 +1405,7 @@ const u32 b43_ntab_channelest[] = { 0x10101010, 0x10101010, 0x10101010, 0x10101010, }; -const u8 b43_ntab_estimatepowerlt0[] = { +static const u8 b43_ntab_estimatepowerlt0[] = { 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, @@ -1416,7 +1416,7 @@ const u8 b43_ntab_estimatepowerlt0[] = { 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, }; -const u8 b43_ntab_estimatepowerlt1[] = { +static const u8 b43_ntab_estimatepowerlt1[] = { 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, @@ -1427,14 +1427,14 @@ const u8 b43_ntab_estimatepowerlt1[] = { 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, }; -const u8 b43_ntab_framelookup[] = { +static const u8 b43_ntab_framelookup[] = { 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, }; -const u32 b43_ntab_framestruct[] = { +static const u32 b43_ntab_framestruct[] = { 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, 0x09804506, 0x00100030, 0x09804507, 0x00100030, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -1645,7 +1645,7 @@ const u32 b43_ntab_framestruct[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; -const u32 b43_ntab_gainctl0[] = { +static const u32 b43_ntab_gainctl0[] = { 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, @@ -1680,7 +1680,7 @@ const u32 b43_ntab_gainctl0[] = { 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, }; -const u32 b43_ntab_gainctl1[] = { +static const u32 b43_ntab_gainctl1[] = { 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, @@ -1715,12 +1715,12 @@ const u32 b43_ntab_gainctl1[] = { 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, }; -const u32 b43_ntab_intlevel[] = { +static const u32 b43_ntab_intlevel[] = { 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, 0x00C1188D, 0x080024D2, 0x00000070, }; -const u32 b43_ntab_iqlt0[] = { +static const u32 b43_ntab_iqlt0[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, @@ -1755,7 +1755,7 @@ const u32 b43_ntab_iqlt0[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, }; -const u32 b43_ntab_iqlt1[] = { +static const u32 b43_ntab_iqlt1[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, @@ -1790,7 +1790,7 @@ const u32 b43_ntab_iqlt1[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, }; -const u16 b43_ntab_loftlt0[] = { +static const u16 b43_ntab_loftlt0[] = { 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, @@ -1815,7 +1815,7 @@ const u16 b43_ntab_loftlt0[] = { 0x0002, 0x0103, }; -const u16 b43_ntab_loftlt1[] = { +static const u16 b43_ntab_loftlt1[] = { 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, @@ -1840,7 +1840,7 @@ const u16 b43_ntab_loftlt1[] = { 0x0002, 0x0103, }; -const u8 b43_ntab_mcs[] = { +static const u8 b43_ntab_mcs[] = { 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, @@ -1859,7 +1859,7 @@ const u8 b43_ntab_mcs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const u32 b43_ntab_noisevar10[] = { +static const u32 b43_ntab_noisevar10[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, @@ -1926,7 +1926,7 @@ const u32 b43_ntab_noisevar10[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, }; -const u32 b43_ntab_noisevar11[] = { +static const u32 b43_ntab_noisevar11[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, @@ -1993,7 +1993,7 @@ const u32 b43_ntab_noisevar11[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, }; -const u16 b43_ntab_pilot[] = { +static const u16 b43_ntab_pilot[] = { 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, @@ -2011,12 +2011,12 @@ const u16 b43_ntab_pilot[] = { 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, }; -const u32 b43_ntab_pilotlt[] = { +static const u32 b43_ntab_pilotlt[] = { 0x76540123, 0x62407351, 0x76543201, 0x76540213, 0x76540123, 0x76430521, }; -const u32 b43_ntab_tdi20a0[] = { +static const u32 b43_ntab_tdi20a0[] = { 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, 0x00020301, 0x00030504, 0x00040708, 0x0005090B, @@ -2033,7 +2033,7 @@ const u32 b43_ntab_tdi20a0[] = { 0x00000000, 0x00000000, 0x00000000, }; -const u32 b43_ntab_tdi20a1[] = { +static const u32 b43_ntab_tdi20a1[] = { 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, @@ -2050,7 +2050,7 @@ const u32 b43_ntab_tdi20a1[] = { 0x00000000, 0x00000000, 0x00000000, }; -const u32 b43_ntab_tdi40a0[] = { +static const u32 b43_ntab_tdi40a0[] = { 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, @@ -2081,7 +2081,7 @@ const u32 b43_ntab_tdi40a0[] = { 0x00000000, 0x00000000, }; -const u32 b43_ntab_tdi40a1[] = { +static const u32 b43_ntab_tdi40a1[] = { 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, @@ -2112,7 +2112,7 @@ const u32 b43_ntab_tdi40a1[] = { 0x00000000, 0x00000000, }; -const u32 b43_ntab_tdtrn[] = { +static const u32 b43_ntab_tdtrn[] = { 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, @@ -2291,7 +2291,7 @@ const u32 b43_ntab_tdtrn[] = { 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, }; -const u32 b43_ntab_tmap[] = { +static const u32 b43_ntab_tmap[] = { 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, @@ -2474,3 +2474,51 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) /* Some compiletime assertions... */ assert_ntab_array_sizes(); } + +#define ntab_upload(dev, offset, data) do { \ + unsigned int i; \ + for (i = 0; i < (offset##_SIZE); i++) \ + b43_ntab_write(dev, (offset) + i, (data)[i]); \ + } while (0) + +void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev) +{ + /* Static tables */ + ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); + ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); + ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); + ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); + ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); + ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); + ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); + ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); + ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); + ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); + ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); + ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); + ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); + ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); + + /* Volatile tables */ + ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); + ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); + ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); + ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); + ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); + ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); + ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); + ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); + ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); + ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); +} + +void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev) +{ + /* Static tables */ + /* TODO */ + + /* Volatile tables */ + /* TODO */ +} diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 4d498b053ec7..1f0a602fd247 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -128,32 +128,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); -extern const u8 b43_ntab_adjustpower0[]; -extern const u8 b43_ntab_adjustpower1[]; -extern const u16 b43_ntab_bdi[]; -extern const u32 b43_ntab_channelest[]; -extern const u8 b43_ntab_estimatepowerlt0[]; -extern const u8 b43_ntab_estimatepowerlt1[]; -extern const u8 b43_ntab_framelookup[]; -extern const u32 b43_ntab_framestruct[]; -extern const u32 b43_ntab_gainctl0[]; -extern const u32 b43_ntab_gainctl1[]; -extern const u32 b43_ntab_intlevel[]; -extern const u32 b43_ntab_iqlt0[]; -extern const u32 b43_ntab_iqlt1[]; -extern const u16 b43_ntab_loftlt0[]; -extern const u16 b43_ntab_loftlt1[]; -extern const u8 b43_ntab_mcs[]; -extern const u32 b43_ntab_noisevar10[]; -extern const u32 b43_ntab_noisevar11[]; -extern const u16 b43_ntab_pilot[]; -extern const u32 b43_ntab_pilotlt[]; -extern const u32 b43_ntab_tdi20a0[]; -extern const u32 b43_ntab_tdi20a1[]; -extern const u32 b43_ntab_tdi40a0[]; -extern const u32 b43_ntab_tdi40a1[]; -extern const u32 b43_ntab_tdtrn[]; -extern const u32 b43_ntab_tmap[]; - +void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev); +void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev); #endif /* B43_TABLES_NPHY_H_ */ -- GitLab From 76a4db303d06066792bbc0e886def2cf99b232ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:27:46 +0100 Subject: [PATCH 0750/3892] b43: N-PHY: add shared memory offsets definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 2f12a750bc98..54d6085a887b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -253,6 +253,14 @@ enum { #define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ #define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ #define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ +/* SHM_SHARED tx iq workarounds */ +#define B43_SHM_SH_NPHY_TXIQW0 0x0700 +#define B43_SHM_SH_NPHY_TXIQW1 0x0702 +#define B43_SHM_SH_NPHY_TXIQW2 0x0704 +#define B43_SHM_SH_NPHY_TXIQW3 0x0706 +/* SHM_SHARED tx pwr ctrl */ +#define B43_SHM_SH_NPHY_TXPWR_INDX0 0x0708 +#define B43_SHM_SH_NPHY_TXPWR_INDX1 0x070E /* SHM_SCRATCH offsets */ #define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ -- GitLab From f8187b5b9780a9ac3c12c70413615a0fdf321cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:34:21 +0100 Subject: [PATCH 0751/3892] b43: N-PHY: add needed struct definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 24 ++++++++++++++++ drivers/net/wireless/b43/phy_n.h | 38 ++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 5 ++++ 3 files changed, 67 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 6b995b92af7a..cb784a2504a6 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -29,6 +29,30 @@ #include "phy_n.h" #include "tables_nphy.h" +struct nphy_txgains { + u16 txgm[2]; + u16 pga[2]; + u16 pad[2]; + u16 ipa[2]; +}; + +struct nphy_iqcal_params { + u16 txgm; + u16 pga; + u16 pad; + u16 ipa; + u16 cal_gain; + u16 ncorr[5]; +}; + +struct nphy_iq_est { + s32 iq0_prod; + u32 i0_pwr; + u32 q0_pwr; + s32 iq1_prod; + u32 i1_pwr; + u32 q1_pwr; +}; void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 1749aef4147d..f829e4e397e8 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -919,6 +919,44 @@ struct b43_wldev; +struct b43_phy_n_iq_comp { + s16 a0; + s16 b0; + s16 a1; + s16 b1; +}; + +struct b43_phy_n_rssical_cache { + u16 rssical_radio_regs_2G[2]; + u16 rssical_phy_regs_2G[12]; + + u16 rssical_radio_regs_5G[2]; + u16 rssical_phy_regs_5G[12]; +}; + +struct b43_phy_n_cal_cache { + u16 txcal_radio_regs_2G[8]; + u16 txcal_coeffs_2G[8]; + struct b43_phy_n_iq_comp rxcal_coeffs_2G; + + u16 txcal_radio_regs_5G[8]; + u16 txcal_coeffs_5G[8]; + struct b43_phy_n_iq_comp rxcal_coeffs_5G; +}; + +struct b43_phy_n_txpwrindex { + s8 index; + s8 index_internal; + s8 index_internal_save; + u16 AfectrlOverride; + u16 AfeCtrlDacGain; + u16 rad_gain; + u8 bbmult; + u16 iqcomp_a; + u16 iqcomp_b; + u16 locomp; +}; + struct b43_phy_n { //TODO lots of missing stuff }; diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 1f0a602fd247..f6753c4b96b2 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -46,6 +46,11 @@ struct b43_nphy_channeltab_entry { struct b43_wldev; +struct nphy_txiqcal_ladder { + u8 percent; + u8 g_env; +}; + /* Upload the default register value table. * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz * table is uploaded. If "ignore_uploadflag" is true, we upload any value -- GitLab From 5b0ade3377b91da14410612b2051d66d26d31069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:40:03 +0100 Subject: [PATCH 0752/3892] b43: N-PHY: add missing register definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index f829e4e397e8..c5084a4e30cd 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -231,6 +231,7 @@ #define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ #define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ #define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ +#define B43_NPHY_AFECTL_OVER1 B43_PHY_N(0x08F) /* AFE control override 1 */ #define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ #define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ #define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 @@ -705,6 +706,10 @@ #define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ #define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ #define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 +#define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */ +#define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */ +#define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */ +#define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */ -- GitLab From 2a448bfc70f4fd4a54996d1c7a371ba28ec0568f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 12:54:30 +0100 Subject: [PATCH 0753/3892] b43: N-PHY: add global variables to b43_phy_n struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.h | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index c5084a4e30cd..4572866756fc 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -963,7 +963,49 @@ struct b43_phy_n_txpwrindex { }; struct b43_phy_n { - //TODO lots of missing stuff + u8 antsel_type; + u8 cal_orig_pwr_idx[2]; + u8 measure_hold; + u8 phyrxchain; + u8 perical; + u32 deaf_count; + u32 rxcalparams; + bool hang_avoid; + bool mute; + u16 papd_epsilon_offset[2]; + + u8 mphase_cal_phase_id; + u16 mphase_txcal_cmdidx; + u16 mphase_txcal_numcmds; + u16 mphase_txcal_bestcoeffs[11]; + + u8 txpwrctrl; + u16 txcal_bbmult; + u16 txiqlocal_bestc[11]; + bool txiqlocal_coeffsvalid; + struct b43_phy_n_txpwrindex txpwrindex[2]; + + u16 tx_rx_cal_phy_saveregs[11]; + u16 tx_rx_cal_radio_saveregs[22]; + + u16 rfctrl_intc1_save; + u16 rfctrl_intc2_save; + + u16 classifier_state; + u16 clip_state[2]; + + bool ipa2g_on; + u8 iqcal_chanspec_2G; + u8 rssical_chanspec_2G; + + bool ipa5g_on; + u8 iqcal_chanspec_5G; + u8 rssical_chanspec_5G; + + struct b43_phy_n_rssical_cache rssical_cache; + struct b43_phy_n_cal_cache cal_cache; + bool crsminpwr_adjusted; + bool noisevars_adjusted; }; -- GitLab From 088e56b44a52bbd58a790627148cf75ed71ae34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 13:02:45 +0100 Subject: [PATCH 0754/3892] b43: N-PHY: add various tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 477 +++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 37 ++ 2 files changed, 514 insertions(+) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index d0b91b561fb8..7dff853ab962 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2406,6 +2406,483 @@ static const u32 b43_ntab_tmap[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; +const u32 b43_ntab_tx_gain_rev0_1_2[] = { + 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, + 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, + 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844, + 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44, + 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844, + 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644, + 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444, + 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44, + 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844, + 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44, + 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944, + 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744, + 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544, + 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44, + 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844, + 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44, + 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944, + 0x03902942, 0x03902844, 0x03902842, 0x03902744, + 0x03902742, 0x03902644, 0x03902642, 0x03902544, + 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44, + 0x03802a42, 0x03802944, 0x03802942, 0x03802844, + 0x03802842, 0x03802744, 0x03802742, 0x03802644, + 0x03802642, 0x03802544, 0x03802542, 0x03802444, + 0x03802442, 0x03802344, 0x03802342, 0x03802244, + 0x03802242, 0x03802144, 0x03802142, 0x03802044, + 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44, + 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44, + 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44, + 0x03801a42, 0x03801944, 0x03801942, 0x03801844, + 0x03801842, 0x03801744, 0x03801742, 0x03801644, + 0x03801642, 0x03801544, 0x03801542, 0x03801444, + 0x03801442, 0x03801344, 0x03801342, 0x00002b00, +}; + +const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = { + 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, + 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, + 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, + 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037, + 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e, + 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037, + 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e, + 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037, + 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e, + 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037, + 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e, + 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037, + 0x19410044, 0x19410042, 0x19410040, 0x1941003e, + 0x1941003c, 0x1941003b, 0x19410039, 0x19410037, + 0x18410044, 0x18410042, 0x18410040, 0x1841003e, + 0x1841003c, 0x1841003b, 0x18410039, 0x18410037, + 0x17410044, 0x17410042, 0x17410040, 0x1741003e, + 0x1741003c, 0x1741003b, 0x17410039, 0x17410037, + 0x16410044, 0x16410042, 0x16410040, 0x1641003e, + 0x1641003c, 0x1641003b, 0x16410039, 0x16410037, + 0x15410044, 0x15410042, 0x15410040, 0x1541003e, + 0x1541003c, 0x1541003b, 0x15410039, 0x15410037, + 0x14410044, 0x14410042, 0x14410040, 0x1441003e, + 0x1441003c, 0x1441003b, 0x14410039, 0x14410037, + 0x13410044, 0x13410042, 0x13410040, 0x1341003e, + 0x1341003c, 0x1341003b, 0x13410039, 0x13410037, + 0x12410044, 0x12410042, 0x12410040, 0x1241003e, + 0x1241003c, 0x1241003b, 0x12410039, 0x12410037, + 0x11410044, 0x11410042, 0x11410040, 0x1141003e, + 0x1141003c, 0x1141003b, 0x11410039, 0x11410037, + 0x10410044, 0x10410042, 0x10410040, 0x1041003e, + 0x1041003c, 0x1041003b, 0x10410039, 0x10410037, +}; + +const u32 b43_ntab_tx_gain_rev3_5ghz[] = { + 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, + 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, + 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, + 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037, + 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e, + 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037, + 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e, + 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037, + 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e, + 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037, + 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e, + 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037, + 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e, + 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037, + 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e, + 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037, + 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e, + 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037, + 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e, + 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037, + 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e, + 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037, + 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e, + 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037, + 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e, + 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037, + 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e, + 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037, + 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e, + 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037, + 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e, + 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037, +}; + +const u32 b43_ntab_tx_gain_rev4_5ghz[] = { + 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, + 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, + 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, + 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037, + 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e, + 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037, + 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e, + 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037, + 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e, + 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037, + 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e, + 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037, + 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e, + 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037, + 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e, + 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037, + 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e, + 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037, + 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e, + 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037, + 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e, + 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037, + 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e, + 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038, + 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e, + 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037, + 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e, + 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037, + 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e, + 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037, + 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c, + 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034, +}; + +const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = { + 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, + 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, + 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, + 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a, + 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e, + 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a, + 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e, + 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037, + 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040, + 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a, + 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c, + 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038, + 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b, + 0x09620039, 0x09620037, 0x09620035, 0x09620033, + 0x08620044, 0x08620042, 0x08620040, 0x0862003e, + 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039, + 0x07620043, 0x07620042, 0x07620040, 0x0762003f, + 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039, + 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b, + 0x06620039, 0x06620037, 0x06620035, 0x06620033, + 0x05620046, 0x05620044, 0x05620042, 0x05620040, + 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039, + 0x04620044, 0x04620042, 0x04620040, 0x0462003e, + 0x0462003c, 0x0462003b, 0x04620039, 0x04620038, + 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039, + 0x03620038, 0x03620037, 0x03620035, 0x03620033, + 0x0262004c, 0x0262004a, 0x02620048, 0x02620047, + 0x02620046, 0x02620044, 0x02620043, 0x02620042, + 0x0162004a, 0x01620048, 0x01620046, 0x01620044, + 0x01620043, 0x01620042, 0x01620041, 0x01620040, + 0x00620042, 0x00620040, 0x0062003e, 0x0062003c, + 0x0062003b, 0x00620039, 0x00620037, 0x00620035, +}; + +const u32 txpwrctrl_tx_gain_ipa[] = { + 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, + 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, + 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, + 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025, + 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029, + 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025, + 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029, + 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025, + 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029, + 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025, + 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029, + 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025, + 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029, + 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025, + 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029, + 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025, + 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029, + 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025, + 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029, + 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025, + 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029, + 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025, + 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029, + 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025, + 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029, + 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025, + 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029, + 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025, + 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029, + 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025, + 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029, + 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025, +}; + +const u32 txpwrctrl_tx_gain_ipa_rev5[] = { + 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, + 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, + 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, + 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025, + 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029, + 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025, + 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029, + 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025, + 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029, + 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025, + 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029, + 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025, + 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029, + 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025, + 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029, + 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025, + 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029, + 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025, + 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029, + 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025, + 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029, + 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025, + 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029, + 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025, + 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029, + 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025, + 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029, + 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025, + 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029, + 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025, + 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029, + 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025, +}; + +const u32 txpwrctrl_tx_gain_ipa_rev6[] = { + 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, + 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, + 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, + 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025, + 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029, + 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025, + 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029, + 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025, + 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029, + 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025, + 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029, + 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025, + 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029, + 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025, + 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029, + 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025, + 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029, + 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025, + 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029, + 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025, + 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029, + 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025, + 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029, + 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025, + 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029, + 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025, + 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029, + 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025, + 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029, + 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025, + 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029, + 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, +}; + +const u32 txpwrctrl_tx_gain_ipa_5g[] = { + 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, + 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, + 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, + 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022, + 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025, + 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027, + 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023, + 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027, + 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022, + 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025, + 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021, + 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026, + 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022, + 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026, + 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022, + 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026, + 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022, + 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026, + 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022, + 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026, + 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021, + 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026, + 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029, + 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024, + 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027, + 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023, + 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026, + 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022, + 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025, + 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027, + 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022, + 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f, +}; + +const u16 tbl_iqcal_gainparams[2][9][8] = { + { + { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 }, + { 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 }, + { 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 }, + { 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 }, + { 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 }, + { 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 }, + { 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 }, + { 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 }, + { 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 } + }, + { + { 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, + { 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, + { 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 }, + { 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 }, + { 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 }, + { 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 }, + { 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 }, + { 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 }, + { 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 } + } +}; + +const struct nphy_txiqcal_ladder ladder_lo[] = { + { 3, 0 }, + { 4, 0 }, + { 6, 0 }, + { 9, 0 }, + { 13, 0 }, + { 18, 0 }, + { 25, 0 }, + { 25, 1 }, + { 25, 2 }, + { 25, 3 }, + { 25, 4 }, + { 25, 5 }, + { 25, 6 }, + { 25, 7 }, + { 35, 7 }, + { 50, 7 }, + { 71, 7 }, + { 100, 7 } +}; + +const struct nphy_txiqcal_ladder ladder_iq[] = { + { 3, 0 }, + { 4, 0 }, + { 6, 0 }, + { 9, 0 }, + { 13, 0 }, + { 18, 0 }, + { 25, 0 }, + { 35, 0 }, + { 50, 0 }, + { 71, 0 }, + { 100, 0 }, + { 100, 1 }, + { 100, 2 }, + { 100, 3 }, + { 100, 4 }, + { 100, 5 }, + { 100, 6 }, + { 100, 7 } +}; + +const u16 loscale[] = { + 256, 256, 271, 271, + 287, 256, 256, 271, + 271, 287, 287, 304, + 304, 256, 256, 271, + 271, 287, 287, 304, + 304, 322, 322, 341, + 341, 362, 362, 383, + 383, 256, 256, 271, + 271, 287, 287, 304, + 304, 322, 322, 256, + 256, 271, 271, 287, + 287, 304, 304, 322, + 322, 341, 341, 362, + 362, 256, 256, 271, + 271, 287, 287, 304, + 304, 322, 322, 256, + 256, 271, 271, 287, + 287, 304, 304, 322, + 322, 341, 341, 362, + 362, 256, 256, 271, + 271, 287, 287, 304, + 304, 322, 322, 341, + 341, 362, 362, 383, + 383, 406, 406, 430, + 430, 455, 455, 482, + 482, 511, 511, 541, + 541, 573, 573, 607, + 607, 643, 643, 681, + 681, 722, 722, 764, + 764, 810, 810, 858, + 858, 908, 908, 962, + 962, 1019, 1019, 256 +}; + +const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { + 0x0200, 0x0300, 0x0400, 0x0700, + 0x0900, 0x0c00, 0x1200, 0x1201, + 0x1202, 0x1203, 0x1204, 0x1205, + 0x1206, 0x1207, 0x1907, 0x2307, + 0x3207, 0x4707 +}; + +const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { + 0x0300, 0x0500, 0x0700, 0x0900, + 0x0d00, 0x1100, 0x1900, 0x1901, + 0x1902, 0x1903, 0x1904, 0x1905, + 0x1906, 0x1907, 0x2407, 0x3207, + 0x4607, 0x6407 +}; + +const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { + 0x0100, 0x0200, 0x0400, 0x0700, + 0x0900, 0x0c00, 0x1200, 0x1900, + 0x2300, 0x3200, 0x4700, 0x4701, + 0x4702, 0x4703, 0x4704, 0x4705, + 0x4706, 0x4707 +}; + +const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { + 0x0200, 0x0300, 0x0600, 0x0900, + 0x0d00, 0x1100, 0x1900, 0x2400, + 0x3200, 0x4600, 0x6400, 0x6401, + 0x6402, 0x6403, 0x6404, 0x6405, + 0x6406, 0x6407 +}; + +const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { }; + +const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { }; + +const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { + 0x8423, 0x8323, 0x8073, 0x8256, + 0x8045, 0x8223, 0x9423, 0x9323, + 0x9073, 0x9256, 0x9045, 0x9223 +}; + +const u16 tbl_tx_iqlo_cal_cmds_recal[] = { + 0x8101, 0x8253, 0x8053, 0x8234, + 0x8034, 0x9101, 0x9253, 0x9053, + 0x9234, 0x9034 +}; + +const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { + 0x8123, 0x8264, 0x8086, 0x8245, + 0x8056, 0x9123, 0x9264, 0x9086, + 0x9245, 0x9056 +}; + +const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { + 0x8434, 0x8334, 0x8084, 0x8267, + 0x8056, 0x8234, 0x9434, 0x9334, + 0x9084, 0x9267, 0x9056, 0x9234 +}; + static inline void assert_ntab_array_sizes(void) { #undef check diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index f6753c4b96b2..51636d02f8b1 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -131,9 +131,46 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); #define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ #define B43_NTAB_C1_LOFEEDTH_SIZE 128 +#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18 +#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18 +#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18 +#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE 18 +#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3 11 +#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS 9 +#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3 12 +#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL 10 +#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10 +#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 + void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev); void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev); +extern const u32 b43_ntab_tx_gain_rev0_1_2[]; +extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[]; +extern const u32 b43_ntab_tx_gain_rev3_5ghz[]; +extern const u32 b43_ntab_tx_gain_rev4_5ghz[]; +extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[]; + +extern const u32 txpwrctrl_tx_gain_ipa[]; +extern const u32 txpwrctrl_tx_gain_ipa_rev5[]; +extern const u32 txpwrctrl_tx_gain_ipa_rev6[]; +extern const u32 txpwrctrl_tx_gain_ipa_5g[]; +extern const u16 tbl_iqcal_gainparams[2][9][8]; +extern const struct nphy_txiqcal_ladder ladder_lo[]; +extern const struct nphy_txiqcal_ladder ladder_iq[]; +extern const u16 loscale[]; + +extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[]; +extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[]; +extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[]; +extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[]; +extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[]; +extern const u16 tbl_tx_iqlo_cal_startcoefs[]; +extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[]; +extern const u16 tbl_tx_iqlo_cal_cmds_recal[]; +extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[]; +extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[]; + #endif /* B43_TABLES_NPHY_H_ */ -- GitLab From 0988a7a1a98300e90a6613b33738e07cdf8ce786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 13:27:29 +0100 Subject: [PATCH 0755/3892] b43: N-PHY: update init code to match current specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous init path was based on old specs from old driver. Update it as much as possible leaving some TODOs for not implemented functions. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 201 +++++++++++++++++++++++++------ 1 file changed, 161 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index cb784a2504a6..c16c98538f65 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -419,75 +419,196 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) //TODO } +/* + * Init N-PHY + * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N + */ int b43_phy_initn(struct b43_wldev *dev) { + struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; + u8 tx_pwr_state; + struct nphy_txgains target; u16 tmp; + enum ieee80211_band tmp2; + bool do_rssi_cal; + + u16 clip[2]; + bool do_cal = false; - //TODO: Spectral management + if ((dev->phy.rev >= 3) && + (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && + (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) { + chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40); + } + nphy->deaf_count = 0; b43_nphy_tables_init(dev); + nphy->crsminpwr_adjusted = false; + nphy->noisevars_adjusted = false; /* Clear all overrides */ - b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + if (dev->phy.rev >= 3) { + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0); + b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0); + } else { + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + } b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + if (dev->phy.rev < 6) { + b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + } b43_phy_mask(dev, B43_NPHY_RFSEQMODE, ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); + if (dev->phy.rev >= 3) + b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0); b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); - tmp = (phy->rev < 2) ? 64 : 59; - b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, - ~B43_NPHY_BPHY_CTL3_SCALE, - tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); - + if (dev->phy.rev <= 2) { + tmp = (dev->phy.rev == 2) ? 0x3B : 0x40; + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, + ~B43_NPHY_BPHY_CTL3_SCALE, + tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); + } b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); - b43_phy_write(dev, B43_NPHY_TXREALFD, 184); - b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); - b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); - b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); + if (bus->sprom.boardflags2_lo & 0x100 || + (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x8B)) + b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0); + else + b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8); + b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50); + b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); - //TODO MIMO-Config - //TODO Update TX/RX chain + /* TODO MIMO-Config */ + /* TODO Update TX/RX chain */ if (phy->rev < 2) { b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); } + + tmp2 = b43_current_band(dev->wl); + if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) || + (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) { + b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1); + b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F, + nphy->papd_epsilon_offset[0] << 7); + b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1); + b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F, + nphy->papd_epsilon_offset[1] << 7); + /* TODO N PHY IPA Set TX Dig Filters */ + } else if (phy->rev >= 5) { + /* TODO N PHY Ext PA Set TX Dig Filters */ + } + b43_nphy_workarounds(dev); - b43_nphy_reset_cca(dev); - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); + /* Reset CCA, in init code it differs a little from standard way */ + /* b43_nphy_bmac_clock_fgc(dev, 1); */ + tmp = b43_phy_read(dev, B43_NPHY_BBCFG); + b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA); + b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); + /* b43_nphy_bmac_clock_fgc(dev, 0); */ + + /* TODO N PHY MAC PHY Clock Set with argument 1 */ + + /* b43_nphy_pa_override(dev, false); */ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + /* b43_nphy_pa_override(dev, true); */ + + /* b43_nphy_classifier(dev, 0, 0); */ + /* b43_nphy_read_clip_detection(dev, clip); */ + tx_pwr_state = nphy->txpwrctrl; + /* TODO N PHY TX power control with argument 0 + (turning off power control) */ + /* TODO Fix the TX Power Settings */ + /* TODO N PHY TX Power Control Idle TSSI */ + /* TODO N PHY TX Power Control Setup */ + + if (phy->rev >= 3) { + /* TODO */ + } else { + /* TODO Write an N PHY table with ID 26, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ + /* TODO Write an N PHY table with ID 27, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ + } - b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ - //TODO read core1/2 clip1 thres regs - - if (1 /* FIXME Band is 2.4GHz */) - b43_nphy_bphy_init(dev); - //TODO disable TX power control - //TODO Fix the TX power settings - //TODO Init periodic calibration with reason 3 - b43_nphy_rssi_cal(dev, 2); - b43_nphy_rssi_cal(dev, 0); - b43_nphy_rssi_cal(dev, 1); - //TODO get TX gain - //TODO init superswitch - //TODO calibrate LO - //TODO idle TSSI TX pctl - //TODO TX power control power setup - //TODO table writes - //TODO TX power control coefficients - //TODO enable TX power control - //TODO control antenna selection - //TODO init radar detection - //TODO reset channel if changed + if (nphy->phyrxchain != 3) + ;/* TODO N PHY RX Core Set State with phyrxchain as argument */ + if (nphy->mphase_cal_phase_id > 0) + ;/* TODO PHY Periodic Calibration Multi-Phase Restart */ + + do_rssi_cal = false; + if (phy->rev >= 3) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + do_rssi_cal = (nphy->rssical_chanspec_2G == 0); + else + do_rssi_cal = (nphy->rssical_chanspec_5G == 0); + + if (do_rssi_cal) + ;/* b43_nphy_rssi_cal(dev); */ + else + ;/* b43_nphy_restore_rssi_cal(dev); */ + } else { + /* b43_nphy_rssi_cal(dev); */ + } + + if (!((nphy->measure_hold & 0x6) != 0)) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + do_cal = (nphy->iqcal_chanspec_2G == 0); + else + do_cal = (nphy->iqcal_chanspec_5G == 0); + + if (nphy->mute) + do_cal = false; + + if (do_cal) { + /* target = b43_nphy_get_tx_gains(dev); */ + + if (nphy->antsel_type == 2) + ;/*TODO NPHY Superswitch Init with argument 1*/ + if (nphy->perical != 2) { + /* b43_nphy_rssi_cal(dev); */ + if (phy->rev >= 3) { + nphy->cal_orig_pwr_idx[0] = + nphy->txpwrindex[0].index_internal; + nphy->cal_orig_pwr_idx[1] = + nphy->txpwrindex[1].index_internal; + /* TODO N PHY Pre Calibrate TX Gain */ + /*target = b43_nphy_get_tx_gains(dev)*/ + } + } + } + } + + /* + if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { + if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) + Call N PHY Save Cal + else if (nphy->mphase_cal_phase_id == 0) + N PHY Periodic Calibration with argument 3 + } else { + b43_nphy_restore_cal(dev); + } + */ + + /* b43_nphy_tx_pwr_ctrl_coef_setup(dev); */ + /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */ + b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015); + b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); + if (phy->rev >= 3 && phy->rev <= 6) + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); + /* b43_nphy_tx_lp_fbw(dev); */ + /* TODO N PHY Spur Workaround */ b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); return 0; -- GitLab From 4a933c8566da3e2b164ea74b1632bf2f43c8ee9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 13:36:43 +0100 Subject: [PATCH 0756/3892] b43: N-PHY: update CCA reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index c16c98538f65..c9d2b7738aef 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -343,18 +343,34 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ +static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) +{ + u32 tmslow; + + if (dev->phy.type != B43_PHYTYPE_N) + return; + + tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + if (force) + tmslow |= SSB_TMSLOW_FGC; + else + tmslow &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ static void b43_nphy_reset_cca(struct b43_wldev *dev) { u16 bbcfg; - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); + b43_nphy_bmac_clock_fgc(dev, 1); bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); - b43_phy_write(dev, B43_NPHY_BBCFG, - bbcfg & ~B43_NPHY_BBCFG_RSTCCA); - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); + b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA); + udelay(1); + b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA); + b43_nphy_bmac_clock_fgc(dev, 0); + /* TODO: N PHY Force RF Seq with argument 2 */ } enum b43_nphy_rf_sequence { -- GitLab From 4cb9977516d0f52a779d12a430ccf263d35802fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 13:40:58 +0100 Subject: [PATCH 0757/3892] b43: N-PHY: split RSSI calibration into 2 functions (rev2, rev3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index c9d2b7738aef..30b9dacb666c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -429,10 +429,31 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } -/* RSSI Calibration */ -static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ +static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) { - //TODO + /* TODO */ +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ +static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) +{ + /* TODO */ +} + +/* + * RSSI Calibration + * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal + */ +static void b43_nphy_rssi_cal(struct b43_wldev *dev) +{ + if (dev->phy.rev >= 3) { + b43_nphy_rev3_rssi_cal(dev); + } else { + b43_nphy_rev2_rssi_cal(dev, 2); + b43_nphy_rev2_rssi_cal(dev, 0); + b43_nphy_rev2_rssi_cal(dev, 1); + } } /* @@ -571,11 +592,11 @@ int b43_phy_initn(struct b43_wldev *dev) do_rssi_cal = (nphy->rssical_chanspec_5G == 0); if (do_rssi_cal) - ;/* b43_nphy_rssi_cal(dev); */ + b43_nphy_rssi_cal(dev); else ;/* b43_nphy_restore_rssi_cal(dev); */ } else { - /* b43_nphy_rssi_cal(dev); */ + b43_nphy_rssi_cal(dev); } if (!((nphy->measure_hold & 0x6) != 0)) { -- GitLab From bbec398c1b7baa1dbde1e49446d1cbf4c6c20fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 14:31:39 +0100 Subject: [PATCH 0758/3892] b43: N-PHY: add clip detection reading/writing and some classifier function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 40 ++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 30b9dacb666c..72b1c410b7ff 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -28,6 +28,7 @@ #include "b43.h" #include "phy_n.h" #include "tables_nphy.h" +#include "main.h" struct nphy_txgains { u16 txgm[2]; @@ -373,6 +374,41 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) /* TODO: N PHY Force RF Seq with argument 2 */ } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) +{ + b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]); + b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) +{ + clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES); + clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ +static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) +{ + u16 tmp; + + if (dev->dev->id.revision == 16) + b43_mac_suspend(dev); + + tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL); + tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN | + B43_NPHY_CLASSCTL_WAITEDEN); + tmp &= ~mask; + tmp |= (val & mask); + b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp); + + if (dev->dev->id.revision == 16) + b43_mac_enable(dev); + + return tmp; +} + enum b43_nphy_rf_sequence { B43_RFSEQ_RX2TX, B43_RFSEQ_TX2RX, @@ -563,8 +599,8 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); /* b43_nphy_pa_override(dev, true); */ - /* b43_nphy_classifier(dev, 0, 0); */ - /* b43_nphy_read_clip_detection(dev, clip); */ + b43_nphy_classifier(dev, 0, 0); + b43_nphy_read_clip_detection(dev, clip); tx_pwr_state = nphy->txpwrctrl; /* TODO N PHY TX power control with argument 0 (turning off power control) */ -- GitLab From 3c95627d404e1094313f2dcb87424e2ae462e814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 14:38:32 +0100 Subject: [PATCH 0759/3892] b43: N-PHY: implement RSSI selection and offset scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 121 +++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 72b1c410b7ff..494c95246954 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -465,6 +465,127 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ +static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, + s8 offset, u8 core, u8 rail, u8 type) +{ + u16 tmp; + bool core1or5 = (core == 1) || (core == 5); + bool core2or5 = (core == 2) || (core == 5); + + offset = clamp_val(offset, -32, 31); + tmp = ((scale & 0x3F) << 8) | (offset & 0x3F); + + if (core1or5 && (rail == 0) && (type == 2)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp); + if (core1or5 && (rail == 1) && (type == 2)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp); + if (core2or5 && (rail == 0) && (type == 2)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp); + if (core2or5 && (rail == 1) && (type == 2)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp); + if (core1or5 && (rail == 0) && (type == 0)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp); + if (core1or5 && (rail == 1) && (type == 0)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp); + if (core2or5 && (rail == 0) && (type == 0)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp); + if (core2or5 && (rail == 1) && (type == 0)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp); + if (core1or5 && (rail == 0) && (type == 1)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp); + if (core1or5 && (rail == 1) && (type == 1)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp); + if (core2or5 && (rail == 0) && (type == 1)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp); + if (core2or5 && (rail == 1) && (type == 1)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp); + if (core1or5 && (rail == 0) && (type == 6)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp); + if (core1or5 && (rail == 1) && (type == 6)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp); + if (core2or5 && (rail == 0) && (type == 6)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp); + if (core2or5 && (rail == 1) && (type == 6)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp); + if (core1or5 && (rail == 0) && (type == 3)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp); + if (core1or5 && (rail == 1) && (type == 3)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp); + if (core2or5 && (rail == 0) && (type == 3)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp); + if (core2or5 && (rail == 1) && (type == 3)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp); + if (core1or5 && (type == 4)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp); + if (core2or5 && (type == 4)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp); + if (core1or5 && (type == 5)) + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp); + if (core2or5 && (type == 5)) + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ +static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) +{ + u16 val; + + if (dev->phy.rev >= 3) { + /* TODO */ + } else { + if (type < 3) + val = 0; + else if (type == 6) + val = 1; + else if (type == 3) + val = 2; + else + val = 3; + + val = (val << 12) | (val << 14); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val); + + if (type < 3) { + b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF, + (type + 1) << 4); + b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF, + (type + 1) << 4); + } + + /* TODO use some definitions */ + if (code == 0) { + b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0); + if (type < 3) { + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, + 0xFEC7, 0); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, + 0xEFDC, 0); + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, + 0xFFFE, 0); + udelay(20); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, + 0xFFFE, 0); + } + } else { + b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, + 0x3000); + if (type < 3) { + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, + 0xFEC7, 0x0180); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, + 0xEFDC, (code << 1 | 0x1021)); + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, + 0xFFFE, 0x0001); + udelay(20); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, + 0xFFFE, 0); + } + } + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) { -- GitLab From dfb4aa5dd0a9b61a6eaa64e9209b2f8839c0a256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 14:45:13 +0100 Subject: [PATCH 0760/3892] b43: N-PHY: add RSSI polling and setting 2055 (radio) VCM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 96 ++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 494c95246954..a0e84c428e79 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -586,6 +586,102 @@ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ +static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf) +{ + int i; + for (i = 0; i < 2; i++) { + if (type == 2) { + if (i == 0) { + b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM, + 0xFC, buf[0]); + b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, + 0xFC, buf[1]); + } else { + b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM, + 0xFC, buf[2 * i]); + b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, + 0xFC, buf[2 * i + 1]); + } + } else { + if (i == 0) + b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, + 0xF3, buf[0] << 2); + else + b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, + 0xF3, buf[2 * i + 1] << 2); + } + } +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ +static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, + u8 nsamp) +{ + int i; + int out; + u16 save_regs_phy[9]; + u16 s[2]; + + if (dev->phy.rev >= 3) { + save_regs_phy[0] = b43_phy_read(dev, + B43_NPHY_RFCTL_LUT_TRSW_UP1); + save_regs_phy[1] = b43_phy_read(dev, + B43_NPHY_RFCTL_LUT_TRSW_UP2); + save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); + save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); + save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); + save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); + save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); + } + + b43_nphy_rssi_select(dev, 5, type); + + if (dev->phy.rev < 2) { + save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL); + b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5); + } + + for (i = 0; i < 4; i++) + buf[i] = 0; + + for (i = 0; i < nsamp; i++) { + if (dev->phy.rev < 2) { + s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT); + s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT); + } else { + s[0] = b43_phy_read(dev, B43_NPHY_RSSI1); + s[1] = b43_phy_read(dev, B43_NPHY_RSSI2); + } + + buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2; + buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2; + buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2; + buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2; + } + out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 | + (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF); + + if (dev->phy.rev < 2) + b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]); + + if (dev->phy.rev >= 3) { + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, + save_regs_phy[0]); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, + save_regs_phy[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]); + b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]); + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]); + b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]); + } + + return out; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) { -- GitLab From 90b9738d85395d46ffdc961e1a0c80a17e8f4d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 14:48:21 +0100 Subject: [PATCH 0761/3892] b43: N-PHY: RSSI calibration for rev < 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 157 ++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index a0e84c428e79..126c0afa5da2 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -685,7 +685,160 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) { - /* TODO */ + int i, j; + u8 state[4]; + u8 code, val; + u16 class, override; + u8 regs_save_radio[2]; + u16 regs_save_phy[2]; + s8 offset[4]; + + u16 clip_state[2]; + u16 clip_off[2] = { 0xFFFF, 0xFFFF }; + s32 results_min[4] = { }; + u8 vcm_final[4] = { }; + s32 results[4][4] = { }; + s32 miniq[4][2] = { }; + + if (type == 2) { + code = 0; + val = 6; + } else if (type < 2) { + code = 25; + val = 4; + } else { + B43_WARN_ON(1); + return; + } + + class = b43_nphy_classifier(dev, 0, 0); + b43_nphy_classifier(dev, 7, 4); + b43_nphy_read_clip_detection(dev, clip_state); + b43_nphy_write_clip_detection(dev, clip_off); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + override = 0x140; + else + override = 0x110; + + regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); + regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override); + b43_radio_write16(dev, B2055_C1_PD_RXTX, val); + + regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); + regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override); + b43_radio_write16(dev, B2055_C2_PD_RXTX, val); + + state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07; + state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07; + b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8); + b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8); + state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07; + state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07; + + b43_nphy_rssi_select(dev, 5, type); + b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type); + b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type); + + for (i = 0; i < 4; i++) { + u8 tmp[4]; + for (j = 0; j < 4; j++) + tmp[j] = i; + if (type != 1) + b43_nphy_set_rssi_2055_vcm(dev, type, tmp); + b43_nphy_poll_rssi(dev, type, results[i], 8); + if (type < 2) + for (j = 0; j < 2; j++) + miniq[i][j] = min(results[i][2 * j], + results[i][2 * j + 1]); + } + + for (i = 0; i < 4; i++) { + s32 mind = 40; + u8 minvcm = 0; + s32 minpoll = 249; + s32 curr; + for (j = 0; j < 4; j++) { + if (type == 2) + curr = abs(results[j][i]); + else + curr = abs(miniq[j][i / 2] - code * 8); + + if (curr < mind) { + mind = curr; + minvcm = j; + } + + if (results[j][i] < minpoll) + minpoll = results[j][i]; + } + results_min[i] = minpoll; + vcm_final[i] = minvcm; + } + + if (type != 1) + b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final); + + for (i = 0; i < 4; i++) { + offset[i] = (code * 8) - results[vcm_final[i]][i]; + + if (offset[i] < 0) + offset[i] = -((abs(offset[i]) + 4) / 8); + else + offset[i] = (offset[i] + 4) / 8; + + if (results_min[i] == 248) + offset[i] = code - 32; + + if (i % 2 == 0) + b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0, + type); + else + b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1, + type); + } + + b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]); + b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]); + + switch (state[2]) { + case 1: + b43_nphy_rssi_select(dev, 1, 2); + break; + case 4: + b43_nphy_rssi_select(dev, 1, 0); + break; + case 2: + b43_nphy_rssi_select(dev, 1, 1); + break; + default: + b43_nphy_rssi_select(dev, 1, 1); + break; + } + + switch (state[3]) { + case 1: + b43_nphy_rssi_select(dev, 2, 2); + break; + case 4: + b43_nphy_rssi_select(dev, 2, 0); + break; + default: + b43_nphy_rssi_select(dev, 2, 1); + break; + } + + b43_nphy_rssi_select(dev, 0, type); + + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]); + b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]); + b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]); + + b43_nphy_classifier(dev, 7, class); + b43_nphy_write_clip_detection(dev, clip_state); } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ @@ -867,7 +1020,7 @@ int b43_phy_initn(struct b43_wldev *dev) if (nphy->antsel_type == 2) ;/*TODO NPHY Superswitch Init with argument 1*/ if (nphy->perical != 2) { - /* b43_nphy_rssi_cal(dev); */ + b43_nphy_rssi_cal(dev); if (phy->rev >= 3) { nphy->cal_orig_pwr_idx[0] = nphy->txpwrindex[0].index_internal; -- GitLab From e50cbcf6741684753da401722f337efacfa4a98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:02:38 +0100 Subject: [PATCH 0762/3892] b43: N-PHY: implement PA overriding (RF control related) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 38 ++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 126c0afa5da2..0e379427270a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -344,6 +344,40 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ +static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) +{ + struct b43_phy_n *nphy = dev->phy.n; + enum ieee80211_band band; + u16 tmp; + + if (!enable) { + nphy->rfctrl_intc1_save = b43_phy_read(dev, + B43_NPHY_RFCTL_INTC1); + nphy->rfctrl_intc2_save = b43_phy_read(dev, + B43_NPHY_RFCTL_INTC2); + band = b43_current_band(dev->wl); + if (dev->phy.rev >= 3) { + if (band == IEEE80211_BAND_5GHZ) + tmp = 0x600; + else + tmp = 0x480; + } else { + if (band == IEEE80211_BAND_5GHZ) + tmp = 0x180; + else + tmp = 0x120; + } + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp); + } else { + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, + nphy->rfctrl_intc1_save); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, + nphy->rfctrl_intc2_save); + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) { @@ -964,10 +998,10 @@ int b43_phy_initn(struct b43_wldev *dev) /* TODO N PHY MAC PHY Clock Set with argument 1 */ - /* b43_nphy_pa_override(dev, false); */ + b43_nphy_pa_override(dev, false); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - /* b43_nphy_pa_override(dev, true); */ + b43_nphy_pa_override(dev, true); b43_nphy_classifier(dev, 0, 0); b43_nphy_read_clip_detection(dev, clip); -- GitLab From 42e1547e5199ebfd41e3fb63db69dac8c4ed8d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:06:47 +0100 Subject: [PATCH 0763/3892] b43: N-PHY: add RSSI calibration restore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki ` Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 45 +++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 0e379427270a..b0ff3a3aaa7b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -896,6 +896,49 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev) } } +/* + * Restore RSSI Calibration + * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal + */ +static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + u16 *rssical_radio_regs = NULL; + u16 *rssical_phy_regs = NULL; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (!nphy->rssical_chanspec_2G) + return; + rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G; + rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G; + } else { + if (!nphy->rssical_chanspec_5G) + return; + rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G; + rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; + } + + /* TODO use some definitions */ + b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]); + b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]); + + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]); + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]); + + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]); + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]); + + b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]); + b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]); + b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]); +} + /* * Init N-PHY * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N @@ -1034,7 +1077,7 @@ int b43_phy_initn(struct b43_wldev *dev) if (do_rssi_cal) b43_nphy_rssi_cal(dev); else - ;/* b43_nphy_restore_rssi_cal(dev); */ + b43_nphy_restore_rssi_cal(dev); } else { b43_nphy_rssi_cal(dev); } -- GitLab From 5c1a140afbd3abeec92b74c91ad495cf69af4de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:10:54 +0100 Subject: [PATCH 0764/3892] b43: N-PHY: add function than forces (not) staying in carrier search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index b0ff3a3aaa7b..62ed7b7f6452 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -443,6 +443,29 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) return tmp; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ +static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; + + if (enable) { + u16 clip[] = { 0xFFFF, 0xFFFF }; + if (nphy->deaf_count++ == 0) { + nphy->classifier_state = b43_nphy_classifier(dev, 0, 0); + b43_nphy_classifier(dev, 0x7, 0); + b43_nphy_read_clip_detection(dev, nphy->clip_state); + b43_nphy_write_clip_detection(dev, clip); + } + b43_nphy_reset_cca(dev); + } else { + if (--nphy->deaf_count == 0) { + b43_nphy_classifier(dev, 0x7, nphy->classifier_state); + b43_nphy_write_clip_detection(dev, nphy->clip_state); + } + } +} + enum b43_nphy_rf_sequence { B43_RFSEQ_RX2TX, B43_RFSEQ_TX2RX, -- GitLab From a67162ab00d5f0d28f58a62ccd48e6a9cab07645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:16:25 +0100 Subject: [PATCH 0765/3892] b43: N-PHY: implement RX IQ coeffs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 62ed7b7f6452..3232a465e0a5 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -408,6 +408,23 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) /* TODO: N PHY Force RF Seq with argument 2 */ } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ +static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, + struct b43_phy_n_iq_comp *pcomp) +{ + if (write) { + b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0); + b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0); + b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1); + b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1); + } else { + pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0); + pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0); + pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1); + pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1); + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) { -- GitLab From 0914640072570f5867818884b8b78c0468b9747f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:17:10 +0100 Subject: [PATCH 0766/3892] b43: N-PHY: implement workaround for TX IQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3232a465e0a5..d67ba207783a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -425,6 +425,22 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ +static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) +{ + u16 array[4]; + int i; + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50); + for (i = 0; i < 4; i++) + array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) { -- GitLab From 2f258b74d13c200944ef018c71ed9d9a7d4da0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:18:35 +0100 Subject: [PATCH 0767/3892] b43: N-PHY: implement restoring general configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki a Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d67ba207783a..68c1582db712 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -995,6 +995,96 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ +static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (dev->phy.rev >= 6) { + /* TODO If the chip is 47162 + return txpwrctrl_tx_gain_ipa_rev5 */ + return txpwrctrl_tx_gain_ipa_rev6; + } else if (dev->phy.rev >= 5) { + return txpwrctrl_tx_gain_ipa_rev5; + } else { + return txpwrctrl_tx_gain_ipa; + } + } else { + return txpwrctrl_tx_gain_ipa_5g; + } +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ +static void b43_nphy_restore_cal(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + u16 coef[4]; + u16 *loft = NULL; + u16 *table = NULL; + + int i; + u16 *txcal_radio_regs = NULL; + struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (nphy->iqcal_chanspec_2G == 0) + return; + table = nphy->cal_cache.txcal_coeffs_2G; + loft = &nphy->cal_cache.txcal_coeffs_2G[5]; + } else { + if (nphy->iqcal_chanspec_5G == 0) + return; + table = nphy->cal_cache.txcal_coeffs_5G; + loft = &nphy->cal_cache.txcal_coeffs_5G[5]; + } + + /* TODO: Write an N PHY table with ID 15, length 4, offset 80, + width 16, and data from table */ + + for (i = 0; i < 4; i++) { + if (dev->phy.rev >= 3) + table[i] = coef[i]; + else + coef[i] = 0; + } + + /* TODO: Write an N PHY table with ID 15, length 4, offset 88, + width 16, and data from coef */ + /* TODO: Write an N PHY table with ID 15, length 2, offset 85, + width 16 and data from loft */ + /* TODO: Write an N PHY table with ID 15, length 2, offset 93, + width 16 and data from loft */ + + if (dev->phy.rev < 2) + b43_nphy_tx_iq_workaround(dev); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G; + rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G; + } else { + txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G; + rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G; + } + + /* TODO use some definitions */ + if (dev->phy.rev >= 3) { + b43_radio_write(dev, 0x2021, txcal_radio_regs[0]); + b43_radio_write(dev, 0x2022, txcal_radio_regs[1]); + b43_radio_write(dev, 0x3021, txcal_radio_regs[2]); + b43_radio_write(dev, 0x3022, txcal_radio_regs[3]); + b43_radio_write(dev, 0x2023, txcal_radio_regs[4]); + b43_radio_write(dev, 0x2024, txcal_radio_regs[5]); + b43_radio_write(dev, 0x3023, txcal_radio_regs[6]); + b43_radio_write(dev, 0x3024, txcal_radio_regs[7]); + } else { + b43_radio_write(dev, 0x8B, txcal_radio_regs[0]); + b43_radio_write(dev, 0xBA, txcal_radio_regs[1]); + b43_radio_write(dev, 0x8D, txcal_radio_regs[2]); + b43_radio_write(dev, 0xBC, txcal_radio_regs[3]); + } + b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); +} + /* * Init N-PHY * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N -- GitLab From 2faa6b832fb44b1910fe668a4ae127a69e998936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:26:12 +0100 Subject: [PATCH 0768/3892] b43: N-PHY: implement RX IQ estimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 68c1582db712..776d0082ef1c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -408,6 +408,45 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) /* TODO: N PHY Force RF Seq with argument 2 */ } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ +static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, + u16 samps, u8 time, bool wait) +{ + int i; + u16 tmp; + + b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps); + b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time); + if (wait) + b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE); + else + b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE); + + b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START); + + for (i = 1000; i; i--) { + tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD); + if (!(tmp & B43_NPHY_IQEST_CMD_START)) { + est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0); + est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0); + est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0); + + est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1); + est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1); + est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) | + b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1); + return; + } + udelay(10); + } + memset(est, 0, sizeof(*est)); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, struct b43_phy_n_iq_comp *pcomp) -- GitLab From 34a56f2cae865224829d3fa7b8d7ddeee139191f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:29:05 +0100 Subject: [PATCH 0769/3892] b43: N-PHY: implement calculating RX IQ comp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 99 ++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 776d0082ef1c..d08feffdce68 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -464,6 +464,105 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ +static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) +{ + int i; + s32 iq; + u32 ii; + u32 qq; + int iq_nbits, qq_nbits; + int arsh, brsh; + u16 tmp, a, b; + + struct nphy_iq_est est; + struct b43_phy_n_iq_comp old; + struct b43_phy_n_iq_comp new = { }; + bool error = false; + + if (mask == 0) + return; + + b43_nphy_rx_iq_coeffs(dev, false, &old); + b43_nphy_rx_iq_coeffs(dev, true, &new); + b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false); + new = old; + + for (i = 0; i < 2; i++) { + if (i == 0 && (mask & 1)) { + iq = est.iq0_prod; + ii = est.i0_pwr; + qq = est.q0_pwr; + } else if (i == 1 && (mask & 2)) { + iq = est.iq1_prod; + ii = est.i1_pwr; + qq = est.q1_pwr; + } else { + B43_WARN_ON(1); + continue; + } + + if (ii + qq < 2) { + error = true; + break; + } + + iq_nbits = fls(abs(iq)); + qq_nbits = fls(qq); + + arsh = iq_nbits - 20; + if (arsh >= 0) { + a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); + tmp = ii >> arsh; + } else { + a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); + tmp = ii << -arsh; + } + if (tmp == 0) { + error = true; + break; + } + a /= tmp; + + brsh = qq_nbits - 11; + if (brsh >= 0) { + b = (qq << (31 - qq_nbits)); + tmp = ii >> brsh; + } else { + b = (qq << (31 - qq_nbits)); + tmp = ii << -brsh; + } + if (tmp == 0) { + error = true; + break; + } + b = int_sqrt(b / tmp - a * a) - (1 << 10); + + if (i == 0 && (mask & 0x1)) { + if (dev->phy.rev >= 3) { + new.a0 = a & 0x3FF; + new.b0 = b & 0x3FF; + } else { + new.a0 = b & 0x3FF; + new.b0 = a & 0x3FF; + } + } else if (i == 1 && (mask & 0x2)) { + if (dev->phy.rev >= 3) { + new.a1 = a & 0x3FF; + new.b1 = b & 0x3FF; + } else { + new.a1 = b & 0x3FF; + new.b1 = a & 0x3FF; + } + } + } + + if (error) + new = old; + + b43_nphy_rx_iq_coeffs(dev, true, &new); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) { -- GitLab From b0022e15cc39abebd997fefa18cf3b6e141f76bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:40:50 +0100 Subject: [PATCH 0770/3892] b43: N-PHY: implement getting TX gains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 87 +++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d08feffdce68..e21526f2f24c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1151,6 +1151,89 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ +static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + u16 curr_gain[2]; + struct nphy_txgains target; + const u32 *table = NULL; + + if (nphy->txpwrctrl == 0) { + int i; + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, true); + /* TODO: Read an N PHY Table with ID 7, length 2, + offset 0x110, width 16, and curr_gain */ + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, false); + + for (i = 0; i < 2; ++i) { + if (dev->phy.rev >= 3) { + target.ipa[i] = curr_gain[i] & 0x000F; + target.pad[i] = (curr_gain[i] & 0x00F0) >> 4; + target.pga[i] = (curr_gain[i] & 0x0F00) >> 8; + target.txgm[i] = (curr_gain[i] & 0x7000) >> 12; + } else { + target.ipa[i] = curr_gain[i] & 0x0003; + target.pad[i] = (curr_gain[i] & 0x000C) >> 2; + target.pga[i] = (curr_gain[i] & 0x0070) >> 4; + target.txgm[i] = (curr_gain[i] & 0x0380) >> 7; + } + } + } else { + int i; + u16 index[2]; + index[0] = (b43_phy_read(dev, B43_NPHY_C1_TXPCTL_STAT) & + B43_NPHY_TXPCTL_STAT_BIDX) >> + B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; + index[1] = (b43_phy_read(dev, B43_NPHY_C2_TXPCTL_STAT) & + B43_NPHY_TXPCTL_STAT_BIDX) >> + B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; + + for (i = 0; i < 2; ++i) { + if (dev->phy.rev >= 3) { + enum ieee80211_band band = + b43_current_band(dev->wl); + + if ((nphy->ipa2g_on && + band == IEEE80211_BAND_2GHZ) || + (nphy->ipa5g_on && + band == IEEE80211_BAND_5GHZ)) { + table = b43_nphy_get_ipa_gain_table(dev); + } else { + if (band == IEEE80211_BAND_5GHZ) { + if (dev->phy.rev == 3) + table = b43_ntab_tx_gain_rev3_5ghz; + else if (dev->phy.rev == 4) + table = b43_ntab_tx_gain_rev4_5ghz; + else + table = b43_ntab_tx_gain_rev5plus_5ghz; + } else { + table = b43_ntab_tx_gain_rev3plus_2ghz; + } + } + + target.ipa[i] = (table[index[i]] >> 16) & 0xF; + target.pad[i] = (table[index[i]] >> 20) & 0xF; + target.pga[i] = (table[index[i]] >> 24) & 0xF; + target.txgm[i] = (table[index[i]] >> 28) & 0xF; + } else { + table = b43_ntab_tx_gain_rev0_1_2; + + target.ipa[i] = (table[index[i]] >> 16) & 0x3; + target.pad[i] = (table[index[i]] >> 18) & 0x3; + target.pga[i] = (table[index[i]] >> 20) & 0x7; + target.txgm[i] = (table[index[i]] >> 23) & 0x7; + } + } + } + + return target; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ static void b43_nphy_restore_cal(struct b43_wldev *dev) { @@ -1376,7 +1459,7 @@ int b43_phy_initn(struct b43_wldev *dev) do_cal = false; if (do_cal) { - /* target = b43_nphy_get_tx_gains(dev); */ + target = b43_nphy_get_tx_gains(dev); if (nphy->antsel_type == 2) ;/*TODO NPHY Superswitch Init with argument 1*/ @@ -1388,7 +1471,7 @@ int b43_phy_initn(struct b43_wldev *dev) nphy->cal_orig_pwr_idx[1] = nphy->txpwrindex[1].index_internal; /* TODO N PHY Pre Calibrate TX Gain */ - /*target = b43_nphy_get_tx_gains(dev)*/ + target = b43_nphy_get_tx_gains(dev); } } } -- GitLab From fe3e46e881daad2c7e3886e767bda90871d5f4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:51:55 +0100 Subject: [PATCH 0771/3892] b43: N-PHY: add TX LP FBW (TX filter 40 related) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e21526f2f24c..242f16d489fa 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -378,6 +378,28 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ +static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + u16 tmp; + enum ieee80211_band band = b43_current_band(dev->wl); + bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) || + (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ); + + if (dev->phy.rev >= 3) { + if (ipa) { + tmp = 4; + b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, + (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); + } + + tmp = 1; + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2, + (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) { @@ -1494,7 +1516,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); if (phy->rev >= 3 && phy->rev <= 6) b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); - /* b43_nphy_tx_lp_fbw(dev); */ + b43_nphy_tx_lp_fbw(dev); /* TODO N PHY Spur Workaround */ b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); -- GitLab From c4a92003b0d02367bb1be94867a79651897e91ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 15:55:18 +0100 Subject: [PATCH 0772/3892] b43: N-PHY: add RX radio cores calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 242f16d489fa..3e587d73619e 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1173,6 +1173,49 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ +static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + u16 *save = nphy->tx_rx_cal_radio_saveregs; + + if (dev->phy.rev >= 3) { + /* TODO */ + } else { + save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1); + b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29); + + save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2); + b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54); + + save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1); + b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29); + + save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2); + b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54); + + save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX); + save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX); + + if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) & + B43_NPHY_BANDCTL_5GHZ)) { + b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04); + b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04); + } else { + b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20); + b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20); + } + + if (dev->phy.rev < 2) { + b43_radio_set(dev, B2055_C1_TX_BB_MXGM, 0x20); + b43_radio_set(dev, B2055_C2_TX_BB_MXGM, 0x20); + } else { + b43_radio_mask(dev, B2055_C1_TX_BB_MXGM, ~0x20); + b43_radio_mask(dev, B2055_C2_TX_BB_MXGM, ~0x20); + } + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) { -- GitLab From de7ed0c6245276eaa62523ffb36512d88bf1efb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:06:35 +0100 Subject: [PATCH 0773/3892] b43: N-PHY: update TX calibration ladder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3e587d73619e..d09a16f76007 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1216,6 +1216,31 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ +static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i; + u16 scale, entry; + + u16 tmp = nphy->txcal_bbmult; + if (core == 0) + tmp >>= 8; + tmp &= 0xff; + + for (i = 0; i < 18; i++) { + scale = (ladder_lo[i].percent * tmp) / 100; + entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env; + /* TODO: Write an N PHY Table with ID 15, length 1, + offset i, width 16, and data entry */ + + scale = (ladder_iq[i].percent * tmp) / 100; + entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env; + /* TODO: Write an N PHY Table with ID 15, length 1, + offset i + 32, width 16, and data entry */ + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) { -- GitLab From e9762492f5c7176660ed030e9dd816b3208def12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:08:25 +0100 Subject: [PATCH 0774/3892] b43: N-PHY: implement calculating IQ gain params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d09a16f76007..8a3bc2c58a81 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1216,6 +1216,44 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ +static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, + struct nphy_txgains target, + struct nphy_iqcal_params *params) +{ + int i, j, indx; + u16 gain; + + if (dev->phy.rev >= 3) { + params->txgm = target.txgm[core]; + params->pga = target.pga[core]; + params->pad = target.pad[core]; + params->ipa = target.ipa[core]; + params->cal_gain = (params->txgm << 12) | (params->pga << 8) | + (params->pad << 4) | (params->ipa); + for (j = 0; j < 5; j++) + params->ncorr[j] = 0x79; + } else { + gain = (target.pad[core]) | (target.pga[core] << 4) | + (target.txgm[core] << 8); + + indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? + 1 : 0; + for (i = 0; i < 9; i++) + if (tbl_iqcal_gainparams[indx][i][0] == gain) + break; + i = min(i, 8); + + params->txgm = tbl_iqcal_gainparams[indx][i][1]; + params->pga = tbl_iqcal_gainparams[indx][i][2]; + params->pad = tbl_iqcal_gainparams[indx][i][3]; + params->cal_gain = (params->txgm << 7) | (params->pga << 4) | + (params->pad << 2); + for (j = 0; j < 4; j++) + params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j]; + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) { -- GitLab From fb43b8e23519f853f142202bb341c21382f39070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:10:48 +0100 Subject: [PATCH 0775/3892] b43: N-PHY: add huge calculating TX IQ LO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 226 +++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8a3bc2c58a81..4111a4626001 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1434,6 +1434,232 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ +static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, + struct nphy_txgains target, + bool full, bool mphase) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i; + int error = 0; + int freq; + bool avoid = false; + u8 length; + u16 tmp, core, type, count, max, numb, last, cmd; + const u16 *table; + bool phy6or5x; + + u16 buffer[11]; + u16 diq_start = 0; + u16 save[2]; + u16 gain[2]; + struct nphy_iqcal_params params[2]; + bool updated[2] = { }; + + b43_nphy_stay_in_carrier_search(dev, true); + + if (dev->phy.rev >= 4) { + avoid = nphy->hang_avoid; + nphy->hang_avoid = 0; + } + + /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data pointer save */ + + for (i = 0; i < 2; i++) { + b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); + gain[i] = params[i].cal_gain; + } + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data pointer gain */ + + b43_nphy_tx_cal_radio_setup(dev); + /* TODO: Call N PHY TX Cal PHY Setup */ + + phy6or5x = dev->phy.rev >= 6 || + (dev->phy.rev == 5 && nphy->ipa2g_on && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); + if (phy6or5x) { + /* TODO */ + } + + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); + + if (1 /* FIXME: the band width is 20 MHz */) + freq = 2500; + else + freq = 5000; + + if (nphy->mphase_cal_phase_id > 2) + ;/* TODO: Call N PHY Run Samples with (band width * 8), + 0xFFFF, 0, 1, 0 as arguments */ + else + ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments + and save result as error */ + + if (error == 0) { + if (nphy->mphase_cal_phase_id > 2) { + table = nphy->mphase_txcal_bestcoeffs; + length = 11; + if (dev->phy.rev < 3) + length -= 2; + } else { + if (!full && nphy->txiqlocal_coeffsvalid) { + table = nphy->txiqlocal_bestc; + length = 11; + if (dev->phy.rev < 3) + length -= 2; + } else { + full = true; + if (dev->phy.rev >= 3) { + table = tbl_tx_iqlo_cal_startcoefs_nphyrev3; + length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3; + } else { + table = tbl_tx_iqlo_cal_startcoefs; + length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS; + } + } + } + + /* TODO: Write an N PHY Table with ID 15, length from above, + offset 64, width 16, and the data pointer from above */ + + if (full) { + if (dev->phy.rev >= 3) + max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3; + else + max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL; + } else { + if (dev->phy.rev >= 3) + max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3; + else + max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL; + } + + if (mphase) { + count = nphy->mphase_txcal_cmdidx; + numb = min(max, + (u16)(count + nphy->mphase_txcal_numcmds)); + } else { + count = 0; + numb = max; + } + + for (; count < numb; count++) { + if (full) { + if (dev->phy.rev >= 3) + cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count]; + else + cmd = tbl_tx_iqlo_cal_cmds_fullcal[count]; + } else { + if (dev->phy.rev >= 3) + cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count]; + else + cmd = tbl_tx_iqlo_cal_cmds_recal[count]; + } + + core = (cmd & 0x3000) >> 12; + type = (cmd & 0x0F00) >> 8; + + if (phy6or5x && updated[core] == 0) { + b43_nphy_update_tx_cal_ladder(dev, core); + updated[core] = 1; + } + + tmp = (params[core].ncorr[type] << 8) | 0x66; + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp); + + if (type == 1 || type == 3 || type == 4) { + /* TODO: Read an N PHY Table with ID 15, + length 1, offset 69 + core, + width 16, and data pointer buffer */ + diq_start = buffer[0]; + buffer[0] = 0; + /* TODO: Write an N PHY Table with ID 15, + length 1, offset 69 + core, width 16, + and data of 0 */ + } + + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd); + for (i = 0; i < 2000; i++) { + tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD); + if (tmp & 0xC000) + break; + udelay(10); + } + + /* TODO: Read an N PHY Table with ID 15, + length table_length, offset 96, width 16, + and data pointer buffer */ + /* TODO: Write an N PHY Table with ID 15, + length table_length, offset 64, width 16, + and data pointer buffer */ + + if (type == 1 || type == 3 || type == 4) + buffer[0] = diq_start; + } + + if (mphase) + nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb; + + last = (dev->phy.rev < 3) ? 6 : 7; + + if (!mphase || nphy->mphase_cal_phase_id == last) { + /* TODO: Write an N PHY Table with ID 15, length 4, + offset 96, width 16, and data pointer buffer */ + /* TODO: Read an N PHY Table with ID 15, length 4, + offset 80, width 16, and data pointer buffer */ + if (dev->phy.rev < 3) { + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + buffer[3] = 0; + } + /* TODO: Write an N PHY Table with ID 15, length 4, + offset 88, width 16, and data pointer buffer */ + /* TODO: Read an N PHY Table with ID 15, length 2, + offset 101, width 16, and data pointer buffer*/ + /* TODO: Write an N PHY Table with ID 15, length 2, + offset 85, width 16, and data pointer buffer */ + /* TODO: Write an N PHY Table with ID 15, length 2, + offset 93, width 16, and data pointer buffer */ + length = 11; + if (dev->phy.rev < 3) + length -= 2; + /* TODO: Read an N PHY Table with ID 15, length length, + offset 96, width 16, and data pointer + nphy->txiqlocal_bestc */ + nphy->txiqlocal_coeffsvalid = true; + /* TODO: Set nphy->txiqlocal_chanspec to + the current channel */ + } else { + length = 11; + if (dev->phy.rev < 3) + length -= 2; + /* TODO: Read an N PHY Table with ID 5, length length, + offset 96, width 16, and data pointer + nphy->mphase_txcal_bestcoeffs */ + } + + /* TODO: Call N PHY Stop Playback */ + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); + } + + /* TODO: Call N PHY TX Cal PHY Cleanup */ + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data from save */ + + if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last)) + b43_nphy_tx_iq_workaround(dev); + + if (dev->phy.rev >= 4) + nphy->hang_avoid = avoid; + + b43_nphy_stay_in_carrier_search(dev, false); + + return error; +} + /* * Init N-PHY * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N -- GitLab From 15931e318b27e85ea06f44d53abc3d3e6a3fc9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:20:56 +0100 Subject: [PATCH 0776/3892] b43: N-PHY: add RX IQ calibrationi for rev < 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 206 ++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 4111a4626001..f982f56d5bf3 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1660,6 +1660,206 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, return error; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ +static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, + struct nphy_txgains target, u8 type, bool debug) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i, j, index; + u8 rfctl[2]; + u8 afectl_core; + u16 tmp[6]; + u16 cur_hpf1, cur_hpf2, cur_lna; + u32 real, imag; + enum ieee80211_band band; + + u8 use; + u16 cur_hpf; + u16 lna[3] = { 3, 3, 1 }; + u16 hpf1[3] = { 7, 2, 0 }; + u16 hpf2[3] = { 2, 0, 0 }; + u32 power[3]; + u16 gain_save[2]; + u16 cal_gain[2]; + struct nphy_iqcal_params cal_params[2]; + struct nphy_iq_est est; + int ret = 0; + bool playtone = true; + int desired = 13; + + b43_nphy_stay_in_carrier_search(dev, 1); + + if (dev->phy.rev < 2) + ;/* TODO: Call N PHY Reapply TX Cal Coeffs */ + /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data gain_save */ + for (i = 0; i < 2; i++) { + b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); + cal_gain[i] = cal_params[i].cal_gain; + } + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data from cal_gain */ + + for (i = 0; i < 2; i++) { + if (i == 0) { + rfctl[0] = B43_NPHY_RFCTL_INTC1; + rfctl[1] = B43_NPHY_RFCTL_INTC2; + afectl_core = B43_NPHY_AFECTL_C1; + } else { + rfctl[0] = B43_NPHY_RFCTL_INTC2; + rfctl[1] = B43_NPHY_RFCTL_INTC1; + afectl_core = B43_NPHY_AFECTL_C2; + } + + tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA); + tmp[2] = b43_phy_read(dev, afectl_core); + tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + tmp[4] = b43_phy_read(dev, rfctl[0]); + tmp[5] = b43_phy_read(dev, rfctl[1]); + + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, + (u16)~B43_NPHY_RFSEQCA_RXDIS, + ((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT)); + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN, + (1 - i)); + b43_phy_set(dev, afectl_core, 0x0006); + b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006); + + band = b43_current_band(dev->wl); + + if (nphy->rxcalparams & 0xFF000000) { + if (band == IEEE80211_BAND_5GHZ) + b43_phy_write(dev, rfctl[0], 0x140); + else + b43_phy_write(dev, rfctl[0], 0x110); + } else { + if (band == IEEE80211_BAND_5GHZ) + b43_phy_write(dev, rfctl[0], 0x180); + else + b43_phy_write(dev, rfctl[0], 0x120); + } + + if (band == IEEE80211_BAND_5GHZ) + b43_phy_write(dev, rfctl[1], 0x148); + else + b43_phy_write(dev, rfctl[1], 0x114); + + if (nphy->rxcalparams & 0x10000) { + b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC, + (i + 1)); + b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC, + (2 - i)); + } + + for (j = 0; i < 4; j++) { + if (j < 3) { + cur_lna = lna[j]; + cur_hpf1 = hpf1[j]; + cur_hpf2 = hpf2[j]; + } else { + if (power[1] > 10000) { + use = 1; + cur_hpf = cur_hpf1; + index = 2; + } else { + if (power[0] > 10000) { + use = 1; + cur_hpf = cur_hpf1; + index = 1; + } else { + index = 0; + use = 2; + cur_hpf = cur_hpf2; + } + } + cur_lna = lna[index]; + cur_hpf1 = hpf1[index]; + cur_hpf2 = hpf2[index]; + cur_hpf += desired - hweight32(power[index]); + cur_hpf = clamp_val(cur_hpf, 0, 10); + if (use == 1) + cur_hpf1 = cur_hpf; + else + cur_hpf2 = cur_hpf; + } + + tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) | + (cur_lna << 2)); + /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0], + 3, 0 as arguments */ + /* TODO: Call N PHY Force RF Seq with 2 as argument */ + /* TODO: Call N PHT Stop Playback */ + + if (playtone) { + /* TODO: Call N PHY TX Tone with 4000, + (nphy_rxcalparams & 0xffff), 0, 0 + as arguments and save result as ret */ + playtone = false; + } else { + /* TODO: Call N PHY Run Samples with 160, + 0xFFFF, 0, 0, 0 as arguments */ + } + + if (ret == 0) { + if (j < 3) { + b43_nphy_rx_iq_est(dev, &est, 1024, 32, + false); + if (i == 0) { + real = est.i0_pwr; + imag = est.q0_pwr; + } else { + real = est.i1_pwr; + imag = est.q1_pwr; + } + power[i] = ((real + imag) / 1024) + 1; + } else { + b43_nphy_calc_rx_iq_comp(dev, 1 << i); + } + /* TODO: Call N PHY Stop Playback */ + } + + if (ret != 0) + break; + } + + b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC); + b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC); + b43_phy_write(dev, rfctl[1], tmp[5]); + b43_phy_write(dev, rfctl[0], tmp[4]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]); + b43_phy_write(dev, afectl_core, tmp[2]); + b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]); + + if (ret != 0) + break; + } + + /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/ + /* TODO: Call N PHY Force RF Seq with 2 as argument */ + /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, + width 16, and data from gain_save */ + + b43_nphy_stay_in_carrier_search(dev, 0); + + return ret; +} + +static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, + struct nphy_txgains target, u8 type, bool debug) +{ + return -1; +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ +static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, + struct nphy_txgains target, u8 type, bool debug) +{ + if (dev->phy.rev >= 3) + return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug); + else + return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); +} + /* * Init N-PHY * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N @@ -1831,16 +2031,14 @@ int b43_phy_initn(struct b43_wldev *dev) } } - /* if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) - Call N PHY Save Cal + ;/* Call N PHY Save Cal */ else if (nphy->mphase_cal_phase_id == 0) - N PHY Periodic Calibration with argument 3 + ;/* N PHY Periodic Calibration with argument 3 */ } else { b43_nphy_restore_cal(dev); } - */ /* b43_nphy_tx_pwr_ctrl_coef_setup(dev); */ /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */ -- GitLab From 6dcd9d911cace479ff5612dab3896c8fceb60773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:24:57 +0100 Subject: [PATCH 0777/3892] b43: N-PHY: implement TX power control coef setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 69 +++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index f982f56d5bf3..a0e8283519fd 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -659,6 +659,73 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ +static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i, j; + u32 tmp; + u32 cur_real, cur_imag, real_part, imag_part; + + u16 buffer[7]; + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, true); + + /* TODO: Read an N PHY Table with ID 15, length 7, offset 80, + width 16, and data pointer buffer */ + + for (i = 0; i < 2; i++) { + tmp = ((buffer[i * 2] & 0x3FF) << 10) | + (buffer[i * 2 + 1] & 0x3FF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, + (((i + 26) << 10) | 320)); + for (j = 0; j < 128; j++) { + b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, + ((tmp >> 16) & 0xFFFF)); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (tmp & 0xFFFF)); + } + } + + for (i = 0; i < 2; i++) { + tmp = buffer[5 + i]; + real_part = (tmp >> 8) & 0xFF; + imag_part = (tmp & 0xFF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, + (((i + 26) << 10) | 448)); + + if (dev->phy.rev >= 3) { + cur_real = real_part; + cur_imag = imag_part; + tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF); + } + + for (j = 0; j < 128; j++) { + if (dev->phy.rev < 3) { + cur_real = (real_part * loscale[j] + 128) >> 8; + cur_imag = (imag_part * loscale[j] + 128) >> 8; + tmp = ((cur_real & 0xFF) << 8) | + (cur_imag & 0xFF); + } + b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, + ((tmp >> 16) & 0xFFFF)); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (tmp & 0xFFFF)); + } + } + + if (dev->phy.rev >= 3) { + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF); + } + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, false); +} + enum b43_nphy_rf_sequence { B43_RFSEQ_RX2TX, B43_RFSEQ_TX2RX, @@ -2040,7 +2107,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_restore_cal(dev); } - /* b43_nphy_tx_pwr_ctrl_coef_setup(dev); */ + b43_nphy_tx_pwr_ctrl_coef_setup(dev); /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */ b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015); b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); -- GitLab From 730dd70549e0ec755dd55615ba5cfc38a482a947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 15 Jan 2010 16:38:07 +0100 Subject: [PATCH 0778/3892] b43: N-PHY: drop unused definition, uncomment needed call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index a0e8283519fd..4a817e3da163 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -222,12 +222,6 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev) ~B43_NPHY_RFCTL_CMD_EN); } -#define ntab_upload(dev, offset, data) do { \ - unsigned int i; \ - for (i = 0; i < (offset##_SIZE); i++) \ - b43_ntab_write(dev, (offset) + i, (data)[i]); \ - } while (0) - /* * Upload the N-PHY tables. * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables @@ -2021,11 +2015,11 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_workarounds(dev); /* Reset CCA, in init code it differs a little from standard way */ - /* b43_nphy_bmac_clock_fgc(dev, 1); */ + b43_nphy_bmac_clock_fgc(dev, 1); tmp = b43_phy_read(dev, B43_NPHY_BBCFG); b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA); b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); - /* b43_nphy_bmac_clock_fgc(dev, 0); */ + b43_nphy_bmac_clock_fgc(dev, 0); /* TODO N PHY MAC PHY Clock Set with argument 1 */ -- GitLab From b87babeb40aaf879d20268792390ce831805a557 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:27 +0000 Subject: [PATCH 0779/3892] qlge: Add data for firmware dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 403 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 5 deletions(-) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index ee0e2bd4842f..a265325abb15 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -75,15 +75,43 @@ #define TX_DESC_PER_OAL 0 #endif +/* Word shifting for converting 64-bit + * address to a series of 16-bit words. + * This is used for some MPI firmware + * mailbox commands. + */ +#define LSW(x) ((u16)(x)) +#define MSW(x) ((u16)((u32)(x) >> 16)) +#define LSD(x) ((u32)((u64)(x))) +#define MSD(x) ((u32)((((u64)(x)) >> 32))) + /* MPI test register definitions. This register * is used for determining alternate NIC function's * PCI->func number. */ enum { MPI_TEST_FUNC_PORT_CFG = 0x1002, + MPI_TEST_FUNC_PRB_CTL = 0x100e, + MPI_TEST_FUNC_PRB_EN = 0x18a20000, + MPI_TEST_FUNC_RST_STS = 0x100a, + MPI_TEST_FUNC_RST_FRC = 0x00000003, + MPI_TEST_NIC_FUNC_MASK = 0x00000007, + MPI_TEST_NIC1_FUNCTION_ENABLE = (1 << 0), + MPI_TEST_NIC1_FUNCTION_MASK = 0x0000000e, MPI_TEST_NIC1_FUNC_SHIFT = 1, + MPI_TEST_NIC2_FUNCTION_ENABLE = (1 << 4), + MPI_TEST_NIC2_FUNCTION_MASK = 0x000000e0, MPI_TEST_NIC2_FUNC_SHIFT = 5, - MPI_TEST_NIC_FUNC_MASK = 0x00000007, + MPI_TEST_FC1_FUNCTION_ENABLE = (1 << 8), + MPI_TEST_FC1_FUNCTION_MASK = 0x00000e00, + MPI_TEST_FC1_FUNCTION_SHIFT = 9, + MPI_TEST_FC2_FUNCTION_ENABLE = (1 << 12), + MPI_TEST_FC2_FUNCTION_MASK = 0x0000e000, + MPI_TEST_FC2_FUNCTION_SHIFT = 13, + + MPI_NIC_READ = 0x00000000, + MPI_NIC_REG_BLOCK = 0x00020000, + MPI_NIC_FUNCTION_SHIFT = 6, }; /* @@ -464,7 +492,7 @@ enum { MDIO_PORT = 0x00000440, MDIO_STATUS = 0x00000450, - /* XGMAC AUX statistics registers */ + XGMAC_REGISTER_END = 0x00000740, }; /* @@ -505,6 +533,7 @@ enum { enum { MAC_ADDR_IDX_SHIFT = 4, MAC_ADDR_TYPE_SHIFT = 16, + MAC_ADDR_TYPE_COUNT = 10, MAC_ADDR_TYPE_MASK = 0x000f0000, MAC_ADDR_TYPE_CAM_MAC = 0x00000000, MAC_ADDR_TYPE_MULTI_MAC = 0x00010000, @@ -522,6 +551,30 @@ enum { MAC_ADDR_MR = (1 << 30), MAC_ADDR_MW = (1 << 31), MAX_MULTICAST_ENTRIES = 32, + + /* Entry count and words per entry + * for each address type in the filter. + */ + MAC_ADDR_MAX_CAM_ENTRIES = 512, + MAC_ADDR_MAX_CAM_WCOUNT = 3, + MAC_ADDR_MAX_MULTICAST_ENTRIES = 32, + MAC_ADDR_MAX_MULTICAST_WCOUNT = 2, + MAC_ADDR_MAX_VLAN_ENTRIES = 4096, + MAC_ADDR_MAX_VLAN_WCOUNT = 1, + MAC_ADDR_MAX_MCAST_FLTR_ENTRIES = 4096, + MAC_ADDR_MAX_MCAST_FLTR_WCOUNT = 1, + MAC_ADDR_MAX_FC_MAC_ENTRIES = 4, + MAC_ADDR_MAX_FC_MAC_WCOUNT = 2, + MAC_ADDR_MAX_MGMT_MAC_ENTRIES = 8, + MAC_ADDR_MAX_MGMT_MAC_WCOUNT = 2, + MAC_ADDR_MAX_MGMT_VLAN_ENTRIES = 16, + MAC_ADDR_MAX_MGMT_VLAN_WCOUNT = 1, + MAC_ADDR_MAX_MGMT_V4_ENTRIES = 4, + MAC_ADDR_MAX_MGMT_V4_WCOUNT = 1, + MAC_ADDR_MAX_MGMT_V6_ENTRIES = 4, + MAC_ADDR_MAX_MGMT_V6_WCOUNT = 4, + MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES = 4, + MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT = 1, }; /* @@ -592,6 +645,7 @@ enum { enum { RT_IDX_IDX_SHIFT = 8, RT_IDX_TYPE_MASK = 0x000f0000, + RT_IDX_TYPE_SHIFT = 16, RT_IDX_TYPE_RT = 0x00000000, RT_IDX_TYPE_RT_INV = 0x00010000, RT_IDX_TYPE_NICQ = 0x00020000, @@ -660,7 +714,89 @@ enum { RT_IDX_UNUSED013 = 13, RT_IDX_UNUSED014 = 14, RT_IDX_PROMISCUOUS_SLOT = 15, - RT_IDX_MAX_SLOTS = 16, + RT_IDX_MAX_RT_SLOTS = 8, + RT_IDX_MAX_NIC_SLOTS = 16, +}; + +/* + * Serdes Address Register (XG_SERDES_ADDR) bit definitions. + */ +enum { + XG_SERDES_ADDR_RDY = (1 << 31), + XG_SERDES_ADDR_R = (1 << 30), + + XG_SERDES_ADDR_STS = 0x00001E06, + XG_SERDES_ADDR_XFI1_PWR_UP = 0x00000005, + XG_SERDES_ADDR_XFI2_PWR_UP = 0x0000000a, + XG_SERDES_ADDR_XAUI_PWR_DOWN = 0x00000001, + + /* Serdes coredump definitions. */ + XG_SERDES_XAUI_AN_START = 0x00000000, + XG_SERDES_XAUI_AN_END = 0x00000034, + XG_SERDES_XAUI_HSS_PCS_START = 0x00000800, + XG_SERDES_XAUI_HSS_PCS_END = 0x0000880, + XG_SERDES_XFI_AN_START = 0x00001000, + XG_SERDES_XFI_AN_END = 0x00001034, + XG_SERDES_XFI_TRAIN_START = 0x10001050, + XG_SERDES_XFI_TRAIN_END = 0x1000107C, + XG_SERDES_XFI_HSS_PCS_START = 0x00001800, + XG_SERDES_XFI_HSS_PCS_END = 0x00001838, + XG_SERDES_XFI_HSS_TX_START = 0x00001c00, + XG_SERDES_XFI_HSS_TX_END = 0x00001c1f, + XG_SERDES_XFI_HSS_RX_START = 0x00001c40, + XG_SERDES_XFI_HSS_RX_END = 0x00001c5f, + XG_SERDES_XFI_HSS_PLL_START = 0x00001e00, + XG_SERDES_XFI_HSS_PLL_END = 0x00001e1f, +}; + +/* + * NIC Probe Mux Address Register (PRB_MX_ADDR) bit definitions. + */ +enum { + PRB_MX_ADDR_ARE = (1 << 16), + PRB_MX_ADDR_UP = (1 << 15), + PRB_MX_ADDR_SWP = (1 << 14), + + /* Module select values. */ + PRB_MX_ADDR_MAX_MODS = 21, + PRB_MX_ADDR_MOD_SEL_SHIFT = 9, + PRB_MX_ADDR_MOD_SEL_TBD = 0, + PRB_MX_ADDR_MOD_SEL_IDE1 = 1, + PRB_MX_ADDR_MOD_SEL_IDE2 = 2, + PRB_MX_ADDR_MOD_SEL_FRB = 3, + PRB_MX_ADDR_MOD_SEL_ODE1 = 4, + PRB_MX_ADDR_MOD_SEL_ODE2 = 5, + PRB_MX_ADDR_MOD_SEL_DA1 = 6, + PRB_MX_ADDR_MOD_SEL_DA2 = 7, + PRB_MX_ADDR_MOD_SEL_IMP1 = 8, + PRB_MX_ADDR_MOD_SEL_IMP2 = 9, + PRB_MX_ADDR_MOD_SEL_OMP1 = 10, + PRB_MX_ADDR_MOD_SEL_OMP2 = 11, + PRB_MX_ADDR_MOD_SEL_ORS1 = 12, + PRB_MX_ADDR_MOD_SEL_ORS2 = 13, + PRB_MX_ADDR_MOD_SEL_REG = 14, + PRB_MX_ADDR_MOD_SEL_MAC1 = 16, + PRB_MX_ADDR_MOD_SEL_MAC2 = 17, + PRB_MX_ADDR_MOD_SEL_VQM1 = 18, + PRB_MX_ADDR_MOD_SEL_VQM2 = 19, + PRB_MX_ADDR_MOD_SEL_MOP = 20, + /* Bit fields indicating which modules + * are valid for each clock domain. + */ + PRB_MX_ADDR_VALID_SYS_MOD = 0x000f7ff7, + PRB_MX_ADDR_VALID_PCI_MOD = 0x000040c1, + PRB_MX_ADDR_VALID_XGM_MOD = 0x00037309, + PRB_MX_ADDR_VALID_FC_MOD = 0x00003001, + PRB_MX_ADDR_VALID_TOTAL = 34, + + /* Clock domain values. */ + PRB_MX_ADDR_CLOCK_SHIFT = 6, + PRB_MX_ADDR_SYS_CLOCK = 0, + PRB_MX_ADDR_PCI_CLOCK = 2, + PRB_MX_ADDR_FC_CLOCK = 5, + PRB_MX_ADDR_XGM_CLOCK = 6, + + PRB_MX_ADDR_MAX_MUX = 64, }; /* @@ -1432,7 +1568,7 @@ struct nic_stats { u64 rx_nic_fifo_drop; }; -/* Address/Length pairs for the coredump. */ +/* Firmware coredump internal register address/length pairs. */ enum { MPI_CORE_REGS_ADDR = 0x00030000, MPI_CORE_REGS_CNT = 127, @@ -1487,7 +1623,7 @@ struct mpi_coredump_segment_header { u8 description[16]; }; -/* Reg dump segment numbers. */ +/* Firmware coredump header segment numbers. */ enum { CORE_SEG_NUM = 1, TEST_LOGIC_SEG_NUM = 2, @@ -1538,6 +1674,67 @@ enum { }; +/* There are 64 generic NIC registers. */ +#define NIC_REGS_DUMP_WORD_COUNT 64 +/* XGMAC word count. */ +#define XGMAC_DUMP_WORD_COUNT (XGMAC_REGISTER_END / 4) +/* Word counts for the SERDES blocks. */ +#define XG_SERDES_XAUI_AN_COUNT 14 +#define XG_SERDES_XAUI_HSS_PCS_COUNT 33 +#define XG_SERDES_XFI_AN_COUNT 14 +#define XG_SERDES_XFI_TRAIN_COUNT 12 +#define XG_SERDES_XFI_HSS_PCS_COUNT 15 +#define XG_SERDES_XFI_HSS_TX_COUNT 32 +#define XG_SERDES_XFI_HSS_RX_COUNT 32 +#define XG_SERDES_XFI_HSS_PLL_COUNT 32 + +/* There are 2 CNA ETS and 8 NIC ETS registers. */ +#define ETS_REGS_DUMP_WORD_COUNT 10 + +/* Each probe mux entry stores the probe type plus 64 entries + * that are each each 64-bits in length. There are a total of + * 34 (PRB_MX_ADDR_VALID_TOTAL) valid probes. + */ +#define PRB_MX_ADDR_PRB_WORD_COUNT (1 + (PRB_MX_ADDR_MAX_MUX * 2)) +#define PRB_MX_DUMP_TOT_COUNT (PRB_MX_ADDR_PRB_WORD_COUNT * \ + PRB_MX_ADDR_VALID_TOTAL) +/* Each routing entry consists of 4 32-bit words. + * They are route type, index, index word, and result. + * There are 2 route blocks with 8 entries each and + * 2 NIC blocks with 16 entries each. + * The totol entries is 48 with 4 words each. + */ +#define RT_IDX_DUMP_ENTRIES 48 +#define RT_IDX_DUMP_WORDS_PER_ENTRY 4 +#define RT_IDX_DUMP_TOT_WORDS (RT_IDX_DUMP_ENTRIES * \ + RT_IDX_DUMP_WORDS_PER_ENTRY) +/* There are 10 address blocks in filter, each with + * different entry counts and different word-count-per-entry. + */ +#define MAC_ADDR_DUMP_ENTRIES \ + ((MAC_ADDR_MAX_CAM_ENTRIES * MAC_ADDR_MAX_CAM_WCOUNT) + \ + (MAC_ADDR_MAX_MULTICAST_ENTRIES * MAC_ADDR_MAX_MULTICAST_WCOUNT) + \ + (MAC_ADDR_MAX_VLAN_ENTRIES * MAC_ADDR_MAX_VLAN_WCOUNT) + \ + (MAC_ADDR_MAX_MCAST_FLTR_ENTRIES * MAC_ADDR_MAX_MCAST_FLTR_WCOUNT) + \ + (MAC_ADDR_MAX_FC_MAC_ENTRIES * MAC_ADDR_MAX_FC_MAC_WCOUNT) + \ + (MAC_ADDR_MAX_MGMT_MAC_ENTRIES * MAC_ADDR_MAX_MGMT_MAC_WCOUNT) + \ + (MAC_ADDR_MAX_MGMT_VLAN_ENTRIES * MAC_ADDR_MAX_MGMT_VLAN_WCOUNT) + \ + (MAC_ADDR_MAX_MGMT_V4_ENTRIES * MAC_ADDR_MAX_MGMT_V4_WCOUNT) + \ + (MAC_ADDR_MAX_MGMT_V6_ENTRIES * MAC_ADDR_MAX_MGMT_V6_WCOUNT) + \ + (MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES * MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT)) +#define MAC_ADDR_DUMP_WORDS_PER_ENTRY 2 +#define MAC_ADDR_DUMP_TOT_WORDS (MAC_ADDR_DUMP_ENTRIES * \ + MAC_ADDR_DUMP_WORDS_PER_ENTRY) +/* Maximum of 4 functions whose semaphore registeres are + * in the coredump. + */ +#define MAX_SEMAPHORE_FUNCTIONS 4 +/* Defines for access the MPI shadow registers. */ +#define RISC_124 0x0003007c +#define RISC_127 0x0003007f +#define SHADOW_OFFSET 0xb0000000 +#define SHADOW_REG_SHIFT 20 + struct ql_nic_misc { u32 rx_ring_count; u32 tx_ring_count; @@ -1579,6 +1776,199 @@ struct ql_reg_dump { u32 ets[8+2]; }; +struct ql_mpi_coredump { + /* segment 0 */ + struct mpi_coredump_global_header mpi_global_header; + + /* segment 1 */ + struct mpi_coredump_segment_header core_regs_seg_hdr; + u32 mpi_core_regs[MPI_CORE_REGS_CNT]; + u32 mpi_core_sh_regs[MPI_CORE_SH_REGS_CNT]; + + /* segment 2 */ + struct mpi_coredump_segment_header test_logic_regs_seg_hdr; + u32 test_logic_regs[TEST_REGS_CNT]; + + /* segment 3 */ + struct mpi_coredump_segment_header rmii_regs_seg_hdr; + u32 rmii_regs[RMII_REGS_CNT]; + + /* segment 4 */ + struct mpi_coredump_segment_header fcmac1_regs_seg_hdr; + u32 fcmac1_regs[FCMAC_REGS_CNT]; + + /* segment 5 */ + struct mpi_coredump_segment_header fcmac2_regs_seg_hdr; + u32 fcmac2_regs[FCMAC_REGS_CNT]; + + /* segment 6 */ + struct mpi_coredump_segment_header fc1_mbx_regs_seg_hdr; + u32 fc1_mbx_regs[FC_MBX_REGS_CNT]; + + /* segment 7 */ + struct mpi_coredump_segment_header ide_regs_seg_hdr; + u32 ide_regs[IDE_REGS_CNT]; + + /* segment 8 */ + struct mpi_coredump_segment_header nic1_mbx_regs_seg_hdr; + u32 nic1_mbx_regs[NIC_MBX_REGS_CNT]; + + /* segment 9 */ + struct mpi_coredump_segment_header smbus_regs_seg_hdr; + u32 smbus_regs[SMBUS_REGS_CNT]; + + /* segment 10 */ + struct mpi_coredump_segment_header fc2_mbx_regs_seg_hdr; + u32 fc2_mbx_regs[FC_MBX_REGS_CNT]; + + /* segment 11 */ + struct mpi_coredump_segment_header nic2_mbx_regs_seg_hdr; + u32 nic2_mbx_regs[NIC_MBX_REGS_CNT]; + + /* segment 12 */ + struct mpi_coredump_segment_header i2c_regs_seg_hdr; + u32 i2c_regs[I2C_REGS_CNT]; + /* segment 13 */ + struct mpi_coredump_segment_header memc_regs_seg_hdr; + u32 memc_regs[MEMC_REGS_CNT]; + + /* segment 14 */ + struct mpi_coredump_segment_header pbus_regs_seg_hdr; + u32 pbus_regs[PBUS_REGS_CNT]; + + /* segment 15 */ + struct mpi_coredump_segment_header mde_regs_seg_hdr; + u32 mde_regs[MDE_REGS_CNT]; + + /* segment 16 */ + struct mpi_coredump_segment_header nic_regs_seg_hdr; + u32 nic_regs[NIC_REGS_DUMP_WORD_COUNT]; + + /* segment 17 */ + struct mpi_coredump_segment_header nic2_regs_seg_hdr; + u32 nic2_regs[NIC_REGS_DUMP_WORD_COUNT]; + + /* segment 18 */ + struct mpi_coredump_segment_header xgmac1_seg_hdr; + u32 xgmac1[XGMAC_DUMP_WORD_COUNT]; + + /* segment 19 */ + struct mpi_coredump_segment_header xgmac2_seg_hdr; + u32 xgmac2[XGMAC_DUMP_WORD_COUNT]; + + /* segment 20 */ + struct mpi_coredump_segment_header code_ram_seg_hdr; + u32 code_ram[CODE_RAM_CNT]; + + /* segment 21 */ + struct mpi_coredump_segment_header memc_ram_seg_hdr; + u32 memc_ram[MEMC_RAM_CNT]; + + /* segment 22 */ + struct mpi_coredump_segment_header xaui_an_hdr; + u32 serdes_xaui_an[XG_SERDES_XAUI_AN_COUNT]; + + /* segment 23 */ + struct mpi_coredump_segment_header xaui_hss_pcs_hdr; + u32 serdes_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT]; + + /* segment 24 */ + struct mpi_coredump_segment_header xfi_an_hdr; + u32 serdes_xfi_an[XG_SERDES_XFI_AN_COUNT]; + + /* segment 25 */ + struct mpi_coredump_segment_header xfi_train_hdr; + u32 serdes_xfi_train[XG_SERDES_XFI_TRAIN_COUNT]; + + /* segment 26 */ + struct mpi_coredump_segment_header xfi_hss_pcs_hdr; + u32 serdes_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT]; + + /* segment 27 */ + struct mpi_coredump_segment_header xfi_hss_tx_hdr; + u32 serdes_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT]; + + /* segment 28 */ + struct mpi_coredump_segment_header xfi_hss_rx_hdr; + u32 serdes_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT]; + + /* segment 29 */ + struct mpi_coredump_segment_header xfi_hss_pll_hdr; + u32 serdes_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT]; + + /* segment 30 */ + struct mpi_coredump_segment_header misc_nic_seg_hdr; + struct ql_nic_misc misc_nic_info; + + /* segment 31 */ + /* one interrupt state for each CQ */ + struct mpi_coredump_segment_header intr_states_seg_hdr; + u32 intr_states[MAX_RX_RINGS]; + + /* segment 32 */ + /* 3 cam words each for 16 unicast, + * 2 cam words for each of 32 multicast. + */ + struct mpi_coredump_segment_header cam_entries_seg_hdr; + u32 cam_entries[(16 * 3) + (32 * 3)]; + + /* segment 33 */ + struct mpi_coredump_segment_header nic_routing_words_seg_hdr; + u32 nic_routing_words[16]; + /* segment 34 */ + struct mpi_coredump_segment_header ets_seg_hdr; + u32 ets[ETS_REGS_DUMP_WORD_COUNT]; + + /* segment 35 */ + struct mpi_coredump_segment_header probe_dump_seg_hdr; + u32 probe_dump[PRB_MX_DUMP_TOT_COUNT]; + + /* segment 36 */ + struct mpi_coredump_segment_header routing_reg_seg_hdr; + u32 routing_regs[RT_IDX_DUMP_TOT_WORDS]; + + /* segment 37 */ + struct mpi_coredump_segment_header mac_prot_reg_seg_hdr; + u32 mac_prot_regs[MAC_ADDR_DUMP_TOT_WORDS]; + + /* segment 38 */ + struct mpi_coredump_segment_header xaui2_an_hdr; + u32 serdes2_xaui_an[XG_SERDES_XAUI_AN_COUNT]; + + /* segment 39 */ + struct mpi_coredump_segment_header xaui2_hss_pcs_hdr; + u32 serdes2_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT]; + + /* segment 40 */ + struct mpi_coredump_segment_header xfi2_an_hdr; + u32 serdes2_xfi_an[XG_SERDES_XFI_AN_COUNT]; + + /* segment 41 */ + struct mpi_coredump_segment_header xfi2_train_hdr; + u32 serdes2_xfi_train[XG_SERDES_XFI_TRAIN_COUNT]; + + /* segment 42 */ + struct mpi_coredump_segment_header xfi2_hss_pcs_hdr; + u32 serdes2_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT]; + + /* segment 43 */ + struct mpi_coredump_segment_header xfi2_hss_tx_hdr; + u32 serdes2_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT]; + + /* segment 44 */ + struct mpi_coredump_segment_header xfi2_hss_rx_hdr; + u32 serdes2_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT]; + + /* segment 45 */ + struct mpi_coredump_segment_header xfi2_hss_pll_hdr; + u32 serdes2_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT]; + + /* segment 50 */ + /* semaphore register for all 5 functions */ + struct mpi_coredump_segment_header sem_regs_seg_hdr; + u32 sem_regs[MAX_SEMAPHORE_FUNCTIONS]; +}; + /* * intr_context structure is used during initialization * to hook the interrupts. It is also used in a single @@ -1735,6 +2125,8 @@ struct ql_adapter { u32 port_link_up; u32 port_init; u32 link_status; + struct ql_mpi_coredump *mpi_coredump; + u32 core_is_dumped; u32 link_config; u32 led_config; u32 max_frame_size; @@ -1747,6 +2139,7 @@ struct ql_adapter { struct delayed_work mpi_work; struct delayed_work mpi_port_cfg_work; struct delayed_work mpi_idc_work; + struct delayed_work mpi_core_to_log; struct completion ide_completion; struct nic_operations *nic_ops; u16 device_id; -- GitLab From 8aae2600030f54494f9061d2cde141802d774be9 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:28 +0000 Subject: [PATCH 0780/3892] qlge: Add basic firmware dump. Adding the infrstructure and basic data for the firmware core dump. The firmware coredump is turned OFF by default. There will be no memory allocations for data dumps to the log. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 6 + drivers/net/qlge/qlge_dbg.c | 523 +++++++++++++++++++++++++++++++++++ drivers/net/qlge/qlge_main.c | 20 ++ drivers/net/qlge/qlge_mpi.c | 73 +++++ 4 files changed, 622 insertions(+) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index a265325abb15..bbdd388aa9b7 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2211,6 +2211,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, void ql_queue_fw_error(struct ql_adapter *qdev); void ql_mpi_work(struct work_struct *work); void ql_mpi_reset_work(struct work_struct *work); +void ql_mpi_core_to_log(struct work_struct *work); int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); void ql_queue_asic_error(struct ql_adapter *qdev); u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); @@ -2221,6 +2222,11 @@ void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); +int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data); +int ql_unpause_mpi_risc(struct ql_adapter *qdev); +int ql_pause_mpi_risc(struct ql_adapter *qdev); +int ql_core_dump(struct ql_adapter *qdev, + struct ql_mpi_coredump *mpi_coredump); int ql_mb_about_fw(struct ql_adapter *qdev); int ql_wol(struct ql_adapter *qdev); int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 9f58c4710761..1d026141b78d 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -91,6 +91,179 @@ err: return status; } +/* Read the MPI Processor shadow registers */ +static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf) +{ + u32 i; + int status; + + for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) { + status = ql_write_mpi_reg(qdev, RISC_124, + (SHADOW_OFFSET | i << SHADOW_REG_SHIFT)); + if (status) + goto end; + status = ql_read_mpi_reg(qdev, RISC_127, buf); + if (status) + goto end; + } +end: + return status; +} + +/* Read the MPI Processor core registers */ +static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf, + u32 offset, u32 count) +{ + int i, status = 0; + for (i = 0; i < count; i++, buf++) { + status = ql_read_mpi_reg(qdev, offset + i, buf); + if (status) + return status; + } + return status; +} + + +/* Read out the routing index registers */ +static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf) +{ + int status; + u32 type, index, index_max; + u32 result_index; + u32 result_data; + u32 val; + + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + return status; + + for (type = 0; type < 4; type++) { + if (type < 2) + index_max = 8; + else + index_max = 16; + for (index = 0; index < index_max; index++) { + val = RT_IDX_RS + | (type << RT_IDX_TYPE_SHIFT) + | (index << RT_IDX_IDX_SHIFT); + ql_write32(qdev, RT_IDX, val); + result_index = 0; + while ((result_index & RT_IDX_MR) == 0) + result_index = ql_read32(qdev, RT_IDX); + result_data = ql_read32(qdev, RT_DATA); + *buf = type; + buf++; + *buf = index; + buf++; + *buf = result_index; + buf++; + *buf = result_data; + buf++; + } + } + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); + return status; +} + +/* Read out the MAC protocol registers */ +static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf) +{ + u32 result_index, result_data; + u32 type; + u32 index; + u32 offset; + u32 val; + u32 initial_val = MAC_ADDR_RS; + u32 max_index; + u32 max_offset; + + for (type = 0; type < MAC_ADDR_TYPE_COUNT; type++) { + switch (type) { + + case 0: /* CAM */ + initial_val |= MAC_ADDR_ADR; + max_index = MAC_ADDR_MAX_CAM_ENTRIES; + max_offset = MAC_ADDR_MAX_CAM_WCOUNT; + break; + case 1: /* Multicast MAC Address */ + max_index = MAC_ADDR_MAX_CAM_WCOUNT; + max_offset = MAC_ADDR_MAX_CAM_WCOUNT; + break; + case 2: /* VLAN filter mask */ + case 3: /* MC filter mask */ + max_index = MAC_ADDR_MAX_CAM_WCOUNT; + max_offset = MAC_ADDR_MAX_CAM_WCOUNT; + break; + case 4: /* FC MAC addresses */ + max_index = MAC_ADDR_MAX_FC_MAC_ENTRIES; + max_offset = MAC_ADDR_MAX_FC_MAC_WCOUNT; + break; + case 5: /* Mgmt MAC addresses */ + max_index = MAC_ADDR_MAX_MGMT_MAC_ENTRIES; + max_offset = MAC_ADDR_MAX_MGMT_MAC_WCOUNT; + break; + case 6: /* Mgmt VLAN addresses */ + max_index = MAC_ADDR_MAX_MGMT_VLAN_ENTRIES; + max_offset = MAC_ADDR_MAX_MGMT_VLAN_WCOUNT; + break; + case 7: /* Mgmt IPv4 address */ + max_index = MAC_ADDR_MAX_MGMT_V4_ENTRIES; + max_offset = MAC_ADDR_MAX_MGMT_V4_WCOUNT; + break; + case 8: /* Mgmt IPv6 address */ + max_index = MAC_ADDR_MAX_MGMT_V6_ENTRIES; + max_offset = MAC_ADDR_MAX_MGMT_V6_WCOUNT; + break; + case 9: /* Mgmt TCP/UDP Dest port */ + max_index = MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES; + max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT; + break; + default: + printk(KERN_ERR"Bad type!!! 0x%08x\n", type); + max_index = 0; + max_offset = 0; + break; + } + for (index = 0; index < max_index; index++) { + for (offset = 0; offset < max_offset; offset++) { + val = initial_val + | (type << MAC_ADDR_TYPE_SHIFT) + | (index << MAC_ADDR_IDX_SHIFT) + | (offset); + ql_write32(qdev, MAC_ADDR_IDX, val); + result_index = 0; + while ((result_index & MAC_ADDR_MR) == 0) { + result_index = ql_read32(qdev, + MAC_ADDR_IDX); + } + result_data = ql_read32(qdev, MAC_ADDR_DATA); + *buf = result_index; + buf++; + *buf = result_data; + buf++; + } + } + } +} + +static void ql_get_sem_registers(struct ql_adapter *qdev, u32 *buf) +{ + u32 func_num, reg, reg_val; + int status; + + for (func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num++) { + reg = MPI_NIC_REG_BLOCK + | (func_num << MPI_NIC_FUNCTION_SHIFT) + | (SEM / 4); + status = ql_read_mpi_reg(qdev, reg, ®_val); + *buf = reg_val; + /* if the read failed then dead fill the element. */ + if (!status) + *buf = 0xdeadbeef; + buf++; + } +} + /* Create a coredump segment header */ static void ql_build_coredump_seg_header( struct mpi_coredump_segment_header *seg_hdr, @@ -103,6 +276,329 @@ static void ql_build_coredump_seg_header( memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1); } +/* + * This function should be called when a coredump / probedump + * is to be extracted from the HBA. It is assumed there is a + * qdev structure that contains the base address of the register + * space for this function as well as a coredump structure that + * will contain the dump. + */ +int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) +{ + int status; + int i; + + if (!mpi_coredump) { + QPRINTK(qdev, DRV, ERR, + "No memory available.\n"); + return -ENOMEM; + } + + /* Try to get the spinlock, but dont worry if + * it isn't available. If the firmware died it + * might be holding the sem. + */ + ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); + + status = ql_pause_mpi_risc(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed RISC pause. Status = 0x%.08x\n", status); + goto err; + } + + /* Insert the global header */ + memset(&(mpi_coredump->mpi_global_header), 0, + sizeof(struct mpi_coredump_global_header)); + mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE; + mpi_coredump->mpi_global_header.headerSize = + sizeof(struct mpi_coredump_global_header); + mpi_coredump->mpi_global_header.imageSize = + sizeof(struct ql_mpi_coredump); + memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + sizeof(mpi_coredump->mpi_global_header.idString)); + + /* Get generic NIC reg dump */ + ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr, + NIC1_CONTROL_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->nic_regs), "NIC1 Registers"); + + if (qdev->func & 1) { + /* Odd means our function is NIC 2 */ + for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) + mpi_coredump->nic2_regs[i] = + ql_read32(qdev, i * sizeof(u32)); + } else { + /* Even means our function is NIC 1 */ + for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) + mpi_coredump->nic_regs[i] = + ql_read32(qdev, i * sizeof(u32)); + } + + ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr, + CORE_SEG_NUM, + sizeof(mpi_coredump->core_regs_seg_hdr) + + sizeof(mpi_coredump->mpi_core_regs) + + sizeof(mpi_coredump->mpi_core_sh_regs), + "Core Registers"); + + /* Get the MPI Core Registers */ + status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0], + MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT); + if (status) + goto err; + /* Get the 16 MPI shadow registers */ + status = ql_get_mpi_shadow_regs(qdev, + &mpi_coredump->mpi_core_sh_regs[0]); + if (status) + goto err; + + /* Get the Test Logic Registers */ + ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr, + TEST_LOGIC_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->test_logic_regs), + "Test Logic Regs"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->test_logic_regs[0], + TEST_REGS_ADDR, TEST_REGS_CNT); + if (status) + goto err; + + /* Get the RMII Registers */ + ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr, + RMII_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->rmii_regs), + "RMII Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->rmii_regs[0], + RMII_REGS_ADDR, RMII_REGS_CNT); + if (status) + goto err; + + /* Get the FCMAC1 Registers */ + ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr, + FCMAC1_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->fcmac1_regs), + "FCMAC1 Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac1_regs[0], + FCMAC1_REGS_ADDR, FCMAC_REGS_CNT); + if (status) + goto err; + + /* Get the FCMAC2 Registers */ + + ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr, + FCMAC2_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->fcmac2_regs), + "FCMAC2 Registers"); + + status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac2_regs[0], + FCMAC2_REGS_ADDR, FCMAC_REGS_CNT); + if (status) + goto err; + + /* Get the FC1 MBX Registers */ + ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr, + FC1_MBOX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->fc1_mbx_regs), + "FC1 MBox Regs"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->fc1_mbx_regs[0], + FC1_MBX_REGS_ADDR, FC_MBX_REGS_CNT); + if (status) + goto err; + + /* Get the IDE Registers */ + ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr, + IDE_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->ide_regs), + "IDE Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->ide_regs[0], + IDE_REGS_ADDR, IDE_REGS_CNT); + if (status) + goto err; + + /* Get the NIC1 MBX Registers */ + ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr, + NIC1_MBOX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->nic1_mbx_regs), + "NIC1 MBox Regs"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->nic1_mbx_regs[0], + NIC1_MBX_REGS_ADDR, NIC_MBX_REGS_CNT); + if (status) + goto err; + + /* Get the SMBus Registers */ + ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr, + SMBUS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->smbus_regs), + "SMBus Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->smbus_regs[0], + SMBUS_REGS_ADDR, SMBUS_REGS_CNT); + if (status) + goto err; + + /* Get the FC2 MBX Registers */ + ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr, + FC2_MBOX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->fc2_mbx_regs), + "FC2 MBox Regs"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->fc2_mbx_regs[0], + FC2_MBX_REGS_ADDR, FC_MBX_REGS_CNT); + if (status) + goto err; + + /* Get the NIC2 MBX Registers */ + ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr, + NIC2_MBOX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->nic2_mbx_regs), + "NIC2 MBox Regs"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->nic2_mbx_regs[0], + NIC2_MBX_REGS_ADDR, NIC_MBX_REGS_CNT); + if (status) + goto err; + + /* Get the I2C Registers */ + ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr, + I2C_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->i2c_regs), + "I2C Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->i2c_regs[0], + I2C_REGS_ADDR, I2C_REGS_CNT); + if (status) + goto err; + + /* Get the MEMC Registers */ + ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr, + MEMC_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->memc_regs), + "MEMC Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->memc_regs[0], + MEMC_REGS_ADDR, MEMC_REGS_CNT); + if (status) + goto err; + + /* Get the PBus Registers */ + ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr, + PBUS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->pbus_regs), + "PBUS Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->pbus_regs[0], + PBUS_REGS_ADDR, PBUS_REGS_CNT); + if (status) + goto err; + + /* Get the MDE Registers */ + ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr, + MDE_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->mde_regs), + "MDE Registers"); + status = ql_get_mpi_regs(qdev, &mpi_coredump->mde_regs[0], + MDE_REGS_ADDR, MDE_REGS_CNT); + if (status) + goto err; + + ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr, + MISC_NIC_INFO_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->misc_nic_info), + "MISC NIC INFO"); + mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count; + mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count; + mpi_coredump->misc_nic_info.intr_count = qdev->intr_count; + mpi_coredump->misc_nic_info.function = qdev->func; + + /* Segment 31 */ + /* Get indexed register values. */ + ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr, + INTR_STATES_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->intr_states), + "INTR States"); + ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]); + + ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr, + CAM_ENTRIES_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->cam_entries), + "CAM Entries"); + status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]); + if (status) + goto err; + + ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr, + ROUTING_WORDS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->nic_routing_words), + "Routing Words"); + status = ql_get_routing_entries(qdev, + &mpi_coredump->nic_routing_words[0]); + if (status) + goto err; + + /* Segment 34 (Rev C. step 23) */ + ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr, + ETS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->ets), + "ETS Registers"); + status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]); + if (status) + goto err; + + ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr, + ROUTING_INDEX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->routing_regs), + "Routing Regs"); + status = ql_get_routing_index_registers(qdev, + &mpi_coredump->routing_regs[0]); + if (status) + goto err; + + ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr, + MAC_PROTOCOL_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->mac_prot_regs), + "MAC Prot Regs"); + ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]); + + /* Get the semaphore registers for all 5 functions */ + ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr, + SEM_REGS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->sem_regs), "Sem Registers"); + + ql_get_sem_registers(qdev, &mpi_coredump->sem_regs[0]); + + /* Prevent the mpi restarting while we dump the memory.*/ + ql_write_mpi_reg(qdev, MPI_TEST_FUNC_RST_STS, MPI_TEST_FUNC_RST_FRC); + + /* clear the pause */ + status = ql_unpause_mpi_risc(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed RISC unpause. Status = 0x%.08x\n", status); + goto err; + } +err: + ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */ + return status; + +} + void ql_gen_reg_dump(struct ql_adapter *qdev, struct ql_reg_dump *mpi_coredump) { @@ -180,6 +676,33 @@ void ql_gen_reg_dump(struct ql_adapter *qdev, return; } +/* Coredump to messages log file using separate worker thread */ +void ql_mpi_core_to_log(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, mpi_core_to_log.work); + u32 *tmp, count; + int i; + + count = sizeof(struct ql_mpi_coredump) / sizeof(u32); + tmp = (u32 *)qdev->mpi_coredump; + QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n"); + + for (i = 0; i < count; i += 8) { + printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x " + "%.08x %.08x %.08x \n", i, + tmp[i + 0], + tmp[i + 1], + tmp[i + 2], + tmp[i + 3], + tmp[i + 4], + tmp[i + 5], + tmp[i + 6], + tmp[i + 7]); + msleep(5); + } +} + #ifdef QL_REG_DUMP static void ql_dump_intr_states(struct ql_adapter *qdev) { diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 167a3dab2f18..e58892304e19 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -73,6 +73,13 @@ static int qlge_irq_type = MSIX_IRQ; module_param(qlge_irq_type, int, MSIX_IRQ); MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); +static int qlge_mpi_coredump; +module_param(qlge_mpi_coredump, int, 0); +MODULE_PARM_DESC(qlge_mpi_coredump, + "Option to enable MPI firmware dump. " + "Default is OFF - Do Not allocate memory. " + "Do not perform firmware coredump."); + static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, @@ -3842,6 +3849,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_idc_work); + cancel_delayed_work_sync(&qdev->mpi_core_to_log); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); for (i = 0; i < qdev->rss_ring_count; i++) @@ -4398,6 +4406,7 @@ static void ql_release_all(struct pci_dev *pdev) iounmap(qdev->reg_base); if (qdev->doorbell_area) iounmap(qdev->doorbell_area); + vfree(qdev->mpi_coredump); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } @@ -4479,6 +4488,15 @@ static int __devinit ql_init_device(struct pci_dev *pdev, spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); + if (qlge_mpi_coredump) { + qdev->mpi_coredump = + vmalloc(sizeof(struct ql_mpi_coredump)); + if (qdev->mpi_coredump == NULL) { + dev_err(&pdev->dev, "Coredump alloc failed.\n"); + err = -ENOMEM; + goto err_out; + } + } /* make sure the EEPROM is good */ err = qdev->nic_ops->get_flash(qdev); if (err) { @@ -4508,6 +4526,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); + INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log); init_completion(&qdev->ide_completion); if (!cards_found) { @@ -4630,6 +4649,7 @@ static void ql_eeh_close(struct net_device *ndev) cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_idc_work); + cancel_delayed_work_sync(&qdev->mpi_core_to_log); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); for (i = 0; i < qdev->rss_ring_count; i++) diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index e2b2286102d4..242b1ea955e4 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -1,5 +1,35 @@ #include "qlge.h" +int ql_unpause_mpi_risc(struct ql_adapter *qdev) +{ + u32 tmp; + + /* Un-pause the RISC */ + tmp = ql_read32(qdev, CSR); + if (!(tmp & CSR_RP)) + return -EIO; + + ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE); + return 0; +} + +int ql_pause_mpi_risc(struct ql_adapter *qdev) +{ + u32 tmp; + int count = UDELAY_COUNT; + + /* Pause the RISC */ + ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE); + do { + tmp = ql_read32(qdev, CSR); + if (tmp & CSR_RP) + break; + mdelay(UDELAY_DELAY); + count--; + } while (count); + return (count == 0) ? -ETIMEDOUT : 0; +} + int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) { int status; @@ -45,6 +75,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) return status; } +/* Determine if we are in charge of the firwmare. If + * we are the lower of the 2 NIC pcie functions, or if + * we are the higher function and the lower function + * is not enabled. + */ +int ql_own_firmware(struct ql_adapter *qdev) +{ + u32 temp; + + /* If we are the lower of the 2 NIC functions + * on the chip the we are responsible for + * core dump and firmware reset after an error. + */ + if (qdev->func < qdev->alt_func) + return 1; + + /* If we are the higher of the 2 NIC functions + * on the chip and the lower function is not + * enabled, then we are responsible for + * core dump and firmware reset after an error. + */ + temp = ql_read32(qdev, STS); + if (!(temp & (1 << (8 + qdev->alt_func)))) + return 1; + + return 0; + +} + static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) { int i, status; @@ -1143,5 +1202,19 @@ void ql_mpi_reset_work(struct work_struct *work) cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); cancel_delayed_work_sync(&qdev->mpi_idc_work); + /* If we're not the dominant NIC function, + * then there is nothing to do. + */ + if (!ql_own_firmware(qdev)) { + QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n"); + return; + } + + if (!ql_core_dump(qdev, qdev->mpi_coredump)) { + QPRINTK(qdev, DRV, ERR, "Core is dumped!\n"); + qdev->core_is_dumped = 1; + queue_delayed_work(qdev->workqueue, + &qdev->mpi_core_to_log, 5 * HZ); + } ql_soft_reset_mpi_risc(qdev); } -- GitLab From c89ec8b9de887cda0879d27036fce8d2a2fd6400 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:29 +0000 Subject: [PATCH 0781/3892] qlge: Add probe regs to firmware dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_dbg.c | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 1d026141b78d..913ca1e10e3e 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -123,6 +123,53 @@ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf, return status; } +/* Read the ASIC probe dump */ +static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock, + u32 valid, u32 *buf) +{ + u32 module, mux_sel, probe, lo_val, hi_val; + + for (module = 0; module < PRB_MX_ADDR_MAX_MODS; module++) { + if (!((valid >> module) & 1)) + continue; + for (mux_sel = 0; mux_sel < PRB_MX_ADDR_MAX_MUX; mux_sel++) { + probe = clock + | PRB_MX_ADDR_ARE + | mux_sel + | (module << PRB_MX_ADDR_MOD_SEL_SHIFT); + ql_write32(qdev, PRB_MX_ADDR, probe); + lo_val = ql_read32(qdev, PRB_MX_DATA); + if (mux_sel == 0) { + *buf = probe; + buf++; + } + probe |= PRB_MX_ADDR_UP; + ql_write32(qdev, PRB_MX_ADDR, probe); + hi_val = ql_read32(qdev, PRB_MX_DATA); + *buf = lo_val; + buf++; + *buf = hi_val; + buf++; + } + } + return buf; +} + +static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf) +{ + /* First we have to enable the probe mux */ + ql_write_mpi_reg(qdev, MPI_TEST_FUNC_PRB_CTL, MPI_TEST_FUNC_PRB_EN); + buf = ql_get_probe(qdev, PRB_MX_ADDR_SYS_CLOCK, + PRB_MX_ADDR_VALID_SYS_MOD, buf); + buf = ql_get_probe(qdev, PRB_MX_ADDR_PCI_CLOCK, + PRB_MX_ADDR_VALID_PCI_MOD, buf); + buf = ql_get_probe(qdev, PRB_MX_ADDR_XGM_CLOCK, + PRB_MX_ADDR_VALID_XGM_MOD, buf); + buf = ql_get_probe(qdev, PRB_MX_ADDR_FC_CLOCK, + PRB_MX_ADDR_VALID_FC_MOD, buf); + return 0; + +} /* Read out the routing index registers */ static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf) @@ -558,6 +605,13 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) if (status) goto err; + ql_build_coredump_seg_header(&mpi_coredump->probe_dump_seg_hdr, + PROBE_DUMP_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->probe_dump), + "Probe Dump"); + ql_get_probe_dump(qdev, &mpi_coredump->probe_dump[0]); + ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr, ROUTING_INDEX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) -- GitLab From 2c1f73c3ddfd526750b003bc49a255641ac1f0ca Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:30 +0000 Subject: [PATCH 0782/3892] qlge: Add RAM dump to firmware dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 3 ++ drivers/net/qlge/qlge_dbg.c | 35 +++++++++++++++++ drivers/net/qlge/qlge_mpi.c | 76 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index bbdd388aa9b7..05feb03e9da6 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2225,6 +2225,9 @@ int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data); int ql_unpause_mpi_risc(struct ql_adapter *qdev); int ql_pause_mpi_risc(struct ql_adapter *qdev); +int ql_hard_reset_mpi_risc(struct ql_adapter *qdev); +int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, + u32 ram_addr, int word_count); int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump); int ql_mb_about_fw(struct ql_adapter *qdev); diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 913ca1e10e3e..833cfd7a22c1 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -647,6 +647,41 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) "Failed RISC unpause. Status = 0x%.08x\n", status); goto err; } + + /* Reset the RISC so we can dump RAM */ + status = ql_hard_reset_mpi_risc(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed RISC reset. Status = 0x%.08x\n", status); + goto err; + } + + ql_build_coredump_seg_header(&mpi_coredump->code_ram_seg_hdr, + WCS_RAM_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->code_ram), + "WCS RAM"); + status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0], + CODE_RAM_ADDR, CODE_RAM_CNT); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed Dump of CODE RAM. Status = 0x%.08x\n", status); + goto err; + } + + /* Insert the segment header */ + ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr, + MEMC_RAM_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->memc_ram), + "MEMC RAM"); + status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0], + MEMC_RAM_ADDR, MEMC_RAM_CNT); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed Dump of MEMC RAM. Status = 0x%.08x\n", status); + goto err; + } err: ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */ return status; diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 242b1ea955e4..3304eb7df581 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -30,6 +30,25 @@ int ql_pause_mpi_risc(struct ql_adapter *qdev) return (count == 0) ? -ETIMEDOUT : 0; } +int ql_hard_reset_mpi_risc(struct ql_adapter *qdev) +{ + u32 tmp; + int count = UDELAY_COUNT; + + /* Reset the RISC */ + ql_write32(qdev, CSR, CSR_CMD_SET_RST); + do { + tmp = ql_read32(qdev, CSR); + if (tmp & CSR_RR) { + ql_write32(qdev, CSR, CSR_CMD_CLR_RST); + break; + } + mdelay(UDELAY_DELAY); + count--; + } while (count); + return (count == 0) ? -ETIMEDOUT : 0; +} + int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) { int status; @@ -728,6 +747,63 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev) return status; } +int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr, + u32 size) +{ + int status = 0; + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 9; + mbcp->out_count = 1; + + mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM; + mbcp->mbox_in[1] = LSW(addr); + mbcp->mbox_in[2] = MSW(req_dma); + mbcp->mbox_in[3] = LSW(req_dma); + mbcp->mbox_in[4] = MSW(size); + mbcp->mbox_in[5] = LSW(size); + mbcp->mbox_in[6] = MSW(MSD(req_dma)); + mbcp->mbox_in[7] = LSW(MSD(req_dma)); + mbcp->mbox_in[8] = MSW(addr); + + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed to dump risc RAM.\n"); + status = -EIO; + } + return status; +} + +/* Issue a mailbox command to dump RISC RAM. */ +int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, + u32 ram_addr, int word_count) +{ + int status; + char *my_buf; + dma_addr_t buf_dma; + + my_buf = pci_alloc_consistent(qdev->pdev, word_count * sizeof(u32), + &buf_dma); + if (!my_buf) + return -EIO; + + status = ql_mb_dump_ram(qdev, buf_dma, ram_addr, word_count); + if (!status) + memcpy(buf, my_buf, word_count * sizeof(u32)); + + pci_free_consistent(qdev->pdev, word_count * sizeof(u32), my_buf, + buf_dma); + return status; +} + /* Get link settings and maximum frame size settings * for the current port. * Most likely will block. -- GitLab From 24bb55b480f16f4cd8d64c2d46e28f0c82df0409 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:31 +0000 Subject: [PATCH 0783/3892] qlge: Add alternate function's reg dump to fw dump. Get the 2nd (other) nic function register values. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_dbg.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 833cfd7a22c1..181281390129 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -1,5 +1,23 @@ #include "qlge.h" +/* Read a NIC register from the alternate function. */ +static u32 ql_read_other_func_reg(struct ql_adapter *qdev, + u32 reg) +{ + u32 register_to_read; + u32 reg_val; + unsigned int status = 0; + + register_to_read = MPI_NIC_REG_BLOCK + | MPI_NIC_READ + | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT) + | reg; + status = ql_read_mpi_reg(qdev, register_to_read, ®_val); + if (status != 0) + return 0xffffffff; + + return reg_val; +} static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf) { @@ -371,16 +389,28 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic_regs), "NIC1 Registers"); + ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr, + NIC2_CONTROL_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->nic2_regs), "NIC2 Registers"); + if (qdev->func & 1) { /* Odd means our function is NIC 2 */ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) mpi_coredump->nic2_regs[i] = ql_read32(qdev, i * sizeof(u32)); + + for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) + mpi_coredump->nic_regs[i] = + ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4); } else { /* Even means our function is NIC 1 */ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) mpi_coredump->nic_regs[i] = ql_read32(qdev, i * sizeof(u32)); + for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) + mpi_coredump->nic2_regs[i] = + ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4); } ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr, -- GitLab From a48c86fdb1253f36167bab1fc30a51211d49a901 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:32 +0000 Subject: [PATCH 0784/3892] qlge: Add serdes reg blocks dump to firmware dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_dbg.c | 417 ++++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 181281390129..87e50d9c3350 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -19,6 +19,318 @@ static u32 ql_read_other_func_reg(struct ql_adapter *qdev, return reg_val; } +/* Write a NIC register from the alternate function. */ +static int ql_write_other_func_reg(struct ql_adapter *qdev, + u32 reg, u32 reg_val) +{ + u32 register_to_read; + int status = 0; + + register_to_read = MPI_NIC_REG_BLOCK + | MPI_NIC_READ + | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT) + | reg; + status = ql_write_mpi_reg(qdev, register_to_read, reg_val); + + return status; +} + +static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg, + u32 bit, u32 err_bit) +{ + u32 temp; + int count = 10; + + while (count) { + temp = ql_read_other_func_reg(qdev, reg); + + /* check for errors */ + if (temp & err_bit) + return -1; + else if (temp & bit) + return 0; + mdelay(10); + count--; + } + return -1; +} + +static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg, + u32 *data) +{ + int status; + + /* wait for reg to come ready */ + status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4, + XG_SERDES_ADDR_RDY, 0); + if (status) + goto exit; + + /* set up for reg read */ + ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R); + + /* wait for reg to come ready */ + status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4, + XG_SERDES_ADDR_RDY, 0); + if (status) + goto exit; + + /* get the data */ + *data = ql_read_other_func_reg(qdev, (XG_SERDES_DATA / 4)); +exit: + return status; +} + +/* Read out the SERDES registers */ +static int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data) +{ + int status; + + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0); + if (status) + goto exit; + + /* set up for reg read */ + ql_write32(qdev, XG_SERDES_ADDR, reg | PROC_ADDR_R); + + /* wait for reg to come ready */ + status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0); + if (status) + goto exit; + + /* get the data */ + *data = ql_read32(qdev, XG_SERDES_DATA); +exit: + return status; +} + +static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr, + u32 *direct_ptr, u32 *indirect_ptr, + unsigned int direct_valid, unsigned int indirect_valid) +{ + unsigned int status; + + status = 1; + if (direct_valid) + status = ql_read_serdes_reg(qdev, addr, direct_ptr); + /* Dead fill any failures or invalids. */ + if (status) + *direct_ptr = 0xDEADBEEF; + + status = 1; + if (indirect_valid) + status = ql_read_other_func_serdes_reg( + qdev, addr, indirect_ptr); + /* Dead fill any failures or invalids. */ + if (status) + *indirect_ptr = 0xDEADBEEF; +} + +static int ql_get_serdes_regs(struct ql_adapter *qdev, + struct ql_mpi_coredump *mpi_coredump) +{ + int status; + unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid; + unsigned int xaui_indirect_valid, i; + u32 *direct_ptr, temp; + u32 *indirect_ptr; + + xfi_direct_valid = xfi_indirect_valid = 0; + xaui_direct_valid = xaui_indirect_valid = 1; + + /* The XAUI needs to be read out per port */ + if (qdev->func & 1) { + /* We are NIC 2 */ + status = ql_read_other_func_serdes_reg(qdev, + XG_SERDES_XAUI_HSS_PCS_START, &temp); + if (status) + temp = XG_SERDES_ADDR_XAUI_PWR_DOWN; + if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == + XG_SERDES_ADDR_XAUI_PWR_DOWN) + xaui_indirect_valid = 0; + + status = ql_read_serdes_reg(qdev, + XG_SERDES_XAUI_HSS_PCS_START, &temp); + if (status) + temp = XG_SERDES_ADDR_XAUI_PWR_DOWN; + + if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == + XG_SERDES_ADDR_XAUI_PWR_DOWN) + xaui_direct_valid = 0; + } else { + /* We are NIC 1 */ + status = ql_read_other_func_serdes_reg(qdev, + XG_SERDES_XAUI_HSS_PCS_START, &temp); + if (status) + temp = XG_SERDES_ADDR_XAUI_PWR_DOWN; + if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == + XG_SERDES_ADDR_XAUI_PWR_DOWN) + xaui_indirect_valid = 0; + + status = ql_read_serdes_reg(qdev, + XG_SERDES_XAUI_HSS_PCS_START, &temp); + if (status) + temp = XG_SERDES_ADDR_XAUI_PWR_DOWN; + if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == + XG_SERDES_ADDR_XAUI_PWR_DOWN) + xaui_direct_valid = 0; + } + + /* + * XFI register is shared so only need to read one + * functions and then check the bits. + */ + status = ql_read_serdes_reg(qdev, XG_SERDES_ADDR_STS, &temp); + if (status) + temp = 0; + + if ((temp & XG_SERDES_ADDR_XFI1_PWR_UP) == + XG_SERDES_ADDR_XFI1_PWR_UP) { + /* now see if i'm NIC 1 or NIC 2 */ + if (qdev->func & 1) + /* I'm NIC 2, so the indirect (NIC1) xfi is up. */ + xfi_indirect_valid = 1; + else + xfi_direct_valid = 1; + } + if ((temp & XG_SERDES_ADDR_XFI2_PWR_UP) == + XG_SERDES_ADDR_XFI2_PWR_UP) { + /* now see if i'm NIC 1 or NIC 2 */ + if (qdev->func & 1) + /* I'm NIC 2, so the indirect (NIC1) xfi is up. */ + xfi_direct_valid = 1; + else + xfi_indirect_valid = 1; + } + + /* Get XAUI_AN register block. */ + if (qdev->func & 1) { + /* Function 2 is direct */ + direct_ptr = mpi_coredump->serdes2_xaui_an; + indirect_ptr = mpi_coredump->serdes_xaui_an; + } else { + /* Function 1 is direct */ + direct_ptr = mpi_coredump->serdes_xaui_an; + indirect_ptr = mpi_coredump->serdes2_xaui_an; + } + + for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xaui_direct_valid, xaui_indirect_valid); + + /* Get XAUI_HSS_PCS register block. */ + if (qdev->func & 1) { + direct_ptr = + mpi_coredump->serdes2_xaui_hss_pcs; + indirect_ptr = + mpi_coredump->serdes_xaui_hss_pcs; + } else { + direct_ptr = + mpi_coredump->serdes_xaui_hss_pcs; + indirect_ptr = + mpi_coredump->serdes2_xaui_hss_pcs; + } + + for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xaui_direct_valid, xaui_indirect_valid); + + /* Get XAUI_XFI_AN register block. */ + if (qdev->func & 1) { + direct_ptr = mpi_coredump->serdes2_xfi_an; + indirect_ptr = mpi_coredump->serdes_xfi_an; + } else { + direct_ptr = mpi_coredump->serdes_xfi_an; + indirect_ptr = mpi_coredump->serdes2_xfi_an; + } + + for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + + /* Get XAUI_XFI_TRAIN register block. */ + if (qdev->func & 1) { + direct_ptr = mpi_coredump->serdes2_xfi_train; + indirect_ptr = + mpi_coredump->serdes_xfi_train; + } else { + direct_ptr = mpi_coredump->serdes_xfi_train; + indirect_ptr = + mpi_coredump->serdes2_xfi_train; + } + + for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + + /* Get XAUI_XFI_HSS_PCS register block. */ + if (qdev->func & 1) { + direct_ptr = + mpi_coredump->serdes2_xfi_hss_pcs; + indirect_ptr = + mpi_coredump->serdes_xfi_hss_pcs; + } else { + direct_ptr = + mpi_coredump->serdes_xfi_hss_pcs; + indirect_ptr = + mpi_coredump->serdes2_xfi_hss_pcs; + } + + for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + + /* Get XAUI_XFI_HSS_TX register block. */ + if (qdev->func & 1) { + direct_ptr = + mpi_coredump->serdes2_xfi_hss_tx; + indirect_ptr = + mpi_coredump->serdes_xfi_hss_tx; + } else { + direct_ptr = mpi_coredump->serdes_xfi_hss_tx; + indirect_ptr = + mpi_coredump->serdes2_xfi_hss_tx; + } + for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + + /* Get XAUI_XFI_HSS_RX register block. */ + if (qdev->func & 1) { + direct_ptr = + mpi_coredump->serdes2_xfi_hss_rx; + indirect_ptr = + mpi_coredump->serdes_xfi_hss_rx; + } else { + direct_ptr = mpi_coredump->serdes_xfi_hss_rx; + indirect_ptr = + mpi_coredump->serdes2_xfi_hss_rx; + } + + for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + + + /* Get XAUI_XFI_HSS_PLL register block. */ + if (qdev->func & 1) { + direct_ptr = + mpi_coredump->serdes2_xfi_hss_pll; + indirect_ptr = + mpi_coredump->serdes_xfi_hss_pll; + } else { + direct_ptr = + mpi_coredump->serdes_xfi_hss_pll; + indirect_ptr = + mpi_coredump->serdes2_xfi_hss_pll; + } + for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++) + ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, + xfi_direct_valid, xfi_indirect_valid); + return 0; +} + static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf) { int status = 0; @@ -413,6 +725,111 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4); } + /* Rev C. Step 20a */ + ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr, + XAUI_AN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xaui_an), + "XAUI AN Registers"); + + /* Rev C. Step 20b */ + ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr, + XAUI_HSS_PCS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xaui_hss_pcs), + "XAUI HSS PCS Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_an), + "XFI AN Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr, + XFI_TRAIN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_train), + "XFI TRAIN Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr, + XFI_HSS_PCS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_hss_pcs), + "XFI HSS PCS Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr, + XFI_HSS_TX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_hss_tx), + "XFI HSS TX Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr, + XFI_HSS_RX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_hss_rx), + "XFI HSS RX Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr, + XFI_HSS_PLL_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes_xfi_hss_pll), + "XFI HSS PLL Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr, + XAUI2_AN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xaui_an), + "XAUI2 AN Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr, + XAUI2_HSS_PCS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xaui_hss_pcs), + "XAUI2 HSS PCS Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr, + XFI2_AN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_an), + "XFI2 AN Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr, + XFI2_TRAIN_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_train), + "XFI2 TRAIN Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr, + XFI2_HSS_PCS_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_hss_pcs), + "XFI2 HSS PCS Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr, + XFI2_HSS_TX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_hss_tx), + "XFI2 HSS TX Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr, + XFI2_HSS_RX_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_hss_rx), + "XFI2 HSS RX Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr, + XFI2_HSS_PLL_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->serdes2_xfi_hss_pll), + "XFI2 HSS PLL Registers"); + + status = ql_get_serdes_regs(qdev, mpi_coredump); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Failed Dump of Serdes Registers. Status = 0x%.08x\n", + status); + goto err; + } + ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr, CORE_SEG_NUM, sizeof(mpi_coredump->core_regs_seg_hdr) + -- GitLab From a2f982328427157eaa819c02986a65b9b168733a Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:33 +0000 Subject: [PATCH 0785/3892] qlge: Add xgmac reg blocks to firwmare dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_dbg.c | 87 +++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 87e50d9c3350..ec4349a254cc 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -331,6 +331,76 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, return 0; } +static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg, + u32 *data) +{ + int status = 0; + + /* wait for reg to come ready */ + status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4, + XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + if (status) + goto exit; + + /* set up for reg read */ + ql_write_other_func_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R); + + /* wait for reg to come ready */ + status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4, + XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + if (status) + goto exit; + + /* get the data */ + *data = ql_read_other_func_reg(qdev, XGMAC_DATA / 4); +exit: + return status; +} + +/* Read the 400 xgmac control/statistics registers + * skipping unused locations. + */ +static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf, + unsigned int other_function) +{ + int status = 0; + int i; + + for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) { + /* We're reading 400 xgmac registers, but we filter out + * serveral locations that are non-responsive to reads. + */ + if ((i == 0x00000114) || + (i == 0x00000118) || + (i == 0x0000013c) || + (i == 0x00000140) || + (i > 0x00000150 && i < 0x000001fc) || + (i > 0x00000278 && i < 0x000002a0) || + (i > 0x000002c0 && i < 0x000002cf) || + (i > 0x000002dc && i < 0x000002f0) || + (i > 0x000003c8 && i < 0x00000400) || + (i > 0x00000400 && i < 0x00000410) || + (i > 0x00000410 && i < 0x00000420) || + (i > 0x00000420 && i < 0x00000430) || + (i > 0x00000430 && i < 0x00000440) || + (i > 0x00000440 && i < 0x00000450) || + (i > 0x00000450 && i < 0x00000500) || + (i > 0x0000054c && i < 0x00000568) || + (i > 0x000005c8 && i < 0x00000600)) { + if (other_function) + status = + ql_read_other_func_xgmac_reg(qdev, i, buf); + else + status = ql_read_xgmac_reg(qdev, i, buf); + + if (status) + *buf = 0xdeadbeef; + break; + } + } + return status; +} + static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf) { int status = 0; @@ -706,6 +776,17 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic2_regs), "NIC2 Registers"); + /* Get XGMac registers. (Segment 18, Rev C. step 21) */ + ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr, + NIC1_XGMAC_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers"); + + ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr, + NIC2_XGMAC_SEG_NUM, + sizeof(struct mpi_coredump_segment_header) + + sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers"); + if (qdev->func & 1) { /* Odd means our function is NIC 2 */ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) @@ -715,6 +796,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) mpi_coredump->nic_regs[i] = ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4); + + ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 0); + ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 1); } else { /* Even means our function is NIC 1 */ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) @@ -723,6 +807,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) mpi_coredump->nic2_regs[i] = ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4); + + ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 0); + ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 1); } /* Rev C. Step 20a */ -- GitLab From d5c1da56afb8a6b232393fb3fdef4909389d05fe Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Fri, 15 Jan 2010 13:31:34 +0000 Subject: [PATCH 0786/3892] qlge: Add module param to force firmware core dump. Default setting is 'off', don't allow force firmware dump. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 3 +++ drivers/net/qlge/qlge_dbg.c | 25 +++++++++++++++++++++++++ drivers/net/qlge/qlge_main.c | 11 +++++++++-- drivers/net/qlge/qlge_mpi.c | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 05feb03e9da6..9169c4cf413a 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2004,6 +2004,7 @@ enum { QL_CAM_RT_SET = 8, QL_SELFTEST = 9, QL_LB_LINK_UP = 10, + QL_FRC_COREDUMP = 11, }; /* link_status bit definitions */ @@ -2230,6 +2231,7 @@ int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, u32 ram_addr, int word_count); int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump); +int ql_mb_sys_err(struct ql_adapter *qdev); int ql_mb_about_fw(struct ql_adapter *qdev); int ql_wol(struct ql_adapter *qdev); int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); @@ -2246,6 +2248,7 @@ void ql_gen_reg_dump(struct ql_adapter *qdev, struct ql_reg_dump *mpi_coredump); netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev); void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *); +int ql_own_firmware(struct ql_adapter *qdev); int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget); #if 1 diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index ec4349a254cc..57df835147eb 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -1222,6 +1222,28 @@ err: } +static void ql_get_core_dump(struct ql_adapter *qdev) +{ + if (!ql_own_firmware(qdev)) { + QPRINTK(qdev, DRV, ERR, "%s: Don't own firmware!\n", + qdev->ndev->name); + return; + } + + if (!netif_running(qdev->ndev)) { + QPRINTK(qdev, IFUP, ERR, + "Force Coredump can only be done from interface " + "that is up.\n"); + return; + } + + if (ql_mb_sys_err(qdev)) { + QPRINTK(qdev, IFUP, ERR, + "Fail force coredump with ql_mb_sys_err().\n"); + return; + } +} + void ql_gen_reg_dump(struct ql_adapter *qdev, struct ql_reg_dump *mpi_coredump) { @@ -1297,6 +1319,9 @@ void ql_gen_reg_dump(struct ql_adapter *qdev, status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]); if (status) return; + + if (test_bit(QL_FRC_COREDUMP, &qdev->flags)) + ql_get_core_dump(qdev); } /* Coredump to messages log file using separate worker thread */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index e58892304e19..95fb63dcd9e4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -77,8 +77,13 @@ static int qlge_mpi_coredump; module_param(qlge_mpi_coredump, int, 0); MODULE_PARM_DESC(qlge_mpi_coredump, "Option to enable MPI firmware dump. " - "Default is OFF - Do Not allocate memory. " - "Do not perform firmware coredump."); + "Default is OFF - Do Not allocate memory. "); + +static int qlge_force_coredump; +module_param(qlge_force_coredump, int, 0); +MODULE_PARM_DESC(qlge_force_coredump, + "Option to allow force of firmware core dump. " + "Default is OFF - Do not allow."); static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, @@ -4496,6 +4501,8 @@ static int __devinit ql_init_device(struct pci_dev *pdev, err = -ENOMEM; goto err_out; } + if (qlge_force_coredump) + set_bit(QL_FRC_COREDUMP, &qdev->flags); } /* make sure the EEPROM is good */ err = qdev->nic_ops->get_flash(qdev); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 3304eb7df581..e2c846f17fc7 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -607,6 +607,22 @@ end: return status; } +int ql_mb_sys_err(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 1; + mbcp->out_count = 0; + + mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR; + + status = ql_mailbox_command(qdev, mbcp); + return status; +} /* Get MPI firmware version. This will be used for * driver banner and for ethtool info. -- GitLab From 6eb3a8553345ba2b4efd5390709e158289b9ece4 Mon Sep 17 00:00:00 2001 From: Patrick Mullaney Date: Sat, 16 Jan 2010 01:05:38 -0800 Subject: [PATCH 0787/3892] macvlan: add GRO bit to features mask Allow macvlan devices to support GRO. Signed-off-by: Patrick Mullaney Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 21a9c9ab4b34..fa0dc514dbaf 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -418,7 +418,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) -- GitLab From af19b49152bdb68fda894183e88096d6d1aa5c3d Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 13 Jan 2010 00:37:25 +0000 Subject: [PATCH 0788/3892] qlcnic: Qlogic ethernet driver for CNA devices o 1G/10G Ethernet Driver for Qlgic QLE8240 and QLE8242 CNA devices. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/Makefile | 8 + drivers/net/qlcnic/qlcnic.h | 1106 ++++++++++++ drivers/net/qlcnic/qlcnic_ctx.c | 536 ++++++ drivers/net/qlcnic/qlcnic_ethtool.c | 870 +++++++++ drivers/net/qlcnic/qlcnic_hdr.h | 937 ++++++++++ drivers/net/qlcnic/qlcnic_hw.c | 1201 ++++++++++++ drivers/net/qlcnic/qlcnic_init.c | 1466 +++++++++++++++ drivers/net/qlcnic/qlcnic_main.c | 2604 +++++++++++++++++++++++++++ 8 files changed, 8728 insertions(+) create mode 100644 drivers/net/qlcnic/Makefile create mode 100644 drivers/net/qlcnic/qlcnic.h create mode 100644 drivers/net/qlcnic/qlcnic_ctx.c create mode 100644 drivers/net/qlcnic/qlcnic_ethtool.c create mode 100644 drivers/net/qlcnic/qlcnic_hdr.h create mode 100644 drivers/net/qlcnic/qlcnic_hw.c create mode 100644 drivers/net/qlcnic/qlcnic_init.c create mode 100644 drivers/net/qlcnic/qlcnic_main.c diff --git a/drivers/net/qlcnic/Makefile b/drivers/net/qlcnic/Makefile new file mode 100644 index 000000000000..ddba83ef3f44 --- /dev/null +++ b/drivers/net/qlcnic/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Qlogic 1G/10G Ethernet Driver for CNA devices +# + +obj-$(CONFIG_QLCNIC) := qlcnic.o + +qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \ + qlcnic_ethtool.o qlcnic_ctx.o diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h new file mode 100644 index 000000000000..abec46846539 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic.h @@ -0,0 +1,1106 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#ifndef _QLCNIC_H_ +#define _QLCNIC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "qlcnic_hdr.h" + +#define _QLCNIC_LINUX_MAJOR 5 +#define _QLCNIC_LINUX_MINOR 0 +#define _QLCNIC_LINUX_SUBVERSION 0 +#define QLCNIC_LINUX_VERSIONID "5.0.0" + +#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) +#define _major(v) (((v) >> 24) & 0xff) +#define _minor(v) (((v) >> 16) & 0xff) +#define _build(v) ((v) & 0xffff) + +/* version in image has weird encoding: + * 7:0 - major + * 15:8 - minor + * 31:16 - build (little endian) + */ +#define QLCNIC_DECODE_VERSION(v) \ + QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16)) + +#define QLCNIC_NUM_FLASH_SECTORS (64) +#define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024) +#define QLCNIC_FLASH_TOTAL_SIZE (QLCNIC_NUM_FLASH_SECTORS \ + * QLCNIC_FLASH_SECTOR_SIZE) + +#define RCV_DESC_RINGSIZE(rds_ring) \ + (sizeof(struct rcv_desc) * (rds_ring)->num_desc) +#define RCV_BUFF_RINGSIZE(rds_ring) \ + (sizeof(struct qlcnic_rx_buffer) * rds_ring->num_desc) +#define STATUS_DESC_RINGSIZE(sds_ring) \ + (sizeof(struct status_desc) * (sds_ring)->num_desc) +#define TX_BUFF_RINGSIZE(tx_ring) \ + (sizeof(struct qlcnic_cmd_buffer) * tx_ring->num_desc) +#define TX_DESC_RINGSIZE(tx_ring) \ + (sizeof(struct cmd_desc_type0) * tx_ring->num_desc) + +#define QLCNIC_P3P_A0 0x50 + +#define QLCNIC_IS_REVISION_P3P(REVISION) (REVISION >= QLCNIC_P3P_A0) + +#define FIRST_PAGE_GROUP_START 0 +#define FIRST_PAGE_GROUP_END 0x100000 + +#define P3_MAX_MTU (9600) +#define QLCNIC_MAX_ETHERHDR 32 /* This contains some padding */ + +#define QLCNIC_P3_RX_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN) +#define QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + P3_MAX_MTU) +#define QLCNIC_CT_DEFAULT_RX_BUF_LEN 2048 +#define QLCNIC_LRO_BUFFER_EXTRA 2048 + +#define QLCNIC_RX_LRO_BUFFER_LENGTH (8060) + +/* Opcodes to be used with the commands */ +#define TX_ETHER_PKT 0x01 +#define TX_TCP_PKT 0x02 +#define TX_UDP_PKT 0x03 +#define TX_IP_PKT 0x04 +#define TX_TCP_LSO 0x05 +#define TX_TCP_LSO6 0x06 +#define TX_IPSEC 0x07 +#define TX_IPSEC_CMD 0x0a +#define TX_TCPV6_PKT 0x0b +#define TX_UDPV6_PKT 0x0c + +/* Tx defines */ +#define MAX_BUFFERS_PER_CMD 32 +#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) +#define QLCNIC_MAX_TX_TIMEOUTS 2 + +/* + * Following are the states of the Phantom. Phantom will set them and + * Host will read to check if the fields are correct. + */ +#define PHAN_INITIALIZE_FAILED 0xffff +#define PHAN_INITIALIZE_COMPLETE 0xff01 + +/* Host writes the following to notify that it has done the init-handshake */ +#define PHAN_INITIALIZE_ACK 0xf00f +#define PHAN_PEG_RCV_INITIALIZED 0xff01 + +#define NUM_RCV_DESC_RINGS 3 +#define NUM_STS_DESC_RINGS 4 + +#define RCV_RING_NORMAL 0 +#define RCV_RING_JUMBO 1 +#define RCV_RING_LRO 2 + +#define MIN_CMD_DESCRIPTORS 64 +#define MIN_RCV_DESCRIPTORS 64 +#define MIN_JUMBO_DESCRIPTORS 32 + +#define MAX_CMD_DESCRIPTORS 1024 +#define MAX_RCV_DESCRIPTORS_1G 4096 +#define MAX_RCV_DESCRIPTORS_10G 8192 +#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512 +#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024 +#define MAX_LRO_RCV_DESCRIPTORS 8 + +#define DEFAULT_RCV_DESCRIPTORS_1G 2048 +#define DEFAULT_RCV_DESCRIPTORS_10G 4096 + +#define get_next_index(index, length) \ + (((index) + 1) & ((length) - 1)) + +#define MPORT_MULTI_FUNCTION_MODE 0x2222 + +/* + * Following data structures describe the descriptors that will be used. + * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when + * we are doing LSO (above the 1500 size packet) only. + */ + +#define FLAGS_VLAN_TAGGED 0x10 +#define FLAGS_VLAN_OOB 0x40 + +#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \ + (cmd_desc)->vlan_TCI = cpu_to_le16(v); +#define qlcnic_set_cmd_desc_port(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) +#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0)) + +#define qlcnic_set_tx_port(_desc, _port) \ + ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0)) + +#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \ + ((_desc)->flags_opcode = \ + cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))) + +#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \ + ((_desc)->nfrags__length = \ + cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))) + +struct cmd_desc_type0 { + u8 tcp_hdr_offset; /* For LSO only */ + u8 ip_hdr_offset; /* For LSO only */ + __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */ + __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */ + + __le64 addr_buffer2; + + __le16 reference_handle; + __le16 mss; + u8 port_ctxid; /* 7:4 ctxid 3:0 port */ + u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ + __le16 conn_id; /* IPSec offoad only */ + + __le64 addr_buffer3; + __le64 addr_buffer1; + + __le16 buffer_length[4]; + + __le64 addr_buffer4; + + __le32 reserved2; + __le16 reserved; + __le16 vlan_TCI; + +} __attribute__ ((aligned(64))); + +/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */ +struct rcv_desc { + __le16 reference_handle; + __le16 reserved; + __le32 buffer_length; /* allocated buffer length (usually 2K) */ + __le64 addr_buffer; +}; + +/* opcode field in status_desc */ +#define QLCNIC_SYN_OFFLOAD 0x03 +#define QLCNIC_RXPKT_DESC 0x04 +#define QLCNIC_OLD_RXPKT_DESC 0x3f +#define QLCNIC_RESPONSE_DESC 0x05 +#define QLCNIC_LRO_DESC 0x12 + +/* for status field in status_desc */ +#define STATUS_CKSUM_OK (2) + +/* owner bits of status_desc */ +#define STATUS_OWNER_HOST (0x1ULL << 56) +#define STATUS_OWNER_PHANTOM (0x2ULL << 56) + +/* Status descriptor: + 0-3 port, 4-7 status, 8-11 type, 12-27 total_length + 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset + 53-55 desc_cnt, 56-57 owner, 58-63 opcode + */ +#define qlcnic_get_sts_port(sts_data) \ + ((sts_data) & 0x0F) +#define qlcnic_get_sts_status(sts_data) \ + (((sts_data) >> 4) & 0x0F) +#define qlcnic_get_sts_type(sts_data) \ + (((sts_data) >> 8) & 0x0F) +#define qlcnic_get_sts_totallength(sts_data) \ + (((sts_data) >> 12) & 0xFFFF) +#define qlcnic_get_sts_refhandle(sts_data) \ + (((sts_data) >> 28) & 0xFFFF) +#define qlcnic_get_sts_prot(sts_data) \ + (((sts_data) >> 44) & 0x0F) +#define qlcnic_get_sts_pkt_offset(sts_data) \ + (((sts_data) >> 48) & 0x1F) +#define qlcnic_get_sts_desc_cnt(sts_data) \ + (((sts_data) >> 53) & 0x7) +#define qlcnic_get_sts_opcode(sts_data) \ + (((sts_data) >> 58) & 0x03F) + +#define qlcnic_get_lro_sts_refhandle(sts_data) \ + ((sts_data) & 0x0FFFF) +#define qlcnic_get_lro_sts_length(sts_data) \ + (((sts_data) >> 16) & 0x0FFFF) +#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \ + (((sts_data) >> 32) & 0x0FF) +#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \ + (((sts_data) >> 40) & 0x0FF) +#define qlcnic_get_lro_sts_timestamp(sts_data) \ + (((sts_data) >> 48) & 0x1) +#define qlcnic_get_lro_sts_type(sts_data) \ + (((sts_data) >> 49) & 0x7) +#define qlcnic_get_lro_sts_push_flag(sts_data) \ + (((sts_data) >> 52) & 0x1) +#define qlcnic_get_lro_sts_seq_number(sts_data) \ + ((sts_data) & 0x0FFFFFFFF) + + +struct status_desc { + __le64 status_desc_data[2]; +} __attribute__ ((aligned(16))); + +/* UNIFIED ROMIMAGE */ +#define QLCNIC_UNI_FW_MIN_SIZE 0xc8000 +#define QLCNIC_UNI_DIR_SECT_PRODUCT_TBL 0x0 +#define QLCNIC_UNI_DIR_SECT_BOOTLD 0x6 +#define QLCNIC_UNI_DIR_SECT_FW 0x7 + +/*Offsets */ +#define QLCNIC_UNI_CHIP_REV_OFF 10 +#define QLCNIC_UNI_FLAGS_OFF 11 +#define QLCNIC_UNI_BIOS_VERSION_OFF 12 +#define QLCNIC_UNI_BOOTLD_IDX_OFF 27 +#define QLCNIC_UNI_FIRMWARE_IDX_OFF 29 + +struct uni_table_desc{ + u32 findex; + u32 num_entries; + u32 entry_size; + u32 reserved[5]; +}; + +struct uni_data_desc{ + u32 findex; + u32 size; + u32 reserved[5]; +}; + +/* Magic number to let user know flash is programmed */ +#define QLCNIC_BDINFO_MAGIC 0x12345678 + +#define QLCNIC_BRDTYPE_P3_REF_QG 0x0021 +#define QLCNIC_BRDTYPE_P3_HMEZ 0x0022 +#define QLCNIC_BRDTYPE_P3_10G_CX4_LP 0x0023 +#define QLCNIC_BRDTYPE_P3_4_GB 0x0024 +#define QLCNIC_BRDTYPE_P3_IMEZ 0x0025 +#define QLCNIC_BRDTYPE_P3_10G_SFP_PLUS 0x0026 +#define QLCNIC_BRDTYPE_P3_10000_BASE_T 0x0027 +#define QLCNIC_BRDTYPE_P3_XG_LOM 0x0028 +#define QLCNIC_BRDTYPE_P3_4_GB_MM 0x0029 +#define QLCNIC_BRDTYPE_P3_10G_SFP_CT 0x002a +#define QLCNIC_BRDTYPE_P3_10G_SFP_QT 0x002b +#define QLCNIC_BRDTYPE_P3_10G_CX4 0x0031 +#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032 +#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080 + +/* Flash memory map */ +#define QLCNIC_BRDCFG_START 0x4000 /* board config */ +#define QLCNIC_BOOTLD_START 0x10000 /* bootld */ +#define QLCNIC_IMAGE_START 0x43000 /* compressed image */ +#define QLCNIC_USER_START 0x3E8000 /* Firmare info */ + +#define QLCNIC_FW_VERSION_OFFSET (QLCNIC_USER_START+0x408) +#define QLCNIC_FW_SIZE_OFFSET (QLCNIC_USER_START+0x40c) +#define QLCNIC_FW_SERIAL_NUM_OFFSET (QLCNIC_USER_START+0x81c) +#define QLCNIC_BIOS_VERSION_OFFSET (QLCNIC_USER_START+0x83c) + +#define QLCNIC_BRDTYPE_OFFSET (QLCNIC_BRDCFG_START+0x8) +#define QLCNIC_FW_MAGIC_OFFSET (QLCNIC_BRDCFG_START+0x128) + +#define QLCNIC_FW_MIN_SIZE (0x3fffff) +#define QLCNIC_UNIFIED_ROMIMAGE 0 +#define QLCNIC_FLASH_ROMIMAGE 1 +#define QLCNIC_UNKNOWN_ROMIMAGE 0xff + +#define QLCNIC_UNIFIED_ROMIMAGE_NAME "phanfw.bin" +#define QLCNIC_FLASH_ROMIMAGE_NAME "flash" + +extern char qlcnic_driver_name[]; + +/* Number of status descriptors to handle per interrupt */ +#define MAX_STATUS_HANDLE (64) + +/* + * qlcnic_skb_frag{} is to contain mapping info for each SG list. This + * has to be freed when DMA is complete. This is part of qlcnic_tx_buffer{}. + */ +struct qlcnic_skb_frag { + u64 dma; + u64 length; +}; + +struct qlcnic_recv_crb { + u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; +}; + +/* Following defines are for the state of the buffers */ +#define QLCNIC_BUFFER_FREE 0 +#define QLCNIC_BUFFER_BUSY 1 + +/* + * There will be one qlcnic_buffer per skb packet. These will be + * used to save the dma info for pci_unmap_page() + */ +struct qlcnic_cmd_buffer { + struct sk_buff *skb; + struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + u32 frag_count; +}; + +/* In rx_buffer, we do not need multiple fragments as is a single buffer */ +struct qlcnic_rx_buffer { + struct list_head list; + struct sk_buff *skb; + u64 dma; + u16 ref_handle; + u16 state; +}; + +/* Board types */ +#define QLCNIC_GBE 0x01 +#define QLCNIC_XGBE 0x02 + +/* + * One hardware_context{} per adapter + * contains interrupt info as well shared hardware info. + */ +struct qlcnic_hardware_context { + void __iomem *pci_base0; + void __iomem *ocm_win_crb; + + unsigned long pci_len0; + + u32 ocm_win; + u32 crb_win; + + rwlock_t crb_lock; + struct mutex mem_lock; + + u8 cut_through; + u8 revision_id; + u8 pci_func; + u8 linkup; + u16 port_type; + u16 board_type; +}; + +struct qlcnic_adapter_stats { + u64 xmitcalled; + u64 xmitfinished; + u64 rxdropped; + u64 txdropped; + u64 csummed; + u64 rx_pkts; + u64 lro_pkts; + u64 rxbytes; + u64 txbytes; +}; + +/* + * Rcv Descriptor Context. One such per Rcv Descriptor. There may + * be one Rcv Descriptor for normal packets, one for jumbo and may be others. + */ +struct qlcnic_host_rds_ring { + u32 producer; + u32 num_desc; + u32 dma_size; + u32 skb_size; + u32 flags; + void __iomem *crb_rcv_producer; + struct rcv_desc *desc_head; + struct qlcnic_rx_buffer *rx_buf_arr; + struct list_head free_list; + spinlock_t lock; + dma_addr_t phys_addr; +}; + +struct qlcnic_host_sds_ring { + u32 consumer; + u32 num_desc; + void __iomem *crb_sts_consumer; + void __iomem *crb_intr_mask; + + struct status_desc *desc_head; + struct qlcnic_adapter *adapter; + struct napi_struct napi; + struct list_head free_list[NUM_RCV_DESC_RINGS]; + + int irq; + + dma_addr_t phys_addr; + char name[IFNAMSIZ+4]; +}; + +struct qlcnic_host_tx_ring { + u32 producer; + __le32 *hw_consumer; + u32 sw_consumer; + void __iomem *crb_cmd_producer; + u32 num_desc; + + struct netdev_queue *txq; + + struct qlcnic_cmd_buffer *cmd_buf_arr; + struct cmd_desc_type0 *desc_head; + dma_addr_t phys_addr; + dma_addr_t hw_cons_phys_addr; +}; + +/* + * Receive context. There is one such structure per instance of the + * receive processing. Any state information that is relevant to + * the receive, and is must be in this structure. The global data may be + * present elsewhere. + */ +struct qlcnic_recv_context { + u32 state; + u16 context_id; + u16 virt_port; + + struct qlcnic_host_rds_ring *rds_rings; + struct qlcnic_host_sds_ring *sds_rings; +}; + +/* HW context creation */ + +#define QLCNIC_OS_CRB_RETRY_COUNT 4000 +#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \ + (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16)) + +#define QLCNIC_CDRP_CMD_BIT 0x80000000 + +/* + * All responses must have the QLCNIC_CDRP_CMD_BIT cleared + * in the crb QLCNIC_CDRP_CRB_OFFSET. + */ +#define QLCNIC_CDRP_FORM_RSP(rsp) (rsp) +#define QLCNIC_CDRP_IS_RSP(rsp) (((rsp) & QLCNIC_CDRP_CMD_BIT) == 0) + +#define QLCNIC_CDRP_RSP_OK 0x00000001 +#define QLCNIC_CDRP_RSP_FAIL 0x00000002 +#define QLCNIC_CDRP_RSP_TIMEOUT 0x00000003 + +/* + * All commands must have the QLCNIC_CDRP_CMD_BIT set in + * the crb QLCNIC_CDRP_CRB_OFFSET. + */ +#define QLCNIC_CDRP_FORM_CMD(cmd) (QLCNIC_CDRP_CMD_BIT | (cmd)) +#define QLCNIC_CDRP_IS_CMD(cmd) (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0) + +#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES 0x00000001 +#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX 0x00000002 +#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX 0x00000003 +#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX 0x00000004 +#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX 0x00000005 +#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX 0x00000006 +#define QLCNIC_CDRP_CMD_CREATE_RX_CTX 0x00000007 +#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008 +#define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009 +#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a +#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e +#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f +#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010 +#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012 +#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013 +#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014 +#define QLCNIC_CDRP_CMD_READ_HW_REG 0x00000015 +#define QLCNIC_CDRP_CMD_GET_FLOW_CTL 0x00000016 +#define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017 +#define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018 +#define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019 +#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a +#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b +#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c +#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d +#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e +#define QLCNIC_CDRP_CMD_MAX 0x0000001f + +#define QLCNIC_RCODE_SUCCESS 0 +#define QLCNIC_RCODE_TIMEOUT 17 +#define QLCNIC_DESTROY_CTX_RESET 0 + +/* + * Capabilities Announced + */ +#define QLCNIC_CAP0_LEGACY_CONTEXT (1) +#define QLCNIC_CAP0_LEGACY_MN (1 << 2) +#define QLCNIC_CAP0_LSO (1 << 6) +#define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7) +#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8) + +/* + * Context state + */ +#define QLCNIC_HOST_CTX_STATE_ACTIVE 2 + +/* + * Rx context + */ + +struct qlcnic_hostrq_sds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le32 ring_size; /* Ring entries */ + __le16 msi_index; + __le16 rsvd; /* Padding */ +}; + +struct qlcnic_hostrq_rds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le64 buff_size; /* Packet buffer size */ + __le32 ring_size; /* Ring entries */ + __le32 ring_kind; /* Class of ring */ +}; + +struct qlcnic_hostrq_rx_ctx { + __le64 host_rsp_dma_addr; /* Response dma'd here */ + __le32 capabilities[4]; /* Flag bit vector */ + __le32 host_int_crb_mode; /* Interrupt crb usage */ + __le32 host_rds_crb_mode; /* RDS crb usage */ + /* These ring offsets are relative to data[0] below */ + __le32 rds_ring_offset; /* Offset to RDS config */ + __le32 sds_ring_offset; /* Offset to SDS config */ + __le16 num_rds_rings; /* Count of RDS rings */ + __le16 num_sds_rings; /* Count of SDS rings */ + __le16 rsvd1; /* Padding */ + __le16 rsvd2; /* Padding */ + u8 reserved[128]; /* reserve space for future expansion*/ + /* MUST BE 64-bit aligned. + The following is packed: + - N hostrq_rds_rings + - N hostrq_sds_rings */ + char data[0]; +}; + +struct qlcnic_cardrsp_rds_ring{ + __le32 host_producer_crb; /* Crb to use */ + __le32 rsvd1; /* Padding */ +}; + +struct qlcnic_cardrsp_sds_ring { + __le32 host_consumer_crb; /* Crb to use */ + __le32 interrupt_crb; /* Crb to use */ +}; + +struct qlcnic_cardrsp_rx_ctx { + /* These ring offsets are relative to data[0] below */ + __le32 rds_ring_offset; /* Offset to RDS config */ + __le32 sds_ring_offset; /* Offset to SDS config */ + __le32 host_ctx_state; /* Starting State */ + __le32 num_fn_per_port; /* How many PCI fn share the port */ + __le16 num_rds_rings; /* Count of RDS rings */ + __le16 num_sds_rings; /* Count of SDS rings */ + __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + u8 reserved[128]; /* save space for future expansion */ + /* MUST BE 64-bit aligned. + The following is packed: + - N cardrsp_rds_rings + - N cardrs_sds_rings */ + char data[0]; +}; + +#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ + (sizeof(HOSTRQ_RX) + \ + (rds_rings)*(sizeof(struct qlcnic_hostrq_rds_ring)) + \ + (sds_rings)*(sizeof(struct qlcnic_hostrq_sds_ring))) + +#define SIZEOF_CARDRSP_RX(CARDRSP_RX, rds_rings, sds_rings) \ + (sizeof(CARDRSP_RX) + \ + (rds_rings)*(sizeof(struct qlcnic_cardrsp_rds_ring)) + \ + (sds_rings)*(sizeof(struct qlcnic_cardrsp_sds_ring))) + +/* + * Tx context + */ + +struct qlcnic_hostrq_cds_ring { + __le64 host_phys_addr; /* Ring base addr */ + __le32 ring_size; /* Ring entries */ + __le32 rsvd; /* Padding */ +}; + +struct qlcnic_hostrq_tx_ctx { + __le64 host_rsp_dma_addr; /* Response dma'd here */ + __le64 cmd_cons_dma_addr; /* */ + __le64 dummy_dma_addr; /* */ + __le32 capabilities[4]; /* Flag bit vector */ + __le32 host_int_crb_mode; /* Interrupt crb usage */ + __le32 rsvd1; /* Padding */ + __le16 rsvd2; /* Padding */ + __le16 interrupt_ctl; + __le16 msi_index; + __le16 rsvd3; /* Padding */ + struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */ + u8 reserved[128]; /* future expansion */ +}; + +struct qlcnic_cardrsp_cds_ring { + __le32 host_producer_crb; /* Crb to use */ + __le32 interrupt_crb; /* Crb to use */ +}; + +struct qlcnic_cardrsp_tx_ctx { + __le32 host_ctx_state; /* Starting state */ + __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */ + u8 reserved[128]; /* future expansion */ +}; + +#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX)) +#define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX)) + +/* CRB */ + +#define QLCNIC_HOST_RDS_CRB_MODE_UNIQUE 0 +#define QLCNIC_HOST_RDS_CRB_MODE_SHARED 1 +#define QLCNIC_HOST_RDS_CRB_MODE_CUSTOM 2 +#define QLCNIC_HOST_RDS_CRB_MODE_MAX 3 + +#define QLCNIC_HOST_INT_CRB_MODE_UNIQUE 0 +#define QLCNIC_HOST_INT_CRB_MODE_SHARED 1 +#define QLCNIC_HOST_INT_CRB_MODE_NORX 2 +#define QLCNIC_HOST_INT_CRB_MODE_NOTX 3 +#define QLCNIC_HOST_INT_CRB_MODE_NORXTX 4 + + +/* MAC */ + +#define MC_COUNT_P3 38 + +#define QLCNIC_MAC_NOOP 0 +#define QLCNIC_MAC_ADD 1 +#define QLCNIC_MAC_DEL 2 + +struct qlcnic_mac_list_s { + struct list_head list; + uint8_t mac_addr[ETH_ALEN+2]; +}; + +/* + * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is + * adjusted based on configured MTU. + */ +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 +#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64 +#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4 + +#define QLCNIC_INTR_DEFAULT 0x04 + +union qlcnic_nic_intr_coalesce_data { + struct { + u16 rx_packets; + u16 rx_time_us; + u16 tx_packets; + u16 tx_time_us; + } data; + u64 word; +}; + +struct qlcnic_nic_intr_coalesce { + u16 stats_time_us; + u16 rate_sample_time; + u16 flags; + u16 rsvd_1; + u32 low_threshold; + u32 high_threshold; + union qlcnic_nic_intr_coalesce_data normal; + union qlcnic_nic_intr_coalesce_data low; + union qlcnic_nic_intr_coalesce_data high; + union qlcnic_nic_intr_coalesce_data irq; +}; + +#define QLCNIC_HOST_REQUEST 0x13 +#define QLCNIC_REQUEST 0x14 + +#define QLCNIC_MAC_EVENT 0x1 + +#define QLCNIC_IP_UP 2 +#define QLCNIC_IP_DOWN 3 + +/* + * Driver --> Firmware + */ +#define QLCNIC_H2C_OPCODE_START 0 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2 +#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 +#define QLCNIC_H2C_OPCODE_CONFIG_LED 4 +#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 +#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6 +#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7 +#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8 +#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9 +#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 +#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11 +#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 +#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 +#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 +#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 +#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16 +#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 +#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18 +#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK 19 +#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20 +#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21 +#define QLCNIC_C2C_OPCODE 22 +#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23 +#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24 +#define QLCNIC_H2C_OPCODE_LAST 25 +/* + * Firmware --> Driver + */ + +#define QLCNIC_C2H_OPCODE_START 128 +#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 +#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 +#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 +#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 +#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 +#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 +#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 +#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136 +#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 +#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 +#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 +#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 +#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 +#define QLCNIC_C2H_OPCODE_LAST 142 + +#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ +#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ +#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ + +#define QLCNIC_LRO_REQUEST_CLEANUP 4 + +/* Capabilites received */ +#define QLCNIC_FW_CAPABILITY_BDG (1 << 8) +#define QLCNIC_FW_CAPABILITY_FVLANTX (1 << 9) +#define QLCNIC_FW_CAPABILITY_HW_LRO (1 << 10) + +/* module types */ +#define LINKEVENT_MODULE_NOT_PRESENT 1 +#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2 +#define LINKEVENT_MODULE_OPTICAL_SRLR 3 +#define LINKEVENT_MODULE_OPTICAL_LRM 4 +#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7 +#define LINKEVENT_MODULE_TWINAX 8 + +#define LINKSPEED_10GBPS 10000 +#define LINKSPEED_1GBPS 1000 +#define LINKSPEED_100MBPS 100 +#define LINKSPEED_10MBPS 10 + +#define LINKSPEED_ENCODED_10MBPS 0 +#define LINKSPEED_ENCODED_100MBPS 1 +#define LINKSPEED_ENCODED_1GBPS 2 + +#define LINKEVENT_AUTONEG_DISABLED 0 +#define LINKEVENT_AUTONEG_ENABLED 1 + +#define LINKEVENT_HALF_DUPLEX 0 +#define LINKEVENT_FULL_DUPLEX 1 + +#define LINKEVENT_LINKSPEED_MBPS 0 +#define LINKEVENT_LINKSPEED_ENCODED 1 + +#define AUTO_FW_RESET_ENABLED 0x01 +/* firmware response header: + * 63:58 - message type + * 57:56 - owner + * 55:53 - desc count + * 52:48 - reserved + * 47:40 - completion id + * 39:32 - opcode + * 31:16 - error code + * 15:00 - reserved + */ +#define qlcnic_get_nic_msg_opcode(msg_hdr) \ + ((msg_hdr >> 32) & 0xFF) + +struct qlcnic_fw_msg { + union { + struct { + u64 hdr; + u64 body[7]; + }; + u64 words[8]; + }; +}; + +struct qlcnic_nic_req { + __le64 qhdr; + __le64 req_hdr; + __le64 words[6]; +}; + +struct qlcnic_mac_req { + u8 op; + u8 tag; + u8 mac_addr[6]; +}; + +#define QLCNIC_MSI_ENABLED 0x02 +#define QLCNIC_MSIX_ENABLED 0x04 +#define QLCNIC_LRO_ENABLED 0x08 +#define QLCNIC_BRIDGE_ENABLED 0X10 +#define QLCNIC_DIAG_ENABLED 0x20 +#define QLCNIC_IS_MSI_FAMILY(adapter) \ + ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) + +#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS +#define QLCNIC_MSIX_TBL_SPACE 8192 +#define QLCNIC_PCI_REG_MSIX_TBL 0x44 + +#define QLCNIC_NETDEV_WEIGHT 128 +#define QLCNIC_ADAPTER_UP_MAGIC 777 + +#define __QLCNIC_FW_ATTACHED 0 +#define __QLCNIC_DEV_UP 1 +#define __QLCNIC_RESETTING 2 +#define __QLCNIC_START_FW 4 + +struct qlcnic_adapter { + struct qlcnic_hardware_context ahw; + + struct net_device *netdev; + struct pci_dev *pdev; + struct list_head mac_list; + + spinlock_t tx_clean_lock; + + u16 num_txd; + u16 num_rxd; + u16 num_jumbo_rxd; + u16 num_lro_rxd; + + u8 max_rds_rings; + u8 max_sds_rings; + u8 driver_mismatch; + u8 msix_supported; + u8 rx_csum; + u8 pci_using_dac; + u8 portnum; + u8 physical_port; + + u8 mc_enabled; + u8 max_mc_count; + u8 rss_supported; + u8 rsrvd1; + u8 fw_wait_cnt; + u8 fw_fail_cnt; + u8 tx_timeo_cnt; + u8 need_fw_reset; + + u8 has_link_events; + u8 fw_type; + u16 tx_context_id; + u16 mtu; + u16 is_up; + + u16 link_speed; + u16 link_duplex; + u16 link_autoneg; + u16 module_type; + + u32 capabilities; + u32 flags; + u32 irq; + u32 temp; + + u32 int_vec_bit; + u32 heartbit; + + u8 dev_state; + u8 rsrd1; + u32 rsrd2; + + + u8 mac_addr[ETH_ALEN]; + + struct qlcnic_adapter_stats stats; + + struct qlcnic_recv_context recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; + + void __iomem *tgt_mask_reg; + void __iomem *tgt_status_reg; + void __iomem *crb_int_state_reg; + void __iomem *isr_int_vec; + + struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + + struct delayed_work fw_work; + + struct work_struct tx_timeout_task; + + struct qlcnic_nic_intr_coalesce coal; + + unsigned long state; + __le32 file_prd_off; /*File fw product offset*/ + u32 fw_version; + const struct firmware *fw; +}; + +int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); +int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); + +u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off); +int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data); +int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data); +int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data); + +#define QLCRD32(adapter, off) \ + (qlcnic_hw_read_wx_2M(adapter, off)) +#define QLCWR32(adapter, off, val) \ + (qlcnic_hw_write_wx_2M(adapter, off, val)) + +int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32); +void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int); + +#define qlcnic_rom_lock(a) \ + qlcnic_pcie_sem_lock((a), 2, QLCNIC_ROM_LOCK_ID) +#define qlcnic_rom_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 2) +#define qlcnic_phy_lock(a) \ + qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID) +#define qlcnic_phy_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 3) +#define qlcnic_api_lock(a) \ + qlcnic_pcie_sem_lock((a), 5, 0) +#define qlcnic_api_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 5) +#define qlcnic_sw_lock(a) \ + qlcnic_pcie_sem_lock((a), 6, 0) +#define qlcnic_sw_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 6) +#define crb_win_lock(a) \ + qlcnic_pcie_sem_lock((a), 7, QLCNIC_CRB_WIN_LOCK_ID) +#define crb_win_unlock(a) \ + qlcnic_pcie_sem_unlock((a), 7) + +int qlcnic_get_board_info(struct qlcnic_adapter *adapter); +int qlcnic_wol_supported(struct qlcnic_adapter *adapter); + +/* Functions from qlcnic_init.c */ +int qlcnic_phantom_init(struct qlcnic_adapter *adapter); +int qlcnic_load_firmware(struct qlcnic_adapter *adapter); +int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter); +void qlcnic_request_firmware(struct qlcnic_adapter *adapter); +void qlcnic_release_firmware(struct qlcnic_adapter *adapter); +int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter); + +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp); +int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size); +int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter); +void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter); + +void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32); + +int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter); +void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter); + +void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter); +void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); + +int qlcnic_init_firmware(struct qlcnic_adapter *adapter); +void qlcnic_watchdog_task(struct work_struct *work); +void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, + struct qlcnic_host_rds_ring *rds_ring); +int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); +void qlcnic_set_multi(struct net_device *netdev); +void qlcnic_free_mac_list(struct qlcnic_adapter *adapter); +int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32); +int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter); +int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable); +int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd); +int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable); +void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); + +int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); +int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); +int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); +int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable); +int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); +void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring); +int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); + +/* Functions from qlcnic_main.c */ +int qlcnic_reset_context(struct qlcnic_adapter *); + +/* + * QLOGIC Board information + */ + +#define QLCNIC_MAX_BOARD_NAME_LEN 64 +struct qlcnic_brdinfo { + unsigned short vendor; + unsigned short device; + unsigned short sub_vendor; + unsigned short sub_device; + char short_name[QLCNIC_MAX_BOARD_NAME_LEN]; +}; + +static const struct qlcnic_brdinfo qlcnic_boards[] = { + {0x1077, 0x8020, 0x1077, 0x203, "8200 Series Single Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x207, "8200 Series Dual Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x20b, + "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x1077, 0x20c, + "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x1077, 0x20f, + "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"}, + {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"}, +}; + +#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards) + +static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) +{ + smp_mb(); + if (tx_ring->producer < tx_ring->sw_consumer) + return tx_ring->sw_consumer - tx_ring->producer; + else + return tx_ring->sw_consumer + tx_ring->num_desc - + tx_ring->producer; +} + +extern const struct ethtool_ops qlcnic_ethtool_ops; + +#endif /* __QLCNIC_H_ */ diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c new file mode 100644 index 000000000000..71c16a183458 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include "qlcnic.h" + +#define QLCHAL_VERSION 1 + +static u32 +qlcnic_poll_rsp(struct qlcnic_adapter *adapter) +{ + u32 rsp; + int timeout = 0; + + do { + /* give atleast 1ms for firmware to respond */ + msleep(1); + + if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) + return QLCNIC_CDRP_RSP_TIMEOUT; + + rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET); + } while (!QLCNIC_CDRP_IS_RSP(rsp)); + + return rsp; +} + +static u32 +qlcnic_issue_cmd(struct qlcnic_adapter *adapter, + u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) +{ + u32 rsp; + u32 signature; + u32 rcode = QLCNIC_RCODE_SUCCESS; + struct pci_dev *pdev = adapter->pdev; + + signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version); + + /* Acquire semaphore before accessing CRB */ + if (qlcnic_api_lock(adapter)) + return QLCNIC_RCODE_TIMEOUT; + + QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature); + QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1); + QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2); + QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3); + QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd)); + + rsp = qlcnic_poll_rsp(adapter); + + if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) { + dev_err(&pdev->dev, "card response timeout.\n"); + rcode = QLCNIC_RCODE_TIMEOUT; + } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { + rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); + dev_err(&pdev->dev, "failed card response code:0x%x\n", + rcode); + } + + /* Release semaphore */ + qlcnic_api_unlock(adapter); + + return rcode; +} + +int +qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) { + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + recv_ctx->context_id, + mtu, + 0, + QLCNIC_CDRP_CMD_SET_MTU)) { + + dev_err(&adapter->pdev->dev, "Failed to set mtu\n"); + return -EIO; + } + } + + return 0; +} + +static int +qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) +{ + void *addr; + struct qlcnic_hostrq_rx_ctx *prq; + struct qlcnic_cardrsp_rx_ctx *prsp; + struct qlcnic_hostrq_rds_ring *prq_rds; + struct qlcnic_hostrq_sds_ring *prq_sds; + struct qlcnic_cardrsp_rds_ring *prsp_rds; + struct qlcnic_cardrsp_sds_ring *prsp_sds; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + + dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; + u64 phys_addr; + + int i, nrds_rings, nsds_rings; + size_t rq_size, rsp_size; + u32 cap, reg, val; + int err; + + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + nrds_rings = adapter->max_rds_rings; + nsds_rings = adapter->max_sds_rings; + + rq_size = + SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings, + nsds_rings); + rsp_size = + SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, + nsds_rings); + + addr = pci_alloc_consistent(adapter->pdev, + rq_size, &hostrq_phys_addr); + if (addr == NULL) + return -ENOMEM; + prq = (struct qlcnic_hostrq_rx_ctx *)addr; + + addr = pci_alloc_consistent(adapter->pdev, + rsp_size, &cardrsp_phys_addr); + if (addr == NULL) { + err = -ENOMEM; + goto out_free_rq; + } + prsp = (struct qlcnic_cardrsp_rx_ctx *)addr; + + prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr); + + cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN); + cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS); + + prq->capabilities[0] = cpu_to_le32(cap); + prq->host_int_crb_mode = + cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED); + prq->host_rds_crb_mode = + cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE); + + prq->num_rds_rings = cpu_to_le16(nrds_rings); + prq->num_sds_rings = cpu_to_le16(nsds_rings); + prq->rds_ring_offset = cpu_to_le32(0); + + val = le32_to_cpu(prq->rds_ring_offset) + + (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); + prq->sds_ring_offset = cpu_to_le32(val); + + prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data + + le32_to_cpu(prq->rds_ring_offset)); + + for (i = 0; i < nrds_rings; i++) { + + rds_ring = &recv_ctx->rds_rings[i]; + + prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr); + prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc); + prq_rds[i].ring_kind = cpu_to_le32(i); + prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size); + } + + prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data + + le32_to_cpu(prq->sds_ring_offset)); + + for (i = 0; i < nsds_rings; i++) { + + sds_ring = &recv_ctx->sds_rings[i]; + + prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr); + prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc); + prq_sds[i].msi_index = cpu_to_le16(i); + } + + phys_addr = hostrq_phys_addr; + err = qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + (u32)(phys_addr >> 32), + (u32)(phys_addr & 0xffffffff), + rq_size, + QLCNIC_CDRP_CMD_CREATE_RX_CTX); + if (err) { + dev_err(&adapter->pdev->dev, + "Failed to create rx ctx in firmware%d\n", err); + goto out_free_rsp; + } + + + prsp_rds = ((struct qlcnic_cardrsp_rds_ring *) + &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]); + + for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) { + rds_ring = &recv_ctx->rds_rings[i]; + + reg = le32_to_cpu(prsp_rds[i].host_producer_crb); + rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + } + + prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) + &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]); + + for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) { + sds_ring = &recv_ctx->sds_rings[i]; + + reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); + sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + + reg = le32_to_cpu(prsp_sds[i].interrupt_crb); + sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(reg - 0x200)); + } + + recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); + recv_ctx->context_id = le16_to_cpu(prsp->context_id); + recv_ctx->virt_port = prsp->virt_port; + +out_free_rsp: + pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); +out_free_rq: + pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); + return err; +} + +static void +qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + recv_ctx->context_id, + QLCNIC_DESTROY_CTX_RESET, + 0, + QLCNIC_CDRP_CMD_DESTROY_RX_CTX)) { + + dev_err(&adapter->pdev->dev, + "Failed to destroy rx ctx in firmware\n"); + } +} + +static int +qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hostrq_tx_ctx *prq; + struct qlcnic_hostrq_cds_ring *prq_cds; + struct qlcnic_cardrsp_tx_ctx *prsp; + void *rq_addr, *rsp_addr; + size_t rq_size, rsp_size; + u32 temp; + int err; + u64 phys_addr; + dma_addr_t rq_phys_addr, rsp_phys_addr; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); + rq_addr = pci_alloc_consistent(adapter->pdev, + rq_size, &rq_phys_addr); + if (!rq_addr) + return -ENOMEM; + + rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); + rsp_addr = pci_alloc_consistent(adapter->pdev, + rsp_size, &rsp_phys_addr); + if (!rsp_addr) { + err = -ENOMEM; + goto out_free_rq; + } + + memset(rq_addr, 0, rq_size); + prq = (struct qlcnic_hostrq_tx_ctx *)rq_addr; + + memset(rsp_addr, 0, rsp_size); + prsp = (struct qlcnic_cardrsp_tx_ctx *)rsp_addr; + + prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr); + + temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN | + QLCNIC_CAP0_LSO); + prq->capabilities[0] = cpu_to_le32(temp); + + prq->host_int_crb_mode = + cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED); + + prq->interrupt_ctl = 0; + prq->msi_index = 0; + prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr); + + prq_cds = &prq->cds_ring; + + prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); + prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); + + phys_addr = rq_phys_addr; + err = qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + (u32)(phys_addr >> 32), + ((u32)phys_addr & 0xffffffff), + rq_size, + QLCNIC_CDRP_CMD_CREATE_TX_CTX); + + if (err == QLCNIC_RCODE_SUCCESS) { + temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); + tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter, + QLCNIC_REG(temp - 0x200)); + + adapter->tx_context_id = + le16_to_cpu(prsp->context_id); + } else { + dev_err(&adapter->pdev->dev, + "Failed to create tx ctx in firmware%d\n", err); + err = -EIO; + } + + pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); + +out_free_rq: + pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); + + return err; +} + +static void +qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) +{ + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + adapter->tx_context_id, + QLCNIC_DESTROY_CTX_RESET, + 0, + QLCNIC_CDRP_CMD_DESTROY_TX_CTX)) { + + dev_err(&adapter->pdev->dev, + "Failed to destroy tx ctx in firmware\n"); + } +} + +int +qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) +{ + + if (qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + reg, + 0, + 0, + QLCNIC_CDRP_CMD_READ_PHY)) { + + return -EIO; + } + + return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); +} + +int +qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) +{ + return qlcnic_issue_cmd(adapter, + adapter->ahw.pci_func, + QLCHAL_VERSION, + reg, + val, + 0, + QLCNIC_CDRP_CMD_WRITE_PHY); +} + +int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) +{ + void *addr; + int err; + int ring; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + + struct pci_dev *pdev = adapter->pdev; + + recv_ctx = &adapter->recv_ctx; + tx_ring = adapter->tx_ring; + + tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32), + &tx_ring->hw_cons_phys_addr); + if (tx_ring->hw_consumer == NULL) { + dev_err(&pdev->dev, "failed to allocate tx consumer\n"); + return -ENOMEM; + } + *(tx_ring->hw_consumer) = 0; + + /* cmd desc ring */ + addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr); + + if (addr == NULL) { + dev_err(&pdev->dev, "failed to allocate tx desc ring\n"); + return -ENOMEM; + } + + tx_ring->desc_head = (struct cmd_desc_type0 *)addr; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + addr = pci_alloc_consistent(adapter->pdev, + RCV_DESC_RINGSIZE(rds_ring), + &rds_ring->phys_addr); + if (addr == NULL) { + dev_err(&pdev->dev, + "failed to allocate rds ring [%d]\n", ring); + err = -ENOMEM; + goto err_out_free; + } + rds_ring->desc_head = (struct rcv_desc *)addr; + + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + addr = pci_alloc_consistent(adapter->pdev, + STATUS_DESC_RINGSIZE(sds_ring), + &sds_ring->phys_addr); + if (addr == NULL) { + dev_err(&pdev->dev, + "failed to allocate sds ring [%d]\n", ring); + err = -ENOMEM; + goto err_out_free; + } + sds_ring->desc_head = (struct status_desc *)addr; + } + + + err = qlcnic_fw_cmd_create_rx_ctx(adapter); + if (err) + goto err_out_free; + err = qlcnic_fw_cmd_create_tx_ctx(adapter); + if (err) + goto err_out_free; + + set_bit(__QLCNIC_FW_ATTACHED, &adapter->state); + return 0; + +err_out_free: + qlcnic_free_hw_resources(adapter); + return err; +} + +void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + + if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) { + qlcnic_fw_cmd_destroy_rx_ctx(adapter); + qlcnic_fw_cmd_destroy_tx_ctx(adapter); + + /* Allow dma queues to drain after context reset */ + msleep(20); + } + + recv_ctx = &adapter->recv_ctx; + + tx_ring = adapter->tx_ring; + if (tx_ring->hw_consumer != NULL) { + pci_free_consistent(adapter->pdev, + sizeof(u32), + tx_ring->hw_consumer, + tx_ring->hw_cons_phys_addr); + tx_ring->hw_consumer = NULL; + } + + if (tx_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + TX_DESC_RINGSIZE(tx_ring), + tx_ring->desc_head, tx_ring->phys_addr); + tx_ring->desc_head = NULL; + } + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + + if (rds_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + RCV_DESC_RINGSIZE(rds_ring), + rds_ring->desc_head, + rds_ring->phys_addr); + rds_ring->desc_head = NULL; + } + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + if (sds_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + STATUS_DESC_RINGSIZE(sds_ring), + sds_ring->desc_head, + sds_ring->phys_addr); + sds_ring->desc_head = NULL; + } + } +} + diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c new file mode 100644 index 000000000000..65e9620e28f1 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -0,0 +1,870 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include +#include +#include +#include +#include + +#include "qlcnic.h" + +struct qlcnic_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m) +#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m) + +static const struct qlcnic_stats qlcnic_gstrings_stats[] = { + {"xmit_called", + QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)}, + {"xmit_finished", + QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)}, + {"rx_dropped", + QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)}, + {"tx_dropped", + QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)}, + {"csummed", + QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)}, + {"rx_pkts", + QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)}, + {"lro_pkts", + QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)}, + {"rx_bytes", + QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)}, + {"tx_bytes", + QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)}, +}; + +#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) + +static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { + "Register_Test_on_offline", + "Link_Test_on_offline" +}; + +#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) + +#define QLCNIC_RING_REGS_COUNT 20 +#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32)) +#define QLCNIC_MAX_EEPROM_LEN 1024 + +static const u32 diag_registers[] = { + CRB_CMDPEG_STATE, + CRB_RCVPEG_STATE, + CRB_XG_STATE_P3, + CRB_FW_CAPABILITIES_1, + ISR_INT_STATE_REG, + QLCNIC_CRB_DEV_REF_COUNT, + QLCNIC_CRB_DEV_STATE, + QLCNIC_CRB_DRV_STATE, + QLCNIC_CRB_DRV_SCRATCH, + QLCNIC_CRB_DEV_PARTITION_INFO, + QLCNIC_CRB_DRV_IDC_VER, + QLCNIC_PEG_ALIVE_COUNTER, + QLCNIC_PEG_HALT_STATUS1, + QLCNIC_PEG_HALT_STATUS2, + QLCNIC_CRB_PEG_NET_0+0x3c, + QLCNIC_CRB_PEG_NET_1+0x3c, + QLCNIC_CRB_PEG_NET_2+0x3c, + QLCNIC_CRB_PEG_NET_4+0x3c, + -1 +}; + +static int qlcnic_get_regs_len(struct net_device *dev) +{ + return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN; +} + +static int qlcnic_get_eeprom_len(struct net_device *dev) +{ + return QLCNIC_FLASH_TOTAL_SIZE; +} + +static void +qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 fw_major, fw_minor, fw_build; + + fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); + + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + strlcpy(drvinfo->driver, qlcnic_driver_name, 32); + strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32); +} + +static int +qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int check_sfp_module = 0; + u16 pcifn = adapter->ahw.pci_func; + + /* read which mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + ecmd->advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + ecmd->speed = adapter->link_speed; + ecmd->duplex = adapter->link_duplex; + ecmd->autoneg = adapter->link_autoneg; + + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + u32 val; + + val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); + if (val == QLCNIC_PORT_MODE_802_3_AP) { + ecmd->supported = SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_1000baseT_Full; + } else { + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; + } + + if (netif_running(dev) && adapter->has_link_events) { + ecmd->speed = adapter->link_speed; + ecmd->autoneg = adapter->link_autoneg; + ecmd->duplex = adapter->link_duplex; + goto skip; + } + + val = QLCRD32(adapter, P3_LINK_SPEED_REG(pcifn)); + ecmd->speed = P3_LINK_SPEED_MHZ * + P3_LINK_SPEED_VAL(pcifn, val); + ecmd->duplex = DUPLEX_FULL; + ecmd->autoneg = AUTONEG_DISABLE; + } else + return -EIO; + +skip: + ecmd->phy_address = adapter->physical_port; + ecmd->transceiver = XCVR_EXTERNAL; + + switch (adapter->ahw.board_type) { + case QLCNIC_BRDTYPE_P3_REF_QG: + case QLCNIC_BRDTYPE_P3_4_GB: + case QLCNIC_BRDTYPE_P3_4_GB_MM: + + ecmd->supported |= SUPPORTED_Autoneg; + ecmd->advertising |= ADVERTISED_Autoneg; + case QLCNIC_BRDTYPE_P3_10G_CX4: + case QLCNIC_BRDTYPE_P3_10G_CX4_LP: + case QLCNIC_BRDTYPE_P3_10000_BASE_T: + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; + ecmd->autoneg = adapter->link_autoneg; + break; + case QLCNIC_BRDTYPE_P3_IMEZ: + case QLCNIC_BRDTYPE_P3_XG_LOM: + case QLCNIC_BRDTYPE_P3_HMEZ: + ecmd->supported |= SUPPORTED_MII; + ecmd->advertising |= ADVERTISED_MII; + ecmd->port = PORT_MII; + ecmd->autoneg = AUTONEG_DISABLE; + break; + case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS: + case QLCNIC_BRDTYPE_P3_10G_SFP_CT: + case QLCNIC_BRDTYPE_P3_10G_SFP_QT: + ecmd->advertising |= ADVERTISED_TP; + ecmd->supported |= SUPPORTED_TP; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; + case QLCNIC_BRDTYPE_P3_10G_XFP: + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + ecmd->autoneg = AUTONEG_DISABLE; + break; + case QLCNIC_BRDTYPE_P3_10G_TP: + if (adapter->ahw.port_type == QLCNIC_XGBE) { + ecmd->autoneg = AUTONEG_DISABLE; + ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); + ecmd->advertising |= + (ADVERTISED_FIBRE | ADVERTISED_TP); + ecmd->port = PORT_FIBRE; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; + } else { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg); + ecmd->advertising |= + (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->port = PORT_TP; + } + break; + default: + dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", + adapter->ahw.board_type); + return -EIO; + } + + if (check_sfp_module) { + switch (adapter->module_type) { + case LINKEVENT_MODULE_OPTICAL_UNKNOWN: + case LINKEVENT_MODULE_OPTICAL_SRLR: + case LINKEVENT_MODULE_OPTICAL_LRM: + case LINKEVENT_MODULE_OPTICAL_SFP_1G: + ecmd->port = PORT_FIBRE; + break; + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: + case LINKEVENT_MODULE_TWINAX: + ecmd->port = PORT_TP; + break; + default: + ecmd->port = PORT_OTHER; + } + } + + return 0; +} + +static int +qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + __u32 status; + + /* read which mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + /* autonegotiation */ + if (qlcnic_fw_cmd_set_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, + ecmd->autoneg) != 0) + return -EIO; + else + adapter->link_autoneg = ecmd->autoneg; + + if (qlcnic_fw_cmd_query_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) + return -EIO; + + switch (ecmd->speed) { + case SPEED_10: + qlcnic_set_phy_speed(status, 0); + break; + case SPEED_100: + qlcnic_set_phy_speed(status, 1); + break; + case SPEED_1000: + qlcnic_set_phy_speed(status, 2); + break; + } + + if (ecmd->duplex == DUPLEX_HALF) + qlcnic_clear_phy_duplex(status); + if (ecmd->duplex == DUPLEX_FULL) + qlcnic_set_phy_duplex(status); + if (qlcnic_fw_cmd_set_phy(adapter, + QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + *((int *)&status)) != 0) + return -EIO; + else { + adapter->link_speed = ecmd->speed; + adapter->link_duplex = ecmd->duplex; + } + } else + return -EOPNOTSUPP; + + if (!netif_running(dev)) + return 0; + + dev->netdev_ops->ndo_stop(dev); + return dev->netdev_ops->ndo_open(dev); +} + +static void +qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_host_sds_ring *sds_ring; + u32 *regs_buff = p; + int ring, i = 0; + + memset(p, 0, qlcnic_get_regs_len(dev)); + regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | + (adapter->pdev)->device; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + for (i = 0; diag_registers[i] != -1; i++) + regs_buff[i] = QLCRD32(adapter, diag_registers[i]); + + regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ + + regs_buff[i++] = 1; /* No. of tx ring */ + regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer)); + regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer); + + regs_buff[i++] = 2; /* No. of rx ring */ + regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer); + regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer); + + regs_buff[i++] = adapter->max_sds_rings; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &(recv_ctx->sds_rings[ring]); + regs_buff[i++] = readl(sds_ring->crb_sts_consumer); + } +} + +static u32 qlcnic_test_link(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 val; + + val = QLCRD32(adapter, CRB_XG_STATE_P3); + val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); + return (val == XG_LINK_UP_P3) ? 0 : 1; +} + +static int +qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *bytes) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int offset; + int ret; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = (adapter->pdev)->vendor | + ((adapter->pdev)->device << 16); + offset = eeprom->offset; + + ret = qlcnic_rom_fast_read_words(adapter, offset, bytes, + eeprom->len); + if (ret < 0) + return ret; + + return 0; +} + +static void +qlcnic_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + ring->rx_pending = adapter->num_rxd; + ring->rx_jumbo_pending = adapter->num_jumbo_rxd; + ring->rx_jumbo_pending += adapter->num_lro_rxd; + ring->tx_pending = adapter->num_txd; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } else { + ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + ring->tx_max_pending = MAX_CMD_DESCRIPTORS; + + ring->rx_mini_max_pending = 0; + ring->rx_mini_pending = 0; +} + +static u32 +qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) +{ + u32 num_desc; + num_desc = max(val, min); + num_desc = min(num_desc, max); + num_desc = roundup_pow_of_two(num_desc); + + if (val != num_desc) { + printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n", + qlcnic_driver_name, r_name, num_desc, val); + } + + return num_desc; +} + +static int +qlcnic_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G; + u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + u16 num_rxd, num_jumbo_rxd, num_txd; + + + if (ring->rx_mini_pending) + return -EOPNOTSUPP; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + max_rcv_desc = MAX_RCV_DESCRIPTORS_1G; + max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + num_rxd = qlcnic_validate_ringparam(ring->rx_pending, + MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx"); + + num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending, + MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo"); + + num_txd = qlcnic_validate_ringparam(ring->tx_pending, + MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx"); + + if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && + num_jumbo_rxd == adapter->num_jumbo_rxd) + return 0; + + adapter->num_rxd = num_rxd; + adapter->num_jumbo_rxd = num_jumbo_rxd; + adapter->num_txd = num_txd; + + return qlcnic_reset_context(adapter); +} + +static void +qlcnic_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int port = adapter->physical_port; + __u32 val; + + if (adapter->ahw.port_type == QLCNIC_GBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) + return; + /* get flow control settings */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + pause->rx_pause = qlcnic_gb_get_rx_flowctl(val); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + switch (port) { + case 0: + pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val)); + break; + case 1: + pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val)); + break; + case 2: + pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val)); + break; + case 3: + default: + pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); + break; + } + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) + return; + pause->rx_pause = 1; + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + if (port == 0) + pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val)); + else + pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); + } else { + dev_err(&netdev->dev, "Unknown board type: %x\n", + adapter->ahw.port_type); + } +} + +static int +qlcnic_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int port = adapter->physical_port; + __u32 val; + + /* read mode */ + if (adapter->ahw.port_type == QLCNIC_GBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) + return -EIO; + /* set flow control */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + + if (pause->rx_pause) + qlcnic_gb_rx_flowctl(val); + else + qlcnic_gb_unset_rx_flowctl(val); + + QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), + val); + /* set autoneg */ + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + switch (port) { + case 0: + if (pause->tx_pause) + qlcnic_gb_unset_gb0_mask(val); + else + qlcnic_gb_set_gb0_mask(val); + break; + case 1: + if (pause->tx_pause) + qlcnic_gb_unset_gb1_mask(val); + else + qlcnic_gb_set_gb1_mask(val); + break; + case 2: + if (pause->tx_pause) + qlcnic_gb_unset_gb2_mask(val); + else + qlcnic_gb_set_gb2_mask(val); + break; + case 3: + default: + if (pause->tx_pause) + qlcnic_gb_unset_gb3_mask(val); + else + qlcnic_gb_set_gb3_mask(val); + break; + } + QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); + } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) + return -EIO; + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + if (port == 0) { + if (pause->tx_pause) + qlcnic_xg_unset_xg0_mask(val); + else + qlcnic_xg_set_xg0_mask(val); + } else { + if (pause->tx_pause) + qlcnic_xg_unset_xg1_mask(val); + else + qlcnic_xg_set_xg1_mask(val); + } + QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); + } else { + dev_err(&netdev->dev, "Unknown board type: %x\n", + adapter->ahw.port_type); + } + return 0; +} + +static int qlcnic_reg_test(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 data_read, data_written; + + data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0)); + if ((data_read & 0xffff) != adapter->pdev->vendor) + return 1; + + data_written = (u32)0xa5a5a5a5; + + QLCWR32(adapter, CRB_SCRATCHPAD_TEST, data_written); + data_read = QLCRD32(adapter, CRB_SCRATCHPAD_TEST); + if (data_written != data_read) + return 1; + + return 0; +} + +static int qlcnic_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_TEST: + return QLCNIC_TEST_LEN; + case ETH_SS_STATS: + return QLCNIC_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void +qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, + u64 *data) +{ + memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + data[0] = qlcnic_reg_test(dev); + if (data[0]) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* link test */ + data[1] = (u64) qlcnic_test_link(dev); + if (data[1]) + eth_test->flags |= ETH_TEST_FL_FAILED; +} + +static void +qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) +{ + int index; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *qlcnic_gstrings_test, + QLCNIC_TEST_LEN * ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (index = 0; index < QLCNIC_STATS_LEN; index++) { + memcpy(data + index * ETH_GSTRING_LEN, + qlcnic_gstrings_stats[index].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +static void +qlcnic_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 * data) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int index; + + for (index = 0; index < QLCNIC_STATS_LEN; index++) { + char *p = + (char *)adapter + + qlcnic_gstrings_stats[index].stat_offset; + data[index] = + (qlcnic_gstrings_stats[index].sizeof_stat == + sizeof(u64)) ? *(u64 *)p:(*(u32 *)p); + } +} + +static u32 qlcnic_get_rx_csum(struct net_device *dev) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + return adapter->rx_csum; +} + +static int qlcnic_set_rx_csum(struct net_device *dev, u32 data) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + adapter->rx_csum = !!data; + return 0; +} + +static u32 qlcnic_get_tso(struct net_device *dev) +{ + return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; +} + +static int qlcnic_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return 0; +} + +static void +qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 wol_cfg; + + wol->supported = 0; + wol->wolopts = 0; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (wol_cfg & (1UL << adapter->portnum)) + wol->supported |= WAKE_MAGIC; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol_cfg & (1UL << adapter->portnum)) + wol->wolopts |= WAKE_MAGIC; +} + +static int +qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + u32 wol_cfg; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EOPNOTSUPP; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (!(wol_cfg & (1 << adapter->portnum))) + return -EOPNOTSUPP; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol->wolopts & WAKE_MAGIC) + wol_cfg |= 1UL << adapter->portnum; + else + wol_cfg &= ~(1UL << adapter->portnum); + + QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg); + + return 0; +} + +/* + * Set the coalescing parameters. Currently only normal is supported. + * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the + * firmware coalescing to default. + */ +static int qlcnic_set_intr_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EINVAL; + + /* + * Return Error if unsupported values or + * unsupported parameters are set. + */ + if (ethcoal->rx_coalesce_usecs > 0xffff || + ethcoal->rx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs > 0xffff || + ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->rx_coalesce_usecs_irq || + ethcoal->rx_max_coalesced_frames_irq || + ethcoal->tx_coalesce_usecs_irq || + ethcoal->tx_max_coalesced_frames_irq || + ethcoal->stats_block_coalesce_usecs || + ethcoal->use_adaptive_rx_coalesce || + ethcoal->use_adaptive_tx_coalesce || + ethcoal->pkt_rate_low || + ethcoal->rx_coalesce_usecs_low || + ethcoal->rx_max_coalesced_frames_low || + ethcoal->tx_coalesce_usecs_low || + ethcoal->tx_max_coalesced_frames_low || + ethcoal->pkt_rate_high || + ethcoal->rx_coalesce_usecs_high || + ethcoal->rx_max_coalesced_frames_high || + ethcoal->tx_coalesce_usecs_high || + ethcoal->tx_max_coalesced_frames_high) + return -EINVAL; + + if (!ethcoal->rx_coalesce_usecs || + !ethcoal->rx_max_coalesced_frames) { + adapter->coal.flags = QLCNIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; + } else { + adapter->coal.flags = 0; + adapter->coal.normal.data.rx_time_us = + ethcoal->rx_coalesce_usecs; + adapter->coal.normal.data.rx_packets = + ethcoal->rx_max_coalesced_frames; + } + adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; + adapter->coal.normal.data.tx_packets = + ethcoal->tx_max_coalesced_frames; + + qlcnic_config_intr_coalesce(adapter); + + return 0; +} + +static int qlcnic_get_intr_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EINVAL; + + ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; + ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; + ethcoal->rx_max_coalesced_frames = + adapter->coal.normal.data.rx_packets; + ethcoal->tx_max_coalesced_frames = + adapter->coal.normal.data.tx_packets; + + return 0; +} + +static int qlcnic_set_flags(struct net_device *netdev, u32 data) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int hw_lro; + + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + ethtool_op_set_flags(netdev, data); + + hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0; + + if (qlcnic_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) + return -EIO; + + + return 0; +} + +const struct ethtool_ops qlcnic_ethtool_ops = { + .get_settings = qlcnic_get_settings, + .set_settings = qlcnic_set_settings, + .get_drvinfo = qlcnic_get_drvinfo, + .get_regs_len = qlcnic_get_regs_len, + .get_regs = qlcnic_get_regs, + .get_link = ethtool_op_get_link, + .get_eeprom_len = qlcnic_get_eeprom_len, + .get_eeprom = qlcnic_get_eeprom, + .get_ringparam = qlcnic_get_ringparam, + .set_ringparam = qlcnic_set_ringparam, + .get_pauseparam = qlcnic_get_pauseparam, + .set_pauseparam = qlcnic_set_pauseparam, + .set_tx_csum = ethtool_op_set_tx_csum, + .set_sg = ethtool_op_set_sg, + .get_tso = qlcnic_get_tso, + .set_tso = qlcnic_set_tso, + .get_wol = qlcnic_get_wol, + .set_wol = qlcnic_set_wol, + .self_test = qlcnic_diag_test, + .get_strings = qlcnic_get_strings, + .get_ethtool_stats = qlcnic_get_ethtool_stats, + .get_sset_count = qlcnic_get_sset_count, + .get_rx_csum = qlcnic_get_rx_csum, + .set_rx_csum = qlcnic_set_rx_csum, + .get_coalesce = qlcnic_get_intr_coalesce, + .set_coalesce = qlcnic_set_intr_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = qlcnic_set_flags, +}; diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h new file mode 100644 index 000000000000..0469f84360a4 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -0,0 +1,937 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#ifndef __QLCNIC_HDR_H_ +#define __QLCNIC_HDR_H_ + +#include +#include + +/* + * The basic unit of access when reading/writing control registers. + */ + +enum { + QLCNIC_HW_H0_CH_HUB_ADR = 0x05, + QLCNIC_HW_H1_CH_HUB_ADR = 0x0E, + QLCNIC_HW_H2_CH_HUB_ADR = 0x03, + QLCNIC_HW_H3_CH_HUB_ADR = 0x01, + QLCNIC_HW_H4_CH_HUB_ADR = 0x06, + QLCNIC_HW_H5_CH_HUB_ADR = 0x07, + QLCNIC_HW_H6_CH_HUB_ADR = 0x08 +}; + +/* Hub 0 */ +enum { + QLCNIC_HW_MN_CRB_AGT_ADR = 0x15, + QLCNIC_HW_MS_CRB_AGT_ADR = 0x25 +}; + +/* Hub 1 */ +enum { + QLCNIC_HW_PS_CRB_AGT_ADR = 0x73, + QLCNIC_HW_SS_CRB_AGT_ADR = 0x20, + QLCNIC_HW_RPMX3_CRB_AGT_ADR = 0x0b, + QLCNIC_HW_QMS_CRB_AGT_ADR = 0x00, + QLCNIC_HW_SQGS0_CRB_AGT_ADR = 0x01, + QLCNIC_HW_SQGS1_CRB_AGT_ADR = 0x02, + QLCNIC_HW_SQGS2_CRB_AGT_ADR = 0x03, + QLCNIC_HW_SQGS3_CRB_AGT_ADR = 0x04, + QLCNIC_HW_C2C0_CRB_AGT_ADR = 0x58, + QLCNIC_HW_C2C1_CRB_AGT_ADR = 0x59, + QLCNIC_HW_C2C2_CRB_AGT_ADR = 0x5a, + QLCNIC_HW_RPMX2_CRB_AGT_ADR = 0x0a, + QLCNIC_HW_RPMX4_CRB_AGT_ADR = 0x0c, + QLCNIC_HW_RPMX7_CRB_AGT_ADR = 0x0f, + QLCNIC_HW_RPMX9_CRB_AGT_ADR = 0x12, + QLCNIC_HW_SMB_CRB_AGT_ADR = 0x18 +}; + +/* Hub 2 */ +enum { + QLCNIC_HW_NIU_CRB_AGT_ADR = 0x31, + QLCNIC_HW_I2C0_CRB_AGT_ADR = 0x19, + QLCNIC_HW_I2C1_CRB_AGT_ADR = 0x29, + + QLCNIC_HW_SN_CRB_AGT_ADR = 0x10, + QLCNIC_HW_I2Q_CRB_AGT_ADR = 0x20, + QLCNIC_HW_LPC_CRB_AGT_ADR = 0x22, + QLCNIC_HW_ROMUSB_CRB_AGT_ADR = 0x21, + QLCNIC_HW_QM_CRB_AGT_ADR = 0x66, + QLCNIC_HW_SQG0_CRB_AGT_ADR = 0x60, + QLCNIC_HW_SQG1_CRB_AGT_ADR = 0x61, + QLCNIC_HW_SQG2_CRB_AGT_ADR = 0x62, + QLCNIC_HW_SQG3_CRB_AGT_ADR = 0x63, + QLCNIC_HW_RPMX1_CRB_AGT_ADR = 0x09, + QLCNIC_HW_RPMX5_CRB_AGT_ADR = 0x0d, + QLCNIC_HW_RPMX6_CRB_AGT_ADR = 0x0e, + QLCNIC_HW_RPMX8_CRB_AGT_ADR = 0x11 +}; + +/* Hub 3 */ +enum { + QLCNIC_HW_PH_CRB_AGT_ADR = 0x1A, + QLCNIC_HW_SRE_CRB_AGT_ADR = 0x50, + QLCNIC_HW_EG_CRB_AGT_ADR = 0x51, + QLCNIC_HW_RPMX0_CRB_AGT_ADR = 0x08 +}; + +/* Hub 4 */ +enum { + QLCNIC_HW_PEGN0_CRB_AGT_ADR = 0x40, + QLCNIC_HW_PEGN1_CRB_AGT_ADR, + QLCNIC_HW_PEGN2_CRB_AGT_ADR, + QLCNIC_HW_PEGN3_CRB_AGT_ADR, + QLCNIC_HW_PEGNI_CRB_AGT_ADR, + QLCNIC_HW_PEGND_CRB_AGT_ADR, + QLCNIC_HW_PEGNC_CRB_AGT_ADR, + QLCNIC_HW_PEGR0_CRB_AGT_ADR, + QLCNIC_HW_PEGR1_CRB_AGT_ADR, + QLCNIC_HW_PEGR2_CRB_AGT_ADR, + QLCNIC_HW_PEGR3_CRB_AGT_ADR, + QLCNIC_HW_PEGN4_CRB_AGT_ADR +}; + +/* Hub 5 */ +enum { + QLCNIC_HW_PEGS0_CRB_AGT_ADR = 0x40, + QLCNIC_HW_PEGS1_CRB_AGT_ADR, + QLCNIC_HW_PEGS2_CRB_AGT_ADR, + QLCNIC_HW_PEGS3_CRB_AGT_ADR, + QLCNIC_HW_PEGSI_CRB_AGT_ADR, + QLCNIC_HW_PEGSD_CRB_AGT_ADR, + QLCNIC_HW_PEGSC_CRB_AGT_ADR +}; + +/* Hub 6 */ +enum { + QLCNIC_HW_CAS0_CRB_AGT_ADR = 0x46, + QLCNIC_HW_CAS1_CRB_AGT_ADR = 0x47, + QLCNIC_HW_CAS2_CRB_AGT_ADR = 0x48, + QLCNIC_HW_CAS3_CRB_AGT_ADR = 0x49, + QLCNIC_HW_NCM_CRB_AGT_ADR = 0x16, + QLCNIC_HW_TMR_CRB_AGT_ADR = 0x17, + QLCNIC_HW_XDMA_CRB_AGT_ADR = 0x05, + QLCNIC_HW_OCM0_CRB_AGT_ADR = 0x06, + QLCNIC_HW_OCM1_CRB_AGT_ADR = 0x07 +}; + +/* Floaters - non existent modules */ +#define QLCNIC_HW_EFC_RPMX0_CRB_AGT_ADR 0x67 + +/* This field defines PCI/X adr [25:20] of agents on the CRB */ +enum { + QLCNIC_HW_PX_MAP_CRB_PH = 0, + QLCNIC_HW_PX_MAP_CRB_PS, + QLCNIC_HW_PX_MAP_CRB_MN, + QLCNIC_HW_PX_MAP_CRB_MS, + QLCNIC_HW_PX_MAP_CRB_PGR1, + QLCNIC_HW_PX_MAP_CRB_SRE, + QLCNIC_HW_PX_MAP_CRB_NIU, + QLCNIC_HW_PX_MAP_CRB_QMN, + QLCNIC_HW_PX_MAP_CRB_SQN0, + QLCNIC_HW_PX_MAP_CRB_SQN1, + QLCNIC_HW_PX_MAP_CRB_SQN2, + QLCNIC_HW_PX_MAP_CRB_SQN3, + QLCNIC_HW_PX_MAP_CRB_QMS, + QLCNIC_HW_PX_MAP_CRB_SQS0, + QLCNIC_HW_PX_MAP_CRB_SQS1, + QLCNIC_HW_PX_MAP_CRB_SQS2, + QLCNIC_HW_PX_MAP_CRB_SQS3, + QLCNIC_HW_PX_MAP_CRB_PGN0, + QLCNIC_HW_PX_MAP_CRB_PGN1, + QLCNIC_HW_PX_MAP_CRB_PGN2, + QLCNIC_HW_PX_MAP_CRB_PGN3, + QLCNIC_HW_PX_MAP_CRB_PGND, + QLCNIC_HW_PX_MAP_CRB_PGNI, + QLCNIC_HW_PX_MAP_CRB_PGS0, + QLCNIC_HW_PX_MAP_CRB_PGS1, + QLCNIC_HW_PX_MAP_CRB_PGS2, + QLCNIC_HW_PX_MAP_CRB_PGS3, + QLCNIC_HW_PX_MAP_CRB_PGSD, + QLCNIC_HW_PX_MAP_CRB_PGSI, + QLCNIC_HW_PX_MAP_CRB_SN, + QLCNIC_HW_PX_MAP_CRB_PGR2, + QLCNIC_HW_PX_MAP_CRB_EG, + QLCNIC_HW_PX_MAP_CRB_PH2, + QLCNIC_HW_PX_MAP_CRB_PS2, + QLCNIC_HW_PX_MAP_CRB_CAM, + QLCNIC_HW_PX_MAP_CRB_CAS0, + QLCNIC_HW_PX_MAP_CRB_CAS1, + QLCNIC_HW_PX_MAP_CRB_CAS2, + QLCNIC_HW_PX_MAP_CRB_C2C0, + QLCNIC_HW_PX_MAP_CRB_C2C1, + QLCNIC_HW_PX_MAP_CRB_TIMR, + QLCNIC_HW_PX_MAP_CRB_PGR3, + QLCNIC_HW_PX_MAP_CRB_RPMX1, + QLCNIC_HW_PX_MAP_CRB_RPMX2, + QLCNIC_HW_PX_MAP_CRB_RPMX3, + QLCNIC_HW_PX_MAP_CRB_RPMX4, + QLCNIC_HW_PX_MAP_CRB_RPMX5, + QLCNIC_HW_PX_MAP_CRB_RPMX6, + QLCNIC_HW_PX_MAP_CRB_RPMX7, + QLCNIC_HW_PX_MAP_CRB_XDMA, + QLCNIC_HW_PX_MAP_CRB_I2Q, + QLCNIC_HW_PX_MAP_CRB_ROMUSB, + QLCNIC_HW_PX_MAP_CRB_CAS3, + QLCNIC_HW_PX_MAP_CRB_RPMX0, + QLCNIC_HW_PX_MAP_CRB_RPMX8, + QLCNIC_HW_PX_MAP_CRB_RPMX9, + QLCNIC_HW_PX_MAP_CRB_OCM0, + QLCNIC_HW_PX_MAP_CRB_OCM1, + QLCNIC_HW_PX_MAP_CRB_SMB, + QLCNIC_HW_PX_MAP_CRB_I2C0, + QLCNIC_HW_PX_MAP_CRB_I2C1, + QLCNIC_HW_PX_MAP_CRB_LPC, + QLCNIC_HW_PX_MAP_CRB_PGNC, + QLCNIC_HW_PX_MAP_CRB_PGR0 +}; + +/* This field defines CRB adr [31:20] of the agents */ + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MN_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PH \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_PH_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_MS \ + ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MS_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_PS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMS \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_QMS_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS0 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS1 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS2 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS3 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C0 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C1 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX4_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX7_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9 \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX9_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SMB \ + ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SMB_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_NIU \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_NIU_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0 \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1 \ + ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C1_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SRE \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SRE_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_EG \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_EG_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMN \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_QM_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX5_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX6_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX8_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS0 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS1 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS2 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS3 \ + ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS3_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNI_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGND \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGND_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN4_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNC_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR0 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR1 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR2 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR3 \ + ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR3_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSI_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSD \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSD_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS2_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3 \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS3_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSC \ + ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSC_CRB_AGT_ADR) + +#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAM \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_NCM_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_TMR_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_XDMA_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_SN \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_SN_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_I2Q_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_ROMUSB_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0 \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM0_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM1 \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM1_CRB_AGT_ADR) +#define QLCNIC_HW_CRB_HUB_AGT_ADR_LPC \ + ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_LPC_CRB_AGT_ADR) + +#define QLCNIC_SRE_MISC (QLCNIC_CRB_SRE + 0x0002c) + +#define QLCNIC_I2Q_CLR_PCI_HI (QLCNIC_CRB_I2Q + 0x00034) + +#define ROMUSB_GLB (QLCNIC_CRB_ROMUSB + 0x00000) +#define ROMUSB_ROM (QLCNIC_CRB_ROMUSB + 0x10000) + +#define QLCNIC_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004) +#define QLCNIC_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008) +#define QLCNIC_ROMUSB_GLB_PAD_GPIO_I (ROMUSB_GLB + 0x000c) +#define QLCNIC_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038) +#define QLCNIC_ROMUSB_GLB_TEST_MUX_SEL (ROMUSB_GLB + 0x0044) +#define QLCNIC_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c) +#define QLCNIC_ROMUSB_GLB_CHIP_CLK_CTRL (ROMUSB_GLB + 0x00A8) + +#define QLCNIC_ROMUSB_GPIO(n) (ROMUSB_GLB + 0x60 + (4 * (n))) + +#define QLCNIC_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004) +#define QLCNIC_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008) +#define QLCNIC_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c) +#define QLCNIC_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010) +#define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014) +#define QLCNIC_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018) + +/* Lock IDs for ROM lock */ +#define ROM_LOCK_DRIVER 0x0d417340 + +/****************************************************************************** +* +* Definitions specific to M25P flash +* +******************************************************************************* +*/ + +/* all are 1MB windows */ + +#define QLCNIC_PCI_CRB_WINDOWSIZE 0x00100000 +#define QLCNIC_PCI_CRB_WINDOW(A) \ + (QLCNIC_PCI_CRBSPACE + (A)*QLCNIC_PCI_CRB_WINDOWSIZE) + +#define QLCNIC_CRB_NIU QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_NIU) +#define QLCNIC_CRB_SRE QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SRE) +#define QLCNIC_CRB_ROMUSB \ + QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_ROMUSB) +#define QLCNIC_CRB_I2Q QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2Q) +#define QLCNIC_CRB_I2C0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2C0) +#define QLCNIC_CRB_SMB QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SMB) +#define QLCNIC_CRB_MAX QLCNIC_PCI_CRB_WINDOW(64) + +#define QLCNIC_CRB_PCIX_HOST QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH) +#define QLCNIC_CRB_PCIX_HOST2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH2) +#define QLCNIC_CRB_PEG_NET_0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN0) +#define QLCNIC_CRB_PEG_NET_1 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN1) +#define QLCNIC_CRB_PEG_NET_2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN2) +#define QLCNIC_CRB_PEG_NET_3 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN3) +#define QLCNIC_CRB_PEG_NET_4 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SQS2) +#define QLCNIC_CRB_PEG_NET_D QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGND) +#define QLCNIC_CRB_PEG_NET_I QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGNI) +#define QLCNIC_CRB_DDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_MN) +#define QLCNIC_CRB_QDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SN) + +#define QLCNIC_CRB_PCIX_MD QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PS) +#define QLCNIC_CRB_PCIE QLCNIC_CRB_PCIX_MD + +#define ISR_INT_VECTOR (QLCNIC_PCIX_PS_REG(PCIX_INT_VECTOR)) +#define ISR_INT_MASK (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_MASK_SLOW (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_TARGET_STATUS (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS)) +#define ISR_INT_TARGET_MASK (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK)) +#define ISR_INT_TARGET_STATUS_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) +#define ISR_INT_TARGET_MASK_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) +#define ISR_INT_TARGET_STATUS_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) +#define ISR_INT_TARGET_MASK_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) +#define ISR_INT_TARGET_STATUS_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) +#define ISR_INT_TARGET_MASK_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) +#define ISR_INT_TARGET_STATUS_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) +#define ISR_INT_TARGET_MASK_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) +#define ISR_INT_TARGET_STATUS_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) +#define ISR_INT_TARGET_MASK_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) +#define ISR_INT_TARGET_STATUS_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) +#define ISR_INT_TARGET_MASK_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) +#define ISR_INT_TARGET_STATUS_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) +#define ISR_INT_TARGET_MASK_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) + +#define QLCNIC_PCI_MN_2M (0) +#define QLCNIC_PCI_MS_2M (0x80000) +#define QLCNIC_PCI_OCM0_2M (0x000c0000UL) +#define QLCNIC_PCI_CRBSPACE (0x06000000UL) +#define QLCNIC_PCI_2MB_SIZE (0x00200000UL) +#define QLCNIC_PCI_CAMQM_2M_BASE (0x000ff800UL) +#define QLCNIC_PCI_CAMQM_2M_END (0x04800800UL) + +#define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM) + +#define QLCNIC_ADDR_DDR_NET (0x0000000000000000ULL) +#define QLCNIC_ADDR_DDR_NET_MAX (0x000000000fffffffULL) +#define QLCNIC_ADDR_OCM0 (0x0000000200000000ULL) +#define QLCNIC_ADDR_OCM0_MAX (0x00000002000fffffULL) +#define QLCNIC_ADDR_OCM1 (0x0000000200400000ULL) +#define QLCNIC_ADDR_OCM1_MAX (0x00000002004fffffULL) +#define QLCNIC_ADDR_QDR_NET (0x0000000300000000ULL) +#define QLCNIC_ADDR_QDR_NET_MAX_P3 (0x0000000303ffffffULL) + +/* + * Register offsets for MN + */ +#define QLCNIC_MIU_CONTROL (0x000) +#define QLCNIC_MIU_MN_CONTROL (QLCNIC_CRB_DDR_NET+QLCNIC_MIU_CONTROL) + +/* 200ms delay in each loop */ +#define QLCNIC_NIU_PHY_WAITLEN 200000 +/* 10 seconds before we give up */ +#define QLCNIC_NIU_PHY_WAITMAX 50 +#define QLCNIC_NIU_MAX_GBE_PORTS 4 +#define QLCNIC_NIU_MAX_XG_PORTS 2 + +#define QLCNIC_NIU_MODE (QLCNIC_CRB_NIU + 0x00000) +#define QLCNIC_NIU_GB_PAUSE_CTL (QLCNIC_CRB_NIU + 0x0030c) +#define QLCNIC_NIU_XG_PAUSE_CTL (QLCNIC_CRB_NIU + 0x00098) + +#define QLCNIC_NIU_GB_MAC_CONFIG_0(I) \ + (QLCNIC_CRB_NIU + 0x30000 + (I)*0x10000) +#define QLCNIC_NIU_GB_MAC_CONFIG_1(I) \ + (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000) + + +#define TEST_AGT_CTRL (0x00) + +#define TA_CTL_START 1 +#define TA_CTL_ENABLE 2 +#define TA_CTL_WRITE 4 +#define TA_CTL_BUSY 8 + +/* + * Register offsets for MN + */ +#define MIU_TEST_AGT_BASE (0x90) + +#define MIU_TEST_AGT_ADDR_LO (0x04) +#define MIU_TEST_AGT_ADDR_HI (0x08) +#define MIU_TEST_AGT_WRDATA_LO (0x10) +#define MIU_TEST_AGT_WRDATA_HI (0x14) +#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x20) +#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x24) +#define MIU_TEST_AGT_WRDATA(i) (0x10+(0x10*((i)>>1))+(4*((i)&1))) +#define MIU_TEST_AGT_RDDATA_LO (0x18) +#define MIU_TEST_AGT_RDDATA_HI (0x1c) +#define MIU_TEST_AGT_RDDATA_UPPER_LO (0x28) +#define MIU_TEST_AGT_RDDATA_UPPER_HI (0x2c) +#define MIU_TEST_AGT_RDDATA(i) (0x18+(0x10*((i)>>1))+(4*((i)&1))) + +#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8 +#define MIU_TEST_AGT_UPPER_ADDR(off) (0) + +/* + * Register offsets for MS + */ +#define SIU_TEST_AGT_BASE (0x60) + +#define SIU_TEST_AGT_ADDR_LO (0x04) +#define SIU_TEST_AGT_ADDR_HI (0x18) +#define SIU_TEST_AGT_WRDATA_LO (0x08) +#define SIU_TEST_AGT_WRDATA_HI (0x0c) +#define SIU_TEST_AGT_WRDATA(i) (0x08+(4*(i))) +#define SIU_TEST_AGT_RDDATA_LO (0x10) +#define SIU_TEST_AGT_RDDATA_HI (0x14) +#define SIU_TEST_AGT_RDDATA(i) (0x10+(4*(i))) + +#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8 +#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22) + +/* XG Link status */ +#define XG_LINK_UP 0x10 +#define XG_LINK_DOWN 0x20 + +#define XG_LINK_UP_P3 0x01 +#define XG_LINK_DOWN_P3 0x02 +#define XG_LINK_STATE_P3_MASK 0xf +#define XG_LINK_STATE_P3(pcifn, val) \ + (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3_MASK) + +#define P3_LINK_SPEED_MHZ 100 +#define P3_LINK_SPEED_MASK 0xff +#define P3_LINK_SPEED_REG(pcifn) \ + (CRB_PF_LINK_SPEED_1 + (((pcifn) / 4) * 4)) +#define P3_LINK_SPEED_VAL(pcifn, reg) \ + (((reg) >> (8 * ((pcifn) & 0x3))) & P3_LINK_SPEED_MASK) + +#define QLCNIC_CAM_RAM_BASE (QLCNIC_CRB_CAM + 0x02000) +#define QLCNIC_CAM_RAM(reg) (QLCNIC_CAM_RAM_BASE + (reg)) +#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150)) +#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154)) +#define QLCNIC_FW_VERSION_SUB (QLCNIC_CAM_RAM(0x158)) +#define QLCNIC_ROM_LOCK_ID (QLCNIC_CAM_RAM(0x100)) +#define QLCNIC_PHY_LOCK_ID (QLCNIC_CAM_RAM(0x120)) +#define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124)) + +#define NIC_CRB_BASE (QLCNIC_CAM_RAM(0x200)) +#define NIC_CRB_BASE_2 (QLCNIC_CAM_RAM(0x700)) +#define QLCNIC_REG(X) (NIC_CRB_BASE+(X)) +#define QLCNIC_REG_2(X) (NIC_CRB_BASE_2+(X)) + +#define QLCNIC_CDRP_CRB_OFFSET (QLCNIC_REG(0x18)) +#define QLCNIC_ARG1_CRB_OFFSET (QLCNIC_REG(0x1c)) +#define QLCNIC_ARG2_CRB_OFFSET (QLCNIC_REG(0x20)) +#define QLCNIC_ARG3_CRB_OFFSET (QLCNIC_REG(0x24)) +#define QLCNIC_SIGN_CRB_OFFSET (QLCNIC_REG(0x28)) + +#define CRB_CMDPEG_STATE (QLCNIC_REG(0x50)) +#define CRB_RCVPEG_STATE (QLCNIC_REG(0x13c)) + +#define CRB_XG_STATE_P3 (QLCNIC_REG(0x98)) +#define CRB_PF_LINK_SPEED_1 (QLCNIC_REG(0xe8)) +#define CRB_PF_LINK_SPEED_2 (QLCNIC_REG(0xec)) + +#define CRB_MPORT_MODE (QLCNIC_REG(0xc4)) +#define CRB_DMA_SHIFT (QLCNIC_REG(0xcc)) + +#define CRB_TEMP_STATE (QLCNIC_REG(0x1b4)) + +#define CRB_V2P_0 (QLCNIC_REG(0x290)) +#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) +#define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0)) + +#define CRB_SW_INT_MASK_0 (QLCNIC_REG(0x1d8)) +#define CRB_SW_INT_MASK_1 (QLCNIC_REG(0x1e0)) +#define CRB_SW_INT_MASK_2 (QLCNIC_REG(0x1e4)) +#define CRB_SW_INT_MASK_3 (QLCNIC_REG(0x1e8)) + +#define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128)) +#define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0)) + +/* + * capabilities register, can be used to selectively enable/disable features + * for backward compability + */ +#define CRB_NIC_CAPABILITIES_HOST QLCNIC_REG(0x1a8) +#define CRB_NIC_CAPABILITIES_FW QLCNIC_REG(0x1dc) +#define CRB_NIC_MSI_MODE_HOST QLCNIC_REG(0x270) +#define CRB_NIC_MSI_MODE_FW QLCNIC_REG(0x274) + +#define INTR_SCHEME_PERPORT 0x1 +#define MSI_MODE_MULTIFUNC 0x1 + +/* used for ethtool tests */ +#define CRB_SCRATCHPAD_TEST QLCNIC_REG(0x280) + +/* + * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address + * which can be read by the Phantom host to get producer/consumer indexes from + * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following + * registers will be used for the addresses of the ring's shared memory + * on the Phantom. + */ + +#define qlcnic_get_temp_val(x) ((x) >> 16) +#define qlcnic_get_temp_state(x) ((x) & 0xffff) +#define qlcnic_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + QLCNIC_TEMP_NORMAL = 0x1, /* Normal operating range */ + QLCNIC_TEMP_WARN, /* Sound alert, temperature getting high */ + QLCNIC_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; + +/* Lock IDs for PHY lock */ +#define PHY_LOCK_DRIVER 0x44524956 + +/* Used for PS PCI Memory access */ +#define PCIX_PS_OP_ADDR_LO (0x10000) +/* via CRB (PS side only) */ +#define PCIX_PS_OP_ADDR_HI (0x10004) + +#define PCIX_INT_VECTOR (0x10100) +#define PCIX_INT_MASK (0x10104) + +#define PCIX_OCM_WINDOW (0x10800) +#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x20 * (func)) + +#define PCIX_TARGET_STATUS (0x10118) +#define PCIX_TARGET_STATUS_F1 (0x10160) +#define PCIX_TARGET_STATUS_F2 (0x10164) +#define PCIX_TARGET_STATUS_F3 (0x10168) +#define PCIX_TARGET_STATUS_F4 (0x10360) +#define PCIX_TARGET_STATUS_F5 (0x10364) +#define PCIX_TARGET_STATUS_F6 (0x10368) +#define PCIX_TARGET_STATUS_F7 (0x1036c) + +#define PCIX_TARGET_MASK (0x10128) +#define PCIX_TARGET_MASK_F1 (0x10170) +#define PCIX_TARGET_MASK_F2 (0x10174) +#define PCIX_TARGET_MASK_F3 (0x10178) +#define PCIX_TARGET_MASK_F4 (0x10370) +#define PCIX_TARGET_MASK_F5 (0x10374) +#define PCIX_TARGET_MASK_F6 (0x10378) +#define PCIX_TARGET_MASK_F7 (0x1037c) + +#define PCIX_MSI_F(i) (0x13000+((i)*4)) + +#define QLCNIC_PCIX_PH_REG(reg) (QLCNIC_CRB_PCIE + (reg)) +#define QLCNIC_PCIX_PS_REG(reg) (QLCNIC_CRB_PCIX_MD + (reg)) +#define QLCNIC_PCIE_REG(reg) (QLCNIC_CRB_PCIE + (reg)) + +#define PCIE_SEM0_LOCK (0x1c000) +#define PCIE_SEM0_UNLOCK (0x1c004) +#define PCIE_SEM_LOCK(N) (PCIE_SEM0_LOCK + 8*(N)) +#define PCIE_SEM_UNLOCK(N) (PCIE_SEM0_UNLOCK + 8*(N)) + +#define PCIE_SETUP_FUNCTION (0x12040) +#define PCIE_SETUP_FUNCTION2 (0x12048) +#define PCIE_MISCCFG_RC (0x1206c) +#define PCIE_TGT_SPLIT_CHICKEN (0x12080) +#define PCIE_CHICKEN3 (0x120c8) + +#define ISR_INT_STATE_REG (QLCNIC_PCIX_PS_REG(PCIE_MISCCFG_RC)) +#define PCIE_MAX_MASTER_SPLIT (0x14048) + +#define QLCNIC_PORT_MODE_NONE 0 +#define QLCNIC_PORT_MODE_XG 1 +#define QLCNIC_PORT_MODE_GB 2 +#define QLCNIC_PORT_MODE_802_3_AP 3 +#define QLCNIC_PORT_MODE_AUTO_NEG 4 +#define QLCNIC_PORT_MODE_AUTO_NEG_1G 5 +#define QLCNIC_PORT_MODE_AUTO_NEG_XG 6 +#define QLCNIC_PORT_MODE_ADDR (QLCNIC_CAM_RAM(0x24)) +#define QLCNIC_WOL_PORT_MODE (QLCNIC_CAM_RAM(0x198)) + +#define QLCNIC_WOL_CONFIG_NV (QLCNIC_CAM_RAM(0x184)) +#define QLCNIC_WOL_CONFIG (QLCNIC_CAM_RAM(0x188)) + +#define QLCNIC_PEG_TUNE_MN_PRESENT 0x1 +#define QLCNIC_PEG_TUNE_CAPABILITY (QLCNIC_CAM_RAM(0x02c)) + +#define QLCNIC_DMA_WATCHDOG_CTRL (QLCNIC_CAM_RAM(0x14)) +#define QLCNIC_PEG_ALIVE_COUNTER (QLCNIC_CAM_RAM(0xb0)) +#define QLCNIC_PEG_HALT_STATUS1 (QLCNIC_CAM_RAM(0xa8)) +#define QLCNIC_PEG_HALT_STATUS2 (QLCNIC_CAM_RAM(0xac)) +#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138)) +#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140)) + +#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144)) +#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148)) +#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c)) +#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x14c)) + + /* Device State */ +#define QLCNIC_DEV_COLD 1 +#define QLCNIC_DEV_INITALIZING 2 +#define QLCNIC_DEV_READY 3 +#define QLCNIC_DEV_NEED_RESET 4 +#define QLCNIC_DEV_NEED_QUISCENT 5 +#define QLCNIC_DEV_FAILED 6 + +#define QLCNIC_RCODE_DRIVER_INFO 0x20000000 +#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000 +#define QLCNIC_RCODE_FATAL_ERROR 0x80000000 +#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff) +#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff) + +#define FW_POLL_DELAY (2 * HZ) +#define FW_FAIL_THRESH 3 +#define FW_POLL_THRESH 10 + +#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC))) +#define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) + +/* + * PCI Interrupt Vector Values. + */ +#define PCIX_INT_VECTOR_BIT_F0 0x0080 +#define PCIX_INT_VECTOR_BIT_F1 0x0100 +#define PCIX_INT_VECTOR_BIT_F2 0x0200 +#define PCIX_INT_VECTOR_BIT_F3 0x0400 +#define PCIX_INT_VECTOR_BIT_F4 0x0800 +#define PCIX_INT_VECTOR_BIT_F5 0x1000 +#define PCIX_INT_VECTOR_BIT_F6 0x2000 +#define PCIX_INT_VECTOR_BIT_F7 0x4000 + +struct qlcnic_legacy_intr_set { + u32 int_vec_bit; + u32 tgt_status_reg; + u32 tgt_mask_reg; + u32 pci_int_reg; +}; + +#define QLCNIC_LEGACY_INTR_CONFIG \ +{ \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ +} + +/* NIU REGS */ + +#define _qlcnic_crb_get_bit(var, bit) ((var >> bit) & 0x1) + +/* + * NIU GB MAC Config Register 0 (applies to GB0, GB1, GB2, GB3) + * + * Bit 0 : enable_tx => 1:enable frame xmit, 0:disable + * Bit 1 : tx_synced => R/O: xmit enable synched to xmit stream + * Bit 2 : enable_rx => 1:enable frame recv, 0:disable + * Bit 3 : rx_synced => R/O: recv enable synched to recv stream + * Bit 4 : tx_flowctl => 1:enable pause frame generation, 0:disable + * Bit 5 : rx_flowctl => 1:act on recv'd pause frames, 0:ignore + * Bit 8 : loopback => 1:loop MAC xmits to MAC recvs, 0:normal + * Bit 16: tx_reset_pb => 1:reset frame xmit protocol blk, 0:no-op + * Bit 17: rx_reset_pb => 1:reset frame recv protocol blk, 0:no-op + * Bit 18: tx_reset_mac => 1:reset data/ctl multiplexer blk, 0:no-op + * Bit 19: rx_reset_mac => 1:reset ctl frames & timers blk, 0:no-op + * Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op + */ +#define qlcnic_gb_rx_flowctl(config_word) \ + ((config_word) |= 1 << 5) +#define qlcnic_gb_get_rx_flowctl(config_word) \ + _qlcnic_crb_get_bit((config_word), 5) +#define qlcnic_gb_unset_rx_flowctl(config_word) \ + ((config_word) &= ~(1 << 5)) + +/* + * NIU GB Pause Ctl Register + */ + +#define qlcnic_gb_set_gb0_mask(config_word) \ + ((config_word) |= 1 << 0) +#define qlcnic_gb_set_gb1_mask(config_word) \ + ((config_word) |= 1 << 2) +#define qlcnic_gb_set_gb2_mask(config_word) \ + ((config_word) |= 1 << 4) +#define qlcnic_gb_set_gb3_mask(config_word) \ + ((config_word) |= 1 << 6) + +#define qlcnic_gb_get_gb0_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 0) +#define qlcnic_gb_get_gb1_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 2) +#define qlcnic_gb_get_gb2_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 4) +#define qlcnic_gb_get_gb3_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 6) + +#define qlcnic_gb_unset_gb0_mask(config_word) \ + ((config_word) &= ~(1 << 0)) +#define qlcnic_gb_unset_gb1_mask(config_word) \ + ((config_word) &= ~(1 << 2)) +#define qlcnic_gb_unset_gb2_mask(config_word) \ + ((config_word) &= ~(1 << 4)) +#define qlcnic_gb_unset_gb3_mask(config_word) \ + ((config_word) &= ~(1 << 6)) + +/* + * NIU XG Pause Ctl Register + * + * Bit 0 : xg0_mask => 1:disable tx pause frames + * Bit 1 : xg0_request => 1:request single pause frame + * Bit 2 : xg0_on_off => 1:request is pause on, 0:off + * Bit 3 : xg1_mask => 1:disable tx pause frames + * Bit 4 : xg1_request => 1:request single pause frame + * Bit 5 : xg1_on_off => 1:request is pause on, 0:off + */ + +#define qlcnic_xg_set_xg0_mask(config_word) \ + ((config_word) |= 1 << 0) +#define qlcnic_xg_set_xg1_mask(config_word) \ + ((config_word) |= 1 << 3) + +#define qlcnic_xg_get_xg0_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 0) +#define qlcnic_xg_get_xg1_mask(config_word) \ + _qlcnic_crb_get_bit((config_word), 3) + +#define qlcnic_xg_unset_xg0_mask(config_word) \ + ((config_word) &= ~(1 << 0)) +#define qlcnic_xg_unset_xg1_mask(config_word) \ + ((config_word) &= ~(1 << 3)) + +/* + * NIU XG Pause Ctl Register + * + * Bit 0 : xg0_mask => 1:disable tx pause frames + * Bit 1 : xg0_request => 1:request single pause frame + * Bit 2 : xg0_on_off => 1:request is pause on, 0:off + * Bit 3 : xg1_mask => 1:disable tx pause frames + * Bit 4 : xg1_request => 1:request single pause frame + * Bit 5 : xg1_on_off => 1:request is pause on, 0:off + */ + +/* + * PHY-Specific MII control/status registers. + */ +#define QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG 4 +#define QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17 + +/* + * PHY-Specific Status Register (reg 17). + * + * Bit 0 : jabber => 1:jabber detected, 0:not + * Bit 1 : polarity => 1:polarity reversed, 0:normal + * Bit 2 : recvpause => 1:receive pause enabled, 0:disabled + * Bit 3 : xmitpause => 1:transmit pause enabled, 0:disabled + * Bit 4 : energydetect => 1:sleep, 0:active + * Bit 5 : downshift => 1:downshift, 0:no downshift + * Bit 6 : crossover => 1:MDIX (crossover), 0:MDI (no crossover) + * Bits 7-9 : cablelen => not valid in 10Mb/s mode + * 0:<50m, 1:50-80m, 2:80-110m, 3:110-140m, 4:>140m + * Bit 10 : link => 1:link up, 0:link down + * Bit 11 : resolved => 1:speed and duplex resolved, 0:not yet + * Bit 12 : pagercvd => 1:page received, 0:page not received + * Bit 13 : duplex => 1:full duplex, 0:half duplex + * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd + */ + +#define qlcnic_get_phy_speed(config_word) (((config_word) >> 14) & 0x03) + +#define qlcnic_set_phy_speed(config_word, val) \ + ((config_word) |= ((val & 0x03) << 14)) +#define qlcnic_set_phy_duplex(config_word) \ + ((config_word) |= 1 << 13) +#define qlcnic_clear_phy_duplex(config_word) \ + ((config_word) &= ~(1 << 13)) + +#define qlcnic_get_phy_link(config_word) \ + _qlcnic_crb_get_bit(config_word, 10) +#define qlcnic_get_phy_duplex(config_word) \ + _qlcnic_crb_get_bit(config_word, 13) + +#define QLCNIC_NIU_NON_PROMISC_MODE 0 +#define QLCNIC_NIU_PROMISC_MODE 1 +#define QLCNIC_NIU_ALLMULTI_MODE 2 + +struct crb_128M_2M_sub_block_map { + unsigned valid; + unsigned start_128M; + unsigned end_128M; + unsigned start_2M; +}; + +struct crb_128M_2M_block_map{ + struct crb_128M_2M_sub_block_map sub_block[16]; +}; +#endif /* __QLCNIC_HDR_H_ */ diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c new file mode 100644 index 000000000000..91234e7b39e4 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -0,0 +1,1201 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include "qlcnic.h" + +#include + +#define MASK(n) ((1ULL<<(n))-1) +#define OCM_WIN_P3P(addr) (addr & 0xffc0000) + +#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) + +#define CRB_BLK(off) ((off >> 20) & 0x3f) +#define CRB_SUBBLK(off) ((off >> 16) & 0xf) +#define CRB_WINDOW_2M (0x130060) +#define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000)) +#define CRB_INDIRECT_2M (0x1e0000UL) + + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val)), (addr)); + writel(((u32) (val >> 32)), (addr + 4)); +} +#endif + +#define ADDR_IN_RANGE(addr, low, high) \ + (((addr) < (high)) && ((addr) >= (low))) + +#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base0 + (off)) + +static void __iomem *pci_base_offset(struct qlcnic_adapter *adapter, + unsigned long off) +{ + if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END)) + return PCI_OFFSET_FIRST_RANGE(adapter, off); + + return NULL; +} + +static const struct crb_128M_2M_block_map +crb_128M_2M_map[64] __cacheline_aligned_in_smp = { + {{{0, 0, 0, 0} } }, /* 0: PCI */ + {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ + {1, 0x0110000, 0x0120000, 0x130000}, + {1, 0x0120000, 0x0122000, 0x124000}, + {1, 0x0130000, 0x0132000, 0x126000}, + {1, 0x0140000, 0x0142000, 0x128000}, + {1, 0x0150000, 0x0152000, 0x12a000}, + {1, 0x0160000, 0x0170000, 0x110000}, + {1, 0x0170000, 0x0172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x01e0000, 0x01e0800, 0x122000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */ + {{{0, 0, 0, 0} } }, /* 3: */ + {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */ + {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */ + {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */ + {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */ + {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x08f0000, 0x08f2000, 0x172000} } }, + {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x09f0000, 0x09f2000, 0x176000} } }, + {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0af0000, 0x0af2000, 0x17a000} } }, + {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, + {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */ + {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */ + {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */ + {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */ + {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */ + {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */ + {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */ + {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */ + {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */ + {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */ + {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */ + {{{0, 0, 0, 0} } }, /* 23: */ + {{{0, 0, 0, 0} } }, /* 24: */ + {{{0, 0, 0, 0} } }, /* 25: */ + {{{0, 0, 0, 0} } }, /* 26: */ + {{{0, 0, 0, 0} } }, /* 27: */ + {{{0, 0, 0, 0} } }, /* 28: */ + {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */ + {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */ + {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */ + {{{0} } }, /* 32: PCI */ + {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */ + {1, 0x2110000, 0x2120000, 0x130000}, + {1, 0x2120000, 0x2122000, 0x124000}, + {1, 0x2130000, 0x2132000, 0x126000}, + {1, 0x2140000, 0x2142000, 0x128000}, + {1, 0x2150000, 0x2152000, 0x12a000}, + {1, 0x2160000, 0x2170000, 0x110000}, + {1, 0x2170000, 0x2172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */ + {{{0} } }, /* 35: */ + {{{0} } }, /* 36: */ + {{{0} } }, /* 37: */ + {{{0} } }, /* 38: */ + {{{0} } }, /* 39: */ + {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */ + {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */ + {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */ + {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */ + {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */ + {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */ + {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */ + {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */ + {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */ + {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */ + {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */ + {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */ + {{{0} } }, /* 52: */ + {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */ + {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */ + {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */ + {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */ + {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */ + {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */ + {{{0} } }, /* 59: I2C0 */ + {{{0} } }, /* 60: I2C1 */ + {{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */ + {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */ + {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */ +}; + +/* + * top 12 bits of crb internal address (hub, agent) + */ +static const unsigned crb_hub_agt[64] = { + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PS, + QLCNIC_HW_CRB_HUB_AGT_ADR_MN, + QLCNIC_HW_CRB_HUB_AGT_ADR_MS, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SRE, + QLCNIC_HW_CRB_HUB_AGT_ADR_NIU, + QLCNIC_HW_CRB_HUB_AGT_ADR_QMN, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2, + QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, + QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, + QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4, + QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGND, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI, + QLCNIC_HW_CRB_HUB_AGT_ADR_SN, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_EG, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PS, + QLCNIC_HW_CRB_HUB_AGT_ADR_CAM, + 0, + 0, + 0, + 0, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7, + QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, + QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8, + QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9, + QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_SMB, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0, + QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1, + 0, + QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC, + 0, +}; + +/* PCI Windowing for DDR regions. */ + +#define QLCNIC_PCIE_SEM_TIMEOUT 10000 + +int +qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) +{ + int done = 0, timeout = 0; + + while (!done) { + done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem))); + if (done == 1) + break; + if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) + return -EIO; + msleep(1); + } + + if (id_reg) + QLCWR32(adapter, id_reg, adapter->portnum); + + return 0; +} + +void +qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem) +{ + QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem))); +} + +static int +qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, + struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) +{ + u32 i, producer, consumer; + struct qlcnic_cmd_buffer *pbuf; + struct cmd_desc_type0 *cmd_desc; + struct qlcnic_host_tx_ring *tx_ring; + + i = 0; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EIO; + + tx_ring = adapter->tx_ring; + __netif_tx_lock_bh(tx_ring->txq); + + producer = tx_ring->producer; + consumer = tx_ring->sw_consumer; + + if (nr_desc >= qlcnic_tx_avail(tx_ring)) { + netif_tx_stop_queue(tx_ring->txq); + __netif_tx_unlock_bh(tx_ring->txq); + return -EBUSY; + } + + do { + cmd_desc = &cmd_desc_arr[i]; + + pbuf = &tx_ring->cmd_buf_arr[producer]; + pbuf->skb = NULL; + pbuf->frag_count = 0; + + memcpy(&tx_ring->desc_head[producer], + &cmd_desc_arr[i], sizeof(struct cmd_desc_type0)); + + producer = get_next_index(producer, tx_ring->num_desc); + i++; + + } while (i != nr_desc); + + tx_ring->producer = producer; + + qlcnic_update_cmd_producer(adapter, tx_ring); + + __netif_tx_unlock_bh(tx_ring->txq); + + return 0; +} + +static int +qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, + unsigned op) +{ + struct qlcnic_nic_req req; + struct qlcnic_mac_req *mac_req; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23); + + word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + mac_req = (struct qlcnic_mac_req *)&req.words[0]; + mac_req->op = op; + memcpy(mac_req->mac_addr, addr, 6); + + return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); +} + +static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, + u8 *addr, struct list_head *del_list) +{ + struct list_head *head; + struct qlcnic_mac_list_s *cur; + + /* look up if already exists */ + list_for_each(head, del_list) { + cur = list_entry(head, struct qlcnic_mac_list_s, list); + + if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { + list_move_tail(head, &adapter->mac_list); + return 0; + } + } + + cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); + if (cur == NULL) { + dev_err(&adapter->netdev->dev, + "failed to add mac address filter\n"); + return -ENOMEM; + } + memcpy(cur->mac_addr, addr, ETH_ALEN); + list_add_tail(&cur->list, &adapter->mac_list); + + return qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_ADD); +} + +void qlcnic_set_multi(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct dev_mc_list *mc_ptr; + u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + u32 mode = VPORT_MISS_MODE_DROP; + LIST_HEAD(del_list); + struct list_head *head; + struct qlcnic_mac_list_s *cur; + + list_splice_tail_init(&adapter->mac_list, &del_list); + + qlcnic_nic_add_mac(adapter, adapter->mac_addr, &del_list); + qlcnic_nic_add_mac(adapter, bcast_addr, &del_list); + + if (netdev->flags & IFF_PROMISC) { + mode = VPORT_MISS_MODE_ACCEPT_ALL; + goto send_fw_cmd; + } + + if ((netdev->flags & IFF_ALLMULTI) || + (netdev->mc_count > adapter->max_mc_count)) { + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + goto send_fw_cmd; + } + + if (netdev->mc_count > 0) { + for (mc_ptr = netdev->mc_list; mc_ptr; + mc_ptr = mc_ptr->next) { + qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, + &del_list); + } + } + +send_fw_cmd: + qlcnic_nic_set_promisc(adapter, mode); + head = &del_list; + while (!list_empty(head)) { + cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + + qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + +int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) +{ + struct qlcnic_nic_req req; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(mode); + + return qlcnic_send_cmd_descs(adapter, + (struct cmd_desc_type0 *)&req, 1); +} + +void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) +{ + struct qlcnic_mac_list_s *cur; + struct list_head *head = &adapter->mac_list; + + while (!list_empty(head)) { + cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + qlcnic_sre_macaddr_change(adapter, + cur->mac_addr, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + +#define QLCNIC_CONFIG_INTR_COALESCE 3 + +/* + * Send the interrupt coalescing parameter set by ethtool to the card. + */ +int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_req req; + u64 word[6]; + int rv, i; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word[0]); + + memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); + for (i = 0; i < 6; i++) + req.words[i] = cpu_to_le64(word[i]); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send interrupt coalescing parameters\n"); + + return rv; +} + +int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send configure hw lro request\n"); + + adapter->flags ^= QLCNIC_LRO_ENABLED; + + return rv; +} + +int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "Could not send configure bridge mode request\n"); + + adapter->flags ^= QLCNIC_BRIDGE_ENABLED; + + return rv; +} + + +#define RSS_HASHTYPE_IP_TCP 0x3 + +int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int i, rv; + + const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL, + 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, + 0x255b0ec26d5a56daULL }; + + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + /* + * RSS request: + * bits 3-0: hash_method + * 5-4: hash_type_ipv4 + * 7-6: hash_type_ipv6 + * 8: enable + * 9: use indirection table + * 47-10: reserved + * 63-48: indirection table mask + */ + word = ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) | + ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) | + ((u64)(enable & 0x1) << 8) | + ((0x7ULL) << 48); + req.words[0] = cpu_to_le64(word); + for (i = 0; i < 5; i++) + req.words[i+1] = cpu_to_le64(key[i]); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, "could not configure RSS\n"); + + return rv; +} + +int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(cmd); + req.words[1] = cpu_to_le64(ip); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not notify %s IP 0x%x reuqest\n", + (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip); + + return rv; +} + +int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(enable | (enable << 8)); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not configure link notification\n"); + + return rv; +} + +int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_req req; + u64 word; + int rv; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_LRO_REQUEST | + ((u64)adapter->portnum << 16) | + ((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ; + + req.req_hdr = cpu_to_le64(word); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) + dev_err(&adapter->netdev->dev, + "could not cleanup lro flows\n"); + + return rv; +} + +/* + * qlcnic_change_mtu - Change the Maximum Transfer Unit + * @returns 0 on success, negative on failure + */ + +int qlcnic_change_mtu(struct net_device *netdev, int mtu) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int rc = 0; + + if (mtu > P3_MAX_MTU) { + dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n", + P3_MAX_MTU); + return -EINVAL; + } + + rc = qlcnic_fw_cmd_set_mtu(adapter, mtu); + + if (!rc) + netdev->mtu = mtu; + + return rc; +} + +int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac) +{ + u32 crbaddr, mac_hi, mac_lo; + int pci_func = adapter->ahw.pci_func; + + crbaddr = CRB_MAC_BLOCK_START + + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); + + mac_lo = QLCRD32(adapter, crbaddr); + mac_hi = QLCRD32(adapter, crbaddr+4); + + if (pci_func & 1) + *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); + else + *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32)); + + return 0; +} + +/* + * Changes the CRB window to the specified window. + */ + /* Returns < 0 if off is not valid, + * 1 if window access is needed. 'off' is set to offset from + * CRB space in 128M pci map + * 0 if no window access is needed. 'off' is set to 2M addr + * In: 'off' is offset from base in 128M pci map + */ +static int +qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, + ulong off, void __iomem **addr) +{ + const struct crb_128M_2M_sub_block_map *m; + + if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE)) + return -EINVAL; + + off -= QLCNIC_PCI_CRBSPACE; + + /* + * Try direct map + */ + m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; + + if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { + *addr = adapter->ahw.pci_base0 + m->start_2M + + (off - m->start_128M); + return 0; + } + + /* + * Not in direct map, use crb window + */ + *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); + return 1; +} + +/* + * In: 'off' is offset from CRB space in 128M pci map + * Out: 'off' is 2M pci map addr + * side effect: lock crb window + */ +static void +qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) +{ + u32 window; + void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; + + off -= QLCNIC_PCI_CRBSPACE; + + window = CRB_HI(off); + + if (adapter->ahw.crb_win == window) + return; + + writel(window, addr); + if (readl(addr) != window) { + if (printk_ratelimit()) + dev_warn(&adapter->pdev->dev, + "failed to set CRB window to %d off 0x%lx\n", + window, off); + } + adapter->ahw.crb_win = window; +} + +int +qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) +{ + unsigned long flags; + int rv; + void __iomem *addr = NULL; + + rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr); + + if (rv == 0) { + writel(data, addr); + return 0; + } + + if (rv > 0) { + /* indirect access */ + write_lock_irqsave(&adapter->ahw.crb_lock, flags); + crb_win_lock(adapter); + qlcnic_pci_set_crbwindow_2M(adapter, off); + writel(data, addr); + crb_win_unlock(adapter); + write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + return 0; + } + + dev_err(&adapter->pdev->dev, + "%s: invalid offset: 0x%016lx\n", __func__, off); + dump_stack(); + return -EIO; +} + +u32 +qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) +{ + unsigned long flags; + int rv; + u32 data; + void __iomem *addr = NULL; + + rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr); + + if (rv == 0) + return readl(addr); + + if (rv > 0) { + /* indirect access */ + write_lock_irqsave(&adapter->ahw.crb_lock, flags); + crb_win_lock(adapter); + qlcnic_pci_set_crbwindow_2M(adapter, off); + data = readl(addr); + crb_win_unlock(adapter); + write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + return data; + } + + dev_err(&adapter->pdev->dev, + "%s: invalid offset: 0x%016lx\n", __func__, off); + dump_stack(); + return -1; +} + + +void __iomem * +qlcnic_get_ioaddr(struct qlcnic_adapter *adapter, u32 offset) +{ + void __iomem *addr = NULL; + + WARN_ON(qlcnic_pci_get_crb_addr_2M(adapter, offset, &addr)); + + return addr; +} + + +static int +qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, + u64 addr, u32 *start) +{ + u32 window; + struct pci_dev *pdev = adapter->pdev; + + if ((addr & 0x00ff800) == 0xff800) { + if (printk_ratelimit()) + dev_warn(&pdev->dev, "QM access not handled\n"); + return -EIO; + } + + window = OCM_WIN_P3P(addr); + + writel(window, adapter->ahw.ocm_win_crb); + /* read back to flush */ + readl(adapter->ahw.ocm_win_crb); + + adapter->ahw.ocm_win = window; + *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); + return 0; +} + +static int +qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, + u64 *data, int op) +{ + void __iomem *addr, *mem_ptr = NULL; + resource_size_t mem_base; + int ret; + u32 start; + + mutex_lock(&adapter->ahw.mem_lock); + + ret = qlcnic_pci_set_window_2M(adapter, off, &start); + if (ret != 0) + goto unlock; + + addr = pci_base_offset(adapter, start); + if (addr) + goto noremap; + + mem_base = pci_resource_start(adapter->pdev, 0) + (start & PAGE_MASK); + + mem_ptr = ioremap(mem_base, PAGE_SIZE); + if (mem_ptr == NULL) { + ret = -EIO; + goto unlock; + } + + addr = mem_ptr + (start & (PAGE_SIZE - 1)); + +noremap: + if (op == 0) /* read */ + *data = readq(addr); + else /* write */ + writeq(*data, addr); + +unlock: + mutex_unlock(&adapter->ahw.mem_lock); + + if (mem_ptr) + iounmap(mem_ptr); + return ret; +} + +#define MAX_CTL_CHECK 1000 + +int +qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, + u64 off, u64 data) +{ + int i, j, ret; + u32 temp, off8; + u64 stride; + void __iomem *mem_crb; + + /* Only 64-bit aligned access */ + if (off & 7) + return -EIO; + + /* P3 onward, test agent base for MIU and SIU is same */ + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, + QLCNIC_ADDR_QDR_NET_MAX_P3)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) + return qlcnic_pci_mem_access_direct(adapter, off, &data, 1); + + return -EIO; + +correct: + stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8; + + off8 = off & ~(stride-1); + + mutex_lock(&adapter->ahw.mem_lock); + + writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); + writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); + + i = 0; + if (stride == 16) { + writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE), + (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + ret = -EIO; + goto done; + } + + i = (off & 0xf) ? 0 : 2; + writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)), + mem_crb + MIU_TEST_AGT_WRDATA(i)); + writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)), + mem_crb + MIU_TEST_AGT_WRDATA(i+1)); + i = (off & 0xf) ? 2 : 0; + } + + writel(data & 0xffffffff, + mem_crb + MIU_TEST_AGT_WRDATA(i)); + writel((data >> 32) & 0xffffffff, + mem_crb + MIU_TEST_AGT_WRDATA(i+1)); + + writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE), + (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + dev_err(&adapter->pdev->dev, + "failed to write through agent\n"); + ret = -EIO; + } else + ret = 0; + +done: + mutex_unlock(&adapter->ahw.mem_lock); + + return ret; +} + +int +qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, + u64 off, u64 *data) +{ + int j, ret; + u32 temp, off8; + u64 val, stride; + void __iomem *mem_crb; + + /* Only 64-bit aligned access */ + if (off & 7) + return -EIO; + + /* P3 onward, test agent base for MIU and SIU is same */ + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, + QLCNIC_ADDR_QDR_NET_MAX_P3)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) { + mem_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE); + goto correct; + } + + if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) { + return qlcnic_pci_mem_access_direct(adapter, + off, data, 0); + } + + return -EIO; + +correct: + stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8; + + off8 = off & ~(stride-1); + + mutex_lock(&adapter->ahw.mem_lock); + + writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); + writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); + writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL)); + writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL)); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = readl(mem_crb + TEST_AGT_CTRL); + if ((temp & TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + dev_err(&adapter->pdev->dev, + "failed to read through agent\n"); + ret = -EIO; + } else { + off8 = MIU_TEST_AGT_RDDATA_LO; + if ((stride == 16) && (off & 0xf)) + off8 = MIU_TEST_AGT_RDDATA_UPPER_LO; + + temp = readl(mem_crb + off8 + 4); + val = (u64)temp << 32; + val |= readl(mem_crb + off8); + *data = val; + ret = 0; + } + + mutex_unlock(&adapter->ahw.mem_lock); + + return ret; +} + +int qlcnic_get_board_info(struct qlcnic_adapter *adapter) +{ + int offset, board_type, magic; + struct pci_dev *pdev = adapter->pdev; + + offset = QLCNIC_FW_MAGIC_OFFSET; + if (qlcnic_rom_fast_read(adapter, offset, &magic)) + return -EIO; + + if (magic != QLCNIC_BDINFO_MAGIC) { + dev_err(&pdev->dev, "invalid board config, magic=%08x\n", + magic); + return -EIO; + } + + offset = QLCNIC_BRDTYPE_OFFSET; + if (qlcnic_rom_fast_read(adapter, offset, &board_type)) + return -EIO; + + adapter->ahw.board_type = board_type; + + if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) { + u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); + if ((gpio & 0x8000) == 0) + board_type = QLCNIC_BRDTYPE_P3_10G_TP; + } + + switch (board_type) { + case QLCNIC_BRDTYPE_P3_HMEZ: + case QLCNIC_BRDTYPE_P3_XG_LOM: + case QLCNIC_BRDTYPE_P3_10G_CX4: + case QLCNIC_BRDTYPE_P3_10G_CX4_LP: + case QLCNIC_BRDTYPE_P3_IMEZ: + case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS: + case QLCNIC_BRDTYPE_P3_10G_SFP_CT: + case QLCNIC_BRDTYPE_P3_10G_SFP_QT: + case QLCNIC_BRDTYPE_P3_10G_XFP: + case QLCNIC_BRDTYPE_P3_10000_BASE_T: + adapter->ahw.port_type = QLCNIC_XGBE; + break; + case QLCNIC_BRDTYPE_P3_REF_QG: + case QLCNIC_BRDTYPE_P3_4_GB: + case QLCNIC_BRDTYPE_P3_4_GB_MM: + adapter->ahw.port_type = QLCNIC_GBE; + break; + case QLCNIC_BRDTYPE_P3_10G_TP: + adapter->ahw.port_type = (adapter->portnum < 2) ? + QLCNIC_XGBE : QLCNIC_GBE; + break; + default: + dev_err(&pdev->dev, "unknown board type %x\n", board_type); + adapter->ahw.port_type = QLCNIC_XGBE; + break; + } + + return 0; +} + +int +qlcnic_wol_supported(struct qlcnic_adapter *adapter) +{ + u32 wol_cfg; + + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + if (wol_cfg & (1UL << adapter->portnum)) { + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + if (wol_cfg & (1 << adapter->portnum)) + return 1; + } + + return 0; +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c new file mode 100644 index 000000000000..7ae8bcc1e439 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -0,0 +1,1466 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include +#include "qlcnic.h" + +struct crb_addr_pair { + u32 addr; + u32 data; +}; + +#define QLCNIC_MAX_CRB_XFORM 60 +static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM]; + +#define crb_addr_transform(name) \ + (crb_addr_xform[QLCNIC_HW_PX_MAP_CRB_##name] = \ + QLCNIC_HW_CRB_HUB_AGT_ADR_##name << 20) + +#define QLCNIC_ADDR_ERROR (0xffffffff) + +static void +qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring); + +static void crb_addr_transform_setup(void) +{ + crb_addr_transform(XDMA); + crb_addr_transform(TIMR); + crb_addr_transform(SRE); + crb_addr_transform(SQN3); + crb_addr_transform(SQN2); + crb_addr_transform(SQN1); + crb_addr_transform(SQN0); + crb_addr_transform(SQS3); + crb_addr_transform(SQS2); + crb_addr_transform(SQS1); + crb_addr_transform(SQS0); + crb_addr_transform(RPMX7); + crb_addr_transform(RPMX6); + crb_addr_transform(RPMX5); + crb_addr_transform(RPMX4); + crb_addr_transform(RPMX3); + crb_addr_transform(RPMX2); + crb_addr_transform(RPMX1); + crb_addr_transform(RPMX0); + crb_addr_transform(ROMUSB); + crb_addr_transform(SN); + crb_addr_transform(QMN); + crb_addr_transform(QMS); + crb_addr_transform(PGNI); + crb_addr_transform(PGND); + crb_addr_transform(PGN3); + crb_addr_transform(PGN2); + crb_addr_transform(PGN1); + crb_addr_transform(PGN0); + crb_addr_transform(PGSI); + crb_addr_transform(PGSD); + crb_addr_transform(PGS3); + crb_addr_transform(PGS2); + crb_addr_transform(PGS1); + crb_addr_transform(PGS0); + crb_addr_transform(PS); + crb_addr_transform(PH); + crb_addr_transform(NIU); + crb_addr_transform(I2Q); + crb_addr_transform(EG); + crb_addr_transform(MN); + crb_addr_transform(MS); + crb_addr_transform(CAS2); + crb_addr_transform(CAS1); + crb_addr_transform(CAS0); + crb_addr_transform(CAM); + crb_addr_transform(C2C1); + crb_addr_transform(C2C0); + crb_addr_transform(SMB); + crb_addr_transform(OCM0); + crb_addr_transform(I2C0); +} + +void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_rx_buffer *rx_buf; + int i, ring; + + recv_ctx = &adapter->recv_ctx; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + for (i = 0; i < rds_ring->num_desc; ++i) { + rx_buf = &(rds_ring->rx_buf_arr[i]); + if (rx_buf->state == QLCNIC_BUFFER_FREE) + continue; + pci_unmap_single(adapter->pdev, + rx_buf->dma, + rds_ring->dma_size, + PCI_DMA_FROMDEVICE); + if (rx_buf->skb != NULL) + dev_kfree_skb_any(rx_buf->skb); + } + } +} + +void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) +{ + struct qlcnic_cmd_buffer *cmd_buf; + struct qlcnic_skb_frag *buffrag; + int i, j; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + cmd_buf = tx_ring->cmd_buf_arr; + for (i = 0; i < tx_ring->num_desc; i++) { + buffrag = cmd_buf->frag_array; + if (buffrag->dma) { + pci_unmap_single(adapter->pdev, buffrag->dma, + buffrag->length, PCI_DMA_TODEVICE); + buffrag->dma = 0ULL; + } + for (j = 0; j < cmd_buf->frag_count; j++) { + buffrag++; + if (buffrag->dma) { + pci_unmap_page(adapter->pdev, buffrag->dma, + buffrag->length, + PCI_DMA_TODEVICE); + buffrag->dma = 0ULL; + } + } + if (cmd_buf->skb) { + dev_kfree_skb_any(cmd_buf->skb); + cmd_buf->skb = NULL; + } + cmd_buf++; + } +} + +void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->rds_rings == NULL) + goto skip_rds; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; + } + kfree(recv_ctx->rds_rings); + +skip_rds: + if (adapter->tx_ring == NULL) + return; + + tx_ring = adapter->tx_ring; + vfree(tx_ring->cmd_buf_arr); + kfree(adapter->tx_ring); +} + +int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + struct qlcnic_rx_buffer *rx_buf; + int ring, i, size; + + struct qlcnic_cmd_buffer *cmd_buf_arr; + struct net_device *netdev = adapter->netdev; + + size = sizeof(struct qlcnic_host_tx_ring); + tx_ring = kzalloc(size, GFP_KERNEL); + if (tx_ring == NULL) { + dev_err(&netdev->dev, "failed to allocate tx ring struct\n"); + return -ENOMEM; + } + adapter->tx_ring = tx_ring; + + tx_ring->num_desc = adapter->num_txd; + tx_ring->txq = netdev_get_tx_queue(netdev, 0); + + cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring)); + if (cmd_buf_arr == NULL) { + dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n"); + return -ENOMEM; + } + memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); + tx_ring->cmd_buf_arr = cmd_buf_arr; + + recv_ctx = &adapter->recv_ctx; + + size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); + rds_ring = kzalloc(size, GFP_KERNEL); + if (rds_ring == NULL) { + dev_err(&netdev->dev, "failed to allocate rds ring struct\n"); + return -ENOMEM; + } + recv_ctx->rds_rings = rds_ring; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + switch (ring) { + case RCV_RING_NORMAL: + rds_ring->num_desc = adapter->num_rxd; + if (adapter->ahw.cut_through) { + rds_ring->dma_size = + QLCNIC_CT_DEFAULT_RX_BUF_LEN; + rds_ring->skb_size = + QLCNIC_CT_DEFAULT_RX_BUF_LEN; + } else { + rds_ring->dma_size = + QLCNIC_P3_RX_BUF_MAX_LEN; + rds_ring->skb_size = + rds_ring->dma_size + NET_IP_ALIGN; + } + break; + + case RCV_RING_JUMBO: + rds_ring->num_desc = adapter->num_jumbo_rxd; + rds_ring->dma_size = + QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA; + + rds_ring->skb_size = + rds_ring->dma_size + NET_IP_ALIGN; + break; + + case RCV_RING_LRO: + rds_ring->num_desc = adapter->num_lro_rxd; + rds_ring->dma_size = QLCNIC_RX_LRO_BUFFER_LENGTH; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; + break; + + } + rds_ring->rx_buf_arr = (struct qlcnic_rx_buffer *) + vmalloc(RCV_BUFF_RINGSIZE(rds_ring)); + if (rds_ring->rx_buf_arr == NULL) { + dev_err(&netdev->dev, "Failed to allocate " + "rx buffer ring %d\n", ring); + goto err_out; + } + memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring)); + INIT_LIST_HEAD(&rds_ring->free_list); + /* + * Now go through all of them, set reference handles + * and put them in the queues. + */ + rx_buf = rds_ring->rx_buf_arr; + for (i = 0; i < rds_ring->num_desc; i++) { + list_add_tail(&rx_buf->list, + &rds_ring->free_list); + rx_buf->ref_handle = i; + rx_buf->state = QLCNIC_BUFFER_FREE; + rx_buf++; + } + spin_lock_init(&rds_ring->lock); + } + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + sds_ring->irq = adapter->msix_entries[ring].vector; + sds_ring->adapter = adapter; + sds_ring->num_desc = adapter->num_rxd; + + for (i = 0; i < NUM_RCV_DESC_RINGS; i++) + INIT_LIST_HEAD(&sds_ring->free_list[i]); + } + + return 0; + +err_out: + qlcnic_free_sw_resources(adapter); + return -ENOMEM; +} + +/* + * Utility to translate from internal Phantom CRB address + * to external PCI CRB address. + */ +static u32 qlcnic_decode_crb_addr(u32 addr) +{ + int i; + u32 base_addr, offset, pci_base; + + crb_addr_transform_setup(); + + pci_base = QLCNIC_ADDR_ERROR; + base_addr = addr & 0xfff00000; + offset = addr & 0x000fffff; + + for (i = 0; i < QLCNIC_MAX_CRB_XFORM; i++) { + if (crb_addr_xform[i] == base_addr) { + pci_base = i << 20; + break; + } + } + if (pci_base == QLCNIC_ADDR_ERROR) + return pci_base; + else + return pci_base + offset; +} + +#define QLCNIC_MAX_ROM_WAIT_USEC 100 + +static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) +{ + long timeout = 0; + long done = 0; + + cond_resched(); + + while (done == 0) { + done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS); + done &= 2; + if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) { + dev_err(&adapter->pdev->dev, + "Timeout reached waiting for rom done"); + return -EIO; + } + udelay(1); + } + return 0; +} + +static int do_rom_fast_read(struct qlcnic_adapter *adapter, + int addr, int *valp) +{ + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_INSTR_OPCODE, 0xb); + if (qlcnic_wait_rom_done(adapter)) { + dev_err(&adapter->pdev->dev, "Error waiting for rom done\n"); + return -EIO; + } + /* reset abyte_cnt and dummy_byte_cnt */ + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 0); + udelay(10); + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + + *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA); + return 0; +} + +static int do_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int addridx; + int ret = 0; + + for (addridx = addr; addridx < (addr + size); addridx += 4) { + int v; + ret = do_rom_fast_read(adapter, addridx, &v); + if (ret != 0) + break; + *(__le32 *)bytes = cpu_to_le32(v); + bytes += 4; + } + + return ret; +} + +int +qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret; + + ret = qlcnic_rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_read_words(adapter, addr, bytes, size); + + qlcnic_rom_unlock(adapter); + return ret; +} + +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp) +{ + int ret; + + if (qlcnic_rom_lock(adapter) != 0) + return -EIO; + + ret = do_rom_fast_read(adapter, addr, valp); + qlcnic_rom_unlock(adapter); + return ret; +} + +int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) +{ + int addr, val; + int i, n, init_delay; + struct crb_addr_pair *buf; + unsigned offset; + u32 off; + struct pci_dev *pdev = adapter->pdev; + + /* resetall */ + qlcnic_rom_lock(adapter); + QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff); + qlcnic_rom_unlock(adapter); + + if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) || + qlcnic_rom_fast_read(adapter, 4, &n) != 0) { + dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n); + return -EIO; + } + offset = n & 0xffffU; + n = (n >> 16) & 0xffffU; + + if (n >= 1024) { + dev_err(&pdev->dev, "QLOGIC card flash not initialized.\n"); + return -EIO; + } + + buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL); + if (buf == NULL) { + dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n"); + return -ENOMEM; + } + + for (i = 0; i < n; i++) { + if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 || + qlcnic_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) { + kfree(buf); + return -EIO; + } + + buf[i].addr = addr; + buf[i].data = val; + } + + for (i = 0; i < n; i++) { + + off = qlcnic_decode_crb_addr(buf[i].addr); + if (off == QLCNIC_ADDR_ERROR) { + dev_err(&pdev->dev, "CRB init value out of range %x\n", + buf[i].addr); + continue; + } + off += QLCNIC_PCI_CRBSPACE; + + if (off & 1) + continue; + + /* skipping cold reboot MAGIC */ + if (off == QLCNIC_CAM_RAM(0x1fc)) + continue; + if (off == (QLCNIC_CRB_I2C0 + 0x1c)) + continue; + if (off == (ROMUSB_GLB + 0xbc)) /* do not reset PCI */ + continue; + if (off == (ROMUSB_GLB + 0xa8)) + continue; + if (off == (ROMUSB_GLB + 0xc8)) /* core clock */ + continue; + if (off == (ROMUSB_GLB + 0x24)) /* MN clock */ + continue; + if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */ + continue; + if ((off & 0x0ff00000) == QLCNIC_CRB_DDR_NET) + continue; + /* skip the function enable register */ + if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION)) + continue; + if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION2)) + continue; + if ((off & 0x0ff00000) == QLCNIC_CRB_SMB) + continue; + + init_delay = 1; + /* After writing this register, HW needs time for CRB */ + /* to quiet down (else crb_window returns 0xffffffff) */ + if (off == QLCNIC_ROMUSB_GLB_SW_RESET) + init_delay = 1000; + + QLCWR32(adapter, off, buf[i].data); + + msleep(init_delay); + } + kfree(buf); + + /* p2dn replyCount */ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e); + /* disable_peg_cache 0 & 1*/ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8); + + /* peg_clr_all */ + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0); + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0); + return 0; +} + +static int +qlcnic_has_mn(struct qlcnic_adapter *adapter) +{ + u32 capability, flashed_ver; + capability = 0; + + qlcnic_rom_fast_read(adapter, + QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver); + flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver); + + if (flashed_ver >= QLCNIC_VERSION_CODE(4, 0, 220)) { + + capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); + if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) + return 1; + } + return 0; +} + +static +struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section) +{ + u32 i; + struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; + __le32 entries = cpu_to_le32(directory->num_entries); + + for (i = 0; i < entries; i++) { + + __le32 offs = cpu_to_le32(directory->findex) + + (i * cpu_to_le32(directory->entry_size)); + __le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8)); + + if (tab_type == section) + return (struct uni_table_desc *) &unirom[offs]; + } + + return NULL; +} + +static int +qlcnic_set_product_offs(struct qlcnic_adapter *adapter) +{ + struct uni_table_desc *ptab_descr; + const u8 *unirom = adapter->fw->data; + u32 i; + __le32 entries; + int mn_present = qlcnic_has_mn(adapter); + + ptab_descr = qlcnic_get_table_desc(unirom, + QLCNIC_UNI_DIR_SECT_PRODUCT_TBL); + if (ptab_descr == NULL) + return -1; + + entries = cpu_to_le32(ptab_descr->num_entries); +nomn: + for (i = 0; i < entries; i++) { + + __le32 flags, file_chiprev, offs; + u8 chiprev = adapter->ahw.revision_id; + u32 flagbit; + + offs = cpu_to_le32(ptab_descr->findex) + + (i * cpu_to_le32(ptab_descr->entry_size)); + flags = cpu_to_le32(*((int *)&unirom[offs] + + QLCNIC_UNI_FLAGS_OFF)); + file_chiprev = cpu_to_le32(*((int *)&unirom[offs] + + QLCNIC_UNI_CHIP_REV_OFF)); + + flagbit = mn_present ? 1 : 2; + + if ((chiprev == file_chiprev) && + ((1ULL << flagbit) & flags)) { + adapter->file_prd_off = offs; + return 0; + } + } + if (mn_present) { + mn_present = 0; + goto nomn; + } + return -1; +} + +static +struct uni_data_desc *qlcnic_get_data_desc(struct qlcnic_adapter *adapter, + u32 section, u32 idx_offset) +{ + const u8 *unirom = adapter->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + + idx_offset)); + struct uni_table_desc *tab_desc; + __le32 offs; + + tab_desc = qlcnic_get_table_desc(unirom, section); + + if (tab_desc == NULL) + return NULL; + + offs = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * idx); + + return (struct uni_data_desc *)&unirom[offs]; +} + +static u8 * +qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter) +{ + u32 offs = QLCNIC_BOOTLD_START; + + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + offs = cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_BOOTLD, + QLCNIC_UNI_BOOTLD_IDX_OFF))->findex); + + return (u8 *)&adapter->fw->data[offs]; +} + +static u8 * +qlcnic_get_fw_offs(struct qlcnic_adapter *adapter) +{ + u32 offs = QLCNIC_IMAGE_START; + + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + offs = cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF))->findex); + + return (u8 *)&adapter->fw->data[offs]; +} + +static __le32 +qlcnic_get_fw_size(struct qlcnic_adapter *adapter) +{ + if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32((qlcnic_get_data_desc(adapter, + QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF))->size); + else + return cpu_to_le32( + *(u32 *)&adapter->fw->data[QLCNIC_FW_SIZE_OFFSET]); +} + +static __le32 +qlcnic_get_fw_version(struct qlcnic_adapter *adapter) +{ + struct uni_data_desc *fw_data_desc; + const struct firmware *fw = adapter->fw; + __le32 major, minor, sub; + const u8 *ver_str; + int i, ret; + + if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]); + + fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW, + QLCNIC_UNI_FIRMWARE_IDX_OFF); + ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) + + cpu_to_le32(fw_data_desc->size) - 17; + + for (i = 0; i < 12; i++) { + if (!strncmp(&ver_str[i], "REV=", 4)) { + ret = sscanf(&ver_str[i+4], "%u.%u.%u ", + &major, &minor, &sub); + if (ret != 3) + return 0; + else + return major + (minor << 8) + (sub << 16); + } + } + + return 0; +} + +static __le32 +qlcnic_get_bios_version(struct qlcnic_adapter *adapter) +{ + const struct firmware *fw = adapter->fw; + __le32 bios_ver, prd_off = adapter->file_prd_off; + + if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE) + return cpu_to_le32( + *(u32 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]); + + bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + + QLCNIC_UNI_BIOS_VERSION_OFF)); + + return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); +} + +int +qlcnic_need_fw_reset(struct qlcnic_adapter *adapter) +{ + u32 count, old_count; + u32 val, version, major, minor, build; + int i, timeout; + + if (adapter->need_fw_reset) + return 1; + + /* last attempt had failed */ + if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED) + return 1; + + old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + + for (i = 0; i < 10; i++) { + + timeout = msleep_interruptible(200); + if (timeout) { + QLCWR32(adapter, CRB_CMDPEG_STATE, + PHAN_INITIALIZE_FAILED); + return -EINTR; + } + + count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + if (count != old_count) + break; + } + + /* firmware is dead */ + if (count == old_count) + return 1; + + /* check if we have got newer or different file firmware */ + if (adapter->fw) { + + val = qlcnic_get_fw_version(adapter); + + version = QLCNIC_DECODE_VERSION(val); + + major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + + if (version > QLCNIC_VERSION_CODE(major, minor, build)) + return 1; + } + + return 0; +} + +static const char *fw_name[] = { + QLCNIC_UNIFIED_ROMIMAGE_NAME, + QLCNIC_FLASH_ROMIMAGE_NAME, +}; + +int +qlcnic_load_firmware(struct qlcnic_adapter *adapter) +{ + u64 *ptr64; + u32 i, flashaddr, size; + const struct firmware *fw = adapter->fw; + struct pci_dev *pdev = adapter->pdev; + + dev_info(&pdev->dev, "loading firmware from %s\n", + fw_name[adapter->fw_type]); + + if (fw) { + __le64 data; + + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + + ptr64 = (u64 *)qlcnic_get_bootld_offs(adapter); + flashaddr = QLCNIC_BOOTLD_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (qlcnic_pci_mem_write_2M(adapter, flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + + size = (__force u32)qlcnic_get_fw_size(adapter) / 8; + + ptr64 = (u64 *)qlcnic_get_fw_offs(adapter); + flashaddr = QLCNIC_IMAGE_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (qlcnic_pci_mem_write_2M(adapter, + flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + } else { + u64 data; + u32 hi, lo; + + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + flashaddr = QLCNIC_BOOTLD_START; + + for (i = 0; i < size; i++) { + if (qlcnic_rom_fast_read(adapter, + flashaddr, (int *)&lo) != 0) + return -EIO; + if (qlcnic_rom_fast_read(adapter, + flashaddr + 4, (int *)&hi) != 0) + return -EIO; + + data = (((u64)hi << 32) | lo); + + if (qlcnic_pci_mem_write_2M(adapter, + flashaddr, data)) + return -EIO; + + flashaddr += 8; + } + } + msleep(1); + + QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020); + QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e); + return 0; +} + +static int +qlcnic_validate_firmware(struct qlcnic_adapter *adapter) +{ + __le32 val; + u32 ver, min_ver, bios, min_size; + struct pci_dev *pdev = adapter->pdev; + const struct firmware *fw = adapter->fw; + u8 fw_type = adapter->fw_type; + + if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) { + if (qlcnic_set_product_offs(adapter)) + return -EINVAL; + + min_size = QLCNIC_UNI_FW_MIN_SIZE; + } else { + val = cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET]); + if ((__force u32)val != QLCNIC_BDINFO_MAGIC) + return -EINVAL; + + min_size = QLCNIC_FW_MIN_SIZE; + } + + if (fw->size < min_size) + return -EINVAL; + + val = qlcnic_get_fw_version(adapter); + + min_ver = QLCNIC_VERSION_CODE(4, 0, 216); + + ver = QLCNIC_DECODE_VERSION(val); + + if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) { + dev_err(&pdev->dev, + "%s: firmware version %d.%d.%d unsupported\n", + fw_name[fw_type], _major(ver), _minor(ver), _build(ver)); + return -EINVAL; + } + + val = qlcnic_get_bios_version(adapter); + qlcnic_rom_fast_read(adapter, QLCNIC_BIOS_VERSION_OFFSET, (int *)&bios); + if ((__force u32)val != bios) { + dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", + fw_name[fw_type]); + return -EINVAL; + } + + /* check if flashed firmware is newer */ + if (qlcnic_rom_fast_read(adapter, + QLCNIC_FW_VERSION_OFFSET, (int *)&val)) + return -EIO; + + val = QLCNIC_DECODE_VERSION(val); + if (val > ver) { + dev_info(&pdev->dev, "%s: firmware is older than flash\n", + fw_name[fw_type]); + return -EINVAL; + } + + QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC); + return 0; +} + +static void +qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter) +{ + u8 fw_type; + + switch (adapter->fw_type) { + case QLCNIC_UNKNOWN_ROMIMAGE: + fw_type = QLCNIC_UNIFIED_ROMIMAGE; + break; + + case QLCNIC_UNIFIED_ROMIMAGE: + default: + fw_type = QLCNIC_FLASH_ROMIMAGE; + break; + } + + adapter->fw_type = fw_type; +} + + + +void qlcnic_request_firmware(struct qlcnic_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int rc; + + adapter->fw_type = QLCNIC_UNKNOWN_ROMIMAGE; + +next: + qlcnic_get_next_fwtype(adapter); + + if (adapter->fw_type == QLCNIC_FLASH_ROMIMAGE) { + adapter->fw = NULL; + } else { + rc = request_firmware(&adapter->fw, + fw_name[adapter->fw_type], &pdev->dev); + if (rc != 0) + goto next; + + rc = qlcnic_validate_firmware(adapter); + if (rc != 0) { + release_firmware(adapter->fw); + msleep(1); + goto next; + } + } +} + + +void +qlcnic_release_firmware(struct qlcnic_adapter *adapter) +{ + if (adapter->fw) + release_firmware(adapter->fw); + adapter->fw = NULL; +} + +int qlcnic_phantom_init(struct qlcnic_adapter *adapter) +{ + u32 val; + int retries = 60; + + do { + val = QLCRD32(adapter, CRB_CMDPEG_STATE); + + switch (val) { + case PHAN_INITIALIZE_COMPLETE: + case PHAN_INITIALIZE_ACK: + return 0; + case PHAN_INITIALIZE_FAILED: + goto out_err; + default: + break; + } + + msleep(500); + + } while (--retries); + + QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); + +out_err: + dev_err(&adapter->pdev->dev, "firmware init failed\n"); + return -EIO; +} + +static int +qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter) +{ + u32 val; + int retries = 2000; + + do { + val = QLCRD32(adapter, CRB_RCVPEG_STATE); + + if (val == PHAN_PEG_RCV_INITIALIZED) + return 0; + + msleep(10); + + } while (--retries); + + if (!retries) { + dev_err(&adapter->pdev->dev, "Receive Peg initialization not " + "complete, state: 0x%x.\n", val); + return -EIO; + } + + return 0; +} + +int qlcnic_init_firmware(struct qlcnic_adapter *adapter) +{ + int err; + + err = qlcnic_receive_peg_ready(adapter); + if (err) + return err; + + QLCWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); + QLCWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); + QLCWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); + QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + + return err; +} + +static void +qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, + struct qlcnic_fw_msg *msg) +{ + u32 cable_OUI; + u16 cable_len; + u16 link_speed; + u8 link_status, module, duplex, autoneg; + struct net_device *netdev = adapter->netdev; + + adapter->has_link_events = 1; + + cable_OUI = msg->body[1] & 0xffffffff; + cable_len = (msg->body[1] >> 32) & 0xffff; + link_speed = (msg->body[1] >> 48) & 0xffff; + + link_status = msg->body[2] & 0xff; + duplex = (msg->body[2] >> 16) & 0xff; + autoneg = (msg->body[2] >> 24) & 0xff; + + module = (msg->body[2] >> 8) & 0xff; + if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) + dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, " + "length %d\n", cable_OUI, cable_len); + else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) + dev_info(&netdev->dev, "unsupported cable length %d\n", + cable_len); + + qlcnic_advert_link_change(adapter, link_status); + + if (duplex == LINKEVENT_FULL_DUPLEX) + adapter->link_duplex = DUPLEX_FULL; + else + adapter->link_duplex = DUPLEX_HALF; + + adapter->module_type = module; + adapter->link_autoneg = autoneg; + adapter->link_speed = link_speed; +} + +static void +qlcnic_handle_fw_message(int desc_cnt, int index, + struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_fw_msg msg; + struct status_desc *desc; + int i = 0, opcode; + + while (desc_cnt > 0 && i < 8) { + desc = &sds_ring->desc_head[index]; + msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); + msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); + + index = get_next_index(index, sds_ring->num_desc); + desc_cnt--; + } + + opcode = qlcnic_get_nic_msg_opcode(msg.body[0]); + switch (opcode) { + case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: + qlcnic_handle_linkevent(sds_ring->adapter, &msg); + break; + default: + break; + } +} + +static int +qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring, + struct qlcnic_rx_buffer *buffer) +{ + struct sk_buff *skb; + dma_addr_t dma; + struct pci_dev *pdev = adapter->pdev; + + buffer->skb = dev_alloc_skb(rds_ring->skb_size); + if (!buffer->skb) + return -ENOMEM; + + skb = buffer->skb; + + if (!adapter->ahw.cut_through) + skb_reserve(skb, 2); + + dma = pci_map_single(pdev, skb->data, + rds_ring->dma_size, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(pdev, dma)) { + dev_kfree_skb_any(skb); + buffer->skb = NULL; + return -ENOMEM; + } + + buffer->skb = skb; + buffer->dma = dma; + buffer->state = QLCNIC_BUFFER_BUSY; + + return 0; +} + +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum) +{ + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + + buffer = &rds_ring->rx_buf_arr[index]; + + pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size, + PCI_DMA_FROMDEVICE); + + skb = buffer->skb; + if (!skb) + goto no_skb; + + if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { + adapter->stats.csummed++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb->ip_summed = CHECKSUM_NONE; + } + + skb->dev = adapter->netdev; + + buffer->skb = NULL; +no_skb: + buffer->state = QLCNIC_BUFFER_FREE; + return skb; +} + +static struct qlcnic_rx_buffer * +qlcnic_process_rcv(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0) +{ + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; + + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = qlcnic_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + length = qlcnic_get_sts_totallength(sts_data0); + cksum = qlcnic_get_sts_status(sts_data0); + pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); + if (!skb) + return buffer; + + if (length > rds_ring->skb_size) + skb_put(skb, rds_ring->skb_size); + else + skb_put(skb, length); + + if (pkt_offset) + skb_pull(skb, pkt_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff); + skb->protocol = eth_type_trans(skb, netdev); + + napi_gro_receive(&sds_ring->napi, skb); + + adapter->stats.rx_pkts++; + adapter->stats.rxbytes += length; + + return buffer; +} + +#define QLC_TCP_HDR_SIZE 20 +#define QLC_TCP_TS_OPTION_SIZE 12 +#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE) + +static struct qlcnic_rx_buffer * +qlcnic_process_lro(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0, u64 sts_data1) +{ + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + struct iphdr *iph; + struct tcphdr *th; + bool push, timestamp; + int l2_hdr_offset, l4_hdr_offset; + int index; + u16 lro_length, length, data_offset; + u32 seq_number; + + if (unlikely(ring > adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = qlcnic_get_lro_sts_refhandle(sts_data0); + if (unlikely(index > rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + timestamp = qlcnic_get_lro_sts_timestamp(sts_data0); + lro_length = qlcnic_get_lro_sts_length(sts_data0); + l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0); + l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0); + push = qlcnic_get_lro_sts_push_flag(sts_data0); + seq_number = qlcnic_get_lro_sts_seq_number(sts_data1); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); + if (!skb) + return buffer; + + if (timestamp) + data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE; + else + data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE; + + skb_put(skb, lro_length + data_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); + + skb_pull(skb, l2_hdr_offset); + skb->protocol = eth_type_trans(skb, netdev); + + iph = (struct iphdr *)skb->data; + th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); + + length = (iph->ihl << 2) + (th->doff << 2) + lro_length; + iph->tot_len = htons(length); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + th->psh = push; + th->seq = htonl(seq_number); + + length = skb->len; + + netif_receive_skb(skb); + + adapter->stats.lro_pkts++; + adapter->stats.rxbytes += length; + + return buffer; +} + +int +qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + struct list_head *cur; + struct status_desc *desc; + struct qlcnic_rx_buffer *rxbuf; + u64 sts_data0, sts_data1; + + int count = 0; + int opcode, ring, desc_cnt; + u32 consumer = sds_ring->consumer; + + while (count < max) { + desc = &sds_ring->desc_head[consumer]; + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); + + if (!(sts_data0 & STATUS_OWNER_HOST)) + break; + + desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); + opcode = qlcnic_get_sts_opcode(sts_data0); + + switch (opcode) { + case QLCNIC_RXPKT_DESC: + case QLCNIC_OLD_RXPKT_DESC: + case QLCNIC_SYN_OFFLOAD: + ring = qlcnic_get_sts_type(sts_data0); + rxbuf = qlcnic_process_rcv(adapter, sds_ring, + ring, sts_data0); + break; + case QLCNIC_LRO_DESC: + ring = qlcnic_get_lro_sts_type(sts_data0); + sts_data1 = le64_to_cpu(desc->status_desc_data[1]); + rxbuf = qlcnic_process_lro(adapter, sds_ring, + ring, sts_data0, sts_data1); + break; + case QLCNIC_RESPONSE_DESC: + qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring); + default: + goto skip; + } + + WARN_ON(desc_cnt > 1); + + if (rxbuf) + list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); + +skip: + for (; desc_cnt > 0; desc_cnt--) { + desc = &sds_ring->desc_head[consumer]; + desc->status_desc_data[0] = + cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + } + count++; + } + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + struct qlcnic_host_rds_ring *rds_ring = + &adapter->recv_ctx.rds_rings[ring]; + + if (!list_empty(&sds_ring->free_list[ring])) { + list_for_each(cur, &sds_ring->free_list[ring]) { + rxbuf = list_entry(cur, + struct qlcnic_rx_buffer, list); + qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf); + } + spin_lock(&rds_ring->lock); + list_splice_tail_init(&sds_ring->free_list[ring], + &rds_ring->free_list); + spin_unlock(&rds_ring->lock); + } + + qlcnic_post_rx_buffers_nodb(adapter, rds_ring); + } + + if (count) { + sds_ring->consumer = consumer; + writel(consumer, sds_ring->crb_sts_consumer); + } + + return count; +} + +void +qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, + struct qlcnic_host_rds_ring *rds_ring) +{ + struct rcv_desc *pdesc; + struct qlcnic_rx_buffer *buffer; + int producer, count = 0; + struct list_head *head; + + producer = rds_ring->producer; + + spin_lock(&rds_ring->lock); + head = &rds_ring->free_list; + while (!list_empty(head)) { + + buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); + + if (!buffer->skb) { + if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) + break; + } + + count++; + list_del(&buffer->list); + + /* make a rcv descriptor */ + pdesc = &rds_ring->desc_head[producer]; + pdesc->addr_buffer = cpu_to_le64(buffer->dma); + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); + + producer = get_next_index(producer, rds_ring->num_desc); + } + spin_unlock(&rds_ring->lock); + + if (count) { + rds_ring->producer = producer; + writel((producer-1) & (rds_ring->num_desc-1), + rds_ring->crb_rcv_producer); + } +} + +static void +qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *rds_ring) +{ + struct rcv_desc *pdesc; + struct qlcnic_rx_buffer *buffer; + int producer, count = 0; + struct list_head *head; + + producer = rds_ring->producer; + if (!spin_trylock(&rds_ring->lock)) + return; + + head = &rds_ring->free_list; + while (!list_empty(head)) { + + buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); + + if (!buffer->skb) { + if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) + break; + } + + count++; + list_del(&buffer->list); + + /* make a rcv descriptor */ + pdesc = &rds_ring->desc_head[producer]; + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); + pdesc->addr_buffer = cpu_to_le64(buffer->dma); + + producer = get_next_index(producer, rds_ring->num_desc); + } + + if (count) { + rds_ring->producer = producer; + writel((producer - 1) & (rds_ring->num_desc - 1), + rds_ring->crb_rcv_producer); + } + spin_unlock(&rds_ring->lock); +} + diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c new file mode 100644 index 000000000000..1698b6a68ed1 --- /dev/null +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -0,0 +1,2604 @@ +/* + * Copyright (C) 2009 - QLogic Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of 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. + * + * The full GNU General Public License is included in this distribution + * in the file called "COPYING". + * + */ + +#include +#include + +#include "qlcnic.h" + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(QLCNIC_LINUX_VERSIONID); +MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME); + +char qlcnic_driver_name[] = "qlcnic"; +static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v" + QLCNIC_LINUX_VERSIONID; + +static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG; + +/* Default to restricted 1G auto-neg mode */ +static int wol_port_mode = 5; + +static int use_msi = 1; +module_param(use_msi, int, 0644); +MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled"); + +static int use_msi_x = 1; +module_param(use_msi_x, int, 0644); +MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled"); + +static int auto_fw_reset = AUTO_FW_RESET_ENABLED; +module_param(auto_fw_reset, int, 0644); +MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled"); + +static int __devinit qlcnic_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void __devexit qlcnic_remove(struct pci_dev *pdev); +static int qlcnic_open(struct net_device *netdev); +static int qlcnic_close(struct net_device *netdev); +static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, + struct net_device *); +static void qlcnic_tx_timeout(struct net_device *netdev); +static void qlcnic_tx_timeout_task(struct work_struct *work); +static void qlcnic_attach_work(struct work_struct *work); +static void qlcnic_fwinit_work(struct work_struct *work); +static void qlcnic_fw_poll_work(struct work_struct *work); +static void qlcnic_schedule_work(struct qlcnic_adapter *adapter, + work_func_t func, int delay); +static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter); +static int qlcnic_poll(struct napi_struct *napi, int budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void qlcnic_poll_controller(struct net_device *netdev); +#endif + +static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter); +static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter); +static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter); +static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); + +static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); +static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); + +static irqreturn_t qlcnic_intr(int irq, void *data); +static irqreturn_t qlcnic_msi_intr(int irq, void *data); +static irqreturn_t qlcnic_msix_intr(int irq, void *data); + +static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev); +static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); + +/* PCI Device ID Table */ +#define ENTRY(device) \ + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ + .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} + +#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020 + +static const struct pci_device_id qlcnic_pci_tbl[] __devinitdata = { + ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), + {0,} +}; + +MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); + + +void +qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(tx_ring->producer, tx_ring->crb_cmd_producer); + + if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) { + netif_stop_queue(adapter->netdev); + smp_mb(); + } +} + +static const u32 msi_tgt_status[8] = { + ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, + ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3, + ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5, + ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7 +}; + +static const +struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG; + +static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) +{ + writel(0, sds_ring->crb_intr_mask); +} + +static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + + writel(0x1, sds_ring->crb_intr_mask); + + if (!QLCNIC_IS_MSI_FAMILY(adapter)) + writel(0xfbff, adapter->tgt_mask_reg); +} + +static int +qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count) +{ + int size = sizeof(struct qlcnic_host_sds_ring) * count; + + recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL); + + return (recv_ctx->sds_rings == NULL); +} + +static void +qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx) +{ + if (recv_ctx->sds_rings != NULL) + kfree(recv_ctx->sds_rings); + + recv_ctx->sds_rings = NULL; +} + +static int +qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) + return -ENOMEM; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + netif_napi_add(netdev, &sds_ring->napi, + qlcnic_poll, QLCNIC_NETDEV_WEIGHT); + } + + return 0; +} + +static void +qlcnic_napi_del(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + netif_napi_del(&sds_ring->napi); + } + + qlcnic_free_sds_rings(&adapter->recv_ctx); +} + +static void +qlcnic_napi_enable(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + napi_enable(&sds_ring->napi); + qlcnic_enable_int(sds_ring); + } +} + +static void +qlcnic_napi_disable(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + qlcnic_disable_int(sds_ring); + napi_synchronize(&sds_ring->napi); + napi_disable(&sds_ring->napi); + } +} + +static void qlcnic_clear_stats(struct qlcnic_adapter *adapter) +{ + memset(&adapter->stats, 0, sizeof(adapter->stats)); + return; +} + +static int qlcnic_set_dma_mask(struct qlcnic_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + u64 mask, cmask; + + adapter->pci_using_dac = 0; + + mask = DMA_BIT_MASK(39); + cmask = mask; + + if (pci_set_dma_mask(pdev, mask) == 0 && + pci_set_consistent_dma_mask(pdev, cmask) == 0) { + adapter->pci_using_dac = 1; + return 0; + } + + return -EIO; +} + +/* Update addressable range if firmware supports it */ +static int +qlcnic_update_dma_mask(struct qlcnic_adapter *adapter) +{ + int change, shift, err; + u64 mask, old_mask, old_cmask; + struct pci_dev *pdev = adapter->pdev; + + change = 0; + + shift = QLCRD32(adapter, CRB_DMA_SHIFT); + if (shift > 32) + return 0; + + if (shift > 9) + change = 1; + + if (change) { + old_mask = pdev->dma_mask; + old_cmask = pdev->dev.coherent_dma_mask; + + mask = DMA_BIT_MASK(32+shift); + + err = pci_set_dma_mask(pdev, mask); + if (err) + goto err_out; + + err = pci_set_consistent_dma_mask(pdev, mask); + if (err) + goto err_out; + dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift); + } + + return 0; + +err_out: + pci_set_dma_mask(pdev, old_mask); + pci_set_consistent_dma_mask(pdev, old_cmask); + return err; +} + +static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter) +{ + u32 val, data; + + val = adapter->ahw.board_type; + if ((val == QLCNIC_BRDTYPE_P3_HMEZ) || + (val == QLCNIC_BRDTYPE_P3_XG_LOM)) { + if (port_mode == QLCNIC_PORT_MODE_802_3_AP) { + data = QLCNIC_PORT_MODE_802_3_AP; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_XG) { + data = QLCNIC_PORT_MODE_XG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) { + data = QLCNIC_PORT_MODE_AUTO_NEG_1G; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) { + data = QLCNIC_PORT_MODE_AUTO_NEG_XG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } else { + data = QLCNIC_PORT_MODE_AUTO_NEG; + QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data); + } + + if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) && + (wol_port_mode != QLCNIC_PORT_MODE_XG) && + (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) && + (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) { + wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG; + } + QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode); + } +} + +static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable) +{ + u32 control; + int pos; + + pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_dword(pdev, pos, &control); + if (enable) + control |= PCI_MSIX_FLAGS_ENABLE; + else + control = 0; + pci_write_config_dword(pdev, pos, control); + } +} + +static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count) +{ + int i; + + for (i = 0; i < count; i++) + adapter->msix_entries[i].entry = i; +} + +static int +qlcnic_read_mac_addr(struct qlcnic_adapter *adapter) +{ + int i; + unsigned char *p; + u64 mac_addr; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0) + return -EIO; + + p = (unsigned char *)&mac_addr; + for (i = 0; i < 6; i++) + netdev->dev_addr[i] = *(p + 5 - i); + + memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); + memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len); + + /* set station address */ + + if (!is_valid_ether_addr(netdev->perm_addr)) + dev_warn(&pdev->dev, "Bad MAC address %pM.\n", + netdev->dev_addr); + + return 0; +} + +static int qlcnic_set_mac(struct net_device *netdev, void *p) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + if (netif_running(netdev)) { + netif_device_detach(netdev); + qlcnic_napi_disable(adapter); + } + + memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len); + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + qlcnic_set_multi(adapter->netdev); + + if (netif_running(netdev)) { + netif_device_attach(netdev); + qlcnic_napi_enable(adapter); + } + return 0; +} + +static const struct net_device_ops qlcnic_netdev_ops = { + .ndo_open = qlcnic_open, + .ndo_stop = qlcnic_close, + .ndo_start_xmit = qlcnic_xmit_frame, + .ndo_get_stats = qlcnic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qlcnic_set_multi, + .ndo_set_mac_address = qlcnic_set_mac, + .ndo_change_mtu = qlcnic_change_mtu, + .ndo_tx_timeout = qlcnic_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = qlcnic_poll_controller, +#endif +}; + +static void +qlcnic_setup_intr(struct qlcnic_adapter *adapter) +{ + const struct qlcnic_legacy_intr_set *legacy_intrp; + struct pci_dev *pdev = adapter->pdev; + int err, num_msix; + + if (adapter->rss_supported) { + num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? + MSIX_ENTRIES_PER_ADAPTER : 2; + } else + num_msix = 1; + + adapter->max_sds_rings = 1; + + adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); + + legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; + + adapter->int_vec_bit = legacy_intrp->int_vec_bit; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_status_reg); + adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_mask_reg); + adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR); + + adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter, + ISR_INT_STATE_REG); + + qlcnic_set_msix_bit(pdev, 0); + + if (adapter->msix_supported) { + + qlcnic_init_msix_entries(adapter, num_msix); + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->flags |= QLCNIC_MSIX_ENABLED; + qlcnic_set_msix_bit(pdev, 1); + + if (adapter->rss_supported) + adapter->max_sds_rings = num_msix; + + dev_info(&pdev->dev, "using msi-x interrupts\n"); + return; + } + + if (err > 0) + pci_disable_msix(pdev); + + /* fall through for msi */ + } + + if (use_msi && !pci_enable_msi(pdev)) { + adapter->flags |= QLCNIC_MSI_ENABLED; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + msi_tgt_status[adapter->ahw.pci_func]); + dev_info(&pdev->dev, "using msi interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; + return; + } + + dev_info(&pdev->dev, "using legacy interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; +} + +static void +qlcnic_teardown_intr(struct qlcnic_adapter *adapter) +{ + if (adapter->flags & QLCNIC_MSIX_ENABLED) + pci_disable_msix(adapter->pdev); + if (adapter->flags & QLCNIC_MSI_ENABLED) + pci_disable_msi(adapter->pdev); +} + +static void +qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) +{ + if (adapter->ahw.pci_base0 != NULL) + iounmap(adapter->ahw.pci_base0); +} + +static int +qlcnic_setup_pci_map(struct qlcnic_adapter *adapter) +{ + void __iomem *mem_ptr0 = NULL; + resource_size_t mem_base; + unsigned long mem_len, pci_len0 = 0; + + struct pci_dev *pdev = adapter->pdev; + int pci_func = adapter->ahw.pci_func; + + /* + * Set the CRB window to invalid. If any register in window 0 is + * accessed it should set the window to 0 and then reset it to 1. + */ + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; + + /* remap phys address */ + mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ + mem_len = pci_resource_len(pdev, 0); + + if (mem_len == QLCNIC_PCI_2MB_SIZE) { + + mem_ptr0 = pci_ioremap_bar(pdev, 0); + if (mem_ptr0 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + return -EIO; + } + pci_len0 = mem_len; + } else { + return -EIO; + } + + dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); + + adapter->ahw.pci_base0 = mem_ptr0; + adapter->ahw.pci_len0 = pci_len0; + + adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); + + return 0; +} + +static void get_brd_name(struct qlcnic_adapter *adapter, char *name) +{ + struct pci_dev *pdev = adapter->pdev; + int i, found = 0; + + for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) { + if (qlcnic_boards[i].vendor == pdev->vendor && + qlcnic_boards[i].device == pdev->device && + qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor && + qlcnic_boards[i].sub_device == pdev->subsystem_device) { + strcpy(name, qlcnic_boards[i].short_name); + found = 1; + break; + } + + } + + if (!found) + name = "Unknown"; +} + +static void +qlcnic_check_options(struct qlcnic_adapter *adapter) +{ + u32 fw_major, fw_minor, fw_build; + char brd_name[QLCNIC_MAX_BOARD_NAME_LEN]; + char serial_num[32]; + int i, offset, val; + int *ptr32; + struct pci_dev *pdev = adapter->pdev; + + adapter->driver_mismatch = 0; + + ptr32 = (int *)&serial_num; + offset = QLCNIC_FW_SERIAL_NUM_OFFSET; + for (i = 0; i < 8; i++) { + if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) { + dev_err(&pdev->dev, "error reading board info\n"); + adapter->driver_mismatch = 1; + return; + } + ptr32[i] = cpu_to_le32(val); + offset += sizeof(u32); + } + + fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); + fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); + fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); + + adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build); + + if (adapter->portnum == 0) { + get_brd_name(adapter, brd_name); + + pr_info("%s: %s Board Chip rev 0x%x\n", + module_name(THIS_MODULE), + brd_name, adapter->ahw.revision_id); + } + + if (adapter->fw_version < QLCNIC_VERSION_CODE(3, 4, 216)) { + adapter->driver_mismatch = 1; + dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", + fw_major, fw_minor, fw_build); + return; + } + + i = QLCRD32(adapter, QLCNIC_SRE_MISC); + adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; + + dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n", + fw_major, fw_minor, fw_build, + adapter->ahw.cut_through ? "cut-through" : "legacy"); + + if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222)) + adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~QLCNIC_LRO_ENABLED; + + if (adapter->ahw.port_type == QLCNIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == QLCNIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } + + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + + adapter->num_txd = MAX_CMD_DESCRIPTORS; + + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; +} + +static int +qlcnic_start_firmware(struct qlcnic_adapter *adapter) +{ + int val, err, first_boot; + + err = qlcnic_set_dma_mask(adapter); + if (err) + return err; + + if (!qlcnic_can_start_firmware(adapter)) + goto wait_init; + + first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc)); + if (first_boot == 0x55555555) + /* This is the first boot after power up */ + QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC); + + qlcnic_request_firmware(adapter); + + err = qlcnic_need_fw_reset(adapter); + if (err < 0) + goto err_out; + if (err == 0) + goto wait_init; + + if (first_boot != 0x55555555) { + QLCWR32(adapter, CRB_CMDPEG_STATE, 0); + qlcnic_pinit_from_rom(adapter); + msleep(1); + } + + QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555); + QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0); + QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0); + + qlcnic_set_port_mode(adapter); + + err = qlcnic_load_firmware(adapter); + if (err) + goto err_out; + + qlcnic_release_firmware(adapter); + + val = (_QLCNIC_LINUX_MAJOR << 16) + | ((_QLCNIC_LINUX_MINOR << 8)) + | (_QLCNIC_LINUX_SUBVERSION); + QLCWR32(adapter, CRB_DRIVER_VERSION, val); + +wait_init: + /* Handshake with the card before we register the devices. */ + err = qlcnic_phantom_init(adapter); + if (err) + goto err_out; + + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY); + + qlcnic_update_dma_mask(adapter); + + qlcnic_check_options(adapter); + + adapter->need_fw_reset = 0; + + /* fall through and release firmware */ + +err_out: + qlcnic_release_firmware(adapter); + return err; +} + +static int +qlcnic_request_irq(struct qlcnic_adapter *adapter) +{ + irq_handler_t handler; + struct qlcnic_host_sds_ring *sds_ring; + int err, ring; + + unsigned long flags = 0; + struct net_device *netdev = adapter->netdev; + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) + handler = qlcnic_msix_intr; + else if (adapter->flags & QLCNIC_MSI_ENABLED) + handler = qlcnic_msi_intr; + else { + flags |= IRQF_SHARED; + handler = qlcnic_intr; + } + adapter->irq = netdev->irq; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + sprintf(sds_ring->name, "%s[%d]", netdev->name, ring); + err = request_irq(sds_ring->irq, handler, + flags, sds_ring->name, sds_ring); + if (err) + return err; + } + + return 0; +} + +static void +qlcnic_free_irq(struct qlcnic_adapter *adapter) +{ + int ring; + struct qlcnic_host_sds_ring *sds_ring; + + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + free_irq(sds_ring->irq, sds_ring); + } +} + +static void +qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) +{ + adapter->coal.flags = QLCNIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; + adapter->coal.normal.data.tx_time_us = + QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US; + adapter->coal.normal.data.tx_packets = + QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS; +} + +static int +__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return -EIO; + + qlcnic_set_multi(netdev); + qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); + + adapter->ahw.linkup = 0; + + if (adapter->max_sds_rings > 1) + qlcnic_config_rss(adapter, 1); + + qlcnic_config_intr_coalesce(adapter); + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); + + qlcnic_napi_enable(adapter); + + qlcnic_linkevent_request(adapter, 1); + + set_bit(__QLCNIC_DEV_UP, &adapter->state); + return 0; +} + +/* Usage: During resume and firmware recovery module.*/ + +static int +qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + int err = 0; + + rtnl_lock(); + if (netif_running(netdev)) + err = __qlcnic_up(adapter, netdev); + rtnl_unlock(); + + return err; +} + +static void +__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state)) + return; + + smp_mb(); + spin_lock(&adapter->tx_clean_lock); + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + qlcnic_free_mac_list(adapter); + + qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE); + + qlcnic_napi_disable(adapter); + + qlcnic_release_tx_buffers(adapter); + spin_unlock(&adapter->tx_clean_lock); +} + +/* Usage: During suspend and firmware recovery module */ + +static void +qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) +{ + rtnl_lock(); + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + rtnl_unlock(); + +} + +static int +qlcnic_attach(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + int err, ring; + struct qlcnic_host_rds_ring *rds_ring; + + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) + return 0; + + err = qlcnic_init_firmware(adapter); + if (err) + return err; + + err = qlcnic_napi_add(adapter, netdev); + if (err) + return err; + + err = qlcnic_alloc_sw_resources(adapter); + if (err) { + dev_err(&pdev->dev, "Error in setting sw resources\n"); + return err; + } + + err = qlcnic_alloc_hw_resources(adapter); + if (err) { + dev_err(&pdev->dev, "Error in setting hw resources\n"); + goto err_out_free_sw; + } + + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &adapter->recv_ctx.rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, ring, rds_ring); + } + + err = qlcnic_request_irq(adapter); + if (err) { + dev_err(&pdev->dev, "failed to setup interrupt\n"); + goto err_out_free_rxbuf; + } + + qlcnic_init_coalesce_defaults(adapter); + + qlcnic_create_sysfs_entries(adapter); + + adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; + return 0; + +err_out_free_rxbuf: + qlcnic_release_rx_buffers(adapter); + qlcnic_free_hw_resources(adapter); +err_out_free_sw: + qlcnic_free_sw_resources(adapter); + return err; +} + +static void +qlcnic_detach(struct qlcnic_adapter *adapter) +{ + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + + qlcnic_remove_sysfs_entries(adapter); + + qlcnic_free_hw_resources(adapter); + qlcnic_release_rx_buffers(adapter); + qlcnic_free_irq(adapter); + qlcnic_napi_del(adapter); + qlcnic_free_sw_resources(adapter); + + adapter->is_up = 0; +} + +int +qlcnic_reset_context(struct qlcnic_adapter *adapter) +{ + int err = 0; + struct net_device *netdev = adapter->netdev; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EBUSY; + + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { + + netif_device_detach(netdev); + + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (!err) + err = __qlcnic_up(adapter, netdev); + + if (err) + goto done; + } + + netif_device_attach(netdev); + } + +done: + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return err; +} + +static int +qlcnic_setup_netdev(struct qlcnic_adapter *adapter, + struct net_device *netdev) +{ + int err; + struct pci_dev *pdev = adapter->pdev; + + adapter->rx_csum = 1; + adapter->mc_enabled = 0; + adapter->max_mc_count = 38; + + netdev->netdev_ops = &qlcnic_netdev_ops; + netdev->watchdog_timeo = 2*HZ; + + qlcnic_change_mtu(netdev, netdev->mtu); + + SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); + + netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); + netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + + if (adapter->pci_using_dac) { + netdev->features |= NETIF_F_HIGHDMA; + netdev->vlan_features |= NETIF_F_HIGHDMA; + } + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX) + netdev->features |= (NETIF_F_HW_VLAN_TX); + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + netdev->features |= NETIF_F_LRO; + + netdev->irq = adapter->msix_entries[0].vector; + + INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task); + + if (qlcnic_read_mac_addr(adapter)) + dev_warn(&pdev->dev, "failed to read mac addr\n"); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + return err; + } + + return 0; +} + +static int __devinit +qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev = NULL; + struct qlcnic_adapter *adapter = NULL; + int err; + int pci_func_id = PCI_FUNC(pdev->devfn); + uint8_t revision_id; + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + err = -ENODEV; + goto err_out_disable_pdev; + } + + err = pci_request_regions(pdev, qlcnic_driver_name); + if (err) + goto err_out_disable_pdev; + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct qlcnic_adapter)); + if (!netdev) { + dev_err(&pdev->dev, "failed to allocate net_device\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->ahw.pci_func = pci_func_id; + + revision_id = pdev->revision; + adapter->ahw.revision_id = revision_id; + + rwlock_init(&adapter->ahw.crb_lock); + mutex_init(&adapter->ahw.mem_lock); + + spin_lock_init(&adapter->tx_clean_lock); + INIT_LIST_HEAD(&adapter->mac_list); + + err = qlcnic_setup_pci_map(adapter); + if (err) + goto err_out_free_netdev; + + /* This will be reset for mezz cards */ + adapter->portnum = pci_func_id; + + err = qlcnic_get_board_info(adapter); + if (err) { + dev_err(&pdev->dev, "Error getting board config info.\n"); + goto err_out_iounmap; + } + + + err = qlcnic_start_firmware(adapter); + if (err) + goto err_out_decr_ref; + + /* + * See if the firmware gave us a virtual-physical port mapping. + */ + adapter->physical_port = adapter->portnum; + + qlcnic_clear_stats(adapter); + + qlcnic_setup_intr(adapter); + + err = qlcnic_setup_netdev(adapter, netdev); + if (err) + goto err_out_disable_msi; + + pci_set_drvdata(pdev, adapter); + + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + + switch (adapter->ahw.port_type) { + case QLCNIC_GBE: + dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", + adapter->netdev->name); + break; + case QLCNIC_XGBE: + dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", + adapter->netdev->name); + break; + } + + qlcnic_create_diag_entries(adapter); + + return 0; + +err_out_disable_msi: + qlcnic_teardown_intr(adapter); + +err_out_decr_ref: + qlcnic_clr_all_drv_state(adapter); + +err_out_iounmap: + qlcnic_cleanup_pci_map(adapter); + +err_out_free_netdev: + free_netdev(netdev); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable_pdev: + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + return err; +} + +static void __devexit qlcnic_remove(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter; + struct net_device *netdev; + + adapter = pci_get_drvdata(pdev); + if (adapter == NULL) + return; + + netdev = adapter->netdev; + + qlcnic_cancel_fw_work(adapter); + + unregister_netdev(netdev); + + cancel_work_sync(&adapter->tx_timeout_task); + + qlcnic_detach(adapter); + + qlcnic_clr_all_drv_state(adapter); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + + qlcnic_teardown_intr(adapter); + + qlcnic_remove_diag_entries(adapter); + + qlcnic_cleanup_pci_map(adapter); + + qlcnic_release_firmware(adapter); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + free_netdev(netdev); +} +static int __qlcnic_shutdown(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + int retval; + + netif_device_detach(netdev); + + qlcnic_cancel_fw_work(adapter); + + if (netif_running(netdev)) + qlcnic_down(adapter, netdev); + + cancel_work_sync(&adapter->tx_timeout_task); + + qlcnic_detach(adapter); + + qlcnic_clr_all_drv_state(adapter); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + + retval = pci_save_state(pdev); + if (retval) + return retval; + + if (qlcnic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + return 0; +} + +static void qlcnic_shutdown(struct pci_dev *pdev) +{ + if (__qlcnic_shutdown(pdev)) + return; + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int +qlcnic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + + retval = __qlcnic_shutdown(pdev); + if (retval) + return retval; + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int +qlcnic_resume(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_restore_state(pdev); + + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; + + err = qlcnic_start_firmware(adapter); + if (err) { + dev_err(&pdev->dev, "failed to start firmware\n"); + return err; + } + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto err_out; + + err = qlcnic_up(adapter, netdev); + if (err) + goto err_out_detach; + + + qlcnic_config_indev_addr(netdev, NETDEV_UP); + } + + netif_device_attach(netdev); + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + return 0; + +err_out_detach: + qlcnic_detach(adapter); +err_out: + qlcnic_clr_all_drv_state(adapter); + return err; +} +#endif + +static int qlcnic_open(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int err; + + if (adapter->driver_mismatch) + return -EIO; + + err = qlcnic_attach(adapter); + if (err) + return err; + + err = __qlcnic_up(adapter, netdev); + if (err) + goto err_out; + + netif_start_queue(netdev); + + return 0; + +err_out: + qlcnic_detach(adapter); + return err; +} + +/* + * qlcnic_close - Disables a network interface entry point + */ +static int qlcnic_close(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + __qlcnic_down(adapter, netdev); + return 0; +} + +static void +qlcnic_tso_check(struct net_device *netdev, + struct qlcnic_host_tx_ring *tx_ring, + struct cmd_desc_type0 *first_desc, + struct sk_buff *skb) +{ + u8 opcode = TX_ETHER_PKT; + __be16 protocol = skb->protocol; + u16 flags = 0, vid = 0; + u32 producer; + int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0; + struct cmd_desc_type0 *hwdesc; + struct vlan_ethhdr *vh; + + if (protocol == cpu_to_be16(ETH_P_8021Q)) { + + vh = (struct vlan_ethhdr *)skb->data; + protocol = vh->h_vlan_encapsulated_proto; + flags = FLAGS_VLAN_TAGGED; + + } else if (vlan_tx_tag_present(skb)) { + + flags = FLAGS_VLAN_OOB; + vid = vlan_tx_tag_get(skb); + qlcnic_set_tx_vlan_tci(first_desc, vid); + vlan_oob = 1; + } + + if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + skb_shinfo(skb)->gso_size > 0) { + + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + + first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + first_desc->total_hdr_length = hdr_len; + if (vlan_oob) { + first_desc->total_hdr_length += VLAN_HLEN; + first_desc->tcp_hdr_offset = VLAN_HLEN; + first_desc->ip_hdr_offset = VLAN_HLEN; + /* Only in case of TSO on vlan device */ + flags |= FLAGS_VLAN_TAGGED; + } + + opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? + TX_TCP_LSO6 : TX_TCP_LSO; + tso = 1; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + u8 l4proto; + + if (protocol == cpu_to_be16(ETH_P_IP)) { + l4proto = ip_hdr(skb)->protocol; + + if (l4proto == IPPROTO_TCP) + opcode = TX_TCP_PKT; + else if (l4proto == IPPROTO_UDP) + opcode = TX_UDP_PKT; + } else if (protocol == cpu_to_be16(ETH_P_IPV6)) { + l4proto = ipv6_hdr(skb)->nexthdr; + + if (l4proto == IPPROTO_TCP) + opcode = TX_TCPV6_PKT; + else if (l4proto == IPPROTO_UDP) + opcode = TX_UDPV6_PKT; + } + } + + first_desc->tcp_hdr_offset += skb_transport_offset(skb); + first_desc->ip_hdr_offset += skb_network_offset(skb); + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); + + if (!tso) + return; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring + */ + producer = tx_ring->producer; + copied = 0; + offset = 2; + + if (vlan_oob) { + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vid); + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len - VLAN_HLEN; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *)hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + barrier(); +} + +static int +qlcnic_map_tx_skb(struct pci_dev *pdev, + struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf) +{ + struct qlcnic_skb_frag *nf; + struct skb_frag_struct *frag; + int i, nr_frags; + dma_addr_t map; + + nr_frags = skb_shinfo(skb)->nr_frags; + nf = &pbuf->frag_array[0]; + + map = pci_map_single(pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto out_err; + + nf->dma = map; + nf->length = skb_headlen(skb); + + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nf = &pbuf->frag_array[i+1]; + + map = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto unwind; + + nf->dma = map; + nf->length = frag->size; + } + + return 0; + +unwind: + while (--i >= 0) { + nf = &pbuf->frag_array[i+1]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); + } + + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + +out_err: + return -ENOMEM; +} + +static inline void +qlcnic_clear_cmddesc(u64 *desc) +{ + desc[0] = 0ULL; + desc[2] = 0ULL; +} + +static netdev_tx_t +qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + struct qlcnic_cmd_buffer *pbuf; + struct qlcnic_skb_frag *buffrag; + struct cmd_desc_type0 *hwdesc, *first_desc; + struct pci_dev *pdev; + int i, k; + + u32 producer; + int frag_count, no_of_desc; + u32 num_txd = tx_ring->num_desc; + + frag_count = skb_shinfo(skb)->nr_frags + 1; + + /* 4 fragments per cmd des */ + no_of_desc = (frag_count + 3) >> 2; + + if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) { + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + + producer = tx_ring->producer; + pbuf = &tx_ring->cmd_buf_arr[producer]; + + pdev = adapter->pdev; + + if (qlcnic_map_tx_skb(pdev, skb, pbuf)) + goto drop_packet; + + pbuf->skb = skb; + pbuf->frag_count = frag_count; + + first_desc = hwdesc = &tx_ring->desc_head[producer]; + qlcnic_clear_cmddesc((u64 *)hwdesc); + + qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len); + qlcnic_set_tx_port(first_desc, adapter->portnum); + + for (i = 0; i < frag_count; i++) { + + k = i % 4; + + if ((k == 0) && (i > 0)) { + /* move to next desc.*/ + producer = get_next_index(producer, num_txd); + hwdesc = &tx_ring->desc_head[producer]; + qlcnic_clear_cmddesc((u64 *)hwdesc); + tx_ring->cmd_buf_arr[producer].skb = NULL; + } + + buffrag = &pbuf->frag_array[i]; + + hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length); + switch (k) { + case 0: + hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); + break; + case 1: + hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma); + break; + case 2: + hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma); + break; + case 3: + hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma); + break; + } + } + + tx_ring->producer = get_next_index(producer, num_txd); + + qlcnic_tso_check(netdev, tx_ring, first_desc, skb); + + qlcnic_update_cmd_producer(adapter, tx_ring); + + adapter->stats.txbytes += skb->len; + adapter->stats.xmitcalled++; + + return NETDEV_TX_OK; + +drop_packet: + adapter->stats.txdropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static int qlcnic_check_temp(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u32 temp, temp_state, temp_val; + int rv = 0; + + temp = QLCRD32(adapter, CRB_TEMP_STATE); + + temp_state = qlcnic_get_temp_state(temp); + temp_val = qlcnic_get_temp_val(temp); + + if (temp_state == QLCNIC_TEMP_PANIC) { + dev_err(&netdev->dev, + "Device temperature %d degrees C exceeds" + " maximum allowed. Hardware has been shut down.\n", + temp_val); + rv = 1; + } else if (temp_state == QLCNIC_TEMP_WARN) { + if (adapter->temp == QLCNIC_TEMP_NORMAL) { + dev_err(&netdev->dev, + "Device temperature %d degrees C " + "exceeds operating range." + " Immediate action needed.\n", + temp_val); + } + } else { + if (adapter->temp == QLCNIC_TEMP_WARN) { + dev_info(&netdev->dev, + "Device temperature is now %d degrees C" + " in normal range.\n", temp_val); + } + } + adapter->temp = temp_state; + return rv; +} + +void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) +{ + struct net_device *netdev = adapter->netdev; + + if (adapter->ahw.linkup && !linkup) { + dev_info(&netdev->dev, "NIC Link is down\n"); + adapter->ahw.linkup = 0; + if (netif_running(netdev)) { + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } else if (!adapter->ahw.linkup && linkup) { + dev_info(&netdev->dev, "NIC Link is up\n"); + adapter->ahw.linkup = 1; + if (netif_running(netdev)) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + } +} + +static void qlcnic_tx_timeout(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) + return; + + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); + schedule_work(&adapter->tx_timeout_task); +} + +static void qlcnic_tx_timeout_task(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = + container_of(work, struct qlcnic_adapter, tx_timeout_task); + + if (!netif_running(adapter->netdev)) + return; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return; + + if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) + goto request_reset; + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + if (!qlcnic_reset_context(adapter)) { + adapter->netdev->trans_start = jiffies; + return; + + /* context reset failed, fall through for fw reset */ + } + +request_reset: + adapter->need_fw_reset = 1; + clear_bit(__QLCNIC_RESETTING, &adapter->state); +} + +static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct net_device_stats *stats = &netdev->stats; + + memset(stats, 0, sizeof(*stats)); + + stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; + stats->tx_packets = adapter->stats.xmitfinished; + stats->rx_bytes = adapter->stats.rxbytes; + stats->tx_bytes = adapter->stats.txbytes; + stats->rx_dropped = adapter->stats.rxdropped; + stats->tx_dropped = adapter->stats.txdropped; + + return stats; +} + +static irqreturn_t qlcnic_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + u32 status; + + status = readl(adapter->isr_int_vec); + + if (!(status & adapter->int_vec_bit)) + return IRQ_NONE; + + /* check interrupt state machine, to be sure */ + status = readl(adapter->crb_int_state_reg); + if (!ISR_LEGACY_INT_TRIGGERED(status)) + return IRQ_NONE; + + writel(0xffffffff, adapter->tgt_status_reg); + /* read twice to ensure write is flushed */ + readl(adapter->isr_int_vec); + readl(adapter->isr_int_vec); + + napi_schedule(&sds_ring->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_msi_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + /* clear interrupt */ + writel(0xffffffff, adapter->tgt_status_reg); + + napi_schedule(&sds_ring->napi); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_msix_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + + napi_schedule(&sds_ring->napi); + return IRQ_HANDLED; +} + +static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter) +{ + u32 sw_consumer, hw_consumer; + int count = 0, i; + struct qlcnic_cmd_buffer *buffer; + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + struct qlcnic_skb_frag *frag; + int done; + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + + if (!spin_trylock(&adapter->tx_clean_lock)) + return 1; + + sw_consumer = tx_ring->sw_consumer; + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + + while (sw_consumer != hw_consumer) { + buffer = &tx_ring->cmd_buf_arr[sw_consumer]; + if (buffer->skb) { + frag = &buffer->frag_array[0]; + pci_unmap_single(pdev, frag->dma, frag->length, + PCI_DMA_TODEVICE); + frag->dma = 0ULL; + for (i = 1; i < buffer->frag_count; i++) { + frag++; + pci_unmap_page(pdev, frag->dma, frag->length, + PCI_DMA_TODEVICE); + frag->dma = 0ULL; + } + + adapter->stats.xmitfinished++; + dev_kfree_skb_any(buffer->skb); + buffer->skb = NULL; + } + + sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc); + if (++count >= MAX_STATUS_HANDLE) + break; + } + + if (count && netif_running(netdev)) { + tx_ring->sw_consumer = sw_consumer; + + smp_mb(); + + if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { + __netif_tx_lock(tx_ring->txq, smp_processor_id()); + if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { + netif_wake_queue(netdev); + adapter->tx_timeo_cnt = 0; + } + __netif_tx_unlock(tx_ring->txq); + } + } + /* + * If everything is freed up to consumer then check if the ring is full + * If the ring is full then check if more needs to be freed and + * schedule the call back again. + * + * This happens when there are 2 CPUs. One could be freeing and the + * other filling it. If the ring is full when we get out of here and + * the card has already interrupted the host then the host can miss the + * interrupt. + * + * There is still a possible race condition and the host could miss an + * interrupt. The card has to take care of this. + */ + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + done = (sw_consumer == hw_consumer); + spin_unlock(&adapter->tx_clean_lock); + + return done; +} + +static int qlcnic_poll(struct napi_struct *napi, int budget) +{ + struct qlcnic_host_sds_ring *sds_ring = + container_of(napi, struct qlcnic_host_sds_ring, napi); + + struct qlcnic_adapter *adapter = sds_ring->adapter; + + int tx_complete; + int work_done; + + tx_complete = qlcnic_process_cmd_ring(adapter); + + work_done = qlcnic_process_rcv_ring(sds_ring, budget); + + if ((work_done < budget) && tx_complete) { + napi_complete(&sds_ring->napi); + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) + qlcnic_enable_int(sds_ring); + } + + return work_done; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void qlcnic_poll_controller(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + disable_irq(adapter->irq); + qlcnic_intr(adapter->irq, adapter); + enable_irq(adapter->irq); +} +#endif + +static void +qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) +{ + u32 val; + + WARN_ON(state != QLCNIC_DEV_NEED_RESET && + state != QLCNIC_DEV_NEED_QUISCENT); + + if (qlcnic_api_lock(adapter)) + return ; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + + if (state == QLCNIC_DEV_NEED_RESET) + val |= ((u32)0x1 << (adapter->portnum * 4)); + else if (state == QLCNIC_DEV_NEED_QUISCENT) + val |= ((u32)0x1 << ((adapter->portnum * 4) + 1)); + + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); +} + +static void +qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter) +{ + u32 val; + + if (qlcnic_api_lock(adapter)) + goto err; + + val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + val &= ~((u32)0x1 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); + + if (!(val & 0x11111111)) + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD); + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); +err: + adapter->fw_fail_cnt = 0; + clear_bit(__QLCNIC_START_FW, &adapter->state); + clear_bit(__QLCNIC_RESETTING, &adapter->state); +} + +static int +qlcnic_check_drv_state(struct qlcnic_adapter *adapter) +{ + int act, state; + + state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + + if (((state & 0x11111111) == (act & 0x11111111)) || + ((act & 0x11111111) == ((state >> 1) & 0x11111111))) + return 0; + else + return 1; +} + +static int +qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) +{ + u32 val, prev_state; + int cnt = 0; + int portnum = adapter->portnum; + + if (qlcnic_api_lock(adapter)) + return -1; + + val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); + if (!(val & ((int)0x1 << (portnum * 4)))) { + val |= ((u32)0x1 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); + } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) { + goto start_fw; + } + + prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + + switch (prev_state) { + case QLCNIC_DEV_COLD: +start_fw: + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING); + qlcnic_api_unlock(adapter); + return 1; + + case QLCNIC_DEV_READY: + qlcnic_api_unlock(adapter); + return 0; + + case QLCNIC_DEV_NEED_RESET: + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val |= ((u32)0x1 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + break; + + case QLCNIC_DEV_NEED_QUISCENT: + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val |= ((u32)0x1 << ((portnum * 4) + 1)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + break; + + case QLCNIC_DEV_FAILED: + qlcnic_api_unlock(adapter); + return -1; + } + + qlcnic_api_unlock(adapter); + msleep(1000); + while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) && + ++cnt < 20) + msleep(1000); + + if (cnt >= 20) + return -1; + + if (qlcnic_api_lock(adapter)) + return -1; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); + + return 0; +} + +static void +qlcnic_fwinit_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + int dev_state; + + if (++adapter->fw_wait_cnt > FW_POLL_THRESH) + goto err_ret; + + if (test_bit(__QLCNIC_START_FW, &adapter->state)) { + + if (qlcnic_check_drv_state(adapter)) { + qlcnic_schedule_work(adapter, + qlcnic_fwinit_work, FW_POLL_DELAY); + return; + } + + if (!qlcnic_start_firmware(adapter)) { + qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); + return; + } + + goto err_ret; + } + + dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + switch (dev_state) { + case QLCNIC_DEV_READY: + if (!qlcnic_start_firmware(adapter)) { + qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); + return; + } + case QLCNIC_DEV_FAILED: + break; + + default: + qlcnic_schedule_work(adapter, + qlcnic_fwinit_work, 2 * FW_POLL_DELAY); + return; + } + +err_ret: + qlcnic_clr_all_drv_state(adapter); +} + +static void +qlcnic_detach_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + u32 status; + + netif_device_detach(netdev); + + qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); + + if (status & QLCNIC_RCODE_FATAL_ERROR) + goto err_ret; + + if (adapter->temp == QLCNIC_TEMP_PANIC) + goto err_ret; + + qlcnic_set_drv_state(adapter, adapter->dev_state); + + adapter->fw_wait_cnt = 0; + + qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY); + + return; + +err_ret: + qlcnic_clr_all_drv_state(adapter); + +} + +static void +qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) +{ + u32 state; + + if (qlcnic_api_lock(adapter)) + return; + + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + + if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) { + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); + set_bit(__QLCNIC_START_FW, &adapter->state); + } + + qlcnic_api_unlock(adapter); +} + +static void +qlcnic_schedule_work(struct qlcnic_adapter *adapter, + work_func_t func, int delay) +{ + INIT_DELAYED_WORK(&adapter->fw_work, func); + schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay)); +} + +static void +qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter) +{ + while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + msleep(10); + + cancel_delayed_work_sync(&adapter->fw_work); +} + +static void +qlcnic_attach_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int err; + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto done; + + err = qlcnic_up(adapter, netdev); + if (err) { + qlcnic_detach(adapter); + goto done; + } + + qlcnic_config_indev_addr(netdev, NETDEV_UP); + } + + netif_device_attach(netdev); + +done: + adapter->fw_fail_cnt = 0; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); +} + +static int +qlcnic_check_health(struct qlcnic_adapter *adapter) +{ + u32 state = 0, heartbit; + struct net_device *netdev = adapter->netdev; + + if (qlcnic_check_temp(adapter)) + goto detach; + + if (adapter->need_fw_reset) { + qlcnic_dev_request_reset(adapter); + goto detach; + } + + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT) + adapter->need_fw_reset = 1; + + heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); + if (heartbit != adapter->heartbit) { + adapter->heartbit = heartbit; + adapter->fw_fail_cnt = 0; + if (adapter->need_fw_reset) + goto detach; + return 0; + } + + if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) + return 0; + + qlcnic_dev_request_reset(adapter); + + clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state); + + dev_info(&netdev->dev, "firmware hang detected\n"); + +detach: + adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state : + QLCNIC_DEV_NEED_RESET; + + if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) && + !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + qlcnic_schedule_work(adapter, qlcnic_detach_work, 0); + + return 1; +} + +static void +qlcnic_fw_poll_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter = container_of(work, + struct qlcnic_adapter, fw_work.work); + + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) + goto reschedule; + + + if (qlcnic_check_health(adapter)) + return; + +reschedule: + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); +} + +static ssize_t +qlcnic_store_bridged_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + unsigned long new; + int ret = -EINVAL; + + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)) + goto err_out; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto err_out; + + if (strict_strtoul(buf, 2, &new)) + goto err_out; + + if (!qlcnic_config_bridged_mode(adapter, !!new)) + ret = len; + +err_out: + return ret; +} + +static ssize_t +qlcnic_show_bridged_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + int bridged_mode = 0; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED); + + return sprintf(buf, "%d\n", bridged_mode); +} + +static struct device_attribute dev_attr_bridged_mode = { + .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_bridged_mode, + .store = qlcnic_store_bridged_mode, +}; + +static ssize_t +qlcnic_store_diag_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + unsigned long new; + + if (strict_strtoul(buf, 2, &new)) + return -EINVAL; + + if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED)) + adapter->flags ^= QLCNIC_DIAG_ENABLED; + + return len; +} + +static ssize_t +qlcnic_show_diag_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", + !!(adapter->flags & QLCNIC_DIAG_ENABLED)); +} + +static struct device_attribute dev_attr_diag_mode = { + .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_diag_mode, + .store = qlcnic_store_diag_mode, +}; + +static int +qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 4) || (offset & 0x3)) + return -EINVAL; + + if (offset < QLCNIC_PCI_CRBSPACE) + return -EINVAL; + + return 0; +} + +static ssize_t +qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = qlcnic_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + data = QLCRD32(adapter, offset); + memcpy(buf, &data, size); + return size; +} + +static ssize_t +qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = qlcnic_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + QLCWR32(adapter, offset, data); + return size; +} + +static int +qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 8) || (offset & 0x7)) + return -EIO; + + return 0; +} + +static ssize_t +qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = qlcnic_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + if (qlcnic_pci_mem_read_2M(adapter, offset, &data)) + return -EIO; + + memcpy(buf, &data, size); + + return size; +} + +static ssize_t +qlcnic_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = qlcnic_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + + if (qlcnic_pci_mem_write_2M(adapter, offset, data)) + return -EIO; + + return size; +} + + +static struct bin_attribute bin_attr_crb = { + .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_crb, + .write = qlcnic_sysfs_write_crb, +}; + +static struct bin_attribute bin_attr_mem = { + .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_mem, + .write = qlcnic_sysfs_write_mem, +}; + +static void +qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + if (device_create_file(dev, &dev_attr_bridged_mode)) + dev_warn(dev, + "failed to create bridged_mode sysfs entry\n"); +} + +static void +qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG) + device_remove_file(dev, &dev_attr_bridged_mode); +} + +static void +qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + if (device_create_file(dev, &dev_attr_diag_mode)) + dev_info(dev, "failed to create diag_mode sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_crb)) + dev_info(dev, "failed to create crb sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_mem)) + dev_info(dev, "failed to create mem sysfs entry\n"); +} + + +static void +qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + + device_remove_file(dev, &dev_attr_diag_mode); + device_remove_bin_file(dev, &bin_attr_crb); + device_remove_bin_file(dev, &bin_attr_mem); +} + +#ifdef CONFIG_INET + +#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops) + +static int +qlcnic_destip_supported(struct qlcnic_adapter *adapter) +{ + if (adapter->ahw.cut_through) + return 0; + + return 1; +} + +static void +qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) +{ + struct in_device *indev; + struct qlcnic_adapter *adapter = netdev_priv(dev); + + if (!qlcnic_destip_supported(adapter)) + return; + + indev = in_dev_get(dev); + if (!indev) + return; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + qlcnic_config_ipaddr(adapter, + ifa->ifa_address, QLCNIC_IP_UP); + break; + case NETDEV_DOWN: + qlcnic_config_ipaddr(adapter, + ifa->ifa_address, QLCNIC_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); + return; +} + +static int qlcnic_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct qlcnic_adapter *adapter; + struct net_device *dev = (struct net_device *)ptr; + +recheck: + if (dev == NULL) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_qlcnic_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter) + goto done; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto done; + + qlcnic_config_indev_addr(dev, event); +done: + return NOTIFY_DONE; +} + +static int +qlcnic_inetaddr_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct qlcnic_adapter *adapter; + struct net_device *dev; + + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; + +recheck: + if (dev == NULL || !netif_running(dev)) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_qlcnic_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !qlcnic_destip_supported(adapter)) + goto done; + + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + goto done; + + switch (event) { + case NETDEV_UP: + qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP); + break; + case NETDEV_DOWN: + qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN); + break; + default: + break; + } + +done: + return NOTIFY_DONE; +} + +static struct notifier_block qlcnic_netdev_cb = { + .notifier_call = qlcnic_netdev_event, +}; + +static struct notifier_block qlcnic_inetaddr_cb = { + .notifier_call = qlcnic_inetaddr_event, +}; +#else +static void +qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) +{ } +#endif + +static struct pci_driver qlcnic_driver = { + .name = qlcnic_driver_name, + .id_table = qlcnic_pci_tbl, + .probe = qlcnic_probe, + .remove = __devexit_p(qlcnic_remove), +#ifdef CONFIG_PM + .suspend = qlcnic_suspend, + .resume = qlcnic_resume, +#endif + .shutdown = qlcnic_shutdown +}; + +static int __init qlcnic_init_module(void) +{ + + printk(KERN_INFO "%s\n", qlcnic_driver_string); + +#ifdef CONFIG_INET + register_netdevice_notifier(&qlcnic_netdev_cb); + register_inetaddr_notifier(&qlcnic_inetaddr_cb); +#endif + + + return pci_register_driver(&qlcnic_driver); +} + +module_init(qlcnic_init_module); + +static void __exit qlcnic_exit_module(void) +{ + + pci_unregister_driver(&qlcnic_driver); + +#ifdef CONFIG_INET + unregister_inetaddr_notifier(&qlcnic_inetaddr_cb); + unregister_netdevice_notifier(&qlcnic_netdev_cb); +#endif +} + +module_exit(qlcnic_exit_module); -- GitLab From 0ec00f0392b807d57a2281576a96552d7694b6bb Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 13 Jan 2010 00:37:26 +0000 Subject: [PATCH 0789/3892] NET: Add Qlogic ethernet driver for CNA devices o Separate Ethernet driver for Qlogic CNA devices Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++++++ drivers/net/Kconfig | 7 +++++++ drivers/net/Makefile | 1 + 3 files changed, 15 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 337dffbe9a47..61367ec865cb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4452,6 +4452,13 @@ S: Supported F: Documentation/networking/LICENSE.qla3xxx F: drivers/net/qla3xxx.* +QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER +M: Amit Kumar Salecha +M: linux-driver@qlogic.com +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/qlcnic/ + QLOGIC QLGE 10Gb ETHERNET DRIVER M: Ron Mercer M: linux-driver@qlogic.com diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5be6a2376f4f..cb0e534418e3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2778,6 +2778,13 @@ config BNX2X To compile this driver as a module, choose M here: the module will be called bnx2x. This is recommended. +config QLCNIC + tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support" + depends on PCI + help + This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet + devices. + config QLGE tristate "QLogic QLGE 10Gb Ethernet Driver Support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6746e8b8bdfc..0b763cbe9b1f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -149,6 +149,7 @@ ll_temac-objs := ll_temac_main.o ll_temac_mdio.o obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o +obj-$(CONFIG_QLCNIC) += qlcnic/ obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_PPP) += ppp_generic.o -- GitLab From 4c54005ca438a8b46dd542b497d4f0dc2ca375e8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 14 Jan 2010 16:10:57 -0800 Subject: [PATCH 0790/3892] rcu: 1Q2010 update for RCU documentation Add expedited functions. Review documentation and update obsolete verbiage. Also fix the advice for the RCU CPU-stall kernel configuration parameter, and document RCU CPU-stall warnings. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12635142581866-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/00-INDEX | 8 +- Documentation/RCU/RTFP.txt | 58 +++++- Documentation/RCU/checklist.txt | 200 +++++++++++-------- Documentation/RCU/rcu.txt | 48 +---- Documentation/RCU/stallwarn.txt | 58 ++++++ Documentation/RCU/torture.txt | 12 ++ Documentation/RCU/whatisRCU.txt | 3 +- Documentation/filesystems/dentry-locking.txt | 3 +- lib/Kconfig.debug | 4 +- 9 files changed, 258 insertions(+), 136 deletions(-) create mode 100644 Documentation/RCU/stallwarn.txt diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index 9bb62f7b89c3..0a27ea9621fa 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -8,14 +8,18 @@ listRCU.txt - Using RCU to Protect Read-Mostly Linked Lists NMI-RCU.txt - Using RCU to Protect Dynamic NMI Handlers +rcubarrier.txt + - RCU and Unloadable Modules +rculist_nulls.txt + - RCU list primitives for use with SLAB_DESTROY_BY_RCU rcuref.txt - Reference-count design for elements of lists/arrays protected by RCU rcu.txt - RCU Concepts -rcubarrier.txt - - Unloading modules that use RCU callbacks RTFP.txt - List of RCU papers (bibliography) going back to 1980. +stallwarn.txt + - RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR) torture.txt - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST) trace.txt diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index d2b85237c76e..5051209e6835 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -25,10 +25,10 @@ to be referencing the data structure. However, this mechanism was not optimized for modern computer systems, which is not surprising given that these overheads were not so expensive in the mid-80s. Nonetheless, passive serialization appears to be the first deferred-destruction -mechanism to be used in production. Furthermore, the relevant patent has -lapsed, so this approach may be used in non-GPL software, if desired. -(In contrast, use of RCU is permitted only in software licensed under -GPL. Sorry!!!) +mechanism to be used in production. Furthermore, the relevant patent +has lapsed, so this approach may be used in non-GPL software, if desired. +(In contrast, implementation of RCU is permitted only in software licensed +under either GPL or LGPL. Sorry!!!) In 1990, Pugh [Pugh90] noted that explicitly tracking which threads were reading a given data structure permitted deferred free to operate @@ -150,6 +150,18 @@ preemptible RCU [PaulEMcKenney2007PreemptibleRCU], and the three-part LWN "What is RCU?" series [PaulEMcKenney2007WhatIsRCUFundamentally, PaulEMcKenney2008WhatIsRCUUsage, and PaulEMcKenney2008WhatIsRCUAPI]. +2008 saw a journal paper on real-time RCU [DinakarGuniguntala2008IBMSysJ], +a history of how Linux changed RCU more than RCU changed Linux +[PaulEMcKenney2008RCUOSR], and a design overview of hierarchical RCU +[PaulEMcKenney2008HierarchicalRCU]. + +2009 introduced user-level RCU algorithms [PaulEMcKenney2009MaliciousURCU], +which Mathieu Desnoyers is now maintaining [MathieuDesnoyers2009URCU] +[MathieuDesnoyersPhD]. TINY_RCU [PaulEMcKenney2009BloatWatchRCU] made +its appearance, as did expedited RCU [PaulEMcKenney2009expeditedRCU]. +The problem of resizeable RCU-protected hash tables may now be on a path +to a solution [JoshTriplett2009RPHash]. + Bibtex Entries @article{Kung80 @@ -730,6 +742,11 @@ Revised: " } +# +# "What is RCU?" LWN series. +# +######################################################################## + @article{DinakarGuniguntala2008IBMSysJ ,author="D. Guniguntala and P. E. McKenney and J. Triplett and J. Walpole" ,title="The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with {Linux}" @@ -820,3 +837,36 @@ Revised: Uniprocessor assumptions allow simplified RCU implementation. " } + +@unpublished{PaulEMcKenney2009expeditedRCU +,Author="Paul E. McKenney" +,Title="[{PATCH} -tip 0/3] expedited 'big hammer' {RCU} grace periods" +,month="June" +,day="25" +,year="2009" +,note="Available: +\url{http://lkml.org/lkml/2009/6/25/306} +[Viewed August 16, 2009]" +,annotation=" + First posting of expedited RCU to be accepted into -tip. +" +} + +@unpublished{JoshTriplett2009RPHash +,Author="Josh Triplett" +,Title="Scalable concurrent hash tables via relativistic programming" +,month="September" +,year="2009" +,note="Linux Plumbers Conference presentation" +,annotation=" + RP fun with hash tables. +" +} + +@phdthesis{MathieuDesnoyersPhD +, title = "Low-impact Operating System Tracing" +, author = "Mathieu Desnoyers" +, school = "Ecole Polytechnique de Montr\'{e}al" +, month = "December" +, year = 2009 +} diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 51525a30e8b4..767cf06a4276 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -8,13 +8,12 @@ would cause. This list is based on experiences reviewing such patches over a rather long period of time, but improvements are always welcome! 0. Is RCU being applied to a read-mostly situation? If the data - structure is updated more than about 10% of the time, then - you should strongly consider some other approach, unless - detailed performance measurements show that RCU is nonetheless - the right tool for the job. Yes, you might think of RCU - as simply cutting overhead off of the readers and imposing it - on the writers. That is exactly why normal uses of RCU will - do much more reading than updating. + structure is updated more than about 10% of the time, then you + should strongly consider some other approach, unless detailed + performance measurements show that RCU is nonetheless the right + tool for the job. Yes, RCU does reduce read-side overhead by + increasing write-side overhead, which is exactly why normal uses + of RCU will do much more reading than updating. Another exception is where performance is not an issue, and RCU provides a simpler implementation. An example of this situation @@ -35,13 +34,13 @@ over a rather long period of time, but improvements are always welcome! If you choose #b, be prepared to describe how you have handled memory barriers on weakly ordered machines (pretty much all of - them -- even x86 allows reads to be reordered), and be prepared - to explain why this added complexity is worthwhile. If you - choose #c, be prepared to explain how this single task does not - become a major bottleneck on big multiprocessor machines (for - example, if the task is updating information relating to itself - that other tasks can read, there by definition can be no - bottleneck). + them -- even x86 allows later loads to be reordered to precede + earlier stores), and be prepared to explain why this added + complexity is worthwhile. If you choose #c, be prepared to + explain how this single task does not become a major bottleneck on + big multiprocessor machines (for example, if the task is updating + information relating to itself that other tasks can read, there + by definition can be no bottleneck). 2. Do the RCU read-side critical sections make proper use of rcu_read_lock() and friends? These primitives are needed @@ -51,8 +50,10 @@ over a rather long period of time, but improvements are always welcome! actuarial risk of your kernel. As a rough rule of thumb, any dereference of an RCU-protected - pointer must be covered by rcu_read_lock() or rcu_read_lock_bh() - or by the appropriate update-side lock. + pointer must be covered by rcu_read_lock(), rcu_read_lock_bh(), + rcu_read_lock_sched(), or by the appropriate update-side lock. + Disabling of preemption can serve as rcu_read_lock_sched(), but + is less readable. 3. Does the update code tolerate concurrent accesses? @@ -62,25 +63,27 @@ over a rather long period of time, but improvements are always welcome! of ways to handle this concurrency, depending on the situation: a. Use the RCU variants of the list and hlist update - primitives to add, remove, and replace elements on an - RCU-protected list. Alternatively, use the RCU-protected - trees that have been added to the Linux kernel. + primitives to add, remove, and replace elements on + an RCU-protected list. Alternatively, use the other + RCU-protected data structures that have been added to + the Linux kernel. This is almost always the best approach. b. Proceed as in (a) above, but also maintain per-element locks (that are acquired by both readers and writers) that guard per-element state. Of course, fields that - the readers refrain from accessing can be guarded by the - update-side lock. + the readers refrain from accessing can be guarded by + some other lock acquired only by updaters, if desired. This works quite well, also. c. Make updates appear atomic to readers. For example, - pointer updates to properly aligned fields will appear - atomic, as will individual atomic primitives. Operations - performed under a lock and sequences of multiple atomic - primitives will -not- appear to be atomic. + pointer updates to properly aligned fields will + appear atomic, as will individual atomic primitives. + Sequences of perations performed under a lock will -not- + appear to be atomic to RCU readers, nor will sequences + of multiple atomic primitives. This can work, but is starting to get a bit tricky. @@ -98,9 +101,9 @@ over a rather long period of time, but improvements are always welcome! a new structure containing updated values. 4. Weakly ordered CPUs pose special challenges. Almost all CPUs - are weakly ordered -- even i386 CPUs allow reads to be reordered. - RCU code must take all of the following measures to prevent - memory-corruption problems: + are weakly ordered -- even x86 CPUs allow later loads to be + reordered to precede earlier stores. RCU code must take all of + the following measures to prevent memory-corruption problems: a. Readers must maintain proper ordering of their memory accesses. The rcu_dereference() primitive ensures that @@ -113,14 +116,21 @@ over a rather long period of time, but improvements are always welcome! The rcu_dereference() primitive is also an excellent documentation aid, letting the person reading the code know exactly which pointers are protected by RCU. - - The rcu_dereference() primitive is used by the various - "_rcu()" list-traversal primitives, such as the - list_for_each_entry_rcu(). Note that it is perfectly - legal (if redundant) for update-side code to use - rcu_dereference() and the "_rcu()" list-traversal - primitives. This is particularly useful in code - that is common to readers and updaters. + Please note that compilers can also reorder code, and + they are becoming increasingly aggressive about doing + just that. The rcu_dereference() primitive therefore + also prevents destructive compiler optimizations. + + The rcu_dereference() primitive is used by the + various "_rcu()" list-traversal primitives, such + as the list_for_each_entry_rcu(). Note that it is + perfectly legal (if redundant) for update-side code to + use rcu_dereference() and the "_rcu()" list-traversal + primitives. This is particularly useful in code that + is common to readers and updaters. However, neither + rcu_dereference() nor the "_rcu()" list-traversal + primitives can substitute for a good concurrency design + coordinating among multiple updaters. b. If the list macros are being used, the list_add_tail_rcu() and list_add_rcu() primitives must be used in order @@ -135,11 +145,14 @@ over a rather long period of time, but improvements are always welcome! readers. Similarly, if the hlist macros are being used, the hlist_del_rcu() primitive is required. - The list_replace_rcu() primitive may be used to - replace an old structure with a new one in an - RCU-protected list. + The list_replace_rcu() and hlist_replace_rcu() primitives + may be used to replace an old structure with a new one + in their respective types of RCU-protected lists. + + d. Rules similar to (4b) and (4c) apply to the "hlist_nulls" + type of RCU-protected linked lists. - d. Updates must ensure that initialization of a given + e. Updates must ensure that initialization of a given structure happens before pointers to that structure are publicized. Use the rcu_assign_pointer() primitive when publicizing a pointer to a structure that can @@ -151,16 +164,31 @@ over a rather long period of time, but improvements are always welcome! it cannot block. 6. Since synchronize_rcu() can block, it cannot be called from - any sort of irq context. Ditto for synchronize_sched() and - synchronize_srcu(). - -7. If the updater uses call_rcu(), then the corresponding readers - must use rcu_read_lock() and rcu_read_unlock(). If the updater - uses call_rcu_bh(), then the corresponding readers must use - rcu_read_lock_bh() and rcu_read_unlock_bh(). If the updater - uses call_rcu_sched(), then the corresponding readers must - disable preemption. Mixing things up will result in confusion - and broken kernels. + any sort of irq context. The same rule applies for + synchronize_rcu_bh(), synchronize_sched(), synchronize_srcu(), + synchronize_rcu_expedited(), synchronize_rcu_bh_expedited(), + synchronize_sched_expedite(), and synchronize_srcu_expedited(). + + The expedited forms of these primitives have the same semantics + as the non-expedited forms, but expediting is both expensive + and unfriendly to real-time workloads. Use of the expedited + primitives should be restricted to rare configuration-change + operations that would not normally be undertaken while a real-time + workload is running. + +7. If the updater uses call_rcu() or synchronize_rcu(), then the + corresponding readers must use rcu_read_lock() and + rcu_read_unlock(). If the updater uses call_rcu_bh() or + synchronize_rcu_bh(), then the corresponding readers must + use rcu_read_lock_bh() and rcu_read_unlock_bh(). If the + updater uses call_rcu_sched() or synchronize_sched(), then + the corresponding readers must disable preemption, possibly + by calling rcu_read_lock_sched() and rcu_read_unlock_sched(). + If the updater uses synchronize_srcu(), the the corresponding + readers must use srcu_read_lock() and srcu_read_unlock(), + and with the same srcu_struct. The rules for the expedited + primitives are the same as for their non-expedited counterparts. + Mixing things up will result in confusion and broken kernels. One exception to this rule: rcu_read_lock() and rcu_read_unlock() may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh() @@ -212,6 +240,8 @@ over a rather long period of time, but improvements are always welcome! e. Periodically invoke synchronize_rcu(), permitting a limited number of updates per grace period. + The same cautions apply to call_rcu_bh() and call_rcu_sched(). + 9. All RCU list-traversal primitives, which include rcu_dereference(), list_for_each_entry_rcu(), list_for_each_continue_rcu(), and list_for_each_safe_rcu(), @@ -229,7 +259,8 @@ over a rather long period of time, but improvements are always welcome! 10. Conversely, if you are in an RCU read-side critical section, and you don't hold the appropriate update-side lock, you -must- use the "_rcu()" variants of the list macros. Failing to do so - will break Alpha and confuse people reading your code. + will break Alpha, cause aggressive compilers to generate bad code, + and confuse people trying to read your code. 11. Note that synchronize_rcu() -only- guarantees to wait until all currently executing rcu_read_lock()-protected RCU read-side @@ -239,15 +270,21 @@ over a rather long period of time, but improvements are always welcome! rcu_read_lock()-protected read-side critical sections, do -not- use synchronize_rcu(). - If you want to wait for some of these other things, you might - instead need to use synchronize_irq() or synchronize_sched(). + Similarly, disabling preemption is not an acceptable substitute + for rcu_read_lock(). Code that attempts to use preemption + disabling where it should be using rcu_read_lock() will break + in real-time kernel builds. + + If you want to wait for interrupt handlers, NMI handlers, and + code under the influence of preempt_disable(), you instead + need to use synchronize_irq() or synchronize_sched(). 12. Any lock acquired by an RCU callback must be acquired elsewhere with softirq disabled, e.g., via spin_lock_irqsave(), spin_lock_bh(), etc. Failing to disable irq on a given - acquisition of that lock will result in deadlock as soon as the - RCU callback happens to interrupt that acquisition's critical - section. + acquisition of that lock will result in deadlock as soon as + the RCU softirq handler happens to run your RCU callback while + interrupting that acquisition's critical section. 13. RCU callbacks can be and are executed in parallel. In many cases, the callback code simply wrappers around kfree(), so that this @@ -265,29 +302,30 @@ over a rather long period of time, but improvements are always welcome! not the case, a self-spawning RCU callback would prevent the victim CPU from ever going offline.) -14. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) - may only be invoked from process context. Unlike other forms of - RCU, it -is- permissible to block in an SRCU read-side critical - section (demarked by srcu_read_lock() and srcu_read_unlock()), - hence the "SRCU": "sleepable RCU". Please note that if you - don't need to sleep in read-side critical sections, you should - be using RCU rather than SRCU, because RCU is almost always - faster and easier to use than is SRCU. +14. SRCU (srcu_read_lock(), srcu_read_unlock(), synchronize_srcu(), + and synchronize_srcu_expedited()) may only be invoked from + process context. Unlike other forms of RCU, it -is- permissible + to block in an SRCU read-side critical section (demarked by + srcu_read_lock() and srcu_read_unlock()), hence the "SRCU": + "sleepable RCU". Please note that if you don't need to sleep + in read-side critical sections, you should be using RCU rather + than SRCU, because RCU is almost always faster and easier to + use than is SRCU. Also unlike other forms of RCU, explicit initialization and cleanup is required via init_srcu_struct() and cleanup_srcu_struct(). These are passed a "struct srcu_struct" that defines the scope of a given SRCU domain. Once initialized, the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock() - and synchronize_srcu(). A given synchronize_srcu() waits only - for SRCU read-side critical sections governed by srcu_read_lock() - and srcu_read_unlock() calls that have been passd the same - srcu_struct. This property is what makes sleeping read-side - critical sections tolerable -- a given subsystem delays only - its own updates, not those of other subsystems using SRCU. - Therefore, SRCU is less prone to OOM the system than RCU would - be if RCU's read-side critical sections were permitted to - sleep. + synchronize_srcu(), and synchronize_srcu_expedited(). A given + synchronize_srcu() waits only for SRCU read-side critical + sections governed by srcu_read_lock() and srcu_read_unlock() + calls that have been passed the same srcu_struct. This property + is what makes sleeping read-side critical sections tolerable -- + a given subsystem delays only its own updates, not those of other + subsystems using SRCU. Therefore, SRCU is less prone to OOM the + system than RCU would be if RCU's read-side critical sections + were permitted to sleep. The ability to sleep in read-side critical sections does not come for free. First, corresponding srcu_read_lock() and @@ -311,12 +349,12 @@ over a rather long period of time, but improvements are always welcome! destructive operation, and -only- -then- invoke call_rcu(), synchronize_rcu(), or friends. - Because these primitives only wait for pre-existing readers, - it is the caller's responsibility to guarantee safety to - any subsequent readers. + Because these primitives only wait for pre-existing readers, it + is the caller's responsibility to guarantee that any subsequent + readers will execute safely. -16. The various RCU read-side primitives do -not- contain memory - barriers. The CPU (and in some cases, the compiler) is free - to reorder code into and out of RCU read-side critical sections. - It is the responsibility of the RCU update-side primitives to - deal with this. +16. The various RCU read-side primitives do -not- necessarily contain + memory barriers. You should therefore plan for the CPU + and the compiler to freely reorder code into and out of RCU + read-side critical sections. It is the responsibility of the + RCU update-side primitives to deal with this. diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 2a23523ce471..31852705b586 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -75,6 +75,8 @@ o I hear that RCU is patented? What is with that? search for the string "Patent" in RTFP.txt to find them. Of these, one was allowed to lapse by the assignee, and the others have been contributed to the Linux kernel under GPL. + There are now also LGPL implementations of user-level RCU + available (http://lttng.org/?q=node/18). o I hear that RCU needs work in order to support realtime kernels? @@ -91,48 +93,4 @@ o Where can I find more information on RCU? o What are all these files in this directory? - - NMI-RCU.txt - - Describes how to use RCU to implement dynamic - NMI handlers, which can be revectored on the fly, - without rebooting. - - RTFP.txt - - List of RCU-related publications and web sites. - - UP.txt - - Discussion of RCU usage in UP kernels. - - arrayRCU.txt - - Describes how to use RCU to protect arrays, with - resizeable arrays whose elements reference other - data structures being of the most interest. - - checklist.txt - - Lists things to check for when inspecting code that - uses RCU. - - listRCU.txt - - Describes how to use RCU to protect linked lists. - This is the simplest and most common use of RCU - in the Linux kernel. - - rcu.txt - - You are reading it! - - rcuref.txt - - Describes how to combine use of reference counts - with RCU. - - whatisRCU.txt - - Overview of how the RCU implementation works. Along - the way, presents a conceptual view of RCU. + See 00-INDEX for the list. diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt new file mode 100644 index 000000000000..1423d2570d78 --- /dev/null +++ b/Documentation/RCU/stallwarn.txt @@ -0,0 +1,58 @@ +Using RCU's CPU Stall Detector + +The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables +RCU's CPU stall detector, which detects conditions that unduly delay +RCU grace periods. The stall detector's idea of what constitutes +"unduly delayed" is controlled by a pair of C preprocessor macros: + +RCU_SECONDS_TILL_STALL_CHECK + + This macro defines the period of time that RCU will wait from + the beginning of a grace period until it issues an RCU CPU + stall warning. It is normally ten seconds. + +RCU_SECONDS_TILL_STALL_RECHECK + + This macro defines the period of time that RCU will wait after + issuing a stall warning until it issues another stall warning. + It is normally set to thirty seconds. + +RCU_STALL_RAT_DELAY + + The CPU stall detector tries to make the offending CPU rat on itself, + as this often gives better-quality stack traces. However, if + the offending CPU does not detect its own stall in the number + of jiffies specified by RCU_STALL_RAT_DELAY, then other CPUs will + complain. This is normally set to two jiffies. + +The following problems can result in an RCU CPU stall warning: + +o A CPU looping in an RCU read-side critical section. + +o A CPU looping with interrupts disabled. + +o A CPU looping with preemption disabled. + +o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel + without invoking schedule(). + +o A bug in the RCU implementation. + +o A hardware failure. This is quite unlikely, but has occurred + at least once in a former life. A CPU failed in a running system, + becoming unresponsive, but not causing an immediate crash. + This resulted in a series of RCU CPU stall warnings, eventually + leading the realization that the CPU had failed. + +The RCU, RCU-sched, and RCU-bh implementations have CPU stall warning. +SRCU does not do so directly, but its calls to synchronize_sched() will +result in RCU-sched detecting any CPU stalls that might be occurring. + +To diagnose the cause of the stall, inspect the stack traces. The offending +function will usually be near the top of the stack. If you have a series +of stall warnings from a single extended stall, comparing the stack traces +can often help determine where the stall is occurring, which will usually +be in the function nearest the top of the stack that stays the same from +trace to trace. + +RCU bugs can often be debugged with the help of CONFIG_RCU_TRACE. diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 9dba3bb90e60..0e50bc2aa1e2 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -30,6 +30,18 @@ MODULE PARAMETERS This module has the following parameters: +fqs_duration Duration (in microseconds) of artificially induced bursts + of force_quiescent_state() invocations. In RCU + implementations having force_quiescent_state(), these + bursts help force races between forcing a given grace + period and that grace period ending on its own. + +fqs_holdoff Holdoff time (in microseconds) between consecutive calls + to force_quiescent_state() within a burst. + +fqs_stutter Wait time (in seconds) between consecutive bursts + of calls to force_quiescent_state(). + irqreaders Says to invoke RCU readers from irq level. This is currently done via timers. Defaults to "1" for variants of RCU that permit this. (Or, more accurately, variants of RCU that do diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index d542ca243b80..469a58b2e67e 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -327,7 +327,8 @@ a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock() b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh() -c. synchronize_sched() preempt_disable() / preempt_enable() +c. synchronize_sched() rcu_read_lock_sched() / rcu_read_unlock_sched() + preempt_disable() / preempt_enable() local_irq_save() / local_irq_restore() hardirq enter / hardirq exit NMI enter / NMI exit diff --git a/Documentation/filesystems/dentry-locking.txt b/Documentation/filesystems/dentry-locking.txt index 4c0c575a4012..79334ed5daa7 100644 --- a/Documentation/filesystems/dentry-locking.txt +++ b/Documentation/filesystems/dentry-locking.txt @@ -62,7 +62,8 @@ changes are : 2. Insertion of a dentry into the hash table is done using hlist_add_head_rcu() which take care of ordering the writes - the writes to the dentry must be visible before the dentry is - inserted. This works in conjunction with hlist_for_each_rcu() while + inserted. This works in conjunction with hlist_for_each_rcu(), + which has since been replaced by hlist_for_each_entry_rcu(), while walking the hash chain. The only requirement is that all initialization to the dentry must be done before hlist_add_head_rcu() since we don't have dcache_lock protection diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 25c3ed594c54..6bf97d176326 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -765,9 +765,9 @@ config RCU_CPU_STALL_DETECTOR CPUs are delaying the current grace period, but only when the grace period extends for excessive time periods. - Say Y if you want RCU to perform such checks. + Say N if you want to disable such checks. - Say N if you are unsure. + Say Y if you are unsure. config KPROBES_SANITY_TEST bool "Kprobes sanity tests" -- GitLab From 017c426138122c8e9b9f5057fbd0567c37b35247 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 14 Jan 2010 16:10:58 -0800 Subject: [PATCH 0791/3892] rcu: Fix sparse warnings Rename local variable "i" in rcu_init() to avoid conflict with RCU_INIT_FLAVOR(), restrict the scope of RCU_TREE_NONCORE, and make __synchronize_srcu() static. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12635142581560-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 6 +++--- kernel/rcutree.h | 6 ++---- kernel/srcu.c | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 3b13d64b010b..099a255ede4c 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1888,7 +1888,7 @@ do { \ void __init rcu_init(void) { - int i; + int cpu; rcu_bootup_announce(); #ifdef CONFIG_RCU_CPU_STALL_DETECTOR @@ -1908,8 +1908,8 @@ void __init rcu_init(void) * or the scheduler are operational. */ cpu_notifier(rcu_cpu_notify, 0); - for_each_online_cpu(i) - rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)i); + for_each_online_cpu(cpu) + rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); } #include "rcutree_plugin.h" diff --git a/kernel/rcutree.h b/kernel/rcutree.h index bd5d78ad1c48..d9d032abd665 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -323,8 +323,6 @@ struct rcu_state { #define RCU_OFL_TASKS_EXP_GP 0x2 /* Tasks blocking expedited */ /* GP were moved to root. */ -#ifdef RCU_TREE_NONCORE - /* * RCU implementation internal declarations: */ @@ -339,7 +337,7 @@ extern struct rcu_state rcu_preempt_state; DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ -#else /* #ifdef RCU_TREE_NONCORE */ +#ifndef RCU_TREE_NONCORE /* Forward declarations for rcutree_plugin.h */ static void rcu_bootup_announce(void); @@ -372,4 +370,4 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu); static void rcu_preempt_send_cbs_to_orphanage(void); static void __init __rcu_init_preempt(void); -#endif /* #else #ifdef RCU_TREE_NONCORE */ +#endif /* #ifndef RCU_TREE_NONCORE */ diff --git a/kernel/srcu.c b/kernel/srcu.c index 818d7d9aa03c..31b275b9c112 100644 --- a/kernel/srcu.c +++ b/kernel/srcu.c @@ -144,7 +144,7 @@ EXPORT_SYMBOL_GPL(srcu_read_unlock); /* * Helper function for synchronize_srcu() and synchronize_srcu_expedited(). */ -void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void)) +static void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void)) { int idx; -- GitLab From 0d755034dbd01e240eadf2d31f4f75d3088ccd21 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 12:23:09 -0200 Subject: [PATCH 0792/3892] perf tools: Don't cast RIP to pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since they can come from another architecture with bigger pointers, i.e. processing a 64-bit perf.data on a 32-bit arch. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263478990-8200-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 4 ++-- tools/perf/builtin-diff.c | 4 ++-- tools/perf/builtin-kmem.c | 7 ++----- tools/perf/builtin-report.c | 7 ++----- tools/perf/builtin-sched.c | 7 ++----- tools/perf/builtin-trace.c | 7 ++----- tools/perf/util/event.c | 9 +++------ tools/perf/util/session.c | 16 ++++++---------- 8 files changed, 21 insertions(+), 40 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 117bbae844bf..73c202ee0882 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -132,8 +132,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) { struct addr_location al; - dump_printf("(IP, %d): %d: %p\n", event->header.misc, - event->ip.pid, (void *)(long)event->ip.ip); + dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, + event->ip.pid, event->ip.ip); if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 924bfb77a6ab..18b3f505f9db 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -42,8 +42,8 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi struct addr_location al; struct sample_data data = { .period = 1, }; - dump_printf("(IP, %d): %d: %p\n", event->header.misc, - event->ip.pid, (void *)(long)event->ip.ip); + dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, + event->ip.pid, event->ip.ip); if (event__preprocess_sample(event, session, &al, NULL) < 0) { pr_warning("problem processing %d event, skipping it.\n", diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 4af7199c5af7..7323d9dfbce8 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -316,11 +316,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) event__parse_sample(event, session->sample_type, &data); - dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", - event->header.misc, - data.pid, data.tid, - (void *)(long)data.ip, - (long long)data.period); + dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, + data.pid, data.tid, data.ip, data.period); thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 80d691a4191f..4c3d6997995b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -93,11 +93,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) event__parse_sample(event, session->sample_type, &data); - dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", - event->header.misc, - data.pid, data.tid, - (void *)(long)data.ip, - (long long)data.period); + dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, + data.pid, data.tid, data.ip, data.period); if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { unsigned int i; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 702322f8fec1..4f5a03e43444 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1621,11 +1621,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) event__parse_sample(event, session->sample_type, &data); - dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", - event->header.misc, - data.pid, data.tid, - (void *)(long)data.ip, - (long long)data.period); + dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, + data.pid, data.tid, data.ip, data.period); thread = perf_session__findnew(session, data.pid); if (thread == NULL) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1831434aa938..8e9cbfe608d6 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -75,11 +75,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) event__parse_sample(event, session->sample_type, &data); - dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", - event->header.misc, - data.pid, data.tid, - (void *)(long)data.ip, - (long long)data.period); + dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, + data.pid, data.tid, data.ip, data.period); thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 4f3e7ef33b83..24ec5be4a1c0 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -313,12 +313,9 @@ int event__process_mmap(event_t *self, struct perf_session *session) struct thread *thread; struct map *map; - dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", - self->mmap.pid, self->mmap.tid, - (void *)(long)self->mmap.start, - (void *)(long)self->mmap.len, - (void *)(long)self->mmap.pgoff, - self->mmap.filename); + dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", + self->mmap.pid, self->mmap.tid, self->mmap.start, + self->mmap.len, self->mmap.pgoff, self->mmap.filename); if (self->mmap.pid == 0) { static const char kmmap_prefix[] = "[kernel.kallsyms."; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index fd1c5a39a5bb..e3ccdb46d6c4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -209,9 +209,8 @@ static int perf_session__process_event(struct perf_session *self, trace_event(event); if (event->header.type < PERF_RECORD_MAX) { - dump_printf("%p [%p]: PERF_RECORD_%s", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("%#lx [%#x]: PERF_RECORD_%s", + offset + head, event->header.size, event__name[event->header.type]); ++event__total[0]; ++event__total[event->header.type]; @@ -362,16 +361,13 @@ more: size = event->header.size; - dump_printf("\n%p [%p]: event: %d\n", - (void *)(offset + head), - (void *)(long)event->header.size, - event->header.type); + dump_printf("\n%#lx [%#x]: event: %d\n", + offset + head, event->header.size, event->header.type); if (size == 0 || perf_session__process_event(self, event, ops, offset, head) < 0) { - dump_printf("%p [%p]: skipping unknown header type: %d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("%#lx [%#x]: skipping unknown header type: %d\n", + offset + head, event->header.size, event->header.type); /* * assume we lost track of the stream, check alignment, and -- GitLab From ba21594cddee0a3af582971656702b1c4509d8f5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 12:23:10 -0200 Subject: [PATCH 0793/3892] perf tools: Cross platform perf.data analysis support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are still some problems related to loading vmlinux files, but those are unrelated to the feature implemented in this patch, so will get fixed in the next patches, but here are some results: 1. collect perf.data file on a Fedora 12 machine, x86_64, 64-bit userland 2. transfer it to a Debian Testing machine, PARISC64, 32-bit userland acme@parisc:~/git/linux-2.6-tip$ perf buildid-list | head -5 74f9930ee94475b6b3238caf3725a50d59cb994b [kernel.kallsyms] 55fdd56670453ea66c011158c4b9d30179c1d049 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/ipt_MASQUERADE.ko 41adff63c730890480980d5d8ba513f1c216a858 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/iptable_nat.ko 90a33def1077bb8e97b8a78546dc96c2de62df46 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/nf_nat.ko 984c7bea90ce1376d5c8e7ef43a781801286e62d /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/tun.ko acme@parisc:~/git/linux-2.6-tip$ perf buildid-list | tail -5 22492f3753c6a67de5c7ccbd6b863390c92c0723 /usr/lib64/libXt.so.6.0.0 353802bb7e1b895ba43507cc678f951e778e4c6f /usr/lib64/libMagickCore.so.2.0.0 d10c2897558595efe7be8b0584cf7e6398bc776c /usr/lib64/libfprint.so.0.0.0 a83ecfb519a788774a84d5ddde633c9ba56c03ab /home/acme/bin/perf d3ca765a8ecf257d263801d7ad8c49c189082317 /usr/lib64/libdwarf.so.0.0 acme@parisc:~/git/linux-2.6-tip$ acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm The file [kernel.kallsyms] cannot be used, trying to use /proc/kallsyms... ^^^^ The problem related to vmlinux handling, it shouldn't be trying this ^^^^ rather alien /proc/kallsyms at all... /lib64/libpthread-2.10.2.so with build id 5c68f7afeb33309c78037e374b0deee84dd441f6 not found, continuing without symbols /lib64/libc-2.10.2.so with build id eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 not found, continuing without symbols /home/acme/bin/perf with build id a83ecfb519a788774a84d5ddde633c9ba56c03ab not found, continuing without symbols /usr/sbin/openvpn with build id f2037a091ef36b591187a858d75e203690ea9409 not found, continuing without symbols Failed to open /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/e1000e/e1000e.ko, continuing without symbols Failed to open /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/wireless/iwlwifi/iwlcore.ko, continuing without symbols # Samples: 293085637 # # Overhead Command # ........ ............... # 61.70% find 23.50% perf 5.86% swapper 3.12% sshd 2.39% init 0.87% bash 0.86% sleep 0.59% dbus-daemon 0.25% hald 0.24% NetworkManager 0.19% hald-addon-rfki 0.15% openvpn 0.07% phy0 0.07% events/0 0.05% iwl3945 0.05% events/1 0.03% kondemand/0 acme@parisc:~/git/linux-2.6-tip$ Which matches what we get when running the same command for the same perf.data file on the F12, x86_64, source machine: [root@doppio linux-2.6-tip]# perf report --sort comm # Samples: 293085637 # # Overhead Command # ........ ............... # 61.70% find 23.50% perf 5.86% swapper 3.12% sshd 2.39% init 0.87% bash 0.86% sleep 0.59% dbus-daemon 0.25% hald 0.24% NetworkManager 0.19% hald-addon-rfki 0.15% openvpn 0.07% phy0 0.07% events/0 0.05% iwl3945 0.05% events/1 0.03% kondemand/0 [root@doppio linux-2.6-tip]# The other modes work as well, modulo the problem with vmlinux: acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm,dso 2> /dev/null | head -15 # Samples: 293085637 # # Overhead Command Shared Object # ........ ............... ................................. # 35.11% find ffffffff81002b5a 18.25% perf ffffffff8102235f 16.17% find libc-2.10.2.so 9.07% find find 5.80% swapper ffffffff8102235f 3.95% perf libc-2.10.2.so 2.33% init ffffffff810091b9 1.65% sshd libcrypto.so.0.9.8k 1.35% find [e1000e] 0.68% sleep libc-2.10.2.so acme@parisc:~/git/linux-2.6-tip$ And the lack of the right buildids: acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm,dso,symbol 2> /dev/null | head -15 # Samples: 293085637 # # Overhead Command Shared Object Symbol # ........ ............... ................................. ...... # 35.11% find ffffffff81002b5a [k] 0xffffffff81002b5a 18.25% perf ffffffff8102235f [k] 0xffffffff8102235f 16.17% find libc-2.10.2.so [.] 0x00000000045782 9.07% find find [.] 0x0000000000fb0e 5.80% swapper ffffffff8102235f [k] 0xffffffff8102235f 3.95% perf libc-2.10.2.so [.] 0x0000000007f398 2.33% init ffffffff810091b9 [k] 0xffffffff810091b9 1.65% sshd libcrypto.so.0.9.8k [.] 0x00000000105440 1.35% find [e1000e] [k] 0x00000000010948 0.68% sleep libc-2.10.2.so [.] 0x0000000011ad5b acme@parisc:~/git/linux-2.6-tip$ But if we: acme@parisc:~/git/linux-2.6-tip$ ls ~/.debug ls: cannot access /home/acme/.debug: No such file or directory acme@parisc:~/git/linux-2.6-tip$ mkdir -p ~/.debug/lib64/libc-2.10.2.so/ acme@parisc:~/git/linux-2.6-tip$ scp doppio:.debug/lib64/libc-2.10.2.so/* ~/.debug/lib64/libc-2.10.2.so/ acme@doppio's password: eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 100% 1783KB 714.7KB/s 00:02 acme@parisc:~/git/linux-2.6-tip$ mkdir -p ~/.debug/.build-id/eb acme@parisc:~/git/linux-2.6-tip$ ln -s ../../lib64/libc-2.10.2.so/eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 ~/.debug/.build-id/eb/4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 acme@parisc:~/git/linux-2.6-tip$ perf report --dsos libc-2.10.2.so 2> /dev/null # dso: libc-2.10.2.so # Samples: 64281170 # # Overhead Command Symbol # ........ ............... ...... # 14.98% perf [.] __GI_strcmp 12.30% find [.] __GI_memmove 9.25% find [.] _int_malloc 7.60% find [.] _IO_vfprintf_internal 6.10% find [.] _IO_new_file_xsputn 6.02% find [.] __GI_close 3.08% find [.] _IO_file_overflow_internal 3.08% find [.] malloc_consolidate 3.08% find [.] _int_free 3.08% find [.] __strchrnul 3.08% find [.] __getdents64 3.08% find [.] __write_nocancel 3.08% sleep [.] __GI__dl_addr 3.08% sshd [.] __libc_select 3.08% find [.] _IO_new_file_write 3.07% find [.] _IO_new_do_write 3.06% find [.] __GI___errno_location 3.05% find [.] __GI___libc_malloc 3.04% perf [.] __GI_memcpy 1.71% find [.] __fprintf_chk 1.29% bash [.] __gconv_transform_utf8_internal 0.79% dbus-daemon [.] __GI_strlen # # (For a higher level overview, try: perf report --sort comm,dso) # acme@parisc:~/git/linux-2.6-tip$ Which matches what we get on the source, F12, x86_64 machine: [root@doppio linux-2.6-tip]# perf report --dsos libc-2.10.2.so # dso: libc-2.10.2.so # Samples: 64281170 # # Overhead Command Symbol # ........ ............... ...... # 14.98% perf [.] __GI_strcmp 12.30% find [.] __GI_memmove 9.25% find [.] _int_malloc 7.60% find [.] _IO_vfprintf_internal 6.10% find [.] _IO_new_file_xsputn 6.02% find [.] __GI_close 3.08% find [.] _IO_file_overflow_internal 3.08% find [.] malloc_consolidate 3.08% find [.] _int_free 3.08% find [.] __strchrnul 3.08% find [.] __getdents64 3.08% find [.] __write_nocancel 3.08% sleep [.] __GI__dl_addr 3.08% sshd [.] __libc_select 3.08% find [.] _IO_new_file_write 3.07% find [.] _IO_new_do_write 3.06% find [.] __GI___errno_location 3.05% find [.] __GI___libc_malloc 3.04% perf [.] __GI_memcpy 1.71% find [.] __fprintf_chk 1.29% bash [.] __gconv_transform_utf8_internal 0.79% dbus-daemon [.] __GI_strlen # # (For a higher level overview, try: perf report --sort comm,dso) # [root@doppio linux-2.6-tip]# So I think this is really, really nice in that it demonstrates the portability of perf.data files and the use of build-ids accross such aliens worlds :-) There are some things to fix tho, like the bitmap on the header, but things are looking good. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263478990-8200-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 63 +++++++++++++++++----- tools/perf/util/header.h | 2 + tools/perf/util/session.c | 108 ++++++++++++++++++++++++++++++++++---- tools/perf/util/session.h | 7 ++- 4 files changed, 157 insertions(+), 23 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ec96321eb9e4..b31e0ae4b8db 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1,8 +1,10 @@ #include +#include #include #include #include #include +#include #include "util.h" #include "header.h" @@ -464,8 +466,21 @@ static int do_read(int fd, void *buf, size_t size) return 0; } +static int perf_header__getbuffer64(struct perf_header *self, + int fd, void *buf, size_t size) +{ + if (do_read(fd, buf, size)) + return -1; + + if (self->needs_swap) + mem_bswap_64(buf, size); + + return 0; +} + int perf_header__process_sections(struct perf_header *self, int fd, int (*process)(struct perf_file_section *self, + struct perf_header *ph, int feat, int fd)) { struct perf_file_section *feat_sec; @@ -486,7 +501,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, lseek(fd, self->data_offset + self->data_size, SEEK_SET); - if (do_read(fd, feat_sec, sec_size)) + if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) goto out_free; err = 0; @@ -494,7 +509,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, if (perf_header__has_feat(self, feat)) { struct perf_file_section *sec = &feat_sec[idx++]; - err = process(sec, feat, fd); + err = process(sec, self, feat, fd); if (err < 0) break; } @@ -511,10 +526,20 @@ int perf_file_header__read(struct perf_file_header *self, lseek(fd, 0, SEEK_SET); if (do_read(fd, self, sizeof(*self)) || - self->magic != PERF_MAGIC || - self->attr_size != sizeof(struct perf_file_attr)) + memcmp(&self->magic, __perf_magic, sizeof(self->magic))) return -1; + if (self->attr_size != sizeof(struct perf_file_attr)) { + u64 attr_size = bswap_64(self->attr_size); + + if (attr_size != sizeof(struct perf_file_attr)) + return -1; + + mem_bswap_64(self, offsetof(struct perf_file_header, + adds_features)); + ph->needs_swap = true; + } + if (self->size != sizeof(*self)) { /* Support the previous format */ if (self->size == offsetof(typeof(*self), adds_features)) @@ -524,16 +549,28 @@ int perf_file_header__read(struct perf_file_header *self, } memcpy(&ph->adds_features, &self->adds_features, - sizeof(self->adds_features)); + sizeof(ph->adds_features)); + /* + * FIXME: hack that assumes that if we need swap the perf.data file + * may be coming from an arch with a different word-size, ergo different + * DEFINE_BITMAP format, investigate more later, but for now its mostly + * safe to assume that we have a build-id section. Trace files probably + * have several other issues in this realm anyway... + */ + if (ph->needs_swap) { + memset(&ph->adds_features, 0, sizeof(ph->adds_features)); + perf_header__set_feat(ph, HEADER_BUILD_ID); + } ph->event_offset = self->event_types.offset; - ph->event_size = self->event_types.size; - ph->data_offset = self->data.offset; + ph->event_size = self->event_types.size; + ph->data_offset = self->data.offset; ph->data_size = self->data.size; return 0; } static int perf_file_section__process(struct perf_file_section *self, + struct perf_header *ph, int feat, int fd) { if (lseek(fd, self->offset, SEEK_SET) < 0) { @@ -548,7 +585,7 @@ static int perf_file_section__process(struct perf_file_section *self, break; case HEADER_BUILD_ID: - if (perf_header__read_build_ids(fd, self->offset, self->size)) + if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) pr_debug("Failed to read buildids, continuing...\n"); break; default: @@ -560,7 +597,7 @@ static int perf_file_section__process(struct perf_file_section *self, int perf_header__read(struct perf_header *self, int fd) { - struct perf_file_header f_header; + struct perf_file_header f_header; struct perf_file_attr f_attr; u64 f_id; int nr_attrs, nr_ids, i, j; @@ -577,8 +614,9 @@ int perf_header__read(struct perf_header *self, int fd) struct perf_header_attr *attr; off_t tmp; - if (do_read(fd, &f_attr, sizeof(f_attr))) + if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) goto out_errno; + tmp = lseek(fd, 0, SEEK_CUR); attr = perf_header_attr__new(&f_attr.attr); @@ -589,7 +627,7 @@ int perf_header__read(struct perf_header *self, int fd) lseek(fd, f_attr.ids.offset, SEEK_SET); for (j = 0; j < nr_ids; j++) { - if (do_read(fd, &f_id, sizeof(f_id))) + if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) goto out_errno; if (perf_header_attr__add_id(attr, f_id) < 0) { @@ -610,7 +648,8 @@ int perf_header__read(struct perf_header *self, int fd) events = malloc(f_header.event_types.size); if (events == NULL) return -ENOMEM; - if (do_read(fd, events, f_header.event_types.size)) + if (perf_header__getbuffer64(self, fd, events, + f_header.event_types.size)) goto out_errno; event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 2b69aab67e35..ccc8540feccd 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -52,6 +52,7 @@ struct perf_header { u64 data_size; u64 event_offset; u64 event_size; + bool needs_swap; DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); }; @@ -80,6 +81,7 @@ bool perf_header__has_feat(const struct perf_header *self, int feat); int perf_header__process_sections(struct perf_header *self, int fd, int (*process)(struct perf_file_section *self, + struct perf_header *ph, int feat, int fd)); #endif /* __PERF_HEADER_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e3ccdb46d6c4..604e14f6a6f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,5 +1,6 @@ #include +#include #include #include @@ -201,21 +202,88 @@ void event__print_totals(void) event__name[i], event__total[i]); } +void mem_bswap_64(void *src, int byte_size) +{ + u64 *m = src; + + while (byte_size > 0) { + *m = bswap_64(*m); + byte_size -= sizeof(u64); + ++m; + } +} + +static void event__all64_swap(event_t *self) +{ + struct perf_event_header *hdr = &self->header; + mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); +} + +static void event__comm_swap(event_t *self) +{ + self->comm.pid = bswap_32(self->comm.pid); + self->comm.tid = bswap_32(self->comm.tid); +} + +static void event__mmap_swap(event_t *self) +{ + self->mmap.pid = bswap_32(self->mmap.pid); + self->mmap.tid = bswap_32(self->mmap.tid); + self->mmap.start = bswap_64(self->mmap.start); + self->mmap.len = bswap_64(self->mmap.len); + self->mmap.pgoff = bswap_64(self->mmap.pgoff); +} + +static void event__task_swap(event_t *self) +{ + self->fork.pid = bswap_32(self->fork.pid); + self->fork.tid = bswap_32(self->fork.tid); + self->fork.ppid = bswap_32(self->fork.ppid); + self->fork.ptid = bswap_32(self->fork.ptid); + self->fork.time = bswap_64(self->fork.time); +} + +static void event__read_swap(event_t *self) +{ + self->read.pid = bswap_32(self->read.pid); + self->read.tid = bswap_32(self->read.tid); + self->read.value = bswap_64(self->read.value); + self->read.time_enabled = bswap_64(self->read.time_enabled); + self->read.time_running = bswap_64(self->read.time_running); + self->read.id = bswap_64(self->read.id); +} + +typedef void (*event__swap_op)(event_t *self); + +static event__swap_op event__swap_ops[] = { + [PERF_RECORD_MMAP] = event__mmap_swap, + [PERF_RECORD_COMM] = event__comm_swap, + [PERF_RECORD_FORK] = event__task_swap, + [PERF_RECORD_EXIT] = event__task_swap, + [PERF_RECORD_LOST] = event__all64_swap, + [PERF_RECORD_READ] = event__read_swap, + [PERF_RECORD_SAMPLE] = event__all64_swap, + [PERF_RECORD_MAX] = NULL, +}; + static int perf_session__process_event(struct perf_session *self, event_t *event, struct perf_event_ops *ops, - unsigned long offset, unsigned long head) + u64 offset, u64 head) { trace_event(event); if (event->header.type < PERF_RECORD_MAX) { - dump_printf("%#lx [%#x]: PERF_RECORD_%s", + dump_printf("%#Lx [%#x]: PERF_RECORD_%s", offset + head, event->header.size, event__name[event->header.type]); ++event__total[0]; ++event__total[event->header.type]; } + if (self->header.needs_swap && event__swap_ops[event->header.type]) + event__swap_ops[event->header.type](event); + switch (event->header.type) { case PERF_RECORD_SAMPLE: return ops->sample(event, self); @@ -241,7 +309,15 @@ static int perf_session__process_event(struct perf_session *self, } } -int perf_header__read_build_ids(int input, u64 offset, u64 size) +void perf_event_header__bswap(struct perf_event_header *self) +{ + self->type = bswap_32(self->type); + self->misc = bswap_16(self->misc); + self->size = bswap_16(self->size); +} + +int perf_header__read_build_ids(struct perf_header *self, + int input, u64 offset, u64 size) { struct build_id_event bev; char filename[PATH_MAX]; @@ -256,6 +332,9 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) if (read(input, &bev, sizeof(bev)) != sizeof(bev)) goto out; + if (self->needs_swap) + perf_event_header__bswap(&bev.header); + len = bev.header.size - sizeof(bev); if (read(input, filename, len) != len) goto out; @@ -292,9 +371,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se int perf_session__process_events(struct perf_session *self, struct perf_event_ops *ops) { - int err; - unsigned long head, shift; - unsigned long offset = 0; + int err, mmap_prot, mmap_flags; + u64 head, shift; + u64 offset = 0; size_t page_size; event_t *event; uint32_t size; @@ -330,9 +409,16 @@ out_getcwd_err: offset += shift; head -= shift; + mmap_prot = PROT_READ; + mmap_flags = MAP_SHARED; + + if (self->header.needs_swap) { + mmap_prot |= PROT_WRITE; + mmap_flags = MAP_PRIVATE; + } remap: - buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, - MAP_SHARED, self->fd, offset); + buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, + mmap_flags, self->fd, offset); if (buf == MAP_FAILED) { pr_err("failed to mmap file\n"); err = -errno; @@ -342,6 +428,8 @@ remap: more: event = (event_t *)(buf + head); + if (self->header.needs_swap) + perf_event_header__bswap(&event->header); size = event->header.size; if (size == 0) size = 8; @@ -361,12 +449,12 @@ more: size = event->header.size; - dump_printf("\n%#lx [%#x]: event: %d\n", + dump_printf("\n%#Lx [%#x]: event: %d\n", offset + head, event->header.size, event->header.type); if (size == 0 || perf_session__process_event(self, event, ops, offset, head) < 0) { - dump_printf("%#lx [%#x]: skipping unknown header type: %d\n", + dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", offset + head, event->header.size, event->header.type); /* diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d4a9d20f8d44..36d1a80c0b6c 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -51,6 +51,8 @@ struct perf_event_ops { struct perf_session *perf_session__new(const char *filename, int mode, bool force); void perf_session__delete(struct perf_session *self); +void perf_event_header__bswap(struct perf_event_header *self); + int perf_session__process_events(struct perf_session *self, struct perf_event_ops *event_ops); @@ -61,7 +63,8 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, bool perf_session__has_traces(struct perf_session *self, const char *msg); -int perf_header__read_build_ids(int input, u64 offset, u64 file_size); +int perf_header__read_build_ids(struct perf_header *self, int input, + u64 offset, u64 file_size); int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, const char *symbol_name, @@ -69,4 +72,6 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, void perf_session__reloc_vmlinux_maps(struct perf_session *self, u64 unrelocated_addr); +void mem_bswap_64(void *src, int byte_size); + #endif /* __PERF_SESSION_H */ -- GitLab From 1b75962e92d48a41019d4b440e221638aa2a7238 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 18:30:04 -0200 Subject: [PATCH 0794/3892] perf tools: Convert getpagesize() uses to sysconf(_SC_GETPAGESIZE) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the more portable and equivalent sysconf call. Reported-by: Aristeu Rozanski Reported-by: Ulrich Drepper Signed-off-by: Arnaldo Carvalho de Melo Cc: Aristeu Rozanski Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ulrich Drepper LKML-Reference: <1263501006-14185-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/session.c | 2 +- tools/perf/util/trace-event-info.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 604e14f6a6f9..1951e330377c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -384,7 +384,7 @@ int perf_session__process_events(struct perf_session *self, perf_event_ops__fill_defaults(ops); - page_size = getpagesize(); + page_size = sysconf(_SC_PAGESIZE); head = self->header.data_offset; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 407fd65b6cdb..5ea8973ad331 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -515,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) write_or_die(buf, 1); /* save page_size */ - page_size = getpagesize(); + page_size = sysconf(_SC_PAGESIZE); write_or_die(&page_size, 4); read_header_files(); -- GitLab From 8d0591f6ad9edf66697ce29de176fb6f3213b9e3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 18:30:05 -0200 Subject: [PATCH 0795/3892] perf symbols: Don't try to load kallsyms if doesn't match the record build-id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now a perf.data file collected on a x86_64 fedora 12 machine gets properly parsed on a Debian testing PARISC64 machine with 32-bit userland: acme@parisc:~/git/linux-2.6-tip$ perf report 2> /dev/null | head -15 # Samples: 293085637 # # Overhead Command Shared Object Symbol # ........ ............... ................................. ...... # 35.11% find [kernel.kallsyms] [k] 0xffffffff81002b5a 18.25% perf [kernel.kallsyms] [k] 0xffffffff8102235f 9.07% find find [.] 0x0000000000fb0e 5.80% swapper [kernel.kallsyms] [k] 0xffffffff8102235f 3.29% perf libc-2.10.2.so [.] __GI_strcmp 2.70% find libc-2.10.2.so [.] __GI_memmove 2.33% init [kernel.kallsyms] [k] 0xffffffff810091b9 2.03% find libc-2.10.2.so [.] _int_malloc 1.67% find libc-2.10.2.so [.] _IO_vfprintf_internal 1.65% sshd libcrypto.so.0.9.8k [.] 0x00000000105440 acme@parisc:~/git/linux-2.6-tip$ Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263501006-14185-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 381999dd5c1f..71d23e1e30e8 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1608,11 +1608,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, u8 kallsyms_build_id[BUILD_ID_SIZE]; if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, - sizeof(kallsyms_build_id)) == 0) - - is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); - if (is_kallsyms) - goto do_kallsyms; + sizeof(kallsyms_build_id)) == 0) { + is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); + if (is_kallsyms) + goto do_kallsyms; + } goto do_vmlinux; } @@ -1623,6 +1623,9 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, do_vmlinux: err = dso__load_vmlinux(self, map, session, self->long_name, filter); if (err <= 0) { + if (self->has_build_id) + return -1; + pr_info("The file %s cannot be used, " "trying to use /proc/kallsyms...", self->long_name); do_kallsyms: -- GitLab From 9e201442de7c954f03710ac76f28c1927d07550c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 18:30:06 -0200 Subject: [PATCH 0796/3892] perf symbols: Cache /proc/kallsyms files by build-id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that when we don't have a vmlinux handy we can store the kallsyms for later use by 'perf report'. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263501006-14185-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 2 +- tools/perf/util/header.c | 15 +++++++++---- tools/perf/util/symbol.c | 48 +++++++++++++++++++++++++++++----------- tools/perf/util/symbol.h | 5 +++-- tools/perf/util/util.c | 30 +++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 24ec5be4a1c0..0e9820ac4f5e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -245,7 +245,7 @@ int event__synthesize_kernel_mmap(event__handler_t process, */ struct process_symbol_args args = { .name = symbol_name, }; - if (kallsyms__parse(&args, find_symbol_cb) <= 0) + if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0) return -ENOENT; size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b31e0ae4b8db..1b65fed0dd2d 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -237,11 +237,13 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir) char *filename = malloc(size), *linkname = malloc(size), *targetname, *sbuild_id; int len, err = -1; + bool is_kallsyms = self->kernel && self->long_name[0] != '/'; if (filename == NULL || linkname == NULL) goto out_free; - len = snprintf(filename, size, "%s%s", debugdir, self->long_name); + len = snprintf(filename, size, "%s%s%s", + debugdir, is_kallsyms ? "/" : "", self->long_name); if (mkdir_p(filename, 0755)) goto out_free; @@ -249,9 +251,14 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir) sbuild_id = filename + len; build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); - if (access(filename, F_OK) && link(self->long_name, filename) && - copyfile(self->long_name, filename)) - goto out_free; + if (access(filename, F_OK)) { + if (is_kallsyms) { + if (copyfile("/proc/kallsyms", filename)) + goto out_free; + } else if (link(self->long_name, filename) && + copyfile(self->long_name, filename)) + goto out_free; + } len = snprintf(linkname, size, "%s/.build-id/%.2s", debugdir, sbuild_id); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 71d23e1e30e8..ae61e9f4d6eb 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -383,13 +383,14 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) return ret; } -int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, +int kallsyms__parse(const char *filename, void *arg, + int (*process_symbol)(void *arg, const char *name, char type, u64 start)) { char *line = NULL; size_t n; int err = 0; - FILE *file = fopen("/proc/kallsyms", "r"); + FILE *file = fopen(filename, "r"); if (file == NULL) goto out_failure; @@ -466,10 +467,11 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * so that we can in the next step set the symbol ->end address and then * call kernel_maps__split_kallsyms. */ -static int dso__load_all_kallsyms(struct dso *self, struct map *map) +static int dso__load_all_kallsyms(struct dso *self, const char *filename, + struct map *map) { struct process_kallsyms_args args = { .map = map, .dso = self, }; - return kallsyms__parse(&args, map__process_kallsym_symbol); + return kallsyms__parse(filename, &args, map__process_kallsym_symbol); } /* @@ -556,10 +558,10 @@ discard_symbol: rb_erase(&pos->rb_node, root); } -static int dso__load_kallsyms(struct dso *self, struct map *map, +static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, struct perf_session *session, symbol_filter_t filter) { - if (dso__load_all_kallsyms(self, map) < 0) + if (dso__load_all_kallsyms(self, filename, map) < 0) return -1; symbols__fixup_end(&self->symbols[map->type]); @@ -1580,7 +1582,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, struct perf_session *session, symbol_filter_t filter) { int err; - bool is_kallsyms; + const char *kallsyms_filename = NULL; + char *kallsyms_allocated_filename = NULL; if (vmlinux_path != NULL) { int i; @@ -1606,19 +1609,37 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, */ if (self->has_build_id) { u8 kallsyms_build_id[BUILD_ID_SIZE]; + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, sizeof(kallsyms_build_id)) == 0) { - is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); - if (is_kallsyms) + if (dso__build_id_equal(self, kallsyms_build_id)) { + kallsyms_filename = "/proc/kallsyms"; goto do_kallsyms; + } } + + build_id__sprintf(self->build_id, sizeof(self->build_id), + sbuild_id); + + if (asprintf(&kallsyms_allocated_filename, + "%s/.debug/[kernel.kallsyms]/%s", + getenv("HOME"), sbuild_id) != -1) { + if (access(kallsyms_filename, F_OK)) { + kallsyms_filename = kallsyms_allocated_filename; + goto do_kallsyms; + } + free(kallsyms_allocated_filename); + kallsyms_allocated_filename = NULL; + } + goto do_vmlinux; } - is_kallsyms = self->long_name[0] == '['; - if (is_kallsyms) + if (self->long_name[0] == '[') { + kallsyms_filename = "/proc/kallsyms"; goto do_kallsyms; + } do_vmlinux: err = dso__load_vmlinux(self, map, session, self->long_name, filter); @@ -1629,9 +1650,10 @@ do_vmlinux: pr_info("The file %s cannot be used, " "trying to use /proc/kallsyms...", self->long_name); do_kallsyms: - err = dso__load_kallsyms(self, map, session, filter); - if (err > 0 && !is_kallsyms) + err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter); + if (err > 0 && kallsyms_filename == NULL) dso__set_long_name(self, strdup("[kernel.kallsyms]")); + free(kallsyms_allocated_filename); } if (err > 0) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 594156e43b10..36b7c717f5ee 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -144,8 +144,9 @@ int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); -int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, - char type, u64 start)); +int kallsyms__parse(const char *filename, void *arg, + int (*process_symbol)(void *arg, const char *name, + char type, u64 start)); int symbol__init(void); bool symbol_type__is_a(char symbol_type, enum map_type map_type); diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index f3c0798a5e78..f0685849b244 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -32,6 +32,33 @@ int mkdir_p(char *path, mode_t mode) return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; } +static int slow_copyfile(const char *from, const char *to) +{ + int err = 0; + char *line = NULL; + size_t n; + FILE *from_fp = fopen(from, "r"), *to_fp; + + if (from_fp == NULL) + goto out; + + to_fp = fopen(to, "w"); + if (to_fp == NULL) + goto out_fclose_from; + + while (getline(&line, &n, from_fp) > 0) + if (fputs(line, to_fp) == EOF) + goto out_fclose_to; + err = 0; +out_fclose_to: + fclose(to_fp); + free(line); +out_fclose_from: + fclose(from_fp); +out: + return err; +} + int copyfile(const char *from, const char *to) { int fromfd, tofd; @@ -42,6 +69,9 @@ int copyfile(const char *from, const char *to) if (stat(from, &st)) goto out; + if (st.st_size == 0) /* /proc? do it slowly... */ + return slow_copyfile(from, to); + fromfd = open(from, O_RDONLY); if (fromfd < 0) goto out; -- GitLab From cf4e5b0838e822dd404638ad00d35b63fffe8191 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 23:45:27 -0200 Subject: [PATCH 0797/3892] perf symbols: Use dso->long_name in dsos__find() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If not we end up duplicating the module DSOs because first we insert them using the short name found in /proc/modules, then, when processing synthesized MMAP events we add them again. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263519930-22803-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ae61e9f4d6eb..4267138c7bbe 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1679,7 +1679,7 @@ static struct dso *dsos__find(struct list_head *head, const char *name) struct dso *pos; list_for_each_entry(pos, head, node) - if (strcmp(pos->name, name) == 0) + if (strcmp(pos->long_name, name) == 0) return pos; return NULL; } -- GitLab From 18c3daa4961b9fa1f2db0711d93c0acf0c39fd12 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 23:45:28 -0200 Subject: [PATCH 0798/3892] perf record: Encode the domain while synthesizing MMAP events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past 'perf record' had to process only userspace MMAP events, the ones generated in the kernel, but after we reused the MMAP events to encode the module mapings we ended up adding them first to the list of userspace DSOs (dsos__user) and to the kernel one (dsos__kernel). Fix this by encoding the header.misc field and then using it, like other parts to decide the right DSOs list to insert/find. The gotcha here is that since the kernel puts zero in .misc, which isn't PERF_RECORD_MISC_KERNEL (1 << 1), to differentiate, we put 1 in .misc. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263519930-22803-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 8 ++++++-- tools/perf/util/event.c | 11 +++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c130df2676f1..614fa9a4c67c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -117,8 +117,12 @@ static void write_event(event_t *buf, size_t size) * Add it to the list of DSOs, so that when we finish this * record session we can pick the available build-ids. */ - if (buf->header.type == PERF_RECORD_MMAP) - dsos__findnew(buf->mmap.filename); + if (buf->header.type == PERF_RECORD_MMAP) { + struct list_head *head = &dsos__user; + if (buf->mmap.header.misc == 1) + head = &dsos__kernel; + __dsos__findnew(head, buf->mmap.filename); + } write_output(buf, size); } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0e9820ac4f5e..1abaefc126a8 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -110,7 +110,10 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, while (1) { char bf[BUFSIZ], *pbf = bf; event_t ev = { - .header = { .type = PERF_RECORD_MMAP }, + .header = { + .type = PERF_RECORD_MMAP, + .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */ + }, }; int n; size_t size; @@ -170,6 +173,7 @@ int event__synthesize_modules(event__handler_t process, size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); memset(&ev, 0, sizeof(ev)); + ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */ ev.mmap.header.type = PERF_RECORD_MMAP; ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); @@ -236,7 +240,10 @@ int event__synthesize_kernel_mmap(event__handler_t process, { size_t size; event_t ev = { - .header = { .type = PERF_RECORD_MMAP }, + .header = { + .type = PERF_RECORD_MMAP, + .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */ + }, }; /* * We should get this from /sys/kernel/sections/.text, but till that is -- GitLab From 59ee68ecd1561a233fb6ad351980bea8402533e7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 23:45:29 -0200 Subject: [PATCH 0799/3892] perf symbols: Create thread__find_addr_map from thread__find_addr_location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because some tools will only want to know with maps had hits, not needing the full symbol resolution done by thread__find_addr_location. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263519930-22803-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 26 +++++++++++++++++--------- tools/perf/util/thread.h | 5 +++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1abaefc126a8..5a6e827a09eb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -422,11 +422,10 @@ int event__process_task(event_t *self, struct perf_session *session) return 0; } -void thread__find_addr_location(struct thread *self, - struct perf_session *session, u8 cpumode, - enum map_type type, u64 addr, - struct addr_location *al, - symbol_filter_t filter) +void thread__find_addr_map(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, u64 addr, + struct addr_location *al) { struct map_groups *mg = &self->mg; @@ -441,7 +440,6 @@ void thread__find_addr_location(struct thread *self, else { al->level = 'H'; al->map = NULL; - al->sym = NULL; return; } try_again: @@ -460,11 +458,21 @@ try_again: mg = &session->kmaps; goto try_again; } - al->sym = NULL; - } else { + } else al->addr = al->map->map_ip(al->map, al->addr); +} + +void thread__find_addr_location(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, u64 addr, + struct addr_location *al, + symbol_filter_t filter) +{ + thread__find_addr_map(self, session, cpumode, type, addr, al); + if (al->map != NULL) al->sym = map__find_symbol(al->map, session, al->addr, filter); - } + else + al->sym = NULL; } static void dso__calc_col_width(struct dso *self) diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index c06c13535a70..e35653c1817c 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -48,6 +48,11 @@ static inline struct map *thread__find_map(struct thread *self, return self ? map_groups__find(&self->mg, type, addr) : NULL; } +void thread__find_addr_map(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, u64 addr, + struct addr_location *al); + void thread__find_addr_location(struct thread *self, struct perf_session *session, u8 cpumode, enum map_type type, u64 addr, -- GitLab From 88d3d9b7c843a42cb73c55a2d13cd1041da31fb9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jan 2010 23:45:30 -0200 Subject: [PATCH 0800/3892] perf buildid-list: Introduce --with-hits option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using this option 'perf buildid-list' will process all samples, marking the DSOs that had some hits to list just them. This in turn will be used by a new porcelain, 'perf archive', that will be just a shell script to create a tarball from the 'perf buildid-list --with-hits' output and the files cached by 'perf record' in ~/.debug. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263519930-22803-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-buildid-list.c | 35 ++++++++++++++++++++++++++++++- tools/perf/util/symbol.c | 11 ++++++---- tools/perf/util/symbol.h | 3 ++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 4229c2c213cc..431f204bde64 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -16,6 +16,7 @@ static char const *input_name = "perf.data"; static int force; +static bool with_hits; static const char * const buildid_list_usage[] = { "perf buildid-list []", @@ -23,6 +24,7 @@ static const char * const buildid_list_usage[] = { }; static const struct option options[] = { + OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), @@ -31,6 +33,34 @@ static const struct option options[] = { OPT_END() }; +static int build_id_list__process_event(event_t *event, + struct perf_session *session) +{ + struct addr_location al; + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct thread *thread = perf_session__findnew(session, event->ip.pid); + + if (thread == NULL) { + pr_err("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.ip, &al); + + if (al.map != NULL) + al.map->dso->hit = 1; + + return 0; +} + +static struct perf_event_ops build_id_list__event_ops = { + .sample = build_id_list__process_event, + .mmap = event__process_mmap, + .fork = event__process_task, +}; + static int __cmd_buildid_list(void) { int err = -1; @@ -40,7 +70,10 @@ static int __cmd_buildid_list(void) if (session == NULL) return -1; - dsos__fprintf_buildid(stdout); + if (with_hits) + perf_session__process_events(session, &build_id_list__event_ops); + + dsos__fprintf_buildid(stdout, with_hits); perf_session__delete(session); return err; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4267138c7bbe..a4e745934584 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1716,22 +1716,25 @@ void dsos__fprintf(FILE *fp) __dsos__fprintf(&dsos__user, fp); } -static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) +static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, + bool with_hits) { struct dso *pos; size_t ret = 0; list_for_each_entry(pos, head, node) { + if (with_hits && !pos->hit) + continue; ret += dso__fprintf_buildid(pos, fp); ret += fprintf(fp, " %s\n", pos->long_name); } return ret; } -size_t dsos__fprintf_buildid(FILE *fp) +size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) { - return (__dsos__fprintf_buildid(&dsos__kernel, fp) + - __dsos__fprintf_buildid(&dsos__user, fp)); + return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) + + __dsos__fprintf_buildid(&dsos__user, fp, with_hits)); } static struct dso *dsos__create_kernel(const char *vmlinux) diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 36b7c717f5ee..525085fd0735 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -97,6 +97,7 @@ struct dso { u8 slen_calculated:1; u8 has_build_id:1; u8 kernel:1; + u8 hit:1; unsigned char origin; u8 sorted_by_name; u8 loaded; @@ -129,7 +130,7 @@ struct perf_session; int dso__load(struct dso *self, struct map *map, struct perf_session *session, symbol_filter_t filter); void dsos__fprintf(FILE *fp); -size_t dsos__fprintf_buildid(FILE *fp); +size_t dsos__fprintf_buildid(FILE *fp, bool with_hits); size_t dso__fprintf_buildid(struct dso *self, FILE *fp); size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); -- GitLab From 460848fceffc91652b2d36d19db4ac40d12fb607 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jan 2010 13:17:51 -0200 Subject: [PATCH 0801/3892] perf symbols: The synthesized kernel modules MMAP must use the pathnames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we use ->long_name in dsos__find now. Now 'perf buildid_list' is not duplicating those and managing to show the proper build-ids for the DSOs with hits: [root@doppio linux-2.6-tip]# perf buildid-list -H 74f9930ee94475b6b3238caf3725a50d59cb994b [kernel.kallsyms] 9ffdcac0a7935922d1f04b6cc9029dfef0f066ef /lib/modules/2.6.33-rc4-tip+/kernel/arch/x86/crypto/aes-x86_64.ko 3aaf89c32ebfc438ff546c93597d41788e3e65f3 /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/wireless/iwlwifi/iwl3945.ko 19f46033f73e1ec612937189bb118c5daba5a0c8 /lib/modules/2.6.33-rc4-tip+/kernel/net/mac80211/mac80211.ko 1772f014a7a7272859655acb0c64a20ab20b75ee /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/e1000e/e1000e.ko eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 /lib64/libc-2.10.2.so 5c68f7afeb33309c78037e374b0deee84dd441f6 /lib64/libpthread-2.10.2.so e9c9ad5c138ef882e4507d2605645b597da43873 /bin/dbus-daemon bcda7d09eb6c9ee380dae0ed3d591d4311decc31 /lib64/libdbus-1.so.3.4.0 7cc449a77f48b85d6088114000e970ced613bed8 /usr/lib64/libcrypto.so.0.9.8k fdd1ccd1ff7917ab020653147ab3bacf0a85b5b9 /lib64/libglib-2.0.so.0.2000.5 e4417ebb8762e5f2eee93c8011a71115ff5edad8 /lib64/libgobject-2.0.so.0.2000.5 931e49461f6df99104f0febcc52f6fed5e2efce6 /usr/sbin/sshd dab5f724c088f89fbd8304da553ed6cb30bbec96 /usr/lib64/libgdk-x11-2.0.so.0.1600.6 f2037a091ef36b591187a858d75e203690ea9409 /usr/sbin/openvpn a8e4f743b40fb1fd8b85e2f9b88d93b661472b8f /bin/find 81120aada06e68b1e85882925a0fc6d7345ef59a /home/acme/bin/perf [root@doppio linux-2.6-tip]# Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263568672-30323-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 5a6e827a09eb..966d207a1509 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -345,15 +345,15 @@ int event__process_mmap(event_t *self, struct perf_session *session) map = perf_session__new_module_map(session, self->mmap.start, - short_module_name); + self->mmap.filename); if (map == NULL) goto out_problem; - name = strdup(self->mmap.filename); + name = strdup(short_module_name); if (name == NULL) goto out_problem; - dso__set_long_name(map->dso, name); + map->dso->short_name = name; map->end = map->start + self->mmap.len; } else if (memcmp(self->mmap.filename, kmmap_prefix, sizeof(kmmap_prefix) - 1) == 0) { -- GitLab From 2c5851747bcf751908c02e253cb7582d342b4612 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jan 2010 13:17:52 -0200 Subject: [PATCH 0802/3892] perf archive: Add helper script to package files needed to do analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It uses 'perf buildid-list --with-hits' to create a tarball with what is needed to have in the destination machine ~/.debug hierarchy to properly decode the perf.data file specified. Here is an example where a perf.data file collected on a x86-64 machine running Fedora 12 is used and then the data is packaged, transferred and decoded on a PARISC64 machine running Debian Testing, 32-bit userspace: [root@doppio linux-2.6-tip]# uname -a Linux doppio.ghostprotocols.net 2.6.33-rc4-tip+ #3 SMP Wed Jan 13 11:58:15 BRST 2010 x86_64 x86_64 x86_64 GNU/Linux [root@doppio linux-2.6-tip]# perf archive [root@doppio linux-2.6-tip]# ls -la perf.data* -rw------- 1 root root 737696 2010-01-14 23:36 perf.data -rw-r--r-- 1 root root 8840025 2010-01-15 12:27 perf.data.tar.bz2 [root@doppio linux-2.6-tip]# scp perf.data.* parisc64:. Password: perf.data.tar.bz2 100% 8633KB 1.4MB/s 00:06 [root@doppio linux-2.6-tip]# ssh parisc64 Password: Linux parisc 2.6.19-g2bbf29ac-dirty #1 Sun Dec 3 17:24:04 BRST 2006 parisc64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Thu Jan 14 11:23:24 2010 from d parisc:~# uname -a Linux parisc 2.6.19-g2bbf29ac-dirty #1 Sun Dec 3 17:24:04 BRST 2006 parisc64 GNU/Linux parisc:~# mkdir .debug parisc:~# tar xvf perf.data.tar.bz2 -C ~/.debug tar: Record size = 8 blocks .build-id/74/f9930ee94475b6b3238caf3725a50d59cb994b [kernel.kallsyms]/74f9930ee94475b6b3238caf3725a50d59cb994b .build-id/9f/fdcac0a7935922d1f04b6cc9029dfef0f066ef lib/modules/2.6.33-rc4-tip+/kernel/arch/x86/crypto/aes-x86_64.ko/9ffdcac0a7935922d1f04b6cc9029dfef0f066ef .build-id/3a/af89c32ebfc438ff546c93597d41788e3e65f3 lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/wireless/iwlwifi/iwl3945.ko/3aaf89c32ebfc438ff546c93597d41788e3e65f3 .build-id/19/f46033f73e1ec612937189bb118c5daba5a0c8 lib/modules/2.6.33-rc4-tip+/kernel/net/mac80211/mac80211.ko/19f46033f73e1ec612937189bb118c5daba5a0c8 .build-id/17/72f014a7a7272859655acb0c64a20ab20b75ee lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/e1000e/e1000e.ko/1772f014a7a7272859655acb0c64a20ab20b75ee .build-id/eb/4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 lib64/libc-2.10.2.so/eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 .build-id/5c/68f7afeb33309c78037e374b0deee84dd441f6 lib64/libpthread-2.10.2.so/5c68f7afeb33309c78037e374b0deee84dd441f6 .build-id/e9/c9ad5c138ef882e4507d2605645b597da43873 bin/dbus-daemon/e9c9ad5c138ef882e4507d2605645b597da43873 .build-id/bc/da7d09eb6c9ee380dae0ed3d591d4311decc31 lib64/libdbus-1.so.3.4.0/bcda7d09eb6c9ee380dae0ed3d591d4311decc31 .build-id/7c/c449a77f48b85d6088114000e970ced613bed8 usr/lib64/libcrypto.so.0.9.8k/7cc449a77f48b85d6088114000e970ced613bed8 .build-id/fd/d1ccd1ff7917ab020653147ab3bacf0a85b5b9 lib64/libglib-2.0.so.0.2000.5/fdd1ccd1ff7917ab020653147ab3bacf0a85b5b9 .build-id/e4/417ebb8762e5f2eee93c8011a71115ff5edad8 lib64/libgobject-2.0.so.0.2000.5/e4417ebb8762e5f2eee93c8011a71115ff5edad8 .build-id/93/1e49461f6df99104f0febcc52f6fed5e2efce6 usr/sbin/sshd/931e49461f6df99104f0febcc52f6fed5e2efce6 .build-id/da/b5f724c088f89fbd8304da553ed6cb30bbec96 usr/lib64/libgdk-x11-2.0.so.0.1600.6/dab5f724c088f89fbd8304da553ed6cb30bbec96 .build-id/f2/037a091ef36b591187a858d75e203690ea9409 usr/sbin/openvpn/f2037a091ef36b591187a858d75e203690ea9409 .build-id/a8/e4f743b40fb1fd8b85e2f9b88d93b661472b8f bin/find/a8e4f743b40fb1fd8b85e2f9b88d93b661472b8f .build-id/81/120aada06e68b1e85882925a0fc6d7345ef59a home/acme/bin/perf/81120aada06e68b1e85882925a0fc6d7345ef59a parisc:~# perf report 2> /dev/null | head -25 9.07% find find [.] 0x0000000000fb0e 3.29% perf libc-2.10.2.so [.] __GI_strcmp 3.19% find [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 2.70% find libc-2.10.2.so [.] __GI_memmove 2.62% perf [kernel.kallsyms] [k] vsnprintf 2.03% find libc-2.10.2.so [.] _int_malloc 2.02% perf [kernel.kallsyms] [k] format_decode 1.70% find [kernel.kallsyms] [k] n_tty_write 1.70% find [kernel.kallsyms] [k] half_md4_transform 1.67% find libc-2.10.2.so [.] _IO_vfprintf_internal 1.66% perf [kernel.kallsyms] [k] audit_free_aux 1.62% swapper [kernel.kallsyms] [k] mwait_idle_with_hints 1.58% find [kernel.kallsyms] [k] __kmalloc 1.35% find [kernel.kallsyms] [k] sched_clock_local 1.35% find [kernel.kallsyms] [k] ext4_check_dir_entry 1.35% find [kernel.kallsyms] [k] ext4_htree_store_dirent 1.35% find [kernel.kallsyms] [k] sys_write 1.35% find [e1000e] [k] e1000_clean 1.35% find [kernel.kallsyms] [k] _atomic_dec_and_lock 1.34% find [kernel.kallsyms] [k] __d_lookup parisc:~# Probably the next step is to have 'perf report' notice that there is a perf.data.tar.bz2 file in the same directory and look if it was already added to ~/.debug/. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263568672-30323-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 10 ++-------- tools/perf/command-list.txt | 1 + tools/perf/perf-archive.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 tools/perf/perf-archive.sh diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2c03a9411317..d739552036d0 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -286,11 +286,7 @@ SCRIPT_PERL = SCRIPT_SH = TEST_PROGRAMS = -# -# No scripts right now: -# - -# SCRIPT_SH += perf-am.sh +SCRIPT_SH += perf-archive.sh # # No Perl scripts right now: @@ -315,9 +311,7 @@ PROGRAMS += perf # List built-in command $C whose implementation cmd_$C() is not in # builtin-$C.o but is linked in as part of some other command. # -# None right now: -# -# BUILT_INS += perf-init $X +BUILT_INS += perf-archive # what 'all' will build and 'install' will install, in perfexecdir ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 71dc7c3fe7b2..f73d1d90f5bd 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -3,6 +3,7 @@ # command name category [deprecated] [common] # perf-annotate mainporcelain common +perf-archive mainporcelain perf-bench mainporcelain common perf-buildid-list mainporcelain common perf-diff mainporcelain common diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh new file mode 100644 index 000000000000..45fbe2f07b15 --- /dev/null +++ b/tools/perf/perf-archive.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# perf archive +# Arnaldo Carvalho de Melo + +PERF_DATA=perf.data +if [ $# -ne 0 ] ; then + PERF_DATA=$1 +fi + +DEBUGDIR=~/.debug/ +BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) + +perf buildid-list -i $PERF_DATA --with-hits > $BUILDIDS +if [ ! -s $BUILDIDS ] ; then + echo "perf archive: no build-ids found" + rm -f $BUILDIDS + exit 1 +fi + +MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) + +cut -d ' ' -f 1 $BUILDIDS | \ +while read build_id ; do + linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2} + filename=$(readlink -f $linkname) + echo ${linkname#$DEBUGDIR} >> $MANIFEST + echo ${filename#$DEBUGDIR} >> $MANIFEST +done + +tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST +rm -f $MANIFEST $BUILDIDS +exit 0 -- GitLab From f5a2c3dce03621b55f84496f58adc2d1a87ca16f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jan 2010 18:08:26 -0200 Subject: [PATCH 0803/3892] perf record: Intercept all events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The event interception we need to do in 'perf record' to create a list of all DSOs in PERF_RECORD_MMAP events wasn't seeing all events, make sure that happens by checking size agains event_t->header.size. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263586107-1756-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 614fa9a4c67c..7bb9ca1b30fa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -113,16 +113,24 @@ static void write_output(void *buf, size_t size) static void write_event(event_t *buf, size_t size) { - /* - * Add it to the list of DSOs, so that when we finish this - * record session we can pick the available build-ids. - */ - if (buf->header.type == PERF_RECORD_MMAP) { - struct list_head *head = &dsos__user; - if (buf->mmap.header.misc == 1) - head = &dsos__kernel; - __dsos__findnew(head, buf->mmap.filename); - } + size_t processed_size = buf->header.size; + event_t *ev = buf; + + do { + /* + * Add it to the list of DSOs, so that when we finish this + * record session we can pick the available build-ids. + */ + if (ev->header.type == PERF_RECORD_MMAP) { + struct list_head *head = &dsos__user; + if (ev->header.misc == 1) + head = &dsos__kernel; + __dsos__findnew(head, ev->mmap.filename); + } + + ev = ((void *)ev) + ev->header.size; + processed_size += ev->header.size; + } while (processed_size < size); write_output(buf, size); } -- GitLab From 881516eb828a3f7276c378bcef96b7788fc99016 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jan 2010 18:08:27 -0200 Subject: [PATCH 0804/3892] perf symbols: Accept an alias when looking for "_text" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it is in PARISC64: parisc:~# uname -a Linux parisc 2.6.33-rc4-tip+ #1 SMP Thu Jan 14 13:33:34 BRST 2010 parisc64 GNU/Linux parisc:~# grep -w _text /proc/kallsyms 0000000040100000 A _text parisc:~# grep 0000000040100000 /proc/kallsyms 0000000040100000 T stext 0000000040100000 T _stext 0000000040100000 A _text parisc:~# Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263586107-1756-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 966d207a1509..dc13cad828d7 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -227,7 +227,12 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start) { struct process_symbol_args *args = arg; - if (!symbol_type__is_a(type, MAP__FUNCTION) || strcmp(name, args->name)) + /* + * Must be a function or at least an alias, as in PARISC64, where "_text" is + * an 'A' to the same address as "_stext". + */ + if (!(symbol_type__is_a(type, MAP__FUNCTION) || + type == 'A') || strcmp(name, args->name)) return 0; args->start = start; -- GitLab From 889ff0150661512d79484219612b7e2e024b6c07 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 9 Jan 2010 20:04:47 +0100 Subject: [PATCH 0805/3892] perf/core: Split context's event group list into pinned and non-pinned lists Split-up struct perf_event_context::group_list into pinned_groups and flexible_groups (non-pinned). This first appears to be useless as it duplicates various loops around the group list handlings. But it scales better in the fast-path in perf_sched_in(). We don't anymore iterate twice through the entire list to separate pinned and non-pinned scheduling. Instead we interate through two distinct lists. The another desired effect is that it makes easier to define distinct scheduling rules on both. Changes in v2: - Respectively rename pinned_grp_list and volatile_grp_list into pinned_groups and flexible_groups as per Ingo suggestion. - Various cleanups Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- include/linux/perf_event.h | 3 +- kernel/perf_event.c | 227 ++++++++++++++++++++++++------------- 2 files changed, 153 insertions(+), 77 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 9a1d276db754..cdbc2aa64a0b 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -683,7 +683,8 @@ struct perf_event_context { */ struct mutex mutex; - struct list_head group_list; + struct list_head pinned_groups; + struct list_head flexible_groups; struct list_head event_list; int nr_events; int nr_active; diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 27f69a04541d..c9f8a757649d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -289,6 +289,15 @@ static void update_event_times(struct perf_event *event) event->total_time_running = run_end - event->tstamp_running; } +static struct list_head * +ctx_group_list(struct perf_event *event, struct perf_event_context *ctx) +{ + if (event->attr.pinned) + return &ctx->pinned_groups; + else + return &ctx->flexible_groups; +} + /* * Add a event from the lists for its context. * Must be called with ctx->mutex and ctx->lock held. @@ -303,9 +312,12 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) * add it straight to the context's event list, or to the group * leader's sibling list: */ - if (group_leader == event) - list_add_tail(&event->group_entry, &ctx->group_list); - else { + if (group_leader == event) { + struct list_head *list; + + list = ctx_group_list(event, ctx); + list_add_tail(&event->group_entry, list); + } else { list_add_tail(&event->group_entry, &group_leader->sibling_list); group_leader->nr_siblings++; } @@ -355,8 +367,10 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) * to the context list directly: */ list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { + struct list_head *list; - list_move_tail(&sibling->group_entry, &ctx->group_list); + list = ctx_group_list(event, ctx); + list_move_tail(&sibling->group_entry, list); sibling->group_leader = sibling; } } @@ -1056,7 +1070,10 @@ void __perf_event_sched_out(struct perf_event_context *ctx, perf_disable(); if (ctx->nr_active) { - list_for_each_entry(event, &ctx->group_list, group_entry) + list_for_each_entry(event, &ctx->pinned_groups, group_entry) + group_sched_out(event, cpuctx, ctx); + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) group_sched_out(event, cpuctx, ctx); } perf_enable(); @@ -1271,9 +1288,8 @@ __perf_event_sched_in(struct perf_event_context *ctx, * First go through the list and put on any pinned groups * in order to give them the best chance of going on. */ - list_for_each_entry(event, &ctx->group_list, group_entry) { - if (event->state <= PERF_EVENT_STATE_OFF || - !event->attr.pinned) + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + if (event->state <= PERF_EVENT_STATE_OFF) continue; if (event->cpu != -1 && event->cpu != cpu) continue; @@ -1291,15 +1307,10 @@ __perf_event_sched_in(struct perf_event_context *ctx, } } - list_for_each_entry(event, &ctx->group_list, group_entry) { - /* - * Ignore events in OFF or ERROR state, and - * ignore pinned events since we did them already. - */ - if (event->state <= PERF_EVENT_STATE_OFF || - event->attr.pinned) + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { + /* Ignore events in OFF or ERROR state */ + if (event->state <= PERF_EVENT_STATE_OFF) continue; - /* * Listen to the 'cpu' scheduling filter constraint * of events: @@ -1453,8 +1464,13 @@ static void rotate_ctx(struct perf_event_context *ctx) * Rotate the first entry last (works just fine for group events too): */ perf_disable(); - list_for_each_entry(event, &ctx->group_list, group_entry) { - list_move_tail(&event->group_entry, &ctx->group_list); + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + list_move_tail(&event->group_entry, &ctx->pinned_groups); + break; + } + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { + list_move_tail(&event->group_entry, &ctx->flexible_groups); break; } perf_enable(); @@ -1490,6 +1506,21 @@ void perf_event_task_tick(struct task_struct *curr) perf_event_task_sched_in(curr); } +static int event_enable_on_exec(struct perf_event *event, + struct perf_event_context *ctx) +{ + if (!event->attr.enable_on_exec) + return 0; + + event->attr.enable_on_exec = 0; + if (event->state >= PERF_EVENT_STATE_INACTIVE) + return 0; + + __perf_event_mark_enabled(event, ctx); + + return 1; +} + /* * Enable all of a task's events that have been marked enable-on-exec. * This expects task == current. @@ -1500,6 +1531,7 @@ static void perf_event_enable_on_exec(struct task_struct *task) struct perf_event *event; unsigned long flags; int enabled = 0; + int ret; local_irq_save(flags); ctx = task->perf_event_ctxp; @@ -1510,14 +1542,16 @@ static void perf_event_enable_on_exec(struct task_struct *task) raw_spin_lock(&ctx->lock); - list_for_each_entry(event, &ctx->group_list, group_entry) { - if (!event->attr.enable_on_exec) - continue; - event->attr.enable_on_exec = 0; - if (event->state >= PERF_EVENT_STATE_INACTIVE) - continue; - __perf_event_mark_enabled(event, ctx); - enabled = 1; + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + ret = event_enable_on_exec(event, ctx); + if (ret) + enabled = 1; + } + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { + ret = event_enable_on_exec(event, ctx); + if (ret) + enabled = 1; } /* @@ -1591,7 +1625,8 @@ __perf_event_init_context(struct perf_event_context *ctx, { raw_spin_lock_init(&ctx->lock); mutex_init(&ctx->mutex); - INIT_LIST_HEAD(&ctx->group_list); + INIT_LIST_HEAD(&ctx->pinned_groups); + INIT_LIST_HEAD(&ctx->flexible_groups); INIT_LIST_HEAD(&ctx->event_list); atomic_set(&ctx->refcount, 1); ctx->task = task; @@ -5032,7 +5067,11 @@ void perf_event_exit_task(struct task_struct *child) mutex_lock_nested(&child_ctx->mutex, SINGLE_DEPTH_NESTING); again: - list_for_each_entry_safe(child_event, tmp, &child_ctx->group_list, + list_for_each_entry_safe(child_event, tmp, &child_ctx->pinned_groups, + group_entry) + __perf_event_exit_task(child_event, child_ctx, child); + + list_for_each_entry_safe(child_event, tmp, &child_ctx->flexible_groups, group_entry) __perf_event_exit_task(child_event, child_ctx, child); @@ -5041,7 +5080,8 @@ again: * its siblings to the list, but we obtained 'tmp' before that which * will still point to the list head terminating the iteration. */ - if (!list_empty(&child_ctx->group_list)) + if (!list_empty(&child_ctx->pinned_groups) || + !list_empty(&child_ctx->flexible_groups)) goto again; mutex_unlock(&child_ctx->mutex); @@ -5049,6 +5089,24 @@ again: put_ctx(child_ctx); } +static void perf_free_event(struct perf_event *event, + struct perf_event_context *ctx) +{ + struct perf_event *parent = event->parent; + + if (WARN_ON_ONCE(!parent)) + return; + + mutex_lock(&parent->child_mutex); + list_del_init(&event->child_list); + mutex_unlock(&parent->child_mutex); + + fput(parent->filp); + + list_del_event(event, ctx); + free_event(event); +} + /* * free an unexposed, unused context as created by inheritance by * init_task below, used by fork() in case of fail. @@ -5063,36 +5121,70 @@ void perf_event_free_task(struct task_struct *task) mutex_lock(&ctx->mutex); again: - list_for_each_entry_safe(event, tmp, &ctx->group_list, group_entry) { - struct perf_event *parent = event->parent; + list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) + perf_free_event(event, ctx); - if (WARN_ON_ONCE(!parent)) - continue; + list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, + group_entry) + perf_free_event(event, ctx); - mutex_lock(&parent->child_mutex); - list_del_init(&event->child_list); - mutex_unlock(&parent->child_mutex); + if (!list_empty(&ctx->pinned_groups) || + !list_empty(&ctx->flexible_groups)) + goto again; - fput(parent->filp); + mutex_unlock(&ctx->mutex); - list_del_event(event, ctx); - free_event(event); + put_ctx(ctx); +} + +static int +inherit_task_group(struct perf_event *event, struct task_struct *parent, + struct perf_event_context *parent_ctx, + struct task_struct *child, + int *inherited_all) +{ + int ret; + struct perf_event_context *child_ctx = child->perf_event_ctxp; + + if (!event->attr.inherit) { + *inherited_all = 0; + return 0; } - if (!list_empty(&ctx->group_list)) - goto again; + if (!child_ctx) { + /* + * This is executed from the parent task context, so + * inherit events that have been marked for cloning. + * First allocate and initialize a context for the + * child. + */ - mutex_unlock(&ctx->mutex); + child_ctx = kzalloc(sizeof(struct perf_event_context), + GFP_KERNEL); + if (!child_ctx) + return -ENOMEM; - put_ctx(ctx); + __perf_event_init_context(child_ctx, child); + child->perf_event_ctxp = child_ctx; + get_task_struct(child); + } + + ret = inherit_group(event, parent, parent_ctx, + child, child_ctx); + + if (ret) + *inherited_all = 0; + + return ret; } + /* * Initialize the perf_event context in task_struct */ int perf_event_init_task(struct task_struct *child) { - struct perf_event_context *child_ctx = NULL, *parent_ctx; + struct perf_event_context *child_ctx, *parent_ctx; struct perf_event_context *cloned_ctx; struct perf_event *event; struct task_struct *parent = current; @@ -5130,41 +5222,22 @@ int perf_event_init_task(struct task_struct *child) * We dont have to disable NMIs - we are only looking at * the list, not manipulating it: */ - list_for_each_entry(event, &parent_ctx->group_list, group_entry) { - - if (!event->attr.inherit) { - inherited_all = 0; - continue; - } - - if (!child->perf_event_ctxp) { - /* - * This is executed from the parent task context, so - * inherit events that have been marked for cloning. - * First allocate and initialize a context for the - * child. - */ - - child_ctx = kzalloc(sizeof(struct perf_event_context), - GFP_KERNEL); - if (!child_ctx) { - ret = -ENOMEM; - break; - } - - __perf_event_init_context(child_ctx, child); - child->perf_event_ctxp = child_ctx; - get_task_struct(child); - } + list_for_each_entry(event, &parent_ctx->pinned_groups, group_entry) { + ret = inherit_task_group(event, parent, parent_ctx, child, + &inherited_all); + if (ret) + break; + } - ret = inherit_group(event, parent, parent_ctx, - child, child_ctx); - if (ret) { - inherited_all = 0; + list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { + ret = inherit_task_group(event, parent, parent_ctx, child, + &inherited_all); + if (ret) break; - } } + child_ctx = child->perf_event_ctxp; + if (child_ctx && inherited_all) { /* * Mark the child context as a clone of the parent @@ -5213,7 +5286,9 @@ static void __perf_event_exit_cpu(void *info) struct perf_event_context *ctx = &cpuctx->ctx; struct perf_event *event, *tmp; - list_for_each_entry_safe(event, tmp, &ctx->group_list, group_entry) + list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) + __perf_event_remove_from_context(event); + list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) __perf_event_remove_from_context(event); } static void perf_event_exit_cpu(int cpu) -- GitLab From 5908cdc85eb30f8d07f2cb11d4a62334d7229048 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 9 Jan 2010 20:53:14 +0100 Subject: [PATCH 0806/3892] list: Introduce list_rotate_left() Bring a new list_rotate_left() helper that rotates a list to the left. This is useful for codes that need to round roubin elements which queue priority increases from tail to head. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- include/linux/list.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index 969f6e92d089..5d9c6558e8ab 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -205,6 +205,20 @@ static inline int list_empty_careful(const struct list_head *head) return (next == head) && (next == head->prev); } +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + /** * list_is_singular - tests whether a list has just one entry. * @head: the list to test. -- GitLab From e286417378b4f9ce6e473b556193465ab22e12ab Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 9 Jan 2010 21:05:28 +0100 Subject: [PATCH 0807/3892] perf: Round robin flexible groups of events using list_rotate_left() This is more proper that doing it through a list_for_each_entry() that breaks after the first entry. v2: Don't rotate pinned groups as its not needed to time share them. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- kernel/perf_event.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index c9f8a757649d..bbebe2832639 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1454,25 +1454,16 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) */ static void rotate_ctx(struct perf_event_context *ctx) { - struct perf_event *event; - if (!ctx->nr_events) return; raw_spin_lock(&ctx->lock); - /* - * Rotate the first entry last (works just fine for group events too): - */ + + /* Rotate the first entry last of non-pinned groups */ perf_disable(); - list_for_each_entry(event, &ctx->pinned_groups, group_entry) { - list_move_tail(&event->group_entry, &ctx->pinned_groups); - break; - } - list_for_each_entry(event, &ctx->flexible_groups, group_entry) { - list_move_tail(&event->group_entry, &ctx->flexible_groups); - break; - } + list_rotate_left(&ctx->flexible_groups); + perf_enable(); raw_spin_unlock(&ctx->lock); -- GitLab From d6f962b57bfaab62891c7abbf1469212a56d6103 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 10 Jan 2010 01:25:51 +0100 Subject: [PATCH 0808/3892] perf: Export software-only event group characteristic as a flag Before scheduling an event group, we first check if a group can go on. We first check if the group is made of software only events first, in which case it is enough to know if the group can be scheduled in. For that purpose, we iterate through the whole group, which is wasteful as we could do this check when we add/delete an event to a group. So we create a group_flags field in perf event that can host characteristics from a group of events, starting with a first PERF_GROUP_SOFTWARE flag that reduces the check on the fast path. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- include/linux/perf_event.h | 5 +++++ kernel/perf_event.c | 30 +++++++++++------------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index cdbc2aa64a0b..c6f812e4d058 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -565,6 +565,10 @@ typedef void (*perf_overflow_handler_t)(struct perf_event *, int, struct perf_sample_data *, struct pt_regs *regs); +enum perf_group_flag { + PERF_GROUP_SOFTWARE = 0x1, +}; + /** * struct perf_event - performance event kernel representation: */ @@ -574,6 +578,7 @@ struct perf_event { struct list_head event_entry; struct list_head sibling_list; int nr_siblings; + int group_flags; struct perf_event *group_leader; struct perf_event *output; const struct pmu *pmu; diff --git a/kernel/perf_event.c b/kernel/perf_event.c index bbebe2832639..eae6ff693604 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -315,9 +315,16 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) if (group_leader == event) { struct list_head *list; + if (is_software_event(event)) + event->group_flags |= PERF_GROUP_SOFTWARE; + list = ctx_group_list(event, ctx); list_add_tail(&event->group_entry, list); } else { + if (group_leader->group_flags & PERF_GROUP_SOFTWARE && + !is_software_event(event)) + group_leader->group_flags &= ~PERF_GROUP_SOFTWARE; + list_add_tail(&event->group_entry, &group_leader->sibling_list); group_leader->nr_siblings++; } @@ -372,6 +379,9 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) list = ctx_group_list(event, ctx); list_move_tail(&sibling->group_entry, list); sibling->group_leader = sibling; + + /* Inherit group flags from the previous leader */ + sibling->group_flags = event->group_flags; } } @@ -699,24 +709,6 @@ group_error: return -EAGAIN; } -/* - * Return 1 for a group consisting entirely of software events, - * 0 if the group contains any hardware events. - */ -static int is_software_only_group(struct perf_event *leader) -{ - struct perf_event *event; - - if (!is_software_event(leader)) - return 0; - - list_for_each_entry(event, &leader->sibling_list, group_entry) - if (!is_software_event(event)) - return 0; - - return 1; -} - /* * Work out whether we can put this event group on the CPU now. */ @@ -727,7 +719,7 @@ static int group_can_go_on(struct perf_event *event, /* * Groups consisting entirely of software events can always go on. */ - if (is_software_only_group(event)) + if (event->group_flags & PERF_GROUP_SOFTWARE) return 1; /* * If an exclusive group is already on, no other hardware -- GitLab From 8eda55142080f0373b1f0268fe6d6807f193e713 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Tue, 17 Nov 2009 21:05:31 +0000 Subject: [PATCH 0809/3892] sh: New extended page flag to wire/unwire TLB entries Provide a new extended page flag, _PAGE_WIRED and an SH4 implementation for wiring TLB entries and use it in the fixmap code path so that we can wire the fixmap TLB entry. Signed-off-by: Matt Fleming --- arch/sh/include/asm/pgtable_32.h | 4 ++ arch/sh/include/asm/tlb.h | 16 ++++++ arch/sh/include/cpu-sh4/cpu/mmu_context.h | 4 ++ arch/sh/mm/tlb-pteaex.c | 66 +++++++++++++++++++++++ arch/sh/mm/tlb-sh4.c | 66 +++++++++++++++++++++++ 5 files changed, 156 insertions(+) diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h index 5003ee86f67b..c573d45f1286 100644 --- a/arch/sh/include/asm/pgtable_32.h +++ b/arch/sh/include/asm/pgtable_32.h @@ -71,6 +71,8 @@ #define _PAGE_EXT_KERN_WRITE 0x1000 /* EPR4-bit: Kernel space writable */ #define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */ +#define _PAGE_EXT_WIRED 0x4000 /* software: Wire TLB entry */ + /* Wrapper for extended mode pgprot twiddling */ #define _PAGE_EXT(x) ((unsigned long long)(x) << 32) @@ -164,6 +166,8 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \ _PAGE_DIRTY | _PAGE_SPECIAL) +#define _PAGE_WIRED (_PAGE_EXT(_PAGE_EXT_WIRED)) + #ifndef __ASSEMBLY__ #if defined(CONFIG_X2TLB) /* SH-X2 TLB */ diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h index da8fe7ab8728..3ed2f7a05416 100644 --- a/arch/sh/include/asm/tlb.h +++ b/arch/sh/include/asm/tlb.h @@ -97,6 +97,22 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) #define tlb_migrate_finish(mm) do { } while (0) +#ifdef CONFIG_CPU_SH4 +extern void tlb_wire_entry(struct vm_area_struct *, unsigned long, pte_t); +extern void tlb_unwire_entry(void); +#else +static inline void tlb_wire_entry(struct vm_area_struct *vma , + unsigned long addr, pte_t pte) +{ + BUG(); +} + +static inline void tlb_unwire_entry(void) +{ + BUG(); +} +#endif /* CONFIG_CPU_SH4 */ + #else /* CONFIG_MMU */ #define tlb_start_vma(tlb, vma) do { } while (0) diff --git a/arch/sh/include/cpu-sh4/cpu/mmu_context.h b/arch/sh/include/cpu-sh4/cpu/mmu_context.h index 3ce7ef6c2978..03ea75c5315d 100644 --- a/arch/sh/include/cpu-sh4/cpu/mmu_context.h +++ b/arch/sh/include/cpu-sh4/cpu/mmu_context.h @@ -25,6 +25,10 @@ #define MMUCR_TI (1<<2) +#define MMUCR_URB 0x00FC0000 +#define MMUCR_URB_SHIFT 18 +#define MMUCR_URB_NENTRIES 64 + #if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40) #define MMUCR_SE (1 << 4) #else diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 409b7c2b4b9d..88c8bb05e16d 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -76,3 +76,69 @@ void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT); back_to_cached(); } + +/* + * Load the entry for 'addr' into the TLB and wire the entry. + */ +void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + /* Load the entry into the TLB */ + __update_tlb(vma, addr, pte); + + /* ... and wire it up. */ + status = ctrl_inl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to wire the last TLB entry slot. + */ + BUG_ON(!--urb); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + ctrl_outl(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} + +/* + * Unwire the last wired TLB entry. + * + * It should also be noted that it is not possible to wire and unwire + * TLB entries in an arbitrary order. If you wire TLB entry N, followed + * by entry N+1, you must unwire entry N+1 first, then entry N. In this + * respect, it works like a stack or LIFO queue. + */ +void tlb_unwire_entry(void) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + status = ctrl_inl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to unwire a TLB entry when none + * have been wired. + */ + BUG_ON(urb++ == MMUCR_URB_NENTRIES); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + ctrl_outl(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 8cf550e2570f..4c6234743318 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -81,3 +81,69 @@ void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, ctrl_outl(data, addr); back_to_cached(); } + +/* + * Load the entry for 'addr' into the TLB and wire the entry. + */ +void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + /* Load the entry into the TLB */ + __update_tlb(vma, addr, pte); + + /* ... and wire it up. */ + status = ctrl_inl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to wire the last TLB entry slot. + */ + BUG_ON(!--urb); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + ctrl_outl(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} + +/* + * Unwire the last wired TLB entry. + * + * It should also be noted that it is not possible to wire and unwire + * TLB entries in an arbitrary order. If you wire TLB entry N, followed + * by entry N+1, you must unwire entry N+1 first, then entry N. In this + * respect, it works like a stack or LIFO queue. + */ +void tlb_unwire_entry(void) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + status = ctrl_inl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to unwire a TLB entry when none + * have been wired. + */ + BUG_ON(urb++ == MMUCR_URB_NENTRIES); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + ctrl_outl(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} -- GitLab From 24ef7fc4dcc57afa0c33166c25bfe7676ffd4296 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 19 Nov 2009 21:11:05 +0000 Subject: [PATCH 0810/3892] sh: Acquire some more page flags for SH-5. We need some more page flags to hook up _PAGE_WIRED (and eventually other things). So use the unused PTE bits above the PPN field as no implementations use these for anything currently. Now that we have _PAGE_WIRED let's provide the SH-5 functions for wiring up TLB entries. Signed-off-by: Matt Fleming --- arch/sh/include/asm/page.h | 2 +- arch/sh/include/asm/pgtable_64.h | 15 +++++++++++- arch/sh/include/asm/tlb.h | 41 ++++++++++++++++++++++++++++++++ arch/sh/mm/tlbflush_64.c | 2 +- 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index a86c0f1d05d4..61e58105adc3 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -88,7 +88,7 @@ typedef struct { unsigned long pgd; } pgd_t; #define __pte(x) ((pte_t) { (x) } ) #else typedef struct { unsigned long long pte_low; } pte_t; -typedef struct { unsigned long pgprot; } pgprot_t; +typedef struct { unsigned long long pgprot; } pgprot_t; typedef struct { unsigned long pgd; } pgd_t; #define pte_val(x) ((x).pte_low) #define __pte(x) ((pte_t) { (x) } ) diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h index dd381588c695..0ee46776dad6 100644 --- a/arch/sh/include/asm/pgtable_64.h +++ b/arch/sh/include/asm/pgtable_64.h @@ -123,8 +123,21 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) #define _PAGE_DIRTY 0x400 /* software: page accessed in write */ #define _PAGE_ACCESSED 0x800 /* software: page referenced */ +/* Wrapper for extended mode pgprot twiddling */ +#define _PAGE_EXT(x) ((unsigned long long)(x) << 32) + +/* + * We can use the sign-extended bits in the PTEL to get 32 bits of + * software flags. This works for now because no implementations uses + * anything above the PPN field. + */ +#define _PAGE_WIRED _PAGE_EXT(0x001) /* software: wire the tlb entry */ + +#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \ + _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED) + /* Mask which drops software flags */ -#define _PAGE_FLAGS_HARDWARE_MASK 0xfffffffffffff3dbLL +#define _PAGE_FLAGS_HARDWARE_MASK (NEFF_MASK & ~(_PAGE_CLEAR_FLAGS)) /* * HugeTLB support diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h index 3ed2f7a05416..dfc8fcd8ee50 100644 --- a/arch/sh/include/asm/tlb.h +++ b/arch/sh/include/asm/tlb.h @@ -11,6 +11,7 @@ #ifdef CONFIG_MMU #include #include +#include /* * TLB handling. This allows us to remove pages from the page @@ -100,6 +101,46 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) #ifdef CONFIG_CPU_SH4 extern void tlb_wire_entry(struct vm_area_struct *, unsigned long, pte_t); extern void tlb_unwire_entry(void); +#elif defined(CONFIG_SUPERH64) +static int dtlb_entry; +static unsigned long long dtlb_entries[64]; + +static inline void tlb_wire_entry(struct vm_area_struct *vma, + unsigned long addr, pte_t pte) +{ + unsigned long long entry; + unsigned long paddr, flags; + + BUG_ON(dtlb_entry == 64); + + local_irq_save(flags); + + entry = sh64_get_wired_dtlb_entry(); + dtlb_entries[dtlb_entry++] = entry; + + paddr = pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK; + paddr &= ~PAGE_MASK; + + sh64_setup_tlb_slot(entry, addr, get_asid(), paddr); + + local_irq_restore(flags); +} + +static inline void tlb_unwire_entry(void) +{ + unsigned long long entry; + unsigned long flags; + + BUG_ON(!dtlb_entry); + + local_irq_save(flags); + entry = dtlb_entries[dtlb_entry--]; + + sh64_teardown_tlb_slot(entry); + sh64_put_wired_dtlb_entry(entry); + + local_irq_restore(flags); +} #else static inline void tlb_wire_entry(struct vm_area_struct *vma , unsigned long addr, pte_t pte) diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index de0b0e881823..706da1d3a67a 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -36,7 +36,7 @@ extern void die(const char *,struct pt_regs *,long); static inline void print_prots(pgprot_t prot) { - printk("prot is 0x%08lx\n",pgprot_val(prot)); + printk("prot is 0x%016llx\n",pgprot_val(prot)); printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ), PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER)); -- GitLab From 07cad4dc1bfdaefd20c6329e9d8179ad1c600e92 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Tue, 17 Nov 2009 22:03:41 +0000 Subject: [PATCH 0811/3892] sh: Generalise the pte handling code for the fixmap path Generalise the code for setting and clearing pte's and allow TLB entries to be pinned and unpinned if the _PAGE_WIRED flag is present. Signed-off-by: Matt Fleming --- arch/sh/include/asm/fixmap.h | 1 + arch/sh/mm/init.c | 44 ++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h index 5ac1e40a511c..1566d3361ca4 100644 --- a/arch/sh/include/asm/fixmap.h +++ b/arch/sh/include/asm/fixmap.h @@ -65,6 +65,7 @@ enum fixed_addresses { extern void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags); +extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags); #define set_fixmap(idx, phys) \ __set_fixmap(idx, phys, PAGE_KERNEL) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index d5fb014279ad..30a9b530d456 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -39,7 +39,7 @@ unsigned long cached_to_uncached = P2SEG - P1SEG; #endif #ifdef CONFIG_MMU -static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) +static pte_t *__get_pte_phys(unsigned long addr) { pgd_t *pgd; pud_t *pud; @@ -49,22 +49,30 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) pgd = pgd_offset_k(addr); if (pgd_none(*pgd)) { pgd_ERROR(*pgd); - return; + return NULL; } pud = pud_alloc(NULL, pgd, addr); if (unlikely(!pud)) { pud_ERROR(*pud); - return; + return NULL; } pmd = pmd_alloc(NULL, pud, addr); if (unlikely(!pmd)) { pmd_ERROR(*pmd); - return; + return NULL; } pte = pte_offset_kernel(pmd, addr); + return pte; +} + +static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) +{ + pte_t *pte; + + pte = __get_pte_phys(addr); if (!pte_none(*pte)) { pte_ERROR(*pte); return; @@ -72,6 +80,22 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); local_flush_tlb_one(get_asid(), addr); + + if (pgprot_val(prot) & _PAGE_WIRED) + tlb_wire_entry(NULL, addr, *pte); +} + +static void clear_pte_phys(unsigned long addr, pgprot_t prot) +{ + pte_t *pte; + + pte = __get_pte_phys(addr); + + if (pgprot_val(prot) & _PAGE_WIRED) + tlb_unwire_entry(); + + set_pte(pte, pfn_pte(0, __pgprot(0))); + local_flush_tlb_one(get_asid(), addr); } /* @@ -101,6 +125,18 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) set_pte_phys(address, phys, prot); } +void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot) +{ + unsigned long address = __fix_to_virt(idx); + + if (idx >= __end_of_fixed_addresses) { + BUG(); + return; + } + + clear_pte_phys(address, prot); +} + void __init page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { -- GitLab From 4d35b93a66e9b87df20784fcf130d2e8760be53f Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 5 Nov 2009 07:54:17 +0000 Subject: [PATCH 0812/3892] sh: Add fixed ioremap support Some devices need to be ioremap'd and accessed very early in the boot process. It is not possible to use the standard ioremap() function in this case because that requires kmalloc()'ing some virtual address space and kmalloc() may not be available so early in boot. This patch provides fixmap mappings that allow physical address ranges to be remapped into the kernel address space during the early boot stages. Signed-off-by: Matt Fleming --- arch/sh/include/asm/fixmap.h | 8 ++ arch/sh/include/asm/io.h | 6 ++ arch/sh/kernel/setup.c | 7 +- arch/sh/mm/Kconfig | 4 + arch/sh/mm/Makefile | 1 + arch/sh/mm/ioremap_fixed.c | 144 +++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 arch/sh/mm/ioremap_fixed.c diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h index 1566d3361ca4..38a1de866873 100644 --- a/arch/sh/include/asm/fixmap.h +++ b/arch/sh/include/asm/fixmap.h @@ -60,6 +60,14 @@ enum fixed_addresses { FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + /* + * FIX_IOREMAP entries are useful for mapping physical address + * space before ioremap() is useable, e.g. really early in boot + * before kmalloc() is working. + */ +#define FIX_N_IOREMAPS 32 + FIX_IOREMAP_BEGIN, + FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS, __end_of_fixed_addresses }; diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index f4314d8b05b8..bee5965e0a82 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -237,6 +237,12 @@ void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, unsigned long flags, void *caller); void __iounmap(void __iomem *addr); +#ifdef CONFIG_IOREMAP_FIXED +extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t); +extern void iounmap_fixed(void __iomem *); +extern void ioremap_fixed_init(void); +#endif + static inline void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags) { diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index f79ebe32a24a..e187750dd319 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -449,14 +449,15 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + paging_init(); + pmb_init(); + + ioremap_fixed_init(); /* Perform the machine specific initialisation */ if (likely(sh_mv.mv_setup)) sh_mv.mv_setup(cmdline_p); - paging_init(); - pmb_init(); - #ifdef CONFIG_SMP plat_smp_setup(); #endif diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 7a4ebc8cbadd..b89075256b70 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -169,6 +169,10 @@ config ARCH_MEMORY_PROBE def_bool y depends on MEMORY_HOTPLUG +config IOREMAP_FIXED + def_bool y + depends on X2TLB || SUPERH64 + choice prompt "Kernel page size" default PAGE_SIZE_4KB diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index edde8bdd681d..89ba56c20ade 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -35,6 +35,7 @@ endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_PMB) += pmb.o obj-$(CONFIG_NUMA) += numa.o +obj-$(CONFIG_IOREMAP_FIXED) += ioremap_fixed.o # Special flags for fault_64.o. This puts restrictions on the number of # caller-save registers that the compiler can target when building this file. diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c new file mode 100644 index 000000000000..3a9d3d88fe8d --- /dev/null +++ b/arch/sh/mm/ioremap_fixed.c @@ -0,0 +1,144 @@ +/* + * Re-map IO memory to kernel address space so that we can access it. + * + * These functions should only be used when it is necessary to map a + * physical address space into the kernel address space before ioremap() + * can be used, e.g. early in boot before paging_init(). + * + * Copyright (C) 2009 Matt Fleming + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ioremap_map { + void __iomem *addr; + unsigned long size; + unsigned long fixmap_addr; +}; + +static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS]; + +void __init ioremap_fixed_init(void) +{ + struct ioremap_map *map; + int i; + + for (i = 0; i < FIX_N_IOREMAPS; i++) { + map = &ioremap_maps[i]; + map->fixmap_addr = __fix_to_virt(FIX_IOREMAP_BEGIN + i); + } +} + +void __init __iomem * +ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot) +{ + enum fixed_addresses idx0, idx; + resource_size_t last_addr; + struct ioremap_map *map; + unsigned long offset; + unsigned int nrpages; + int i, slot; + + slot = -1; + for (i = 0; i < FIX_N_IOREMAPS; i++) { + map = &ioremap_maps[i]; + if (!map->addr) { + map->size = size; + slot = i; + break; + } + } + + if (slot < 0) + return NULL; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Fixmap mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + /* + * Mappings have to fit in the FIX_IOREMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > FIX_N_IOREMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx0 = FIX_IOREMAP_BEGIN + slot; + idx = idx0; + while (nrpages > 0) { + pgprot_val(prot) |= _PAGE_WIRED; + __set_fixmap(idx, phys_addr, prot); + phys_addr += PAGE_SIZE; + idx++; + --nrpages; + } + + map->addr = (void __iomem *)(offset + map->fixmap_addr); + return map->addr; +} + +void __init iounmap_fixed(void __iomem *addr) +{ + enum fixed_addresses idx; + unsigned long virt_addr; + struct ioremap_map *map; + unsigned long offset; + unsigned int nrpages; + int i, slot; + pgprot_t prot; + + slot = -1; + for (i = 0; i < FIX_N_IOREMAPS; i++) { + map = &ioremap_maps[i]; + if (map->addr == addr) { + slot = i; + break; + } + } + + if (slot < 0) + return; + + virt_addr = (unsigned long)addr; + + offset = virt_addr & ~PAGE_MASK; + nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT; + + pgprot_val(prot) = _PAGE_WIRED; + + idx = FIX_IOREMAP_BEGIN + slot + nrpages; + while (nrpages > 0) { + __clear_fixmap(idx, prot); + --idx; + --nrpages; + } + + map->size = 0; + map->addr = NULL; +} -- GitLab From 6f82b6ebb1dcc0c3c23820a70a5d79a60c4f5e84 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 5 Nov 2009 08:01:10 +0000 Subject: [PATCH 0813/3892] sh: Use ioremap_fixmed to map the SM501 DRAM config register We need to write to the DRAM config register very early and at such an early stage ioremap() is not available. So use ioremap_fixed() to map the register. The reason that we are avoiding using the legacy P2 mapping is that there will come a day when the legacy P2 mappings no longer exist. Signed-off-by: Matt Fleming --- arch/sh/boards/board-sh7785lcr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index 7eea90db6cea..511de38d2046 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -332,8 +332,15 @@ static void __init sh7785lcr_setup(char **cmdline_p) pm_power_off = sh7785lcr_power_off; /* sm501 DRAM configuration */ - sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL; - writel(0x000307c2, sm501_reg); + sm501_reg = ioremap_fixed(SM107_REG_ADDR, SM501_DRAM_CONTROL, + PAGE_KERNEL); + if (!sm501_reg) { + printk(KERN_ERR "%s: ioremap error.\n", __func__); + return; + } + + writel(0x000307c2, sm501_reg + SM501_DRAM_CONTROL); + iounmap_fixed(sm501_reg); } /* Return the board specific boot mode pin configuration */ -- GitLab From 597fe76ec36e782aa45b8dac5e12e4dbb0588967 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 5 Nov 2009 20:49:05 +0000 Subject: [PATCH 0814/3892] sh: Use ioremap_fixed() to implement SH-5 ioremap() Use the fixmap-based memory mapping implementation for SH-5's ioremap() functions and delete the old static allocator that was borrowed from sparc. Signed-off-by: Matt Fleming --- arch/sh/mm/ioremap_64.c | 287 +--------------------------------------- 1 file changed, 4 insertions(+), 283 deletions(-) diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c index ef434657d428..fb0aa457c71e 100644 --- a/arch/sh/mm/ioremap_64.c +++ b/arch/sh/mm/ioremap_64.c @@ -28,299 +28,20 @@ #include #include -static struct resource shmedia_iomap = { - .name = "shmedia_iomap", - .start = IOBASE_VADDR + PAGE_SIZE, - .end = IOBASE_END - 1, -}; - -static void shmedia_mapioaddr(unsigned long pa, unsigned long va, - unsigned long flags); -static void shmedia_unmapioaddr(unsigned long vaddr); -static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, - int sz, unsigned long flags); - -/* - * We have the same problem as the SPARC, so lets have the same comment: - * Our mini-allocator... - * Boy this is gross! We need it because we must map I/O for - * timers and interrupt controller before the kmalloc is available. - */ - -#define XNMLN 15 -#define XNRES 10 - -struct xresource { - struct resource xres; /* Must be first */ - int xflag; /* 1 == used */ - char xname[XNMLN+1]; -}; - -static struct xresource xresv[XNRES]; - -static struct xresource *xres_alloc(void) -{ - struct xresource *xrp; - int n; - - xrp = xresv; - for (n = 0; n < XNRES; n++) { - if (xrp->xflag == 0) { - xrp->xflag = 1; - return xrp; - } - xrp++; - } - return NULL; -} - -static void xres_free(struct xresource *xrp) -{ - xrp->xflag = 0; -} - -static struct resource *shmedia_find_resource(struct resource *root, - unsigned long vaddr) -{ - struct resource *res; - - for (res = root->child; res; res = res->sibling) - if (res->start <= vaddr && res->end >= vaddr) - return res; - - return NULL; -} - -static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, - const char *name, unsigned long flags) -{ - struct xresource *xres; - struct resource *res; - char *tack; - int tlen; - - if (name == NULL) - name = "???"; - - xres = xres_alloc(); - if (xres != 0) { - tack = xres->xname; - res = &xres->xres; - } else { - printk_once(KERN_NOTICE "%s: done with statics, " - "switching to kmalloc\n", __func__); - tlen = strlen(name); - tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); - if (!tack) - return NULL; - memset(tack, 0, sizeof(struct resource)); - res = (struct resource *) tack; - tack += sizeof(struct resource); - } - - strncpy(tack, name, XNMLN); - tack[XNMLN] = 0; - res->name = tack; - - return shmedia_ioremap(res, phys, size, flags); -} - -static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz, - unsigned long flags) -{ - unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); - unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; - unsigned long va; - unsigned int psz; - - if (allocate_resource(&shmedia_iomap, res, round_sz, - shmedia_iomap.start, shmedia_iomap.end, - PAGE_SIZE, NULL, NULL) != 0) { - panic("alloc_io_res(%s): cannot occupy\n", - (res->name != NULL) ? res->name : "???"); - } - - va = res->start; - pa &= PAGE_MASK; - - psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; - - for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { - shmedia_mapioaddr(pa, va, flags); - va += PAGE_SIZE; - pa += PAGE_SIZE; - } - - return (void __iomem *)(unsigned long)(res->start + offset); -} - -static void shmedia_free_io(struct resource *res) -{ - unsigned long len = res->end - res->start + 1; - - BUG_ON((len & (PAGE_SIZE - 1)) != 0); - - while (len) { - len -= PAGE_SIZE; - shmedia_unmapioaddr(res->start + len); - } - - release_resource(res); -} - -static __init_refok void *sh64_get_page(void) -{ - void *page; - - if (slab_is_available()) - page = (void *)get_zeroed_page(GFP_KERNEL); - else - page = alloc_bootmem_pages(PAGE_SIZE); - - if (!page || ((unsigned long)page & ~PAGE_MASK)) - panic("sh64_get_page: Out of memory already?\n"); - - return page; -} - -static void shmedia_mapioaddr(unsigned long pa, unsigned long va, - unsigned long flags) +void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, + unsigned long flags, void *caller) { - pgd_t *pgdp; - pud_t *pudp; - pmd_t *pmdp; - pte_t *ptep, pte; pgprot_t prot; - pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); - - if (!flags) - flags = 1; /* 1 = CB0-1 device */ - - pgdp = pgd_offset_k(va); - if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { - pudp = (pud_t *)sh64_get_page(); - set_pgd(pgdp, __pgd((unsigned long)pudp | _KERNPG_TABLE)); - } - - pudp = pud_offset(pgdp, va); - if (pud_none(*pudp) || !pud_present(*pudp)) { - pmdp = (pmd_t *)sh64_get_page(); - set_pud(pudp, __pud((unsigned long)pmdp | _KERNPG_TABLE)); - } - - pmdp = pmd_offset(pudp, va); - if (pmd_none(*pmdp) || !pmd_present(*pmdp)) { - ptep = (pte_t *)sh64_get_page(); - set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); - } - prot = __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SHARED | flags); - pte = pfn_pte(pa >> PAGE_SHIFT, prot); - ptep = pte_offset_kernel(pmdp, va); - - if (!pte_none(*ptep) && - pte_val(*ptep) != pte_val(pte)) - pte_ERROR(*ptep); - - set_pte(ptep, pte); - - flush_tlb_kernel_range(va, PAGE_SIZE); -} - -static void shmedia_unmapioaddr(unsigned long vaddr) -{ - pgd_t *pgdp; - pud_t *pudp; - pmd_t *pmdp; - pte_t *ptep; - - pgdp = pgd_offset_k(vaddr); - if (pgd_none(*pgdp) || pgd_bad(*pgdp)) - return; - - pudp = pud_offset(pgdp, vaddr); - if (pud_none(*pudp) || pud_bad(*pudp)) - return; - - pmdp = pmd_offset(pudp, vaddr); - if (pmd_none(*pmdp) || pmd_bad(*pmdp)) - return; - - ptep = pte_offset_kernel(pmdp, vaddr); - - if (pte_none(*ptep) || !pte_present(*ptep)) - return; - - clear_page((void *)ptep); - pte_clear(&init_mm, vaddr, ptep); -} - -void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, - unsigned long flags, void *caller) -{ - char name[14]; - - sprintf(name, "phys_%08x", (u32)offset); - return shmedia_alloc_io(offset, size, name, flags); + return ioremap_fixed(offset, size, prot); } EXPORT_SYMBOL(__ioremap_caller); void __iounmap(void __iomem *virtual) { - unsigned long vaddr = (unsigned long)virtual & PAGE_MASK; - struct resource *res; - unsigned int psz; - - res = shmedia_find_resource(&shmedia_iomap, vaddr); - if (!res) { - printk(KERN_ERR "%s: Failed to free 0x%08lx\n", - __func__, vaddr); - return; - } - - psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; - - shmedia_free_io(res); - - if ((char *)res >= (char *)xresv && - (char *)res < (char *)&xresv[XNRES]) { - xres_free((struct xresource *)res); - } else { - kfree(res); - } + iounmap_fixed(virtual); } EXPORT_SYMBOL(__iounmap); - -static int -ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, - void *data) -{ - char *p = buf, *e = buf + length; - struct resource *r; - const char *nm; - - for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { - if (p + 32 >= e) /* Better than nothing */ - break; - nm = r->name; - if (nm == NULL) - nm = "???"; - - p += sprintf(p, "%08lx-%08lx: %s\n", - (unsigned long)r->start, - (unsigned long)r->end, nm); - } - - return p-buf; -} - -static int __init register_proc_onchip(void) -{ - create_proc_read_entry("io_map", 0, 0, ioremap_proc_info, - &shmedia_iomap); - return 0; -} -late_initcall(register_proc_onchip); -- GitLab From 78bf04fc96f509474c6b443b515d6b79bb7bf584 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 17 Jan 2010 01:45:26 +0900 Subject: [PATCH 0815/3892] sh: Tidy up non-translatable checks in iounmap path. This tidies up the iounmap path with consolidated checks for nontranslatable mappings. This is in preparation of unifying the implementations. Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap_32.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c index 2141befb4f91..c80a8166fbb0 100644 --- a/arch/sh/mm/ioremap_32.c +++ b/arch/sh/mm/ioremap_32.c @@ -105,15 +105,35 @@ void __iomem *__ioremap_caller(unsigned long phys_addr, unsigned long size, } EXPORT_SYMBOL(__ioremap_caller); +/* + * Simple checks for non-translatable mappings. + */ +static inline int iomapping_nontranslatable(unsigned long offset) +{ +#ifdef CONFIG_29BIT + /* + * In 29-bit mode this includes the fixed P1/P2 areas, as well as + * parts of P3. + */ + if (PXSEG(offset) < P3SEG || offset >= P3_ADDR_MAX) + return 1; +#endif + + if (is_pci_memory_fixed_range(offset, 0)) + return 1; + + return 0; +} + void __iounmap(void __iomem *addr) { unsigned long vaddr = (unsigned long __force)addr; - unsigned long seg = PXSEG(vaddr); struct vm_struct *p; - if (seg < P3SEG || vaddr >= P3_ADDR_MAX) - return; - if (is_pci_memory_fixed_range(vaddr, 0)) + /* + * Nothing to do if there is no translatable mapping. + */ + if (iomapping_nontranslatable(vaddr)) return; #ifdef CONFIG_PMB -- GitLab From 69e3f52d1b1a3ed4390bb8a09bb1324265af7fbf Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 16 Jan 2010 14:21:15 +0100 Subject: [PATCH 0816/3892] perf: Fix implicit declaration of getline in util.c getline() is considered as undeclared in util/util.c because it includes string.h, that in turn includes stdio.h, without having defined _GNU_SOURCE. But util.c also includes util.h that handles the _GNU_SOURCE and all the needed inclusions already. Let's include only util.h and sys/mman.h which is the only one header not handled by util.h This fixes the following build error: util/util.c: In function 'slow_copyfile': util/util.c:49: erreur: implicit declaration of function 'getline' util/util.c:49: erreur: nested extern declaration of 'getline' Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras LKML-Reference: <1263648075-3858-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/util.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index f0685849b244..f9b890fde681 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,10 +1,5 @@ -#include -#include -#include -#include -#include -#include #include "util.h" +#include int mkdir_p(char *path, mode_t mode) { -- GitLab From 0eda7385db1f30271ade830a231006938a76fb53 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 16 Jan 2010 21:31:16 +0900 Subject: [PATCH 0817/3892] perf probe: Fix build error of builtin-probe.c I got this build error when building tip tree: | cc1: warnings being treated as errors | builtin-probe.c:123: error: 'opt_show_lines' defined but not used This error is caused by: | #ifndef NO_LIBDWARF | OPT_CALLBACK('L', "line", NULL, | "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", | "Show source code lines.", opt_show_lines), | #endif My environment defines NO_LIBDWARF, so gcc treated opt_show_lines() as garbage. So I moved opt_show_lines() into #ifndef NO_LIBDWARF ... #endif block. Signed-off-by: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Masami Hiramatsu Cc: Mike Galbraith LKML-Reference: <1263645076-9993-1-git-send-email-mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar --- tools/perf/builtin-probe.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 1d3a99ea5ce1..34f2acb1cc88 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -118,15 +118,6 @@ static int opt_del_probe_event(const struct option *opt __used, return 0; } -static int opt_show_lines(const struct option *opt __used, - const char *str, int unset __used) -{ - if (str) - parse_line_range_desc(str, &session.line_range); - INIT_LIST_HEAD(&session.line_range.line_list); - session.show_lines = true; - return 0; -} /* Currently just checking function name from symbol map */ static void evaluate_probe_point(struct probe_point *pp) { @@ -148,6 +139,16 @@ static int open_vmlinux(void) pr_debug("Try to open %s\n", session.kmap->dso->long_name); return open(session.kmap->dso->long_name, O_RDONLY); } + +static int opt_show_lines(const struct option *opt __used, + const char *str, int unset __used) +{ + if (str) + parse_line_range_desc(str, &session.line_range); + INIT_LIST_HEAD(&session.line_range.line_list); + session.show_lines = true; + return 0; +} #endif static const char * const probe_usage[] = { -- GitLab From 6d686f4564f3fc7c6e678852919e48ad331d276b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 13 Jan 2010 20:21:52 -0700 Subject: [PATCH 0818/3892] sched: Don't expose local functions kernel/sched: don't expose local functions The get_rr_interval_* functions are all class methods of struct sched_class. They are not exported so make them static. Signed-off-by: H Hartley Sweeten Cc: Peter Zijlstra LKML-Reference: <201001132021.53253.hartleys@visionengravers.com> Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 2 +- kernel/sched_idletask.c | 2 +- kernel/sched_rt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 42ac3c9f66f6..71778601c103 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2076,7 +2076,7 @@ static void moved_group_fair(struct task_struct *p, int on_rq) } #endif -unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task) +static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task) { struct sched_entity *se = &task->se; unsigned int rr_interval = 0; diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c index 5f93b570d383..01332bfc61a7 100644 --- a/kernel/sched_idletask.c +++ b/kernel/sched_idletask.c @@ -97,7 +97,7 @@ static void prio_changed_idle(struct rq *rq, struct task_struct *p, check_preempt_curr(rq, p, 0); } -unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task) +static unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task) { return 0; } diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index f48328ac216f..072b3fcee8d8 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1721,7 +1721,7 @@ static void set_curr_task_rt(struct rq *rq) dequeue_pushable_task(rq, p); } -unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task) +static unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task) { /* * Time slice is 0 for SCHED_FIFO tasks -- GitLab From 231e36f4d2e63dd770db80b9f5113310c2bcfcfd Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Jan 2010 00:12:12 -0500 Subject: [PATCH 0819/3892] tracing/kprobe: Update kprobe tracing self test for new syntax Update kprobe tracing self test for new syntax (it supports deleting individual probes, and drops $argN support) and behavior change (new probes are disabled in default). This selftest includes the following checks: - Adding function-entry probe and return probe with arguments. - Enabling these probes. - Deleting it individually. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <20100114051211.7814.29436.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar --- kernel/trace/trace_kprobe.c | 55 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 7ac728ded964..d6266cad6953 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1507,28 +1507,67 @@ static int kprobe_trace_selftest_target(int a1, int a2, int a3, static __init int kprobe_trace_self_tests_init(void) { - int ret; + int ret, warn = 0; int (*target)(int, int, int, int, int, int); + struct trace_probe *tp; target = kprobe_trace_selftest_target; pr_info("Testing kprobe tracing: "); ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target " - "$arg1 $arg2 $arg3 $arg4 $stack $stack0"); - if (WARN_ON_ONCE(ret)) - pr_warning("error enabling function entry\n"); + "$stack $stack0 +0($stack)"); + if (WARN_ON_ONCE(ret)) { + pr_warning("error on probing function entry.\n"); + warn++; + } else { + /* Enable trace point */ + tp = find_probe_event("testprobe", KPROBE_EVENT_SYSTEM); + if (WARN_ON_ONCE(tp == NULL)) { + pr_warning("error on getting new probe.\n"); + warn++; + } else + probe_event_enable(&tp->call); + } ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target " "$retval"); - if (WARN_ON_ONCE(ret)) - pr_warning("error enabling function return\n"); + if (WARN_ON_ONCE(ret)) { + pr_warning("error on probing function return.\n"); + warn++; + } else { + /* Enable trace point */ + tp = find_probe_event("testprobe2", KPROBE_EVENT_SYSTEM); + if (WARN_ON_ONCE(tp == NULL)) { + pr_warning("error on getting new probe.\n"); + warn++; + } else + probe_event_enable(&tp->call); + } + + if (warn) + goto end; ret = target(1, 2, 3, 4, 5, 6); - cleanup_all_probes(); + ret = command_trace_probe("-:testprobe"); + if (WARN_ON_ONCE(ret)) { + pr_warning("error on deleting a probe.\n"); + warn++; + } + + ret = command_trace_probe("-:testprobe2"); + if (WARN_ON_ONCE(ret)) { + pr_warning("error on deleting a probe.\n"); + warn++; + } - pr_cont("OK\n"); +end: + cleanup_all_probes(); + if (warn) + pr_cont("NG: Some tests are failed. Please check them.\n"); + else + pr_cont("OK\n"); return 0; } -- GitLab From 73c89c15b959adf06366722c4be8d2eddec0a529 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Sun, 17 Jan 2010 21:52:11 +1100 Subject: [PATCH 0820/3892] crypto: gcm - Add RFC4543 wrapper for GCM This patch adds the RFC4543 (GMAC) wrapper for GCM similar to the existing RFC4106 wrapper. The main differences between GCM and GMAC are the contents of the AAD and that the plaintext is empty for the latter. Signed-off-by: Tobias Brunner Signed-off-by: Herbert Xu --- crypto/gcm.c | 287 ++++++++++++++++++++++++++++++++++++++++ include/linux/pfkeyv2.h | 1 + net/xfrm/xfrm_algo.c | 16 +++ 3 files changed, 304 insertions(+) diff --git a/crypto/gcm.c b/crypto/gcm.c index c6547130624c..2f5fbba6576c 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -37,6 +37,19 @@ struct crypto_rfc4106_ctx { u8 nonce[4]; }; +struct crypto_rfc4543_ctx { + struct crypto_aead *child; + u8 nonce[4]; +}; + +struct crypto_rfc4543_req_ctx { + u8 auth_tag[16]; + struct scatterlist cipher[1]; + struct scatterlist payload[2]; + struct scatterlist assoc[2]; + struct aead_request subreq; +}; + struct crypto_gcm_ghash_ctx { unsigned int cryptlen; struct scatterlist *src; @@ -1047,6 +1060,272 @@ static struct crypto_template crypto_rfc4106_tmpl = { .module = THIS_MODULE, }; +static inline struct crypto_rfc4543_req_ctx *crypto_rfc4543_reqctx( + struct aead_request *req) +{ + unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req)); + + return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); +} + +static int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); + struct crypto_aead *child = ctx->child; + int err; + + if (keylen < 4) + return -EINVAL; + + keylen -= 4; + memcpy(ctx->nonce, key + keylen, 4); + + crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_aead_setkey(child, key, keylen); + crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return err; +} + +static int crypto_rfc4543_setauthsize(struct crypto_aead *parent, + unsigned int authsize) +{ + struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); + + if (authsize != 16) + return -EINVAL; + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +/* this is the same as crypto_authenc_chain */ +static void crypto_rfc4543_chain(struct scatterlist *head, + struct scatterlist *sg, int chain) +{ + if (chain) { + head->length += sg->length; + sg = scatterwalk_sg_next(sg); + } + + if (sg) + scatterwalk_sg_chain(head, 2, sg); + else + sg_mark_end(head); +} + +static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req, + int enc) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req); + struct aead_request *subreq = &rctx->subreq; + struct scatterlist *dst = req->dst; + struct scatterlist *cipher = rctx->cipher; + struct scatterlist *payload = rctx->payload; + struct scatterlist *assoc = rctx->assoc; + unsigned int authsize = crypto_aead_authsize(aead); + unsigned int assoclen = req->assoclen; + struct page *dstp; + u8 *vdst; + u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child), + crypto_aead_alignmask(ctx->child) + 1); + + memcpy(iv, ctx->nonce, 4); + memcpy(iv + 4, req->iv, 8); + + /* construct cipher/plaintext */ + if (enc) + memset(rctx->auth_tag, 0, authsize); + else + scatterwalk_map_and_copy(rctx->auth_tag, dst, + req->cryptlen - authsize, + authsize, 0); + + sg_init_one(cipher, rctx->auth_tag, authsize); + + /* construct the aad */ + dstp = sg_page(dst); + vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset; + + sg_init_table(payload, 2); + sg_set_buf(payload, req->iv, 8); + crypto_rfc4543_chain(payload, dst, vdst == req->iv + 8); + assoclen += 8 + req->cryptlen - (enc ? 0 : authsize); + + sg_init_table(assoc, 2); + sg_set_page(assoc, sg_page(req->assoc), req->assoc->length, + req->assoc->offset); + crypto_rfc4543_chain(assoc, payload, 0); + + aead_request_set_tfm(subreq, ctx->child); + aead_request_set_callback(subreq, req->base.flags, req->base.complete, + req->base.data); + aead_request_set_crypt(subreq, cipher, cipher, enc ? 0 : authsize, iv); + aead_request_set_assoc(subreq, assoc, assoclen); + + return subreq; +} + +static int crypto_rfc4543_encrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req); + struct aead_request *subreq; + int err; + + subreq = crypto_rfc4543_crypt(req, 1); + err = crypto_aead_encrypt(subreq); + if (err) + return err; + + scatterwalk_map_and_copy(rctx->auth_tag, req->dst, req->cryptlen, + crypto_aead_authsize(aead), 1); + + return 0; +} + +static int crypto_rfc4543_decrypt(struct aead_request *req) +{ + req = crypto_rfc4543_crypt(req, 0); + + return crypto_aead_decrypt(req); +} + +static int crypto_rfc4543_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aead *aead; + unsigned long align; + + aead = crypto_spawn_aead(spawn); + if (IS_ERR(aead)) + return PTR_ERR(aead); + + ctx->child = aead; + + align = crypto_aead_alignmask(aead); + align &= ~(crypto_tfm_ctx_alignment() - 1); + tfm->crt_aead.reqsize = sizeof(struct crypto_rfc4543_req_ctx) + + ALIGN(crypto_aead_reqsize(aead), + crypto_tfm_ctx_alignment()) + + align + 16; + + return 0; +} + +static void crypto_rfc4543_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static struct crypto_instance *crypto_rfc4543_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_aead_spawn *spawn; + struct crypto_alg *alg; + const char *ccm_name; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + + ccm_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(ccm_name); + if (IS_ERR(ccm_name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + crypto_set_aead_spawn(spawn, inst); + err = crypto_grab_aead(spawn, ccm_name, 0, + crypto_requires_sync(algt->type, algt->mask)); + if (err) + goto out_free_inst; + + alg = crypto_aead_spawn_alg(spawn); + + err = -EINVAL; + + /* We only support 16-byte blocks. */ + if (alg->cra_aead.ivsize != 16) + goto out_drop_alg; + + /* Not a stream cipher? */ + if (alg->cra_blocksize != 1) + goto out_drop_alg; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "rfc4543(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "rfc4543(%s)", alg->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_drop_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_nivaead_type; + + inst->alg.cra_aead.ivsize = 8; + inst->alg.cra_aead.maxauthsize = 16; + + inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx); + + inst->alg.cra_init = crypto_rfc4543_init_tfm; + inst->alg.cra_exit = crypto_rfc4543_exit_tfm; + + inst->alg.cra_aead.setkey = crypto_rfc4543_setkey; + inst->alg.cra_aead.setauthsize = crypto_rfc4543_setauthsize; + inst->alg.cra_aead.encrypt = crypto_rfc4543_encrypt; + inst->alg.cra_aead.decrypt = crypto_rfc4543_decrypt; + + inst->alg.cra_aead.geniv = "seqiv"; + +out: + return inst; + +out_drop_alg: + crypto_drop_aead(spawn); +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static void crypto_rfc4543_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_rfc4543_tmpl = { + .name = "rfc4543", + .alloc = crypto_rfc4543_alloc, + .free = crypto_rfc4543_free, + .module = THIS_MODULE, +}; + static int __init crypto_gcm_module_init(void) { int err; @@ -1067,8 +1346,14 @@ static int __init crypto_gcm_module_init(void) if (err) goto out_undo_gcm; + err = crypto_register_template(&crypto_rfc4543_tmpl); + if (err) + goto out_undo_rfc4106; + return 0; +out_undo_rfc4106: + crypto_unregister_template(&crypto_rfc4106_tmpl); out_undo_gcm: crypto_unregister_template(&crypto_gcm_tmpl); out_undo_base: @@ -1081,6 +1366,7 @@ out: static void __exit crypto_gcm_module_exit(void) { kfree(gcm_zeroes); + crypto_unregister_template(&crypto_rfc4543_tmpl); crypto_unregister_template(&crypto_rfc4106_tmpl); crypto_unregister_template(&crypto_gcm_tmpl); crypto_unregister_template(&crypto_gcm_base_tmpl); @@ -1094,3 +1380,4 @@ MODULE_DESCRIPTION("Galois/Counter Mode"); MODULE_AUTHOR("Mikko Herranen "); MODULE_ALIAS("gcm_base"); MODULE_ALIAS("rfc4106"); +MODULE_ALIAS("rfc4543"); diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 228b0b6306b0..0b80c806631f 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -315,6 +315,7 @@ struct sadb_x_kmaddress { #define SADB_X_EALG_AES_GCM_ICV12 19 #define SADB_X_EALG_AES_GCM_ICV16 20 #define SADB_X_EALG_CAMELLIACBC 22 +#define SADB_X_EALG_NULL_AES_GMAC 23 #define SADB_EALG_MAX 253 /* last EALG */ /* private allocations should use 249-255 (RFC2407) */ #define SADB_X_EALG_SERPENTCBC 252 /* draft-ietf-ipsec-ciph-aes-cbc-00 */ diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 743c0134a6a9..8b4d6e3246e5 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -125,6 +125,22 @@ static struct xfrm_algo_desc aead_list[] = { .sadb_alg_maxbits = 256 } }, +{ + .name = "rfc4543(gcm(aes))", + + .uinfo = { + .aead = { + .icv_truncbits = 128, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC, + .sadb_alg_ivlen = 8, + .sadb_alg_minbits = 128, + .sadb_alg_maxbits = 256 + } +}, }; static struct xfrm_algo_desc aalg_list[] = { -- GitLab From 6c3f975a4cafaf4dcc9795385da6d42caa37ddeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Sun, 17 Jan 2010 21:54:01 +1100 Subject: [PATCH 0821/3892] crypto: Make Open Firmware device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Márton Németh The match_table field of the struct of_device_id is constant in so it is worth to make the initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 2 +- drivers/crypto/talitos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 46e899ac924e..1c3849f6b7a2 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1274,7 +1274,7 @@ static int __exit crypto4xx_remove(struct of_device *ofdev) return 0; } -static struct of_device_id crypto4xx_match[] = { +static const struct of_device_id crypto4xx_match[] = { { .compatible = "amcc,ppc4xx-crypto",}, { }, }; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c47ffe8a73ef..fd529d68c5ba 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1958,7 +1958,7 @@ err_out: return err; } -static struct of_device_id talitos_match[] = { +static const struct of_device_id talitos_match[] = { { .compatible = "fsl,sec2.0", }, -- GitLab From 7d6f75eb21b84cdc5dfb09789974f02b42a89058 Mon Sep 17 00:00:00 2001 From: Max Vozeler Date: Sun, 17 Jan 2010 21:55:31 +1100 Subject: [PATCH 0822/3892] crypto: md5 - Add export support This patch adds export/import support to md5. The exported type is defined by struct md5_state. This is modeled after the equivalent change to sha1_generic. Signed-off-by: Max Vozeler Signed-off-by: Herbert Xu --- crypto/md5.c | 40 ++++++++++++++++++++++++---------------- include/crypto/md5.h | 17 +++++++++++++++++ 2 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 include/crypto/md5.h diff --git a/crypto/md5.c b/crypto/md5.c index 83eb52961750..9fda213a592e 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -16,17 +16,13 @@ * */ #include +#include #include #include #include #include #include -#define MD5_DIGEST_SIZE 16 -#define MD5_HMAC_BLOCK_SIZE 64 -#define MD5_BLOCK_WORDS 16 -#define MD5_HASH_WORDS 4 - #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) @@ -35,12 +31,6 @@ #define MD5STEP(f, w, x, y, z, in, s) \ (w += f(x, y, z) + in, w = (w<>(32-s)) + x) -struct md5_ctx { - u32 hash[MD5_HASH_WORDS]; - u32 block[MD5_BLOCK_WORDS]; - u64 byte_count; -}; - static void md5_transform(u32 *hash, u32 const *in) { u32 a, b, c, d; @@ -141,7 +131,7 @@ static inline void cpu_to_le32_array(u32 *buf, unsigned int words) } } -static inline void md5_transform_helper(struct md5_ctx *ctx) +static inline void md5_transform_helper(struct md5_state *ctx) { le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); md5_transform(ctx->hash, ctx->block); @@ -149,7 +139,7 @@ static inline void md5_transform_helper(struct md5_ctx *ctx) static int md5_init(struct shash_desc *desc) { - struct md5_ctx *mctx = shash_desc_ctx(desc); + struct md5_state *mctx = shash_desc_ctx(desc); mctx->hash[0] = 0x67452301; mctx->hash[1] = 0xefcdab89; @@ -162,7 +152,7 @@ static int md5_init(struct shash_desc *desc) static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct md5_ctx *mctx = shash_desc_ctx(desc); + struct md5_state *mctx = shash_desc_ctx(desc); const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); mctx->byte_count += len; @@ -194,7 +184,7 @@ static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) static int md5_final(struct shash_desc *desc, u8 *out) { - struct md5_ctx *mctx = shash_desc_ctx(desc); + struct md5_state *mctx = shash_desc_ctx(desc); const unsigned int offset = mctx->byte_count & 0x3f; char *p = (char *)mctx->block + offset; int padding = 56 - (offset + 1); @@ -220,12 +210,30 @@ static int md5_final(struct shash_desc *desc, u8 *out) return 0; } +static int md5_export(struct shash_desc *desc, void *out) +{ + struct md5_state *ctx = shash_desc_ctx(desc); + + memcpy(out, ctx, sizeof(*ctx)); + return 0; +} + +static int md5_import(struct shash_desc *desc, const void *in) +{ + struct md5_state *ctx = shash_desc_ctx(desc); + + memcpy(ctx, in, sizeof(*ctx)); + return 0; +} + static struct shash_alg alg = { .digestsize = MD5_DIGEST_SIZE, .init = md5_init, .update = md5_update, .final = md5_final, - .descsize = sizeof(struct md5_ctx), + .export = md5_export, + .import = md5_import, + .descsize = sizeof(struct md5_state), .base = { .cra_name = "md5", .cra_flags = CRYPTO_ALG_TYPE_SHASH, diff --git a/include/crypto/md5.h b/include/crypto/md5.h new file mode 100644 index 000000000000..65f299b08b0d --- /dev/null +++ b/include/crypto/md5.h @@ -0,0 +1,17 @@ +#ifndef _CRYPTO_MD5_H +#define _CRYPTO_MD5_H + +#include + +#define MD5_DIGEST_SIZE 16 +#define MD5_HMAC_BLOCK_SIZE 64 +#define MD5_BLOCK_WORDS 16 +#define MD5_HASH_WORDS 4 + +struct md5_state { + u32 hash[MD5_HASH_WORDS]; + u32 block[MD5_BLOCK_WORDS]; + u64 byte_count; +}; + +#endif -- GitLab From 8380222ec9458d38a4e0cc3cb688ad7fff311df4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 25 Nov 2009 16:41:04 +0100 Subject: [PATCH 0823/3892] ASoC: Add a new imx-ssi sound driver The old driver has the number of SSI units in the system hardcoded, does not make use of the device model and works only on i.MX21/27. This driver replaces it. It works in DMA mode on i.MX21/27 and using an FIQ handler on other systems. It also supports AC97 mode of the SSI units. Signed-off-by: Sascha Hauer Acked-by: Javier Martin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/arm/plat-mxc/Makefile | 6 + arch/arm/plat-mxc/ssi-fiq-ksym.c | 20 + arch/arm/plat-mxc/ssi-fiq.S | 134 ++++++ sound/soc/imx/Kconfig | 20 +- sound/soc/imx/Makefile | 12 +- sound/soc/imx/imx-pcm-dma-mx2.c | 313 +++++++++++++ sound/soc/imx/imx-pcm-fiq.c | 277 +++++++++++ sound/soc/imx/imx-ssi.c | 762 +++++++++++++++++++++++++++++++ sound/soc/imx/imx-ssi.h | 238 ++++++++++ 9 files changed, 1762 insertions(+), 20 deletions(-) create mode 100644 arch/arm/plat-mxc/ssi-fiq-ksym.c create mode 100644 arch/arm/plat-mxc/ssi-fiq.S create mode 100644 sound/soc/imx/imx-pcm-dma-mx2.c create mode 100644 sound/soc/imx/imx-pcm-fiq.c create mode 100644 sound/soc/imx/imx-ssi.c create mode 100644 sound/soc/imx/imx-ssi.h diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index e3212c8ff421..b0b9fc3e5ab0 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -9,3 +9,9 @@ obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o obj-$(CONFIG_MXC_PWM) += pwm.o +obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o +obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o +ifdef CONFIG_SND_IMX_SOC +obj-y += ssi-fiq.o +obj-y += ssi-fiq-ksym.o +endif diff --git a/arch/arm/plat-mxc/ssi-fiq-ksym.c b/arch/arm/plat-mxc/ssi-fiq-ksym.c new file mode 100644 index 000000000000..b5fad454da78 --- /dev/null +++ b/arch/arm/plat-mxc/ssi-fiq-ksym.c @@ -0,0 +1,20 @@ +/* + * Exported ksyms for the SSI FIQ handler + * + * Copyright (C) 2009, Sascha Hauer + * + * 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 + +EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer); +EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer); +EXPORT_SYMBOL(imx_ssi_fiq_start); +EXPORT_SYMBOL(imx_ssi_fiq_end); +EXPORT_SYMBOL(imx_ssi_fiq_base); + diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S new file mode 100644 index 000000000000..4ddce565b353 --- /dev/null +++ b/arch/arm/plat-mxc/ssi-fiq.S @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009 Sascha Hauer + * + * 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 + +/* + * r8 = bit 0-15: tx offset, bit 16-31: tx buffer size + * r9 = bit 0-15: rx offset, bit 16-31: rx buffer size + */ + +#define SSI_STX0 0x00 +#define SSI_SRX0 0x08 +#define SSI_SISR 0x14 +#define SSI_SIER 0x18 +#define SSI_SACNT 0x38 + +#define SSI_SACNT_AC97EN (1 << 0) + +#define SSI_SIER_TFE0_EN (1 << 0) +#define SSI_SISR_TFE0 (1 << 0) +#define SSI_SISR_RFF0 (1 << 2) +#define SSI_SIER_RFF0_EN (1 << 2) + + .text + .global imx_ssi_fiq_start + .global imx_ssi_fiq_end + .global imx_ssi_fiq_base + .global imx_ssi_fiq_rx_buffer + .global imx_ssi_fiq_tx_buffer + +imx_ssi_fiq_start: + ldr r12, imx_ssi_fiq_base + + /* TX */ + ldr r11, imx_ssi_fiq_tx_buffer + + /* shall we send? */ + ldr r13, [r12, #SSI_SIER] + tst r13, #SSI_SIER_TFE0_EN + beq 1f + + /* TX FIFO empty? */ + ldr r13, [r12, #SSI_SISR] + tst r13, #SSI_SISR_TFE0 + beq 1f + + mov r10, #0x10000 + sub r10, #1 + and r10, r10, r8 /* r10: current buffer offset */ + + add r11, r11, r10 + + ldrh r13, [r11] + strh r13, [r12, #SSI_STX0] + + ldrh r13, [r11, #2] + strh r13, [r12, #SSI_STX0] + + ldrh r13, [r11, #4] + strh r13, [r12, #SSI_STX0] + + ldrh r13, [r11, #6] + strh r13, [r12, #SSI_STX0] + + add r10, #8 + lsr r13, r8, #16 /* r13: buffer size */ + cmp r10, r13 + lslgt r8, r13, #16 + addle r8, #8 +1: + /* RX */ + + /* shall we receive? */ + ldr r13, [r12, #SSI_SIER] + tst r13, #SSI_SIER_RFF0_EN + beq 1f + + /* RX FIFO full? */ + ldr r13, [r12, #SSI_SISR] + tst r13, #SSI_SISR_RFF0 + beq 1f + + ldr r11, imx_ssi_fiq_rx_buffer + + mov r10, #0x10000 + sub r10, #1 + and r10, r10, r9 /* r10: current buffer offset */ + + add r11, r11, r10 + + ldr r13, [r12, #SSI_SACNT] + tst r13, #SSI_SACNT_AC97EN + + ldr r13, [r12, #SSI_SRX0] + strh r13, [r11] + + ldr r13, [r12, #SSI_SRX0] + strh r13, [r11, #2] + + /* dummy read to skip slot 12 */ + ldrne r13, [r12, #SSI_SRX0] + + ldr r13, [r12, #SSI_SRX0] + strh r13, [r11, #4] + + ldr r13, [r12, #SSI_SRX0] + strh r13, [r11, #6] + + /* dummy read to skip slot 12 */ + ldrne r13, [r12, #SSI_SRX0] + + add r10, #8 + lsr r13, r9, #16 /* r13: buffer size */ + cmp r10, r13 + lslgt r9, r13, #16 + addle r9, #8 + +1: + @ return from FIQ + subs pc, lr, #4 +imx_ssi_fiq_base: + .word 0x0 +imx_ssi_fiq_rx_buffer: + .word 0x0 +imx_ssi_fiq_tx_buffer: + .word 0x0 +imx_ssi_fiq_end: + diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index a700562e8692..84a25e61bed8 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,21 +1,13 @@ -config SND_MX1_MX2_SOC - tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs" - depends on ARCH_MX2 || ARCH_MX1 +config SND_IMX_SOC + tristate "SoC Audio for Freecale i.MX CPUs" + depends on ARCH_MXC select SND_PCM + select FIQ + select SND_SOC_AC97_BUS help Say Y or M if you want to add support for codecs attached to - the MX1 or MX2 SSI interface. + the i.MX SSI interface. config SND_MXC_SOC_SSI tristate -config SND_SOC_MX27VIS_WM8974 - tristate "SoC Audio support for MX27 - WM8974 Visstrim_sm10 board" - depends on SND_MX1_MX2_SOC && MACH_MX27 && MACH_IMX27_VISSTRIM_M10 - select SND_MXC_SOC_SSI - select SND_SOC_WM8974 - help - Say Y if you want to add support for SoC audio on Visstrim SM10 - board with WM8974. - - diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index c2ffd2c8df5a..4bde34a3a878 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -1,10 +1,10 @@ # i.MX Platform Support -snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o -snd-soc-mxc-ssi-objs := mxc-ssi.o +snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o imx-pcm-dma-mx2.o -obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o -obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o +ifdef CONFIG_MACH_MX27 +snd-soc-imx-objs += imx-pcm-dma-mx2.o +endif + +obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o # i.MX Machine Support -snd-soc-mx27vis-wm8974-objs := mx27vis_wm8974.o -obj-$(CONFIG_SND_SOC_MX27VIS_WM8974) += snd-soc-mx27vis-wm8974.o diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c new file mode 100644 index 000000000000..19452e44afdc --- /dev/null +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -0,0 +1,313 @@ +/* + * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer + * + * Copyright 2009 Sascha Hauer + * + * This code is based on code copyrighted by Freescale, + * Liam Girdwood, Javier Martin and probably others. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "imx-ssi.h" + +struct imx_pcm_runtime_data { + int sg_count; + struct scatterlist *sg_list; + int period; + int periods; + unsigned long dma_addr; + int dma; + struct snd_pcm_substream *substream; + unsigned long offset; + unsigned long size; + unsigned long period_cnt; + void *buf; + int period_time; +}; + +/* Called by the DMA framework when a period has elapsed */ +static void imx_ssi_dma_progression(int channel, void *data, + struct scatterlist *sg) +{ + struct snd_pcm_substream *substream = data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + if (!sg) + return; + + runtime = iprtd->substream->runtime; + + iprtd->offset = sg->dma_address - runtime->dma_addr; + + snd_pcm_period_elapsed(iprtd->substream); +} + +static void imx_ssi_dma_callback(int channel, void *data) +{ + pr_err("%s shouldn't be called\n", __func__); +} + +static void snd_imx_dma_err_callback(int channel, void *data, int err) +{ + pr_err("DMA error callback called\n"); + + pr_err("DMA timeout on channel %d -%s%s%s%s\n", + channel, + err & IMX_DMA_ERR_BURST ? " burst" : "", + err & IMX_DMA_ERR_REQUEST ? " request" : "", + err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", + err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); +} + +static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + int ret; + + iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); + if (iprtd->dma < 0) { + pr_err("Failed to claim the audio DMA\n"); + return -ENODEV; + } + + ret = imx_dma_setup_handlers(iprtd->dma, + imx_ssi_dma_callback, + snd_imx_dma_err_callback, substream); + if (ret) + goto out; + + ret = imx_dma_setup_progression_handler(iprtd->dma, + imx_ssi_dma_progression); + if (ret) { + pr_err("Failed to setup the DMA handler\n"); + goto out; + } + + ret = imx_dma_config_channel(iprtd->dma, + IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, + dma_params->dma, 1); + if (ret < 0) { + pr_err("Cannot configure DMA channel: %d\n", ret); + goto out; + } + + imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); + + return 0; +out: + imx_dma_free(iprtd->dma); + return ret; +} + +static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + int i; + unsigned long dma_addr; + + imx_ssi_dma_alloc(substream); + + iprtd->size = params_buffer_bytes(params); + iprtd->periods = params_periods(params); + iprtd->period = params_period_bytes(params); + iprtd->offset = 0; + iprtd->period_time = HZ / (params_rate(params) / + params_period_size(params)); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + if (iprtd->sg_count != iprtd->periods) { + kfree(iprtd->sg_list); + + iprtd->sg_list = kcalloc(iprtd->periods + 1, + sizeof(struct scatterlist), GFP_KERNEL); + if (!iprtd->sg_list) + return -ENOMEM; + iprtd->sg_count = iprtd->periods + 1; + } + + sg_init_table(iprtd->sg_list, iprtd->sg_count); + dma_addr = runtime->dma_addr; + + for (i = 0; i < iprtd->periods; i++) { + iprtd->sg_list[i].page_link = 0; + iprtd->sg_list[i].offset = 0; + iprtd->sg_list[i].dma_address = dma_addr; + iprtd->sg_list[i].length = iprtd->period; + dma_addr += iprtd->period; + } + + /* close the loop */ + iprtd->sg_list[iprtd->sg_count - 1].offset = 0; + iprtd->sg_list[iprtd->sg_count - 1].length = 0; + iprtd->sg_list[iprtd->sg_count - 1].page_link = + ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; + return 0; +} + +static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + if (iprtd->dma >= 0) { + imx_dma_free(iprtd->dma); + iprtd->dma = -EINVAL; + } + + kfree(iprtd->sg_list); + iprtd->sg_list = NULL; + + return 0; +} + +static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + int err; + + iprtd->substream = substream; + iprtd->buf = (unsigned int *)substream->dma_buffer.area; + iprtd->period_cnt = 0; + + pr_debug("%s: buf: %p period: %d periods: %d\n", + __func__, iprtd->buf, iprtd->period, iprtd->periods); + + err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, + IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_MODE_WRITE : DMA_MODE_READ); + if (err) + return err; + + return 0; +} + +static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + imx_dma_enable(iprtd->dma); + + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + imx_dma_disable(iprtd->dma); + + break; + default: + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + return bytes_to_frames(substream->runtime, iprtd->offset); +} + +static struct snd_pcm_hardware snd_imx_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = 16 * 1024, + .periods_min = 2, + .periods_max = 255, + .fifo_size = 0, +}; + +static int snd_imx_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd; + int ret; + + iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); + runtime->private_data = iprtd; + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + return 0; +} + +static struct snd_pcm_ops imx_pcm_ops = { + .open = snd_imx_open, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_imx_pcm_hw_params, + .hw_free = snd_imx_pcm_hw_free, + .prepare = snd_imx_pcm_prepare, + .trigger = snd_imx_pcm_trigger, + .pointer = snd_imx_pcm_pointer, + .mmap = snd_imx_pcm_mmap, +}; + +static struct snd_soc_platform imx_soc_platform_dma = { + .name = "imx-audio", + .pcm_ops = &imx_pcm_ops, + .pcm_new = imx_pcm_new, + .pcm_free = imx_pcm_free, +}; + +struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, + struct imx_ssi *ssi) +{ + ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST; + ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST; + + return &imx_soc_platform_dma; +} + diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c new file mode 100644 index 000000000000..5532579ece4d --- /dev/null +++ b/sound/soc/imx/imx-pcm-fiq.c @@ -0,0 +1,277 @@ +/* + * imx-pcm-fiq.c -- ALSA Soc Audio Layer + * + * Copyright 2009 Sascha Hauer + * + * This code is based on code copyrighted by Freescale, + * Liam Girdwood, Javier Martin and probably others. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "imx-ssi.h" + +struct imx_pcm_runtime_data { + int period; + int periods; + unsigned long dma_addr; + int dma; + unsigned long offset; + unsigned long size; + unsigned long period_cnt; + void *buf; + struct timer_list timer; + int period_time; +}; + +static void imx_ssi_timer_callback(unsigned long data) +{ + struct snd_pcm_substream *substream = (void *)data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + struct pt_regs regs; + + get_fiq_regs(®s); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + iprtd->offset = regs.ARM_r8 & 0xffff; + else + iprtd->offset = regs.ARM_r9 & 0xffff; + + iprtd->timer.expires = jiffies + iprtd->period_time; + add_timer(&iprtd->timer); + snd_pcm_period_elapsed(substream); +} + +static struct fiq_handler fh = { + .name = DRV_NAME, +}; + +static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + iprtd->size = params_buffer_bytes(params); + iprtd->periods = params_periods(params); + iprtd->period = params_period_bytes(params); + iprtd->offset = 0; + iprtd->period_time = HZ / (params_rate(params) / params_period_size(params)); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; +} + +static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + struct pt_regs regs; + + get_fiq_regs(®s); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regs.ARM_r8 = (iprtd->period * iprtd->periods - 1) << 16; + else + regs.ARM_r9 = (iprtd->period * iprtd->periods - 1) << 16; + + set_fiq_regs(®s); + + return 0; +} + +static int fiq_enable; +static int imx_pcm_fiq; + +static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + iprtd->timer.expires = jiffies + iprtd->period_time; + add_timer(&iprtd->timer); + if (++fiq_enable == 1) + enable_fiq(imx_pcm_fiq); + + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + del_timer(&iprtd->timer); + if (--fiq_enable == 0) + disable_fiq(imx_pcm_fiq); + + + break; + default: + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + return bytes_to_frames(substream->runtime, iprtd->offset); +} + +static struct snd_pcm_hardware snd_imx_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = 16 * 1024, + .periods_min = 2, + .periods_max = 255, + .fifo_size = 0, +}; + +static int snd_imx_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd; + int ret; + + iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); + runtime->private_data = iprtd; + + init_timer(&iprtd->timer); + iprtd->timer.data = (unsigned long)substream; + iprtd->timer.function = imx_ssi_timer_callback; + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + return 0; +} + +static int snd_imx_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + del_timer_sync(&iprtd->timer); + kfree(iprtd); + + return 0; +} + +static struct snd_pcm_ops imx_pcm_ops = { + .open = snd_imx_open, + .close = snd_imx_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_imx_pcm_hw_params, + .prepare = snd_imx_pcm_prepare, + .trigger = snd_imx_pcm_trigger, + .pointer = snd_imx_pcm_pointer, + .mmap = snd_imx_pcm_mmap, +}; + +static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret; + + ret = imx_pcm_new(card, dai, pcm); + if (ret) + return ret; + + if (dai->playback.channels_min) { + struct snd_pcm_substream *substream = + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + imx_ssi_fiq_tx_buffer = (unsigned long)buf->area; + } + + if (dai->capture.channels_min) { + struct snd_pcm_substream *substream = + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + imx_ssi_fiq_rx_buffer = (unsigned long)buf->area; + } + + set_fiq_handler(&imx_ssi_fiq_start, + &imx_ssi_fiq_end - &imx_ssi_fiq_start); + + return 0; +} + +static struct snd_soc_platform imx_soc_platform_fiq = { + .pcm_ops = &imx_pcm_ops, + .pcm_new = imx_pcm_fiq_new, + .pcm_free = imx_pcm_free, +}; + +struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, + struct imx_ssi *ssi) +{ + int ret = 0; + + ret = claim_fiq(&fh); + if (ret) { + dev_err(&pdev->dev, "failed to claim fiq: %d", ret); + return ERR_PTR(ret); + } + + mxc_set_irq_fiq(ssi->irq, 1); + + imx_pcm_fiq = ssi->irq; + + imx_ssi_fiq_base = (unsigned long)ssi->base; + + ssi->dma_params_tx.burstsize = 4; + ssi->dma_params_rx.burstsize = 6; + + return &imx_soc_platform_fiq; +} + +void imx_ssi_fiq_exit(struct platform_device *pdev, + struct imx_ssi *ssi) +{ + mxc_set_irq_fiq(ssi->irq, 0); + release_fiq(&fh); +} + diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c new file mode 100644 index 000000000000..c57a11f66954 --- /dev/null +++ b/sound/soc/imx/imx-ssi.c @@ -0,0 +1,762 @@ +/* + * imx-ssi.c -- ALSA Soc Audio Layer + * + * Copyright 2009 Sascha Hauer + * + * This code is based on code copyrighted by Freescale, + * Liam Girdwood, Javier Martin and probably others. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * + * The i.MX SSI core has some nasty limitations in AC97 mode. While most + * sane processor vendors have a FIFO per AC97 slot, the i.MX has only + * one FIFO which combines all valid receive slots. We cannot even select + * which slots we want to receive. The WM9712 with which this driver + * was developped with always sends GPIO status data in slot 12 which + * we receive in our (PCM-) data stream. The only chance we have is to + * manually skip this data in the FIQ handler. With sampling rates different + * from 48000Hz not every frame has valid receive data, so the ratio + * between pcm data and GPIO status data changes. Our FIQ handler is not + * able to handle this, hence this driver only works with 48000Hz sampling + * rate. + * Reading and writing AC97 registers is another challange. The core + * provides us status bits when the read register is updated with *another* + * value. When we read the same register two times (and the register still + * contains the same value) these status bits are not set. We work + * around this by not polling these bits but only wait a fixed delay. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "imx-ssi.h" + +#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV) + +/* + * SSI Network Mode or TDM slots configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +{ + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + u32 sccr; + + sccr = readl(ssi->base + SSI_STCCR); + sccr &= ~SSI_STCCR_DC_MASK; + sccr |= SSI_STCCR_DC(slots - 1); + writel(sccr, ssi->base + SSI_STCCR); + + sccr = readl(ssi->base + SSI_SRCCR); + sccr &= ~SSI_STCCR_DC_MASK; + sccr |= SSI_STCCR_DC(slots - 1); + writel(sccr, ssi->base + SSI_SRCCR); + + writel(tx_mask, ssi->base + SSI_STMSK); + writel(rx_mask, ssi->base + SSI_SRMSK); + + return 0; +} + +/* + * SSI DAI format configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + * Note: We don't use the I2S modes but instead manually configure the + * SSI for I2S because the I2S mode is only a register preset. + */ +static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + u32 strcr = 0, scr; + + scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET); + + /* DAI mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* data on rising edge of bclk, frame low 1clk before data */ + strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; + scr |= SSI_SCR_NET; + break; + case SND_SOC_DAIFMT_LEFT_J: + /* data on rising edge of bclk, frame high with data */ + strcr |= SSI_STCR_TXBIT0; + break; + case SND_SOC_DAIFMT_DSP_B: + /* data on rising edge of bclk, frame high with data */ + strcr |= SSI_STCR_TFSL; + break; + case SND_SOC_DAIFMT_DSP_A: + /* data on rising edge of bclk, frame high 1clk before data */ + strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; + break; + } + + /* DAI clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + strcr |= SSI_STCR_TFSI; + strcr &= ~SSI_STCR_TSCKP; + break; + case SND_SOC_DAIFMT_IB_NF: + strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI); + break; + case SND_SOC_DAIFMT_NB_IF: + strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP; + break; + case SND_SOC_DAIFMT_NB_NF: + strcr &= ~SSI_STCR_TFSI; + strcr |= SSI_STCR_TSCKP; + break; + } + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + strcr |= SSI_STCR_TFDIR; + break; + case SND_SOC_DAIFMT_CBS_CFM: + strcr |= SSI_STCR_TXDIR; + break; + } + + strcr |= SSI_STCR_TFEN0; + + writel(strcr, ssi->base + SSI_STCR); + writel(strcr, ssi->base + SSI_SRCR); + writel(scr, ssi->base + SSI_SCR); + + return 0; +} + +/* + * SSI system clock configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + u32 scr; + + scr = readl(ssi->base + SSI_SCR); + + switch (clk_id) { + case IMX_SSP_SYS_CLK: + if (dir == SND_SOC_CLOCK_OUT) + scr |= SSI_SCR_SYS_CLK_EN; + else + scr &= ~SSI_SCR_SYS_CLK_EN; + break; + default: + return -EINVAL; + } + + writel(scr, ssi->base + SSI_SCR); + + return 0; +} + +/* + * SSI Clock dividers + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + u32 stccr, srccr; + + stccr = readl(ssi->base + SSI_STCCR); + srccr = readl(ssi->base + SSI_SRCCR); + + switch (div_id) { + case IMX_SSI_TX_DIV_2: + stccr &= ~SSI_STCCR_DIV2; + stccr |= div; + break; + case IMX_SSI_TX_DIV_PSR: + stccr &= ~SSI_STCCR_PSR; + stccr |= div; + break; + case IMX_SSI_TX_DIV_PM: + stccr &= ~0xff; + stccr |= SSI_STCCR_PM(div); + break; + case IMX_SSI_RX_DIV_2: + stccr &= ~SSI_STCCR_DIV2; + stccr |= div; + break; + case IMX_SSI_RX_DIV_PSR: + stccr &= ~SSI_STCCR_PSR; + stccr |= div; + break; + case IMX_SSI_RX_DIV_PM: + stccr &= ~0xff; + stccr |= SSI_STCCR_PM(div); + break; + default: + return -EINVAL; + } + + writel(stccr, ssi->base + SSI_STCCR); + writel(srccr, ssi->base + SSI_SRCCR); + + return 0; +} + +/* + * Should only be called when port is inactive (i.e. SSIEN = 0), + * although can be called multiple times by upper layers. + */ +static int imx_ssi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + u32 reg, sccr; + + /* Tx/Rx config */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + reg = SSI_STCCR; + cpu_dai->dma_data = &ssi->dma_params_tx; + } else { + reg = SSI_SRCCR; + cpu_dai->dma_data = &ssi->dma_params_rx; + } + + sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; + + /* DAI data (word) size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + sccr |= SSI_SRCCR_WL(16); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + sccr |= SSI_SRCCR_WL(20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + sccr |= SSI_SRCCR_WL(24); + break; + } + + writel(sccr, ssi->base + reg); + + return 0; +} + +static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + unsigned int sier_bits, sier; + unsigned int scr; + + scr = readl(ssi->base + SSI_SCR); + sier = readl(ssi->base + SSI_SIER); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (ssi->flags & IMX_SSI_DMA) + sier_bits = SSI_SIER_TDMAE; + else + sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN; + } else { + if (ssi->flags & IMX_SSI_DMA) + sier_bits = SSI_SIER_RDMAE; + else + sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + scr |= SSI_SCR_TE; + else + scr |= SSI_SCR_RE; + sier |= sier_bits; + + if (++ssi->enabled == 1) + scr |= SSI_SCR_SSIEN; + + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + scr &= ~SSI_SCR_TE; + else + scr &= ~SSI_SCR_RE; + sier &= ~sier_bits; + + if (--ssi->enabled == 0) + scr &= ~SSI_SCR_SSIEN; + + break; + default: + return -EINVAL; + } + + if (!(ssi->flags & IMX_SSI_USE_AC97)) + /* rx/tx are always enabled to access ac97 registers */ + writel(scr, ssi->base + SSI_SCR); + + writel(sier, ssi->base + SSI_SIER); + + return 0; +} + +static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { + .hw_params = imx_ssi_hw_params, + .set_fmt = imx_ssi_set_dai_fmt, + .set_clkdiv = imx_ssi_set_dai_clkdiv, + .set_sysclk = imx_ssi_set_dai_sysclk, + .set_tdm_slot = imx_ssi_set_dai_tdm_slot, + .trigger = imx_ssi_trigger, +}; + +static struct snd_soc_dai imx_ssi_dai = { + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &imx_ssi_pcm_dai_ops, +}; + +int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = dma_mmap_coherent(NULL, vma, runtime->dma_area, + runtime->dma_addr, runtime->dma_bytes); + + pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); + return ret; +} + +static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = IMX_SSI_DMABUF_SIZE; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + + return 0; +} + +static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); + +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &imx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + if (dai->playback.channels_min) { + ret = imx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = imx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + +out: + return ret; +} + +void imx_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +struct snd_soc_platform imx_soc_platform = { + .name = "imx-audio", +}; +EXPORT_SYMBOL_GPL(imx_soc_platform); + +static struct snd_soc_dai imx_ac97_dai = { + .name = "AC97", + .ac97_control = 1, + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &imx_ssi_pcm_dai_ops, +}; + +static void setup_channel_to_ac97(struct imx_ssi *imx_ssi) +{ + void __iomem *base = imx_ssi->base; + + writel(0x0, base + SSI_SCR); + writel(0x0, base + SSI_STCR); + writel(0x0, base + SSI_SRCR); + + writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR); + + writel(SSI_SFCSR_RFWM0(8) | + SSI_SFCSR_TFWM0(8) | + SSI_SFCSR_RFWM1(8) | + SSI_SFCSR_TFWM1(8), base + SSI_SFCSR); + + writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR); + writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR); + + writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR); + writel(SSI_SOR_WAIT(3), base + SSI_SOR); + + writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN | + SSI_SCR_TE | SSI_SCR_RE, + base + SSI_SCR); + + writel(SSI_SACNT_DEFAULT, base + SSI_SACNT); + writel(0xff, base + SSI_SACCDIS); + writel(0x300, base + SSI_SACCEN); +} + +static struct imx_ssi *ac97_ssi; + +static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + struct imx_ssi *imx_ssi = ac97_ssi; + void __iomem *base = imx_ssi->base; + unsigned int lreg; + unsigned int lval; + + if (reg > 0x7f) + return; + + pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); + + lreg = reg << 12; + writel(lreg, base + SSI_SACADD); + + lval = val << 4; + writel(lval , base + SSI_SACDAT); + + writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT); + udelay(100); +} + +static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + struct imx_ssi *imx_ssi = ac97_ssi; + void __iomem *base = imx_ssi->base; + + unsigned short val = -1; + unsigned int lreg; + + lreg = (reg & 0x7f) << 12 ; + writel(lreg, base + SSI_SACADD); + writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT); + + udelay(100); + + val = (readl(base + SSI_SACDAT) >> 4) & 0xffff; + + pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); + + return val; +} + +static void imx_ssi_ac97_reset(struct snd_ac97 *ac97) +{ + struct imx_ssi *imx_ssi = ac97_ssi; + + if (imx_ssi->ac97_reset) + imx_ssi->ac97_reset(ac97); +} + +static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97) +{ + struct imx_ssi *imx_ssi = ac97_ssi; + + if (imx_ssi->ac97_warm_reset) + imx_ssi->ac97_warm_reset(ac97); +} + +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = imx_ssi_ac97_read, + .write = imx_ssi_ac97_write, + .reset = imx_ssi_ac97_reset, + .warm_reset = imx_ssi_ac97_warm_reset +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +struct snd_soc_dai *imx_ssi_pcm_dai[2]; +EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); + +static int imx_ssi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct imx_ssi *ssi; + struct imx_ssi_platform_data *pdata = pdev->dev.platform_data; + struct snd_soc_platform *platform; + int ret = 0; + unsigned int val; + + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + if (!ssi) + return -ENOMEM; + + if (pdata) { + ssi->ac97_reset = pdata->ac97_reset; + ssi->ac97_warm_reset = pdata->ac97_warm_reset; + ssi->flags = pdata->flags; + } + + imx_ssi_pcm_dai[pdev->id] = &ssi->dai; + + ssi->irq = platform_get_irq(pdev, 0); + + ssi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(ssi->clk)) { + ret = PTR_ERR(ssi->clk); + dev_err(&pdev->dev, "Cannot get the clock: %d\n", + ret); + goto failed_clk; + } + clk_enable(ssi->clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto failed_get_resource; + } + + if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto failed_get_resource; + } + + ssi->base = ioremap(res->start, resource_size(res)); + if (!ssi->base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENODEV; + goto failed_ioremap; + } + + if (ssi->flags & IMX_SSI_USE_AC97) { + if (ac97_ssi) { + ret = -EBUSY; + goto failed_ac97; + } + ac97_ssi = ssi; + setup_channel_to_ac97(ssi); + memcpy(&ssi->dai, &imx_ac97_dai, sizeof(imx_ac97_dai)); + } else + memcpy(&ssi->dai, &imx_ssi_dai, sizeof(imx_ssi_dai)); + + ssi->dai.id = pdev->id; + ssi->dai.dev = &pdev->dev; + ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); + + writel(0x0, ssi->base + SSI_SIER); + + ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; + ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); + if (res) + ssi->dma_params_tx.dma = res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); + if (res) + ssi->dma_params_rx.dma = res->start; + + ssi->dai.id = pdev->id; + ssi->dai.dev = &pdev->dev; + ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); + + if ((cpu_is_mx27() || cpu_is_mx21()) && + !(ssi->flags & IMX_SSI_USE_AC97)) { + ssi->flags |= IMX_SSI_DMA; + platform = imx_ssi_dma_mx2_init(pdev, ssi); + } else + platform = imx_ssi_fiq_init(pdev, ssi); + + imx_soc_platform.pcm_ops = platform->pcm_ops; + imx_soc_platform.pcm_new = platform->pcm_new; + imx_soc_platform.pcm_free = platform->pcm_free; + + val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | + SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); + writel(val, ssi->base + SSI_SFCSR); + + ret = snd_soc_register_dai(&ssi->dai); + if (ret) { + dev_err(&pdev->dev, "register DAI failed\n"); + goto failed_register; + } + + platform_set_drvdata(pdev, ssi); + + return 0; + +failed_register: +failed_ac97: + iounmap(ssi->base); +failed_ioremap: + release_mem_region(res->start, resource_size(res)); +failed_get_resource: + clk_disable(ssi->clk); + clk_put(ssi->clk); +failed_clk: + kfree(ssi); + + return ret; +} + +static int __devexit imx_ssi_remove(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct imx_ssi *ssi = platform_get_drvdata(pdev); + + snd_soc_unregister_dai(&ssi->dai); + + if (ssi->flags & IMX_SSI_USE_AC97) + ac97_ssi = NULL; + + if (!(ssi->flags & IMX_SSI_DMA)) + imx_ssi_fiq_exit(pdev, ssi); + + iounmap(ssi->base); + release_mem_region(res->start, resource_size(res)); + clk_disable(ssi->clk); + clk_put(ssi->clk); + kfree(ssi); + + return 0; +} + +static struct platform_driver imx_ssi_driver = { + .probe = imx_ssi_probe, + .remove = __devexit_p(imx_ssi_remove), + + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init imx_ssi_init(void) +{ + int ret; + + ret = snd_soc_register_platform(&imx_soc_platform); + if (ret) { + pr_err("failed to register soc platform: %d\n", ret); + return ret; + } + + ret = platform_driver_register(&imx_ssi_driver); + if (ret) { + snd_soc_unregister_platform(&imx_soc_platform); + return ret; + } + + return 0; +} + +static void __exit imx_ssi_exit(void) +{ + platform_driver_unregister(&imx_ssi_driver); + snd_soc_unregister_platform(&imx_soc_platform); +} + +module_init(imx_ssi_init); +module_exit(imx_ssi_exit); + +/* Module information */ +MODULE_AUTHOR("Sascha Hauer, "); +MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h new file mode 100644 index 000000000000..cb2c81f1a6fc --- /dev/null +++ b/sound/soc/imx/imx-ssi.h @@ -0,0 +1,238 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _IMX_SSI_H +#define _IMX_SSI_H + +#define SSI_STX0 0x00 +#define SSI_STX1 0x04 +#define SSI_SRX0 0x08 +#define SSI_SRX1 0x0c + +#define SSI_SCR 0x10 +#define SSI_SCR_CLK_IST (1 << 9) +#define SSI_SCR_CLK_IST_SHIFT 9 +#define SSI_SCR_TCH_EN (1 << 8) +#define SSI_SCR_SYS_CLK_EN (1 << 7) +#define SSI_SCR_I2S_MODE_NORM (0 << 5) +#define SSI_SCR_I2S_MODE_MSTR (1 << 5) +#define SSI_SCR_I2S_MODE_SLAVE (2 << 5) +#define SSI_I2S_MODE_MASK (3 << 5) +#define SSI_SCR_SYN (1 << 4) +#define SSI_SCR_NET (1 << 3) +#define SSI_SCR_RE (1 << 2) +#define SSI_SCR_TE (1 << 1) +#define SSI_SCR_SSIEN (1 << 0) + +#define SSI_SISR 0x14 +#define SSI_SISR_MASK ((1 << 19) - 1) +#define SSI_SISR_CMDAU (1 << 18) +#define SSI_SISR_CMDDU (1 << 17) +#define SSI_SISR_RXT (1 << 16) +#define SSI_SISR_RDR1 (1 << 15) +#define SSI_SISR_RDR0 (1 << 14) +#define SSI_SISR_TDE1 (1 << 13) +#define SSI_SISR_TDE0 (1 << 12) +#define SSI_SISR_ROE1 (1 << 11) +#define SSI_SISR_ROE0 (1 << 10) +#define SSI_SISR_TUE1 (1 << 9) +#define SSI_SISR_TUE0 (1 << 8) +#define SSI_SISR_TFS (1 << 7) +#define SSI_SISR_RFS (1 << 6) +#define SSI_SISR_TLS (1 << 5) +#define SSI_SISR_RLS (1 << 4) +#define SSI_SISR_RFF1 (1 << 3) +#define SSI_SISR_RFF0 (1 << 2) +#define SSI_SISR_TFE1 (1 << 1) +#define SSI_SISR_TFE0 (1 << 0) + +#define SSI_SIER 0x18 +#define SSI_SIER_RDMAE (1 << 22) +#define SSI_SIER_RIE (1 << 21) +#define SSI_SIER_TDMAE (1 << 20) +#define SSI_SIER_TIE (1 << 19) +#define SSI_SIER_CMDAU_EN (1 << 18) +#define SSI_SIER_CMDDU_EN (1 << 17) +#define SSI_SIER_RXT_EN (1 << 16) +#define SSI_SIER_RDR1_EN (1 << 15) +#define SSI_SIER_RDR0_EN (1 << 14) +#define SSI_SIER_TDE1_EN (1 << 13) +#define SSI_SIER_TDE0_EN (1 << 12) +#define SSI_SIER_ROE1_EN (1 << 11) +#define SSI_SIER_ROE0_EN (1 << 10) +#define SSI_SIER_TUE1_EN (1 << 9) +#define SSI_SIER_TUE0_EN (1 << 8) +#define SSI_SIER_TFS_EN (1 << 7) +#define SSI_SIER_RFS_EN (1 << 6) +#define SSI_SIER_TLS_EN (1 << 5) +#define SSI_SIER_RLS_EN (1 << 4) +#define SSI_SIER_RFF1_EN (1 << 3) +#define SSI_SIER_RFF0_EN (1 << 2) +#define SSI_SIER_TFE1_EN (1 << 1) +#define SSI_SIER_TFE0_EN (1 << 0) + +#define SSI_STCR 0x1c +#define SSI_STCR_TXBIT0 (1 << 9) +#define SSI_STCR_TFEN1 (1 << 8) +#define SSI_STCR_TFEN0 (1 << 7) +#define SSI_FIFO_ENABLE_0_SHIFT 7 +#define SSI_STCR_TFDIR (1 << 6) +#define SSI_STCR_TXDIR (1 << 5) +#define SSI_STCR_TSHFD (1 << 4) +#define SSI_STCR_TSCKP (1 << 3) +#define SSI_STCR_TFSI (1 << 2) +#define SSI_STCR_TFSL (1 << 1) +#define SSI_STCR_TEFS (1 << 0) + +#define SSI_SRCR 0x20 +#define SSI_SRCR_RXBIT0 (1 << 9) +#define SSI_SRCR_RFEN1 (1 << 8) +#define SSI_SRCR_RFEN0 (1 << 7) +#define SSI_FIFO_ENABLE_0_SHIFT 7 +#define SSI_SRCR_RFDIR (1 << 6) +#define SSI_SRCR_RXDIR (1 << 5) +#define SSI_SRCR_RSHFD (1 << 4) +#define SSI_SRCR_RSCKP (1 << 3) +#define SSI_SRCR_RFSI (1 << 2) +#define SSI_SRCR_RFSL (1 << 1) +#define SSI_SRCR_REFS (1 << 0) + +#define SSI_SRCCR 0x28 +#define SSI_SRCCR_DIV2 (1 << 18) +#define SSI_SRCCR_PSR (1 << 17) +#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) +#define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8) +#define SSI_SRCCR_PM(x) (((x) & 0xff) << 0) +#define SSI_SRCCR_WL_MASK (0xf << 13) +#define SSI_SRCCR_DC_MASK (0x1f << 8) +#define SSI_SRCCR_PM_MASK (0xff << 0) + +#define SSI_STCCR 0x24 +#define SSI_STCCR_DIV2 (1 << 18) +#define SSI_STCCR_PSR (1 << 17) +#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) +#define SSI_STCCR_DC(x) (((x) & 0x1f) << 8) +#define SSI_STCCR_PM(x) (((x) & 0xff) << 0) +#define SSI_STCCR_WL_MASK (0xf << 13) +#define SSI_STCCR_DC_MASK (0x1f << 8) +#define SSI_STCCR_PM_MASK (0xff << 0) + +#define SSI_SFCSR 0x2c +#define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28) +#define SSI_RX_FIFO_1_COUNT_SHIFT 28 +#define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24) +#define SSI_TX_FIFO_1_COUNT_SHIFT 24 +#define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20) +#define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16) +#define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12) +#define SSI_RX_FIFO_0_COUNT_SHIFT 12 +#define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8) +#define SSI_TX_FIFO_0_COUNT_SHIFT 8 +#define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4) +#define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0) +#define SSI_SFCSR_RFWM0_MASK (0xf << 4) +#define SSI_SFCSR_TFWM0_MASK (0xf << 0) + +#define SSI_STR 0x30 +#define SSI_STR_TEST (1 << 15) +#define SSI_STR_RCK2TCK (1 << 14) +#define SSI_STR_RFS2TFS (1 << 13) +#define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8) +#define SSI_STR_TXD2RXD (1 << 7) +#define SSI_STR_TCK2RCK (1 << 6) +#define SSI_STR_TFS2RFS (1 << 5) +#define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0) + +#define SSI_SOR 0x34 +#define SSI_SOR_CLKOFF (1 << 6) +#define SSI_SOR_RX_CLR (1 << 5) +#define SSI_SOR_TX_CLR (1 << 4) +#define SSI_SOR_INIT (1 << 3) +#define SSI_SOR_WAIT(x) (((x) & 0x3) << 1) +#define SSI_SOR_WAIT_MASK (0x3 << 1) +#define SSI_SOR_SYNRST (1 << 0) + +#define SSI_SACNT 0x38 +#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) +#define SSI_SACNT_WR (1 << 4) +#define SSI_SACNT_RD (1 << 3) +#define SSI_SACNT_TIF (1 << 2) +#define SSI_SACNT_FV (1 << 1) +#define SSI_SACNT_AC97EN (1 << 0) + +#define SSI_SACADD 0x3c +#define SSI_SACDAT 0x40 +#define SSI_SATAG 0x44 +#define SSI_STMSK 0x48 +#define SSI_SRMSK 0x4c +#define SSI_SACCST 0x50 +#define SSI_SACCEN 0x54 +#define SSI_SACCDIS 0x58 + +/* SSI clock sources */ +#define IMX_SSP_SYS_CLK 0 + +/* SSI audio dividers */ +#define IMX_SSI_TX_DIV_2 0 +#define IMX_SSI_TX_DIV_PSR 1 +#define IMX_SSI_TX_DIV_PM 2 +#define IMX_SSI_RX_DIV_2 3 +#define IMX_SSI_RX_DIV_PSR 4 +#define IMX_SSI_RX_DIV_PM 5 + +extern struct snd_soc_dai *imx_ssi_pcm_dai[2]; +extern struct snd_soc_platform imx_soc_platform; + +#define DRV_NAME "imx-ssi" + +struct imx_pcm_dma_params { + int dma; + unsigned long dma_addr; + int burstsize; +}; + +struct imx_ssi { + struct snd_soc_dai dai; + struct platform_device *ac97_dev; + + struct snd_soc_device imx_ac97; + struct clk *clk; + void __iomem *base; + int irq; + int fiq_enable; + unsigned int offset; + + unsigned int flags; + + void (*ac97_reset) (struct snd_ac97 *ac97); + void (*ac97_warm_reset)(struct snd_ac97 *ac97); + + struct imx_pcm_dma_params dma_params_rx; + struct imx_pcm_dma_params dma_params_tx; + + int enabled; +}; + +struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, + struct imx_ssi *ssi); +void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi); +struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, + struct imx_ssi *ssi); + +int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm); +void imx_pcm_free(struct snd_pcm *pcm); + +/* + * Do not change this as the FIQ handler depends on this size + */ +#define IMX_SSI_DMABUF_SIZE (64 * 1024) + +#define DMA_RXFIFO_BURST 0x4 +#define DMA_TXFIFO_BURST 0x6 + +#endif /* _IMX_SSI_H */ -- GitLab From 157a777c8e809bd0c703e3f7617b3539df30feff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Jan 2010 17:50:29 +0000 Subject: [PATCH 0824/3892] ASoC: Fix i.MX audio build for i.MX3x Don't unconditionally include the i.MX2x DMA driver, the arch/arm functions it uses aren't available for i.MX3x. Signed-off-by: Mark Brown Acked-by: Javier Martin --- sound/soc/imx/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index 4bde34a3a878..d05cc95c5cc4 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -1,5 +1,5 @@ # i.MX Platform Support -snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o imx-pcm-dma-mx2.o +snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o ifdef CONFIG_MACH_MX27 snd-soc-imx-objs += imx-pcm-dma-mx2.o -- GitLab From 48dbc41988d07c7a9ba83afd31543d8ecb2beecc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Jan 2010 17:56:52 +0000 Subject: [PATCH 0825/3892] ASoC: Convert new i.MX SSI driver to use static DAI array While dynamically allocated DAIs are the way forward the core doesn't yet support anything except matching with a pointer to the actual DAI so convert to doing that so that machine drivers don't have to jump through hoops to register themselves. Signed-off-by: Mark Brown Acked-by: Javier Martin --- sound/soc/imx/imx-ssi.c | 40 ++++++++++++++++++++-------------------- sound/soc/imx/imx-ssi.h | 3 +-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index c57a11f66954..ccb7ec9ce997 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -60,7 +60,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; u32 sccr; sccr = readl(ssi->base + SSI_STCCR); @@ -87,7 +87,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, */ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; u32 strcr = 0, scr; scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET); @@ -160,7 +160,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; u32 scr; scr = readl(ssi->base + SSI_SCR); @@ -188,7 +188,7 @@ static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; u32 stccr, srccr; stccr = readl(ssi->base + SSI_STCCR); @@ -237,7 +237,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; u32 reg, sccr; /* Tx/Rx config */ @@ -274,7 +274,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai); + struct imx_ssi *ssi = cpu_dai->private_data; unsigned int sier_bits, sier; unsigned int scr; @@ -570,7 +570,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { }; EXPORT_SYMBOL_GPL(soc_ac97_ops); -struct snd_soc_dai *imx_ssi_pcm_dai[2]; +struct snd_soc_dai imx_ssi_pcm_dai[2]; EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); static int imx_ssi_probe(struct platform_device *pdev) @@ -581,6 +581,10 @@ static int imx_ssi_probe(struct platform_device *pdev) struct snd_soc_platform *platform; int ret = 0; unsigned int val; + struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id]; + + if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai)) + return -EINVAL; ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); if (!ssi) @@ -592,8 +596,6 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->flags = pdata->flags; } - imx_ssi_pcm_dai[pdev->id] = &ssi->dai; - ssi->irq = platform_get_irq(pdev, 0); ssi->clk = clk_get(&pdev->dev, NULL); @@ -631,13 +633,9 @@ static int imx_ssi_probe(struct platform_device *pdev) } ac97_ssi = ssi; setup_channel_to_ac97(ssi); - memcpy(&ssi->dai, &imx_ac97_dai, sizeof(imx_ac97_dai)); + memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai)); } else - memcpy(&ssi->dai, &imx_ssi_dai, sizeof(imx_ssi_dai)); - - ssi->dai.id = pdev->id; - ssi->dai.dev = &pdev->dev; - ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); + memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai)); writel(0x0, ssi->base + SSI_SIER); @@ -652,9 +650,10 @@ static int imx_ssi_probe(struct platform_device *pdev) if (res) ssi->dma_params_rx.dma = res->start; - ssi->dai.id = pdev->id; - ssi->dai.dev = &pdev->dev; - ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); + dai->id = pdev->id; + dai->dev = &pdev->dev; + dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id); + dai->private_data = ssi; if ((cpu_is_mx27() || cpu_is_mx21()) && !(ssi->flags & IMX_SSI_USE_AC97)) { @@ -671,7 +670,7 @@ static int imx_ssi_probe(struct platform_device *pdev) SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); writel(val, ssi->base + SSI_SFCSR); - ret = snd_soc_register_dai(&ssi->dai); + ret = snd_soc_register_dai(dai); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); goto failed_register; @@ -699,8 +698,9 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct imx_ssi *ssi = platform_get_drvdata(pdev); + struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id]; - snd_soc_unregister_dai(&ssi->dai); + snd_soc_unregister_dai(dai); if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index cb2c81f1a6fc..55f26ebcd8c2 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -183,7 +183,7 @@ #define IMX_SSI_RX_DIV_PSR 4 #define IMX_SSI_RX_DIV_PM 5 -extern struct snd_soc_dai *imx_ssi_pcm_dai[2]; +extern struct snd_soc_dai imx_ssi_pcm_dai[2]; extern struct snd_soc_platform imx_soc_platform; #define DRV_NAME "imx-ssi" @@ -195,7 +195,6 @@ struct imx_pcm_dma_params { }; struct imx_ssi { - struct snd_soc_dai dai; struct platform_device *ac97_dev; struct snd_soc_device imx_ac97; -- GitLab From d08a68bfca5a6464eb9167be0659bf0676f02555 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 11 Jan 2010 16:56:19 +0000 Subject: [PATCH 0826/3892] ASoC: i.MX SSI driver does not yet support master mode The clocks for the SSI block need handling before this can work. Signed-off-by: Mark Brown --- sound/soc/imx/imx-ssi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index ccb7ec9ce997..56f46a75d297 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -133,15 +133,11 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) /* DAI clock master masks */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; - break; - case SND_SOC_DAIFMT_CBM_CFS: - strcr |= SSI_STCR_TFDIR; - break; - case SND_SOC_DAIFMT_CBS_CFM: - strcr |= SSI_STCR_TXDIR; + case SND_SOC_DAIFMT_CBM_CFM: break; + default: + /* Master mode not implemented, needs handling of clocks. */ + return -EINVAL; } strcr |= SSI_STCR_TFEN0; -- GitLab From e919c24b6422a095bed3929074bd74ae1dbf251f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 17 Jan 2010 11:08:38 +0000 Subject: [PATCH 0827/3892] ASoC: Remove old i.MX driver code This has been superceeded by Sascha's new driver but was not removed in the patch series due to cutdowns for review. Signed-off-by: Mark Brown --- sound/soc/imx/mx1_mx2-pcm.c | 488 ------------------- sound/soc/imx/mx1_mx2-pcm.h | 26 - sound/soc/imx/mx27vis_wm8974.c | 317 ------------ sound/soc/imx/mxc-ssi.c | 860 --------------------------------- sound/soc/imx/mxc-ssi.h | 238 --------- 5 files changed, 1929 deletions(-) delete mode 100644 sound/soc/imx/mx1_mx2-pcm.c delete mode 100644 sound/soc/imx/mx1_mx2-pcm.h delete mode 100644 sound/soc/imx/mx27vis_wm8974.c delete mode 100644 sound/soc/imx/mxc-ssi.c delete mode 100644 sound/soc/imx/mxc-ssi.h diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c deleted file mode 100644 index bffffcd5ff34..000000000000 --- a/sound/soc/imx/mx1_mx2-pcm.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * mx1_mx2-pcm.c -- ALSA SoC interface for Freescale i.MX1x, i.MX2x CPUs - * - * Copyright 2009 Vista Silicon S.L. - * Author: Javier Martin - * javier.martin@vista-silicon.com - * - * Based on mxc-pcm.c by Liam Girdwood. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "mx1_mx2-pcm.h" - - -static const struct snd_pcm_hardware mx1_mx2_pcm_hardware = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .buffer_bytes_max = 32 * 1024, - .period_bytes_min = 64, - .period_bytes_max = 8 * 1024, - .periods_min = 2, - .periods_max = 255, - .fifo_size = 0, -}; - -struct mx1_mx2_runtime_data { - int dma_ch; - int active; - unsigned int period; - unsigned int periods; - int tx_spin; - spinlock_t dma_lock; - struct mx1_mx2_pcm_dma_params *dma_params; -}; - - -/** - * This function stops the current dma transfer for playback - * and clears the dma pointers. - * - * @param substream pointer to the structure of the current stream. - * - */ -static int audio_stop_dma(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - unsigned long flags; - - spin_lock_irqsave(&prtd->dma_lock, flags); - - pr_debug("%s\n", __func__); - - prtd->active = 0; - prtd->period = 0; - prtd->periods = 0; - - /* this stops the dma channel and clears the buffer ptrs */ - - imx_dma_disable(prtd->dma_ch); - - spin_unlock_irqrestore(&prtd->dma_lock, flags); - - return 0; -} - -/** - * This function is called whenever a new audio block needs to be - * transferred to the codec. The function receives the address and the size - * of the new block and start a new DMA transfer. - * - * @param substream pointer to the structure of the current stream. - * - */ -static int dma_new_period(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - unsigned int dma_size; - unsigned int offset; - int ret = 0; - dma_addr_t mem_addr; - unsigned int dev_addr; - - if (prtd->active) { - dma_size = frames_to_bytes(runtime, runtime->period_size); - offset = dma_size * prtd->period; - - pr_debug("%s: period (%d) out of (%d)\n", __func__, - prtd->period, - runtime->periods); - pr_debug("period_size %d frames\n offset %d bytes\n", - (unsigned int)runtime->period_size, - offset); - pr_debug("dma_size %d bytes\n", dma_size); - - snd_BUG_ON(dma_size > mx1_mx2_pcm_hardware.period_bytes_max); - - mem_addr = (dma_addr_t)(runtime->dma_addr + offset); - dev_addr = prtd->dma_params->per_address; - pr_debug("%s: mem_addr is %x\n dev_addr is %x\n", - __func__, mem_addr, dev_addr); - - ret = imx_dma_setup_single(prtd->dma_ch, mem_addr, - dma_size, dev_addr, - prtd->dma_params->transfer_type); - if (ret < 0) { - printk(KERN_ERR "Error %d configuring DMA\n", ret); - return ret; - } - imx_dma_enable(prtd->dma_ch); - - pr_debug("%s: transfer enabled\nmem_addr = %x\n", - __func__, (unsigned int) mem_addr); - pr_debug("dev_addr = %x\ndma_size = %d\n", - (unsigned int) dev_addr, dma_size); - - prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */ - prtd->period++; - prtd->period %= runtime->periods; - } - return ret; -} - - -/** - * This is a callback which will be called - * when a TX transfer finishes. The call occurs - * in interrupt context. - * - * @param dat pointer to the structure of the current stream. - * - */ -static void audio_dma_irq(int channel, void *data) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - struct mx1_mx2_runtime_data *prtd; - unsigned int dma_size; - unsigned int previous_period; - unsigned int offset; - - substream = data; - runtime = substream->runtime; - prtd = runtime->private_data; - previous_period = prtd->periods; - dma_size = frames_to_bytes(runtime, runtime->period_size); - offset = dma_size * previous_period; - - prtd->tx_spin = 0; - prtd->periods++; - prtd->periods %= runtime->periods; - - pr_debug("%s: irq per %d offset %x\n", __func__, prtd->periods, offset); - - /* - * If we are getting a callback for an active stream then we inform - * the PCM middle layer we've finished a period - */ - if (prtd->active) - snd_pcm_period_elapsed(substream); - - /* - * Trig next DMA transfer - */ - dma_new_period(substream); -} - -/** - * This function configures the hardware to allow audio - * playback operations. It is called by ALSA framework. - * - * @param substream pointer to the structure of the current stream. - * - * @return 0 on success, -1 otherwise. - */ -static int -snd_mx1_mx2_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - - prtd->period = 0; - prtd->periods = 0; - - return 0; -} - -static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int ret; - - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - printk(KERN_ERR "%s: Error %d failed to malloc pcm pages \n", - __func__, ret); - return ret; - } - - pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_addr 0x(%x)\n", - __func__, (unsigned int)runtime->dma_addr); - pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_area 0x(%x)\n", - __func__, (unsigned int)runtime->dma_area); - pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_bytes 0x(%x)\n", - __func__, (unsigned int)runtime->dma_bytes); - - return ret; -} - -static int mx1_mx2_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - - imx_dma_free(prtd->dma_ch); - - snd_pcm_lib_free_pages(substream); - - return 0; -} - -static int mx1_mx2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct mx1_mx2_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->tx_spin = 0; - /* requested stream startup */ - prtd->active = 1; - pr_debug("%s: starting dma_new_period\n", __func__); - ret = dma_new_period(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - /* requested stream shutdown */ - pr_debug("%s: stopping dma transfer\n", __func__); - ret = audio_stop_dma(substream); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static snd_pcm_uframes_t -mx1_mx2_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - unsigned int offset = 0; - - /* tx_spin value is used here to check if a transfer is active */ - if (prtd->tx_spin) { - offset = (runtime->period_size * (prtd->periods)) + - (runtime->period_size >> 1); - if (offset >= runtime->buffer_size) - offset = runtime->period_size >> 1; - } else { - offset = (runtime->period_size * (prtd->periods)); - if (offset >= runtime->buffer_size) - offset = 0; - } - pr_debug("%s: pointer offset %x\n", __func__, offset); - - return offset; -} - -static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mx1_mx2_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; - int ret; - - snd_soc_set_runtime_hwparams(substream, &mx1_mx2_pcm_hardware); - - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - - prtd = kzalloc(sizeof(struct mx1_mx2_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - - runtime->private_data = prtd; - - if (!dma_data) - return -ENODEV; - - prtd->dma_params = dma_data; - - pr_debug("%s: Requesting dma channel (%s)\n", __func__, - prtd->dma_params->name); - ret = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH); - if (ret < 0) { - printk(KERN_ERR "Error %d requesting dma channel\n", ret); - return ret; - } - prtd->dma_ch = ret; - imx_dma_config_burstlen(prtd->dma_ch, - prtd->dma_params->watermark_level); - - ret = imx_dma_config_channel(prtd->dma_ch, - prtd->dma_params->per_config, - prtd->dma_params->mem_config, - prtd->dma_params->event_id, 0); - - if (ret) { - pr_debug(KERN_ERR "Error %d configuring dma channel %d\n", - ret, prtd->dma_ch); - return ret; - } - - pr_debug("%s: Setting tx dma callback function\n", __func__); - ret = imx_dma_setup_handlers(prtd->dma_ch, - audio_dma_irq, NULL, - (void *)substream); - if (ret < 0) { - printk(KERN_ERR "Error %d setting dma callback function\n", ret); - return ret; - } - return 0; - - out: - return ret; -} - -static int mx1_mx2_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mx1_mx2_runtime_data *prtd = runtime->private_data; - - kfree(prtd); - - return 0; -} - -static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -static struct snd_pcm_ops mx1_mx2_pcm_ops = { - .open = mx1_mx2_pcm_open, - .close = mx1_mx2_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = mx1_mx2_pcm_hw_params, - .hw_free = mx1_mx2_pcm_hw_free, - .prepare = snd_mx1_mx2_prepare, - .trigger = mx1_mx2_pcm_trigger, - .pointer = mx1_mx2_pcm_pointer, - .mmap = mx1_mx2_pcm_mmap, -}; - -static u64 mx1_mx2_pcm_dmamask = 0xffffffff; - -static int mx1_mx2_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = mx1_mx2_pcm_hardware.buffer_bytes_max; - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - - /* Reserve uncached-buffered memory area for DMA */ - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - pr_debug("%s: preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - __func__, (void *) buf->area, (void *) buf->addr, size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -static int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &mx1_mx2_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - pr_debug("%s: preallocate playback buffer\n", __func__); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - pr_debug("%s: preallocate capture buffer\n", __func__); - if (ret) - goto out; - } - out: - return ret; -} - -struct snd_soc_platform mx1_mx2_soc_platform = { - .name = "mx1_mx2-audio", - .pcm_ops = &mx1_mx2_pcm_ops, - .pcm_new = mx1_mx2_pcm_new, - .pcm_free = mx1_mx2_pcm_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(mx1_mx2_soc_platform); - -static int __init mx1_mx2_soc_platform_init(void) -{ - return snd_soc_register_platform(&mx1_mx2_soc_platform); -} -module_init(mx1_mx2_soc_platform_init); - -static void __exit mx1_mx2_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&mx1_mx2_soc_platform); -} -module_exit(mx1_mx2_soc_platform_exit); - -MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); -MODULE_DESCRIPTION("Freescale i.MX2x, i.MX1x PCM DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h deleted file mode 100644 index 2e528106570b..000000000000 --- a/sound/soc/imx/mx1_mx2-pcm.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * mx1_mx2-pcm.h :- ASoC platform header for Freescale i.MX1x, i.MX2x - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _MX1_MX2_PCM_H -#define _MX1_MX2_PCM_H - -/* DMA information for mx1_mx2 platforms */ -struct mx1_mx2_pcm_dma_params { - char *name; /* stream identifier */ - unsigned int transfer_type; /* READ or WRITE DMA transfer */ - dma_addr_t per_address; /* physical address of SSI fifo */ - int event_id; /* fixed DMA number for SSI fifo */ - int watermark_level; /* SSI fifo watermark level */ - int per_config; /* DMA Config flags for peripheral */ - int mem_config; /* DMA Config flags for RAM */ - }; - -/* platform data */ -extern struct snd_soc_platform mx1_mx2_soc_platform; - -#endif diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c deleted file mode 100644 index 0267d2d91685..000000000000 --- a/sound/soc/imx/mx27vis_wm8974.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * mx27vis_wm8974.c -- SoC audio for mx27vis - * - * Copyright 2009 Vista Silicon S.L. - * Author: Javier Martin - * javier.martin@vista-silicon.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "../codecs/wm8974.h" -#include "mx1_mx2-pcm.h" -#include "mxc-ssi.h" -#include -#include - -#define IGNORED_ARG 0 - - -static struct snd_soc_card mx27vis; - -/** - * This function connects SSI1 (HPCR1) as slave to - * SSI1 external signals (PPCR1) - * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from - * port 4 - */ -void audmux_connect_1_4(void) -{ - pr_debug("AUDMUX: normal operation mode\n"); - /* Reset HPCR1 and PPCR1 */ - - DAM_HPCR1 = 0x00000000; - DAM_PPCR1 = 0x00000000; - - /* set to synchronous */ - DAM_HPCR1 |= AUDMUX_HPCR_SYN; - DAM_PPCR1 |= AUDMUX_PPCR_SYN; - - - /* set Rx sources 1 <--> 4 */ - DAM_HPCR1 |= AUDMUX_HPCR_RXDSEL(3); /* port 4 */ - DAM_PPCR1 |= AUDMUX_PPCR_RXDSEL(0); /* port 1 */ - - /* set Tx frame and Clock direction and source 4 --> 1 output */ - DAM_HPCR1 |= AUDMUX_HPCR_TFSDIR | AUDMUX_HPCR_TCLKDIR; - DAM_HPCR1 |= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */ - - return; -} - -static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int pll_out = 0, bclk = 0, fmt = 0, mclk = 0; - int ret = 0; - - /* - * The WM8974 is better at generating accurate audio clocks than the - * MX27 SSI controller, so we will use it as master when we can. - */ - switch (params_rate(params)) { - case 8000: - fmt = SND_SOC_DAIFMT_CBM_CFM; - mclk = WM8974_MCLKDIV_12; - pll_out = 24576000; - break; - case 16000: - fmt = SND_SOC_DAIFMT_CBM_CFM; - pll_out = 12288000; - break; - case 48000: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_4; - pll_out = 12288000; - break; - case 96000: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_2; - pll_out = 12288000; - break; - case 11025: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_16; - pll_out = 11289600; - break; - case 22050: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_8; - pll_out = 11289600; - break; - case 44100: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_4; - mclk = WM8974_MCLKDIV_2; - pll_out = 11289600; - break; - case 88200: - fmt = SND_SOC_DAIFMT_CBM_CFM; - bclk = WM8974_BCLKDIV_2; - pll_out = 11289600; - break; - } - - /* set codec DAI configuration */ - ret = codec_dai->ops->set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_SYNC | fmt); - if (ret < 0) { - printk(KERN_ERR "Error from codec DAI configuration\n"); - return ret; - } - - /* set cpu DAI configuration */ - ret = cpu_dai->ops->set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_SYNC | fmt); - if (ret < 0) { - printk(KERN_ERR "Error from cpu DAI configuration\n"); - return ret; - } - - /* Put DC field of STCCR to 1 (not zero) */ - ret = cpu_dai->ops->set_tdm_slot(cpu_dai, 0, 2); - - /* set the SSI system clock as input */ - ret = cpu_dai->ops->set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "Error when setting system SSI clk\n"); - return ret; - } - - /* set codec BCLK division for sample rate */ - ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_BCLKDIV, bclk); - if (ret < 0) { - printk(KERN_ERR "Error when setting BCLK division\n"); - return ret; - } - - - /* codec PLL input is 25 MHz */ - ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, - 25000000, pll_out); - if (ret < 0) { - printk(KERN_ERR "Error when setting PLL input\n"); - return ret; - } - - /*set codec MCLK division for sample rate */ - ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_MCLKDIV, mclk); - if (ret < 0) { - printk(KERN_ERR "Error when setting MCLK division\n"); - return ret; - } - - return 0; -} - -static int mx27vis_hifi_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - - /* disable the PLL */ - return codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, 0, 0); -} - -/* - * mx27vis WM8974 HiFi DAI opserations. - */ -static struct snd_soc_ops mx27vis_hifi_ops = { - .hw_params = mx27vis_hifi_hw_params, - .hw_free = mx27vis_hifi_hw_free, -}; - - -static int mx27vis_suspend(struct platform_device *pdev, pm_message_t state) -{ - return 0; -} - -static int mx27vis_resume(struct platform_device *pdev) -{ - return 0; -} - -static int mx27vis_probe(struct platform_device *pdev) -{ - int ret = 0; - - ret = get_ssi_clk(0, &pdev->dev); - - if (ret < 0) { - printk(KERN_ERR "%s: cant get ssi clock\n", __func__); - return ret; - } - - - return 0; -} - -static int mx27vis_remove(struct platform_device *pdev) -{ - put_ssi_clk(0); - return 0; -} - -static struct snd_soc_dai_link mx27vis_dai[] = { -{ /* Hifi Playback*/ - .name = "WM8974", - .stream_name = "WM8974 HiFi", - .cpu_dai = &imx_ssi_pcm_dai[0], - .codec_dai = &wm8974_dai, - .ops = &mx27vis_hifi_ops, -}, -}; - -static struct snd_soc_card mx27vis = { - .name = "mx27vis", - .platform = &mx1_mx2_soc_platform, - .probe = mx27vis_probe, - .remove = mx27vis_remove, - .suspend_pre = mx27vis_suspend, - .resume_post = mx27vis_resume, - .dai_link = mx27vis_dai, - .num_links = ARRAY_SIZE(mx27vis_dai), -}; - -static struct snd_soc_device mx27vis_snd_devdata = { - .card = &mx27vis, - .codec_dev = &soc_codec_dev_wm8974, -}; - -static struct platform_device *mx27vis_snd_device; - -/* Temporal definition of board specific behaviour */ -void gpio_ssi_active(int ssi_num) -{ - int ret = 0; - - unsigned int ssi1_pins[] = { - PC20_PF_SSI1_FS, - PC21_PF_SSI1_RXD, - PC22_PF_SSI1_TXD, - PC23_PF_SSI1_CLK, - }; - unsigned int ssi2_pins[] = { - PC24_PF_SSI2_FS, - PC25_PF_SSI2_RXD, - PC26_PF_SSI2_TXD, - PC27_PF_SSI2_CLK, - }; - if (ssi_num == 0) - ret = mxc_gpio_setup_multiple_pins(ssi1_pins, - ARRAY_SIZE(ssi1_pins), "USB OTG"); - else - ret = mxc_gpio_setup_multiple_pins(ssi2_pins, - ARRAY_SIZE(ssi2_pins), "USB OTG"); - if (ret) - printk(KERN_ERR "Error requesting ssi %x pins\n", ssi_num); -} - - -static int __init mx27vis_init(void) -{ - int ret; - - mx27vis_snd_device = platform_device_alloc("soc-audio", -1); - if (!mx27vis_snd_device) - return -ENOMEM; - - platform_set_drvdata(mx27vis_snd_device, &mx27vis_snd_devdata); - mx27vis_snd_devdata.dev = &mx27vis_snd_device->dev; - ret = platform_device_add(mx27vis_snd_device); - - if (ret) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - platform_device_put(mx27vis_snd_device); - } - - /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */ - gpio_ssi_active(0); - audmux_connect_1_4(); - - return ret; -} - -static void __exit mx27vis_exit(void) -{ - /* We should call some "ssi_gpio_inactive()" properly */ -} - -module_init(mx27vis_init); -module_exit(mx27vis_exit); - - -MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); -MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c deleted file mode 100644 index ccdefe60e752..000000000000 --- a/sound/soc/imx/mxc-ssi.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * mxc-ssi.c -- SSI driver for Freescale IMX - * - * Copyright 2006 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com - * - * Based on mxc-alsa-mc13783 (C) 2006 Freescale. - * - * 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. - * - * TODO: - * Need to rework SSI register defs when new defs go into mainline. - * Add support for TDM and FIFO 1. - * Add support for i.mx3x DMA interface. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mxc-ssi.h" -#include "mx1_mx2-pcm.h" - -#define SSI1_PORT 0 -#define SSI2_PORT 1 - -static int ssi_active[2] = {0, 0}; - -/* DMA information for mx1_mx2 platforms */ -static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = { - .name = "SSI1 PCM Stereo out 0", - .transfer_type = DMA_MODE_WRITE, - .per_address = SSI1_BASE_ADDR + STX0, - .event_id = DMA_REQ_SSI1_TX0, - .watermark_level = TXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = { - .name = "SSI1 PCM Stereo out 1", - .transfer_type = DMA_MODE_WRITE, - .per_address = SSI1_BASE_ADDR + STX1, - .event_id = DMA_REQ_SSI1_TX1, - .watermark_level = TXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = { - .name = "SSI1 PCM Stereo in 0", - .transfer_type = DMA_MODE_READ, - .per_address = SSI1_BASE_ADDR + SRX0, - .event_id = DMA_REQ_SSI1_RX0, - .watermark_level = RXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = { - .name = "SSI1 PCM Stereo in 1", - .transfer_type = DMA_MODE_READ, - .per_address = SSI1_BASE_ADDR + SRX1, - .event_id = DMA_REQ_SSI1_RX1, - .watermark_level = RXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = { - .name = "SSI2 PCM Stereo out 0", - .transfer_type = DMA_MODE_WRITE, - .per_address = SSI2_BASE_ADDR + STX0, - .event_id = DMA_REQ_SSI2_TX0, - .watermark_level = TXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = { - .name = "SSI2 PCM Stereo out 1", - .transfer_type = DMA_MODE_WRITE, - .per_address = SSI2_BASE_ADDR + STX1, - .event_id = DMA_REQ_SSI2_TX1, - .watermark_level = TXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = { - .name = "SSI2 PCM Stereo in 0", - .transfer_type = DMA_MODE_READ, - .per_address = SSI2_BASE_ADDR + SRX0, - .event_id = DMA_REQ_SSI2_RX0, - .watermark_level = RXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = { - .name = "SSI2 PCM Stereo in 1", - .transfer_type = DMA_MODE_READ, - .per_address = SSI2_BASE_ADDR + SRX1, - .event_id = DMA_REQ_SSI2_RX1, - .watermark_level = RXFIFO_WATERMARK, - .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -}; - -static struct clk *ssi_clk0, *ssi_clk1; - -int get_ssi_clk(int ssi, struct device *dev) -{ - switch (ssi) { - case 0: - ssi_clk0 = clk_get(dev, "ssi1"); - if (IS_ERR(ssi_clk0)) - return PTR_ERR(ssi_clk0); - return 0; - case 1: - ssi_clk1 = clk_get(dev, "ssi2"); - if (IS_ERR(ssi_clk1)) - return PTR_ERR(ssi_clk1); - return 0; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(get_ssi_clk); - -void put_ssi_clk(int ssi) -{ - switch (ssi) { - case 0: - clk_put(ssi_clk0); - ssi_clk0 = NULL; - break; - case 1: - clk_put(ssi_clk1); - ssi_clk1 = NULL; - break; - } -} -EXPORT_SYMBOL(put_ssi_clk); - -/* - * SSI system clock configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - u32 scr; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - scr = SSI1_SCR; - pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr); - } else { - scr = SSI2_SCR; - pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr); - } - - if (scr & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - - switch (clk_id) { - case IMX_SSP_SYS_CLK: - if (dir == SND_SOC_CLOCK_OUT) { - scr |= SSI_SCR_SYS_CLK_EN; - pr_debug("%s: clk of is output\n", __func__); - } else { - scr &= ~SSI_SCR_SYS_CLK_EN; - pr_debug("%s: clk of is input\n", __func__); - } - break; - default: - return -EINVAL; - } - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - pr_debug("%s: writeback of SSI1_SCR\n", __func__); - SSI1_SCR = scr; - } else { - pr_debug("%s: writeback of SSI2_SCR\n", __func__); - SSI2_SCR = scr; - } - - return 0; -} - -/* - * SSI Clock dividers - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - u32 stccr, srccr; - - pr_debug("%s\n", __func__); - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - if (SSI1_SCR & SSI_SCR_SSIEN) - return 0; - srccr = SSI1_STCCR; - stccr = SSI1_STCCR; - } else { - if (SSI2_SCR & SSI_SCR_SSIEN) - return 0; - srccr = SSI2_STCCR; - stccr = SSI2_STCCR; - } - - switch (div_id) { - case IMX_SSI_TX_DIV_2: - stccr &= ~SSI_STCCR_DIV2; - stccr |= div; - break; - case IMX_SSI_TX_DIV_PSR: - stccr &= ~SSI_STCCR_PSR; - stccr |= div; - break; - case IMX_SSI_TX_DIV_PM: - stccr &= ~0xff; - stccr |= SSI_STCCR_PM(div); - break; - case IMX_SSI_RX_DIV_2: - stccr &= ~SSI_STCCR_DIV2; - stccr |= div; - break; - case IMX_SSI_RX_DIV_PSR: - stccr &= ~SSI_STCCR_PSR; - stccr |= div; - break; - case IMX_SSI_RX_DIV_PM: - stccr &= ~0xff; - stccr |= SSI_STCCR_PM(div); - break; - default: - return -EINVAL; - } - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - SSI1_STCCR = stccr; - SSI1_SRCCR = srccr; - } else { - SSI2_STCCR = stccr; - SSI2_SRCCR = srccr; - } - return 0; -} - -/* - * SSI Network Mode or TDM slots configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int mask, int slots) -{ - u32 stmsk, srmsk, stccr; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - if (SSI1_SCR & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - stccr = SSI1_STCCR; - } else { - if (SSI2_SCR & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - stccr = SSI2_STCCR; - } - - stmsk = srmsk = mask; - stccr &= ~SSI_STCCR_DC_MASK; - stccr |= SSI_STCCR_DC(slots - 1); - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - SSI1_STMSK = stmsk; - SSI1_SRMSK = srmsk; - SSI1_SRCCR = SSI1_STCCR = stccr; - } else { - SSI2_STMSK = stmsk; - SSI2_SRMSK = srmsk; - SSI2_SRCCR = SSI2_STCCR = stccr; - } - - return 0; -} - -/* - * SSI DAI format configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - * Note: We don't use the I2S modes but instead manually configure the - * SSI for I2S. - */ -static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - u32 stcr = 0, srcr = 0, scr; - - /* - * This is done to avoid this function to modify - * previous set values in stcr - */ - stcr = SSI1_STCR; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) - scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); - else - scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); - - if (scr & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - - /* DAI mode */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* data on rising edge of bclk, frame low 1clk before data */ - stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; - srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0; - break; - case SND_SOC_DAIFMT_LEFT_J: - /* data on rising edge of bclk, frame high with data */ - stcr |= SSI_STCR_TXBIT0; - srcr |= SSI_SRCR_RXBIT0; - break; - case SND_SOC_DAIFMT_DSP_B: - /* data on rising edge of bclk, frame high with data */ - stcr |= SSI_STCR_TFSL; - srcr |= SSI_SRCR_RFSL; - break; - case SND_SOC_DAIFMT_DSP_A: - /* data on rising edge of bclk, frame high 1clk before data */ - stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; - srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS; - break; - } - - /* DAI clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - stcr |= SSI_STCR_TFSI; - stcr &= ~SSI_STCR_TSCKP; - srcr |= SSI_SRCR_RFSI; - srcr &= ~SSI_SRCR_RSCKP; - break; - case SND_SOC_DAIFMT_IB_NF: - stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI); - srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI); - break; - case SND_SOC_DAIFMT_NB_IF: - stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP; - srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP; - break; - case SND_SOC_DAIFMT_NB_NF: - stcr &= ~SSI_STCR_TFSI; - stcr |= SSI_STCR_TSCKP; - srcr &= ~SSI_SRCR_RFSI; - srcr |= SSI_SRCR_RSCKP; - break; - } - - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; - srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR; - break; - case SND_SOC_DAIFMT_CBM_CFS: - stcr |= SSI_STCR_TFDIR; - srcr |= SSI_SRCR_RFDIR; - break; - case SND_SOC_DAIFMT_CBS_CFM: - stcr |= SSI_STCR_TXDIR; - srcr |= SSI_SRCR_RXDIR; - break; - } - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - SSI1_STCR = stcr; - SSI1_SRCR = srcr; - SSI1_SCR = scr; - } else { - SSI2_STCR = stcr; - SSI2_SRCR = srcr; - SSI2_SCR = scr; - } - - return 0; -} - -static int imx_ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* set up TX DMA params */ - switch (cpu_dai->id) { - case IMX_DAI_SSI0: - cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0; - break; - case IMX_DAI_SSI1: - cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1; - break; - case IMX_DAI_SSI2: - cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0; - break; - case IMX_DAI_SSI3: - cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1; - } - pr_debug("%s: (playback)\n", __func__); - } else { - /* set up RX DMA params */ - switch (cpu_dai->id) { - case IMX_DAI_SSI0: - cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0; - break; - case IMX_DAI_SSI1: - cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1; - break; - case IMX_DAI_SSI2: - cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0; - break; - case IMX_DAI_SSI3: - cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1; - } - pr_debug("%s: (capture)\n", __func__); - } - - /* - * we cant really change any SSI values after SSI is enabled - * need to fix in software for max flexibility - lrg - */ - if (cpu_dai->active) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - - /* reset the SSI port - Sect 45.4.4 */ - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - - if (!ssi_clk0) - return -EINVAL; - - if (ssi_active[SSI1_PORT]++) { - pr_debug("%s: exit before reset\n", __func__); - return 0; - } - - /* SSI1 Reset */ - SSI1_SCR = 0; - - SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | - SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | - SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | - SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); - } else { - - if (!ssi_clk1) - return -EINVAL; - - if (ssi_active[SSI2_PORT]++) { - pr_debug("%s: exit before reset\n", __func__); - return 0; - } - - /* SSI2 Reset */ - SSI2_SCR = 0; - - SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | - SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | - SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | - SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); - } - - return 0; -} - -int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - u32 stccr, stcr, sier; - - pr_debug("%s\n", __func__); - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK; - stcr = SSI1_STCR; - sier = SSI1_SIER; - } else { - stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK; - stcr = SSI2_STCR; - sier = SSI2_SIER; - } - - /* DAI data (word) size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - stccr |= SSI_STCCR_WL(16); - break; - case SNDRV_PCM_FORMAT_S20_3LE: - stccr |= SSI_STCCR_WL(20); - break; - case SNDRV_PCM_FORMAT_S24_LE: - stccr |= SSI_STCCR_WL(24); - break; - } - - /* enable interrupts */ - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) - stcr |= SSI_STCR_TFEN0; - else - stcr |= SSI_STCR_TFEN1; - sier |= SSI_SIER_TDMAE; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - SSI1_STCR = stcr; - SSI1_STCCR = stccr; - SSI1_SIER = sier; - } else { - SSI2_STCR = stcr; - SSI2_STCCR = stccr; - SSI2_SIER = sier; - } - - return 0; -} - -int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - u32 srccr, srcr, sier; - - pr_debug("%s\n", __func__); - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK; - srcr = SSI1_SRCR; - sier = SSI1_SIER; - } else { - srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK; - srcr = SSI2_SRCR; - sier = SSI2_SIER; - } - - /* DAI data (word) size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - srccr |= SSI_SRCCR_WL(16); - break; - case SNDRV_PCM_FORMAT_S20_3LE: - srccr |= SSI_SRCCR_WL(20); - break; - case SNDRV_PCM_FORMAT_S24_LE: - srccr |= SSI_SRCCR_WL(24); - break; - } - - /* enable interrupts */ - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) - srcr |= SSI_SRCR_RFEN0; - else - srcr |= SSI_SRCR_RFEN1; - sier |= SSI_SIER_RDMAE; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - SSI1_SRCR = srcr; - SSI1_SRCCR = srccr; - SSI1_SIER = sier; - } else { - SSI2_SRCR = srcr; - SSI2_SRCCR = srccr; - SSI2_SIER = sier; - } - - return 0; -} - -/* - * Should only be called when port is inactive (i.e. SSIEN = 0), - * although can be called multiple times by upper layers. - */ -int imx_ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - int ret; - - /* cant change any parameters when SSI is running */ - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - if (SSI1_SCR & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - } else { - if (SSI2_SCR & SSI_SCR_SSIEN) { - printk(KERN_WARNING "Warning ssi already enabled\n"); - return 0; - } - } - - /* - * Configure both tx and rx params with the same settings. This is - * really a harware restriction because SSI must be disabled until - * we can change those values. If there is an active audio stream in - * one direction, enabling the other direction with different - * settings would mean disturbing the running one. - */ - ret = imx_ssi_hw_tx_params(substream, params); - if (ret < 0) - return ret; - return imx_ssi_hw_rx_params(substream, params); -} - -int imx_ssi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - pr_debug("%s\n", __func__); - - /* Enable clks here to follow SSI recommended init sequence */ - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { - ret = clk_enable(ssi_clk0); - if (ret < 0) - printk(KERN_ERR "Unable to enable ssi_clk0\n"); - } else { - ret = clk_enable(ssi_clk1); - if (ret < 0) - printk(KERN_ERR "Unable to enable ssi_clk1\n"); - } - - return 0; -} - -static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - u32 scr; - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) - scr = SSI1_SCR; - else - scr = SSI2_SCR; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - scr |= SSI_SCR_TE | SSI_SCR_SSIEN; - else - scr |= SSI_SCR_RE | SSI_SCR_SSIEN; - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - scr &= ~SSI_SCR_TE; - else - scr &= ~SSI_SCR_RE; - break; - default: - return -EINVAL; - } - - if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) - SSI1_SCR = scr; - else - SSI2_SCR = scr; - - return 0; -} - -static void imx_ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - /* shutdown SSI if neither Tx or Rx is active */ - if (!cpu_dai->active) { - - if (cpu_dai->id == IMX_DAI_SSI0 || - cpu_dai->id == IMX_DAI_SSI2) { - - if (--ssi_active[SSI1_PORT] > 1) - return; - - SSI1_SCR = 0; - clk_disable(ssi_clk0); - } else { - if (--ssi_active[SSI2_PORT]) - return; - SSI2_SCR = 0; - clk_disable(ssi_clk1); - } - } -} - -#ifdef CONFIG_PM -static int imx_ssi_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) -{ - return 0; -} - -static int imx_ssi_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - return 0; -} - -#else -#define imx_ssi_suspend NULL -#define imx_ssi_resume NULL -#endif - -#define IMX_SSI_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000) - -#define IMX_SSI_BITS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { - .startup = imx_ssi_startup, - .shutdown = imx_ssi_shutdown, - .trigger = imx_ssi_trigger, - .prepare = imx_ssi_prepare, - .hw_params = imx_ssi_hw_params, - .set_sysclk = imx_ssi_set_dai_sysclk, - .set_clkdiv = imx_ssi_set_dai_clkdiv, - .set_fmt = imx_ssi_set_dai_fmt, - .set_tdm_slot = imx_ssi_set_dai_tdm_slot, -}; - -struct snd_soc_dai imx_ssi_pcm_dai[] = { -{ - .name = "imx-i2s-1-0", - .id = IMX_DAI_SSI0, - .suspend = imx_ssi_suspend, - .resume = imx_ssi_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .ops = &imx_ssi_pcm_dai_ops, -}, -{ - .name = "imx-i2s-2-0", - .id = IMX_DAI_SSI1, - .playback = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .ops = &imx_ssi_pcm_dai_ops, -}, -{ - .name = "imx-i2s-1-1", - .id = IMX_DAI_SSI2, - .suspend = imx_ssi_suspend, - .resume = imx_ssi_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .ops = &imx_ssi_pcm_dai_ops, -}, -{ - .name = "imx-i2s-2-1", - .id = IMX_DAI_SSI3, - .playback = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .formats = IMX_SSI_BITS, - .rates = IMX_SSI_RATES,}, - .ops = &imx_ssi_pcm_dai_ops, -}, -}; -EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); - -static int __init imx_ssi_init(void) -{ - return snd_soc_register_dais(imx_ssi_pcm_dai, - ARRAY_SIZE(imx_ssi_pcm_dai)); -} - -static void __exit imx_ssi_exit(void) -{ - snd_soc_unregister_dais(imx_ssi_pcm_dai, - ARRAY_SIZE(imx_ssi_pcm_dai)); -} - -module_init(imx_ssi_init); -module_exit(imx_ssi_exit); -MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com"); -MODULE_DESCRIPTION("i.MX ASoC I2S driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/imx/mxc-ssi.h b/sound/soc/imx/mxc-ssi.h deleted file mode 100644 index 12bbdc9c7ecd..000000000000 --- a/sound/soc/imx/mxc-ssi.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _IMX_SSI_H -#define _IMX_SSI_H - -#include - -/* SSI regs definition - MOVE to /arch/arm/plat-mxc/include/mach/ when stable */ -#define SSI1_IO_BASE_ADDR IO_ADDRESS(SSI1_BASE_ADDR) -#define SSI2_IO_BASE_ADDR IO_ADDRESS(SSI2_BASE_ADDR) - -#define STX0 0x00 -#define STX1 0x04 -#define SRX0 0x08 -#define SRX1 0x0c -#define SCR 0x10 -#define SISR 0x14 -#define SIER 0x18 -#define STCR 0x1c -#define SRCR 0x20 -#define STCCR 0x24 -#define SRCCR 0x28 -#define SFCSR 0x2c -#define STR 0x30 -#define SOR 0x34 -#define SACNT 0x38 -#define SACADD 0x3c -#define SACDAT 0x40 -#define SATAG 0x44 -#define STMSK 0x48 -#define SRMSK 0x4c - -#define SSI1_STX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX0))) -#define SSI1_STX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX1))) -#define SSI1_SRX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX0))) -#define SSI1_SRX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX1))) -#define SSI1_SCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SCR))) -#define SSI1_SISR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SISR))) -#define SSI1_SIER (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SIER))) -#define SSI1_STCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCR))) -#define SSI1_SRCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCR))) -#define SSI1_STCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCCR))) -#define SSI1_SRCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCCR))) -#define SSI1_SFCSR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SFCSR))) -#define SSI1_STR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STR))) -#define SSI1_SOR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SOR))) -#define SSI1_SACNT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACNT))) -#define SSI1_SACADD (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACADD))) -#define SSI1_SACDAT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACDAT))) -#define SSI1_SATAG (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SATAG))) -#define SSI1_STMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STMSK))) -#define SSI1_SRMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRMSK))) - - -#define SSI2_STX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX0))) -#define SSI2_STX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX1))) -#define SSI2_SRX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX0))) -#define SSI2_SRX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX1))) -#define SSI2_SCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SCR))) -#define SSI2_SISR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SISR))) -#define SSI2_SIER (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SIER))) -#define SSI2_STCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCR))) -#define SSI2_SRCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCR))) -#define SSI2_STCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCCR))) -#define SSI2_SRCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCCR))) -#define SSI2_SFCSR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SFCSR))) -#define SSI2_STR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STR))) -#define SSI2_SOR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SOR))) -#define SSI2_SACNT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACNT))) -#define SSI2_SACADD (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACADD))) -#define SSI2_SACDAT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACDAT))) -#define SSI2_SATAG (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SATAG))) -#define SSI2_STMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STMSK))) -#define SSI2_SRMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRMSK))) - -#define SSI_SCR_CLK_IST (1 << 9) -#define SSI_SCR_TCH_EN (1 << 8) -#define SSI_SCR_SYS_CLK_EN (1 << 7) -#define SSI_SCR_I2S_MODE_NORM (0 << 5) -#define SSI_SCR_I2S_MODE_MSTR (1 << 5) -#define SSI_SCR_I2S_MODE_SLAVE (2 << 5) -#define SSI_SCR_SYN (1 << 4) -#define SSI_SCR_NET (1 << 3) -#define SSI_SCR_RE (1 << 2) -#define SSI_SCR_TE (1 << 1) -#define SSI_SCR_SSIEN (1 << 0) - -#define SSI_SISR_CMDAU (1 << 18) -#define SSI_SISR_CMDDU (1 << 17) -#define SSI_SISR_RXT (1 << 16) -#define SSI_SISR_RDR1 (1 << 15) -#define SSI_SISR_RDR0 (1 << 14) -#define SSI_SISR_TDE1 (1 << 13) -#define SSI_SISR_TDE0 (1 << 12) -#define SSI_SISR_ROE1 (1 << 11) -#define SSI_SISR_ROE0 (1 << 10) -#define SSI_SISR_TUE1 (1 << 9) -#define SSI_SISR_TUE0 (1 << 8) -#define SSI_SISR_TFS (1 << 7) -#define SSI_SISR_RFS (1 << 6) -#define SSI_SISR_TLS (1 << 5) -#define SSI_SISR_RLS (1 << 4) -#define SSI_SISR_RFF1 (1 << 3) -#define SSI_SISR_RFF0 (1 << 2) -#define SSI_SISR_TFE1 (1 << 1) -#define SSI_SISR_TFE0 (1 << 0) - -#define SSI_SIER_RDMAE (1 << 22) -#define SSI_SIER_RIE (1 << 21) -#define SSI_SIER_TDMAE (1 << 20) -#define SSI_SIER_TIE (1 << 19) -#define SSI_SIER_CMDAU_EN (1 << 18) -#define SSI_SIER_CMDDU_EN (1 << 17) -#define SSI_SIER_RXT_EN (1 << 16) -#define SSI_SIER_RDR1_EN (1 << 15) -#define SSI_SIER_RDR0_EN (1 << 14) -#define SSI_SIER_TDE1_EN (1 << 13) -#define SSI_SIER_TDE0_EN (1 << 12) -#define SSI_SIER_ROE1_EN (1 << 11) -#define SSI_SIER_ROE0_EN (1 << 10) -#define SSI_SIER_TUE1_EN (1 << 9) -#define SSI_SIER_TUE0_EN (1 << 8) -#define SSI_SIER_TFS_EN (1 << 7) -#define SSI_SIER_RFS_EN (1 << 6) -#define SSI_SIER_TLS_EN (1 << 5) -#define SSI_SIER_RLS_EN (1 << 4) -#define SSI_SIER_RFF1_EN (1 << 3) -#define SSI_SIER_RFF0_EN (1 << 2) -#define SSI_SIER_TFE1_EN (1 << 1) -#define SSI_SIER_TFE0_EN (1 << 0) - -#define SSI_STCR_TXBIT0 (1 << 9) -#define SSI_STCR_TFEN1 (1 << 8) -#define SSI_STCR_TFEN0 (1 << 7) -#define SSI_STCR_TFDIR (1 << 6) -#define SSI_STCR_TXDIR (1 << 5) -#define SSI_STCR_TSHFD (1 << 4) -#define SSI_STCR_TSCKP (1 << 3) -#define SSI_STCR_TFSI (1 << 2) -#define SSI_STCR_TFSL (1 << 1) -#define SSI_STCR_TEFS (1 << 0) - -#define SSI_SRCR_RXBIT0 (1 << 9) -#define SSI_SRCR_RFEN1 (1 << 8) -#define SSI_SRCR_RFEN0 (1 << 7) -#define SSI_SRCR_RFDIR (1 << 6) -#define SSI_SRCR_RXDIR (1 << 5) -#define SSI_SRCR_RSHFD (1 << 4) -#define SSI_SRCR_RSCKP (1 << 3) -#define SSI_SRCR_RFSI (1 << 2) -#define SSI_SRCR_RFSL (1 << 1) -#define SSI_SRCR_REFS (1 << 0) - -#define SSI_STCCR_DIV2 (1 << 18) -#define SSI_STCCR_PSR (1 << 15) -#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) -#define SSI_STCCR_DC(x) (((x) & 0x1f) << 8) -#define SSI_STCCR_PM(x) (((x) & 0xff) << 0) -#define SSI_STCCR_WL_MASK (0xf << 13) -#define SSI_STCCR_DC_MASK (0x1f << 8) -#define SSI_STCCR_PM_MASK (0xff << 0) - -#define SSI_SRCCR_DIV2 (1 << 18) -#define SSI_SRCCR_PSR (1 << 15) -#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) -#define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8) -#define SSI_SRCCR_PM(x) (((x) & 0xff) << 0) -#define SSI_SRCCR_WL_MASK (0xf << 13) -#define SSI_SRCCR_DC_MASK (0x1f << 8) -#define SSI_SRCCR_PM_MASK (0xff << 0) - - -#define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28) -#define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24) -#define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20) -#define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16) -#define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12) -#define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8) -#define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4) -#define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0) - -#define SSI_STR_TEST (1 << 15) -#define SSI_STR_RCK2TCK (1 << 14) -#define SSI_STR_RFS2TFS (1 << 13) -#define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8) -#define SSI_STR_TXD2RXD (1 << 7) -#define SSI_STR_TCK2RCK (1 << 6) -#define SSI_STR_TFS2RFS (1 << 5) -#define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0) - -#define SSI_SOR_CLKOFF (1 << 6) -#define SSI_SOR_RX_CLR (1 << 5) -#define SSI_SOR_TX_CLR (1 << 4) -#define SSI_SOR_INIT (1 << 3) -#define SSI_SOR_WAIT(x) (((x) & 0x3) << 1) -#define SSI_SOR_SYNRST (1 << 0) - -#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) -#define SSI_SACNT_WR (x << 4) -#define SSI_SACNT_RD (x << 3) -#define SSI_SACNT_TIF (x << 2) -#define SSI_SACNT_FV (x << 1) -#define SSI_SACNT_AC97EN (x << 0) - -/* Watermarks for FIFO's */ -#define TXFIFO_WATERMARK 0x4 -#define RXFIFO_WATERMARK 0x4 - -/* i.MX DAI SSP ID's */ -#define IMX_DAI_SSI0 0 /* SSI1 FIFO 0 */ -#define IMX_DAI_SSI1 1 /* SSI1 FIFO 1 */ -#define IMX_DAI_SSI2 2 /* SSI2 FIFO 0 */ -#define IMX_DAI_SSI3 3 /* SSI2 FIFO 1 */ - -/* SSI clock sources */ -#define IMX_SSP_SYS_CLK 0 - -/* SSI audio dividers */ -#define IMX_SSI_TX_DIV_2 0 -#define IMX_SSI_TX_DIV_PSR 1 -#define IMX_SSI_TX_DIV_PM 2 -#define IMX_SSI_RX_DIV_2 3 -#define IMX_SSI_RX_DIV_PSR 4 -#define IMX_SSI_RX_DIV_PM 5 - - -/* SSI Div 2 */ -#define IMX_SSI_DIV_2_OFF (~SSI_STCCR_DIV2) -#define IMX_SSI_DIV_2_ON SSI_STCCR_DIV2 - -extern struct snd_soc_dai imx_ssi_pcm_dai[4]; -extern int get_ssi_clk(int ssi, struct device *dev); -extern void put_ssi_clk(int ssi); -#endif -- GitLab From 42cce92f4ddfa41e2dfe26fdcad4887943c032f2 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 17 Jan 2010 10:36:08 +0100 Subject: [PATCH 0828/3892] perf: Make __perf_event_sched_out static __perf_event_sched_out doesn't need to be globally available, make it static. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- kernel/perf_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index eae6ff693604..c4e90b8cd60d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1049,8 +1049,8 @@ static int perf_event_refresh(struct perf_event *event, int refresh) return 0; } -void __perf_event_sched_out(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx) +static void __perf_event_sched_out(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx) { struct perf_event *event; -- GitLab From 5b0311e1f2464547fc6f17a82d7ea2538c8c7a70 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 17 Jan 2010 11:59:13 +0100 Subject: [PATCH 0829/3892] perf: Allow pinned and flexible groups to be scheduled separately Tune the scheduling helpers so that we can choose to schedule either pinned and/or flexible groups from a context. And while at it, refactor a bit the naming of these helpers to make these more consistent and flexible. There is no (intended) change in scheduling behaviour in this patch. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- kernel/perf_event.c | 137 ++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index c4e90b8cd60d..bfc4ee015c87 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1049,8 +1049,15 @@ static int perf_event_refresh(struct perf_event *event, int refresh) return 0; } -static void __perf_event_sched_out(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx) +enum event_type_t { + EVENT_FLEXIBLE = 0x1, + EVENT_PINNED = 0x2, + EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, +}; + +static void ctx_sched_out(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + enum event_type_t event_type) { struct perf_event *event; @@ -1061,13 +1068,18 @@ static void __perf_event_sched_out(struct perf_event_context *ctx, update_context_time(ctx); perf_disable(); - if (ctx->nr_active) { + if (!ctx->nr_active) + goto out_enable; + + if (event_type & EVENT_PINNED) list_for_each_entry(event, &ctx->pinned_groups, group_entry) group_sched_out(event, cpuctx, ctx); + if (event_type & EVENT_FLEXIBLE) list_for_each_entry(event, &ctx->flexible_groups, group_entry) group_sched_out(event, cpuctx, ctx); - } + + out_enable: perf_enable(); out: raw_spin_unlock(&ctx->lock); @@ -1229,15 +1241,13 @@ void perf_event_task_sched_out(struct task_struct *task, rcu_read_unlock(); if (do_switch) { - __perf_event_sched_out(ctx, cpuctx); + ctx_sched_out(ctx, cpuctx, EVENT_ALL); cpuctx->task_ctx = NULL; } } -/* - * Called with IRQs disabled - */ -static void __perf_event_task_sched_out(struct perf_event_context *ctx) +static void task_ctx_sched_out(struct perf_event_context *ctx, + enum event_type_t event_type) { struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); @@ -1247,39 +1257,34 @@ static void __perf_event_task_sched_out(struct perf_event_context *ctx) if (WARN_ON_ONCE(ctx != cpuctx->task_ctx)) return; - __perf_event_sched_out(ctx, cpuctx); + ctx_sched_out(ctx, cpuctx, event_type); cpuctx->task_ctx = NULL; } /* * Called with IRQs disabled */ -static void perf_event_cpu_sched_out(struct perf_cpu_context *cpuctx) +static void __perf_event_task_sched_out(struct perf_event_context *ctx) { - __perf_event_sched_out(&cpuctx->ctx, cpuctx); + task_ctx_sched_out(ctx, EVENT_ALL); +} + +/* + * Called with IRQs disabled + */ +static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, + enum event_type_t event_type) +{ + ctx_sched_out(&cpuctx->ctx, cpuctx, event_type); } static void -__perf_event_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx) +ctx_pinned_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + int cpu) { - int cpu = smp_processor_id(); struct perf_event *event; - int can_add_hw = 1; - - raw_spin_lock(&ctx->lock); - ctx->is_active = 1; - if (likely(!ctx->nr_events)) - goto out; - - ctx->timestamp = perf_clock(); - - perf_disable(); - /* - * First go through the list and put on any pinned groups - * in order to give them the best chance of going on. - */ list_for_each_entry(event, &ctx->pinned_groups, group_entry) { if (event->state <= PERF_EVENT_STATE_OFF) continue; @@ -1298,6 +1303,15 @@ __perf_event_sched_in(struct perf_event_context *ctx, event->state = PERF_EVENT_STATE_ERROR; } } +} + +static void +ctx_flexible_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + int cpu) +{ + struct perf_event *event; + int can_add_hw = 1; list_for_each_entry(event, &ctx->flexible_groups, group_entry) { /* Ignore events in OFF or ERROR state */ @@ -1314,11 +1328,53 @@ __perf_event_sched_in(struct perf_event_context *ctx, if (group_sched_in(event, cpuctx, ctx, cpu)) can_add_hw = 0; } +} + +static void +ctx_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + enum event_type_t event_type) +{ + int cpu = smp_processor_id(); + + raw_spin_lock(&ctx->lock); + ctx->is_active = 1; + if (likely(!ctx->nr_events)) + goto out; + + ctx->timestamp = perf_clock(); + + perf_disable(); + + /* + * First go through the list and put on any pinned groups + * in order to give them the best chance of going on. + */ + if (event_type & EVENT_PINNED) + ctx_pinned_sched_in(ctx, cpuctx, cpu); + + /* Then walk through the lower prio flexible groups */ + if (event_type & EVENT_FLEXIBLE) + ctx_flexible_sched_in(ctx, cpuctx, cpu); + perf_enable(); out: raw_spin_unlock(&ctx->lock); } +static void task_ctx_sched_in(struct task_struct *task, + enum event_type_t event_type) +{ + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_event_context *ctx = task->perf_event_ctxp; + + if (likely(!ctx)) + return; + if (cpuctx->task_ctx == ctx) + return; + ctx_sched_in(ctx, cpuctx, event_type); + cpuctx->task_ctx = ctx; +} /* * Called from scheduler to add the events of the current task * with interrupts disabled. @@ -1332,22 +1388,15 @@ __perf_event_sched_in(struct perf_event_context *ctx, */ void perf_event_task_sched_in(struct task_struct *task) { - struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); - struct perf_event_context *ctx = task->perf_event_ctxp; - - if (likely(!ctx)) - return; - if (cpuctx->task_ctx == ctx) - return; - __perf_event_sched_in(ctx, cpuctx); - cpuctx->task_ctx = ctx; + task_ctx_sched_in(task, EVENT_ALL); } -static void perf_event_cpu_sched_in(struct perf_cpu_context *cpuctx) +static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, + enum event_type_t event_type) { struct perf_event_context *ctx = &cpuctx->ctx; - __perf_event_sched_in(ctx, cpuctx); + ctx_sched_in(ctx, cpuctx, event_type); } #define MAX_INTERRUPTS (~0ULL) @@ -1476,17 +1525,17 @@ void perf_event_task_tick(struct task_struct *curr) if (ctx) perf_ctx_adjust_freq(ctx); - perf_event_cpu_sched_out(cpuctx); + cpu_ctx_sched_out(cpuctx, EVENT_ALL); if (ctx) - __perf_event_task_sched_out(ctx); + task_ctx_sched_out(ctx, EVENT_ALL); rotate_ctx(&cpuctx->ctx); if (ctx) rotate_ctx(ctx); - perf_event_cpu_sched_in(cpuctx); + cpu_ctx_sched_in(cpuctx, EVENT_ALL); if (ctx) - perf_event_task_sched_in(curr); + task_ctx_sched_in(curr, EVENT_ALL); } static int event_enable_on_exec(struct perf_event *event, -- GitLab From 7defb0f879bbcfe29e3c6f29d685d4f29b7a0700 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 17 Jan 2010 12:15:31 +0100 Subject: [PATCH 0830/3892] perf: Don't schedule out/in pinned events on task tick We don't need to schedule in/out pinned events on task tick, now that pinned and flexible groups can be scheduled separately. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- kernel/perf_event.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index bfc4ee015c87..a90ae694cbc1 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1525,17 +1525,17 @@ void perf_event_task_tick(struct task_struct *curr) if (ctx) perf_ctx_adjust_freq(ctx); - cpu_ctx_sched_out(cpuctx, EVENT_ALL); + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); if (ctx) - task_ctx_sched_out(ctx, EVENT_ALL); + task_ctx_sched_out(ctx, EVENT_FLEXIBLE); rotate_ctx(&cpuctx->ctx); if (ctx) rotate_ctx(ctx); - cpu_ctx_sched_in(cpuctx, EVENT_ALL); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE); if (ctx) - task_ctx_sched_in(curr, EVENT_ALL); + task_ctx_sched_in(curr, EVENT_FLEXIBLE); } static int event_enable_on_exec(struct perf_event *event, -- GitLab From 329c0e012b99fa2325a0be205c052e4aba690f16 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 17 Jan 2010 12:56:05 +0100 Subject: [PATCH 0831/3892] perf: Better order flexible and pinned scheduling When a task gets scheduled in. We don't touch the cpu bound events so the priority order becomes: cpu pinned, cpu flexible, task pinned, task flexible. So schedule out cpu flexibles when a new task context gets in and correctly order the groups to schedule in: task pinned, cpu flexible, task flexible. Cpu pinned groups don't need to be touched at this time. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo --- kernel/perf_event.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index a90ae694cbc1..edc46b92b508 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1362,6 +1362,14 @@ ctx_sched_in(struct perf_event_context *ctx, raw_spin_unlock(&ctx->lock); } +static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, + enum event_type_t event_type) +{ + struct perf_event_context *ctx = &cpuctx->ctx; + + ctx_sched_in(ctx, cpuctx, event_type); +} + static void task_ctx_sched_in(struct task_struct *task, enum event_type_t event_type) { @@ -1388,15 +1396,27 @@ static void task_ctx_sched_in(struct task_struct *task, */ void perf_event_task_sched_in(struct task_struct *task) { - task_ctx_sched_in(task, EVENT_ALL); -} + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_event_context *ctx = task->perf_event_ctxp; -static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, - enum event_type_t event_type) -{ - struct perf_event_context *ctx = &cpuctx->ctx; + if (likely(!ctx)) + return; - ctx_sched_in(ctx, cpuctx, event_type); + if (cpuctx->task_ctx == ctx) + return; + + /* + * We want to keep the following priority order: + * cpu pinned (that don't need to move), task pinned, + * cpu flexible, task flexible. + */ + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); + + ctx_sched_in(ctx, cpuctx, EVENT_PINNED); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE); + ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE); + + cpuctx->task_ctx = ctx; } #define MAX_INTERRUPTS (~0ULL) -- GitLab From b05f5c13d5bc2fa9945c9534f8881396555290a9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 17 Jan 2010 16:45:06 +0000 Subject: [PATCH 0832/3892] ASoC: Mark new i.MX drivers as BROKEN until arch/arm merged Currently they don't build due to cross tree dependencies, they will be reenabled once the arch/arm side has merged. Signed-off-by: Mark Brown --- sound/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 84a25e61bed8..5f006f0d03dc 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,6 +1,6 @@ config SND_IMX_SOC tristate "SoC Audio for Freecale i.MX CPUs" - depends on ARCH_MXC + depends on ARCH_MXC && BROKEN select SND_PCM select FIQ select SND_SOC_AC97_BUS -- GitLab From 933a838aa1aae8388438bb002fbdaf6fca519a5c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 29 Dec 2009 18:21:39 +0100 Subject: [PATCH 0833/3892] pcmcia: make use of pcmcia_dev_resume() return value In runtime_resume(), do not throw away the return value of pcmcia_dev_resume(), for we can use it (at least) in pcmcia_store_pm_state(). This also fixes the pointless assignment previosly seen there, as noted by Dan Carpenter. CC: Dan Carpenter Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 1a4a3c49cc15..defa44c27b97 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -970,13 +970,14 @@ static int runtime_suspend(struct device *dev) return rc; } -static void runtime_resume(struct device *dev) +static int runtime_resume(struct device *dev) { int rc; down(&dev->sem); rc = pcmcia_dev_resume(dev); up(&dev->sem); + return rc; } /************************ per-device sysfs output ***************************/ @@ -1027,7 +1028,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) ret = runtime_suspend(dev); else if (p_dev->suspended && !strncmp(buf, "on", 2)) - runtime_resume(dev); + ret = runtime_resume(dev); return ret ? ret : count; } -- GitLab From cd2e18fe785082b132d960063df83a02acc9a4f2 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 1 Jan 2010 17:43:08 +0100 Subject: [PATCH 0834/3892] pcmcia: remove remaining unused IRQ_FIRST_SHARED parameter Komuro pointed out correctly that I missed one IRQ_FIRST_SHARED parameter in smc91c92_cs.c, and that another line could be writter more beautifully. CC: netdev@vger.kernel.org CC: Komuro Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/smc91c92_cs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6dd486d2977b..aa57cfd1e3fb 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -453,8 +453,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; - link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->io.IOAddrLines = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; @@ -652,8 +651,7 @@ static int osi_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; - link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->io.NumPorts1 = 64; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; -- GitLab From fa0b3bc504ff813cc05988bb30bbb6c6a0263eb4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:08:22 +0100 Subject: [PATCH 0835/3892] pcmcia: do not meddle with already assigned resources Do not release any iomem resources already in use. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 9b0dc433a8c3..4f93889301b6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -727,13 +727,6 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned break; case REMOVE_MANAGED_RESOURCE: ret = sub_interval(&data->mem_db, start, size); - if (!ret) { - struct pcmcia_socket *socket; - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(socket, &pcmcia_socket_list, socket_list) - release_cis_mem(socket); - up_read(&pcmcia_socket_list_rwsem); - } break; default: ret = -EINVAL; -- GitLab From 904e377744bfdcea276c27167fa6a609929f39dc Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:28:04 +0100 Subject: [PATCH 0836/3892] pcmcia: validate CIS, not CIS cache. In pccard_validate_cis(), validate the card CIS, not the CIS cache. Also, destroy the CIS cache if pccard_validate_cis fails. Furthermore, do not remove the fake CIS in destroy_cis_cache() but do so explicitely in the code paths where it makes sense. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 24 ++++++++++++++++-------- drivers/pcmcia/cs.c | 4 ++++ drivers/pcmcia/rsrc_nonstatic.c | 3 +-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 25b1cd219e37..41ec7729eddc 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -319,22 +319,23 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) } } +/** + * destroy_cis_cache() - destroy the CIS cache + * @s: pcmcia_socket for which CIS cache shall be destroyed + * + * This destroys the CIS cache but keeps any fake CIS alive. + */ + void destroy_cis_cache(struct pcmcia_socket *s) { struct list_head *l, *n; + struct cis_cache_entry *cis; list_for_each_safe(l, n, &s->cis_cache) { - struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node); - + cis = list_entry(l, struct cis_cache_entry, node); list_del(&cis->node); kfree(cis); } - - /* - * If there was a fake CIS, destroy that as well. - */ - kfree(s->fake_cis); - s->fake_cis = NULL; } EXPORT_SYMBOL(destroy_cis_cache); @@ -1596,6 +1597,9 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) if (!s) return -EINVAL; + /* We do not want to validate the CIS cache... */ + destroy_cis_cache(s); + tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); if (tuple == NULL) { dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); @@ -1647,6 +1651,10 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) count = 0; done: + /* invalidate CIS cache on failure */ + if (!dev_ok || !ident_ok || !count) + destroy_cis_cache(s); + if (info) *info = count; kfree(tuple); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 6d6f82b38a68..96d8d25c209d 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -407,6 +407,8 @@ static void socket_shutdown(struct pcmcia_socket *s) s->irq.AssignedIRQ = s->irq.Config = 0; s->lock_count = 0; destroy_cis_cache(s); + kfree(s->fake_cis); + s->fake_cis = NULL; #ifdef CONFIG_CARDBUS cb_free(s); #endif @@ -577,6 +579,8 @@ static int socket_late_resume(struct pcmcia_socket *skt) dev_dbg(&skt->dev, "cis mismatch - different card\n"); socket_remove_drivers(skt); destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; /* * Workaround: give DS time to schedule removal. * Remove me once the 100ms delay is eliminated diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 4f93889301b6..b886385f12e2 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -281,10 +281,9 @@ static int readable(struct pcmcia_socket *s, struct resource *res, s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { ret = pccard_validate_cis(s, count); - /* invalidate mapping and CIS cache */ + /* invalidate mapping */ iounmap(s->cis_virt); s->cis_virt = NULL; - destroy_cis_cache(s); } s->cis_mem.res = NULL; if ((ret != 0) || (*count == 0)) -- GitLab From f131ddc4bd1713385c70606555d4d63bed5ec3fd Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 12:58:10 +0100 Subject: [PATCH 0837/3892] pcmcia: cleanup pccard_validate_cis() Cleanup pccard_validate_cis() and make it return an error code on all failures, not merely on some failures. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 155 +++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 74 deletions(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 41ec7729eddc..04bf1ba607f7 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1577,88 +1577,95 @@ next_entry: EXPORT_SYMBOL(pccard_loop_tuple); -/*====================================================================== - - This tries to determine if a card has a sensible CIS. It returns - the number of tuples in the CIS, or 0 if the CIS looks bad. The - checks include making sure several critical tuples are present and - valid; seeing if the total number of tuples is reasonable; and - looking for tuples that use reserved codes. - -======================================================================*/ - +/** + * pccard_validate_cis() - check whether card has a sensible CIS + * @s: the struct pcmcia_socket we are to check + * @info: returns the number of tuples in the (valid) CIS, or 0 + * + * This tries to determine if a card has a sensible CIS. In @info, it + * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The + * checks include making sure several critical tuples are present and + * valid; seeing if the total number of tuples is reasonable; and + * looking for tuples that use reserved codes. + * + * The function returns 0 on success. + */ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) { - tuple_t *tuple; - cisparse_t *p; - unsigned int count = 0; - int ret, reserved, dev_ok = 0, ident_ok = 0; + tuple_t *tuple; + cisparse_t *p; + unsigned int count = 0; + int ret, reserved, dev_ok = 0, ident_ok = 0; - if (!s) - return -EINVAL; + if (!s) + return -EINVAL; - /* We do not want to validate the CIS cache... */ - destroy_cis_cache(s); + /* We do not want to validate the CIS cache... */ + destroy_cis_cache(s); - tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); - if (tuple == NULL) { - dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); - return -ENOMEM; - } - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - kfree(tuple); - dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); - return -ENOMEM; - } + tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); + if (tuple == NULL) { + dev_warn(&s->dev, "no memory to validate CIS\n"); + return -ENOMEM; + } + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + kfree(tuple); + dev_warn(&s->dev, "no memory to validate CIS\n"); + return -ENOMEM; + } - count = reserved = 0; - tuple->DesiredTuple = RETURN_FIRST_TUPLE; - tuple->Attributes = TUPLE_RETURN_COMMON; - ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); - if (ret != 0) - goto done; - - /* First tuple should be DEVICE; we should really have either that - or a CFTABLE_ENTRY of some sort */ - if ((tuple->TupleCode == CISTPL_DEVICE) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p) == 0)) - dev_ok++; - - /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 - tuple, for card identification. Certain old D-Link and Linksys - cards have only a broken VERS_2 tuple; hence the bogus test. */ - if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || - (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) - ident_ok++; - - if (!dev_ok && !ident_ok) - goto done; - - for (count = 1; count < MAX_TUPLES; count++) { - ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); + count = reserved = 0; + tuple->DesiredTuple = RETURN_FIRST_TUPLE; + tuple->Attributes = TUPLE_RETURN_COMMON; + ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); if (ret != 0) - break; - if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || - ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || - ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) - reserved++; - } - if ((count == MAX_TUPLES) || (reserved > 5) || - ((!dev_ok || !ident_ok) && (count > 10))) - count = 0; + goto done; + + /* First tuple should be DEVICE; we should really have either that + or a CFTABLE_ENTRY of some sort */ + if ((tuple->TupleCode == CISTPL_DEVICE) || + (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) || + (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p))) + dev_ok++; + + /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 + tuple, for card identification. Certain old D-Link and Linksys + cards have only a broken VERS_2 tuple; hence the bogus test. */ + if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || + (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || + (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) + ident_ok++; + + if (!dev_ok && !ident_ok) + goto done; + + for (count = 1; count < MAX_TUPLES; count++) { + ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); + if (ret != 0) + break; + if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || + ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || + ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) + reserved++; + } + if ((count == MAX_TUPLES) || (reserved > 5) || + ((!dev_ok || !ident_ok) && (count > 10))) + count = 0; + + ret = 0; done: - /* invalidate CIS cache on failure */ - if (!dev_ok || !ident_ok || !count) - destroy_cis_cache(s); - - if (info) - *info = count; - kfree(tuple); - kfree(p); - return 0; + /* invalidate CIS cache on failure */ + if (!dev_ok || !ident_ok || !count) { + destroy_cis_cache(s); + ret = -EIO; + } + + if (info) + *info = count; + kfree(tuple); + kfree(p); + return ret; } EXPORT_SYMBOL(pccard_validate_cis); -- GitLab From 88b060d6c03fcb9e4d2018b4349954c4242a5c7f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 14:14:23 +0100 Subject: [PATCH 0838/3892] pcmcia: improve check for same card in slot after resume During a suspend/resume cycle, an user may change the card in the PCMCIA/CardBus slot. The pcmcia_core can at least look at the socket state to check whether it is the same. For PCMCIA devices, move the detection and handling of such a change to ds.c. For CardBus devices, the PCI hotplug interface doesn't offer a "rescan" facility which also _removes_ devices no longer to be found behind a bridge. Therefore, remove and re-add all devices unconditionally. CC: Jesse Barnes CC: Linus Torvalds Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 1 + drivers/pcmcia/cs.c | 65 +++++++++++++++++++---------------------- drivers/pcmcia/ds.c | 16 +++++++++- include/pcmcia/ss.h | 1 + 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 04bf1ba607f7..a8323cb2e34d 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -377,6 +377,7 @@ int verify_cis_cache(struct pcmcia_socket *s) kfree(buf); return 0; } +EXPORT_SYMBOL(verify_cis_cache); /*====================================================================== diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 96d8d25c209d..8c51493d1f95 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -328,7 +328,7 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) { int ret; - if (s->state & SOCKET_CARDBUS) + if ((s->state & SOCKET_CARDBUS) && (event != CS_EVENT_CARD_REMOVAL)) return 0; dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n", @@ -346,13 +346,6 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) return ret; } -static void socket_remove_drivers(struct pcmcia_socket *skt) -{ - dev_dbg(&skt->dev, "remove_drivers\n"); - - send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); -} - static int socket_reset(struct pcmcia_socket *skt) { int status, i; @@ -395,7 +388,7 @@ static void socket_shutdown(struct pcmcia_socket *s) dev_dbg(&s->dev, "shutdown\n"); - socket_remove_drivers(s); + send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); s->state &= SOCKET_INUSE | SOCKET_PRESENT; msleep(shutdown_delay * 10); s->state &= SOCKET_INUSE; @@ -462,7 +455,8 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) return -EINVAL; } skt->state |= SOCKET_CARDBUS; - } + } else + skt->state &= ~SOCKET_CARDBUS; /* * Decode the card voltage requirements, and apply power to the card. @@ -544,6 +538,8 @@ static int socket_suspend(struct pcmcia_socket *skt) if (skt->state & SOCKET_SUSPEND) return -EBUSY; + skt->suspended_state = skt->state; + send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); skt->socket = dead_socket; skt->ops->set_socket(skt, &skt->socket); @@ -566,38 +562,37 @@ static int socket_early_resume(struct pcmcia_socket *skt) static int socket_late_resume(struct pcmcia_socket *skt) { - if (!(skt->state & SOCKET_PRESENT)) { - skt->state &= ~SOCKET_SUSPEND; + skt->state &= ~SOCKET_SUSPEND; + + if (!(skt->state & SOCKET_PRESENT)) return socket_insert(skt); + + if (skt->resume_status) { + socket_shutdown(skt); + return 0; } - if (skt->resume_status == 0) { - /* - * FIXME: need a better check here for cardbus cards. - */ - if (verify_cis_cache(skt) != 0) { - dev_dbg(&skt->dev, "cis mismatch - different card\n"); - socket_remove_drivers(skt); - destroy_cis_cache(skt); - kfree(skt->fake_cis); - skt->fake_cis = NULL; - /* - * Workaround: give DS time to schedule removal. - * Remove me once the 100ms delay is eliminated - * in ds.c - */ - msleep(200); - send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); - } else { - dev_dbg(&skt->dev, "cis matches cache\n"); - send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); - } - } else { + if (skt->suspended_state != skt->state) { + dev_dbg(&skt->dev, + "suspend state 0x%x != resume state 0x%x\n", + skt->suspended_state, skt->state); + socket_shutdown(skt); + return socket_insert(skt); } - skt->state &= ~SOCKET_SUSPEND; +#ifdef CONFIG_CARDBUS + if (skt->state & SOCKET_CARDBUS) { + /* We can't be sure the CardBus card is the same + * as the one previously inserted. Therefore, remove + * and re-add... */ + cb_free(skt); + cb_alloc(skt); + return 0; + } +#endif + send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index defa44c27b97..87e06395c129 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1252,8 +1252,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) case CS_EVENT_EJECTION_REQUEST: break; - case CS_EVENT_PM_SUSPEND: case CS_EVENT_PM_RESUME: + if (verify_cis_cache(skt) != 0) { + dev_dbg(&skt->dev, "cis mismatch - different card\n"); + /* first, remove the card */ + ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); + destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; + /* now, add the new card */ + ds_event(skt, CS_EVENT_CARD_INSERTION, + CS_EVENT_PRI_LOW); + } + handle_event(skt, event); + break; + + case CS_EVENT_PM_SUSPEND: case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_CARD_RESET: default: diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index cbfba885eb85..b0ebd11130cc 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -137,6 +137,7 @@ struct pcmcia_socket { spinlock_t lock; socket_state_t socket; u_int state; + u_int suspended_state; /* state before suspend */ u_short functions; u_short lock_count; pccard_mem_map cis_mem; -- GitLab From 57197b9b7712eb19f5344c466e8aefbac1adbe55 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 17:27:33 +0100 Subject: [PATCH 0839/3892] pcmcia: CardBus doesn't need CIS access At least no in-kernel CardBus-capable PCI driver makes use of the CIS access functions. Therefore, it seems sensible to remove this unused code, and cleanup cardbus.c a lot. CC: Jesse Barnes CC: Linus Torvalds Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cardbus.c | 175 +++------------------------------- drivers/pcmcia/cistpl.c | 200 +++++++-------------------------------- include/pcmcia/ss.h | 6 -- 3 files changed, 46 insertions(+), 335 deletions(-) diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index d99f846451a3..ac0686efbf75 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -20,170 +20,12 @@ */ -#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include "cs_internal.h" - -/*====================================================================*/ - -/* Offsets in the Expansion ROM Image Header */ -#define ROM_SIGNATURE 0x0000 /* 2 bytes */ -#define ROM_DATA_PTR 0x0018 /* 2 bytes */ - -/* Offsets in the CardBus PC Card Data Structure */ -#define PCDATA_SIGNATURE 0x0000 /* 4 bytes */ -#define PCDATA_VPD_PTR 0x0008 /* 2 bytes */ -#define PCDATA_LENGTH 0x000a /* 2 bytes */ -#define PCDATA_REVISION 0x000c -#define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */ -#define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */ -#define PCDATA_CODE_TYPE 0x0014 -#define PCDATA_INDICATOR 0x0015 - -/*===================================================================== - - Expansion ROM's have a special layout, and pointers specify an - image number and an offset within that image. xlate_rom_addr() - converts an image/offset address to an absolute offset from the - ROM's base address. - -=====================================================================*/ - -static u_int xlate_rom_addr(void __iomem *b, u_int addr) -{ - u_int img = 0, ofs = 0, sz; - u_short data; - while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { - if (img == (addr >> 28)) - return (addr & 0x0fffffff) + ofs; - data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); - sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + - (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); - if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) - break; - b += sz; - ofs += sz; - img++; - } - return 0; -} - -/*===================================================================== - - These are similar to setup_cis_mem and release_cis_mem for 16-bit - cards. The "result" that is used externally is the cb_cis_virt - pointer in the struct pcmcia_socket structure. - -=====================================================================*/ - -static void cb_release_cis_mem(struct pcmcia_socket *s) -{ - if (s->cb_cis_virt) { - dev_dbg(&s->dev, "cb_release_cis_mem()\n"); - iounmap(s->cb_cis_virt); - s->cb_cis_virt = NULL; - s->cb_cis_res = NULL; - } -} - -static int cb_setup_cis_mem(struct pcmcia_socket *s, struct resource *res) -{ - unsigned int start, size; - - if (res == s->cb_cis_res) - return 0; - - if (s->cb_cis_res) - cb_release_cis_mem(s); - - start = res->start; - size = res->end - start + 1; - s->cb_cis_virt = ioremap(start, size); - - if (!s->cb_cis_virt) - return -1; - - s->cb_cis_res = res; - - return 0; -} - -/*===================================================================== - - This is used by the CIS processing code to read CIS information - from a CardBus device. - -=====================================================================*/ - -int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, - void *ptr) -{ - struct pci_dev *dev; - struct resource *res; - - dev_dbg(&s->dev, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); - dev = pci_get_slot(s->cb_dev->subordinate, 0); - if (!dev) - goto fail; - - /* Config space? */ - if (space == 0) { - if (addr + len > 0x100) - goto failput; - for (; len; addr++, ptr++, len--) - pci_read_config_byte(dev, addr, ptr); - return 0; - } - - res = dev->resource + space - 1; - - pci_dev_put(dev); - - if (!res->flags) - goto fail; - - if (cb_setup_cis_mem(s, res) != 0) - goto fail; - - if (space == 7) { - addr = xlate_rom_addr(s->cb_cis_virt, addr); - if (addr == 0) - goto fail; - } - - if (addr + len > res->end - res->start) - goto fail; - - memcpy_fromio(ptr, s->cb_cis_virt + addr, len); - return 0; - -failput: - pci_dev_put(dev); -fail: - memset(ptr, 0xff, len); - return -1; -} - -/*===================================================================== - - cb_alloc() and cb_free() allocate and free the kernel data - structures for a Cardbus device, and handle the lowest level PCI - device setup issues. - -=====================================================================*/ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq) { @@ -215,6 +57,13 @@ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq) } } +/** + * cb_alloc() - add CardBus device + * @s: the pcmcia_socket where the CardBus device is located + * + * cb_alloc() allocates the kernel data structures for a Cardbus device + * and handles the lowest level PCI device setup issues. + */ int __ref cb_alloc(struct pcmcia_socket *s) { struct pci_bus *bus = s->cb_dev->subordinate; @@ -249,12 +98,16 @@ int __ref cb_alloc(struct pcmcia_socket *s) return 0; } +/** + * cb_free() - remove CardBus device + * @s: the pcmcia_socket where the CardBus device was located + * + * cb_free() handles the lowest level PCI device cleanup. + */ void cb_free(struct pcmcia_socket *s) { struct pci_dev *bridge = s->cb_dev; - cb_release_cis_mem(s); - if (bridge) pci_remove_behind_bridge(bridge); } diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index a8323cb2e34d..368367ced62b 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -268,29 +268,27 @@ EXPORT_SYMBOL(pcmcia_write_cis_mem); static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, size_t len, void *ptr) { - struct cis_cache_entry *cis; - int ret; + struct cis_cache_entry *cis; + int ret; - if (s->fake_cis) { - if (s->fake_cis_len >= addr+len) - memcpy(ptr, s->fake_cis+addr, len); - else - memset(ptr, 0xff, len); - return; - } + if (s->state & SOCKET_CARDBUS) + return; - list_for_each_entry(cis, &s->cis_cache, node) { - if (cis->addr == addr && cis->len == len && cis->attr == attr) { - memcpy(ptr, cis->cache, len); - return; + if (s->fake_cis) { + if (s->fake_cis_len >= addr+len) + memcpy(ptr, s->fake_cis+addr, len); + else + memset(ptr, 0xff, len); + return; + } + + list_for_each_entry(cis, &s->cis_cache, node) { + if (cis->addr == addr && cis->len == len && cis->attr == attr) { + memcpy(ptr, cis->cache, len); + return; + } } - } -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) - ret = read_cb_mem(s, attr, addr, len, ptr); - else -#endif ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); if (ret == 0) { @@ -351,6 +349,9 @@ int verify_cis_cache(struct pcmcia_socket *s) struct cis_cache_entry *cis; char *buf; + if (s->state & SOCKET_CARDBUS) + return -EINVAL; + buf = kmalloc(256, GFP_KERNEL); if (buf == NULL) { dev_printk(KERN_WARNING, &s->dev, @@ -362,12 +363,8 @@ int verify_cis_cache(struct pcmcia_socket *s) if (len > 256) len = 256; -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) - read_cb_mem(s, cis->attr, cis->addr, len, buf); - else -#endif - pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); + + pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); if (memcmp(buf, cis->cache, len) != 0) { kfree(buf); @@ -427,25 +424,16 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple { if (!s) return -EINVAL; - if (!(s->state & SOCKET_PRESENT)) + + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) return -ENODEV; tuple->TupleLink = tuple->Flags = 0; -#ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) { - struct pci_dev *dev = s->cb_dev; - u_int ptr; - pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr); - tuple->CISOffset = ptr & ~7; - SPACE(tuple->Flags) = (ptr & 7); - } else -#endif - { - /* Assume presence of a LONGLINK_C to address 0 */ - tuple->CISOffset = tuple->LinkOffset = 0; - SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; - } - if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && - !(tuple->Attributes & TUPLE_RETURN_COMMON)) { + + /* Assume presence of a LONGLINK_C to address 0 */ + tuple->CISOffset = tuple->LinkOffset = 0; + SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; + + if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { cisdata_t req = tuple->DesiredTuple; tuple->DesiredTuple = CISTPL_LONGLINK_MFC; if (pccard_get_next_tuple(s, function, tuple) == 0) { @@ -481,7 +469,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) } else { return -1; } - if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { + if (SPACE(tuple->Flags)) { /* This is ugly, but a common CIS error is to code the long link offset incorrectly, so we check the right spot... */ read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); @@ -507,7 +495,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ if (!s) return -EINVAL; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) return -ENODEV; link[1] = tuple->TupleLink; @@ -1192,119 +1180,6 @@ static int parse_cftable_entry(tuple_t *tuple, /*====================================================================*/ -#ifdef CONFIG_CARDBUS - -static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) -{ - u_char *p; - if (tuple->TupleDataLen < 6) - return -EINVAL; - p = (u_char *)tuple->TupleData; - bar->attr = *p; - p += 2; - bar->size = get_unaligned_le32(p); - return 0; -} - -static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) -{ - u_char *p; - - p = (u_char *)tuple->TupleData; - if ((*p != 3) || (tuple->TupleDataLen < 6)) - return -EINVAL; - config->last_idx = *(++p); - p++; - config->base = get_unaligned_le32(p); - config->subtuples = tuple->TupleDataLen - 6; - return 0; -} - -static int parse_cftable_entry_cb(tuple_t *tuple, - cistpl_cftable_entry_cb_t *entry) -{ - u_char *p, *q, features; - - p = tuple->TupleData; - q = p + tuple->TupleDataLen; - entry->index = *p & 0x3f; - entry->flags = 0; - if (*p & 0x40) - entry->flags |= CISTPL_CFTABLE_DEFAULT; - - /* Process optional features */ - if (++p == q) - return -EINVAL; - features = *p; p++; - - /* Power options */ - if ((features & 3) > 0) { - p = parse_power(p, q, &entry->vcc); - if (p == NULL) - return -EINVAL; - } else - entry->vcc.present = 0; - if ((features & 3) > 1) { - p = parse_power(p, q, &entry->vpp1); - if (p == NULL) - return -EINVAL; - } else - entry->vpp1.present = 0; - if ((features & 3) > 2) { - p = parse_power(p, q, &entry->vpp2); - if (p == NULL) - return -EINVAL; - } else - entry->vpp2.present = 0; - - /* I/O window options */ - if (features & 0x08) { - if (p == q) - return -EINVAL; - entry->io = *p; p++; - } else - entry->io = 0; - - /* Interrupt options */ - if (features & 0x10) { - p = parse_irq(p, q, &entry->irq); - if (p == NULL) - return -EINVAL; - } else - entry->irq.IRQInfo1 = 0; - - if (features & 0x20) { - if (p == q) - return -EINVAL; - entry->mem = *p; p++; - } else - entry->mem = 0; - - /* Misc features */ - if (features & 0x80) { - if (p == q) - return -EINVAL; - entry->flags |= (*p << 8); - if (*p & 0x80) { - if (++p == q) - return -EINVAL; - entry->flags |= (*p << 16); - } - while (*p & 0x80) - if (++p == q) - return -EINVAL; - p++; - } - - entry->subtuples = q-p; - - return 0; -} - -#endif - -/*====================================================================*/ - static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) { u_char *p, *q; @@ -1406,17 +1281,6 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) case CISTPL_DEVICE_A: ret = parse_device(tuple, &parse->device); break; -#ifdef CONFIG_CARDBUS - case CISTPL_BAR: - ret = parse_bar(tuple, &parse->bar); - break; - case CISTPL_CONFIG_CB: - ret = parse_config_cb(tuple, &parse->config); - break; - case CISTPL_CFTABLE_ENTRY_CB: - ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); - break; -#endif case CISTPL_CHECKSUM: ret = parse_checksum(tuple, &parse->checksum); break; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index b0ebd11130cc..b4e5cfd49ce1 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -244,12 +244,6 @@ struct pcmcia_socket { #endif /* CONFIG_PCMCIA_IOCTL */ #endif /* CONFIG_PCMCIA */ - /* cardbus (32-bit) */ -#ifdef CONFIG_CARDBUS - struct resource *cb_cis_res; - void __iomem *cb_cis_virt; -#endif /* CONFIG_CARDBUS */ - /* socket device */ struct device dev; /* data internal to the socket driver */ -- GitLab From 180c33ee409eb3ed605d4ad9884e4a526a7655ff Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 17:34:09 +0100 Subject: [PATCH 0840/3892] pcmcia: call CIS cleanup from ds.c As ds.c is the only real user of CIS access functions, call the cleanup functions from ds.c, too. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 3 --- drivers/pcmcia/ds.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 8c51493d1f95..9d8b9c1f5a69 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -283,8 +283,6 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) if (socket->thread) kthread_stop(socket->thread); - release_cis_mem(socket); - /* remove from our own list */ down_write(&pcmcia_socket_list_rwsem); list_del(&socket->socket_list); @@ -399,7 +397,6 @@ static void socket_shutdown(struct pcmcia_socket *s) s->ops->set_socket(s, &s->socket); s->irq.AssignedIRQ = s->irq.Config = 0; s->lock_count = 0; - destroy_cis_cache(s); kfree(s->fake_cis); s->fake_cis = NULL; #ifdef CONFIG_CARDBUS diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 87e06395c129..7bb52b003f0e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1241,10 +1241,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) s->pcmcia_state.present = 0; pcmcia_card_remove(skt, NULL); handle_event(skt, event); + destroy_cis_cache(s); break; case CS_EVENT_CARD_INSERTION: s->pcmcia_state.present = 1; + destroy_cis_cache(s); /* to be on the safe side... */ pcmcia_card_add(skt); handle_event(skt, event); break; @@ -1366,6 +1368,7 @@ static void pcmcia_bus_remove_socket(struct device *dev, /* unregister any unbound devices */ mutex_lock(&socket->skt_mutex); pcmcia_card_remove(socket, NULL); + release_cis_mem(socket); mutex_unlock(&socket->skt_mutex); pcmcia_put_socket(socket); -- GitLab From 3f32b3c093eddc03ed477ae0d7a6938db6b94a05 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 22:22:50 +0100 Subject: [PATCH 0841/3892] pcmcia: rsrc_nonstatic io memory probe improvements Add a lot of documentation to the rsrc_nonstatic io memory probe functions. Also, add a first memory probe call -- just checking whether request_resource() succeeds -- upon adding of resources. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 174 +++++++++++++++++++++----------- 1 file changed, 114 insertions(+), 60 deletions(-) diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index b886385f12e2..120d5ad99296 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -264,18 +264,15 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, } #endif -/*====================================================================== - - This is tricky... when we set up CIS memory, we try to validate - the memory window space allocations. - -======================================================================*/ +/*======================================================================*/ -/* Validation function for cards with a valid CIS */ +/** + * readable() - iomem validation function for cards with a valid CIS + */ static int readable(struct pcmcia_socket *s, struct resource *res, unsigned int *count) { - int ret = -1; + int ret = -EINVAL; s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); @@ -286,13 +283,16 @@ static int readable(struct pcmcia_socket *s, struct resource *res, s->cis_virt = NULL; } s->cis_mem.res = NULL; - if ((ret != 0) || (*count == 0)) - return 0; - return 1; + if ((ret) || (*count == 0)) + return -EINVAL; + return 0; } -/* Validation function for simple memory cards */ -static int checksum(struct pcmcia_socket *s, struct resource *res) +/** + * checksum() - iomem validation function for simple memory cards + */ +static int checksum(struct pcmcia_socket *s, struct resource *res, + unsigned int *value) { pccard_mem_map map; int i, a = 0, b = -1, d; @@ -320,61 +320,83 @@ static int checksum(struct pcmcia_socket *s, struct resource *res) iounmap(virt); } - return (b == -1) ? -1 : (a>>1); -} - -static int -cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) -{ - struct resource *res1, *res2; - unsigned int info1, info2; - int ret = 0; - - res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); - res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, - "PCMCIA memprobe"); - - if (res1 && res2) { - ret = readable(s, res1, &info1); - ret += readable(s, res2, &info2); - } + if (b == -1) + return -EINVAL; - free_region(res2); - free_region(res1); + *value = a; - return (ret == 2) && (info1 == info2); + return 0; } -static int -checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) +/** + * do_validate_mem() - low level validate a memory region for PCMCIA use + * @s: PCMCIA socket to validate + * @base: start address of resource to check + * @size: size of resource to check + * @validate: validation function to use + * + * do_validate_mem() splits up the memory region which is to be checked + * into two parts. Both are passed to the @validate() function. If + * @validate() returns non-zero, or the value parameter to @validate() + * is zero, or the value parameter is different between both calls, + * the check fails, and -EINVAL is returned. Else, 0 is returned. + */ +static int do_validate_mem(struct pcmcia_socket *s, + unsigned long base, unsigned long size, + int validate (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value)) { struct resource *res1, *res2; - int a = -1, b = -1; + unsigned int info1 = 1, info2 = 1; + int ret = -EINVAL; res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); if (res1 && res2) { - a = checksum(s, res1); - b = checksum(s, res2); + ret = 0; + if (validate) { + ret = validate(s, res1, &info1); + ret += validate(s, res2, &info2); + } } free_region(res2); free_region(res1); - return (a == b) && (a >= 0); -} + dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u", + base, base+size-1, res1, res2, ret, info1, info2); -/*====================================================================== + if ((ret) || (info1 != info2) || (info1 == 0)) + return -EINVAL; - The memory probe. If the memory list includes a 64K-aligned block - below 1MB, we probe in 64K chunks, and as soon as we accumulate at - least mem_limit free space, we quit. + return 0; +} -======================================================================*/ -static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) +/** + * do_mem_probe() - validate a memory region for PCMCIA use + * @s: PCMCIA socket to validate + * @base: start address of resource to check + * @num: size of resource to check + * @validate: validation function to use + * @fallback: validation function to use if validate fails + * + * do_mem_probe() checks a memory region for use by the PCMCIA subsystem. + * To do so, the area is split up into sensible parts, and then passed + * into the @validate() function. Only if @validate() and @fallback() fail, + * the area is marked as unavaibale for use by the PCMCIA subsystem. The + * function returns the size of the usable memory area. + */ +static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + int validate (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value), + int fallback (struct pcmcia_socket *s, + struct resource *res, + unsigned int *value)) { struct socket_data *s_data = s->resource_data; u_long i, j, bad, fail, step; @@ -392,15 +414,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) { - if (cis_readable(s, j, step)) + if (!do_validate_mem(s, j, step, validate)) break; } fail = ((i == base) && (j == base+num)); } - if (fail) { - for (j = i; j < base+num; j += 2*step) - if (checksum_match(s, j, step) && - checksum_match(s, j + step, step)) + if ((fail) && (fallback)) { + for (j = i; j < base+num; j += step) + if (!do_validate_mem(s, j, step, fallback)) break; } if (i != j) { @@ -415,8 +436,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) return num - bad; } + #ifdef CONFIG_PCMCIA_PROBE +/** + * inv_probe() - top-to-bottom search for one usuable high memory area + * @s: PCMCIA socket to validate + * @m: resource_map to check + */ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) { struct socket_data *s_data = s->resource_data; @@ -431,9 +458,18 @@ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, s); + return do_mem_probe(s, m->base, m->num, readable, checksum); } +/** + * validate_mem() - memory probe function + * @s: PCMCIA socket to validate + * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH + * + * The memory probe. If the memory list includes a 64K-aligned block + * below 1MB, we probe in 64K chunks, and as soon as we accumulate at + * least mem_limit free space, we quit. Returns 0 on usuable ports. + */ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { struct resource_map *m, mm; @@ -456,7 +492,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) if (mm.base >= 0x100000) continue; if ((mm.base | mm.num) & 0xffff) { - ok += do_mem_probe(mm.base, mm.num, s); + ok += do_mem_probe(s, mm.base, mm.num, readable, + checksum); continue; } /* Special probe for 64K-aligned block */ @@ -466,7 +503,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) if (ok >= mem_limit) sub_interval(&s_data->mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, s); + ok += do_mem_probe(s, b, 0x10000, + readable, checksum); } } } @@ -479,6 +517,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) #else /* CONFIG_PCMCIA_PROBE */ +/** + * validate_mem() - memory probe function + * @s: PCMCIA socket to validate + * @probe_mask: ignored + * + * Returns 0 on usuable ports. + */ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { struct resource_map *m, mm; @@ -487,7 +532,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { mm = *m; - ok += do_mem_probe(mm.base, mm.num, s); + ok += do_mem_probe(s, mm.base, mm.num, readable, checksum); } if (ok > 0) return 0; @@ -497,7 +542,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) #endif /* CONFIG_PCMCIA_PROBE */ -/* +/** + * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use + * @s: PCMCIA socket to validate + * + * This is tricky... when we set up CIS memory, we try to validate + * the memory window space allocations. + * * Locking note: Must be called with skt_mutex held! */ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) @@ -515,10 +566,11 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) probe_mask = MEM_PROBE_HIGH; if (probe_mask & ~s_data->rsrc_mem_probe) { - if (s->state & SOCKET_PRESENT) + if (s->state & SOCKET_PRESENT) { ret = validate_mem(s, probe_mask); - if (!ret) - s_data->rsrc_mem_probe |= probe_mask; + if (!ret) + s_data->rsrc_mem_probe |= probe_mask; + } } mutex_unlock(&rsrc_mutex); @@ -723,6 +775,8 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned switch (action) { case ADD_MANAGED_RESOURCE: ret = add_interval(&data->mem_db, start, size); + if (!ret) + do_mem_probe(s, start, size, NULL, NULL); break; case REMOVE_MANAGED_RESOURCE: ret = sub_interval(&data->mem_db, start, size); -- GitLab From 593f010bc0d8f7fde2ce948cac3f77f6a3d9db2b Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 22:59:15 +0100 Subject: [PATCH 0842/3892] pcmcia: do not lock socket driver module in pcmcia_get_socket() Do not lock the socket driver module in pcmcia_get_socket(), as the PCMCIA core can handle a socket module removal: In pcmcia_unregister_socket(), we explicitely wait for the last put_device() to succeed. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 9d8b9c1f5a69..f0630a61da90 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -140,19 +140,13 @@ struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) struct device *dev = get_device(&skt->dev); if (!dev) return NULL; - skt = dev_get_drvdata(dev); - if (!try_module_get(skt->owner)) { - put_device(&skt->dev); - return NULL; - } - return skt; + return dev_get_drvdata(dev); } EXPORT_SYMBOL(pcmcia_get_socket); void pcmcia_put_socket(struct pcmcia_socket *skt) { - module_put(skt->owner); put_device(&skt->dev); } EXPORT_SYMBOL(pcmcia_put_socket); -- GitLab From 8b0e58a70a7a41443c779de074288035b014cb94 Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Wed, 13 Jan 2010 21:52:34 +0100 Subject: [PATCH 0843/3892] HID: let hid-input accept digitizers Extended IS_INPUT_APPLICATION to accept digitzers that are actual input devices (touchscreens, light pens, touch pads, white boards) Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- include/linux/hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index 87093652dda8..b978c1e2e74d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -663,7 +663,7 @@ struct hid_ll_driver { /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ /* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002)) +#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006))) /* HID core API */ -- GitLab From 72659ecce68588b74f6c46862c2b4cec137d7a5a Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sun, 17 Jan 2010 19:09:39 -0800 Subject: [PATCH 0844/3892] tcp: account SYN-ACK timeouts & retransmissions Currently we don't increment SYN-ACK timeouts & retransmissions although we do increment the same stats for SYN. We seem to have lost the SYN-ACK accounting with the introduction of tcp_syn_recv_timer (commit 2248761e in the netdev-vger-cvs tree). This patch fixes this issue. In the process we also rename the v4/v6 syn/ack retransmit functions for clarity. We also add a new request_socket operations (syn_ack_timeout) so we can keep code in inet_connection_sock.c protocol agnostic. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/request_sock.h | 2 ++ include/net/tcp.h | 2 ++ net/ipv4/inet_connection_sock.c | 2 ++ net/ipv4/tcp_ipv4.c | 18 ++++++++++-------- net/ipv4/tcp_timer.c | 6 ++++++ net/ipv6/tcp_ipv6.c | 12 ++++++++++-- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index c9b50ebd9ce9..99e6e19b57c2 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -45,6 +45,8 @@ struct request_sock_ops { void (*send_reset)(struct sock *sk, struct sk_buff *skb); void (*destructor)(struct request_sock *req); + void (*syn_ack_timeout)(struct sock *sk, + struct request_sock *req); }; /* struct request_sock - mini sock to represent a connection request diff --git a/include/net/tcp.h b/include/net/tcp.h index 788c99f98597..87d164b9bd8f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -400,6 +400,8 @@ extern int compat_tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen); extern void tcp_set_keepalive(struct sock *sk, int val); +extern void tcp_syn_ack_timeout(struct sock *sk, + struct request_sock *req); extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int nonblock, diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index ee16475f8fc3..8da6429269dd 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -529,6 +529,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, syn_ack_recalc(req, thresh, max_retries, queue->rskq_defer_accept, &expire, &resend); + if (req->rsk_ops->syn_ack_timeout) + req->rsk_ops->syn_ack_timeout(parent, req); if (!expire && (!resend || !req->rsk_ops->rtx_syn_ack(parent, req, NULL) || diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 382f667238ec..356f544c4c10 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -742,9 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, * This still operates on a request_sock only, not on a big * socket. */ -static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, - struct request_sock *req, - struct request_values *rvp) +static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, + struct request_sock *req, + struct request_values *rvp) { const struct inet_request_sock *ireq = inet_rsk(req); int err = -1; @@ -775,10 +775,11 @@ static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, return err; } -static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, +static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req, struct request_values *rvp) { - return __tcp_v4_send_synack(sk, NULL, req, rvp); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); + return tcp_v4_send_synack(sk, NULL, req, rvp); } /* @@ -1192,10 +1193,11 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), - .rtx_syn_ack = tcp_v4_send_synack, + .rtx_syn_ack = tcp_v4_rtx_synack, .send_ack = tcp_v4_reqsk_send_ack, .destructor = tcp_v4_reqsk_destructor, .send_reset = tcp_v4_send_reset, + .syn_ack_timeout = tcp_syn_ack_timeout, }; #ifdef CONFIG_TCP_MD5SIG @@ -1373,8 +1375,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) } tcp_rsk(req)->snt_isn = isn; - if (__tcp_v4_send_synack(sk, dst, req, - (struct request_values *)&tmp_ext) || + if (tcp_v4_send_synack(sk, dst, req, + (struct request_values *)&tmp_ext) || want_cookie) goto drop_and_free; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 8816a20c2597..de7d1bf9114f 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -474,6 +474,12 @@ static void tcp_synack_timer(struct sock *sk) TCP_TIMEOUT_INIT, TCP_RTO_MAX); } +void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req) +{ + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS); +} +EXPORT_SYMBOL(tcp_syn_ack_timeout); + void tcp_set_keepalive(struct sock *sk, int val) { if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1c832bf198b3..82f2dea0e39e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -520,6 +520,13 @@ done: return err; } +static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, + struct request_values *rvp) +{ + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); + return tcp_v6_send_synack(sk, req, rvp); +} + static inline void syn_flood_warning(struct sk_buff *skb) { #ifdef CONFIG_SYN_COOKIES @@ -890,10 +897,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), - .rtx_syn_ack = tcp_v6_send_synack, + .rtx_syn_ack = tcp_v6_rtx_synack, .send_ack = tcp_v6_reqsk_send_ack, .destructor = tcp_v6_reqsk_destructor, - .send_reset = tcp_v6_send_reset + .send_reset = tcp_v6_send_reset, + .syn_ack_timeout = tcp_syn_ack_timeout, }; #ifdef CONFIG_TCP_MD5SIG -- GitLab From 2c8c1e7297e19bdef3c178c3ea41d898a7716e3e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 17 Jan 2010 03:35:32 +0000 Subject: [PATCH 0845/3892] net: spread __net_init, __net_exit __net_init/__net_exit are apparently not going away, so use them to full extent. In some cases __net_init was removed, because it was called from __net_exit code. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 12 ++++++------ net/8021q/vlan.c | 4 ++-- net/8021q/vlanproc.c | 2 +- net/bridge/br_if.c | 2 +- net/core/fib_rules.c | 2 +- net/core/rtnetlink.c | 4 ++-- net/core/sock.c | 4 ++-- net/dccp/ipv4.c | 4 ++-- net/dccp/ipv6.c | 4 ++-- net/ipv4/fib_frontend.c | 4 ++-- net/ipv4/igmp.c | 4 ++-- net/ipv4/ip_fragment.c | 8 ++++---- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ipip.c | 7 +++---- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/udp.c | 4 ++-- net/ipv4/udplite.c | 4 ++-- net/ipv6/addrconf.c | 8 ++++---- net/ipv6/af_inet6.c | 4 ++-- net/ipv6/anycast.c | 2 +- net/ipv6/fib6_rules.c | 4 ++-- net/ipv6/icmp.c | 2 +- net/ipv6/ip6_fib.c | 6 +++--- net/ipv6/ip6_flowlabel.c | 9 ++++----- net/ipv6/ip6_tunnel.c | 9 ++++----- net/ipv6/mcast.c | 13 ++++++------- net/ipv6/ndisc.c | 4 ++-- net/ipv6/proc.c | 4 ++-- net/ipv6/raw.c | 4 ++-- net/ipv6/reassembly.c | 8 ++++---- net/ipv6/route.c | 6 +++--- net/ipv6/sit.c | 9 ++++----- net/ipv6/sysctl_net_ipv6.c | 4 ++-- net/ipv6/tcp_ipv6.c | 8 ++++---- net/ipv6/udp.c | 2 +- net/ipv6/udplite.c | 4 ++-- net/key/af_key.c | 6 +++--- net/packet/af_packet.c | 4 ++-- net/phonet/pn_dev.c | 4 ++-- net/sysctl_net.c | 4 ++-- net/unix/af_unix.c | 4 ++-- net/unix/sysctl_net_unix.c | 2 +- net/wireless/wext-proc.c | 4 ++-- net/xfrm/xfrm_sysctl.c | 4 ++-- 44 files changed, 107 insertions(+), 112 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6a42a1453afa..99a0ff3889ee 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3307,7 +3307,7 @@ static void bond_remove_proc_entry(struct bonding *bond) /* Create the bonding directory under /proc/net, if doesn't exist yet. * Caller must hold rtnl_lock. */ -static void bond_create_proc_dir(struct bond_net *bn) +static void __net_init bond_create_proc_dir(struct bond_net *bn) { if (!bn->proc_dir) { bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net); @@ -3320,7 +3320,7 @@ static void bond_create_proc_dir(struct bond_net *bn) /* Destroy the bonding directory under /proc/net, if empty. * Caller must hold rtnl_lock. */ -static void bond_destroy_proc_dir(struct bond_net *bn) +static void __net_exit bond_destroy_proc_dir(struct bond_net *bn) { if (bn->proc_dir) { remove_proc_entry(DRV_NAME, bn->net->proc_net); @@ -3338,11 +3338,11 @@ static void bond_remove_proc_entry(struct bonding *bond) { } -static void bond_create_proc_dir(struct bond_net *bn) +static inline void bond_create_proc_dir(struct bond_net *bn) { } -static void bond_destroy_proc_dir(struct bond_net *bn) +static inline void bond_destroy_proc_dir(struct bond_net *bn) { } @@ -4955,7 +4955,7 @@ out_netdev: goto out; } -static int bond_net_init(struct net *net) +static int __net_init bond_net_init(struct net *net) { struct bond_net *bn = net_generic(net, bond_net_id); @@ -4967,7 +4967,7 @@ static int bond_net_init(struct net *net) return 0; } -static void bond_net_exit(struct net *net) +static void __net_exit bond_net_exit(struct net *net) { struct bond_net *bn = net_generic(net, bond_net_id); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 33f90e7362cc..453512266ea1 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -663,7 +663,7 @@ out: return err; } -static int vlan_init_net(struct net *net) +static int __net_init vlan_init_net(struct net *net) { struct vlan_net *vn = net_generic(net, vlan_net_id); int err; @@ -675,7 +675,7 @@ static int vlan_init_net(struct net *net) return err; } -static void vlan_exit_net(struct net *net) +static void __net_exit vlan_exit_net(struct net *net) { vlan_proc_cleanup(net); } diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 9ec1f057c03a..afead353e215 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -140,7 +140,7 @@ void vlan_proc_cleanup(struct net *net) * Create /proc/net/vlan entries */ -int vlan_proc_init(struct net *net) +int __net_init vlan_proc_init(struct net *net) { struct vlan_net *vn = net_generic(net, vlan_net_id); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index a2cbe61f6e65..7bc0604069c7 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -467,7 +467,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) return 0; } -void br_net_exit(struct net *net) +void __net_exit br_net_exit(struct net *net) { struct net_device *dev; LIST_HEAD(list); diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 02a3b2c69c1e..9a24377146bf 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -708,7 +708,7 @@ static struct notifier_block fib_rules_notifier = { .notifier_call = fib_rules_event, }; -static int fib_rules_net_init(struct net *net) +static int __net_init fib_rules_net_init(struct net *net) { INIT_LIST_HEAD(&net->rules_ops); spin_lock_init(&net->rules_mod_lock); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 794bcb897ff0..62f3878a6010 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1386,7 +1386,7 @@ static struct notifier_block rtnetlink_dev_notifier = { }; -static int rtnetlink_net_init(struct net *net) +static int __net_init rtnetlink_net_init(struct net *net) { struct sock *sk; sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, @@ -1397,7 +1397,7 @@ static int rtnetlink_net_init(struct net *net) return 0; } -static void rtnetlink_net_exit(struct net *net) +static void __net_exit rtnetlink_net_exit(struct net *net) { netlink_kernel_release(net->rtnl); net->rtnl = NULL; diff --git a/net/core/sock.c b/net/core/sock.c index 10b1d3243a72..ceef50bd131b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2140,13 +2140,13 @@ int sock_prot_inuse_get(struct net *net, struct proto *prot) } EXPORT_SYMBOL_GPL(sock_prot_inuse_get); -static int sock_inuse_init_net(struct net *net) +static int __net_init sock_inuse_init_net(struct net *net) { net->core.inuse = alloc_percpu(struct prot_inuse); return net->core.inuse ? 0 : -ENOMEM; } -static void sock_inuse_exit_net(struct net *net) +static void __net_exit sock_inuse_exit_net(struct net *net) { free_percpu(net->core.inuse); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index dad7bc4878e0..b195c4feaa0a 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -996,7 +996,7 @@ static struct inet_protosw dccp_v4_protosw = { .flags = INET_PROTOSW_ICSK, }; -static int dccp_v4_init_net(struct net *net) +static int __net_init dccp_v4_init_net(struct net *net) { int err; @@ -1005,7 +1005,7 @@ static int dccp_v4_init_net(struct net *net) return err; } -static void dccp_v4_exit_net(struct net *net) +static void __net_exit dccp_v4_exit_net(struct net *net) { inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index baf05cf43c28..1aec6349e858 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1189,7 +1189,7 @@ static struct inet_protosw dccp_v6_protosw = { .flags = INET_PROTOSW_ICSK, }; -static int dccp_v6_init_net(struct net *net) +static int __net_init dccp_v6_init_net(struct net *net) { int err; @@ -1198,7 +1198,7 @@ static int dccp_v6_init_net(struct net *net) return err; } -static void dccp_v6_exit_net(struct net *net) +static void __net_exit dccp_v6_exit_net(struct net *net) { inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 82dbf711d6d0..9b3e28ed5240 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -883,7 +883,7 @@ static void nl_fib_input(struct sk_buff *skb) netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT); } -static int nl_fib_lookup_init(struct net *net) +static int __net_init nl_fib_lookup_init(struct net *net) { struct sock *sk; sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, @@ -1004,7 +1004,7 @@ fail: return err; } -static void __net_exit ip_fib_net_exit(struct net *net) +static void ip_fib_net_exit(struct net *net) { unsigned int i; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 76c08402c933..8f5468393f01 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2603,7 +2603,7 @@ static const struct file_operations igmp_mcf_seq_fops = { .release = seq_release_net, }; -static int igmp_net_init(struct net *net) +static int __net_init igmp_net_init(struct net *net) { struct proc_dir_entry *pde; @@ -2621,7 +2621,7 @@ out_igmp: return -ENOMEM; } -static void igmp_net_exit(struct net *net) +static void __net_exit igmp_net_exit(struct net *net) { proc_net_remove(net, "mcfilter"); proc_net_remove(net, "igmp"); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 86964b353c31..891c72aea520 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -646,7 +646,7 @@ static struct ctl_table ip4_frags_ctl_table[] = { { } }; -static int ip4_frags_ns_ctl_register(struct net *net) +static int __net_init ip4_frags_ns_ctl_register(struct net *net) { struct ctl_table *table; struct ctl_table_header *hdr; @@ -676,7 +676,7 @@ err_alloc: return -ENOMEM; } -static void ip4_frags_ns_ctl_unregister(struct net *net) +static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net) { struct ctl_table *table; @@ -704,7 +704,7 @@ static inline void ip4_frags_ctl_register(void) } #endif -static int ipv4_frags_init_net(struct net *net) +static int __net_init ipv4_frags_init_net(struct net *net) { /* * Fragment cache limits. We will commit 256K at one time. Should we @@ -726,7 +726,7 @@ static int ipv4_frags_init_net(struct net *net) return ip4_frags_ns_ctl_register(net); } -static void ipv4_frags_exit_net(struct net *net) +static void __net_exit ipv4_frags_exit_net(struct net *net) { ip4_frags_ns_ctl_unregister(net); inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f36ce156cac6..7631b20490f5 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1307,7 +1307,7 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head) } } -static int ipgre_init_net(struct net *net) +static int __net_init ipgre_init_net(struct net *net) { struct ipgre_net *ign = net_generic(net, ipgre_net_id); int err; @@ -1334,7 +1334,7 @@ err_alloc_dev: return err; } -static void ipgre_exit_net(struct net *net) +static void __net_exit ipgre_exit_net(struct net *net) { struct ipgre_net *ign; LIST_HEAD(list); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index eda04fed3379..95db732e542b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -130,7 +130,6 @@ struct ipip_net { struct net_device *fb_tunnel_dev; }; -static void ipip_fb_tunnel_init(struct net_device *dev); static void ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); @@ -730,7 +729,7 @@ static void ipip_tunnel_init(struct net_device *dev) ipip_tunnel_bind_dev(dev); } -static void ipip_fb_tunnel_init(struct net_device *dev) +static void __net_init ipip_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -773,7 +772,7 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) } } -static int ipip_init_net(struct net *net) +static int __net_init ipip_init_net(struct net *net) { struct ipip_net *ipn = net_generic(net, ipip_net_id); int err; @@ -806,7 +805,7 @@ err_alloc_dev: return err; } -static void ipip_exit_net(struct net *net) +static void __net_exit ipip_exit_net(struct net *net) { struct ipip_net *ipn = net_generic(net, ipip_net_id); LIST_HEAD(list); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 356f544c4c10..c3588b4fd979 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2430,12 +2430,12 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = { }, }; -static int tcp4_proc_init_net(struct net *net) +static int __net_init tcp4_proc_init_net(struct net *net) { return tcp_proc_register(net, &tcp4_seq_afinfo); } -static void tcp4_proc_exit_net(struct net *net) +static void __net_exit tcp4_proc_exit_net(struct net *net) { tcp_proc_unregister(net, &tcp4_seq_afinfo); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f0126fdd7e04..4f7d2122d818 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2027,12 +2027,12 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { }, }; -static int udp4_proc_init_net(struct net *net) +static int __net_init udp4_proc_init_net(struct net *net) { return udp_proc_register(net, &udp4_seq_afinfo); } -static void udp4_proc_exit_net(struct net *net) +static void __net_exit udp4_proc_exit_net(struct net *net) { udp_proc_unregister(net, &udp4_seq_afinfo); } diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 66f79513f4a5..6610bf76369f 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -81,12 +81,12 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = { }, }; -static int udplite4_proc_init_net(struct net *net) +static int __net_init udplite4_proc_init_net(struct net *net) { return udp_proc_register(net, &udplite4_seq_afinfo); } -static void udplite4_proc_exit_net(struct net *net) +static void __net_exit udplite4_proc_exit_net(struct net *net) { udp_proc_unregister(net, &udplite4_seq_afinfo); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index de7a194a64ab..1593289155ff 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3027,14 +3027,14 @@ static const struct file_operations if6_fops = { .release = seq_release_net, }; -static int if6_proc_net_init(struct net *net) +static int __net_init if6_proc_net_init(struct net *net) { if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) return -ENOMEM; return 0; } -static void if6_proc_net_exit(struct net *net) +static void __net_exit if6_proc_net_exit(struct net *net) { proc_net_remove(net, "if_inet6"); } @@ -4418,7 +4418,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) #endif -static int addrconf_init_net(struct net *net) +static int __net_init addrconf_init_net(struct net *net) { int err; struct ipv6_devconf *all, *dflt; @@ -4467,7 +4467,7 @@ err_alloc_all: return err; } -static void addrconf_exit_net(struct net *net) +static void __net_exit addrconf_exit_net(struct net *net) { #ifdef CONFIG_SYSCTL __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 12e69d364dd5..e29160ff4a0f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -999,7 +999,7 @@ err_udplite_mib: return -ENOMEM; } -static void __net_exit ipv6_cleanup_mibs(struct net *net) +static void ipv6_cleanup_mibs(struct net *net) { snmp_mib_free((void **)net->mib.udp_stats_in6); snmp_mib_free((void **)net->mib.udplite_stats_in6); @@ -1042,7 +1042,7 @@ out: #endif } -static void inet6_net_exit(struct net *net) +static void __net_exit inet6_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS udp6_proc_exit(net); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f1c74c8ef9de..c4f6ca32fa74 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -538,7 +538,7 @@ static const struct file_operations ac6_seq_fops = { .release = seq_release_net, }; -int ac6_proc_init(struct net *net) +int __net_init ac6_proc_init(struct net *net) { if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) return -ENOMEM; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b7aa7c64cc4a..551882b9dfd6 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -262,7 +262,7 @@ static struct fib_rules_ops fib6_rules_ops_template = { .fro_net = &init_net, }; -static int fib6_rules_net_init(struct net *net) +static int __net_init fib6_rules_net_init(struct net *net) { struct fib_rules_ops *ops; int err = -ENOMEM; @@ -291,7 +291,7 @@ out_fib6_rules_ops: goto out; } -static void fib6_rules_net_exit(struct net *net) +static void __net_exit fib6_rules_net_exit(struct net *net) { fib_rules_unregister(net->ipv6.fib6_rules_ops); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 4ae661bc3677..217dbc2e28d4 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -951,7 +951,7 @@ ctl_table ipv6_icmp_table_template[] = { { }, }; -struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) +struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) { struct ctl_table *table; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0e93ca56eb69..f626ea2b304f 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -239,7 +239,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) return NULL; } -static void fib6_tables_init(struct net *net) +static void __net_init fib6_tables_init(struct net *net) { fib6_link_table(net, net->ipv6.fib6_main_tbl); fib6_link_table(net, net->ipv6.fib6_local_tbl); @@ -262,7 +262,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); } -static void fib6_tables_init(struct net *net) +static void __net_init fib6_tables_init(struct net *net) { fib6_link_table(net, net->ipv6.fib6_main_tbl); } @@ -1469,7 +1469,7 @@ static void fib6_gc_timer_cb(unsigned long arg) fib6_run_gc(0, (struct net *)arg); } -static int fib6_net_init(struct net *net) +static int __net_init fib6_net_init(struct net *net) { setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 6e7bffa2205e..e41eba8aacf1 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -154,7 +154,7 @@ static void ip6_fl_gc(unsigned long dummy) write_unlock(&ip6_fl_lock); } -static void ip6_fl_purge(struct net *net) +static void __net_exit ip6_fl_purge(struct net *net) { int i; @@ -735,7 +735,7 @@ static const struct file_operations ip6fl_seq_fops = { .release = seq_release_net, }; -static int ip6_flowlabel_proc_init(struct net *net) +static int __net_init ip6_flowlabel_proc_init(struct net *net) { if (!proc_net_fops_create(net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops)) @@ -743,7 +743,7 @@ static int ip6_flowlabel_proc_init(struct net *net) return 0; } -static void ip6_flowlabel_proc_fini(struct net *net) +static void __net_exit ip6_flowlabel_proc_fini(struct net *net) { proc_net_remove(net, "ip6_flowlabel"); } @@ -754,11 +754,10 @@ static inline int ip6_flowlabel_proc_init(struct net *net) } static inline void ip6_flowlabel_proc_fini(struct net *net) { - return ; } #endif -static inline void ip6_flowlabel_net_exit(struct net *net) +static void __net_exit ip6_flowlabel_net_exit(struct net *net) { ip6_fl_purge(net); ip6_flowlabel_proc_fini(net); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d453d07b0dfe..fbd786981aa9 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -74,7 +74,6 @@ MODULE_LICENSE("GPL"); (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ (HASH_SIZE - 1)) -static void ip6_fb_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_setup(struct net_device *dev); @@ -1364,7 +1363,7 @@ static void ip6_tnl_dev_init(struct net_device *dev) * Return: 0 **/ -static void ip6_fb_tnl_dev_init(struct net_device *dev) +static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); struct net *net = dev_net(dev); @@ -1388,7 +1387,7 @@ static struct xfrm6_tunnel ip6ip6_handler = { .priority = 1, }; -static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) +static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) { int h; struct ip6_tnl *t; @@ -1407,7 +1406,7 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) unregister_netdevice_many(&list); } -static int ip6_tnl_init_net(struct net *net) +static int __net_init ip6_tnl_init_net(struct net *net) { struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); int err; @@ -1436,7 +1435,7 @@ err_alloc_dev: return err; } -static void ip6_tnl_exit_net(struct net *net) +static void __net_exit ip6_tnl_exit_net(struct net *net) { struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 1f9c44442e65..25f6cca79e6b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2646,7 +2646,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { .release = seq_release_net, }; -static int igmp6_proc_init(struct net *net) +static int __net_init igmp6_proc_init(struct net *net) { int err; @@ -2666,23 +2666,22 @@ out_proc_net_igmp6: goto out; } -static void igmp6_proc_exit(struct net *net) +static void __net_exit igmp6_proc_exit(struct net *net) { proc_net_remove(net, "mcfilter6"); proc_net_remove(net, "igmp6"); } #else -static int igmp6_proc_init(struct net *net) +static inline int igmp6_proc_init(struct net *net) { return 0; } -static void igmp6_proc_exit(struct net *net) +static inline void igmp6_proc_exit(struct net *net) { - ; } #endif -static int igmp6_net_init(struct net *net) +static int __net_init igmp6_net_init(struct net *net) { int err; @@ -2708,7 +2707,7 @@ out_sock_create: goto out; } -static void igmp6_net_exit(struct net *net) +static void __net_exit igmp6_net_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv6.igmp_sk); igmp6_proc_exit(net); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c45852798092..2dfec6bb8ada 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1772,7 +1772,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu #endif -static int ndisc_net_init(struct net *net) +static int __net_init ndisc_net_init(struct net *net) { struct ipv6_pinfo *np; struct sock *sk; @@ -1797,7 +1797,7 @@ static int ndisc_net_init(struct net *net) return 0; } -static void ndisc_net_exit(struct net *net) +static void __net_exit ndisc_net_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv6.ndisc_sk); } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 7b197b7132e0..02f20016b4c9 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -267,7 +267,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) return 0; } -static int ipv6_proc_init_net(struct net *net) +static int __net_init ipv6_proc_init_net(struct net *net) { if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, &sockstat6_seq_fops)) @@ -288,7 +288,7 @@ proc_dev_snmp6_fail: return -ENOMEM; } -static void ipv6_proc_exit_net(struct net *net) +static void __net_exit ipv6_proc_exit_net(struct net *net) { proc_net_remove(net, "sockstat6"); proc_net_remove(net, "dev_snmp6"); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 926ce8eeffaf..ed31c37c6e39 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1275,7 +1275,7 @@ static const struct file_operations raw6_seq_fops = { .release = seq_release_net, }; -static int raw6_init_net(struct net *net) +static int __net_init raw6_init_net(struct net *net) { if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) return -ENOMEM; @@ -1283,7 +1283,7 @@ static int raw6_init_net(struct net *net) return 0; } -static void raw6_exit_net(struct net *net) +static void __net_exit raw6_exit_net(struct net *net) { proc_net_remove(net, "raw6"); } diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2cddea3bd6be..fa38fc7cc6e9 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -672,7 +672,7 @@ static struct ctl_table ip6_frags_ctl_table[] = { { } }; -static int ip6_frags_ns_sysctl_register(struct net *net) +static int __net_init ip6_frags_ns_sysctl_register(struct net *net) { struct ctl_table *table; struct ctl_table_header *hdr; @@ -702,7 +702,7 @@ err_alloc: return -ENOMEM; } -static void ip6_frags_ns_sysctl_unregister(struct net *net) +static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net) { struct ctl_table *table; @@ -745,7 +745,7 @@ static inline void ip6_frags_sysctl_unregister(void) } #endif -static int ipv6_frags_init_net(struct net *net) +static int __net_init ipv6_frags_init_net(struct net *net) { net->ipv6.frags.high_thresh = 256 * 1024; net->ipv6.frags.low_thresh = 192 * 1024; @@ -756,7 +756,7 @@ static int ipv6_frags_init_net(struct net *net) return ip6_frags_ns_sysctl_register(net); } -static void ipv6_frags_exit_net(struct net *net) +static void __net_exit ipv6_frags_exit_net(struct net *net) { ip6_frags_ns_sysctl_unregister(net); inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c2bd74c5f8d9..8500156f2637 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2612,7 +2612,7 @@ ctl_table ipv6_route_table_template[] = { { } }; -struct ctl_table *ipv6_route_sysctl_init(struct net *net) +struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) { struct ctl_table *table; @@ -2637,7 +2637,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) } #endif -static int ip6_route_net_init(struct net *net) +static int __net_init ip6_route_net_init(struct net *net) { int ret = -ENOMEM; @@ -2702,7 +2702,7 @@ out_ip6_dst_ops: goto out; } -static void ip6_route_net_exit(struct net *net) +static void __net_exit ip6_route_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS proc_net_remove(net, "ipv6_route"); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 976e68244b99..10207cc8cc0e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -62,7 +62,6 @@ #define HASH_SIZE 16 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) -static void ipip6_fb_tunnel_init(struct net_device *dev); static void ipip6_tunnel_init(struct net_device *dev); static void ipip6_tunnel_setup(struct net_device *dev); @@ -1120,7 +1119,7 @@ static void ipip6_tunnel_init(struct net_device *dev) ipip6_tunnel_bind_dev(dev); } -static void ipip6_fb_tunnel_init(struct net_device *dev) +static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -1145,7 +1144,7 @@ static struct xfrm_tunnel sit_handler = { .priority = 1, }; -static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) +static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) { int prio; @@ -1162,7 +1161,7 @@ static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) } } -static int sit_init_net(struct net *net) +static int __net_init sit_init_net(struct net *net) { struct sit_net *sitn = net_generic(net, sit_net_id); int err; @@ -1195,7 +1194,7 @@ err_alloc_dev: return err; } -static void sit_exit_net(struct net *net) +static void __net_exit sit_exit_net(struct net *net) { struct sit_net *sitn = net_generic(net, sit_net_id); LIST_HEAD(list); diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index c690736885b4..f841d93bf987 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -55,7 +55,7 @@ struct ctl_path net_ipv6_ctl_path[] = { }; EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); -static int ipv6_sysctl_net_init(struct net *net) +static int __net_init ipv6_sysctl_net_init(struct net *net) { struct ctl_table *ipv6_table; struct ctl_table *ipv6_route_table; @@ -98,7 +98,7 @@ out_ipv6_table: goto out; } -static void ipv6_sysctl_net_exit(struct net *net) +static void __net_exit ipv6_sysctl_net_exit(struct net *net) { struct ctl_table *ipv6_table; struct ctl_table *ipv6_route_table; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 82f2dea0e39e..6963a6b6763e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2113,7 +2113,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { }, }; -int tcp6_proc_init(struct net *net) +int __net_init tcp6_proc_init(struct net *net) { return tcp_proc_register(net, &tcp6_seq_afinfo); } @@ -2182,18 +2182,18 @@ static struct inet_protosw tcpv6_protosw = { INET_PROTOSW_ICSK, }; -static int tcpv6_net_init(struct net *net) +static int __net_init tcpv6_net_init(struct net *net) { return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, SOCK_RAW, IPPROTO_TCP, net); } -static void tcpv6_net_exit(struct net *net) +static void __net_exit tcpv6_net_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv6.tcp_sk); } -static void tcpv6_net_exit_batch(struct list_head *net_exit_list) +static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) { inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 69ebdbe78c47..34efb3589ffa 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1396,7 +1396,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { }, }; -int udp6_proc_init(struct net *net) +int __net_init udp6_proc_init(struct net *net) { return udp_proc_register(net, &udp6_seq_afinfo); } diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 6ea6938919e6..5f48fadc27f7 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -104,12 +104,12 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { }, }; -static int udplite6_proc_init_net(struct net *net) +static int __net_init udplite6_proc_init_net(struct net *net) { return udp_proc_register(net, &udplite6_seq_afinfo); } -static void udplite6_proc_exit_net(struct net *net) +static void __net_exit udplite6_proc_exit_net(struct net *net) { udp_proc_unregister(net, &udplite6_seq_afinfo); } diff --git a/net/key/af_key.c b/net/key/af_key.c index 76fa6fef6473..4744b1f6372f 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3738,17 +3738,17 @@ static int __net_init pfkey_init_proc(struct net *net) return 0; } -static void pfkey_exit_proc(struct net *net) +static void __net_exit pfkey_exit_proc(struct net *net) { proc_net_remove(net, "pfkey"); } #else -static int __net_init pfkey_init_proc(struct net *net) +static inline int pfkey_init_proc(struct net *net) { return 0; } -static void pfkey_exit_proc(struct net *net) +static inline void pfkey_exit_proc(struct net *net) { } #endif diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e0516a22be2e..a97acfe7e770 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2448,7 +2448,7 @@ static const struct file_operations packet_seq_fops = { #endif -static int packet_net_init(struct net *net) +static int __net_init packet_net_init(struct net *net) { rwlock_init(&net->packet.sklist_lock); INIT_HLIST_HEAD(&net->packet.sklist); @@ -2459,7 +2459,7 @@ static int packet_net_init(struct net *net) return 0; } -static void packet_net_exit(struct net *net) +static void __net_exit packet_net_exit(struct net *net) { proc_net_remove(net, "packet"); } diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index bc4a33bf2d3d..c597cc53a6fb 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -311,7 +311,7 @@ static struct notifier_block phonet_device_notifier = { }; /* Per-namespace Phonet devices handling */ -static int phonet_init_net(struct net *net) +static int __net_init phonet_init_net(struct net *net) { struct phonet_net *pnn = net_generic(net, phonet_net_id); @@ -324,7 +324,7 @@ static int phonet_init_net(struct net *net) return 0; } -static void phonet_exit_net(struct net *net) +static void __net_exit phonet_exit_net(struct net *net) { struct phonet_net *pnn = net_generic(net, phonet_net_id); struct net_device *dev; diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 0b15d7250c40..53196009160a 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -71,7 +71,7 @@ static struct ctl_table_root net_sysctl_ro_root = { .permissions = net_ctl_ro_header_perms, }; -static int sysctl_net_init(struct net *net) +static int __net_init sysctl_net_init(struct net *net) { setup_sysctl_set(&net->sysctls, &net_sysctl_ro_root.default_set, @@ -79,7 +79,7 @@ static int sysctl_net_init(struct net *net) return 0; } -static void sysctl_net_exit(struct net *net) +static void __net_exit sysctl_net_exit(struct net *net) { WARN_ON(!list_empty(&net->sysctls.list)); return; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f25511903115..9bc9b92bc099 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2224,7 +2224,7 @@ static const struct net_proto_family unix_family_ops = { }; -static int unix_net_init(struct net *net) +static int __net_init unix_net_init(struct net *net) { int error = -ENOMEM; @@ -2243,7 +2243,7 @@ out: return error; } -static void unix_net_exit(struct net *net) +static void __net_exit unix_net_exit(struct net *net) { unix_sysctl_unregister(net); proc_net_remove(net, "unix"); diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 708f5df6b7f0..d095c7be10d0 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -31,7 +31,7 @@ static struct ctl_path unix_path[] = { { }, }; -int unix_sysctl_register(struct net *net) +int __net_init unix_sysctl_register(struct net *net) { struct ctl_table *table; diff --git a/net/wireless/wext-proc.c b/net/wireless/wext-proc.c index 273a7f77c834..8bafa31fa9f8 100644 --- a/net/wireless/wext-proc.c +++ b/net/wireless/wext-proc.c @@ -140,7 +140,7 @@ static const struct file_operations wireless_seq_fops = { .release = seq_release_net, }; -int wext_proc_init(struct net *net) +int __net_init wext_proc_init(struct net *net) { /* Create /proc/net/wireless entry */ if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) @@ -149,7 +149,7 @@ int wext_proc_init(struct net *net) return 0; } -void wext_proc_exit(struct net *net) +void __net_exit wext_proc_exit(struct net *net) { proc_net_remove(net, "wireless"); } diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c index 2e221f2cad7e..2c4d6cdcba49 100644 --- a/net/xfrm/xfrm_sysctl.c +++ b/net/xfrm/xfrm_sysctl.c @@ -2,7 +2,7 @@ #include #include -static void __xfrm_sysctl_init(struct net *net) +static void __net_init __xfrm_sysctl_init(struct net *net) { net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME; net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE; @@ -64,7 +64,7 @@ out_kmemdup: return -ENOMEM; } -void xfrm_sysctl_fini(struct net *net) +void __net_exit xfrm_sysctl_fini(struct net *net) { struct ctl_table *table; -- GitLab From a47430583dab67b23161b0e75226781deed50138 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 17 Jan 2010 07:30:43 +0000 Subject: [PATCH 0846/3892] bnx2: Refine statistics code. Refine the statistics macros by passing in just the name of the counter field. This makes it a lot easier and cleaner to add counters saved before the last reset in the next patch. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 62 ++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b1c20e5f7de8..47fb5086cf56 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6542,92 +6542,94 @@ bnx2_close(struct net_device *dev) return 0; } -#define GET_NET_STATS64(ctr) \ +#define GET_64BIT_NET_STATS64(ctr) \ (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \ (unsigned long) (ctr##_lo) -#define GET_NET_STATS32(ctr) \ +#define GET_64BIT_NET_STATS32(ctr) \ (ctr##_lo) #if (BITS_PER_LONG == 64) -#define GET_NET_STATS GET_NET_STATS64 +#define GET_64BIT_NET_STATS(ctr) \ + GET_64BIT_NET_STATS64(bp->stats_blk->ctr) #else -#define GET_NET_STATS GET_NET_STATS32 +#define GET_64BIT_NET_STATS(ctr) \ + GET_64BIT_NET_STATS32(bp->stats_blk->ctr) #endif +#define GET_32BIT_NET_STATS(ctr) \ + (unsigned long) (bp->stats_blk->ctr) + static struct net_device_stats * bnx2_get_stats(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); - struct statistics_block *stats_blk = bp->stats_blk; struct net_device_stats *net_stats = &dev->stats; if (bp->stats_blk == NULL) { return net_stats; } net_stats->rx_packets = - GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) + - GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) + - GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts); + GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) + + GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) + + GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts); net_stats->tx_packets = - GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) + - GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) + - GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts); + GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) + + GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) + + GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts); net_stats->rx_bytes = - GET_NET_STATS(stats_blk->stat_IfHCInOctets); + GET_64BIT_NET_STATS(stat_IfHCInOctets); net_stats->tx_bytes = - GET_NET_STATS(stats_blk->stat_IfHCOutOctets); + GET_64BIT_NET_STATS(stat_IfHCOutOctets); net_stats->multicast = - GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts); + GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts); net_stats->collisions = - (unsigned long) stats_blk->stat_EtherStatsCollisions; + GET_32BIT_NET_STATS(stat_EtherStatsCollisions); net_stats->rx_length_errors = - (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts + - stats_blk->stat_EtherStatsOverrsizePkts); + GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) + + GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts); net_stats->rx_over_errors = - (unsigned long) (stats_blk->stat_IfInFTQDiscards + - stats_blk->stat_IfInMBUFDiscards); + GET_32BIT_NET_STATS(stat_IfInFTQDiscards) + + GET_32BIT_NET_STATS(stat_IfInMBUFDiscards); net_stats->rx_frame_errors = - (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors; + GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors); net_stats->rx_crc_errors = - (unsigned long) stats_blk->stat_Dot3StatsFCSErrors; + GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors); net_stats->rx_errors = net_stats->rx_length_errors + net_stats->rx_over_errors + net_stats->rx_frame_errors + net_stats->rx_crc_errors; net_stats->tx_aborted_errors = - (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions + - stats_blk->stat_Dot3StatsLateCollisions); + GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) + + GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions); if ((CHIP_NUM(bp) == CHIP_NUM_5706) || (CHIP_ID(bp) == CHIP_ID_5708_A0)) net_stats->tx_carrier_errors = 0; else { net_stats->tx_carrier_errors = - (unsigned long) - stats_blk->stat_Dot3StatsCarrierSenseErrors; + GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors); } net_stats->tx_errors = - (unsigned long) - stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors - + + GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) + net_stats->tx_aborted_errors + net_stats->tx_carrier_errors; net_stats->rx_missed_errors = - (unsigned long) (stats_blk->stat_IfInFTQDiscards + - stats_blk->stat_IfInMBUFDiscards + stats_blk->stat_FwRxDrop); + GET_32BIT_NET_STATS(stat_IfInFTQDiscards) + + GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) + + GET_32BIT_NET_STATS(stat_FwRxDrop); return net_stats; } -- GitLab From 354fcd7774a00809ebefdba75e747364cb22a940 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 17 Jan 2010 07:30:44 +0000 Subject: [PATCH 0847/3892] bnx2: Save statistics during reset. MTU changes, ring size changes, etc cause the chip to be reset and the statisctics flushed. To keep track of the accumulated statistics, we add code to save the whole statistics block before reset. We also modify the macros and statistics functions to return the sum of the saved and current counters. Based on original patch by Breno Leitao Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 64 ++++++++++++++++++++++++++++++++++++++++------ drivers/net/bnx2.h | 1 + 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 47fb5086cf56..d83512d3e02f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6231,6 +6231,8 @@ bnx2_open(struct net_device *dev) atomic_set(&bp->intr_sem, 0); + memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block)); + bnx2_enable_int(bp); if (bp->flags & BNX2_FLAG_USING_MSI) { @@ -6542,6 +6544,30 @@ bnx2_close(struct net_device *dev) return 0; } +static void +bnx2_save_stats(struct bnx2 *bp) +{ + u32 *hw_stats = (u32 *) bp->stats_blk; + u32 *temp_stats = (u32 *) bp->temp_stats_blk; + int i; + + /* The 1st 10 counters are 64-bit counters */ + for (i = 0; i < 20; i += 2) { + u32 hi; + u64 lo; + + hi = *(temp_stats + i) + *(hw_stats + i); + lo = *(temp_stats + i + 1) + *(hw_stats + i + 1); + if (lo > 0xffffffff) + hi++; + *(temp_stats + i) = hi; + *(temp_stats + i + 1) = lo & 0xffffffff; + } + + for ( ; i < sizeof(struct statistics_block) / 4; i++) + *(temp_stats + i) = *(temp_stats + i) + *(hw_stats + i); +} + #define GET_64BIT_NET_STATS64(ctr) \ (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \ (unsigned long) (ctr##_lo) @@ -6551,14 +6577,17 @@ bnx2_close(struct net_device *dev) #if (BITS_PER_LONG == 64) #define GET_64BIT_NET_STATS(ctr) \ - GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \ + GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr) #else #define GET_64BIT_NET_STATS(ctr) \ - GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \ + GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr) #endif #define GET_32BIT_NET_STATS(ctr) \ - (unsigned long) (bp->stats_blk->ctr) + (unsigned long) (bp->stats_blk->ctr + \ + bp->temp_stats_blk->ctr) static struct net_device_stats * bnx2_get_stats(struct net_device *dev) @@ -7089,6 +7118,9 @@ static int bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) { if (netif_running(bp->dev)) { + /* Reset will erase chipset stats; save them */ + bnx2_save_stats(bp); + bnx2_netif_stop(bp); bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); bnx2_free_skbs(bp); @@ -7433,6 +7465,7 @@ bnx2_get_ethtool_stats(struct net_device *dev, struct bnx2 *bp = netdev_priv(dev); int i; u32 *hw_stats = (u32 *) bp->stats_blk; + u32 *temp_stats = (u32 *) bp->temp_stats_blk; u8 *stats_len_arr = NULL; if (hw_stats == NULL) { @@ -7449,21 +7482,26 @@ bnx2_get_ethtool_stats(struct net_device *dev, stats_len_arr = bnx2_5708_stats_len_arr; for (i = 0; i < BNX2_NUM_STATS; i++) { + unsigned long offset; + if (stats_len_arr[i] == 0) { /* skip this counter */ buf[i] = 0; continue; } + + offset = bnx2_stats_offset_arr[i]; if (stats_len_arr[i] == 4) { /* 4-byte counter */ - buf[i] = (u64) - *(hw_stats + bnx2_stats_offset_arr[i]); + buf[i] = (u64) *(hw_stats + offset) + + *(temp_stats + offset); continue; } /* 8-byte counter */ - buf[i] = (((u64) *(hw_stats + - bnx2_stats_offset_arr[i])) << 32) + - *(hw_stats + bnx2_stats_offset_arr[i] + 1); + buf[i] = (((u64) *(hw_stats + offset)) << 32) + + *(hw_stats + offset + 1) + + (((u64) *(temp_stats + offset)) << 32) + + *(temp_stats + offset + 1); } } @@ -7831,6 +7869,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->flags = 0; bp->phy_flags = 0; + bp->temp_stats_blk = + kzalloc(sizeof(struct statistics_block), GFP_KERNEL); + + if (bp->temp_stats_blk == NULL) { + rc = -ENOMEM; + goto err_out; + } + /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device(pdev); if (rc) { @@ -8352,6 +8398,8 @@ bnx2_remove_one(struct pci_dev *pdev) if (bp->regview) iounmap(bp->regview); + kfree(bp->temp_stats_blk); + free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 939dc44d50a0..b860fbbff355 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6851,6 +6851,7 @@ struct bnx2 { dma_addr_t status_blk_mapping; struct statistics_block *stats_blk; + struct statistics_block *temp_stats_blk; dma_addr_t stats_blk_mapping; int ctx_pages; -- GitLab From 4126faf0ab7417fbc6eb99fb0fd407e01e9e9dfe Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 17 Jan 2010 10:24:07 -0800 Subject: [PATCH 0848/3892] x86: Fix breakage of UML from the changes in the rwsem system The patches 5d0b7235d83eefdafda300656e97d368afcafc9a and bafaecd11df15ad5b1e598adc7736afcd38ee13d broke the UML build: On Sun, 17 Jan 2010, Ingo Molnar wrote: > > FYI, -tip testing found that these changes break the UML build: > > kernel/built-in.o: In function `__up_read': > /home/mingo/tip/arch/x86/include/asm/rwsem.h:192: undefined reference to `call_rwsem_wake' > kernel/built-in.o: In function `__up_write': > /home/mingo/tip/arch/x86/include/asm/rwsem.h:210: undefined reference to `call_rwsem_wake' > kernel/built-in.o: In function `__downgrade_write': > /home/mingo/tip/arch/x86/include/asm/rwsem.h:228: undefined reference to `call_rwsem_downgrade_wake' > kernel/built-in.o: In function `__down_read': > /home/mingo/tip/arch/x86/include/asm/rwsem.h:112: undefined reference to `call_rwsem_down_read_failed' > kernel/built-in.o: In function `__down_write_nested': > /home/mingo/tip/arch/x86/include/asm/rwsem.h:154: undefined reference to `call_rwsem_down_write_failed' > collect2: ld returned 1 exit status Add lib/rwsem_64.o to the UML subarch objects to fix. LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/um/sys-x86_64/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 2201e9c20e4a..c1ea9eb04466 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -8,7 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ sysrq.o ksyms.o tls.o -subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o +subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ + lib/rwsem_64.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o ldt-y = ../sys-i386/ldt.o -- GitLab From 83fc81024bd8572f31db784f8c0079e999a4fa44 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:07:50 +0100 Subject: [PATCH 0849/3892] netfilter: xt_connlimit: netns support Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/xt_connlimit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 8103bef78e44..0d9d18ea2b09 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -90,7 +90,8 @@ same_source_net(const union nf_inet_addr *addr, } } -static int count_them(struct xt_connlimit_data *data, +static int count_them(struct net *net, + struct xt_connlimit_data *data, const struct nf_conntrack_tuple *tuple, const union nf_inet_addr *addr, const union nf_inet_addr *mask, @@ -113,7 +114,7 @@ static int count_them(struct xt_connlimit_data *data, /* check the saved connections */ list_for_each_entry_safe(conn, tmp, hash, list) { - found = nf_conntrack_find_get(&init_net, &conn->tuple); + found = nf_conntrack_find_get(net, &conn->tuple); found_ct = NULL; if (found != NULL) @@ -171,6 +172,7 @@ static int count_them(struct xt_connlimit_data *data, static bool connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) { + struct net *net = dev_net(par->in ? par->in : par->out); const struct xt_connlimit_info *info = par->matchinfo; union nf_inet_addr addr; struct nf_conntrack_tuple tuple; @@ -195,7 +197,7 @@ connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) } spin_lock_bh(&info->data->lock); - connections = count_them(info->data, tuple_ptr, &addr, + connections = count_them(net, info->data, tuple_ptr, &addr, &info->mask, par->family); spin_unlock_bh(&info->data->lock); -- GitLab From e9d3897cc2205eec8b7afcc022e4730914b4f48c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:08:37 +0100 Subject: [PATCH 0850/3892] netfilter: netns: #ifdef ->iptable_security, ->ip6table_security 'security' tables depend on SECURITY, so ifdef them. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/net/netns/ipv4.h | 2 ++ include/net/netns/ipv6.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 2eb3814d6258..8098f6b8319d 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -37,7 +37,9 @@ struct netns_ipv4 { struct xt_table *iptable_mangle; struct xt_table *iptable_raw; struct xt_table *arptable_filter; +#ifdef CONFIG_SECURITY struct xt_table *iptable_security; +#endif struct xt_table *nat_table; struct hlist_head *nat_bysource; int nat_vmalloced; diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index dfeb2d7c425b..1f11ebc22151 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,7 +36,9 @@ struct netns_ipv6 { struct xt_table *ip6table_filter; struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; +#ifdef CONFIG_SECURITY struct xt_table *ip6table_security; +#endif #endif struct rt6_info *ip6_null_entry; struct rt6_statistics *rt6_stats; -- GitLab From a1004d8e3d463012f231bab104325ecb15637f78 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:14:50 +0100 Subject: [PATCH 0851/3892] netfilter: xt_hashlimit: simplify seqfile code Simply pass hashtable to seqfile iterators, proc entry itself is not needed. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 5bdc1fbf3ad7..944fd11c8989 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -841,8 +841,7 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = { static void *dl_seq_start(struct seq_file *s, loff_t *pos) __acquires(htable->lock) { - struct proc_dir_entry *pde = s->private; - struct xt_hashlimit_htable *htable = pde->data; + struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket; spin_lock_bh(&htable->lock); @@ -859,8 +858,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos) static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct proc_dir_entry *pde = s->private; - struct xt_hashlimit_htable *htable = pde->data; + struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket = (unsigned int *)v; *pos = ++(*bucket); @@ -874,8 +872,7 @@ static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) static void dl_seq_stop(struct seq_file *s, void *v) __releases(htable->lock) { - struct proc_dir_entry *pde = s->private; - struct xt_hashlimit_htable *htable = pde->data; + struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket = (unsigned int *)v; kfree(bucket); @@ -917,8 +914,7 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, static int dl_seq_show(struct seq_file *s, void *v) { - struct proc_dir_entry *pde = s->private; - struct xt_hashlimit_htable *htable = pde->data; + struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket = (unsigned int *)v; struct dsthash_ent *ent; struct hlist_node *pos; @@ -944,7 +940,7 @@ static int dl_proc_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *sf = file->private_data; - sf->private = PDE(inode); + sf->private = PDE(inode)->data; } return ret; } -- GitLab From a83d8e8d099fc373a5ca7112ad08c553bb2c180f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:21:13 +0100 Subject: [PATCH 0852/3892] netfilter: xtables: add struct xt_mtchk_param::net Some complex match modules (like xt_hashlimit/xt_recent) want netns information at constructor and destructor time. We propably can play games at match destruction time, because netns can be passed in object, but I think it's cleaner to explicitly pass netns. Add ->net, make sure it's set from ebtables/iptables/ip6tables code. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 1 + net/bridge/netfilter/ebtables.c | 14 +++++++++----- net/ipv4/netfilter/ip_tables.c | 24 ++++++++++++++---------- net/ipv6/netfilter/ip6_tables.c | 14 ++++++++------ 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 378f27ae7772..88261b9829a7 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -205,6 +205,7 @@ struct xt_match_param { * @hook_mask: via which hooks the new rule is reachable */ struct xt_mtchk_param { + struct net *net; const char *table; const void *entryinfo; const struct xt_match *match; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index bd1c65425d4f..c77bab986696 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -619,7 +619,9 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) } static inline int -ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, +ebt_check_entry(struct ebt_entry *e, + struct net *net, + struct ebt_table_info *newinfo, const char *name, unsigned int *cnt, struct ebt_cl_stack *cl_s, unsigned int udc_cnt) { @@ -671,6 +673,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, } i = 0; + mtpar.net = net; mtpar.table = tgpar.table = name; mtpar.entryinfo = tgpar.entryinfo = e; mtpar.hook_mask = tgpar.hook_mask = hookmask; @@ -808,7 +811,8 @@ letscontinue: } /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */ -static int translate_table(char *name, struct ebt_table_info *newinfo) +static int translate_table(struct net *net, char *name, + struct ebt_table_info *newinfo) { unsigned int i, j, k, udc_cnt; int ret; @@ -917,7 +921,7 @@ static int translate_table(char *name, struct ebt_table_info *newinfo) /* used to know what we need to clean up if something goes wrong */ i = 0; ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, - ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt); + ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt); if (ret != 0) { EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ebt_cleanup_entry, &i); @@ -1017,7 +1021,7 @@ static int do_replace(struct net *net, void __user *user, unsigned int len) if (ret != 0) goto free_counterstmp; - ret = translate_table(tmp.name, newinfo); + ret = translate_table(net, tmp.name, newinfo); if (ret != 0) goto free_counterstmp; @@ -1154,7 +1158,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table) newinfo->hook_entry[i] = p + ((char *)repl->hook_entry[i] - repl->entries); } - ret = translate_table(repl->name, newinfo); + ret = translate_table(net, repl->name, newinfo); if (ret != 0) { BUGPRINT("Translate_table failed\n"); goto free_chainstack; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 572330a552ef..a069d72d9482 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -661,8 +661,8 @@ static int check_target(struct ipt_entry *e, const char *name) } static int -find_check_entry(struct ipt_entry *e, const char *name, unsigned int size, - unsigned int *i) +find_check_entry(struct ipt_entry *e, struct net *net, const char *name, + unsigned int size, unsigned int *i) { struct ipt_entry_target *t; struct xt_target *target; @@ -675,6 +675,7 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size, return ret; j = 0; + mtpar.net = net; mtpar.table = name; mtpar.entryinfo = &e->ip; mtpar.hook_mask = e->comefrom; @@ -798,7 +799,8 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i) /* Checks and translates the user-supplied table segment (held in newinfo) */ static int -translate_table(const char *name, +translate_table(struct net *net, + const char *name, unsigned int valid_hooks, struct xt_table_info *newinfo, void *entry0, @@ -860,7 +862,7 @@ translate_table(const char *name, /* Finally, each sanity check must pass */ i = 0; ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, - find_check_entry, name, size, &i); + find_check_entry, net, name, size, &i); if (ret != 0) { IPT_ENTRY_ITERATE(entry0, newinfo->size, @@ -1303,7 +1305,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_table(tmp.name, tmp.valid_hooks, + ret = translate_table(net, tmp.name, tmp.valid_hooks, newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) @@ -1655,7 +1657,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, } static int -compat_check_entry(struct ipt_entry *e, const char *name, +compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, unsigned int *i) { struct xt_mtchk_param mtpar; @@ -1663,6 +1665,7 @@ compat_check_entry(struct ipt_entry *e, const char *name, int ret; j = 0; + mtpar.net = net; mtpar.table = name; mtpar.entryinfo = &e->ip; mtpar.hook_mask = e->comefrom; @@ -1684,7 +1687,8 @@ compat_check_entry(struct ipt_entry *e, const char *name, } static int -translate_compat_table(const char *name, +translate_compat_table(struct net *net, + const char *name, unsigned int valid_hooks, struct xt_table_info **pinfo, void **pentry0, @@ -1773,7 +1777,7 @@ translate_compat_table(const char *name, i = 0; ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, - name, &i); + net, name, &i); if (ret) { j -= i; COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, @@ -1833,7 +1837,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_compat_table(tmp.name, tmp.valid_hooks, + ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, &newinfo, &loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); @@ -2086,7 +2090,7 @@ struct xt_table *ipt_register_table(struct net *net, loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; memcpy(loc_cpu_entry, repl->entries, repl->size); - ret = translate_table(table->name, table->valid_hooks, + ret = translate_table(net, table->name, table->valid_hooks, newinfo, loc_cpu_entry, repl->size, repl->num_entries, repl->hook_entry, diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 480d7f8c9802..a825940a92ef 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -693,8 +693,8 @@ static int check_target(struct ip6t_entry *e, const char *name) } static int -find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, - unsigned int *i) +find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, + unsigned int size, unsigned int *i) { struct ip6t_entry_target *t; struct xt_target *target; @@ -707,6 +707,7 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, return ret; j = 0; + mtpar.net = net; mtpar.table = name; mtpar.entryinfo = &e->ipv6; mtpar.hook_mask = e->comefrom; @@ -830,7 +831,8 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) /* Checks and translates the user-supplied table segment (held in newinfo) */ static int -translate_table(const char *name, +translate_table(struct net *net, + const char *name, unsigned int valid_hooks, struct xt_table_info *newinfo, void *entry0, @@ -892,7 +894,7 @@ translate_table(const char *name, /* Finally, each sanity check must pass */ i = 0; ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, - find_check_entry, name, size, &i); + find_check_entry, net, name, size, &i); if (ret != 0) { IP6T_ENTRY_ITERATE(entry0, newinfo->size, @@ -1336,7 +1338,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_table(tmp.name, tmp.valid_hooks, + ret = translate_table(net, tmp.name, tmp.valid_hooks, newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) @@ -2121,7 +2123,7 @@ struct xt_table *ip6t_register_table(struct net *net, loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; memcpy(loc_cpu_entry, repl->entries, repl->size); - ret = translate_table(table->name, table->valid_hooks, + ret = translate_table(net, table->name, table->valid_hooks, newinfo, loc_cpu_entry, repl->size, repl->num_entries, repl->hook_entry, -- GitLab From f54e9367f8499a9bf6b2afbc0dce63e1d53c525a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:25:47 +0100 Subject: [PATCH 0853/3892] netfilter: xtables: add struct xt_mtdtor_param::net Add ->net to match destructor list like ->net in constructor list. Make sure it's set in ebtables/iptables/ip6tables, this requires to propagate netns up to *_unregister_table(). Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 1 + include/linux/netfilter_bridge/ebtables.h | 2 +- include/linux/netfilter_ipv4/ip_tables.h | 2 +- include/linux/netfilter_ipv6/ip6_tables.h | 2 +- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- net/bridge/netfilter/ebtables.c | 19 ++++++------ net/ipv4/netfilter/ip_tables.c | 25 +++++++-------- net/ipv4/netfilter/iptable_filter.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 2 +- net/ipv4/netfilter/iptable_raw.c | 2 +- net/ipv4/netfilter/iptable_security.c | 2 +- net/ipv4/netfilter/nf_nat_rule.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 37 ++++++++++++----------- net/ipv6/netfilter/ip6table_filter.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 2 +- net/ipv6/netfilter/ip6table_raw.c | 2 +- net/ipv6/netfilter/ip6table_security.c | 2 +- 19 files changed, 59 insertions(+), 53 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 88261b9829a7..3caf5e151102 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -216,6 +216,7 @@ struct xt_mtchk_param { /* Match destructor parameters */ struct xt_mtdtor_param { + struct net *net; const struct xt_match *match; void *matchinfo; u_int8_t family; diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 3cc40c131cc3..1c6f0c5f530e 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -289,7 +289,7 @@ struct ebt_table { ~(__alignof__(struct ebt_replace)-1)) extern struct ebt_table *ebt_register_table(struct net *net, const struct ebt_table *table); -extern void ebt_unregister_table(struct ebt_table *table); +extern void ebt_unregister_table(struct net *net, struct ebt_table *table); extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, struct ebt_table *table); diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 27b3f5807305..8d1f273d350b 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -242,7 +242,7 @@ extern void ipt_init(void) __init; extern struct xt_table *ipt_register_table(struct net *net, const struct xt_table *table, const struct ipt_replace *repl); -extern void ipt_unregister_table(struct xt_table *table); +extern void ipt_unregister_table(struct net *net, struct xt_table *table); /* Standard entry. */ struct ipt_standard { diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index b31050d20ae4..d2952d2fa658 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -300,7 +300,7 @@ extern void ip6t_init(void) __init; extern struct xt_table *ip6t_register_table(struct net *net, const struct xt_table *table, const struct ip6t_replace *repl); -extern void ip6t_unregister_table(struct xt_table *table); +extern void ip6t_unregister_table(struct net *net, struct xt_table *table); extern unsigned int ip6t_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index d32ab13e728c..ae3f106c3908 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -71,7 +71,7 @@ static int __net_init broute_net_init(struct net *net) static void __net_exit broute_net_exit(struct net *net) { - ebt_unregister_table(net->xt.broute_table); + ebt_unregister_table(net, net->xt.broute_table); } static struct pernet_operations broute_net_ops = { diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 60b1a6ca7185..42e6bd094574 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -107,7 +107,7 @@ static int __net_init frame_filter_net_init(struct net *net) static void __net_exit frame_filter_net_exit(struct net *net) { - ebt_unregister_table(net->xt.frame_filter); + ebt_unregister_table(net, net->xt.frame_filter); } static struct pernet_operations frame_filter_net_ops = { diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 4a98804203b0..6dc2f878ae05 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -107,7 +107,7 @@ static int __net_init frame_nat_net_init(struct net *net) static void __net_exit frame_nat_net_exit(struct net *net) { - ebt_unregister_table(net->xt.frame_nat); + ebt_unregister_table(net, net->xt.frame_nat); } static struct pernet_operations frame_nat_net_ops = { diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index c77bab986696..1aa0e4c1f52d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -561,13 +561,14 @@ ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, } static inline int -ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i) +ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i) { struct xt_mtdtor_param par; if (i && (*i)-- == 0) return 1; + par.net = net; par.match = m->u.match; par.matchinfo = m->data; par.family = NFPROTO_BRIDGE; @@ -595,7 +596,7 @@ ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) } static inline int -ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) +ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt) { struct xt_tgdtor_param par; struct ebt_entry_target *t; @@ -606,7 +607,7 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) if (cnt && (*cnt)-- == 0) return 1; EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); - EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); + EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); par.target = t->u.target; @@ -731,7 +732,7 @@ ebt_check_entry(struct ebt_entry *e, cleanup_watchers: EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); cleanup_matches: - EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); + EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i); return ret; } @@ -924,7 +925,7 @@ static int translate_table(struct net *net, char *name, ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt); if (ret != 0) { EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, - ebt_cleanup_entry, &i); + ebt_cleanup_entry, net, &i); } vfree(cl_s); return ret; @@ -1074,7 +1075,7 @@ static int do_replace(struct net *net, void __user *user, unsigned int len) /* decrease module count and free resources */ EBT_ENTRY_ITERATE(table->entries, table->entries_size, - ebt_cleanup_entry, NULL); + ebt_cleanup_entry, net, NULL); vfree(table->entries); if (table->chainstack) { @@ -1091,7 +1092,7 @@ free_unlock: mutex_unlock(&ebt_mutex); free_iterate: EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, - ebt_cleanup_entry, NULL); + ebt_cleanup_entry, net, NULL); free_counterstmp: vfree(counterstmp); /* can be initialized in translate_table() */ @@ -1208,7 +1209,7 @@ out: return ERR_PTR(ret); } -void ebt_unregister_table(struct ebt_table *table) +void ebt_unregister_table(struct net *net, struct ebt_table *table) { int i; @@ -1220,7 +1221,7 @@ void ebt_unregister_table(struct ebt_table *table) list_del(&table->list); mutex_unlock(&ebt_mutex); EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, - ebt_cleanup_entry, NULL); + ebt_cleanup_entry, net, NULL); if (table->private->nentries) module_put(table->me); vfree(table->private->entries); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a069d72d9482..cfaba0e2e6fc 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -553,13 +553,14 @@ mark_source_chains(struct xt_table_info *newinfo, } static int -cleanup_match(struct ipt_entry_match *m, unsigned int *i) +cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) { struct xt_mtdtor_param par; if (i && (*i)-- == 0) return 1; + par.net = net; par.match = m->u.kernel.match; par.matchinfo = m->data; par.family = NFPROTO_IPV4; @@ -705,7 +706,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, err: module_put(t->u.kernel.target->me); cleanup_matches: - IPT_MATCH_ITERATE(e, cleanup_match, &j); + IPT_MATCH_ITERATE(e, cleanup_match, net, &j); return ret; } @@ -775,7 +776,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, } static int -cleanup_entry(struct ipt_entry *e, unsigned int *i) +cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) { struct xt_tgdtor_param par; struct ipt_entry_target *t; @@ -784,7 +785,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i) return 1; /* Cleanup all matches */ - IPT_MATCH_ITERATE(e, cleanup_match, NULL); + IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); t = ipt_get_target(e); par.target = t->u.kernel.target; @@ -866,7 +867,7 @@ translate_table(struct net *net, if (ret != 0) { IPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, net, &i); return ret; } @@ -1260,7 +1261,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, - NULL); + net, NULL); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, sizeof(struct xt_counters) * num_counters) != 0) @@ -1320,7 +1321,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) return 0; free_newinfo_untrans: - IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); + IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1682,7 +1683,7 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, return 0; cleanup_matches: - IPT_MATCH_ITERATE(e, cleanup_match, &j); + IPT_MATCH_ITERATE(e, cleanup_match, net, &j); return ret; } @@ -1782,7 +1783,7 @@ translate_compat_table(struct net *net, j -= i; COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, compat_release_entry, &j); - IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); + IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); xt_free_table_info(newinfo); return ret; } @@ -1853,7 +1854,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) return 0; free_newinfo_untrans: - IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); + IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -2112,7 +2113,7 @@ out: return ERR_PTR(ret); } -void ipt_unregister_table(struct xt_table *table) +void ipt_unregister_table(struct net *net, struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; @@ -2122,7 +2123,7 @@ void ipt_unregister_table(struct xt_table *table) /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries[raw_smp_processor_id()]; - IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); + IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); if (private->number > private->initial_entries) module_put(table_owner); xt_free_table_info(private); diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index df566cbd68e5..dee90eb8aa47 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -138,7 +138,7 @@ static int __net_init iptable_filter_net_init(struct net *net) static void __net_exit iptable_filter_net_exit(struct net *net) { - ipt_unregister_table(net->ipv4.iptable_filter); + ipt_unregister_table(net, net->ipv4.iptable_filter); } static struct pernet_operations iptable_filter_net_ops = { diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index fae78c3076c4..e07bf242343a 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -208,7 +208,7 @@ static int __net_init iptable_mangle_net_init(struct net *net) static void __net_exit iptable_mangle_net_exit(struct net *net) { - ipt_unregister_table(net->ipv4.iptable_mangle); + ipt_unregister_table(net, net->ipv4.iptable_mangle); } static struct pernet_operations iptable_mangle_net_ops = { diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 993edc23be09..40f2b9f611a2 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -100,7 +100,7 @@ static int __net_init iptable_raw_net_init(struct net *net) static void __net_exit iptable_raw_net_exit(struct net *net) { - ipt_unregister_table(net->ipv4.iptable_raw); + ipt_unregister_table(net, net->ipv4.iptable_raw); } static struct pernet_operations iptable_raw_net_ops = { diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 3bd3d6388da5..7ce2366e4305 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -138,7 +138,7 @@ static int __net_init iptable_security_net_init(struct net *net) static void __net_exit iptable_security_net_exit(struct net *net) { - ipt_unregister_table(net->ipv4.iptable_security); + ipt_unregister_table(net, net->ipv4.iptable_security); } static struct pernet_operations iptable_security_net_ops = { diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 9e81e0dfb4ec..85da34fdc755 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -195,7 +195,7 @@ static int __net_init nf_nat_rule_net_init(struct net *net) static void __net_exit nf_nat_rule_net_exit(struct net *net) { - ipt_unregister_table(net->ipv4.nat_table); + ipt_unregister_table(net, net->ipv4.nat_table); } static struct pernet_operations nf_nat_rule_net_ops = { diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index a825940a92ef..9f1d45f2ba8f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -585,13 +585,14 @@ mark_source_chains(struct xt_table_info *newinfo, } static int -cleanup_match(struct ip6t_entry_match *m, unsigned int *i) +cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) { struct xt_mtdtor_param par; if (i && (*i)-- == 0) return 1; + par.net = net; par.match = m->u.kernel.match; par.matchinfo = m->data; par.family = NFPROTO_IPV6; @@ -737,7 +738,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, err: module_put(t->u.kernel.target->me); cleanup_matches: - IP6T_MATCH_ITERATE(e, cleanup_match, &j); + IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); return ret; } @@ -807,7 +808,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, } static int -cleanup_entry(struct ip6t_entry *e, unsigned int *i) +cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) { struct xt_tgdtor_param par; struct ip6t_entry_target *t; @@ -816,7 +817,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) return 1; /* Cleanup all matches */ - IP6T_MATCH_ITERATE(e, cleanup_match, NULL); + IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); t = ip6t_get_target(e); par.target = t->u.kernel.target; @@ -898,7 +899,7 @@ translate_table(struct net *net, if (ret != 0) { IP6T_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, net, &i); return ret; } @@ -1293,7 +1294,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, - NULL); + net, NULL); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, sizeof(struct xt_counters) * num_counters) != 0) @@ -1353,7 +1354,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) return 0; free_newinfo_untrans: - IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); + IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1692,14 +1693,15 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, return ret; } -static int compat_check_entry(struct ip6t_entry *e, const char *name, - unsigned int *i) +static int compat_check_entry(struct ip6t_entry *e, struct net *net, + const char *name, unsigned int *i) { unsigned int j; int ret; struct xt_mtchk_param mtpar; j = 0; + mtpar.net = net; mtpar.table = name; mtpar.entryinfo = &e->ipv6; mtpar.hook_mask = e->comefrom; @@ -1716,12 +1718,13 @@ static int compat_check_entry(struct ip6t_entry *e, const char *name, return 0; cleanup_matches: - IP6T_MATCH_ITERATE(e, cleanup_match, &j); + IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); return ret; } static int -translate_compat_table(const char *name, +translate_compat_table(struct net *net, + const char *name, unsigned int valid_hooks, struct xt_table_info **pinfo, void **pentry0, @@ -1810,12 +1813,12 @@ translate_compat_table(const char *name, i = 0; ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, - name, &i); + net, name, &i); if (ret) { j -= i; COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, compat_release_entry, &j); - IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); + IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); xt_free_table_info(newinfo); return ret; } @@ -1870,7 +1873,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) goto free_newinfo; } - ret = translate_compat_table(tmp.name, tmp.valid_hooks, + ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, &newinfo, &loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); @@ -1886,7 +1889,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) return 0; free_newinfo_untrans: - IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); + IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -2144,7 +2147,7 @@ out: return ERR_PTR(ret); } -void ip6t_unregister_table(struct xt_table *table) +void ip6t_unregister_table(struct net *net, struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; @@ -2154,7 +2157,7 @@ void ip6t_unregister_table(struct xt_table *table) /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries[raw_smp_processor_id()]; - IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); + IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); if (private->number > private->initial_entries) module_put(table_owner); xt_free_table_info(private); diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index ad378efd0eb8..33ddfe53e18d 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -131,7 +131,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) static void __net_exit ip6table_filter_net_exit(struct net *net) { - ip6t_unregister_table(net->ipv6.ip6table_filter); + ip6t_unregister_table(net, net->ipv6.ip6table_filter); } static struct pernet_operations ip6table_filter_net_ops = { diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index a929c19d30e3..9bc483f000e5 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -182,7 +182,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) static void __net_exit ip6table_mangle_net_exit(struct net *net) { - ip6t_unregister_table(net->ipv6.ip6table_mangle); + ip6t_unregister_table(net, net->ipv6.ip6table_mangle); } static struct pernet_operations ip6table_mangle_net_ops = { diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index ed1a1180f3b3..4c90b552e433 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -94,7 +94,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) static void __net_exit ip6table_raw_net_exit(struct net *net) { - ip6t_unregister_table(net->ipv6.ip6table_raw); + ip6t_unregister_table(net, net->ipv6.ip6table_raw); } static struct pernet_operations ip6table_raw_net_ops = { diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 41b444c60934..baa8d4ef3b0a 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -134,7 +134,7 @@ static int __net_init ip6table_security_net_init(struct net *net) static void __net_exit ip6table_security_net_exit(struct net *net) { - ip6t_unregister_table(net->ipv6.ip6table_security); + ip6t_unregister_table(net, net->ipv6.ip6table_security); } static struct pernet_operations ip6table_security_net_ops = { -- GitLab From 7d07d5632b672c892a65882c2a119345fd9596c9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:31:00 +0100 Subject: [PATCH 0854/3892] netfilter: xt_recent: netns support Make recent table list per-netns. Make proc files per-netns. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/xt_recent.c | 136 ++++++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 41 deletions(-) diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 768d01ff1fea..203333107367 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -78,15 +79,26 @@ struct recent_table { struct list_head iphash[0]; }; -static LIST_HEAD(tables); +struct recent_net { + struct list_head tables; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *xt_recent; +#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT + struct proc_dir_entry *ipt_recent; +#endif +#endif +}; + +static int recent_net_id; +static inline struct recent_net *recent_pernet(struct net *net) +{ + return net_generic(net, recent_net_id); +} + static DEFINE_SPINLOCK(recent_lock); static DEFINE_MUTEX(recent_mutex); #ifdef CONFIG_PROC_FS -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT -static struct proc_dir_entry *proc_old_dir; -#endif -static struct proc_dir_entry *recent_proc_dir; static const struct file_operations recent_old_fops, recent_mt_fops; #endif @@ -172,11 +184,12 @@ static void recent_entry_update(struct recent_table *t, struct recent_entry *e) list_move_tail(&e->lru_list, &t->lru_list); } -static struct recent_table *recent_table_lookup(const char *name) +static struct recent_table *recent_table_lookup(struct recent_net *recent_net, + const char *name) { struct recent_table *t; - list_for_each_entry(t, &tables, list) + list_for_each_entry(t, &recent_net->tables, list) if (!strcmp(t->name, name)) return t; return NULL; @@ -195,6 +208,8 @@ static void recent_table_flush(struct recent_table *t) static bool recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) { + struct net *net = dev_net(par->in ? par->in : par->out); + struct recent_net *recent_net = recent_pernet(net); const struct xt_recent_mtinfo *info = par->matchinfo; struct recent_table *t; struct recent_entry *e; @@ -227,7 +242,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) ttl++; spin_lock_bh(&recent_lock); - t = recent_table_lookup(info->name); + t = recent_table_lookup(recent_net, info->name); e = recent_entry_lookup(t, &addr, par->match->family, (info->check_set & XT_RECENT_TTL) ? ttl : 0); if (e == NULL) { @@ -271,6 +286,7 @@ out: static bool recent_mt_check(const struct xt_mtchk_param *par) { + struct recent_net *recent_net = recent_pernet(par->net); const struct xt_recent_mtinfo *info = par->matchinfo; struct recent_table *t; #ifdef CONFIG_PROC_FS @@ -297,7 +313,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) return false; mutex_lock(&recent_mutex); - t = recent_table_lookup(info->name); + t = recent_table_lookup(recent_net, info->name); if (t != NULL) { t->refcnt++; ret = true; @@ -314,7 +330,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) for (i = 0; i < ip_list_hash_size; i++) INIT_LIST_HEAD(&t->iphash[i]); #ifdef CONFIG_PROC_FS - pde = proc_create_data(t->name, ip_list_perms, recent_proc_dir, + pde = proc_create_data(t->name, ip_list_perms, recent_net->xt_recent, &recent_mt_fops, t); if (pde == NULL) { kfree(t); @@ -323,10 +339,10 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) pde->uid = ip_list_uid; pde->gid = ip_list_gid; #ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - pde = proc_create_data(t->name, ip_list_perms, proc_old_dir, + pde = proc_create_data(t->name, ip_list_perms, recent_net->ipt_recent, &recent_old_fops, t); if (pde == NULL) { - remove_proc_entry(t->name, proc_old_dir); + remove_proc_entry(t->name, recent_net->xt_recent); kfree(t); goto out; } @@ -335,7 +351,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) #endif #endif spin_lock_bh(&recent_lock); - list_add_tail(&t->list, &tables); + list_add_tail(&t->list, &recent_net->tables); spin_unlock_bh(&recent_lock); ret = true; out: @@ -345,20 +361,21 @@ out: static void recent_mt_destroy(const struct xt_mtdtor_param *par) { + struct recent_net *recent_net = recent_pernet(par->net); const struct xt_recent_mtinfo *info = par->matchinfo; struct recent_table *t; mutex_lock(&recent_mutex); - t = recent_table_lookup(info->name); + t = recent_table_lookup(recent_net, info->name); if (--t->refcnt == 0) { spin_lock_bh(&recent_lock); list_del(&t->list); spin_unlock_bh(&recent_lock); #ifdef CONFIG_PROC_FS #ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - remove_proc_entry(t->name, proc_old_dir); + remove_proc_entry(t->name, recent_net->ipt_recent); #endif - remove_proc_entry(t->name, recent_proc_dir); + remove_proc_entry(t->name, recent_net->xt_recent); #endif recent_table_flush(t); kfree(t); @@ -607,8 +624,65 @@ static const struct file_operations recent_mt_fops = { .release = seq_release_private, .owner = THIS_MODULE, }; + +static int __net_init recent_proc_net_init(struct net *net) +{ + struct recent_net *recent_net = recent_pernet(net); + + recent_net->xt_recent = proc_mkdir("xt_recent", net->proc_net); + if (!recent_net->xt_recent) + return -ENOMEM; +#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT + recent_net->ipt_recent = proc_mkdir("ipt_recent", net->proc_net); + if (!recent_net->ipt_recent) { + proc_net_remove(net, "xt_recent"); + return -ENOMEM; + } +#endif + return 0; +} + +static void __net_exit recent_proc_net_exit(struct net *net) +{ +#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT + proc_net_remove(net, "ipt_recent"); +#endif + proc_net_remove(net, "xt_recent"); +} +#else +static inline int recent_proc_net_init(struct net *net) +{ + return 0; +} + +static inline void recent_proc_net_exit(struct net *net) +{ +} #endif /* CONFIG_PROC_FS */ +static int __net_init recent_net_init(struct net *net) +{ + struct recent_net *recent_net = recent_pernet(net); + + INIT_LIST_HEAD(&recent_net->tables); + return recent_proc_net_init(net); +} + +static void __net_exit recent_net_exit(struct net *net) +{ + struct recent_net *recent_net = recent_pernet(net); + + BUG_ON(!list_empty(&recent_net->tables)); + recent_proc_net_exit(net); +} + +static struct pernet_operations recent_net_ops = { + .init = recent_net_init, + .exit = recent_net_exit, + .id = &recent_net_id, + .size = sizeof(struct recent_net), +}; + static struct xt_match recent_mt_reg[] __read_mostly = { { .name = "recent", @@ -640,39 +714,19 @@ static int __init recent_mt_init(void) return -EINVAL; ip_list_hash_size = 1 << fls(ip_list_tot); - err = xt_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); -#ifdef CONFIG_PROC_FS + err = register_pernet_subsys(&recent_net_ops); if (err) return err; - recent_proc_dir = proc_mkdir("xt_recent", init_net.proc_net); - if (recent_proc_dir == NULL) { - xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); - err = -ENOMEM; - } -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - if (err < 0) - return err; - proc_old_dir = proc_mkdir("ipt_recent", init_net.proc_net); - if (proc_old_dir == NULL) { - remove_proc_entry("xt_recent", init_net.proc_net); - xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); - err = -ENOMEM; - } -#endif -#endif + err = xt_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); + if (err) + unregister_pernet_subsys(&recent_net_ops); return err; } static void __exit recent_mt_exit(void) { - BUG_ON(!list_empty(&tables)); xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); -#ifdef CONFIG_PROC_FS -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - remove_proc_entry("ipt_recent", init_net.proc_net); -#endif - remove_proc_entry("xt_recent", init_net.proc_net); -#endif + unregister_pernet_subsys(&recent_net_ops); } module_init(recent_mt_init); -- GitLab From e89fc3f1b06d9241f65e580b002789abaa6d11ac Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 18 Jan 2010 08:33:28 +0100 Subject: [PATCH 0855/3892] netfilter: xt_hashlimit: netns support Make hashtable per-netns. Make proc files per-netns. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 141 ++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 43 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 944fd11c8989..fb7fcb773a3f 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -26,6 +26,7 @@ #endif #include +#include #include #include @@ -40,9 +41,19 @@ MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match"); MODULE_ALIAS("ipt_hashlimit"); MODULE_ALIAS("ip6t_hashlimit"); +struct hashlimit_net { + struct hlist_head htables; + struct proc_dir_entry *ipt_hashlimit; + struct proc_dir_entry *ip6t_hashlimit; +}; + +static int hashlimit_net_id; +static inline struct hashlimit_net *hashlimit_pernet(struct net *net) +{ + return net_generic(net, hashlimit_net_id); +} + /* need to declare this at the top */ -static struct proc_dir_entry *hashlimit_procdir4; -static struct proc_dir_entry *hashlimit_procdir6; static const struct file_operations dl_file_ops; /* hash table crap */ @@ -93,13 +104,13 @@ struct xt_hashlimit_htable { /* seq_file stuff */ struct proc_dir_entry *pde; + struct net *net; struct hlist_head hash[0]; /* hashtable itself */ }; static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ -static HLIST_HEAD(hashlimit_htables); static struct kmem_cache *hashlimit_cachep __read_mostly; static inline bool dst_cmp(const struct dsthash_ent *ent, @@ -185,8 +196,9 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) } static void htable_gc(unsigned long htlong); -static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family) +static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_int8_t family) { + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); struct xt_hashlimit_htable *hinfo; unsigned int size; unsigned int i; @@ -239,26 +251,29 @@ static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family) spin_lock_init(&hinfo->lock); hinfo->pde = proc_create_data(minfo->name, 0, (family == NFPROTO_IPV4) ? - hashlimit_procdir4 : hashlimit_procdir6, + hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit, &dl_file_ops, hinfo); if (!hinfo->pde) { vfree(hinfo); return -1; } + hinfo->net = net; setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo); hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); add_timer(&hinfo->timer); spin_lock_bh(&hashlimit_lock); - hlist_add_head(&hinfo->node, &hashlimit_htables); + hlist_add_head(&hinfo->node, &hashlimit_net->htables); spin_unlock_bh(&hashlimit_lock); return 0; } -static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) +static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, + u_int8_t family) { + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); struct xt_hashlimit_htable *hinfo; unsigned int size; unsigned int i; @@ -301,19 +316,20 @@ static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) hinfo->pde = proc_create_data(minfo->name, 0, (family == NFPROTO_IPV4) ? - hashlimit_procdir4 : hashlimit_procdir6, + hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit, &dl_file_ops, hinfo); if (hinfo->pde == NULL) { vfree(hinfo); return -1; } + hinfo->net = net; setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo); hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); add_timer(&hinfo->timer); spin_lock_bh(&hashlimit_lock); - hlist_add_head(&hinfo->node, &hashlimit_htables); + hlist_add_head(&hinfo->node, &hashlimit_net->htables); spin_unlock_bh(&hashlimit_lock); return 0; @@ -364,24 +380,30 @@ static void htable_gc(unsigned long htlong) static void htable_destroy(struct xt_hashlimit_htable *hinfo) { + struct hashlimit_net *hashlimit_net = hashlimit_pernet(hinfo->net); + struct proc_dir_entry *parent; + del_timer_sync(&hinfo->timer); - /* remove proc entry */ - remove_proc_entry(hinfo->pde->name, - hinfo->family == NFPROTO_IPV4 ? hashlimit_procdir4 : - hashlimit_procdir6); + if (hinfo->family == NFPROTO_IPV4) + parent = hashlimit_net->ipt_hashlimit; + else + parent = hashlimit_net->ip6t_hashlimit; + remove_proc_entry(hinfo->pde->name, parent); htable_selective_cleanup(hinfo, select_all); vfree(hinfo); } -static struct xt_hashlimit_htable *htable_find_get(const char *name, +static struct xt_hashlimit_htable *htable_find_get(struct net *net, + const char *name, u_int8_t family) { + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); struct xt_hashlimit_htable *hinfo; struct hlist_node *pos; spin_lock_bh(&hashlimit_lock); - hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { + hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node) { if (!strcmp(name, hinfo->pde->name) && hinfo->family == family) { atomic_inc(&hinfo->use); @@ -665,6 +687,7 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) { + struct net *net = par->net; struct xt_hashlimit_info *r = par->matchinfo; /* Check for overflow. */ @@ -694,8 +717,8 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) * the list of htable's in htable_create(), since then we would * create duplicate proc files. -HW */ mutex_lock(&hlimit_mutex); - r->hinfo = htable_find_get(r->name, par->match->family); - if (!r->hinfo && htable_create_v0(r, par->match->family) != 0) { + r->hinfo = htable_find_get(net, r->name, par->match->family); + if (!r->hinfo && htable_create_v0(net, r, par->match->family) != 0) { mutex_unlock(&hlimit_mutex); return false; } @@ -706,6 +729,7 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) static bool hashlimit_mt_check(const struct xt_mtchk_param *par) { + struct net *net = par->net; struct xt_hashlimit_mtinfo1 *info = par->matchinfo; /* Check for overflow. */ @@ -735,8 +759,8 @@ static bool hashlimit_mt_check(const struct xt_mtchk_param *par) * the list of htable's in htable_create(), since then we would * create duplicate proc files. -HW */ mutex_lock(&hlimit_mutex); - info->hinfo = htable_find_get(info->name, par->match->family); - if (!info->hinfo && htable_create(info, par->match->family) != 0) { + info->hinfo = htable_find_get(net, info->name, par->match->family); + if (!info->hinfo && htable_create(net, info, par->match->family) != 0) { mutex_unlock(&hlimit_mutex); return false; } @@ -953,10 +977,61 @@ static const struct file_operations dl_file_ops = { .release = seq_release }; +static int __net_init hashlimit_proc_net_init(struct net *net) +{ + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + + hashlimit_net->ipt_hashlimit = proc_mkdir("ipt_hashlimit", net->proc_net); + if (!hashlimit_net->ipt_hashlimit) + return -ENOMEM; +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) + hashlimit_net->ip6t_hashlimit = proc_mkdir("ip6t_hashlimit", net->proc_net); + if (!hashlimit_net->ip6t_hashlimit) { + proc_net_remove(net, "ipt_hashlimit"); + return -ENOMEM; + } +#endif + return 0; +} + +static void __net_exit hashlimit_proc_net_exit(struct net *net) +{ + proc_net_remove(net, "ipt_hashlimit"); +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) + proc_net_remove(net, "ip6t_hashlimit"); +#endif +} + +static int __net_init hashlimit_net_init(struct net *net) +{ + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + + INIT_HLIST_HEAD(&hashlimit_net->htables); + return hashlimit_proc_net_init(net); +} + +static void __net_exit hashlimit_net_exit(struct net *net) +{ + struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + + BUG_ON(!hlist_empty(&hashlimit_net->htables)); + hashlimit_proc_net_exit(net); +} + +static struct pernet_operations hashlimit_net_ops = { + .init = hashlimit_net_init, + .exit = hashlimit_net_exit, + .id = &hashlimit_net_id, + .size = sizeof(struct hashlimit_net), +}; + static int __init hashlimit_mt_init(void) { int err; + err = register_pernet_subsys(&hashlimit_net_ops); + if (err < 0) + return err; err = xt_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); if (err < 0) @@ -970,41 +1045,21 @@ static int __init hashlimit_mt_init(void) printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); goto err2; } - hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); - if (!hashlimit_procdir4) { - printk(KERN_ERR "xt_hashlimit: unable to create proc dir " - "entry\n"); - goto err3; - } - err = 0; -#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) - hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net); - if (!hashlimit_procdir6) { - printk(KERN_ERR "xt_hashlimit: unable to create proc dir " - "entry\n"); - err = -ENOMEM; - } -#endif - if (!err) - return 0; - remove_proc_entry("ipt_hashlimit", init_net.proc_net); -err3: - kmem_cache_destroy(hashlimit_cachep); + return 0; + err2: xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); err1: + unregister_pernet_subsys(&hashlimit_net_ops); return err; } static void __exit hashlimit_mt_exit(void) { - remove_proc_entry("ipt_hashlimit", init_net.proc_net); -#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) - remove_proc_entry("ip6t_hashlimit", init_net.proc_net); -#endif kmem_cache_destroy(hashlimit_cachep); xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); + unregister_pernet_subsys(&hashlimit_net_ops); } module_init(hashlimit_mt_init); -- GitLab From 00097c4fdf117d9845d772f571a987ae95523f8c Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Sun, 17 Jan 2010 19:44:44 -0200 Subject: [PATCH 0856/3892] x86, trivial: Fix grammo in tsc comment about Geode TSC reliability Signed-off-by: Thadeu Lima de Souza Cascardo Cc: marcelo@kvack.org Cc: dilinger@collabora.co.uk Cc: trivial@kernel.org LKML-Reference: <1263764685-9871-1-git-send-email-cascardo@holoscopio.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 597683aa5ba0..23066ecf12fa 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -806,7 +806,7 @@ static void __init check_system_tsc_reliable(void) unsigned long res_low, res_high; rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); - /* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */ + /* Geode_LX - the OLPC CPU has a very reliable TSC */ if (res_low & RTSC_SUSP) tsc_clocksource_reliable = 1; #endif -- GitLab From e03bcb68629c7f0728c95f1afe06ce48565c7713 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Mon, 18 Jan 2010 13:00:51 +1100 Subject: [PATCH 0857/3892] generic-ipi: Optimize accesses by using DEFINE_PER_CPU_SHARED_ALIGNED for IPI data The smp ipi data is passed around and given write access by other cpus and should be separated from per-cpu data consumed by this cpu. Looking for hot lines, I saw call_function_data shared with tick_cpu_sched. Signed-off-by: Milton Miller Acked-by: Anton Blanchard Acked-by: Jens Axboe Cc: Andrew Morton Cc: Linus Torvalds Cc: Peter Zijlstra Cc: : Nick Piggin LKML-Reference: <20100118020051.GR12666@kryten> Signed-off-by: Ingo Molnar --- kernel/smp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index f10408422444..9867b6bfefce 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -12,8 +12,6 @@ #include #include -static DEFINE_PER_CPU(struct call_single_queue, call_single_queue); - static struct { struct list_head queue; raw_spinlock_t lock; @@ -33,12 +31,14 @@ struct call_function_data { cpumask_var_t cpumask; }; +static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data); + struct call_single_queue { struct list_head list; raw_spinlock_t lock; }; -static DEFINE_PER_CPU(struct call_function_data, cfd_data); +static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_queue, call_single_queue); static int hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) @@ -256,7 +256,7 @@ void generic_smp_call_function_single_interrupt(void) } } -static DEFINE_PER_CPU(struct call_single_data, csd_data); +static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data); /* * smp_call_function_single - Run a function on a specific CPU -- GitLab From 2ae3111eafd797e24cc390bb5ce6a8fa0deacdb2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 18 Jan 2010 00:29:19 -0800 Subject: [PATCH 0858/3892] drivers/net: Eliminate useless code The variable qdev is initialized twice to the same (side effect-free) expression. Drop one initialization. A simplified version of the semantic match that finds this problem is: (http://coccinelle.lip6.fr/) // @forall@ idexpression *x; identifier f!=ERR_PTR; @@ x = f(...) ... when != x ( x = f(...,<+...x...+>,...) | * x = f(...) ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/qla3xxx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index f922294fd349..4ef0afbcbe1b 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -4087,7 +4087,6 @@ static void __devexit ql3xxx_remove(struct pci_dev *pdev) struct ql3_adapter *qdev = netdev_priv(ndev); unregister_netdev(ndev); - qdev = netdev_priv(ndev); ql_disable_interrupts(qdev); -- GitLab From a5d896adf019143adf72d08826fe5359b6a8762c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Mon, 18 Jan 2010 09:44:39 +0100 Subject: [PATCH 0859/3892] netfilter: nfnetlink_queue: simplify warning message This patch remove variable part from a debug message to have message concatenation from syslog. Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy --- net/netfilter/nfnetlink_queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 5c589b27d6eb..90cf36decea3 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -414,8 +414,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) queue->queue_dropped++; if (net_ratelimit()) printk(KERN_WARNING "nf_queue: full at %d entries, " - "dropping packets(s). Dropped: %d\n", - queue->queue_total, queue->queue_dropped); + "dropping packets(s).\n", + queue->queue_total); goto err_out_free_nskb; } -- GitLab From 3d467676abf5f01f5ee99056273a58486968e252 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 18 Jan 2010 19:33:10 +0900 Subject: [PATCH 0860/3892] sh: Setup early PMB mappings. More and more boards are going to start shipping that boot with the MMU in 32BIT mode by default. Previously we relied on the bootloader to setup PMB mappings for use by the kernel but we also need to cater for boards whose bootloaders don't set them up. If CONFIG_PMB_LEGACY is not enabled we have full control over our PMB mappings and can compress our address space. Usually, the distance between the the cached and uncached mappings of RAM is always 512MB, however we can compress the distance to be the amount of RAM on the board. pmb_init() now becomes much simpler. It no longer has to calculate any mappings, it just has to synchronise the software PMB table with the hardware. Tested on SDK7786 and SH7785LCR. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/head_32.S | 241 +++++++++++++++++++++++++++++++++++++++ arch/sh/mm/pmb.c | 156 ++++++++++++++++--------- 2 files changed, 346 insertions(+), 51 deletions(-) diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index e5d421db4c83..8ee31a0b973e 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -3,6 +3,7 @@ * arch/sh/kernel/head.S * * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * Copyright (C) 2010 Matt Fleming * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -84,6 +85,236 @@ ENTRY(_stext) ldc r0, r7_bank ! ... and initial thread_info #endif +#if defined(CONFIG_PMB) && !defined(CONFIG_PMB_LEGACY) + /* + * Reconfigure the initial PMB mappings setup by the hardware. + * + * When we boot in 32-bit MMU mode there are 2 PMB entries already + * setup for us. + * + * Entry VPN PPN V SZ C UB WT + * --------------------------------------------------------------- + * 0 0x80000000 0x00000000 1 512MB 1 0 1 + * 1 0xA0000000 0x00000000 1 512MB 0 0 0 + * + * But we reprogram them here because we want complete control over + * our address space and the initial mappings may not map PAGE_OFFSET + * to __MEMORY_START (or even map all of our RAM). + * + * Once we've setup cached and uncached mappings for all of RAM we + * clear the rest of the PMB entries. + * + * This clearing also deals with the fact that PMB entries can persist + * across reboots. The PMB could have been left in any state when the + * reboot occurred, so to be safe we clear all entries and start with + * with a clean slate. + */ + + mov.l .LMMUCR, r1 /* Flush the TLB */ + mov.l @r1, r0 + or #MMUCR_TI, r0 + mov.l r0, @r1 + + mov.l .LMEMORY_SIZE, r5 + mov r5, r7 + + mov #PMB_E_SHIFT, r0 + mov #0x1, r4 + shld r0, r4 + + mov.l .LFIRST_DATA_ENTRY, r0 + mov.l .LPMB_DATA, r1 + mov.l .LFIRST_ADDR_ENTRY, r2 + mov.l .LPMB_ADDR, r3 + + mov #0, r10 + + /* + * r0 = PMB_DATA data field + * r1 = PMB_DATA address field + * r2 = PMB_ADDR data field + * r3 = PMB_ADDR address field + * r4 = PMB_E_SHIFT + * r5 = remaining amount of RAM to map + * r6 = PMB mapping size we're trying to use + * r7 = cached_to_uncached + * r8 = scratch register + * r9 = scratch register + * r10 = number of PMB entries we've setup + */ +.L512: + mov #(512 >> 4), r6 + shll16 r6 + shll8 r6 + + cmp/hi r5, r6 + bt .L128 + + mov #(PMB_SZ_512M >> 2), r9 + shll2 r9 + + /* + * Cached mapping + */ + mov #PMB_C, r8 + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov.l r2, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + /* + * Uncached mapping + */ + mov #(PMB_UB >> 8), r8 + shll8 r8 + + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov r2, r8 + add r7, r8 + mov.l r8, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + sub r6, r5 + add r6, r0 + add r6, r2 + + bra .L512 + +.L128: + mov #(128 >> 4), r6 + shll16 r6 + shll8 r6 + + cmp/hi r5, r6 + bt .L64 + + mov #(PMB_SZ_128M >> 2), r9 + shll2 r9 + + /* + * Cached mapping + */ + mov #PMB_C, r8 + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov.l r2, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + /* + * Uncached mapping + */ + mov #(PMB_UB >> 8), r8 + shll8 r8 + + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov r2, r8 + add r7, r8 + mov.l r8, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + sub r6, r5 + add r6, r0 + add r6, r2 + + bra .L128 + +.L64: + mov #(64 >> 4), r6 + shll16 r6 + shll8 r6 + + cmp/hi r5, r6 + bt .Ldone + + mov #(PMB_SZ_64M >> 2), r9 + shll2 r9 + + /* + * Cached mapping + */ + mov #PMB_C, r8 + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov.l r2, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + /* + * Uncached mapping + */ + mov #(PMB_UB >> 8), r8 + shll8 r8 + + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov r2, r8 + add r7, r8 + mov.l r8, @r3 + + add r4, r1 /* Increment to the next PMB_DATA entry */ + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + add #1, r10 /* Increment number of PMB entries */ + + sub r6, r5 + add r6, r0 + add r6, r2 + + bra .L64 + +.Ldone: + /* Update cached_to_uncached */ + mov.l .Lcached_to_uncached, r0 + mov.l r7, @r0 + + /* + * Clear the remaining PMB entries. + * + * r3 = entry to begin clearing from + * r10 = number of entries we've setup so far + */ + mov #0, r1 + mov #PMB_ENTRY_MAX, r0 + +.Lagain: + mov.l r1, @r3 /* Clear PMB_ADDR entry */ + add #1, r10 /* Increment the loop counter */ + cmp/eq r0, r10 + bf/s .Lagain + add r4, r3 /* Increment to the next PMB_ADDR entry */ + + mov.l 6f, r0 + icbi @r0 + +#endif /* !CONFIG_PMB_LEGACY */ + #ifndef CONFIG_SH_NO_BSS_INIT /* * Don't clear BSS if running on slow platforms such as an RTL simulation, @@ -133,3 +364,13 @@ ENTRY(stack_start) 5: .long start_kernel 6: .long sh_cpu_init 7: .long init_thread_union + +#if defined(CONFIG_PMB) && !defined(CONFIG_PMB_LEGACY) +.LPMB_ADDR: .long PMB_ADDR +.LPMB_DATA: .long PMB_DATA +.LFIRST_ADDR_ENTRY: .long PAGE_OFFSET | PMB_V +.LFIRST_DATA_ENTRY: .long __MEMORY_START | PMB_V +.LMMUCR: .long MMUCR +.Lcached_to_uncached: .long cached_to_uncached +.LMEMORY_SIZE: .long __MEMORY_SIZE +#endif diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 8f7dbf183fb0..b796b6c021b4 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -3,11 +3,8 @@ * * Privileged Space Mapping Buffer (PMB) Support. * - * Copyright (C) 2005 - 2010 Paul Mundt - * - * P1/P2 Section mapping definitions from map32.h, which was: - * - * Copyright 2003 (c) Lineo Solutions,Inc. + * Copyright (C) 2005 - 2010 Paul Mundt + * Copyright (C) 2010 Matt Fleming * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -280,46 +277,82 @@ static void __pmb_unmap(struct pmb_entry *pmbe) } #ifdef CONFIG_PMB_LEGACY +static inline unsigned int pmb_ppn_in_range(unsigned long ppn) +{ + return ppn >= __MEMORY_START && ppn < __MEMORY_START + __MEMORY_SIZE; +} + static int pmb_apply_legacy_mappings(void) { - int i; - unsigned long addr, data; unsigned int applied = 0; + int i; - for (i = 0; i < PMB_ENTRY_MAX; i++) { - struct pmb_entry *pmbe; - unsigned long vpn, ppn, flags; - - addr = PMB_DATA + (i << PMB_E_SHIFT); - data = ctrl_inl(addr); - if (!(data & PMB_V)) - continue; + pr_info("PMB: Preserving legacy mappings:\n"); - if (data & PMB_C) { -#if defined(CONFIG_CACHE_WRITETHROUGH) - data |= PMB_WT; -#elif defined(CONFIG_CACHE_WRITEBACK) - data &= ~PMB_WT; -#else - data &= ~(PMB_C | PMB_WT); -#endif - } - ctrl_outl(data, addr); - - ppn = data & PMB_PFN_MASK; + /* + * The following entries are setup by the bootloader. + * + * Entry VPN PPN V SZ C UB + * -------------------------------------------------------- + * 0 0xA0000000 0x00000000 1 64MB 0 0 + * 1 0xA4000000 0x04000000 1 16MB 0 0 + * 2 0xA6000000 0x08000000 1 16MB 0 0 + * 9 0x88000000 0x48000000 1 128MB 1 1 + * 10 0x90000000 0x50000000 1 128MB 1 1 + * 11 0x98000000 0x58000000 1 128MB 1 1 + * 13 0xA8000000 0x48000000 1 128MB 0 0 + * 14 0xB0000000 0x50000000 1 128MB 0 0 + * 15 0xB8000000 0x58000000 1 128MB 0 0 + * + * The only entries the we need are the ones that map the kernel + * at the cached and uncached addresses. + */ + for (i = 0; i < PMB_ENTRY_MAX; i++) { + unsigned long addr, data; + unsigned long addr_val, data_val; + unsigned long ppn, vpn; - flags = data & (PMB_C | PMB_WT | PMB_UB); - flags |= data & PMB_SZ_MASK; + addr = mk_pmb_addr(i); + data = mk_pmb_data(i); - addr = PMB_ADDR + (i << PMB_E_SHIFT); - data = ctrl_inl(addr); + addr_val = __raw_readl(addr); + data_val = __raw_readl(data); - vpn = data & PMB_PFN_MASK; + /* + * Skip over any bogus entries + */ + if (!(data_val & PMB_V) || !(addr_val & PMB_V)) + continue; - pmbe = pmb_alloc(vpn, ppn, flags, i); - WARN_ON(IS_ERR(pmbe)); + ppn = data_val & PMB_PFN_MASK; + vpn = addr_val & PMB_PFN_MASK; - applied++; + /* + * Only preserve in-range mappings. + */ + if (pmb_ppn_in_range(ppn)) { + unsigned int size; + char *sz_str = NULL; + + size = data_val & PMB_SZ_MASK; + + sz_str = (size == PMB_SZ_16M) ? " 16MB": + (size == PMB_SZ_64M) ? " 64MB": + (size == PMB_SZ_128M) ? "128MB": + "512MB"; + + pr_info("\t0x%08lx -> 0x%08lx [ %s %scached ]\n", + vpn >> PAGE_SHIFT, ppn >> PAGE_SHIFT, sz_str, + (data_val & PMB_C) ? "" : "un"); + + applied++; + } else { + /* + * Invalidate anything out of bounds. + */ + __raw_writel(addr_val & ~PMB_V, addr); + __raw_writel(data_val & ~PMB_V, data); + } } return (applied == 0); @@ -333,8 +366,9 @@ static inline int pmb_apply_legacy_mappings(void) int __uses_jump_to_uncached pmb_init(void) { - unsigned int i; - unsigned long size, ret; + int i; + unsigned long addr, data; + unsigned long ret; jump_to_uncached(); @@ -352,25 +386,45 @@ int __uses_jump_to_uncached pmb_init(void) } /* - * Insert PMB entries for the P1 and P2 areas so that, after - * we've switched the MMU to 32-bit mode, the semantics of P1 - * and P2 are the same as in 29-bit mode, e.g. - * - * P1 - provides a cached window onto physical memory - * P2 - provides an uncached window onto physical memory + * Sync our software copy of the PMB mappings with those in + * hardware. The mappings in the hardware PMB were either set up + * by the bootloader or very early on by the kernel. */ - size = (unsigned long)__MEMORY_START + __MEMORY_SIZE; + for (i = 0; i < PMB_ENTRY_MAX; i++) { + struct pmb_entry *pmbe; + unsigned long vpn, ppn, flags; - ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C); - BUG_ON(ret != size); + addr = PMB_DATA + (i << PMB_E_SHIFT); + data = ctrl_inl(addr); + if (!(data & PMB_V)) + continue; - ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB); - BUG_ON(ret != size); + if (data & PMB_C) { +#if defined(CONFIG_CACHE_WRITETHROUGH) + data |= PMB_WT; +#elif defined(CONFIG_CACHE_WRITEBACK) + data &= ~PMB_WT; +#else + data &= ~(PMB_C | PMB_WT); +#endif + } + ctrl_outl(data, addr); - ctrl_outl(0, PMB_IRMCR); + ppn = data & PMB_PFN_MASK; + + flags = data & (PMB_C | PMB_WT | PMB_UB); + flags |= data & PMB_SZ_MASK; - /* PMB.SE and UB[7] */ - ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR); + addr = PMB_ADDR + (i << PMB_E_SHIFT); + data = ctrl_inl(addr); + + vpn = data & PMB_PFN_MASK; + + pmbe = pmb_alloc(vpn, ppn, flags, i); + WARN_ON(IS_ERR(pmbe)); + } + + ctrl_outl(0, PMB_IRMCR); /* Flush out the TLB */ i = ctrl_inl(MMUCR); -- GitLab From 4291b730cd0f0cf98a90d946b6cabbd804397350 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 20:39:49 +0900 Subject: [PATCH 0861/3892] sh: Need IRQs enabled for init_fpu(). This tosses in a local_irq_enable()/disable() pair around the init_fpu() callsite in the FPU state restore exception handler. Fixes up a slab BUG triggered by making a slab cache allocation that can sleep whilst irqs_disabled(). This follows the behaviour undertaken by the x86 implementation. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/fpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/kernel/cpu/fpu.c b/arch/sh/kernel/cpu/fpu.c index c23e6727002a..f059ed62cf57 100644 --- a/arch/sh/kernel/cpu/fpu.c +++ b/arch/sh/kernel/cpu/fpu.c @@ -56,6 +56,7 @@ void fpu_state_restore(struct pt_regs *regs) } if (!tsk_used_math(tsk)) { + local_irq_enable(); /* * does a slab alloc which can sleep */ @@ -66,6 +67,7 @@ void fpu_state_restore(struct pt_regs *regs) do_group_exit(SIGKILL); return; } + local_irq_disable(); } grab_fpu(regs); -- GitLab From d9b9487af79955a8e8fcddc963f56697e020cfed Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:08:32 +0900 Subject: [PATCH 0862/3892] sh: Handle early ioremaps through fixed mappings. This adds in a mem_init_done to work out when a standard ioremap() is possible, falling back to the fixmap based ioremap otherwise. Signed-off-by: Paul Mundt --- arch/sh/include/asm/processor.h | 3 +++ arch/sh/mm/init.c | 4 ++++ arch/sh/mm/ioremap_32.c | 12 +++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index 017e0c1807b2..a522e5d8f44f 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h @@ -101,6 +101,9 @@ struct seq_operations; extern struct pt_regs fake_swapper_regs; +/* arch/sh/mm/init.c */ +extern unsigned int mem_init_done; + /* arch/sh/kernel/setup.c */ const char *get_cpu_subtype(struct sh_cpuinfo *c); extern const struct seq_operations cpuinfo_op; diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 30a9b530d456..fe578a286fdd 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -237,6 +237,8 @@ static void __init iommu_init(void) no_iommu_init(); } +unsigned int mem_init_done = 0; + void __init mem_init(void) { int codesize, datasize, initsize; @@ -287,6 +289,8 @@ void __init mem_init(void) /* Initialize the vDSO */ vsyscall_init(); + + mem_init_done = 1; } void free_initmem(void) diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c index c80a8166fbb0..24f6ba6bff71 100644 --- a/arch/sh/mm/ioremap_32.c +++ b/arch/sh/mm/ioremap_32.c @@ -1,13 +1,13 @@ /* * arch/sh/mm/ioremap.c * + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2005 - 2010 Paul Mundt + * * Re-map IO memory to kernel address space so that we can access it. * This is needed for high PCI addresses that aren't mapped in the * 640k-1MB IO memory area on PC's * - * (C) Copyright 1995 1996 Linus Torvalds - * (C) Copyright 2005, 2006 Paul Mundt - * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this * archive for more details. @@ -64,6 +64,12 @@ void __iomem *__ioremap_caller(unsigned long phys_addr, unsigned long size, phys_addr &= PAGE_MASK; size = PAGE_ALIGN(last_addr+1) - phys_addr; + /* + * If we can't yet use the regular approach, go the fixmap route. + */ + if (!mem_init_done) + return ioremap_fixed(phys_addr, size, __pgprot(flags)); + /* * Ok, go for it.. */ -- GitLab From edf711b66f2a8a9629aa253ad8b3a5a03b5d7af5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:20:13 +0900 Subject: [PATCH 0863/3892] sh: Fixup the IOREMAP_FIXED=n build. Presently the fixed ioremap API is only defined when CONFIG_IOREMAP_FIXED is set. As we want to call in to it unconditionally, provide a stubbed out interface. Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index bee5965e0a82..9aa9438c66c3 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -241,6 +241,15 @@ void __iounmap(void __iomem *addr); extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t); extern void iounmap_fixed(void __iomem *); extern void ioremap_fixed_init(void); +#else +static inline void __iomem * +ioremap_fixed(resource_size t phys_addr, unsigned long size, pgprot_t prot) +{ + BUG(); +} + +static inline void ioremap_fixed_init(void) { } +static inline void iounmap_fixed(void __iomem *addr) { } #endif static inline void __iomem * -- GitLab From 0b59e38ffaf7b201ff6afe5b736365d16848c7e3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:21:32 +0900 Subject: [PATCH 0864/3892] sh: Merge _32/_64 ioremap implementations. There is nothing of interest in the _64 version anymore, so the _32 one can be renamed and used unconditionally. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile | 2 +- arch/sh/mm/{ioremap_32.c => ioremap.c} | 0 arch/sh/mm/ioremap_64.c | 47 -------------------------- 3 files changed, 1 insertion(+), 48 deletions(-) rename arch/sh/mm/{ioremap_32.c => ioremap.c} (100%) delete mode 100644 arch/sh/mm/ioremap_64.c diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 89ba56c20ade..0027cdea2c20 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -15,7 +15,7 @@ obj-y += $(cacheops-y) mmu-y := nommu.o extable_32.o mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o \ - ioremap_$(BITS).o kmap.o pgtable.o tlbflush_$(BITS).o + ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o obj-y += $(mmu-y) obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap.c similarity index 100% rename from arch/sh/mm/ioremap_32.c rename to arch/sh/mm/ioremap.c diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c deleted file mode 100644 index fb0aa457c71e..000000000000 --- a/arch/sh/mm/ioremap_64.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * arch/sh/mm/ioremap_64.c - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * Copyright (C) 2003 - 2007 Paul Mundt - * - * Mostly derived from arch/sh/mm/ioremap.c which, in turn is mostly - * derived from arch/i386/mm/ioremap.c . - * - * (C) Copyright 1995 1996 Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, - unsigned long flags, void *caller) -{ - pgprot_t prot; - - prot = __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | - _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SHARED | flags); - - return ioremap_fixed(offset, size, prot); -} -EXPORT_SYMBOL(__ioremap_caller); - -void __iounmap(void __iomem *virtual) -{ - iounmap_fixed(virtual); -} -EXPORT_SYMBOL(__iounmap); -- GitLab From 4f744affc345f8b158615e0cdd01d1f4985837c3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:30:29 +0900 Subject: [PATCH 0865/3892] sh: Make iounmap_fixed() return success/failure for iounmap() path. This converts iounmap_fixed() to return success/error if it handled the unmap request or not. At the same time, drop the __init label, as this can be called in to later. Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 5 +++-- arch/sh/mm/ioremap_fixed.c | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 9aa9438c66c3..6a0dd8c1e0a9 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -22,6 +22,7 @@ * for old compat code for I/O offseting to SuperIOs, all of which are * better handled through the machvec ioport mapping routines these days. */ +#include #include #include #include @@ -239,7 +240,7 @@ void __iounmap(void __iomem *addr); #ifdef CONFIG_IOREMAP_FIXED extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t); -extern void iounmap_fixed(void __iomem *); +extern int iounmap_fixed(void __iomem *); extern void ioremap_fixed_init(void); #else static inline void __iomem * @@ -249,7 +250,7 @@ ioremap_fixed(resource_size t phys_addr, unsigned long size, pgprot_t prot) } static inline void ioremap_fixed_init(void) { } -static inline void iounmap_fixed(void __iomem *addr) { } +static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } #endif static inline void __iomem * diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c index 3a9d3d88fe8d..425f6c6bf250 100644 --- a/arch/sh/mm/ioremap_fixed.c +++ b/arch/sh/mm/ioremap_fixed.c @@ -103,7 +103,7 @@ ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot) return map->addr; } -void __init iounmap_fixed(void __iomem *addr) +int iounmap_fixed(void __iomem *addr) { enum fixed_addresses idx; unsigned long virt_addr; @@ -122,8 +122,11 @@ void __init iounmap_fixed(void __iomem *addr) } } + /* + * If we don't match, it's not for us. + */ if (slot < 0) - return; + return -EINVAL; virt_addr = (unsigned long)addr; @@ -141,4 +144,6 @@ void __init iounmap_fixed(void __iomem *addr) map->size = 0; map->addr = NULL; + + return 0; } -- GitLab From 12b6b01cb47dc3eefbef866592193661dad7afb9 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:33:08 +0900 Subject: [PATCH 0866/3892] sh: Handle unmapping of fixed slots transparently in iounmap(). iounmap() should balance whatever is done by ioremap(). Presently ioremap() can do any of fixed mappings, PMB mappings, or page table mappings. Presently only the latter two are handled through the standard unmap path, so tie in the fixed unmapping, too. Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index 24f6ba6bff71..e8b65f645aed 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -142,6 +142,12 @@ void __iounmap(void __iomem *addr) if (iomapping_nontranslatable(vaddr)) return; + /* + * There's no VMA if it's from an early fixed mapping. + */ + if (iounmap_fixed(addr) == 0) + return; + #ifdef CONFIG_PMB /* * Purge any PMB entries that may have been established for this -- GitLab From af1415314a4190b8ea06e53808d392fcf91555af Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jan 2010 21:45:00 +0900 Subject: [PATCH 0867/3892] sh: Flag __ioremap_caller() __init_refok. The mem_init_done test makes sure that this path is only entered in __init cases, so leaving ioremap_fixed() as __init and flagging the caller __init_refok is sufficient. Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index e8b65f645aed..a130b2278e92 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -33,8 +33,9 @@ * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ -void __iomem *__ioremap_caller(unsigned long phys_addr, unsigned long size, - unsigned long flags, void *caller) +void __iomem * __init_refok +__ioremap_caller(unsigned long phys_addr, unsigned long size, + unsigned long flags, void *caller) { struct vm_struct *area; unsigned long offset, last_addr, addr, orig_addr; -- GitLab From 3e879d7bac705be4813a0ec9560cbe31db4b269f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Jan 2010 14:49:50 +0100 Subject: [PATCH 0868/3892] ALSA: pcm - Remove unneeded ifdef pgprot_noncached Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a870fe696578..5df0d21f18b3 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3162,9 +3162,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, long size; unsigned long offset; -#ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -#endif area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; -- GitLab From c32d977b8157bf67cdf47729ce7dd054a26eb534 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Jan 2010 14:58:57 +0100 Subject: [PATCH 0869/3892] ALSA: pcm - Call pgprot_noncached() for vmalloc'ed buffers pgprot_noncached() can be set for vmalloc'ed buffers safely, and we'd need non-cached behavior more or less, even for the intermediate ring- buffers. Now snd_pcm_lib_mmap_vmalloc() is added as the common PCM mmap callback that is coupled with snd_pcm_lib_alloc_vmalloc_buffer() & co. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 4 ++++ sound/core/pcm_native.c | 9 +++++++++ sound/drivers/vx/vx_pcm.c | 2 ++ sound/mips/sgio2audio.c | 3 +++ sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 1 + sound/usb/ua101.c | 2 ++ sound/usb/usbaudio.c | 2 ++ 7 files changed, 23 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1d4ca2aae50d..aabf48bb8ee6 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1021,6 +1021,10 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_iomem NULL #endif +int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, + struct vm_area_struct *area); +#define snd_pcm_lib_mmap_vmalloc snd_pcm_lib_mmap_noncached + static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) { *max = dma < 4 ? 64 * 1024 : 128 * 1024; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5df0d21f18b3..88fff44702a4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3176,6 +3176,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); #endif /* SNDRV_PCM_INFO_MMAP */ +/* mmap callback with pgprot_noncached */ +int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_noncached(area->vm_page_prot); + return snd_pcm_default_mmap(substream, area); +} +EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); + /* * mmap DMA buffer */ diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index c8385d26a16f..35a2f71a6af5 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -905,6 +905,7 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -1125,6 +1126,7 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 9b486beeb932..6aff217379d9 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -691,6 +691,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -703,6 +704,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -715,6 +717,7 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; /* diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 0afa683c900e..0d668f471620 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -277,6 +277,7 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c index 16dc7bd5e120..4f4ccdf70dd0 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/ua101.c @@ -911,6 +911,7 @@ static struct snd_pcm_ops capture_pcm_ops = { .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops playback_pcm_ops = { @@ -923,6 +924,7 @@ static struct snd_pcm_ops playback_pcm_ops = { .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct uac_format_type_i_discrete_descriptor * diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 4ada98e16309..b8e0b8fda607 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1997,6 +1997,7 @@ static struct snd_pcm_ops snd_usb_playback_ops = { .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_usb_capture_ops = { @@ -2009,6 +2010,7 @@ static struct snd_pcm_ops snd_usb_capture_ops = { .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; -- GitLab From a32f66746c635ebf2341d99b3d4c0cc1c11b2cbf Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 18 Jan 2010 15:40:56 +0100 Subject: [PATCH 0870/3892] sound: seq_timer: simplify snd_seq_timer_set_tick_resolution() parameters As snd_seq_timer_set_tick_resolution() is always called with the same three fields of struct snd_seq_timer, it suffices to give that as the only parameter. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/core/seq/seq_timer.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index f745c317d6af..160b1bd0cd62 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -33,22 +33,21 @@ #define SKEW_BASE 0x10000 /* 16bit shift */ -static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick, - int tempo, int ppq) +static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) { - if (tempo < 1000000) - tick->resolution = (tempo * 1000) / ppq; + if (tmr->tempo < 1000000) + tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; else { /* might overflow.. */ unsigned int s; - s = tempo % ppq; - s = (s * 1000) / ppq; - tick->resolution = (tempo / ppq) * 1000; - tick->resolution += s; + s = tmr->tempo % tmr->ppq; + s = (s * 1000) / tmr->ppq; + tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; + tmr->tick.resolution += s; } - if (tick->resolution <= 0) - tick->resolution = 1; - snd_seq_timer_update_tick(tick, 0); + if (tmr->tick.resolution <= 0) + tmr->tick.resolution = 1; + snd_seq_timer_update_tick(&tmr->tick, 0); } /* create new timer (constructor) */ @@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); + snd_seq_timer_set_tick_resolution(tmr); tmr->running = 0; tmr->type = SNDRV_SEQ_TIMER_ALSA; @@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) spin_lock_irqsave(&tmr->lock, flags); if ((unsigned int)tempo != tmr->tempo) { tmr->tempo = tempo; - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); + snd_seq_timer_set_tick_resolution(tmr); } spin_unlock_irqrestore(&tmr->lock, flags); return 0; @@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) } tmr->ppq = ppq; - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); + snd_seq_timer_set_tick_resolution(tmr); spin_unlock_irqrestore(&tmr->lock, flags); return 0; } -- GitLab From d1db38c015a392b0ea8c15ab95abb3ee768b8d47 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 18 Jan 2010 15:44:04 +0100 Subject: [PATCH 0871/3892] sound: virtuoso: add Xonar DS support Add experimental support for the Asus Xonar DS. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- .../sound/alsa/ALSA-Configuration.txt | 2 +- sound/pci/Kconfig | 1 + sound/pci/oxygen/Makefile | 2 +- sound/pci/oxygen/virtuoso.c | 3 + sound/pci/oxygen/wm8766.h | 73 ++ sound/pci/oxygen/wm8776.h | 177 +++ sound/pci/oxygen/xonar.h | 2 + sound/pci/oxygen/xonar_wm87x6.c | 1021 +++++++++++++++++ 8 files changed, 1279 insertions(+), 2 deletions(-) create mode 100644 sound/pci/oxygen/wm8766.h create mode 100644 sound/pci/oxygen/wm8776.h create mode 100644 sound/pci/oxygen/xonar_wm87x6.c diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 8923597bd2bd..3579e8296998 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1923,7 +1923,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------- Module for sound cards based on the Asus AV100/AV200 chips, - i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST + i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST (Deluxe) and Essence STX. This module supports autoprobe and multiple cards. diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 351654cf7b09..1298c68d6bf0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -789,6 +789,7 @@ config SND_VIRTUOSO Say Y here to include support for sound cards based on the Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, Essence ST (Deluxe), and Essence STX. + Support for the DS is experimental. Support for the HDAV1.3 (Deluxe) is very experimental. To compile this driver as a module, choose M here: the module diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 389941cf6100..acd8f15f7bff 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -2,7 +2,7 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o snd-hifier-objs := hifier.o snd-oxygen-objs := oxygen.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ - xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o + xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o obj-$(CONFIG_SND_HIFIER) += snd-hifier.o diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 6accaf9580b2..563b6f50821f 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -49,6 +49,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, + { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; @@ -61,6 +62,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, return 0; if (get_xonar_cs43xx_model(chip, id) >= 0) return 0; + if (get_xonar_wm87x6_model(chip, id) >= 0) + return 0; return -EINVAL; } diff --git a/sound/pci/oxygen/wm8766.h b/sound/pci/oxygen/wm8766.h new file mode 100644 index 000000000000..e0e849a7eaeb --- /dev/null +++ b/sound/pci/oxygen/wm8766.h @@ -0,0 +1,73 @@ +#ifndef WM8766_H_INCLUDED +#define WM8766_H_INCLUDED + +#define WM8766_LDA1 0x00 +#define WM8766_RDA1 0x01 +#define WM8766_DAC_CTRL 0x02 +#define WM8766_INT_CTRL 0x03 +#define WM8766_LDA2 0x04 +#define WM8766_RDA2 0x05 +#define WM8766_LDA3 0x06 +#define WM8766_RDA3 0x07 +#define WM8766_MASTDA 0x08 +#define WM8766_DAC_CTRL2 0x09 +#define WM8766_DAC_CTRL3 0x0a +#define WM8766_MUTE1 0x0c +#define WM8766_MUTE2 0x0f +#define WM8766_RESET 0x1f + +/* LDAx/RDAx/MASTDA */ +#define WM8766_ATT_MASK 0x0ff +#define WM8766_UPDATE 0x100 +/* DAC_CTRL */ +#define WM8766_MUTEALL 0x001 +#define WM8766_DEEMPALL 0x002 +#define WM8766_PWDN 0x004 +#define WM8766_ATC 0x008 +#define WM8766_IZD 0x010 +#define WM8766_PL_LEFT_MASK 0x060 +#define WM8766_PL_LEFT_MUTE 0x000 +#define WM8766_PL_LEFT_LEFT 0x020 +#define WM8766_PL_LEFT_RIGHT 0x040 +#define WM8766_PL_LEFT_LRMIX 0x060 +#define WM8766_PL_RIGHT_MASK 0x180 +#define WM8766_PL_RIGHT_MUTE 0x000 +#define WM8766_PL_RIGHT_LEFT 0x080 +#define WM8766_PL_RIGHT_RIGHT 0x100 +#define WM8766_PL_RIGHT_LRMIX 0x180 +/* INT_CTRL */ +#define WM8766_FMT_MASK 0x003 +#define WM8766_FMT_RJUST 0x000 +#define WM8766_FMT_LJUST 0x001 +#define WM8766_FMT_I2S 0x002 +#define WM8766_FMT_DSP 0x003 +#define WM8766_LRP 0x004 +#define WM8766_BCP 0x008 +#define WM8766_IWL_MASK 0x030 +#define WM8766_IWL_16 0x000 +#define WM8766_IWL_20 0x010 +#define WM8766_IWL_24 0x020 +#define WM8766_IWL_32 0x030 +#define WM8766_PHASE_MASK 0x1c0 +/* DAC_CTRL2 */ +#define WM8766_ZCD 0x001 +#define WM8766_DZFM_MASK 0x006 +#define WM8766_DMUTE_MASK 0x038 +#define WM8766_DEEMP_MASK 0x1c0 +/* DAC_CTRL3 */ +#define WM8766_DACPD_MASK 0x00e +#define WM8766_PWRDNALL 0x010 +#define WM8766_MS 0x020 +#define WM8766_RATE_MASK 0x1c0 +#define WM8766_RATE_128 0x000 +#define WM8766_RATE_192 0x040 +#define WM8766_RATE_256 0x080 +#define WM8766_RATE_384 0x0c0 +#define WM8766_RATE_512 0x100 +#define WM8766_RATE_768 0x140 +/* MUTE1 */ +#define WM8766_MPD1 0x040 +/* MUTE2 */ +#define WM8766_MPD2 0x020 + +#endif diff --git a/sound/pci/oxygen/wm8776.h b/sound/pci/oxygen/wm8776.h new file mode 100644 index 000000000000..1a96f5615727 --- /dev/null +++ b/sound/pci/oxygen/wm8776.h @@ -0,0 +1,177 @@ +#ifndef WM8776_H_INCLUDED +#define WM8776_H_INCLUDED + +/* + * the following register names are from: + * wm8776.h -- WM8776 ASoC driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define WM8776_HPLVOL 0x00 +#define WM8776_HPRVOL 0x01 +#define WM8776_HPMASTER 0x02 +#define WM8776_DACLVOL 0x03 +#define WM8776_DACRVOL 0x04 +#define WM8776_DACMASTER 0x05 +#define WM8776_PHASESWAP 0x06 +#define WM8776_DACCTRL1 0x07 +#define WM8776_DACMUTE 0x08 +#define WM8776_DACCTRL2 0x09 +#define WM8776_DACIFCTRL 0x0a +#define WM8776_ADCIFCTRL 0x0b +#define WM8776_MSTRCTRL 0x0c +#define WM8776_PWRDOWN 0x0d +#define WM8776_ADCLVOL 0x0e +#define WM8776_ADCRVOL 0x0f +#define WM8776_ALCCTRL1 0x10 +#define WM8776_ALCCTRL2 0x11 +#define WM8776_ALCCTRL3 0x12 +#define WM8776_NOISEGATE 0x13 +#define WM8776_LIMITER 0x14 +#define WM8776_ADCMUX 0x15 +#define WM8776_OUTMUX 0x16 +#define WM8776_RESET 0x17 + + +/* HPLVOL/HPRVOL/HPMASTER */ +#define WM8776_HPATT_MASK 0x07f +#define WM8776_HPZCEN 0x080 +#define WM8776_UPDATE 0x100 + +/* DACLVOL/DACRVOL/DACMASTER */ +#define WM8776_DATT_MASK 0x0ff +/*#define WM8776_UPDATE 0x100*/ + +/* PHASESWAP */ +#define WM8776_PH_MASK 0x003 + +/* DACCTRL1 */ +#define WM8776_DZCEN 0x001 +#define WM8776_ATC 0x002 +#define WM8776_IZD 0x004 +#define WM8776_TOD 0x008 +#define WM8776_PL_LEFT_MASK 0x030 +#define WM8776_PL_LEFT_MUTE 0x000 +#define WM8776_PL_LEFT_LEFT 0x010 +#define WM8776_PL_LEFT_RIGHT 0x020 +#define WM8776_PL_LEFT_LRMIX 0x030 +#define WM8776_PL_RIGHT_MASK 0x0c0 +#define WM8776_PL_RIGHT_MUTE 0x000 +#define WM8776_PL_RIGHT_LEFT 0x040 +#define WM8776_PL_RIGHT_RIGHT 0x080 +#define WM8776_PL_RIGHT_LRMIX 0x0c0 + +/* DACMUTE */ +#define WM8776_DMUTE 0x001 + +/* DACCTRL2 */ +#define WM8776_DEEMPH 0x001 +#define WM8776_DZFM_MASK 0x006 +#define WM8776_DZFM_NONE 0x000 +#define WM8776_DZFM_LR 0x002 +#define WM8776_DZFM_BOTH 0x004 +#define WM8776_DZFM_EITHER 0x006 + +/* DACIFCTRL */ +#define WM8776_DACFMT_MASK 0x003 +#define WM8776_DACFMT_RJUST 0x000 +#define WM8776_DACFMT_LJUST 0x001 +#define WM8776_DACFMT_I2S 0x002 +#define WM8776_DACFMT_DSP 0x003 +#define WM8776_DACLRP 0x004 +#define WM8776_DACBCP 0x008 +#define WM8776_DACWL_MASK 0x030 +#define WM8776_DACWL_16 0x000 +#define WM8776_DACWL_20 0x010 +#define WM8776_DACWL_24 0x020 +#define WM8776_DACWL_32 0x030 + +/* ADCIFCTRL */ +#define WM8776_ADCFMT_MASK 0x003 +#define WM8776_ADCFMT_RJUST 0x000 +#define WM8776_ADCFMT_LJUST 0x001 +#define WM8776_ADCFMT_I2S 0x002 +#define WM8776_ADCFMT_DSP 0x003 +#define WM8776_ADCLRP 0x004 +#define WM8776_ADCBCP 0x008 +#define WM8776_ADCWL_MASK 0x030 +#define WM8776_ADCWL_16 0x000 +#define WM8776_ADCWL_20 0x010 +#define WM8776_ADCWL_24 0x020 +#define WM8776_ADCWL_32 0x030 +#define WM8776_ADCMCLK 0x040 +#define WM8776_ADCHPD 0x100 + +/* MSTRCTRL */ +#define WM8776_ADCRATE_MASK 0x007 +#define WM8776_ADCRATE_256 0x002 +#define WM8776_ADCRATE_384 0x003 +#define WM8776_ADCRATE_512 0x004 +#define WM8776_ADCRATE_768 0x005 +#define WM8776_ADCOSR 0x008 +#define WM8776_DACRATE_MASK 0x070 +#define WM8776_DACRATE_128 0x000 +#define WM8776_DACRATE_192 0x010 +#define WM8776_DACRATE_256 0x020 +#define WM8776_DACRATE_384 0x030 +#define WM8776_DACRATE_512 0x040 +#define WM8776_DACRATE_768 0x050 +#define WM8776_DACMS 0x080 +#define WM8776_ADCMS 0x100 + +/* PWRDOWN */ +#define WM8776_PDWN 0x001 +#define WM8776_ADCPD 0x002 +#define WM8776_DACPD 0x004 +#define WM8776_HPPD 0x008 +#define WM8776_AINPD 0x040 + +/* ADCLVOL/ADCRVOL */ +#define WM8776_AGMASK 0x0ff +#define WM8776_ZCA 0x100 + +/* ALCCTRL1 */ +#define WM8776_LCT_MASK 0x00f +#define WM8776_MAXGAIN_MASK 0x070 +#define WM8776_LCSEL_MASK 0x180 +#define WM8776_LCSEL_LIMITER 0x000 +#define WM8776_LCSEL_ALC_RIGHT 0x080 +#define WM8776_LCSEL_ALC_LEFT 0x100 +#define WM8776_LCSEL_ALC_STEREO 0x180 + +/* ALCCTRL2 */ +#define WM8776_HLD_MASK 0x00f +#define WM8776_ALCZC 0x080 +#define WM8776_LCEN 0x100 + +/* ALCCTRL3 */ +#define WM8776_ATK_MASK 0x00f +#define WM8776_DCY_MASK 0x0f0 + +/* NOISEGATE */ +#define WM8776_NGAT 0x001 +#define WM8776_NGTH_MASK 0x01c + +/* LIMITER */ +#define WM8776_MAXATTEN_MASK 0x00f +#define WM8776_TRANWIN_MASK 0x070 + +/* ADCMUX */ +#define WM8776_AMX_MASK 0x01f +#define WM8776_MUTERA 0x040 +#define WM8776_MUTELA 0x080 +#define WM8776_LRBOTH 0x100 + +/* OUTMUX */ +#define WM8776_MX_DAC 0x001 +#define WM8776_MX_AUX 0x002 +#define WM8776_MX_BYPASS 0x004 + +#endif diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index 89b3ed814d64..b35343b0a9a5 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h @@ -35,6 +35,8 @@ int get_xonar_pcm179x_model(struct oxygen *chip, const struct pci_device_id *id); int get_xonar_cs43xx_model(struct oxygen *chip, const struct pci_device_id *id); +int get_xonar_wm87x6_model(struct oxygen *chip, + const struct pci_device_id *id); /* HDMI helper functions */ diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c new file mode 100644 index 000000000000..7754db166d9e --- /dev/null +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -0,0 +1,1021 @@ +/* + * card driver for models with WM8776/WM8766 DACs (Xonar DS) + * + * Copyright (c) Clemens Ladisch + * + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver 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 driver; if not, see . + */ + +/* + * Xonar DS + * -------- + * + * CMI8788: + * + * SPI 0 -> WM8766 (surround, center/LFE, back) + * SPI 1 -> WM8776 (front, input) + * + * GPIO 4 <- headphone detect + * GPIO 6 -> route input jack to input 1/2 (1/0) + * GPIO 7 -> enable output to speakers + * GPIO 8 -> enable output to speakers + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xonar.h" +#include "wm8776.h" +#include "wm8766.h" + +#define GPIO_DS_HP_DETECT 0x0010 +#define GPIO_DS_INPUT_ROUTE 0x0040 +#define GPIO_DS_OUTPUT_ENABLE 0x0180 + +#define LC_CONTROL_LIMITER 0x40000000 +#define LC_CONTROL_ALC 0x20000000 + +struct xonar_wm87x6 { + struct xonar_generic generic; + u16 wm8776_regs[0x17]; + u16 wm8766_regs[0x10]; + struct snd_kcontrol *lc_controls[13]; +}; + +static void wm8776_write(struct oxygen *chip, + unsigned int reg, unsigned int value) +{ + struct xonar_wm87x6 *data = chip->model_data; + + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CLOCK_160 | + (1 << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_LO, + (reg << 9) | value); + if (reg < ARRAY_SIZE(data->wm8776_regs)) { + if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) + value &= ~WM8776_UPDATE; + data->wm8776_regs[reg] = value; + } +} + +static void wm8776_write_cached(struct oxygen *chip, + unsigned int reg, unsigned int value) +{ + struct xonar_wm87x6 *data = chip->model_data; + + if (reg >= ARRAY_SIZE(data->wm8776_regs) || + value != data->wm8776_regs[reg]) + wm8776_write(chip, reg, value); +} + +static void wm8766_write(struct oxygen *chip, + unsigned int reg, unsigned int value) +{ + struct xonar_wm87x6 *data = chip->model_data; + + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CLOCK_160 | + (0 << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_LO, + (reg << 9) | value); + if (reg < ARRAY_SIZE(data->wm8766_regs)) + data->wm8766_regs[reg] = value; +} + +static void wm8766_write_cached(struct oxygen *chip, + unsigned int reg, unsigned int value) +{ + struct xonar_wm87x6 *data = chip->model_data; + + if (reg >= ARRAY_SIZE(data->wm8766_regs) || + value != data->wm8766_regs[reg]) { + if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || + (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) + value &= ~WM8766_UPDATE; + wm8766_write(chip, reg, value); + } +} + +static void wm8776_registers_init(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + + wm8776_write(chip, WM8776_RESET, 0); + wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | + WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); + wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); + wm8776_write(chip, WM8776_DACIFCTRL, + WM8776_DACFMT_LJUST | WM8776_DACWL_24); + wm8776_write(chip, WM8776_ADCIFCTRL, + data->wm8776_regs[WM8776_ADCIFCTRL]); + wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]); + wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]); + wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]); + wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] | + WM8776_UPDATE); + wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]); + wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]); + wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]); + wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]); + wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE); +} + +static void wm8766_registers_init(struct oxygen *chip) +{ + wm8766_write(chip, WM8766_RESET, 0); + wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); + wm8766_write(chip, WM8766_DAC_CTRL2, + WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); + wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]); + wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]); + wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]); + wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]); + wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]); + wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE); +} + +static void wm8776_init(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + + data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN; + data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN; + data->wm8776_regs[WM8776_ADCIFCTRL] = + WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK; + data->wm8776_regs[WM8776_MSTRCTRL] = + WM8776_ADCRATE_256 | WM8776_DACRATE_256; + data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD; + data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA; + data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA; + data->wm8776_regs[WM8776_ADCMUX] = 0x001; + wm8776_registers_init(chip); +} + +static void xonar_ds_init(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + + data->generic.anti_pop_delay = 300; + data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; + + wm8776_init(chip); + wm8766_registers_init(chip); + + oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, + GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); + oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); + chip->interrupt_mask |= OXYGEN_INT_GPIO; + + xonar_enable_output(chip); + + snd_component_add(chip->card, "WM8776"); + snd_component_add(chip->card, "WM8766"); +} + +static void xonar_ds_cleanup(struct oxygen *chip) +{ + xonar_disable_output(chip); +} + +static void xonar_ds_suspend(struct oxygen *chip) +{ + xonar_ds_cleanup(chip); +} + +static void xonar_ds_resume(struct oxygen *chip) +{ + wm8776_registers_init(chip); + wm8766_registers_init(chip); + xonar_enable_output(chip); +} + +static void wm8776_adc_hardware_filter(unsigned int channel, + struct snd_pcm_hardware *hardware) +{ + if (channel == PCM_A) { + hardware->rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + hardware->rate_max = 96000; + } +} + +static void set_wm87x6_dac_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ +} + +static void set_wm8776_adc_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + u16 reg; + + reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256; + if (params_rate(params) > 48000) + reg |= WM8776_ADCOSR; + wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); +} + +static void update_wm8776_volume(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + u8 to_change; + + if (chip->dac_volume[0] == chip->dac_volume[1]) { + if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] || + chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) { + wm8776_write(chip, WM8776_DACMASTER, + chip->dac_volume[0] | WM8776_UPDATE); + data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0]; + data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0]; + } + } else { + to_change = (chip->dac_volume[0] != + data->wm8776_regs[WM8776_DACLVOL]) << 0; + to_change |= (chip->dac_volume[1] != + data->wm8776_regs[WM8776_DACLVOL]) << 1; + if (to_change & 1) + wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] | + ((to_change & 2) ? 0 : WM8776_UPDATE)); + if (to_change & 2) + wm8776_write(chip, WM8776_DACRVOL, + chip->dac_volume[1] | WM8776_UPDATE); + } +} + +static void update_wm87x6_volume(struct oxygen *chip) +{ + static const u8 wm8766_regs[6] = { + WM8766_LDA1, WM8766_RDA1, + WM8766_LDA2, WM8766_RDA2, + WM8766_LDA3, WM8766_RDA3, + }; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int i; + u8 to_change; + + update_wm8776_volume(chip); + if (chip->dac_volume[2] == chip->dac_volume[3] && + chip->dac_volume[2] == chip->dac_volume[4] && + chip->dac_volume[2] == chip->dac_volume[5] && + chip->dac_volume[2] == chip->dac_volume[6] && + chip->dac_volume[2] == chip->dac_volume[7]) { + to_change = 0; + for (i = 0; i < 6; ++i) + if (chip->dac_volume[2] != + data->wm8766_regs[wm8766_regs[i]]) + to_change = 1; + if (to_change) { + wm8766_write(chip, WM8766_MASTDA, + chip->dac_volume[2] | WM8766_UPDATE); + for (i = 0; i < 6; ++i) + data->wm8766_regs[wm8766_regs[i]] = + chip->dac_volume[2]; + } + } else { + to_change = 0; + for (i = 0; i < 6; ++i) + to_change |= (chip->dac_volume[2 + i] != + data->wm8766_regs[wm8766_regs[i]]) << i; + for (i = 0; i < 6; ++i) + if (to_change & (1 << i)) + wm8766_write(chip, wm8766_regs[i], + chip->dac_volume[2 + i] | + ((to_change & (0x3e << i)) + ? 0 : WM8766_UPDATE)); + } +} + +static void update_wm8776_mute(struct oxygen *chip) +{ + wm8776_write_cached(chip, WM8776_DACMUTE, + chip->dac_mute ? WM8776_DMUTE : 0); +} + +static void update_wm87x6_mute(struct oxygen *chip) +{ + update_wm8776_mute(chip); + wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD | + (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); +} + +static void xonar_ds_gpio_changed(struct oxygen *chip) +{ + u16 bits; + + bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); + snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); +} + +static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + u16 bit = ctl->private_value & 0xffff; + unsigned int reg_index = (ctl->private_value >> 16) & 0xff; + bool invert = (ctl->private_value >> 24) & 1; + + value->value.integer.value[0] = + ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert; + return 0; +} + +static int wm8776_bit_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + u16 bit = ctl->private_value & 0xffff; + u16 reg_value; + unsigned int reg_index = (ctl->private_value >> 16) & 0xff; + bool invert = (ctl->private_value >> 24) & 1; + int changed; + + mutex_lock(&chip->mutex); + reg_value = data->wm8776_regs[reg_index] & ~bit; + if (value->value.integer.value[0] ^ invert) + reg_value |= bit; + changed = reg_value != data->wm8776_regs[reg_index]; + if (changed) + wm8776_write(chip, reg_index, reg_value); + mutex_unlock(&chip->mutex); + return changed; +} + +static int wm8776_field_enum_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const hld[16] = { + "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", + "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", + "341 ms", "683 ms", "1.37 s", "2.73 s", + "5.46 s", "10.9 s", "21.8 s", "43.7 s", + }; + static const char *const atk_lim[11] = { + "0.25 ms", "0.5 ms", "1 ms", "2 ms", + "4 ms", "8 ms", "16 ms", "32 ms", + "64 ms", "128 ms", "256 ms", + }; + static const char *const atk_alc[11] = { + "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", + "134 ms", "269 ms", "538 ms", "1.08 s", + "2.15 s", "4.3 s", "8.6 s", + }; + static const char *const dcy_lim[11] = { + "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", + "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", + "307 ms", "614 ms", "1.23 s", + }; + static const char *const dcy_alc[11] = { + "33.5 ms", "67.0 ms", "134 ms", "268 ms", + "536 ms", "1.07 s", "2.14 s", "4.29 s", + "8.58 s", "17.2 s", "34.3 s", + }; + static const char *const tranwin[8] = { + "0 us", "62.5 us", "125 us", "250 us", + "500 us", "1 ms", "2 ms", "4 ms", + }; + u8 max; + const char *const *names; + + max = (ctl->private_value >> 12) & 0xf; + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = max + 1; + if (info->value.enumerated.item > max) + info->value.enumerated.item = max; + switch ((ctl->private_value >> 24) & 0x1f) { + case WM8776_ALCCTRL2: + names = hld; + break; + case WM8776_ALCCTRL3: + if (((ctl->private_value >> 20) & 0xf) == 0) { + if (ctl->private_value & LC_CONTROL_LIMITER) + names = atk_lim; + else + names = atk_alc; + } else { + if (ctl->private_value & LC_CONTROL_LIMITER) + names = dcy_lim; + else + names = dcy_alc; + } + break; + case WM8776_LIMITER: + names = tranwin; + break; + default: + return -ENXIO; + } + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int wm8776_field_volume_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 1; + info->value.integer.min = (ctl->private_value >> 8) & 0xf; + info->value.integer.max = (ctl->private_value >> 12) & 0xf; + return 0; +} + +static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int value, reg_index, mode; + u8 min, max, shift; + u16 mask, reg_value; + bool invert; + + if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == + WM8776_LCSEL_LIMITER) + mode = LC_CONTROL_LIMITER; + else + mode = LC_CONTROL_ALC; + if (!(ctl->private_value & mode)) + return; + + value = ctl->private_value & 0xf; + min = (ctl->private_value >> 8) & 0xf; + max = (ctl->private_value >> 12) & 0xf; + mask = (ctl->private_value >> 16) & 0xf; + shift = (ctl->private_value >> 20) & 0xf; + reg_index = (ctl->private_value >> 24) & 0x1f; + invert = (ctl->private_value >> 29) & 0x1; + + if (invert) + value = max - (value - min); + reg_value = data->wm8776_regs[reg_index]; + reg_value &= ~(mask << shift); + reg_value |= value << shift; + wm8776_write_cached(chip, reg_index, reg_value); +} + +static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value) +{ + struct oxygen *chip = ctl->private_data; + u8 min, max; + int changed; + + min = (ctl->private_value >> 8) & 0xf; + max = (ctl->private_value >> 12) & 0xf; + if (value < min || value > max) + return -EINVAL; + mutex_lock(&chip->mutex); + changed = value != (ctl->private_value & 0xf); + if (changed) { + ctl->private_value = (ctl->private_value & ~0xf) | value; + wm8776_field_set_from_ctl(ctl); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int wm8776_field_enum_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = ctl->private_value & 0xf; + return 0; +} + +static int wm8776_field_volume_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + value->value.integer.value[0] = ctl->private_value & 0xf; + return 0; +} + +static int wm8776_field_enum_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + return wm8776_field_set(ctl, value->value.enumerated.item[0]); +} + +static int wm8776_field_volume_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + return wm8776_field_set(ctl, value->value.integer.value[0]); +} + +static int wm8776_hp_vol_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0x79 - 60; + info->value.integer.max = 0x7f; + return 0; +} + +static int wm8776_hp_vol_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = + data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK; + value->value.integer.value[1] = + data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK; + mutex_unlock(&chip->mutex); + return 0; +} + +static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + u8 to_update; + + mutex_lock(&chip->mutex); + to_update = (value->value.integer.value[0] != + (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK)) + << 0; + to_update |= (value->value.integer.value[1] != + (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK)) + << 1; + if (value->value.integer.value[0] == value->value.integer.value[1]) { + if (to_update) { + wm8776_write(chip, WM8776_HPMASTER, + value->value.integer.value[0] | + WM8776_HPZCEN | WM8776_UPDATE); + data->wm8776_regs[WM8776_HPLVOL] = + value->value.integer.value[0] | WM8776_HPZCEN; + data->wm8776_regs[WM8776_HPRVOL] = + value->value.integer.value[0] | WM8776_HPZCEN; + } + } else { + if (to_update & 1) + wm8776_write(chip, WM8776_HPLVOL, + value->value.integer.value[0] | + WM8776_HPZCEN | + ((to_update & 2) ? 0 : WM8776_UPDATE)); + if (to_update & 2) + wm8776_write(chip, WM8776_HPRVOL, + value->value.integer.value[1] | + WM8776_HPZCEN | WM8776_UPDATE); + } + mutex_unlock(&chip->mutex); + return to_update != 0; +} + +static int wm8776_input_mux_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int mux_bit = ctl->private_value; + + value->value.integer.value[0] = + !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit); + return 0; +} + +static int wm8776_input_mux_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int mux_bit = ctl->private_value; + u16 reg; + int changed; + + mutex_lock(&chip->mutex); + reg = data->wm8776_regs[WM8776_ADCMUX]; + if (value->value.integer.value[0]) { + reg &= ~0x003; + reg |= mux_bit; + } else + reg &= ~mux_bit; + changed = reg != data->wm8776_regs[WM8776_ADCMUX]; + if (changed) { + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + reg & 1 ? GPIO_DS_INPUT_ROUTE : 0, + GPIO_DS_INPUT_ROUTE); + wm8776_write(chip, WM8776_ADCMUX, reg); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int wm8776_input_vol_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0xa5; + info->value.integer.max = 0xff; + return 0; +} + +static int wm8776_input_vol_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = + data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK; + value->value.integer.value[1] = + data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK; + mutex_unlock(&chip->mutex); + return 0; +} + +static int wm8776_input_vol_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + int changed = 0; + + mutex_lock(&chip->mutex); + changed = (value->value.integer.value[0] != + (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) || + (value->value.integer.value[1] != + (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK)); + wm8776_write_cached(chip, WM8776_ADCLVOL, + value->value.integer.value[0] | WM8776_ZCA); + wm8776_write_cached(chip, WM8776_ADCRVOL, + value->value.integer.value[1] | WM8776_ZCA); + mutex_unlock(&chip->mutex); + return changed; +} + +static int wm8776_level_control_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "None", "Peak Limiter", "Automatic Level Control" + }; + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item >= 3) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int wm8776_level_control_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + + if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN)) + value->value.enumerated.item[0] = 0; + else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == + WM8776_LCSEL_LIMITER) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + return 0; +} + +static void activate_control(struct oxygen *chip, + struct snd_kcontrol *ctl, unsigned int mode) +{ + unsigned int access; + + if (ctl->private_value & mode) + access = 0; + else + access = SNDRV_CTL_ELEM_ACCESS_INACTIVE; + if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) { + ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } +} + +static int wm8776_level_control_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int mode = 0, i; + u16 ctrl1, ctrl2; + int changed; + + if (value->value.enumerated.item[0] >= 3) + return -EINVAL; + mutex_lock(&chip->mutex); + changed = value->value.enumerated.item[0] != ctl->private_value; + if (changed) { + ctl->private_value = value->value.enumerated.item[0]; + ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1]; + ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2]; + switch (value->value.enumerated.item[0]) { + default: + wm8776_write_cached(chip, WM8776_ALCCTRL2, + ctrl2 & ~WM8776_LCEN); + break; + case 1: + wm8776_write_cached(chip, WM8776_ALCCTRL1, + (ctrl1 & ~WM8776_LCSEL_MASK) | + WM8776_LCSEL_LIMITER); + wm8776_write_cached(chip, WM8776_ALCCTRL2, + ctrl2 | WM8776_LCEN); + mode = LC_CONTROL_LIMITER; + break; + case 2: + wm8776_write_cached(chip, WM8776_ALCCTRL1, + (ctrl1 & ~WM8776_LCSEL_MASK) | + WM8776_LCSEL_ALC_STEREO); + wm8776_write_cached(chip, WM8776_ALCCTRL2, + ctrl2 | WM8776_LCEN); + mode = LC_CONTROL_ALC; + break; + } + for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i) + activate_control(chip, data->lc_controls[i], mode); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { + "None", "High-pass Filter" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + + value->value.enumerated.item[0] = + !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD); + return 0; +} + +static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_wm87x6 *data = chip->model_data; + unsigned int reg; + int changed; + + mutex_lock(&chip->mutex); + reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD; + if (!value->value.enumerated.item[0]) + reg |= WM8776_ADCHPD; + changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL]; + if (changed) + wm8776_write(chip, WM8776_ADCIFCTRL, reg); + mutex_unlock(&chip->mutex); + return changed; +} + +#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = snd_ctl_boolean_mono_info, \ + .get = wm8776_bit_switch_get, \ + .put = wm8776_bit_switch_put, \ + .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \ +} +#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = (initval) | ((min) << 8) | ((max) << 12) | \ + ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags) +#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\ + _WM8776_FIELD_CTL(xname " Capture Enum", \ + reg, shift, init, min, max, mask, flags), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_INACTIVE, \ + .info = wm8776_field_enum_info, \ + .get = wm8776_field_enum_get, \ + .put = wm8776_field_enum_put, \ +} +#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \ + _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_INACTIVE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = wm8776_field_volume_info, \ + .get = wm8776_field_volume_get, \ + .put = wm8776_field_volume_put, \ + .tlv = { .p = tlv_p }, \ +} + +static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0); + +static const struct snd_kcontrol_new ds_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Volume", + .info = wm8776_hp_vol_info, + .get = wm8776_hp_vol_get, + .put = wm8776_hp_vol_put, + .tlv = { .p = wm8776_hp_db_scale }, + }, + WM8776_BIT_SWITCH("Headphone Playback Switch", + WM8776_PWRDOWN, WM8776_HPPD, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Capture Volume", + .info = wm8776_input_vol_info, + .get = wm8776_input_vol_get, + .put = wm8776_input_vol_put, + .tlv = { .p = wm8776_adc_db_scale }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Capture Switch", + .info = snd_ctl_boolean_mono_info, + .get = wm8776_input_mux_get, + .put = wm8776_input_mux_put, + .private_value = 1 << 0, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Switch", + .info = snd_ctl_boolean_mono_info, + .get = wm8776_input_mux_get, + .put = wm8776_input_mux_put, + .private_value = 1 << 1, + }, + WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Filter Capture Enum", + .info = hpf_info, + .get = hpf_get, + .put = hpf_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Level Control Capture Enum", + .info = wm8776_level_control_info, + .get = wm8776_level_control_get, + .put = wm8776_level_control_put, + .private_value = 0, + }, +}; +static const struct snd_kcontrol_new lc_controls[] = { + WM8776_FIELD_CTL_VOLUME("Limiter Threshold", + WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, + LC_CONTROL_LIMITER, wm8776_lct_db_scale), + WM8776_FIELD_CTL_ENUM("Limiter Attack Time", + WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, + LC_CONTROL_LIMITER), + WM8776_FIELD_CTL_ENUM("Limiter Decay Time", + WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, + LC_CONTROL_LIMITER), + WM8776_FIELD_CTL_ENUM("Limiter Transient Window", + WM8776_LIMITER, 4, 2, 0, 7, 0x7, + LC_CONTROL_LIMITER), + WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation", + WM8776_LIMITER, 0, 6, 3, 12, 0xf, + LC_CONTROL_LIMITER, + wm8776_maxatten_lim_db_scale), + WM8776_FIELD_CTL_VOLUME("ALC Target Level", + WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, + LC_CONTROL_ALC, wm8776_lct_db_scale), + WM8776_FIELD_CTL_ENUM("ALC Attack Time", + WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, + LC_CONTROL_ALC), + WM8776_FIELD_CTL_ENUM("ALC Decay Time", + WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, + LC_CONTROL_ALC), + WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain", + WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7, + LC_CONTROL_ALC, wm8776_maxgain_db_scale), + WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation", + WM8776_LIMITER, 0, 10, 10, 15, 0xf, + LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale), + WM8776_FIELD_CTL_ENUM("ALC Hold Time", + WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf, + LC_CONTROL_ALC), + WM8776_BIT_SWITCH("Noise Gate Capture Switch", + WM8776_NOISEGATE, WM8776_NGAT, 0, + LC_CONTROL_ALC), + WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold", + WM8776_NOISEGATE, 2, 0, 0, 7, 0x7, + LC_CONTROL_ALC, wm8776_ngth_db_scale), +}; + +static int xonar_ds_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "CD Capture ", 11)) + return 1; /* no CD input */ + return 0; +} + +static int xonar_ds_mixer_init(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + unsigned int i; + struct snd_kcontrol *ctl; + int err; + + for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) { + ctl = snd_ctl_new1(&ds_controls[i], chip); + if (!ctl) + return -ENOMEM; + err = snd_ctl_add(chip->card, ctl); + if (err < 0) + return err; + } + BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); + for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { + ctl = snd_ctl_new1(&lc_controls[i], chip); + if (!ctl) + return -ENOMEM; + err = snd_ctl_add(chip->card, ctl); + if (err < 0) + return err; + data->lc_controls[i] = ctl; + } + return 0; +} + +static const struct oxygen_model model_xonar_ds = { + .shortname = "Xonar DS", + .longname = "Asus Virtuoso 200", + .chip = "AV200", + .init = xonar_ds_init, + .control_filter = xonar_ds_control_filter, + .mixer_init = xonar_ds_mixer_init, + .cleanup = xonar_ds_cleanup, + .suspend = xonar_ds_suspend, + .resume = xonar_ds_resume, + .pcm_hardware_filter = wm8776_adc_hardware_filter, + .get_i2s_mclk = oxygen_default_i2s_mclk, + .set_dac_params = set_wm87x6_dac_params, + .set_adc_params = set_wm8776_adc_params, + .update_dac_volume = update_wm87x6_volume, + .update_dac_mute = update_wm87x6_mute, + .gpio_changed = xonar_ds_gpio_changed, + .dac_tlv = wm87x6_dac_db_scale, + .model_data_size = sizeof(struct xonar_wm87x6), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_1, + .dac_channels = 8, + .dac_volume_min = 255 - 2*60, + .dac_volume_max = 255, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +int __devinit get_xonar_wm87x6_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + switch (id->subdevice) { + case 0x838e: + chip->model = model_xonar_ds; + break; + default: + return -EINVAL; + } + return 0; +} -- GitLab From e3deec090558d5cb5ffdc574e5560f3ed9723394 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 3 Nov 2009 12:33:07 -0600 Subject: [PATCH 0872/3892] [SCSI] eliminate potential kmalloc failure in scsi_get_vpd_page() The best way to fix this is to eliminate the intenal kmalloc() and make the caller allocate the required amount of storage. Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 40 ++++++++++++-------------------------- drivers/scsi/sd.c | 26 ++++++++++++++----------- drivers/scsi/ses.c | 10 +++++++--- include/scsi/scsi_device.h | 3 ++- 4 files changed, 36 insertions(+), 43 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a60da5555577..513661f45e5f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1026,55 +1026,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, * responsible for calling kfree() on this pointer when it is no longer * needed. If we cannot retrieve the VPD page this routine returns %NULL. */ -unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) +int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, + int buf_len) { int i, result; - unsigned int len; - const unsigned int init_vpd_len = 255; - unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL); - - if (!buf) - return NULL; /* Ask for all the pages supported by this device */ - result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); + result = scsi_vpd_inquiry(sdev, buf, 0, buf_len); if (result) goto fail; /* If the user actually wanted this page, we can skip the rest */ if (page == 0) - return buf; + return -EINVAL; - for (i = 0; i < buf[3]; i++) + for (i = 0; i < min((int)buf[3], buf_len - 4); i++) if (buf[i + 4] == page) goto found; + + if (i < buf[3] && i > buf_len) + /* ran off the end of the buffer, give us benefit of doubt */ + goto found; /* The device claims it doesn't support the requested page */ goto fail; found: - result = scsi_vpd_inquiry(sdev, buf, page, 255); + result = scsi_vpd_inquiry(sdev, buf, page, buf_len); if (result) goto fail; - /* - * Some pages are longer than 255 bytes. The actual length of - * the page is returned in the header. - */ - len = ((buf[2] << 8) | buf[3]) + 4; - if (len <= init_vpd_len) - return buf; - - kfree(buf); - buf = kmalloc(len, GFP_KERNEL); - result = scsi_vpd_inquiry(sdev, buf, page, len); - if (result) - goto fail; - - return buf; + return 0; fail: - kfree(buf); - return NULL; + return -EINVAL; } EXPORT_SYMBOL_GPL(scsi_get_vpd_page); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 255da53e5a01..c5e9a99d4066 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1946,13 +1946,13 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) { struct request_queue *q = sdkp->disk->queue; unsigned int sector_sz = sdkp->device->sector_size; - char *buffer; + const int vpd_len = 32; + unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); - /* Block Limits VPD */ - buffer = scsi_get_vpd_page(sdkp->device, 0xb0); - - if (buffer == NULL) - return; + if (!buffer || + /* Block Limits VPD */ + scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) + goto out; blk_queue_io_min(sdkp->disk->queue, get_unaligned_be16(&buffer[6]) * sector_sz); @@ -1984,6 +1984,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) get_unaligned_be32(&buffer[32]) & ~(1 << 31); } + out: kfree(buffer); } @@ -1993,20 +1994,23 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) */ static void sd_read_block_characteristics(struct scsi_disk *sdkp) { - char *buffer; + unsigned char *buffer; u16 rot; + const int vpd_len = 32; - /* Block Device Characteristics VPD */ - buffer = scsi_get_vpd_page(sdkp->device, 0xb1); + buffer = kmalloc(vpd_len, GFP_KERNEL); - if (buffer == NULL) - return; + if (!buffer || + /* Block Device Characteristics VPD */ + scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len)) + goto out; rot = get_unaligned_be16(&buffer[4]); if (rot == 1) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue); + out: kfree(buffer); } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 55b034b72708..1d7a8780e00c 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -448,13 +448,17 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, .addr = 0, }; - buf = scsi_get_vpd_page(sdev, 0x83); - if (!buf) - return; + buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL); + if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE)) + goto free; ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); vpd_len = ((buf[2] << 8) | buf[3]) + 4; + kfree(buf); + buf = kmalloc(vpd_len, GFP_KERNEL); + if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len)) + goto free; desc = buf + 4; while (desc < buf + vpd_len) { diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 7c4449900c24..d80b6dbed1ca 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -348,7 +348,8 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp, struct scsi_sense_hdr *); extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, struct scsi_sense_hdr *sshdr); -extern unsigned char *scsi_get_vpd_page(struct scsi_device *, u8 page); +extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, + int buf_len); extern int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state); extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, -- GitLab From 40c4f3e4eaa7eda2b0a00abd4d69778808d26f77 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 4 Dec 2009 20:38:49 +0100 Subject: [PATCH 0873/3892] [SCSI] libsrp: fix typo -- replace RDAM by RDMA Fixed a typo in libsrp.c: replaced two occurrences of 'RDAM' by 'RDMA'. Signed-off-by: Bart Van Assche Acked-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/libsrp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index ab19b3b4be52..f79602f28ba7 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -1,5 +1,5 @@ /* - * SCSI RDAM Protocol lib functions + * SCSI RDMA Protocol lib functions * * Copyright (C) 2006 FUJITA Tomonori * @@ -440,6 +440,6 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, } EXPORT_SYMBOL_GPL(srp_cmd_queue); -MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions"); +MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions"); MODULE_AUTHOR("FUJITA Tomonori"); MODULE_LICENSE("GPL"); -- GitLab From 9b7dac086bec7c71722d6e79464609e17f0996e7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 4 Dec 2009 20:43:37 +0100 Subject: [PATCH 0874/3892] [SCSI] ibmvscsi: fix a typo in a source code comment Signed-off-by: Bart Van Assche Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e475b7957c2d..e3a18e0ef276 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -40,7 +40,7 @@ * (CRQ), which is just a buffer of 16 byte entries in the receiver's * Senders cannot access the buffer directly, but send messages by * making a hypervisor call and passing in the 16 bytes. The hypervisor - * puts the message in the next 16 byte space in round-robbin fashion, + * puts the message in the next 16 byte space in round-robin fashion, * turns on the high order bit of the message (the valid bit), and * generates an interrupt to the receiver (if interrupts are turned on.) * The receiver just turns off the valid bit when they have copied out -- GitLab From 8fe79162a6807bf120140d64e96da54fc273b88b Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:57 -0800 Subject: [PATCH 0875/3892] [SCSI] eata: fix buffer overflow Allows i == MAX_INT_PARAM, which is out of range. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/eata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c7076ce25e21..3c5abf7cd762 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1509,7 +1509,7 @@ static int option_setup(char *str) char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { + while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) -- GitLab From 4a02462af1f4c3498e6a330ffd5c063118309b31 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:59 -0800 Subject: [PATCH 0876/3892] [SCSI] u14-34f: fix buffer overflow This allows i == MAX_INT_PARAM, which is out of range for ints[] Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/u14-34f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 54023d41fd15..26e8e0e6b8dd 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1070,7 +1070,7 @@ static int option_setup(char *str) { char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { + while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) cur++; -- GitLab From 340f052001d46aff9e7e853c492e0d3f5554d42f Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 14:08:56 -0800 Subject: [PATCH 0877/3892] [SCSI] ibmmca: fix buffer overflow Allows i == IM_MAX_HOSTS, which is out of range. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/ibmmca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 9c1e6a5b5af0..9a4b69d4f4eb 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -2336,7 +2336,7 @@ static int option_setup(char *str) char *cur = str; int i = 1; - while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) { + while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) { ints[i++] = simple_strtoul(cur, NULL, 0); if ((cur = strchr(cur, ',')) != NULL) cur++; -- GitLab From e47c11c7a402a054a85cb917a6ed020f6b5fae04 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Mon, 14 Dec 2009 21:21:56 +0100 Subject: [PATCH 0878/3892] [SCSI] fusion: fix warning when not using procfs Fixes the following warning: drivers/message/fusion/mptbase.c:129: warning: 'mpt_proc_root_dir' defined but not used also moves it from public data section since it is static. Signed-off-by: Erik Ekman Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 44d2037e9e56..5382b5a44aff 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -126,8 +126,6 @@ static int mfcounter = 0; * Public data... */ -static struct proc_dir_entry *mpt_proc_root_dir; - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -146,6 +144,9 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *mpt_proc_root_dir; +#endif /* * Driver Callback Index's -- GitLab From f2818663c82b7297ff4aa38cbddb870dc02f7104 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 15 Dec 2009 09:26:06 +0100 Subject: [PATCH 0879/3892] [SCSI] scsi_transport_fc: Remove capping from dev_loss_tmo Currently dev_loss_tmo is capped by SCSI_DEVICE_BLOCK_MAX_TIMEOUT. This causes problem with multipathing when the 'no_path_retry' setting exceeds the dev_loss_tmo setting, as then the system might run into a deadlock when all paths have been removed temporarily for longer than dev_loss_tmo. The principal reasons for the capping has been that we should not allow a remote port to remain in status 'blocked' indefinitely, so the capping is there to ensure that the port status is being reset eventually. However, the fast_io_fail_tmo will also move the remote port out of the 'blocked' state, so for any HBA driver implementing both the capping should really be on the fast_io_fail_tmo, and not on the dev_loss_tmo. This patch implements just that, ie the fast_io_fail_tmo is capped to SCSI_DEVICE_BLOCK_TIMEOUT and the capping is removed from dev_loss_tmo when fast_io_fail_tmo is set. This allows us to synchronize the dev_loss_tmo setting to the 'no_path_retry' setting from multipathing thus avoiding the deadlock. Signed-off-by: Hannes Reinecke Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 653f22a8deb9..79660ee3e211 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -475,7 +475,8 @@ MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC transport should" " insulate the loss of a remote port. Once this value is" " exceeded, the scsi target is removed. Value should be" - " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); + " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" + " fast_io_fail_tmo is not set."); /* * Netlink Infrastructure @@ -842,9 +843,17 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || - (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) + if ((*cp && (*cp != '\n')) || (val < 0)) return -EINVAL; + + /* + * If fast_io_fail is off we have to cap + * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT + */ + if (rport->fast_io_fail_tmo == -1 && + val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) + return -EINVAL; + i->f->set_rport_dev_loss_tmo(rport, val); return count; } @@ -925,9 +934,16 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, rport->fast_io_fail_tmo = -1; else { val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || - (val < 0) || (val >= rport->dev_loss_tmo)) + if ((*cp && (*cp != '\n')) || (val < 0)) return -EINVAL; + /* + * Cap fast_io_fail by dev_loss_tmo or + * SCSI_DEVICE_BLOCK_MAX_TIMEOUT. + */ + if ((val >= rport->dev_loss_tmo) || + (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) + return -EINVAL; + rport->fast_io_fail_tmo = val; } return count; -- GitLab From 02507a80b35edd720480540d917e9f92cc371009 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 5 Dec 2009 12:30:42 +1100 Subject: [PATCH 0880/3892] [SCSI] mac_esp: fix PIO mode, take 2 The mac_esp PIO algorithm no longer works in 2.6.31 and crashes my Centris 660av. So here's a better one. Also, force async with esp_set_offset() rather than esp_slave_configure(). One of the SCSI drives I tested still doesn't like the PIO mode and fails with "esp: esp0: Reconnect IRQ2 timeout" (the same drive works fine in PDMA mode). This failure happens when esp_reconnect_with_tag() tries to read in two tag bytes but the chip only provides one (0x20). I don't know what causes this. I decided not to waste any more time trying to fix it because the best solution is to rip out the PIO mode altogether and use the DMA engine. Signed-off-by: Finn Thain Signed-off-by: James Bottomley --- drivers/scsi/esp_scsi.c | 14 ++---- drivers/scsi/mac_esp.c | 95 +++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index a680e18b5f3b..e2bc779f86c1 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) if (offset > 15) goto do_reject; - if (esp->flags & ESP_FLAG_DISABLE_SYNC) - offset = 0; - if (offset) { int one_clock; @@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev) struct esp_target_data *tp = &esp->target[dev->id]; int goal_tags, queue_depth; - if (esp->flags & ESP_FLAG_DISABLE_SYNC) { - /* Bypass async domain validation */ - dev->ppr = 0; - dev->sdtr = 0; - } - goal_tags = 0; if (dev->tagged_supported) { @@ -2660,7 +2651,10 @@ static void esp_set_offset(struct scsi_target *target, int offset) struct esp *esp = shost_priv(host); struct esp_target_data *tp = &esp->target[target->id]; - tp->nego_goal_offset = offset; + if (esp->flags & ESP_FLAG_DISABLE_SYNC) + tp->nego_goal_offset = 0; + else + tp->nego_goal_offset = offset; tp->flags |= ESP_TGT_CHECK_NEGO; } diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index c24e86f07804..dd808ae942a1 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -22,7 +22,6 @@ #include #include - #include #include @@ -279,24 +278,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, * Programmed IO routines follow. */ -static inline int mac_esp_wait_for_fifo(struct esp *esp) +static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp) { int i = 500000; do { - if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) - return 0; + unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + if (fbytes) + return fbytes; udelay(2); } while (--i); printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", esp_read8(ESP_STATUS)); - return 1; + return 0; } static inline int mac_esp_wait_for_intr(struct esp *esp) { + struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); int i = 500000; do { @@ -308,6 +310,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) } while (--i); printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); + mep->error = 1; return 1; } @@ -347,11 +350,10 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - unsigned long flags; struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); u8 *fifo = esp->regs + ESP_FDATA * 16; - local_irq_save(flags); + disable_irq(esp->host->irq); cmd &= ~ESP_CMD_DMA; mep->error = 0; @@ -359,11 +361,35 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, if (write) { scsi_esp_cmd(esp, cmd); - if (!mac_esp_wait_for_intr(esp)) { - if (mac_esp_wait_for_fifo(esp)) - esp_count = 0; - } else { - esp_count = 0; + while (1) { + unsigned int n; + + n = mac_esp_wait_for_fifo(esp); + if (!n) + break; + + if (n > esp_count) + n = esp_count; + esp_count -= n; + + MAC_ESP_PIO_LOOP("%2@,%0@+", n); + + if (!esp_count) + break; + + if (mac_esp_wait_for_intr(esp)) + break; + + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) + break; + + scsi_esp_cmd(esp, ESP_CMD_TI); } } else { scsi_esp_cmd(esp, ESP_CMD_FLUSH); @@ -374,47 +400,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); scsi_esp_cmd(esp, cmd); - } - - while (esp_count) { - unsigned int n; - - if (mac_esp_wait_for_intr(esp)) { - mep->error = 1; - break; - } - - if (esp->sreg & ESP_STAT_SPAM) { - printk(KERN_ERR PFX "gross error\n"); - mep->error = 1; - break; - } - n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - if (write) { - if (n > esp_count) - n = esp_count; - esp_count -= n; - - MAC_ESP_PIO_LOOP("%2@,%0@+", n); + while (esp_count) { + unsigned int n; - if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP) + if (mac_esp_wait_for_intr(esp)) break; - if (esp_count) { - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) - break; + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP)) + break; - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) break; - n = MAC_ESP_FIFO_SIZE - n; + n = MAC_ESP_FIFO_SIZE - + (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); if (n > esp_count) n = esp_count; @@ -429,7 +432,7 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, } } - local_irq_restore(flags); + enable_irq(esp->host->irq); } static int mac_esp_irq_pending(struct esp *esp) -- GitLab From 65f89c2396aa113a06fe7e2f6ba46f0712cb4806 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:01:13 +0530 Subject: [PATCH 0881/3892] [SCSI] mptfusion: Added MPI_SCSIIO_CONTROL_HEADOFQ priority There is a 'ioprio' field in the BIO and the Request structure. check this priority field and set MPI_SCSIIO_CONTROL_HEADOFQ to pass down I/O priority. An enhancement to the LSI Disk Array Controller firmware is being developed to look at the Head Of Queue bit to allow I/Os with the HOQ bit set to be processed before I/Os which do not have the HOQ bit set. In order to set the HOQ bit, the mpt fusion driver needs to look at the 'ioprio' field in the request structure associated with the scsi command. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 57752751712b..8128d3095f9f 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1438,9 +1438,14 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; - } else { + if (SCpnt->request && SCpnt->request->ioprio) { + if (((SCpnt->request->ioprio & 0x7) == 1) || + !(SCpnt->request->ioprio & 0x7)) + scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ; + } + } else scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; - } + /* Use the above information to set up the message frame */ -- GitLab From e0f553ab58f478321717100e44b28f765bd2a045 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:01:58 +0530 Subject: [PATCH 0882/3892] [SCSI] mptfusion: Added sysfs expander manufacture information at the time of expander add. Added new function mptsas_exp_manufacture_info, which will obtain the REPORT_MANUFACTURING, and fill the details into the sas_expander_device object when the expander port is created. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 186 ++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83873e3d0ce7..1b7f550daebc 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2686,6 +2686,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, return error; } +struct rep_manu_request{ + u8 smp_frame_type; + u8 function; + u8 reserved; + u8 request_length; +}; + +struct rep_manu_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x01 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved0[2]; + u8 sas_format:1; + u8 reserved1:7; + u8 reserved2[3]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u16 component_id; + u8 component_revision_id; + u8 reserved3; + u8 vendor_specific[8]; +}; + +/** + * mptsas_exp_repmanufacture_info - + * @ioc: per adapter object + * @sas_address: expander sas address + * @edev: the sas_expander_device object + * + * Fills in the sas_expander_device object when SMP port is created. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, + u64 sas_address, struct sas_expander_device *edev) +{ + MPT_FRAME_HDR *mf; + SmpPassthroughRequest_t *smpreq; + SmpPassthroughReply_t *smprep; + struct rep_manu_reply *manufacture_reply; + struct rep_manu_request *manufacture_request; + int ret; + int flagsLength; + unsigned long timeleft; + char *psge; + unsigned long flags; + void *data_out = NULL; + dma_addr_t data_out_dma = 0; + u32 sz; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); + if (ret) + goto out; + + mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); + if (!mf) { + ret = -ENOMEM; + goto out_unlock; + } + + smpreq = (SmpPassthroughRequest_t *)mf; + memset(smpreq, 0, sizeof(*smpreq)); + + sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + + data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + ret = -ENOMEM; + goto put_mf; + } + + manufacture_request = data_out; + manufacture_request->smp_frame_type = 0x40; + manufacture_request->function = 1; + manufacture_request->reserved = 0; + manufacture_request->request_length = 0; + + smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + smpreq->PhysicalPort = 0xFF; + *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); + smpreq->RequestDataLength = sizeof(struct rep_manu_request); + + psge = (char *) + (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_request); + + ioc->add_sge(psge, flagsLength, data_out_dma); + psge += ioc->SGE_size; + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_reply); + ioc->add_sge(psge, flagsLength, data_out_dma + + sizeof(struct rep_manu_request)); + + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) + mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); + + timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_free; + if (!timeleft) + mpt_HardResetHandler(ioc, CAN_SLEEP); + goto out_free; + } + + mf = NULL; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { + u8 *tmp; + + smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; + if (le16_to_cpu(smprep->ResponseDataLength) != + sizeof(struct rep_manu_reply)) + goto out_free; + + manufacture_reply = data_out + sizeof(struct rep_manu_request); + strncpy(edev->vendor_id, manufacture_reply->vendor_id, + SAS_EXPANDER_VENDOR_ID_LEN); + strncpy(edev->product_id, manufacture_reply->product_id, + SAS_EXPANDER_PRODUCT_ID_LEN); + strncpy(edev->product_rev, manufacture_reply->product_rev, + SAS_EXPANDER_PRODUCT_REV_LEN); + edev->level = manufacture_reply->sas_format; + if (manufacture_reply->sas_format) { + strncpy(edev->component_vendor_id, + manufacture_reply->component_vendor_id, + SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); + tmp = (u8 *)&manufacture_reply->component_id; + edev->component_id = tmp[0] << 8 | tmp[1]; + edev->component_revision_id = + manufacture_reply->component_revision_id; + } + } else { + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", + ioc->name, __func__); + ret = -ENXIO; + } +out_free: + if (data_out_dma) + pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); +put_mf: + if (mf) + mpt_free_msg_frame(ioc, mf); +out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) + mutex_unlock(&ioc->sas_mgmt.mutex); +out: + return ret; + } + static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -2967,6 +3148,11 @@ static int mptsas_probe_one_phy(struct device *dev, goto out; } mptsas_set_rphy(ioc, phy_info, rphy); + if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || + identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) + mptsas_exp_repmanufacture_info(ioc, + identify.sas_address, + rphy_to_expander_device(rphy)); } out: -- GitLab From 64e155adc250ab68255b761c1faa77799aa1e41a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:02:29 +0530 Subject: [PATCH 0883/3892] [SCSI] mptfusion: block device when target is being removed by FW Add support to set the sdev state to SDEV_BLOCK during device removal to stop IOs comming to the deleting driver immediately. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 1b7f550daebc..c20bbe45da82 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1075,6 +1075,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) return 0; } +static void +mptsas_block_io_sdev(struct scsi_device *sdev, void *data) +{ + scsi_device_set_state(sdev, SDEV_BLOCK); +} + +static void +mptsas_block_io_starget(struct scsi_target *starget) +{ + if (starget) + starget_for_each_device(starget, NULL, mptsas_block_io_sdev); +} + /** * mptsas_target_reset_queue * @@ -1098,10 +1111,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, id = sas_event_data->TargetID; channel = sas_event_data->Bus; - if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) - return; - - vtarget->deleted = 1; /* block IO */ + vtarget = mptsas_find_vtarget(ioc, channel, id); + if (vtarget) { + mptsas_block_io_starget(vtarget->starget); + vtarget->deleted = 1; /* block IO */ + } target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); @@ -1868,7 +1882,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) if (ioc->sas_discovery_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; -// scsi_print_command(SCpnt); + if (ioc->debug_level & MPT_DEBUG_SCSI) + scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done); } -- GitLab From de81562f2f9852a1f2c609ede1e26c07ed457c60 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:02:59 +0530 Subject: [PATCH 0884/3892] [SCSI] mptfusion: corrected if condition check for SCSIIO and PASSTHROUGH commands Modified the function type check to verify it is not MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or MPI_FUNCTION_SCSI_IO_REQUEST. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 352acd05c46b..caa8f568a41c 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -360,8 +360,8 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) u16 iocstatus; /* bus reset is only good for SCSI IO, RAID PASSTHRU */ - if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || - (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { + if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || + function == MPI_FUNCTION_SCSI_IO_REQUEST)) { dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n", ioc->name)); return -EPERM; -- GitLab From 4ffd005a4dedf536330756742595ec904f740f48 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 19:04:49 +0530 Subject: [PATCH 0885/3892] [SCSI] mptfusion: Bump version 03.04.14 Version upgrade to 3.04.14. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index b4948671eb92..9718c8f2e959 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.13" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13" +#define MPT_LINUX_VERSION_COMMON "3.04.14" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.14" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- GitLab From 3dbf6c0012d12473461b7485006db373e8192fa5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 19 Dec 2009 08:17:27 +0100 Subject: [PATCH 0886/3892] [SCSI] pm8001: Use kzalloc for allocating only one thing Use kzalloc rather than kcalloc(1,...) The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ @@ - kcalloc(1, + kzalloc( ...) // Signed-off-by: Julia Lawall Acked-by:Jack Wang Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index c2f1032496cb..f80c1da8f6ca 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -654,7 +654,7 @@ static int __devinit pm8001_pci_probe(struct pci_dev *pdev, } chip = &pm8001_chips[ent->driver_data]; SHOST_TO_SAS_HA(shost) = - kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); + kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); if (!SHOST_TO_SAS_HA(shost)) { rc = -ENOMEM; goto err_out_free_host; -- GitLab From 0ed8570ef4d51bb46e2028b2e3c3ddd1f860e193 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 21 Dec 2009 16:27:55 -0800 Subject: [PATCH 0887/3892] [SCSI] cxgbi3: remove unnecessary NULL test Stanse found that c3cn is poked many times around in cxgb3i_conn_pdu_ready, there is no need to check if it is NULL. Remove the test. Signed-off-by: Jiri Slaby Reviewed-by: Mike Christie Acked-by: Karen Xie Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/cxgb3i/cxgb3i_pdu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c index 1fe3b0f1f3c9..9c38539557fc 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c @@ -461,10 +461,8 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) skb = skb_peek(&c3cn->receive_queue); } read_unlock(&c3cn->callback_lock); - if (c3cn) { - c3cn->copied_seq += read; - cxgb3i_c3cn_rx_credits(c3cn, read); - } + c3cn->copied_seq += read; + cxgb3i_c3cn_rx_credits(c3cn, read); conn->rxdata_octets += read; if (err) { -- GitLab From 5d7ebb9c7a04d29efce1099024944dfd94d9f63c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 28 Dec 2009 20:08:39 +0200 Subject: [PATCH 0888/3892] [SCSI] FlashPoint: fix off by one tests The check on MAX_SCSI_TAR should be >= instead of > or we could go past the end of the array. Joe Eykholt aslo correctly points out that the check on MAX_LUN should be >= as well. That matches with how it is used in the rest of the file. Signed-off-by: Dan Carpenter Signed-off-by: James Bottomley --- drivers/scsi/FlashPoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index b898d382b7b0..e40cdfb7541f 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -3924,7 +3924,7 @@ static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card) { struct sccb_mgr_tar_info *currTar_Info; - if ((p_sccb->TargID > MAX_SCSI_TAR) || (p_sccb->Lun > MAX_LUN)) { + if ((p_sccb->TargID >= MAX_SCSI_TAR) || (p_sccb->Lun >= MAX_LUN)) { return; } currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID]; -- GitLab From e7efe5932b1d3916c79326a4221693ea90a900e2 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sun, 3 Jan 2010 13:51:15 -0500 Subject: [PATCH 0889/3892] [SCSI] skip sense logging for some ATA PASS-THROUGH cdbs Further to the lsml thread titled: "does scsi_io_completion need to dump sense data for ata pass through (ck_cond = 1) ?" This is a patch to skip logging when the sense data is associated with a SENSE_KEY of "RECOVERED_ERROR" and the additional sense code is "ATA PASS-THROUGH INFORMATION AVAILABLE". This only occurs with the SAT ATA PASS-THROUGH commands when CK_COND=1 (in the cdb). It indicates that the sense data contains ATA registers. Smartmontools uses such commands on ATA disks connected via SAT. Periodic checks such as those done by smartd cause nuisance entries into logs that are: - neither errors nor warnings - pointless unless the cdb that caused them are also logged Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c6642423cc67..56977097de9f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -773,8 +773,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * we already took a copy of the original into rq->errors which * is what gets returned to the user */ - if (sense_valid && sshdr.sense_key == RECOVERED_ERROR) { - if (!(req->cmd_flags & REQ_QUIET)) + if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) { + /* if ATA PASS-THROUGH INFORMATION AVAILABLE skip + * print since caller wants ATA registers. Only occurs on + * SCSI ATA PASS_THROUGH commands when CK_COND=1 + */ + if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d)) + ; + else if (!(req->cmd_flags & REQ_QUIET)) scsi_print_sense("", cmd); result = 0; /* BLOCK_PC may have set error */ -- GitLab From 1fe6dbf4d0afba52ad0249f398e6296a1433a004 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 4 Jan 2010 10:19:34 -0500 Subject: [PATCH 0890/3892] [SCSI] gdth: Convert to use regular kernel types. converted using this script.. perl -p -i -e 's|ulong32|u32|g' drivers/scsi/gdth* perl -p -i -e 's|ulong64|u64|g' drivers/scsi/gdth* perl -p -i -e 's|ushort|u16|g' drivers/scsi/gdth* perl -p -i -e 's|unchar|u8|g' drivers/scsi/gdth* perl -p -i -e 's|ulong|unsigned long|g' drivers/scsi/gdth* perl -p -i -e 's|PACKED|__attribute__((packed))|g' drivers/scsi/gdth* sha1sum of the generated code was identical before and after. Signed-off-by: Dave Jones Signed-off-by: James Bottomley --- drivers/scsi/gdth.c | 430 ++++++++--------- drivers/scsi/gdth.h | 952 +++++++++++++++++++------------------- drivers/scsi/gdth_ioctl.h | 366 +++++++-------- drivers/scsi/gdth_proc.c | 42 +- drivers/scsi/gdth_proc.h | 4 +- 5 files changed, 893 insertions(+), 901 deletions(-) diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 9e8fce0f0c1b..ba3c94c9c25f 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -140,40 +140,40 @@ #include "gdth.h" static void gdth_delay(int milliseconds); -static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); +static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs); static irqreturn_t gdth_interrupt(int irq, void *dev_id); static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int gdth_from_wait, int* pIndex); -static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, +static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, Scsi_Cmnd *scp); static int gdth_async_event(gdth_ha_str *ha); static void gdth_log_event(gdth_evt_data *dvr, char *buffer); -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority); +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority); static void gdth_next(gdth_ha_str *ha); -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b); +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b); static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, - ushort idx, gdth_evt_data *evt); +static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, + u16 idx, gdth_evt_data *evt); static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr); -static void gdth_readapp_event(gdth_ha_str *ha, unchar application, +static void gdth_readapp_event(gdth_ha_str *ha, u8 application, gdth_evt_str *estr); static void gdth_clear_events(void); static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count); + char *buffer, u16 count); static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive); static void gdth_enable_int(gdth_ha_str *ha); static int gdth_test_busy(gdth_ha_str *ha); static int gdth_get_cmd_index(gdth_ha_str *ha); static void gdth_release_event(gdth_ha_str *ha); -static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time); -static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, - ulong32 p1, ulong64 p2,ulong64 p3); +static int gdth_wait(gdth_ha_str *ha, int index,u32 time); +static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, + u32 p1, u64 p2,u64 p3); static int gdth_search_drives(gdth_ha_str *ha); -static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive); +static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive); static const char *gdth_ctr_name(gdth_ha_str *ha); @@ -189,7 +189,7 @@ static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, static void gdth_scsi_done(struct scsi_cmnd *scp); #ifdef DEBUG_GDTH -static unchar DebugState = DEBUG_GDTH; +static u8 DebugState = DEBUG_GDTH; #ifdef __SERIAL__ #define MAX_SERBUF 160 @@ -270,30 +270,30 @@ static int ser_printk(const char *fmt, ...) #endif #ifdef GDTH_STATISTICS -static ulong32 max_rq=0, max_index=0, max_sg=0; +static u32 max_rq=0, max_index=0, max_sg=0; #ifdef INT_COAL -static ulong32 max_int_coal=0; +static u32 max_int_coal=0; #endif -static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; +static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; static struct timer_list gdth_timer; #endif -#define PTR2USHORT(a) (ushort)(ulong)(a) +#define PTR2USHORT(a) (u16)(unsigned long)(a) #define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b) #define INDEX_OK(i,t) ((i)(a)->virt_bus ? (b-1):(b)) #ifdef CONFIG_ISA -static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ +static u8 gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ #endif #if defined(CONFIG_EISA) || defined(CONFIG_ISA) -static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ +static u8 gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ #endif -static unchar gdth_polling; /* polling if TRUE */ +static u8 gdth_polling; /* polling if TRUE */ static int gdth_ctr_count = 0; /* controller count */ static LIST_HEAD(gdth_instances); /* controller list */ -static unchar gdth_write_through = FALSE; /* write through */ +static u8 gdth_write_through = FALSE; /* write through */ static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ static int elastidx; static int eoldidx; @@ -303,7 +303,7 @@ static int major; #define DOU 2 /* OUT data direction */ #define DNO DIN /* no data transfer */ #define DUN DIN /* unknown data direction */ -static unchar gdth_direction_tab[0x100] = { +static u8 gdth_direction_tab[0x100] = { DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, @@ -390,7 +390,7 @@ static gdth_ha_str *gdth_find_ha(int hanum) static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) { struct gdth_cmndinfo *priv = NULL; - ulong flags; + unsigned long flags; int i; spin_lock_irqsave(&ha->smp_lock, flags); @@ -493,7 +493,7 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, return rval; } -static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs) +static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs) { *cyls = size /HEADS/SECS; if (*cyls <= MAXCYLS) { @@ -514,9 +514,9 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs /* controller search and initialization functions */ #ifdef CONFIG_EISA -static int __init gdth_search_eisa(ushort eisa_adr) +static int __init gdth_search_eisa(u16 eisa_adr) { - ulong32 id; + u32 id; TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr)); id = inl(eisa_adr+ID0REG); @@ -533,13 +533,13 @@ static int __init gdth_search_eisa(ushort eisa_adr) #endif /* CONFIG_EISA */ #ifdef CONFIG_ISA -static int __init gdth_search_isa(ulong32 bios_adr) +static int __init gdth_search_isa(u32 bios_adr) { void __iomem *addr; - ulong32 id; + u32 id; TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); - if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) { + if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) { id = readl(addr); iounmap(addr); if (id == GDT2_ID) /* GDT2000 */ @@ -551,7 +551,7 @@ static int __init gdth_search_isa(ulong32 bios_adr) #ifdef CONFIG_PCI -static bool gdth_search_vortex(ushort device) +static bool gdth_search_vortex(u16 device) { if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) return true; @@ -603,9 +603,9 @@ static void __devexit gdth_pci_remove_one(struct pci_dev *pdev) static int __devinit gdth_pci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - ushort vendor = pdev->vendor; - ushort device = pdev->device; - ulong base0, base1, base2; + u16 vendor = pdev->vendor; + u16 device = pdev->device; + unsigned long base0, base1, base2; int rc; gdth_pci_str gdth_pcistr; gdth_ha_str *ha = NULL; @@ -658,10 +658,10 @@ static int __devinit gdth_pci_init_one(struct pci_dev *pdev, #endif /* CONFIG_PCI */ #ifdef CONFIG_EISA -static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) +static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha) { - ulong32 retries,id; - unchar prot_ver,eisacf,i,irq_found; + u32 retries,id; + u8 prot_ver,eisacf,i,irq_found; TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr)); @@ -688,7 +688,7 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) return 0; } ha->bmic = eisa_adr; - ha->brd_phys = (ulong32)eisa_adr >> 12; + ha->brd_phys = (u32)eisa_adr >> 12; outl(0,eisa_adr+MAILBOXREG); outl(0,eisa_adr+MAILBOXREG+4); @@ -752,12 +752,12 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) #endif /* CONFIG_EISA */ #ifdef CONFIG_ISA -static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) +static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha) { register gdt2_dpram_str __iomem *dp2_ptr; int i; - unchar irq_drq,prot_ver; - ulong32 retries; + u8 irq_drq,prot_ver; + u32 retries; TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr)); @@ -812,7 +812,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) } gdth_delay(1); } - prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]); writeb(0, &dp2_ptr->u.ic.Status); writeb(0xff, &dp2_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { @@ -859,9 +859,9 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, register gdt6_dpram_str __iomem *dp6_ptr; register gdt6c_dpram_str __iomem *dp6c_ptr; register gdt6m_dpram_str __iomem *dp6m_ptr; - ulong32 retries; - unchar prot_ver; - ushort command; + u32 retries; + u8 prot_ver; + u16 command; int i, found = FALSE; TRACE(("gdth_init_pci()\n")); @@ -871,7 +871,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, else ha->oem_id = OEM_ID_ICP; ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8); - ha->stype = (ulong32)pdev->device; + ha->stype = (u32)pdev->device; ha->irq = pdev->irq; ha->pdev = pdev; @@ -891,7 +891,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -947,7 +947,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]); writeb(0, &dp6_ptr->u.ic.S_Status); writeb(0xff, &dp6_ptr->io.irqdel); if (prot_ver != PROTOCOL_VERSION) { @@ -1000,7 +1000,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1059,7 +1059,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]); writeb(0, &dp6c_ptr->u.ic.Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); @@ -1128,7 +1128,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(ushort)); + ha->brd = ioremap(i, sizeof(u16)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; @@ -1180,7 +1180,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]); + prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]); writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver != PROTOCOL_VERSION) { printk("GDT-PCI: Illegal protocol version\n"); @@ -1223,7 +1223,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, } gdth_delay(1); } - prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); + prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); writeb(0, &dp6m_ptr->u.ic.S_Status); if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ ha->dma64_support = 0; @@ -1239,7 +1239,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, static void __devinit gdth_enable_int(gdth_ha_str *ha) { - ulong flags; + unsigned long flags; gdt2_dpram_str __iomem *dp2_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt6m_dpram_str __iomem *dp6m_ptr; @@ -1274,14 +1274,14 @@ static void __devinit gdth_enable_int(gdth_ha_str *ha) } /* return IStatus if interrupt was from this card else 0 */ -static unchar gdth_get_status(gdth_ha_str *ha) +static u8 gdth_get_status(gdth_ha_str *ha) { - unchar IStatus = 0; + u8 IStatus = 0; TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); if (ha->type == GDT_EISA) - IStatus = inb((ushort)ha->bmic + EDOORREG); + IStatus = inb((u16)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) IStatus = readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); @@ -1329,7 +1329,7 @@ static int gdth_get_cmd_index(gdth_ha_str *ha) if (ha->cmd_tab[i].cmnd == UNUSED_CMND) { ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer; ha->cmd_tab[i].service = ha->pccb->Service; - ha->pccb->CommandIndex = (ulong32)i+2; + ha->pccb->CommandIndex = (u32)i+2; return (i+2); } } @@ -1362,7 +1362,7 @@ static void gdth_copy_command(gdth_ha_str *ha) register gdt6c_dpram_str __iomem *dp6c_ptr; gdt6_dpram_str __iomem *dp6_ptr; gdt2_dpram_str __iomem *dp2_ptr; - ushort cp_count,dp_offset,cmd_no; + u16 cp_count,dp_offset,cmd_no; TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); @@ -1386,28 +1386,28 @@ static void gdth_copy_command(gdth_ha_str *ha) dp2_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp2_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCI) { dp6_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCINEW) { dp6c_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } else if (ha->type == GDT_PCIMPR) { dp6m_ptr = ha->brd; writew(dp_offset + DPMEM_COMMAND_OFFSET, &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); - writew((ushort)cmd_ptr->Service, + writew((u16)cmd_ptr->Service, &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id); memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); } @@ -1420,14 +1420,14 @@ static void gdth_release_event(gdth_ha_str *ha) #ifdef GDTH_STATISTICS { - ulong32 i,j; + u32 i,j; for (i=0,j=0; jcmd_tab[j].cmnd != UNUSED_CMND) ++i; } if (max_index < i) { max_index = i; - TRACE3(("GDT: max_index = %d\n",(ushort)i)); + TRACE3(("GDT: max_index = %d\n",(u16)i)); } } #endif @@ -1450,7 +1450,7 @@ static void gdth_release_event(gdth_ha_str *ha) } } -static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) +static int gdth_wait(gdth_ha_str *ha, int index, u32 time) { int answer_found = FALSE; int wait_index = 0; @@ -1476,8 +1476,8 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) } -static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, - ulong32 p1, ulong64 p2, ulong64 p3) +static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, + u32 p1, u64 p2, u64 p3) { register gdth_cmd_str *cmd_ptr; int retries,index; @@ -1501,35 +1501,35 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, if (service == CACHESERVICE) { if (opcode == GDT_IOCTL) { cmd_ptr->u.ioctl.subfunc = p1; - cmd_ptr->u.ioctl.channel = (ulong32)p2; - cmd_ptr->u.ioctl.param_size = (ushort)p3; + cmd_ptr->u.ioctl.channel = (u32)p2; + cmd_ptr->u.ioctl.param_size = (u16)p3; cmd_ptr->u.ioctl.p_param = ha->scratch_phys; } else { if (ha->cache_feat & GDT_64BIT) { - cmd_ptr->u.cache64.DeviceNo = (ushort)p1; + cmd_ptr->u.cache64.DeviceNo = (u16)p1; cmd_ptr->u.cache64.BlockNo = p2; } else { - cmd_ptr->u.cache.DeviceNo = (ushort)p1; - cmd_ptr->u.cache.BlockNo = (ulong32)p2; + cmd_ptr->u.cache.DeviceNo = (u16)p1; + cmd_ptr->u.cache.BlockNo = (u32)p2; } } } else if (service == SCSIRAWSERVICE) { if (ha->raw_feat & GDT_64BIT) { cmd_ptr->u.raw64.direction = p1; - cmd_ptr->u.raw64.bus = (unchar)p2; - cmd_ptr->u.raw64.target = (unchar)p3; - cmd_ptr->u.raw64.lun = (unchar)(p3 >> 8); + cmd_ptr->u.raw64.bus = (u8)p2; + cmd_ptr->u.raw64.target = (u8)p3; + cmd_ptr->u.raw64.lun = (u8)(p3 >> 8); } else { cmd_ptr->u.raw.direction = p1; - cmd_ptr->u.raw.bus = (unchar)p2; - cmd_ptr->u.raw.target = (unchar)p3; - cmd_ptr->u.raw.lun = (unchar)(p3 >> 8); + cmd_ptr->u.raw.bus = (u8)p2; + cmd_ptr->u.raw.target = (u8)p3; + cmd_ptr->u.raw.lun = (u8)(p3 >> 8); } } else if (service == SCREENSERVICE) { if (opcode == GDT_REALTIME) { - *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1; - *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2; - *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3; + *(u32 *)&cmd_ptr->u.screen.su.data[0] = p1; + *(u32 *)&cmd_ptr->u.screen.su.data[4] = (u32)p2; + *(u32 *)&cmd_ptr->u.screen.su.data[8] = (u32)p3; } } ha->cmd_len = sizeof(gdth_cmd_str); @@ -1555,9 +1555,9 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, static int __devinit gdth_search_drives(gdth_ha_str *ha) { - ushort cdev_cnt, i; + u16 cdev_cnt, i; int ok; - ulong32 bus_no, drv_cnt, drv_no, j; + u32 bus_no, drv_cnt, drv_no, j; gdth_getch_str *chn; gdth_drlist_str *drl; gdth_iochan_str *ioc; @@ -1570,8 +1570,8 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) #endif #ifdef GDTH_RTC - unchar rtc[12]; - ulong flags; + u8 rtc[12]; + unsigned long flags; #endif TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); @@ -1584,7 +1584,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->screen_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error screen service (code %d)\n", @@ -1609,11 +1609,11 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) rtc[j] = CMOS_READ(j); } while (rtc[0] != CMOS_READ(0)); spin_unlock_irqrestore(&rtc_lock, flags); - TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0], - *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8])); + TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(u32 *)&rtc[0], + *(u32 *)&rtc[4], *(u32 *)&rtc[8])); /* 3. send to controller firmware */ - gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0], - *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]); + gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(u32 *)&rtc[0], + *(u32 *)&rtc[4], *(u32 *)&rtc[8]); #endif /* unfreeze all IOs */ @@ -1627,7 +1627,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->cache_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error cache service (code %d)\n", @@ -1635,7 +1635,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) return 0; } TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); - cdev_cnt = (ushort)ha->info; + cdev_cnt = (u16)ha->info; ha->fw_vers = ha->service; #ifdef INT_COAL @@ -1644,7 +1644,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) pmod = (gdth_perf_modes *)ha->pscratch; pmod->version = 1; pmod->st_mode = 1; /* enable one status buffer */ - *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; + *((u64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; pmod->st_buff_indx1 = COALINDEX; pmod->st_buff_addr2 = 0; pmod->st_buff_u_addr2 = 0; @@ -1705,7 +1705,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) else ha->bus_id[bus_no] = 0xff; } - ha->bus_cnt = (unchar)bus_no; + ha->bus_cnt = (u8)bus_no; } TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt)); @@ -1789,12 +1789,12 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) /* logical drives */ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT, - INVALID_CHANNEL,sizeof(ulong32))) { - drv_cnt = *(ulong32 *)ha->pscratch; + INVALID_CHANNEL,sizeof(u32))) { + drv_cnt = *(u32 *)ha->pscratch; if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST, - INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { + INVALID_CHANNEL,drv_cnt * sizeof(u32))) { for (j = 0; j < drv_cnt; ++j) { - drv_no = ((ulong32 *)ha->pscratch)[j]; + drv_no = ((u32 *)ha->pscratch)[j]; if (drv_no < MAX_LDRIVES) { ha->hdr[drv_no].is_logdrv = TRUE; TRACE2(("Drive %d is log. drive\n",drv_no)); @@ -1838,7 +1838,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (ok) ha->raw_feat = GDT_64BIT; } - if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC)) + if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0); if (!ok) { printk("GDT-HA %d: Initialization error raw service (code %d)\n", @@ -1854,7 +1854,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", ha->info)); - ha->raw_feat |= (ushort)ha->info; + ha->raw_feat |= (u16)ha->info; } } @@ -1865,7 +1865,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) { TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", ha->info)); - ha->cache_feat |= (ushort)ha->info; + ha->cache_feat |= (u16)ha->info; } } @@ -1923,9 +1923,9 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha) return 1; } -static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) +static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive) { - ulong32 drv_cyls; + u32 drv_cyls; int drv_hds, drv_secs; TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive)); @@ -1944,17 +1944,17 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) } else { drv_hds = ha->info2 & 0xff; drv_secs = (ha->info2 >> 8) & 0xff; - drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs; + drv_cyls = (u32)ha->hdr[hdrive].size / drv_hds / drv_secs; } - ha->hdr[hdrive].heads = (unchar)drv_hds; - ha->hdr[hdrive].secs = (unchar)drv_secs; + ha->hdr[hdrive].heads = (u8)drv_hds; + ha->hdr[hdrive].secs = (u8)drv_secs; /* round size */ ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; if (ha->cache_feat & GDT_64BIT) { if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0) && ha->info2 != 0) { - ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info; + ha->hdr[hdrive].size = ((u64)ha->info2 << 32) | ha->info; } } TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", @@ -1964,7 +1964,7 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", hdrive,ha->info)); - ha->hdr[hdrive].devtype = (ushort)ha->info; + ha->hdr[hdrive].devtype = (u16)ha->info; } /* cluster info */ @@ -1972,14 +1972,14 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", hdrive,ha->info)); if (!shared_access) - ha->hdr[hdrive].cluster_type = (unchar)ha->info; + ha->hdr[hdrive].cluster_type = (u8)ha->info; } /* R/W attributes */ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) { TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", hdrive,ha->info)); - ha->hdr[hdrive].rw_attribs = (unchar)ha->info; + ha->hdr[hdrive].rw_attribs = (u8)ha->info; } return 1; @@ -1988,12 +1988,12 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive) /* command queueing/sending functions */ -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority) +static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority) { struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; - ulong flags; + unsigned long flags; TRACE(("gdth_putq() priority %d\n",priority)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2023,7 +2023,7 @@ static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority) ++flags; if (max_rq < flags) { max_rq = flags; - TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq)); + TRACE3(("GDT: max_rq = %d\n",(u16)max_rq)); } #endif } @@ -2032,9 +2032,9 @@ static void gdth_next(gdth_ha_str *ha) { register Scsi_Cmnd *pscp; register Scsi_Cmnd *nscp; - unchar b, t, l, firsttime; - unchar this_cmd, next_cmd; - ulong flags = 0; + u8 b, t, l, firsttime; + u8 this_cmd, next_cmd; + unsigned long flags = 0; int cmd_index; TRACE(("gdth_next() hanum %d\n", ha->hanum)); @@ -2282,20 +2282,20 @@ static void gdth_next(gdth_ha_str *ha) * buffers, kmap_atomic() as needed. */ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count) + char *buffer, u16 count) { - ushort cpcount,i, max_sg = scsi_sg_count(scp); - ushort cpsum,cpnow; + u16 cpcount,i, max_sg = scsi_sg_count(scp); + u16 cpsum,cpnow; struct scatterlist *sl; char *address; - cpcount = min_t(ushort, count, scsi_bufflen(scp)); + cpcount = min_t(u16, count, scsi_bufflen(scp)); if (cpcount) { cpsum=0; scsi_for_each_sg(scp, sl, max_sg, i) { unsigned long flags; - cpnow = (ushort)sl->length; + cpnow = (u16)sl->length; TRACE(("copy_internal() now %d sum %d count %d %d\n", cpnow, cpsum, cpcount, scsi_bufflen(scp))); if (cpsum+cpnow > cpcount) @@ -2325,7 +2325,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { - unchar t; + u8 t; gdth_inq_data inq; gdth_rdcap_data rdc; gdth_sense_data sd; @@ -2389,7 +2389,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) case READ_CAPACITY: TRACE2(("Read capacity hdrive %d\n",t)); - if (ha->hdr[t].size > (ulong64)0xffffffff) + if (ha->hdr[t].size > (u64)0xffffffff) rdc.last_block_no = 0xffffffff; else rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); @@ -2425,12 +2425,12 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) return 0; } -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) +static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive) { register gdth_cmd_str *cmdp; struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - ulong32 cnt, blockcnt; - ulong64 no, blockno; + u32 cnt, blockcnt; + u64 no, blockno; int i, cmd_index, read_write, sgcnt, mode64; cmdp = ha->pccb; @@ -2498,17 +2498,17 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) if (read_write) { if (scp->cmd_len == 16) { - memcpy(&no, &scp->cmnd[2], sizeof(ulong64)); + memcpy(&no, &scp->cmnd[2], sizeof(u64)); blockno = be64_to_cpu(no); - memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32)); + memcpy(&cnt, &scp->cmnd[10], sizeof(u32)); blockcnt = be32_to_cpu(cnt); } else if (scp->cmd_len == 10) { - memcpy(&no, &scp->cmnd[2], sizeof(ulong32)); + memcpy(&no, &scp->cmnd[2], sizeof(u32)); blockno = be32_to_cpu(no); - memcpy(&cnt, &scp->cmnd[7], sizeof(ushort)); + memcpy(&cnt, &scp->cmnd[7], sizeof(u16)); blockcnt = be16_to_cpu(cnt); } else { - memcpy(&no, &scp->cmnd[0], sizeof(ulong32)); + memcpy(&no, &scp->cmnd[0], sizeof(u32)); blockno = be32_to_cpu(no) & 0x001fffffUL; blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; } @@ -2516,7 +2516,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) cmdp->u.cache64.BlockNo = blockno; cmdp->u.cache64.BlockCnt = blockcnt; } else { - cmdp->u.cache.BlockNo = (ulong32)blockno; + cmdp->u.cache.BlockNo = (u32)blockno; cmdp->u.cache.BlockCnt = blockcnt; } @@ -2528,12 +2528,12 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) if (mode64) { struct scatterlist *sl; - cmdp->u.cache64.DestAddr= (ulong64)-1; + cmdp->u.cache64.DestAddr= (u64)-1; cmdp->u.cache64.sg_canz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS - if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + if (cmdp->u.cache64.sg_lst[i].sg_ptr > (u64)0xffffffff) ha->dma64_cnt++; else ha->dma32_cnt++; @@ -2555,8 +2555,8 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) } #ifdef GDTH_STATISTICS - if (max_sg < (ulong32)sgcnt) { - max_sg = (ulong32)sgcnt; + if (max_sg < (u32)sgcnt) { + max_sg = (u32)sgcnt; TRACE3(("GDT: max_sg = %d\n",max_sg)); } #endif @@ -2572,7 +2572,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt)); ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + - (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); + (u16)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); } else { TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, @@ -2581,7 +2581,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + - (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); + (u16)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); } if (ha->cmd_len & 3) ha->cmd_len += (4 - (ha->cmd_len & 3)); @@ -2600,15 +2600,15 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) return cmd_index; } -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) +static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b) { register gdth_cmd_str *cmdp; - ushort i; + u16 i; dma_addr_t sense_paddr; int cmd_index, sgcnt, mode64; - unchar t,l; + u8 t,l; struct page *page; - ulong offset; + unsigned long offset; struct gdth_cmndinfo *cmndinfo; t = scp->device->id; @@ -2654,7 +2654,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) } else { page = virt_to_page(scp->sense_buffer); - offset = (ulong)scp->sense_buffer & ~PAGE_MASK; + offset = (unsigned long)scp->sense_buffer & ~PAGE_MASK; sense_paddr = pci_map_page(ha->pdev,page,offset, 16,PCI_DMA_FROMDEVICE); @@ -2703,12 +2703,12 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) if (mode64) { struct scatterlist *sl; - cmdp->u.raw64.sdata = (ulong64)-1; + cmdp->u.raw64.sdata = (u64)-1; cmdp->u.raw64.sg_ranz = sgcnt; scsi_for_each_sg(scp, sl, sgcnt, i) { cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); #ifdef GDTH_DMA_STATISTICS - if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff) + if (cmdp->u.raw64.sg_lst[i].sg_ptr > (u64)0xffffffff) ha->dma64_cnt++; else ha->dma32_cnt++; @@ -2744,7 +2744,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw64.sg_lst[0].sg_len)); /* evaluate command size */ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + - (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); + (u16)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); } else { TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, @@ -2752,7 +2752,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw.sg_lst[0].sg_len)); /* evaluate command size */ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + - (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); + (u16)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); } } /* check space */ @@ -2802,7 +2802,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) if (cmdp->OpCode == GDT_IOCTL) { TRACE2(("IOCTL\n")); ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64); + GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(u64); } else if (cmdp->Service == CACHESERVICE) { TRACE2(("cache command %d\n",cmdp->OpCode)); if (ha->cache_feat & GDT_64BIT) @@ -2840,8 +2840,8 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) /* Controller event handling functions */ -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, - ushort idx, gdth_evt_data *evt) +static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, + u16 idx, gdth_evt_data *evt) { gdth_evt_str *e; struct timeval tv; @@ -2890,7 +2890,7 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) { gdth_evt_str *e; int eindex; - ulong flags; + unsigned long flags; TRACE2(("gdth_read_event() handle %d\n", handle)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2919,12 +2919,12 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) } static void gdth_readapp_event(gdth_ha_str *ha, - unchar application, gdth_evt_str *estr) + u8 application, gdth_evt_str *estr) { gdth_evt_str *e; int eindex; - ulong flags; - unchar found = FALSE; + unsigned long flags; + u8 found = FALSE; TRACE2(("gdth_readapp_event() app. %d\n", application)); spin_lock_irqsave(&ha->smp_lock, flags); @@ -2969,9 +2969,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, gdt2_dpram_str __iomem *dp2_ptr; Scsi_Cmnd *scp; int rval, i; - unchar IStatus; - ushort Service; - ulong flags = 0; + u8 IStatus; + u16 Service; + unsigned long flags = 0; #ifdef INT_COAL int coalesced = FALSE; int next = FALSE; @@ -3018,7 +3018,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, if (coalesced) { /* For coalesced requests all status information is found in the status buffer */ - IStatus = (unchar)(pcs->status & 0xff); + IStatus = (u8)(pcs->status & 0xff); } #endif @@ -3197,7 +3197,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, ++act_int_coal; if (act_int_coal > max_int_coal) { max_int_coal = act_int_coal; - printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal); + printk("GDT: max_int_coal = %d\n",(u16)max_int_coal); } #endif /* see if there is another status */ @@ -3225,12 +3225,12 @@ static irqreturn_t gdth_interrupt(int irq, void *dev_id) return __gdth_interrupt(ha, false, NULL); } -static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, +static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, Scsi_Cmnd *scp) { gdth_msg_str *msg; gdth_cmd_str *cmdp; - unchar b, t; + u8 b, t; struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); cmdp = ha->pccb; @@ -3263,7 +3263,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); gdth_release_event(ha); @@ -3297,7 +3297,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); gdth_release_event(ha); @@ -3335,7 +3335,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, cmndinfo->OpCode)); /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ if (cmndinfo->OpCode == GDT_CLUST_INFO) { - ha->hdr[t].cluster_type = (unchar)ha->info; + ha->hdr[t].cluster_type = (u8)ha->info; if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) { /* NOT MOUNTED -> MOUNT */ @@ -3397,7 +3397,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; } memset((char*)scp->sense_buffer,0,16); - if (ha->status == (ushort)S_CACHE_RESERV) { + if (ha->status == (u16)S_CACHE_RESERV) { scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1); } else { scp->sense_buffer[0] = 0x70; @@ -3614,16 +3614,16 @@ static int gdth_async_event(gdth_ha_str *ha) cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; ha->cmd_offs_dpmem = 0; ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(ulong64); + + sizeof(u64); ha->cmd_cnt = 0; gdth_copy_command(ha); if (ha->type == GDT_EISA) - printk("[EISA slot %d] ",(ushort)ha->brd_phys); + printk("[EISA slot %d] ",(u16)ha->brd_phys); else if (ha->type == GDT_ISA) - printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys); + printk("[DPMEM 0x%4X] ",(u16)ha->brd_phys); else - printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8), - (ushort)((ha->brd_phys>>3)&0x1f)); + printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), + (u16)((ha->brd_phys>>3)&0x1f)); gdth_release_event(ha); } @@ -3640,7 +3640,7 @@ static int gdth_async_event(gdth_ha_str *ha) ha->dvr.eu.async.service = ha->service; ha->dvr.eu.async.status = ha->status; ha->dvr.eu.async.info = ha->info; - *(ulong32 *)ha->dvr.eu.async.scsi_coord = ha->info2; + *(u32 *)ha->dvr.eu.async.scsi_coord = ha->info2; } gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr ); gdth_log_event( &ha->dvr, NULL ); @@ -3648,8 +3648,8 @@ static int gdth_async_event(gdth_ha_str *ha) /* new host drive from expand? */ if (ha->service == CACHESERVICE && ha->status == 56) { TRACE2(("gdth_async_event(): new host drive %d created\n", - (ushort)ha->info)); - /* gdth_analyse_hdrive(hanum, (ushort)ha->info); */ + (u16)ha->info)); + /* gdth_analyse_hdrive(hanum, (u16)ha->info); */ } } return 1; @@ -3680,13 +3680,13 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer) for (j=0,i=1; i < f[0]; i+=2) { switch (f[i+1]) { case 4: - stack.b[j++] = *(ulong32*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u32*)&dvr->eu.stream[(int)f[i]]; break; case 2: - stack.b[j++] = *(ushort*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u16*)&dvr->eu.stream[(int)f[i]]; break; case 1: - stack.b[j++] = *(unchar*)&dvr->eu.stream[(int)f[i]]; + stack.b[j++] = *(u8*)&dvr->eu.stream[(int)f[i]]; break; default: break; @@ -3712,14 +3712,14 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer) } #ifdef GDTH_STATISTICS -static unchar gdth_timer_running; +static u8 gdth_timer_running; -static void gdth_timeout(ulong data) +static void gdth_timeout(unsigned long data) { - ulong32 i; + u32 i; Scsi_Cmnd *nscp; gdth_ha_str *ha; - ulong flags; + unsigned long flags; if(unlikely(list_empty(&gdth_instances))) { gdth_timer_running = 0; @@ -3891,8 +3891,8 @@ static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) { gdth_ha_str *ha = shost_priv(scp->device->host); struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - unchar b, t; - ulong flags; + u8 b, t; + unsigned long flags; enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED; TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); @@ -3924,9 +3924,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) { gdth_ha_str *ha = shost_priv(scp->device->host); int i; - ulong flags; + unsigned long flags; Scsi_Cmnd *cmnd; - unchar b; + u8 b; TRACE2(("gdth_eh_bus_reset()\n")); @@ -3974,7 +3974,7 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp) static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) { - unchar b, t; + u8 b, t; gdth_ha_str *ha = shost_priv(sdev->host); struct scsi_device *sd; unsigned capacity; @@ -4062,7 +4062,7 @@ static int ioc_event(void __user *arg) { gdth_ioctl_event evt; gdth_ha_str *ha; - ulong flags; + unsigned long flags; if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event))) return -EFAULT; @@ -4098,8 +4098,8 @@ static int ioc_event(void __user *arg) static int ioc_lockdrv(void __user *arg) { gdth_ioctl_lockdrv ldrv; - unchar i, j; - ulong flags; + u8 i, j; + unsigned long flags; gdth_ha_str *ha; if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv))) @@ -4165,7 +4165,7 @@ static int ioc_general(void __user *arg, char *cmnd) { gdth_ioctl_general gen; char *buf = NULL; - ulong64 paddr; + u64 paddr; gdth_ha_str *ha; int rval; @@ -4194,7 +4194,7 @@ static int ioc_general(void __user *arg, char *cmnd) gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo; /* addresses */ if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache64.DestAddr = (ulong64)-1; + gen.command.u.cache64.DestAddr = (u64)-1; gen.command.u.cache64.sg_canz = 1; gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len; @@ -4207,7 +4207,7 @@ static int ioc_general(void __user *arg, char *cmnd) if (ha->cache_feat & SCATTER_GATHER) { gen.command.u.cache.DestAddr = 0xffffffff; gen.command.u.cache.sg_canz = 1; - gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; gen.command.u.cache.sg_lst[1].sg_len = 0; } else { @@ -4230,7 +4230,7 @@ static int ioc_general(void __user *arg, char *cmnd) gen.command.u.raw64.direction = gen.command.u.raw.direction; /* addresses */ if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw64.sdata = (ulong64)-1; + gen.command.u.raw64.sdata = (u64)-1; gen.command.u.raw64.sg_ranz = 1; gen.command.u.raw64.sg_lst[0].sg_ptr = paddr; gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len; @@ -4244,14 +4244,14 @@ static int ioc_general(void __user *arg, char *cmnd) if (ha->raw_feat & SCATTER_GATHER) { gen.command.u.raw.sdata = 0xffffffff; gen.command.u.raw.sg_ranz = 1; - gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr; + gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; gen.command.u.raw.sg_lst[0].sg_len = gen.data_len; gen.command.u.raw.sg_lst[1].sg_len = 0; } else { gen.command.u.raw.sdata = paddr; gen.command.u.raw.sg_ranz = 0; } - gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len; + gen.command.u.raw.sense_data = (u32)paddr + gen.data_len; } } else { gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); @@ -4283,7 +4283,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) gdth_ioctl_rescan *rsc; gdth_cmd_str *cmd; gdth_ha_str *ha; - unchar i; + u8 i; int rc = -ENOMEM; u32 cluster_type = 0; @@ -4335,11 +4335,11 @@ static int ioc_rescan(void __user *arg, char *cmnd) { gdth_ioctl_rescan *rsc; gdth_cmd_str *cmd; - ushort i, status, hdr_cnt; - ulong32 info; + u16 i, status, hdr_cnt; + u32 info; int cyls, hds, secs; int rc = -ENOMEM; - ulong flags; + unsigned long flags; gdth_ha_str *ha; rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); @@ -4367,7 +4367,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); i = 0; - hdr_cnt = (status == S_OK ? (ushort)info : 0); + hdr_cnt = (status == S_OK ? (u16)info : 0); } else { i = rsc->hdr_no; hdr_cnt = i + 1; @@ -4418,7 +4418,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0); + ha->hdr[i].devtype = (status == S_OK ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); cmd->Service = CACHESERVICE; @@ -4432,7 +4432,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) spin_lock_irqsave(&ha->smp_lock, flags); ha->hdr[i].cluster_type = - ((status == S_OK && !shared_access) ? (ushort)info : 0); + ((status == S_OK && !shared_access) ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; @@ -4446,7 +4446,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0); + ha->hdr[i].rw_attribs = (status == S_OK ? (u16)info : 0); spin_unlock_irqrestore(&ha->smp_lock, flags); } @@ -4466,7 +4466,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, { gdth_ha_str *ha; Scsi_Cmnd *scp; - ulong flags; + unsigned long flags; char cmnd[MAX_COMMAND_SIZE]; void __user *argp = (void __user *)arg; @@ -4495,9 +4495,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, { gdth_ioctl_osvers osv; - osv.version = (unchar)(LINUX_VERSION_CODE >> 16); - osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8); - osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff); + osv.version = (u8)(LINUX_VERSION_CODE >> 16); + osv.subversion = (u8)(LINUX_VERSION_CODE >> 8); + osv.revision = (u16)(LINUX_VERSION_CODE & 0xff); if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers))) return -EFAULT; break; @@ -4512,10 +4512,10 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, return -EFAULT; if (ha->type == GDT_ISA || ha->type == GDT_EISA) { - ctrt.type = (unchar)((ha->stype>>20) - 0x10); + ctrt.type = (u8)((ha->stype>>20) - 0x10); } else { if (ha->type != GDT_PCIMPR) { - ctrt.type = (unchar)((ha->stype<<4) + 6); + ctrt.type = (u8)((ha->stype<<4) + 6); } else { ctrt.type = (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); @@ -4546,7 +4546,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, case GDTIOCTL_LOCKCHN: { gdth_ioctl_lockchn lchn; - unchar i, j; + u8 i, j; if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || (NULL == (ha = gdth_find_ha(lchn.ionode)))) @@ -4670,7 +4670,7 @@ static struct scsi_host_template gdth_template = { }; #ifdef CONFIG_ISA -static int __init gdth_isa_probe_one(ulong32 isa_bios) +static int __init gdth_isa_probe_one(u32 isa_bios) { struct Scsi_Host *shp; gdth_ha_str *ha; @@ -4802,7 +4802,7 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios) #endif /* CONFIG_ISA */ #ifdef CONFIG_EISA -static int __init gdth_eisa_probe_one(ushort eisa_slot) +static int __init gdth_eisa_probe_one(u16 eisa_slot) { struct Scsi_Host *shp; gdth_ha_str *ha; @@ -5120,7 +5120,7 @@ static void gdth_remove_one(gdth_ha_str *ha) scsi_host_put(shp); } -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) +static int gdth_halt(struct notifier_block *nb, unsigned long event, void *buf) { gdth_ha_str *ha; @@ -5158,14 +5158,14 @@ static int __init gdth_init(void) if (probe_eisa_isa) { /* scanning for controllers, at first: ISA controller */ #ifdef CONFIG_ISA - ulong32 isa_bios; + u32 isa_bios; for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL; isa_bios += 0x8000UL) gdth_isa_probe_one(isa_bios); #endif #ifdef CONFIG_EISA { - ushort eisa_slot; + u16 eisa_slot; for (eisa_slot = 0x1000; eisa_slot <= 0x8000; eisa_slot += 0x1000) gdth_eisa_probe_one(eisa_slot); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 1646444e9bd5..120a0625a7b5 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -321,524 +321,524 @@ /* screenservice message */ typedef struct { - ulong32 msg_handle; /* message handle */ - ulong32 msg_len; /* size of message */ - ulong32 msg_alen; /* answer length */ - unchar msg_answer; /* answer flag */ - unchar msg_ext; /* more messages */ - unchar msg_reserved[2]; + u32 msg_handle; /* message handle */ + u32 msg_len; /* size of message */ + u32 msg_alen; /* answer length */ + u8 msg_answer; /* answer flag */ + u8 msg_ext; /* more messages */ + u8 msg_reserved[2]; char msg_text[MSGLEN+2]; /* the message text */ -} PACKED gdth_msg_str; +} __attribute__((packed)) gdth_msg_str; /* IOCTL data structures */ /* Status coalescing buffer for returning multiple requests per interrupt */ typedef struct { - ulong32 status; - ulong32 ext_status; - ulong32 info0; - ulong32 info1; -} PACKED gdth_coal_status; + u32 status; + u32 ext_status; + u32 info0; + u32 info1; +} __attribute__((packed)) gdth_coal_status; /* performance mode data structure */ typedef struct { - ulong32 version; /* The version of this IOCTL structure. */ - ulong32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ - ulong32 st_buff_addr1; /* physical address of status buffer 1 */ - ulong32 st_buff_u_addr1; /* reserved for 64 bit addressing */ - ulong32 st_buff_indx1; /* reserved command idx. for this buffer */ - ulong32 st_buff_addr2; /* physical address of status buffer 1 */ - ulong32 st_buff_u_addr2; /* reserved for 64 bit addressing */ - ulong32 st_buff_indx2; /* reserved command idx. for this buffer */ - ulong32 st_buff_size; /* size of each buffer in bytes */ - ulong32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ - ulong32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ - ulong32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ - ulong32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ - ulong32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ - ulong32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ - ulong32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ - ulong32 cmd_buff_size; /* size of each cmd bufer in bytes */ - ulong32 reserved1; - ulong32 reserved2; -} PACKED gdth_perf_modes; + u32 version; /* The version of this IOCTL structure. */ + u32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ + u32 st_buff_addr1; /* physical address of status buffer 1 */ + u32 st_buff_u_addr1; /* reserved for 64 bit addressing */ + u32 st_buff_indx1; /* reserved command idx. for this buffer */ + u32 st_buff_addr2; /* physical address of status buffer 1 */ + u32 st_buff_u_addr2; /* reserved for 64 bit addressing */ + u32 st_buff_indx2; /* reserved command idx. for this buffer */ + u32 st_buff_size; /* size of each buffer in bytes */ + u32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ + u32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ + u32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ + u32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ + u32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ + u32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ + u32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ + u32 cmd_buff_size; /* size of each cmd bufer in bytes */ + u32 reserved1; + u32 reserved2; +} __attribute__((packed)) gdth_perf_modes; /* SCSI drive info */ typedef struct { - unchar vendor[8]; /* vendor string */ - unchar product[16]; /* product string */ - unchar revision[4]; /* revision */ - ulong32 sy_rate; /* current rate for sync. tr. */ - ulong32 sy_max_rate; /* max. rate for sync. tr. */ - ulong32 no_ldrive; /* belongs to this log. drv.*/ - ulong32 blkcnt; /* number of blocks */ - ushort blksize; /* size of block in bytes */ - unchar available; /* flag: access is available */ - unchar init; /* medium is initialized */ - unchar devtype; /* SCSI devicetype */ - unchar rm_medium; /* medium is removable */ - unchar wp_medium; /* medium is write protected */ - unchar ansi; /* SCSI I/II or III? */ - unchar protocol; /* same as ansi */ - unchar sync; /* flag: sync. transfer enab. */ - unchar disc; /* flag: disconnect enabled */ - unchar queueing; /* flag: command queing enab. */ - unchar cached; /* flag: caching enabled */ - unchar target_id; /* target ID of device */ - unchar lun; /* LUN id of device */ - unchar orphan; /* flag: drive fragment */ - ulong32 last_error; /* sense key or drive state */ - ulong32 last_result; /* result of last command */ - ulong32 check_errors; /* err. in last surface check */ - unchar percent; /* progress for surface check */ - unchar last_check; /* IOCTRL operation */ - unchar res[2]; - ulong32 flags; /* from 1.19/2.19: raw reserv.*/ - unchar multi_bus; /* multi bus dev? (fibre ch.) */ - unchar mb_status; /* status: available? */ - unchar res2[2]; - unchar mb_alt_status; /* status on second bus */ - unchar mb_alt_bid; /* number of second bus */ - unchar mb_alt_tid; /* target id on second bus */ - unchar res3; - unchar fc_flag; /* from 1.22/2.22: info valid?*/ - unchar res4; - ushort fc_frame_size; /* frame size (bytes) */ + u8 vendor[8]; /* vendor string */ + u8 product[16]; /* product string */ + u8 revision[4]; /* revision */ + u32 sy_rate; /* current rate for sync. tr. */ + u32 sy_max_rate; /* max. rate for sync. tr. */ + u32 no_ldrive; /* belongs to this log. drv.*/ + u32 blkcnt; /* number of blocks */ + u16 blksize; /* size of block in bytes */ + u8 available; /* flag: access is available */ + u8 init; /* medium is initialized */ + u8 devtype; /* SCSI devicetype */ + u8 rm_medium; /* medium is removable */ + u8 wp_medium; /* medium is write protected */ + u8 ansi; /* SCSI I/II or III? */ + u8 protocol; /* same as ansi */ + u8 sync; /* flag: sync. transfer enab. */ + u8 disc; /* flag: disconnect enabled */ + u8 queueing; /* flag: command queing enab. */ + u8 cached; /* flag: caching enabled */ + u8 target_id; /* target ID of device */ + u8 lun; /* LUN id of device */ + u8 orphan; /* flag: drive fragment */ + u32 last_error; /* sense key or drive state */ + u32 last_result; /* result of last command */ + u32 check_errors; /* err. in last surface check */ + u8 percent; /* progress for surface check */ + u8 last_check; /* IOCTRL operation */ + u8 res[2]; + u32 flags; /* from 1.19/2.19: raw reserv.*/ + u8 multi_bus; /* multi bus dev? (fibre ch.) */ + u8 mb_status; /* status: available? */ + u8 res2[2]; + u8 mb_alt_status; /* status on second bus */ + u8 mb_alt_bid; /* number of second bus */ + u8 mb_alt_tid; /* target id on second bus */ + u8 res3; + u8 fc_flag; /* from 1.22/2.22: info valid?*/ + u8 res4; + u16 fc_frame_size; /* frame size (bytes) */ char wwn[8]; /* world wide name */ -} PACKED gdth_diskinfo_str; +} __attribute__((packed)) gdth_diskinfo_str; /* get SCSI channel count */ typedef struct { - ulong32 channel_no; /* number of channel */ - ulong32 drive_cnt; /* drive count */ - unchar siop_id; /* SCSI processor ID */ - unchar siop_state; /* SCSI processor state */ -} PACKED gdth_getch_str; + u32 channel_no; /* number of channel */ + u32 drive_cnt; /* drive count */ + u8 siop_id; /* SCSI processor ID */ + u8 siop_state; /* SCSI processor state */ +} __attribute__((packed)) gdth_getch_str; /* get SCSI drive numbers */ typedef struct { - ulong32 sc_no; /* SCSI channel */ - ulong32 sc_cnt; /* sc_list[] elements */ - ulong32 sc_list[MAXID]; /* minor device numbers */ -} PACKED gdth_drlist_str; + u32 sc_no; /* SCSI channel */ + u32 sc_cnt; /* sc_list[] elements */ + u32 sc_list[MAXID]; /* minor device numbers */ +} __attribute__((packed)) gdth_drlist_str; /* get grown/primary defect count */ typedef struct { - unchar sddc_type; /* 0x08: grown, 0x10: prim. */ - unchar sddc_format; /* list entry format */ - unchar sddc_len; /* list entry length */ - unchar sddc_res; - ulong32 sddc_cnt; /* entry count */ -} PACKED gdth_defcnt_str; + u8 sddc_type; /* 0x08: grown, 0x10: prim. */ + u8 sddc_format; /* list entry format */ + u8 sddc_len; /* list entry length */ + u8 sddc_res; + u32 sddc_cnt; /* entry count */ +} __attribute__((packed)) gdth_defcnt_str; /* disk statistics */ typedef struct { - ulong32 bid; /* SCSI channel */ - ulong32 first; /* first SCSI disk */ - ulong32 entries; /* number of elements */ - ulong32 count; /* (R) number of init. el. */ - ulong32 mon_time; /* time stamp */ + u32 bid; /* SCSI channel */ + u32 first; /* first SCSI disk */ + u32 entries; /* number of elements */ + u32 count; /* (R) number of init. el. */ + u32 mon_time; /* time stamp */ struct { - unchar tid; /* target ID */ - unchar lun; /* LUN */ - unchar res[2]; - ulong32 blk_size; /* block size in bytes */ - ulong32 rd_count; /* bytes read */ - ulong32 wr_count; /* bytes written */ - ulong32 rd_blk_count; /* blocks read */ - ulong32 wr_blk_count; /* blocks written */ - ulong32 retries; /* retries */ - ulong32 reassigns; /* reassigns */ - } PACKED list[1]; -} PACKED gdth_dskstat_str; + u8 tid; /* target ID */ + u8 lun; /* LUN */ + u8 res[2]; + u32 blk_size; /* block size in bytes */ + u32 rd_count; /* bytes read */ + u32 wr_count; /* bytes written */ + u32 rd_blk_count; /* blocks read */ + u32 wr_blk_count; /* blocks written */ + u32 retries; /* retries */ + u32 reassigns; /* reassigns */ + } __attribute__((packed)) list[1]; +} __attribute__((packed)) gdth_dskstat_str; /* IO channel header */ typedef struct { - ulong32 version; /* version (-1UL: newest) */ - unchar list_entries; /* list entry count */ - unchar first_chan; /* first channel number */ - unchar last_chan; /* last channel number */ - unchar chan_count; /* (R) channel count */ - ulong32 list_offset; /* offset of list[0] */ -} PACKED gdth_iochan_header; + u32 version; /* version (-1UL: newest) */ + u8 list_entries; /* list entry count */ + u8 first_chan; /* first channel number */ + u8 last_chan; /* last channel number */ + u8 chan_count; /* (R) channel count */ + u32 list_offset; /* offset of list[0] */ +} __attribute__((packed)) gdth_iochan_header; /* get IO channel description */ typedef struct { gdth_iochan_header hdr; struct { - ulong32 address; /* channel address */ - unchar type; /* type (SCSI, FCAL) */ - unchar local_no; /* local number */ - ushort features; /* channel features */ - } PACKED list[MAXBUS]; -} PACKED gdth_iochan_str; + u32 address; /* channel address */ + u8 type; /* type (SCSI, FCAL) */ + u8 local_no; /* local number */ + u16 features; /* channel features */ + } __attribute__((packed)) list[MAXBUS]; +} __attribute__((packed)) gdth_iochan_str; /* get raw IO channel description */ typedef struct { gdth_iochan_header hdr; struct { - unchar proc_id; /* processor id */ - unchar proc_defect; /* defect ? */ - unchar reserved[2]; - } PACKED list[MAXBUS]; -} PACKED gdth_raw_iochan_str; + u8 proc_id; /* processor id */ + u8 proc_defect; /* defect ? */ + u8 reserved[2]; + } __attribute__((packed)) list[MAXBUS]; +} __attribute__((packed)) gdth_raw_iochan_str; /* array drive component */ typedef struct { - ulong32 al_controller; /* controller ID */ - unchar al_cache_drive; /* cache drive number */ - unchar al_status; /* cache drive state */ - unchar al_res[2]; -} PACKED gdth_arraycomp_str; + u32 al_controller; /* controller ID */ + u8 al_cache_drive; /* cache drive number */ + u8 al_status; /* cache drive state */ + u8 al_res[2]; +} __attribute__((packed)) gdth_arraycomp_str; /* array drive information */ typedef struct { - unchar ai_type; /* array type (RAID0,4,5) */ - unchar ai_cache_drive_cnt; /* active cachedrives */ - unchar ai_state; /* array drive state */ - unchar ai_master_cd; /* master cachedrive */ - ulong32 ai_master_controller; /* ID of master controller */ - ulong32 ai_size; /* user capacity [sectors] */ - ulong32 ai_striping_size; /* striping size [sectors] */ - ulong32 ai_secsize; /* sector size [bytes] */ - ulong32 ai_err_info; /* failed cache drive */ - unchar ai_name[8]; /* name of the array drive */ - unchar ai_controller_cnt; /* number of controllers */ - unchar ai_removable; /* flag: removable */ - unchar ai_write_protected; /* flag: write protected */ - unchar ai_devtype; /* type: always direct access */ + u8 ai_type; /* array type (RAID0,4,5) */ + u8 ai_cache_drive_cnt; /* active cachedrives */ + u8 ai_state; /* array drive state */ + u8 ai_master_cd; /* master cachedrive */ + u32 ai_master_controller; /* ID of master controller */ + u32 ai_size; /* user capacity [sectors] */ + u32 ai_striping_size; /* striping size [sectors] */ + u32 ai_secsize; /* sector size [bytes] */ + u32 ai_err_info; /* failed cache drive */ + u8 ai_name[8]; /* name of the array drive */ + u8 ai_controller_cnt; /* number of controllers */ + u8 ai_removable; /* flag: removable */ + u8 ai_write_protected; /* flag: write protected */ + u8 ai_devtype; /* type: always direct access */ gdth_arraycomp_str ai_drives[35]; /* drive components: */ - unchar ai_drive_entries; /* number of drive components */ - unchar ai_protected; /* protection flag */ - unchar ai_verify_state; /* state of a parity verify */ - unchar ai_ext_state; /* extended array drive state */ - unchar ai_expand_state; /* array expand state (>=2.18)*/ - unchar ai_reserved[3]; -} PACKED gdth_arrayinf_str; + u8 ai_drive_entries; /* number of drive components */ + u8 ai_protected; /* protection flag */ + u8 ai_verify_state; /* state of a parity verify */ + u8 ai_ext_state; /* extended array drive state */ + u8 ai_expand_state; /* array expand state (>=2.18)*/ + u8 ai_reserved[3]; +} __attribute__((packed)) gdth_arrayinf_str; /* get array drive list */ typedef struct { - ulong32 controller_no; /* controller no. */ - unchar cd_handle; /* master cachedrive */ - unchar is_arrayd; /* Flag: is array drive? */ - unchar is_master; /* Flag: is array master? */ - unchar is_parity; /* Flag: is parity drive? */ - unchar is_hotfix; /* Flag: is hotfix drive? */ - unchar res[3]; -} PACKED gdth_alist_str; + u32 controller_no; /* controller no. */ + u8 cd_handle; /* master cachedrive */ + u8 is_arrayd; /* Flag: is array drive? */ + u8 is_master; /* Flag: is array master? */ + u8 is_parity; /* Flag: is parity drive? */ + u8 is_hotfix; /* Flag: is hotfix drive? */ + u8 res[3]; +} __attribute__((packed)) gdth_alist_str; typedef struct { - ulong32 entries_avail; /* allocated entries */ - ulong32 entries_init; /* returned entries */ - ulong32 first_entry; /* first entry number */ - ulong32 list_offset; /* offset of following list */ + u32 entries_avail; /* allocated entries */ + u32 entries_init; /* returned entries */ + u32 first_entry; /* first entry number */ + u32 list_offset; /* offset of following list */ gdth_alist_str list[1]; /* list */ -} PACKED gdth_arcdl_str; +} __attribute__((packed)) gdth_arcdl_str; /* cache info/config IOCTL */ typedef struct { - ulong32 version; /* firmware version */ - ushort state; /* cache state (on/off) */ - ushort strategy; /* cache strategy */ - ushort write_back; /* write back state (on/off) */ - ushort block_size; /* cache block size */ -} PACKED gdth_cpar_str; + u32 version; /* firmware version */ + u16 state; /* cache state (on/off) */ + u16 strategy; /* cache strategy */ + u16 write_back; /* write back state (on/off) */ + u16 block_size; /* cache block size */ +} __attribute__((packed)) gdth_cpar_str; typedef struct { - ulong32 csize; /* cache size */ - ulong32 read_cnt; /* read/write counter */ - ulong32 write_cnt; - ulong32 tr_hits; /* hits */ - ulong32 sec_hits; - ulong32 sec_miss; /* misses */ -} PACKED gdth_cstat_str; + u32 csize; /* cache size */ + u32 read_cnt; /* read/write counter */ + u32 write_cnt; + u32 tr_hits; /* hits */ + u32 sec_hits; + u32 sec_miss; /* misses */ +} __attribute__((packed)) gdth_cstat_str; typedef struct { gdth_cpar_str cpar; gdth_cstat_str cstat; -} PACKED gdth_cinfo_str; +} __attribute__((packed)) gdth_cinfo_str; /* cache drive info */ typedef struct { - unchar cd_name[8]; /* cache drive name */ - ulong32 cd_devtype; /* SCSI devicetype */ - ulong32 cd_ldcnt; /* number of log. drives */ - ulong32 cd_last_error; /* last error */ - unchar cd_initialized; /* drive is initialized */ - unchar cd_removable; /* media is removable */ - unchar cd_write_protected; /* write protected */ - unchar cd_flags; /* Pool Hot Fix? */ - ulong32 ld_blkcnt; /* number of blocks */ - ulong32 ld_blksize; /* blocksize */ - ulong32 ld_dcnt; /* number of disks */ - ulong32 ld_slave; /* log. drive index */ - ulong32 ld_dtype; /* type of logical drive */ - ulong32 ld_last_error; /* last error */ - unchar ld_name[8]; /* log. drive name */ - unchar ld_error; /* error */ -} PACKED gdth_cdrinfo_str; + u8 cd_name[8]; /* cache drive name */ + u32 cd_devtype; /* SCSI devicetype */ + u32 cd_ldcnt; /* number of log. drives */ + u32 cd_last_error; /* last error */ + u8 cd_initialized; /* drive is initialized */ + u8 cd_removable; /* media is removable */ + u8 cd_write_protected; /* write protected */ + u8 cd_flags; /* Pool Hot Fix? */ + u32 ld_blkcnt; /* number of blocks */ + u32 ld_blksize; /* blocksize */ + u32 ld_dcnt; /* number of disks */ + u32 ld_slave; /* log. drive index */ + u32 ld_dtype; /* type of logical drive */ + u32 ld_last_error; /* last error */ + u8 ld_name[8]; /* log. drive name */ + u8 ld_error; /* error */ +} __attribute__((packed)) gdth_cdrinfo_str; /* OEM string */ typedef struct { - ulong32 ctl_version; - ulong32 file_major_version; - ulong32 file_minor_version; - ulong32 buffer_size; - ulong32 cpy_count; - ulong32 ext_error; - ulong32 oem_id; - ulong32 board_id; -} PACKED gdth_oem_str_params; - -typedef struct { - unchar product_0_1_name[16]; - unchar product_4_5_name[16]; - unchar product_cluster_name[16]; - unchar product_reserved[16]; - unchar scsi_cluster_target_vendor_id[16]; - unchar cluster_raid_fw_name[16]; - unchar oem_brand_name[16]; - unchar oem_raid_type[16]; - unchar bios_type[13]; - unchar bios_title[50]; - unchar oem_company_name[37]; - ulong32 pci_id_1; - ulong32 pci_id_2; - unchar validation_status[80]; - unchar reserved_1[4]; - unchar scsi_host_drive_inquiry_vendor_id[16]; - unchar library_file_template[16]; - unchar reserved_2[16]; - unchar tool_name_1[32]; - unchar tool_name_2[32]; - unchar tool_name_3[32]; - unchar oem_contact_1[84]; - unchar oem_contact_2[84]; - unchar oem_contact_3[84]; -} PACKED gdth_oem_str; + u32 ctl_version; + u32 file_major_version; + u32 file_minor_version; + u32 buffer_size; + u32 cpy_count; + u32 ext_error; + u32 oem_id; + u32 board_id; +} __attribute__((packed)) gdth_oem_str_params; + +typedef struct { + u8 product_0_1_name[16]; + u8 product_4_5_name[16]; + u8 product_cluster_name[16]; + u8 product_reserved[16]; + u8 scsi_cluster_target_vendor_id[16]; + u8 cluster_raid_fw_name[16]; + u8 oem_brand_name[16]; + u8 oem_raid_type[16]; + u8 bios_type[13]; + u8 bios_title[50]; + u8 oem_company_name[37]; + u32 pci_id_1; + u32 pci_id_2; + u8 validation_status[80]; + u8 reserved_1[4]; + u8 scsi_host_drive_inquiry_vendor_id[16]; + u8 library_file_template[16]; + u8 reserved_2[16]; + u8 tool_name_1[32]; + u8 tool_name_2[32]; + u8 tool_name_3[32]; + u8 oem_contact_1[84]; + u8 oem_contact_2[84]; + u8 oem_contact_3[84]; +} __attribute__((packed)) gdth_oem_str; typedef struct { gdth_oem_str_params params; gdth_oem_str text; -} PACKED gdth_oem_str_ioctl; +} __attribute__((packed)) gdth_oem_str_ioctl; /* board features */ typedef struct { - unchar chaining; /* Chaining supported */ - unchar striping; /* Striping (RAID-0) supp. */ - unchar mirroring; /* Mirroring (RAID-1) supp. */ - unchar raid; /* RAID-4/5/10 supported */ -} PACKED gdth_bfeat_str; + u8 chaining; /* Chaining supported */ + u8 striping; /* Striping (RAID-0) supp. */ + u8 mirroring; /* Mirroring (RAID-1) supp. */ + u8 raid; /* RAID-4/5/10 supported */ +} __attribute__((packed)) gdth_bfeat_str; /* board info IOCTL */ typedef struct { - ulong32 ser_no; /* serial no. */ - unchar oem_id[2]; /* OEM ID */ - ushort ep_flags; /* eprom flags */ - ulong32 proc_id; /* processor ID */ - ulong32 memsize; /* memory size (bytes) */ - unchar mem_banks; /* memory banks */ - unchar chan_type; /* channel type */ - unchar chan_count; /* channel count */ - unchar rdongle_pres; /* dongle present? */ - ulong32 epr_fw_ver; /* (eprom) firmware version */ - ulong32 upd_fw_ver; /* (update) firmware version */ - ulong32 upd_revision; /* update revision */ + u32 ser_no; /* serial no. */ + u8 oem_id[2]; /* OEM ID */ + u16 ep_flags; /* eprom flags */ + u32 proc_id; /* processor ID */ + u32 memsize; /* memory size (bytes) */ + u8 mem_banks; /* memory banks */ + u8 chan_type; /* channel type */ + u8 chan_count; /* channel count */ + u8 rdongle_pres; /* dongle present? */ + u32 epr_fw_ver; /* (eprom) firmware version */ + u32 upd_fw_ver; /* (update) firmware version */ + u32 upd_revision; /* update revision */ char type_string[16]; /* controller name */ char raid_string[16]; /* RAID firmware name */ - unchar update_pres; /* update present? */ - unchar xor_pres; /* XOR engine present? */ - unchar prom_type; /* ROM type (eprom/flash) */ - unchar prom_count; /* number of ROM devices */ - ulong32 dup_pres; /* duplexing module present? */ - ulong32 chan_pres; /* number of expansion chn. */ - ulong32 mem_pres; /* memory expansion inst. ? */ - unchar ft_bus_system; /* fault bus supported? */ - unchar subtype_valid; /* board_subtype valid? */ - unchar board_subtype; /* subtype/hardware level */ - unchar ramparity_pres; /* RAM parity check hardware? */ -} PACKED gdth_binfo_str; + u8 update_pres; /* update present? */ + u8 xor_pres; /* XOR engine present? */ + u8 prom_type; /* ROM type (eprom/flash) */ + u8 prom_count; /* number of ROM devices */ + u32 dup_pres; /* duplexing module present? */ + u32 chan_pres; /* number of expansion chn. */ + u32 mem_pres; /* memory expansion inst. ? */ + u8 ft_bus_system; /* fault bus supported? */ + u8 subtype_valid; /* board_subtype valid? */ + u8 board_subtype; /* subtype/hardware level */ + u8 ramparity_pres; /* RAM parity check hardware? */ +} __attribute__((packed)) gdth_binfo_str; /* get host drive info */ typedef struct { char name[8]; /* host drive name */ - ulong32 size; /* size (sectors) */ - unchar host_drive; /* host drive number */ - unchar log_drive; /* log. drive (master) */ - unchar reserved; - unchar rw_attribs; /* r/w attribs */ - ulong32 start_sec; /* start sector */ -} PACKED gdth_hentry_str; - -typedef struct { - ulong32 entries; /* entry count */ - ulong32 offset; /* offset of entries */ - unchar secs_p_head; /* sectors/head */ - unchar heads_p_cyl; /* heads/cylinder */ - unchar reserved; - unchar clust_drvtype; /* cluster drive type */ - ulong32 location; /* controller number */ + u32 size; /* size (sectors) */ + u8 host_drive; /* host drive number */ + u8 log_drive; /* log. drive (master) */ + u8 reserved; + u8 rw_attribs; /* r/w attribs */ + u32 start_sec; /* start sector */ +} __attribute__((packed)) gdth_hentry_str; + +typedef struct { + u32 entries; /* entry count */ + u32 offset; /* offset of entries */ + u8 secs_p_head; /* sectors/head */ + u8 heads_p_cyl; /* heads/cylinder */ + u8 reserved; + u8 clust_drvtype; /* cluster drive type */ + u32 location; /* controller number */ gdth_hentry_str entry[MAX_HDRIVES]; /* entries */ -} PACKED gdth_hget_str; +} __attribute__((packed)) gdth_hget_str; /* DPRAM structures */ /* interface area ISA/PCI */ typedef struct { - unchar S_Cmd_Indx; /* special command */ - unchar volatile S_Status; /* status special command */ - ushort reserved1; - ulong32 S_Info[4]; /* add. info special command */ - unchar volatile Sema0; /* command semaphore */ - unchar reserved2[3]; - unchar Cmd_Index; /* command number */ - unchar reserved3[3]; - ushort volatile Status; /* command status */ - ushort Service; /* service(for async.events) */ - ulong32 Info[2]; /* additional info */ + u8 S_Cmd_Indx; /* special command */ + u8 volatile S_Status; /* status special command */ + u16 reserved1; + u32 S_Info[4]; /* add. info special command */ + u8 volatile Sema0; /* command semaphore */ + u8 reserved2[3]; + u8 Cmd_Index; /* command number */ + u8 reserved3[3]; + u16 volatile Status; /* command status */ + u16 Service; /* service(for async.events) */ + u32 Info[2]; /* additional info */ struct { - ushort offset; /* command offs. in the DPRAM*/ - ushort serv_id; /* service */ - } PACKED comm_queue[MAXOFFSETS]; /* command queue */ - ulong32 bios_reserved[2]; - unchar gdt_dpr_cmd[1]; /* commands */ -} PACKED gdt_dpr_if; + u16 offset; /* command offs. in the DPRAM*/ + u16 serv_id; /* service */ + } __attribute__((packed)) comm_queue[MAXOFFSETS]; /* command queue */ + u32 bios_reserved[2]; + u8 gdt_dpr_cmd[1]; /* commands */ +} __attribute__((packed)) gdt_dpr_if; /* SRAM structure PCI controllers */ typedef struct { - ulong32 magic; /* controller ID from BIOS */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding[9]; - unchar os_used[16]; /* OS code per service */ - unchar unused[28]; - unchar fw_magic; /* contr. ID from firmware */ -} PACKED gdt_pci_sram; + u32 magic; /* controller ID from BIOS */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding[9]; + u8 os_used[16]; /* OS code per service */ + u8 unused[28]; + u8 fw_magic; /* contr. ID from firmware */ +} __attribute__((packed)) gdt_pci_sram; /* SRAM structure EISA controllers (but NOT GDT3000/3020) */ typedef struct { - unchar os_used[16]; /* OS code per service */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding; -} PACKED gdt_eisa_sram; + u8 os_used[16]; /* OS code per service */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding; +} __attribute__((packed)) gdt_eisa_sram; /* DPRAM ISA controllers */ typedef struct { union { struct { - unchar bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ - ulong32 magic; /* controller (EISA) ID */ - ushort need_deinit; /* switch betw. BIOS/driver */ - unchar switch_support; /* see need_deinit */ - unchar padding[9]; - unchar os_used[16]; /* OS code per service */ - } PACKED dp_sram; - unchar bios_area[0x4000]; /* 16KB reserved for BIOS */ + u8 bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ + u32 magic; /* controller (EISA) ID */ + u16 need_deinit; /* switch betw. BIOS/driver */ + u8 switch_support; /* see need_deinit */ + u8 padding[9]; + u8 os_used[16]; /* OS code per service */ + } __attribute__((packed)) dp_sram; + u8 bios_area[0x4000]; /* 16KB reserved for BIOS */ } bu; union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x3000]; /* 12KB for interface */ + u8 if_area[0x3000]; /* 12KB for interface */ } u; struct { - unchar memlock; /* write protection DPRAM */ - unchar event; /* release event */ - unchar irqen; /* board interrupts enable */ - unchar irqdel; /* acknowledge board int. */ - unchar volatile Sema1; /* status semaphore */ - unchar rq; /* IRQ/DRQ configuration */ - } PACKED io; -} PACKED gdt2_dpram_str; + u8 memlock; /* write protection DPRAM */ + u8 event; /* release event */ + u8 irqen; /* board interrupts enable */ + u8 irqdel; /* acknowledge board int. */ + u8 volatile Sema1; /* status semaphore */ + u8 rq; /* IRQ/DRQ configuration */ + } __attribute__((packed)) io; +} __attribute__((packed)) gdt2_dpram_str; /* DPRAM PCI controllers */ typedef struct { union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0xff0-sizeof(gdt_pci_sram)]; + u8 if_area[0xff0-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ struct { - unchar unused0[1]; - unchar volatile Sema1; /* command semaphore */ - unchar unused1[3]; - unchar irqen; /* board interrupts enable */ - unchar unused2[2]; - unchar event; /* release event */ - unchar unused3[3]; - unchar irqdel; /* acknowledge board int. */ - unchar unused4[3]; - } PACKED io; -} PACKED gdt6_dpram_str; + u8 unused0[1]; + u8 volatile Sema1; /* command semaphore */ + u8 unused1[3]; + u8 irqen; /* board interrupts enable */ + u8 unused2[2]; + u8 event; /* release event */ + u8 unused3[3]; + u8 irqdel; /* acknowledge board int. */ + u8 unused4[3]; + } __attribute__((packed)) io; +} __attribute__((packed)) gdt6_dpram_str; /* PLX register structure (new PCI controllers) */ typedef struct { - unchar cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/ - unchar unused1[0x3f]; - unchar volatile sema0_reg; /* command semaphore */ - unchar volatile sema1_reg; /* status semaphore */ - unchar unused2[2]; - ushort volatile status; /* command status */ - ushort service; /* service */ - ulong32 info[2]; /* additional info */ - unchar unused3[0x10]; - unchar ldoor_reg; /* PCI to local doorbell */ - unchar unused4[3]; - unchar volatile edoor_reg; /* local to PCI doorbell */ - unchar unused5[3]; - unchar control0; /* control0 register(unused) */ - unchar control1; /* board interrupts enable */ - unchar unused6[0x16]; -} PACKED gdt6c_plx_regs; + u8 cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/ + u8 unused1[0x3f]; + u8 volatile sema0_reg; /* command semaphore */ + u8 volatile sema1_reg; /* status semaphore */ + u8 unused2[2]; + u16 volatile status; /* command status */ + u16 service; /* service */ + u32 info[2]; /* additional info */ + u8 unused3[0x10]; + u8 ldoor_reg; /* PCI to local doorbell */ + u8 unused4[3]; + u8 volatile edoor_reg; /* local to PCI doorbell */ + u8 unused5[3]; + u8 control0; /* control0 register(unused) */ + u8 control1; /* board interrupts enable */ + u8 unused6[0x16]; +} __attribute__((packed)) gdt6c_plx_regs; /* DPRAM new PCI controllers */ typedef struct { union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x4000-sizeof(gdt_pci_sram)]; + u8 if_area[0x4000-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ -} PACKED gdt6c_dpram_str; +} __attribute__((packed)) gdt6c_dpram_str; /* i960 register structure (PCI MPR controllers) */ typedef struct { - unchar unused1[16]; - unchar volatile sema0_reg; /* command semaphore */ - unchar unused2; - unchar volatile sema1_reg; /* status semaphore */ - unchar unused3; - ushort volatile status; /* command status */ - ushort service; /* service */ - ulong32 info[2]; /* additional info */ - unchar ldoor_reg; /* PCI to local doorbell */ - unchar unused4[11]; - unchar volatile edoor_reg; /* local to PCI doorbell */ - unchar unused5[7]; - unchar edoor_en_reg; /* board interrupts enable */ - unchar unused6[27]; - ulong32 unused7[939]; - ulong32 severity; + u8 unused1[16]; + u8 volatile sema0_reg; /* command semaphore */ + u8 unused2; + u8 volatile sema1_reg; /* status semaphore */ + u8 unused3; + u16 volatile status; /* command status */ + u16 service; /* service */ + u32 info[2]; /* additional info */ + u8 ldoor_reg; /* PCI to local doorbell */ + u8 unused4[11]; + u8 volatile edoor_reg; /* local to PCI doorbell */ + u8 unused5[7]; + u8 edoor_en_reg; /* board interrupts enable */ + u8 unused6[27]; + u32 unused7[939]; + u32 severity; char evt_str[256]; /* event string */ -} PACKED gdt6m_i960_regs; +} __attribute__((packed)) gdt6m_i960_regs; /* DPRAM PCI MPR controllers */ typedef struct { gdt6m_i960_regs i960r; /* 4KB i960 registers */ union { gdt_dpr_if ic; /* interface area */ - unchar if_area[0x3000-sizeof(gdt_pci_sram)]; + u8 if_area[0x3000-sizeof(gdt_pci_sram)]; } u; gdt_pci_sram gdt6sr; /* SRAM structure */ -} PACKED gdt6m_dpram_str; +} __attribute__((packed)) gdt6m_dpram_str; /* PCI resources */ typedef struct { struct pci_dev *pdev; - ulong dpmem; /* DPRAM address */ - ulong io; /* IO address */ + unsigned long dpmem; /* DPRAM address */ + unsigned long io; /* IO address */ } gdth_pci_str; @@ -846,93 +846,93 @@ typedef struct { typedef struct { struct Scsi_Host *shost; struct list_head list; - ushort hanum; - ushort oem_id; /* OEM */ - ushort type; /* controller class */ - ulong32 stype; /* subtype (PCI: device ID) */ - ushort fw_vers; /* firmware version */ - ushort cache_feat; /* feat. cache serv. (s/g,..)*/ - ushort raw_feat; /* feat. raw service (s/g,..)*/ - ushort screen_feat; /* feat. raw service (s/g,..)*/ - ushort bmic; /* BMIC address (EISA) */ + u16 hanum; + u16 oem_id; /* OEM */ + u16 type; /* controller class */ + u32 stype; /* subtype (PCI: device ID) */ + u16 fw_vers; /* firmware version */ + u16 cache_feat; /* feat. cache serv. (s/g,..)*/ + u16 raw_feat; /* feat. raw service (s/g,..)*/ + u16 screen_feat; /* feat. raw service (s/g,..)*/ + u16 bmic; /* BMIC address (EISA) */ void __iomem *brd; /* DPRAM address */ - ulong32 brd_phys; /* slot number/BIOS address */ + u32 brd_phys; /* slot number/BIOS address */ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ gdth_cmd_str cmdext; gdth_cmd_str *pccb; /* address command structure */ - ulong32 ccb_phys; /* phys. address */ + u32 ccb_phys; /* phys. address */ #ifdef INT_COAL gdth_coal_status *coal_stat; /* buffer for coalescing int.*/ - ulong64 coal_stat_phys; /* phys. address */ + u64 coal_stat_phys; /* phys. address */ #endif char *pscratch; /* scratch (DMA) buffer */ - ulong64 scratch_phys; /* phys. address */ - unchar scratch_busy; /* in use? */ - unchar dma64_support; /* 64-bit DMA supported? */ + u64 scratch_phys; /* phys. address */ + u8 scratch_busy; /* in use? */ + u8 dma64_support; /* 64-bit DMA supported? */ gdth_msg_str *pmsg; /* message buffer */ - ulong64 msg_phys; /* phys. address */ - unchar scan_mode; /* current scan mode */ - unchar irq; /* IRQ */ - unchar drq; /* DRQ (ISA controllers) */ - ushort status; /* command status */ - ushort service; /* service/firmware ver./.. */ - ulong32 info; - ulong32 info2; /* additional info */ + u64 msg_phys; /* phys. address */ + u8 scan_mode; /* current scan mode */ + u8 irq; /* IRQ */ + u8 drq; /* DRQ (ISA controllers) */ + u16 status; /* command status */ + u16 service; /* service/firmware ver./.. */ + u32 info; + u32 info2; /* additional info */ Scsi_Cmnd *req_first; /* top of request queue */ struct { - unchar present; /* Flag: host drive present? */ - unchar is_logdrv; /* Flag: log. drive (master)? */ - unchar is_arraydrv; /* Flag: array drive? */ - unchar is_master; /* Flag: array drive master? */ - unchar is_parity; /* Flag: parity drive? */ - unchar is_hotfix; /* Flag: hotfix drive? */ - unchar master_no; /* number of master drive */ - unchar lock; /* drive locked? (hot plug) */ - unchar heads; /* mapping */ - unchar secs; - ushort devtype; /* further information */ - ulong64 size; /* capacity */ - unchar ldr_no; /* log. drive no. */ - unchar rw_attribs; /* r/w attributes */ - unchar cluster_type; /* cluster properties */ - unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */ - ulong32 start_sec; /* start sector */ + u8 present; /* Flag: host drive present? */ + u8 is_logdrv; /* Flag: log. drive (master)? */ + u8 is_arraydrv; /* Flag: array drive? */ + u8 is_master; /* Flag: array drive master? */ + u8 is_parity; /* Flag: parity drive? */ + u8 is_hotfix; /* Flag: hotfix drive? */ + u8 master_no; /* number of master drive */ + u8 lock; /* drive locked? (hot plug) */ + u8 heads; /* mapping */ + u8 secs; + u16 devtype; /* further information */ + u64 size; /* capacity */ + u8 ldr_no; /* log. drive no. */ + u8 rw_attribs; /* r/w attributes */ + u8 cluster_type; /* cluster properties */ + u8 media_changed; /* Flag:MOUNT/UNMOUNT occured */ + u32 start_sec; /* start sector */ } hdr[MAX_LDRIVES]; /* host drives */ struct { - unchar lock; /* channel locked? (hot plug) */ - unchar pdev_cnt; /* physical device count */ - unchar local_no; /* local channel number */ - unchar io_cnt[MAXID]; /* current IO count */ - ulong32 address; /* channel address */ - ulong32 id_list[MAXID]; /* IDs of the phys. devices */ + u8 lock; /* channel locked? (hot plug) */ + u8 pdev_cnt; /* physical device count */ + u8 local_no; /* local channel number */ + u8 io_cnt[MAXID]; /* current IO count */ + u32 address; /* channel address */ + u32 id_list[MAXID]; /* IDs of the phys. devices */ } raw[MAXBUS]; /* SCSI channels */ struct { Scsi_Cmnd *cmnd; /* pending request */ - ushort service; /* service */ + u16 service; /* service */ } cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */ struct gdth_cmndinfo { /* per-command private info */ int index; int internal_command; /* don't call scsi_done */ gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ dma_addr_t sense_paddr; /* sense dma-addr */ - unchar priority; + u8 priority; int timeout_count; /* # of timeout calls */ volatile int wait_for_completion; - ushort status; - ulong32 info; + u16 status; + u32 info; enum dma_data_direction dma_dir; int phase; /* ???? */ int OpCode; } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */ - unchar bus_cnt; /* SCSI bus count */ - unchar tid_cnt; /* Target ID count */ - unchar bus_id[MAXBUS]; /* IOP IDs */ - unchar virt_bus; /* number of virtual bus */ - unchar more_proc; /* more /proc info supported */ - ushort cmd_cnt; /* command count in DPRAM */ - ushort cmd_len; /* length of actual command */ - ushort cmd_offs_dpmem; /* actual offset in DPRAM */ - ushort ic_all_size; /* sizeof DPRAM interf. area */ + u8 bus_cnt; /* SCSI bus count */ + u8 tid_cnt; /* Target ID count */ + u8 bus_id[MAXBUS]; /* IOP IDs */ + u8 virt_bus; /* number of virtual bus */ + u8 more_proc; /* more /proc info supported */ + u16 cmd_cnt; /* command count in DPRAM */ + u16 cmd_len; /* length of actual command */ + u16 cmd_offs_dpmem; /* actual offset in DPRAM */ + u16 ic_all_size; /* sizeof DPRAM interf. area */ gdth_cpar_str cpar; /* controller cache par. */ gdth_bfeat_str bfeat; /* controller features */ gdth_binfo_str binfo; /* controller info */ @@ -941,7 +941,7 @@ typedef struct { struct pci_dev *pdev; char oem_name[8]; #ifdef GDTH_DMA_STATISTICS - ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ + unsigned long dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ #endif struct scsi_device *sdev; } gdth_ha_str; @@ -953,65 +953,65 @@ static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd) /* INQUIRY data format */ typedef struct { - unchar type_qual; - unchar modif_rmb; - unchar version; - unchar resp_aenc; - unchar add_length; - unchar reserved1; - unchar reserved2; - unchar misc; - unchar vendor[8]; - unchar product[16]; - unchar revision[4]; -} PACKED gdth_inq_data; + u8 type_qual; + u8 modif_rmb; + u8 version; + u8 resp_aenc; + u8 add_length; + u8 reserved1; + u8 reserved2; + u8 misc; + u8 vendor[8]; + u8 product[16]; + u8 revision[4]; +} __attribute__((packed)) gdth_inq_data; /* READ_CAPACITY data format */ typedef struct { - ulong32 last_block_no; - ulong32 block_length; -} PACKED gdth_rdcap_data; + u32 last_block_no; + u32 block_length; +} __attribute__((packed)) gdth_rdcap_data; /* READ_CAPACITY (16) data format */ typedef struct { - ulong64 last_block_no; - ulong32 block_length; -} PACKED gdth_rdcap16_data; + u64 last_block_no; + u32 block_length; +} __attribute__((packed)) gdth_rdcap16_data; /* REQUEST_SENSE data format */ typedef struct { - unchar errorcode; - unchar segno; - unchar key; - ulong32 info; - unchar add_length; - ulong32 cmd_info; - unchar adsc; - unchar adsq; - unchar fruc; - unchar key_spec[3]; -} PACKED gdth_sense_data; + u8 errorcode; + u8 segno; + u8 key; + u32 info; + u8 add_length; + u32 cmd_info; + u8 adsc; + u8 adsq; + u8 fruc; + u8 key_spec[3]; +} __attribute__((packed)) gdth_sense_data; /* MODE_SENSE data format */ typedef struct { struct { - unchar data_length; - unchar med_type; - unchar dev_par; - unchar bd_length; - } PACKED hd; + u8 data_length; + u8 med_type; + u8 dev_par; + u8 bd_length; + } __attribute__((packed)) hd; struct { - unchar dens_code; - unchar block_count[3]; - unchar reserved; - unchar block_length[3]; - } PACKED bd; -} PACKED gdth_modep_data; + u8 dens_code; + u8 block_count[3]; + u8 reserved; + u8 block_length[3]; + } __attribute__((packed)) bd; +} __attribute__((packed)) gdth_modep_data; /* stack frame */ typedef struct { - ulong b[10]; /* 32/64 bit compiler ! */ -} PACKED gdth_stackframe; + unsigned long b[10]; /* 32/64 bit compiler ! */ +} __attribute__((packed)) gdth_stackframe; /* function prototyping */ diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h index 783fae737f17..b004c6165887 100644 --- a/drivers/scsi/gdth_ioctl.h +++ b/drivers/scsi/gdth_ioctl.h @@ -32,109 +32,101 @@ #define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */ #endif -/* typedefs */ -#ifdef __KERNEL__ -typedef u32 ulong32; -typedef u64 ulong64; -#endif - -#define PACKED __attribute__((packed)) - /* scatter/gather element */ typedef struct { - ulong32 sg_ptr; /* address */ - ulong32 sg_len; /* length */ -} PACKED gdth_sg_str; + u32 sg_ptr; /* address */ + u32 sg_len; /* length */ +} __attribute__((packed)) gdth_sg_str; /* scatter/gather element - 64bit addresses */ typedef struct { - ulong64 sg_ptr; /* address */ - ulong32 sg_len; /* length */ -} PACKED gdth_sg64_str; + u64 sg_ptr; /* address */ + u32 sg_len; /* length */ +} __attribute__((packed)) gdth_sg64_str; /* command structure */ typedef struct { - ulong32 BoardNode; /* board node (always 0) */ - ulong32 CommandIndex; /* command number */ - ushort OpCode; /* the command (READ,..) */ + u32 BoardNode; /* board node (always 0) */ + u32 CommandIndex; /* command number */ + u16 OpCode; /* the command (READ,..) */ union { struct { - ushort DeviceNo; /* number of cache drive */ - ulong32 BlockNo; /* block number */ - ulong32 BlockCnt; /* block count */ - ulong32 DestAddr; /* dest. addr. (if s/g: -1) */ - ulong32 sg_canz; /* s/g element count */ + u16 DeviceNo; /* number of cache drive */ + u32 BlockNo; /* block number */ + u32 BlockCnt; /* block count */ + u32 DestAddr; /* dest. addr. (if s/g: -1) */ + u32 sg_canz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED cache; /* cache service cmd. str. */ + } __attribute__((packed)) cache; /* cache service cmd. str. */ struct { - ushort DeviceNo; /* number of cache drive */ - ulong64 BlockNo; /* block number */ - ulong32 BlockCnt; /* block count */ - ulong64 DestAddr; /* dest. addr. (if s/g: -1) */ - ulong32 sg_canz; /* s/g element count */ + u16 DeviceNo; /* number of cache drive */ + u64 BlockNo; /* block number */ + u32 BlockCnt; /* block count */ + u64 DestAddr; /* dest. addr. (if s/g: -1) */ + u32 sg_canz; /* s/g element count */ gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED cache64; /* cache service cmd. str. */ + } __attribute__((packed)) cache64; /* cache service cmd. str. */ struct { - ushort param_size; /* size of p_param buffer */ - ulong32 subfunc; /* IOCTL function */ - ulong32 channel; /* device */ - ulong64 p_param; /* buffer */ - } PACKED ioctl; /* IOCTL command structure */ + u16 param_size; /* size of p_param buffer */ + u32 subfunc; /* IOCTL function */ + u32 channel; /* device */ + u64 p_param; /* buffer */ + } __attribute__((packed)) ioctl; /* IOCTL command structure */ struct { - ushort reserved; + u16 reserved; union { struct { - ulong32 msg_handle; /* message handle */ - ulong64 msg_addr; /* message buffer address */ - } PACKED msg; - unchar data[12]; /* buffer for rtc data, ... */ + u32 msg_handle; /* message handle */ + u64 msg_addr; /* message buffer address */ + } __attribute__((packed)) msg; + u8 data[12]; /* buffer for rtc data, ... */ } su; - } PACKED screen; /* screen service cmd. str. */ + } __attribute__((packed)) screen; /* screen service cmd. str. */ struct { - ushort reserved; - ulong32 direction; /* data direction */ - ulong32 mdisc_time; /* disc. time (0: no timeout)*/ - ulong32 mcon_time; /* connect time(0: no to.) */ - ulong32 sdata; /* dest. addr. (if s/g: -1) */ - ulong32 sdlen; /* data length (bytes) */ - ulong32 clen; /* SCSI cmd. length(6,10,12) */ - unchar cmd[12]; /* SCSI command */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar bus; /* SCSI bus number */ - unchar priority; /* only 0 used */ - ulong32 sense_len; /* sense data length */ - ulong32 sense_data; /* sense data addr. */ - ulong32 link_p; /* linked cmds (not supp.) */ - ulong32 sg_ranz; /* s/g element count */ + u16 reserved; + u32 direction; /* data direction */ + u32 mdisc_time; /* disc. time (0: no timeout)*/ + u32 mcon_time; /* connect time(0: no to.) */ + u32 sdata; /* dest. addr. (if s/g: -1) */ + u32 sdlen; /* data length (bytes) */ + u32 clen; /* SCSI cmd. length(6,10,12) */ + u8 cmd[12]; /* SCSI command */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 bus; /* SCSI bus number */ + u8 priority; /* only 0 used */ + u32 sense_len; /* sense data length */ + u32 sense_data; /* sense data addr. */ + u32 link_p; /* linked cmds (not supp.) */ + u32 sg_ranz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED raw; /* raw service cmd. struct. */ + } __attribute__((packed)) raw; /* raw service cmd. struct. */ struct { - ushort reserved; - ulong32 direction; /* data direction */ - ulong32 mdisc_time; /* disc. time (0: no timeout)*/ - ulong32 mcon_time; /* connect time(0: no to.) */ - ulong64 sdata; /* dest. addr. (if s/g: -1) */ - ulong32 sdlen; /* data length (bytes) */ - ulong32 clen; /* SCSI cmd. length(6,..,16) */ - unchar cmd[16]; /* SCSI command */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar bus; /* SCSI bus number */ - unchar priority; /* only 0 used */ - ulong32 sense_len; /* sense data length */ - ulong64 sense_data; /* sense data addr. */ - ulong32 sg_ranz; /* s/g element count */ + u16 reserved; + u32 direction; /* data direction */ + u32 mdisc_time; /* disc. time (0: no timeout)*/ + u32 mcon_time; /* connect time(0: no to.) */ + u64 sdata; /* dest. addr. (if s/g: -1) */ + u32 sdlen; /* data length (bytes) */ + u32 clen; /* SCSI cmd. length(6,..,16) */ + u8 cmd[16]; /* SCSI command */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 bus; /* SCSI bus number */ + u8 priority; /* only 0 used */ + u32 sense_len; /* sense data length */ + u64 sense_data; /* sense data addr. */ + u32 sg_ranz; /* s/g element count */ gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } PACKED raw64; /* raw service cmd. struct. */ + } __attribute__((packed)) raw64; /* raw service cmd. struct. */ } u; /* additional variables */ - unchar Service; /* controller service */ - unchar reserved; - ushort Status; /* command result */ - ulong32 Info; /* additional information */ + u8 Service; /* controller service */ + u8 reserved; + u16 Status; /* command result */ + u32 Info; /* additional information */ void *RequestBuffer; /* request buffer */ -} PACKED gdth_cmd_str; +} __attribute__((packed)) gdth_cmd_str; /* controller event structure */ #define ES_ASYNC 1 @@ -142,129 +134,129 @@ typedef struct { #define ES_TEST 3 #define ES_SYNC 4 typedef struct { - ushort size; /* size of structure */ + u16 size; /* size of structure */ union { char stream[16]; struct { - ushort ionode; - ushort service; - ulong32 index; - } PACKED driver; + u16 ionode; + u16 service; + u32 index; + } __attribute__((packed)) driver; struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - unchar scsi_coord[3]; - } PACKED async; + u16 ionode; + u16 service; + u16 status; + u32 info; + u8 scsi_coord[3]; + } __attribute__((packed)) async; struct { - ushort ionode; - ushort service; - ushort status; - ulong32 info; - ushort hostdrive; - unchar scsi_coord[3]; - unchar sense_key; - } PACKED sync; + u16 ionode; + u16 service; + u16 status; + u32 info; + u16 hostdrive; + u8 scsi_coord[3]; + u8 sense_key; + } __attribute__((packed)) sync; struct { - ulong32 l1, l2, l3, l4; - } PACKED test; + u32 l1, l2, l3, l4; + } __attribute__((packed)) test; } eu; - ulong32 severity; - unchar event_string[256]; -} PACKED gdth_evt_data; + u32 severity; + u8 event_string[256]; +} __attribute__((packed)) gdth_evt_data; typedef struct { - ulong32 first_stamp; - ulong32 last_stamp; - ushort same_count; - ushort event_source; - ushort event_idx; - unchar application; - unchar reserved; + u32 first_stamp; + u32 last_stamp; + u16 same_count; + u16 event_source; + u16 event_idx; + u8 application; + u8 reserved; gdth_evt_data event_data; -} PACKED gdth_evt_str; +} __attribute__((packed)) gdth_evt_str; #ifdef GDTH_IOCTL_PROC /* IOCTL structure (write) */ typedef struct { - ulong32 magic; /* IOCTL magic */ - ushort ioctl; /* IOCTL */ - ushort ionode; /* controller number */ - ushort service; /* controller service */ - ushort timeout; /* timeout */ + u32 magic; /* IOCTL magic */ + u16 ioctl; /* IOCTL */ + u16 ionode; /* controller number */ + u16 service; /* controller service */ + u16 timeout; /* timeout */ union { struct { - unchar command[512]; /* controller command */ - unchar data[1]; /* add. data */ + u8 command[512]; /* controller command */ + u8 data[1]; /* add. data */ } general; struct { - unchar lock; /* lock/unlock */ - unchar drive_cnt; /* drive count */ - ushort drives[MAX_HDRIVES];/* drives */ + u8 lock; /* lock/unlock */ + u8 drive_cnt; /* drive count */ + u16 drives[MAX_HDRIVES];/* drives */ } lockdrv; struct { - unchar lock; /* lock/unlock */ - unchar channel; /* channel */ + u8 lock; /* lock/unlock */ + u8 channel; /* channel */ } lockchn; struct { int erase; /* erase event ? */ int handle; - unchar evt[EVENT_SIZE]; /* event structure */ + u8 evt[EVENT_SIZE]; /* event structure */ } event; struct { - unchar bus; /* SCSI bus */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cmd_len; /* command length */ - unchar cmd[12]; /* SCSI command */ + u8 bus; /* SCSI bus */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cmd_len; /* command length */ + u8 cmd[12]; /* SCSI command */ } scsi; struct { - ushort hdr_no; /* host drive number */ - unchar flag; /* old meth./add/remove */ + u16 hdr_no; /* host drive number */ + u8 flag; /* old meth./add/remove */ } rescan; } iu; } gdth_iowr_str; /* IOCTL structure (read) */ typedef struct { - ulong32 size; /* buffer size */ - ulong32 status; /* IOCTL error code */ + u32 size; /* buffer size */ + u32 status; /* IOCTL error code */ union { struct { - unchar data[1]; /* data */ + u8 data[1]; /* data */ } general; struct { - ushort version; /* driver version */ + u16 version; /* driver version */ } drvers; struct { - unchar type; /* controller type */ - ushort info; /* slot etc. */ - ushort oem_id; /* OEM ID */ - ushort bios_ver; /* not used */ - ushort access; /* not used */ - ushort ext_type; /* extended type */ - ushort device_id; /* device ID */ - ushort sub_device_id; /* sub device ID */ + u8 type; /* controller type */ + u16 info; /* slot etc. */ + u16 oem_id; /* OEM ID */ + u16 bios_ver; /* not used */ + u16 access; /* not used */ + u16 ext_type; /* extended type */ + u16 device_id; /* device ID */ + u16 sub_device_id; /* sub device ID */ } ctrtype; struct { - unchar version; /* OS version */ - unchar subversion; /* OS subversion */ - ushort revision; /* revision */ + u8 version; /* OS version */ + u8 subversion; /* OS subversion */ + u16 revision; /* revision */ } osvers; struct { - ushort count; /* controller count */ + u16 count; /* controller count */ } ctrcnt; struct { int handle; - unchar evt[EVENT_SIZE]; /* event structure */ + u8 evt[EVENT_SIZE]; /* event structure */ } event; struct { - unchar bus; /* SCSI bus, 0xff: invalid */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cluster_type; /* cluster properties */ + u8 bus; /* SCSI bus, 0xff: invalid */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cluster_type; /* cluster properties */ } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } iu; } gdth_iord_str; @@ -272,53 +264,53 @@ typedef struct { /* GDTIOCTL_GENERAL */ typedef struct { - ushort ionode; /* controller number */ - ushort timeout; /* timeout */ - ulong32 info; /* error info */ - ushort status; /* status */ - ulong data_len; /* data buffer size */ - ulong sense_len; /* sense buffer size */ + u16 ionode; /* controller number */ + u16 timeout; /* timeout */ + u32 info; /* error info */ + u16 status; /* status */ + unsigned long data_len; /* data buffer size */ + unsigned long sense_len; /* sense buffer size */ gdth_cmd_str command; /* command */ } gdth_ioctl_general; /* GDTIOCTL_LOCKDRV */ typedef struct { - ushort ionode; /* controller number */ - unchar lock; /* lock/unlock */ - unchar drive_cnt; /* drive count */ - ushort drives[MAX_HDRIVES]; /* drives */ + u16 ionode; /* controller number */ + u8 lock; /* lock/unlock */ + u8 drive_cnt; /* drive count */ + u16 drives[MAX_HDRIVES]; /* drives */ } gdth_ioctl_lockdrv; /* GDTIOCTL_LOCKCHN */ typedef struct { - ushort ionode; /* controller number */ - unchar lock; /* lock/unlock */ - unchar channel; /* channel */ + u16 ionode; /* controller number */ + u8 lock; /* lock/unlock */ + u8 channel; /* channel */ } gdth_ioctl_lockchn; /* GDTIOCTL_OSVERS */ typedef struct { - unchar version; /* OS version */ - unchar subversion; /* OS subversion */ - ushort revision; /* revision */ + u8 version; /* OS version */ + u8 subversion; /* OS subversion */ + u16 revision; /* revision */ } gdth_ioctl_osvers; /* GDTIOCTL_CTRTYPE */ typedef struct { - ushort ionode; /* controller number */ - unchar type; /* controller type */ - ushort info; /* slot etc. */ - ushort oem_id; /* OEM ID */ - ushort bios_ver; /* not used */ - ushort access; /* not used */ - ushort ext_type; /* extended type */ - ushort device_id; /* device ID */ - ushort sub_device_id; /* sub device ID */ + u16 ionode; /* controller number */ + u8 type; /* controller type */ + u16 info; /* slot etc. */ + u16 oem_id; /* OEM ID */ + u16 bios_ver; /* not used */ + u16 access; /* not used */ + u16 ext_type; /* extended type */ + u16 device_id; /* device ID */ + u16 sub_device_id; /* sub device ID */ } gdth_ioctl_ctrtype; /* GDTIOCTL_EVENT */ typedef struct { - ushort ionode; + u16 ionode; int erase; /* erase event? */ int handle; /* event handle */ gdth_evt_str event; @@ -326,22 +318,22 @@ typedef struct { /* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */ typedef struct { - ushort ionode; /* controller number */ - unchar flag; /* add/remove */ - ushort hdr_no; /* drive no. */ + u16 ionode; /* controller number */ + u8 flag; /* add/remove */ + u16 hdr_no; /* drive no. */ struct { - unchar bus; /* SCSI bus */ - unchar target; /* target ID */ - unchar lun; /* LUN */ - unchar cluster_type; /* cluster properties */ + u8 bus; /* SCSI bus */ + u8 target; /* target ID */ + u8 lun; /* LUN */ + u8 cluster_type; /* cluster properties */ } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } gdth_ioctl_rescan; /* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */ typedef struct { - ushort ionode; /* controller number */ - ushort number; /* bus/host drive number */ - ushort status; /* status */ + u16 ionode; /* controller number */ + u16 number; /* bus/host drive number */ + u16 status; /* status */ } gdth_ioctl_reset; #endif diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 1258da34fbc2..ffb2b21992ba 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -43,7 +43,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int i, found; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; - ulong64 paddr; + u64 paddr; char cmnd[MAX_COMMAND_SIZE]; memset(cmnd, 0xff, 12); @@ -156,8 +156,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, off_t begin = 0,pos = 0; int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; - ulong32 cnt; - ulong64 paddr; + u32 cnt; + u64 paddr; int rc = -ENOMEM; gdth_cmd_str *gdtcmd; @@ -220,14 +220,14 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, if (ha->more_proc) sprintf(hrec, "%d.%02d.%02d-%c%03X", - (unchar)(ha->binfo.upd_fw_ver>>24), - (unchar)(ha->binfo.upd_fw_ver>>16), - (unchar)(ha->binfo.upd_fw_ver), + (u8)(ha->binfo.upd_fw_ver>>24), + (u8)(ha->binfo.upd_fw_ver>>16), + (u8)(ha->binfo.upd_fw_ver), ha->bfeat.raid ? 'R':'N', ha->binfo.upd_revision); else - sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), - (unchar)(ha->cpar.version)); + sprintf(hrec, "%d.%02d", (u8)(ha->cpar.version>>8), + (u8)(ha->cpar.version)); size = sprintf(buffer+len, " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", @@ -281,7 +281,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, pds->bid = ha->raw[i].local_no; pds->first = 0; pds->entries = ha->raw[i].pdev_cnt; - cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / + cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) / sizeof(pds->list[0]); if (pds->entries > cnt) pds->entries = cnt; @@ -604,7 +604,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, size = sprintf(buffer+len, " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", - (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); + (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); len += size; pos = begin + len; if (pos < offset) { len = 0; @@ -664,9 +664,9 @@ free_fail: } static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - ulong64 *paddr) + u64 *paddr) { - ulong flags; + unsigned long flags; char *ret_val; if (size == 0) @@ -691,9 +691,9 @@ static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, return ret_val; } -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr) +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr) { - ulong flags; + unsigned long flags; if (buf == ha->pscratch) { spin_lock_irqsave(&ha->smp_lock, flags); @@ -705,16 +705,16 @@ static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr) } #ifdef GDTH_IOCTL_PROC -static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size) +static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size) { - ulong flags; + unsigned long flags; int ret_val; spin_lock_irqsave(&ha->smp_lock, flags); ret_val = FALSE; if (ha->scratch_busy) { - if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size) + if (((gdth_iord_str *)ha->pscratch)->size == (u32)size) ret_val = TRUE; } spin_unlock_irqrestore(&ha->smp_lock, flags); @@ -724,11 +724,11 @@ static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size) static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) { - ulong flags; + unsigned long flags; int i; Scsi_Cmnd *scp; struct gdth_cmndinfo *cmndinfo; - unchar b, t; + u8 b, t; spin_lock_irqsave(&ha->smp_lock, flags); @@ -738,8 +738,8 @@ static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) b = scp->device->channel; t = scp->device->id; - if (!SPECIAL_SCP(scp) && t == (unchar)id && - b == (unchar)busnum) { + if (!SPECIAL_SCP(scp) && t == (u8)id && + b == (u8)busnum) { cmndinfo->wait_for_completion = 0; spin_unlock_irqrestore(&ha->smp_lock, flags); while (!cmndinfo->wait_for_completion) diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h index 9b900cc9ebe8..dab15f59f2cc 100644 --- a/drivers/scsi/gdth_proc.h +++ b/drivers/scsi/gdth_proc.h @@ -17,8 +17,8 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, int length, gdth_ha_str *ha); static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - ulong64 *paddr); -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr); + u64 *paddr); +static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr); static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); #endif -- GitLab From 7da5087971b1a187f92be4efb74a991ac9ccb0a3 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:04:12 +0530 Subject: [PATCH 0891/3892] [SCSI] be2iscsi: Use start cid and number of cid and icd from FW This patch enablesi be2iscsi to use the start number and number of cids/icd provided by FW rather than hard coded values. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 7 +- drivers/scsi/be2iscsi/be_main.c | 106 +++++++++++++++++-------------- drivers/scsi/be2iscsi/be_main.h | 10 +-- drivers/scsi/be2iscsi/be_mgmt.c | 11 +++- 4 files changed, 75 insertions(+), 59 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d587b0362f18..2b3c58bd6529 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -431,9 +431,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, } SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ", beiscsi_ep->ep_cid); - phba->ep_array[beiscsi_ep->ep_cid] = ep; - if (beiscsi_ep->ep_cid > - (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) { + phba->ep_array[beiscsi_ep->ep_cid - + phba->fw_config.iscsi_cid_start] = ep; + if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); return ret; } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1a557fa77888..6c512b6416c2 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -230,29 +230,27 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) static void beiscsi_get_params(struct beiscsi_hba *phba) { - phba->params.ios_per_ctrl = BE2_IO_DEPTH; - phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS; - phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS; - phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2; + phba->params.ios_per_ctrl = (phba->fw_config.iscsi_icd_count + - (phba->fw_config.iscsi_cid_count + + BE2_TMFS + + BE2_NOPOUT_REQ)); + phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count; + phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count;; + phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;; phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; phba->params.eq_timer = 64; phba->params.num_eq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) ? 1024 : phba->params.num_eq_entries; SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n", - phba->params.num_eq_entries); + phba->params.num_eq_entries); phba->params.num_cq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; - SE_DEBUG(DBG_LVL_8, - "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d" - "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n", - phba->params.num_cq_entries, BE2_CMDS_PER_CXN, - BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS); + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.wrbs_per_cxn = 256; } @@ -877,7 +875,8 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, } else { pwrb_context = &phwi_ctrlr->wrb_context[((psol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6)]; + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; @@ -939,7 +938,8 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, pwrb_context = &phwi_ctrlr-> wrb_context[((psol->dw[offsetof (struct amap_sol_cqe, cid) / 32] - & SOL_CID_MASK) >> 6)]; + & SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; @@ -1077,7 +1077,8 @@ hwi_get_async_handle(struct beiscsi_hba *phba, WARN_ON(!pasync_handle); - pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid; + pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start; pasync_handle->is_header = is_header; pasync_handle->buffer_len = ((pdpdu_cqe-> dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] @@ -1327,9 +1328,10 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, } status = beiscsi_process_async_pdu(beiscsi_conn, phba, - beiscsi_conn->beiscsi_conn_cid, - phdr, hdr_len, pfirst_buffer, - buf_len); + (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start), + phdr, hdr_len, pfirst_buffer, + buf_len); if (status == 0) hwi_free_async_msg(phba, cri); @@ -1456,10 +1458,10 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) } } else { - beiscsi_conn = phba->conn_table[(u32) (sol-> + beiscsi_conn = phba->conn_table[(u32) ((sol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6]; - + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; if (!beiscsi_conn || !beiscsi_conn->ep) { shost_printk(KERN_WARNING, phba->shost, "Connection table empty for cid = %d\n", @@ -1557,8 +1559,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); @@ -1575,8 +1577,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "received/sent on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); @@ -1586,8 +1588,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "received on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); break; } @@ -2383,7 +2385,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, &paddr); if (!cq_vaddress) goto create_cq_error; - ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2, + ret = be_fill_queue(cq, phba->params.num_cq_entries, sizeof(struct sol_cqe), cq_vaddress); if (ret) { shost_printk(KERN_ERR, phba->shost, @@ -2634,7 +2636,8 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, "wrbq create failed."); return status; } - phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id; + phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i]. + id; } kfree(pwrb_arr); return 0; @@ -2807,12 +2810,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) ring_mode = 1; else ring_mode = 0; - status = mgmt_get_fw_config(ctrl, phba); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Error getting fw config\n"); - goto error; - } status = beiscsi_create_cqs(phba, phwi_context); if (status != 0) { @@ -3032,7 +3029,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); pfrag += phba->params.num_sge_per_io; psgl_handle->sgl_index = - phba->fw_config.iscsi_cid_start + arr_index++; + phba->fw_config.iscsi_icd_start + arr_index++; } idx++; } @@ -3064,7 +3061,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) kfree(phba->cid_array); return -ENOMEM; } - new_cid = phba->fw_config.iscsi_icd_start; + new_cid = phba->fw_config.iscsi_cid_start; for (i = 0; i < phba->params.cxns_per_ctrl; i++) { phba->cid_array[i] = new_cid; new_cid += 2; @@ -3219,7 +3216,8 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, * We can always use 0 here because it is reserved by libiscsi for * login/startup related tasks. */ - pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0); + pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start), 0); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, @@ -3328,7 +3326,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->bhs_pa.u.a64.address = paddr; io_task->libiscsi_itt = (itt_t)task->itt; io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid, + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start, task->itt); io_task->conn = beiscsi_conn; @@ -3372,10 +3371,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) (io_task->psgl_handle->sgl_index)); if (ring_mode) { phba->sgl_hndl_array[io_task->psgl_handle->sgl_index - - phba->fw_config.iscsi_cid_start] = + phba->fw_config.iscsi_icd_start] = io_task->psgl_handle; io_task->psgl_handle->task = task; - io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid; + io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start; } else io_task->pwrb_handle->pio_handle = task; @@ -3384,7 +3384,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) free_hndls: phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[ + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start]; free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, @@ -3404,7 +3406,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) struct hwi_controller *phwi_ctrlr; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid + - phba->fw_config.iscsi_cid_start]; if (io_task->pwrb_handle) { free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; @@ -3561,7 +3564,8 @@ static int beiscsi_mtask(struct iscsi_task *task) session = conn->session; i = ((struct iscsi_tm *)task->hdr)->rtt; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[cid]; + pwrb_context = &phwi_ctrlr->wrb_context[cid - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i) >> 16]; aborted_task = pwrb_handle->pio_handle; @@ -3754,6 +3758,14 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, spin_lock_init(&phba->io_sgl_lock); spin_lock_init(&phba->mgmt_sgl_lock); spin_lock_init(&phba->isr_lock); + ret = mgmt_get_fw_config(&phba->ctrl, phba); + if (ret != 0) { + shost_printk(KERN_ERR, phba->shost, + "Error getting fw config\n"); + goto free_port; + } + phba->shost->max_id = phba->fw_config.iscsi_cid_count; + phba->shost->can_queue = phba->params.ios_per_ctrl; beiscsi_get_params(phba); ret = beiscsi_init_port(phba); if (ret < 0) { @@ -3859,7 +3871,7 @@ struct iscsi_transport beiscsi_iscsi_transport = { ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | - ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | + ISCSI_LU_RESET_TMO | ISCSI_PING_TMO | ISCSI_RECV_TMO | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 25e6b208b771..0e2eac627bee 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -46,23 +46,18 @@ #define OC_DEVICE_ID3 0x712 #define OC_DEVICE_ID4 0x222 -#define BE2_MAX_SESSIONS 64 +#define BE2_IO_DEPTH 1024 +#define BE2_MAX_SESSIONS 256 #define BE2_CMDS_PER_CXN 128 -#define BE2_LOGOUTS BE2_MAX_SESSIONS #define BE2_TMFS 16 #define BE2_NOPOUT_REQ 16 -#define BE2_ASYNCPDUS BE2_MAX_SESSIONS -#define BE2_MAX_ICDS 2048 #define BE2_SGE 32 #define BE2_DEFPDU_HDR_SZ 64 #define BE2_DEFPDU_DATA_SZ 8192 -#define BE2_IO_DEPTH \ - (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ)) #define MAX_CPUS 31 #define BEISCSI_SGLIST_ELEMENTS BE2_SGE -#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */ #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ #define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ @@ -802,7 +797,6 @@ struct hwi_controller { struct be_ring default_pdu_hdr; struct be_ring default_pdu_data; struct hwi_context_memory *phwi_ctxt; - unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN]; }; enum hwh_type_enum { diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 79c2bd525a84..df1b327fe17b 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -48,6 +48,14 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, pfw_cfg->ulp[0].sq_base; phba->fw_config.iscsi_cid_count = pfw_cfg->ulp[0].sq_count; + if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { + status = 1; + shost_printk(KERN_WARNING, phba->shost, + "FW reported MAX CXNS as %d \t" + "Max Supported = %d. Failing to load \n", + phba->fw_config.iscsi_cid_count, + BE2_MAX_SESSIONS); + } } else { shost_printk(KERN_WARNING, phba->shost, "Failed in mgmt_get_fw_config \n"); @@ -317,7 +325,8 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct tcp_connect_and_offload_out *ptcpcnct_out = embedded_payload(wrb); - ep = phba->ep_array[ptcpcnct_out->cid]; + ep = phba->ep_array[ptcpcnct_out->cid - + phba->fw_config.iscsi_cid_start]; beiscsi_ep = ep->dd_data; beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; beiscsi_ep->cid_vld = 1; -- GitLab From c24622886fb934313a2a43ea1f516cbf1ddd947b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:05:34 +0530 Subject: [PATCH 0892/3892] [SCSI] be2iscsi: Move freeing of resources to stop_conn We need to hold on to ep resources untill invalidate and close connection are completed Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 23 ++++++++++------------- drivers/scsi/be2iscsi/be_main.c | 31 ++++++++++--------------------- drivers/scsi/be2iscsi/be_mgmt.h | 1 + 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 2b3c58bd6529..f22918427a2e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -460,14 +460,12 @@ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) * beiscsi_free_ep - free endpoint * @ep: pointer to iscsi endpoint structure */ -static void beiscsi_free_ep(struct iscsi_endpoint *ep) +static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) { - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; beiscsi_put_cid(phba, beiscsi_ep->ep_cid); beiscsi_ep->phba = NULL; - iscsi_destroy_endpoint(ep); } /** @@ -498,7 +496,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, if (phba->state) { ret = -EBUSY; - SE_DEBUG(DBG_LVL_1, "The Adapet state is Not UP \n"); + SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); } @@ -510,9 +508,10 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; + beiscsi_ep->openiscsi_ep = ep; if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { - SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; goto free_ep; } @@ -520,7 +519,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ep; free_ep: - beiscsi_free_ep(ep); + beiscsi_free_ep(beiscsi_ep); return ERR_PTR(ret); } @@ -547,15 +546,14 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) * @ep: The iscsi endpoint * @flag: The type of connection closure */ -static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag) +static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) { int ret = 0; - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; if (MGMT_STATUS_SUCCESS != mgmt_upload_connection(phba, beiscsi_ep->ep_cid, - CONNECTION_UPLOAD_GRACEFUL)) { + flag)) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", beiscsi_ep->ep_cid); ret = -1; @@ -575,19 +573,15 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_hba *phba; - int flag = 0; beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n"); if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); - beiscsi_close_conn(ep, flag); } - beiscsi_free_ep(ep); } /** @@ -637,6 +631,9 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); } + beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); + beiscsi_free_ep(beiscsi_ep); + iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); iscsi_conn_stop(cls_conn, flag); } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6c512b6416c2..139002395d99 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1434,6 +1434,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) unsigned int tot_nump = 0; struct beiscsi_conn *beiscsi_conn; struct sgl_handle *psgl_handle = NULL; + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_endpoint *ep; struct beiscsi_hba *phba; cq = pbe_eq->cq; @@ -1449,28 +1451,15 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) dw[offsetof(struct amap_sol_cqe_ring, icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6)]; - beiscsi_conn = phba->conn_table[psgl_handle->cid]; - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - psgl_handle->cid); - return 0; - } - + ep = phba->ep_array[psgl_handle->cid]; } else { - beiscsi_conn = phba->conn_table[(u32) ((sol-> - dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6) - + ep = phba->ep_array[(u32) ((sol-> + dw[offsetof(struct amap_sol_cqe, cid) / 32] & + SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - (u32)(sol->dw[offsetof(struct amap_sol_cqe, - cid) / 32] & SOL_CID_MASK) >> 6); - return 0; - } } - + beiscsi_ep = ep->dd_data; + beiscsi_conn = beiscsi_ep->conn; if (num_processed >= 32) { hwi_ring_cq_db(phba, cq->id, num_processed, 0, 0); @@ -3044,7 +3033,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) { int i, new_cid; - phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl, + phba->cid_array = kzalloc(sizeof(void *) * phba->params.cxns_per_ctrl, GFP_KERNEL); if (!phba->cid_array) { shost_printk(KERN_ERR, phba->shost, @@ -3052,7 +3041,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) "hba_setup_cid_tbls\n"); return -ENOMEM; } - phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) * + phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) * phba->params.cxns_per_ctrl * 2, GFP_KERNEL); if (!phba->ep_array) { shost_printk(KERN_ERR, phba->shost, diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 24eaff923f85..6bc59e8e1fe5 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -231,6 +231,7 @@ struct beiscsi_endpoint { struct beiscsi_hba *phba; struct beiscsi_sess *sess; struct beiscsi_conn *conn; + struct iscsi_endpoint *openiscsi_ep; unsigned short ip_type; char dst6_addr[ISCSI_ADDRESS_BUF_LEN]; unsigned long dst_addr; -- GitLab From d543148883f65c34e6cd54c5e9ed0592dfbb6acb Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:06:21 +0530 Subject: [PATCH 0893/3892] [SCSI] be2iscsi: Link Wrb with next Wrb This patch will link the current allocated wrb with the next wrb that will be allocated. This is a requirement from the chip. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 19 ++++++++++--------- drivers/scsi/be2iscsi/be_main.h | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 139002395d99..ac76b14ec4c1 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -629,29 +629,30 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * alloc_wrb_handle - To allocate a wrb handle * @phba: The hba pointer * @cid: The cid to use for allocation - * @index: index allocation and wrb index * * This happens under session_lock until submission to chip */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index) +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) { struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle; + struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[cid]; - if (pwrb_context->wrb_handles_available) { + if (pwrb_context->wrb_handles_available >= 2) { pwrb_handle = pwrb_context->pwrb_handle_base[ pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; - pwrb_handle->nxt_wrb_index = pwrb_handle->wrb_index; if (pwrb_context->alloc_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; + + pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ + pwrb_context->alloc_index]; + pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; } else pwrb_handle = NULL; return pwrb_handle; @@ -3206,7 +3207,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, * login/startup related tasks. */ pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start), 0); + phba->fw_config.iscsi_cid_start)); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, @@ -3316,8 +3317,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->libiscsi_itt = (itt_t)task->itt; io_task->pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start, - task->itt); + phba->fw_config.iscsi_cid_start + ); io_task->conn = beiscsi_conn; task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 0e2eac627bee..0553f49db9be 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -651,8 +651,7 @@ struct amap_iscsi_wrb { } __packed; -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index); +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); -- GitLab From 7bd6e25cdbee7d4f6bc4946dc914310220e637b8 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:07:02 +0530 Subject: [PATCH 0894/3892] [SCSI] be2iscsi: Added opcode for LOGOUT_RSP, TEXT_RESP, TMFUNC_RSP This patch adds opcodes in thecompletion path that were missed out earlier Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index ac76b14ec4c1..4a855a9c7126 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -559,6 +559,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n"); break; case ISCSI_OP_LOGIN_RSP: + case ISCSI_OP_TEXT_RSP: task = conn->login_task; io_task = task->dd_data; login_hdr = (struct iscsi_hdr *)ppdu; @@ -810,6 +811,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, struct iscsi_conn *conn = beiscsi_conn->conn; hdr = (struct iscsi_logout_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_LOGOUT_RSP; hdr->t2wait = 5; hdr->t2retain = 0; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] @@ -824,6 +826,9 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, & SOL_EXP_CMD_SN_MASK) + ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) / 32] & SOL_CMD_WND_MASK) >> 24) - 1); + hdr->dlength[0] = 0; + hdr->dlength[1] = 0; + hdr->dlength[2] = 0; hdr->hlength = 0; hdr->itt = io_task->libiscsi_itt; __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); @@ -838,6 +843,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn, struct beiscsi_io_task *io_task = task->dd_data; hdr = (struct iscsi_tm_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] & SOL_FLAGS_MASK) >> 24) | 0x80; hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / -- GitLab From 2807afb7411b97834fc7338f3735f3d152443551 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:07:49 +0530 Subject: [PATCH 0895/3892] [SCSI] be2iscsi:moved pci_set_drvdata to inside beiscsi_hba_alloc This patch moves pci_set_drvdata to inside beiscsi_hba_alloc Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 4a855a9c7126..18471ede7f80 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -112,6 +112,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) memset(phba, 0, sizeof(*phba)); phba->shost = shost; phba->pcidev = pci_dev_get(pcidev); + pci_set_drvdata(pcidev, phba); if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; @@ -3734,7 +3735,6 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, } SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba); - pci_set_drvdata(pcidev, phba); if (enable_msix) num_cpus = find_num_cpus(); else -- GitLab From d7aea67b8a7665fe5e53cdf59ba76c9b8d67b751 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:08:39 +0530 Subject: [PATCH 0896/3892] [SCSI] be2iscsi: Use of opcode in beiscsi_alloc_pdu This patch enables use of opcode that is passed in Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 18471ede7f80..0fae26468a09 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3339,7 +3339,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) goto free_hndls; } else { io_task->scsi_cmnd = NULL; - if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { + if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { if (!beiscsi_conn->login_in_progress) { spin_lock(&phba->mgmt_sgl_lock); io_task->psgl_handle = (struct sgl_handle *) -- GitLab From 0ecb0b45f22df911c564070b64af21db36934f0f Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:09:19 +0530 Subject: [PATCH 0897/3892] [SCSI] be2iscsi: decide which requests need completion This patch decides whether ack based completion is required or not Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 0fae26468a09..26d7016492da 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3546,6 +3546,11 @@ static int beiscsi_mtask(struct iscsi_task *task) else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD); + if (task->hdr->ttt == ISCSI_RESERVED_TAG) + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); + else + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); + hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: @@ -3554,6 +3559,7 @@ static int beiscsi_mtask(struct iscsi_task *task) else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); break; -- GitLab From 51a462500fbed4a1e8110dc60a421a3f12b9580b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:10:01 +0530 Subject: [PATCH 0898/3892] [SCSI] be2iscsi: No requirement for endianess change for data_count This patch removes the endianess change that was wrongly added for data_count Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 26d7016492da..6170548a5289 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3607,7 +3607,7 @@ static int beiscsi_mtask(struct iscsi_task *task) } AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, - be32_to_cpu(task->data_count)); + task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, io_task->pwrb_handle->nxt_wrb_index); be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); -- GitLab From 756d29c8c7ed8887ed7d752371ce2f6d12399267 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:10:46 +0530 Subject: [PATCH 0899/3892] [SCSI] be2iscsi: Enable async mode for mcc rings This patches enables async mode for mcc rings so that multiple requests can be queued. Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be.h | 16 +++- drivers/scsi/be2iscsi/be_cmds.c | 82 +++++++++++++++++--- drivers/scsi/be2iscsi/be_cmds.h | 12 ++- drivers/scsi/be2iscsi/be_iscsi.c | 100 +++++++++++++++++++++--- drivers/scsi/be2iscsi/be_main.c | 83 ++++++++++++++++++-- drivers/scsi/be2iscsi/be_main.h | 2 + drivers/scsi/be2iscsi/be_mgmt.c | 128 +++++++++++++++++-------------- drivers/scsi/be2iscsi/be_mgmt.h | 3 - 8 files changed, 330 insertions(+), 96 deletions(-) diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index a93a5040f087..3861cf44dc15 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -24,6 +24,7 @@ #define FW_VER_LEN 32 #define MCC_Q_LEN 128 #define MCC_CQ_LEN 256 +#define MAX_MCC_CMD 16 struct be_dma_mem { void *va; @@ -57,6 +58,11 @@ static inline void *queue_head_node(struct be_queue_info *q) return q->dma_mem.va + q->head * q->entry_size; } +static inline void *queue_get_wrb(struct be_queue_info *q, unsigned int wrb_num) +{ + return q->dma_mem.va + wrb_num * q->entry_size; +} + static inline void *queue_tail_node(struct be_queue_info *q) { return q->dma_mem.va + q->tail * q->entry_size; @@ -104,15 +110,19 @@ struct be_ctrl_info { spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ spinlock_t mcc_cq_lock; - /* MCC Async callback */ - void (*async_cb) (void *adapter, bool link_up); - void *adapter_ctxt; + wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1]; + unsigned int mcc_tag[MAX_MCC_CMD]; + unsigned int mcc_numtag[MAX_MCC_CMD + 1]; + unsigned short mcc_alloc_index; + unsigned short mcc_free_index; + unsigned int mcc_tag_available; }; #include "be_cmds.h" #define PAGE_SHIFT_4K 12 #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) +#define mcc_timeout 120000 /* 5s timeout */ /* Returns number of pages spanned by the data starting at the given addr */ #define PAGES_4K_SPANNED(_address, size) \ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index f008708f1b08..d4a0d1da4875 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -19,7 +19,7 @@ #include "be_mgmt.h" #include "be_main.h" -static void be_mcc_notify(struct beiscsi_hba *phba) +void be_mcc_notify(struct beiscsi_hba *phba) { struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; u32 val = 0; @@ -29,6 +29,52 @@ static void be_mcc_notify(struct beiscsi_hba *phba) iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); } +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) +{ + unsigned int tag = 0; + unsigned int num = 0; + +mcc_tag_rdy: + if (phba->ctrl.mcc_tag_available) { + tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; + phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; + phba->ctrl.mcc_numtag[tag] = 0; + } else { + udelay(100); + num++; + if (num < mcc_timeout) + goto mcc_tag_rdy; + } + if (tag) { + phba->ctrl.mcc_tag_available--; + if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) + phba->ctrl.mcc_alloc_index = 0; + else + phba->ctrl.mcc_alloc_index++; + } + return tag; +} + +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag) +{ + spin_lock(&ctrl->mbox_lock); + tag = tag & 0x000000FF; + ctrl->mcc_tag[ctrl->mcc_free_index] = tag; + if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) + ctrl->mcc_free_index = 0; + else + ctrl->mcc_free_index++; + ctrl->mcc_tag_available++; + spin_unlock(&ctrl->mbox_lock); +} + +bool is_link_state_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_LINK_STATE); +} + static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) { if (compl->flags != 0) { @@ -64,12 +110,30 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, return 0; } - -static inline bool is_link_state_evt(u32 trailer) +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl) { - return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & - ASYNC_TRAILER_EVENT_CODE_MASK) == - ASYNC_EVENT_CODE_LINK_STATE); + u16 compl_status, extd_status; + unsigned short tag; + + be_dws_le_to_cpu(compl, 4); + + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; + /* The ctrl.mcc_numtag[tag] is filled with + * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status, + * [7:0] = compl_status + */ + tag = (compl->tag0 & 0x000000FF); + extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & + CQE_STATUS_EXTD_MASK; + + ctrl->mcc_numtag[tag] = 0x80000000; + ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); + ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; + ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); + wake_up_interruptible(&ctrl->mcc_wait[tag]); + return 0; } static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba) @@ -89,7 +153,7 @@ static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session) iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); } -static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, struct be_async_event_link_state *evt) { switch (evt->port_link_status) { @@ -162,7 +226,6 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba) /* Wait till no more pending mcc requests are present */ static int be_mcc_wait_compl(struct beiscsi_hba *phba) { -#define mcc_timeout 120000 /* 5s timeout */ int i, status; for (i = 0; i < mcc_timeout; i++) { status = beiscsi_process_mcc(phba); @@ -372,9 +435,10 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba) BUG_ON(atomic_read(&mccq->used) >= mccq->len); wrb = queue_head_node(mccq); + memset(wrb, 0, sizeof(*wrb)); + wrb->tag0 = (mccq->head & 0x000000FF) << 16; queue_head_inc(mccq); atomic_inc(&mccq->used); - memset(wrb, 0, sizeof(*wrb)); return wrb; } diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 5de8acb924cb..69dddfaebe59 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -425,14 +425,20 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, int be_poll_mcc(struct be_ctrl_info *ctrl); unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr); - +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba); int be_mcc_notify_wait(struct beiscsi_hba *phba); +void be_mcc_notify(struct beiscsi_hba *phba); +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba); +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, + struct be_async_event_link_state *evt); +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl); int be_mbox_notify(struct be_ctrl_info *ctrl); @@ -448,6 +454,8 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, struct be_queue_info *wrbq); +bool is_link_state_evt(u32 trailer); + struct be_default_pdu_context { u32 dw[4]; } __packed; diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index f22918427a2e..95694d3d2089 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -101,6 +101,7 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) struct iscsi_session *sess = cls_session->dd_data; struct beiscsi_session *beiscsi_sess = sess->dd_data; + SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n"); pci_pool_destroy(beiscsi_sess->bhs_pool); iscsi_session_teardown(cls_session); } @@ -224,6 +225,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, struct beiscsi_conn *beiscsi_conn = conn->dd_data; int len = 0; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_1, @@ -254,6 +256,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, struct iscsi_session *session = conn->session; int ret; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param); ret = iscsi_set_param(cls_conn, param, buf, buflen); if (ret) return ret; @@ -293,12 +296,41 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); + struct be_cmd_resp_get_mac_addr *resp; + struct be_mcc_wrb *wrb; + unsigned int tag, wrb_num; int len = 0; + unsigned short status, extd_status; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - be_cmd_get_mac_addr(phba, phba->mac_address); - len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); + tag = be_cmd_get_mac_addr(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n"); + return -1; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + " status = %d extd_status = %d \n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -1; + } else { + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + resp = embedded_payload(wrb); + memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); + len = sysfs_format_mac(buf, phba->mac_address, + ETH_ALEN); + } break; default: return iscsi_host_get_param(shost, param, buf); @@ -378,6 +410,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_offload_params params; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n"); memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) @@ -422,8 +455,14 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, { struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_out *ptcpcnct_out; + unsigned short status, extd_status; + unsigned int tag, wrb_num; int ret = -1; + SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); if (beiscsi_ep->ep_cid == 0xFFFF) { SE_DEBUG(DBG_LVL_1, "No free cid available\n"); @@ -440,7 +479,35 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, } beiscsi_ep->cid_vld = 0; - return mgmt_open_connection(phba, dst_addr, beiscsi_ep); + tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep); + if (!tag) { + SE_DEBUG(DBG_LVL_1, + "mgmt_invalidate_connection Failed for cid=%d \n", + beiscsi_ep->ep_cid); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + } + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" + " status = %d extd_status = %d \n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -1; + } else { + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + + ptcpcnct_out = embedded_payload(wrb); + beiscsi_ep = ep->dd_data; + beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; + beiscsi_ep->cid_vld = 1; + SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); + } + return 0; } /** @@ -509,7 +576,6 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; beiscsi_ep->openiscsi_ep = ep; - if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; @@ -549,16 +615,19 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) { int ret = 0; + unsigned int tag; struct beiscsi_hba *phba = beiscsi_ep->phba; - if (MGMT_STATUS_SUCCESS != - mgmt_upload_connection(phba, beiscsi_ep->ep_cid, - flag)) { + tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); + if (!tag) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", beiscsi_ep->ep_cid); ret = -1; + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } - return ret; } @@ -576,6 +645,8 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", + beiscsi_ep->ep_cid); if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; @@ -614,22 +685,27 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) struct iscsi_session *session = conn->session; struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); - unsigned int status; + unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n"); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); return; } - status = mgmt_invalidate_connection(phba, beiscsi_ep, + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", + beiscsi_ep->ep_cid); + tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 1, savecfg_flag); - if (status != MGMT_STATUS_SUCCESS) { + if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); beiscsi_free_ep(beiscsi_ep); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6170548a5289..a6a2c6469677 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -442,7 +442,7 @@ static irqreturn_t be_isr(int irq, void *dev_id) if (phba->todo_mcc_cq) queue_work(phba->wq, &phba->work_cqs); - if ((num_mcceq_processed) && (!num_ioeq_processed)) + if ((num_mcceq_processed) && (!num_ioeq_processed)) hwi_ring_eq_db(phba, eq->id, 0, (num_ioeq_processed + num_mcceq_processed) , 1, 1); @@ -651,7 +651,6 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; - pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ pwrb_context->alloc_index]; pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; @@ -791,6 +790,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn, memcpy(task->sc->sense_buffer, sense, min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); } + if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) { if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] & SOL_RES_CNT_MASK) @@ -1432,6 +1432,48 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, hwi_post_async_buffers(phba, pasync_handle->is_header); } +static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba) +{ + struct be_queue_info *mcc_cq; + struct be_mcc_compl *mcc_compl; + unsigned int num_processed = 0; + + mcc_cq = &phba->ctrl.mcc_obj.cq; + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { + + if (num_processed >= 32) { + hwi_ring_cq_db(phba, mcc_cq->id, + num_processed, 0, 0); + num_processed = 0; + } + if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ + if (is_link_state_evt(mcc_compl->flags)) + /* Interpret compl as a async link evt */ + beiscsi_async_link_state_process(phba, + (struct be_async_event_link_state *) mcc_compl); + else + SE_DEBUG(DBG_LVL_1, + " Unsupported Async Event, flags" + " = 0x%08x \n", mcc_compl->flags); + } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { + be_mcc_compl_process_isr(&phba->ctrl, mcc_compl); + atomic_dec(&phba->ctrl.mcc_obj.q.used); + } + + mcc_compl->flags = 0; + queue_tail_inc(mcc_cq); + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + num_processed++; + } + + if (num_processed > 0) + hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0); + +} static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) { @@ -1468,6 +1510,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) } beiscsi_ep = ep->dd_data; beiscsi_conn = beiscsi_ep->conn; + if (num_processed >= 32) { hwi_ring_cq_db(phba, cq->id, num_processed, 0, 0); @@ -1603,7 +1646,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) return tot_nump; } -static void beiscsi_process_all_cqs(struct work_struct *work) +void beiscsi_process_all_cqs(struct work_struct *work) { unsigned long flags; struct hwi_controller *phwi_ctrlr; @@ -1623,6 +1666,7 @@ static void beiscsi_process_all_cqs(struct work_struct *work) spin_lock_irqsave(&phba->isr_lock, flags); phba->todo_mcc_cq = 0; spin_unlock_irqrestore(&phba->isr_lock, flags); + beiscsi_process_mcc_isr(phba); } if (phba->todo_cq) { @@ -3160,6 +3204,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) struct be_queue_info *eq; struct be_eq_entry *eqe = NULL; int i, eq_msix; + unsigned int num_processed; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -3171,13 +3216,17 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) for (i = 0; i < (phba->num_cpus + eq_msix); i++) { eq = &phwi_context->be_eq[i].q; eqe = queue_tail_node(eq); - + num_processed = 0; while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); + num_processed++; } + + if (num_processed) + hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); } } @@ -3189,8 +3238,9 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) if (mgmt_status) shost_printk(KERN_WARNING, phba->shost, "mgmt_epfw_cleanup FAILED \n"); - hwi_cleanup(phba); + hwi_purge_eq(phba); + hwi_cleanup(phba); if (ring_mode) kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); @@ -3519,6 +3569,7 @@ static int beiscsi_mtask(struct iscsi_task *task) unsigned int doorbell = 0; unsigned int i, cid; struct iscsi_task *aborted_task; + unsigned int tag; cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; @@ -3550,7 +3601,6 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); else AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); - hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: @@ -3579,9 +3629,18 @@ static int beiscsi_mtask(struct iscsi_task *task) if (!aborted_io_task->scsi_cmnd) return 0; - mgmt_invalidate_icds(phba, + tag = mgmt_invalidate_icds(phba, aborted_io_task->psgl_handle->sgl_index, cid); + if (!tag) { + shost_printk(KERN_WARNING, phba->shost, + "mgmt_invalidate_icds could not be" + " submitted\n"); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); + } if (ring_mode) io_task->psgl_handle->type = INI_TMF_CMD; else @@ -3656,7 +3715,6 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); } - static void beiscsi_remove(struct pci_dev *pcidev) { struct beiscsi_hba *phba = NULL; @@ -3776,6 +3834,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_port; } + for (i = 0; i < MAX_MCC_CMD ; i++) { + init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); + phba->ctrl.mcc_tag[i] = i + 1; + phba->ctrl.mcc_numtag[i + 1] = 0; + phba->ctrl.mcc_tag_available++; + } + + phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; + snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u", phba->shost->host_no); phba->wq = create_workqueue(phba->wq_name); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 0553f49db9be..4cde8f6eb5bc 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -655,6 +655,8 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); +void beiscsi_process_all_cqs(struct work_struct *work); + struct pdu_nop_out { u32 dw[12]; }; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index df1b327fe17b..18f80411aef6 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -148,10 +148,17 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, { struct be_dma_mem nonemb_cmd; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_sge *sge = nonembedded_sgl(wrb); + struct be_mcc_wrb *wrb; + struct be_sge *sge; struct invalidate_commands_params_in *req; - int status = 0; + unsigned int tag = 0; + + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, sizeof(struct invalidate_commands_params_in), @@ -164,8 +171,9 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, } nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); req = nonemb_cmd.va; - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + wrb = wrb_from_mccq(phba); + sge = nonembedded_sgl(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, @@ -180,14 +188,12 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); if (nonemb_cmd.va) pci_free_consistent(ctrl->pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); - return status; + return tag; } unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, @@ -197,13 +203,19 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short savecfg_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct iscsi_invalidate_connection_params_in *req = - embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct iscsi_invalidate_connection_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + wrb->tag0 |= tag; + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, @@ -216,35 +228,37 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, else req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; req->save_cfg = savecfg_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n"); - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_upload_params_in *req = embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct tcp_upload_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); req->id = (unsigned short)cid; req->upload_type = (unsigned char)upload_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } int mgmt_open_connection(struct beiscsi_hba *phba, @@ -256,13 +270,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_connect_and_offload_in *req = embedded_payload(wrb); + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_in *req; unsigned short def_hdr_id; unsigned short def_data_id; struct phys_addr template_address = { 0, 0 }; struct phys_addr *ptemplate_address; - int status = 0; + unsigned int tag = 0; unsigned int i; unsigned short cid = beiscsi_ep->ep_cid; @@ -274,7 +288,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba, ptemplate_address = &template_address; ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, @@ -319,47 +340,36 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->do_offload = 1; req->dataout_template_pa.lo = ptemplate_address->lo; req->dataout_template_pa.hi = ptemplate_address->hi; - status = be_mcc_notify_wait(phba); - if (!status) { - struct iscsi_endpoint *ep; - struct tcp_connect_and_offload_out *ptcpcnct_out = - embedded_payload(wrb); - - ep = phba->ep_array[ptcpcnct_out->cid - - phba->fw_config.iscsi_cid_start]; - beiscsi_ep = ep->dd_data; - beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; - beiscsi_ep->cid_vld = 1; - SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); - } else - SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr) +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb); - int status; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_addr *req; + unsigned int tag = 0; SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, sizeof(*req)); - status = be_mcc_notify_wait(phba); - if (!status) { - struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb); - - memcpy(mac_addr, resp->mac_address, ETH_ALEN); - } - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 6bc59e8e1fe5..f873a66cd48f 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -250,7 +250,4 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short issue_reset, unsigned short savecfg_flag); -unsigned char mgmt_fw_cmd(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba, - char *buf, unsigned int len); #endif -- GitLab From da7408c800e3ae293275f52497d0ef7a9b09c9e4 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:11:23 +0530 Subject: [PATCH 0900/3892] [SCSI] be2iscsi: The session failure only when Link Goes down This fixes a situation where the sessions were being killed whenever LinkUP is notified rather than LinkDown Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index d4a0d1da4875..44e69bdf359a 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -161,13 +161,13 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", evt->physical_port); phba->state |= BE_ADAPTER_LINK_DOWN; + iscsi_host_for_each_session(phba->shost, + be2iscsi_fail_session); break; case ASYNC_EVENT_LINK_UP: phba->state = BE_ADAPTER_UP; SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", evt->physical_port); - iscsi_host_for_each_session(phba->shost, - be2iscsi_fail_session); break; default: SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" -- GitLab From aa874f0738ecac7e5ac13b4d808a1026dcb5367d Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:12:03 +0530 Subject: [PATCH 0901/3892] [SCSI] be2iscsi: Fixing initialization of can_queue This patch fixes can_queue being uninitiallized since it was done before beiscsi_get_params was called. Thanks to Mike Christie for identifying this Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index a6a2c6469677..b1c897528300 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3825,8 +3825,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_port; } phba->shost->max_id = phba->fw_config.iscsi_cid_count; - phba->shost->can_queue = phba->params.ios_per_ctrl; beiscsi_get_params(phba); + phba->shost->can_queue = phba->params.ios_per_ctrl; ret = beiscsi_init_port(phba); if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" -- GitLab From 9db0fb3aa4cc4e42241e194ef64931321fa72196 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 5 Jan 2010 05:12:43 +0530 Subject: [PATCH 0902/3892] [SCSI] be2iscsi: Enable TEXT req resp This patch enables TEXT Request / Response for the driver Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b1c897528300..9fc4446b21e0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3917,7 +3917,7 @@ disable_pci: struct iscsi_transport beiscsi_iscsi_transport = { .owner = THIS_MODULE, .name = DRV_NAME, - .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO | CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, .param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH | -- GitLab From 90a86fc05ffefe48581c88106d0b9cc37f6e060c Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 12 Jan 2010 13:02:46 -0800 Subject: [PATCH 0903/3892] [SCSI] qla2xxx: Enhance EEH support and enable AER support. qla2xxx: EEH added call to pci_restore_state. qla2xxx: EEH added delay in slot reset routine. qla2xxx: EEH moved call to pci_save_state(), see (1). qla2xxx: EEH additional changes for RHEL5.5. qla2xxx: EEH added function call, removed function call, see (2). (1) In qla2xxx_probe_one the call to pci_save_state() has been moved to after the call to qla2xxx_request_irqs(). (2) Add call to pci_disable_pcie_error_reporting() in remove_one. Delete call to pci_cleanup_aer_uncorrect_error_status() in pci_resume. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 5 +++-- drivers/scsi/qla2xxx/qla_os.c | 40 ++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ffd0efdff40e..5613456dbbb1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2252,10 +2252,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); - else if (ha->flags.inta_enabled) { + else if (ha->flags.msi_enabled) { free_irq(ha->pdev->irq, rsp); pci_disable_msi(ha->pdev); - } + } else + free_irq(ha->pdev->irq, rsp); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8529eb1f3cd4..fe34b7f9dee6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1818,7 +1818,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Set EEH reset type to fundamental if required by hba */ if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) { pdev->needs_freset = 1; - pci_save_state(pdev); } /* Configure PCI I/O space */ @@ -1975,6 +1974,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ret = qla2x00_request_irqs(ha, rsp); if (ret) goto probe_init_failed; + + pci_save_state(pdev); + /* Alloc arrays of request and response ring ptrs */ que_init: if (!qla2x00_alloc_queues(ha)) { @@ -2176,6 +2178,8 @@ qla2x00_remove_one(struct pci_dev *pdev) kfree(ha); ha = NULL; + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -3310,6 +3314,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; + qla2x00_free_irqs(vha); pci_disable_device(pdev); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: @@ -3363,10 +3368,19 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); struct qla_hw_data *ha = base_vha->hw; - int rc; + struct rsp_que *rsp; + int rc, retries = 10; DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n")); + /* Workaround: qla2xxx driver which access hardware earlier + * needs error state to be pci_channel_io_online. + * Otherwise mailbox command timesout. + */ + pdev->error_state = pci_channel_io_normal; + + pci_restore_state(pdev); + if (ha->mem_only) rc = pci_enable_device_mem(pdev); else @@ -3378,27 +3392,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) return ret; } + rsp = ha->rsp_q_map[0]; + if (qla2x00_request_irqs(ha, rsp)) + return ret; + if (ha->isp_ops->pci_config(base_vha)) return ret; -#ifdef QL_DEBUG_LEVEL_17 - { - uint8_t b; - uint32_t i; + while (ha->flags.mbox_busy && retries--) + msleep(1000); - printk("slot_reset_1: "); - for (i = 0; i < 256; i++) { - pci_read_config_byte(ha->pdev, i, &b); - printk("%s%02x", (i%16) ? " " : "\n", b); - } - printk("\n"); - } -#endif set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) ret = PCI_ERS_RESULT_RECOVERED; clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + pci_cleanup_aer_uncorrect_error_status(pdev); + DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset-return:ret=%x\n", ret)); @@ -3422,8 +3432,6 @@ qla2xxx_pci_resume(struct pci_dev *pdev) } ha->flags.eeh_busy = 0; - - pci_cleanup_aer_uncorrect_error_status(pdev); } static struct pci_error_handlers qla2xxx_err_handler = { -- GitLab From 1838ef1d782f7527e6defe87e180598622d2d071 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 18 Jan 2010 14:00:34 -0800 Subject: [PATCH 0904/3892] x86-64, rwsem: 64-bit xadd rwsem implementation For x86-64, 32767 threads really is not enough. Change rwsem_count_t to a signed long, so that it is 64 bits on x86-64. This required the following changes to the assembly code: a) %z0 doesn't work on all versions of gcc! At least gcc 4.4.2 as shipped with Fedora 12 emits "ll" not "q" for 64 bits, even for integer operands. Newer gccs apparently do this correctly, but avoid this problem by using the _ASM_ macros instead of %z. b) 64 bits immediates are only allowed in "movq $imm,%reg" constructs... no others. Change some of the constraints to "e", and fix the one case where we would have had to use an invalid immediate -- in that case, we only care about the upper half anyway, so just access the upper half. Signed-off-by: H. Peter Anvin Cc: Linus Torvalds LKML-Reference: --- arch/x86/include/asm/rwsem.h | 53 +++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 5f9af3081d66..10204a25bf93 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -41,6 +41,7 @@ #include #include #include +#include struct rwsem_waiter; @@ -56,18 +57,24 @@ extern asmregparm struct rw_semaphore * /* * the semaphore definition * - * The bias values and the counter type needs to be extended to 64 bits - * if we want to have more than 32767 potential readers/writers + * The bias values and the counter type limits the number of + * potential readers/writers to 32767 for 32 bits and 2147483647 + * for 64 bits. */ -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) +#ifdef CONFIG_X86_64 +# define RWSEM_ACTIVE_MASK 0xffffffffL +#else +# define RWSEM_ACTIVE_MASK 0x0000ffffL +#endif + +#define RWSEM_UNLOCKED_VALUE 0x00000000L +#define RWSEM_ACTIVE_BIAS 0x00000001L +#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) -typedef signed int rwsem_count_t; +typedef signed long rwsem_count_t; struct rw_semaphore { rwsem_count_t count; @@ -110,7 +117,7 @@ do { \ static inline void __down_read(struct rw_semaphore *sem) { asm volatile("# beginning down_read\n\t" - LOCK_PREFIX " inc%z0 (%1)\n\t" + LOCK_PREFIX _ASM_INC "(%1)\n\t" /* adds 0x00000001, returns the old value */ " jns 1f\n" " call call_rwsem_down_read_failed\n" @@ -225,8 +232,25 @@ static inline void __up_write(struct rw_semaphore *sem) */ static inline void __downgrade_write(struct rw_semaphore *sem) { +#ifdef CONFIG_X86_64 +# if RWSEM_WAITING_BIAS != -0x100000000 +# error "This code assumes RWSEM_WAITING_BIAS == -2^32" +# endif + + /* 64-bit immediates are special and expensive, and not needed here */ + asm volatile("# beginning __downgrade_write\n\t" + LOCK_PREFIX "incl 4(%1)\n\t" + /* transitions 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 */ + " jns 1f\n\t" + " call call_rwsem_downgrade_wake\n" + "1:\n\t" + "# ending __downgrade_write\n" + : "+m" (sem->count) + : "a" (sem) + : "memory", "cc"); +#else asm volatile("# beginning __downgrade_write\n\t" - LOCK_PREFIX " add%z0 %2,(%1)\n\t" + LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ " jns 1f\n\t" " call call_rwsem_downgrade_wake\n" @@ -235,22 +259,25 @@ static inline void __downgrade_write(struct rw_semaphore *sem) : "+m" (sem->count) : "a" (sem), "i" (-RWSEM_WAITING_BIAS) : "memory", "cc"); +#endif } /* * implement atomic add functionality */ -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +static inline void rwsem_atomic_add(rwsem_count_t delta, + struct rw_semaphore *sem) { - asm volatile(LOCK_PREFIX "add%z0 %1,%0" + asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0" : "+m" (sem->count) - : "ir" (delta)); + : "er" (delta)); } /* * implement exchange and add functionality */ -static inline rwsem_count_t rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline rwsem_count_t rwsem_atomic_update(rwsem_count_t delta, + struct rw_semaphore *sem) { rwsem_count_t tmp = delta; -- GitLab From 9a069e196767d7b87184fd8d8211d22bb5b9c0b8 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:47 -0800 Subject: [PATCH 0905/3892] [SCSI] qla2xxx: Add BSG support for FC ELS/CT passthrough and vendor commands. [jejb: fixed printk casting issues] Signed-off-by: Sarang Radke Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 746 +++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_def.h | 155 +++++++ drivers/scsi/qla2xxx/qla_fw.h | 33 ++ drivers/scsi/qla2xxx/qla_gbl.h | 5 + drivers/scsi/qla2xxx/qla_init.c | 14 +- drivers/scsi/qla2xxx/qla_iocb.c | 120 +++++ drivers/scsi/qla2xxx/qla_isr.c | 105 ++++- drivers/scsi/qla2xxx/qla_mbx.c | 151 +++++++ drivers/scsi/qla2xxx/qla_os.c | 1 + 9 files changed, 1326 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 3a9f5b288aee..5a19aea17022 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -11,7 +11,9 @@ #include static int qla24xx_vport_disable(struct fc_vport *, bool); - +static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); +int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *); +static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); /* SYSFS attributes --------------------------------------------------------- */ static ssize_t @@ -1167,6 +1169,28 @@ qla2x00_total_isp_aborts_show(struct device *dev, ha->qla_stats.total_isp_aborts); } +static ssize_t +qla24xx_84xx_fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rval = QLA_SUCCESS; + uint16_t status[2] = {0, 0}; + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (IS_QLA84XX(ha) && ha->cs84xx) { + if (ha->cs84xx->op_fw_version == 0) { + rval = qla84xx_verify_chip(vha, status); + } + + if ((rval == QLA_SUCCESS) && (status[0] == 0)) + return snprintf(buf, PAGE_SIZE, "%u\n", + (uint32_t)ha->cs84xx->op_fw_version); + } + + return snprintf(buf, PAGE_SIZE, "\n"); +} + static ssize_t qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1281,6 +1305,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, qla2x00_optrom_fcode_version_show, NULL); static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, NULL); +static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, + NULL); static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); @@ -1310,6 +1336,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_optrom_efi_version, &dev_attr_optrom_fcode_version, &dev_attr_optrom_fw_version, + &dev_attr_84xx_fw_version, &dev_attr_total_isp_aborts, &dev_attr_mpi_version, &dev_attr_phy_version, @@ -1795,6 +1822,597 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) return 0; } +/* BSG support for ELS/CT pass through */ +inline srb_t * +qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) +{ + srb_t *sp; + struct qla_hw_data *ha = vha->hw; + struct srb_bsg_ctx *ctx; + + sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + if (!sp) + goto done; + ctx = kzalloc(size, GFP_KERNEL); + if (!ctx) { + mempool_free(sp, ha->srb_mempool); + goto done; + } + + memset(sp, 0, sizeof(*sp)); + sp->fcport = fcport; + sp->ctx = ctx; +done: + return sp; +} + +static int +qla2x00_process_els(struct fc_bsg_job *bsg_job) +{ + struct fc_rport *rport; + fc_port_t *fcport; + struct Scsi_Host *host; + scsi_qla_host_t *vha; + struct qla_hw_data *ha; + srb_t *sp; + const char *type; + int req_sg_cnt, rsp_sg_cnt; + int rval = (DRIVER_ERROR << 16); + uint16_t nextlid = 0; + struct srb_bsg *els; + + /* Multiple SG's are not supported for ELS requests */ + if (bsg_job->request_payload.sg_cnt > 1 || + bsg_job->reply_payload.sg_cnt > 1) { + DEBUG2(printk(KERN_INFO + "multiple SG's are not supported for ELS requests" + " [request_sg_cnt: %x reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, + bsg_job->reply_payload.sg_cnt)); + rval = -EPERM; + goto done; + } + + /* ELS request for rport */ + if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { + rport = bsg_job->rport; + fcport = *(fc_port_t **) rport->dd_data; + host = rport_to_shost(rport); + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_RPT_ELS"; + + DEBUG2(printk(KERN_INFO + "scsi(%ld): loop-id=%x portid=%02x%02x%02x.\n", + fcport->vha->host_no, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + /* make sure the rport is logged in, + * if not perform fabric login + */ + if (qla2x00_fabric_login(vha, fcport, &nextlid)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "failed to login port %06X for ELS passthru\n", + fcport->d_id.b24)); + rval = -EIO; + goto done; + } + } else { + host = bsg_job->shost; + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_HST_ELS_NOLOGIN"; + + DEBUG2(printk(KERN_INFO + "scsi(%ld): loop-id=%x portid=%02x%02x%02x.\n", + vha->host_no, vha->loop_id, + vha->d_id.b.domain, vha->d_id.b.area, vha->d_id.b.al_pa)); + + /* Allocate a dummy fcport structure, since functions + * preparing the IOCB and mailbox command retrieves port + * specific information from fcport structure. For Host based + * ELS commands there will be no fcport structure allocated + */ + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); + if (!fcport) { + rval = -ENOMEM; + goto done; + } + + /* Initialize all required fields of fcport */ + fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; + fcport->d_id.b.al_pa = + bsg_job->request->rqst_data.h_els.port_id[0]; + fcport->d_id.b.area = + bsg_job->request->rqst_data.h_els.port_id[1]; + fcport->d_id.b.domain = + bsg_job->request->rqst_data.h_els.port_id[2]; + fcport->loop_id = + (fcport->d_id.b.al_pa == 0xFD) ? + NPH_FABRIC_CONTROLLER : NPH_F_PORT; + } + + DEBUG2(printk(KERN_INFO + "scsi(%ld): vendor-id = %llu\n", + vha->host_no, host->hostt->vendor_id)); + + req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!req_sg_cnt) { + rval = -ENOMEM; + goto done_free_fcport; + } + rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!rsp_sg_cnt) { + rval = -ENOMEM; + goto done_free_fcport; + } + + if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(printk(KERN_INFO + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, req_sg_cnt, + bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + + /* Alloc SRB structure */ + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + if (!sp) { + rval = -ENOMEM; + goto done_unmap_sg; + } + + els = sp->ctx; + els->ctx.type = + (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? + SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); + els->bsg_job = bsg_job; + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " + "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, + bsg_job->request->rqst_data.h_els.command_code, + fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + rval = -EIO; + goto done_unmap_sg; + } + return rval; + +done_unmap_sg: + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + goto done_free_fcport; + +done_free_fcport: + if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) + kfree(fcport); +done: + return rval; +} + +static int +qla2x00_process_ct(struct fc_bsg_job *bsg_job) +{ + srb_t *sp; + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + struct qla_hw_data *ha = vha->hw; + int rval = (DRIVER_ERROR << 16); + int req_sg_cnt, rsp_sg_cnt; + uint16_t loop_id; + struct fc_port *fcport; + char *type = "FC_BSG_HST_CT"; + struct srb_bsg *ct; + + /* pass through is supported only for ISP 4Gb or higher */ + if (!IS_FWI2_CAPABLE(ha)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld):Firmware is not capable to support FC " + "CT pass thru\n", vha->host_no)); + rval = -EPERM; + goto done; + } + + req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!req_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!rsp_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(qla_printk(KERN_WARNING, ha, + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, req_sg_cnt, + bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + + loop_id = + (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) + >> 24; + switch (loop_id) { + case 0xFC: + loop_id = cpu_to_le16(NPH_SNS); + break; + case 0xFA: + loop_id = vha->mgmt_svr_loop_id; + break; + default: + DEBUG2(qla_printk(KERN_INFO, ha, + "Unknown loop id: %x\n", loop_id)); + rval = -EINVAL; + goto done_unmap_sg; + } + + /* Allocate a dummy fcport structure, since functions preparing the + * IOCB and mailbox command retrieves port specific information + * from fcport structure. For Host based ELS commands there will be + * no fcport structure allocated + */ + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); + if (!fcport) + { + rval = -ENOMEM; + goto done_unmap_sg; + } + + /* Initialize all required fields of fcport */ + fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; + fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; + fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; + fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; + fcport->loop_id = loop_id; + + /* Alloc SRB structure */ + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + if (!sp) { + rval = -ENOMEM; + goto done_free_fcport; + } + + ct = sp->ctx; + ct->ctx.type = SRB_CT_CMD; + ct->bsg_job = bsg_job; + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " + "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, + (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), + fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + rval = -EIO; + goto done_free_fcport; + } + return rval; + +done_free_fcport: + kfree(fcport); +done_unmap_sg: + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); +done: + return rval; +} + +static int +qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) +{ + struct Scsi_Host *host = bsg_job->shost; + scsi_qla_host_t *vha = shost_priv(host); + struct qla_hw_data *ha = vha->hw; + int rval; + uint8_t command_sent; + uint32_t vendor_cmd; + char *type; + struct msg_echo_lb elreq; + uint16_t response[MAILBOX_REGISTER_COUNT]; + uint8_t* fw_sts_ptr; + uint8_t *req_data; + dma_addr_t req_data_dma; + uint32_t req_data_len; + uint8_t *rsp_data; + dma_addr_t rsp_data_dma; + uint32_t rsp_data_len; + + if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || + test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { + rval = -EBUSY; + goto done; + } + + elreq.req_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + if (!elreq.req_sg_cnt) { + rval = -ENOMEM; + goto done; + } + elreq.rsp_sg_cnt = + dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if (!elreq.rsp_sg_cnt) { + rval = -ENOMEM; + goto done; + } + + if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || + (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) + { + DEBUG2(printk(KERN_INFO + "dma mapping resulted in different sg counts \ + [request_sg_cnt: %x dma_request_sg_cnt: %x\ + reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", + bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, + bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); + rval = -EAGAIN; + goto done_unmap_sg; + } + req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; + req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, + &req_data_dma, GFP_KERNEL); + + rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, + &rsp_data_dma, GFP_KERNEL); + + /* Copy the request buffer in req_data now */ + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, req_data, + req_data_len); + + elreq.send_dma = req_data_dma; + elreq.rcv_dma = rsp_data_dma; + elreq.transfer_size = req_data_len; + + /* Vendor cmd : loopback or ECHO diagnostic + * Options: + * Loopback : Either internal or external loopback + * ECHO: ECHO ELS or Vendor specific FC4 link data + */ + vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]; + elreq.options = + *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd) + + 1); + + switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { + case QL_VND_LOOPBACK: + if (ha->current_topology != ISP_CFG_F) { + type = "FC_BSG_HST_VENDOR_LOOPBACK"; + + if ((IS_QLA81XX(ha)) && + ((elreq.options == 0) || (elreq.options == 2))) { + DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld)" + "loopback option:0x%x not supported\n", vha->host_no, elreq.options)); + rval = -EINVAL; + goto done_unmap_sg; + } + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", + vha->host_no, type, vendor_cmd, elreq.options)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) tx_addr: 0x%llx rx_addr: 0x%llx tx_sg_cnt: %x rx_sg_cnt: %x\n", + vha->host_no, (unsigned long long)elreq.send_dma, (unsigned long long)elreq.rcv_dma, elreq.req_sg_cnt, elreq.rsp_sg_cnt)); + command_sent = INT_DEF_LB_LOOPBACK_CMD; + rval = qla2x00_loopback_test(vha, &elreq, response); + if (IS_QLA81XX(ha)) { + if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) { + DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " + "ISP\n", __func__, vha->host_no)); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + } + } else { + type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", + vha->host_no, type, vendor_cmd, elreq.options)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) tx_addr: 0x%llx rx_addr: 0x%llx tx_sg_cnt: %x rx_sg_cnt: %x\n", + vha->host_no, (unsigned long long)elreq.send_dma, (unsigned long long)elreq.rcv_dma, elreq.req_sg_cnt, elreq.rsp_sg_cnt)); + command_sent = INT_DEF_LB_ECHO_CMD; + rval = qla2x00_echo_test(vha, &elreq, response); + } + break; + case QLA84_RESET: + if (!IS_QLA84XX(vha->hw)) { + rval = -EINVAL; + DEBUG16(printk( + "%s(%ld): 8xxx exiting.\n", + __func__, vha->host_no)); + return rval; + } + rval = qla84xx_reset(vha, &elreq, bsg_job); + break; + case QLA84_MGMT_CMD: + if (!IS_QLA84XX(vha->hw)) { + rval = -EINVAL; + DEBUG16(printk( + "%s(%ld): 8xxx exiting.\n", + __func__, vha->host_no)); + return rval; + } + rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job); + break; + default: + rval = -ENOSYS; + } + + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld) Vendor request %s failed\n", vha->host_no, type)); + rval = 0; + bsg_job->reply->result = (DID_ERROR << 16); + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, response, sizeof(response)); + fw_sts_ptr += sizeof(response); + *fw_sts_ptr = command_sent; + } else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld) Vendor request %s completed\n", vha->host_no, type)); + rval = bsg_job->reply->result = 0; + bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); + bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy(fw_sts_ptr, response, sizeof(response)); + fw_sts_ptr += sizeof(response); + *fw_sts_ptr = command_sent; + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, rsp_data, + rsp_data_len); + } + bsg_job->job_done(bsg_job); + +done_unmap_sg: + + if(req_data) + dma_free_coherent(&ha->pdev->dev, req_data_len, + req_data, req_data_dma); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + +done: + return rval; +} + +static int +qla24xx_bsg_request(struct fc_bsg_job *bsg_job) +{ + int ret = -EINVAL; + + switch (bsg_job->request->msgcode) { + case FC_BSG_RPT_ELS: + case FC_BSG_HST_ELS_NOLOGIN: + ret = qla2x00_process_els(bsg_job); + break; + case FC_BSG_HST_CT: + ret = qla2x00_process_ct(bsg_job); + break; + case FC_BSG_HST_VENDOR: + ret = qla2x00_process_vendor_specific(bsg_job); + break; + case FC_BSG_HST_ADD_RPORT: + case FC_BSG_HST_DEL_RPORT: + case FC_BSG_RPT_CT: + default: + DEBUG2(printk("qla2xxx: unsupported BSG request\n")); + break; + } + return ret; +} + +static int +qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(bsg_job->shost); + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + int i; + unsigned long flags; + uint16_t que_id; + struct req_que *req; + struct rsp_que *rsp; + int found = 0; + struct srb_bsg *sp_bsg; + + /* find the bsg job from the active list of commands */ + spin_lock_irqsave(&ha->hardware_lock, flags); + req = ha->req_q_map[0]; + que_id = req->id; + if (req->rsp) + rsp = req->rsp; + else + rsp = ha->rsp_q_map[que_id]; + + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++ ) { + sp = req->outstanding_cmds[i]; + + if (sp == NULL) + continue; + + sp_bsg = (struct srb_bsg*)sp->ctx; + + if (((sp_bsg->ctx.type == SRB_CT_CMD) || + (sp_bsg->ctx.type == SRB_ELS_CMD_RPT) + || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) && + (sp_bsg->bsg_job == bsg_job)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) req_q: %p rsp_q: %p que_id: %x sp: %p\n", + vha->host_no, req, rsp, que_id, sp)); + found = 1; + break; + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (!found) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) SRB not found to abort\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = -ENXIO; + return 0; + } + + if (ha->isp_ops->abort_command(sp)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld): mbx abort_command failed\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = -EIO; + } else { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld): mbx abort_command success\n", vha->host_no)); + bsg_job->req->errors = bsg_job->reply->result = 0; + } + + if (bsg_job->request->msgcode == FC_BSG_HST_CT) + kfree(sp->fcport); + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + return 0; +} + struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, @@ -1838,6 +2456,8 @@ struct fc_function_template qla2xxx_transport_functions = { .vport_create = qla24xx_vport_create, .vport_disable = qla24xx_vport_disable, .vport_delete = qla24xx_vport_delete, + .bsg_request = qla24xx_bsg_request, + .bsg_timeout = qla24xx_bsg_timeout, }; struct fc_function_template qla2xxx_transport_vport_functions = { @@ -1878,6 +2498,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = { .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, .terminate_rport_io = qla2x00_terminate_rport_io, .get_fc_host_stats = qla2x00_get_fc_host_stats, + .bsg_request = qla24xx_bsg_request, + .bsg_timeout = qla24xx_bsg_timeout, }; void @@ -1906,3 +2528,125 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) speed = FC_PORTSPEED_1GBIT; fc_host_supported_speeds(vha->host) = speed; } +static int +qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) +{ + int ret = 0; + int cmd; + uint16_t cmd_status; + + DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2)) + == A84_RESET_FLAG_ENABLE_DIAG_FW ? + A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW; + ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW, + &cmd_status); + return ret; +} + +static int +qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) +{ + struct access_chip_84xx *mn; + dma_addr_t mn_dma, mgmt_dma; + void *mgmt_b = NULL; + int ret = 0; + int rsp_hdr_len, len = 0; + struct qla84_msg_mgmt *ql84_mgmt; + + ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt)); + ql84_mgmt->cmd = + *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2)); + ql84_mgmt->mgmtp.u.mem.start_addr = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3)); + ql84_mgmt->len = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4)); + ql84_mgmt->mgmtp.u.config.id = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5)); + ql84_mgmt->mgmtp.u.config.param0 = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6)); + ql84_mgmt->mgmtp.u.config.param1 = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7)); + ql84_mgmt->mgmtp.u.info.type = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8)); + ql84_mgmt->mgmtp.u.info.context = + *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9)); + + rsp_hdr_len = bsg_job->request_payload.payload_len; + + mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " + "failed%lu\n", __func__, ha->host_no)); + return -ENOMEM; + } + + memset(mn, 0, sizeof (struct access_chip_84xx)); + + mn->entry_type = ACCESS_CHIP_IOCB_TYPE; + mn->entry_count = 1; + + switch (ql84_mgmt->cmd) { + case QLA84_MGMT_READ_MEM: + mn->options = cpu_to_le16(ACO_DUMP_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_WRITE_MEM: + mn->options = cpu_to_le16(ACO_LOAD_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_CHNG_CONFIG: + mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); + mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); + break; + case QLA84_MGMT_GET_INFO: + mn->options = cpu_to_le16(ACO_REQUEST_INFO); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); + break; + default: + ret = -EIO; + goto exit_mgmt0; + } + + if ((len == ql84_mgmt->len) && + ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { + mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len, + &mgmt_dma, GFP_KERNEL); + if (mgmt_b == NULL) { + DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b " + "failed%lu\n", __func__, ha->host_no)); + ret = -ENOMEM; + goto exit_mgmt0; + } + mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); + mn->dseg_count = cpu_to_le16(1); + mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); + mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); + mn->dseg_length = cpu_to_le32(len); + + if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { + memcpy(mgmt_b, ql84_mgmt->payload, len); + } + } + + ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); + if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) + || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { + if (ret != QLA_SUCCESS) + DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", + __func__, ha->host_no)); + } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) || + (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { + } + + if (mgmt_b) + dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma); + +exit_mgmt0: + dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma); + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1263d9796e89..afa95614aaf8 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -31,6 +31,7 @@ #include #include #include +#include #define QLA2XXX_DRIVER_NAME "qla2xxx" @@ -228,6 +229,27 @@ struct srb_logio { uint16_t flags; }; +struct srb_bsg_ctx { +#define SRB_ELS_CMD_RPT 3 +#define SRB_ELS_CMD_HST 4 +#define SRB_CT_CMD 5 + uint16_t type; +}; + +struct srb_bsg { + struct srb_bsg_ctx ctx; + struct fc_bsg_job *bsg_job; +}; + +struct msg_echo_lb { + dma_addr_t send_dma; + dma_addr_t rcv_dma; + uint16_t req_sg_cnt; + uint16_t rsp_sg_cnt; + uint16_t options; + uint32_t transfer_size; +}; + /* * ISP I/O Register Set structure definitions. */ @@ -522,6 +544,8 @@ typedef struct { #define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */ #define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */ +/* ISP mailbox loopback echo diagnostic error code */ +#define MBS_LB_RESET 0x17 /* * Firmware options 1, 2, 3. */ @@ -2230,6 +2254,13 @@ struct req_que { int max_q_depth; }; +/* Place holder for FW buffer parameters */ +struct qlfc_fw { + void *fw_buf; + dma_addr_t fw_dma; + uint32_t len; +}; + /* * Qlogic host adapter specific data structure. */ @@ -2594,6 +2625,7 @@ struct qla_hw_data { struct qla_statistics qla_stats; struct isp_operations *isp_ops; struct workqueue_struct *wq; + struct qlfc_fw fw_buf; }; /* @@ -2766,4 +2798,127 @@ typedef struct scsi_qla_host { #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) +/* + * BSG Vendor specific commands + */ + +#define QL_VND_LOOPBACK 0x01 +#define QLA84_RESET 0x02 +#define QLA84_UPDATE_FW 0x03 +#define QLA84_MGMT_CMD 0x04 + +/* BSG definations for interpreting CommandSent field */ +#define INT_DEF_LB_LOOPBACK_CMD 0 +#define INT_DEF_LB_ECHO_CMD 1 + +/* BSG Vendor specific definations */ +typedef struct _A84_RESET { + uint16_t Flags; + uint16_t Reserved; +#define A84_RESET_FLAG_ENABLE_DIAG_FW 1 +} __attribute__((packed)) A84_RESET, *PA84_RESET; + +#define A84_ISSUE_WRITE_TYPE_CMD 0 +#define A84_ISSUE_READ_TYPE_CMD 1 +#define A84_CLEANUP_CMD 2 +#define A84_ISSUE_RESET_OP_FW 3 +#define A84_ISSUE_RESET_DIAG_FW 4 +#define A84_ISSUE_UPDATE_OPFW_CMD 5 +#define A84_ISSUE_UPDATE_DIAGFW_CMD 6 + +struct qla84_mgmt_param { + union { + struct { + uint32_t start_addr; + } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ + struct { + uint32_t id; +#define QLA84_MGMT_CONFIG_ID_UIF 1 +#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 +#define QLA84_MGMT_CONFIG_ID_PAUSE 3 +#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 + + uint32_t param0; + uint32_t param1; + } config; /* for QLA84_MGMT_CHNG_CONFIG */ + + struct { + uint32_t type; +#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ +#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ +#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ +#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ +#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ +#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ +#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ + + uint32_t context; +/* +* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA +*/ +#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 +#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 +#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 +#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 +#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 +#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 +#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 +#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 + +/* +* context definitions for QLA84_MGMT_INFO_PORT_STAT +*/ +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 + + +/* +* context definitions for QLA84_MGMT_INFO_LIF_STAT +*/ +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 +#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 + + } info; /* for QLA84_MGMT_GET_INFO */ + } u; +}; + +struct qla84_msg_mgmt { + uint16_t cmd; +#define QLA84_MGMT_READ_MEM 0x00 +#define QLA84_MGMT_WRITE_MEM 0x01 +#define QLA84_MGMT_CHNG_CONFIG 0x02 +#define QLA84_MGMT_GET_INFO 0x03 + uint16_t rsrvd; + struct qla84_mgmt_param mgmtp;/* parameters for cmd */ + uint32_t len; /* bytes in payload following this struct */ + uint8_t payload[0]; /* payload for cmd */ +}; + +struct msg_update_fw { + /* + * diag_fw = 0 operational fw + * otherwise diagnostic fw + * offset, len, fw_len are present to overcome the current limitation + * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk + * specifies the byte "offset" where it fits in the fw buffer. The + * number of bytes in each chunk is specified in "len". "fw_len" + * is the total size of fw. The first chunk should start at offset = 0. + * When offset+len == fw_len, the fw is written to the HBA. + */ + uint32_t diag_fw; + uint32_t offset;/* start offset */ + uint32_t len; /* num bytes in cur xfer */ + uint32_t fw_len; /* size of fw in bytes */ + uint8_t fw_bytes[0]; +}; + #endif diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 66a8da5d7d08..cebf4f1bb7d9 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -627,6 +627,39 @@ struct els_entry_24xx { uint32_t rx_len; /* Data segment 1 length. */ }; +struct els_sts_entry_24xx { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System Defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint32_t handle; /* System handle. */ + + uint16_t comp_status; + + uint16_t nport_handle; /* N_PORT handle. */ + + uint16_t reserved_1; + + uint8_t vp_index; + uint8_t sof_type; + + uint32_t rx_xchg_address; /* Receive exchange address. */ + uint16_t reserved_2; + + uint8_t opcode; + uint8_t reserved_3; + + uint8_t port_id[3]; + uint8_t reserved_4; + + uint16_t reserved_5; + + uint16_t control_flags; /* Control flags. */ + uint32_t total_byte_count; + uint32_t error_subcode_1; + uint32_t error_subcode_2; +}; /* * ISP queue - Mailbox Command entry structure definition. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f61fb8d01330..b42e704bdca9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -60,6 +60,8 @@ extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern fc_port_t * +qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); /* * Global Data in qla_os.c source file. */ @@ -154,6 +156,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); extern int qla2x00_start_sp(srb_t *); +extern void qla2x00_ctx_sp_free(srb_t *); /* * Global Function Prototypes in qla_mbx.c source file. @@ -426,6 +429,8 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_init_host_attr(scsi_qla_host_t *); extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); +extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); +extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); /* * Global Function Prototypes in qla_dfs.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3f8e8495b743..1128c8d5771b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -62,7 +62,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data) ctx->free(sp); } -static void +void qla2x00_ctx_sp_free(srb_t *sp) { struct srb_ctx *ctx = sp->ctx; @@ -338,6 +338,16 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) rval = qla2x00_init_rings(vha); ha->flags.chip_reset_done = 1; + if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { + /* Issue verify 84xx FW IOCB to complete 84xx initialization */ + rval = qla84xx_init_chip(vha); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_ERR, ha, + "Unable to initialize ISP84XX.\n"); + qla84xx_put_chip(vha); + } + } + return (rval); } @@ -2216,7 +2226,7 @@ qla2x00_rport_del(void *data) * * Returns a pointer to the allocated fcport, or NULL, if none available. */ -static fc_port_t * +fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c5ccac0bef76..8299a9891bfe 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1025,6 +1025,119 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) /* Implicit: mbx->mbx10 = 0. */ } +static void +qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) +{ + struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + + els_iocb->entry_type = ELS_IOCB_TYPE; + els_iocb->entry_count = 1; + els_iocb->sys_define = 0; + els_iocb->entry_status = 0; + els_iocb->handle = sp->handle; + els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + els_iocb->vp_index = sp->fcport->vp_idx; + els_iocb->sof_type = EST_SOFI3; + els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + + els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ? + bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code; + els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; + els_iocb->port_id[1] = sp->fcport->d_id.b.area; + els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->control_flags = 0; + els_iocb->rx_byte_count = + cpu_to_le32(bsg_job->reply_payload.payload_len); + els_iocb->tx_byte_count = + cpu_to_le32(bsg_job->request_payload.payload_len); + + els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + els_iocb->tx_len = cpu_to_le32(sg_dma_len + (bsg_job->request_payload.sg_list)); + + els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + els_iocb->rx_len = cpu_to_le32(sg_dma_len + (bsg_job->reply_payload.sg_list)); +} + +static void +qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + struct scatterlist *sg; + int index; + uint16_t tot_dsds; + scsi_qla_host_t *vha = sp->fcport->vha; + struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + int loop_iterartion = 0; + int cont_iocb_prsnt = 0; + int entry_count = 1; + + ct_iocb->entry_type = CT_IOCB_TYPE; + ct_iocb->entry_status = 0; + ct_iocb->sys_define = 0; + ct_iocb->handle = sp->handle; + + ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + ct_iocb->vp_index = sp->fcport->vp_idx; + ct_iocb->comp_status = __constant_cpu_to_le16(0); + + ct_iocb->cmd_dsd_count = + __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + ct_iocb->timeout = 0; + ct_iocb->rsp_dsd_count = + __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + ct_iocb->rsp_byte_count = + cpu_to_le32(bsg_job->reply_payload.payload_len); + ct_iocb->cmd_byte_count = + cpu_to_le32(bsg_job->request_payload.payload_len); + ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len + (bsg_job->request_payload.sg_list)); + + avail_dsds = 1; + cur_dsd = (uint32_t *)ct_iocb->dseg_1_address; + index = 0; + tot_dsds = bsg_job->reply_payload.sg_cnt; + + for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { + dma_addr_t sle_dma; + cont_a64_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Five DSDs are available in the Cont. + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + avail_dsds = 5; + cont_iocb_prsnt = 1; + entry_count++; + } + + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + loop_iterartion++; + avail_dsds--; + } + ct_iocb->entry_count = entry_count; +} + int qla2x00_start_sp(srb_t *sp) { @@ -1052,6 +1165,13 @@ qla2x00_start_sp(srb_t *sp) qla24xx_logout_iocb(sp, pkt): qla2x00_logout_iocb(sp, pkt); break; + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + qla24xx_els_iocb(sp, pkt); + break; + case SRB_CT_CMD: + qla24xx_ct_iocb(sp, pkt); + break; default: break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 5613456dbbb1..09ba26bc230c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -8,6 +8,7 @@ #include #include +#include static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, @@ -881,7 +882,9 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, index); return NULL; } + req->outstanding_cmds[index] = NULL; + done: return sp; } @@ -981,6 +984,100 @@ done_post_logio_done_work: lio->ctx.free(sp); } +static void +qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, + struct sts_entry_24xx *pkt, int iocb_type) +{ + const char func[] = "ELS_CT_IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_bsg *sp_bsg; + struct fc_bsg_job *bsg_job; + uint16_t comp_status; + uint32_t fw_status[3]; + uint8_t* fw_sts_ptr; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + sp_bsg = (struct srb_bsg*)sp->ctx; + bsg_job = sp_bsg->bsg_job; + + type = NULL; + switch (sp_bsg->ctx.type) { + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + type = "els"; + break; + case SRB_CT_CMD: + type = "ct pass-through"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + sp_bsg->ctx.type); + return; + } + + comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); + fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); + fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); + + /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT + * fc payload to the caller + */ + bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status); + + if (comp_status != CS_COMPLETE) { + if (comp_status == CS_DATA_UNDERRUN) { + bsg_job->reply->result = DID_OK << 16; + bsg_job->reply->reply_payload_rcv_len = + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count); + + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", + vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2], + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count))); + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x.\n", + vha->host_no, sp->handle, type, comp_status, + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1), + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2))); + bsg_job->reply->result = DID_ERROR << 16; + bsg_job->reply->reply_payload_rcv_len = 0; + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt))); + } + else { + bsg_job->reply->result = DID_OK << 16;; + bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; + bsg_job->reply_len = 0; + } + + dma_unmap_sg(&ha->pdev->dev, + bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) || + (sp_bsg->ctx.type == SRB_CT_CMD)) + kfree(sp->fcport); + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + bsg_job->job_done(bsg_job); +} + static void qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, struct logio_entry_24xx *logio) @@ -1749,6 +1846,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_logio_entry(vha, rsp->req, (struct logio_entry_24xx *)pkt); break; + case CT_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); + clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); + break; + case ELS_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -2046,7 +2150,6 @@ qla24xx_msix_default(int irq, void *dev_id) set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); complete(&ha->mbx_intr_comp); } - return IRQ_HANDLED; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 056e4d4505f3..6e53bdbb1da8 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3635,6 +3635,157 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) return rval; } +int +qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint32_t iter_cnt = 0x1; + + DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no)); + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; + mcp->mb[1] = mreq->options | BIT_6; // BIT_6 specifies 64 bit addressing + + /* transfer count */ + mcp->mb[10] = LSW(mreq->transfer_size); + mcp->mb[11] = MSW(mreq->transfer_size); + + /* send data address */ + mcp->mb[14] = LSW(mreq->send_dma); + mcp->mb[15] = MSW(mreq->send_dma); + mcp->mb[20] = LSW(MSD(mreq->send_dma)); + mcp->mb[21] = MSW(MSD(mreq->send_dma)); + + /* recieve data address */ + mcp->mb[16] = LSW(mreq->rcv_dma); + mcp->mb[17] = MSW(mreq->rcv_dma); + mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); + mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); + + /* Iteration count */ + mcp->mb[18] = LSW(iter_cnt); + mcp->mb[19] = MSW(iter_cnt); + + mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15| + MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; + if (IS_QLA81XX(vha->hw)) + mcp->out_mb |= MBX_2; + mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0; + + mcp->buf_size = mreq->transfer_size; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "(%ld): failed=%x mb[0]=0x%x " + "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x mb[19]=0x%x. \n", vha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19])); + } else { + DEBUG2(printk(KERN_WARNING + "scsi(%ld): done.\n", vha->host_no)); + } + + /* Copy mailbox information */ + memcpy( mresp, mcp->mb, 64); + mresp[3] = mcp->mb[18]; + mresp[4] = mcp->mb[19]; + return rval; +} + +int +qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no)); + + memset(mcp->mb, 0 , sizeof(mcp->mb)); + mcp->mb[0] = MBC_DIAGNOSTIC_ECHO; + mcp->mb[1] = mreq->options | BIT_6; /* BIT_6 specifies 64bit address */ + if (IS_QLA81XX(ha)) + mcp->mb[1] |= BIT_15; + mcp->mb[2] = IS_QLA81XX(ha) ? vha->fcoe_fcf_idx : 0; + mcp->mb[16] = LSW(mreq->rcv_dma); + mcp->mb[17] = MSW(mreq->rcv_dma); + mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); + mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); + + mcp->mb[10] = LSW(mreq->transfer_size); + + mcp->mb[14] = LSW(mreq->send_dma); + mcp->mb[15] = MSW(mreq->send_dma); + mcp->mb[20] = LSW(MSD(mreq->send_dma)); + mcp->mb[21] = MSW(MSD(mreq->send_dma)); + + mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15| + MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; + if (IS_QLA81XX(ha)) + mcp->out_mb |= MBX_2; + + mcp->in_mb = MBX_0; + if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) + mcp->in_mb |= MBX_1; + if (IS_QLA81XX(ha)) + mcp->in_mb |= MBX_3; + + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + mcp->buf_size = mreq->transfer_size; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2(printk(KERN_WARNING + "(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n", + vha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG2(printk(KERN_WARNING + "scsi(%ld): done.\n", vha->host_no)); + } + + /* Copy mailbox information */ + memcpy( mresp, mcp->mb, 32); + return rval; +} +int +qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic, + uint16_t *cmd_status) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG16(printk("%s(%ld): enable_diag=%d entered.\n", __func__, + ha->host_no, enable_diagnostic)); + + mcp->mb[0] = MBC_ISP84XX_RESET; + mcp->mb[1] = enable_diagnostic; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; + rval = qla2x00_mailbox_command(ha, mcp); + + /* Return mailbox statuses. */ + *cmd_status = mcp->mb[0]; + if (rval != QLA_SUCCESS) + DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, + rval)); + else + DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no)); + + return rval; +} + int qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fe34b7f9dee6..15ddfc435ea8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1969,6 +1969,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_channel = MAX_BUSES - 1; host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; + sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); /* Set up the irqs */ ret = qla2x00_request_irqs(ha, rsp); -- GitLab From f8ac60855ebfa239319a4a9945799995feda3b06 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:48 -0800 Subject: [PATCH 0906/3892] [SCSI] qla2xxx: Remove firmware hint for 81xx parts. Firmware is loaded from flash for these ISP types. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 15ddfc435ea8..ddc1d3def36c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3545,4 +3545,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); MODULE_FIRMWARE(FW_FILE_ISP25XX); -MODULE_FIRMWARE(FW_FILE_ISP81XX); -- GitLab From e8a392444d338d3ce77d157bcbe4975828536efa Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 12 Jan 2010 13:02:49 -0800 Subject: [PATCH 0907/3892] [SCSI] qla2xxx: Update version number to 8.03.02-k0. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index ed36279a33c1..082394b1ec07 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k10" +#define QLA2XXX_VERSION "8.03.02-k0" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 1 +#define QLA_DRIVER_PATCH_VER 2 #define QLA_DRIVER_BETA_VER 0 -- GitLab From 8605c46c171f02859fb3a32655fa226ce446c6ec Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 17 Jan 2010 21:19:31 +0200 Subject: [PATCH 0908/3892] [SCSI] lpfc: restore MSI-X/MSI support A Gentoo bug report [1] showed that as of 2.6.31 lpfc only uses INTx interrupts. This patch restores lpfc's ability to support MSI-X/MSI interrupts that the "Addition of SLI4 Interface - Base Support" patch [2] broke. It reestablishes MSI-X as the default interrupt method and in case MSI-X is not supported lpfc_sli{4,}_enable_intr fallbacks to MSI and then to INTx. [1]: http://bugs.gentoo.org/show_bug.cgi?id=296319 [2]: commit da0436e915a5c17ee79e72c1bf978a4ebb1cbf4d [James Smart: Background: Nothing Broke. This was intended. We had originally enabled MSI-X by default, but in qualification within the last 12 months, we encountered a major catch-22: There were at least 4 platforms, from 2 major OEMs, that : - Say they support MSI-X - platform routines work and act as if they do. - We enable it, generate a test interrupt to check they really do deliver it, and it works. - But shortly after attachment, the system hangs or loses interrupts, resulting in a bad system behavior. Given the distro's picking up the 2.6.32 kernel, we had to stick with a default of MSI-X off, with user-enabled MSI-X as these platforms couldn't get fixed. However, we're also now encountering platforms that require MSI-X and never INTx, so we must change. It's desired also for also for performance reasons. So - now (2.6.33) is the right time to re-enable MSI-X by default. ] [jejb: fix up comment on default values] Signed-off-by: George Kadianakis Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 91542f786edf..a8908e7c368a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3114,12 +3114,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, /* # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that # support this feature -# 0 = MSI disabled (default) +# 0 = MSI disabled # 1 = MSI enabled -# 2 = MSI-X enabled -# Value range is [0,2]. Default value is 0. +# 2 = MSI-X enabled (default) +# Value range is [0,2]. Default value is 2. */ -LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " +LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " "MSI-X (2), if possible"); /* -- GitLab From d57d64080ddc0ff13fcffc898b6251074a482ba1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 13:34:38 +0900 Subject: [PATCH 0909/3892] sh: Prevent 64-bit pgprot clobbering across ioremap implementations. Presently 'flags' gets passed around a lot between the various ioremap helpers and implementations, which is only 32-bits. In the X2TLB case we use 64-bit pgprots which presently results in the upper 32bits being chopped off (which handily include our read/write/exec permissions). As such, we convert everything internally to using pgprot_t directly and simply convert over with pgprot_val() where needed. With this in place, transparent fixmap utilization for early ioremap works as expected. Signed-off-by: Paul Mundt --- arch/sh/boards/board-sh7785lcr.c | 6 ++-- arch/sh/boards/mach-landisk/setup.c | 2 +- arch/sh/boards/mach-lboxre2/setup.c | 2 +- arch/sh/boards/mach-sh03/setup.c | 2 +- arch/sh/include/asm/io.h | 53 +++++++++++++++++------------ arch/sh/mm/ioremap.c | 9 +++-- 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c index 511de38d2046..fe7e686c94ac 100644 --- a/arch/sh/boards/board-sh7785lcr.c +++ b/arch/sh/boards/board-sh7785lcr.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -332,15 +333,14 @@ static void __init sh7785lcr_setup(char **cmdline_p) pm_power_off = sh7785lcr_power_off; /* sm501 DRAM configuration */ - sm501_reg = ioremap_fixed(SM107_REG_ADDR, SM501_DRAM_CONTROL, - PAGE_KERNEL); + sm501_reg = ioremap_nocache(SM107_REG_ADDR, SM501_DRAM_CONTROL); if (!sm501_reg) { printk(KERN_ERR "%s: ioremap error.\n", __func__); return; } writel(0x000307c2, sm501_reg + SM501_DRAM_CONTROL); - iounmap_fixed(sm501_reg); + iounmap(sm501_reg); } /* Return the board specific boot mode pin configuration */ diff --git a/arch/sh/boards/mach-landisk/setup.c b/arch/sh/boards/mach-landisk/setup.c index db22ea2e6d49..59816355d199 100644 --- a/arch/sh/boards/mach-landisk/setup.c +++ b/arch/sh/boards/mach-landisk/setup.c @@ -63,7 +63,7 @@ static int __init landisk_devices_setup(void) /* open I/O area window */ paddrbase = virt_to_phys((void *)PA_AREA5_IO); prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); - cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot); + cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot); if (!cf_ide_base) { printk("allocate_cf_area : can't open CF I/O window!\n"); return -ENOMEM; diff --git a/arch/sh/boards/mach-lboxre2/setup.c b/arch/sh/boards/mach-lboxre2/setup.c index 2b0b5818e1e4..408dd5df7d45 100644 --- a/arch/sh/boards/mach-lboxre2/setup.c +++ b/arch/sh/boards/mach-lboxre2/setup.c @@ -57,7 +57,7 @@ static int __init lboxre2_devices_setup(void) paddrbase = virt_to_phys((void*)PA_AREA5_IO); psize = PAGE_SIZE; prot = PAGE_KERNEL_PCC( 1 , _PAGE_PCC_IO16); - cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot.pgprot); + cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot); if (!cf0_io_base) { printk(KERN_ERR "%s : can't open CF I/O window!\n" , __func__ ); return -ENOMEM; diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c index 74cfb4b8b03d..f14ba0fa950b 100644 --- a/arch/sh/boards/mach-sh03/setup.c +++ b/arch/sh/boards/mach-sh03/setup.c @@ -82,7 +82,7 @@ static int __init sh03_devices_setup(void) /* open I/O area window */ paddrbase = virt_to_phys((void *)PA_AREA5_IO); prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); - cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot); + cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot); if (!cf_ide_base) { printk("allocate_cf_area : can't open CF I/O window!\n"); return -ENOMEM; diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 6a0dd8c1e0a9..13696dfccc16 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -235,7 +235,7 @@ unsigned long long poke_real_address_q(unsigned long long addr, */ #ifdef CONFIG_MMU void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, - unsigned long flags, void *caller); + pgprot_t prot, void *caller); void __iounmap(void __iomem *addr); #ifdef CONFIG_IOREMAP_FIXED @@ -254,13 +254,13 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } #endif static inline void __iomem * -__ioremap(unsigned long offset, unsigned long size, unsigned long flags) +__ioremap(unsigned long offset, unsigned long size, pgprot_t prot) { - return __ioremap_caller(offset, size, flags, __builtin_return_address(0)); + return __ioremap_caller(offset, size, prot, __builtin_return_address(0)); } static inline void __iomem * -__ioremap_29bit(unsigned long offset, unsigned long size, unsigned long flags) +__ioremap_29bit(unsigned long offset, unsigned long size, pgprot_t prot) { #ifdef CONFIG_29BIT unsigned long last_addr = offset + size - 1; @@ -272,7 +272,7 @@ __ioremap_29bit(unsigned long offset, unsigned long size, unsigned long flags) * mapping must be done by the PMB or by using page tables. */ if (likely(PXSEG(offset) < P3SEG && PXSEG(last_addr) < P3SEG)) { - if (unlikely(flags & _PAGE_CACHABLE)) + if (unlikely(pgprot_val(prot) & _PAGE_CACHABLE)) return (void __iomem *)P1SEGADDR(offset); return (void __iomem *)P2SEGADDR(offset); @@ -287,7 +287,7 @@ __ioremap_29bit(unsigned long offset, unsigned long size, unsigned long flags) } static inline void __iomem * -__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) +__ioremap_mode(unsigned long offset, unsigned long size, pgprot_t prot) { void __iomem *ret; @@ -295,30 +295,39 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) if (ret) return ret; - ret = __ioremap_29bit(offset, size, flags); + ret = __ioremap_29bit(offset, size, prot); if (ret) return ret; - return __ioremap(offset, size, flags); + return __ioremap(offset, size, prot); } #else -#define __ioremap(offset, size, flags) ((void __iomem *)(offset)) -#define __ioremap_mode(offset, size, flags) ((void __iomem *)(offset)) +#define __ioremap(offset, size, prot) ((void __iomem *)(offset)) +#define __ioremap_mode(offset, size, prot) ((void __iomem *)(offset)) #define __iounmap(addr) do { } while (0) #endif /* CONFIG_MMU */ -#define ioremap(offset, size) \ - __ioremap_mode((offset), (size), 0) -#define ioremap_nocache(offset, size) \ - __ioremap_mode((offset), (size), 0) -#define ioremap_cache(offset, size) \ - __ioremap_mode((offset), (size), _PAGE_CACHABLE) -#define p3_ioremap(offset, size, flags) \ - __ioremap((offset), (size), (flags)) -#define ioremap_prot(offset, size, flags) \ - __ioremap_mode((offset), (size), (flags)) -#define iounmap(addr) \ - __iounmap((addr)) +static inline void __iomem * +ioremap(unsigned long offset, unsigned long size) +{ + return __ioremap_mode(offset, size, PAGE_KERNEL_NOCACHE); +} + +static inline void __iomem * +ioremap_cache(unsigned long offset, unsigned long size) +{ + return __ioremap_mode(offset, size, PAGE_KERNEL); +} + +static inline void __iomem * +ioremap_prot(resource_size_t offset, unsigned long size, unsigned long flags) +{ + return __ioremap_mode(offset, size, __pgprot(flags)); +} + +#define ioremap_nocache ioremap +#define p3_ioremap __ioremap +#define iounmap __iounmap #define maybebadio(port) \ printk(KERN_ERR "bad PC-like io %s:%u for port 0x%lx at 0x%08x\n", \ diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index a130b2278e92..85b420d00622 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -35,11 +35,10 @@ */ void __iomem * __init_refok __ioremap_caller(unsigned long phys_addr, unsigned long size, - unsigned long flags, void *caller) + pgprot_t pgprot, void *caller) { struct vm_struct *area; unsigned long offset, last_addr, addr, orig_addr; - pgprot_t pgprot; /* Don't allow wraparound or zero size */ last_addr = phys_addr + size - 1; @@ -69,7 +68,7 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, * If we can't yet use the regular approach, go the fixmap route. */ if (!mem_init_done) - return ioremap_fixed(phys_addr, size, __pgprot(flags)); + return ioremap_fixed(phys_addr, size, pgprot); /* * Ok, go for it.. @@ -91,8 +90,9 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, * PMB entries are all pre-faulted. */ if (unlikely(phys_addr >= P1SEG)) { - unsigned long mapped = pmb_remap(addr, phys_addr, size, flags); + unsigned long mapped; + mapped = pmb_remap(addr, phys_addr, size, pgprot_val(pgprot)); if (likely(mapped)) { addr += mapped; phys_addr += mapped; @@ -101,7 +101,6 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, } #endif - pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags); if (likely(size)) if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) { vunmap((void *)orig_addr); -- GitLab From acf2c9685fb8295cb62a623d7358a1cfde8b07ea Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 13:49:19 +0900 Subject: [PATCH 0910/3892] sh: Kill off duplicate address alignment in ioremap_fixed(). This is already taken care of in the top-level ioremap, and now that no one should be calling ioremap_fixed() directly we can simply throw the mapping displacement in as an additional argument. Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 6 ++++-- arch/sh/mm/ioremap.c | 2 +- arch/sh/mm/ioremap_fixed.c | 22 +++------------------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 13696dfccc16..70269813cef1 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -239,12 +239,14 @@ void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, void __iounmap(void __iomem *addr); #ifdef CONFIG_IOREMAP_FIXED -extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t); +extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, + unsigned long, pgprot_t); extern int iounmap_fixed(void __iomem *); extern void ioremap_fixed_init(void); #else static inline void __iomem * -ioremap_fixed(resource_size t phys_addr, unsigned long size, pgprot_t prot) +ioremap_fixed(resource_size t phys_addr, unsigned long offset, + unsigned long size, pgprot_t prot) { BUG(); } diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index 85b420d00622..bb03308e8408 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -68,7 +68,7 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, * If we can't yet use the regular approach, go the fixmap route. */ if (!mem_init_done) - return ioremap_fixed(phys_addr, size, pgprot); + return ioremap_fixed(phys_addr, offset, size, pgprot); /* * Ok, go for it.. diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c index 425f6c6bf250..551b513e8fce 100644 --- a/arch/sh/mm/ioremap_fixed.c +++ b/arch/sh/mm/ioremap_fixed.c @@ -45,12 +45,11 @@ void __init ioremap_fixed_init(void) } void __init __iomem * -ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot) +ioremap_fixed(resource_size_t phys_addr, unsigned long offset, + unsigned long size, pgprot_t prot) { enum fixed_addresses idx0, idx; - resource_size_t last_addr; struct ioremap_map *map; - unsigned long offset; unsigned int nrpages; int i, slot; @@ -67,18 +66,6 @@ ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot) if (slot < 0) return NULL; - /* Don't allow wraparound or zero size */ - last_addr = phys_addr + size - 1; - if (!size || last_addr < phys_addr) - return NULL; - - /* - * Fixmap mappings have to be page-aligned - */ - offset = phys_addr & ~PAGE_MASK; - phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr + 1) - phys_addr; - /* * Mappings have to fit in the FIX_IOREMAP area. */ @@ -111,7 +98,6 @@ int iounmap_fixed(void __iomem *addr) unsigned long offset; unsigned int nrpages; int i, slot; - pgprot_t prot; slot = -1; for (i = 0; i < FIX_N_IOREMAPS; i++) { @@ -133,11 +119,9 @@ int iounmap_fixed(void __iomem *addr) offset = virt_addr & ~PAGE_MASK; nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT; - pgprot_val(prot) = _PAGE_WIRED; - idx = FIX_IOREMAP_BEGIN + slot + nrpages; while (nrpages > 0) { - __clear_fixmap(idx, prot); + __clear_fixmap(idx, __pgprot(_PAGE_WIRED)); --idx; --nrpages; } -- GitLab From f33609344acfdde1c1acedf6de3efe6b80af93a6 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 13:55:41 +0900 Subject: [PATCH 0911/3892] sh: Convert p3_ioremap() users to ioremap_prot(). This kills off the ancient p3_ioremap(), converting over to the more generic ioremap_prot() instead. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-landisk/setup.c | 2 +- arch/sh/boards/mach-lboxre2/setup.c | 4 ++-- arch/sh/boards/mach-sh03/setup.c | 2 +- arch/sh/include/asm/io.h | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/sh/boards/mach-landisk/setup.c b/arch/sh/boards/mach-landisk/setup.c index 59816355d199..2d09d4d34f87 100644 --- a/arch/sh/boards/mach-landisk/setup.c +++ b/arch/sh/boards/mach-landisk/setup.c @@ -63,7 +63,7 @@ static int __init landisk_devices_setup(void) /* open I/O area window */ paddrbase = virt_to_phys((void *)PA_AREA5_IO); prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); - cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot); + cf_ide_base = ioremap_prot(paddrbase, PAGE_SIZE, pgprot_val(prot)); if (!cf_ide_base) { printk("allocate_cf_area : can't open CF I/O window!\n"); return -ENOMEM; diff --git a/arch/sh/boards/mach-lboxre2/setup.c b/arch/sh/boards/mach-lboxre2/setup.c index 408dd5df7d45..79b4e0d77b71 100644 --- a/arch/sh/boards/mach-lboxre2/setup.c +++ b/arch/sh/boards/mach-lboxre2/setup.c @@ -56,8 +56,8 @@ static int __init lboxre2_devices_setup(void) /* open I/O area window */ paddrbase = virt_to_phys((void*)PA_AREA5_IO); psize = PAGE_SIZE; - prot = PAGE_KERNEL_PCC( 1 , _PAGE_PCC_IO16); - cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot); + prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); + cf0_io_base = (u32)ioremap_prot(paddrbase, psize, pgprot_val(prot)); if (!cf0_io_base) { printk(KERN_ERR "%s : can't open CF I/O window!\n" , __func__ ); return -ENOMEM; diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c index f14ba0fa950b..af4a0c012a96 100644 --- a/arch/sh/boards/mach-sh03/setup.c +++ b/arch/sh/boards/mach-sh03/setup.c @@ -82,7 +82,7 @@ static int __init sh03_devices_setup(void) /* open I/O area window */ paddrbase = virt_to_phys((void *)PA_AREA5_IO); prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); - cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot); + cf_ide_base = ioremap_prot(paddrbase, PAGE_SIZE, pgprot_val(prot)); if (!cf_ide_base) { printk("allocate_cf_area : can't open CF I/O window!\n"); return -ENOMEM; diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 70269813cef1..c32a55601d01 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -328,7 +328,6 @@ ioremap_prot(resource_size_t offset, unsigned long size, unsigned long flags) } #define ioremap_nocache ioremap -#define p3_ioremap __ioremap #define iounmap __iounmap #define maybebadio(port) \ -- GitLab From 6d63e73d520b690e4378cef3003eb5f01f7d128c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 14:00:14 +0900 Subject: [PATCH 0912/3892] sh: Limit ioremap_prot() to 32bit pgprot parts. Presently ioremap_prot() uses an unsigned long to pass the pgprot value around. This results in the upper half of the pgprot being chomped when using 64-bit pgprots on a 32-bit ABI (X2TLB and SH-5). As the only users of ioremap_prot() are presently legacy parts, this doesn't cause too much of an issue. In the future when the interface is converted to use pgprot_t directly this can be re-enabled for the other parts, too. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 2 +- arch/sh/include/asm/io.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5ac0115c9e20..8d0eabbf7460 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -13,7 +13,6 @@ config SUPERH select HAVE_LMB select HAVE_OPROFILE select HAVE_GENERIC_DMA_COHERENT - select HAVE_IOREMAP_PROT if MMU select HAVE_ARCH_TRACEHOOK select HAVE_DMA_API_DEBUG select HAVE_DMA_ATTRS @@ -36,6 +35,7 @@ config SUPERH32 def_bool ARCH = "sh" select HAVE_KPROBES select HAVE_KRETPROBES + select HAVE_IOREMAP_PROT if MMU && !X2TLB select HAVE_FUNCTION_TRACER select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index c32a55601d01..4bad72a1b39e 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -321,11 +321,13 @@ ioremap_cache(unsigned long offset, unsigned long size) return __ioremap_mode(offset, size, PAGE_KERNEL); } +#ifdef CONFIG_HAVE_IOREMAP_PROT static inline void __iomem * ioremap_prot(resource_size_t offset, unsigned long size, unsigned long flags) { return __ioremap_mode(offset, size, __pgprot(flags)); } +#endif #define ioremap_nocache ioremap #define iounmap __iounmap -- GitLab From 046581f9623b53f551a93864bb74e15ad2514f0c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 14:23:39 +0900 Subject: [PATCH 0913/3892] sh: Provide a dummy _PAGE_WIRED flag for non-X2TLB parts. This provides a dummy value for legacy parts which permits the entry wiring to be open-coded. The compiler takes care of optimizing the entry wiring away in these cases. Signed-off-by: Paul Mundt --- arch/sh/include/asm/pgtable_32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h index c573d45f1286..e172d696e52b 100644 --- a/arch/sh/include/asm/pgtable_32.h +++ b/arch/sh/include/asm/pgtable_32.h @@ -143,12 +143,14 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) # elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) # define _PAGE_SZHUGE (_PAGE_EXT_ESZ2 | _PAGE_EXT_ESZ3) # endif +# define _PAGE_WIRED (_PAGE_EXT(_PAGE_EXT_WIRED)) #else # if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) # define _PAGE_SZHUGE (_PAGE_SZ1) # elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) # define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1) # endif +# define _PAGE_WIRED (0) #endif /* @@ -166,8 +168,6 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \ _PAGE_DIRTY | _PAGE_SPECIAL) -#define _PAGE_WIRED (_PAGE_EXT(_PAGE_EXT_WIRED)) - #ifndef __ASSEMBLY__ #if defined(CONFIG_X2TLB) /* SH-X2 TLB */ -- GitLab From bb29c677b366fdf4f6522cd82228a32567aa98c7 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:20:35 +0900 Subject: [PATCH 0914/3892] sh: Split out MMUCR.URB based entry wiring in to shared helper. Presently this is duplicated between tlb-sh4 and tlb-pteaex. Split the helpers out in to a generic tlb-urb that can be used by any parts equipped with MMUCR.URB. At the same time, move the SH-5 code out-of-line, as we require single global state for DTLB entry wiring. Signed-off-by: Paul Mundt --- arch/sh/include/asm/tlb.h | 44 +-------------------- arch/sh/mm/Makefile | 4 +- arch/sh/mm/tlb-pteaex.c | 66 ------------------------------- arch/sh/mm/tlb-sh4.c | 66 ------------------------------- arch/sh/mm/tlb-sh5.c | 39 +++++++++++++++++++ arch/sh/mm/tlb-urb.c | 81 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 176 deletions(-) create mode 100644 arch/sh/mm/tlb-urb.c diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h index dfc8fcd8ee50..75abb38dffd5 100644 --- a/arch/sh/include/asm/tlb.h +++ b/arch/sh/include/asm/tlb.h @@ -98,49 +98,9 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) #define tlb_migrate_finish(mm) do { } while (0) -#ifdef CONFIG_CPU_SH4 +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SUPERH64) extern void tlb_wire_entry(struct vm_area_struct *, unsigned long, pte_t); extern void tlb_unwire_entry(void); -#elif defined(CONFIG_SUPERH64) -static int dtlb_entry; -static unsigned long long dtlb_entries[64]; - -static inline void tlb_wire_entry(struct vm_area_struct *vma, - unsigned long addr, pte_t pte) -{ - unsigned long long entry; - unsigned long paddr, flags; - - BUG_ON(dtlb_entry == 64); - - local_irq_save(flags); - - entry = sh64_get_wired_dtlb_entry(); - dtlb_entries[dtlb_entry++] = entry; - - paddr = pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK; - paddr &= ~PAGE_MASK; - - sh64_setup_tlb_slot(entry, addr, get_asid(), paddr); - - local_irq_restore(flags); -} - -static inline void tlb_unwire_entry(void) -{ - unsigned long long entry; - unsigned long flags; - - BUG_ON(!dtlb_entry); - - local_irq_save(flags); - entry = dtlb_entries[dtlb_entry--]; - - sh64_teardown_tlb_slot(entry); - sh64_put_wired_dtlb_entry(entry); - - local_irq_restore(flags); -} #else static inline void tlb_wire_entry(struct vm_area_struct *vma , unsigned long addr, pte_t pte) @@ -152,7 +112,7 @@ static inline void tlb_unwire_entry(void) { BUG(); } -#endif /* CONFIG_CPU_SH4 */ +#endif #else /* CONFIG_MMU */ diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 0027cdea2c20..de714cbd961a 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -26,9 +26,9 @@ endif ifdef CONFIG_MMU tlb-$(CONFIG_CPU_SH3) := tlb-sh3.o -tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o +tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o tlb-urb.o tlb-$(CONFIG_CPU_SH5) := tlb-sh5.o -tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o +tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o tlb-urb.o obj-y += $(tlb-y) endif diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 88c8bb05e16d..409b7c2b4b9d 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -76,69 +76,3 @@ void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT); back_to_cached(); } - -/* - * Load the entry for 'addr' into the TLB and wire the entry. - */ -void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) -{ - unsigned long status, flags; - int urb; - - local_irq_save(flags); - - /* Load the entry into the TLB */ - __update_tlb(vma, addr, pte); - - /* ... and wire it up. */ - status = ctrl_inl(MMUCR); - urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; - status &= ~MMUCR_URB; - - /* - * Make sure we're not trying to wire the last TLB entry slot. - */ - BUG_ON(!--urb); - - urb = urb % MMUCR_URB_NENTRIES; - - status |= (urb << MMUCR_URB_SHIFT); - ctrl_outl(status, MMUCR); - ctrl_barrier(); - - local_irq_restore(flags); -} - -/* - * Unwire the last wired TLB entry. - * - * It should also be noted that it is not possible to wire and unwire - * TLB entries in an arbitrary order. If you wire TLB entry N, followed - * by entry N+1, you must unwire entry N+1 first, then entry N. In this - * respect, it works like a stack or LIFO queue. - */ -void tlb_unwire_entry(void) -{ - unsigned long status, flags; - int urb; - - local_irq_save(flags); - - status = ctrl_inl(MMUCR); - urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; - status &= ~MMUCR_URB; - - /* - * Make sure we're not trying to unwire a TLB entry when none - * have been wired. - */ - BUG_ON(urb++ == MMUCR_URB_NENTRIES); - - urb = urb % MMUCR_URB_NENTRIES; - - status |= (urb << MMUCR_URB_SHIFT); - ctrl_outl(status, MMUCR); - ctrl_barrier(); - - local_irq_restore(flags); -} diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 4c6234743318..8cf550e2570f 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -81,69 +81,3 @@ void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, ctrl_outl(data, addr); back_to_cached(); } - -/* - * Load the entry for 'addr' into the TLB and wire the entry. - */ -void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) -{ - unsigned long status, flags; - int urb; - - local_irq_save(flags); - - /* Load the entry into the TLB */ - __update_tlb(vma, addr, pte); - - /* ... and wire it up. */ - status = ctrl_inl(MMUCR); - urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; - status &= ~MMUCR_URB; - - /* - * Make sure we're not trying to wire the last TLB entry slot. - */ - BUG_ON(!--urb); - - urb = urb % MMUCR_URB_NENTRIES; - - status |= (urb << MMUCR_URB_SHIFT); - ctrl_outl(status, MMUCR); - ctrl_barrier(); - - local_irq_restore(flags); -} - -/* - * Unwire the last wired TLB entry. - * - * It should also be noted that it is not possible to wire and unwire - * TLB entries in an arbitrary order. If you wire TLB entry N, followed - * by entry N+1, you must unwire entry N+1 first, then entry N. In this - * respect, it works like a stack or LIFO queue. - */ -void tlb_unwire_entry(void) -{ - unsigned long status, flags; - int urb; - - local_irq_save(flags); - - status = ctrl_inl(MMUCR); - urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; - status &= ~MMUCR_URB; - - /* - * Make sure we're not trying to unwire a TLB entry when none - * have been wired. - */ - BUG_ON(urb++ == MMUCR_URB_NENTRIES); - - urb = urb % MMUCR_URB_NENTRIES; - - status |= (urb << MMUCR_URB_SHIFT); - ctrl_outl(status, MMUCR); - ctrl_barrier(); - - local_irq_restore(flags); -} diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c index fdb64e41ec50..f27dbe1c1599 100644 --- a/arch/sh/mm/tlb-sh5.c +++ b/arch/sh/mm/tlb-sh5.c @@ -143,3 +143,42 @@ void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr, */ void sh64_teardown_tlb_slot(unsigned long long config_addr) __attribute__ ((alias("__flush_tlb_slot"))); + +static int dtlb_entry; +static unsigned long long dtlb_entries[64]; + +void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + unsigned long long entry; + unsigned long paddr, flags; + + BUG_ON(dtlb_entry == ARRAY_SIZE(dtlb_entries)); + + local_irq_save(flags); + + entry = sh64_get_wired_dtlb_entry(); + dtlb_entries[dtlb_entry++] = entry; + + paddr = pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK; + paddr &= ~PAGE_MASK; + + sh64_setup_tlb_slot(entry, addr, get_asid(), paddr); + + local_irq_restore(flags); +} + +void tlb_unwire_entry(void) +{ + unsigned long long entry; + unsigned long flags; + + BUG_ON(!dtlb_entry); + + local_irq_save(flags); + entry = dtlb_entries[dtlb_entry--]; + + sh64_teardown_tlb_slot(entry); + sh64_put_wired_dtlb_entry(entry); + + local_irq_restore(flags); +} diff --git a/arch/sh/mm/tlb-urb.c b/arch/sh/mm/tlb-urb.c new file mode 100644 index 000000000000..bb5b9098956d --- /dev/null +++ b/arch/sh/mm/tlb-urb.c @@ -0,0 +1,81 @@ +/* + * arch/sh/mm/tlb-urb.c + * + * TLB entry wiring helpers for URB-equipped parts. + * + * Copyright (C) 2010 Matt Fleming + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +/* + * Load the entry for 'addr' into the TLB and wire the entry. + */ +void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + /* Load the entry into the TLB */ + __update_tlb(vma, addr, pte); + + /* ... and wire it up. */ + status = __raw_readl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to wire the last TLB entry slot. + */ + BUG_ON(!--urb); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + __raw_writel(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} + +/* + * Unwire the last wired TLB entry. + * + * It should also be noted that it is not possible to wire and unwire + * TLB entries in an arbitrary order. If you wire TLB entry N, followed + * by entry N+1, you must unwire entry N+1 first, then entry N. In this + * respect, it works like a stack or LIFO queue. + */ +void tlb_unwire_entry(void) +{ + unsigned long status, flags; + int urb; + + local_irq_save(flags); + + status = __raw_readl(MMUCR); + urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT; + status &= ~MMUCR_URB; + + /* + * Make sure we're not trying to unwire a TLB entry when none + * have been wired. + */ + BUG_ON(urb++ == MMUCR_URB_NENTRIES); + + urb = urb % MMUCR_URB_NENTRIES; + + status |= (urb << MMUCR_URB_SHIFT); + __raw_writel(status, MMUCR); + ctrl_barrier(); + + local_irq_restore(flags); +} -- GitLab From cb6d04468d16de5a6161167ec7e76a43be540a80 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:22:52 +0900 Subject: [PATCH 0915/3892] sh: Kill off now bogus fixmap/page wiring documentation. The plans for _PAGE_WIRED were detailed in a comment with the fixmap code, but as it's now all taken care of, we no longer have any reason for keeping it around, particularly since it's no longer accurate. Kill it off. Signed-off-by: Paul Mundt --- arch/sh/mm/init.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index fe578a286fdd..32ebd1592e63 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -98,21 +98,6 @@ static void clear_pte_phys(unsigned long addr, pgprot_t prot) local_flush_tlb_one(get_asid(), addr); } -/* - * As a performance optimization, other platforms preserve the fixmap mapping - * across a context switch, we don't presently do this, but this could be done - * in a similar fashion as to the wired TLB interface that sh64 uses (by way - * of the memory mapped UTLB configuration) -- this unfortunately forces us to - * give up a TLB entry for each mapping we want to preserve. While this may be - * viable for a small number of fixmaps, it's not particularly useful for - * everything and needs to be carefully evaluated. (ie, we may want this for - * the vsyscall page). - * - * XXX: Perhaps add a _PAGE_WIRED flag or something similar that we can pass - * in at __set_fixmap() time to determine the appropriate behavior to follow. - * - * -- PFM. - */ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) { unsigned long address = __fix_to_virt(idx); -- GitLab From 3ef2932b8c1fc89408ef1fd4b1e1c2caabc7f07d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:40:03 +0900 Subject: [PATCH 0916/3892] sh64: Fix up the build for the thread_xstate changes. This updates the sh64 processor info with the sh32 changes in order to tie in to the generic task_xstate management code. Signed-off-by: Paul Mundt --- arch/sh/include/asm/processor.h | 6 ++++++ arch/sh/include/asm/processor_32.h | 4 ---- arch/sh/include/asm/processor_64.h | 18 +++++++++--------- arch/sh/kernel/cpu/sh5/fpu.c | 12 ++++++------ arch/sh/kernel/process_64.c | 2 +- arch/sh/kernel/ptrace_64.c | 10 +++++----- arch/sh/kernel/signal_64.c | 4 ++-- arch/sh/kernel/traps_64.c | 28 ++++++++++++++-------------- 8 files changed, 43 insertions(+), 41 deletions(-) diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index a522e5d8f44f..87a8d1ef64e4 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h @@ -98,9 +98,15 @@ extern struct sh_cpuinfo cpu_data[]; /* Forward decl */ struct seq_operations; +struct task_struct; extern struct pt_regs fake_swapper_regs; +/* arch/sh/kernel/process.c */ +extern unsigned int xstate_size; +extern void free_thread_xstate(struct task_struct *); +extern struct kmem_cache *task_xstate_cachep; + /* arch/sh/mm/init.c */ extern unsigned int mem_init_done; diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 5fd83125fb89..488f0a906a41 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -96,10 +96,6 @@ union thread_xstate { struct sh_fpu_soft_struct softfpu; }; -extern unsigned int xstate_size; -extern void free_thread_xstate(struct task_struct *); -extern struct kmem_cache *task_xstate_cachep; - struct thread_struct { /* Saved registers when thread is descheduled */ unsigned long sp; diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index 5727d31b0ccf..7b1560f03d14 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h @@ -87,20 +87,21 @@ struct sh_fpu_hard_struct { /* long status; * software status information */ }; -#if 0 /* Dummy fpu emulator */ struct sh_fpu_soft_struct { - unsigned long long fp_regs[32]; + unsigned long fp_regs[64]; unsigned int fpscr; unsigned char lookahead; unsigned long entry_pc; }; -#endif -union sh_fpu_union { - struct sh_fpu_hard_struct hard; - /* 'hard' itself only produces 32 bit alignment, yet we need - to access it using 64 bit load/store as well. */ +union thread_xstate { + struct sh_fpu_hard_struct hardfpu; + struct sh_fpu_soft_struct softfpu; + /* + * The structure definitions only produce 32 bit alignment, yet we need + * to access them using 64 bit load/store as well. + */ unsigned long long alignment_dummy; }; @@ -122,7 +123,7 @@ struct thread_struct { /* Hardware debugging registers may come here */ /* floating point info */ - union sh_fpu_union fpu; + union thread_xstate *xstate; }; #define INIT_MMAP \ @@ -137,7 +138,6 @@ struct thread_struct { .trap_no = 0, \ .error_code = 0, \ .address = 0, \ - .fpu = { { { 0, } }, } \ } /* diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c index 4648ccee6c4d..92df285fbe4b 100644 --- a/arch/sh/kernel/cpu/sh5/fpu.c +++ b/arch/sh/kernel/cpu/sh5/fpu.c @@ -27,8 +27,8 @@ #define sNAN64 0xFFFFFFFFFFFFFFFFULL #define sNAN32 0xFFFFFFFFUL -static union sh_fpu_union init_fpuregs = { - .hard = { +static union thread_xstate init_fpuregs = { + .hardfpu = { .fp_regs = { [0 ... 63] = sNAN32 }, .fpscr = FPSCR_INIT } @@ -72,7 +72,7 @@ void save_fpu(struct task_struct *tsk) "fgetscr fr63\n\t" "fst.s %0, (32*8), fr63\n\t" : /* no output */ - : "r" (&tsk->thread.fpu.hard) + : "r" (&tsk->thread.xstate->hardfpu) : "memory"); } @@ -121,7 +121,7 @@ fpload(struct sh_fpu_hard_struct *fpregs) void fpinit(struct sh_fpu_hard_struct *fpregs) { - *fpregs = init_fpuregs.hard; + *fpregs = init_fpuregs.hardfpu; } asmlinkage void @@ -157,10 +157,10 @@ do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) last_task_used_math = current; if (used_math()) { - fpload(¤t->thread.fpu.hard); + fpload(¤t->thread.xstate->hardfpu); } else { /* First time FPU user. */ - fpload(&init_fpuregs.hard); + fpload(&init_fpuregs.hardfpu); set_used_math(); } disable_fpu(); diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 31f80c61b031..c9554a70bd0e 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -410,7 +410,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) regs->sr |= SR_FD; } - memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); + memcpy(fpu, &tsk->thread.xstate->hardfpu, sizeof(*fpu)); } return fpvalid; diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 873ebdc4f98e..67fbcee89e7e 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -88,7 +88,7 @@ get_fpu_long(struct task_struct *task, unsigned long addr) regs->sr |= SR_FD; } - tmp = ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)]; + tmp = ((long *)task->thread.xstate)[addr / sizeof(unsigned long)]; return tmp; } @@ -114,7 +114,7 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1; if (!tsk_used_math(task)) { - fpinit(&task->thread.fpu.hard); + fpinit(&task->thread.xstate->hardfpu); set_stopped_child_used_math(task); } else if (last_task_used_math == task) { enable_fpu(); @@ -124,7 +124,7 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) regs->sr |= SR_FD; } - ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)] = data; + ((long *)task->thread.xstate)[addr / sizeof(unsigned long)] = data; return 0; } @@ -222,7 +222,7 @@ int fpregs_get(struct task_struct *target, return ret; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.hard, 0, -1); + &target->thread.xstate->hardfpu, 0, -1); } static int fpregs_set(struct task_struct *target, @@ -239,7 +239,7 @@ static int fpregs_set(struct task_struct *target, set_stopped_child_used_math(target); return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu.hard, 0, -1); + &target->thread.xstate->hardfpu, 0, -1); } static int fpregs_active(struct task_struct *target, diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index ce76dbdef294..4733bfc59d39 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -295,7 +295,7 @@ restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) regs->sr |= SR_FD; } - err |= __copy_from_user(¤t->thread.fpu.hard, &sc->sc_fpregs[0], + err |= __copy_from_user(¤t->thread.xstate->hardfpu, &sc->sc_fpregs[0], (sizeof(long long) * 32) + (sizeof(int) * 1)); return err; @@ -320,7 +320,7 @@ setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) regs->sr |= SR_FD; } - err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.fpu.hard, + err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.xstate->hardfpu, (sizeof(long long) * 32) + (sizeof(int) * 1)); clear_used_math(); diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index d86f5315a0c1..e3f92eb05ffd 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c @@ -611,19 +611,19 @@ static int misaligned_fpu_load(struct pt_regs *regs, switch (width_shift) { case 2: - current->thread.fpu.hard.fp_regs[destreg] = buflo; + current->thread.xstate->hardfpu.fp_regs[destreg] = buflo; break; case 3: if (do_paired_load) { - current->thread.fpu.hard.fp_regs[destreg] = buflo; - current->thread.fpu.hard.fp_regs[destreg+1] = bufhi; + current->thread.xstate->hardfpu.fp_regs[destreg] = buflo; + current->thread.xstate->hardfpu.fp_regs[destreg+1] = bufhi; } else { #if defined(CONFIG_CPU_LITTLE_ENDIAN) - current->thread.fpu.hard.fp_regs[destreg] = bufhi; - current->thread.fpu.hard.fp_regs[destreg+1] = buflo; + current->thread.xstate->hardfpu.fp_regs[destreg] = bufhi; + current->thread.xstate->hardfpu.fp_regs[destreg+1] = buflo; #else - current->thread.fpu.hard.fp_regs[destreg] = buflo; - current->thread.fpu.hard.fp_regs[destreg+1] = bufhi; + current->thread.xstate->hardfpu.fp_regs[destreg] = buflo; + current->thread.xstate->hardfpu.fp_regs[destreg+1] = bufhi; #endif } break; @@ -681,19 +681,19 @@ static int misaligned_fpu_store(struct pt_regs *regs, switch (width_shift) { case 2: - buflo = current->thread.fpu.hard.fp_regs[srcreg]; + buflo = current->thread.xstate->hardfpu.fp_regs[srcreg]; break; case 3: if (do_paired_load) { - buflo = current->thread.fpu.hard.fp_regs[srcreg]; - bufhi = current->thread.fpu.hard.fp_regs[srcreg+1]; + buflo = current->thread.xstate->hardfpu.fp_regs[srcreg]; + bufhi = current->thread.xstate->hardfpu.fp_regs[srcreg+1]; } else { #if defined(CONFIG_CPU_LITTLE_ENDIAN) - bufhi = current->thread.fpu.hard.fp_regs[srcreg]; - buflo = current->thread.fpu.hard.fp_regs[srcreg+1]; + bufhi = current->thread.xstate->hardfpu.fp_regs[srcreg]; + buflo = current->thread.xstate->hardfpu.fp_regs[srcreg+1]; #else - buflo = current->thread.fpu.hard.fp_regs[srcreg]; - bufhi = current->thread.fpu.hard.fp_regs[srcreg+1]; + buflo = current->thread.xstate->hardfpu.fp_regs[srcreg]; + bufhi = current->thread.xstate->hardfpu.fp_regs[srcreg+1]; #endif } break; -- GitLab From 88ea1a445a84fcfbedb810c01e84d6711352bd82 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:41:50 +0900 Subject: [PATCH 0917/3892] sh64: Fix up PC casting in unaligned fixup notifier with 32bit ABI. Presently the build bails with the following: CC arch/sh/mm/alignment.o cc1: warnings being treated as errors arch/sh/mm/alignment.c: In function 'unaligned_fixups_notify': arch/sh/mm/alignment.c:69: warning: cast to pointer from integer of different size arch/sh/mm/alignment.c:74: warning: cast to pointer from integer of different size make[2]: *** [arch/sh/mm/alignment.o] Error 1 This is due to the fact that regs->pc is always 64-bit, while the pointer size depends on the ABI. Wrapping through instruction_pointer() takes care of the appropriate casting for both configurations. Signed-off-by: Paul Mundt --- arch/sh/mm/alignment.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c index e615151eac3b..2da808802a4c 100644 --- a/arch/sh/mm/alignment.c +++ b/arch/sh/mm/alignment.c @@ -69,12 +69,12 @@ void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn, pr_notice("Fixing up unaligned userspace access " "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", tsk->comm, task_pid_nr(tsk), - (void *)regs->pc, insn); + (void *)instruction_pointer(regs), insn); else if (se_kernmode_warn && printk_ratelimit()) pr_notice("Fixing up unaligned kernel access " "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", tsk->comm, task_pid_nr(tsk), - (void *)regs->pc, insn); + (void *)instruction_pointer(regs), insn); } static const char *se_usermode_action[] = { -- GitLab From d6db8888c8957fbdcd611e1321a6f6a0d6fb7e15 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:55:27 +0900 Subject: [PATCH 0918/3892] sh64: Use the shared FPU state restorer. This kills off the sh64-specific state restorer and switches over to the generic one. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh5/entry.S | 4 +-- arch/sh/kernel/cpu/sh5/fpu.c | 63 +++------------------------------- arch/sh/kernel/ptrace_64.c | 3 +- 3 files changed, 8 insertions(+), 62 deletions(-) diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index 8f13f73cb2cb..36d031c700bb 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S @@ -1124,7 +1124,7 @@ fpu_error_or_IRQA: pta its_IRQ, tr0 beqi/l r4, EVENT_INTERRUPT, tr0 #ifdef CONFIG_SH_FPU - movi do_fpu_state_restore, r6 + movi fpu_state_restore_trap_handler, r6 #else movi do_exception_error, r6 #endif @@ -1135,7 +1135,7 @@ fpu_error_or_IRQB: pta its_IRQ, tr0 beqi/l r4, EVENT_INTERRUPT, tr0 #ifdef CONFIG_SH_FPU - movi do_fpu_state_restore, r6 + movi fpu_state_restore_trap_handler, r6 #else movi do_exception_error, r6 #endif diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c index 92df285fbe4b..4b3bb35e99f3 100644 --- a/arch/sh/kernel/cpu/sh5/fpu.c +++ b/arch/sh/kernel/cpu/sh5/fpu.c @@ -15,24 +15,6 @@ #include #include #include -#include -#include -#include - -/* - * Initially load the FPU with signalling NANS. This bit pattern - * has the property that no matter whether considered as single or as - * double precision, it still represents a signalling NAN. - */ -#define sNAN64 0xFFFFFFFFFFFFFFFFULL -#define sNAN32 0xFFFFFFFFUL - -static union thread_xstate init_fpuregs = { - .hardfpu = { - .fp_regs = { [0 ... 63] = sNAN32 }, - .fpscr = FPSCR_INIT - } -}; void save_fpu(struct task_struct *tsk) { @@ -76,8 +58,7 @@ void save_fpu(struct task_struct *tsk) : "memory"); } -static inline void -fpload(struct sh_fpu_hard_struct *fpregs) +void restore_fpu(struct task_struct *tsk) { asm volatile("fld.p %0, (0*8), fp0\n\t" "fld.p %0, (1*8), fp2\n\t" @@ -116,16 +97,11 @@ fpload(struct sh_fpu_hard_struct *fpregs) "fld.p %0, (31*8), fp62\n\t" : /* no output */ - : "r" (fpregs) ); -} - -void fpinit(struct sh_fpu_hard_struct *fpregs) -{ - *fpregs = init_fpuregs.hardfpu; + : "r" (&tsk->thread.xstate->hardfpu) + : "memory"); } -asmlinkage void -do_fpu_error(unsigned long ex, struct pt_regs *regs) +asmlinkage void do_fpu_error(unsigned long ex, struct pt_regs *regs) { struct task_struct *tsk = current; @@ -133,35 +109,6 @@ do_fpu_error(unsigned long ex, struct pt_regs *regs) tsk->thread.trap_no = 11; tsk->thread.error_code = 0; - force_sig(SIGFPE, tsk); -} - - -asmlinkage void -do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) -{ - void die(const char *str, struct pt_regs *regs, long err); - - if (! user_mode(regs)) - die("FPU used in kernel", regs, ex); - regs->sr &= ~SR_FD; - - if (last_task_used_math == current) - return; - - enable_fpu(); - if (last_task_used_math != NULL) - /* Other processes fpu state, save away */ - save_fpu(last_task_used_math); - - last_task_used_math = current; - if (used_math()) { - fpload(¤t->thread.xstate->hardfpu); - } else { - /* First time FPU user. */ - fpload(&init_fpuregs.hardfpu); - set_used_math(); - } - disable_fpu(); + force_sig(SIGFPE, tsk); } diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 67fbcee89e7e..23fbd92a74e7 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -114,8 +114,7 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1; if (!tsk_used_math(task)) { - fpinit(&task->thread.xstate->hardfpu); - set_stopped_child_used_math(task); + init_fpu(task); } else if (last_task_used_math == task) { enable_fpu(); save_fpu(task); -- GitLab From a4ae2b2b18d1766768987dc5de42dfa3c2a6d9f7 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 15:58:27 +0900 Subject: [PATCH 0919/3892] sh64: Fixup build breakage from breakpoint handler rename. The breakpoint handler was renamed on sh32, but sh64 was overlooked in the conversion. Fix it up now. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh5/entry.S | 2 +- arch/sh/kernel/ptrace_64.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index 36d031c700bb..6b80295dd7a4 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S @@ -187,7 +187,7 @@ trap_jtable: .rept 6 .long do_exception_error /* 0x880 - 0x920 */ .endr - .long do_software_break_point /* 0x940 */ + .long breakpoint_trap_handler /* 0x940 */ .long do_exception_error /* 0x960 */ .long do_single_step /* 0x980 */ diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 23fbd92a74e7..2f6140e95ec5 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -478,9 +478,10 @@ asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs) } /* Called with interrupts disabled */ -asmlinkage void do_software_break_point(unsigned long long vec, - struct pt_regs *regs) +BUILD_TRAP_HANDLER(breakpoint) { + TRAP_HANDLER_DECL; + /* We need to forward step the PC, to counteract the backstep done in signal.c. */ local_irq_enable(); -- GitLab From 5a9003db1faa34c0560561f66b263f288d623324 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 19 Jan 2010 00:28:44 -0800 Subject: [PATCH 0920/3892] Input: ADP5588 - add support for ADP5587 devices The ADP5587 is quite similar to the ADP5588 but features a greater I/O voltage range and lacks the Dual Light Sensor Interface. This new part is also supported by this driver. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 4 ++-- drivers/input/keyboard/adp5588-keys.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 02c836e11813..c72283c6916f 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -35,10 +35,10 @@ config KEYBOARD_ADP5520 be called adp5520-keys. config KEYBOARD_ADP5588 - tristate "ADP5588 I2C QWERTY Keypad and IO Expander" + tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander" depends on I2C help - Say Y here if you want to use a ADP5588 attached to your + Say Y here if you want to use a ADP5588/87 attached to your system I2C bus. To compile this driver as a module, choose M here: the diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index d48c808d5928..6737fe4c0f12 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -1,6 +1,7 @@ /* * File: drivers/input/keyboard/adp5588_keys.c - * Description: keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander + * Description: keypad driver for ADP5588 and ADP5587 + * I2C QWERTY Keypad and IO Expander * Bugs: Enter bugs at http://blackfin.uclinux.org/ * * Copyright (C) 2008-2009 Analog Devices Inc. @@ -327,6 +328,7 @@ static struct dev_pm_ops adp5588_dev_pm_ops = { static const struct i2c_device_id adp5588_id[] = { { KBUILD_MODNAME, 0 }, + { "adp5587-keys", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, adp5588_id); @@ -357,5 +359,5 @@ module_exit(adp5588_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("ADP5588 Keypad driver"); +MODULE_DESCRIPTION("ADP5588/87 Keypad driver"); MODULE_ALIAS("platform:adp5588-keys"); -- GitLab From fa44a73cc766c7f3bac71a66d564e0049b800325 Mon Sep 17 00:00:00 2001 From: Lennart Sorensen Date: Mon, 18 Jan 2010 12:59:55 +0000 Subject: [PATCH 0921/3892] ppp_generic.c severly whitespace damanged by 9c705260feea6ae329bc6b6d5f6d2ef0227eda0a I was just looking at ppp_generic, and noticed that it fairly recently (as in the last year) got rather mangled with many spaces turned into tabs in places they very much shouldn't have been. I tracked it down to commit 9c705260feea6ae329bc6b6d5f6d2ef0227eda0a (ppp: ppp_mp_explode() redesign). I am amazed if that patch passed the patch checking script. I have no idea what kind of weird editor setting did this, but it has to have been a weird editor setting or a very unfortunate search and replace gone wrong. I only found it trying to apply a patch I was playing with and wondering why it wouldn't apply. Then I found there were tabs in the middle of comments that used to be spaces. Well here is a patch that should fix it up as far as I can tell. Purely whitespace repair. No actual code changes. Signed-off-by: Len Sorensen Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 122 +++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 2282e729edbe..6d61602208c1 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -167,7 +167,7 @@ struct channel { u8 avail; /* flag used in multilink stuff */ u8 had_frag; /* >= 1 fragments have been sent */ u32 lastseq; /* MP: last sequence # received */ - int speed; /* speed of the corresponding ppp channel*/ + int speed; /* speed of the corresponding ppp channel*/ #endif /* CONFIG_PPP_MULTILINK */ }; @@ -1293,13 +1293,13 @@ ppp_push(struct ppp *ppp) */ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) { - int len, totlen; - int i, bits, hdrlen, mtu; - int flen; - int navail, nfree, nzero; - int nbigger; - int totspeed; - int totfree; + int len, totlen; + int i, bits, hdrlen, mtu; + int flen; + int navail, nfree, nzero; + int nbigger; + int totspeed; + int totfree; unsigned char *p, *q; struct list_head *list; struct channel *pch; @@ -1307,21 +1307,21 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) struct ppp_channel *chan; totspeed = 0; /*total bitrate of the bundle*/ - nfree = 0; /* # channels which have no packet already queued */ - navail = 0; /* total # of usable channels (not deregistered) */ - nzero = 0; /* number of channels with zero speed associated*/ - totfree = 0; /*total # of channels available and + nfree = 0; /* # channels which have no packet already queued */ + navail = 0; /* total # of usable channels (not deregistered) */ + nzero = 0; /* number of channels with zero speed associated*/ + totfree = 0; /*total # of channels available and *having no queued packets before *starting the fragmentation*/ hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; - i = 0; - list_for_each_entry(pch, &ppp->channels, clist) { + i = 0; + list_for_each_entry(pch, &ppp->channels, clist) { navail += pch->avail = (pch->chan != NULL); pch->speed = pch->chan->speed; - if (pch->avail) { + if (pch->avail) { if (skb_queue_empty(&pch->file.xq) || - !pch->had_frag) { + !pch->had_frag) { if (pch->speed == 0) nzero++; else @@ -1331,60 +1331,60 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) ++nfree; ++totfree; } - if (!pch->had_frag && i < ppp->nxchan) - ppp->nxchan = i; + if (!pch->had_frag && i < ppp->nxchan) + ppp->nxchan = i; } ++i; } /* - * Don't start sending this packet unless at least half of - * the channels are free. This gives much better TCP - * performance if we have a lot of channels. + * Don't start sending this packet unless at least half of + * the channels are free. This gives much better TCP + * performance if we have a lot of channels. */ - if (nfree == 0 || nfree < navail / 2) - return 0; /* can't take now, leave it in xmit_pending */ + if (nfree == 0 || nfree < navail / 2) + return 0; /* can't take now, leave it in xmit_pending */ /* Do protocol field compression (XXX this should be optional) */ - p = skb->data; - len = skb->len; + p = skb->data; + len = skb->len; if (*p == 0) { ++p; --len; } totlen = len; - nbigger = len % nfree; + nbigger = len % nfree; - /* skip to the channel after the one we last used - and start at that one */ + /* skip to the channel after the one we last used + and start at that one */ list = &ppp->channels; - for (i = 0; i < ppp->nxchan; ++i) { + for (i = 0; i < ppp->nxchan; ++i) { list = list->next; - if (list == &ppp->channels) { - i = 0; + if (list == &ppp->channels) { + i = 0; break; } } - /* create a fragment for each channel */ + /* create a fragment for each channel */ bits = B; - while (len > 0) { + while (len > 0) { list = list->next; - if (list == &ppp->channels) { - i = 0; + if (list == &ppp->channels) { + i = 0; continue; } - pch = list_entry(list, struct channel, clist); + pch = list_entry(list, struct channel, clist); ++i; if (!pch->avail) continue; /* - * Skip this channel if it has a fragment pending already and - * we haven't given a fragment to all of the free channels. + * Skip this channel if it has a fragment pending already and + * we haven't given a fragment to all of the free channels. */ if (pch->avail == 1) { - if (nfree > 0) + if (nfree > 0) continue; } else { pch->avail = 1; @@ -1393,32 +1393,32 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* check the channel's mtu and whether it is still attached. */ spin_lock_bh(&pch->downl); if (pch->chan == NULL) { - /* can't use this channel, it's being deregistered */ + /* can't use this channel, it's being deregistered */ if (pch->speed == 0) nzero--; else - totspeed -= pch->speed; + totspeed -= pch->speed; spin_unlock_bh(&pch->downl); pch->avail = 0; totlen = len; totfree--; nfree--; - if (--navail == 0) + if (--navail == 0) break; continue; } /* *if the channel speed is not set divide - *the packet evenly among the free channels; + *the packet evenly among the free channels; *otherwise divide it according to the speed *of the channel we are going to transmit on */ flen = len; if (nfree > 0) { if (pch->speed == 0) { - flen = totlen/nfree ; + flen = totlen/nfree; if (nbigger > 0) { flen++; nbigger--; @@ -1436,8 +1436,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) } /* - *check if we are on the last channel or - *we exceded the lenght of the data to + *check if we are on the last channel or + *we exceded the lenght of the data to *fragment */ if ((nfree <= 0) || (flen > len)) @@ -1448,29 +1448,29 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) *above formula will be equal or less than zero. *Skip the channel in this case */ - if (flen <= 0) { + if (flen <= 0) { pch->avail = 2; spin_unlock_bh(&pch->downl); continue; } - mtu = pch->chan->mtu - hdrlen; - if (mtu < 4) - mtu = 4; + mtu = pch->chan->mtu - hdrlen; + if (mtu < 4) + mtu = 4; if (flen > mtu) flen = mtu; - if (flen == len) - bits |= E; - frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); + if (flen == len) + bits |= E; + frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); if (!frag) goto noskb; - q = skb_put(frag, flen + hdrlen); + q = skb_put(frag, flen + hdrlen); - /* make the MP header */ + /* make the MP header */ q[0] = PPP_MP >> 8; q[1] = PPP_MP; if (ppp->flags & SC_MP_XSHORTSEQ) { - q[2] = bits + ((ppp->nxseq >> 8) & 0xf); + q[2] = bits + ((ppp->nxseq >> 8) & 0xf); q[3] = ppp->nxseq; } else { q[2] = bits; @@ -1483,24 +1483,24 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* try to send it down the channel */ chan = pch->chan; - if (!skb_queue_empty(&pch->file.xq) || + if (!skb_queue_empty(&pch->file.xq) || !chan->ops->start_xmit(chan, frag)) skb_queue_tail(&pch->file.xq, frag); - pch->had_frag = 1; + pch->had_frag = 1; p += flen; - len -= flen; + len -= flen; ++ppp->nxseq; bits = 0; spin_unlock_bh(&pch->downl); } - ppp->nxchan = i; + ppp->nxchan = i; return 1; noskb: spin_unlock_bh(&pch->downl); if (ppp->debug & 1) - printk(KERN_ERR "PPP: no memory (fragment)\n"); + printk(KERN_ERR "PPP: no memory (fragment)\n"); ++ppp->dev->stats.tx_errors; ++ppp->nxseq; return 1; /* abandon the frame */ -- GitLab From 6d955180b2f9ccff444df06265160868cabb289a Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 18 Jan 2010 12:58:44 +0000 Subject: [PATCH 0922/3892] ipv4: allow warming up the ARP cache with request type gratuitous ARP If the per device ARP_ACCEPT option is enable, currently we only allow creating new ARP cache entries for response type gratuitous ARP. Allowing gratuitous ARP to create new ARP entries (not only to update existing ones) is useful when we want to avoid unnecessary delays for the first packet of a stream. This patch allows request type gratuitous ARP to create new ARP cache entries as well. This is useful when we want to populate the ARP cache entries for a large number of hosts on the same LAN. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 15 ++++++++++++--- net/ipv4/arp.c | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index c532884f4fec..2dc7a1d97686 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -852,9 +852,18 @@ arp_notify - BOOLEAN or hardware address changes. arp_accept - BOOLEAN - Define behavior when gratuitous arp replies are received: - 0 - drop gratuitous arp frames - 1 - accept gratuitous arp frames + Define behavior for gratuitous ARP frames who's IP is not + already present in the ARP table: + 0 - don't create new entries in the ARP table + 1 - create new entries in the ARP table + + Both replies and requests type gratuitous arp will trigger the + ARP table to be updated, if this setting is on. + + If the ARP table already contains the IP address of the + gratuitous arp frame, the arp table will be updated regardless + if this setting is on or off. + app_solicit - INTEGER The maximum number of probes to send to the user space ARP daemon diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 078709233bc4..1940b4df7699 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -907,7 +907,8 @@ static int arp_process(struct sk_buff *skb) devices (strip is candidate) */ if (n == NULL && - arp->ar_op == htons(ARPOP_REPLY) && + (arp->ar_op == htons(ARPOP_REPLY) || + (arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) && inet_addr_type(net, sip) == RTN_UNICAST) n = __neigh_lookup(&arp_tbl, &sip, dev, 1); } -- GitLab From 43a1839cb1e0e0ed08b8ace0adb3716865fd0c4c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 19:37:14 +0900 Subject: [PATCH 0923/3892] sh: SH7786 clock framework rewrite. This rewrites the SH7786 clock framework support completely. It's reworked to provide all of the DIV4 and MSTP function clocks. This brings it in line with the current clock framework code and lets us drop SH7786 from the list of CPUs that require legacy CPG handling. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 6 +- arch/sh/kernel/cpu/sh4a/clock-sh7786.c | 184 ++++++++++++------------- 2 files changed, 91 insertions(+), 99 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 8d0eabbf7460..352879c1b86b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -551,8 +551,7 @@ config SH_PCLK_FREQ CPU_SUBTYPE_SH7203 || \ CPU_SUBTYPE_SH7206 || \ CPU_SUBTYPE_SH7263 || \ - CPU_SUBTYPE_MXG || \ - CPU_SUBTYPE_SH7786 + CPU_SUBTYPE_MXG default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R default "66000000" if CPU_SUBTYPE_SH4_202 default "50000000" @@ -566,7 +565,8 @@ config SH_CLK_CPG config SH_CLK_CPG_LEGACY depends on SH_CLK_CPG - def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE + def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \ + !CPU_SUBTYPE_SH7786 config SH_CLK_MD int "CPU Mode Pin Setting" diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c index a0e8869071ac..494c636012bb 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c @@ -3,11 +3,7 @@ * * SH7786 support for the clock framework * - * Copyright (C) 2008, 2009 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on SH7785 - * Copyright (C) 2007 Paul Mundt + * Copyright (C) 2010 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -15,127 +11,123 @@ */ #include #include +#include +#include #include #include -#include - -static int ifc_divisors[] = { 1, 2, 4, 1 }; -static int sfc_divisors[] = { 1, 1, 4, 1 }; -static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1, - 24, 32, 1, 1, 1, 1, 1, 1 }; -static int mfc_divisors[] = { 1, 1, 4, 1 }; -static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1, - 24, 32, 1, 48, 1, 1, 1, 1 }; - -static void master_clk_init(struct clk *clk) -{ - clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f]; -} -static struct clk_ops sh7786_master_clk_ops = { - .init = master_clk_init, +/* + * Default rate for the root input clock, reset this with clk_set_rate() + * from the platform code. + */ +static struct clk extal_clk = { + .name = "extal", + .id = -1, + .rate = 33333333, }; -static unsigned long module_clk_recalc(struct clk *clk) +static unsigned long pll_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQMR1) & 0x000f); - return clk->parent->rate / pfc_divisors[idx]; -} + int multiplier; -static struct clk_ops sh7786_module_clk_ops = { - .recalc = module_clk_recalc, -}; + /* + * Clock modes 0, 1, and 2 use an x64 multiplier against PLL1, + * while modes 3, 4, and 5 use an x32. + */ + multiplier = (sh_mv.mv_mode_pins() & 0xf) < 3 ? 64 : 32; -static unsigned long bus_clk_recalc(struct clk *clk) -{ - int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f); - return clk->parent->rate / bfc_divisors[idx]; + return clk->parent->rate * multiplier; } -static struct clk_ops sh7786_bus_clk_ops = { - .recalc = bus_clk_recalc, +static struct clk_ops pll_clk_ops = { + .recalc = pll_recalc, }; -static unsigned long cpu_clk_recalc(struct clk *clk) -{ - int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003); - return clk->parent->rate / ifc_divisors[idx]; -} - -static struct clk_ops sh7786_cpu_clk_ops = { - .recalc = cpu_clk_recalc, +static struct clk pll_clk = { + .name = "pll_clk", + .id = -1, + .ops = &pll_clk_ops, + .parent = &extal_clk, + .flags = CLK_ENABLE_ON_INIT, }; -static struct clk_ops *sh7786_clk_ops[] = { - &sh7786_master_clk_ops, - &sh7786_module_clk_ops, - &sh7786_bus_clk_ops, - &sh7786_cpu_clk_ops, +static struct clk *clks[] = { + &extal_clk, + &pll_clk, }; -void __init arch_init_clk_ops(struct clk_ops **ops, int idx) -{ - if (idx < ARRAY_SIZE(sh7786_clk_ops)) - *ops = sh7786_clk_ops[idx]; -} - -static unsigned long shyway_clk_recalc(struct clk *clk) -{ - int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003); - return clk->parent->rate / sfc_divisors[idx]; -} +static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18, + 24, 32, 36, 48 }; -static struct clk_ops sh7786_shyway_clk_ops = { - .recalc = shyway_clk_recalc, +static struct clk_div_mult_table div4_table = { + .divisors = div2, + .nr_divisors = ARRAY_SIZE(div2), }; -static struct clk sh7786_shyway_clk = { - .name = "shyway_clk", - .flags = CLK_ENABLE_ON_INIT, - .ops = &sh7786_shyway_clk_ops, -}; +enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_DU, DIV4_P, DIV4_NR }; -static unsigned long ddr_clk_recalc(struct clk *clk) -{ - int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003); - return clk->parent->rate / mfc_divisors[idx]; -} +#define DIV4(_str, _bit, _mask, _flags) \ + SH_CLK_DIV4(_str, &pll_clk, FRQMR1, _bit, _mask, _flags) -static struct clk_ops sh7786_ddr_clk_ops = { - .recalc = ddr_clk_recalc, +struct clk div4_clks[DIV4_NR] = { + [DIV4_P] = DIV4("peripheral_clk", 0, 0x0b40, 0), + [DIV4_DU] = DIV4("du_clk", 4, 0x0010, 0), + [DIV4_DDR] = DIV4("ddr_clk", 12, 0x0002, CLK_ENABLE_ON_INIT), + [DIV4_B] = DIV4("bus_clk", 16, 0x0360, CLK_ENABLE_ON_INIT), + [DIV4_SH] = DIV4("shyway_clk", 20, 0x0002, CLK_ENABLE_ON_INIT), + [DIV4_I] = DIV4("cpu_clk", 28, 0x0006, CLK_ENABLE_ON_INIT), }; -static struct clk sh7786_ddr_clk = { - .name = "ddr_clk", - .flags = CLK_ENABLE_ON_INIT, - .ops = &sh7786_ddr_clk_ops, -}; - -/* - * Additional SH7786-specific on-chip clocks that aren't already part of the - * clock framework - */ -static struct clk *sh7786_onchip_clocks[] = { - &sh7786_shyway_clk, - &sh7786_ddr_clk, +#define MSTPCR0 0xffc40030 +#define MSTPCR1 0xffc40034 + +static struct clk mstp_clks[] = { + /* MSTPCR0 */ + SH_CLK_MSTP32("scif_fck", 5, &div4_clks[DIV4_P], MSTPCR0, 29, 0), + SH_CLK_MSTP32("scif_fck", 4, &div4_clks[DIV4_P], MSTPCR0, 28, 0), + SH_CLK_MSTP32("scif_fck", 3, &div4_clks[DIV4_P], MSTPCR0, 27, 0), + SH_CLK_MSTP32("scif_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 26, 0), + SH_CLK_MSTP32("scif_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 25, 0), + SH_CLK_MSTP32("scif_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 24, 0), + SH_CLK_MSTP32("ssi_fck", 3, &div4_clks[DIV4_P], MSTPCR0, 23, 0), + SH_CLK_MSTP32("ssi_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 22, 0), + SH_CLK_MSTP32("ssi_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 21, 0), + SH_CLK_MSTP32("ssi_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 20, 0), + SH_CLK_MSTP32("hac_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 17, 0), + SH_CLK_MSTP32("hac_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 16, 0), + SH_CLK_MSTP32("i2c_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 15, 0), + SH_CLK_MSTP32("i2c_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 14, 0), + SH_CLK_MSTP32("tmu9_11_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 11, 0), + SH_CLK_MSTP32("tmu678_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 10, 0), + SH_CLK_MSTP32("tmu345_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 9, 0), + SH_CLK_MSTP32("tmu012_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 8, 0), + SH_CLK_MSTP32("sdif_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 5, 0), + SH_CLK_MSTP32("sdif_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 4, 0), + SH_CLK_MSTP32("hspi_fck", -1, &div4_clks[DIV4_P], MSTPCR0, 2, 0), + + /* MSTPCR1 */ + SH_CLK_MSTP32("usb_fck", -1, NULL, MSTPCR1, 12, 0), + SH_CLK_MSTP32("pcie_fck", 2, NULL, MSTPCR1, 10, 0), + SH_CLK_MSTP32("pcie_fck", 1, NULL, MSTPCR1, 9, 0), + SH_CLK_MSTP32("pcie_fck", 0, NULL, MSTPCR1, 8, 0), + SH_CLK_MSTP32("dmac_11_6_fck", -1, NULL, MSTPCR1, 5, 0), + SH_CLK_MSTP32("dmac_5_0_fck", -1, NULL, MSTPCR1, 4, 0), + SH_CLK_MSTP32("du_fck", -1, NULL, MSTPCR1, 3, 0), + SH_CLK_MSTP32("ether_fck", -1, NULL, MSTPCR1, 2, 0), }; int __init arch_clk_init(void) { - struct clk *clk; int i, ret = 0; - cpg_clk_init(); - - clk = clk_get(NULL, "master_clk"); - for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) { - struct clk *clkp = sh7786_onchip_clocks[i]; - - clkp->parent = clk; - ret |= clk_register(clkp); - } + for (i = 0; i < ARRAY_SIZE(clks); i++) + ret |= clk_register(clks[i]); - clk_put(clk); + if (!ret) + ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks), + &div4_table); + if (!ret) + ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks)); return ret; } -- GitLab From c8098218271d19e7123d8b9137b9a4b87e5ffec0 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 19:38:36 +0900 Subject: [PATCH 0924/3892] sh: mach-sdk7786: Detect/configure/propagate EXTAL. This uses the mode pins exposed through the FPGA to work out whether we're driven from EXTAL or not and does the appropriate setup and propagation through the clock framework. This will also -EINVAL out for anyone adding in their own oscillators, forcing proper configuration with the clock framework instead of proceeding on with bogus clock values. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/setup.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index c38c6cc293b5..0e4b1c39742c 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -235,6 +236,27 @@ static int sdk7786_mode_pins(void) return pin_states; } +static int sdk7786_clk_init(void) +{ + struct clk *clk; + int ret; + + /* + * Only handle the EXTAL case, anyone interfacing a crystal + * resonator will need to provide their own input clock. + */ + if (test_mode_pin(MODE_PIN9)) + return -EINVAL; + + clk = clk_get(NULL, "extal"); + if (!clk || IS_ERR(clk)) + return PTR_ERR(clk); + ret = clk_set_rate(clk, 33333333); + clk_put(clk); + + return ret; +} + /* Initialize the board */ static void __init sdk7786_setup(char **cmdline_p) { @@ -248,5 +270,6 @@ static struct sh_machine_vector mv_sdk7786 __initmv = { .mv_name = "SDK7786", .mv_setup = sdk7786_setup, .mv_mode_pins = sdk7786_mode_pins, + .mv_clk_init = sdk7786_clk_init, .mv_init_irq = init_sdk7786_IRQ, }; -- GitLab From dea3cf1c3935047a5b0d21b21d26718e09135f97 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 20:09:28 +0900 Subject: [PATCH 0925/3892] sh: urquell: Handle EXTAL configuration here, too. urquell happens to use the same mode pins and EXTAL configuration as SDK7786, so just copy it over. Signed-off-by: Paul Mundt --- arch/sh/boards/board-urquell.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c index 268f09e46568..8aeac64810dc 100644 --- a/arch/sh/boards/board-urquell.c +++ b/arch/sh/boards/board-urquell.c @@ -2,7 +2,7 @@ * Renesas Technology Corp. SH7786 Urquell Support. * * Copyright (C) 2008 Kuninori Morimoto - * Copyright (C) 2009 Paul Mundt + * Copyright (C) 2009, 2010 Paul Mundt * * Based on board-sh7785lcr.c * Copyright (C) 2008 Yoshihiro Shimoda @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -175,6 +176,27 @@ static int urquell_mode_pins(void) return __raw_readw(UBOARDREG(MDSWMR)); } +static int urquell_clk_init(void) +{ + struct clk *clk; + int ret; + + /* + * Only handle the EXTAL case, anyone interfacing a crystal + * resonator will need to provide their own input clock. + */ + if (test_mode_pin(MODE_PIN9)) + return -EINVAL; + + clk = clk_get(NULL, "extal"); + if (!clk || IS_ERR(clk)) + return PTR_ERR(clk); + ret = clk_set_rate(clk, 33333333); + clk_put(clk); + + return ret; +} + /* Initialize the board */ static void __init urquell_setup(char **cmdline_p) { @@ -191,4 +213,5 @@ static struct sh_machine_vector mv_urquell __initmv = { .mv_setup = urquell_setup, .mv_init_irq = urquell_init_irq, .mv_mode_pins = urquell_mode_pins, + .mv_clk_init = urquell_clk_init, }; -- GitLab From 14965f16b4bb8f3e51b09c1d8f61b8e98f9d12db Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jan 2010 20:10:33 +0900 Subject: [PATCH 0926/3892] sh: Fix up sdk7780 and urquell builds. These two got broken in the heartbeat private data conversion, fix them up. Signed-off-by: Paul Mundt --- arch/sh/boards/board-urquell.c | 2 +- arch/sh/boards/mach-sdk7780/setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c index 8aeac64810dc..a9bd6e3ee10b 100644 --- a/arch/sh/boards/board-urquell.c +++ b/arch/sh/boards/board-urquell.c @@ -60,7 +60,7 @@ static struct resource heartbeat_resource = { static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .num_resources = 1 + .num_resources = 1, .resource = &heartbeat_resource, }; diff --git a/arch/sh/boards/mach-sdk7780/setup.c b/arch/sh/boards/mach-sdk7780/setup.c index 1d04657e992d..b887373a2599 100644 --- a/arch/sh/boards/mach-sdk7780/setup.c +++ b/arch/sh/boards/mach-sdk7780/setup.c @@ -30,7 +30,7 @@ static struct resource heartbeat_resource = { static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, - .num_resources = 1 + .num_resources = 1, .resource = &heartbeat_resource, }; -- GitLab From 31c3af503eb75488aafb7a3d292b9e00962f2cee Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Jan 2010 11:14:31 +0000 Subject: [PATCH 0927/3892] sh: support SIU sourcing from external clock on sh7722 Implement .set_rate() for all SH "div4 clocks," .enable(), .disable(), and .set_parent() for those, that support them. This allows, among other uses, reparenting of SIU clocks to the external source, and enabling and disabling of the IrDA clock on sh7722. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/sh/include/asm/clock.h | 4 ++ arch/sh/kernel/cpu/clock-cpg.c | 94 +++++++++++++++++++++++++- arch/sh/kernel/cpu/sh4a/clock-sh7722.c | 25 +++++-- 3 files changed, 116 insertions(+), 7 deletions(-) diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h index 9fe7d7f8af40..501d0b076283 100644 --- a/arch/sh/include/asm/clock.h +++ b/arch/sh/include/asm/clock.h @@ -148,6 +148,10 @@ int sh_clk_mstp32_register(struct clk *clks, int nr); int sh_clk_div4_register(struct clk *clks, int nr, struct clk_div_mult_table *table); +int sh_clk_div4_enable_register(struct clk *clks, int nr, + struct clk_div_mult_table *table); +int sh_clk_div4_reparent_register(struct clk *clks, int nr, + struct clk_div_mult_table *table); #define SH_CLK_DIV6(_name, _parent, _reg, _flags) \ { \ diff --git a/arch/sh/kernel/cpu/clock-cpg.c b/arch/sh/kernel/cpu/clock-cpg.c index 6dfe2cced3fc..2827abb5d2ab 100644 --- a/arch/sh/kernel/cpu/clock-cpg.c +++ b/arch/sh/kernel/cpu/clock-cpg.c @@ -160,13 +160,81 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk) return clk->freq_table[idx].frequency; } +static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_div_mult_table *table = clk->priv; + u32 value; + int ret; + + if (!strcmp("pll_clk", parent->name)) + value = __raw_readl(clk->enable_reg) & ~(1 << 7); + else + value = __raw_readl(clk->enable_reg) | (1 << 7); + + ret = clk_reparent(clk, parent); + if (ret < 0) + return ret; + + __raw_writel(value, clk->enable_reg); + + /* Rebiuld the frequency table */ + clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, + table, &clk->arch_flags); + + return 0; +} + +static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id) +{ + unsigned long value; + int idx = clk_rate_table_find(clk, clk->freq_table, rate); + if (idx < 0) + return idx; + + value = __raw_readl(clk->enable_reg); + value &= ~0xf; + value |= idx; + __raw_writel(value, clk->enable_reg); + + return 0; +} + +static int sh_clk_div4_enable(struct clk *clk) +{ + __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg); + return 0; +} + +static void sh_clk_div4_disable(struct clk *clk) +{ + __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg); +} + static struct clk_ops sh_clk_div4_clk_ops = { .recalc = sh_clk_div4_recalc, + .set_rate = sh_clk_div4_set_rate, .round_rate = sh_clk_div_round_rate, }; -int __init sh_clk_div4_register(struct clk *clks, int nr, - struct clk_div_mult_table *table) +static struct clk_ops sh_clk_div4_enable_clk_ops = { + .recalc = sh_clk_div4_recalc, + .set_rate = sh_clk_div4_set_rate, + .round_rate = sh_clk_div_round_rate, + .enable = sh_clk_div4_enable, + .disable = sh_clk_div4_disable, +}; + +static struct clk_ops sh_clk_div4_reparent_clk_ops = { + .recalc = sh_clk_div4_recalc, + .set_rate = sh_clk_div4_set_rate, + .round_rate = sh_clk_div_round_rate, + .enable = sh_clk_div4_enable, + .disable = sh_clk_div4_disable, + .set_parent = sh_clk_div4_set_parent, +}; + +static int __init sh_clk_div4_register_ops(struct clk *clks, int nr, + struct clk_div_mult_table *table, struct clk_ops *ops) { struct clk *clkp; void *freq_table; @@ -185,7 +253,7 @@ int __init sh_clk_div4_register(struct clk *clks, int nr, for (k = 0; !ret && (k < nr); k++) { clkp = clks + k; - clkp->ops = &sh_clk_div4_clk_ops; + clkp->ops = ops; clkp->id = -1; clkp->priv = table; @@ -198,6 +266,26 @@ int __init sh_clk_div4_register(struct clk *clks, int nr, return ret; } +int __init sh_clk_div4_register(struct clk *clks, int nr, + struct clk_div_mult_table *table) +{ + return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops); +} + +int __init sh_clk_div4_enable_register(struct clk *clks, int nr, + struct clk_div_mult_table *table) +{ + return sh_clk_div4_register_ops(clks, nr, table, + &sh_clk_div4_enable_clk_ops); +} + +int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, + struct clk_div_mult_table *table) +{ + return sh_clk_div4_register_ops(clks, nr, table, + &sh_clk_div4_reparent_clk_ops); +} + #ifdef CONFIG_SH_CLK_CPG_LEGACY static struct clk master_clk = { .name = "master_clk", diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index ea38b554dc05..860ee2bf4bf0 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -117,12 +117,11 @@ static struct clk_div_mult_table div4_table = { .nr_multipliers = ARRAY_SIZE(multipliers), }; -enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, - DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR }; - #define DIV4(_str, _reg, _bit, _mask, _flags) \ SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags) +enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR }; + struct clk div4_clks[DIV4_NR] = { [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT), [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT), @@ -130,9 +129,19 @@ struct clk div4_clks[DIV4_NR] = { [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT), [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT), [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0), +}; + +enum { DIV4_IRDA, DIV4_ENABLE_NR }; + +struct clk div4_enable_clks[DIV4_ENABLE_NR] = { + [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0), +}; + +enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR }; + +struct clk div4_reparent_clks[DIV4_REPARENT_NR] = { [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0), [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0), - [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0), }; struct clk div6_clks[] = { @@ -188,6 +197,14 @@ int __init arch_clk_init(void) if (!ret) ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + if (!ret) + ret = sh_clk_div4_enable_register(div4_enable_clks, + DIV4_ENABLE_NR, &div4_table); + + if (!ret) + ret = sh_clk_div4_reparent_register(div4_reparent_clks, + DIV4_REPARENT_NR, &div4_table); + if (!ret) ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); -- GitLab From a5b5a0649a84db1a0cc1e19997572be8ef3b8c81 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 19 Jan 2010 11:15:45 +0200 Subject: [PATCH 0928/3892] ASoC: tlv320dac33: Correct the prefill number of samples Set the prefill number of samples as the same as the lower threshold in mode7. In this way the codec will read the same amount of data on startup and during the running playback. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 2df9c20b7d52..65683aa3920c 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -559,7 +559,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) break; case DAC33_FIFO_MODE7: dac33_write16(codec, DAC33_PREFILL_MSB, - DAC33_THRREG(20)); + DAC33_THRREG(10)); break; default: dev_warn(codec->dev, "Unhandled FIFO mode: %d\n", -- GitLab From 84740ac19a0aeb87d1dc21e9d7d517f11bd49748 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Jan 2010 08:39:05 +0100 Subject: [PATCH 0929/3892] ASoC: fix compile breakage - add a missing header include Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ca24e7f7a3f5..061f16d4c878 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -16,6 +16,8 @@ #include +#include + struct snd_pcm_substream; /* -- GitLab From 70911b861bfbba1851cbb3497635030f34703c7a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 02:45:05 +0900 Subject: [PATCH 0930/3892] sh: Shut up noisy IOREMAP_FIXED=n build. The ioremap_fixed() stub neglected to provide a return value, resulting in a fairly noisy build. Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 4bad72a1b39e..e4f563f472eb 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -245,10 +245,11 @@ extern int iounmap_fixed(void __iomem *); extern void ioremap_fixed_init(void); #else static inline void __iomem * -ioremap_fixed(resource_size t phys_addr, unsigned long offset, +ioremap_fixed(resource_size_t phys_addr, unsigned long offset, unsigned long size, pgprot_t prot) { BUG(); + return NULL; } static inline void ioremap_fixed_init(void) { } -- GitLab From 50dd3145a58b5cef03a95c1b98765bcc847a72d0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 19 Jan 2010 13:52:28 +0000 Subject: [PATCH 0931/3892] sh: update PFC to allow any enum in MARK lists This patch updates the PFC code with some clarifying comments together with a functional change. The change allows function type of GPIO to select any type of enum in their MARK lists. Without this patch only function type of enums are allowed in MARK lists. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/pfc.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c index 082604edc4c2..cf0303acab8e 100644 --- a/drivers/sh/pfc.c +++ b/drivers/sh/pfc.c @@ -337,12 +337,39 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, if (!enum_id) break; + /* first check if this is a function enum */ in_range = enum_in_range(enum_id, &gpioc->function); - if (!in_range && range) { - in_range = enum_in_range(enum_id, range); - - if (in_range && enum_id == range->force) - continue; + if (!in_range) { + /* not a function enum */ + if (range) { + /* + * other range exists, so this pin is + * a regular GPIO pin that now is being + * bound to a specific direction. + * + * for this case we only allow function enums + * and the enums that match the other range. + */ + in_range = enum_in_range(enum_id, range); + + /* + * special case pass through for fixed + * input-only or output-only pins without + * function enum register association. + */ + if (in_range && enum_id == range->force) + continue; + } else { + /* + * no other range exists, so this pin + * must then be of the function type. + * + * allow function type pins to select + * any combination of function/in/out + * in their MARK lists. + */ + in_range = 1; + } } if (!in_range) -- GitLab From bdc27300f5718626a3817e6478e339f6cca6b994 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 03:38:56 +0900 Subject: [PATCH 0932/3892] sh: Handle SH-4 FPU variants with broken CVR values. Usually we can look to the CVR to work out whether we have an FPU or not. Unfortunately not all parts comply with this, so just set the flag manually for all SH-4 parts and clear it on the only SH-4 that doesn't have one (SH4-501). Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4/probe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 21371f8cf010..cc02b3145cca 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -71,11 +71,11 @@ int __init detect_cpu_and_cache_system(void) boot_cpu_data.dcache.ways = 4; } else { /* And some SH-4 defaults.. */ - boot_cpu_data.flags |= CPU_HAS_PTEA; + boot_cpu_data.flags |= CPU_HAS_PTEA | CPU_HAS_FPU; boot_cpu_data.family = CPU_FAMILY_SH4; } - /* FPU detection works for everyone */ + /* FPU detection works for almost everyone */ if ((cvr & 0x20000000)) boot_cpu_data.flags |= CPU_HAS_FPU; @@ -161,6 +161,7 @@ int __init detect_cpu_and_cache_system(void) break; case 0x700: boot_cpu_data.type = CPU_SH4_501; + boot_cpu_data.flags &= ~CPU_HAS_FPU; boot_cpu_data.icache.ways = 2; boot_cpu_data.dcache.ways = 2; break; -- GitLab From 861a57cd01f97e984320b5aeeee019ede48c714d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Jan 2010 04:08:26 +0100 Subject: [PATCH 0933/3892] mac80211: fix WMM AC default for non-QoS data frames The WMM AC selection added to the monitor mode selection function accidentally assigns non-QoS data frames to the same AC as mgmt frames (VO). This is not serious, but should be fixed anyway. This patch assigns them to the BE AC instead. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/iface.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index edf21cebeee8..09fff4662e80 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -695,10 +695,14 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); - if (!ieee80211_is_data_qos(hdr->frame_control)) { + if (!ieee80211_is_data(hdr->frame_control)) { skb->priority = 7; return ieee802_1d_to_ac[skb->priority]; } + if (!ieee80211_is_data_qos(hdr->frame_control)) { + skb->priority = 0; + return ieee802_1d_to_ac[skb->priority]; + } p = ieee80211_get_qos_ctl(hdr); skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; -- GitLab From 9ed333e0298c8f12cf7f3b4aec4258e81ef588a0 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:33 -0800 Subject: [PATCH 0934/3892] iwlwifi: fix clear statistics counter command When receive reply statistics command with "clear" mask, just reset the accumulated statistics counters, but not the current statistics counters, so the accumulated statistics counter can provide the correct information. Signed-off-by: Wey-Yi Guy Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f36b6e79f5e..10db97327452 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -638,8 +638,6 @@ void iwl_reply_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = rxb_addr(rxb); if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { - memset(&priv->statistics, 0, - sizeof(struct iwl_notif_statistics)); #ifdef CONFIG_IWLWIFI_DEBUG memset(&priv->accum_statistics, 0, sizeof(struct iwl_notif_statistics)); -- GitLab From e3ef2164386a13a37714ec033e30811d052c7999 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:34 -0800 Subject: [PATCH 0935/3892] iwlwifi: format and show statistics counter from uCode To help debug uCode related problem, adding "delta" and "max" information in debugfs statistics counters display. Those information show the delta between two statistics report from uCode, user can monitor the counters for any "un-normal" behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: Jay Sternberg Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 850 +++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 + drivers/net/wireless/iwlwifi/iwl-rx.c | 19 +- 3 files changed, 545 insertions(+), 326 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 4a2ac9311ba8..2264cbd95a00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1081,6 +1081,12 @@ static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, return p; } +static const char ucode_stats_header[] = + "%-32s current acumulative delta max\n"; +static const char ucode_stats_short_format[] = + " %-30s %10u\n"; +static const char ucode_stats_format[] = + " %-30s %10u %10u %10u %10u\n"; static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, @@ -1089,14 +1095,15 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 20 + - sizeof(struct statistics_rx_non_phy) * 20 + - sizeof(struct statistics_rx_ht_phy) * 20 + 400; + int bufsz = sizeof(struct statistics_rx_phy) * 40 + + sizeof(struct statistics_rx_non_phy) * 40 + + sizeof(struct statistics_rx_ht_phy) * 40 + 400; ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm; - struct statistics_rx_phy *cck, *accum_cck; + struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; + struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_ht_phy *ht, *accum_ht; + struct statistics_rx_non_phy *delta_general, *max_general; + struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1129,267 +1136,401 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, accum_cck = &priv->accum_statistics.rx.cck; accum_general = &priv->accum_statistics.rx.general; accum_ht = &priv->accum_statistics.rx.ofdm_ht; + delta_ofdm = &priv->delta_statistics.rx.ofdm; + delta_cck = &priv->delta_statistics.rx.cck; + delta_general = &priv->delta_statistics.rx.general; + delta_ht = &priv->delta_statistics.rx.ofdm_ht; + max_ofdm = &priv->max_delta.rx.ofdm; + max_cck = &priv->max_delta.rx.cck; + max_general = &priv->max_delta.rx.general; + max_ht = &priv->max_delta.rx.ofdm_ht; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - "overrun_err:\t\t%u\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_Rx - OFDM:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "ina_cnt:", le32_to_cpu(ofdm->ina_cnt), + accum_ofdm->ina_cnt, + delta_ofdm->ina_cnt, max_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_cnt:", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, + delta_ofdm->fina_cnt, max_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "plcp_err:", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, + delta_ofdm->plcp_err, max_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_err:", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, + delta_ofdm->crc32_err, max_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "overrun_err:", le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - "early_overrun_err:\t%u\t\t\t%u\n", + accum_ofdm->overrun_err, + delta_ofdm->overrun_err, max_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "early_overrun_err:", le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + accum_ofdm->early_overrun_err, + delta_ofdm->early_overrun_err, + max_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_good:", le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - "false_alarm_cnt:\t%u\t\t\t%u\n", + accum_ofdm->crc32_good, + delta_ofdm->crc32_good, max_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "false_alarm_cnt:", le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "fina_sync_err_cnt:\t%u\t\t\t%u\n", + accum_ofdm->false_alarm_cnt, + delta_ofdm->false_alarm_cnt, + max_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_sync_err_cnt:", le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sfd_timeout:\t\t%u\t\t\t%u\n", + accum_ofdm->fina_sync_err_cnt, + delta_ofdm->fina_sync_err_cnt, + max_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sfd_timeout:", le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "fina_timeout:\t\t%u\t\t\t%u\n", + accum_ofdm->sfd_timeout, + delta_ofdm->sfd_timeout, + max_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_timeout:", le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "unresponded_rts:\t%u\t\t\t%u\n", + accum_ofdm->fina_timeout, + delta_ofdm->fina_timeout, + max_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "unresponded_rts:", le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + accum_ofdm->unresponded_rts, + delta_ofdm->unresponded_rts, + max_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "rxe_frame_lmt_ovrun:", le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_ack_cnt:\t\t%u\t\t\t%u\n", + accum_ofdm->rxe_frame_limit_overrun, + delta_ofdm->rxe_frame_limit_overrun, + max_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_ack_cnt:", le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_cts_cnt:\t\t%u\t\t\t%u\n", + accum_ofdm->sent_ack_cnt, + delta_ofdm->sent_ack_cnt, + max_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_cts_cnt:", le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + accum_ofdm->sent_cts_cnt, + delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_ba_rsp_cnt:", le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "dsp_self_kill:\t\t%u\t\t\t%u\n", + accum_ofdm->sent_ba_rsp_cnt, + delta_ofdm->sent_ba_rsp_cnt, + max_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "dsp_self_kill:", le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - "mh_format_err:\t\t%u\t\t\t%u\n", + accum_ofdm->dsp_self_kill, + delta_ofdm->dsp_self_kill, + max_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "mh_format_err:", le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + accum_ofdm->mh_format_err, + delta_ofdm->mh_format_err, + max_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "re_acq_main_rssi_sum:", le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - "overrun_err:\t\t%u\t\t\t%u\n", + accum_ofdm->re_acq_main_rssi_sum, + delta_ofdm->re_acq_main_rssi_sum, + max_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_Rx - CCK:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "ina_cnt:", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, + delta_cck->ina_cnt, max_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_cnt:", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, + delta_cck->fina_cnt, max_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "plcp_err:", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, + delta_cck->plcp_err, max_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_err:", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, + delta_cck->crc32_err, max_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "overrun_err:", le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - "early_overrun_err:\t%u\t\t\t%u\n", + accum_cck->overrun_err, + delta_cck->overrun_err, max_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "early_overrun_err:", le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - "false_alarm_cnt:\t%u\t\t\t%u\n", + accum_cck->early_overrun_err, + delta_cck->early_overrun_err, + max_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_good:", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, + delta_cck->crc32_good, + max_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "false_alarm_cnt:", le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "fina_sync_err_cnt:\t%u\t\t\t%u\n", + accum_cck->false_alarm_cnt, + delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_sync_err_cnt:", le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sfd_timeout:\t\t%u\t\t\t%u\n", + accum_cck->fina_sync_err_cnt, + delta_cck->fina_sync_err_cnt, + max_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sfd_timeout:", le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "fina_timeout:\t\t%u\t\t\t%u\n", + accum_cck->sfd_timeout, + delta_cck->sfd_timeout, max_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "fina_timeout:", le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "unresponded_rts:\t%u\t\t\t%u\n", + accum_cck->fina_timeout, + delta_cck->fina_timeout, max_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "unresponded_rts:", le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + accum_cck->unresponded_rts, + delta_cck->unresponded_rts, + max_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "rxe_frame_lmt_ovrun:", le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_ack_cnt:\t\t%u\t\t\t%u\n", + accum_cck->rxe_frame_limit_overrun, + delta_cck->rxe_frame_limit_overrun, + max_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_ack_cnt:", le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_cts_cnt:\t\t%u\t\t\t%u\n", + accum_cck->sent_ack_cnt, + delta_cck->sent_ack_cnt, + max_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_cts_cnt:", le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + accum_cck->sent_cts_cnt, + delta_cck->sent_cts_cnt, + max_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sent_ba_rsp_cnt:", le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "dsp_self_kill:\t\t%u\t\t\t%u\n", + accum_cck->sent_ba_rsp_cnt, + delta_cck->sent_ba_rsp_cnt, + max_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "dsp_self_kill:", le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - "mh_format_err:\t\t%u\t\t\t%u\n", + accum_cck->dsp_self_kill, + delta_cck->dsp_self_kill, + max_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "mh_format_err:", le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + accum_cck->mh_format_err, + delta_cck->mh_format_err, max_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "re_acq_main_rssi_sum:", le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n", + accum_cck->re_acq_main_rssi_sum, + delta_cck->re_acq_main_rssi_sum, + max_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_Rx - GENERAL:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "bogus_cts:", le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n", + accum_general->bogus_cts, + delta_general->bogus_cts, max_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "bogus_ack:", le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - "non_bssid_frames:\t%u\t\t\t%u\n", + accum_general->bogus_ack, + delta_general->bogus_ack, max_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "non_bssid_frames:", le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - "filtered_frames:\t%u\t\t\t%u\n", + accum_general->non_bssid_frames, + delta_general->non_bssid_frames, + max_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "filtered_frames:", le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - "non_channel_beacons:\t%u\t\t\t%u\n", + accum_general->filtered_frames, + delta_general->filtered_frames, + max_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "non_channel_beacons:", le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - "channel_beacons:\t%u\t\t\t%u\n", + accum_general->non_channel_beacons, + delta_general->non_channel_beacons, + max_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "channel_beacons:", le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - "num_missed_bcon:\t%u\t\t\t%u\n", + accum_general->channel_beacons, + delta_general->channel_beacons, + max_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "num_missed_bcon:", le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, - "adc_rx_saturation_time:\t%u\t\t\t%u\n", + accum_general->num_missed_bcon, + delta_general->num_missed_bcon, + max_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "adc_rx_saturation_time:", le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, - "ina_detect_search_tm:\t%u\t\t\t%u\n", + accum_general->adc_rx_saturation_time, + delta_general->adc_rx_saturation_time, + max_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "ina_detect_search_tm:", le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_silence_rssi_a:\t%u\t\t\t%u\n", + accum_general->ina_detection_search_time, + delta_general->ina_detection_search_time, + max_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_silence_rssi_a:", le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_silence_rssi_b:\t%u\t\t\t%u\n", + accum_general->beacon_silence_rssi_a, + delta_general->beacon_silence_rssi_a, + max_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_silence_rssi_b:", le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_silence_rssi_c:\t%u\t\t\t%u\n", + accum_general->beacon_silence_rssi_b, + delta_general->beacon_silence_rssi_b, + max_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_silence_rssi_c:", le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - "interference_data_flag:\t%u\t\t\t%u\n", + accum_general->beacon_silence_rssi_c, + delta_general->beacon_silence_rssi_c, + max_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "interference_data_flag:", le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, - "channel_load:\t\t%u\t\t\t%u\n", + accum_general->interference_data_flag, + delta_general->interference_data_flag, + max_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "channel_load:", le32_to_cpu(general->channel_load), - accum_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, - "dsp_false_alarms:\t%u\t\t\t%u\n", + accum_general->channel_load, + delta_general->channel_load, + max_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "dsp_false_alarms:", le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_rssi_a:\t\t%u\t\t\t%u\n", + accum_general->dsp_false_alarms, + delta_general->dsp_false_alarms, + max_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_rssi_a:", le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_rssi_b:\t\t%u\t\t\t%u\n", + accum_general->beacon_rssi_a, + delta_general->beacon_rssi_a, + max_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_rssi_b:", le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_rssi_c:\t\t%u\t\t\t%u\n", + accum_general->beacon_rssi_b, + delta_general->beacon_rssi_b, + max_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_rssi_c:", le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_energy_a:\t%u\t\t\t%u\n", + accum_general->beacon_rssi_c, + delta_general->beacon_rssi_c, + max_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_energy_a:", le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_energy_b:\t%u\t\t\t%u\n", + accum_general->beacon_energy_a, + delta_general->beacon_energy_a, + max_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_energy_b:", le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, - "beacon_energy_c:\t%u\t\t\t%u\n", + accum_general->beacon_energy_b, + delta_general->beacon_energy_b, + max_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "beacon_energy_c:", le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c); + accum_general->beacon_energy_c, + delta_general->beacon_energy_c, + max_general->beacon_energy_c); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - "overrun_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - "early_overrun_err:\t%u\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_Rx - OFDM_HT:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "plcp_err:", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, + delta_ht->plcp_err, max_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "overrun_err:", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, + delta_ht->overrun_err, max_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "early_overrun_err:", le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - "mh_format_err:\t\t%u\t\t\t%u\n", + accum_ht->early_overrun_err, + delta_ht->early_overrun_err, + max_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_good:", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, + delta_ht->crc32_good, max_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "crc32_err:", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, + delta_ht->crc32_err, max_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "mh_format_err:", le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - "agg_crc32_good:\t\t%u\t\t\t%u\n", + accum_ht->mh_format_err, + delta_ht->mh_format_err, max_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg_crc32_good:", le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - "agg_mpdu_cnt:\t\t%u\t\t\t%u\n", + accum_ht->agg_crc32_good, + delta_ht->agg_crc32_good, max_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg_mpdu_cnt:", le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n", + accum_ht->agg_mpdu_cnt, + delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg_cnt:", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, + delta_ht->agg_cnt, max_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "unsupport_mcs:", le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs); + accum_ht->unsupport_mcs, + delta_ht->unsupport_mcs, max_ht->unsupport_mcs); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1403,9 +1544,9 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; - int bufsz = (sizeof(struct statistics_tx) * 24) + 250; + int bufsz = (sizeof(struct statistics_tx) * 48) + 250; ssize_t ret; - struct statistics_tx *tx, *accum_tx; + struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1432,106 +1573,148 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, */ tx = &priv->statistics.tx; accum_tx = &priv->accum_statistics.tx; + delta_tx = &priv->delta_statistics.tx; + max_tx = &priv->max_delta.tx; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_Tx:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "preamble:", le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "rx_detected_cnt:\t\t%u\t\t\t%u\n", + accum_tx->preamble_cnt, + delta_tx->preamble_cnt, max_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "rx_detected_cnt:", le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n", + accum_tx->rx_detected_cnt, + delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "bt_prio_defer_cnt:", le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n", + accum_tx->bt_prio_defer_cnt, + delta_tx->bt_prio_defer_cnt, + max_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "bt_prio_kill_cnt:", le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "few_bytes_cnt:\t\t\t%u\t\t\t%u\n", + accum_tx->bt_prio_kill_cnt, + delta_tx->bt_prio_kill_cnt, + max_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "few_bytes_cnt:", le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "cts_timeout:\t\t\t%u\t\t\t%u\n", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "ack_timeout:\t\t\t%u\t\t\t%u\n", + accum_tx->few_bytes_cnt, + delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "cts_timeout:", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, + delta_tx->cts_timeout, max_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "ack_timeout:", le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "expected_ack_cnt:\t\t%u\t\t\t%u\n", + accum_tx->ack_timeout, + delta_tx->ack_timeout, max_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "expected_ack_cnt:", le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "actual_ack_cnt:\t\t\t%u\t\t\t%u\n", + accum_tx->expected_ack_cnt, + delta_tx->expected_ack_cnt, + max_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "actual_ack_cnt:", le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n", + accum_tx->actual_ack_cnt, + delta_tx->actual_ack_cnt, + max_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "dump_msdu_cnt:", le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "abort_nxt_frame_mismatch:" - "\t%u\t\t\t%u\n", + accum_tx->dump_msdu_cnt, + delta_tx->dump_msdu_cnt, + max_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "abort_nxt_frame_mismatch:", le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "abort_missing_nxt_frame:" - "\t%u\t\t\t%u\n", + accum_tx->burst_abort_next_frame_mismatch_cnt, + delta_tx->burst_abort_next_frame_mismatch_cnt, + max_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "abort_missing_nxt_frame:", le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "cts_timeout_collision:\t\t%u\t\t\t%u\n", + accum_tx->burst_abort_missing_next_frame_cnt, + delta_tx->burst_abort_missing_next_frame_cnt, + max_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "cts_timeout_collision:", le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - "ack_ba_timeout_collision:\t%u\t\t\t%u\n", + accum_tx->cts_timeout_collision, + delta_tx->cts_timeout_collision, + max_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "ack_ba_timeout_collision:", le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - "agg ba_timeout:\t\t\t%u\t\t\t%u\n", + accum_tx->ack_or_ba_timeout_collision, + delta_tx->ack_or_ba_timeout_collision, + max_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg ba_timeout:", le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - "agg ba_resched_frames:\t\t%u\t\t\t%u\n", + accum_tx->agg.ba_timeout, + delta_tx->agg.ba_timeout, + max_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg ba_resched_frames:", le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_agg_frame:\t%u\t\t\t%u\n", + accum_tx->agg.ba_reschedule_frames, + delta_tx->agg.ba_reschedule_frames, + max_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg scd_query_agg_frame:", le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_no_agg:\t\t%u\t\t\t%u\n", + accum_tx->agg.scd_query_agg_frame_cnt, + delta_tx->agg.scd_query_agg_frame_cnt, + max_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg scd_query_no_agg:", le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_agg:\t\t%u\t\t\t%u\n", + accum_tx->agg.scd_query_no_agg, + delta_tx->agg.scd_query_no_agg, + max_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg scd_query_agg:", le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_mismatch:\t\t%u\t\t\t%u\n", + accum_tx->agg.scd_query_agg, + delta_tx->agg.scd_query_agg, + max_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg scd_query_mismatch:", le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, - "agg frame_not_ready:\t\t%u\t\t\t%u\n", + accum_tx->agg.scd_query_mismatch, + delta_tx->agg.scd_query_mismatch, + max_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg frame_not_ready:", le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, - "agg underrun:\t\t\t%u\t\t\t%u\n", + accum_tx->agg.frame_not_ready, + delta_tx->agg.frame_not_ready, + max_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg underrun:", le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, - "agg bt_prio_kill:\t\t%u\t\t\t%u\n", + accum_tx->agg.underrun, + delta_tx->agg.underrun, max_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg bt_prio_kill:", le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, - "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n", + accum_tx->agg.bt_prio_kill, + delta_tx->agg.bt_prio_kill, + max_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "agg rx_ba_rsp_cnt:", le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt); + accum_tx->agg.rx_ba_rsp_cnt, + delta_tx->agg.rx_ba_rsp_cnt, + max_tx->agg.rx_ba_rsp_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1545,11 +1728,12 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; - int bufsz = sizeof(struct statistics_general) * 4 + 250; + int bufsz = sizeof(struct statistics_general) * 8 + 250; ssize_t ret; struct statistics_general *general, *accum_general; - struct statistics_dbg *dbg, *accum_dbg; - struct statistics_div *div, *accum_div; + struct statistics_general *delta_general, *max_general; + struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; + struct statistics_div *div, *accum_div, *delta_div, *max_div; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1578,52 +1762,72 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, dbg = &priv->statistics.general.dbg; div = &priv->statistics.general.div; accum_general = &priv->accum_statistics.general; + delta_general = &priv->delta_statistics.general; + max_general = &priv->max_delta.general; accum_dbg = &priv->accum_statistics.general.dbg; + delta_dbg = &priv->delta_statistics.general.dbg; + max_dbg = &priv->max_delta.general.dbg; accum_div = &priv->accum_statistics.general.div; + delta_div = &priv->delta_statistics.general.div; + max_div = &priv->max_delta.general.div; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, + "Statistics_General:"); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format, + "temperature:", le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format, + "temperature_m:", le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, - "burst_check:\t\t\t%u\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "burst_check:", le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - "burst_count:\t\t\t%u\t\t\t%u\n", + accum_dbg->burst_check, + delta_dbg->burst_check, max_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "burst_count:", le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - "sleep_time:\t\t\t%u\t\t\t%u\n", + accum_dbg->burst_count, + delta_dbg->burst_count, max_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "sleep_time:", le32_to_cpu(general->sleep_time), - accum_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - "slots_out:\t\t\t%u\t\t\t%u\n", + accum_general->sleep_time, + delta_general->sleep_time, max_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "slots_out:", le32_to_cpu(general->slots_out), - accum_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - "slots_idle:\t\t\t%u\t\t\t%u\n", + accum_general->slots_out, + delta_general->slots_out, max_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "slots_idle:", le32_to_cpu(general->slots_idle), - accum_general->slots_idle); + accum_general->slots_idle, + delta_general->slots_idle, max_general->slots_idle); pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n", le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - "exec_time:\t\t\t%u\t\t\t%u\n", - le32_to_cpu(div->exec_time), accum_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - "probe_time:\t\t\t%u\t\t\t%u\n", - le32_to_cpu(div->probe_time), accum_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, - "rx_enable_counter:\t\t%u\t\t\t%u\n", + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "tx_on_a:", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, + delta_div->tx_on_a, max_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "tx_on_b:", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, + delta_div->tx_on_b, max_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "exec_time:", + le32_to_cpu(div->exec_time), accum_div->exec_time, + delta_div->exec_time, max_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "probe_time:", + le32_to_cpu(div->probe_time), accum_div->probe_time, + delta_div->probe_time, max_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "rx_enable_counter:", le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter); + accum_general->rx_enable_counter, + delta_general->rx_enable_counter, + max_general->rx_enable_counter); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 70f0e79c8e4a..63e45cd3f634 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1162,6 +1162,8 @@ struct iwl_priv { struct iwl_notif_statistics statistics; #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_notif_statistics accum_statistics; + struct iwl_notif_statistics delta_statistics; + struct iwl_notif_statistics max_delta; #endif /* context information */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 10db97327452..5bbe5f1f749c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -564,15 +564,24 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, int i; __le32 *prev_stats; u32 *accum_stats; + u32 *delta, *max_delta; prev_stats = (__le32 *)&priv->statistics; accum_stats = (u32 *)&priv->accum_statistics; + delta = (u32 *)&priv->delta_statistics; + max_delta = (u32 *)&priv->max_delta; for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); - i += sizeof(__le32), stats++, prev_stats++, accum_stats++) - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) - *accum_stats += (le32_to_cpu(*stats) - + i += sizeof(__le32), stats++, prev_stats++, delta++, + max_delta++, accum_stats++) { + if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { + *delta = (le32_to_cpu(*stats) - le32_to_cpu(*prev_stats)); + *accum_stats += *delta; + if (*delta > *max_delta) + *max_delta = *delta; + } + } /* reset accumulative statistics for "no-counter" type statistics */ priv->accum_statistics.general.temperature = @@ -641,6 +650,10 @@ void iwl_reply_statistics(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG memset(&priv->accum_statistics, 0, sizeof(struct iwl_notif_statistics)); + memset(&priv->delta_statistics, 0, + sizeof(struct iwl_notif_statistics)); + memset(&priv->max_delta, 0, + sizeof(struct iwl_notif_statistics)); #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } -- GitLab From 11fc524941248dc717f1af5dfa844eceb7c0217f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:35 -0800 Subject: [PATCH 0936/3892] iwlwifi: add num_of_sos_stats to statistics counter When uCode detects number of beacon missed consecutively above the internal missed beacon threshold (set by uCode), it will reset and re-tune the radio in order to get out of bad PHY state. This "num_of_sos_states" counter monitors number of time uCode encounters this bad condition and has to re-tune the radio. Signed-off-by: Wey-Yi Guy Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 7 ++++++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 3320cce3d57b..8dc34a3d4f7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3095,7 +3095,12 @@ struct statistics_general { __le32 ttl_timestamp; struct statistics_div div; __le32 rx_enable_counter; - __le32 reserved1; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; __le32 reserved2; __le32 reserved3; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2264cbd95a00..19c7fab47939 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1728,7 +1728,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, struct iwl_priv *priv = file->private_data; int pos = 0; char *buf; - int bufsz = sizeof(struct statistics_general) * 8 + 250; + int bufsz = sizeof(struct statistics_general) * 10 + 300; ssize_t ret; struct statistics_general *general, *accum_general; struct statistics_general *delta_general, *max_general; @@ -1828,6 +1828,12 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, accum_general->rx_enable_counter, delta_general->rx_enable_counter, max_general->rx_enable_counter); + pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, + "num_of_sos_states:", + le32_to_cpu(general->num_of_sos_states), + accum_general->num_of_sos_states, + delta_general->num_of_sos_states, + max_general->num_of_sos_states); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; -- GitLab From 937c397eb633b804d9a806d08c395ecfc42b1fec Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:36 -0800 Subject: [PATCH 0937/3892] iwlwifi: correct return code for log_event When dumping event log in debugfs, iwl_dump_nic_event_log() should return the correct error code instead of let the calling function makes it own assumption. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c78063312ea9..eaa309d8bee1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1965,7 +1965,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); - return pos; + return -EINVAL; } /* event log header */ @@ -2013,7 +2013,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, bufsz = size * 48; *buf = kmalloc(bufsz, GFP_KERNEL); if (!*buf) - return pos; + return -ENOMEM; } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 19c7fab47939..a7ca06d21d59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -429,8 +429,9 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, int pos = 0; ssize_t ret = -ENOMEM; - pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true); - if (pos && buf) { + ret = pos = priv->cfg->ops->lib->dump_nic_event_log( + priv, true, &buf, true); + if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 10b0aa8024c4..8bbcc5487aa0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1644,7 +1644,7 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return pos; + return -EINVAL; } /* event log header */ @@ -1693,7 +1693,7 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, bufsz = size * 48; *buf = kmalloc(bufsz, GFP_KERNEL); if (!*buf) - return pos; + return -ENOMEM; } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* if uCode has wrapped back to top of log, -- GitLab From 2be76703a3afb281155894ac52d34f7f5d736633 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:37 -0800 Subject: [PATCH 0938/3892] iwlwifi: set interrupt coalescing timer range and default For interrupt coalescing timer, the CSR_INT_COALESCING is an 8 bit register in 32-usec unit, the range can go from 0x00 - 0xFF. set the range and default timeout value for both calibration mode and operation mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-rx.c | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5b56307a3812..29eb7b4dc7d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -257,8 +257,8 @@ int iwl_hw_nic_init(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->cfg->ops->lib->apm_ops.init(priv); - /* Set interrupt coalescing timer to 512 usecs */ - iwl_write8(priv, CSR_INT_COALESCING, 512 / 32); + /* Set interrupt coalescing calibration timer to default (512 usecs) */ + iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 63e45cd3f634..251eb737860c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1011,6 +1011,21 @@ struct iwl_event_log { int wraps_more_count; }; +/* + * host interrupt timeout value + * used with setting interrupt coalescing timer + * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit + * + * default interrupt coalescing timer is 64 x 32 = 2048 usecs + * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs + */ +#define IWL_HOST_INT_TIMEOUT_MAX (0xFF) +#define IWL_HOST_INT_TIMEOUT_DEF (0x40) +#define IWL_HOST_INT_TIMEOUT_MIN (0x0) +#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF) +#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) +#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) + struct iwl_priv { /* ieee device used by generic ieee processing code */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5bbe5f1f749c..07bdba93c179 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -473,8 +473,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */ - iwl_write8(priv, CSR_INT_COALESCING, 0x40); + /* Set interrupt coalescing timer to default (2048 usecs) */ + iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); return 0; } -- GitLab From 2a11df6ee58d1b1fc7e5ecd7593a04d7555dc522 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:38 -0800 Subject: [PATCH 0939/3892] iwlwifi: software w/a for h/w bug cause Rx bit get clear This is a w/a for a hardware bug. the h/w bug may cause the Rx bit (bit 15 before shifting it to 31) to clear when using interrupt coalescing. This does not mean frames are lost - their processing is just delayed until next interrupt arrives. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 29eb7b4dc7d4..9d6c144d0701 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1803,6 +1803,16 @@ irqreturn_t iwl_isr_ict(int irq, void *data) if (val == 0xffffffff) val = 0; + /* + * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit + * (bit 15 before shifting it to 31) to clear when using interrupt + * coalescing. fortunately, bits 18 and 19 stay set when this happens + * so we use them to decide on the real state of the Rx bit. + * In order words, bit 15 is set if bit 18 or bit 19 are set. + */ + if (val & 0xC0000) + val |= 0x8000; + inta = (0xff & val) | ((0xff00 & val) << 16); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", inta, inta_mask, val); -- GitLab From 1b3eb8236ad9369ae519216b61a3d22806370115 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:39 -0800 Subject: [PATCH 0940/3892] iwlwifi: display flowhandler register when sw error or on-demand Flowhandler handle the communication between driver and uCode, when any uCode error happen, we also like to know what is the status of the flowhandler; it can help to debug flowhandler related problem. Also adding debugfs file to dump current value of flowhandler registers. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + drivers/net/wireless/iwlwifi/iwl-6000.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 65 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 24 ++++++++ drivers/net/wireless/iwlwifi/iwl-fh.h | 19 +++++++ 8 files changed, 114 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 0db1fda94a65..506429f00c12 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -106,6 +106,7 @@ static struct iwl_lib_ops iwl1000_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, + .dump_fh = iwl_dump_fh, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c6120f0b8f98..500c410f5242 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1467,6 +1467,7 @@ struct iwl_lib_ops iwl5000_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, + .dump_fh = iwl_dump_fh, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a5a0ed4817a4..c5f244f3d747 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -216,6 +216,7 @@ static struct iwl_lib_ops iwl6000_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, + .dump_fh = iwl_dump_fh, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9d6c144d0701..28d97f5f8ccf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1353,6 +1353,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv) priv->cfg->ops->lib->dump_nic_error_log(priv); if (priv->cfg->ops->lib->dump_csr) priv->cfg->ops->lib->dump_csr(priv); + if (priv->cfg->ops->lib->dump_fh) + priv->cfg->ops->lib->dump_fh(priv, NULL, false); priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) @@ -3278,6 +3280,69 @@ void iwl_dump_csr(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_dump_csr); +const static char *get_fh_string(int cmd) +{ + switch (cmd) { + IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); + IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); + IWL_CMD(FH_RSCSR_CHNL0_WPTR); + IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); + IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); + IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); + IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); + IWL_CMD(FH_TSSR_TX_STATUS_REG); + IWL_CMD(FH_TSSR_TX_ERROR_REG); + default: + return "UNKNOWN"; + + } +} + +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) +{ + int i; +#ifdef CONFIG_IWLWIFI_DEBUG + int pos = 0; + size_t bufsz = 0; +#endif + u32 fh_tbl[] = { + FH_RSCSR_CHNL0_STTS_WPTR_REG, + FH_RSCSR_CHNL0_RBDCB_BASE_REG, + FH_RSCSR_CHNL0_WPTR, + FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_MEM_RSSR_SHARED_CTRL_REG, + FH_MEM_RSSR_RX_STATUS_REG, + FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, + FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_ERROR_REG + }; +#ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + pos += scnprintf(*buf + pos, bufsz - pos, + "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + pos += scnprintf(*buf + pos, bufsz - pos, + " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(priv, fh_tbl[i])); + } + return pos; + } +#endif + IWL_ERR(priv, "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + IWL_ERR(priv, " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(priv, fh_tbl[i])); + } + return 0; +} +EXPORT_SYMBOL(iwl_dump_fh); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8deb83bfe182..666b0e0728b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -171,6 +171,7 @@ struct iwl_lib_ops { bool full_log, char **buf, bool display); void (*dump_nic_error_log)(struct iwl_priv *priv); void (*dump_csr)(struct iwl_priv *priv); + int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ struct iwl_apm_ops apm_ops; @@ -582,6 +583,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); void iwl_dump_csr(struct iwl_priv *priv); +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 58e0462cafa3..1d1e655317a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -111,6 +111,7 @@ struct iwl_debugfs { struct dentry *file_clear_traffic_statistics; struct dentry *file_csr; struct dentry *file_ucode_tracing; + struct dentry *file_fh_reg; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a7ca06d21d59..a3d461ff4a9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2151,6 +2151,27 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char *buf; + int pos = 0; + ssize_t ret = -EFAULT; + + if (priv->cfg->ops->lib->dump_fh) { + ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, + count, ppos, buf, pos); + kfree(buf); + } + } + + return ret; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2167,6 +2188,7 @@ DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); +DEBUGFS_READ_FILE_OPS(fh_reg); /* * Create the debugfs files and directories @@ -2218,6 +2240,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); + DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); @@ -2277,6 +2300,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_clear_traffic_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 65fa8a69fd5a..1342cf40297a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -379,6 +379,25 @@ #define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) +/** + * Bit fields for TSSR(Tx Shared Status & Control) error status register: + * 31: Indicates an address error when accessed to internal memory + * uCode/driver must write "1" in order to clear this flag + * 30: Indicates that Host did not send the expected number of dwords to FH + * uCode/driver must write "1" in order to clear this flag + * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA + * command was received from the scheduler while the TRB was already full + * with previous command + * uCode/driver must write "1" in order to clear this flag + * 7-0: Each status bit indicates a channel's TxCredit error. When an error + * bit is set, it indicates that the FH has received a full indication + * from the RTC TxFIFO and the current value of the TxCredit counter was + * not equal to zero. This mean that the credit mechanism was not + * synchronized to the TxFIFO status + * uCode/driver must write "1" in order to clear this flag + */ +#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018) + #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) -- GitLab From 4e9772b0a94c7d3a5f7062ba94afdbb9e692275d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 15 Jan 2010 13:43:40 -0800 Subject: [PATCH 0941/3892] iwlwifi: remove extra statistics request from debugfs When reading current ucode statistics information from debugfs, in current implementation, it will always send a new "statistics request" to uCode. In normal operation, uCode should report the statistics per beacon interval. Remove this extra request to reduce the additional command exchanges between driver and uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 41 ---------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a3d461ff4a9c..38e2f9f9f1dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1109,16 +1109,6 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, if (!iwl_is_alive(priv)) return -EAGAIN; - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1552,16 +1542,6 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, if (!iwl_is_alive(priv)) return -EAGAIN; - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1739,16 +1719,6 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, if (!iwl_is_alive(priv)) return -EAGAIN; - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1986,23 +1956,12 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, struct iwl_priv *priv = file->private_data; char buf[128]; int pos = 0; - ssize_t ret; const size_t bufsz = sizeof(buf); struct statistics_tx *tx; if (!iwl_is_alive(priv)) pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); else { - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, "Error sending statistics request: %zd\n", - ret); - return -EAGAIN; - } tx = &priv->statistics.tx; if (tx->tx_power.ant_a || tx->tx_power.ant_b || -- GitLab From 1f44780827c6bbbcd1f12d5c6b6ce84f49a96bc0 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 15 Jan 2010 13:43:41 -0800 Subject: [PATCH 0942/3892] iwlwifi: update copyright year to 2010 Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-fh.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-led.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-6000-hw.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-led.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-calib.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-csr.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-fh.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-helpers.h | 2 +- drivers/net/wireless/iwlwifi/iwl-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-led.h | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- drivers/net/wireless/iwlwifi/iwl-prph.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- drivers/net/wireless/iwlwifi/iwl-spectrum.c | 2 +- drivers/net/wireless/iwlwifi/iwl-spectrum.h | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.h | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 47 files changed, 63 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 506429f00c12..d5c6edbbc95a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008-2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h index 08ce259a0e60..042f6bc0df13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 6fd10d443ba3..3a876a8ece38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index a871d09d598f..abe2b739c4dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 5a1033ca7aaa..ce990adc51e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index d4b49883b30e..47909f94271e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 28ffe4c826d8..6472910b72d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 3ec2fe370b58..db4137d9a3ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index c606366b582c..67ef562e8db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6a004abb5973..8159a0fcf5a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index bc056e9ab85f..714e032f6217 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 500c410f5242..aab6cf23c2bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 90185777d98b..ddba39999997 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c5f244f3d747..4dab7f12e725 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008-2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c index 3bccba20f6da..1a24946bc203 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h index ab55f92a161d..a594e4fdc6b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b93e49158196..6aebcedaca8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index affc0c5a2f2c..2f0094a43261 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index eaa309d8bee1..8db86239bd6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index dc61906290e8..845831ac053e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index b6cef989a796..2b7b1df83ba0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8dc34a3d4f7e..cee5fb2187c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 28d97f5f8ccf..bb3ed25f8438 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 666b0e0728b3..785331a98aa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,7 +71,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" #define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 1ec8cb4d5eae..1e00720bf8b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 1d1e655317a2..0facaca9b40b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 38e2f9f9f1dc..af00ad2afa14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 251eb737860c..c6310b0b2f12 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 4a30969689ff..fd37152abae3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 0cd9c02ee044..4e1ba824dc50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 1342cf40297a..113c3669b9ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 87d684efe110..86783c27d97c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index bd0b12efb5c7..45af5bbc1c56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index e552d4c4bdbe..c719baf2585a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 46c7a95b88f0..a6f9c918aabc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index f47f053f02ea..49a70baa3fb6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 8ccc0bb1d9ed..8599444bef01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 310c32e8f698..5db91c10dcc8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 6d95832db06d..d2d2a9174900 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 07bdba93c179..eb45f8be0746 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index fa1c89ba6459..ceb91f969e45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c index 1ea5cd345fe8..da166d1d1b13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index a77c1e619062..af6babee2891 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ieee80211 subsystem header files. * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index cde09a890b73..8afa39b4b488 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 8d052de2d405..8c6850d03e47 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 87ce2bd292c7..d365d13e3291 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8bbcc5487aa0..c46f988d0a5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -77,7 +77,7 @@ #endif #define DRV_VERSION IWLWIFI_VERSION VD VS -#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" #define DRV_AUTHOR "" MODULE_DESCRIPTION(DRV_DESCRIPTION); -- GitLab From 8e9310c1790566ea2de2e8b6e1c04bacbbee648c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 16 Jan 2010 14:36:53 -0500 Subject: [PATCH 0943/3892] mac80211: pid: replace open-coded msecs_to_jiffies Code directly scaling by HZ and rounding can be more efficiently and clearly performed with msecs_to_jiffies. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- net/mac80211/rc80211_pid_algo.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 29bc4c516238..2652a374974e 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -157,9 +157,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, /* In case nothing happened during the previous control interval, turn * the sharpening factor on. */ - period = (HZ * pinfo->sampling_period + 500) / 1000; - if (!period) - period = 1; + period = msecs_to_jiffies(pinfo->sampling_period); if (jiffies - spinfo->last_sample > 2 * period) spinfo->sharp_cnt = pinfo->sharpen_duration; @@ -252,9 +250,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba } /* Update PID controller state. */ - period = (HZ * pinfo->sampling_period + 500) / 1000; - if (!period) - period = 1; + period = msecs_to_jiffies(pinfo->sampling_period); if (time_after(jiffies, spinfo->last_sample + period)) rate_control_pid_sample(pinfo, sband, sta, spinfo); } -- GitLab From edc6ccb7b992bd9ea5db4555c8f0bf74c656f964 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 01:47:55 +0100 Subject: [PATCH 0944/3892] mac80211: move and rename misc tx handler This TX handler is used only for assigning the station pointer in the control information, so give it a better name. Also move it before rate control. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index daf81048c1f7..a74ab797fed9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -559,6 +559,17 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) return TX_CONTINUE; } +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + + if (tx->sta) + info->control.sta = &tx->sta->sta; + + return TX_CONTINUE; +} + static ieee80211_tx_result debug_noinline ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { @@ -733,17 +744,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - - if (tx->sta) - info->control.sta = &tx->sta->sta; - - return TX_CONTINUE; -} - static ieee80211_tx_result debug_noinline ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) { @@ -1292,10 +1292,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) CALL_TXH(ieee80211_tx_h_check_assoc); CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_select_key); + CALL_TXH(ieee80211_tx_h_sta); CALL_TXH(ieee80211_tx_h_michael_mic_add); if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) CALL_TXH(ieee80211_tx_h_rate_ctrl); - CALL_TXH(ieee80211_tx_h_misc); CALL_TXH(ieee80211_tx_h_sequence); CALL_TXH(ieee80211_tx_h_fragment); /* handlers after fragment must be aware of tx info fragmentation! */ -- GitLab From 697e6a0fb0c8783695d4b4a5d7131476b296d623 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 01:47:56 +0100 Subject: [PATCH 0945/3892] mac80211: clear TX control on filtered frames When an skb survived a round-trip through the driver and needs to be re-used, its control information is definitely not valid any more, the driver will have overwritten it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/status.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 0ebcdda24200..9e171b178276 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -69,6 +69,14 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ goto drop; + /* + * This skb 'survived' a round-trip through the driver, and + * hopefully the driver didn't mangle it too badly. However, + * we can definitely not rely on the the control information + * being correct. Clear it so we don't get junk there. + */ + memset(&info->control, 0, sizeof(info->control)); + sta->tx_filtered_count++; /* -- GitLab From a6bae9e7ab19876a157c91019852395539e4f20e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 01:47:57 +0100 Subject: [PATCH 0946/3892] mac80211: remove useless setting of IEEE80211_TX_INTFL_DONT_ENCRYPT There's no value in setting a flag that will never be checked after this point, this seems to be legacy code -- I think previously the flag was used to check whether to encrypt the frame or not. Now, however, the flag need not be set, and setting it actually interferes if the frame will be processed again later. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a74ab797fed9..9afbee0d53c0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -553,9 +553,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } } - if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - return TX_CONTINUE; } -- GitLab From 813d76694043d00b59475baa1fbfaf54a2eb7fad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 01:47:58 +0100 Subject: [PATCH 0947/3892] mac80211: move control.hw_key assignment When mac80211 asks a driver to encrypt a frame, it must assign the control.hw_key pointer for it to know which key to use etc. Currently, mac80211 does this whenever it would software-encrypt a frame. Change the logic of this code to assign the hw_key pointer when selecting the key, and later check it when deciding whether to encrypt the frame or let it be encrypted by the hardware. This allows us to later simply skip the encryption function since it no longer modifies the TX control. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tkip.c | 11 +++++---- net/mac80211/tx.c | 9 +++++++ net/mac80211/wep.c | 18 +++++++------- net/mac80211/wpa.c | 57 +++++++++++++++++---------------------------- 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b73454a507f9..14fe49332c02 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -195,11 +195,13 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, } EXPORT_SYMBOL(ieee80211_get_tkip_key); -/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the +/* + * Encrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing payload. This payload must include - * headroom of eight octets for IV and Ext. IV and taildroom of four octets - * for ICV. @payload_len is the length of payload (_not_ including extra - * headroom and tailroom). @ta is the transmitter addresses. */ + * the IV/Ext.IV and space for (taildroom) four octets for ICV. + * @payload_len is the length of payload (_not_ including IV/ICV length). + * @ta is the transmitter addresses. + */ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta) @@ -214,7 +216,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); - pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9afbee0d53c0..e3d8ff533ee6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -529,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; if (tx->key) { + bool skip_hw = false; + tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ @@ -545,12 +547,19 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) !ieee80211_use_mfp(hdr->frame_control, tx->sta, tx->skb)) tx->key = NULL; + skip_hw = (tx->key->conf.flags & + IEEE80211_KEY_FLAG_SW_MGMT) && + ieee80211_is_mgmt(hdr->frame_control); break; case ALG_AES_CMAC: if (!ieee80211_is_mgmt(hdr->frame_control)) tx->key = NULL; break; } + + if (!skip_hw && + tx->key->conf.flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + info->control.hw_key = &tx->key->conf; } return TX_CONTINUE; diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 247123fe1a7a..0a4c641c9605 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -305,20 +305,20 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (!info->control.hw_key) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else { - info->control.hw_key = &tx->key->conf; - if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { - if (!ieee80211_wep_add_iv(tx->local, skb, - tx->key->conf.keylen, - tx->key->conf.keyidx)) - return -1; - } } + + if (info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, + tx->key->conf.keylen, + tx->key->conf.keyidx)) + return -1; + } + return 0; } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 5332014cb229..f4971cd45c64 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -31,8 +31,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) unsigned int hdrlen; struct ieee80211_hdr *hdr; struct sk_buff *skb = tx->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int authenticator; - int wpa_test = 0; int tail; hdr = (struct ieee80211_hdr *)skb->data; @@ -47,16 +47,15 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) data = skb->data + hdrlen; data_len = skb->len - hdrlen; - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + if (info->control.hw_key && !(tx->flags & IEEE80211_TX_FRAGMENTED) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && - !wpa_test) { - /* hwaccel - with no need for preallocated room for MMIC */ + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { + /* hwaccel - with no need for SW-generated MMIC */ return TX_CONTINUE; } tail = MICHAEL_MIC_LEN; - if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!info->control.hw_key) tail += TKIP_ICV_LEN; if (WARN_ON(skb_tailroom(skb) < tail || @@ -147,17 +146,16 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) int len, tail; u8 *pos; - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* hwaccel - with no need for preallocated room for IV/ICV */ - info->control.hw_key = &tx->key->conf; + if (info->control.hw_key && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for software-generated IV */ return 0; } hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; - if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + if (info->control.hw_key) tail = 0; else tail = TKIP_ICV_LEN; @@ -175,13 +173,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) if (key->u.tkip.tx.iv16 == 0) key->u.tkip.tx.iv32++; - if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - /* hwaccel - with preallocated room for IV */ - ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); + pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); - info->control.hw_key = &tx->key->conf; + /* hwaccel - with software IV */ + if (info->control.hw_key) return 0; - } /* Add room for ICV */ skb_put(skb, TKIP_ICV_LEN); @@ -363,24 +359,20 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) int hdrlen, len, tail; u8 *pos, *pn; int i; - bool skip_hw; - - skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) && - ieee80211_is_mgmt(hdr->frame_control); - if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && - !skip_hw) { - /* hwaccel - with no need for preallocated room for CCMP - * header or MIC fields */ - info->control.hw_key = &tx->key->conf; + if (info->control.hw_key && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* + * hwaccel has no need for preallocated room for CCMP + * header or MIC fields + */ return 0; } hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; - if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + if (info->control.hw_key) tail = 0; else tail = CCMP_MIC_LEN; @@ -405,11 +397,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ccmp_pn2hdr(pos, pn, key->conf.keyidx); - if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) { - /* hwaccel - with preallocated room for CCMP header */ - info->control.hw_key = &tx->key->conf; + /* hwaccel - with software CCMP header */ + if (info->control.hw_key) return 0; - } pos += CCMP_HDR_LEN; ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); @@ -525,11 +515,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) u8 *pn, aad[20]; int i; - if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - /* hwaccel */ - info->control.hw_key = &tx->key->conf; + if (info->control.hw_key) return 0; - } if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) return TX_DROP; -- GitLab From c6fcf6bcfc3cfc1c00cc7fd9610cfa2b1a18041f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 01:47:59 +0100 Subject: [PATCH 0948/3892] mac80211: re-enable re-transmission of filtered frames In an earlier commit, mac80211: disable software retry for now Pavel Roskin reported a problem that seems to be due to software retry of already transmitted frames. It turns out that we've never done that correctly, but due to some recent changes it now crashes in the TX code. I've added a comment in the patch that explains the problem better and also points to possible solutions -- which I can't implement right now. I disabled software retry of failed/filtered frames because it was broken. With the work of the previous patches, it now becomes fairly easy to re-enable it by adding a flag indicating that the frame shouldn't be modified, but still running it through the transmit handlers to populate the control information. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 4 ++++ net/mac80211/status.c | 32 +++++--------------------------- net/mac80211/tx.c | 7 ++++++- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c90047de4428..f03f97b627fe 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -271,6 +271,9 @@ struct ieee80211_bss_conf { * transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the * queue gets full. + * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted + * after TX status because the destination was asleep, it must not + * be modified again (no seqno assignment, crypto, etc.) */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -291,6 +294,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), + IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), }; /** diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 9e171b178276..800b6777e0ed 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -44,38 +44,17 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - /* - * XXX: This is temporary! - * - * The problem here is that when we get here, the driver will - * quite likely have pretty much overwritten info->control by - * using info->driver_data or info->rate_driver_data. Thus, - * when passing out the frame to the driver again, we would be - * passing completely bogus data since the driver would then - * expect a properly filled info->control. In mac80211 itself - * the same problem occurs, since we need info->control.vif - * internally. - * - * To fix this, we should send the frame through TX processing - * again. However, it's not that simple, since the frame will - * have been software-encrypted (if applicable) already, and - * encrypting it again doesn't do much good. So to properly do - * that, we not only have to skip the actual 'raw' encryption - * (key selection etc. still has to be done!) but also the - * sequence number assignment since that impacts the crypto - * encapsulation, of course. - * - * Hence, for now, fix the bug by just dropping the frame. - */ - goto drop; - /* * This skb 'survived' a round-trip through the driver, and * hopefully the driver didn't mangle it too badly. However, * we can definitely not rely on the the control information - * being correct. Clear it so we don't get junk there. + * being correct. Clear it so we don't get junk there, and + * indicate that it needs new processing, but must not be + * modified/encrypted again. */ memset(&info->control, 0, sizeof(info->control)); + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | + IEEE80211_TX_INTFL_RETRANSMISSION; sta->tx_filtered_count++; @@ -130,7 +109,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } - drop: #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped TX filtered frame, " diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e3d8ff533ee6..da557b0d0114 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1285,6 +1285,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, static int invoke_tx_handlers(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ieee80211_tx_result res = TX_DROP; #define CALL_TXH(txh) \ @@ -1299,9 +1300,13 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_select_key); CALL_TXH(ieee80211_tx_h_sta); - CALL_TXH(ieee80211_tx_h_michael_mic_add); if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) CALL_TXH(ieee80211_tx_h_rate_ctrl); + + if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) + goto txh_done; + + CALL_TXH(ieee80211_tx_h_michael_mic_add); CALL_TXH(ieee80211_tx_h_sequence); CALL_TXH(ieee80211_tx_h_fragment); /* handlers after fragment must be aware of tx info fragmentation! */ -- GitLab From 026816fce48390807859508cd5172e9c79901ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:03:28 +0100 Subject: [PATCH 0949/3892] b43: N-PHY: implement RX PHY cleanup and setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 4a817e3da163..a1dd381c6c6e 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -480,6 +480,88 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ +static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) +{ + u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; + + b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]); + if (core == 0) { + b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]); + } else { + b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]); + } + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]); + b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]); + b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]); + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]); + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]); + b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]); + b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ +static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) +{ + u8 rxval, txval; + u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; + + regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA); + if (core == 0) { + regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); + regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); + } else { + regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); + regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + } + regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); + regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); + regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); + regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); + regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1); + regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); + regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); + regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); + + b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); + b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); + + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS, + ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT)); + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN, + ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT)); + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN, + (core << B43_NPHY_RFSEQCA_RXEN_SHIFT)); + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS, + (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT)); + + if (core == 0) { + b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007); + b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007); + } else { + b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007); + b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007); + } + + /* TODO: Call N PHY RF Ctrl Intc Override with 2, 0, 3 as arguments */ + /* TODO: Call N PHY RF Intc Override with 8, 0, 3, 0 as arguments */ + /* TODO: Call N PHY RF Seq with 0 as argument */ + + if (core == 0) { + rxval = 1; + txval = 8; + } else { + rxval = 4; + txval = 2; + } + + /* TODO: Call N PHY RF Ctrl Intc Override with 1, rxval, (core + 1) */ + /* TODO: Call N PHY RF Ctrl Intc Override with 1, txval, (2 - core) */ +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) { -- GitLab From e53de67449bbcaf5551f54e506a4dff62fc6a49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:03:32 +0100 Subject: [PATCH 0950/3892] b43: N-PHY: implement TX PHY cleanup and setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 112 ++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index a1dd381c6c6e..fd93b2a6b494 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1505,6 +1505,114 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) return target; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ +static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) +{ + u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; + + if (dev->phy.rev >= 3) { + b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[0]); + b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[3]); + b43_phy_write(dev, B43_NPHY_BBCFG, regs[4]); + /* TODO: Write an N PHY Table with ID 8, length 1, offset 3, + width 16, and data from regs[5] */ + /* TODO: Write an N PHY Table with ID 8, length 1, offset 19, + width 16, and data from regs[6] */ + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[7]); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[8]); + b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]); + b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); + b43_nphy_reset_cca(dev); + } else { + b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, regs[0]); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, regs[1]); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]); + /* TODO: Write an N PHY Table with ID 8, length 1, offset 2, + width 16, and data from regs[3] */ + /* TODO: Write an N PHY Table with ID 8, length 1, offset 18, + width 16, and data from regs[4] */ + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[5]); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[6]); + } +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ +static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) +{ + u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; + u16 tmp; + + regs[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); + regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); + if (dev->phy.rev >= 3) { + b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0xF0FF, 0x0A00); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0xF0FF, 0x0A00); + + tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); + regs[2] = tmp; + b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, tmp | 0x0600); + + tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + regs[3] = tmp; + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600); + + regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG); + b43_phy_mask(dev, B43_NPHY_BBCFG, ~B43_NPHY_BBCFG_RSTRX); + + /* TODO: Read an N PHY Table with ID 8, length 1, offset 3, + width 16, and data pointing to tmp */ + regs[5] = tmp; + + /* TODO: Write an N PHY Table with ID 8, length 1, offset 3, + width 16, and data 0 */ + /* TODO: Read an N PHY Table with ID 8, length 1, offset 19, + width 16, and data pointing to tmp */ + regs[6] = tmp; + + /* TODO: Write an N PHY Table with ID 8, length 1, offset 19, + width 16, and data 0 */ + regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); + regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); + + /* TODO: Call N PHY RF Ctrl Intc Override with 2, 1, 3 */ + /* TODO: Call N PHY RF Ctrl Intc Override with 1, 2, 1 */ + /* TODO: Call N PHY RF Ctrl Intc Override with 1, 8, 2 */ + + regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); + regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); + b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); + b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); + } else { + b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000); + tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); + regs[2] = tmp; + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x3000); + /* TODO: Read an N PHY Table with ID 8, length 1, offset 2, + width 16, and data pointing to tmp */ + regs[3] = tmp; + tmp |= 0x2000; + /* TODO: Write an N PHY Table with ID 8, length 1, offset 2, + width 16, and data pointer tmp */ + /* TODO: Read an N PHY Table with ID 8, length 1, offset 18, + width 16, and data pointer tmp */ + regs[4] = tmp; + tmp |= 0x2000; + /* TODO: Write an N PHY Table with ID 8, length 1, offset 18, + width 16, and data pointer tmp */ + regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); + regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp = 0x0180; + else + tmp = 0x0120; + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp); + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ static void b43_nphy_restore_cal(struct b43_wldev *dev) { @@ -1617,7 +1725,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, width 16, and data pointer gain */ b43_nphy_tx_cal_radio_setup(dev); - /* TODO: Call N PHY TX Cal PHY Setup */ + b43_nphy_tx_cal_phy_setup(dev); phy6or5x = dev->phy.rev >= 6 || (dev->phy.rev == 5 && nphy->ipa2g_on && @@ -1788,7 +1896,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); } - /* TODO: Call N PHY TX Cal PHY Cleanup */ + b43_nphy_tx_cal_phy_cleanup(dev); /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, width 16, and data from save */ -- GitLab From ad9716e8e8bc39664a0d41ec94f9bffbf748b45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:03:40 +0100 Subject: [PATCH 0951/3892] b43: N-PHY: implement MIMO config update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 16 +++++++++++++++- drivers/net/wireless/b43/phy_n.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index fd93b2a6b494..1996843eac11 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -424,6 +424,20 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) /* TODO: N PHY Force RF Seq with argument 2 */ } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ +static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) +{ + u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG); + + mimocfg |= B43_NPHY_MIMOCFG_AUTO; + if (preamble == 1) + mimocfg |= B43_NPHY_MIMOCFG_GFMIX; + else + mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX; + + b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, u16 samps, u8 time, bool wait) @@ -2180,7 +2194,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50); b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); - /* TODO MIMO-Config */ + b43_nphy_update_mimo_config(dev, nphy->preamble_override); /* TODO Update TX/RX chain */ if (phy->rev < 2) { diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 4572866756fc..ae00e3f2d613 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -973,6 +973,7 @@ struct b43_phy_n { bool hang_avoid; bool mute; u16 papd_epsilon_offset[2]; + s32 preamble_override; u8 mphase_cal_phase_id; u16 mphase_txcal_cmdidx; -- GitLab From 53ae8e8c92b2715f27c95e8e7169bca9a8909856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:03:48 +0100 Subject: [PATCH 0952/3892] b43: N-PHY: implement stopping playback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 34 +++++++++++++++++++++++++++++--- drivers/net/wireless/b43/phy_n.h | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1996843eac11..229f2d0364f2 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -749,6 +749,34 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ +static void b43_nphy_stop_playback(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + u16 tmp; + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, 1); + + tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT); + if (tmp & 0x1) + b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP); + else if (tmp & 0x2) + b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000); + + b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004); + + if (nphy->bb_mult_save & 0x80000000) { + tmp = nphy->bb_mult_save & 0xFFFF; + /* TODO: Write an N PHY Table with ID 15, length 1, offset 87, + width 16 and data from tmp */ + nphy->bb_mult_save = 0; + } + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, 0); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) { @@ -1906,7 +1934,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, nphy->mphase_txcal_bestcoeffs */ } - /* TODO: Call N PHY Stop Playback */ + b43_nphy_stop_playback(dev); b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); } @@ -2053,7 +2081,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0], 3, 0 as arguments */ /* TODO: Call N PHY Force RF Seq with 2 as argument */ - /* TODO: Call N PHT Stop Playback */ + b43_nphy_stop_playback(dev); if (playtone) { /* TODO: Call N PHY TX Tone with 4000, @@ -2080,7 +2108,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, } else { b43_nphy_calc_rx_iq_comp(dev, 1 << i); } - /* TODO: Call N PHY Stop Playback */ + b43_nphy_stop_playback(dev); } if (ret != 0) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index ae00e3f2d613..d6c92a81d3c0 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -974,6 +974,7 @@ struct b43_phy_n { bool mute; u16 papd_epsilon_offset[2]; s32 preamble_override; + u32 bb_mult_save; u8 mphase_cal_phase_id; u16 mphase_txcal_cmdidx; -- GitLab From 4f4ab6cd1486fcb0ab8d689d625ac7691198f36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:03:55 +0100 Subject: [PATCH 0953/3892] b43: N-PHY: implement chain selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 30 +++++++++++++++++++++++++++++- drivers/net/wireless/b43/phy_n.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 229f2d0364f2..90a49cfaa965 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -438,6 +438,34 @@ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ +static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + bool override = false; + u16 chain = 0x33; + + if (nphy->txrx_chain == 0) { + chain = 0x11; + override = true; + } else if (nphy->txrx_chain == 1) { + chain = 0x22; + override = true; + } + + b43_phy_maskset(dev, B43_NPHY_RFSEQCA, + ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN), + chain); + + if (override) + b43_phy_set(dev, B43_NPHY_RFSEQMODE, + B43_NPHY_RFSEQMODE_CAOVER); + else + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~B43_NPHY_RFSEQMODE_CAOVER); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, u16 samps, u8 time, bool wait) @@ -2223,7 +2251,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); b43_nphy_update_mimo_config(dev, nphy->preamble_override); - /* TODO Update TX/RX chain */ + b43_nphy_update_txrx_chain(dev); if (phy->rev < 2) { b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index d6c92a81d3c0..f5a27661f659 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -987,6 +987,7 @@ struct b43_phy_n { bool txiqlocal_coeffsvalid; struct b43_phy_n_txpwrindex txpwrindex[2]; + u8 txrx_chain; u16 tx_rx_cal_phy_saveregs[11]; u16 tx_rx_cal_radio_saveregs[22]; -- GitLab From 67c0d6e2d1abb9cbff9235143a8faaef89119628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:04:02 +0100 Subject: [PATCH 0954/3892] b43: N-PHY: move RF sequence declarations top, add missing calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 90a49cfaa965..99024b02bdbd 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -55,6 +55,18 @@ struct nphy_iq_est { u32 q1_pwr; }; +enum b43_nphy_rf_sequence { + B43_RFSEQ_RX2TX, + B43_RFSEQ_TX2RX, + B43_RFSEQ_RESET2RX, + B43_RFSEQ_UPDATE_GAINH, + B43_RFSEQ_UPDATE_GAINL, + B43_RFSEQ_UPDATE_GAINU, +}; + +static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, + enum b43_nphy_rf_sequence seq); + void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO } @@ -421,7 +433,7 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) udelay(1); b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA); b43_nphy_bmac_clock_fgc(dev, 0); - /* TODO: N PHY Force RF Seq with argument 2 */ + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ @@ -590,7 +602,7 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) /* TODO: Call N PHY RF Ctrl Intc Override with 2, 0, 3 as arguments */ /* TODO: Call N PHY RF Intc Override with 8, 0, 3, 0 as arguments */ - /* TODO: Call N PHY RF Seq with 0 as argument */ + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); if (core == 0) { rxval = 1; @@ -872,15 +884,7 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, false); } -enum b43_nphy_rf_sequence { - B43_RFSEQ_RX2TX, - B43_RFSEQ_TX2RX, - B43_RFSEQ_RESET2RX, - B43_RFSEQ_UPDATE_GAINH, - B43_RFSEQ_UPDATE_GAINL, - B43_RFSEQ_UPDATE_GAINU, -}; - +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, enum b43_nphy_rf_sequence seq) { @@ -2156,7 +2160,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, } /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/ - /* TODO: Call N PHY Force RF Seq with 2 as argument */ + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, width 16, and data from gain_save */ -- GitLab From c57199bc32ebcd914253496486d2e09b1c9a3de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Jan 2010 13:04:08 +0100 Subject: [PATCH 0955/3892] b43: N-PHY: store seq mode for proper restoring (follow specs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 99024b02bdbd..95190d42372c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -897,6 +897,7 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, }; int i; + u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE); B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); @@ -910,8 +911,7 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, } b43err(dev->wl, "RF sequence status timeout\n"); ok: - b43_phy_mask(dev, B43_NPHY_RFSEQMODE, - ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); + b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); } static void b43_nphy_bphy_init(struct b43_wldev *dev) -- GitLab From 5f2aa25e0e5b221a176ab3d1c51d51da265cb4a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jan 2010 15:49:02 +0100 Subject: [PATCH 0956/3892] cfg80211: rcu-ify rdev and wdev Future code will need to look up rdev and wdev within atomic sections, but currently we need to lock a mutex for such lookups. Change the list handling for both to be RCU-safe so that we can look them up in rcu sections instead in the future. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.c | 26 +++++++++++++++----------- net/wireless/core.h | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 20db90246de5..d07f57c906db 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1,7 +1,7 @@ /* * This is the linux wireless configuration interface. * - * Copyright 2006-2009 Johannes Berg + * Copyright 2006-2010 Johannes Berg */ #include @@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("wireless configuration support"); -/* RCU might be appropriate here since we usually - * only read the list, and that can happen quite - * often because we need to do it for each command */ +/* RCU-protected (and cfg80211_mutex for writers) */ LIST_HEAD(cfg80211_rdev_list); int cfg80211_rdev_list_generation; -/* - * This is used to protect the cfg80211_rdev_list - */ DEFINE_MUTEX(cfg80211_mutex); /* for debugfs */ @@ -477,7 +472,7 @@ int wiphy_register(struct wiphy *wiphy) /* set up regulatory info */ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - list_add(&rdev->list, &cfg80211_rdev_list); + list_add_rcu(&rdev->list, &cfg80211_rdev_list); cfg80211_rdev_list_generation++; mutex_unlock(&cfg80211_mutex); @@ -554,7 +549,8 @@ void wiphy_unregister(struct wiphy *wiphy) * it impossible to find from userspace. */ debugfs_remove_recursive(rdev->wiphy.debugfsdir); - list_del(&rdev->list); + list_del_rcu(&rdev->list); + synchronize_rcu(); /* * Try to grab rdev->mtx. If a command is still in progress, @@ -670,7 +666,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); - list_add(&wdev->list, &rdev->netdev_list); + list_add_rcu(&wdev->list, &rdev->netdev_list); rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -782,13 +778,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, */ if (!list_empty(&wdev->list)) { sysfs_remove_link(&dev->dev.kobj, "phy80211"); - list_del_init(&wdev->list); + list_del_rcu(&wdev->list); rdev->devlist_generation++; #ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.keys); #endif } mutex_unlock(&rdev->devlist_mtx); + /* + * synchronise (so that we won't find this netdev + * from other code any more) and then clear the list + * head so that the above code can safely check for + * !list_empty() to avoid double-cleanup. + */ + synchronize_rcu(); + INIT_LIST_HEAD(&wdev->list); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/net/wireless/core.h b/net/wireless/core.h index 2d6a6b9c0c43..c326a667022a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -1,7 +1,7 @@ /* * Wireless configuration interface internals. * - * Copyright 2006-2009 Johannes Berg + * Copyright 2006-2010 Johannes Berg */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -48,6 +48,7 @@ struct cfg80211_registered_device { /* associate netdev list */ struct mutex devlist_mtx; + /* protected by devlist_mtx or RCU */ struct list_head netdev_list; int devlist_generation; int opencount; /* also protected by devlist_mtx */ -- GitLab From 27032059677b98f33634ceb90488812db432cbc9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 17 Jan 2010 21:08:50 +0100 Subject: [PATCH 0957/3892] ath9k: fix RTS/CTS handling The Tx DMA descriptor has two kinds of flags that select RTS/CTS usage. The first one (global for the frame) selects whether RTS/CTS or CTS-to-self should be used, the second one enables RTS/CTS or CTS-to-self usage for an individual multi-rate-retry entry. Previously the code preparing the descriptor only enabled the global flag, if the first MRR series selected the local one. Fix this by enabling the global flag if any of the MRR entries need it. With this patch, rate control can properly select the use of RTS/CTS for all MRR entries except the first one, which is the default behavior. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 37 ++++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a821bb687b3b..a6893cf0c43b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1498,26 +1498,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ctsrate |= rate->hw_value_short; - /* - * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. - * Check the first rate in the series to decide whether RTS/CTS - * or CTS-to-self has to be used. - */ - if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - flags = ATH9K_TXDESC_CTSENA; - else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - flags = ATH9K_TXDESC_RTSENA; - - /* FIXME: Handle aggregation protection */ - if (sc->config.ath_aggr_prot && - (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { - flags = ATH9K_TXDESC_RTSENA; - } - - /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) - flags &= ~(ATH9K_TXDESC_RTSENA); - for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; int phy; @@ -1529,8 +1509,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) series[i].Tries = rates[i].count; series[i].ChSel = common->tx_chainmask; - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) + if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) || + (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) { series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + flags |= ATH9K_TXDESC_RTSENA; + } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + flags |= ATH9K_TXDESC_CTSENA; + } + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) series[i].RateFlags |= ATH9K_RATESERIES_2040; if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) @@ -1568,6 +1555,14 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp); } + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) + flags &= ~ATH9K_TXDESC_RTSENA; + + /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ + if (flags & ATH9K_TXDESC_RTSENA) + flags &= ~ATH9K_TXDESC_CTSENA; + /* set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, bf->bf_lastbf->bf_desc, -- GitLab From ce9058aedd75f14785400dcc49a2bc352ca38871 Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Sun, 17 Jan 2010 22:45:23 +0100 Subject: [PATCH 0958/3892] mac80211: removed useless code in IBSS management ieee82011_sta_find_ibss() and ieee80211_sta_merge_ibss() are always called with a defined state. So it's useless to check it or set it in those function. Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5bcde4c3fba1..c2a708e3a18c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -454,6 +454,9 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) return active; } +/* + * This function is called with state == IEEE80211_IBSS_MLME_JOINED + */ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) { @@ -519,6 +522,10 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) capability, 0); } +/* + * This function is called with state == IEEE80211_IBSS_MLME_SEARCH + */ + static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; @@ -575,18 +582,14 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) #endif /* CONFIG_MAC80211_IBSS_DEBUG */ /* Selected IBSS not found in current scan results - try to scan */ - if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && - !ieee80211_sta_active_ibss(sdata)) { - mod_timer(&ifibss->timer, - round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - } else if (time_after(jiffies, ifibss->last_scan_completed + + if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " "join\n", sdata->name); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); - } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { + } else { int interval = IEEE80211_SCAN_INTERVAL; if (time_after(jiffies, ifibss->ibss_join_req + @@ -604,7 +607,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) interval = IEEE80211_SCAN_INTERVAL_SLOW; } - ifibss->state = IEEE80211_IBSS_MLME_SEARCH; mod_timer(&ifibss->timer, round_jiffies(jiffies + interval)); } -- GitLab From a98bfec2985221d8e0904a526cbe88590eaad2a6 Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Sun, 17 Jan 2010 22:45:24 +0100 Subject: [PATCH 0959/3892] mac80211: Fixed a bug in IBSS merge First, both beacons and probe responses can be used for IBSS merge. Next, sdata->u.ibss.bssid was always true (and thus IBSS merge was disabled). We should use sdata->u.ibss.fixed_bssid instead. Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c2a708e3a18c..f95750b423e3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -293,12 +293,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, /* check if we need to merge IBSS */ - /* merge only on beacons (???) */ - if (!beacon) - goto put_bss; - /* we use a fixed BSSID */ - if (sdata->u.ibss.bssid) + if (sdata->u.ibss.fixed_bssid) goto put_bss; /* not an IBSS */ -- GitLab From 288c8ce8047695fd8872dd5db3ef21a9679c402f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 17 Jan 2010 23:17:29 +0100 Subject: [PATCH 0960/3892] p54pci: handle dma mapping errors This patch adds error-paths to handle pci_dma_mapping errors. Cc: Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index a72f7c2577de..4bf4c213baec 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -157,6 +157,14 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev, skb_tail_pointer(skb), priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(priv->pdev, mapping)) { + dev_kfree_skb_any(skb); + dev_err(&priv->pdev->dev, + "RX DMA Mapping error\n"); + break; + } + desc->host_addr = cpu_to_le32(mapping); desc->device_addr = 0; // FIXME: necessary? desc->len = cpu_to_le16(priv->common.rx_mtu + 32); @@ -325,14 +333,20 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u32 device_idx, idx, i; spin_lock_irqsave(&priv->lock, flags); - device_idx = le32_to_cpu(ring_control->device_idx[1]); idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - priv->tx_buf_data[i] = skb; mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(priv->pdev, mapping)) { + spin_unlock_irqrestore(&priv->lock, flags); + p54_free_skb(dev, skb); + dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); + return ; + } + priv->tx_buf_data[i] = skb; + desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; -- GitLab From d713804c6032b95cd3035014e16fadebb9655c6f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 17 Jan 2010 23:19:25 +0100 Subject: [PATCH 0961/3892] p54pci: move tx cleanup into tasklet This patch moves the tx cleanup routines out of the critical interrupt context and into the (previously known as rx) tasklet. The main goal of this operation is to remove the extensive usage of spin_lock_irqsaves in the generic p54common library. The next step would be to modify p54usb to do the rx processing inside a tasklet (just like usbnet). Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 56 ++++++++++++++++--------------- drivers/net/wireless/p54/p54pci.h | 6 ++-- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 4bf4c213baec..48cae48ed6eb 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -234,25 +234,26 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); } -/* caller must hold priv->lock */ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, int ring_index, struct p54p_desc *ring, u32 ring_limit, - void **tx_buf) + struct sk_buff **tx_buf) { + unsigned long flags; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_desc *desc; + struct sk_buff *skb; u32 idx, i; i = (*index) % ring_limit; (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); idx %= ring_limit; + spin_lock_irqsave(&priv->lock, flags); while (i != idx) { desc = &ring[i]; - if (tx_buf[i]) - if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) - p54_free_skb(dev, tx_buf[i]); + + skb = tx_buf[i]; tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -263,17 +264,32 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, desc->len = 0; desc->flags = 0; + if (skb && FREE_AFTER_TX(skb)) { + spin_unlock_irqrestore(&priv->lock, flags); + p54_free_skb(dev, skb); + spin_lock_irqsave(&priv->lock, flags); + } + i++; i %= ring_limit; } + spin_unlock_irqrestore(&priv->lock, flags); } -static void p54p_rx_tasklet(unsigned long dev_id) +static void p54p_tasklet(unsigned long dev_id) { struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; + p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt, + ARRAY_SIZE(ring_control->tx_mgmt), + priv->tx_buf_mgmt); + + p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data, + ARRAY_SIZE(ring_control->tx_data), + priv->tx_buf_data); + p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); @@ -288,38 +304,24 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) { struct ieee80211_hw *dev = dev_id; struct p54p_priv *priv = dev->priv; - struct p54p_ring_control *ring_control = priv->ring_control; __le32 reg; spin_lock(&priv->lock); reg = P54P_READ(int_ident); if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { - spin_unlock(&priv->lock); - return IRQ_HANDLED; + goto out; } - P54P_WRITE(int_ack, reg); reg &= P54P_READ(int_enable); - if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { - p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, - 3, ring_control->tx_mgmt, - ARRAY_SIZE(ring_control->tx_mgmt), - priv->tx_buf_mgmt); - - p54p_check_tx_ring(dev, &priv->tx_idx_data, - 1, ring_control->tx_data, - ARRAY_SIZE(ring_control->tx_data), - priv->tx_buf_data); - - tasklet_schedule(&priv->rx_tasklet); - - } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) + if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) + tasklet_schedule(&priv->tasklet); + else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) complete(&priv->boot_comp); +out: spin_unlock(&priv->lock); - return reg ? IRQ_HANDLED : IRQ_NONE; } @@ -368,7 +370,7 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; - tasklet_kill(&priv->rx_tasklet); + tasklet_kill(&priv->tasklet); P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); @@ -559,7 +561,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->common.tx = p54p_tx; spin_lock_init(&priv->lock); - tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); err = request_firmware(&priv->firmware, "isl3886pci", &priv->pdev->dev); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index fbb683953fb2..2feead617a3b 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -92,7 +92,7 @@ struct p54p_priv { struct p54_common common; struct pci_dev *pdev; struct p54p_csr __iomem *map; - struct tasklet_struct rx_tasklet; + struct tasklet_struct tasklet; const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; @@ -101,8 +101,8 @@ struct p54p_priv { u32 rx_idx_mgmt, tx_idx_mgmt; struct sk_buff *rx_buf_data[8]; struct sk_buff *rx_buf_mgmt[4]; - void *tx_buf_data[32]; - void *tx_buf_mgmt[4]; + struct sk_buff *tx_buf_data[32]; + struct sk_buff *tx_buf_mgmt[4]; struct completion boot_comp; }; -- GitLab From d41a3552f96673480d7913c170cab31fa00b7697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Jan 2010 00:21:17 +0100 Subject: [PATCH 0962/3892] b43: N-PHY: add writing one element tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 40 +++++++++++--------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 95190d42372c..32f837049ef9 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -808,8 +808,7 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) if (nphy->bb_mult_save & 0x80000000) { tmp = nphy->bb_mult_save & 0xFFFF; - /* TODO: Write an N PHY Table with ID 15, length 1, offset 87, - width 16 and data from tmp */ + b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); nphy->bb_mult_save = 0; } @@ -1486,13 +1485,11 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) for (i = 0; i < 18; i++) { scale = (ladder_lo[i].percent * tmp) / 100; entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env; - /* TODO: Write an N PHY Table with ID 15, length 1, - offset i, width 16, and data entry */ + b43_ntab_write(dev, B43_NTAB16(15, i), entry); scale = (ladder_iq[i].percent * tmp) / 100; entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env; - /* TODO: Write an N PHY Table with ID 15, length 1, - offset i + 32, width 16, and data entry */ + b43_ntab_write(dev, B43_NTAB16(15, i + 32), entry); } } @@ -1590,10 +1587,8 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]); b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[3]); b43_phy_write(dev, B43_NPHY_BBCFG, regs[4]); - /* TODO: Write an N PHY Table with ID 8, length 1, offset 3, - width 16, and data from regs[5] */ - /* TODO: Write an N PHY Table with ID 8, length 1, offset 19, - width 16, and data from regs[6] */ + b43_ntab_write(dev, B43_NTAB16(8, 3), regs[5]); + b43_ntab_write(dev, B43_NTAB16(8, 19), regs[6]); b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[7]); b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[8]); b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]); @@ -1603,10 +1598,8 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, regs[0]); b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, regs[1]); b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]); - /* TODO: Write an N PHY Table with ID 8, length 1, offset 2, - width 16, and data from regs[3] */ - /* TODO: Write an N PHY Table with ID 8, length 1, offset 18, - width 16, and data from regs[4] */ + b43_ntab_write(dev, B43_NTAB16(8, 2), regs[3]); + b43_ntab_write(dev, B43_NTAB16(8, 18), regs[4]); b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[5]); b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[6]); } @@ -1638,15 +1631,11 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) /* TODO: Read an N PHY Table with ID 8, length 1, offset 3, width 16, and data pointing to tmp */ regs[5] = tmp; - - /* TODO: Write an N PHY Table with ID 8, length 1, offset 3, - width 16, and data 0 */ + b43_ntab_write(dev, B43_NTAB16(8, 3), 0); /* TODO: Read an N PHY Table with ID 8, length 1, offset 19, width 16, and data pointing to tmp */ regs[6] = tmp; - - /* TODO: Write an N PHY Table with ID 8, length 1, offset 19, - width 16, and data 0 */ + b43_ntab_write(dev, B43_NTAB16(8, 19), 0); regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); @@ -1668,14 +1657,12 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) width 16, and data pointing to tmp */ regs[3] = tmp; tmp |= 0x2000; - /* TODO: Write an N PHY Table with ID 8, length 1, offset 2, - width 16, and data pointer tmp */ + b43_ntab_write(dev, B43_NTAB16(8, 2), tmp); /* TODO: Read an N PHY Table with ID 8, length 1, offset 18, width 16, and data pointer tmp */ regs[4] = tmp; tmp |= 0x2000; - /* TODO: Write an N PHY Table with ID 8, length 1, offset 18, - width 16, and data pointer tmp */ + b43_ntab_write(dev, B43_NTAB16(8, 18), tmp); regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) @@ -1900,9 +1887,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, width 16, and data pointer buffer */ diq_start = buffer[0]; buffer[0] = 0; - /* TODO: Write an N PHY Table with ID 15, - length 1, offset 69 + core, width 16, - and data of 0 */ + b43_ntab_write(dev, B43_NTAB16(15, 69 + core), + 0); } b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd); -- GitLab From 2581b1434ccba6960e0b671927d87c83b5152c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Jan 2010 00:21:21 +0100 Subject: [PATCH 0963/3892] b43: N-PHY: implement and add multi-dimensional table writing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 58 +++++++++++--------------- drivers/net/wireless/b43/tables_nphy.c | 40 ++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 2 + 3 files changed, 67 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 32f837049ef9..671fbcfdc0ec 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1699,8 +1699,7 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) loft = &nphy->cal_cache.txcal_coeffs_5G[5]; } - /* TODO: Write an N PHY table with ID 15, length 4, offset 80, - width 16, and data from table */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, table); for (i = 0; i < 4; i++) { if (dev->phy.rev >= 3) @@ -1709,12 +1708,9 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) coef[i] = 0; } - /* TODO: Write an N PHY table with ID 15, length 4, offset 88, - width 16, and data from coef */ - /* TODO: Write an N PHY table with ID 15, length 2, offset 85, - width 16 and data from loft */ - /* TODO: Write an N PHY table with ID 15, length 2, offset 93, - width 16 and data from loft */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, coef); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, loft); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, loft); if (dev->phy.rev < 2) b43_nphy_tx_iq_workaround(dev); @@ -1782,8 +1778,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); gain[i] = params[i].cal_gain; } - /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data pointer gain */ + + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain); b43_nphy_tx_cal_radio_setup(dev); b43_nphy_tx_cal_phy_setup(dev); @@ -1833,8 +1829,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, } } - /* TODO: Write an N PHY Table with ID 15, length from above, - offset 64, width 16, and the data pointer from above */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, table); if (full) { if (dev->phy.rev >= 3) @@ -1902,9 +1897,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, /* TODO: Read an N PHY Table with ID 15, length table_length, offset 96, width 16, and data pointer buffer */ - /* TODO: Write an N PHY Table with ID 15, - length table_length, offset 64, width 16, - and data pointer buffer */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, + buffer); if (type == 1 || type == 3 || type == 4) buffer[0] = diq_start; @@ -1916,8 +1910,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, last = (dev->phy.rev < 3) ? 6 : 7; if (!mphase || nphy->mphase_cal_phase_id == last) { - /* TODO: Write an N PHY Table with ID 15, length 4, - offset 96, width 16, and data pointer buffer */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 96), 4, buffer); /* TODO: Read an N PHY Table with ID 15, length 4, offset 80, width 16, and data pointer buffer */ if (dev->phy.rev < 3) { @@ -1926,14 +1919,14 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, buffer[2] = 0; buffer[3] = 0; } - /* TODO: Write an N PHY Table with ID 15, length 4, - offset 88, width 16, and data pointer buffer */ - /* TODO: Read an N PHY Table with ID 15, length 2, - offset 101, width 16, and data pointer buffer*/ - /* TODO: Write an N PHY Table with ID 15, length 2, - offset 85, width 16, and data pointer buffer */ - /* TODO: Write an N PHY Table with ID 15, length 2, - offset 93, width 16, and data pointer buffer */ + b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, + buffer); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2, + buffer); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, + buffer); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, + buffer); length = 11; if (dev->phy.rev < 3) length -= 2; @@ -1957,8 +1950,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, } b43_nphy_tx_cal_phy_cleanup(dev); - /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data from save */ + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, save); if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last)) b43_nphy_tx_iq_workaround(dev); @@ -2008,8 +2000,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); cal_gain[i] = cal_params[i].cal_gain; } - /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data from cal_gain */ + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, cal_gain); for (i = 0; i < 2; i++) { if (i == 0) { @@ -2147,8 +2138,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data from gain_save */ + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); b43_nphy_stay_in_carrier_search(dev, 0); @@ -2290,8 +2280,10 @@ int b43_phy_initn(struct b43_wldev *dev) if (phy->rev >= 3) { /* TODO */ } else { - /* TODO Write an N PHY table with ID 26, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ - /* TODO Write an N PHY table with ID 27, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ + b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, + b43_ntab_tx_gain_rev0_1_2); + b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, + b43_ntab_tx_gain_rev0_1_2); } if (nphy->phyrxchain != 3) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 7dff853ab962..fc08be0b976e 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2952,6 +2952,46 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) assert_ntab_array_sizes(); } +void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data) +{ + u32 type, value; + const u8 *data = _data; + unsigned int i; + + type = offset & B43_NTAB_TYPEMASK; + offset &= ~B43_NTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_NTAB_8BIT: + value = *data; + data++; + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_16BIT: + value = *((u16 *)data); + data += 2; + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_32BIT: + value = *((u32 *)data); + data += 4; + b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + } +} + #define ntab_upload(dev, offset, data) do { \ unsigned int i; \ for (i = 0; i < (offset##_SIZE); i++) \ diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 51636d02f8b1..d5605df5d6b8 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -143,6 +143,8 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); +void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data); void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev); void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev); -- GitLab From 11380a4b2d86fae9a6bce75c9373668cc323fe57 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Jan 2010 13:46:10 -0800 Subject: [PATCH 0964/3892] net: Unexport napi_gro_flush(). Nothing outside of net/core/dev.c uses it. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 - net/core/dev.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a3fccc85b1a0..468a11dea58c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1527,7 +1527,6 @@ extern int netif_rx(struct sk_buff *skb); extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); -extern void napi_gro_flush(struct napi_struct *napi); extern gro_result_t dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb); extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); diff --git a/net/core/dev.c b/net/core/dev.c index a008f6987a95..5747b9edc1bb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2582,7 +2582,7 @@ out: return netif_receive_skb(skb); } -void napi_gro_flush(struct napi_struct *napi) +static void napi_gro_flush(struct napi_struct *napi) { struct sk_buff *skb, *next; @@ -2595,7 +2595,6 @@ void napi_gro_flush(struct napi_struct *napi) napi->gro_count = 0; napi->gro_list = NULL; } -EXPORT_SYMBOL(napi_gro_flush); enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { -- GitLab From c643a66ef5ccfd4d359327fb8afa9949f1abbfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Jan 2010 00:21:27 +0100 Subject: [PATCH 0965/3892] b43: N-PHY: implement and add reading one element tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 18 ++++++--------- drivers/net/wireless/b43/tables_nphy.c | 31 ++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 1 + 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 671fbcfdc0ec..7eac0ae2b15e 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1628,12 +1628,11 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG); b43_phy_mask(dev, B43_NPHY_BBCFG, ~B43_NPHY_BBCFG_RSTRX); - /* TODO: Read an N PHY Table with ID 8, length 1, offset 3, - width 16, and data pointing to tmp */ + tmp = b43_ntab_read(dev, B43_NTAB16(8, 3)); regs[5] = tmp; b43_ntab_write(dev, B43_NTAB16(8, 3), 0); - /* TODO: Read an N PHY Table with ID 8, length 1, offset 19, - width 16, and data pointing to tmp */ + + tmp = b43_ntab_read(dev, B43_NTAB16(8, 19)); regs[6] = tmp; b43_ntab_write(dev, B43_NTAB16(8, 19), 0); regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); @@ -1653,13 +1652,11 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); regs[2] = tmp; b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x3000); - /* TODO: Read an N PHY Table with ID 8, length 1, offset 2, - width 16, and data pointing to tmp */ + tmp = b43_ntab_read(dev, B43_NTAB16(8, 2)); regs[3] = tmp; tmp |= 0x2000; b43_ntab_write(dev, B43_NTAB16(8, 2), tmp); - /* TODO: Read an N PHY Table with ID 8, length 1, offset 18, - width 16, and data pointer tmp */ + tmp = b43_ntab_read(dev, B43_NTAB16(8, 18)); regs[4] = tmp; tmp |= 0x2000; b43_ntab_write(dev, B43_NTAB16(8, 18), tmp); @@ -1877,9 +1874,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp); if (type == 1 || type == 3 || type == 4) { - /* TODO: Read an N PHY Table with ID 15, - length 1, offset 69 + core, - width 16, and data pointer buffer */ + buffer[0] = b43_ntab_read(dev, + B43_NTAB16(15, 69 + core)); diq_start = buffer[0]; buffer[0] = 0; b43_ntab_write(dev, B43_NTAB16(15, 69 + core), diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index fc08be0b976e..b8aed456da1f 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2919,6 +2919,37 @@ static inline void assert_ntab_array_sizes(void) #undef check } +u32 b43_ntab_read(struct b43_wldev *dev, u32 offset) +{ + u32 type, value; + + type = offset & B43_NTAB_TYPEMASK; + offset &= ~B43_NTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + switch (type) { + case B43_NTAB_8BIT: + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF; + break; + case B43_NTAB_16BIT: + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + break; + case B43_NTAB_32BIT: + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); + value <<= 16; + value |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + break; + default: + B43_WARN_ON(1); + value = 0; + } + + return value; +} + void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) { u32 type; diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index d5605df5d6b8..64e990a14de3 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -142,6 +142,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10 #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 +u32 b43_ntab_read(struct b43_wldev *dev, u32 offset); void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *_data); -- GitLab From 9145834e84805f5efcca4706edfd641047af1d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Jan 2010 00:21:35 +0100 Subject: [PATCH 0966/3892] b43: N-PHY: implement and add multi-dimensional table reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 30 ++++++++-------------- drivers/net/wireless/b43/tables_nphy.c | 35 ++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 2 ++ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 7eac0ae2b15e..1359267a35ff 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -829,8 +829,7 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, true); - /* TODO: Read an N PHY Table with ID 15, length 7, offset 80, - width 16, and data pointer buffer */ + b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); for (i = 0; i < 2; i++) { tmp = ((buffer[i * 2] & 0x3FF) << 10) | @@ -1507,8 +1506,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, true); - /* TODO: Read an N PHY Table with ID 7, length 2, - offset 0x110, width 16, and curr_gain */ + b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, curr_gain); if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, false); @@ -1768,8 +1766,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, nphy->hang_avoid = 0; } - /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data pointer save */ + b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save); for (i = 0; i < 2; i++) { b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); @@ -1890,9 +1887,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, udelay(10); } - /* TODO: Read an N PHY Table with ID 15, - length table_length, offset 96, width 16, - and data pointer buffer */ + b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, + buffer); b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, buffer); @@ -1907,8 +1903,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, if (!mphase || nphy->mphase_cal_phase_id == last) { b43_ntab_write_bulk(dev, B43_NTAB16(15, 96), 4, buffer); - /* TODO: Read an N PHY Table with ID 15, length 4, - offset 80, width 16, and data pointer buffer */ + b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 4, buffer); if (dev->phy.rev < 3) { buffer[0] = 0; buffer[1] = 0; @@ -1926,9 +1921,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, length = 11; if (dev->phy.rev < 3) length -= 2; - /* TODO: Read an N PHY Table with ID 15, length length, - offset 96, width 16, and data pointer - nphy->txiqlocal_bestc */ + b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, + nphy->txiqlocal_bestc); nphy->txiqlocal_coeffsvalid = true; /* TODO: Set nphy->txiqlocal_chanspec to the current channel */ @@ -1936,9 +1930,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, length = 11; if (dev->phy.rev < 3) length -= 2; - /* TODO: Read an N PHY Table with ID 5, length length, - offset 96, width 16, and data pointer - nphy->mphase_txcal_bestcoeffs */ + b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, + nphy->mphase_txcal_bestcoeffs); } b43_nphy_stop_playback(dev); @@ -1990,8 +1983,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, if (dev->phy.rev < 2) ;/* TODO: Call N PHY Reapply TX Cal Coeffs */ - /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, - width 16, and data gain_save */ + b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); for (i = 0; i < 2; i++) { b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); cal_gain[i] = cal_params[i].cal_gain; diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index b8aed456da1f..b8c9fc619ab1 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2950,6 +2950,41 @@ u32 b43_ntab_read(struct b43_wldev *dev, u32 offset) return value; } +void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data) +{ + u32 type; + u8 *data = _data; + unsigned int i; + + type = offset & B43_NTAB_TYPEMASK; + offset &= ~B43_NTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_NTAB_8BIT: + *data = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF; + data++; + break; + case B43_NTAB_16BIT: + *((u16 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + data += 2; + break; + case B43_NTAB_32BIT: + *((u32 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); + *((u32 *)data) <<= 16; + *((u32 *)data) |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + data += 4; + break; + default: + B43_WARN_ON(1); + } + } +} + void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) { u32 type; diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 64e990a14de3..6bbef894010c 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -143,6 +143,8 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 u32 b43_ntab_read(struct b43_wldev *dev, u32 offset); +void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data); void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *_data); -- GitLab From de9a47f92795f697964f662415cb27816c2d9b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Jan 2010 00:21:49 +0100 Subject: [PATCH 0967/3892] b43: N-PHY: silence warnings, add missing call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1359267a35ff..e77f1f24d101 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1624,7 +1624,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600); regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_mask(dev, B43_NPHY_BBCFG, ~B43_NPHY_BBCFG_RSTRX); + b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX); tmp = b43_ntab_read(dev, B43_NTAB16(8, 3)); regs[5] = tmp; @@ -1970,7 +1970,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, u16 lna[3] = { 3, 3, 1 }; u16 hpf1[3] = { 7, 2, 0 }; u16 hpf2[3] = { 2, 0, 0 }; - u32 power[3]; + u32 power[3] = { }; u16 gain_save[2]; u16 cal_gain[2]; struct nphy_iqcal_params cal_params[2]; @@ -2077,7 +2077,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, (cur_lna << 2)); /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0], 3, 0 as arguments */ - /* TODO: Call N PHY Force RF Seq with 2 as argument */ + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); b43_nphy_stop_playback(dev); if (playtone) { -- GitLab From 1625c148cde23a8b4180e171ed4a17e17521b995 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 19 Jan 2010 00:19:21 +0100 Subject: [PATCH 0968/3892] libertas: Set/clear WPA keys before the WEP ones With the v10 firmware running on 8688 HW, clearing WPA keys after setting the WEP key prevents us from being able to associate with WEP APs. Swapping the calling order for assoc_helper_wpa_keys() and assoc_helper_wep_keys fixes that issue. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5e650f358415..fb3dff0fdfa8 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -2052,13 +2052,6 @@ void lbs_association_worker(struct work_struct *work) goto out; } - if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) - || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { - ret = assoc_helper_wep_keys(priv, assoc_req); - if (ret) - goto out; - } - if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { ret = assoc_helper_secinfo(priv, assoc_req); if (ret) @@ -2078,6 +2071,14 @@ void lbs_association_worker(struct work_struct *work) goto out; } + if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { + ret = assoc_helper_wep_keys(priv, assoc_req); + if (ret) + goto out; + } + + /* SSID/BSSID should be the _last_ config option set, because they * trigger the association attempt. */ -- GitLab From 27e310c91c3433ab9997b925b3fd65e660634c76 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 Jan 2010 10:53:30 -0800 Subject: [PATCH 0969/3892] nl80211: Allow association to change channels during reassociation nl80211_associate() was rejecting (re)association attempts with EBUSY in some cases where we are currently associated with an AP that uses different channel from the destination AP. Fix this by passing the current wdev to rdev_fixed_channel() in the same way that was already done for join-IBSS and connect commands. This allows the fixedchan check to skipped for the current wdev and allows the reassociation to proceed. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4af7991a9ec8..5b79ecf17bea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3571,6 +3571,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; struct net_device *dev; + struct wireless_dev *wdev; struct cfg80211_crypto_settings crypto; struct ieee80211_channel *chan, *fixedchan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; @@ -3616,7 +3617,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } mutex_lock(&rdev->devlist_mtx); - fixedchan = rdev_fixed_channel(rdev, NULL); + wdev = dev->ieee80211_ptr; + fixedchan = rdev_fixed_channel(rdev, wdev); if (fixedchan && chan != fixedchan) { err = -EBUSY; mutex_unlock(&rdev->devlist_mtx); -- GitLab From c9f6a6567f3e8dd69dd3f80a67e73d7d10884bea Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 19 Jan 2010 14:04:19 -0500 Subject: [PATCH 0970/3892] ath9k: make tx power config changes take effect immediatley Users wishing to tweak tx power want it to happen immediately, try to respect that. This was tested by Lorenzo by measuring the received signal strength from an AP with ath9k and the patch. Changing the tx power on the AP produced these results: 1) iwconfig wlan0 txpower 20 ---> Rx power -37dbm 2) iwconfig wlan0 txpower 15 ---> Rx power -41dbm 3) iwconfig wlan0 txpower 10 ---> Rx power -45dbm 4) iwconfig wlan0 txpower 5 ---> Rx power -51dbm 5) iwconfig wlan0 txpower 0 ---> Rx power -37dbm The result with 0 is an anomoly and would need to be addressed through a separate patch. Signed-off-by: Luis R. Rodriguez Tested-by: Lorenzo Bianconi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c0c571c2e8c4..6f3e71c5071e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1624,8 +1624,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } skip_chan_change: - if (changed & IEEE80211_CONF_CHANGE_POWER) + if (changed & IEEE80211_CONF_CHANGE_POWER) { sc->config.txpowlimit = 2 * conf->power_level; + ath_update_txpow(sc); + } spin_lock_bh(&sc->wiphy_lock); disable_radio = ath9k_all_wiphys_idle(sc); -- GitLab From 64147c729732ba9c9e50966971bdfbd503c888bb Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 19 Jan 2010 17:07:41 -0500 Subject: [PATCH 0971/3892] libertas/assoc.c: rearrange some strange line breaks Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 62 +++++++++++++-------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index fb3dff0fdfa8..0979b07799a0 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1160,11 +1160,11 @@ int lbs_adhoc_stop(struct lbs_private *priv) static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != WLAN_EID_GENERIC - && match_bss->rsn_ie[0] != WLAN_EID_RSN - && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (!secinfo->wep_enabled && + !secinfo->WPAenabled && !secinfo->WPA2enabled && + match_bss->wpa_ie[0] != WLAN_EID_GENERIC && + match_bss->rsn_ie[0] != WLAN_EID_RSN && + !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1173,9 +1173,9 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (secinfo->wep_enabled && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (secinfo->wep_enabled && + !secinfo->WPAenabled && !secinfo->WPA2enabled && + (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1184,8 +1184,8 @@ static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) + if (!secinfo->wep_enabled && secinfo->WPAenabled && + (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -1210,11 +1210,11 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) - && (match_bss->rsn_ie[0] != WLAN_EID_RSN) - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (!secinfo->wep_enabled && + !secinfo->WPAenabled && !secinfo->WPA2enabled && + (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) && + (match_bss->rsn_ie[0] != WLAN_EID_RSN) && + (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1525,8 +1525,8 @@ static int assoc_helper_associate(struct lbs_private *priv, /* If we're given and 'any' BSSID, try associating based on SSID */ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (compare_ether_addr(bssid_any, assoc_req->bssid) - && compare_ether_addr(bssid_off, assoc_req->bssid)) { + if (compare_ether_addr(bssid_any, assoc_req->bssid) && + compare_ether_addr(bssid_off, assoc_req->bssid)) { ret = assoc_helper_bssid(priv, assoc_req); done = 1; } @@ -1612,11 +1612,9 @@ static int assoc_helper_channel(struct lbs_private *priv, goto restore_mesh; } - if ( assoc_req->secinfo.wep_enabled - && (assoc_req->wep_keys[0].len - || assoc_req->wep_keys[1].len - || assoc_req->wep_keys[2].len - || assoc_req->wep_keys[3].len)) { + if (assoc_req->secinfo.wep_enabled && + (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || + assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) { /* Make sure WEP keys are re-sent to firmware */ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); } @@ -1983,14 +1981,14 @@ void lbs_association_worker(struct work_struct *work) assoc_req->secinfo.auth_mode); /* If 'any' SSID was specified, find an SSID to associate with */ - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) - && !assoc_req->ssid_len) + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) && + !assoc_req->ssid_len) find_any_ssid = 1; /* But don't use 'any' SSID if there's a valid locked BSSID to use */ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (compare_ether_addr(assoc_req->bssid, bssid_any) - && compare_ether_addr(assoc_req->bssid, bssid_off)) + if (compare_ether_addr(assoc_req->bssid, bssid_any) && + compare_ether_addr(assoc_req->bssid, bssid_off)) find_any_ssid = 0; } @@ -2064,15 +2062,15 @@ void lbs_association_worker(struct work_struct *work) goto out; } - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) - || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) || + test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); if (ret) goto out; } - if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) - || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { + if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) || + test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { ret = assoc_helper_wep_keys(priv, assoc_req); if (ret) goto out; @@ -2082,8 +2080,8 @@ void lbs_association_worker(struct work_struct *work) /* SSID/BSSID should be the _last_ config option set, because they * trigger the association attempt. */ - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) - || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) || + test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { int success = 1; ret = assoc_helper_associate(priv, assoc_req); -- GitLab From 7981d6f6b280d28779343cff4a88029fe53d1b47 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 19 Jan 2010 14:23:57 -0800 Subject: [PATCH 0972/3892] tipc: Clean up configuration file This patch addresses a number of minor (mostly cosmetic) issues relating to the configuration of TIPC, including the following: - Corrects range limits for maximum number of ports per node - Adds missing range limits for size of log buffer - Removes configuration setting relating to unsupported slave node capability - Standardizes description and help text wording for configuration settings - Removes unneeded blank spaces Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/Kconfig | 73 ++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index dafbd533067c..b74f78d0c033 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig @@ -10,7 +10,7 @@ menuconfig TIPC specially designed for intra cluster communication. This protocol originates from Ericsson where it has been used in carrier grade cluster applications for many years. - + For more information about TIPC, see http://tipc.sourceforge.net. This protocol support is also available as a module ( = code which @@ -23,24 +23,23 @@ menuconfig TIPC if TIPC config TIPC_ADVANCED - bool "TIPC: Advanced configuration" + bool "Advanced TIPC configuration" default n help - Saying Y here will open some advanced configuration - for TIPC. Most users do not need to bother, so if - unsure, just say N. + Saying Y here will open some advanced configuration for TIPC. + Most users do not need to bother; if unsure, just say N. config TIPC_ZONES - int "Maximum number of zones in network" + int "Maximum number of zones in a network" depends on TIPC_ADVANCED range 1 255 default "3" help - Max number of zones inside TIPC network. Max supported value - is 255 zones, minimum is 1 + Specifies how many zones can be supported in a TIPC network. + Can range from 1 to 255 zones; default is 3. - Default is 3 zones in a network; setting this to higher - allows more zones but might use more memory. + Setting this to a smaller value saves some memory; + setting it to a higher value allows for more zones. config TIPC_CLUSTERS int "Maximum number of clusters in a zone" @@ -48,70 +47,52 @@ config TIPC_CLUSTERS range 1 1 default "1" help - ***Only 1 (one cluster in a zone) is supported by current code.*** - - (Max number of clusters inside TIPC zone. Max supported - value is 4095 clusters, minimum is 1. + Specifies how many clusters can be supported in a TIPC zone. - Default is 1; setting this to smaller value might save - some memory, setting it to higher - allows more clusters and might consume more memory.) + *** Currently TIPC only supports a single cluster per zone. *** config TIPC_NODES - int "Maximum number of nodes in cluster" + int "Maximum number of nodes in a cluster" depends on TIPC_ADVANCED range 8 2047 default "255" help - Maximum number of nodes inside a TIPC cluster. Maximum - supported value is 2047 nodes, minimum is 8. - - Setting this to a smaller value saves some memory, - setting it to higher allows more nodes. - -config TIPC_SLAVE_NODES - int "Maximum number of slave nodes in cluster" - depends on TIPC_ADVANCED - range 0 2047 - default "0" - help - ***This capability is not supported by current code.*** - - Maximum number of slave nodes inside a TIPC cluster. Maximum - supported value is 2047 nodes, minimum is 0. + Specifies how many nodes can be supported in a TIPC cluster. + Can range from 8 to 2047 nodes; default is 255. - Setting this to a smaller value saves some memory, - setting it to higher allows more nodes. + Setting this to a smaller value saves some memory; + setting it to higher allows for more nodes. config TIPC_PORTS int "Maximum number of ports in a node" depends on TIPC_ADVANCED - range 217 65536 + range 127 65535 default "8191" help - Maximum number of ports within a node. Maximum - supported value is 64535 nodes, minimum is 127. + Specifies how many ports can be supported by a node. + Can range from 127 to 65535 ports; default is 8191. Setting this to a smaller value saves some memory, - setting it to higher allows more ports. + setting it to higher allows for more ports. config TIPC_LOG int "Size of log buffer" depends on TIPC_ADVANCED - default 0 + range 0 32768 + default "0" help - Size (in bytes) of TIPC's internal log buffer, which records the - occurrence of significant events. Maximum supported value - is 32768 bytes, minimum is 0. + Size (in bytes) of TIPC's internal log buffer, which records the + occurrence of significant events. Can range from 0 to 32768 bytes; + default is 0. There is no need to enable the log buffer unless the node will be managed remotely via TIPC. config TIPC_DEBUG - bool "Enable debugging support" + bool "Enable debug messages" default n help - This will enable debugging of TIPC. + This enables debugging of TIPC. Only say Y here if you are having trouble with TIPC. It will enable the display of detailed information about what is going on. -- GitLab From e2bcd936eb95d0019ca5e05f9fdd27e770ddded1 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:44:58 +1100 Subject: [PATCH 0973/3892] xfs: directory names are unsigned Convert the struct xfs_name to use unsigned chars for the name strings to match both what is stored on disk (__uint8_t) and what the VFS expects (unsigned char). Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index d725428c9df6..b09904555d07 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h @@ -151,8 +151,8 @@ typedef enum { } xfs_btnum_t; struct xfs_name { - const char *name; - int len; + const unsigned char *name; + int len; }; #endif /* __XFS_TYPES_H__ */ -- GitLab From 046ea753130fc51d885835458bf8c1d84765b9ac Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:47:08 +1100 Subject: [PATCH 0974/3892] xfs: convert DM ops to use unsigned char names dmops uses a signed char for it's namespace event. To be consistent with the rest of the code, convert them to unsigned char for the namespace string. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_mount.h | 3 ++- fs/xfs/xfs_vnodeops.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index e62fd1cde464..f4d1441f3f15 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -78,7 +78,8 @@ typedef int (*xfs_send_destroy_t)(struct xfs_inode *, dm_right_t); typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *, struct xfs_inode *, dm_right_t, struct xfs_inode *, dm_right_t, - const char *, const char *, mode_t, int, int); + const unsigned char *, const unsigned char *, + mode_t, int, int); typedef int (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t, char *, char *); typedef void (*xfs_send_unmount_t)(struct xfs_mount *, struct xfs_inode *, diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 6f268756bf36..9f7c001ef469 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -2199,7 +2199,8 @@ xfs_symlink( if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, - link_name->name, target_path, 0, 0, 0); + link_name->name, + (unsigned char *)target_path, 0, 0, 0); if (error) return error; } @@ -2395,7 +2396,8 @@ std_return: dp, DM_RIGHT_NULL, error ? NULL : ip, DM_RIGHT_NULL, link_name->name, - target_path, 0, error, 0); + (unsigned char *)target_path, + 0, error, 0); } if (!error) -- GitLab From 2bc754213d40d67c39ddd58cf240f2b948e1951e Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:47:17 +1100 Subject: [PATCH 0975/3892] xfs: convert dirnameops to unsigned char names To be consistent across the codebase, convert the dirnameops to pass the directory names by unsigned char strings. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_da_btree.c | 4 ++-- fs/xfs/xfs_da_btree.h | 5 +++-- fs/xfs/xfs_dir2.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index c0c8869115b1..0ca556b4bf31 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -1534,8 +1534,8 @@ xfs_da_hashname(const __uint8_t *name, int namelen) enum xfs_dacmp xfs_da_compname( struct xfs_da_args *args, - const char *name, - int len) + const unsigned char *name, + int len) { return (args->namelen == len && memcmp(args->name, name, len) == 0) ? XFS_CMP_EXACT : XFS_CMP_DIFFERENT; diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 30cd08f56a3a..fe9f5a8c1d2a 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -209,7 +209,8 @@ typedef struct xfs_da_state { */ struct xfs_nameops { xfs_dahash_t (*hashname)(struct xfs_name *); - enum xfs_dacmp (*compname)(struct xfs_da_args *, const char *, int); + enum xfs_dacmp (*compname)(struct xfs_da_args *, + const unsigned char *, int); }; @@ -260,7 +261,7 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, uint xfs_da_hashname(const __uint8_t *name_string, int name_length); enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, - const char *name, int len); + const unsigned char *name, int len); xfs_da_state_t *xfs_da_state_alloc(void); diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 93634a7e90e9..c21c527766bf 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -66,8 +66,8 @@ xfs_ascii_ci_hashname( STATIC enum xfs_dacmp xfs_ascii_ci_compname( struct xfs_da_args *args, - const char *name, - int len) + const unsigned char *name, + int len) { enum xfs_dacmp result; int i; -- GitLab From a3380ae39fa321282c407ba5e1835e14b64853d9 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:47:25 +1100 Subject: [PATCH 0976/3892] xfs: make xfs_dir_cilookup_result use unsigned char For consistency with the result of the code. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_dir2.c | 2 +- fs/xfs/xfs_dir2.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index c21c527766bf..3a8c6ba0638f 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -247,7 +247,7 @@ xfs_dir_createname( int xfs_dir_cilookup_result( struct xfs_da_args *args, - const char *name, + const unsigned char *name, int len) { if (args->cmpresult == XFS_CMP_DIFFERENT) diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index 1d9ef96f33aa..74a3b1057685 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h @@ -100,7 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_dabuf *bp); -extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name, - int len); +extern int xfs_dir_cilookup_result(struct xfs_da_args *args, + const unsigned char *name, int len); #endif /* __XFS_DIR2_H__ */ -- GitLab From b9c48649577dfc4a8c263c106d518effa24ea54b Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:47:39 +1100 Subject: [PATCH 0977/3892] xfs: xfs_buf_iomove() doesn't care about signedness xfs_buf_iomove() uses xfs_caddr_t as it's parameter types, but it doesn't care about the signedness of the variables as it is just copying the data. Change the prototype to use void * so that we don't get sign warnings at call sites. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_buf.c | 2 +- fs/xfs/linux-2.6/xfs_buf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 158fad4550df..efd745bb8887 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1443,7 +1443,7 @@ xfs_buf_iomove( xfs_buf_t *bp, /* buffer to process */ size_t boff, /* starting buffer offset */ size_t bsize, /* length to copy */ - caddr_t data, /* data address */ + void *data, /* data address */ xfs_buf_rw_t mode) /* read/write/zero flag */ { size_t bend, cpoff, csize; diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 9a29d18656ec..4f2ad66edb76 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -243,7 +243,7 @@ extern void xfs_buf_ioend(xfs_buf_t *, int); extern void xfs_buf_ioerror(xfs_buf_t *, int); extern int xfs_buf_iorequest(xfs_buf_t *); extern int xfs_buf_iowait(xfs_buf_t *); -extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, xfs_caddr_t, +extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *, xfs_buf_rw_t); static inline int xfs_buf_iostrategy(xfs_buf_t *bp) -- GitLab From a9273ca5c6814f393e18ed66645f817b2b71e9ad Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:47:48 +1100 Subject: [PATCH 0978/3892] xfs: convert attr to use unsigned names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be consistent with the directory code, the attr code should use unsigned names. Convert the names from the vfs at the highest level to unsigned, and ænsure they are consistenly used as unsigned down to disk. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_acl.c | 11 +++++----- fs/xfs/linux-2.6/xfs_ioctl.c | 18 ++++++++-------- fs/xfs/linux-2.6/xfs_ioctl.h | 12 +++++------ fs/xfs/linux-2.6/xfs_ioctl32.c | 4 ++-- fs/xfs/linux-2.6/xfs_iops.c | 4 ++-- fs/xfs/linux-2.6/xfs_xattr.c | 27 +++++++++++++++++------- fs/xfs/xfs_acl.h | 4 ++-- fs/xfs/xfs_attr.c | 38 ++++++++++++++++++++-------------- fs/xfs/xfs_attr.h | 2 +- fs/xfs/xfs_attr_leaf.c | 28 ++++++++++++------------- fs/xfs/xfs_attr_sf.h | 2 +- fs/xfs/xfs_vnodeops.h | 10 ++++----- 12 files changed, 90 insertions(+), 70 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index 883ca5ab8af5..bf85bbe4a9ae 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c @@ -106,7 +106,7 @@ xfs_get_acl(struct inode *inode, int type) struct posix_acl *acl; struct xfs_acl *xfs_acl; int len = sizeof(struct xfs_acl); - char *ea_name; + unsigned char *ea_name; int error; acl = get_cached_acl(inode, type); @@ -133,7 +133,8 @@ xfs_get_acl(struct inode *inode, int type) if (!xfs_acl) return ERR_PTR(-ENOMEM); - error = -xfs_attr_get(ip, ea_name, (char *)xfs_acl, &len, ATTR_ROOT); + error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, + &len, ATTR_ROOT); if (error) { /* * If the attribute doesn't exist make sure we have a negative @@ -162,7 +163,7 @@ STATIC int xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct xfs_inode *ip = XFS_I(inode); - char *ea_name; + unsigned char *ea_name; int error; if (S_ISLNK(inode->i_mode)) @@ -194,7 +195,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) (sizeof(struct xfs_acl_entry) * (XFS_ACL_MAX_ENTRIES - acl->a_count)); - error = -xfs_attr_set(ip, ea_name, (char *)xfs_acl, + error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, len, ATTR_ROOT); kfree(xfs_acl); @@ -262,7 +263,7 @@ xfs_set_mode(struct inode *inode, mode_t mode) } static int -xfs_acl_exists(struct inode *inode, char *name) +xfs_acl_exists(struct inode *inode, unsigned char *name) { int len = sizeof(struct xfs_acl); diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index a034cf624437..3906e85abfdc 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -447,12 +447,12 @@ xfs_attrlist_by_handle( int xfs_attrmulti_attr_get( struct inode *inode, - char *name, - char __user *ubuf, + unsigned char *name, + unsigned char __user *ubuf, __uint32_t *len, __uint32_t flags) { - char *kbuf; + unsigned char *kbuf; int error = EFAULT; if (*len > XATTR_SIZE_MAX) @@ -476,12 +476,12 @@ xfs_attrmulti_attr_get( int xfs_attrmulti_attr_set( struct inode *inode, - char *name, - const char __user *ubuf, + unsigned char *name, + const unsigned char __user *ubuf, __uint32_t len, __uint32_t flags) { - char *kbuf; + unsigned char *kbuf; int error = EFAULT; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) @@ -501,7 +501,7 @@ xfs_attrmulti_attr_set( int xfs_attrmulti_attr_remove( struct inode *inode, - char *name, + unsigned char *name, __uint32_t flags) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) @@ -519,7 +519,7 @@ xfs_attrmulti_by_handle( xfs_fsop_attrmulti_handlereq_t am_hreq; struct dentry *dentry; unsigned int i, size; - char *attr_name; + unsigned char *attr_name; if (!capable(CAP_SYS_ADMIN)) return -XFS_ERROR(EPERM); @@ -547,7 +547,7 @@ xfs_attrmulti_by_handle( error = 0; for (i = 0; i < am_hreq.opcount; i++) { - ops[i].am_error = strncpy_from_user(attr_name, + ops[i].am_error = strncpy_from_user((char *)attr_name, ops[i].am_attrname, MAXNAMELEN); if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) error = -ERANGE; diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/linux-2.6/xfs_ioctl.h index 7bd7c6afc1eb..d56173b34a2a 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.h +++ b/fs/xfs/linux-2.6/xfs_ioctl.h @@ -45,23 +45,23 @@ xfs_readlink_by_handle( extern int xfs_attrmulti_attr_get( struct inode *inode, - char *name, - char __user *ubuf, + unsigned char *name, + unsigned char __user *ubuf, __uint32_t *len, __uint32_t flags); extern int - xfs_attrmulti_attr_set( +xfs_attrmulti_attr_set( struct inode *inode, - char *name, - const char __user *ubuf, + unsigned char *name, + const unsigned char __user *ubuf, __uint32_t len, __uint32_t flags); extern int xfs_attrmulti_attr_remove( struct inode *inode, - char *name, + unsigned char *name, __uint32_t flags); extern struct dentry * diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index be1527b1670c..0bf6d61f0528 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -411,7 +411,7 @@ xfs_compat_attrmulti_by_handle( compat_xfs_fsop_attrmulti_handlereq_t am_hreq; struct dentry *dentry; unsigned int i, size; - char *attr_name; + unsigned char *attr_name; if (!capable(CAP_SYS_ADMIN)) return -XFS_ERROR(EPERM); @@ -440,7 +440,7 @@ xfs_compat_attrmulti_by_handle( error = 0; for (i = 0; i < am_hreq.opcount; i++) { - ops[i].am_error = strncpy_from_user(attr_name, + ops[i].am_error = strncpy_from_user((char *)attr_name, compat_ptr(ops[i].am_attrname), MAXNAMELEN); if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 225946012d0b..e8566bbf0f00 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -140,10 +140,10 @@ xfs_init_security( struct xfs_inode *ip = XFS_I(inode); size_t length; void *value; - char *name; + unsigned char *name; int error; - error = security_inode_init_security(inode, dir, &name, + error = security_inode_init_security(inode, dir, (char **)&name, &value, &length); if (error) { if (error == -EOPNOTSUPP) diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/linux-2.6/xfs_xattr.c index 0b1878857fc3..fa01b9daba6b 100644 --- a/fs/xfs/linux-2.6/xfs_xattr.c +++ b/fs/xfs/linux-2.6/xfs_xattr.c @@ -45,7 +45,7 @@ xfs_xattr_get(struct dentry *dentry, const char *name, value = NULL; } - error = -xfs_attr_get(ip, name, value, &asize, xflags); + error = -xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); if (error) return error; return asize; @@ -67,8 +67,9 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, xflags |= ATTR_REPLACE; if (!value) - return -xfs_attr_remove(ip, name, xflags); - return -xfs_attr_set(ip, name, (void *)value, size, xflags); + return -xfs_attr_remove(ip, (unsigned char *)name, xflags); + return -xfs_attr_set(ip, (unsigned char *)name, + (void *)value, size, xflags); } static struct xattr_handler xfs_xattr_user_handler = { @@ -124,8 +125,13 @@ static const char *xfs_xattr_prefix(int flags) } static int -xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags, - char *name, int namelen, int valuelen, char *value) +xfs_xattr_put_listent( + struct xfs_attr_list_context *context, + int flags, + unsigned char *name, + int namelen, + int valuelen, + unsigned char *value) { unsigned int prefix_len = xfs_xattr_prefix_len(flags); char *offset; @@ -148,7 +154,7 @@ xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags, offset = (char *)context->alist + context->count; strncpy(offset, xfs_xattr_prefix(flags), prefix_len); offset += prefix_len; - strncpy(offset, name, namelen); /* real name */ + strncpy(offset, (char *)name, namelen); /* real name */ offset += namelen; *offset = '\0'; context->count += prefix_len + namelen + 1; @@ -156,8 +162,13 @@ xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags, } static int -xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags, - char *name, int namelen, int valuelen, char *value) +xfs_xattr_put_listent_sizes( + struct xfs_attr_list_context *context, + int flags, + unsigned char *name, + int namelen, + int valuelen, + unsigned char *value) { context->count += xfs_xattr_prefix_len(flags) + namelen + 1; return 0; diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 00fd357c3e46..d13eeba2c8f8 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -36,8 +36,8 @@ struct xfs_acl { }; /* On-disk XFS extended attribute names */ -#define SGI_ACL_FILE "SGI_ACL_FILE" -#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" +#define SGI_ACL_FILE (unsigned char *)"SGI_ACL_FILE" +#define SGI_ACL_DEFAULT (unsigned char *)"SGI_ACL_DEFAULT" #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 9d11ebad43b6..f7b426a1b6ee 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -93,12 +93,12 @@ STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); STATIC int xfs_attr_name_to_xname( struct xfs_name *xname, - const char *aname) + const unsigned char *aname) { if (!aname) return EINVAL; xname->name = aname; - xname->len = strlen(aname); + xname->len = strlen((char *)aname); if (xname->len >= MAXNAMELEN) return EFAULT; /* match IRIX behaviour */ @@ -124,7 +124,7 @@ STATIC int xfs_attr_get_int( struct xfs_inode *ip, struct xfs_name *name, - char *value, + unsigned char *value, int *valuelenp, int flags) { @@ -171,8 +171,8 @@ xfs_attr_get_int( int xfs_attr_get( xfs_inode_t *ip, - const char *name, - char *value, + const unsigned char *name, + unsigned char *value, int *valuelenp, int flags) { @@ -235,8 +235,12 @@ xfs_attr_calc_size( } STATIC int -xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, - char *value, int valuelen, int flags) +xfs_attr_set_int( + struct xfs_inode *dp, + struct xfs_name *name, + unsigned char *value, + int valuelen, + int flags) { xfs_da_args_t args; xfs_fsblock_t firstblock; @@ -452,8 +456,8 @@ out: int xfs_attr_set( xfs_inode_t *dp, - const char *name, - char *value, + const unsigned char *name, + unsigned char *value, int valuelen, int flags) { @@ -600,7 +604,7 @@ out: int xfs_attr_remove( xfs_inode_t *dp, - const char *name, + const unsigned char *name, int flags) { int error; @@ -669,9 +673,13 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) */ /*ARGSUSED*/ STATIC int -xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags, - char *name, int namelen, - int valuelen, char *value) +xfs_attr_put_listent( + xfs_attr_list_context_t *context, + int flags, + unsigned char *name, + int namelen, + int valuelen, + unsigned char *value) { struct attrlist *alist = (struct attrlist *)context->alist; attrlist_ent_t *aep; @@ -1980,7 +1988,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; xfs_mount_t *mp; xfs_daddr_t dblkno; - xfs_caddr_t dst; + void *dst; xfs_buf_t *bp; int nmap, error, tmp, valuelen, blkcnt, i; xfs_dablk_t lblkno; @@ -2039,7 +2047,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) xfs_inode_t *dp; xfs_bmbt_irec_t map; xfs_daddr_t dblkno; - xfs_caddr_t src; + void *src; xfs_buf_t *bp; xfs_dablk_t lblkno; int blkcnt, valuelen, nmap, error, tmp, committed; diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 9c3a24372914..e920d68ef509 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -113,7 +113,7 @@ typedef struct attrlist_cursor_kern { typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int, - char *, int, int, char *); + unsigned char *, int, int, unsigned char *); typedef struct xfs_attr_list_context { struct xfs_inode *dp; /* inode */ diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index baf41b5af756..52519a201849 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -521,11 +521,11 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; i++) { - nargs.name = (char *)sfe->nameval; + nargs.name = sfe->nameval; nargs.namelen = sfe->namelen; - nargs.value = (char *)&sfe->nameval[nargs.namelen]; + nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; - nargs.hashval = xfs_da_hashname((char *)sfe->nameval, + nargs.hashval = xfs_da_hashname(sfe->nameval, sfe->namelen); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags); error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ @@ -612,10 +612,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { error = context->put_listent(context, sfe->flags, - (char *)sfe->nameval, + sfe->nameval, (int)sfe->namelen, (int)sfe->valuelen, - (char*)&sfe->nameval[sfe->namelen]); + &sfe->nameval[sfe->namelen]); /* * Either search callback finished early or @@ -659,8 +659,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) } sbp->entno = i; - sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); - sbp->name = (char *)sfe->nameval; + sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen); + sbp->name = sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ sbp->valuelen = sfe->valuelen; @@ -818,9 +818,9 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) continue; ASSERT(entry->flags & XFS_ATTR_LOCAL); name_loc = xfs_attr_leaf_name_local(leaf, i); - nargs.name = (char *)name_loc->nameval; + nargs.name = name_loc->nameval; nargs.namelen = name_loc->namelen; - nargs.value = (char *)&name_loc->nameval[nargs.namelen]; + nargs.value = &name_loc->nameval[nargs.namelen]; nargs.valuelen = be16_to_cpu(name_loc->valuelen); nargs.hashval = be32_to_cpu(entry->hashval); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags); @@ -2370,10 +2370,10 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) retval = context->put_listent(context, entry->flags, - (char *)name_loc->nameval, + name_loc->nameval, (int)name_loc->namelen, be16_to_cpu(name_loc->valuelen), - (char *)&name_loc->nameval[name_loc->namelen]); + &name_loc->nameval[name_loc->namelen]); if (retval) return retval; } else { @@ -2397,15 +2397,15 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) return retval; retval = context->put_listent(context, entry->flags, - (char *)name_rmt->name, + name_rmt->name, (int)name_rmt->namelen, valuelen, - (char*)args.value); + args.value); kmem_free(args.value); } else { retval = context->put_listent(context, entry->flags, - (char *)name_rmt->name, + name_rmt->name, (int)name_rmt->namelen, valuelen, NULL); diff --git a/fs/xfs/xfs_attr_sf.h b/fs/xfs/xfs_attr_sf.h index 76ab7b0cbb3a..919756e3ba53 100644 --- a/fs/xfs/xfs_attr_sf.h +++ b/fs/xfs/xfs_attr_sf.h @@ -52,7 +52,7 @@ typedef struct xfs_attr_sf_sort { __uint8_t valuelen; /* length of value */ __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ - char *name; /* name value, pointer into buffer */ + unsigned char *name; /* name value, pointer into buffer */ } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 167a467403a5..774f40729ca1 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -43,11 +43,11 @@ int xfs_change_file_space(struct xfs_inode *ip, int cmd, int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, struct xfs_inode *src_ip, struct xfs_inode *target_dp, struct xfs_name *target_name, struct xfs_inode *target_ip); -int xfs_attr_get(struct xfs_inode *ip, const char *name, char *value, - int *valuelenp, int flags); -int xfs_attr_set(struct xfs_inode *dp, const char *name, char *value, - int valuelen, int flags); -int xfs_attr_remove(struct xfs_inode *dp, const char *name, int flags); +int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, + unsigned char *value, int *valuelenp, int flags); +int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, + unsigned char *value, int valuelen, int flags); +int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int flags, struct attrlist_cursor_kern *cursor); ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb, -- GitLab From 4a24cb71407dc25035d75dd3d118e0e55679e217 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:48:05 +1100 Subject: [PATCH 0979/3892] xfs: clean up sign warnings in dir2 code We are now consistently using unsigned char strings for names so fix up the remaining warnings in the dir2 code to complete the cleanup. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_dir2.c | 2 +- fs/xfs/xfs_dir2_block.c | 9 +++++---- fs/xfs/xfs_dir2_leaf.c | 2 +- fs/xfs/xfs_dir2_sf.c | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 3a8c6ba0638f..42520f041265 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -44,7 +44,7 @@ #include "xfs_vnodeops.h" #include "xfs_trace.h" -struct xfs_name xfs_name_dotdot = {"..", 2}; +struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2}; /* * ASCII case-insensitive (ie. A-Z) support for directories that was diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index ddc4ecc7807f..779a267b0a84 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -57,8 +57,8 @@ static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; void xfs_dir_startup(void) { - xfs_dir_hash_dot = xfs_da_hashname(".", 1); - xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); + xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1); + xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); } /* @@ -513,8 +513,9 @@ xfs_dir2_block_getdents( /* * If it didn't fit, set the final offset to here & return. */ - if (filldir(dirent, dep->name, dep->namelen, cook & 0x7fffffff, - be64_to_cpu(dep->inumber), DT_UNKNOWN)) { + if (filldir(dirent, (char *)dep->name, dep->namelen, + cook & 0x7fffffff, be64_to_cpu(dep->inumber), + DT_UNKNOWN)) { *offset = cook & 0x7fffffff; xfs_da_brelse(NULL, bp); return 0; diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 29f484c11b3a..e2d89854ec9e 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -1081,7 +1081,7 @@ xfs_dir2_leaf_getdents( dep = (xfs_dir2_data_entry_t *)ptr; length = xfs_dir2_data_entsize(dep->namelen); - if (filldir(dirent, dep->name, dep->namelen, + if (filldir(dirent, (char *)dep->name, dep->namelen, xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff, be64_to_cpu(dep->inumber), DT_UNKNOWN)) break; diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 9d4f17a69676..c1a5945d463a 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c @@ -782,7 +782,7 @@ xfs_dir2_sf_getdents( } ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep)); - if (filldir(dirent, sfep->name, sfep->namelen, + if (filldir(dirent, (char *)sfep->name, sfep->namelen, off & 0x7fffffff, ino, DT_UNKNOWN)) { *offset = off & 0x7fffffff; return 0; -- GitLab From 58c75cfb51393a52b45262394c1fa81514b4d9bd Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:49:18 +1100 Subject: [PATCH 0980/3892] xfs: make compile warn about char sign mismatches again The -fno-unsigned-char directive has no effect anymore as the XFs build is clean. However, the kernel build hides pointer sign differences so turn that back on so that we can clean up all the mismatches prior to a userspace code resync. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 56641fe52a23..19267019dacf 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -16,7 +16,7 @@ # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 -funsigned-char +EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 -Wpointer-sign XFS_LINUX := linux-2.6 -- GitLab From f0a0eaa8da08ebc6519cacd731df05bbb4ca47ce Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 10:50:06 +1100 Subject: [PATCH 0981/3892] xfs: suppress spurious uninitialised var warning in xfs_bmapi() Initialise the xfs_bmalloca_t structure to zero to avoid uninitialised variable warnings. This is done by zeroing the arg structure rather than using the uninitialised_var() trick so we know for certain that the structure is correctly initialised as xfs_bmapi is a very complex function and it is difficult to prove warnings are spurious. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_bmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 7c6d9acd7154..1869fb973819 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -4471,7 +4471,7 @@ xfs_bmapi( xfs_fsblock_t abno; /* allocated block number */ xfs_extlen_t alen; /* allocated extent length */ xfs_fileoff_t aoff; /* allocated file offset */ - xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ + xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */ xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_fileoff_t end; /* end of mapped file region */ int eof; /* we've hit the end of extents */ -- GitLab From 587aa0feb74ffe3239b5e26ff5d017ba9f5daec9 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 20 Jan 2010 12:04:53 +1100 Subject: [PATCH 0982/3892] xfs: rearrange xfs_mod_sb() to avoid array subscript warning gcc warns of an array subscript out of bounds in xfs_mod_sb(). The code is written in such a way that if the array subscript is out of bounds, then it will assert fail. Rearrange the code to avoid the bounds check warning. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_mount.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 0df5045abd3b..d95bd1809f3c 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1631,15 +1631,14 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields); /* find modified range */ + f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + last = xfs_sb_info[f + 1].offset - 1; f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); ASSERT((1LL << f) & XFS_SB_MOD_BITS); first = xfs_sb_info[f].offset; - f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); - ASSERT((1LL << f) & XFS_SB_MOD_BITS); - last = xfs_sb_info[f + 1].offset - 1; - xfs_trans_log_buf(tp, bp, first, last); } -- GitLab From efd590d57a5edddabaaf4cfaf532c0f674193b81 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 15:08:36 +0900 Subject: [PATCH 0983/3892] sh: mach-sdk7786: FPGA updates. This does a bit of refactoring of the FPGA management code. The primary FPGA initialization is moved out to its own file in preparation for implementing some of the more complex capabilities, a complete set of register definitions is provided, and all of the existing users in the board code are moved over to use the new interface instead of setting up overlapping mappings. This also corrects the FPGA size, which previously was chomped off at the SDIF control register. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/Makefile | 2 +- arch/sh/boards/mach-sdk7786/fpga.c | 37 ++++++++ arch/sh/boards/mach-sdk7786/setup.c | 78 ++-------------- arch/sh/include/mach-sdk7786/mach/fpga.h | 112 +++++++++++++++++++++++ 4 files changed, 159 insertions(+), 70 deletions(-) create mode 100644 arch/sh/boards/mach-sdk7786/fpga.c create mode 100644 arch/sh/include/mach-sdk7786/mach/fpga.h diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile index f663768429f0..50c8065deaa0 100644 --- a/arch/sh/boards/mach-sdk7786/Makefile +++ b/arch/sh/boards/mach-sdk7786/Makefile @@ -1 +1 @@ -obj-y := setup.o +obj-y := setup.o fpga.o diff --git a/arch/sh/boards/mach-sdk7786/fpga.c b/arch/sh/boards/mach-sdk7786/fpga.c new file mode 100644 index 000000000000..99f903c8b238 --- /dev/null +++ b/arch/sh/boards/mach-sdk7786/fpga.c @@ -0,0 +1,37 @@ +/* + * SDK7786 FPGA Support. + * + * Copyright (C) 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +#define FPGA_REGS_BASE 0x07fff800 +#define FPGA_REGS_SIZE 0x490 + +void __iomem *sdk7786_fpga_base; + +void __init sdk7786_fpga_init(void) +{ + u16 version, date; + + sdk7786_fpga_base = ioremap_nocache(FPGA_REGS_BASE, FPGA_REGS_SIZE); + if (unlikely(!sdk7786_fpga_base)) { + panic("FPGA remapping failed.\n"); + return; + } + + version = fpga_read_reg(FPGAVR); + date = fpga_read_reg(FPGADR); + + pr_info("\tFPGA version:\t%d.%d (built on %d/%d/%d)\n", + bcd2bin(version >> 8) & 0xf, bcd2bin(version & 0xf), + ((date >> 12) & 0xf) + 2000, + (date >> 8) & 0xf, bcd2bin(date & 0xff)); +} diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index 0e4b1c39742c..8dbbdea9c983 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -18,6 +18,7 @@ #include #include #include +#include static struct resource heartbeat_resource = { .start = 0x07fff8b0, @@ -103,27 +104,17 @@ static struct platform_device *sh7786_devices[] __initdata = { &smbus_pcie_device, }; -#define SBCR_REGS_BASE 0x07fff990 - -#define SCBR_I2CMEN (1 << 0) /* FPGA I2C master enable */ -#define SCBR_I2CCEN (1 << 1) /* CPU I2C master enable */ - static int sdk7786_i2c_setup(void) { - void __iomem *sbcr; unsigned int tmp; - sbcr = ioremap_nocache(SBCR_REGS_BASE, SZ_16); - /* * Hand over I2C control to the FPGA. */ - tmp = ioread16(sbcr); + tmp = fpga_read_reg(SBCR); tmp &= ~SCBR_I2CCEN; tmp |= SCBR_I2CMEN; - iowrite16(tmp, sbcr); - - iounmap(sbcr); + fpga_write_reg(tmp, SBCR); return i2c_register_board_info(0, sdk7786_i2c_devices, ARRAY_SIZE(sdk7786_i2c_devices)); @@ -141,43 +132,6 @@ static int __init sdk7786_devices_setup(void) } __initcall(sdk7786_devices_setup); -#define FPGA_REGS_BASE 0x07fff800 -#define FPGA_REGS_SIZE 1152 - -#define INTASR 0x010 -#define INTAMR 0x020 -#define INTBSR 0x090 -#define INTBMR 0x0a0 -#define INTMSR 0x130 - -#define IASELR1 0x210 -#define IASELR2 0x220 -#define IASELR3 0x230 -#define IASELR4 0x240 -#define IASELR5 0x250 -#define IASELR6 0x260 -#define IASELR7 0x270 -#define IASELR8 0x280 -#define IASELR9 0x290 -#define IASELR10 0x2a0 -#define IASELR11 0x2b0 -#define IASELR12 0x2c0 -#define IASELR13 0x2d0 -#define IASELR14 0x2e0 -#define IASELR15 0x2f0 - -static void __iomem *fpga_regs; - -static u16 fpga_read_reg(unsigned int reg) -{ - return __raw_readw(fpga_regs + reg); -} - -static void fpga_write_reg(u16 val, unsigned int reg) -{ - __raw_writew(val, fpga_regs + reg); -} - enum { ATA_IRQ_BIT = 1, SPI_BUSY_BIT = 2, @@ -197,12 +151,6 @@ static void __init init_sdk7786_IRQ(void) { unsigned int tmp; - fpga_regs = ioremap_nocache(FPGA_REGS_BASE, FPGA_REGS_SIZE); - if (!fpga_regs) { - printk(KERN_ERR "Couldn't map FPGA registers\n"); - return; - } - /* Enable priority encoding for all IRLs */ fpga_write_reg(fpga_read_reg(INTMSR) | 0x0303, INTMSR); @@ -219,21 +167,9 @@ static void __init init_sdk7786_IRQ(void) plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK); } -#define MODSWR_REGS 0x07fff830 - static int sdk7786_mode_pins(void) { - void __iomem *modswr; - int pin_states; - - modswr = ioremap_nocache(MODSWR_REGS, SZ_16); - if (!modswr) - return -ENXIO; - - pin_states = ioread16(modswr); - iounmap(modswr); - - return pin_states; + return fpga_read_reg(MODSWR); } static int sdk7786_clk_init(void) @@ -260,7 +196,11 @@ static int sdk7786_clk_init(void) /* Initialize the board */ static void __init sdk7786_setup(char **cmdline_p) { - printk(KERN_INFO "Renesas Technology Corp. SDK7786 support.\n"); + pr_info("Renesas Technology Europe SDK7786 support:\n"); + + sdk7786_fpga_init(); + + pr_info("\tPCB revision:\t%d\n", fpga_read_reg(PCBRR) & 0xf); } /* diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h new file mode 100644 index 000000000000..a85d9853d34f --- /dev/null +++ b/arch/sh/include/mach-sdk7786/mach/fpga.h @@ -0,0 +1,112 @@ +#ifndef __MACH_SDK7786_FPGA_H +#define __MACH_SDK7786_FPGA_H + +#include +#include +#include + +#define SRSTR 0x000 +#define INTASR 0x010 +#define INTAMR 0x020 +#define MODSWR 0x030 +#define INTTESTR 0x040 +#define SYSSR 0x050 +#define NRGPR 0x060 +#define NMISR 0x070 + +#define NMIMR 0x080 +#define NMIMR_MAN_NMIM BIT(0) /* Manual NMI mask */ +#define NMIMR_AUX_NMIM BIT(1) /* Auxiliary NMI mask */ + +#define INTBSR 0x090 +#define INTBMR 0x0a0 +#define USRLEDR 0x0b0 +#define MAPSWR 0x0c0 +#define FPGAVR 0x0d0 +#define FPGADR 0x0e0 +#define PCBRR 0x0f0 +#define RSR 0x100 +#define EXTASR 0x110 +#define SPCAR 0x120 +#define INTMSR 0x130 +#define PCIECR 0x140 +#define FAER 0x150 +#define USRGPIR 0x160 +/* 0x170 reserved */ +#define LCLASR 0x180 + +#define SBCR 0x190 +#define SCBR_I2CMEN BIT(0) /* FPGA I2C master enable */ +#define SCBR_I2CCEN BIT(1) /* CPU I2C master enable */ + +#define PWRCR 0x1a0 +#define SPCBR 0x1b0 +#define SPICR 0x1c0 +#define SPIDR 0x1d0 +#define I2CCR 0x1e0 +#define I2CDR 0x1f0 +#define FPGACR 0x200 +#define IASELR1 0x210 +#define IASELR2 0x220 +#define IASELR3 0x230 +#define IASELR4 0x240 +#define IASELR5 0x250 +#define IASELR6 0x260 +#define IASELR7 0x270 +#define IASELR8 0x280 +#define IASELR9 0x290 +#define IASELR10 0x2a0 +#define IASELR11 0x2b0 +#define IASELR12 0x2c0 +#define IASELR13 0x2d0 +#define IASELR14 0x2e0 +#define IASELR15 0x2f0 +/* 0x300 reserved */ +#define IBSELR1 0x310 +#define IBSELR2 0x320 +#define IBSELR3 0x330 +#define IBSELR4 0x340 +#define IBSELR5 0x350 +#define IBSELR6 0x360 +#define IBSELR7 0x370 +#define IBSELR8 0x380 +#define IBSELR9 0x390 +#define IBSELR10 0x3a0 +#define IBSELR11 0x3b0 +#define IBSELR12 0x3c0 +#define IBSELR13 0x3d0 +#define IBSELR14 0x3e0 +#define IBSELR15 0x3f0 +#define USRACR 0x400 +#define BEEPR 0x410 +#define USRLCDR 0x420 +#define SMBCR 0x430 +#define SMBDR 0x440 +#define USBCR 0x450 +#define AMSR 0x460 +#define ACCR 0x470 +#define SDIFCR 0x480 + +/* arch/sh/boards/mach-sdk7786/fpga.c */ +extern void __iomem *sdk7786_fpga_base; +extern void sdk7786_fpga_init(void); + +#define SDK7786_FPGA_REGADDR(reg) (sdk7786_fpga_base + (reg)) + +/* + * A convenience wrapper from register offset to internal I2C address, + * when the FPGA is in I2C slave mode. + */ +#define SDK7786_FPGA_I2CADDR(reg) ((reg) >> 3) + +static inline u16 fpga_read_reg(unsigned int reg) +{ + return ioread16(sdk7786_fpga_base + reg); +} + +static inline void fpga_write_reg(u16 val, unsigned int reg) +{ + iowrite16(val, sdk7786_fpga_base + reg); +} + +#endif /* __MACH_SDK7786_FPGA_H */ -- GitLab From 580d9e00fdfb85e65c5097dcd739c6efcdbadc96 Mon Sep 17 00:00:00 2001 From: Motohiro KOSAKI Date: Mon, 18 Jan 2010 21:35:05 -0500 Subject: [PATCH 0984/3892] kprobetrace, doc: Shell needs single quote to use $ character Shell interprets $val as shell variable, thus we need quote if we use the echo command. Signed-off-by: KOSAKI Motohiro Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE LKML-Reference: <20100119023505.31880.17367.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar --- Documentation/trace/kprobetrace.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index f30978e001f8..ab57f02e53bb 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -79,7 +79,7 @@ Usage examples To add a probe as a new event, write a new definition to kprobe_events as below. - echo p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack) > /sys/kernel/debug/tracing/kprobe_events + echo 'p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)' > /sys/kernel/debug/tracing/kprobe_events This sets a kprobe on the top of do_sys_open() function with recording 1st to 4th arguments as "myprobe" event. Note, which register/stack entry is @@ -88,7 +88,7 @@ the ABI, please try to use probe subcommand of perf-tools (you can find it under tools/perf/). As this example shows, users can choose more familiar names for each arguments. - echo r:myretprobe do_sys_open $retval >> /sys/kernel/debug/tracing/kprobe_events + echo 'r:myretprobe do_sys_open $retval' >> /sys/kernel/debug/tracing/kprobe_events This sets a kretprobe on the return point of do_sys_open() function with recording return value as "myretprobe" event. -- GitLab From df3ab708b787a2b35de5101452bd51d4a8ae0ded Mon Sep 17 00:00:00 2001 From: Motohiro KOSAKI Date: Mon, 18 Jan 2010 21:35:12 -0500 Subject: [PATCH 0985/3892] kprobetrace, doc: Add the explanation to remove probe points Latest kprobetrace can remove probe points selectively, thus the documentation should be updated too. Signed-off-by: KOSAKI Motohiro Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE LKML-Reference: <20100119023512.31880.35535.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar --- Documentation/trace/kprobetrace.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index ab57f02e53bb..a9100b28eb84 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -24,6 +24,7 @@ Synopsis of kprobe_events ------------------------- p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe + -:[GRP/]EVENT : Clear a probe GRP : Group name. If omitted, use "kprobes" for it. EVENT : Event name. If omitted, the event name is generated @@ -122,6 +123,12 @@ REC->dfd, REC->filename, REC->flags, REC->mode This clears all probe points. + Or, + + echo -:myprobe >> kprobe_events + + This clears probe points selectively. + Right after definition, each event is disabled by default. For tracing these events, you need to enable it. -- GitLab From 5f240718b475dcddee86b138b624f24c681dbb29 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 15:23:54 +0900 Subject: [PATCH 0986/3892] sh: mach-sdk7786: Split out FPGA IRQ controller setup. This moves out the FPGA IRQ controller setup code to its own file, in preparation for switching off of IRL mode and having it provide its own irq_chip. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/Makefile | 2 +- arch/sh/boards/mach-sdk7786/irq.c | 48 +++++++++++++++++++++++++ arch/sh/boards/mach-sdk7786/setup.c | 40 ++------------------- arch/sh/include/mach-sdk7786/mach/irq.h | 7 ++++ 4 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 arch/sh/boards/mach-sdk7786/irq.c create mode 100644 arch/sh/include/mach-sdk7786/mach/irq.h diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile index 50c8065deaa0..a29f19e85b63 100644 --- a/arch/sh/boards/mach-sdk7786/Makefile +++ b/arch/sh/boards/mach-sdk7786/Makefile @@ -1 +1 @@ -obj-y := setup.o fpga.o +obj-y := setup.o fpga.o irq.o diff --git a/arch/sh/boards/mach-sdk7786/irq.c b/arch/sh/boards/mach-sdk7786/irq.c new file mode 100644 index 000000000000..46943a0da5b7 --- /dev/null +++ b/arch/sh/boards/mach-sdk7786/irq.c @@ -0,0 +1,48 @@ +/* + * SDK7786 FPGA IRQ Controller Support. + * + * Copyright (C) 2010 Matt Fleming + * Copyright (C) 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include + +enum { + ATA_IRQ_BIT = 1, + SPI_BUSY_BIT = 2, + LIRQ5_BIT = 3, + LIRQ6_BIT = 4, + LIRQ7_BIT = 5, + LIRQ8_BIT = 6, + KEY_IRQ_BIT = 7, + PEN_IRQ_BIT = 8, + ETH_IRQ_BIT = 9, + RTC_ALARM_BIT = 10, + CRYSTAL_FAIL_BIT = 12, + ETH_PME_BIT = 14, +}; + +void __init sdk7786_init_irq(void) +{ + unsigned int tmp; + + /* Enable priority encoding for all IRLs */ + fpga_write_reg(fpga_read_reg(INTMSR) | 0x0303, INTMSR); + + /* Clear FPGA interrupt status registers */ + fpga_write_reg(0x0000, INTASR); + fpga_write_reg(0x0000, INTBSR); + + /* Unmask FPGA interrupts */ + tmp = fpga_read_reg(INTAMR); + tmp &= ~(1 << ETH_IRQ_BIT); + fpga_write_reg(tmp, INTAMR); + + plat_irq_setup_pins(IRQ_MODE_IRL7654_MASK); + plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK); +} diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index 8dbbdea9c983..3c3c9a38cfda 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -15,10 +15,11 @@ #include #include #include +#include +#include #include #include #include -#include static struct resource heartbeat_resource = { .start = 0x07fff8b0, @@ -132,41 +133,6 @@ static int __init sdk7786_devices_setup(void) } __initcall(sdk7786_devices_setup); -enum { - ATA_IRQ_BIT = 1, - SPI_BUSY_BIT = 2, - LIRQ5_BIT = 3, - LIRQ6_BIT = 4, - LIRQ7_BIT = 5, - LIRQ8_BIT = 6, - KEY_IRQ_BIT = 7, - PEN_IRQ_BIT = 8, - ETH_IRQ_BIT = 9, - RTC_ALARM_BIT = 10, - CRYSTAL_FAIL_BIT = 12, - ETH_PME_BIT = 14, -}; - -static void __init init_sdk7786_IRQ(void) -{ - unsigned int tmp; - - /* Enable priority encoding for all IRLs */ - fpga_write_reg(fpga_read_reg(INTMSR) | 0x0303, INTMSR); - - /* Clear FPGA interrupt status registers */ - fpga_write_reg(0x0000, INTASR); - fpga_write_reg(0x0000, INTBSR); - - /* Unmask FPGA interrupts */ - tmp = fpga_read_reg(INTAMR); - tmp &= ~(1 << ETH_IRQ_BIT); - fpga_write_reg(tmp, INTAMR); - - plat_irq_setup_pins(IRQ_MODE_IRL7654_MASK); - plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK); -} - static int sdk7786_mode_pins(void) { return fpga_read_reg(MODSWR); @@ -211,5 +177,5 @@ static struct sh_machine_vector mv_sdk7786 __initmv = { .mv_setup = sdk7786_setup, .mv_mode_pins = sdk7786_mode_pins, .mv_clk_init = sdk7786_clk_init, - .mv_init_irq = init_sdk7786_IRQ, + .mv_init_irq = sdk7786_init_irq, }; diff --git a/arch/sh/include/mach-sdk7786/mach/irq.h b/arch/sh/include/mach-sdk7786/mach/irq.h new file mode 100644 index 000000000000..0f584635e6e5 --- /dev/null +++ b/arch/sh/include/mach-sdk7786/mach/irq.h @@ -0,0 +1,7 @@ +#ifndef __MACH_SDK7786_IRQ_H +#define __MACH_SDK7786_IRQ_H + +/* arch/sh/boards/mach-sdk7786/irq.c */ +extern void sdk7786_init_irq(void); + +#endif /* __MACH_SDK7786_IRQ_H */ -- GitLab From 2efa53b269ec1e9289a108e1506f53f6f1de440b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 16:40:48 +0900 Subject: [PATCH 0987/3892] sh: Make 29/32-bit mode check helper generally available. Presently __in_29bit_mode() is only defined for the PMB case, but it's also easily derived from the CONFIG_29BIT and CONFIG_32BIT && CONFIG_PMB=n cases. Signed-off-by: Paul Mundt --- arch/sh/include/asm/addrspace.h | 6 ------ arch/sh/include/asm/mmu.h | 10 +++++++++- arch/sh/mm/init.c | 7 ------- arch/sh/mm/pmb.c | 5 +++++ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h index 268efd62ed21..446b3831c214 100644 --- a/arch/sh/include/asm/addrspace.h +++ b/arch/sh/include/asm/addrspace.h @@ -65,11 +65,5 @@ #define P3_ADDR_MAX P4SEG #endif -#ifndef __ASSEMBLY__ -#ifdef CONFIG_PMB -extern int __in_29bit_mode(void); -#endif /* CONFIG_PMB */ -#endif /* __ASSEMBLY__ */ - #endif /* __KERNEL__ */ #endif /* __ASM_SH_ADDRSPACE_H */ diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index e5e8f48830ef..ca7d91e8aa72 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h @@ -31,6 +31,7 @@ #ifndef __ASSEMBLY__ #include +#include /* Default "unsigned long" context */ typedef unsigned long mm_context_id_t[NR_CPUS]; @@ -72,6 +73,7 @@ long pmb_remap(unsigned long virt, unsigned long phys, unsigned long size, unsigned long flags); void pmb_unmap(unsigned long addr); int pmb_init(void); +bool __in_29bit_mode(void); #else static inline long pmb_remap(unsigned long virt, unsigned long phys, unsigned long size, unsigned long flags) @@ -87,8 +89,14 @@ static inline int pmb_init(void) { return -ENODEV; } -#endif /* CONFIG_PMB */ +#ifdef CONFIG_29BIT +#define __in_29bit_mode() (1) +#else +#define __in_29bit_mode() (0) +#endif + +#endif /* CONFIG_PMB */ #endif /* __ASSEMBLY__ */ #endif /* __MMU_H */ diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 32ebd1592e63..491d9d5c8e0d 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -338,10 +338,3 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); #endif #endif /* CONFIG_MEMORY_HOTPLUG */ - -#ifdef CONFIG_PMB -int __in_29bit_mode(void) -{ - return !(ctrl_inl(PMB_PASCR) & PASCR_SE); -} -#endif /* CONFIG_PMB */ diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index b796b6c021b4..d318fa6caffe 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -436,6 +436,11 @@ int __uses_jump_to_uncached pmb_init(void) return 0; } +bool __in_29bit_mode(void) +{ + return (__raw_readl(PMB_PASCR) & PASCR_SE) == 0; +} + static int pmb_seq_show(struct seq_file *file, void *iter) { int i; -- GitLab From fbb82b03653cdb7fd1863b911e7540011259d2ce Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 16:42:52 +0900 Subject: [PATCH 0988/3892] sh: machine_ops based reboot support. This provides a machine_ops-based reboot interface loosely cloned from x86, and converts the native sh32 and sh64 cases over to it. Necessary both for tying in SMP support and also enabling platforms like SDK7786 to add support for their microcontroller-based power managers. Signed-off-by: Paul Mundt --- arch/sh/include/asm/reboot.h | 21 +++++++ arch/sh/include/asm/system.h | 1 + arch/sh/include/asm/system_32.h | 12 ++++ arch/sh/include/asm/system_64.h | 7 +++ arch/sh/kernel/Makefile | 3 +- arch/sh/kernel/idle.c | 14 ++++- arch/sh/kernel/machine_kexec.c | 8 +-- arch/sh/kernel/process_32.c | 48 ---------------- arch/sh/kernel/process_64.c | 25 +-------- arch/sh/kernel/reboot.c | 98 +++++++++++++++++++++++++++++++++ arch/sh/kernel/smp.c | 9 --- 11 files changed, 156 insertions(+), 90 deletions(-) create mode 100644 arch/sh/include/asm/reboot.h create mode 100644 arch/sh/kernel/reboot.c diff --git a/arch/sh/include/asm/reboot.h b/arch/sh/include/asm/reboot.h new file mode 100644 index 000000000000..b3da0c63fc3d --- /dev/null +++ b/arch/sh/include/asm/reboot.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_REBOOT_H +#define __ASM_SH_REBOOT_H + +#include + +struct pt_regs; + +struct machine_ops { + void (*restart)(char *cmd); + void (*halt)(void); + void (*power_off)(void); + void (*shutdown)(void); + void (*crash_shutdown)(struct pt_regs *); +}; + +extern struct machine_ops machine_ops; + +/* arch/sh/kernel/machine_kexec.c */ +void native_machine_crash_shutdown(struct pt_regs *regs); + +#endif /* __ASM_SH_REBOOT_H */ diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index 62e4fc1e4409..de2fc3963c12 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -143,6 +143,7 @@ extern struct dentry *sh_debugfs_root; void per_cpu_trap_init(void); void default_idle(void); void cpu_idle_wait(void); +void stop_this_cpu(void *); #ifdef CONFIG_SUPERH32 #define BUILD_TRAP_HANDLER(name) \ diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h index 06814f5b59c7..34bd2bac9a5f 100644 --- a/arch/sh/include/asm/system_32.h +++ b/arch/sh/include/asm/system_32.h @@ -2,6 +2,7 @@ #define __ASM_SH_SYSTEM_32_H #include +#include #ifdef CONFIG_SH_DSP @@ -216,6 +217,17 @@ static inline reg_size_t register_align(void *val) int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, struct mem_access *ma, int); +static inline void trigger_address_error(void) +{ + if (__in_29bit_mode()) + __asm__ __volatile__ ( + "ldc %0, sr\n\t" + "mov.l @%1, %0" + : + : "r" (0x10000000), "r" (0x80000001) + ); +} + asmlinkage void do_address_error(struct pt_regs *regs, unsigned long writeaccess, unsigned long address); diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h index ab1dd917ea87..604ba7802cc2 100644 --- a/arch/sh/include/asm/system_64.h +++ b/arch/sh/include/asm/system_64.h @@ -48,6 +48,13 @@ static inline reg_size_t register_align(void *val) return (unsigned long long)(signed long long)(signed long)val; } +extern void phys_stext(void); + +static inline void trigger_address_error(void) +{ + phys_stext(); +} + #define SR_BL_LL 0x0000000010000000LL static inline void set_bl_bit(void) diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 56704a6d723a..02fd3ae8b0ee 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -14,7 +14,8 @@ CFLAGS_REMOVE_return_address.o = -pg obj-y := debugtraps.o dma-nommu.o dumpstack.o \ idle.o io.o io_generic.o irq.o \ irq_$(BITS).o machvec.o nmi_debug.o process.o \ - process_$(BITS).o ptrace_$(BITS).o return_address.o \ + process_$(BITS).o ptrace_$(BITS).o \ + reboot.o return_address.o \ setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ syscalls_$(BITS).o time.o topology.o traps.o \ traps_$(BITS).o unwinder.o diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 6b3d706deac1..0fd7b41f0a22 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -20,10 +20,9 @@ #include #include -static int hlt_counter; void (*pm_idle)(void) = NULL; -void (*pm_power_off)(void); -EXPORT_SYMBOL(pm_power_off); + +static int hlt_counter; static int __init nohlt_setup(char *__unused) { @@ -131,6 +130,15 @@ static void do_nothing(void *unused) { } +void stop_this_cpu(void *unused) +{ + local_irq_disable(); + cpu_clear(smp_processor_id(), cpu_online_map); + + for (;;) + cpu_sleep(); +} + /* * cpu_idle_wait - Used to ensure that all the CPUs discard old value of * pm_idle and update to new pm_idle value. Required while changing pm_idle diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index f52d8ed69e12..7672141c841b 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -22,6 +22,7 @@ #include #include #include +#include typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, unsigned long reboot_code_buffer, @@ -31,12 +32,9 @@ extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; extern void *vbr_base; -void machine_shutdown(void) -{ -} - -void machine_crash_shutdown(struct pt_regs *regs) +void native_machine_crash_shutdown(struct pt_regs *regs) { + /* Nothing to do for UP, but definitely broken for SMP.. */ } /* diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 856010f9ebc9..b6f43f0ea743 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -16,63 +16,15 @@ #include #include #include -#include #include -#include -#include -#include -#include #include #include -#include #include #include #include -#include #include #include #include -#include - -#ifdef CONFIG_32BIT -static void watchdog_trigger_immediate(void) -{ - sh_wdt_write_cnt(0xFF); - sh_wdt_write_csr(0xC2); -} - -void machine_restart(char * __unused) -{ - local_irq_disable(); - - /* Use watchdog timer to trigger reset */ - watchdog_trigger_immediate(); - - while (1) - cpu_sleep(); -} -#else -void machine_restart(char * __unused) -{ - /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ - asm volatile("ldc %0, sr\n\t" - "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); -} -#endif - -void machine_halt(void) -{ - local_irq_disable(); - - while (1) - cpu_sleep(); -} - -void machine_power_off(void) -{ - if (pm_power_off) - pm_power_off(); -} void show_regs(struct pt_regs * regs) { diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index c9554a70bd0e..6ae5987230f8 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -32,30 +32,7 @@ struct task_struct *last_task_used_math = NULL; -void machine_restart(char * __unused) -{ - extern void phys_stext(void); - - phys_stext(); -} - -void machine_halt(void) -{ - for (;;); -} - -void machine_power_off(void) -{ - __asm__ __volatile__ ( - "sleep\n\t" - "synci\n\t" - "nop;nop;nop;nop\n\t" - ); - - panic("Unexpected wakeup!\n"); -} - -void show_regs(struct pt_regs * regs) +void show_regs(struct pt_regs *regs) { unsigned long long ah, al, bh, bl, ch, cl; diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c new file mode 100644 index 000000000000..b1fca66bb92e --- /dev/null +++ b/arch/sh/kernel/reboot.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#ifdef CONFIG_SUPERH32 +#include +#endif +#include +#include +#include + +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +#ifdef CONFIG_SUPERH32 +static void watchdog_trigger_immediate(void) +{ + sh_wdt_write_cnt(0xFF); + sh_wdt_write_csr(0xC2); +} +#endif + +static void native_machine_restart(char * __unused) +{ + local_irq_disable(); + + /* Address error with SR.BL=1 first. */ + trigger_address_error(); + +#ifdef CONFIG_SUPERH32 + /* If that fails or is unsupported, go for the watchdog next. */ + watchdog_trigger_immediate(); +#endif + + /* + * Give up and sleep. + */ + while (1) + cpu_sleep(); +} + +static void native_machine_shutdown(void) +{ + smp_send_stop(); +} + +static void native_machine_power_off(void) +{ + if (pm_power_off) + pm_power_off(); +} + +static void native_machine_halt(void) +{ + /* stop other cpus */ + machine_shutdown(); + + /* stop this cpu */ + stop_this_cpu(NULL); +} + +struct machine_ops machine_ops = { + .power_off = native_machine_power_off, + .shutdown = native_machine_shutdown, + .restart = native_machine_restart, + .halt = native_machine_halt, +#ifdef CONFIG_KEXEC + .crash_shutdown = native_machine_crash_shutdown, +#endif +}; + +void machine_power_off(void) +{ + machine_ops.power_off(); +} + +void machine_shutdown(void) +{ + machine_ops.shutdown(); +} + +void machine_restart(char *cmd) +{ + machine_ops.restart(cmd); +} + +void machine_halt(void) +{ + machine_ops.halt(); +} + +#ifdef CONFIG_KEXEC +void machine_crash_shutdown(struct pt_regs *regs) +{ + machine_ops.crash_shutdown(regs); +} +#endif diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 983e0792d5f3..e124cf7008df 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -161,15 +161,6 @@ void smp_send_reschedule(int cpu) plat_send_ipi(cpu, SMP_MSG_RESCHEDULE); } -static void stop_this_cpu(void *unused) -{ - cpu_clear(smp_processor_id(), cpu_online_map); - local_irq_disable(); - - for (;;) - cpu_relax(); -} - void smp_send_stop(void) { smp_call_function(stop_this_cpu, 0, 0); -- GitLab From b51989b8afe9409ee68c67ce2a5de4390693bd2b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 16:53:11 +0900 Subject: [PATCH 0989/3892] sh: mach-sdk7786: reset controller reboot support. This wires up the machine_ops reboot call to use the system reset controller. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/setup.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index 3c3c9a38cfda..f094ea2ee783 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include static struct resource heartbeat_resource = { .start = 0x07fff8b0, @@ -159,6 +160,11 @@ static int sdk7786_clk_init(void) return ret; } +static void sdk7786_restart(char *cmd) +{ + fpga_write_reg(0xa5a5, SRSTR); +} + /* Initialize the board */ static void __init sdk7786_setup(char **cmdline_p) { @@ -167,6 +173,8 @@ static void __init sdk7786_setup(char **cmdline_p) sdk7786_fpga_init(); pr_info("\tPCB revision:\t%d\n", fpga_read_reg(PCBRR) & 0xf); + + machine_ops.restart = sdk7786_restart; } /* -- GitLab From e8d433f335d44028d41af231ef5c52fd8a9b280b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jan 2010 15:59:19 -0200 Subject: [PATCH 0990/3892] perf archive: Add documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also makes it appear on the 'perf --help' output, i.e. util/generate-cmdlist.sh now takes it into account. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263837559-24168-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf-archive.txt | 22 ++++++++++++++++++++++ tools/perf/command-list.txt | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tools/perf/Documentation/perf-archive.txt diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt new file mode 100644 index 000000000000..fae174dc7d01 --- /dev/null +++ b/tools/perf/Documentation/perf-archive.txt @@ -0,0 +1,22 @@ +perf-archive(1) +=============== + +NAME +---- +perf-archive - Create archive with object files with build-ids found in perf.data file + +SYNOPSIS +-------- +[verse] +'perf archive' [file] + +DESCRIPTION +----------- +This command runs runs perf-buildid-list --with-hits, and collects the files +with the buildids found so that analisys of perf.data contents can be possible +on another machine. + + +SEE ALSO +-------- +linkperf:perf-record[1], linkperf:perf-buildid-list[1], linkperf:perf-report[1] diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index f73d1d90f5bd..cf6444dfd73a 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -3,7 +3,7 @@ # command name category [deprecated] [common] # perf-annotate mainporcelain common -perf-archive mainporcelain +perf-archive mainporcelain common perf-bench mainporcelain common perf-buildid-list mainporcelain common perf-diff mainporcelain common -- GitLab From d5526d8cb8e5aa3349c1ff4e409ad9b4cdac380c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jan 2010 18:21:42 -0200 Subject: [PATCH 0991/3892] perf archive: Fix installation steps in the Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix these warning: acme@parisc:~/git/linux-2.6-tip$ make -C tools/perf/ install make: Entering directory `/home/acme/git/linux-2.6-tip/tools/perf' Makefile:833: warning: overriding commands for target `perf-archive' Makefile:822: warning: ignoring old commands for target `perf-archive' Reported-by: Ingo Molnar Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263846102-24841-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index d739552036d0..ddbeeee9ade2 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -311,7 +311,6 @@ PROGRAMS += perf # List built-in command $C whose implementation cmd_$C() is not in # builtin-$C.o but is linked in as part of some other command. # -BUILT_INS += perf-archive # what 'all' will build and 'install' will install, in perfexecdir ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) @@ -1004,6 +1003,7 @@ install: all $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' + $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' -- GitLab From f162f87ad6e98e8bfb2362955da46bed7b2514be Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 19 Jan 2010 10:36:13 -0200 Subject: [PATCH 0992/3892] perf symbols: Set dso->kernel when handling the fake vmlinux MMAP event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because it may be possible that there was no buildid section, where we would set this to 1. Found while analysing a perf.data file collected on an ARM machine where an explicitely specified vmlinux was being disregarded. Reported-by: Jamie Iles Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263904574-30732-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index dc13cad828d7..bbaee61c1683 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -373,6 +373,7 @@ int event__process_mmap(event_t *self, struct perf_session *session) if (kernel == NULL) goto out_problem; + kernel->kernel = 1; if (__map_groups__create_kernel_maps(&session->kmaps, session->vmlinux_maps, kernel) < 0) -- GitLab From dc8d6ab2b61a2d92b5d7438565ccd20b29724cb2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 19 Jan 2010 10:36:14 -0200 Subject: [PATCH 0993/3892] perf symbols: Use only --vmlinux if specified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found while analysing a perf.data file collected on an ARM machine where an explicitely specified vmlinux was being disregarded. Reported-by: Jamie Iles Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1263904574-30732-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 67 ++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a4e745934584..b6ab23dd5f9f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1572,7 +1572,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return -1; dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); + err = dso__load_sym(self, map, session, vmlinux, fd, filter, 1, 0); close(fd); return err; @@ -1584,6 +1584,26 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, int err; const char *kallsyms_filename = NULL; char *kallsyms_allocated_filename = NULL; + /* + * Step 1: if the user specified a vmlinux filename, use it and only + * it, reporting errors to the user if it cannot be used. + * + * For instance, try to analyse an ARM perf.data file _without_ a + * build-id, or if the user specifies the wrong path to the right + * vmlinux file, obviously we can't fallback to another vmlinux (a + * x86_86 one, on the machine where analysis is being performed, say), + * or worse, /proc/kallsyms. + * + * If the specified file _has_ a build-id and there is a build-id + * section in the perf.data file, we will still do the expected + * validation in dso__load_vmlinux and will bail out if they don't + * match. + */ + if (symbol_conf.vmlinux_name != NULL) { + err = dso__load_vmlinux(self, map, session, + symbol_conf.vmlinux_name, filter); + goto out_try_fixup; + } if (vmlinux_path != NULL) { int i; @@ -1618,46 +1638,41 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, goto do_kallsyms; } } - + /* + * Now look if we have it on the build-id cache in + * $HOME/.debug/[kernel.kallsyms]. + */ build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); if (asprintf(&kallsyms_allocated_filename, "%s/.debug/[kernel.kallsyms]/%s", - getenv("HOME"), sbuild_id) != -1) { - if (access(kallsyms_filename, F_OK)) { - kallsyms_filename = kallsyms_allocated_filename; - goto do_kallsyms; - } + getenv("HOME"), sbuild_id) == -1) + return -1; + + if (access(kallsyms_filename, F_OK)) { free(kallsyms_allocated_filename); - kallsyms_allocated_filename = NULL; + return -1; } - goto do_vmlinux; - } - - if (self->long_name[0] == '[') { + kallsyms_filename = kallsyms_allocated_filename; + } else { + /* + * Last resort, if we don't have a build-id and couldn't find + * any vmlinux file, try the running kernel kallsyms table. + */ kallsyms_filename = "/proc/kallsyms"; - goto do_kallsyms; } -do_vmlinux: - err = dso__load_vmlinux(self, map, session, self->long_name, filter); - if (err <= 0) { - if (self->has_build_id) - return -1; - - pr_info("The file %s cannot be used, " - "trying to use /proc/kallsyms...", self->long_name); do_kallsyms: - err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter); - if (err > 0 && kallsyms_filename == NULL) - dso__set_long_name(self, strdup("[kernel.kallsyms]")); - free(kallsyms_allocated_filename); - } + err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter); + free(kallsyms_allocated_filename); +out_try_fixup: if (err > 0) { out_fixup: + if (kallsyms_filename == NULL) + dso__set_long_name(self, strdup("[kernel.kallsyms]")); map__fixup_start(map); map__fixup_end(map); } -- GitLab From 016ddd9b5b315fe52ac6ba3167521f50b3868d34 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 18 Jan 2010 17:05:40 +0100 Subject: [PATCH 0994/3892] x86: Put 'nopat' in kernel-parameters Add missing 'nopat' boot option into Documentation/kernel-parameters.txt. Signed-off-by: Jiri Kosina LKML-Reference: Signed-off-by: Ingo Molnar --- Documentation/kernel-parameters.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 736d45602886..5bf45c0ac749 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1729,6 +1729,9 @@ and is between 256 and 4096 characters. It is defined in the file nomfgpt [X86-32] Disable Multi-Function General Purpose Timer usage (for AMD Geode machines). + nopat [X86] Disable PAT (page attribute table extension of + pagetables) support. + norandmaps Don't use address space randomization. Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space -- GitLab From 920efaabcbd34e6b8dc05c5b777df3e936af5812 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 18:10:30 +0900 Subject: [PATCH 0995/3892] sh: Correct iounmap fixmap teardown. iounmap_fixed() had a couple of bugs in it that caused it to effectively fail at life. The total number of pages to unmap factored in the mapping offset and aligned up to the next page boundary, which doesn't match the ioremap_fixed() behaviour. When ioremap_fixed() pegs a slot, the address in the mapping data already contains the offset displacement, and the size is recorded verbatim given that we're only interested in total number of pages required. As such, we need to calculate the total number from the original size in the unmap path as well. At the same time, there was also an off-by-1 problem in the fixmap index calculation which has also been corrected. Previously subsequent remaps of an identical fixmap index would trigger the pte_ERROR() in set_pte_phys(): arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). arch/sh/mm/init.c:77: bad pte 8053ffb0(0000781003fff506). With this patch in place, the iounmap-driven fixmap teardown actually does what it's supposed to do. Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap_fixed.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c index 551b513e8fce..0b78b1e20ef1 100644 --- a/arch/sh/mm/ioremap_fixed.c +++ b/arch/sh/mm/ioremap_fixed.c @@ -93,9 +93,7 @@ ioremap_fixed(resource_size_t phys_addr, unsigned long offset, int iounmap_fixed(void __iomem *addr) { enum fixed_addresses idx; - unsigned long virt_addr; struct ioremap_map *map; - unsigned long offset; unsigned int nrpages; int i, slot; @@ -114,12 +112,9 @@ int iounmap_fixed(void __iomem *addr) if (slot < 0) return -EINVAL; - virt_addr = (unsigned long)addr; + nrpages = map->size >> PAGE_SHIFT; - offset = virt_addr & ~PAGE_MASK; - nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT; - - idx = FIX_IOREMAP_BEGIN + slot + nrpages; + idx = FIX_IOREMAP_BEGIN + slot + nrpages - 1; while (nrpages > 0) { __clear_fixmap(idx, __pgprot(_PAGE_WIRED)); --idx; -- GitLab From d9116d07f60383cef134c43a0ba15ec4375310fc Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 18:25:19 +0900 Subject: [PATCH 0996/3892] sh: mach-sdk7786: Probe system FPGA area mapping. This implements dynamic probing for the system FPGA. The system reset controller contains a fixed magic read word in order to identify the FPGA. This just utilizes a simple loop that scans across all of the fixed physical areas (area 0 through area 6) to locate the FPGA. The FPGA also contains register information detailing the area mappings and chip select settings for all of the other blocks, so this needs to be done before we can set up anything else. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-sdk7786/fpga.c | 43 +++++++++++++++++++++--- arch/sh/include/cpu-sh4/cpu/addrspace.h | 9 +++++ arch/sh/include/mach-sdk7786/mach/fpga.h | 2 ++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/arch/sh/boards/mach-sdk7786/fpga.c b/arch/sh/boards/mach-sdk7786/fpga.c index 99f903c8b238..3e4ec66a0417 100644 --- a/arch/sh/boards/mach-sdk7786/fpga.c +++ b/arch/sh/boards/mach-sdk7786/fpga.c @@ -11,9 +11,44 @@ #include #include #include +#include -#define FPGA_REGS_BASE 0x07fff800 -#define FPGA_REGS_SIZE 0x490 +#define FPGA_REGS_OFFSET 0x03fff800 +#define FPGA_REGS_SIZE 0x490 + +/* + * The FPGA can be mapped in any of the generally available areas, + * so we attempt to scan for it using the fixed SRSTR read magic. + * + * Once the FPGA is located, the rest of the mapping data for the other + * components can be determined dynamically from its section mapping + * registers. + */ +static void __iomem *sdk7786_fpga_probe(void) +{ + unsigned long area; + void __iomem *base; + + /* + * Iterate over all of the areas where the FPGA could be mapped. + * The possible range is anywhere from area 0 through 6, area 7 + * is reserved. + */ + for (area = PA_AREA0; area < PA_AREA7; area += SZ_64M) { + base = ioremap_nocache(area + FPGA_REGS_OFFSET, FPGA_REGS_SIZE); + if (!base) { + /* Failed to remap this area, move along. */ + continue; + } + + if (ioread16(base + SRSTR) == SRSTR_MAGIC) + return base; /* Found it! */ + + iounmap(base); + } + + return NULL; +} void __iomem *sdk7786_fpga_base; @@ -21,9 +56,9 @@ void __init sdk7786_fpga_init(void) { u16 version, date; - sdk7786_fpga_base = ioremap_nocache(FPGA_REGS_BASE, FPGA_REGS_SIZE); + sdk7786_fpga_base = sdk7786_fpga_probe(); if (unlikely(!sdk7786_fpga_base)) { - panic("FPGA remapping failed.\n"); + panic("FPGA detection failed.\n"); return; } diff --git a/arch/sh/include/cpu-sh4/cpu/addrspace.h b/arch/sh/include/cpu-sh4/cpu/addrspace.h index a3fa733c1c7d..d51da25da72c 100644 --- a/arch/sh/include/cpu-sh4/cpu/addrspace.h +++ b/arch/sh/include/cpu-sh4/cpu/addrspace.h @@ -28,6 +28,15 @@ #define P4SEG_TLB_DATA 0xf7000000 #define P4SEG_REG_BASE 0xff000000 +#define PA_AREA0 0x00000000 +#define PA_AREA1 0x04000000 +#define PA_AREA2 0x08000000 +#define PA_AREA3 0x0c000000 +#define PA_AREA4 0x10000000 +#define PA_AREA5 0x14000000 +#define PA_AREA6 0x18000000 +#define PA_AREA7 0x1c000000 + #define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */ #define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */ diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h index a85d9853d34f..2120d67dec70 100644 --- a/arch/sh/include/mach-sdk7786/mach/fpga.h +++ b/arch/sh/include/mach-sdk7786/mach/fpga.h @@ -6,6 +6,8 @@ #include #define SRSTR 0x000 +#define SRSTR_MAGIC 0x1971 /* Fixed magical read value */ + #define INTASR 0x010 #define INTAMR 0x020 #define MODSWR 0x030 -- GitLab From b38f6eddeee510ce8178c2d2db54ed25f1d7cb63 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Wed, 20 Jan 2010 10:39:14 +0100 Subject: [PATCH 0997/3892] netfilter: nf_conntrack_ipv6: delete the redundant macro definitions The following three macro definitions are never used, so delete them. Signed-off-by: Shan Wei Acked-by: David S. Miller Signed-off-by: Patrick McHardy --- net/ipv6/netfilter/nf_conntrack_reasm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 312c20adc83f..1030ce1e6c79 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -45,9 +45,6 @@ #include #include -#define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */ -#define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ -#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT struct nf_ct_frag6_skb_cb { -- GitLab From 7c070aa947d1a4105742378579c267f6e7fd08a1 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Wed, 20 Jan 2010 10:42:41 +0100 Subject: [PATCH 0998/3892] IPv6: reassembly: replace magic number with macro definitions Use macro to define high/low thresh value, refer to IPV6_FRAG_TIMEOUT. Signed-off-by: Shan Wei Acked-by: David S. Miller Signed-off-by: Patrick McHardy --- include/net/ipv6.h | 2 ++ net/ipv6/netfilter/nf_conntrack_reasm.c | 4 ++-- net/ipv6/reassembly.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index ccab5946c830..299bbf5adfb6 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -246,6 +246,8 @@ extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb); int ip6_frag_nqueues(struct net *net); int ip6_frag_mem(struct net *net); +#define IPV6_FRAG_HIGH_THRESH 262144 /* == 256*1024 */ +#define IPV6_FRAG_LOW_THRESH 196608 /* == 192*1024 */ #define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */ extern int __ipv6_addr_type(const struct in6_addr *addr); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 1030ce1e6c79..744ea49de356 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -666,8 +666,8 @@ int nf_ct_frag6_init(void) nf_frags.frag_expire = nf_ct_frag6_expire; nf_frags.secret_interval = 10 * 60 * HZ; nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; - nf_init_frags.high_thresh = 256 * 1024; - nf_init_frags.low_thresh = 192 * 1024; + nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH; inet_frags_init_net(&nf_init_frags); inet_frags_init(&nf_frags); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2cddea3bd6be..15bb122e1ce4 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -747,8 +747,8 @@ static inline void ip6_frags_sysctl_unregister(void) static int ipv6_frags_init_net(struct net *net) { - net->ipv6.frags.high_thresh = 256 * 1024; - net->ipv6.frags.low_thresh = 192 * 1024; + net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; inet_frags_init_net(&net->ipv6.frags); -- GitLab From 35f99c0da17beb5004f06ba86a87d82c1a6467be Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 18:48:17 +0900 Subject: [PATCH 0999/3892] sh: pretty print virtual memory map on boot. This cribs the pretty printing from arch/x86/mm/init_32.c to dump the virtual memory layout on boot. This is primarily intended as a debugging aid, given that the newer CPUs have full control over their address space and as such have little to nothing in common with the legacy layout. Signed-off-by: Paul Mundt --- arch/sh/mm/init.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 491d9d5c8e0d..f3e23ad075cb 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -260,6 +260,9 @@ void __init mem_init(void) memset(empty_zero_page, 0, PAGE_SIZE); __flush_wback_region(empty_zero_page, PAGE_SIZE); + /* Initialize the vDSO */ + vsyscall_init(); + codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; @@ -272,8 +275,39 @@ void __init mem_init(void) datasize >> 10, initsize >> 10); - /* Initialize the vDSO */ - vsyscall_init(); + printk(KERN_INFO "virtual kernel memory layout:\n" + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" +#ifdef CONFIG_HIGHMEM + " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" +#endif + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" + " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" + " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" + " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", + FIXADDR_START, FIXADDR_TOP, + (FIXADDR_TOP - FIXADDR_START) >> 10, + +#ifdef CONFIG_HIGHMEM + PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, + (LAST_PKMAP*PAGE_SIZE) >> 10, +#endif + + (unsigned long)VMALLOC_START, VMALLOC_END, + (VMALLOC_END - VMALLOC_START) >> 20, + + (unsigned long)memory_start, (unsigned long)high_memory, + ((unsigned long)high_memory - (unsigned long)memory_start) >> 20, + + (unsigned long)&__init_begin, (unsigned long)&__init_end, + ((unsigned long)&__init_end - + (unsigned long)&__init_begin) >> 10, + + (unsigned long)&_etext, (unsigned long)&_edata, + ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, + + (unsigned long)&_text, (unsigned long)&_etext, + ((unsigned long)&_etext - (unsigned long)&_text) >> 10); mem_init_done = 1; } -- GitLab From 6cd6cede8c33364d8e1abb5ea35adf627e3781b0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Jan 2010 09:39:35 +0200 Subject: [PATCH 1000/3892] ASoC: tlv320dac33: BCLK divider fix The BCLK divider was not configured in case of mode7. This leads to unpredictable behavior when switching between FIFO modes. Configure the BCLK divider depending on the fifo_mode (FIFO is in use, or FIFO bypass). Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 65683aa3920c..e1aa66ff7f1c 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -845,11 +845,14 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b); - switch (dac33->fifo_mode) { - case DAC33_FIFO_MODE1: - /* 20: BCLK divide ratio */ + /* BCLK divide ratio */ + if (dac33->fifo_mode) dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); + else + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); + switch (dac33->fifo_mode) { + case DAC33_FIFO_MODE1: dac33_write16(codec, DAC33_ATHR_MSB, DAC33_THRREG(dac33->alarm_threshold)); break; @@ -864,8 +867,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) DAC33_THRREG(10)); break; default: - /* BYPASS mode */ - dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); break; } -- GitLab From 6aceabb459c07a3fb4873c8306de8143c56241b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Jan 2010 09:39:36 +0200 Subject: [PATCH 1001/3892] ASoC: tlv320dac33: Burst mode BCLK divider configuration Add possibility to configure the burst mode BCLK divider through platform data structure. The BCLK divider changes the actual speed of the serial bus in burst mode, which is faster than the sampling frequency of the running stream. In this way platforms can experiment with the optimal burst speed without the need to modify the codec driver itself. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/tlv320dac33-plat.h | 1 + sound/soc/codecs/tlv320dac33.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h index 5858d06a7ffa..ac0665264bdf 100644 --- a/include/sound/tlv320dac33-plat.h +++ b/include/sound/tlv320dac33-plat.h @@ -15,6 +15,7 @@ struct tlv320dac33_platform_data { int power_gpio; + u8 burst_bclkdiv; }; #endif /* __TLV320DAC33_PLAT_H */ diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index e1aa66ff7f1c..1b35d0cf3364 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -91,6 +91,7 @@ struct tlv320dac33_priv { * this */ enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ unsigned int nsample; /* burst read amount from host */ + u8 burst_bclkdiv; /* BCLK divider value in burst mode */ enum dac33_state state; }; @@ -845,9 +846,18 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b); - /* BCLK divide ratio */ + /* + * BCLK divide ratio + * 0: 1.5 + * 1: 1 + * 2: 2 + * ... + * 254: 254 + * 255: 255 + */ if (dac33->fifo_mode) - dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, + dac33->burst_bclkdiv); else dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); @@ -1239,6 +1249,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, dac33); dac33->power_gpio = pdata->power_gpio; + dac33->burst_bclkdiv = pdata->burst_bclkdiv; dac33->irq = client->irq; dac33->nsample = NSAMPLE_MAX; /* Disable FIFO use by default */ -- GitLab From bb06b737143bd35939e65b05e073019c5c451be9 Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Tue, 12 Jan 2010 19:09:12 +0100 Subject: [PATCH 1002/3892] ARM: 5881/1: vic.c: reorganize code This reorganizes the vic.c code in anticipation of a second patch to use struct vic_device as the data stored in set_irq_chip_data(). The code now has the following flow: 1) struct vic_device definition, static variables, and to_vic() moved to the start of the code. 2) common code (vic_init2) 3) vic power management callbacks 4) vic power management initialization/registration 5) irq_chip callbacks 6) vendor specific vic initialization 7) vic initialization In addition the typo vik_init_st is fixed (vic_init_st). There is no functional change with this patch. Tested-by: Linus Walleij Cc: Ben Dooks Cc: Alessandro Rubini Comments from Hartley Sweeten: Please change from Cc to: Tested-by: Alessandro Rubini Signed-off-by: H Hartley Sweeten Signed-off-by: Russell King --- arch/arm/common/vic.c | 265 +++++++++++++++++++++--------------------- 1 file changed, 132 insertions(+), 133 deletions(-) diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index f232941de8ab..1cf999ade4bc 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -18,6 +18,7 @@ * 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 @@ -28,48 +29,6 @@ #include #include -static void vic_ack_irq(unsigned int irq) -{ - void __iomem *base = get_irq_chip_data(irq); - irq &= 31; - writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); - /* moreover, clear the soft-triggered, in case it was the reason */ - writel(1 << irq, base + VIC_INT_SOFT_CLEAR); -} - -static void vic_mask_irq(unsigned int irq) -{ - void __iomem *base = get_irq_chip_data(irq); - irq &= 31; - writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); -} - -static void vic_unmask_irq(unsigned int irq) -{ - void __iomem *base = get_irq_chip_data(irq); - irq &= 31; - writel(1 << irq, base + VIC_INT_ENABLE); -} - -/** - * vic_init2 - common initialisation code - * @base: Base of the VIC. - * - * Common initialisation code for registeration - * and resume. -*/ -static void vic_init2(void __iomem *base) -{ - int i; - - for (i = 0; i < 16; i++) { - void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); - writel(VIC_VECT_CNTL_ENABLE | i, reg); - } - - writel(32, base + VIC_PL190_DEF_VECT_ADDR); -} - #if defined(CONFIG_PM) /** * struct vic_device - VIC PM device @@ -99,13 +58,34 @@ struct vic_device { /* we cannot allocate memory when VICs are initially registered */ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; +static int vic_id; + static inline struct vic_device *to_vic(struct sys_device *sys) { return container_of(sys, struct vic_device, sysdev); } +#endif /* CONFIG_PM */ -static int vic_id; +/** + * vic_init2 - common initialisation code + * @base: Base of the VIC. + * + * Common initialisation code for registeration + * and resume. +*/ +static void vic_init2(void __iomem *base) +{ + int i; + + for (i = 0; i < 16; i++) { + void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); + writel(VIC_VECT_CNTL_ENABLE | i, reg); + } + + writel(32, base + VIC_PL190_DEF_VECT_ADDR); +} +#if defined(CONFIG_PM) static int vic_class_resume(struct sys_device *dev) { struct vic_device *vic = to_vic(dev); @@ -158,31 +138,6 @@ struct sysdev_class vic_class = { .resume = vic_class_resume, }; -/** - * vic_pm_register - Register a VIC for later power management control - * @base: The base address of the VIC. - * @irq: The base IRQ for the VIC. - * @resume_sources: bitmask of interrupts allowed for resume sources. - * - * Register the VIC with the system device tree so that it can be notified - * of suspend and resume requests and ensure that the correct actions are - * taken to re-instate the settings on resume. - */ -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) -{ - struct vic_device *v; - - if (vic_id >= ARRAY_SIZE(vic_devices)) - printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); - else { - v = &vic_devices[vic_id]; - v->base = base; - v->resume_sources = resume_sources; - v->irq = irq; - vic_id++; - } -} - /** * vic_pm_init - initicall to register VIC pm * @@ -219,9 +174,60 @@ static int __init vic_pm_init(void) return 0; } - late_initcall(vic_pm_init); +/** + * vic_pm_register - Register a VIC for later power management control + * @base: The base address of the VIC. + * @irq: The base IRQ for the VIC. + * @resume_sources: bitmask of interrupts allowed for resume sources. + * + * Register the VIC with the system device tree so that it can be notified + * of suspend and resume requests and ensure that the correct actions are + * taken to re-instate the settings on resume. + */ +static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) +{ + struct vic_device *v; + + if (vic_id >= ARRAY_SIZE(vic_devices)) + printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); + else { + v = &vic_devices[vic_id]; + v->base = base; + v->resume_sources = resume_sources; + v->irq = irq; + vic_id++; + } +} +#else +static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { } +#endif /* CONFIG_PM */ + +static void vic_ack_irq(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + irq &= 31; + writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); + /* moreover, clear the soft-triggered, in case it was the reason */ + writel(1 << irq, base + VIC_INT_SOFT_CLEAR); +} + +static void vic_mask_irq(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + irq &= 31; + writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); +} + +static void vic_unmask_irq(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + irq &= 31; + writel(1 << irq, base + VIC_INT_ENABLE); +} + +#if defined(CONFIG_PM) static struct vic_device *vic_from_irq(unsigned int irq) { struct vic_device *v = vic_devices; @@ -255,10 +261,7 @@ static int vic_set_wake(unsigned int irq, unsigned int on) return 0; } - #else -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { } - #define vic_set_wake NULL #endif /* CONFIG_PM */ @@ -270,9 +273,62 @@ static struct irq_chip vic_chip = { .set_wake = vic_set_wake, }; -/* The PL190 cell from ARM has been modified by ST, so handle both here */ -static void vik_init_st(void __iomem *base, unsigned int irq_start, - u32 vic_sources); +/* + * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. + * The original cell has 32 interrupts, while the modified one has 64, + * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case + * the probe function is called twice, with base set to offset 000 + * and 020 within the page. We call this "second block". + */ +static void __init vic_init_st(void __iomem *base, unsigned int irq_start, + u32 vic_sources) +{ + unsigned int i; + int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; + + /* Disable all interrupts initially. */ + + writel(0, base + VIC_INT_SELECT); + writel(0, base + VIC_INT_ENABLE); + writel(~0, base + VIC_INT_ENABLE_CLEAR); + writel(0, base + VIC_IRQ_STATUS); + writel(0, base + VIC_ITCR); + writel(~0, base + VIC_INT_SOFT_CLEAR); + + /* + * Make sure we clear all existing interrupts. The vector registers + * in this cell are after the second block of general registers, + * so we can address them using standard offsets, but only from + * the second base address, which is 0x20 in the page + */ + if (vic_2nd_block) { + writel(0, base + VIC_PL190_VECT_ADDR); + for (i = 0; i < 19; i++) { + unsigned int value; + + value = readl(base + VIC_PL190_VECT_ADDR); + writel(value, base + VIC_PL190_VECT_ADDR); + } + /* ST has 16 vectors as well, but we don't enable them by now */ + for (i = 0; i < 16; i++) { + void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); + writel(0, reg); + } + + writel(32, base + VIC_PL190_DEF_VECT_ADDR); + } + + for (i = 0; i < 32; i++) { + if (vic_sources & (1 << i)) { + unsigned int irq = irq_start + i; + + set_irq_chip(irq, &vic_chip); + set_irq_chip_data(irq, base); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + } +} /** * vic_init - initialise a vectored interrupt controller @@ -299,7 +355,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, switch(vendor) { case AMBA_VENDOR_ST: - vik_init_st(base, irq_start, vic_sources); + vic_init_st(base, irq_start, vic_sources); return; default: printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n"); @@ -343,60 +399,3 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, vic_pm_register(base, irq_start, resume_sources); } - -/* - * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. - * The original cell has 32 interrupts, while the modified one has 64, - * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case - * the probe function is called twice, with base set to offset 000 - * and 020 within the page. We call this "second block". - */ -static void __init vik_init_st(void __iomem *base, unsigned int irq_start, - u32 vic_sources) -{ - unsigned int i; - int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; - - /* Disable all interrupts initially. */ - - writel(0, base + VIC_INT_SELECT); - writel(0, base + VIC_INT_ENABLE); - writel(~0, base + VIC_INT_ENABLE_CLEAR); - writel(0, base + VIC_IRQ_STATUS); - writel(0, base + VIC_ITCR); - writel(~0, base + VIC_INT_SOFT_CLEAR); - - /* - * Make sure we clear all existing interrupts. The vector registers - * in this cell are after the second block of general registers, - * so we can address them using standard offsets, but only from - * the second base address, which is 0x20 in the page - */ - if (vic_2nd_block) { - writel(0, base + VIC_PL190_VECT_ADDR); - for (i = 0; i < 19; i++) { - unsigned int value; - - value = readl(base + VIC_PL190_VECT_ADDR); - writel(value, base + VIC_PL190_VECT_ADDR); - } - /* ST has 16 vectors as well, but we don't enable them by now */ - for (i = 0; i < 16; i++) { - void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); - writel(0, reg); - } - - writel(32, base + VIC_PL190_DEF_VECT_ADDR); - } - - for (i = 0; i < 32; i++) { - if (vic_sources & (1 << i)) { - unsigned int irq = irq_start + i; - - set_irq_chip(irq, &vic_chip); - set_irq_chip_data(irq, base); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - } -} -- GitLab From 5e38efae9635436efa1e4952cf953085839a7121 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 15 Dec 2009 21:57:27 +0100 Subject: [PATCH 1003/3892] ARM: 5850/1: [AT91] AT572D940HF processor support Add support for the Atmel AT572D940HF processor (DIOPSIS range). This processor integrates an ARM926 core, a DSP and the SoC peripherals usually found on an AT91 processor (USART, SSC, SPI, TWI, CAN, etc) Signed-off-by: Antonio R. Costa Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91/Kconfig | 6 + arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/at572d940hf.c | 377 +++++++ arch/arm/mach-at91/at572d940hf_devices.c | 970 ++++++++++++++++++ arch/arm/mach-at91/clock.c | 8 +- arch/arm/mach-at91/clock.h | 2 +- arch/arm/mach-at91/generic.h | 2 + arch/arm/mach-at91/include/mach/at572d940hf.h | 123 +++ .../include/mach/at572d940hf_matrix.h | 123 +++ arch/arm/mach-at91/include/mach/at91_pmc.h | 1 + arch/arm/mach-at91/include/mach/board.h | 5 +- arch/arm/mach-at91/include/mach/cpu.h | 8 + arch/arm/mach-at91/include/mach/hardware.h | 2 + arch/arm/mach-at91/include/mach/timex.h | 5 + 14 files changed, 1628 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-at91/at572d940hf.c create mode 100644 arch/arm/mach-at91/at572d940hf_devices.c create mode 100644 arch/arm/mach-at91/include/mach/at572d940hf.h create mode 100644 arch/arm/mach-at91/include/mach/at572d940hf_matrix.h diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 0b2ee953f164..c67fa3b7eeb1 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -89,6 +89,12 @@ config ARCH_AT91CAP9 select GENERIC_CLOCKEVENTS select HAVE_FB_ATMEL +config ARCH_AT572D940HF + bool "AT572D940HF" + select CPU_ARM926T + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + config ARCH_AT91X40 bool "AT91x40" diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 709fbad4a3ee..8ddce96b6aa5 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devi obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o +obj-$(CONFIG_ARCH_AT572D940HF) += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o # AT91RM9200 board-specific support diff --git a/arch/arm/mach-at91/at572d940hf.c b/arch/arm/mach-at91/at572d940hf.c new file mode 100644 index 000000000000..a6b9c68c003a --- /dev/null +++ b/arch/arm/mach-at91/at572d940hf.c @@ -0,0 +1,377 @@ +/* + * arch/arm/mach-at91/at572d940hf.c + * + * Antonio R. Costa + * Copyright (C) 2008 Atmel + * + * Copyright (C) 2005 SAN People + * + * 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 +#include + +#include "generic.h" +#include "clock.h" + +static struct map_desc at572d940hf_io_desc[] __initdata = { + { + .virtual = AT91_VA_BASE_SYS, + .pfn = __phys_to_pfn(AT91_BASE_SYS), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_IO_VIRT_BASE - AT572D940HF_SRAM_SIZE, + .pfn = __phys_to_pfn(AT572D940HF_SRAM_BASE), + .length = AT572D940HF_SRAM_SIZE, + .type = MT_DEVICE, + }, +}; + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT572D940HF_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT572D940HF_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioC_clk = { + .name = "pioC_clk", + .pmc_mask = 1 << AT572D940HF_ID_PIOC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT572D940HF_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT572D940HF_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT572D940HF_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT572D940HF_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc_clk = { + .name = "mci_clk", + .pmc_mask = 1 << AT572D940HF_ID_MCI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT572D940HF_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi0_clk = { + .name = "twi0_clk", + .pmc_mask = 1 << AT572D940HF_ID_TWI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT572D940HF_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT572D940HF_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT572D940HF_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT572D940HF_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc2_clk = { + .name = "ssc2_clk", + .pmc_mask = 1 << AT572D940HF_ID_SSC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT572D940HF_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT572D940HF_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT572D940HF_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT572D940HF_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc3_clk = { + .name = "ssc3_clk", + .pmc_mask = 1 << AT572D940HF_ID_SSC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi1_clk = { + .name = "twi1_clk", + .pmc_mask = 1 << AT572D940HF_ID_TWI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk can0_clk = { + .name = "can0_clk", + .pmc_mask = 1 << AT572D940HF_ID_CAN0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk can1_clk = { + .name = "can1_clk", + .pmc_mask = 1 << AT572D940HF_ID_CAN1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mAgicV_clk = { + .name = "mAgicV_clk", + .pmc_mask = 1 << AT572D940HF_ID_MSIRQ0, + .type = CLK_TYPE_PERIPHERAL, +}; + + +static struct clk *periph_clocks[] __initdata = { + &pioA_clk, + &pioB_clk, + &pioC_clk, + &macb_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc_clk, + &udc_clk, + &twi0_clk, + &spi0_clk, + &spi1_clk, + &ssc0_clk, + &ssc1_clk, + &ssc2_clk, + &tc0_clk, + &tc1_clk, + &tc2_clk, + &ohci_clk, + &ssc3_clk, + &twi1_clk, + &can0_clk, + &can1_clk, + &mAgicV_clk, + /* irq0 .. irq2 */ +}; + +/* + * The five programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 3, +}; + +static struct clk mAgicV_mem_clk = { + .name = "mAgicV_mem_clk", + .pmc_mask = AT91_PMC_PCK4, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 4, +}; + +/* HClocks */ +static struct clk hck0 = { + .name = "hck0", + .pmc_mask = AT91_PMC_HCK0, + .type = CLK_TYPE_SYSTEM, + .id = 0, +}; +static struct clk hck1 = { + .name = "hck1", + .pmc_mask = AT91_PMC_HCK1, + .type = CLK_TYPE_SYSTEM, + .id = 1, +}; + +static void __init at572d940hf_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); + clk_register(&pck2); + clk_register(&pck3); + clk_register(&mAgicV_mem_clk); + + clk_register(&hck0); + clk_register(&hck1); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ + +static struct at91_gpio_bank at572d940hf_gpio[] = { + { + .id = AT572D940HF_ID_PIOA, + .offset = AT91_PIOA, + .clock = &pioA_clk, + }, { + .id = AT572D940HF_ID_PIOB, + .offset = AT91_PIOB, + .clock = &pioB_clk, + }, { + .id = AT572D940HF_ID_PIOC, + .offset = AT91_PIOC, + .clock = &pioC_clk, + } +}; + +static void at572d940hf_reset(void) +{ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); +} + + +/* -------------------------------------------------------------------- + * AT572D940HF processor initialization + * -------------------------------------------------------------------- */ + +void __init at572d940hf_initialize(unsigned long main_clock) +{ + /* Map peripherals */ + iotable_init(at572d940hf_io_desc, ARRAY_SIZE(at572d940hf_io_desc)); + + at91_arch_reset = at572d940hf_reset; + at91_extern_irq = (1 << AT572D940HF_ID_IRQ0) | (1 << AT572D940HF_ID_IRQ1) + | (1 << AT572D940HF_ID_IRQ2); + + /* Init clock subsystem */ + at91_clock_init(main_clock); + + /* Register the processor-specific clocks */ + at572d940hf_register_clocks(); + + /* Register GPIO subsystem */ + at91_gpio_init(at572d940hf_gpio, 3); +} + +/* -------------------------------------------------------------------- + * Interrupt initialization + * -------------------------------------------------------------------- */ + +/* + * The default interrupt priority levels (0 = lowest, 7 = highest). + */ +static unsigned int at572d940hf_default_irq_priority[NR_AIC_IRQS] __initdata = { + 7, /* Advanced Interrupt Controller */ + 7, /* System Peripherals */ + 0, /* Parallel IO Controller A */ + 0, /* Parallel IO Controller B */ + 0, /* Parallel IO Controller C */ + 3, /* Ethernet */ + 6, /* USART 0 */ + 6, /* USART 1 */ + 6, /* USART 2 */ + 0, /* Multimedia Card Interface */ + 4, /* USB Device Port */ + 0, /* Two-Wire Interface 0 */ + 6, /* Serial Peripheral Interface 0 */ + 6, /* Serial Peripheral Interface 1 */ + 5, /* Serial Synchronous Controller 0 */ + 5, /* Serial Synchronous Controller 1 */ + 5, /* Serial Synchronous Controller 2 */ + 0, /* Timer Counter 0 */ + 0, /* Timer Counter 1 */ + 0, /* Timer Counter 2 */ + 3, /* USB Host port */ + 3, /* Serial Synchronous Controller 3 */ + 0, /* Two-Wire Interface 1 */ + 0, /* CAN Controller 0 */ + 0, /* CAN Controller 1 */ + 0, /* mAgicV HALT line */ + 0, /* mAgicV SIRQ0 line */ + 0, /* mAgicV exception line */ + 0, /* mAgicV end of DMA line */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ +}; + +void __init at572d940hf_init_interrupts(unsigned int priority[NR_AIC_IRQS]) +{ + if (!priority) + priority = at572d940hf_default_irq_priority; + + /* Initialize the AIC interrupt controller */ + at91_aic_init(priority); + + /* Enable GPIO interrupts */ + at91_gpio_irq_setup(); +} + diff --git a/arch/arm/mach-at91/at572d940hf_devices.c b/arch/arm/mach-at91/at572d940hf_devices.c new file mode 100644 index 000000000000..0fc20a240782 --- /dev/null +++ b/arch/arm/mach-at91/at572d940hf_devices.c @@ -0,0 +1,970 @@ +/* + * arch/arm/mach-at91/at572d940hf_devices.c + * + * Copyright (C) 2008 Atmel Antonio R. Costa + * Copyright (C) 2005 Thibaut VARENE + * Copyright (C) 2005 David Brownell + * + * 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 +#include +#include +#include + +#include "generic.h" +#include "sam9_smc.h" + + +/* -------------------------------------------------------------------- + * USB Host + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static u64 ohci_dmamask = DMA_BIT_MASK(32); +static struct at91_usbh_data usbh_data; + +static struct resource usbh_resources[] = { + [0] = { + .start = AT572D940HF_UHP_BASE, + .end = AT572D940HF_UHP_BASE + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_UHP, + .end = AT572D940HF_ID_UHP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_usbh_device = { + .name = "at91_ohci", + .id = -1, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &usbh_data, + }, + .resource = usbh_resources, + .num_resources = ARRAY_SIZE(usbh_resources), +}; + +void __init at91_add_device_usbh(struct at91_usbh_data *data) +{ + if (!data) + return; + + usbh_data = *data; + platform_device_register(&at572d940hf_usbh_device); + +} +#else +void __init at91_add_device_usbh(struct at91_usbh_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_AT91 +static struct at91_udc_data udc_data; + +static struct resource udc_resources[] = { + [0] = { + .start = AT572D940HF_BASE_UDP, + .end = AT572D940HF_BASE_UDP + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_UDP, + .end = AT572D940HF_ID_UDP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_udc_device = { + .name = "at91_udc", + .id = -1, + .dev = { + .platform_data = &udc_data, + }, + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), +}; + +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (!data) + return; + + if (data->vbus_pin) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + /* Pullup pin is handled internally */ + + udc_data = *data; + platform_device_register(&at572d940hf_udc_device); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * Ethernet + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE) +static u64 eth_dmamask = DMA_BIT_MASK(32); +static struct at91_eth_data eth_data; + +static struct resource eth_resources[] = { + [0] = { + .start = AT572D940HF_BASE_EMAC, + .end = AT572D940HF_BASE_EMAC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_EMAC, + .end = AT572D940HF_ID_EMAC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_eth_device = { + .name = "macb", + .id = -1, + .dev = { + .dma_mask = ð_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = ð_data, + }, + .resource = eth_resources, + .num_resources = ARRAY_SIZE(eth_resources), +}; + +void __init at91_add_device_eth(struct at91_eth_data *data) +{ + if (!data) + return; + + if (data->phy_irq_pin) { + at91_set_gpio_input(data->phy_irq_pin, 0); + at91_set_deglitch(data->phy_irq_pin, 1); + } + + /* Only RMII is supported */ + data->is_rmii = 1; + + /* Pins used for RMII */ + at91_set_A_periph(AT91_PIN_PA16, 0); /* ETXCK_EREFCK */ + at91_set_A_periph(AT91_PIN_PA17, 0); /* ERXDV */ + at91_set_A_periph(AT91_PIN_PA18, 0); /* ERX0 */ + at91_set_A_periph(AT91_PIN_PA19, 0); /* ERX1 */ + at91_set_A_periph(AT91_PIN_PA20, 0); /* ERXER */ + at91_set_A_periph(AT91_PIN_PA23, 0); /* ETXEN */ + at91_set_A_periph(AT91_PIN_PA21, 0); /* ETX0 */ + at91_set_A_periph(AT91_PIN_PA22, 0); /* ETX1 */ + at91_set_A_periph(AT91_PIN_PA13, 0); /* EMDIO */ + at91_set_A_periph(AT91_PIN_PA14, 0); /* EMDC */ + + eth_data = *data; + platform_device_register(&at572d940hf_eth_device); +} +#else +void __init at91_add_device_eth(struct at91_eth_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * MMC / SD + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +static u64 mmc_dmamask = DMA_BIT_MASK(32); +static struct at91_mmc_data mmc_data; + +static struct resource mmc_resources[] = { + [0] = { + .start = AT572D940HF_BASE_MCI, + .end = AT572D940HF_BASE_MCI + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_MCI, + .end = AT572D940HF_ID_MCI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_mmc_device = { + .name = "at91_mci", + .id = -1, + .dev = { + .dma_mask = &mmc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &mmc_data, + }, + .resource = mmc_resources, + .num_resources = ARRAY_SIZE(mmc_resources), +}; + +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +{ + if (!data) + return; + + /* input/irq */ + if (data->det_pin) { + at91_set_gpio_input(data->det_pin, 1); + at91_set_deglitch(data->det_pin, 1); + } + if (data->wp_pin) + at91_set_gpio_input(data->wp_pin, 1); + if (data->vcc_pin) + at91_set_gpio_output(data->vcc_pin, 0); + + /* CLK */ + at91_set_A_periph(AT91_PIN_PC22, 0); + + /* CMD */ + at91_set_A_periph(AT91_PIN_PC23, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PC24, 1); + if (data->wire4) { + at91_set_A_periph(AT91_PIN_PC25, 1); + at91_set_A_periph(AT91_PIN_PC26, 1); + at91_set_A_periph(AT91_PIN_PC27, 1); + } + + mmc_data = *data; + platform_device_register(&at572d940hf_mmc_device); +} +#else +void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * NAND / SmartMedia + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE) +static struct atmel_nand_data nand_data; + +#define NAND_BASE AT91_CHIPSELECT_3 + +static struct resource nand_resources[] = { + { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at572d940hf_nand_device = { + .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, + }, + .resource = nand_resources, + .num_resources = ARRAY_SIZE(nand_resources), +}; + +void __init at91_add_device_nand(struct atmel_nand_data *data) +{ + unsigned long csa; + + if (!data) + return; + + csa = at91_sys_read(AT91_MATRIX_EBICSA); + at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA); + + /* enable pin */ + if (data->enable_pin) + at91_set_gpio_output(data->enable_pin, 1); + + /* ready/busy pin */ + if (data->rdy_pin) + at91_set_gpio_input(data->rdy_pin, 1); + + /* card detect pin */ + if (data->det_pin) + at91_set_gpio_input(data->det_pin, 1); + + at91_set_A_periph(AT91_PIN_PB28, 0); /* A[22] */ + at91_set_B_periph(AT91_PIN_PA28, 0); /* NANDOE */ + at91_set_B_periph(AT91_PIN_PA29, 0); /* NANDWE */ + + nand_data = *data; + platform_device_register(&at572d940hf_nand_device); +} + +#else +void __init at91_add_device_nand(struct atmel_nand_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * TWI (i2c) + * -------------------------------------------------------------------- */ + +/* + * Prefer the GPIO code since the TWI controller isn't robust + * (gets overruns and underruns under load) and can only issue + * repeated STARTs in one scenario (the driver doesn't yet handle them). + */ + +#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE) + +static struct i2c_gpio_platform_data pdata = { + .sda_pin = AT91_PIN_PC7, + .sda_is_open_drain = 1, + .scl_pin = AT91_PIN_PC8, + .scl_is_open_drain = 1, + .udelay = 2, /* ~100 kHz */ +}; + +static struct platform_device at572d940hf_twi_device { + .name = "i2c-gpio", + .id = -1, + .dev.platform_data = &pdata, +}; + +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) +{ + at91_set_GPIO_periph(AT91_PIN_PC7, 1); /* TWD (SDA) */ + at91_set_multi_drive(AT91_PIN_PC7, 1); + + at91_set_GPIO_periph(AT91_PIN_PA8, 1); /* TWCK (SCL) */ + at91_set_multi_drive(AT91_PIN_PC8, 1); + + i2c_register_board_info(0, devices, nr_devices); + platform_device_register(&at572d940hf_twi_device); +} + +#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) + +static struct resource twi0_resources[] = { + [0] = { + .start = AT572D940HF_BASE_TWI0, + .end = AT572D940HF_BASE_TWI0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_TWI0, + .end = AT572D940HF_ID_TWI0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_twi0_device = { + .name = "at91_i2c", + .id = 0, + .resource = twi0_resources, + .num_resources = ARRAY_SIZE(twi0_resources), +}; + +static struct resource twi1_resources[] = { + [0] = { + .start = AT572D940HF_BASE_TWI1, + .end = AT572D940HF_BASE_TWI1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_TWI1, + .end = AT572D940HF_ID_TWI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_twi1_device = { + .name = "at91_i2c", + .id = 1, + .resource = twi1_resources, + .num_resources = ARRAY_SIZE(twi1_resources), +}; + +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) +{ + /* pins used for TWI0 interface */ + at91_set_A_periph(AT91_PIN_PC7, 0); /* TWD */ + at91_set_multi_drive(AT91_PIN_PC7, 1); + + at91_set_A_periph(AT91_PIN_PC8, 0); /* TWCK */ + at91_set_multi_drive(AT91_PIN_PC8, 1); + + /* pins used for TWI1 interface */ + at91_set_A_periph(AT91_PIN_PC20, 0); /* TWD */ + at91_set_multi_drive(AT91_PIN_PC20, 1); + + at91_set_A_periph(AT91_PIN_PC21, 0); /* TWCK */ + at91_set_multi_drive(AT91_PIN_PC21, 1); + + i2c_register_board_info(0, devices, nr_devices); + platform_device_register(&at572d940hf_twi0_device); + platform_device_register(&at572d940hf_twi1_device); +} +#else +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {} +#endif + + +/* -------------------------------------------------------------------- + * SPI + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) +static u64 spi_dmamask = DMA_BIT_MASK(32); + +static struct resource spi0_resources[] = { + [0] = { + .start = AT572D940HF_BASE_SPI0, + .end = AT572D940HF_BASE_SPI0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_SPI0, + .end = AT572D940HF_ID_SPI0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_spi0_device = { + .name = "atmel_spi", + .id = 0, + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = spi0_resources, + .num_resources = ARRAY_SIZE(spi0_resources), +}; + +static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 }; + +static struct resource spi1_resources[] = { + [0] = { + .start = AT572D940HF_BASE_SPI1, + .end = AT572D940HF_BASE_SPI1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_SPI1, + .end = AT572D940HF_ID_SPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_spi1_device = { + .name = "atmel_spi", + .id = 1, + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = spi1_resources, + .num_resources = ARRAY_SIZE(spi1_resources), +}; + +static const unsigned spi1_standard_cs[4] = { AT91_PIN_PC3, AT91_PIN_PC4, AT91_PIN_PC5, AT91_PIN_PC6 }; + +void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) +{ + int i; + unsigned long cs_pin; + short enable_spi0 = 0; + short enable_spi1 = 0; + + /* Choose SPI chip-selects */ + for (i = 0; i < nr_devices; i++) { + if (devices[i].controller_data) + cs_pin = (unsigned long) devices[i].controller_data; + else if (devices[i].bus_num == 0) + cs_pin = spi0_standard_cs[devices[i].chip_select]; + else + cs_pin = spi1_standard_cs[devices[i].chip_select]; + + if (devices[i].bus_num == 0) + enable_spi0 = 1; + else + enable_spi1 = 1; + + /* enable chip-select pin */ + at91_set_gpio_output(cs_pin, 1); + + /* pass chip-select pin to driver */ + devices[i].controller_data = (void *) cs_pin; + } + + spi_register_board_info(devices, nr_devices); + + /* Configure SPI bus(es) */ + if (enable_spi0) { + at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */ + at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */ + at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI0_SPCK */ + + at91_clock_associate("spi0_clk", &at572d940hf_spi0_device.dev, "spi_clk"); + platform_device_register(&at572d940hf_spi0_device); + } + if (enable_spi1) { + at91_set_A_periph(AT91_PIN_PC0, 0); /* SPI1_MISO */ + at91_set_A_periph(AT91_PIN_PC1, 0); /* SPI1_MOSI */ + at91_set_A_periph(AT91_PIN_PC2, 0); /* SPI1_SPCK */ + + at91_clock_associate("spi1_clk", &at572d940hf_spi1_device.dev, "spi_clk"); + platform_device_register(&at572d940hf_spi1_device); + } +} +#else +void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {} +#endif + + +/* -------------------------------------------------------------------- + * Timer/Counter blocks + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_ATMEL_TCLIB + +static struct resource tcb_resources[] = { + [0] = { + .start = AT572D940HF_BASE_TCB, + .end = AT572D940HF_BASE_TCB + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_TC0, + .end = AT572D940HF_ID_TC0, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AT572D940HF_ID_TC1, + .end = AT572D940HF_ID_TC1, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = AT572D940HF_ID_TC2, + .end = AT572D940HF_ID_TC2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at572d940hf_tcb_device = { + .name = "atmel_tcb", + .id = 0, + .resource = tcb_resources, + .num_resources = ARRAY_SIZE(tcb_resources), +}; + +static void __init at91_add_device_tc(void) +{ + /* this chip has a separate clock and irq for each TC channel */ + at91_clock_associate("tc0_clk", &at572d940hf_tcb_device.dev, "t0_clk"); + at91_clock_associate("tc1_clk", &at572d940hf_tcb_device.dev, "t1_clk"); + at91_clock_associate("tc2_clk", &at572d940hf_tcb_device.dev, "t2_clk"); + platform_device_register(&at572d940hf_tcb_device); +} +#else +static void __init at91_add_device_tc(void) { } +#endif + + +/* -------------------------------------------------------------------- + * RTT + * -------------------------------------------------------------------- */ + +static struct resource rtt_resources[] = { + { + .start = AT91_BASE_SYS + AT91_RTT, + .end = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at572d940hf_rtt_device = { + .name = "at91_rtt", + .id = 0, + .resource = rtt_resources, + .num_resources = ARRAY_SIZE(rtt_resources), +}; + +static void __init at91_add_device_rtt(void) +{ + platform_device_register(&at572d940hf_rtt_device); +} + + +/* -------------------------------------------------------------------- + * Watchdog + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE) +static struct platform_device at572d940hf_wdt_device = { + .name = "at91_wdt", + .id = -1, + .num_resources = 0, +}; + +static void __init at91_add_device_watchdog(void) +{ + platform_device_register(&at572d940hf_wdt_device); +} +#else +static void __init at91_add_device_watchdog(void) {} +#endif + + +/* -------------------------------------------------------------------- + * UART + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_SERIAL_ATMEL) +static struct resource dbgu_resources[] = { + [0] = { + .start = AT91_VA_BASE_SYS + AT91_DBGU, + .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91_ID_SYS, + .end = AT91_ID_SYS, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data dbgu_data = { + .use_dma_tx = 0, + .use_dma_rx = 0, /* DBGU not capable of receive DMA */ + .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU), +}; + +static u64 dbgu_dmamask = DMA_BIT_MASK(32); + +static struct platform_device at572d940hf_dbgu_device = { + .name = "atmel_usart", + .id = 0, + .dev = { + .dma_mask = &dbgu_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dbgu_data, + }, + .resource = dbgu_resources, + .num_resources = ARRAY_SIZE(dbgu_resources), +}; + +static inline void configure_dbgu_pins(void) +{ + at91_set_A_periph(AT91_PIN_PC31, 1); /* DTXD */ + at91_set_A_periph(AT91_PIN_PC30, 0); /* DRXD */ +} + +static struct resource uart0_resources[] = { + [0] = { + .start = AT572D940HF_BASE_US0, + .end = AT572D940HF_BASE_US0 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_US0, + .end = AT572D940HF_ID_US0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart0_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static u64 uart0_dmamask = DMA_BIT_MASK(32); + +static struct platform_device at572d940hf_uart0_device = { + .name = "atmel_usart", + .id = 1, + .dev = { + .dma_mask = &uart0_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &uart0_data, + }, + .resource = uart0_resources, + .num_resources = ARRAY_SIZE(uart0_resources), +}; + +static inline void configure_usart0_pins(unsigned pins) +{ + at91_set_A_periph(AT91_PIN_PA8, 1); /* TXD0 */ + at91_set_A_periph(AT91_PIN_PA7, 0); /* RXD0 */ + + if (pins & ATMEL_UART_RTS) + at91_set_A_periph(AT91_PIN_PA10, 0); /* RTS0 */ + if (pins & ATMEL_UART_CTS) + at91_set_A_periph(AT91_PIN_PA9, 0); /* CTS0 */ +} + +static struct resource uart1_resources[] = { + [0] = { + .start = AT572D940HF_BASE_US1, + .end = AT572D940HF_BASE_US1 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_US1, + .end = AT572D940HF_ID_US1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart1_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static u64 uart1_dmamask = DMA_BIT_MASK(32); + +static struct platform_device at572d940hf_uart1_device = { + .name = "atmel_usart", + .id = 2, + .dev = { + .dma_mask = &uart1_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &uart1_data, + }, + .resource = uart1_resources, + .num_resources = ARRAY_SIZE(uart1_resources), +}; + +static inline void configure_usart1_pins(unsigned pins) +{ + at91_set_A_periph(AT91_PIN_PC10, 1); /* TXD1 */ + at91_set_A_periph(AT91_PIN_PC9 , 0); /* RXD1 */ + + if (pins & ATMEL_UART_RTS) + at91_set_A_periph(AT91_PIN_PC12, 0); /* RTS1 */ + if (pins & ATMEL_UART_CTS) + at91_set_A_periph(AT91_PIN_PC11, 0); /* CTS1 */ +} + +static struct resource uart2_resources[] = { + [0] = { + .start = AT572D940HF_BASE_US2, + .end = AT572D940HF_BASE_US2 + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT572D940HF_ID_US2, + .end = AT572D940HF_ID_US2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct atmel_uart_data uart2_data = { + .use_dma_tx = 1, + .use_dma_rx = 1, +}; + +static u64 uart2_dmamask = DMA_BIT_MASK(32); + +static struct platform_device at572d940hf_uart2_device = { + .name = "atmel_usart", + .id = 3, + .dev = { + .dma_mask = &uart2_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &uart2_data, + }, + .resource = uart2_resources, + .num_resources = ARRAY_SIZE(uart2_resources), +}; + +static inline void configure_usart2_pins(unsigned pins) +{ + at91_set_A_periph(AT91_PIN_PC15, 1); /* TXD2 */ + at91_set_A_periph(AT91_PIN_PC14, 0); /* RXD2 */ + + if (pins & ATMEL_UART_RTS) + at91_set_A_periph(AT91_PIN_PC17, 0); /* RTS2 */ + if (pins & ATMEL_UART_CTS) + at91_set_A_periph(AT91_PIN_PC16, 0); /* CTS2 */ +} + +static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ +struct platform_device *atmel_default_console_device; /* the serial console device */ + +void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) +{ + struct platform_device *pdev; + + switch (id) { + case 0: /* DBGU */ + pdev = &at572d940hf_dbgu_device; + configure_dbgu_pins(); + at91_clock_associate("mck", &pdev->dev, "usart"); + break; + case AT572D940HF_ID_US0: + pdev = &at572d940hf_uart0_device; + configure_usart0_pins(pins); + at91_clock_associate("usart0_clk", &pdev->dev, "usart"); + break; + case AT572D940HF_ID_US1: + pdev = &at572d940hf_uart1_device; + configure_usart1_pins(pins); + at91_clock_associate("usart1_clk", &pdev->dev, "usart"); + break; + case AT572D940HF_ID_US2: + pdev = &at572d940hf_uart2_device; + configure_usart2_pins(pins); + at91_clock_associate("usart2_clk", &pdev->dev, "usart"); + break; + default: + return; + } + pdev->id = portnr; /* update to mapped ID */ + + if (portnr < ATMEL_MAX_UART) + at91_uarts[portnr] = pdev; +} + +void __init at91_set_serial_console(unsigned portnr) +{ + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +} + +void __init at91_add_device_serial(void) +{ + int i; + + for (i = 0; i < ATMEL_MAX_UART; i++) { + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } + + if (!atmel_default_console_device) + printk(KERN_INFO "AT91: No default serial console defined.\n"); +} + +#else +void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +void __init at91_set_serial_console(unsigned portnr) {} +void __init at91_add_device_serial(void) {} +#endif + + +/* -------------------------------------------------------------------- + * mAgic + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_MAGICV +static struct resource mAgic_resources[] = { + { + .start = AT91_MAGIC_PM_BASE, + .end = AT91_MAGIC_PM_BASE + AT91_MAGIC_PM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT91_MAGIC_DM_I_BASE, + .end = AT91_MAGIC_DM_I_BASE + AT91_MAGIC_DM_I_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT91_MAGIC_DM_F_BASE, + .end = AT91_MAGIC_DM_F_BASE + AT91_MAGIC_DM_F_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT91_MAGIC_DM_DB_BASE, + .end = AT91_MAGIC_DM_DB_BASE + AT91_MAGIC_DM_DB_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT91_MAGIC_REGS_BASE, + .end = AT91_MAGIC_REGS_BASE + AT91_MAGIC_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT91_MAGIC_EXTPAGE_BASE, + .end = AT91_MAGIC_EXTPAGE_BASE + AT91_MAGIC_EXTPAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = AT572D940HF_ID_MSIRQ0, + .end = AT572D940HF_ID_MSIRQ0, + .flags = IORESOURCE_IRQ, + }, + { + .start = AT572D940HF_ID_MHALT, + .end = AT572D940HF_ID_MHALT, + .flags = IORESOURCE_IRQ, + }, + { + .start = AT572D940HF_ID_MEXC, + .end = AT572D940HF_ID_MEXC, + .flags = IORESOURCE_IRQ, + }, + { + .start = AT572D940HF_ID_MEDMA, + .end = AT572D940HF_ID_MEDMA, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mAgic_device = { + .name = "mAgic", + .id = -1, + .num_resources = ARRAY_SIZE(mAgic_resources), + .resource = mAgic_resources, +}; + +void __init at91_add_device_mAgic(void) +{ + platform_device_register(&mAgic_device); +} +#else +void __init at91_add_device_mAgic(void) {} +#endif + + +/* -------------------------------------------------------------------- */ + +/* + * These devices are always present and don't need any board-specific + * setup. + */ +static int __init at91_add_standard_devices(void) +{ + at91_add_device_rtt(); + at91_add_device_watchdog(); + at91_add_device_tc(); + return 0; +} + +arch_initcall(at91_add_standard_devices); diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index c042dcf4725f..7f7da439341f 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -29,6 +29,7 @@ #include #include "clock.h" +#include "generic.h" /* @@ -628,7 +629,7 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock) at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20() || - cpu_is_at91sam9g10()) { + cpu_is_at91sam9g10() || cpu_is_at572d940hf()) { uhpck.pmc_mask = AT91SAM926x_PMC_UHP; udpck.pmc_mask = AT91SAM926x_PMC_UDP; } else if (cpu_is_at91cap9()) { @@ -711,12 +712,13 @@ int __init at91_clock_init(unsigned long main_clock) /* * USB HS clock init */ - if (cpu_has_utmi()) + if (cpu_has_utmi()) { /* * multiplier is hard-wired to 40 * (obtain the USB High Speed 480 MHz when input is 12 MHz) */ utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + } /* * USB FS clock init @@ -746,7 +748,7 @@ int __init at91_clock_init(unsigned long main_clock) mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ } else { - mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ } /* Register the PMC's standard clocks */ diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h index 1ba3b95ff359..6cf4b78e175d 100644 --- a/arch/arm/mach-at91/clock.h +++ b/arch/arm/mach-at91/clock.h @@ -22,7 +22,7 @@ struct clk { struct clk *parent; u32 pmc_mask; void (*mode)(struct clk *, int); - unsigned id:2; /* PCK0..3, or 32k/main/a/b */ + unsigned id:3; /* PCK0..4, or 32k/main/a/b */ unsigned type; /* clock type */ u16 users; }; diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 88e413b38480..65c3dc5ba0d0 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -17,6 +17,7 @@ extern void __init at91sam9rl_initialize(unsigned long main_clock); extern void __init at91sam9g45_initialize(unsigned long main_clock); extern void __init at91x40_initialize(unsigned long main_clock); extern void __init at91cap9_initialize(unsigned long main_clock); +extern void __init at572d940hf_initialize(unsigned long main_clock); /* Interrupts */ extern void __init at91rm9200_init_interrupts(unsigned int priority[]); @@ -27,6 +28,7 @@ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]); extern void __init at91sam9g45_init_interrupts(unsigned int priority[]); extern void __init at91x40_init_interrupts(unsigned int priority[]); extern void __init at91cap9_init_interrupts(unsigned int priority[]); +extern void __init at572d940hf_init_interrupts(unsigned int priority[]); extern void __init at91_aic_init(unsigned int priority[]); /* Timer */ diff --git a/arch/arm/mach-at91/include/mach/at572d940hf.h b/arch/arm/mach-at91/include/mach/at572d940hf.h new file mode 100644 index 000000000000..2d9b0af9c4d5 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at572d940hf.h @@ -0,0 +1,123 @@ +/* + * include/mach/at572d940hf.h + * + * Antonio R. Costa + * Copyright (C) 2008 Atmel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef AT572D940HF_H +#define AT572D940HF_H + +/* + * Peripheral identifiers/interrupts. + */ +#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */ +#define AT91_ID_SYS 1 /* System Peripherals */ +#define AT572D940HF_ID_PIOA 2 /* Parallel IO Controller A */ +#define AT572D940HF_ID_PIOB 3 /* Parallel IO Controller B */ +#define AT572D940HF_ID_PIOC 4 /* Parallel IO Controller C */ +#define AT572D940HF_ID_EMAC 5 /* MACB ethernet controller */ +#define AT572D940HF_ID_US0 6 /* USART 0 */ +#define AT572D940HF_ID_US1 7 /* USART 1 */ +#define AT572D940HF_ID_US2 8 /* USART 2 */ +#define AT572D940HF_ID_MCI 9 /* Multimedia Card Interface */ +#define AT572D940HF_ID_UDP 10 /* USB Device Port */ +#define AT572D940HF_ID_TWI0 11 /* Two-Wire Interface 0 */ +#define AT572D940HF_ID_SPI0 12 /* Serial Peripheral Interface 0 */ +#define AT572D940HF_ID_SPI1 13 /* Serial Peripheral Interface 1 */ +#define AT572D940HF_ID_SSC0 14 /* Serial Synchronous Controller 0 */ +#define AT572D940HF_ID_SSC1 15 /* Serial Synchronous Controller 1 */ +#define AT572D940HF_ID_SSC2 16 /* Serial Synchronous Controller 2 */ +#define AT572D940HF_ID_TC0 17 /* Timer Counter 0 */ +#define AT572D940HF_ID_TC1 18 /* Timer Counter 1 */ +#define AT572D940HF_ID_TC2 19 /* Timer Counter 2 */ +#define AT572D940HF_ID_UHP 20 /* USB Host port */ +#define AT572D940HF_ID_SSC3 21 /* Serial Synchronous Controller 3 */ +#define AT572D940HF_ID_TWI1 22 /* Two-Wire Interface 1 */ +#define AT572D940HF_ID_CAN0 23 /* CAN Controller 0 */ +#define AT572D940HF_ID_CAN1 24 /* CAN Controller 1 */ +#define AT572D940HF_ID_MHALT 25 /* mAgicV HALT line */ +#define AT572D940HF_ID_MSIRQ0 26 /* mAgicV SIRQ0 line */ +#define AT572D940HF_ID_MEXC 27 /* mAgicV exception line */ +#define AT572D940HF_ID_MEDMA 28 /* mAgicV end of DMA line */ +#define AT572D940HF_ID_IRQ0 29 /* External Interrupt Source (IRQ0) */ +#define AT572D940HF_ID_IRQ1 30 /* External Interrupt Source (IRQ1) */ +#define AT572D940HF_ID_IRQ2 31 /* External Interrupt Source (IRQ2) */ + + +/* + * User Peripheral physical base addresses. + */ +#define AT572D940HF_BASE_TCB 0xfffa0000 +#define AT572D940HF_BASE_TC0 0xfffa0000 +#define AT572D940HF_BASE_TC1 0xfffa0040 +#define AT572D940HF_BASE_TC2 0xfffa0080 +#define AT572D940HF_BASE_UDP 0xfffa4000 +#define AT572D940HF_BASE_MCI 0xfffa8000 +#define AT572D940HF_BASE_TWI0 0xfffac000 +#define AT572D940HF_BASE_US0 0xfffb0000 +#define AT572D940HF_BASE_US1 0xfffb4000 +#define AT572D940HF_BASE_US2 0xfffb8000 +#define AT572D940HF_BASE_SSC0 0xfffbc000 +#define AT572D940HF_BASE_SSC1 0xfffc0000 +#define AT572D940HF_BASE_SSC2 0xfffc4000 +#define AT572D940HF_BASE_SPI0 0xfffc8000 +#define AT572D940HF_BASE_SPI1 0xfffcc000 +#define AT572D940HF_BASE_SSC3 0xfffd0000 +#define AT572D940HF_BASE_TWI1 0xfffd4000 +#define AT572D940HF_BASE_EMAC 0xfffd8000 +#define AT572D940HF_BASE_CAN0 0xfffdc000 +#define AT572D940HF_BASE_CAN1 0xfffe0000 +#define AT91_BASE_SYS 0xffffea00 + + +/* + * System Peripherals (offset from AT91_BASE_SYS) + */ +#define AT91_SDRAMC (0xffffea00 - AT91_BASE_SYS) +#define AT91_SMC (0xffffec00 - AT91_BASE_SYS) +#define AT91_MATRIX (0xffffee00 - AT91_BASE_SYS) +#define AT91_AIC (0xfffff000 - AT91_BASE_SYS) +#define AT91_DBGU (0xfffff200 - AT91_BASE_SYS) +#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) +#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) +#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) +#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) +#define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) +#define AT91_RTT (0xfffffd20 - AT91_BASE_SYS) +#define AT91_PIT (0xfffffd30 - AT91_BASE_SYS) +#define AT91_WDT (0xfffffd40 - AT91_BASE_SYS) + +#define AT91_USART0 AT572D940HF_ID_US0 +#define AT91_USART1 AT572D940HF_ID_US1 +#define AT91_USART2 AT572D940HF_ID_US2 + + +/* + * Internal Memory. + */ +#define AT572D940HF_SRAM_BASE 0x00300000 /* Internal SRAM base address */ +#define AT572D940HF_SRAM_SIZE (48 * SZ_1K) /* Internal SRAM size (48Kb) */ + +#define AT572D940HF_ROM_BASE 0x00400000 /* Internal ROM base address */ +#define AT572D940HF_ROM_SIZE SZ_32K /* Internal ROM size (32Kb) */ + +#define AT572D940HF_UHP_BASE 0x00500000 /* USB Host controller */ + + +#endif diff --git a/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h b/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h new file mode 100644 index 000000000000..b6751df09488 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h @@ -0,0 +1,123 @@ +/* + * include/mach//at572d940hf_matrix.h + * + * Antonio R. Costa + * Copyright (C) 2008 Atmel + * + * Copyright (C) 2005 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AT572D940HF_MATRIX_H +#define AT572D940HF_MATRIX_H + +#define AT91_MATRIX_MCFG0 (AT91_MATRIX + 0x00) /* Master Configuration Register 0 */ +#define AT91_MATRIX_MCFG1 (AT91_MATRIX + 0x04) /* Master Configuration Register 1 */ +#define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */ +#define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */ +#define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */ +#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */ + +#define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */ +#define AT91_MATRIX_ULBT_INFINITE (0 << 0) +#define AT91_MATRIX_ULBT_SINGLE (1 << 0) +#define AT91_MATRIX_ULBT_FOUR (2 << 0) +#define AT91_MATRIX_ULBT_EIGHT (3 << 0) +#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0) + +#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x40) /* Slave Configuration Register 0 */ +#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x44) /* Slave Configuration Register 1 */ +#define AT91_MATRIX_SCFG2 (AT91_MATRIX + 0x48) /* Slave Configuration Register 2 */ +#define AT91_MATRIX_SCFG3 (AT91_MATRIX + 0x4C) /* Slave Configuration Register 3 */ +#define AT91_MATRIX_SCFG4 (AT91_MATRIX + 0x50) /* Slave Configuration Register 4 */ +#define AT91_MATRIX_SLOT_CYCLE (0xff << 0) /* Maximum Number of Allowed Cycles for a Burst */ +#define AT91_MATRIX_DEFMSTR_TYPE (3 << 16) /* Default Master Type */ +#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16) +#define AT91_MATRIX_FIXED_DEFMSTR (0x7 << 18) /* Fixed Index of Default Master */ +#define AT91_MATRIX_ARBT (3 << 24) /* Arbitration Type */ +#define AT91_MATRIX_ARBT_ROUND_ROBIN (0 << 24) +#define AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24) + +#define AT91_MATRIX_PRAS0 (AT91_MATRIX + 0x80) /* Priority Register A for Slave 0 */ +#define AT91_MATRIX_PRAS1 (AT91_MATRIX + 0x88) /* Priority Register A for Slave 1 */ +#define AT91_MATRIX_PRAS2 (AT91_MATRIX + 0x90) /* Priority Register A for Slave 2 */ +#define AT91_MATRIX_PRAS3 (AT91_MATRIX + 0x98) /* Priority Register A for Slave 3 */ +#define AT91_MATRIX_PRAS4 (AT91_MATRIX + 0xA0) /* Priority Register A for Slave 4 */ + +#define AT91_MATRIX_M0PR (3 << 0) /* Master 0 Priority */ +#define AT91_MATRIX_M1PR (3 << 4) /* Master 1 Priority */ +#define AT91_MATRIX_M2PR (3 << 8) /* Master 2 Priority */ +#define AT91_MATRIX_M3PR (3 << 12) /* Master 3 Priority */ +#define AT91_MATRIX_M4PR (3 << 16) /* Master 4 Priority */ +#define AT91_MATRIX_M5PR (3 << 20) /* Master 5 Priority */ +#define AT91_MATRIX_M6PR (3 << 24) /* Master 6 Priority */ + +#define AT91_MATRIX_MRCR (AT91_MATRIX + 0x100) /* Master Remap Control Register */ +#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */ +#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */ + +#define AT91_MATRIX_SFR0 (AT91_MATRIX + 0x110) /* Special Function Register 0 */ +#define AT91_MATRIX_SFR1 (AT91_MATRIX + 0x114) /* Special Function Register 1 */ +#define AT91_MATRIX_SFR2 (AT91_MATRIX + 0x118) /* Special Function Register 2 */ +#define AT91_MATRIX_SFR3 (AT91_MATRIX + 0x11C) /* Special Function Register 3 */ +#define AT91_MATRIX_SFR4 (AT91_MATRIX + 0x120) /* Special Function Register 4 */ +#define AT91_MATRIX_SFR5 (AT91_MATRIX + 0x124) /* Special Function Register 5 */ +#define AT91_MATRIX_SFR6 (AT91_MATRIX + 0x128) /* Special Function Register 6 */ +#define AT91_MATRIX_SFR7 (AT91_MATRIX + 0x12C) /* Special Function Register 7 */ +#define AT91_MATRIX_SFR8 (AT91_MATRIX + 0x130) /* Special Function Register 8 */ +#define AT91_MATRIX_SFR9 (AT91_MATRIX + 0x134) /* Special Function Register 9 */ +#define AT91_MATRIX_SFR10 (AT91_MATRIX + 0x138) /* Special Function Register 10 */ +#define AT91_MATRIX_SFR11 (AT91_MATRIX + 0x13C) /* Special Function Register 11 */ +#define AT91_MATRIX_SFR12 (AT91_MATRIX + 0x140) /* Special Function Register 12 */ +#define AT91_MATRIX_SFR13 (AT91_MATRIX + 0x144) /* Special Function Register 13 */ +#define AT91_MATRIX_SFR14 (AT91_MATRIX + 0x148) /* Special Function Register 14 */ +#define AT91_MATRIX_SFR15 (AT91_MATRIX + 0x14C) /* Special Function Register 15 */ + + +/* + * The following registers / bits are not defined in the Datasheet (Revision A) + */ + +#define AT91_MATRIX_TCR (AT91_MATRIX + 0x100) /* TCM Configuration Register */ +#define AT91_MATRIX_ITCM_SIZE (0xf << 0) /* Size of ITCM enabled memory block */ +#define AT91_MATRIX_ITCM_0 (0 << 0) +#define AT91_MATRIX_ITCM_16 (5 << 0) +#define AT91_MATRIX_ITCM_32 (6 << 0) +#define AT91_MATRIX_ITCM_64 (7 << 0) +#define AT91_MATRIX_DTCM_SIZE (0xf << 4) /* Size of DTCM enabled memory block */ +#define AT91_MATRIX_DTCM_0 (0 << 4) +#define AT91_MATRIX_DTCM_16 (5 << 4) +#define AT91_MATRIX_DTCM_32 (6 << 4) +#define AT91_MATRIX_DTCM_64 (7 << 4) + +#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x11C) /* EBI Chip Select Assignment Register */ +#define AT91_MATRIX_CS1A (1 << 1) /* Chip Select 1 Assignment */ +#define AT91_MATRIX_CS1A_SMC (0 << 1) +#define AT91_MATRIX_CS1A_SDRAMC (1 << 1) +#define AT91_MATRIX_CS3A (1 << 3) /* Chip Select 3 Assignment */ +#define AT91_MATRIX_CS3A_SMC (0 << 3) +#define AT91_MATRIX_CS3A_SMC_SMARTMEDIA (1 << 3) +#define AT91_MATRIX_CS4A (1 << 4) /* Chip Select 4 Assignment */ +#define AT91_MATRIX_CS4A_SMC (0 << 4) +#define AT91_MATRIX_CS4A_SMC_CF1 (1 << 4) +#define AT91_MATRIX_CS5A (1 << 5) /* Chip Select 5 Assignment */ +#define AT91_MATRIX_CS5A_SMC (0 << 5) +#define AT91_MATRIX_CS5A_SMC_CF2 (1 << 5) +#define AT91_MATRIX_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */ + +#endif diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h index 64589eaaaee8..e46f93e34aab 100644 --- a/arch/arm/mach-at91/include/mach/at91_pmc.h +++ b/arch/arm/mach-at91/include/mach/at91_pmc.h @@ -32,6 +32,7 @@ #define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */ #define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */ #define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_PCK4 (1 << 12) /* Programmable Clock 4 [AT572D940HF only] */ #define AT91_PMC_HCK0 (1 << 16) /* AHB Clock (USB host) [AT91SAM9261 only] */ #define AT91_PMC_HCK1 (1 << 17) /* AHB Clock (LCD) [AT91SAM9261 only] */ diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index bb6f6a7ba5e0..ceaec6c16eb2 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -87,7 +87,7 @@ struct at91_eth_data { extern void __init at91_add_device_eth(struct at91_eth_data *data); #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \ - || defined(CONFIG_ARCH_AT91SAM9G45) + || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF) #define eth_platform_data at91_eth_data #endif @@ -205,6 +205,9 @@ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); extern void __init at91_pwm_leds(struct gpio_led *leds, int nr); + /* AT572D940HF DSP */ +extern void __init at91_add_device_mAgic(void); + /* FIXME: this needs a better location, but gets stuff building again */ extern int at91_suspend_entering_slow_clock(void); diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index c22df30ed5e5..5a0650101d45 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -33,6 +33,8 @@ #define ARCH_ID_AT91SAM9XE256 0x329a93a0 #define ARCH_ID_AT91SAM9XE512 0x329aa3a0 +#define ARCH_ID_AT572D940HF 0x0e0303e0 + #define ARCH_ID_AT91M40800 0x14080044 #define ARCH_ID_AT91R40807 0x44080746 #define ARCH_ID_AT91M40807 0x14080745 @@ -141,6 +143,12 @@ static inline unsigned long at91cap9_rev_identify(void) #define cpu_is_at91cap9_revC() (0) #endif +#ifdef CONFIG_ARCH_AT572D940HF +#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF) +#else +#define cpu_is_at572d940hf() (0) +#endif + /* * Since this is ARM, we will never run on any AVR32 CPU. But these * definitions may reduce clutter in common drivers. diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h index a0df8b022df2..3d64a75e3ed5 100644 --- a/arch/arm/mach-at91/include/mach/hardware.h +++ b/arch/arm/mach-at91/include/mach/hardware.h @@ -32,6 +32,8 @@ #include #elif defined(CONFIG_ARCH_AT91X40) #include +#elif defined(CONFIG_ARCH_AT572D940HF) +#include #else #error "Unsupported AT91 processor" #endif diff --git a/arch/arm/mach-at91/include/mach/timex.h b/arch/arm/mach-at91/include/mach/timex.h index 31ac2d97f14c..05a6e8af80c4 100644 --- a/arch/arm/mach-at91/include/mach/timex.h +++ b/arch/arm/mach-at91/include/mach/timex.h @@ -82,6 +82,11 @@ #define AT91X40_MASTER_CLOCK 40000000 #define CLOCK_TICK_RATE (AT91X40_MASTER_CLOCK) +#elif defined(CONFIG_ARCH_AT572D940HF) + +#define AT572D940HF_MASTER_CLOCK 80000000 +#define CLOCK_TICK_RATE (AT572D940HF_MASTER_CLOCK/16) + #endif #endif -- GitLab From c9a8fdd8b3ecdcfa3aa40e553c87c5787f5d70e4 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 15 Dec 2009 22:00:18 +0100 Subject: [PATCH 1004/3892] ARM: 5851/1: [AT91] AT572D940HF-EK board support Add support for the Atmel AT572D940HF-EK board (development board for the AT572D940HF processor). Signed-off-by: Antonio R. Costa Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/configs/at572d940hfek_defconfig | 1640 +++++++++++++++++++++ arch/arm/mach-at91/Kconfig | 17 + arch/arm/mach-at91/Makefile | 3 + arch/arm/mach-at91/board-at572d940hf_ek.c | 328 +++++ 4 files changed, 1988 insertions(+) create mode 100644 arch/arm/configs/at572d940hfek_defconfig create mode 100644 arch/arm/mach-at91/board-at572d940hf_ek.c diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig new file mode 100644 index 000000000000..76d724b8041a --- /dev/null +++ b/arch/arm/configs/at572d940hfek_defconfig @@ -0,0 +1,1640 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.28-rc7 +# Fri Dec 5 10:58:47 2008 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="-AT572D940HF" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_AUDIT=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NS is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +# CONFIG_USER_SCHED is not set +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_RESOURCE_COUNTERS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_MARKERS=y +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y +# CONFIG_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +CONFIG_ARCH_AT91=y +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set + +# +# Boot options +# + +# +# Power management +# + +# +# Atmel AT91 System-on-Chip +# +# CONFIG_ARCH_AT91RM9200 is not set +# CONFIG_ARCH_AT91SAM9260 is not set +# CONFIG_ARCH_AT91SAM9261 is not set +# CONFIG_ARCH_AT91SAM9263 is not set +# CONFIG_ARCH_AT91SAM9RL is not set +# CONFIG_ARCH_AT91SAM9G20 is not set +# CONFIG_ARCH_AT91CAP9 is not set +# CONFIG_ARCH_AT91X40 is not set +CONFIG_ARCH_AT572D940HF=y +CONFIG_AT91_PMC_UNIT=y + +# +# AT572D940HF Board Type +# +CONFIG_MACH_AT572D940HFEB=y + +# +# AT91 Board Options +# +# CONFIG_MTD_AT91_DATAFLASH_CARD is not set +# CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16 is not set +CONFIG_NUM_SERIAL=3 + +# +# AT91 Feature Selections +# +CONFIG_AT91_PROGRAMMABLE_CLOCKS=y +CONFIG_AT91_TIMER_HZ=100 +CONFIG_AT91_EARLY_DBGU=y +# CONFIG_AT91_EARLY_USART0 is not set +# CONFIG_AT91_EARLY_USART1 is not set +# CONFIG_AT91_EARLY_USART2 is not set +# CONFIG_AT91_EARLY_USART3 is not set +# CONFIG_AT91_EARLY_USART4 is not set +# CONFIG_AT91_EARLY_USART5 is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +# CONFIG_AEABI is not set +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +CONFIG_RESOURCES_64BIT=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="mem=48M console=ttyS0 initrd=0x21100000,3145728 root=/dev/ram0 rw ip=172.16.1.181" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +CONFIG_FPE_NWFPE_XP=y +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +# CONFIG_HAMRADIO is not set +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=m +CONFIG_CAN_DEBUG_DEVICES=y +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_PHONET is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_MAC80211 is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_CRYPT_CCMP is not set +# CONFIG_IEEE80211_CRYPT_TKIP is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_IMPA7 is not set +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set +# CONFIG_MTD_DATAFLASH_OTP is not set +CONFIG_MTD_M25P80=m +CONFIG_M25PXX_USE_FAST_READ=y +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_VERIFY_WRITE=y +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +# CONFIG_MTD_NAND_ATMEL is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ICS932S401 is not set +CONFIG_ATMEL_SSC=m +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +# CONFIG_REALTEK_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_MACB=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_SMC911X is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_WLAN_80211=y +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_USB_ZD1201=m +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_IWLWIFI_LEDS is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +# CONFIG_USB_NET_SMSC95XX is not set +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_GPIO=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +# CONFIG_MOUSE_BCM5974 is not set +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOUSE_GPIO=m +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVKMEM=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +CONFIG_SPECIALIX=m +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_SERIAL_ATMEL_PDC=y +# CONFIG_SERIAL_ATMEL_TTYAT is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_NVRAM=m +CONFIG_R3964=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_TCG_TPM=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_DS1682=m +# CONFIG_AT24 is not set +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_ATMEL=y +CONFIG_SPI_BITBANG=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DRIVERS=y +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +# CONFIG_SND_AT73C213 is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +# CONFIG_SND_SOC is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m + +# +# Special HID drivers +# +CONFIG_HID_COMPAT=y +CONFIG_HID_A4TECH=m +CONFIG_HID_APPLE=m +CONFIG_HID_BELKIN=m +CONFIG_HID_BRIGHT=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DELL=m +CONFIG_HID_EZKEY=m +CONFIG_HID_GYRATION=m +CONFIG_HID_LOGITECH=m +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_PANTHERLORD=m +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_HID_SUNPLUS=m +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_ZEROPLUS_FF is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DYNAMIC_MINORS=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; +# + +# +# see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +# CONFIG_USB_STORAGE_ONETOUCH is not set +CONFIG_USB_STORAGE_KARMA=y +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +CONFIG_USB_EZUSB=y +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP2101 is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_OTI6858 is not set +CONFIG_USB_SERIAL_SPCP8X5=m +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +CONFIG_USB_SERIAL_DEBUG=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +CONFIG_USB_TEST=m +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +CONFIG_USB_GADGET=m +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_AT91=y +CONFIG_USB_AT91=m +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +CONFIG_MMC_AT91=y +CONFIG_MMC_SPI=m +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=m +# CONFIG_LEDS_PCA955X is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +CONFIG_RTC_DRV_DS1305=y +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_AT91SAM9 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_CHECK=y +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_UBIFS_FS is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +# CONFIG_SUNRPC_REGISTER_V4 is not set +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_LDM_DEBUG=y +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=m +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_FRAME_POINTER=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y + +# +# Tracers +# +# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_SECURITYFS=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_GF128MUL=m +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +# CONFIG_CRC_T10DIF is not set +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index c67fa3b7eeb1..2db43a5ddd9b 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -396,6 +396,23 @@ endif # ---------------------------------------------------------- +if ARCH_AT572D940HF + +comment "AT572D940HF Board Type" + +config MACH_AT572D940HFEB + bool "AT572D940HF-EK" + depends on ARCH_AT572D940HF + select HAVE_AT91_DATAFLASH_CARD + select HAVE_NAND_ATMEL_BUSWIDTH_16 + help + Select this if you are using Atmel's AT572D940HF-EK evaluation kit. + + +endif + +# ---------------------------------------------------------- + if ARCH_AT91X40 comment "AT91X40 Board Type" diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 8ddce96b6aa5..027dd570dcc3 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -70,6 +70,9 @@ obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o # AT91CAP9 board-specific support obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o +# AT572D940HF board-specific support +obj-$(CONFIG_MACH_AT572D940HFEB) += board-at572d940hf_ek.o + # AT91X40 board-specific support obj-$(CONFIG_MACH_AT91EB01) += board-eb01.o diff --git a/arch/arm/mach-at91/board-at572d940hf_ek.c b/arch/arm/mach-at91/board-at572d940hf_ek.c new file mode 100644 index 000000000000..5daff277f53e --- /dev/null +++ b/arch/arm/mach-at91/board-at572d940hf_ek.c @@ -0,0 +1,328 @@ +/* + * linux/arch/arm/mach-at91/board-at572d940hf_ek.c + * + * Copyright (C) 2008 Atmel Antonio R. Costa + * Copyright (C) 2005 SAN People + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "sam9_smc.h" +#include "generic.h" + + +static void __init eb_map_io(void) +{ + /* Initialize processor: 12.500 MHz crystal */ + at572d940hf_initialize(12000000); + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); + + /* USART0 on ttyS1. (Rx & Tx only) */ + at91_register_uart(AT572D940HF_ID_US0, 1, 0); + + /* USART1 on ttyS2. (Rx & Tx only) */ + at91_register_uart(AT572D940HF_ID_US1, 2, 0); + + /* USART2 on ttyS3. (Tx & Rx only */ + at91_register_uart(AT572D940HF_ID_US2, 3, 0); + + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); +} + +static void __init eb_init_irq(void) +{ + at572d940hf_init_interrupts(NULL); +} + + +/* + * USB Host Port + */ +static struct at91_usbh_data __initdata eb_usbh_data = { + .ports = 2, +}; + + +/* + * USB Device Port + */ +static struct at91_udc_data __initdata eb_udc_data = { + .vbus_pin = 0, /* no VBUS detection,UDC always on */ + .pullup_pin = 0, /* pull-up driven by UDC */ +}; + + +/* + * MCI (SD/MMC) + */ +static struct at91_mmc_data __initdata eb_mmc_data = { + .wire4 = 1, +/* .det_pin = ... not connected */ +/* .wp_pin = ... not connected */ +/* .vcc_pin = ... not connected */ +}; + + +/* + * MACB Ethernet device + */ +static struct at91_eth_data __initdata eb_eth_data = { + .phy_irq_pin = AT91_PIN_PB25, + .is_rmii = 1, +}; + +/* + * NOR flash + */ + +static struct mtd_partition eb_nor_partitions[] = { + { + .name = "Raw Environment", + .offset = 0, + .size = SZ_4M, + .mask_flags = 0, + }, + { + .name = "OS FS", + .offset = MTDPART_OFS_APPEND, + .size = 3 * SZ_1M, + .mask_flags = 0, + }, + { + .name = "APP FS", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + }, +}; + +static void nor_flash_set_vpp(struct map_info* mi, int i) { +}; + +static struct physmap_flash_data nor_flash_data = { + .width = 4, + .parts = eb_nor_partitions, + .nr_parts = ARRAY_SIZE(eb_nor_partitions), + .set_vpp = nor_flash_set_vpp, +}; + +static struct resource nor_flash_resources[] = { + { + .start = AT91_CHIPSELECT_0, + .end = AT91_CHIPSELECT_0 + SZ_16M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device nor_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &nor_flash_data, + }, + .resource = nor_flash_resources, + .num_resources = ARRAY_SIZE(nor_flash_resources), +}; + +static struct sam9_smc_config __initdata eb_nor_smc_config = { + .ncs_read_setup = 1, + .nrd_setup = 1, + .ncs_write_setup = 1, + .nwe_setup = 1, + + .ncs_read_pulse = 7, + .nrd_pulse = 7, + .ncs_write_pulse = 7, + .nwe_pulse = 7, + + .read_cycle = 9, + .write_cycle = 9, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_32, + .tdf_cycles = 1, +}; + +static void __init eb_add_device_nor(void) +{ + /* configure chip-select 0 (NOR) */ + sam9_smc_configure(0, &eb_nor_smc_config); + platform_device_register(&nor_flash); +} + +/* + * NAND flash + */ +static struct mtd_partition __initdata eb_nand_partition[] = { + { + .name = "Partition 1", + .offset = 0, + .size = SZ_16M, + }, + { + .name = "Partition 2", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) +{ + *num_partitions = ARRAY_SIZE(eb_nand_partition); + return eb_nand_partition; +} + +static struct atmel_nand_data __initdata eb_nand_data = { + .ale = 22, + .cle = 21, +/* .det_pin = ... not connected */ +/* .rdy_pin = AT91_PIN_PC16, */ + .enable_pin = AT91_PIN_PA15, + .partition_info = nand_partitions, +#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) + .bus_width_16 = 1, +#else + .bus_width_16 = 0, +#endif +}; + +static struct sam9_smc_config __initdata eb_nand_smc_config = { + .ncs_read_setup = 0, + .nrd_setup = 0, + .ncs_write_setup = 1, + .nwe_setup = 1, + + .ncs_read_pulse = 3, + .nrd_pulse = 3, + .ncs_write_pulse = 3, + .nwe_pulse = 3, + + .read_cycle = 5, + .write_cycle = 5, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 12, +}; + +static void __init eb_add_device_nand(void) +{ + /* setup bus-width (8 or 16) */ + if (eb_nand_data.bus_width_16) + eb_nand_smc_config.mode |= AT91_SMC_DBW_16; + else + eb_nand_smc_config.mode |= AT91_SMC_DBW_8; + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &eb_nand_smc_config); + + at91_add_device_nand(&eb_nand_data); +} + + +/* + * SPI devices + */ +static struct resource rtc_resources[] = { + [0] = { + .start = AT572D940HF_ID_IRQ1, + .end = AT572D940HF_ID_IRQ1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ds1305_platform_data ds1306_data = { + .is_ds1306 = true, + .en_1hz = false, +}; + +static struct spi_board_info eb_spi_devices[] = { + { /* RTC Dallas DS1306 */ + .modalias = "rtc-ds1305", + .chip_select = 3, + .mode = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA, + .max_speed_hz = 500000, + .bus_num = 0, + .irq = AT572D940HF_ID_IRQ1, + .platform_data = (void *) &ds1306_data, + }, +#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD) + { /* Dataflash card */ + .modalias = "mtd_dataflash", + .chip_select = 0, + .max_speed_hz = 15 * 1000 * 1000, + .bus_num = 0, + }, +#endif +}; + +static void __init eb_board_init(void) +{ + /* Serial */ + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&eb_usbh_data); + /* USB Device */ + at91_add_device_udc(&eb_udc_data); + /* I2C */ + at91_add_device_i2c(NULL, 0); + /* NOR */ + eb_add_device_nor(); + /* NAND */ + eb_add_device_nand(); + /* SPI */ + at91_add_device_spi(eb_spi_devices, ARRAY_SIZE(eb_spi_devices)); + /* MMC */ + at91_add_device_mmc(0, &eb_mmc_data); + /* Ethernet */ + at91_add_device_eth(&eb_eth_data); + /* mAgic */ + at91_add_device_mAgic(); +} + +MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB") + /* Maintainer: Atmel */ + .phys_io = AT91_BASE_SYS, + .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, + .boot_params = AT91_SDRAM_BASE + 0x100, + .timer = &at91sam926x_timer, + .map_io = eb_map_io, + .init_irq = eb_init_irq, + .init_machine = eb_board_init, +MACHINE_END -- GitLab From c26c20b823d48addbde9cb5709d80655c6fadf18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 16:21:35 +0000 Subject: [PATCH 1005/3892] ARM: make_coherent: split adjust_pte() in two adjust_pte() walks the page tables, and do_adjust_pte() does the page table manipulation. Signed-off-by: Russell King --- arch/arm/mm/fault-armv.c | 52 ++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 56ee15321b00..074e6bb54eb3 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -36,28 +36,12 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; * Therefore those configurations which might call adjust_pte (those * without CONFIG_CPU_CACHE_VIPT) cannot support split page_table_lock. */ -static int adjust_pte(struct vm_area_struct *vma, unsigned long address) +static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, + pte_t *ptep) { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, entry; + pte_t entry = *ptep; int ret; - pgd = pgd_offset(vma->vm_mm, address); - if (pgd_none(*pgd)) - goto no_pgd; - if (pgd_bad(*pgd)) - goto bad_pgd; - - pmd = pmd_offset(pgd, address); - if (pmd_none(*pmd)) - goto no_pmd; - if (pmd_bad(*pmd)) - goto bad_pmd; - - pte = pte_offset_map(pmd, address); - entry = *pte; - /* * If this page is present, it's actually being shared. */ @@ -74,10 +58,38 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) (pfn << PAGE_SHIFT) + PAGE_SIZE); pte_val(entry) &= ~L_PTE_MT_MASK; pte_val(entry) |= shared_pte_mask; - set_pte_at(vma->vm_mm, address, pte, entry); + set_pte_at(vma->vm_mm, address, ptep, entry); flush_tlb_page(vma, address); } + + return ret; +} + +static int adjust_pte(struct vm_area_struct *vma, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int ret; + + pgd = pgd_offset(vma->vm_mm, address); + if (pgd_none(*pgd)) + goto no_pgd; + if (pgd_bad(*pgd)) + goto bad_pgd; + + pmd = pmd_offset(pgd, address); + if (pmd_none(*pmd)) + goto no_pmd; + if (pmd_bad(*pmd)) + goto bad_pmd; + + pte = pte_offset_map(pmd, address); + + ret = do_adjust_pte(vma, address, pte); + pte_unmap(pte); + return ret; bad_pgd: -- GitLab From f8a85f1164a33e3eb5b421b137ced793ed53ee33 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 16:23:44 +0000 Subject: [PATCH 1006/3892] ARM: make_coherent: convert adjust_pte() to use p*d_none_or_clear_bad() Signed-off-by: Russell King --- arch/arm/mm/fault-armv.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 074e6bb54eb3..7a8efe1b37d8 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -73,16 +73,12 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) int ret; pgd = pgd_offset(vma->vm_mm, address); - if (pgd_none(*pgd)) - goto no_pgd; - if (pgd_bad(*pgd)) - goto bad_pgd; + if (pgd_none_or_clear_bad(pgd)) + return 0; pmd = pmd_offset(pgd, address); - if (pmd_none(*pmd)) - goto no_pmd; - if (pmd_bad(*pmd)) - goto bad_pmd; + if (pmd_none_or_clear_bad(pmd)) + return 0; pte = pte_offset_map(pmd, address); @@ -91,18 +87,6 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) pte_unmap(pte); return ret; - -bad_pgd: - pgd_ERROR(*pgd); - pgd_clear(pgd); -no_pgd: - return 0; - -bad_pmd: - pmd_ERROR(*pmd); - pmd_clear(pmd); -no_pmd: - return 0; } static void -- GitLab From 56dd47098abe1fdde598a8d8b7c04d775506f456 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 16:24:34 +0000 Subject: [PATCH 1007/3892] ARM: make_coherent: fix problems with highpte, part 1 update_mmu_cache() is called with a page table already mapped. We call make_coherent(), which then calls adjust_pte() which wants to map other page tables. This causes kmap_atomic() to BUG() because the slot its trying to use is already taken. Since do_adjust_pte() modifies the page tables, we are also missing any form of locking, so we're risking corrupting the page tables. Fix this by using pte_offset_map_nested(), and taking the pte page table lock around do_adjust_pte(). Signed-off-by: Russell King --- arch/arm/mm/fault-armv.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 7a8efe1b37d8..8e9bc517132e 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -67,6 +67,7 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, static int adjust_pte(struct vm_area_struct *vma, unsigned long address) { + spinlock_t *ptl; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -80,11 +81,19 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) if (pmd_none_or_clear_bad(pmd)) return 0; - pte = pte_offset_map(pmd, address); + /* + * This is called while another page table is mapped, so we + * must use the nested version. This also means we need to + * open-code the spin-locking. + */ + ptl = pte_lockptr(vma->vm_mm, pmd); + pte = pte_offset_map_nested(pmd, address); + spin_lock(ptl); ret = do_adjust_pte(vma, address, pte); - pte_unmap(pte); + spin_unlock(ptl); + pte_unmap_nested(pte); return ret; } -- GitLab From ed42acaef1a9d51631a31b55e9ed52d400430492 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 16:31:38 +0000 Subject: [PATCH 1008/3892] ARM: make_coherent: avoid recalculating the pfn for the modified page We already know the pfn for the page to be modified in make_coherent, so let's stop recalculating it unnecessarily. Signed-off-by: Russell King --- arch/arm/mm/fault-armv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 8e9bc517132e..ae88f2c3a6df 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -37,7 +37,7 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; * without CONFIG_CPU_CACHE_VIPT) cannot support split page_table_lock. */ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, - pte_t *ptep) + unsigned long pfn, pte_t *ptep) { pte_t entry = *ptep; int ret; @@ -52,7 +52,6 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, * fault (ie, is old), we can safely ignore any issues. */ if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) { - unsigned long pfn = pte_pfn(entry); flush_cache_page(vma, address, pfn); outer_flush_range((pfn << PAGE_SHIFT), (pfn << PAGE_SHIFT) + PAGE_SIZE); @@ -65,7 +64,8 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, return ret; } -static int adjust_pte(struct vm_area_struct *vma, unsigned long address) +static int adjust_pte(struct vm_area_struct *vma, unsigned long address, + unsigned long pfn) { spinlock_t *ptl; pgd_t *pgd; @@ -90,7 +90,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) pte = pte_offset_map_nested(pmd, address); spin_lock(ptl); - ret = do_adjust_pte(vma, address, pte); + ret = do_adjust_pte(vma, address, pfn, pte); spin_unlock(ptl); pte_unmap_nested(pte); @@ -127,11 +127,11 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigne if (!(mpnt->vm_flags & VM_MAYSHARE)) continue; offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; - aliases += adjust_pte(mpnt, mpnt->vm_start + offset); + aliases += adjust_pte(mpnt, mpnt->vm_start + offset, pfn); } flush_dcache_mmap_unlock(mapping); if (aliases) - adjust_pte(vma, addr); + adjust_pte(vma, addr, pfn); else flush_cache_page(vma, addr, pfn); } -- GitLab From 358934a60d2180dcd1ed20691dbb66d4fb977ab2 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Wed, 16 Dec 2009 22:02:18 +0000 Subject: [PATCH 1009/3892] spi: Add SPI master driver for DaVinci/DA8xx This patch adds support for a SPI master driver for the DaVinci series of SOCs Signed-off-by: Sandeep Paulraj Signed-off-by: Mark A. Greer Signed-off-by: Philby John Signed-off-by: Sudhakar Rajashekhara Signed-off-by: Kevin Hilman Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/davinci_spi.c | 1255 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1263 insertions(+) create mode 100644 drivers/spi/davinci_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f55eb0107336..82dabbca00c1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -100,6 +100,13 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_DAVINCI + tristate "SPI controller driver for DaVinci/DA8xx SoC's" + depends on SPI_MASTER && ARCH_DAVINCI + select SPI_BITBANG + help + SPI master controller for DaVinci and DA8xx SPI modules. + config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" depends on GENERIC_GPIO diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f3d2810ba11c..84b490fb7f8a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c new file mode 100644 index 000000000000..225ab60b02c4 --- /dev/null +++ b/drivers/spi/davinci_spi.c @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2009 Texas Instruments. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#define SPI_NO_RESOURCE ((resource_size_t)-1) + +#define SPI_MAX_CHIPSELECT 2 + +#define CS_DEFAULT 0xFF + +#define SPI_BUFSIZ (SMP_CACHE_BYTES + 1) +#define DAVINCI_DMA_DATA_TYPE_S8 0x01 +#define DAVINCI_DMA_DATA_TYPE_S16 0x02 +#define DAVINCI_DMA_DATA_TYPE_S32 0x04 + +#define SPIFMT_PHASE_MASK BIT(16) +#define SPIFMT_POLARITY_MASK BIT(17) +#define SPIFMT_DISTIMER_MASK BIT(18) +#define SPIFMT_SHIFTDIR_MASK BIT(20) +#define SPIFMT_WAITENA_MASK BIT(21) +#define SPIFMT_PARITYENA_MASK BIT(22) +#define SPIFMT_ODD_PARITY_MASK BIT(23) +#define SPIFMT_WDELAY_MASK 0x3f000000u +#define SPIFMT_WDELAY_SHIFT 24 +#define SPIFMT_CHARLEN_MASK 0x0000001Fu + +/* SPIGCR1 */ +#define SPIGCR1_SPIENA_MASK 0x01000000u + +/* SPIPC0 */ +#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */ +#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */ +#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */ +#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ +#define SPIPC0_EN1FUN_MASK BIT(1) +#define SPIPC0_EN0FUN_MASK BIT(0) + +#define SPIINT_MASKALL 0x0101035F +#define SPI_INTLVL_1 0x000001FFu +#define SPI_INTLVL_0 0x00000000u + +/* SPIDAT1 */ +#define SPIDAT1_CSHOLD_SHIFT 28 +#define SPIDAT1_CSNR_SHIFT 16 +#define SPIGCR1_CLKMOD_MASK BIT(1) +#define SPIGCR1_MASTER_MASK BIT(0) +#define SPIGCR1_LOOPBACK_MASK BIT(16) + +/* SPIBUF */ +#define SPIBUF_TXFULL_MASK BIT(29) +#define SPIBUF_RXEMPTY_MASK BIT(31) + +/* Error Masks */ +#define SPIFLG_DLEN_ERR_MASK BIT(0) +#define SPIFLG_TIMEOUT_MASK BIT(1) +#define SPIFLG_PARERR_MASK BIT(2) +#define SPIFLG_DESYNC_MASK BIT(3) +#define SPIFLG_BITERR_MASK BIT(4) +#define SPIFLG_OVRRUN_MASK BIT(6) +#define SPIFLG_RX_INTR_MASK BIT(8) +#define SPIFLG_TX_INTR_MASK BIT(9) +#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24) +#define SPIFLG_MASK (SPIFLG_DLEN_ERR_MASK \ + | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \ + | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \ + | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \ + | SPIFLG_TX_INTR_MASK \ + | SPIFLG_BUF_INIT_ACTIVE_MASK) + +#define SPIINT_DLEN_ERR_INTR BIT(0) +#define SPIINT_TIMEOUT_INTR BIT(1) +#define SPIINT_PARERR_INTR BIT(2) +#define SPIINT_DESYNC_INTR BIT(3) +#define SPIINT_BITERR_INTR BIT(4) +#define SPIINT_OVRRUN_INTR BIT(6) +#define SPIINT_RX_INTR BIT(8) +#define SPIINT_TX_INTR BIT(9) +#define SPIINT_DMA_REQ_EN BIT(16) +#define SPIINT_ENABLE_HIGHZ BIT(24) + +#define SPI_T2CDELAY_SHIFT 16 +#define SPI_C2TDELAY_SHIFT 24 + +/* SPI Controller registers */ +#define SPIGCR0 0x00 +#define SPIGCR1 0x04 +#define SPIINT 0x08 +#define SPILVL 0x0c +#define SPIFLG 0x10 +#define SPIPC0 0x14 +#define SPIPC1 0x18 +#define SPIPC2 0x1c +#define SPIPC3 0x20 +#define SPIPC4 0x24 +#define SPIPC5 0x28 +#define SPIPC6 0x2c +#define SPIPC7 0x30 +#define SPIPC8 0x34 +#define SPIDAT0 0x38 +#define SPIDAT1 0x3c +#define SPIBUF 0x40 +#define SPIEMU 0x44 +#define SPIDELAY 0x48 +#define SPIDEF 0x4c +#define SPIFMT0 0x50 +#define SPIFMT1 0x54 +#define SPIFMT2 0x58 +#define SPIFMT3 0x5c +#define TGINTVEC0 0x60 +#define TGINTVEC1 0x64 + +struct davinci_spi_slave { + u32 cmd_to_write; + u32 clk_ctrl_to_write; + u32 bytes_per_word; + u8 active_cs; +}; + +/* We have 2 DMA channels per CS, one for RX and one for TX */ +struct davinci_spi_dma { + int dma_tx_channel; + int dma_rx_channel; + int dma_tx_sync_dev; + int dma_rx_sync_dev; + enum dma_event_q eventq; + + struct completion dma_tx_completion; + struct completion dma_rx_completion; +}; + +/* SPI Controller driver's private data. */ +struct davinci_spi { + struct spi_bitbang bitbang; + struct clk *clk; + + u8 version; + resource_size_t pbase; + void __iomem *base; + size_t region_size; + u32 irq; + struct completion done; + + const void *tx; + void *rx; + u8 *tmp_buf; + int count; + struct davinci_spi_dma *dma_channels; + struct davinci_spi_platform_data *pdata; + + void (*get_rx)(u32 rx_data, struct davinci_spi *); + u32 (*get_tx)(struct davinci_spi *); + + struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT]; +}; + +static unsigned use_dma; + +static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi) +{ + u8 *rx = davinci_spi->rx; + + *rx++ = (u8)data; + davinci_spi->rx = rx; +} + +static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi) +{ + u16 *rx = davinci_spi->rx; + + *rx++ = (u16)data; + davinci_spi->rx = rx; +} + +static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi) +{ + u32 data; + const u8 *tx = davinci_spi->tx; + + data = *tx++; + davinci_spi->tx = tx; + return data; +} + +static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi) +{ + u32 data; + const u16 *tx = davinci_spi->tx; + + data = *tx++; + davinci_spi->tx = tx; + return data; +} + +static inline void set_io_bits(void __iomem *addr, u32 bits) +{ + u32 v = ioread32(addr); + + v |= bits; + iowrite32(v, addr); +} + +static inline void clear_io_bits(void __iomem *addr, u32 bits) +{ + u32 v = ioread32(addr); + + v &= ~bits; + iowrite32(v, addr); +} + +static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num) +{ + set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits); +} + +static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num) +{ + clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits); +} + +static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable) +{ + struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master); + + if (enable) + set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); + else + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); +} + +/* + * Interface to control the chip select signal + */ +static void davinci_spi_chipselect(struct spi_device *spi, int value) +{ + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + u32 data1_reg_val = 0; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + /* + * Board specific chip select logic decides the polarity and cs + * line for the controller + */ + if (value == BITBANG_CS_INACTIVE) { + set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT); + + data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT; + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + } +} + +/** + * davinci_spi_setup_transfer - This functions will determine transfer method + * @spi: spi device on which data transfer to be done + * @t: spi transfer in which transfer info is filled + * + * This function determines data transfer method (8/16/32 bit transfer). + * It will also set the SPI Clock Control register according to + * SPI slave device freq. + */ +static int davinci_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + u8 bits_per_word = 0; + u32 hz = 0, prescale; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + if (t) { + bits_per_word = t->bits_per_word; + hz = t->speed_hz; + } + + /* if bits_per_word is not set then set it default */ + if (!bits_per_word) + bits_per_word = spi->bits_per_word; + + /* + * Assign function pointer to appropriate transfer method + * 8bit, 16bit or 32bit transfer + */ + if (bits_per_word <= 8 && bits_per_word >= 2) { + davinci_spi->get_rx = davinci_spi_rx_buf_u8; + davinci_spi->get_tx = davinci_spi_tx_buf_u8; + davinci_spi->slave[spi->chip_select].bytes_per_word = 1; + } else if (bits_per_word <= 16 && bits_per_word >= 2) { + davinci_spi->get_rx = davinci_spi_rx_buf_u16; + davinci_spi->get_tx = davinci_spi_tx_buf_u16; + davinci_spi->slave[spi->chip_select].bytes_per_word = 2; + } else + return -EINVAL; + + if (!hz) + hz = spi->max_speed_hz; + + clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK, + spi->chip_select); + set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f, + spi->chip_select); + + prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff; + + clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select); + set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select); + + return 0; +} + +static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data) +{ + struct spi_device *spi = (struct spi_device *)data; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); + pdata = davinci_spi->pdata; + + if (ch_status == DMA_COMPLETE) + edma_stop(davinci_spi_dma->dma_rx_channel); + else + edma_clean_channel(davinci_spi_dma->dma_rx_channel); + + complete(&davinci_spi_dma->dma_rx_completion); + /* We must disable the DMA RX request */ + davinci_spi_set_dma_req(spi, 0); +} + +static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data) +{ + struct spi_device *spi = (struct spi_device *)data; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); + pdata = davinci_spi->pdata; + + if (ch_status == DMA_COMPLETE) + edma_stop(davinci_spi_dma->dma_tx_channel); + else + edma_clean_channel(davinci_spi_dma->dma_tx_channel); + + complete(&davinci_spi_dma->dma_tx_completion); + /* We must disable the DMA TX request */ + davinci_spi_set_dma_req(spi, 0); +} + +static int davinci_spi_request_dma(struct spi_device *spi) +{ + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_platform_data *pdata; + struct device *sdev; + int r; + + davinci_spi = spi_master_get_devdata(spi->master); + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + pdata = davinci_spi->pdata; + sdev = davinci_spi->bitbang.master->dev.parent; + + r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev, + davinci_spi_dma_rx_callback, spi, + davinci_spi_dma->eventq); + if (r < 0) { + dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n"); + return -EAGAIN; + } + davinci_spi_dma->dma_rx_channel = r; + r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev, + davinci_spi_dma_tx_callback, spi, + davinci_spi_dma->eventq); + if (r < 0) { + edma_free_channel(davinci_spi_dma->dma_rx_channel); + davinci_spi_dma->dma_rx_channel = -1; + dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n"); + return -EAGAIN; + } + davinci_spi_dma->dma_tx_channel = r; + + return 0; +} + +/** + * davinci_spi_setup - This functions will set default transfer method + * @spi: spi device on which data transfer to be done + * + * This functions sets the default transfer method. + */ + +static int davinci_spi_setup(struct spi_device *spi) +{ + int retval; + struct davinci_spi *davinci_spi; + struct davinci_spi_dma *davinci_spi_dma; + struct device *sdev; + + davinci_spi = spi_master_get_devdata(spi->master); + sdev = davinci_spi->bitbang.master->dev.parent; + + /* if bits per word length is zero then set it default 8 */ + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + davinci_spi->slave[spi->chip_select].cmd_to_write = 0; + + if (use_dma && davinci_spi->dma_channels) { + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if ((davinci_spi_dma->dma_rx_channel == -1) + || (davinci_spi_dma->dma_tx_channel == -1)) { + retval = davinci_spi_request_dma(spi); + if (retval < 0) + return retval; + } + } + + /* + * SPI in DaVinci and DA8xx operate between + * 600 KHz and 50 MHz + */ + if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) { + dev_dbg(sdev, "Operating frequency is not in acceptable " + "range\n"); + return -EINVAL; + } + + /* + * Set up SPIFMTn register, unique to this chipselect. + * + * NOTE: we could do all of these with one write. Also, some + * of the "version 2" features are found in chips that don't + * support all of them... + */ + if (spi->mode & SPI_LSB_FIRST) + set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK, + spi->chip_select); + + if (spi->mode & SPI_CPOL) + set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK, + spi->chip_select); + + if (!(spi->mode & SPI_CPHA)) + set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK, + spi->chip_select); + + /* + * Version 1 hardware supports two basic SPI modes: + * - Standard SPI mode uses 4 pins, with chipselect + * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS) + * (distinct from SPI_3WIRE, with just one data wire; + * or similar variants without MOSI or without MISO) + * + * Version 2 hardware supports an optional handshaking signal, + * so it can support two more modes: + * - 5 pin SPI variant is standard SPI plus SPI_READY + * - 4 pin with enable is (SPI_READY | SPI_NO_CS) + */ + + if (davinci_spi->version == SPI_VERSION_2) { + clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK, + spi->chip_select); + set_fmt_bits(davinci_spi->base, + (davinci_spi->pdata->wdelay + << SPIFMT_WDELAY_SHIFT) + & SPIFMT_WDELAY_MASK, + spi->chip_select); + + if (davinci_spi->pdata->odd_parity) + set_fmt_bits(davinci_spi->base, + SPIFMT_ODD_PARITY_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_ODD_PARITY_MASK, + spi->chip_select); + + if (davinci_spi->pdata->parity_enable) + set_fmt_bits(davinci_spi->base, + SPIFMT_PARITYENA_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_PARITYENA_MASK, + spi->chip_select); + + if (davinci_spi->pdata->wait_enable) + set_fmt_bits(davinci_spi->base, + SPIFMT_WAITENA_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_WAITENA_MASK, + spi->chip_select); + + if (davinci_spi->pdata->timer_disable) + set_fmt_bits(davinci_spi->base, + SPIFMT_DISTIMER_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, + SPIFMT_DISTIMER_MASK, + spi->chip_select); + } + + retval = davinci_spi_setup_transfer(spi, NULL); + + return retval; +} + +static void davinci_spi_cleanup(struct spi_device *spi) +{ + struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master); + struct davinci_spi_dma *davinci_spi_dma; + + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if (use_dma && davinci_spi->dma_channels) { + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + if ((davinci_spi_dma->dma_rx_channel != -1) + && (davinci_spi_dma->dma_tx_channel != -1)) { + edma_free_channel(davinci_spi_dma->dma_tx_channel); + edma_free_channel(davinci_spi_dma->dma_rx_channel); + } + } +} + +static int davinci_spi_bufs_prep(struct spi_device *spi, + struct davinci_spi *davinci_spi) +{ + int op_mode = 0; + + /* + * REVISIT unless devices disagree about SPI_LOOP or + * SPI_READY (SPI_NO_CS only allows one device!), this + * should not need to be done before each message... + * optimize for both flags staying cleared. + */ + + op_mode = SPIPC0_DIFUN_MASK + | SPIPC0_DOFUN_MASK + | SPIPC0_CLKFUN_MASK; + if (!(spi->mode & SPI_NO_CS)) + op_mode |= 1 << spi->chip_select; + if (spi->mode & SPI_READY) + op_mode |= SPIPC0_SPIENA_MASK; + + iowrite32(op_mode, davinci_spi->base + SPIPC0); + + if (spi->mode & SPI_LOOP) + set_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_LOOPBACK_MASK); + else + clear_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_LOOPBACK_MASK); + + return 0; +} + +static int davinci_spi_check_error(struct davinci_spi *davinci_spi, + int int_status) +{ + struct device *sdev = davinci_spi->bitbang.master->dev.parent; + + if (int_status & SPIFLG_TIMEOUT_MASK) { + dev_dbg(sdev, "SPI Time-out Error\n"); + return -ETIMEDOUT; + } + if (int_status & SPIFLG_DESYNC_MASK) { + dev_dbg(sdev, "SPI Desynchronization Error\n"); + return -EIO; + } + if (int_status & SPIFLG_BITERR_MASK) { + dev_dbg(sdev, "SPI Bit error\n"); + return -EIO; + } + + if (davinci_spi->version == SPI_VERSION_2) { + if (int_status & SPIFLG_DLEN_ERR_MASK) { + dev_dbg(sdev, "SPI Data Length Error\n"); + return -EIO; + } + if (int_status & SPIFLG_PARERR_MASK) { + dev_dbg(sdev, "SPI Parity Error\n"); + return -EIO; + } + if (int_status & SPIFLG_OVRRUN_MASK) { + dev_dbg(sdev, "SPI Data Overrun error\n"); + return -EIO; + } + if (int_status & SPIFLG_TX_INTR_MASK) { + dev_dbg(sdev, "SPI TX intr bit set\n"); + return -EIO; + } + if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) { + dev_dbg(sdev, "SPI Buffer Init Active\n"); + return -EBUSY; + } + } + + return 0; +} + +/** + * davinci_spi_bufs - functions which will handle transfer data + * @spi: spi device on which data transfer to be done + * @t: spi transfer in which transfer info is filled + * + * This function will put data to be transferred into data register + * of SPI controller and then wait until the completion will be marked + * by the IRQ Handler. + */ +static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) +{ + struct davinci_spi *davinci_spi; + int int_status, count, ret; + u8 conv, tmp; + u32 tx_data, data1_reg_val; + u32 buf_val, flg_val; + struct davinci_spi_platform_data *pdata; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + + davinci_spi->tx = t->tx_buf; + davinci_spi->rx = t->rx_buf; + + /* convert len to words based on bits_per_word */ + conv = davinci_spi->slave[spi->chip_select].bytes_per_word; + davinci_spi->count = t->len / conv; + + INIT_COMPLETION(davinci_spi->done); + + ret = davinci_spi_bufs_prep(spi, davinci_spi); + if (ret) + return ret; + + /* Enable SPI */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + + iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | + (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + davinci_spi->base + SPIDELAY); + + count = davinci_spi->count; + data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT; + tmp = ~(0x1 << spi->chip_select); + + clear_io_bits(davinci_spi->base + SPIDEF, ~tmp); + + data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + + /* Determine the command to execute READ or WRITE */ + if (t->tx_buf) { + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + + while (1) { + tx_data = davinci_spi->get_tx(davinci_spi); + + data1_reg_val &= ~(0xFFFF); + data1_reg_val |= (0xFFFF & tx_data); + + buf_val = ioread32(davinci_spi->base + SPIBUF); + if ((buf_val & SPIBUF_TXFULL_MASK) == 0) { + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + count--; + } + while (ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) + cpu_relax(); + + /* getting the returned byte */ + if (t->rx_buf) { + buf_val = ioread32(davinci_spi->base + SPIBUF); + davinci_spi->get_rx(buf_val, davinci_spi); + } + if (count <= 0) + break; + } + } else { + if (pdata->poll_mode) { + while (1) { + /* keeps the serial clock going */ + if ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_TXFULL_MASK) == 0) + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + while (ioread32(davinci_spi->base + SPIBUF) & + SPIBUF_RXEMPTY_MASK) + cpu_relax(); + + flg_val = ioread32(davinci_spi->base + SPIFLG); + buf_val = ioread32(davinci_spi->base + SPIBUF); + + davinci_spi->get_rx(buf_val, davinci_spi); + + count--; + if (count <= 0) + break; + } + } else { /* Receive in Interrupt mode */ + int i; + + for (i = 0; i < davinci_spi->count; i++) { + set_io_bits(davinci_spi->base + SPIINT, + SPIINT_BITERR_INTR + | SPIINT_OVRRUN_INTR + | SPIINT_RX_INTR); + + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); + + while (ioread32(davinci_spi->base + SPIINT) & + SPIINT_RX_INTR) + cpu_relax(); + } + iowrite32((data1_reg_val & 0x0ffcffff), + davinci_spi->base + SPIDAT1); + } + } + + /* + * Check for bit error, desync error,parity error,timeout error and + * receive overflow errors + */ + int_status = ioread32(davinci_spi->base + SPIFLG); + + ret = davinci_spi_check_error(davinci_spi, int_status); + if (ret != 0) + return ret; + + /* SPI Framework maintains the count only in bytes so convert back */ + davinci_spi->count *= conv; + + return t->len; +} + +#define DAVINCI_DMA_DATA_TYPE_S8 0x01 +#define DAVINCI_DMA_DATA_TYPE_S16 0x02 +#define DAVINCI_DMA_DATA_TYPE_S32 0x04 + +static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) +{ + struct davinci_spi *davinci_spi; + int int_status = 0; + int count, temp_count; + u8 conv = 1; + u8 tmp; + u32 data1_reg_val; + struct davinci_spi_dma *davinci_spi_dma; + int word_len, data_type, ret; + unsigned long tx_reg, rx_reg; + struct davinci_spi_platform_data *pdata; + struct device *sdev; + + davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; + sdev = davinci_spi->bitbang.master->dev.parent; + + davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; + + tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1; + rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF; + + davinci_spi->tx = t->tx_buf; + davinci_spi->rx = t->rx_buf; + + /* convert len to words based on bits_per_word */ + conv = davinci_spi->slave[spi->chip_select].bytes_per_word; + davinci_spi->count = t->len / conv; + + INIT_COMPLETION(davinci_spi->done); + + init_completion(&davinci_spi_dma->dma_rx_completion); + init_completion(&davinci_spi_dma->dma_tx_completion); + + word_len = conv * 8; + + if (word_len <= 8) + data_type = DAVINCI_DMA_DATA_TYPE_S8; + else if (word_len <= 16) + data_type = DAVINCI_DMA_DATA_TYPE_S16; + else if (word_len <= 32) + data_type = DAVINCI_DMA_DATA_TYPE_S32; + else + return -EINVAL; + + ret = davinci_spi_bufs_prep(spi, davinci_spi); + if (ret) + return ret; + + /* Put delay val if required */ + iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | + (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + davinci_spi->base + SPIDELAY); + + count = davinci_spi->count; /* the number of elements */ + data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT; + + /* CS default = 0xFF */ + tmp = ~(0x1 << spi->chip_select); + + clear_io_bits(davinci_spi->base + SPIDEF, ~tmp); + + data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; + + /* disable all interrupts for dma transfers */ + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + /* Disable SPI to write configuration bits in SPIDAT */ + clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + /* Enable SPI */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); + + while ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_RXEMPTY_MASK) == 0) + cpu_relax(); + + + if (t->tx_buf) { + t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count, + DMA_TO_DEVICE); + if (dma_mapping_error(&spi->dev, t->tx_dma)) { + dev_dbg(sdev, "Unable to DMA map a %d bytes" + " TX buffer\n", count); + return -ENOMEM; + } + temp_count = count; + } else { + /* We need TX clocking for RX transaction */ + t->tx_dma = dma_map_single(&spi->dev, + (void *)davinci_spi->tmp_buf, count + 1, + DMA_TO_DEVICE); + if (dma_mapping_error(&spi->dev, t->tx_dma)) { + dev_dbg(sdev, "Unable to DMA map a %d bytes" + " TX tmp buffer\n", count); + return -ENOMEM; + } + temp_count = count + 1; + } + + edma_set_transfer_params(davinci_spi_dma->dma_tx_channel, + data_type, temp_count, 1, 0, ASYNC); + edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT); + edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT); + edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0); + edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0); + + if (t->rx_buf) { + /* initiate transaction */ + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + + t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count, + DMA_FROM_DEVICE); + if (dma_mapping_error(&spi->dev, t->rx_dma)) { + dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", + count); + if (t->tx_buf != NULL) + dma_unmap_single(NULL, t->tx_dma, + count, DMA_TO_DEVICE); + return -ENOMEM; + } + edma_set_transfer_params(davinci_spi_dma->dma_rx_channel, + data_type, count, 1, 0, ASYNC); + edma_set_src(davinci_spi_dma->dma_rx_channel, + rx_reg, INCR, W8BIT); + edma_set_dest(davinci_spi_dma->dma_rx_channel, + t->rx_dma, INCR, W8BIT); + edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0); + edma_set_dest_index(davinci_spi_dma->dma_rx_channel, + data_type, 0); + } + + if ((t->tx_buf) || (t->rx_buf)) + edma_start(davinci_spi_dma->dma_tx_channel); + + if (t->rx_buf) + edma_start(davinci_spi_dma->dma_rx_channel); + + if ((t->rx_buf) || (t->tx_buf)) + davinci_spi_set_dma_req(spi, 1); + + if (t->tx_buf) + wait_for_completion_interruptible( + &davinci_spi_dma->dma_tx_completion); + + if (t->rx_buf) + wait_for_completion_interruptible( + &davinci_spi_dma->dma_rx_completion); + + dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE); + + if (t->rx_buf) + dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE); + + /* + * Check for bit error, desync error,parity error,timeout error and + * receive overflow errors + */ + int_status = ioread32(davinci_spi->base + SPIFLG); + + ret = davinci_spi_check_error(davinci_spi, int_status); + if (ret != 0) + return ret; + + /* SPI Framework maintains the count only in bytes so convert back */ + davinci_spi->count *= conv; + + return t->len; +} + +/** + * davinci_spi_irq - IRQ handler for DaVinci SPI + * @irq: IRQ number for this SPI Master + * @context_data: structure for SPI Master controller davinci_spi + */ +static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) +{ + struct davinci_spi *davinci_spi = context_data; + u32 int_status, rx_data = 0; + irqreturn_t ret = IRQ_NONE; + + int_status = ioread32(davinci_spi->base + SPIFLG); + + while ((int_status & SPIFLG_RX_INTR_MASK)) { + if (likely(int_status & SPIFLG_RX_INTR_MASK)) { + ret = IRQ_HANDLED; + + rx_data = ioread32(davinci_spi->base + SPIBUF); + davinci_spi->get_rx(rx_data, davinci_spi); + + /* Disable Receive Interrupt */ + iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR), + davinci_spi->base + SPIINT); + } else + (void)davinci_spi_check_error(davinci_spi, int_status); + + int_status = ioread32(davinci_spi->base + SPIFLG); + } + + return ret; +} + +/** + * davinci_spi_probe - probe function for SPI Master Controller + * @pdev: platform_device structure which contains plateform specific data + */ +static int davinci_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct davinci_spi *davinci_spi; + struct davinci_spi_platform_data *pdata; + struct resource *r, *mem; + resource_size_t dma_rx_chan = SPI_NO_RESOURCE; + resource_size_t dma_tx_chan = SPI_NO_RESOURCE; + resource_size_t dma_eventq = SPI_NO_RESOURCE; + int i = 0, ret = 0; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) { + ret = -ENODEV; + goto err; + } + + master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi)); + if (master == NULL) { + ret = -ENOMEM; + goto err; + } + + dev_set_drvdata(&pdev->dev, master); + + davinci_spi = spi_master_get_devdata(master); + if (davinci_spi == NULL) { + ret = -ENOENT; + goto free_master; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENOENT; + goto free_master; + } + + davinci_spi->pbase = r->start; + davinci_spi->region_size = resource_size(r); + davinci_spi->pdata = pdata; + + mem = request_mem_region(r->start, davinci_spi->region_size, + pdev->name); + if (mem == NULL) { + ret = -EBUSY; + goto free_master; + } + + davinci_spi->base = (struct davinci_spi_reg __iomem *) + ioremap(r->start, davinci_spi->region_size); + if (davinci_spi->base == NULL) { + ret = -ENOMEM; + goto release_region; + } + + davinci_spi->irq = platform_get_irq(pdev, 0); + if (davinci_spi->irq <= 0) { + ret = -EINVAL; + goto unmap_io; + } + + ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED, + dev_name(&pdev->dev), davinci_spi); + if (ret) + goto unmap_io; + + /* Allocate tmp_buf for tx_buf */ + davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL); + if (davinci_spi->tmp_buf == NULL) { + ret = -ENOMEM; + goto irq_free; + } + + davinci_spi->bitbang.master = spi_master_get(master); + if (davinci_spi->bitbang.master == NULL) { + ret = -ENODEV; + goto free_tmp_buf; + } + + davinci_spi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(davinci_spi->clk)) { + ret = -ENODEV; + goto put_master; + } + clk_enable(davinci_spi->clk); + + + master->bus_num = pdev->id; + master->num_chipselect = pdata->num_chipselect; + master->setup = davinci_spi_setup; + master->cleanup = davinci_spi_cleanup; + + davinci_spi->bitbang.chipselect = davinci_spi_chipselect; + davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer; + + davinci_spi->version = pdata->version; + use_dma = pdata->use_dma; + + davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; + if (davinci_spi->version == SPI_VERSION_2) + davinci_spi->bitbang.flags |= SPI_READY; + + if (use_dma) { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r) + dma_rx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r) + dma_tx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (r) + dma_eventq = r->start; + } + + if (!use_dma || + dma_rx_chan == SPI_NO_RESOURCE || + dma_tx_chan == SPI_NO_RESOURCE || + dma_eventq == SPI_NO_RESOURCE) { + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; + use_dma = 0; + } else { + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma; + davinci_spi->dma_channels = kzalloc(master->num_chipselect + * sizeof(struct davinci_spi_dma), GFP_KERNEL); + if (davinci_spi->dma_channels == NULL) { + ret = -ENOMEM; + goto free_clk; + } + + for (i = 0; i < master->num_chipselect; i++) { + davinci_spi->dma_channels[i].dma_rx_channel = -1; + davinci_spi->dma_channels[i].dma_rx_sync_dev = + dma_rx_chan; + davinci_spi->dma_channels[i].dma_tx_channel = -1; + davinci_spi->dma_channels[i].dma_tx_sync_dev = + dma_tx_chan; + davinci_spi->dma_channels[i].eventq = dma_eventq; + } + dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n" + "Using RX channel = %d , TX channel = %d and " + "event queue = %d", dma_rx_chan, dma_tx_chan, + dma_eventq); + } + + davinci_spi->get_rx = davinci_spi_rx_buf_u8; + davinci_spi->get_tx = davinci_spi_tx_buf_u8; + + init_completion(&davinci_spi->done); + + /* Reset In/OUT SPI module */ + iowrite32(0, davinci_spi->base + SPIGCR0); + udelay(100); + iowrite32(1, davinci_spi->base + SPIGCR0); + + /* Clock internal */ + if (davinci_spi->pdata->clk_internal) + set_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_CLKMOD_MASK); + else + clear_io_bits(davinci_spi->base + SPIGCR1, + SPIGCR1_CLKMOD_MASK); + + /* master mode default */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK); + + if (davinci_spi->pdata->intr_level) + iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); + else + iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL); + + ret = spi_bitbang_start(&davinci_spi->bitbang); + if (ret) + goto free_clk; + + dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base); + + if (!pdata->poll_mode) + dev_info(&pdev->dev, "Operating in interrupt mode" + " using IRQ %d\n", davinci_spi->irq); + + return ret; + +free_clk: + clk_disable(davinci_spi->clk); + clk_put(davinci_spi->clk); +put_master: + spi_master_put(master); +free_tmp_buf: + kfree(davinci_spi->tmp_buf); +irq_free: + free_irq(davinci_spi->irq, davinci_spi); +unmap_io: + iounmap(davinci_spi->base); +release_region: + release_mem_region(davinci_spi->pbase, davinci_spi->region_size); +free_master: + kfree(master); +err: + return ret; +} + +/** + * davinci_spi_remove - remove function for SPI Master Controller + * @pdev: platform_device structure which contains plateform specific data + * + * This function will do the reverse action of davinci_spi_probe function + * It will free the IRQ and SPI controller's memory region. + * It will also call spi_bitbang_stop to destroy the work queue which was + * created by spi_bitbang_start. + */ +static int __exit davinci_spi_remove(struct platform_device *pdev) +{ + struct davinci_spi *davinci_spi; + struct spi_master *master; + + master = dev_get_drvdata(&pdev->dev); + davinci_spi = spi_master_get_devdata(master); + + spi_bitbang_stop(&davinci_spi->bitbang); + + clk_disable(davinci_spi->clk); + clk_put(davinci_spi->clk); + spi_master_put(master); + kfree(davinci_spi->tmp_buf); + free_irq(davinci_spi->irq, davinci_spi); + iounmap(davinci_spi->base); + release_mem_region(davinci_spi->pbase, davinci_spi->region_size); + + return 0; +} + +static struct platform_driver davinci_spi_driver = { + .driver.name = "spi_davinci", + .remove = __exit_p(davinci_spi_remove), +}; + +static int __init davinci_spi_init(void) +{ + return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe); +} +module_init(davinci_spi_init); + +static void __exit davinci_spi_exit(void) +{ + platform_driver_unregister(&davinci_spi_driver); +} +module_exit(davinci_spi_exit); + +MODULE_DESCRIPTION("TI DaVinci SPI Master Controller Driver"); +MODULE_LICENSE("GPL"); -- GitLab From 68ea2d82c3671d2eccb600e6871fcbec1cac7fca Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1010/3892] spi: Fix reversed args to time_before() in Freescale stmp driver. Signed-off-by: Robert P. J. Day Signed-off-by: Grant Likely --- drivers/spi/spi_stmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_stmp.c b/drivers/spi/spi_stmp.c index 2552bb364005..fadff76eb7e0 100644 --- a/drivers/spi/spi_stmp.c +++ b/drivers/spi/spi_stmp.c @@ -76,7 +76,7 @@ struct stmp_spi { break; \ } \ cpu_relax(); \ - } while (time_before(end_jiffies, jiffies)); \ + } while (time_before(jiffies, end_jiffies)); \ succeeded; \ }) -- GitLab From 631e61b7ca12ef14c834f99f8948e410c539f585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1011/3892] spi: make Open Firmware device id constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The match_table field of the struct of_device_id is constant in so it is worth to make the initialization data constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Cc: cocci@diku.dk Signed-off-by: Grant Likely --- drivers/spi/mpc52xx_psc_spi.c | 2 +- drivers/spi/mpc52xx_spi.c | 2 +- drivers/spi/spi_ppc4xx.c | 2 +- drivers/spi/xilinx_spi_of.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index f50c81df336a..04747868d6c4 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -503,7 +503,7 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op) return mpc52xx_psc_spi_do_remove(&op->dev); } -static struct of_device_id mpc52xx_psc_spi_of_match[] = { +static const struct of_device_id mpc52xx_psc_spi_of_match[] = { { .compatible = "fsl,mpc5200-psc-spi", }, { .compatible = "mpc5200-psc-spi", }, /* old */ {} diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c index 45bfe6458173..6eab46537a0a 100644 --- a/drivers/spi/mpc52xx_spi.c +++ b/drivers/spi/mpc52xx_spi.c @@ -550,7 +550,7 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op) return 0; } -static struct of_device_id mpc52xx_spi_match[] __devinitdata = { +static const struct of_device_id mpc52xx_spi_match[] __devinitconst = { { .compatible = "fsl,mpc5200-spi", }, {} }; diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c index 140a18d6cf3e..6d8d4026a07a 100644 --- a/drivers/spi/spi_ppc4xx.c +++ b/drivers/spi/spi_ppc4xx.c @@ -578,7 +578,7 @@ static int __exit spi_ppc4xx_of_remove(struct of_device *op) return 0; } -static struct of_device_id spi_ppc4xx_of_match[] = { +static const struct of_device_id spi_ppc4xx_of_match[] = { { .compatible = "ibm,ppc4xx-spi", }, {}, }; diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c index 71dc3adc0495..ed34a8d419c7 100644 --- a/drivers/spi/xilinx_spi_of.c +++ b/drivers/spi/xilinx_spi_of.c @@ -99,7 +99,7 @@ static int __exit xilinx_spi_of_remove(struct of_device *op) return xilinx_spi_remove(op); } -static struct of_device_id xilinx_spi_of_match[] = { +static const struct of_device_id xilinx_spi_of_match[] = { { .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.b", }, {} -- GitLab From 34b8c66173666025020e3a6f8d4a5c238b19cde5 Mon Sep 17 00:00:00 2001 From: Steven King Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1012/3892] spi: Add Freescale/Motorola Coldfire QSPI driver Add support for the QSPI controller found some on Freescale/Motorola Coldfire MCUs. Full duplex, active high cs, spi modes 0-3 and word sizes 8-16 bits are supported. The hardware drives the MISO, MOSI and SCLK lines, but the chip selects are managed via GPIO and must be configured by the board code. The QSPI controller has an 80 byte buffer which allows us to transfer up to 16 words at a time. For transfers longer than 16 words, we split the buffer in half so we can update in one half while the controller is operating on the other half. Interrupt latencies then ultimately limits our sustained thru-put to something less than half the maximum speed supported by the part. Signed-off-by: Steven King Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 1 + drivers/spi/coldfire_qspi.c | 640 ++++++++++++++++++++++++++++++++++++ 3 files changed, 651 insertions(+) create mode 100644 drivers/spi/coldfire_qspi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82dabbca00c1..28becdd4dea9 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -100,6 +100,16 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_COLDFIRE_QSPI + tristate "Freescale Coldfire QSPI controller" + depends on (M520x || M523x || M5249 || M527x || M528x || M532x) + help + This enables support for the Coldfire QSPI controller in master + mode. + + This driver can also be built as a module. If so, the module + will be called coldfire_qspi. + config SPI_DAVINCI tristate "SPI controller driver for DaVinci/DA8xx SoC's" depends on SPI_MASTER && ARCH_DAVINCI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 84b490fb7f8a..d3a65ab8ebbf 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c new file mode 100644 index 000000000000..59be3efe0636 --- /dev/null +++ b/drivers/spi/coldfire_qspi.c @@ -0,0 +1,640 @@ +/* + * Freescale/Motorola Coldfire Queued SPI driver + * + * Copyright 2010 Steven King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "mcfqspi" + +#define MCFQSPI_BUSCLK (MCF_BUSCLK / 2) + +#define MCFQSPI_QMR 0x00 +#define MCFQSPI_QMR_MSTR 0x8000 +#define MCFQSPI_QMR_CPOL 0x0200 +#define MCFQSPI_QMR_CPHA 0x0100 +#define MCFQSPI_QDLYR 0x04 +#define MCFQSPI_QDLYR_SPE 0x8000 +#define MCFQSPI_QWR 0x08 +#define MCFQSPI_QWR_HALT 0x8000 +#define MCFQSPI_QWR_WREN 0x4000 +#define MCFQSPI_QWR_CSIV 0x1000 +#define MCFQSPI_QIR 0x0C +#define MCFQSPI_QIR_WCEFB 0x8000 +#define MCFQSPI_QIR_ABRTB 0x4000 +#define MCFQSPI_QIR_ABRTL 0x1000 +#define MCFQSPI_QIR_WCEFE 0x0800 +#define MCFQSPI_QIR_ABRTE 0x0400 +#define MCFQSPI_QIR_SPIFE 0x0100 +#define MCFQSPI_QIR_WCEF 0x0008 +#define MCFQSPI_QIR_ABRT 0x0004 +#define MCFQSPI_QIR_SPIF 0x0001 +#define MCFQSPI_QAR 0x010 +#define MCFQSPI_QAR_TXBUF 0x00 +#define MCFQSPI_QAR_RXBUF 0x10 +#define MCFQSPI_QAR_CMDBUF 0x20 +#define MCFQSPI_QDR 0x014 +#define MCFQSPI_QCR 0x014 +#define MCFQSPI_QCR_CONT 0x8000 +#define MCFQSPI_QCR_BITSE 0x4000 +#define MCFQSPI_QCR_DT 0x2000 + +struct mcfqspi { + void __iomem *iobase; + int irq; + struct clk *clk; + struct mcfqspi_cs_control *cs_control; + + wait_queue_head_t waitq; + + struct work_struct work; + struct workqueue_struct *workq; + spinlock_t lock; + struct list_head msgq; +}; + +static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QMR); +} + +static void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QDLYR); +} + +static u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi) +{ + return readw(mcfqspi->iobase + MCFQSPI_QDLYR); +} + +static void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QWR); +} + +static void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QIR); +} + +static void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QAR); +} + +static void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val) +{ + writew(val, mcfqspi->iobase + MCFQSPI_QDR); +} + +static u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi) +{ + return readw(mcfqspi->iobase + MCFQSPI_QDR); +} + +static void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select, + bool cs_high) +{ + mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high); +} + +static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select, + bool cs_high) +{ + mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high); +} + +static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi) +{ + return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ? + mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0; +} + +static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi) +{ + if (mcfqspi->cs_control && mcfqspi->cs_control->teardown) + mcfqspi->cs_control->teardown(mcfqspi->cs_control); +} + +static u8 mcfqspi_qmr_baud(u32 speed_hz) +{ + return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u); +} + +static bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi) +{ + return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE; +} + +static irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id) +{ + struct mcfqspi *mcfqspi = dev_id; + + /* clear interrupt */ + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF); + wake_up(&mcfqspi->waitq); + + return IRQ_HANDLED; +} + +static void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count, + const u8 *txbuf, u8 *rxbuf) +{ + unsigned i, n, offset = 0; + + n = min(count, 16u); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF); + if (txbuf) + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + else + for (i = 0; i < count; ++i) + mcfqspi_wr_qdr(mcfqspi, 0); + + count -= n; + if (count) { + u16 qwr = 0xf08; + mcfqspi_wr_qwr(mcfqspi, 0x700); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + + do { + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } + n = min(count, 8u); + if (txbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_TXBUF + offset); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + } + qwr = (offset ? 0x808 : 0) + ((n - 1) << 8); + offset ^= 8; + count -= n; + } while (count); + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + offset ^= 8; + } + } else { + mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + } + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < n; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } +} + +static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count, + const u16 *txbuf, u16 *rxbuf) +{ + unsigned i, n, offset = 0; + + n = min(count, 16u); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE); + + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF); + if (txbuf) + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + else + for (i = 0; i < count; ++i) + mcfqspi_wr_qdr(mcfqspi, 0); + + count -= n; + if (count) { + u16 qwr = 0xf08; + mcfqspi_wr_qwr(mcfqspi, 0x700); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + + do { + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } + n = min(count, 8u); + if (txbuf) { + mcfqspi_wr_qar(mcfqspi, + MCFQSPI_QAR_TXBUF + offset); + for (i = 0; i < n; ++i) + mcfqspi_wr_qdr(mcfqspi, *txbuf++); + } + qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8); + offset ^= 8; + count -= n; + } while (count); + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + mcfqspi_wr_qwr(mcfqspi, qwr); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < 8; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + offset ^= 8; + } + } else { + mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8); + mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE); + } + wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi)); + if (rxbuf) { + mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset); + for (i = 0; i < n; ++i) + *rxbuf++ = mcfqspi_rd_qdr(mcfqspi); + } +} + +static void mcfqspi_work(struct work_struct *work) +{ + struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work); + unsigned long flags; + + spin_lock_irqsave(&mcfqspi->lock, flags); + while (!list_empty(&mcfqspi->msgq)) { + struct spi_message *msg; + struct spi_device *spi; + struct spi_transfer *xfer; + int status = 0; + + msg = container_of(mcfqspi->msgq.next, struct spi_message, + queue); + + list_del_init(&mcfqspi->msgq); + spin_unlock_irqrestore(&mcfqspi->lock, flags); + + spi = msg->spi; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + bool cs_high = spi->mode & SPI_CS_HIGH; + u16 qmr = MCFQSPI_QMR_MSTR; + + if (xfer->bits_per_word) + qmr |= xfer->bits_per_word << 10; + else + qmr |= spi->bits_per_word << 10; + if (spi->mode & SPI_CPHA) + qmr |= MCFQSPI_QMR_CPHA; + if (spi->mode & SPI_CPOL) + qmr |= MCFQSPI_QMR_CPOL; + if (xfer->speed_hz) + qmr |= mcfqspi_qmr_baud(xfer->speed_hz); + else + qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); + mcfqspi_wr_qmr(mcfqspi, qmr); + + mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); + + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); + if ((xfer->bits_per_word ? xfer->bits_per_word : + spi->bits_per_word) == 8) + mcfqspi_transfer_msg8(mcfqspi, xfer->len, + xfer->tx_buf, + xfer->rx_buf); + else + mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2, + xfer->tx_buf, + xfer->rx_buf); + mcfqspi_wr_qir(mcfqspi, 0); + + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + if (xfer->cs_change) { + if (!list_is_last(&xfer->transfer_list, + &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, + spi->chip_select, + cs_high); + } else { + if (list_is_last(&xfer->transfer_list, + &msg->transfers)) + mcfqspi_cs_deselect(mcfqspi, + spi->chip_select, + cs_high); + } + msg->actual_length += xfer->len; + } + msg->status = status; + msg->complete(msg->context); + + spin_lock_irqsave(&mcfqspi->lock, flags); + } + spin_unlock_irqrestore(&mcfqspi->lock, flags); +} + +static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct mcfqspi *mcfqspi; + struct spi_transfer *xfer; + unsigned long flags; + + mcfqspi = spi_master_get_devdata(spi->master); + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->bits_per_word && ((xfer->bits_per_word < 8) + || (xfer->bits_per_word > 16))) { + dev_dbg(&spi->dev, + "%d bits per word is not supported\n", + xfer->bits_per_word); + goto fail; + } + if (xfer->speed_hz) { + u32 real_speed = MCFQSPI_BUSCLK / + mcfqspi_qmr_baud(xfer->speed_hz); + if (real_speed != xfer->speed_hz) + dev_dbg(&spi->dev, + "using speed %d instead of %d\n", + real_speed, xfer->speed_hz); + } + } + msg->status = -EINPROGRESS; + msg->actual_length = 0; + + spin_lock_irqsave(&mcfqspi->lock, flags); + list_add_tail(&msg->queue, &mcfqspi->msgq); + queue_work(mcfqspi->workq, &mcfqspi->work); + spin_unlock_irqrestore(&mcfqspi->lock, flags); + + return 0; +fail: + msg->status = -EINVAL; + return -EINVAL; +} + +static int mcfqspi_setup(struct spi_device *spi) +{ + if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) { + dev_dbg(&spi->dev, "%d bits per word is not supported\n", + spi->bits_per_word); + return -EINVAL; + } + if (spi->chip_select >= spi->master->num_chipselect) { + dev_dbg(&spi->dev, "%d chip select is out of range\n", + spi->chip_select); + return -EINVAL; + } + + mcfqspi_cs_deselect(spi_master_get_devdata(spi->master), + spi->chip_select, spi->mode & SPI_CS_HIGH); + + dev_dbg(&spi->dev, + "bits per word %d, chip select %d, speed %d KHz\n", + spi->bits_per_word, spi->chip_select, + (MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz)) + / 1000); + + return 0; +} + +static int __devinit mcfqspi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct mcfqspi *mcfqspi; + struct resource *res; + struct mcfqspi_platform_data *pdata; + int status; + + master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi)); + if (master == NULL) { + dev_dbg(&pdev->dev, "spi_alloc_master failed\n"); + return -ENOMEM; + } + + mcfqspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(&pdev->dev, "platform_get_resource failed\n"); + status = -ENXIO; + goto fail0; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + status = -EBUSY; + goto fail0; + } + + mcfqspi->iobase = ioremap(res->start, resource_size(res)); + if (!mcfqspi->iobase) { + dev_dbg(&pdev->dev, "ioremap failed\n"); + status = -ENOMEM; + goto fail1; + } + + mcfqspi->irq = platform_get_irq(pdev, 0); + if (mcfqspi->irq < 0) { + dev_dbg(&pdev->dev, "platform_get_irq failed\n"); + status = -ENXIO; + goto fail2; + } + + status = request_irq(mcfqspi->irq, mcfqspi_irq_handler, IRQF_DISABLED, + pdev->name, mcfqspi); + if (status) { + dev_dbg(&pdev->dev, "request_irq failed\n"); + goto fail2; + } + + mcfqspi->clk = clk_get(&pdev->dev, "qspi_clk"); + if (IS_ERR(mcfqspi->clk)) { + dev_dbg(&pdev->dev, "clk_get failed\n"); + status = PTR_ERR(mcfqspi->clk); + goto fail3; + } + clk_enable(mcfqspi->clk); + + mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent)); + if (!mcfqspi->workq) { + dev_dbg(&pdev->dev, "create_workqueue failed\n"); + status = -ENOMEM; + goto fail4; + } + INIT_WORK(&mcfqspi->work, mcfqspi_work); + spin_lock_init(&mcfqspi->lock); + INIT_LIST_HEAD(&mcfqspi->msgq); + init_waitqueue_head(&mcfqspi->waitq); + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_dbg(&pdev->dev, "platform data is missing\n"); + goto fail5; + } + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->num_chipselect; + + mcfqspi->cs_control = pdata->cs_control; + status = mcfqspi_cs_setup(mcfqspi); + if (status) { + dev_dbg(&pdev->dev, "error initializing cs_control\n"); + goto fail5; + } + + master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; + master->setup = mcfqspi_setup; + master->transfer = mcfqspi_transfer; + + platform_set_drvdata(pdev, master); + + status = spi_register_master(master); + if (status) { + dev_dbg(&pdev->dev, "spi_register_master failed\n"); + goto fail6; + } + dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); + + return 0; + +fail6: + mcfqspi_cs_teardown(mcfqspi); +fail5: + destroy_workqueue(mcfqspi->workq); +fail4: + clk_disable(mcfqspi->clk); + clk_put(mcfqspi->clk); +fail3: + free_irq(mcfqspi->irq, mcfqspi); +fail2: + iounmap(mcfqspi->iobase); +fail1: + release_mem_region(res->start, resource_size(res)); +fail0: + spi_master_put(master); + + dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n"); + + return status; +} + +static int __devexit mcfqspi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + /* disable the hardware (set the baud rate to 0) */ + mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); + + platform_set_drvdata(pdev, NULL); + mcfqspi_cs_teardown(mcfqspi); + destroy_workqueue(mcfqspi->workq); + clk_disable(mcfqspi->clk); + clk_put(mcfqspi->clk); + free_irq(mcfqspi->irq, mcfqspi); + iounmap(mcfqspi->iobase); + release_mem_region(res->start, resource_size(res)); + spi_unregister_master(master); + spi_master_put(master); + + return 0; +} + +#ifdef CONFIG_PM + +static int mcfqspi_suspend(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + + clk_disable(mcfqspi->clk); + + return 0; +} + +static int mcfqspi_resume(struct device *dev) +{ + struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + + clk_enable(mcfqspi->clk); + + return 0; +} + +static struct dev_pm_ops mcfqspi_dev_pm_ops = { + .suspend = mcfqspi_suspend, + .resume = mcfqspi_resume, +}; + +#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops) +#else +#define MCFQSPI_DEV_PM_OPS NULL +#endif + +static struct platform_driver mcfqspi_driver = { + .driver.name = DRIVER_NAME, + .driver.owner = THIS_MODULE, + .driver.pm = MCFQSPI_DEV_PM_OPS, + .remove = __devexit_p(mcfqspi_remove), +}; + +static int __init mcfqspi_init(void) +{ + return platform_driver_probe(&mcfqspi_driver, mcfqspi_probe); +} +module_init(mcfqspi_init); + +static void __exit mcfqspi_exit(void) +{ + platform_driver_unregister(&mcfqspi_driver); +} +module_exit(mcfqspi_exit); + +MODULE_AUTHOR("Steven King "); +MODULE_DESCRIPTION("Coldfire QSPI Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); -- GitLab From e9a172f074ba85de144e63b0786c7c5c5ba93c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1013/3892] spi/mpc8xxx: don't check platform_get_irq's return value against zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_irq returns -ENXIO on failure, so !irq was probably always true. Make irq a signed variable and compare irq <= 0. Note that a return value of zero is still handled as error even though this could mean irq0. This is a followup to 305b3228f9ff4d59f49e6d34a7034d44ee8ce2f0 that changed the return value of platform_get_irq from 0 to -ENXIO on error. Signed-off-by: Uwe Kleine-König Acked-by: Anton Vorontsov Signed-off-by: Grant Likely --- drivers/spi/spi_mpc8xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c index 1fb2a6ea328c..08065fb15817 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -1328,7 +1328,7 @@ static struct of_platform_driver of_mpc8xxx_spi_driver = { static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) { struct resource *mem; - unsigned int irq; + int irq; struct spi_master *master; if (!pdev->dev.platform_data) @@ -1339,7 +1339,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) return -EINVAL; irq = platform_get_irq(pdev, 0); - if (!irq) + if (irq <= 0) return -EINVAL; master = mpc8xxx_spi_probe(&pdev->dev, mem, irq); -- GitLab From ad7de729c60380a48844f885f37451158169c50d Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1014/3892] spi/s3c64xx: Rename s3c64xx_spi_cntrlr_info Rename 'struct s3c64xx_spi_cntrlr_info' to lesser wordy 'struct s3c64xx_spi_info' Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 88a456dba967..ad93d5d8539c 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -160,7 +160,7 @@ struct s3c64xx_spi_driver_data { struct platform_device *pdev; struct spi_master *master; struct workqueue_struct *workqueue; - struct s3c64xx_spi_cntrlr_info *cntrlr_info; + struct s3c64xx_spi_info *cntrlr_info; struct spi_device *tgl_spi; struct work_struct work; struct list_head queue; @@ -180,7 +180,7 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = { static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned long loops; u32 val; @@ -225,7 +225,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 modecfg, chcfg; @@ -310,7 +310,7 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, struct spi_transfer *xfer, int dma_mode) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned long val; int ms; @@ -389,7 +389,7 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 val; @@ -558,7 +558,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, static void handle_msg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct spi_device *spi = msg->spi; struct s3c64xx_spi_csinfo *cs = spi->controller_data; struct spi_transfer *xfer; @@ -786,7 +786,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs = spi->controller_data; struct s3c64xx_spi_driver_data *sdd; - struct s3c64xx_spi_cntrlr_info *sci; + struct s3c64xx_spi_info *sci; struct spi_message *msg; u32 psr, speed; unsigned long flags; @@ -867,7 +867,7 @@ setup_exit: static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) { - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; unsigned int val; @@ -902,7 +902,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res; struct s3c64xx_spi_driver_data *sdd; - struct s3c64xx_spi_cntrlr_info *sci; + struct s3c64xx_spi_info *sci; struct spi_master *master; int ret; @@ -1078,7 +1078,7 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct resource *mem_res; unsigned long flags; @@ -1118,7 +1118,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct s3c64xx_spi_csinfo *cs; unsigned long flags; @@ -1144,7 +1144,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; unsigned long flags; sci->cfg_gpio(pdev); -- GitLab From ee64a37732c23ab2bcef5fe7785fd237a7e38951 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1015/3892] spi/s3c64xx: Differentiate ip and rate clock The instance of SPI clock for controller and that used for generating signals ought to be independently handled. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index ad93d5d8539c..6d03d8f2de6d 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -1000,10 +1000,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err4; } - if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK) - sci->src_clk = sdd->clk; - else - sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); + sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); if (IS_ERR(sci->src_clk)) { dev_err(&pdev->dev, "Unable to acquire clock '%s'\n", sci->src_clk_name); @@ -1011,7 +1008,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err5; } - if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) { + if (clk_enable(sci->src_clk)) { dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", sci->src_clk_name); ret = -EBUSY; @@ -1053,11 +1050,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) err8: destroy_workqueue(sdd->workqueue); err7: - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); + clk_disable(sci->src_clk); err6: - if (sci->src_clk != sdd->clk) - clk_put(sci->src_clk); + clk_put(sci->src_clk); err5: clk_disable(sdd->clk); err4: @@ -1093,11 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) destroy_workqueue(sdd->workqueue); - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); - - if (sci->src_clk != sdd->clk) - clk_put(sci->src_clk); + clk_disable(sci->src_clk); + clk_put(sci->src_clk); clk_disable(sdd->clk); clk_put(sdd->clk); @@ -1130,9 +1122,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) msleep(10); /* Disable the clock */ - if (sci->src_clk != sdd->clk) - clk_disable(sci->src_clk); - + clk_disable(sci->src_clk); clk_disable(sdd->clk); sdd->cur_speed = 0; /* Output Clock is stopped */ @@ -1150,9 +1140,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) sci->cfg_gpio(pdev); /* Enable the clock */ - if (sci->src_clk != sdd->clk) - clk_enable(sci->src_clk); - + clk_enable(sci->src_clk); clk_enable(sdd->clk); s3c64xx_spi_hwinit(sdd, pdev->id); -- GitLab From b0d5d6e55340348b0de75eb691b93d7e60dba879 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1016/3892] spi/s3c64xx: Move src_clk to local driver data The pointer to SPI rate source clock had better be the member of driver local data structure rather than platform specific. Also, remove definitions of variable 'sci' that are rendered useless as a consequence. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 6d03d8f2de6d..3acf38119e96 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -137,6 +137,7 @@ /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. + * @src_clk: Pointer to the clock used to generate SPI signals. * @master: Pointer to the SPI Protocol master. * @workqueue: Work queue for the SPI xfer requests. * @cntrlr_info: Platform specific data for the controller this driver manages. @@ -157,6 +158,7 @@ struct s3c64xx_spi_driver_data { void __iomem *regs; struct clk *clk; + struct clk *src_clk; struct platform_device *pdev; struct spi_master *master; struct workqueue_struct *workqueue; @@ -389,7 +391,6 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 val; @@ -435,7 +436,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) /* Configure Clock */ val = readl(regs + S3C64XX_SPI_CLK_CFG); val &= ~S3C64XX_SPI_PSR_MASK; - val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1) + val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) & S3C64XX_SPI_PSR_MASK); writel(val, regs + S3C64XX_SPI_CLK_CFG); @@ -831,17 +832,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } /* Check if we can provide the requested rate */ - speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */ + speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ if (spi->max_speed_hz > speed) spi->max_speed_hz = speed; - psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1; + psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; psr &= S3C64XX_SPI_PSR_MASK; if (psr == S3C64XX_SPI_PSR_MASK) psr--; - speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); if (spi->max_speed_hz < speed) { if (psr+1 < S3C64XX_SPI_PSR_MASK) { psr++; @@ -851,7 +852,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } } - speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); if (spi->max_speed_hz >= speed) spi->max_speed_hz = speed; else @@ -1000,15 +1001,15 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err4; } - sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); - if (IS_ERR(sci->src_clk)) { + sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name); + if (IS_ERR(sdd->src_clk)) { dev_err(&pdev->dev, "Unable to acquire clock '%s'\n", sci->src_clk_name); - ret = PTR_ERR(sci->src_clk); + ret = PTR_ERR(sdd->src_clk); goto err5; } - if (clk_enable(sci->src_clk)) { + if (clk_enable(sdd->src_clk)) { dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", sci->src_clk_name); ret = -EBUSY; @@ -1050,9 +1051,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) err8: destroy_workqueue(sdd->workqueue); err7: - clk_disable(sci->src_clk); + clk_disable(sdd->src_clk); err6: - clk_put(sci->src_clk); + clk_put(sdd->src_clk); err5: clk_disable(sdd->clk); err4: @@ -1073,7 +1074,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct resource *mem_res; unsigned long flags; @@ -1088,8 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) destroy_workqueue(sdd->workqueue); - clk_disable(sci->src_clk); - clk_put(sci->src_clk); + clk_disable(sdd->src_clk); + clk_put(sdd->src_clk); clk_disable(sdd->clk); clk_put(sdd->clk); @@ -1110,8 +1110,6 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - struct s3c64xx_spi_info *sci = sdd->cntrlr_info; - struct s3c64xx_spi_csinfo *cs; unsigned long flags; spin_lock_irqsave(&sdd->lock, flags); @@ -1122,7 +1120,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) msleep(10); /* Disable the clock */ - clk_disable(sci->src_clk); + clk_disable(sdd->src_clk); clk_disable(sdd->clk); sdd->cur_speed = 0; /* Output Clock is stopped */ @@ -1140,7 +1138,7 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) sci->cfg_gpio(pdev); /* Enable the clock */ - clk_enable(sci->src_clk); + clk_enable(sdd->src_clk); clk_enable(sdd->clk); s3c64xx_spi_hwinit(sdd, pdev->id); -- GitLab From ef6c680dc5a182a79b09567168d6713f46c85784 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:44 -0700 Subject: [PATCH 1017/3892] spi/s3c64xx: Check before mem-region release Add precautionary check before releasing memory region. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 3acf38119e96..0e883f9c720b 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -1097,7 +1097,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) iounmap((void *) sdd->regs); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem_res->start, resource_size(mem_res)); + if (mem_res != NULL) + release_mem_region(mem_res->start, resource_size(mem_res)); platform_set_drvdata(pdev, NULL); spi_master_put(master); -- GitLab From e6b873c9666015484a01373a4eebc6cfa82e670d Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1018/3892] spi/s3c64xx: Include moved header Header for platform specific stuff has been rename to include the SoC type. Include the new header instead. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 0e883f9c720b..9fa0b99e1607 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -28,7 +28,7 @@ #include #include -#include +#include /* Registers and bit-fields */ -- GitLab From fa0fcde66ac3360678360104b24492015e7b852b Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1019/3892] spi/s3c64xx: Add new parameter to cs callback Since most of the chip-selects are simply going to be like gpio_set_value, it would do good to have the same callback type so that it could simply be made to point at gpio_set_value. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 9fa0b99e1607..32db69540fa9 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -300,13 +300,14 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ /* Deselect the last toggled device */ cs = sdd->tgl_spi->controller_data; - cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); + cs->set_level(cs->line, + spi->mode & SPI_CS_HIGH ? 0 : 1); } sdd->tgl_spi = NULL; } cs = spi->controller_data; - cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0); + cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); } static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, @@ -386,7 +387,7 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, if (sdd->tgl_spi == spi) sdd->tgl_spi = NULL; - cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); + cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); } static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) -- GitLab From b490e3704ccee12deb295f96029d68e0daf02feb Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1020/3892] spi/dw_spi: bug fix in wait_till_not_busy() Make the driver wait at least for 1 jiffie before issuing the warning, no matter what HZ is set to Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 31620fae77be..521d680af289 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -161,7 +161,7 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) static void wait_till_not_busy(struct dw_spi *dws) { - unsigned long end = jiffies + usecs_to_jiffies(1000); + unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); while (time_before(jiffies, end)) { if (!(dw_readw(dws, sr) & SR_BUSY)) -- GitLab From 51f921c1eb1124fb99ab0728c19e8e14c82c81be Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1021/3892] spi/dw_spi: add a missed dw_spi_remove_host() in exit sequence Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c index 34ba69161734..7980f1443ce1 100644 --- a/drivers/spi/dw_spi_pci.c +++ b/drivers/spi/dw_spi_pci.c @@ -98,6 +98,7 @@ static void __devexit spi_pci_remove(struct pci_dev *pdev) struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); pci_set_drvdata(pdev, NULL); + dw_spi_remove_host(&dwpci->dws); iounmap(dwpci->dws.regs); pci_release_region(pdev, 0); kfree(dwpci); -- GitLab From 552e450929a7298cc8834fd2824a60b2e914f70e Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1022/3892] spi/dw_spi: refine the IRQ mode working flow Now dw_spi core fully supports 3 transfer modes: pure polling, DMA and IRQ mode. IRQ mode will use the FIFO half empty as the IRQ trigger, so each interface driver need set the fifo_len, so that core driver can handle it properly Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 64 +++++++++++++++++++++++--------------- drivers/spi/dw_spi_pci.c | 1 + include/linux/spi/dw_spi.h | 1 + 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 521d680af289..1bb709b3920f 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -358,6 +358,8 @@ static void transfer_complete(struct dw_spi *dws) static irqreturn_t interrupt_transfer(struct dw_spi *dws) { u16 irq_status, irq_mask = 0x3f; + u32 int_level = dws->fifo_len / 2; + u32 left; irq_status = dw_readw(dws, isr) & irq_mask; /* Error handling */ @@ -369,22 +371,23 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) return IRQ_HANDLED; } - /* INT comes from tx */ - if (dws->tx && (irq_status & SPI_INT_TXEI)) { - while (dws->tx < dws->tx_end) + if (irq_status & SPI_INT_TXEI) { + spi_mask_intr(dws, SPI_INT_TXEI); + + left = (dws->tx_end - dws->tx) / dws->n_bytes; + left = (left > int_level) ? int_level : left; + + while (left--) dws->write(dws); + dws->read(dws); - if (dws->tx == dws->tx_end) { - spi_mask_intr(dws, SPI_INT_TXEI); + /* Re-enable the IRQ if there is still data left to tx */ + if (dws->tx_end > dws->tx) + spi_umask_intr(dws, SPI_INT_TXEI); + else transfer_complete(dws); - } } - /* INT comes from rx */ - if (dws->rx && (irq_status & SPI_INT_RXFI)) { - if (dws->read(dws)) - transfer_complete(dws); - } return IRQ_HANDLED; } @@ -428,6 +431,7 @@ static void pump_transfers(unsigned long data) u8 bits = 0; u8 imask = 0; u8 cs_change = 0; + u16 txint_level = 0; u16 clk_div = 0; u32 speed = 0; u32 cr0 = 0; @@ -438,6 +442,9 @@ static void pump_transfers(unsigned long data) chip = dws->cur_chip; spi = message->spi; + if (unlikely(!chip->clk_div)) + chip->clk_div = dws->max_freq / chip->speed_hz; + if (message->state == ERROR_STATE) { message->status = -EIO; goto early_exit; @@ -492,7 +499,7 @@ static void pump_transfers(unsigned long data) /* clk_div doesn't support odd number */ clk_div = dws->max_freq / speed; - clk_div = (clk_div >> 1) << 1; + clk_div = (clk_div + 1) & 0xfffe; chip->speed_hz = speed; chip->clk_div = clk_div; @@ -535,11 +542,16 @@ static void pump_transfers(unsigned long data) /* Check if current transfer is a DMA transaction */ dws->dma_mapped = map_dma_buffers(dws); + /* + * Interrupt mode + * we only need set the TXEI IRQ, as TX/RX always happen syncronizely + */ if (!dws->dma_mapped && !chip->poll_mode) { - if (dws->rx) - imask |= SPI_INT_RXFI; - if (dws->tx) - imask |= SPI_INT_TXEI; + int templen = dws->len / dws->n_bytes; + txint_level = dws->fifo_len / 2; + txint_level = (templen > txint_level) ? txint_level : templen; + + imask |= SPI_INT_TXEI; dws->transfer_handler = interrupt_transfer; } @@ -549,21 +561,23 @@ static void pump_transfers(unsigned long data) * 2. clk_div is changed * 3. control value changes */ - if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) { + if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div || imask) { spi_enable_chip(dws, 0); if (dw_readw(dws, ctrl0) != cr0) dw_writew(dws, ctrl0, cr0); + spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); + spi_chip_sel(dws, spi->chip_select); + /* Set the interrupt mask, for poll mode just diable all int */ spi_mask_intr(dws, 0xff); - if (!chip->poll_mode) + if (imask) spi_umask_intr(dws, imask); + if (txint_level) + dw_writew(dws, txfltr, txint_level); - spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); - spi_chip_sel(dws, spi->chip_select); spi_enable_chip(dws, 1); - if (cs_change) dws->prev_chip = chip; } @@ -712,11 +726,11 @@ static int dw_spi_setup(struct spi_device *spi) } chip->bits_per_word = spi->bits_per_word; + if (!spi->max_speed_hz) { + dev_err(&spi->dev, "No max speed HZ parameter\n"); + return -EINVAL; + } chip->speed_hz = spi->max_speed_hz; - if (chip->speed_hz) - chip->clk_div = 25000000 / chip->speed_hz; - else - chip->clk_div = 8; /* default value */ chip->tmode = 0; /* Tx & Rx */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */ diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c index 7980f1443ce1..1f0735f9cc76 100644 --- a/drivers/spi/dw_spi_pci.c +++ b/drivers/spi/dw_spi_pci.c @@ -73,6 +73,7 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev, dws->num_cs = 4; dws->max_freq = 25000000; /* for Moorestwon */ dws->irq = pdev->irq; + dws->fifo_len = 40; /* FIFO has 40 words buffer */ ret = dw_spi_add_host(dws); if (ret) diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h index 51b3e771a9a3..1a127a31e017 100644 --- a/include/linux/spi/dw_spi.h +++ b/include/linux/spi/dw_spi.h @@ -90,6 +90,7 @@ struct dw_spi { unsigned long paddr; u32 iolen; int irq; + u32 fifo_len; /* depth of the FIFO buffer */ u32 max_freq; /* max bus freq supported */ u16 bus_num; -- GitLab From ac48eee064f743a198cb38e5a6a62c3f1082ebc1 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1023/3892] spi: update MSIOF includes Update the MSIOF driver to remove the architecture speficic spi header file and add err.h. This makes the driver compile on non-SH architectures. Signed-off-by: Magnus Damm Signed-off-by: Grant Likely --- drivers/spi/spi_sh_msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c index 51e5e1dfa6e5..3b5b1be57057 100644 --- a/drivers/spi/spi_sh_msiof.c +++ b/drivers/spi/spi_sh_msiof.c @@ -20,12 +20,12 @@ #include #include #include +#include #include #include #include -#include #include struct sh_msiof_spi_priv { -- GitLab From f4d4ecfe788b4141d8c90cfc3ac2831f620f5c1b Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1024/3892] spi/spi_imx: add device information by switching pr_debug() to dev_dbg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful when debugging multiple spi channels. Signed-off-by: Alberto Panizzo Acked-by: Uwe Kleine-König Signed-off-by: Grant Likely --- drivers/spi/spi_imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 1893f1e96dc4..0ddbbe45e834 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -469,7 +469,7 @@ static int spi_imx_setup(struct spi_device *spi) struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); int gpio = spi_imx->chipselect[spi->chip_select]; - pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__, + dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); if (gpio >= 0) -- GitLab From 9778214990af88ec6720bd771d7fc0fa1b140b02 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 20 Jan 2010 13:49:45 -0700 Subject: [PATCH 1025/3892] spi: xilinx_spi: Fix up I/O routine wrapping bogosity. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xilinx_spi presently makes some fairly questionable assumptions about I/O routines, and attempts to assign ioread32/iowrite32 and friends directly to its own internal function pointers. On many platforms these I/O routines are macros or wrappers and not actual functions on their own, resulting in things like: ERROR: "ioread32be" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "iowrite32be" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "iowrite32" [drivers/spi/xilinx_spi.ko] undefined! ERROR: "ioread32" [drivers/spi/xilinx_spi.ko] undefined! If xilinx_spi wants to do this sort of casting, it needs to provide its own wrappers for these, or change how it does accesses completely. I've opted for the first approach, and the attached silly patch does that. If someone with the hardware available wants to give the second option a try that's ok too. In any event, the current code is broken for at least: arm, avr32, blackfin, microblaze, mn10300, and sh. Signed-off-by: Paul Mundt Acked-by: Richard Röjfors Signed-off-by: Grant Likely --- drivers/spi/xilinx_spi.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 9f386379c169..1b47363cb73f 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -93,6 +93,26 @@ struct xilinx_spi { void (*rx_fn) (struct xilinx_spi *); }; +static void xspi_write32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +static unsigned int xspi_read32(void __iomem *addr) +{ + return ioread32(addr); +} + +static void xspi_write32_be(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +static unsigned int xspi_read32_be(void __iomem *addr) +{ + return ioread32be(addr); +} + static void xspi_tx8(struct xilinx_spi *xspi) { xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET); @@ -374,11 +394,11 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->mem = *mem; xspi->irq = irq; if (pdata->little_endian) { - xspi->read_fn = ioread32; - xspi->write_fn = iowrite32; + xspi->read_fn = xspi_read32; + xspi->write_fn = xspi_write32; } else { - xspi->read_fn = ioread32be; - xspi->write_fn = iowrite32be; + xspi->read_fn = xspi_read32_be; + xspi->write_fn = xspi_write32_be; } xspi->bits_per_word = pdata->bits_per_word; if (xspi->bits_per_word == 8) { -- GitLab From 99147b5c4167612a987860b661b9f8b79e66b81f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 20 Jan 2010 14:03:39 -0700 Subject: [PATCH 1026/3892] spi/dw_spi: fix __init/__devinit section mismatch Section mismatch in reference from the function dw_spi_add_host() to the function init_queue() Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 1bb709b3920f..f713af8309e3 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -749,7 +749,7 @@ static void dw_spi_cleanup(struct spi_device *spi) kfree(chip); } -static int __init init_queue(struct dw_spi *dws) +static int __devinit init_queue(struct dw_spi *dws) { INIT_LIST_HEAD(&dws->queue); spin_lock_init(&dws->lock); -- GitLab From 614b05900ec3516b835cd06f848ef6bc915beeea Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:02 +0000 Subject: [PATCH 1027/3892] tg3: Enable PLL PD when CLKREQ disabled for 5717A0 PCIe PLL power down cannot be used if CLKREQ is enabled because data corruption will occur. If CLKREQ is disabled though, enabling PCIE P1 PLL power-down saves some power. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 16 ++++++++++++++++ drivers/net/tg3.h | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b0630cd093a3..b80e7eef8af9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7569,6 +7569,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); } + if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) { + u32 grc_mode = tr32(GRC_MODE); + + /* Access the lower 1K of PL PCIE block registers. */ + val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK; + tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL); + + val = tr32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1); + tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1, + val | TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN); + + tw32(GRC_MODE, grc_mode); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express @@ -13096,6 +13110,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A1) tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; + } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) { + tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN; } } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index cd30889650f8..44a505d07e20 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1540,6 +1540,8 @@ #define GRC_MODE_HOST_SENDBDS 0x00020000 #define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 #define GRC_MODE_NVRAM_WR_ENABLE 0x00200000 +#define GRC_MODE_PCIE_TL_SEL 0x00000000 +#define GRC_MODE_PCIE_PL_SEL 0x00400000 #define GRC_MODE_NO_RX_PHDR_CSUM 0x00800000 #define GRC_MODE_IRQ_ON_TX_CPU_ATTN 0x01000000 #define GRC_MODE_IRQ_ON_RX_CPU_ATTN 0x02000000 @@ -1547,7 +1549,13 @@ #define GRC_MODE_IRQ_ON_DMA_ATTN 0x08000000 #define GRC_MODE_IRQ_ON_FLOW_ATTN 0x10000000 #define GRC_MODE_4X_NIC_SEND_RINGS 0x20000000 +#define GRC_MODE_PCIE_DL_SEL 0x20000000 #define GRC_MODE_MCAST_FRM_ENABLE 0x40000000 +#define GRC_MODE_PCIE_HI_1K_EN 0x80000000 +#define GRC_MODE_PCIE_PORT_MASK (GRC_MODE_PCIE_TL_SEL | \ + GRC_MODE_PCIE_PL_SEL | \ + GRC_MODE_PCIE_DL_SEL | \ + GRC_MODE_PCIE_HI_1K_EN) #define GRC_MISC_CFG 0x00006804 #define GRC_MISC_CFG_CORECLK_RESET 0x00000001 #define GRC_MISC_CFG_PRESCALAR_MASK 0x000000fe @@ -1801,6 +1809,11 @@ /* 0x7e74 --> 0x8000 unused */ +/* Alternate PCIE definitions */ +#define TG3_PCIE_TLDLPL_PORT 0x00007c00 +#define TG3_PCIE_PL_LO_PHYCTL1 0x00000004 +#define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN 0x00001000 + /* OTP bit definitions */ #define TG3_OTP_AGCTGT_MASK 0x000000e0 #define TG3_OTP_AGCTGT_SHIFT 1 @@ -2809,6 +2822,7 @@ struct tg3 { #define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000 #define TG3_FLG3_SHORT_DMA_BUG 0x00200000 #define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 +#define TG3_FLG3_L1PLLPD_EN 0x00800000 struct timer_list timer; u16 timer_counter; -- GitLab From 666bc831cf820e16cbd0c2d5be780c512b1afe15 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:03 +0000 Subject: [PATCH 1028/3892] tg3: Improve internal resource allocations The 5717 and the 57765 have more resources at their disposal internally. This patch tunes the driver to get better performance. The adjustments made here only apply to the 57765 and 5717 asic revs. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 25 +++++++++++++++++++++---- drivers/net/tg3.h | 4 ++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b80e7eef8af9..adb579f0d75d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8152,7 +8152,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Prevent chip from dropping frames when flow control * is enabled. */ - tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + val = 1; + else + val = 2; + tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { @@ -14091,9 +14095,22 @@ static void __devinit tg3_init_link_config(struct tg3 *tp) static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) { + tp->bufmgr_config.mbuf_read_dma_low_water = + DEFAULT_MB_RDMA_LOW_WATER_5705; + tp->bufmgr_config.mbuf_mac_rx_low_water = + DEFAULT_MB_MACRX_LOW_WATER_57765; + tp->bufmgr_config.mbuf_high_water = + DEFAULT_MB_HIGH_WATER_57765; + + tp->bufmgr_config.mbuf_read_dma_low_water_jumbo = + DEFAULT_MB_RDMA_LOW_WATER_5705; + tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo = + DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765; + tp->bufmgr_config.mbuf_high_water_jumbo = + DEFAULT_MB_HIGH_WATER_JUMBO_57765; + } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 44a505d07e20..91139fdf7f43 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1203,14 +1203,18 @@ #define DEFAULT_MB_MACRX_LOW_WATER 0x00000020 #define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010 #define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004 +#define DEFAULT_MB_MACRX_LOW_WATER_57765 0x0000002a #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098 #define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b +#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765 0x0000007e #define BUFMGR_MB_HIGH_WATER 0x00004418 #define DEFAULT_MB_HIGH_WATER 0x00000060 #define DEFAULT_MB_HIGH_WATER_5705 0x00000060 #define DEFAULT_MB_HIGH_WATER_5906 0x00000010 +#define DEFAULT_MB_HIGH_WATER_57765 0x000000a0 #define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c #define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096 +#define DEFAULT_MB_HIGH_WATER_JUMBO_57765 0x000000ea #define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c #define BUFMGR_MB_ALLOC_BIT 0x10000000 #define BUFMGR_RX_MB_ALLOC_RESP 0x00004420 -- GitLab From 9b952f51d019db37276bdb2924e776ca09132fc1 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:04 +0000 Subject: [PATCH 1029/3892] tg3: Add 5717 serdes phy ID The serdes and copper phys of the 5717 asic rev have different phy IDs. This patch adds the serdes phy ID. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- drivers/net/tg3.h | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index adb579f0d75d..4a653478edd6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -14170,7 +14170,8 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM5906: return "5906"; case PHY_ID_BCM5761: return "5761"; - case PHY_ID_BCM5717: return "5717"; + case PHY_ID_BCM5718C: return "5718C"; + case PHY_ID_BCM5718S: return "5718S"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 91139fdf7f43..edb7a14cf58f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2893,7 +2893,8 @@ struct tg3 { #define PHY_ID_BCM5756 0xbc050ed0 #define PHY_ID_BCM5784 0xbc050fa0 #define PHY_ID_BCM5761 0xbc050fd0 -#define PHY_ID_BCM5717 0x5c0d8a00 +#define PHY_ID_BCM5718C 0x5c0d8a00 +#define PHY_ID_BCM5718S 0xbc050ff0 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2936,7 +2937,8 @@ struct tg3 { (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \ - (X) == PHY_ID_BCM5717 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5718C || (X) == PHY_ID_BCM5718S || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; -- GitLab From ecf1410b9d70b3034e5955e92bb0c3e02ff21e9c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:05 +0000 Subject: [PATCH 1030/3892] tg3: Abort phy init for 5717 serdes devices The 5717 serdes devices have a different phy register layout than all other previous serdes devices. This patch aborts the phy init sequence in tg3_phy_reset() if the device is a 5717 serdes. It also aborts the tg3_phy_toggle_apd() operation. Most other operations in the MII_SERDES path are O.K. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4a653478edd6..7a36bf4dc968 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1560,7 +1560,9 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) { u32 reg; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) return; if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { @@ -1935,6 +1937,10 @@ static int tg3_phy_reset(struct tg3 *tp) } } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) + return 0; + tg3_phy_apply_otp(tp); if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) -- GitLab From 8b5a6c42e1f2277433aeefa9ee5a0c1a2473b7d8 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:06 +0000 Subject: [PATCH 1031/3892] tg3: Fix 5717 and 57765 memory selftests Both the 5717 and the 57765 will fail 'ethtool -t' selftests at the memory selftest portion. The memory map for these two devices differs from the rest of the asic revs and each other. This patch adds a new memory map to use for memory selftests. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7a36bf4dc968..44ac9e233bef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10659,12 +10659,27 @@ static int tg3_test_memory(struct tg3 *tp) { 0x00008000, 0x01000}, { 0x00010000, 0x01000}, { 0xffffffff, 0x00000} + }, mem_tbl_5717[] = { + { 0x00000200, 0x00008}, + { 0x00010000, 0x0a000}, + { 0x00020000, 0x13c00}, + { 0xffffffff, 0x00000} + }, mem_tbl_57765[] = { + { 0x00000200, 0x00008}, + { 0x00004000, 0x00800}, + { 0x00006000, 0x09800}, + { 0x00010000, 0x0a000}, + { 0xffffffff, 0x00000} }; struct mem_entry *mem_tbl; int err = 0; int i; - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + mem_tbl = mem_tbl_5717; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + mem_tbl = mem_tbl_57765; + else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; -- GitLab From 5fd68fbdaf75505a2400826c7f314a1f3121a5f7 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:07 +0000 Subject: [PATCH 1032/3892] tg3: Supply a nicaddr for 57765 jumbo RCB The 57765 needs the driver to supply a nic address to the jumbo RCB, just like all other devices except the 5717. This patch changes the test to single out the 5717 rather than maintain a lengthy whitelist of asic revs. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 44ac9e233bef..72d1e18a152c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7787,7 +7787,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | BDINFO_FLAGS_USE_EXT_RECV); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_JUMBO_BUFFER_DESC); } else { -- GitLab From c2353a3214ff5813c4b719b3cdacbe939b1c63a0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:08 +0000 Subject: [PATCH 1033/3892] tg3: Fix tx mailbox initialization If a device supports MSI-X interrupts, the driver assumes TSS will be available. This is not true for the 57765. This patch changes the code so that only the default tx mailbox is initialized if TSS is not available. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 72d1e18a152c..dffa51a4aafb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7440,10 +7440,13 @@ static void tg3_rings_reset(struct tg3 *tp) for (i = 1; i < TG3_IRQ_MAX_VECS; i++) { tp->napi[i].tx_prod = 0; tp->napi[i].tx_cons = 0; - tw32_mailbox(tp->napi[i].prodmbox, 0); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + tw32_mailbox(tp->napi[i].prodmbox, 0); tw32_rx_mbox(tp->napi[i].consmbox, 0); tw32_mailbox_f(tp->napi[i].int_mbox, 1); } + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) + tw32_mailbox(tp->napi[0].prodmbox, 0); } else { tp->napi[0].tx_prod = 0; tp->napi[0].tx_cons = 0; -- GitLab From cb4ed1fd8af963101a59c8c5fef97cbbf5f3fb88 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:09 +0000 Subject: [PATCH 1034/3892] tg3: Turn off the debug UART for 57765 If the debug UART is left enabled, the LEDs will not work properly. This patch disables the debug UART. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dffa51a4aafb..075d21a6b55a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -13328,7 +13328,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || -- GitLab From 334355aa590c4b58750015c2f5710cd5074f45dd Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:10 +0000 Subject: [PATCH 1035/3892] tg3: Bypass power source switching for 57765 The 57765 repurposes all the GPIOs normally used to switch power sources when configured as a NIC device. This patch changes the code to avoid touching the GPIOs for this asic rev. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 075d21a6b55a..78102023aa93 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2021,7 +2021,9 @@ static void tg3_frob_aux_power(struct tg3 *tp) { struct tg3 *tp_peer = tp; - if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0) + /* The GPIOs do something completely different on 57765. */ + if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) return; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || -- GitLab From b0f752210c0aa5e3d9ece4cbfefdc43092a68b83 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Jan 2010 16:58:11 +0000 Subject: [PATCH 1036/3892] tg3: Add 57765 phy ID and enable devices. This patch rounds out the 57765 asic rev support by adding the 57765 phy ID and entering the 57765 device IDs in the pci table. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 7 +++++++ drivers/net/tg3.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 78102023aa93..eaed2aa09e1f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -244,6 +244,12 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5718)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5724)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57781)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -14199,6 +14205,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5761: return "5761"; case PHY_ID_BCM5718C: return "5718C"; case PHY_ID_BCM5718S: return "5718S"; + case PHY_ID_BCM57765: return "57765"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index edb7a14cf58f..34c9ef4b74a3 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2895,6 +2895,7 @@ struct tg3 { #define PHY_ID_BCM5761 0xbc050fd0 #define PHY_ID_BCM5718C 0x5c0d8a00 #define PHY_ID_BCM5718S 0xbc050ff0 +#define PHY_ID_BCM57765 0x5c0d8a40 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2938,7 +2939,7 @@ struct tg3 { (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \ (X) == PHY_ID_BCM5718C || (X) == PHY_ID_BCM5718S || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM57765 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; -- GitLab From 77c2019fc1b4495ce483ef2af9cb12bae23e353b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 21 Jan 2010 14:19:41 +0900 Subject: [PATCH 1037/3892] sh: initial PMB mapping iteration by helper macro. All of the cached/uncached mapping setup is duplicated for each size, and also misses out on the 16MB case. Rather than duplicating the same iter code for that we just consolidate it in to a helper macro that builds an iter for each size. The 16MB case is then trivially bolted on at the end. Signed-off-by: Paul Mundt --- arch/sh/kernel/head_32.S | 207 ++++++++++++--------------------------- 1 file changed, 60 insertions(+), 147 deletions(-) diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 8ee31a0b973e..ee954d1b8cc6 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -86,6 +86,62 @@ ENTRY(_stext) #endif #if defined(CONFIG_PMB) && !defined(CONFIG_PMB_LEGACY) + +#define __PMB_ITER_BY_SIZE(size) \ +.L##size: \ + mov #(size >> 4), r6; \ + shll16 r6; \ + shll8 r6; \ + \ + cmp/hi r5, r6; \ + bt 9999f; \ + \ + mov #(PMB_SZ_##size##M >> 2), r9; \ + shll2 r9; \ + \ + /* \ + * Cached mapping \ + */ \ + mov #PMB_C, r8; \ + or r0, r8; \ + or r9, r8; \ + mov.l r8, @r1; \ + mov.l r2, @r3; \ + \ + /* Increment to the next PMB_DATA entry */ \ + add r4, r1; \ + /* Increment to the next PMB_ADDR entry */ \ + add r4, r3; \ + /* Increment number of PMB entries */ \ + add #1, r10; \ + \ + /* \ + * Uncached mapping \ + */ \ + mov #(PMB_UB >> 8), r8; \ + shll8 r8; \ + \ + or r0, r8; \ + or r9, r8; \ + mov.l r8, @r1; \ + mov r2, r8; \ + add r7, r8; \ + mov.l r8, @r3; \ + \ + /* Increment to the next PMB_DATA entry */ \ + add r4, r1; \ + /* Increment to the next PMB_ADDR entry */ \ + add r4, r3; \ + /* Increment number of PMB entries */ \ + add #1, r10; \ + \ + sub r6, r5; \ + add r6, r0; \ + add r6, r2; \ + \ + bra .L##size; \ +9999: + /* * Reconfigure the initial PMB mappings setup by the hardware. * @@ -142,154 +198,11 @@ ENTRY(_stext) * r9 = scratch register * r10 = number of PMB entries we've setup */ -.L512: - mov #(512 >> 4), r6 - shll16 r6 - shll8 r6 - - cmp/hi r5, r6 - bt .L128 - - mov #(PMB_SZ_512M >> 2), r9 - shll2 r9 - - /* - * Cached mapping - */ - mov #PMB_C, r8 - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov.l r2, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - /* - * Uncached mapping - */ - mov #(PMB_UB >> 8), r8 - shll8 r8 - - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov r2, r8 - add r7, r8 - mov.l r8, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - sub r6, r5 - add r6, r0 - add r6, r2 - - bra .L512 - -.L128: - mov #(128 >> 4), r6 - shll16 r6 - shll8 r6 - - cmp/hi r5, r6 - bt .L64 - - mov #(PMB_SZ_128M >> 2), r9 - shll2 r9 - - /* - * Cached mapping - */ - mov #PMB_C, r8 - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov.l r2, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - /* - * Uncached mapping - */ - mov #(PMB_UB >> 8), r8 - shll8 r8 - - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov r2, r8 - add r7, r8 - mov.l r8, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - sub r6, r5 - add r6, r0 - add r6, r2 - - bra .L128 - -.L64: - mov #(64 >> 4), r6 - shll16 r6 - shll8 r6 - - cmp/hi r5, r6 - bt .Ldone - - mov #(PMB_SZ_64M >> 2), r9 - shll2 r9 - - /* - * Cached mapping - */ - mov #PMB_C, r8 - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov.l r2, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - /* - * Uncached mapping - */ - mov #(PMB_UB >> 8), r8 - shll8 r8 - - or r0, r8 - or r9, r8 - mov.l r8, @r1 - mov r2, r8 - add r7, r8 - mov.l r8, @r3 - - add r4, r1 /* Increment to the next PMB_DATA entry */ - add r4, r3 /* Increment to the next PMB_ADDR entry */ - - add #1, r10 /* Increment number of PMB entries */ - - sub r6, r5 - add r6, r0 - add r6, r2 - - bra .L64 + __PMB_ITER_BY_SIZE(512) + __PMB_ITER_BY_SIZE(128) + __PMB_ITER_BY_SIZE(64) + __PMB_ITER_BY_SIZE(16) -.Ldone: /* Update cached_to_uncached */ mov.l .Lcached_to_uncached, r0 mov.l r7, @r0 -- GitLab From 2023b843d7b62d99e7356b872e99abc7d6667e49 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 21 Jan 2010 15:42:58 +0900 Subject: [PATCH 1038/3892] sh: Rework P2 to only include kernel text. This effectively neutralizes P2 by getting rid of P1 identity mapping for all available memory and instead only establishes a single unbuffered PMB entry (16MB -- the smallest available) that covers the kernel. As using segmentation for abusing caching attributes in drivers is no longer supported (and there are no drivers that can be enabled in 32-bit mode that do this), this provides us with all of the uncached access needs by the kernel itself. Drivers and their ilk need to specify their caching attributes when remapping through page tables, as usual. Signed-off-by: Paul Mundt --- arch/sh/kernel/head_32.S | 169 +++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index ee954d1b8cc6..e93320135cda 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -86,7 +86,96 @@ ENTRY(_stext) #endif #if defined(CONFIG_PMB) && !defined(CONFIG_PMB_LEGACY) +/* + * Reconfigure the initial PMB mappings setup by the hardware. + * + * When we boot in 32-bit MMU mode there are 2 PMB entries already + * setup for us. + * + * Entry VPN PPN V SZ C UB WT + * --------------------------------------------------------------- + * 0 0x80000000 0x00000000 1 512MB 1 0 1 + * 1 0xA0000000 0x00000000 1 512MB 0 0 0 + * + * But we reprogram them here because we want complete control over + * our address space and the initial mappings may not map PAGE_OFFSET + * to __MEMORY_START (or even map all of our RAM). + * + * Once we've setup cached and uncached mappings we clear the rest of the + * PMB entries. This clearing also deals with the fact that PMB entries + * can persist across reboots. The PMB could have been left in any state + * when the reboot occurred, so to be safe we clear all entries and start + * with with a clean slate. + * + * The uncached mapping is constructed using the smallest possible + * mapping with a single unbufferable page. Only the kernel text needs to + * be covered via the uncached mapping so that certain functions can be + * run uncached. + * + * Drivers and the like that have previously abused the 1:1 identity + * mapping are unsupported in 32-bit mode and must specify their caching + * preference when page tables are constructed. + * + * This frees up the P2 space for more nefarious purposes. + * + * Register utilization is as follows: + * + * r0 = PMB_DATA data field + * r1 = PMB_DATA address field + * r2 = PMB_ADDR data field + * r3 = PMB_ADDR address field + * r4 = PMB_E_SHIFT + * r5 = remaining amount of RAM to map + * r6 = PMB mapping size we're trying to use + * r7 = cached_to_uncached + * r8 = scratch register + * r9 = scratch register + * r10 = number of PMB entries we've setup + */ + + mov.l .LMMUCR, r1 /* Flush the TLB */ + mov.l @r1, r0 + or #MMUCR_TI, r0 + mov.l r0, @r1 + + mov.l .LMEMORY_SIZE, r5 + mov r5, r7 + + mov #PMB_E_SHIFT, r0 + mov #0x1, r4 + shld r0, r4 + mov.l .LFIRST_DATA_ENTRY, r0 + mov.l .LPMB_DATA, r1 + mov.l .LFIRST_ADDR_ENTRY, r2 + mov.l .LPMB_ADDR, r3 + + mov #0, r10 + + /* + * Uncached mapping + */ + mov #(PMB_SZ_16M >> 2), r9 + shll2 r9 + + mov #(PMB_UB >> 8), r8 + shll8 r8 + + or r0, r8 + or r9, r8 + mov.l r8, @r1 + mov r2, r8 + add r7, r8 + mov.l r8, @r3 + + add r4, r1 + add r4, r3 + add #1, r10 + +/* + * Iterate over all of the available sizes from largest to + * smallest for constructing the cached mapping. + */ #define __PMB_ITER_BY_SIZE(size) \ .L##size: \ mov #(size >> 4), r6; \ @@ -113,26 +202,6 @@ ENTRY(_stext) /* Increment to the next PMB_ADDR entry */ \ add r4, r3; \ /* Increment number of PMB entries */ \ - add #1, r10; \ - \ - /* \ - * Uncached mapping \ - */ \ - mov #(PMB_UB >> 8), r8; \ - shll8 r8; \ - \ - or r0, r8; \ - or r9, r8; \ - mov.l r8, @r1; \ - mov r2, r8; \ - add r7, r8; \ - mov.l r8, @r3; \ - \ - /* Increment to the next PMB_DATA entry */ \ - add r4, r1; \ - /* Increment to the next PMB_ADDR entry */ \ - add r4, r3; \ - /* Increment number of PMB entries */ \ add #1, r10; \ \ sub r6, r5; \ @@ -142,68 +211,14 @@ ENTRY(_stext) bra .L##size; \ 9999: - /* - * Reconfigure the initial PMB mappings setup by the hardware. - * - * When we boot in 32-bit MMU mode there are 2 PMB entries already - * setup for us. - * - * Entry VPN PPN V SZ C UB WT - * --------------------------------------------------------------- - * 0 0x80000000 0x00000000 1 512MB 1 0 1 - * 1 0xA0000000 0x00000000 1 512MB 0 0 0 - * - * But we reprogram them here because we want complete control over - * our address space and the initial mappings may not map PAGE_OFFSET - * to __MEMORY_START (or even map all of our RAM). - * - * Once we've setup cached and uncached mappings for all of RAM we - * clear the rest of the PMB entries. - * - * This clearing also deals with the fact that PMB entries can persist - * across reboots. The PMB could have been left in any state when the - * reboot occurred, so to be safe we clear all entries and start with - * with a clean slate. - */ - - mov.l .LMMUCR, r1 /* Flush the TLB */ - mov.l @r1, r0 - or #MMUCR_TI, r0 - mov.l r0, @r1 - - mov.l .LMEMORY_SIZE, r5 - mov r5, r7 - - mov #PMB_E_SHIFT, r0 - mov #0x1, r4 - shld r0, r4 - - mov.l .LFIRST_DATA_ENTRY, r0 - mov.l .LPMB_DATA, r1 - mov.l .LFIRST_ADDR_ENTRY, r2 - mov.l .LPMB_ADDR, r3 - - mov #0, r10 - - /* - * r0 = PMB_DATA data field - * r1 = PMB_DATA address field - * r2 = PMB_ADDR data field - * r3 = PMB_ADDR address field - * r4 = PMB_E_SHIFT - * r5 = remaining amount of RAM to map - * r6 = PMB mapping size we're trying to use - * r7 = cached_to_uncached - * r8 = scratch register - * r9 = scratch register - * r10 = number of PMB entries we've setup - */ __PMB_ITER_BY_SIZE(512) __PMB_ITER_BY_SIZE(128) __PMB_ITER_BY_SIZE(64) __PMB_ITER_BY_SIZE(16) - /* Update cached_to_uncached */ + /* + * Now that we can access it, update cached_to_uncached. + */ mov.l .Lcached_to_uncached, r0 mov.l r7, @r0 -- GitLab From 3125ee72dca25fc2157dcddd07e2d740db921fc4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 21 Jan 2010 15:54:31 +0900 Subject: [PATCH 1039/3892] sh: Track the uncached mapping size. This provides a variable for tracking the uncached mapping size, and uses it for pretty printing the uncached lowmem range. Beyond this, we'll also be building on top of this for figuring out from where the remainder of P2 becomes usable when constructing unrelated mappings. Signed-off-by: Paul Mundt --- arch/sh/include/asm/system.h | 1 + arch/sh/kernel/head_32.S | 10 +++++++++- arch/sh/mm/init.c | 21 ++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index de2fc3963c12..6442f1783fe0 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -137,6 +137,7 @@ extern unsigned int instruction_size(unsigned int insn); #endif extern unsigned long cached_to_uncached; +extern unsigned long uncached_size; extern struct dentry *sh_debugfs_root; diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index e93320135cda..83f2b84b58da 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -217,11 +217,18 @@ ENTRY(_stext) __PMB_ITER_BY_SIZE(16) /* - * Now that we can access it, update cached_to_uncached. + * Now that we can access it, update cached_to_uncached and + * uncached_size. */ mov.l .Lcached_to_uncached, r0 mov.l r7, @r0 + mov.l .Luncached_size, r0 + mov #1, r7 + shll16 r7 + shll8 r7 + mov.l r7, @r0 + /* * Clear the remaining PMB entries. * @@ -300,5 +307,6 @@ ENTRY(stack_start) .LFIRST_DATA_ENTRY: .long __MEMORY_START | PMB_V .LMMUCR: .long MMUCR .Lcached_to_uncached: .long cached_to_uncached +.Luncached_size: .long uncached_size .LMEMORY_SIZE: .long __MEMORY_SIZE #endif diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index f3e23ad075cb..a28ff63c17a6 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -27,15 +27,17 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD]; #ifdef CONFIG_SUPERH32 /* - * Handle trivial transitions between cached and uncached - * segments, making use of the 1:1 mapping relationship in - * 512MB lowmem. - * * This is the offset of the uncached section from its cached alias. - * Default value only valid in 29 bit mode, in 32bit mode will be - * overridden in pmb_init. + * + * Legacy platforms handle trivial transitions between cached and + * uncached segments by making use of the 1:1 mapping relationship in + * 512MB lowmem, others via a special uncached mapping. + * + * Default value only valid in 29 bit mode, in 32bit mode this will be + * updated by the early PMB initialization code. */ unsigned long cached_to_uncached = P2SEG - P1SEG; +unsigned long uncached_size = 0x20000000; #endif #ifdef CONFIG_MMU @@ -281,7 +283,8 @@ void __init mem_init(void) " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" #endif " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" - " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB) (cached)\n" + " : 0x%08lx - 0x%08lx (%4ld MB) (uncached)\n" " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", @@ -299,6 +302,10 @@ void __init mem_init(void) (unsigned long)memory_start, (unsigned long)high_memory, ((unsigned long)high_memory - (unsigned long)memory_start) >> 20, + (unsigned long)memory_start + cached_to_uncached, + (unsigned long)memory_start + cached_to_uncached + uncached_size, + uncached_size >> 20, + (unsigned long)&__init_begin, (unsigned long)&__init_end, ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10, -- GitLab From 2dc2f8e0c46864e2a3722c84eaa96513d4cf8b2f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 21 Jan 2010 16:05:25 +0900 Subject: [PATCH 1040/3892] sh: Kill off the special uncached section and fixmap. Now that cached_to_uncached works as advertized in 32-bit mode and we're never going to be able to map < 16MB anyways, there's no need for the special uncached section. Kill it off. Signed-off-by: Paul Mundt --- arch/sh/include/asm/fixmap.h | 4 +++- arch/sh/include/asm/system_32.h | 3 --- arch/sh/include/asm/system_64.h | 2 -- arch/sh/kernel/cpu/init.c | 4 ++-- arch/sh/kernel/cpu/sh3/probe.c | 2 +- arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 3 ++- arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 3 ++- arch/sh/kernel/vmlinux.lds.S | 12 ------------ arch/sh/mm/cache-debugfs.c | 3 +-- arch/sh/mm/cache-sh4.c | 4 ++-- arch/sh/mm/cache-sh7705.c | 4 ++-- arch/sh/mm/init.c | 3 --- arch/sh/mm/pmb.c | 6 +++--- arch/sh/mm/tlb-pteaex.c | 3 +-- arch/sh/mm/tlb-sh4.c | 3 +-- 15 files changed, 20 insertions(+), 39 deletions(-) diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h index 38a1de866873..17b22b6c1001 100644 --- a/arch/sh/include/asm/fixmap.h +++ b/arch/sh/include/asm/fixmap.h @@ -55,11 +55,12 @@ enum fixed_addresses { #define FIX_N_COLOURS 8 FIX_CMAP_BEGIN, FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS) - 1, - FIX_UNCACHED, + #ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + /* * FIX_IOREMAP entries are useful for mapping physical address * space before ioremap() is useable, e.g. really early in boot @@ -68,6 +69,7 @@ enum fixed_addresses { #define FIX_N_IOREMAPS 32 FIX_IOREMAP_BEGIN, FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS, + __end_of_fixed_addresses }; diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h index 34bd2bac9a5f..51296b36770e 100644 --- a/arch/sh/include/asm/system_32.h +++ b/arch/sh/include/asm/system_32.h @@ -145,9 +145,6 @@ do { \ __restore_dsp(prev); \ } while (0) -#define __uses_jump_to_uncached \ - noinline __attribute__ ((__section__ (".uncached.text"))) - /* * Jump to uncached area. * When handling TLB or caches, we need to do it from an uncached area. diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h index 604ba7802cc2..3391bb6b21d8 100644 --- a/arch/sh/include/asm/system_64.h +++ b/arch/sh/include/asm/system_64.h @@ -33,8 +33,6 @@ do { \ &next->thread); \ } while (0) -#define __uses_jump_to_uncached - #define jump_to_uncached() do { } while (0) #define back_to_cached() do { } while (0) diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index a5bb0550bbf3..05a7d2a373b6 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -98,7 +98,7 @@ static void __init expmask_init(void) #endif /* 2nd-level cache init */ -void __uses_jump_to_uncached __attribute__ ((weak)) l2_cache_init(void) +void __attribute__ ((weak)) l2_cache_init(void) { } @@ -106,7 +106,7 @@ void __uses_jump_to_uncached __attribute__ ((weak)) l2_cache_init(void) * Generic first-level cache init */ #ifdef CONFIG_SUPERH32 -static void __uses_jump_to_uncached cache_init(void) +static void cache_init(void) { unsigned long ccr, flags; diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c index f9c7df64eb01..c2db65719f4d 100644 --- a/arch/sh/kernel/cpu/sh3/probe.c +++ b/arch/sh/kernel/cpu/sh3/probe.c @@ -16,7 +16,7 @@ #include #include -int __uses_jump_to_uncached detect_cpu_and_cache_system(void) +int detect_cpu_and_cache_system(void) { unsigned long addr0, addr1, data0, data1, data2, data3; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index 772b9265d0e4..9d426258aa00 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -592,7 +592,8 @@ void __init plat_early_device_setup(void) #define RAMCR_CACHE_L2FC 0x0002 #define RAMCR_CACHE_L2E 0x0001 #define L2_CACHE_ENABLE (RAMCR_CACHE_L2E|RAMCR_CACHE_L2FC) -void __uses_jump_to_uncached l2_cache_init(void) + +void l2_cache_init(void) { /* Enable L2 cache */ ctrl_outl(L2_CACHE_ENABLE, RAMCR); diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index d32f96c1cc15..578e9f80271f 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -714,7 +714,8 @@ void __init plat_early_device_setup(void) #define RAMCR_CACHE_L2FC 0x0002 #define RAMCR_CACHE_L2E 0x0001 #define L2_CACHE_ENABLE (RAMCR_CACHE_L2E|RAMCR_CACHE_L2FC) -void __uses_jump_to_uncached l2_cache_init(void) + +void l2_cache_init(void) { /* Enable L2 cache */ ctrl_outl(L2_CACHE_ENABLE, RAMCR); diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 9e5a5878eeae..93e9b25a1811 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -53,18 +53,6 @@ SECTIONS NOTES RO_DATA(PAGE_SIZE) - - /* - * Code which must be executed uncached and the associated data - */ - . = ALIGN(PAGE_SIZE); - .uncached : AT(ADDR(.uncached) - LOAD_OFFSET) { - __uncached_start = .; - *(.uncached.text) - *(.uncached.data) - __uncached_end = .; - } - RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) _edata = .; /* End of data section */ diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index 5ba067b26591..48ce82ee9fd2 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c @@ -22,8 +22,7 @@ enum cache_type { CACHE_TYPE_UNIFIED, }; -static int __uses_jump_to_uncached cache_seq_show(struct seq_file *file, - void *iter) +static int cache_seq_show(struct seq_file *file, void *iter) { unsigned int cache_type = (unsigned int)file->private; struct cache_info *cache; diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index a2301daeefa3..87115b3ee70e 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -36,7 +36,7 @@ static void __flush_cache_one(unsigned long addr, unsigned long phys, * Called from kernel/module.c:sys_init_module and routine for a.out format, * signal handler code and kprobes code */ -static void __uses_jump_to_uncached sh4_flush_icache_range(void *args) +static void sh4_flush_icache_range(void *args) { struct flusher_data *data = args; unsigned long start, end; @@ -124,7 +124,7 @@ static void sh4_flush_dcache_page(void *arg) } /* TODO: Selective icache invalidation through IC address array.. */ -static void __uses_jump_to_uncached flush_icache_all(void) +static void flush_icache_all(void) { unsigned long flags, ccr; diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index f527fb70fce6..870293ee539e 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -78,7 +78,7 @@ static void sh7705_flush_icache_range(void *args) /* * Writeback&Invalidate the D-cache of the page */ -static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys) +static void __flush_dcache_page(unsigned long phys) { unsigned long ways, waysize, addrstart; unsigned long flags; @@ -144,7 +144,7 @@ static void sh7705_flush_dcache_page(void *arg) __flush_dcache_page(__pa(page_address(page))); } -static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args) +static void sh7705_flush_cache_all(void *args) { unsigned long flags; diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index a28ff63c17a6..dffa6c749489 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -211,9 +211,6 @@ void __init paging_init(void) } free_area_init_nodes(max_zone_pfns); - - /* Set up the uncached fixmap */ - set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); } /* diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index d318fa6caffe..3d5eece7e6d0 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -127,14 +127,14 @@ static void __set_pmb_entry(unsigned long vpn, unsigned long ppn, ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos)); } -static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe) +static void set_pmb_entry(struct pmb_entry *pmbe) { jump_to_uncached(); __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry); back_to_cached(); } -static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe) +static void clear_pmb_entry(struct pmb_entry *pmbe) { unsigned int entry = pmbe->entry; unsigned long addr; @@ -364,7 +364,7 @@ static inline int pmb_apply_legacy_mappings(void) } #endif -int __uses_jump_to_uncached pmb_init(void) +int pmb_init(void) { int i; unsigned long addr, data; diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 409b7c2b4b9d..32dc674c550c 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -68,8 +68,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) * in extended mode, the legacy 8-bit ASID field in address array 1 has * undefined behaviour. */ -void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, - unsigned long page) +void local_flush_tlb_one(unsigned long asid, unsigned long page) { jump_to_uncached(); __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT); diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 8cf550e2570f..624c1daa9f3f 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -64,8 +64,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) local_irq_restore(flags); } -void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid, - unsigned long page) +void local_flush_tlb_one(unsigned long asid, unsigned long page) { unsigned long addr, data; -- GitLab From a077e91690fb32a1453423b2cf1df3492fd30c3a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 21 Jan 2010 16:16:36 +0900 Subject: [PATCH 1041/3892] sh: Conserve fixmap slots when IOREMAP_FIXED=n. Presently the IOREMAP_FIXED fixmaps are always defined, even if the platform isn't capable of supporting it. Since we already have an ifdef for it, ifdef the entries, too. Signed-off-by: Paul Mundt --- arch/sh/include/asm/fixmap.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h index 17b22b6c1001..6e7cea453895 100644 --- a/arch/sh/include/asm/fixmap.h +++ b/arch/sh/include/asm/fixmap.h @@ -61,6 +61,7 @@ enum fixed_addresses { FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif +#ifdef CONFIG_IOREMAP_FIXED /* * FIX_IOREMAP entries are useful for mapping physical address * space before ioremap() is useable, e.g. really early in boot @@ -69,6 +70,7 @@ enum fixed_addresses { #define FIX_N_IOREMAPS 32 FIX_IOREMAP_BEGIN, FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS, +#endif __end_of_fixed_addresses }; -- GitLab From ef12a141306c90336a3a10d40213ecd98624d274 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 20 Jan 2010 15:28:45 -0200 Subject: [PATCH 1042/3892] perf buildid-cache: Add new command to manage build-id cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now it just has operations to examine a given file, find its build-id and add or remove it to/from the cache. Useful, for instance, when adding binaries sent together with a perf.data file, so that we can add them to the cache and have the tools find it when resolving symbols. It'll also manage the size of the cache like 'ccache' does. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264008525-29025-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- .../perf/Documentation/perf-buildid-cache.txt | 33 +++++ tools/perf/Makefile | 1 + tools/perf/builtin-buildid-cache.c | 133 ++++++++++++++++++ tools/perf/builtin.h | 1 + tools/perf/command-list.txt | 1 + tools/perf/perf.c | 1 + tools/perf/util/header.c | 72 ++++++++-- tools/perf/util/header.h | 5 + tools/perf/util/symbol.c | 4 +- tools/perf/util/symbol.h | 2 +- 10 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 tools/perf/Documentation/perf-buildid-cache.txt create mode 100644 tools/perf/builtin-buildid-cache.c diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt new file mode 100644 index 000000000000..88bc3b519746 --- /dev/null +++ b/tools/perf/Documentation/perf-buildid-cache.txt @@ -0,0 +1,33 @@ +perf-buildid-cache(1) +===================== + +NAME +---- +perf-buildid-cache - Manage build-id cache. + +SYNOPSIS +-------- +[verse] +'perf buildid-list ' + +DESCRIPTION +----------- +This command manages the build-id cache. It can add and remove files to the +cache. In the future it should as well purge older entries, set upper limits +for the space used by the cache, etc. + +OPTIONS +------- +-a:: +--add=:: + Add specified file to the cache. +-r:: +--remove=:: + Remove specified file to the cache. +-v:: +--verbose:: + Be more verbose. + +SEE ALSO +-------- +linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ddbeeee9ade2..9b173e66fb41 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -445,6 +445,7 @@ BUILTIN_OBJS += builtin-diff.o BUILTIN_OBJS += builtin-help.o BUILTIN_OBJS += builtin-sched.o BUILTIN_OBJS += builtin-buildid-list.o +BUILTIN_OBJS += builtin-buildid-cache.o BUILTIN_OBJS += builtin-list.o BUILTIN_OBJS += builtin-record.o BUILTIN_OBJS += builtin-report.o diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c new file mode 100644 index 000000000000..30a05f552c96 --- /dev/null +++ b/tools/perf/builtin-buildid-cache.c @@ -0,0 +1,133 @@ +/* + * builtin-buildid-cache.c + * + * Builtin buildid-cache command: Manages build-id cache + * + * Copyright (C) 2010, Red Hat Inc. + * Copyright (C) 2010, Arnaldo Carvalho de Melo + */ +#include "builtin.h" +#include "perf.h" +#include "util/cache.h" +#include "util/debug.h" +#include "util/header.h" +#include "util/parse-options.h" +#include "util/strlist.h" +#include "util/symbol.h" + +static char const *add_name_list_str, *remove_name_list_str; + +static const char * const buildid_cache_usage[] = { + "perf buildid-cache []", + NULL +}; + +static const struct option buildid_cache_options[] = { + OPT_STRING('a', "add", &add_name_list_str, + "file list", "file(s) to add"), + OPT_STRING('r', "remove", &remove_name_list_str, "file list", + "file(s) to remove"), + OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"), + OPT_END() +}; + +static int build_id_cache__add_file(const char *filename, const char *debugdir) +{ + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + u8 build_id[BUILD_ID_SIZE]; + int err; + + if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { + pr_debug("Couldn't read a build-id in %s\n", filename); + return -1; + } + + build_id__sprintf(build_id, sizeof(build_id), sbuild_id); + err = build_id_cache__add_s(sbuild_id, debugdir, filename, false); + if (verbose) + pr_info("Adding %s %s: %s\n", sbuild_id, filename, + err ? "FAIL" : "Ok"); + return err; +} + +static int build_id_cache__remove_file(const char *filename __used, + const char *debugdir __used) +{ + u8 build_id[BUILD_ID_SIZE]; + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + + int err; + + if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { + pr_debug("Couldn't read a build-id in %s\n", filename); + return -1; + } + + build_id__sprintf(build_id, sizeof(build_id), sbuild_id); + err = build_id_cache__remove_s(sbuild_id, debugdir); + if (verbose) + pr_info("Removing %s %s: %s\n", sbuild_id, filename, + err ? "FAIL" : "Ok"); + + return err; +} + +static int __cmd_buildid_cache(void) +{ + struct strlist *list; + struct str_node *pos; + char debugdir[PATH_MAX]; + + snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), + DEBUG_CACHE_DIR); + + if (add_name_list_str) { + list = strlist__new(true, add_name_list_str); + if (list) { + strlist__for_each(pos, list) + if (build_id_cache__add_file(pos->s, debugdir)) { + if (errno == EEXIST) { + pr_debug("%s already in the cache\n", + pos->s); + continue; + } + pr_warning("Couldn't add %s: %s\n", + pos->s, strerror(errno)); + } + + strlist__delete(list); + } + } + + if (remove_name_list_str) { + list = strlist__new(true, remove_name_list_str); + if (list) { + strlist__for_each(pos, list) + if (build_id_cache__remove_file(pos->s, debugdir)) { + if (errno == ENOENT) { + pr_debug("%s wasn't in the cache\n", + pos->s); + continue; + } + pr_warning("Couldn't remove %s: %s\n", + pos->s, strerror(errno)); + } + + strlist__delete(list); + } + } + + return 0; +} + +int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used) +{ + argc = parse_options(argc, argv, buildid_cache_options, + buildid_cache_usage, 0); + + if (symbol__init() < 0) + return -1; + + setup_pager(); + return __cmd_buildid_cache(); +} diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 18035b1f16c7..dee97cfe3794 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd); extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_bench(int argc, const char **argv, const char *prefix); +extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); extern int cmd_diff(int argc, const char **argv, const char *prefix); extern int cmd_help(int argc, const char **argv, const char *prefix); diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index cf6444dfd73a..9afcff2e3ae5 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -5,6 +5,7 @@ perf-annotate mainporcelain common perf-archive mainporcelain common perf-bench mainporcelain common +perf-buildid-cache mainporcelain common perf-buildid-list mainporcelain common perf-diff mainporcelain common perf-list mainporcelain common diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fc89005c3e51..05c861c045d5 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -285,6 +285,7 @@ static void handle_internal_command(int argc, const char **argv) { const char *cmd = argv[0]; static struct cmd_struct commands[] = { + { "buildid-cache", cmd_buildid_cache, 0 }, { "buildid-list", cmd_buildid_list, 0 }, { "diff", cmd_diff, 0 }, { "help", cmd_help, 0 }, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1b65fed0dd2d..2bb2bdb1f456 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -231,32 +231,29 @@ static int dsos__write_buildid_table(int fd) return err; } -static int dso__cache_build_id(struct dso *self, const char *debugdir) +int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, + const char *name, bool is_kallsyms) { const size_t size = PATH_MAX; char *filename = malloc(size), - *linkname = malloc(size), *targetname, *sbuild_id; + *linkname = malloc(size), *targetname; int len, err = -1; - bool is_kallsyms = self->kernel && self->long_name[0] != '/'; if (filename == NULL || linkname == NULL) goto out_free; len = snprintf(filename, size, "%s%s%s", - debugdir, is_kallsyms ? "/" : "", self->long_name); + debugdir, is_kallsyms ? "/" : "", name); if (mkdir_p(filename, 0755)) goto out_free; - len += snprintf(filename + len, sizeof(filename) - len, "/"); - sbuild_id = filename + len; - build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); + snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); if (access(filename, F_OK)) { if (is_kallsyms) { if (copyfile("/proc/kallsyms", filename)) goto out_free; - } else if (link(self->long_name, filename) && - copyfile(self->long_name, filename)) + } else if (link(name, filename) && copyfile(name, filename)) goto out_free; } @@ -278,6 +275,63 @@ out_free: return err; } +static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, + const char *name, const char *debugdir, + bool is_kallsyms) +{ + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + + build_id__sprintf(build_id, build_id_size, sbuild_id); + + return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); +} + +int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) +{ + const size_t size = PATH_MAX; + char *filename = malloc(size), + *linkname = malloc(size); + int err = -1; + + if (filename == NULL || linkname == NULL) + goto out_free; + + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, sbuild_id + 2); + + if (access(linkname, F_OK)) + goto out_free; + + if (readlink(linkname, filename, size) < 0) + goto out_free; + + if (unlink(linkname)) + goto out_free; + + /* + * Since the link is relative, we must make it absolute: + */ + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, filename); + + if (unlink(linkname)) + goto out_free; + + err = 0; +out_free: + free(filename); + free(linkname); + return err; +} + +static int dso__cache_build_id(struct dso *self, const char *debugdir) +{ + bool is_kallsyms = self->kernel && self->long_name[0] != '/'; + + return build_id_cache__add_b(self->build_id, sizeof(self->build_id), + self->long_name, debugdir, is_kallsyms); +} + static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) { struct dso *pos; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index ccc8540feccd..82a6af72d4cc 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -5,6 +5,7 @@ #include #include #include "types.h" +#include "event.h" #include @@ -84,4 +85,8 @@ int perf_header__process_sections(struct perf_header *self, int fd, struct perf_header *ph, int feat, int fd)); +int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, + const char *name, bool is_kallsyms); +int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); + #endif /* __PERF_HEADER_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b6ab23dd5f9f..6f30fe18c265 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -345,10 +345,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type) &self->symbols[type]); } -int build_id__sprintf(u8 *self, int len, char *bf) +int build_id__sprintf(const u8 *self, int len, char *bf) { char *bid = bf; - u8 *raw = self; + const u8 *raw = self; int i; for (i = 0; i < len; ++i) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 525085fd0735..ffe0b0f2e5d3 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -144,7 +144,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); -int build_id__sprintf(u8 *self, int len, char *bf); +int build_id__sprintf(const u8 *self, int len, char *bf); int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start)); -- GitLab From 3bf127637e22ddf95e67e10a23c339cee3d52429 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 21 Jan 2010 00:02:36 -0800 Subject: [PATCH 1043/3892] Input: sh_keysc - add mode 4 and mode 5 support Add Mode 4 and Mode 5 support to the SH_KEYSC driver. These modes allow slightly larger key pad matrixes. While at it, make use of resource_size(). Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 6 +++--- include/linux/input/sh_keysc.h | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 076111fc72d2..25706f802258 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -36,6 +36,8 @@ static const struct { [SH_KEYSC_MODE_1] = { 0, 6, 5 }, [SH_KEYSC_MODE_2] = { 1, 5, 6 }, [SH_KEYSC_MODE_3] = { 2, 4, 7 }, + [SH_KEYSC_MODE_4] = { 3, 6, 6 }, + [SH_KEYSC_MODE_5] = { 4, 6, 7 }, }; struct sh_keysc_priv { @@ -122,8 +124,6 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) return IRQ_HANDLED; } -#define res_size(res) ((res)->end - (res)->start + 1) - static int __devinit sh_keysc_probe(struct platform_device *pdev) { struct sh_keysc_priv *priv; @@ -164,7 +164,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata)); pdata = &priv->pdata; - priv->iomem_base = ioremap_nocache(res->start, res_size(res)); + priv->iomem_base = ioremap_nocache(res->start, resource_size(res)); if (priv->iomem_base == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; diff --git a/include/linux/input/sh_keysc.h b/include/linux/input/sh_keysc.h index c211b5cf08e6..2aff38bcf2ba 100644 --- a/include/linux/input/sh_keysc.h +++ b/include/linux/input/sh_keysc.h @@ -1,10 +1,11 @@ #ifndef __SH_KEYSC_H__ #define __SH_KEYSC_H__ -#define SH_KEYSC_MAXKEYS 30 +#define SH_KEYSC_MAXKEYS 42 struct sh_keysc_info { - enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3 } mode; + enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3, + SH_KEYSC_MODE_4, SH_KEYSC_MODE_5 } mode; int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */ int delay; int kycr2_delay; -- GitLab From d03e067778104911cc02cb92dd152df2f3b988a5 Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Wed, 13 Jan 2010 22:13:16 +0000 Subject: [PATCH 1044/3892] dts/mpc8569mds: Cleanup tbi phy to support rtbi After these change, when need to work in rtbi mode, just change phy-connection-type to "rtbi". Also, this work can be done by u-boot. Signed-off-by: Liu Yu Signed-off-by: David S. Miller --- arch/powerpc/boot/dts/mpc8569mds.dts | 47 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts index 795eb362fcf9..8b72eaff5b03 100644 --- a/arch/powerpc/boot/dts/mpc8569mds.dts +++ b/arch/powerpc/boot/dts/mpc8569mds.dts @@ -535,6 +535,7 @@ rx-clock-name = "none"; tx-clock-name = "clk12"; pio-handle = <&pio1>; + tbi-handle = <&tbi1>; phy-handle = <&qe_phy0>; phy-connection-type = "rgmii-id"; }; @@ -579,7 +580,7 @@ reg = <0x6>; device_type = "ethernet-phy"; }; - tbi-phy@11 { + tbi1: tbi-phy@11 { reg = <0x11>; device_type = "tbi-phy"; }; @@ -590,7 +591,7 @@ reg = <0x3520 0x18>; compatible = "fsl,ucc-mdio"; - tbi0: tbi-phy@15 { + tbi6: tbi-phy@15 { reg = <0x15>; device_type = "tbi-phy"; }; @@ -600,7 +601,7 @@ #size-cells = <0>; reg = <0x3720 0x38>; compatible = "fsl,ucc-mdio"; - tbi1: tbi-phy@17 { + tbi8: tbi-phy@17 { reg = <0x17>; device_type = "tbi-phy"; }; @@ -617,10 +618,22 @@ rx-clock-name = "none"; tx-clock-name = "clk12"; pio-handle = <&pio3>; + tbi-handle = <&tbi3>; phy-handle = <&qe_phy2>; phy-connection-type = "rgmii-id"; }; + mdio@2320 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2320 0x18>; + compatible = "fsl,ucc-mdio"; + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + enet1: ucc@3000 { device_type = "network"; compatible = "ucc_geth"; @@ -632,10 +645,22 @@ rx-clock-name = "none"; tx-clock-name = "clk17"; pio-handle = <&pio2>; + tbi-handle = <&tbi2>; phy-handle = <&qe_phy1>; phy-connection-type = "rgmii-id"; }; + mdio@3120 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3120 0x18>; + compatible = "fsl,ucc-mdio"; + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + enet3: ucc@3200 { device_type = "network"; compatible = "ucc_geth"; @@ -647,10 +672,22 @@ rx-clock-name = "none"; tx-clock-name = "clk17"; pio-handle = <&pio4>; + tbi-handle = <&tbi4>; phy-handle = <&qe_phy3>; phy-connection-type = "rgmii-id"; }; + mdio@3320 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3320 0x18>; + compatible = "fsl,ucc-mdio"; + tbi4: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + enet5: ucc@3400 { device_type = "network"; compatible = "ucc_geth"; @@ -661,7 +698,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; rx-clock-name = "none"; tx-clock-name = "none"; - tbi-handle = <&tbi0>; + tbi-handle = <&tbi6>; phy-handle = <&qe_phy5>; phy-connection-type = "sgmii"; }; @@ -676,7 +713,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; rx-clock-name = "none"; tx-clock-name = "none"; - tbi-handle = <&tbi1>; + tbi-handle = <&tbi8>; phy-handle = <&qe_phy7>; phy-connection-type = "sgmii"; }; -- GitLab From c1fb8340d7a39346c08ec4b1db4fb432f02acd4c Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Wed, 13 Jan 2010 22:13:17 +0000 Subject: [PATCH 1045/3892] mpc8569mds: Add bscr setting for rtbi mode Signed-off-by: Liu Yu Signed-off-by: David S. Miller --- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 21f61b8c445b..04ed2156db1c 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -237,6 +237,8 @@ static void __init mpc85xx_mds_setup_arch(void) } else if (machine_is(mpc8569_mds)) { #define BCSR7_UCC12_GETHnRST (0x1 << 2) #define BCSR8_UEM_MARVELL_RST (0x1 << 1) +#define BCSR_UCC_RGMII (0x1 << 6) +#define BCSR_UCC_RTBI (0x1 << 5) /* * U-Boot mangles interrupt polarity for Marvell PHYs, * so reset built-in and UEM Marvell PHYs, this puts @@ -247,6 +249,28 @@ static void __init mpc85xx_mds_setup_arch(void) setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST); clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST); + + for (np = NULL; (np = of_find_compatible_node(np, + "network", + "ucc_geth")) != NULL;) { + const unsigned int *prop; + int ucc_num; + + prop = of_get_property(np, "cell-index", NULL); + if (prop == NULL) + continue; + + ucc_num = *prop - 1; + + prop = of_get_property(np, "phy-connection-type", NULL); + if (prop == NULL) + continue; + + if (strcmp("rtbi", (const char *)prop) == 0) + clrsetbits_8(&bcsr_regs[7 + ucc_num], + BCSR_UCC_RGMII, BCSR_UCC_RTBI); + } + } iounmap(bcsr_regs); } -- GitLab From 81abb43a243b6d74b6f7201a7a22aa5355cd3a8a Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Wed, 13 Jan 2010 22:13:18 +0000 Subject: [PATCH 1046/3892] ucc_geth: update the tbi-phy setting Old method only set tbi-phy for eth0. Signed-off-by: Liu Yu Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 96bdc0b43889..6750de10a087 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "ucc_geth.h" #include "fsl_pq_mdio.h" @@ -1334,7 +1335,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) struct ucc_geth __iomem *ug_regs; struct ucc_fast __iomem *uf_regs; int ret_val; - u32 upsmr, maccfg2, tbiBaseAddress; + u32 upsmr, maccfg2; u16 value; ugeth_vdbg("%s: IN", __func__); @@ -1389,14 +1390,20 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) /* Note that this depends on proper setting in utbipar register. */ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { - tbiBaseAddress = in_be32(&ug_regs->utbipar); - tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; - tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; - value = ugeth->phydev->bus->read(ugeth->phydev->bus, - (u8) tbiBaseAddress, ENET_TBI_MII_CR); + struct ucc_geth_info *ug_info = ugeth->ug_info; + struct phy_device *tbiphy; + + if (!ug_info->tbi_node) + ugeth_warn("TBI mode requires that the device " + "tree specify a tbi-handle\n"); + + tbiphy = of_phy_find_device(ug_info->tbi_node); + if (!tbiphy) + ugeth_warn("Could not get TBI device\n"); + + value = phy_read(tbiphy, ENET_TBI_MII_CR); value &= ~0x1000; /* Turn off autonegotiation */ - ugeth->phydev->bus->write(ugeth->phydev->bus, - (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); + phy_write(tbiphy, ENET_TBI_MII_CR, value); } init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); -- GitLab From 5f8cbc13225eadd981c817f7d14b8deab61ebfaa Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Wed, 13 Jan 2010 22:13:19 +0000 Subject: [PATCH 1047/3892] phy: add RTBI mode for m88e1111 Signed-off-by: Liu Yu Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 6f69b9ba0df8..65ed385c2ceb 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -63,6 +63,7 @@ #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 +#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 @@ -269,6 +270,43 @@ static int m88e1111_config_init(struct phy_device *phydev) return err; } + if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; + + /* soft reset */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + do + temp = phy_read(phydev, MII_BMCR); + while (temp & BMCR_RESET); + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; + } + + err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) return err; -- GitLab From 4b258461c0b31ded170a1a56b944b0fded1c887b Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 21 Jan 2010 01:26:29 -0800 Subject: [PATCH 1048/3892] net: Optimize non-gso test checks Avoid checking twice whether skb needs to be linearized, if one skb_linearize was already done. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- net/core/dev.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 5747b9edc1bb..4fad9db417b1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1982,6 +1982,21 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, return rc; } +/* + * Returns true if either: + * 1. skb has frag_list and the device doesn't support FRAGLIST, or + * 2. skb is fragmented and the device does not support SG, or if + * at least one of fragments is in highmem and device does not + * support DMA from it. + */ +static inline int skb_needs_linearize(struct sk_buff *skb, + struct net_device *dev) +{ + return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) || + (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || + illegal_highdma(dev, skb))); +} + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -2018,18 +2033,8 @@ int dev_queue_xmit(struct sk_buff *skb) if (netif_needs_gso(dev, skb)) goto gso; - if (skb_has_frags(skb) && - !(dev->features & NETIF_F_FRAGLIST) && - __skb_linearize(skb)) - goto out_kfree_skb; - - /* Fragmented skb is linearized if device does not support SG, - * or if at least one of fragments is in highmem and device - * does not support DMA from it. - */ - if (skb_shinfo(skb)->nr_frags && - (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - __skb_linearize(skb)) + /* Convert a paged skb to linear, if required */ + if (skb_needs_linearize(skb, dev) && __skb_linearize(skb)) goto out_kfree_skb; /* If packet is not checksummed and device does not support -- GitLab From 17660f81243e998f36257881ac3ae61685bf91c1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 21 Jan 2010 01:28:45 -0800 Subject: [PATCH 1049/3892] vhost: fix TUN=m VHOST_NET=y drivers/built-in.o: In function `get_tun_socket': net.c:(.text+0x15436e): undefined reference to `tun_get_socket' If tun is a module, vhost must be a module, too. If tun is built-in or disabled, vhost can be built-in. Note: TUN || !TUN might look a bit strange until you realize that boolean logic rules do not apply for tristate variables. Reported-by: Randy Dunlap Signed-off-by: Michael S. Tsirkin Acked-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/vhost/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 9f409f447aea..9e9355367bb3 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -1,6 +1,6 @@ config VHOST_NET tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)" - depends on NET && EVENTFD && EXPERIMENTAL + depends on NET && EVENTFD && (TUN || !TUN) && EXPERIMENTAL ---help--- This kernel module can be loaded in host kernel to accelerate guest networking with virtio_net. Not to be confused with virtio_net -- GitLab From c91a988dc6551c66418690e36b2a23cdb0255da8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 21 Jan 2010 10:32:15 +0100 Subject: [PATCH 1050/3892] ALSA: pcm_core: Fix wake_up() optimization This change fixes the "ALSA: pcm_lib - optimize wake_up() calls for PCM I/O" commit. New sleeping queue is introduced to separate user space and kernel space wake_ups. runtime->nowake is renamed to twake (transfer wake). Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 5 +++-- sound/core/pcm.c | 1 + sound/core/pcm_lib.c | 20 ++++++++++---------- sound/core/pcm_native.c | 3 +++ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e26fb3c58037..3bc9bca771ec 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -311,8 +311,9 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ - unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ - wait_queue_head_t sleep; + unsigned int twake: 1; /* do transfer (!poll) wakeup */ + wait_queue_head_t sleep; /* poll sleep */ + wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; /* -- private section -- */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index df57a0e30bf2..0d428d0896db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); + init_waitqueue_head(&runtime->tsleep); runtime->status->state = SNDRV_PCM_STATE_OPEN; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 5417f7dce834..e2a817eac2a9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -285,8 +285,8 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return -EPIPE; } } - if (!runtime->nowake && avail >= runtime->control->avail_min) - wake_up(&runtime->sleep); + if (avail >= runtime->control->avail_min) + wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); return 0; } @@ -1692,7 +1692,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, long tout; init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->sleep, &wait); + add_wait_queue(&runtime->tsleep, &wait); for (;;) { if (signal_pending(current)) { err = -ERESTARTSYS; @@ -1735,7 +1735,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, break; } _endloop: - remove_wait_queue(&runtime->sleep, &wait); + remove_wait_queue(&runtime->tsleep, &wait); *availp = avail; return err; } @@ -1794,7 +1794,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->nowake = 1; + runtime->twake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1816,7 +1816,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->nowake = 0; + runtime->twake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } @@ -1855,7 +1855,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } } _end_unlock: - runtime->nowake = 0; + runtime->twake = 0; if (xfer > 0 && err >= 0) snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); @@ -2016,7 +2016,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->nowake = 1; + runtime->twake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2045,7 +2045,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->nowake = 0; + runtime->twake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } @@ -2078,7 +2078,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, xfer += frames; } _end_unlock: - runtime->nowake = 0; + runtime->twake = 0; if (xfer > 0 && err >= 0) snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 27284f628361..56ec35e8510b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -919,6 +919,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) runtime->status->state = state; } wake_up(&runtime->sleep); + wake_up(&runtime->tsleep); } static struct action_ops snd_pcm_action_stop = { @@ -1004,6 +1005,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp); wake_up(&runtime->sleep); + wake_up(&runtime->tsleep); } else { runtime->status->state = SNDRV_PCM_STATE_RUNNING; if (substream->timer) @@ -1061,6 +1063,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) runtime->status->suspended_state = runtime->status->state; runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; wake_up(&runtime->sleep); + wake_up(&runtime->tsleep); } static struct action_ops snd_pcm_action_suspend = { -- GitLab From 09cb47a2c68f9596927bc05dab0453edb35cd32d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 21 Jan 2010 02:43:20 -0800 Subject: [PATCH 1051/3892] net/sctp: Eliminate useless code The variable newinet is initialized twice to the same (side effect-free) expression. Drop one initialization. A simplified version of the semantic match that finds this problem is: (http://coccinelle.lip6.fr/) // @forall@ idexpression *x; identifier f!=ERR_PTR; @@ x = f(...) ... when != x ( x = f(...,<+...x...+>,...) | * x = f(...) ) // Signed-off-by: Julia Lawall Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 67fdac9d2d33..f6d1e59c4151 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6359,7 +6359,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, struct sctp_association *asoc) { struct inet_sock *inet = inet_sk(sk); - struct inet_sock *newinet = inet_sk(newsk); + struct inet_sock *newinet; newsk->sk_type = sk->sk_type; newsk->sk_bound_dev_if = sk->sk_bound_dev_if; -- GitLab From b91b8fa02482a5a18f598ee5d2cd42970051731b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Jan 2010 18:18:35 +0000 Subject: [PATCH 1052/3892] ASoC: Remove console DAPM debug code The same information is now visible via debugfs and with large modern devices dumping everything to the console can be very resource intensive, causing more harm than good. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-dapm.c | 80 ++------------------------------------------ 1 file changed, 3 insertions(+), 77 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index de22c2f1842e..d8e93749321e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -44,13 +44,6 @@ #include #include -/* debug */ -#ifdef DEBUG -#define dump_dapm(codec, action) dbg_dump_dapm(codec, action) -#else -#define dump_dapm(codec, action) -#endif - /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, @@ -1063,66 +1056,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) return 0; } -#ifdef DEBUG -static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) -{ - struct snd_soc_dapm_widget *w; - struct snd_soc_dapm_path *p = NULL; - int in, out; - - printk("DAPM %s %s\n", codec->name, action); - - list_for_each_entry(w, &codec->dapm_widgets, list) { - - /* only display widgets that effect routing */ - switch (w->id) { - case snd_soc_dapm_pre: - case snd_soc_dapm_post: - case snd_soc_dapm_vmid: - continue; - case snd_soc_dapm_mux: - case snd_soc_dapm_value_mux: - case snd_soc_dapm_output: - case snd_soc_dapm_input: - case snd_soc_dapm_switch: - case snd_soc_dapm_hp: - case snd_soc_dapm_mic: - case snd_soc_dapm_spk: - case snd_soc_dapm_line: - case snd_soc_dapm_micbias: - case snd_soc_dapm_dac: - case snd_soc_dapm_adc: - case snd_soc_dapm_pga: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: - case snd_soc_dapm_supply: - case snd_soc_dapm_aif_in: - case snd_soc_dapm_aif_out: - if (w->name) { - in = is_connected_input_ep(w); - dapm_clear_walk(w->codec); - out = is_connected_output_ep(w); - dapm_clear_walk(w->codec); - printk("%s: %s in %d out %d\n", w->name, - w->power ? "On":"Off",in, out); - - list_for_each_entry(p, &w->sources, list_sink) { - if (p->connect) - printk(" in %s %s\n", p->name ? p->name : "static", - p->source->name); - } - list_for_each_entry(p, &w->sinks, list_source) { - if (p->connect) - printk(" out %s %s\n", p->name ? p->name : "static", - p->sink->name); - } - } - break; - } - } -} -#endif - #ifdef CONFIG_DEBUG_FS static int dapm_widget_power_open_file(struct inode *inode, struct file *file) { @@ -1254,10 +1187,8 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, path->connect = 0; /* old connection must be powered down */ } - if (found) { + if (found) dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mux power update"); - } return 0; } @@ -1285,10 +1216,8 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, break; } - if (found) { + if (found) dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mixer power update"); - } return 0; } @@ -1404,9 +1333,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, */ int snd_soc_dapm_sync(struct snd_soc_codec *codec) { - int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(codec, "sync"); - return ret; + return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); @@ -2163,7 +2090,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, dapm_power_widgets(codec, event); mutex_unlock(&codec->mutex); - dump_dapm(codec, __func__); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); -- GitLab From a96ca3387382498ec8b501db5acef3ed9eb1bd36 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 19 Jan 2010 22:49:43 +0000 Subject: [PATCH 1053/3892] ASoC: Support turning off bias when the CODEC is idle Currently ASoC always maintains the bias of the CODEC while the system is active. With older mobile CODECs this is required since the outputs are referenced to a non-zero voltage and enabling or disabling this voltage without audible pops or clicks in the output takes too long to do when starting or stopping audio. As a result of features such as ground referenced outputs and class D speaker drivers current generation devices are able to power on and off much more quickly without these system level issues so provide a new flag idle_bias_off in snd_soc_codec which will cause the core to turn off the CODEC bias. The distinction between STANDBY and OFF is still maintained. This is partly for consistency but also allows for potential future extensions such as per-machine overrides or deferring the bias removal. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 2 ++ sound/soc/soc-dapm.c | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 08909ccd235b..a8768ea7571a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -405,6 +405,8 @@ struct snd_soc_codec { short reg_cache_size; short reg_cache_step; + unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ + /* dapm */ u32 pop_time; struct list_head dapm_widgets; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d8e93749321e..6c3351095786 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1012,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) sys_power = 0; break; case SND_SOC_DAPM_STREAM_NOP: - sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; + switch (codec->bias_level) { + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + sys_power = 0; + break; + default: + sys_power = 1; + break; + } break; default: break; } } + if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { + ret = snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_STANDBY); + if (ret != 0) + pr_err("Failed to turn on bias: %d\n", ret); + } + /* If we're changing to all on or all off then prepare */ if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { @@ -1042,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) pr_err("Failed to apply standby bias: %d\n", ret); } + /* If we're in standby and can support bias off then do that */ + if (codec->bias_level == SND_SOC_BIAS_STANDBY && + codec->idle_bias_off) { + ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); + if (ret != 0) + pr_err("Failed to turn off bias: %d\n", ret); + } + /* If we just powered up then move to active bias */ if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { ret = snd_soc_dapm_set_bias_level(socdev, -- GitLab From 821dd91ec7838e1313d783384ea9ce43510d4013 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 21 Jan 2010 11:33:20 +0000 Subject: [PATCH 1054/3892] ASoC: Use BIAS_OFF when idle for wm_hubs devices This provides a small power saving when audio is inactive. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm_hubs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index d73c30536a2c..a67319d9ca7e 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -753,6 +753,12 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, WM8993_LINEOUT2_MODE, WM8993_LINEOUT2_MODE); + /* If the line outputs are differential then we aren't presenting + * VMID as an output and can disable it. + */ + if (lineout1_diff && lineout2_diff) + codec->idle_bias_off = 1; + if (lineout1fb) snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); -- GitLab From 1e3c88bdeb1260edc341e45c9fb8efd182a5c511 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 17:00:43 +0100 Subject: [PATCH 1055/3892] sched: Move load balance code into sched_fair.c Straight fwd code movement. Since non of the load-balance abstractions are used anymore, do away with them and simplify the code some. In preparation move the code around. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched.c | 1919 ++----------------------------------------- kernel/sched_fair.c | 1765 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 1844 insertions(+), 1840 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 64298a52eaa6..13a2acf18b2d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1805,6 +1805,51 @@ static inline void double_unlock_balance(struct rq *this_rq, struct rq *busiest) raw_spin_unlock(&busiest->lock); lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_); } + +/* + * double_rq_lock - safely lock two runqueues + * + * Note this does not disable interrupts like task_rq_lock, + * you need to do so manually before calling. + */ +static void double_rq_lock(struct rq *rq1, struct rq *rq2) + __acquires(rq1->lock) + __acquires(rq2->lock) +{ + BUG_ON(!irqs_disabled()); + if (rq1 == rq2) { + raw_spin_lock(&rq1->lock); + __acquire(rq2->lock); /* Fake it out ;) */ + } else { + if (rq1 < rq2) { + raw_spin_lock(&rq1->lock); + raw_spin_lock_nested(&rq2->lock, SINGLE_DEPTH_NESTING); + } else { + raw_spin_lock(&rq2->lock); + raw_spin_lock_nested(&rq1->lock, SINGLE_DEPTH_NESTING); + } + } + update_rq_clock(rq1); + update_rq_clock(rq2); +} + +/* + * double_rq_unlock - safely unlock two runqueues + * + * Note this does not restore interrupts like task_rq_unlock, + * you need to do so manually after calling. + */ +static void double_rq_unlock(struct rq *rq1, struct rq *rq2) + __releases(rq1->lock) + __releases(rq2->lock) +{ + raw_spin_unlock(&rq1->lock); + if (rq1 != rq2) + raw_spin_unlock(&rq2->lock); + else + __release(rq2->lock); +} + #endif #ifdef CONFIG_FAIR_GROUP_SCHED @@ -1834,18 +1879,14 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) #endif } -#include "sched_stats.h" -#include "sched_idletask.c" -#include "sched_fair.c" -#include "sched_rt.c" -#ifdef CONFIG_SCHED_DEBUG -# include "sched_debug.c" -#endif +static const struct sched_class rt_sched_class; #define sched_class_highest (&rt_sched_class) #define for_each_class(class) \ for (class = sched_class_highest; class; class = class->next) +#include "sched_stats.h" + static void inc_nr_running(struct rq *rq) { rq->nr_running++; @@ -1911,6 +1952,37 @@ static void dequeue_task(struct rq *rq, struct task_struct *p, int sleep) p->se.on_rq = 0; } +/* + * activate_task - move a task to the runqueue. + */ +static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) +{ + if (task_contributes_to_load(p)) + rq->nr_uninterruptible--; + + enqueue_task(rq, p, wakeup); + inc_nr_running(rq); +} + +/* + * deactivate_task - remove a task from the runqueue. + */ +static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep) +{ + if (task_contributes_to_load(p)) + rq->nr_uninterruptible++; + + dequeue_task(rq, p, sleep); + dec_nr_running(rq); +} + +#include "sched_idletask.c" +#include "sched_fair.c" +#include "sched_rt.c" +#ifdef CONFIG_SCHED_DEBUG +# include "sched_debug.c" +#endif + /* * __normal_prio - return the priority that is based on the static prio */ @@ -1957,30 +2029,6 @@ static int effective_prio(struct task_struct *p) return p->prio; } -/* - * activate_task - move a task to the runqueue. - */ -static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) -{ - if (task_contributes_to_load(p)) - rq->nr_uninterruptible--; - - enqueue_task(rq, p, wakeup); - inc_nr_running(rq); -} - -/* - * deactivate_task - remove a task from the runqueue. - */ -static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep) -{ - if (task_contributes_to_load(p)) - rq->nr_uninterruptible++; - - dequeue_task(rq, p, sleep); - dec_nr_running(rq); -} - /** * task_curr - is this task currently executing on a CPU? * @p: the task in question. @@ -3087,50 +3135,6 @@ static void update_cpu_load(struct rq *this_rq) #ifdef CONFIG_SMP -/* - * double_rq_lock - safely lock two runqueues - * - * Note this does not disable interrupts like task_rq_lock, - * you need to do so manually before calling. - */ -static void double_rq_lock(struct rq *rq1, struct rq *rq2) - __acquires(rq1->lock) - __acquires(rq2->lock) -{ - BUG_ON(!irqs_disabled()); - if (rq1 == rq2) { - raw_spin_lock(&rq1->lock); - __acquire(rq2->lock); /* Fake it out ;) */ - } else { - if (rq1 < rq2) { - raw_spin_lock(&rq1->lock); - raw_spin_lock_nested(&rq2->lock, SINGLE_DEPTH_NESTING); - } else { - raw_spin_lock(&rq2->lock); - raw_spin_lock_nested(&rq1->lock, SINGLE_DEPTH_NESTING); - } - } - update_rq_clock(rq1); - update_rq_clock(rq2); -} - -/* - * double_rq_unlock - safely unlock two runqueues - * - * Note this does not restore interrupts like task_rq_unlock, - * you need to do so manually after calling. - */ -static void double_rq_unlock(struct rq *rq1, struct rq *rq2) - __releases(rq1->lock) - __releases(rq2->lock) -{ - raw_spin_unlock(&rq1->lock); - if (rq1 != rq2) - raw_spin_unlock(&rq2->lock); - else - __release(rq2->lock); -} - /* * sched_exec - execve() is a valuable balancing opportunity, because at * this point the task has the smallest effective memory and cache footprint. @@ -3179,1771 +3183,6 @@ again: task_rq_unlock(rq, &flags); } -/* - * pull_task - move a task from a remote runqueue to the local runqueue. - * Both runqueues must be locked. - */ -static void pull_task(struct rq *src_rq, struct task_struct *p, - struct rq *this_rq, int this_cpu) -{ - deactivate_task(src_rq, p, 0); - set_task_cpu(p, this_cpu); - activate_task(this_rq, p, 0); - check_preempt_curr(this_rq, p, 0); -} - -/* - * can_migrate_task - may task p from runqueue rq be migrated to this_cpu? - */ -static -int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned) -{ - int tsk_cache_hot = 0; - /* - * We do not migrate tasks that are: - * 1) running (obviously), or - * 2) cannot be migrated to this CPU due to cpus_allowed, or - * 3) are cache-hot on their current CPU. - */ - if (!cpumask_test_cpu(this_cpu, &p->cpus_allowed)) { - schedstat_inc(p, se.nr_failed_migrations_affine); - return 0; - } - *all_pinned = 0; - - if (task_running(rq, p)) { - schedstat_inc(p, se.nr_failed_migrations_running); - return 0; - } - - /* - * Aggressive migration if: - * 1) task is cache cold, or - * 2) too many balance attempts have failed. - */ - - tsk_cache_hot = task_hot(p, rq->clock, sd); - if (!tsk_cache_hot || - sd->nr_balance_failed > sd->cache_nice_tries) { -#ifdef CONFIG_SCHEDSTATS - if (tsk_cache_hot) { - schedstat_inc(sd, lb_hot_gained[idle]); - schedstat_inc(p, se.nr_forced_migrations); - } -#endif - return 1; - } - - if (tsk_cache_hot) { - schedstat_inc(p, se.nr_failed_migrations_hot); - return 0; - } - return 1; -} - -static unsigned long -balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, struct sched_domain *sd, - enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct rq_iterator *iterator) -{ - int loops = 0, pulled = 0, pinned = 0; - struct task_struct *p; - long rem_load_move = max_load_move; - - if (max_load_move == 0) - goto out; - - pinned = 1; - - /* - * Start the load-balancing iterator: - */ - p = iterator->start(iterator->arg); -next: - if (!p || loops++ > sysctl_sched_nr_migrate) - goto out; - - if ((p->se.load.weight >> 1) > rem_load_move || - !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { - p = iterator->next(iterator->arg); - goto next; - } - - pull_task(busiest, p, this_rq, this_cpu); - pulled++; - rem_load_move -= p->se.load.weight; - -#ifdef CONFIG_PREEMPT - /* - * NEWIDLE balancing is a source of latency, so preemptible kernels - * will stop after the first task is pulled to minimize the critical - * section. - */ - if (idle == CPU_NEWLY_IDLE) - goto out; -#endif - - /* - * We only want to steal up to the prescribed amount of weighted load. - */ - if (rem_load_move > 0) { - if (p->prio < *this_best_prio) - *this_best_prio = p->prio; - p = iterator->next(iterator->arg); - goto next; - } -out: - /* - * Right now, this is one of only two places pull_task() is called, - * so we can safely collect pull_task() stats here rather than - * inside pull_task(). - */ - schedstat_add(sd, lb_gained[idle], pulled); - - if (all_pinned) - *all_pinned = pinned; - - return max_load_move - rem_load_move; -} - -/* - * move_tasks tries to move up to max_load_move weighted load from busiest to - * this_rq, as part of a balancing operation within domain "sd". - * Returns 1 if successful and 0 otherwise. - * - * Called with both runqueues locked. - */ -static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned) -{ - const struct sched_class *class = sched_class_highest; - unsigned long total_load_moved = 0; - int this_best_prio = this_rq->curr->prio; - - do { - total_load_moved += - class->load_balance(this_rq, this_cpu, busiest, - max_load_move - total_load_moved, - sd, idle, all_pinned, &this_best_prio); - class = class->next; - -#ifdef CONFIG_PREEMPT - /* - * NEWIDLE balancing is a source of latency, so preemptible - * kernels will stop after the first task is pulled to minimize - * the critical section. - */ - if (idle == CPU_NEWLY_IDLE && this_rq->nr_running) - break; -#endif - } while (class && max_load_move > total_load_moved); - - return total_load_moved > 0; -} - -static int -iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle, - struct rq_iterator *iterator) -{ - struct task_struct *p = iterator->start(iterator->arg); - int pinned = 0; - - while (p) { - if (can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { - pull_task(busiest, p, this_rq, this_cpu); - /* - * Right now, this is only the second place pull_task() - * is called, so we can safely collect pull_task() - * stats here rather than inside pull_task(). - */ - schedstat_inc(sd, lb_gained[idle]); - - return 1; - } - p = iterator->next(iterator->arg); - } - - return 0; -} - -/* - * move_one_task tries to move exactly one task from busiest to this_rq, as - * part of active balancing operations within "domain". - * Returns 1 if successful and 0 otherwise. - * - * Called with both runqueues locked. - */ -static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - const struct sched_class *class; - - for_each_class(class) { - if (class->move_one_task(this_rq, this_cpu, busiest, sd, idle)) - return 1; - } - - return 0; -} -/********** Helpers for find_busiest_group ************************/ -/* - * sd_lb_stats - Structure to store the statistics of a sched_domain - * during load balancing. - */ -struct sd_lb_stats { - struct sched_group *busiest; /* Busiest group in this sd */ - struct sched_group *this; /* Local group in this sd */ - unsigned long total_load; /* Total load of all groups in sd */ - unsigned long total_pwr; /* Total power of all groups in sd */ - unsigned long avg_load; /* Average load across all groups in sd */ - - /** Statistics of this group */ - unsigned long this_load; - unsigned long this_load_per_task; - unsigned long this_nr_running; - - /* Statistics of the busiest group */ - unsigned long max_load; - unsigned long busiest_load_per_task; - unsigned long busiest_nr_running; - - int group_imb; /* Is there imbalance in this sd */ -#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) - int power_savings_balance; /* Is powersave balance needed for this sd */ - struct sched_group *group_min; /* Least loaded group in sd */ - struct sched_group *group_leader; /* Group which relieves group_min */ - unsigned long min_load_per_task; /* load_per_task in group_min */ - unsigned long leader_nr_running; /* Nr running of group_leader */ - unsigned long min_nr_running; /* Nr running of group_min */ -#endif -}; - -/* - * sg_lb_stats - stats of a sched_group required for load_balancing - */ -struct sg_lb_stats { - unsigned long avg_load; /*Avg load across the CPUs of the group */ - unsigned long group_load; /* Total load over the CPUs of the group */ - unsigned long sum_nr_running; /* Nr tasks running in the group */ - unsigned long sum_weighted_load; /* Weighted load of group's tasks */ - unsigned long group_capacity; - int group_imb; /* Is there an imbalance in the group ? */ -}; - -/** - * group_first_cpu - Returns the first cpu in the cpumask of a sched_group. - * @group: The group whose first cpu is to be returned. - */ -static inline unsigned int group_first_cpu(struct sched_group *group) -{ - return cpumask_first(sched_group_cpus(group)); -} - -/** - * get_sd_load_idx - Obtain the load index for a given sched domain. - * @sd: The sched_domain whose load_idx is to be obtained. - * @idle: The Idle status of the CPU for whose sd load_icx is obtained. - */ -static inline int get_sd_load_idx(struct sched_domain *sd, - enum cpu_idle_type idle) -{ - int load_idx; - - switch (idle) { - case CPU_NOT_IDLE: - load_idx = sd->busy_idx; - break; - - case CPU_NEWLY_IDLE: - load_idx = sd->newidle_idx; - break; - default: - load_idx = sd->idle_idx; - break; - } - - return load_idx; -} - - -#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) -/** - * init_sd_power_savings_stats - Initialize power savings statistics for - * the given sched_domain, during load balancing. - * - * @sd: Sched domain whose power-savings statistics are to be initialized. - * @sds: Variable containing the statistics for sd. - * @idle: Idle status of the CPU at which we're performing load-balancing. - */ -static inline void init_sd_power_savings_stats(struct sched_domain *sd, - struct sd_lb_stats *sds, enum cpu_idle_type idle) -{ - /* - * Busy processors will not participate in power savings - * balance. - */ - if (idle == CPU_NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE)) - sds->power_savings_balance = 0; - else { - sds->power_savings_balance = 1; - sds->min_nr_running = ULONG_MAX; - sds->leader_nr_running = 0; - } -} - -/** - * update_sd_power_savings_stats - Update the power saving stats for a - * sched_domain while performing load balancing. - * - * @group: sched_group belonging to the sched_domain under consideration. - * @sds: Variable containing the statistics of the sched_domain - * @local_group: Does group contain the CPU for which we're performing - * load balancing ? - * @sgs: Variable containing the statistics of the group. - */ -static inline void update_sd_power_savings_stats(struct sched_group *group, - struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs) -{ - - if (!sds->power_savings_balance) - return; - - /* - * If the local group is idle or completely loaded - * no need to do power savings balance at this domain - */ - if (local_group && (sds->this_nr_running >= sgs->group_capacity || - !sds->this_nr_running)) - sds->power_savings_balance = 0; - - /* - * If a group is already running at full capacity or idle, - * don't include that group in power savings calculations - */ - if (!sds->power_savings_balance || - sgs->sum_nr_running >= sgs->group_capacity || - !sgs->sum_nr_running) - return; - - /* - * Calculate the group which has the least non-idle load. - * This is the group from where we need to pick up the load - * for saving power - */ - if ((sgs->sum_nr_running < sds->min_nr_running) || - (sgs->sum_nr_running == sds->min_nr_running && - group_first_cpu(group) > group_first_cpu(sds->group_min))) { - sds->group_min = group; - sds->min_nr_running = sgs->sum_nr_running; - sds->min_load_per_task = sgs->sum_weighted_load / - sgs->sum_nr_running; - } - - /* - * Calculate the group which is almost near its - * capacity but still has some space to pick up some load - * from other group and save more power - */ - if (sgs->sum_nr_running + 1 > sgs->group_capacity) - return; - - if (sgs->sum_nr_running > sds->leader_nr_running || - (sgs->sum_nr_running == sds->leader_nr_running && - group_first_cpu(group) < group_first_cpu(sds->group_leader))) { - sds->group_leader = group; - sds->leader_nr_running = sgs->sum_nr_running; - } -} - -/** - * check_power_save_busiest_group - see if there is potential for some power-savings balance - * @sds: Variable containing the statistics of the sched_domain - * under consideration. - * @this_cpu: Cpu at which we're currently performing load-balancing. - * @imbalance: Variable to store the imbalance. - * - * Description: - * Check if we have potential to perform some power-savings balance. - * If yes, set the busiest group to be the least loaded group in the - * sched_domain, so that it's CPUs can be put to idle. - * - * Returns 1 if there is potential to perform power-savings balance. - * Else returns 0. - */ -static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, - int this_cpu, unsigned long *imbalance) -{ - if (!sds->power_savings_balance) - return 0; - - if (sds->this != sds->group_leader || - sds->group_leader == sds->group_min) - return 0; - - *imbalance = sds->min_load_per_task; - sds->busiest = sds->group_min; - - return 1; - -} -#else /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ -static inline void init_sd_power_savings_stats(struct sched_domain *sd, - struct sd_lb_stats *sds, enum cpu_idle_type idle) -{ - return; -} - -static inline void update_sd_power_savings_stats(struct sched_group *group, - struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs) -{ - return; -} - -static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, - int this_cpu, unsigned long *imbalance) -{ - return 0; -} -#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ - - -unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu) -{ - return SCHED_LOAD_SCALE; -} - -unsigned long __weak arch_scale_freq_power(struct sched_domain *sd, int cpu) -{ - return default_scale_freq_power(sd, cpu); -} - -unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu) -{ - unsigned long weight = cpumask_weight(sched_domain_span(sd)); - unsigned long smt_gain = sd->smt_gain; - - smt_gain /= weight; - - return smt_gain; -} - -unsigned long __weak arch_scale_smt_power(struct sched_domain *sd, int cpu) -{ - return default_scale_smt_power(sd, cpu); -} - -unsigned long scale_rt_power(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - u64 total, available; - - sched_avg_update(rq); - - total = sched_avg_period() + (rq->clock - rq->age_stamp); - available = total - rq->rt_avg; - - if (unlikely((s64)total < SCHED_LOAD_SCALE)) - total = SCHED_LOAD_SCALE; - - total >>= SCHED_LOAD_SHIFT; - - return div_u64(available, total); -} - -static void update_cpu_power(struct sched_domain *sd, int cpu) -{ - unsigned long weight = cpumask_weight(sched_domain_span(sd)); - unsigned long power = SCHED_LOAD_SCALE; - struct sched_group *sdg = sd->groups; - - if (sched_feat(ARCH_POWER)) - power *= arch_scale_freq_power(sd, cpu); - else - power *= default_scale_freq_power(sd, cpu); - - power >>= SCHED_LOAD_SHIFT; - - if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { - if (sched_feat(ARCH_POWER)) - power *= arch_scale_smt_power(sd, cpu); - else - power *= default_scale_smt_power(sd, cpu); - - power >>= SCHED_LOAD_SHIFT; - } - - power *= scale_rt_power(cpu); - power >>= SCHED_LOAD_SHIFT; - - if (!power) - power = 1; - - sdg->cpu_power = power; -} - -static void update_group_power(struct sched_domain *sd, int cpu) -{ - struct sched_domain *child = sd->child; - struct sched_group *group, *sdg = sd->groups; - unsigned long power; - - if (!child) { - update_cpu_power(sd, cpu); - return; - } - - power = 0; - - group = child->groups; - do { - power += group->cpu_power; - group = group->next; - } while (group != child->groups); - - sdg->cpu_power = power; -} - -/** - * update_sg_lb_stats - Update sched_group's statistics for load balancing. - * @sd: The sched_domain whose statistics are to be updated. - * @group: sched_group whose statistics are to be updated. - * @this_cpu: Cpu for which load balance is currently performed. - * @idle: Idle status of this_cpu - * @load_idx: Load index of sched_domain of this_cpu for load calc. - * @sd_idle: Idle status of the sched_domain containing group. - * @local_group: Does group contain this_cpu. - * @cpus: Set of cpus considered for load balancing. - * @balance: Should we balance. - * @sgs: variable to hold the statistics for this group. - */ -static inline void update_sg_lb_stats(struct sched_domain *sd, - struct sched_group *group, int this_cpu, - enum cpu_idle_type idle, int load_idx, int *sd_idle, - int local_group, const struct cpumask *cpus, - int *balance, struct sg_lb_stats *sgs) -{ - unsigned long load, max_cpu_load, min_cpu_load; - int i; - unsigned int balance_cpu = -1, first_idle_cpu = 0; - unsigned long sum_avg_load_per_task; - unsigned long avg_load_per_task; - - if (local_group) { - balance_cpu = group_first_cpu(group); - if (balance_cpu == this_cpu) - update_group_power(sd, this_cpu); - } - - /* Tally up the load of all CPUs in the group */ - sum_avg_load_per_task = avg_load_per_task = 0; - max_cpu_load = 0; - min_cpu_load = ~0UL; - - for_each_cpu_and(i, sched_group_cpus(group), cpus) { - struct rq *rq = cpu_rq(i); - - if (*sd_idle && rq->nr_running) - *sd_idle = 0; - - /* Bias balancing toward cpus of our domain */ - if (local_group) { - if (idle_cpu(i) && !first_idle_cpu) { - first_idle_cpu = 1; - balance_cpu = i; - } - - load = target_load(i, load_idx); - } else { - load = source_load(i, load_idx); - if (load > max_cpu_load) - max_cpu_load = load; - if (min_cpu_load > load) - min_cpu_load = load; - } - - sgs->group_load += load; - sgs->sum_nr_running += rq->nr_running; - sgs->sum_weighted_load += weighted_cpuload(i); - - sum_avg_load_per_task += cpu_avg_load_per_task(i); - } - - /* - * First idle cpu or the first cpu(busiest) in this sched group - * is eligible for doing load balancing at this and above - * domains. In the newly idle case, we will allow all the cpu's - * to do the newly idle load balance. - */ - if (idle != CPU_NEWLY_IDLE && local_group && - balance_cpu != this_cpu && balance) { - *balance = 0; - return; - } - - /* Adjust by relative CPU power of the group */ - sgs->avg_load = (sgs->group_load * SCHED_LOAD_SCALE) / group->cpu_power; - - - /* - * Consider the group unbalanced when the imbalance is larger - * than the average weight of two tasks. - * - * APZ: with cgroup the avg task weight can vary wildly and - * might not be a suitable number - should we keep a - * normalized nr_running number somewhere that negates - * the hierarchy? - */ - avg_load_per_task = (sum_avg_load_per_task * SCHED_LOAD_SCALE) / - group->cpu_power; - - if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task) - sgs->group_imb = 1; - - sgs->group_capacity = - DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE); -} - -/** - * update_sd_lb_stats - Update sched_group's statistics for load balancing. - * @sd: sched_domain whose statistics are to be updated. - * @this_cpu: Cpu for which load balance is currently performed. - * @idle: Idle status of this_cpu - * @sd_idle: Idle status of the sched_domain containing group. - * @cpus: Set of cpus considered for load balancing. - * @balance: Should we balance. - * @sds: variable to hold the statistics for this sched_domain. - */ -static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, - enum cpu_idle_type idle, int *sd_idle, - const struct cpumask *cpus, int *balance, - struct sd_lb_stats *sds) -{ - struct sched_domain *child = sd->child; - struct sched_group *group = sd->groups; - struct sg_lb_stats sgs; - int load_idx, prefer_sibling = 0; - - if (child && child->flags & SD_PREFER_SIBLING) - prefer_sibling = 1; - - init_sd_power_savings_stats(sd, sds, idle); - load_idx = get_sd_load_idx(sd, idle); - - do { - int local_group; - - local_group = cpumask_test_cpu(this_cpu, - sched_group_cpus(group)); - memset(&sgs, 0, sizeof(sgs)); - update_sg_lb_stats(sd, group, this_cpu, idle, load_idx, sd_idle, - local_group, cpus, balance, &sgs); - - if (local_group && balance && !(*balance)) - return; - - sds->total_load += sgs.group_load; - sds->total_pwr += group->cpu_power; - - /* - * In case the child domain prefers tasks go to siblings - * first, lower the group capacity to one so that we'll try - * and move all the excess tasks away. - */ - if (prefer_sibling) - sgs.group_capacity = min(sgs.group_capacity, 1UL); - - if (local_group) { - sds->this_load = sgs.avg_load; - sds->this = group; - sds->this_nr_running = sgs.sum_nr_running; - sds->this_load_per_task = sgs.sum_weighted_load; - } else if (sgs.avg_load > sds->max_load && - (sgs.sum_nr_running > sgs.group_capacity || - sgs.group_imb)) { - sds->max_load = sgs.avg_load; - sds->busiest = group; - sds->busiest_nr_running = sgs.sum_nr_running; - sds->busiest_load_per_task = sgs.sum_weighted_load; - sds->group_imb = sgs.group_imb; - } - - update_sd_power_savings_stats(group, sds, local_group, &sgs); - group = group->next; - } while (group != sd->groups); -} - -/** - * fix_small_imbalance - Calculate the minor imbalance that exists - * amongst the groups of a sched_domain, during - * load balancing. - * @sds: Statistics of the sched_domain whose imbalance is to be calculated. - * @this_cpu: The cpu at whose sched_domain we're performing load-balance. - * @imbalance: Variable to store the imbalance. - */ -static inline void fix_small_imbalance(struct sd_lb_stats *sds, - int this_cpu, unsigned long *imbalance) -{ - unsigned long tmp, pwr_now = 0, pwr_move = 0; - unsigned int imbn = 2; - - if (sds->this_nr_running) { - sds->this_load_per_task /= sds->this_nr_running; - if (sds->busiest_load_per_task > - sds->this_load_per_task) - imbn = 1; - } else - sds->this_load_per_task = - cpu_avg_load_per_task(this_cpu); - - if (sds->max_load - sds->this_load + sds->busiest_load_per_task >= - sds->busiest_load_per_task * imbn) { - *imbalance = sds->busiest_load_per_task; - return; - } - - /* - * OK, we don't have enough imbalance to justify moving tasks, - * however we may be able to increase total CPU power used by - * moving them. - */ - - pwr_now += sds->busiest->cpu_power * - min(sds->busiest_load_per_task, sds->max_load); - pwr_now += sds->this->cpu_power * - min(sds->this_load_per_task, sds->this_load); - pwr_now /= SCHED_LOAD_SCALE; - - /* Amount of load we'd subtract */ - tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / - sds->busiest->cpu_power; - if (sds->max_load > tmp) - pwr_move += sds->busiest->cpu_power * - min(sds->busiest_load_per_task, sds->max_load - tmp); - - /* Amount of load we'd add */ - if (sds->max_load * sds->busiest->cpu_power < - sds->busiest_load_per_task * SCHED_LOAD_SCALE) - tmp = (sds->max_load * sds->busiest->cpu_power) / - sds->this->cpu_power; - else - tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / - sds->this->cpu_power; - pwr_move += sds->this->cpu_power * - min(sds->this_load_per_task, sds->this_load + tmp); - pwr_move /= SCHED_LOAD_SCALE; - - /* Move if we gain throughput */ - if (pwr_move > pwr_now) - *imbalance = sds->busiest_load_per_task; -} - -/** - * calculate_imbalance - Calculate the amount of imbalance present within the - * groups of a given sched_domain during load balance. - * @sds: statistics of the sched_domain whose imbalance is to be calculated. - * @this_cpu: Cpu for which currently load balance is being performed. - * @imbalance: The variable to store the imbalance. - */ -static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, - unsigned long *imbalance) -{ - unsigned long max_pull; - /* - * In the presence of smp nice balancing, certain scenarios can have - * max load less than avg load(as we skip the groups at or below - * its cpu_power, while calculating max_load..) - */ - if (sds->max_load < sds->avg_load) { - *imbalance = 0; - return fix_small_imbalance(sds, this_cpu, imbalance); - } - - /* Don't want to pull so many tasks that a group would go idle */ - max_pull = min(sds->max_load - sds->avg_load, - sds->max_load - sds->busiest_load_per_task); - - /* How much load to actually move to equalise the imbalance */ - *imbalance = min(max_pull * sds->busiest->cpu_power, - (sds->avg_load - sds->this_load) * sds->this->cpu_power) - / SCHED_LOAD_SCALE; - - /* - * if *imbalance is less than the average load per runnable task - * there is no gaurantee that any tasks will be moved so we'll have - * a think about bumping its value to force at least one task to be - * moved - */ - if (*imbalance < sds->busiest_load_per_task) - return fix_small_imbalance(sds, this_cpu, imbalance); - -} -/******* find_busiest_group() helpers end here *********************/ - -/** - * find_busiest_group - Returns the busiest group within the sched_domain - * if there is an imbalance. If there isn't an imbalance, and - * the user has opted for power-savings, it returns a group whose - * CPUs can be put to idle by rebalancing those tasks elsewhere, if - * such a group exists. - * - * Also calculates the amount of weighted load which should be moved - * to restore balance. - * - * @sd: The sched_domain whose busiest group is to be returned. - * @this_cpu: The cpu for which load balancing is currently being performed. - * @imbalance: Variable which stores amount of weighted load which should - * be moved to restore balance/put a group to idle. - * @idle: The idle status of this_cpu. - * @sd_idle: The idleness of sd - * @cpus: The set of CPUs under consideration for load-balancing. - * @balance: Pointer to a variable indicating if this_cpu - * is the appropriate cpu to perform load balancing at this_level. - * - * Returns: - the busiest group if imbalance exists. - * - If no imbalance and user has opted for power-savings balance, - * return the least loaded group whose CPUs can be - * put to idle by rebalancing its tasks onto our group. - */ -static struct sched_group * -find_busiest_group(struct sched_domain *sd, int this_cpu, - unsigned long *imbalance, enum cpu_idle_type idle, - int *sd_idle, const struct cpumask *cpus, int *balance) -{ - struct sd_lb_stats sds; - - memset(&sds, 0, sizeof(sds)); - - /* - * Compute the various statistics relavent for load balancing at - * this level. - */ - update_sd_lb_stats(sd, this_cpu, idle, sd_idle, cpus, - balance, &sds); - - /* Cases where imbalance does not exist from POV of this_cpu */ - /* 1) this_cpu is not the appropriate cpu to perform load balancing - * at this level. - * 2) There is no busy sibling group to pull from. - * 3) This group is the busiest group. - * 4) This group is more busy than the avg busieness at this - * sched_domain. - * 5) The imbalance is within the specified limit. - * 6) Any rebalance would lead to ping-pong - */ - if (balance && !(*balance)) - goto ret; - - if (!sds.busiest || sds.busiest_nr_running == 0) - goto out_balanced; - - if (sds.this_load >= sds.max_load) - goto out_balanced; - - sds.avg_load = (SCHED_LOAD_SCALE * sds.total_load) / sds.total_pwr; - - if (sds.this_load >= sds.avg_load) - goto out_balanced; - - if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load) - goto out_balanced; - - sds.busiest_load_per_task /= sds.busiest_nr_running; - if (sds.group_imb) - sds.busiest_load_per_task = - min(sds.busiest_load_per_task, sds.avg_load); - - /* - * We're trying to get all the cpus to the average_load, so we don't - * want to push ourselves above the average load, nor do we wish to - * reduce the max loaded cpu below the average load, as either of these - * actions would just result in more rebalancing later, and ping-pong - * tasks around. Thus we look for the minimum possible imbalance. - * Negative imbalances (*we* are more loaded than anyone else) will - * be counted as no imbalance for these purposes -- we can't fix that - * by pulling tasks to us. Be careful of negative numbers as they'll - * appear as very large values with unsigned longs. - */ - if (sds.max_load <= sds.busiest_load_per_task) - goto out_balanced; - - /* Looks like there is an imbalance. Compute it */ - calculate_imbalance(&sds, this_cpu, imbalance); - return sds.busiest; - -out_balanced: - /* - * There is no obvious imbalance. But check if we can do some balancing - * to save power. - */ - if (check_power_save_busiest_group(&sds, this_cpu, imbalance)) - return sds.busiest; -ret: - *imbalance = 0; - return NULL; -} - -/* - * find_busiest_queue - find the busiest runqueue among the cpus in group. - */ -static struct rq * -find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle, - unsigned long imbalance, const struct cpumask *cpus) -{ - struct rq *busiest = NULL, *rq; - unsigned long max_load = 0; - int i; - - for_each_cpu(i, sched_group_cpus(group)) { - unsigned long power = power_of(i); - unsigned long capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE); - unsigned long wl; - - if (!cpumask_test_cpu(i, cpus)) - continue; - - rq = cpu_rq(i); - wl = weighted_cpuload(i) * SCHED_LOAD_SCALE; - wl /= power; - - if (capacity && rq->nr_running == 1 && wl > imbalance) - continue; - - if (wl > max_load) { - max_load = wl; - busiest = rq; - } - } - - return busiest; -} - -/* - * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but - * so long as it is large enough. - */ -#define MAX_PINNED_INTERVAL 512 - -/* Working cpumask for load_balance and load_balance_newidle. */ -static DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask); - -/* - * Check this_cpu to ensure it is balanced within domain. Attempt to move - * tasks if there is an imbalance. - */ -static int load_balance(int this_cpu, struct rq *this_rq, - struct sched_domain *sd, enum cpu_idle_type idle, - int *balance) -{ - int ld_moved, all_pinned = 0, active_balance = 0, sd_idle = 0; - struct sched_group *group; - unsigned long imbalance; - struct rq *busiest; - unsigned long flags; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - - cpumask_copy(cpus, cpu_active_mask); - - /* - * When power savings policy is enabled for the parent domain, idle - * sibling can pick up load irrespective of busy siblings. In this case, - * let the state of idle sibling percolate up as CPU_IDLE, instead of - * portraying it as CPU_NOT_IDLE. - */ - if (idle != CPU_NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - sd_idle = 1; - - schedstat_inc(sd, lb_count[idle]); - -redo: - update_shares(sd); - group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle, - cpus, balance); - - if (*balance == 0) - goto out_balanced; - - if (!group) { - schedstat_inc(sd, lb_nobusyg[idle]); - goto out_balanced; - } - - busiest = find_busiest_queue(group, idle, imbalance, cpus); - if (!busiest) { - schedstat_inc(sd, lb_nobusyq[idle]); - goto out_balanced; - } - - BUG_ON(busiest == this_rq); - - schedstat_add(sd, lb_imbalance[idle], imbalance); - - ld_moved = 0; - if (busiest->nr_running > 1) { - /* - * Attempt to move tasks. If find_busiest_group has found - * an imbalance but busiest->nr_running <= 1, the group is - * still unbalanced. ld_moved simply stays zero, so it is - * correctly treated as an imbalance. - */ - local_irq_save(flags); - double_rq_lock(this_rq, busiest); - ld_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, idle, &all_pinned); - double_rq_unlock(this_rq, busiest); - local_irq_restore(flags); - - /* - * some other cpu did the load balance for us. - */ - if (ld_moved && this_cpu != smp_processor_id()) - resched_cpu(this_cpu); - - /* All tasks on this runqueue were pinned by CPU affinity */ - if (unlikely(all_pinned)) { - cpumask_clear_cpu(cpu_of(busiest), cpus); - if (!cpumask_empty(cpus)) - goto redo; - goto out_balanced; - } - } - - if (!ld_moved) { - schedstat_inc(sd, lb_failed[idle]); - sd->nr_balance_failed++; - - if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) { - - raw_spin_lock_irqsave(&busiest->lock, flags); - - /* don't kick the migration_thread, if the curr - * task on busiest cpu can't be moved to this_cpu - */ - if (!cpumask_test_cpu(this_cpu, - &busiest->curr->cpus_allowed)) { - raw_spin_unlock_irqrestore(&busiest->lock, - flags); - all_pinned = 1; - goto out_one_pinned; - } - - if (!busiest->active_balance) { - busiest->active_balance = 1; - busiest->push_cpu = this_cpu; - active_balance = 1; - } - raw_spin_unlock_irqrestore(&busiest->lock, flags); - if (active_balance) - wake_up_process(busiest->migration_thread); - - /* - * We've kicked active balancing, reset the failure - * counter. - */ - sd->nr_balance_failed = sd->cache_nice_tries+1; - } - } else - sd->nr_balance_failed = 0; - - if (likely(!active_balance)) { - /* We were unbalanced, so reset the balancing interval */ - sd->balance_interval = sd->min_interval; - } else { - /* - * If we've begun active balancing, start to back off. This - * case may not be covered by the all_pinned logic if there - * is only 1 task on the busy runqueue (because we don't call - * move_tasks). - */ - if (sd->balance_interval < sd->max_interval) - sd->balance_interval *= 2; - } - - if (!ld_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - ld_moved = -1; - - goto out; - -out_balanced: - schedstat_inc(sd, lb_balanced[idle]); - - sd->nr_balance_failed = 0; - -out_one_pinned: - /* tune up the balancing interval */ - if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) || - (sd->balance_interval < sd->max_interval)) - sd->balance_interval *= 2; - - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - ld_moved = -1; - else - ld_moved = 0; -out: - if (ld_moved) - update_shares(sd); - return ld_moved; -} - -/* - * Check this_cpu to ensure it is balanced within domain. Attempt to move - * tasks if there is an imbalance. - * - * Called from schedule when this_rq is about to become idle (CPU_NEWLY_IDLE). - * this_rq is locked. - */ -static int -load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) -{ - struct sched_group *group; - struct rq *busiest = NULL; - unsigned long imbalance; - int ld_moved = 0; - int sd_idle = 0; - int all_pinned = 0; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - - cpumask_copy(cpus, cpu_active_mask); - - /* - * When power savings policy is enabled for the parent domain, idle - * sibling can pick up load irrespective of busy siblings. In this case, - * let the state of idle sibling percolate up as IDLE, instead of - * portraying it as CPU_NOT_IDLE. - */ - if (sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - sd_idle = 1; - - schedstat_inc(sd, lb_count[CPU_NEWLY_IDLE]); -redo: - update_shares_locked(this_rq, sd); - group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE, - &sd_idle, cpus, NULL); - if (!group) { - schedstat_inc(sd, lb_nobusyg[CPU_NEWLY_IDLE]); - goto out_balanced; - } - - busiest = find_busiest_queue(group, CPU_NEWLY_IDLE, imbalance, cpus); - if (!busiest) { - schedstat_inc(sd, lb_nobusyq[CPU_NEWLY_IDLE]); - goto out_balanced; - } - - BUG_ON(busiest == this_rq); - - schedstat_add(sd, lb_imbalance[CPU_NEWLY_IDLE], imbalance); - - ld_moved = 0; - if (busiest->nr_running > 1) { - /* Attempt to move tasks */ - double_lock_balance(this_rq, busiest); - /* this_rq->clock is already updated */ - update_rq_clock(busiest); - ld_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, CPU_NEWLY_IDLE, - &all_pinned); - double_unlock_balance(this_rq, busiest); - - if (unlikely(all_pinned)) { - cpumask_clear_cpu(cpu_of(busiest), cpus); - if (!cpumask_empty(cpus)) - goto redo; - } - } - - if (!ld_moved) { - int active_balance = 0; - - schedstat_inc(sd, lb_failed[CPU_NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - return -1; - - if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP) - return -1; - - if (sd->nr_balance_failed++ < 2) - return -1; - - /* - * The only task running in a non-idle cpu can be moved to this - * cpu in an attempt to completely freeup the other CPU - * package. The same method used to move task in load_balance() - * have been extended for load_balance_newidle() to speedup - * consolidation at sched_mc=POWERSAVINGS_BALANCE_WAKEUP (2) - * - * The package power saving logic comes from - * find_busiest_group(). If there are no imbalance, then - * f_b_g() will return NULL. However when sched_mc={1,2} then - * f_b_g() will select a group from which a running task may be - * pulled to this cpu in order to make the other package idle. - * If there is no opportunity to make a package idle and if - * there are no imbalance, then f_b_g() will return NULL and no - * action will be taken in load_balance_newidle(). - * - * Under normal task pull operation due to imbalance, there - * will be more than one task in the source run queue and - * move_tasks() will succeed. ld_moved will be true and this - * active balance code will not be triggered. - */ - - /* Lock busiest in correct order while this_rq is held */ - double_lock_balance(this_rq, busiest); - - /* - * don't kick the migration_thread, if the curr - * task on busiest cpu can't be moved to this_cpu - */ - if (!cpumask_test_cpu(this_cpu, &busiest->curr->cpus_allowed)) { - double_unlock_balance(this_rq, busiest); - all_pinned = 1; - return ld_moved; - } - - if (!busiest->active_balance) { - busiest->active_balance = 1; - busiest->push_cpu = this_cpu; - active_balance = 1; - } - - double_unlock_balance(this_rq, busiest); - /* - * Should not call ttwu while holding a rq->lock - */ - raw_spin_unlock(&this_rq->lock); - if (active_balance) - wake_up_process(busiest->migration_thread); - raw_spin_lock(&this_rq->lock); - - } else - sd->nr_balance_failed = 0; - - update_shares_locked(this_rq, sd); - return ld_moved; - -out_balanced: - schedstat_inc(sd, lb_balanced[CPU_NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - return -1; - sd->nr_balance_failed = 0; - - return 0; -} - -/* - * idle_balance is called by schedule() if this_cpu is about to become - * idle. Attempts to pull tasks from other CPUs. - */ -static void idle_balance(int this_cpu, struct rq *this_rq) -{ - struct sched_domain *sd; - int pulled_task = 0; - unsigned long next_balance = jiffies + HZ; - - this_rq->idle_stamp = this_rq->clock; - - if (this_rq->avg_idle < sysctl_sched_migration_cost) - return; - - for_each_domain(this_cpu, sd) { - unsigned long interval; - - if (!(sd->flags & SD_LOAD_BALANCE)) - continue; - - if (sd->flags & SD_BALANCE_NEWIDLE) - /* If we've pulled tasks over stop searching: */ - pulled_task = load_balance_newidle(this_cpu, this_rq, - sd); - - interval = msecs_to_jiffies(sd->balance_interval); - if (time_after(next_balance, sd->last_balance + interval)) - next_balance = sd->last_balance + interval; - if (pulled_task) { - this_rq->idle_stamp = 0; - break; - } - } - if (pulled_task || time_after(jiffies, this_rq->next_balance)) { - /* - * We are going idle. next_balance may be set based on - * a busy processor. So reset next_balance. - */ - this_rq->next_balance = next_balance; - } -} - -/* - * active_load_balance is run by migration threads. It pushes running tasks - * off the busiest CPU onto idle CPUs. It requires at least 1 task to be - * running on each physical CPU where possible, and avoids physical / - * logical imbalances. - * - * Called with busiest_rq locked. - */ -static void active_load_balance(struct rq *busiest_rq, int busiest_cpu) -{ - int target_cpu = busiest_rq->push_cpu; - struct sched_domain *sd; - struct rq *target_rq; - - /* Is there any task to move? */ - if (busiest_rq->nr_running <= 1) - return; - - target_rq = cpu_rq(target_cpu); - - /* - * This condition is "impossible", if it occurs - * we need to fix it. Originally reported by - * Bjorn Helgaas on a 128-cpu setup. - */ - BUG_ON(busiest_rq == target_rq); - - /* move a task from busiest_rq to target_rq */ - double_lock_balance(busiest_rq, target_rq); - update_rq_clock(busiest_rq); - update_rq_clock(target_rq); - - /* Search for an sd spanning us and the target CPU. */ - for_each_domain(target_cpu, sd) { - if ((sd->flags & SD_LOAD_BALANCE) && - cpumask_test_cpu(busiest_cpu, sched_domain_span(sd))) - break; - } - - if (likely(sd)) { - schedstat_inc(sd, alb_count); - - if (move_one_task(target_rq, target_cpu, busiest_rq, - sd, CPU_IDLE)) - schedstat_inc(sd, alb_pushed); - else - schedstat_inc(sd, alb_failed); - } - double_unlock_balance(busiest_rq, target_rq); -} - -#ifdef CONFIG_NO_HZ -static struct { - atomic_t load_balancer; - cpumask_var_t cpu_mask; - cpumask_var_t ilb_grp_nohz_mask; -} nohz ____cacheline_aligned = { - .load_balancer = ATOMIC_INIT(-1), -}; - -int get_nohz_load_balancer(void) -{ - return atomic_read(&nohz.load_balancer); -} - -#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) -/** - * lowest_flag_domain - Return lowest sched_domain containing flag. - * @cpu: The cpu whose lowest level of sched domain is to - * be returned. - * @flag: The flag to check for the lowest sched_domain - * for the given cpu. - * - * Returns the lowest sched_domain of a cpu which contains the given flag. - */ -static inline struct sched_domain *lowest_flag_domain(int cpu, int flag) -{ - struct sched_domain *sd; - - for_each_domain(cpu, sd) - if (sd && (sd->flags & flag)) - break; - - return sd; -} - -/** - * for_each_flag_domain - Iterates over sched_domains containing the flag. - * @cpu: The cpu whose domains we're iterating over. - * @sd: variable holding the value of the power_savings_sd - * for cpu. - * @flag: The flag to filter the sched_domains to be iterated. - * - * Iterates over all the scheduler domains for a given cpu that has the 'flag' - * set, starting from the lowest sched_domain to the highest. - */ -#define for_each_flag_domain(cpu, sd, flag) \ - for (sd = lowest_flag_domain(cpu, flag); \ - (sd && (sd->flags & flag)); sd = sd->parent) - -/** - * is_semi_idle_group - Checks if the given sched_group is semi-idle. - * @ilb_group: group to be checked for semi-idleness - * - * Returns: 1 if the group is semi-idle. 0 otherwise. - * - * We define a sched_group to be semi idle if it has atleast one idle-CPU - * and atleast one non-idle CPU. This helper function checks if the given - * sched_group is semi-idle or not. - */ -static inline int is_semi_idle_group(struct sched_group *ilb_group) -{ - cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask, - sched_group_cpus(ilb_group)); - - /* - * A sched_group is semi-idle when it has atleast one busy cpu - * and atleast one idle cpu. - */ - if (cpumask_empty(nohz.ilb_grp_nohz_mask)) - return 0; - - if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group))) - return 0; - - return 1; -} -/** - * find_new_ilb - Finds the optimum idle load balancer for nomination. - * @cpu: The cpu which is nominating a new idle_load_balancer. - * - * Returns: Returns the id of the idle load balancer if it exists, - * Else, returns >= nr_cpu_ids. - * - * This algorithm picks the idle load balancer such that it belongs to a - * semi-idle powersavings sched_domain. The idea is to try and avoid - * completely idle packages/cores just for the purpose of idle load balancing - * when there are other idle cpu's which are better suited for that job. - */ -static int find_new_ilb(int cpu) -{ - struct sched_domain *sd; - struct sched_group *ilb_group; - - /* - * Have idle load balancer selection from semi-idle packages only - * when power-aware load balancing is enabled - */ - if (!(sched_smt_power_savings || sched_mc_power_savings)) - goto out_done; - - /* - * Optimize for the case when we have no idle CPUs or only one - * idle CPU. Don't walk the sched_domain hierarchy in such cases - */ - if (cpumask_weight(nohz.cpu_mask) < 2) - goto out_done; - - for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) { - ilb_group = sd->groups; - - do { - if (is_semi_idle_group(ilb_group)) - return cpumask_first(nohz.ilb_grp_nohz_mask); - - ilb_group = ilb_group->next; - - } while (ilb_group != sd->groups); - } - -out_done: - return cpumask_first(nohz.cpu_mask); -} -#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ -static inline int find_new_ilb(int call_cpu) -{ - return cpumask_first(nohz.cpu_mask); -} -#endif - -/* - * This routine will try to nominate the ilb (idle load balancing) - * owner among the cpus whose ticks are stopped. ilb owner will do the idle - * load balancing on behalf of all those cpus. If all the cpus in the system - * go into this tickless mode, then there will be no ilb owner (as there is - * no need for one) and all the cpus will sleep till the next wakeup event - * arrives... - * - * For the ilb owner, tick is not stopped. And this tick will be used - * for idle load balancing. ilb owner will still be part of - * nohz.cpu_mask.. - * - * While stopping the tick, this cpu will become the ilb owner if there - * is no other owner. And will be the owner till that cpu becomes busy - * or if all cpus in the system stop their ticks at which point - * there is no need for ilb owner. - * - * When the ilb owner becomes busy, it nominates another owner, during the - * next busy scheduler_tick() - */ -int select_nohz_load_balancer(int stop_tick) -{ - int cpu = smp_processor_id(); - - if (stop_tick) { - cpu_rq(cpu)->in_nohz_recently = 1; - - if (!cpu_active(cpu)) { - if (atomic_read(&nohz.load_balancer) != cpu) - return 0; - - /* - * If we are going offline and still the leader, - * give up! - */ - if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) - BUG(); - - return 0; - } - - cpumask_set_cpu(cpu, nohz.cpu_mask); - - /* time for ilb owner also to sleep */ - if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) { - if (atomic_read(&nohz.load_balancer) == cpu) - atomic_set(&nohz.load_balancer, -1); - return 0; - } - - if (atomic_read(&nohz.load_balancer) == -1) { - /* make me the ilb owner */ - if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1) - return 1; - } else if (atomic_read(&nohz.load_balancer) == cpu) { - int new_ilb; - - if (!(sched_smt_power_savings || - sched_mc_power_savings)) - return 1; - /* - * Check to see if there is a more power-efficient - * ilb. - */ - new_ilb = find_new_ilb(cpu); - if (new_ilb < nr_cpu_ids && new_ilb != cpu) { - atomic_set(&nohz.load_balancer, -1); - resched_cpu(new_ilb); - return 0; - } - return 1; - } - } else { - if (!cpumask_test_cpu(cpu, nohz.cpu_mask)) - return 0; - - cpumask_clear_cpu(cpu, nohz.cpu_mask); - - if (atomic_read(&nohz.load_balancer) == cpu) - if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) - BUG(); - } - return 0; -} -#endif - -static DEFINE_SPINLOCK(balancing); - -/* - * It checks each scheduling domain to see if it is due to be balanced, - * and initiates a balancing operation if so. - * - * Balancing parameters are set up in arch_init_sched_domains. - */ -static void rebalance_domains(int cpu, enum cpu_idle_type idle) -{ - int balance = 1; - struct rq *rq = cpu_rq(cpu); - unsigned long interval; - struct sched_domain *sd; - /* Earliest time when we have to do rebalance again */ - unsigned long next_balance = jiffies + 60*HZ; - int update_next_balance = 0; - int need_serialize; - - for_each_domain(cpu, sd) { - if (!(sd->flags & SD_LOAD_BALANCE)) - continue; - - interval = sd->balance_interval; - if (idle != CPU_IDLE) - interval *= sd->busy_factor; - - /* scale ms to jiffies */ - interval = msecs_to_jiffies(interval); - if (unlikely(!interval)) - interval = 1; - if (interval > HZ*NR_CPUS/10) - interval = HZ*NR_CPUS/10; - - need_serialize = sd->flags & SD_SERIALIZE; - - if (need_serialize) { - if (!spin_trylock(&balancing)) - goto out; - } - - if (time_after_eq(jiffies, sd->last_balance + interval)) { - if (load_balance(cpu, rq, sd, idle, &balance)) { - /* - * We've pulled tasks over so either we're no - * longer idle, or one of our SMT siblings is - * not idle. - */ - idle = CPU_NOT_IDLE; - } - sd->last_balance = jiffies; - } - if (need_serialize) - spin_unlock(&balancing); -out: - if (time_after(next_balance, sd->last_balance + interval)) { - next_balance = sd->last_balance + interval; - update_next_balance = 1; - } - - /* - * Stop the load balance at this level. There is another - * CPU in our sched group which is doing load balancing more - * actively. - */ - if (!balance) - break; - } - - /* - * next_balance will be updated only when there is a need. - * When the cpu is attached to null domain for ex, it will not be - * updated. - */ - if (likely(update_next_balance)) - rq->next_balance = next_balance; -} - -/* - * run_rebalance_domains is triggered when needed from the scheduler tick. - * In CONFIG_NO_HZ case, the idle load balance owner will do the - * rebalancing for all the cpus for whom scheduler ticks are stopped. - */ -static void run_rebalance_domains(struct softirq_action *h) -{ - int this_cpu = smp_processor_id(); - struct rq *this_rq = cpu_rq(this_cpu); - enum cpu_idle_type idle = this_rq->idle_at_tick ? - CPU_IDLE : CPU_NOT_IDLE; - - rebalance_domains(this_cpu, idle); - -#ifdef CONFIG_NO_HZ - /* - * If this cpu is the owner for idle load balancing, then do the - * balancing on behalf of the other idle cpus whose ticks are - * stopped. - */ - if (this_rq->idle_at_tick && - atomic_read(&nohz.load_balancer) == this_cpu) { - struct rq *rq; - int balance_cpu; - - for_each_cpu(balance_cpu, nohz.cpu_mask) { - if (balance_cpu == this_cpu) - continue; - - /* - * If this cpu gets work to do, stop the load balancing - * work being done for other cpus. Next load - * balancing owner will pick it up. - */ - if (need_resched()) - break; - - rebalance_domains(balance_cpu, CPU_IDLE); - - rq = cpu_rq(balance_cpu); - if (time_after(this_rq->next_balance, rq->next_balance)) - this_rq->next_balance = rq->next_balance; - } - } -#endif -} - -static inline int on_null_domain(int cpu) -{ - return !rcu_dereference(cpu_rq(cpu)->sd); -} - -/* - * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing. - * - * In case of CONFIG_NO_HZ, this is the place where we nominate a new - * idle load balancing owner or decide to stop the periodic load balancing, - * if the whole system is idle. - */ -static inline void trigger_load_balance(struct rq *rq, int cpu) -{ -#ifdef CONFIG_NO_HZ - /* - * If we were in the nohz mode recently and busy at the current - * scheduler tick, then check if we need to nominate new idle - * load balancer. - */ - if (rq->in_nohz_recently && !rq->idle_at_tick) { - rq->in_nohz_recently = 0; - - if (atomic_read(&nohz.load_balancer) == cpu) { - cpumask_clear_cpu(cpu, nohz.cpu_mask); - atomic_set(&nohz.load_balancer, -1); - } - - if (atomic_read(&nohz.load_balancer) == -1) { - int ilb = find_new_ilb(cpu); - - if (ilb < nr_cpu_ids) - resched_cpu(ilb); - } - } - - /* - * If this cpu is idle and doing idle load balancing for all the - * cpus with ticks stopped, is it time for that to stop? - */ - if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu && - cpumask_weight(nohz.cpu_mask) == num_online_cpus()) { - resched_cpu(cpu); - return; - } - - /* - * If this cpu is idle and the idle load balancing is done by - * someone else, then no need raise the SCHED_SOFTIRQ - */ - if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu && - cpumask_test_cpu(cpu, nohz.cpu_mask)) - return; -#endif - /* Don't need to rebalance while attached to NULL domain */ - if (time_after_eq(jiffies, rq->next_balance) && - likely(!on_null_domain(cpu))) - raise_softirq(SCHED_SOFTIRQ); -} - -#else /* CONFIG_SMP */ - -/* - * on UP we do not need to balance between CPUs: - */ -static inline void idle_balance(int cpu, struct rq *rq) -{ -} - #endif DEFINE_PER_CPU(struct kernel_stat, kstat); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 71778601c103..5116b81d7727 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1952,6 +1952,1762 @@ move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, return 0; } +/* + * pull_task - move a task from a remote runqueue to the local runqueue. + * Both runqueues must be locked. + */ +static void pull_task(struct rq *src_rq, struct task_struct *p, + struct rq *this_rq, int this_cpu) +{ + deactivate_task(src_rq, p, 0); + set_task_cpu(p, this_cpu); + activate_task(this_rq, p, 0); + check_preempt_curr(this_rq, p, 0); +} + +/* + * can_migrate_task - may task p from runqueue rq be migrated to this_cpu? + */ +static +int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu, + struct sched_domain *sd, enum cpu_idle_type idle, + int *all_pinned) +{ + int tsk_cache_hot = 0; + /* + * We do not migrate tasks that are: + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. + */ + if (!cpumask_test_cpu(this_cpu, &p->cpus_allowed)) { + schedstat_inc(p, se.nr_failed_migrations_affine); + return 0; + } + *all_pinned = 0; + + if (task_running(rq, p)) { + schedstat_inc(p, se.nr_failed_migrations_running); + return 0; + } + + /* + * Aggressive migration if: + * 1) task is cache cold, or + * 2) too many balance attempts have failed. + */ + + tsk_cache_hot = task_hot(p, rq->clock, sd); + if (!tsk_cache_hot || + sd->nr_balance_failed > sd->cache_nice_tries) { +#ifdef CONFIG_SCHEDSTATS + if (tsk_cache_hot) { + schedstat_inc(sd, lb_hot_gained[idle]); + schedstat_inc(p, se.nr_forced_migrations); + } +#endif + return 1; + } + + if (tsk_cache_hot) { + schedstat_inc(p, se.nr_failed_migrations_hot); + return 0; + } + return 1; +} + +static unsigned long +balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, + unsigned long max_load_move, struct sched_domain *sd, + enum cpu_idle_type idle, int *all_pinned, + int *this_best_prio, struct rq_iterator *iterator) +{ + int loops = 0, pulled = 0, pinned = 0; + struct task_struct *p; + long rem_load_move = max_load_move; + + if (max_load_move == 0) + goto out; + + pinned = 1; + + /* + * Start the load-balancing iterator: + */ + p = iterator->start(iterator->arg); +next: + if (!p || loops++ > sysctl_sched_nr_migrate) + goto out; + + if ((p->se.load.weight >> 1) > rem_load_move || + !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { + p = iterator->next(iterator->arg); + goto next; + } + + pull_task(busiest, p, this_rq, this_cpu); + pulled++; + rem_load_move -= p->se.load.weight; + +#ifdef CONFIG_PREEMPT + /* + * NEWIDLE balancing is a source of latency, so preemptible kernels + * will stop after the first task is pulled to minimize the critical + * section. + */ + if (idle == CPU_NEWLY_IDLE) + goto out; +#endif + + /* + * We only want to steal up to the prescribed amount of weighted load. + */ + if (rem_load_move > 0) { + if (p->prio < *this_best_prio) + *this_best_prio = p->prio; + p = iterator->next(iterator->arg); + goto next; + } +out: + /* + * Right now, this is one of only two places pull_task() is called, + * so we can safely collect pull_task() stats here rather than + * inside pull_task(). + */ + schedstat_add(sd, lb_gained[idle], pulled); + + if (all_pinned) + *all_pinned = pinned; + + return max_load_move - rem_load_move; +} + +/* + * move_tasks tries to move up to max_load_move weighted load from busiest to + * this_rq, as part of a balancing operation within domain "sd". + * Returns 1 if successful and 0 otherwise. + * + * Called with both runqueues locked. + */ +static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, + unsigned long max_load_move, + struct sched_domain *sd, enum cpu_idle_type idle, + int *all_pinned) +{ + const struct sched_class *class = sched_class_highest; + unsigned long total_load_moved = 0; + int this_best_prio = this_rq->curr->prio; + + do { + total_load_moved += + class->load_balance(this_rq, this_cpu, busiest, + max_load_move - total_load_moved, + sd, idle, all_pinned, &this_best_prio); + class = class->next; + +#ifdef CONFIG_PREEMPT + /* + * NEWIDLE balancing is a source of latency, so preemptible + * kernels will stop after the first task is pulled to minimize + * the critical section. + */ + if (idle == CPU_NEWLY_IDLE && this_rq->nr_running) + break; +#endif + } while (class && max_load_move > total_load_moved); + + return total_load_moved > 0; +} + +static int +iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle, + struct rq_iterator *iterator) +{ + struct task_struct *p = iterator->start(iterator->arg); + int pinned = 0; + + while (p) { + if (can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { + pull_task(busiest, p, this_rq, this_cpu); + /* + * Right now, this is only the second place pull_task() + * is called, so we can safely collect pull_task() + * stats here rather than inside pull_task(). + */ + schedstat_inc(sd, lb_gained[idle]); + + return 1; + } + p = iterator->next(iterator->arg); + } + + return 0; +} + +/* + * move_one_task tries to move exactly one task from busiest to this_rq, as + * part of active balancing operations within "domain". + * Returns 1 if successful and 0 otherwise. + * + * Called with both runqueues locked. + */ +static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle) +{ + const struct sched_class *class; + + for_each_class(class) { + if (class->move_one_task(this_rq, this_cpu, busiest, sd, idle)) + return 1; + } + + return 0; +} +/********** Helpers for find_busiest_group ************************/ +/* + * sd_lb_stats - Structure to store the statistics of a sched_domain + * during load balancing. + */ +struct sd_lb_stats { + struct sched_group *busiest; /* Busiest group in this sd */ + struct sched_group *this; /* Local group in this sd */ + unsigned long total_load; /* Total load of all groups in sd */ + unsigned long total_pwr; /* Total power of all groups in sd */ + unsigned long avg_load; /* Average load across all groups in sd */ + + /** Statistics of this group */ + unsigned long this_load; + unsigned long this_load_per_task; + unsigned long this_nr_running; + + /* Statistics of the busiest group */ + unsigned long max_load; + unsigned long busiest_load_per_task; + unsigned long busiest_nr_running; + + int group_imb; /* Is there imbalance in this sd */ +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) + int power_savings_balance; /* Is powersave balance needed for this sd */ + struct sched_group *group_min; /* Least loaded group in sd */ + struct sched_group *group_leader; /* Group which relieves group_min */ + unsigned long min_load_per_task; /* load_per_task in group_min */ + unsigned long leader_nr_running; /* Nr running of group_leader */ + unsigned long min_nr_running; /* Nr running of group_min */ +#endif +}; + +/* + * sg_lb_stats - stats of a sched_group required for load_balancing + */ +struct sg_lb_stats { + unsigned long avg_load; /*Avg load across the CPUs of the group */ + unsigned long group_load; /* Total load over the CPUs of the group */ + unsigned long sum_nr_running; /* Nr tasks running in the group */ + unsigned long sum_weighted_load; /* Weighted load of group's tasks */ + unsigned long group_capacity; + int group_imb; /* Is there an imbalance in the group ? */ +}; + +/** + * group_first_cpu - Returns the first cpu in the cpumask of a sched_group. + * @group: The group whose first cpu is to be returned. + */ +static inline unsigned int group_first_cpu(struct sched_group *group) +{ + return cpumask_first(sched_group_cpus(group)); +} + +/** + * get_sd_load_idx - Obtain the load index for a given sched domain. + * @sd: The sched_domain whose load_idx is to be obtained. + * @idle: The Idle status of the CPU for whose sd load_icx is obtained. + */ +static inline int get_sd_load_idx(struct sched_domain *sd, + enum cpu_idle_type idle) +{ + int load_idx; + + switch (idle) { + case CPU_NOT_IDLE: + load_idx = sd->busy_idx; + break; + + case CPU_NEWLY_IDLE: + load_idx = sd->newidle_idx; + break; + default: + load_idx = sd->idle_idx; + break; + } + + return load_idx; +} + + +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) +/** + * init_sd_power_savings_stats - Initialize power savings statistics for + * the given sched_domain, during load balancing. + * + * @sd: Sched domain whose power-savings statistics are to be initialized. + * @sds: Variable containing the statistics for sd. + * @idle: Idle status of the CPU at which we're performing load-balancing. + */ +static inline void init_sd_power_savings_stats(struct sched_domain *sd, + struct sd_lb_stats *sds, enum cpu_idle_type idle) +{ + /* + * Busy processors will not participate in power savings + * balance. + */ + if (idle == CPU_NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE)) + sds->power_savings_balance = 0; + else { + sds->power_savings_balance = 1; + sds->min_nr_running = ULONG_MAX; + sds->leader_nr_running = 0; + } +} + +/** + * update_sd_power_savings_stats - Update the power saving stats for a + * sched_domain while performing load balancing. + * + * @group: sched_group belonging to the sched_domain under consideration. + * @sds: Variable containing the statistics of the sched_domain + * @local_group: Does group contain the CPU for which we're performing + * load balancing ? + * @sgs: Variable containing the statistics of the group. + */ +static inline void update_sd_power_savings_stats(struct sched_group *group, + struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs) +{ + + if (!sds->power_savings_balance) + return; + + /* + * If the local group is idle or completely loaded + * no need to do power savings balance at this domain + */ + if (local_group && (sds->this_nr_running >= sgs->group_capacity || + !sds->this_nr_running)) + sds->power_savings_balance = 0; + + /* + * If a group is already running at full capacity or idle, + * don't include that group in power savings calculations + */ + if (!sds->power_savings_balance || + sgs->sum_nr_running >= sgs->group_capacity || + !sgs->sum_nr_running) + return; + + /* + * Calculate the group which has the least non-idle load. + * This is the group from where we need to pick up the load + * for saving power + */ + if ((sgs->sum_nr_running < sds->min_nr_running) || + (sgs->sum_nr_running == sds->min_nr_running && + group_first_cpu(group) > group_first_cpu(sds->group_min))) { + sds->group_min = group; + sds->min_nr_running = sgs->sum_nr_running; + sds->min_load_per_task = sgs->sum_weighted_load / + sgs->sum_nr_running; + } + + /* + * Calculate the group which is almost near its + * capacity but still has some space to pick up some load + * from other group and save more power + */ + if (sgs->sum_nr_running + 1 > sgs->group_capacity) + return; + + if (sgs->sum_nr_running > sds->leader_nr_running || + (sgs->sum_nr_running == sds->leader_nr_running && + group_first_cpu(group) < group_first_cpu(sds->group_leader))) { + sds->group_leader = group; + sds->leader_nr_running = sgs->sum_nr_running; + } +} + +/** + * check_power_save_busiest_group - see if there is potential for some power-savings balance + * @sds: Variable containing the statistics of the sched_domain + * under consideration. + * @this_cpu: Cpu at which we're currently performing load-balancing. + * @imbalance: Variable to store the imbalance. + * + * Description: + * Check if we have potential to perform some power-savings balance. + * If yes, set the busiest group to be the least loaded group in the + * sched_domain, so that it's CPUs can be put to idle. + * + * Returns 1 if there is potential to perform power-savings balance. + * Else returns 0. + */ +static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, + int this_cpu, unsigned long *imbalance) +{ + if (!sds->power_savings_balance) + return 0; + + if (sds->this != sds->group_leader || + sds->group_leader == sds->group_min) + return 0; + + *imbalance = sds->min_load_per_task; + sds->busiest = sds->group_min; + + return 1; + +} +#else /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ +static inline void init_sd_power_savings_stats(struct sched_domain *sd, + struct sd_lb_stats *sds, enum cpu_idle_type idle) +{ + return; +} + +static inline void update_sd_power_savings_stats(struct sched_group *group, + struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs) +{ + return; +} + +static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, + int this_cpu, unsigned long *imbalance) +{ + return 0; +} +#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ + + +unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu) +{ + return SCHED_LOAD_SCALE; +} + +unsigned long __weak arch_scale_freq_power(struct sched_domain *sd, int cpu) +{ + return default_scale_freq_power(sd, cpu); +} + +unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu) +{ + unsigned long weight = cpumask_weight(sched_domain_span(sd)); + unsigned long smt_gain = sd->smt_gain; + + smt_gain /= weight; + + return smt_gain; +} + +unsigned long __weak arch_scale_smt_power(struct sched_domain *sd, int cpu) +{ + return default_scale_smt_power(sd, cpu); +} + +unsigned long scale_rt_power(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + u64 total, available; + + sched_avg_update(rq); + + total = sched_avg_period() + (rq->clock - rq->age_stamp); + available = total - rq->rt_avg; + + if (unlikely((s64)total < SCHED_LOAD_SCALE)) + total = SCHED_LOAD_SCALE; + + total >>= SCHED_LOAD_SHIFT; + + return div_u64(available, total); +} + +static void update_cpu_power(struct sched_domain *sd, int cpu) +{ + unsigned long weight = cpumask_weight(sched_domain_span(sd)); + unsigned long power = SCHED_LOAD_SCALE; + struct sched_group *sdg = sd->groups; + + if (sched_feat(ARCH_POWER)) + power *= arch_scale_freq_power(sd, cpu); + else + power *= default_scale_freq_power(sd, cpu); + + power >>= SCHED_LOAD_SHIFT; + + if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { + if (sched_feat(ARCH_POWER)) + power *= arch_scale_smt_power(sd, cpu); + else + power *= default_scale_smt_power(sd, cpu); + + power >>= SCHED_LOAD_SHIFT; + } + + power *= scale_rt_power(cpu); + power >>= SCHED_LOAD_SHIFT; + + if (!power) + power = 1; + + sdg->cpu_power = power; +} + +static void update_group_power(struct sched_domain *sd, int cpu) +{ + struct sched_domain *child = sd->child; + struct sched_group *group, *sdg = sd->groups; + unsigned long power; + + if (!child) { + update_cpu_power(sd, cpu); + return; + } + + power = 0; + + group = child->groups; + do { + power += group->cpu_power; + group = group->next; + } while (group != child->groups); + + sdg->cpu_power = power; +} + +/** + * update_sg_lb_stats - Update sched_group's statistics for load balancing. + * @sd: The sched_domain whose statistics are to be updated. + * @group: sched_group whose statistics are to be updated. + * @this_cpu: Cpu for which load balance is currently performed. + * @idle: Idle status of this_cpu + * @load_idx: Load index of sched_domain of this_cpu for load calc. + * @sd_idle: Idle status of the sched_domain containing group. + * @local_group: Does group contain this_cpu. + * @cpus: Set of cpus considered for load balancing. + * @balance: Should we balance. + * @sgs: variable to hold the statistics for this group. + */ +static inline void update_sg_lb_stats(struct sched_domain *sd, + struct sched_group *group, int this_cpu, + enum cpu_idle_type idle, int load_idx, int *sd_idle, + int local_group, const struct cpumask *cpus, + int *balance, struct sg_lb_stats *sgs) +{ + unsigned long load, max_cpu_load, min_cpu_load; + int i; + unsigned int balance_cpu = -1, first_idle_cpu = 0; + unsigned long sum_avg_load_per_task; + unsigned long avg_load_per_task; + + if (local_group) { + balance_cpu = group_first_cpu(group); + if (balance_cpu == this_cpu) + update_group_power(sd, this_cpu); + } + + /* Tally up the load of all CPUs in the group */ + sum_avg_load_per_task = avg_load_per_task = 0; + max_cpu_load = 0; + min_cpu_load = ~0UL; + + for_each_cpu_and(i, sched_group_cpus(group), cpus) { + struct rq *rq = cpu_rq(i); + + if (*sd_idle && rq->nr_running) + *sd_idle = 0; + + /* Bias balancing toward cpus of our domain */ + if (local_group) { + if (idle_cpu(i) && !first_idle_cpu) { + first_idle_cpu = 1; + balance_cpu = i; + } + + load = target_load(i, load_idx); + } else { + load = source_load(i, load_idx); + if (load > max_cpu_load) + max_cpu_load = load; + if (min_cpu_load > load) + min_cpu_load = load; + } + + sgs->group_load += load; + sgs->sum_nr_running += rq->nr_running; + sgs->sum_weighted_load += weighted_cpuload(i); + + sum_avg_load_per_task += cpu_avg_load_per_task(i); + } + + /* + * First idle cpu or the first cpu(busiest) in this sched group + * is eligible for doing load balancing at this and above + * domains. In the newly idle case, we will allow all the cpu's + * to do the newly idle load balance. + */ + if (idle != CPU_NEWLY_IDLE && local_group && + balance_cpu != this_cpu && balance) { + *balance = 0; + return; + } + + /* Adjust by relative CPU power of the group */ + sgs->avg_load = (sgs->group_load * SCHED_LOAD_SCALE) / group->cpu_power; + + + /* + * Consider the group unbalanced when the imbalance is larger + * than the average weight of two tasks. + * + * APZ: with cgroup the avg task weight can vary wildly and + * might not be a suitable number - should we keep a + * normalized nr_running number somewhere that negates + * the hierarchy? + */ + avg_load_per_task = (sum_avg_load_per_task * SCHED_LOAD_SCALE) / + group->cpu_power; + + if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task) + sgs->group_imb = 1; + + sgs->group_capacity = + DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE); +} + +/** + * update_sd_lb_stats - Update sched_group's statistics for load balancing. + * @sd: sched_domain whose statistics are to be updated. + * @this_cpu: Cpu for which load balance is currently performed. + * @idle: Idle status of this_cpu + * @sd_idle: Idle status of the sched_domain containing group. + * @cpus: Set of cpus considered for load balancing. + * @balance: Should we balance. + * @sds: variable to hold the statistics for this sched_domain. + */ +static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, + enum cpu_idle_type idle, int *sd_idle, + const struct cpumask *cpus, int *balance, + struct sd_lb_stats *sds) +{ + struct sched_domain *child = sd->child; + struct sched_group *group = sd->groups; + struct sg_lb_stats sgs; + int load_idx, prefer_sibling = 0; + + if (child && child->flags & SD_PREFER_SIBLING) + prefer_sibling = 1; + + init_sd_power_savings_stats(sd, sds, idle); + load_idx = get_sd_load_idx(sd, idle); + + do { + int local_group; + + local_group = cpumask_test_cpu(this_cpu, + sched_group_cpus(group)); + memset(&sgs, 0, sizeof(sgs)); + update_sg_lb_stats(sd, group, this_cpu, idle, load_idx, sd_idle, + local_group, cpus, balance, &sgs); + + if (local_group && balance && !(*balance)) + return; + + sds->total_load += sgs.group_load; + sds->total_pwr += group->cpu_power; + + /* + * In case the child domain prefers tasks go to siblings + * first, lower the group capacity to one so that we'll try + * and move all the excess tasks away. + */ + if (prefer_sibling) + sgs.group_capacity = min(sgs.group_capacity, 1UL); + + if (local_group) { + sds->this_load = sgs.avg_load; + sds->this = group; + sds->this_nr_running = sgs.sum_nr_running; + sds->this_load_per_task = sgs.sum_weighted_load; + } else if (sgs.avg_load > sds->max_load && + (sgs.sum_nr_running > sgs.group_capacity || + sgs.group_imb)) { + sds->max_load = sgs.avg_load; + sds->busiest = group; + sds->busiest_nr_running = sgs.sum_nr_running; + sds->busiest_load_per_task = sgs.sum_weighted_load; + sds->group_imb = sgs.group_imb; + } + + update_sd_power_savings_stats(group, sds, local_group, &sgs); + group = group->next; + } while (group != sd->groups); +} + +/** + * fix_small_imbalance - Calculate the minor imbalance that exists + * amongst the groups of a sched_domain, during + * load balancing. + * @sds: Statistics of the sched_domain whose imbalance is to be calculated. + * @this_cpu: The cpu at whose sched_domain we're performing load-balance. + * @imbalance: Variable to store the imbalance. + */ +static inline void fix_small_imbalance(struct sd_lb_stats *sds, + int this_cpu, unsigned long *imbalance) +{ + unsigned long tmp, pwr_now = 0, pwr_move = 0; + unsigned int imbn = 2; + + if (sds->this_nr_running) { + sds->this_load_per_task /= sds->this_nr_running; + if (sds->busiest_load_per_task > + sds->this_load_per_task) + imbn = 1; + } else + sds->this_load_per_task = + cpu_avg_load_per_task(this_cpu); + + if (sds->max_load - sds->this_load + sds->busiest_load_per_task >= + sds->busiest_load_per_task * imbn) { + *imbalance = sds->busiest_load_per_task; + return; + } + + /* + * OK, we don't have enough imbalance to justify moving tasks, + * however we may be able to increase total CPU power used by + * moving them. + */ + + pwr_now += sds->busiest->cpu_power * + min(sds->busiest_load_per_task, sds->max_load); + pwr_now += sds->this->cpu_power * + min(sds->this_load_per_task, sds->this_load); + pwr_now /= SCHED_LOAD_SCALE; + + /* Amount of load we'd subtract */ + tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / + sds->busiest->cpu_power; + if (sds->max_load > tmp) + pwr_move += sds->busiest->cpu_power * + min(sds->busiest_load_per_task, sds->max_load - tmp); + + /* Amount of load we'd add */ + if (sds->max_load * sds->busiest->cpu_power < + sds->busiest_load_per_task * SCHED_LOAD_SCALE) + tmp = (sds->max_load * sds->busiest->cpu_power) / + sds->this->cpu_power; + else + tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / + sds->this->cpu_power; + pwr_move += sds->this->cpu_power * + min(sds->this_load_per_task, sds->this_load + tmp); + pwr_move /= SCHED_LOAD_SCALE; + + /* Move if we gain throughput */ + if (pwr_move > pwr_now) + *imbalance = sds->busiest_load_per_task; +} + +/** + * calculate_imbalance - Calculate the amount of imbalance present within the + * groups of a given sched_domain during load balance. + * @sds: statistics of the sched_domain whose imbalance is to be calculated. + * @this_cpu: Cpu for which currently load balance is being performed. + * @imbalance: The variable to store the imbalance. + */ +static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, + unsigned long *imbalance) +{ + unsigned long max_pull; + /* + * In the presence of smp nice balancing, certain scenarios can have + * max load less than avg load(as we skip the groups at or below + * its cpu_power, while calculating max_load..) + */ + if (sds->max_load < sds->avg_load) { + *imbalance = 0; + return fix_small_imbalance(sds, this_cpu, imbalance); + } + + /* Don't want to pull so many tasks that a group would go idle */ + max_pull = min(sds->max_load - sds->avg_load, + sds->max_load - sds->busiest_load_per_task); + + /* How much load to actually move to equalise the imbalance */ + *imbalance = min(max_pull * sds->busiest->cpu_power, + (sds->avg_load - sds->this_load) * sds->this->cpu_power) + / SCHED_LOAD_SCALE; + + /* + * if *imbalance is less than the average load per runnable task + * there is no gaurantee that any tasks will be moved so we'll have + * a think about bumping its value to force at least one task to be + * moved + */ + if (*imbalance < sds->busiest_load_per_task) + return fix_small_imbalance(sds, this_cpu, imbalance); + +} +/******* find_busiest_group() helpers end here *********************/ + +/** + * find_busiest_group - Returns the busiest group within the sched_domain + * if there is an imbalance. If there isn't an imbalance, and + * the user has opted for power-savings, it returns a group whose + * CPUs can be put to idle by rebalancing those tasks elsewhere, if + * such a group exists. + * + * Also calculates the amount of weighted load which should be moved + * to restore balance. + * + * @sd: The sched_domain whose busiest group is to be returned. + * @this_cpu: The cpu for which load balancing is currently being performed. + * @imbalance: Variable which stores amount of weighted load which should + * be moved to restore balance/put a group to idle. + * @idle: The idle status of this_cpu. + * @sd_idle: The idleness of sd + * @cpus: The set of CPUs under consideration for load-balancing. + * @balance: Pointer to a variable indicating if this_cpu + * is the appropriate cpu to perform load balancing at this_level. + * + * Returns: - the busiest group if imbalance exists. + * - If no imbalance and user has opted for power-savings balance, + * return the least loaded group whose CPUs can be + * put to idle by rebalancing its tasks onto our group. + */ +static struct sched_group * +find_busiest_group(struct sched_domain *sd, int this_cpu, + unsigned long *imbalance, enum cpu_idle_type idle, + int *sd_idle, const struct cpumask *cpus, int *balance) +{ + struct sd_lb_stats sds; + + memset(&sds, 0, sizeof(sds)); + + /* + * Compute the various statistics relavent for load balancing at + * this level. + */ + update_sd_lb_stats(sd, this_cpu, idle, sd_idle, cpus, + balance, &sds); + + /* Cases where imbalance does not exist from POV of this_cpu */ + /* 1) this_cpu is not the appropriate cpu to perform load balancing + * at this level. + * 2) There is no busy sibling group to pull from. + * 3) This group is the busiest group. + * 4) This group is more busy than the avg busieness at this + * sched_domain. + * 5) The imbalance is within the specified limit. + * 6) Any rebalance would lead to ping-pong + */ + if (balance && !(*balance)) + goto ret; + + if (!sds.busiest || sds.busiest_nr_running == 0) + goto out_balanced; + + if (sds.this_load >= sds.max_load) + goto out_balanced; + + sds.avg_load = (SCHED_LOAD_SCALE * sds.total_load) / sds.total_pwr; + + if (sds.this_load >= sds.avg_load) + goto out_balanced; + + if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load) + goto out_balanced; + + sds.busiest_load_per_task /= sds.busiest_nr_running; + if (sds.group_imb) + sds.busiest_load_per_task = + min(sds.busiest_load_per_task, sds.avg_load); + + /* + * We're trying to get all the cpus to the average_load, so we don't + * want to push ourselves above the average load, nor do we wish to + * reduce the max loaded cpu below the average load, as either of these + * actions would just result in more rebalancing later, and ping-pong + * tasks around. Thus we look for the minimum possible imbalance. + * Negative imbalances (*we* are more loaded than anyone else) will + * be counted as no imbalance for these purposes -- we can't fix that + * by pulling tasks to us. Be careful of negative numbers as they'll + * appear as very large values with unsigned longs. + */ + if (sds.max_load <= sds.busiest_load_per_task) + goto out_balanced; + + /* Looks like there is an imbalance. Compute it */ + calculate_imbalance(&sds, this_cpu, imbalance); + return sds.busiest; + +out_balanced: + /* + * There is no obvious imbalance. But check if we can do some balancing + * to save power. + */ + if (check_power_save_busiest_group(&sds, this_cpu, imbalance)) + return sds.busiest; +ret: + *imbalance = 0; + return NULL; +} + +/* + * find_busiest_queue - find the busiest runqueue among the cpus in group. + */ +static struct rq * +find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle, + unsigned long imbalance, const struct cpumask *cpus) +{ + struct rq *busiest = NULL, *rq; + unsigned long max_load = 0; + int i; + + for_each_cpu(i, sched_group_cpus(group)) { + unsigned long power = power_of(i); + unsigned long capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE); + unsigned long wl; + + if (!cpumask_test_cpu(i, cpus)) + continue; + + rq = cpu_rq(i); + wl = weighted_cpuload(i) * SCHED_LOAD_SCALE; + wl /= power; + + if (capacity && rq->nr_running == 1 && wl > imbalance) + continue; + + if (wl > max_load) { + max_load = wl; + busiest = rq; + } + } + + return busiest; +} + +/* + * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but + * so long as it is large enough. + */ +#define MAX_PINNED_INTERVAL 512 + +/* Working cpumask for load_balance and load_balance_newidle. */ +static DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask); + +/* + * Check this_cpu to ensure it is balanced within domain. Attempt to move + * tasks if there is an imbalance. + */ +static int load_balance(int this_cpu, struct rq *this_rq, + struct sched_domain *sd, enum cpu_idle_type idle, + int *balance) +{ + int ld_moved, all_pinned = 0, active_balance = 0, sd_idle = 0; + struct sched_group *group; + unsigned long imbalance; + struct rq *busiest; + unsigned long flags; + struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); + + cpumask_copy(cpus, cpu_active_mask); + + /* + * When power savings policy is enabled for the parent domain, idle + * sibling can pick up load irrespective of busy siblings. In this case, + * let the state of idle sibling percolate up as CPU_IDLE, instead of + * portraying it as CPU_NOT_IDLE. + */ + if (idle != CPU_NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + sd_idle = 1; + + schedstat_inc(sd, lb_count[idle]); + +redo: + update_shares(sd); + group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle, + cpus, balance); + + if (*balance == 0) + goto out_balanced; + + if (!group) { + schedstat_inc(sd, lb_nobusyg[idle]); + goto out_balanced; + } + + busiest = find_busiest_queue(group, idle, imbalance, cpus); + if (!busiest) { + schedstat_inc(sd, lb_nobusyq[idle]); + goto out_balanced; + } + + BUG_ON(busiest == this_rq); + + schedstat_add(sd, lb_imbalance[idle], imbalance); + + ld_moved = 0; + if (busiest->nr_running > 1) { + /* + * Attempt to move tasks. If find_busiest_group has found + * an imbalance but busiest->nr_running <= 1, the group is + * still unbalanced. ld_moved simply stays zero, so it is + * correctly treated as an imbalance. + */ + local_irq_save(flags); + double_rq_lock(this_rq, busiest); + ld_moved = move_tasks(this_rq, this_cpu, busiest, + imbalance, sd, idle, &all_pinned); + double_rq_unlock(this_rq, busiest); + local_irq_restore(flags); + + /* + * some other cpu did the load balance for us. + */ + if (ld_moved && this_cpu != smp_processor_id()) + resched_cpu(this_cpu); + + /* All tasks on this runqueue were pinned by CPU affinity */ + if (unlikely(all_pinned)) { + cpumask_clear_cpu(cpu_of(busiest), cpus); + if (!cpumask_empty(cpus)) + goto redo; + goto out_balanced; + } + } + + if (!ld_moved) { + schedstat_inc(sd, lb_failed[idle]); + sd->nr_balance_failed++; + + if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) { + + raw_spin_lock_irqsave(&busiest->lock, flags); + + /* don't kick the migration_thread, if the curr + * task on busiest cpu can't be moved to this_cpu + */ + if (!cpumask_test_cpu(this_cpu, + &busiest->curr->cpus_allowed)) { + raw_spin_unlock_irqrestore(&busiest->lock, + flags); + all_pinned = 1; + goto out_one_pinned; + } + + if (!busiest->active_balance) { + busiest->active_balance = 1; + busiest->push_cpu = this_cpu; + active_balance = 1; + } + raw_spin_unlock_irqrestore(&busiest->lock, flags); + if (active_balance) + wake_up_process(busiest->migration_thread); + + /* + * We've kicked active balancing, reset the failure + * counter. + */ + sd->nr_balance_failed = sd->cache_nice_tries+1; + } + } else + sd->nr_balance_failed = 0; + + if (likely(!active_balance)) { + /* We were unbalanced, so reset the balancing interval */ + sd->balance_interval = sd->min_interval; + } else { + /* + * If we've begun active balancing, start to back off. This + * case may not be covered by the all_pinned logic if there + * is only 1 task on the busy runqueue (because we don't call + * move_tasks). + */ + if (sd->balance_interval < sd->max_interval) + sd->balance_interval *= 2; + } + + if (!ld_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + ld_moved = -1; + + goto out; + +out_balanced: + schedstat_inc(sd, lb_balanced[idle]); + + sd->nr_balance_failed = 0; + +out_one_pinned: + /* tune up the balancing interval */ + if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) || + (sd->balance_interval < sd->max_interval)) + sd->balance_interval *= 2; + + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + ld_moved = -1; + else + ld_moved = 0; +out: + if (ld_moved) + update_shares(sd); + return ld_moved; +} + +/* + * Check this_cpu to ensure it is balanced within domain. Attempt to move + * tasks if there is an imbalance. + * + * Called from schedule when this_rq is about to become idle (CPU_NEWLY_IDLE). + * this_rq is locked. + */ +static int +load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) +{ + struct sched_group *group; + struct rq *busiest = NULL; + unsigned long imbalance; + int ld_moved = 0; + int sd_idle = 0; + int all_pinned = 0; + struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); + + cpumask_copy(cpus, cpu_active_mask); + + /* + * When power savings policy is enabled for the parent domain, idle + * sibling can pick up load irrespective of busy siblings. In this case, + * let the state of idle sibling percolate up as IDLE, instead of + * portraying it as CPU_NOT_IDLE. + */ + if (sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + sd_idle = 1; + + schedstat_inc(sd, lb_count[CPU_NEWLY_IDLE]); +redo: + update_shares_locked(this_rq, sd); + group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE, + &sd_idle, cpus, NULL); + if (!group) { + schedstat_inc(sd, lb_nobusyg[CPU_NEWLY_IDLE]); + goto out_balanced; + } + + busiest = find_busiest_queue(group, CPU_NEWLY_IDLE, imbalance, cpus); + if (!busiest) { + schedstat_inc(sd, lb_nobusyq[CPU_NEWLY_IDLE]); + goto out_balanced; + } + + BUG_ON(busiest == this_rq); + + schedstat_add(sd, lb_imbalance[CPU_NEWLY_IDLE], imbalance); + + ld_moved = 0; + if (busiest->nr_running > 1) { + /* Attempt to move tasks */ + double_lock_balance(this_rq, busiest); + /* this_rq->clock is already updated */ + update_rq_clock(busiest); + ld_moved = move_tasks(this_rq, this_cpu, busiest, + imbalance, sd, CPU_NEWLY_IDLE, + &all_pinned); + double_unlock_balance(this_rq, busiest); + + if (unlikely(all_pinned)) { + cpumask_clear_cpu(cpu_of(busiest), cpus); + if (!cpumask_empty(cpus)) + goto redo; + } + } + + if (!ld_moved) { + int active_balance = 0; + + schedstat_inc(sd, lb_failed[CPU_NEWLY_IDLE]); + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + return -1; + + if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP) + return -1; + + if (sd->nr_balance_failed++ < 2) + return -1; + + /* + * The only task running in a non-idle cpu can be moved to this + * cpu in an attempt to completely freeup the other CPU + * package. The same method used to move task in load_balance() + * have been extended for load_balance_newidle() to speedup + * consolidation at sched_mc=POWERSAVINGS_BALANCE_WAKEUP (2) + * + * The package power saving logic comes from + * find_busiest_group(). If there are no imbalance, then + * f_b_g() will return NULL. However when sched_mc={1,2} then + * f_b_g() will select a group from which a running task may be + * pulled to this cpu in order to make the other package idle. + * If there is no opportunity to make a package idle and if + * there are no imbalance, then f_b_g() will return NULL and no + * action will be taken in load_balance_newidle(). + * + * Under normal task pull operation due to imbalance, there + * will be more than one task in the source run queue and + * move_tasks() will succeed. ld_moved will be true and this + * active balance code will not be triggered. + */ + + /* Lock busiest in correct order while this_rq is held */ + double_lock_balance(this_rq, busiest); + + /* + * don't kick the migration_thread, if the curr + * task on busiest cpu can't be moved to this_cpu + */ + if (!cpumask_test_cpu(this_cpu, &busiest->curr->cpus_allowed)) { + double_unlock_balance(this_rq, busiest); + all_pinned = 1; + return ld_moved; + } + + if (!busiest->active_balance) { + busiest->active_balance = 1; + busiest->push_cpu = this_cpu; + active_balance = 1; + } + + double_unlock_balance(this_rq, busiest); + /* + * Should not call ttwu while holding a rq->lock + */ + raw_spin_unlock(&this_rq->lock); + if (active_balance) + wake_up_process(busiest->migration_thread); + raw_spin_lock(&this_rq->lock); + + } else + sd->nr_balance_failed = 0; + + update_shares_locked(this_rq, sd); + return ld_moved; + +out_balanced: + schedstat_inc(sd, lb_balanced[CPU_NEWLY_IDLE]); + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + return -1; + sd->nr_balance_failed = 0; + + return 0; +} + +/* + * idle_balance is called by schedule() if this_cpu is about to become + * idle. Attempts to pull tasks from other CPUs. + */ +static void idle_balance(int this_cpu, struct rq *this_rq) +{ + struct sched_domain *sd; + int pulled_task = 0; + unsigned long next_balance = jiffies + HZ; + + this_rq->idle_stamp = this_rq->clock; + + if (this_rq->avg_idle < sysctl_sched_migration_cost) + return; + + for_each_domain(this_cpu, sd) { + unsigned long interval; + + if (!(sd->flags & SD_LOAD_BALANCE)) + continue; + + if (sd->flags & SD_BALANCE_NEWIDLE) + /* If we've pulled tasks over stop searching: */ + pulled_task = load_balance_newidle(this_cpu, this_rq, + sd); + + interval = msecs_to_jiffies(sd->balance_interval); + if (time_after(next_balance, sd->last_balance + interval)) + next_balance = sd->last_balance + interval; + if (pulled_task) { + this_rq->idle_stamp = 0; + break; + } + } + if (pulled_task || time_after(jiffies, this_rq->next_balance)) { + /* + * We are going idle. next_balance may be set based on + * a busy processor. So reset next_balance. + */ + this_rq->next_balance = next_balance; + } +} + +/* + * active_load_balance is run by migration threads. It pushes running tasks + * off the busiest CPU onto idle CPUs. It requires at least 1 task to be + * running on each physical CPU where possible, and avoids physical / + * logical imbalances. + * + * Called with busiest_rq locked. + */ +static void active_load_balance(struct rq *busiest_rq, int busiest_cpu) +{ + int target_cpu = busiest_rq->push_cpu; + struct sched_domain *sd; + struct rq *target_rq; + + /* Is there any task to move? */ + if (busiest_rq->nr_running <= 1) + return; + + target_rq = cpu_rq(target_cpu); + + /* + * This condition is "impossible", if it occurs + * we need to fix it. Originally reported by + * Bjorn Helgaas on a 128-cpu setup. + */ + BUG_ON(busiest_rq == target_rq); + + /* move a task from busiest_rq to target_rq */ + double_lock_balance(busiest_rq, target_rq); + update_rq_clock(busiest_rq); + update_rq_clock(target_rq); + + /* Search for an sd spanning us and the target CPU. */ + for_each_domain(target_cpu, sd) { + if ((sd->flags & SD_LOAD_BALANCE) && + cpumask_test_cpu(busiest_cpu, sched_domain_span(sd))) + break; + } + + if (likely(sd)) { + schedstat_inc(sd, alb_count); + + if (move_one_task(target_rq, target_cpu, busiest_rq, + sd, CPU_IDLE)) + schedstat_inc(sd, alb_pushed); + else + schedstat_inc(sd, alb_failed); + } + double_unlock_balance(busiest_rq, target_rq); +} + +#ifdef CONFIG_NO_HZ +static struct { + atomic_t load_balancer; + cpumask_var_t cpu_mask; + cpumask_var_t ilb_grp_nohz_mask; +} nohz ____cacheline_aligned = { + .load_balancer = ATOMIC_INIT(-1), +}; + +int get_nohz_load_balancer(void) +{ + return atomic_read(&nohz.load_balancer); +} + +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) +/** + * lowest_flag_domain - Return lowest sched_domain containing flag. + * @cpu: The cpu whose lowest level of sched domain is to + * be returned. + * @flag: The flag to check for the lowest sched_domain + * for the given cpu. + * + * Returns the lowest sched_domain of a cpu which contains the given flag. + */ +static inline struct sched_domain *lowest_flag_domain(int cpu, int flag) +{ + struct sched_domain *sd; + + for_each_domain(cpu, sd) + if (sd && (sd->flags & flag)) + break; + + return sd; +} + +/** + * for_each_flag_domain - Iterates over sched_domains containing the flag. + * @cpu: The cpu whose domains we're iterating over. + * @sd: variable holding the value of the power_savings_sd + * for cpu. + * @flag: The flag to filter the sched_domains to be iterated. + * + * Iterates over all the scheduler domains for a given cpu that has the 'flag' + * set, starting from the lowest sched_domain to the highest. + */ +#define for_each_flag_domain(cpu, sd, flag) \ + for (sd = lowest_flag_domain(cpu, flag); \ + (sd && (sd->flags & flag)); sd = sd->parent) + +/** + * is_semi_idle_group - Checks if the given sched_group is semi-idle. + * @ilb_group: group to be checked for semi-idleness + * + * Returns: 1 if the group is semi-idle. 0 otherwise. + * + * We define a sched_group to be semi idle if it has atleast one idle-CPU + * and atleast one non-idle CPU. This helper function checks if the given + * sched_group is semi-idle or not. + */ +static inline int is_semi_idle_group(struct sched_group *ilb_group) +{ + cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask, + sched_group_cpus(ilb_group)); + + /* + * A sched_group is semi-idle when it has atleast one busy cpu + * and atleast one idle cpu. + */ + if (cpumask_empty(nohz.ilb_grp_nohz_mask)) + return 0; + + if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group))) + return 0; + + return 1; +} +/** + * find_new_ilb - Finds the optimum idle load balancer for nomination. + * @cpu: The cpu which is nominating a new idle_load_balancer. + * + * Returns: Returns the id of the idle load balancer if it exists, + * Else, returns >= nr_cpu_ids. + * + * This algorithm picks the idle load balancer such that it belongs to a + * semi-idle powersavings sched_domain. The idea is to try and avoid + * completely idle packages/cores just for the purpose of idle load balancing + * when there are other idle cpu's which are better suited for that job. + */ +static int find_new_ilb(int cpu) +{ + struct sched_domain *sd; + struct sched_group *ilb_group; + + /* + * Have idle load balancer selection from semi-idle packages only + * when power-aware load balancing is enabled + */ + if (!(sched_smt_power_savings || sched_mc_power_savings)) + goto out_done; + + /* + * Optimize for the case when we have no idle CPUs or only one + * idle CPU. Don't walk the sched_domain hierarchy in such cases + */ + if (cpumask_weight(nohz.cpu_mask) < 2) + goto out_done; + + for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) { + ilb_group = sd->groups; + + do { + if (is_semi_idle_group(ilb_group)) + return cpumask_first(nohz.ilb_grp_nohz_mask); + + ilb_group = ilb_group->next; + + } while (ilb_group != sd->groups); + } + +out_done: + return cpumask_first(nohz.cpu_mask); +} +#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ +static inline int find_new_ilb(int call_cpu) +{ + return cpumask_first(nohz.cpu_mask); +} +#endif + +/* + * This routine will try to nominate the ilb (idle load balancing) + * owner among the cpus whose ticks are stopped. ilb owner will do the idle + * load balancing on behalf of all those cpus. If all the cpus in the system + * go into this tickless mode, then there will be no ilb owner (as there is + * no need for one) and all the cpus will sleep till the next wakeup event + * arrives... + * + * For the ilb owner, tick is not stopped. And this tick will be used + * for idle load balancing. ilb owner will still be part of + * nohz.cpu_mask.. + * + * While stopping the tick, this cpu will become the ilb owner if there + * is no other owner. And will be the owner till that cpu becomes busy + * or if all cpus in the system stop their ticks at which point + * there is no need for ilb owner. + * + * When the ilb owner becomes busy, it nominates another owner, during the + * next busy scheduler_tick() + */ +int select_nohz_load_balancer(int stop_tick) +{ + int cpu = smp_processor_id(); + + if (stop_tick) { + cpu_rq(cpu)->in_nohz_recently = 1; + + if (!cpu_active(cpu)) { + if (atomic_read(&nohz.load_balancer) != cpu) + return 0; + + /* + * If we are going offline and still the leader, + * give up! + */ + if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) + BUG(); + + return 0; + } + + cpumask_set_cpu(cpu, nohz.cpu_mask); + + /* time for ilb owner also to sleep */ + if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) { + if (atomic_read(&nohz.load_balancer) == cpu) + atomic_set(&nohz.load_balancer, -1); + return 0; + } + + if (atomic_read(&nohz.load_balancer) == -1) { + /* make me the ilb owner */ + if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1) + return 1; + } else if (atomic_read(&nohz.load_balancer) == cpu) { + int new_ilb; + + if (!(sched_smt_power_savings || + sched_mc_power_savings)) + return 1; + /* + * Check to see if there is a more power-efficient + * ilb. + */ + new_ilb = find_new_ilb(cpu); + if (new_ilb < nr_cpu_ids && new_ilb != cpu) { + atomic_set(&nohz.load_balancer, -1); + resched_cpu(new_ilb); + return 0; + } + return 1; + } + } else { + if (!cpumask_test_cpu(cpu, nohz.cpu_mask)) + return 0; + + cpumask_clear_cpu(cpu, nohz.cpu_mask); + + if (atomic_read(&nohz.load_balancer) == cpu) + if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu) + BUG(); + } + return 0; +} +#endif + +static DEFINE_SPINLOCK(balancing); + +/* + * It checks each scheduling domain to see if it is due to be balanced, + * and initiates a balancing operation if so. + * + * Balancing parameters are set up in arch_init_sched_domains. + */ +static void rebalance_domains(int cpu, enum cpu_idle_type idle) +{ + int balance = 1; + struct rq *rq = cpu_rq(cpu); + unsigned long interval; + struct sched_domain *sd; + /* Earliest time when we have to do rebalance again */ + unsigned long next_balance = jiffies + 60*HZ; + int update_next_balance = 0; + int need_serialize; + + for_each_domain(cpu, sd) { + if (!(sd->flags & SD_LOAD_BALANCE)) + continue; + + interval = sd->balance_interval; + if (idle != CPU_IDLE) + interval *= sd->busy_factor; + + /* scale ms to jiffies */ + interval = msecs_to_jiffies(interval); + if (unlikely(!interval)) + interval = 1; + if (interval > HZ*NR_CPUS/10) + interval = HZ*NR_CPUS/10; + + need_serialize = sd->flags & SD_SERIALIZE; + + if (need_serialize) { + if (!spin_trylock(&balancing)) + goto out; + } + + if (time_after_eq(jiffies, sd->last_balance + interval)) { + if (load_balance(cpu, rq, sd, idle, &balance)) { + /* + * We've pulled tasks over so either we're no + * longer idle, or one of our SMT siblings is + * not idle. + */ + idle = CPU_NOT_IDLE; + } + sd->last_balance = jiffies; + } + if (need_serialize) + spin_unlock(&balancing); +out: + if (time_after(next_balance, sd->last_balance + interval)) { + next_balance = sd->last_balance + interval; + update_next_balance = 1; + } + + /* + * Stop the load balance at this level. There is another + * CPU in our sched group which is doing load balancing more + * actively. + */ + if (!balance) + break; + } + + /* + * next_balance will be updated only when there is a need. + * When the cpu is attached to null domain for ex, it will not be + * updated. + */ + if (likely(update_next_balance)) + rq->next_balance = next_balance; +} + +/* + * run_rebalance_domains is triggered when needed from the scheduler tick. + * In CONFIG_NO_HZ case, the idle load balance owner will do the + * rebalancing for all the cpus for whom scheduler ticks are stopped. + */ +static void run_rebalance_domains(struct softirq_action *h) +{ + int this_cpu = smp_processor_id(); + struct rq *this_rq = cpu_rq(this_cpu); + enum cpu_idle_type idle = this_rq->idle_at_tick ? + CPU_IDLE : CPU_NOT_IDLE; + + rebalance_domains(this_cpu, idle); + +#ifdef CONFIG_NO_HZ + /* + * If this cpu is the owner for idle load balancing, then do the + * balancing on behalf of the other idle cpus whose ticks are + * stopped. + */ + if (this_rq->idle_at_tick && + atomic_read(&nohz.load_balancer) == this_cpu) { + struct rq *rq; + int balance_cpu; + + for_each_cpu(balance_cpu, nohz.cpu_mask) { + if (balance_cpu == this_cpu) + continue; + + /* + * If this cpu gets work to do, stop the load balancing + * work being done for other cpus. Next load + * balancing owner will pick it up. + */ + if (need_resched()) + break; + + rebalance_domains(balance_cpu, CPU_IDLE); + + rq = cpu_rq(balance_cpu); + if (time_after(this_rq->next_balance, rq->next_balance)) + this_rq->next_balance = rq->next_balance; + } + } +#endif +} + +static inline int on_null_domain(int cpu) +{ + return !rcu_dereference(cpu_rq(cpu)->sd); +} + +/* + * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing. + * + * In case of CONFIG_NO_HZ, this is the place where we nominate a new + * idle load balancing owner or decide to stop the periodic load balancing, + * if the whole system is idle. + */ +static inline void trigger_load_balance(struct rq *rq, int cpu) +{ +#ifdef CONFIG_NO_HZ + /* + * If we were in the nohz mode recently and busy at the current + * scheduler tick, then check if we need to nominate new idle + * load balancer. + */ + if (rq->in_nohz_recently && !rq->idle_at_tick) { + rq->in_nohz_recently = 0; + + if (atomic_read(&nohz.load_balancer) == cpu) { + cpumask_clear_cpu(cpu, nohz.cpu_mask); + atomic_set(&nohz.load_balancer, -1); + } + + if (atomic_read(&nohz.load_balancer) == -1) { + int ilb = find_new_ilb(cpu); + + if (ilb < nr_cpu_ids) + resched_cpu(ilb); + } + } + + /* + * If this cpu is idle and doing idle load balancing for all the + * cpus with ticks stopped, is it time for that to stop? + */ + if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu && + cpumask_weight(nohz.cpu_mask) == num_online_cpus()) { + resched_cpu(cpu); + return; + } + + /* + * If this cpu is idle and the idle load balancing is done by + * someone else, then no need raise the SCHED_SOFTIRQ + */ + if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu && + cpumask_test_cpu(cpu, nohz.cpu_mask)) + return; +#endif + /* Don't need to rebalance while attached to NULL domain */ + if (time_after_eq(jiffies, rq->next_balance) && + likely(!on_null_domain(cpu))) + raise_softirq(SCHED_SOFTIRQ); +} + static void rq_online_fair(struct rq *rq) { update_sysctl(); @@ -1962,6 +3718,15 @@ static void rq_offline_fair(struct rq *rq) update_sysctl(); } +#else /* CONFIG_SMP */ + +/* + * on UP we do not need to balance between CPUs: + */ +static inline void idle_balance(int cpu, struct rq *rq) +{ +} + #endif /* CONFIG_SMP */ /* -- GitLab From 3d45fd804a95055ecab5b3eed81f5ab2dbb047a2 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 17:12:46 +0100 Subject: [PATCH 1056/3892] sched: Remove the sched_class load_balance methods Take out the sched_class methods for load-balancing. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- include/linux/sched.h | 8 ----- kernel/sched.c | 26 ---------------- kernel/sched_fair.c | 66 +++++++++++++++++++++++------------------ kernel/sched_idletask.c | 21 ------------- kernel/sched_rt.c | 20 ------------- 5 files changed, 37 insertions(+), 104 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index f2f842db03ce..50d685cde70e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1087,14 +1087,6 @@ struct sched_class { #ifdef CONFIG_SMP int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags); - unsigned long (*load_balance) (struct rq *this_rq, int this_cpu, - struct rq *busiest, unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio); - - int (*move_one_task) (struct rq *this_rq, int this_cpu, - struct rq *busiest, struct sched_domain *sd, - enum cpu_idle_type idle); void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); void (*post_schedule) (struct rq *this_rq); void (*task_waking) (struct rq *this_rq, struct task_struct *task); diff --git a/kernel/sched.c b/kernel/sched.c index 13a2acf18b2d..c0be07932a8d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1390,32 +1390,6 @@ static const u32 prio_to_wmult[40] = { /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153, }; -static void activate_task(struct rq *rq, struct task_struct *p, int wakeup); - -/* - * runqueue iterator, to support SMP load-balancing between different - * scheduling classes, without having to expose their internal data - * structures to the load-balancing proper: - */ -struct rq_iterator { - void *arg; - struct task_struct *(*start)(void *); - struct task_struct *(*next)(void *); -}; - -#ifdef CONFIG_SMP -static unsigned long -balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, struct sched_domain *sd, - enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct rq_iterator *iterator); - -static int -iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle, - struct rq_iterator *iterator); -#endif - /* Time spent by the tasks of the cpu accounting group executing in ... */ enum cpuacct_stat_index { CPUACCT_STAT_USER, /* ... user mode */ diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 5116b81d7727..faf9a2f099ab 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1851,6 +1851,24 @@ static struct task_struct *load_balance_next_fair(void *arg) return __load_balance_iterator(cfs_rq, cfs_rq->balance_iterator); } +/* + * runqueue iterator, to support SMP load-balancing between different + * scheduling classes, without having to expose their internal data + * structures to the load-balancing proper: + */ +struct rq_iterator { + void *arg; + struct task_struct *(*start)(void *); + struct task_struct *(*next)(void *); +}; + +static unsigned long +balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, + unsigned long max_load_move, struct sched_domain *sd, + enum cpu_idle_type idle, int *all_pinned, + int *this_best_prio, struct rq_iterator *iterator); + + static unsigned long __load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, @@ -1929,8 +1947,20 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, #endif static int -move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) +iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle, + struct rq_iterator *iterator); + +/* + * move_one_task tries to move exactly one task from busiest to this_rq, as + * part of active balancing operations within "domain". + * Returns 1 if successful and 0 otherwise. + * + * Called with both runqueues locked. + */ +static int +move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle) { struct cfs_rq *busy_cfs_rq; struct rq_iterator cfs_rq_iterator; @@ -2094,16 +2124,15 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned) { - const struct sched_class *class = sched_class_highest; - unsigned long total_load_moved = 0; + unsigned long total_load_moved = 0, load_moved; int this_best_prio = this_rq->curr->prio; do { - total_load_moved += - class->load_balance(this_rq, this_cpu, busiest, + load_moved = load_balance_fair(this_rq, this_cpu, busiest, max_load_move - total_load_moved, sd, idle, all_pinned, &this_best_prio); - class = class->next; + + total_load_moved += load_moved; #ifdef CONFIG_PREEMPT /* @@ -2114,7 +2143,7 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, if (idle == CPU_NEWLY_IDLE && this_rq->nr_running) break; #endif - } while (class && max_load_move > total_load_moved); + } while (load_moved && max_load_move > total_load_moved); return total_load_moved > 0; } @@ -2145,25 +2174,6 @@ iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, return 0; } -/* - * move_one_task tries to move exactly one task from busiest to this_rq, as - * part of active balancing operations within "domain". - * Returns 1 if successful and 0 otherwise. - * - * Called with both runqueues locked. - */ -static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - const struct sched_class *class; - - for_each_class(class) { - if (class->move_one_task(this_rq, this_cpu, busiest, sd, idle)) - return 1; - } - - return 0; -} /********** Helpers for find_busiest_group ************************/ /* * sd_lb_stats - Structure to store the statistics of a sched_domain @@ -3873,8 +3883,6 @@ static const struct sched_class fair_sched_class = { #ifdef CONFIG_SMP .select_task_rq = select_task_rq_fair, - .load_balance = load_balance_fair, - .move_one_task = move_one_task_fair, .rq_online = rq_online_fair, .rq_offline = rq_offline_fair, diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c index 01332bfc61a7..a8a6d8a50947 100644 --- a/kernel/sched_idletask.c +++ b/kernel/sched_idletask.c @@ -44,24 +44,6 @@ static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) { } -#ifdef CONFIG_SMP -static unsigned long -load_balance_idle(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) -{ - return 0; -} - -static int -move_one_task_idle(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - return 0; -} -#endif - static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued) { } @@ -119,9 +101,6 @@ static const struct sched_class idle_sched_class = { #ifdef CONFIG_SMP .select_task_rq = select_task_rq_idle, - - .load_balance = load_balance_idle, - .move_one_task = move_one_task_idle, #endif .set_curr_task = set_curr_task_idle, diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 072b3fcee8d8..502bb614e40a 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1481,24 +1481,6 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p) push_rt_tasks(rq); } -static unsigned long -load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) -{ - /* don't touch RT tasks */ - return 0; -} - -static int -move_one_task_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - /* don't touch RT tasks */ - return 0; -} - static void set_cpus_allowed_rt(struct task_struct *p, const struct cpumask *new_mask) { @@ -1746,8 +1728,6 @@ static const struct sched_class rt_sched_class = { #ifdef CONFIG_SMP .select_task_rq = select_task_rq_rt, - .load_balance = load_balance_rt, - .move_one_task = move_one_task_rt, .set_cpus_allowed = set_cpus_allowed_rt, .rq_online = rq_online_rt, .rq_offline = rq_offline_rt, -- GitLab From ee00e66ffff250fb0d3a789e5565462f71c7c9a7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 17:25:20 +0100 Subject: [PATCH 1057/3892] sched: Remove rq_iterator usage from load_balance_fair Since we only ever iterate the fair class, do away with this abstraction. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 80 ++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index faf9a2f099ab..709deb33708a 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1866,26 +1866,9 @@ static unsigned long balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct rq_iterator *iterator); + int *this_best_prio, struct cfs_rq *busiest_cfs_rq); -static unsigned long -__load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, struct sched_domain *sd, - enum cpu_idle_type idle, int *all_pinned, int *this_best_prio, - struct cfs_rq *cfs_rq) -{ - struct rq_iterator cfs_rq_iterator; - - cfs_rq_iterator.start = load_balance_start_fair; - cfs_rq_iterator.next = load_balance_next_fair; - cfs_rq_iterator.arg = cfs_rq; - - return balance_tasks(this_rq, this_cpu, busiest, - max_load_move, sd, idle, all_pinned, - this_best_prio, &cfs_rq_iterator); -} - #ifdef CONFIG_FAIR_GROUP_SCHED static unsigned long load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, @@ -1915,9 +1898,9 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, rem_load = (u64)rem_load_move * busiest_weight; rem_load = div_u64(rem_load, busiest_h_load + 1); - moved_load = __load_balance_fair(this_rq, this_cpu, busiest, + moved_load = balance_tasks(this_rq, this_cpu, busiest, rem_load, sd, idle, all_pinned, this_best_prio, - tg->cfs_rq[busiest_cpu]); + busiest_cfs_rq); if (!moved_load) continue; @@ -1940,7 +1923,7 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned, int *this_best_prio) { - return __load_balance_fair(this_rq, this_cpu, busiest, + return balance_tasks(this_rq, this_cpu, busiest, max_load_move, sd, idle, all_pinned, this_best_prio, &busiest->cfs); } @@ -2050,53 +2033,48 @@ static unsigned long balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct rq_iterator *iterator) + int *this_best_prio, struct cfs_rq *busiest_cfs_rq) { int loops = 0, pulled = 0, pinned = 0; - struct task_struct *p; long rem_load_move = max_load_move; + struct task_struct *p, *n; if (max_load_move == 0) goto out; pinned = 1; - /* - * Start the load-balancing iterator: - */ - p = iterator->start(iterator->arg); -next: - if (!p || loops++ > sysctl_sched_nr_migrate) - goto out; + list_for_each_entry_safe(p, n, &busiest_cfs_rq->tasks, se.group_node) { + if (loops++ > sysctl_sched_nr_migrate) + break; - if ((p->se.load.weight >> 1) > rem_load_move || - !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { - p = iterator->next(iterator->arg); - goto next; - } + if ((p->se.load.weight >> 1) > rem_load_move || + !can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) + continue; - pull_task(busiest, p, this_rq, this_cpu); - pulled++; - rem_load_move -= p->se.load.weight; + pull_task(busiest, p, this_rq, this_cpu); + pulled++; + rem_load_move -= p->se.load.weight; #ifdef CONFIG_PREEMPT - /* - * NEWIDLE balancing is a source of latency, so preemptible kernels - * will stop after the first task is pulled to minimize the critical - * section. - */ - if (idle == CPU_NEWLY_IDLE) - goto out; + /* + * NEWIDLE balancing is a source of latency, so preemptible + * kernels will stop after the first task is pulled to minimize + * the critical section. + */ + if (idle == CPU_NEWLY_IDLE) + break; #endif - /* - * We only want to steal up to the prescribed amount of weighted load. - */ - if (rem_load_move > 0) { + /* + * We only want to steal up to the prescribed amount of + * weighted load. + */ + if (rem_load_move <= 0) + break; + if (p->prio < *this_best_prio) *this_best_prio = p->prio; - p = iterator->next(iterator->arg); - goto next; } out: /* -- GitLab From 897c395f4c94ae19302f92393a0b8304e414ee06 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 17:45:42 +0100 Subject: [PATCH 1058/3892] sched: Remove rq_iterator from move_one_task Again, since we only iterate the fair class, remove the abstraction. Since this is the last user of the rq_iterator, remove all that too. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 146 +++++++++++--------------------------------- 1 file changed, 36 insertions(+), 110 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 709deb33708a..e48e459da98d 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1814,54 +1814,6 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev) * Fair scheduling class load-balancing methods: */ -/* - * Load-balancing iterator. Note: while the runqueue stays locked - * during the whole iteration, the current task might be - * dequeued so the iterator has to be dequeue-safe. Here we - * achieve that by always pre-iterating before returning - * the current task: - */ -static struct task_struct * -__load_balance_iterator(struct cfs_rq *cfs_rq, struct list_head *next) -{ - struct task_struct *p = NULL; - struct sched_entity *se; - - if (next == &cfs_rq->tasks) - return NULL; - - se = list_entry(next, struct sched_entity, group_node); - p = task_of(se); - cfs_rq->balance_iterator = next->next; - - return p; -} - -static struct task_struct *load_balance_start_fair(void *arg) -{ - struct cfs_rq *cfs_rq = arg; - - return __load_balance_iterator(cfs_rq, cfs_rq->tasks.next); -} - -static struct task_struct *load_balance_next_fair(void *arg) -{ - struct cfs_rq *cfs_rq = arg; - - return __load_balance_iterator(cfs_rq, cfs_rq->balance_iterator); -} - -/* - * runqueue iterator, to support SMP load-balancing between different - * scheduling classes, without having to expose their internal data - * structures to the load-balancing proper: - */ -struct rq_iterator { - void *arg; - struct task_struct *(*start)(void *); - struct task_struct *(*next)(void *); -}; - static unsigned long balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, @@ -1929,42 +1881,6 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, } #endif -static int -iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle, - struct rq_iterator *iterator); - -/* - * move_one_task tries to move exactly one task from busiest to this_rq, as - * part of active balancing operations within "domain". - * Returns 1 if successful and 0 otherwise. - * - * Called with both runqueues locked. - */ -static int -move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - struct cfs_rq *busy_cfs_rq; - struct rq_iterator cfs_rq_iterator; - - cfs_rq_iterator.start = load_balance_start_fair; - cfs_rq_iterator.next = load_balance_next_fair; - - for_each_leaf_cfs_rq(busiest, busy_cfs_rq) { - /* - * pass busy_cfs_rq argument into - * load_balance_[start|next]_fair iterators - */ - cfs_rq_iterator.arg = busy_cfs_rq; - if (iter_move_one_task(this_rq, this_cpu, busiest, sd, idle, - &cfs_rq_iterator)) - return 1; - } - - return 0; -} - /* * pull_task - move a task from a remote runqueue to the local runqueue. * Both runqueues must be locked. @@ -2029,6 +1945,42 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu, return 1; } +/* + * move_one_task tries to move exactly one task from busiest to this_rq, as + * part of active balancing operations within "domain". + * Returns 1 if successful and 0 otherwise. + * + * Called with both runqueues locked. + */ +static int +move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle) +{ + struct task_struct *p, *n; + struct cfs_rq *cfs_rq; + int pinned = 0; + + for_each_leaf_cfs_rq(busiest, cfs_rq) { + list_for_each_entry_safe(p, n, &cfs_rq->tasks, se.group_node) { + + if (!can_migrate_task(p, busiest, this_cpu, + sd, idle, &pinned)) + continue; + + pull_task(busiest, p, this_rq, this_cpu); + /* + * Right now, this is only the second place pull_task() + * is called, so we can safely collect pull_task() + * stats here rather than inside pull_task(). + */ + schedstat_inc(sd, lb_gained[idle]); + return 1; + } + } + + return 0; +} + static unsigned long balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, @@ -2126,32 +2078,6 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, return total_load_moved > 0; } -static int -iter_move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle, - struct rq_iterator *iterator) -{ - struct task_struct *p = iterator->start(iterator->arg); - int pinned = 0; - - while (p) { - if (can_migrate_task(p, busiest, this_cpu, sd, idle, &pinned)) { - pull_task(busiest, p, this_rq, this_cpu); - /* - * Right now, this is only the second place pull_task() - * is called, so we can safely collect pull_task() - * stats here rather than inside pull_task(). - */ - schedstat_inc(sd, lb_gained[idle]); - - return 1; - } - p = iterator->next(iterator->arg); - } - - return 0; -} - /********** Helpers for find_busiest_group ************************/ /* * sd_lb_stats - Structure to store the statistics of a sched_domain -- GitLab From 230059de77a4e0f6afba98073e73bc9fd471506e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 17:47:12 +0100 Subject: [PATCH 1059/3892] sched: Remove from fwd decls Move code around to get rid of fwd declarations. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 127 +++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 67 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index e48e459da98d..93fccbadde23 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1814,73 +1814,6 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev) * Fair scheduling class load-balancing methods: */ -static unsigned long -balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, struct sched_domain *sd, - enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct cfs_rq *busiest_cfs_rq); - - -#ifdef CONFIG_FAIR_GROUP_SCHED -static unsigned long -load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) -{ - long rem_load_move = max_load_move; - int busiest_cpu = cpu_of(busiest); - struct task_group *tg; - - rcu_read_lock(); - update_h_load(busiest_cpu); - - list_for_each_entry_rcu(tg, &task_groups, list) { - struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu]; - unsigned long busiest_h_load = busiest_cfs_rq->h_load; - unsigned long busiest_weight = busiest_cfs_rq->load.weight; - u64 rem_load, moved_load; - - /* - * empty group - */ - if (!busiest_cfs_rq->task_weight) - continue; - - rem_load = (u64)rem_load_move * busiest_weight; - rem_load = div_u64(rem_load, busiest_h_load + 1); - - moved_load = balance_tasks(this_rq, this_cpu, busiest, - rem_load, sd, idle, all_pinned, this_best_prio, - busiest_cfs_rq); - - if (!moved_load) - continue; - - moved_load *= busiest_h_load; - moved_load = div_u64(moved_load, busiest_weight + 1); - - rem_load_move -= moved_load; - if (rem_load_move < 0) - break; - } - rcu_read_unlock(); - - return max_load_move - rem_load_move; -} -#else -static unsigned long -load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, - unsigned long max_load_move, - struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) -{ - return balance_tasks(this_rq, this_cpu, busiest, - max_load_move, sd, idle, all_pinned, - this_best_prio, &busiest->cfs); -} -#endif - /* * pull_task - move a task from a remote runqueue to the local runqueue. * Both runqueues must be locked. @@ -2042,6 +1975,66 @@ out: return max_load_move - rem_load_move; } +#ifdef CONFIG_FAIR_GROUP_SCHED +static unsigned long +load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, + unsigned long max_load_move, + struct sched_domain *sd, enum cpu_idle_type idle, + int *all_pinned, int *this_best_prio) +{ + long rem_load_move = max_load_move; + int busiest_cpu = cpu_of(busiest); + struct task_group *tg; + + rcu_read_lock(); + update_h_load(busiest_cpu); + + list_for_each_entry_rcu(tg, &task_groups, list) { + struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu]; + unsigned long busiest_h_load = busiest_cfs_rq->h_load; + unsigned long busiest_weight = busiest_cfs_rq->load.weight; + u64 rem_load, moved_load; + + /* + * empty group + */ + if (!busiest_cfs_rq->task_weight) + continue; + + rem_load = (u64)rem_load_move * busiest_weight; + rem_load = div_u64(rem_load, busiest_h_load + 1); + + moved_load = balance_tasks(this_rq, this_cpu, busiest, + rem_load, sd, idle, all_pinned, this_best_prio, + busiest_cfs_rq); + + if (!moved_load) + continue; + + moved_load *= busiest_h_load; + moved_load = div_u64(moved_load, busiest_weight + 1); + + rem_load_move -= moved_load; + if (rem_load_move < 0) + break; + } + rcu_read_unlock(); + + return max_load_move - rem_load_move; +} +#else +static unsigned long +load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, + unsigned long max_load_move, + struct sched_domain *sd, enum cpu_idle_type idle, + int *all_pinned, int *this_best_prio) +{ + return balance_tasks(this_rq, this_cpu, busiest, + max_load_move, sd, idle, all_pinned, + this_best_prio, &busiest->cfs); +} +#endif + /* * move_tasks tries to move up to max_load_move weighted load from busiest to * this_rq, as part of a balancing operation within domain "sd". -- GitLab From baa8c1102f0cd86e69c1497d61d2ee177e663663 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 17 Dec 2009 18:10:09 +0100 Subject: [PATCH 1060/3892] sched: Add a lock break for PREEMPT=y Since load-balancing can hold rq->locks for quite a long while, allow breaking out early when there is lock contention. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 93fccbadde23..65d08207e925 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2065,6 +2065,10 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, */ if (idle == CPU_NEWLY_IDLE && this_rq->nr_running) break; + + if (raw_spin_is_contended(&this_rq->lock) || + raw_spin_is_contended(&busiest->lock)) + break; #endif } while (load_moved && max_load_move > total_load_moved); -- GitLab From 1af3ed3ddf27499c3f57662c4c29871e2b95e5f9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Dec 2009 15:10:31 +0100 Subject: [PATCH 1061/3892] sched: Unify load_balance{,_newidle}() load_balance() and load_balance_newidle() look remarkably similar, one key point they differ in is the condition on when to active balance. So split out that logic into a separate function. One side effect is that previously load_balance_newidle() used to fail and return -1 under these conditions, whereas now it doesn't. I've not yet fully figured out the whole -1 return case for either load_balance{,_newidle}(). Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 115 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 65d08207e925..10408323794e 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2816,6 +2816,39 @@ find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle, /* Working cpumask for load_balance and load_balance_newidle. */ static DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask); +static int need_active_balance(struct sched_domain *sd, int sd_idle, int idle) +{ + if (idle == CPU_NEWLY_IDLE) { + /* + * The only task running in a non-idle cpu can be moved to this + * cpu in an attempt to completely freeup the other CPU + * package. + * + * The package power saving logic comes from + * find_busiest_group(). If there are no imbalance, then + * f_b_g() will return NULL. However when sched_mc={1,2} then + * f_b_g() will select a group from which a running task may be + * pulled to this cpu in order to make the other package idle. + * If there is no opportunity to make a package idle and if + * there are no imbalance, then f_b_g() will return NULL and no + * action will be taken in load_balance_newidle(). + * + * Under normal task pull operation due to imbalance, there + * will be more than one task in the source run queue and + * move_tasks() will succeed. ld_moved will be true and this + * active balance code will not be triggered. + */ + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && + !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) + return 0; + + if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP) + return 0; + } + + return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2); +} + /* * Check this_cpu to ensure it is balanced within domain. Attempt to move * tasks if there is an imbalance. @@ -2902,8 +2935,7 @@ redo: schedstat_inc(sd, lb_failed[idle]); sd->nr_balance_failed++; - if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) { - + if (need_active_balance(sd, sd_idle, idle)) { raw_spin_lock_irqsave(&busiest->lock, flags); /* don't kick the migration_thread, if the curr @@ -3049,66 +3081,37 @@ redo: int active_balance = 0; schedstat_inc(sd, lb_failed[CPU_NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - return -1; - - if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP) - return -1; + sd->nr_balance_failed++; - if (sd->nr_balance_failed++ < 2) - return -1; + if (need_active_balance(sd, sd_idle, CPU_NEWLY_IDLE)) { + double_lock_balance(this_rq, busiest); - /* - * The only task running in a non-idle cpu can be moved to this - * cpu in an attempt to completely freeup the other CPU - * package. The same method used to move task in load_balance() - * have been extended for load_balance_newidle() to speedup - * consolidation at sched_mc=POWERSAVINGS_BALANCE_WAKEUP (2) - * - * The package power saving logic comes from - * find_busiest_group(). If there are no imbalance, then - * f_b_g() will return NULL. However when sched_mc={1,2} then - * f_b_g() will select a group from which a running task may be - * pulled to this cpu in order to make the other package idle. - * If there is no opportunity to make a package idle and if - * there are no imbalance, then f_b_g() will return NULL and no - * action will be taken in load_balance_newidle(). - * - * Under normal task pull operation due to imbalance, there - * will be more than one task in the source run queue and - * move_tasks() will succeed. ld_moved will be true and this - * active balance code will not be triggered. - */ + /* + * don't kick the migration_thread, if the curr + * task on busiest cpu can't be moved to this_cpu + */ + if (!cpumask_test_cpu(this_cpu, + &busiest->curr->cpus_allowed)) { + double_unlock_balance(this_rq, busiest); + all_pinned = 1; + return ld_moved; + } - /* Lock busiest in correct order while this_rq is held */ - double_lock_balance(this_rq, busiest); + if (!busiest->active_balance) { + busiest->active_balance = 1; + busiest->push_cpu = this_cpu; + active_balance = 1; + } - /* - * don't kick the migration_thread, if the curr - * task on busiest cpu can't be moved to this_cpu - */ - if (!cpumask_test_cpu(this_cpu, &busiest->curr->cpus_allowed)) { double_unlock_balance(this_rq, busiest); - all_pinned = 1; - return ld_moved; - } - - if (!busiest->active_balance) { - busiest->active_balance = 1; - busiest->push_cpu = this_cpu; - active_balance = 1; + /* + * Should not call ttwu while holding a rq->lock + */ + raw_spin_unlock(&this_rq->lock); + if (active_balance) + wake_up_process(busiest->migration_thread); + raw_spin_lock(&this_rq->lock); } - - double_unlock_balance(this_rq, busiest); - /* - * Should not call ttwu while holding a rq->lock - */ - raw_spin_unlock(&this_rq->lock); - if (active_balance) - wake_up_process(busiest->migration_thread); - raw_spin_lock(&this_rq->lock); - } else sd->nr_balance_failed = 0; -- GitLab From f492e12ef050e02bf0185b6b57874992591b9be1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Dec 2009 15:29:42 +0100 Subject: [PATCH 1062/3892] sched: Remove load_balance_newidle() The two functions: load_balance{,_newidle}() are very similar, with the following differences: - rq->lock usage - sb->balance_interval updates - *balance check So remove the load_balance_newidle() call with load_balance(.idle = CPU_NEWLY_IDLE), explicitly unlock the rq->lock before calling (would be done by double_lock_balance() anyway), and ignore the other differences for now. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 135 +++++--------------------------------------- 1 file changed, 13 insertions(+), 122 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 10408323794e..de5ab1239e04 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -3009,125 +3009,6 @@ out: return ld_moved; } -/* - * Check this_cpu to ensure it is balanced within domain. Attempt to move - * tasks if there is an imbalance. - * - * Called from schedule when this_rq is about to become idle (CPU_NEWLY_IDLE). - * this_rq is locked. - */ -static int -load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) -{ - struct sched_group *group; - struct rq *busiest = NULL; - unsigned long imbalance; - int ld_moved = 0; - int sd_idle = 0; - int all_pinned = 0; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - - cpumask_copy(cpus, cpu_active_mask); - - /* - * When power savings policy is enabled for the parent domain, idle - * sibling can pick up load irrespective of busy siblings. In this case, - * let the state of idle sibling percolate up as IDLE, instead of - * portraying it as CPU_NOT_IDLE. - */ - if (sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - sd_idle = 1; - - schedstat_inc(sd, lb_count[CPU_NEWLY_IDLE]); -redo: - update_shares_locked(this_rq, sd); - group = find_busiest_group(sd, this_cpu, &imbalance, CPU_NEWLY_IDLE, - &sd_idle, cpus, NULL); - if (!group) { - schedstat_inc(sd, lb_nobusyg[CPU_NEWLY_IDLE]); - goto out_balanced; - } - - busiest = find_busiest_queue(group, CPU_NEWLY_IDLE, imbalance, cpus); - if (!busiest) { - schedstat_inc(sd, lb_nobusyq[CPU_NEWLY_IDLE]); - goto out_balanced; - } - - BUG_ON(busiest == this_rq); - - schedstat_add(sd, lb_imbalance[CPU_NEWLY_IDLE], imbalance); - - ld_moved = 0; - if (busiest->nr_running > 1) { - /* Attempt to move tasks */ - double_lock_balance(this_rq, busiest); - /* this_rq->clock is already updated */ - update_rq_clock(busiest); - ld_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, CPU_NEWLY_IDLE, - &all_pinned); - double_unlock_balance(this_rq, busiest); - - if (unlikely(all_pinned)) { - cpumask_clear_cpu(cpu_of(busiest), cpus); - if (!cpumask_empty(cpus)) - goto redo; - } - } - - if (!ld_moved) { - int active_balance = 0; - - schedstat_inc(sd, lb_failed[CPU_NEWLY_IDLE]); - sd->nr_balance_failed++; - - if (need_active_balance(sd, sd_idle, CPU_NEWLY_IDLE)) { - double_lock_balance(this_rq, busiest); - - /* - * don't kick the migration_thread, if the curr - * task on busiest cpu can't be moved to this_cpu - */ - if (!cpumask_test_cpu(this_cpu, - &busiest->curr->cpus_allowed)) { - double_unlock_balance(this_rq, busiest); - all_pinned = 1; - return ld_moved; - } - - if (!busiest->active_balance) { - busiest->active_balance = 1; - busiest->push_cpu = this_cpu; - active_balance = 1; - } - - double_unlock_balance(this_rq, busiest); - /* - * Should not call ttwu while holding a rq->lock - */ - raw_spin_unlock(&this_rq->lock); - if (active_balance) - wake_up_process(busiest->migration_thread); - raw_spin_lock(&this_rq->lock); - } - } else - sd->nr_balance_failed = 0; - - update_shares_locked(this_rq, sd); - return ld_moved; - -out_balanced: - schedstat_inc(sd, lb_balanced[CPU_NEWLY_IDLE]); - if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && - !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE)) - return -1; - sd->nr_balance_failed = 0; - - return 0; -} - /* * idle_balance is called by schedule() if this_cpu is about to become * idle. Attempts to pull tasks from other CPUs. @@ -3143,16 +3024,23 @@ static void idle_balance(int this_cpu, struct rq *this_rq) if (this_rq->avg_idle < sysctl_sched_migration_cost) return; + /* + * Drop the rq->lock, but keep IRQ/preempt disabled. + */ + raw_spin_unlock(&this_rq->lock); + for_each_domain(this_cpu, sd) { unsigned long interval; + int balance = 1; if (!(sd->flags & SD_LOAD_BALANCE)) continue; - if (sd->flags & SD_BALANCE_NEWIDLE) + if (sd->flags & SD_BALANCE_NEWIDLE) { /* If we've pulled tasks over stop searching: */ - pulled_task = load_balance_newidle(this_cpu, this_rq, - sd); + pulled_task = load_balance(this_cpu, this_rq, + sd, CPU_NEWLY_IDLE, &balance); + } interval = msecs_to_jiffies(sd->balance_interval); if (time_after(next_balance, sd->last_balance + interval)) @@ -3162,6 +3050,9 @@ static void idle_balance(int this_cpu, struct rq *this_rq) break; } } + + raw_spin_lock(&this_rq->lock); + if (pulled_task || time_after(jiffies, this_rq->next_balance)) { /* * We are going idle. next_balance may be set based on -- GitLab From 8f190fb3f7a405682666d3723f6ec370b5afe4da Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 24 Dec 2009 14:18:21 +0100 Subject: [PATCH 1063/3892] sched: Assume *balance is valid Since all load_balance() callers will have !NULL balance parameters we can now assume so and remove a few checks. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index de5ab1239e04..0b482f5b5b3b 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2465,7 +2465,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, * to do the newly idle load balance. */ if (idle != CPU_NEWLY_IDLE && local_group && - balance_cpu != this_cpu && balance) { + balance_cpu != this_cpu) { *balance = 0; return; } @@ -2528,7 +2528,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, update_sg_lb_stats(sd, group, this_cpu, idle, load_idx, sd_idle, local_group, cpus, balance, &sgs); - if (local_group && balance && !(*balance)) + if (local_group && !(*balance)) return; sds->total_load += sgs.group_load; @@ -2720,7 +2720,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, * 5) The imbalance is within the specified limit. * 6) Any rebalance would lead to ping-pong */ - if (balance && !(*balance)) + if (!(*balance)) goto ret; if (!sds.busiest || sds.busiest_nr_running == 0) -- GitLab From 871e35bc9733f273eaf5ceb69bbd0423b58e5285 Mon Sep 17 00:00:00 2001 From: Gautham R Shenoy Date: Wed, 20 Jan 2010 14:02:44 -0600 Subject: [PATCH 1064/3892] sched: Fix the place where group powers are updated We want to update the sched_group_powers when balance_cpu == this_cpu. Currently the group powers are updated only if the balance_cpu is the first CPU in the local group. But balance_cpu = this_cpu could also be the first idle cpu in the group. Hence fix the place where the group powers are updated. Signed-off-by: Gautham R Shenoy Signed-off-by: Joel Schopp Signed-off-by: Peter Zijlstra LKML-Reference: <1264017764.5717.127.camel@jschopp-laptop> Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 0b482f5b5b3b..22231ccb2f98 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2418,11 +2418,8 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, unsigned long sum_avg_load_per_task; unsigned long avg_load_per_task; - if (local_group) { + if (local_group) balance_cpu = group_first_cpu(group); - if (balance_cpu == this_cpu) - update_group_power(sd, this_cpu); - } /* Tally up the load of all CPUs in the group */ sum_avg_load_per_task = avg_load_per_task = 0; @@ -2470,6 +2467,8 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, return; } + update_group_power(sd, this_cpu); + /* Adjust by relative CPU power of the group */ sgs->avg_load = (sgs->group_load * SCHED_LOAD_SCALE) / group->cpu_power; -- GitLab From 7c9414385ebfdd87cc542d4e7e3bb0dbb2d3ce25 Mon Sep 17 00:00:00 2001 From: Dhaval Giani Date: Wed, 20 Jan 2010 13:26:18 +0100 Subject: [PATCH 1065/3892] sched: Remove USER_SCHED Remove the USER_SCHED feature. It has been scheduled to be removed in 2.6.34 as per http://marc.info/?l=linux-kernel&m=125728479022976&w=2 Signed-off-by: Dhaval Giani Signed-off-by: Peter Zijlstra LKML-Reference: <1263990378.24844.3.camel@localhost> Signed-off-by: Ingo Molnar --- Documentation/feature-removal-schedule.txt | 15 - include/linux/sched.h | 14 +- init/Kconfig | 81 ++---- kernel/ksysfs.c | 8 - kernel/sched.c | 114 +------- kernel/sys.c | 5 - kernel/user.c | 305 --------------------- 7 files changed, 38 insertions(+), 504 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 870d190fe617..04a3fc3d139b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,21 +6,6 @@ be removed from this file. --------------------------- -What: USER_SCHED -When: 2.6.34 - -Why: USER_SCHED was implemented as a proof of concept for group scheduling. - The effect of USER_SCHED can already be achieved from userspace with - the help of libcgroup. The removal of USER_SCHED will also simplify - the scheduler code with the removal of one major ifdef. There are also - issues USER_SCHED has with USER_NS. A decision was taken not to fix - those and instead remove USER_SCHED. Also new group scheduling - features will not be implemented for USER_SCHED. - -Who: Dhaval Giani - ---------------------------- - What: PRISM54 When: 2.6.34 diff --git a/include/linux/sched.h b/include/linux/sched.h index 50d685cde70e..8b079735ae5f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -731,14 +731,6 @@ struct user_struct { uid_t uid; struct user_namespace *user_ns; -#ifdef CONFIG_USER_SCHED - struct task_group *tg; -#ifdef CONFIG_SYSFS - struct kobject kobj; - struct delayed_work work; -#endif -#endif - #ifdef CONFIG_PERF_EVENTS atomic_long_t locked_vm; #endif @@ -2502,13 +2494,9 @@ extern long sched_getaffinity(pid_t pid, struct cpumask *mask); extern void normalize_rt_tasks(void); -#ifdef CONFIG_GROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED extern struct task_group init_task_group; -#ifdef CONFIG_USER_SCHED -extern struct task_group root_task_group; -extern void set_tg_uid(struct user_struct *user); -#endif extern struct task_group *sched_create_group(struct task_group *parent); extern void sched_destroy_group(struct task_group *tg); diff --git a/init/Kconfig b/init/Kconfig index a23da9f01803..e9fa3007a6fc 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -435,57 +435,6 @@ config LOG_BUF_SHIFT config HAVE_UNSTABLE_SCHED_CLOCK bool -config GROUP_SCHED - bool "Group CPU scheduler" - depends on EXPERIMENTAL - default n - help - This feature lets CPU scheduler recognize task groups and control CPU - bandwidth allocation to such task groups. - In order to create a group from arbitrary set of processes, use - CONFIG_CGROUPS. (See Control Group support.) - -config FAIR_GROUP_SCHED - bool "Group scheduling for SCHED_OTHER" - depends on GROUP_SCHED - default GROUP_SCHED - -config RT_GROUP_SCHED - bool "Group scheduling for SCHED_RR/FIFO" - depends on EXPERIMENTAL - depends on GROUP_SCHED - default n - help - This feature lets you explicitly allocate real CPU bandwidth - to users or control groups (depending on the "Basis for grouping tasks" - setting below. If enabled, it will also make it impossible to - schedule realtime tasks for non-root users until you allocate - realtime bandwidth for them. - See Documentation/scheduler/sched-rt-group.txt for more information. - -choice - depends on GROUP_SCHED - prompt "Basis for grouping tasks" - default USER_SCHED - -config USER_SCHED - bool "user id" - help - This option will choose userid as the basis for grouping - tasks, thus providing equal CPU bandwidth to each user. - -config CGROUP_SCHED - bool "Control groups" - depends on CGROUPS - help - This option allows you to create arbitrary task groups - using the "cgroup" pseudo filesystem and control - the cpu bandwidth allocated to each such task group. - Refer to Documentation/cgroups/cgroups.txt for more - information on "cgroup" pseudo filesystem. - -endchoice - menuconfig CGROUPS boolean "Control Group support" help @@ -606,6 +555,36 @@ config CGROUP_MEM_RES_CTLR_SWAP Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page size is 4096bytes, 512k per 1Gbytes of swap. +menuconfig CGROUP_SCHED + bool "Group CPU scheduler" + depends on EXPERIMENTAL && CGROUPS + default n + help + This feature lets CPU scheduler recognize task groups and control CPU + bandwidth allocation to such task groups. It uses cgroups to group + tasks. + +if CGROUP_SCHED +config FAIR_GROUP_SCHED + bool "Group scheduling for SCHED_OTHER" + depends on CGROUP_SCHED + default CGROUP_SCHED + +config RT_GROUP_SCHED + bool "Group scheduling for SCHED_RR/FIFO" + depends on EXPERIMENTAL + depends on CGROUP_SCHED + default n + help + This feature lets you explicitly allocate real CPU bandwidth + to users or control groups (depending on the "Basis for grouping tasks" + setting below. If enabled, it will also make it impossible to + schedule realtime tasks for non-root users until you allocate + realtime bandwidth for them. + See Documentation/scheduler/sched-rt-group.txt for more information. + +endif #CGROUP_SCHED + endif # CGROUPS config MM_OWNER diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 3feaf5a74514..6b1ccc3f0205 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -197,16 +197,8 @@ static int __init ksysfs_init(void) goto group_exit; } - /* create the /sys/kernel/uids/ directory */ - error = uids_sysfs_init(); - if (error) - goto notes_exit; - return 0; -notes_exit: - if (notes_size > 0) - sysfs_remove_bin_file(kernel_kobj, ¬es_attr); group_exit: sysfs_remove_group(kernel_kobj, &kernel_attr_group); kset_exit: diff --git a/kernel/sched.c b/kernel/sched.c index c0be07932a8d..41e76d325648 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -233,7 +233,7 @@ static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b) */ static DEFINE_MUTEX(sched_domains_mutex); -#ifdef CONFIG_GROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED #include @@ -243,13 +243,7 @@ static LIST_HEAD(task_groups); /* task group related information */ struct task_group { -#ifdef CONFIG_CGROUP_SCHED struct cgroup_subsys_state css; -#endif - -#ifdef CONFIG_USER_SCHED - uid_t uid; -#endif #ifdef CONFIG_FAIR_GROUP_SCHED /* schedulable entities of this group on each cpu */ @@ -274,35 +268,7 @@ struct task_group { struct list_head children; }; -#ifdef CONFIG_USER_SCHED - -/* Helper function to pass uid information to create_sched_user() */ -void set_tg_uid(struct user_struct *user) -{ - user->tg->uid = user->uid; -} - -/* - * Root task group. - * Every UID task group (including init_task_group aka UID-0) will - * be a child to this group. - */ -struct task_group root_task_group; - -#ifdef CONFIG_FAIR_GROUP_SCHED -/* Default task group's sched entity on each cpu */ -static DEFINE_PER_CPU(struct sched_entity, init_sched_entity); -/* Default task group's cfs_rq on each cpu */ -static DEFINE_PER_CPU_SHARED_ALIGNED(struct cfs_rq, init_tg_cfs_rq); -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -#ifdef CONFIG_RT_GROUP_SCHED -static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity); -static DEFINE_PER_CPU_SHARED_ALIGNED(struct rt_rq, init_rt_rq_var); -#endif /* CONFIG_RT_GROUP_SCHED */ -#else /* !CONFIG_USER_SCHED */ #define root_task_group init_task_group -#endif /* CONFIG_USER_SCHED */ /* task_group_lock serializes add/remove of task groups and also changes to * a task group's cpu shares. @@ -318,11 +284,7 @@ static int root_task_group_empty(void) } #endif -#ifdef CONFIG_USER_SCHED -# define INIT_TASK_GROUP_LOAD (2*NICE_0_LOAD) -#else /* !CONFIG_USER_SCHED */ # define INIT_TASK_GROUP_LOAD NICE_0_LOAD -#endif /* CONFIG_USER_SCHED */ /* * A weight of 0 or 1 can cause arithmetics problems. @@ -348,11 +310,7 @@ static inline struct task_group *task_group(struct task_struct *p) { struct task_group *tg; -#ifdef CONFIG_USER_SCHED - rcu_read_lock(); - tg = __task_cred(p)->user->tg; - rcu_read_unlock(); -#elif defined(CONFIG_CGROUP_SCHED) +#ifdef CONFIG_CGROUP_SCHED tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id), struct task_group, css); #else @@ -383,7 +341,7 @@ static inline struct task_group *task_group(struct task_struct *p) return NULL; } -#endif /* CONFIG_GROUP_SCHED */ +#endif /* CONFIG_CGROUP_SCHED */ /* CFS-related fields in a runqueue */ struct cfs_rq { @@ -7678,9 +7636,6 @@ void __init sched_init(void) #ifdef CONFIG_RT_GROUP_SCHED alloc_size += 2 * nr_cpu_ids * sizeof(void **); #endif -#ifdef CONFIG_USER_SCHED - alloc_size *= 2; -#endif #ifdef CONFIG_CPUMASK_OFFSTACK alloc_size += num_possible_cpus() * cpumask_size(); #endif @@ -7694,13 +7649,6 @@ void __init sched_init(void) init_task_group.cfs_rq = (struct cfs_rq **)ptr; ptr += nr_cpu_ids * sizeof(void **); -#ifdef CONFIG_USER_SCHED - root_task_group.se = (struct sched_entity **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - - root_task_group.cfs_rq = (struct cfs_rq **)ptr; - ptr += nr_cpu_ids * sizeof(void **); -#endif /* CONFIG_USER_SCHED */ #endif /* CONFIG_FAIR_GROUP_SCHED */ #ifdef CONFIG_RT_GROUP_SCHED init_task_group.rt_se = (struct sched_rt_entity **)ptr; @@ -7709,13 +7657,6 @@ void __init sched_init(void) init_task_group.rt_rq = (struct rt_rq **)ptr; ptr += nr_cpu_ids * sizeof(void **); -#ifdef CONFIG_USER_SCHED - root_task_group.rt_se = (struct sched_rt_entity **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - - root_task_group.rt_rq = (struct rt_rq **)ptr; - ptr += nr_cpu_ids * sizeof(void **); -#endif /* CONFIG_USER_SCHED */ #endif /* CONFIG_RT_GROUP_SCHED */ #ifdef CONFIG_CPUMASK_OFFSTACK for_each_possible_cpu(i) { @@ -7735,22 +7676,13 @@ void __init sched_init(void) #ifdef CONFIG_RT_GROUP_SCHED init_rt_bandwidth(&init_task_group.rt_bandwidth, global_rt_period(), global_rt_runtime()); -#ifdef CONFIG_USER_SCHED - init_rt_bandwidth(&root_task_group.rt_bandwidth, - global_rt_period(), RUNTIME_INF); -#endif /* CONFIG_USER_SCHED */ #endif /* CONFIG_RT_GROUP_SCHED */ -#ifdef CONFIG_GROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED list_add(&init_task_group.list, &task_groups); INIT_LIST_HEAD(&init_task_group.children); -#ifdef CONFIG_USER_SCHED - INIT_LIST_HEAD(&root_task_group.children); - init_task_group.parent = &root_task_group; - list_add(&init_task_group.siblings, &root_task_group.children); -#endif /* CONFIG_USER_SCHED */ -#endif /* CONFIG_GROUP_SCHED */ +#endif /* CONFIG_CGROUP_SCHED */ #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP update_shares_data = __alloc_percpu(nr_cpu_ids * sizeof(unsigned long), @@ -7790,25 +7722,6 @@ void __init sched_init(void) * directly in rq->cfs (i.e init_task_group->se[] = NULL). */ init_tg_cfs_entry(&init_task_group, &rq->cfs, NULL, i, 1, NULL); -#elif defined CONFIG_USER_SCHED - root_task_group.shares = NICE_0_LOAD; - init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, 0, NULL); - /* - * In case of task-groups formed thr' the user id of tasks, - * init_task_group represents tasks belonging to root user. - * Hence it forms a sibling of all subsequent groups formed. - * In this case, init_task_group gets only a fraction of overall - * system cpu resource, based on the weight assigned to root - * user's cpu share (INIT_TASK_GROUP_LOAD). This is accomplished - * by letting tasks of init_task_group sit in a separate cfs_rq - * (init_tg_cfs_rq) and having one entity represent this group of - * tasks in rq->cfs (i.e init_task_group->se[] != NULL). - */ - init_tg_cfs_entry(&init_task_group, - &per_cpu(init_tg_cfs_rq, i), - &per_cpu(init_sched_entity, i), i, 1, - root_task_group.se[i]); - #endif #endif /* CONFIG_FAIR_GROUP_SCHED */ @@ -7817,12 +7730,6 @@ void __init sched_init(void) INIT_LIST_HEAD(&rq->leaf_rt_rq_list); #ifdef CONFIG_CGROUP_SCHED init_tg_rt_entry(&init_task_group, &rq->rt, NULL, i, 1, NULL); -#elif defined CONFIG_USER_SCHED - init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, 0, NULL); - init_tg_rt_entry(&init_task_group, - &per_cpu(init_rt_rq_var, i), - &per_cpu(init_sched_rt_entity, i), i, 1, - root_task_group.rt_se[i]); #endif #endif @@ -8218,7 +8125,7 @@ static inline void unregister_rt_sched_group(struct task_group *tg, int cpu) } #endif /* CONFIG_RT_GROUP_SCHED */ -#ifdef CONFIG_GROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED static void free_sched_group(struct task_group *tg) { free_fair_sched_group(tg); @@ -8327,7 +8234,7 @@ void sched_move_task(struct task_struct *tsk) task_rq_unlock(rq, &flags); } -#endif /* CONFIG_GROUP_SCHED */ +#endif /* CONFIG_CGROUP_SCHED */ #ifdef CONFIG_FAIR_GROUP_SCHED static void __set_se_shares(struct sched_entity *se, unsigned long shares) @@ -8469,13 +8376,6 @@ static int tg_schedulable(struct task_group *tg, void *data) runtime = d->rt_runtime; } -#ifdef CONFIG_USER_SCHED - if (tg == &root_task_group) { - period = global_rt_period(); - runtime = global_rt_runtime(); - } -#endif - /* * Cannot have more runtime than the period. */ diff --git a/kernel/sys.c b/kernel/sys.c index 26a6b73a6b85..f75bf0936f47 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -569,11 +569,6 @@ static int set_user(struct cred *new) if (!new_user) return -EAGAIN; - if (!task_can_switch_user(new_user, current)) { - free_uid(new_user); - return -EINVAL; - } - if (atomic_read(&new_user->processes) >= current->signal->rlim[RLIMIT_NPROC].rlim_cur && new_user != INIT_USER) { diff --git a/kernel/user.c b/kernel/user.c index 46d0165ca70c..766467b3bcb7 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -56,9 +56,6 @@ struct user_struct root_user = { .sigpending = ATOMIC_INIT(0), .locked_shm = 0, .user_ns = &init_user_ns, -#ifdef CONFIG_USER_SCHED - .tg = &init_task_group, -#endif }; /* @@ -75,268 +72,6 @@ static void uid_hash_remove(struct user_struct *up) put_user_ns(up->user_ns); } -#ifdef CONFIG_USER_SCHED - -static void sched_destroy_user(struct user_struct *up) -{ - sched_destroy_group(up->tg); -} - -static int sched_create_user(struct user_struct *up) -{ - int rc = 0; - - up->tg = sched_create_group(&root_task_group); - if (IS_ERR(up->tg)) - rc = -ENOMEM; - - set_tg_uid(up); - - return rc; -} - -#else /* CONFIG_USER_SCHED */ - -static void sched_destroy_user(struct user_struct *up) { } -static int sched_create_user(struct user_struct *up) { return 0; } - -#endif /* CONFIG_USER_SCHED */ - -#if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS) - -static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) -{ - struct user_struct *user; - struct hlist_node *h; - - hlist_for_each_entry(user, h, hashent, uidhash_node) { - if (user->uid == uid) { - /* possibly resurrect an "almost deleted" object */ - if (atomic_inc_return(&user->__count) == 1) - cancel_delayed_work(&user->work); - return user; - } - } - - return NULL; -} - -static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */ -static DEFINE_MUTEX(uids_mutex); - -static inline void uids_mutex_lock(void) -{ - mutex_lock(&uids_mutex); -} - -static inline void uids_mutex_unlock(void) -{ - mutex_unlock(&uids_mutex); -} - -/* uid directory attributes */ -#ifdef CONFIG_FAIR_GROUP_SCHED -static ssize_t cpu_shares_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - - return sprintf(buf, "%lu\n", sched_group_shares(up->tg)); -} - -static ssize_t cpu_shares_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t size) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - unsigned long shares; - int rc; - - sscanf(buf, "%lu", &shares); - - rc = sched_group_set_shares(up->tg, shares); - - return (rc ? rc : size); -} - -static struct kobj_attribute cpu_share_attr = - __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store); -#endif - -#ifdef CONFIG_RT_GROUP_SCHED -static ssize_t cpu_rt_runtime_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - - return sprintf(buf, "%ld\n", sched_group_rt_runtime(up->tg)); -} - -static ssize_t cpu_rt_runtime_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t size) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - unsigned long rt_runtime; - int rc; - - sscanf(buf, "%ld", &rt_runtime); - - rc = sched_group_set_rt_runtime(up->tg, rt_runtime); - - return (rc ? rc : size); -} - -static struct kobj_attribute cpu_rt_runtime_attr = - __ATTR(cpu_rt_runtime, 0644, cpu_rt_runtime_show, cpu_rt_runtime_store); - -static ssize_t cpu_rt_period_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - - return sprintf(buf, "%lu\n", sched_group_rt_period(up->tg)); -} - -static ssize_t cpu_rt_period_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t size) -{ - struct user_struct *up = container_of(kobj, struct user_struct, kobj); - unsigned long rt_period; - int rc; - - sscanf(buf, "%lu", &rt_period); - - rc = sched_group_set_rt_period(up->tg, rt_period); - - return (rc ? rc : size); -} - -static struct kobj_attribute cpu_rt_period_attr = - __ATTR(cpu_rt_period, 0644, cpu_rt_period_show, cpu_rt_period_store); -#endif - -/* default attributes per uid directory */ -static struct attribute *uids_attributes[] = { -#ifdef CONFIG_FAIR_GROUP_SCHED - &cpu_share_attr.attr, -#endif -#ifdef CONFIG_RT_GROUP_SCHED - &cpu_rt_runtime_attr.attr, - &cpu_rt_period_attr.attr, -#endif - NULL -}; - -/* the lifetime of user_struct is not managed by the core (now) */ -static void uids_release(struct kobject *kobj) -{ - return; -} - -static struct kobj_type uids_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = uids_attributes, - .release = uids_release, -}; - -/* - * Create /sys/kernel/uids//cpu_share file for this user - * We do not create this file for users in a user namespace (until - * sysfs tagging is implemented). - * - * See Documentation/scheduler/sched-design-CFS.txt for ramifications. - */ -static int uids_user_create(struct user_struct *up) -{ - struct kobject *kobj = &up->kobj; - int error; - - memset(kobj, 0, sizeof(struct kobject)); - if (up->user_ns != &init_user_ns) - return 0; - kobj->kset = uids_kset; - error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid); - if (error) { - kobject_put(kobj); - goto done; - } - - kobject_uevent(kobj, KOBJ_ADD); -done: - return error; -} - -/* create these entries in sysfs: - * "/sys/kernel/uids" directory - * "/sys/kernel/uids/0" directory (for root user) - * "/sys/kernel/uids/0/cpu_share" file (for root user) - */ -int __init uids_sysfs_init(void) -{ - uids_kset = kset_create_and_add("uids", NULL, kernel_kobj); - if (!uids_kset) - return -ENOMEM; - - return uids_user_create(&root_user); -} - -/* delayed work function to remove sysfs directory for a user and free up - * corresponding structures. - */ -static void cleanup_user_struct(struct work_struct *w) -{ - struct user_struct *up = container_of(w, struct user_struct, work.work); - unsigned long flags; - int remove_user = 0; - - /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del() - * atomic. - */ - uids_mutex_lock(); - - spin_lock_irqsave(&uidhash_lock, flags); - if (atomic_read(&up->__count) == 0) { - uid_hash_remove(up); - remove_user = 1; - } - spin_unlock_irqrestore(&uidhash_lock, flags); - - if (!remove_user) - goto done; - - if (up->user_ns == &init_user_ns) { - kobject_uevent(&up->kobj, KOBJ_REMOVE); - kobject_del(&up->kobj); - kobject_put(&up->kobj); - } - - sched_destroy_user(up); - key_put(up->uid_keyring); - key_put(up->session_keyring); - kmem_cache_free(uid_cachep, up); - -done: - uids_mutex_unlock(); -} - -/* IRQs are disabled and uidhash_lock is held upon function entry. - * IRQ state (as stored in flags) is restored and uidhash_lock released - * upon function exit. - */ -static void free_user(struct user_struct *up, unsigned long flags) -{ - INIT_DELAYED_WORK(&up->work, cleanup_user_struct); - schedule_delayed_work(&up->work, msecs_to_jiffies(1000)); - spin_unlock_irqrestore(&uidhash_lock, flags); -} - -#else /* CONFIG_USER_SCHED && CONFIG_SYSFS */ - static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) { struct user_struct *user; @@ -352,11 +87,6 @@ static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) return NULL; } -int uids_sysfs_init(void) { return 0; } -static inline int uids_user_create(struct user_struct *up) { return 0; } -static inline void uids_mutex_lock(void) { } -static inline void uids_mutex_unlock(void) { } - /* IRQs are disabled and uidhash_lock is held upon function entry. * IRQ state (as stored in flags) is restored and uidhash_lock released * upon function exit. @@ -365,32 +95,11 @@ static void free_user(struct user_struct *up, unsigned long flags) { uid_hash_remove(up); spin_unlock_irqrestore(&uidhash_lock, flags); - sched_destroy_user(up); key_put(up->uid_keyring); key_put(up->session_keyring); kmem_cache_free(uid_cachep, up); } -#endif - -#if defined(CONFIG_RT_GROUP_SCHED) && defined(CONFIG_USER_SCHED) -/* - * We need to check if a setuid can take place. This function should be called - * before successfully completing the setuid. - */ -int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) -{ - - return sched_rt_can_attach(up->tg, tsk); - -} -#else -int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) -{ - return 1; -} -#endif - /* * Locate the user_struct for the passed UID. If found, take a ref on it. The * caller must undo that ref with free_uid(). @@ -431,8 +140,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) /* Make uid_hash_find() + uids_user_create() + uid_hash_insert() * atomic. */ - uids_mutex_lock(); - spin_lock_irq(&uidhash_lock); up = uid_hash_find(uid, hashent); spin_unlock_irq(&uidhash_lock); @@ -445,14 +152,8 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) new->uid = uid; atomic_set(&new->__count, 1); - if (sched_create_user(new) < 0) - goto out_free_user; - new->user_ns = get_user_ns(ns); - if (uids_user_create(new)) - goto out_destoy_sched; - /* * Before adding this, check whether we raced * on adding the same user already.. @@ -475,17 +176,11 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) spin_unlock_irq(&uidhash_lock); } - uids_mutex_unlock(); - return up; -out_destoy_sched: - sched_destroy_user(new); put_user_ns(new->user_ns); -out_free_user: kmem_cache_free(uid_cachep, new); out_unlock: - uids_mutex_unlock(); return NULL; } -- GitLab From fd0b092a7b14559e2ff17ef3aaefb5d8adc7e15f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 21 Jan 2010 14:54:38 +0100 Subject: [PATCH 1066/3892] ALSA: hda - AD1988 codec - fix SPDIF-input mixer initialization (unmute) The SPDIF-input pin 0x1c is muted by default in hardware. Unmute appropriate pin to get captured samples instead zeros. Tested on Lenovo Thinkstation. Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index cecd3c108990..865715e3f938 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2458,6 +2458,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { { } }; +static struct hda_verb ad1988_spdif_in_init_verbs[] = { + /* unmute SPDIF input pin */ + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } +}; + /* AD1989 has no ADC -> SPDIF route */ static struct hda_verb ad1989_spdif_init_verbs[] = { /* SPDIF-1 out pin */ @@ -3193,8 +3199,11 @@ static int patch_ad1988(struct hda_codec *codec) ad1988_spdif_init_verbs; } } - if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) + if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; + spec->init_verbs[spec->num_init_verbs++] = + ad1988_spdif_in_init_verbs; + } codec->patch_ops = ad198x_patch_ops; switch (board_config) { -- GitLab From c587b6fa05106606053fc5e8e344f07cd34ace23 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 21 Jan 2010 10:41:10 +0800 Subject: [PATCH 1067/3892] spi/dw_spi: add a FIFO depth detection FIFO depth is configurable for each implementation of DW core, so add a depth detection for those interface drivers who don't set the fifo_len explicitly Signed-off-by: Feng Tang Acked-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index f713af8309e3..d948ef4f3910 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -831,6 +831,22 @@ static void spi_hw_init(struct dw_spi *dws) spi_mask_intr(dws, 0xff); spi_enable_chip(dws, 1); flush(dws); + + /* + * Try to detect the FIFO depth if not set by interface driver, + * the depth could be from 2 to 256 from HW spec + */ + if (!dws->fifo_len) { + u32 fifo; + for (fifo = 2; fifo <= 257; fifo++) { + dw_writew(dws, txfltr, fifo); + if (fifo != dw_readw(dws, txfltr)) + break; + } + + dws->fifo_len = (fifo == 257) ? 0 : fifo; + dw_writew(dws, txfltr, 0); + } } int __devinit dw_spi_add_host(struct dw_spi *dws) -- GitLab From 83fe518a839e317480e50a138ef4acd73510d7ce Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:48 +0000 Subject: [PATCH 1068/3892] spi/dw_spi: enable platform specific chipselect. The driver core allows for a platform-specific chipselect assert/deassert function, however the chipselect function in the core doesn't take advantage of this fact. This enables the use of a custom function, should it be defined. Signed-off-by: George Shore Signed-off-by: Grant Likely --- include/linux/spi/dw_spi.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h index 1a127a31e017..cc813f95a2f2 100644 --- a/include/linux/spi/dw_spi.h +++ b/include/linux/spi/dw_spi.h @@ -172,6 +172,10 @@ static inline void spi_chip_sel(struct dw_spi *dws, u16 cs) { if (cs > dws->num_cs) return; + + if (dws->cs_control) + dws->cs_control(1); + dw_writel(dws, ser, 1 << cs); } -- GitLab From 20a588fcc862df79d8fcafbc41950e3ae93dea09 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:49 +0000 Subject: [PATCH 1069/3892] spi/dw_spi: add return value to empty mrst_spi_debugfs_init() As per the function signature. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d948ef4f3910..cf945a4cc419 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -152,6 +152,7 @@ static void mrst_spi_debugfs_remove(struct dw_spi *dws) #else static inline int mrst_spi_debugfs_init(struct dw_spi *dws) { + return 0; } static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) -- GitLab From 426c0093d8da4d7b6b0e62cda917b1bae26db4c2 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:50 +0000 Subject: [PATCH 1070/3892] spi/dw_spi: fixed a spelling typo in a warning message. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index cf945a4cc419..d0a080a5b598 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -169,7 +169,7 @@ static void wait_till_not_busy(struct dw_spi *dws) return; } dev_err(&dws->master->dev, - "DW SPI: Stutus keeps busy for 1000us after a read/write!\n"); + "DW SPI: Status keeps busy for 1000us after a read/write!\n"); } static void flush(struct dw_spi *dws) -- GitLab From f4aec798ae5a837a1f062e295f9a5f1b00962589 Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:51 +0000 Subject: [PATCH 1071/3892] spi/dw_spi: remove conditional from 'poll_transfer'. The 'poll_transfer' function employs a conditional to test whether the transmit buffer is valid; in doing so, on a receive operation no data is clocked out, thus no data is clocked in and ultimately errors appear. This removes the conditional as the transmit function will be set to a null writer when the transmit buffer is invalid, allowing the driver to clock 0x00 out to the device to receive data from the device. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d0a080a5b598..3853df5db052 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -408,12 +408,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) /* Must be called inside pump_transfers() */ static void poll_transfer(struct dw_spi *dws) { - if (dws->tx) { - while (dws->write(dws)) - dws->read(dws); - } + while (dws->write(dws)) + dws->read(dws); - dws->read(dws); transfer_complete(dws); } -- GitLab From 052dc7c45d8f685fb3720a08331ba3e91e87937e Mon Sep 17 00:00:00 2001 From: George Shore Date: Thu, 21 Jan 2010 11:40:52 +0000 Subject: [PATCH 1072/3892] spi/dw_spi: conditional transfer mode changes This allows the switching between transfer modes between 'transmit only', 'receive only' and 'transmit and receive' modes. Due to the design of the SPI block, changing transfer modes requires that the block be disabled; in doing so the chipselect line is inherently deasserted and (usually) the attached device discards its state. Consequentially, switching modes requires that a platform-specific chipselect function has been defined so that the chipselect is not dropped during the change. Signed-off-by: George Shore Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 3853df5db052..e434320fded8 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -537,6 +537,22 @@ static void pump_transfers(unsigned long data) } message->state = RUNNING_STATE; + /* + * Adjust transfer mode if necessary. Requires platform dependent + * chipselect mechanism. + */ + if (dws->cs_control) { + if (dws->rx && dws->tx) + chip->tmode = 0x00; + else if (dws->rx) + chip->tmode = 0x02; + else + chip->tmode = 0x01; + + cr0 &= ~(0x3 << SPI_MODE_OFFSET); + cr0 |= (chip->tmode << SPI_TMOD_OFFSET); + } + /* Check if current transfer is a DMA transaction */ dws->dma_mapped = map_dma_buffers(dws); -- GitLab From 8bcb4a88c5834c6a0fc7140edea32186664fe360 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 21 Jan 2010 07:25:38 -0700 Subject: [PATCH 1073/3892] spi/dw_spi: fix missing export of dw_spi_remove_host So that interface drivers could be built as modules Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index e434320fded8..8ed38f1d6c18 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -957,6 +957,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) /* Disconnect from the SPI framework */ spi_unregister_master(dws->master); } +EXPORT_SYMBOL(dw_spi_remove_host); int dw_spi_suspend_host(struct dw_spi *dws) { -- GitLab From f7b6fd6d1d3833529f1626c761ba7e338586d35e Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 07:46:42 -0700 Subject: [PATCH 1074/3892] Memory-mapped dw_spi driver Adds a memory-mapped I/O dw_spi platform device. Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 4 ++ drivers/spi/Makefile | 1 + drivers/spi/dw_spi_mmio.c | 148 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 drivers/spi/dw_spi_mmio.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 28becdd4dea9..201746ad825c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -334,6 +334,10 @@ config SPI_DW_PCI tristate "PCI interface driver for DW SPI core" depends on SPI_DESIGNWARE && PCI +config SPI_DW_MMIO + tristate "Memory-mapped io interface driver for DW SPI core" + depends on SPI_DESIGNWARE + # # There are lots of SPI device types, with sensors and memory # being probably the most widely used ones. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d3a65ab8ebbf..d7d0f89b797b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o +obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c new file mode 100644 index 000000000000..26c4b49bdd5c --- /dev/null +++ b/drivers/spi/dw_spi_mmio.c @@ -0,0 +1,148 @@ +/* + * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core + * + * Copyright (c) 2010, Octasic semiconductor. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DRIVER_NAME "dw_spi_mmio" + +struct dw_spi_mmio { + struct dw_spi dws; + struct clk *clk; +}; + +static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) +{ + struct dw_spi_mmio *dwsmmio; + struct dw_spi *dws; + struct resource *mem, *ioarea; + int ret; + + dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL); + if (!dwsmmio) { + ret = -ENOMEM; + goto err_end; + } + + dws = &dwsmmio->dws; + + /* Get basic io resource and map it */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + ret = -EINVAL; + goto err_kfree; + } + + ioarea = request_mem_region(mem->start, resource_size(mem), + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "SPI region already claimed\n"); + ret = -EBUSY; + goto err_kfree; + } + + dws->regs = ioremap_nocache(mem->start, resource_size(mem)); + if (!dws->regs) { + dev_err(&pdev->dev, "SPI region already mapped\n"); + ret = -ENOMEM; + goto err_release_reg; + } + + dws->irq = platform_get_irq(pdev, 0); + if (dws->irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + ret = dws->irq; /* -ENXIO */ + goto err_unmap; + } + + dwsmmio->clk = clk_get(&pdev->dev, NULL); + if (!dwsmmio->clk) { + ret = -ENODEV; + goto err_irq; + } + clk_enable(dwsmmio->clk); + + dws->parent_dev = &pdev->dev; + dws->bus_num = 0; + dws->num_cs = 4; + dws->max_freq = clk_get_rate(dwsmmio->clk); + + ret = dw_spi_add_host(dws); + if (ret) + goto err_clk; + + platform_set_drvdata(pdev, dwsmmio); + return 0; + +err_clk: + clk_disable(dwsmmio->clk); + clk_put(dwsmmio->clk); + dwsmmio->clk = NULL; +err_irq: + free_irq(dws->irq, dws); +err_unmap: + iounmap(dws->regs); +err_release_reg: + release_mem_region(mem->start, resource_size(mem)); +err_kfree: + kfree(dwsmmio); +err_end: + return ret; +} + +static int __devexit dw_spi_mmio_remove(struct platform_device *pdev) +{ + struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + + clk_disable(dwsmmio->clk); + clk_put(dwsmmio->clk); + dwsmmio->clk = NULL; + + free_irq(dwsmmio->dws.irq, &dwsmmio->dws); + dw_spi_remove_host(&dwsmmio->dws); + iounmap(dwsmmio->dws.regs); + kfree(dwsmmio); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + return 0; +} + +static struct platform_driver dw_spi_mmio_driver = { + .remove = __devexit_p(dw_spi_mmio_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init dw_spi_mmio_init(void) +{ + return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); +} + +static void __exit dw_spi_mmio_exit(void) +{ + platform_driver_unregister(&dw_spi_mmio_driver); +} + +module_init(dw_spi_mmio_init); +module_exit(dw_spi_mmio_exit); + +MODULE_AUTHOR("Jean-Hugues Deschenes "); +MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); +MODULE_LICENSE("GPL v2"); -- GitLab From 0a4c1d7d446d3ed6179f907541d180e49b56d4f4 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 09:55:42 -0700 Subject: [PATCH 1075/3892] spi/dw_spi: mmio code style fixups Minor code style cleanups following comments by Wolfram Sang Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/dw_spi_mmio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c index 26c4b49bdd5c..e35b45ac5174 100644 --- a/drivers/spi/dw_spi_mmio.c +++ b/drivers/spi/dw_spi_mmio.c @@ -17,8 +17,8 @@ #define DRIVER_NAME "dw_spi_mmio" struct dw_spi_mmio { - struct dw_spi dws; - struct clk *clk; + struct dw_spi dws; + struct clk *clk; }; static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) @@ -134,13 +134,12 @@ static int __init dw_spi_mmio_init(void) { return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe); } +module_init(dw_spi_mmio_init); static void __exit dw_spi_mmio_exit(void) { platform_driver_unregister(&dw_spi_mmio_driver); } - -module_init(dw_spi_mmio_init); module_exit(dw_spi_mmio_exit); MODULE_AUTHOR("Jean-Hugues Deschenes "); -- GitLab From 8ca8d15ade201b7723fa386eadcce2044463ff56 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Thu, 21 Jan 2010 09:55:54 -0700 Subject: [PATCH 1076/3892] spi/dw_spi: Allow dw_spi.c to be a module Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 201746ad825c..1d1e39686c38 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -325,7 +325,7 @@ config SPI_NUC900 # config SPI_DESIGNWARE - bool "DesignWare SPI controller core support" + tristate "DesignWare SPI controller core support" depends on SPI_MASTER help general driver for SPI controller core from DesignWare -- GitLab From 512dd1abd9539a474f2792eeaf6783c59ad7778a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jan 2010 22:05:48 +0000 Subject: [PATCH 1077/3892] xfs: kill XFS_QMOPT_ASYNC The option is unused and one of the few remaining users of xfs_bawrite, so let's get rid of it. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_dquot.c | 2 -- fs/xfs/xfs_quota.h | 1 - 2 files changed, 3 deletions(-) diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index d7c7eea09fc2..a447493690eb 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1253,8 +1253,6 @@ xfs_qm_dqflush( if (flags & XFS_QMOPT_DELWRI) { xfs_bdwrite(mp, bp); - } else if (flags & XFS_QMOPT_ASYNC) { - error = xfs_bawrite(mp, bp); } else { error = xfs_bwrite(mp, bp); } diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 91bfd60f4c74..21d11d9f48f2 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -226,7 +226,6 @@ typedef struct xfs_qoff_logformat { * flags for dqflush and dqflush_all. */ #define XFS_QMOPT_SYNC 0x1000000 -#define XFS_QMOPT_ASYNC 0x2000000 #define XFS_QMOPT_DELWRI 0x4000000 /* -- GitLab From 4d1f88d75b00c4d23f4c51305ab5b779a86ef74e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Jan 2010 22:05:49 +0000 Subject: [PATCH 1078/3892] xfs: clean up error handling in xfs_trans_dqresv Move the error code selection after the goto label and fold the xfs_quota_error helper into it. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_trans_dquot.c | 48 ++++++++++++---------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 97ac9640be98..b9db6f781cd6 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -589,14 +589,6 @@ xfs_trans_unreserve_and_mod_dquots( } } -STATIC int -xfs_quota_error(uint flags) -{ - if (flags & XFS_QMOPT_ENOSPC) - return ENOSPC; - return EDQUOT; -} - /* * This reserves disk blocks and inodes against a dquot. * Flags indicate if the dquot is to be locked here and also @@ -612,7 +604,6 @@ xfs_trans_dqresv( long ninos, uint flags) { - int error; xfs_qcnt_t hardlimit; xfs_qcnt_t softlimit; time_t timer; @@ -649,7 +640,6 @@ xfs_trans_dqresv( warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount); resbcountp = &dqp->q_res_rtbcount; } - error = 0; if ((flags & XFS_QMOPT_FORCE_RES) == 0 && dqp->q_core.d_id && @@ -667,19 +657,13 @@ xfs_trans_dqresv( * nblks. */ if (hardlimit > 0ULL && - (hardlimit <= nblks + *resbcountp)) { - error = xfs_quota_error(flags); + hardlimit <= nblks + *resbcountp) goto error_return; - } - if (softlimit > 0ULL && - (softlimit <= nblks + *resbcountp)) { - if ((timer != 0 && get_seconds() > timer) || - (warns != 0 && warns >= warnlimit)) { - error = xfs_quota_error(flags); - goto error_return; - } - } + softlimit <= nblks + *resbcountp && + ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit))) + goto error_return; } if (ninos > 0) { count = be64_to_cpu(dqp->q_core.d_icount); @@ -692,16 +676,13 @@ xfs_trans_dqresv( softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit); if (!softlimit) softlimit = q->qi_isoftlimit; - if (hardlimit > 0ULL && count >= hardlimit) { - error = xfs_quota_error(flags); + + if (hardlimit > 0ULL && count >= hardlimit) + goto error_return; + if (softlimit > 0ULL && count >= softlimit && + ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit))) goto error_return; - } else if (softlimit > 0ULL && count >= softlimit) { - if ((timer != 0 && get_seconds() > timer) || - (warns != 0 && warns >= warnlimit)) { - error = xfs_quota_error(flags); - goto error_return; - } - } } } @@ -736,9 +717,14 @@ xfs_trans_dqresv( ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount)); ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount)); + xfs_dqunlock(dqp); + return 0; + error_return: xfs_dqunlock(dqp); - return error; + if (flags & XFS_QMOPT_ENOSPC) + return ENOSPC; + return EDQUOT; } -- GitLab From a210c1aa7f6c90b729cc3a72d03e789b13cb6c47 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jan 2010 22:36:19 +0000 Subject: [PATCH 1079/3892] xfs: implement quota warnings via netlink Wire up quota_send_warning to send quota warnings over netlink. This is used by various desktops to show user quota warnings. Tested by running the quota_nld daemon while running the xfstest quota tests and observing the warnings. I'll see how I can get a more formal testcase for it written. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_trans_dquot.c | 49 +++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index b9db6f781cd6..c3ab75cb1d9a 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -589,6 +589,20 @@ xfs_trans_unreserve_and_mod_dquots( } } +STATIC void +xfs_quota_warn( + struct xfs_mount *mp, + struct xfs_dquot *dqp, + int type) +{ + /* no warnings for project quotas - we just return ENOSPC later */ + if (dqp->dq_flags & XFS_DQ_PROJ) + return; + quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA, + be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev, + type); +} + /* * This reserves disk blocks and inodes against a dquot. * Flags indicate if the dquot is to be locked here and also @@ -657,13 +671,21 @@ xfs_trans_dqresv( * nblks. */ if (hardlimit > 0ULL && - hardlimit <= nblks + *resbcountp) + hardlimit <= nblks + *resbcountp) { + xfs_quota_warn(mp, dqp, QUOTA_NL_BHARDWARN); goto error_return; + } if (softlimit > 0ULL && - softlimit <= nblks + *resbcountp && - ((timer != 0 && get_seconds() > timer) || - (warns != 0 && warns >= warnlimit))) - goto error_return; + softlimit <= nblks + *resbcountp) { + if ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit)) { + xfs_quota_warn(mp, dqp, + QUOTA_NL_BSOFTLONGWARN); + goto error_return; + } + + xfs_quota_warn(mp, dqp, QUOTA_NL_BSOFTWARN); + } } if (ninos > 0) { count = be64_to_cpu(dqp->q_core.d_icount); @@ -677,12 +699,19 @@ xfs_trans_dqresv( if (!softlimit) softlimit = q->qi_isoftlimit; - if (hardlimit > 0ULL && count >= hardlimit) - goto error_return; - if (softlimit > 0ULL && count >= softlimit && - ((timer != 0 && get_seconds() > timer) || - (warns != 0 && warns >= warnlimit))) + if (hardlimit > 0ULL && count >= hardlimit) { + xfs_quota_warn(mp, dqp, QUOTA_NL_IHARDWARN); goto error_return; + } + if (softlimit > 0ULL && count >= softlimit) { + if ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit)) { + xfs_quota_warn(mp, dqp, + QUOTA_NL_ISOFTLONGWARN); + goto error_return; + } + xfs_quota_warn(mp, dqp, QUOTA_NL_ISOFTWARN); + } } } -- GitLab From 0cadda1c5f194f98a05d252ff4385d86d2ed0862 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jan 2010 09:56:44 +0000 Subject: [PATCH 1080/3892] xfs: remove duplicate buffer flags Currently we define aliases for the buffer flags in various namespaces, which only adds confusion. Remove all but the XBF_ flags to clean this up a bit. Note that we still abuse XFS_B_ASYNC/XBF_ASYNC for some non-buffer uses, but I'll clean that up later. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 2 +- fs/xfs/linux-2.6/xfs_buf.h | 22 ++++------------------ fs/xfs/linux-2.6/xfs_fs_subr.c | 2 +- fs/xfs/linux-2.6/xfs_sync.c | 4 ++-- fs/xfs/quota/xfs_dquot.c | 3 +-- fs/xfs/quota/xfs_dquot_item.c | 3 +-- fs/xfs/xfs_alloc.c | 2 +- fs/xfs/xfs_attr.c | 12 +++++------- fs/xfs/xfs_attr_leaf.c | 2 +- fs/xfs/xfs_btree.c | 4 ++-- fs/xfs/xfs_ialloc.c | 2 +- fs/xfs/xfs_inode.c | 20 ++++++++++---------- fs/xfs/xfs_inode_item.c | 2 +- fs/xfs/xfs_log_recover.c | 8 ++++---- fs/xfs/xfs_mount.c | 4 ++-- fs/xfs/xfs_trans_buf.c | 27 ++++++++++++++------------- fs/xfs/xfs_vnodeops.c | 4 ++-- 17 files changed, 53 insertions(+), 70 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index efd745bb8887..730eff1e71a3 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1169,7 +1169,7 @@ xfs_bioerror_relse( XFS_BUF_STALE(bp); XFS_BUF_CLR_IODONE_FUNC(bp); XFS_BUF_CLR_BDSTRAT_FUNC(bp); - if (!(fl & XFS_B_ASYNC)) { + if (!(fl & XBF_ASYNC)) { /* * Mark b_error and B_ERROR _both_. * Lot's of chunkcache code assumes that. diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 4f2ad66edb76..ea8c198f0c39 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -275,33 +275,19 @@ extern void xfs_buf_terminate(void); ({ char __b[BDEVNAME_SIZE]; bdevname((target)->bt_bdev, __b); __b; }) -#define XFS_B_ASYNC XBF_ASYNC -#define XFS_B_DELWRI XBF_DELWRI -#define XFS_B_READ XBF_READ -#define XFS_B_WRITE XBF_WRITE -#define XFS_B_STALE XBF_STALE - -#define XFS_BUF_TRYLOCK XBF_TRYLOCK -#define XFS_INCORE_TRYLOCK XBF_TRYLOCK -#define XFS_BUF_LOCK XBF_LOCK -#define XFS_BUF_MAPPED XBF_MAPPED - -#define BUF_BUSY XBF_DONT_BLOCK - #define XFS_BUF_BFLAGS(bp) ((bp)->b_flags) #define XFS_BUF_ZEROFLAGS(bp) ((bp)->b_flags &= \ ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI|XBF_ORDERED)) -#define XFS_BUF_STALE(bp) ((bp)->b_flags |= XFS_B_STALE) -#define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XFS_B_STALE) -#define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XFS_B_STALE) +#define XFS_BUF_STALE(bp) ((bp)->b_flags |= XBF_STALE) +#define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XBF_STALE) +#define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XBF_STALE) #define XFS_BUF_SUPER_STALE(bp) do { \ XFS_BUF_STALE(bp); \ xfs_buf_delwri_dequeue(bp); \ XFS_BUF_DONE(bp); \ } while (0) -#define XFS_BUF_MANAGE XBF_FS_MANAGED #define XFS_BUF_UNMANAGE(bp) ((bp)->b_flags &= ~XBF_FS_MANAGED) #define XFS_BUF_DELAYWRITE(bp) ((bp)->b_flags |= XBF_DELWRI) @@ -390,7 +376,7 @@ static inline void xfs_buf_relse(xfs_buf_t *bp) #define xfs_biomove(bp, off, len, data, rw) \ xfs_buf_iomove((bp), (off), (len), (data), \ - ((rw) == XFS_B_WRITE) ? XBRW_WRITE : XBRW_READ) + ((rw) == XBF_WRITE) ? XBRW_WRITE : XBRW_READ) #define xfs_biozero(bp, off, len) \ xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO) diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index 7501b85fd860..b6918d76bc7b 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c @@ -79,7 +79,7 @@ xfs_flush_pages( xfs_iflags_clear(ip, XFS_ITRUNCATED); ret = -filemap_fdatawrite(mapping); } - if (flags & XFS_B_ASYNC) + if (flags & XBF_ASYNC) return ret; ret2 = xfs_wait_on_pages(ip, first, last); if (!ret) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index b58f8412dfe2..58c24be72c65 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -234,7 +234,7 @@ xfs_sync_inode_data( } error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ? - 0 : XFS_B_ASYNC, FI_NONE); + 0 : XBF_ASYNC, FI_NONE); xfs_iunlock(ip, XFS_IOLOCK_SHARED); out_wait: @@ -370,7 +370,7 @@ xfs_sync_fsdata( if (flags & SYNC_TRYLOCK) { ASSERT(!(flags & SYNC_WAIT)); - bp = xfs_getsb(mp, XFS_BUF_TRYLOCK); + bp = xfs_getsb(mp, XBF_TRYLOCK); if (!bp) goto out; diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index a447493690eb..5756392ffdee 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1527,8 +1527,7 @@ xfs_qm_dqflock_pushbuf_wait( * the flush lock when the I/O completes. */ bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno, - XFS_QI_DQCHUNKLEN(dqp->q_mount), - XFS_INCORE_TRYLOCK); + XFS_QI_DQCHUNKLEN(dqp->q_mount), XBF_TRYLOCK); if (bp != NULL) { if (XFS_BUF_ISDELAYWRITE(bp)) { int error; diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index d0d4a9a0bbd7..37929d19ef44 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -237,8 +237,7 @@ xfs_qm_dquot_logitem_pushbuf( } mp = dqp->q_mount; bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, - XFS_QI_DQCHUNKLEN(mp), - XFS_INCORE_TRYLOCK); + XFS_QI_DQCHUNKLEN(mp), XBF_TRYLOCK); if (bp != NULL) { if (XFS_BUF_ISDELAYWRITE(bp)) { dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 8aa181d6dd7d..a27aeb7d9e74 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2180,7 +2180,7 @@ xfs_alloc_read_agf( ASSERT(agno != NULLAGNUMBER); error = xfs_read_agf(mp, tp, agno, - (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0, + (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0, bpp); if (error) return error; diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index f7b426a1b6ee..b9c196a53c42 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -2015,15 +2015,14 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, - blkcnt, - XFS_BUF_LOCK | XBF_DONT_BLOCK, + blkcnt, XBF_LOCK | XBF_DONT_BLOCK, &bp); if (error) return(error); tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : XFS_BUF_SIZE(bp); - xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); + xfs_biomove(bp, 0, tmp, dst, XBF_READ); xfs_buf_relse(bp); dst += tmp; valuelen -= tmp; @@ -2149,13 +2148,13 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, - XFS_BUF_LOCK | XBF_DONT_BLOCK); + XBF_LOCK | XBF_DONT_BLOCK); ASSERT(bp); ASSERT(!XFS_BUF_GETERROR(bp)); tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : XFS_BUF_SIZE(bp); - xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); + xfs_biomove(bp, 0, tmp, src, XBF_WRITE); if (tmp < XFS_BUF_SIZE(bp)) xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ @@ -2216,8 +2215,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) /* * If the "remote" value is in the cache, remove it. */ - bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, - XFS_INCORE_TRYLOCK); + bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK); if (bp) { XFS_BUF_STALE(bp); XFS_BUF_UNDELAYWRITE(bp); diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 52519a201849..a90ce74fc256 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -2950,7 +2950,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, map.br_blockcount); bp = xfs_trans_get_buf(*trans, dp->i_mount->m_ddev_targp, - dblkno, dblkcnt, XFS_BUF_LOCK); + dblkno, dblkcnt, XBF_LOCK); xfs_trans_binval(*trans, bp); /* * Roll to next transaction. diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 36a0992dd669..96be4b0f2496 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -977,7 +977,7 @@ xfs_btree_get_buf_block( xfs_daddr_t d; /* need to sort out how callers deal with failures first */ - ASSERT(!(flags & XFS_BUF_TRYLOCK)); + ASSERT(!(flags & XBF_TRYLOCK)); d = xfs_btree_ptr_to_daddr(cur, ptr); *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, @@ -1008,7 +1008,7 @@ xfs_btree_read_buf_block( int error; /* need to sort out how callers deal with failures first */ - ASSERT(!(flags & XFS_BUF_TRYLOCK)); + ASSERT(!(flags & XBF_TRYLOCK)); d = xfs_btree_ptr_to_daddr(cur, ptr); error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 52c9d006c0e6..9d884c127bb9 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -205,7 +205,7 @@ xfs_ialloc_inode_init( d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster)); fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize * blks_per_cluster, - XFS_BUF_LOCK); + XBF_LOCK); ASSERT(fbuf); ASSERT(!XFS_BUF_GETERROR(fbuf)); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 0317b000ab44..bbb3bee8e936 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -151,7 +151,7 @@ xfs_imap_to_bp( "an error %d on %s. Returning error.", error, mp->m_fsname); } else { - ASSERT(buf_flags & XFS_BUF_TRYLOCK); + ASSERT(buf_flags & XBF_TRYLOCK); } return error; } @@ -239,7 +239,7 @@ xfs_inotobp( if (error) return error; - error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, imap_flags); + error = xfs_imap_to_bp(mp, tp, &imap, &bp, XBF_LOCK, imap_flags); if (error) return error; @@ -285,7 +285,7 @@ xfs_itobp( return error; if (!bp) { - ASSERT(buf_flags & XFS_BUF_TRYLOCK); + ASSERT(buf_flags & XBF_TRYLOCK); ASSERT(tp == NULL); *bpp = NULL; return EAGAIN; @@ -807,7 +807,7 @@ xfs_iread( * Get pointers to the on-disk inode and the buffer containing it. */ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, - XFS_BUF_LOCK, iget_flags); + XBF_LOCK, iget_flags); if (error) return error; dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); @@ -1751,7 +1751,7 @@ xfs_iunlink( * Here we put the head pointer into our next pointer, * and then we fall through to point the head at us. */ - error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); + error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK); if (error) return error; @@ -1833,7 +1833,7 @@ xfs_iunlink_remove( * of dealing with the buffer when there is no need to * change it. */ - error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); + error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK); if (error) { cmn_err(CE_WARN, "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", @@ -1895,7 +1895,7 @@ xfs_iunlink_remove( * Now last_ibp points to the buffer previous to us on * the unlinked list. Pull us from the list. */ - error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); + error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK); if (error) { cmn_err(CE_WARN, "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", @@ -2040,7 +2040,7 @@ xfs_ifree_cluster( bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, mp->m_bsize * blks_per_cluster, - XFS_BUF_LOCK); + XBF_LOCK); pre_flushed = 0; lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); @@ -2151,7 +2151,7 @@ xfs_ifree( xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XFS_BUF_LOCK); + error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XBF_LOCK); if (error) return error; @@ -2952,7 +2952,7 @@ xfs_iflush( * Get the buffer containing the on-disk inode. */ error = xfs_itobp(mp, NULL, ip, &dip, &bp, - noblock ? XFS_BUF_TRYLOCK : XFS_BUF_LOCK); + noblock ? XBF_TRYLOCK : XBF_LOCK); if (error || !bp) { xfs_ifunlock(ip); return error; diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index f38855d21ea5..6194fb5d3777 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -785,7 +785,7 @@ xfs_inode_item_pushbuf( mp = ip->i_mount; bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno, - iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK); + iip->ili_format.ilf_len, XBF_TRYLOCK); if (bp != NULL) { if (XFS_BUF_ISDELAYWRITE(bp)) { diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 65f1f137d789..97148f0c4bdd 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2184,9 +2184,9 @@ xlog_recover_do_buffer_trans( } mp = log->l_mp; - buf_flags = XFS_BUF_LOCK; + buf_flags = XBF_LOCK; if (!(flags & XFS_BLI_INODE_BUF)) - buf_flags |= XFS_BUF_MAPPED; + buf_flags |= XBF_MAPPED; bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, buf_flags); if (XFS_BUF_ISERROR(bp)) { @@ -2288,7 +2288,7 @@ xlog_recover_do_inode_trans( } bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, - XFS_BUF_LOCK); + XBF_LOCK); if (XFS_BUF_ISERROR(bp)) { xfs_ioerror_alert("xlog_recover_do..(read#2)", mp, bp, in_f->ilf_blkno); @@ -3146,7 +3146,7 @@ xlog_recover_process_one_iunlink( /* * Get the on disk inode to find the next inode in the bucket. */ - error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XFS_BUF_LOCK); + error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XBF_LOCK); if (error) goto fail_iput; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index d95bd1809f3c..bb0154047e85 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -665,7 +665,7 @@ xfs_readsb(xfs_mount_t *mp, int flags) * access to the superblock. */ sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); - extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED; + extra_flags = XBF_LOCK | XBF_FS_MANAGED | XBF_MAPPED; bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), extra_flags); @@ -1969,7 +1969,7 @@ xfs_getsb( ASSERT(mp->m_sb_bp != NULL); bp = mp->m_sb_bp; - if (flags & XFS_BUF_TRYLOCK) { + if (flags & XBF_TRYLOCK) { if (!XFS_BUF_CPSEMA(bp)) { return NULL; } diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 49130628d5ef..5ffd544434eb 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -75,13 +75,14 @@ xfs_trans_get_buf(xfs_trans_t *tp, xfs_buf_log_item_t *bip; if (flags == 0) - flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + flags = XBF_LOCK | XBF_MAPPED; /* * Default to a normal get_buf() call if the tp is NULL. */ if (tp == NULL) - return xfs_buf_get(target_dev, blkno, len, flags | BUF_BUSY); + return xfs_buf_get(target_dev, blkno, len, + flags | XBF_DONT_BLOCK); /* * If we find the buffer in the cache with this transaction @@ -117,14 +118,14 @@ xfs_trans_get_buf(xfs_trans_t *tp, } /* - * We always specify the BUF_BUSY flag within a transaction so - * that get_buf does not try to push out a delayed write buffer + * We always specify the XBF_DONT_BLOCK flag within a transaction + * so that get_buf does not try to push out a delayed write buffer * which might cause another transaction to take place (if the * buffer was delayed alloc). Such recursive transactions can * easily deadlock with our current transaction as well as cause * us to run out of stack space. */ - bp = xfs_buf_get(target_dev, blkno, len, flags | BUF_BUSY); + bp = xfs_buf_get(target_dev, blkno, len, flags | XBF_DONT_BLOCK); if (bp == NULL) { return NULL; } @@ -290,15 +291,15 @@ xfs_trans_read_buf( int error; if (flags == 0) - flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + flags = XBF_LOCK | XBF_MAPPED; /* * Default to a normal get_buf() call if the tp is NULL. */ if (tp == NULL) { - bp = xfs_buf_read(target, blkno, len, flags | BUF_BUSY); + bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK); if (!bp) - return (flags & XFS_BUF_TRYLOCK) ? + return (flags & XBF_TRYLOCK) ? EAGAIN : XFS_ERROR(ENOMEM); if (XFS_BUF_GETERROR(bp) != 0) { @@ -385,14 +386,14 @@ xfs_trans_read_buf( } /* - * We always specify the BUF_BUSY flag within a transaction so - * that get_buf does not try to push out a delayed write buffer + * We always specify the XBF_DONT_BLOCK flag within a transaction + * so that get_buf does not try to push out a delayed write buffer * which might cause another transaction to take place (if the * buffer was delayed alloc). Such recursive transactions can * easily deadlock with our current transaction as well as cause * us to run out of stack space. */ - bp = xfs_buf_read(target, blkno, len, flags | BUF_BUSY); + bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK); if (bp == NULL) { *bpp = NULL; return 0; @@ -472,8 +473,8 @@ shutdown_abort: if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp)) cmn_err(CE_NOTE, "about to pop assert, bp == 0x%p", bp); #endif - ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) != - (XFS_B_STALE|XFS_B_DELWRI)); + ASSERT((XFS_BUF_BFLAGS(bp) & (XBF_STALE|XBF_DELWRI)) != + (XBF_STALE|XBF_DELWRI)); trace_xfs_trans_read_buf_shut(bp, _RET_IP_); xfs_buf_relse(bp); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 9f7c001ef469..4da96cdffb76 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -256,7 +256,7 @@ xfs_setattr( iattr->ia_size > ip->i_d.di_size) { code = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, - XFS_B_ASYNC, FI_NONE); + XBF_ASYNC, FI_NONE); } /* wait for all I/O to complete */ @@ -1096,7 +1096,7 @@ xfs_release( */ truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) - xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); + xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE); } if (ip->i_d.di_nlink != 0) { -- GitLab From 4139b3b337cffd106744386c842b89dc86e31d4b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jan 2010 09:56:45 +0000 Subject: [PATCH 1081/3892] xfs: kill XLOG_VEC_SET_TYPE This macro only obsfucates the log item type assignments, so kill it. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_dquot_item.c | 6 +++--- fs/xfs/xfs_buf_item.c | 8 ++++---- fs/xfs/xfs_extfree_item.c | 4 ++-- fs/xfs/xfs_inode_item.c | 18 +++++++++--------- fs/xfs/xfs_log.c | 4 ++-- fs/xfs/xfs_log.h | 4 +--- fs/xfs/xfs_trans.c | 2 +- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 37929d19ef44..116580d52fae 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -74,11 +74,11 @@ xfs_qm_dquot_logitem_format( logvec->i_addr = (xfs_caddr_t)&logitem->qli_format; logvec->i_len = sizeof(xfs_dq_logformat_t); - XLOG_VEC_SET_TYPE(logvec, XLOG_REG_TYPE_QFORMAT); + logvec->i_type = XLOG_REG_TYPE_QFORMAT; logvec++; logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core; logvec->i_len = sizeof(xfs_disk_dquot_t); - XLOG_VEC_SET_TYPE(logvec, XLOG_REG_TYPE_DQUOT); + logvec->i_type = XLOG_REG_TYPE_DQUOT; ASSERT(2 == logitem->qli_item.li_desc->lid_size); logitem->qli_format.qlf_size = 2; @@ -466,7 +466,7 @@ xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf, log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format); log_vector->i_len = sizeof(xfs_qoff_logitem_t); - XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_QUOTAOFF); + log_vector->i_type = XLOG_REG_TYPE_QUOTAOFF; qf->qql_format.qf_size = 1; } diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index a30f7e9eb2b9..e0a11583ce5a 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -250,7 +250,7 @@ xfs_buf_item_format( ((bip->bli_format.blf_map_size - 1) * sizeof(uint))); vecp->i_addr = (xfs_caddr_t)&bip->bli_format; vecp->i_len = base_size; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BFORMAT); + vecp->i_type = XLOG_REG_TYPE_BFORMAT; vecp++; nvecs = 1; @@ -297,14 +297,14 @@ xfs_buf_item_format( buffer_offset = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); + vecp->i_type = XLOG_REG_TYPE_BCHUNK; nvecs++; break; } else if (next_bit != last_bit + 1) { buffer_offset = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); + vecp->i_type = XLOG_REG_TYPE_BCHUNK; nvecs++; vecp++; first_bit = next_bit; @@ -316,7 +316,7 @@ xfs_buf_item_format( buffer_offset = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); + vecp->i_type = XLOG_REG_TYPE_BCHUNK; /* You would think we need to bump the nvecs here too, but we do not * this number is used by recovery, and it gets confused by the boundary * split here diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 05a4bdd4be39..6f35ed1b39b9 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -82,7 +82,7 @@ xfs_efi_item_format(xfs_efi_log_item_t *efip, log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format); log_vector->i_len = size; - XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFI_FORMAT); + log_vector->i_type = XLOG_REG_TYPE_EFI_FORMAT; ASSERT(size >= sizeof(xfs_efi_log_format_t)); } @@ -406,7 +406,7 @@ xfs_efd_item_format(xfs_efd_log_item_t *efdp, log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format); log_vector->i_len = size; - XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFD_FORMAT); + log_vector->i_type = XLOG_REG_TYPE_EFD_FORMAT; ASSERT(size >= sizeof(xfs_efd_log_format_t)); } diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 6194fb5d3777..da4cac67bdae 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -228,7 +228,7 @@ xfs_inode_item_format( vecp->i_addr = (xfs_caddr_t)&iip->ili_format; vecp->i_len = sizeof(xfs_inode_log_format_t); - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IFORMAT); + vecp->i_type = XLOG_REG_TYPE_IFORMAT; vecp++; nvecs = 1; @@ -279,7 +279,7 @@ xfs_inode_item_format( vecp->i_addr = (xfs_caddr_t)&ip->i_d; vecp->i_len = sizeof(struct xfs_icdinode); - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE); + vecp->i_type = XLOG_REG_TYPE_ICORE; vecp++; nvecs++; iip->ili_format.ilf_fields |= XFS_ILOG_CORE; @@ -336,7 +336,7 @@ xfs_inode_item_format( vecp->i_addr = (char *)(ip->i_df.if_u1.if_extents); vecp->i_len = ip->i_df.if_bytes; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT); + vecp->i_type = XLOG_REG_TYPE_IEXT; } else #endif { @@ -355,7 +355,7 @@ xfs_inode_item_format( vecp->i_addr = (xfs_caddr_t)ext_buffer; vecp->i_len = xfs_iextents_copy(ip, ext_buffer, XFS_DATA_FORK); - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT); + vecp->i_type = XLOG_REG_TYPE_IEXT; } ASSERT(vecp->i_len <= ip->i_df.if_bytes); iip->ili_format.ilf_dsize = vecp->i_len; @@ -373,7 +373,7 @@ xfs_inode_item_format( ASSERT(ip->i_df.if_broot != NULL); vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot; vecp->i_len = ip->i_df.if_broot_bytes; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IBROOT); + vecp->i_type = XLOG_REG_TYPE_IBROOT; vecp++; nvecs++; iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes; @@ -399,7 +399,7 @@ xfs_inode_item_format( ASSERT((ip->i_df.if_real_bytes == 0) || (ip->i_df.if_real_bytes == data_bytes)); vecp->i_len = (int)data_bytes; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ILOCAL); + vecp->i_type = XLOG_REG_TYPE_ILOCAL; vecp++; nvecs++; iip->ili_format.ilf_dsize = (unsigned)data_bytes; @@ -477,7 +477,7 @@ xfs_inode_item_format( vecp->i_len = xfs_iextents_copy(ip, ext_buffer, XFS_ATTR_FORK); #endif - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_EXT); + vecp->i_type = XLOG_REG_TYPE_IATTR_EXT; iip->ili_format.ilf_asize = vecp->i_len; vecp++; nvecs++; @@ -492,7 +492,7 @@ xfs_inode_item_format( ASSERT(ip->i_afp->if_broot != NULL); vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot; vecp->i_len = ip->i_afp->if_broot_bytes; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_BROOT); + vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT; vecp++; nvecs++; iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes; @@ -516,7 +516,7 @@ xfs_inode_item_format( ASSERT((ip->i_afp->if_real_bytes == 0) || (ip->i_afp->if_real_bytes == data_bytes)); vecp->i_len = (int)data_bytes; - XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_LOCAL); + vecp->i_type = XLOG_REG_TYPE_IATTR_LOCAL; vecp++; nvecs++; iip->ili_format.ilf_asize = (unsigned)data_bytes; diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 0d17516fbb13..20118ddadef6 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -617,7 +617,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) if (! (XLOG_FORCED_SHUTDOWN(log))) { reg[0].i_addr = (void*)&magic; reg[0].i_len = sizeof(magic); - XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_UNMOUNT); + reg[0].i_type = XLOG_REG_TYPE_UNMOUNT; error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE); @@ -1236,7 +1236,7 @@ xlog_commit_record(xfs_mount_t *mp, reg[0].i_addr = NULL; reg[0].i_len = 0; - XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_COMMIT); + reg[0].i_type = XLOG_REG_TYPE_COMMIT; ASSERT_ALWAYS(iclog); if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index d0c9baa50b1a..811ccf4d8b3e 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h @@ -110,10 +110,8 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2) #define XLOG_REG_TYPE_TRANSHDR 19 #define XLOG_REG_TYPE_MAX 19 -#define XLOG_VEC_SET_TYPE(vecp, t) ((vecp)->i_type = (t)) - typedef struct xfs_log_iovec { - xfs_caddr_t i_addr; /* beginning address of region */ + xfs_caddr_t i_addr; /* beginning address of region */ int i_len; /* length in bytes of region */ uint i_type; /* type of region */ } xfs_log_iovec_t; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 237badcbac3b..7dbe3c3051db 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -1121,7 +1121,7 @@ xfs_trans_fill_vecs( tp->t_header.th_num_items = nitems; log_vector->i_addr = (xfs_caddr_t)&tp->t_header; log_vector->i_len = sizeof(xfs_trans_header_t); - XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_TRANSHDR); + log_vector->i_type = XLOG_REG_TYPE_TRANSHDR; } -- GitLab From a14a348bff2f99471a28e5928eb6801224c053d8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jan 2010 09:56:46 +0000 Subject: [PATCH 1082/3892] xfs: cleanup up xfs_log_force calling conventions Remove the XFS_LOG_FORCE argument which was always set, and the XFS_LOG_URGE define, which was never used. Split xfs_log_force into a two helpers - xfs_log_force which forces the whole log, and xfs_log_force_lsn which forces up to the specified LSN. The underlying implementations already were entirely separate, as were the users. Also re-indent the new _xfs_log_force/_xfs_log_force which previously had a weird coding style. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_sync.c | 17 +- fs/xfs/quota/xfs_dquot.c | 10 +- fs/xfs/quota/xfs_dquot_item.c | 9 +- fs/xfs/quota/xfs_qm_syscalls.c | 4 +- fs/xfs/xfs_alloc.c | 2 +- fs/xfs/xfs_inode.c | 9 +- fs/xfs/xfs_inode_item.c | 7 +- fs/xfs/xfs_log.c | 312 ++++++++++++++++----------------- fs/xfs/xfs_log.h | 15 +- fs/xfs/xfs_log_recover.c | 3 +- fs/xfs/xfs_mount.c | 4 +- fs/xfs/xfs_trans.c | 5 +- fs/xfs/xfs_trans_ail.c | 2 +- fs/xfs/xfs_vnodeops.c | 5 +- 14 files changed, 193 insertions(+), 211 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 58c24be72c65..c9b863eacab7 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -296,10 +296,7 @@ xfs_sync_data( if (error) return XFS_ERROR(error); - xfs_log_force(mp, 0, - (flags & SYNC_WAIT) ? - XFS_LOG_FORCE | XFS_LOG_SYNC : - XFS_LOG_FORCE); + xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0); return 0; } @@ -325,10 +322,6 @@ xfs_commit_dummy_trans( struct xfs_inode *ip = mp->m_rootip; struct xfs_trans *tp; int error; - int log_flags = XFS_LOG_FORCE; - - if (flags & SYNC_WAIT) - log_flags |= XFS_LOG_SYNC; /* * Put a dummy transaction in the log to tell recovery @@ -350,7 +343,7 @@ xfs_commit_dummy_trans( xfs_iunlock(ip, XFS_ILOCK_EXCL); /* the log force ensures this transaction is pushed to disk */ - xfs_log_force(mp, 0, log_flags); + xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0); return error; } @@ -390,7 +383,7 @@ xfs_sync_fsdata( * become pinned in between there and here. */ if (XFS_BUF_ISPINNED(bp)) - xfs_log_force(mp, 0, XFS_LOG_FORCE); + xfs_log_force(mp, 0); } @@ -575,7 +568,7 @@ xfs_flush_inodes( igrab(inode); xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion); wait_for_completion(&completion); - xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); + xfs_log_force(ip->i_mount, XFS_LOG_SYNC); } /* @@ -591,7 +584,7 @@ xfs_sync_worker( int error; if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + xfs_log_force(mp, 0); xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC); /* dgc: errors ignored here */ error = xfs_qm_sync(mp, SYNC_TRYLOCK); diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 5756392ffdee..f9baeedbfdfe 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1248,7 +1248,7 @@ xfs_qm_dqflush( */ if (XFS_BUF_ISPINNED(bp)) { trace_xfs_dqflush_force(dqp); - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + xfs_log_force(mp, 0); } if (flags & XFS_QMOPT_DELWRI) { @@ -1531,11 +1531,9 @@ xfs_qm_dqflock_pushbuf_wait( if (bp != NULL) { if (XFS_BUF_ISDELAYWRITE(bp)) { int error; - if (XFS_BUF_ISPINNED(bp)) { - xfs_log_force(dqp->q_mount, - (xfs_lsn_t)0, - XFS_LOG_FORCE); - } + + if (XFS_BUF_ISPINNED(bp)) + xfs_log_force(dqp->q_mount, 0); error = xfs_bawrite(dqp->q_mount, bp); if (error) xfs_fs_cmn_err(CE_WARN, dqp->q_mount, diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 116580d52fae..1b564376d50c 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -190,7 +190,7 @@ xfs_qm_dqunpin_wait( /* * Give the log a push so we don't wait here too long. */ - xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); + xfs_log_force(dqp->q_mount, 0); wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); } @@ -245,10 +245,9 @@ xfs_qm_dquot_logitem_pushbuf( qip->qli_pushbuf_flag = 0; xfs_dqunlock(dqp); - if (XFS_BUF_ISPINNED(bp)) { - xfs_log_force(mp, (xfs_lsn_t)0, - XFS_LOG_FORCE); - } + if (XFS_BUF_ISPINNED(bp)) + xfs_log_force(mp, 0); + if (dopush) { int error; #ifdef XFSRACEDEBUG diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 873e07e29074..5d0ee8d492db 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -1192,9 +1192,9 @@ xfs_qm_internalqcheck( if (! XFS_IS_QUOTA_ON(mp)) return XFS_ERROR(ESRCH); - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_log_force(mp, XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_log_force(mp, XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); mutex_lock(&qcheck_lock); diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index a27aeb7d9e74..94cddbfb2560 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2601,5 +2601,5 @@ xfs_alloc_search_busy(xfs_trans_t *tp, * transaction that freed the block */ if (lsn) - xfs_log_force(tp->t_mountp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); + xfs_log_force_lsn(tp->t_mountp, lsn, XFS_LOG_SYNC); } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bbb3bee8e936..d0d1b5a05183 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2484,8 +2484,11 @@ __xfs_iunpin_wait( return; /* Give the log a push to start the unpinning I/O */ - xfs_log_force(ip->i_mount, (iip && iip->ili_last_lsn) ? - iip->ili_last_lsn : 0, XFS_LOG_FORCE); + if (iip && iip->ili_last_lsn) + xfs_log_force_lsn(ip->i_mount, iip->ili_last_lsn, 0); + else + xfs_log_force(ip->i_mount, 0); + if (wait) wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0)); } @@ -2970,7 +2973,7 @@ xfs_iflush( * get stuck waiting in the write for too long. */ if (XFS_BUF_ISPINNED(bp)) - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + xfs_log_force(mp, 0); /* * inode clustering: diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index da4cac67bdae..48ec1c0b23ce 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -804,10 +804,9 @@ xfs_inode_item_pushbuf( trace_xfs_inode_item_push(bp, _RET_IP_); - if (XFS_BUF_ISPINNED(bp)) { - xfs_log_force(mp, (xfs_lsn_t)0, - XFS_LOG_FORCE); - } + if (XFS_BUF_ISPINNED(bp)) + xfs_log_force(mp, 0); + if (dopush) { int error; error = xfs_bawrite(mp, bp); diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 20118ddadef6..4f16be4b6ee5 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -79,11 +79,6 @@ STATIC int xlog_state_release_iclog(xlog_t *log, STATIC void xlog_state_switch_iclogs(xlog_t *log, xlog_in_core_t *iclog, int eventual_size); -STATIC int xlog_state_sync(xlog_t *log, - xfs_lsn_t lsn, - uint flags, - int *log_flushed); -STATIC int xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed); STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog); /* local functions to manipulate grant head */ @@ -296,65 +291,6 @@ xfs_log_done(xfs_mount_t *mp, return lsn; } /* xfs_log_done */ - -/* - * Force the in-core log to disk. If flags == XFS_LOG_SYNC, - * the force is done synchronously. - * - * Asynchronous forces are implemented by setting the WANT_SYNC - * bit in the appropriate in-core log and then returning. - * - * Synchronous forces are implemented with a signal variable. All callers - * to force a given lsn to disk will wait on a the sv attached to the - * specific in-core log. When given in-core log finally completes its - * write to disk, that thread will wake up all threads waiting on the - * sv. - */ -int -_xfs_log_force( - xfs_mount_t *mp, - xfs_lsn_t lsn, - uint flags, - int *log_flushed) -{ - xlog_t *log = mp->m_log; - int dummy; - - if (!log_flushed) - log_flushed = &dummy; - - ASSERT(flags & XFS_LOG_FORCE); - - XFS_STATS_INC(xs_log_force); - - if (log->l_flags & XLOG_IO_ERROR) - return XFS_ERROR(EIO); - if (lsn == 0) - return xlog_state_sync_all(log, flags, log_flushed); - else - return xlog_state_sync(log, lsn, flags, log_flushed); -} /* _xfs_log_force */ - -/* - * Wrapper for _xfs_log_force(), to be used when caller doesn't care - * about errors or whether the log was flushed or not. This is the normal - * interface to use when trying to unpin items or move the log forward. - */ -void -xfs_log_force( - xfs_mount_t *mp, - xfs_lsn_t lsn, - uint flags) -{ - int error; - error = _xfs_log_force(mp, lsn, flags, NULL); - if (error) { - xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: " - "error %d returned.", error); - } -} - - /* * Attaches a new iclog I/O completion callback routine during * transaction commit. If the log is in error state, a non-zero @@ -601,7 +537,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; - error = _xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC, NULL); + error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL); ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log))); #ifdef DEBUG @@ -2853,7 +2789,6 @@ xlog_state_switch_iclogs(xlog_t *log, log->l_iclog = iclog->ic_next; } /* xlog_state_switch_iclogs */ - /* * Write out all data in the in-core log as of this exact moment in time. * @@ -2881,11 +2816,17 @@ xlog_state_switch_iclogs(xlog_t *log, * b) when we return from flushing out this iclog, it is still * not in the active nor dirty state. */ -STATIC int -xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) +int +_xfs_log_force( + struct xfs_mount *mp, + uint flags, + int *log_flushed) { - xlog_in_core_t *iclog; - xfs_lsn_t lsn; + struct log *log = mp->m_log; + struct xlog_in_core *iclog; + xfs_lsn_t lsn; + + XFS_STATS_INC(xs_log_force); spin_lock(&log->l_icloglock); @@ -2931,7 +2872,9 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); - *log_flushed = 1; + + if (log_flushed) + *log_flushed = 1; spin_lock(&log->l_icloglock); if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn && iclog->ic_state != XLOG_STATE_DIRTY) @@ -2975,19 +2918,37 @@ maybe_sleep: */ if (iclog->ic_state & XLOG_STATE_IOERROR) return XFS_ERROR(EIO); - *log_flushed = 1; - + if (log_flushed) + *log_flushed = 1; } else { no_sleep: spin_unlock(&log->l_icloglock); } return 0; -} /* xlog_state_sync_all */ +} +/* + * Wrapper for _xfs_log_force(), to be used when caller doesn't care + * about errors or whether the log was flushed or not. This is the normal + * interface to use when trying to unpin items or move the log forward. + */ +void +xfs_log_force( + xfs_mount_t *mp, + uint flags) +{ + int error; + + error = _xfs_log_force(mp, flags, NULL); + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: " + "error %d returned.", error); + } +} /* - * Used by code which implements synchronous log forces. + * Force the in-core log to disk for a specific LSN. * * Find in-core log with lsn. * If it is in the DIRTY state, just return. @@ -2995,109 +2956,142 @@ no_sleep: * state and go to sleep or return. * If it is in any other state, go to sleep or return. * - * If filesystem activity goes to zero, the iclog will get flushed only by - * bdflush(). + * Synchronous forces are implemented with a signal variable. All callers + * to force a given lsn to disk will wait on a the sv attached to the + * specific in-core log. When given in-core log finally completes its + * write to disk, that thread will wake up all threads waiting on the + * sv. */ -STATIC int -xlog_state_sync(xlog_t *log, - xfs_lsn_t lsn, - uint flags, - int *log_flushed) +int +_xfs_log_force_lsn( + struct xfs_mount *mp, + xfs_lsn_t lsn, + uint flags, + int *log_flushed) { - xlog_in_core_t *iclog; - int already_slept = 0; - -try_again: - spin_lock(&log->l_icloglock); - iclog = log->l_iclog; + struct log *log = mp->m_log; + struct xlog_in_core *iclog; + int already_slept = 0; - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return XFS_ERROR(EIO); - } + ASSERT(lsn != 0); - do { - if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) { - iclog = iclog->ic_next; - continue; - } + XFS_STATS_INC(xs_log_force); - if (iclog->ic_state == XLOG_STATE_DIRTY) { +try_again: + spin_lock(&log->l_icloglock); + iclog = log->l_iclog; + if (iclog->ic_state & XLOG_STATE_IOERROR) { spin_unlock(&log->l_icloglock); - return 0; + return XFS_ERROR(EIO); } - if (iclog->ic_state == XLOG_STATE_ACTIVE) { - /* - * We sleep here if we haven't already slept (e.g. - * this is the first time we've looked at the correct - * iclog buf) and the buffer before us is going to - * be sync'ed. The reason for this is that if we - * are doing sync transactions here, by waiting for - * the previous I/O to complete, we can allow a few - * more transactions into this iclog before we close - * it down. - * - * Otherwise, we mark the buffer WANT_SYNC, and bump - * up the refcnt so we can release the log (which drops - * the ref count). The state switch keeps new transaction - * commits from using this buffer. When the current commits - * finish writing into the buffer, the refcount will drop to - * zero and the buffer will go out then. - */ - if (!already_slept && - (iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC | - XLOG_STATE_SYNCING))) { - ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); - XFS_STATS_INC(xs_log_force_sleep); - sv_wait(&iclog->ic_prev->ic_write_wait, PSWP, - &log->l_icloglock, s); - *log_flushed = 1; - already_slept = 1; - goto try_again; - } else { + do { + if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) { + iclog = iclog->ic_next; + continue; + } + + if (iclog->ic_state == XLOG_STATE_DIRTY) { + spin_unlock(&log->l_icloglock); + return 0; + } + + if (iclog->ic_state == XLOG_STATE_ACTIVE) { + /* + * We sleep here if we haven't already slept (e.g. + * this is the first time we've looked at the correct + * iclog buf) and the buffer before us is going to + * be sync'ed. The reason for this is that if we + * are doing sync transactions here, by waiting for + * the previous I/O to complete, we can allow a few + * more transactions into this iclog before we close + * it down. + * + * Otherwise, we mark the buffer WANT_SYNC, and bump + * up the refcnt so we can release the log (which + * drops the ref count). The state switch keeps new + * transaction commits from using this buffer. When + * the current commits finish writing into the buffer, + * the refcount will drop to zero and the buffer will + * go out then. + */ + if (!already_slept && + (iclog->ic_prev->ic_state & + (XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) { + ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); + + XFS_STATS_INC(xs_log_force_sleep); + + sv_wait(&iclog->ic_prev->ic_write_wait, + PSWP, &log->l_icloglock, s); + if (log_flushed) + *log_flushed = 1; + already_slept = 1; + goto try_again; + } atomic_inc(&iclog->ic_refcnt); xlog_state_switch_iclogs(log, iclog, 0); spin_unlock(&log->l_icloglock); if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); - *log_flushed = 1; + if (log_flushed) + *log_flushed = 1; spin_lock(&log->l_icloglock); } - } - if ((flags & XFS_LOG_SYNC) && /* sleep */ - !(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { + if ((flags & XFS_LOG_SYNC) && /* sleep */ + !(iclog->ic_state & + (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { + /* + * Don't wait on completion if we know that we've + * gotten a log write error. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) { + spin_unlock(&log->l_icloglock); + return XFS_ERROR(EIO); + } + XFS_STATS_INC(xs_log_force_sleep); + sv_wait(&iclog->ic_force_wait, PSWP, &log->l_icloglock, s); + /* + * No need to grab the log lock here since we're + * only deciding whether or not to return EIO + * and the memory read should be atomic. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) + return XFS_ERROR(EIO); - /* - * Don't wait on completion if we know that we've - * gotten a log write error. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) { + if (log_flushed) + *log_flushed = 1; + } else { /* just return */ spin_unlock(&log->l_icloglock); - return XFS_ERROR(EIO); } - XFS_STATS_INC(xs_log_force_sleep); - sv_wait(&iclog->ic_force_wait, PSWP, &log->l_icloglock, s); - /* - * No need to grab the log lock here since we're - * only deciding whether or not to return EIO - * and the memory read should be atomic. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) - return XFS_ERROR(EIO); - *log_flushed = 1; - } else { /* just return */ - spin_unlock(&log->l_icloglock); - } - return 0; - } while (iclog != log->l_iclog); + return 0; + } while (iclog != log->l_iclog); - spin_unlock(&log->l_icloglock); - return 0; -} /* xlog_state_sync */ + spin_unlock(&log->l_icloglock); + return 0; +} + +/* + * Wrapper for _xfs_log_force_lsn(), to be used when caller doesn't care + * about errors or whether the log was flushed or not. This is the normal + * interface to use when trying to unpin items or move the log forward. + */ +void +xfs_log_force_lsn( + xfs_mount_t *mp, + xfs_lsn_t lsn, + uint flags) +{ + int error; + error = _xfs_log_force_lsn(mp, lsn, flags, NULL); + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: " + "error %d returned.", error); + } +} /* * Called when we want to mark the current iclog as being ready to sync to @@ -3462,7 +3456,6 @@ xfs_log_force_umount( xlog_ticket_t *tic; xlog_t *log; int retval; - int dummy; log = mp->m_log; @@ -3536,13 +3529,14 @@ xfs_log_force_umount( } spin_unlock(&log->l_grant_lock); - if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { + if (!(log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { ASSERT(!logerror); /* * Force the incore logs to disk before shutting the * log down completely. */ - xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC, &dummy); + _xfs_log_force(mp, XFS_LOG_SYNC, NULL); + spin_lock(&log->l_icloglock); retval = xlog_state_ioerror(log); spin_unlock(&log->l_icloglock); diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index 811ccf4d8b3e..7074be9d13e9 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h @@ -70,14 +70,8 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2) * Flags to xfs_log_force() * * XFS_LOG_SYNC: Synchronous force in-core log to disk - * XFS_LOG_FORCE: Start in-core log write now. - * XFS_LOG_URGE: Start write within some window of time. - * - * Note: Either XFS_LOG_FORCE or XFS_LOG_URGE must be set. */ #define XFS_LOG_SYNC 0x1 -#define XFS_LOG_FORCE 0x2 -#define XFS_LOG_URGE 0x4 #endif /* __KERNEL__ */ @@ -138,12 +132,17 @@ xfs_lsn_t xfs_log_done(struct xfs_mount *mp, void **iclog, uint flags); int _xfs_log_force(struct xfs_mount *mp, - xfs_lsn_t lsn, uint flags, int *log_forced); void xfs_log_force(struct xfs_mount *mp, - xfs_lsn_t lsn, uint flags); +int _xfs_log_force_lsn(struct xfs_mount *mp, + xfs_lsn_t lsn, + uint flags, + int *log_forced); +void xfs_log_force_lsn(struct xfs_mount *mp, + xfs_lsn_t lsn, + uint flags); int xfs_log_mount(struct xfs_mount *mp, struct xfs_buftarg *log_target, xfs_daddr_t start_block, diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 97148f0c4bdd..22e6efdc17ea 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3913,8 +3913,7 @@ xlog_recover_finish( * case the unlink transactions would have problems * pushing the EFIs out of the way. */ - xfs_log_force(log->l_mp, (xfs_lsn_t)0, - (XFS_LOG_FORCE | XFS_LOG_SYNC)); + xfs_log_force(log->l_mp, XFS_LOG_SYNC); xlog_recover_process_iunlinks(log); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index bb0154047e85..7f81ed72c875 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1455,7 +1455,7 @@ xfs_unmountfs( * push out the iclog we will never get that unlocked. hence we * need to force the log first. */ - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_log_force(mp, XFS_LOG_SYNC); xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC); xfs_qm_unmount(mp); @@ -1465,7 +1465,7 @@ xfs_unmountfs( * that nothing is pinned. This is important because bflush() * will skip pinned buffers. */ - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_log_force(mp, XFS_LOG_SYNC); xfs_binval(mp->m_ddev_targp); if (mp->m_rtdev_targp) { diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 7dbe3c3051db..be942d4e3324 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -981,9 +981,8 @@ shut_us_down: */ if (sync) { if (!error) { - error = _xfs_log_force(mp, commit_lsn, - XFS_LOG_FORCE | XFS_LOG_SYNC, - log_flushed); + error = _xfs_log_force_lsn(mp, commit_lsn, + XFS_LOG_SYNC, log_flushed); } XFS_STATS_INC(xs_trans_sync); } else { diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 063dfbdca94b..d7b1af8a832d 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -371,7 +371,7 @@ xfsaild_push( * move forward in the AIL. */ XFS_STATS_INC(xs_push_ail_flush); - xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + xfs_log_force(mp, 0); } if (!count) { diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 4da96cdffb76..fd108b738559 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -631,9 +631,8 @@ xfs_fsync( xfs_iunlock(ip, XFS_ILOCK_SHARED); if (xfs_ipincount(ip)) { - error = _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, - XFS_LOG_FORCE | XFS_LOG_SYNC, - &log_flushed); + error = _xfs_log_force(ip->i_mount, XFS_LOG_SYNC, + &log_flushed); } else { /* * If the inode is not pinned and nothing has changed -- GitLab From bdfb04301fa5fdd95f219539a9a5b9663b1e5fc2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 20 Jan 2010 21:55:30 +0000 Subject: [PATCH 1083/3892] xfs: replace KM_LARGE with explicit vmalloc use We use the KM_LARGE flag to make kmem_alloc and friends use vmalloc if necessary. As we only need this for a few boot/mount time allocations just switch to explicit vmalloc calls there. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/kmem.c | 56 ++++++++++++++------------------------ fs/xfs/linux-2.6/kmem.h | 21 ++++++++++++-- fs/xfs/linux-2.6/xfs_buf.c | 6 ++-- fs/xfs/quota/xfs_qm.c | 26 ++++++++++++++---- fs/xfs/xfs_itable.c | 8 ++++-- 5 files changed, 66 insertions(+), 51 deletions(-) diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 2d3f90afe5f1..bc7405585def 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -16,7 +16,6 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include #include #include #include @@ -24,8 +23,25 @@ #include "time.h" #include "kmem.h" -#define MAX_VMALLOCS 6 -#define MAX_SLAB_SIZE 0x20000 +/* + * Greedy allocation. May fail and may return vmalloced memory. + * + * Must be freed using kmem_free_large. + */ +void * +kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) +{ + void *ptr; + size_t kmsize = maxsize; + + while (!(ptr = kmem_zalloc_large(kmsize))) { + if ((kmsize >>= 1) <= minsize) + kmsize = minsize; + } + if (ptr) + *size = kmsize; + return ptr; +} void * kmem_alloc(size_t size, unsigned int __nocast flags) @@ -34,19 +50,8 @@ kmem_alloc(size_t size, unsigned int __nocast flags) gfp_t lflags = kmem_flags_convert(flags); void *ptr; -#ifdef DEBUG - if (unlikely(!(flags & KM_LARGE) && (size > PAGE_SIZE))) { - printk(KERN_WARNING "Large %s attempt, size=%ld\n", - __func__, (long)size); - dump_stack(); - } -#endif - do { - if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS) - ptr = kmalloc(size, lflags); - else - ptr = __vmalloc(size, lflags, PAGE_KERNEL); + ptr = kmalloc(size, lflags); if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) return ptr; if (!(++retries % 100)) @@ -68,27 +73,6 @@ kmem_zalloc(size_t size, unsigned int __nocast flags) return ptr; } -void * -kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize, - unsigned int __nocast flags) -{ - void *ptr; - size_t kmsize = maxsize; - unsigned int kmflags = (flags & ~KM_SLEEP) | KM_NOSLEEP; - - while (!(ptr = kmem_zalloc(kmsize, kmflags))) { - if ((kmsize <= minsize) && (flags & KM_NOSLEEP)) - break; - if ((kmsize >>= 1) <= minsize) { - kmsize = minsize; - kmflags = flags; - } - } - if (ptr) - *size = kmsize; - return ptr; -} - void kmem_free(const void *ptr) { diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 179cbd630f69..f7c8f7a9ea6d 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -21,6 +21,7 @@ #include #include #include +#include /* * General memory allocation interfaces @@ -30,7 +31,6 @@ #define KM_NOSLEEP 0x0002u #define KM_NOFS 0x0004u #define KM_MAYFAIL 0x0008u -#define KM_LARGE 0x0010u /* * We use a special process flag to avoid recursive callbacks into @@ -42,7 +42,7 @@ kmem_flags_convert(unsigned int __nocast flags) { gfp_t lflags; - BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_LARGE)); + BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL)); if (flags & KM_NOSLEEP) { lflags = GFP_ATOMIC | __GFP_NOWARN; @@ -56,10 +56,25 @@ kmem_flags_convert(unsigned int __nocast flags) extern void *kmem_alloc(size_t, unsigned int __nocast); extern void *kmem_zalloc(size_t, unsigned int __nocast); -extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast); extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast); extern void kmem_free(const void *); +static inline void *kmem_zalloc_large(size_t size) +{ + void *ptr; + + ptr = vmalloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} +static inline void kmem_free_large(void *ptr) +{ + vfree(ptr); +} + +extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); + /* * Zone interfaces */ diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 730eff1e71a3..44e20e578ba0 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1525,8 +1525,8 @@ xfs_alloc_bufhash( btp->bt_hashshift = external ? 3 : 8; /* 8 or 256 buckets */ btp->bt_hashmask = (1 << btp->bt_hashshift) - 1; - btp->bt_hash = kmem_zalloc((1 << btp->bt_hashshift) * - sizeof(xfs_bufhash_t), KM_SLEEP | KM_LARGE); + btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) * + sizeof(xfs_bufhash_t)); for (i = 0; i < (1 << btp->bt_hashshift); i++) { spin_lock_init(&btp->bt_hash[i].bh_lock); INIT_LIST_HEAD(&btp->bt_hash[i].bh_list); @@ -1537,7 +1537,7 @@ STATIC void xfs_free_bufhash( xfs_buftarg_t *btp) { - kmem_free(btp->bt_hash); + kmem_free_large(btp->bt_hash); btp->bt_hash = NULL; } diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 9e627a8b5b0e..11cfd8245c7c 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -118,9 +118,14 @@ xfs_Gqm_init(void) */ udqhash = kmem_zalloc_greedy(&hsize, XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t), - XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t), - KM_SLEEP | KM_MAYFAIL | KM_LARGE); - gdqhash = kmem_zalloc(hsize, KM_SLEEP | KM_LARGE); + XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t)); + if (!udqhash) + goto out; + + gdqhash = kmem_zalloc_large(hsize); + if (!udqhash) + goto out_free_udqhash; + hsize /= sizeof(xfs_dqhash_t); ndquot = hsize << 8; @@ -170,6 +175,11 @@ xfs_Gqm_init(void) mutex_init(&qcheck_lock); #endif return xqm; + + out_free_udqhash: + kmem_free_large(udqhash); + out: + return NULL; } /* @@ -189,8 +199,8 @@ xfs_qm_destroy( xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); } - kmem_free(xqm->qm_usr_dqhtable); - kmem_free(xqm->qm_grp_dqhtable); + kmem_free_large(xqm->qm_usr_dqhtable); + kmem_free_large(xqm->qm_grp_dqhtable); xqm->qm_usr_dqhtable = NULL; xqm->qm_grp_dqhtable = NULL; xqm->qm_dqhashmask = 0; @@ -219,8 +229,12 @@ xfs_qm_hold_quotafs_ref( */ mutex_lock(&xfs_Gqm_lock); - if (xfs_Gqm == NULL) + if (!xfs_Gqm) { xfs_Gqm = xfs_Gqm_init(); + if (!xfs_Gqm) + return ENOMEM; + } + /* * We can keep a list of all filesystems with quotas mounted for * debugging and statistical purposes, but ... diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 940307a6a60b..3af02314c605 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -408,8 +408,10 @@ xfs_bulkstat( (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); nimask = ~(nicluster - 1); nbcluster = nicluster >> mp->m_sb.sb_inopblog; - irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4, - KM_SLEEP | KM_MAYFAIL | KM_LARGE); + irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); + if (!irbuf) + return ENOMEM; + nirbuf = irbsize / sizeof(*irbuf); /* @@ -727,7 +729,7 @@ xfs_bulkstat( /* * Done, we're either out of filesystem or space to put the data. */ - kmem_free(irbuf); + kmem_free_large(irbuf); *ubcountp = ubelem; /* * Found some inodes, return them now and return the error next time. -- GitLab From 9b00f30762fe9f914eb6e03057a616ed63a4e8ca Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 21 Jan 2010 11:17:20 +0000 Subject: [PATCH 1084/3892] xfs: quota limit statvfs available blocks A "df" run on an NFS client of an exported XFS file system reports the wrong information for "available" blocks. When a block quota is enforced, the amount reported as free is limited by the quota, but the amount reported available is not (and should be). Reported-by: Guk-Bong, Kwon Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_qm_bhv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index a5346630dfae..97b410c12794 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c @@ -59,7 +59,7 @@ xfs_fill_statvfs_from_dquot( be64_to_cpu(dp->d_blk_hardlimit); if (limit && statp->f_blocks > limit) { statp->f_blocks = limit; - statp->f_bfree = + statp->f_bfree = statp->f_bavail = (statp->f_blocks > be64_to_cpu(dp->d_bcount)) ? (statp->f_blocks - be64_to_cpu(dp->d_bcount)) : 0; } -- GitLab From 8f47afe080df450eedda7b29873512c2a9a9adcb Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Tue, 19 Jan 2010 05:15:00 +0000 Subject: [PATCH 1085/3892] be2net: ethtool self test reorganization. The ddr dma ethtool self test needs to be performed even when ETH_TEST_FL_OFFLINE is not set. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_ethtool.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index f18c02f3a5e4..2f2ebbd678f2 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -545,10 +545,11 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) &data[2]) != 0) { test->flags |= ETH_TEST_FL_FAILED; } + } - data[3] = be_test_ddr_dma(adapter); - if (data[3] != 0) - test->flags |= ETH_TEST_FL_FAILED; + if (be_test_ddr_dma(adapter) != 0) { + data[3] = 1; + test->flags |= ETH_TEST_FL_FAILED; } } -- GitLab From 4276e47e2d1c85a2477caf0d22b91c4f2377fba8 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Tue, 19 Jan 2010 05:15:36 +0000 Subject: [PATCH 1086/3892] be2net: Add link test to list of ethtool self tests. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_ethtool.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 2f2ebbd678f2..09d8899b2de9 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -112,6 +112,7 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = { "PHY Loopback test", "External Loopback test", "DDR DMA test" + "Link test" }; #define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests) @@ -529,6 +530,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { struct be_adapter *adapter = netdev_priv(netdev); + bool link_up; + u8 mac_speed = 0; + u16 qos_link_speed = 0; memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); @@ -552,6 +556,13 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) test->flags |= ETH_TEST_FL_FAILED; } + if (be_cmd_link_status_query(adapter, &link_up, &mac_speed, + &qos_link_speed) != 0) { + test->flags |= ETH_TEST_FL_FAILED; + data[4] = -1; + } else if (mac_speed) { + data[4] = 1; + } } static int -- GitLab From 212b3c8b8ab94d983c2e0ee1821f17dd5b4e0859 Mon Sep 17 00:00:00 2001 From: Jean-Hugues Deschenes Date: Fri, 22 Jan 2010 10:08:31 -0700 Subject: [PATCH 1087/3892] spi/dw_spi: Fix dw_spi_mmio to depend on HAVE_CLK dw_spi_mmio is dependent on the clock framework. This marks it as such in Kconfig. Signed-off-by: Jean-Hugues Deschenes Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1d1e39686c38..0fee95cd9a49 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -336,7 +336,7 @@ config SPI_DW_PCI config SPI_DW_MMIO tristate "Memory-mapped io interface driver for DW SPI core" - depends on SPI_DESIGNWARE + depends on SPI_DESIGNWARE && HAVE_CLK # # There are lots of SPI device types, with sensors and memory -- GitLab From ea87bb7853168434f4a82426dd1ea8421f9e604d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 20 Jan 2010 20:58:57 +0000 Subject: [PATCH 1088/3892] sched: Extend enqueue_task to allow head queueing The ability of enqueueing a task to the head of a SCHED_FIFO priority list is required to fix some violations of POSIX scheduling policy. Extend the related functions with a "head" argument. Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Tested-by: Carsten Emde Tested-by: Mathias Weber LKML-Reference: <20100120171629.734886007@linutronix.de> --- include/linux/sched.h | 3 ++- kernel/sched.c | 13 +++++++------ kernel/sched_fair.c | 3 ++- kernel/sched_rt.c | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 8b079735ae5f..b35c0c7130c8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1067,7 +1067,8 @@ struct sched_domain; struct sched_class { const struct sched_class *next; - void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup); + void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup, + bool head); void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep); void (*yield_task) (struct rq *rq); diff --git a/kernel/sched.c b/kernel/sched.c index 41e76d325648..f47560ff3346 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1856,13 +1856,14 @@ static void update_avg(u64 *avg, u64 sample) *avg += diff >> 3; } -static void enqueue_task(struct rq *rq, struct task_struct *p, int wakeup) +static void +enqueue_task(struct rq *rq, struct task_struct *p, int wakeup, bool head) { if (wakeup) p->se.start_runtime = p->se.sum_exec_runtime; sched_info_queued(p); - p->sched_class->enqueue_task(rq, p, wakeup); + p->sched_class->enqueue_task(rq, p, wakeup, head); p->se.on_rq = 1; } @@ -1892,7 +1893,7 @@ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) if (task_contributes_to_load(p)) rq->nr_uninterruptible--; - enqueue_task(rq, p, wakeup); + enqueue_task(rq, p, wakeup, false); inc_nr_running(rq); } @@ -4236,7 +4237,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) if (running) p->sched_class->set_curr_task(rq); if (on_rq) { - enqueue_task(rq, p, 0); + enqueue_task(rq, p, 0, false); check_class_changed(rq, p, prev_class, oldprio, running); } @@ -4280,7 +4281,7 @@ void set_user_nice(struct task_struct *p, long nice) delta = p->prio - old_prio; if (on_rq) { - enqueue_task(rq, p, 0); + enqueue_task(rq, p, 0, false); /* * If the task increased its priority or is running and * lowered its priority, then reschedule its CPU: @@ -8230,7 +8231,7 @@ void sched_move_task(struct task_struct *tsk) if (unlikely(running)) tsk->sched_class->set_curr_task(rq); if (on_rq) - enqueue_task(rq, tsk, 0); + enqueue_task(rq, tsk, 0, false); task_rq_unlock(rq, &flags); } diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 22231ccb2f98..0e7a7af9cf8b 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1053,7 +1053,8 @@ static inline void hrtick_update(struct rq *rq) * increased. Here we update the fair scheduling stats and * then put the task into the rbtree: */ -static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup) +static void +enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup, bool head) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 502bb614e40a..38076dabb44a 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -878,7 +878,8 @@ static void dequeue_rt_entity(struct sched_rt_entity *rt_se) /* * Adding/removing a task to/from a priority array: */ -static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup) +static void +enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, bool head) { struct sched_rt_entity *rt_se = &p->rt; -- GitLab From 37dad3fce97f01e5149d69de0833d8452c0e862e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 20 Jan 2010 20:59:01 +0000 Subject: [PATCH 1089/3892] sched: Implement head queueing for sched_rt The ability of enqueueing a task to the head of a SCHED_FIFO priority list is required to fix some violations of POSIX scheduling policy. Implement the functionality in sched_rt. Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Tested-by: Carsten Emde Tested-by: Mathias Weber LKML-Reference: <20100120171629.772169931@linutronix.de> --- kernel/sched_rt.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 38076dabb44a..ca49ceb01201 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -194,7 +194,7 @@ static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) return rt_se->my_q; } -static void enqueue_rt_entity(struct sched_rt_entity *rt_se); +static void enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head); static void dequeue_rt_entity(struct sched_rt_entity *rt_se); static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) @@ -204,7 +204,7 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) if (rt_rq->rt_nr_running) { if (rt_se && !on_rt_rq(rt_se)) - enqueue_rt_entity(rt_se); + enqueue_rt_entity(rt_se, false); if (rt_rq->highest_prio.curr < curr->prio) resched_task(curr); } @@ -803,7 +803,7 @@ void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) dec_rt_group(rt_se, rt_rq); } -static void __enqueue_rt_entity(struct sched_rt_entity *rt_se) +static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head) { struct rt_rq *rt_rq = rt_rq_of_se(rt_se); struct rt_prio_array *array = &rt_rq->active; @@ -819,7 +819,10 @@ static void __enqueue_rt_entity(struct sched_rt_entity *rt_se) if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running)) return; - list_add_tail(&rt_se->run_list, queue); + if (head) + list_add(&rt_se->run_list, queue); + else + list_add_tail(&rt_se->run_list, queue); __set_bit(rt_se_prio(rt_se), array->bitmap); inc_rt_tasks(rt_se, rt_rq); @@ -856,11 +859,11 @@ static void dequeue_rt_stack(struct sched_rt_entity *rt_se) } } -static void enqueue_rt_entity(struct sched_rt_entity *rt_se) +static void enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head) { dequeue_rt_stack(rt_se); for_each_sched_rt_entity(rt_se) - __enqueue_rt_entity(rt_se); + __enqueue_rt_entity(rt_se, head); } static void dequeue_rt_entity(struct sched_rt_entity *rt_se) @@ -871,7 +874,7 @@ static void dequeue_rt_entity(struct sched_rt_entity *rt_se) struct rt_rq *rt_rq = group_rt_rq(rt_se); if (rt_rq && rt_rq->rt_nr_running) - __enqueue_rt_entity(rt_se); + __enqueue_rt_entity(rt_se, false); } } @@ -886,7 +889,7 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup, bool head) if (wakeup) rt_se->timeout = 0; - enqueue_rt_entity(rt_se); + enqueue_rt_entity(rt_se, head); if (!task_current(rq, p) && p->rt.nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); -- GitLab From 60db48cacb9b253d5607a5ff206112a59cd09e34 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 20 Jan 2010 20:59:06 +0000 Subject: [PATCH 1090/3892] sched: Queue a deboosted task to the head of the RT prio queue rtmutex_set_prio() is used to implement priority inheritance for futexes. When a task is deboosted it gets enqueued at the tail of its RT priority list. This is violating the POSIX scheduling semantics: rt priority list X contains two runnable tasks A and B task A runs with priority X and holds mutex M task C preempts A and is blocked on mutex M -> task A is boosted to priority of task C (Y) task A unlocks the mutex M and deboosts itself -> A is dequeued from rt priority list Y -> A is enqueued to the tail of rt priority list X task C schedules away task B runs This is wrong as task A did not schedule away and therefor violates the POSIX scheduling semantics. Enqueue the task to the head of the priority list instead. Reported-by: Mathias Weber Reported-by: Carsten Emde Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Tested-by: Carsten Emde Tested-by: Mathias Weber LKML-Reference: <20100120171629.809074113@linutronix.de> --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index f47560ff3346..a56ead42d651 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4237,7 +4237,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) if (running) p->sched_class->set_curr_task(rq); if (on_rq) { - enqueue_task(rq, p, 0, false); + enqueue_task(rq, p, 0, oldprio < prio); check_class_changed(rq, p, prev_class, oldprio, running); } -- GitLab From 2147d3f00f85c9e993786863d8138694672da01b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 Jan 2010 09:08:31 +0800 Subject: [PATCH 1091/3892] ACPICA: Update for new gcc-4 warning options Added several new options for the gcc-4 generation, and updated the source accordingly. This includes some code restructuring to eliminate unreachable code, elimination of some gotos, elimination of unused return values, and some additional casting. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/exconfig.c | 13 +++++-------- drivers/acpi/acpica/hwgpe.c | 6 ++---- drivers/acpi/acpica/nspredef.c | 24 +++++++++++------------- drivers/acpi/acpica/nsrepair2.c | 24 +++++++++--------------- drivers/acpi/acpica/utmutex.c | 16 +++------------- include/acpi/platform/acenv.h | 4 ++-- 6 files changed, 32 insertions(+), 55 deletions(-) diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 46adfa541cbc..2ea8daccba1c 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -490,7 +490,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, status = acpi_tb_add_table(&table_desc, &table_index); if (ACPI_FAILURE(status)) { - goto cleanup; + + /* Delete allocated table buffer */ + + acpi_tb_delete_table(&table_desc); + return_ACPI_STATUS(status); } /* @@ -533,13 +537,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, acpi_gbl_table_handler_context); } - cleanup: - if (ACPI_FAILURE(status)) { - - /* Delete allocated table buffer */ - - acpi_tb_delete_table(&table_desc); - } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index c28c41b3180b..55c4507957bb 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -224,7 +224,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + return (status); } if (register_bit & in_byte) { @@ -234,9 +234,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* Set return value */ (*event_status) = local_event_status; - - unlock_and_exit: - return (status); + return (AE_OK); } /****************************************************************************** diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index d34fa59548f7..309586f5809c 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -1000,27 +1000,25 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data, /* Is the object one of the expected types? */ - if (!(return_btype & expected_btypes)) { + if (return_btype & expected_btypes) { - /* Type mismatch -- attempt repair of the returned object */ + /* For reference objects, check that the reference type is correct */ - status = acpi_ns_repair_object(data, expected_btypes, - package_index, - return_object_ptr); - if (ACPI_SUCCESS(status)) { - return (AE_OK); /* Repair was successful */ + if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) { + status = acpi_ns_check_reference(data, return_object); } - goto type_error_exit; + + return (status); } - /* For reference objects, check that the reference type is correct */ + /* Type mismatch -- attempt repair of the returned object */ - if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) { - status = acpi_ns_check_reference(data, return_object); + status = acpi_ns_repair_object(data, expected_btypes, + package_index, return_object_ptr); + if (ACPI_SUCCESS(status)) { + return (AE_OK); /* Repair was successful */ } - return (status); - type_error_exit: /* Create a string with all expected types for this predefined object */ diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index f13691c1cca5..6d6926466a08 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -93,7 +93,7 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, u32 sort_index, u8 sort_direction, char *sort_key_name); -static acpi_status +static void acpi_ns_sort_list(union acpi_operand_object **elements, u32 count, u32 index, u8 sort_direction); @@ -443,7 +443,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, union acpi_operand_object *obj_desc; u32 i; u32 previous_value; - acpi_status status; ACPI_FUNCTION_NAME(ns_check_sorted_list); @@ -494,19 +493,15 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, /* * The list must be sorted in the specified order. If we detect a - * discrepancy, issue a warning and sort the entire list + * discrepancy, sort the entire list. */ if (((sort_direction == ACPI_SORT_ASCENDING) && (obj_desc->integer.value < previous_value)) || ((sort_direction == ACPI_SORT_DESCENDING) && (obj_desc->integer.value > previous_value))) { - status = - acpi_ns_sort_list(return_object->package.elements, - outer_element_count, sort_index, - sort_direction); - if (ACPI_FAILURE(status)) { - return (status); - } + acpi_ns_sort_list(return_object->package.elements, + outer_element_count, sort_index, + sort_direction); data->flags |= ACPI_OBJECT_REPAIRED; @@ -615,15 +610,16 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data, * Index - Sort by which package element * sort_direction - Ascending or Descending sort * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Sort the objects that are in a package element list. * - * NOTE: Assumes that all NULL elements have been removed from the package. + * NOTE: Assumes that all NULL elements have been removed from the package, + * and that all elements have been verified to be of type Integer. * *****************************************************************************/ -static acpi_status +static void acpi_ns_sort_list(union acpi_operand_object **elements, u32 count, u32 index, u8 sort_direction) { @@ -652,6 +648,4 @@ acpi_ns_sort_list(union acpi_operand_object **elements, } } } - - return (AE_OK); } diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 80bb65154117..1f58a8824146 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utmutex") /* Local prototypes */ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id); -static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id); +static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id); /******************************************************************************* * @@ -114,7 +114,7 @@ void acpi_ut_mutex_terminate(void) /* Delete each predefined mutex object */ for (i = 0; i < ACPI_NUM_MUTEX; i++) { - (void)acpi_ut_delete_mutex(i); + acpi_ut_delete_mutex(i); } /* Delete the spinlocks */ @@ -146,10 +146,6 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id); - if (mutex_id > ACPI_MAX_MUTEX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - if (!acpi_gbl_mutex_info[mutex_id].mutex) { status = acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex); @@ -173,21 +169,15 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) * ******************************************************************************/ -static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) +static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) { ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id); - if (mutex_id > ACPI_MAX_MUTEX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex); acpi_gbl_mutex_info[mutex_id].mutex = NULL; acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; - - return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index e62f10d9a7d8..fa7689a6fc4b 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -311,8 +311,8 @@ typedef char *va_list; #define ACPI_MEMCMP(s1,s2,n) acpi_ut_memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (acpi_size)(n)) -#define ACPI_TOUPPER acpi_ut_to_upper -#define ACPI_TOLOWER acpi_ut_to_lower +#define ACPI_TOUPPER(c) acpi_ut_to_upper ((int) (c)) +#define ACPI_TOLOWER(c) acpi_ut_to_lower ((int) (c)) #endif /* ACPI_USE_SYSTEM_CLIBRARY */ -- GitLab From a8357b0c95484b46944728712f8810d3b37bf588 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 22 Jan 2010 19:07:36 +0800 Subject: [PATCH 1092/3892] ACPICA: Update all ACPICA copyrights and signons to 2010 Add 2010 copyright to all module headers and signons, including the Linux header. This affects virtually every file in the ACPICA core subsystem, iASL compiler, and all utilities. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/accommon.h | 2 +- drivers/acpi/acpica/acconfig.h | 2 +- drivers/acpi/acpica/acdebug.h | 2 +- drivers/acpi/acpica/acdispat.h | 2 +- drivers/acpi/acpica/acevents.h | 2 +- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/achware.h | 2 +- drivers/acpi/acpica/acinterp.h | 2 +- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/acmacros.h | 2 +- drivers/acpi/acpica/acnamesp.h | 2 +- drivers/acpi/acpica/acobject.h | 2 +- drivers/acpi/acpica/acopcode.h | 2 +- drivers/acpi/acpica/acparser.h | 2 +- drivers/acpi/acpica/acpredef.h | 2 +- drivers/acpi/acpica/acresrc.h | 2 +- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/actables.h | 2 +- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/amlcode.h | 2 +- drivers/acpi/acpica/amlresrc.h | 2 +- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsinit.c | 2 +- drivers/acpi/acpica/dsmethod.c | 2 +- drivers/acpi/acpica/dsmthdat.c | 2 +- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/dsopcode.c | 2 +- drivers/acpi/acpica/dsutils.c | 2 +- drivers/acpi/acpica/dswexec.c | 2 +- drivers/acpi/acpica/dswload.c | 2 +- drivers/acpi/acpica/dswscope.c | 2 +- drivers/acpi/acpica/dswstate.c | 2 +- drivers/acpi/acpica/evevent.c | 2 +- drivers/acpi/acpica/evgpe.c | 2 +- drivers/acpi/acpica/evgpeblk.c | 2 +- drivers/acpi/acpica/evmisc.c | 2 +- drivers/acpi/acpica/evregion.c | 2 +- drivers/acpi/acpica/evrgnini.c | 2 +- drivers/acpi/acpica/evsci.c | 2 +- drivers/acpi/acpica/evxface.c | 2 +- drivers/acpi/acpica/evxfevnt.c | 2 +- drivers/acpi/acpica/evxfregn.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 2 +- drivers/acpi/acpica/excreate.c | 2 +- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/exfield.c | 2 +- drivers/acpi/acpica/exfldio.c | 2 +- drivers/acpi/acpica/exmisc.c | 2 +- drivers/acpi/acpica/exmutex.c | 2 +- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg1.c | 2 +- drivers/acpi/acpica/exoparg2.c | 2 +- drivers/acpi/acpica/exoparg3.c | 2 +- drivers/acpi/acpica/exoparg6.c | 2 +- drivers/acpi/acpica/exprep.c | 2 +- drivers/acpi/acpica/exregion.c | 2 +- drivers/acpi/acpica/exresnte.c | 2 +- drivers/acpi/acpica/exresolv.c | 2 +- drivers/acpi/acpica/exresop.c | 2 +- drivers/acpi/acpica/exstore.c | 2 +- drivers/acpi/acpica/exstoren.c | 2 +- drivers/acpi/acpica/exstorob.c | 2 +- drivers/acpi/acpica/exsystem.c | 2 +- drivers/acpi/acpica/exutils.c | 2 +- drivers/acpi/acpica/hwacpi.c | 2 +- drivers/acpi/acpica/hwgpe.c | 2 +- drivers/acpi/acpica/hwregs.c | 2 +- drivers/acpi/acpica/hwsleep.c | 2 +- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/hwvalid.c | 2 +- drivers/acpi/acpica/hwxface.c | 2 +- drivers/acpi/acpica/nsaccess.c | 2 +- drivers/acpi/acpica/nsalloc.c | 2 +- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nsdumpdv.c | 2 +- drivers/acpi/acpica/nseval.c | 2 +- drivers/acpi/acpica/nsinit.c | 2 +- drivers/acpi/acpica/nsload.c | 2 +- drivers/acpi/acpica/nsnames.c | 2 +- drivers/acpi/acpica/nsobject.c | 2 +- drivers/acpi/acpica/nsparse.c | 2 +- drivers/acpi/acpica/nspredef.c | 2 +- drivers/acpi/acpica/nsrepair.c | 2 +- drivers/acpi/acpica/nsrepair2.c | 2 +- drivers/acpi/acpica/nssearch.c | 2 +- drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/nswalk.c | 2 +- drivers/acpi/acpica/nsxfeval.c | 2 +- drivers/acpi/acpica/nsxfname.c | 2 +- drivers/acpi/acpica/nsxfobj.c | 2 +- drivers/acpi/acpica/psargs.c | 2 +- drivers/acpi/acpica/psloop.c | 2 +- drivers/acpi/acpica/psopcode.c | 2 +- drivers/acpi/acpica/psparse.c | 2 +- drivers/acpi/acpica/psscope.c | 2 +- drivers/acpi/acpica/pstree.c | 2 +- drivers/acpi/acpica/psutils.c | 2 +- drivers/acpi/acpica/pswalk.c | 2 +- drivers/acpi/acpica/psxface.c | 2 +- drivers/acpi/acpica/rsaddr.c | 2 +- drivers/acpi/acpica/rscalc.c | 2 +- drivers/acpi/acpica/rscreate.c | 2 +- drivers/acpi/acpica/rsdump.c | 2 +- drivers/acpi/acpica/rsinfo.c | 2 +- drivers/acpi/acpica/rsio.c | 2 +- drivers/acpi/acpica/rsirq.c | 2 +- drivers/acpi/acpica/rslist.c | 2 +- drivers/acpi/acpica/rsmemory.c | 2 +- drivers/acpi/acpica/rsmisc.c | 2 +- drivers/acpi/acpica/rsutils.c | 2 +- drivers/acpi/acpica/rsxface.c | 2 +- drivers/acpi/acpica/tbfadt.c | 2 +- drivers/acpi/acpica/tbfind.c | 2 +- drivers/acpi/acpica/tbinstal.c | 2 +- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 2 +- drivers/acpi/acpica/tbxfroot.c | 2 +- drivers/acpi/acpica/utalloc.c | 2 +- drivers/acpi/acpica/utcopy.c | 2 +- drivers/acpi/acpica/utdebug.c | 2 +- drivers/acpi/acpica/utdelete.c | 2 +- drivers/acpi/acpica/uteval.c | 2 +- drivers/acpi/acpica/utglobal.c | 2 +- drivers/acpi/acpica/utids.c | 2 +- drivers/acpi/acpica/utinit.c | 2 +- drivers/acpi/acpica/utlock.c | 2 +- drivers/acpi/acpica/utmath.c | 2 +- drivers/acpi/acpica/utmisc.c | 2 +- drivers/acpi/acpica/utmutex.c | 2 +- drivers/acpi/acpica/utobject.c | 2 +- drivers/acpi/acpica/utresrc.c | 2 +- drivers/acpi/acpica/utstate.c | 2 +- drivers/acpi/acpica/utxface.c | 2 +- include/acpi/acexcep.h | 2 +- include/acpi/acnames.h | 2 +- include/acpi/acoutput.h | 2 +- include/acpi/acpi.h | 2 +- include/acpi/acpiosxf.h | 2 +- include/acpi/acpixf.h | 2 +- include/acpi/acrestyp.h | 2 +- include/acpi/actbl.h | 2 +- include/acpi/actbl1.h | 2 +- include/acpi/actbl2.h | 43 +++++++++++++++++++++++++++++++++ include/acpi/actypes.h | 2 +- include/acpi/platform/acenv.h | 2 +- include/acpi/platform/acgcc.h | 2 +- include/acpi/platform/aclinux.h | 2 +- 148 files changed, 190 insertions(+), 147 deletions(-) diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 3b20786cbb0d..3e50c74ed4a1 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index a4471e3d3853..33181ad350d5 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index a4fb001d96f1..48faf3eba9fb 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 6291904be01e..894a0ff2a946 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 0bba148a2c61..13d2b0bc2144 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 29ba66d5a790..f8dd8f250ac4 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 36192f142fbb..5900f135dc6d 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 5db9f2916f7c..c9d7802f9118 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 81e64f478679..2caf141076fc 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 7d9ba6e57554..a4a9519a1288 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 61edb156e8d0..73f9b0c88dd8 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 64062b1be3ee..6d0b4de68cf6 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index dfdf63327885..8c15ff43f42b 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 22881e8ce229..d0bb0fd3e57a 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 57bdaf6ffab1..97116082cb6c 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index eef5bd7a59fa..528bcbaf4ce7 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 7980a26bad35..161bc0e3d70a 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 01c76b8ea7ba..8ff3b741df28 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 3a451a21a3f9..d3ae626cf715 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 4940249f2524..1f484ba228fc 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 7b070e42b7c5..0e5798fcbb19 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 54a225e56a64..effbf1550b03 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index f23fa0be6fc2..abe140318a74 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index e786f9fd767f..721039233aa7 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 0ba19f84ad82..cc343b959540 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 9bc1ba076347..edd7aa238cf1 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index b79978f7bc71..bf980cadb1e8 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index dfa104102926..306c62ab2e88 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index f0280856dc0e..6b76c486d784 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index b40513dd6a6a..140a9d002959 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 908645e72f03..d1e701709dac 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index e46c821cf572..050df8164165 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index cd55c774e882..c1e6f472d435 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index afacf4416c73..1685ce37dd12 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 247920900187..77670e04812d 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index ce224e1eaa89..e77374d92816 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 5336d911fbf0..654b2833598c 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index ff168052a332..86bd5a7f40d0 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 567b356c85af..8dfbaa96e422 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 2fe0809d4eb2..292c36375de8 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index eed7a38d25f2..8bbde6244908 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index c98aa7c2d67c..541cbc1544d5 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 2ea8daccba1c..cee2bceb2169 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 51d5f224f9fa..adcaf3b89587 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 02b25d233d99..0aa57d938698 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index de3446372ddc..d39d438ba1e3 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 1588a2d660e7..c9190c784194 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index d7b3b418fb45..dc2f9e8bee6e 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 998eac329937..d29e542bb6df 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 3c456bd575d0..cc8a10268f68 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index ffdae122d94a..679f308c5a89 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 752fe48b2d20..2b2128e52d42 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 85d95c92dfd3..ea115021ee7d 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 253f9e122584..25d1cd35c3e1 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 295542e6bd51..580abbd924dc 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 52fec07064f0..edf62bf5b266 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 2bd83ac57c3a..0cd88f6c95f7 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 607958ff467c..fdc1b27999ef 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index c93b54ce7f78..fdd6a7079b97 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 5c729a9e9131..c5ecd615f145 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 6efd07a4f779..702b9ecfd44b 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 608e838d537e..d4af684620ca 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 257706e7734f..e972b667b09b 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index 3d00b9357233..c6cb6042603c 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 7d41f99f7052..0f2ce9c52f02 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 9af361a191e7..679a112a7d26 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 55c4507957bb..bd72319a38f0 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 15c9ed2be853..ec7fc227b33f 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index cc22f9a585b0..5e6d4dbb8024 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 6b282e85d039..ce0cbbc18ad0 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index ec33f270c5b7..e26c17d4b716 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 647c7b6e6756..50cc3be77724 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index d622ba770000..aa2b80132d0a 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 8a58a1b85aa0..982269c1fa48 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index e37836e27e29..0689d36638d9 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 36be7f0e97ec..d2a97921e249 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index af9fe9103734..f52829cc294b 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 4f8abac231d2..9bd6f050f299 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index a7234e60e985..df18be94fefe 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 8f9a4875ce26..959372451635 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 60f3af08d28c..41a9213dd5af 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 662a4bd5b621..27cda52c76bc 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 309586f5809c..ba1072fb0daa 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 4fd1bdb056b2..c82060fd3821 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 6d6926466a08..29ff5d14e1d5 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 7e865639a928..08f8b3f5ccaa 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 47d91e668a1b..24d05a87a2a3 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index d7e6b52b4482..00e79fb26029 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index f0c0892bc7e5..c5a5357c69e6 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index e611dd961b20..b01e45a415e3 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 0cc6ba01a495..eafef24ea448 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index b161f3544b51..6aa6a1a4d918 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 0988e4a8901d..59aabaeab1d3 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 3bc3a60194d6..2b0c3be2b1b8 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 4df8f139026c..8d81542194d4 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 2feca5ca9581..40e2b279ea12 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 4d3389118ec3..d4b970c3630b 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index e636e078ad3d..fe29eee5adb1 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 78b8b791f2ae..8abb9629443d 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index d0c1b91eb8ca..6064dd4e94c2 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 1e437bfd8db5..226c806ae986 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 3c4dcc3d1069..d6ebf7ec622d 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index a3c23d686d5f..61a038dbfe23 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 3f0ca5a12d34..f859b0386fe4 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 77b25fdb459c..1fd868b964fd 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 35a49aa95609..33bff17c0bbc 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 2e0256983aa6..545da40d7fa7 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 1b1dbc69f087..fd057c72d252 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index ddc76cebdc92..887b8ba8c432 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 5bc49a553284..07de352fa443 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index bc03d5966829..22cfcfbd9fff 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index f27feb4772f6..9f6a6e7e1c8e 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index c016335fb759..f43fbe0fc3fc 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 1054dfd49207..e252180ce61c 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 63e82329a9e8..7ec02b0f69e0 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 1f15497f00d1..02723a9fb10c 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index a88f02bd6c94..5217a6159a31 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 85ea834199e2..dda6e8c497d3 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 7580f6b3069e..3d706b8fd449 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index f857c5efb79f..97ec3621e71d 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 527d729f6815..e156915fa0e8 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 96e26e70c63d..16b51c69606a 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 5d54e36ab453..f4c5ee8109bc 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 3f2c68f4e959..49286a39b09e 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 52eaae404554..1397fadd0d4b 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 9d0919ebf7b0..a39c93dac719 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index 25e03120686d..b081cd46a15f 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index c9f682d640ef..7cfa1d8164d0 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 6c6a5137b728..fb55924e6e0f 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 1f58a8824146..55d014ed6d55 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 42e658b543f1..3356f0cb0745 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 91b7c00236f4..7965919000b1 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 0440c958f5a4..d35d109b8da2 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index b1f5f680bc78..db9d8ca57987 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 473d584b1d31..5b2e5e80ecb0 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index c1343a9265fa..9cf736ea4691 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index d814da4b5365..d7726685797e 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index 472b7bf0c5d4..a091cabca4b1 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index eb0e7189075f..c7e9431e16f1 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -8,7 +8,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 86e9735a96bd..2bf965ac06da 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index 9ffe00feada6..dc6302e94793 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 1b6587952604..ad2001683ba7 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 0b9b430b092b..c637b75b9f3f 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 6f3dce9991e1..5b02e307bff3 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1,3 +1,46 @@ +/****************************************************************************** + * + * Name: actbl2.h - ACPI Specification Revision 2.0 Tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2010, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + #ifndef __ACTBL2_H__ #define __ACTBL2_H__ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 153f12dc3373..4e65c201dcd4 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index fa7689a6fc4b..c05aeba9e8f0 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 6aadbf84ae71..0cd53e3cd1a3 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 09469971472f..e5039a2856f8 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2009, Intel Corp. + * Copyright (C) 2000 - 2010, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without -- GitLab From 5f8902acf87aa206ee4b3f633104456d82747ca6 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 21 Jan 2010 09:15:20 +0800 Subject: [PATCH 1093/3892] ACPICA: AcpiGetDevices: Eliminate unnecessary _STA calls In the case where a specific _HID is requested, do not run _STA until a _HID match is found. This eliminates potentially dozens of _STA calls during a search for a particular device/HID. Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/nsxfeval.c | 52 +++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index c5a5357c69e6..ebef8a7fd707 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -562,25 +562,20 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (AE_BAD_PARAMETER); } - /* Run _STA to determine if device is present */ - - status = acpi_ut_execute_STA(node, &flags); - if (ACPI_FAILURE(status)) { - return (AE_CTRL_DEPTH); - } - - if (!(flags & ACPI_STA_DEVICE_PRESENT) && - !(flags & ACPI_STA_DEVICE_FUNCTIONING)) { - /* - * Don't examine the children of the device only when the - * device is neither present nor functional. See ACPI spec, - * description of _STA for more information. - */ - return (AE_CTRL_DEPTH); - } - - /* Filter based on device HID & CID */ - + /* + * First, filter based on the device HID and CID. + * + * 01/2010: For this case where a specific HID is requested, we don't + * want to run _STA until we have an actual HID match. Thus, we will + * not unnecessarily execute _STA on devices for which the caller + * doesn't care about. Previously, _STA was executed unconditionally + * on all devices found here. + * + * A side-effect of this change is that now we will continue to search + * for a matching HID even under device trees where the parent device + * would have returned a _STA that indicates it is not present or + * not functioning (thus aborting the search on that branch). + */ if (info->hid != NULL) { status = acpi_ut_execute_HID(node, &hid); if (status == AE_NOT_FOUND) { @@ -620,6 +615,25 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, } } + /* Run _STA to determine if device is present */ + + status = acpi_ut_execute_STA(node, &flags); + if (ACPI_FAILURE(status)) { + return (AE_CTRL_DEPTH); + } + + if (!(flags & ACPI_STA_DEVICE_PRESENT) && + !(flags & ACPI_STA_DEVICE_FUNCTIONING)) { + /* + * Don't examine the children of the device only when the + * device is neither present nor functional. See ACPI spec, + * description of _STA for more information. + */ + return (AE_CTRL_DEPTH); + } + + /* We have a valid device, invoke the user function */ + status = info->user_function(obj_handle, nesting_level, info->context, return_value); return (status); -- GitLab From 091f4d718620a79698e1c8ca3e9acbf78eb62da3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 Jan 2010 09:28:32 +0800 Subject: [PATCH 1094/3892] ACPICA: Predefined name repair: fix NULL package elements For the predefined methods that return fixed-length packages (or subpackages), attempt repair for a NULL element. Create an Integer of value 0, a NULL String, or a zero-length buffer as appropriate. http://www.acpica.org/bugzilla/show_bug.cgi?id=818 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/acnamesp.h | 16 ++- drivers/acpi/acpica/nspredef.c | 27 ++++- drivers/acpi/acpica/nsrepair.c | 173 ++++++++++++++++++++++++++++++++ drivers/acpi/acpica/nsrepair2.c | 84 ---------------- 5 files changed, 209 insertions(+), 92 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2caf141076fc..681205c75563 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -374,6 +374,7 @@ union acpi_predefined_info { struct acpi_predefined_data { char *pathname; const union acpi_predefined_info *predefined; + union acpi_operand_object *parent_package; u32 flags; u8 node_flags; }; diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 73f9b0c88dd8..258159cfcdfa 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -286,6 +286,17 @@ acpi_status acpi_ns_repair_package_list(struct acpi_predefined_data *data, union acpi_operand_object **obj_desc_ptr); +acpi_status +acpi_ns_repair_null_element(struct acpi_predefined_data *data, + u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr); + +void +acpi_ns_remove_null_elements(struct acpi_predefined_data *data, + u8 package_type, + union acpi_operand_object *obj_desc); + /* * nsrepair2 - Return object repair for specific * predefined methods/objects @@ -296,11 +307,6 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data, acpi_status validate_status, union acpi_operand_object **return_object_ptr); -void -acpi_ns_remove_null_elements(struct acpi_predefined_data *data, - u8 package_type, - union acpi_operand_object *obj_desc); - /* * nssearch - Namespace searching and entry */ diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index ba1072fb0daa..7096bcda0c72 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -231,6 +231,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * Note: Package may have been newly created by call above. */ if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) { + data->parent_package = *return_object_ptr; status = acpi_ns_check_package(data, return_object_ptr); if (ACPI_FAILURE(status)) { goto exit; @@ -710,6 +711,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, for (i = 0; i < count; i++) { sub_package = *elements; sub_elements = sub_package->package.elements; + data->parent_package = sub_package; /* Each sub-object must be of type Package */ @@ -721,6 +723,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, /* Examine the different types of expected sub-packages */ + data->parent_package = sub_package; switch (package->ret_info.type) { case ACPI_PTYPE2: case ACPI_PTYPE2_PKG_COUNT: @@ -800,7 +803,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, /* * First element is the (Integer) count of elements, including - * the count field. + * the count field (the ACPI name is num_elements) */ status = acpi_ns_check_object_type(data, sub_elements, ACPI_RTYPE_INTEGER, @@ -822,6 +825,16 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, expected_count = package->ret_info.count1; goto package_too_small; } + if (expected_count == 0) { + /* + * Either the num_entries element was originally zero or it was + * a NULL element and repaired to an Integer of value zero. + * In either case, repair it by setting num_entries to be the + * actual size of the subpackage. + */ + expected_count = sub_package->package.count; + (*sub_elements)->integer.value = expected_count; + } /* Check the type of each sub-package element */ @@ -945,10 +958,18 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data, char type_buffer[48]; /* Room for 5 types */ /* - * If we get a NULL return_object here, it is a NULL package element, - * and this is always an error. + * If we get a NULL return_object here, it is a NULL package element. + * Since all extraneous NULL package elements were removed earlier by a + * call to acpi_ns_remove_null_elements, this is an unexpected NULL element. + * We will attempt to repair it. */ if (!return_object) { + status = acpi_ns_repair_null_element(data, expected_btypes, + package_index, + return_object_ptr); + if (ACPI_SUCCESS(status)) { + return (AE_OK); /* Repair was successful */ + } goto type_error_exit; } diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index c82060fd3821..d4be37751be4 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -45,6 +45,7 @@ #include "accommon.h" #include "acnamesp.h" #include "acinterp.h" +#include "acpredef.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsrepair") @@ -71,6 +72,12 @@ ACPI_MODULE_NAME("nsrepair") * Buffer -> Package of Integers * Package -> Package of one Package * + * Additional possible repairs: + * + * Optional/unnecessary NULL package elements removed + * Required package elements that are NULL replaced by Integer/String/Buffer + * Incorrect standalone package wrapped with required outer package + * ******************************************************************************/ /* Local prototypes */ static acpi_status @@ -504,6 +511,172 @@ acpi_ns_convert_to_package(union acpi_operand_object *original_object, return (AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_null_element + * + * PARAMETERS: Data - Pointer to validation data structure + * expected_btypes - Object types expected + * package_index - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair a NULL element of a returned Package object. + * + ******************************************************************************/ + +acpi_status +acpi_ns_repair_null_element(struct acpi_predefined_data *data, + u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr) +{ + union acpi_operand_object *return_object = *return_object_ptr; + union acpi_operand_object *new_object; + + ACPI_FUNCTION_NAME(ns_repair_null_element); + + /* No repair needed if return object is non-NULL */ + + if (return_object) { + return (AE_OK); + } + + /* + * Attempt to repair a NULL element of a Package object. This applies to + * predefined names that return a fixed-length package and each element + * is required. It does not apply to variable-length packages where NULL + * elements are allowed, especially at the end of the package. + */ + if (expected_btypes & ACPI_RTYPE_INTEGER) { + + /* Need an Integer - create a zero-value integer */ + + new_object = acpi_ut_create_integer_object(0); + } else if (expected_btypes & ACPI_RTYPE_STRING) { + + /* Need a String - create a NULL string */ + + new_object = acpi_ut_create_string_object(0); + } else if (expected_btypes & ACPI_RTYPE_BUFFER) { + + /* Need a Buffer - create a zero-length buffer */ + + new_object = acpi_ut_create_buffer_object(0); + } else { + /* Error for all other expected types */ + + return (AE_AML_OPERAND_TYPE); + } + + if (!new_object) { + return (AE_NO_MEMORY); + } + + /* Set the reference count according to the parent Package object */ + + new_object->common.reference_count = + data->parent_package->common.reference_count; + + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Converted NULL package element to expected %s at index %u\n", + data->pathname, + acpi_ut_get_object_type_name(new_object), + package_index)); + + *return_object_ptr = new_object; + data->flags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_remove_null_elements + * + * PARAMETERS: Data - Pointer to validation data structure + * package_type - An acpi_return_package_types value + * obj_desc - A Package object + * + * RETURN: None. + * + * DESCRIPTION: Remove all NULL package elements from packages that contain + * a variable number of sub-packages. For these types of + * packages, NULL elements can be safely removed. + * + *****************************************************************************/ + +void +acpi_ns_remove_null_elements(struct acpi_predefined_data *data, + u8 package_type, + union acpi_operand_object *obj_desc) +{ + union acpi_operand_object **source; + union acpi_operand_object **dest; + u32 count; + u32 new_count; + u32 i; + + ACPI_FUNCTION_NAME(ns_remove_null_elements); + + /* + * PTYPE1 packages contain no subpackages. + * PTYPE2 packages contain a variable number of sub-packages. We can + * safely remove all NULL elements from the PTYPE2 packages. + */ + switch (package_type) { + case ACPI_PTYPE1_FIXED: + case ACPI_PTYPE1_VAR: + case ACPI_PTYPE1_OPTION: + return; + + case ACPI_PTYPE2: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_REV_FIXED: + break; + + default: + return; + } + + count = obj_desc->package.count; + new_count = count; + + source = obj_desc->package.elements; + dest = source; + + /* Examine all elements of the package object, remove nulls */ + + for (i = 0; i < count; i++) { + if (!*source) { + new_count--; + } else { + *dest = *source; + dest++; + } + source++; + } + + /* Update parent package if any null elements were removed */ + + if (new_count < count) { + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Found and removed %u NULL elements\n", + data->pathname, (count - new_count))); + + /* NULL terminate list and update the package count */ + + *dest = NULL; + obj_desc->package.count = new_count; + } +} + /******************************************************************************* * * FUNCTION: acpi_ns_repair_package_list diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 29ff5d14e1d5..61bd0f6755d2 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -45,7 +45,6 @@ #include #include "accommon.h" #include "acnamesp.h" -#include "acpredef.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsrepair2") @@ -518,89 +517,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, return (AE_OK); } -/****************************************************************************** - * - * FUNCTION: acpi_ns_remove_null_elements - * - * PARAMETERS: Data - Pointer to validation data structure - * package_type - An acpi_return_package_types value - * obj_desc - A Package object - * - * RETURN: None. - * - * DESCRIPTION: Remove all NULL package elements from packages that contain - * a variable number of sub-packages. - * - *****************************************************************************/ - -void -acpi_ns_remove_null_elements(struct acpi_predefined_data *data, - u8 package_type, - union acpi_operand_object *obj_desc) -{ - union acpi_operand_object **source; - union acpi_operand_object **dest; - u32 count; - u32 new_count; - u32 i; - - ACPI_FUNCTION_NAME(ns_remove_null_elements); - - /* - * PTYPE1 packages contain no subpackages. - * PTYPE2 packages contain a variable number of sub-packages. We can - * safely remove all NULL elements from the PTYPE2 packages. - */ - switch (package_type) { - case ACPI_PTYPE1_FIXED: - case ACPI_PTYPE1_VAR: - case ACPI_PTYPE1_OPTION: - return; - - case ACPI_PTYPE2: - case ACPI_PTYPE2_COUNT: - case ACPI_PTYPE2_PKG_COUNT: - case ACPI_PTYPE2_FIXED: - case ACPI_PTYPE2_MIN: - case ACPI_PTYPE2_REV_FIXED: - break; - - default: - return; - } - - count = obj_desc->package.count; - new_count = count; - - source = obj_desc->package.elements; - dest = source; - - /* Examine all elements of the package object, remove nulls */ - - for (i = 0; i < count; i++) { - if (!*source) { - new_count--; - } else { - *dest = *source; - dest++; - } - source++; - } - - /* Update parent package if any null elements were removed */ - - if (new_count < count) { - ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, - "%s: Found and removed %u NULL elements\n", - data->pathname, (count - new_count))); - - /* NULL terminate list and update the package count */ - - *dest = NULL; - obj_desc->package.count = new_count; - } -} - /****************************************************************************** * * FUNCTION: acpi_ns_sort_list -- GitLab From 5df7e6cb42da36c7d878239bebc81907b15f3943 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 Jan 2010 10:06:32 +0800 Subject: [PATCH 1095/3892] ACPICA: Remove obsolete ACPI_INTEGER (acpi_integer) type This type was introduced as the code was migrated from ACPI 1.0 (with 32-bit AML integers) to ACPI 2.0 (with 64-bit integers). It is now obsolete and this change removes it from the ACPICA code base, replaced by u64. The original typedef has been retained for now for compatibility with existing device driver code. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acevents.h | 3 +- drivers/acpi/acpica/acinterp.h | 42 ++++++++++++------------- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/acmacros.h | 12 +++---- drivers/acpi/acpica/acobject.h | 2 +- drivers/acpi/acpica/acutils.h | 20 +++++------- drivers/acpi/acpica/dsfield.c | 10 +++--- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/evregion.c | 5 ++- drivers/acpi/acpica/evrgnini.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 19 +++++------- drivers/acpi/acpica/exfield.c | 7 ++--- drivers/acpi/acpica/exfldio.c | 57 ++++++++++++++++------------------ drivers/acpi/acpica/exmisc.c | 10 +++--- drivers/acpi/acpica/exoparg1.c | 14 ++++----- drivers/acpi/acpica/exoparg2.c | 4 +-- drivers/acpi/acpica/exoparg3.c | 2 +- drivers/acpi/acpica/exoparg6.c | 8 ++--- drivers/acpi/acpica/exregion.c | 33 +++++++++----------- drivers/acpi/acpica/exsystem.c | 2 +- drivers/acpi/acpica/exutils.c | 22 ++++++------- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/psargs.c | 2 +- drivers/acpi/acpica/rscreate.c | 2 +- drivers/acpi/acpica/utdebug.c | 3 +- drivers/acpi/acpica/uteval.c | 2 +- drivers/acpi/acpica/utglobal.c | 2 +- drivers/acpi/acpica/utmath.c | 25 ++++++--------- drivers/acpi/acpica/utmisc.c | 14 ++++----- include/acpi/acpiosxf.h | 4 +-- include/acpi/acrestyp.h | 2 +- include/acpi/actypes.h | 27 +++++++++------- 33 files changed, 169 insertions(+), 196 deletions(-) diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 13d2b0bc2144..31056bc89774 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -139,8 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - u32 region_offset, - u32 bit_width, acpi_integer * value); + u32 region_offset, u32 bit_width, u64 *value); acpi_status acpi_ev_attach_region(union acpi_operand_object *handler_obj, diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index c9d7802f9118..6df3f8428168 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -129,18 +129,17 @@ acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc, acpi_status acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, - acpi_integer mask, - acpi_integer field_value, - u32 field_datum_byte_offset); + u64 mask, + u64 field_value, u32 field_datum_byte_offset); void -acpi_ex_get_buffer_datum(acpi_integer * datum, +acpi_ex_get_buffer_datum(u64 *datum, void *buffer, u32 buffer_length, u32 byte_granularity, u32 buffer_offset); void -acpi_ex_set_buffer_datum(acpi_integer merged_datum, +acpi_ex_set_buffer_datum(u64 merged_datum, void *buffer, u32 buffer_length, u32 byte_granularity, u32 buffer_offset); @@ -168,8 +167,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, acpi_status acpi_ex_access_region(union acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - acpi_integer * value, u32 read_write); + u32 field_datum_byte_offset, u64 *value, u32 read_write); /* * exmisc - misc support routines @@ -193,16 +191,14 @@ acpi_ex_do_concatenate(union acpi_operand_object *obj_desc, acpi_status acpi_ex_do_logical_numeric_op(u16 opcode, - acpi_integer integer0, - acpi_integer integer1, u8 * logical_result); + u64 integer0, u64 integer1, u8 *logical_result); acpi_status acpi_ex_do_logical_op(u16 opcode, union acpi_operand_object *operand0, - union acpi_operand_object *operand1, u8 * logical_result); + union acpi_operand_object *operand1, u8 *logical_result); -acpi_integer -acpi_ex_do_math_op(u16 opcode, acpi_integer operand0, acpi_integer operand1); +u64 acpi_ex_do_math_op(u16 opcode, u64 operand0, u64 operand1); acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state); @@ -278,7 +274,7 @@ acpi_status acpi_ex_system_do_notify_op(union acpi_operand_object *value, union acpi_operand_object *obj_desc); -acpi_status acpi_ex_system_do_suspend(acpi_integer time); +acpi_status acpi_ex_system_do_suspend(u64 time); acpi_status acpi_ex_system_do_stall(u32 time); @@ -461,9 +457,9 @@ void acpi_ex_acquire_global_lock(u32 rule); void acpi_ex_release_global_lock(u32 rule); -void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id); +void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); -void acpi_ex_integer_to_string(char *dest, acpi_integer value); +void acpi_ex_integer_to_string(char *dest, u64 value); /* * exregion - default op_region handlers @@ -472,7 +468,7 @@ acpi_status acpi_ex_system_memory_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); @@ -480,35 +476,35 @@ acpi_status acpi_ex_system_io_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); acpi_status acpi_ex_pci_config_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); acpi_status acpi_ex_cmos_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); acpi_status acpi_ex_pci_bar_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); acpi_status acpi_ex_embedded_controller_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); @@ -516,14 +512,14 @@ acpi_status acpi_ex_sm_bus_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); acpi_status acpi_ex_data_table_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); #endif /* __INTERP_H__ */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 681205c75563..4894decfdcf5 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -650,7 +650,7 @@ struct acpi_opcode_info { }; union acpi_parse_value { - acpi_integer integer; /* Integer constant (Up to 64 bits) */ + u64 integer; /* Integer constant (Up to 64 bits) */ struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */ u32 size; /* bytelist or field size */ char *string; /* NULL terminated string */ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index a4a9519a1288..9894929a2abb 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -272,8 +272,8 @@ * MASK_BITS_ABOVE creates a mask starting AT the position and above * MASK_BITS_BELOW creates a mask starting one bit BELOW the position */ -#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position)))) -#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position))) +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_UINT64_MAX) << ((u32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_UINT64_MAX) << ((u32) (position))) /* Bitfields within ACPI registers */ @@ -414,16 +414,16 @@ acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \ return (_s); }) #define return_VALUE(s) ACPI_DO_WHILE0 ({ \ - register acpi_integer _s = (s); \ + register u64 _s = (s); \ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \ return (_s); }) #define return_UINT8(s) ACPI_DO_WHILE0 ({ \ register u8 _s = (u8) (s); \ - acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \ return (_s); }) #define return_UINT32(s) ACPI_DO_WHILE0 ({ \ register u32 _s = (u32) (s); \ - acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \ return (_s); }) #else /* Use original less-safe macros */ @@ -434,7 +434,7 @@ acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \ return((s)); }) #define return_VALUE(s) ACPI_DO_WHILE0 ({ \ - acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) (s)); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) (s)); \ return((s)); }) #define return_UINT8(s) return_VALUE(s) #define return_UINT32(s) return_VALUE(s) diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 6d0b4de68cf6..3b5d8bf51251 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -111,7 +111,7 @@ ACPI_OBJECT_COMMON_HEADER}; struct acpi_object_integer { ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */ - acpi_integer value; + u64 value; }; /* diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index d3ae626cf715..35df755251ce 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -134,7 +134,7 @@ char *acpi_ut_get_region_name(u8 space_id); char *acpi_ut_get_event_name(u32 event_id); -char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position); +char acpi_ut_hex_to_ascii_char(u64 integer, u32 position); u8 acpi_ut_valid_object_type(acpi_object_type type); @@ -279,8 +279,7 @@ acpi_ut_status_exit(u32 line_number, void acpi_ut_value_exit(u32 line_number, const char *function_name, - const char *module_name, - u32 component_id, acpi_integer value); + const char *module_name, u32 component_id, u64 value); void acpi_ut_ptr_exit(u32 line_number, @@ -324,7 +323,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, acpi_status acpi_ut_evaluate_numeric_object(char *object_name, struct acpi_namespace_node *device_node, - acpi_integer *value); + u64 *value); acpi_status acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags); @@ -437,14 +436,12 @@ void acpi_ut_delete_generic_state(union acpi_generic_state *state); * utmath */ acpi_status -acpi_ut_divide(acpi_integer in_dividend, - acpi_integer in_divisor, - acpi_integer * out_quotient, acpi_integer * out_remainder); +acpi_ut_divide(u64 in_dividend, + u64 in_divisor, u64 *out_quotient, u64 *out_remainder); acpi_status -acpi_ut_short_divide(acpi_integer in_dividend, - u32 divisor, - acpi_integer * out_quotient, u32 * out_remainder); +acpi_ut_short_divide(u64 in_dividend, + u32 divisor, u64 *out_quotient, u32 *out_remainder); /* * utmisc @@ -474,8 +471,7 @@ acpi_name acpi_ut_repair_name(char *name); u8 acpi_ut_valid_acpi_char(char character, u32 position); -acpi_status -acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer); +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer); void ACPI_INTERNAL_VAR_XFACE acpi_ut_predefined_warning(const char *module_name, diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index effbf1550b03..bb13817e0c31 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -220,7 +220,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, union acpi_parse_object *arg) { acpi_status status; - acpi_integer position; + u64 position; ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); @@ -240,8 +240,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: - position = (acpi_integer) info->field_bit_position - + (acpi_integer) arg->common.value.size; + position = (u64) info->field_bit_position + + (u64) arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, @@ -305,8 +305,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, /* Keep track of bit position for the next field */ - position = (acpi_integer) info->field_bit_position - + (acpi_integer) arg->common.value.size; + position = (u64) info->field_bit_position + + (u64) arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index edd7aa238cf1..891e08bf560b 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -684,7 +684,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, case AML_ONES_OP: - obj_desc->integer.value = ACPI_INTEGER_MAX; + obj_desc->integer.value = ACPI_UINT64_MAX; /* Truncate value if we are executing from a 32-bit ACPI table */ diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 654b2833598c..98fd210e87b2 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -329,7 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) * Value - Pointer to in or out value, must be - * full 64-bit acpi_integer + * a full 64-bit integer * * RETURN: Status * @@ -341,8 +341,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - u32 region_offset, - u32 bit_width, acpi_integer * value) + u32 region_offset, u32 bit_width, u64 *value) { acpi_status status; acpi_adr_space_handler handler; diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 86bd5a7f40d0..2e3b0334072f 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -168,7 +168,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, void *handler_context, void **region_context) { acpi_status status = AE_OK; - acpi_integer pci_value; + u64 pci_value; struct acpi_pci_id *pci_id = *region_context; union acpi_operand_object *handler_obj; struct acpi_namespace_node *parent_node; diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index cee2bceb2169..7e8b3bedc376 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -284,7 +284,7 @@ static acpi_status acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) { acpi_status status; - acpi_integer value; + u64 value; u32 region_offset = 0; u32 i; diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index adcaf3b89587..bda7aed0404b 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -51,8 +51,7 @@ ACPI_MODULE_NAME("exconvrt") /* Local prototypes */ static u32 -acpi_ex_convert_to_ascii(acpi_integer integer, - u16 base, u8 * string, u8 max_length); +acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length); /******************************************************************************* * @@ -75,7 +74,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, { union acpi_operand_object *return_desc; u8 *pointer; - acpi_integer result; + u64 result; u32 i; u32 count; acpi_status status; @@ -155,7 +154,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, * Little endian is used, meaning that the first byte of the buffer * is the LSB of the integer */ - result |= (((acpi_integer) pointer[i]) << (i * 8)); + result |= (((u64) pointer[i]) << (i * 8)); } break; @@ -285,10 +284,9 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, ******************************************************************************/ static u32 -acpi_ex_convert_to_ascii(acpi_integer integer, - u16 base, u8 * string, u8 data_width) +acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width) { - acpi_integer digit; + u64 digit; u32 i; u32 j; u32 k = 0; @@ -531,10 +529,9 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, * (separated by commas or spaces) */ for (i = 0; i < obj_desc->buffer.length; i++) { - new_buf += acpi_ex_convert_to_ascii((acpi_integer) - obj_desc->buffer. - pointer[i], base, - new_buf, 1); + new_buf += acpi_ex_convert_to_ascii((u64) obj_desc-> + buffer.pointer[i], + base, new_buf, 1); *new_buf++ = separator; /* each separated by a comma or space */ } diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index c9190c784194..6c79fecbee42 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -130,7 +130,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, /* Call the region handler for the read */ status = acpi_ex_access_region(obj_desc, 0, - ACPI_CAST_PTR(acpi_integer, + ACPI_CAST_PTR(u64, buffer_desc-> buffer.pointer), function); @@ -141,7 +141,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, /* * Allocate a buffer for the contents of the field. * - * If the field is larger than the size of an acpi_integer, create + * If the field is larger than the current integer width, create * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. @@ -306,8 +306,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, * same buffer) */ status = acpi_ex_access_region(obj_desc, 0, - (acpi_integer *) buffer, - function); + (u64 *) buffer, function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index dc2f9e8bee6e..f68a216168be 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -55,11 +55,10 @@ ACPI_MODULE_NAME("exfldio") static acpi_status acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, - acpi_integer * value, u32 read_write); + u64 *value, u32 read_write); static u8 -acpi_ex_register_overflow(union acpi_operand_object *obj_desc, - acpi_integer value); +acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value); static acpi_status acpi_ex_setup_region(union acpi_operand_object *obj_desc, @@ -212,7 +211,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, * field_datum_byte_offset - Byte offset of this datum within the * parent field * Value - Where to store value (must at least - * the size of acpi_integer) + * 64 bits) * Function - Read or Write flag plus other region- * dependent flags * @@ -224,8 +223,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, acpi_status acpi_ex_access_region(union acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - acpi_integer * value, u32 function) + u32 field_datum_byte_offset, u64 *value, u32 function) { acpi_status status; union acpi_operand_object *rgn_desc; @@ -317,8 +315,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, ******************************************************************************/ static u8 -acpi_ex_register_overflow(union acpi_operand_object *obj_desc, - acpi_integer value) +acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) { if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { @@ -329,7 +326,7 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, return (FALSE); } - if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) { + if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) { /* * The Value is larger than the maximum value that can fit into * the register. @@ -362,11 +359,10 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, static acpi_status acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - acpi_integer * value, u32 read_write) + u32 field_datum_byte_offset, u64 *value, u32 read_write) { acpi_status status; - acpi_integer local_value; + u64 local_value; ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset); @@ -439,8 +435,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, * the register */ if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj, - (acpi_integer) obj_desc-> - bank_field.value)) { + (u64) obj_desc->bank_field. + value)) { return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); } @@ -481,8 +477,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, * the register */ if (acpi_ex_register_overflow(obj_desc->index_field.index_obj, - (acpi_integer) obj_desc-> - index_field.value)) { + (u64) obj_desc->index_field. + value)) { return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); } @@ -512,7 +508,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, status = acpi_ex_extract_from_field(obj_desc->index_field. data_obj, value, - sizeof(acpi_integer)); + sizeof(u64)); } else { /* Write the datum to the data_register */ @@ -523,7 +519,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, status = acpi_ex_insert_into_field(obj_desc->index_field. data_obj, value, - sizeof(acpi_integer)); + sizeof(u64)); } break; @@ -571,13 +567,12 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, acpi_status acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, - acpi_integer mask, - acpi_integer field_value, - u32 field_datum_byte_offset) + u64 mask, + u64 field_value, u32 field_datum_byte_offset) { acpi_status status = AE_OK; - acpi_integer merged_value; - acpi_integer current_value; + u64 merged_value; + u64 current_value; ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask); @@ -587,7 +582,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, /* If the mask is all ones, we don't need to worry about the update rule */ - if (mask != ACPI_INTEGER_MAX) { + if (mask != ACPI_UINT64_MAX) { /* Decode the update rule */ @@ -678,8 +673,8 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; - acpi_integer raw_datum; - acpi_integer merged_datum; + u64 raw_datum; + u64 merged_datum; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; @@ -804,10 +799,10 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; - acpi_integer mask; - acpi_integer width_mask; - acpi_integer merged_datum; - acpi_integer raw_datum = 0; + u64 mask; + u64 width_mask; + u64 merged_datum; + u64 raw_datum = 0; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; @@ -855,7 +850,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, * shift operator */ if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) { - width_mask = ACPI_INTEGER_MAX; + width_mask = ACPI_UINT64_MAX; } else { width_mask = ACPI_MASK_BITS_ABOVE(obj_desc->common_field. diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index d29e542bb6df..c5bb1eeed2df 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -409,8 +409,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, * ******************************************************************************/ -acpi_integer -acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1) +u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1) { ACPI_FUNCTION_ENTRY(); @@ -498,8 +497,7 @@ acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1) acpi_status acpi_ex_do_logical_numeric_op(u16 opcode, - acpi_integer integer0, - acpi_integer integer1, u8 * logical_result) + u64 integer0, u64 integer1, u8 *logical_result) { acpi_status status = AE_OK; u8 local_result = FALSE; @@ -564,8 +562,8 @@ acpi_ex_do_logical_op(u16 opcode, union acpi_operand_object *operand1, u8 * logical_result) { union acpi_operand_object *local_operand1 = operand1; - acpi_integer integer0; - acpi_integer integer1; + u64 integer0; + u64 integer1; u32 length0; u32 length1; acpi_status status = AE_OK; diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 2b2128e52d42..99adbab5acbf 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -261,8 +261,8 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) union acpi_operand_object *return_desc2 = NULL; u32 temp32; u32 i; - acpi_integer power_of_ten; - acpi_integer digit; + u64 power_of_ten; + u64 digit; ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); @@ -362,7 +362,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) /* Sum the digit into the result with the current power of 10 */ return_desc->integer.value += - (((acpi_integer) temp32) * power_of_ten); + (((u64) temp32) * power_of_ten); /* Shift to next BCD digit */ @@ -392,7 +392,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) * remainder from above */ return_desc->integer.value |= - (((acpi_integer) temp32) << ACPI_MUL_4(i)); + (((u64) temp32) << ACPI_MUL_4(i)); } /* Overflow if there is any data left in Digit */ @@ -439,7 +439,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) /* The object exists in the namespace, return TRUE */ - return_desc->integer.value = ACPI_INTEGER_MAX; + return_desc->integer.value = ACPI_UINT64_MAX; goto cleanup; default: @@ -589,7 +589,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; u32 type; - acpi_integer value; + u64 value; ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); @@ -610,7 +610,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * return_desc->Integer.Value is initially == 0 (FALSE) from above. */ if (!operand[0]->integer.value) { - return_desc->integer.value = ACPI_INTEGER_MAX; + return_desc->integer.value = ACPI_UINT64_MAX; } break; diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index ea115021ee7d..22841bbbe63c 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -282,7 +282,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; - acpi_integer index; + u64 index; acpi_status status = AE_OK; acpi_size length; @@ -584,7 +584,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) * Default is FALSE (zero) */ if (logical_result) { - return_desc->integer.value = ACPI_INTEGER_MAX; + return_desc->integer.value = ACPI_UINT64_MAX; } cleanup: diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 25d1cd35c3e1..8bb1012ef44e 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -148,7 +148,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) union acpi_operand_object *return_desc = NULL; char *buffer = NULL; acpi_status status = AE_OK; - acpi_integer index; + u64 index; acpi_size length; ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 580abbd924dc..f256b6a25f2e 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -218,7 +218,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; - acpi_integer index; + u64 index; union acpi_operand_object *this_element; ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, @@ -253,9 +253,9 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) } /* Create an integer for the return value */ - /* Default return value is ACPI_INTEGER_MAX if no match found */ + /* Default return value is ACPI_UINT64_MAX if no match found */ - return_desc = acpi_ut_create_integer_object(ACPI_INTEGER_MAX); + return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -270,7 +270,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) * * Upon finding a match, the loop will terminate via "break" at * the bottom. If it terminates "normally", match_value will be - * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no + * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no * match was found. */ for (; index < operand[0]->package.count; index++) { diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 0cd88f6c95f7..486b2e5661b6 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -70,7 +70,7 @@ acpi_status acpi_ex_system_memory_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; @@ -115,8 +115,7 @@ acpi_ex_system_memory_space_handler(u32 function, * Hardware does not support non-aligned data transfers, we must verify * the request. */ - (void)acpi_ut_short_divide((acpi_integer) address, length, NULL, - &remainder); + (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder); if (remainder != 0) { return_ACPI_STATUS(AE_AML_ALIGNMENT); } @@ -128,10 +127,9 @@ acpi_ex_system_memory_space_handler(u32 function, * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || - (((acpi_integer) address + length) > ((acpi_integer) - mem_info-> - mapped_physical_address + - mem_info->mapped_length))) { + (((u64) address + length) > ((u64) + mem_info->mapped_physical_address + + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. @@ -193,8 +191,7 @@ acpi_ex_system_memory_space_handler(u32 function, * access */ logical_addr_ptr = mem_info->mapped_logical_address + - ((acpi_integer) address - - (acpi_integer) mem_info->mapped_physical_address); + ((u64) address - (u64) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n", @@ -215,19 +212,19 @@ acpi_ex_system_memory_space_handler(u32 function, *value = 0; switch (bit_width) { case 8: - *value = (acpi_integer) ACPI_GET8(logical_addr_ptr); + *value = (u64) ACPI_GET8(logical_addr_ptr); break; case 16: - *value = (acpi_integer) ACPI_GET16(logical_addr_ptr); + *value = (u64) ACPI_GET16(logical_addr_ptr); break; case 32: - *value = (acpi_integer) ACPI_GET32(logical_addr_ptr); + *value = (u64) ACPI_GET32(logical_addr_ptr); break; case 64: - *value = (acpi_integer) ACPI_GET64(logical_addr_ptr); + *value = (u64) ACPI_GET64(logical_addr_ptr); break; default: @@ -291,7 +288,7 @@ acpi_status acpi_ex_system_io_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; @@ -350,7 +347,7 @@ acpi_status acpi_ex_pci_config_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; @@ -425,7 +422,7 @@ acpi_status acpi_ex_cmos_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; @@ -457,7 +454,7 @@ acpi_status acpi_ex_pci_bar_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; @@ -489,7 +486,7 @@ acpi_status acpi_ex_data_table_space_handler(u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context) { ACPI_FUNCTION_TRACE(ex_data_table_space_handler); diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index c6cb6042603c..e11b6cb42a57 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -193,7 +193,7 @@ acpi_status acpi_ex_system_do_stall(u32 how_long) * ******************************************************************************/ -acpi_status acpi_ex_system_do_suspend(acpi_integer how_long) +acpi_status acpi_ex_system_do_suspend(u64 how_long) { ACPI_FUNCTION_ENTRY(); diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 0f2ce9c52f02..74c24d517f81 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -67,7 +67,7 @@ ACPI_MODULE_NAME("exutils") /* Local prototypes */ -static u32 acpi_ex_digits_needed(acpi_integer value, u32 base); +static u32 acpi_ex_digits_needed(u64 value, u32 base); #ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* @@ -230,7 +230,7 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) * We are running a method that exists in a 32-bit ACPI table. * Truncate the value to 32 bits by zeroing out the upper 32-bit field */ - obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX; + obj_desc->integer.value &= (u64) ACPI_UINT32_MAX; } } @@ -327,14 +327,14 @@ void acpi_ex_release_global_lock(u32 field_flags) * ******************************************************************************/ -static u32 acpi_ex_digits_needed(acpi_integer value, u32 base) +static u32 acpi_ex_digits_needed(u64 value, u32 base) { u32 num_digits; - acpi_integer current_value; + u64 current_value; ACPI_FUNCTION_TRACE(ex_digits_needed); - /* acpi_integer is unsigned, so we don't worry about a '-' prefix */ + /* u64 is unsigned, so we don't worry about a '-' prefix */ if (value == 0) { return_UINT32(1); @@ -370,7 +370,7 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base) * ******************************************************************************/ -void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id) +void acpi_ex_eisa_id_to_string(char *out_string, u64 compressed_id) { u32 swapped_id; @@ -394,10 +394,10 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id) (char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F)); out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F)); out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F)); - out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12); - out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8); - out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4); - out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0); + out_string[3] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 12); + out_string[4] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 8); + out_string[5] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 4); + out_string[6] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 0); out_string[7] = 0; } @@ -418,7 +418,7 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id) * ******************************************************************************/ -void acpi_ex_integer_to_string(char *out_string, acpi_integer value) +void acpi_ex_integer_to_string(char *out_string, u64 value) { u32 count; u32 digits_needed; diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index ce0cbbc18ad0..1ef8e0bb250b 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -140,7 +140,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) { acpi_status status; u32 delta_ticks; - acpi_integer quotient; + u64 quotient; ACPI_FUNCTION_TRACE(acpi_get_timer_duration); diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 6aa6a1a4d918..00493e108a01 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -403,7 +403,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, /* Get 1 byte from the AML stream */ opcode = AML_BYTE_OP; - arg->common.value.integer = (acpi_integer) * aml; + arg->common.value.integer = (u64) *aml; length = 1; break; diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 61a038dbfe23..f2ee3b548609 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -182,7 +182,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a - * package that in turn contains an acpi_integer Address, a u8 Pin, + * package that in turn contains an u64 Address, a u8 Pin, * a Name, and a u8 source_index. */ top_object_list = package_object->package.elements; diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index e156915fa0e8..983510640059 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -460,8 +460,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) void acpi_ut_value_exit(u32 line_number, const char *function_name, - const char *module_name, - u32 component_id, acpi_integer value) + const char *module_name, u32 component_id, u64 value) { acpi_debug_print(ACPI_LV_FUNCTIONS, diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index f4c5ee8109bc..7f5e734ce7f7 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -348,7 +348,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, acpi_status acpi_ut_evaluate_numeric_object(char *object_name, struct acpi_namespace_node *device_node, - acpi_integer *value) + u64 *value) { union acpi_operand_object *obj_desc; acpi_status status; diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 49286a39b09e..eda3e656c4af 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -234,7 +234,7 @@ static const char acpi_gbl_hex_to_ascii[] = { * ******************************************************************************/ -char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position) +char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) { return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index 7cfa1d8164d0..35059a14eb72 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -70,9 +70,8 @@ ACPI_MODULE_NAME("utmath") * ******************************************************************************/ acpi_status -acpi_ut_short_divide(acpi_integer dividend, - u32 divisor, - acpi_integer * out_quotient, u32 * out_remainder) +acpi_ut_short_divide(u64 dividend, + u32 divisor, u64 *out_quotient, u32 *out_remainder) { union uint64_overlay dividend_ovl; union uint64_overlay quotient; @@ -126,9 +125,8 @@ acpi_ut_short_divide(acpi_integer dividend, ******************************************************************************/ acpi_status -acpi_ut_divide(acpi_integer in_dividend, - acpi_integer in_divisor, - acpi_integer * out_quotient, acpi_integer * out_remainder) +acpi_ut_divide(u64 in_dividend, + u64 in_divisor, u64 *out_quotient, u64 *out_remainder) { union uint64_overlay dividend; union uint64_overlay divisor; @@ -199,9 +197,8 @@ acpi_ut_divide(acpi_integer in_dividend, * The 64-bit remainder must be generated. */ partial1 = quotient.part.lo * divisor.part.hi; - partial2.full = - (acpi_integer) quotient.part.lo * divisor.part.lo; - partial3.full = (acpi_integer) partial2.part.hi + partial1; + partial2.full = (u64) quotient.part.lo * divisor.part.lo; + partial3.full = (u64) partial2.part.hi + partial1; remainder.part.hi = partial3.part.lo; remainder.part.lo = partial2.part.lo; @@ -257,9 +254,8 @@ acpi_ut_divide(acpi_integer in_dividend, * ******************************************************************************/ acpi_status -acpi_ut_short_divide(acpi_integer in_dividend, - u32 divisor, - acpi_integer * out_quotient, u32 * out_remainder) +acpi_ut_short_divide(u64 in_dividend, + u32 divisor, u64 *out_quotient, u32 *out_remainder) { ACPI_FUNCTION_TRACE(ut_short_divide); @@ -284,9 +280,8 @@ acpi_ut_short_divide(acpi_integer in_dividend, } acpi_status -acpi_ut_divide(acpi_integer in_dividend, - acpi_integer in_divisor, - acpi_integer * out_quotient, acpi_integer * out_remainder) +acpi_ut_divide(u64 in_dividend, + u64 in_divisor, u64 *out_quotient, u64 *out_remainder) { ACPI_FUNCTION_TRACE(ut_divide); diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index fb55924e6e0f..32982e2ac384 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -724,13 +724,12 @@ acpi_name acpi_ut_repair_name(char *name) * ******************************************************************************/ -acpi_status -acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) { u32 this_digit = 0; - acpi_integer return_value = 0; - acpi_integer quotient; - acpi_integer dividend; + u64 return_value = 0; + u64 quotient; + u64 dividend; u32 to_integer_op = (base == ACPI_ANY_BASE); u32 mode32 = (acpi_gbl_integer_byte_width == 4); u8 valid_digits = 0; @@ -844,9 +843,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) /* Divide the digit into the correct position */ - (void) - acpi_ut_short_divide((dividend - (acpi_integer) this_digit), - base, "ient, NULL); + (void)acpi_ut_short_divide((dividend - (u64) this_digit), + base, "ient, NULL); if (return_value > quotient) { if (to_integer_op) { diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index c7e9431e16f1..b396854b83b0 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -196,7 +196,7 @@ acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context); void acpi_os_wait_events_complete(void *context); -void acpi_os_sleep(acpi_integer milliseconds); +void acpi_os_sleep(u64 milliseconds); void acpi_os_stall(u32 microseconds); @@ -227,7 +227,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, acpi_status acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, - u32 reg, acpi_integer value, u32 width); + u32 reg, u64 value, u32 width); /* * Interim function needed for PCI IRQ routing diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index dc6302e94793..e5526354ba5e 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -397,7 +397,7 @@ struct acpi_resource { struct acpi_pci_routing_table { u32 length; u32 pin; - acpi_integer address; /* here for 64-bit alignment */ + u64 address; /* here for 64-bit alignment */ u32 source_index; char source[4]; /* pad to 64 bits so sizeof() works in all cases */ }; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 4e65c201dcd4..07f2cdcc5eb1 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -390,14 +390,6 @@ struct uint32_struct { u32 hi; }; -/* - * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI - * version 2, integers are 64 bits. Note that this pertains to the ACPI integer - * type only, not other integers used in the implementation of the ACPI CA - * subsystem. - */ -typedef unsigned long long acpi_integer; -#define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 #define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ @@ -421,6 +413,19 @@ typedef unsigned long long acpi_integer; #define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ #define ACPI_DO_NOT_WAIT 0 +/* + * Obsolete: Acpi integer width. In ACPI version 1 (1996), integers are 32 bits. + * In ACPI version 2 (2000) and later, integers are 64 bits. Note that this + * pertains to the ACPI integer type only, not to other integers used in the + * implementation of the ACPICA subsystem. + * + * 01/2010: This type is obsolete and has been removed from the entire ACPICA + * code base. It remains here for compatibility with device drivers that use + * the type. However, it will be removed in the future. + */ +typedef u64 acpi_integer; +#define ACPI_INTEGER_MAX ACPI_UINT64_MAX + /******************************************************************************* * * Commonly used macros @@ -801,7 +806,7 @@ union acpi_object { acpi_object_type type; /* See definition of acpi_ns_type for values */ struct { acpi_object_type type; /* ACPI_TYPE_INTEGER */ - acpi_integer value; /* The actual number */ + u64 value; /* The actual number */ } integer; struct { @@ -945,7 +950,7 @@ typedef acpi_status(*acpi_adr_space_handler) (u32 function, acpi_physical_address address, u32 bit_width, - acpi_integer * value, + u64 *value, void *handler_context, void *region_context); @@ -1005,7 +1010,7 @@ struct acpi_device_info { u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ u32 current_status; /* _STA value */ - acpi_integer address; /* _ADR value */ + u64 address; /* _ADR value */ struct acpica_device_id hardware_id; /* _HID value */ struct acpica_device_id unique_id; /* _UID value */ struct acpica_device_id_list compatible_id_list; /* _CID list */ -- GitLab From 758d49313d0bdea1c41aa1d91ab204ca47177aae Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 Jan 2010 10:08:42 +0800 Subject: [PATCH 1096/3892] ACPICA: Disassembler: Remove obsolete "Integer64" field in parse object This field is no longer needed. The "Integer" field is 64 bit and is sufficient. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/aclocal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 4894decfdcf5..c6d9f6d33bf7 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -651,7 +651,6 @@ struct acpi_opcode_info { union acpi_parse_value { u64 integer; /* Integer constant (Up to 64 bits) */ - struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */ u32 size; /* bytelist or field size */ char *string; /* NULL terminated string */ u8 *buffer; /* buffer or string */ -- GitLab From a8f13b7083a10580eeed0723df4b414ed741e0d2 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 Jan 2010 10:09:43 +0800 Subject: [PATCH 1097/3892] ACPICA: Remove unused uint32_struct type This type is not used in ACPICA and thus removed. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- include/acpi/actypes.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 07f2cdcc5eb1..2ccfa47a0ed7 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -385,11 +385,6 @@ union uint64_overlay { struct uint64_struct part; }; -struct uint32_struct { - u32 lo; - u32 hi; -}; - #define ACPI_INTEGER_BIT_SIZE 64 #define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ -- GitLab From aea9c04bcc257caad9841c283b90ec1b28267fae Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 22 Jan 2010 19:09:06 +0800 Subject: [PATCH 1098/3892] ACPICA: Update version to 20100121. Version 20100121. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2bf965ac06da..06adbaccb912 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20091214 +#define ACPI_CA_VERSION 0x20100121 #include "actypes.h" #include "actbl.h" -- GitLab From e4fca007b06165900d0e44e8d5e251376819bf5d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 22 Jan 2010 12:33:09 -0500 Subject: [PATCH 1099/3892] mac80211: avoid NULL ptr deref when using WEP "mac80211: move control.hw_key assignment" changed an if-else into two separate if statments, but the if-else is needed to prevent dereferencing a null info->control.hw_key. This fixes avoids a lock-up during association on my machine when using WEP. Signed-off-by: John W. Linville --- net/mac80211/wep.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 0a4c641c9605..5d745f2d7236 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -310,9 +310,8 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } - - if (info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + } else if (info->control.hw_key->flags & + IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key->conf.keylen, tx->key->conf.keyidx)) -- GitLab From b3fbdcf49f940d0703c356441e0daf045e64e076 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 11:40:47 +0100 Subject: [PATCH 1100/3892] mac80211: pass vif and station to update_tkip_key When a TKIP key is updated, we should pass the station pointer instead of just the address, since drivers can use that to store their own data. We also need to pass the virtual interface pointer. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 11 ++++++++--- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++++++--- include/net/mac80211.h | 6 ++++-- net/mac80211/driver-ops.h | 14 ++++++++++---- net/mac80211/driver-trace.h | 15 +++++++++------ net/mac80211/tkip.c | 12 +++++------- 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c238468bca7f..c699e46534dc 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -844,8 +844,10 @@ static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, } static void b43_op_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_key_conf *keyconf, const u8 *addr, - u32 iv32, u16 *phase1key) + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -863,7 +865,10 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw, keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ rx_tkip_phase1_write(dev, index, iv32, phase1key); - keymac_write(dev, index, addr); + /* only pairwise TKIP keys are supported right now */ + if (WARN_ON(!sta)) + goto out_unlock; + keymac_write(dev, index, sta->addr); out_unlock: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8db86239bd6a..62b6939df52e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2839,14 +2839,18 @@ void iwl_config_ap(struct iwl_priv *priv) } static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_key_conf *keyconf, const u8 *addr, - u32 iv32, u16 *phase1key) + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211(priv, "enter\n"); - iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); + iwl_update_tkip_key(priv, keyconf, + sta ? sta->addr : iwl_bcast_addr, + iv32, phase1key); IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f03f97b627fe..f56d6f479532 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1614,8 +1614,10 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); void (*update_tkip_key)(struct ieee80211_hw *hw, - struct ieee80211_key_conf *conf, const u8 *address, - u32 iv32, u16 *phase1key); + struct ieee80211_vif *vif, + struct ieee80211_key_conf *conf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); int (*hw_scan)(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); void (*sw_scan_start)(struct ieee80211_hw *hw); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index de91d39e0276..40c6e9a89864 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -137,16 +137,22 @@ static inline int drv_set_key(struct ieee80211_local *local, } static inline void drv_update_tkip_key(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, struct ieee80211_key_conf *conf, - const u8 *address, u32 iv32, + struct sta_info *sta, u32 iv32, u16 *phase1key) { + struct ieee80211_sta *ista = NULL; + might_sleep(); + if (sta) + ista = &sta->sta; + if (local->ops->update_tkip_key) - local->ops->update_tkip_key(&local->hw, conf, address, - iv32, phase1key); - trace_drv_update_tkip_key(local, conf, address, iv32); + local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, + ista, iv32, phase1key); + trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); } static inline int drv_hw_scan(struct ieee80211_local *local, diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 0ea258123b8e..fefa6e6b01bc 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -331,26 +331,29 @@ TRACE_EVENT(drv_set_key, TRACE_EVENT(drv_update_tkip_key, TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, struct ieee80211_key_conf *conf, - const u8 *address, u32 iv32), + struct ieee80211_sta *sta, u32 iv32), - TP_ARGS(local, conf, address, iv32), + TP_ARGS(local, sdata, conf, sta, iv32), TP_STRUCT__entry( LOCAL_ENTRY - __array(u8, addr, 6) + VIF_ENTRY + STA_ENTRY __field(u32, iv32) ), TP_fast_assign( LOCAL_ASSIGN; - memcpy(__entry->addr, address, 6); + VIF_ASSIGN; + STA_ASSIGN; __entry->iv32 = iv32; ), TP_printk( - LOCAL_PR_FMT " addr:%pM iv32:%#x", - LOCAL_PR_ARG, __entry->addr, __entry->iv32 + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", + LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32 ) ); diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 14fe49332c02..7ef491e9d66d 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -304,14 +304,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (key->local->ops->update_tkip_key && key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { - static const u8 bcast[ETH_ALEN] = - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - const u8 *sta_addr = key->sta->sta.addr; + struct ieee80211_sub_if_data *sdata = key->sdata; - if (is_multicast_ether_addr(ra)) - sta_addr = bcast; - - drv_update_tkip_key(key->local, &key->conf, sta_addr, + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(key->sdata->bss, + struct ieee80211_sub_if_data, u.ap); + drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, iv32, key->u.tkip.rx[queue].p1k); key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; } -- GitLab From ef15aac6073b27fd4f70007784d2d52ed394bf43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Jan 2010 12:02:33 +0100 Subject: [PATCH 1101/3892] cfg80211: export multiple MAC addresses in sysfs If a device has multiple MAC addresses, userspace will need to know about that. Similarly, if it allows the MAC addresses to vary by a bitmask. If a driver exports multiple addresses, it is assumed that it will be able to deal with that many different addresses, which need not necessarily match the ones programmed into the device; if a mask is set then the device should deal addresses within that mask based on an arbitrary "base address". To test it all and show how it is used, add support to hwsim even though it can't actually deal with addresses different from the default. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 8 +++++++- include/net/cfg80211.h | 22 +++++++++++++++++++++- net/wireless/core.c | 12 ++++++++++++ net/wireless/sysfs.c | 20 ++++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 84df3fcf37b3..0dbda8dfbd99 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -281,6 +281,8 @@ struct mac80211_hwsim_data { struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; + struct mac_address addresses[2]; + struct ieee80211_channel *channel; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; @@ -1154,7 +1156,11 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_DEV(hw, data->dev); addr[3] = i >> 8; addr[4] = i; - SET_IEEE80211_PERM_ADDR(hw, addr); + memcpy(data->addresses[0].addr, addr, ETH_ALEN); + memcpy(data->addresses[1].addr, addr, ETH_ALEN); + data->addresses[1].addr[0] |= 0x40; + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; hw->channel_change_time = 1; hw->queues = 4; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2af52704e670..c5d16f299d6f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1195,6 +1195,10 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_STATION = BIT(6), }; +struct mac_address { + u8 addr[ETH_ALEN]; +}; + /** * struct wiphy - wireless hardware description * @idx: the wiphy index assigned to this item @@ -1213,12 +1217,28 @@ enum wiphy_flags { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in + * @perm_addr: permanent MAC address of this device + * @addr_mask: If the device supports multiple MAC addresses by masking, + * set this to a mask with variable bits set to 1, e.g. if the last + * four bits are variable then set it to 00:...:00:0f. The actual + * variable bits shall be determined by the interfaces added, with + * interfaces not matching the mask being rejected to be brought up. + * @n_addresses: number of addresses in @addresses. + * @addresses: If the device has more than one address, set this pointer + * to a list of addresses (6 bytes each). The first one will be used + * by default for perm_addr. In this case, the mask should be set to + * all-zeroes. In this case it is assumed that the device can handle + * the same number of arbitrary MAC addresses. */ struct wiphy { /* assign these fields before you register the wiphy */ - /* permanent MAC address */ + /* permanent MAC address(es) */ u8 perm_addr[ETH_ALEN]; + u8 addr_mask[ETH_ALEN]; + + u16 n_addresses; + struct mac_address *addresses; /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; diff --git a/net/wireless/core.c b/net/wireless/core.c index d07f57c906db..71b6b3a9cf1f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -413,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; + if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) + return -EINVAL; + + if (WARN_ON(wiphy->addresses && + !is_zero_ether_addr(wiphy->perm_addr) && + memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, + ETH_ALEN))) + return -EINVAL; + + if (wiphy->addresses) + memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); + /* sanity check ifmodes */ WARN_ON(!ifmodes); ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index efe3c5c92b2d..9f2cef3e0ca0 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev, \ SHOW_FMT(index, "%d", wiphy_idx); SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); +SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); + +static ssize_t addresses_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + char *start = buf; + int i; + + if (!wiphy->addresses) + return sprintf(buf, "%pM\n", wiphy->perm_addr); + + for (i = 0; i < wiphy->n_addresses; i++) + buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); + + return buf - start; +} static struct device_attribute ieee80211_dev_attrs[] = { __ATTR_RO(index), __ATTR_RO(macaddress), + __ATTR_RO(address_mask), + __ATTR_RO(addresses), {} }; -- GitLab From d0dd2de0d055f0ffb1e2ecdc21380de9d12a85e2 Mon Sep 17 00:00:00 2001 From: Andriy Tkachuk Date: Wed, 20 Jan 2010 13:55:06 +0200 Subject: [PATCH 1102/3892] mac80211: Account HT Control field in Data frame hdrlen according to 802.11n-2009 ieee80211_hdrlen() should account account new HT Control field in 802.11 data frame header introduced by IEEE 802.11n standard. According to 802.11n-2009 HT Control field is present in data frames when both of following are met: 1. It is QoS data frame. 2. Order bit is set in Frame Control field. The change might be totally compatible with legacy non-11n aware frames, because 802.11-2007 standard states that "all QoS STAs set this subfield to 0". Signed-off-by: Andriy V. Tkachuk Acked-by : Benoit Papillault Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 2 ++ net/wireless/util.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 842701906ae9..19984958ab7b 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -138,6 +138,8 @@ #define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 #define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 +#define IEEE80211_HT_CTL_LEN 4 + struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; diff --git a/net/wireless/util.c b/net/wireless/util.c index 23557c1d0a9c..be2ab8c59e3a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -227,8 +227,11 @@ unsigned int ieee80211_hdrlen(__le16 fc) if (ieee80211_is_data(fc)) { if (ieee80211_has_a4(fc)) hdrlen = 30; - if (ieee80211_is_data_qos(fc)) + if (ieee80211_is_data_qos(fc)) { hdrlen += IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_order(fc)) + hdrlen += IEEE80211_HT_CTL_LEN; + } goto out; } -- GitLab From 5d6ce628f986d1a3c523cbb0a5a52095c48cc332 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 20 Jan 2010 23:51:03 -0500 Subject: [PATCH 1103/3892] ath5k: dont use external sleep clock in AP mode When using the external sleep clock in AP mode, the TSF increments too quickly, causing beacon interval to be much lower than it is supposed to be, resulting in lots of beacon-not-ready interrupts. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=14802. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/reset.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 6690923fd78c..a35a7db0fc4c 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1374,8 +1374,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one * exists */ - if (ah->ah_version == AR5K_AR5212) - ath5k_hw_set_sleep_clock(ah, true); + if (ah->ah_version == AR5K_AR5212 && + ah->ah_op_mode != NL80211_IFTYPE_AP) + ath5k_hw_set_sleep_clock(ah, true); /* * Disable beacons and reset the register -- GitLab From a951ae2176b982574ffa197455db6c89359fd5eb Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 20 Jan 2010 23:51:04 -0500 Subject: [PATCH 1104/3892] ath5k: fix setup for CAB queue The beacon sent gating doesn't seem to work with any combination of flags. Thus, buffered frames tend to stay buffered forever, using up tx descriptors. Instead, use the DBA gating and hold transmission of the buffered frames until 80% of the beacon interval has elapsed using the ready time. This fixes the following error in AP mode: ath5k phy0: no further txbuf available, dropping packet Add a comment to acknowledge that this isn't the best solution. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/base.c | 22 +++++++++++++++++++--- drivers/net/wireless/ath/ath5k/qcu.c | 5 +++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 66bcb506a112..ad4d446f0264 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -535,7 +535,7 @@ struct ath5k_txq_info { u32 tqi_cbr_period; /* Constant bit rate period */ u32 tqi_cbr_overflow_limit; u32 tqi_burst_time; - u32 tqi_ready_time; /* Not used */ + u32 tqi_ready_time; /* Time queue waits after an event */ }; /* diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index b5015376d4ba..535a6afb94e3 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1516,7 +1516,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc) ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); if (ret) - return ret; + goto err; + if (sc->opmode == NL80211_IFTYPE_AP || sc->opmode == NL80211_IFTYPE_MESH_POINT) { /* @@ -1543,10 +1544,25 @@ ath5k_beaconq_config(struct ath5k_softc *sc) if (ret) { ATH5K_ERR(sc, "%s: unable to update parameters for beacon " "hardware queue!\n", __func__); - return ret; + goto err; } + ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */ + if (ret) + goto err; - return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; + /* reconfigure cabq with ready time to 80% of beacon_interval */ + ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); + if (ret) + goto err; + + qi.tqi_ready_time = (sc->bintval * 80) / 100; + ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); + if (ret) + goto err; + + ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB); +err: + return ret; } static void diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index abe36c0d139c..9122a8556f45 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -408,12 +408,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) break; case AR5K_TX_QUEUE_CAB: + /* XXX: use BCN_SENT_GT, if we can figure out how */ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | + AR5K_QCU_MISC_FRSHED_DBA_GT | AR5K_QCU_MISC_CBREXP_DIS | AR5K_QCU_MISC_CBREXP_BCN_DIS); - ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - + ath5k_hw_reg_write(ah, ((tq->tqi_ready_time - (AR5K_TUNE_SW_BEACON_RESP - AR5K_TUNE_DMA_BEACON_RESP) - AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | -- GitLab From 58da1318ee92ad3fe7917278d596768bbe441850 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 21 Jan 2010 11:17:27 +0530 Subject: [PATCH 1105/3892] ath9k: Fix wifi disconnection when collocated bt scan is active As all bt packets are priority traffic during bt scan, wifi will get disconnected when bt scan lasts for few seconds. Fix this by allocating 10% of bt period time (4.5ms) to wifi fully. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/btcoex.h | 2 ++ drivers/net/wireless/ath/ath9k/gpio.c | 30 ++++++++++++++++++------- drivers/net/wireless/ath/ath9k/reg.h | 6 ++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bf3d4c4bfa52..bdbcc70df075 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -364,6 +364,7 @@ struct ath_btcoex { int bt_stomp_type; /* Types of BT stomping */ u32 btcoex_no_stomp; /* in usec */ u32 btcoex_period; /* in usec */ + u32 btscan_no_stomp; /* in usec */ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ }; @@ -429,6 +430,7 @@ void ath_deinit_leds(struct ath_softc *sc); #define SC_OP_SCANNING BIT(10) #define SC_OP_TSF_RESET BIT(11) #define SC_OP_BT_PRIORITY_DETECTED BIT(12) +#define SC_OP_BT_SCAN BIT(13) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 1ba31a73317c..1ee5a15ccbb1 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -25,10 +25,12 @@ #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 +#define ATH_BTCOEX_BTSCAN_DUTY_CYCLE 90 #define ATH_BTCOEX_BMISS_THRESH 50 #define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */ #define ATH_BT_CNT_THRESHOLD 3 +#define ATH_BT_CNT_SCAN_THRESHOLD 15 enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index e204bd25ff65..deab8beb0680 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -230,12 +230,17 @@ static void ath_detect_bt_priority(struct ath_softc *sc) if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); + /* Detect if colocated bt started scanning */ + if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, + "BT scan detected"); + sc->sc_flags |= (SC_OP_BT_SCAN | + SC_OP_BT_PRIORITY_DETECTED); + } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, "BT priority traffic detected"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; - } else { - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; } btcoex->bt_priority_cnt = 0; @@ -316,12 +321,17 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; + u32 timer_period; + bool is_btscan; ath_detect_bt_priority(sc); + is_btscan = sc->sc_flags & SC_OP_BT_SCAN; + spin_lock_bh(&btcoex->btcoex_lock); - ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); + ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL : + btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -329,11 +339,12 @@ static void ath_btcoex_period_timer(unsigned long data) if (btcoex->hw_timer_enabled) ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); + timer_period = is_btscan ? btcoex->btscan_no_stomp : + btcoex->btcoex_no_stomp; ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, (ath9k_hw_gettsf32(ah) + - btcoex->btcoex_no_stomp), - btcoex->btcoex_no_stomp * 10); + timer_period), timer_period * 10); btcoex->hw_timer_enabled = true; } @@ -350,13 +361,14 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; + bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "no stomp timer running \n"); spin_lock_bh(&btcoex->btcoex_lock); - if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); @@ -371,6 +383,8 @@ int ath_init_btcoex_timer(struct ath_softc *sc) btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; + btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * + btcoex->btcoex_period / 100; setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, (unsigned long) sc); @@ -405,7 +419,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); mod_timer(&btcoex->period_timer, jiffies); } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8e653fb937a1..72cfa8ebd9ae 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1547,9 +1547,9 @@ enum { #define AR_BT_COEX_WEIGHT 0x8174 #define AR_BT_COEX_WGHT 0xff55 -#define AR_STOMP_ALL_WLAN_WGHT 0xffcc -#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8 -#define AR_STOMP_NONE_WLAN_WGHT 0xaa00 +#define AR_STOMP_ALL_WLAN_WGHT 0xfcfc +#define AR_STOMP_LOW_WLAN_WGHT 0xa8a8 +#define AR_STOMP_NONE_WLAN_WGHT 0x0000 #define AR_BTCOEX_BT_WGHT 0x0000ffff #define AR_BTCOEX_BT_WGHT_S 0 #define AR_BTCOEX_WL_WGHT 0xffff0000 -- GitLab From 4bb29f8c390fb7be207ec3f11b9d30ccdf1cb6ac Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 22 Jan 2010 00:36:39 +0100 Subject: [PATCH 1106/3892] mac80211: fix rx data handling for non-data frames on multiple vifs The loop that passes non-data frames to all relevant vifs inside the __ieee80211_rx_handle_packet keeps a pointer to the previous sdata to avoid having to make unnecessary copies of the frame it's handling. This led to a bug that caused it to apply the ieee80211_rx_data state to the wrong interface, thereby either missing the rx.sta pointer or having it assigned where it shouldn't be. This breaks (among other things) aggregation on some vifs, as action frame exchages are dropped to the cooked monitor interface due to rx->sta being NULL. Fix this by restructuring the loop so that it prepares the rx data just before making the skb copy and calling the rx handlers. Cc: stable@kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/rx.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a8e15b84c05b..7e0b3e340389 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2348,22 +2348,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; - rx.sta = sta_info_get(sdata, hdr->addr2); - - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(sdata, &rx, hdr); - - if (!prepares) - continue; - - if (status->flag & RX_FLAG_MMIC_ERROR) { - rx.sdata = sdata; - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, - &rx); - continue; - } - /* * frame is destined for this interface, but if it's * not also for the previous one we handle that after @@ -2375,6 +2359,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } + rx.sta = sta_info_get(prev, hdr->addr2); + + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(prev, &rx, hdr); + + if (!prepares) + goto next; + + if (status->flag & RX_FLAG_MMIC_ERROR) { + rx.sdata = prev; + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, + &rx); + goto next; + } + /* * frame was destined for the previous interface * so invoke RX handlers for it @@ -2387,11 +2387,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, "multicast frame for %s\n", wiphy_name(local->hw.wiphy), prev->name); - continue; + goto next; } ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); +next: prev = sdata; } + + if (prev) { + rx.sta = sta_info_get(prev, hdr->addr2); + + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(prev, &rx, hdr); + + if (!prepares) + prev = NULL; + } } if (prev) ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); -- GitLab From aa4c7b2a2547db95388f795f092ea286fbdd98a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 22 Jan 2010 01:53:12 +0100 Subject: [PATCH 1107/3892] b43: check band width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 6 ++++++ drivers/net/wireless/b43/phy_common.h | 3 +++ drivers/net/wireless/b43/phy_n.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c699e46534dc..6d7cf3c2f7bf 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3576,6 +3576,12 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) dev = wl->current_dev; phy = &dev->phy; + if (conf_is_ht(conf)) + phy->is_40mhz = + (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf)); + else + phy->is_40mhz = false; + b43_mac_suspend(dev); if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9edd4e8e0c85..f635f9e4f83d 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -212,6 +212,9 @@ struct b43_phy { bool supports_2ghz; bool supports_5ghz; + /* HT info */ + bool is_40mhz; + /* GMODE bit enabled? */ bool gmode; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e77f1f24d101..2cdf32e5fd9b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1787,7 +1787,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); - if (1 /* FIXME: the band width is 20 MHz */) + if (!dev->phy.is_40mhz) freq = 2500; else freq = 5000; -- GitLab From 75377b2476d85d90c0db07e780ee95741cff3a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 22 Jan 2010 01:53:13 +0100 Subject: [PATCH 1108/3892] b43: N-PHY: implement overriding RF control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 82 +++++++++++++++++++++++++- drivers/net/wireless/b43/tables_nphy.c | 37 ++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 21 +++++++ 3 files changed, 137 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 2cdf32e5fd9b..d3c9783b76ba 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -912,6 +912,82 @@ ok: b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ +static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, + u16 value, u8 core, bool off) +{ + int i; + u8 index = fls(field); + u8 addr, en_addr, val_addr; + /* we expect only one bit set */ + B43_WARN_ON(field & (~(1 << index))); + + if (dev->phy.rev >= 3) { + const struct nphy_rf_control_override_rev3 *rf_ctrl; + for (i = 0; i < 2; i++) { + if (index == 0 || index == 16) { + b43err(dev->wl, + "Unsupported RF Ctrl Override call\n"); + return; + } + + rf_ctrl = &tbl_rf_control_override_rev3[index - 1]; + en_addr = B43_PHY_N((i == 0) ? + rf_ctrl->en_addr0 : rf_ctrl->en_addr1); + val_addr = B43_PHY_N((i == 0) ? + rf_ctrl->val_addr0 : rf_ctrl->val_addr1); + + if (off) { + b43_phy_mask(dev, en_addr, ~(field)); + b43_phy_mask(dev, val_addr, + ~(rf_ctrl->val_mask)); + } else { + if (core == 0 || ((1 << core) & i) != 0) { + b43_phy_set(dev, en_addr, field); + b43_phy_maskset(dev, val_addr, + ~(rf_ctrl->val_mask), + (value << rf_ctrl->val_shift)); + } + } + } + } else { + const struct nphy_rf_control_override_rev2 *rf_ctrl; + if (off) { + b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field)); + value = 0; + } else { + b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field); + } + + for (i = 0; i < 2; i++) { + if (index <= 1 || index == 16) { + b43err(dev->wl, + "Unsupported RF Ctrl Override call\n"); + return; + } + + if (index == 2 || index == 10 || + (index >= 13 && index <= 15)) { + core = 1; + } + + rf_ctrl = &tbl_rf_control_override_rev2[index - 2]; + addr = B43_PHY_N((i == 0) ? + rf_ctrl->addr0 : rf_ctrl->addr1); + + if ((core & (1 << i)) != 0) + b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask), + (value << rf_ctrl->shift)); + + b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_START); + udelay(1); + b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE); + } + } +} + static void b43_nphy_bphy_init(struct b43_wldev *dev) { unsigned int i; @@ -2075,8 +2151,8 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) | (cur_lna << 2)); - /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0], - 3, 0 as arguments */ + b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3, + false); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); b43_nphy_stop_playback(dev); @@ -2124,7 +2200,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, break; } - /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/ + b43_nphy_rf_control_override(dev, 0x400, 0, 3, true); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index b8c9fc619ab1..dd9687d611d7 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2883,6 +2883,43 @@ const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { 0x9084, 0x9267, 0x9056, 0x9234 }; +/* addr0, addr1, bmask, shift */ +const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[] = { + { 0x78, 0x78, 0x0038, 3 }, /* for field == 0x0002 (fls == 2) */ + { 0x7A, 0x7D, 0x0001, 0 }, /* for field == 0x0004 (fls == 3) */ + { 0x7A, 0x7D, 0x0002, 1 }, /* for field == 0x0008 (fls == 4) */ + { 0x7A, 0x7D, 0x0004, 2 }, /* for field == 0x0010 (fls == 5) */ + { 0x7A, 0x7D, 0x0030, 4 }, /* for field == 0x0020 (fls == 6) */ + { 0x7A, 0x7D, 0x00C0, 6 }, /* for field == 0x0040 (fls == 7) */ + { 0x7A, 0x7D, 0x0100, 8 }, /* for field == 0x0080 (fls == 8) */ + { 0x7A, 0x7D, 0x0200, 9 }, /* for field == 0x0100 (fls == 9) */ + { 0x78, 0x78, 0x0004, 2 }, /* for field == 0x0200 (fls == 10) */ + { 0x7B, 0x7E, 0x01FF, 0 }, /* for field == 0x0400 (fls == 11) */ + { 0x7C, 0x7F, 0x01FF, 0 }, /* for field == 0x0800 (fls == 12) */ + { 0x78, 0x78, 0x0100, 8 }, /* for field == 0x1000 (fls == 13) */ + { 0x78, 0x78, 0x0200, 9 }, /* for field == 0x2000 (fls == 14) */ + { 0x78, 0x78, 0xF000, 12 } /* for field == 0x4000 (fls == 15) */ +}; + +/* val_mask, val_shift, en_addr0, val_addr0, en_addr1, val_addr1 */ +const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = { + { 0x8000, 15, 0xE5, 0xF9, 0xE6, 0xFB }, /* field == 0x0001 (fls 1) */ + { 0x0001, 0, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0002 (fls 2) */ + { 0x0002, 1, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0004 (fls 3) */ + { 0x0004, 2, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0008 (fls 4) */ + { 0x0016, 4, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0010 (fls 5) */ + { 0x0020, 5, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0020 (fls 6) */ + { 0x0040, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0040 (fls 7) */ + { 0x0080, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0080 (fls 8) */ + { 0x0100, 7, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0100 (fls 9) */ + { 0x0007, 0, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0200 (fls 10) */ + { 0x0070, 4, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0400 (fls 11) */ + { 0xE000, 13, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0800 (fls 12) */ + { 0xFFFF, 0, 0xE7, 0x7B, 0xEC, 0x7E }, /* field == 0x1000 (fls 13) */ + { 0xFFFF, 0, 0xE7, 0x7C, 0xEC, 0x7F }, /* field == 0x2000 (fls 14) */ + { 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */ +}; + static inline void assert_ntab_array_sizes(void) { #undef check diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 6bbef894010c..5d38172a152d 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -51,6 +51,22 @@ struct nphy_txiqcal_ladder { u8 g_env; }; +struct nphy_rf_control_override_rev2 { + u8 addr0; + u8 addr1; + u16 bmask; + u8 shift; +}; + +struct nphy_rf_control_override_rev3 { + u16 val_mask; + u8 val_shift; + u8 en_addr0; + u8 val_addr0; + u8 en_addr1; + u8 val_addr1; +}; + /* Upload the default register value table. * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz * table is uploaded. If "ignore_uploadflag" is true, we upload any value @@ -178,4 +194,9 @@ extern const u16 tbl_tx_iqlo_cal_cmds_recal[]; extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[]; extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[]; +extern const struct nphy_rf_control_override_rev2 + tbl_rf_control_override_rev2[]; +extern const struct nphy_rf_control_override_rev3 + tbl_rf_control_override_rev3[]; + #endif /* B43_TABLES_NPHY_H_ */ -- GitLab From 10a798733e0f47923a1050231d8d39609c62be70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 22 Jan 2010 01:53:14 +0100 Subject: [PATCH 1109/3892] b43: N-PHY: add running samples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 68 ++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d3c9783b76ba..f5900f04ff5c 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -816,6 +816,66 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ +static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, + u16 wait, bool iqmode, bool dac_test) +{ + struct b43_phy_n *nphy = dev->phy.n; + int i; + u16 seq_mode; + u32 tmp; + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, true); + + if ((nphy->bb_mult_save & 0x80000000) == 0) { + tmp = b43_ntab_read(dev, B43_NTAB16(15, 87)); + nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000; + } + + if (!dev->phy.is_40mhz) + tmp = 0x6464; + else + tmp = 0x4747; + b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, false); + + b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1)); + + if (loops != 0xFFFF) + b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1)); + else + b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops); + + b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait); + + seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE); + + b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER); + if (iqmode) { + b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF); + b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000); + } else { + if (dac_test) + b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5); + else + b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1); + } + for (i = 0; i < 100; i++) { + if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) { + i = 0; + break; + } + udelay(10); + } + if (i) + b43err(dev->wl, "run samples timeout\n"); + + b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) { @@ -1869,8 +1929,8 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, freq = 5000; if (nphy->mphase_cal_phase_id > 2) - ;/* TODO: Call N PHY Run Samples with (band width * 8), - 0xFFFF, 0, 1, 0 as arguments */ + b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8, + 0xFFFF, 0, true, false); else ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments and save result as error */ @@ -2162,8 +2222,8 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, as arguments and save result as ret */ playtone = false; } else { - /* TODO: Call N PHY Run Samples with 160, - 0xFFFF, 0, 0, 0 as arguments */ + b43_nphy_run_samples(dev, 160, 0xFFFF, 0, + false, false); } if (ret == 0) { -- GitLab From 45ca697e60eb5d3cac4530ae3a88f96c297efb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 22 Jan 2010 01:53:15 +0100 Subject: [PATCH 1110/3892] b43: N-PHY: add setting power amplifier filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 41 ++++++++++++++++++++++++-- drivers/net/wireless/b43/tables_nphy.c | 24 +++++++++++++++ drivers/net/wireless/b43/tables_nphy.h | 1 + 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index f5900f04ff5c..97a44e43d057 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1628,6 +1628,43 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ +static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev) +{ + int i; + for (i = 0; i < 15; i++) + b43_phy_write(dev, B43_PHY_N(0x2C5 + i), + tbl_tx_filter_coef_rev4[2][i]); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ +static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) +{ + int i, j; + /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ + u16 offset[] = { 0x186, 0x195, 0x2C5 }; + + for (i = 0; i < 3; i++) + for (j = 0; j < 15; j++) + b43_phy_write(dev, B43_PHY_N(offset[i] + j), + tbl_tx_filter_coef_rev4[i][j]); + + if (dev->phy.is_40mhz) { + for (j = 0; j < 15; j++) + b43_phy_write(dev, B43_PHY_N(offset[0] + j), + tbl_tx_filter_coef_rev4[3][j]); + } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + for (j = 0; j < 15; j++) + b43_phy_write(dev, B43_PHY_N(offset[0] + j), + tbl_tx_filter_coef_rev4[5][j]); + } + + if (dev->phy.channel == 14) + for (j = 0; j < 15; j++) + b43_phy_write(dev, B43_PHY_N(offset[0] + j), + tbl_tx_filter_coef_rev4[6][j]); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) { @@ -2371,9 +2408,9 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1); b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F, nphy->papd_epsilon_offset[1] << 7); - /* TODO N PHY IPA Set TX Dig Filters */ + b43_nphy_int_pa_set_tx_dig_filters(dev); } else if (phy->rev >= 5) { - /* TODO N PHY Ext PA Set TX Dig Filters */ + b43_nphy_ext_pa_set_tx_dig_filters(dev); } b43_nphy_workarounds(dev); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index dd9687d611d7..a00d509150f7 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2883,6 +2883,30 @@ const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { 0x9084, 0x9267, 0x9056, 0x9234 }; +const s16 tbl_tx_filter_coef_rev4[7][15] = { + { -377, 137, -407, 208, -1527, + 956, 93, 186, 93, 230, + -44, 230, 20, -191, 201 }, + { -77, 20, -98, 49, -93, + 60, 56, 111, 56, 26, + -5, 26, 34, -32, 34 }, + { -360, 164, -376, 164, -1533, + 576, 308, -314, 308, 121, + -73, 121, 91, 124, 91 }, + { -295, 200, -363, 142, -1391, + 826, 151, 301, 151, 151, + 301, 151, 602, -752, 602 }, + { -92, 58, -96, 49, -104, + 44, 17, 35, 17, 12, + 25, 12, 13, 27, 13 }, + { -375, 136, -399, 209, -1479, + 949, 130, 260, 130, 230, + -44, 230, 201, -191, 201 }, + { 0xed9, 0xc8, 0xe95, 0x8e, 0xa91, + 0x33a, 0x97, 0x12d, 0x97, 0x97, + 0x12d, 0x97, 0x25a, 0xd10, 0x25a } +}; + /* addr0, addr1, bmask, shift */ const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[] = { { 0x78, 0x78, 0x0038, 3 }, /* for field == 0x0002 (fls == 2) */ diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 5d38172a152d..9c1c6ecd3672 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -193,6 +193,7 @@ extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[]; extern const u16 tbl_tx_iqlo_cal_cmds_recal[]; extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[]; extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[]; +extern const s16 tbl_tx_filter_coef_rev4[7][15]; extern const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[]; -- GitLab From 59af099b1956086b06c0d0f32ea99ce136b415b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 22 Jan 2010 01:53:16 +0100 Subject: [PATCH 1111/3892] b43: N-PHY: add TX tone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 60 +++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 97a44e43d057..a45a1f3ced42 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -816,6 +816,43 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ +static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, + bool test) +{ + int i; + u16 bw, len, num, rot, angle; + /* TODO: *buffer; */ + + bw = (dev->phy.is_40mhz) ? 40 : 20; + len = bw << 3; + + if (test) { + if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX) + bw = 82; + else + bw = 80; + + if (dev->phy.is_40mhz) + bw <<= 1; + + len = bw << 1; + } + + /* TODO: buffer = kzalloc(len * sizeof(u32), GFP_KERNEL); */ + num = len; + rot = (((freq * 36) / bw) << 16) / 100; + angle = 0; + + for (i = 0; i < num; i++) { + /* TODO */ + } + + /* TODO: Call N PHY Load Sample Table with buffer, num as arguments */ + /* TODO: kfree(buffer); */ + return num; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, u16 wait, bool iqmode, bool dac_test) @@ -876,6 +913,20 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); } +/* + * Transmits a known value for LO calibration + * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone + */ +static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, + bool iqmode, bool dac_test) +{ + u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test); + if (samp == 0) + return -1; + b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test); + return 0; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) { @@ -1969,8 +2020,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8, 0xFFFF, 0, true, false); else - ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments - and save result as error */ + error = b43_nphy_tx_tone(dev, freq, 250, true, false); if (error == 0) { if (nphy->mphase_cal_phase_id > 2) { @@ -2254,9 +2304,9 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, b43_nphy_stop_playback(dev); if (playtone) { - /* TODO: Call N PHY TX Tone with 4000, - (nphy_rxcalparams & 0xffff), 0, 0 - as arguments and save result as ret */ + ret = b43_nphy_tx_tone(dev, 4000, + (nphy->rxcalparams & 0xFFFF), + false, false); playtone = false; } else { b43_nphy_run_samples(dev, 160, 0xFFFF, 0, -- GitLab From b92f7d30830a319148df2943b7565989494e5ad1 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 22 Jan 2010 08:01:11 +0100 Subject: [PATCH 1112/3892] p54pci: revise tx locking This patch continues the effort which began with: "[PATCH] p54pci: move tx cleanup into tasklet". Thanks to these changes, p54pci's interrupt & tx cleanup routines can be made lock-less. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 48cae48ed6eb..bda29c00f3ef 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -238,7 +238,6 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, int ring_index, struct p54p_desc *ring, u32 ring_limit, struct sk_buff **tx_buf) { - unsigned long flags; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_desc *desc; @@ -249,7 +248,6 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); idx %= ring_limit; - spin_lock_irqsave(&priv->lock, flags); while (i != idx) { desc = &ring[i]; @@ -264,16 +262,12 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, desc->len = 0; desc->flags = 0; - if (skb && FREE_AFTER_TX(skb)) { - spin_unlock_irqrestore(&priv->lock, flags); + if (skb && FREE_AFTER_TX(skb)) p54_free_skb(dev, skb); - spin_lock_irqsave(&priv->lock, flags); - } i++; i %= ring_limit; } - spin_unlock_irqrestore(&priv->lock, flags); } static void p54p_tasklet(unsigned long dev_id) @@ -306,7 +300,6 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) struct p54p_priv *priv = dev->priv; __le32 reg; - spin_lock(&priv->lock); reg = P54P_READ(int_ident); if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { goto out; @@ -321,15 +314,14 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) complete(&priv->boot_comp); out: - spin_unlock(&priv->lock); return reg ? IRQ_HANDLED : IRQ_NONE; } static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { + unsigned long flags; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; - unsigned long flags; struct p54p_desc *desc; dma_addr_t mapping; u32 device_idx, idx, i; @@ -370,14 +362,14 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; - tasklet_kill(&priv->tasklet); - P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); free_irq(priv->pdev->irq, dev); + tasklet_kill(&priv->tasklet); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { -- GitLab From 477781477a88f60c89003c852def4aedc6f78101 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 22 Jan 2010 22:21:18 +0100 Subject: [PATCH 1113/3892] netfiltr: ipt_CLUSTERIP: simplify seq_file codeA Pass "struct clusterip_config" itself to seq_file iterators and save one dereference. Proc entry itself isn't interesting. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 40ca2d240abb..0886f96c736b 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -560,8 +560,7 @@ struct clusterip_seq_position { static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) { - const struct proc_dir_entry *pde = s->private; - struct clusterip_config *c = pde->data; + struct clusterip_config *c = s->private; unsigned int weight; u_int32_t local_nodes; struct clusterip_seq_position *idx; @@ -632,10 +631,9 @@ static int clusterip_proc_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *sf = file->private_data; - struct proc_dir_entry *pde = PDE(inode); - struct clusterip_config *c = pde->data; + struct clusterip_config *c = PDE(inode)->data; - sf->private = pde; + sf->private = c; clusterip_config_get(c); } @@ -645,8 +643,7 @@ static int clusterip_proc_open(struct inode *inode, struct file *file) static int clusterip_proc_release(struct inode *inode, struct file *file) { - struct proc_dir_entry *pde = PDE(inode); - struct clusterip_config *c = pde->data; + struct clusterip_config *c = PDE(inode)->data; int ret; ret = seq_release(inode, file); @@ -660,10 +657,9 @@ static int clusterip_proc_release(struct inode *inode, struct file *file) static ssize_t clusterip_proc_write(struct file *file, const char __user *input, size_t size, loff_t *ofs) { + struct clusterip_config *c = PDE(file->f_path.dentry->d_inode)->data; #define PROC_WRITELEN 10 char buffer[PROC_WRITELEN+1]; - const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); - struct clusterip_config *c = pde->data; unsigned long nodenum; if (copy_from_user(buffer, input, PROC_WRITELEN)) -- GitLab From f12553ebe045a8a40ab33fa500fb57d10706e226 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 22:07:59 +0100 Subject: [PATCH 1114/3892] mac80211: add missing key check ieee80211_tx_h_select_key might decide that a frame need not be encrypted at all, in which case it will clear tx->key. In that case it may crash if a key was previously selected, e.g. as the default key. This is also due to my patch "mac80211: move control.hw_key assignment". Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index da557b0d0114..fcfa988a37a3 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -557,7 +557,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) break; } - if (!skip_hw && + if (!skip_hw && tx->key && tx->key->conf.flags & KEY_FLAG_UPLOADED_TO_HARDWARE) info->control.hw_key = &tx->key->conf; } -- GitLab From a7b480e7f30b3813353ec009f10f2ac7a6669f3b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:03 +0100 Subject: [PATCH 1115/3892] x86, lib: Add wbinvd smp helpers Add wbinvd_on_cpu and wbinvd_on_all_cpus stubs for executing wbinvd on a particular CPU. [ hpa: renamed lib/smp.c to lib/cache-smp.c ] [ hpa: wbinvd_on_all_cpus() returns int, but wbinvd() returns void. Thus, the former cannot be a macro for the latter, replace with an inline function. ] Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-2-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/smp.h | 9 +++++++++ arch/x86/lib/Makefile | 2 +- arch/x86/lib/cache-smp.c | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/cache-smp.c diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 1e796782cd7b..4cfc90824068 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -135,6 +135,8 @@ int native_cpu_disable(void); void native_cpu_die(unsigned int cpu); void native_play_dead(void); void play_dead_common(void); +void wbinvd_on_cpu(int cpu); +int wbinvd_on_all_cpus(void); void native_send_call_func_ipi(const struct cpumask *mask); void native_send_call_func_single_ipi(int cpu); @@ -147,6 +149,13 @@ static inline int num_booting_cpus(void) { return cpumask_weight(cpu_callout_mask); } +#else /* !CONFIG_SMP */ +#define wbinvd_on_cpu(cpu) wbinvd() +static inline int wbinvd_on_all_cpus(void) +{ + wbinvd(); + return 0; +} #endif /* CONFIG_SMP */ extern unsigned disabled_cpus __cpuinitdata; diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index cffd754f3039..d85e0e438b58 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -14,7 +14,7 @@ $(obj)/inat.o: $(obj)/inat-tables.c clean-files := inat-tables.c -obj-$(CONFIG_SMP) += msr-smp.o +obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o lib-y := delay.o lib-y += thunk_$(BITS).o diff --git a/arch/x86/lib/cache-smp.c b/arch/x86/lib/cache-smp.c new file mode 100644 index 000000000000..a3c668875038 --- /dev/null +++ b/arch/x86/lib/cache-smp.c @@ -0,0 +1,19 @@ +#include +#include + +static void __wbinvd(void *dummy) +{ + wbinvd(); +} + +void wbinvd_on_cpu(int cpu) +{ + smp_call_function_single(cpu, __wbinvd, NULL, 1); +} +EXPORT_SYMBOL(wbinvd_on_cpu); + +int wbinvd_on_all_cpus(void) +{ + return on_each_cpu(__wbinvd, NULL, 1); +} +EXPORT_SYMBOL(wbinvd_on_all_cpus); -- GitLab From 48a719c238bcbb72d6da79de9c5b3b93ab472107 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:04 +0100 Subject: [PATCH 1116/3892] intel-agp: Switch to wbinvd_on_all_cpus Simplify if-statement while at it. [ hpa: we need to #include ] Cc: Dave Jones Cc: David Airlie Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-3-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- drivers/char/agp/intel-agp.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 3999a5f25f38..8a713f1e9653 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "agp.h" /* @@ -815,12 +816,6 @@ static void intel_i830_setup_flush(void) intel_i830_fini_flush(); } -static void -do_wbinvd(void *null) -{ - wbinvd(); -} - /* The chipset_flush interface needs to get data that has already been * flushed out of the CPU all the way out to main memory, because the GPU * doesn't snoop those buffers. @@ -837,12 +832,10 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) memset(pg, 0, 1024); - if (cpu_has_clflush) { + if (cpu_has_clflush) clflush_cache_range(pg, 1024); - } else { - if (on_each_cpu(do_wbinvd, NULL, 1) != 0) - printk(KERN_ERR "Timed out waiting for cache flush.\n"); - } + else if (wbinvd_on_all_cpus() != 0) + printk(KERN_ERR "Timed out waiting for cache flush.\n"); } /* The intel i830 automatically initializes the agp aperture during POST. -- GitLab From dcf39daf3d6d97f8741e82f0b9fb7554704ed2d1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:05 +0100 Subject: [PATCH 1117/3892] x86, cacheinfo: Fix disabling of L3 cache indices * Correct the masks used for writing the cache index disable indices. * Do not turn off L3 scrubber - it is not necessary. * Make sure wbinvd is executed on the same node where the L3 is. * Check for out-of-bounds values written to the registers. * Make show_cache_disable hex values unambiguous * Check for Erratum #388 Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-4-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/intel_cacheinfo.c | 34 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index fc6c8ef92dcc..08c91abc4d32 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -18,6 +18,7 @@ #include #include #include +#include #define LVL_1_INST 1 #define LVL_1_DATA 2 @@ -299,8 +300,10 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) if (boot_cpu_data.x86 == 0x11) return; - /* see erratum #382 */ - if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) + /* see errata #382 and #388 */ + if ((boot_cpu_data.x86 == 0x10) && + ((boot_cpu_data.x86_model < 0x9) || + (boot_cpu_data.x86_mask < 0x1))) return; this_leaf->can_disable = 1; @@ -726,12 +729,12 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, return -EINVAL; pci_read_config_dword(dev, 0x1BC + index * 4, ®); - return sprintf(buf, "%x\n", reg); + return sprintf(buf, "0x%08x\n", reg); } #define SHOW_CACHE_DISABLE(index) \ static ssize_t \ -show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ +show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ { \ return show_cache_disable(this_leaf, buf, index); \ } @@ -745,7 +748,9 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, int node = cpu_to_node(cpu); struct pci_dev *dev = node_to_k8_nb_misc(node); unsigned long val = 0; - unsigned int scrubber = 0; + +#define SUBCACHE_MASK (3UL << 20) +#define SUBCACHE_INDEX 0xfff if (!this_leaf->can_disable) return -EINVAL; @@ -759,21 +764,24 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; - val |= 0xc0000000; - - pci_read_config_dword(dev, 0x58, &scrubber); - scrubber &= ~0x1f000000; - pci_write_config_dword(dev, 0x58, scrubber); + /* do not allow writes outside of allowed bits */ + if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) + return -EINVAL; - pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); - wbinvd(); + val |= BIT(30); pci_write_config_dword(dev, 0x1BC + index * 4, val); + /* + * We need to WBINVD on a core on the node containing the L3 cache which + * indices we disable therefore a simple wbinvd() is not sufficient. + */ + wbinvd_on_cpu(cpu); + pci_write_config_dword(dev, 0x1BC + index * 4, val | BIT(31)); return count; } #define STORE_CACHE_DISABLE(index) \ static ssize_t \ -store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ +store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ const char *buf, size_t count) \ { \ return store_cache_disable(this_leaf, buf, count, index); \ -- GitLab From 897de50e08937663912c86fb12ad7f708af2386c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:06 +0100 Subject: [PATCH 1118/3892] x86, cacheinfo: Add cache index disable sysfs attrs only to L3 caches The cache_disable_[01] attribute in /sys/devices/system/cpu/cpu?/cache/index[0-3]/ is enabled on all cache levels although only L3 supports it. Add it only to the cache level that actually supports it. Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-5-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/intel_cacheinfo.c | 35 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 08c91abc4d32..3976ce95095f 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -814,16 +814,24 @@ static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, show_cache_disable_1, store_cache_disable_1); +#define DEFAULT_SYSFS_CACHE_ATTRS \ + &type.attr, \ + &level.attr, \ + &coherency_line_size.attr, \ + &physical_line_partition.attr, \ + &ways_of_associativity.attr, \ + &number_of_sets.attr, \ + &size.attr, \ + &shared_cpu_map.attr, \ + &shared_cpu_list.attr + static struct attribute *default_attrs[] = { - &type.attr, - &level.attr, - &coherency_line_size.attr, - &physical_line_partition.attr, - &ways_of_associativity.attr, - &number_of_sets.attr, - &size.attr, - &shared_cpu_map.attr, - &shared_cpu_list.attr, + DEFAULT_SYSFS_CACHE_ATTRS, + NULL +}; + +static struct attribute *default_l3_attrs[] = { + DEFAULT_SYSFS_CACHE_ATTRS, &cache_disable_0.attr, &cache_disable_1.attr, NULL @@ -916,6 +924,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) unsigned int cpu = sys_dev->id; unsigned long i, j; struct _index_kobject *this_object; + struct _cpuid4_info *this_leaf; int retval; retval = cpuid4_cache_sysfs_init(cpu); @@ -934,6 +943,14 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) this_object = INDEX_KOBJECT_PTR(cpu, i); this_object->cpu = cpu; this_object->index = i; + + this_leaf = CPUID4_INFO_IDX(cpu, i); + + if (this_leaf->can_disable) + ktype_cache.default_attrs = default_l3_attrs; + else + ktype_cache.default_attrs = default_attrs; + retval = kobject_init_and_add(&(this_object->kobj), &ktype_cache, per_cpu(ici_cache_kobject, cpu), -- GitLab From 048a8774ca43488d78605031f11cc206d7a2682a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jan 2010 16:01:07 +0100 Subject: [PATCH 1119/3892] x86, cacheinfo: Calculate L3 indices We need to know the valid L3 indices interval when disabling them over /sysfs. Do that when the core is brought online and add boundary checks to the sysfs .store attribute. Signed-off-by: Borislav Petkov LKML-Reference: <1264172467-25155-6-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/intel_cacheinfo.c | 35 ++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 3976ce95095f..589b705e80ed 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -151,7 +151,8 @@ struct _cpuid4_info { union _cpuid4_leaf_ebx ebx; union _cpuid4_leaf_ecx ecx; unsigned long size; - unsigned long can_disable; + bool can_disable; + unsigned int l3_indices; DECLARE_BITMAP(shared_cpu_map, NR_CPUS); }; @@ -161,7 +162,8 @@ struct _cpuid4_info_regs { union _cpuid4_leaf_ebx ebx; union _cpuid4_leaf_ecx ecx; unsigned long size; - unsigned long can_disable; + bool can_disable; + unsigned int l3_indices; }; unsigned short num_cache_leaves; @@ -291,6 +293,29 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, (ebx->split.ways_of_associativity + 1) - 1; } +static unsigned int __cpuinit amd_calc_l3_indices(void) +{ + /* + * We're called over smp_call_function_single() and therefore + * are on the correct cpu. + */ + int cpu = smp_processor_id(); + int node = cpu_to_node(cpu); + struct pci_dev *dev = node_to_k8_nb_misc(node); + unsigned int sc0, sc1, sc2, sc3; + u32 val; + + pci_read_config_dword(dev, 0x1C4, &val); + + /* calculate subcache sizes */ + sc0 = !(val & BIT(0)); + sc1 = !(val & BIT(4)); + sc2 = !(val & BIT(8)) + !(val & BIT(9)); + sc3 = !(val & BIT(12)) + !(val & BIT(13)); + + return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1; +} + static void __cpuinit amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) { @@ -306,7 +331,8 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) (boot_cpu_data.x86_mask < 0x1))) return; - this_leaf->can_disable = 1; + this_leaf->can_disable = true; + this_leaf->l3_indices = amd_calc_l3_indices(); } static int @@ -765,7 +791,8 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, return -EINVAL; /* do not allow writes outside of allowed bits */ - if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) + if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) || + ((val & SUBCACHE_INDEX) > this_leaf->l3_indices)) return -EINVAL; val |= BIT(30); -- GitLab From 1ada1b1b41b0e54291aca67eed4bd42e61e7e529 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:45:43 +0000 Subject: [PATCH 1120/3892] ixgbe: Set the correct pool when VLANs are added in SR-IOV mode. When VFs are allocated (as indicated by adapter->num_vfs is non-zero) then the PF pool is no longer zero. Instead it will be the same as the number of VFs allocated. When setting the VLVF entry for the PF we need to use the correct pool otherwise the PF will get VLAN packets from the wire because the packet will pass VFTA filtering and the PF has the default pool, but it will not get VLAN packets from the VFs because it has not set the correct pool bit in the VLVF entry. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index c46252520d7a..b8fd81748602 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2432,15 +2432,17 @@ static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + int pool_ndx = adapter->num_vfs; /* add VID to filter table */ - hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true); + hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, true); } static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + int pool_ndx = adapter->num_vfs; if (!test_bit(__IXGBE_DOWN, &adapter->state)) ixgbe_irq_disable(adapter); @@ -2451,7 +2453,7 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) ixgbe_irq_enable(adapter); /* remove VID from filter table */ - hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false); + hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, false); } static void ixgbe_vlan_rx_register(struct net_device *netdev, -- GitLab From ef291b8c71ee934d077676b891494c50e17ccc28 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:46:02 +0000 Subject: [PATCH 1121/3892] ixgbe: Remove unused emulation MAC storage from the per VF data structure. This data storage for SW emulated MAC addresses is unlikely to ever be used so pull it. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index db64f139f173..e576fb4740bc 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -110,7 +110,6 @@ struct vf_data_storage { u16 num_vf_mc_hashes; u16 default_vf_vlan_id; u16 vlans_enabled; - unsigned char em_mac_addresses[MAX_EMULATION_MAC_ADDRS * ETH_ALEN]; bool clear_to_send; int rar; }; -- GitLab From c9205697c7527173c8f8bfa9f8c9dabdbced3c49 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:46:22 +0000 Subject: [PATCH 1122/3892] ixgbe: Allow the VF driver to be loaded before the PF driver The PF Reset Done bit should not be set in the extended control register until the PF has actually completed the bring up process. It is a mis- interpretation of the purpose of this bit to assume it should be set when the physical reset of the device is done. Instead it should be used to indicate to the VFs when the PF is ready to provide them with required services. This is not until after the PF is finished coming up and ready to process mailbox events. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82599.c | 6 +----- drivers/net/ixgbe/ixgbe_main.c | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index c92b5b8b3181..d4ed6adb7975 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -890,7 +890,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { s32 status = 0; - u32 ctrl, ctrl_ext; + u32 ctrl; u32 i; u32 autoc; u32 autoc2; @@ -945,10 +945,6 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) status = IXGBE_ERR_RESET_FAILED; hw_dbg(hw, "Reset polling failed to complete.\n"); } - /* Clear PF Reset Done bit so PF/VF Mail Ops can work */ - ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); - ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; - IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); msleep(50); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b8fd81748602..b96afd98fa3d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2826,6 +2826,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) u32 txdctl, rxdctl, mhadd; u32 dmatxctl; u32 gpie; + u32 ctrl_ext; ixgbe_get_hw_control(adapter); @@ -3015,6 +3016,12 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; mod_timer(&adapter->watchdog_timer, jiffies); + + /* Set PF Reset Done bit so PF/VF Mail Ops can work */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + return 0; } -- GitLab From 767081adbd920ce93e3f1cbe797d0631637f92b3 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:46:40 +0000 Subject: [PATCH 1123/3892] ixgbe: Improve reset coordination between the PF and the VF Inadequate coordination between the PF driver and the VF driver results in tx hangs in the VF driver when you perform certain actions that will lead to a re-init of the PF. Add feature to notify active VFs when the PF is about to re-initialize so that the VFs can take appropriate action. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 11 +++++++++++ drivers/net/ixgbe/ixgbe_sriov.c | 26 ++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_sriov.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b96afd98fa3d..ee41d331a35f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3203,6 +3203,17 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); + /* disable receive for all VFs and wait one second */ + if (adapter->num_vfs) { + for (i = 0 ; i < adapter->num_vfs; i++) + adapter->vfinfo[i].clear_to_send = 0; + + /* ping all the active vfs to let them know we are going down */ + ixgbe_ping_all_vfs(adapter); + /* Disable all VFTE/VFRE TX/RX */ + ixgbe_disable_tx_rx(adapter); + } + /* disable receives */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 74bca74d57c1..d4cd20f30199 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -334,3 +334,29 @@ void ixgbe_msg_task(struct ixgbe_adapter *adapter) } } +void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + /* disable transmit and receive for all vfs */ + IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0); + + IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0); +} + +void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 ping; + int i; + + for (i = 0 ; i < adapter->num_vfs; i++) { + ping = IXGBE_PF_CONTROL_MSG; + if (adapter->vfinfo[i].clear_to_send) + ping |= IXGBE_VT_MSGTYPE_CTS; + ixgbe_write_mbx(hw, &ping, 1, i); + } +} + diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ixgbe/ixgbe_sriov.h index 664b237eacb9..51d1106c45a1 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ixgbe/ixgbe_sriov.h @@ -39,6 +39,8 @@ void ixgbe_msg_task(struct ixgbe_adapter *adapter); int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, int vf, unsigned char *mac_addr); int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask); +void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter); +void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter); void ixgbe_dump_registers(struct ixgbe_adapter *adapter); #endif /* _IXGBE_SRIOV_H_ */ -- GitLab From a9ee25a2b87c8077042ce23d3231f67f026719b0 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:47:00 +0000 Subject: [PATCH 1124/3892] ixgbevf: Take action when the PF notifies the VF it is resetting. When the VF driver gets a control message from the PF that indicates the PF is about to reset or go down we schedule the watchdog timer so that it will detect the PF has gone offline and take appropriate action. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 39544afdc57f..bd2fd4608ed7 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -956,10 +956,17 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) struct ixgbevf_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 eicr; + u32 msg; eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS); IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr); + hw->mbx.ops.read(hw, &msg, 1); + + if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 10)); + return IRQ_HANDLED; } -- GitLab From c0456c231a8b2981128cc29e211b7bad1bd997df Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:47:18 +0000 Subject: [PATCH 1125/3892] ixgbevf: Fix panics in the VF driver Fix panics in the VF driver that occur when you bring it down after having already brought the PF down. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index bd2fd4608ed7..0a27fa17e7ff 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1693,8 +1693,10 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter, unsigned long size; unsigned int i; - /* Free all the Rx ring sk_buffs */ + if (!rx_ring->rx_buffer_info) + return; + /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { struct ixgbevf_rx_buffer *rx_buffer_info; @@ -1751,6 +1753,9 @@ static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter, unsigned long size; unsigned int i; + if (!tx_ring->tx_buffer_info) + return; + /* Free all the Tx ring sk_buffs */ for (i = 0; i < tx_ring->count; i++) { @@ -1843,12 +1848,24 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter) { + struct ixgbe_hw *hw = &adapter->hw; + WARN_ON(in_interrupt()); + while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) msleep(1); - ixgbevf_down(adapter); - ixgbevf_up(adapter); + /* + * Check if PF is up before re-init. If not then skip until + * later when the PF is up and ready to service requests from + * the VF via mailbox. If the VF is up and running then the + * watchdog task will continue to schedule reset tasks until + * the PF is up and running. + */ + if (!hw->mac.ops.reset_hw(hw)) { + ixgbevf_down(adapter); + ixgbevf_up(adapter); + } clear_bit(__IXGBEVF_RESETTING, &adapter->state); } @@ -2423,7 +2440,6 @@ void ixgbevf_free_tx_resources(struct ixgbevf_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; - ixgbevf_clean_tx_ring(adapter, tx_ring); vfree(tx_ring->tx_buffer_info); -- GitLab From da6b33306801af7ee6479c177051e70842974932 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 22 Jan 2010 22:47:37 +0000 Subject: [PATCH 1126/3892] ixgbevf: Tell network stack to stop tx when the VF detects PF reset When the VF detects that the PF has reset turn off carrier and stop all tx queues. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 0a27fa17e7ff..623353db11ba 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -2381,6 +2381,8 @@ static void ixgbevf_watchdog_task(struct work_struct *work) &link_up, false)) != 0) { adapter->link_up = link_up; adapter->link_speed = link_speed; + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); schedule_work(&adapter->reset_task); goto pf_has_reset; } -- GitLab From a271623f871dda970319ca15dfad3a8c8c36249f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 22 Jan 2010 10:13:10 +0000 Subject: [PATCH 1127/3892] netdev: remove certain HAVE_ macros After netdev_ops compat code HAVE_* macros aren't needed, in fact they _will_ result in compile breakage for out of tree drivers. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/netdevice.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 468a11dea58c..b5fb51d0b8b1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -621,30 +621,21 @@ struct net_device_ops { struct net_device *dev); u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); -#define HAVE_CHANGE_RX_FLAGS void (*ndo_change_rx_flags)(struct net_device *dev, int flags); -#define HAVE_SET_RX_MODE void (*ndo_set_rx_mode)(struct net_device *dev); -#define HAVE_MULTICAST void (*ndo_set_multicast_list)(struct net_device *dev); -#define HAVE_SET_MAC_ADDR int (*ndo_set_mac_address)(struct net_device *dev, void *addr); -#define HAVE_VALIDATE_ADDR int (*ndo_validate_addr)(struct net_device *dev); -#define HAVE_PRIVATE_IOCTL int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); -#define HAVE_SET_CONFIG int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); -#define HAVE_CHANGE_MTU int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); int (*ndo_neigh_setup)(struct net_device *dev, struct neigh_parms *); -#define HAVE_TX_TIMEOUT void (*ndo_tx_timeout) (struct net_device *dev); struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); @@ -656,7 +647,6 @@ struct net_device_ops { void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); #ifdef CONFIG_NET_POLL_CONTROLLER -#define HAVE_NETDEV_POLL void (*ndo_poll_controller)(struct net_device *dev); #endif #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) -- GitLab From 81c1ebfc4379f529b001e23164dd5c2282bdc0ec Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 22 Jan 2010 10:16:05 +0000 Subject: [PATCH 1128/3892] neigh: simplify seq_file code Simpily pass 'struct neigh_table' with seq_file private pointer, and save one dereference. Proc entry itself isn't interesting. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/core/neighbour.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f35377b643e4..f2efd72da799 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2417,8 +2417,7 @@ EXPORT_SYMBOL(neigh_seq_stop); static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) { - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; + struct neigh_table *tbl = seq->private; int cpu; if (*pos == 0) @@ -2435,8 +2434,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; + struct neigh_table *tbl = seq->private; int cpu; for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { @@ -2455,8 +2453,7 @@ static void neigh_stat_seq_stop(struct seq_file *seq, void *v) static int neigh_stat_seq_show(struct seq_file *seq, void *v) { - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; + struct neigh_table *tbl = seq->private; struct neigh_statistics *st = v; if (v == SEQ_START_TOKEN) { @@ -2501,7 +2498,7 @@ static int neigh_stat_seq_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *sf = file->private_data; - sf->private = PDE(inode); + sf->private = PDE(inode)->data; } return ret; }; -- GitLab From 5833929cc2ad2b3064b4fac8c44e293972d240d8 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 22 Jan 2010 10:17:26 +0000 Subject: [PATCH 1129/3892] net: constify MIB name tables Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/net/snmp.h | 2 +- net/ipv4/proc.c | 4 ++-- net/ipv6/proc.c | 12 ++++++------ net/sctp/proc.c | 2 +- net/xfrm/xfrm_proc.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/snmp.h b/include/net/snmp.h index f0d756f2ac99..da02ee027d69 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -32,7 +32,7 @@ * - name of entries. */ struct snmp_mib { - char *name; + const char *name; int entry; }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index f25542c48b7d..1b09a6dde7c0 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -127,8 +127,8 @@ static const struct snmp_mib snmp4_ipextstats_list[] = { SNMP_MIB_SENTINEL }; -static struct { - char *name; +static const struct { + const char *name; int index; } icmpmibmap[] = { { "DestUnreachs", ICMP_DEST_UNREACH }, diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 02f20016b4c9..bfe2598dd563 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -59,7 +59,7 @@ static const struct file_operations sockstat6_seq_fops = { .release = single_release_net, }; -static struct snmp_mib snmp6_ipstats_list[] = { +static const struct snmp_mib snmp6_ipstats_list[] = { /* ipv6 mib according to RFC 2465 */ SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), @@ -92,7 +92,7 @@ static struct snmp_mib snmp6_ipstats_list[] = { SNMP_MIB_SENTINEL }; -static struct snmp_mib snmp6_icmp6_list[] = { +static const struct snmp_mib snmp6_icmp6_list[] = { /* icmpv6 mib according to RFC 2466 */ SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), @@ -120,7 +120,7 @@ static const char *const icmp6type2name[256] = { }; -static struct snmp_mib snmp6_udp6_list[] = { +static const struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), @@ -128,7 +128,7 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; -static struct snmp_mib snmp6_udplite6_list[] = { +static const struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), @@ -170,8 +170,8 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) return; } -static inline void -snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) +static void snmp6_seq_show_item(struct seq_file *seq, void **mib, + const struct snmp_mib *itemlist) { int i; for (i=0; itemlist[i].name; i++) diff --git a/net/sctp/proc.c b/net/sctp/proc.c index d093cbfeaac4..a5ac6e0a8d9c 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -40,7 +40,7 @@ #include #include /* for snmp_fold_field */ -static struct snmp_mib sctp_snmp_list[] = { +static const struct snmp_mib sctp_snmp_list[] = { SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB), SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS), SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS), diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index fef8db553e8d..c083a4e4e796 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c @@ -15,7 +15,7 @@ #include #include -static struct snmp_mib xfrm_mib_list[] = { +static const struct snmp_mib xfrm_mib_list[] = { SNMP_MIB_ITEM("XfrmInError", LINUX_MIB_XFRMINERROR), SNMP_MIB_ITEM("XfrmInBufferError", LINUX_MIB_XFRMINBUFFERERROR), SNMP_MIB_ITEM("XfrmInHdrError", LINUX_MIB_XFRMINHDRERROR), -- GitLab From e754834e65220b2b674c55c3b6dfb2fb1a2804d0 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 22 Jan 2010 10:18:25 +0000 Subject: [PATCH 1130/3892] icmp: move icmp_err_convert[] to .rodata Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/net/icmp.h | 2 +- net/ipv4/icmp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/icmp.h b/include/net/icmp.h index dfa72d4e8907..15b3dfe9fce8 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -28,7 +28,7 @@ struct icmp_err { unsigned fatal:1; }; -extern struct icmp_err icmp_err_convert[]; +extern const struct icmp_err icmp_err_convert[]; #define ICMP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmp_statistics, field) #define ICMP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field) #define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index fe11f60ce41b..4b4c2bcd15db 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -114,7 +114,7 @@ struct icmp_bxm { /* An array of errno for error messages from dest unreach. */ /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ -struct icmp_err icmp_err_convert[] = { +const struct icmp_err icmp_err_convert[] = { { .errno = ENETUNREACH, /* ICMP_NET_UNREACH */ .fatal = 0, -- GitLab From e9017b55189355e9e6569990a18919e83f35bccb Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Sat, 23 Jan 2010 01:57:42 -0800 Subject: [PATCH 1131/3892] IP: Send an ICMP "Fragment Reassembly Timeout" message when enabling connection track No matter whether connection track is enabled, an end host should send an ICMPv4 "Fragment Reassembly Timeout" message when defrag timeout. The reasons are following two points: 1. RFC 792 says: >>>> >> > > If a host reassembling a fragmented datagram cannot complete the >>>> >> > > reassembly due to missing fragments within its time limit it >>>> >> > > discards the datagram, and it may send a time exceeded message. >>>> >> > > >>>> >> > > If fragment zero is not available then no time exceeded need be >>>> >> > > sent at all. >>>> >> > > >>>> >> > > Read more: http://www.faqs.org/rfcs/rfc792.html#ixzz0aOXRD7Wp 2. Patrick McHardy also agrees with this opinion. :-) About the discussion of this opinion, refer to http://patchwork.ozlabs.org/patch/41649 The patch fixed the problem like this: When enabling connection track, fragments are received at PRE_ROUTING HOOK. If they are failed to reassemble, ip_expire() will be called. Before sending an ICMP "Fragment Reassembly Timeout" message, the patch searches router table to get the destination entry only for host type. The patch has been tested on both host type and route type. Signed-off-by: Shan Wei Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 891c72aea520..9f41bd311754 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -205,13 +207,37 @@ static void ip_expire(unsigned long arg) if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; - /* Send an ICMP "Fragment Reassembly Timeout" message. */ rcu_read_lock(); head->dev = dev_get_by_index_rcu(net, qp->iif); - if (head->dev) - icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); - rcu_read_unlock(); + if (!head->dev) + goto out_rcu_unlock; + + /* + * Only search router table for the head fragment, + * when defraging timeout at PRE_ROUTING HOOK. + */ + if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) { + const struct iphdr *iph = ip_hdr(head); + int err = ip_route_input(head, iph->daddr, iph->saddr, + iph->tos, head->dev); + if (unlikely(err)) + goto out_rcu_unlock; + + /* + * Only an end host needs to send an ICMP + * "Fragment Reassembly Timeout" message, per RFC792. + */ + if (skb_rtable(head)->rt_type != RTN_LOCAL) + goto out_rcu_unlock; + + } + + /* Send an ICMP "Fragment Reassembly Timeout" message. */ + icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); } + +out_rcu_unlock: + rcu_read_unlock(); out: spin_unlock(&qp->q.lock); ipq_put(qp); -- GitLab From 9010bc3364db56dd88a1851e0797e597e322ce08 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Sat, 23 Jan 2010 02:06:26 -0800 Subject: [PATCH 1132/3892] ixgbevf: Fix IPv6 GSO type checks Based on patch from Sridhar Samudrala The following patch fixes the check for IPv6 GSO packet in ixgbevf driver to use skb_is_gso_v6(). SKB_GSO_DODGY is also set when packets are forwarded from a guest. CC: Sridhar Samudrala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbevf/ixgbevf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 623353db11ba..7b3af107ca84 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -2781,7 +2781,7 @@ static int ixgbevf_tso(struct ixgbevf_adapter *adapter, IPPROTO_TCP, 0); adapter->hw_tso_ctxt++; - } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + } else if (skb_is_gso_v6(skb)) { ipv6_hdr(skb)->payload_len = 0; tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -- GitLab From 5f6c3de6a79820de124fa2bb1b77d43a09410e42 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 23 Jan 2010 22:19:29 +0100 Subject: [PATCH 1133/3892] ALSA: hda - Minor fixes for Compaq Presario F700 quirk Minor fixes for HP Compaq Presario F700 quirks with Cxt5051 codec: - changed the capture mixer elements to the standard name. - fixed the quirk name string without a space - sorted the quirk list - updated the documentation Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_conexant.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index e72cee9e2a71..cb46eb259d68 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -279,6 +279,7 @@ Conexant 5051 laptop Basic Laptop config (default) hp HP Spartan laptop hp-dv6736 HP dv6736 + hp-f700 HP Compaq Presario F700 lenovo-x200 Lenovo X200 laptop Conexant 5066 diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 685015a53292..084600e40829 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1742,8 +1742,8 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { }; static struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1901,17 +1901,17 @@ static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", [CXT5051_LENOVO_X200] = "lenovo-x200", - [CXT5051_F700] = "hp 700" + [CXT5051_F700] = "hp-700", }; static struct snd_pci_quirk cxt5051_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), + SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), {} }; -- GitLab From 4e4ac60030293cb3d1e4bacf7c8be9aebdb8df61 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 23 Jan 2010 22:29:54 +0100 Subject: [PATCH 1134/3892] ALSA: hda - Fix HP dv6736 capture mixer name Use the standard "Capture" mixer name for HP dv6736 with Cxt5051 codec. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 084600e40829..08c5b32dcd63 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1726,8 +1726,8 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { }; static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -- GitLab From 3b43a18743421cccd33902e29016fa49b2d52dbb Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sat, 23 Jan 2010 20:27:14 +0200 Subject: [PATCH 1135/3892] mac80211: fix tx select key null pointer crash with hostapd Pavel Roskin reported a crash in ieee80211_tx_h_select_key(): http://marc.info/?l=linux-wireless&m=126419655108528&w=2 This is a regression from patch "mac80211: move control.hw_key assignment". Fix it as suggested by Johannes, adding an else statement to make sure that tx->key is not accessed when it's null. Compile-tested only. Reported-by: Pavel Roskin Cc: Johannes Berg Signed-off-by: Kalle Valo Tested-by: Bob Copeland Signed-off-by: John W. Linville --- net/mac80211/tx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index fcfa988a37a3..d017b3530d4d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -547,9 +547,10 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) !ieee80211_use_mfp(hdr->frame_control, tx->sta, tx->skb)) tx->key = NULL; - skip_hw = (tx->key->conf.flags & - IEEE80211_KEY_FLAG_SW_MGMT) && - ieee80211_is_mgmt(hdr->frame_control); + else + skip_hw = (tx->key->conf.flags & + IEEE80211_KEY_FLAG_SW_MGMT) && + ieee80211_is_mgmt(hdr->frame_control); break; case ALG_AES_CMAC: if (!ieee80211_is_mgmt(hdr->frame_control)) -- GitLab From faddaa5d1c0cd29629c9c7e7a9d41ecb3149a064 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 23 Jan 2010 22:31:36 +0100 Subject: [PATCH 1136/3892] ALSA: hda - Add support for Toshiba Satellite M300 Added the support for Toshiba Satellite M300 with Conexant 5051 codec. Since the laptop has no port C connection and the pin reports always the jack sense true, we need to ignore port-C unsol event. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_conexant.c | 38 +++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index cb46eb259d68..8f06f20096f4 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -281,6 +281,7 @@ Conexant 5051 hp-dv6736 HP dv6736 hp-f700 HP Compaq Presario F700 lenovo-x200 Lenovo X200 laptop + toshiba Toshiba Satellite M300 Conexant 5066 ============= diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 08c5b32dcd63..56dda9c7f899 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -46,6 +46,8 @@ #define CXT5051_PORTB_EVENT 0x38 #define CXT5051_PORTC_EVENT 0x39 +#define AUTO_MIC_PORTB (1 << 1) +#define AUTO_MIC_PORTC (1 << 2) struct conexant_jack { @@ -74,7 +76,7 @@ struct conexant_spec { */ unsigned int cur_eapd; unsigned int hp_present; - unsigned int no_auto_mic; + unsigned int auto_mic; unsigned int need_dac_fix; /* capture */ @@ -1626,7 +1628,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int present; - if (spec->no_auto_mic) + if (!(spec->auto_mic & AUTO_MIC_PORTB)) return; present = snd_hda_jack_detect(codec, 0x17); snd_hda_codec_write(codec, 0x14, 0, @@ -1641,7 +1643,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) unsigned int present; hda_nid_t new_adc; - if (spec->no_auto_mic) + if (!(spec->auto_mic & AUTO_MIC_PORTC)) return; present = snd_hda_jack_detect(codec, 0x18); if (present) @@ -1757,6 +1759,24 @@ static struct snd_kcontrol_new cxt5051_f700_mixers[] = { {} }; +static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { + HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = cxt_eapd_info, + .get = cxt_eapd_get, + .put = cxt5051_hp_master_sw_put, + .private_value = 0x1a, + }, + + {} +}; + static struct hda_verb cxt5051_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, @@ -1893,6 +1913,7 @@ enum { CXT5051_HP_DV6736, /* HP without mic switch */ CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ CXT5051_F700, /* HP Compaq Presario F700 */ + CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_MODELS }; @@ -1902,12 +1923,14 @@ static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_HP_DV6736] = "hp-dv6736", [CXT5051_LENOVO_X200] = "lenovo-x200", [CXT5051_F700] = "hp-700", + [CXT5051_TOSHIBA] = "toshiba", }; static struct snd_pci_quirk cxt5051_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), + SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), @@ -1950,6 +1973,7 @@ static int patch_cxt5051(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, cxt5051_models, cxt5051_cfg_tbl); + spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; switch (board_config) { case CXT5051_HP: spec->mixers[0] = cxt5051_hp_mixers; @@ -1957,7 +1981,7 @@ static int patch_cxt5051(struct hda_codec *codec) case CXT5051_HP_DV6736: spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; spec->mixers[0] = cxt5051_hp_dv6736_mixers; - spec->no_auto_mic = 1; + spec->auto_mic = 0; break; case CXT5051_LENOVO_X200: spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; @@ -1965,7 +1989,11 @@ static int patch_cxt5051(struct hda_codec *codec) case CXT5051_F700: spec->init_verbs[0] = cxt5051_f700_init_verbs; spec->mixers[0] = cxt5051_f700_mixers; - spec->no_auto_mic = 1; + spec->auto_mic = 0; + break; + case CXT5051_TOSHIBA: + spec->mixers[0] = cxt5051_toshiba_mixers; + spec->auto_mic = AUTO_MIC_PORTB; break; } -- GitLab From 2c7a3fb3f81df7318c70d2b8ecbd87f008e28d52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 24 Jan 2010 10:47:02 +0100 Subject: [PATCH 1137/3892] ALSA: hda - Merge playback controls for Cx5051 codec models All cx5051 codec models have the same Master playback mixer definitions. Merge them together. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 62 +++++++--------------------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 56dda9c7f899..e24bec6ca23a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1689,13 +1689,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, conexant_report_jack(codec, nid); } -static struct snd_kcontrol_new cxt5051_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), +static struct snd_kcontrol_new cxt5051_playback_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1705,7 +1699,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = { .put = cxt5051_hp_master_sw_put, .private_value = 0x1a, }, + {} +}; +static struct snd_kcontrol_new cxt5051_capture_mixers[] = { + HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), {} }; @@ -1714,48 +1717,18 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} }; static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} }; static struct snd_kcontrol_new cxt5051_f700_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} }; @@ -1764,16 +1737,6 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} }; @@ -1958,8 +1921,9 @@ static int patch_cxt5051(struct hda_codec *codec) spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ spec->adc_nids = cxt5051_adc_nids; - spec->num_mixers = 1; - spec->mixers[0] = cxt5051_mixers; + spec->num_mixers = 2; + spec->mixers[0] = cxt5051_capture_mixers; + spec->mixers[1] = cxt5051_playback_mixers; spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5051_init_verbs; spec->spdif_route = 0; -- GitLab From 6953e5524a2ee0dcf57a83d8a6728d1262c54c37 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 24 Jan 2010 11:00:27 +0100 Subject: [PATCH 1138/3892] ALSA: hda - initialize mic port on cxt5051 codec dynamically Initialize the mic ports B & C on Conexant 5051 codec dynamically according to the mic jack detection, instead of static init arrays. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e24bec6ca23a..4fbb398ccd67 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1765,8 +1765,6 @@ static struct hda_verb cxt5051_init_verbs[] = { /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, { } /* end */ }; @@ -1792,7 +1790,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, { } /* end */ }; @@ -1824,8 +1821,6 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, { } /* end */ }; @@ -1852,15 +1847,34 @@ static struct hda_verb cxt5051_f700_init_verbs[] = { /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, { } /* end */ }; +static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, + unsigned int event) +{ + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | event); +#ifdef CONFIG_SND_HDA_INPUT_JACK + conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); + conexant_report_jack(codec, nid); +#endif +} + /* initialize jack-sensing, too */ static int cxt5051_init(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; + conexant_init(codec); conexant_init_jacks(codec); + + if (spec->auto_mic & AUTO_MIC_PORTB) + cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); + if (spec->auto_mic & AUTO_MIC_PORTC) + cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); + if (codec->patch_ops.unsol_event) { cxt5051_hp_automute(codec); cxt5051_portb_automic(codec); -- GitLab From ecda0cff9df77d3f7d388bd4966e61f1947d2c95 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 24 Jan 2010 11:14:36 +0100 Subject: [PATCH 1139/3892] ALSA: hda - Fix SPDIF output widget for Cxt5051 codec Fixed the wrongly set up for SPDIF output on Conexant 5051 codec. It must point to the audio out widget instead of a pin. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4fbb398ccd67..250b74f8136e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -42,7 +42,7 @@ /* Conexant 5051 specific */ -#define CXT5051_SPDIF_OUT 0x1C +#define CXT5051_SPDIF_OUT 0x12 #define CXT5051_PORTB_EVENT 0x38 #define CXT5051_PORTC_EVENT 0x39 -- GitLab From 23d2df5b0db67fa90d3caf4b2d2f21ca33ec9c11 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 24 Jan 2010 11:19:27 +0100 Subject: [PATCH 1140/3892] ALSA: hda - Change headphone pin control with master volume on cx5051 The HP pin (0x16) control has to be changed dynamically depending on the master volume switch as well as the speaker pin (0x1a). Otherwise the headphone still sounds with master off. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 250b74f8136e..9077e4174ee6 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1605,6 +1605,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; unsigned int pinctl; + /* headphone pin */ + pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); + /* speaker pin */ pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); -- GitLab From 3970dd8c5169505f0cc5e4c3e2fde7bdd9bbad3e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Jan 2010 23:19:45 +0100 Subject: [PATCH 1141/3892] pcmcia: do not lock socket driver module on card insert Do not lock the socket driver module on card insert, as the PCMCIA core can handle a socket module removal, at least if we add a call to socket_remove() on pccardd()'s shutdown. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 13 ++++++++++--- drivers/pcmcia/cs_internal.h | 20 -------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f0630a61da90..137a5db2eca2 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -407,7 +407,7 @@ static void socket_shutdown(struct pcmcia_socket *s) "*** DANGER *** unable to remove socket power\n"); } - cs_socket_put(s); + s->state &= ~SOCKET_INUSE; } static int socket_setup(struct pcmcia_socket *skt, int initial_delay) @@ -496,8 +496,8 @@ static int socket_insert(struct pcmcia_socket *skt) dev_dbg(&skt->dev, "insert\n"); - if (!cs_socket_get(skt)) - return -ENODEV; + WARN_ON(skt->state & SOCKET_INUSE); + skt->state |= SOCKET_INUSE; ret = socket_setup(skt, setup_delay); if (ret == 0) { @@ -697,6 +697,13 @@ static int pccardd(void *__skt) /* make sure we are running before we exit */ set_current_state(TASK_RUNNING); + /* shut down socket, if a device is still present */ + if (skt->state & SOCKET_PRESENT) { + mutex_lock(&skt->skt_mutex); + socket_remove(skt); + mutex_unlock(&skt->skt_mutex); + } + /* remove from the device core */ pccard_sysfs_remove_socket(&skt->dev); device_unregister(&skt->dev); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 3bc02d53a3a3..9a3bbad7761b 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -87,26 +87,6 @@ struct pccard_resource_ops { #define SOCKET_CARDBUS 0x8000 #define SOCKET_CARDBUS_CONFIG 0x10000 -static inline int cs_socket_get(struct pcmcia_socket *skt) -{ - int ret; - - WARN_ON(skt->state & SOCKET_INUSE); - - ret = try_module_get(skt->owner); - if (ret) - skt->state |= SOCKET_INUSE; - return ret; -} - -static inline void cs_socket_put(struct pcmcia_socket *skt) -{ - if (skt->state & SOCKET_INUSE) { - skt->state &= ~SOCKET_INUSE; - module_put(skt->owner); - } -} - /* * Stuff internal to module "pcmcia_core": -- GitLab From 385ee871092a524869c71a8180888aadcd6ca36d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 11:23:58 +0100 Subject: [PATCH 1142/3892] pcmcia: remove useless indirection As release_resoure_db() used to be called only from one place, and it's a two-line function, remove it. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 3 ++- drivers/pcmcia/cs_internal.h | 3 --- drivers/pcmcia/rsrc_mgr.c | 6 ------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 137a5db2eca2..43c90f69a7a5 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -283,7 +283,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) up_write(&pcmcia_socket_list_rwsem); /* wait for sysfs to drop all references */ - release_resource_db(socket); + if (socket->resource_ops->exit) + socket->resource_ops->exit(socket); wait_for_completion(&socket->socket_released); } /* pcmcia_unregister_socket */ EXPORT_SYMBOL(pcmcia_unregister_socket); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 9a3bbad7761b..7f86d09a5830 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -95,9 +95,6 @@ struct pccard_resource_ops { /* cistpl.c */ int verify_cis_cache(struct pcmcia_socket *s); -/* rsrc_mgr.c */ -void release_resource_db(struct pcmcia_socket *s); - /* socket_sysfs.c */ extern int pccard_sysfs_add_socket(struct device *dev); extern void pccard_sysfs_remove_socket(struct device *dev); diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 52db17263d8b..66c780073cd2 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -58,12 +58,6 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, } EXPORT_SYMBOL(pcmcia_find_mem_region); -void release_resource_db(struct pcmcia_socket *s) -{ - if (s->resource_ops->exit) - s->resource_ops->exit(s); -} - static int static_init(struct pcmcia_socket *s) { -- GitLab From f9c316f4a2d32e4d03497ecb24e1d2309361a5b8 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 11:32:22 +0100 Subject: [PATCH 1143/3892] pcmcia: remove some rsrc_mgr indirections Remove rsrc_mgr indirections only used by pcmcia_resource.c Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 8 -------- drivers/pcmcia/pcmcia_resource.c | 17 +++++++++++++++++ drivers/pcmcia/rsrc_mgr.c | 18 ------------------ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7f86d09a5830..ad05e3b59473 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -168,14 +168,6 @@ int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); /* rsrc_mgr.c */ int pcmcia_validate_mem(struct pcmcia_socket *s); -struct resource *pcmcia_find_io_region(unsigned long base, - int num, - unsigned long align, - struct pcmcia_socket *s); -int pcmcia_adjust_io_region(struct resource *res, - unsigned long r_start, - unsigned long r_end, - struct pcmcia_socket *s); struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index d5db95644b64..880b0b63b6a3 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -43,6 +43,23 @@ module_param(io_speed, int, 0444); static u8 pcmcia_used_irq[NR_IRQS]; #endif +static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, + unsigned long end, struct pcmcia_socket *s) +{ + if (s->resource_ops->adjust_io_region) + return s->resource_ops->adjust_io_region(res, start, end, s); + return -ENOMEM; +} + +static struct resource *pcmcia_find_io_region(unsigned long base, int num, + unsigned long align, + struct pcmcia_socket *s) +{ + if (s->resource_ops->find_io) + return s->resource_ops->find_io(base, num, align, s); + return NULL; +} + /** alloc_io_space * diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 66c780073cd2..81540c420bbd 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -31,24 +31,6 @@ int pcmcia_validate_mem(struct pcmcia_socket *s) } EXPORT_SYMBOL(pcmcia_validate_mem); -int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, - unsigned long r_end, struct pcmcia_socket *s) -{ - if (s->resource_ops->adjust_io_region) - return s->resource_ops->adjust_io_region(res, r_start, r_end, s); - return -ENOMEM; -} -EXPORT_SYMBOL(pcmcia_adjust_io_region); - -struct resource *pcmcia_find_io_region(unsigned long base, int num, - unsigned long align, struct pcmcia_socket *s) -{ - if (s->resource_ops->find_io) - return s->resource_ops->find_io(base, num, align, s); - return NULL; -} -EXPORT_SYMBOL(pcmcia_find_io_region); - struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { -- GitLab From a7eb169dc7292979d78f2d2f1655026ae3a9ff5f Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 6 Jan 2010 12:18:13 +0100 Subject: [PATCH 1144/3892] pcmcia: m32r uses static socket resources m32r_cfc sets the socket capabilities to SS_CAP_STATIC_MAP and also sets io_offset != 0. This means no calls to &pccard_nonstatic_ops went through. Therfore, replace it with &pccard_static_ops which is exactly for this case. CC: Mamoru Sakugawa CC: Hirokazu Takata Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 2 -- drivers/pcmcia/m32r_cfc.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 9f3adbd9f700..7e9fd38e14fb 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -238,14 +238,12 @@ config PCMCIA_PROBE config M32R_PCC bool "M32R PCMCIA I/F" depends on M32R && CHIP_M32700 && PCMCIA - select PCCARD_NONSTATIC help Say Y here to use the M32R PCMCIA controller. config M32R_CFC bool "M32R CF I/F Controller" depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT) - select PCCARD_NONSTATIC help Say Y here to use the M32R CompactFlash controller. diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 26a621c9e2fc..0ece2cd4a85e 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -764,7 +764,7 @@ static int __init init_m32r_pcc(void) for (i = 0 ; i < pcc_sockets ; i++) { socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; - socket[i].socket.resource_ops = &pccard_nonstatic_ops; + socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); -- GitLab From ce841b945b84bf7360aa32e60ddaa1e9ccae3e96 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 21 Jan 2010 23:52:37 -0800 Subject: [PATCH 1145/3892] Input: xilinx_ps2 - use resource_size Use the resource_size inline function instead of manually calculating the resource size. Signed-off-by: Tobias Klauser Acked-by: John Linn Signed-off-by: Dmitry Torokhov --- drivers/input/serio/xilinx_ps2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 78c64fb8a4b0..8298e1f68234 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -270,7 +270,7 @@ static int __devinit xps2_of_probe(struct of_device *ofdev, drvdata->irq = r_irq.start; phys_addr = r_mem.start; - remap_size = r_mem.end - r_mem.start + 1; + remap_size = resource_size(&r_mem); if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) { dev_err(dev, "Couldn't lock memory region at 0x%08llX\n", (unsigned long long)phys_addr); @@ -344,7 +344,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev) if (of_address_to_resource(of_dev->node, 0, &r_mem)) dev_err(dev, "invalid address\n"); else - release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1); + release_mem_region(r_mem.start, resource_size(&r_mem)); kfree(drvdata); -- GitLab From 121873059fbe3b4f1ddb4781b578a2128e78be4a Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 21 Jan 2010 20:19:06 -0800 Subject: [PATCH 1146/3892] Input: xpad - add rumble support for original xbox controller Signed-off-by: Benjamin Valentin Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 53 ++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 66be6901619d..9b3353b404da 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -530,7 +530,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) struct usb_endpoint_descriptor *ep_irq_out; int error = -ENOMEM; - if (xpad->xtype != XTYPE_XBOX360) + if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX) return 0; xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN, @@ -560,13 +560,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) static void xpad_stop_output(struct usb_xpad *xpad) { - if (xpad->xtype == XTYPE_XBOX360) + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) usb_kill_urb(xpad->irq_out); } static void xpad_deinit_output(struct usb_xpad *xpad) { - if (xpad->xtype == XTYPE_XBOX360) { + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) { usb_free_urb(xpad->irq_out); usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); @@ -579,24 +579,45 @@ static void xpad_stop_output(struct usb_xpad *xpad) {} #endif #ifdef CONFIG_JOYSTICK_XPAD_FF -static int xpad_play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) +static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { struct usb_xpad *xpad = input_get_drvdata(dev); if (effect->type == FF_RUMBLE) { __u16 strong = effect->u.rumble.strong_magnitude; __u16 weak = effect->u.rumble.weak_magnitude; - xpad->odata[0] = 0x00; - xpad->odata[1] = 0x08; - xpad->odata[2] = 0x00; - xpad->odata[3] = strong / 256; - xpad->odata[4] = weak / 256; - xpad->odata[5] = 0x00; - xpad->odata[6] = 0x00; - xpad->odata[7] = 0x00; - xpad->irq_out->transfer_buffer_length = 8; - usb_submit_urb(xpad->irq_out, GFP_ATOMIC); + + switch (xpad->xtype) { + + case XTYPE_XBOX: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x06; + xpad->odata[2] = 0x00; + xpad->odata[3] = strong / 256; /* left actuator */ + xpad->odata[4] = 0x00; + xpad->odata[5] = weak / 256; /* right actuator */ + xpad->irq_out->transfer_buffer_length = 6; + + return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); + + case XTYPE_XBOX360: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x08; + xpad->odata[2] = 0x00; + xpad->odata[3] = strong / 256; /* left actuator? */ + xpad->odata[4] = weak / 256; /* right actuator? */ + xpad->odata[5] = 0x00; + xpad->odata[6] = 0x00; + xpad->odata[7] = 0x00; + xpad->irq_out->transfer_buffer_length = 8; + + return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); + + default: + dbg("%s - rumble command sent to unsupported xpad type: %d", + __func__, xpad->xtype); + return -1; + } } return 0; @@ -604,7 +625,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, static int xpad_init_ff(struct usb_xpad *xpad) { - if (xpad->xtype != XTYPE_XBOX360) + if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX) return 0; input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); -- GitLab From 95f475f7a2e5d60fe9eeb7a2700753036a6ee6a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Jan 2010 15:41:11 +0100 Subject: [PATCH 1147/3892] ALSA: hda - Remove coef output in Realtek proc files The output of COEF index/value in the proc file for Realtek codecs is rather useless since the value varies together with the index. Let's get rid of it again. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c53faa959390..a3d223894642 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -841,27 +841,6 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) spec->init_verbs[spec->num_init_verbs++] = verb; } -#ifdef CONFIG_PROC_FS -/* - * hook for proc - */ -static void print_realtek_coef(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - int coeff; - - if (nid != 0x20) - return; - coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); - snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); - coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_COEF_INDEX, 0); - snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); -} -#else -#define print_realtek_coef NULL -#endif - /* * set up from the preset table */ @@ -5078,7 +5057,6 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc880_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -6688,7 +6666,6 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -10306,7 +10283,6 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc882_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -12170,7 +12146,6 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc262_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -13237,8 +13212,6 @@ static int patch_alc268(struct hda_codec *codec) if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; - codec->proc_widget_hook = print_realtek_coef; - return 0; } @@ -13955,7 +13928,6 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -15083,7 +15055,6 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -16063,7 +16034,6 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -18198,7 +18168,6 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc662_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } -- GitLab From 0aea778efa0d632b62eb35122cbb3b9fae548c61 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Jan 2010 15:44:11 +0100 Subject: [PATCH 1148/3892] ALSA: hda - Remove the COEF setup for ALC267/ALC268 The COEF setup for model=auto seems problematic on some laptops, resulting in the silent speaker output. Better to disable it for now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a3d223894642..b2f543d3b833 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1145,6 +1145,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0888: alc888_coef_init(codec); break; +#if 0 /* XXX: This may cause the silent output on speaker on some machines */ case 0x10ec0267: case 0x10ec0268: snd_hda_codec_write(codec, 0x20, 0, @@ -1157,6 +1158,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) AC_VERB_SET_PROC_COEF, tmp | 0x3000); break; +#endif /* XXX */ } break; } -- GitLab From 8484c63f4b363d79febe35f95328e38018b65026 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Jan 2010 21:10:47 +0100 Subject: [PATCH 1149/3892] ASoC: add simplified versions of widget macros Many macros from include/sound/soc-dapm.h take an array and a number of elements in it as arguments, whereas most users use static arrays and use "x, ARRAY_SIZE(x)" as arguments. This patch adds simplified versions of those macros, calling ARRAY_SIZE() internally. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c5c95e1da65b..c0922a034223 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -95,6 +95,21 @@ .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ .num_kcontrols = 1} +/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ +#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ + wcontrols) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} +#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ + wcontrols)\ +{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} +#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ + wcontrols)\ +{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ + .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ + .num_kcontrols = ARRAY_SIZE(wcontrols)} + /* path domain with event - event handler must return 0 for success */ #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ @@ -126,6 +141,23 @@ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} +/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ +#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ + wevent, wflags) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ + .event = wevent, .event_flags = wflags} +#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ + wevent, wflags) \ +{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ + .event = wevent, .event_flags = wflags} +#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ + wcontrols, wevent, wflags) \ +{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ + .invert = winvert, .kcontrols = wcontrols, \ + .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags} + /* events that are pre and post DAPM */ #define SND_SOC_DAPM_PRE(wname, wevent) \ { .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ -- GitLab From 6c2fb6a8d8c43544e7665859f29373c98d17df75 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Jan 2010 22:04:03 +0100 Subject: [PATCH 1150/3892] ASoC: add helper macros to declare struct soc_enum instances Several shortcuts for popular uses of some of SOC_ENUM_* and SOC_VALUE_ENUM_* macros. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index a8768ea7571a..4bbeb9f83ece 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -168,6 +168,23 @@ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&xenum } +/* + * Simplified versions of above macros, declaring a struct and calculating + * ARRAY_SIZE internally + */ +#define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ + struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ + ARRAY_SIZE(xtexts), xtexts) +#define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ + SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) +#define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ + struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) +#define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ + struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ + ARRAY_SIZE(xtexts), xtexts, xvalues) +#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ + SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) + /* * Bias levels * -- GitLab From 895d4509d069f0706427ca75fcf0929ed136d0d7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Jan 2010 19:09:03 +0100 Subject: [PATCH 1151/3892] ASoC: add DAI and platform / DMA drivers for SH SIU Several SuperH platforms, including sh7722, sh7343, sh7354, sh7367 include a Sound Interface Unit (SIU). This patch adds DAI and platform / DMA drivers for this interface. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/sh/include/asm/siu.h | 26 ++ sound/soc/sh/Kconfig | 6 + sound/soc/sh/Makefile | 2 + sound/soc/sh/siu.h | 193 +++++++++ sound/soc/sh/siu_dai.c | 847 ++++++++++++++++++++++++++++++++++++++ sound/soc/sh/siu_pcm.c | 616 +++++++++++++++++++++++++++ 6 files changed, 1690 insertions(+) create mode 100644 arch/sh/include/asm/siu.h create mode 100644 sound/soc/sh/siu.h create mode 100644 sound/soc/sh/siu_dai.c create mode 100644 sound/soc/sh/siu_pcm.c diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h new file mode 100644 index 000000000000..57565a3b551f --- /dev/null +++ b/arch/sh/include/asm/siu.h @@ -0,0 +1,26 @@ +/* + * platform header for the SIU ASoC driver + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ASM_SIU_H +#define ASM_SIU_H + +#include + +struct device; + +struct siu_platform { + struct device *dma_dev; + enum sh_dmae_slave_chan_id dma_slave_tx_a; + enum sh_dmae_slave_chan_id dma_slave_rx_a; + enum sh_dmae_slave_chan_id dma_slave_tx_b; + enum sh_dmae_slave_chan_id dma_slave_rx_b; +}; + +#endif /* ASM_SIU_H */ diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 8072a6d1c4db..3f1cd5503342 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -26,6 +26,12 @@ config SND_SOC_SH4_FSI help This option enables FSI sound support +config SND_SOC_SH4_SIU + tristate + depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + select DMADEVICES + select SH_DMAE + ## ## Boards ## diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index 1d0ec0af74b7..5a97d2539d84 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -6,9 +6,11 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o snd-soc-hac-objs := hac.o snd-soc-ssi-objs := ssi.o snd-soc-fsi-objs := fsi.o +snd-soc-siu-objs := siu_pcm.o siu_dai.o obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o +obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o ## boards snd-soc-sh7760-ac97-objs := sh7760-ac97.o diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h new file mode 100644 index 000000000000..9cc04ab2bce7 --- /dev/null +++ b/sound/soc/sh/siu.h @@ -0,0 +1,193 @@ +/* + * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * Copyright (C) 2006 Carlos Munoz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef SIU_H +#define SIU_H + +/* Common kernel and user-space firmware-building defines and types */ + +#define YRAM0_SIZE (0x0040 / 4) /* 16 */ +#define YRAM1_SIZE (0x0080 / 4) /* 32 */ +#define YRAM2_SIZE (0x0040 / 4) /* 16 */ +#define YRAM3_SIZE (0x0080 / 4) /* 32 */ +#define YRAM4_SIZE (0x0080 / 4) /* 32 */ +#define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \ + YRAM3_SIZE + YRAM4_SIZE) +#define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */ +#define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */ + +#define XRAM0_SIZE (0x0400 / 4) /* 256 */ +#define XRAM1_SIZE (0x0200 / 4) /* 128 */ +#define XRAM2_SIZE (0x0200 / 4) /* 128 */ + +/* PRAM program array size */ +#define PRAM0_SIZE (0x0100 / 4) /* 64 */ +#define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */ + +#include + +struct siu_spb_param { + __u32 ab1a; /* input FIFO address */ + __u32 ab0a; /* output FIFO address */ + __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */ + __u32 event; /* SPB program starting conditions */ + __u32 stfifo; /* STFIFO register setting value */ + __u32 trdat; /* TRDAT register setting value */ +}; + +struct siu_firmware { + __u32 yram_fir_coeff[YRAM_FIR_SIZE]; + __u32 pram0[PRAM0_SIZE]; + __u32 pram1[PRAM1_SIZE]; + __u32 yram0[YRAM0_SIZE]; + __u32 yram1[YRAM1_SIZE]; + __u32 yram2[YRAM2_SIZE]; + __u32 yram3[YRAM3_SIZE]; + __u32 yram4[YRAM4_SIZE]; + __u32 spbpar_num; + struct siu_spb_param spbpar[32]; +}; + +#ifdef __KERNEL__ + +#include +#include +#include + +#include + +#include +#include +#include + +#define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */ +#define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */ +#define SIU_PERIODS_MAX 64 /* Max periods in buffer */ +#define SIU_PERIODS_MIN 4 /* Min periods in buffer */ +#define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX) + +/* SIU ports: only one can be used at a time */ +enum { + SIU_PORT_A, + SIU_PORT_B, + SIU_PORT_NUM, +}; + +/* SIU clock configuration */ +enum { + SIU_CLKA_PLL, + SIU_CLKA_EXT, + SIU_CLKB_PLL, + SIU_CLKB_EXT +}; + +struct siu_info { + int port_id; + u32 __iomem *pram; + u32 __iomem *xram; + u32 __iomem *yram; + u32 __iomem *reg; + struct siu_firmware fw; +}; + +struct siu_stream { + struct tasklet_struct tasklet; + struct snd_pcm_substream *substream; + snd_pcm_format_t format; + size_t buf_bytes; + size_t period_bytes; + int cur_period; /* Period currently in dma */ + u32 volume; + snd_pcm_sframes_t xfer_cnt; /* Number of frames */ + u8 rw_flg; /* transfer status */ + /* DMA status */ + struct dma_chan *chan; /* DMA channel */ + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t cookie; + struct sh_dmae_slave param; +}; + +struct siu_port { + unsigned long play_cap; /* Used to track full duplex */ + struct snd_pcm *pcm; + struct siu_stream playback; + struct siu_stream capture; + u32 stfifo; /* STFIFO value from firmware */ + u32 trdat; /* TRDAT value from firmware */ +}; + +extern struct siu_port *siu_ports[SIU_PORT_NUM]; + +static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream) +{ + struct platform_device *pdev = + to_platform_device(substream->pcm->card->dev); + return siu_ports[pdev->id]; +} + +/* Register access */ +static inline void siu_write32(u32 __iomem *addr, u32 val) +{ + __raw_writel(val, addr); +} + +static inline u32 siu_read32(u32 __iomem *addr) +{ + return __raw_readl(addr); +} + +/* SIU registers */ +#define SIU_IFCTL (0x000 / sizeof(u32)) +#define SIU_SRCTL (0x004 / sizeof(u32)) +#define SIU_SFORM (0x008 / sizeof(u32)) +#define SIU_CKCTL (0x00c / sizeof(u32)) +#define SIU_TRDAT (0x010 / sizeof(u32)) +#define SIU_STFIFO (0x014 / sizeof(u32)) +#define SIU_DPAK (0x01c / sizeof(u32)) +#define SIU_CKREV (0x020 / sizeof(u32)) +#define SIU_EVNTC (0x028 / sizeof(u32)) +#define SIU_SBCTL (0x040 / sizeof(u32)) +#define SIU_SBPSET (0x044 / sizeof(u32)) +#define SIU_SBFSTS (0x068 / sizeof(u32)) +#define SIU_SBDVCA (0x06c / sizeof(u32)) +#define SIU_SBDVCB (0x070 / sizeof(u32)) +#define SIU_SBACTIV (0x074 / sizeof(u32)) +#define SIU_DMAIA (0x090 / sizeof(u32)) +#define SIU_DMAIB (0x094 / sizeof(u32)) +#define SIU_DMAOA (0x098 / sizeof(u32)) +#define SIU_DMAOB (0x09c / sizeof(u32)) +#define SIU_DMAML (0x0a0 / sizeof(u32)) +#define SIU_SPSTS (0x0cc / sizeof(u32)) +#define SIU_SPCTL (0x0d0 / sizeof(u32)) +#define SIU_BRGASEL (0x100 / sizeof(u32)) +#define SIU_BRRA (0x104 / sizeof(u32)) +#define SIU_BRGBSEL (0x108 / sizeof(u32)) +#define SIU_BRRB (0x10c / sizeof(u32)) + +extern struct snd_soc_platform siu_platform; +extern struct snd_soc_dai siu_i2s_dai; + +int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card); +void siu_free_port(struct siu_port *port_info); + +#endif + +#endif /* SIU_H */ diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c new file mode 100644 index 000000000000..5452d19607e1 --- /dev/null +++ b/sound/soc/sh/siu_dai.c @@ -0,0 +1,847 @@ +/* + * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * Copyright (C) 2006 Carlos Munoz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "siu.h" + +/* Board specifics */ +#if defined(CONFIG_CPU_SUBTYPE_SH7722) +# define SIU_MAX_VOLUME 0x1000 +#else +# define SIU_MAX_VOLUME 0x7fff +#endif + +#define PRAM_SIZE 0x2000 +#define XRAM_SIZE 0x800 +#define YRAM_SIZE 0x800 + +#define XRAM_OFFSET 0x4000 +#define YRAM_OFFSET 0x6000 +#define REG_OFFSET 0xc000 + +#define PLAYBACK_ENABLED 1 +#define CAPTURE_ENABLED 2 + +#define VOLUME_CAPTURE 0 +#define VOLUME_PLAYBACK 1 +#define DFLT_VOLUME_LEVEL 0x08000800 + +/* + * SPDIF is only available on port A and on some SIU implementations it is only + * available for input. Due to the lack of hardware to test it, SPDIF is left + * disabled in this driver version + */ +struct format_flag { + u32 i2s; + u32 pcm; + u32 spdif; + u32 mask; +}; + +struct port_flag { + struct format_flag playback; + struct format_flag capture; +}; + +static struct port_flag siu_flags[SIU_PORT_NUM] = { + [SIU_PORT_A] = { + .playback = { + .i2s = 0x50000000, + .pcm = 0x40000000, + .spdif = 0x80000000, /* not on all SIU versions */ + .mask = 0xd0000000, + }, + .capture = { + .i2s = 0x05000000, + .pcm = 0x04000000, + .spdif = 0x08000000, + .mask = 0x0d000000, + }, + }, + [SIU_PORT_B] = { + .playback = { + .i2s = 0x00500000, + .pcm = 0x00400000, + .spdif = 0, /* impossible - turn off */ + .mask = 0x00500000, + }, + .capture = { + .i2s = 0x00050000, + .pcm = 0x00040000, + .spdif = 0, /* impossible - turn off */ + .mask = 0x00050000, + }, + }, +}; + +static void siu_dai_start(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + + dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); + + /* Turn on SIU clock */ + pm_runtime_get_sync(siu_i2s_dai.dev); + + /* Issue software reset to siu */ + siu_write32(base + SIU_SRCTL, 0); + + /* Wait for the reset to take effect */ + udelay(1); + + port_info->stfifo = 0; + port_info->trdat = 0; + + /* portA, portB, SIU operate */ + siu_write32(base + SIU_SRCTL, 0x301); + + /* portA=256fs, portB=256fs */ + siu_write32(base + SIU_CKCTL, 0x40400000); + + /* portA's BRG does not divide SIUCKA */ + siu_write32(base + SIU_BRGASEL, 0); + siu_write32(base + SIU_BRRA, 0); + + /* portB's BRG divides SIUCKB by half */ + siu_write32(base + SIU_BRGBSEL, 1); + siu_write32(base + SIU_BRRB, 0); + + siu_write32(base + SIU_IFCTL, 0x44440000); + + /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */ + siu_write32(base + SIU_SFORM, 0x0c0c0000); + + /* + * Volume levels: looks like the DSP firmware implements volume controls + * differently from what's described in the datasheet + */ + siu_write32(base + SIU_SBDVCA, port_info->playback.volume); + siu_write32(base + SIU_SBDVCB, port_info->capture.volume); +} + +static void siu_dai_stop(void) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + + /* SIU software reset */ + siu_write32(base + SIU_SRCTL, 0); + + /* Turn off SIU clock */ + pm_runtime_put_sync(siu_i2s_dai.dev); +} + +static void siu_dai_spbAselect(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + u32 idx; + + /* path A use */ + if (!info->port_id) + idx = 1; /* portA */ + else + idx = 2; /* portB */ + + ydef[0] = (fw->spbpar[idx].ab1a << 16) | + (fw->spbpar[idx].ab0a << 8) | + (fw->spbpar[idx].dir << 7) | 3; + ydef[1] = fw->yram0[1]; /* 0x03000300 */ + ydef[2] = (16 / 2) << 24; + ydef[3] = fw->yram0[3]; /* 0 */ + ydef[4] = fw->yram0[4]; /* 0 */ + ydef[7] = fw->spbpar[idx].event; + port_info->stfifo |= fw->spbpar[idx].stfifo; + port_info->trdat |= fw->spbpar[idx].trdat; +} + +static void siu_dai_spbBselect(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + u32 idx; + + /* path B use */ + if (!info->port_id) + idx = 7; /* portA */ + else + idx = 8; /* portB */ + + ydef[5] = (fw->spbpar[idx].ab1a << 16) | + (fw->spbpar[idx].ab0a << 8) | 1; + ydef[6] = fw->spbpar[idx].event; + port_info->stfifo |= fw->spbpar[idx].stfifo; + port_info->trdat |= fw->spbpar[idx].trdat; +} + +static void siu_dai_open(struct siu_stream *siu_stream) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + u32 srctl, ifctl; + + srctl = siu_read32(base + SIU_SRCTL); + ifctl = siu_read32(base + SIU_IFCTL); + + switch (info->port_id) { + case SIU_PORT_A: + /* portA operates */ + srctl |= 0x200; + ifctl &= ~0xc2; + break; + case SIU_PORT_B: + /* portB operates */ + srctl |= 0x100; + ifctl &= ~0x31; + break; + } + + siu_write32(base + SIU_SRCTL, srctl); + /* Unmute and configure portA */ + siu_write32(base + SIU_IFCTL, ifctl); +} + +/* + * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower + * packing is supported + */ +static void siu_dai_pcmdatapack(struct siu_stream *siu_stream) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + u32 dpak; + + dpak = siu_read32(base + SIU_DPAK); + + switch (info->port_id) { + case SIU_PORT_A: + dpak &= ~0xc0000000; + break; + case SIU_PORT_B: + dpak &= ~0x00c00000; + break; + } + + siu_write32(base + SIU_DPAK, dpak); +} + +static int siu_dai_spbstart(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + int cnt; + u32 __iomem *add; + u32 *ptr; + + /* Load SPB Program in PRAM */ + ptr = fw->pram0; + add = info->pram; + for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++) + siu_write32(add, *ptr); + + ptr = fw->pram1; + add = info->pram + (0x0100 / sizeof(u32)); + for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++) + siu_write32(add, *ptr); + + /* XRAM initialization */ + add = info->xram; + for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++) + siu_write32(add, 0); + + /* YRAM variable area initialization */ + add = info->yram; + for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++) + siu_write32(add, ydef[cnt]); + + /* YRAM FIR coefficient area initialization */ + add = info->yram + (0x0200 / sizeof(u32)); + for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++) + siu_write32(add, fw->yram_fir_coeff[cnt]); + + /* YRAM IIR coefficient area initialization */ + add = info->yram + (0x0600 / sizeof(u32)); + for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++) + siu_write32(add, 0); + + siu_write32(base + SIU_TRDAT, port_info->trdat); + port_info->trdat = 0x0; + + + /* SPB start condition: software */ + siu_write32(base + SIU_SBACTIV, 0); + /* Start SPB */ + siu_write32(base + SIU_SBCTL, 0xc0000000); + /* Wait for program to halt */ + cnt = 0x10000; + while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000) + cpu_relax(); + + if (!cnt) + return -EBUSY; + + /* SPB program start address setting */ + siu_write32(base + SIU_SBPSET, 0x00400000); + /* SPB hardware start(FIFOCTL source) */ + siu_write32(base + SIU_SBACTIV, 0xc0000000); + + return 0; +} + +static void siu_dai_spbstop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + + siu_write32(base + SIU_SBACTIV, 0); + /* SPB stop */ + siu_write32(base + SIU_SBCTL, 0); + + port_info->stfifo = 0; +} + +/* API functions */ + +/* Playback and capture hardware properties are identical */ +static struct snd_pcm_hardware siu_dai_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = SIU_BUFFER_BYTES_MAX, + .period_bytes_min = SIU_PERIOD_BYTES_MIN, + .period_bytes_max = SIU_PERIOD_BYTES_MAX, + .periods_min = SIU_PERIODS_MIN, + .periods_max = SIU_PERIODS_MAX, +}; + +static int siu_dai_info_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_info *uinfo) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + + dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SIU_MAX_VOLUME; + + return 0; +} + +static int siu_dai_get_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + struct device *dev = port_info->pcm->card->dev; + u32 vol; + + dev_dbg(dev, "%s\n", __func__); + + switch (kctrl->private_value) { + case VOLUME_PLAYBACK: + /* Playback is always on port 0 */ + vol = port_info->playback.volume; + ucontrol->value.integer.value[0] = vol & 0xffff; + ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; + break; + case VOLUME_CAPTURE: + /* Capture is always on port 1 */ + vol = port_info->capture.volume; + ucontrol->value.integer.value[0] = vol & 0xffff; + ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; + break; + default: + dev_err(dev, "%s() invalid private_value=%ld\n", + __func__, kctrl->private_value); + return -EINVAL; + } + + return 0; +} + +static int siu_dai_put_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + struct device *dev = port_info->pcm->card->dev; + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + u32 new_vol; + u32 cur_vol; + + dev_dbg(dev, "%s\n", __func__); + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > SIU_MAX_VOLUME || + ucontrol->value.integer.value[1] < 0 || + ucontrol->value.integer.value[1] > SIU_MAX_VOLUME) + return -EINVAL; + + new_vol = ucontrol->value.integer.value[0] | + ucontrol->value.integer.value[1] << 16; + + /* See comment above - DSP firmware implementation */ + switch (kctrl->private_value) { + case VOLUME_PLAYBACK: + /* Playback is always on port 0 */ + cur_vol = port_info->playback.volume; + siu_write32(base + SIU_SBDVCA, new_vol); + port_info->playback.volume = new_vol; + break; + case VOLUME_CAPTURE: + /* Capture is always on port 1 */ + cur_vol = port_info->capture.volume; + siu_write32(base + SIU_SBDVCB, new_vol); + port_info->capture.volume = new_vol; + break; + default: + dev_err(dev, "%s() invalid private_value=%ld\n", + __func__, kctrl->private_value); + return -EINVAL; + } + + if (cur_vol != new_vol) + return 1; + + return 0; +} + +static struct snd_kcontrol_new playback_controls = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .index = 0, + .info = siu_dai_info_volume, + .get = siu_dai_get_volume, + .put = siu_dai_put_volume, + .private_value = VOLUME_PLAYBACK, +}; + +static struct snd_kcontrol_new capture_controls = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Capture Volume", + .index = 0, + .info = siu_dai_info_volume, + .get = siu_dai_get_volume, + .put = siu_dai_put_volume, + .private_value = VOLUME_CAPTURE, +}; + +int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card) +{ + struct device *dev = card->dev; + struct snd_kcontrol *kctrl; + int ret; + + *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL); + if (!*port_info) + return -ENOMEM; + + dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info); + + (*port_info)->playback.volume = DFLT_VOLUME_LEVEL; + (*port_info)->capture.volume = DFLT_VOLUME_LEVEL; + + /* + * Add mixer support. The SPB is used to change the volume. Both + * ports use the same SPB. Therefore, we only register one + * control instance since it will be used by both channels. + * In error case we continue without controls. + */ + kctrl = snd_ctl_new1(&playback_controls, *port_info); + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + dev_err(dev, + "failed to add playback controls %p port=%d err=%d\n", + kctrl, port, ret); + + kctrl = snd_ctl_new1(&capture_controls, *port_info); + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + dev_err(dev, + "failed to add capture controls %p port=%d err=%d\n", + kctrl, port, ret); + + return 0; +} + +void siu_free_port(struct siu_port *port_info) +{ + kfree(port_info); +} + +static int siu_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + int ret; + + dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, + info->port_id, port_info); + + snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw); + + ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); + if (unlikely(ret < 0)) + return ret; + + siu_dai_start(port_info); + + return 0; +} + +static void siu_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_port *port_info = siu_port_info(substream); + + dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, + info->port_id, port_info); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_info->play_cap &= ~PLAYBACK_ENABLED; + else + port_info->play_cap &= ~CAPTURE_ENABLED; + + /* Stop the siu if the other stream is not using it */ + if (!port_info->play_cap) { + /* during stmread or stmwrite ? */ + BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg); + siu_dai_spbstop(port_info); + siu_dai_stop(); + } +} + +/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */ +static int siu_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + struct siu_stream *siu_stream; + int self, ret; + + dev_dbg(substream->pcm->card->dev, + "%s: port %d, active streams %lx, %d channels\n", + __func__, info->port_id, port_info->play_cap, rt->channels); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + self = PLAYBACK_ENABLED; + siu_stream = &port_info->playback; + } else { + self = CAPTURE_ENABLED; + siu_stream = &port_info->capture; + } + + /* Set up the siu if not already done */ + if (!port_info->play_cap) { + siu_stream->rw_flg = 0; /* stream-data transfer flag */ + + siu_dai_spbAselect(port_info); + siu_dai_spbBselect(port_info); + + siu_dai_open(siu_stream); + + siu_dai_pcmdatapack(siu_stream); + + ret = siu_dai_spbstart(port_info); + if (ret < 0) + goto fail; + } + + port_info->play_cap |= self; + +fail: + return ret; +} + +/* + * SIU can set bus format to I2S / PCM / SPDIF independently for playback and + * capture, however, the current API sets the bus format globally for a DAI. + */ +static int siu_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + u32 ifctl; + + dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n", + __func__, fmt, info->port_id); + + if (info->port_id < 0) + return -ENODEV; + + /* Here select between I2S / PCM / SPDIF */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ifctl = siu_flags[info->port_id].playback.i2s | + siu_flags[info->port_id].capture.i2s; + break; + case SND_SOC_DAIFMT_LEFT_J: + ifctl = siu_flags[info->port_id].playback.pcm | + siu_flags[info->port_id].capture.pcm; + break; + /* SPDIF disabled - see comment at the top */ + default: + return -EINVAL; + } + + ifctl |= ~(siu_flags[info->port_id].playback.mask | + siu_flags[info->port_id].capture.mask) & + siu_read32(base + SIU_IFCTL); + siu_write32(base + SIU_IFCTL, ifctl); + + return 0; +} + +static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct clk *siu_clk, *parent_clk; + char *siu_name, *parent_name; + int ret; + + if (dir != SND_SOC_CLOCK_IN) + return -EINVAL; + + dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id); + + switch (clk_id) { + case SIU_CLKA_PLL: + siu_name = "siua_clk"; + parent_name = "pll_clk"; + break; + case SIU_CLKA_EXT: + siu_name = "siua_clk"; + parent_name = "siumcka_clk"; + break; + case SIU_CLKB_PLL: + siu_name = "siub_clk"; + parent_name = "pll_clk"; + break; + case SIU_CLKB_EXT: + siu_name = "siub_clk"; + parent_name = "siumckb_clk"; + break; + default: + return -EINVAL; + } + + siu_clk = clk_get(siu_i2s_dai.dev, siu_name); + if (IS_ERR(siu_clk)) + return PTR_ERR(siu_clk); + + parent_clk = clk_get(siu_i2s_dai.dev, parent_name); + if (!IS_ERR(parent_clk)) { + ret = clk_set_parent(siu_clk, parent_clk); + if (!ret) + clk_set_rate(siu_clk, freq); + clk_put(parent_clk); + } + + clk_put(siu_clk); + + return 0; +} + +static struct snd_soc_dai_ops siu_dai_ops = { + .startup = siu_dai_startup, + .shutdown = siu_dai_shutdown, + .prepare = siu_dai_prepare, + .set_sysclk = siu_dai_set_sysclk, + .set_fmt = siu_dai_set_fmt, +}; + +struct snd_soc_dai siu_i2s_dai = { + .name = "sh-siu", + .id = 0, + .playback = { + .channels_min = 2, + .channels_max = 2, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + }, + .ops = &siu_dai_ops, +}; +EXPORT_SYMBOL_GPL(siu_i2s_dai); + +static int __devinit siu_probe(struct platform_device *pdev) +{ + const struct firmware *fw_entry; + struct resource *res, *region; + struct siu_info *info; + int ret; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev); + if (ret) + goto ereqfw; + + /* + * Loaded firmware is "const" - read only, but we have to modify it in + * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect() + */ + memcpy(&info->fw, fw_entry->data, fw_entry->size); + + release_firmware(fw_entry); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto egetres; + } + + region = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!region) { + dev_err(&pdev->dev, "SIU region already claimed\n"); + ret = -EBUSY; + goto ereqmemreg; + } + + ret = -ENOMEM; + info->pram = ioremap(res->start, PRAM_SIZE); + if (!info->pram) + goto emappram; + info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE); + if (!info->xram) + goto emapxram; + info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE); + if (!info->yram) + goto emapyram; + info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) - + REG_OFFSET); + if (!info->reg) + goto emapreg; + + siu_i2s_dai.dev = &pdev->dev; + siu_i2s_dai.private_data = info; + + ret = snd_soc_register_dais(&siu_i2s_dai, 1); + if (ret < 0) + goto edaiinit; + + ret = snd_soc_register_platform(&siu_platform); + if (ret < 0) + goto esocregp; + + pm_runtime_enable(&pdev->dev); + + return ret; + +esocregp: + snd_soc_unregister_dais(&siu_i2s_dai, 1); +edaiinit: + iounmap(info->reg); +emapreg: + iounmap(info->yram); +emapyram: + iounmap(info->xram); +emapxram: + iounmap(info->pram); +emappram: + release_mem_region(res->start, resource_size(res)); +ereqmemreg: +egetres: +ereqfw: + kfree(info); + + return ret; +} + +static int __devexit siu_remove(struct platform_device *pdev) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct resource *res; + + pm_runtime_disable(&pdev->dev); + + snd_soc_unregister_platform(&siu_platform); + snd_soc_unregister_dais(&siu_i2s_dai, 1); + + iounmap(info->reg); + iounmap(info->yram); + iounmap(info->xram); + iounmap(info->pram); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + kfree(info); + + return 0; +} + +static struct platform_driver siu_driver = { + .driver = { + .name = "sh_siu", + }, + .probe = siu_probe, + .remove = __devexit_p(siu_remove), +}; + +static int __init siu_init(void) +{ + return platform_driver_register(&siu_driver); +} + +static void __exit siu_exit(void) +{ + platform_driver_unregister(&siu_driver); +} + +module_init(siu_init) +module_exit(siu_exit) + +MODULE_AUTHOR("Carlos Munoz "); +MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c new file mode 100644 index 000000000000..c5efc30f0136 --- /dev/null +++ b/sound/soc/sh/siu_pcm.c @@ -0,0 +1,616 @@ +/* + * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral. + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * Copyright (C) 2006 Carlos Munoz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "siu.h" + +#define GET_MAX_PERIODS(buf_bytes, period_bytes) \ + ((buf_bytes) / (period_bytes)) +#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \ + ((buf_addr) + ((period_num) * (period_bytes))) + +#define RWF_STM_RD 0x01 /* Read in progress */ +#define RWF_STM_WT 0x02 /* Write in progress */ + +struct siu_port *siu_ports[SIU_PORT_NUM]; + +/* transfersize is number of u32 dma transfers per period */ +static int siu_pcm_stmwrite_stop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->playback; + u32 stfifo; + + if (!siu_stream->rw_flg) + return -EPERM; + + /* output FIFO disable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18); + pr_debug("%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo & ~0x0c180c18); + + /* during stmwrite clear */ + siu_stream->rw_flg = 0; + + return 0; +} + +static int siu_pcm_stmwrite_start(struct siu_port *port_info) +{ + struct siu_stream *siu_stream = &port_info->playback; + + if (siu_stream->rw_flg) + return -EPERM; + + /* Current period in buffer */ + port_info->playback.cur_period = 0; + + /* during stmwrite flag set */ + siu_stream->rw_flg = RWF_STM_WT; + + /* DMA transfer start */ + tasklet_schedule(&siu_stream->tasklet); + + return 0; +} + +static void siu_dma_tx_complete(void *arg) +{ + struct siu_stream *siu_stream = arg; + + if (!siu_stream->rw_flg) + return; + + /* Update completed period count */ + if (++siu_stream->cur_period >= + GET_MAX_PERIODS(siu_stream->buf_bytes, + siu_stream->period_bytes)) + siu_stream->cur_period = 0; + + pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n", + __func__, siu_stream->cur_period, + siu_stream->cur_period * siu_stream->period_bytes, + siu_stream->buf_bytes, siu_stream->cookie); + + tasklet_schedule(&siu_stream->tasklet); + + /* Notify alsa: a period is done */ + snd_pcm_period_elapsed(siu_stream->substream); +} + +static int siu_pcm_wr_set(struct siu_port *port_info, + dma_addr_t buff, u32 size) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->playback; + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + struct scatterlist sg; + u32 stfifo; + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), + size, offset_in_page(buff)); + sg_dma_address(&sg) = buff; + + desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, + &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dev, "Failed to allocate a dma descriptor\n"); + return -ENOMEM; + } + + desc->callback = siu_dma_tx_complete; + desc->callback_param = siu_stream; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + dev_err(dev, "Failed to submit a dma transfer\n"); + return cookie; + } + + siu_stream->tx_desc = desc; + siu_stream->cookie = cookie; + + dma_async_issue_pending(siu_stream->chan); + + /* only output FIFO enable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18)); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo | (port_info->stfifo & 0x0c180c18)); + + return 0; +} + +static int siu_pcm_rd_set(struct siu_port *port_info, + dma_addr_t buff, size_t size) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->capture; + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + struct scatterlist sg; + u32 stfifo; + + dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff); + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), + size, offset_in_page(buff)); + sg_dma_address(&sg) = buff; + + desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, + &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dev, "Failed to allocate dma descriptor\n"); + return -ENOMEM; + } + + desc->callback = siu_dma_tx_complete; + desc->callback_param = siu_stream; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + dev_err(dev, "Failed to submit dma descriptor\n"); + return cookie; + } + + siu_stream->tx_desc = desc; + siu_stream->cookie = cookie; + + dma_async_issue_pending(siu_stream->chan); + + /* only input FIFO enable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) | + (port_info->stfifo & 0x13071307)); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo | (port_info->stfifo & 0x13071307)); + + return 0; +} + +static void siu_io_tasklet(unsigned long data) +{ + struct siu_stream *siu_stream = (struct siu_stream *)data; + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + + dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg); + + if (!siu_stream->rw_flg) { + dev_dbg(dev, "%s: stream inactive\n", __func__); + return; + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + dma_addr_t buff; + size_t count; + u8 *virt; + + buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes); + virt = PERIOD_OFFSET(rt->dma_area, + siu_stream->cur_period, + siu_stream->period_bytes); + count = siu_stream->period_bytes; + + /* DMA transfer start */ + siu_pcm_rd_set(port_info, buff, count); + } else { + siu_pcm_wr_set(port_info, + (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes), + siu_stream->period_bytes); + } +} + +/* Capture */ +static int siu_pcm_stmread_start(struct siu_port *port_info) +{ + struct siu_stream *siu_stream = &port_info->capture; + + if (siu_stream->xfer_cnt > 0x1000000) + return -EINVAL; + if (siu_stream->rw_flg) + return -EPERM; + + /* Current period in buffer */ + siu_stream->cur_period = 0; + + /* during stmread flag set */ + siu_stream->rw_flg = RWF_STM_RD; + + tasklet_schedule(&siu_stream->tasklet); + + return 0; +} + +static int siu_pcm_stmread_stop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->capture; + struct device *dev = siu_stream->substream->pcm->card->dev; + u32 stfifo; + + if (!siu_stream->rw_flg) + return -EPERM; + + /* input FIFO disable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo & ~0x13071307); + + /* during stmread flag clear */ + siu_stream->rw_flg = 0; + + return 0; +} + +static int siu_pcm_hw_params(struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *hw_params) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct device *dev = ss->pcm->card->dev; + int ret; + + dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); + + ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); + if (ret < 0) + dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n"); + + return ret; +} + +static int siu_pcm_hw_free(struct snd_pcm_substream *ss) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_port *port_info = siu_port_info(ss); + struct device *dev = ss->pcm->card->dev; + struct siu_stream *siu_stream; + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); + + return snd_pcm_lib_free_pages(ss); +} + +static bool filter(struct dma_chan *chan, void *slave) +{ + struct sh_dmae_slave *param = slave; + + pr_debug("%s: slave ID %d\n", __func__, param->slave_id); + + if (unlikely(param->dma_dev != chan->device->dev)) + return false; + + chan->private = param; + return true; +} + +static int siu_pcm_open(struct snd_pcm_substream *ss) +{ + /* Playback / Capture */ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_port *port_info = siu_port_info(ss); + struct siu_stream *siu_stream; + u32 port = info->port_id; + struct siu_platform *pdata = siu_i2s_dai.dev->platform_data; + struct device *dev = ss->pcm->card->dev; + dma_cap_mask_t mask; + struct sh_dmae_slave *param; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info); + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) { + siu_stream = &port_info->playback; + param = &siu_stream->param; + param->slave_id = port ? SHDMA_SLAVE_SIUB_TX : + SHDMA_SLAVE_SIUA_TX; + } else { + siu_stream = &port_info->capture; + param = &siu_stream->param; + param->slave_id = port ? SHDMA_SLAVE_SIUB_RX : + SHDMA_SLAVE_SIUA_RX; + } + + param->dma_dev = pdata->dma_dev; + /* Get DMA channel */ + siu_stream->chan = dma_request_channel(mask, filter, param); + if (!siu_stream->chan) { + dev_err(dev, "DMA channel allocation failed!\n"); + return -EBUSY; + } + + siu_stream->substream = ss; + + return 0; +} + +static int siu_pcm_close(struct snd_pcm_substream *ss) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct device *dev = ss->pcm->card->dev; + struct siu_port *port_info = siu_port_info(ss); + struct siu_stream *siu_stream; + + dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + dma_release_channel(siu_stream->chan); + siu_stream->chan = NULL; + + siu_stream->substream = NULL; + + return 0; +} + +static int siu_pcm_prepare(struct snd_pcm_substream *ss) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct siu_port *port_info = siu_port_info(ss); + struct device *dev = ss->pcm->card->dev; + struct snd_pcm_runtime *rt = ss->runtime; + struct siu_stream *siu_stream; + snd_pcm_sframes_t xfer_cnt; + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + rt = siu_stream->substream->runtime; + + siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss); + siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss); + + dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__, + info->port_id, rt->channels, siu_stream->period_bytes); + + /* We only support buffers that are multiples of the period */ + if (siu_stream->buf_bytes % siu_stream->period_bytes) { + dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n", + __func__, siu_stream->buf_bytes, + siu_stream->period_bytes); + return -EINVAL; + } + + xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes); + if (!xfer_cnt || xfer_cnt > 0x1000000) + return -EINVAL; + + siu_stream->format = rt->format; + siu_stream->xfer_cnt = xfer_cnt; + + dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d " + "format=%d channels=%d xfer_cnt=%d\n", info->port_id, + (unsigned long)rt->dma_addr, siu_stream->buf_bytes, + siu_stream->period_bytes, + siu_stream->format, rt->channels, (int)xfer_cnt); + + return 0; +} + +static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd) +{ + struct siu_info *info = siu_i2s_dai.private_data; + struct device *dev = ss->pcm->card->dev; + struct siu_port *port_info = siu_port_info(ss); + int ret; + + dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__, + info->port_id, port_info, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = siu_pcm_stmwrite_start(port_info); + else + ret = siu_pcm_stmread_start(port_info); + + if (ret < 0) + dev_warn(dev, "%s: start failed on port=%d\n", + __func__, info->port_id); + + break; + case SNDRV_PCM_TRIGGER_STOP: + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_pcm_stmwrite_stop(port_info); + else + siu_pcm_stmread_stop(port_info); + ret = 0; + + break; + default: + dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd); + ret = -EINVAL; + } + + return ret; +} + +/* + * So far only resolution of one period is supported, subject to extending the + * dmangine API + */ +static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) +{ + struct device *dev = ss->pcm->card->dev; + struct siu_info *info = siu_i2s_dai.private_data; + u32 __iomem *base = info->reg; + struct siu_port *port_info = siu_port_info(ss); + struct snd_pcm_runtime *rt = ss->runtime; + size_t ptr; + struct siu_stream *siu_stream; + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + /* + * ptr is the offset into the buffer where the dma is currently at. We + * check if the dma buffer has just wrapped. + */ + ptr = PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes) - rt->dma_addr; + + dev_dbg(dev, + "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n", + __func__, info->port_id, siu_read32(base + SIU_EVNTC), + siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes, + siu_stream->cookie); + + if (ptr >= siu_stream->buf_bytes) + ptr = 0; + + return bytes_to_frames(ss->runtime, ptr); +} + +static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + /* card->dev == socdev->dev, see snd_soc_new_pcms() */ + struct siu_info *info = siu_i2s_dai.private_data; + struct platform_device *pdev = to_platform_device(card->dev); + int ret; + int i; + + /* pdev->id selects between SIUA and SIUB */ + if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM) + return -EINVAL; + + info->port_id = pdev->id; + + /* + * While the siu has 2 ports, only one port can be on at a time (only 1 + * SPB). So far all the boards using the siu had only one of the ports + * wired to a codec. To simplify things, we only register one port with + * alsa. In case both ports are needed, it should be changed here + */ + for (i = pdev->id; i < pdev->id + 1; i++) { + struct siu_port **port_info = &siu_ports[i]; + + ret = siu_init_port(i, port_info, card); + if (ret < 0) + return ret; + + ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV, NULL, + SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); + if (ret < 0) { + dev_err(card->dev, + "snd_pcm_lib_preallocate_pages_for_all() err=%d", + ret); + goto fail; + } + + (*port_info)->pcm = pcm; + + /* IO tasklets */ + tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet, + (unsigned long)&(*port_info)->playback); + tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet, + (unsigned long)&(*port_info)->capture); + } + + dev_info(card->dev, "SuperH SIU driver initialized.\n"); + return 0; + +fail: + siu_free_port(siu_ports[pdev->id]); + dev_err(card->dev, "SIU: failed to initialize.\n"); + return ret; +} + +static void siu_pcm_free(struct snd_pcm *pcm) +{ + struct platform_device *pdev = to_platform_device(pcm->card->dev); + struct siu_port *port_info = siu_ports[pdev->id]; + + tasklet_kill(&port_info->capture.tasklet); + tasklet_kill(&port_info->playback.tasklet); + + siu_free_port(port_info); + snd_pcm_lib_preallocate_free_for_all(pcm); + + dev_dbg(pcm->card->dev, "%s\n", __func__); +} + +static struct snd_pcm_ops siu_pcm_ops = { + .open = siu_pcm_open, + .close = siu_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = siu_pcm_hw_params, + .hw_free = siu_pcm_hw_free, + .prepare = siu_pcm_prepare, + .trigger = siu_pcm_trigger, + .pointer = siu_pcm_pointer_dma, +}; + +struct snd_soc_platform siu_platform = { + .name = "siu-audio", + .pcm_ops = &siu_pcm_ops, + .pcm_new = siu_pcm_new, + .pcm_free = siu_pcm_free, +}; +EXPORT_SYMBOL_GPL(siu_platform); -- GitLab From 84549d239ab9bb2e3a85c6efcf0e6478a38b4260 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Mon, 25 Jan 2010 16:42:25 +0800 Subject: [PATCH 1152/3892] ASoC: ad1836: reset and restore clock control mode in suspend/resume entry tests show frequent suspend/resume(frequent poweroff/on ad1836 internal components) maybe make ad1836 clock mode wrong sometimes after wakeup. This patch reset/restore ad1836 clock mode while executing PM, then ad1836 can always resume to right clock status. Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/codecs/ad1836.h | 1 + 2 files changed, 33 insertions(+) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2c18e3d1b71e..83add2f3afba 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -223,6 +223,36 @@ static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, return reg_cache[reg]; } +#ifdef CONFIG_PM +static int ad1836_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + /* reset clock control mode */ + u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); +} + +static int ad1836_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + /* restore clock control mode */ + u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 |= AD1836_ADC_AUX; + + return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); +} +#else +#define ad1836_soc_suspend NULL +#define ad1836_soc_resume NULL +#endif + static int __devinit ad1836_spi_probe(struct spi_device *spi) { struct snd_soc_codec *codec; @@ -404,6 +434,8 @@ static int ad1836_remove(struct platform_device *pdev) struct snd_soc_codec_device soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, + .suspend = ad1836_soc_suspend, + .resume = ad1836_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h index 7660ee6973c0..e9d90d3951c5 100644 --- a/sound/soc/codecs/ad1836.h +++ b/sound/soc/codecs/ad1836.h @@ -54,6 +54,7 @@ #define AD1836_ADC_SERFMT_MASK (7 << 6) #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) +#define AD1836_ADC_AUX (0x6 << 6) #define AD1836_ADC_CTRL3 14 -- GitLab From 9df5f74194871ebd0e51ef5ad2eca5084acaaaba Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 25 Jan 2010 11:42:20 -0600 Subject: [PATCH 1153/3892] mm: add coherence API for DMA to vmalloc/vmap areas On Virtually Indexed architectures (which don't do automatic alias resolution in their caches), we have to flush via the correct virtual address to prepare pages for DMA. On some architectures (like arm) we cannot prevent the CPU from doing data movein along the alias (and thus giving stale read data), so we not only have to introduce a flush API to push dirty cache lines out, but also an invalidate API to kill inconsistent cache lines that may have moved in before DMA changed the data Signed-off-by: James Bottomley --- Documentation/cachetlb.txt | 24 ++++++++++++++++++++++++ include/linux/highmem.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt index da42ab414c48..b231414bb8bc 100644 --- a/Documentation/cachetlb.txt +++ b/Documentation/cachetlb.txt @@ -377,3 +377,27 @@ maps this page at its virtual address. All the functionality of flush_icache_page can be implemented in flush_dcache_page and update_mmu_cache. In 2.7 the hope is to remove this interface completely. + +The final category of APIs is for I/O to deliberately aliased address +ranges inside the kernel. Such aliases are set up by use of the +vmap/vmalloc API. Since kernel I/O goes via physical pages, the I/O +subsystem assumes that the user mapping and kernel offset mapping are +the only aliases. This isn't true for vmap aliases, so anything in +the kernel trying to do I/O to vmap areas must manually manage +coherency. It must do this by flushing the vmap range before doing +I/O and invalidating it after the I/O returns. + + void flush_kernel_vmap_range(void *vaddr, int size) + flushes the kernel cache for a given virtual address range in + the vmap area. This is to make sure that any data the kernel + modified in the vmap range is made visible to the physical + page. The design is to make this area safe to perform I/O on. + Note that this API does *not* also flush the offset map alias + of the area. + + void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates + the cache for a given virtual address range in the vmap area + which prevents the processor from making the cache stale by + speculatively reading data while the I/O was occurring to the + physical pages. This is only necessary for data reads into the + vmap area. diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 211ff4497269..adfe1013b2bd 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -17,6 +17,12 @@ static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page static inline void flush_kernel_dcache_page(struct page *page) { } +static inline void flush_kernel_vmap_range(void *vaddr, int size) +{ +} +static inline void invalidate_kernel_vmap_range(void *vaddr, int size) +{ +} #endif #include -- GitLab From a3662f6bbe09a3ce7cccd622654822c0d378be2e Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Fri, 22 Jan 2010 01:42:02 +0100 Subject: [PATCH 1154/3892] ARM: 5892/1: ep93xx: Add support for Simplemachines Sim.One board Add support for the Simplemachines EP9307 based Sim.One board. Cc: Hartley Sweeten Cc: Sergio Sorrenti Signed-off-by: Ryan Mallon Acked-by: Hartley Sweeten Signed-off-by: Russell King --- arch/arm/mach-ep93xx/Kconfig | 7 +++ arch/arm/mach-ep93xx/Makefile | 1 + arch/arm/mach-ep93xx/simone.c | 97 +++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 arch/arm/mach-ep93xx/simone.c diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 9167c3d2a5ed..5231a3a2c74b 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -161,6 +161,13 @@ config MACH_MICRO9S Say 'Y' here if you want your kernel to support the Contec Micro9-Slim board. +config MACH_SIM_ONE + bool "Support Simplemachines Sim.One board" + depends on EP93XX_SDCE0_PHYS_OFFSET + help + Say 'Y' here if you want your kernel to support the + Simplemachines Sim.One board. + config MACH_TS72XX bool "Support Technologic Systems TS-72xx SBC" depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index eae6199a9891..c731fa9789d1 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_MACH_ADSSPHERE) += adssphere.o obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o obj-$(CONFIG_MACH_MICRO9) += micro9.o +obj-$(CONFIG_MACH_SIM_ONE) += simone.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c new file mode 100644 index 000000000000..cd93990f1b99 --- /dev/null +++ b/arch/arm/mach-ep93xx/simone.c @@ -0,0 +1,97 @@ +/* + * arch/arm/mach-ep93xx/simone.c + * Simplemachines Sim.One support. + * + * Copyright (C) 2010 Ryan Mallon + * + * Based on the 2.6.24.7 support: + * Copyright (C) 2009 Simplemachines + * MMC support by Peter Ivanov , 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static struct physmap_flash_data simone_flash_data = { + .width = 2, +}; + +static struct resource simone_flash_resource = { + .start = EP93XX_CS6_PHYS_BASE, + .end = EP93XX_CS6_PHYS_BASE + SZ_8M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device simone_flash = { + .name = "physmap-flash", + .id = 0, + .num_resources = 1, + .resource = &simone_flash_resource, + .dev = { + .platform_data = &simone_flash_data, + }, +}; + +static struct ep93xx_eth_data simone_eth_data = { + .phy_id = 1, +}; + +static struct ep93xxfb_mach_info simone_fb_info = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, + .flags = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING, +}; + +static struct i2c_gpio_platform_data simone_i2c_gpio_data = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .sda_is_open_drain = 0, + .scl_pin = EP93XX_GPIO_LINE_EECLK, + .scl_is_open_drain = 0, + .udelay = 0, + .timeout = 0, +}; + +static struct i2c_board_info __initdata simone_i2c_board_info[] = { + { + I2C_BOARD_INFO("ds1337", 0x68), + }, +}; + +static void __init simone_init_machine(void) +{ + ep93xx_init_devices(); + + platform_device_register(&simone_flash); + ep93xx_register_eth(&simone_eth_data, 1); + ep93xx_register_fb(&simone_fb_info); + ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info, + ARRAY_SIZE(simone_i2c_board_info)); +} + +MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board") +/* Maintainer: Ryan Mallon */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = simone_init_machine, +MACHINE_END -- GitLab From 32e7bfc41110bc8f29ec0f293c3bcee6645fef34 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 25 Jan 2010 13:36:10 -0800 Subject: [PATCH 1155/3892] net: use helpers to access uc list V2 This patch introduces three macros to work with uc list from net drivers. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 5 ++--- drivers/net/e1000/e1000_main.c | 4 ++-- drivers/net/igb/igb_main.c | 7 ++++--- drivers/net/ixgbe/ixgbe_common.c | 7 +++---- drivers/net/ixgbe/ixgbe_common.h | 2 +- drivers/net/ixgbe/ixgbe_main.c | 2 +- drivers/net/ixgbe/ixgbe_type.h | 4 ++-- drivers/net/mv643xx_eth.c | 3 +-- drivers/net/niu.c | 4 ++-- drivers/net/stmmac/dwmac1000_core.c | 10 +++++----- drivers/net/virtio_net.c | 12 +++++++----- drivers/s390/net/qeth_l2_main.c | 2 +- include/linux/netdevice.h | 5 +++++ net/core/dev.c | 4 ++-- 14 files changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d83512d3e02f..a7b6b12c1c05 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -48,7 +48,6 @@ #include #include #include -#include #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) #define BCM_CNIC 1 @@ -3579,14 +3578,14 @@ bnx2_set_rx_mode(struct net_device *dev) sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; } - if (dev->uc.count > BNX2_MAX_UNICAST_ADDRESSES) { + if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) { rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | BNX2_RPM_SORT_USER0_PROM_VLAN; } else if (!(dev->flags & IFF_PROMISC)) { /* Add all entries into to the match filter list */ i = 0; - list_for_each_entry(ha, &dev->uc.list, list) { + netdev_for_each_uc_addr(ha, dev) { bnx2_set_mac_addr(bp, ha->addr, i + BNX2_START_UNICAST_ADDRESS_INDEX); sort_mode |= (1 << diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 87f575ca427d..2ce88c5f75c5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2139,7 +2139,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl |= E1000_RCTL_VFE; } - if (netdev->uc.count > rar_entries - 1) { + if (netdev_uc_count(netdev) > rar_entries - 1) { rctl |= E1000_RCTL_UPE; } else if (!(netdev->flags & IFF_PROMISC)) { rctl &= ~E1000_RCTL_UPE; @@ -2162,7 +2162,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) */ i = 1; if (use_uc) - list_for_each_entry(ha, &netdev->uc.list, list) { + netdev_for_each_uc_addr(ha, netdev) { if (i == rar_entries) break; e1000_rar_set(hw, ha->addr, i++); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index d9679493c635..01cc29483e2f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2905,12 +2905,13 @@ static int igb_write_uc_addr_list(struct net_device *netdev) int count = 0; /* return ENOMEM indicating insufficient memory for addresses */ - if (netdev->uc.count > rar_entries) + if (netdev_uc_count(netdev) > rar_entries) return -ENOMEM; - if (netdev->uc.count && rar_entries) { + if (!netdev_uc_empty(netdev) && rar_entries) { struct netdev_hw_addr *ha; - list_for_each_entry(ha, &netdev->uc.list, list) { + + netdev_for_each_uc_addr(ha, netdev) { if (!rar_entries) break; igb_rar_set_qsel(adapter, ha->addr, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 276c2aaa800b..eb49020903c1 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "ixgbe.h" @@ -1347,7 +1346,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) /** * ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses * @hw: pointer to hardware structure - * @uc_list: the list of new addresses + * @netdev: pointer to net device structure * * The given list replaces any existing list. Clears the secondary addrs from * receive address registers. Uses unused receive address registers for the @@ -1357,7 +1356,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) * manually putting the device into promiscuous mode. **/ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, - struct list_head *uc_list) + struct net_device *netdev) { u32 i; u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; @@ -1381,7 +1380,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, } /* Add the new addresses */ - list_for_each_entry(ha, uc_list, list) { + netdev_for_each_uc_addr(ha, netdev) { hw_dbg(hw, " Adding the secondary addresses:\n"); ixgbe_add_uc_addr(hw, ha->addr, 0); } diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index dfff0ffaa502..13606d4809c9 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -60,7 +60,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, u32 mc_addr_count, ixgbe_mc_addr_itr func); s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, - struct list_head *uc_list); + struct net_device *netdev); s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ee41d331a35f..439645d2aeef 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2568,7 +2568,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); /* reprogram secondary unicast list */ - hw->mac.ops.update_uc_addr_list(hw, &netdev->uc.list); + hw->mac.ops.update_uc_addr_list(hw, netdev); /* reprogram multicast list */ addr_count = netdev->mc_count; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index b4caa7011a2b..0db67c19b2c4 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -30,7 +30,7 @@ #include #include -#include +#include /* Vendor ID */ #define IXGBE_INTEL_VENDOR_ID 0x8086 @@ -2405,7 +2405,7 @@ struct ixgbe_mac_operations { s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*init_rx_addrs)(struct ixgbe_hw *); - s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *); + s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct net_device *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ixgbe_mc_addr_itr); s32 (*enable_mc)(struct ixgbe_hw *); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index af67af55efe7..e24072a9a979 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -55,7 +55,6 @@ #include #include #include -#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -1697,7 +1696,7 @@ static u32 uc_addr_filter_mask(struct net_device *dev) return 0; nibbles = 1 << (dev->dev_addr[5] & 0x0f); - list_for_each_entry(ha, &dev->uc.list, list) { + netdev_for_each_uc_addr(ha, dev) { if (memcmp(dev->dev_addr, ha->addr, 5)) return 0; if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 0e260cfbff7b..af9a8647c7e8 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6372,7 +6372,7 @@ static void niu_set_rx_mode(struct net_device *dev) if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) np->flags |= NIU_FLAGS_MCAST; - alt_cnt = dev->uc.count; + alt_cnt = netdev_uc_count(dev); if (alt_cnt > niu_num_alt_addr(np)) { alt_cnt = 0; np->flags |= NIU_FLAGS_PROMISC; @@ -6381,7 +6381,7 @@ static void niu_set_rx_mode(struct net_device *dev) if (alt_cnt) { int index = 0; - list_for_each_entry(ha, &dev->uc.list, list) { + netdev_for_each_uc_addr(ha, dev) { err = niu_set_alt_mac(np, index, ha->addr); if (err) printk(KERN_WARNING PFX "%s: Error %d " diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index 928eac05b912..d812e9cdb3db 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -83,7 +83,7 @@ static void dwmac1000_set_filter(struct net_device *dev) unsigned int value = 0; DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", - __func__, dev->mc_count, dev->uc.count); + __func__, dev->mc_count, netdev_uc_count(dev)); if (dev->flags & IFF_PROMISC) value = GMAC_FRAME_FILTER_PR; @@ -117,7 +117,7 @@ static void dwmac1000_set_filter(struct net_device *dev) } /* Handle multiple unicast addresses (perfect filtering)*/ - if (dev->uc.count > GMAC_MAX_UNICAST_ADDRESSES) + if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES) /* Switch to promiscuous mode is more than 16 addrs are required */ value |= GMAC_FRAME_FILTER_PR; @@ -125,9 +125,9 @@ static void dwmac1000_set_filter(struct net_device *dev) int reg = 1; struct netdev_hw_addr *ha; - list_for_each_entry(ha, &dev->uc.list, list) { - dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); - reg++; + netdev_for_each_uc_addr(ha, dev) { + dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); + reg++; } } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index c708ecc3cb2e..088332a943f7 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -675,6 +675,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) struct virtio_net_ctrl_mac *mac_data; struct dev_addr_list *addr; struct netdev_hw_addr *ha; + int uc_count; void *buf; int i; @@ -701,8 +702,9 @@ static void virtnet_set_rx_mode(struct net_device *dev) dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", allmulti ? "en" : "dis"); + uc_count = netdev_uc_count(dev); /* MAC filter - use one buffer for both lists */ - mac_data = buf = kzalloc(((dev->uc.count + dev->mc_count) * ETH_ALEN) + + mac_data = buf = kzalloc(((uc_count + dev->mc_count) * ETH_ALEN) + (2 * sizeof(mac_data->entries)), GFP_ATOMIC); if (!buf) { dev_warn(&dev->dev, "No memory for MAC address buffer\n"); @@ -712,16 +714,16 @@ static void virtnet_set_rx_mode(struct net_device *dev) sg_init_table(sg, 2); /* Store the unicast list and count in the front of the buffer */ - mac_data->entries = dev->uc.count; + mac_data->entries = uc_count; i = 0; - list_for_each_entry(ha, &dev->uc.list, list) + netdev_for_each_uc_addr(ha, dev) memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); sg_set_buf(&sg[0], mac_data, - sizeof(mac_data->entries) + (dev->uc.count * ETH_ALEN)); + sizeof(mac_data->entries) + (uc_count * ETH_ALEN)); /* multicast list and count fill the end */ - mac_data = (void *)&mac_data->macs[dev->uc.count][0]; + mac_data = (void *)&mac_data->macs[uc_count][0]; mac_data->entries = dev->mc_count; addr = dev->mc_list; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index c3258b0dd649..51fde6f2e0b8 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -622,7 +622,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) for (dm = dev->mc_list; dm; dm = dm->next) qeth_l2_add_mc(card, dm->da_addr, 0); - list_for_each_entry(ha, &dev->uc.list, list) + netdev_for_each_uc_addr(ha, dev) qeth_l2_add_mc(card, ha->addr, 1); spin_unlock_bh(&card->mclock); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b5fb51d0b8b1..93a32a5ca74f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -263,6 +263,11 @@ struct netdev_hw_addr_list { int count; }; +#define netdev_uc_count(dev) ((dev)->uc.count) +#define netdev_uc_empty(dev) ((dev)->uc.count == 0) +#define netdev_for_each_uc_addr(ha, dev) \ + list_for_each_entry(ha, &dev->uc.list, list) + struct hh_cache { struct hh_cache *hh_next; /* Next entry */ atomic_t hh_refcnt; /* number of users */ diff --git a/net/core/dev.c b/net/core/dev.c index 4fad9db417b1..2cba5c521e56 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3665,10 +3665,10 @@ void __dev_set_rx_mode(struct net_device *dev) /* Unicast addresses changes may only happen under the rtnl, * therefore calling __dev_set_promiscuity here is safe. */ - if (dev->uc.count > 0 && !dev->uc_promisc) { + if (!netdev_uc_empty(dev) && !dev->uc_promisc) { __dev_set_promiscuity(dev, 1); dev->uc_promisc = 1; - } else if (dev->uc.count == 0 && dev->uc_promisc) { + } else if (netdev_uc_empty(dev) && dev->uc_promisc) { __dev_set_promiscuity(dev, -1); dev->uc_promisc = 0; } -- GitLab From a13d276f1e49ae0bc4ad18ce8ea3c90656c9e8d4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 Jan 2010 14:22:42 -0800 Subject: [PATCH 1156/3892] iwlwifi: configure missed beacon threshold Add support to configure missed beacon threshold, by default, if receive "missed beacon" notification from uCode and has more than 5 consecutive beacon missed, then perform sensitivity calibration; with this change, allow user to adjust the missed beacon threshold from debugfs in case more sensitivity calibration required for better performance in noisy environment The default value (=5) should be good enough for the normal condition, but for very noisy environment, more sensitivity calibration could help improve the throughput, so by setting the missed beacon threshold to lower number, user might experience better performance result. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-commands.h | 25 +++++++++-- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 46 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-rx.c | 5 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 7 files changed, 74 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 62b6939df52e..e9f786443d1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3372,6 +3372,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; + priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index cee5fb2187c8..8823d18b9f43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3165,13 +3165,30 @@ struct iwl_notif_statistics { /* * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) + * + * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed + * in regardless of how many missed beacons, which mean when driver receive the + * notification, inside the command, it can find all the beacons information + * which include number of total missed beacons, number of consecutive missed + * beacons, number of beacons received and number of beacons expected to + * receive. + * + * If uCode detected consecutive_missed_beacons > 5, it will reset the radio + * in order to bring the radio/PHY back to working state; which has no relation + * to when driver will perform sensitivity calibration. + * + * Driver should set it own missed_beacon_threshold to decide when to perform + * sensitivity calibration based on number of consecutive missed beacons in + * order to improve overall performance, especially in noisy environment. + * */ -/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, - * then this notification will be sent. */ -#define CONSECUTIVE_MISSED_BCONS_TH 20 + +#define IWL_MISSED_BEACON_THRESHOLD_MIN (1) +#define IWL_MISSED_BEACON_THRESHOLD_DEF (5) +#define IWL_MISSED_BEACON_THRESHOLD_MAX IWL_MISSED_BEACON_THRESHOLD_DEF struct iwl_missed_beacon_notif { - __le32 consequtive_missed_beacons; + __le32 consecutive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; __le32 num_recvd_beacons; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 0facaca9b40b..36b558f23325 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -112,6 +112,7 @@ struct iwl_debugfs { struct dentry *file_csr; struct dentry *file_ucode_tracing; struct dentry *file_fh_reg; + struct dentry *file_missed_beacon; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index af00ad2afa14..02f80bc21307 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2131,6 +2131,49 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = file->private_data; + int pos = 0; + char buf[12]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", + priv->missed_beacon_threshold); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + +static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int missed; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &missed) != 1) + return -EINVAL; + + if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN || + missed > IWL_MISSED_BEACON_THRESHOLD_MAX) + priv->missed_beacon_threshold = + IWL_MISSED_BEACON_THRESHOLD_DEF; + else + priv->missed_beacon_threshold = missed; + + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2148,6 +2191,7 @@ DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); DEBUGFS_READ_FILE_OPS(fh_reg); +DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); /* * Create the debugfs files and directories @@ -2200,6 +2244,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); + DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); @@ -2260,6 +2305,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) file_clear_traffic_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c6310b0b2f12..5e06e666f176 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1053,6 +1053,7 @@ struct iwl_priv { #endif /* ucode beacon time */ u32 ucode_beacon_time; + int missed_beacon_threshold; /* we allocate array of iwl4965_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index eb45f8be0746..dc06c7bb0f5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -499,9 +499,10 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; - if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { + if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > + priv->missed_beacon_threshold) { IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n", - le32_to_cpu(missed_beacon->consequtive_missed_beacons), + le32_to_cpu(missed_beacon->consecutive_missed_beacons), le32_to_cpu(missed_beacon->total_missed_becons), le32_to_cpu(missed_beacon->num_recvd_beacons), le32_to_cpu(missed_beacon->num_expected_beacons)); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c46f988d0a5b..9c0b6ebbdc59 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3881,6 +3881,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; + priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; iwl_reset_qos(priv); -- GitLab From afbdd69af0e6a0c40676d4d4b94a0a4414708eaa Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 Jan 2010 14:22:43 -0800 Subject: [PATCH 1157/3892] iwlwifi: add function to reset/tune radio if needed Adding "radio reset" function to help reset and stabilize the radio. During normal operation, sometime for unknown reason, radio encounter problem and can not recover by itself; the best way to recover from it is to reset and re-tune the radio. Currently, there is no RF reset command available, but since radio will get reset when switching channel, use internal hw scan request to force radio reset and get back to normal operation state. The internal hw scan will only perform passive scan on the first available channel (not the channel being used) in associated state. The request should be ignored if already performing scan operation or STA is not in associated state. Also include an "internal_scan" debugfs file to help trigger the internal scan from user mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 24 ++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 24 ++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-scan.c | 155 +++++++++++++++++++-- 6 files changed, 193 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index bb3ed25f8438..645bc133577a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3343,6 +3343,30 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) } EXPORT_SYMBOL(iwl_dump_fh); +void iwl_force_rf_reset(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!iwl_is_associated(priv)) { + IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n"); + return; + } + /* + * There is no easy and better way to force reset the radio, + * the only known method is switching channel which will force to + * reset and tune the radio. + * Use internal short scan (single channel) operation to should + * achieve this objective. + * Driver should reset the radio when number of consecutive missed + * beacon, or any other uCode error condition detected. + */ + IWL_DEBUG_INFO(priv, "perform radio reset.\n"); + iwl_internal_short_hw_scan(priv); + return; +} +EXPORT_SYMBOL(iwl_force_rf_reset); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 785331a98aa5..6de83d1e1eb8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -494,6 +494,8 @@ void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); +int iwl_internal_short_hw_scan(struct iwl_priv *priv); +void iwl_force_rf_reset(struct iwl_priv *priv); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 36b558f23325..d81b4f39bb1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -113,6 +113,7 @@ struct iwl_debugfs { struct dentry *file_ucode_tracing; struct dentry *file_fh_reg; struct dentry *file_missed_beacon; + struct dentry *file_internal_scan; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 02f80bc21307..4944fdb31ba8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2174,6 +2174,27 @@ static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_internal_scan_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int scan; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &scan) != 1) + return -EINVAL; + + iwl_internal_short_hw_scan(priv); + + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2192,6 +2213,7 @@ DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); +DEBUGFS_WRITE_FILE_OPS(internal_scan); /* * Create the debugfs files and directories @@ -2245,6 +2267,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); + DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); @@ -2306,6 +2329,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5e06e666f176..502d7a6b0904 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1080,6 +1080,7 @@ struct iwl_priv { void *scan; int scan_bands; struct cfg80211_scan_request *scan_request; + bool is_internal_short_scan; u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index ceb91f969e45..fd6bafbddfca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -314,6 +314,72 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_get_passive_dwell_time); +static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, + enum ieee80211_band band, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_supported_band *sband; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int i, added = 0; + u16 channel = 0; + + sband = iwl_get_hw_mode(priv, band); + if (!sband) { + IWL_ERR(priv, "invalid band\n"); + return added; + } + + active_dwell = iwl_get_active_dwell_time(priv, band, 0); + passive_dwell = iwl_get_passive_dwell_time(priv, band); + + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + + /* only scan single channel, good enough to reset the RF */ + /* pick the first valid not in-use channel */ + if (band == IEEE80211_BAND_5GHZ) { + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel != + le16_to_cpu(priv->staging_rxon.channel)) { + channel = priv->channel_info[i].channel; + ch_info = iwl_get_channel_info(priv, + band, channel); + if (is_channel_valid(ch_info)) + break; + } + } + } else { + for (i = 0; i < 14; i++) { + if (priv->channel_info[i].channel != + le16_to_cpu(priv->staging_rxon.channel)) { + channel = + priv->channel_info[i].channel; + ch_info = iwl_get_channel_info(priv, + band, channel); + if (is_channel_valid(ch_info)) + break; + } + } + } + if (channel) { + scan_ch->channel = cpu_to_le16(channel); + scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + if (band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + added++; + } else + IWL_ERR(priv, "no valid channel found\n"); + return added; +} + static int iwl_get_channels_for_scan(struct iwl_priv *priv, enum ieee80211_band band, u8 is_active, u8 n_probes, @@ -421,6 +487,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Starting scan...\n"); set_bit(STATUS_SCANNING, &priv->status); + priv->is_internal_short_scan = false; priv->scan_start = jiffies; priv->scan_pass_start = priv->scan_start; @@ -488,6 +555,45 @@ out_unlock: } EXPORT_SYMBOL(iwl_mac_hw_scan); +/* + * internal short scan, this function should only been called while associated. + * It will reset and tune the radio to prevent possible RF related problem + */ +int iwl_internal_short_hw_scan(struct iwl_priv *priv) +{ + int ret = 0; + + if (!iwl_is_ready_rf(priv)) { + ret = -EIO; + IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); + goto out; + } + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); + ret = -EAGAIN; + goto out; + } + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); + ret = -EAGAIN; + goto out; + } + priv->scan_bands = 0; + if (priv->band == IEEE80211_BAND_5GHZ) + priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); + else + priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); + + IWL_DEBUG_SCAN(priv, "Start internal short scan...\n"); + set_bit(STATUS_SCANNING, &priv->status); + priv->is_internal_short_scan = true; + queue_work(priv->workqueue, &priv->request_scan); + +out: + return ret; +} +EXPORT_SYMBOL(iwl_internal_short_hw_scan); + #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) void iwl_bg_scan_check(struct work_struct *data) @@ -551,7 +657,8 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, if (WARN_ON(left < ie_len)) return len; - memcpy(pos, ies, ie_len); + if (ies) + memcpy(pos, ies, ie_len); len += ie_len; left -= ie_len; @@ -654,7 +761,6 @@ static void iwl_bg_request_scan(struct work_struct *data) unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - spin_lock_irqsave(&priv->lock, flags); interval = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); @@ -672,7 +778,9 @@ static void iwl_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - if (priv->scan_request->n_ssids) { + if (priv->is_internal_short_scan) { + IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); + } else if (priv->scan_request->n_ssids) { int i, p = 0; IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); for (i = 0; i < priv->scan_request->n_ssids; i++) { @@ -753,24 +861,38 @@ static void iwl_bg_request_scan(struct work_struct *data) rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; scan->rx_chain = cpu_to_le16(rx_chain); - cmd_len = iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - priv->scan_request->ie, - priv->scan_request->ie_len, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + if (!priv->is_internal_short_scan) { + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); + } else { + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + NULL, 0, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); + } scan->tx_cmd.len = cpu_to_le16(cmd_len); - if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); - scan->channel_count = - iwl_get_channels_for_scan(priv, band, is_active, n_probes, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); - + if (priv->is_internal_short_scan) { + scan->channel_count = + iwl_get_single_channel_for_scan(priv, band, + (void *)&scan->data[le16_to_cpu( + scan->tx_cmd.len)]); + } else { + scan->channel_count = + iwl_get_channels_for_scan(priv, band, + is_active, n_probes, + (void *)&scan->data[le16_to_cpu( + scan->tx_cmd.len)]); + } if (scan->channel_count == 0) { IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); goto done; @@ -831,7 +953,12 @@ void iwl_bg_scan_completed(struct work_struct *work) cancel_delayed_work(&priv->scan_check); - ieee80211_scan_completed(priv->hw, false); + if (!priv->is_internal_short_scan) + ieee80211_scan_completed(priv->hw, false); + else { + priv->is_internal_short_scan = false; + IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); + } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; -- GitLab From 220575f78fb0b8d2a1c41cd28115d52ae8d132ee Mon Sep 17 00:00:00 2001 From: Henry Zhangh Date: Fri, 22 Jan 2010 14:22:44 -0800 Subject: [PATCH 1158/3892] iwlwifi: Fix A band scanning when associated This patch allows A band to be scanned when driver is associated to AP. Scan mechanism is that mac80211/cfg80211 requests driver to scan G band first and then immediately to scan A band. Original code require driver to wait for 2 seconds after any scan before another scan will be performed. This caused driver to service G band scan request from mac80211/cfg80211 but deny the A band scan request. Signed-off-by: Henry Zhangh Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-scan.c | 17 ++--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 502d7a6b0904..42cf1810b451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1072,7 +1072,6 @@ struct iwl_priv { struct iwl_calib_result calib_results[IWL_CALIB_MAX]; /* Scan related variables */ - unsigned long last_scan_jiffies; unsigned long next_scan_jiffies; unsigned long scan_start; unsigned long scan_pass_start; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index fd6bafbddfca..07fabbbfd567 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -192,18 +192,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan ch.res: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d " - "elapsed=%lu usec (%dms since last)\n", + "elapsed=%lu usec\n", notif->channel, notif->band ? "bg" : "a", le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), le32_to_cpu(notif->statistics[0]), - le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, - jiffies_to_msecs(elapsed_jiffies - (priv->last_scan_jiffies, jiffies))); + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); #endif - priv->last_scan_jiffies = jiffies; priv->next_scan_jiffies = 0; } @@ -250,7 +247,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, goto reschedule; } - priv->last_scan_jiffies = jiffies; priv->next_scan_jiffies = 0; IWL_DEBUG_INFO(priv, "Setting scan to off\n"); @@ -528,15 +524,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } - /* if we just finished scan ask for delay */ - if (iwl_is_associated(priv) && priv->last_scan_jiffies && - time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { - IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); - queue_work(priv->workqueue, &priv->scan_completed); - ret = 0; - goto out_unlock; - } - priv->scan_bands = 0; for (i = 0; i < req->n_channels; i++) priv->scan_bands |= BIT(req->channels[i]->band); -- GitLab From d4d59e88cb746165c6fe33eacb6f582d525c6ef1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 Jan 2010 14:22:45 -0800 Subject: [PATCH 1159/3892] iwlwifi: Logic to control how frequent radio should be reset if needed Add additional logic for internal scan routine to control how frequent this function should be performed. The intent of this function is to reset/re-tune the radio and bring the RF/PHY back to normal state, it does not make sense calling it too frequent, if reset the radio can not bring it back to normal state, it indicate there are other reason to cause the radio not operate correctly. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-scan.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 42cf1810b451..86d38ae2ec7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1076,6 +1076,7 @@ struct iwl_priv { unsigned long scan_start; unsigned long scan_pass_start; unsigned long scan_start_tsf; + unsigned long last_internal_scan_jiffies; void *scan; int scan_bands; struct cfg80211_scan_request *scan_request; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 07fabbbfd567..08faafae8497 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -201,7 +201,8 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); #endif - priv->next_scan_jiffies = 0; + if (!priv->is_internal_short_scan) + priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ @@ -247,7 +248,11 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, goto reschedule; } - priv->next_scan_jiffies = 0; + if (!priv->is_internal_short_scan) + priv->next_scan_jiffies = 0; + else + priv->last_internal_scan_jiffies = jiffies; + IWL_DEBUG_INFO(priv, "Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); @@ -546,6 +551,8 @@ EXPORT_SYMBOL(iwl_mac_hw_scan); * internal short scan, this function should only been called while associated. * It will reset and tune the radio to prevent possible RF related problem */ +#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1) + int iwl_internal_short_hw_scan(struct iwl_priv *priv) { int ret = 0; @@ -565,6 +572,13 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv) ret = -EAGAIN; goto out; } + if (priv->last_internal_scan_jiffies && + time_after(priv->last_internal_scan_jiffies + + IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) { + IWL_DEBUG_SCAN(priv, "internal scan rejected\n"); + goto out; + } + priv->scan_bands = 0; if (priv->band == IEEE80211_BAND_5GHZ) priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); -- GitLab From 3e4fb5faefb57824f2e42305b3d5907845af978c Mon Sep 17 00:00:00 2001 From: Trieu 'Andrew' Nguyen Date: Fri, 22 Jan 2010 14:22:46 -0800 Subject: [PATCH 1160/3892] iwlwifi: Tune radio to prevent unexpected behavior We have seen the throughput dropped due to external noisy environment and the radio is out of tune. There are lot of plcp errors indicating this condition. Eventually the station can get de-authenticated by the Access Point. By resetting and tuning the radio, the plcp errors are reduced or eliminated and the throughput starts to rise. To prevent unexpected behavior such as drop in throughput or deauthentication, - The change provides the driver feature to monitor and tune the radio base on the statistics notification from the uCode. - It also allows the setting of the plcp error rate threshold via the plcp_delta under debugfs interface. Signed-off-by: Trieu 'Andrew' Nguyen Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-3945.c | 2 + drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 7 +++ drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 44 ++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 12 +++++ drivers/net/wireless/iwlwifi/iwl-rx.c | 54 ++++++++++++++++++++++ 10 files changed, 132 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index d5c6edbbc95a..85162e2c35d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -175,6 +175,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -201,6 +202,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 6472910b72d4..764479f74c8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2830,6 +2830,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .ht_greenfield_support = false, .led_compensation = 64, .broken_powersave = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2847,6 +2848,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .ht_greenfield_support = false, .led_compensation = 64, .broken_powersave = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8159a0fcf5a8..c36fef99b4b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2239,6 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index aab6cf23c2bd..cbbc0e4f2c76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1603,6 +1603,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5100_bgn_cfg = { @@ -1627,6 +1628,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1649,6 +1651,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1673,6 +1676,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1697,6 +1701,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1721,6 +1726,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; struct iwl_cfg iwl5150_abg_cfg = { @@ -1743,6 +1749,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4dab7f12e725..b191c634ad92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -308,6 +308,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -337,6 +338,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -366,6 +368,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -396,6 +399,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -425,6 +429,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -455,6 +460,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6de83d1e1eb8..661918347d48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -232,6 +232,8 @@ struct iwl_mod_params { * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition * @support_wimax_coexist: support wimax/wifi co-exist + * @plcp_delta_threshold: plcp error rate threshold used to trigger + * radio tuning when there is a high receiving plcp error rate * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -288,6 +290,7 @@ struct iwl_cfg { bool adv_thermal_throttle; bool support_ct_kill_exit; const bool support_wimax_coexist; + u8 plcp_delta_threshold; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d81b4f39bb1d..aff1dc0756fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -114,6 +114,7 @@ struct iwl_debugfs { struct dentry *file_fh_reg; struct dentry *file_missed_beacon; struct dentry *file_internal_scan; + struct dentry *file_plcp_delta; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 4944fdb31ba8..3f9c03998491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2195,6 +2195,47 @@ static ssize_t iwl_dbgfs_internal_scan_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char buf[12]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, "%u\n", + priv->cfg->plcp_delta_threshold); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + +static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int plcp; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &plcp) != 1) + return -EINVAL; + if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || + (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) + priv->cfg->plcp_delta_threshold = + IWL_MAX_PLCP_ERR_THRESHOLD_DEF; + else + priv->cfg->plcp_delta_threshold = plcp; + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2214,6 +2255,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); DEBUGFS_WRITE_FILE_OPS(internal_scan); +DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); /* * Create the debugfs files and directories @@ -2268,6 +2310,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR); + DEBUGFS_ADD_FILE(plcp_delta, debug, S_IWUSR | S_IRUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); @@ -2330,6 +2373,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_plcp_delta); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 86d38ae2ec7e..a1f3ecb69ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1026,6 +1026,15 @@ struct iwl_event_log { #define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) #define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) +/* + * This is the threshold value of plcp error rate per 100mSecs. It is + * used to set and check for the validity of plcp_delta. + */ +#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0) +#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) +#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) +#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1055,6 +1064,9 @@ struct iwl_priv { u32 ucode_beacon_time; int missed_beacon_threshold; + /* storing the jiffies when the plcp error rate is received */ + unsigned long plcp_jiffies; + /* we allocate array of iwl4965_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ struct iwl_channel_info *channel_info; /* channel info array */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index dc06c7bb0f5c..ea309f42a78a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -602,11 +602,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, #define REG_RECALIB_PERIOD (60) +#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); + int combined_plcp_delta; + unsigned int plcp_msec; + unsigned long plcp_received_jiffies; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(priv->statistics), @@ -621,6 +625,56 @@ void iwl_rx_statistics(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); #endif + /* + * check for plcp_err and trigger radio reset if it exceeds + * the plcp error threshold plcp_delta. + */ + plcp_received_jiffies = jiffies; + plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - + (long) priv->plcp_jiffies); + priv->plcp_jiffies = plcp_received_jiffies; + /* + * check to make sure plcp_msec is not 0 to prevent division + * by zero. + */ + if (plcp_msec) { + combined_plcp_delta = + (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) - + le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) + + (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) - + le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); + + if ((combined_plcp_delta > 0) && + ((combined_plcp_delta * 100) / plcp_msec) > + priv->cfg->plcp_delta_threshold) { + /* + * if plcp_err exceed the threshold, the following + * data is printed in csv format: + * Text: plcp_err exceeded %d, + * Received ofdm.plcp_err, + * Current ofdm.plcp_err, + * Received ofdm_ht.plcp_err, + * Current ofdm_ht.plcp_err, + * combined_plcp_delta, + * plcp_msec + */ + IWL_DEBUG_RADIO(priv, PLCP_MSG, + priv->cfg->plcp_delta_threshold, + le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), + le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), + le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), + le32_to_cpu( + priv->statistics.rx.ofdm_ht.plcp_err), + combined_plcp_delta, plcp_msec); + + /* + * Reset the RF radio due to the high plcp + * error rate + */ + iwl_force_rf_reset(priv); + } + } + memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); set_bit(STATUS_STATISTICS, &priv->status); -- GitLab From 07f33f92e8e1e6ed2ec9d4de048142e7a1d96856 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 22 Jan 2010 14:22:47 -0800 Subject: [PATCH 1161/3892] iwlwifi: enable DC calibration From: Abhijeet Kolekar For 6X50 DC calibration needs to be initialized else uCode will run an endless loop. Enbale DC calibration in hw config. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b191c634ad92..f89ef4aa78fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -158,11 +158,25 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ /* Set initial calibration set */ priv->hw_params.sens = &iwl6000_sensitivity; - priv->hw_params.calib_init_cfg = + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_6x50: + priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_DC) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); + + break; + default: + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); + break; + } + return 0; } -- GitLab From 1fa97aaeb7fb5111f69abfdb8db656ce19e4951e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 22 Jan 2010 14:22:48 -0800 Subject: [PATCH 1162/3892] iwlwifi: cleanup station adding code The work done when a station is added is very similar whether the station is added synchronously or asynchronously. Centralize this work. At the same time increase the status flags being checked for when the command returns with accompanying debug messages. Also increase checking when setting the "ucode active" state with accompanying debugging. This work is done in preparation for station notification support. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 114 +++++++++++++++++-------- 1 file changed, 78 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 8afa39b4b488..842f15653238 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -80,46 +80,103 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) } EXPORT_SYMBOL(iwl_get_ra_sta_id); +/* priv->sta_lock must be held */ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) - IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", - sta_id); + IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n", + sta_id, priv->stations[sta_id].sta.sta.addr); - priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC(priv, "Added STA to Ucode: %pM\n", - priv->stations[sta_id].sta.sta.addr); - - spin_unlock_irqrestore(&priv->sta_lock, flags); + if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) { + IWL_DEBUG_ASSOC(priv, + "STA id %u addr %pM already present in uCode (according to driver)\n", + sta_id, priv->stations[sta_id].sta.sta.addr); + } else { + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", + sta_id, priv->stations[sta_id].sta.sta.addr); + } } -static void iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt) +static void iwl_process_add_sta_resp(struct iwl_priv *priv, + struct iwl_addsta_cmd *addsta, + struct iwl_rx_packet *pkt, + bool sync) { - struct iwl_addsta_cmd *addsta = - (struct iwl_addsta_cmd *)cmd->cmd.payload; u8 sta_id = addsta->sta.sta_id; + unsigned long flags; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); + pkt->hdr.flags); return; } + IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", + sta_id); + + spin_lock_irqsave(&priv->sta_lock, flags); + switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); iwl_sta_ucode_activate(priv, sta_id); - /* fall through */ + break; + case ADD_STA_NO_ROOM_IN_TABLE: + IWL_ERR(priv, "Adding station %d failed, no room in table.\n", + sta_id); + break; + case ADD_STA_NO_BLOCK_ACK_RESOURCE: + IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n", + sta_id); + break; + case ADD_STA_MODIFY_NON_EXIST_STA: + IWL_ERR(priv, "Attempting to modify non-existing station %d \n", + sta_id); + break; default: - IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", - pkt->u.add_sta.status); + IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", + pkt->u.add_sta.status); break; } + + IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", + priv->stations[sta_id].sta.mode == + STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", + sta_id, priv->stations[sta_id].sta.sta.addr); + + /* + * XXX: The MAC address in the command buffer is often changed from + * the original sent to the device. That is, the MAC address + * written to the command buffer often is not the same MAC adress + * read from the command buffer when the command returns. This + * issue has not yet been resolved and this debugging is left to + * observe the problem. + */ + IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", + priv->stations[sta_id].sta.mode == + STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", + addsta->sta.addr); + + /* + * Determine if we wanted to modify or add a station, + * if adding a station succeeded we have some more initialization + * to do when using station notification. TODO + */ + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + +static void iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct iwl_rx_packet *pkt) +{ + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *)cmd->cmd.payload; + + iwl_process_add_sta_resp(priv, addsta, pkt, false); + } int iwl_send_add_sta(struct iwl_priv *priv, @@ -145,24 +202,9 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - pkt = (struct iwl_rx_packet *)cmd.reply_page; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - } - if (ret == 0) { - switch (pkt->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - iwl_sta_ucode_activate(priv, sta->sta.sta_id); - IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); - break; - default: - ret = -EIO; - IWL_WARN(priv, "REPLY_ADD_STA failed\n"); - break; - } + pkt = (struct iwl_rx_packet *)cmd.reply_page; + iwl_process_add_sta_resp(priv, sta, pkt, true); } iwl_free_pages(priv, cmd.reply_page); -- GitLab From 3459ab5a1c92eaf8b76e9fa1b6ca529cf83066f3 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 22 Jan 2010 14:22:49 -0800 Subject: [PATCH 1163/3892] iwlwifi: make broadcast station addition generic Add function pointer for broadcast station addition so that we can call it in from iwlcore at a later time. We only distinguish between iwlagn and iwl3945 broadcast station addition. For the iwl3945 station addition we add that function to iwlcore since that is where most station functionality resides, making it part of iwl3945 will require significant code reorganization that will dilute station management functionality. This seems to be an efficient solution. It may seem as though we are removing error checking when adding the 3945 broadcast station but this error checking was never really necessary since the function returns the station id and the broadcast station id is always set. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.c | 7 ++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-6000.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-sta.c | 11 +++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 1 + 9 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 85162e2c35d9..4281999cfaaa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -140,6 +140,7 @@ static struct iwl_lib_ops iwl1000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl1000_set_ct_threshold, }, + .add_bcast_station = iwl_add_bcast_station, }; static const struct iwl_ops iwl1000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 764479f74c8b..57194bbd2762 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1951,11 +1951,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == - IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); - return -EIO; - } + priv->cfg->ops->lib->add_bcast_station(priv); /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ @@ -2796,6 +2792,7 @@ static struct iwl_lib_ops iwl3945_lib = { .post_associate = iwl3945_post_associate, .isr = iwl_isr_legacy, .config_ap = iwl3945_config_ap, + .add_bcast_station = iwl3945_add_bcast_station, }; static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c36fef99b4b0..aebe8c51d3e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2206,6 +2206,7 @@ static struct iwl_lib_ops iwl4965_lib = { .temperature = iwl4965_temperature_calib, .set_ct_kill = iwl4965_set_ct_threshold, }, + .add_bcast_station = iwl_add_bcast_station, }; static const struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cbbc0e4f2c76..6027e2a658d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1503,6 +1503,7 @@ struct iwl_lib_ops iwl5000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl5000_set_ct_threshold, }, + .add_bcast_station = iwl_add_bcast_station, }; static struct iwl_lib_ops iwl5150_lib = { @@ -1556,6 +1557,7 @@ static struct iwl_lib_ops iwl5150_lib = { .temperature = iwl5150_temperature, .set_ct_kill = iwl5150_set_ct_threshold, }, + .add_bcast_station = iwl_add_bcast_station, }; static const struct iwl_ops iwl5000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f89ef4aa78fd..81e03e33ec73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -266,6 +266,7 @@ static struct iwl_lib_ops iwl6000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl6000_set_ct_threshold, }, + .add_bcast_station = iwl_add_bcast_station, }; static const struct iwl_ops iwl6000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e9f786443d1f..bed5dda8d6b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -203,7 +203,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ - iwl_add_bcast_station(priv); + priv->cfg->ops->lib->add_bcast_station(priv); + /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 661918347d48..e14e32976b80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -188,6 +188,8 @@ struct iwl_lib_ops { /* temperature */ struct iwl_temp_ops temp_ops; + /* station management */ + void (*add_bcast_station)(struct iwl_priv *priv); }; struct iwl_led_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 842f15653238..fcac73cf82bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1127,6 +1127,7 @@ static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) */ void iwl_add_bcast_station(struct iwl_priv *priv) { + IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); /* Set up default rate scaling table in device's station table */ @@ -1134,6 +1135,16 @@ void iwl_add_bcast_station(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_add_bcast_station); +/** + * iwl3945_add_bcast_station - add broadcast station into station table. + */ +void iwl3945_add_bcast_station(struct iwl_priv *priv) +{ + IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); + iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); +} +EXPORT_SYMBOL(iwl3945_add_bcast_station); + /** * iwl_get_sta_id - Find station's index within station table * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 8c6850d03e47..2dc35fe28f56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -53,6 +53,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_add_bcast_station(struct iwl_priv *priv); +void iwl3945_add_bcast_station(struct iwl_priv *priv); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); -- GitLab From dab1c161fed18eb6b3472bdbfd827264caae097f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 Jan 2010 14:22:50 -0800 Subject: [PATCH 1164/3892] iwlwifi: bit field description for BT Config command Give better bit filed define and description for flag parameter in REPLY_BT_CONFIG command: flags: bit 0 - 1: BT channel announcement enabled 0: disable bit 1 - 1: priority of BT device enabled 0: disable bit 2 - 1: BT 2 wire support enabled 0: disable Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 15 ++++++++++++--- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8823d18b9f43..ce538946f3ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2247,10 +2247,19 @@ struct iwl_link_quality_cmd { __le32 reserved2; } __attribute__ ((packed)); +/* + * BT configuration enable flags: + * bit 0 - 1: BT channel announcement enabled + * 0: disable + * bit 1 - 1: priority of BT device enabled + * 0: disable + * bit 2 - 1: BT 2 wire support enabled + * 0: disable + */ #define BT_COEX_DISABLE (0x0) -#define BT_COEX_MODE_2W (0x1) -#define BT_COEX_MODE_3W (0x2) -#define BT_COEX_MODE_4W (0x3) +#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0) +#define BT_ENABLE_PRIORITY BIT(1) +#define BT_ENABLE_2_WIRE BIT(2) #define BT_LEAD_TIME_MIN (0x0) #define BT_LEAD_TIME_DEF (0x1E) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 645bc133577a..d625aa8fe7a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1977,7 +1977,7 @@ EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { - .flags = BT_COEX_MODE_4W, + .flags = BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY, .lead_time = BT_LEAD_TIME_DEF, .max_kill = BT_MAX_KILL_DEF, .kill_ack_mask = 0, -- GitLab From 06702a735eacf8679e9ff0d49eb3c989bc6b96ce Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 Jan 2010 14:22:51 -0800 Subject: [PATCH 1165/3892] iwlwifi: module parameter to enable/disable bt co-exist Adding "bt_coex_active" module parameter for iwlcore to enable/disable BT coexist; if bt_coex_active is true (default), uCode will do kill/defer every time the priority line is asserted (BT is sending signals on the priority line in the PCIx). By disable the bt_coex_active, uCode will ignore the BT activity and perform the normal operation. Users might experience transmit issue on some platform due to this WiFi/BT co-exist problem. The possible symptoms are: NetworkManager and other similar programs can scan and find all the available APs, but will timeout and unable to associate with any of the APs; no out-going frames can be found with wireless sniffer tools. On those platforms, WiFi communication can be restored by set "bt_coex_active" module parameter to "false" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 3 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 29 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ce538946f3ff..c2f31eb26bef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2261,6 +2261,9 @@ struct iwl_link_quality_cmd { #define BT_ENABLE_PRIORITY BIT(1) #define BT_ENABLE_2_WIRE BIT(2) +#define BT_COEX_DISABLE (0x0) +#define BT_COEX_ENABLE (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY) + #define BT_LEAD_TIME_MIN (0x0) #define BT_LEAD_TIME_DEF (0x1E) #define BT_LEAD_TIME_MAX (0xFF) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d625aa8fe7a2..1cfabd6be0b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -47,6 +47,26 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); +/* + * set bt_coex_active to true, uCode will do kill/defer + * every time the priority line is asserted (BT is sending signals on the + * priority line in the PCIx). + * set bt_coex_active to false, uCode will ignore the BT activity and + * perform the normal operation + * + * User might experience transmit issue on some platform due to WiFi/BT + * co-exist problem. The possible behaviors are: + * Able to scan and finding all the available AP + * Not able to associate with any AP + * On those platforms, WiFi communication can be restored by set + * "bt_coex_active" module parameter to "false" + * + * default: bt_coex_active = true (BT_COEX_ENABLE) + */ +static bool bt_coex_active = true; +module_param(bt_coex_active, bool, S_IRUGO); +MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n"); + static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, 0, COEX_UNASSOC_IDLE_FLAGS}, @@ -1977,13 +1997,20 @@ EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { - .flags = BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY, .lead_time = BT_LEAD_TIME_DEF, .max_kill = BT_MAX_KILL_DEF, .kill_ack_mask = 0, .kill_cts_mask = 0, }; + if (!bt_coex_active) + bt_cmd.flags = BT_COEX_DISABLE; + else + bt_cmd.flags = BT_COEX_ENABLE; + + IWL_DEBUG_INFO(priv, "BT coex %s\n", + (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(struct iwl_bt_cmd), &bt_cmd); } -- GitLab From 1d8c4ae9169ee8d8ca7fb84a7b6bb4c7a4d49397 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 14:22:52 -0800 Subject: [PATCH 1166/3892] iwlwifi: is no longer experimental It really hasn't been for a long time, not sure why this stuck around. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b16b06c2031f..e44e572acb92 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,6 +1,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" - depends on PCI && MAC80211 && EXPERIMENTAL + depends on PCI && MAC80211 select FW_LOADER config IWLWIFI_SPECTRUM_MEASUREMENT -- GitLab From 158bea07c6017fa67bc0c64815ce5c3a998083dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 14:22:53 -0800 Subject: [PATCH 1167/3892] iwlwifi: reorder device setup It is better to first notify cfg80211 about the hw rfkill state (so the rfkill device that will be registered won't have the wrong state while being registered), and the power/tt variable init can (and probably should) also be done first. Also rename iwl_setup_mac to iwl_mac_setup_register to better describe what it really does. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index bed5dda8d6b2..1853064855cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2608,7 +2608,7 @@ void iwl_post_associate(struct iwl_priv *priv) * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. */ -static int iwl_setup_mac(struct iwl_priv *priv) +static int iwl_mac_setup_register(struct iwl_priv *priv) { int ret; struct ieee80211_hw *hw = priv->hw; @@ -3625,9 +3625,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); - /********************************** - * 8. Setup and register mac80211 - **********************************/ + /********************************************* + * 8. Enable interrupts and read RFKILL state + *********************************************/ /* enable interrupts if needed: hw bug w/a */ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); @@ -3638,14 +3638,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_enable_interrupts(priv); - err = iwl_setup_mac(priv); - if (err) - goto out_remove_sysfs; - - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -3657,6 +3649,18 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_power_initialize(priv); iwl_tt_initialize(priv); + + /************************************************** + * 9. Setup and register with mac80211 and debugfs + **************************************************/ + err = iwl_mac_setup_register(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + return 0; out_remove_sysfs: -- GitLab From 4c84a8f1679f754d6080e49892f5cae2c88c91a8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 14:22:54 -0800 Subject: [PATCH 1168/3892] iwlwifi: clean up debugfs code The debugfs code can be made a whole lot more efficient by using debugfs_remove_recursive(), the large chunk of variables can completely go away and by moving two variables we no longer need to allocate an extra chunk of memory. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 64 +----- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 239 ++++++++------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 3 files changed, 91 insertions(+), 215 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index aff1dc0756fc..1c7b53d511c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -67,63 +67,6 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) -#ifdef CONFIG_IWLWIFI_DEBUGFS -struct iwl_debugfs { - const char *name; - struct dentry *dir_drv; - struct dentry *dir_data; - struct dentry *dir_debug; - struct dentry *dir_rf; - struct dir_data_files { - struct dentry *file_sram; - struct dentry *file_nvm; - struct dentry *file_stations; - struct dentry *file_log_event; - struct dentry *file_channels; - struct dentry *file_status; - struct dentry *file_interrupt; - struct dentry *file_qos; - struct dentry *file_thermal_throttling; - struct dentry *file_led; - struct dentry *file_disable_ht40; - struct dentry *file_sleep_level_override; - struct dentry *file_current_sleep_command; - } dbgfs_data_files; - struct dir_rf_files { - struct dentry *file_disable_sensitivity; - struct dentry *file_disable_chain_noise; - struct dentry *file_disable_tx_power; - } dbgfs_rf_files; - struct dir_debug_files { - struct dentry *file_rx_statistics; - struct dentry *file_tx_statistics; - struct dentry *file_traffic_log; - struct dentry *file_rx_queue; - struct dentry *file_tx_queue; - struct dentry *file_ucode_rx_stats; - struct dentry *file_ucode_tx_stats; - struct dentry *file_ucode_general_stats; - struct dentry *file_sensitivity; - struct dentry *file_chain_noise; - struct dentry *file_tx_power; - struct dentry *file_power_save_status; - struct dentry *file_clear_ucode_statistics; - struct dentry *file_clear_traffic_statistics; - struct dentry *file_csr; - struct dentry *file_ucode_tracing; - struct dentry *file_fh_reg; - struct dentry *file_missed_beacon; - struct dentry *file_internal_scan; - struct dentry *file_plcp_delta; - } dbgfs_debug_files; - u32 sram_offset; - u32 sram_len; -}; - -int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); -void iwl_dbgfs_unregister(struct iwl_priv *priv); -#endif - #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) @@ -132,9 +75,10 @@ static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, {} #endif /* CONFIG_IWLWIFI_DEBUG */ - - -#ifndef CONFIG_IWLWIFI_DEBUGFS +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); +void iwl_dbgfs_unregister(struct iwl_priv *priv); +#else static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 3f9c03998491..5c8377b9ad9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -41,43 +41,28 @@ #include "iwl-calib.h" /* create and remove of files */ -#define DEBUGFS_ADD_DIR(name, parent) do { \ - dbgfs->dir_##name = debugfs_create_dir(#name, parent); \ - if (!(dbgfs->dir_##name)) \ - goto err; \ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, priv, \ + &iwl_dbgfs_##name##_ops)) \ + goto err; \ } while (0) -#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ - dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, mode, \ - dbgfs->dir_##parent, priv, \ - &iwl_dbgfs_##name##_ops); \ - if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ - goto err; \ +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ } while (0) -#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ - dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ - dbgfs->dir_##parent, ptr); \ - if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ - || !dbgfs->dbgfs_##parent##_files.file_##name) \ - goto err; \ +#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ } while (0) -#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ - dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \ - if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ - || !dbgfs->dbgfs_##parent##_files.file_##name) \ - goto err; \ -} while (0) - -#define DEBUGFS_REMOVE(name) do { \ - debugfs_remove(name); \ - name = NULL; \ -} while (0); - /* file operation */ #define DEBUGFS_READ_FUNC(name) \ static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ @@ -236,24 +221,24 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, size_t bufsz; /* default is to dump the entire data segment */ - if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) { - priv->dbgfs->sram_offset = 0x800000; + if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { + priv->dbgfs_sram_offset = 0x800000; if (priv->ucode_type == UCODE_INIT) - priv->dbgfs->sram_len = priv->ucode_init_data.len; + priv->dbgfs_sram_len = priv->ucode_init_data.len; else - priv->dbgfs->sram_len = priv->ucode_data.len; + priv->dbgfs_sram_len = priv->ucode_data.len; } - bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10; + bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", - priv->dbgfs->sram_len); + priv->dbgfs_sram_len); pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", - priv->dbgfs->sram_offset); - for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { - val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ - priv->dbgfs->sram_len - i); + priv->dbgfs_sram_offset); + for (i = priv->dbgfs_sram_len; i > 0; i -= 4) { + val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \ + priv->dbgfs_sram_len - i); if (i < 4) { switch (i) { case 1: @@ -293,11 +278,11 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x,%x", &offset, &len) == 2) { - priv->dbgfs->sram_offset = offset; - priv->dbgfs->sram_len = len; + priv->dbgfs_sram_offset = offset; + priv->dbgfs_sram_len = len; } else { - priv->dbgfs->sram_offset = 0; - priv->dbgfs->sram_len = 0; + priv->dbgfs_sram_offset = 0; + priv->dbgfs_sram_len = 0; } return count; @@ -2263,75 +2248,73 @@ DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); */ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { - struct iwl_debugfs *dbgfs; struct dentry *phyd = priv->hw->wiphy->debugfsdir; - int ret = 0; + struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; - dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); - if (!dbgfs) { - ret = -ENOMEM; - goto err; - } + dir_drv = debugfs_create_dir(name, phyd); + if (!dir_drv) + return -ENOMEM; - priv->dbgfs = dbgfs; - dbgfs->name = name; - dbgfs->dir_drv = debugfs_create_dir(name, phyd); - if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) { - ret = -ENOENT; + priv->debugfs_dir = dir_drv; + + dir_data = debugfs_create_dir("data", dir_drv); + if (!dir_data) + goto err; + dir_rf = debugfs_create_dir("rf", dir_drv); + if (!dir_rf) + goto err; + dir_debug = debugfs_create_dir("debug", dir_drv); + if (!dir_debug) goto err; - } - DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); - DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); - DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); - DEBUGFS_ADD_FILE(nvm, data, S_IRUSR); - DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(stations, data, S_IRUSR); - DEBUGFS_ADD_FILE(channels, data, S_IRUSR); - DEBUGFS_ADD_FILE(status, data, S_IRUSR); - DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(qos, data, S_IRUSR); - DEBUGFS_ADD_FILE(led, data, S_IRUSR); - DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR); - DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR); - DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR); - DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR); - DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); - DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); - DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); - DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); - DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); - DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); - DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR); - DEBUGFS_ADD_FILE(plcp_delta, debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { - DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); - DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); - DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); } - DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); - DEBUGFS_ADD_BOOL(disable_chain_noise, rf, + DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, &priv->disable_chain_noise_cal); if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) - DEBUGFS_ADD_BOOL(disable_tx_power, rf, + DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &priv->disable_tx_power_cal); return 0; err: - IWL_ERR(priv, "Can't open the debugfs directory\n"); + IWL_ERR(priv, "Can't create the debugfs directory\n"); iwl_dbgfs_unregister(priv); - return ret; + return -ENOMEM; } EXPORT_SYMBOL(iwl_dbgfs_register); @@ -2341,63 +2324,11 @@ EXPORT_SYMBOL(iwl_dbgfs_register); */ void iwl_dbgfs_unregister(struct iwl_priv *priv) { - if (!priv->dbgfs) + if (!priv->debugfs_dir) return; - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); - DEBUGFS_REMOVE(priv->dbgfs->dir_data); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_clear_ucode_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_clear_traffic_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_plcp_delta); - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_ucode_rx_stats); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_ucode_tx_stats); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_ucode_general_stats); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_sensitivity); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_chain_noise); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. - file_ucode_tracing); - } - DEBUGFS_REMOVE(priv->dbgfs->dir_debug); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); - if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || - ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); - DEBUGFS_REMOVE(priv->dbgfs->dir_rf); - DEBUGFS_REMOVE(priv->dbgfs->dir_drv); - kfree(priv->dbgfs); - priv->dbgfs = NULL; + debugfs_remove_recursive(priv->debugfs_dir); + priv->debugfs_dir = NULL; } EXPORT_SYMBOL(iwl_dbgfs_unregister); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a1f3ecb69ed0..d9f325bd4b69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1309,7 +1309,8 @@ struct iwl_priv { u16 rx_traffic_idx; u8 *tx_traffic; u8 *rx_traffic; - struct iwl_debugfs *dbgfs; + struct dentry *debugfs_dir; + u32 dbgfs_sram_offset, dbgfs_sram_len; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUG */ -- GitLab From 875295f183a8cb18e9fde0edae0ab88719debcbd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 14:22:55 -0800 Subject: [PATCH 1169/3892] iwlwifi: fix sparse warning sparse correctly warns about symbol not being static, make static to shut it up. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1853064855cd..d4500b5e0175 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -705,7 +705,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -void iwl_continuous_event_trace(struct iwl_priv *priv) +static void iwl_continuous_event_trace(struct iwl_priv *priv) { u32 capacity; /* event log capacity in # entries */ u32 base; /* SRAM byte address of event log header */ -- GitLab From 65baa90d92097ce9b7c080697e6b370d335c2efc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jan 2010 14:22:56 -0800 Subject: [PATCH 1170/3892] iwlwifi: check endianness annotations by default sparse won't check endianness annotations by default, but iwlwifi is and should be clean so we can make sparse check them on it. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 7f82044af242..bdaa924d2853 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -20,3 +20,5 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o # 3945 obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o + +ccflags-y += -D__CHECK_ENDIAN__ -- GitLab From 81963d68575d497d626ce13e42c84518a931cc12 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 22 Jan 2010 14:22:57 -0800 Subject: [PATCH 1171/3892] iwlwifi: cleanup spectrum measurement command support In iwlagn the support for spectrum measurement command has been disabled since v2.6.29 without any requests for it. In addition to this when this command is indeed enabled it has been found to trigger firmware SYSASSERT on at least 4965 and 5100 hardware (see http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=1952 ). Since then this code has been bitrotting and cannot just be enabled without porting. Remove support for spectrum measurement command from iwlagn. It can be added back if there is a future need and the firmware problem it triggers has been fixed. Support for the spectrim measurement notification remains as it has been enabled all the time. In addition to this remove the 3945 spectrum measurement command Kconfig option and make this command always supported. The code added by this enabling is minimal and only run when user triggers a spectrum measurement request via sysfs. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 12 -- drivers/net/wireless/iwlwifi/Makefile | 1 - drivers/net/wireless/iwlwifi/iwl-agn.c | 11 +- drivers/net/wireless/iwlwifi/iwl-core.h | 10 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 18 ++ drivers/net/wireless/iwlwifi/iwl-spectrum.c | 198 -------------------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 27 +-- 8 files changed, 33 insertions(+), 247 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/iwl-spectrum.c diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index e44e572acb92..dc8ed1527666 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -3,12 +3,6 @@ config IWLWIFI depends on PCI && MAC80211 select FW_LOADER -config IWLWIFI_SPECTRUM_MEASUREMENT - bool "Enable Spectrum Measurement in iwlagn driver" - depends on IWLWIFI - ---help--- - This option will enable spectrum measurement for the iwlagn driver. - config IWLWIFI_DEBUG bool "Enable full debugging output in iwlagn and iwl3945 drivers" depends on IWLWIFI @@ -120,9 +114,3 @@ config IWL3945 inserted in and removed from the running kernel whenever you want), say M here and read . The module will be called iwl3945. - -config IWL3945_SPECTRUM_MEASUREMENT - bool "Enable Spectrum Measurement in iwl3945 driver" - depends on IWL3945 - ---help--- - This option will enable spectrum measurement for the iwl3945 driver. diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index bdaa924d2853..4e378faee650 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -3,7 +3,6 @@ iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwl-led.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o -iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d4500b5e0175..4a268927377b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -73,13 +73,7 @@ #define VD #endif -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT -#define VS "s" -#else -#define VS -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD VS +#define DRV_VERSION IWLWIFI_VERSION VD MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -889,6 +883,8 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; @@ -902,7 +898,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; - iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); /* status change handler */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e14e32976b80..ec1fe1d7cc9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -429,6 +429,8 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_reply_statistics(struct iwl_priv *priv, @@ -531,14 +533,6 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); void iwl_calib_free_results(struct iwl_priv *priv); -/******************************************************************************* - * Spectrum Measureemtns in iwl-spectrum.c - ******************************************************************************/ -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT -void iwl_setup_spectrum_handlers(struct iwl_priv *priv); -#else -static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} -#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d9f325bd4b69..9b0a5cbc20f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1055,11 +1055,10 @@ struct iwl_priv { struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; -#if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT) /* spectrum measurement report caching */ struct iwl_spectrum_notification measure_report; u8 measurement_status; -#endif + /* ucode beacon time */ u32 ucode_beacon_time; int missed_beacon_threshold; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index ea309f42a78a..5df66382d922 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -512,6 +512,24 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); +void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG_11H(priv, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +} +EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); + + /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c deleted file mode 100644 index da166d1d1b13..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ /dev/null @@ -1,198 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-spectrum.h" - -#define BEACON_TIME_MASK_LOW 0x00FFFFFF -#define BEACON_TIME_MASK_HIGH 0xFF000000 -#define TIME_UNIT 1024 - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in 8:24 format - * the high 1 byte is the beacon counts - * the lower 3 bytes is the time in usec within one beacon interval - */ - -/* TOOD: was used in sysfs debug interface need to add to mac */ -#if 0 -static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * 1024; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); - rem = (usec % interval) & BEACON_TIME_MASK_LOW; - - return (quot << 24) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ - -static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) -{ - u32 base_low = base & BEACON_TIME_MASK_LOW; - u32 addon_low = addon & BEACON_TIME_MASK_LOW; - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & BEACON_TIME_MASK_HIGH) + - (addon & BEACON_TIME_MASK_HIGH); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << 24); - } else - res += (1 << 24); - - return cpu_to_le32(res); -} -static int iwl_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl4965_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - - if (iwl_is_associated(priv)) - add_time = - iwl_usecs_to_beacons( - le64_to_cpu(params->start_time) - priv->last_tsf, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv)) - spectrum.start_time = - iwl_add_beacon_time(priv->last_beacon_time, - add_time, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO(priv, - "Replaced existing measurement: %d\n", - res->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} -#endif - -static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG_11H(priv, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -} - -void iwl_setup_spectrum_handlers(struct iwl_priv *priv) -{ - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; -} -EXPORT_SYMBOL(iwl_setup_spectrum_handlers); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9c0b6ebbdc59..cd42b5838b38 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -56,6 +56,7 @@ #include "iwl-helpers.h" #include "iwl-core.h" #include "iwl-dev.h" +#include "iwl-spectrum.h" /* * module name, copyright, version, etc. @@ -70,13 +71,12 @@ #define VD #endif -#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT -#define VS "s" -#else -#define VS -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD VS +/* + * add "s" to indicate spectrum measurement included. + * we add it here to be consistent with previous releases in which + * this was configurable. + */ +#define DRV_VERSION IWLWIFI_VERSION VD "s" #define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" #define DRV_AUTHOR "" @@ -689,10 +689,6 @@ drop: return -1; } -#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT - -#include "iwl-spectrum.h" - #define BEACON_TIME_MASK_LOW 0x00FFFFFF #define BEACON_TIME_MASK_HIGH 0xFF000000 #define TIME_UNIT 1024 @@ -819,7 +815,6 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, return rc; } -#endif static void iwl3945_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -962,6 +957,8 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; @@ -975,7 +972,6 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; - iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; @@ -3569,8 +3565,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT - static ssize_t show_measurement(struct device *d, struct device_attribute *attr, char *buf) { @@ -3640,7 +3634,6 @@ static ssize_t store_measurement(struct device *d, static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); -#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, @@ -3823,9 +3816,7 @@ static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_dump_errors.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, -#endif &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, -- GitLab From ff27fabe62d288038b36f41ac6a2190ed7d15993 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Fri, 22 Jan 2010 14:22:58 -0800 Subject: [PATCH 1172/3892] iwlwifi: fix throughput degradation in aggregation mode The following commit commit e4da8c37af626001ff704fb29ea14eb58f5f7208 Author: Johannes Berg Date: Wed Dec 23 13:15:43 2009 +0100 mac80211: make off-channel work generic triggered a bug in iwlwifi where HT parameters would not be correctly set in some mac80211 pathways. The aggregation (and possibly other) station flags were not being set, which limited the size of aggregation blocks and reduced throughput at high rates. >From Johannes: """ Due to Wey-Yi's patch to use the set-channel command when the channel changes while associated, we don't get a full new RXON. Therefore, we don't re-set the rxon-station either. However, under some circumstances that apparently have gotten more likely mac80211 will first set up the BSS info, then add the station and then switch to an HT channel type. Therefore, the check for "priv->current_ht_config.is_ht" in iwl_rxon_add_station() will hit false and not fill in the HT information. However, that check can just be removed, which is the easiest fix for all this, because the HT capa struct is always there, just could possibly have the ht_supported member set to false. """ A sample good link in my 3x3 network improves by approximately 25% TCP throughput. This fixes Bug 2144 (http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2144). Signed-off-by: Daniel Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index fcac73cf82bc..e0b13fb78653 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1045,24 +1045,19 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) struct ieee80211_sta_ht_cap *cur_ht_config = NULL; u8 sta_id; - /* Add station to device's station table */ - /* - * XXX: This check is definitely not correct, if we're an AP - * it'll always be false which is not what we want, but - * it doesn't look like iwlagn is prepared to be an HT - * AP anyway. + * Set HT capabilities. It is ok to set this struct even if not using + * HT config: the priv->current_ht_config.is_ht flag will just be false */ - if (priv->current_ht_config.is_ht) { - rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, addr); - if (sta) { - memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); - cur_ht_config = &ht_config; - } - rcu_read_unlock(); + rcu_read_lock(); + sta = ieee80211_find_sta(priv->vif, addr); + if (sta) { + memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); + cur_ht_config = &ht_config; } + rcu_read_unlock(); + /* Add station to device's station table */ sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); /* Set up default rate scaling table in device's station table */ -- GitLab From 658965107e2a45a1a4297cb494adc55797dd9ad1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 24 Jan 2010 03:26:11 +0100 Subject: [PATCH 1173/3892] ath9k: improve max rate retry handling ath9k currently forces hw->max_rate_tries to 4 to work around rate control inefficiencies. This has some negative side effects, such as rate_control_send_low also using a maximum of 4 tries, which could negatively affect reliability of unicast management frames. This patch pushes the retry limit to the rate control instead, and allows it to use more tries on the last stage to prevent unnecessary packet loss. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 3 +-- drivers/net/wireless/ath/ath9k/rc.c | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5f78d7a5ff22..c3066b553546 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -640,8 +640,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->max_rates = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; - /* Hardware supports 10 but we use 4 */ - hw->max_rate_tries = 4; + hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index c915954d4d5b..74290137f43d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -678,13 +678,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, * For Multi Rate Retry we use a different number of * retry attempt counts. This ends up looking like this: * - * MRR[0] = 2 - * MRR[1] = 2 - * MRR[2] = 2 - * MRR[3] = 4 + * MRR[0] = 4 + * MRR[1] = 4 + * MRR[2] = 4 + * MRR[3] = 8 * */ - try_per_rate = sc->hw->max_rate_tries; + try_per_rate = 4; rate_table = sc->cur_rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); @@ -714,7 +714,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, for ( ; i < 4; i++) { /* Use twice the number of tries for the last MRR segment. */ if (i + 1 == 4) - try_per_rate = 4; + try_per_rate = 8; ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); /* All other rates in the series have RTS enabled */ -- GitLab From 96869a39399269a776a94812e9fff3d38b47d838 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 24 Jan 2010 13:13:32 +0100 Subject: [PATCH 1174/3892] b43: Workaround circular locking in hw-tkip key update callback The TKIP key update callback is called from the RX path, where the driver mutex is already locked. This results in a circular locking bug. Avoid this by removing the lock. Johannes noted that there is a separate bug: The callback still breaks on SDIO hardware, because SDIO hardware access needs to sleep, but we are not allowed to sleep in the callback due to mac80211's RCU locking. Signed-off-by: Michael Buesch Tested-by: Larry Finger Reported-by: kecsa@kutfo.hit.bme.hu Cc: Johannes Berg Cc: stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6d7cf3c2f7bf..66220cde9c49 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -856,22 +856,19 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw, if (B43_WARN_ON(!modparam_hwtkip)) return; - mutex_lock(&wl->mutex); - + /* This is only called from the RX path through mac80211, where + * our mutex is already locked. */ + B43_WARN_ON(!mutex_is_locked(&wl->mutex)); dev = wl->current_dev; - if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) - goto out_unlock; + B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED); keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ rx_tkip_phase1_write(dev, index, iv32, phase1key); /* only pairwise TKIP keys are supported right now */ if (WARN_ON(!sta)) - goto out_unlock; + return; keymac_write(dev, index, sta->addr); - -out_unlock: - mutex_unlock(&wl->mutex); } static void do_key_write(struct b43_wldev *dev, -- GitLab From eb807fb23878bc319e029ed8ce3d835d239723a5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sun, 24 Jan 2010 14:55:12 +0200 Subject: [PATCH 1175/3892] mac80211: fix update_tkip_key() documentation about the context Johannes noticed that I had incorrectly documented the context of update_tkip_key() driver operation. It must be atomic because all RX code is run inside rcu critical section. Reported-by: Johannes Berg Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 +- net/mac80211/driver-ops.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f56d6f479532..f64402f6312b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1489,7 +1489,7 @@ enum ieee80211_ampdu_mlme_action { * @update_tkip_key: See the section "Hardware crypto acceleration" * This callback will be called in the context of Rx. Called for drivers * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. - * The callback can sleep. + * The callback must be atomic. * * @hw_scan: Ask the hardware to service the scan request, no need to start * the scan state machine in stack. The scan must honour the channel diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 40c6e9a89864..6c31f38ac7f5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -144,8 +144,6 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, { struct ieee80211_sta *ista = NULL; - might_sleep(); - if (sta) ista = &sta->sta; -- GitLab From 1396b231b0369c4146988c2f42fb416ae19e2572 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 24 Jan 2010 20:44:35 +0100 Subject: [PATCH 1176/3892] mac80211: fix WARN_ON in the new work code ieee80211_work_rx_mgmt currently enqueues various management frames, including deauth and disassoc frames, however the function ieee80211_work_rx_queued_mgmt does not handle these, as they should only occur if the AP is buggy. It does emit a WARN_ON when this happens though, and several users have reported such instances. Fix the WARN_ON by not queueing such frames in the first place. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/work.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 81bd5d592bb4..df8277cdb4d0 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -1022,8 +1022,6 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_DISASSOC: skb_queue_tail(&local->work_skb_queue, skb); ieee80211_queue_work(&local->hw, &local->work_work); return RX_QUEUED; -- GitLab From 382b16559d599c4260aeb82a5ea5ba44459d1cd2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Jan 2010 11:36:16 +0100 Subject: [PATCH 1177/3892] mac80211: fix sw crypto What a stupid mistake. In commit 813d76694043d00b59475baa1fbfaf54a2eb7fad Author: Johannes Berg Date: Sun Jan 17 01:47:58 2010 +0100 mac80211: move control.hw_key assignment I inserted code testing the wrong flags field, which means that the test is almost always true (it's really testing for the peer's WMM support) and thus the later parts of the stack assume hw crypto will be done even if that's not true. Obviously, that broke software crypto. Maxim said so specifically, and Jochen probably uses some cipher that iwl3945 doesn't support in hardware, which might also explain that Maxim reports that even hw crypto is broken. Fix this to test the right flags field. Reported-by: Maxim Levitsky Reported-by: Jochen Friedrich Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d017b3530d4d..14c70452c245 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -559,7 +559,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!skip_hw && tx->key && - tx->key->conf.flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) info->control.hw_key = &tx->key->conf; } -- GitLab From 723bae7ee44fd79c1cd3c7531ed581d373920774 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Jan 2010 13:36:36 +0100 Subject: [PATCH 1178/3892] mac80211: track work started through callbacks Currently, the remain_on_channel work callback needs to track in its own data structure whether the work was just started or not. By reordering some code this becomes unnecessary, the generic wk->started variable can still be 'false' on the first invocation and only be 'true' on actual timeout invocations, so that the extra variable can be removed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/work.c | 17 ++++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c18f576f1848..3067fbd69d63 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -299,7 +299,6 @@ struct ieee80211_work { } assoc; struct { u32 duration; - bool started; } remain; }; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index df8277cdb4d0..7e708d5c88b4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -535,8 +535,7 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) * First time we run, do nothing -- the generic code will * have switched to the right channel etc. */ - if (!wk->remain.started) { - wk->remain.started = true; + if (!wk->started) { wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, @@ -821,15 +820,17 @@ static void ieee80211_work_work(struct work_struct *work) mutex_lock(&local->work_mtx); list_for_each_entry_safe(wk, tmp, &local->work_list, list) { + bool started = wk->started; + /* mark work as started if it's on the current off-channel */ - if (!wk->started && local->tmp_channel && + if (!started && local->tmp_channel && wk->chan == local->tmp_channel && wk->chan_type == local->tmp_channel_type) { - wk->started = true; + started = true; wk->timeout = jiffies; } - if (!wk->started && !local->tmp_channel) { + if (!started && !local->tmp_channel) { /* * TODO: could optimize this by leaving the * station vifs in awake mode if they @@ -842,12 +843,12 @@ static void ieee80211_work_work(struct work_struct *work) local->tmp_channel = wk->chan; local->tmp_channel_type = wk->chan_type; ieee80211_hw_config(local, 0); - wk->started = true; + started = true; wk->timeout = jiffies; } /* don't try to work with items that aren't started */ - if (!wk->started) + if (!started) continue; if (time_is_after_jiffies(wk->timeout)) { @@ -882,6 +883,8 @@ static void ieee80211_work_work(struct work_struct *work) break; } + wk->started = started; + switch (rma) { case WORK_ACT_NONE: /* might have changed the timeout */ -- GitLab From 3ed0fac3b56504aaaa3d800e7891ed4a7068b85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 25 Jan 2010 18:59:58 +0100 Subject: [PATCH 1179/3892] b43: N-PHY: fix one bit off in parsing RF Ctrl Override arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index a45a1f3ced42..061b01b814d1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1031,7 +1031,7 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, u8 index = fls(field); u8 addr, en_addr, val_addr; /* we expect only one bit set */ - B43_WARN_ON(field & (~(1 << index))); + B43_WARN_ON(field & (~(1 << (index - 1)))); if (dev->phy.rev >= 3) { const struct nphy_rf_control_override_rev3 *rf_ctrl; -- GitLab From 986504540306137dfc90a936f9f25086d15621c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 25 Jan 2010 18:59:59 +0100 Subject: [PATCH 1180/3892] b43: make cordic common (LP-PHY and N-PHY need it) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 38 ++++++++++++++++++++++ drivers/net/wireless/b43/phy_common.h | 3 ++ drivers/net/wireless/b43/phy_lp.c | 45 ++------------------------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 75b26e175e8f..446c41bb1e9f 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -421,3 +421,41 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) { b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); } + +struct b43_c32 b43_cordic(int theta) +{ + u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, + 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, + 229, 115, 57, 29, }; + int i, tmp, signx = 1, angle = 0; + struct b43_c32 ret = { .i = 39797, .q = 0, }; + + theta = clamp_t(int, theta, -180, 180); + + if (theta > 90) { + theta -= 180; + signx = -1; + } else if (theta < -90) { + theta += 180; + signx = -1; + } + + for (i = 0; i <= 17; i++) { + if (theta > angle) { + tmp = ret.i - (ret.q >> i); + ret.q += ret.i >> i; + ret.i = tmp; + angle += arctg[i]; + } else { + tmp = ret.i + (ret.q >> i); + ret.q -= ret.i >> i; + ret.i = tmp; + angle -= arctg[i]; + } + } + + ret.i *= signx; + ret.q *= signx; + + return ret; +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index f635f9e4f83d..9e4de47d0608 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -5,6 +5,8 @@ struct b43_wldev; +/* Complex number using 2 32-bit signed integers */ +struct b43_c32 { s32 i, q; }; /* PHY register routing bits */ #define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ @@ -421,5 +423,6 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); */ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); +struct b43_c32 b43_cordic(int theta); #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index b58d6cf26580..453585073437 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1767,47 +1767,6 @@ out: return ret; } -/* Complex number using 2 32-bit signed integers */ -typedef struct {s32 i, q;} lpphy_c32; - -static lpphy_c32 lpphy_cordic(int theta) -{ - u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, - 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, - 229, 115, 57, 29, }; - int i, tmp, signx = 1, angle = 0; - lpphy_c32 ret = { .i = 39797, .q = 0, }; - - theta = clamp_t(int, theta, -180, 180); - - if (theta > 90) { - theta -= 180; - signx = -1; - } else if (theta < -90) { - theta += 180; - signx = -1; - } - - for (i = 0; i <= 17; i++) { - if (theta > angle) { - tmp = ret.i - (ret.q >> i); - ret.q += ret.i >> i; - ret.i = tmp; - angle += arctg[i]; - } else { - tmp = ret.i + (ret.q >> i); - ret.q -= ret.i >> i; - ret.i = tmp; - angle -= arctg[i]; - } - } - - ret.i *= signx; - ret.q *= signx; - - return ret; -} - static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops, u16 wait) { @@ -1826,7 +1785,7 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) struct b43_phy_lp *lpphy = dev->phy.lp; u16 buf[64]; int i, samples = 0, angle = 0, rotation = (9 * freq) / 500; - lpphy_c32 sample; + struct b43_c32 sample; lpphy->tx_tone_freq = freq; @@ -1842,7 +1801,7 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) } for (i = 0; i < samples; i++) { - sample = lpphy_cordic(angle); + sample = b43_cordic(angle); angle += rotation; buf[i] = ((sample.i * max) & 0xFF) << 8; buf[i] |= (sample.q * max) & 0xFF; -- GitLab From 6f98e62a9f1bdbd83d8d1be8c2ca6f58099846ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 25 Jan 2010 19:00:00 +0100 Subject: [PATCH 1181/3892] b43: update cordic code to match current specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 19 +++++++++++++------ drivers/net/wireless/b43/phy_common.h | 4 ++++ drivers/net/wireless/b43/phy_lp.c | 7 ++++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 446c41bb1e9f..8f7d7eff2d80 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -422,21 +422,28 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */ struct b43_c32 b43_cordic(int theta) { u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, 229, 115, 57, 29, }; - int i, tmp, signx = 1, angle = 0; + u8 i; + s32 tmp; + s8 signx = 1; + u32 angle = 0; struct b43_c32 ret = { .i = 39797, .q = 0, }; - theta = clamp_t(int, theta, -180, 180); + while (theta > (180 << 16)) + theta -= (360 << 16); + while (theta < -(180 << 16)) + theta += (360 << 16); - if (theta > 90) { - theta -= 180; + if (theta > (90 << 16)) { + theta -= (180 << 16); signx = -1; - } else if (theta < -90) { - theta += 180; + } else if (theta < -(90 << 16)) { + theta += (180 << 16); signx = -1; } diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9e4de47d0608..bd480b481bfc 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -8,6 +8,10 @@ struct b43_wldev; /* Complex number using 2 32-bit signed integers */ struct b43_c32 { s32 i, q; }; +#define CORDIC_CONVERT(value) (((value) >= 0) ? \ + ((((value) >> 15) + 1) >> 1) : \ + -((((-(value)) >> 15) + 1) >> 1)) + /* PHY register routing bits */ #define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ #define B43_PHYROUTE_BASE 0x0000 /* Base registers */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 453585073437..185219e0a552 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1784,7 +1784,8 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) { struct b43_phy_lp *lpphy = dev->phy.lp; u16 buf[64]; - int i, samples = 0, angle = 0, rotation = (9 * freq) / 500; + int i, samples = 0, angle = 0; + int rotation = (((36 * freq) / 20) << 16) / 100; struct b43_c32 sample; lpphy->tx_tone_freq = freq; @@ -1803,8 +1804,8 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) for (i = 0; i < samples; i++) { sample = b43_cordic(angle); angle += rotation; - buf[i] = ((sample.i * max) & 0xFF) << 8; - buf[i] |= (sample.q * max) & 0xFF; + buf[i] = CORDIC_CONVERT((sample.i * max) & 0xFF) << 8; + buf[i] |= CORDIC_CONVERT((sample.q * max) & 0xFF); } b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf); -- GitLab From f2982181e0531c0b12752336a1578626f99e7828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 25 Jan 2010 19:00:01 +0100 Subject: [PATCH 1182/3892] b43: N-PHY: use cordic to generate samples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 061b01b814d1..df4bf435e218 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -821,8 +821,9 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, bool test) { int i; - u16 bw, len, num, rot, angle; - /* TODO: *buffer; */ + u16 bw, len, rot, angle; + b43_c32 *samples; + bw = (dev->phy.is_40mhz) ? 40 : 20; len = bw << 3; @@ -839,18 +840,20 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, len = bw << 1; } - /* TODO: buffer = kzalloc(len * sizeof(u32), GFP_KERNEL); */ - num = len; + samples = kzalloc(len * sizeof(b43_c32), GFP_KERNEL); rot = (((freq * 36) / bw) << 16) / 100; angle = 0; - for (i = 0; i < num; i++) { - /* TODO */ + for (i = 0; i < len; i++) { + samples[i] = b43_cordic(angle); + angle += rot; + samples[i].q = CORDIC_CONVERT(samples[i].q * max); + samples[i].i = CORDIC_CONVERT(samples[i].i * max); } - /* TODO: Call N PHY Load Sample Table with buffer, num as arguments */ - /* TODO: kfree(buffer); */ - return num; + /* TODO: Call N PHY Load Sample Table with buffer, len as arguments */ + kfree(samples); + return len; } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ -- GitLab From 18c949070b57d2cbcc0b25c5cfa003ece204e468 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Jan 2010 19:07:39 +0100 Subject: [PATCH 1183/3892] mac80211: fill jiffies/vif on filtered frames Filtered frames not only need their control information cleared to avoid wrong checks, but also need to have jiffies and vif assigned so they can be processed or expired. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/status.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 800b6777e0ed..e57ad6b1d7ea 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -53,6 +53,9 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * modified/encrypted again. */ memset(&info->control, 0, sizeof(info->control)); + + info->control.jiffies = jiffies; + info->control.vif = &sta->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | IEEE80211_TX_INTFL_RETRANSMISSION; -- GitLab From cd9ec30da58bcd8ab154eba9eb54d16c67e7ef3b Mon Sep 17 00:00:00 2001 From: Johnathon Harris Date: Thu, 21 Jan 2010 14:36:52 +0000 Subject: [PATCH 1184/3892] HID: add support for Ortek WKB-2000 This patch adds a new USB HID driver for the Ortek WKB-2000, working around an incorrect LogicalMaximum value in the USB resource descriptor. Tracked by http://bugzilla.kernel.org/show_bug.cgi?id=14787 Bug originally reported by Ubuntu users: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/405390 Signed-off-by: Johnathon Harris Tested-by: Daniel J Blueman Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-ortek.c | 56 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 drivers/hid/hid-ortek.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 38e969207636..139668d6382a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -218,6 +218,13 @@ config HID_NTRIG ---help--- Support for N-Trig touch screen. +config HID_ORTEK + tristate "Ortek" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. + config HID_PANTHERLORD tristate "Pantherlord support" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 15541c47b172..b62d4b3afdc2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o +obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_QUANTA) += hid-quanta.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 116a3460e75a..7fe509879fe3 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1337,6 +1337,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 064c09a221ef..6c38359385a9 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -363,6 +363,9 @@ #define USB_VENDOR_ID_ONTRAK 0x0a07 #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 +#define USB_VENDOR_ID_ORTEK 0x05a4 +#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 + #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_PANTHERLORD 0x0810 diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c new file mode 100644 index 000000000000..aa9a960f73a4 --- /dev/null +++ b/drivers/hid/hid-ortek.c @@ -0,0 +1,56 @@ +/* + * HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad). + * Fixes LogicalMaximum error in USB report description, see + * http://bugzilla.kernel.org/show_bug.cgi?id=14787 + * + * Copyright (c) 2010 Johnathon Harris + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { + dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 " + "report descriptor.\n"); + rdesc[55] = 0x92; + } +} + +static const struct hid_device_id ortek_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ortek_devices); + +static struct hid_driver ortek_driver = { + .name = "ortek", + .id_table = ortek_devices, + .report_fixup = ortek_report_fixup +}; + +static int __init ortek_init(void) +{ + return hid_register_driver(&ortek_driver); +} + +static void __exit ortek_exit(void) +{ + hid_unregister_driver(&ortek_driver); +} + +module_init(ortek_init); +module_exit(ortek_exit); +MODULE_LICENSE("GPL"); -- GitLab From 9d56dd3b083a3bec56e9da35ce07baca81030b03 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 26 Jan 2010 12:58:40 +0900 Subject: [PATCH 1185/3892] sh: Mass ctrl_in/outX to __raw_read/writeX conversion. The old ctrl in/out routines are non-portable and unsuitable for cross-platform use. While drivers/sh has already been sanitized, there is still quite a lot of code that is not. This converts the arch/sh/ bits over, which permits us to flag the routines as deprecated whilst still building with -Werror for the architecture code, and to ensure that future users are not added. Signed-off-by: Paul Mundt --- arch/sh/boards/board-magicpanelr2.c | 74 +++++++++---------- arch/sh/boards/board-polaris.c | 22 +++--- arch/sh/boards/board-shmin.c | 4 +- arch/sh/boards/mach-ap325rxa/setup.c | 16 ++-- arch/sh/boards/mach-cayman/irq.c | 16 ++-- arch/sh/boards/mach-dreamcast/rtc.c | 20 ++--- arch/sh/boards/mach-ecovec24/setup.c | 20 ++--- arch/sh/boards/mach-highlander/irq-r7780mp.c | 2 +- arch/sh/boards/mach-highlander/irq-r7780rp.c | 2 +- arch/sh/boards/mach-highlander/irq-r7785rp.c | 16 ++-- arch/sh/boards/mach-highlander/psw.c | 4 +- arch/sh/boards/mach-highlander/setup.c | 14 ++-- arch/sh/boards/mach-hp6xx/hp6xx_apm.c | 2 +- arch/sh/boards/mach-hp6xx/pm.c | 38 +++++----- arch/sh/boards/mach-hp6xx/setup.c | 12 +-- arch/sh/boards/mach-kfr2r09/setup.c | 14 ++-- arch/sh/boards/mach-landisk/gio.c | 12 +-- arch/sh/boards/mach-landisk/irq.c | 6 +- arch/sh/boards/mach-landisk/psw.c | 4 +- arch/sh/boards/mach-landisk/setup.c | 4 +- arch/sh/boards/mach-microdev/io.c | 4 +- arch/sh/boards/mach-microdev/irq.c | 10 +-- arch/sh/boards/mach-migor/setup.c | 8 +- arch/sh/boards/mach-r2d/irq.c | 4 +- arch/sh/boards/mach-r2d/setup.c | 8 +- arch/sh/boards/mach-rsk/devices-rsk7203.c | 2 +- arch/sh/boards/mach-sdk7780/irq.c | 4 +- arch/sh/boards/mach-sdk7780/setup.c | 6 +- arch/sh/boards/mach-se/7206/io.c | 2 +- arch/sh/boards/mach-se/7206/irq.c | 40 +++++----- arch/sh/boards/mach-se/7343/irq.c | 10 +-- arch/sh/boards/mach-se/7343/setup.c | 6 +- arch/sh/boards/mach-se/770x/irq.c | 14 ++-- arch/sh/boards/mach-se/7721/irq.c | 2 +- arch/sh/boards/mach-se/7721/setup.c | 8 +- arch/sh/boards/mach-se/7722/irq.c | 10 +-- arch/sh/boards/mach-se/7722/setup.c | 34 ++++----- arch/sh/boards/mach-se/7724/irq.c | 20 ++--- arch/sh/boards/mach-se/7724/setup.c | 26 +++---- arch/sh/boards/mach-se/7780/irq.c | 18 ++--- arch/sh/boards/mach-se/7780/setup.c | 26 +++---- arch/sh/boards/mach-sh03/rtc.c | 50 ++++++------- arch/sh/boards/mach-sh7763rdp/irq.c | 10 +-- arch/sh/boards/mach-sh7763rdp/setup.c | 40 +++++----- arch/sh/boards/mach-snapgear/setup.c | 2 +- arch/sh/boards/mach-systemh/irq.c | 12 +-- arch/sh/boards/mach-titan/io.c | 30 ++++---- arch/sh/boards/mach-x3proto/ilsel.c | 8 +- arch/sh/boards/mach-x3proto/setup.c | 2 +- arch/sh/cchips/hd6446x/hd64461.c | 2 +- arch/sh/drivers/dma/dma-pvr2.c | 10 +-- arch/sh/drivers/dma/dma-sh.c | 26 +++---- arch/sh/drivers/dma/dmabrg.c | 22 +++--- arch/sh/drivers/pci/fixups-rts7751r2d.c | 4 +- arch/sh/drivers/pci/pci-sh4.h | 4 +- arch/sh/drivers/pci/pci-sh5.h | 12 +-- arch/sh/drivers/pci/pci-sh7751.c | 12 +-- arch/sh/drivers/superhyway/ops-sh4-202.c | 8 +- arch/sh/include/asm/dma-sh.h | 12 +-- arch/sh/include/asm/mmu_context.h | 6 +- arch/sh/include/asm/mmu_context_32.h | 4 +- arch/sh/include/asm/watchdog.h | 18 ++--- arch/sh/include/cpu-sh2/cpu/watchdog.h | 4 +- arch/sh/include/cpu-sh3/cpu/dac.h | 12 +-- .../include/mach-common/mach/magicpanelr2.h | 12 +-- arch/sh/kernel/cpu/adc.c | 12 +-- arch/sh/kernel/cpu/init.c | 10 +-- arch/sh/kernel/cpu/irq/intc-sh5.c | 14 ++-- arch/sh/kernel/cpu/sh2/clock-sh7619.c | 6 +- arch/sh/kernel/cpu/sh2a/clock-sh7201.c | 8 +- arch/sh/kernel/cpu/sh2a/clock-sh7203.c | 6 +- arch/sh/kernel/cpu/sh2a/clock-sh7206.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh3.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh7705.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh7706.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh7709.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh7710.c | 8 +- arch/sh/kernel/cpu/sh3/clock-sh7712.c | 6 +- arch/sh/kernel/cpu/sh3/probe.c | 26 +++---- arch/sh/kernel/cpu/sh3/setup-sh3.c | 2 +- arch/sh/kernel/cpu/sh4/clock-sh4-202.c | 10 +-- arch/sh/kernel/cpu/sh4/clock-sh4.c | 8 +- arch/sh/kernel/cpu/sh4/probe.c | 6 +- arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 2 +- arch/sh/kernel/cpu/sh4/setup-sh7750.c | 2 +- arch/sh/kernel/cpu/sh4/setup-sh7760.c | 2 +- arch/sh/kernel/cpu/sh4/sq.c | 10 +-- arch/sh/kernel/cpu/sh4a/clock-sh7757.c | 8 +- arch/sh/kernel/cpu/sh4a/clock-sh7763.c | 8 +- arch/sh/kernel/cpu/sh4a/clock-sh7770.c | 8 +- arch/sh/kernel/cpu/sh4a/clock-sh7780.c | 10 +-- arch/sh/kernel/cpu/sh4a/clock-shx3.c | 10 +-- arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 2 +- arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 2 +- arch/sh/kernel/cpu/sh4a/setup-sh7757.c | 26 +++---- arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 20 ++--- arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 24 +++--- arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 24 +++--- arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 26 +++---- arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 24 +++--- arch/sh/kernel/cpu/sh5/clock-sh5.c | 8 +- arch/sh/kernel/io_trapped.c | 16 ++-- arch/sh/kernel/process_32.c | 2 +- arch/sh/kernel/signal_32.c | 6 +- arch/sh/kernel/traps.c | 4 +- arch/sh/mm/cache-debugfs.c | 4 +- arch/sh/mm/cache-sh2.c | 12 +-- arch/sh/mm/cache-sh2a.c | 20 ++--- arch/sh/mm/cache-sh3.c | 6 +- arch/sh/mm/cache-sh4.c | 10 +-- arch/sh/mm/cache-sh7705.c | 8 +- arch/sh/mm/pmb.c | 24 +++--- arch/sh/mm/tlb-sh3.c | 6 +- arch/sh/mm/tlb-sh4.c | 10 +-- arch/sh/mm/tlbflush_32.c | 4 +- 115 files changed, 698 insertions(+), 698 deletions(-) diff --git a/arch/sh/boards/board-magicpanelr2.c b/arch/sh/boards/board-magicpanelr2.c index 99ffc5f1c0dd..efba450a0518 100644 --- a/arch/sh/boards/board-magicpanelr2.c +++ b/arch/sh/boards/board-magicpanelr2.c @@ -23,7 +23,7 @@ #include #include -#define LAN9115_READY (ctrl_inl(0xA8000084UL) & 0x00000001UL) +#define LAN9115_READY (__raw_readl(0xA8000084UL) & 0x00000001UL) /* Prefer cmdline over RedBoot */ static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; @@ -60,33 +60,33 @@ static void __init setup_chip_select(void) { /* CS2: LAN (0x08000000 - 0x0bffffff) */ /* no idle cycles, normal space, 8 bit data bus */ - ctrl_outl(0x36db0400, CS2BCR); + __raw_writel(0x36db0400, CS2BCR); /* (SW:1.5 WR:3 HW:1.5), ext. wait */ - ctrl_outl(0x000003c0, CS2WCR); + __raw_writel(0x000003c0, CS2WCR); /* CS4: CAN1 (0xb0000000 - 0xb3ffffff) */ /* no idle cycles, normal space, 8 bit data bus */ - ctrl_outl(0x00000200, CS4BCR); + __raw_writel(0x00000200, CS4BCR); /* (SW:1.5 WR:3 HW:1.5), ext. wait */ - ctrl_outl(0x00100981, CS4WCR); + __raw_writel(0x00100981, CS4WCR); /* CS5a: CAN2 (0xb4000000 - 0xb5ffffff) */ /* no idle cycles, normal space, 8 bit data bus */ - ctrl_outl(0x00000200, CS5ABCR); + __raw_writel(0x00000200, CS5ABCR); /* (SW:1.5 WR:3 HW:1.5), ext. wait */ - ctrl_outl(0x00100981, CS5AWCR); + __raw_writel(0x00100981, CS5AWCR); /* CS5b: CAN3 (0xb6000000 - 0xb7ffffff) */ /* no idle cycles, normal space, 8 bit data bus */ - ctrl_outl(0x00000200, CS5BBCR); + __raw_writel(0x00000200, CS5BBCR); /* (SW:1.5 WR:3 HW:1.5), ext. wait */ - ctrl_outl(0x00100981, CS5BWCR); + __raw_writel(0x00100981, CS5BWCR); /* CS6a: Rotary (0xb8000000 - 0xb9ffffff) */ /* no idle cycles, normal space, 8 bit data bus */ - ctrl_outl(0x00000200, CS6ABCR); + __raw_writel(0x00000200, CS6ABCR); /* (SW:1.5 WR:3 HW:1.5), no ext. wait */ - ctrl_outl(0x001009C1, CS6AWCR); + __raw_writel(0x001009C1, CS6AWCR); } static void __init setup_port_multiplexing(void) @@ -94,71 +94,71 @@ static void __init setup_port_multiplexing(void) /* A7 GPO(LED8); A6 GPO(LED7); A5 GPO(LED6); A4 GPO(LED5); * A3 GPO(LED4); A2 GPO(LED3); A1 GPO(LED2); A0 GPO(LED1); */ - ctrl_outw(0x5555, PORT_PACR); /* 01 01 01 01 01 01 01 01 */ + __raw_writew(0x5555, PORT_PACR); /* 01 01 01 01 01 01 01 01 */ /* B7 GPO(RST4); B6 GPO(RST3); B5 GPO(RST2); B4 GPO(RST1); * B3 GPO(PB3); B2 GPO(PB2); B1 GPO(PB1); B0 GPO(PB0); */ - ctrl_outw(0x5555, PORT_PBCR); /* 01 01 01 01 01 01 01 01 */ + __raw_writew(0x5555, PORT_PBCR); /* 01 01 01 01 01 01 01 01 */ /* C7 GPO(PC7); C6 GPO(PC6); C5 GPO(PC5); C4 GPO(PC4); * C3 LCD_DATA3; C2 LCD_DATA2; C1 LCD_DATA1; C0 LCD_DATA0; */ - ctrl_outw(0x5500, PORT_PCCR); /* 01 01 01 01 00 00 00 00 */ + __raw_writew(0x5500, PORT_PCCR); /* 01 01 01 01 00 00 00 00 */ /* D7 GPO(PD7); D6 GPO(PD6); D5 GPO(PD5); D4 GPO(PD4); * D3 GPO(PD3); D2 GPO(PD2); D1 GPO(PD1); D0 GPO(PD0); */ - ctrl_outw(0x5555, PORT_PDCR); /* 01 01 01 01 01 01 01 01 */ + __raw_writew(0x5555, PORT_PDCR); /* 01 01 01 01 01 01 01 01 */ /* E7 (x); E6 GPI(nu); E5 GPI(nu); E4 LCD_M_DISP; * E3 LCD_CL1; E2 LCD_CL2; E1 LCD_DON; E0 LCD_FLM; */ - ctrl_outw(0x3C00, PORT_PECR); /* 00 11 11 00 00 00 00 00 */ + __raw_writew(0x3C00, PORT_PECR); /* 00 11 11 00 00 00 00 00 */ /* F7 (x); F6 DA1(VLCD); F5 DA0(nc); F4 AN3; * F3 AN2(MID_AD); F2 AN1(EARTH_AD); F1 AN0(TEMP); F0 GPI+(nc); */ - ctrl_outw(0x0002, PORT_PFCR); /* 00 00 00 00 00 00 00 10 */ + __raw_writew(0x0002, PORT_PFCR); /* 00 00 00 00 00 00 00 10 */ /* G7 (x); G6 IRQ5(TOUCH_BUSY); G5 IRQ4(TOUCH_IRQ); G4 GPI(KEY2); * G3 GPI(KEY1); G2 GPO(LED11); G1 GPO(LED10); G0 GPO(LED9); */ - ctrl_outw(0x03D5, PORT_PGCR); /* 00 00 00 11 11 01 01 01 */ + __raw_writew(0x03D5, PORT_PGCR); /* 00 00 00 11 11 01 01 01 */ /* H7 (x); H6 /RAS(BRAS); H5 /CAS(BCAS); H4 CKE(BCKE); * H3 GPO(EARTH_OFF); H2 GPO(EARTH_TEST); H1 USB2_PWR; H0 USB1_PWR; */ - ctrl_outw(0x0050, PORT_PHCR); /* 00 00 00 00 01 01 00 00 */ + __raw_writew(0x0050, PORT_PHCR); /* 00 00 00 00 01 01 00 00 */ /* J7 (x); J6 AUDCK; J5 ASEBRKAK; J4 AUDATA3; * J3 AUDATA2; J2 AUDATA1; J1 AUDATA0; J0 AUDSYNC; */ - ctrl_outw(0x0000, PORT_PJCR); /* 00 00 00 00 00 00 00 00 */ + __raw_writew(0x0000, PORT_PJCR); /* 00 00 00 00 00 00 00 00 */ /* K7 (x); K6 (x); K5 (x); K4 (x); * K3 PINT7(/PWR2); K2 PINT6(/PWR1); K1 PINT5(nu); K0 PINT4(FLASH_READY) */ - ctrl_outw(0x00FF, PORT_PKCR); /* 00 00 00 00 11 11 11 11 */ + __raw_writew(0x00FF, PORT_PKCR); /* 00 00 00 00 11 11 11 11 */ /* L7 TRST; L6 TMS; L5 TDO; L4 TDI; * L3 TCK; L2 (x); L1 (x); L0 (x); */ - ctrl_outw(0x0000, PORT_PLCR); /* 00 00 00 00 00 00 00 00 */ + __raw_writew(0x0000, PORT_PLCR); /* 00 00 00 00 00 00 00 00 */ /* M7 GPO(CURRENT_SINK); M6 GPO(PWR_SWITCH); M5 GPO(LAN_SPEED); * M4 GPO(LAN_RESET); M3 GPO(BUZZER); M2 GPO(LCD_BL); * M1 CS5B(CAN3_CS); M0 GPI+(nc); */ - ctrl_outw(0x5552, PORT_PMCR); /* 01 01 01 01 01 01 00 10 */ + __raw_writew(0x5552, PORT_PMCR); /* 01 01 01 01 01 01 00 10 */ /* CURRENT_SINK=off, PWR_SWITCH=off, LAN_SPEED=100MBit, * LAN_RESET=off, BUZZER=off, LCD_BL=off */ #if CONFIG_SH_MAGIC_PANEL_R2_VERSION == 2 - ctrl_outb(0x30, PORT_PMDR); + __raw_writeb(0x30, PORT_PMDR); #elif CONFIG_SH_MAGIC_PANEL_R2_VERSION == 3 - ctrl_outb(0xF0, PORT_PMDR); + __raw_writeb(0xF0, PORT_PMDR); #else #error Unknown revision of PLATFORM_MP_R2 #endif @@ -167,8 +167,8 @@ static void __init setup_port_multiplexing(void) * P4 GPO(nu); P3 IRQ3(LAN_IRQ); P2 IRQ2(CAN3_IRQ); * P1 IRQ1(CAN2_IRQ); P0 IRQ0(CAN1_IRQ) */ - ctrl_outw(0x0100, PORT_PPCR); /* 00 00 00 01 00 00 00 00 */ - ctrl_outb(0x10, PORT_PPDR); + __raw_writew(0x0100, PORT_PPCR); /* 00 00 00 01 00 00 00 00 */ + __raw_writeb(0x10, PORT_PPDR); /* R7 A25; R6 A24; R5 A23; R4 A22; * R3 A21; R2 A20; R1 A19; R0 A0; @@ -185,22 +185,22 @@ static void __init setup_port_multiplexing(void) /* S7 (x); S6 (x); S5 (x); S4 GPO(EEPROM_CS2); * S3 GPO(EEPROM_CS1); S2 SIOF0_TXD; S1 SIOF0_RXD; S0 SIOF0_SCK; */ - ctrl_outw(0x0140, PORT_PSCR); /* 00 00 00 01 01 00 00 00 */ + __raw_writew(0x0140, PORT_PSCR); /* 00 00 00 01 01 00 00 00 */ /* T7 (x); T6 (x); T5 (x); T4 COM1_CTS; * T3 COM1_RTS; T2 COM1_TXD; T1 COM1_RXD; T0 GPO(WDOG) */ - ctrl_outw(0x0001, PORT_PTCR); /* 00 00 00 00 00 00 00 01 */ + __raw_writew(0x0001, PORT_PTCR); /* 00 00 00 00 00 00 00 01 */ /* U7 (x); U6 (x); U5 (x); U4 GPI+(/AC_FAULT); * U3 GPO(TOUCH_CS); U2 TOUCH_TXD; U1 TOUCH_RXD; U0 TOUCH_SCK; */ - ctrl_outw(0x0240, PORT_PUCR); /* 00 00 00 10 01 00 00 00 */ + __raw_writew(0x0240, PORT_PUCR); /* 00 00 00 10 01 00 00 00 */ /* V7 (x); V6 (x); V5 (x); V4 GPO(MID2); * V3 GPO(MID1); V2 CARD_TxD; V1 CARD_RxD; V0 GPI+(/BAT_FAULT); */ - ctrl_outw(0x0142, PORT_PVCR); /* 00 00 00 01 01 00 00 10 */ + __raw_writew(0x0142, PORT_PVCR); /* 00 00 00 01 01 00 00 10 */ } static void __init mpr2_setup(char **cmdline_p) @@ -209,24 +209,24 @@ static void __init mpr2_setup(char **cmdline_p) * /PCC_CD1, /PCC_CD2, PCC_BVD1, PCC_BVD2, * /IOIS16, IRQ4, IRQ5, USB1d_SUSPEND */ - ctrl_outw(0xAABC, PORT_PSELA); + __raw_writew(0xAABC, PORT_PSELA); /* set Pin Select Register B: * /SCIF0_RTS, /SCIF0_CTS, LCD_VCPWC, * LCD_VEPWC, IIC_SDA, IIC_SCL, Reserved */ - ctrl_outw(0x3C00, PORT_PSELB); + __raw_writew(0x3C00, PORT_PSELB); /* set Pin Select Register C: * SIOF1_SCK, SIOF1_RxD, SCIF1_RxD, SCIF1_TxD, Reserved */ - ctrl_outw(0x0000, PORT_PSELC); + __raw_writew(0x0000, PORT_PSELC); /* set Pin Select Register D: Reserved, SIOF1_TxD, Reserved, SIOF1_MCLK, * Reserved, SIOF1_SYNC, Reserved, SCIF1_SCK, Reserved */ - ctrl_outw(0x0000, PORT_PSELD); + __raw_writew(0x0000, PORT_PSELD); /* set USB TxRx Control: Reserved, DRV, Reserved, USB_TRANS, USB_SEL */ - ctrl_outw(0x0101, PORT_UTRCTL); + __raw_writew(0x0101, PORT_UTRCTL); /* set USB Clock Control: USSCS, USSTB, Reserved (HighByte always A5) */ - ctrl_outw(0xA5C0, PORT_UCLKCR_W); + __raw_writew(0xA5C0, PORT_UCLKCR_W); setup_chip_select(); diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c index 5bc126900ce3..594866356c24 100644 --- a/arch/sh/boards/board-polaris.c +++ b/arch/sh/boards/board-polaris.c @@ -89,15 +89,15 @@ static int __init polaris_initialise(void) printk(KERN_INFO "Configuring Polaris external bus\n"); /* Configure area 5 with 2 wait states */ - wcr = ctrl_inw(WCR2); + wcr = __raw_readw(WCR2); wcr &= (~AREA5_WAIT_CTRL); wcr |= (WAIT_STATES_10 << 10); - ctrl_outw(wcr, WCR2); + __raw_writew(wcr, WCR2); /* Configure area 5 for 32-bit access */ - bcr_mask = ctrl_inw(BCR2); + bcr_mask = __raw_readw(BCR2); bcr_mask |= 1 << 10; - ctrl_outw(bcr_mask, BCR2); + __raw_writew(bcr_mask, BCR2); return platform_add_devices(polaris_devices, ARRAY_SIZE(polaris_devices)); @@ -128,13 +128,13 @@ static struct ipr_desc ipr_irq_desc = { static void __init init_polaris_irq(void) { /* Disable all interrupts */ - ctrl_outw(0, BCR_ILCRA); - ctrl_outw(0, BCR_ILCRB); - ctrl_outw(0, BCR_ILCRC); - ctrl_outw(0, BCR_ILCRD); - ctrl_outw(0, BCR_ILCRE); - ctrl_outw(0, BCR_ILCRF); - ctrl_outw(0, BCR_ILCRG); + __raw_writew(0, BCR_ILCRA); + __raw_writew(0, BCR_ILCRB); + __raw_writew(0, BCR_ILCRC); + __raw_writew(0, BCR_ILCRD); + __raw_writew(0, BCR_ILCRE); + __raw_writew(0, BCR_ILCRF); + __raw_writew(0, BCR_ILCRG); register_ipr_controller(&ipr_irq_desc); } diff --git a/arch/sh/boards/board-shmin.c b/arch/sh/boards/board-shmin.c index b1dcbbc89188..325bed53b87e 100644 --- a/arch/sh/boards/board-shmin.c +++ b/arch/sh/boards/board-shmin.c @@ -17,8 +17,8 @@ static void __init init_shmin_irq(void) { - ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ - ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active. + __raw_writew(0x2a00, PFC_PHCR); // IRQ0-3=IRQ + __raw_writew(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active. plat_irq_setup_pins(IRQ_MODE_IRQ); } diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 1f5fa5c44f6d..27277cbdb636 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -159,21 +159,21 @@ static void ap320_wvga_power_on(void *board_data) msleep(100); /* ASD AP-320/325 LCD ON */ - ctrl_outw(FPGA_LCDREG_VAL, FPGA_LCDREG); + __raw_writew(FPGA_LCDREG_VAL, FPGA_LCDREG); /* backlight */ gpio_set_value(GPIO_PTS3, 0); - ctrl_outw(0x100, FPGA_BKLREG); + __raw_writew(0x100, FPGA_BKLREG); } static void ap320_wvga_power_off(void *board_data) { /* backlight */ - ctrl_outw(0, FPGA_BKLREG); + __raw_writew(0, FPGA_BKLREG); gpio_set_value(GPIO_PTS3, 1); /* ASD AP-320/325 LCD OFF */ - ctrl_outw(0, FPGA_LCDREG); + __raw_writew(0, FPGA_LCDREG); } static struct sh_mobile_lcdc_info lcdc_info = { @@ -595,7 +595,7 @@ static int __init ap325rxa_devices_setup(void) gpio_request(GPIO_PTZ4, NULL); gpio_direction_output(GPIO_PTZ4, 0); /* SADDR */ - ctrl_outw(ctrl_inw(PORT_MSELCRB) & ~0x0001, PORT_MSELCRB); + __raw_writew(__raw_readw(PORT_MSELCRB) & ~0x0001, PORT_MSELCRB); /* FLCTL */ gpio_request(GPIO_FN_FCE, NULL); @@ -613,9 +613,9 @@ static int __init ap325rxa_devices_setup(void) gpio_request(GPIO_FN_FWE, NULL); gpio_request(GPIO_FN_FRB, NULL); - ctrl_outw(0, PORT_HIZCRC); - ctrl_outw(0xFFFF, PORT_DRVCRA); - ctrl_outw(0xFFFF, PORT_DRVCRB); + __raw_writew(0, PORT_HIZCRC); + __raw_writew(0xFFFF, PORT_DRVCRA); + __raw_writew(0xFFFF, PORT_DRVCRB); platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20); diff --git a/arch/sh/boards/mach-cayman/irq.c b/arch/sh/boards/mach-cayman/irq.c index 33f770856319..1394b078db36 100644 --- a/arch/sh/boards/mach-cayman/irq.c +++ b/arch/sh/boards/mach-cayman/irq.c @@ -66,9 +66,9 @@ static void enable_cayman_irq(unsigned int irq) reg = EPLD_MASK_BASE + ((irq / 8) << 2); bit = 1<<(irq % 8); local_irq_save(flags); - mask = ctrl_inl(reg); + mask = __raw_readl(reg); mask |= bit; - ctrl_outl(mask, reg); + __raw_writel(mask, reg); local_irq_restore(flags); } @@ -83,9 +83,9 @@ void disable_cayman_irq(unsigned int irq) reg = EPLD_MASK_BASE + ((irq / 8) << 2); bit = 1<<(irq % 8); local_irq_save(flags); - mask = ctrl_inl(reg); + mask = __raw_readl(reg); mask &= ~bit; - ctrl_outl(mask, reg); + __raw_writel(mask, reg); local_irq_restore(flags); } @@ -109,8 +109,8 @@ int cayman_irq_demux(int evt) unsigned long status; int i; - status = ctrl_inl(EPLD_STATUS_BASE) & - ctrl_inl(EPLD_MASK_BASE) & 0xff; + status = __raw_readl(EPLD_STATUS_BASE) & + __raw_readl(EPLD_MASK_BASE) & 0xff; if (status == 0) { irq = -1; } else { @@ -126,8 +126,8 @@ int cayman_irq_demux(int evt) unsigned long status; int i; - status = ctrl_inl(EPLD_STATUS_BASE + 3 * sizeof(u32)) & - ctrl_inl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff; + status = __raw_readl(EPLD_STATUS_BASE + 3 * sizeof(u32)) & + __raw_readl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff; if (status == 0) { irq = -1; } else { diff --git a/arch/sh/boards/mach-dreamcast/rtc.c b/arch/sh/boards/mach-dreamcast/rtc.c index a7433685798d..061d65714fcc 100644 --- a/arch/sh/boards/mach-dreamcast/rtc.c +++ b/arch/sh/boards/mach-dreamcast/rtc.c @@ -35,11 +35,11 @@ static void aica_rtc_gettimeofday(struct timespec *ts) unsigned long val1, val2; do { - val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | - (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); + val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | + (__raw_readl(AICA_RTC_SECS_L) & 0xffff); - val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | - (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); + val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | + (__raw_readl(AICA_RTC_SECS_L) & 0xffff); } while (val1 != val2); ts->tv_sec = val1 - TWENTY_YEARS; @@ -60,14 +60,14 @@ static int aica_rtc_settimeofday(const time_t secs) unsigned long adj = secs + TWENTY_YEARS; do { - ctrl_outl((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); - ctrl_outl((adj & 0xffff), AICA_RTC_SECS_L); + __raw_writel((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); + __raw_writel((adj & 0xffff), AICA_RTC_SECS_L); - val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | - (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); + val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | + (__raw_readl(AICA_RTC_SECS_L) & 0xffff); - val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | - (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); + val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | + (__raw_readl(AICA_RTC_SECS_L) & 0xffff); } while (val1 != val2); return 0; diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index a49cce16e783..1135c3b848f2 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -696,13 +696,13 @@ static struct platform_device camera_devices[] = { #define FCLKBCR 0xa415000c static void fsimck_init(struct clk *clk) { - u32 status = ctrl_inl(clk->enable_reg); + u32 status = __raw_readl(clk->enable_reg); /* use external clock */ status &= ~0x000000ff; status |= 0x00000080; - ctrl_outl(status, clk->enable_reg); + __raw_writel(status, clk->enable_reg); } static struct clk_ops fsimck_clk_ops = { @@ -853,7 +853,7 @@ static int __init arch_setup(void) gpio_direction_output(GPIO_PTG1, 0); gpio_direction_output(GPIO_PTG2, 0); gpio_direction_output(GPIO_PTG3, 0); - ctrl_outw((ctrl_inw(PORT_HIZA) & ~(0x1 << 1)) , PORT_HIZA); + __raw_writew((__raw_readw(PORT_HIZA) & ~(0x1 << 1)) , PORT_HIZA); /* enable SH-Eth */ gpio_request(GPIO_PTA1, NULL); @@ -873,16 +873,16 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_LNKSTA, NULL); /* enable USB */ - ctrl_outw(0x0000, 0xA4D80000); - ctrl_outw(0x0000, 0xA4D90000); + __raw_writew(0x0000, 0xA4D80000); + __raw_writew(0x0000, 0xA4D90000); gpio_request(GPIO_PTB3, NULL); gpio_request(GPIO_PTB4, NULL); gpio_request(GPIO_PTB5, NULL); gpio_direction_input(GPIO_PTB3); gpio_direction_output(GPIO_PTB4, 0); gpio_direction_output(GPIO_PTB5, 0); - ctrl_outw(0x0600, 0xa40501d4); - ctrl_outw(0x0600, 0xa4050192); + __raw_writew(0x0600, 0xa40501d4); + __raw_writew(0x0600, 0xa4050192); if (gpio_get_value(GPIO_PTB3)) { printk(KERN_INFO "USB1 function is selected\n"); @@ -923,7 +923,7 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_LCDVSYN, NULL); gpio_request(GPIO_FN_LCDDON, NULL); gpio_request(GPIO_FN_LCDLCLK, NULL); - ctrl_outw((ctrl_inw(PORT_HIZA) & ~0x0001), PORT_HIZA); + __raw_writew((__raw_readw(PORT_HIZA) & ~0x0001), PORT_HIZA); gpio_request(GPIO_PTE6, NULL); gpio_request(GPIO_PTU1, NULL); @@ -935,7 +935,7 @@ static int __init arch_setup(void) gpio_direction_output(GPIO_PTA2, 0); /* I/O buffer drive ability is high */ - ctrl_outw((ctrl_inw(IODRIVEA) & ~0x00c0) | 0x0080 , IODRIVEA); + __raw_writew((__raw_readw(IODRIVEA) & ~0x00c0) | 0x0080 , IODRIVEA); if (gpio_get_value(GPIO_PTE6)) { /* DVI */ @@ -1067,7 +1067,7 @@ static int __init arch_setup(void) gpio_direction_output(GPIO_PTB7, 0); /* I/O buffer drive ability is high for SDHI1 */ - ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA); + __raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA); #else /* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */ gpio_request(GPIO_FN_MSIOF0_TXD, NULL); diff --git a/arch/sh/boards/mach-highlander/irq-r7780mp.c b/arch/sh/boards/mach-highlander/irq-r7780mp.c index 83c28bcd4d2a..9893fd3a1358 100644 --- a/arch/sh/boards/mach-highlander/irq-r7780mp.c +++ b/arch/sh/boards/mach-highlander/irq-r7780mp.c @@ -64,7 +64,7 @@ static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors, unsigned char * __init highlander_plat_irq_setup(void) { - if ((ctrl_inw(0xa4000700) & 0xf000) == 0x2000) { + if ((__raw_readw(0xa4000700) & 0xf000) == 0x2000) { printk(KERN_INFO "Using r7780mp interrupt controller.\n"); register_intc_controller(&intc_desc); return irl2irq; diff --git a/arch/sh/boards/mach-highlander/irq-r7780rp.c b/arch/sh/boards/mach-highlander/irq-r7780rp.c index b721e86b5af4..0805b2151452 100644 --- a/arch/sh/boards/mach-highlander/irq-r7780rp.c +++ b/arch/sh/boards/mach-highlander/irq-r7780rp.c @@ -57,7 +57,7 @@ static DECLARE_INTC_DESC(intc_desc, "r7780rp", vectors, unsigned char * __init highlander_plat_irq_setup(void) { - if (ctrl_inw(0xa5000600)) { + if (__raw_readw(0xa5000600)) { printk(KERN_INFO "Using r7780rp interrupt controller.\n"); register_intc_controller(&intc_desc); return irl2irq; diff --git a/arch/sh/boards/mach-highlander/irq-r7785rp.c b/arch/sh/boards/mach-highlander/irq-r7785rp.c index 3811b060a39b..558b24862776 100644 --- a/arch/sh/boards/mach-highlander/irq-r7785rp.c +++ b/arch/sh/boards/mach-highlander/irq-r7785rp.c @@ -66,20 +66,20 @@ static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors, unsigned char * __init highlander_plat_irq_setup(void) { - if ((ctrl_inw(0xa4000158) & 0xf000) != 0x1000) + if ((__raw_readw(0xa4000158) & 0xf000) != 0x1000) return NULL; printk(KERN_INFO "Using r7785rp interrupt controller.\n"); - ctrl_outw(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */ + __raw_writew(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */ /* Setup the FPGA IRL */ - ctrl_outw(0x0000, PA_IRLPRA); /* FPGA IRLA */ - ctrl_outw(0xe598, PA_IRLPRB); /* FPGA IRLB */ - ctrl_outw(0x7060, PA_IRLPRC); /* FPGA IRLC */ - ctrl_outw(0x0000, PA_IRLPRD); /* FPGA IRLD */ - ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */ - ctrl_outw(0xdcba, PA_IRLPRF); /* FPGA IRLF */ + __raw_writew(0x0000, PA_IRLPRA); /* FPGA IRLA */ + __raw_writew(0xe598, PA_IRLPRB); /* FPGA IRLB */ + __raw_writew(0x7060, PA_IRLPRC); /* FPGA IRLC */ + __raw_writew(0x0000, PA_IRLPRD); /* FPGA IRLD */ + __raw_writew(0x4321, PA_IRLPRE); /* FPGA IRLE */ + __raw_writew(0xdcba, PA_IRLPRF); /* FPGA IRLF */ register_intc_controller(&intc_desc); return irl2irq; diff --git a/arch/sh/boards/mach-highlander/psw.c b/arch/sh/boards/mach-highlander/psw.c index 37b1a2ee71a5..522786318d36 100644 --- a/arch/sh/boards/mach-highlander/psw.c +++ b/arch/sh/boards/mach-highlander/psw.c @@ -24,7 +24,7 @@ static irqreturn_t psw_irq_handler(int irq, void *arg) unsigned int l, mask; int ret = 0; - l = ctrl_inw(PA_DBSW); + l = __raw_readw(PA_DBSW); /* Nothing to do if there's no state change */ if (psw->state) { @@ -45,7 +45,7 @@ static irqreturn_t psw_irq_handler(int irq, void *arg) out: /* Clear the switch IRQs */ l |= (0x7 << 12); - ctrl_outw(l, PA_DBSW); + __raw_writew(l, PA_DBSW); return IRQ_RETVAL(ret); } diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c index f663c14d8885..affd66747ba3 100644 --- a/arch/sh/boards/mach-highlander/setup.c +++ b/arch/sh/boards/mach-highlander/setup.c @@ -311,13 +311,13 @@ device_initcall(r7780rp_devices_setup); */ static int ivdr_clk_enable(struct clk *clk) { - ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL); + __raw_writew(__raw_readw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL); return 0; } static void ivdr_clk_disable(struct clk *clk) { - ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL); + __raw_writew(__raw_readw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL); } static struct clk_ops ivdr_clk_ops = { @@ -337,7 +337,7 @@ static struct clk *r7780rp_clocks[] = { static void r7780rp_power_off(void) { if (mach_is_r7780mp() || mach_is_r7785rp()) - ctrl_outw(0x0001, PA_POFF); + __raw_writew(0x0001, PA_POFF); } /* @@ -345,7 +345,7 @@ static void r7780rp_power_off(void) */ static void __init highlander_setup(char **cmdline_p) { - u16 ver = ctrl_inw(PA_VERREG); + u16 ver = __raw_readw(PA_VERREG); int i; printk(KERN_INFO "Renesas Solutions Highlander %s support.\n", @@ -370,12 +370,12 @@ static void __init highlander_setup(char **cmdline_p) clk_enable(clk); } - ctrl_outw(0x0000, PA_OBLED); /* Clear LED. */ + __raw_writew(0x0000, PA_OBLED); /* Clear LED. */ if (mach_is_r7780rp()) - ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */ + __raw_writew(0x0001, PA_SDPOW); /* SD Power ON */ - ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x01, PA_IVDRCTL); /* Si13112 */ + __raw_writew(__raw_readw(PA_IVDRCTL) | 0x01, PA_IVDRCTL); /* Si13112 */ pm_power_off = r7780rp_power_off; } diff --git a/arch/sh/boards/mach-hp6xx/hp6xx_apm.c b/arch/sh/boards/mach-hp6xx/hp6xx_apm.c index e85212faf40a..b49535c0ddd9 100644 --- a/arch/sh/boards/mach-hp6xx/hp6xx_apm.c +++ b/arch/sh/boards/mach-hp6xx/hp6xx_apm.c @@ -53,7 +53,7 @@ static void hp6x0_apm_get_power_status(struct apm_power_info *info) info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ? APM_AC_ONLINE : APM_AC_OFFLINE; - pgdr = ctrl_inb(PGDR); + pgdr = __raw_readb(PGDR); if (pgdr & PGDR_MAIN_BATTERY_OUT) { info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT; info->battery_flag = 0x80; diff --git a/arch/sh/boards/mach-hp6xx/pm.c b/arch/sh/boards/mach-hp6xx/pm.c index d936c1af7620..4499a3749d40 100644 --- a/arch/sh/boards/mach-hp6xx/pm.c +++ b/arch/sh/boards/mach-hp6xx/pm.c @@ -53,17 +53,17 @@ static void pm_enter(void) sh_wdt_write_cnt(0); /* disable PLL1 */ - frqcr = ctrl_inw(FRQCR); + frqcr = __raw_readw(FRQCR); frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY); - ctrl_outw(frqcr, FRQCR); + __raw_writew(frqcr, FRQCR); /* enable standby */ - stbcr = ctrl_inb(STBCR); - ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); + stbcr = __raw_readb(STBCR); + __raw_writeb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); /* set self-refresh */ - mcr = ctrl_inw(MCR); - ctrl_outw(mcr & ~MCR_RFSH, MCR); + mcr = __raw_readw(MCR); + __raw_writew(mcr & ~MCR_RFSH, MCR); /* set interrupt handler */ asm volatile("stc vbr, %0" : "=r" (vbr_old)); @@ -73,8 +73,8 @@ static void pm_enter(void) &wakeup_start, &wakeup_end - &wakeup_start); asm volatile("ldc %0, vbr" : : "r" (vbr_new)); - ctrl_outw(0, RTCNT); - ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR); + __raw_writew(0, RTCNT); + __raw_writew(mcr | MCR_RFSH | MCR_RMODE, MCR); cpu_sleep(); @@ -83,14 +83,14 @@ static void pm_enter(void) free_page(vbr_new); /* enable PLL1 */ - frqcr = ctrl_inw(FRQCR); + frqcr = __raw_readw(FRQCR); frqcr |= FRQCR_PSTBY; - ctrl_outw(frqcr, FRQCR); + __raw_writew(frqcr, FRQCR); udelay(50); frqcr |= FRQCR_PLLEN; - ctrl_outw(frqcr, FRQCR); + __raw_writew(frqcr, FRQCR); - ctrl_outb(stbcr, STBCR); + __raw_writeb(stbcr, STBCR); clear_bl_bit(); } @@ -115,21 +115,21 @@ static int hp6x0_pm_enter(suspend_state_t state) outw(hd64461_stbcr, HD64461_STBCR); #endif - ctrl_outb(0x1f, DACR); + __raw_writeb(0x1f, DACR); - stbcr = ctrl_inb(STBCR); - ctrl_outb(0x01, STBCR); + stbcr = __raw_readb(STBCR); + __raw_writeb(0x01, STBCR); - stbcr2 = ctrl_inb(STBCR2); - ctrl_outb(0x7f , STBCR2); + stbcr2 = __raw_readb(STBCR2); + __raw_writeb(0x7f , STBCR2); outw(0xf07f, HD64461_SCPUCR); pm_enter(); outw(0, HD64461_SCPUCR); - ctrl_outb(stbcr, STBCR); - ctrl_outb(stbcr2, STBCR2); + __raw_writeb(stbcr, STBCR); + __raw_writeb(stbcr2, STBCR2); #ifdef CONFIG_HD64461_ENABLER hd64461_stbcr = inw(HD64461_STBCR); diff --git a/arch/sh/boards/mach-hp6xx/setup.c b/arch/sh/boards/mach-hp6xx/setup.c index e6dd5e96321e..8c9add5f4cfa 100644 --- a/arch/sh/boards/mach-hp6xx/setup.c +++ b/arch/sh/boards/mach-hp6xx/setup.c @@ -149,19 +149,19 @@ static void __init hp6xx_setup(char **cmdline_p) sh_dac_output(0, DAC_SPEAKER_VOLUME); sh_dac_disable(DAC_SPEAKER_VOLUME); - v8 = ctrl_inb(DACR); + v8 = __raw_readb(DACR); v8 &= ~DACR_DAE; - ctrl_outb(v8,DACR); + __raw_writeb(v8,DACR); - v8 = ctrl_inb(SCPDR); + v8 = __raw_readb(SCPDR); v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y; v8 &= ~SCPDR_TS_SCAN_ENABLE; - ctrl_outb(v8, SCPDR); + __raw_writeb(v8, SCPDR); - v = ctrl_inw(SCPCR); + v = __raw_readw(SCPCR); v &= ~SCPCR_TS_MASK; v |= SCPCR_TS_ENABLE; - ctrl_outw(v, SCPCR); + __raw_writew(v, SCPCR); } device_initcall(hp6xx_devices_setup); diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 5d7b5d92475e..ca9e82d77d0a 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -282,7 +282,7 @@ static int camera_power(struct device *dev, int mode) * use 1.8 V for VccQ_VIO * use 2.85V for VccQ_SR */ - ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB); + __raw_writew((__raw_readw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB); /* reset clear */ ret = gpio_request(GPIO_PTB4, NULL); @@ -492,13 +492,13 @@ static int kfr2r09_usb0_gadget_setup(void) if (kfr2r09_usb0_gadget_i2c_setup() != 0) return -ENODEV; /* unable to configure using i2c */ - ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); + __raw_writew((__raw_readw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); gpio_request(GPIO_FN_PDSTATUS, NULL); /* R-standby disables USB clock */ gpio_request(GPIO_PTV6, NULL); /* USBCLK_ON */ gpio_direction_output(GPIO_PTV6, 1); /* USBCLK_ON = H */ msleep(20); /* wait 20ms to let the clock settle */ clk_enable(clk_get(NULL, "usb0")); - ctrl_outw(0x0600, 0xa40501d4); + __raw_writew(0x0600, 0xa40501d4); return 0; } @@ -526,12 +526,12 @@ static int __init kfr2r09_devices_setup(void) gpio_direction_output(GPIO_PTG3, 1); /* HPON_ON = H */ /* setup NOR flash at CS0 */ - ctrl_outl(0x36db0400, BSC_CS0BCR); - ctrl_outl(0x00000500, BSC_CS0WCR); + __raw_writel(0x36db0400, BSC_CS0BCR); + __raw_writel(0x00000500, BSC_CS0WCR); /* setup NAND flash at CS4 */ - ctrl_outl(0x36db0400, BSC_CS4BCR); - ctrl_outl(0x00000500, BSC_CS4WCR); + __raw_writel(0x36db0400, BSC_CS4BCR); + __raw_writel(0x00000500, BSC_CS4WCR); /* setup KEYSC pins */ gpio_request(GPIO_FN_KEYOUT0, NULL); diff --git a/arch/sh/boards/mach-landisk/gio.c b/arch/sh/boards/mach-landisk/gio.c index 528013188196..01e6abb769b9 100644 --- a/arch/sh/boards/mach-landisk/gio.c +++ b/arch/sh/boards/mach-landisk/gio.c @@ -76,39 +76,39 @@ static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; case GIODRV_IOCSGIODATA1: /* write byte */ - ctrl_outb((unsigned char)(0x0ff & data), addr); + __raw_writeb((unsigned char)(0x0ff & data), addr); break; case GIODRV_IOCSGIODATA2: /* write word */ if (addr & 0x01) { return -EFAULT; } - ctrl_outw((unsigned short int)(0x0ffff & data), addr); + __raw_writew((unsigned short int)(0x0ffff & data), addr); break; case GIODRV_IOCSGIODATA4: /* write long */ if (addr & 0x03) { return -EFAULT; } - ctrl_outl(data, addr); + __raw_writel(data, addr); break; case GIODRV_IOCGGIODATA1: /* read byte */ - data = ctrl_inb(addr); + data = __raw_readb(addr); break; case GIODRV_IOCGGIODATA2: /* read word */ if (addr & 0x01) { return -EFAULT; } - data = ctrl_inw(addr); + data = __raw_readw(addr); break; case GIODRV_IOCGGIODATA4: /* read long */ if (addr & 0x03) { return -EFAULT; } - data = ctrl_inl(addr); + data = __raw_readl(addr); break; default: return -EFAULT; diff --git a/arch/sh/boards/mach-landisk/irq.c b/arch/sh/boards/mach-landisk/irq.c index 7b284cde1f58..96f38a4187d0 100644 --- a/arch/sh/boards/mach-landisk/irq.c +++ b/arch/sh/boards/mach-landisk/irq.c @@ -22,14 +22,14 @@ static void disable_landisk_irq(unsigned int irq) { unsigned char mask = 0xff ^ (0x01 << (irq - 5)); - ctrl_outb(ctrl_inb(PA_IMASK) & mask, PA_IMASK); + __raw_writeb(__raw_readb(PA_IMASK) & mask, PA_IMASK); } static void enable_landisk_irq(unsigned int irq) { unsigned char value = (0x01 << (irq - 5)); - ctrl_outb(ctrl_inb(PA_IMASK) | value, PA_IMASK); + __raw_writeb(__raw_readb(PA_IMASK) | value, PA_IMASK); } static struct irq_chip landisk_irq_chip __read_mostly = { @@ -52,5 +52,5 @@ void __init init_landisk_IRQ(void) handle_level_irq, "level"); enable_landisk_irq(i); } - ctrl_outb(0x00, PA_PWRINT_CLR); + __raw_writeb(0x00, PA_PWRINT_CLR); } diff --git a/arch/sh/boards/mach-landisk/psw.c b/arch/sh/boards/mach-landisk/psw.c index e6b0efa098d1..bef83522f958 100644 --- a/arch/sh/boards/mach-landisk/psw.c +++ b/arch/sh/boards/mach-landisk/psw.c @@ -25,7 +25,7 @@ static irqreturn_t psw_irq_handler(int irq, void *arg) unsigned int sw_value; int ret = 0; - sw_value = (0x0ff & (~ctrl_inb(PA_STATUS))); + sw_value = (0x0ff & (~__raw_readb(PA_STATUS))); /* Nothing to do if there's no state change */ if (psw->state) { @@ -42,7 +42,7 @@ static irqreturn_t psw_irq_handler(int irq, void *arg) out: /* Clear the switch IRQs */ - ctrl_outb(0x00, PA_PWRINT_CLR); + __raw_writeb(0x00, PA_PWRINT_CLR); return IRQ_RETVAL(ret); } diff --git a/arch/sh/boards/mach-landisk/setup.c b/arch/sh/boards/mach-landisk/setup.c index 2d09d4d34f87..50337acc18c5 100644 --- a/arch/sh/boards/mach-landisk/setup.c +++ b/arch/sh/boards/mach-landisk/setup.c @@ -25,7 +25,7 @@ void init_landisk_IRQ(void); static void landisk_power_off(void) { - ctrl_outb(0x01, PA_SHUTDOWN); + __raw_writeb(0x01, PA_SHUTDOWN); } static struct resource cf_ide_resources[3]; @@ -88,7 +88,7 @@ __initcall(landisk_devices_setup); static void __init landisk_setup(char **cmdline_p) { /* LED ON */ - ctrl_outb(ctrl_inb(PA_LED) | 0x03, PA_LED); + __raw_writeb(__raw_readb(PA_LED) | 0x03, PA_LED); printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n"); pm_power_off = landisk_power_off; diff --git a/arch/sh/boards/mach-microdev/io.c b/arch/sh/boards/mach-microdev/io.c index 52dd748211c7..2960c659020e 100644 --- a/arch/sh/boards/mach-microdev/io.c +++ b/arch/sh/boards/mach-microdev/io.c @@ -141,10 +141,10 @@ static inline void delay(void) #if defined(CONFIG_PCI) /* System board present, just make a dummy SRAM access. (CS0 will be mapped to PCI memory, probably good to avoid it.) */ - ctrl_inw(0xa6800000); + __raw_readw(0xa6800000); #else /* CS0 will be mapped to flash, ROM etc so safe to access it. */ - ctrl_inw(0xa0000000); + __raw_readw(0xa0000000); #endif } diff --git a/arch/sh/boards/mach-microdev/irq.c b/arch/sh/boards/mach-microdev/irq.c index b551963579c1..a26d16669aa2 100644 --- a/arch/sh/boards/mach-microdev/irq.c +++ b/arch/sh/boards/mach-microdev/irq.c @@ -88,7 +88,7 @@ static void disable_microdev_irq(unsigned int irq) fpgaIrq = fpgaIrqTable[irq].fpgaIrq; /* disable interrupts on the FPGA INTC register */ - ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG); + __raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG); } static void enable_microdev_irq(unsigned int irq) @@ -107,13 +107,13 @@ static void enable_microdev_irq(unsigned int irq) priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq); /* set priority for the interrupt */ - priorities = ctrl_inl(priorityReg); + priorities = __raw_readl(priorityReg); priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq); priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri); - ctrl_outl(priorities, priorityReg); + __raw_writel(priorities, priorityReg); /* enable interrupts on the FPGA INTC register */ - ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG); + __raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG); } /* This function sets the desired irq handler to be a MicroDev type */ @@ -134,7 +134,7 @@ extern void __init init_microdev_irq(void) int i; /* disable interrupts on the FPGA INTC register */ - ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG); + __raw_writel(~0ul, MICRODEV_FPGA_INTDSB_REG); for (i = 0; i < NUM_EXTERNAL_IRQS; i++) make_microdev_irq(i); diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 507c77be476d..ed2eeeb390a5 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -516,8 +516,8 @@ static int __init migor_devices_setup(void) /* SMC91C111 - Enable IRQ0, Setup CS4 for 16-bit fast access */ gpio_request(GPIO_FN_IRQ0, NULL); - ctrl_outl(0x00003400, BSC_CS4BCR); - ctrl_outl(0x00110080, BSC_CS4WCR); + __raw_writel(0x00003400, BSC_CS4BCR); + __raw_writel(0x00110080, BSC_CS4WCR); /* KEYSC */ gpio_request(GPIO_FN_KEYOUT0, NULL); @@ -533,7 +533,7 @@ static int __init migor_devices_setup(void) /* NAND Flash */ gpio_request(GPIO_FN_CS6A_CE2B, NULL); - ctrl_outl((ctrl_inl(BSC_CS6ABCR) & ~0x0600) | 0x0200, BSC_CS6ABCR); + __raw_writel((__raw_readl(BSC_CS6ABCR) & ~0x0600) | 0x0200, BSC_CS6ABCR); gpio_request(GPIO_PTA1, NULL); gpio_direction_input(GPIO_PTA1); @@ -627,7 +627,7 @@ static int __init migor_devices_setup(void) #else gpio_direction_output(GPIO_PTT0, 1); #endif - ctrl_outw(ctrl_inw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */ + __raw_writew(__raw_readw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */ platform_resource_setup_memory(&migor_ceu_device, "ceu", 4 << 20); diff --git a/arch/sh/boards/mach-r2d/irq.c b/arch/sh/boards/mach-r2d/irq.c index 78d7b27c80da..574f009c3c31 100644 --- a/arch/sh/boards/mach-r2d/irq.c +++ b/arch/sh/boards/mach-r2d/irq.c @@ -129,7 +129,7 @@ void __init init_rts7751r2d_IRQ(void) { struct intc_desc *d; - switch (ctrl_inw(PA_VERREG) & 0xf0) { + switch (__raw_readw(PA_VERREG) & 0xf0) { #ifdef CONFIG_RTS7751R2D_PLUS case 0x10: printk(KERN_INFO "Using R2D-PLUS interrupt controller.\n"); @@ -147,7 +147,7 @@ void __init init_rts7751r2d_IRQ(void) #endif default: printk(KERN_INFO "Unknown R2D interrupt controller 0x%04x\n", - ctrl_inw(PA_VERREG)); + __raw_readw(PA_VERREG)); return; } diff --git a/arch/sh/boards/mach-r2d/setup.c b/arch/sh/boards/mach-r2d/setup.c index a625ecb93e47..b84df6a3a93c 100644 --- a/arch/sh/boards/mach-r2d/setup.c +++ b/arch/sh/boards/mach-r2d/setup.c @@ -70,7 +70,7 @@ static struct spi_board_info spi_bus[] = { static void r2d_chip_select(struct sh_spi_info *spi, int cs, int state) { BUG_ON(cs != 0); /* Single Epson RTC-9701JE attached on CS0 */ - ctrl_outw(state == BITBANG_CS_ACTIVE, PA_RTCCE); + __raw_writew(state == BITBANG_CS_ACTIVE, PA_RTCCE); } static struct sh_spi_info spi_info = { @@ -262,7 +262,7 @@ __initcall(rts7751r2d_devices_setup); static void rts7751r2d_power_off(void) { - ctrl_outw(0x0001, PA_POWOFF); + __raw_writew(0x0001, PA_POWOFF); } /* @@ -271,14 +271,14 @@ static void rts7751r2d_power_off(void) static void __init rts7751r2d_setup(char **cmdline_p) { void __iomem *sm501_reg; - u16 ver = ctrl_inw(PA_VERREG); + u16 ver = __raw_readw(PA_VERREG); printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n"); printk(KERN_INFO "FPGA version:%d (revision:%d)\n", (ver >> 4) & 0xf, ver & 0xf); - ctrl_outw(0x0000, PA_OUTPORT); + __raw_writew(0x0000, PA_OUTPORT); pm_power_off = rts7751r2d_power_off; /* sm501 dram configuration: diff --git a/arch/sh/boards/mach-rsk/devices-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c index c37617e63220..4fa08ba10253 100644 --- a/arch/sh/boards/mach-rsk/devices-rsk7203.c +++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c @@ -96,7 +96,7 @@ static int __init rsk7203_devices_setup(void) gpio_request(GPIO_FN_RXD0, NULL); /* Setup LAN9118: CS1 in 16-bit Big Endian Mode, IRQ0 at Port B */ - ctrl_outl(0x36db0400, 0xfffc0008); /* CS1BCR */ + __raw_writel(0x36db0400, 0xfffc0008); /* CS1BCR */ gpio_request(GPIO_FN_IRQ0_PB, NULL); return platform_add_devices(rsk7203_devices, diff --git a/arch/sh/boards/mach-sdk7780/irq.c b/arch/sh/boards/mach-sdk7780/irq.c index 855558163c58..e5f7564f2511 100644 --- a/arch/sh/boards/mach-sdk7780/irq.c +++ b/arch/sh/boards/mach-sdk7780/irq.c @@ -37,9 +37,9 @@ void __init init_sdk7780_IRQ(void) { printk(KERN_INFO "Using SDK7780 interrupt controller.\n"); - ctrl_outw(0xFFFF, FPGA_IRQ0MR); + __raw_writew(0xFFFF, FPGA_IRQ0MR); /* Setup IRL 0-3 */ - ctrl_outw(0x0003, FPGA_IMSR); + __raw_writew(0x0003, FPGA_IMSR); plat_irq_setup_pins(IRQ_MODE_IRL3210); register_intc_controller(&fpga_intc_desc); diff --git a/arch/sh/boards/mach-sdk7780/setup.c b/arch/sh/boards/mach-sdk7780/setup.c index b887373a2599..4da38db4b5fe 100644 --- a/arch/sh/boards/mach-sdk7780/setup.c +++ b/arch/sh/boards/mach-sdk7780/setup.c @@ -74,8 +74,8 @@ device_initcall(sdk7780_devices_setup); static void __init sdk7780_setup(char **cmdline_p) { - u16 ver = ctrl_inw(FPGA_FPVERR); - u16 dateStamp = ctrl_inw(FPGA_FPDATER); + u16 ver = __raw_readw(FPGA_FPVERR); + u16 dateStamp = __raw_readw(FPGA_FPDATER); printk(KERN_INFO "Renesas Technology Europe SDK7780 support.\n"); printk(KERN_INFO "Board version: %d (revision %d), " @@ -85,7 +85,7 @@ static void __init sdk7780_setup(char **cmdline_p) dateStamp); /* Setup pin mux'ing for PCIC */ - ctrl_outw(0x0000, GPIO_PECR); + __raw_writew(0x0000, GPIO_PECR); } /* diff --git a/arch/sh/boards/mach-se/7206/io.c b/arch/sh/boards/mach-se/7206/io.c index 180455642a43..adadc77532ee 100644 --- a/arch/sh/boards/mach-se/7206/io.c +++ b/arch/sh/boards/mach-se/7206/io.c @@ -16,7 +16,7 @@ static inline void delay(void) { - ctrl_inw(0x20000000); /* P2 ROM Area */ + __raw_readw(0x20000000); /* P2 ROM Area */ } /* MS7750 requires special versions of in*, out* routines, since diff --git a/arch/sh/boards/mach-se/7206/irq.c b/arch/sh/boards/mach-se/7206/irq.c index aef7f052851a..79be4bc59933 100644 --- a/arch/sh/boards/mach-se/7206/irq.c +++ b/arch/sh/boards/mach-se/7206/irq.c @@ -32,12 +32,12 @@ static void disable_se7206_irq(unsigned int irq) unsigned short msk0,msk1; /* Set the priority in IPR to 0 */ - val = ctrl_inw(INTC_IPR01); + val = __raw_readw(INTC_IPR01); val &= mask; - ctrl_outw(val, INTC_IPR01); + __raw_writew(val, INTC_IPR01); /* FPGA mask set */ - msk0 = ctrl_inw(INTMSK0); - msk1 = ctrl_inw(INTMSK1); + msk0 = __raw_readw(INTMSK0); + msk1 = __raw_readw(INTMSK1); switch (irq) { case IRQ0_IRQ: @@ -51,8 +51,8 @@ static void disable_se7206_irq(unsigned int irq) msk1 |= 0x00ff; break; } - ctrl_outw(msk0, INTMSK0); - ctrl_outw(msk1, INTMSK1); + __raw_writew(msk0, INTMSK0); + __raw_writew(msk1, INTMSK1); } static void enable_se7206_irq(unsigned int irq) @@ -62,13 +62,13 @@ static void enable_se7206_irq(unsigned int irq) unsigned short msk0,msk1; /* Set priority in IPR back to original value */ - val = ctrl_inw(INTC_IPR01); + val = __raw_readw(INTC_IPR01); val |= value; - ctrl_outw(val, INTC_IPR01); + __raw_writew(val, INTC_IPR01); /* FPGA mask reset */ - msk0 = ctrl_inw(INTMSK0); - msk1 = ctrl_inw(INTMSK1); + msk0 = __raw_readw(INTMSK0); + msk1 = __raw_readw(INTMSK1); switch (irq) { case IRQ0_IRQ: @@ -82,8 +82,8 @@ static void enable_se7206_irq(unsigned int irq) msk1 &= ~0x00ff; break; } - ctrl_outw(msk0, INTMSK0); - ctrl_outw(msk1, INTMSK1); + __raw_writew(msk0, INTMSK0); + __raw_writew(msk1, INTMSK1); } static void eoi_se7206_irq(unsigned int irq) @@ -93,8 +93,8 @@ static void eoi_se7206_irq(unsigned int irq) if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_se7206_irq(irq); /* FPGA isr clear */ - sts0 = ctrl_inw(INTSTS0); - sts1 = ctrl_inw(INTSTS1); + sts0 = __raw_readw(INTSTS0); + sts1 = __raw_readw(INTSTS1); switch (irq) { case IRQ0_IRQ: @@ -108,8 +108,8 @@ static void eoi_se7206_irq(unsigned int irq) sts1 &= ~0x00ff; break; } - ctrl_outw(sts0, INTSTS0); - ctrl_outw(sts1, INTSTS1); + __raw_writew(sts0, INTSTS0); + __raw_writew(sts1, INTSTS1); } static struct irq_chip se7206_irq_chip __read_mostly = { @@ -136,11 +136,11 @@ void __init init_se7206_IRQ(void) make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */ make_se7206_irq(IRQ1_IRQ); /* ATA */ make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */ - ctrl_outw(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */ + __raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */ /* FPGA System register setup*/ - ctrl_outw(0x0000,INTSTS0); /* Clear INTSTS0 */ - ctrl_outw(0x0000,INTSTS1); /* Clear INTSTS1 */ + __raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */ + __raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */ /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */ - ctrl_outw(0x0001,INTSEL); + __raw_writew(0x0001,INTSEL); } diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c index c60fd13608d0..d4305c26e9f7 100644 --- a/arch/sh/boards/mach-se/7343/irq.c +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -21,13 +21,13 @@ unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, }; static void disable_se7343_irq(unsigned int irq) { unsigned int bit = (unsigned int)get_irq_chip_data(irq); - ctrl_outw(ctrl_inw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK); + __raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK); } static void enable_se7343_irq(unsigned int irq) { unsigned int bit = (unsigned int)get_irq_chip_data(irq); - ctrl_outw(ctrl_inw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK); + __raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK); } static struct irq_chip se7343_irq_chip __read_mostly = { @@ -39,7 +39,7 @@ static struct irq_chip se7343_irq_chip __read_mostly = { static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) { - unsigned short intv = ctrl_inw(PA_CPLD_ST); + unsigned short intv = __raw_readw(PA_CPLD_ST); unsigned int ext_irq = 0; intv &= (1 << SE7343_FPGA_IRQ_NR) - 1; @@ -59,8 +59,8 @@ void __init init_7343se_IRQ(void) { int i, irq; - ctrl_outw(0, PA_CPLD_IMSK); /* disable all irqs */ - ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ + __raw_writew(0, PA_CPLD_IMSK); /* disable all irqs */ + __raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */ for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) { irq = create_irq(); diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c index 3412bb2973ae..d2370af56d77 100644 --- a/arch/sh/boards/mach-se/7343/setup.c +++ b/arch/sh/boards/mach-se/7343/setup.c @@ -161,10 +161,10 @@ device_initcall(sh7343se_devices_setup); */ static void __init sh7343se_setup(char **cmdline_p) { - ctrl_outw(0xf900, FPGA_OUT); /* FPGA */ + __raw_writew(0xf900, FPGA_OUT); /* FPGA */ - ctrl_outw(0x0002, PORT_PECR); /* PORT E 1 = IRQ5 */ - ctrl_outw(0x0020, PORT_PSELD); + __raw_writew(0x0002, PORT_PECR); /* PORT E 1 = IRQ5 */ + __raw_writew(0x0020, PORT_PSELD); printk(KERN_INFO "MS7343CP01 Setup...done\n"); } diff --git a/arch/sh/boards/mach-se/770x/irq.c b/arch/sh/boards/mach-se/770x/irq.c index ec1fea571b52..1028c17b81bc 100644 --- a/arch/sh/boards/mach-se/770x/irq.c +++ b/arch/sh/boards/mach-se/770x/irq.c @@ -96,13 +96,13 @@ static struct ipr_desc ipr_irq_desc = { void __init init_se_IRQ(void) { /* Disable all interrupts */ - ctrl_outw(0, BCR_ILCRA); - ctrl_outw(0, BCR_ILCRB); - ctrl_outw(0, BCR_ILCRC); - ctrl_outw(0, BCR_ILCRD); - ctrl_outw(0, BCR_ILCRE); - ctrl_outw(0, BCR_ILCRF); - ctrl_outw(0, BCR_ILCRG); + __raw_writew(0, BCR_ILCRA); + __raw_writew(0, BCR_ILCRB); + __raw_writew(0, BCR_ILCRC); + __raw_writew(0, BCR_ILCRD); + __raw_writew(0, BCR_ILCRE); + __raw_writew(0, BCR_ILCRF); + __raw_writew(0, BCR_ILCRG); register_ipr_controller(&ipr_irq_desc); } diff --git a/arch/sh/boards/mach-se/7721/irq.c b/arch/sh/boards/mach-se/7721/irq.c index b417acc4dad0..d85022ea3f12 100644 --- a/arch/sh/boards/mach-se/7721/irq.c +++ b/arch/sh/boards/mach-se/7721/irq.c @@ -38,7 +38,7 @@ static DECLARE_INTC_DESC(intc_desc, "SE7721", vectors, void __init init_se7721_IRQ(void) { /* PPCR */ - ctrl_outw(ctrl_inw(0xa4050118) & ~0x00ff, 0xa4050118); + __raw_writew(__raw_readw(0xa4050118) & ~0x00ff, 0xa4050118); register_intc_controller(&intc_desc); intc_set_priority(MRSHPC_IRQ0, 0xf - MRSHPC_IRQ0); diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c index 460da53b4961..7416ad7ee53a 100644 --- a/arch/sh/boards/mach-se/7721/setup.c +++ b/arch/sh/boards/mach-se/7721/setup.c @@ -80,10 +80,10 @@ device_initcall(se7721_devices_setup); static void __init se7721_setup(char **cmdline_p) { /* for USB */ - ctrl_outw(0x0000, 0xA405010C); /* PGCR */ - ctrl_outw(0x0000, 0xA405010E); /* PHCR */ - ctrl_outw(0x00AA, 0xA4050118); /* PPCR */ - ctrl_outw(0x0000, 0xA4050124); /* PSELA */ + __raw_writew(0x0000, 0xA405010C); /* PGCR */ + __raw_writew(0x0000, 0xA405010E); /* PHCR */ + __raw_writew(0x00AA, 0xA4050118); /* PPCR */ + __raw_writew(0x0000, 0xA4050124); /* PSELA */ } /* diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c index b221b6842b0d..61605db04ee6 100644 --- a/arch/sh/boards/mach-se/7722/irq.c +++ b/arch/sh/boards/mach-se/7722/irq.c @@ -21,13 +21,13 @@ unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, }; static void disable_se7722_irq(unsigned int irq) { unsigned int bit = (unsigned int)get_irq_chip_data(irq); - ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK); + __raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK); } static void enable_se7722_irq(unsigned int irq) { unsigned int bit = (unsigned int)get_irq_chip_data(irq); - ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK); + __raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK); } static struct irq_chip se7722_irq_chip __read_mostly = { @@ -39,7 +39,7 @@ static struct irq_chip se7722_irq_chip __read_mostly = { static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) { - unsigned short intv = ctrl_inw(IRQ01_STS); + unsigned short intv = __raw_readw(IRQ01_STS); unsigned int ext_irq = 0; intv &= (1 << SE7722_FPGA_IRQ_NR) - 1; @@ -59,8 +59,8 @@ void __init init_se7722_IRQ(void) { int i, irq; - ctrl_outw(0, IRQ01_MASK); /* disable all irqs */ - ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ + __raw_writew(0, IRQ01_MASK); /* disable all irqs */ + __raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */ for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) { irq = create_irq(); diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c index 93675418171d..80a4e571b310 100644 --- a/arch/sh/boards/mach-se/7722/setup.c +++ b/arch/sh/boards/mach-se/7722/setup.c @@ -156,32 +156,32 @@ device_initcall(se7722_devices_setup); static void __init se7722_setup(char **cmdline_p) { - ctrl_outw(0x010D, FPGA_OUT); /* FPGA */ + __raw_writew(0x010D, FPGA_OUT); /* FPGA */ - ctrl_outw(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */ - ctrl_outw(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */ + __raw_writew(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */ + __raw_writew(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */ /* LCDC I/O */ - ctrl_outw(0x0020, PORT_PSELD); + __raw_writew(0x0020, PORT_PSELD); /* SIOF1*/ - ctrl_outw(0x0003, PORT_PSELB); - ctrl_outw(0xe000, PORT_PSELC); - ctrl_outw(0x0000, PORT_PKCR); + __raw_writew(0x0003, PORT_PSELB); + __raw_writew(0xe000, PORT_PSELC); + __raw_writew(0x0000, PORT_PKCR); /* LCDC */ - ctrl_outw(0x4020, PORT_PHCR); - ctrl_outw(0x0000, PORT_PLCR); - ctrl_outw(0x0000, PORT_PMCR); - ctrl_outw(0x0002, PORT_PRCR); - ctrl_outw(0x0000, PORT_PXCR); /* LCDC,CS6A */ + __raw_writew(0x4020, PORT_PHCR); + __raw_writew(0x0000, PORT_PLCR); + __raw_writew(0x0000, PORT_PMCR); + __raw_writew(0x0002, PORT_PRCR); + __raw_writew(0x0000, PORT_PXCR); /* LCDC,CS6A */ /* KEYSC */ - ctrl_outw(0x0A10, PORT_PSELA); /* BS,SHHID2 */ - ctrl_outw(0x0000, PORT_PYCR); - ctrl_outw(0x0000, PORT_PZCR); - ctrl_outw(ctrl_inw(PORT_HIZCRA) & ~0x4000, PORT_HIZCRA); - ctrl_outw(ctrl_inw(PORT_HIZCRC) & ~0xc000, PORT_HIZCRC); + __raw_writew(0x0A10, PORT_PSELA); /* BS,SHHID2 */ + __raw_writew(0x0000, PORT_PYCR); + __raw_writew(0x0000, PORT_PZCR); + __raw_writew(__raw_readw(PORT_HIZCRA) & ~0x4000, PORT_HIZCRA); + __raw_writew(__raw_readw(PORT_HIZCRC) & ~0xc000, PORT_HIZCRC); } /* diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c index f76cf3b49f23..e5e021a7d1e6 100644 --- a/arch/sh/boards/mach-se/7724/irq.c +++ b/arch/sh/boards/mach-se/7724/irq.c @@ -72,14 +72,14 @@ static void disable_se7724_irq(unsigned int irq) { struct fpga_irq set = get_fpga_irq(fpga2irq(irq)); unsigned int bit = irq - set.base; - ctrl_outw(ctrl_inw(set.mraddr) | 0x0001 << bit, set.mraddr); + __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr); } static void enable_se7724_irq(unsigned int irq) { struct fpga_irq set = get_fpga_irq(fpga2irq(irq)); unsigned int bit = irq - set.base; - ctrl_outw(ctrl_inw(set.mraddr) & ~(0x0001 << bit), set.mraddr); + __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr); } static struct irq_chip se7724_irq_chip __read_mostly = { @@ -92,7 +92,7 @@ static struct irq_chip se7724_irq_chip __read_mostly = { static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) { struct fpga_irq set = get_fpga_irq(irq); - unsigned short intv = ctrl_inw(set.sraddr); + unsigned short intv = __raw_readw(set.sraddr); struct irq_desc *ext_desc; unsigned int ext_irq = set.base; @@ -115,13 +115,13 @@ void __init init_se7724_IRQ(void) { int i; - ctrl_outw(0xffff, IRQ0_MR); /* mask all */ - ctrl_outw(0xffff, IRQ1_MR); /* mask all */ - ctrl_outw(0xffff, IRQ2_MR); /* mask all */ - ctrl_outw(0x0000, IRQ0_SR); /* clear irq */ - ctrl_outw(0x0000, IRQ1_SR); /* clear irq */ - ctrl_outw(0x0000, IRQ2_SR); /* clear irq */ - ctrl_outw(0x002a, IRQ_MODE); /* set irq type */ + __raw_writew(0xffff, IRQ0_MR); /* mask all */ + __raw_writew(0xffff, IRQ1_MR); /* mask all */ + __raw_writew(0xffff, IRQ2_MR); /* mask all */ + __raw_writew(0x0000, IRQ0_SR); /* clear irq */ + __raw_writew(0x0000, IRQ1_SR); /* clear irq */ + __raw_writew(0x0000, IRQ2_SR); /* clear irq */ + __raw_writew(0x002a, IRQ_MODE); /* set irq type */ for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) set_irq_chip_and_handler_name(SE7724_FPGA_IRQ_BASE + i, diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index cbfba783ee49..242dc843f574 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -256,12 +256,12 @@ static struct platform_device ceu1_device = { #define FCLKACR 0xa4150008 static void fsimck_init(struct clk *clk) { - u32 status = ctrl_inl(clk->enable_reg); + u32 status = __raw_readl(clk->enable_reg); /* use external clock */ status &= ~0x000000ff; status |= 0x00000080; - ctrl_outl(status, clk->enable_reg); + __raw_writel(status, clk->enable_reg); } static struct clk_ops fsimck_clk_ops = { @@ -522,7 +522,7 @@ static int __init sh_eth_is_eeprom_ready(void) int t = 10000; while (t--) { - if (!ctrl_inw(EEPROM_STAT)) + if (!__raw_readw(EEPROM_STAT)) return 1; cpu_relax(); } @@ -542,13 +542,13 @@ static void __init sh_eth_init(void) /* read MAC addr from EEPROM */ for (i = 0 ; i < 3 ; i++) { - ctrl_outw(0x0, EEPROM_OP); /* read */ - ctrl_outw(i*2, EEPROM_ADR); - ctrl_outw(0x1, EEPROM_STRT); + __raw_writew(0x0, EEPROM_OP); /* read */ + __raw_writew(i*2, EEPROM_ADR); + __raw_writew(0x1, EEPROM_STRT); if (!sh_eth_is_eeprom_ready()) return; - mac = ctrl_inw(EEPROM_DATA); + mac = __raw_readw(EEPROM_DATA); sh_eth_plat.mac_addr[i << 1] = mac & 0xff; sh_eth_plat.mac_addr[(i << 1) + 1] = mac >> 8; } @@ -585,7 +585,7 @@ arch_initcall(arch_setup); static int __init devices_setup(void) { - u16 sw = ctrl_inw(SW4140); /* select camera, monitor */ + u16 sw = __raw_readw(SW4140); /* select camera, monitor */ struct clk *fsia_clk; /* register board specific self-refresh code */ @@ -595,7 +595,7 @@ static int __init devices_setup(void) &ms7724se_sdram_leave_start, &ms7724se_sdram_leave_end); /* Reset Release */ - ctrl_outw(ctrl_inw(FPGA_OUT) & + __raw_writew(__raw_readw(FPGA_OUT) & ~((1 << 1) | /* LAN */ (1 << 6) | /* VIDEO DAC */ (1 << 7) | /* AK4643 */ @@ -604,7 +604,7 @@ static int __init devices_setup(void) FPGA_OUT); /* turn on USB clocks, use external clock */ - ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); + __raw_writew((__raw_readw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); #ifdef CONFIG_PM /* Let LED9 show STATUS2 */ @@ -633,10 +633,10 @@ static int __init devices_setup(void) #endif /* enable USB0 port */ - ctrl_outw(0x0600, 0xa40501d4); + __raw_writew(0x0600, 0xa40501d4); /* enable USB1 port */ - ctrl_outw(0x0600, 0xa4050192); + __raw_writew(0x0600, 0xa4050192); /* enable IRQ 0,1,2 */ gpio_request(GPIO_FN_INTC_IRQ0, NULL); @@ -684,7 +684,7 @@ static int __init devices_setup(void) gpio_request(GPIO_FN_LCDVCPWC, NULL); gpio_request(GPIO_FN_LCDRD, NULL); gpio_request(GPIO_FN_LCDLCLK, NULL); - ctrl_outw((ctrl_inw(PORT_HIZA) & ~0x0001), PORT_HIZA); + __raw_writew((__raw_readw(PORT_HIZA) & ~0x0001), PORT_HIZA); /* enable CEU0 */ gpio_request(GPIO_FN_VIO0_D15, NULL); diff --git a/arch/sh/boards/mach-se/7780/irq.c b/arch/sh/boards/mach-se/7780/irq.c index 121744c08714..d5c9edc172a3 100644 --- a/arch/sh/boards/mach-se/7780/irq.c +++ b/arch/sh/boards/mach-se/7780/irq.c @@ -24,30 +24,30 @@ void __init init_se7780_IRQ(void) { /* enable all interrupt at FPGA */ - ctrl_outw(0, FPGA_INTMSK1); + __raw_writew(0, FPGA_INTMSK1); /* mask SM501 interrupt */ - ctrl_outw((ctrl_inw(FPGA_INTMSK1) | 0x0002), FPGA_INTMSK1); + __raw_writew((__raw_readw(FPGA_INTMSK1) | 0x0002), FPGA_INTMSK1); /* enable all interrupt at FPGA */ - ctrl_outw(0, FPGA_INTMSK2); + __raw_writew(0, FPGA_INTMSK2); /* set FPGA INTSEL register */ /* FPGA + 0x06 */ - ctrl_outw( ((IRQPIN_SM501 << IRQPOS_SM501) | + __raw_writew( ((IRQPIN_SM501 << IRQPOS_SM501) | (IRQPIN_SMC91CX << IRQPOS_SMC91CX)), FPGA_INTSEL1); /* FPGA + 0x08 */ - ctrl_outw(((IRQPIN_EXTINT4 << IRQPOS_EXTINT4) | + __raw_writew(((IRQPIN_EXTINT4 << IRQPOS_EXTINT4) | (IRQPIN_EXTINT3 << IRQPOS_EXTINT3) | (IRQPIN_EXTINT2 << IRQPOS_EXTINT2) | (IRQPIN_EXTINT1 << IRQPOS_EXTINT1)), FPGA_INTSEL2); /* FPGA + 0x0A */ - ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3); + __raw_writew((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3); plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-7 */ /* ICR1: detect low level(for 2ndcut) */ - ctrl_outl(0xAAAA0000, INTC_ICR1); + __raw_writel(0xAAAA0000, INTC_ICR1); /* * FPGA PCISEL register initialize @@ -63,6 +63,6 @@ void __init init_se7780_IRQ(void) * INTD || INTD | INTC | -- | INTA * ------------------------------------- */ - ctrl_outw(0x0013, FPGA_PCI_INTSEL1); - ctrl_outw(0xE402, FPGA_PCI_INTSEL2); + __raw_writew(0x0013, FPGA_PCI_INTSEL1); + __raw_writew(0xE402, FPGA_PCI_INTSEL2); } diff --git a/arch/sh/boards/mach-se/7780/setup.c b/arch/sh/boards/mach-se/7780/setup.c index f7bfb3f83692..6f7c207138e1 100644 --- a/arch/sh/boards/mach-se/7780/setup.c +++ b/arch/sh/boards/mach-se/7780/setup.c @@ -75,14 +75,14 @@ device_initcall(se7780_devices_setup); static void __init se7780_setup(char **cmdline_p) { /* "SH-Linux" on LED Display */ - ctrl_outw( 'S' , PA_LED_DISP + (DISP_SEL0_ADDR << 1) ); - ctrl_outw( 'H' , PA_LED_DISP + (DISP_SEL1_ADDR << 1) ); - ctrl_outw( '-' , PA_LED_DISP + (DISP_SEL2_ADDR << 1) ); - ctrl_outw( 'L' , PA_LED_DISP + (DISP_SEL3_ADDR << 1) ); - ctrl_outw( 'i' , PA_LED_DISP + (DISP_SEL4_ADDR << 1) ); - ctrl_outw( 'n' , PA_LED_DISP + (DISP_SEL5_ADDR << 1) ); - ctrl_outw( 'u' , PA_LED_DISP + (DISP_SEL6_ADDR << 1) ); - ctrl_outw( 'x' , PA_LED_DISP + (DISP_SEL7_ADDR << 1) ); + __raw_writew( 'S' , PA_LED_DISP + (DISP_SEL0_ADDR << 1) ); + __raw_writew( 'H' , PA_LED_DISP + (DISP_SEL1_ADDR << 1) ); + __raw_writew( '-' , PA_LED_DISP + (DISP_SEL2_ADDR << 1) ); + __raw_writew( 'L' , PA_LED_DISP + (DISP_SEL3_ADDR << 1) ); + __raw_writew( 'i' , PA_LED_DISP + (DISP_SEL4_ADDR << 1) ); + __raw_writew( 'n' , PA_LED_DISP + (DISP_SEL5_ADDR << 1) ); + __raw_writew( 'u' , PA_LED_DISP + (DISP_SEL6_ADDR << 1) ); + __raw_writew( 'x' , PA_LED_DISP + (DISP_SEL7_ADDR << 1) ); printk(KERN_INFO "Hitachi UL Solutions Engine 7780SE03 support.\n"); @@ -93,15 +93,15 @@ static void __init se7780_setup(char **cmdline_p) * REQ2/GNT2 -> Serial ATA * REQ3/GNT3 -> PCI slot */ - ctrl_outw(0x0213, FPGA_REQSEL); + __raw_writew(0x0213, FPGA_REQSEL); /* GPIO setting */ - ctrl_outw(0x0000, GPIO_PECR); - ctrl_outw(ctrl_inw(GPIO_PHCR)&0xfff3, GPIO_PHCR); - ctrl_outw(0x0c00, GPIO_PMSELR); + __raw_writew(0x0000, GPIO_PECR); + __raw_writew(__raw_readw(GPIO_PHCR)&0xfff3, GPIO_PHCR); + __raw_writew(0x0c00, GPIO_PMSELR); /* iVDR Power ON */ - ctrl_outw(0x0001, FPGA_IVDRPW); + __raw_writew(0x0001, FPGA_IVDRPW); } /* diff --git a/arch/sh/boards/mach-sh03/rtc.c b/arch/sh/boards/mach-sh03/rtc.c index a8b9f844ab5b..1b200990500c 100644 --- a/arch/sh/boards/mach-sh03/rtc.c +++ b/arch/sh/boards/mach-sh03/rtc.c @@ -44,15 +44,15 @@ unsigned long get_cmos_time(void) spin_lock(&sh03_rtc_lock); again: do { - sec = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10; - min = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10; - hour = (ctrl_inb(RTC_HOU1) & 0xf) + (ctrl_inb(RTC_HOU10) & 0xf) * 10; - day = (ctrl_inb(RTC_DAY1) & 0xf) + (ctrl_inb(RTC_DAY10) & 0xf) * 10; - mon = (ctrl_inb(RTC_MON1) & 0xf) + (ctrl_inb(RTC_MON10) & 0xf) * 10; - year = (ctrl_inb(RTC_YEA1) & 0xf) + (ctrl_inb(RTC_YEA10) & 0xf) * 10 - + (ctrl_inb(RTC_YEA100 ) & 0xf) * 100 - + (ctrl_inb(RTC_YEA1000) & 0xf) * 1000; - } while (sec != (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10); + sec = (__raw_readb(RTC_SEC1) & 0xf) + (__raw_readb(RTC_SEC10) & 0x7) * 10; + min = (__raw_readb(RTC_MIN1) & 0xf) + (__raw_readb(RTC_MIN10) & 0xf) * 10; + hour = (__raw_readb(RTC_HOU1) & 0xf) + (__raw_readb(RTC_HOU10) & 0xf) * 10; + day = (__raw_readb(RTC_DAY1) & 0xf) + (__raw_readb(RTC_DAY10) & 0xf) * 10; + mon = (__raw_readb(RTC_MON1) & 0xf) + (__raw_readb(RTC_MON10) & 0xf) * 10; + year = (__raw_readb(RTC_YEA1) & 0xf) + (__raw_readb(RTC_YEA10) & 0xf) * 10 + + (__raw_readb(RTC_YEA100 ) & 0xf) * 100 + + (__raw_readb(RTC_YEA1000) & 0xf) * 1000; + } while (sec != (__raw_readb(RTC_SEC1) & 0xf) + (__raw_readb(RTC_SEC10) & 0x7) * 10); if (year == 0 || mon < 1 || mon > 12 || day > 31 || day < 1 || hour > 23 || min > 59 || sec > 59) { printk(KERN_ERR @@ -60,16 +60,16 @@ unsigned long get_cmos_time(void) printk("year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n", year, mon, day, hour, min, sec); - ctrl_outb(0, RTC_SEC1); ctrl_outb(0, RTC_SEC10); - ctrl_outb(0, RTC_MIN1); ctrl_outb(0, RTC_MIN10); - ctrl_outb(0, RTC_HOU1); ctrl_outb(0, RTC_HOU10); - ctrl_outb(6, RTC_WEE1); - ctrl_outb(1, RTC_DAY1); ctrl_outb(0, RTC_DAY10); - ctrl_outb(1, RTC_MON1); ctrl_outb(0, RTC_MON10); - ctrl_outb(0, RTC_YEA1); ctrl_outb(0, RTC_YEA10); - ctrl_outb(0, RTC_YEA100); - ctrl_outb(2, RTC_YEA1000); - ctrl_outb(0, RTC_CTL); + __raw_writeb(0, RTC_SEC1); __raw_writeb(0, RTC_SEC10); + __raw_writeb(0, RTC_MIN1); __raw_writeb(0, RTC_MIN10); + __raw_writeb(0, RTC_HOU1); __raw_writeb(0, RTC_HOU10); + __raw_writeb(6, RTC_WEE1); + __raw_writeb(1, RTC_DAY1); __raw_writeb(0, RTC_DAY10); + __raw_writeb(1, RTC_MON1); __raw_writeb(0, RTC_MON10); + __raw_writeb(0, RTC_YEA1); __raw_writeb(0, RTC_YEA10); + __raw_writeb(0, RTC_YEA100); + __raw_writeb(2, RTC_YEA1000); + __raw_writeb(0, RTC_CTL); goto again; } @@ -93,9 +93,9 @@ static int set_rtc_mmss(unsigned long nowtime) /* gets recalled with irq locally disabled */ spin_lock(&sh03_rtc_lock); for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (!(ctrl_inb(RTC_CTL) & RTC_BUSY)) + if (!(__raw_readb(RTC_CTL) & RTC_BUSY)) break; - cmos_minutes = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10; + cmos_minutes = (__raw_readb(RTC_MIN1) & 0xf) + (__raw_readb(RTC_MIN10) & 0xf) * 10; real_seconds = nowtime % 60; real_minutes = nowtime / 60; if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) @@ -103,10 +103,10 @@ static int set_rtc_mmss(unsigned long nowtime) real_minutes %= 60; if (abs(real_minutes - cmos_minutes) < 30) { - ctrl_outb(real_seconds % 10, RTC_SEC1); - ctrl_outb(real_seconds / 10, RTC_SEC10); - ctrl_outb(real_minutes % 10, RTC_MIN1); - ctrl_outb(real_minutes / 10, RTC_MIN10); + __raw_writeb(real_seconds % 10, RTC_SEC1); + __raw_writeb(real_seconds / 10, RTC_SEC10); + __raw_writeb(real_minutes % 10, RTC_MIN1); + __raw_writeb(real_minutes / 10, RTC_MIN10); } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", diff --git a/arch/sh/boards/mach-sh7763rdp/irq.c b/arch/sh/boards/mach-sh7763rdp/irq.c index d8ebfa7d8c76..add698c8f2b4 100644 --- a/arch/sh/boards/mach-sh7763rdp/irq.c +++ b/arch/sh/boards/mach-sh7763rdp/irq.c @@ -28,18 +28,18 @@ void __init init_sh7763rdp_IRQ(void) { /* GPIO enabled */ - ctrl_outl(1 << 25, INTC_INT2MSKCR); + __raw_writel(1 << 25, INTC_INT2MSKCR); /* enable GPIO interrupts */ - ctrl_outl((ctrl_inl(INTC_INT2PRI7) & 0xFF00FFFF) | 0x000F0000, + __raw_writel((__raw_readl(INTC_INT2PRI7) & 0xFF00FFFF) | 0x000F0000, INTC_INT2PRI7); /* USBH enabled */ - ctrl_outl(1 << 17, INTC_INT2MSKCR1); + __raw_writel(1 << 17, INTC_INT2MSKCR1); /* GETHER enabled */ - ctrl_outl(1 << 16, INTC_INT2MSKCR1); + __raw_writel(1 << 16, INTC_INT2MSKCR1); /* DMAC enabled */ - ctrl_outl(1 << 8, INTC_INT2MSKCR); + __raw_writel(1 << 8, INTC_INT2MSKCR); } diff --git a/arch/sh/boards/mach-sh7763rdp/setup.c b/arch/sh/boards/mach-sh7763rdp/setup.c index 390534a0b35c..f64a6918224c 100644 --- a/arch/sh/boards/mach-sh7763rdp/setup.c +++ b/arch/sh/boards/mach-sh7763rdp/setup.c @@ -158,50 +158,50 @@ device_initcall(sh7763rdp_devices_setup); static void __init sh7763rdp_setup(char **cmdline_p) { /* Board version check */ - if (ctrl_inw(CPLD_BOARD_ID_ERV_REG) == 0xECB1) + if (__raw_readw(CPLD_BOARD_ID_ERV_REG) == 0xECB1) printk(KERN_INFO "RTE Standard Configuration\n"); else printk(KERN_INFO "RTA Standard Configuration\n"); /* USB pin select bits (clear bit 5-2 to 0) */ - ctrl_outw((ctrl_inw(PORT_PSEL2) & 0xFFC3), PORT_PSEL2); + __raw_writew((__raw_readw(PORT_PSEL2) & 0xFFC3), PORT_PSEL2); /* USBH setup port I controls to other (clear bits 4-9 to 0) */ - ctrl_outw(ctrl_inw(PORT_PICR) & 0xFC0F, PORT_PICR); + __raw_writew(__raw_readw(PORT_PICR) & 0xFC0F, PORT_PICR); /* Select USB Host controller */ - ctrl_outw(0x00, USB_USBHSC); + __raw_writew(0x00, USB_USBHSC); /* For LCD */ /* set PTJ7-1, bits 15-2 of PJCR to 0 */ - ctrl_outw(ctrl_inw(PORT_PJCR) & 0x0003, PORT_PJCR); + __raw_writew(__raw_readw(PORT_PJCR) & 0x0003, PORT_PJCR); /* set PTI5, bits 11-10 of PICR to 0 */ - ctrl_outw(ctrl_inw(PORT_PICR) & 0xF3FF, PORT_PICR); - ctrl_outw(0, PORT_PKCR); - ctrl_outw(0, PORT_PLCR); + __raw_writew(__raw_readw(PORT_PICR) & 0xF3FF, PORT_PICR); + __raw_writew(0, PORT_PKCR); + __raw_writew(0, PORT_PLCR); /* set PSEL2 bits 14-8, 5-4, of PSEL2 to 0 */ - ctrl_outw((ctrl_inw(PORT_PSEL2) & 0x00C0), PORT_PSEL2); + __raw_writew((__raw_readw(PORT_PSEL2) & 0x00C0), PORT_PSEL2); /* set PSEL3 bits 14-12, 6-4, 2-0 of PSEL3 to 0 */ - ctrl_outw((ctrl_inw(PORT_PSEL3) & 0x0700), PORT_PSEL3); + __raw_writew((__raw_readw(PORT_PSEL3) & 0x0700), PORT_PSEL3); /* For HAC */ /* bit3-0 0100:HAC & SSI1 enable */ - ctrl_outw((ctrl_inw(PORT_PSEL1) & 0xFFF0) | 0x0004, PORT_PSEL1); + __raw_writew((__raw_readw(PORT_PSEL1) & 0xFFF0) | 0x0004, PORT_PSEL1); /* bit14 1:SSI_HAC_CLK enable */ - ctrl_outw(ctrl_inw(PORT_PSEL4) | 0x4000, PORT_PSEL4); + __raw_writew(__raw_readw(PORT_PSEL4) | 0x4000, PORT_PSEL4); /* SH-Ether */ - ctrl_outw((ctrl_inw(PORT_PSEL1) & ~0xff00) | 0x2400, PORT_PSEL1); - ctrl_outw(0x0, PORT_PFCR); - ctrl_outw(0x0, PORT_PFCR); - ctrl_outw(0x0, PORT_PFCR); + __raw_writew((__raw_readw(PORT_PSEL1) & ~0xff00) | 0x2400, PORT_PSEL1); + __raw_writew(0x0, PORT_PFCR); + __raw_writew(0x0, PORT_PFCR); + __raw_writew(0x0, PORT_PFCR); /* MMC */ /*selects SCIF and MMC other functions */ - ctrl_outw(0x0001, PORT_PSEL0); + __raw_writew(0x0001, PORT_PSEL0); /* MMC clock operates */ - ctrl_outl(ctrl_inl(MSTPCR1) & ~0x8, MSTPCR1); - ctrl_outw(ctrl_inw(PORT_PACR) & ~0x3000, PORT_PACR); - ctrl_outw(ctrl_inw(PORT_PCCR) & ~0xCFC3, PORT_PCCR); + __raw_writel(__raw_readl(MSTPCR1) & ~0x8, MSTPCR1); + __raw_writew(__raw_readw(PORT_PACR) & ~0x3000, PORT_PACR); + __raw_writew(__raw_readw(PORT_PCCR) & ~0xCFC3, PORT_PCCR); } static struct sh_machine_vector mv_sh7763rdp __initmv = { diff --git a/arch/sh/boards/mach-snapgear/setup.c b/arch/sh/boards/mach-snapgear/setup.c index a3277a23cf14..331745dee379 100644 --- a/arch/sh/boards/mach-snapgear/setup.c +++ b/arch/sh/boards/mach-snapgear/setup.c @@ -30,7 +30,7 @@ static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id) { - (void)ctrl_inb(0xb8000000); /* dummy read */ + (void)__raw_readb(0xb8000000); /* dummy read */ printk("SnapGear: erase switch interrupt!\n"); diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c index 986a0e71d220..523aea5dc94e 100644 --- a/arch/sh/boards/mach-systemh/irq.c +++ b/arch/sh/boards/mach-systemh/irq.c @@ -41,13 +41,13 @@ static void disable_systemh_irq(unsigned int irq) unsigned long val, mask = 0x01 << 1; /* Clear the "irq"th bit in the mask and set it in the request */ - val = ctrl_inl((unsigned long)systemh_irq_mask_register); + val = __raw_readl((unsigned long)systemh_irq_mask_register); val &= ~mask; - ctrl_outl(val, (unsigned long)systemh_irq_mask_register); + __raw_writel(val, (unsigned long)systemh_irq_mask_register); - val = ctrl_inl((unsigned long)systemh_irq_request_register); + val = __raw_readl((unsigned long)systemh_irq_request_register); val |= mask; - ctrl_outl(val, (unsigned long)systemh_irq_request_register); + __raw_writel(val, (unsigned long)systemh_irq_request_register); } } @@ -57,9 +57,9 @@ static void enable_systemh_irq(unsigned int irq) unsigned long val, mask = 0x01 << 1; /* Set "irq"th bit in the mask register */ - val = ctrl_inl((unsigned long)systemh_irq_mask_register); + val = __raw_readl((unsigned long)systemh_irq_mask_register); val |= mask; - ctrl_outl(val, (unsigned long)systemh_irq_mask_register); + __raw_writel(val, (unsigned long)systemh_irq_mask_register); } } diff --git a/arch/sh/boards/mach-titan/io.c b/arch/sh/boards/mach-titan/io.c index 0130e9826aca..29754c5091f0 100644 --- a/arch/sh/boards/mach-titan/io.c +++ b/arch/sh/boards/mach-titan/io.c @@ -16,8 +16,8 @@ static inline unsigned int port2adr(unsigned int port) u8 titan_inb(unsigned long port) { if (PXSEG(port)) - return ctrl_inb(port); - return ctrl_inw(port2adr(port)) & 0xff; + return __raw_readb(port); + return __raw_readw(port2adr(port)) & 0xff; } u8 titan_inb_p(unsigned long port) @@ -25,9 +25,9 @@ u8 titan_inb_p(unsigned long port) u8 v; if (PXSEG(port)) - v = ctrl_inb(port); + v = __raw_readb(port); else - v = ctrl_inw(port2adr(port)) & 0xff; + v = __raw_readw(port2adr(port)) & 0xff; ctrl_delay(); return v; } @@ -35,9 +35,9 @@ u8 titan_inb_p(unsigned long port) u16 titan_inw(unsigned long port) { if (PXSEG(port)) - return ctrl_inw(port); + return __raw_readw(port); else if (port >= 0x2000) - return ctrl_inw(port2adr(port)); + return __raw_readw(port2adr(port)); else maybebadio(port); return 0; @@ -46,9 +46,9 @@ u16 titan_inw(unsigned long port) u32 titan_inl(unsigned long port) { if (PXSEG(port)) - return ctrl_inl(port); + return __raw_readl(port); else if (port >= 0x2000) - return ctrl_inw(port2adr(port)); + return __raw_readw(port2adr(port)); else maybebadio(port); return 0; @@ -57,26 +57,26 @@ u32 titan_inl(unsigned long port) void titan_outb(u8 value, unsigned long port) { if (PXSEG(port)) - ctrl_outb(value, port); + __raw_writeb(value, port); else - ctrl_outw(value, port2adr(port)); + __raw_writew(value, port2adr(port)); } void titan_outb_p(u8 value, unsigned long port) { if (PXSEG(port)) - ctrl_outb(value, port); + __raw_writeb(value, port); else - ctrl_outw(value, port2adr(port)); + __raw_writew(value, port2adr(port)); ctrl_delay(); } void titan_outw(u16 value, unsigned long port) { if (PXSEG(port)) - ctrl_outw(value, port); + __raw_writew(value, port); else if (port >= 0x2000) - ctrl_outw(value, port2adr(port)); + __raw_writew(value, port2adr(port)); else maybebadio(port); } @@ -84,7 +84,7 @@ void titan_outw(u16 value, unsigned long port) void titan_outl(u32 value, unsigned long port) { if (PXSEG(port)) - ctrl_outl(value, port); + __raw_writel(value, port); else maybebadio(port); } diff --git a/arch/sh/boards/mach-x3proto/ilsel.c b/arch/sh/boards/mach-x3proto/ilsel.c index b5c673c39337..5c9842704c60 100644 --- a/arch/sh/boards/mach-x3proto/ilsel.c +++ b/arch/sh/boards/mach-x3proto/ilsel.c @@ -70,10 +70,10 @@ static void __ilsel_enable(ilsel_source_t set, unsigned int bit) pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n", __func__, bit, addr, shift, set); - tmp = ctrl_inw(addr); + tmp = __raw_readw(addr); tmp &= ~(0xf << shift); tmp |= set << shift; - ctrl_outw(tmp, addr); + __raw_writew(tmp, addr); } /** @@ -142,9 +142,9 @@ void ilsel_disable(unsigned int irq) addr = mk_ilsel_addr(irq); - tmp = ctrl_inw(addr); + tmp = __raw_readw(addr); tmp &= ~(0xf << mk_ilsel_shift(irq)); - ctrl_outw(tmp, addr); + __raw_writew(tmp, addr); clear_bit(irq, &ilsel_level_map); } diff --git a/arch/sh/boards/mach-x3proto/setup.c b/arch/sh/boards/mach-x3proto/setup.c index efe4cb9f8a77..e284592fd42a 100644 --- a/arch/sh/boards/mach-x3proto/setup.c +++ b/arch/sh/boards/mach-x3proto/setup.c @@ -149,7 +149,7 @@ static void __init x3proto_init_irq(void) plat_irq_setup_pins(IRQ_MODE_IRL3210); /* Set ICR0.LVLMODE */ - ctrl_outl(ctrl_inl(0xfe410000) | (1 << 21), 0xfe410000); + __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000); } static struct sh_machine_vector mv_x3proto __initmv = { diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c index 50aa0c1f76ea..cbfedfb42e04 100644 --- a/arch/sh/cchips/hd6446x/hd64461.c +++ b/arch/sh/cchips/hd6446x/hd64461.c @@ -55,7 +55,7 @@ static struct irq_chip hd64461_irq_chip = { static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc) { - unsigned short intv = ctrl_inw(HD64461_NIRR); + unsigned short intv = __raw_readw(HD64461_NIRR); struct irq_desc *ext_desc; unsigned int ext_irq = HD64461_IRQBASE; diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c index 391cbe1c2956..3cee58e7f1e5 100644 --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -40,10 +40,10 @@ static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) static int pvr2_request_dma(struct dma_channel *chan) { - if (ctrl_inl(PVR2_DMA_MODE) != 0) + if (__raw_readl(PVR2_DMA_MODE) != 0) return -EBUSY; - ctrl_outl(0, PVR2_DMA_LMMODE0); + __raw_writel(0, PVR2_DMA_LMMODE0); return 0; } @@ -60,9 +60,9 @@ static int pvr2_xfer_dma(struct dma_channel *chan) xfer_complete = 0; - ctrl_outl(chan->dar, PVR2_DMA_ADDR); - ctrl_outl(chan->count, PVR2_DMA_COUNT); - ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); + __raw_writel(chan->dar, PVR2_DMA_ADDR); + __raw_writel(chan->count, PVR2_DMA_COUNT); + __raw_writel(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); return 0; } diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index 37fb5b8bbc3f..565cc1a4cbba 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -54,7 +54,7 @@ static inline unsigned int get_dmte_irq(unsigned int chan) */ static inline unsigned int calc_xmit_shift(struct dma_channel *chan) { - u32 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR); + u32 chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR); return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT]; } @@ -70,13 +70,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id) struct dma_channel *chan = dev_id; u32 chcr; - chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR); + chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR); if (!(chcr & CHCR_TE)) return IRQ_NONE; chcr &= ~(CHCR_IE | CHCR_DE); - ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR)); + __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR)); wake_up(&chan->wait_queue); @@ -115,7 +115,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) chan->flags &= ~DMA_TEI_CAPABLE; } - ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR)); + __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR)); chan->flags |= DMA_CONFIGURED; return 0; @@ -126,13 +126,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan) int irq; u32 chcr; - chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR); + chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR); chcr |= CHCR_DE; if (chan->flags & DMA_TEI_CAPABLE) chcr |= CHCR_IE; - ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR)); + __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR)); if (chan->flags & DMA_TEI_CAPABLE) { irq = get_dmte_irq(chan->chan); @@ -150,9 +150,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan) disable_irq(irq); } - chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR); + chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR); chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); - ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR)); + __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR)); } static int sh_dmac_xfer_dma(struct dma_channel *chan) @@ -183,12 +183,12 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan) */ if (chan->sar || (mach_is_dreamcast() && chan->chan == PVR2_CASCADE_CHAN)) - ctrl_outl(chan->sar, (dma_base_addr[chan->chan]+SAR)); + __raw_writel(chan->sar, (dma_base_addr[chan->chan]+SAR)); if (chan->dar || (mach_is_dreamcast() && chan->chan == PVR2_CASCADE_CHAN)) - ctrl_outl(chan->dar, (dma_base_addr[chan->chan] + DAR)); + __raw_writel(chan->dar, (dma_base_addr[chan->chan] + DAR)); - ctrl_outl(chan->count >> calc_xmit_shift(chan), + __raw_writel(chan->count >> calc_xmit_shift(chan), (dma_base_addr[chan->chan] + TCR)); sh_dmac_enable_dma(chan); @@ -198,10 +198,10 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan) static int sh_dmac_get_dma_residue(struct dma_channel *chan) { - if (!(ctrl_inl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE)) + if (!(__raw_readl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE)) return 0; - return ctrl_inl(dma_base_addr[chan->chan] + TCR) + return __raw_readl(dma_base_addr[chan->chan] + TCR) << calc_xmit_shift(chan); } diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c index 5e22689c2fcf..72622e307613 100644 --- a/arch/sh/drivers/dma/dmabrg.c +++ b/arch/sh/drivers/dma/dmabrg.c @@ -86,8 +86,8 @@ static irqreturn_t dmabrg_irq(int irq, void *data) unsigned long dcr; unsigned int i; - dcr = ctrl_inl(DMABRGCR); - ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */ + dcr = __raw_readl(DMABRGCR); + __raw_writel(dcr & ~0x00ff0003, DMABRGCR); /* ack all */ dcr &= dcr >> 8; /* ignore masked */ /* USB stuff, get it out of the way first */ @@ -109,17 +109,17 @@ static irqreturn_t dmabrg_irq(int irq, void *data) static void dmabrg_disable_irq(unsigned int dmairq) { unsigned long dcr; - dcr = ctrl_inl(DMABRGCR); + dcr = __raw_readl(DMABRGCR); dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); - ctrl_outl(dcr, DMABRGCR); + __raw_writel(dcr, DMABRGCR); } static void dmabrg_enable_irq(unsigned int dmairq) { unsigned long dcr; - dcr = ctrl_inl(DMABRGCR); + dcr = __raw_readl(DMABRGCR); dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); - ctrl_outl(dcr, DMABRGCR); + __raw_writel(dcr, DMABRGCR); } int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*), @@ -165,13 +165,13 @@ static int __init dmabrg_init(void) printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n"); #endif - ctrl_outl(0, DMABRGCR); - ctrl_outl(0, DMACHCR0); - ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */ + __raw_writel(0, DMABRGCR); + __raw_writel(0, DMACHCR0); + __raw_writel(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */ /* enable DMABRG mode, enable the DMAC */ - or = ctrl_inl(DMAOR); - ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR); + or = __raw_readl(DMAOR); + __raw_writel(or | DMAOR_BRG | DMAOR_DMEN, DMAOR); ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED, "DMABRG USB address error", NULL); diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c index 7898f14d6641..e248516118a9 100644 --- a/arch/sh/drivers/pci/fixups-rts7751r2d.c +++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c @@ -43,7 +43,7 @@ int pci_fixup_pcic(struct pci_channel *chan) { unsigned long bcr1, mcr; - bcr1 = ctrl_inl(SH7751_BCR1); + bcr1 = __raw_readl(SH7751_BCR1); bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ pci_write_reg(chan, bcr1, SH4_PCIBCR1); @@ -54,7 +54,7 @@ int pci_fixup_pcic(struct pci_channel *chan) pci_write_reg(chan, 0xfb900047, SH7751_PCICONF1); pci_write_reg(chan, 0xab000001, SH7751_PCICONF4); - mcr = ctrl_inl(SH7751_MCR); + mcr = __raw_readl(SH7751_MCR); mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; pci_write_reg(chan, mcr, SH4_PCIMCR); diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h index 3d5296cde622..4744a7dede0c 100644 --- a/arch/sh/drivers/pci/pci-sh4.h +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -167,13 +167,13 @@ struct sh4_pci_address_map { static inline void pci_write_reg(struct pci_channel *chan, unsigned long val, unsigned long reg) { - ctrl_outl(val, chan->reg_base + reg); + __raw_writel(val, chan->reg_base + reg); } static inline unsigned long pci_read_reg(struct pci_channel *chan, unsigned long reg) { - return ctrl_inl(chan->reg_base + reg); + return __raw_readl(chan->reg_base + reg); } #endif /* __PCI_SH4_H */ diff --git a/arch/sh/drivers/pci/pci-sh5.h b/arch/sh/drivers/pci/pci-sh5.h index f277628221f3..3f01decb4307 100644 --- a/arch/sh/drivers/pci/pci-sh5.h +++ b/arch/sh/drivers/pci/pci-sh5.h @@ -86,14 +86,14 @@ extern unsigned long pcicr_virt; /* #define PCISH5_VCR_REG(x) ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */ /* Write I/O functions */ -#define SH5PCI_WRITE(reg,val) ctrl_outl((u32)(val),PCISH5_ICR_REG(reg)) -#define SH5PCI_WRITE_SHORT(reg,val) ctrl_outw((u16)(val),PCISH5_ICR_REG(reg)) -#define SH5PCI_WRITE_BYTE(reg,val) ctrl_outb((u8)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE(reg,val) __raw_writel((u32)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_SHORT(reg,val) __raw_writew((u16)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_BYTE(reg,val) __raw_writeb((u8)(val),PCISH5_ICR_REG(reg)) /* Read I/O functions */ -#define SH5PCI_READ(reg) ctrl_inl(PCISH5_ICR_REG(reg)) -#define SH5PCI_READ_SHORT(reg) ctrl_inw(PCISH5_ICR_REG(reg)) -#define SH5PCI_READ_BYTE(reg) ctrl_inb(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ(reg) __raw_readl(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_SHORT(reg) __raw_readw(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_BYTE(reg) __raw_readb(PCISH5_ICR_REG(reg)) /* Set PCI config bits */ #define SET_CONFIG_BITS(bus,devfn,where) ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000) diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 70c1999a0ec4..2455cf32db5a 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -97,9 +97,9 @@ static int __init sh7751_pci_init(void) return ret; /* Set the BCR's to enable PCI access */ - reg = ctrl_inl(SH7751_BCR1); + reg = __raw_readl(SH7751_BCR1); reg |= 0x80000; - ctrl_outl(reg, SH7751_BCR1); + __raw_writel(reg, SH7751_BCR1); /* Turn the clocks back on (not done in reset)*/ pci_write_reg(chan, 0, SH4_PCICLKR); @@ -159,13 +159,13 @@ static int __init sh7751_pci_init(void) return -1; /* configure the wait control registers */ - word = ctrl_inl(SH7751_WCR1); + word = __raw_readl(SH7751_WCR1); pci_write_reg(chan, word, SH4_PCIWCR1); - word = ctrl_inl(SH7751_WCR2); + word = __raw_readl(SH7751_WCR2); pci_write_reg(chan, word, SH4_PCIWCR2); - word = ctrl_inl(SH7751_WCR3); + word = __raw_readl(SH7751_WCR3); pci_write_reg(chan, word, SH4_PCIWCR3); - word = ctrl_inl(SH7751_MCR); + word = __raw_readl(SH7751_MCR); pci_write_reg(chan, word, SH4_PCIMCR); /* NOTE: I'm ignoring the PCI error IRQs for now.. diff --git a/arch/sh/drivers/superhyway/ops-sh4-202.c b/arch/sh/drivers/superhyway/ops-sh4-202.c index 3b14bf860db6..6da62e9475c4 100644 --- a/arch/sh/drivers/superhyway/ops-sh4-202.c +++ b/arch/sh/drivers/superhyway/ops-sh4-202.c @@ -134,8 +134,8 @@ static int sh4202_read_vcr(unsigned long base, struct superhyway_vcr_info *vcr) * * Do not trust the documentation, for it is evil. */ - vcrh = ctrl_inl(base); - vcrl = ctrl_inl(base + sizeof(u32)); + vcrh = __raw_readl(base); + vcrl = __raw_readl(base + sizeof(u32)); tmp = ((u64)vcrh << 32) | vcrl; memcpy(vcr, &tmp, sizeof(u64)); @@ -147,8 +147,8 @@ static int sh4202_write_vcr(unsigned long base, struct superhyway_vcr_info vcr) { u64 tmp = *(u64 *)&vcr; - ctrl_outl((tmp >> 32) & 0xffffffff, base); - ctrl_outl(tmp & 0xffffffff, base + sizeof(u32)); + __raw_writel((tmp >> 32) & 0xffffffff, base); + __raw_writel(tmp & 0xffffffff, base + sizeof(u32)); return 0; } diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h index 78eed3e0bdf5..47de10976991 100644 --- a/arch/sh/include/asm/dma-sh.h +++ b/arch/sh/include/asm/dma-sh.h @@ -20,14 +20,14 @@ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) #define dmaor_read_reg(n) \ - (n ? ctrl_inw(SH_DMAC_BASE1 + DMAOR) \ - : ctrl_inw(SH_DMAC_BASE0 + DMAOR)) + (n ? __raw_readw(SH_DMAC_BASE1 + DMAOR) \ + : __raw_readw(SH_DMAC_BASE0 + DMAOR)) #define dmaor_write_reg(n, data) \ - (n ? ctrl_outw(data, SH_DMAC_BASE1 + DMAOR) \ - : ctrl_outw(data, SH_DMAC_BASE0 + DMAOR)) + (n ? __raw_writew(data, SH_DMAC_BASE1 + DMAOR) \ + : __raw_writew(data, SH_DMAC_BASE0 + DMAOR)) #else /* Other CPU */ -#define dmaor_read_reg(n) ctrl_inw(SH_DMAC_BASE0 + DMAOR) -#define dmaor_write_reg(n, data) ctrl_outw(data, SH_DMAC_BASE0 + DMAOR) +#define dmaor_read_reg(n) __raw_readw(SH_DMAC_BASE0 + DMAOR) +#define dmaor_write_reg(n, data) __raw_writew(data, SH_DMAC_BASE0 + DMAOR) #endif static int dmte_irq_map[] __maybe_unused = { diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h index 41080b173a7a..384c7471a374 100644 --- a/arch/sh/include/asm/mmu_context.h +++ b/arch/sh/include/asm/mmu_context.h @@ -158,7 +158,7 @@ static inline void enable_mmu(void) unsigned int cpu = smp_processor_id(); /* Enable MMU */ - ctrl_outl(MMU_CONTROL_INIT, MMUCR); + __raw_writel(MMU_CONTROL_INIT, MMUCR); ctrl_barrier(); if (asid_cache(cpu) == NO_CONTEXT) @@ -171,9 +171,9 @@ static inline void disable_mmu(void) { unsigned long cr; - cr = ctrl_inl(MMUCR); + cr = __raw_readl(MMUCR); cr &= ~MMU_CONTROL_INIT; - ctrl_outl(cr, MMUCR); + __raw_writel(cr, MMUCR); ctrl_barrier(); } diff --git a/arch/sh/include/asm/mmu_context_32.h b/arch/sh/include/asm/mmu_context_32.h index 8ef800c549ab..10e2e17210d2 100644 --- a/arch/sh/include/asm/mmu_context_32.h +++ b/arch/sh/include/asm/mmu_context_32.h @@ -49,11 +49,11 @@ static inline unsigned long get_asid(void) /* MMU_TTB is used for optimizing the fault handling. */ static inline void set_TTB(pgd_t *pgd) { - ctrl_outl((unsigned long)pgd, MMU_TTB); + __raw_writel((unsigned long)pgd, MMU_TTB); } static inline pgd_t *get_TTB(void) { - return (pgd_t *)ctrl_inl(MMU_TTB); + return (pgd_t *)__raw_readl(MMU_TTB); } #endif /* __ASM_SH_MMU_CONTEXT_32_H */ diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h index 19dfff5c8511..85a7aca7fb8f 100644 --- a/arch/sh/include/asm/watchdog.h +++ b/arch/sh/include/asm/watchdog.h @@ -70,7 +70,7 @@ */ static inline __u32 sh_wdt_read_cnt(void) { - return ctrl_inl(WTCNT_R); + return __raw_readl(WTCNT_R); } /** @@ -82,7 +82,7 @@ static inline __u32 sh_wdt_read_cnt(void) */ static inline void sh_wdt_write_cnt(__u32 val) { - ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT); + __raw_writel((WTCNT_HIGH << 24) | (__u32)val, WTCNT); } /** @@ -94,7 +94,7 @@ static inline void sh_wdt_write_cnt(__u32 val) */ static inline void sh_wdt_write_bst(__u32 val) { - ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST); + __raw_writel((WTBST_HIGH << 24) | (__u32)val, WTBST); } /** * sh_wdt_read_csr - Read from Control/Status Register @@ -103,7 +103,7 @@ static inline void sh_wdt_write_bst(__u32 val) */ static inline __u32 sh_wdt_read_csr(void) { - return ctrl_inl(WTCSR_R); + return __raw_readl(WTCSR_R); } /** @@ -115,7 +115,7 @@ static inline __u32 sh_wdt_read_csr(void) */ static inline void sh_wdt_write_csr(__u32 val) { - ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR); + __raw_writel((WTCSR_HIGH << 24) | (__u32)val, WTCSR); } #else /** @@ -124,7 +124,7 @@ static inline void sh_wdt_write_csr(__u32 val) */ static inline __u8 sh_wdt_read_cnt(void) { - return ctrl_inb(WTCNT_R); + return __raw_readb(WTCNT_R); } /** @@ -136,7 +136,7 @@ static inline __u8 sh_wdt_read_cnt(void) */ static inline void sh_wdt_write_cnt(__u8 val) { - ctrl_outw((WTCNT_HIGH << 8) | (__u16)val, WTCNT); + __raw_writew((WTCNT_HIGH << 8) | (__u16)val, WTCNT); } /** @@ -146,7 +146,7 @@ static inline void sh_wdt_write_cnt(__u8 val) */ static inline __u8 sh_wdt_read_csr(void) { - return ctrl_inb(WTCSR_R); + return __raw_readb(WTCSR_R); } /** @@ -158,7 +158,7 @@ static inline __u8 sh_wdt_read_csr(void) */ static inline void sh_wdt_write_csr(__u8 val) { - ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR); + __raw_writew((WTCSR_HIGH << 8) | (__u16)val, WTCSR); } #endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */ #endif /* __KERNEL__ */ diff --git a/arch/sh/include/cpu-sh2/cpu/watchdog.h b/arch/sh/include/cpu-sh2/cpu/watchdog.h index 393161c9c6d0..1eab8aa63a6d 100644 --- a/arch/sh/include/cpu-sh2/cpu/watchdog.h +++ b/arch/sh/include/cpu-sh2/cpu/watchdog.h @@ -44,7 +44,7 @@ static inline __u8 sh_wdt_read_rstcsr(void) /* * Same read/write brain-damage as for WTCNT here.. */ - return ctrl_inb(RSTCSR_R); + return __raw_readb(RSTCSR_R); } /** @@ -62,7 +62,7 @@ static inline void sh_wdt_write_rstcsr(__u8 val) * we can't presently touch the WOVF bit, since the upper byte * has to be swapped for this. So just leave it alone.. */ - ctrl_outw((WTCNT_HIGH << 8) | (__u16)val, RSTCSR); + __raw_writeb((WTCNT_HIGH << 8) | (__u16)val, RSTCSR); } #endif /* __ASM_CPU_SH2_WATCHDOG_H */ diff --git a/arch/sh/include/cpu-sh3/cpu/dac.h b/arch/sh/include/cpu-sh3/cpu/dac.h index 05fda8316ebc..98f1d15f0ab5 100644 --- a/arch/sh/include/cpu-sh3/cpu/dac.h +++ b/arch/sh/include/cpu-sh3/cpu/dac.h @@ -17,25 +17,25 @@ static __inline__ void sh_dac_enable(int channel) { unsigned char v; - v = ctrl_inb(DACR); + v = __raw_readb(DACR); if(channel) v |= DACR_DAOE1; else v |= DACR_DAOE0; - ctrl_outb(v,DACR); + __raw_writeb(v,DACR); } static __inline__ void sh_dac_disable(int channel) { unsigned char v; - v = ctrl_inb(DACR); + v = __raw_readb(DACR); if(channel) v &= ~DACR_DAOE1; else v &= ~DACR_DAOE0; - ctrl_outb(v,DACR); + __raw_writeb(v,DACR); } static __inline__ void sh_dac_output(u8 value, int channel) { - if(channel) ctrl_outb(value,DADR1); - else ctrl_outb(value,DADR0); + if(channel) __raw_writeb(value,DADR1); + else __raw_writeb(value,DADR0); } #endif /* __ASM_CPU_SH3_DAC_H */ diff --git a/arch/sh/include/mach-common/mach/magicpanelr2.h b/arch/sh/include/mach-common/mach/magicpanelr2.h index c644a77ee357..183a2f744251 100644 --- a/arch/sh/include/mach-common/mach/magicpanelr2.h +++ b/arch/sh/include/mach-common/mach/magicpanelr2.h @@ -19,12 +19,12 @@ #include -#define SETBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) | mask, reg) -#define SETBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) | mask, reg) -#define SETBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) | mask, reg) -#define CLRBITS_OUTB(mask, reg) ctrl_outb(ctrl_inb(reg) & ~mask, reg) -#define CLRBITS_OUTW(mask, reg) ctrl_outw(ctrl_inw(reg) & ~mask, reg) -#define CLRBITS_OUTL(mask, reg) ctrl_outl(ctrl_inl(reg) & ~mask, reg) +#define SETBITS_OUTB(mask, reg) __raw_writeb(__raw_readb(reg) | mask, reg) +#define SETBITS_OUTW(mask, reg) __raw_writew(__raw_readw(reg) | mask, reg) +#define SETBITS_OUTL(mask, reg) __raw_writel(__raw_readl(reg) | mask, reg) +#define CLRBITS_OUTB(mask, reg) __raw_writeb(__raw_readb(reg) & ~mask, reg) +#define CLRBITS_OUTW(mask, reg) __raw_writew(__raw_readw(reg) & ~mask, reg) +#define CLRBITS_OUTL(mask, reg) __raw_writel(__raw_readl(reg) & ~mask, reg) #define PA_LED PORT_PADR /* LED */ diff --git a/arch/sh/kernel/cpu/adc.c b/arch/sh/kernel/cpu/adc.c index da3d6877f93d..d307571d54b6 100644 --- a/arch/sh/kernel/cpu/adc.c +++ b/arch/sh/kernel/cpu/adc.c @@ -18,19 +18,19 @@ int adc_single(unsigned int channel) off = (channel & 0x03) << 2; - csr = ctrl_inb(ADCSR); + csr = __raw_readb(ADCSR); csr = channel | ADCSR_ADST | ADCSR_CKS; - ctrl_outb(csr, ADCSR); + __raw_writeb(csr, ADCSR); do { - csr = ctrl_inb(ADCSR); + csr = __raw_readb(ADCSR); } while ((csr & ADCSR_ADF) == 0); csr &= ~(ADCSR_ADF | ADCSR_ADST); - ctrl_outb(csr, ADCSR); + __raw_writeb(csr, ADCSR); - return (((ctrl_inb(ADDRAH + off) << 8) | - ctrl_inb(ADDRAL + off)) >> 6); + return (((__raw_readb(ADDRAH + off) << 8) | + __raw_readb(ADDRAL + off)) >> 6); } EXPORT_SYMBOL(adc_single); diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 05a7d2a373b6..6311b0b1789d 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -61,10 +61,10 @@ onchip_setup(dsp); static void __init speculative_execution_init(void) { /* Clear RABD */ - ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM); + __raw_writel(__raw_readl(CPUOPM) & ~CPUOPM_RABD, CPUOPM); /* Flush the update */ - (void)ctrl_inl(CPUOPM); + (void)__raw_readl(CPUOPM); ctrl_barrier(); } #else @@ -111,7 +111,7 @@ static void cache_init(void) unsigned long ccr, flags; jump_to_uncached(); - ccr = ctrl_inl(CCR); + ccr = __raw_readl(CCR); /* * At this point we don't know whether the cache is enabled or not - a @@ -155,7 +155,7 @@ static void cache_init(void) for (addr = addrstart; addr < addrstart + waysize; addr += current_cpu_data.dcache.linesz) - ctrl_outl(0, addr); + __raw_writel(0, addr); addrstart += current_cpu_data.dcache.way_incr; } while (--ways); @@ -188,7 +188,7 @@ static void cache_init(void) l2_cache_init(); - ctrl_outl(flags, CCR); + __raw_writel(flags, CCR); back_to_cached(); } #else diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c index 06e7e2959b54..96a239583948 100644 --- a/arch/sh/kernel/cpu/irq/intc-sh5.c +++ b/arch/sh/kernel/cpu/irq/intc-sh5.c @@ -123,7 +123,7 @@ static void enable_intc_irq(unsigned int irq) bitmask = 1 << (irq - 32); } - ctrl_outl(bitmask, reg); + __raw_writel(bitmask, reg); } static void disable_intc_irq(unsigned int irq) @@ -139,7 +139,7 @@ static void disable_intc_irq(unsigned int irq) bitmask = 1 << (irq - 32); } - ctrl_outl(bitmask, reg); + __raw_writel(bitmask, reg); } static void mask_and_ack_intc(unsigned int irq) @@ -170,11 +170,11 @@ void __init plat_irq_setup(void) /* Disable all interrupts and set all priorities to 0 to avoid trouble */ - ctrl_outl(-1, INTC_INTDSB_0); - ctrl_outl(-1, INTC_INTDSB_1); + __raw_writel(-1, INTC_INTDSB_0); + __raw_writel(-1, INTC_INTDSB_1); for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8) - ctrl_outl( NO_PRIORITY, reg); + __raw_writel( NO_PRIORITY, reg); #ifdef CONFIG_SH_CAYMAN @@ -199,7 +199,7 @@ void __init plat_irq_setup(void) reg = INTC_ICR_SET; i = IRQ_IRL0; } - ctrl_outl(INTC_ICR_IRLM, reg); + __raw_writel(INTC_ICR_IRLM, reg); /* Set interrupt priorities according to platform description */ for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) { @@ -207,7 +207,7 @@ void __init plat_irq_setup(void) ((i % INTC_INTPRI_PPREG) * 4); if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) { /* Upon the 7th, set Priority Register */ - ctrl_outl(data, reg); + __raw_writel(data, reg); data = 0; reg += 8; } diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c index 4fe863170e31..0c9f24d7a02f 100644 --- a/arch/sh/kernel/cpu/sh2/clock-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c @@ -31,7 +31,7 @@ static const int pfc_divisors[] = {1,2,0,4}; static void master_clk_init(struct clk *clk) { - clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; + clk->rate *= PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; } static struct clk_ops sh7619_master_clk_ops = { @@ -40,7 +40,7 @@ static struct clk_ops sh7619_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -50,7 +50,7 @@ static struct clk_ops sh7619_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - return clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; + return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; } static struct clk_ops sh7619_bus_clk_ops = { diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c index 7814c76159a7..b26264dc2aef 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c @@ -34,7 +34,7 @@ static const int pfc_divisors[]={1,2,3,4,6,8,12}; static void master_clk_init(struct clk *clk) { - return 10000000 * PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; + return 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; } static struct clk_ops sh7201_master_clk_ops = { @@ -43,7 +43,7 @@ static struct clk_ops sh7201_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -53,7 +53,7 @@ static struct clk_ops sh7201_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -63,7 +63,7 @@ static struct clk_ops sh7201_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inw(FREQCR) >> 4) & 0x0007); + int idx = ((__raw_readw(FREQCR) >> 4) & 0x0007); return clk->parent->rate / ifc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c index 940986965102..7e75d8f79502 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c @@ -39,7 +39,7 @@ static const int pfc_divisors[]={1,2,3,4,6,8,12}; static void master_clk_init(struct clk *clk) { - clk->rate *= pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0003] * PLL2 ; + clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * PLL2 ; } static struct clk_ops sh7203_master_clk_ops = { @@ -48,7 +48,7 @@ static struct clk_ops sh7203_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -58,7 +58,7 @@ static struct clk_ops sh7203_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx-2]; } diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c index c2268bdeceeb..b27a5e2687ab 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c @@ -34,7 +34,7 @@ static const int pfc_divisors[]={1,2,3,4,6,8,12}; static void master_clk_init(struct clk *clk) { - clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; + clk->rate *= PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; } static struct clk_ops sh7206_master_clk_ops = { @@ -43,7 +43,7 @@ static struct clk_ops sh7206_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -53,7 +53,7 @@ static struct clk_ops sh7206_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - return clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; + return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; } static struct clk_ops sh7206_bus_clk_ops = { @@ -62,7 +62,7 @@ static struct clk_ops sh7206_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FREQCR) & 0x0007); + int idx = (__raw_readw(FREQCR) & 0x0007); return clk->parent->rate / ifc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh3/clock-sh3.c b/arch/sh/kernel/cpu/sh3/clock-sh3.c index 27b8738f0b09..b78384afac09 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh3.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh3.c @@ -28,7 +28,7 @@ static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; static void master_clk_init(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); clk->rate *= pfc_divisors[idx]; @@ -40,7 +40,7 @@ static struct clk_ops sh3_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); return clk->parent->rate / pfc_divisors[idx]; @@ -52,7 +52,7 @@ static struct clk_ops sh3_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4); return clk->parent->rate / stc_multipliers[idx]; @@ -64,7 +64,7 @@ static struct clk_ops sh3_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); return clk->parent->rate / ifc_divisors[idx]; diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7705.c b/arch/sh/kernel/cpu/sh3/clock-sh7705.c index 0ca8f2c3646c..0ecea1451c6f 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7705.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7705.c @@ -32,7 +32,7 @@ static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; static void master_clk_init(struct clk *clk) { - clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0003]; + clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0003]; } static struct clk_ops sh7705_master_clk_ops = { @@ -41,7 +41,7 @@ static struct clk_ops sh7705_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = ctrl_inw(FRQCR) & 0x0003; + int idx = __raw_readw(FRQCR) & 0x0003; return clk->parent->rate / pfc_divisors[idx]; } @@ -51,7 +51,7 @@ static struct clk_ops sh7705_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0300) >> 8; + int idx = (__raw_readw(FRQCR) & 0x0300) >> 8; return clk->parent->rate / stc_multipliers[idx]; } @@ -61,7 +61,7 @@ static struct clk_ops sh7705_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0030) >> 4; + int idx = (__raw_readw(FRQCR) & 0x0030) >> 4; return clk->parent->rate / ifc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c index 4bf7887d310a..6f9ff8b57dd6 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7706.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c @@ -24,7 +24,7 @@ static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; static void master_clk_init(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); clk->rate *= pfc_divisors[idx]; @@ -36,7 +36,7 @@ static struct clk_ops sh7706_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); return clk->parent->rate / pfc_divisors[idx]; @@ -48,7 +48,7 @@ static struct clk_ops sh7706_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4); return clk->parent->rate / stc_multipliers[idx]; @@ -60,7 +60,7 @@ static struct clk_ops sh7706_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); return clk->parent->rate / ifc_divisors[idx]; diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7709.c b/arch/sh/kernel/cpu/sh3/clock-sh7709.c index e8749505bd2a..f302ba09e681 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7709.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7709.c @@ -24,7 +24,7 @@ static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; static void master_clk_init(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); clk->rate *= pfc_divisors[idx]; @@ -36,7 +36,7 @@ static struct clk_ops sh7709_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); return clk->parent->rate / pfc_divisors[idx]; @@ -48,7 +48,7 @@ static struct clk_ops sh7709_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = (frqcr & 0x0080) ? ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4) : 1; @@ -61,7 +61,7 @@ static struct clk_ops sh7709_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); return clk->parent->rate / ifc_divisors[idx]; diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7710.c b/arch/sh/kernel/cpu/sh3/clock-sh7710.c index 030a58ba18a5..29a87d8946a4 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7710.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7710.c @@ -26,7 +26,7 @@ static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; static void master_clk_init(struct clk *clk) { - clk->rate *= md_table[ctrl_inw(FRQCR) & 0x0007]; + clk->rate *= md_table[__raw_readw(FRQCR) & 0x0007]; } static struct clk_ops sh7710_master_clk_ops = { @@ -35,7 +35,7 @@ static struct clk_ops sh7710_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0007); + int idx = (__raw_readw(FRQCR) & 0x0007); return clk->parent->rate / md_table[idx]; } @@ -45,7 +45,7 @@ static struct clk_ops sh7710_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0700) >> 8; + int idx = (__raw_readw(FRQCR) & 0x0700) >> 8; return clk->parent->rate / md_table[idx]; } @@ -55,7 +55,7 @@ static struct clk_ops sh7710_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0070) >> 4; + int idx = (__raw_readw(FRQCR) & 0x0070) >> 4; return clk->parent->rate / md_table[idx]; } diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7712.c b/arch/sh/kernel/cpu/sh3/clock-sh7712.c index 6428ee6c77ed..b0d0c5203996 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7712.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7712.c @@ -23,7 +23,7 @@ static int divisors[] = { 1, 2, 3, 4, 6 }; static void master_clk_init(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = (frqcr & 0x0300) >> 8; clk->rate *= multipliers[idx]; @@ -35,7 +35,7 @@ static struct clk_ops sh7712_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = frqcr & 0x0007; return clk->parent->rate / divisors[idx]; @@ -47,7 +47,7 @@ static struct clk_ops sh7712_module_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int frqcr = ctrl_inw(FRQCR); + int frqcr = __raw_readw(FRQCR); int idx = (frqcr & 0x0030) >> 4; return clk->parent->rate / divisors[idx]; diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c index c2db65719f4d..295ec4c99e98 100644 --- a/arch/sh/kernel/cpu/sh3/probe.c +++ b/arch/sh/kernel/cpu/sh3/probe.c @@ -30,23 +30,23 @@ int detect_cpu_and_cache_system(void) addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12); /* First, write back & invalidate */ - data0 = ctrl_inl(addr0); - ctrl_outl(data0&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr0); - data1 = ctrl_inl(addr1); - ctrl_outl(data1&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr1); + data0 = __raw_readl(addr0); + __raw_writel(data0&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr0); + data1 = __raw_readl(addr1); + __raw_writel(data1&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr1); /* Next, check if there's shadow or not */ - data0 = ctrl_inl(addr0); + data0 = __raw_readl(addr0); data0 ^= SH_CACHE_VALID; - ctrl_outl(data0, addr0); - data1 = ctrl_inl(addr1); + __raw_writel(data0, addr0); + data1 = __raw_readl(addr1); data2 = data1 ^ SH_CACHE_VALID; - ctrl_outl(data2, addr1); - data3 = ctrl_inl(addr0); + __raw_writel(data2, addr1); + data3 = __raw_readl(addr0); /* Lastly, invaliate them. */ - ctrl_outl(data0&~SH_CACHE_VALID, addr0); - ctrl_outl(data2&~SH_CACHE_VALID, addr1); + __raw_writel(data0&~SH_CACHE_VALID, addr0); + __raw_writel(data2&~SH_CACHE_VALID, addr1); back_to_cached(); @@ -94,9 +94,9 @@ int detect_cpu_and_cache_system(void) boot_cpu_data.dcache.way_incr = (1 << 13); boot_cpu_data.dcache.entry_mask = 0x1ff0; boot_cpu_data.dcache.sets = 512; - ctrl_outl(CCR_CACHE_32KB, CCR3_REG); + __raw_writel(CCR_CACHE_32KB, CCR3_REG); #else - ctrl_outl(CCR_CACHE_16KB, CCR3_REG); + __raw_writel(CCR_CACHE_16KB, CCR3_REG); #endif #endif } diff --git a/arch/sh/kernel/cpu/sh3/setup-sh3.c b/arch/sh/kernel/cpu/sh3/setup-sh3.c index c98846857855..53be70b98116 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh3.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh3.c @@ -58,7 +58,7 @@ static DECLARE_INTC_DESC_ACK(intc_desc_irq45, "sh3-irq45", void __init plat_irq_setup_pins(int mode) { if (mode == IRQ_MODE_IRQ) { - ctrl_outw(ctrl_inw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1); + __raw_writew(__raw_readw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1); register_intc_controller(&intc_desc_irq0123); return; } diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index 21421e34e7d5..6b80850294da 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -23,7 +23,7 @@ static int frqcr3_values[] = { 0, 1, 2, 3, 4, 5, 6 }; static unsigned long emi_clk_recalc(struct clk *clk) { - int idx = ctrl_inl(CPG2_FRQCR3) & 0x0007; + int idx = __raw_readl(CPG2_FRQCR3) & 0x0007; return clk->parent->rate / frqcr3_divisors[idx]; } @@ -52,7 +52,7 @@ static struct clk sh4202_emi_clk = { static unsigned long femi_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(CPG2_FRQCR3) >> 3) & 0x0007; + int idx = (__raw_readl(CPG2_FRQCR3) >> 3) & 0x0007; return clk->parent->rate / frqcr3_divisors[idx]; } @@ -92,7 +92,7 @@ static void shoc_clk_init(struct clk *clk) static unsigned long shoc_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(CPG2_FRQCR3) >> 6) & 0x0007; + int idx = (__raw_readl(CPG2_FRQCR3) >> 6) & 0x0007; return clk->parent->rate / frqcr3_divisors[idx]; } @@ -122,10 +122,10 @@ static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id) tmp = frqcr3_lookup(clk, rate); - frqcr3 = ctrl_inl(CPG2_FRQCR3); + frqcr3 = __raw_readl(CPG2_FRQCR3); frqcr3 &= ~(0x0007 << 6); frqcr3 |= tmp << 6; - ctrl_outl(frqcr3, CPG2_FRQCR3); + __raw_writel(frqcr3, CPG2_FRQCR3); clk->rate = clk->parent->rate / frqcr3_divisors[tmp]; diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4.c b/arch/sh/kernel/cpu/sh4/clock-sh4.c index 73294d9cd049..5add75c1f539 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4.c @@ -28,7 +28,7 @@ static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; static void master_clk_init(struct clk *clk) { - clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0007]; + clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0007]; } static struct clk_ops sh4_master_clk_ops = { @@ -37,7 +37,7 @@ static struct clk_ops sh4_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) & 0x0007); + int idx = (__raw_readw(FRQCR) & 0x0007); return clk->parent->rate / pfc_divisors[idx]; } @@ -47,7 +47,7 @@ static struct clk_ops sh4_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) >> 3) & 0x0007; + int idx = (__raw_readw(FRQCR) >> 3) & 0x0007; return clk->parent->rate / bfc_divisors[idx]; } @@ -57,7 +57,7 @@ static struct clk_ops sh4_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(FRQCR) >> 6) & 0x0007; + int idx = (__raw_readw(FRQCR) >> 6) & 0x0007; return clk->parent->rate / ifc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index cc02b3145cca..822977a06d84 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -28,9 +28,9 @@ int __init detect_cpu_and_cache_system(void) [9] = (1 << 16) }; - pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff; - prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff; - cvr = (ctrl_inl(CCN_CVR)); + pvr = (__raw_readl(CCN_PVR) >> 8) & 0xffffff; + prr = (__raw_readl(CCN_PRR) >> 4) & 0xff; + cvr = (__raw_readl(CCN_CVR)); /* * Setup some sane SH-4 defaults for the icache diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c index 4b733715cdb5..b9b7e10ad68f 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c @@ -198,7 +198,7 @@ void __init plat_irq_setup_pins(int mode) { switch (mode) { case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */ - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); + __raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); register_intc_controller(&intc_desc_irlm); break; default: diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index b2a9df1af64c..ffd79e57254f 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -442,7 +442,7 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */ - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); + __raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); register_intc_controller(&intc_desc_irlm); break; default: diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 5b74cc0b43da..a16eb3656f4b 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -319,7 +319,7 @@ void __init plat_irq_setup_pins(int mode) { switch (mode) { case IRQ_MODE_IRQ: - ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); + __raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); register_intc_controller(&intc_desc_irq); break; default: diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 8a8a993f55ea..97aea9d69b00 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -43,9 +43,9 @@ static unsigned long *sq_bitmap; #define store_queue_barrier() \ do { \ - (void)ctrl_inl(P4SEG_STORE_QUE); \ - ctrl_outl(0, P4SEG_STORE_QUE + 0); \ - ctrl_outl(0, P4SEG_STORE_QUE + 8); \ + (void)__raw_readl(P4SEG_STORE_QUE); \ + __raw_writel(0, P4SEG_STORE_QUE + 0); \ + __raw_writel(0, P4SEG_STORE_QUE + 8); \ } while (0); /** @@ -123,8 +123,8 @@ static int __sq_remap(struct sq_mapping *map, unsigned long flags) * straightforward, as we can just load up each queue's QACR with * the physical address appropriately masked. */ - ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0); - ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1); + __raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0); + __raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1); #endif return 0; diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c index ddc235ca9664..86aae60677dc 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c @@ -35,7 +35,7 @@ static struct clk_ops sh7757_master_clk_ops = { static void module_clk_recalc(struct clk *clk) { - int idx = ctrl_inl(FRQCR) & 0x0000000f; + int idx = __raw_readl(FRQCR) & 0x0000000f; clk->rate = clk->parent->rate / p1fc_divisors[idx]; } @@ -45,7 +45,7 @@ static struct clk_ops sh7757_module_clk_ops = { static void bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQCR) >> 8) & 0x0000000f; + int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f; clk->rate = clk->parent->rate / bfc_divisors[idx]; } @@ -55,7 +55,7 @@ static struct clk_ops sh7757_bus_clk_ops = { static void cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQCR) >> 20) & 0x0000000f; + int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f; clk->rate = clk->parent->rate / ifc_divisors[idx]; } @@ -78,7 +78,7 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx) static void shyway_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQCR) >> 12) & 0x0000000f; + int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f; clk->rate = clk->parent->rate / sfc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c index 370cd47642ef..9f401163e71e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c @@ -22,7 +22,7 @@ static int cfc_divisors[] = { 1, 1, 4, 1, 1, 1, 1, 1 }; static void master_clk_init(struct clk *clk) { - clk->rate *= p0fc_divisors[(ctrl_inl(FRQCR) >> 4) & 0x07]; + clk->rate *= p0fc_divisors[(__raw_readl(FRQCR) >> 4) & 0x07]; } static struct clk_ops sh7763_master_clk_ops = { @@ -31,7 +31,7 @@ static struct clk_ops sh7763_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 4) & 0x07); + int idx = ((__raw_readl(FRQCR) >> 4) & 0x07); return clk->parent->rate / p0fc_divisors[idx]; } @@ -41,7 +41,7 @@ static struct clk_ops sh7763_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 16) & 0x07); + int idx = ((__raw_readl(FRQCR) >> 16) & 0x07); return clk->parent->rate / bfc_divisors[idx]; } @@ -68,7 +68,7 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx) static unsigned long shyway_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 20) & 0x07); + int idx = ((__raw_readl(FRQCR) >> 20) & 0x07); return clk->parent->rate / cfc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c index e0b896769205..9e3354365d40 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c @@ -21,7 +21,7 @@ static int pfc_divisors[] = { 1, 8, 1,10,12,16, 1, 1 }; static void master_clk_init(struct clk *clk) { - clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> 28) & 0x000f]; + clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> 28) & 0x000f]; } static struct clk_ops sh7770_master_clk_ops = { @@ -30,7 +30,7 @@ static struct clk_ops sh7770_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 28) & 0x000f); + int idx = ((__raw_readl(FRQCR) >> 28) & 0x000f); return clk->parent->rate / pfc_divisors[idx]; } @@ -40,7 +40,7 @@ static struct clk_ops sh7770_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQCR) & 0x000f); + int idx = (__raw_readl(FRQCR) & 0x000f); return clk->parent->rate / bfc_divisors[idx]; } @@ -50,7 +50,7 @@ static struct clk_ops sh7770_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 24) & 0x000f); + int idx = ((__raw_readl(FRQCR) >> 24) & 0x000f); return clk->parent->rate / ifc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c index a249d823578e..150963a6001e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c @@ -22,7 +22,7 @@ static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 }; static void master_clk_init(struct clk *clk) { - clk->rate *= pfc_divisors[ctrl_inl(FRQCR) & 0x0003]; + clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003]; } static struct clk_ops sh7780_master_clk_ops = { @@ -31,7 +31,7 @@ static struct clk_ops sh7780_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inl(FRQCR) & 0x0003); + int idx = (__raw_readl(FRQCR) & 0x0003); return clk->parent->rate / pfc_divisors[idx]; } @@ -41,7 +41,7 @@ static struct clk_ops sh7780_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 16) & 0x0007); + int idx = ((__raw_readl(FRQCR) >> 16) & 0x0007); return clk->parent->rate / bfc_divisors[idx]; } @@ -51,7 +51,7 @@ static struct clk_ops sh7780_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 24) & 0x0001); + int idx = ((__raw_readl(FRQCR) >> 24) & 0x0001); return clk->parent->rate / ifc_divisors[idx]; } @@ -74,7 +74,7 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx) static unsigned long shyway_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> 20) & 0x0007); + int idx = ((__raw_readl(FRQCR) >> 20) & 0x0007); return clk->parent->rate / cfc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c index 23c27d32d982..e75c57bdfa5e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c @@ -33,7 +33,7 @@ static int cfc_divisors[] = { 1, 1, 4, 6 }; static void master_clk_init(struct clk *clk) { - clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK]; + clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK]; } static struct clk_ops shx3_master_clk_ops = { @@ -42,7 +42,7 @@ static struct clk_ops shx3_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK); + int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK); return clk->parent->rate / pfc_divisors[idx]; } @@ -52,7 +52,7 @@ static struct clk_ops shx3_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> BFC_POS) & BFC_MSK); + int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK); return clk->parent->rate / bfc_divisors[idx]; } @@ -62,7 +62,7 @@ static struct clk_ops shx3_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> IFC_POS) & IFC_MSK); + int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK); return clk->parent->rate / ifc_divisors[idx]; } @@ -85,7 +85,7 @@ void __init arch_init_clk_ops(struct clk_ops **ops, int idx) static unsigned long shyway_clk_recalc(struct clk *clk) { - int idx = ((ctrl_inl(FRQCR) >> CFC_POS) & CFC_MSK); + int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK); return clk->parent->rate / cfc_divisors[idx]; } diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index 9d426258aa00..9e8620e3ad3e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -596,7 +596,7 @@ void __init plat_early_device_setup(void) void l2_cache_init(void) { /* Enable L2 cache */ - ctrl_outl(L2_CACHE_ENABLE, RAMCR); + __raw_writel(L2_CACHE_ENABLE, RAMCR); } enum { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index 578e9f80271f..aa0f6e9bb89e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -718,7 +718,7 @@ void __init plat_early_device_setup(void) void l2_cache_init(void) { /* Enable L2 cache */ - ctrl_outl(L2_CACHE_ENABLE, RAMCR); + __raw_writel(L2_CACHE_ENABLE, RAMCR); } enum { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c index 37e32efbbaa7..e75edf58796a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c @@ -487,17 +487,17 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7757-irl4567", vectors_irl4567, void __init plat_irq_setup(void) { /* disable IRQ3-0 + IRQ7-4 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); /* select IRL mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); /* disable holding function, ie enable "SH-4 Mode" */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0); register_intc_controller(&intc_desc); } @@ -507,32 +507,32 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ7654: /* select IRQ mode for IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00400000, INTC_ICR0); register_intc_controller(&intc_desc_irq4567); break; case IRQ_MODE_IRQ3210: /* select IRQ mode for IRL3-0 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0); register_intc_controller(&intc_desc_irq0123); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl4567); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl0123); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c index 6aba26fec416..7f6b0a5f7f82 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c @@ -538,11 +538,11 @@ static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7763-irl3210", irl_vectors, void __init plat_irq_setup(void) { /* disable IRQ7-0 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); register_intc_controller(&intc_desc); } @@ -552,27 +552,27 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ: /* select IRQ mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00c00000, INTC_ICR0); register_intc_controller(&intc_irq_desc); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl7654_desc); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl3210_desc); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c index c1643bc9590d..86d681ecf90e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c @@ -694,17 +694,17 @@ static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors, void __init plat_irq_setup(void) { /* disable IRQ7-0 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); /* select IRL mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); /* disable holding function, ie enable "SH-4 Mode" */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0); register_intc_controller(&intc_desc); } @@ -714,27 +714,27 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ: /* select IRQ mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00c00000, INTC_ICR0); register_intc_controller(&intc_irq_desc); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl7654_desc); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl3210_desc); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index c310558490d5..f8f21618d785 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -461,17 +461,17 @@ static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors, void __init plat_irq_setup(void) { /* disable IRQ7-0 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); /* select IRL mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); /* disable holding function, ie enable "SH-4 Mode" */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0); register_intc_controller(&intc_desc); } @@ -481,27 +481,27 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ: /* select IRQ mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00c00000, INTC_ICR0); register_intc_controller(&intc_irq_desc); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl7654_desc); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_irl3210_desc); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index f685b9b21999..23448d8c6711 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -541,17 +541,17 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567, void __init plat_irq_setup(void) { /* disable IRQ3-0 + IRQ7-4 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); /* select IRL mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); /* disable holding function, ie enable "SH-4 Mode" */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00200000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0); register_intc_controller(&intc_desc); } @@ -561,32 +561,32 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ7654: /* select IRQ mode for IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00400000, INTC_ICR0); register_intc_controller(&intc_desc_irq4567); break; case IRQ_MODE_IRQ3210: /* select IRQ mode for IRL3-0 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0); register_intc_controller(&intc_desc_irq0123); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl4567); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl0123); break; default: diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c index 71673487ace0..7e585320710a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c @@ -867,14 +867,14 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567, void __init plat_irq_setup(void) { /* disable IRQ3-0 + IRQ7-4 */ - ctrl_outl(0xff000000, INTC_INTMSK0); + __raw_writel(0xff000000, INTC_INTMSK0); /* disable IRL3-0 + IRL7-4 */ - ctrl_outl(0xc0000000, INTC_INTMSK1); - ctrl_outl(0xfffefffe, INTC_INTMSK2); + __raw_writel(0xc0000000, INTC_INTMSK1); + __raw_writel(0xfffefffe, INTC_INTMSK2); /* select IRL mode for IRL3-0 + IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0); register_intc_controller(&intc_desc); } @@ -884,32 +884,32 @@ void __init plat_irq_setup_pins(int mode) switch (mode) { case IRQ_MODE_IRQ7654: /* select IRQ mode for IRL7-4 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00400000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00400000, INTC_ICR0); register_intc_controller(&intc_desc_irq4567); break; case IRQ_MODE_IRQ3210: /* select IRQ mode for IRL3-0 */ - ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00800000, INTC_ICR0); + __raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0); register_intc_controller(&intc_desc_irq0123); break; case IRQ_MODE_IRL7654: /* enable IRL7-4 but don't provide any masking */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); - ctrl_outl(0x0000fffe, INTC_INTMSKCLR2); + __raw_writel(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x0000fffe, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL3210: /* enable IRL0-3 but don't provide any masking */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + __raw_writel(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0xfffe0000, INTC_INTMSKCLR2); break; case IRQ_MODE_IRL7654_MASK: /* enable IRL7-4 and mask using cpu intc controller */ - ctrl_outl(0x40000000, INTC_INTMSKCLR1); + __raw_writel(0x40000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl4567); break; case IRQ_MODE_IRL3210_MASK: /* enable IRL0-3 and mask using cpu intc controller */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); + __raw_writel(0x80000000, INTC_INTMSKCLR1); register_intc_controller(&intc_desc_irl0123); break; default: diff --git a/arch/sh/kernel/cpu/sh5/clock-sh5.c b/arch/sh/kernel/cpu/sh5/clock-sh5.c index 7f864ebc51d3..9cfc19b8dbe4 100644 --- a/arch/sh/kernel/cpu/sh5/clock-sh5.c +++ b/arch/sh/kernel/cpu/sh5/clock-sh5.c @@ -24,7 +24,7 @@ static unsigned long cprc_base; static void master_clk_init(struct clk *clk) { - int idx = (ctrl_inl(cprc_base + 0x00) >> 6) & 0x0007; + int idx = (__raw_readl(cprc_base + 0x00) >> 6) & 0x0007; clk->rate *= ifc_table[idx]; } @@ -34,7 +34,7 @@ static struct clk_ops sh5_master_clk_ops = { static unsigned long module_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(cprc_base) >> 12) & 0x0007; + int idx = (__raw_readw(cprc_base) >> 12) & 0x0007; return clk->parent->rate / ifc_table[idx]; } @@ -44,7 +44,7 @@ static struct clk_ops sh5_module_clk_ops = { static unsigned long bus_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(cprc_base) >> 3) & 0x0007; + int idx = (__raw_readw(cprc_base) >> 3) & 0x0007; return clk->parent->rate / ifc_table[idx]; } @@ -54,7 +54,7 @@ static struct clk_ops sh5_bus_clk_ops = { static unsigned long cpu_clk_recalc(struct clk *clk) { - int idx = (ctrl_inw(cprc_base) & 0x0007); + int idx = (__raw_readw(cprc_base) & 0x0007); return clk->parent->rate / ifc_table[idx]; } diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 69be603aa2d7..16b83cc89a41 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -184,31 +184,31 @@ static unsigned long long copy_word(unsigned long src_addr, int src_len, switch (src_len) { case 1: - tmp = ctrl_inb(src_addr); + tmp = __raw_readb(src_addr); break; case 2: - tmp = ctrl_inw(src_addr); + tmp = __raw_readw(src_addr); break; case 4: - tmp = ctrl_inl(src_addr); + tmp = __raw_readl(src_addr); break; case 8: - tmp = ctrl_inq(src_addr); + tmp = __raw_readq(src_addr); break; } switch (dst_len) { case 1: - ctrl_outb(tmp, dst_addr); + __raw_writeb(tmp, dst_addr); break; case 2: - ctrl_outw(tmp, dst_addr); + __raw_writew(tmp, dst_addr); break; case 4: - ctrl_outl(tmp, dst_addr); + __raw_writel(tmp, dst_addr); break; case 8: - ctrl_outq(tmp, dst_addr); + __raw_writeq(tmp, dst_addr); break; } diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index b6f43f0ea743..3cb88f114d7a 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -41,7 +41,7 @@ void show_regs(struct pt_regs * regs) printk("PC : %08lx SP : %08lx SR : %08lx ", regs->pc, regs->regs[15], regs->sr); #ifdef CONFIG_MMU - printk("TEA : %08x\n", ctrl_inl(MMU_TEA)); + printk("TEA : %08x\n", __raw_readl(MMU_TEA)); #else printk("\n"); #endif diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 6a7cce79eb4e..579cd2ca358d 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -528,7 +528,7 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs, /* fallthrough */ case -ERESTARTNOINTR: regs->regs[0] = save_r0; - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); break; } } @@ -626,9 +626,9 @@ no_signal: regs->regs[0] == -ERESTARTSYS || regs->regs[0] == -ERESTARTNOINTR) { regs->regs[0] = save_r0; - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); regs->regs[3] = __NR_restart_syscall; } } diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 7b036339dc92..0830c2a9f712 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -58,7 +58,7 @@ BUILD_TRAP_HANDLER(debug) TRAP_HANDLER_DECL; /* Rewind */ - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff, SIGTRAP) == NOTIFY_STOP) @@ -75,7 +75,7 @@ BUILD_TRAP_HANDLER(bug) TRAP_HANDLER_DECL; /* Rewind */ - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff, SIGTRAP) == NOTIFY_STOP) diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index 48ce82ee9fd2..690ed010d002 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c @@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter) */ jump_to_uncached(); - ccr = ctrl_inl(CCR); + ccr = __raw_readl(CCR); if ((ccr & CCR_CACHE_ENABLE) == 0) { back_to_cached(); @@ -89,7 +89,7 @@ static int cache_seq_show(struct seq_file *file, void *iter) for (addr = addrstart, line = 0; addr < addrstart + waysize; addr += cache->linesz, line++) { - unsigned long data = ctrl_inl(addr); + unsigned long data = __raw_readl(addr); /* Check the V bit, ignore invalid cachelines */ if ((data & 1) == 0) diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c index 699a71f46327..defcf719f2e8 100644 --- a/arch/sh/mm/cache-sh2.c +++ b/arch/sh/mm/cache-sh2.c @@ -28,10 +28,10 @@ static void sh2__flush_wback_region(void *start, int size) unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0); int way; for (way = 0; way < 4; way++) { - unsigned long data = ctrl_inl(addr | (way << 12)); + unsigned long data = __raw_readl(addr | (way << 12)); if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { data &= ~SH_CACHE_UPDATED; - ctrl_outl(data, addr | (way << 12)); + __raw_writel(data, addr | (way << 12)); } } } @@ -47,7 +47,7 @@ static void sh2__flush_purge_region(void *start, int size) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); } @@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size) local_irq_save(flags); jump_to_uncached(); - ccr = ctrl_inl(CCR); + ccr = __raw_readl(CCR); ccr |= CCR_CACHE_INVALIDATE; - ctrl_outl(ccr, CCR); + __raw_writel(ccr, CCR); back_to_cached(); local_irq_restore(flags); @@ -78,7 +78,7 @@ static void sh2__flush_invalidate_region(void *start, int size) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); #endif } diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index 975899d83564..1f51225426a2 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c @@ -32,10 +32,10 @@ static void sh2a__flush_wback_region(void *start, int size) unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0); int way; for (way = 0; way < 4; way++) { - unsigned long data = ctrl_inl(addr | (way << 11)); + unsigned long data = __raw_readl(addr | (way << 11)); if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { data &= ~SH_CACHE_UPDATED; - ctrl_outl(data, addr | (way << 11)); + __raw_writel(data, addr | (way << 11)); } } } @@ -58,7 +58,7 @@ static void sh2a__flush_purge_region(void *start, int size) jump_to_uncached(); for (v = begin; v < end; v+=L1_CACHE_BYTES) { - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); } back_to_cached(); @@ -78,17 +78,17 @@ static void sh2a__flush_invalidate_region(void *start, int size) jump_to_uncached(); #ifdef CONFIG_CACHE_WRITEBACK - ctrl_outl(ctrl_inl(CCR) | CCR_OCACHE_INVALIDATE, CCR); + __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR); /* I-cache invalidate */ for (v = begin; v < end; v+=L1_CACHE_BYTES) { - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); } #else for (v = begin; v < end; v+=L1_CACHE_BYTES) { - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); - ctrl_outl((v & CACHE_PHYSADDR_MASK), + __raw_writel((v & CACHE_PHYSADDR_MASK), CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); } #endif @@ -115,14 +115,14 @@ static void sh2a_flush_icache_range(void *args) int way; /* O-Cache writeback */ for (way = 0; way < 4; way++) { - unsigned long data = ctrl_inl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); + unsigned long data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { data &= ~SH_CACHE_UPDATED; - ctrl_outl(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); + __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); } } /* I-Cache invalidate */ - ctrl_outl(addr, + __raw_writel(addr, CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); } diff --git a/arch/sh/mm/cache-sh3.c b/arch/sh/mm/cache-sh3.c index faef80c98134..e37523f65195 100644 --- a/arch/sh/mm/cache-sh3.c +++ b/arch/sh/mm/cache-sh3.c @@ -50,12 +50,12 @@ static void sh3__flush_wback_region(void *start, int size) p = __pa(v); addr = addrstart | (v & current_cpu_data.dcache.entry_mask); local_irq_save(flags); - data = ctrl_inl(addr); + data = __raw_readl(addr); if ((data & CACHE_PHYSADDR_MASK) == (p & CACHE_PHYSADDR_MASK)) { data &= ~SH_CACHE_UPDATED; - ctrl_outl(data, addr); + __raw_writel(data, addr); local_irq_restore(flags); break; } @@ -86,7 +86,7 @@ static void sh3__flush_purge_region(void *start, int size) data = (v & 0xfffffc00); /* _Virtual_ address, ~U, ~V */ addr = CACHE_OC_ADDRESS_ARRAY | (v & current_cpu_data.dcache.entry_mask) | SH_CACHE_ASSOC; - ctrl_outl(data, addr); + __raw_writel(data, addr); } } diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 87115b3ee70e..2cfae81914aa 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -132,9 +132,9 @@ static void flush_icache_all(void) jump_to_uncached(); /* Flush I-cache */ - ccr = ctrl_inl(CCR); + ccr = __raw_readl(CCR); ccr |= CCR_CACHE_ICI; - ctrl_outl(ccr, CCR); + __raw_writel(ccr, CCR); /* * back_to_cached() will take care of the barrier for us, don't add @@ -377,9 +377,9 @@ extern void __weak sh4__flush_region_init(void); void __init sh4_cache_init(void) { printk("PVR=%08x CVR=%08x PRR=%08x\n", - ctrl_inl(CCN_PVR), - ctrl_inl(CCN_CVR), - ctrl_inl(CCN_PRR)); + __raw_readl(CCN_PVR), + __raw_readl(CCN_CVR), + __raw_readl(CCN_PRR)); local_flush_icache_range = sh4_flush_icache_range; local_flush_dcache_page = sh4_flush_dcache_page; diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 870293ee539e..f498da1cce7a 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -48,10 +48,10 @@ static inline void cache_wback_all(void) unsigned long data; int v = SH_CACHE_UPDATED | SH_CACHE_VALID; - data = ctrl_inl(addr); + data = __raw_readl(addr); if ((data & v) == v) - ctrl_outl(data & ~v, addr); + __raw_writel(data & ~v, addr); } @@ -115,10 +115,10 @@ static void __flush_dcache_page(unsigned long phys) addr += current_cpu_data.dcache.linesz) { unsigned long data; - data = ctrl_inl(addr) & (0x1ffffC00 | SH_CACHE_VALID); + data = __raw_readl(addr) & (0x1ffffC00 | SH_CACHE_VALID); if (data == phys) { data &= ~(SH_CACHE_VALID | SH_CACHE_UPDATED); - ctrl_outl(data, addr); + __raw_writel(data, addr); } } diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 3d5eece7e6d0..3c9bf5b5c36f 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -112,7 +112,7 @@ static void pmb_free(struct pmb_entry *pmbe) static void __set_pmb_entry(unsigned long vpn, unsigned long ppn, unsigned long flags, int pos) { - ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); + __raw_writel(vpn | PMB_V, mk_pmb_addr(pos)); #ifdef CONFIG_CACHE_WRITETHROUGH /* @@ -124,7 +124,7 @@ static void __set_pmb_entry(unsigned long vpn, unsigned long ppn, flags |= PMB_WT; #endif - ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos)); + __raw_writel(ppn | flags | PMB_V, mk_pmb_data(pos)); } static void set_pmb_entry(struct pmb_entry *pmbe) @@ -146,10 +146,10 @@ static void clear_pmb_entry(struct pmb_entry *pmbe) /* Clear V-bit */ addr = mk_pmb_addr(entry); - ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); + __raw_writel(__raw_readl(addr) & ~PMB_V, addr); addr = mk_pmb_data(entry); - ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); + __raw_writel(__raw_readl(addr) & ~PMB_V, addr); back_to_cached(); } @@ -395,7 +395,7 @@ int pmb_init(void) unsigned long vpn, ppn, flags; addr = PMB_DATA + (i << PMB_E_SHIFT); - data = ctrl_inl(addr); + data = __raw_readl(addr); if (!(data & PMB_V)) continue; @@ -408,7 +408,7 @@ int pmb_init(void) data &= ~(PMB_C | PMB_WT); #endif } - ctrl_outl(data, addr); + __raw_writel(data, addr); ppn = data & PMB_PFN_MASK; @@ -416,7 +416,7 @@ int pmb_init(void) flags |= data & PMB_SZ_MASK; addr = PMB_ADDR + (i << PMB_E_SHIFT); - data = ctrl_inl(addr); + data = __raw_readl(addr); vpn = data & PMB_PFN_MASK; @@ -424,12 +424,12 @@ int pmb_init(void) WARN_ON(IS_ERR(pmbe)); } - ctrl_outl(0, PMB_IRMCR); + __raw_writel(0, PMB_IRMCR); /* Flush out the TLB */ - i = ctrl_inl(MMUCR); + i = __raw_readl(MMUCR); i |= MMUCR_TI; - ctrl_outl(i, MMUCR); + __raw_writel(i, MMUCR); back_to_cached(); @@ -454,8 +454,8 @@ static int pmb_seq_show(struct seq_file *file, void *iter) unsigned int size; char *sz_str = NULL; - addr = ctrl_inl(mk_pmb_addr(i)); - data = ctrl_inl(mk_pmb_data(i)); + addr = __raw_readl(mk_pmb_addr(i)); + data = __raw_readl(mk_pmb_data(i)); size = data & PMB_SZ_MASK; sz_str = (size == PMB_SZ_16M) ? " 16MB": diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index ace8e6d2f59d..4f5f7cbdd508 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -41,14 +41,14 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) /* Set PTEH register */ vpn = (address & MMU_VPN_MASK) | get_asid(); - ctrl_outl(vpn, MMU_PTEH); + __raw_writel(vpn, MMU_PTEH); pteval = pte_val(pte); /* Set PTEL register */ pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ /* conveniently, we want all the software flags to be 0 anyway */ - ctrl_outl(pteval, MMU_PTEL); + __raw_writel(pteval, MMU_PTEL); /* Load the TLB */ asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); @@ -75,5 +75,5 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) } for (i = 0; i < ways; i++) - ctrl_outl(data, addr + (i << 8)); + __raw_writel(data, addr + (i << 8)); } diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 624c1daa9f3f..ccac77f504a8 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -29,7 +29,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) /* Set PTEH register */ vpn = (address & MMU_VPN_MASK) | get_asid(); - ctrl_outl(vpn, MMU_PTEH); + __raw_writel(vpn, MMU_PTEH); pteval = pte.pte_low; @@ -41,13 +41,13 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) * the protection bits (with the exception of the compat-mode SZ * and PR bits, which are cleared) being written out in PTEL. */ - ctrl_outl(pte.pte_high, MMU_PTEA); + __raw_writel(pte.pte_high, MMU_PTEA); #else if (cpu_data->flags & CPU_HAS_PTEA) { /* The last 3 bits and the first one of pteval contains * the PTEA timing control and space attribute bits */ - ctrl_outl(copy_ptea_attributes(pteval), MMU_PTEA); + __raw_writel(copy_ptea_attributes(pteval), MMU_PTEA); } #endif @@ -57,7 +57,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) pteval |= _PAGE_WT; #endif /* conveniently, we want all the software flags to be 0 anyway */ - ctrl_outl(pteval, MMU_PTEL); + __raw_writel(pteval, MMU_PTEL); /* Load the TLB */ asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); @@ -77,6 +77,6 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT; data = page | asid; /* VALID bit is off */ jump_to_uncached(); - ctrl_outl(data, addr); + __raw_writel(data, addr); back_to_cached(); } diff --git a/arch/sh/mm/tlbflush_32.c b/arch/sh/mm/tlbflush_32.c index 6f45c1f8a7fe..004bb3f25b5f 100644 --- a/arch/sh/mm/tlbflush_32.c +++ b/arch/sh/mm/tlbflush_32.c @@ -132,9 +132,9 @@ void local_flush_tlb_all(void) * It's same position, bit #2. */ local_irq_save(flags); - status = ctrl_inl(MMUCR); + status = __raw_readl(MMUCR); status |= 0x04; - ctrl_outl(status, MMUCR); + __raw_writel(status, MMUCR); ctrl_barrier(); local_irq_restore(flags); } -- GitLab From 485773f3e401fca31c112c1ff24797e42ff87afd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 26 Jan 2010 13:02:10 +0900 Subject: [PATCH 1186/3892] sh: flag ctrl_in/outX as __deprecated. These routines are unsuitable for cross-platform use and no new code should be using them, flag them as deprecated in order to give drivers sufficient time to migrate over. Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 55 ++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index e4f563f472eb..98c62fa168c2 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -80,16 +80,51 @@ #define writel(v,a) ({ __raw_writel((v),(a)); mb(); }) #define writeq(v,a) ({ __raw_writeq((v),(a)); mb(); }) -/* SuperH on-chip I/O functions */ -#define ctrl_inb __raw_readb -#define ctrl_inw __raw_readw -#define ctrl_inl __raw_readl -#define ctrl_inq __raw_readq - -#define ctrl_outb __raw_writeb -#define ctrl_outw __raw_writew -#define ctrl_outl __raw_writel -#define ctrl_outq __raw_writeq +/* + * Legacy SuperH on-chip I/O functions + * + * These are all deprecated, all new (and especially cross-platform) code + * should be using the __raw_xxx() routines directly. + */ +static inline u8 __deprecated ctrl_inb(unsigned long addr) +{ + return __raw_readb(addr); +} + +static inline u16 __deprecated ctrl_inw(unsigned long addr) +{ + return __raw_readw(addr); +} + +static inline u32 __deprecated ctrl_inl(unsigned long addr) +{ + return __raw_readl(addr); +} + +static inline u64 __deprecated ctrl_inq(unsigned long addr) +{ + return __raw_readq(addr); +} + +static inline void __deprecated ctrl_outb(u8 v, unsigned long addr) +{ + __raw_writeb(v, addr); +} + +static inline void __deprecated ctrl_outw(u16 v, unsigned long addr) +{ + __raw_writew(v, addr); +} + +static inline void __deprecated ctrl_outl(u32 v, unsigned long addr) +{ + __raw_writel(v, addr); +} + +static inline void __deprecated ctrl_outq(u64 v, unsigned long addr) +{ + __raw_writeq(v, addr); +} extern unsigned long generic_io_base; -- GitLab From cbe132a8bdcff0f9afd9060948fb50597c7400b8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 26 Jan 2010 15:08:49 +1100 Subject: [PATCH 1187/3892] xfs: don't hold onto reserved blocks on remount,ro If we hold onto reserved blocks when doing a remount,ro we end up writing the blocks used count to disk that includes the reserved blocks. Reserved blocks are not actually used, so this results in the values in the superblock being incorrect. Hence if we run xfs_check or xfs_repair -n while the filesystem is mounted remount,ro we end up with an inconsistent filesystem being reported. Also, running xfs_copy on the remount,ro filesystem will result in an inconsistent image being generated. To fix this, unreserve the blocks when doing the remount,ro, and reserved them again on remount,rw. This way a remount,ro filesystem will appear consistent on disk to all utilities. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_super.c | 28 ++++++++++++++++++++++++++++ fs/xfs/xfs_mount.h | 1 + 2 files changed, 29 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 9f2e398a5616..e9c21454b9e2 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1318,6 +1318,8 @@ xfs_fs_remount( /* ro -> rw */ if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { + __uint64_t resblks; + mp->m_flags &= ~XFS_MOUNT_RDONLY; if (mp->m_flags & XFS_MOUNT_BARRIER) xfs_mountfs_check_barriers(mp); @@ -1335,11 +1337,37 @@ xfs_fs_remount( } mp->m_update_flags = 0; } + + /* + * Fill out the reserve pool if it is empty. Use the stashed + * value if it is non-zero, otherwise go with the default. + */ + if (mp->m_resblks_save) { + resblks = mp->m_resblks_save; + mp->m_resblks_save = 0; + } else { + resblks = mp->m_sb.sb_dblocks; + do_div(resblks, 20); + resblks = min_t(__uint64_t, resblks, 1024); + } + xfs_reserve_blocks(mp, &resblks, NULL); } /* rw -> ro */ if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { + /* + * After we have synced the data but before we sync the + * metadata, we need to free up the reserve block pool so that + * the used block count in the superblock on disk is correct at + * the end of the remount. Stash the current reserve pool size + * so that if we get remounted rw, we can return it to the same + * size. + */ + __uint64_t resblks = 0; + xfs_quiesce_data(mp); + mp->m_resblks_save = mp->m_resblks; + xfs_reserve_blocks(mp, &resblks, NULL); xfs_quiesce_attr(mp); mp->m_flags |= XFS_MOUNT_RDONLY; } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f4d1441f3f15..02d45f213e58 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -225,6 +225,7 @@ typedef struct xfs_mount { __uint64_t m_maxioffset; /* maximum inode offset */ __uint64_t m_resblks; /* total reserved blocks */ __uint64_t m_resblks_avail;/* available reserved blocks */ + __uint64_t m_resblks_save; /* reserved blks @ remount,ro */ int m_dalign; /* stripe unit */ int m_swidth; /* stripe width */ int m_sinoalign; /* stripe unit inode alignment */ -- GitLab From 388f1f0c346b533b06d8bc792f7204ebc3e4b7da Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 26 Jan 2010 15:10:15 +1100 Subject: [PATCH 1188/3892] xfs: turn off sign warnings Because they cause warnings in static inline functions conditionally compiled into XFS from the VFS (e.g. fsnotify). Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 19267019dacf..5c5a366aa332 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -16,7 +16,7 @@ # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 -Wpointer-sign +EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 XFS_LINUX := linux-2.6 -- GitLab From d5db0f97fbbeff11c88dec1aaf1536a975afbaeb Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 5 Feb 2010 22:59:53 +0000 Subject: [PATCH 1189/3892] xfs: more reserved blocks fixups This mangles the reserved blocks counts a little more. 1) add a helper function for the default reserved count 2) add helper functions to save/restore counts on ro/rw 3) save/restore reserved blocks on freeze/thaw 4) disallow changing reserved count while readonly V2: changed field name to match Dave's changes Signed-off-by: Eric Sandeen Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_ioctl.c | 3 +++ fs/xfs/linux-2.6/xfs_super.c | 51 ++++++++++++++++++++++++++---------- fs/xfs/xfs_mount.c | 34 ++++++++++++++++-------- fs/xfs/xfs_mount.h | 1 + 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 3906e85abfdc..4ea1ee18aded 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -1431,6 +1431,9 @@ xfs_file_ioctl( if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (mp->m_flags & XFS_MOUNT_RDONLY) + return -XFS_ERROR(EROFS); + if (copy_from_user(&inout, arg, sizeof(inout))) return -XFS_ERROR(EFAULT); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index e9c21454b9e2..6ce828e0e17b 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1256,6 +1256,29 @@ xfs_fs_statfs( return 0; } +STATIC void +xfs_save_resvblks(struct xfs_mount *mp) +{ + __uint64_t resblks = 0; + + mp->m_resblks_save = mp->m_resblks; + xfs_reserve_blocks(mp, &resblks, NULL); +} + +STATIC void +xfs_restore_resvblks(struct xfs_mount *mp) +{ + __uint64_t resblks; + + if (mp->m_resblks_save) { + resblks = mp->m_resblks_save; + mp->m_resblks_save = 0; + } else + resblks = xfs_default_resblks(mp); + + xfs_reserve_blocks(mp, &resblks, NULL); +} + STATIC int xfs_fs_remount( struct super_block *sb, @@ -1318,8 +1341,6 @@ xfs_fs_remount( /* ro -> rw */ if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { - __uint64_t resblks; - mp->m_flags &= ~XFS_MOUNT_RDONLY; if (mp->m_flags & XFS_MOUNT_BARRIER) xfs_mountfs_check_barriers(mp); @@ -1342,15 +1363,7 @@ xfs_fs_remount( * Fill out the reserve pool if it is empty. Use the stashed * value if it is non-zero, otherwise go with the default. */ - if (mp->m_resblks_save) { - resblks = mp->m_resblks_save; - mp->m_resblks_save = 0; - } else { - resblks = mp->m_sb.sb_dblocks; - do_div(resblks, 20); - resblks = min_t(__uint64_t, resblks, 1024); - } - xfs_reserve_blocks(mp, &resblks, NULL); + xfs_restore_resvblks(mp); } /* rw -> ro */ @@ -1363,11 +1376,9 @@ xfs_fs_remount( * so that if we get remounted rw, we can return it to the same * size. */ - __uint64_t resblks = 0; xfs_quiesce_data(mp); - mp->m_resblks_save = mp->m_resblks; - xfs_reserve_blocks(mp, &resblks, NULL); + xfs_save_resvblks(mp); xfs_quiesce_attr(mp); mp->m_flags |= XFS_MOUNT_RDONLY; } @@ -1386,10 +1397,21 @@ xfs_fs_freeze( { struct xfs_mount *mp = XFS_M(sb); + xfs_save_resvblks(mp); xfs_quiesce_attr(mp); return -xfs_fs_log_dummy(mp); } +STATIC int +xfs_fs_unfreeze( + struct super_block *sb) +{ + struct xfs_mount *mp = XFS_M(sb); + + xfs_restore_resvblks(mp); + return 0; +} + STATIC int xfs_fs_show_options( struct seq_file *m, @@ -1612,6 +1634,7 @@ static const struct super_operations xfs_super_operations = { .put_super = xfs_fs_put_super, .sync_fs = xfs_fs_sync_fs, .freeze_fs = xfs_fs_freeze, + .unfreeze_fs = xfs_fs_unfreeze, .statfs = xfs_fs_statfs, .remount_fs = xfs_fs_remount, .show_options = xfs_fs_show_options, diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 7f81ed72c875..5061149b2cc4 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1091,6 +1091,22 @@ xfs_mount_reset_sbqflags( return xfs_trans_commit(tp, 0); } +__uint64_t +xfs_default_resblks(xfs_mount_t *mp) +{ + __uint64_t resblks; + + /* + * We default to 5% or 1024 fsbs of space reserved, whichever is smaller. + * This may drive us straight to ENOSPC on mount, but that implies + * we were already there on the last unmount. Warn if this occurs. + */ + resblks = mp->m_sb.sb_dblocks; + do_div(resblks, 20); + resblks = min_t(__uint64_t, resblks, 1024); + return resblks; +} + /* * This function does the following on an initial mount of a file system: * - reads the superblock from disk and init the mount struct @@ -1401,18 +1417,14 @@ xfs_mountfs( * when at ENOSPC. This is needed for operations like create with * attr, unwritten extent conversion at ENOSPC, etc. Data allocations * are not allowed to use this reserved space. - * - * We default to 5% or 1024 fsbs of space reserved, whichever is smaller. - * This may drive us straight to ENOSPC on mount, but that implies - * we were already there on the last unmount. Warn if this occurs. */ - resblks = mp->m_sb.sb_dblocks; - do_div(resblks, 20); - resblks = min_t(__uint64_t, resblks, 1024); - error = xfs_reserve_blocks(mp, &resblks, NULL); - if (error) - cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. " - "Continuing without a reserve pool."); + if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { + resblks = xfs_default_resblks(mp); + error = xfs_reserve_blocks(mp, &resblks, NULL); + if (error) + cmn_err(CE_WARN, "XFS: Unable to allocate reserve " + "blocks. Continuing without a reserve pool."); + } return 0; diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 02d45f213e58..70504fcf14cd 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -421,6 +421,7 @@ typedef struct xfs_mod_sb { } xfs_mod_sb_t; extern int xfs_log_sbcount(xfs_mount_t *, uint); +extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp); extern void xfs_unmountfs(xfs_mount_t *); -- GitLab From 777df5afdb26c71634edd60582be620ff94e87a0 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Sat, 6 Feb 2010 12:37:26 +1100 Subject: [PATCH 1190/3892] xfs: Make inode reclaim states explicit A.K.A.: don't rely on xfs_iflush() return value in reclaim We have gradually been moving checks out of the reclaim code because they are duplicated in xfs_iflush(). We've had a history of problems in this area, and many of them stem from the overloading of the return values from xfs_iflush() and interaction with inode flush locking to determine if the inode is safe to reclaim. With the desire to move to delayed write flushing of inodes and non-blocking inode tree reclaim walks, the overloading of the return value of xfs_iflush makes it very difficult to determine the correct thing to do next. This patch explicitly re-adds the checks to the inode reclaim code, removing the reliance on the return value of xfs_iflush() to determine what to do next. It also means that we can clearly document all the inode states that reclaim must handle and hence we can easily see that we handled all the necessary cases. This also removes the need for the xfs_inode_clean() check in xfs_iflush() as all callers now check this first (safely). Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_sync.c | 81 ++++++++++++++++++++++++++++--------- fs/xfs/xfs_inode.c | 11 +---- fs/xfs/xfs_inode.h | 1 + 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index c9b863eacab7..525260c7617f 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -706,12 +706,43 @@ __xfs_inode_clear_reclaim_tag( XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); } +/* + * Inodes in different states need to be treated differently, and the return + * value of xfs_iflush is not sufficient to get this right. The following table + * lists the inode states and the reclaim actions necessary for non-blocking + * reclaim: + * + * + * inode state iflush ret required action + * --------------- ---------- --------------- + * bad - reclaim + * shutdown EIO unpin and reclaim + * clean, unpinned 0 reclaim + * stale, unpinned 0 reclaim + * clean, pinned(*) 0 unpin and reclaim + * stale, pinned 0 unpin and reclaim + * dirty, async 0 block on flush lock, reclaim + * dirty, sync flush 0 block on flush lock, reclaim + * + * (*) dgc: I don't think the clean, pinned state is possible but it gets + * handled anyway given the order of checks implemented. + * + * Hence the order of actions after gaining the locks should be: + * bad => reclaim + * shutdown => unpin and reclaim + * pinned => unpin + * stale => reclaim + * clean => reclaim + * dirty => flush, wait and reclaim + */ STATIC int xfs_reclaim_inode( struct xfs_inode *ip, struct xfs_perag *pag, int sync_mode) { + int error; + /* * The radix tree lock here protects a thread in xfs_iget from racing * with us starting reclaim on the inode. Once we have the @@ -729,30 +760,42 @@ xfs_reclaim_inode( spin_unlock(&ip->i_flags_lock); write_unlock(&pag->pag_ici_lock); - /* - * If the inode is still dirty, then flush it out. If the inode - * is not in the AIL, then it will be OK to flush it delwri as - * long as xfs_iflush() does not keep any references to the inode. - * We leave that decision up to xfs_iflush() since it has the - * knowledge of whether it's OK to simply do a delwri flush of - * the inode or whether we need to wait until the inode is - * pulled from the AIL. - * We get the flush lock regardless, though, just to make sure - * we don't free it while it is being flushed. - */ xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_iflock(ip); - /* - * In the case of a forced shutdown we rely on xfs_iflush() to - * wait for the inode to be unpinned before returning an error. - */ - if (!is_bad_inode(VFS_I(ip)) && xfs_iflush(ip, sync_mode) == 0) { - /* synchronize with xfs_iflush_done */ - xfs_iflock(ip); - xfs_ifunlock(ip); + if (is_bad_inode(VFS_I(ip))) + goto reclaim; + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { + xfs_iunpin_wait(ip); + goto reclaim; + } + if (xfs_ipincount(ip)) + xfs_iunpin_wait(ip); + if (xfs_iflags_test(ip, XFS_ISTALE)) + goto reclaim; + if (xfs_inode_clean(ip)) + goto reclaim; + + /* Now we have an inode that needs flushing */ + error = xfs_iflush(ip, sync_mode); + if (!error) { + switch(sync_mode) { + case XFS_IFLUSH_DELWRI_ELSE_ASYNC: + case XFS_IFLUSH_DELWRI: + case XFS_IFLUSH_ASYNC: + case XFS_IFLUSH_DELWRI_ELSE_SYNC: + case XFS_IFLUSH_SYNC: + /* IO issued, synchronise with IO completion */ + xfs_iflock(ip); + break; + default: + ASSERT(0); + break; + } } +reclaim: + xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_ireclaim(ip); return 0; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d0d1b5a05183..8d0666dd170a 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2493,7 +2493,7 @@ __xfs_iunpin_wait( wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0)); } -static inline void +void xfs_iunpin_wait( xfs_inode_t *ip) { @@ -2848,15 +2848,6 @@ xfs_iflush( iip = ip->i_itemp; mp = ip->i_mount; - /* - * If the inode isn't dirty, then just release the inode flush lock and - * do nothing. - */ - if (xfs_inode_clean(ip)) { - xfs_ifunlock(ip); - return 0; - } - /* * We can't flush the inode until it is unpinned, so wait for it if we * are allowed to block. We know noone new can pin it, because we are diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index ec1f28c4fc4f..8b618ea4d692 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -483,6 +483,7 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); void xfs_iext_realloc(xfs_inode_t *, int, int); void xfs_ipin(xfs_inode_t *); void xfs_iunpin(xfs_inode_t *); +void xfs_iunpin_wait(xfs_inode_t *); int xfs_iflush(xfs_inode_t *, uint); void xfs_ichgtime(xfs_inode_t *, int); void xfs_lock_inodes(xfs_inode_t **, int, uint); -- GitLab From c854363e80b49dd04a4de18ebc379eb8c8806674 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Sat, 6 Feb 2010 12:39:36 +1100 Subject: [PATCH 1191/3892] xfs: Use delayed write for inodes rather than async V2 We currently do background inode flush asynchronously, resulting in inodes being written in whatever order the background writeback issues them. Not only that, there are also blocking and non-blocking asynchronous inode flushes, depending on where the flush comes from. This patch completely removes asynchronous inode writeback. It removes all the strange writeback modes and replaces them with either a synchronous flush or a non-blocking delayed write flush. That is, inode flushes will only issue IO directly if they are synchronous, and background flushing may do nothing if the operation would block (e.g. on a pinned inode or buffer lock). Delayed write flushes will now result in the inode buffer sitting in the delwri queue of the buffer cache to be flushed by either an AIL push or by the xfsbufd timing out the buffer. This will allow accumulation of dirty inode buffers in memory and allow optimisation of inode cluster writeback at the xfsbufd level where we have much greater queue depths than the block layer elevators. We will also get adjacent inode cluster buffer IO merging for free when a later patch in the series allows sorting of the delayed write buffers before dispatch. This effectively means that any inode that is written back by background writeback will be seen as flush locked during AIL pushing, and will result in the buffers being pushed from there. This writeback path is currently non-optimal, but the next patch in the series will fix that problem. A side effect of this delayed write mechanism is that background inode reclaim will no longer directly flush inodes, nor can it wait on the flush lock. The result is that inode reclaim must leave the inode in the reclaimable state until it is clean. Hence attempts to reclaim a dirty inode in the background will simply skip the inode until it is clean and this allows other mechanisms (i.e. xfsbufd) to do more optimal writeback of the dirty buffers. As a result, the inode reclaim code has been rewritten so that it no longer relies on the ambiguous return values of xfs_iflush() to determine whether it is safe to reclaim an inode. Portions of this patch are derived from patches by Christoph Hellwig. Version 2: - cleanup reclaim code as suggested by Christoph - log background reclaim inode flush errors - just pass sync flags to xfs_iflush Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_super.c | 4 +- fs/xfs/linux-2.6/xfs_sync.c | 105 +++++++++++++++++++++++++---------- fs/xfs/xfs_inode.c | 75 ++----------------------- fs/xfs/xfs_inode.h | 10 ---- fs/xfs/xfs_inode_item.c | 10 +++- fs/xfs/xfs_mount.c | 13 ++++- 6 files changed, 102 insertions(+), 115 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 6ce828e0e17b..3b5b46b8e3b9 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1064,7 +1064,7 @@ xfs_fs_write_inode( xfs_ilock(ip, XFS_ILOCK_SHARED); xfs_iflock(ip); - error = xfs_iflush(ip, XFS_IFLUSH_SYNC); + error = xfs_iflush(ip, SYNC_WAIT); } else { error = EAGAIN; if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) @@ -1072,7 +1072,7 @@ xfs_fs_write_inode( if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) goto out_unlock; - error = xfs_iflush(ip, XFS_IFLUSH_ASYNC_NOBLOCK); + error = xfs_iflush(ip, 0); } out_unlock: diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 525260c7617f..a9f6d20aff41 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -270,8 +270,7 @@ xfs_sync_inode_attr( goto out_unlock; } - error = xfs_iflush(ip, (flags & SYNC_WAIT) ? - XFS_IFLUSH_SYNC : XFS_IFLUSH_DELWRI); + error = xfs_iflush(ip, flags); out_unlock: xfs_iunlock(ip, XFS_ILOCK_SHARED); @@ -460,16 +459,18 @@ xfs_quiesce_fs( { int count = 0, pincount; + xfs_reclaim_inodes(mp, 0); xfs_flush_buftarg(mp->m_ddev_targp, 0); - xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC); /* * This loop must run at least twice. The first instance of the loop * will flush most meta data but that will generate more meta data * (typically directory updates). Which then must be flushed and - * logged before we can write the unmount record. + * logged before we can write the unmount record. We also so sync + * reclaim of inodes to catch any that the above delwri flush skipped. */ do { + xfs_reclaim_inodes(mp, SYNC_WAIT); xfs_sync_attr(mp, SYNC_WAIT); pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); if (!pincount) { @@ -585,7 +586,7 @@ xfs_sync_worker( if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { xfs_log_force(mp, 0); - xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC); + xfs_reclaim_inodes(mp, 0); /* dgc: errors ignored here */ error = xfs_qm_sync(mp, SYNC_TRYLOCK); error = xfs_sync_fsdata(mp, SYNC_TRYLOCK); @@ -719,21 +720,42 @@ __xfs_inode_clear_reclaim_tag( * shutdown EIO unpin and reclaim * clean, unpinned 0 reclaim * stale, unpinned 0 reclaim - * clean, pinned(*) 0 unpin and reclaim - * stale, pinned 0 unpin and reclaim - * dirty, async 0 block on flush lock, reclaim - * dirty, sync flush 0 block on flush lock, reclaim + * clean, pinned(*) 0 requeue + * stale, pinned EAGAIN requeue + * dirty, delwri ok 0 requeue + * dirty, delwri blocked EAGAIN requeue + * dirty, sync flush 0 reclaim * * (*) dgc: I don't think the clean, pinned state is possible but it gets * handled anyway given the order of checks implemented. * + * As can be seen from the table, the return value of xfs_iflush() is not + * sufficient to correctly decide the reclaim action here. The checks in + * xfs_iflush() might look like duplicates, but they are not. + * + * Also, because we get the flush lock first, we know that any inode that has + * been flushed delwri has had the flush completed by the time we check that + * the inode is clean. The clean inode check needs to be done before flushing + * the inode delwri otherwise we would loop forever requeuing clean inodes as + * we cannot tell apart a successful delwri flush and a clean inode from the + * return value of xfs_iflush(). + * + * Note that because the inode is flushed delayed write by background + * writeback, the flush lock may already be held here and waiting on it can + * result in very long latencies. Hence for sync reclaims, where we wait on the + * flush lock, the caller should push out delayed write inodes first before + * trying to reclaim them to minimise the amount of time spent waiting. For + * background relaim, we just requeue the inode for the next pass. + * * Hence the order of actions after gaining the locks should be: * bad => reclaim * shutdown => unpin and reclaim - * pinned => unpin + * pinned, delwri => requeue + * pinned, sync => unpin * stale => reclaim * clean => reclaim - * dirty => flush, wait and reclaim + * dirty, delwri => flush and requeue + * dirty, sync => flush, wait and reclaim */ STATIC int xfs_reclaim_inode( @@ -741,7 +763,7 @@ xfs_reclaim_inode( struct xfs_perag *pag, int sync_mode) { - int error; + int error = 0; /* * The radix tree lock here protects a thread in xfs_iget from racing @@ -761,7 +783,11 @@ xfs_reclaim_inode( write_unlock(&pag->pag_ici_lock); xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_iflock(ip); + if (!xfs_iflock_nowait(ip)) { + if (!(sync_mode & SYNC_WAIT)) + goto out; + xfs_iflock(ip); + } if (is_bad_inode(VFS_I(ip))) goto reclaim; @@ -769,8 +795,13 @@ xfs_reclaim_inode( xfs_iunpin_wait(ip); goto reclaim; } - if (xfs_ipincount(ip)) + if (xfs_ipincount(ip)) { + if (!(sync_mode & SYNC_WAIT)) { + xfs_ifunlock(ip); + goto out; + } xfs_iunpin_wait(ip); + } if (xfs_iflags_test(ip, XFS_ISTALE)) goto reclaim; if (xfs_inode_clean(ip)) @@ -778,27 +809,43 @@ xfs_reclaim_inode( /* Now we have an inode that needs flushing */ error = xfs_iflush(ip, sync_mode); - if (!error) { - switch(sync_mode) { - case XFS_IFLUSH_DELWRI_ELSE_ASYNC: - case XFS_IFLUSH_DELWRI: - case XFS_IFLUSH_ASYNC: - case XFS_IFLUSH_DELWRI_ELSE_SYNC: - case XFS_IFLUSH_SYNC: - /* IO issued, synchronise with IO completion */ - xfs_iflock(ip); - break; - default: - ASSERT(0); - break; - } + if (sync_mode & SYNC_WAIT) { + xfs_iflock(ip); + goto reclaim; } + /* + * When we have to flush an inode but don't have SYNC_WAIT set, we + * flush the inode out using a delwri buffer and wait for the next + * call into reclaim to find it in a clean state instead of waiting for + * it now. We also don't return errors here - if the error is transient + * then the next reclaim pass will flush the inode, and if the error + * is permanent then the next sync reclaim will relcaim the inode and + * pass on the error. + */ + if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "inode 0x%llx background reclaim flush failed with %d", + (long long)ip->i_ino, error); + } +out: + xfs_iflags_clear(ip, XFS_IRECLAIM); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + /* + * We could return EAGAIN here to make reclaim rescan the inode tree in + * a short while. However, this just burns CPU time scanning the tree + * waiting for IO to complete and xfssyncd never goes back to the idle + * state. Instead, return 0 to let the next scheduled background reclaim + * attempt to reclaim the inode again. + */ + return 0; + reclaim: xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_ireclaim(ip); - return 0; + return error; + } int diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 8d0666dd170a..fa31360046d4 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2835,8 +2835,6 @@ xfs_iflush( xfs_dinode_t *dip; xfs_mount_t *mp; int error; - int noblock = (flags == XFS_IFLUSH_ASYNC_NOBLOCK); - enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) }; XFS_STATS_INC(xs_iflush_count); @@ -2859,7 +2857,7 @@ xfs_iflush( * in the same cluster are dirty, they will probably write the inode * out for us if they occur after the log force completes. */ - if (noblock && xfs_ipincount(ip)) { + if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) { xfs_iunpin_nowait(ip); xfs_ifunlock(ip); return EAGAIN; @@ -2892,61 +2890,11 @@ xfs_iflush( return XFS_ERROR(EIO); } - /* - * Decide how buffer will be flushed out. This is done before - * the call to xfs_iflush_int because this field is zeroed by it. - */ - if (iip != NULL && iip->ili_format.ilf_fields != 0) { - /* - * Flush out the inode buffer according to the directions - * of the caller. In the cases where the caller has given - * us a choice choose the non-delwri case. This is because - * the inode is in the AIL and we need to get it out soon. - */ - switch (flags) { - case XFS_IFLUSH_SYNC: - case XFS_IFLUSH_DELWRI_ELSE_SYNC: - flags = 0; - break; - case XFS_IFLUSH_ASYNC_NOBLOCK: - case XFS_IFLUSH_ASYNC: - case XFS_IFLUSH_DELWRI_ELSE_ASYNC: - flags = INT_ASYNC; - break; - case XFS_IFLUSH_DELWRI: - flags = INT_DELWRI; - break; - default: - ASSERT(0); - flags = 0; - break; - } - } else { - switch (flags) { - case XFS_IFLUSH_DELWRI_ELSE_SYNC: - case XFS_IFLUSH_DELWRI_ELSE_ASYNC: - case XFS_IFLUSH_DELWRI: - flags = INT_DELWRI; - break; - case XFS_IFLUSH_ASYNC_NOBLOCK: - case XFS_IFLUSH_ASYNC: - flags = INT_ASYNC; - break; - case XFS_IFLUSH_SYNC: - flags = 0; - break; - default: - ASSERT(0); - flags = 0; - break; - } - } - /* * Get the buffer containing the on-disk inode. */ error = xfs_itobp(mp, NULL, ip, &dip, &bp, - noblock ? XBF_TRYLOCK : XBF_LOCK); + (flags & SYNC_WAIT) ? XBF_LOCK : XBF_TRYLOCK); if (error || !bp) { xfs_ifunlock(ip); return error; @@ -2974,13 +2922,10 @@ xfs_iflush( if (error) goto cluster_corrupt_out; - if (flags & INT_DELWRI) { - xfs_bdwrite(mp, bp); - } else if (flags & INT_ASYNC) { - error = xfs_bawrite(mp, bp); - } else { + if (flags & SYNC_WAIT) error = xfs_bwrite(mp, bp); - } + else + xfs_bdwrite(mp, bp); return error; corrupt_out: @@ -3015,16 +2960,6 @@ xfs_iflush_int( iip = ip->i_itemp; mp = ip->i_mount; - - /* - * If the inode isn't dirty, then just release the inode - * flush lock and do nothing. - */ - if (xfs_inode_clean(ip)) { - xfs_ifunlock(ip); - return 0; - } - /* set *dip = inode's place in the buffer */ dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 8b618ea4d692..6c912b027596 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -419,16 +419,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip) #define XFS_IOLOCK_DEP(flags) (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT) #define XFS_ILOCK_DEP(flags) (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT) -/* - * Flags for xfs_iflush() - */ -#define XFS_IFLUSH_DELWRI_ELSE_SYNC 1 -#define XFS_IFLUSH_DELWRI_ELSE_ASYNC 2 -#define XFS_IFLUSH_SYNC 3 -#define XFS_IFLUSH_ASYNC 4 -#define XFS_IFLUSH_DELWRI 5 -#define XFS_IFLUSH_ASYNC_NOBLOCK 6 - /* * Flags for xfs_itruncate_start(). */ diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 48ec1c0b23ce..207553e82954 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -866,10 +866,14 @@ xfs_inode_item_push( iip->ili_format.ilf_fields != 0); /* - * Write out the inode. The completion routine ('iflush_done') will - * pull it from the AIL, mark it clean, unlock the flush lock. + * Push the inode to it's backing buffer. This will not remove the + * inode from the AIL - a further push will be required to trigger a + * buffer push. However, this allows all the dirty inodes to be pushed + * to the buffer before it is pushed to disk. THe buffer IO completion + * will pull th einode from the AIL, mark it clean and unlock the flush + * lock. */ - (void) xfs_iflush(ip, XFS_IFLUSH_ASYNC); + (void) xfs_iflush(ip, 0); xfs_iunlock(ip, XFS_ILOCK_SHARED); return; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 5061149b2cc4..6afaaeb2950a 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1468,7 +1468,18 @@ xfs_unmountfs( * need to force the log first. */ xfs_log_force(mp, XFS_LOG_SYNC); - xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC); + + /* + * Do a delwri reclaim pass first so that as many dirty inodes are + * queued up for IO as possible. Then flush the buffers before making + * a synchronous path to catch all the remaining inodes are reclaimed. + * This makes the reclaim process as quick as possible by avoiding + * synchronous writeout and blocking on inodes already in the delwri + * state as much as possible. + */ + xfs_reclaim_inodes(mp, 0); + XFS_bflush(mp->m_ddev_targp); + xfs_reclaim_inodes(mp, SYNC_WAIT); xfs_qm_unmount(mp); -- GitLab From d808f617ad00a413585b806de340feda5ad9a2da Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 2 Feb 2010 10:13:42 +1100 Subject: [PATCH 1192/3892] xfs: Don't issue buffer IO direct from AIL push V2 All buffers logged into the AIL are marked as delayed write. When the AIL needs to push the buffer out, it issues an async write of the buffer. This means that IO patterns are dependent on the order of buffers in the AIL. Instead of flushing the buffer, promote the buffer in the delayed write list so that the next time the xfsbufd is run the buffer will be flushed by the xfsbufd. Return the state to the xfsaild that the buffer was promoted so that the xfsaild knows that it needs to cause the xfsbufd to run to flush the buffers that were promoted. Using the xfsbufd for issuing the IO allows us to dispatch all buffer IO from the one queue. This means that we can make much more enlightened decisions on what order to flush buffers to disk as we don't have multiple places issuing IO. Optimisations to xfsbufd will be in a future patch. Version 2 - kill XFS_ITEM_FLUSHING as it is now unused. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_buf.c | 29 +++++++++++ fs/xfs/linux-2.6/xfs_buf.h | 2 + fs/xfs/linux-2.6/xfs_trace.h | 1 + fs/xfs/quota/xfs_dquot_item.c | 85 +++++------------------------- fs/xfs/quota/xfs_dquot_item.h | 4 -- fs/xfs/xfs_buf_item.c | 64 ++++++++++++----------- fs/xfs/xfs_inode_item.c | 98 ++++++----------------------------- fs/xfs/xfs_inode_item.h | 6 --- fs/xfs/xfs_trans.h | 3 +- fs/xfs/xfs_trans_ail.c | 13 ++--- 10 files changed, 102 insertions(+), 203 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 44e20e578ba0..b306265caa33 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1778,6 +1778,35 @@ xfs_buf_delwri_dequeue( trace_xfs_buf_delwri_dequeue(bp, _RET_IP_); } +/* + * If a delwri buffer needs to be pushed before it has aged out, then promote + * it to the head of the delwri queue so that it will be flushed on the next + * xfsbufd run. We do this by resetting the queuetime of the buffer to be older + * than the age currently needed to flush the buffer. Hence the next time the + * xfsbufd sees it is guaranteed to be considered old enough to flush. + */ +void +xfs_buf_delwri_promote( + struct xfs_buf *bp) +{ + struct xfs_buftarg *btp = bp->b_target; + long age = xfs_buf_age_centisecs * msecs_to_jiffies(10) + 1; + + ASSERT(bp->b_flags & XBF_DELWRI); + ASSERT(bp->b_flags & _XBF_DELWRI_Q); + + /* + * Check the buffer age before locking the delayed write queue as we + * don't need to promote buffers that are already past the flush age. + */ + if (bp->b_queuetime < jiffies - age) + return; + bp->b_queuetime = jiffies - age; + spin_lock(&btp->bt_delwrite_lock); + list_move(&bp->b_list, &btp->bt_delwrite_queue); + spin_unlock(&btp->bt_delwrite_lock); +} + STATIC void xfs_buf_runall_queues( struct workqueue_struct *queue) diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index ea8c198f0c39..be45e8c5768d 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -266,6 +266,7 @@ extern int xfs_buf_ispin(xfs_buf_t *); /* Delayed Write Buffer Routines */ extern void xfs_buf_delwri_dequeue(xfs_buf_t *); +extern void xfs_buf_delwri_promote(xfs_buf_t *); /* Buffer Daemon Setup Routines */ extern int xfs_buf_init(void); @@ -395,6 +396,7 @@ extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *); extern void xfs_wait_buftarg(xfs_buftarg_t *); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int); + #ifdef CONFIG_KDB_MODULES extern struct list_head *xfs_get_buftarg_list(void); #endif diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index 1bb09e70b2eb..a4574dcf5065 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h @@ -483,6 +483,7 @@ DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock); DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale); DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed); DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push); +DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pushbuf); DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf); DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur); DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb); diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 1b564376d50c..dda0fb045c8a 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -212,18 +212,10 @@ xfs_qm_dquot_logitem_pushbuf( xfs_dquot_t *dqp; xfs_mount_t *mp; xfs_buf_t *bp; - uint dopush; dqp = qip->qli_dquot; ASSERT(XFS_DQ_IS_LOCKED(dqp)); - /* - * The qli_pushbuf_flag keeps others from - * trying to duplicate our effort. - */ - ASSERT(qip->qli_pushbuf_flag != 0); - ASSERT(qip->qli_push_owner == current_pid()); - /* * If flushlock isn't locked anymore, chances are that the * inode flush completed and the inode was taken off the AIL. @@ -231,47 +223,20 @@ xfs_qm_dquot_logitem_pushbuf( */ if (completion_done(&dqp->q_flush) || ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { - qip->qli_pushbuf_flag = 0; xfs_dqunlock(dqp); return; } mp = dqp->q_mount; bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, XFS_QI_DQCHUNKLEN(mp), XBF_TRYLOCK); - if (bp != NULL) { - if (XFS_BUF_ISDELAYWRITE(bp)) { - dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && - !completion_done(&dqp->q_flush)); - qip->qli_pushbuf_flag = 0; - xfs_dqunlock(dqp); - - if (XFS_BUF_ISPINNED(bp)) - xfs_log_force(mp, 0); - - if (dopush) { - int error; -#ifdef XFSRACEDEBUG - delay_for_intr(); - delay(300); -#endif - error = xfs_bawrite(mp, bp); - if (error) - xfs_fs_cmn_err(CE_WARN, mp, - "xfs_qm_dquot_logitem_pushbuf: pushbuf error %d on qip %p, bp %p", - error, qip, bp); - } else { - xfs_buf_relse(bp); - } - } else { - qip->qli_pushbuf_flag = 0; - xfs_dqunlock(dqp); - xfs_buf_relse(bp); - } + xfs_dqunlock(dqp); + if (!bp) return; - } + if (XFS_BUF_ISDELAYWRITE(bp)) + xfs_buf_delwri_promote(bp); + xfs_buf_relse(bp); + return; - qip->qli_pushbuf_flag = 0; - xfs_dqunlock(dqp); } /* @@ -289,50 +254,24 @@ xfs_qm_dquot_logitem_trylock( xfs_dq_logitem_t *qip) { xfs_dquot_t *dqp; - uint retval; dqp = qip->qli_dquot; if (atomic_read(&dqp->q_pincount) > 0) - return (XFS_ITEM_PINNED); + return XFS_ITEM_PINNED; if (! xfs_qm_dqlock_nowait(dqp)) - return (XFS_ITEM_LOCKED); + return XFS_ITEM_LOCKED; - retval = XFS_ITEM_SUCCESS; if (!xfs_dqflock_nowait(dqp)) { /* - * The dquot is already being flushed. It may have been - * flushed delayed write, however, and we don't want to - * get stuck waiting for that to complete. So, we want to check - * to see if we can lock the dquot's buffer without sleeping. - * If we can and it is marked for delayed write, then we - * hold it and send it out from the push routine. We don't - * want to do that now since we might sleep in the device - * strategy routine. We also don't want to grab the buffer lock - * here because we'd like not to call into the buffer cache - * while holding the AIL lock. - * Make sure to only return PUSHBUF if we set pushbuf_flag - * ourselves. If someone else is doing it then we don't - * want to go to the push routine and duplicate their efforts. + * dquot has already been flushed to the backing buffer, + * leave it locked, pushbuf routine will unlock it. */ - if (qip->qli_pushbuf_flag == 0) { - qip->qli_pushbuf_flag = 1; - ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno); -#ifdef DEBUG - qip->qli_push_owner = current_pid(); -#endif - /* - * The dquot is left locked. - */ - retval = XFS_ITEM_PUSHBUF; - } else { - retval = XFS_ITEM_FLUSHING; - xfs_dqunlock_nonotify(dqp); - } + return XFS_ITEM_PUSHBUF; } ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); - return (retval); + return XFS_ITEM_SUCCESS; } diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/quota/xfs_dquot_item.h index 5a632531f843..5acae2ada70b 100644 --- a/fs/xfs/quota/xfs_dquot_item.h +++ b/fs/xfs/quota/xfs_dquot_item.h @@ -27,10 +27,6 @@ typedef struct xfs_dq_logitem { xfs_log_item_t qli_item; /* common portion */ struct xfs_dquot *qli_dquot; /* dquot ptr */ xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ - unsigned short qli_pushbuf_flag; /* 1 bit used in push_ail */ -#ifdef DEBUG - uint64_t qli_push_owner; -#endif xfs_dq_logformat_t qli_format; /* logged structure */ } xfs_dq_logitem_t; diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index e0a11583ce5a..f3c49e69eab9 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -467,8 +467,10 @@ xfs_buf_item_unpin_remove( /* * This is called to attempt to lock the buffer associated with this * buf log item. Don't sleep on the buffer lock. If we can't get - * the lock right away, return 0. If we can get the lock, pull the - * buffer from the free list, mark it busy, and return 1. + * the lock right away, return 0. If we can get the lock, take a + * reference to the buffer. If this is a delayed write buffer that + * needs AIL help to be written back, invoke the pushbuf routine + * rather than the normal success path. */ STATIC uint xfs_buf_item_trylock( @@ -477,24 +479,18 @@ xfs_buf_item_trylock( xfs_buf_t *bp; bp = bip->bli_buf; - - if (XFS_BUF_ISPINNED(bp)) { + if (XFS_BUF_ISPINNED(bp)) return XFS_ITEM_PINNED; - } - - if (!XFS_BUF_CPSEMA(bp)) { + if (!XFS_BUF_CPSEMA(bp)) return XFS_ITEM_LOCKED; - } - /* - * Remove the buffer from the free list. Only do this - * if it's on the free list. Private buffers like the - * superblock buffer are not. - */ + /* take a reference to the buffer. */ XFS_BUF_HOLD(bp); ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); trace_xfs_buf_item_trylock(bip); + if (XFS_BUF_ISDELAYWRITE(bp)) + return XFS_ITEM_PUSHBUF; return XFS_ITEM_SUCCESS; } @@ -626,11 +622,9 @@ xfs_buf_item_committed( } /* - * This is called to asynchronously write the buffer associated with this - * buf log item out to disk. The buffer will already have been locked by - * a successful call to xfs_buf_item_trylock(). If the buffer still has - * B_DELWRI set, then get it going out to disk with a call to bawrite(). - * If not, then just release the buffer. + * The buffer is locked, but is not a delayed write buffer. This happens + * if we race with IO completion and hence we don't want to try to write it + * again. Just release the buffer. */ STATIC void xfs_buf_item_push( @@ -642,17 +636,29 @@ xfs_buf_item_push( trace_xfs_buf_item_push(bip); bp = bip->bli_buf; + ASSERT(!XFS_BUF_ISDELAYWRITE(bp)); + xfs_buf_relse(bp); +} - if (XFS_BUF_ISDELAYWRITE(bp)) { - int error; - error = xfs_bawrite(bip->bli_item.li_mountp, bp); - if (error) - xfs_fs_cmn_err(CE_WARN, bip->bli_item.li_mountp, - "xfs_buf_item_push: pushbuf error %d on bip %p, bp %p", - error, bip, bp); - } else { - xfs_buf_relse(bp); - } +/* + * The buffer is locked and is a delayed write buffer. Promote the buffer + * in the delayed write queue as the caller knows that they must invoke + * the xfsbufd to get this buffer written. We have to unlock the buffer + * to allow the xfsbufd to write it, too. + */ +STATIC void +xfs_buf_item_pushbuf( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + trace_xfs_buf_item_pushbuf(bip); + + bp = bip->bli_buf; + ASSERT(XFS_BUF_ISDELAYWRITE(bp)); + xfs_buf_delwri_promote(bp); + xfs_buf_relse(bp); } /* ARGSUSED */ @@ -677,7 +683,7 @@ static struct xfs_item_ops xfs_buf_item_ops = { .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_buf_item_committed, .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push, - .iop_pushbuf = NULL, + .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_buf_item_pushbuf, .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_buf_item_committing }; diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 207553e82954..d4dc063111f8 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -602,33 +602,20 @@ xfs_inode_item_trylock( if (!xfs_iflock_nowait(ip)) { /* - * If someone else isn't already trying to push the inode - * buffer, we get to do it. + * inode has already been flushed to the backing buffer, + * leave it locked in shared mode, pushbuf routine will + * unlock it. */ - if (iip->ili_pushbuf_flag == 0) { - iip->ili_pushbuf_flag = 1; -#ifdef DEBUG - iip->ili_push_owner = current_pid(); -#endif - /* - * Inode is left locked in shared mode. - * Pushbuf routine gets to unlock it. - */ - return XFS_ITEM_PUSHBUF; - } else { - /* - * We hold the AIL lock, so we must specify the - * NONOTIFY flag so that we won't double trip. - */ - xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); - return XFS_ITEM_FLUSHING; - } - /* NOTREACHED */ + return XFS_ITEM_PUSHBUF; } /* Stale items should force out the iclog */ if (ip->i_flags & XFS_ISTALE) { xfs_ifunlock(ip); + /* + * we hold the AIL lock - notify the unlock routine of this + * so it doesn't try to get the lock again. + */ xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); return XFS_ITEM_PINNED; } @@ -746,11 +733,8 @@ xfs_inode_item_committed( * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK * failed to get the inode flush lock but did get the inode locked SHARED. * Here we're trying to see if the inode buffer is incore, and if so whether it's - * marked delayed write. If that's the case, we'll initiate a bawrite on that - * buffer to expedite the process. - * - * We aren't holding the AIL lock (or the flush lock) when this gets called, - * so it is inherently race-y. + * marked delayed write. If that's the case, we'll promote it and that will + * allow the caller to write the buffer by triggering the xfsbufd to run. */ STATIC void xfs_inode_item_pushbuf( @@ -759,26 +743,16 @@ xfs_inode_item_pushbuf( xfs_inode_t *ip; xfs_mount_t *mp; xfs_buf_t *bp; - uint dopush; ip = iip->ili_inode; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); - /* - * The ili_pushbuf_flag keeps others from - * trying to duplicate our effort. - */ - ASSERT(iip->ili_pushbuf_flag != 0); - ASSERT(iip->ili_push_owner == current_pid()); - /* * If a flush is not in progress anymore, chances are that the * inode was taken off the AIL. So, just get out. */ if (completion_done(&ip->i_flush) || ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { - iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); return; } @@ -787,53 +761,12 @@ xfs_inode_item_pushbuf( bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno, iip->ili_format.ilf_len, XBF_TRYLOCK); - if (bp != NULL) { - if (XFS_BUF_ISDELAYWRITE(bp)) { - /* - * We were racing with iflush because we don't hold - * the AIL lock or the flush lock. However, at this point, - * we have the buffer, and we know that it's dirty. - * So, it's possible that iflush raced with us, and - * this item is already taken off the AIL. - * If not, we can flush it async. - */ - dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && - !completion_done(&ip->i_flush)); - iip->ili_pushbuf_flag = 0; - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - trace_xfs_inode_item_push(bp, _RET_IP_); - - if (XFS_BUF_ISPINNED(bp)) - xfs_log_force(mp, 0); - - if (dopush) { - int error; - error = xfs_bawrite(mp, bp); - if (error) - xfs_fs_cmn_err(CE_WARN, mp, - "xfs_inode_item_pushbuf: pushbuf error %d on iip %p, bp %p", - error, iip, bp); - } else { - xfs_buf_relse(bp); - } - } else { - iip->ili_pushbuf_flag = 0; - xfs_iunlock(ip, XFS_ILOCK_SHARED); - xfs_buf_relse(bp); - } - return; - } - /* - * We have to be careful about resetting pushbuf flag too early (above). - * Even though in theory we can do it as soon as we have the buflock, - * we don't want others to be doing work needlessly. They'll come to - * this function thinking that pushing the buffer is their - * responsibility only to find that the buffer is still locked by - * another doing the same thing - */ - iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); + if (!bp) + return; + if (XFS_BUF_ISDELAYWRITE(bp)) + xfs_buf_delwri_promote(bp); + xfs_buf_relse(bp); return; } @@ -937,7 +870,6 @@ xfs_inode_item_init( /* We have zeroed memory. No need ... iip->ili_extents_buf = NULL; - iip->ili_pushbuf_flag = 0; */ iip->ili_format.ilf_type = XFS_LI_INODE; diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h index cc8df1ac7783..9a467958ecdd 100644 --- a/fs/xfs/xfs_inode_item.h +++ b/fs/xfs/xfs_inode_item.h @@ -144,12 +144,6 @@ typedef struct xfs_inode_log_item { data exts */ struct xfs_bmbt_rec *ili_aextents_buf; /* array of logged attr exts */ - unsigned int ili_pushbuf_flag; /* one bit used in push_ail */ - -#ifdef DEBUG - uint64_t ili_push_owner; /* one who sets pushbuf_flag - above gets to push the buf */ -#endif #ifdef XFS_TRANS_DEBUG int ili_root_size; char *ili_orig_root; diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index ca64f33c63a3..c93e3a102857 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -861,8 +861,7 @@ typedef struct xfs_item_ops { #define XFS_ITEM_SUCCESS 0 #define XFS_ITEM_PINNED 1 #define XFS_ITEM_LOCKED 2 -#define XFS_ITEM_FLUSHING 3 -#define XFS_ITEM_PUSHBUF 4 +#define XFS_ITEM_PUSHBUF 3 /* * This structure is used to maintain a list of block ranges that have been diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index d7b1af8a832d..e799824f7245 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -253,6 +253,7 @@ xfsaild_push( int flush_log, count, stuck; xfs_mount_t *mp = ailp->xa_mount; struct xfs_ail_cursor *cur = &ailp->xa_cursors; + int push_xfsbufd = 0; spin_lock(&ailp->xa_lock); xfs_trans_ail_cursor_init(ailp, cur); @@ -308,6 +309,7 @@ xfsaild_push( XFS_STATS_INC(xs_push_ail_pushbuf); IOP_PUSHBUF(lip); last_pushed_lsn = lsn; + push_xfsbufd = 1; break; case XFS_ITEM_PINNED: @@ -322,12 +324,6 @@ xfsaild_push( stuck++; break; - case XFS_ITEM_FLUSHING: - XFS_STATS_INC(xs_push_ail_flushing); - last_pushed_lsn = lsn; - stuck++; - break; - default: ASSERT(0); break; @@ -374,6 +370,11 @@ xfsaild_push( xfs_log_force(mp, 0); } + if (push_xfsbufd) { + /* we've got delayed write buffers to flush */ + wake_up_process(mp->m_ddev_targp->bt_task); + } + if (!count) { /* We're past our target or empty, so idle */ last_pushed_lsn = 0; -- GitLab From 089716aa1480b7197bcd678b8477774c379a2768 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 26 Jan 2010 15:13:25 +1100 Subject: [PATCH 1193/3892] xfs: Sort delayed write buffers before dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when the xfsbufd writes delayed write buffers, it pushes them to disk in the order they come off the delayed write list. If there are lots of buffers Ñ•pread widely over the disk, this results in overwhelming the elevator sort queues in the block layer and we end up losing the posibility of merging adjacent buffers to minimise the number of IOs. Use the new generic list_sort function to sort the delwri dispatch queue before issue to ensure that the buffers are pushed in the most friendly order possible to the lower layers. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_buf.c | 87 ++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index b306265caa33..4556a4c31e36 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "xfs_sb.h" #include "xfs_inum.h" @@ -1877,14 +1878,42 @@ xfs_buf_delwri_split( } +/* + * Compare function is more complex than it needs to be because + * the return value is only 32 bits and we are doing comparisons + * on 64 bit values + */ +static int +xfs_buf_cmp( + void *priv, + struct list_head *a, + struct list_head *b) +{ + struct xfs_buf *ap = container_of(a, struct xfs_buf, b_list); + struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list); + xfs_daddr_t diff; + + diff = ap->b_bn - bp->b_bn; + if (diff < 0) + return -1; + if (diff > 0) + return 1; + return 0; +} + +void +xfs_buf_delwri_sort( + xfs_buftarg_t *target, + struct list_head *list) +{ + list_sort(NULL, list, xfs_buf_cmp); +} + STATIC int xfsbufd( void *data) { - struct list_head tmp; - xfs_buftarg_t *target = (xfs_buftarg_t *)data; - int count; - xfs_buf_t *bp; + xfs_buftarg_t *target = (xfs_buftarg_t *)data; current->flags |= PF_MEMALLOC; @@ -1893,6 +1922,8 @@ xfsbufd( do { long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10); + int count = 0; + struct list_head tmp; if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); @@ -1907,11 +1938,10 @@ xfsbufd( schedule_timeout_interruptible(tout); xfs_buf_delwri_split(target, &tmp, age); - count = 0; + list_sort(NULL, &tmp, xfs_buf_cmp); while (!list_empty(&tmp)) { - bp = list_entry(tmp.next, xfs_buf_t, b_list); - ASSERT(target == bp->b_target); - + struct xfs_buf *bp; + bp = list_first_entry(&tmp, struct xfs_buf, b_list); list_del_init(&bp->b_list); xfs_buf_iostrategy(bp); count++; @@ -1937,42 +1967,45 @@ xfs_flush_buftarg( xfs_buftarg_t *target, int wait) { - struct list_head tmp; - xfs_buf_t *bp, *n; + xfs_buf_t *bp; int pincount = 0; + LIST_HEAD(tmp_list); + LIST_HEAD(wait_list); xfs_buf_runall_queues(xfsconvertd_workqueue); xfs_buf_runall_queues(xfsdatad_workqueue); xfs_buf_runall_queues(xfslogd_workqueue); set_bit(XBT_FORCE_FLUSH, &target->bt_flags); - pincount = xfs_buf_delwri_split(target, &tmp, 0); + pincount = xfs_buf_delwri_split(target, &tmp_list, 0); /* - * Dropped the delayed write list lock, now walk the temporary list + * Dropped the delayed write list lock, now walk the temporary list. + * All I/O is issued async and then if we need to wait for completion + * we do that after issuing all the IO. */ - list_for_each_entry_safe(bp, n, &tmp, b_list) { + list_sort(NULL, &tmp_list, xfs_buf_cmp); + while (!list_empty(&tmp_list)) { + bp = list_first_entry(&tmp_list, struct xfs_buf, b_list); ASSERT(target == bp->b_target); - if (wait) + list_del_init(&bp->b_list); + if (wait) { bp->b_flags &= ~XBF_ASYNC; - else - list_del_init(&bp->b_list); - + list_add(&bp->b_list, &wait_list); + } xfs_buf_iostrategy(bp); } - if (wait) + if (wait) { + /* Expedite and wait for IO to complete. */ blk_run_address_space(target->bt_mapping); + while (!list_empty(&wait_list)) { + bp = list_first_entry(&wait_list, struct xfs_buf, b_list); - /* - * Remaining list items must be flushed before returning - */ - while (!list_empty(&tmp)) { - bp = list_entry(tmp.next, xfs_buf_t, b_list); - - list_del_init(&bp->b_list); - xfs_iowait(bp); - xfs_buf_relse(bp); + list_del_init(&bp->b_list); + xfs_iowait(bp); + xfs_buf_relse(bp); + } } return pincount; -- GitLab From 7d6a7bde52e449f21a0e86a7a4955b4e08a49d69 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 26 Jan 2010 15:13:41 +1100 Subject: [PATCH 1194/3892] xfs: Use delay write promotion for dquot flushing xfs_qm_dqflock_pushbuf_wait() does a very similar trick to item pushing used to do to flush out delayed write dquot buffers. Change it to use the new promotion method rather than an async flush. Also, xfs_qm_dqflock_pushbuf_wait() can return without the flush lock held, yet the callers make the assumption that after this call the flush lock is held. Always return with the flush lock held. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/quota/xfs_dquot.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index f9baeedbfdfe..1620a56b067e 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1528,21 +1528,16 @@ xfs_qm_dqflock_pushbuf_wait( */ bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno, XFS_QI_DQCHUNKLEN(dqp->q_mount), XBF_TRYLOCK); - if (bp != NULL) { - if (XFS_BUF_ISDELAYWRITE(bp)) { - int error; - - if (XFS_BUF_ISPINNED(bp)) - xfs_log_force(dqp->q_mount, 0); - error = xfs_bawrite(dqp->q_mount, bp); - if (error) - xfs_fs_cmn_err(CE_WARN, dqp->q_mount, - "xfs_qm_dqflock_pushbuf_wait: " - "pushbuf error %d on dqp %p, bp %p", - error, dqp, bp); - } else { - xfs_buf_relse(bp); - } + if (!bp) + goto out_lock; + + if (XFS_BUF_ISDELAYWRITE(bp)) { + if (XFS_BUF_ISPINNED(bp)) + xfs_log_force(dqp->q_mount, 0); + xfs_buf_delwri_promote(bp); + wake_up_process(bp->b_target->bt_task); } + xfs_buf_relse(bp); +out_lock: xfs_dqflock(dqp); } -- GitLab From cf944ee55cc318bdb1d4b2f3f5cce3257f7c07b3 Mon Sep 17 00:00:00 2001 From: Florian Zumbiehl Date: Tue, 26 Jan 2010 09:06:14 +0100 Subject: [PATCH 1195/3892] ALSA: cs46xx: Fix cpu idling with resume Make sure that capture DMA doesn't stay enabled after system resume as that potentially prevents the processor from entering deep sleep states. Signed-off-by: Florian Zumbiehl Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index e6b4a879ae2e..56fcf00c0e27 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) #ifdef CONFIG_SND_CS46XX_NEW_DSP int i; #endif + unsigned int tmp; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); + /* + * Stop capture DMA. + */ + tmp = snd_cs46xx_peek(chip, BA1_CCTL); + chip->capt.ctl = tmp & 0x0000ffff; + snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000); + + mdelay(5); + /* reset playback/capture */ snd_cs46xx_set_play_sample_rate(chip, 8000); snd_cs46xx_set_capture_sample_rate(chip, 8000); -- GitLab From ccc5df058da70d1c26c72cd1c24072a89998d735 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Tue, 26 Jan 2010 15:59:33 +0800 Subject: [PATCH 1196/3892] ALSA: hda - Add support for more the 8 streams In azx_stream_start() and azx_stream_stop(), it use azx_readb/azx_writeb to read/write SIE, it just enable/disable 8 streams. But according to the HDA spec, it support 30 streams, and the new HDA controller will support more then 8 streams. So we should use azx_readl/azx_writel to read/write SIE. Signed-off-by: Wei Ni Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6d331c4cf185..6eeefda63838 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -954,8 +954,8 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) azx_dev->insufficient = 1; /* enable SIE */ - azx_writeb(chip, INTCTL, - azx_readb(chip, INTCTL) | (1 << azx_dev->index)); + azx_writel(chip, INTCTL, + azx_readl(chip, INTCTL) | (1 << azx_dev->index)); /* set DMA start and interrupt mask */ azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_DMA_START | SD_INT_MASK); @@ -974,8 +974,8 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) { azx_stream_clear(chip, azx_dev); /* disable SIE */ - azx_writeb(chip, INTCTL, - azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); + azx_writel(chip, INTCTL, + azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); } -- GitLab From e473b847424bd215b686cbc1e781e82c904ee967 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Wed, 20 Jan 2010 17:06:33 +0530 Subject: [PATCH 1197/3892] ASoC: DaVinci: Fix stream restart error Sometimes after a suspend-resume cycle, the ALSA application restarts the stream when resume fails and McASP fails to work as the clock is not enabled. This patch corrects this bug. Testes on TI DA850/OMAP-L138 EVM. Signed-off-by: Chaithrika U S Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a613bbb0bc91..ab6518d86f18 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -768,13 +768,12 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (!dev->clk_active) { clk_enable(dev->clk); dev->clk_active = 1; } - /* Fall through */ - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_mcasp_start(dev, substream->stream); break; -- GitLab From b747caf365b4121903b26d1cd65454c7bc607184 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Jan 2010 05:17:00 -0800 Subject: [PATCH 1198/3892] ariadne: Fix build. References removed HAVE_MULTICAST. Reporeted-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ariadne.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index c35af3e106b1..e2c202493fa7 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -123,9 +123,7 @@ static void ariadne_reset(struct net_device *dev); static irqreturn_t ariadne_interrupt(int irq, void *data); static int ariadne_close(struct net_device *dev); static struct net_device_stats *ariadne_get_stats(struct net_device *dev); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct net_device *dev); -#endif static void memcpyw(volatile u_short *dest, u_short *src, int len) -- GitLab From e7636925789b042ff9d98c51d48392e8c5549480 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 26 Jan 2010 17:08:24 +0100 Subject: [PATCH 1199/3892] ALSA: pcm_lib - return back hw_ptr_interrupt Clemens Ladisch noted for hw_ptr_removal in "cleanup & merge hw_ptr update functions" commit: "It is possible for the status/delay ioctls to be called when the sound card's pointer register alreay shows a position at the beginning of the new period, but immediately before the interrupt is actually executed. (This happens regularly on a SMP machine with mplayer.) When that happens, the code thinks that the position must be at least one period ahead of the current position and drops an entire buffer of data." Return back the hw_ptr_interrupt variable. The last interrupt pointer is always computed from the latest hw_ptr instead of tracking it separately (in this case all hw_ptr checks and modifications might influence also hw_ptr_interrupt and it is difficult to keep it consistent). Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 1 + sound/core/oss/pcm_oss.c | 3 +-- sound/core/pcm_lib.c | 7 +++++-- sound/core/pcm_native.c | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3bc9bca771ec..13bc83ca35fb 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -271,6 +271,7 @@ struct snd_pcm_runtime { int overrange; snd_pcm_uframes_t avail_max; snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ + snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 255ad910077a..82d4e3329b3d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -635,8 +635,7 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) static inline snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime) { - snd_pcm_uframes_t ptr = runtime->status->hw_ptr; - return ptr - (ptr % runtime->period_size); + return runtime->hw_ptr_interrupt; } /* define extended formats in the recent OSS versions (if any) */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e2a817eac2a9..aa54195ef3b0 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -325,8 +325,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (in_interrupt) { /* we know that one period was processed */ /* delta = "expected next hw_ptr" for in_interrupt != 0 */ - delta = old_hw_ptr - (old_hw_ptr % runtime->period_size) - + runtime->period_size; + delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) @@ -437,6 +436,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (in_interrupt) { + runtime->hw_ptr_interrupt = new_hw_ptr - + (new_hw_ptr % runtime->period_size); + } runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 56ec35e8510b..7a002db512b4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1252,6 +1252,8 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) if (err < 0) return err; runtime->hw_ptr_base = 0; + runtime->hw_ptr_interrupt = runtime->status->hw_ptr - + runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; return 0; -- GitLab From c21dbf9214bce129f92e1af05552553ff0e318ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 26 Jan 2010 14:15:46 +0100 Subject: [PATCH 1200/3892] cfg80211: export cfg80211_find_ie This new function (previously a static function called just "find_ie" can be used to find a specific IE in a buffer of IEs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 16 ++++++++++++++++ net/wireless/scan.c | 38 ++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c5d16f299d6f..a3f0a7ed31ac 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1658,6 +1658,22 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, */ unsigned int cfg80211_classify8021d(struct sk_buff *skb); +/** + * cfg80211_find_ie - find information element in data + * + * @eid: element ID + * @ies: data consisting of IEs + * @len: length of data + * + * This function will return %NULL if the element ID could + * not be found or if the element is invalid (claims to be + * longer than the given data), or a pointer to the first byte + * of the requested element, that is the byte containing the + * element ID. There are no checks on the element length + * other than having to fit into the given data. + */ +const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); + /* * Regulatory helper functions for wiphys */ diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 06b0231ee5e3..978cac3414b5 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -143,9 +143,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) dev->bss_generation++; } -static u8 *find_ie(u8 num, u8 *ies, int len) +const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) { - while (len > 2 && ies[0] != num) { + while (len > 2 && ies[0] != eid) { len -= ies[1] + 2; ies += ies[1] + 2; } @@ -155,11 +155,12 @@ static u8 *find_ie(u8 num, u8 *ies, int len) return NULL; return ies; } +EXPORT_SYMBOL(cfg80211_find_ie); static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) { - const u8 *ie1 = find_ie(num, ies1, len1); - const u8 *ie2 = find_ie(num, ies2, len2); + const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); + const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); int r; if (!ie1 && !ie2) @@ -185,9 +186,9 @@ static bool is_bss(struct cfg80211_bss *a, if (!ssid) return true; - ssidie = find_ie(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements); + ssidie = cfg80211_find_ie(WLAN_EID_SSID, + a->information_elements, + a->len_information_elements); if (!ssidie) return false; if (ssidie[1] != ssid_len) @@ -204,9 +205,9 @@ static bool is_mesh(struct cfg80211_bss *a, if (!is_zero_ether_addr(a->bssid)) return false; - ie = find_ie(WLAN_EID_MESH_ID, - a->information_elements, - a->len_information_elements); + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); if (!ie) return false; if (ie[1] != meshidlen) @@ -214,9 +215,9 @@ static bool is_mesh(struct cfg80211_bss *a, if (memcmp(ie + 2, meshid, meshidlen)) return false; - ie = find_ie(WLAN_EID_MESH_CONFIG, - a->information_elements, - a->len_information_elements); + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); if (!ie) return false; if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) @@ -395,11 +396,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, if (is_zero_ether_addr(res->pub.bssid)) { /* must be mesh, verify */ - meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements, - res->pub.len_information_elements); - meshcfg = find_ie(WLAN_EID_MESH_CONFIG, - res->pub.information_elements, - res->pub.len_information_elements); + meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, + res->pub.information_elements, + res->pub.len_information_elements); + meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + res->pub.information_elements, + res->pub.len_information_elements); if (!meshid || !meshcfg || meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { /* bogus mesh */ -- GitLab From 56007a028c51cbf800a6c969d6f6431d23443b99 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 26 Jan 2010 14:19:52 +0100 Subject: [PATCH 1201/3892] mac80211: wait for beacon before enabling powersave Because DTIM information is required for powersave but is only conveyed in beacons, wait for a beacon before enabling powersave, and change the way the information is conveyed to the driver accordingly. mwl8k doesn't currently seem to implement PS but requires the DTIM period in a different way; after talking to Lennert we agreed to just have mwl8k do the parsing itself in the finalize_join work. Signed-off-by: Johannes Berg Acked-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/mwl8k.c | 14 +++++++----- drivers/net/wireless/wl12xx/wl1251.h | 3 --- drivers/net/wireless/wl12xx/wl1251_main.c | 25 ++++++--------------- include/net/mac80211.h | 7 +++++- net/mac80211/mlme.c | 27 ++++++++++++++++++++--- net/mac80211/scan.c | 4 ---- 7 files changed, 47 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 8599444bef01..9e3ca0641451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -319,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; if (priv->vif) - dtimper = priv->vif->bss_conf.dtim_period; + dtimper = priv->hw->conf.ps_dtim_period; else dtimper = 1; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 68546ca0ba37..f0f08f3919cc 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - struct mwl8k_vif *mwl8k_vif; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable); + const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM, + mgmt->u.beacon.variable, len); + int dtim_period = 1; + + if (tim && tim[1] >= 2) + dtim_period = tim[3]; - mwl8k_vif = mwl8k_first_vif(priv); - if (mwl8k_vif != NULL) - mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, - mwl8k_vif->vif->bss_conf.dtim_period); + mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period); dev_kfree_skb(skb); priv->beacon_skb = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 6301578d1565..37c61c19cae5 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -341,9 +341,6 @@ struct wl1251 { /* Are we currently scanning */ bool scanning; - /* Our association ID */ - u16 aid; - /* Default key (for WEP) */ u32 default_key; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 595f0f94d16e..a717dde4822e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->psm_requested = true; + wl->dtim_period = conf->ps_dtim_period; + + ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, + wl->dtim_period); + /* - * We enter PSM only if we're already associated. - * If we're not, we'll enter it when joining an SSID, - * through the bss_info_changed() hook. + * mac80211 enables PSM only if we're already associated. */ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) @@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum wl1251_cmd_ps_mode mode; struct wl1251 *wl = hw->priv; struct sk_buff *beacon, *skb; int ret; @@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->beacon_int = bss_conf->beacon_int; - wl->dtim_period = bss_conf->dtim_period; - - ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, - wl->dtim_period); - wl->aid = bss_conf->aid; skb = ieee80211_pspoll_get(wl->hw, wl->vif); if (!skb) @@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - ret = wl1251_acx_aid(wl, wl->aid); + ret = wl1251_acx_aid(wl, bss_conf->aid); if (ret < 0) goto out_sleep; - - /* If we want to go in PSM but we're not there yet */ - if (wl->psm_requested && !wl->psm) { - mode = STATION_POWER_SAVE_MODE; - ret = wl1251_ps_set_mode(wl, mode); - if (ret < 0) - goto out_sleep; - } } else { /* use defaults when not associated */ wl->beacon_int = WL1251_DEFAULT_BEACON_INT; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f64402f6312b..1e9c93024cf2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -186,7 +186,8 @@ enum ieee80211_bss_change { * @use_short_slot: use short slot time (only relevant for ERP); * if the hardware cannot handle this it must set the * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag - * @dtim_period: num of beacons before the next DTIM, for PSM + * @dtim_period: num of beacons before the next DTIM, for beaconing, + * not valid in station mode (cf. hw conf ps_dtim_period) * @timestamp: beacon timestamp * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp @@ -648,6 +649,9 @@ enum ieee80211_smps_mode { * value will be only achievable between DTIM frames, the hardware * needs to check for the multicast traffic bit in DTIM beacons. * This variable is valid only when the CONF_PS flag is set. + * @ps_dtim_period: The DTIM period of the AP we're connected to, for use + * in power saving. Power saving will not be enabled until a beacon + * has been received and the DTIM period is known. * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the * powersave documentation below. This variable is valid only when * the CONF_PS flag is set. @@ -674,6 +678,7 @@ struct ieee80211_conf { int max_sleep_period; u16 listen_interval; + u8 ps_dtim_period; u8 long_frame_max_tx_count, short_frame_max_tx_count; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1e1d16c55ee5..86c6ad1b058d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) if (count == 1 && found->u.mgd.powersave && found->u.mgd.associated && + found->u.mgd.associated->beacon_ies && !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL))) { s32 beaconint_us; @@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) if (beaconint_us > latency) { local->ps_sdata = NULL; } else { - u8 dtimper = found->vif.bss_conf.dtim_period; + struct ieee80211_bss *bss; int maxslp = 1; + u8 dtimper; - if (dtimper > 1) + bss = (void *)found->u.mgd.associated->priv; + dtimper = bss->dtim_period; + + /* If the TIM IE is invalid, pretend the value is 1 */ + if (!dtimper) + dtimper = 1; + else if (dtimper > 1) maxslp = min_t(int, dtimper, latency / beaconint_us); local->hw.conf.max_sleep_period = maxslp; + local->hw.conf.ps_dtim_period = dtimper; local->ps_sdata = found; } } else { @@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, /* set timing information */ sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; sdata->vif.bss_conf.timestamp = cbss->tsf; - sdata->vif.bss_conf.dtim_period = bss->dtim_period; bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, @@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, int freq; struct ieee80211_bss *bss; struct ieee80211_channel *channel; + bool need_ps = false; + + if (sdata->u.mgd.associated) { + bss = (void *)sdata->u.mgd.associated->priv; + /* not previously set so we may need to recalc */ + need_ps = !bss->dtim_period; + } if (elems->ds_params && elems->ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems->ds_params[0]); @@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (!sdata->u.mgd.associated) return; + if (need_ps) { + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); + } + if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)) { diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 9afe2f9885dc..bc061f629674 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, bss->dtim_period = tim_ie->dtim_period; } - /* set default value for buggy AP/no TIM element */ - if (bss->dtim_period == 0) - bss->dtim_period = 1; - bss->supp_rates_len = 0; if (elems->supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; -- GitLab From c6a6e6e203ee9a34fa53f773272f21d48b4e3454 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:51 -0700 Subject: [PATCH 1202/3892] ARM: OMAP4: PM: OMAP4 essential basic initialisations. Some of the OMAP4 specific chip level initialisations are taken care of. Signed-off-by: Abhijit Pagare Cc: Benoit Cousson Cc: Rajendra Nayak Cc: Tony Lindgren [paul@pwsan.com: updated to use '4430ES1' rather than simply '4430'; updated to apply after the intervening cpu.h/id.c patch; thanks also to Tony for catching a bug in my rewrite] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/id.c | 1 + arch/arm/plat-omap/include/plat/cpu.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 3d65c50bd017..9e7c4aeeae02 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -281,6 +281,7 @@ void __init omap4_check_revision(void) if ((hawkeye == 0xb852) && (rev == 0x0)) { omap_revision = OMAP4430_REV_ES1_0; + omap_chip.oc |= CHIP_IS_OMAP4430ES1; pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name); return; } diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index a162f585b1e3..ccd78fd473d1 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -44,7 +44,7 @@ int omap_type(void); struct omap_chip_id { - u8 oc; + u16 oc; u8 type; }; @@ -154,6 +154,7 @@ unsigned int omap_rev(void); * cpu_is_omap242x(): True for OMAP2420, OMAP2422, OMAP2423 * cpu_is_omap243x(): True for OMAP2430 * cpu_is_omap343x(): True for OMAP3430 + * cpu_is_omap443x(): True for OMAP4430 */ #define GET_OMAP_CLASS (omap_rev() & 0xff) @@ -286,6 +287,7 @@ IS_OMAP_SUBCLASS(443x, 0x443) * cpu_is_omap2423(): True for OMAP2423 * cpu_is_omap2430(): True for OMAP2430 * cpu_is_omap3430(): True for OMAP3430 + * cpu_is_omap4430(): True for OMAP4430 * cpu_is_omap3505(): True for OMAP3505 * cpu_is_omap3517(): True for OMAP3517 */ @@ -334,6 +336,7 @@ IS_OMAP_TYPE(3517, 0x3517) #define cpu_is_omap3505() 0 #define cpu_is_omap3517() 0 #define cpu_is_omap3430() 0 +#define cpu_is_omap4430() 0 #define cpu_is_omap3630() 0 /* @@ -471,9 +474,12 @@ IS_OMAP_TYPE(3517, 0x3517) #define CHIP_IS_OMAP3430ES3_0 (1 << 5) #define CHIP_IS_OMAP3430ES3_1 (1 << 6) #define CHIP_IS_OMAP3630ES1 (1 << 7) +#define CHIP_IS_OMAP4430ES1 (1 << 8) #define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430) +#define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1) + /* * "GE" here represents "greater than or equal to" in terms of ES * levels. So CHIP_GE_OMAP3430ES2 is intended to match all OMAP3430 -- GitLab From 3790300903e6a98ce5f5391f4d435959266f79e7 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:51 -0700 Subject: [PATCH 1203/3892] ARM: OMAP4: PM: OMAP4 Power Domain Porting Related Clean-up. Module offsets were same for OMAP2 and OMAP3 while they differ for OMAP4. Hence we need different macros for identifying platform specific offsets. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/clockdomain.c | 4 ++-- arch/arm/mach-omap2/pm-debug.c | 14 +++++++------- arch/arm/mach-omap2/pm24xx.c | 5 +++-- arch/arm/mach-omap2/pm34xx.c | 24 ++++++++++++------------ arch/arm/mach-omap2/powerdomain.c | 22 +++++++++++----------- arch/arm/mach-omap2/prcm-common.h | 9 +++++++++ arch/arm/mach-omap2/prcm.c | 17 ++++++++++++++--- arch/arm/mach-omap2/prm.h | 17 ++++++++++++----- arch/arm/mach-omap2/sleep34xx.S | 2 +- 9 files changed, 71 insertions(+), 43 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index dd285f001467..50c8cd7c7126 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -413,7 +413,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) if (cpu_is_omap24xx()) { cm_set_mod_reg_bits(OMAP24XX_FORCESTATE, - clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL); + clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); } else if (cpu_is_omap34xx()) { @@ -455,7 +455,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) if (cpu_is_omap24xx()) { cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE, - clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL); + clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); } else if (cpu_is_omap34xx()) { diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index a0866268aa41..03dc845c82cb 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -68,8 +68,8 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) /* MPU */ DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL); - DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL); - DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST); + DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTCTRL); + DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTST); DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); #endif #if 0 @@ -93,7 +93,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN); DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN); DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE); - DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST); + DUMP_PRM_MOD_REG(CORE_MOD, OMAP2_PM_PWSTST); #endif #if 0 /* DSP */ @@ -104,10 +104,10 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTCTRL); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTST); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTCTRL); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTST); } #endif } else { diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index cba05b9f041f..754381857cb6 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -219,11 +219,12 @@ static void omap2_enter_mpu_retention(void) /* Try to enter MPU retention */ prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | OMAP_LOGICRETSTATE, - MPU_MOD, PM_PWSTCTRL); + MPU_MOD, OMAP2_PM_PWSTCTRL); } else { /* Block MPU retention */ - prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL); + prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, + OMAP2_PM_PWSTCTRL); only_idle = 1; } diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 910a7acf542d..f841a6e33611 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -685,7 +685,7 @@ static void __init omap3_iva_idle(void) prm_write_mod_reg(OMAP3430_RST1_IVA2 | OMAP3430_RST2_IVA2 | OMAP3430_RST3_IVA2, - OMAP3430_IVA2_MOD, RM_RSTCTRL); + OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); /* Enable IVA2 clock */ cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2, @@ -696,7 +696,7 @@ static void __init omap3_iva_idle(void) OMAP343X_CONTROL_IVA2_BOOTMOD); /* Un-reset IVA2 */ - prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL); + prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); /* Disable IVA2 clock */ cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); @@ -705,7 +705,7 @@ static void __init omap3_iva_idle(void) prm_write_mod_reg(OMAP3430_RST1_IVA2 | OMAP3430_RST2_IVA2 | OMAP3430_RST3_IVA2, - OMAP3430_IVA2_MOD, RM_RSTCTRL); + OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); } static void __init omap3_d2d_idle(void) @@ -728,8 +728,8 @@ static void __init omap3_d2d_idle(void) /* reset modem */ prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, - CORE_MOD, RM_RSTCTRL); - prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL); + CORE_MOD, OMAP2_RM_RSTCTRL); + prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL); } static void __init prcm_setup_regs(void) @@ -916,13 +916,13 @@ static void __init prcm_setup_regs(void) prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); /* Clear any pending 'reset' flags */ - prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST); - prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST); /* Clear any pending PRCM interrupts */ prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 26b3f3ee82a3..e503050dda06 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -710,7 +710,7 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, (pwrst << OMAP_POWERSTATE_SHIFT), - pwrdm->prcm_offs, PM_PWSTCTRL); + pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); return 0; } @@ -728,7 +728,7 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL, + return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL, OMAP_POWERSTATE_MASK); } @@ -745,7 +745,7 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, + return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, OMAP_POWERSTATEST_MASK); } @@ -796,7 +796,7 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) */ prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE, (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)), - pwrdm->prcm_offs, PM_PWSTCTRL); + pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); return 0; } @@ -856,7 +856,7 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) } prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), - pwrdm->prcm_offs, PM_PWSTCTRL); + pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); return 0; } @@ -917,7 +917,7 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) } prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs, - PM_PWSTCTRL); + OMAP2_PM_PWSTCTRL); return 0; } @@ -936,7 +936,7 @@ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, + return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, OMAP3430_LOGICSTATEST); } @@ -1010,7 +1010,7 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) return -EEXIST; } - return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, m); + return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, m); } /** @@ -1114,7 +1114,7 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) pwrdm->name); prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, - pwrdm->prcm_offs, PM_PWSTCTRL); + pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); return 0; } @@ -1142,7 +1142,7 @@ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) pwrdm->name); prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0, - pwrdm->prcm_offs, PM_PWSTCTRL); + pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); return 0; } @@ -1183,7 +1183,7 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) */ /* XXX Is this udelay() value meaningful? */ - while ((prm_read_mod_reg(pwrdm->prcm_offs, PM_PWSTST) & + while ((prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) & OMAP_INTRANSITION) && (c++ < PWRDM_TRANSITION_BAILOUT)) udelay(1); diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 61ac2a418bd0..90f603d434c6 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -119,6 +119,15 @@ #define OMAP4430_CHIRONSS_CHIRONSS_CPU0_MOD 0x0400 #define OMAP4430_CHIRONSS_CHIRONSS_CPU1_MOD 0x0800 +/* Base Addresses for the OMAP4 */ + +#define OMAP4430_CM1_BASE 0x4a004000 +#define OMAP4430_CM2_BASE 0x4a008000 +#define OMAP4430_PRM_BASE 0x4a306000 +#define OMAP4430_SCRM_BASE 0x4a30a000 +#define OMAP4430_CHIRONSS_BASE 0x48243000 + + /* 24XX register bits shared between CM & PRM registers */ /* CM_FCLKEN1_CORE, CM_ICLKEN1_CORE, PM_WKEN1_CORE shared bits */ diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index cf466ea1dffc..b4ba14974b37 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -11,6 +11,7 @@ * Rajendra Nayak * * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc. + * Upgraded with OMAP4 support by Abhijit Pagare * * 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 @@ -121,7 +122,10 @@ struct omap3_prcm_regs prcm_context; u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ - return prm_read_mod_reg(WKUP_MOD, RM_RSTST) & 0x7f; + if (cpu_is_omap24xx() | cpu_is_omap34xx()) + return prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST) & 0x7f; + if (cpu_is_omap44xx()) + return prm_read_mod_reg(WKUP_MOD, OMAP4_RM_RSTST) & 0x7f; } EXPORT_SYMBOL(omap_prcm_get_reset_sources); @@ -144,10 +148,17 @@ void omap_prcm_arch_reset(char mode) * cf. OMAP34xx TRM, Initialization / Software Booting * Configuration. */ omap_writel(l, OMAP343X_SCRATCHPAD + 4); - } else + } else if (cpu_is_omap44xx()) + prcm_offs = OMAP4430_PRM_DEVICE_MOD; + else WARN_ON(1); - prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL); + if (cpu_is_omap24xx() | cpu_is_omap34xx()) + prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, + OMAP2_RM_RSTCTRL); + if (cpu_is_omap44xx()) + prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, + OMAP4_RM_RSTCTRL); } static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg) diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 40f006285163..5fba2aa8932c 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -179,9 +179,11 @@ /* Registers appearing on both 24xx and 34xx */ -#define RM_RSTCTRL 0x0050 -#define RM_RSTTIME 0x0054 -#define RM_RSTST 0x0058 +#define OMAP2_RM_RSTCTRL 0x0050 +#define OMAP2_RM_RSTTIME 0x0054 +#define OMAP2_RM_RSTST 0x0058 +#define OMAP2_PM_PWSTCTRL 0x00e0 +#define OMAP2_PM_PWSTST 0x00e4 #define PM_WKEN 0x00a0 #define PM_WKEN1 PM_WKEN @@ -191,8 +193,6 @@ #define PM_EVGENCTRL 0x00d4 #define PM_EVGENONTIM 0x00d8 #define PM_EVGENOFFTIM 0x00dc -#define PM_PWSTCTRL 0x00e0 -#define PM_PWSTST 0x00e4 /* Omap2 specific registers */ #define OMAP24XX_PM_WKEN2 0x00a4 @@ -220,6 +220,13 @@ #define OMAP3430_PRM_IRQSTATUS_IVA2 0x00f8 #define OMAP3430_PRM_IRQENABLE_IVA2 0x00fc +/* Omap4 specific registers */ +#define OMAP4_RM_RSTCTRL 0x0000 +#define OMAP4_RM_RSTTIME 0x0004 +#define OMAP4_RM_RSTST 0x0008 +#define OMAP4_PM_PWSTCTRL 0x0000 +#define OMAP4_PM_PWSTST 0x0004 + #ifndef __ASSEMBLER__ diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index c3626ea48143..22fcc14e63be 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -38,7 +38,7 @@ #define PM_PREPWSTST_CORE_P 0x48306AE8 #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ OMAP3430_PM_PREPWSTST) -#define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL +#define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + OMAP2_PM_PWSTCTRL #define CM_IDLEST1_CORE_V OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1) #define SRAM_BASE_P 0x40200000 #define CONTROL_STAT 0x480022F0 -- GitLab From f37c6dfac99451b8babdd320d7aed4e03d51b94b Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:52 -0700 Subject: [PATCH 1204/3892] ARM: OMAP4: PM: Add the Autogenerated OMAP4 specific power domain framework. The Autogenerated OMAP4 power domain specific file (mach-omap2/powerdomains44xx.h) is added here. This file is auto-generated using python scripting and following is the list of the people involved: Paul Walmsley Benoit Cousson Abhijit Pagare Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Signed-off-by: Benoit Cousson Signed-off-by: Rajendra Nayak --- arch/arm/mach-omap2/powerdomains44xx.h | 310 ++++++++++++++++++ arch/arm/plat-omap/include/plat/powerdomain.h | 3 + 2 files changed, 313 insertions(+) create mode 100644 arch/arm/mach-omap2/powerdomains44xx.h diff --git a/arch/arm/mach-omap2/powerdomains44xx.h b/arch/arm/mach-omap2/powerdomains44xx.h new file mode 100644 index 000000000000..c1015147d579 --- /dev/null +++ b/arch/arm/mach-omap2/powerdomains44xx.h @@ -0,0 +1,310 @@ +/* + * OMAP4 Power domains framework + * + * Copyright (C) 2009 Texas Instruments, Inc. + * Copyright (C) 2009 Nokia Corporation + * + * Abhijit Pagare (abhijitpagare@ti.com) + * Benoit Cousson (b-cousson@ti.com) + * Paul Walmsley + * + * This file is automatically generated from the OMAP hardware databases. + * We respectfully ask that any modifications to this file be coordinated + * with the public linux-omap@vger.kernel.org mailing list and the + * authors above to ensure that the autogeneration scripts are kept + * up-to-date with the file contents. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAINS44XX_H +#define __ARCH_ARM_MACH_OMAP2_POWERDOMAINS44XX_H + +#include + +#include "prcm-common.h" +#include "cm.h" +#include "cm-regbits-44xx.h" +#include "prm.h" +#include "prm-regbits-44xx.h" + +#if defined(CONFIG_ARCH_OMAP4) + +/* core_44xx_pwrdm: CORE power domain */ +static struct powerdomain core_44xx_pwrdm = { + .name = "core_pwrdm", + .prcm_offs = OMAP4430_PRM_CORE_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 5, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* core_nret_bank */ + [1] = PWRSTS_OFF_RET, /* core_ocmram */ + [2] = PWRDM_POWER_RET, /* core_other_bank */ + [3] = PWRSTS_OFF_RET, /* ducati_l2ram */ + [4] = PWRSTS_OFF_RET, /* ducati_unicache */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* core_nret_bank */ + [1] = PWRSTS_OFF_RET, /* core_ocmram */ + [2] = PWRDM_POWER_ON, /* core_other_bank */ + [3] = PWRDM_POWER_ON, /* ducati_l2ram */ + [4] = PWRDM_POWER_ON, /* ducati_unicache */ + }, +}; + +/* gfx_44xx_pwrdm: 3D accelerator power domain */ +static struct powerdomain gfx_44xx_pwrdm = { + .name = "gfx_pwrdm", + .prcm_offs = OMAP4430_PRM_GFX_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_ON, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* gfx_mem */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* gfx_mem */ + }, +}; + +/* abe_44xx_pwrdm: Audio back end power domain */ +static struct powerdomain abe_44xx_pwrdm = { + .name = "abe_pwrdm", + .prcm_offs = OMAP4430_PRM_ABE_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRDM_POWER_OFF, + .banks = 2, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_RET, /* aessmem */ + [1] = PWRDM_POWER_OFF, /* periphmem */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* aessmem */ + [1] = PWRDM_POWER_ON, /* periphmem */ + }, +}; + +/* dss_44xx_pwrdm: Display subsystem power domain */ +static struct powerdomain dss_44xx_pwrdm = { + .name = "dss_pwrdm", + .prcm_offs = OMAP4430_PRM_DSS_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* dss_mem */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* dss_mem */ + }, +}; + +/* tesla_44xx_pwrdm: Tesla processor power domain */ +static struct powerdomain tesla_44xx_pwrdm = { + .name = "tesla_pwrdm", + .prcm_offs = OMAP4430_PRM_TESLA_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 3, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_RET, /* tesla_edma */ + [1] = PWRSTS_OFF_RET, /* tesla_l1 */ + [2] = PWRSTS_OFF_RET, /* tesla_l2 */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* tesla_edma */ + [1] = PWRDM_POWER_ON, /* tesla_l1 */ + [2] = PWRDM_POWER_ON, /* tesla_l2 */ + }, +}; + +/* wkup_44xx_pwrdm: Wake-up power domain */ +static struct powerdomain wkup_44xx_pwrdm = { + .name = "wkup_pwrdm", + .prcm_offs = OMAP4430_PRM_WKUP_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRDM_POWER_ON, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* wkup_bank */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* wkup_bank */ + }, +}; + +/* cpu0_44xx_pwrdm: MPU0 processor and Neon coprocessor power domain */ +static struct powerdomain cpu0_44xx_pwrdm = { + .name = "cpu0_pwrdm", + .prcm_offs = OMAP4430_CHIRONSS_CHIRONSS_CPU0_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRSTS_OFF_RET, /* cpu0_l1 */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* cpu0_l1 */ + }, +}; + +/* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */ +static struct powerdomain cpu1_44xx_pwrdm = { + .name = "cpu1_pwrdm", + .prcm_offs = OMAP4430_CHIRONSS_CHIRONSS_CPU1_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRSTS_OFF_RET, /* cpu1_l1 */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* cpu1_l1 */ + }, +}; + +/* emu_44xx_pwrdm: Emulation power domain */ +static struct powerdomain emu_44xx_pwrdm = { + .name = "emu_pwrdm", + .prcm_offs = OMAP4430_PRM_EMU_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_ON, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* emu_bank */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* emu_bank */ + }, +}; + +/* mpu_44xx_pwrdm: Modena processor and the Neon coprocessor power domain */ +static struct powerdomain mpu_44xx_pwrdm = { + .name = "mpu_pwrdm", + .prcm_offs = OMAP4430_PRM_MPU_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 3, + .pwrsts_mem_ret = { + [0] = PWRSTS_OFF_RET, /* mpu_l1 */ + [1] = PWRSTS_OFF_RET, /* mpu_l2 */ + [2] = PWRDM_POWER_RET, /* mpu_ram */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* mpu_l1 */ + [1] = PWRDM_POWER_ON, /* mpu_l2 */ + [2] = PWRDM_POWER_ON, /* mpu_ram */ + }, +}; + +/* ivahd_44xx_pwrdm: IVA-HD power domain */ +static struct powerdomain ivahd_44xx_pwrdm = { + .name = "ivahd_pwrdm", + .prcm_offs = OMAP4430_PRM_IVAHD_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRDM_POWER_OFF, + .banks = 4, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* hwa_mem */ + [1] = PWRSTS_OFF_RET, /* sl2_mem */ + [2] = PWRSTS_OFF_RET, /* tcm1_mem */ + [3] = PWRSTS_OFF_RET, /* tcm2_mem */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* hwa_mem */ + [1] = PWRDM_POWER_ON, /* sl2_mem */ + [2] = PWRDM_POWER_ON, /* tcm1_mem */ + [3] = PWRDM_POWER_ON, /* tcm2_mem */ + }, +}; + +/* cam_44xx_pwrdm: Camera subsystem power domain */ +static struct powerdomain cam_44xx_pwrdm = { + .name = "cam_pwrdm", + .prcm_offs = OMAP4430_PRM_CAM_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_ON, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* cam_mem */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* cam_mem */ + }, +}; + +/* l3init_44xx_pwrdm: L3 initators pheripherals power domain */ +static struct powerdomain l3init_44xx_pwrdm = { + .name = "l3init_pwrdm", + .prcm_offs = OMAP4430_PRM_L3INIT_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 1, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* l3init_bank1 */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* l3init_bank1 */ + }, +}; + +/* l4per_44xx_pwrdm: Target peripherals power domain */ +static struct powerdomain l4per_44xx_pwrdm = { + .name = "l4per_pwrdm", + .prcm_offs = OMAP4430_PRM_L4PER_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 2, + .pwrsts_mem_ret = { + [0] = PWRDM_POWER_OFF, /* nonretained_bank */ + [1] = PWRDM_POWER_RET, /* retained_bank */ + }, + .pwrsts_mem_on = { + [0] = PWRDM_POWER_ON, /* nonretained_bank */ + [1] = PWRDM_POWER_ON, /* retained_bank */ + }, +}; + +/* + * always_on_core_44xx_pwrdm: Always ON logic that sits in VDD_CORE voltage + * domain + */ +static struct powerdomain always_on_core_44xx_pwrdm = { + .name = "always_on_core_pwrdm", + .prcm_offs = OMAP4430_PRM_ALWAYS_ON_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRDM_POWER_ON, +}; + +/* cefuse_44xx_pwrdm: Customer efuse controller power domain */ +static struct powerdomain cefuse_44xx_pwrdm = { + .name = "cefuse_pwrdm", + .prcm_offs = OMAP4430_PRM_CEFUSE_MOD, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .pwrsts = PWRSTS_OFF_ON, +}; + +/* + * The following power domains are not under SW control + * + * always_on_iva + * always_on_mpu + * stdefuse + */ + +#endif + +#endif diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index 0b960051eaed..2510005e5ef0 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -37,6 +37,9 @@ #define PWRSTS_OFF_RET ((1 << PWRDM_POWER_OFF) | \ (1 << PWRDM_POWER_RET)) +#define PWRSTS_RET_ON ((1 << PWRDM_POWER_RET) | \ + (1 << PWRDM_POWER_ON)) + #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON)) -- GitLab From 38900c27fbbbe97e16f448b8bc9cafc05af03460 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:52 -0700 Subject: [PATCH 1205/3892] ARM: OMAP4: PM: Adapt the existing OMAP2/3 and common Power Domain Frameworks. Taking care of the platform specific and common power domains with proper checks. Also refining some Macros according to the latest OMAP4 requirements. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/powerdomains.h | 40 +++++++++++++++++-- arch/arm/plat-omap/include/plat/powerdomain.h | 10 ++--- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h index 057b2e3e2c35..d646c9979c38 100644 --- a/arch/arm/mach-omap2/powerdomains.h +++ b/arch/arm/mach-omap2/powerdomains.h @@ -12,6 +12,12 @@ * published by the Free Software Foundation. */ +/* + * To Do List + * -> Move the Sleep/Wakeup dependencies from Power Domain framework to + * Clock Domain Framework + */ + #ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS #define ARCH_ARM_MACH_OMAP2_POWERDOMAINS @@ -71,6 +77,7 @@ /* OMAP2/3-common powerdomains and wakeup dependencies */ +#ifndef CONFIG_ARCH_OMAP4 /* * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE @@ -110,21 +117,25 @@ static struct pwrdm_dep cam_gfx_sleepdeps[] = { }, { NULL }, }; +#endif #include "powerdomains24xx.h" #include "powerdomains34xx.h" +#include "powerdomains44xx.h" /* * OMAP2/3 common powerdomains */ +#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) + /* * The GFX powerdomain is not present on 3430ES2, but currently we do not * have a macro to filter it out at compile-time. */ -static struct powerdomain gfx_pwrdm = { +static struct powerdomain gfx_omap2_pwrdm = { .name = "gfx_pwrdm", .prcm_offs = GFX_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | @@ -142,20 +153,23 @@ static struct powerdomain gfx_pwrdm = { }, }; -static struct powerdomain wkup_pwrdm = { +static struct powerdomain wkup_omap2_pwrdm = { .name = "wkup_pwrdm", .prcm_offs = WKUP_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430), .dep_bit = OMAP_EN_WKUP_SHIFT, }; +#endif /* As powerdomains are added or removed above, this list must also be changed */ static struct powerdomain *powerdomains_omap[] __initdata = { - &gfx_pwrdm, - &wkup_pwrdm, +#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) + &wkup_omap2_pwrdm, + &gfx_omap2_pwrdm, +#endif #ifdef CONFIG_ARCH_OMAP24XX &dsp_pwrdm, @@ -186,6 +200,24 @@ static struct powerdomain *powerdomains_omap[] __initdata = { &dpll5_pwrdm, #endif +#ifdef CONFIG_ARCH_OMAP4 + &core_44xx_pwrdm, + &gfx_44xx_pwrdm, + &abe_44xx_pwrdm, + &dss_44xx_pwrdm, + &tesla_44xx_pwrdm, + &wkup_44xx_pwrdm, + &cpu0_44xx_pwrdm, + &cpu1_44xx_pwrdm, + &emu_44xx_pwrdm, + &mpu_44xx_pwrdm, + &ivahd_44xx_pwrdm, + &cam_44xx_pwrdm, + &l3init_44xx_pwrdm, + &l4per_44xx_pwrdm, + &always_on_core_44xx_pwrdm, + &cefuse_44xx_pwrdm, +#endif NULL }; diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index 2510005e5ef0..bac378eff8df 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -51,16 +51,16 @@ */ /* - * Number of memory banks that are power-controllable. On OMAP3430, the - * maximum is 4. + * Number of memory banks that are power-controllable. On OMAP4430, the + * maximum is 5. */ -#define PWRDM_MAX_MEM_BANKS 4 +#define PWRDM_MAX_MEM_BANKS 5 /* * Maximum number of clockdomains that can be associated with a powerdomain. - * CORE powerdomain on OMAP3 is the worst case + * CORE powerdomain on OMAP4 is the worst case */ -#define PWRDM_MAX_CLKDMS 4 +#define PWRDM_MAX_CLKDMS 9 /* XXX A completely arbitrary number. What is reasonable here? */ #define PWRDM_TRANSITION_BAILOUT 100000 -- GitLab From 3a759f09d7b9c6bbefffadd38fdc116125c49730 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:53 -0700 Subject: [PATCH 1206/3892] ARM: OMAP4: PM: Refine the APIs to support OMAP4 features. The proper Macros have to be used for platform specific calls and some of the compiling requirements and init calls are taken care of. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/io.c | 2 +- arch/arm/mach-omap2/powerdomain.c | 112 +++++++++++++++++++++++------- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index b32678b848bc..4a54e5afbac5 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -13,7 +13,7 @@ clock-common = clock.o clock_common_data.o clockdomain.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(omap-3-4-common) -obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) prcm.o clock.o +obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) clock.o obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 5a7996402c53..aa237ff644d6 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -312,12 +312,12 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, else if (cpu_is_omap34xx()) hwmods = omap34xx_hwmods; + pwrdm_init(powerdomains_omap); #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ /* The OPP tables have to be registered before a clk init */ omap_hwmod_init(hwmods); omap2_mux_init(); omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps); - pwrdm_init(powerdomains_omap); clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); #endif omap2_clk_init(); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index e503050dda06..c0de05097b5d 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -6,6 +6,8 @@ * * Written by Paul Walmsley * + * Added OMAP4 specific support by Abhijit Pagare + * * 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. @@ -26,8 +28,10 @@ #include "cm.h" #include "cm-regbits-34xx.h" +#include "cm-regbits-44xx.h" #include "prm.h" #include "prm-regbits-34xx.h" +#include "prm-regbits-44xx.h" #include #include @@ -40,6 +44,38 @@ enum { PWRDM_STATE_PREV, }; +/* Variable holding value of the CPU dependent PWRSTCTRL Register Offset */ +static u16 pwrstctrl_reg_offs; + +/* Variable holding value of the CPU dependent PWRSTST Register Offset */ +static u16 pwrstst_reg_offs; + +/* OMAP3 and OMAP4 specific register bit initialisations + * Notice that the names here are not according to each power + * domain but the bit mapping used applies to all of them + */ + +/* OMAP3 and OMAP4 Memory Onstate Masks (common across all power domains) */ +#define OMAP_MEM0_ONSTATE_MASK OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK +#define OMAP_MEM1_ONSTATE_MASK OMAP3430_L1FLATMEMONSTATE_MASK +#define OMAP_MEM2_ONSTATE_MASK OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK +#define OMAP_MEM3_ONSTATE_MASK OMAP3430_L2FLATMEMONSTATE_MASK +#define OMAP_MEM4_ONSTATE_MASK OMAP4430_OCP_NRET_BANK_ONSTATE_MASK + +/* OMAP3 and OMAP4 Memory Retstate Masks (common across all power domains) */ +#define OMAP_MEM0_RETSTATE_MASK OMAP3430_SHAREDL1CACHEFLATRETSTATE +#define OMAP_MEM1_RETSTATE_MASK OMAP3430_L1FLATMEMRETSTATE +#define OMAP_MEM2_RETSTATE_MASK OMAP3430_SHAREDL2CACHEFLATRETSTATE +#define OMAP_MEM3_RETSTATE_MASK OMAP3430_L2FLATMEMRETSTATE +#define OMAP_MEM4_RETSTATE_MASK OMAP4430_OCP_NRET_BANK_RETSTATE_MASK + +/* OMAP3 and OMAP4 Memory Status bits */ +#define OMAP_MEM0_STATEST_MASK OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK +#define OMAP_MEM1_STATEST_MASK OMAP3430_L1FLATMEMSTATEST_MASK +#define OMAP_MEM2_STATEST_MASK OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK +#define OMAP_MEM3_STATEST_MASK OMAP3430_L2FLATMEMSTATEST_MASK +#define OMAP_MEM4_STATEST_MASK OMAP4430_OCP_NRET_BANK_STATEST_MASK + /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); @@ -181,6 +217,18 @@ void pwrdm_init(struct powerdomain **pwrdm_list) { struct powerdomain **p = NULL; + if (cpu_is_omap24xx() | cpu_is_omap34xx()) { + pwrstctrl_reg_offs = OMAP2_PM_PWSTCTRL; + pwrstst_reg_offs = OMAP2_PM_PWSTST; + } else if (cpu_is_omap44xx()) { + pwrstctrl_reg_offs = OMAP4_PM_PWSTCTRL; + pwrstst_reg_offs = OMAP4_PM_PWSTST; + } else { + printk(KERN_ERR "Power Domain struct not supported for " \ + "this CPU\n"); + return; + } + if (pwrdm_list) { for (p = pwrdm_list; *p; p++) { pwrdm_register(*p); @@ -710,7 +758,7 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, (pwrst << OMAP_POWERSTATE_SHIFT), - pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); + pwrdm->prcm_offs, pwrstctrl_reg_offs); return 0; } @@ -728,8 +776,8 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL, - OMAP_POWERSTATE_MASK); + return prm_read_mod_bits_shift(pwrdm->prcm_offs, + pwrstctrl_reg_offs, OMAP_POWERSTATE_MASK); } /** @@ -745,8 +793,8 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, - OMAP_POWERSTATEST_MASK); + return prm_read_mod_bits_shift(pwrdm->prcm_offs, + pwrstst_reg_offs, OMAP_POWERSTATEST_MASK); } /** @@ -796,7 +844,7 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) */ prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE, (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)), - pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); + pwrdm->prcm_offs, pwrstctrl_reg_offs); return 0; } @@ -839,16 +887,19 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) */ switch (bank) { case 0: - m = OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK; + m = OMAP_MEM0_ONSTATE_MASK; break; case 1: - m = OMAP3430_L1FLATMEMONSTATE_MASK; + m = OMAP_MEM1_ONSTATE_MASK; break; case 2: - m = OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK; + m = OMAP_MEM2_ONSTATE_MASK; break; case 3: - m = OMAP3430_L2FLATMEMONSTATE_MASK; + m = OMAP_MEM3_ONSTATE_MASK; + break; + case 4: + m = OMAP_MEM4_ONSTATE_MASK; break; default: WARN_ON(1); /* should never happen */ @@ -856,7 +907,7 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) } prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), - pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); + pwrdm->prcm_offs, pwrstctrl_reg_offs); return 0; } @@ -900,16 +951,19 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) */ switch (bank) { case 0: - m = OMAP3430_SHAREDL1CACHEFLATRETSTATE; + m = OMAP_MEM0_RETSTATE_MASK; break; case 1: - m = OMAP3430_L1FLATMEMRETSTATE; + m = OMAP_MEM1_RETSTATE_MASK; break; case 2: - m = OMAP3430_SHAREDL2CACHEFLATRETSTATE; + m = OMAP_MEM2_RETSTATE_MASK; break; case 3: - m = OMAP3430_L2FLATMEMRETSTATE; + m = OMAP_MEM3_RETSTATE_MASK; + break; + case 4: + m = OMAP_MEM4_RETSTATE_MASK; break; default: WARN_ON(1); /* should never happen */ @@ -917,7 +971,7 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) } prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs, - OMAP2_PM_PWSTCTRL); + pwrstctrl_reg_offs); return 0; } @@ -936,8 +990,8 @@ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, - OMAP3430_LOGICSTATEST); + return prm_read_mod_bits_shift(pwrdm->prcm_offs, + pwrstst_reg_offs, OMAP3430_LOGICSTATEST); } /** @@ -994,23 +1048,27 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) */ switch (bank) { case 0: - m = OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK; + m = OMAP_MEM0_STATEST_MASK; break; case 1: - m = OMAP3430_L1FLATMEMSTATEST_MASK; + m = OMAP_MEM1_STATEST_MASK; break; case 2: - m = OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK; + m = OMAP_MEM2_STATEST_MASK; break; case 3: - m = OMAP3430_L2FLATMEMSTATEST_MASK; + m = OMAP_MEM3_STATEST_MASK; + break; + case 4: + m = OMAP_MEM4_STATEST_MASK; break; default: WARN_ON(1); /* should never happen */ return -EEXIST; } - return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, m); + return prm_read_mod_bits_shift(pwrdm->prcm_offs, + pwrstst_reg_offs, m); } /** @@ -1114,7 +1172,7 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) pwrdm->name); prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, - pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); + pwrdm->prcm_offs, pwrstctrl_reg_offs); return 0; } @@ -1142,7 +1200,7 @@ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) pwrdm->name); prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0, - pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); + pwrdm->prcm_offs, pwrstctrl_reg_offs); return 0; } @@ -1183,10 +1241,10 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) */ /* XXX Is this udelay() value meaningful? */ - while ((prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) & + while ((prm_read_mod_reg(pwrdm->prcm_offs, pwrstst_reg_offs) & OMAP_INTRANSITION) && (c++ < PWRDM_TRANSITION_BAILOUT)) - udelay(1); + udelay(1); if (c > PWRDM_TRANSITION_BAILOUT) { printk(KERN_ERR "powerdomain: waited too long for " -- GitLab From 84c0c39aec31a09571fc08a752a2f4da0fe9fcf2 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:53 -0700 Subject: [PATCH 1207/3892] ARM: OMAP4: PM: Make OMAP3 Clock-domain framework compatible for OMAP4. Here the ".clkstctrl_reg" field is added to the clockdomain stucture as the module offsets for OMAP4 do not map one to one for powerdomains and clockdomains as it used to for OMAP3. Hence we need to use absolute addresses to access the control registers. Some of the clock domains have modules falling in the address space of PRM partition. Hence necessitating the use of absolute adresses. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/clockdomain.c | 12 +- arch/arm/mach-omap2/clockdomains.h | 133 ++++++++++++++---- arch/arm/mach-omap2/cm.h | 5 +- arch/arm/mach-omap2/pm-debug.c | 4 +- arch/arm/mach-omap2/prcm.c | 43 +++--- arch/arm/plat-omap/include/plat/clockdomain.h | 3 + 6 files changed, 142 insertions(+), 58 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 50c8cd7c7126..52885ac5bb5d 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -163,7 +163,7 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v << __ffs(clkdm->clktrctrl_mask), - clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL); + clkdm->pwrdm.ptr->prcm_offs, OMAP2_CM_CLKSTCTRL); } static struct clockdomain *_clkdm_lookup(const char *name) @@ -371,7 +371,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) * @clk: struct clk * of a clockdomain * * Return the clockdomain's current state transition mode from the - * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if clk + * corresponding domain OMAP2_CM_CLKSTCTRL register. Returns -EINVAL if clk * is NULL or the current mode upon success. */ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) @@ -381,7 +381,7 @@ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) if (!clkdm) return -EINVAL; - v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL); + v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, OMAP2_CM_CLKSTCTRL); v &= clkdm->clktrctrl_mask; v >>= __ffs(clkdm->clktrctrl_mask); @@ -421,7 +421,8 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) __ffs(clkdm->clktrctrl_mask)); cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, - clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL); + clkdm->pwrdm.ptr->prcm_offs, + OMAP2_CM_CLKSTCTRL); } else { BUG(); @@ -463,7 +464,8 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) __ffs(clkdm->clktrctrl_mask)); cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, - clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL); + clkdm->pwrdm.ptr->prcm_offs, + OMAP2_CM_CLKSTCTRL); } else { BUG(); diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index c4ee0761d908..0e6114058db5 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -11,6 +11,8 @@ #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H #include +#include "cm.h" +#include "prm44xx.h" /* * OMAP2/3-common clockdomains @@ -50,6 +52,7 @@ static struct clockdomain mpu_2420_clkdm = { .name = "mpu_clkdm", .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -58,11 +61,59 @@ static struct clockdomain iva1_2420_clkdm = { .name = "iva1_clkdm", .pwrdm = { .name = "dsp_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(OMAP24XX_DSP_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; -#endif /* CONFIG_ARCH_OMAP2420 */ +static struct clockdomain dsp_2420_clkdm = { + .name = "dsp_clkdm", + .pwrdm = { .name = "dsp_pwrdm" }, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(OMAP24XX_DSP_MOD, + OMAP2_CM_CLKSTCTRL), + .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +static struct clockdomain gfx_2420_clkdm = { + .name = "gfx_clkdm", + .pwrdm = { .name = "gfx_pwrdm" }, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), + .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +static struct clockdomain core_l3_2420_clkdm = { + .name = "core_l3_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +static struct clockdomain core_l4_2420_clkdm = { + .name = "core_l4_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +static struct clockdomain dss_2420_clkdm = { + .name = "dss_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2420_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +#endif /* CONFIG_ARCH_OMAP2420 */ /* @@ -75,6 +126,8 @@ static struct clockdomain mpu_2430_clkdm = { .name = "mpu_clkdm", .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(MPU_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -83,60 +136,59 @@ static struct clockdomain mdm_clkdm = { .name = "mdm_clkdm", .pwrdm = { .name = "mdm_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP2430_MDM_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -#endif /* CONFIG_ARCH_OMAP2430 */ - - -/* - * 24XX-only clockdomains - */ - -#if defined(CONFIG_ARCH_OMAP24XX) - -static struct clockdomain dsp_clkdm = { +static struct clockdomain dsp_2430_clkdm = { .name = "dsp_clkdm", .pwrdm = { .name = "dsp_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP24XX_DSP_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -static struct clockdomain gfx_24xx_clkdm = { +static struct clockdomain gfx_2430_clkdm = { .name = "gfx_clkdm", .pwrdm = { .name = "gfx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -static struct clockdomain core_l3_24xx_clkdm = { +static struct clockdomain core_l3_2430_clkdm = { .name = "core_l3_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -static struct clockdomain core_l4_24xx_clkdm = { +static struct clockdomain core_l4_2430_clkdm = { .name = "core_l4_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -static struct clockdomain dss_24xx_clkdm = { +static struct clockdomain dss_2430_clkdm = { .name = "dss_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP2430_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -#endif /* CONFIG_ARCH_OMAP24XX */ +#endif /* CONFIG_ARCH_OMAP2430 */ /* @@ -149,6 +201,7 @@ static struct clockdomain mpu_34xx_clkdm = { .name = "mpu_clkdm", .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -157,6 +210,8 @@ static struct clockdomain neon_clkdm = { .name = "neon_clkdm", .pwrdm = { .name = "neon_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_NEON_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_NEON_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -165,6 +220,8 @@ static struct clockdomain iva2_clkdm = { .name = "iva2_clkdm", .pwrdm = { .name = "iva2_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_IVA2_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -173,6 +230,7 @@ static struct clockdomain gfx_3430es1_clkdm = { .name = "gfx_clkdm", .pwrdm = { .name = "gfx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1), }; @@ -181,6 +239,8 @@ static struct clockdomain sgx_clkdm = { .name = "sgx_clkdm", .pwrdm = { .name = "sgx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_SGX_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -196,6 +256,7 @@ static struct clockdomain d2d_clkdm = { .name = "d2d_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -204,6 +265,7 @@ static struct clockdomain core_l3_34xx_clkdm = { .name = "core_l3_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -212,6 +274,7 @@ static struct clockdomain core_l4_34xx_clkdm = { .name = "core_l4_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_L4_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -220,6 +283,8 @@ static struct clockdomain dss_34xx_clkdm = { .name = "dss_clkdm", .pwrdm = { .name = "dss_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -228,6 +293,8 @@ static struct clockdomain cam_clkdm = { .name = "cam_clkdm", .pwrdm = { .name = "cam_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_CAM_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -236,6 +303,8 @@ static struct clockdomain usbhost_clkdm = { .name = "usbhost_clkdm", .pwrdm = { .name = "usbhost_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -244,6 +313,8 @@ static struct clockdomain per_clkdm = { .name = "per_clkdm", .pwrdm = { .name = "per_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_PER_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -256,6 +327,8 @@ static struct clockdomain emu_clkdm = { .name = "emu_clkdm", .pwrdm = { .name = "emu_pwrdm" }, .flags = /* CLKDM_CAN_ENABLE_AUTO | */CLKDM_CAN_SWSUP, + .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_EMU_MOD, + OMAP2_CM_CLKSTCTRL), .clktrctrl_mask = OMAP3430_CLKTRCTRL_EMU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -323,19 +396,21 @@ static struct clockdomain *clockdomains_omap[] = { #ifdef CONFIG_ARCH_OMAP2420 &mpu_2420_clkdm, &iva1_2420_clkdm, + &dsp_2420_clkdm, + &gfx_2420_clkdm, + &core_l3_2420_clkdm, + &core_l4_2420_clkdm, + &dss_2420_clkdm, #endif #ifdef CONFIG_ARCH_OMAP2430 &mpu_2430_clkdm, &mdm_clkdm, -#endif - -#ifdef CONFIG_ARCH_OMAP24XX - &dsp_clkdm, - &gfx_24xx_clkdm, - &core_l3_24xx_clkdm, - &core_l4_24xx_clkdm, - &dss_24xx_clkdm, + &dsp_2430_clkdm, + &gfx_2430_clkdm, + &core_l3_2430_clkdm, + &core_l4_2430_clkdm, + &dss_2430_clkdm, #endif #ifdef CONFIG_ARCH_OMAP34XX diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 90a4086fbdf4..4e4ac8ccd7f5 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -67,7 +67,8 @@ #define CM_CLKSEL 0x0040 #define CM_CLKSEL1 CM_CLKSEL #define CM_CLKSEL2 0x0044 -#define CM_CLKSTCTRL 0x0048 +#define OMAP2_CM_CLKSTCTRL 0x0048 +#define OMAP4_CM_CLKSTCTRL 0x0000 /* Architecture-specific registers */ @@ -88,7 +89,7 @@ #define OMAP3430_CM_CLKSEL1_PLL CM_CLKSEL #define OMAP3430_CM_CLKSEL2_PLL CM_CLKSEL2 #define OMAP3430_CM_SLEEPDEP CM_CLKSEL2 -#define OMAP3430_CM_CLKSEL3 CM_CLKSTCTRL +#define OMAP3430_CM_CLKSEL3 OMAP2_CM_CLKSTCTRL #define OMAP3430_CM_CLKSTST 0x004c #define OMAP3430ES2_CM_CLKSEL4 0x004c #define OMAP3430ES2_CM_CLKSEL5 0x0050 diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 03dc845c82cb..5b6ae1e88e01 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -67,7 +67,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) #if 0 /* MPU */ DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); - DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL); + DUMP_CM_MOD_REG(MPU_MOD, OMAP2_CM_CLKSTCTRL); DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTCTRL); DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTST); DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); @@ -103,7 +103,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST); DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL); DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTCTRL); DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTST); DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTCTRL); diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index b4ba14974b37..82ad8f8ad83a 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -291,7 +291,7 @@ void omap3_prcm_save_context(void) prcm_context.emu_cm_clksel = cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); prcm_context.emu_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.pll_cm_autoidle2 = cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); prcm_context.pll_cm_clksel4 = @@ -344,23 +344,25 @@ void omap3_prcm_save_context(void) prcm_context.mpu_cm_autoidle2 = cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2); prcm_context.iva2_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.mpu_cm_clkstctrl = - cm_read_mod_reg(MPU_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(MPU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_clkstctrl = - cm_read_mod_reg(CORE_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(CORE_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.sgx_cm_clkstctrl = - cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, + OMAP2_CM_CLKSTCTRL); prcm_context.dss_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.cam_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.per_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.neon_cm_clkstctrl = - cm_read_mod_reg(OMAP3430_NEON_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430_NEON_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.usbhost_cm_clkstctrl = - cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL); + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, + OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_autoidle1 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1); prcm_context.core_cm_autoidle2 = @@ -443,7 +445,7 @@ void omap3_prcm_restore_context(void) cm_write_mod_reg(prcm_context.emu_cm_clksel, OMAP3430_EMU_MOD, CM_CLKSEL1); cm_write_mod_reg(prcm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.pll_cm_autoidle2, PLL_MOD, CM_AUTOIDLE2); cm_write_mod_reg(prcm_context.pll_cm_clksel4, PLL_MOD, @@ -489,22 +491,23 @@ void omap3_prcm_restore_context(void) CM_AUTOIDLE2); cm_write_mod_reg(prcm_context.mpu_cm_autoidle2, MPU_MOD, CM_AUTOIDLE2); cm_write_mod_reg(prcm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD, - CM_CLKSTCTRL); - cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.core_cm_clkstctrl, CORE_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.sgx_cm_clkstctrl, OMAP3430ES2_SGX_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.dss_cm_clkstctrl, OMAP3430_DSS_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.cam_cm_clkstctrl, OMAP3430_CAM_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.per_cm_clkstctrl, OMAP3430_PER_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.neon_cm_clkstctrl, OMAP3430_NEON_MOD, - CM_CLKSTCTRL); + OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.usbhost_cm_clkstctrl, - OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL); + OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.core_cm_autoidle1, CORE_MOD, CM_AUTOIDLE1); cm_write_mod_reg(prcm_context.core_cm_autoidle2, CORE_MOD, diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index eb734826e64e..4806e2c52c11 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -74,6 +74,9 @@ struct clockdomain { struct powerdomain *ptr; } pwrdm; + /* CLKSTCTRL reg for the given clock domain*/ + void __iomem *clkstctrl_reg; + /* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */ const u16 clktrctrl_mask; -- GitLab From b099474aa4e7fbaf5dc3b5858bc83dee2f94c60f Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:53 -0700 Subject: [PATCH 1208/3892] ARM: OMAP4: PM: Modify Clock-domain interfaces for OMAP4 compatibility. Here the APIs are modified to use absolute addresses instead of module offsets. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/clockdomain.c | 44 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 52885ac5bb5d..5366a10d8597 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -145,25 +145,29 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm) */ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) { - u32 v; + u32 bits, v; if (cpu_is_omap24xx()) { if (enable) - v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; + bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; else - v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; + bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; } else if (cpu_is_omap34xx()) { if (enable) - v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; + bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; else - v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO; + bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO; } else { BUG(); } - cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, - v << __ffs(clkdm->clktrctrl_mask), - clkdm->pwrdm.ptr->prcm_offs, OMAP2_CM_CLKSTCTRL); + bits = bits << __ffs(clkdm->clktrctrl_mask); + + v = __raw_readl(clkdm->clkstctrl_reg); + v &= ~(clkdm->clktrctrl_mask); + v |= bits; + __raw_writel(v, clkdm->clkstctrl_reg); + } static struct clockdomain *_clkdm_lookup(const char *name) @@ -381,7 +385,7 @@ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) if (!clkdm) return -EINVAL; - v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, OMAP2_CM_CLKSTCTRL); + v = __raw_readl(clkdm->clkstctrl_reg); v &= clkdm->clktrctrl_mask; v >>= __ffs(clkdm->clktrctrl_mask); @@ -417,12 +421,13 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) } else if (cpu_is_omap34xx()) { - u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << + u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << __ffs(clkdm->clktrctrl_mask)); - cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, - clkdm->pwrdm.ptr->prcm_offs, - OMAP2_CM_CLKSTCTRL); + u32 v = __raw_readl(clkdm->clkstctrl_reg); + v &= ~(clkdm->clktrctrl_mask); + v |= bits; + __raw_writel(v, clkdm->clkstctrl_reg); } else { BUG(); @@ -460,12 +465,13 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) } else if (cpu_is_omap34xx()) { - u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << + u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << __ffs(clkdm->clktrctrl_mask)); - cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, - clkdm->pwrdm.ptr->prcm_offs, - OMAP2_CM_CLKSTCTRL); + u32 v = __raw_readl(clkdm->clkstctrl_reg); + v &= ~(clkdm->clktrctrl_mask); + v |= bits; + __raw_writel(v, clkdm->clkstctrl_reg); } else { BUG(); @@ -561,7 +567,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) * downstream clocks for debugging purposes? */ - if (!clkdm || !clk || !clkdm->clktrctrl_mask) + if (!clkdm || !clk || !clkdm->clkstctrl_reg) return -EINVAL; if (atomic_inc_return(&clkdm->usecount) > 1) @@ -612,7 +618,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) * downstream clocks for debugging purposes? */ - if (!clkdm || !clk || !clkdm->clktrctrl_mask) + if (!clkdm || !clk || !clkdm->clkstctrl_reg) return -EINVAL; #ifdef DEBUG -- GitLab From 30b8863d2aa9d3f4804302f98821732a6a8f1419 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:54 -0700 Subject: [PATCH 1209/3892] ARM: OMAP4: PM: Add the Autogenerated OMAP4 specific clock domain framework. The Autogenerated OMAP4 clock domain specific file (mach-omap2/clockdomains44xx.h) is added here. This file is auto-generated using python scripting, and following is the lsit of the people involved: Benoit Cousson Abhijit Pagare Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Signed-off-by: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/clockdomains44xx.h | 237 +++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 arch/arm/mach-omap2/clockdomains44xx.h diff --git a/arch/arm/mach-omap2/clockdomains44xx.h b/arch/arm/mach-omap2/clockdomains44xx.h new file mode 100644 index 000000000000..2f23d3830ede --- /dev/null +++ b/arch/arm/mach-omap2/clockdomains44xx.h @@ -0,0 +1,237 @@ +/* + * OMAP4 Clock domains framework + * + * Copyright (C) 2009 Texas Instruments, Inc. + * Copyright (C) 2009 Nokia Corporation + * + * Abhijit Pagare (abhijitpagare@ti.com) + * Benoit Cousson (b-cousson@ti.com) + * + * This file is automatically generated from the OMAP hardware databases. + * We respectfully ask that any modifications to this file be coordinated + * with the public linux-omap@vger.kernel.org mailing list and the + * authors above to ensure that the autogeneration scripts are kept + * up-to-date with the file contents. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS44XX_H +#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS44XX_H + +#include + +#if defined(CONFIG_ARCH_OMAP4) + +static struct clockdomain l4_cefuse_44xx_clkdm = { + .name = "l4_cefuse_clkdm", + .pwrdm = { .name = "cefuse_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_CEFUSE_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l4_cfg_44xx_clkdm = { + .name = "l4_cfg_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L4CFG_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain tesla_44xx_clkdm = { + .name = "tesla_clkdm", + .pwrdm = { .name = "tesla_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_TESLA_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_gfx_44xx_clkdm = { + .name = "l3_gfx_clkdm", + .pwrdm = { .name = "gfx_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_GFX_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain ivahd_44xx_clkdm = { + .name = "ivahd_clkdm", + .pwrdm = { .name = "ivahd_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_IVAHD_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l4_secure_44xx_clkdm = { + .name = "l4_secure_clkdm", + .pwrdm = { .name = "l4per_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L4SEC_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l4_per_44xx_clkdm = { + .name = "l4_per_clkdm", + .pwrdm = { .name = "l4per_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L4PER_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain abe_44xx_clkdm = { + .name = "abe_clkdm", + .pwrdm = { .name = "abe_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM1_ABE_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_init_44xx_clkdm = { + .name = "l3_init_clkdm", + .pwrdm = { .name = "l3init_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L3INIT_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain mpuss_44xx_clkdm = { + .name = "mpuss_clkdm", + .pwrdm = { .name = "mpu_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_MPU_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain mpu0_44xx_clkdm = { + .name = "mpu0_clkdm", + .pwrdm = { .name = "cpu0_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_PDA_CPU0_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain mpu1_44xx_clkdm = { + .name = "mpu1_clkdm", + .pwrdm = { .name = "cpu1_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_PDA_CPU1_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_emif_44xx_clkdm = { + .name = "l3_emif_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_MEMIF_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l4_ao_44xx_clkdm = { + .name = "l4_ao_clkdm", + .pwrdm = { .name = "always_on_core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_ALWON_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain ducati_44xx_clkdm = { + .name = "ducati_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_DUCATI_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_2_44xx_clkdm = { + .name = "l3_2_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L3_2_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_1_44xx_clkdm = { + .name = "l3_1_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L3_1_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_d2d_44xx_clkdm = { + .name = "l3_d2d_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_D2D_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain iss_44xx_clkdm = { + .name = "iss_clkdm", + .pwrdm = { .name = "cam_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_CAM_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_dss_44xx_clkdm = { + .name = "l3_dss_clkdm", + .pwrdm = { .name = "dss_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_DSS_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l4_wkup_44xx_clkdm = { + .name = "l4_wkup_clkdm", + .pwrdm = { .name = "wkup_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_WKUP_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain emu_sys_44xx_clkdm = { + .name = "emu_sys_clkdm", + .pwrdm = { .name = "emu_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_EMU_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +static struct clockdomain l3_dma_44xx_clkdm = { + .name = "l3_dma_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_SDMA_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + +#endif + +#endif -- GitLab From 1a422724c6995004d0b9e95596ec4623e8ca1fc2 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:54 -0700 Subject: [PATCH 1210/3892] ARM: OMAP4: PM: Adapt the existing OMAP2/3 Clock Domain Frameworks. The introduction of the OMAP4 Clock Domain framework requires some adaptaions to be done in the earlier files to place the common and uncommon data in the proper places where they belong. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/clockdomains.h | 48 ++++++++++++++++++++++++-- arch/arm/mach-omap2/clockdomains44xx.h | 5 +++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 0e6114058db5..f985e0a15c4b 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -7,12 +7,18 @@ * Written by Paul Walmsley */ +/* + * To-Do List + * -> Port the Sleep/Wakeup dependencies for the domains + * from the Power domain framework + */ + #ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H #include #include "cm.h" -#include "prm44xx.h" +#include "prm.h" /* * OMAP2/3-common clockdomains @@ -23,6 +29,8 @@ * sys_clkout/sys_clkout2. */ +#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) + /* This is an implicit clockdomain - it is never defined as such in TRM */ static struct clockdomain wkup_clkdm = { .name = "wkup_clkdm", @@ -42,6 +50,8 @@ static struct clockdomain cm_clkdm = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430), }; +#endif + /* * 2420-only clockdomains */ @@ -365,11 +375,15 @@ static struct clockdomain dpll5_clkdm = { #endif /* CONFIG_ARCH_OMAP34XX */ +#include "clockdomains44xx.h" + /* * Clockdomain-powerdomain hwsup dependencies (34XX only) */ static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = { + +#ifdef CONFIG_ARCH_OMAP34XX { .pwrdm = { .name = "mpu_pwrdm" }, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -381,17 +395,21 @@ static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = { { .pwrdm = { .name = NULL }, } +#endif + }; /* - * + * List of clockdomain pointers per platform */ static struct clockdomain *clockdomains_omap[] = { +#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) &wkup_clkdm, &cm_clkdm, &prm_clkdm, +#endif #ifdef CONFIG_ARCH_OMAP2420 &mpu_2420_clkdm, @@ -434,6 +452,32 @@ static struct clockdomain *clockdomains_omap[] = { &dpll5_clkdm, #endif +#ifdef CONFIG_ARCH_OMAP4 + &l4_cefuse_44xx_clkdm, + &l4_cfg_44xx_clkdm, + &tesla_44xx_clkdm, + &l3_gfx_44xx_clkdm, + &ivahd_44xx_clkdm, + &l4_secure_44xx_clkdm, + &l4_per_44xx_clkdm, + &abe_44xx_clkdm, + &l3_init_44xx_clkdm, + &mpuss_44xx_clkdm, + &mpu0_44xx_clkdm, + &mpu1_44xx_clkdm, + &l3_emif_44xx_clkdm, + &l4_ao_44xx_clkdm, + &ducati_44xx_clkdm, + &l3_2_44xx_clkdm, + &l3_1_44xx_clkdm, + &l3_d2d_44xx_clkdm, + &iss_44xx_clkdm, + &l3_dss_44xx_clkdm, + &l4_wkup_44xx_clkdm, + &emu_sys_44xx_clkdm, + &l3_dma_44xx_clkdm, +#endif + NULL, }; diff --git a/arch/arm/mach-omap2/clockdomains44xx.h b/arch/arm/mach-omap2/clockdomains44xx.h index 2f23d3830ede..6fc55e4ed2b5 100644 --- a/arch/arm/mach-omap2/clockdomains44xx.h +++ b/arch/arm/mach-omap2/clockdomains44xx.h @@ -18,6 +18,11 @@ * published by the Free Software Foundation. */ +/* + * To-Do List + * -> Populate the Sleep/Wakeup dependencies for the domains + */ + #ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS44XX_H #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS44XX_H -- GitLab From 8a3ddc759b33d3b3b3953d001c8d3d9107becbb9 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:54 -0700 Subject: [PATCH 1211/3892] ARM: OMAP4: PM: Refine the APIs to support OMAP4 features. Port the APIs to support the OMAP4 clockdomain framework. Also take care of the compiling requirements for the same. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley Cc: Benoit Cousson Cc: Rajendra Nayak --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clockdomain.c | 21 ++++++++++++--------- arch/arm/mach-omap2/io.c | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 4a54e5afbac5..64de2fdf6556 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -13,7 +13,7 @@ clock-common = clock.o clock_common_data.o clockdomain.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(omap-3-4-common) -obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) clock.o +obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) $(clock-common) obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 5366a10d8597..8c9e78c2c17f 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -1,10 +1,11 @@ /* - * OMAP2/3 clockdomain framework functions + * OMAP2/3/4 clockdomain framework functions * - * Copyright (C) 2008 Texas Instruments, Inc. + * Copyright (C) 2008-2009 Texas Instruments, Inc. * Copyright (C) 2008-2009 Nokia Corporation * * Written by Paul Walmsley and Jouni Högander + * Added OMAP4 specific support by Abhijit Pagare * * 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 @@ -152,7 +153,7 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; else bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; - } else if (cpu_is_omap34xx()) { + } else if (cpu_is_omap34xx() | cpu_is_omap44xx()) { if (enable) bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; else @@ -213,10 +214,12 @@ void clkdm_init(struct clockdomain **clkdms, for (c = clkdms; *c; c++) clkdm_register(*c); - autodeps = init_autodeps; - if (autodeps) - for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) - _autodep_lookup(autodep); + if (!cpu_is_omap44xx()) { + autodeps = init_autodeps; + if (autodeps) + for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) + _autodep_lookup(autodep); + } } /** @@ -419,7 +422,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) cm_set_mod_reg_bits(OMAP24XX_FORCESTATE, clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); - } else if (cpu_is_omap34xx()) { + } else if (cpu_is_omap34xx() | cpu_is_omap44xx()) { u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << __ffs(clkdm->clktrctrl_mask)); @@ -463,7 +466,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE, clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); - } else if (cpu_is_omap34xx()) { + } else if (cpu_is_omap34xx() | cpu_is_omap44xx()) { u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << __ffs(clkdm->clktrctrl_mask)); diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index aa237ff644d6..51d7453f406d 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -313,12 +313,12 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, hwmods = omap34xx_hwmods; pwrdm_init(powerdomains_omap); + clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ /* The OPP tables have to be registered before a clk init */ omap_hwmod_init(hwmods); omap2_mux_init(); omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps); - clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); #endif omap2_clk_init(); omap_serial_early_init(); -- GitLab From 05842a32c7df9ad016cb55c66c9edb46aee1240b Mon Sep 17 00:00:00 2001 From: Ranjith Lohithakshan Date: Tue, 26 Jan 2010 20:12:56 -0700 Subject: [PATCH 1212/3892] AM35xx: Add AM35xx specific control module registers AM3517/05 has a few additional control module registers defined mainly to control the new IP's. This patch adds support for those new registers. Signed-off-by: Ranjith Lohithakshan Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/control.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index a745d62fad0d..61e7b8a8c993 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -160,6 +160,14 @@ #define OMAP343X_CONTROL_SRAMLDO5 (OMAP2_CONTROL_GENERAL + 0x02C0) #define OMAP343X_CONTROL_CSI (OMAP2_CONTROL_GENERAL + 0x02C4) +/* AM35XX only CONTROL_GENERAL register offsets */ +#define AM35XX_CONTROL_MSUSPENDMUX_6 (OMAP2_CONTROL_GENERAL + 0x0038) +#define AM35XX_CONTROL_DEVCONF2 (OMAP2_CONTROL_GENERAL + 0x0310) +#define AM35XX_CONTROL_DEVCONF3 (OMAP2_CONTROL_GENERAL + 0x0314) +#define AM35XX_CONTROL_CBA_PRIORITY (OMAP2_CONTROL_GENERAL + 0x0320) +#define AM35XX_CONTROL_LVL_INTR_CLEAR (OMAP2_CONTROL_GENERAL + 0x0324) +#define AM35XX_CONTROL_IP_SW_RESET (OMAP2_CONTROL_GENERAL + 0x0328) +#define AM35XX_CONTROL_IPSS_CLK_CTRL (OMAP2_CONTROL_GENERAL + 0x032C) /* 34xx PADCONF register offsets */ #define OMAP343X_PADCONF_ETK(i) (OMAP2_CONTROL_PADCONFS + 0x5a8 + \ @@ -257,6 +265,15 @@ #define OMAP343X_SCRATCHPAD (OMAP343X_CTRL_BASE + 0x910) #define OMAP343X_SCRATCHPAD_ROM_OFFSET 0x19C +/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */ +#define AM35XX_USBOTG_VBUSP_CLK_SHIFT 0 +#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT 1 +#define AM35XX_VPFE_VBUSP_CLK_SHIFT 2 +#define AM35XX_HECC_VBUSP_CLK_SHIFT 3 +#define AM35XX_USBOTG_FCLK_SHIFT 8 +#define AM35XX_CPGMAC_FCLK_SHIFT 9 +#define AM35XX_VPFE_FCLK_SHIFT 10 + /* * CONTROL OMAP STATUS register to identify OMAP3 features */ -- GitLab From 2c8a177eba6762ca828738c92efcdaed02d198bc Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:56 -0700 Subject: [PATCH 1213/3892] OMAP3 clock: reorganize CK_* platform flags Add CK_* flags for the two new Sitara chips, AM3505 and AM3517, and the OMAP34xx die shrink, OMAP36xx/OMAP37xx. Introduce a new CK_* flag, CK_3XXX, that marks all clocks that are common to OMAP3 family chips. CK_343X now refers to clocks that are available only on OMAP34{1,2,3,4}0 (WTBU) and OMAP35{03,15,25,30} (any version). At some point, the RATE_IN_* flags should be updated also. While here, add some documentation describing the chip families covered by these clock flags. This patch is partially based on patches from Ranjith Lohithakshan and Vishwanath Sripathy . Signed-off-by: Paul Walmsley Cc: Ranjith Lohithakshan Cc: Vishwanath Sripathy --- arch/arm/mach-omap2/clock34xx_data.c | 4 +-- arch/arm/plat-omap/include/plat/clkdev_omap.h | 26 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c index 74930e3158e3..ea8a0fa0088c 100644 --- a/arch/arm/mach-omap2/clock34xx_data.c +++ b/arch/arm/mach-omap2/clock34xx_data.c @@ -3216,11 +3216,11 @@ int __init omap2_clk_init(void) /* struct prcm_config *prcm; */ struct omap_clk *c; /* u32 clkrate; */ - u32 cpu_clkflg; + u32 cpu_clkflg = CK_3XXX; if (cpu_is_omap34xx()) { cpu_mask = RATE_IN_343X; - cpu_clkflg = CK_343X; + cpu_clkflg |= CK_343X; /* * Update this if there are further clock changes between ES2 diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h index 35b36caf5f91..bb937f3fabed 100644 --- a/arch/arm/plat-omap/include/plat/clkdev_omap.h +++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h @@ -25,17 +25,25 @@ struct omap_clk { }, \ } - +/* Platform flags for the clkdev-OMAP integration code */ #define CK_310 (1 << 0) -#define CK_7XX (1 << 1) +#define CK_7XX (1 << 1) /* 7xx, 850 */ #define CK_1510 (1 << 2) -#define CK_16XX (1 << 3) -#define CK_243X (1 << 4) -#define CK_242X (1 << 5) -#define CK_343X (1 << 6) -#define CK_3430ES1 (1 << 7) -#define CK_3430ES2 (1 << 8) -#define CK_443X (1 << 9) +#define CK_16XX (1 << 3) /* 16xx, 17xx, 5912 */ +#define CK_242X (1 << 4) +#define CK_243X (1 << 5) +#define CK_3XXX (1 << 6) /* OMAP3 + AM3 common clocks*/ +#define CK_343X (1 << 7) /* OMAP34xx common clocks */ +#define CK_3430ES1 (1 << 8) /* 34xxES1 only */ +#define CK_3430ES2 (1 << 9) /* 34xxES2, ES3, non-Sitara 35xx only */ +#define CK_3505 (1 << 10) +#define CK_3517 (1 << 11) +#define CK_36XX (1 << 12) /* OMAP36xx/37xx-specific clocks */ +#define CK_443X (1 << 13) + +#define CK_AM35XX (CK_3505 | CK_3517) /* all Sitara AM35xx */ + + #endif -- GitLab From ced825293ac34d4f250775c40f13cc6330653309 Mon Sep 17 00:00:00 2001 From: Ranjith Lohithakshan Date: Tue, 26 Jan 2010 20:12:57 -0700 Subject: [PATCH 1214/3892] AM35xx: Clock table updates for AM3505/17 AM3505/17 though a OMAP3530 derivative have the following main differences - Removal of the following OMAP3 modules - IVA - ISP/CAM - Modem and D2D components (MAD2D, SAD2D) - USIM - SSI - Mailboxes - USB OTG - ICR - MSPRO - SmartReflex - SDRC replaced with EMIF4 Controller in the SDRC subsystem thus adding support for DDR2 memory devices - Addition of the following new modules - Ethernet MAC (CPGMAC) - CAN Controller (HECC) - New USB OTG Controller with integrated Phy - Video Processing Front End (VPFE) - Additional UART (UART4) - All security accelerators disabled on GP devices and not to be accessed or configured This patch defines CPU flags for AM3505/17 and update the clock table. Clock support for new modules will be added by subsequent patches. Signed-off-by: Ranjith Lohithakshan [paul@pwsan.com: updated for 2.6.34 clock layout] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock34xx_data.c | 353 ++++++++++++++------------- 1 file changed, 180 insertions(+), 173 deletions(-) diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c index ea8a0fa0088c..cbb421a45763 100644 --- a/arch/arm/mach-omap2/clock34xx_data.c +++ b/arch/arm/mach-omap2/clock34xx_data.c @@ -2988,139 +2988,140 @@ static struct clk wdt1_fck = { * clkdev */ -static struct omap_clk omap34xx_clks[] = { - CLK(NULL, "omap_32k_fck", &omap_32k_fck, CK_343X), - CLK(NULL, "virt_12m_ck", &virt_12m_ck, CK_343X), - CLK(NULL, "virt_13m_ck", &virt_13m_ck, CK_343X), - CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck, CK_3430ES2), - CLK(NULL, "virt_19_2m_ck", &virt_19_2m_ck, CK_343X), - CLK(NULL, "virt_26m_ck", &virt_26m_ck, CK_343X), - CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck, CK_343X), - CLK(NULL, "osc_sys_ck", &osc_sys_ck, CK_343X), - CLK(NULL, "sys_ck", &sys_ck, CK_343X), - CLK(NULL, "sys_altclk", &sys_altclk, CK_343X), - CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_343X), - CLK(NULL, "sys_clkout1", &sys_clkout1, CK_343X), - CLK(NULL, "dpll1_ck", &dpll1_ck, CK_343X), - CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck, CK_343X), - CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck, CK_343X), +/* XXX At some point we should rename this file to clock3xxx_data.c */ +static struct omap_clk omap3xxx_clks[] = { + CLK(NULL, "omap_32k_fck", &omap_32k_fck, CK_3XXX), + CLK(NULL, "virt_12m_ck", &virt_12m_ck, CK_3XXX), + CLK(NULL, "virt_13m_ck", &virt_13m_ck, CK_3XXX), + CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "virt_19_2m_ck", &virt_19_2m_ck, CK_3XXX), + CLK(NULL, "virt_26m_ck", &virt_26m_ck, CK_3XXX), + CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck, CK_3XXX), + CLK(NULL, "osc_sys_ck", &osc_sys_ck, CK_3XXX), + CLK(NULL, "sys_ck", &sys_ck, CK_3XXX), + CLK(NULL, "sys_altclk", &sys_altclk, CK_3XXX), + CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_3XXX), + CLK(NULL, "sys_clkout1", &sys_clkout1, CK_3XXX), + CLK(NULL, "dpll1_ck", &dpll1_ck, CK_3XXX), + CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck, CK_3XXX), + CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck, CK_3XXX), CLK(NULL, "dpll2_ck", &dpll2_ck, CK_343X), CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck, CK_343X), - CLK(NULL, "dpll3_ck", &dpll3_ck, CK_343X), - CLK(NULL, "core_ck", &core_ck, CK_343X), - CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck, CK_343X), - CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck, CK_343X), - CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck, CK_343X), - CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck, CK_343X), - CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck, CK_343X), - CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck, CK_343X), - CLK(NULL, "dpll4_ck", &dpll4_ck, CK_343X), - CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck, CK_343X), - CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_343X), - CLK(NULL, "omap_96m_fck", &omap_96m_fck, CK_343X), - CLK(NULL, "cm_96m_fck", &cm_96m_fck, CK_343X), - CLK(NULL, "omap_54m_fck", &omap_54m_fck, CK_343X), - CLK(NULL, "omap_48m_fck", &omap_48m_fck, CK_343X), - CLK(NULL, "omap_12m_fck", &omap_12m_fck, CK_343X), - CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck, CK_343X), - CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck, CK_343X), - CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck, CK_343X), - CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck, CK_343X), - CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck, CK_343X), - CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck, CK_343X), - CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck, CK_343X), - CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck, CK_343X), - CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck, CK_343X), - CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck, CK_343X), - CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X), - CLK(NULL, "dpll5_ck", &dpll5_ck, CK_3430ES2), - CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck, CK_3430ES2), - CLK(NULL, "clkout2_src_ck", &clkout2_src_ck, CK_343X), - CLK(NULL, "sys_clkout2", &sys_clkout2, CK_343X), - CLK(NULL, "corex2_fck", &corex2_fck, CK_343X), - CLK(NULL, "dpll1_fck", &dpll1_fck, CK_343X), - CLK(NULL, "mpu_ck", &mpu_ck, CK_343X), - CLK(NULL, "arm_fck", &arm_fck, CK_343X), - CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck, CK_343X), + CLK(NULL, "dpll3_ck", &dpll3_ck, CK_3XXX), + CLK(NULL, "core_ck", &core_ck, CK_3XXX), + CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck, CK_3XXX), + CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck, CK_3XXX), + CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck, CK_3XXX), + CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck, CK_3XXX), + CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck, CK_3XXX), + CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck, CK_3XXX), + CLK(NULL, "dpll4_ck", &dpll4_ck, CK_3XXX), + CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck, CK_3XXX), + CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_3XXX), + CLK(NULL, "omap_96m_fck", &omap_96m_fck, CK_3XXX), + CLK(NULL, "cm_96m_fck", &cm_96m_fck, CK_3XXX), + CLK(NULL, "omap_54m_fck", &omap_54m_fck, CK_3XXX), + CLK(NULL, "omap_48m_fck", &omap_48m_fck, CK_3XXX), + CLK(NULL, "omap_12m_fck", &omap_12m_fck, CK_3XXX), + CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck, CK_3XXX), + CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck, CK_3XXX), + CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck, CK_3XXX), + CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck, CK_3XXX), + CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck, CK_3XXX), + CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck, CK_3XXX), + CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck, CK_3XXX), + CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck, CK_3XXX), + CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck, CK_3XXX), + CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck, CK_3XXX), + CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck, CK_3XXX), + CLK(NULL, "dpll5_ck", &dpll5_ck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "clkout2_src_ck", &clkout2_src_ck, CK_3XXX), + CLK(NULL, "sys_clkout2", &sys_clkout2, CK_3XXX), + CLK(NULL, "corex2_fck", &corex2_fck, CK_3XXX), + CLK(NULL, "dpll1_fck", &dpll1_fck, CK_3XXX), + CLK(NULL, "mpu_ck", &mpu_ck, CK_3XXX), + CLK(NULL, "arm_fck", &arm_fck, CK_3XXX), + CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck, CK_3XXX), CLK(NULL, "dpll2_fck", &dpll2_fck, CK_343X), CLK(NULL, "iva2_ck", &iva2_ck, CK_343X), - CLK(NULL, "l3_ick", &l3_ick, CK_343X), - CLK(NULL, "l4_ick", &l4_ick, CK_343X), - CLK(NULL, "rm_ick", &rm_ick, CK_343X), + CLK(NULL, "l3_ick", &l3_ick, CK_3XXX), + CLK(NULL, "l4_ick", &l4_ick, CK_3XXX), + CLK(NULL, "rm_ick", &rm_ick, CK_3XXX), CLK(NULL, "gfx_l3_ck", &gfx_l3_ck, CK_3430ES1), CLK(NULL, "gfx_l3_fck", &gfx_l3_fck, CK_3430ES1), CLK(NULL, "gfx_l3_ick", &gfx_l3_ick, CK_3430ES1), CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck, CK_3430ES1), CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck, CK_3430ES1), - CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2), - CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2), + CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2 | CK_3517), + CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2 | CK_3517), CLK(NULL, "d2d_26m_fck", &d2d_26m_fck, CK_3430ES1), CLK(NULL, "modem_fck", &modem_fck, CK_343X), CLK(NULL, "sad2d_ick", &sad2d_ick, CK_343X), CLK(NULL, "mad2d_ick", &mad2d_ick, CK_343X), - CLK(NULL, "gpt10_fck", &gpt10_fck, CK_343X), - CLK(NULL, "gpt11_fck", &gpt11_fck, CK_343X), - CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2), - CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2), - CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2), - CLK(NULL, "core_96m_fck", &core_96m_fck, CK_343X), - CLK("mmci-omap-hs.2", "fck", &mmchs3_fck, CK_3430ES2), - CLK("mmci-omap-hs.1", "fck", &mmchs2_fck, CK_343X), + CLK(NULL, "gpt10_fck", &gpt10_fck, CK_3XXX), + CLK(NULL, "gpt11_fck", &gpt11_fck, CK_3XXX), + CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX), + CLK("mmci-omap-hs.2", "fck", &mmchs3_fck, CK_3430ES2 | CK_AM35XX), + CLK("mmci-omap-hs.1", "fck", &mmchs2_fck, CK_3XXX), CLK(NULL, "mspro_fck", &mspro_fck, CK_343X), - CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_343X), - CLK("i2c_omap.3", "fck", &i2c3_fck, CK_343X), - CLK("i2c_omap.2", "fck", &i2c2_fck, CK_343X), - CLK("i2c_omap.1", "fck", &i2c1_fck, CK_343X), - CLK("omap-mcbsp.5", "fck", &mcbsp5_fck, CK_343X), - CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_343X), - CLK(NULL, "core_48m_fck", &core_48m_fck, CK_343X), - CLK("omap2_mcspi.4", "fck", &mcspi4_fck, CK_343X), - CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_343X), - CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_343X), - CLK("omap2_mcspi.1", "fck", &mcspi1_fck, CK_343X), - CLK(NULL, "uart2_fck", &uart2_fck, CK_343X), - CLK(NULL, "uart1_fck", &uart1_fck, CK_343X), + CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_3XXX), + CLK("i2c_omap.3", "fck", &i2c3_fck, CK_3XXX), + CLK("i2c_omap.2", "fck", &i2c2_fck, CK_3XXX), + CLK("i2c_omap.1", "fck", &i2c1_fck, CK_3XXX), + CLK("omap-mcbsp.5", "fck", &mcbsp5_fck, CK_3XXX), + CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_3XXX), + CLK(NULL, "core_48m_fck", &core_48m_fck, CK_3XXX), + CLK("omap2_mcspi.4", "fck", &mcspi4_fck, CK_3XXX), + CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_3XXX), + CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_3XXX), + CLK("omap2_mcspi.1", "fck", &mcspi1_fck, CK_3XXX), + CLK(NULL, "uart2_fck", &uart2_fck, CK_3XXX), + CLK(NULL, "uart1_fck", &uart1_fck, CK_3XXX), CLK(NULL, "fshostusb_fck", &fshostusb_fck, CK_3430ES1), - CLK(NULL, "core_12m_fck", &core_12m_fck, CK_343X), - CLK("omap_hdq.0", "fck", &hdq_fck, CK_343X), + CLK(NULL, "core_12m_fck", &core_12m_fck, CK_3XXX), + CLK("omap_hdq.0", "fck", &hdq_fck, CK_3XXX), CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1, CK_3430ES1), CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2, CK_3430ES2), CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1, CK_3430ES1), CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2, CK_3430ES2), - CLK(NULL, "core_l3_ick", &core_l3_ick, CK_343X), + CLK(NULL, "core_l3_ick", &core_l3_ick, CK_3XXX), CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es1, CK_3430ES1), CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es2, CK_3430ES2), - CLK(NULL, "sdrc_ick", &sdrc_ick, CK_343X), - CLK(NULL, "gpmc_fck", &gpmc_fck, CK_343X), + CLK(NULL, "sdrc_ick", &sdrc_ick, CK_3XXX), + CLK(NULL, "gpmc_fck", &gpmc_fck, CK_3XXX), CLK(NULL, "security_l3_ick", &security_l3_ick, CK_343X), CLK(NULL, "pka_ick", &pka_ick, CK_343X), - CLK(NULL, "core_l4_ick", &core_l4_ick, CK_343X), - CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2), - CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2), + CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX), + CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2 | CK_AM35XX), + CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2 | CK_AM35XX), CLK(NULL, "icr_ick", &icr_ick, CK_343X), CLK(NULL, "aes2_ick", &aes2_ick, CK_343X), CLK(NULL, "sha12_ick", &sha12_ick, CK_343X), CLK(NULL, "des2_ick", &des2_ick, CK_343X), - CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_343X), - CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_343X), + CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_3XXX), + CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_3XXX), CLK(NULL, "mspro_ick", &mspro_ick, CK_343X), - CLK("omap_hdq.0", "ick", &hdq_ick, CK_343X), - CLK("omap2_mcspi.4", "ick", &mcspi4_ick, CK_343X), - CLK("omap2_mcspi.3", "ick", &mcspi3_ick, CK_343X), - CLK("omap2_mcspi.2", "ick", &mcspi2_ick, CK_343X), - CLK("omap2_mcspi.1", "ick", &mcspi1_ick, CK_343X), - CLK("i2c_omap.3", "ick", &i2c3_ick, CK_343X), - CLK("i2c_omap.2", "ick", &i2c2_ick, CK_343X), - CLK("i2c_omap.1", "ick", &i2c1_ick, CK_343X), - CLK(NULL, "uart2_ick", &uart2_ick, CK_343X), - CLK(NULL, "uart1_ick", &uart1_ick, CK_343X), - CLK(NULL, "gpt11_ick", &gpt11_ick, CK_343X), - CLK(NULL, "gpt10_ick", &gpt10_ick, CK_343X), - CLK("omap-mcbsp.5", "ick", &mcbsp5_ick, CK_343X), - CLK("omap-mcbsp.1", "ick", &mcbsp1_ick, CK_343X), + CLK("omap_hdq.0", "ick", &hdq_ick, CK_3XXX), + CLK("omap2_mcspi.4", "ick", &mcspi4_ick, CK_3XXX), + CLK("omap2_mcspi.3", "ick", &mcspi3_ick, CK_3XXX), + CLK("omap2_mcspi.2", "ick", &mcspi2_ick, CK_3XXX), + CLK("omap2_mcspi.1", "ick", &mcspi1_ick, CK_3XXX), + CLK("i2c_omap.3", "ick", &i2c3_ick, CK_3XXX), + CLK("i2c_omap.2", "ick", &i2c2_ick, CK_3XXX), + CLK("i2c_omap.1", "ick", &i2c1_ick, CK_3XXX), + CLK(NULL, "uart2_ick", &uart2_ick, CK_3XXX), + CLK(NULL, "uart1_ick", &uart1_ick, CK_3XXX), + CLK(NULL, "gpt11_ick", &gpt11_ick, CK_3XXX), + CLK(NULL, "gpt10_ick", &gpt10_ick, CK_3XXX), + CLK("omap-mcbsp.5", "ick", &mcbsp5_ick, CK_3XXX), + CLK("omap-mcbsp.1", "ick", &mcbsp1_ick, CK_3XXX), CLK(NULL, "fac_ick", &fac_ick, CK_3430ES1), CLK(NULL, "mailboxes_ick", &mailboxes_ick, CK_343X), - CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_343X), + CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_3XXX), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_343X), CLK(NULL, "ssi_ick", &ssi_ick_3430es1, CK_3430ES1), CLK(NULL, "ssi_ick", &ssi_ick_3430es2, CK_3430ES2), @@ -3131,83 +3132,83 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "sha11_ick", &sha11_ick, CK_343X), CLK(NULL, "des1_ick", &des1_ick, CK_343X), CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1), - CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2), - CLK("omapdss", "tv_fck", &dss_tv_fck, CK_343X), - CLK("omapdss", "video_fck", &dss_96m_fck, CK_343X), - CLK("omapdss", "dss2_fck", &dss2_alwon_fck, CK_343X), + CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2 | CK_AM35XX), + CLK("omapdss", "tv_fck", &dss_tv_fck, CK_3XXX), + CLK("omapdss", "video_fck", &dss_96m_fck, CK_3XXX), + CLK("omapdss", "dss2_fck", &dss2_alwon_fck, CK_3XXX), CLK("omapdss", "ick", &dss_ick_3430es1, CK_3430ES1), - CLK("omapdss", "ick", &dss_ick_3430es2, CK_3430ES2), + CLK("omapdss", "ick", &dss_ick_3430es2, CK_3430ES2 | CK_AM35XX), CLK(NULL, "cam_mclk", &cam_mclk, CK_343X), CLK(NULL, "cam_ick", &cam_ick, CK_343X), CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X), - CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2), - CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2), - CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2), + CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2 | CK_AM35XX), + CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2 | CK_AM35XX), CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2), - CLK(NULL, "gpt1_fck", &gpt1_fck, CK_343X), - CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_343X), - CLK(NULL, "gpio1_dbck", &gpio1_dbck, CK_343X), - CLK("omap_wdt", "fck", &wdt2_fck, CK_343X), + CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX), + CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX), + CLK(NULL, "gpio1_dbck", &gpio1_dbck, CK_3XXX), + CLK("omap_wdt", "fck", &wdt2_fck, CK_3XXX), CLK(NULL, "wkup_l4_ick", &wkup_l4_ick, CK_343X), CLK(NULL, "usim_ick", &usim_ick, CK_3430ES2), - CLK("omap_wdt", "ick", &wdt2_ick, CK_343X), - CLK(NULL, "wdt1_ick", &wdt1_ick, CK_343X), - CLK(NULL, "gpio1_ick", &gpio1_ick, CK_343X), - CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_343X), - CLK(NULL, "gpt12_ick", &gpt12_ick, CK_343X), - CLK(NULL, "gpt1_ick", &gpt1_ick, CK_343X), - CLK(NULL, "per_96m_fck", &per_96m_fck, CK_343X), - CLK(NULL, "per_48m_fck", &per_48m_fck, CK_343X), - CLK(NULL, "uart3_fck", &uart3_fck, CK_343X), - CLK(NULL, "gpt2_fck", &gpt2_fck, CK_343X), - CLK(NULL, "gpt3_fck", &gpt3_fck, CK_343X), - CLK(NULL, "gpt4_fck", &gpt4_fck, CK_343X), - CLK(NULL, "gpt5_fck", &gpt5_fck, CK_343X), - CLK(NULL, "gpt6_fck", &gpt6_fck, CK_343X), - CLK(NULL, "gpt7_fck", &gpt7_fck, CK_343X), - CLK(NULL, "gpt8_fck", &gpt8_fck, CK_343X), - CLK(NULL, "gpt9_fck", &gpt9_fck, CK_343X), - CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck, CK_343X), - CLK(NULL, "gpio6_dbck", &gpio6_dbck, CK_343X), - CLK(NULL, "gpio5_dbck", &gpio5_dbck, CK_343X), - CLK(NULL, "gpio4_dbck", &gpio4_dbck, CK_343X), - CLK(NULL, "gpio3_dbck", &gpio3_dbck, CK_343X), - CLK(NULL, "gpio2_dbck", &gpio2_dbck, CK_343X), - CLK(NULL, "wdt3_fck", &wdt3_fck, CK_343X), - CLK(NULL, "per_l4_ick", &per_l4_ick, CK_343X), - CLK(NULL, "gpio6_ick", &gpio6_ick, CK_343X), - CLK(NULL, "gpio5_ick", &gpio5_ick, CK_343X), - CLK(NULL, "gpio4_ick", &gpio4_ick, CK_343X), - CLK(NULL, "gpio3_ick", &gpio3_ick, CK_343X), - CLK(NULL, "gpio2_ick", &gpio2_ick, CK_343X), - CLK(NULL, "wdt3_ick", &wdt3_ick, CK_343X), - CLK(NULL, "uart3_ick", &uart3_ick, CK_343X), - CLK(NULL, "gpt9_ick", &gpt9_ick, CK_343X), - CLK(NULL, "gpt8_ick", &gpt8_ick, CK_343X), - CLK(NULL, "gpt7_ick", &gpt7_ick, CK_343X), - CLK(NULL, "gpt6_ick", &gpt6_ick, CK_343X), - CLK(NULL, "gpt5_ick", &gpt5_ick, CK_343X), - CLK(NULL, "gpt4_ick", &gpt4_ick, CK_343X), - CLK(NULL, "gpt3_ick", &gpt3_ick, CK_343X), - CLK(NULL, "gpt2_ick", &gpt2_ick, CK_343X), - CLK("omap-mcbsp.2", "ick", &mcbsp2_ick, CK_343X), - CLK("omap-mcbsp.3", "ick", &mcbsp3_ick, CK_343X), - CLK("omap-mcbsp.4", "ick", &mcbsp4_ick, CK_343X), - CLK("omap-mcbsp.2", "fck", &mcbsp2_fck, CK_343X), - CLK("omap-mcbsp.3", "fck", &mcbsp3_fck, CK_343X), - CLK("omap-mcbsp.4", "fck", &mcbsp4_fck, CK_343X), - CLK("etb", "emu_src_ck", &emu_src_ck, CK_343X), - CLK(NULL, "pclk_fck", &pclk_fck, CK_343X), - CLK(NULL, "pclkx2_fck", &pclkx2_fck, CK_343X), - CLK(NULL, "atclk_fck", &atclk_fck, CK_343X), - CLK(NULL, "traceclk_src_fck", &traceclk_src_fck, CK_343X), - CLK(NULL, "traceclk_fck", &traceclk_fck, CK_343X), + CLK("omap_wdt", "ick", &wdt2_ick, CK_3XXX), + CLK(NULL, "wdt1_ick", &wdt1_ick, CK_3XXX), + CLK(NULL, "gpio1_ick", &gpio1_ick, CK_3XXX), + CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX), + CLK(NULL, "gpt12_ick", &gpt12_ick, CK_3XXX), + CLK(NULL, "gpt1_ick", &gpt1_ick, CK_3XXX), + CLK(NULL, "per_96m_fck", &per_96m_fck, CK_3XXX), + CLK(NULL, "per_48m_fck", &per_48m_fck, CK_3XXX), + CLK(NULL, "uart3_fck", &uart3_fck, CK_3XXX), + CLK(NULL, "gpt2_fck", &gpt2_fck, CK_3XXX), + CLK(NULL, "gpt3_fck", &gpt3_fck, CK_3XXX), + CLK(NULL, "gpt4_fck", &gpt4_fck, CK_3XXX), + CLK(NULL, "gpt5_fck", &gpt5_fck, CK_3XXX), + CLK(NULL, "gpt6_fck", &gpt6_fck, CK_3XXX), + CLK(NULL, "gpt7_fck", &gpt7_fck, CK_3XXX), + CLK(NULL, "gpt8_fck", &gpt8_fck, CK_3XXX), + CLK(NULL, "gpt9_fck", &gpt9_fck, CK_3XXX), + CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck, CK_3XXX), + CLK(NULL, "gpio6_dbck", &gpio6_dbck, CK_3XXX), + CLK(NULL, "gpio5_dbck", &gpio5_dbck, CK_3XXX), + CLK(NULL, "gpio4_dbck", &gpio4_dbck, CK_3XXX), + CLK(NULL, "gpio3_dbck", &gpio3_dbck, CK_3XXX), + CLK(NULL, "gpio2_dbck", &gpio2_dbck, CK_3XXX), + CLK(NULL, "wdt3_fck", &wdt3_fck, CK_3XXX), + CLK(NULL, "per_l4_ick", &per_l4_ick, CK_3XXX), + CLK(NULL, "gpio6_ick", &gpio6_ick, CK_3XXX), + CLK(NULL, "gpio5_ick", &gpio5_ick, CK_3XXX), + CLK(NULL, "gpio4_ick", &gpio4_ick, CK_3XXX), + CLK(NULL, "gpio3_ick", &gpio3_ick, CK_3XXX), + CLK(NULL, "gpio2_ick", &gpio2_ick, CK_3XXX), + CLK(NULL, "wdt3_ick", &wdt3_ick, CK_3XXX), + CLK(NULL, "uart3_ick", &uart3_ick, CK_3XXX), + CLK(NULL, "gpt9_ick", &gpt9_ick, CK_3XXX), + CLK(NULL, "gpt8_ick", &gpt8_ick, CK_3XXX), + CLK(NULL, "gpt7_ick", &gpt7_ick, CK_3XXX), + CLK(NULL, "gpt6_ick", &gpt6_ick, CK_3XXX), + CLK(NULL, "gpt5_ick", &gpt5_ick, CK_3XXX), + CLK(NULL, "gpt4_ick", &gpt4_ick, CK_3XXX), + CLK(NULL, "gpt3_ick", &gpt3_ick, CK_3XXX), + CLK(NULL, "gpt2_ick", &gpt2_ick, CK_3XXX), + CLK("omap-mcbsp.2", "ick", &mcbsp2_ick, CK_3XXX), + CLK("omap-mcbsp.3", "ick", &mcbsp3_ick, CK_3XXX), + CLK("omap-mcbsp.4", "ick", &mcbsp4_ick, CK_3XXX), + CLK("omap-mcbsp.2", "fck", &mcbsp2_fck, CK_3XXX), + CLK("omap-mcbsp.3", "fck", &mcbsp3_fck, CK_3XXX), + CLK("omap-mcbsp.4", "fck", &mcbsp4_fck, CK_3XXX), + CLK("etb", "emu_src_ck", &emu_src_ck, CK_3XXX), + CLK(NULL, "pclk_fck", &pclk_fck, CK_3XXX), + CLK(NULL, "pclkx2_fck", &pclkx2_fck, CK_3XXX), + CLK(NULL, "atclk_fck", &atclk_fck, CK_3XXX), + CLK(NULL, "traceclk_src_fck", &traceclk_src_fck, CK_3XXX), + CLK(NULL, "traceclk_fck", &traceclk_fck, CK_3XXX), CLK(NULL, "sr1_fck", &sr1_fck, CK_343X), CLK(NULL, "sr2_fck", &sr2_fck, CK_343X), CLK(NULL, "sr_l4_ick", &sr_l4_ick, CK_343X), - CLK(NULL, "secure_32k_fck", &secure_32k_fck, CK_343X), - CLK(NULL, "gpt12_fck", &gpt12_fck, CK_343X), - CLK(NULL, "wdt1_fck", &wdt1_fck, CK_343X), + CLK(NULL, "secure_32k_fck", &secure_32k_fck, CK_3XXX), + CLK(NULL, "gpt12_fck", &gpt12_fck, CK_3XXX), + CLK(NULL, "wdt1_fck", &wdt1_fck, CK_3XXX), }; @@ -3218,7 +3219,13 @@ int __init omap2_clk_init(void) /* u32 clkrate; */ u32 cpu_clkflg = CK_3XXX; - if (cpu_is_omap34xx()) { + if (cpu_is_omap3517()) { + cpu_mask = RATE_IN_343X | RATE_IN_3430ES2; + cpu_clkflg |= CK_3517; + } else if (cpu_is_omap3505()) { + cpu_mask = RATE_IN_343X | RATE_IN_3430ES2; + cpu_clkflg |= CK_3505; + } else if (cpu_is_omap34xx()) { cpu_mask = RATE_IN_343X; cpu_clkflg |= CK_343X; @@ -3237,10 +3244,10 @@ int __init omap2_clk_init(void) clk_init(&omap2_clk_functions); - for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) + for (c = omap3xxx_clks; c < omap3xxx_clks + ARRAY_SIZE(omap3xxx_clks); c++) clk_preinit(c->lk.clk); - for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) + for (c = omap3xxx_clks; c < omap3xxx_clks + ARRAY_SIZE(omap3xxx_clks); c++) if (c->cpu & cpu_clkflg) { clkdev_add(&c->lk); clk_register(c->lk.clk); -- GitLab From e9b98f6040f5a7a04d659759d83ea28d9c528800 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:57 -0700 Subject: [PATCH 1215/3892] OMAP clock: make the fixed divisor clock code available for all OMAPs One of the OMAP1 clocks can use the fixed divisor recalculation code introduced in the OMAP2 clock code, so rename the omap2_fixed_divisor_recalc() function to omap_fixed_divisor_recalc() and make it available to all OMAPs. A followup patch converts the OMAP1 clock. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.c | 11 ----------- arch/arm/mach-omap2/clock.h | 1 - arch/arm/mach-omap2/clock2xxx_data.c | 4 ++-- arch/arm/mach-omap2/clock34xx_data.c | 6 +++--- arch/arm/plat-omap/clock.c | 11 +++++++++++ arch/arm/plat-omap/include/plat/clock.h | 3 ++- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 759c72a48f7f..7565f8e40a0e 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -300,17 +300,6 @@ u32 omap2_get_dpll_rate(struct clk *clk) return dpll_clk; } -/* - * Used for clocks that have the same value as the parent clock, - * divided by some factor - */ -unsigned long omap2_fixed_divisor_recalc(struct clk *clk) -{ - WARN_ON(!clk->fixed_div); - - return clk->parent->rate / clk->fixed_div; -} - /** * omap2_clk_dflt_find_companion - find companion clock to @clk * @clk: struct clk * to find the companion clock of diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 93c48df3b5b1..0d70dc09370b 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -78,7 +78,6 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, u32 *new_div); u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val); u32 omap2_divisor_to_clksel(struct clk *clk, u32 div); -unsigned long omap2_fixed_divisor_recalc(struct clk *clk); long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); u32 omap2_get_dpll_rate(struct clk *clk); diff --git a/arch/arm/mach-omap2/clock2xxx_data.c b/arch/arm/mach-omap2/clock2xxx_data.c index 97dc7cf7751d..402115fa9c12 100644 --- a/arch/arm/mach-omap2/clock2xxx_data.c +++ b/arch/arm/mach-omap2/clock2xxx_data.c @@ -261,7 +261,7 @@ static struct clk func_12m_ck = { .parent = &func_48m_ck, .fixed_div = 4, .clkdm_name = "wkup_clkdm", - .recalc = &omap2_fixed_divisor_recalc, + .recalc = &omap_fixed_divisor_recalc, }; /* Secure timer, only available in secure mode */ @@ -557,7 +557,7 @@ static struct clk iva1_mpu_int_ifck = { .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN), .enable_bit = OMAP2420_EN_IVA_MPU_SHIFT, .fixed_div = 2, - .recalc = &omap2_fixed_divisor_recalc, + .recalc = &omap_fixed_divisor_recalc, }; /* diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c index cbb421a45763..9e7f68a8fca2 100644 --- a/arch/arm/mach-omap2/clock34xx_data.c +++ b/arch/arm/mach-omap2/clock34xx_data.c @@ -735,7 +735,7 @@ static struct clk omap_12m_fck = { .ops = &clkops_null, .parent = &omap_48m_fck, .fixed_div = 4, - .recalc = &omap2_fixed_divisor_recalc, + .recalc = &omap_fixed_divisor_recalc, }; /* This virstual clock is the source for dpll4_m4x2_ck */ @@ -1588,7 +1588,7 @@ static struct clk ssi_sst_fck_3430es1 = { .ops = &clkops_null, .parent = &ssi_ssr_fck_3430es1, .fixed_div = 2, - .recalc = &omap2_fixed_divisor_recalc, + .recalc = &omap_fixed_divisor_recalc, }; static struct clk ssi_sst_fck_3430es2 = { @@ -1596,7 +1596,7 @@ static struct clk ssi_sst_fck_3430es2 = { .ops = &clkops_null, .parent = &ssi_ssr_fck_3430es2, .fixed_div = 2, - .recalc = &omap2_fixed_divisor_recalc, + .recalc = &omap_fixed_divisor_recalc, }; diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index d9f8c844c385..e0f72f48b8b1 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -199,6 +199,17 @@ unsigned long followparent_recalc(struct clk *clk) return clk->parent->rate; } +/* + * Used for clocks that have the same value as the parent clock, + * divided by some factor + */ +unsigned long omap_fixed_divisor_recalc(struct clk *clk) +{ + WARN_ON(!clk->fixed_div); + + return clk->parent->rate / clk->fixed_div; +} + void clk_reparent(struct clk *child, struct clk *parent) { list_del_init(&child->sibling); diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 94fe2a0ce40a..896cedc923a7 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -88,9 +88,9 @@ struct clk { void (*init)(struct clk *); __u8 enable_bit; __s8 usecount; + u8 fixed_div; #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) - u8 fixed_div; void __iomem *clksel_reg; u32 clksel_mask; const struct clksel *clksel; @@ -134,6 +134,7 @@ extern void propagate_rate(struct clk *clk); extern void recalculate_root_clocks(void); extern unsigned long followparent_recalc(struct clk *clk); extern void clk_enable_init_clocks(void); +unsigned long omap_fixed_divisor_recalc(struct clk *clk); #ifdef CONFIG_CPU_FREQ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); -- GitLab From 0dfc242ff05fcc4bbef1e1bf4eed6f7d01e0cb44 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:57 -0700 Subject: [PATCH 1216/3892] OMAP1 clock: convert armwdt_ck to use the fixed divisor recalc function The armwdt_ck clock uses a fixed divisor, so it can use the OMAP clock fixed divisor recalculation code, rather than a custom function. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap1/clock.c | 6 ------ arch/arm/mach-omap1/clock_data.c | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 04f1d29cba2c..3e052f6532b1 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -52,12 +52,6 @@ const struct clkops clkops_dummy = { .disable = clk_omap1_dummy_disable, }; -/* XXX can be replaced with a fixed_divisor_recalc */ -unsigned long omap1_watchdog_recalc(struct clk *clk) -{ - return clk->parent->rate / 14; -} - unsigned long omap1_uart_recalc(struct clk *clk) { unsigned int val = __raw_readl(clk->enable_reg); diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c index 65e7b5b85d83..edefb3440d30 100644 --- a/arch/arm/mach-omap1/clock_data.c +++ b/arch/arm/mach-omap1/clock_data.c @@ -149,7 +149,8 @@ static struct arm_idlect1_clk armwdt_ck = { .flags = CLOCK_IDLE_CONTROL, .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2), .enable_bit = EN_WDTCK, - .recalc = &omap1_watchdog_recalc, + .fixed_div = 14, + .recalc = &omap_fixed_divisor_recalc, }, .idlect_shift = 0, }; -- GitLab From bf9854010692d7fbb4c21817c66270b40db55a3b Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:58 -0700 Subject: [PATCH 1217/3892] ARM: OMAP4 clock framework: Remove the checks preventing OMAP4 clockdomain validation The clockdomain related code being in place, it is not necessary to have some part of the clock code commented out. This would help the validation of the clockdomain functions using the clock level interfaces. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.c | 8 -------- arch/arm/mach-omap2/clock44xx_data.c | 2 -- 2 files changed, 10 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 7565f8e40a0e..d88b25565a42 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -181,7 +181,6 @@ static int _dpll_test_fint(struct clk *clk, u8 n) * clockdomain pointer, and save it into the struct clk. Intended to be * called during clk_register(). No return value. */ -#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdm f/w is in place */ void omap2_init_clk_clkdm(struct clk *clk) { struct clockdomain *clkdm; @@ -199,7 +198,6 @@ void omap2_init_clk_clkdm(struct clk *clk) "clkdm %s\n", clk->name, clk->clkdm_name); } } -#endif /** * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware @@ -465,10 +463,8 @@ void omap2_clk_disable(struct clk *clk) _omap2_clk_disable(clk); if (clk->parent) omap2_clk_disable(clk->parent); -#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdm f/w is in place */ if (clk->clkdm) omap2_clkdm_clk_disable(clk->clkdm, clk); -#endif } } @@ -478,10 +474,8 @@ int omap2_clk_enable(struct clk *clk) int ret = 0; if (clk->usecount++ == 0) { -#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdm f/w is in place */ if (clk->clkdm) omap2_clkdm_clk_enable(clk->clkdm, clk); -#endif if (clk->parent) { ret = omap2_clk_enable(clk->parent); @@ -500,10 +494,8 @@ int omap2_clk_enable(struct clk *clk) return ret; err: -#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdm f/w is in place */ if (clk->clkdm) omap2_clkdm_clk_disable(clk->clkdm, clk); -#endif clk->usecount--; return ret; } diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 9d882bcb56e3..ae9649f2973d 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -2749,9 +2749,7 @@ int __init omap2_clk_init(void) if (c->cpu & cpu_clkflg) { clkdev_add(&c->lk); clk_register(c->lk.clk); - /* TODO omap2_init_clk_clkdm(c->lk.clk); - */ } recalculate_root_clocks(); -- GitLab From 6b04e0d99d4113ede24e263e3df246a17f490339 Mon Sep 17 00:00:00 2001 From: Abhijit Pagare Date: Tue, 26 Jan 2010 20:12:58 -0700 Subject: [PATCH 1218/3892] ARM: OMAP4 clock domains : Add the missing Clock Domain Structure One of the clock domains was missing from the auto-generated file. It has been added here. Signed-off-by: Abhijit Pagare Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clockdomains.h | 1 + arch/arm/mach-omap2/clockdomains44xx.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index f985e0a15c4b..6dc5ddc9a3a4 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -461,6 +461,7 @@ static struct clockdomain *clockdomains_omap[] = { &l4_secure_44xx_clkdm, &l4_per_44xx_clkdm, &abe_44xx_clkdm, + &l3_instr_44xx_clkdm, &l3_init_44xx_clkdm, &mpuss_44xx_clkdm, &mpu0_44xx_clkdm, diff --git a/arch/arm/mach-omap2/clockdomains44xx.h b/arch/arm/mach-omap2/clockdomains44xx.h index 6fc55e4ed2b5..438aaee2e392 100644 --- a/arch/arm/mach-omap2/clockdomains44xx.h +++ b/arch/arm/mach-omap2/clockdomains44xx.h @@ -102,6 +102,14 @@ static struct clockdomain abe_44xx_clkdm = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), }; +static struct clockdomain l3_instr_44xx_clkdm = { + .name = "l3_instr_clkdm", + .pwrdm = { .name = "core_pwrdm" }, + .clkstctrl_reg = OMAP4430_CM_L3INSTR_CLKSTCTRL, + .clktrctrl_mask = OMAP4430_CLKTRCTRL_MASK, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), +}; + static struct clockdomain l3_init_44xx_clkdm = { .name = "l3_init_clkdm", .pwrdm = { .name = "l3init_pwrdm" }, -- GitLab From 55ed96945b1f3d0f4ad21a27b32ce4bd99d8c268 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:59 -0700 Subject: [PATCH 1219/3892] OMAP2/3 clkdm/pwrdm: move wkdep/sleepdep handling from pwrdm to clkdm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move clockdomain wakeup dependency and sleep dependency data structures from the powerdomain layer to the clockdomain layer, where they belong. These dependencies were originally placed in the powerdomain layer due to unclear documentation; however, it is clear now that these dependencies are between clockdomains. For OMAP2/3, this is not such a big problem, but for OMAP4 this needs to be fixed. Thanks to Benoît Cousson for his advice on this patch. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/clockdomain.c | 368 ++++++++++++++--- arch/arm/mach-omap2/clockdomains.h | 378 +++++++++++++++++- arch/arm/mach-omap2/io.c | 2 +- arch/arm/mach-omap2/omap_hwmod.c | 10 +- arch/arm/mach-omap2/pm34xx.c | 10 +- arch/arm/mach-omap2/powerdomain.c | 259 +----------- arch/arm/mach-omap2/powerdomains.h | 88 +--- arch/arm/mach-omap2/powerdomains24xx.h | 87 +--- arch/arm/mach-omap2/powerdomains34xx.h | 145 +------ arch/arm/mach-omap2/prcm.c | 12 + arch/arm/plat-omap/include/plat/clockdomain.h | 50 ++- arch/arm/plat-omap/include/plat/powerdomain.h | 34 +- arch/arm/plat-omap/include/plat/prcm.h | 8 + 13 files changed, 761 insertions(+), 690 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 8c9e78c2c17f..a70ba29f66cc 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -27,14 +27,14 @@ #include -#include - #include "prm.h" #include "prm-regbits-24xx.h" #include "cm.h" +#include #include #include +#include /* clkdm_list contains all registered struct clockdomains */ static LIST_HEAD(clkdm_list); @@ -42,28 +42,75 @@ static LIST_HEAD(clkdm_list); /* clkdm_mutex protects clkdm_list add and del ops */ static DEFINE_MUTEX(clkdm_mutex); -/* array of powerdomain deps to be added/removed when clkdm in hwsup mode */ -static struct clkdm_pwrdm_autodep *autodeps; +/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ +static struct clkdm_autodep *autodeps; /* Private functions */ +static struct clockdomain *_clkdm_lookup(const char *name) +{ + struct clockdomain *clkdm, *temp_clkdm; + + if (!name) + return NULL; + + clkdm = NULL; + + list_for_each_entry(temp_clkdm, &clkdm_list, node) { + if (!strcmp(name, temp_clkdm->name)) { + clkdm = temp_clkdm; + break; + } + } + + return clkdm; +} + +/* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */ +static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, + struct clkdm_dep *deps) +{ + struct clkdm_dep *cd; + + if (!clkdm || !deps || !omap_chip_is(clkdm->omap_chip)) + return ERR_PTR(-EINVAL); + + for (cd = deps; cd->clkdm_name; cd++) { + + if (!omap_chip_is(cd->omap_chip)) + continue; + + if (!cd->clkdm && cd->clkdm_name) + cd->clkdm = _clkdm_lookup(cd->clkdm_name); + + if (cd->clkdm == clkdm) + break; + + } + + if (!cd->clkdm_name) + return ERR_PTR(-ENOENT); + + return cd; +} + /* - * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store - * @autodep: struct clkdm_pwrdm_autodep * to resolve + * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store + * @autodep: struct clkdm_autodep * to resolve * - * Resolve autodep powerdomain names to powerdomain pointers via - * pwrdm_lookup() and store the pointers in the autodep structure. An - * "autodep" is a powerdomain sleep/wakeup dependency that is + * Resolve autodep clockdomain names to clockdomain pointers via + * clkdm_lookup() and store the pointers in the autodep structure. An + * "autodep" is a clockdomain sleep/wakeup dependency that is * automatically added and removed whenever clocks in the associated * clockdomain are enabled or disabled (respectively) when the * clockdomain is in hardware-supervised mode. Meant to be called * once at clockdomain layer initialization, since these should remain * fixed for a particular architecture. No return value. */ -static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep) +static void _autodep_lookup(struct clkdm_autodep *autodep) { - struct powerdomain *pwrdm; + struct clockdomain *clkdm; if (!autodep) return; @@ -71,13 +118,13 @@ static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep) if (!omap_chip_is(autodep->omap_chip)) return; - pwrdm = pwrdm_lookup(autodep->pwrdm.name); - if (!pwrdm) { - pr_err("clockdomain: autodeps: powerdomain %s does not exist\n", - autodep->pwrdm.name); - pwrdm = ERR_PTR(-ENOENT); + clkdm = clkdm_lookup(autodep->clkdm.name); + if (!clkdm) { + pr_err("clockdomain: autodeps: clockdomain %s does not exist\n", + autodep->clkdm.name); + clkdm = ERR_PTR(-ENOENT); } - autodep->pwrdm.ptr = pwrdm; + autodep->clkdm.ptr = clkdm; } /* @@ -90,21 +137,21 @@ static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep) */ static void _clkdm_add_autodeps(struct clockdomain *clkdm) { - struct clkdm_pwrdm_autodep *autodep; + struct clkdm_autodep *autodep; - for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) { - if (IS_ERR(autodep->pwrdm.ptr)) + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) continue; if (!omap_chip_is(autodep->omap_chip)) continue; pr_debug("clockdomain: adding %s sleepdep/wkdep for " - "pwrdm %s\n", autodep->pwrdm.ptr->name, - clkdm->pwrdm.ptr->name); + "clkdm %s\n", autodep->clkdm.ptr->name, + clkdm->name); - pwrdm_add_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr); - pwrdm_add_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr); + clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); + clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); } } @@ -118,21 +165,21 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm) */ static void _clkdm_del_autodeps(struct clockdomain *clkdm) { - struct clkdm_pwrdm_autodep *autodep; + struct clkdm_autodep *autodep; - for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) { - if (IS_ERR(autodep->pwrdm.ptr)) + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) continue; if (!omap_chip_is(autodep->omap_chip)) continue; pr_debug("clockdomain: removing %s sleepdep/wkdep for " - "pwrdm %s\n", autodep->pwrdm.ptr->name, - clkdm->pwrdm.ptr->name); + "clkdm %s\n", autodep->clkdm.ptr->name, + clkdm->name); - pwrdm_del_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr); - pwrdm_del_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr); + clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); + clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); } } @@ -171,25 +218,6 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) } -static struct clockdomain *_clkdm_lookup(const char *name) -{ - struct clockdomain *clkdm, *temp_clkdm; - - if (!name) - return NULL; - - clkdm = NULL; - - list_for_each_entry(temp_clkdm, &clkdm_list, node) { - if (!strcmp(name, temp_clkdm->name)) { - clkdm = temp_clkdm; - break; - } - } - - return clkdm; -} - /* Public functions */ @@ -200,26 +228,24 @@ static struct clockdomain *_clkdm_lookup(const char *name) * * Set up internal state. If a pointer to an array of clockdomains * was supplied, loop through the list of clockdomains, register all - * that are available on the current platform. Similarly, if a - * pointer to an array of clockdomain-powerdomain autodependencies was - * provided, register those. No return value. + * that are available on the current platform. Similarly, if a pointer + * to an array of clockdomain autodependencies was provided, register + * those. No return value. */ void clkdm_init(struct clockdomain **clkdms, - struct clkdm_pwrdm_autodep *init_autodeps) + struct clkdm_autodep *init_autodeps) { struct clockdomain **c = NULL; - struct clkdm_pwrdm_autodep *autodep = NULL; + struct clkdm_autodep *autodep = NULL; if (clkdms) for (c = clkdms; *c; c++) clkdm_register(*c); - if (!cpu_is_omap44xx()) { - autodeps = init_autodeps; - if (autodeps) - for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) - _autodep_lookup(autodep); - } + autodeps = init_autodeps; + if (autodeps) + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) + _autodep_lookup(autodep); } /** @@ -373,6 +399,226 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) /* Hardware clockdomain control */ +/** + * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 + * @clkdm1: wake this struct clockdomain * up (dependent) + * @clkdm2: when this struct clockdomain * wakes up (source) + * + * When the clockdomain represented by @clkdm2 wakes up, wake up + * @clkdm1. Implemented in hardware on the OMAP, this feature is + * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. + * Returns -EINVAL if presented with invalid clockdomain pointers, + * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon + * success. + */ +int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear wake up of " + "%s when %s wakes up\n", clkdm1->name, clkdm2->name); + return PTR_ERR(cd); + } + + pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + + prm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + + return 0; +} + +/** + * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1 + * @clkdm1: wake this struct clockdomain * up (dependent) + * @clkdm2: when this struct clockdomain * wakes up (source) + * + * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 + * wakes up. Returns -EINVAL if presented with invalid clockdomain + * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or + * 0 upon success. + */ +int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear wake up of " + "%s when %s wakes up\n", clkdm1->name, clkdm2->name); + return PTR_ERR(cd); + } + + pr_debug("clockdomain: hardware will no longer wake up %s after %s " + "wakes up\n", clkdm1->name, clkdm2->name); + + prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + + return 0; +} + +/** + * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1 + * @clkdm1: wake this struct clockdomain * up (dependent) + * @clkdm2: when this struct clockdomain * wakes up (source) + * + * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be + * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL + * if either clockdomain pointer is invalid; or -ENOENT if the hardware + * is incapable. + * + * REVISIT: Currently this function only represents software-controllable + * wakeup dependencies. Wakeup dependencies fixed in hardware are not + * yet handled here. + */ +int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear wake up of " + "%s when %s wakes up\n", clkdm1->name, clkdm2->name); + return PTR_ERR(cd); + } + + return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, + (1 << clkdm2->dep_bit)); +} + +/** + * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 + * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) + * @clkdm2: when this struct clockdomain * is active (source) + * + * Prevent @clkdm1 from automatically going inactive (and then to + * retention or off) if @clkdm2 is active. Returns -EINVAL if + * presented with invalid clockdomain pointers or called on a machine + * that does not support software-configurable hardware sleep + * dependencies, -ENOENT if the specified dependency cannot be set in + * hardware, or 0 upon success. + */ +int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!cpu_is_omap34xx()) + return -EINVAL; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear sleep " + "dependency affecting %s from %s\n", clkdm1->name, + clkdm2->name); + return PTR_ERR(cd); + } + + pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", + clkdm1->name, clkdm2->name); + + cm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + + return 0; +} + +/** + * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1 + * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) + * @clkdm2: when this struct clockdomain * is active (source) + * + * Allow @clkdm1 to automatically go inactive (and then to retention or + * off), independent of the activity state of @clkdm2. Returns -EINVAL + * if presented with invalid clockdomain pointers or called on a machine + * that does not support software-configurable hardware sleep dependencies, + * -ENOENT if the specified dependency cannot be cleared in hardware, or + * 0 upon success. + */ +int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!cpu_is_omap34xx()) + return -EINVAL; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear sleep " + "dependency affecting %s from %s\n", clkdm1->name, + clkdm2->name); + return PTR_ERR(cd); + } + + pr_debug("clockdomain: will no longer prevent %s from sleeping if " + "%s is active\n", clkdm1->name, clkdm2->name); + + cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + + return 0; +} + +/** + * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1 + * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) + * @clkdm2: when this struct clockdomain * is active (source) + * + * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will + * not be allowed to automatically go inactive if @clkdm2 is active; + * 0 if @clkdm1's automatic power state inactivity transition is independent + * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called + * on a machine that does not support software-configurable hardware sleep + * dependencies; or -ENOENT if the hardware is incapable. + * + * REVISIT: Currently this function only represents software-controllable + * sleep dependencies. Sleep dependencies fixed in hardware are not + * yet handled here. + */ +int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + + if (!cpu_is_omap34xx()) + return -EINVAL; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); + if (IS_ERR(cd)) { + pr_debug("clockdomain: hardware cannot set/clear sleep " + "dependency affecting %s from %s\n", clkdm1->name, + clkdm2->name); + return PTR_ERR(cd); + } + + return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP, + (1 << clkdm2->dep_bit)); +} + + /** * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode * @clk: struct clk * of a clockdomain diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 6dc5ddc9a3a4..ff216f24f1a0 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -2,9 +2,28 @@ * OMAP2/3 clockdomains * * Copyright (C) 2008 Texas Instruments, Inc. - * Copyright (C) 2008 Nokia Corporation + * Copyright (C) 2008-2009 Nokia Corporation * - * Written by Paul Walmsley + * Written by Paul Walmsley and Jouni Högander + * + * This file contains clockdomains and clockdomain wakeup/sleep + * dependencies for the OMAP2/3 chips. Some notes: + * + * A useful validation rule for struct clockdomain: Any clockdomain + * referenced by a wkdep_srcs or sleepdep_srcs array must have a + * dep_bit assigned. So wkdep_srcs/sleepdep_srcs are really just + * software-controllable dependencies. Non-software-controllable + * dependencies do exist, but they are not encoded below (yet). + * + * 24xx does not support programmable sleep dependencies (SLEEPDEP) + * + * The overly-specific dep_bit names are due to a bit name collision + * with CM_FCLKEN_{DSP,IVA2}. The DSP/IVA2 PM_WKDEP and CM_SLEEPDEP shift + * value are the same for all powerdomains: 2 + * + * XXX should dep_bit be a mask, so we can test to see if it is 0 as a + * sanity check? + * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE */ /* @@ -20,6 +39,287 @@ #include "cm.h" #include "prm.h" +/* + * Clockdomain dependencies for wkdeps/sleepdeps + * + * XXX Hardware dependencies (e.g., dependencies that cannot be + * changed in software) are not included here yet, but should be. + */ + +/* OMAP2/3-common wakeup dependencies */ + +/* + * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP + * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE + * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE + */ +static struct clkdm_dep gfx_sgx_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | + CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | + CHIP_IS_OMAP3430) + }, + { NULL }, +}; + + +/* 24XX-specific possible dependencies */ + +#ifdef CONFIG_ARCH_OMAP24XX + +/* Wakeup dependency source arrays */ + +/* + * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP + * 2420/2430 PM_WKDEP_MDM: same as DSP + */ +static struct clkdm_dep dsp_mdm_24xx_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { NULL }, +}; + +/* + * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP + * 2430 adds MDM + */ +static struct clkdm_dep mpu_24xx_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "dsp_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "mdm_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) + }, + { NULL }, +}; + +/* + * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP + * 2430 adds MDM + */ +static struct clkdm_dep core_24xx_wkdeps[] = { + { + .clkdm_name = "dsp_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "gfx_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "mdm_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) + }, + { NULL }, +}; + +#endif + +/* 34XX-specific possible dependencies */ + +#ifdef CONFIG_ARCH_OMAP34XX + +/* + * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP + * (USBHOST is ES2 only) + */ +static struct clkdm_dep per_usbhost_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* + * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER + */ +static struct clkdm_dep mpu_34xx_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "dss_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "per_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* + * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER + */ +static struct clkdm_dep iva2_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "dss_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "per_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + + +/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */ +static struct clkdm_dep cam_dss_wkdeps[] = { + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* 3430: PM_WKDEP_NEON: MPU */ +static struct clkdm_dep neon_wkdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + + +/* Sleep dependency source arrays for 34xx-specific clkdms - 34XX only */ + +/* + * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA + * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA + */ +static struct clkdm_dep dss_per_usbhost_sleepdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* + * 3430: CM_SLEEPDEP_CAM: MPU + * 3430ES1: CM_SLEEPDEP_GFX: MPU + * 3430ES2: CM_SLEEPDEP_SGX: MPU + */ +static struct clkdm_dep cam_gfx_sleepdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +#endif /* CONFIG_ARCH_OMAP34XX */ + + /* * OMAP2/3-common clockdomains * @@ -35,6 +335,7 @@ static struct clockdomain wkup_clkdm = { .name = "wkup_clkdm", .pwrdm = { .name = "wkup_pwrdm" }, + .dep_bit = OMAP_EN_WKUP_SHIFT, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430), }; @@ -63,6 +364,7 @@ static struct clockdomain mpu_2420_clkdm = { .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP2420_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = mpu_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -73,6 +375,8 @@ static struct clockdomain iva1_2420_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2420_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT, + .wkdep_srcs = dsp_mdm_24xx_wkdeps, .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -92,6 +396,7 @@ static struct clockdomain gfx_2420_clkdm = { .pwrdm = { .name = "gfx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2420_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = gfx_sgx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -101,6 +406,7 @@ static struct clockdomain core_l3_2420_clkdm = { .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP2420_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = core_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -110,6 +416,7 @@ static struct clockdomain core_l4_2420_clkdm = { .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP2420_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = core_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -138,16 +445,20 @@ static struct clockdomain mpu_2430_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = mpu_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; +/* Another case of bit name collisions between several registers: EN_MDM */ static struct clockdomain mdm_clkdm = { .name = "mdm_clkdm", .pwrdm = { .name = "mdm_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP2430_MDM_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT, + .wkdep_srcs = dsp_mdm_24xx_wkdeps, .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -158,6 +469,8 @@ static struct clockdomain dsp_2430_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT, + .wkdep_srcs = dsp_mdm_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -167,24 +480,39 @@ static struct clockdomain gfx_2430_clkdm = { .pwrdm = { .name = "gfx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = gfx_sgx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; +/* + * XXX add usecounting for clkdm dependencies, otherwise the presence + * of a single dep bit for core_l3_24xx_clkdm and core_l4_24xx_clkdm + * could cause trouble + */ static struct clockdomain core_l3_2430_clkdm = { .name = "core_l3_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP24XX_EN_CORE_SHIFT, + .wkdep_srcs = core_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; +/* + * XXX add usecounting for clkdm dependencies, otherwise the presence + * of a single dep bit for core_l3_24xx_clkdm and core_l4_24xx_clkdm + * could cause trouble + */ static struct clockdomain core_l4_2430_clkdm = { .name = "core_l4_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP2430_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP24XX_EN_CORE_SHIFT, + .wkdep_srcs = core_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -212,6 +540,8 @@ static struct clockdomain mpu_34xx_clkdm = { .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_EN_MPU_SHIFT, + .wkdep_srcs = mpu_34xx_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -222,6 +552,7 @@ static struct clockdomain neon_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_NEON_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = neon_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_NEON_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -232,6 +563,8 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, + .wkdep_srcs = iva2_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -241,6 +574,8 @@ static struct clockdomain gfx_3430es1_clkdm = { .pwrdm = { .name = "gfx_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = gfx_sgx_wkdeps, + .sleepdep_srcs = cam_gfx_sleepdeps, .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1), }; @@ -251,6 +586,8 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_SGX_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = gfx_sgx_wkdeps, + .sleepdep_srcs = cam_gfx_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -271,30 +608,46 @@ static struct clockdomain d2d_clkdm = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; +/* + * XXX add usecounting for clkdm dependencies, otherwise the presence + * of a single dep bit for core_l3_34xx_clkdm and core_l4_34xx_clkdm + * could cause trouble + */ static struct clockdomain core_l3_34xx_clkdm = { .name = "core_l3_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_EN_CORE_SHIFT, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; +/* + * XXX add usecounting for clkdm dependencies, otherwise the presence + * of a single dep bit for core_l3_34xx_clkdm and core_l4_34xx_clkdm + * could cause trouble + */ static struct clockdomain core_l4_34xx_clkdm = { .name = "core_l4_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(CORE_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_EN_CORE_SHIFT, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L4_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; +/* Another case of bit name collisions between several registers: EN_DSS */ static struct clockdomain dss_34xx_clkdm = { .name = "dss_clkdm", .pwrdm = { .name = "dss_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT, + .wkdep_srcs = cam_dss_wkdeps, + .sleepdep_srcs = dss_per_usbhost_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -305,6 +658,8 @@ static struct clockdomain cam_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = cam_dss_wkdeps, + .sleepdep_srcs = cam_gfx_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -315,6 +670,8 @@ static struct clockdomain usbhost_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL), + .wkdep_srcs = per_usbhost_wkdeps, + .sleepdep_srcs = dss_per_usbhost_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -325,6 +682,9 @@ static struct clockdomain per_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL), + .dep_bit = OMAP3430_EN_PER_SHIFT, + .wkdep_srcs = per_usbhost_wkdeps, + .sleepdep_srcs = dss_per_usbhost_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -378,25 +738,21 @@ static struct clockdomain dpll5_clkdm = { #include "clockdomains44xx.h" /* - * Clockdomain-powerdomain hwsup dependencies (34XX only) + * Clockdomain hwsup dependencies (34XX only) */ -static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = { - -#ifdef CONFIG_ARCH_OMAP34XX +static struct clkdm_autodep clkdm_autodeps[] = { { - .pwrdm = { .name = "mpu_pwrdm" }, + .clkdm = { .name = "mpu_clkdm" }, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) }, { - .pwrdm = { .name = "iva2_pwrdm" }, + .clkdm = { .name = "iva2_clkdm" }, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) }, { - .pwrdm = { .name = NULL }, + .clkdm = { .name = NULL }, } -#endif - }; /* diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 51d7453f406d..8c58699083f6 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -313,7 +313,7 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, hwmods = omap34xx_hwmods; pwrdm_init(powerdomains_omap); - clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); + clkdm_init(clockdomains_omap, clkdm_autodeps); #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ /* The OPP tables have to be registered before a clk init */ omap_hwmod_init(hwmods); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 478ae585ca39..ad884c0aaa42 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -299,15 +299,14 @@ static int _disable_wakeup(struct omap_hwmod *oh) * be accessed by the IVA, there should be a sleepdep between the IVA * initiator and the module). Only applies to modules in smart-idle * mode. Returns -EINVAL upon error or passes along - * pwrdm_add_sleepdep() value upon success. + * clkdm_add_sleepdep() value upon success. */ static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) { if (!oh->_clk) return -EINVAL; - return pwrdm_add_sleepdep(oh->_clk->clkdm->pwrdm.ptr, - init_oh->_clk->clkdm->pwrdm.ptr); + return clkdm_add_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); } /** @@ -320,15 +319,14 @@ static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) * be accessed by the IVA, there should be no sleepdep between the IVA * initiator and the module). Only applies to modules in smart-idle * mode. Returns -EINVAL upon error or passes along - * pwrdm_add_sleepdep() value upon success. + * clkdm_del_sleepdep() value upon success. */ static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) { if (!oh->_clk) return -EINVAL; - return pwrdm_del_sleepdep(oh->_clk->clkdm->pwrdm.ptr, - init_oh->_clk->clkdm->pwrdm.ptr); + return clkdm_del_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); } /** diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index f841a6e33611..5f59df87abf7 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -1018,6 +1018,7 @@ void omap_push_sram_idle(void) static int __init omap3_pm_init(void) { struct power_state *pwrst, *tmp; + struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; int ret; if (!cpu_is_omap34xx()) @@ -1057,6 +1058,11 @@ static int __init omap3_pm_init(void) core_pwrdm = pwrdm_lookup("core_pwrdm"); cam_pwrdm = pwrdm_lookup("cam_pwrdm"); + neon_clkdm = clkdm_lookup("neon_clkdm"); + mpu_clkdm = clkdm_lookup("mpu_clkdm"); + per_clkdm = clkdm_lookup("per_clkdm"); + core_clkdm = clkdm_lookup("core_clkdm"); + omap_push_sram_idle(); #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); @@ -1065,14 +1071,14 @@ static int __init omap3_pm_init(void) pm_idle = omap3_pm_idle; omap3_idle_init(); - pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); + clkdm_add_wkdep(neon_clkdm, mpu_clkdm); /* * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for * IO-pad wakeup. Otherwise it will unnecessarily waste power * waking up PER with every CORE wakeup - see * http://marc.info/?l=linux-omap&m=121852150710062&w=2 */ - pwrdm_add_wkdep(per_pwrdm, core_pwrdm); + clkdm_add_wkdep(per_clkdm, core_clkdm); if (omap_type() != OMAP2_DEVICE_TYPE_GP) { omap3_secure_ram_storage = diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index c0de05097b5d..e8e8d8872a0e 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -2,7 +2,7 @@ * OMAP powerdomain control * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * @@ -36,6 +36,7 @@ #include #include #include +#include #include "pm.h" @@ -88,17 +89,6 @@ static DEFINE_RWLOCK(pwrdm_rwlock); /* Private functions */ -static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) -{ - u32 v; - - v = prm_read_mod_reg(domain, idx); - v &= mask; - v >>= __ffs(mask); - - return v; -} - static struct powerdomain *_pwrdm_lookup(const char *name) { struct powerdomain *pwrdm, *temp_pwrdm; @@ -115,34 +105,6 @@ static struct powerdomain *_pwrdm_lookup(const char *name) return pwrdm; } -/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */ -static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, - struct pwrdm_dep *deps) -{ - struct pwrdm_dep *pd; - - if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip)) - return ERR_PTR(-EINVAL); - - for (pd = deps; pd->pwrdm_name; pd++) { - - if (!omap_chip_is(pd->omap_chip)) - continue; - - if (!pd->pwrdm && pd->pwrdm_name) - pd->pwrdm = pwrdm_lookup(pd->pwrdm_name); - - if (pd->pwrdm == pwrdm) - break; - - } - - if (!pd->pwrdm_name) - return ERR_PTR(-ENOENT); - - return pd->pwrdm; -} - static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { @@ -502,223 +464,6 @@ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, return ret; } - -/** - * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1 - * @pwrdm1: wake this struct powerdomain * up (dependent) - * @pwrdm2: when this struct powerdomain * wakes up (source) - * - * When the powerdomain represented by pwrdm2 wakes up (due to an - * interrupt), wake up pwrdm1. Implemented in hardware on the OMAP, - * this feature is designed to reduce wakeup latency of the dependent - * powerdomain. Returns -EINVAL if presented with invalid powerdomain - * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or - * 0 upon success. - */ -int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear wake up of " - "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name); - return PTR_ERR(p); - } - - pr_debug("powerdomain: hardware will wake up %s when %s wakes up\n", - pwrdm1->name, pwrdm2->name); - - prm_set_mod_reg_bits((1 << pwrdm2->dep_bit), - pwrdm1->prcm_offs, PM_WKDEP); - - return 0; -} - -/** - * pwrdm_del_wkdep - remove a wakeup dependency from pwrdm2 to pwrdm1 - * @pwrdm1: wake this struct powerdomain * up (dependent) - * @pwrdm2: when this struct powerdomain * wakes up (source) - * - * Remove a wakeup dependency that causes pwrdm1 to wake up when pwrdm2 - * wakes up. Returns -EINVAL if presented with invalid powerdomain - * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or - * 0 upon success. - */ -int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear wake up of " - "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name); - return PTR_ERR(p); - } - - pr_debug("powerdomain: hardware will no longer wake up %s after %s " - "wakes up\n", pwrdm1->name, pwrdm2->name); - - prm_clear_mod_reg_bits((1 << pwrdm2->dep_bit), - pwrdm1->prcm_offs, PM_WKDEP); - - return 0; -} - -/** - * pwrdm_read_wkdep - read wakeup dependency state from pwrdm2 to pwrdm1 - * @pwrdm1: wake this struct powerdomain * up (dependent) - * @pwrdm2: when this struct powerdomain * wakes up (source) - * - * Return 1 if a hardware wakeup dependency exists wherein pwrdm1 will be - * awoken when pwrdm2 wakes up; 0 if dependency is not set; -EINVAL - * if either powerdomain pointer is invalid; or -ENOENT if the hardware - * is incapable. - * - * REVISIT: Currently this function only represents software-controllable - * wakeup dependencies. Wakeup dependencies fixed in hardware are not - * yet handled here. - */ -int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear wake up of " - "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name); - return PTR_ERR(p); - } - - return prm_read_mod_bits_shift(pwrdm1->prcm_offs, PM_WKDEP, - (1 << pwrdm2->dep_bit)); -} - -/** - * pwrdm_add_sleepdep - add a sleep dependency from pwrdm2 to pwrdm1 - * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent) - * @pwrdm2: when this struct powerdomain * is active (source) - * - * Prevent pwrdm1 from automatically going inactive (and then to - * retention or off) if pwrdm2 is still active. Returns -EINVAL if - * presented with invalid powerdomain pointers or called on a machine - * that does not support software-configurable hardware sleep dependencies, - * -ENOENT if the specified dependency cannot be set in hardware, or - * 0 upon success. - */ -int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!cpu_is_omap34xx()) - return -EINVAL; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear sleep " - "dependency affecting %s from %s\n", pwrdm1->name, - pwrdm2->name); - return PTR_ERR(p); - } - - pr_debug("powerdomain: will prevent %s from sleeping if %s is active\n", - pwrdm1->name, pwrdm2->name); - - cm_set_mod_reg_bits((1 << pwrdm2->dep_bit), - pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP); - - return 0; -} - -/** - * pwrdm_del_sleepdep - remove a sleep dependency from pwrdm2 to pwrdm1 - * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent) - * @pwrdm2: when this struct powerdomain * is active (source) - * - * Allow pwrdm1 to automatically go inactive (and then to retention or - * off), independent of the activity state of pwrdm2. Returns -EINVAL - * if presented with invalid powerdomain pointers or called on a machine - * that does not support software-configurable hardware sleep dependencies, - * -ENOENT if the specified dependency cannot be cleared in hardware, or - * 0 upon success. - */ -int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!cpu_is_omap34xx()) - return -EINVAL; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear sleep " - "dependency affecting %s from %s\n", pwrdm1->name, - pwrdm2->name); - return PTR_ERR(p); - } - - pr_debug("powerdomain: will no longer prevent %s from sleeping if " - "%s is active\n", pwrdm1->name, pwrdm2->name); - - cm_clear_mod_reg_bits((1 << pwrdm2->dep_bit), - pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP); - - return 0; -} - -/** - * pwrdm_read_sleepdep - read sleep dependency state from pwrdm2 to pwrdm1 - * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent) - * @pwrdm2: when this struct powerdomain * is active (source) - * - * Return 1 if a hardware sleep dependency exists wherein pwrdm1 will - * not be allowed to automatically go inactive if pwrdm2 is active; - * 0 if pwrdm1's automatic power state inactivity transition is independent - * of pwrdm2's; -EINVAL if either powerdomain pointer is invalid or called - * on a machine that does not support software-configurable hardware sleep - * dependencies; or -ENOENT if the hardware is incapable. - * - * REVISIT: Currently this function only represents software-controllable - * sleep dependencies. Sleep dependencies fixed in hardware are not - * yet handled here. - */ -int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2) -{ - struct powerdomain *p; - - if (!cpu_is_omap34xx()) - return -EINVAL; - - if (!pwrdm1) - return -EINVAL; - - p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs); - if (IS_ERR(p)) { - pr_debug("powerdomain: hardware cannot set/clear sleep " - "dependency affecting %s from %s\n", pwrdm1->name, - pwrdm2->name); - return PTR_ERR(p); - } - - return prm_read_mod_bits_shift(pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP, - (1 << pwrdm2->dep_bit)); -} - /** * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain * @pwrdm: struct powerdomain * diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h index d646c9979c38..faa8fc952d95 100644 --- a/arch/arm/mach-omap2/powerdomains.h +++ b/arch/arm/mach-omap2/powerdomains.h @@ -1,8 +1,8 @@ /* * OMAP2/3 common powerdomain definitions * - * Copyright (C) 2007-8 Texas Instruments, Inc. - * Copyright (C) 2007-8 Nokia Corporation + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * Debugging and integration fixes by Jouni Högander @@ -25,19 +25,8 @@ * This file contains all of the powerdomains that have some element * of software control for the OMAP24xx and OMAP34XX chips. * - * A few notes: - * * This is not an exhaustive listing of powerdomains on the chips; only * powerdomains that can be controlled in software. - * - * A useful validation rule for struct powerdomain: - * Any powerdomain referenced by a wkdep_srcs or sleepdep_srcs array - * must have a dep_bit assigned. So wkdep_srcs/sleepdep_srcs are really - * just software-controllable dependencies. Non-software-controllable - * dependencies do exist, but they are not encoded below (yet). - * - * 24xx does not support programmable sleep dependencies (SLEEPDEP) - * */ /* @@ -47,26 +36,17 @@ * * On the 2420, this is a 'C55 DSP called, simply, the DSP. Its * powerdomain is called the "DSP power domain." On the 2430, the - * on-board DSP is a 'C64 DSP, now called the IVA2 or IVA2.1. Its - * powerdomain is still called the "DSP power domain." On the 3430, - * the DSP is a 'C64 DSP like the 2430, also known as the IVA2; but - * its powerdomain is now called the "IVA2 power domain." + * on-board DSP is a 'C64 DSP, now called (along with its hardware + * accelerators) the IVA2 or IVA2.1. Its powerdomain is still called + * the "DSP power domain." On the 3430, the DSP is a 'C64 DSP like the + * 2430, also known as the IVA2; but its powerdomain is now called the + * "IVA2 power domain." * * The 2420 also has something called the IVA, which is a separate ARM * core, and has nothing to do with the DSP/IVA2. * * Ideally the DSP/IVA2 could just be the same powerdomain, but the PRCM * address offset is different between the C55 and C64 DSPs. - * - * The overly-specific dep_bit names are due to a bit name collision - * with CM_FCLKEN_{DSP,IVA2}. The DSP/IVA2 PM_WKDEP and CM_SLEEPDEP shift - * value are the same for all powerdomains: 2 - */ - -/* - * XXX should dep_bit be a mask, so we can test to see if it is 0 as a - * sanity check? - * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE */ #include @@ -74,60 +54,11 @@ #include "prcm-common.h" #include "prm.h" #include "cm.h" - -/* OMAP2/3-common powerdomains and wakeup dependencies */ - -#ifndef CONFIG_ARCH_OMAP4 -/* - * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP - * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE - * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE - */ -static struct pwrdm_dep gfx_sgx_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "iva2_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | - CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | - CHIP_IS_OMAP3430) - }, - { NULL }, -}; - -/* - * 3430: CM_SLEEPDEP_CAM: MPU - * 3430ES1: CM_SLEEPDEP_GFX: MPU - * 3430ES2: CM_SLEEPDEP_SGX: MPU - */ -static struct pwrdm_dep cam_gfx_sleepdeps[] = { - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; -#endif - - #include "powerdomains24xx.h" #include "powerdomains34xx.h" #include "powerdomains44xx.h" - -/* - * OMAP2/3 common powerdomains - */ +/* OMAP2/3-common powerdomains */ #if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) @@ -140,8 +71,6 @@ static struct powerdomain gfx_omap2_pwrdm = { .prcm_offs = GFX_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430ES1), - .wkdep_srcs = gfx_sgx_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, .banks = 1, @@ -157,7 +86,6 @@ static struct powerdomain wkup_omap2_pwrdm = { .name = "wkup_pwrdm", .prcm_offs = WKUP_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430), - .dep_bit = OMAP_EN_WKUP_SHIFT, }; #endif diff --git a/arch/arm/mach-omap2/powerdomains24xx.h b/arch/arm/mach-omap2/powerdomains24xx.h index bd249a495aa9..652a01b729e9 100644 --- a/arch/arm/mach-omap2/powerdomains24xx.h +++ b/arch/arm/mach-omap2/powerdomains24xx.h @@ -2,7 +2,7 @@ * OMAP24XX powerdomain definitions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * Debugging and integration fixes by Jouni Högander @@ -32,90 +32,12 @@ #ifdef CONFIG_ARCH_OMAP24XX - -/* Wakeup dependency source arrays */ - -/* - * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP - * 2430 PM_WKDEP_MDM: same as above - */ -static struct pwrdm_dep dsp_mdm_24xx_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { NULL }, -}; - -/* - * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP - * 2430 adds MDM - */ -static struct pwrdm_dep mpu_24xx_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "dsp_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "mdm_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) - }, - { NULL }, -}; - -/* - * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP - * 2430 adds MDM - */ -static struct pwrdm_dep core_24xx_wkdeps[] = { - { - .pwrdm_name = "dsp_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "gfx_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) - }, - { - .pwrdm_name = "mdm_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) - }, - { NULL }, -}; - - /* Powerdomains */ static struct powerdomain dsp_pwrdm = { .name = "dsp_pwrdm", .prcm_offs = OMAP24XX_DSP_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), - .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT, - .wkdep_srcs = dsp_mdm_24xx_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, .banks = 1, @@ -131,8 +53,6 @@ static struct powerdomain mpu_24xx_pwrdm = { .name = "mpu_pwrdm", .prcm_offs = MPU_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), - .dep_bit = OMAP24XX_EN_MPU_SHIFT, - .wkdep_srcs = mpu_24xx_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 1, @@ -148,9 +68,7 @@ static struct powerdomain core_24xx_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX), - .wkdep_srcs = core_24xx_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, - .dep_bit = OMAP24XX_EN_CORE_SHIFT, .banks = 3, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ @@ -176,13 +94,10 @@ static struct powerdomain core_24xx_pwrdm = { /* XXX 2430 KILLDOMAINWKUP bit? No current users apparently */ -/* Another case of bit name collisions between several registers: EN_MDM */ static struct powerdomain mdm_pwrdm = { .name = "mdm_pwrdm", .prcm_offs = OMAP2430_MDM_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), - .dep_bit = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT, - .wkdep_srcs = dsp_mdm_24xx_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, .banks = 1, diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index 588f7e07d0ea..28228ef20e86 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -2,7 +2,7 @@ * OMAP34XX powerdomain definitions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * Debugging and integration fixes by Jouni Högander @@ -34,127 +34,6 @@ #ifdef CONFIG_ARCH_OMAP34XX -/* - * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP - * (USBHOST is ES2 only) - */ -static struct pwrdm_dep per_usbhost_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "iva2_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - -/* - * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER - */ -static struct pwrdm_dep mpu_34xx_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "iva2_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "dss_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "per_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - -/* - * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER - */ -static struct pwrdm_dep iva2_wkdeps[] = { - { - .pwrdm_name = "core_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "dss_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "per_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - - -/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */ -static struct pwrdm_dep cam_dss_wkdeps[] = { - { - .pwrdm_name = "iva2_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "wkup_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - -/* 3430: PM_WKDEP_NEON: MPU */ -static struct pwrdm_dep neon_wkdeps[] = { - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - - -/* Sleep dependency source arrays for 34xx-specific pwrdms - 34XX only */ - -/* - * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA - * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA - */ -static struct pwrdm_dep dss_per_usbhost_sleepdeps[] = { - { - .pwrdm_name = "mpu_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { - .pwrdm_name = "iva2_pwrdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) - }, - { NULL }, -}; - - /* * Powerdomains */ @@ -163,8 +42,6 @@ static struct powerdomain iva2_pwrdm = { .name = "iva2_pwrdm", .prcm_offs = OMAP3430_IVA2_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), - .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, - .wkdep_srcs = iva2_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 4, @@ -186,8 +63,6 @@ static struct powerdomain mpu_34xx_pwrdm = { .name = "mpu_pwrdm", .prcm_offs = MPU_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), - .dep_bit = OMAP3430_EN_MPU_SHIFT, - .wkdep_srcs = mpu_34xx_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .flags = PWRDM_HAS_MPU_QUIRK, @@ -200,7 +75,6 @@ static struct powerdomain mpu_34xx_pwrdm = { }, }; -/* No wkdeps or sleepdeps for 34xx core apparently */ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, @@ -208,7 +82,6 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0), .pwrsts = PWRSTS_OFF_RET_ON, - .dep_bit = OMAP3430_EN_CORE_SHIFT, .banks = 2, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ @@ -220,13 +93,11 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { }, }; -/* No wkdeps or sleepdeps for 34xx core apparently */ static struct powerdomain core_34xx_es3_1_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES3_1), .pwrsts = PWRSTS_OFF_RET_ON, - .dep_bit = OMAP3430_EN_CORE_SHIFT, .flags = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */ .banks = 2, .pwrsts_mem_ret = { @@ -239,14 +110,10 @@ static struct powerdomain core_34xx_es3_1_pwrdm = { }, }; -/* Another case of bit name collisions between several registers: EN_DSS */ static struct powerdomain dss_pwrdm = { .name = "dss_pwrdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .prcm_offs = OMAP3430_DSS_MOD, - .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT, - .wkdep_srcs = cam_dss_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, .banks = 1, @@ -267,8 +134,6 @@ static struct powerdomain sgx_pwrdm = { .name = "sgx_pwrdm", .prcm_offs = OMAP3430ES2_SGX_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), - .wkdep_srcs = gfx_sgx_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, /* XXX This is accurate for 3430 SGX, but what about GFX? */ .pwrsts = PWRSTS_OFF_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, @@ -285,8 +150,6 @@ static struct powerdomain cam_pwrdm = { .name = "cam_pwrdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .prcm_offs = OMAP3430_CAM_MOD, - .wkdep_srcs = cam_dss_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, .banks = 1, @@ -302,9 +165,6 @@ static struct powerdomain per_pwrdm = { .name = "per_pwrdm", .prcm_offs = OMAP3430_PER_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), - .dep_bit = OMAP3430_EN_PER_SHIFT, - .wkdep_srcs = per_usbhost_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 1, @@ -326,7 +186,6 @@ static struct powerdomain neon_pwrdm = { .name = "neon_pwrdm", .prcm_offs = OMAP3430_NEON_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), - .wkdep_srcs = neon_wkdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, }; @@ -335,8 +194,6 @@ static struct powerdomain usbhost_pwrdm = { .name = "usbhost_pwrdm", .prcm_offs = OMAP3430ES2_USBHOST_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), - .wkdep_srcs = per_usbhost_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, /* diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index 82ad8f8ad83a..abafd2298ece 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -199,6 +199,18 @@ u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) return v; } +/* Read a PRM register, AND it, and shift the result down to bit 0 */ +u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) +{ + u32 v; + + v = prm_read_mod_reg(domain, idx); + v &= mask; + v >>= __ffs(mask); + + return v; +} + /* Read a register in a CM module */ u32 cm_read_mod_reg(s16 module, u16 idx) { diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index 4806e2c52c11..f77ca72ec3ad 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -4,7 +4,7 @@ * OMAP2/3 clockdomain framework functions * * Copyright (C) 2008 Texas Instruments, Inc. - * Copyright (C) 2008 Nokia Corporation + * Copyright (C) 2008-2009 Nokia Corporation * * Written by Paul Walmsley * @@ -41,26 +41,40 @@ #define OMAP34XX_CLKSTCTRL_ENABLE_AUTO 0x3 /* - * struct clkdm_pwrdm_autodep - a powerdomain that should have wkdeps - * and sleepdeps added when a powerdomain should stay active in hwsup mode; - * and conversely, removed when the powerdomain should be allowed to go + * struct clkdm_autodep - a clockdomain that should have wkdeps + * and sleepdeps added when a clockdomain should stay active in hwsup mode; + * and conversely, removed when the clockdomain should be allowed to go * inactive in hwsup mode. */ -struct clkdm_pwrdm_autodep { +struct clkdm_autodep { union { - /* Name of the powerdomain to add a wkdep/sleepdep on */ + /* Name of the clockdomain to add a wkdep/sleepdep on */ const char *name; - /* Powerdomain pointer (looked up at clkdm_init() time) */ - struct powerdomain *ptr; - } pwrdm; + /* Clockdomain pointer (looked up at clkdm_init() time) */ + struct clockdomain *ptr; + } clkdm; /* OMAP chip types that this clockdomain dep is valid on */ const struct omap_chip_id omap_chip; }; +/* Encodes dependencies between clockdomains - statically defined */ +struct clkdm_dep { + + /* Clockdomain name */ + const char *clkdm_name; + + /* Clockdomain pointer - resolved by the clockdomain code */ + struct clockdomain *clkdm; + + /* Flags to mark OMAP chip restrictions, etc. */ + const struct omap_chip_id omap_chip; + +}; + struct clockdomain { /* Clockdomain name */ @@ -83,6 +97,15 @@ struct clockdomain { /* Clockdomain capability flags */ const u8 flags; + /* Bit shift of this clockdomain's PM_WKDEP/CM_SLEEPDEP bit */ + const u8 dep_bit; + + /* Clockdomains that can be told to wake this powerdomain up */ + struct clkdm_dep *wkdep_srcs; + + /* Clockdomains that can be told to keep this clkdm from inactivity */ + struct clkdm_dep *sleepdep_srcs; + /* OMAP chip types that this clockdomain is valid on */ const struct omap_chip_id omap_chip; @@ -93,7 +116,7 @@ struct clockdomain { }; -void clkdm_init(struct clockdomain **clkdms, struct clkdm_pwrdm_autodep *autodeps); +void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *autodeps); int clkdm_register(struct clockdomain *clkdm); int clkdm_unregister(struct clockdomain *clkdm); struct clockdomain *clkdm_lookup(const char *name); @@ -102,6 +125,13 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), void *user); struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm); +int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); + void omap2_clkdm_allow_idle(struct clockdomain *clkdm); void omap2_clkdm_deny_idle(struct clockdomain *clkdm); diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index bac378eff8df..dd5f79dabb3b 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -1,8 +1,8 @@ /* * OMAP2/3 powerdomain control * - * Copyright (C) 2007-8 Texas Instruments, Inc. - * Copyright (C) 2007-8 Nokia Corporation + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * @@ -68,20 +68,6 @@ struct clockdomain; struct powerdomain; -/* Encodes dependencies between powerdomains - statically defined */ -struct pwrdm_dep { - - /* Powerdomain name */ - const char *pwrdm_name; - - /* Powerdomain pointer - resolved by the powerdomain code */ - struct powerdomain *pwrdm; - - /* Flags to mark OMAP chip restrictions, etc. */ - const struct omap_chip_id omap_chip; - -}; - struct powerdomain { /* Powerdomain name */ @@ -93,15 +79,6 @@ struct powerdomain { /* Used to represent the OMAP chip types containing this pwrdm */ const struct omap_chip_id omap_chip; - /* Powerdomains that can be told to wake this powerdomain up */ - struct pwrdm_dep *wkdep_srcs; - - /* Powerdomains that can be told to keep this pwrdm from inactivity */ - struct pwrdm_dep *sleepdep_srcs; - - /* Bit shift of this powerdomain's PM_WKDEP/CM_SLEEPDEP bit */ - const u8 dep_bit; - /* Possible powerdomain power states */ const u8 pwrsts; @@ -152,13 +129,6 @@ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, int (*fn)(struct powerdomain *pwrdm, struct clockdomain *clkdm)); -int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); -int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); -int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); -int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); -int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); -int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); - int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm); int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h index e63e94e18975..66938a9f8dae 100644 --- a/arch/arm/plat-omap/include/plat/prcm.h +++ b/arch/arm/plat-omap/include/plat/prcm.h @@ -33,6 +33,14 @@ int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name); void omap3_prcm_save_context(void); void omap3_prcm_restore_context(void); +u32 prm_read_mod_reg(s16 module, u16 idx); +void prm_write_mod_reg(u32 val, s16 module, u16 idx); +u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); +u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask); +u32 cm_read_mod_reg(s16 module, u16 idx); +void cm_write_mod_reg(u32 val, s16 module, u16 idx); +u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); + #endif -- GitLab From a26017002847eef09625a94f897a0fb1ff58da4b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:59 -0700 Subject: [PATCH 1220/3892] OMAP2/3 clockdomains: split shared structures so usecounting works Previously some of the clockdomain wakeup/sleep dependency structures were shared between several domains. For the subsequent wakeup and sleep dependency usecounting patch to work, these can no longer be shared. This patch splits the shared structures apart. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clockdomains.h | 163 ++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index ff216f24f1a0..9629ef1c7535 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -52,6 +52,8 @@ * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE + * These can share data since they will never be present simultaneously + * on the same device. */ static struct clkdm_dep gfx_sgx_wkdeps[] = { { @@ -86,11 +88,32 @@ static struct clkdm_dep gfx_sgx_wkdeps[] = { /* Wakeup dependency source arrays */ +/* 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP */ +static struct clkdm_dep dsp_24xx_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) + }, + { NULL }, +}; + /* - * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP - * 2420/2430 PM_WKDEP_MDM: same as DSP + * 2420/2430 PM_WKDEP_MDM: CORE, MPU, WKUP + * XXX This is probably 2430-only; 2420 did not have a stacked modem config. */ -static struct clkdm_dep dsp_mdm_24xx_wkdeps[] = { +static struct clkdm_dep mdm_24xx_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) @@ -172,11 +195,8 @@ static struct clkdm_dep core_24xx_wkdeps[] = { #ifdef CONFIG_ARCH_OMAP34XX -/* - * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP - * (USBHOST is ES2 only) - */ -static struct clkdm_dep per_usbhost_wkdeps[] = { +/* 3430: PM_WKDEP_PER: CORE, IVA2, MPU, WKUP */ +static struct clkdm_dep per_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -200,9 +220,32 @@ static struct clkdm_dep per_usbhost_wkdeps[] = { { NULL }, }; -/* - * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER - */ +/* 3430ES2: PM_WKDEP_USBHOST: CORE, IVA2, MPU, WKUP */ +static struct clkdm_dep usbhost_wkdeps[] = { + { + .clkdm_name = "core_l3_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "core_l4_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER */ static struct clkdm_dep mpu_34xx_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", @@ -227,9 +270,7 @@ static struct clkdm_dep mpu_34xx_wkdeps[] = { { NULL }, }; -/* - * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER - */ +/* 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER */ static struct clkdm_dep iva2_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", @@ -259,8 +300,25 @@ static struct clkdm_dep iva2_wkdeps[] = { }; -/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */ -static struct clkdm_dep cam_dss_wkdeps[] = { +/* 3430 PM_WKDEP_CAM: IVA2, MPU, WKUP */ +static struct clkdm_dep cam_wkdeps[] = { + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "wkup_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* 3430 PM_WKDEP_DSS: IVA2, MPU, WKUP */ +static struct clkdm_dep dss_wkdeps[] = { { .clkdm_name = "iva2_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -288,11 +346,8 @@ static struct clkdm_dep neon_wkdeps[] = { /* Sleep dependency source arrays for 34xx-specific clkdms - 34XX only */ -/* - * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA - * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA - */ -static struct clkdm_dep dss_per_usbhost_sleepdeps[] = { +/* 3430: CM_SLEEPDEP_DSS: MPU, IVA */ +static struct clkdm_dep dss_sleepdeps[] = { { .clkdm_name = "mpu_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -304,12 +359,48 @@ static struct clkdm_dep dss_per_usbhost_sleepdeps[] = { { NULL }, }; +/* 3430: CM_SLEEPDEP_PER: MPU, IVA */ +static struct clkdm_dep per_sleepdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA */ +static struct clkdm_dep usbhost_sleepdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { + .clkdm_name = "iva2_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + +/* 3430: CM_SLEEPDEP_CAM: MPU */ +static struct clkdm_dep cam_sleepdeps[] = { + { + .clkdm_name = "mpu_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) + }, + { NULL }, +}; + /* - * 3430: CM_SLEEPDEP_CAM: MPU * 3430ES1: CM_SLEEPDEP_GFX: MPU * 3430ES2: CM_SLEEPDEP_SGX: MPU + * These can share data since they will never be present simultaneously + * on the same device. */ -static struct clkdm_dep cam_gfx_sleepdeps[] = { +static struct clkdm_dep gfx_sgx_sleepdeps[] = { { .clkdm_name = "mpu_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -376,7 +467,7 @@ static struct clockdomain iva1_2420_clkdm = { .clkstctrl_reg = OMAP2420_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT, - .wkdep_srcs = dsp_mdm_24xx_wkdeps, + .wkdep_srcs = dsp_24xx_wkdeps, .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), }; @@ -458,7 +549,7 @@ static struct clockdomain mdm_clkdm = { .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP2430_MDM_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT, - .wkdep_srcs = dsp_mdm_24xx_wkdeps, + .wkdep_srcs = mdm_24xx_wkdeps, .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -470,7 +561,7 @@ static struct clockdomain dsp_2430_clkdm = { .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT, - .wkdep_srcs = dsp_mdm_24xx_wkdeps, + .wkdep_srcs = dsp_24xx_wkdeps, .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; @@ -575,7 +666,7 @@ static struct clockdomain gfx_3430es1_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(GFX_MOD, OMAP2_CM_CLKSTCTRL), .wkdep_srcs = gfx_sgx_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, + .sleepdep_srcs = gfx_sgx_sleepdeps, .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1), }; @@ -587,7 +678,7 @@ static struct clockdomain sgx_clkdm = { .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_SGX_MOD, OMAP2_CM_CLKSTCTRL), .wkdep_srcs = gfx_sgx_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, + .sleepdep_srcs = gfx_sgx_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -646,8 +737,8 @@ static struct clockdomain dss_34xx_clkdm = { .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT, - .wkdep_srcs = cam_dss_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, + .wkdep_srcs = dss_wkdeps, + .sleepdep_srcs = dss_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -658,8 +749,8 @@ static struct clockdomain cam_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL), - .wkdep_srcs = cam_dss_wkdeps, - .sleepdep_srcs = cam_gfx_sleepdeps, + .wkdep_srcs = cam_wkdeps, + .sleepdep_srcs = cam_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -670,8 +761,8 @@ static struct clockdomain usbhost_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL), - .wkdep_srcs = per_usbhost_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, + .wkdep_srcs = usbhost_wkdeps, + .sleepdep_srcs = usbhost_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; @@ -683,8 +774,8 @@ static struct clockdomain per_clkdm = { .clkstctrl_reg = OMAP34XX_CM_REGADDR(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP3430_EN_PER_SHIFT, - .wkdep_srcs = per_usbhost_wkdeps, - .sleepdep_srcs = dss_per_usbhost_sleepdeps, + .wkdep_srcs = per_wkdeps, + .sleepdep_srcs = per_sleepdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; -- GitLab From 3d309cdef37e238c108cade95a8192d5688bd56a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:12:59 -0700 Subject: [PATCH 1221/3892] OMAP2 clockdomain: modem clockdomain is only present on OMAP2430 For some reason, previously, we included the MDM clockdomain on all 24xx, but the stacked die-on-die modem configuration (chassis mode) is only available on OMAP2430. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clockdomains.h | 49 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 9629ef1c7535..fb026dabfc37 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -110,10 +110,10 @@ static struct clkdm_dep dsp_24xx_wkdeps[] = { }; /* - * 2420/2430 PM_WKDEP_MDM: CORE, MPU, WKUP - * XXX This is probably 2430-only; 2420 did not have a stacked modem config. + * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP + * 2430 adds MDM */ -static struct clkdm_dep mdm_24xx_wkdeps[] = { +static struct clkdm_dep mpu_24xx_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) @@ -123,31 +123,35 @@ static struct clkdm_dep mdm_24xx_wkdeps[] = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { - .clkdm_name = "mpu_clkdm", + .clkdm_name = "dsp_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { .clkdm_name = "wkup_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, + { + .clkdm_name = "mdm_clkdm", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) + }, { NULL }, }; /* - * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP + * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP * 2430 adds MDM */ -static struct clkdm_dep mpu_24xx_wkdeps[] = { +static struct clkdm_dep core_24xx_wkdeps[] = { { - .clkdm_name = "core_l3_clkdm", + .clkdm_name = "dsp_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { - .clkdm_name = "core_l4_clkdm", + .clkdm_name = "gfx_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { - .clkdm_name = "dsp_clkdm", + .clkdm_name = "mpu_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { @@ -161,17 +165,21 @@ static struct clkdm_dep mpu_24xx_wkdeps[] = { { NULL }, }; -/* - * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP - * 2430 adds MDM - */ -static struct clkdm_dep core_24xx_wkdeps[] = { +#endif + + +/* 2430-specific possible wakeup dependencies */ + +#ifdef CONFIG_ARCH_OMAP2430 + +/* 2430 PM_WKDEP_MDM: CORE, MPU, WKUP */ +static struct clkdm_dep mdm_2430_wkdeps[] = { { - .clkdm_name = "dsp_clkdm", + .clkdm_name = "core_l3_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { - .clkdm_name = "gfx_clkdm", + .clkdm_name = "core_l4_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, { @@ -182,14 +190,11 @@ static struct clkdm_dep core_24xx_wkdeps[] = { .clkdm_name = "wkup_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX) }, - { - .clkdm_name = "mdm_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) - }, { NULL }, }; -#endif +#endif /* CONFIG_ARCH_OMAP2430 */ + /* 34XX-specific possible dependencies */ @@ -549,7 +554,7 @@ static struct clockdomain mdm_clkdm = { .clkstctrl_reg = OMAP2430_CM_REGADDR(OMAP2430_MDM_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT, - .wkdep_srcs = mdm_24xx_wkdeps, + .wkdep_srcs = mdm_2430_wkdeps, .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), }; -- GitLab From e909d62a8afda7a224a7e322cf2f387d69ca771f Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:00 -0700 Subject: [PATCH 1222/3892] OMAP clockdomain/powerdomain: remove runtime register/unregister OMAP clockdomains and powerdomains are currently defined statically, only registered at boot, and never unregistered, so we can remove the unregister function and the locking. A variant of this was originally suggested a while ago by Dmitry Baryshkov . This version of this patch contains an additional fix from Kevin Hilman to address one of the pwrdm_for_each_nolock() users in mach-omap2/pm-debug.c. Thanks Kevin. Signed-off-by: Paul Walmsley Cc: Dmitry Baryshkov Cc: Kevin Hilman --- arch/arm/mach-omap2/clockdomain.c | 118 ++++-------- arch/arm/mach-omap2/pm-debug.c | 2 +- arch/arm/mach-omap2/powerdomain.c | 178 +++++------------- arch/arm/plat-omap/include/plat/clockdomain.h | 2 - arch/arm/plat-omap/include/plat/powerdomain.h | 2 - 5 files changed, 86 insertions(+), 216 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index a70ba29f66cc..2af9996f010b 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -39,9 +39,6 @@ /* clkdm_list contains all registered struct clockdomains */ static LIST_HEAD(clkdm_list); -/* clkdm_mutex protects clkdm_list add and del ops */ -static DEFINE_MUTEX(clkdm_mutex); - /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ static struct clkdm_autodep *autodeps; @@ -67,6 +64,45 @@ static struct clockdomain *_clkdm_lookup(const char *name) return clkdm; } +/** + * _clkdm_register - register a clockdomain + * @clkdm: struct clockdomain * to register + * + * Adds a clockdomain to the internal clockdomain list. + * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is + * already registered by the provided name, or 0 upon success. + */ +static int _clkdm_register(struct clockdomain *clkdm) +{ + struct powerdomain *pwrdm; + + if (!clkdm || !clkdm->name) + return -EINVAL; + + if (!omap_chip_is(clkdm->omap_chip)) + return -EINVAL; + + pwrdm = pwrdm_lookup(clkdm->pwrdm.name); + if (!pwrdm) { + pr_err("clockdomain: %s: powerdomain %s does not exist\n", + clkdm->name, clkdm->pwrdm.name); + return -EINVAL; + } + clkdm->pwrdm.ptr = pwrdm; + + /* Verify that the clockdomain is not already registered */ + if (_clkdm_lookup(clkdm->name)) + return -EEXIST; + + list_add(&clkdm->node, &clkdm_list); + + pwrdm_add_clkdm(pwrdm, clkdm); + + pr_debug("clockdomain: registered %s\n", clkdm->name); + + return 0; +} + /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, struct clkdm_dep *deps) @@ -240,7 +276,7 @@ void clkdm_init(struct clockdomain **clkdms, if (clkdms) for (c = clkdms; *c; c++) - clkdm_register(*c); + _clkdm_register(*c); autodeps = init_autodeps; if (autodeps) @@ -248,76 +284,6 @@ void clkdm_init(struct clockdomain **clkdms, _autodep_lookup(autodep); } -/** - * clkdm_register - register a clockdomain - * @clkdm: struct clockdomain * to register - * - * Adds a clockdomain to the internal clockdomain list. - * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is - * already registered by the provided name, or 0 upon success. - */ -int clkdm_register(struct clockdomain *clkdm) -{ - int ret = -EINVAL; - struct powerdomain *pwrdm; - - if (!clkdm || !clkdm->name) - return -EINVAL; - - if (!omap_chip_is(clkdm->omap_chip)) - return -EINVAL; - - pwrdm = pwrdm_lookup(clkdm->pwrdm.name); - if (!pwrdm) { - pr_err("clockdomain: %s: powerdomain %s does not exist\n", - clkdm->name, clkdm->pwrdm.name); - return -EINVAL; - } - clkdm->pwrdm.ptr = pwrdm; - - mutex_lock(&clkdm_mutex); - /* Verify that the clockdomain is not already registered */ - if (_clkdm_lookup(clkdm->name)) { - ret = -EEXIST; - goto cr_unlock; - } - - list_add(&clkdm->node, &clkdm_list); - - pwrdm_add_clkdm(pwrdm, clkdm); - - pr_debug("clockdomain: registered %s\n", clkdm->name); - ret = 0; - -cr_unlock: - mutex_unlock(&clkdm_mutex); - - return ret; -} - -/** - * clkdm_unregister - unregister a clockdomain - * @clkdm: struct clockdomain * to unregister - * - * Removes a clockdomain from the internal clockdomain list. Returns - * -EINVAL if clkdm argument is NULL. - */ -int clkdm_unregister(struct clockdomain *clkdm) -{ - if (!clkdm) - return -EINVAL; - - pwrdm_del_clkdm(clkdm->pwrdm.ptr, clkdm); - - mutex_lock(&clkdm_mutex); - list_del(&clkdm->node); - mutex_unlock(&clkdm_mutex); - - pr_debug("clockdomain: unregistered %s\n", clkdm->name); - - return 0; -} - /** * clkdm_lookup - look up a clockdomain by name, return a pointer * @name: name of clockdomain @@ -334,14 +300,12 @@ struct clockdomain *clkdm_lookup(const char *name) clkdm = NULL; - mutex_lock(&clkdm_mutex); list_for_each_entry(temp_clkdm, &clkdm_list, node) { if (!strcmp(name, temp_clkdm->name)) { clkdm = temp_clkdm; break; } } - mutex_unlock(&clkdm_mutex); return clkdm; } @@ -369,13 +333,11 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), if (!fn) return -EINVAL; - mutex_lock(&clkdm_mutex); list_for_each_entry(clkdm, &clkdm_list, node) { ret = (*fn)(clkdm, user); if (ret) break; } - mutex_unlock(&clkdm_mutex); return ret; } diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 5b6ae1e88e01..0ce356f351a3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -577,7 +577,7 @@ static int __init pm_dbg_init(void) (void) debugfs_create_file("time", S_IRUGO, d, (void *)DEBUG_FILE_TIMERS, &debug_fops); - pwrdm_for_each_nolock(pwrdms_setup, (void *)d); + pwrdm_for_each(pwrdms_setup, (void *)d); pm_dbg_dir = debugfs_create_dir("registers", d); if (IS_ERR(pm_dbg_dir)) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index e8e8d8872a0e..411361f97eda 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -80,13 +80,6 @@ static u16 pwrstst_reg_offs; /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); -/* - * pwrdm_rwlock protects pwrdm_list add and del ops - also reused to - * protect pwrdm_clkdms[] during clkdm add/del ops - */ -static DEFINE_RWLOCK(pwrdm_rwlock); - - /* Private functions */ static struct powerdomain *_pwrdm_lookup(const char *name) @@ -105,6 +98,42 @@ static struct powerdomain *_pwrdm_lookup(const char *name) return pwrdm; } +/** + * _pwrdm_register - register a powerdomain + * @pwrdm: struct powerdomain * to register + * + * Adds a powerdomain to the internal powerdomain list. Returns + * -EINVAL if given a null pointer, -EEXIST if a powerdomain is + * already registered by the provided name, or 0 upon success. + */ +static int _pwrdm_register(struct powerdomain *pwrdm) +{ + int i; + + if (!pwrdm) + return -EINVAL; + + if (!omap_chip_is(pwrdm->omap_chip)) + return -EINVAL; + + if (_pwrdm_lookup(pwrdm->name)) + return -EEXIST; + + list_add(&pwrdm->node, &pwrdm_list); + + /* Initialize the powerdomain's state counter */ + for (i = 0; i < 4; i++) + pwrdm->state_counter[i] = 0; + + pwrdm_wait_transition(pwrdm); + pwrdm->state = pwrdm_read_pwrst(pwrdm); + pwrdm->state_counter[pwrdm->state] = 1; + + pr_debug("powerdomain: registered %s\n", pwrdm->name); + + return 0; +} + static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { @@ -152,19 +181,6 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) return 0; } -static __init void _pwrdm_setup(struct powerdomain *pwrdm) -{ - int i; - - for (i = 0; i < PWRDM_MAX_PWRSTS; i++) - pwrdm->state_counter[i] = 0; - - pwrdm_wait_transition(pwrdm); - pwrdm->state = pwrdm_read_pwrst(pwrdm); - pwrdm->state_counter[pwrdm->state] = 1; - -} - /* Public functions */ /** @@ -192,72 +208,11 @@ void pwrdm_init(struct powerdomain **pwrdm_list) } if (pwrdm_list) { - for (p = pwrdm_list; *p; p++) { - pwrdm_register(*p); - _pwrdm_setup(*p); - } + for (p = pwrdm_list; *p; p++) + _pwrdm_register(*p); } } -/** - * pwrdm_register - register a powerdomain - * @pwrdm: struct powerdomain * to register - * - * Adds a powerdomain to the internal powerdomain list. Returns - * -EINVAL if given a null pointer, -EEXIST if a powerdomain is - * already registered by the provided name, or 0 upon success. - */ -int pwrdm_register(struct powerdomain *pwrdm) -{ - unsigned long flags; - int ret = -EINVAL; - - if (!pwrdm) - return -EINVAL; - - if (!omap_chip_is(pwrdm->omap_chip)) - return -EINVAL; - - write_lock_irqsave(&pwrdm_rwlock, flags); - if (_pwrdm_lookup(pwrdm->name)) { - ret = -EEXIST; - goto pr_unlock; - } - - list_add(&pwrdm->node, &pwrdm_list); - - pr_debug("powerdomain: registered %s\n", pwrdm->name); - ret = 0; - -pr_unlock: - write_unlock_irqrestore(&pwrdm_rwlock, flags); - - return ret; -} - -/** - * pwrdm_unregister - unregister a powerdomain - * @pwrdm: struct powerdomain * to unregister - * - * Removes a powerdomain from the internal powerdomain list. Returns - * -EINVAL if pwrdm argument is NULL. - */ -int pwrdm_unregister(struct powerdomain *pwrdm) -{ - unsigned long flags; - - if (!pwrdm) - return -EINVAL; - - write_lock_irqsave(&pwrdm_rwlock, flags); - list_del(&pwrdm->node); - write_unlock_irqrestore(&pwrdm_rwlock, flags); - - pr_debug("powerdomain: unregistered %s\n", pwrdm->name); - - return 0; -} - /** * pwrdm_lookup - look up a powerdomain by name, return a pointer * @name: name of powerdomain @@ -268,20 +223,17 @@ int pwrdm_unregister(struct powerdomain *pwrdm) struct powerdomain *pwrdm_lookup(const char *name) { struct powerdomain *pwrdm; - unsigned long flags; if (!name) return NULL; - read_lock_irqsave(&pwrdm_rwlock, flags); pwrdm = _pwrdm_lookup(name); - read_unlock_irqrestore(&pwrdm_rwlock, flags); return pwrdm; } /** - * pwrdm_for_each_nolock - call function on each registered clockdomain + * pwrdm_for_each - call function on each registered clockdomain * @fn: callback function * * * Call the supplied function for each registered powerdomain. The @@ -290,8 +242,8 @@ struct powerdomain *pwrdm_lookup(const char *name) * should be 0 for success or anything else to indicate failure; or -EINVAL if * the function pointer is null. */ -int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user), - void *user) +int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), + void *user) { struct powerdomain *temp_pwrdm; int ret = 0; @@ -308,28 +260,6 @@ int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user), return ret; } -/** - * pwrdm_for_each - call function on each registered clockdomain - * @fn: callback function * - * - * This function is the same as 'pwrdm_for_each_nolock()', but keeps the - * &pwrdm_rwlock locked for reading, so no powerdomain structure manipulation - * functions should be called from the callback, although hardware powerdomain - * control functions are fine. - */ -int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), - void *user) -{ - unsigned long flags; - int ret; - - read_lock_irqsave(&pwrdm_rwlock, flags); - ret = pwrdm_for_each_nolock(fn, user); - read_unlock_irqrestore(&pwrdm_rwlock, flags); - - return ret; -} - /** * pwrdm_add_clkdm - add a clockdomain to a powerdomain * @pwrdm: struct powerdomain * to add the clockdomain to @@ -342,7 +272,6 @@ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), */ int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) { - unsigned long flags; int i; int ret = -EINVAL; @@ -352,8 +281,6 @@ int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) pr_debug("powerdomain: associating clockdomain %s with powerdomain " "%s\n", clkdm->name, pwrdm->name); - write_lock_irqsave(&pwrdm_rwlock, flags); - for (i = 0; i < PWRDM_MAX_CLKDMS; i++) { if (!pwrdm->pwrdm_clkdms[i]) break; @@ -378,8 +305,6 @@ int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) ret = 0; pac_exit: - write_unlock_irqrestore(&pwrdm_rwlock, flags); - return ret; } @@ -395,7 +320,6 @@ pac_exit: */ int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) { - unsigned long flags; int ret = -EINVAL; int i; @@ -405,8 +329,6 @@ int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) pr_debug("powerdomain: dissociating clockdomain %s from powerdomain " "%s\n", clkdm->name, pwrdm->name); - write_lock_irqsave(&pwrdm_rwlock, flags); - for (i = 0; i < PWRDM_MAX_CLKDMS; i++) if (pwrdm->pwrdm_clkdms[i] == clkdm) break; @@ -423,8 +345,6 @@ int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) ret = 0; pdc_exit: - write_unlock_irqrestore(&pwrdm_rwlock, flags); - return ret; } @@ -435,32 +355,24 @@ pdc_exit: * * Call the supplied function for each clockdomain in the powerdomain * 'pwrdm'. The callback function can return anything but 0 to bail - * out early from the iterator. The callback function is called with - * the pwrdm_rwlock held for reading, so no powerdomain structure - * manipulation functions should be called from the callback, although - * hardware powerdomain control functions are fine. Returns -EINVAL - * if presented with invalid pointers; or passes along the last return - * value of the callback function, which should be 0 for success or - * anything else to indicate failure. + * out early from the iterator. Returns -EINVAL if presented with + * invalid pointers; or passes along the last return value of the + * callback function, which should be 0 for success or anything else + * to indicate failure. */ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, int (*fn)(struct powerdomain *pwrdm, struct clockdomain *clkdm)) { - unsigned long flags; int ret = 0; int i; if (!fn) return -EINVAL; - read_lock_irqsave(&pwrdm_rwlock, flags); - for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++) ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]); - read_unlock_irqrestore(&pwrdm_rwlock, flags); - return ret; } diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index f77ca72ec3ad..22869713265f 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -117,8 +117,6 @@ struct clockdomain { }; void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *autodeps); -int clkdm_register(struct clockdomain *clkdm); -int clkdm_unregister(struct clockdomain *clkdm); struct clockdomain *clkdm_lookup(const char *name); int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index dd5f79dabb3b..c590e2fc140f 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -114,8 +114,6 @@ struct powerdomain { void pwrdm_init(struct powerdomain **pwrdm_list); -int pwrdm_register(struct powerdomain *pwrdm); -int pwrdm_unregister(struct powerdomain *pwrdm); struct powerdomain *pwrdm_lookup(const char *name); int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), -- GitLab From 369d5614457384edcf62c5f39b03dd20be6ea1df Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:01 -0700 Subject: [PATCH 1223/3892] OMAP clockdomains: add usecounting for wakeup and sleep dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add usecounting for wakeup and sleep dependencies. In the current situation, if several functions add dependencies on the same clockdomains, when the first dependency removal function is called, the dependency will be incorrectly removed from the hardware. Add clkdm_clear_all_wkdeps() and clkdm_clear_all_sleepdeps(), which provide a fast and usecounting-consistent way to clear all hardware clockdomain dependencies, since accesses to these registers can be quite slow. pm{2,3}4xx.c has been updated to use these new functions. The original version of this patch did not touch these files, which previously wrote directly to the wkdep registers, and thus confused the usecounting code. This problem was found by Kevin Hilman . N.B.: This patch introduces one significant functional difference over the previous pm34xx.c code: sleepdeps are now cleared during clockdomain initialization, whereas previously they were left untouched. This has been tested by Kevin and confirmed to work. The original version of this patch also did not take into consideration that some clockdomains do not have sleep or wakeup dependency sources, which caused NULL pointer dereferences. This problem was debugged and fixed by Kevin Hilman . Signed-off-by: Paul Walmsley Signed-off-by: Kevin Hilman Cc: Jouni Högander --- arch/arm/mach-omap2/clockdomain.c | 216 ++++++++++++++++-- arch/arm/mach-omap2/pm24xx.c | 49 ++-- arch/arm/mach-omap2/pm34xx.c | 3 + arch/arm/plat-omap/include/plat/clockdomain.h | 8 + 4 files changed, 237 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 2af9996f010b..6eaa9314cd64 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -113,7 +113,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, return ERR_PTR(-EINVAL); for (cd = deps; cd->clkdm_name; cd++) { - if (!omap_chip_is(cd->omap_chip)) continue; @@ -122,7 +121,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, if (cd->clkdm == clkdm) break; - } if (!cd->clkdm_name) @@ -254,6 +252,96 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) } +/** + * _init_wkdep_usecount - initialize wkdep usecounts to match hardware + * @clkdm: clockdomain to initialize wkdep usecounts + * + * Initialize the wakeup dependency usecount variables for clockdomain @clkdm. + * If a wakeup dependency is present in the hardware, the usecount will be + * set to 1; otherwise, it will be set to 0. Software should clear all + * software wakeup dependencies prior to calling this function if it wishes + * to ensure that all usecounts start at 0. No return value. + */ +static void _init_wkdep_usecount(struct clockdomain *clkdm) +{ + u32 v; + struct clkdm_dep *cd; + + if (!clkdm->wkdep_srcs) + return; + + for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + + if (!cd->clkdm && cd->clkdm_name) + cd->clkdm = _clkdm_lookup(cd->clkdm_name); + + if (!cd->clkdm) { + WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not " + "found\n", clkdm->name, cd->clkdm_name); + continue; + } + + v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs, + PM_WKDEP, + (1 << cd->clkdm->dep_bit)); + + if (v) + pr_debug("clockdomain: %s: wakeup dependency already " + "set to wake up when %s wakes\n", + clkdm->name, cd->clkdm->name); + + atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0); + } +} + +/** + * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware + * @clkdm: clockdomain to initialize sleepdep usecounts + * + * Initialize the sleep dependency usecount variables for clockdomain @clkdm. + * If a sleep dependency is present in the hardware, the usecount will be + * set to 1; otherwise, it will be set to 0. Software should clear all + * software sleep dependencies prior to calling this function if it wishes + * to ensure that all usecounts start at 0. No return value. + */ +static void _init_sleepdep_usecount(struct clockdomain *clkdm) +{ + u32 v; + struct clkdm_dep *cd; + + if (!cpu_is_omap34xx()) + return; + + if (!clkdm->sleepdep_srcs) + return; + + for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + + if (!cd->clkdm && cd->clkdm_name) + cd->clkdm = _clkdm_lookup(cd->clkdm_name); + + if (!cd->clkdm) { + WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s " + "not found\n", clkdm->name, cd->clkdm_name); + continue; + } + + v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP, + (1 << cd->clkdm->dep_bit)); + + if (v) + pr_debug("clockdomain: %s: sleep dependency already " + "set to prevent from idling until %s " + "idles\n", clkdm->name, cd->clkdm->name); + + atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0); + } +}; /* Public functions */ @@ -272,6 +360,7 @@ void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *init_autodeps) { struct clockdomain **c = NULL; + struct clockdomain *clkdm; struct clkdm_autodep *autodep = NULL; if (clkdms) @@ -282,6 +371,15 @@ void clkdm_init(struct clockdomain **clkdms, if (autodeps) for (autodep = autodeps; autodep->clkdm.ptr; autodep++) _autodep_lookup(autodep); + + /* + * Ensure that the *dep_usecount registers reflect the current + * state of the PRCM. + */ + list_for_each_entry(clkdm, &clkdm_list, node) { + _init_wkdep_usecount(clkdm); + _init_sleepdep_usecount(clkdm); + } } /** @@ -387,11 +485,13 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } - pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", - clkdm1->name, clkdm2->name); + if (atomic_inc_return(&cd->wkdep_usecount) == 1) { + pr_debug("clockdomain: hardware will wake up %s when %s wakes " + "up\n", clkdm1->name, clkdm2->name); - prm_set_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + prm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + } return 0; } @@ -420,11 +520,13 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } - pr_debug("clockdomain: hardware will no longer wake up %s after %s " - "wakes up\n", clkdm1->name, clkdm2->name); + if (atomic_dec_return(&cd->wkdep_usecount) == 0) { + pr_debug("clockdomain: hardware will no longer wake up %s " + "after %s wakes up\n", clkdm1->name, clkdm2->name); - prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); + } return 0; } @@ -457,10 +559,43 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } + /* XXX It's faster to return the atomic wkdep_usecount */ return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, (1 << clkdm2->dep_bit)); } +/** + * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm + * @clkdm: struct clockdomain * to remove all wakeup dependencies from + * + * Remove all inter-clockdomain wakeup dependencies that could cause + * @clkdm to wake. Intended to be used during boot to initialize the + * PRCM to a known state, after all clockdomains are put into swsup idle + * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or + * 0 upon success. + */ +int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) +{ + struct clkdm_dep *cd; + u32 mask = 0; + + if (!clkdm) + return -EINVAL; + + for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + + /* PRM accesses are slow, so minimize them */ + mask |= 1 << cd->clkdm->dep_bit; + atomic_set(&cd->wkdep_usecount, 0); + } + + prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); + + return 0; +} + /** * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) @@ -491,12 +626,14 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } - pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", - clkdm1->name, clkdm2->name); + if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { + pr_debug("clockdomain: will prevent %s from sleeping if %s " + "is active\n", clkdm1->name, clkdm2->name); - cm_set_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP); + cm_set_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + } return 0; } @@ -531,12 +668,15 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } - pr_debug("clockdomain: will no longer prevent %s from sleeping if " - "%s is active\n", clkdm1->name, clkdm2->name); + if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { + pr_debug("clockdomain: will no longer prevent %s from " + "sleeping if %s is active\n", clkdm1->name, + clkdm2->name); - cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), - clkdm1->pwrdm.ptr->prcm_offs, - OMAP3430_CM_SLEEPDEP); + cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), + clkdm1->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + } return 0; } @@ -575,11 +715,47 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return PTR_ERR(cd); } + /* XXX It's faster to return the atomic sleepdep_usecount */ return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit)); } +/** + * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm + * @clkdm: struct clockdomain * to remove all sleep dependencies from + * + * Remove all inter-clockdomain sleep dependencies that could prevent + * @clkdm from idling. Intended to be used during boot to initialize the + * PRCM to a known state, after all clockdomains are put into swsup idle + * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or + * 0 upon success. + */ +int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) +{ + struct clkdm_dep *cd; + u32 mask = 0; + + if (!cpu_is_omap34xx()) + return -EINVAL; + + if (!clkdm) + return -EINVAL; + + for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { + if (!omap_chip_is(cd->omap_chip)) + continue; + + /* PRM accesses are slow, so minimize them */ + mask |= 1 << cd->clkdm->dep_bit; + atomic_set(&cd->sleepdep_usecount, 0); + } + + prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, + OMAP3430_CM_SLEEPDEP); + + return 0; +} /** * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 754381857cb6..374299ea7ade 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -57,11 +57,8 @@ static void (*omap2_sram_idle)(void); static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); -static struct powerdomain *mpu_pwrdm; -static struct powerdomain *core_pwrdm; - -static struct clockdomain *dsp_clkdm; -static struct clockdomain *gfx_clkdm; +static struct powerdomain *mpu_pwrdm, *core_pwrdm; +static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm; static struct clk *osc_ck, *emul_ck; @@ -334,9 +331,17 @@ static struct platform_suspend_ops omap_pm_ops = { .valid = suspend_valid_only_mem, }; -static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm, void *unused) +/* XXX This function should be shareable between OMAP2xxx and OMAP3 */ +static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) { - omap2_clkdm_allow_idle(clkdm); + clkdm_clear_all_wkdeps(clkdm); + clkdm_clear_all_sleepdeps(clkdm); + + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + omap2_clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + omap2_clkdm_sleep(clkdm); return 0; } @@ -349,14 +354,6 @@ static void __init prcm_setup_regs(void) prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD, OMAP2_PRCM_SYSCONFIG_OFFSET); - /* Set all domain wakeup dependencies */ - prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP); - prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP); - prm_write_mod_reg(0, GFX_MOD, PM_WKDEP); - prm_write_mod_reg(0, CORE_MOD, PM_WKDEP); - if (cpu_is_omap2430()) - prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP); - /* * Set CORE powerdomain memory banks to retain their contents * during RETENTION @@ -385,8 +382,12 @@ static void __init prcm_setup_regs(void) pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); omap2_clkdm_sleep(gfx_clkdm); - /* Enable clockdomain hardware-supervised control for all clkdms */ - clkdm_for_each(_pm_clkdm_enable_hwsup, NULL); + /* + * Clear clockdomain wakeup dependencies and enable + * hardware-supervised idle for all clkdms + */ + clkdm_for_each(clkdms_setup, NULL); + clkdm_add_wkdep(mpu_clkdm, wkup_clkdm); /* Enable clock autoidle for all domains */ cm_write_mod_reg(OMAP24XX_AUTO_CAM | @@ -482,7 +483,7 @@ static int __init omap2_pm_init(void) l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET); printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); - /* Look up important powerdomains, clockdomains */ + /* Look up important powerdomains */ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); if (!mpu_pwrdm) @@ -492,9 +493,19 @@ static int __init omap2_pm_init(void) if (!core_pwrdm) pr_err("PM: core_pwrdm not found\n"); + /* Look up important clockdomains */ + + mpu_clkdm = clkdm_lookup("mpu_clkdm"); + if (!mpu_clkdm) + pr_err("PM: mpu_clkdm not found\n"); + + wkup_clkdm = clkdm_lookup("wkup_clkdm"); + if (!wkup_clkdm) + pr_err("PM: wkup_clkdm not found\n"); + dsp_clkdm = clkdm_lookup("dsp_clkdm"); if (!dsp_clkdm) - pr_err("PM: mpu_clkdm not found\n"); + pr_err("PM: dsp_clkdm not found\n"); gfx_clkdm = clkdm_lookup("gfx_clkdm"); if (!gfx_clkdm) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 5f59df87abf7..5087b153b093 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -998,6 +998,9 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) */ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) { + clkdm_clear_all_wkdeps(clkdm); + clkdm_clear_all_sleepdeps(clkdm); + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) omap2_clkdm_allow_idle(clkdm); else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index 22869713265f..45b5debc5d3f 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -70,6 +70,12 @@ struct clkdm_dep { /* Clockdomain pointer - resolved by the clockdomain code */ struct clockdomain *clkdm; + /* Number of wakeup dependencies causing this clkdm to wake */ + atomic_t wkdep_usecount; + + /* Number of sleep dependencies that could prevent clkdm from idle */ + atomic_t sleepdep_usecount; + /* Flags to mark OMAP chip restrictions, etc. */ const struct omap_chip_id omap_chip; @@ -126,9 +132,11 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm); int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_clear_all_wkdeps(struct clockdomain *clkdm); int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); +int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); void omap2_clkdm_allow_idle(struct clockdomain *clkdm); void omap2_clkdm_deny_idle(struct clockdomain *clkdm); -- GitLab From cf57aa7c5453e786acd37edea8acdd9497c708d6 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:01 -0700 Subject: [PATCH 1224/3892] OMAP powerdomain/PM: use symbolic constants for the max number of power states Replace some bare constants with symbolic constants. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/powerdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 411361f97eda..df6446a9c353 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -122,7 +122,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) list_add(&pwrdm->node, &pwrdm_list); /* Initialize the powerdomain's state counter */ - for (i = 0; i < 4; i++) + for (i = 0; i < PWRDM_MAX_PWRSTS; i++) pwrdm->state_counter[i] = 0; pwrdm_wait_transition(pwrdm); -- GitLab From e0594b448a040473fdc283934df66811f497a275 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:01 -0700 Subject: [PATCH 1225/3892] OMAP powerdomain: rearrange struct powerdomain to save some memory This patch rearranges the order of structure members in struct powerdomain to avoid wasting memory due to alignment restrictions. Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/powerdomain.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index c590e2fc140f..87e13f88994f 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -73,12 +73,12 @@ struct powerdomain { /* Powerdomain name */ const char *name; - /* the address offset from CM_BASE/PRM_BASE */ - const s16 prcm_offs; - /* Used to represent the OMAP chip types containing this pwrdm */ const struct omap_chip_id omap_chip; + /* the address offset from CM_BASE/PRM_BASE */ + const s16 prcm_offs; + /* Possible powerdomain power states */ const u8 pwrsts; -- GitLab From 915aad89fcc57a03511c69915b3876f4e53074ee Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:02 -0700 Subject: [PATCH 1226/3892] OMAP powerdomain: remove pwrdm_clk_state_switch Nothing calls pwrdm_clk_state_switch(), and the function that seems to be its ideal use case calls pwrdm_clkdm_state_switch(clk->clkdm), so remove it. Signed-off-by: Paul Walmsley Cc: Tero Kristo Cc: Kevin Hilman --- arch/arm/mach-omap2/powerdomain.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index df6446a9c353..9d4b8f5e09b6 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -928,12 +928,6 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm) return -EINVAL; } -int pwrdm_clk_state_switch(struct clk *clk) -{ - if (clk != NULL && clk->clkdm != NULL) - return pwrdm_clkdm_state_switch(clk->clkdm); - return -EINVAL; -} int pwrdm_pre_transition(void) { -- GitLab From f0271d65f9ac511d2e3e1fdbcd7418a5a7df0769 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:02 -0700 Subject: [PATCH 1227/3892] OMAP clockdomain/powerdomain: improve documentation This patch only affects documentation; no functional changes are included. Clean up comments in the current clockdomain, powerdomain code and header files. This mostly involves conversion to kerneldoc format, although some clarifications are also included. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clockdomain.c | 65 ++++---- arch/arm/mach-omap2/powerdomain.c | 149 +++++++++--------- arch/arm/plat-omap/include/plat/clockdomain.h | 87 +++++----- arch/arm/plat-omap/include/plat/powerdomain.h | 40 +++-- 4 files changed, 167 insertions(+), 174 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 6eaa9314cd64..a38a615b422f 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -351,10 +351,10 @@ static void _init_sleepdep_usecount(struct clockdomain *clkdm) * @init_autodeps: optional pointer to an array of autodeps to register * * Set up internal state. If a pointer to an array of clockdomains - * was supplied, loop through the list of clockdomains, register all - * that are available on the current platform. Similarly, if a pointer - * to an array of clockdomain autodependencies was provided, register - * those. No return value. + * @clkdms was supplied, loop through the list of clockdomains, + * register all that are available on the current platform. Similarly, + * if a pointer to an array of clockdomain autodependencies + * @init_autodeps was provided, register those. No return value. */ void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *init_autodeps) @@ -386,8 +386,8 @@ void clkdm_init(struct clockdomain **clkdms, * clkdm_lookup - look up a clockdomain by name, return a pointer * @name: name of clockdomain * - * Find a registered clockdomain by its name. Returns a pointer to the - * struct clockdomain if found, or NULL otherwise. + * Find a registered clockdomain by its name @name. Returns a pointer + * to the struct clockdomain if found, or NULL otherwise. */ struct clockdomain *clkdm_lookup(const char *name) { @@ -412,8 +412,8 @@ struct clockdomain *clkdm_lookup(const char *name) * clkdm_for_each - call function on each registered clockdomain * @fn: callback function * * - * Call the supplied function for each registered clockdomain. - * The callback function can return anything but 0 to bail + * Call the supplied function @fn for each registered clockdomain. + * The callback function @fn can return anything but 0 to bail * out early from the iterator. The callback function is called with * the clkdm_mutex held, so no clockdomain structure manipulation * functions should be called from the callback, although hardware @@ -446,7 +446,7 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), * @clkdm: struct clockdomain * * * Return a pointer to the struct powerdomain that the specified clockdomain - * 'clkdm' exists in, or returns NULL if clkdm argument is NULL. + * @clkdm exists in, or returns NULL if @clkdm is NULL. */ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) { @@ -759,10 +759,10 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) /** * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode - * @clk: struct clk * of a clockdomain + * @clkdm: struct clkdm * of a clockdomain * - * Return the clockdomain's current state transition mode from the - * corresponding domain OMAP2_CM_CLKSTCTRL register. Returns -EINVAL if clk + * Return the clockdomain @clkdm current state transition mode from the + * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if @clkdm * is NULL or the current mode upon success. */ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) @@ -784,7 +784,7 @@ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) * @clkdm: struct clockdomain * * * Instruct the CM to force a sleep transition on the specified - * clockdomain 'clkdm'. Returns -EINVAL if clk is NULL or if + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if * clockdomain does not support software-initiated sleep; 0 upon * success. */ @@ -828,7 +828,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) * @clkdm: struct clockdomain * * * Instruct the CM to force a wakeup transition on the specified - * clockdomain 'clkdm'. Returns -EINVAL if clkdm is NULL or if the + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the * clockdomain does not support software-controlled wakeup; 0 upon * success. */ @@ -871,7 +871,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * * - * Allow the hardware to automatically switch the clockdomain into + * Allow the hardware to automatically switch the clockdomain @clkdm into * active or idle states, as needed by downstream clocks. If the * clockdomain has any downstream clocks enabled in the clock * framework, wkdep/sleepdep autodependencies are added; this is so @@ -904,8 +904,8 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) * @clkdm: struct clockdomain * * * Prevent the hardware from automatically switching the clockdomain - * into inactive or idle states. If the clockdomain has downstream - * clocks enabled in the clock framework, wkdep/sleepdep + * @clkdm into inactive or idle states. If the clockdomain has + * downstream clocks enabled in the clock framework, wkdep/sleepdep * autodependencies are removed. No return value. */ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) @@ -936,14 +936,14 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) * @clkdm: struct clockdomain * * @clk: struct clk * of the enabled downstream clock * - * Increment the usecount of this clockdomain 'clkdm' and ensure that - * it is awake. Intended to be called by clk_enable() code. If the - * clockdomain is in software-supervised idle mode, force the - * clockdomain to wake. If the clockdomain is in hardware-supervised - * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices - * in the clockdomain can be read from/written to by on-chip processors. - * Returns -EINVAL if passed null pointers; returns 0 upon success or - * if the clockdomain is in hwsup idle mode. + * Increment the usecount of the clockdomain @clkdm and ensure that it + * is awake before @clk is enabled. Intended to be called by + * clk_enable() code. If the clockdomain is in software-supervised + * idle mode, force the clockdomain to wake. If the clockdomain is in + * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to + * ensure that devices in the clockdomain can be read from/written to + * by on-chip processors. Returns -EINVAL if passed null pointers; + * returns 0 upon success or if the clockdomain is in hwsup idle mode. */ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) { @@ -988,13 +988,14 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) * @clkdm: struct clockdomain * * @clk: struct clk * of the disabled downstream clock * - * Decrement the usecount of this clockdomain 'clkdm'. Intended to be - * called by clk_disable() code. If the usecount goes to 0, put the - * clockdomain to sleep (software-supervised mode) or remove the - * clkdm-pwrdm autodependencies (hardware-supervised mode). Returns - * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount - * underflows and debugging is enabled; or returns 0 upon success or - * if the clockdomain is in hwsup idle mode. + * Decrement the usecount of this clockdomain @clkdm when @clk is + * disabled. Intended to be called by clk_disable() code. If the + * clockdomain usecount goes to 0, put the clockdomain to sleep + * (software-supervised mode) or remove the clkdm autodependencies + * (hardware-supervised mode). Returns -EINVAL if passed null + * pointers; -ERANGE if the @clkdm usecount underflows and debugging + * is enabled; or returns 0 upon success or if the clockdomain is in + * hwsup idle mode. */ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) { diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 9d4b8f5e09b6..dc03289d5dea 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -185,11 +185,13 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) /** * pwrdm_init - set up the powerdomain layer + * @pwrdm_list: array of struct powerdomain pointers to register * - * Loop through the list of powerdomains, registering all that are - * available on the current CPU. If pwrdm_list is supplied and not - * null, all of the referenced powerdomains will be registered. No - * return value. + * Loop through the array of powerdomains @pwrdm_list, registering all + * that are available on the current CPU. If pwrdm_list is supplied + * and not null, all of the referenced powerdomains will be + * registered. No return value. XXX pwrdm_list is not really a + * "list"; it is an array. Rename appropriately. */ void pwrdm_init(struct powerdomain **pwrdm_list) { @@ -217,8 +219,8 @@ void pwrdm_init(struct powerdomain **pwrdm_list) * pwrdm_lookup - look up a powerdomain by name, return a pointer * @name: name of powerdomain * - * Find a registered powerdomain by its name. Returns a pointer to the - * struct powerdomain if found, or NULL otherwise. + * Find a registered powerdomain by its name @name. Returns a pointer + * to the struct powerdomain if found, or NULL otherwise. */ struct powerdomain *pwrdm_lookup(const char *name) { @@ -236,11 +238,11 @@ struct powerdomain *pwrdm_lookup(const char *name) * pwrdm_for_each - call function on each registered clockdomain * @fn: callback function * * - * Call the supplied function for each registered powerdomain. The - * callback function can return anything but 0 to bail out early from - * the iterator. Returns the last return value of the callback function, which - * should be 0 for success or anything else to indicate failure; or -EINVAL if - * the function pointer is null. + * Call the supplied function @fn for each registered powerdomain. + * The callback function @fn can return anything but 0 to bail out + * early from the iterator. Returns the last return value of the + * callback function, which should be 0 for success or anything else + * to indicate failure; or -EINVAL if the function pointer is null. */ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), void *user) @@ -265,7 +267,7 @@ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), * @pwrdm: struct powerdomain * to add the clockdomain to * @clkdm: struct clockdomain * to associate with a powerdomain * - * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'. This + * Associate the clockdomain @clkdm with a powerdomain @pwrdm. This * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if * presented with invalid pointers; -ENOMEM if memory could not be allocated; * or 0 upon success. @@ -313,10 +315,10 @@ pac_exit: * @pwrdm: struct powerdomain * to add the clockdomain to * @clkdm: struct clockdomain * to associate with a powerdomain * - * Dissociate the clockdomain 'clkdm' from the powerdomain - * 'pwrdm'. Returns -EINVAL if presented with invalid pointers; - * -ENOENT if the clkdm was not associated with the powerdomain, or 0 - * upon success. + * Dissociate the clockdomain @clkdm from the powerdomain + * @pwrdm. Returns -EINVAL if presented with invalid pointers; -ENOENT + * if @clkdm was not associated with the powerdomain, or 0 upon + * success. */ int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) { @@ -353,8 +355,8 @@ pdc_exit: * @pwrdm: struct powerdomain * to iterate over * @fn: callback function * * - * Call the supplied function for each clockdomain in the powerdomain - * 'pwrdm'. The callback function can return anything but 0 to bail + * Call the supplied function @fn for each clockdomain in the powerdomain + * @pwrdm. The callback function can return anything but 0 to bail * out early from the iterator. Returns -EINVAL if presented with * invalid pointers; or passes along the last return value of the * callback function, which should be 0 for success or anything else @@ -380,7 +382,7 @@ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain * @pwrdm: struct powerdomain * * - * Return the number of controllable memory banks in powerdomain pwrdm, + * Return the number of controllable memory banks in powerdomain @pwrdm, * starting with 1. Returns -EINVAL if the powerdomain pointer is null. */ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) @@ -396,7 +398,7 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) * @pwrdm: struct powerdomain * to set * @pwrst: one of the PWRDM_POWER_* macros * - * Set the powerdomain pwrdm's next power state to pwrst. The powerdomain + * Set the powerdomain @pwrdm's next power state to @pwrst. The powerdomain * may not enter this state immediately if the preconditions for this state * have not been satisfied. Returns -EINVAL if the powerdomain pointer is * null or if the power state is invalid for the powerdomin, or returns 0 @@ -424,7 +426,7 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) * pwrdm_read_next_pwrst - get next powerdomain power state * @pwrdm: struct powerdomain * to get power state * - * Return the powerdomain pwrdm's next power state. Returns -EINVAL + * Return the powerdomain @pwrdm's next power state. Returns -EINVAL * if the powerdomain pointer is null or returns the next power state * upon success. */ @@ -441,7 +443,7 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) * pwrdm_read_pwrst - get current powerdomain power state * @pwrdm: struct powerdomain * to get power state * - * Return the powerdomain pwrdm's current power state. Returns -EINVAL + * Return the powerdomain @pwrdm's current power state. Returns -EINVAL * if the powerdomain pointer is null or returns the current power state * upon success. */ @@ -458,7 +460,7 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm) * pwrdm_read_prev_pwrst - get previous powerdomain power state * @pwrdm: struct powerdomain * to get previous power state * - * Return the powerdomain pwrdm's previous power state. Returns -EINVAL + * Return the powerdomain @pwrdm's previous power state. Returns -EINVAL * if the powerdomain pointer is null or returns the previous power state * upon success. */ @@ -476,11 +478,11 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) * @pwrdm: struct powerdomain * to set * @pwrst: one of the PWRDM_POWER_* macros * - * Set the next power state that the logic portion of the powerdomain - * pwrdm will enter when the powerdomain enters retention. This will - * be either RETENTION or OFF, if supported. Returns -EINVAL if the - * powerdomain pointer is null or the target power state is not not - * supported, or returns 0 upon success. + * Set the next power state @pwrst that the logic portion of the + * powerdomain @pwrdm will enter when the powerdomain enters retention. + * This will be either RETENTION or OFF, if supported. Returns + * -EINVAL if the powerdomain pointer is null or the target power + * state is not not supported, or returns 0 upon success. */ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) { @@ -512,13 +514,14 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) * @bank: memory bank number to set (0-3) * @pwrst: one of the PWRDM_POWER_* macros * - * Set the next power state that memory bank x of the powerdomain - * pwrdm will enter when the powerdomain enters the ON state. Bank - * will be a number from 0 to 3, and represents different types of - * memory, depending on the powerdomain. Returns -EINVAL if the - * powerdomain pointer is null or the target power state is not not - * supported for this memory bank, -EEXIST if the target memory bank - * does not exist or is not controllable, or returns 0 upon success. + * Set the next power state @pwrst that memory bank @bank of the + * powerdomain @pwrdm will enter when the powerdomain enters the ON + * state. @bank will be a number from 0 to 3, and represents different + * types of memory, depending on the powerdomain. Returns -EINVAL if + * the powerdomain pointer is null or the target power state is not + * not supported for this memory bank, -EEXIST if the target memory + * bank does not exist or is not controllable, or returns 0 upon + * success. */ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) { @@ -575,14 +578,15 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) * @bank: memory bank number to set (0-3) * @pwrst: one of the PWRDM_POWER_* macros * - * Set the next power state that memory bank x of the powerdomain - * pwrdm will enter when the powerdomain enters the RETENTION state. - * Bank will be a number from 0 to 3, and represents different types - * of memory, depending on the powerdomain. pwrst will be either - * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain - * pointer is null or the target power state is not not supported for - * this memory bank, -EEXIST if the target memory bank does not exist - * or is not controllable, or returns 0 upon success. + * Set the next power state @pwrst that memory bank @bank of the + * powerdomain @pwrdm will enter when the powerdomain enters the + * RETENTION state. Bank will be a number from 0 to 3, and represents + * different types of memory, depending on the powerdomain. @pwrst + * will be either RETENTION or OFF, if supported. Returns -EINVAL if + * the powerdomain pointer is null or the target power state is not + * not supported for this memory bank, -EEXIST if the target memory + * bank does not exist or is not controllable, or returns 0 upon + * success. */ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) { @@ -637,10 +641,10 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state * @pwrdm: struct powerdomain * to get current logic retention power state * - * Return the current power state that the logic portion of - * powerdomain pwrdm will enter - * Returns -EINVAL if the powerdomain pointer is null or returns the - * current logic retention power state upon success. + * Return the power state that the logic portion of powerdomain @pwrdm + * will enter when the powerdomain enters retention. Returns -EINVAL + * if the powerdomain pointer is null or returns the logic retention + * power state upon success. */ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) { @@ -655,9 +659,9 @@ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state * @pwrdm: struct powerdomain * to get previous logic power state * - * Return the powerdomain pwrdm's logic power state. Returns -EINVAL - * if the powerdomain pointer is null or returns the previous logic - * power state upon success. + * Return the powerdomain @pwrdm's previous logic power state. Returns + * -EINVAL if the powerdomain pointer is null or returns the previous + * logic power state upon success. */ int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm) { @@ -679,8 +683,8 @@ int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm) * @pwrdm: struct powerdomain * to get current memory bank power state * @bank: memory bank number (0-3) * - * Return the powerdomain pwrdm's current memory power state for bank - * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if + * Return the powerdomain @pwrdm's current memory power state for bank + * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if * the target memory bank does not exist or is not controllable, or * returns the current memory power state upon success. */ @@ -733,10 +737,11 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) * @pwrdm: struct powerdomain * to get previous memory bank power state * @bank: memory bank number (0-3) * - * Return the powerdomain pwrdm's previous memory power state for bank - * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if - * the target memory bank does not exist or is not controllable, or - * returns the previous memory power state upon success. + * Return the powerdomain @pwrdm's previous memory power state for + * bank @bank. Returns -EINVAL if the powerdomain pointer is null, + * -EEXIST if the target memory bank does not exist or is not + * controllable, or returns the previous memory power state upon + * success. */ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) { @@ -783,10 +788,10 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm * @pwrdm: struct powerdomain * to clear * - * Clear the powerdomain's previous power state register. Clears the - * entire register, including logic and memory bank previous power states. - * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon - * success. + * Clear the powerdomain's previous power state register @pwrdm. + * Clears the entire register, including logic and memory bank + * previous power states. Returns -EINVAL if the powerdomain pointer + * is null, or returns 0 upon success. */ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) { @@ -811,11 +816,11 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) * @pwrdm: struct powerdomain * * * Enable automatic context save-and-restore upon power state change - * for some devices in a powerdomain. Warning: this only affects a - * subset of devices in a powerdomain; check the TRM closely. Returns - * -EINVAL if the powerdomain pointer is null or if the powerdomain - * does not support automatic save-and-restore, or returns 0 upon - * success. + * for some devices in the powerdomain @pwrdm. Warning: this only + * affects a subset of devices in a powerdomain; check the TRM + * closely. Returns -EINVAL if the powerdomain pointer is null or if + * the powerdomain does not support automatic save-and-restore, or + * returns 0 upon success. */ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) { @@ -839,11 +844,11 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) * @pwrdm: struct powerdomain * * * Disable automatic context save-and-restore upon power state change - * for some devices in a powerdomain. Warning: this only affects a - * subset of devices in a powerdomain; check the TRM closely. Returns - * -EINVAL if the powerdomain pointer is null or if the powerdomain - * does not support automatic save-and-restore, or returns 0 upon - * success. + * for some devices in the powerdomain @pwrdm. Warning: this only + * affects a subset of devices in a powerdomain; check the TRM + * closely. Returns -EINVAL if the powerdomain pointer is null or if + * the powerdomain does not support automatic save-and-restore, or + * returns 0 upon success. */ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) { @@ -866,7 +871,7 @@ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR * @pwrdm: struct powerdomain * * - * Returns 1 if powerdomain 'pwrdm' supports hardware save-and-restore + * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore * for some devices, or 0 if it does not. */ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) @@ -878,7 +883,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) * pwrdm_wait_transition - wait for powerdomain power transition to finish * @pwrdm: struct powerdomain * to wait for * - * If the powerdomain pwrdm is in the process of a state transition, + * If the powerdomain @pwrdm is in the process of a state transition, * spin until it completes the power transition, or until an iteration * bailout value is reached. Returns -EINVAL if the powerdomain * pointer is null, -EAGAIN if the bailout value was reached, or diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index 45b5debc5d3f..ba0a6c07c0fe 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -40,86 +40,77 @@ #define OMAP34XX_CLKSTCTRL_FORCE_WAKEUP 0x2 #define OMAP34XX_CLKSTCTRL_ENABLE_AUTO 0x3 -/* - * struct clkdm_autodep - a clockdomain that should have wkdeps - * and sleepdeps added when a clockdomain should stay active in hwsup mode; - * and conversely, removed when the clockdomain should be allowed to go - * inactive in hwsup mode. +/** + * struct clkdm_autodep - clkdm deps to add when entering/exiting hwsup mode + * @clkdm: clockdomain to add wkdep+sleepdep on - set name member only + * @omap_chip: OMAP chip types that this autodep is valid on + * + * A clockdomain that should have wkdeps and sleepdeps added when a + * clockdomain should stay active in hwsup mode; and conversely, + * removed when the clockdomain should be allowed to go inactive in + * hwsup mode. + * + * Autodeps are deprecated and should be removed after + * omap_hwmod-based fine-grained module idle control is added. */ struct clkdm_autodep { - union { - /* Name of the clockdomain to add a wkdep/sleepdep on */ const char *name; - - /* Clockdomain pointer (looked up at clkdm_init() time) */ struct clockdomain *ptr; } clkdm; - - /* OMAP chip types that this clockdomain dep is valid on */ const struct omap_chip_id omap_chip; - }; -/* Encodes dependencies between clockdomains - statically defined */ +/** + * struct clkdm_dep - encode dependencies between clockdomains + * @clkdm_name: clockdomain name + * @clkdm: pointer to the struct clockdomain of @clkdm_name + * @omap_chip: OMAP chip types that this dependency is valid on + * @wkdep_usecount: Number of wakeup dependencies causing this clkdm to wake + * @sleepdep_usecount: Number of sleep deps that could prevent clkdm from idle + * + * Statically defined. @clkdm is resolved from @clkdm_name at runtime and + * should not be pre-initialized. + * + * XXX Should also include hardware (fixed) dependencies. + */ struct clkdm_dep { - - /* Clockdomain name */ const char *clkdm_name; - - /* Clockdomain pointer - resolved by the clockdomain code */ struct clockdomain *clkdm; - - /* Number of wakeup dependencies causing this clkdm to wake */ atomic_t wkdep_usecount; - - /* Number of sleep dependencies that could prevent clkdm from idle */ atomic_t sleepdep_usecount; - - /* Flags to mark OMAP chip restrictions, etc. */ const struct omap_chip_id omap_chip; - }; +/** + * struct clockdomain - OMAP clockdomain + * @name: clockdomain name + * @pwrdm: powerdomain containing this clockdomain + * @clktrctrl_reg: CLKSTCTRL reg for the given clock domain + * @clktrctrl_mask: CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg + * @flags: Clockdomain capability flags + * @dep_bit: Bit shift of this clockdomain's PM_WKDEP/CM_SLEEPDEP bit + * @wkdep_srcs: Clockdomains that can be told to wake this powerdomain up + * @sleepdep_srcs: Clockdomains that can be told to keep this clkdm from inact + * @omap_chip: OMAP chip types that this clockdomain is valid on + * @usecount: Usecount tracking + * @node: list_head to link all clockdomains together + */ struct clockdomain { - - /* Clockdomain name */ const char *name; - union { - /* Powerdomain enclosing this clockdomain */ const char *name; - - /* Powerdomain pointer assigned at clkdm_register() */ struct powerdomain *ptr; } pwrdm; - - /* CLKSTCTRL reg for the given clock domain*/ void __iomem *clkstctrl_reg; - - /* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */ const u16 clktrctrl_mask; - - /* Clockdomain capability flags */ const u8 flags; - - /* Bit shift of this clockdomain's PM_WKDEP/CM_SLEEPDEP bit */ const u8 dep_bit; - - /* Clockdomains that can be told to wake this powerdomain up */ struct clkdm_dep *wkdep_srcs; - - /* Clockdomains that can be told to keep this clkdm from inactivity */ struct clkdm_dep *sleepdep_srcs; - - /* OMAP chip types that this clockdomain is valid on */ const struct omap_chip_id omap_chip; - - /* Usecount tracking */ atomic_t usecount; - struct list_head node; - }; void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *autodeps); diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index 87e13f88994f..e15c7e9da975 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -68,40 +68,36 @@ struct clockdomain; struct powerdomain; +/** + * struct powerdomain - OMAP powerdomain + * @name: Powerdomain name + * @omap_chip: represents the OMAP chip types containing this pwrdm + * @prcm_offs: the address offset from CM_BASE/PRM_BASE + * @pwrsts: Possible powerdomain power states + * @pwrsts_logic_ret: Possible logic power states when pwrdm in RETENTION + * @flags: Powerdomain flags + * @banks: Number of software-controllable memory banks in this powerdomain + * @pwrsts_mem_ret: Possible memory bank pwrstates when pwrdm in RETENTION + * @pwrsts_mem_on: Possible memory bank pwrstates when pwrdm in ON + * @pwrdm_clkdms: Clockdomains in this powerdomain + * @node: list_head linking all powerdomains + * @state: + * @state_counter: + * @timer: + * @state_timer: + */ struct powerdomain { - - /* Powerdomain name */ const char *name; - - /* Used to represent the OMAP chip types containing this pwrdm */ const struct omap_chip_id omap_chip; - - /* the address offset from CM_BASE/PRM_BASE */ const s16 prcm_offs; - - /* Possible powerdomain power states */ const u8 pwrsts; - - /* Possible logic power states when pwrdm in RETENTION */ const u8 pwrsts_logic_ret; - - /* Powerdomain flags */ const u8 flags; - - /* Number of software-controllable memory banks in this powerdomain */ const u8 banks; - - /* Possible memory bank pwrstates when pwrdm in RETENTION */ const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS]; - - /* Possible memory bank pwrstates when pwrdm is ON */ const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS]; - - /* Clockdomains in this powerdomain */ struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; - struct list_head node; - int state; unsigned state_counter[PWRDM_MAX_PWRSTS]; -- GitLab From 9799aca2032ad53418ff4bc0d1a6f2cb4f79b6c0 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 26 Jan 2010 20:13:02 -0700 Subject: [PATCH 1228/3892] OMAP: omap_device: optionally auto-adjust device activate/deactivate latencies First, this patch adds new worst-case latency values to the omap_device_pm_latency struct. Here the worst-case measured latencies for the activate and deactivate hooks are stored. In addition, add an option to auto-adjust the latency values used for device activate/deactivate. By setting a new 'OMAP_DEVICE_LATENCY_AUTO_ADJUST' flag in the omap_device_pm_latency struct, the omap_device layer automatically adjusts the activate/deactivate latencies to the worst-case measured values. Anytime a new worst-case value is found, it is printed to the console. Here is an example log during boot using UART2 s an example. After boot, the OPP is manually changed to the 125MHz OPP: [...] Freeing init memory: 128K omap_device: serial8250.2: new worst case deactivate latency 0: 30517 omap_device: serial8250.2: new worst case activate latency 0: 30517 omap_device: serial8250.2: new worst case activate latency 0: 218139648 omap_device: serial8250.2: new worst case deactivate latency 0: 61035 omap_device: serial8250.2: new worst case activate latency 0: 278076171 omap_device: serial8250.2: new worst case activate latency 0: 298614501 omap_device: serial8250.2: new worst case activate latency 0: 327331542 / # echo 125000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed omap_device: serial8250.2: new worst case deactivate latency 0: 91552 Motivation: this can be used as a technique to automatically determine the worst case latency values. The current method of printing a warning on every violation is too noisy to actually interact the console in order to set low OPP to discover latencies. Another motivation for this patch is that the activate/deactivate latenices can vary depending on the idlemode of the device. While working on the UARTs, I noticed that when using no-idle, the activate latencies were as high as several hundred msecs as shown above. When the UARTs are in smart-idle, the max latency is well under 100 usecs. Signed-off-by: Kevin Hilman Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/include/plat/omap_device.h | 4 ++ arch/arm/plat-omap/omap_device.c | 41 +++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h index dc1fac1d805c..76d49171fed9 100644 --- a/arch/arm/plat-omap/include/plat/omap_device.h +++ b/arch/arm/plat-omap/include/plat/omap_device.h @@ -131,11 +131,15 @@ int omap_device_enable_clocks(struct omap_device *od); */ struct omap_device_pm_latency { u32 deactivate_lat; + u32 deactivate_lat_worst; int (*deactivate_func)(struct omap_device *od); u32 activate_lat; + u32 activate_lat_worst; int (*activate_func)(struct omap_device *od); + u32 flags; }; +#define OMAP_DEVICE_LATENCY_AUTO_ADJUST BIT(1) /* Get omap_device pointer from platform_device pointer */ #define to_omap_device(x) container_of((x), struct omap_device, pdev) diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 1e5648d3e3d8..d8c75c8f78d7 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -148,10 +148,22 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat) "%llu nsec\n", od->pdev.name, od->pm_lat_level, act_lat); - WARN(act_lat > odpl->activate_lat, "omap_device: %s.%d: " - "activate step %d took longer than expected (%llu > %d)\n", - od->pdev.name, od->pdev.id, od->pm_lat_level, - act_lat, odpl->activate_lat); + if (act_lat > odpl->activate_lat) { + odpl->activate_lat_worst = act_lat; + if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { + odpl->activate_lat = act_lat; + pr_warning("omap_device: %s.%d: new worst case " + "activate latency %d: %llu\n", + od->pdev.name, od->pdev.id, + od->pm_lat_level, act_lat); + } else + pr_warning("omap_device: %s.%d: activate " + "latency %d higher than exptected. " + "(%llu > %d)\n", + od->pdev.name, od->pdev.id, + od->pm_lat_level, act_lat, + odpl->activate_lat); + } od->dev_wakeup_lat -= odpl->activate_lat; } @@ -204,10 +216,23 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat) "%llu nsec\n", od->pdev.name, od->pm_lat_level, deact_lat); - WARN(deact_lat > odpl->deactivate_lat, "omap_device: %s.%d: " - "deactivate step %d took longer than expected " - "(%llu > %d)\n", od->pdev.name, od->pdev.id, - od->pm_lat_level, deact_lat, odpl->deactivate_lat); + if (deact_lat > odpl->deactivate_lat) { + odpl->deactivate_lat_worst = deact_lat; + if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { + odpl->deactivate_lat = deact_lat; + pr_warning("omap_device: %s.%d: new worst case " + "deactivate latency %d: %llu\n", + od->pdev.name, od->pdev.id, + od->pm_lat_level, deact_lat); + } else + pr_warning("omap_device: %s.%d: deactivate " + "latency %d higher than exptected. " + "(%llu > %d)\n", + od->pdev.name, od->pdev.id, + od->pm_lat_level, deact_lat, + odpl->deactivate_lat); + } + od->dev_wakeup_lat += odpl->activate_lat; -- GitLab From 46273e6f37bdf3801363986e2228350ecad19059 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 26 Jan 2010 20:13:03 -0700 Subject: [PATCH 1229/3892] OMAP: hwmod: add API for slave idlemode setting Some HW blocks have errata which requires specific slave idle mode under certain conditions. This patch adds an hwmod API to allow setting slave idlemode ensuring that any SYSCONFIG register updates go through hwmod. Signed-off-by: Kevin Hilman Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 17 +++++++++++++++++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index ad884c0aaa42..70912d1c71e0 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -992,6 +992,23 @@ void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs) __raw_writel(v, oh->_rt_va + reg_offs); } +int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) +{ + u32 v; + int retval = 0; + + if (!oh) + return -EINVAL; + + v = oh->_sysc_cache; + + retval = _set_slave_idlemode(oh, idlemode, &v); + if (!retval) + _write_sysconfig(v, oh); + + return retval; +} + /** * omap_hwmod_register - register a struct omap_hwmod * @oh: struct omap_hwmod * diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 33933256a226..921990e2a29a 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -441,6 +441,8 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh); int omap_hwmod_enable_clocks(struct omap_hwmod *oh); int omap_hwmod_disable_clocks(struct omap_hwmod *oh); +int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode); + int omap_hwmod_reset(struct omap_hwmod *oh); void omap_hwmod_ocp_barrier(struct omap_hwmod *oh); -- GitLab From 98c4545749234393ec918b703f48eb708658a23d Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:03 -0700 Subject: [PATCH 1230/3892] OMAP3 clock: move OMAP3-specific DPLL functions to dpll3xxx.c Mark the OMAP3-specific DPLL functions as being OMAP3-specific by moving them from mach-omap2/dpll.c to mach-omap2/dpll3xxx.c. Signed-off-by: Paul Walmsley Cc: Rajendra Nayak --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/{dpll.c => dpll3xxx.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arm/mach-omap2/{dpll.c => dpll3xxx.c} (100%) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 64de2fdf6556..7d46fde2ce67 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -6,7 +6,7 @@ obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o omap-2-3-common = irq.o sdrc.o omap_hwmod.o -omap-3-4-common = dpll.o +omap-3-4-common = dpll3xxx.o prcm-common = prcm.o powerdomain.o clock-common = clock.o clock_common_data.o clockdomain.o diff --git a/arch/arm/mach-omap2/dpll.c b/arch/arm/mach-omap2/dpll3xxx.c similarity index 100% rename from arch/arm/mach-omap2/dpll.c rename to arch/arm/mach-omap2/dpll3xxx.c -- GitLab From 0b96af683026ab9ca4dd52f9005a1a4fc582e914 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:03 -0700 Subject: [PATCH 1231/3892] OMAP2/3/4 clock: move DPLL clock functions into mach-omap2/clkt_dpll.c Move all DPLL-related clock functions from mach-omap2/clock.c to mach-omap2/clkt_dpll.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage DPLLs are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for DPLLs alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be moved to the plat-omap/ directory to be shared. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt_dpll.c | 386 ++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock.c | 355 ----------------------------- 3 files changed, 388 insertions(+), 356 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt_dpll.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 7d46fde2ce67..1a135c8e7f1e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -8,7 +8,8 @@ obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o omap-2-3-common = irq.o sdrc.o omap_hwmod.o omap-3-4-common = dpll3xxx.o prcm-common = prcm.o powerdomain.o -clock-common = clock.o clock_common_data.o clockdomain.o +clock-common = clock.o clock_common_data.o \ + clockdomain.o clkt_dpll.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c new file mode 100644 index 000000000000..9eee0e67d5d6 --- /dev/null +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -0,0 +1,386 @@ +/* + * OMAP2/3/4 DPLL clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include + +#include + +#include "clock.h" +#include "cm.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" + +/* DPLL rate rounding: minimum DPLL multiplier, divider values */ +#define DPLL_MIN_MULTIPLIER 1 +#define DPLL_MIN_DIVIDER 1 + +/* Possible error results from _dpll_test_mult */ +#define DPLL_MULT_UNDERFLOW -1 + +/* + * Scale factor to mitigate roundoff errors in DPLL rate rounding. + * The higher the scale factor, the greater the risk of arithmetic overflow, + * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR + * must be a power of DPLL_SCALE_BASE. + */ +#define DPLL_SCALE_FACTOR 64 +#define DPLL_SCALE_BASE 2 +#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ + (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) + +/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ +#define DPLL_FINT_BAND1_MIN 750000 +#define DPLL_FINT_BAND1_MAX 2100000 +#define DPLL_FINT_BAND2_MIN 7500000 +#define DPLL_FINT_BAND2_MAX 21000000 + +/* _dpll_test_fint() return codes */ +#define DPLL_FINT_UNDERFLOW -1 +#define DPLL_FINT_INVALID -2 + +/* Private functions */ + +/* + * _dpll_test_fint - test whether an Fint value is valid for the DPLL + * @clk: DPLL struct clk to test + * @n: divider value (N) to test + * + * Tests whether a particular divider @n will result in a valid DPLL + * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter + * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate + * (assuming that it is counting N upwards), or -2 if the enclosing loop + * should skip to the next iteration (again assuming N is increasing). + */ +static int _dpll_test_fint(struct clk *clk, u8 n) +{ + struct dpll_data *dd; + long fint; + int ret = 0; + + dd = clk->dpll_data; + + /* DPLL divider must result in a valid jitter correction val */ + fint = clk->parent->rate / (n + 1); + if (fint < DPLL_FINT_BAND1_MIN) { + + pr_debug("rejecting n=%d due to Fint failure, " + "lowering max_divider\n", n); + dd->max_divider = n; + ret = DPLL_FINT_UNDERFLOW; + + } else if (fint > DPLL_FINT_BAND1_MAX && + fint < DPLL_FINT_BAND2_MIN) { + + pr_debug("rejecting n=%d due to Fint failure\n", n); + ret = DPLL_FINT_INVALID; + + } else if (fint > DPLL_FINT_BAND2_MAX) { + + pr_debug("rejecting n=%d due to Fint failure, " + "boosting min_divider\n", n); + dd->min_divider = n; + ret = DPLL_FINT_INVALID; + + } + + return ret; +} + +static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, + unsigned int m, unsigned int n) +{ + unsigned long long num; + + num = (unsigned long long)parent_rate * m; + do_div(num, n); + return num; +} + +/* + * _dpll_test_mult - test a DPLL multiplier value + * @m: pointer to the DPLL m (multiplier) value under test + * @n: current DPLL n (divider) value under test + * @new_rate: pointer to storage for the resulting rounded rate + * @target_rate: the desired DPLL rate + * @parent_rate: the DPLL's parent clock rate + * + * This code tests a DPLL multiplier value, ensuring that the + * resulting rate will not be higher than the target_rate, and that + * the multiplier value itself is valid for the DPLL. Initially, the + * integer pointed to by the m argument should be prescaled by + * multiplying by DPLL_SCALE_FACTOR. The code will replace this with + * a non-scaled m upon return. This non-scaled m will result in a + * new_rate as close as possible to target_rate (but not greater than + * target_rate) given the current (parent_rate, n, prescaled m) + * triple. Returns DPLL_MULT_UNDERFLOW in the event that the + * non-scaled m attempted to underflow, which can allow the calling + * function to bail out early; or 0 upon success. + */ +static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, + unsigned long target_rate, + unsigned long parent_rate) +{ + int r = 0, carry = 0; + + /* Unscale m and round if necessary */ + if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) + carry = 1; + *m = (*m / DPLL_SCALE_FACTOR) + carry; + + /* + * The new rate must be <= the target rate to avoid programming + * a rate that is impossible for the hardware to handle + */ + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + if (*new_rate > target_rate) { + (*m)--; + *new_rate = 0; + } + + /* Guard against m underflow */ + if (*m < DPLL_MIN_MULTIPLIER) { + *m = DPLL_MIN_MULTIPLIER; + *new_rate = 0; + r = DPLL_MULT_UNDERFLOW; + } + + if (*new_rate == 0) + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + + return r; +} + +/* Public functions */ + +void omap2_init_dpll_parent(struct clk *clk) +{ + u32 v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return; + + /* Return bypass rate if DPLL is bypassed */ + v = __raw_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + /* Reparent in case the dpll is in bypass */ + if (cpu_is_omap24xx()) { + if (v == OMAP2XXX_EN_DPLL_LPBYPASS || + v == OMAP2XXX_EN_DPLL_FRBYPASS) + clk_reparent(clk, dd->clk_bypass); + } else if (cpu_is_omap34xx()) { + if (v == OMAP3XXX_EN_DPLL_LPBYPASS || + v == OMAP3XXX_EN_DPLL_FRBYPASS) + clk_reparent(clk, dd->clk_bypass); + } else if (cpu_is_omap44xx()) { + if (v == OMAP4XXX_EN_DPLL_LPBYPASS || + v == OMAP4XXX_EN_DPLL_FRBYPASS || + v == OMAP4XXX_EN_DPLL_MNBYPASS) + clk_reparent(clk, dd->clk_bypass); + } + return; +} + +/** + * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate + * @clk: struct clk * of a DPLL + * + * DPLLs can be locked or bypassed - basically, enabled or disabled. + * When locked, the DPLL output depends on the M and N values. When + * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock + * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and + * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively + * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. + * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is + * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 + * if the clock @clk is not a DPLL. + */ +u32 omap2_get_dpll_rate(struct clk *clk) +{ + long long dpll_clk; + u32 dpll_mult, dpll_div, v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return 0; + + /* Return bypass rate if DPLL is bypassed */ + v = __raw_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + if (cpu_is_omap24xx()) { + if (v == OMAP2XXX_EN_DPLL_LPBYPASS || + v == OMAP2XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } else if (cpu_is_omap34xx()) { + if (v == OMAP3XXX_EN_DPLL_LPBYPASS || + v == OMAP3XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } else if (cpu_is_omap44xx()) { + if (v == OMAP4XXX_EN_DPLL_LPBYPASS || + v == OMAP4XXX_EN_DPLL_FRBYPASS || + v == OMAP4XXX_EN_DPLL_MNBYPASS) + return dd->clk_bypass->rate; + } + + v = __raw_readl(dd->mult_div1_reg); + dpll_mult = v & dd->mult_mask; + dpll_mult >>= __ffs(dd->mult_mask); + dpll_div = v & dd->div1_mask; + dpll_div >>= __ffs(dd->div1_mask); + + dpll_clk = (long long)dd->clk_ref->rate * dpll_mult; + do_div(dpll_clk, dpll_div + 1); + + return dpll_clk; +} + +/* DPLL rate rounding code */ + +/** + * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding + * @clk: struct clk * of the DPLL + * @tolerance: maximum rate error tolerance + * + * Set the maximum DPLL rate error tolerance for the rate rounding + * algorithm. The rate tolerance is an attempt to balance DPLL power + * saving (the least divider value "n") vs. rate fidelity (the least + * difference between the desired DPLL target rate and the rounded + * rate out of the algorithm). So, increasing the tolerance is likely + * to decrease DPLL power consumption and increase DPLL rate error. + * Returns -EINVAL if provided a null clock ptr or a clk that is not a + * DPLL; or 0 upon success. + */ +int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance) +{ + if (!clk || !clk->dpll_data) + return -EINVAL; + + clk->dpll_data->rate_tolerance = tolerance; + + return 0; +} + +/** + * omap2_dpll_round_rate - round a target rate for an OMAP DPLL + * @clk: struct clk * for a DPLL + * @target_rate: desired DPLL clock rate + * + * Given a DPLL, a desired target rate, and a rate tolerance, round + * the target rate to a possible, programmable rate for this DPLL. + * Rate tolerance is assumed to be set by the caller before this + * function is called. Attempts to select the minimum possible n + * within the tolerance to reduce power consumption. Stores the + * computed (m, n) in the DPLL's dpll_data structure so set_rate() + * will not need to call this (expensive) function again. Returns ~0 + * if the target rate cannot be rounded, either because the rate is + * too low or because the rate tolerance is set too tightly; or the + * rounded rate upon success. + */ +long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) +{ + int m, n, r, e, scaled_max_m; + unsigned long scaled_rt_rp, new_rate; + int min_e = -1, min_e_m = -1, min_e_n = -1; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return ~0; + + dd = clk->dpll_data; + + pr_debug("clock: starting DPLL round_rate for clock %s, target rate " + "%ld\n", clk->name, target_rate); + + scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); + scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; + + dd->last_rounded_rate = 0; + + for (n = dd->min_divider; n <= dd->max_divider; n++) { + + /* Is the (input clk, divider) pair valid for the DPLL? */ + r = _dpll_test_fint(clk, n); + if (r == DPLL_FINT_UNDERFLOW) + break; + else if (r == DPLL_FINT_INVALID) + continue; + + /* Compute the scaled DPLL multiplier, based on the divider */ + m = scaled_rt_rp * n; + + /* + * Since we're counting n up, a m overflow means we + * can bail out completely (since as n increases in + * the next iteration, there's no way that m can + * increase beyond the current m) + */ + if (m > scaled_max_m) + break; + + r = _dpll_test_mult(&m, n, &new_rate, target_rate, + dd->clk_ref->rate); + + /* m can't be set low enough for this n - try with a larger n */ + if (r == DPLL_MULT_UNDERFLOW) + continue; + + e = target_rate - new_rate; + pr_debug("clock: n = %d: m = %d: rate error is %d " + "(new_rate = %ld)\n", n, m, e, new_rate); + + if (min_e == -1 || + min_e >= (int)(abs(e) - dd->rate_tolerance)) { + min_e = e; + min_e_m = m; + min_e_n = n; + + pr_debug("clock: found new least error %d\n", min_e); + + /* We found good settings -- bail out now */ + if (min_e <= dd->rate_tolerance) + break; + } + } + + if (min_e < 0) { + pr_debug("clock: error: target rate or tolerance too low\n"); + return ~0; + } + + dd->last_rounded_m = min_e_m; + dd->last_rounded_n = min_e_n; + dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, + min_e_m, min_e_n); + + pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", + min_e, min_e_m, min_e_n); + pr_debug("clock: final rate: %ld (target rate: %ld)\n", + dd->last_rounded_rate, target_rate); + + return dd->last_rounded_rate; +} + diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index d88b25565a42..98196285e80c 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -28,10 +28,7 @@ #include #include #include -#include -#include -#include "sdrc.h" #include "clock.h" #include "prm.h" #include "prm-regbits-24xx.h" @@ -39,72 +36,12 @@ #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" -/* DPLL rate rounding: minimum DPLL multiplier, divider values */ -#define DPLL_MIN_MULTIPLIER 1 -#define DPLL_MIN_DIVIDER 1 - -/* Possible error results from _dpll_test_mult */ -#define DPLL_MULT_UNDERFLOW -1 - -/* - * Scale factor to mitigate roundoff errors in DPLL rate rounding. - * The higher the scale factor, the greater the risk of arithmetic overflow, - * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR - * must be a power of DPLL_SCALE_BASE. - */ -#define DPLL_SCALE_FACTOR 64 -#define DPLL_SCALE_BASE 2 -#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ - (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) - -/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ -#define DPLL_FINT_BAND1_MIN 750000 -#define DPLL_FINT_BAND1_MAX 2100000 -#define DPLL_FINT_BAND2_MIN 7500000 -#define DPLL_FINT_BAND2_MAX 21000000 - -/* _dpll_test_fint() return codes */ -#define DPLL_FINT_UNDERFLOW -1 -#define DPLL_FINT_INVALID -2 - u8 cpu_mask; /*------------------------------------------------------------------------- * OMAP2/3/4 specific clock functions *-------------------------------------------------------------------------*/ -void omap2_init_dpll_parent(struct clk *clk) -{ - u32 v; - struct dpll_data *dd; - - dd = clk->dpll_data; - if (!dd) - return; - - /* Return bypass rate if DPLL is bypassed */ - v = __raw_readl(dd->control_reg); - v &= dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - /* Reparent in case the dpll is in bypass */ - if (cpu_is_omap24xx()) { - if (v == OMAP2XXX_EN_DPLL_LPBYPASS || - v == OMAP2XXX_EN_DPLL_FRBYPASS) - clk_reparent(clk, dd->clk_bypass); - } else if (cpu_is_omap34xx()) { - if (v == OMAP3XXX_EN_DPLL_LPBYPASS || - v == OMAP3XXX_EN_DPLL_FRBYPASS) - clk_reparent(clk, dd->clk_bypass); - } else if (cpu_is_omap44xx()) { - if (v == OMAP4XXX_EN_DPLL_LPBYPASS || - v == OMAP4XXX_EN_DPLL_FRBYPASS || - v == OMAP4XXX_EN_DPLL_MNBYPASS) - clk_reparent(clk, dd->clk_bypass); - } - return; -} - /** * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware * @clk: struct clk * @@ -127,52 +64,6 @@ static void _omap2xxx_clk_commit(struct clk *clk) prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); } -/* - * _dpll_test_fint - test whether an Fint value is valid for the DPLL - * @clk: DPLL struct clk to test - * @n: divider value (N) to test - * - * Tests whether a particular divider @n will result in a valid DPLL - * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter - * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate - * (assuming that it is counting N upwards), or -2 if the enclosing loop - * should skip to the next iteration (again assuming N is increasing). - */ -static int _dpll_test_fint(struct clk *clk, u8 n) -{ - struct dpll_data *dd; - long fint; - int ret = 0; - - dd = clk->dpll_data; - - /* DPLL divider must result in a valid jitter correction val */ - fint = clk->parent->rate / (n + 1); - if (fint < DPLL_FINT_BAND1_MIN) { - - pr_debug("rejecting n=%d due to Fint failure, " - "lowering max_divider\n", n); - dd->max_divider = n; - ret = DPLL_FINT_UNDERFLOW; - - } else if (fint > DPLL_FINT_BAND1_MAX && - fint < DPLL_FINT_BAND2_MIN) { - - pr_debug("rejecting n=%d due to Fint failure\n", n); - ret = DPLL_FINT_INVALID; - - } else if (fint > DPLL_FINT_BAND2_MAX) { - - pr_debug("rejecting n=%d due to Fint failure, " - "boosting min_divider\n", n); - dd->min_divider = n; - ret = DPLL_FINT_INVALID; - - } - - return ret; -} - /** * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk * @clk: OMAP clock struct ptr to use @@ -242,62 +133,6 @@ void omap2_init_clksel_parent(struct clk *clk) return; } -/** - * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate - * @clk: struct clk * of a DPLL - * - * DPLLs can be locked or bypassed - basically, enabled or disabled. - * When locked, the DPLL output depends on the M and N values. When - * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock - * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and - * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively - * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. - * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is - * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 - * if the clock @clk is not a DPLL. - */ -u32 omap2_get_dpll_rate(struct clk *clk) -{ - long long dpll_clk; - u32 dpll_mult, dpll_div, v; - struct dpll_data *dd; - - dd = clk->dpll_data; - if (!dd) - return 0; - - /* Return bypass rate if DPLL is bypassed */ - v = __raw_readl(dd->control_reg); - v &= dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - if (cpu_is_omap24xx()) { - if (v == OMAP2XXX_EN_DPLL_LPBYPASS || - v == OMAP2XXX_EN_DPLL_FRBYPASS) - return dd->clk_bypass->rate; - } else if (cpu_is_omap34xx()) { - if (v == OMAP3XXX_EN_DPLL_LPBYPASS || - v == OMAP3XXX_EN_DPLL_FRBYPASS) - return dd->clk_bypass->rate; - } else if (cpu_is_omap44xx()) { - if (v == OMAP4XXX_EN_DPLL_LPBYPASS || - v == OMAP4XXX_EN_DPLL_FRBYPASS || - v == OMAP4XXX_EN_DPLL_MNBYPASS) - return dd->clk_bypass->rate; - } - - v = __raw_readl(dd->mult_div1_reg); - dpll_mult = v & dd->mult_mask; - dpll_mult >>= __ffs(dd->mult_mask); - dpll_div = v & dd->div1_mask; - dpll_div >>= __ffs(dd->div1_mask); - - dpll_clk = (long long)dd->clk_ref->rate * dpll_mult; - do_div(dpll_clk, dpll_div + 1); - - return dpll_clk; -} - /** * omap2_clk_dflt_find_companion - find companion clock to @clk * @clk: struct clk * to find the companion clock of @@ -858,196 +693,6 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) return 0; } -/* DPLL rate rounding code */ - -/** - * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding - * @clk: struct clk * of the DPLL - * @tolerance: maximum rate error tolerance - * - * Set the maximum DPLL rate error tolerance for the rate rounding - * algorithm. The rate tolerance is an attempt to balance DPLL power - * saving (the least divider value "n") vs. rate fidelity (the least - * difference between the desired DPLL target rate and the rounded - * rate out of the algorithm). So, increasing the tolerance is likely - * to decrease DPLL power consumption and increase DPLL rate error. - * Returns -EINVAL if provided a null clock ptr or a clk that is not a - * DPLL; or 0 upon success. - */ -int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance) -{ - if (!clk || !clk->dpll_data) - return -EINVAL; - - clk->dpll_data->rate_tolerance = tolerance; - - return 0; -} - -static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, - unsigned int m, unsigned int n) -{ - unsigned long long num; - - num = (unsigned long long)parent_rate * m; - do_div(num, n); - return num; -} - -/* - * _dpll_test_mult - test a DPLL multiplier value - * @m: pointer to the DPLL m (multiplier) value under test - * @n: current DPLL n (divider) value under test - * @new_rate: pointer to storage for the resulting rounded rate - * @target_rate: the desired DPLL rate - * @parent_rate: the DPLL's parent clock rate - * - * This code tests a DPLL multiplier value, ensuring that the - * resulting rate will not be higher than the target_rate, and that - * the multiplier value itself is valid for the DPLL. Initially, the - * integer pointed to by the m argument should be prescaled by - * multiplying by DPLL_SCALE_FACTOR. The code will replace this with - * a non-scaled m upon return. This non-scaled m will result in a - * new_rate as close as possible to target_rate (but not greater than - * target_rate) given the current (parent_rate, n, prescaled m) - * triple. Returns DPLL_MULT_UNDERFLOW in the event that the - * non-scaled m attempted to underflow, which can allow the calling - * function to bail out early; or 0 upon success. - */ -static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, - unsigned long target_rate, - unsigned long parent_rate) -{ - int r = 0, carry = 0; - - /* Unscale m and round if necessary */ - if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) - carry = 1; - *m = (*m / DPLL_SCALE_FACTOR) + carry; - - /* - * The new rate must be <= the target rate to avoid programming - * a rate that is impossible for the hardware to handle - */ - *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); - if (*new_rate > target_rate) { - (*m)--; - *new_rate = 0; - } - - /* Guard against m underflow */ - if (*m < DPLL_MIN_MULTIPLIER) { - *m = DPLL_MIN_MULTIPLIER; - *new_rate = 0; - r = DPLL_MULT_UNDERFLOW; - } - - if (*new_rate == 0) - *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); - - return r; -} - -/** - * omap2_dpll_round_rate - round a target rate for an OMAP DPLL - * @clk: struct clk * for a DPLL - * @target_rate: desired DPLL clock rate - * - * Given a DPLL, a desired target rate, and a rate tolerance, round - * the target rate to a possible, programmable rate for this DPLL. - * Rate tolerance is assumed to be set by the caller before this - * function is called. Attempts to select the minimum possible n - * within the tolerance to reduce power consumption. Stores the - * computed (m, n) in the DPLL's dpll_data structure so set_rate() - * will not need to call this (expensive) function again. Returns ~0 - * if the target rate cannot be rounded, either because the rate is - * too low or because the rate tolerance is set too tightly; or the - * rounded rate upon success. - */ -long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) -{ - int m, n, r, e, scaled_max_m; - unsigned long scaled_rt_rp, new_rate; - int min_e = -1, min_e_m = -1, min_e_n = -1; - struct dpll_data *dd; - - if (!clk || !clk->dpll_data) - return ~0; - - dd = clk->dpll_data; - - pr_debug("clock: starting DPLL round_rate for clock %s, target rate " - "%ld\n", clk->name, target_rate); - - scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); - scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; - - dd->last_rounded_rate = 0; - - for (n = dd->min_divider; n <= dd->max_divider; n++) { - - /* Is the (input clk, divider) pair valid for the DPLL? */ - r = _dpll_test_fint(clk, n); - if (r == DPLL_FINT_UNDERFLOW) - break; - else if (r == DPLL_FINT_INVALID) - continue; - - /* Compute the scaled DPLL multiplier, based on the divider */ - m = scaled_rt_rp * n; - - /* - * Since we're counting n up, a m overflow means we - * can bail out completely (since as n increases in - * the next iteration, there's no way that m can - * increase beyond the current m) - */ - if (m > scaled_max_m) - break; - - r = _dpll_test_mult(&m, n, &new_rate, target_rate, - dd->clk_ref->rate); - - /* m can't be set low enough for this n - try with a larger n */ - if (r == DPLL_MULT_UNDERFLOW) - continue; - - e = target_rate - new_rate; - pr_debug("clock: n = %d: m = %d: rate error is %d " - "(new_rate = %ld)\n", n, m, e, new_rate); - - if (min_e == -1 || - min_e >= (int)(abs(e) - dd->rate_tolerance)) { - min_e = e; - min_e_m = m; - min_e_n = n; - - pr_debug("clock: found new least error %d\n", min_e); - - /* We found good settings -- bail out now */ - if (min_e <= dd->rate_tolerance) - break; - } - } - - if (min_e < 0) { - pr_debug("clock: error: target rate or tolerance too low\n"); - return ~0; - } - - dd->last_rounded_m = min_e_m; - dd->last_rounded_n = min_e_n; - dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, - min_e_m, min_e_n); - - pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", - min_e, min_e_m, min_e_n); - pr_debug("clock: final rate: %ld (target rate: %ld)\n", - dd->last_rounded_rate, target_rate); - - return dd->last_rounded_rate; -} - /*------------------------------------------------------------------------- * Omap2 clock reset and init functions *-------------------------------------------------------------------------*/ -- GitLab From df791b3ebf181b3eece9c770565fcf0844bbd7cb Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:04 -0700 Subject: [PATCH 1232/3892] OMAP2/3/4 clock: move clksel clock functions into mach-omap2/clkt_clksel.c Move all clksel-related clock functions from mach-omap2/clock.c to mach-omap2/clkt_clksel.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage clksel clocks are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for clksel clocks alon. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be moved to the plat-omap/ directory to be shared. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt_clksel.c | 417 ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock.c | 377 +-------------------------- arch/arm/mach-omap2/clock.h | 2 + 4 files changed, 424 insertions(+), 375 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt_clksel.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1a135c8e7f1e..9ecc58d2c986 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -9,7 +9,8 @@ omap-2-3-common = irq.o sdrc.o omap_hwmod.o omap-3-4-common = dpll3xxx.o prcm-common = prcm.o powerdomain.o clock-common = clock.o clock_common_data.o \ - clockdomain.o clkt_dpll.o + clockdomain.o clkt_dpll.o \ + clkt_clksel.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c new file mode 100644 index 000000000000..25a2363106de --- /dev/null +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -0,0 +1,417 @@ +/* + * clkt_clksel.c - OMAP2/3/4 clksel clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * 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. + * + * XXX At some point these clksel clocks should be split into + * "divider" clocks and "mux" clocks to better match the hardware. + * + * XXX Currently these clocks are only used in the OMAP2/3/4 code, but + * many of the OMAP1 clocks should be convertible to use this + * mechanism. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include + +#include "clock.h" +#include "cm.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" + +/* Private functions */ + +/** + * _omap2_get_clksel_by_parent - return clksel struct for a given clk & parent + * @clk: OMAP struct clk ptr to inspect + * @src_clk: OMAP struct clk ptr of the parent clk to search for + * + * Scan the struct clksel array associated with the clock to find + * the element associated with the supplied parent clock address. + * Returns a pointer to the struct clksel on success or NULL on error. + */ +static const struct clksel *_omap2_get_clksel_by_parent(struct clk *clk, + struct clk *src_clk) +{ + const struct clksel *clks; + + if (!clk->clksel) + return NULL; + + for (clks = clk->clksel; clks->parent; clks++) { + if (clks->parent == src_clk) + break; /* Found the requested parent */ + } + + if (!clks->parent) { + printk(KERN_ERR "clock: Could not find parent clock %s in " + "clksel array of clock %s\n", src_clk->name, + clk->name); + return NULL; + } + + return clks; +} + +/* + * Converts encoded control register address into a full address + * On error, the return value (parent_div) will be 0. + */ +static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk, + u32 *field_val) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + + clks = _omap2_get_clksel_by_parent(clk, src_clk); + if (!clks) + return 0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE) + break; /* Found the default rate for this platform */ + } + + if (!clkr->div) { + printk(KERN_ERR "clock: Could not find default rate for " + "clock %s parent %s\n", clk->name, + src_clk->parent->name); + return 0; + } + + /* Should never happen. Add a clksel mask to the struct clk. */ + WARN_ON(clk->clksel_mask == 0); + + *field_val = clkr->val; + + return clkr->div; +} + + +/* Public functions */ + +/** + * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware + * @clk: OMAP clock struct ptr to use + * + * Given a pointer to a source-selectable struct clk, read the hardware + * register and determine what its parent is currently set to. Update the + * clk->parent field with the appropriate clk ptr. + */ +void omap2_init_clksel_parent(struct clk *clk) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + u32 r, found = 0; + + if (!clk->clksel) + return; + + r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + r >>= __ffs(clk->clksel_mask); + + for (clks = clk->clksel; clks->parent && !found; clks++) { + for (clkr = clks->rates; clkr->div && !found; clkr++) { + if ((clkr->flags & cpu_mask) && (clkr->val == r)) { + if (clk->parent != clks->parent) { + pr_debug("clock: inited %s parent " + "to %s (was %s)\n", + clk->name, clks->parent->name, + ((clk->parent) ? + clk->parent->name : "NULL")); + clk_reparent(clk, clks->parent); + }; + found = 1; + } + } + } + + if (!found) + printk(KERN_ERR "clock: init parent: could not find " + "regval %0x for clock %s\n", r, clk->name); + + return; +} + +/* + * Used for clocks that are part of CLKSEL_xyz governed clocks. + * REVISIT: Maybe change to use clk->enable() functions like on omap1? + */ +unsigned long omap2_clksel_recalc(struct clk *clk) +{ + unsigned long rate; + u32 div = 0; + + pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); + + div = omap2_clksel_get_divisor(clk); + if (div == 0) + return clk->rate; + + rate = clk->parent->rate / div; + + pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div); + + return rate; +} + +/** + * omap2_clksel_round_rate_div - find divisor for the given clock and rate + * @clk: OMAP struct clk to use + * @target_rate: desired clock rate + * @new_div: ptr to where we should store the divisor + * + * Finds 'best' divider value in an array based on the source and target + * rates. The divider array must be sorted with smallest divider first. + * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, + * they are only settable as part of virtual_prcm set. + * + * Returns the rounded clock rate or returns 0xffffffff on error. + */ +u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, + u32 *new_div) +{ + unsigned long test_rate; + const struct clksel *clks; + const struct clksel_rate *clkr; + u32 last_div = 0; + + pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", + clk->name, target_rate); + + *new_div = 1; + + clks = _omap2_get_clksel_by_parent(clk, clk->parent); + if (!clks) + return ~0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + /* Sanity check */ + if (clkr->div <= last_div) + pr_err("clock: clksel_rate table not sorted " + "for clock %s", clk->name); + + last_div = clkr->div; + + test_rate = clk->parent->rate / clkr->div; + + if (test_rate <= target_rate) + break; /* found it */ + } + + if (!clkr->div) { + pr_err("clock: Could not find divisor for target " + "rate %ld for clock %s parent %s\n", target_rate, + clk->name, clk->parent->name); + return ~0; + } + + *new_div = clkr->div; + + pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, + (clk->parent->rate / clkr->div)); + + return clk->parent->rate / clkr->div; +} + +/** + * omap2_clksel_round_rate - find rounded rate for the given clock and rate + * @clk: OMAP struct clk to use + * @target_rate: desired clock rate + * + * Compatibility wrapper for OMAP clock framework + * Finds best target rate based on the source clock and possible dividers. + * rates. The divider array must be sorted with smallest divider first. + * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, + * they are only settable as part of virtual_prcm set. + * + * Returns the rounded clock rate or returns 0xffffffff on error. + */ +long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) +{ + u32 new_div; + + return omap2_clksel_round_rate_div(clk, target_rate, &new_div); +} + + +/* Given a clock and a rate apply a clock specific rounding function */ +long omap2_clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk->round_rate) + return clk->round_rate(clk, rate); + + if (clk->flags & RATE_FIXED) + printk(KERN_ERR "clock: generic omap2_clk_round_rate called " + "on fixed-rate clock %s\n", clk->name); + + return clk->rate; +} + +/** + * omap2_clksel_to_divisor() - turn clksel field value into integer divider + * @clk: OMAP struct clk to use + * @field_val: register field value to find + * + * Given a struct clk of a rate-selectable clksel clock, and a register field + * value to search for, find the corresponding clock divisor. The register + * field value should be pre-masked and shifted down so the LSB is at bit 0 + * before calling. Returns 0 on error + */ +u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + + clks = _omap2_get_clksel_by_parent(clk, clk->parent); + if (!clks) + return 0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) + break; + } + + if (!clkr->div) { + printk(KERN_ERR "clock: Could not find fieldval %d for " + "clock %s parent %s\n", field_val, clk->name, + clk->parent->name); + return 0; + } + + return clkr->div; +} + +/** + * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value + * @clk: OMAP struct clk to use + * @div: integer divisor to search for + * + * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, + * find the corresponding register field value. The return register value is + * the value before left-shifting. Returns ~0 on error + */ +u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + + /* should never happen */ + WARN_ON(div == 0); + + clks = _omap2_get_clksel_by_parent(clk, clk->parent); + if (!clks) + return ~0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if ((clkr->flags & cpu_mask) && (clkr->div == div)) + break; + } + + if (!clkr->div) { + printk(KERN_ERR "clock: Could not find divisor %d for " + "clock %s parent %s\n", div, clk->name, + clk->parent->name); + return ~0; + } + + return clkr->val; +} + +/** + * omap2_clksel_get_divisor - get current divider applied to parent clock. + * @clk: OMAP struct clk to use. + * + * Returns the integer divisor upon success or 0 on error. + */ +u32 omap2_clksel_get_divisor(struct clk *clk) +{ + u32 v; + + if (!clk->clksel_mask) + return 0; + + v = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + v >>= __ffs(clk->clksel_mask); + + return omap2_clksel_to_divisor(clk, v); +} + +int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) +{ + u32 v, field_val, validrate, new_div = 0; + + if (!clk->clksel_mask) + return -EINVAL; + + validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + if (validrate != rate) + return -EINVAL; + + field_val = omap2_divisor_to_clksel(clk, new_div); + if (field_val == ~0) + return -EINVAL; + + v = __raw_readl(clk->clksel_reg); + v &= ~clk->clksel_mask; + v |= field_val << __ffs(clk->clksel_mask); + __raw_writel(v, clk->clksel_reg); + v = __raw_readl(clk->clksel_reg); /* OCP barrier */ + + clk->rate = clk->parent->rate / new_div; + + omap2xxx_clk_commit(clk); + + return 0; +} + +int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) +{ + u32 field_val, v, parent_div; + + if (!clk->clksel) + return -EINVAL; + + parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val); + if (!parent_div) + return -EINVAL; + + /* Set new source value (previous dividers if any in effect) */ + v = __raw_readl(clk->clksel_reg); + v &= ~clk->clksel_mask; + v |= field_val << __ffs(clk->clksel_mask); + __raw_writel(v, clk->clksel_reg); + v = __raw_readl(clk->clksel_reg); /* OCP barrier */ + + omap2xxx_clk_commit(clk); + + clk_reparent(clk, new_parent); + + /* CLKSEL clocks follow their parents' rates, divided by a divisor */ + clk->rate = new_parent->rate; + + if (parent_div > 0) + clk->rate /= parent_div; + + pr_debug("clock: set parent of %s to %s (new rate %ld)\n", + clk->name, clk->parent->name, clk->rate); + + return 0; +} diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 98196285e80c..d3ebb74873f8 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -43,14 +43,14 @@ u8 cpu_mask; *-------------------------------------------------------------------------*/ /** - * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware + * omap2xxx_clk_commit - commit clock parent/rate changes in hardware * @clk: struct clk * * * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes * don't take effect until the VALID_CONFIG bit is written, write the * VALID_CONFIG bit and wait for the write to complete. No return value. */ -static void _omap2xxx_clk_commit(struct clk *clk) +void omap2xxx_clk_commit(struct clk *clk) { if (!cpu_is_omap24xx()) return; @@ -90,49 +90,6 @@ void omap2_init_clk_clkdm(struct clk *clk) } } -/** - * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware - * @clk: OMAP clock struct ptr to use - * - * Given a pointer to a source-selectable struct clk, read the hardware - * register and determine what its parent is currently set to. Update the - * clk->parent field with the appropriate clk ptr. - */ -void omap2_init_clksel_parent(struct clk *clk) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - u32 r, found = 0; - - if (!clk->clksel) - return; - - r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; - r >>= __ffs(clk->clksel_mask); - - for (clks = clk->clksel; clks->parent && !found; clks++) { - for (clkr = clks->rates; clkr->div && !found; clkr++) { - if ((clkr->flags & cpu_mask) && (clkr->val == r)) { - if (clk->parent != clks->parent) { - pr_debug("clock: inited %s parent " - "to %s (was %s)\n", - clk->name, clks->parent->name, - ((clk->parent) ? - clk->parent->name : "NULL")); - clk_reparent(clk, clks->parent); - }; - found = 1; - } - } - } - - if (!found) - printk(KERN_ERR "clock: init parent: could not find " - "regval %0x for clock %s\n", r, clk->name); - - return; -} - /** * omap2_clk_dflt_find_companion - find companion clock to @clk * @clk: struct clk * to find the companion clock of @@ -335,274 +292,6 @@ err: return ret; } -/* - * Used for clocks that are part of CLKSEL_xyz governed clocks. - * REVISIT: Maybe change to use clk->enable() functions like on omap1? - */ -unsigned long omap2_clksel_recalc(struct clk *clk) -{ - unsigned long rate; - u32 div = 0; - - pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); - - div = omap2_clksel_get_divisor(clk); - if (div == 0) - return clk->rate; - - rate = clk->parent->rate / div; - - pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div); - - return rate; -} - -/** - * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent - * @clk: OMAP struct clk ptr to inspect - * @src_clk: OMAP struct clk ptr of the parent clk to search for - * - * Scan the struct clksel array associated with the clock to find - * the element associated with the supplied parent clock address. - * Returns a pointer to the struct clksel on success or NULL on error. - */ -static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk, - struct clk *src_clk) -{ - const struct clksel *clks; - - if (!clk->clksel) - return NULL; - - for (clks = clk->clksel; clks->parent; clks++) { - if (clks->parent == src_clk) - break; /* Found the requested parent */ - } - - if (!clks->parent) { - printk(KERN_ERR "clock: Could not find parent clock %s in " - "clksel array of clock %s\n", src_clk->name, - clk->name); - return NULL; - } - - return clks; -} - -/** - * omap2_clksel_round_rate_div - find divisor for the given clock and rate - * @clk: OMAP struct clk to use - * @target_rate: desired clock rate - * @new_div: ptr to where we should store the divisor - * - * Finds 'best' divider value in an array based on the source and target - * rates. The divider array must be sorted with smallest divider first. - * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, - * they are only settable as part of virtual_prcm set. - * - * Returns the rounded clock rate or returns 0xffffffff on error. - */ -u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, - u32 *new_div) -{ - unsigned long test_rate; - const struct clksel *clks; - const struct clksel_rate *clkr; - u32 last_div = 0; - - pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", - clk->name, target_rate); - - *new_div = 1; - - clks = omap2_get_clksel_by_parent(clk, clk->parent); - if (!clks) - return ~0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if (!(clkr->flags & cpu_mask)) - continue; - - /* Sanity check */ - if (clkr->div <= last_div) - pr_err("clock: clksel_rate table not sorted " - "for clock %s", clk->name); - - last_div = clkr->div; - - test_rate = clk->parent->rate / clkr->div; - - if (test_rate <= target_rate) - break; /* found it */ - } - - if (!clkr->div) { - pr_err("clock: Could not find divisor for target " - "rate %ld for clock %s parent %s\n", target_rate, - clk->name, clk->parent->name); - return ~0; - } - - *new_div = clkr->div; - - pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, - (clk->parent->rate / clkr->div)); - - return (clk->parent->rate / clkr->div); -} - -/** - * omap2_clksel_round_rate - find rounded rate for the given clock and rate - * @clk: OMAP struct clk to use - * @target_rate: desired clock rate - * - * Compatibility wrapper for OMAP clock framework - * Finds best target rate based on the source clock and possible dividers. - * rates. The divider array must be sorted with smallest divider first. - * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, - * they are only settable as part of virtual_prcm set. - * - * Returns the rounded clock rate or returns 0xffffffff on error. - */ -long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) -{ - u32 new_div; - - return omap2_clksel_round_rate_div(clk, target_rate, &new_div); -} - - -/* Given a clock and a rate apply a clock specific rounding function */ -long omap2_clk_round_rate(struct clk *clk, unsigned long rate) -{ - if (clk->round_rate) - return clk->round_rate(clk, rate); - - if (clk->flags & RATE_FIXED) - printk(KERN_ERR "clock: generic omap2_clk_round_rate called " - "on fixed-rate clock %s\n", clk->name); - - return clk->rate; -} - -/** - * omap2_clksel_to_divisor() - turn clksel field value into integer divider - * @clk: OMAP struct clk to use - * @field_val: register field value to find - * - * Given a struct clk of a rate-selectable clksel clock, and a register field - * value to search for, find the corresponding clock divisor. The register - * field value should be pre-masked and shifted down so the LSB is at bit 0 - * before calling. Returns 0 on error - */ -u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - - clks = omap2_get_clksel_by_parent(clk, clk->parent); - if (!clks) - return 0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) - break; - } - - if (!clkr->div) { - printk(KERN_ERR "clock: Could not find fieldval %d for " - "clock %s parent %s\n", field_val, clk->name, - clk->parent->name); - return 0; - } - - return clkr->div; -} - -/** - * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value - * @clk: OMAP struct clk to use - * @div: integer divisor to search for - * - * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, - * find the corresponding register field value. The return register value is - * the value before left-shifting. Returns ~0 on error - */ -u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - - /* should never happen */ - WARN_ON(div == 0); - - clks = omap2_get_clksel_by_parent(clk, clk->parent); - if (!clks) - return ~0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if ((clkr->flags & cpu_mask) && (clkr->div == div)) - break; - } - - if (!clkr->div) { - printk(KERN_ERR "clock: Could not find divisor %d for " - "clock %s parent %s\n", div, clk->name, - clk->parent->name); - return ~0; - } - - return clkr->val; -} - -/** - * omap2_clksel_get_divisor - get current divider applied to parent clock. - * @clk: OMAP struct clk to use. - * - * Returns the integer divisor upon success or 0 on error. - */ -u32 omap2_clksel_get_divisor(struct clk *clk) -{ - u32 v; - - if (!clk->clksel_mask) - return 0; - - v = __raw_readl(clk->clksel_reg) & clk->clksel_mask; - v >>= __ffs(clk->clksel_mask); - - return omap2_clksel_to_divisor(clk, v); -} - -int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) -{ - u32 v, field_val, validrate, new_div = 0; - - if (!clk->clksel_mask) - return -EINVAL; - - validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); - if (validrate != rate) - return -EINVAL; - - field_val = omap2_divisor_to_clksel(clk, new_div); - if (field_val == ~0) - return -EINVAL; - - v = __raw_readl(clk->clksel_reg); - v &= ~clk->clksel_mask; - v |= field_val << __ffs(clk->clksel_mask); - __raw_writel(v, clk->clksel_reg); - v = __raw_readl(clk->clksel_reg); /* OCP barrier */ - - clk->rate = clk->parent->rate / new_div; - - _omap2xxx_clk_commit(clk); - - return 0; -} - - /* Set the clock rate for a clock source */ int omap2_clk_set_rate(struct clk *clk, unsigned long rate) { @@ -622,75 +311,15 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate) return ret; } -/* - * Converts encoded control register address into a full address - * On error, the return value (parent_div) will be 0. - */ -static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk, - u32 *field_val) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - - clks = omap2_get_clksel_by_parent(clk, src_clk); - if (!clks) - return 0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE) - break; /* Found the default rate for this platform */ - } - - if (!clkr->div) { - printk(KERN_ERR "clock: Could not find default rate for " - "clock %s parent %s\n", clk->name, - src_clk->parent->name); - return 0; - } - - /* Should never happen. Add a clksel mask to the struct clk. */ - WARN_ON(clk->clksel_mask == 0); - - *field_val = clkr->val; - - return clkr->div; -} - int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) { - u32 field_val, v, parent_div; - if (clk->flags & CONFIG_PARTICIPANT) return -EINVAL; if (!clk->clksel) return -EINVAL; - parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val); - if (!parent_div) - return -EINVAL; - - /* Set new source value (previous dividers if any in effect) */ - v = __raw_readl(clk->clksel_reg); - v &= ~clk->clksel_mask; - v |= field_val << __ffs(clk->clksel_mask); - __raw_writel(v, clk->clksel_reg); - v = __raw_readl(clk->clksel_reg); /* OCP barrier */ - - _omap2xxx_clk_commit(clk); - - clk_reparent(clk, new_parent); - - /* CLKSEL clocks follow their parents' rates, divided by a divisor */ - clk->rate = new_parent->rate; - - if (parent_div > 0) - clk->rate /= parent_div; - - pr_debug("clock: set parent of %s to %s (new rate %ld)\n", - clk->name, clk->parent->name, clk->rate); - - return 0; + return omap2_clksel_set_parent(clk, new_parent); } /*------------------------------------------------------------------------- diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 0d70dc09370b..0d21702a3cdd 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -80,6 +80,7 @@ u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val); u32 omap2_divisor_to_clksel(struct clk *clk, u32 div); long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); +int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); u32 omap2_get_dpll_rate(struct clk *clk); void omap2_init_dpll_parent(struct clk *clk); int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); @@ -90,6 +91,7 @@ void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, u8 *other_bit); void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, u8 *idlest_bit); +void omap2xxx_clk_commit(struct clk *clk); extern u8 cpu_mask; -- GitLab From 4b1f76ed4f8012929494261eb6923b3c98554a9a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:04 -0700 Subject: [PATCH 1233/3892] OMAP2 clock: move all static functions to the top of the file Move static functions to the top of the file and ensure that their names are prefixed with an underscore to conform with the practice in the newer OMAP clock code files. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.c | 88 +++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index d3ebb74873f8..0d54fde5b455 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -42,6 +42,51 @@ u8 cpu_mask; * OMAP2/3/4 specific clock functions *-------------------------------------------------------------------------*/ +/* Private functions */ + +/** + * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void _omap2_module_wait_ready(struct clk *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(__raw_readl(companion_reg) & (1 << other_bit))) + return; + } + + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); + + omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); +} + +/* Enables clock without considering parent dependencies or use count + * REVISIT: Maybe change this to use clk->enable like on omap1? + */ +static int _omap2_clk_enable(struct clk *clk) +{ + return clk->ops->enable(clk); +} + +/* Disables clock without considering parent dependencies or use count */ +static void _omap2_clk_disable(struct clk *clk) +{ + clk->ops->disable(clk); +} + +/* Public functions */ + /** * omap2xxx_clk_commit - commit clock parent/rate changes in hardware * @clk: struct clk * @@ -149,33 +194,6 @@ void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, *idlest_bit = clk->enable_bit; } -/** - * omap2_module_wait_ready - wait for an OMAP module to leave IDLE - * @clk: struct clk * belonging to the module - * - * If the necessary clocks for the OMAP hardware IP block that - * corresponds to clock @clk are enabled, then wait for the module to - * indicate readiness (i.e., to leave IDLE). This code does not - * belong in the clock code and will be moved in the medium term to - * module-dependent code. No return value. - */ -static void omap2_module_wait_ready(struct clk *clk) -{ - void __iomem *companion_reg, *idlest_reg; - u8 other_bit, idlest_bit; - - /* Not all modules have multiple clocks that their IDLEST depends on */ - if (clk->ops->find_companion) { - clk->ops->find_companion(clk, &companion_reg, &other_bit); - if (!(__raw_readl(companion_reg) & (1 << other_bit))) - return; - } - - clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); - - omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); -} - int omap2_dflt_clk_enable(struct clk *clk) { u32 v; @@ -195,7 +213,7 @@ int omap2_dflt_clk_enable(struct clk *clk) v = __raw_readl(clk->enable_reg); /* OCP barrier */ if (clk->ops->find_idlest) - omap2_module_wait_ready(clk); + _omap2_module_wait_ready(clk); return 0; } @@ -235,20 +253,6 @@ const struct clkops clkops_omap2_dflt = { .disable = omap2_dflt_clk_disable, }; -/* Enables clock without considering parent dependencies or use count - * REVISIT: Maybe change this to use clk->enable like on omap1? - */ -static int _omap2_clk_enable(struct clk *clk) -{ - return clk->ops->enable(clk); -} - -/* Disables clock without considering parent dependencies or use count */ -static void _omap2_clk_disable(struct clk *clk) -{ - clk->ops->disable(clk); -} - void omap2_clk_disable(struct clk *clk) { if (clk->usecount > 0 && !(--clk->usecount)) { -- GitLab From 69ecefca514c318d0ce993c48ffa3bad009c7b9b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:04 -0700 Subject: [PATCH 1234/3892] OMAP2/3/4 clock: combine all omap2_clk_functions The struct clk_functions for OMAP2, 3, and 4 are all essentially the same, so combine them. This removes one multi-OMAP kernel impediment and saves memory on multi-OMAP builds. The stubs for omap2_clk_{init,exit}_cpufreq() code will removed once the OPP layer code that's currently in Kevin's PM branch is merged. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/clock.c | 17 +++++++++++++++++ arch/arm/mach-omap2/clock.h | 7 +++++++ arch/arm/mach-omap2/clock2xxx.c | 23 ++++++++--------------- arch/arm/mach-omap2/clock34xx.c | 9 --------- arch/arm/mach-omap2/clock44xx.c | 9 --------- 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 0d54fde5b455..999b91e023b1 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -351,3 +351,20 @@ void omap2_clk_disable_unused(struct clk *clk) pwrdm_clkdm_state_switch(clk->clkdm); } #endif + +/* Common data */ + +struct clk_functions omap2_clk_functions = { + .clk_enable = omap2_clk_enable, + .clk_disable = omap2_clk_disable, + .clk_round_rate = omap2_clk_round_rate, + .clk_set_rate = omap2_clk_set_rate, + .clk_set_parent = omap2_clk_set_parent, + .clk_disable_unused = omap2_clk_disable_unused, +#ifdef CONFIG_CPU_FREQ + /* These will be removed when the OPP code is integrated */ + .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, + .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, +#endif +}; + diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 0d21702a3cdd..dcd58cde13b6 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -105,5 +105,12 @@ extern const struct clksel_rate gpt_32k_rates[]; extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; +#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_CPU_FREQ) +extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); +extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); +#else +#define omap2_clk_init_cpufreq_table 0 +#define omap2_clk_exit_cpufreq_table 0 +#endif #endif diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index 5420356eb407..bef557488fec 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -453,13 +453,16 @@ int omap2_select_table_rate(struct clk *clk, unsigned long rate) */ static struct cpufreq_frequency_table *freq_table; -void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) +void omap2xxx_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) { const struct prcm_config *prcm; long sys_ck_rate; int i = 0; int tbl_sz = 0; + if (!cpu_is_omap2xxx()) + return; + sys_ck_rate = clk_get_rate(sclk); for (prcm = rate_table; prcm->mpu_speed; prcm++) { @@ -516,26 +519,16 @@ void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) *table = &freq_table[0]; } -void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) +void omap2xxx_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) { + if (!cpu_is_omap2xxx()) + return; + kfree(freq_table); } #endif -struct clk_functions omap2_clk_functions = { - .clk_enable = omap2_clk_enable, - .clk_disable = omap2_clk_disable, - .clk_round_rate = omap2_clk_round_rate, - .clk_set_rate = omap2_clk_set_rate, - .clk_set_parent = omap2_clk_set_parent, - .clk_disable_unused = omap2_clk_disable_unused, -#ifdef CONFIG_CPU_FREQ - .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, - .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, -#endif -}; - static u32 omap2_get_apll_clkin(void) { u32 aplls, srate = 0; diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index d4217b93e10b..4c4bb3cb79e8 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -258,15 +258,6 @@ int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) */ #if defined(CONFIG_ARCH_OMAP3) -struct clk_functions omap2_clk_functions = { - .clk_enable = omap2_clk_enable, - .clk_disable = omap2_clk_disable, - .clk_round_rate = omap2_clk_round_rate, - .clk_set_rate = omap2_clk_set_rate, - .clk_set_parent = omap2_clk_set_parent, - .clk_disable_unused = omap2_clk_disable_unused, -}; - /* * Set clocks for bypass mode for reboot to work. */ diff --git a/arch/arm/mach-omap2/clock44xx.c b/arch/arm/mach-omap2/clock44xx.c index e370868a79a8..08dd6427df70 100644 --- a/arch/arm/mach-omap2/clock44xx.c +++ b/arch/arm/mach-omap2/clock44xx.c @@ -13,15 +13,6 @@ #include #include "clock.h" -struct clk_functions omap2_clk_functions = { - .clk_enable = omap2_clk_enable, - .clk_disable = omap2_clk_disable, - .clk_round_rate = omap2_clk_round_rate, - .clk_set_rate = omap2_clk_set_rate, - .clk_set_parent = omap2_clk_set_parent, - .clk_disable_unused = omap2_clk_disable_unused, -}; - const struct clkops clkops_noncore_dpll_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, -- GitLab From b1823d8616b11477e9e0967c727ed5325fb12403 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:06 -0700 Subject: [PATCH 1235/3892] OMAP2xxx clock: move the DPLL+CORE composite clock code into mach-omap2/clkt2xxx_dpllcore.c Move the DPLL+CORE composite clock functions from clock2xxx.c to mach-omap2/clkt2xxx_dpllcore.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage the OMAP2 DPLL+CORE clock are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for the DPLL+CORE clock alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/ directory, rather than shared with other chip types that don't use this clock type. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Richard Woodruff Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 4 +- arch/arm/mach-omap2/clkt2xxx_dpllcore.c | 173 ++++++++++++++++++++++++ arch/arm/mach-omap2/clock2xxx.c | 136 ------------------- 3 files changed, 176 insertions(+), 137 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_dpllcore.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 9ecc58d2c986..04ce372bb105 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -11,8 +11,10 @@ prcm-common = prcm.o powerdomain.o clock-common = clock.o clock_common_data.o \ clockdomain.o clkt_dpll.o \ clkt_clksel.o +clock-omap2xxx = clkt2xxx_dpllcore.o -obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) +obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ + $(clock-omap2xxx) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(omap-3-4-common) obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) $(clock-common) diff --git a/arch/arm/mach-omap2/clkt2xxx_dpllcore.c b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c new file mode 100644 index 000000000000..019048434f13 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c @@ -0,0 +1,173 @@ +/* + * DPLL + CORE_CLK composite clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * XXX The DPLL and CORE clocks should be split into two separate clock + * types. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "opp2xxx.h" +#include "cm.h" +#include "cm-regbits-24xx.h" + +/* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */ + +/** + * omap2xxx_clk_get_core_rate - return the CORE_CLK rate + * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") + * + * Returns the CORE_CLK rate. CORE_CLK can have one of three rate + * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz + * (the latter is unusual). This currently should be called with + * struct clk *dpll_ck, which is a composite clock of dpll_ck and + * core_ck. + */ +unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) +{ + long long core_clk; + u32 v; + + core_clk = omap2_get_dpll_rate(clk); + + v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + v &= OMAP24XX_CORE_CLK_SRC_MASK; + + if (v == CORE_CLK_SRC_32K) + core_clk = 32768; + else + core_clk *= v; + + return core_clk; +} + +/* + * Uses the current prcm set to tell if a rate is valid. + * You can go slower, but not faster within a given rate set. + */ +static long omap2_dpllcore_round_rate(unsigned long target_rate) +{ + u32 high, low, core_clk_src; + + core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; + + if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ + high = curr_prcm_set->dpll_speed * 2; + low = curr_prcm_set->dpll_speed; + } else { /* DPLL clockout x 2 */ + high = curr_prcm_set->dpll_speed; + low = curr_prcm_set->dpll_speed / 2; + } + +#ifdef DOWN_VARIABLE_DPLL + if (target_rate > high) + return high; + else + return target_rate; +#else + if (target_rate > low) + return high; + else + return low; +#endif + +} + +unsigned long omap2_dpllcore_recalc(struct clk *clk) +{ + return omap2xxx_clk_get_core_rate(clk); +} + +int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) +{ + u32 cur_rate, low, mult, div, valid_rate, done_rate; + u32 bypass = 0; + struct prcm_config tmpset; + const struct dpll_data *dd; + + cur_rate = omap2xxx_clk_get_core_rate(dclk); + mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + mult &= OMAP24XX_CORE_CLK_SRC_MASK; + + if ((rate == (cur_rate / 2)) && (mult == 2)) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); + } else if ((rate == (cur_rate * 2)) && (mult == 1)) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + } else if (rate != cur_rate) { + valid_rate = omap2_dpllcore_round_rate(rate); + if (valid_rate != rate) + return -EINVAL; + + if (mult == 1) + low = curr_prcm_set->dpll_speed; + else + low = curr_prcm_set->dpll_speed / 2; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); + tmpset.cm_clksel1_pll &= ~(dd->mult_mask | + dd->div1_mask); + div = ((curr_prcm_set->xtal_speed / 1000000) - 1); + tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; + if (rate > low) { + tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; + mult = ((rate / 2) / 1000000); + done_rate = CORE_CLK_SRC_DPLL_X2; + } else { + tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; + mult = (rate / 1000000); + done_rate = CORE_CLK_SRC_DPLL; + } + tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); + tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); + + /* Worst case */ + tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; + + if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ + bypass = 1; + + /* For omap2xxx_sdrc_init_params() */ + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + + /* Force dll lock mode */ + omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, + bypass); + + /* Errata: ret dll entry state */ + omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); + omap2xxx_sdrc_reprogram(done_rate, 0); + } + + return 0; +} + diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index bef557488fec..419ae80fa1d4 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -54,8 +54,6 @@ #define APLLS_CLKIN_13MHZ 2 #define APLLS_CLKIN_12MHZ 3 -/* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */ - const struct prcm_config *curr_prcm_set; const struct prcm_config *rate_table; @@ -94,34 +92,6 @@ const struct clkops clkops_omap2430_i2chs_wait = { .find_companion = omap2_clk_dflt_find_companion, }; -/** - * omap2xxx_clk_get_core_rate - return the CORE_CLK rate - * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") - * - * Returns the CORE_CLK rate. CORE_CLK can have one of three rate - * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz - * (the latter is unusual). This currently should be called with - * struct clk *dpll_ck, which is a composite clock of dpll_ck and - * core_ck. - */ -unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) -{ - long long core_clk; - u32 v; - - core_clk = omap2_get_dpll_rate(clk); - - v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); - v &= OMAP24XX_CORE_CLK_SRC_MASK; - - if (v == CORE_CLK_SRC_32K) - core_clk = 32768; - else - core_clk *= v; - - return core_clk; -} - static int omap2_enable_osc_ck(struct clk *clk) { u32 pcc; @@ -215,112 +185,6 @@ const struct clkops clkops_apll54 = { .disable = omap2_clk_apll_disable, }; -/* - * Uses the current prcm set to tell if a rate is valid. - * You can go slower, but not faster within a given rate set. - */ -long omap2_dpllcore_round_rate(unsigned long target_rate) -{ - u32 high, low, core_clk_src; - - core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); - core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; - - if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ - high = curr_prcm_set->dpll_speed * 2; - low = curr_prcm_set->dpll_speed; - } else { /* DPLL clockout x 2 */ - high = curr_prcm_set->dpll_speed; - low = curr_prcm_set->dpll_speed / 2; - } - -#ifdef DOWN_VARIABLE_DPLL - if (target_rate > high) - return high; - else - return target_rate; -#else - if (target_rate > low) - return high; - else - return low; -#endif - -} - -unsigned long omap2_dpllcore_recalc(struct clk *clk) -{ - return omap2xxx_clk_get_core_rate(clk); -} - -int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) -{ - u32 cur_rate, low, mult, div, valid_rate, done_rate; - u32 bypass = 0; - struct prcm_config tmpset; - const struct dpll_data *dd; - - cur_rate = omap2xxx_clk_get_core_rate(dclk); - mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); - mult &= OMAP24XX_CORE_CLK_SRC_MASK; - - if ((rate == (cur_rate / 2)) && (mult == 2)) { - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); - } else if ((rate == (cur_rate * 2)) && (mult == 1)) { - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); - } else if (rate != cur_rate) { - valid_rate = omap2_dpllcore_round_rate(rate); - if (valid_rate != rate) - return -EINVAL; - - if (mult == 1) - low = curr_prcm_set->dpll_speed; - else - low = curr_prcm_set->dpll_speed / 2; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); - tmpset.cm_clksel1_pll &= ~(dd->mult_mask | - dd->div1_mask); - div = ((curr_prcm_set->xtal_speed / 1000000) - 1); - tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); - tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; - if (rate > low) { - tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; - mult = ((rate / 2) / 1000000); - done_rate = CORE_CLK_SRC_DPLL_X2; - } else { - tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; - mult = (rate / 1000000); - done_rate = CORE_CLK_SRC_DPLL; - } - tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); - tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); - - /* Worst case */ - tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; - - if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ - bypass = 1; - - /* For omap2xxx_sdrc_init_params() */ - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); - - /* Force dll lock mode */ - omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, - bypass); - - /* Errata: ret dll entry state */ - omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); - omap2xxx_sdrc_reprogram(done_rate, 0); - } - - return 0; -} - /** * omap2_table_mpu_recalc - just return the MPU speed * @clk: virt_prcm_set struct clk -- GitLab From 734f69a773d8ff65111562116c18c987049ddac4 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:06 -0700 Subject: [PATCH 1236/3892] OMAP2xxx clock: move the DVFS virtual clock code into mach-omap2/clkt2xxx_virt_prcm_set.c Move the DVFS virtual clock functions from clock2xxx.c to mach-omap2/clkt2xxx_virt_prcm_set.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage the virt_prcm_set clock are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for the virt_prcm_set clock alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/ directory, rather than shared with other chip types that don't use this clock type. Thanks to Alexander Shishkin for his comments. Thanks also to Kevin Hilman for finding and fixing a bug with the CONFIG_CPU_FREQ portion of this patch. Signed-off-by: Paul Walmsley Cc: Richard Woodruff Cc: Alexander Shishkin Cc: Kevin Hilman --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c | 254 +++++++++++++++++++ arch/arm/mach-omap2/clock2xxx.c | 211 --------------- 3 files changed, 256 insertions(+), 212 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 04ce372bb105..2b58363a8947 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -11,7 +11,8 @@ prcm-common = prcm.o powerdomain.o clock-common = clock.o clock_common_data.o \ clockdomain.o clkt_dpll.o \ clkt_clksel.o -clock-omap2xxx = clkt2xxx_dpllcore.o +clock-omap2xxx = clkt2xxx_dpllcore.o \ + clkt2xxx_virt_prcm_set.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(clock-omap2xxx) diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c new file mode 100644 index 000000000000..3b1eac4d5390 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c @@ -0,0 +1,254 @@ +/* + * OMAP2xxx DVFS virtual clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * XXX Some of this code should be replaceable by the upcoming OPP layer + * code. However, some notion of "rate set" is probably still necessary + * for OMAP2xxx at least. Rate sets should be generalized so they can be + * used for any OMAP chip, not just OMAP2xxx. In particular, Richard Woodruff + * has in the past expressed a preference to use rate sets for OPP changes, + * rather than dynamically recalculating the clock tree, so if someone wants + * this badly enough to write the code to handle it, we should support it + * as an option. + */ +#undef DEBUG + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "opp2xxx.h" +#include "cm.h" +#include "cm-regbits-24xx.h" + +const struct prcm_config *curr_prcm_set; +const struct prcm_config *rate_table; + +/** + * omap2_table_mpu_recalc - just return the MPU speed + * @clk: virt_prcm_set struct clk + * + * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set. + */ +unsigned long omap2_table_mpu_recalc(struct clk *clk) +{ + return curr_prcm_set->mpu_speed; +} + +/* + * Look for a rate equal or less than the target rate given a configuration set. + * + * What's not entirely clear is "which" field represents the key field. + * Some might argue L3-DDR, others ARM, others IVA. This code is simple and + * just uses the ARM rates. + */ +long omap2_round_to_table_rate(struct clk *clk, unsigned long rate) +{ + const struct prcm_config *ptr; + long highest_rate; + long sys_ck_rate; + + sys_ck_rate = clk_get_rate(sclk); + + highest_rate = -EINVAL; + + for (ptr = rate_table; ptr->mpu_speed; ptr++) { + if (!(ptr->flags & cpu_mask)) + continue; + if (ptr->xtal_speed != sys_ck_rate) + continue; + + highest_rate = ptr->mpu_speed; + + /* Can check only after xtal frequency check */ + if (ptr->mpu_speed <= rate) + break; + } + return highest_rate; +} + +/* Sets basic clocks based on the specified rate */ +int omap2_select_table_rate(struct clk *clk, unsigned long rate) +{ + u32 cur_rate, done_rate, bypass = 0, tmp; + const struct prcm_config *prcm; + unsigned long found_speed = 0; + unsigned long flags; + long sys_ck_rate; + + sys_ck_rate = clk_get_rate(sclk); + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + + if (prcm->xtal_speed != sys_ck_rate) + continue; + + if (prcm->mpu_speed <= rate) { + found_speed = prcm->mpu_speed; + break; + } + } + + if (!found_speed) { + printk(KERN_INFO "Could not set MPU rate to %luMHz\n", + rate / 1000000); + return -EINVAL; + } + + curr_prcm_set = prcm; + cur_rate = omap2xxx_clk_get_core_rate(dclk); + + if (prcm->dpll_speed == cur_rate / 2) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); + } else if (prcm->dpll_speed == cur_rate * 2) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + } else if (prcm->dpll_speed != cur_rate) { + local_irq_save(flags); + + if (prcm->dpll_speed == prcm->xtal_speed) + bypass = 1; + + if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) == + CORE_CLK_SRC_DPLL_X2) + done_rate = CORE_CLK_SRC_DPLL_X2; + else + done_rate = CORE_CLK_SRC_DPLL; + + /* MPU divider */ + cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL); + + /* dsp + iva1 div(2420), iva2.1(2430) */ + cm_write_mod_reg(prcm->cm_clksel_dsp, + OMAP24XX_DSP_MOD, CM_CLKSEL); + + cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL); + + /* Major subsystem dividers */ + tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK; + cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, + CM_CLKSEL1); + + if (cpu_is_omap2430()) + cm_write_mod_reg(prcm->cm_clksel_mdm, + OMAP2430_MDM_MOD, CM_CLKSEL); + + /* x2 to enter omap2xxx_sdrc_init_params() */ + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + + omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, + bypass); + + omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); + omap2xxx_sdrc_reprogram(done_rate, 0); + + local_irq_restore(flags); + } + + return 0; +} + +#ifdef CONFIG_CPU_FREQ +/* + * Walk PRCM rate table and fillout cpufreq freq_table + * XXX This should be replaced by an OPP layer in the near future + */ +static struct cpufreq_frequency_table *freq_table; + +void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) +{ + const struct prcm_config *prcm; + long sys_ck_rate; + int i = 0; + int tbl_sz = 0; + + if (!cpu_is_omap24xx()) + return; + + sys_ck_rate = clk_get_rate(sclk); + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + if (prcm->xtal_speed != sys_ck_rate) + continue; + + /* don't put bypass rates in table */ + if (prcm->dpll_speed == prcm->xtal_speed) + continue; + + tbl_sz++; + } + + /* + * XXX Ensure that we're doing what CPUFreq expects for this error + * case and the following one + */ + if (tbl_sz == 0) { + pr_warning("%s: no matching entries in rate_table\n", + __func__); + return; + } + + /* Include the CPUFREQ_TABLE_END terminator entry */ + tbl_sz++; + + freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * tbl_sz, + GFP_ATOMIC); + if (!freq_table) { + pr_err("%s: could not kzalloc frequency table\n", __func__); + return; + } + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + if (prcm->xtal_speed != sys_ck_rate) + continue; + + /* don't put bypass rates in table */ + if (prcm->dpll_speed == prcm->xtal_speed) + continue; + + freq_table[i].index = i; + freq_table[i].frequency = prcm->mpu_speed / 1000; + i++; + } + + freq_table[i].index = i; + freq_table[i].frequency = CPUFREQ_TABLE_END; + + *table = &freq_table[0]; +} + +void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) +{ + if (!cpu_is_omap24xx()) + return; + + kfree(freq_table); +} + +#endif diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index 419ae80fa1d4..11d6edb0b32f 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -54,9 +54,6 @@ #define APLLS_CLKIN_13MHZ 2 #define APLLS_CLKIN_12MHZ 3 -const struct prcm_config *curr_prcm_set; -const struct prcm_config *rate_table; - struct clk *vclk, *sclk, *dclk; void __iomem *prcm_clksrc_ctrl; @@ -185,214 +182,6 @@ const struct clkops clkops_apll54 = { .disable = omap2_clk_apll_disable, }; -/** - * omap2_table_mpu_recalc - just return the MPU speed - * @clk: virt_prcm_set struct clk - * - * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set. - */ -unsigned long omap2_table_mpu_recalc(struct clk *clk) -{ - return curr_prcm_set->mpu_speed; -} - -/* - * Look for a rate equal or less than the target rate given a configuration set. - * - * What's not entirely clear is "which" field represents the key field. - * Some might argue L3-DDR, others ARM, others IVA. This code is simple and - * just uses the ARM rates. - */ -long omap2_round_to_table_rate(struct clk *clk, unsigned long rate) -{ - const struct prcm_config *ptr; - long highest_rate; - long sys_ck_rate; - - sys_ck_rate = clk_get_rate(sclk); - - highest_rate = -EINVAL; - - for (ptr = rate_table; ptr->mpu_speed; ptr++) { - if (!(ptr->flags & cpu_mask)) - continue; - if (ptr->xtal_speed != sys_ck_rate) - continue; - - highest_rate = ptr->mpu_speed; - - /* Can check only after xtal frequency check */ - if (ptr->mpu_speed <= rate) - break; - } - return highest_rate; -} - -/* Sets basic clocks based on the specified rate */ -int omap2_select_table_rate(struct clk *clk, unsigned long rate) -{ - u32 cur_rate, done_rate, bypass = 0, tmp; - const struct prcm_config *prcm; - unsigned long found_speed = 0; - unsigned long flags; - long sys_ck_rate; - - sys_ck_rate = clk_get_rate(sclk); - - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - - if (prcm->xtal_speed != sys_ck_rate) - continue; - - if (prcm->mpu_speed <= rate) { - found_speed = prcm->mpu_speed; - break; - } - } - - if (!found_speed) { - printk(KERN_INFO "Could not set MPU rate to %luMHz\n", - rate / 1000000); - return -EINVAL; - } - - curr_prcm_set = prcm; - cur_rate = omap2xxx_clk_get_core_rate(dclk); - - if (prcm->dpll_speed == cur_rate / 2) { - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); - } else if (prcm->dpll_speed == cur_rate * 2) { - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); - } else if (prcm->dpll_speed != cur_rate) { - local_irq_save(flags); - - if (prcm->dpll_speed == prcm->xtal_speed) - bypass = 1; - - if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) == - CORE_CLK_SRC_DPLL_X2) - done_rate = CORE_CLK_SRC_DPLL_X2; - else - done_rate = CORE_CLK_SRC_DPLL; - - /* MPU divider */ - cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL); - - /* dsp + iva1 div(2420), iva2.1(2430) */ - cm_write_mod_reg(prcm->cm_clksel_dsp, - OMAP24XX_DSP_MOD, CM_CLKSEL); - - cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL); - - /* Major subsystem dividers */ - tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK; - cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, - CM_CLKSEL1); - - if (cpu_is_omap2430()) - cm_write_mod_reg(prcm->cm_clksel_mdm, - OMAP2430_MDM_MOD, CM_CLKSEL); - - /* x2 to enter omap2xxx_sdrc_init_params() */ - omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); - - omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, - bypass); - - omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); - omap2xxx_sdrc_reprogram(done_rate, 0); - - local_irq_restore(flags); - } - - return 0; -} - -#ifdef CONFIG_CPU_FREQ -/* - * Walk PRCM rate table and fillout cpufreq freq_table - * XXX This should be replaced by an OPP layer in the near future - */ -static struct cpufreq_frequency_table *freq_table; - -void omap2xxx_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) -{ - const struct prcm_config *prcm; - long sys_ck_rate; - int i = 0; - int tbl_sz = 0; - - if (!cpu_is_omap2xxx()) - return; - - sys_ck_rate = clk_get_rate(sclk); - - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - if (prcm->xtal_speed != sys_ck_rate) - continue; - - /* don't put bypass rates in table */ - if (prcm->dpll_speed == prcm->xtal_speed) - continue; - - tbl_sz++; - } - - /* - * XXX Ensure that we're doing what CPUFreq expects for this error - * case and the following one - */ - if (tbl_sz == 0) { - pr_warning("%s: no matching entries in rate_table\n", - __func__); - return; - } - - /* Include the CPUFREQ_TABLE_END terminator entry */ - tbl_sz++; - - freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * tbl_sz, - GFP_ATOMIC); - if (!freq_table) { - pr_err("%s: could not kzalloc frequency table\n", __func__); - return; - } - - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - if (prcm->xtal_speed != sys_ck_rate) - continue; - - /* don't put bypass rates in table */ - if (prcm->dpll_speed == prcm->xtal_speed) - continue; - - freq_table[i].index = i; - freq_table[i].frequency = prcm->mpu_speed / 1000; - i++; - } - - freq_table[i].index = i; - freq_table[i].frequency = CPUFREQ_TABLE_END; - - *table = &freq_table[0]; -} - -void omap2xxx_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) -{ - if (!cpu_is_omap2xxx()) - return; - - kfree(freq_table); -} - -#endif - static u32 omap2_get_apll_clkin(void) { u32 aplls, srate = 0; -- GitLab From 99824461ea72ca0044cc6508f02c0e1cabf37ba5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:00 +0000 Subject: [PATCH 1237/3892] net/atm: Convert printk to pr_ Add #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ Remove function names from output Use single line pr_debug instead of broken multiple uses without newline Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/br2684.c | 18 ++--- net/atm/clip.c | 60 +++++++------- net/atm/common.c | 52 ++++++------ net/atm/ioctl.c | 7 +- net/atm/lec.c | 192 +++++++++++++++++++------------------------- net/atm/mpc.c | 4 +- net/atm/mpoa_proc.c | 3 +- net/atm/pppoatm.c | 17 ++-- net/atm/raw.c | 5 +- net/atm/resources.c | 12 +-- net/atm/signaling.c | 19 +++-- net/atm/svc.c | 13 +-- 12 files changed, 190 insertions(+), 212 deletions(-) diff --git a/net/atm/br2684.c b/net/atm/br2684.c index c9230c398697..d72b1a579911 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -6,6 +6,8 @@ * Eric Kinzie, 2006-2007, US Naval Research Laboratory */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include @@ -148,7 +150,7 @@ static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) struct br2684_vcc *brvcc = BR2684_VCC(vcc); struct net_device *net_dev = skb->dev; - pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev); + pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev); brvcc->old_pop(vcc, skb); if (!net_dev) @@ -244,7 +246,7 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, struct br2684_dev *brdev = BRPRIV(dev); struct br2684_vcc *brvcc; - pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb)); + pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); read_lock(&devs_lock); brvcc = pick_outgoing_vcc(skb, brdev); if (brvcc == NULL) { @@ -352,7 +354,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) struct net_device *net_dev = brvcc->device; struct br2684_dev *brdev = BRPRIV(net_dev); - pr_debug("br2684_push\n"); + pr_debug("\n"); if (unlikely(skb == NULL)) { /* skb==NULL means VCC is being destroyed */ @@ -479,8 +481,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) write_lock_irq(&devs_lock); net_dev = br2684_find_dev(&be.ifspec); if (net_dev == NULL) { - printk(KERN_ERR - "br2684: tried to attach to non-existant device\n"); + pr_err("tried to attach to non-existant device\n"); err = -ENXIO; goto error; } @@ -503,8 +504,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) err = -EINVAL; goto error; } - pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, - be.encaps, brvcc); + pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc); if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { unsigned char *esi = atmvcc->dev->esi; if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) @@ -595,7 +595,7 @@ static int br2684_create(void __user * arg) struct atm_newif_br2684 ni; enum br2684_payload payload; - pr_debug("br2684_create\n"); + pr_debug("\n"); if (copy_from_user(&ni, arg, sizeof ni)) { return -EFAULT; @@ -624,7 +624,7 @@ static int br2684_create(void __user * arg) /* open, stop, do_ioctl ? */ err = register_netdev(netdev); if (err < 0) { - printk(KERN_ERR "br2684_create: register_netdev failed\n"); + pr_err("register_netdev failed\n"); free_netdev(netdev); return err; } diff --git a/net/atm/clip.c b/net/atm/clip.c index 64629c354343..d7939fd58cd3 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -2,6 +2,8 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include /* for UINT_MAX */ @@ -51,7 +53,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) struct atmarp_ctrl *ctrl; struct sk_buff *skb; - pr_debug("to_atmarpd(%d)\n", type); + pr_debug("(%d)\n", type); if (!atmarpd) return -EUNATCH; skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); @@ -71,8 +73,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry) { - pr_debug("link_vcc %p to entry %p (neigh %p)\n", clip_vcc, entry, - entry->neigh); + pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh); clip_vcc->entry = entry; clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */ clip_vcc->next = entry->vccs; @@ -86,7 +87,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) struct clip_vcc **walk; if (!entry) { - printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n", clip_vcc); + pr_crit("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc); return; } netif_tx_lock_bh(entry->neigh->dev); /* block clip_start_xmit() */ @@ -106,12 +107,10 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) error = neigh_update(entry->neigh, NULL, NUD_NONE, NEIGH_UPDATE_F_ADMIN); if (error) - printk(KERN_CRIT "unlink_clip_vcc: " - "neigh_update failed with %d\n", error); + pr_crit("neigh_update failed with %d\n", error); goto out; } - printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc " - "0x%p)\n", entry, clip_vcc); + pr_crit("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc); out: netif_tx_unlock_bh(entry->neigh->dev); } @@ -127,7 +126,7 @@ static int neigh_check_cb(struct neighbour *n) if (cv->idle_timeout && time_after(jiffies, exp)) { pr_debug("releasing vcc %p->%p of entry %p\n", - cv, cv->vcc, entry); + cv, cv->vcc, entry); vcc_release_async(cv->vcc, -ETIMEDOUT); } } @@ -139,7 +138,7 @@ static int neigh_check_cb(struct neighbour *n) struct sk_buff *skb; pr_debug("destruction postponed with ref %d\n", - atomic_read(&n->refcnt)); + atomic_read(&n->refcnt)); while ((skb = skb_dequeue(&n->arp_queue)) != NULL) dev_kfree_skb(skb); @@ -163,7 +162,7 @@ static int clip_arp_rcv(struct sk_buff *skb) { struct atm_vcc *vcc; - pr_debug("clip_arp_rcv\n"); + pr_debug("\n"); vcc = ATM_SKB(skb)->vcc; if (!vcc || !atm_charge(vcc, skb->truesize)) { dev_kfree_skb_any(skb); @@ -188,7 +187,7 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); - pr_debug("clip push\n"); + pr_debug("\n"); if (!skb) { pr_debug("removing VCC %p\n", clip_vcc); if (clip_vcc->entry) @@ -239,7 +238,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) int old; unsigned long flags; - pr_debug("clip_pop(vcc %p)\n", vcc); + pr_debug("(vcc %p)\n", vcc); clip_vcc->old_pop(vcc, skb); /* skb->dev == NULL in outbound ARP packets */ if (!dev) @@ -255,7 +254,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) { - pr_debug("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb); + pr_debug("(neigh %p, skb %p)\n", neigh, skb); to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip); } @@ -284,7 +283,7 @@ static int clip_constructor(struct neighbour *neigh) struct in_device *in_dev; struct neigh_parms *parms; - pr_debug("clip_constructor (neigh %p, entry %p)\n", neigh, entry); + pr_debug("(neigh %p, entry %p)\n", neigh, entry); neigh->type = inet_addr_type(&init_net, entry->ip); if (neigh->type != RTN_UNICAST) return -EINVAL; @@ -369,9 +368,9 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, int old; unsigned long flags; - pr_debug("clip_start_xmit (skb %p)\n", skb); + pr_debug("(skb %p)\n", skb); if (!skb_dst(skb)) { - printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n"); + pr_err("skb_dst(skb) == NULL\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -385,7 +384,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, return 0; } #endif - printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n"); + pr_err("NO NEIGHBOUR !\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -421,7 +420,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ if (old) { - printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); + pr_warning("XOFF->XOFF transition\n"); return NETDEV_TX_OK; } dev->stats.tx_packets++; @@ -456,7 +455,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL); if (!clip_vcc) return -ENOMEM; - pr_debug("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc); + pr_debug("%p vcc %p\n", clip_vcc, vcc); clip_vcc->vcc = vcc; vcc->user_back = clip_vcc; set_bit(ATM_VF_IS_CLIP, &vcc->flags); @@ -506,16 +505,16 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) struct rtable *rt; if (vcc->push != clip_push) { - printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n"); + pr_warning("non-CLIP VCC\n"); return -EBADF; } clip_vcc = CLIP_VCC(vcc); if (!ip) { if (!clip_vcc->entry) { - printk(KERN_ERR "hiding hidden ATMARP entry\n"); + pr_err("hiding hidden ATMARP entry\n"); return 0; } - pr_debug("setentry: remove\n"); + pr_debug("remove\n"); unlink_clip_vcc(clip_vcc); return 0; } @@ -529,9 +528,9 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) entry = NEIGH2ENTRY(neigh); if (entry != clip_vcc->entry) { if (!clip_vcc->entry) - pr_debug("setentry: add\n"); + pr_debug("add\n"); else { - pr_debug("setentry: update\n"); + pr_debug("update\n"); unlink_clip_vcc(clip_vcc); } link_vcc(clip_vcc, entry); @@ -614,16 +613,16 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_UP: - pr_debug("clip_device_event NETDEV_UP\n"); + pr_debug("NETDEV_UP\n"); to_atmarpd(act_up, PRIV(dev)->number, 0); break; case NETDEV_GOING_DOWN: - pr_debug("clip_device_event NETDEV_DOWN\n"); + pr_debug("NETDEV_DOWN\n"); to_atmarpd(act_down, PRIV(dev)->number, 0); break; case NETDEV_CHANGE: case NETDEV_CHANGEMTU: - pr_debug("clip_device_event NETDEV_CHANGE*\n"); + pr_debug("NETDEV_CHANGE*\n"); to_atmarpd(act_change, PRIV(dev)->number, 0); break; } @@ -660,7 +659,7 @@ static struct notifier_block clip_inet_notifier = { static void atmarpd_close(struct atm_vcc *vcc) { - pr_debug("atmarpd_close\n"); + pr_debug("\n"); rtnl_lock(); atmarpd = NULL; @@ -950,8 +949,7 @@ static int __init atm_clip_init(void) p = proc_create("arp", S_IRUGO, atm_proc_root, &arp_seq_fops); if (!p) { - printk(KERN_ERR "Unable to initialize " - "/proc/net/atm/arp\n"); + pr_err("Unable to initialize /proc/net/atm/arp\n"); atm_clip_exit_noproc(); return -ENOMEM; } diff --git a/net/atm/common.c b/net/atm/common.c index d61e051e0a3f..17f7e5f2131b 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -2,6 +2,7 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include #include @@ -64,8 +65,7 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) { pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", - sk_wmem_alloc_get(sk), size, - sk->sk_sndbuf); + sk_wmem_alloc_get(sk), size, sk->sk_sndbuf); return NULL; } while (!(skb = alloc_skb(size, GFP_KERNEL))) @@ -249,8 +249,7 @@ static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) max_sdu = ATM_MAX_AAL34_PDU; break; default: - printk(KERN_WARNING "ATM: AAL problems ... " - "(%d)\n",aal); + pr_warning("AAL problems ... (%d)\n", aal); /* fall through */ case ATM_AAL5: max_sdu = ATM_MAX_AAL5_PDU; @@ -385,11 +384,17 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); if (error) goto fail; - pr_debug("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); - pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, - vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); - pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, - vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu); + pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal); + pr_debug(" TX: %d, PCR %d..%d, SDU %d\n", + vcc->qos.txtp.traffic_class, + vcc->qos.txtp.min_pcr, + vcc->qos.txtp.max_pcr, + vcc->qos.txtp.max_sdu); + pr_debug(" RX: %d, PCR %d..%d, SDU %d\n", + vcc->qos.rxtp.traffic_class, + vcc->qos.rxtp.min_pcr, + vcc->qos.rxtp.max_pcr, + vcc->qos.rxtp.max_sdu); if (dev->ops->open) { if ((error = dev->ops->open(vcc))) @@ -413,7 +418,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) struct atm_vcc *vcc = ATM_SD(sock); int error; - pr_debug("vcc_connect (vpi %d, vci %d)\n",vpi,vci); + pr_debug("(vpi %d, vci %d)\n", vpi, vci); if (sock->state == SS_CONNECTED) return -EISCONN; if (sock->state != SS_UNCONNECTED) @@ -426,14 +431,15 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; - pr_debug("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; " - "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", - vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, - vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, - vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr, - vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, - vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : - " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); + pr_debug("(TX: cl %d,bw %d-%d,sdu %d; " + "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", + vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr, + vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu, + vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr, + vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, + vcc->qos.aal == ATM_AAL5 ? "" : + vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ", + vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) return -EBADFD; if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || @@ -497,7 +503,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (error) return error; sock_recv_ts_and_drops(msg, sk, skb); - pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize); + pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize); atm_return(vcc, skb->truesize); skb_free_datagram(sk, skb); return copied; @@ -772,19 +778,19 @@ static int __init atm_init(void) goto out; if ((error = atmpvc_init()) < 0) { - printk(KERN_ERR "atmpvc_init() failed with %d\n", error); + pr_err("atmpvc_init() failed with %d\n", error); goto out_unregister_vcc_proto; } if ((error = atmsvc_init()) < 0) { - printk(KERN_ERR "atmsvc_init() failed with %d\n", error); + pr_err("atmsvc_init() failed with %d\n", error); goto out_atmpvc_exit; } if ((error = atm_proc_init()) < 0) { - printk(KERN_ERR "atm_proc_init() failed with %d\n",error); + pr_err("atm_proc_init() failed with %d\n", error); goto out_atmsvc_exit; } if ((error = atm_sysfs_init()) < 0) { - printk(KERN_ERR "atm_sysfs_init() failed with %d\n",error); + pr_err("atm_sysfs_init() failed with %d\n", error); goto out_atmproc_exit; } out: diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 2ea40995dced..b75afba1f72b 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -3,6 +3,7 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ /* 2003 John Levon */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include #include @@ -97,8 +98,8 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg goto done; case ATM_SETSC: if (net_ratelimit()) - printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n", - current->comm, task_pid_nr(current)); + pr_warning("ATM_SETSC is obsolete; used by %s:%d\n", + current->comm, task_pid_nr(current)); error = 0; goto done; case ATMSIGD_CTRL: @@ -123,7 +124,7 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg to think about it at all. dwmw2. */ if (compat) { if (net_ratelimit()) - printk(KERN_WARNING "32-bit task cannot be atmsigd\n"); + pr_warning("32-bit task cannot be atmsigd\n"); error = -EINVAL; goto done; } diff --git a/net/atm/lec.c b/net/atm/lec.c index 42749b7b917c..6873813c3c99 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -4,6 +4,8 @@ * Marko Kiiskila */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include @@ -242,7 +244,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb) static void lec_tx_timeout(struct net_device *dev) { - printk(KERN_INFO "%s: tx timeout\n", dev->name); + pr_info("%s\n", dev->name); dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -266,7 +268,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, int i = 0; #endif /* DUMP_PACKETS >0 */ - pr_debug("lec_start_xmit called\n"); + pr_debug("called\n"); if (!priv->lecd) { printk("%s:No lecd attached\n", dev->name); dev->stats.tx_errors++; @@ -276,8 +278,8 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, } pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", - (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb), - (long)skb_end_pointer(skb)); + (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb), + (long)skb_end_pointer(skb)); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0) lec_handle_bridge(skb, dev); @@ -286,7 +288,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, /* Make sure we have room for lec_id */ if (skb_headroom(skb) < 2) { - pr_debug("lec_start_xmit: reallocating skb\n"); + pr_debug("reallocating skb\n"); skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); kfree_skb(skb); if (skb2 == NULL) @@ -367,19 +369,16 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, #endif entry = NULL; vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); - pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", dev->name, - vcc, vcc ? vcc->flags : 0, entry); + pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", + dev->name, vcc, vcc ? vcc->flags : 0, entry); if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) { if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { - pr_debug("%s:lec_start_xmit: queuing packet, ", - dev->name); - pr_debug("MAC address %pM\n", lec_h->h_dest); + pr_debug("%s:queuing packet, MAC address %pM\n", + dev->name, lec_h->h_dest); skb_queue_tail(&entry->tx_wait, skb); } else { - pr_debug - ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", - dev->name); - pr_debug("MAC address %pM\n", lec_h->h_dest); + pr_debug("%s:tx queue full or no arp entry, dropping, MAC address: %pM\n", + dev->name, lec_h->h_dest); dev->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -390,8 +389,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, #endif /* DUMP_PACKETS > 0 */ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { - pr_debug("lec.c: emptying tx queue, "); - pr_debug("MAC address %pM\n", lec_h->h_dest); + pr_debug("emptying tx queue, MAC address %pM\n", lec_h->h_dest); lec_send(vcc, skb2); } @@ -477,10 +475,10 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) mesg->content.normal.atm_addr, mesg->content.normal.flag, mesg->content.normal.targetless_le_arp); - pr_debug("lec: in l_arp_update\n"); + pr_debug("in l_arp_update\n"); if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ - pr_debug("lec: LANE2 3.1.5, got tlvs, size %d\n", - mesg->sizeoftlvs); + pr_debug("LANE2 3.1.5, got tlvs, size %d\n", + mesg->sizeoftlvs); lane2_associate_ind(dev, mesg->content.normal.mac_addr, tmp, mesg->sizeoftlvs); } @@ -531,9 +529,8 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct sk_buff *skb2; struct sock *sk; - pr_debug - ("%s: entry found, responding to zeppelin\n", - dev->name); + pr_debug("%s: entry found, responding to zeppelin\n", + dev->name); skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); @@ -633,7 +630,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, sk->sk_data_ready(sk, skb->len); if (data != NULL) { - pr_debug("lec: about to send %d bytes of data\n", data->len); + pr_debug("about to send %d bytes of data\n", data->len); atm_force_charge(priv->lecd, data->truesize); skb_queue_tail(&sk->sk_receive_queue, data); sk->sk_data_ready(sk, skb->len); @@ -692,35 +689,27 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) struct lec_priv *priv = netdev_priv(dev); #if DUMP_PACKETS >0 - int i = 0; - char buf[300]; - - printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name, - vcc->vpi, vcc->vci); + printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d\n", + dev->name, vcc->vpi, vcc->vci); #endif if (!skb) { pr_debug("%s: null skb\n", dev->name); lec_vcc_close(priv, vcc); return; } -#if DUMP_PACKETS > 0 - printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name, - skb->len, priv->lecid); #if DUMP_PACKETS >= 2 - for (i = 0; i < skb->len && i < 99; i++) { - sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); - } +#define MAX_SKB_DUMP 99 #elif DUMP_PACKETS >= 1 - for (i = 0; i < skb->len && i < 30; i++) { - sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); - } -#endif /* DUMP_PACKETS >= 1 */ - if (i == skb->len) - printk("%s\n", buf); - else - printk("%s...\n", buf); +#define MAX_SKB_DUMP 30 +#endif +#if DUMP_PACKETS > 0 + printk(KERN_DEBUG "%s: rcv datalen:%ld lecid:%4.4x\n", + dev->name, skb->len, priv->lecid); + print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1, + skb->data, min(MAX_SKB_DUMP, skb->len), true); #endif /* DUMP_PACKETS > 0 */ - if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */ + if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { + /* Control frame, to daemon */ struct sock *sk = sk_atm(vcc); pr_debug("%s: To daemon\n", dev->name); @@ -801,7 +790,7 @@ static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb) struct net_device *dev = skb->dev; if (vpriv == NULL) { - printk("lec_pop(): vpriv = NULL!?!?!?\n"); + pr_info("vpriv = NULL!?!?!?\n"); return; } @@ -822,11 +811,8 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) /* Lecd must be up in this case */ bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); - if (bytes_left != 0) { - printk - ("lec: lec_vcc_attach, copy from user failed for %d bytes\n", - bytes_left); - } + if (bytes_left != 0) + pr_info("copy from user failed for %d bytes\n", bytes_left); if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || !dev_lec[ioc_data.dev_num]) return -EINVAL; @@ -1199,7 +1185,7 @@ static int __init lane_module_init(void) p = proc_create("lec", S_IRUGO, atm_proc_root, &lec_seq_fops); if (!p) { - printk(KERN_ERR "Unable to initialize /proc/net/atm/lec\n"); + pr_err("Unable to initialize /proc/net/atm/lec\n"); return -ENOMEM; } #endif @@ -1381,7 +1367,7 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, #if 0 #define pr_debug(format,args...) /* -#define pr_debug printk + #define pr_debug printk */ #endif #define DEBUG_ARP_TABLE 0 @@ -1450,10 +1436,7 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry) tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])]; hlist_add_head(&entry->next, tmp); - pr_debug("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - 0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1], - 0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3], - 0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]); + pr_debug("Added entry:%pM\n", entry->mac_addr); } /* @@ -1492,10 +1475,7 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) } skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ - pr_debug("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - 0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1], - 0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3], - 0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]); + pr_debug("Removed entry:%pM\n", to_remove->mac_addr); return 0; } @@ -1714,9 +1694,7 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, struct hlist_head *head; struct lec_arp_table *entry; - pr_debug("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", - mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff, - mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff); + pr_debug("%pM\n", mac_addr); head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])]; hlist_for_each_entry(entry, node, head, next) { @@ -1755,7 +1733,7 @@ static void lec_arp_expire_arp(unsigned long data) entry = (struct lec_arp_table *)data; - pr_debug("lec_arp_expire_arp\n"); + pr_debug("\n"); if (entry->status == ESI_ARP_PENDING) { if (entry->no_tries <= entry->priv->max_retry_count) { if (entry->is_rdesc) @@ -1779,10 +1757,10 @@ static void lec_arp_expire_vcc(unsigned long data) del_timer(&to_remove->timer); - pr_debug("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", - to_remove, priv, - to_remove->vcc ? to_remove->recv_vcc->vpi : 0, - to_remove->vcc ? to_remove->recv_vcc->vci : 0); + pr_debug("%p %p: vpi:%d vci:%d\n", + to_remove, priv, + to_remove->vcc ? to_remove->recv_vcc->vpi : 0, + to_remove->vcc ? to_remove->recv_vcc->vci : 0); spin_lock_irqsave(&priv->lec_arp_lock, flags); hlist_del(&to_remove->next); @@ -1819,7 +1797,7 @@ static void lec_arp_check_expire(struct work_struct *work) unsigned long time_to_check; int i; - pr_debug("lec_arp_check_expire %p\n", priv); + pr_debug("%p\n", priv); now = jiffies; restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); @@ -1832,12 +1810,12 @@ restart: time_to_check = priv->aging_time; pr_debug("About to expire: %lx - %lx > %lx\n", - now, entry->last_used, time_to_check); + now, entry->last_used, time_to_check); if (time_after(now, entry->last_used + time_to_check) && !(entry->flags & LEC_PERMANENT_FLAG) && !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ /* Remove entry */ - pr_debug("LEC:Entry timed out\n"); + pr_debug("Entry timed out\n"); lec_arp_remove(priv, entry); lec_arp_put(entry); } else { @@ -1934,7 +1912,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, entry->packets_flooded < priv->maximum_unknown_frame_count) { entry->packets_flooded++; - pr_debug("LEC_ARP: Flooding..\n"); + pr_debug("Flooding..\n"); found = priv->mcast_vcc; goto out; } @@ -1945,13 +1923,13 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, */ lec_arp_hold(entry); *ret_entry = entry; - pr_debug("lec: entry->status %d entry->vcc %p\n", entry->status, - entry->vcc); + pr_debug("entry->status %d entry->vcc %p\n", entry->status, + entry->vcc); found = NULL; } else { /* No matching entry was found */ entry = make_entry(priv, mac_to_find); - pr_debug("LEC_ARP: Making entry\n"); + pr_debug("Making entry\n"); if (!entry) { found = priv->mcast_vcc; goto out; @@ -1988,7 +1966,7 @@ lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, struct lec_arp_table *entry; int i; - pr_debug("lec_addr_delete\n"); + pr_debug("\n"); spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { @@ -2019,10 +1997,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, struct lec_arp_table *entry, *tmp; int i; - pr_debug("lec:%s", (targetless_le_arp) ? "targetless " : " "); - pr_debug("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], - mac_addr[4], mac_addr[5]); + pr_debug("%smac:%pM\n", + (targetless_le_arp) ? "targetless " : "", mac_addr); spin_lock_irqsave(&priv->lec_arp_lock, flags); entry = lec_arp_find(priv, mac_addr); @@ -2149,19 +2125,17 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, * Vcc which we don't want to make default vcc, * attach it anyway. */ - pr_debug - ("LEC_ARP:Attaching data direct, not default: " - "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", - ioc_data->atm_addr[0], ioc_data->atm_addr[1], - ioc_data->atm_addr[2], ioc_data->atm_addr[3], - ioc_data->atm_addr[4], ioc_data->atm_addr[5], - ioc_data->atm_addr[6], ioc_data->atm_addr[7], - ioc_data->atm_addr[8], ioc_data->atm_addr[9], - ioc_data->atm_addr[10], ioc_data->atm_addr[11], - ioc_data->atm_addr[12], ioc_data->atm_addr[13], - ioc_data->atm_addr[14], ioc_data->atm_addr[15], - ioc_data->atm_addr[16], ioc_data->atm_addr[17], - ioc_data->atm_addr[18], ioc_data->atm_addr[19]); + pr_debug("LEC_ARP:Attaching data direct, not default: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + ioc_data->atm_addr[0], ioc_data->atm_addr[1], + ioc_data->atm_addr[2], ioc_data->atm_addr[3], + ioc_data->atm_addr[4], ioc_data->atm_addr[5], + ioc_data->atm_addr[6], ioc_data->atm_addr[7], + ioc_data->atm_addr[8], ioc_data->atm_addr[9], + ioc_data->atm_addr[10], ioc_data->atm_addr[11], + ioc_data->atm_addr[12], ioc_data->atm_addr[13], + ioc_data->atm_addr[14], ioc_data->atm_addr[15], + ioc_data->atm_addr[16], ioc_data->atm_addr[17], + ioc_data->atm_addr[18], ioc_data->atm_addr[19]); entry = make_entry(priv, bus_mac); if (entry == NULL) goto out; @@ -2177,19 +2151,17 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, dump_arp_table(priv); goto out; } - pr_debug - ("LEC_ARP:Attaching data direct, default: " - "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", - ioc_data->atm_addr[0], ioc_data->atm_addr[1], - ioc_data->atm_addr[2], ioc_data->atm_addr[3], - ioc_data->atm_addr[4], ioc_data->atm_addr[5], - ioc_data->atm_addr[6], ioc_data->atm_addr[7], - ioc_data->atm_addr[8], ioc_data->atm_addr[9], - ioc_data->atm_addr[10], ioc_data->atm_addr[11], - ioc_data->atm_addr[12], ioc_data->atm_addr[13], - ioc_data->atm_addr[14], ioc_data->atm_addr[15], - ioc_data->atm_addr[16], ioc_data->atm_addr[17], - ioc_data->atm_addr[18], ioc_data->atm_addr[19]); + pr_debug("LEC_ARP:Attaching data direct, default: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + ioc_data->atm_addr[0], ioc_data->atm_addr[1], + ioc_data->atm_addr[2], ioc_data->atm_addr[3], + ioc_data->atm_addr[4], ioc_data->atm_addr[5], + ioc_data->atm_addr[6], ioc_data->atm_addr[7], + ioc_data->atm_addr[8], ioc_data->atm_addr[9], + ioc_data->atm_addr[10], ioc_data->atm_addr[11], + ioc_data->atm_addr[12], ioc_data->atm_addr[13], + ioc_data->atm_addr[14], ioc_data->atm_addr[15], + ioc_data->atm_addr[16], ioc_data->atm_addr[17], + ioc_data->atm_addr[18], ioc_data->atm_addr[19]); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { if (memcmp @@ -2197,9 +2169,9 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, ATM_ESA_LEN) == 0) { pr_debug("LEC_ARP: Attaching data direct\n"); pr_debug("Currently -> Vcc: %d, Rvcc:%d\n", - entry->vcc ? entry->vcc->vci : 0, - entry->recv_vcc ? entry->recv_vcc-> - vci : 0); + entry->vcc ? entry->vcc->vci : 0, + entry->recv_vcc ? entry->recv_vcc-> + vci : 0); found_entry = 1; del_timer(&entry->timer); entry->vcc = vcc; @@ -2271,7 +2243,7 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) struct lec_arp_table *entry; int i; - pr_debug("LEC:lec_flush_complete %lx\n", tran_id); + pr_debug("%lx\n", tran_id); restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { @@ -2312,7 +2284,7 @@ lec_set_flush_tran_id(struct lec_priv *priv, if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { entry->flush_tran_id = tran_id; pr_debug("Set flush transaction id to %lx for %p\n", - tran_id, entry); + tran_id, entry); } } spin_unlock_irqrestore(&priv->lec_arp_lock, flags); diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 38a6cb0863f0..3c45aef47b7e 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include @@ -1447,7 +1449,7 @@ static __init int atm_mpoa_init(void) register_atm_ioctl(&atm_ioctl_ops); if (mpc_proc_init() != 0) - printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); + pr_info("failed to initialize /proc/mpoa\n"); printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index 1a0f5ccea9c4..0603ab478cf5 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -1,3 +1,4 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #ifdef CONFIG_PROC_FS #include @@ -278,7 +279,7 @@ int mpc_proc_init(void) p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_file_operations); if (!p) { - printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); + pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); return -ENOMEM; } return 0; diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 0af84cd4f65b..62db6d71dbab 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -33,6 +33,8 @@ * These hooks are not yet available in ppp_generic */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include #include @@ -132,7 +134,7 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); - pr_debug("pppoatm push\n"); + pr_debug("\n"); if (skb == NULL) { /* VCC was closed */ pr_debug("removing ATMPPP VCC %p\n", pvcc); pppoatm_unassign_vcc(atmvcc); @@ -165,10 +167,9 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) pvcc->chan.mtu += LLC_LEN; break; } - pr_debug("Couldn't autodetect yet " - "(skb: %02X %02X %02X %02X %02X %02X)\n", - skb->data[0], skb->data[1], skb->data[2], - skb->data[3], skb->data[4], skb->data[5]); + pr_debug("Couldn't autodetect yet (skb: %02X %02X %02X %02X %02X %02X)\n", + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); goto error; case e_vc: break; @@ -194,7 +195,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); ATM_SKB(skb)->vcc = pvcc->atmvcc; - pr_debug("pppoatm_send (skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); + pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) (void) skb_pull(skb, 1); switch (pvcc->encaps) { /* LLC encapsulation needed */ @@ -226,8 +227,8 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; - pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, - ATM_SKB(skb)->vcc->dev); + pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", + skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) ? DROP_PACKET : 1; nospace: diff --git a/net/atm/raw.c b/net/atm/raw.c index cbfcc71a17b1..fb8a9497653c 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -2,6 +2,7 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include #include @@ -32,8 +33,8 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { struct sock *sk = sk_atm(vcc); - pr_debug("APopR (%d) %d -= %d\n", vcc->vci, - sk_wmem_alloc_get(sk), skb->truesize); + pr_debug("(%d) %d -= %d\n", + vcc->vci, sk_wmem_alloc_get(sk), skb->truesize); atomic_sub(skb->truesize, &sk->sk_wmem_alloc); dev_kfree_skb_any(skb); sk->sk_write_space(sk); diff --git a/net/atm/resources.c b/net/atm/resources.c index 56b7322ff461..0d4c0ee090db 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -7,6 +7,7 @@ * 2002/01 - don't free the whole struct sock on sk->destruct time, * use the default destruct function initialized by sock_init_data */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include #include @@ -79,8 +80,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, dev = __alloc_atm_dev(type); if (!dev) { - printk(KERN_ERR "atm_dev_register: no space for dev %s\n", - type); + pr_err("no space for dev %s\n", type); return NULL; } mutex_lock(&atm_dev_mutex); @@ -109,16 +109,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, atomic_set(&dev->refcnt, 1); if (atm_proc_dev_register(dev) < 0) { - printk(KERN_ERR "atm_dev_register: " - "atm_proc_dev_register failed for dev %s\n", - type); + pr_err("atm_proc_dev_register failed for dev %s\n", type); goto out_fail; } if (atm_register_sysfs(dev) < 0) { - printk(KERN_ERR "atm_dev_register: " - "atm_register_sysfs failed for dev %s\n", - type); + pr_err("atm_register_sysfs failed for dev %s\n", type); atm_proc_dev_deregister(dev); goto out_fail; } diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 229921400522..28df4edf9ca4 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -2,6 +2,7 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include /* error codes */ #include /* printk */ @@ -37,14 +38,14 @@ static void sigd_put_skb(struct sk_buff *skb) add_wait_queue(&sigd_sleep,&wait); while (!sigd) { set_current_state(TASK_UNINTERRUPTIBLE); - pr_debug("atmsvc: waiting for signaling demon...\n"); + pr_debug("atmsvc: waiting for signaling daemon...\n"); schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&sigd_sleep,&wait); #else if (!sigd) { - pr_debug("atmsvc: no signaling demon\n"); + pr_debug("atmsvc: no signaling daemon\n"); kfree_skb(skb); return; } @@ -90,8 +91,7 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) msg = (struct atmsvc_msg *) skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); vcc = *(struct atm_vcc **) &msg->vcc; - pr_debug("sigd_send %d (0x%lx)\n",(int) msg->type, - (unsigned long) vcc); + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); sk = sk_atm(vcc); switch (msg->type) { @@ -150,8 +150,7 @@ as_indicate_complete: clear_bit(ATM_VF_WAITING, &vcc->flags); break; default: - printk(KERN_ALERT "sigd_send: bad message type %d\n", - (int) msg->type); + pr_alert("bad message type %d\n", (int)msg->type); return -EINVAL; } sk->sk_state_change(sk); @@ -169,7 +168,7 @@ void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type, struct atmsvc_msg *msg; static unsigned session = 0; - pr_debug("sigd_enq %d (0x%p)\n",(int) type,vcc); + pr_debug("%d (0x%p)\n", (int)type, vcc); while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) schedule(); msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)); @@ -219,10 +218,10 @@ static void sigd_close(struct atm_vcc *vcc) struct sock *s; int i; - pr_debug("sigd_close\n"); + pr_debug("\n"); sigd = NULL; if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) - printk(KERN_ERR "sigd_close: closing with requests pending\n"); + pr_err("closing with requests pending\n"); skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); read_lock(&vcc_sklist_lock); @@ -256,7 +255,7 @@ static struct atm_dev sigd_dev = { int sigd_attach(struct atm_vcc *vcc) { if (sigd) return -EADDRINUSE; - pr_debug("sigd_attach\n"); + pr_debug("\n"); sigd = vcc; vcc->dev = &sigd_dev; vcc_insert_socket(sk_atm(vcc)); diff --git a/net/atm/svc.c b/net/atm/svc.c index 66e1d9b3e5de..251ddbc42e4b 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -2,6 +2,7 @@ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include #include /* struct socket, struct proto_ops */ @@ -46,7 +47,7 @@ static void svc_disconnect(struct atm_vcc *vcc) struct sk_buff *skb; struct sock *sk = sk_atm(vcc); - pr_debug("svc_disconnect %p\n",vcc); + pr_debug("%p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); @@ -76,7 +77,7 @@ static int svc_release(struct socket *sock) if (sk) { vcc = ATM_SD(sock); - pr_debug("svc_release %p\n", vcc); + pr_debug("%p\n", vcc); clear_bit(ATM_VF_READY, &vcc->flags); /* VCC pointer is used as a reference, so we must not free it (thereby subjecting it to re-use) before all pending connections @@ -153,7 +154,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, struct atm_vcc *vcc = ATM_SD(sock); int error; - pr_debug("svc_connect %p\n",vcc); + pr_debug("%p\n",vcc); lock_sock(sk); if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { error = -EINVAL; @@ -286,7 +287,7 @@ static int svc_listen(struct socket *sock,int backlog) struct atm_vcc *vcc = ATM_SD(sock); int error; - pr_debug("svc_listen %p\n",vcc); + pr_debug("%p\n", vcc); lock_sock(sk); /* let server handle listen on unbound sockets */ if (test_bit(ATM_VF_SESSION,&vcc->flags)) { @@ -336,7 +337,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) new_vcc = ATM_SD(newsock); - pr_debug("svc_accept %p -> %p\n",old_vcc,new_vcc); + pr_debug("%p -> %p\n", old_vcc, new_vcc); while (1) { DEFINE_WAIT(wait); @@ -540,7 +541,7 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, error = -EINPROGRESS; goto out; } - pr_debug("svc_addparty added wait queue\n"); + pr_debug("added wait queue\n"); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); -- GitLab From c39f01d7883f944ae75961cc1a31d348c7970599 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:01 +0000 Subject: [PATCH 1238/3892] net/atm/addr.c: Convert include Signed-off-by: David S. Miller --- net/atm/addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/atm/addr.c b/net/atm/addr.c index 82e85abc303d..cf3ae8b47572 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include "signaling.h" #include "addr.h" -- GitLab From 3356b4d41605f9b0977b0963c65f466eee213fe9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:02 +0000 Subject: [PATCH 1239/3892] net/atm/atm_misc.c: checkpatch cleanups Moved EXPORT_SYMBOL to follow definition Add space after commas Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/atm_misc.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index 02cc7e71efea..fc63526d8695 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -2,37 +2,35 @@ /* Written 1995-2000 by Werner Almesberger, EPFL ICA */ - #include #include #include #include #include #include +#include #include -#include - -int atm_charge(struct atm_vcc *vcc,int truesize) +int atm_charge(struct atm_vcc *vcc, int truesize) { - atm_force_charge(vcc,truesize); + atm_force_charge(vcc, truesize); if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf) return 1; - atm_return(vcc,truesize); + atm_return(vcc, truesize); atomic_inc(&vcc->stats->rx_drop); return 0; } +EXPORT_SYMBOL(atm_charge); - -struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, - gfp_t gfp_flags) +struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size, + gfp_t gfp_flags) { struct sock *sk = sk_atm(vcc); int guess = atm_guess_pdu2truesize(pdu_size); - atm_force_charge(vcc,guess); + atm_force_charge(vcc, guess); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { - struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags); + struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags); if (skb) { atomic_add(skb->truesize-guess, @@ -40,10 +38,11 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, return skb; } } - atm_return(vcc,guess); + atm_return(vcc, guess); atomic_inc(&vcc->stats->rx_drop); return NULL; } +EXPORT_SYMBOL(atm_alloc_charge); /* @@ -73,7 +72,6 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, * else * */ - int atm_pcr_goal(const struct atm_trafprm *tp) { if (tp->pcr && tp->pcr != ATM_MAX_PCR) @@ -84,26 +82,20 @@ int atm_pcr_goal(const struct atm_trafprm *tp) return -tp->max_pcr; return 0; } +EXPORT_SYMBOL(atm_pcr_goal); - -void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to) +void sonet_copy_stats(struct k_sonet_stats *from, struct sonet_stats *to) { #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) __SONET_ITEMS #undef __HANDLE_ITEM } +EXPORT_SYMBOL(sonet_copy_stats); - -void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to) +void sonet_subtract_stats(struct k_sonet_stats *from, struct sonet_stats *to) { -#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i) +#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) __SONET_ITEMS #undef __HANDLE_ITEM } - - -EXPORT_SYMBOL(atm_charge); -EXPORT_SYMBOL(atm_alloc_charge); -EXPORT_SYMBOL(atm_pcr_goal); -EXPORT_SYMBOL(sonet_copy_stats); EXPORT_SYMBOL(sonet_subtract_stats); -- GitLab From f0a6cb118d7f9e72799a9c0c13f75d1b236a6546 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:03 +0000 Subject: [PATCH 1240/3892] net/atm/atm_sysfs.c: checkpatch cleanups Add space after for Indent switch/case statements 80 column wrapping Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/atm_sysfs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index b5674dc2083d..f693b78eb467 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -42,13 +42,14 @@ static ssize_t show_atmaddress(struct device *cdev, spin_lock_irqsave(&adev->lock, flags); list_for_each_entry(aaddr, &adev->local, entry) { - for(i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) { + for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) { if (j == *fmt) { pos += sprintf(pos, "."); ++fmt; j = 0; } - pos += sprintf(pos, "%02x", aaddr->addr.sas_addr.prv[i]); + pos += sprintf(pos, "%02x", + aaddr->addr.sas_addr.prv[i]); } pos += sprintf(pos, "\n"); } @@ -78,17 +79,17 @@ static ssize_t show_link_rate(struct device *cdev, /* show the link rate, not the data rate */ switch (adev->link_rate) { - case ATM_OC3_PCR: - link_rate = 155520000; - break; - case ATM_OC12_PCR: - link_rate = 622080000; - break; - case ATM_25_PCR: - link_rate = 25600000; - break; - default: - link_rate = adev->link_rate * 8 * 53; + case ATM_OC3_PCR: + link_rate = 155520000; + break; + case ATM_OC12_PCR: + link_rate = 622080000; + break; + case ATM_25_PCR: + link_rate = 25600000; + break; + default: + link_rate = adev->link_rate * 8 * 53; } pos += sprintf(pos, "%d\n", link_rate); -- GitLab From 641d729eb6236db0ce33e2b07a7f93193e60ea5a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:04 +0000 Subject: [PATCH 1241/3892] net/atm/br2684.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/br2684.c | 72 +++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/net/atm/br2684.c b/net/atm/br2684.c index d72b1a579911..4d64d87e7578 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -28,20 +28,14 @@ #include "common.h" -#ifdef SKB_DEBUG static void skb_debug(const struct sk_buff *skb) { +#ifdef SKB_DEBUG #define NUM2PRINT 50 - char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */ - int i = 0; - for (i = 0; i < skb->len && i < NUM2PRINT; i++) { - sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); - } - printk(KERN_DEBUG "br2684: skb: %s\n", buf); -} -#else -#define skb_debug(skb) do {} while (0) + print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET, + 16, 1, skb->data, min(NUM2PRINT, skb->len), true); #endif +} #define BR2684_ETHERTYPE_LEN 2 #define BR2684_PAD_LEN 2 @@ -70,7 +64,7 @@ struct br2684_vcc { struct atm_vcc *atmvcc; struct net_device *device; /* keep old push, pop functions for chaining */ - void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb); + void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); enum br2684_encaps encaps; struct list_head brvccs; @@ -302,7 +296,8 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg) struct br2684_dev *brdev; read_lock(&devs_lock); brdev = BRPRIV(br2684_find_dev(&fs.ifspec)); - if (brdev == NULL || list_empty(&brdev->brvccs) || brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ + if (brdev == NULL || list_empty(&brdev->brvccs) || + brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ brvcc = NULL; else brvcc = list_entry_brvcc(brdev->brvccs.next); @@ -378,29 +373,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) __skb_trim(skb, skb->len - 4); /* accept packets that have "ipv[46]" in the snap header */ - if ((skb->len >= (sizeof(llc_oui_ipv4))) - && - (memcmp - (skb->data, llc_oui_ipv4, - sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { - if (memcmp - (skb->data + 6, ethertype_ipv6, - sizeof(ethertype_ipv6)) == 0) + if ((skb->len >= (sizeof(llc_oui_ipv4))) && + (memcmp(skb->data, llc_oui_ipv4, + sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { + if (memcmp(skb->data + 6, ethertype_ipv6, + sizeof(ethertype_ipv6)) == 0) skb->protocol = htons(ETH_P_IPV6); - else if (memcmp - (skb->data + 6, ethertype_ipv4, - sizeof(ethertype_ipv4)) == 0) + else if (memcmp(skb->data + 6, ethertype_ipv4, + sizeof(ethertype_ipv4)) == 0) skb->protocol = htons(ETH_P_IP); else goto error; skb_pull(skb, sizeof(llc_oui_ipv4)); skb_reset_network_header(skb); skb->pkt_type = PACKET_HOST; - /* - * Let us waste some time for checking the encapsulation. - * Note, that only 7 char is checked so frames with a valid FCS - * are also accepted (but FCS is not checked of course). - */ + /* + * Let us waste some time for checking the encapsulation. + * Note, that only 7 char is checked so frames with a valid FCS + * are also accepted (but FCS is not checked of course). + */ } else if ((skb->len >= sizeof(llc_oui_pid_pad)) && (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) { skb_pull(skb, sizeof(llc_oui_pid_pad)); @@ -495,12 +486,12 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) err = -EEXIST; goto error; } - if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || - be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != - BR2684_ENCAPS_VC - && be.encaps != - BR2684_ENCAPS_LLC) - || be.min_size != 0) { + if (be.fcs_in != BR2684_FCSIN_NO || + be.fcs_out != BR2684_FCSOUT_NO || + be.fcs_auto || be.has_vpiid || be.send_padding || + (be.encaps != BR2684_ENCAPS_VC && + be.encaps != BR2684_ENCAPS_LLC) || + be.min_size != 0) { err = -EINVAL; goto error; } @@ -541,7 +532,8 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) } __module_get(THIS_MODULE); return 0; - error: + +error: write_unlock_irq(&devs_lock); kfree(brvcc); return err; @@ -587,7 +579,7 @@ static void br2684_setup_routed(struct net_device *netdev) INIT_LIST_HEAD(&brdev->brvccs); } -static int br2684_create(void __user * arg) +static int br2684_create(void __user *arg) { int err; struct net_device *netdev; @@ -597,9 +589,8 @@ static int br2684_create(void __user * arg) pr_debug("\n"); - if (copy_from_user(&ni, arg, sizeof ni)) { + if (copy_from_user(&ni, arg, sizeof ni)) return -EFAULT; - } if (ni.media & BR2684_FLAG_ROUTED) payload = p_routed; @@ -607,9 +598,8 @@ static int br2684_create(void __user * arg) payload = p_bridged; ni.media &= 0xffff; /* strip flags */ - if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { + if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) return -EINVAL; - } netdev = alloc_netdev(sizeof(struct br2684_dev), ni.ifname[0] ? ni.ifname : "nas%d", -- GitLab From e956ea1b7de1df5ae4d6dc3e7460ed9e140803cd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:05 +0000 Subject: [PATCH 1242/3892] net/atm/clip.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/clip.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/net/atm/clip.c b/net/atm/clip.c index d7939fd58cd3..ebfa022008f7 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -32,10 +32,10 @@ #include #include /* for struct rtable and routing */ #include /* icmp_send */ -#include /* for HZ */ +#include /* for HZ */ +#include #include /* for htons etc. */ #include /* save/restore_flags */ -#include #include #include "common.h" @@ -56,10 +56,10 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) pr_debug("(%d)\n", type); if (!atmarpd) return -EUNATCH; - skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); + skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC); if (!skb) return -ENOMEM; - ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl)); + ctrl = (struct atmarp_ctrl *)skb_put(skb, sizeof(struct atmarp_ctrl)); ctrl->type = type; ctrl->itf_num = itf; ctrl->ip = ip; @@ -111,7 +111,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) goto out; } pr_crit("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc); - out: +out: netif_tx_unlock_bh(entry->neigh->dev); } @@ -205,12 +205,12 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) } ATM_SKB(skb)->vcc = vcc; skb_reset_mac_header(skb); - if (!clip_vcc->encap - || skb->len < RFC1483LLC_LEN - || memcmp(skb->data, llc_oui, sizeof (llc_oui))) + if (!clip_vcc->encap || + skb->len < RFC1483LLC_LEN || + memcmp(skb->data, llc_oui, sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP); else { - skb->protocol = ((__be16 *) skb->data)[3]; + skb->protocol = ((__be16 *)skb->data)[3]; skb_pull(skb, RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { skb->dev->stats.rx_packets++; @@ -644,7 +644,6 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event, return clip_device_event(this, NETDEV_CHANGE, in_dev->dev); } - static struct notifier_block clip_dev_notifier = { .notifier_call = clip_device_event, }; @@ -670,7 +669,6 @@ static void atmarpd_close(struct atm_vcc *vcc) module_put(THIS_MODULE); } - static struct atmdev_ops atmarpd_dev_ops = { .close = atmarpd_close }; @@ -692,11 +690,11 @@ static int atm_init_atmarp(struct atm_vcc *vcc) return -EADDRINUSE; } - mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ); + mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ); atmarpd = vcc; - set_bit(ATM_VF_META,&vcc->flags); - set_bit(ATM_VF_READY,&vcc->flags); + set_bit(ATM_VF_META, &vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); /* allow replies and avoid getting closed if signaling dies */ vcc->dev = &atmarpd_dev; vcc_insert_socket(sk_atm(vcc)); -- GitLab From a8147d737bd37bd51bb01737ac9c17a2cfc02a38 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:06 +0000 Subject: [PATCH 1243/3892] net/atm/common.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/common.c | 338 ++++++++++++++++++++++++----------------------- 1 file changed, 173 insertions(+), 165 deletions(-) diff --git a/net/atm/common.c b/net/atm/common.c index 17f7e5f2131b..74d095a081e3 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -19,11 +19,10 @@ #include #include #include /* struct sock */ +#include +#include -#include #include -#include - #include "resources.h" /* atm_find_dev */ #include "common.h" /* prototypes */ @@ -32,13 +31,15 @@ #include "signaling.h" /* for WAITING and sigd_attach */ struct hlist_head vcc_hash[VCC_HTABLE_SIZE]; +EXPORT_SYMBOL(vcc_hash); + DEFINE_RWLOCK(vcc_sklist_lock); +EXPORT_SYMBOL(vcc_sklist_lock); static void __vcc_insert_socket(struct sock *sk) { struct atm_vcc *vcc = atm_sk(sk); - struct hlist_head *head = &vcc_hash[vcc->vci & - (VCC_HTABLE_SIZE - 1)]; + struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)]; sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1); sk_add_node(sk, head); } @@ -49,6 +50,7 @@ void vcc_insert_socket(struct sock *sk) __vcc_insert_socket(sk); write_unlock_irq(&vcc_sklist_lock); } +EXPORT_SYMBOL(vcc_insert_socket); static void vcc_remove_socket(struct sock *sk) { @@ -57,8 +59,7 @@ static void vcc_remove_socket(struct sock *sk) write_unlock_irq(&vcc_sklist_lock); } - -static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) +static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size) { struct sk_buff *skb; struct sock *sk = sk_atm(vcc); @@ -70,23 +71,20 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) } while (!(skb = alloc_skb(size, GFP_KERNEL))) schedule(); - pr_debug("AlTx %d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); + pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); atomic_add(skb->truesize, &sk->sk_wmem_alloc); return skb; } - -EXPORT_SYMBOL(vcc_hash); -EXPORT_SYMBOL(vcc_sklist_lock); -EXPORT_SYMBOL(vcc_insert_socket); - static void vcc_sock_destruct(struct sock *sk) { if (atomic_read(&sk->sk_rmem_alloc)) - printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc)); + printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n", + __func__, atomic_read(&sk->sk_rmem_alloc)); if (atomic_read(&sk->sk_wmem_alloc)) - printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc)); + printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n", + __func__, atomic_read(&sk->sk_wmem_alloc)); } static void vcc_def_wakeup(struct sock *sk) @@ -142,8 +140,8 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family) vcc = atm_sk(sk); vcc->dev = NULL; - memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); - memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); + memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc)); + memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc)); vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */ atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_rmem_alloc, 0); @@ -156,7 +154,6 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family) return 0; } - static void vcc_destroy_socket(struct sock *sk) { struct atm_vcc *vcc = atm_sk(sk); @@ -171,7 +168,7 @@ static void vcc_destroy_socket(struct sock *sk) vcc->push(vcc, NULL); /* atmarpd has no push */ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - atm_return(vcc,skb->truesize); + atm_return(vcc, skb->truesize); kfree_skb(skb); } @@ -182,7 +179,6 @@ static void vcc_destroy_socket(struct sock *sk) vcc_remove_socket(sk); } - int vcc_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -197,7 +193,6 @@ int vcc_release(struct socket *sock) return 0; } - void vcc_release_async(struct atm_vcc *vcc, int reply) { struct sock *sk = sk_atm(vcc); @@ -208,8 +203,6 @@ void vcc_release_async(struct atm_vcc *vcc, int reply) clear_bit(ATM_VF_WAITING, &vcc->flags); sk->sk_state_change(sk); } - - EXPORT_SYMBOL(vcc_release_async); @@ -235,36 +228,37 @@ void atm_dev_release_vccs(struct atm_dev *dev) write_unlock_irq(&vcc_sklist_lock); } - -static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) +static int adjust_tp(struct atm_trafprm *tp, unsigned char aal) { int max_sdu; - if (!tp->traffic_class) return 0; + if (!tp->traffic_class) + return 0; switch (aal) { - case ATM_AAL0: - max_sdu = ATM_CELL_SIZE-1; - break; - case ATM_AAL34: - max_sdu = ATM_MAX_AAL34_PDU; - break; - default: - pr_warning("AAL problems ... (%d)\n", aal); - /* fall through */ - case ATM_AAL5: - max_sdu = ATM_MAX_AAL5_PDU; + case ATM_AAL0: + max_sdu = ATM_CELL_SIZE-1; + break; + case ATM_AAL34: + max_sdu = ATM_MAX_AAL34_PDU; + break; + default: + pr_warning("AAL problems ... (%d)\n", aal); + /* fall through */ + case ATM_AAL5: + max_sdu = ATM_MAX_AAL5_PDU; } - if (!tp->max_sdu) tp->max_sdu = max_sdu; - else if (tp->max_sdu > max_sdu) return -EINVAL; - if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV; + if (!tp->max_sdu) + tp->max_sdu = max_sdu; + else if (tp->max_sdu > max_sdu) + return -EINVAL; + if (!tp->max_cdv) + tp->max_cdv = ATM_MAX_CDV; return 0; } - static int check_ci(const struct atm_vcc *vcc, short vpi, int vci) { - struct hlist_head *head = &vcc_hash[vci & - (VCC_HTABLE_SIZE - 1)]; + struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)]; struct hlist_node *node; struct sock *s; struct atm_vcc *walk; @@ -288,7 +282,6 @@ static int check_ci(const struct atm_vcc *vcc, short vpi, int vci) return 0; } - static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci) { static short p; /* poor man's per-device cache */ @@ -326,14 +319,13 @@ static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci) if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) && *vpi == ATM_VPI_ANY) { p++; - if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; + if (p >= 1 << vcc->dev->ci_range.vpi_bits) + p = 0; } - } - while (old_p != p || old_c != c); + } while (old_p != p || old_c != c); return -EADDRINUSE; } - static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, int vci) { @@ -361,27 +353,29 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, __vcc_insert_socket(sk); write_unlock_irq(&vcc_sklist_lock); switch (vcc->qos.aal) { - case ATM_AAL0: - error = atm_init_aal0(vcc); - vcc->stats = &dev->stats.aal0; - break; - case ATM_AAL34: - error = atm_init_aal34(vcc); - vcc->stats = &dev->stats.aal34; - break; - case ATM_NO_AAL: - /* ATM_AAL5 is also used in the "0 for default" case */ - vcc->qos.aal = ATM_AAL5; - /* fall through */ - case ATM_AAL5: - error = atm_init_aal5(vcc); - vcc->stats = &dev->stats.aal5; - break; - default: - error = -EPROTOTYPE; + case ATM_AAL0: + error = atm_init_aal0(vcc); + vcc->stats = &dev->stats.aal0; + break; + case ATM_AAL34: + error = atm_init_aal34(vcc); + vcc->stats = &dev->stats.aal34; + break; + case ATM_NO_AAL: + /* ATM_AAL5 is also used in the "0 for default" case */ + vcc->qos.aal = ATM_AAL5; + /* fall through */ + case ATM_AAL5: + error = atm_init_aal5(vcc); + vcc->stats = &dev->stats.aal5; + break; + default: + error = -EPROTOTYPE; } - if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal); - if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); + if (!error) + error = adjust_tp(&vcc->qos.txtp, vcc->qos.aal); + if (!error) + error = adjust_tp(&vcc->qos.rxtp, vcc->qos.aal); if (error) goto fail; pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal); @@ -397,7 +391,8 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, vcc->qos.rxtp.max_sdu); if (dev->ops->open) { - if ((error = dev->ops->open(vcc))) + error = dev->ops->open(vcc); + if (error) goto fail; } return 0; @@ -411,7 +406,6 @@ fail_module_put: return error; } - int vcc_connect(struct socket *sock, int itf, short vpi, int vci) { struct atm_dev *dev; @@ -427,16 +421,16 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) return -EINVAL; if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) - clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_PARTIAL, &vcc->flags); else - if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) + if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) return -EINVAL; pr_debug("(TX: cl %d,bw %d-%d,sdu %d; " "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu, vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr, - vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, + vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_sdu, vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ", vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); @@ -446,12 +440,14 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; if (likely(itf != ATM_ITF_ANY)) { - dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); + dev = try_then_request_module(atm_dev_lookup(itf), + "atm-device-%d", itf); } else { dev = NULL; mutex_lock(&atm_dev_mutex); if (!list_empty(&atm_devs)) { - dev = list_entry(atm_devs.next, struct atm_dev, dev_list); + dev = list_entry(atm_devs.next, + struct atm_dev, dev_list); atm_dev_hold(dev); } mutex_unlock(&atm_dev_mutex); @@ -464,13 +460,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) return error; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) - set_bit(ATM_VF_PARTIAL,&vcc->flags); - if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags)) + set_bit(ATM_VF_PARTIAL, &vcc->flags); + if (test_bit(ATM_VF_READY, &ATM_SD(sock)->flags)) sock->state = SS_CONNECTED; return 0; } - int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { @@ -484,8 +479,8 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (flags & ~MSG_DONTWAIT) /* only handle MSG_DONTWAIT */ return -EOPNOTSUPP; vcc = ATM_SD(sock); - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags) || + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || + test_bit(ATM_VF_CLOSE, &vcc->flags) || !test_bit(ATM_VF_READY, &vcc->flags)) return 0; @@ -509,7 +504,6 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, return copied; } - int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { @@ -517,7 +511,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, DEFINE_WAIT(wait); struct atm_vcc *vcc; struct sk_buff *skb; - int eff,error; + int eff, error; const void __user *buff; int size; @@ -556,7 +550,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, eff = (size+3) & ~3; /* align to word boundary */ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); error = 0; - while (!(skb = alloc_tx(vcc,eff))) { + while (!(skb = alloc_tx(vcc, eff))) { if (m->msg_flags & MSG_DONTWAIT) { error = -EAGAIN; break; @@ -566,9 +560,9 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, error = -ERESTARTSYS; break; } - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags) || - !test_bit(ATM_VF_READY,&vcc->flags)) { + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || + test_bit(ATM_VF_CLOSE, &vcc->flags) || + !test_bit(ATM_VF_READY, &vcc->flags)) { error = -EPIPE; send_sig(SIGPIPE, current, 0); break; @@ -580,20 +574,20 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, goto out; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; - if (copy_from_user(skb_put(skb,size),buff,size)) { + if (copy_from_user(skb_put(skb, size), buff, size)) { kfree_skb(skb); error = -EFAULT; goto out; } - if (eff != size) memset(skb->data+size,0,eff-size); - error = vcc->dev->ops->send(vcc,skb); + if (eff != size) + memset(skb->data + size, 0, eff-size); + error = vcc->dev->ops->send(vcc, skb); error = error ? error : size; out: release_sock(sk); return error; } - unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; @@ -629,8 +623,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait) return mask; } - -static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) +static int atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) { int error; @@ -642,25 +635,31 @@ static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class || qos->txtp.traffic_class != vcc->qos.txtp.traffic_class) return -EINVAL; - error = adjust_tp(&qos->txtp,qos->aal); - if (!error) error = adjust_tp(&qos->rxtp,qos->aal); - if (error) return error; - if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; + error = adjust_tp(&qos->txtp, qos->aal); + if (!error) + error = adjust_tp(&qos->rxtp, qos->aal); + if (error) + return error; + if (!vcc->dev->ops->change_qos) + return -EOPNOTSUPP; if (sk_atm(vcc)->sk_family == AF_ATMPVC) - return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET); - return svc_change_qos(vcc,qos); + return vcc->dev->ops->change_qos(vcc, qos, ATM_MF_SET); + return svc_change_qos(vcc, qos); } - static int check_tp(const struct atm_trafprm *tp) { /* @@@ Should be merged with adjust_tp */ - if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0; + if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) + return 0; if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr && - !tp->max_pcr) return -EINVAL; - if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL; + !tp->max_pcr) + return -EINVAL; + if (tp->min_pcr == ATM_MAX_PCR) + return -EINVAL; if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && - tp->min_pcr > tp->max_pcr) return -EINVAL; + tp->min_pcr > tp->max_pcr) + return -EINVAL; /* * We allow pcr to be outside [min_pcr,max_pcr], because later * adjustment may still push it in the valid range. @@ -668,7 +667,6 @@ static int check_tp(const struct atm_trafprm *tp) return 0; } - static int check_qos(const struct atm_qos *qos) { int error; @@ -678,9 +676,11 @@ static int check_qos(const struct atm_qos *qos) if (qos->txtp.traffic_class != qos->rxtp.traffic_class && qos->txtp.traffic_class && qos->rxtp.traffic_class && qos->txtp.traffic_class != ATM_ANYCLASS && - qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL; + qos->rxtp.traffic_class != ATM_ANYCLASS) + return -EINVAL; error = check_tp(&qos->txtp); - if (error) return error; + if (error) + return error; return check_tp(&qos->rxtp); } @@ -696,37 +696,41 @@ int vcc_setsockopt(struct socket *sock, int level, int optname, vcc = ATM_SD(sock); switch (optname) { - case SO_ATMQOS: - { - struct atm_qos qos; - - if (copy_from_user(&qos,optval,sizeof(qos))) - return -EFAULT; - error = check_qos(&qos); - if (error) return error; - if (sock->state == SS_CONNECTED) - return atm_change_qos(vcc,&qos); - if (sock->state != SS_UNCONNECTED) - return -EBADFD; - vcc->qos = qos; - set_bit(ATM_VF_HASQOS,&vcc->flags); - return 0; - } - case SO_SETCLP: - if (get_user(value,(unsigned long __user *)optval)) - return -EFAULT; - if (value) vcc->atm_options |= ATM_ATMOPT_CLP; - else vcc->atm_options &= ~ATM_ATMOPT_CLP; - return 0; - default: - if (level == SOL_SOCKET) return -EINVAL; - break; + case SO_ATMQOS: + { + struct atm_qos qos; + + if (copy_from_user(&qos, optval, sizeof(qos))) + return -EFAULT; + error = check_qos(&qos); + if (error) + return error; + if (sock->state == SS_CONNECTED) + return atm_change_qos(vcc, &qos); + if (sock->state != SS_UNCONNECTED) + return -EBADFD; + vcc->qos = qos; + set_bit(ATM_VF_HASQOS, &vcc->flags); + return 0; } - if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL; - return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen); + case SO_SETCLP: + if (get_user(value, (unsigned long __user *)optval)) + return -EFAULT; + if (value) + vcc->atm_options |= ATM_ATMOPT_CLP; + else + vcc->atm_options &= ~ATM_ATMOPT_CLP; + return 0; + default: + if (level == SOL_SOCKET) + return -EINVAL; + break; + } + if (!vcc->dev || !vcc->dev->ops->setsockopt) + return -EINVAL; + return vcc->dev->ops->setsockopt(vcc, level, optname, optval, optlen); } - int vcc_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { @@ -740,33 +744,33 @@ int vcc_getsockopt(struct socket *sock, int level, int optname, vcc = ATM_SD(sock); switch (optname) { - case SO_ATMQOS: - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) - return -EINVAL; - return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ? - -EFAULT : 0; - case SO_SETCLP: - return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : - 0,(unsigned long __user *)optval) ? -EFAULT : 0; - case SO_ATMPVC: - { - struct sockaddr_atmpvc pvc; - - if (!vcc->dev || - !test_bit(ATM_VF_ADDR,&vcc->flags)) - return -ENOTCONN; - pvc.sap_family = AF_ATMPVC; - pvc.sap_addr.itf = vcc->dev->number; - pvc.sap_addr.vpi = vcc->vpi; - pvc.sap_addr.vci = vcc->vci; - return copy_to_user(optval,&pvc,sizeof(pvc)) ? - -EFAULT : 0; - } - default: - if (level == SOL_SOCKET) return -EINVAL; + case SO_ATMQOS: + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) + return -EINVAL; + return copy_to_user(optval, &vcc->qos, sizeof(vcc->qos)) + ? -EFAULT : 0; + case SO_SETCLP: + return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0, + (unsigned long __user *)optval) ? -EFAULT : 0; + case SO_ATMPVC: + { + struct sockaddr_atmpvc pvc; + + if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags)) + return -ENOTCONN; + pvc.sap_family = AF_ATMPVC; + pvc.sap_addr.itf = vcc->dev->number; + pvc.sap_addr.vpi = vcc->vpi; + pvc.sap_addr.vci = vcc->vci; + return copy_to_user(optval, &pvc, sizeof(pvc)) ? -EFAULT : 0; + } + default: + if (level == SOL_SOCKET) + return -EINVAL; break; } - if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; + if (!vcc->dev || !vcc->dev->ops->getsockopt) + return -EINVAL; return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len); } @@ -774,22 +778,26 @@ static int __init atm_init(void) { int error; - if ((error = proto_register(&vcc_proto, 0)) < 0) + error = proto_register(&vcc_proto, 0); + if (error < 0) goto out; - - if ((error = atmpvc_init()) < 0) { + error = atmpvc_init(); + if (error < 0) { pr_err("atmpvc_init() failed with %d\n", error); goto out_unregister_vcc_proto; } - if ((error = atmsvc_init()) < 0) { + error = atmsvc_init(); + if (error < 0) { pr_err("atmsvc_init() failed with %d\n", error); goto out_atmpvc_exit; } - if ((error = atm_proc_init()) < 0) { + error = atm_proc_init(); + if (error < 0) { pr_err("atm_proc_init() failed with %d\n", error); goto out_atmsvc_exit; } - if ((error = atm_sysfs_init()) < 0) { + error = atm_sysfs_init(); + if (error < 0) { pr_err("atm_sysfs_init() failed with %d\n", error); goto out_atmproc_exit; } -- GitLab From 5ff7ef7911d100b6568c731b1d078f819da82d03 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:07 +0000 Subject: [PATCH 1244/3892] net/atm/ioctl.c: checkpatch cleanups Spacing cleanups Moved EXPORT_SYMBOL Mostly 80 column wrapped. switch/case cleanups Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/ioctl.c | 195 ++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 98 deletions(-) diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index b75afba1f72b..62dc8bfe6fe7 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -37,6 +37,7 @@ void register_atm_ioctl(struct atm_ioctl *ioctl) list_add_tail(&ioctl->list, &ioctl_list); mutex_unlock(&ioctl_mutex); } +EXPORT_SYMBOL(register_atm_ioctl); void deregister_atm_ioctl(struct atm_ioctl *ioctl) { @@ -44,129 +45,128 @@ void deregister_atm_ioctl(struct atm_ioctl *ioctl) list_del(&ioctl->list); mutex_unlock(&ioctl_mutex); } - -EXPORT_SYMBOL(register_atm_ioctl); EXPORT_SYMBOL(deregister_atm_ioctl); -static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat) +static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg, int compat) { struct sock *sk = sock->sk; struct atm_vcc *vcc; int error; - struct list_head * pos; + struct list_head *pos; void __user *argp = (void __user *)arg; vcc = ATM_SD(sock); switch (cmd) { - case SIOCOUTQ: - if (sock->state != SS_CONNECTED || - !test_bit(ATM_VF_READY, &vcc->flags)) { - error = -EINVAL; - goto done; - } - error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk), - (int __user *) argp) ? -EFAULT : 0; + case SIOCOUTQ: + if (sock->state != SS_CONNECTED || + !test_bit(ATM_VF_READY, &vcc->flags)) { + error = -EINVAL; + goto done; + } + error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk), + (int __user *)argp) ? -EFAULT : 0; + goto done; + case SIOCINQ: + { + struct sk_buff *skb; + + if (sock->state != SS_CONNECTED) { + error = -EINVAL; goto done; - case SIOCINQ: - { - struct sk_buff *skb; - - if (sock->state != SS_CONNECTED) { - error = -EINVAL; - goto done; - } - skb = skb_peek(&sk->sk_receive_queue); - error = put_user(skb ? skb->len : 0, - (int __user *)argp) ? -EFAULT : 0; - goto done; - } - case SIOCGSTAMP: /* borrowed from IP */ + } + skb = skb_peek(&sk->sk_receive_queue); + error = put_user(skb ? skb->len : 0, + (int __user *)argp) ? -EFAULT : 0; + goto done; + } + case SIOCGSTAMP: /* borrowed from IP */ #ifdef CONFIG_COMPAT - if (compat) - error = compat_sock_get_timestamp(sk, argp); - else + if (compat) + error = compat_sock_get_timestamp(sk, argp); + else #endif - error = sock_get_timestamp(sk, argp); - goto done; - case SIOCGSTAMPNS: /* borrowed from IP */ + error = sock_get_timestamp(sk, argp); + goto done; + case SIOCGSTAMPNS: /* borrowed from IP */ #ifdef CONFIG_COMPAT - if (compat) - error = compat_sock_get_timestampns(sk, argp); - else + if (compat) + error = compat_sock_get_timestampns(sk, argp); + else #endif - error = sock_get_timestampns(sk, argp); + error = sock_get_timestampns(sk, argp); + goto done; + case ATM_SETSC: + if (net_ratelimit()) + pr_warning("ATM_SETSC is obsolete; used by %s:%d\n", + current->comm, task_pid_nr(current)); + error = 0; + goto done; + case ATMSIGD_CTRL: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; goto done; - case ATM_SETSC: - if (net_ratelimit()) - pr_warning("ATM_SETSC is obsolete; used by %s:%d\n", - current->comm, task_pid_nr(current)); - error = 0; + } + /* + * The user/kernel protocol for exchanging signalling + * info uses kernel pointers as opaque references, + * so the holder of the file descriptor can scribble + * on the kernel... so we should make sure that we + * have the same privileges that /proc/kcore needs + */ + if (!capable(CAP_SYS_RAWIO)) { + error = -EPERM; goto done; - case ATMSIGD_CTRL: - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - /* - * The user/kernel protocol for exchanging signalling - * info uses kernel pointers as opaque references, - * so the holder of the file descriptor can scribble - * on the kernel... so we should make sure that we - * have the same privileges that /proc/kcore needs - */ - if (!capable(CAP_SYS_RAWIO)) { - error = -EPERM; - goto done; - } + } #ifdef CONFIG_COMPAT - /* WTF? I don't even want to _think_ about making this - work for 32-bit userspace. TBH I don't really want - to think about it at all. dwmw2. */ - if (compat) { - if (net_ratelimit()) - pr_warning("32-bit task cannot be atmsigd\n"); - error = -EINVAL; - goto done; - } + /* WTF? I don't even want to _think_ about making this + work for 32-bit userspace. TBH I don't really want + to think about it at all. dwmw2. */ + if (compat) { + if (net_ratelimit()) + pr_warning("32-bit task cannot be atmsigd\n"); + error = -EINVAL; + goto done; + } #endif - error = sigd_attach(vcc); - if (!error) - sock->state = SS_CONNECTED; + error = sigd_attach(vcc); + if (!error) + sock->state = SS_CONNECTED; + goto done; + case ATM_SETBACKEND: + case ATM_NEWBACKENDIF: + { + atm_backend_t backend; + error = get_user(backend, (atm_backend_t __user *)argp); + if (error) goto done; - case ATM_SETBACKEND: - case ATM_NEWBACKENDIF: - { - atm_backend_t backend; - error = get_user(backend, (atm_backend_t __user *) argp); - if (error) - goto done; - switch (backend) { - case ATM_BACKEND_PPP: - request_module("pppoatm"); - break; - case ATM_BACKEND_BR2684: - request_module("br2684"); - break; - } - } - break; - case ATMMPC_CTRL: - case ATMMPC_DATA: - request_module("mpoa"); - break; - case ATMARPD_CTRL: - request_module("clip"); + switch (backend) { + case ATM_BACKEND_PPP: + request_module("pppoatm"); break; - case ATMLEC_CTRL: - request_module("lec"); + case ATM_BACKEND_BR2684: + request_module("br2684"); break; + } + break; + } + case ATMMPC_CTRL: + case ATMMPC_DATA: + request_module("mpoa"); + break; + case ATMARPD_CTRL: + request_module("clip"); + break; + case ATMLEC_CTRL: + request_module("lec"); + break; } error = -ENOIOCTLCMD; mutex_lock(&ioctl_mutex); list_for_each(pos, &ioctl_list) { - struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list); + struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list); if (try_module_get(ic->owner)) { error = ic->ioctl(sock, cmd, arg); module_put(ic->owner); @@ -185,7 +185,6 @@ done: return error; } - int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { return do_vcc_ioctl(sock, cmd, arg, 0); @@ -288,8 +287,8 @@ static int do_atmif_sioc(struct socket *sock, unsigned int cmd, sioc = compat_alloc_user_space(sizeof(*sioc)); sioc32 = compat_ptr(arg); - if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) - || get_user(data, &sioc32->arg)) + if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || + get_user(data, &sioc32->arg)) return -EFAULT; datap = compat_ptr(data); if (put_user(datap, &sioc->arg)) -- GitLab From c48192a7075fb218d92810fbe76ddd8732f2bbb8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:08 +0000 Subject: [PATCH 1245/3892] net/atm/lec.c: checkpatch cleanups Convert #include Use print_hex_dump Move embedded assigns out of tests Move trailing statements to new lines Remove unnecessary braces around single line statements switch/case cleanups Removed paren around returns Use %pM Moved leading continuation logical tests to end of previous line Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/lec.c | 284 ++++++++++++++++++++++++-------------------------- 1 file changed, 136 insertions(+), 148 deletions(-) diff --git a/net/atm/lec.c b/net/atm/lec.c index 6873813c3c99..aefd278d6af6 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -87,17 +87,19 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, int is_rdesc, struct lec_arp_table **ret_entry); static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, - const unsigned char *atm_addr, unsigned long remoteflag, + const unsigned char *atm_addr, + unsigned long remoteflag, unsigned int targetless_le_arp); static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc); static void lec_set_flush_tran_id(struct lec_priv *priv, const unsigned char *atm_addr, unsigned long tran_id); -static void lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, +static void lec_vcc_added(struct lec_priv *priv, + const struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, - void (*old_push) (struct atm_vcc *vcc, - struct sk_buff *skb)); + void (*old_push)(struct atm_vcc *vcc, + struct sk_buff *skb)); static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); /* must be done under lec_arp_lock */ @@ -112,7 +114,6 @@ static inline void lec_arp_put(struct lec_arp_table *entry) kfree(entry); } - static struct lane2_ops lane2_ops = { lane2_resolve, /* resolve, spec 3.1.3 */ lane2_associate_req, /* associate_req, spec 3.1.4 */ @@ -150,7 +151,8 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) mesg = (struct atmlec_msg *)skb2->data; mesg->type = l_topology_change; buff += 4; - mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */ + mesg->content.normal.flag = *buff & 0x01; + /* 0x01 is topology change */ priv = netdev_priv(dev); atm_force_charge(priv->lecd, skb2->truesize); @@ -263,14 +265,10 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */ #endif int is_rdesc; -#if DUMP_PACKETS > 0 - char buf[300]; - int i = 0; -#endif /* DUMP_PACKETS >0 */ pr_debug("called\n"); if (!priv->lecd) { - printk("%s:No lecd attached\n", dev->name); + pr_info("%s:No lecd attached\n", dev->name); dev->stats.tx_errors++; netif_stop_queue(dev); kfree_skb(skb); @@ -315,23 +313,17 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, } #endif -#if DUMP_PACKETS > 0 - printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name, - skb->len, priv->lecid); #if DUMP_PACKETS >= 2 - for (i = 0; i < skb->len && i < 99; i++) { - sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); - } +#define MAX_DUMP_SKB 99 #elif DUMP_PACKETS >= 1 - for (i = 0; i < skb->len && i < 30; i++) { - sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); - } +#define MAX_DUMP_SKB 30 +#endif +#if DUMP_PACKETS >= 1 + printk(KERN_DEBUG "%s: send datalen:%ld lecid:%4.4x\n", + dev->name, skb->len, priv->lecid); + print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1, + skb->data, min(skb->len, MAX_DUMP_SKB), true); #endif /* DUMP_PACKETS >= 1 */ - if (i == skb->len) - printk("%s\n", buf); - else - printk("%s...\n", buf); -#endif /* DUMP_PACKETS > 0 */ /* Minimum ethernet-frame size */ #ifdef CONFIG_TR @@ -385,7 +377,8 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, goto out; } #if DUMP_PACKETS > 0 - printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci); + printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d\n", + dev->name, vcc->vpi, vcc->vci); #endif /* DUMP_PACKETS > 0 */ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { @@ -442,14 +435,12 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type); switch (mesg->type) { case l_set_mac_addr: - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = mesg->content.normal.mac_addr[i]; - } break; case l_del_mac_addr: - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = 0; - } break; case l_addr_delete: lec_addr_delete(priv, mesg->content.normal.atm_addr, @@ -497,13 +488,14 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) priv->flush_timeout = (mesg->content.config.flush_timeout * HZ); priv->path_switching_delay = (mesg->content.config.path_switching_delay * HZ); - priv->lane_version = mesg->content.config.lane_version; /* LANE2 */ + priv->lane_version = mesg->content.config.lane_version; + /* LANE2 */ priv->lane2_ops = NULL; if (priv->lane_version > 1) priv->lane2_ops = &lane2_ops; if (dev_set_mtu(dev, mesg->content.config.mtu)) - printk("%s: change_mtu to %d failed\n", dev->name, - mesg->content.config.mtu); + pr_info("%s: change_mtu to %d failed\n", + dev->name, mesg->content.config.mtu); priv->is_proxy = mesg->content.config.is_proxy; break; case l_flush_tran_id: @@ -524,16 +516,15 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) break; if (br_fdb_test_addr_hook(dev, - mesg->content.proxy.mac_addr)) { + mesg->content.proxy.mac_addr)) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; struct sock *sk; pr_debug("%s: entry found, responding to zeppelin\n", dev->name); - skb2 = - alloc_skb(sizeof(struct atmlec_msg), - GFP_ATOMIC); + skb2 = alloc_skb(sizeof(struct atmlec_msg), + GFP_ATOMIC); if (skb2 == NULL) break; skb2->len = sizeof(struct atmlec_msg); @@ -548,7 +539,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; default: - printk("%s: Unknown message type %d\n", dev->name, mesg->type); + pr_info("%s: Unknown message type %d\n", dev->name, mesg->type); dev_kfree_skb(skb); return -EINVAL; } @@ -569,14 +560,13 @@ static void lec_atm_close(struct atm_vcc *vcc) lec_arp_destroy(priv); if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) - printk("%s lec_atm_close: closing with messages pending\n", - dev->name); + pr_info("%s closing with messages pending\n", dev->name); while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); dev_kfree_skb(skb); } - printk("%s: Shut down!\n", dev->name); + pr_info("%s: Shut down!\n", dev->name); module_put(THIS_MODULE); } @@ -605,9 +595,8 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, struct sk_buff *skb; struct atmlec_msg *mesg; - if (!priv || !priv->lecd) { + if (!priv || !priv->lecd) return -1; - } skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); if (!skb) return -1; @@ -688,7 +677,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) struct net_device *dev = (struct net_device *)vcc->proto_data; struct lec_priv *priv = netdev_priv(dev); -#if DUMP_PACKETS >0 +#if DUMP_PACKETS > 0 printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci); #endif @@ -767,9 +756,8 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) dev_kfree_skb(skb); return; } - if (!hlist_empty(&priv->lec_arp_empty_ones)) { + if (!hlist_empty(&priv->lec_arp_empty_ones)) lec_arp_check_empties(priv, vcc, skb); - } skb_pull(skb, 2); /* skip lec_id */ #ifdef CONFIG_TR if (priv->is_trdev) @@ -816,7 +804,8 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || !dev_lec[ioc_data.dev_num]) return -EINVAL; - if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL))) + vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL); + if (!vpriv) return -ENOMEM; vpriv->xoff = 0; vpriv->old_pop = vcc->pop; @@ -907,9 +896,8 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) priv->flush_timeout = (4 * HZ); priv->path_switching_delay = (6 * HZ); - if (dev_lec[i]->flags & IFF_UP) { + if (dev_lec[i]->flags & IFF_UP) netif_start_queue(dev_lec[i]); - } __module_get(THIS_MODULE); return i; } @@ -1111,7 +1099,9 @@ static int lec_seq_show(struct seq_file *seq, void *v) else { struct lec_state *state = seq->private; struct net_device *dev = state->dev; - struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next); + struct lec_arp_table *entry = hlist_entry(state->node, + struct lec_arp_table, + next); seq_printf(seq, "%s ", dev->name); lec_info(seq, entry); @@ -1191,7 +1181,7 @@ static int __init lane_module_init(void) #endif register_atm_ioctl(&lane_ioctl_ops); - printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); + pr_info("lec.c: " __DATE__ " " __TIME__ " initialized\n"); return 0; } @@ -1280,13 +1270,13 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, struct lec_priv *priv = netdev_priv(dev); if (compare_ether_addr(lan_dst, dev->dev_addr)) - return (0); /* not our mac address */ + return 0; /* not our mac address */ kfree(priv->tlvs); /* NULL if there was no previous association */ priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL); if (priv->tlvs == NULL) - return (0); + return 0; priv->sizeoftlvs = sizeoftlvs; skb = alloc_skb(sizeoftlvs, GFP_ATOMIC); @@ -1296,12 +1286,12 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, skb_copy_to_linear_data(skb, tlvs, sizeoftlvs); retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb); if (retval != 0) - printk("lec.c: lane2_associate_req() failed\n"); + pr_info("lec.c: lane2_associate_req() failed\n"); /* * If the previous association has changed we must * somehow notify other LANE entities about the change */ - return (1); + return 1; } /* @@ -1334,12 +1324,12 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, entry->sizeoftlvs = sizeoftlvs; #endif #if 0 - printk("lec.c: lane2_associate_ind()\n"); - printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); + pr_info("\n"); + pr_info("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); while (i < sizeoftlvs) - printk("%02x ", tlvs[i++]); + pr_cont("%02x ", tlvs[i++]); - printk("\n"); + pr_cont("\n"); #endif /* tell MPOA about the TLVs we saw */ @@ -1359,13 +1349,13 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, #include #include -#include +#include #include #include #include #if 0 -#define pr_debug(format,args...) +#define pr_debug(format, args...) /* #define pr_debug printk */ @@ -1381,7 +1371,7 @@ static void lec_arp_expire_arp(unsigned long data); * Arp table funcs */ -#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1)) +#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1)) /* * Initialization of arp-cache @@ -1390,9 +1380,8 @@ static void lec_arp_init(struct lec_priv *priv) { unsigned short i; - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { + for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) INIT_HLIST_HEAD(&priv->lec_arp_tables[i]); - } INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); INIT_HLIST_HEAD(&priv->lec_no_forward); INIT_HLIST_HEAD(&priv->mcast_fwds); @@ -1449,20 +1438,23 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) struct lec_arp_table *entry; int i, remove_vcc = 1; - if (!to_remove) { + if (!to_remove) return -1; - } hlist_del(&to_remove->next); del_timer(&to_remove->timer); - /* If this is the only MAC connected to this VCC, also tear down the VCC */ + /* + * If this is the only MAC connected to this VCC, + * also tear down the VCC + */ if (to_remove->status >= ESI_FLUSH_PENDING) { /* * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT */ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry(entry, node, + &priv->lec_arp_tables[i], next) { if (memcmp(to_remove->atm_addr, entry->atm_addr, ATM_ESA_LEN) == 0) { remove_vcc = 0; @@ -1493,9 +1485,8 @@ static const char *get_status_string(unsigned char st) return "ESI_FLUSH_PENDING"; case ESI_FORWARD_DIRECT: return "ESI_FORWARD_DIRECT"; - default: - return ""; } + return ""; } static void dump_arp_table(struct lec_priv *priv) @@ -1505,18 +1496,15 @@ static void dump_arp_table(struct lec_priv *priv) char buf[256]; int i, j, offset; - printk("Dump %p:\n", priv); + pr_info("Dump %p:\n", priv); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry(rulla, node, + &priv->lec_arp_tables[i], next) { offset = 0; offset += sprintf(buf, "%d: %p\n", i, rulla); - offset += sprintf(buf + offset, "Mac:"); - for (j = 0; j < ETH_ALEN; j++) { - offset += sprintf(buf + offset, - "%2.2x ", - rulla->mac_addr[j] & 0xff); - } - offset += sprintf(buf + offset, "Atm:"); + offset += sprintf(buf + offset, "Mac: %pM", + rulla->mac_addr); + offset += sprintf(buf + offset, " Atm:"); for (j = 0; j < ATM_ESA_LEN; j++) { offset += sprintf(buf + offset, "%2.2x ", @@ -1536,20 +1524,16 @@ static void dump_arp_table(struct lec_priv *priv) "Flags:%x, Packets_flooded:%x, Status: %s ", rulla->flags, rulla->packets_flooded, get_status_string(rulla->status)); - printk("%s\n", buf); + pr_info("%s\n", buf); } } if (!hlist_empty(&priv->lec_no_forward)) - printk("No forward\n"); + pr_info("No forward\n"); hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) { offset = 0; - offset += sprintf(buf + offset, "Mac:"); - for (j = 0; j < ETH_ALEN; j++) { - offset += sprintf(buf + offset, "%2.2x ", - rulla->mac_addr[j] & 0xff); - } - offset += sprintf(buf + offset, "Atm:"); + offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr); + offset += sprintf(buf + offset, " Atm:"); for (j = 0; j < ATM_ESA_LEN; j++) { offset += sprintf(buf + offset, "%2.2x ", rulla->atm_addr[j] & 0xff); @@ -1566,19 +1550,15 @@ static void dump_arp_table(struct lec_priv *priv) "Flags:%x, Packets_flooded:%x, Status: %s ", rulla->flags, rulla->packets_flooded, get_status_string(rulla->status)); - printk("%s\n", buf); + pr_info("%s\n", buf); } if (!hlist_empty(&priv->lec_arp_empty_ones)) - printk("Empty ones\n"); + pr_info("Empty ones\n"); hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) { offset = 0; - offset += sprintf(buf + offset, "Mac:"); - for (j = 0; j < ETH_ALEN; j++) { - offset += sprintf(buf + offset, "%2.2x ", - rulla->mac_addr[j] & 0xff); - } - offset += sprintf(buf + offset, "Atm:"); + offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr); + offset += sprintf(buf + offset, " Atm:"); for (j = 0; j < ATM_ESA_LEN; j++) { offset += sprintf(buf + offset, "%2.2x ", rulla->atm_addr[j] & 0xff); @@ -1595,19 +1575,15 @@ static void dump_arp_table(struct lec_priv *priv) "Flags:%x, Packets_flooded:%x, Status: %s ", rulla->flags, rulla->packets_flooded, get_status_string(rulla->status)); - printk("%s", buf); + pr_info("%s", buf); } if (!hlist_empty(&priv->mcast_fwds)) - printk("Multicast Forward VCCs\n"); + pr_info("Multicast Forward VCCs\n"); hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) { offset = 0; - offset += sprintf(buf + offset, "Mac:"); - for (j = 0; j < ETH_ALEN; j++) { - offset += sprintf(buf + offset, "%2.2x ", - rulla->mac_addr[j] & 0xff); - } - offset += sprintf(buf + offset, "Atm:"); + offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr); + offset += sprintf(buf + offset, " Atm:"); for (j = 0; j < ATM_ESA_LEN; j++) { offset += sprintf(buf + offset, "%2.2x ", rulla->atm_addr[j] & 0xff); @@ -1624,7 +1600,7 @@ static void dump_arp_table(struct lec_priv *priv) "Flags:%x, Packets_flooded:%x, Status: %s ", rulla->flags, rulla->packets_flooded, get_status_string(rulla->status)); - printk("%s\n", buf); + pr_info("%s\n", buf); } } @@ -1650,14 +1626,16 @@ static void lec_arp_destroy(struct lec_priv *priv) spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_tables[i], next) { lec_arp_remove(priv, entry); lec_arp_put(entry); } INIT_HLIST_HEAD(&priv->lec_arp_tables[i]); } - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_empty_ones, next) { del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); hlist_del(&entry->next); @@ -1665,7 +1643,8 @@ static void lec_arp_destroy(struct lec_priv *priv) } INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); - hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_no_forward, next) { del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); hlist_del(&entry->next); @@ -1698,9 +1677,8 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])]; hlist_for_each_entry(entry, node, head, next) { - if (!compare_ether_addr(mac_addr, entry->mac_addr)) { + if (!compare_ether_addr(mac_addr, entry->mac_addr)) return entry; - } } return NULL; } @@ -1712,7 +1690,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv, to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC); if (!to_return) { - printk("LEC: Arp entry kmalloc failed\n"); + pr_info("LEC: Arp entry kmalloc failed\n"); return NULL; } memcpy(to_return->mac_addr, mac_addr, ETH_ALEN); @@ -1802,7 +1780,8 @@ static void lec_arp_check_expire(struct work_struct *work) restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_tables[i], next) { if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change) time_to_check = priv->forward_delay_time; @@ -1811,9 +1790,9 @@ restart: pr_debug("About to expire: %lx - %lx > %lx\n", now, entry->last_used, time_to_check); - if (time_after(now, entry->last_used + time_to_check) - && !(entry->flags & LEC_PERMANENT_FLAG) - && !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ + if (time_after(now, entry->last_used + time_to_check) && + !(entry->flags & LEC_PERMANENT_FLAG) && + !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ /* Remove entry */ pr_debug("Entry timed out\n"); lec_arp_remove(priv, entry); @@ -1821,11 +1800,10 @@ restart: } else { /* Something else */ if ((entry->status == ESI_VC_PENDING || - entry->status == ESI_ARP_PENDING) - && time_after_eq(now, - entry->timestamp + - priv-> - max_unknown_frame_time)) { + entry->status == ESI_ARP_PENDING) && + time_after_eq(now, + entry->timestamp + + priv->max_unknown_frame_time)) { entry->timestamp = jiffies; entry->packets_flooded = 0; if (entry->status == ESI_VC_PENDING) @@ -1834,8 +1812,7 @@ restart: entry->atm_addr, NULL); } - if (entry->status == ESI_FLUSH_PENDING - && + if (entry->status == ESI_FLUSH_PENDING && time_after_eq(now, entry->timestamp + priv->path_switching_delay)) { struct sk_buff *skb; @@ -1863,7 +1840,8 @@ restart: * */ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - const unsigned char *mac_to_find, int is_rdesc, + const unsigned char *mac_to_find, + int is_rdesc, struct lec_arp_table **ret_entry) { unsigned long flags; @@ -1899,9 +1877,8 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, * If the LE_ARP cache entry is still pending, reset count to 0 * so another LE_ARP request can be made for this frame. */ - if (entry->status == ESI_ARP_PENDING) { + if (entry->status == ESI_ARP_PENDING) entry->no_tries = 0; - } /* * Data direct VC not yet set up, check to see if the unknown * frame count is greater than the limit. If the limit has @@ -1969,10 +1946,11 @@ lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, pr_debug("\n"); spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { - if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) - && (permanent || - !(entry->flags & LEC_PERMANENT_FLAG))) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_tables[i], next) { + if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) && + (permanent || + !(entry->flags & LEC_PERMANENT_FLAG))) { lec_arp_remove(priv, entry); lec_arp_put(entry); } @@ -2008,7 +1986,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, * we have no entry in the cache. 7.1.30 */ if (!hlist_empty(&priv->lec_arp_empty_ones)) { - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_empty_ones, next) { if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) { hlist_del(&entry->next); del_timer(&entry->timer); @@ -2052,7 +2031,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); del_timer(&entry->timer); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(tmp, node, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry(tmp, node, + &priv->lec_arp_tables[i], next) { if (entry != tmp && !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) { /* Vcc to this host exists */ @@ -2097,14 +2077,13 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, int i, found_entry = 0; spin_lock_irqsave(&priv->lec_arp_lock, flags); + /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ if (ioc_data->receive == 2) { - /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ - pr_debug("LEC_ARP: Attaching mcast forward\n"); #if 0 entry = lec_arp_find(priv, bus_mac); if (!entry) { - printk("LEC_ARP: Multicast entry not found!\n"); + pr_info("LEC_ARP: Multicast entry not found!\n"); goto out; } memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); @@ -2163,7 +2142,8 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, ioc_data->atm_addr[16], ioc_data->atm_addr[17], ioc_data->atm_addr[18], ioc_data->atm_addr[19]); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry(entry, node, + &priv->lec_arp_tables[i], next) { if (memcmp (ioc_data->atm_addr, entry->atm_addr, ATM_ESA_LEN) == 0) { @@ -2247,14 +2227,16 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { - if (entry->flush_tran_id == tran_id - && entry->status == ESI_FLUSH_PENDING) { + hlist_for_each_entry(entry, node, + &priv->lec_arp_tables[i], next) { + if (entry->flush_tran_id == tran_id && + entry->status == ESI_FLUSH_PENDING) { struct sk_buff *skb; struct atm_vcc *vcc = entry->vcc; lec_arp_hold(entry); - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, + flags); while ((skb = skb_dequeue(&entry->tx_wait)) != NULL) lec_send(vcc, skb); entry->last_used = jiffies; @@ -2280,7 +2262,8 @@ lec_set_flush_tran_id(struct lec_priv *priv, spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) - hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry(entry, node, + &priv->lec_arp_tables[i], next) { if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { entry->flush_tran_id = tran_id; pr_debug("Set flush transaction id to %lx for %p\n", @@ -2300,7 +2283,8 @@ static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) struct lec_vcc_priv *vpriv; int err = 0; - if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL))) + vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL); + if (!vpriv) return -ENOMEM; vpriv->xoff = 0; vpriv->old_pop = vcc->pop; @@ -2340,18 +2324,19 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_tables[i], next) { if (vcc == entry->vcc) { lec_arp_remove(priv, entry); lec_arp_put(entry); - if (priv->mcast_vcc == vcc) { + if (priv->mcast_vcc == vcc) priv->mcast_vcc = NULL; - } } } } - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_empty_ones, next) { if (entry->vcc == vcc) { lec_arp_clear_vccs(entry); del_timer(&entry->timer); @@ -2360,7 +2345,8 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) } } - hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_no_forward, next) { if (entry->recv_vcc == vcc) { lec_arp_clear_vccs(entry); del_timer(&entry->timer); @@ -2401,14 +2387,16 @@ lec_arp_check_empties(struct lec_priv *priv, src = hdr->h_source; spin_lock_irqsave(&priv->lec_arp_lock, flags); - hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) { + hlist_for_each_entry_safe(entry, node, next, + &priv->lec_arp_empty_ones, next) { if (vcc == entry->vcc) { del_timer(&entry->timer); memcpy(entry->mac_addr, src, ETH_ALEN); entry->status = ESI_FORWARD_DIRECT; entry->last_used = jiffies; /* We might have got an entry */ - if ((tmp = lec_arp_find(priv, src))) { + tmp = lec_arp_find(priv, src); + if (tmp) { lec_arp_remove(priv, tmp); lec_arp_put(tmp); } -- GitLab From 5710044073ea734c0d7806d7fb9cd6308053704b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:09 +0000 Subject: [PATCH 1246/3892] net/atm/mpc.c: checkpatch cleanups Convert #include pr_info and pr_cont Moved labels to column 1 Move trailing statements to new lines switch/case cleanups remove unnecessary breaks after returns Remove unnecessary braces around single line statements Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/mpc.c | 445 ++++++++++++++++++++++++++++---------------------- 1 file changed, 252 insertions(+), 193 deletions(-) diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 3c45aef47b7e..55dba22e44b3 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include /* for ip_fast_csum() */ #include #include @@ -38,15 +38,17 @@ */ #if 0 -#define dprintk printk /* debug */ +#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ #else -#define dprintk(format,args...) +#define dprintk(format, args...) \ + do { if (0) printk(KERN_DEBUG format, ##args); } while (0) #endif #if 0 -#define ddprintk printk /* more debug */ +#define ddprintk printk(KERN_DEBUG format, ##args) /* more debug */ #else -#define ddprintk(format,args...) +#define ddprintk(format, args...) \ + do { if (0) printk(KERN_DEBUG format, ##args); } while (0) #endif @@ -54,15 +56,19 @@ #define MPOA_TAG_LEN 4 /* mpc_daemon -> kernel */ -static void MPOA_trigger_rcvd (struct k_message *msg, struct mpoa_client *mpc); +static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc); static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); static void mps_death(struct k_message *msg, struct mpoa_client *mpc); -static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action); -static void MPOA_cache_impos_rcvd(struct k_message *msg, struct mpoa_client *mpc); -static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); -static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc); +static void clean_up(struct k_message *msg, struct mpoa_client *mpc, + int action); +static void MPOA_cache_impos_rcvd(struct k_message *msg, + struct mpoa_client *mpc); +static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, + struct mpoa_client *mpc); +static void set_mps_mac_addr_rcvd(struct k_message *mesg, + struct mpoa_client *mpc); static const uint8_t *copy_macs(struct mpoa_client *mpc, const uint8_t *router_mac, @@ -76,10 +82,11 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb); static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb); static netdev_tx_t mpc_send_packet(struct sk_buff *skb, - struct net_device *dev); -static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev); + struct net_device *dev); +static int mpoa_event_listener(struct notifier_block *mpoa_notifier, + unsigned long event, void *dev); static void mpc_timer_refresh(void); -static void mpc_cache_check( unsigned long checking_time ); +static void mpc_cache_check(unsigned long checking_time); static struct llc_snap_hdr llc_snap_mpoa_ctrl = { 0xaa, 0xaa, 0x03, @@ -169,7 +176,7 @@ struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos) entry = kmalloc(sizeof(struct atm_mpoa_qos), GFP_KERNEL); if (entry == NULL) { - printk("mpoa: atm_mpoa_add_qos: out of memory\n"); + pr_info("mpoa: out of memory\n"); return entry; } @@ -187,10 +194,9 @@ struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip) struct atm_mpoa_qos *qos; qos = qos_head; - while( qos != NULL ){ - if(qos->ipaddr == dst_ip) { + while (qos) { + if (qos->ipaddr == dst_ip) break; - } qos = qos->next; } @@ -202,10 +208,10 @@ struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip) */ int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry) { - struct atm_mpoa_qos *curr; - if (entry == NULL) return 0; + if (entry == NULL) + return 0; if (entry == qos_head) { qos_head = qos_head->next; kfree(entry); @@ -236,9 +242,17 @@ void atm_mpoa_disp_qos(struct seq_file *m) while (qos != NULL) { seq_printf(m, "%pI4\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", - &qos->ipaddr, - qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu, - qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu); + &qos->ipaddr, + qos->qos.txtp.max_pcr, + qos->qos.txtp.pcr, + qos->qos.txtp.min_pcr, + qos->qos.txtp.max_cdv, + qos->qos.txtp.max_sdu, + qos->qos.rxtp.max_pcr, + qos->qos.rxtp.pcr, + qos->qos.rxtp.min_pcr, + qos->qos.rxtp.max_cdv, + qos->qos.rxtp.max_sdu); qos = qos->next; } } @@ -258,7 +272,7 @@ static struct mpoa_client *alloc_mpc(void) { struct mpoa_client *mpc; - mpc = kzalloc(sizeof (struct mpoa_client), GFP_KERNEL); + mpc = kzalloc(sizeof(struct mpoa_client), GFP_KERNEL); if (mpc == NULL) return NULL; rwlock_init(&mpc->ingress_lock); @@ -268,7 +282,7 @@ static struct mpoa_client *alloc_mpc(void) mpc->parameters.mpc_p1 = MPC_P1; mpc->parameters.mpc_p2 = MPC_P2; - memset(mpc->parameters.mpc_p3,0,sizeof(mpc->parameters.mpc_p3)); + memset(mpc->parameters.mpc_p3, 0, sizeof(mpc->parameters.mpc_p3)); mpc->parameters.mpc_p4 = MPC_P4; mpc->parameters.mpc_p5 = MPC_P5; mpc->parameters.mpc_p6 = MPC_P6; @@ -290,7 +304,7 @@ static void start_mpc(struct mpoa_client *mpc, struct net_device *dev) dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); if (!dev->netdev_ops) - printk("mpoa: (%s) start_mpc not starting\n", dev->name); + pr_info("(%s) not starting\n", dev->name); else { mpc->old_ops = dev->netdev_ops; mpc->new_ops = *mpc->old_ops; @@ -321,25 +335,18 @@ static const char *mpoa_device_type_string(char type) __attribute__ ((unused)); static const char *mpoa_device_type_string(char type) { - switch(type) { + switch (type) { case NON_MPOA: return "non-MPOA device"; - break; case MPS: return "MPS"; - break; case MPC: return "MPC"; - break; case MPS_AND_MPC: return "both MPS and MPC"; - break; - default: - return "unspecified (non-MPOA) device"; - break; } - return ""; /* not reached */ + return "unspecified (non-MPOA) device"; } /* @@ -368,22 +375,24 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, dprintk("total length of all TLVs %d\n", sizeoftlvs); mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */ if (mpc == NULL) { - printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name); + pr_info("(%s) no mpc\n", dev->name); return; } end_of_tlvs = tlvs + sizeoftlvs; while (end_of_tlvs - tlvs >= 5) { - type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; + type = ((tlvs[0] << 24) | (tlvs[1] << 16) | + (tlvs[2] << 8) | tlvs[3]); length = tlvs[4]; tlvs += 5; dprintk(" type 0x%x length %02x\n", type, length); if (tlvs + length > end_of_tlvs) { - printk("TLV value extends past its buffer, aborting parse\n"); + pr_info("TLV value extends past its buffer, aborting parse\n"); return; } if (type == 0) { - printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name); + pr_info("mpoa: (%s) TLV type was 0, returning\n", + dev->name); return; } @@ -393,39 +402,47 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, } mpoa_device_type = *tlvs++; number_of_mps_macs = *tlvs++; - dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type)); + dprintk("mpoa: (%s) MPOA device type '%s', ", + dev->name, mpoa_device_type_string(mpoa_device_type)); if (mpoa_device_type == MPS_AND_MPC && length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */ - printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", - dev->name); + pr_info("(%s) short MPOA Device Type TLV\n", + dev->name); continue; } - if ((mpoa_device_type == MPS || mpoa_device_type == MPC) - && length < 22 + number_of_mps_macs*ETH_ALEN) { - printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n", - dev->name); + if ((mpoa_device_type == MPS || mpoa_device_type == MPC) && + length < 22 + number_of_mps_macs*ETH_ALEN) { + pr_info("(%s) short MPOA Device Type TLV\n", dev->name); continue; } - if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) { + if (mpoa_device_type != MPS && + mpoa_device_type != MPS_AND_MPC) { dprintk("ignoring non-MPS device\n"); - if (mpoa_device_type == MPC) tlvs += 20; + if (mpoa_device_type == MPC) + tlvs += 20; continue; /* we are only interested in MPSs */ } - if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) { - printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name); + if (number_of_mps_macs == 0 && + mpoa_device_type == MPS_AND_MPC) { + pr_info("(%s) MPS_AND_MPC has zero MACs\n", dev->name); continue; /* someone should read the spec */ } dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs); - /* ok, now we can go and tell our daemon the control address of MPS */ + /* + * ok, now we can go and tell our daemon + * the control address of MPS + */ send_set_mps_ctrl_addr(tlvs, mpc); - tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type); - if (tlvs == NULL) return; + tlvs = copy_macs(mpc, mac_addr, tlvs, + number_of_mps_macs, mpoa_device_type); + if (tlvs == NULL) + return; } if (end_of_tlvs - tlvs != 0) - printk("mpoa: (%s) lane2_assoc_ind: ignoring %Zd bytes of trailing TLV carbage\n", - dev->name, end_of_tlvs - tlvs); + pr_info("(%s) ignoring %Zd bytes of trailing TLV garbage\n", + dev->name, end_of_tlvs - tlvs); return; } @@ -443,11 +460,12 @@ static const uint8_t *copy_macs(struct mpoa_client *mpc, num_macs = (mps_macs > 1) ? mps_macs : 1; if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */ - if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs); + if (mpc->number_of_mps_macs != 0) + kfree(mpc->mps_macs); mpc->number_of_mps_macs = 0; - mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL); + mpc->mps_macs = kmalloc(num_macs * ETH_ALEN, GFP_KERNEL); if (mpc->mps_macs == NULL) { - printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name); + pr_info("(%s) out of mem\n", mpc->dev->name); return NULL; } } @@ -480,24 +498,30 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) iph = (struct iphdr *)buff; ipaddr = iph->daddr; - ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr); + ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", + mpc->dev->name, ipaddr); entry = mpc->in_ops->get(ipaddr, mpc); if (entry == NULL) { entry = mpc->in_ops->add_entry(ipaddr, mpc); - if (entry != NULL) mpc->in_ops->put(entry); + if (entry != NULL) + mpc->in_ops->put(entry); return 1; } - if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){ /* threshold not exceeded or VCC not ready */ - ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name); + /* threshold not exceeded or VCC not ready */ + if (mpc->in_ops->cache_hit(entry, mpc) != OPEN) { + ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", + mpc->dev->name); mpc->in_ops->put(entry); return 1; } - ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name); + ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", + mpc->dev->name); /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ if (iph->ttl <= 1) { - ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); + ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", + mpc->dev->name, iph->ttl); mpc->in_ops->put(entry); return 1; } @@ -506,15 +530,18 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); if (entry->ctrl_info.tag != 0) { - ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); + ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", + mpc->dev->name, entry->ctrl_info.tag); tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; - skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ - skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ + skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ + skb_push(skb, sizeof(tagged_llc_snap_hdr)); + /* add LLC/SNAP header */ skb_copy_to_linear_data(skb, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); } else { - skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ - skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ + skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ + skb_push(skb, sizeof(struct llc_snap_hdr)); + /* add LLC/SNAP header + tag */ skb_copy_to_linear_data(skb, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); } @@ -539,8 +566,8 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb, int i = 0; mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ - if(mpc == NULL) { - printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name); + if (mpc == NULL) { + pr_info("(%s) no MPC found\n", dev->name); goto non_ip; } @@ -556,14 +583,15 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb, goto non_ip; while (i < mpc->number_of_mps_macs) { - if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN))) - if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ - return NETDEV_TX_OK; /* success! */ + if (!compare_ether_addr(eth->h_dest, + (mpc->mps_macs + i*ETH_ALEN))) + if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */ + return NETDEV_TX_OK; i++; } - non_ip: - return mpc->old_ops->ndo_start_xmit(skb,dev); +non_ip: + return mpc->old_ops->ndo_start_xmit(skb, dev); } static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) @@ -576,7 +604,8 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc)); if (bytes_left != 0) { - printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left); + pr_info("mpoa:Short read (missed %d bytes) from userland\n", + bytes_left); return -EFAULT; } ipaddr = ioc_data.ipaddr; @@ -589,18 +618,20 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) if (ioc_data.type == MPC_SOCKET_INGRESS) { in_entry = mpc->in_ops->get(ipaddr, mpc); - if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) { - printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n", + if (in_entry == NULL || + in_entry->entry_state < INGRESS_RESOLVED) { + pr_info("(%s) did not find RESOLVED entry from ingress cache\n", mpc->dev->name); - if (in_entry != NULL) mpc->in_ops->put(in_entry); + if (in_entry != NULL) + mpc->in_ops->put(in_entry); return -EINVAL; } - printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %pI4\n", - mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); + pr_info("(%s) attaching ingress SVC, entry = %pI4\n", + mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); in_entry->shortcut = vcc; mpc->in_ops->put(in_entry); } else { - printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name); + pr_info("(%s) attaching egress SVC\n", mpc->dev->name); } vcc->proto_data = mpc->dev; @@ -620,7 +651,7 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) mpc = find_mpc_by_lec(dev); if (mpc == NULL) { - printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name); + pr_info("(%s) close for unknown MPC\n", dev->name); return; } @@ -628,19 +659,21 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) in_entry = mpc->in_ops->get_by_vcc(vcc, mpc); if (in_entry) { dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %pI4\n", - mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); + mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); in_entry->shortcut = NULL; mpc->in_ops->put(in_entry); } eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc); if (eg_entry) { - dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name); + dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", + mpc->dev->name); eg_entry->shortcut = NULL; mpc->eg_ops->put(eg_entry); } if (in_entry == NULL && eg_entry == NULL) - dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", dev->name); + dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", + dev->name); return; } @@ -656,16 +689,19 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) ddprintk("mpoa: (%s) mpc_push:\n", dev->name); if (skb == NULL) { - dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name); + dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", + dev->name); mpc_vcc_close(vcc, dev); return; } skb->dev = dev; - if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { + if (memcmp(skb->data, &llc_snap_mpoa_ctrl, + sizeof(struct llc_snap_hdr)) == 0) { struct sock *sk = sk_atm(vcc); - dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name); + dprintk("mpoa: (%s) mpc_push: control packet arrived\n", + dev->name); /* Pass control packets to daemon */ skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); @@ -677,20 +713,23 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) mpc = find_mpc_by_lec(dev); if (mpc == NULL) { - printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name); + pr_info("(%s) unknown MPC\n", dev->name); return; } - if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ - ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name); + if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, + sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ + ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", + dev->name); - } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ - printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name); - printk(" mpc_push: non-tagged data unsupported, purging\n"); + } else if (memcmp(skb->data, &llc_snap_mpoa_data, + sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ + pr_info("(%s) Unsupported non-tagged data packet arrived. Purging\n", + dev->name); dev_kfree_skb_any(skb); return; } else { - printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name); + pr_info("(%s) garbage arrived, purging\n", dev->name); dev_kfree_skb_any(skb); return; } @@ -700,8 +739,8 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) eg = mpc->eg_ops->get_by_tag(tag, mpc); if (eg == NULL) { - printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n", - dev->name,tag); + pr_info("mpoa: (%s) Didn't find egress cache entry, tag = %u\n", + dev->name, tag); purge_egress_shortcut(vcc, NULL); dev_kfree_skb_any(skb); return; @@ -713,13 +752,15 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) */ if (eg->shortcut == NULL) { eg->shortcut = vcc; - printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name); + pr_info("(%s) egress SVC in use\n", dev->name); } - skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ - new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ + skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); + /* get rid of LLC/SNAP header */ + new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); + /* LLC/SNAP is shorter than MAC header :( */ dev_kfree_skb_any(skb); - if (new_skb == NULL){ + if (new_skb == NULL) { mpc->eg_ops->put(eg); return; } @@ -752,7 +793,7 @@ static struct atm_dev mpc_dev = { /* members not explicitly initialised will be 0 */ }; -static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) +static int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg) { struct mpoa_client *mpc; struct lec_priv *priv; @@ -772,15 +813,17 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) mpc = find_mpc_by_itfnum(arg); if (mpc == NULL) { - dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg); + dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", + arg); mpc = alloc_mpc(); if (mpc == NULL) return -ENOMEM; mpc->dev_num = arg; - mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */ + mpc->dev = find_lec_by_itfnum(arg); + /* NULL if there was no lec */ } if (mpc->mpoad_vcc) { - printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg); + pr_info("mpoad is already present for itf %d\n", arg); return -EADDRINUSE; } @@ -796,8 +839,8 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) mpc->mpoad_vcc = vcc; vcc->dev = &mpc_dev; vcc_insert_socket(sk_atm(vcc)); - set_bit(ATM_VF_META,&vcc->flags); - set_bit(ATM_VF_READY,&vcc->flags); + set_bit(ATM_VF_META, &vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); if (mpc->dev) { char empty[ATM_ESA_LEN]; @@ -807,7 +850,7 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) /* set address if mpcd e.g. gets killed and restarted. * If we do not do it now we have to wait for the next LE_ARP */ - if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 ) + if (memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0) send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); } @@ -819,7 +862,7 @@ static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc) { struct k_message mesg; - memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); + memcpy(mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); mesg.type = SET_MPS_CTRL_ADDR; memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); @@ -835,11 +878,11 @@ static void mpoad_close(struct atm_vcc *vcc) mpc = find_mpc_by_vcc(vcc); if (mpc == NULL) { - printk("mpoa: mpoad_close: did not find MPC\n"); + pr_info("did not find MPC\n"); return; } if (!mpc->mpoad_vcc) { - printk("mpoa: mpoad_close: close for non-present mpoad\n"); + pr_info("close for non-present mpoad\n"); return; } @@ -859,7 +902,7 @@ static void mpoad_close(struct atm_vcc *vcc) kfree_skb(skb); } - printk("mpoa: (%s) going down\n", + pr_info("(%s) going down\n", (mpc->dev) ? mpc->dev->name : ""); module_put(THIS_MODULE); @@ -873,15 +916,16 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) { struct mpoa_client *mpc = find_mpc_by_vcc(vcc); - struct k_message *mesg = (struct k_message*)skb->data; + struct k_message *mesg = (struct k_message *)skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); if (mpc == NULL) { - printk("mpoa: msg_from_mpoad: no mpc found\n"); + pr_info("no mpc found\n"); return 0; } - dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : ""); - switch(mesg->type) { + dprintk("mpoa: (%s) msg_from_mpoad:", + (mpc->dev) ? mpc->dev->name : ""); + switch (mesg->type) { case MPOA_RES_REPLY_RCVD: dprintk(" mpoa_res_reply_rcvd\n"); MPOA_res_reply_rcvd(mesg, mpc); @@ -942,7 +986,7 @@ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) struct sock *sk; if (mpc == NULL || !mpc->mpoad_vcc) { - printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type); + pr_info("mesg %d to a non-existent mpoad\n", mesg->type); return -ENXIO; } @@ -960,7 +1004,8 @@ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) return 0; } -static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr) +static int mpoa_event_listener(struct notifier_block *mpoa_notifier, + unsigned long event, void *dev_ptr) { struct net_device *dev; struct mpoa_client *mpc; @@ -983,10 +1028,10 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo mpc = find_mpc_by_itfnum(priv->itfnum); if (mpc == NULL) { dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n", - dev->name); + dev->name); mpc = alloc_mpc(); if (mpc == NULL) { - printk("mpoa: mpoa_event_listener: no new mpc"); + pr_info("no new mpc"); break; } } @@ -1010,9 +1055,8 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; - if (mpc->mpoad_vcc != NULL) { + if (mpc->mpoad_vcc != NULL) start_mpc(mpc, dev); - } break; case NETDEV_DOWN: /* the dev was ifconfig'ed down */ @@ -1022,9 +1066,8 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; - if (mpc->mpoad_vcc != NULL) { + if (mpc->mpoad_vcc != NULL) stop_mpc(mpc); - } break; case NETDEV_REBOOT: case NETDEV_CHANGE: @@ -1051,7 +1094,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) in_cache_entry *entry; entry = mpc->in_ops->get(dst_ip, mpc); - if(entry == NULL){ + if (entry == NULL) { entry = mpc->in_ops->add_entry(dst_ip, mpc); entry->entry_state = INGRESS_RESOLVING; msg->type = SND_MPOA_RES_RQST; @@ -1062,7 +1105,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) return; } - if(entry->entry_state == INGRESS_INVALID){ + if (entry->entry_state == INGRESS_INVALID) { entry->entry_state = INGRESS_RESOLVING; msg->type = SND_MPOA_RES_RQST; msg->content.in_info = entry->ctrl_info; @@ -1072,7 +1115,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) return; } - printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n", + pr_info("(%s) entry already in resolving state\n", (mpc->dev) ? mpc->dev->name : ""); mpc->in_ops->put(entry); return; @@ -1082,22 +1125,24 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) * Things get complicated because we have to check if there's an egress * shortcut with suitable traffic parameters we could use. */ -static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry) +static void check_qos_and_open_shortcut(struct k_message *msg, + struct mpoa_client *client, + in_cache_entry *entry) { __be32 dst_ip = msg->content.in_info.in_dst_ip; struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); - if(eg_entry && eg_entry->shortcut){ - if(eg_entry->shortcut->qos.txtp.traffic_class & - msg->qos.txtp.traffic_class & - (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)){ - if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR) - entry->shortcut = eg_entry->shortcut; - else if(eg_entry->shortcut->qos.txtp.max_pcr > 0) - entry->shortcut = eg_entry->shortcut; + if (eg_entry && eg_entry->shortcut) { + if (eg_entry->shortcut->qos.txtp.traffic_class & + msg->qos.txtp.traffic_class & + (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)) { + if (eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR) + entry->shortcut = eg_entry->shortcut; + else if (eg_entry->shortcut->qos.txtp.max_pcr > 0) + entry->shortcut = eg_entry->shortcut; } - if(entry->shortcut){ + if (entry->shortcut) { dprintk("mpoa: (%s) using egress SVC to reach %pI4\n", client->dev->name, &dst_ip); client->eg_ops->put(eg_entry); @@ -1109,12 +1154,13 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien /* No luck in the egress cache we must open an ingress SVC */ msg->type = OPEN_INGRESS_SVC; - if (qos && (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) - { + if (qos && + (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) { msg->qos = qos->qos; - printk("mpoa: (%s) trying to get a CBR shortcut\n",client->dev->name); - } - else memset(&msg->qos,0,sizeof(struct atm_qos)); + pr_info("(%s) trying to get a CBR shortcut\n", + client->dev->name); + } else + memset(&msg->qos, 0, sizeof(struct atm_qos)); msg_to_mpoad(msg, client); return; } @@ -1126,15 +1172,17 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %pI4\n", mpc->dev->name, &dst_ip); - ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry); - if(entry == NULL){ - printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name); + ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", + mpc->dev->name, entry); + if (entry == NULL) { + pr_info("(%s) ARGH, received res. reply for an entry that doesn't exist.\n", + mpc->dev->name); return; } ddprintk(" entry_state = %d ", entry->entry_state); if (entry->entry_state == INGRESS_RESOLVED) { - printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", mpc->dev->name); + pr_info("(%s) RESOLVED entry!\n", mpc->dev->name); mpc->in_ops->put(entry); return; } @@ -1145,15 +1193,16 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) entry->refresh_time = 0; ddprintk("entry->shortcut = %p\n", entry->shortcut); - if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){ + if (entry->entry_state == INGRESS_RESOLVING && + entry->shortcut != NULL) { entry->entry_state = INGRESS_RESOLVED; mpc->in_ops->put(entry); return; /* Shortcut already open... */ } if (entry->shortcut != NULL) { - printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n", - mpc->dev->name); + pr_info("(%s) entry->shortcut != NULL, impossible!\n", + mpc->dev->name); mpc->in_ops->put(entry); return; } @@ -1172,9 +1221,9 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) __be32 mask = msg->ip_mask; in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); - if(entry == NULL){ - printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ip = %pI4\n", - mpc->dev->name, &dst_ip); + if (entry == NULL) { + pr_info("(%s) purge for a non-existing entry, ip = %pI4\n", + mpc->dev->name, &dst_ip); return; } @@ -1197,7 +1246,8 @@ static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); if (entry == NULL) { - dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", mpc->dev->name); + dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", + mpc->dev->name); return; } @@ -1218,13 +1268,13 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) dprintk("mpoa: purge_egress_shortcut: entering\n"); if (vcc == NULL) { - printk("mpoa: purge_egress_shortcut: vcc == NULL\n"); + pr_info("vcc == NULL\n"); return; } skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); if (skb == NULL) { - printk("mpoa: purge_egress_shortcut: out of memory\n"); + pr_info("out of memory\n"); return; } @@ -1249,14 +1299,14 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) * Our MPS died. Tell our daemon to send NHRP data plane purge to each * of the egress shortcuts we have. */ -static void mps_death( struct k_message * msg, struct mpoa_client * mpc ) +static void mps_death(struct k_message *msg, struct mpoa_client *mpc) { eg_cache_entry *entry; dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name); - if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){ - printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name); + if (memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)) { + pr_info("(%s) wrong MPS\n", mpc->dev->name); return; } @@ -1275,20 +1325,21 @@ static void mps_death( struct k_message * msg, struct mpoa_client * mpc ) return; } -static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc) +static void MPOA_cache_impos_rcvd(struct k_message *msg, + struct mpoa_client *mpc) { uint16_t holding_time; eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc); holding_time = msg->content.eg_info.holding_time; dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n", - mpc->dev->name, entry, holding_time); - if(entry == NULL && holding_time) { + mpc->dev->name, entry, holding_time); + if (entry == NULL && holding_time) { entry = mpc->eg_ops->add_entry(msg, mpc); mpc->eg_ops->put(entry); return; } - if(holding_time){ + if (holding_time) { mpc->eg_ops->update(entry, holding_time); return; } @@ -1302,7 +1353,8 @@ static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * return; } -static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc) +static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, + struct mpoa_client *mpc) { struct lec_priv *priv; int i, retval ; @@ -1318,33 +1370,38 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *m memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); dprintk("mpoa: (%s) setting MPC ctrl ATM address to ", - (mpc->dev) ? mpc->dev->name : ""); + (mpc->dev) ? mpc->dev->name : ""); for (i = 7; i < sizeof(tlv); i++) dprintk("%02x ", tlv[i]); dprintk("\n"); if (mpc->dev) { priv = netdev_priv(mpc->dev); - retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv)); + retval = priv->lane2_ops->associate_req(mpc->dev, + mpc->dev->dev_addr, + tlv, sizeof(tlv)); if (retval == 0) - printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name); + pr_info("(%s) MPOA device type TLV association failed\n", + mpc->dev->name); retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL); if (retval < 0) - printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name); + pr_info("(%s) targetless LE_ARP request failed\n", + mpc->dev->name); } return; } -static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client) +static void set_mps_mac_addr_rcvd(struct k_message *msg, + struct mpoa_client *client) { - if(client->number_of_mps_macs) + if (client->number_of_mps_macs) kfree(client->mps_macs); client->number_of_mps_macs = 0; client->mps_macs = kmemdup(msg->MPS_ctrl, ETH_ALEN, GFP_KERNEL); if (client->mps_macs == NULL) { - printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n"); + pr_info("out of memory\n"); return; } client->number_of_mps_macs = 1; @@ -1365,11 +1422,11 @@ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action) /* FIXME: This knows too much of the cache structure */ read_lock_irq(&mpc->egress_lock); entry = mpc->eg_cache; - while (entry != NULL){ - msg->content.eg_info = entry->ctrl_info; - dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id); - msg_to_mpoad(msg, mpc); - entry = entry->next; + while (entry != NULL) { + msg->content.eg_info = entry->ctrl_info; + dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id); + msg_to_mpoad(msg, mpc); + entry = entry->next; } read_unlock_irq(&mpc->egress_lock); @@ -1388,20 +1445,22 @@ static void mpc_timer_refresh(void) return; } -static void mpc_cache_check( unsigned long checking_time ) +static void mpc_cache_check(unsigned long checking_time) { struct mpoa_client *mpc = mpcs; static unsigned long previous_resolving_check_time; static unsigned long previous_refresh_time; - while( mpc != NULL ){ + while (mpc != NULL) { mpc->in_ops->clear_count(mpc); mpc->eg_ops->clear_expired(mpc); - if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){ + if (checking_time - previous_resolving_check_time > + mpc->parameters.mpc_p4 * HZ) { mpc->in_ops->check_resolving(mpc); previous_resolving_check_time = checking_time; } - if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){ + if (checking_time - previous_refresh_time > + mpc->parameters.mpc_p5 * HZ) { mpc->in_ops->refresh(mpc); previous_refresh_time = checking_time; } @@ -1412,7 +1471,8 @@ static void mpc_cache_check( unsigned long checking_time ) return; } -static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) { int err = 0; struct atm_vcc *vcc = ATM_SD(sock); @@ -1424,21 +1484,20 @@ static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, unsigned long a return -EPERM; switch (cmd) { - case ATMMPC_CTRL: - err = atm_mpoa_mpoad_attach(vcc, (int)arg); - if (err >= 0) - sock->state = SS_CONNECTED; - break; - case ATMMPC_DATA: - err = atm_mpoa_vcc_attach(vcc, (void __user *)arg); - break; - default: - break; + case ATMMPC_CTRL: + err = atm_mpoa_mpoad_attach(vcc, (int)arg); + if (err >= 0) + sock->state = SS_CONNECTED; + break; + case ATMMPC_DATA: + err = atm_mpoa_vcc_attach(vcc, (void __user *)arg); + break; + default: + break; } return err; } - static struct atm_ioctl atm_ioctl_ops = { .owner = THIS_MODULE, .ioctl = atm_mpoa_ioctl, @@ -1451,7 +1510,7 @@ static __init int atm_mpoa_init(void) if (mpc_proc_init() != 0) pr_info("failed to initialize /proc/mpoa\n"); - printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); + pr_info("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); return 0; } -- GitLab From bee67d34b2dd495feafb1a37b5ea2d6179b74178 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:10 +0000 Subject: [PATCH 1247/3892] net/atm/mpoa_caches.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/mpoa_caches.c | 160 +++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 72 deletions(-) diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index 4504a4b339bb..de21cc66feb4 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -11,15 +11,17 @@ */ #if 0 -#define dprintk printk /* debug */ +#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ #else -#define dprintk(format,args...) +#define dprintk(format, args...) \ + do { if (0) printk(KERN_DEBUG format, ##args); } while (0) #endif #if 0 -#define ddprintk printk /* more debug */ +#define ddprintk printk(KERN_DEBUG format, ##args) /* more debug */ #else -#define ddprintk(format,args...) +#define ddprintk(format, args...) \ + do { if (0) printk(KERN_DEBUG format, ##args); } while (0) #endif static in_cache_entry *in_cache_get(__be32 dst_ip, @@ -29,8 +31,8 @@ static in_cache_entry *in_cache_get(__be32 dst_ip, read_lock_bh(&client->ingress_lock); entry = client->in_cache; - while(entry != NULL){ - if( entry->ctrl_info.in_dst_ip == dst_ip ){ + while (entry != NULL) { + if (entry->ctrl_info.in_dst_ip == dst_ip) { atomic_inc(&entry->use); read_unlock_bh(&client->ingress_lock); return entry; @@ -50,8 +52,8 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, read_lock_bh(&client->ingress_lock); entry = client->in_cache; - while(entry != NULL){ - if((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask )){ + while (entry != NULL) { + if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) { atomic_inc(&entry->use); read_unlock_bh(&client->ingress_lock); return entry; @@ -65,14 +67,14 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, } static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, - struct mpoa_client *client ) + struct mpoa_client *client) { in_cache_entry *entry; read_lock_bh(&client->ingress_lock); entry = client->in_cache; - while(entry != NULL){ - if(entry->shortcut == vcc) { + while (entry != NULL) { + if (entry->shortcut == vcc) { atomic_inc(&entry->use); read_unlock_bh(&client->ingress_lock); return entry; @@ -90,11 +92,12 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip, in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL); if (entry == NULL) { - printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); + pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); return NULL; } - dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &dst_ip); + dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", + &dst_ip); atomic_set(&entry->use, 1); dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); @@ -126,39 +129,41 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) struct k_message msg; entry->count++; - if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) + if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) return OPEN; - if(entry->entry_state == INGRESS_REFRESHING){ - if(entry->count > mpc->parameters.mpc_p1){ + if (entry->entry_state == INGRESS_REFRESHING) { + if (entry->count > mpc->parameters.mpc_p1) { msg.type = SND_MPOA_RES_RQST; msg.content.in_info = entry->ctrl_info; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) msg.qos = qos->qos; + if (qos != NULL) + msg.qos = qos->qos; msg_to_mpoad(&msg, mpc); do_gettimeofday(&(entry->reply_wait)); entry->entry_state = INGRESS_RESOLVING; } - if(entry->shortcut != NULL) + if (entry->shortcut != NULL) return OPEN; return CLOSED; } - if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) + if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) return OPEN; - if( entry->count > mpc->parameters.mpc_p1 && - entry->entry_state == INGRESS_INVALID){ + if (entry->count > mpc->parameters.mpc_p1 && + entry->entry_state == INGRESS_INVALID) { dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n", mpc->dev->name, &entry->ctrl_info.in_dst_ip); entry->entry_state = INGRESS_RESOLVING; - msg.type = SND_MPOA_RES_RQST; - memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); + msg.type = SND_MPOA_RES_RQST; + memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); msg.content.in_info = entry->ctrl_info; qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) msg.qos = qos->qos; - msg_to_mpoad( &msg, mpc); + if (qos != NULL) + msg.qos = qos->qos; + msg_to_mpoad(&msg, mpc); do_gettimeofday(&(entry->reply_wait)); } @@ -195,14 +200,15 @@ static void in_cache_remove_entry(in_cache_entry *entry, if (entry->next != NULL) entry->next->prev = entry->prev; client->in_ops->put(entry); - if(client->in_cache == NULL && client->eg_cache == NULL){ + if (client->in_cache == NULL && client->eg_cache == NULL) { msg.type = STOP_KEEP_ALIVE_SM; - msg_to_mpoad(&msg,client); + msg_to_mpoad(&msg, client); } /* Check if the egress side still uses this VCC */ if (vcc != NULL) { - eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client); + eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, + client); if (eg_entry != NULL) { client->eg_ops->put(eg_entry); return; @@ -213,7 +219,6 @@ static void in_cache_remove_entry(in_cache_entry *entry, return; } - /* Call this every MPC-p2 seconds... Not exactly correct solution, but an easy one... */ static void clear_count_and_expired(struct mpoa_client *client) @@ -225,11 +230,11 @@ static void clear_count_and_expired(struct mpoa_client *client) write_lock_bh(&client->ingress_lock); entry = client->in_cache; - while(entry != NULL){ - entry->count=0; + while (entry != NULL) { + entry->count = 0; next_entry = entry->next; - if((now.tv_sec - entry->tv.tv_sec) - > entry->ctrl_info.holding_time){ + if ((now.tv_sec - entry->tv.tv_sec) + > entry->ctrl_info.holding_time) { dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n", &entry->ctrl_info.in_dst_ip); client->in_ops->remove_entry(entry, client); @@ -250,33 +255,38 @@ static void check_resolving_entries(struct mpoa_client *client) struct timeval now; struct k_message msg; - do_gettimeofday( &now ); + do_gettimeofday(&now); read_lock_bh(&client->ingress_lock); entry = client->in_cache; - while( entry != NULL ){ - if(entry->entry_state == INGRESS_RESOLVING){ - if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){ - entry = entry->next; /* Entry in hold down */ + while (entry != NULL) { + if (entry->entry_state == INGRESS_RESOLVING) { + if ((now.tv_sec - entry->hold_down.tv_sec) < + client->parameters.mpc_p6) { + entry = entry->next; /* Entry in hold down */ continue; } - if( (now.tv_sec - entry->reply_wait.tv_sec) > - entry->retry_time ){ - entry->retry_time = MPC_C1*( entry->retry_time ); - if(entry->retry_time > client->parameters.mpc_p5){ - /* Retry time maximum exceeded, put entry in hold down. */ + if ((now.tv_sec - entry->reply_wait.tv_sec) > + entry->retry_time) { + entry->retry_time = MPC_C1 * (entry->retry_time); + /* + * Retry time maximum exceeded, + * put entry in hold down. + */ + if (entry->retry_time > client->parameters.mpc_p5) { do_gettimeofday(&(entry->hold_down)); entry->retry_time = client->parameters.mpc_p4; entry = entry->next; continue; } /* Ask daemon to send a resolution request. */ - memset(&(entry->hold_down),0,sizeof(struct timeval)); + memset(&(entry->hold_down), 0, sizeof(struct timeval)); msg.type = SND_MPOA_RES_RTRY; memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); msg.content.in_info = entry->ctrl_info; qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) msg.qos = qos->qos; + if (qos != NULL) + msg.qos = qos->qos; msg_to_mpoad(&msg, client); do_gettimeofday(&(entry->reply_wait)); } @@ -296,11 +306,12 @@ static void refresh_entries(struct mpoa_client *client) do_gettimeofday(&now); read_lock_bh(&client->ingress_lock); - while( entry != NULL ){ - if( entry->entry_state == INGRESS_RESOLVED ){ - if(!(entry->refresh_time)) - entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3; - if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){ + while (entry != NULL) { + if (entry->entry_state == INGRESS_RESOLVED) { + if (!(entry->refresh_time)) + entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3; + if ((now.tv_sec - entry->reply_wait.tv_sec) > + entry->refresh_time) { dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); entry->entry_state = INGRESS_REFRESHING; @@ -314,21 +325,22 @@ static void refresh_entries(struct mpoa_client *client) static void in_destroy_cache(struct mpoa_client *mpc) { write_lock_irq(&mpc->ingress_lock); - while(mpc->in_cache != NULL) + while (mpc->in_cache != NULL) mpc->in_ops->remove_entry(mpc->in_cache, mpc); write_unlock_irq(&mpc->ingress_lock); return; } -static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, + struct mpoa_client *mpc) { eg_cache_entry *entry; read_lock_irq(&mpc->egress_lock); entry = mpc->eg_cache; - while(entry != NULL){ - if(entry->ctrl_info.cache_id == cache_id){ + while (entry != NULL) { + if (entry->ctrl_info.cache_id == cache_id) { atomic_inc(&entry->use); read_unlock_irq(&mpc->egress_lock); return entry; @@ -348,7 +360,7 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) read_lock_irqsave(&mpc->egress_lock, flags); entry = mpc->eg_cache; - while (entry != NULL){ + while (entry != NULL) { if (entry->ctrl_info.tag == tag) { atomic_inc(&entry->use); read_unlock_irqrestore(&mpc->egress_lock, flags); @@ -362,14 +374,15 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) } /* This can be called from any context since it saves CPU flags */ -static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, + struct mpoa_client *mpc) { unsigned long flags; eg_cache_entry *entry; read_lock_irqsave(&mpc->egress_lock, flags); entry = mpc->eg_cache; - while (entry != NULL){ + while (entry != NULL) { if (entry->shortcut == vcc) { atomic_inc(&entry->use); read_unlock_irqrestore(&mpc->egress_lock, flags); @@ -382,14 +395,15 @@ static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_clie return NULL; } -static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc) +static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, + struct mpoa_client *mpc) { eg_cache_entry *entry; read_lock_irq(&mpc->egress_lock); entry = mpc->eg_cache; - while(entry != NULL){ - if(entry->latest_ip_addr == ipaddr) { + while (entry != NULL) { + if (entry->latest_ip_addr == ipaddr) { atomic_inc(&entry->use); read_unlock_irq(&mpc->egress_lock); return entry; @@ -429,9 +443,9 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, if (entry->next != NULL) entry->next->prev = entry->prev; client->eg_ops->put(entry); - if(client->in_cache == NULL && client->eg_cache == NULL){ + if (client->in_cache == NULL && client->eg_cache == NULL) { msg.type = STOP_KEEP_ALIVE_SM; - msg_to_mpoad(&msg,client); + msg_to_mpoad(&msg, client); } /* Check if the ingress side still uses this VCC */ @@ -447,12 +461,13 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, return; } -static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client) +static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, + struct mpoa_client *client) { eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL); if (entry == NULL) { - printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n"); + pr_info("out of memory\n"); return NULL; } @@ -472,7 +487,8 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli entry->ctrl_info = msg->content.eg_info; do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; - dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); + dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %u\n", + ntohl(entry->ctrl_info.cache_id)); dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n", &entry->ctrl_info.mps_ip); atomic_inc(&entry->use); @@ -483,7 +499,7 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli return entry; } -static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time) +static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time) { do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; @@ -502,13 +518,14 @@ static void clear_expired(struct mpoa_client *client) write_lock_irq(&client->egress_lock); entry = client->eg_cache; - while(entry != NULL){ + while (entry != NULL) { next_entry = entry->next; - if((now.tv_sec - entry->tv.tv_sec) - > entry->ctrl_info.holding_time){ + if ((now.tv_sec - entry->tv.tv_sec) + > entry->ctrl_info.holding_time) { msg.type = SND_EGRESS_PURGE; msg.content.eg_info = entry->ctrl_info; - dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); + dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %u.\n", + ntohl(entry->ctrl_info.cache_id)); msg_to_mpoad(&msg, client); client->eg_ops->remove_entry(entry, client); } @@ -522,7 +539,7 @@ static void clear_expired(struct mpoa_client *client) static void eg_destroy_cache(struct mpoa_client *mpc) { write_lock_irq(&mpc->egress_lock); - while(mpc->eg_cache != NULL) + while (mpc->eg_cache != NULL) mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); write_unlock_irq(&mpc->egress_lock); @@ -530,7 +547,6 @@ static void eg_destroy_cache(struct mpoa_client *mpc) } - static struct in_cache_ops ingress_ops = { in_cache_add_entry, /* add_entry */ in_cache_get, /* get */ -- GitLab From f1e100491e0e696b19f37f2b0cf728a5f2bc56e7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:11 +0000 Subject: [PATCH 1248/3892] net/atm/mpoa_proc.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/mpoa_proc.c | 64 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index 0603ab478cf5..aae4a87c22ac 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "mpc.h" @@ -21,9 +21,10 @@ */ #if 1 -#define dprintk printk /* debug */ +#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ #else -#define dprintk(format,args...) +#define dprintk(format, args...) \ + do { if (0) printk(KERN_DEBUG format, ##args); } while (0) #endif #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ @@ -52,42 +53,37 @@ static const struct file_operations mpc_file_operations = { /* * Returns the state of an ingress cache entry as a string */ -static const char *ingress_state_string(int state){ - switch(state) { +static const char *ingress_state_string(int state) +{ + switch (state) { case INGRESS_RESOLVING: return "resolving "; - break; case INGRESS_RESOLVED: return "resolved "; - break; case INGRESS_INVALID: return "invalid "; - break; case INGRESS_REFRESHING: return "refreshing "; - break; - default: - return ""; } + + return ""; } /* * Returns the state of an egress cache entry as a string */ -static const char *egress_state_string(int state){ - switch(state) { +static const char *egress_state_string(int state) +{ + switch (state) { case EGRESS_RESOLVED: return "resolved "; - break; case EGRESS_PURGE: return "purge "; - break; case EGRESS_INVALID: return "invalid "; - break; - default: - return ""; } + + return ""; } /* @@ -124,7 +120,6 @@ static void mpc_stop(struct seq_file *m, void *v) static int mpc_show(struct seq_file *m, void *v) { struct mpoa_client *mpc = v; - unsigned char *temp; int i; in_cache_entry *in_entry; eg_cache_entry *eg_entry; @@ -141,15 +136,17 @@ static int mpc_show(struct seq_file *m, void *v) do_gettimeofday(&now); for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { - temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; - sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); + sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip); seq_printf(m, "%-16s%s%-14lu%-12u", - ip_string, - ingress_state_string(in_entry->entry_state), - in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec), - in_entry->packets_fwded); + ip_string, + ingress_state_string(in_entry->entry_state), + in_entry->ctrl_info.holding_time - + (now.tv_sec-in_entry->tv.tv_sec), + in_entry->packets_fwded); if (in_entry->shortcut) - seq_printf(m, " %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci); + seq_printf(m, " %-3d %-3d", + in_entry->shortcut->vpi, + in_entry->shortcut->vci); seq_printf(m, "\n"); } @@ -157,21 +154,23 @@ static int mpc_show(struct seq_file *m, void *v) seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; - for(i = 0; i < ATM_ESA_LEN; i++) + for (i = 0; i < ATM_ESA_LEN; i++) seq_printf(m, "%02x", p[i]); seq_printf(m, "\n%-16lu%s%-14lu%-15u", (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), - (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), + (eg_entry->ctrl_info.holding_time - + (now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd); /* latest IP address */ - temp = (unsigned char *)&eg_entry->latest_ip_addr; - sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); + sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr); seq_printf(m, "%-16s", ip_string); if (eg_entry->shortcut) - seq_printf(m, " %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); + seq_printf(m, " %-3d %-3d", + eg_entry->shortcut->vpi, + eg_entry->shortcut->vci); seq_printf(m, "\n"); } seq_printf(m, "\n"); @@ -290,10 +289,9 @@ int mpc_proc_init(void) */ void mpc_proc_clean(void) { - remove_proc_entry(STAT_FILE_NAME,atm_proc_root); + remove_proc_entry(STAT_FILE_NAME, atm_proc_root); } - #endif /* CONFIG_PROC_FS */ -- GitLab From d81219db6add0a176c37d6fe4e1c050778de9d2f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:12 +0000 Subject: [PATCH 1249/3892] net/atm/pppoatm.c: checkpatch cleanups Move embedded assigns out of tests Move trailing statements to new lines Move labels to column 1 Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/pppoatm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 62db6d71dbab..400839273c67 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -176,7 +176,8 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) } ppp_input(&pvcc->chan, skb); return; - error: + +error: kfree_skb(skb); ppp_input_error(&pvcc->chan, 0); } @@ -209,7 +210,8 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) goto nospace; } kfree_skb(skb); - if ((skb = n) == NULL) + skb = n; + if (skb == NULL) return DROP_PACKET; } else if (!atm_may_send(pvcc->atmvcc, skb->truesize)) goto nospace; @@ -231,7 +233,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) ? DROP_PACKET : 1; - nospace: +nospace: /* * We don't have space to send this SKB now, but we might have * already applied SC_COMP_PROT compression, so may need to undo @@ -290,7 +292,8 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) (be.encaps == e_vc ? 0 : LLC_LEN); pvcc->wakeup_tasklet = tasklet_proto; pvcc->wakeup_tasklet.data = (unsigned long) &pvcc->chan; - if ((err = ppp_register_channel(&pvcc->chan)) != 0) { + err = ppp_register_channel(&pvcc->chan); + if (err != 0) { kfree(pvcc); return err; } -- GitLab From 07367adbe5f18b6b7a7476094181ff99cd90cb7e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:13 +0000 Subject: [PATCH 1250/3892] net/atm/proc.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/proc.c | 81 +++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/net/atm/proc.c b/net/atm/proc.c index ab8419a324b6..476779d845eb 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -24,15 +24,15 @@ #include /* for __init */ #include #include -#include +#include +#include /* for HZ */ #include -#include /* for HZ */ #include "resources.h" #include "common.h" /* atm_proc_init prototype */ #include "signaling.h" /* to get sigd - ugly too */ -static ssize_t proc_dev_atm_read(struct file *file,char __user *buf,size_t count, - loff_t *pos); +static ssize_t proc_dev_atm_read(struct file *file, char __user *buf, + size_t count, loff_t *pos); static const struct file_operations proc_atm_dev_ops = { .owner = THIS_MODULE, @@ -43,9 +43,9 @@ static void add_stats(struct seq_file *seq, const char *aal, const struct k_atm_aal_stats *stats) { seq_printf(seq, "%s ( %d %d %d %d %d )", aal, - atomic_read(&stats->tx),atomic_read(&stats->tx_err), - atomic_read(&stats->rx),atomic_read(&stats->rx_err), - atomic_read(&stats->rx_drop)); + atomic_read(&stats->tx), atomic_read(&stats->tx_err), + atomic_read(&stats->rx), atomic_read(&stats->rx_err), + atomic_read(&stats->rx_drop)); } static void atm_dev_info(struct seq_file *seq, const struct atm_dev *dev) @@ -151,8 +151,8 @@ static void *vcc_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) { - static const char *const class_name[] = - {"off","UBR","CBR","VBR","ABR"}; + static const char *const class_name[] = { + "off", "UBR", "CBR", "VBR", "ABR"}; static const char *const aal_name[] = { "---", "1", "2", "3/4", /* 0- 3 */ "???", "5", "???", "???", /* 4- 7 */ @@ -160,11 +160,12 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) "???", "0", "???", "???"}; /* 12-15 */ seq_printf(seq, "%3d %3d %5d %-3s %7d %-5s %7d %-6s", - vcc->dev->number,vcc->vpi,vcc->vci, - vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" : - aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr, - class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr, - class_name[vcc->qos.txtp.traffic_class]); + vcc->dev->number, vcc->vpi, vcc->vci, + vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" : + aal_name[vcc->qos.aal], vcc->qos.rxtp.min_pcr, + class_name[vcc->qos.rxtp.traffic_class], + vcc->qos.txtp.min_pcr, + class_name[vcc->qos.txtp.traffic_class]); if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); struct net_device *dev; @@ -195,19 +196,20 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc) seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi, vcc->vci); switch (sk->sk_family) { - case AF_ATMPVC: - seq_printf(seq, "PVC"); - break; - case AF_ATMSVC: - seq_printf(seq, "SVC"); - break; - default: - seq_printf(seq, "%3d", sk->sk_family); + case AF_ATMPVC: + seq_printf(seq, "PVC"); + break; + case AF_ATMSVC: + seq_printf(seq, "SVC"); + break; + default: + seq_printf(seq, "%3d", sk->sk_family); } - seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err, - sk_wmem_alloc_get(sk), sk->sk_sndbuf, - sk_rmem_alloc_get(sk), sk->sk_rcvbuf, - atomic_read(&sk->sk_refcnt)); + seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n", + vcc->flags, sk->sk_err, + sk_wmem_alloc_get(sk), sk->sk_sndbuf, + sk_rmem_alloc_get(sk), sk->sk_rcvbuf, + atomic_read(&sk->sk_refcnt)); } static void svc_info(struct seq_file *seq, struct atm_vcc *vcc) @@ -376,32 +378,35 @@ static ssize_t proc_dev_atm_read(struct file *file, char __user *buf, unsigned long page; int length; - if (count == 0) return 0; + if (count == 0) + return 0; page = get_zeroed_page(GFP_KERNEL); - if (!page) return -ENOMEM; + if (!page) + return -ENOMEM; dev = PDE(file->f_path.dentry->d_inode)->data; if (!dev->ops->proc_read) length = -EINVAL; else { - length = dev->ops->proc_read(dev,pos,(char *) page); - if (length > count) length = -EINVAL; + length = dev->ops->proc_read(dev, pos, (char *)page); + if (length > count) + length = -EINVAL; } if (length >= 0) { - if (copy_to_user(buf,(char *) page,length)) length = -EFAULT; + if (copy_to_user(buf, (char *)page, length)) + length = -EFAULT; (*pos)++; } free_page(page); return length; } - struct proc_dir_entry *atm_proc_root; EXPORT_SYMBOL(atm_proc_root); int atm_proc_dev_register(struct atm_dev *dev) { - int digits,num; + int digits, num; int error; /* No proc info */ @@ -410,26 +415,28 @@ int atm_proc_dev_register(struct atm_dev *dev) error = -ENOMEM; digits = 0; - for (num = dev->number; num; num /= 10) digits++; - if (!digits) digits++; + for (num = dev->number; num; num /= 10) + digits++; + if (!digits) + digits++; dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_KERNEL); if (!dev->proc_name) goto err_out; - sprintf(dev->proc_name,"%s:%d",dev->type, dev->number); + sprintf(dev->proc_name, "%s:%d", dev->type, dev->number); dev->proc_entry = proc_create_data(dev->proc_name, 0, atm_proc_root, &proc_atm_dev_ops, dev); if (!dev->proc_entry) goto err_free_name; return 0; + err_free_name: kfree(dev->proc_name); err_out: return error; } - void atm_proc_dev_deregister(struct atm_dev *dev) { if (!dev->ops->proc_read) -- GitLab From 6b6dd498f409463635c4f29a3a49585bc7e5d43e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:14 +0000 Subject: [PATCH 1251/3892] net/atm/pvc.c: checkpatch cleanups Spacing cleanups Mostly 80 column wrapped. Move trailing statements to new lines Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/pvc.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 8d74e62b0d79..437ee70c5e62 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -17,32 +17,35 @@ #include "common.h" /* common for PVCs and SVCs */ -static int pvc_shutdown(struct socket *sock,int how) +static int pvc_shutdown(struct socket *sock, int how) { return 0; } - -static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, - int sockaddr_len) +static int pvc_bind(struct socket *sock, struct sockaddr *sockaddr, + int sockaddr_len) { struct sock *sk = sock->sk; struct sockaddr_atmpvc *addr; struct atm_vcc *vcc; int error; - if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; - addr = (struct sockaddr_atmpvc *) sockaddr; - if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; + if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) + return -EINVAL; + addr = (struct sockaddr_atmpvc *)sockaddr; + if (addr->sap_family != AF_ATMPVC) + return -EAFNOSUPPORT; lock_sock(sk); vcc = ATM_SD(sock); if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { error = -EBADFD; goto out; } - if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) { - if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; - if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; + if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) { + if (vcc->vpi != ATM_VPI_UNSPEC) + addr->sap_addr.vpi = vcc->vpi; + if (vcc->vci != ATM_VCI_UNSPEC) + addr->sap_addr.vci = vcc->vci; } error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi, addr->sap_addr.vci); @@ -51,11 +54,10 @@ out: return error; } - -static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, - int sockaddr_len,int flags) +static int pvc_connect(struct socket *sock, struct sockaddr *sockaddr, + int sockaddr_len, int flags) { - return pvc_bind(sock,sockaddr,sockaddr_len); + return pvc_bind(sock, sockaddr, sockaddr_len); } static int pvc_setsockopt(struct socket *sock, int level, int optname, @@ -70,7 +72,6 @@ static int pvc_setsockopt(struct socket *sock, int level, int optname, return error; } - static int pvc_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { @@ -83,16 +84,16 @@ static int pvc_getsockopt(struct socket *sock, int level, int optname, return error; } - -static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, - int *sockaddr_len,int peer) +static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr, + int *sockaddr_len, int peer) { struct sockaddr_atmpvc *addr; struct atm_vcc *vcc = ATM_SD(sock); - if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN; + if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags)) + return -ENOTCONN; *sockaddr_len = sizeof(struct sockaddr_atmpvc); - addr = (struct sockaddr_atmpvc *) sockaddr; + addr = (struct sockaddr_atmpvc *)sockaddr; addr->sap_family = AF_ATMPVC; addr->sap_addr.itf = vcc->dev->number; addr->sap_addr.vpi = vcc->vpi; @@ -100,7 +101,6 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, return 0; } - static const struct proto_ops pvc_proto_ops = { .family = PF_ATMPVC, .owner = THIS_MODULE, @@ -137,7 +137,6 @@ static int pvc_create(struct net *net, struct socket *sock, int protocol, return vcc_create(net, sock, protocol, PF_ATMPVC); } - static const struct net_proto_family pvc_family_ops = { .family = PF_ATMPVC, .create = pvc_create, -- GitLab From fa61f0cac8b91e671eb0ba27a4972c7e72a909a6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:15 +0000 Subject: [PATCH 1252/3892] net/atm/raw.c: checkpatch cleanups Spacing cleanups Mostly 80 column wrapped. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/raw.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/net/atm/raw.c b/net/atm/raw.c index fb8a9497653c..d0c4bd047dc4 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -18,7 +18,7 @@ * SKB == NULL indicates that the link is being closed */ -static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) +static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb) { if (skb) { struct sock *sk = sk_atm(vcc); @@ -28,8 +28,7 @@ static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) } } - -static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) +static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb) { struct sock *sk = sk_atm(vcc); @@ -40,24 +39,22 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) sk->sk_write_space(sk); } - -static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb) +static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb) { /* * Note that if vpi/vci are _ANY or _UNSPEC the below will * still work */ if (!capable(CAP_NET_ADMIN) && - (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) != - ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT))) - { + (((u32 *)skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) != + ((vcc->vpi << ATM_HDR_VPI_SHIFT) | + (vcc->vci << ATM_HDR_VCI_SHIFT))) { kfree_skb(skb); return -EADDRNOTAVAIL; } - return vcc->dev->ops->send(vcc,skb); + return vcc->dev->ops->send(vcc, skb); } - int atm_init_aal0(struct atm_vcc *vcc) { vcc->push = atm_push_raw; @@ -67,7 +64,6 @@ int atm_init_aal0(struct atm_vcc *vcc) return 0; } - int atm_init_aal34(struct atm_vcc *vcc) { vcc->push = atm_push_raw; @@ -77,7 +73,6 @@ int atm_init_aal34(struct atm_vcc *vcc) return 0; } - int atm_init_aal5(struct atm_vcc *vcc) { vcc->push = atm_push_raw; @@ -86,6 +81,4 @@ int atm_init_aal5(struct atm_vcc *vcc) vcc->send = vcc->dev->ops->send; return 0; } - - EXPORT_SYMBOL(atm_init_aal5); -- GitLab From 07b54c9ad4804bdd546d3db0889b0db381c726e3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:16 +0000 Subject: [PATCH 1253/3892] net/atm/resources.c: checkpatch cleanups Spacing cleanups Mostly 80 column wrapped. Move embedded assigns out of tests Move trailing statements to new lines switch/case cleanups Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/resources.c | 390 ++++++++++++++++++++++---------------------- 1 file changed, 192 insertions(+), 198 deletions(-) diff --git a/net/atm/resources.c b/net/atm/resources.c index 0d4c0ee090db..447ed89205d8 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -71,7 +71,7 @@ struct atm_dev *atm_dev_lookup(int number) mutex_unlock(&atm_dev_mutex); return dev; } - +EXPORT_SYMBOL(atm_dev_lookup); struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, int number, unsigned long *flags) @@ -85,7 +85,8 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, } mutex_lock(&atm_dev_mutex); if (number != -1) { - if ((inuse = __atm_dev_lookup(number))) { + inuse = __atm_dev_lookup(number); + if (inuse) { atm_dev_put(inuse); mutex_unlock(&atm_dev_mutex); kfree(dev); @@ -130,7 +131,7 @@ out_fail: dev = NULL; goto out; } - +EXPORT_SYMBOL(atm_dev_register); void atm_dev_deregister(struct atm_dev *dev) { @@ -152,7 +153,7 @@ void atm_dev_deregister(struct atm_dev *dev) atm_dev_put(dev); } - +EXPORT_SYMBOL(atm_dev_deregister); static void copy_aal_stats(struct k_atm_aal_stats *from, struct atm_aal_stats *to) @@ -162,7 +163,6 @@ static void copy_aal_stats(struct k_atm_aal_stats *from, #undef __HANDLE_ITEM } - static void subtract_aal_stats(struct k_atm_aal_stats *from, struct atm_aal_stats *to) { @@ -171,8 +171,8 @@ static void subtract_aal_stats(struct k_atm_aal_stats *from, #undef __HANDLE_ITEM } - -static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, int zero) +static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, + int zero) { struct atm_dev_stats tmp; int error = 0; @@ -190,7 +190,6 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in return error ? -EFAULT : 0; } - int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) { void __user *buf; @@ -206,50 +205,49 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) #endif switch (cmd) { - case ATM_GETNAMES: - - if (compat) { + case ATM_GETNAMES: + if (compat) { #ifdef CONFIG_COMPAT - struct compat_atm_iobuf __user *ciobuf = arg; - compat_uptr_t cbuf; - iobuf_len = &ciobuf->length; - if (get_user(cbuf, &ciobuf->buffer)) - return -EFAULT; - buf = compat_ptr(cbuf); + struct compat_atm_iobuf __user *ciobuf = arg; + compat_uptr_t cbuf; + iobuf_len = &ciobuf->length; + if (get_user(cbuf, &ciobuf->buffer)) + return -EFAULT; + buf = compat_ptr(cbuf); #endif - } else { - struct atm_iobuf __user *iobuf = arg; - iobuf_len = &iobuf->length; - if (get_user(buf, &iobuf->buffer)) - return -EFAULT; - } - if (get_user(len, iobuf_len)) + } else { + struct atm_iobuf __user *iobuf = arg; + iobuf_len = &iobuf->length; + if (get_user(buf, &iobuf->buffer)) return -EFAULT; - mutex_lock(&atm_dev_mutex); - list_for_each(p, &atm_devs) - size += sizeof(int); - if (size > len) { - mutex_unlock(&atm_dev_mutex); - return -E2BIG; - } - tmp_buf = kmalloc(size, GFP_ATOMIC); - if (!tmp_buf) { - mutex_unlock(&atm_dev_mutex); - return -ENOMEM; - } - tmp_p = tmp_buf; - list_for_each(p, &atm_devs) { - dev = list_entry(p, struct atm_dev, dev_list); - *tmp_p++ = dev->number; - } + } + if (get_user(len, iobuf_len)) + return -EFAULT; + mutex_lock(&atm_dev_mutex); + list_for_each(p, &atm_devs) + size += sizeof(int); + if (size > len) { mutex_unlock(&atm_dev_mutex); - error = ((copy_to_user(buf, tmp_buf, size)) || - put_user(size, iobuf_len)) - ? -EFAULT : 0; - kfree(tmp_buf); - return error; - default: - break; + return -E2BIG; + } + tmp_buf = kmalloc(size, GFP_ATOMIC); + if (!tmp_buf) { + mutex_unlock(&atm_dev_mutex); + return -ENOMEM; + } + tmp_p = tmp_buf; + list_for_each(p, &atm_devs) { + dev = list_entry(p, struct atm_dev, dev_list); + *tmp_p++ = dev->number; + } + mutex_unlock(&atm_dev_mutex); + error = ((copy_to_user(buf, tmp_buf, size)) || + put_user(size, iobuf_len)) + ? -EFAULT : 0; + kfree(tmp_buf); + return error; + default: + break; } if (compat) { @@ -278,166 +276,167 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) if (get_user(number, &sioc->number)) return -EFAULT; } - if (!(dev = try_then_request_module(atm_dev_lookup(number), - "atm-device-%d", number))) + + dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", + number); + if (!dev) return -ENODEV; switch (cmd) { - case ATM_GETTYPE: - size = strlen(dev->type) + 1; - if (copy_to_user(buf, dev->type, size)) { - error = -EFAULT; - goto done; - } - break; - case ATM_GETESI: - size = ESI_LEN; - if (copy_to_user(buf, dev->esi, size)) { - error = -EFAULT; - goto done; - } - break; - case ATM_SETESI: - { - int i; - - for (i = 0; i < ESI_LEN; i++) - if (dev->esi[i]) { - error = -EEXIST; - goto done; - } - } - /* fall through */ - case ATM_SETESIF: - { - unsigned char esi[ESI_LEN]; - - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - if (copy_from_user(esi, buf, ESI_LEN)) { - error = -EFAULT; - goto done; - } - memcpy(dev->esi, esi, ESI_LEN); - error = ESI_LEN; - goto done; - } - case ATM_GETSTATZ: - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - /* fall through */ - case ATM_GETSTAT: - size = sizeof(struct atm_dev_stats); - error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); - if (error) - goto done; - break; - case ATM_GETCIRANGE: - size = sizeof(struct atm_cirange); - if (copy_to_user(buf, &dev->ci_range, size)) { - error = -EFAULT; - goto done; - } - break; - case ATM_GETLINKRATE: - size = sizeof(int); - if (copy_to_user(buf, &dev->link_rate, size)) { - error = -EFAULT; - goto done; - } - break; - case ATM_RSTADDR: - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - atm_reset_addr(dev, ATM_ADDR_LOCAL); - break; - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_ADDLECSADDR: - case ATM_DELLECSADDR: - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - { - struct sockaddr_atmsvc addr; - - if (copy_from_user(&addr, buf, sizeof(addr))) { - error = -EFAULT; - goto done; - } - if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) - error = atm_add_addr(dev, &addr, - (cmd == ATM_ADDADDR ? - ATM_ADDR_LOCAL : ATM_ADDR_LECS)); - else - error = atm_del_addr(dev, &addr, - (cmd == ATM_DELADDR ? - ATM_ADDR_LOCAL : ATM_ADDR_LECS)); + case ATM_GETTYPE: + size = strlen(dev->type) + 1; + if (copy_to_user(buf, dev->type, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETESI: + size = ESI_LEN; + if (copy_to_user(buf, dev->esi, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_SETESI: + { + int i; + + for (i = 0; i < ESI_LEN; i++) + if (dev->esi[i]) { + error = -EEXIST; goto done; } - case ATM_GETADDR: - case ATM_GETLECSADDR: - error = atm_get_addr(dev, buf, len, - (cmd == ATM_GETADDR ? + } + /* fall through */ + case ATM_SETESIF: + { + unsigned char esi[ESI_LEN]; + + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + if (copy_from_user(esi, buf, ESI_LEN)) { + error = -EFAULT; + goto done; + } + memcpy(dev->esi, esi, ESI_LEN); + error = ESI_LEN; + goto done; + } + case ATM_GETSTATZ: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + case ATM_GETSTAT: + size = sizeof(struct atm_dev_stats); + error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); + if (error) + goto done; + break; + case ATM_GETCIRANGE: + size = sizeof(struct atm_cirange); + if (copy_to_user(buf, &dev->ci_range, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETLINKRATE: + size = sizeof(int); + if (copy_to_user(buf, &dev->link_rate, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_RSTADDR: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + atm_reset_addr(dev, ATM_ADDR_LOCAL); + break; + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_ADDLECSADDR: + case ATM_DELLECSADDR: + { + struct sockaddr_atmsvc addr; + + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + + if (copy_from_user(&addr, buf, sizeof(addr))) { + error = -EFAULT; + goto done; + } + if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) + error = atm_add_addr(dev, &addr, + (cmd == ATM_ADDADDR ? ATM_ADDR_LOCAL : ATM_ADDR_LECS)); - if (error < 0) - goto done; - size = error; - /* may return 0, but later on size == 0 means "don't - write the length" */ - error = put_user(size, sioc_len) - ? -EFAULT : 0; + else + error = atm_del_addr(dev, &addr, + (cmd == ATM_DELADDR ? + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); + goto done; + } + case ATM_GETADDR: + case ATM_GETLECSADDR: + error = atm_get_addr(dev, buf, len, + (cmd == ATM_GETADDR ? + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); + if (error < 0) + goto done; + size = error; + /* may return 0, but later on size == 0 means "don't + write the length" */ + error = put_user(size, sioc_len) ? -EFAULT : 0; + goto done; + case ATM_SETLOOP: + if (__ATM_LM_XTRMT((int) (unsigned long) buf) && + __ATM_LM_XTLOC((int) (unsigned long) buf) > + __ATM_LM_XTRMT((int) (unsigned long) buf)) { + error = -EINVAL; goto done; - case ATM_SETLOOP: - if (__ATM_LM_XTRMT((int) (unsigned long) buf) && - __ATM_LM_XTLOC((int) (unsigned long) buf) > - __ATM_LM_XTRMT((int) (unsigned long) buf)) { + } + /* fall through */ + case ATM_SETCIRANGE: + case SONET_GETSTATZ: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + default: + if (compat) { +#ifdef CONFIG_COMPAT + if (!dev->ops->compat_ioctl) { error = -EINVAL; goto done; } - /* fall through */ - case ATM_SETCIRANGE: - case SONET_GETSTATZ: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - if (!capable(CAP_NET_ADMIN)) { - error = -EPERM; - goto done; - } - /* fall through */ - default: - if (compat) { -#ifdef CONFIG_COMPAT - if (!dev->ops->compat_ioctl) { - error = -EINVAL; - goto done; - } - size = dev->ops->compat_ioctl(dev, cmd, buf); + size = dev->ops->compat_ioctl(dev, cmd, buf); #endif - } else { - if (!dev->ops->ioctl) { - error = -EINVAL; - goto done; - } - size = dev->ops->ioctl(dev, cmd, buf); - } - if (size < 0) { - error = (size == -ENOIOCTLCMD ? -EINVAL : size); + } else { + if (!dev->ops->ioctl) { + error = -EINVAL; goto done; } + size = dev->ops->ioctl(dev, cmd, buf); + } + if (size < 0) { + error = (size == -ENOIOCTLCMD ? -EINVAL : size); + goto done; + } } if (size) - error = put_user(size, sioc_len) - ? -EFAULT : 0; + error = put_user(size, sioc_len) ? -EFAULT : 0; else error = 0; done: @@ -445,7 +444,7 @@ done: return error; } -static __inline__ void *dev_get_idx(loff_t left) +static inline void *dev_get_idx(loff_t left) { struct list_head *p; @@ -474,8 +473,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) ? atm_devs.next : ((struct list_head *)v)->next; return (v == &atm_devs) ? NULL : v; } - - -EXPORT_SYMBOL(atm_dev_register); -EXPORT_SYMBOL(atm_dev_deregister); -EXPORT_SYMBOL(atm_dev_lookup); -- GitLab From 0ec96e656fcd4a8ea8cb0e92f90ab4bb6f79cada Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:17 +0000 Subject: [PATCH 1254/3892] net/atm/signaling.c: checkpatch cleanups Mostly 80 column wrapped. Move embedded assigns out of tests Move trailing statements to new lines switch/case cleanups Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/signaling.c | 202 ++++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 28df4edf9ca4..ad1d28ae512b 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -18,7 +18,6 @@ #include "resources.h" #include "signaling.h" - #undef WAIT_FOR_DEMON /* #define this if system calls on SVC sockets should block until the demon runs. Danger: may cause nasty hangs if the demon @@ -29,20 +28,19 @@ struct atm_vcc *sigd = NULL; static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep); #endif - static void sigd_put_skb(struct sk_buff *skb) { #ifdef WAIT_FOR_DEMON - DECLARE_WAITQUEUE(wait,current); + DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&sigd_sleep,&wait); + add_wait_queue(&sigd_sleep, &wait); while (!sigd) { set_current_state(TASK_UNINTERRUPTIBLE); pr_debug("atmsvc: waiting for signaling daemon...\n"); schedule(); } current->state = TASK_RUNNING; - remove_wait_queue(&sigd_sleep,&wait); + remove_wait_queue(&sigd_sleep, &wait); #else if (!sigd) { pr_debug("atmsvc: no signaling daemon\n"); @@ -50,39 +48,39 @@ static void sigd_put_skb(struct sk_buff *skb) return; } #endif - atm_force_charge(sigd,skb->truesize); - skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb); + atm_force_charge(sigd, skb->truesize); + skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len); } - -static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg) +static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg) { struct sk_buff *skb; - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - !test_bit(ATM_VF_READY,&vcc->flags)) + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || + !test_bit(ATM_VF_READY, &vcc->flags)) return; msg->type = as_error; - if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP; + if (!vcc->dev->ops->change_qos) + msg->reply = -EOPNOTSUPP; else { /* should lock VCC */ - msg->reply = vcc->dev->ops->change_qos(vcc,&msg->qos, - msg->reply); - if (!msg->reply) msg->type = as_okay; + msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos, + msg->reply); + if (!msg->reply) + msg->type = as_okay; } /* * Should probably just turn around the old skb. But the, the buffer * space accounting needs to follow the change too. Maybe later. */ - while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) + while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) schedule(); - *(struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)) = *msg; + *(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg; sigd_put_skb(skb); } - -static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) +static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) { struct atmsvc_msg *msg; struct atm_vcc *session_vcc; @@ -95,63 +93,64 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) sk = sk_atm(vcc); switch (msg->type) { - case as_okay: - sk->sk_err = -msg->reply; - clear_bit(ATM_VF_WAITING, &vcc->flags); - if (!*vcc->local.sas_addr.prv && - !*vcc->local.sas_addr.pub) { - vcc->local.sas_family = AF_ATMSVC; - memcpy(vcc->local.sas_addr.prv, - msg->local.sas_addr.prv,ATM_ESA_LEN); - memcpy(vcc->local.sas_addr.pub, - msg->local.sas_addr.pub,ATM_E164_LEN+1); - } - session_vcc = vcc->session ? vcc->session : vcc; - if (session_vcc->vpi || session_vcc->vci) break; - session_vcc->itf = msg->pvc.sap_addr.itf; - session_vcc->vpi = msg->pvc.sap_addr.vpi; - session_vcc->vci = msg->pvc.sap_addr.vci; - if (session_vcc->vpi || session_vcc->vci) - session_vcc->qos = msg->qos; - break; - case as_error: - clear_bit(ATM_VF_REGIS,&vcc->flags); - clear_bit(ATM_VF_READY,&vcc->flags); - sk->sk_err = -msg->reply; - clear_bit(ATM_VF_WAITING, &vcc->flags); + case as_okay: + sk->sk_err = -msg->reply; + clear_bit(ATM_VF_WAITING, &vcc->flags); + if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) { + vcc->local.sas_family = AF_ATMSVC; + memcpy(vcc->local.sas_addr.prv, + msg->local.sas_addr.prv, ATM_ESA_LEN); + memcpy(vcc->local.sas_addr.pub, + msg->local.sas_addr.pub, ATM_E164_LEN + 1); + } + session_vcc = vcc->session ? vcc->session : vcc; + if (session_vcc->vpi || session_vcc->vci) break; - case as_indicate: - vcc = *(struct atm_vcc **) &msg->listen_vcc; - sk = sk_atm(vcc); - pr_debug("as_indicate!!!\n"); - lock_sock(sk); - if (sk_acceptq_is_full(sk)) { - sigd_enq(NULL,as_reject,vcc,NULL,NULL); - dev_kfree_skb(skb); - goto as_indicate_complete; - } - sk->sk_ack_backlog++; - skb_queue_tail(&sk->sk_receive_queue, skb); - pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep); - sk->sk_state_change(sk); + session_vcc->itf = msg->pvc.sap_addr.itf; + session_vcc->vpi = msg->pvc.sap_addr.vpi; + session_vcc->vci = msg->pvc.sap_addr.vci; + if (session_vcc->vpi || session_vcc->vci) + session_vcc->qos = msg->qos; + break; + case as_error: + clear_bit(ATM_VF_REGIS, &vcc->flags); + clear_bit(ATM_VF_READY, &vcc->flags); + sk->sk_err = -msg->reply; + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: + vcc = *(struct atm_vcc **)&msg->listen_vcc; + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); + if (sk_acceptq_is_full(sk)) { + sigd_enq(NULL, as_reject, vcc, NULL, NULL); + dev_kfree_skb(skb); + goto as_indicate_complete; + } + sk->sk_ack_backlog++; + skb_queue_tail(&sk->sk_receive_queue, skb); + pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep); + sk->sk_state_change(sk); as_indicate_complete: - release_sock(sk); - return 0; - case as_close: - set_bit(ATM_VF_RELEASED,&vcc->flags); - vcc_release_async(vcc, msg->reply); - goto out; - case as_modify: - modify_qos(vcc,msg); - break; - case as_addparty: - case as_dropparty: - sk->sk_err_soft = msg->reply; /* < 0 failure, otherwise ep_ref */ - clear_bit(ATM_VF_WAITING, &vcc->flags); - break; - default: - pr_alert("bad message type %d\n", (int)msg->type); - return -EINVAL; + release_sock(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); + vcc_release_async(vcc, msg->reply); + goto out; + case as_modify: + modify_qos(vcc, msg); + break; + case as_addparty: + case as_dropparty: + sk->sk_err_soft = msg->reply; + /* < 0 failure, otherwise ep_ref */ + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); + return -EINVAL; } sk->sk_state_change(sk); out: @@ -159,48 +158,52 @@ out: return 0; } - -void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type, - struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, - const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply) +void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type, + struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, + const struct sockaddr_atmsvc *svc, const struct atm_qos *qos, + int reply) { struct sk_buff *skb; struct atmsvc_msg *msg; static unsigned session = 0; pr_debug("%d (0x%p)\n", (int)type, vcc); - while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) + while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) schedule(); - msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)); - memset(msg,0,sizeof(*msg)); + msg = (struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)); + memset(msg, 0, sizeof(*msg)); msg->type = type; *(struct atm_vcc **) &msg->vcc = vcc; *(struct atm_vcc **) &msg->listen_vcc = listen_vcc; msg->reply = reply; - if (qos) msg->qos = *qos; - if (vcc) msg->sap = vcc->sap; - if (svc) msg->svc = *svc; - if (vcc) msg->local = vcc->local; - if (pvc) msg->pvc = *pvc; + if (qos) + msg->qos = *qos; + if (vcc) + msg->sap = vcc->sap; + if (svc) + msg->svc = *svc; + if (vcc) + msg->local = vcc->local; + if (pvc) + msg->pvc = *pvc; if (vcc) { if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags)) msg->session = ++session; /* every new pmp connect gets the next session number */ } sigd_put_skb(skb); - if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags); + if (vcc) + set_bit(ATM_VF_REGIS, &vcc->flags); } - -void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, - struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, - const struct sockaddr_atmsvc *svc) +void sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type, + struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, + const struct sockaddr_atmsvc *svc) { - sigd_enq2(vcc,type,listen_vcc,pvc,svc,vcc ? &vcc->qos : NULL,0); + sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0); /* other ISP applications may use "reply" */ } - static void purge_vcc(struct atm_vcc *vcc) { if (sk_atm(vcc)->sk_family == PF_ATMSVC && @@ -211,7 +214,6 @@ static void purge_vcc(struct atm_vcc *vcc) } } - static void sigd_close(struct atm_vcc *vcc) { struct hlist_node *node; @@ -225,7 +227,7 @@ static void sigd_close(struct atm_vcc *vcc) skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); read_lock(&vcc_sklist_lock); - for(i = 0; i < VCC_HTABLE_SIZE; ++i) { + for (i = 0; i < VCC_HTABLE_SIZE; ++i) { struct hlist_head *head = &vcc_hash[i]; sk_for_each(s, node, head) { @@ -237,13 +239,11 @@ static void sigd_close(struct atm_vcc *vcc) read_unlock(&vcc_sklist_lock); } - static struct atmdev_ops sigd_dev_ops = { .close = sigd_close, .send = sigd_send }; - static struct atm_dev sigd_dev = { .ops = &sigd_dev_ops, .type = "sig", @@ -251,16 +251,16 @@ static struct atm_dev sigd_dev = { .lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock) }; - int sigd_attach(struct atm_vcc *vcc) { - if (sigd) return -EADDRINUSE; + if (sigd) + return -EADDRINUSE; pr_debug("\n"); sigd = vcc; vcc->dev = &sigd_dev; vcc_insert_socket(sk_atm(vcc)); - set_bit(ATM_VF_META,&vcc->flags); - set_bit(ATM_VF_READY,&vcc->flags); + set_bit(ATM_VF_META, &vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); #ifdef WAIT_FOR_DEMON wake_up(&sigd_sleep); #endif -- GitLab From b7d9371befd6fa3eb0ad9d574860095642bf70ed Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:18 +0000 Subject: [PATCH 1255/3892] net/atm/svc.c: checkpatch cleanups Convert #include Signed-off-by: David S. Miller --- net/atm/svc.c | 249 +++++++++++++++++++++++++------------------------- 1 file changed, 125 insertions(+), 124 deletions(-) diff --git a/net/atm/svc.c b/net/atm/svc.c index 251ddbc42e4b..3ba9a45a51ac 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -19,14 +19,15 @@ #include #include #include /* for sock_no_* */ -#include +#include #include "resources.h" #include "common.h" /* common for PVCs and SVCs */ #include "signaling.h" #include "addr.h" -static int svc_create(struct net *net, struct socket *sock, int protocol, int kern); +static int svc_create(struct net *net, struct socket *sock, int protocol, + int kern); /* * Note: since all this is still nicely synchronized with the signaling demon, @@ -35,25 +36,25 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, int ke */ -static int svc_shutdown(struct socket *sock,int how) +static int svc_shutdown(struct socket *sock, int how) { return 0; } - static void svc_disconnect(struct atm_vcc *vcc) { DEFINE_WAIT(wait); struct sk_buff *skb; struct sock *sk = sk_atm(vcc); - pr_debug("%p\n",vcc); - if (test_bit(ATM_VF_REGIS,&vcc->flags)) { + pr_debug("%p\n", vcc); + if (test_bit(ATM_VF_REGIS, &vcc->flags)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); - sigd_enq(vcc,as_close,NULL,NULL,NULL); - while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { + sigd_enq(vcc, as_close, NULL, NULL, NULL); + while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) { schedule(); - prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, + TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); } @@ -62,35 +63,35 @@ static void svc_disconnect(struct atm_vcc *vcc) while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); pr_debug("LISTEN REL\n"); - sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); + sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0); dev_kfree_skb(skb); } clear_bit(ATM_VF_REGIS, &vcc->flags); /* ... may retry later */ } - static int svc_release(struct socket *sock) { struct sock *sk = sock->sk; struct atm_vcc *vcc; - if (sk) { + if (sk) { vcc = ATM_SD(sock); pr_debug("%p\n", vcc); clear_bit(ATM_VF_READY, &vcc->flags); - /* VCC pointer is used as a reference, so we must not free it - (thereby subjecting it to re-use) before all pending connections - are closed */ + /* + * VCC pointer is used as a reference, + * so we must not free it (thereby subjecting it to re-use) + * before all pending connections are closed + */ svc_disconnect(vcc); vcc_release(sock); } return 0; } - -static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, - int sockaddr_len) +static int svc_bind(struct socket *sock, struct sockaddr *sockaddr, + int sockaddr_len) { DEFINE_WAIT(wait); struct sock *sk = sock->sk; @@ -115,38 +116,37 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, error = -EAFNOSUPPORT; goto out; } - clear_bit(ATM_VF_BOUND,&vcc->flags); + clear_bit(ATM_VF_BOUND, &vcc->flags); /* failing rebind will kill old binding */ /* @@@ check memory (de)allocation on rebind */ - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) { + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { error = -EBADFD; goto out; } vcc->local = *addr; set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); - sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); + sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); - clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */ + clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */ if (!sigd) { error = -EUNATCH; goto out; } if (!sk->sk_err) - set_bit(ATM_VF_BOUND,&vcc->flags); + set_bit(ATM_VF_BOUND, &vcc->flags); error = -sk->sk_err; out: release_sock(sk); return error; } - -static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, - int sockaddr_len,int flags) +static int svc_connect(struct socket *sock, struct sockaddr *sockaddr, + int sockaddr_len, int flags) { DEFINE_WAIT(wait); struct sock *sk = sock->sk; @@ -154,7 +154,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, struct atm_vcc *vcc = ATM_SD(sock); int error; - pr_debug("%p\n",vcc); + pr_debug("%p\n", vcc); lock_sock(sk); if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { error = -EINVAL; @@ -202,7 +202,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, vcc->remote = *addr; set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); + sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote); if (flags & O_NONBLOCK) { finish_wait(sk->sk_sleep, &wait); sock->state = SS_CONNECTING; @@ -213,7 +213,8 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); if (!signal_pending(current)) { - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); continue; } pr_debug("*ABORT*\n"); @@ -229,20 +230,22 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, * Kernel <--okay---- Demon * Kernel <--close--- Demon */ - sigd_enq(vcc,as_close,NULL,NULL,NULL); + sigd_enq(vcc, as_close, NULL, NULL, NULL); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); schedule(); } if (!sk->sk_err) - while (!test_bit(ATM_VF_RELEASED,&vcc->flags) - && sigd) { - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && + sigd) { + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); schedule(); } - clear_bit(ATM_VF_REGIS,&vcc->flags); - clear_bit(ATM_VF_RELEASED,&vcc->flags); - clear_bit(ATM_VF_CLOSE,&vcc->flags); + clear_bit(ATM_VF_REGIS, &vcc->flags); + clear_bit(ATM_VF_RELEASED, &vcc->flags); + clear_bit(ATM_VF_CLOSE, &vcc->flags); /* we're gone now but may connect later */ error = -EINTR; break; @@ -270,17 +273,17 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, /* * #endif */ - if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci))) + error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci); + if (!error) sock->state = SS_CONNECTED; else - (void) svc_disconnect(vcc); + (void)svc_disconnect(vcc); out: release_sock(sk); return error; } - -static int svc_listen(struct socket *sock,int backlog) +static int svc_listen(struct socket *sock, int backlog) { DEFINE_WAIT(wait); struct sock *sk = sock->sk; @@ -290,17 +293,17 @@ static int svc_listen(struct socket *sock,int backlog) pr_debug("%p\n", vcc); lock_sock(sk); /* let server handle listen on unbound sockets */ - if (test_bit(ATM_VF_SESSION,&vcc->flags)) { + if (test_bit(ATM_VF_SESSION, &vcc->flags)) { error = -EINVAL; goto out; } if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { error = -EADDRINUSE; goto out; - } + } set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); - sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); + sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); @@ -310,7 +313,7 @@ static int svc_listen(struct socket *sock,int backlog) error = -EUNATCH; goto out; } - set_bit(ATM_VF_LISTEN,&vcc->flags); + set_bit(ATM_VF_LISTEN, &vcc->flags); vcc_insert_socket(sk); sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; error = -sk->sk_err; @@ -319,8 +322,7 @@ out: return error; } - -static int svc_accept(struct socket *sock,struct socket *newsock,int flags) +static int svc_accept(struct socket *sock, struct socket *newsock, int flags) { struct sock *sk = sock->sk; struct sk_buff *skb; @@ -344,8 +346,9 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); while (!(skb = skb_dequeue(&sk->sk_receive_queue)) && sigd) { - if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; - if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { + if (test_bit(ATM_VF_RELEASED, &old_vcc->flags)) + break; + if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) { error = -sk->sk_err; break; } @@ -360,7 +363,8 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) error = -ERESTARTSYS; break; } - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); if (error) @@ -369,31 +373,34 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) error = -EUNATCH; goto out; } - msg = (struct atmsvc_msg *) skb->data; + msg = (struct atmsvc_msg *)skb->data; new_vcc->qos = msg->qos; - set_bit(ATM_VF_HASQOS,&new_vcc->flags); + set_bit(ATM_VF_HASQOS, &new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; error = vcc_connect(newsock, msg->pvc.sap_addr.itf, - msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci); + msg->pvc.sap_addr.vpi, + msg->pvc.sap_addr.vci); dev_kfree_skb(skb); sk->sk_ack_backlog--; if (error) { - sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, - &old_vcc->qos,error); + sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL, + &old_vcc->qos, error); error = error == -EAGAIN ? -EBUSY : error; goto out; } /* wait should be short, so we ignore the non-blocking flag */ set_bit(ATM_VF_WAITING, &new_vcc->flags); - prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); - sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); + prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, + TASK_UNINTERRUPTIBLE); + sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL); while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) { release_sock(sk); schedule(); lock_sock(sk); - prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, + TASK_UNINTERRUPTIBLE); } finish_wait(sk_atm(new_vcc)->sk_sleep, &wait); if (!sigd) { @@ -413,39 +420,37 @@ out: return error; } - -static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, - int *sockaddr_len,int peer) +static int svc_getname(struct socket *sock, struct sockaddr *sockaddr, + int *sockaddr_len, int peer) { struct sockaddr_atmsvc *addr; *sockaddr_len = sizeof(struct sockaddr_atmsvc); addr = (struct sockaddr_atmsvc *) sockaddr; - memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, - sizeof(struct sockaddr_atmsvc)); + memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, + sizeof(struct sockaddr_atmsvc)); return 0; } - -int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) +int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) { struct sock *sk = sk_atm(vcc); DEFINE_WAIT(wait); set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); - sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); + sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0); while (test_bit(ATM_VF_WAITING, &vcc->flags) && !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); - if (!sigd) return -EUNATCH; + if (!sigd) + return -EUNATCH; return -sk->sk_err; } - static int svc_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { @@ -455,37 +460,35 @@ static int svc_setsockopt(struct socket *sock, int level, int optname, lock_sock(sk); switch (optname) { - case SO_ATMSAP: - if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) { - error = -EINVAL; - goto out; - } - if (copy_from_user(&vcc->sap, optval, optlen)) { - error = -EFAULT; - goto out; - } - set_bit(ATM_VF_HASSAP, &vcc->flags); - break; - case SO_MULTIPOINT: - if (level != SOL_ATM || optlen != sizeof(int)) { - error = -EINVAL; - goto out; - } - if (get_user(value, (int __user *) optval)) { - error = -EFAULT; - goto out; - } - if (value == 1) { - set_bit(ATM_VF_SESSION, &vcc->flags); - } else if (value == 0) { - clear_bit(ATM_VF_SESSION, &vcc->flags); - } else { - error = -EINVAL; - } - break; - default: - error = vcc_setsockopt(sock, level, optname, - optval, optlen); + case SO_ATMSAP: + if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) { + error = -EINVAL; + goto out; + } + if (copy_from_user(&vcc->sap, optval, optlen)) { + error = -EFAULT; + goto out; + } + set_bit(ATM_VF_HASSAP, &vcc->flags); + break; + case SO_MULTIPOINT: + if (level != SOL_ATM || optlen != sizeof(int)) { + error = -EINVAL; + goto out; + } + if (get_user(value, (int __user *)optval)) { + error = -EFAULT; + goto out; + } + if (value == 1) + set_bit(ATM_VF_SESSION, &vcc->flags); + else if (value == 0) + clear_bit(ATM_VF_SESSION, &vcc->flags); + else + error = -EINVAL; + break; + default: + error = vcc_setsockopt(sock, level, optname, optval, optlen); } out: @@ -493,9 +496,8 @@ out: return error; } - -static int svc_getsockopt(struct socket *sock,int level,int optname, - char __user *optval,int __user *optlen) +static int svc_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; int error = 0, len; @@ -522,7 +524,6 @@ out: return error; } - static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, int sockaddr_len, int flags) { @@ -553,7 +554,6 @@ out: return error; } - static int svc_dropparty(struct socket *sock, int ep_ref) { DEFINE_WAIT(wait); @@ -580,7 +580,6 @@ out: return error; } - static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { int error, ep_ref; @@ -588,29 +587,31 @@ static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct atm_vcc *vcc = ATM_SD(sock); switch (cmd) { - case ATM_ADDPARTY: - if (!test_bit(ATM_VF_SESSION, &vcc->flags)) - return -EINVAL; - if (copy_from_user(&sa, (void __user *) arg, sizeof(sa))) - return -EFAULT; - error = svc_addparty(sock, (struct sockaddr *) &sa, sizeof(sa), 0); - break; - case ATM_DROPPARTY: - if (!test_bit(ATM_VF_SESSION, &vcc->flags)) - return -EINVAL; - if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int))) - return -EFAULT; - error = svc_dropparty(sock, ep_ref); - break; - default: - error = vcc_ioctl(sock, cmd, arg); + case ATM_ADDPARTY: + if (!test_bit(ATM_VF_SESSION, &vcc->flags)) + return -EINVAL; + if (copy_from_user(&sa, (void __user *) arg, sizeof(sa))) + return -EFAULT; + error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa), + 0); + break; + case ATM_DROPPARTY: + if (!test_bit(ATM_VF_SESSION, &vcc->flags)) + return -EINVAL; + if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int))) + return -EFAULT; + error = svc_dropparty(sock, ep_ref); + break; + default: + error = vcc_ioctl(sock, cmd, arg); } return error; } #ifdef CONFIG_COMPAT -static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) { /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. But actually it takes a struct sockaddr_atmsvc, which doesn't need @@ -661,13 +662,13 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, sock->ops = &svc_proto_ops; error = vcc_create(net, sock, protocol, AF_ATMSVC); - if (error) return error; + if (error) + return error; ATM_SD(sock)->local.sas_family = AF_ATMSVC; ATM_SD(sock)->remote.sas_family = AF_ATMSVC; return 0; } - static const struct net_proto_family svc_family_ops = { .family = PF_ATMSVC, .create = svc_create, -- GitLab From b4c84ec0fd9ec2297b796443051554d062007ba3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:19 +0000 Subject: [PATCH 1256/3892] net/atm/lec.c: Add __lec_arp_check_expire and other cleanups Reduce indentation in lec_arp_check_expire Indent a case label Remove != NULL logical tests from while ((skb = foo())) assign and tests Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/lec.c | 153 ++++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 73 deletions(-) diff --git a/net/atm/lec.c b/net/atm/lec.c index aefd278d6af6..5da5753157f9 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -285,7 +285,6 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb, /* Make sure we have room for lec_id */ if (skb_headroom(skb) < 2) { - pr_debug("reallocating skb\n"); skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); kfree_skb(skb); @@ -508,34 +507,31 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) break; case l_should_bridge: #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - { - pr_debug("%s: bridge zeppelin asks about %pM\n", - dev->name, mesg->content.proxy.mac_addr); + { + pr_debug("%s: bridge zeppelin asks about %pM\n", + dev->name, mesg->content.proxy.mac_addr); - if (br_fdb_test_addr_hook == NULL) - break; + if (br_fdb_test_addr_hook == NULL) + break; - if (br_fdb_test_addr_hook(dev, - mesg->content.proxy.mac_addr)) { - /* hit from bridge table, send LE_ARP_RESPONSE */ - struct sk_buff *skb2; - struct sock *sk; - - pr_debug("%s: entry found, responding to zeppelin\n", - dev->name); - skb2 = alloc_skb(sizeof(struct atmlec_msg), - GFP_ATOMIC); - if (skb2 == NULL) - break; - skb2->len = sizeof(struct atmlec_msg); - skb_copy_to_linear_data(skb2, mesg, - sizeof(*mesg)); - atm_force_charge(priv->lecd, skb2->truesize); - sk = sk_atm(priv->lecd); - skb_queue_tail(&sk->sk_receive_queue, skb2); - sk->sk_data_ready(sk, skb2->len); - } + if (br_fdb_test_addr_hook(dev, mesg->content.proxy.mac_addr)) { + /* hit from bridge table, send LE_ARP_RESPONSE */ + struct sk_buff *skb2; + struct sock *sk; + + pr_debug("%s: entry found, responding to zeppelin\n", + dev->name); + skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); + if (skb2 == NULL) + break; + skb2->len = sizeof(struct atmlec_msg); + skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); + atm_force_charge(priv->lecd, skb2->truesize); + sk = sk_atm(priv->lecd); + skb_queue_tail(&sk->sk_receive_queue, skb2); + sk->sk_data_ready(sk, skb2->len); } + } #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; default: @@ -561,7 +557,7 @@ static void lec_atm_close(struct atm_vcc *vcc) if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) pr_info("%s closing with messages pending\n", dev->name); - while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) { atm_return(vcc, skb->truesize); dev_kfree_skb(skb); } @@ -1748,6 +1744,50 @@ static void lec_arp_expire_vcc(unsigned long data) lec_arp_put(to_remove); } +static bool __lec_arp_check_expire(struct lec_arp_table *entry, + unsigned long now, + struct lec_priv *priv) +{ + unsigned long time_to_check; + + if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change) + time_to_check = priv->forward_delay_time; + else + time_to_check = priv->aging_time; + + pr_debug("About to expire: %lx - %lx > %lx\n", + now, entry->last_used, time_to_check); + if (time_after(now, entry->last_used + time_to_check) && + !(entry->flags & LEC_PERMANENT_FLAG) && + !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ + /* Remove entry */ + pr_debug("Entry timed out\n"); + lec_arp_remove(priv, entry); + lec_arp_put(entry); + } else { + /* Something else */ + if ((entry->status == ESI_VC_PENDING || + entry->status == ESI_ARP_PENDING) && + time_after_eq(now, entry->timestamp + + priv->max_unknown_frame_time)) { + entry->timestamp = jiffies; + entry->packets_flooded = 0; + if (entry->status == ESI_VC_PENDING) + send_to_lecd(priv, l_svc_setup, + entry->mac_addr, + entry->atm_addr, + NULL); + } + if (entry->status == ESI_FLUSH_PENDING && + time_after_eq(now, entry->timestamp + + priv->path_switching_delay)) { + lec_arp_hold(entry); + return true; + } + } + + return false; +} /* * Expire entries. * 1. Re-set timer @@ -1772,7 +1812,6 @@ static void lec_arp_check_expire(struct work_struct *work) struct hlist_node *node, *next; struct lec_arp_table *entry; unsigned long now; - unsigned long time_to_check; int i; pr_debug("%p\n", priv); @@ -1782,51 +1821,19 @@ restart: for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { - if ((entry->flags) & LEC_REMOTE_FLAG && - priv->topology_change) - time_to_check = priv->forward_delay_time; - else - time_to_check = priv->aging_time; - - pr_debug("About to expire: %lx - %lx > %lx\n", - now, entry->last_used, time_to_check); - if (time_after(now, entry->last_used + time_to_check) && - !(entry->flags & LEC_PERMANENT_FLAG) && - !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ - /* Remove entry */ - pr_debug("Entry timed out\n"); - lec_arp_remove(priv, entry); + if (__lec_arp_check_expire(entry, now, priv)) { + struct sk_buff *skb; + struct atm_vcc *vcc = entry->vcc; + + spin_unlock_irqrestore(&priv->lec_arp_lock, + flags); + while ((skb = skb_dequeue(&entry->tx_wait))) + lec_send(vcc, skb); + entry->last_used = jiffies; + entry->status = ESI_FORWARD_DIRECT; lec_arp_put(entry); - } else { - /* Something else */ - if ((entry->status == ESI_VC_PENDING || - entry->status == ESI_ARP_PENDING) && - time_after_eq(now, - entry->timestamp + - priv->max_unknown_frame_time)) { - entry->timestamp = jiffies; - entry->packets_flooded = 0; - if (entry->status == ESI_VC_PENDING) - send_to_lecd(priv, l_svc_setup, - entry->mac_addr, - entry->atm_addr, - NULL); - } - if (entry->status == ESI_FLUSH_PENDING && - time_after_eq(now, entry->timestamp + - priv->path_switching_delay)) { - struct sk_buff *skb; - struct atm_vcc *vcc = entry->vcc; - - lec_arp_hold(entry); - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - while ((skb = skb_dequeue(&entry->tx_wait)) != NULL) - lec_send(vcc, skb); - entry->last_used = jiffies; - entry->status = ESI_FORWARD_DIRECT; - lec_arp_put(entry); - goto restart; - } + + goto restart; } } } @@ -2237,7 +2244,7 @@ restart: lec_arp_hold(entry); spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - while ((skb = skb_dequeue(&entry->tx_wait)) != NULL) + while ((skb = skb_dequeue(&entry->tx_wait))) lec_send(vcc, skb); entry->last_used = jiffies; entry->status = ESI_FORWARD_DIRECT; -- GitLab From b50c2ea72a8ed6bc2a954019b6feb6ca41fce07e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Jan 2010 11:40:20 +0000 Subject: [PATCH 1257/3892] net/atm: Cleanup dprint/ddprintk #defines and uses Move "mpoa:%s: ", __func__/__FILE__ to #defines Remove mpoa __func__/__FILE__ from dprintk uses Add and use #define dprint_cont where appropriate Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/mpc.c | 153 +++++++++++++++++++++--------------------- net/atm/mpoa_caches.c | 50 +++++++------- net/atm/mpoa_proc.c | 28 +++++--- 3 files changed, 124 insertions(+), 107 deletions(-) diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 55dba22e44b3..a6521c8aa88b 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -38,21 +38,31 @@ */ #if 0 -#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ +#define dprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args) +#define dprintk_cont(format, args...) printk(KERN_CONT format, ##args) #else -#define dprintk(format, args...) \ - do { if (0) printk(KERN_DEBUG format, ##args); } while (0) +#define dprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\ + } while (0) +#define dprintk_cont(format, args...) \ + do { if (0) printk(KERN_CONT format, ##args); } while (0) #endif #if 0 -#define ddprintk printk(KERN_DEBUG format, ##args) /* more debug */ +#define ddprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args) +#define ddprintk_cont(format, args...) printk(KERN_CONT format, ##args) #else -#define ddprintk(format, args...) \ - do { if (0) printk(KERN_DEBUG format, ##args); } while (0) +#define ddprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\ + } while (0) +#define ddprintk_cont(format, args...) \ + do { if (0) printk(KERN_CONT format, ##args); } while (0) #endif - - #define MPOA_TAG_LEN 4 /* mpc_daemon -> kernel */ @@ -302,7 +312,7 @@ static struct mpoa_client *alloc_mpc(void) static void start_mpc(struct mpoa_client *mpc, struct net_device *dev) { - dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name); + dprintk("(%s)\n", mpc->dev->name); if (!dev->netdev_ops) pr_info("(%s) not starting\n", dev->name); else { @@ -316,14 +326,14 @@ static void start_mpc(struct mpoa_client *mpc, struct net_device *dev) static void stop_mpc(struct mpoa_client *mpc) { struct net_device *dev = mpc->dev; - dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name); + dprintk("(%s)", mpc->dev->name); /* Lets not nullify lec device's dev->hard_start_xmit */ if (dev->netdev_ops != &mpc->new_ops) { - dprintk(" mpc already stopped, not fatal\n"); + dprintk_cont(" mpc already stopped, not fatal\n"); return; } - dprintk("\n"); + dprintk_cont("\n"); dev->netdev_ops = mpc->old_ops; mpc->old_ops = NULL; @@ -371,7 +381,7 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, struct mpoa_client *mpc; mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */ - dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name); + dprintk("(%s) received TLV(s), ", dev->name); dprintk("total length of all TLVs %d\n", sizeoftlvs); mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */ if (mpc == NULL) { @@ -402,7 +412,7 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, } mpoa_device_type = *tlvs++; number_of_mps_macs = *tlvs++; - dprintk("mpoa: (%s) MPOA device type '%s', ", + dprintk("(%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type)); if (mpoa_device_type == MPS_AND_MPC && length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */ @@ -417,7 +427,7 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, } if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) { - dprintk("ignoring non-MPS device\n"); + dprintk("ignoring non-MPS device "); if (mpoa_device_type == MPC) tlvs += 20; continue; /* we are only interested in MPSs */ @@ -427,7 +437,8 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, pr_info("(%s) MPS_AND_MPC has zero MACs\n", dev->name); continue; /* someone should read the spec */ } - dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs); + dprintk_cont("this MPS has %d MAC addresses\n", + number_of_mps_macs); /* * ok, now we can go and tell our daemon @@ -498,7 +509,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) iph = (struct iphdr *)buff; ipaddr = iph->daddr; - ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", + ddprintk("(%s) ipaddr 0x%x\n", mpc->dev->name, ipaddr); entry = mpc->in_ops->get(ipaddr, mpc); @@ -510,17 +521,17 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) } /* threshold not exceeded or VCC not ready */ if (mpc->in_ops->cache_hit(entry, mpc) != OPEN) { - ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", + ddprintk("(%s) cache_hit: returns != OPEN\n", mpc->dev->name); mpc->in_ops->put(entry); return 1; } - ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", + ddprintk("(%s) using shortcut\n", mpc->dev->name); /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ if (iph->ttl <= 1) { - ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", + ddprintk("(%s) IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); mpc->in_ops->put(entry); return 1; @@ -530,7 +541,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); if (entry->ctrl_info.tag != 0) { - ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", + ddprintk("(%s) adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ @@ -655,25 +666,23 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) return; } - dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name); + dprintk("(%s)\n", dev->name); in_entry = mpc->in_ops->get_by_vcc(vcc, mpc); if (in_entry) { - dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %pI4\n", + dprintk("(%s) ingress SVC closed ip = %pI4\n", mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); in_entry->shortcut = NULL; mpc->in_ops->put(in_entry); } eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc); if (eg_entry) { - dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", - mpc->dev->name); + dprintk("(%s) egress SVC closed\n", mpc->dev->name); eg_entry->shortcut = NULL; mpc->eg_ops->put(eg_entry); } if (in_entry == NULL && eg_entry == NULL) - dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", - dev->name); + dprintk("(%s) unused vcc closed\n", dev->name); return; } @@ -687,10 +696,9 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) __be32 tag; char *tmp; - ddprintk("mpoa: (%s) mpc_push:\n", dev->name); + ddprintk("(%s)\n", dev->name); if (skb == NULL) { - dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", - dev->name); + dprintk("(%s) null skb, closing VCC\n", dev->name); mpc_vcc_close(vcc, dev); return; } @@ -700,8 +708,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) sizeof(struct llc_snap_hdr)) == 0) { struct sock *sk = sk_atm(vcc); - dprintk("mpoa: (%s) mpc_push: control packet arrived\n", - dev->name); + dprintk("(%s) control packet arrived\n", dev->name); /* Pass control packets to daemon */ skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); @@ -719,8 +726,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ - ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", - dev->name); + ddprintk("(%s) tagged data packet arrived\n", dev->name); } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ @@ -813,8 +819,7 @@ static int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg) mpc = find_mpc_by_itfnum(arg); if (mpc == NULL) { - dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", - arg); + dprintk("allocating new mpc for itf %d\n", arg); mpc = alloc_mpc(); if (mpc == NULL) return -ENOMEM; @@ -923,55 +928,54 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) pr_info("no mpc found\n"); return 0; } - dprintk("mpoa: (%s) msg_from_mpoad:", - (mpc->dev) ? mpc->dev->name : ""); + dprintk("(%s)", mpc->dev ? mpc->dev->name : ""); switch (mesg->type) { case MPOA_RES_REPLY_RCVD: - dprintk(" mpoa_res_reply_rcvd\n"); + dprintk_cont("mpoa_res_reply_rcvd\n"); MPOA_res_reply_rcvd(mesg, mpc); break; case MPOA_TRIGGER_RCVD: - dprintk(" mpoa_trigger_rcvd\n"); + dprintk_cont("mpoa_trigger_rcvd\n"); MPOA_trigger_rcvd(mesg, mpc); break; case INGRESS_PURGE_RCVD: - dprintk(" nhrp_purge_rcvd\n"); + dprintk_cont("nhrp_purge_rcvd\n"); ingress_purge_rcvd(mesg, mpc); break; case EGRESS_PURGE_RCVD: - dprintk(" egress_purge_reply_rcvd\n"); + dprintk_cont("egress_purge_reply_rcvd\n"); egress_purge_rcvd(mesg, mpc); break; case MPS_DEATH: - dprintk(" mps_death\n"); + dprintk_cont("mps_death\n"); mps_death(mesg, mpc); break; case CACHE_IMPOS_RCVD: - dprintk(" cache_impos_rcvd\n"); + dprintk_cont("cache_impos_rcvd\n"); MPOA_cache_impos_rcvd(mesg, mpc); break; case SET_MPC_CTRL_ADDR: - dprintk(" set_mpc_ctrl_addr\n"); + dprintk_cont("set_mpc_ctrl_addr\n"); set_mpc_ctrl_addr_rcvd(mesg, mpc); break; case SET_MPS_MAC_ADDR: - dprintk(" set_mps_mac_addr\n"); + dprintk_cont("set_mps_mac_addr\n"); set_mps_mac_addr_rcvd(mesg, mpc); break; case CLEAN_UP_AND_EXIT: - dprintk(" clean_up_and_exit\n"); + dprintk_cont("clean_up_and_exit\n"); clean_up(mesg, mpc, DIE); break; case RELOAD: - dprintk(" reload\n"); + dprintk_cont("reload\n"); clean_up(mesg, mpc, RELOAD); break; case SET_MPC_PARAMS: - dprintk(" set_mpc_params\n"); + dprintk_cont("set_mpc_params\n"); mpc->parameters = mesg->content.params; break; default: - dprintk(" unknown message %d\n", mesg->type); + dprintk_cont("unknown message %d\n", mesg->type); break; } kfree_skb(skb); @@ -1027,8 +1031,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, priv->lane2_ops->associate_indicator = lane2_assoc_ind; mpc = find_mpc_by_itfnum(priv->itfnum); if (mpc == NULL) { - dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n", - dev->name); + dprintk("allocating new mpc for %s\n", dev->name); mpc = alloc_mpc(); if (mpc == NULL) { pr_info("no new mpc"); @@ -1038,14 +1041,14 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, mpc->dev_num = priv->itfnum; mpc->dev = dev; dev_hold(dev); - dprintk("mpoa: (%s) was initialized\n", dev->name); + dprintk("(%s) was initialized\n", dev->name); break; case NETDEV_UNREGISTER: /* the lec device was deallocated */ mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; - dprintk("mpoa: device (%s) was deallocated\n", dev->name); + dprintk("device (%s) was deallocated\n", dev->name); stop_mpc(mpc); dev_put(mpc->dev); mpc->dev = NULL; @@ -1143,7 +1146,7 @@ static void check_qos_and_open_shortcut(struct k_message *msg, entry->shortcut = eg_entry->shortcut; } if (entry->shortcut) { - dprintk("mpoa: (%s) using egress SVC to reach %pI4\n", + dprintk("(%s) using egress SVC to reach %pI4\n", client->dev->name, &dst_ip); client->eg_ops->put(eg_entry); return; @@ -1170,16 +1173,16 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); - dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %pI4\n", + dprintk("(%s) ip %pI4\n", mpc->dev->name, &dst_ip); - ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", + ddprintk("(%s) entry = %p", mpc->dev->name, entry); if (entry == NULL) { pr_info("(%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name); return; } - ddprintk(" entry_state = %d ", entry->entry_state); + ddprintk_cont(" entry_state = %d ", entry->entry_state); if (entry->entry_state == INGRESS_RESOLVED) { pr_info("(%s) RESOLVED entry!\n", mpc->dev->name); @@ -1191,7 +1194,7 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) do_gettimeofday(&(entry->tv)); do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */ entry->refresh_time = 0; - ddprintk("entry->shortcut = %p\n", entry->shortcut); + ddprintk_cont("entry->shortcut = %p\n", entry->shortcut); if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) { @@ -1228,7 +1231,7 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) } do { - dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %pI4\n", + dprintk("(%s) removing an ingress entry, ip = %pI4\n", mpc->dev->name, &dst_ip); write_lock_bh(&mpc->ingress_lock); mpc->in_ops->remove_entry(entry, mpc); @@ -1246,7 +1249,7 @@ static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); if (entry == NULL) { - dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", + dprintk("(%s) purge for a non-existing entry\n", mpc->dev->name); return; } @@ -1266,7 +1269,7 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) struct k_message *purge_msg; struct sk_buff *skb; - dprintk("mpoa: purge_egress_shortcut: entering\n"); + dprintk("entering\n"); if (vcc == NULL) { pr_info("vcc == NULL\n"); return; @@ -1290,7 +1293,7 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) sk = sk_atm(vcc); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); - dprintk("mpoa: purge_egress_shortcut: exiting:\n"); + dprintk("exiting\n"); return; } @@ -1303,7 +1306,7 @@ static void mps_death(struct k_message *msg, struct mpoa_client *mpc) { eg_cache_entry *entry; - dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name); + dprintk("(%s)\n", mpc->dev->name); if (memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)) { pr_info("(%s) wrong MPS\n", mpc->dev->name); @@ -1332,7 +1335,7 @@ static void MPOA_cache_impos_rcvd(struct k_message *msg, eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc); holding_time = msg->content.eg_info.holding_time; - dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n", + dprintk("(%s) entry = %p, holding_time = %u\n", mpc->dev->name, entry, holding_time); if (entry == NULL && holding_time) { entry = mpc->eg_ops->add_entry(msg, mpc); @@ -1369,11 +1372,11 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); - dprintk("mpoa: (%s) setting MPC ctrl ATM address to ", - (mpc->dev) ? mpc->dev->name : ""); + dprintk("(%s) setting MPC ctrl ATM address to", + mpc->dev ? mpc->dev->name : ""); for (i = 7; i < sizeof(tlv); i++) - dprintk("%02x ", tlv[i]); - dprintk("\n"); + dprintk_cont(" %02x", tlv[i]); + dprintk_cont("\n"); if (mpc->dev) { priv = netdev_priv(mpc->dev); @@ -1424,7 +1427,7 @@ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action) entry = mpc->eg_cache; while (entry != NULL) { msg->content.eg_info = entry->ctrl_info; - dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id); + dprintk("cache_id %u\n", entry->ctrl_info.cache_id); msg_to_mpoad(msg, mpc); entry = entry->next; } @@ -1537,15 +1540,15 @@ static void __exit atm_mpoa_cleanup(void) if (priv->lane2_ops != NULL) priv->lane2_ops->associate_indicator = NULL; } - ddprintk("mpoa: cleanup_module: about to clear caches\n"); + ddprintk("about to clear caches\n"); mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); - ddprintk("mpoa: cleanup_module: caches cleared\n"); + ddprintk("caches cleared\n"); kfree(mpc->mps_macs); memset(mpc, 0, sizeof(struct mpoa_client)); - ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc); + ddprintk("about to kfree %p\n", mpc); kfree(mpc); - ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp); + ddprintk("next mpc is at %p\n", tmp); mpc = tmp; } @@ -1553,7 +1556,7 @@ static void __exit atm_mpoa_cleanup(void) qos_head = NULL; while (qos != NULL) { nextqos = qos->next; - dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos); + dprintk("freeing qos entry %p\n", qos); kfree(qos); qos = nextqos; } diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index de21cc66feb4..4c141810eb6d 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -11,17 +11,23 @@ */ #if 0 -#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ +#define dprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ #else -#define dprintk(format, args...) \ - do { if (0) printk(KERN_DEBUG format, ##args); } while (0) +#define dprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ + } while (0) #endif #if 0 -#define ddprintk printk(KERN_DEBUG format, ##args) /* more debug */ +#define ddprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ #else -#define ddprintk(format, args...) \ - do { if (0) printk(KERN_DEBUG format, ##args); } while (0) +#define ddprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ + } while (0) #endif static in_cache_entry *in_cache_get(__be32 dst_ip, @@ -96,11 +102,10 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip, return NULL; } - dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", - &dst_ip); + dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip); atomic_set(&entry->use, 1); - dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); + dprintk("new_in_cache_entry: about to lock\n"); write_lock_bh(&client->ingress_lock); entry->next = client->in_cache; entry->prev = NULL; @@ -118,7 +123,7 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip, atomic_inc(&entry->use); write_unlock_bh(&client->ingress_lock); - dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n"); + dprintk("new_in_cache_entry: unlocked\n"); return entry; } @@ -154,7 +159,7 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) if (entry->count > mpc->parameters.mpc_p1 && entry->entry_state == INGRESS_INVALID) { - dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n", + dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n", mpc->dev->name, &entry->ctrl_info.in_dst_ip); entry->entry_state = INGRESS_RESOLVING; msg.type = SND_MPOA_RES_RQST; @@ -190,7 +195,7 @@ static void in_cache_remove_entry(in_cache_entry *entry, struct k_message msg; vcc = entry->shortcut; - dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n", + dprintk("removing an ingress entry, ip = %pI4\n", &entry->ctrl_info.in_dst_ip); if (entry->prev != NULL) @@ -235,7 +240,7 @@ static void clear_count_and_expired(struct mpoa_client *client) next_entry = entry->next; if ((now.tv_sec - entry->tv.tv_sec) > entry->ctrl_info.holding_time) { - dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n", + dprintk("holding time expired, ip = %pI4\n", &entry->ctrl_info.in_dst_ip); client->in_ops->remove_entry(entry, client); } @@ -302,7 +307,7 @@ static void refresh_entries(struct mpoa_client *client) struct timeval now; struct in_cache_entry *entry = client->in_cache; - ddprintk("mpoa: mpoa_caches.c: refresh_entries\n"); + ddprintk("refresh_entries\n"); do_gettimeofday(&now); read_lock_bh(&client->ingress_lock); @@ -312,7 +317,7 @@ static void refresh_entries(struct mpoa_client *client) entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3; if ((now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time) { - dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n"); + dprintk("refreshing an entry.\n"); entry->entry_state = INGRESS_REFRESHING; } @@ -435,7 +440,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, struct k_message msg; vcc = entry->shortcut; - dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n"); + dprintk("removing an egress entry.\n"); if (entry->prev != NULL) entry->prev->next = entry->next; else @@ -471,11 +476,11 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, return NULL; } - dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n", + dprintk("adding an egress entry, ip = %pI4, this should be our IP\n", &msg->content.eg_info.eg_dst_ip); atomic_set(&entry->use, 1); - dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); + dprintk("new_eg_cache_entry: about to lock\n"); write_lock_irq(&client->egress_lock); entry->next = client->eg_cache; entry->prev = NULL; @@ -487,14 +492,13 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, entry->ctrl_info = msg->content.eg_info; do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; - dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %u\n", + dprintk("new_eg_cache_entry cache_id %u\n", ntohl(entry->ctrl_info.cache_id)); - dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n", - &entry->ctrl_info.mps_ip); + dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip); atomic_inc(&entry->use); write_unlock_irq(&client->egress_lock); - dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n"); + dprintk("new_eg_cache_entry: unlocked\n"); return entry; } @@ -524,7 +528,7 @@ static void clear_expired(struct mpoa_client *client) > entry->ctrl_info.holding_time) { msg.type = SND_EGRESS_PURGE; msg.content.eg_info = entry->ctrl_info; - dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %u.\n", + dprintk("egress_cache: holding time expired, cache_id = %u.\n", ntohl(entry->ctrl_info.cache_id)); msg_to_mpoad(&msg, client); client->eg_ops->remove_entry(entry, client); diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index aae4a87c22ac..b9bdb98427e4 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -21,10 +21,23 @@ */ #if 1 -#define dprintk(format, args...) printk(KERN_DEBUG format, ##args) /* debug */ +#define dprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ #else -#define dprintk(format, args...) \ - do { if (0) printk(KERN_DEBUG format, ##args); } while (0) +#define dprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ + } while (0) +#endif + +#if 0 +#define ddprintk(format, args...) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ +#else +#define ddprintk(format, args...) \ + do { if (0) \ + printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ + } while (0) #endif #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ @@ -258,12 +271,9 @@ static int parse_qos(const char *buff) qos.rxtp.max_pcr = rx_pcr; qos.rxtp.max_sdu = rx_sdu; qos.aal = ATM_AAL5; - dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", - qos.txtp.max_pcr, - qos.txtp.max_sdu, - qos.rxtp.max_pcr, - qos.rxtp.max_sdu - ); + dprintk("parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n", + qos.txtp.max_pcr, qos.txtp.max_sdu, + qos.rxtp.max_pcr, qos.rxtp.max_sdu); atm_mpoa_add_qos(ipaddr, &qos); return 1; -- GitLab From abd50713944c8ea9e0af5b7bffa0aacae21cc91a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 26 Jan 2010 18:50:16 +0100 Subject: [PATCH 1258/3892] perf: Reimplement frequency driven sampling There was a bug in the old period code that caused intel_pmu_enable_all() or native_write_msr_safe() to show up quite high in the profiles. In staring at that code it made my head hurt, so I rewrote it in a hopefully simpler fashion. Its now fully symetric between tick and overflow driven adjustments and uses less data to boot. The only complication is that it basically wants to do a u128 division. The code approximates that in a rather simple truncate until it fits fashion, taking care to balance the terms while truncating. This version does not generate that sampling artefact. Signed-off-by: Peter Zijlstra LKML-Reference: Cc: Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 5 +- kernel/perf_event.c | 132 ++++++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 43 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index c6f812e4d058..72b2615600d8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -498,9 +498,8 @@ struct hw_perf_event { atomic64_t period_left; u64 interrupts; - u64 freq_count; - u64 freq_interrupts; - u64 freq_stamp; + u64 freq_time_stamp; + u64 freq_count_stamp; #endif }; diff --git a/kernel/perf_event.c b/kernel/perf_event.c index edc46b92b508..251fb9552492 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1423,14 +1423,83 @@ void perf_event_task_sched_in(struct task_struct *task) static void perf_log_throttle(struct perf_event *event, int enable); -static void perf_adjust_period(struct perf_event *event, u64 events) +static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) +{ + u64 frequency = event->attr.sample_freq; + u64 sec = NSEC_PER_SEC; + u64 divisor, dividend; + + int count_fls, nsec_fls, frequency_fls, sec_fls; + + count_fls = fls64(count); + nsec_fls = fls64(nsec); + frequency_fls = fls64(frequency); + sec_fls = 30; + + /* + * We got @count in @nsec, with a target of sample_freq HZ + * the target period becomes: + * + * @count * 10^9 + * period = ------------------- + * @nsec * sample_freq + * + */ + + /* + * Reduce accuracy by one bit such that @a and @b converge + * to a similar magnitude. + */ +#define REDUCE_FLS(a, b) \ +do { \ + if (a##_fls > b##_fls) { \ + a >>= 1; \ + a##_fls--; \ + } else { \ + b >>= 1; \ + b##_fls--; \ + } \ +} while (0) + + /* + * Reduce accuracy until either term fits in a u64, then proceed with + * the other, so that finally we can do a u64/u64 division. + */ + while (count_fls + sec_fls > 64 && nsec_fls + frequency_fls > 64) { + REDUCE_FLS(nsec, frequency); + REDUCE_FLS(sec, count); + } + + if (count_fls + sec_fls > 64) { + divisor = nsec * frequency; + + while (count_fls + sec_fls > 64) { + REDUCE_FLS(count, sec); + divisor >>= 1; + } + + dividend = count * sec; + } else { + dividend = count * sec; + + while (nsec_fls + frequency_fls > 64) { + REDUCE_FLS(nsec, frequency); + dividend >>= 1; + } + + divisor = nsec * frequency; + } + + return div64_u64(dividend, divisor); +} + +static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) { struct hw_perf_event *hwc = &event->hw; u64 period, sample_period; s64 delta; - events *= hwc->sample_period; - period = div64_u64(events, event->attr.sample_freq); + period = perf_calculate_period(event, nsec, count); delta = (s64)(period - hwc->sample_period); delta = (delta + 7) / 8; /* low pass filter */ @@ -1441,13 +1510,22 @@ static void perf_adjust_period(struct perf_event *event, u64 events) sample_period = 1; hwc->sample_period = sample_period; + + if (atomic64_read(&hwc->period_left) > 8*sample_period) { + perf_disable(); + event->pmu->disable(event); + atomic64_set(&hwc->period_left, 0); + event->pmu->enable(event); + perf_enable(); + } } static void perf_ctx_adjust_freq(struct perf_event_context *ctx) { struct perf_event *event; struct hw_perf_event *hwc; - u64 interrupts, freq; + u64 interrupts, now; + s64 delta; raw_spin_lock(&ctx->lock); list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { @@ -1468,44 +1546,18 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) if (interrupts == MAX_INTERRUPTS) { perf_log_throttle(event, 1); event->pmu->unthrottle(event); - interrupts = 2*sysctl_perf_event_sample_rate/HZ; } if (!event->attr.freq || !event->attr.sample_freq) continue; - /* - * if the specified freq < HZ then we need to skip ticks - */ - if (event->attr.sample_freq < HZ) { - freq = event->attr.sample_freq; - - hwc->freq_count += freq; - hwc->freq_interrupts += interrupts; - - if (hwc->freq_count < HZ) - continue; - - interrupts = hwc->freq_interrupts; - hwc->freq_interrupts = 0; - hwc->freq_count -= HZ; - } else - freq = HZ; - - perf_adjust_period(event, freq * interrupts); + event->pmu->read(event); + now = atomic64_read(&event->count); + delta = now - hwc->freq_count_stamp; + hwc->freq_count_stamp = now; - /* - * In order to avoid being stalled by an (accidental) huge - * sample period, force reset the sample period if we didn't - * get any events in this freq period. - */ - if (!interrupts) { - perf_disable(); - event->pmu->disable(event); - atomic64_set(&hwc->period_left, 0); - event->pmu->enable(event); - perf_enable(); - } + if (delta > 0) + perf_adjust_period(event, TICK_NSEC, delta); } raw_spin_unlock(&ctx->lock); } @@ -3768,12 +3820,12 @@ static int __perf_event_overflow(struct perf_event *event, int nmi, if (event->attr.freq) { u64 now = perf_clock(); - s64 delta = now - hwc->freq_stamp; + s64 delta = now - hwc->freq_time_stamp; - hwc->freq_stamp = now; + hwc->freq_time_stamp = now; - if (delta > 0 && delta < TICK_NSEC) - perf_adjust_period(event, NSEC_PER_SEC / (int)delta); + if (delta > 0 && delta < 2*TICK_NSEC) + perf_adjust_period(event, delta, hwc->last_period); } /* -- GitLab From 63b62ab0d52c736b3274b294df962e0a4b7aae79 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Wed, 27 Jan 2010 11:46:17 +0800 Subject: [PATCH 1259/3892] ASoC: ad1836: use soc-cache framework for codec registers access Signed-off-by: Barry Song Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 92 ++++++++++----------------------------- sound/soc/soc-cache.c | 67 ++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 83add2f3afba..3c80137d5938 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -171,58 +171,6 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, return 0; } - -/* - * interface to read/write ad1836 register - */ -#define AD1836_SPI_REG_SHFT 12 -#define AD1836_SPI_READ (1 << 11) -#define AD1836_SPI_VAL_MSK 0x3FF - -/* - * write to the ad1836 register space - */ - -static int ad1836_write_reg(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *reg_cache = codec->reg_cache; - int ret = 0; - - if (value != reg_cache[reg]) { - unsigned short buf; - struct spi_transfer t = { - .tx_buf = &buf, - .len = 2, - }; - struct spi_message m; - - buf = (reg << AD1836_SPI_REG_SHFT) | - (value & AD1836_SPI_VAL_MSK); - spi_message_init(&m); - spi_message_add_tail(&t, &m); - ret = spi_sync(codec->control_data, &m); - if (ret == 0) - reg_cache[reg] = value; - } - - return ret; -} - -/* - * read from the ad1836 register space cache - */ -static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *reg_cache = codec->reg_cache; - - if (reg >= codec->reg_cache_size) - return -EINVAL; - - return reg_cache[reg]; -} - #ifdef CONFIG_PM static int ad1836_soc_suspend(struct platform_device *pdev, pm_message_t state) @@ -231,10 +179,10 @@ static int ad1836_soc_suspend(struct platform_device *pdev, struct snd_soc_codec *codec = socdev->card->codec; /* reset clock control mode */ - u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; - return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } static int ad1836_soc_resume(struct platform_device *pdev) @@ -243,10 +191,10 @@ static int ad1836_soc_resume(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->card->codec; /* restore clock control mode */ - u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); adc_ctrl2 |= AD1836_ADC_AUX; - return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2); + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } #else #define ad1836_soc_suspend NULL @@ -336,32 +284,38 @@ static int ad1836_register(struct ad1836_priv *ad1836) codec->owner = THIS_MODULE; codec->dai = &ad1836_dai; codec->num_dai = 1; - codec->write = ad1836_write_reg; - codec->read = ad1836_read_reg_cache; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); ad1836_dai.dev = codec->dev; ad1836_codec = codec; + ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); + if (ret < 0) { + dev_err(codec->dev, "failed to set cache I/O: %d\n", + ret); + kfree(ad1836); + return ret; + } + /* default setting for ad1836 */ /* de-emphasis: 48kHz, power-on dac */ - codec->write(codec, AD1836_DAC_CTRL1, 0x300); + snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300); /* unmute dac channels */ - codec->write(codec, AD1836_DAC_CTRL2, 0x0); + snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0); /* high-pass filter enable, power-on adc */ - codec->write(codec, AD1836_ADC_CTRL1, 0x100); + snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); /* unmute adc channles, adc aux mode */ - codec->write(codec, AD1836_ADC_CTRL2, 0x180); + snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); /* left/right diff:PGA/MUX */ - codec->write(codec, AD1836_ADC_CTRL3, 0x3A); + snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); /* volume */ - codec->write(codec, AD1836_DAC_L1_VOL, 0x3FF); - codec->write(codec, AD1836_DAC_R1_VOL, 0x3FF); - codec->write(codec, AD1836_DAC_L2_VOL, 0x3FF); - codec->write(codec, AD1836_DAC_R2_VOL, 0x3FF); - codec->write(codec, AD1836_DAC_L3_VOL, 0x3FF); - codec->write(codec, AD1836_DAC_R3_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); ret = snd_soc_register_codec(codec); if (ret != 0) { diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 02c235711bb8..cde7b63de113 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -15,6 +15,68 @@ #include #include +static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= codec->reg_cache_size) + return -1; + return cache[reg]; +} + +static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[2]; + int ret; + + BUG_ON(codec->volatile_register); + + data[0] = (reg << 4) | ((value >> 8) & 0x000f); + data[1] = value & 0x00ff; + + if (reg < codec->reg_cache_size) + cache[reg] = value; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret == 2) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +#if defined(CONFIG_SPI_MASTER) +static int snd_soc_4_12_spi_write(void *control_data, const char *data, + int len) +{ + struct spi_device *spi = control_data; + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[1]; + msg[1] = data[0]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#else +#define snd_soc_4_12_spi_write NULL +#endif + static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -179,6 +241,11 @@ static struct { unsigned int (*read)(struct snd_soc_codec *, unsigned int); unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { + { + .addr_bits = 4, .data_bits = 12, + .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, + .spi_write = snd_soc_4_12_spi_write, + }, { .addr_bits = 7, .data_bits = 9, .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, -- GitLab From 994dc4245d3f50329da4ead453a5dfcfbc716a0d Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Wed, 27 Jan 2010 11:46:18 +0800 Subject: [PATCH 1260/3892] ASoC: ad1938: use soc-cache framework for codec registers access Signed-off-by: Barry Song Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1938.c | 164 +++++++++----------------------------- sound/soc/soc-cache.c | 108 +++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 128 deletions(-) diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 47d9ac0ec9d9..c233810d463d 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -46,6 +46,11 @@ struct ad1938_priv { u8 reg_cache[AD1938_NUM_REGS]; }; +/* ad1938 register cache & default register settings */ +static const u8 ad1938_reg[AD1938_NUM_REGS] = { + 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, +}; + static struct snd_soc_codec *ad1938_codec; struct snd_soc_codec_device soc_codec_dev_ad1938; static int ad1938_register(struct ad1938_priv *ad1938); @@ -129,10 +134,10 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) struct snd_soc_codec *codec = dai->codec; int reg; - reg = codec->read(codec, AD1938_DAC_CTRL2); + reg = snd_soc_read(codec, AD1938_DAC_CTRL2); reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & (~AD1938_DAC_MASTER_MUTE); - codec->write(codec, AD1938_DAC_CTRL2, reg); + snd_soc_write(codec, AD1938_DAC_CTRL2, reg); return 0; } @@ -141,8 +146,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int width) { struct snd_soc_codec *codec = dai->codec; - int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); - int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); + int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); + int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); dac_reg &= ~AD1938_DAC_CHAN_MASK; adc_reg &= ~AD1938_ADC_CHAN_MASK; @@ -168,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - codec->write(codec, AD1938_DAC_CTRL1, dac_reg); - codec->write(codec, AD1938_ADC_CTRL2, adc_reg); + snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); + snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); return 0; } @@ -180,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; int adc_reg, dac_reg; - adc_reg = codec->read(codec, AD1938_ADC_CTRL2); - dac_reg = codec->read(codec, AD1938_DAC_CTRL1); + adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); + dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) @@ -258,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - codec->write(codec, AD1938_ADC_CTRL2, adc_reg); - codec->write(codec, AD1938_DAC_CTRL1, dac_reg); + snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); + snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); return 0; } @@ -288,116 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream, break; } - reg = codec->read(codec, AD1938_DAC_CTRL2); + reg = snd_soc_read(codec, AD1938_DAC_CTRL2); reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; - codec->write(codec, AD1938_DAC_CTRL2, reg); + snd_soc_write(codec, AD1938_DAC_CTRL2, reg); - reg = codec->read(codec, AD1938_ADC_CTRL1); + reg = snd_soc_read(codec, AD1938_ADC_CTRL1); reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; - codec->write(codec, AD1938_ADC_CTRL1, reg); - - return 0; -} - -/* - * interface to read/write ad1938 register - */ - -#define AD1938_SPI_ADDR 0x4 -#define AD1938_SPI_READ 0x1 -#define AD1938_SPI_BUFLEN 3 - -/* - * write to the ad1938 register space - */ - -static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 *reg_cache = codec->reg_cache; - int ret = 0; - - if (value != reg_cache[reg]) { - uint8_t buf[AD1938_SPI_BUFLEN]; - struct spi_transfer t = { - .tx_buf = buf, - .len = AD1938_SPI_BUFLEN, - }; - struct spi_message m; - - buf[0] = AD1938_SPI_ADDR << 1; - buf[1] = reg; - buf[2] = value; - spi_message_init(&m); - spi_message_add_tail(&t, &m); - ret = spi_sync(codec->control_data, &m); - if (ret == 0) - reg_cache[reg] = value; - } - - return ret; -} - -/* - * read from the ad1938 register space cache - */ - -static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *reg_cache = codec->reg_cache; - - if (reg >= codec->reg_cache_size) - return -EINVAL; - - return reg_cache[reg]; -} - -/* - * read from the ad1938 register space - */ - -static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, - unsigned int reg) -{ - char w_buf[AD1938_SPI_BUFLEN]; - char r_buf[AD1938_SPI_BUFLEN]; - int ret; - - struct spi_transfer t = { - .tx_buf = w_buf, - .rx_buf = r_buf, - .len = AD1938_SPI_BUFLEN, - }; - struct spi_message m; - - w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ; - w_buf[1] = reg; - w_buf[2] = 0; - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - ret = spi_sync(codec->control_data, &m); - if (ret == 0) - return r_buf[2]; - else - return -EIO; -} - -static int ad1938_fill_cache(struct snd_soc_codec *codec) -{ - int i; - u8 *reg_cache = codec->reg_cache; - struct spi_device *spi = codec->control_data; - - for (i = 0; i < codec->reg_cache_size; i++) { - int ret = ad1938_read_reg(codec, i); - if (ret == -EIO) { - dev_err(&spi->dev, "AD1938 SPI read failure\n"); - return ret; - } - reg_cache[i] = ret; - } + snd_soc_write(codec, AD1938_ADC_CTRL1, reg); return 0; } @@ -487,31 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938) codec->owner = THIS_MODULE; codec->dai = &ad1938_dai; codec->num_dai = 1; - codec->write = ad1938_write_reg; - codec->read = ad1938_read_reg_cache; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); ad1938_dai.dev = codec->dev; ad1938_codec = codec; + memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS); + + ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI); + if (ret < 0) { + dev_err(codec->dev, "failed to set cache I/O: %d\n", + ret); + kfree(ad1938); + return ret; + } + /* default setting for ad1938 */ /* unmute dac channels */ - codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); + snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0); /* de-emphasis: 48kHz, powedown dac */ - codec->write(codec, AD1938_DAC_CTRL2, 0x1A); + snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A); /* powerdown dac, dac in tdm mode */ - codec->write(codec, AD1938_DAC_CTRL0, 0x41); + snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41); /* high-pass filter enable */ - codec->write(codec, AD1938_ADC_CTRL0, 0x3); + snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3); /* sata delay=1, adc aux mode */ - codec->write(codec, AD1938_ADC_CTRL1, 0x43); + snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43); /* pll input: mclki/xi */ - codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); - codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); - - ad1938_fill_cache(codec); + snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); + snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04); ret = snd_soc_register_codec(codec); if (ret != 0) { diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index cde7b63de113..097e33510a7a 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -233,6 +233,108 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, #define snd_soc_8_16_read_i2c NULL #endif +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + struct i2c_msg xfer[2]; + u16 reg = r; + u8 data; + int ret; + struct i2c_client *client = codec->control_data; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = (u8 *)® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 1; + xfer[1].buf = &data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return data; +} +#else +#define snd_soc_16_8_read_i2c NULL +#endif + +static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + reg &= 0xff; + if (reg >= codec->reg_cache_size) + return -1; + return cache[reg]; +} + +static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[3]; + int ret; + + BUG_ON(codec->volatile_register); + + data[0] = (reg >> 8) & 0xff; + data[1] = reg & 0xff; + data[2] = value; + + reg &= 0xff; + if (reg < codec->reg_cache_size) + cache[reg] = value; + ret = codec->hw_write(codec->control_data, data, 3); + if (ret == 3) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +#if defined(CONFIG_SPI_MASTER) +static int snd_soc_16_8_spi_write(void *control_data, const char *data, + int len) +{ + struct spi_device *spi = control_data; + struct spi_transfer t; + struct spi_message m; + u8 msg[3]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + msg[2] = data[2]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#else +#define snd_soc_16_8_spi_write NULL +#endif + + static struct { int addr_bits; int data_bits; @@ -260,6 +362,12 @@ static struct { .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, .i2c_read = snd_soc_8_16_read_i2c, }, + { + .addr_bits = 16, .data_bits = 8, + .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, + .i2c_read = snd_soc_16_8_read_i2c, + .spi_write = snd_soc_16_8_spi_write, + }, }; /** -- GitLab From 24bfef0f924b4ac4312614422a4982b5f4d9a4c7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 21 Jan 2010 13:04:43 -0200 Subject: [PATCH 1261/3892] perf top: Fix sample counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broken since "5b2bb75 perf top: Support userspace symbols too". Reported-by: Mike Galbraith Tested-by: Mike Galbraith Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264086284-1431-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a8a77ec2c9d..8b049888a9dd 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -934,8 +934,11 @@ static void event__process_sample(const event_t *self, struct addr_location al; u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + ++samples; + switch (origin) { case PERF_RECORD_MISC_USER: + ++userspace_samples; if (hide_user_symbols) return; break; @@ -960,9 +963,6 @@ static void event__process_sample(const event_t *self, if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); pthread_mutex_unlock(&active_symbols_lock); - if (origin == PERF_RECORD_MISC_USER) - ++userspace_samples; - ++samples; } } -- GitLab From 0f35cd4cea08a8893e3e2ea03cbdb65f5d2b0e7a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 21 Jan 2010 13:04:44 -0200 Subject: [PATCH 1262/3892] perf top: Handle PERF_RECORD_{FORK,EXIT} events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As noticed by Mike, symbols in new tasks were not being processed as we weren't processing these events. Reported-by: Mike Galbraith Tested-by: Mike Galbraith Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264086284-1431-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8b049888a9dd..2227b84aa002 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -975,6 +975,10 @@ static int event__process(event_t *event, struct perf_session *session) case PERF_RECORD_MMAP: event__process_mmap(event, session); break; + case PERF_RECORD_FORK: + case PERF_RECORD_EXIT: + event__process_task(event, session); + break; default: break; } -- GitLab From e1c7c6a40c8037478742ce134190c1a955853bfb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jan 2010 14:35:01 -0200 Subject: [PATCH 1263/3892] perf symbols: Fix inverted logic for showing kallsyms as the source of symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only if we parsed /proc/kallsyms (or a copy found in the buildid cache) we should set the dso long name to "[kernel.kallsyms]". Reported-by: Mike Galbraith Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264178102-4203-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 6f30fe18c265..1270cf867e61 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1671,7 +1671,7 @@ do_kallsyms: out_try_fixup: if (err > 0) { out_fixup: - if (kallsyms_filename == NULL) + if (kallsyms_filename != NULL) dso__set_long_name(self, strdup("[kernel.kallsyms]")); map__fixup_start(map); map__fixup_end(map); -- GitLab From 19fc2dedff448120a7aeaa3c136689c6b71777c6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jan 2010 14:35:02 -0200 Subject: [PATCH 1264/3892] perf symbols: Use the right variable to check for kallsyms in the cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Probably this wasn't noticed when testing this on my parisc machine because I must have copied manually to its cache the vmlinux file used in the x86_64 machine, now that I tried looking on a x86-32 machine with a fresh cache, kernel symbols weren't being resolved even with the right kallsyms copy on its cache, duh. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264178102-4203-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1270cf867e61..f1f609dcf9a1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1650,12 +1650,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, getenv("HOME"), sbuild_id) == -1) return -1; + kallsyms_filename = kallsyms_allocated_filename; + if (access(kallsyms_filename, F_OK)) { free(kallsyms_allocated_filename); return -1; } - - kallsyms_filename = kallsyms_allocated_filename; } else { /* * Last resort, if we don't have a build-id and couldn't find -- GitLab From 408f0d18ba6b9bb447f807f621b2c9663c5cf638 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Fri, 22 Jan 2010 22:45:29 +0900 Subject: [PATCH 1265/3892] perf trace: Add -i option for choosing input file perf trace lacks -i option for choosing input file. This patch adds it to perf trace. Signed-off-by: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1264167929-6741-1-git-send-email-mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar --- tools/perf/builtin-trace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8e9cbfe608d6..0b65779e3c10 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -515,6 +515,8 @@ static const struct option options[] = { parse_scriptname), OPT_STRING('g', "gen-script", &generate_script_lang, "lang", "generate perf-trace.xx script in specified language"), + OPT_STRING('i', "input", &input_name, "file", + "input file name"), OPT_END() }; -- GitLab From 08b36c4a02b5a9db609fc6d93b9c41d7fa75713c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 27 Jan 2010 21:56:57 +0900 Subject: [PATCH 1266/3892] sh: Optimize runtime disabling of trapped I/O. Presently trapped I/O is only registered if it's not explicitly disabled for the platforms that select it openly. From the fault path this runs through an address lookup before figuring out that nothing matches and falls back through the error path, but we can forego the lookup completely by testing if it's been explicitly disabled. This provides a measurable speedup for things like qemu that rely on runtime disabling. Signed-off-by: Paul Mundt --- arch/sh/kernel/io_trapped.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 16b83cc89a41..4a8bb4eeb8ad 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -271,6 +271,8 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address) insn_size_t instruction; int tmp; + if (trapped_io_disable) + return 0; if (!lookup_tiop(address)) return 0; -- GitLab From 660e2acad81c19b404f7d7d06e57a6d5e6ce7426 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 27 Jan 2010 22:03:11 +0900 Subject: [PATCH 1267/3892] sh: kmemleak support. Enables support for kmemleak on sh. Signed-off-by: Chris Smith Signed-off-by: Paul Mundt --- arch/sh/kernel/vmlinux.lds.S | 6 +++--- lib/Kconfig.debug | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 93e9b25a1811..f0bc6b886eed 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -50,12 +50,12 @@ SECTIONS } = 0x0009 EXCEPTION_TABLE(16) - NOTES + + _sdata = .; RO_DATA(PAGE_SIZE) RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) - - _edata = .; /* End of data section */ + _edata = .; DWARF_EH_FRAME diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 25c3ed594c54..d62e3cdab357 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -355,7 +355,7 @@ config SLUB_STATS config DEBUG_KMEMLEAK bool "Kernel memory leak detector" depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ - (X86 || ARM || PPC || S390) + (X86 || ARM || PPC || S390 || SUPERH) select DEBUG_FS if SYSFS select STACKTRACE if STACKTRACE_SUPPORT -- GitLab From 7013109f52ff38ad9ea38952cedc144c8e8b9636 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Mon, 25 Jan 2010 16:12:07 +0100 Subject: [PATCH 1268/3892] sh: fixed cmpxchg gRB version This patch fixes a bug within the cmpxchg GRB version. A problem was notices while running some tests to stress the priority inheritance, for example pi_stress (http://rt.wiki.kernel.org/index.php/PI_Mutex_Test). Also, without this patch, after applying the latest work to consolidate atomic_cmpxchg() definitions (commit: 8c0b8139c87cfe8b95c6e763b4ca3190aa9b1ad0) the Kernel doesn't boot at all. Signed-off-by: Giuseppe Cavallaro Signed-off-by: Stuart Menefy Signed-off-by: Paul Mundt --- arch/sh/include/asm/cmpxchg-grb.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/sh/include/asm/cmpxchg-grb.h b/arch/sh/include/asm/cmpxchg-grb.h index e2681abe764f..4676bf57693a 100644 --- a/arch/sh/include/asm/cmpxchg-grb.h +++ b/arch/sh/include/asm/cmpxchg-grb.h @@ -57,11 +57,10 @@ static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, " mov.l @%1, %0 \n\t" /* load old value */ " cmp/eq %0, %2 \n\t" " bf 1f \n\t" /* if not equal */ - " mov.l %2, @%1 \n\t" /* store new value */ + " mov.l %3, @%1 \n\t" /* store new value */ "1: mov r1, r15 \n\t" /* LOGOUT */ - : "=&r" (retval), - "+r" (m) - : "r" (new) + : "=&r" (retval) + : "r" (m), "r" (old), "r" (new) : "memory" , "r0", "r1", "t"); return retval; -- GitLab From 7910b4a1db63fefc3d291853d33c34c5b6352e8e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 27 Jan 2010 18:10:13 +0100 Subject: [PATCH 1269/3892] ALSA: pcm_native - fix runtime->boundary calculation The code in pcm_lib updating runtime->hw_ptr_interrupt expects that runtime->boundary is divisible with runtime->period_size. Thanks are going to Clemens Ladisch for the notice. Fix the runtime->boundary calculation using buffer_size * period_size as base and find a least common multiple for 32bit platforms when the expression might overflow. Signed-off-by: Jaroslav Kysela --- sound/core/pcm_native.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7a002db512b4..9cbaf90d3d88 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) return usecs; } +static int calc_boundary(struct snd_pcm_runtime *runtime) +{ + u_int64_t boundary; + + boundary = (u_int64_t)runtime->buffer_size * + (u_int64_t)runtime->period_size; +#if BITS_PER_LONG < 64 + /* try to find lowest common multiple for buffer and period */ + if (boundary > LONG_MAX - runtime->buffer_size) { + u_int32_t remainder = -1; + u_int32_t divident = runtime->buffer_size; + u_int32_t divisor = runtime->period_size; + while (remainder) { + remainder = divident % divisor; + if (remainder) { + divident = divisor; + divisor = remainder; + } + } + boundary = div_u64(boundary, divisor); + if (boundary > LONG_MAX - runtime->buffer_size) + return -ERANGE; + } +#endif + if (boundary == 0) + return -ERANGE; + runtime->boundary = boundary; + while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) + runtime->boundary *= 2; + return 0; +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->stop_threshold = runtime->buffer_size; runtime->silence_threshold = 0; runtime->silence_size = 0; - runtime->boundary = runtime->buffer_size; - while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) - runtime->boundary *= 2; + err = calc_boundary(runtime); + if (err < 0) + goto _error; snd_pcm_timer_resolution_change(substream); runtime->status->state = SNDRV_PCM_STATE_SETUP; -- GitLab From 47db3a677b533489d1a5a027282aa33f46dffa79 Mon Sep 17 00:00:00 2001 From: Luca Verdesca Date: Tue, 22 Dec 2009 18:10:01 +0100 Subject: [PATCH 1270/3892] ath5k: adding LED support for AR5BXB63 cards With following patch, LED should now work with LiteOn AR5BXB63 mini pci-e cards. (Broken patch fixed-up by me...let's hope I did it right! -- JWL) Signed-off-by: Luca Verdesca Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/led.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 60f547503d75..67aa52e9bf94 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -77,6 +77,8 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) }, /* HP Compaq C700 (nitrousnrg@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) }, + /* LiteOn AR5BXB63 (magooz@salug.it) */ + { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) }, /* IBM-specific AR5212 (all others) */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, /* Dell Vostro A860 (shahar@shahar-or.co.il) */ -- GitLab From d3d5621abf6d2105700795fcbdf784b9cb46b495 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 27 Jan 2010 14:23:17 -0500 Subject: [PATCH 1271/3892] libertas: add comment re: v10 firmware key handling Comment text suggested by Dan Williams in <1263952092.4481.2.camel@localhost.localdomain>. Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 0979b07799a0..f03d5e4e59c3 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -2062,6 +2062,11 @@ void lbs_association_worker(struct work_struct *work) goto out; } + /* + * v10 FW wants WPA keys to be set/cleared before WEP key operations, + * otherwise it will fail to correctly associate to WEP networks. + * Other firmware versions don't appear to care. + */ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); -- GitLab From d2bb8e02810cc5844fe2bd5a81d4058b8afe6de9 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 26 Jan 2010 16:22:20 -0500 Subject: [PATCH 1272/3892] rtl8180: implement get_tsf op for mac80211 Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180_dev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 5a2b7199f5d5..109ab1baf625 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -761,6 +761,14 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); } +static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | + (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; +} + static const struct ieee80211_ops rtl8180_ops = { .tx = rtl8180_tx, .start = rtl8180_start, @@ -771,6 +779,7 @@ static const struct ieee80211_ops rtl8180_ops = { .bss_info_changed = rtl8180_bss_info_changed, .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, + .get_tsf = rtl8180_get_tsf, }; static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) -- GitLab From da8604757b1cdf79f24e118b156349543eb1b722 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 26 Jan 2010 16:42:02 -0600 Subject: [PATCH 1273/3892] b43: N PHY: Fix compilation after removal of typdef b43_c32 In the conversion between typedef and struct, two places that needed a "struct" were missed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index df4bf435e218..8c39fb126d4f 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -822,7 +822,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, { int i; u16 bw, len, rot, angle; - b43_c32 *samples; + struct b43_c32 *samples; bw = (dev->phy.is_40mhz) ? 40 : 20; @@ -840,7 +840,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, len = bw << 1; } - samples = kzalloc(len * sizeof(b43_c32), GFP_KERNEL); + samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL); rot = (((freq * 36) / bw) << 16) / 100; angle = 0; -- GitLab From 22e16e55e36ab91148592c9bf0f2444bf766cd3c Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 26 Jan 2010 17:45:28 -0600 Subject: [PATCH 1274/3892] rtl8187: Add callback for get_tsf Signed-off-by: Larry Finger Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index f336c63053c1..a05382557789 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1265,6 +1265,14 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } +static u64 rtl8187_get_tsf(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + + return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | + (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, .start = rtl8187_start, @@ -1276,7 +1284,8 @@ static const struct ieee80211_ops rtl8187_ops = { .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx, - .rfkill_poll = rtl8187_rfkill_poll + .rfkill_poll = rtl8187_rfkill_poll, + .get_tsf = rtl8187_get_tsf, }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) -- GitLab From 54233261d5aa2926f080b67ac22f508c9f15e690 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 27 Jan 2010 09:44:48 -0500 Subject: [PATCH 1275/3892] cfg80211: fix wext-compat for setting rate to 'auto' Signed-off-by: John W. Linville --- net/wireless/wext-compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 966d2f01beac..b17eeae448d5 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1214,7 +1214,7 @@ int cfg80211_wext_siwrate(struct net_device *dev, memset(&mask, 0, sizeof(mask)); fixed = 0; - maxrate = 0; + maxrate = (u32)-1; if (rate->value < 0) { /* nothing */ -- GitLab From fc93ea2f9315eda2ec8645c2f8bcc30f75a6b88e Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 27 Jan 2010 14:59:08 +0900 Subject: [PATCH 1276/3892] ASoC: AC97: S3C: Add controller driver Add the AC97 controller driver for Samsung SoCs that have one. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 6 +- sound/soc/s3c24xx/Makefile | 3 +- sound/soc/s3c24xx/s3c-ac97.c | 518 +++++++++++++++++++++++++++++++++++ sound/soc/s3c24xx/s3c-ac97.h | 23 ++ 4 files changed, 548 insertions(+), 2 deletions(-) create mode 100644 sound/soc/s3c24xx/s3c-ac97.c create mode 100644 sound/soc/s3c24xx/s3c-ac97.h diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index b489f1ae103d..ad3690ec3de8 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -32,7 +32,11 @@ config SND_S3C2443_SOC_AC97 select S3C2410_DMA select AC97_BUS select SND_SOC_AC97_BUS - + +config SND_S3C_SOC_AC97 + tristate + select SND_SOC_AC97_BUS + config SND_S3C24XX_SOC_NEO1973_WM8753 tristate "SoC I2S Audio support for NEO1973 - WM8753" depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index b744657733d7..b7411bd59f33 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -4,12 +4,14 @@ snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o +snd-soc-s3c-ac97-objs := s3c-ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-s3c-pcm-objs := s3c-pcm.o obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o +obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o @@ -37,4 +39,3 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o - diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c new file mode 100644 index 000000000000..ee8ed9d7e703 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-ac97.c @@ -0,0 +1,518 @@ +/* sound/soc/s3c24xx/s3c-ac97.c + * + * ALSA SoC Audio Layer - S3C AC97 Controller driver + * Evolved from s3c2443-ac97.c + * + * Copyright (c) 2010 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * Credits: Graeme Gregory, Sean Choi + * + * 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 + +#include +#include +#include + +#include "s3c-dma.h" +#include "s3c-ac97.h" + +#define AC_CMD_ADDR(x) (x << 16) +#define AC_CMD_DATA(x) (x & 0xffff) + +struct s3c_ac97_info { + unsigned state; + struct clk *ac97_clk; + void __iomem *regs; + struct mutex lock; + struct completion done; +}; +static struct s3c_ac97_info s3c_ac97; + +static struct s3c2410_dma_client s3c_dma_client_out = { + .name = "AC97 PCMOut" +}; + +static struct s3c2410_dma_client s3c_dma_client_in = { + .name = "AC97 PCMIn" +}; + +static struct s3c2410_dma_client s3c_dma_client_micin = { + .name = "AC97 MicIn" +}; + +static struct s3c_dma_params s3c_ac97_pcm_out = { + .client = &s3c_dma_client_out, + .dma_size = 4, +}; + +static struct s3c_dma_params s3c_ac97_pcm_in = { + .client = &s3c_dma_client_in, + .dma_size = 4, +}; + +static struct s3c_dma_params s3c_ac97_mic_in = { + .client = &s3c_dma_client_micin, + .dma_size = 4, +}; + +static void s3c_ac97_activate(struct snd_ac97 *ac97) +{ + u32 ac_glbctrl, stat; + + stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; + if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) + return; /* Return if already active */ + + INIT_COMPLETION(s3c_ac97.done); + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); + + ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) + printk(KERN_ERR "AC97: Unable to activate!"); +} + +static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + u32 ac_glbctrl, ac_codec_cmd; + u32 stat, addr, data; + + mutex_lock(&s3c_ac97.lock); + + s3c_ac97_activate(ac97); + + INIT_COMPLETION(s3c_ac97.done); + + ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); + ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); + writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); + + udelay(50); + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) + printk(KERN_ERR "AC97: Unable to read!"); + + stat = readl(s3c_ac97.regs + S3C_AC97_STAT); + addr = (stat >> 16) & 0x7f; + data = (stat & 0xffff); + + if (addr != reg) + printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr); + + mutex_unlock(&s3c_ac97.lock); + + return (unsigned short)data; +} + +static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + u32 ac_glbctrl, ac_codec_cmd; + + mutex_lock(&s3c_ac97.lock); + + s3c_ac97_activate(ac97); + + INIT_COMPLETION(s3c_ac97.done); + + ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); + ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); + writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); + + udelay(50); + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) + printk(KERN_ERR "AC97: Unable to write!"); + + ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); + ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; + writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); + + mutex_unlock(&s3c_ac97.lock); +} + +static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) +{ + writel(S3C_AC97_GLBCTRL_COLDRESET, + s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); + + writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); +} + +static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) +{ + u32 stat; + + stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; + if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) + return; /* Return if already active */ + + writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); + + writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); + msleep(1); + + s3c_ac97_activate(ac97); +} + +static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) +{ + u32 ac_glbctrl, ac_glbstat; + + ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); + + if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + complete(&s3c_ac97.done); + } + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl |= (1<<30); /* Clear interrupt */ + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + return IRQ_HANDLED; +} + +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = s3c_ac97_read, + .write = s3c_ac97_write, + .warm_reset = s3c_ac97_warm_reset, + .reset = s3c_ac97_cold_reset, +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + cpu_dai->dma_data = &s3c_ac97_pcm_out; + else + cpu_dai->dma_data = &s3c_ac97_pcm_in; + + return 0; +} + +static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + u32 ac_glbctrl; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channel = ((struct s3c_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; + else + ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; + else + ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + } + + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); + + return 0; +} + +static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return -ENODEV; + else + cpu_dai->dma_data = &s3c_ac97_mic_in; + + return 0; +} + +static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + u32 ac_glbctrl; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channel = ((struct s3c_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; + + ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); + ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + } + + writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); + + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); + + return 0; +} + +static struct snd_soc_dai_ops s3c_ac97_dai_ops = { + .hw_params = s3c_ac97_hw_params, + .trigger = s3c_ac97_trigger, +}; + +static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { + .hw_params = s3c_ac97_hw_mic_params, + .trigger = s3c_ac97_mic_trigger, +}; + +struct snd_soc_dai s3c_ac97_dai[] = { + [S3C_AC97_DAI_PCM] = { + .name = "s3c-ac97", + .id = S3C_AC97_DAI_PCM, + .ac97_control = 1, + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &s3c_ac97_dai_ops, + }, + [S3C_AC97_DAI_MIC] = { + .name = "s3c-ac97-mic", + .id = S3C_AC97_DAI_MIC, + .ac97_control = 1, + .capture = { + .stream_name = "AC97 Mic Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &s3c_ac97_mic_dai_ops, + }, +}; +EXPORT_SYMBOL_GPL(s3c_ac97_dai); + +static __devinit int s3c_ac97_probe(struct platform_device *pdev) +{ + struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; + struct s3c_audio_pdata *ac97_pdata; + int ret; + + ac97_pdata = pdev->dev.platform_data; + if (!ac97_pdata || !ac97_pdata->cfg_gpio) { + dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); + return -EINVAL; + } + + /* Check for availability of necessary resource */ + dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmatx_res) { + dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n"); + return -ENXIO; + } + + dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!dmarx_res) { + dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n"); + return -ENXIO; + } + + dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (!dmamic_res) { + dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n"); + return -ENXIO; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "Unable to get register resource\n"); + return -ENXIO; + } + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_res) { + dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); + return -ENXIO; + } + + if (!request_mem_region(mem_res->start, + resource_size(mem_res), "s3c-ac97")) { + dev_err(&pdev->dev, "Unable to request register region\n"); + return -EBUSY; + } + + s3c_ac97_pcm_out.channel = dmatx_res->start; + s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; + s3c_ac97_pcm_in.channel = dmarx_res->start; + s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; + s3c_ac97_mic_in.channel = dmamic_res->start; + s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; + + init_completion(&s3c_ac97.done); + mutex_init(&s3c_ac97.lock); + + s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); + if (s3c_ac97.regs == NULL) { + dev_err(&pdev->dev, "Unable to ioremap register region\n"); + ret = -ENXIO; + goto err1; + } + + s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); + if (IS_ERR(s3c_ac97.ac97_clk)) { + dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n"); + ret = -ENODEV; + goto err2; + } + clk_enable(s3c_ac97.ac97_clk); + + if (ac97_pdata->cfg_gpio(pdev)) { + dev_err(&pdev->dev, "Unable to configure gpio\n"); + ret = -EINVAL; + goto err3; + } + + ret = request_irq(irq_res->start, s3c_ac97_irq, + IRQF_DISABLED, "AC97", NULL); + if (ret < 0) { + printk(KERN_ERR "s3c-ac97: interrupt request failed.\n"); + goto err4; + } + + s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev; + s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev; + + ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); + if (ret) + goto err5; + + return 0; + +err5: + free_irq(irq_res->start, NULL); +err4: +err3: + clk_disable(s3c_ac97.ac97_clk); + clk_put(s3c_ac97.ac97_clk); +err2: + iounmap(s3c_ac97.regs); +err1: + release_mem_region(mem_res->start, resource_size(mem_res)); + + return ret; +} + +static __devexit int s3c_ac97_remove(struct platform_device *pdev) +{ + struct resource *mem_res, *irq_res; + + snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq_res) + free_irq(irq_res->start, NULL); + + clk_disable(s3c_ac97.ac97_clk); + clk_put(s3c_ac97.ac97_clk); + + iounmap(s3c_ac97.regs); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem_res) + release_mem_region(mem_res->start, resource_size(mem_res)); + + return 0; +} + +static struct platform_driver s3c_ac97_driver = { + .probe = s3c_ac97_probe, + .remove = s3c_ac97_remove, + .driver = { + .name = "s3c-ac97", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c_ac97_init(void) +{ + return platform_driver_register(&s3c_ac97_driver); +} +module_init(s3c_ac97_init); + +static void __exit s3c_ac97_exit(void) +{ + platform_driver_unregister(&s3c_ac97_driver); +} +module_exit(s3c_ac97_exit); + +MODULE_AUTHOR("Jaswinder Singh, "); +MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h new file mode 100644 index 000000000000..278198379def --- /dev/null +++ b/sound/soc/s3c24xx/s3c-ac97.h @@ -0,0 +1,23 @@ +/* sound/soc/s3c24xx/s3c-ac97.h + * + * ALSA SoC Audio Layer - S3C AC97 Controller driver + * Evolved from s3c2443-ac97.h + * + * Copyright (c) 2010 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * Credits: Graeme Gregory, Sean Choi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __S3C_AC97_H_ +#define __S3C_AC97_H_ + +#define S3C_AC97_DAI_PCM 0 +#define S3C_AC97_DAI_MIC 1 + +extern struct snd_soc_dai s3c_ac97_dai[]; + +#endif /* __S3C_AC97_H_ */ -- GitLab From ff6e64dabf66b8e4e7def21857320085fc68db6b Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 27 Jan 2010 14:59:19 +0900 Subject: [PATCH 1277/3892] ASoC: AC97: SMDK: Add wm9713 machine driver This patch adds the common machine driver for SMDKs that have a WM9713 codec attched to the AC97 controller. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 8 +++ sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/smdk_wm9713.c | 97 +++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 sound/soc/s3c24xx/smdk_wm9713.c diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index ad3690ec3de8..d1c6f9392463 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -115,3 +115,11 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES select SND_S3C24XX_SOC_I2S select SND_SOC_TLV320AIC3X select SND_S3C24XX_SOC_SIMTEC + +config SND_SOC_SMDK_WM9713 + tristate "SoC AC97 Audio support for SMDK with WM9713" + depends on SND_S3C24XX_SOC && MACH_SMDK6410 + select SND_SOC_WM9713 + select SND_S3C_SOC_AC97 + help + Sat Y if you want to add support for SoC audio on the SMDK. diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index b7411bd59f33..1117678ae4e1 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -28,6 +28,7 @@ snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o +snd-soc-smdk-wm9713-objs := smdk_wm9713.o obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -39,3 +40,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o +obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c new file mode 100644 index 000000000000..7dd933f7cbf9 --- /dev/null +++ b/sound/soc/s3c24xx/smdk_wm9713.c @@ -0,0 +1,97 @@ +/* + * smdk_wm9713.c -- SoC audio for SMDK + * + * Copyright 2010 Samsung Electronics Co. Ltd. + * Author: Jaswinder Singh Brar + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + */ + +#include +#include +#include + +#include "../codecs/wm9713.h" +#include "s3c-dma.h" +#include "s3c-ac97.h" + +static struct snd_soc_card smdk; + +/* + Playback (HeadPhone):- + Headphone Playback Switch - On + $ amixer cset numid=4 1 + + Right Headphone Out Mux - Headphone + $ amixer cset numid=92 2 + Left Headphone Out Mux - Headphone + $ amixer cset numid=93 2 + + Right HP Mixer PCM Playback Switch - On + $ amixer cset numid=75 1 + Left HP Mixer PCM Playback Switch - On + $ amixer cset numid=81 1 + + Capture (LineIn):- + Right Capture Source - Line + $ amixer cset numid=86 2 + Left Capture Source - Line + $ amixer cset numid=87 2 +*/ + +static struct snd_soc_dai_link smdk_dai = { + .name = "AC97", + .stream_name = "AC97 PCM", + .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], + .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], +}; + +static struct snd_soc_card smdk = { + .name = "SMDK", + .platform = &s3c24xx_soc_platform, + .dai_link = &smdk_dai, + .num_links = 1, +}; + +static struct snd_soc_device smdk_snd_ac97_devdata = { + .card = &smdk, + .codec_dev = &soc_codec_dev_wm9713, +}; + +static struct platform_device *smdk_snd_ac97_device; + +static int __init smdk_init(void) +{ + int ret; + + smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1); + if (!smdk_snd_ac97_device) + return -ENOMEM; + + platform_set_drvdata(smdk_snd_ac97_device, + &smdk_snd_ac97_devdata); + smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev; + + ret = platform_device_add(smdk_snd_ac97_device); + if (ret) + platform_device_put(smdk_snd_ac97_device); + + return ret; +} + +static void __exit smdk_exit(void) +{ + platform_device_unregister(smdk_snd_ac97_device); +} + +module_init(smdk_init); +module_exit(smdk_exit); + +/* Module information */ +MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com"); +MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); +MODULE_LICENSE("GPL"); -- GitLab From 1ec2963a8cd5fbc5f49dfa20c94229f1b46d1968 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 27 Jan 2010 15:01:03 +0900 Subject: [PATCH 1278/3892] ASoC: AC97: SMDK2443: Switch to s3c-ac97.c Switch to use s3c-ac97.c AC97 controller driver. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 4 +++- sound/soc/s3c24xx/smdk2443_wm9710.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index d1c6f9392463..8b62798a04b8 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -75,8 +75,10 @@ config SND_S3C64XX_SOC_WM8580 config SND_S3C24XX_SOC_SMDK2443_WM9710 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" depends on SND_S3C24XX_SOC && MACH_SMDK2443 - select SND_S3C2443_SOC_AC97 + select S3C2410_DMA + select AC97_BUS select SND_SOC_AC97_CODEC + select SND_S3C_SOC_AC97 help Say Y if you want to add support for SoC audio on smdk2443 with the WM9710. diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 12b783b12fcb..362258835e8d 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -21,7 +21,7 @@ #include "../codecs/ac97.h" #include "s3c-dma.h" -#include "s3c24xx-ac97.h" +#include "s3c-ac97.h" static struct snd_soc_card smdk2443; @@ -29,7 +29,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = { { .name = "AC97", .stream_name = "AC97 HiFi", - .cpu_dai = &s3c2443_ac97_dai[0], + .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], .codec_dai = &ac97_dai, }, }; -- GitLab From c67d90ffd43a6cf18def21a0de7db56504d78295 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 27 Jan 2010 15:02:04 +0900 Subject: [PATCH 1279/3892] ASoC: AC97: LN2440SBC: Switch to s3c-ac97.c Switch to use s3c-ac97.c AC97 controller driver. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 7 +++---- sound/soc/s3c24xx/ln2440sbc_alc650.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 8b62798a04b8..69d143e3ab25 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -29,9 +29,6 @@ config SND_S3C_SOC_PCM config SND_S3C2443_SOC_AC97 tristate - select S3C2410_DMA - select AC97_BUS - select SND_SOC_AC97_BUS config SND_S3C_SOC_AC97 tristate @@ -86,8 +83,10 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710 config SND_S3C24XX_SOC_LN2440SBC_ALC650 tristate "SoC AC97 Audio support for LN2440SBC - ALC650" depends on SND_S3C24XX_SOC && ARCH_S3C2410 - select SND_S3C2443_SOC_AC97 + select S3C2410_DMA + select AC97_BUS select SND_SOC_AC97_CODEC + select SND_S3C_SOC_AC97 help Say Y if you want to add support for SoC audio on ln2440sbc with the ALC650. diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index d00d359a03e6..ffa954fe6931 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -25,7 +25,7 @@ #include "../codecs/ac97.h" #include "s3c-dma.h" -#include "s3c24xx-ac97.h" +#include "s3c-ac97.h" static struct snd_soc_card ln2440sbc; @@ -33,7 +33,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { { .name = "AC97", .stream_name = "AC97 HiFi", - .cpu_dai = &s3c2443_ac97_dai[0], + .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM], .codec_dai = &ac97_dai, }, }; -- GitLab From 7beba4d50d5f70c3851f608927882959d532671c Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 27 Jan 2010 15:04:36 +0900 Subject: [PATCH 1280/3892] ASoC: AC97: S3C2443: Remove unused driver Since, we have generic AC97 controller driver and all the machines have moved to that, there is no need for old s3c2443-ac97.c to exist. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 3 - sound/soc/s3c24xx/Makefile | 2 - sound/soc/s3c24xx/s3c2443-ac97.c | 432 ------------------------------- sound/soc/s3c24xx/s3c24xx-ac97.h | 25 -- 4 files changed, 462 deletions(-) delete mode 100644 sound/soc/s3c24xx/s3c2443-ac97.c delete mode 100644 sound/soc/s3c24xx/s3c24xx-ac97.h diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 69d143e3ab25..15fe57e5a232 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -27,9 +27,6 @@ config SND_S3C64XX_SOC_I2S config SND_S3C_SOC_PCM tristate -config SND_S3C2443_SOC_AC97 - tristate - config SND_S3C_SOC_AC97 tristate select SND_SOC_AC97_BUS diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 1117678ae4e1..df071a376fa2 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -3,14 +3,12 @@ snd-soc-s3c24xx-objs := s3c-dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o -snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o snd-soc-s3c-ac97-objs := s3c-ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-s3c-pcm-objs := s3c-pcm.o obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o -obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c deleted file mode 100644 index 0191e3acb0b4..000000000000 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * s3c2443-ac97.c -- ALSA Soc Audio Layer - * - * (c) 2007 Wolfson Microelectronics PLC. - * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * Copyright (C) 2005, Sean Choi - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "s3c-dma.h" -#include "s3c24xx-ac97.h" - -struct s3c24xx_ac97_info { - void __iomem *regs; - struct clk *ac97_clk; -}; -static struct s3c24xx_ac97_info s3c24xx_ac97; - -static DECLARE_COMPLETION(ac97_completion); -static u32 codec_ready; -static DEFINE_MUTEX(ac97_mutex); - -static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - u32 ac_glbctrl; - u32 ac_codec_cmd; - u32 stat, addr, data; - - mutex_lock(&ac97_mutex); - - codec_ready = S3C_AC97_GLBSTAT_CODECREADY; - ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); - writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - - wait_for_completion(&ac97_completion); - - stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT); - addr = (stat >> 16) & 0x7f; - data = (stat & 0xffff); - - if (addr != reg) - printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," - " rep addr = %02x\n", reg, addr); - - mutex_unlock(&ac97_mutex); - - return (unsigned short)data; -} - -static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - u32 ac_glbctrl; - u32 ac_codec_cmd; - - mutex_lock(&ac97_mutex); - - codec_ready = S3C_AC97_GLBSTAT_CODECREADY; - ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); - writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - - wait_for_completion(&ac97_completion); - - ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; - writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - - mutex_unlock(&ac97_mutex); - -} - -static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = 0; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); -} - -static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = 0; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA | - S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); -} - -static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id) -{ - int status; - u32 ac_glbctrl; - - status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready; - - if (status) { - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - complete(&ac97_completion); - } - return IRQ_HANDLED; -} - -struct snd_ac97_bus_ops soc_ac97_ops = { - .read = s3c2443_ac97_read, - .write = s3c2443_ac97_write, - .warm_reset = s3c2443_ac97_warm_reset, - .reset = s3c2443_ac97_cold_reset, -}; - -static struct s3c2410_dma_client s3c2443_dma_client_out = { - .name = "AC97 PCM Stereo out" -}; - -static struct s3c2410_dma_client s3c2443_dma_client_in = { - .name = "AC97 PCM Stereo in" -}; - -static struct s3c2410_dma_client s3c2443_dma_client_micin = { - .name = "AC97 Mic Mono in" -}; - -static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = { - .client = &s3c2443_dma_client_out, - .channel = DMACH_PCM_OUT, - .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, - .dma_size = 4, -}; - -static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = { - .client = &s3c2443_dma_client_in, - .channel = DMACH_PCM_IN, - .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, - .dma_size = 4, -}; - -static struct s3c_dma_params s3c2443_ac97_mic_mono_in = { - .client = &s3c2443_dma_client_micin, - .channel = DMACH_MIC_IN, - .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, - .dma_size = 4, -}; - -static int s3c2443_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - int ret; - u32 ac_glbctrl; - - s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100); - if (s3c24xx_ac97.regs == NULL) - return -ENXIO; - - s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); - if (s3c24xx_ac97.ac97_clk == NULL) { - printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n"); - iounmap(s3c24xx_ac97.regs); - return -ENODEV; - } - clk_enable(s3c24xx_ac97.ac97_clk); - - s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET); - s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC); - s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI); - s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO); - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = 0; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - - ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq, - IRQF_DISABLED, "AC97", NULL); - if (ret < 0) { - printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n"); - clk_disable(s3c24xx_ac97.ac97_clk); - clk_put(s3c24xx_ac97.ac97_clk); - iounmap(s3c24xx_ac97.regs); - } - return ret; -} - -static void s3c2443_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - free_irq(IRQ_S3C244x_AC97, NULL); - clk_disable(s3c24xx_ac97.ac97_clk); - clk_put(s3c24xx_ac97.ac97_clk); - iounmap(s3c24xx_ac97.regs); -} - -static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; - else - cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in; - - return 0; -} - -static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; - else - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; - else - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; - break; - } - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - - s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); - - return 0; -} - -static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return -ENODEV; - else - cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in; - - return 0; -} - -static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; - - ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; - } - writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); - - s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); - - return 0; -} - -#define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = { - .hw_params = s3c2443_ac97_hw_params, - .trigger = s3c2443_ac97_trigger, -}; - -static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = { - .hw_params = s3c2443_ac97_hw_mic_params, - .trigger = s3c2443_ac97_mic_trigger, -}; - -struct snd_soc_dai s3c2443_ac97_dai[] = { -{ - .name = "s3c2443-ac97", - .id = 0, - .ac97_control = 1, - .probe = s3c2443_ac97_probe, - .remove = s3c2443_ac97_remove, - .playback = { - .stream_name = "AC97 Playback", - .channels_min = 2, - .channels_max = 2, - .rates = s3c2443_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "AC97 Capture", - .channels_min = 2, - .channels_max = 2, - .rates = s3c2443_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = &s3c2443_ac97_dai_ops, -}, -{ - .name = "pxa2xx-ac97-mic", - .id = 1, - .ac97_control = 1, - .capture = { - .stream_name = "AC97 Mic Capture", - .channels_min = 1, - .channels_max = 1, - .rates = s3c2443_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = &s3c2443_ac97_mic_dai_ops, -}, -}; -EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -static int __init s3c2443_ac97_init(void) -{ - return snd_soc_register_dais(s3c2443_ac97_dai, - ARRAY_SIZE(s3c2443_ac97_dai)); -} -module_init(s3c2443_ac97_init); - -static void __exit s3c2443_ac97_exit(void) -{ - snd_soc_unregister_dais(s3c2443_ac97_dai, - ARRAY_SIZE(s3c2443_ac97_dai)); -} -module_exit(s3c2443_ac97_exit); - - -MODULE_AUTHOR("Graeme Gregory"); -MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h deleted file mode 100644 index e96f941a810b..000000000000 --- a/sound/soc/s3c24xx/s3c24xx-ac97.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * s3c24xx-ac97.c -- ALSA Soc Audio Layer - * - * (c) 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Revision history - * 10th Nov 2006 Initial version. - */ - -#ifndef S3C24XXAC97_H_ -#define S3C24XXAC97_H_ - -#define AC_CMD_ADDR(x) (x << 16) -#define AC_CMD_DATA(x) (x & 0xffff) - -extern struct snd_soc_dai s3c2443_ac97_dai[]; - -#endif /*S3C24XXAC97_H_*/ -- GitLab From 583b2be626b047eeb4f9a26721e38fe4992b2d02 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Jan 2010 20:54:13 +0000 Subject: [PATCH 1281/3892] ASoC: Note jumper settings for smdk_wm9713 driver on SMDK6410 The board supports both GPIO sets for the AC97 bus and the analogue outputs can be switched between this and the WM8580 so add some comments saying what the setup the standard kernel expects is. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk_wm9713.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c index 7dd933f7cbf9..6fa2c9d17d7a 100644 --- a/sound/soc/s3c24xx/smdk_wm9713.c +++ b/sound/soc/s3c24xx/smdk_wm9713.c @@ -21,6 +21,12 @@ static struct snd_soc_card smdk; +/* + * Default CFG switch settings to use this driver: + * + * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off + */ + /* Playback (HeadPhone):- Headphone Playback Switch - On -- GitLab From 0d34e91596ef537c2893a031f0483014bb82adf3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jan 2010 18:56:23 +0100 Subject: [PATCH 1282/3892] ASoC: add a WM8978 codec driver The WM8978 codec from Wolfson Microelectronics is very similar to wm8974, but is stereo and also has some differences in pin configuration and internal signal routing. This driver is based on wm8974 and takes the differences into account. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8978.c | 1124 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8978.h | 89 +++ 4 files changed, 1219 insertions(+) create mode 100644 sound/soc/codecs/wm8978.c create mode 100644 sound/soc/codecs/wm8978.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 62ff26a08a2f..0aad72fc1961 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8961 if I2C select SND_SOC_WM8971 if I2C select SND_SOC_WM8974 if I2C + select SND_SOC_WM8978 if I2C select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C select SND_SOC_WM8993 if I2C @@ -230,6 +231,9 @@ config SND_SOC_WM8971 config SND_SOC_WM8974 tristate +config SND_SOC_WM8978 + tristate + config SND_SOC_WM8988 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ea9835412e6a..fbd290e41e9e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -44,6 +44,7 @@ snd-soc-wm8960-objs := wm8960.o snd-soc-wm8961-objs := wm8961.o snd-soc-wm8971-objs := wm8971.o snd-soc-wm8974-objs := wm8974.o +snd-soc-wm8978-objs := wm8978.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o snd-soc-wm8993-objs := wm8993.o @@ -103,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o +obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c new file mode 100644 index 000000000000..d9d4e9dd1adb --- /dev/null +++ b/sound/soc/codecs/wm8978.c @@ -0,0 +1,1124 @@ +/* + * wm8978.c -- WM8978 ALSA SoC Audio Codec driver + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * Copyright (C) 2007 Carlos Munoz + * Copyright 2006-2009 Wolfson Microelectronics PLC. + * Based on wm8974 and wm8990 by Liam Girdwood + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8978.h" + +static struct snd_soc_codec *wm8978_codec; + +/* wm8978 register cache. Note that register 0 is not included in the cache. */ +static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { + 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */ + 0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */ + 0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */ + 0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */ + 0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */ + 0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */ + 0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */ + 0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */ + 0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */ + 0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */ + 0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */ + 0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */ + 0x0001, 0x0001, /* 0x38...0x3b */ +}; + +/* codec private data */ +struct wm8978_priv { + struct snd_soc_codec codec; + unsigned int f_pllout; + unsigned int f_mclk; + unsigned int f_256fs; + unsigned int f_opclk; + enum wm8978_sysclk_src sysclk; + u16 reg_cache[WM8978_CACHEREGNUM]; +}; + +static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"}; +static const char *wm8978_eqmode[] = {"Capture", "Playback"}; +static const char *wm8978_bw[] = {"Narrow", "Wide"}; +static const char *wm8978_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz"}; +static const char *wm8978_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz"}; +static const char *wm8978_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz"}; +static const char *wm8978_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"}; +static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"}; +static const char *wm8978_alc3[] = {"ALC", "Limiter"}; +static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; + +static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, + wm8978_companding); +static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, + wm8978_companding); +static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); +static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); +static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); +static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); +static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); +static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); +static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); +static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); +static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); +static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); +static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); + +static const struct snd_kcontrol_new wm8978_snd_controls[] = { + + SOC_SINGLE("Digital Loopback Switch", + WM8978_COMPANDING_CONTROL, 0, 1, 0), + + SOC_ENUM("ADC Companding", adc_compand), + SOC_ENUM("DAC Companding", dac_compand), + + SOC_DOUBLE("DAC Inversion Switch", WM8978_DAC_CONTROL, 0, 1, 1, 0), + + SOC_DOUBLE_R_TLV("PCM Volume", + WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME, + 0, 255, 0, digital_tlv), + + SOC_SINGLE("High Pass Filter Switch", WM8978_ADC_CONTROL, 8, 1, 0), + SOC_SINGLE("High Pass Cut Off", WM8978_ADC_CONTROL, 4, 7, 0), + SOC_DOUBLE("ADC Inversion Switch", WM8978_ADC_CONTROL, 0, 1, 1, 0), + + SOC_DOUBLE_R_TLV("ADC Volume", + WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME, + 0, 255, 0, digital_tlv), + + SOC_ENUM("Equaliser Function", eqmode), + SOC_ENUM("EQ1 Cut Off", eq1), + SOC_SINGLE_TLV("EQ1 Volume", WM8978_EQ1, 0, 24, 1, eq_tlv), + + SOC_ENUM("Equaliser EQ2 Bandwith", eq2bw), + SOC_ENUM("EQ2 Cut Off", eq2), + SOC_SINGLE_TLV("EQ2 Volume", WM8978_EQ2, 0, 24, 1, eq_tlv), + + SOC_ENUM("Equaliser EQ3 Bandwith", eq3bw), + SOC_ENUM("EQ3 Cut Off", eq3), + SOC_SINGLE_TLV("EQ3 Volume", WM8978_EQ3, 0, 24, 1, eq_tlv), + + SOC_ENUM("Equaliser EQ4 Bandwith", eq4bw), + SOC_ENUM("EQ4 Cut Off", eq4), + SOC_SINGLE_TLV("EQ4 Volume", WM8978_EQ4, 0, 24, 1, eq_tlv), + + SOC_ENUM("EQ5 Cut Off", eq5), + SOC_SINGLE_TLV("EQ5 Volume", WM8978_EQ5, 0, 24, 1, eq_tlv), + + SOC_SINGLE("DAC Playback Limiter Switch", + WM8978_DAC_LIMITER_1, 8, 1, 0), + SOC_SINGLE("DAC Playback Limiter Decay", + WM8978_DAC_LIMITER_1, 4, 15, 0), + SOC_SINGLE("DAC Playback Limiter Attack", + WM8978_DAC_LIMITER_1, 0, 15, 0), + + SOC_SINGLE("DAC Playback Limiter Threshold", + WM8978_DAC_LIMITER_2, 4, 7, 0), + SOC_SINGLE("DAC Playback Limiter Boost", + WM8978_DAC_LIMITER_2, 0, 15, 0), + + SOC_ENUM("ALC Enable Switch", alc1), + SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0), + SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0), + + SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 7, 0), + SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0), + + SOC_ENUM("ALC Capture Mode", alc3), + SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 15, 0), + SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 15, 0), + + SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0), + SOC_SINGLE("ALC Capture Noise Gate Threshold", + WM8978_NOISE_GATE, 0, 7, 0), + + SOC_DOUBLE_R("Capture PGA ZC Switch", + WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, + 7, 1, 0), + + /* OUT1 - Headphones */ + SOC_DOUBLE_R("Headphone Playback ZC Switch", + WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0), + + SOC_DOUBLE_R_TLV("Headphone Playback Volume", + WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, + 0, 63, 0, spk_tlv), + + /* OUT2 - Speakers */ + SOC_DOUBLE_R("Speaker Playback ZC Switch", + WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0), + + SOC_DOUBLE_R_TLV("Speaker Playback Volume", + WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, + 0, 63, 0, spk_tlv), + + /* OUT3/4 - Line Output */ + SOC_DOUBLE_R("Line Playback Switch", + WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1), + + /* Mixer #3: Boost (Input) mixer */ + SOC_DOUBLE_R("PGA Boost (+20dB)", + WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, + 8, 1, 0), + SOC_DOUBLE_R_TLV("L2/R2 Boost Volume", + WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, + 4, 7, 0, boost_tlv), + SOC_DOUBLE_R_TLV("Aux Boost Volume", + WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, + 0, 7, 0, boost_tlv), + + /* Input PGA volume */ + SOC_DOUBLE_R_TLV("Input PGA Volume", + WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, + 0, 63, 0, inpga_tlv), + + /* Headphone */ + SOC_DOUBLE_R("Headphone Switch", + WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1), + + /* Speaker */ + SOC_DOUBLE_R("Speaker Switch", + WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1), +}; + +/* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */ +static const struct snd_kcontrol_new wm8978_left_out_mixer[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_LEFT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_LEFT_MIXER_CONTROL, 0, 1, 0), +}; + +static const struct snd_kcontrol_new wm8978_right_out_mixer[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0), +}; + +/* OUT3/OUT4 Mixer not implemented */ + +/* Mixer #2: Input PGA Mute */ +static const struct snd_kcontrol_new wm8978_left_input_mixer[] = { + SOC_DAPM_SINGLE("L2 Switch", WM8978_INPUT_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 0, 1, 0), +}; +static const struct snd_kcontrol_new wm8978_right_input_mixer[] = { + SOC_DAPM_SINGLE("R2 Switch", WM8978_INPUT_CONTROL, 6, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = { + SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", + WM8978_POWER_MANAGEMENT_3, 0, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", + WM8978_POWER_MANAGEMENT_3, 1, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", + WM8978_POWER_MANAGEMENT_2, 0, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", + WM8978_POWER_MANAGEMENT_2, 1, 0), + + /* Mixer #1: OUT1,2 */ + SOC_MIXER_ARRAY("Left Output Mixer", WM8978_POWER_MANAGEMENT_3, + 2, 0, wm8978_left_out_mixer), + SOC_MIXER_ARRAY("Right Output Mixer", WM8978_POWER_MANAGEMENT_3, + 3, 0, wm8978_right_out_mixer), + + SOC_MIXER_ARRAY("Left Input Mixer", WM8978_POWER_MANAGEMENT_2, + 2, 0, wm8978_left_input_mixer), + SOC_MIXER_ARRAY("Right Input Mixer", WM8978_POWER_MANAGEMENT_2, + 3, 0, wm8978_right_input_mixer), + + SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2, + 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2, + 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Capture PGA", WM8978_LEFT_INP_PGA_CONTROL, + 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Capture PGA", WM8978_RIGHT_INP_PGA_CONTROL, + 6, 1, NULL, 0), + + SND_SOC_DAPM_PGA("Left Headphone Out", WM8978_POWER_MANAGEMENT_2, + 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Headphone Out", WM8978_POWER_MANAGEMENT_2, + 8, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Speaker Out", WM8978_POWER_MANAGEMENT_3, + 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Speaker Out", WM8978_POWER_MANAGEMENT_3, + 5, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("OUT4 VMID", WM8978_POWER_MANAGEMENT_3, + 8, 0, NULL, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8978_POWER_MANAGEMENT_1, 4, 0), + + SND_SOC_DAPM_INPUT("LMICN"), + SND_SOC_DAPM_INPUT("LMICP"), + SND_SOC_DAPM_INPUT("RMICN"), + SND_SOC_DAPM_INPUT("RMICP"), + SND_SOC_DAPM_INPUT("LAUX"), + SND_SOC_DAPM_INPUT("RAUX"), + SND_SOC_DAPM_INPUT("L2"), + SND_SOC_DAPM_INPUT("R2"), + SND_SOC_DAPM_OUTPUT("LHP"), + SND_SOC_DAPM_OUTPUT("RHP"), + SND_SOC_DAPM_OUTPUT("LSPK"), + SND_SOC_DAPM_OUTPUT("RSPK"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Output mixer */ + {"Right Output Mixer", "PCM Playback Switch", "Right DAC"}, + {"Right Output Mixer", "Aux Playback Switch", "RAUX"}, + {"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"}, + + {"Left Output Mixer", "PCM Playback Switch", "Left DAC"}, + {"Left Output Mixer", "Aux Playback Switch", "LAUX"}, + {"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"}, + + /* Outputs */ + {"Right Headphone Out", NULL, "Right Output Mixer"}, + {"RHP", NULL, "Right Headphone Out"}, + + {"Left Headphone Out", NULL, "Left Output Mixer"}, + {"LHP", NULL, "Left Headphone Out"}, + + {"Right Speaker Out", NULL, "Right Output Mixer"}, + {"RSPK", NULL, "Right Speaker Out"}, + + {"Left Speaker Out", NULL, "Left Output Mixer"}, + {"LSPK", NULL, "Left Speaker Out"}, + + /* Boost Mixer */ + {"Right ADC", NULL, "Right Boost Mixer"}, + + {"Right Boost Mixer", NULL, "RAUX"}, + {"Right Boost Mixer", NULL, "Right Capture PGA"}, + {"Right Boost Mixer", NULL, "R2"}, + + {"Left ADC", NULL, "Left Boost Mixer"}, + + {"Left Boost Mixer", NULL, "LAUX"}, + {"Left Boost Mixer", NULL, "Left Capture PGA"}, + {"Left Boost Mixer", NULL, "L2"}, + + /* Input PGA */ + {"Right Capture PGA", NULL, "Right Input Mixer"}, + {"Left Capture PGA", NULL, "Left Input Mixer"}, + + {"Right Input Mixer", "R2 Switch", "R2"}, + {"Right Input Mixer", "MicN Switch", "RMICN"}, + {"Right Input Mixer", "MicP Switch", "RMICP"}, + + {"Left Input Mixer", "L2 Switch", "L2"}, + {"Left Input Mixer", "MicN Switch", "LMICN"}, + {"Left Input Mixer", "MicP Switch", "LMICP"}, +}; + +static int wm8978_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8978_dapm_widgets, + ARRAY_SIZE(wm8978_dapm_widgets)); + + /* set up the WM8978 audio map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + return 0; +} + +/* PLL divisors */ +struct wm8978_pll_div { + u32 k; + u8 n; + u8 div2; +}; + +#define FIXED_PLL_SIZE (1 << 24) + +static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, + unsigned int source) +{ + u64 k_part; + unsigned int k, n_div, n_mod; + + n_div = target / source; + if (n_div < 6) { + source >>= 1; + pll_div->div2 = 1; + n_div = target / source; + } else { + pll_div->div2 = 0; + } + + if (n_div < 6 || n_div > 12) + dev_warn(wm8978_codec->dev, + "WM8978 N value exceeds recommended range! N = %u\n", + n_div); + + pll_div->n = n_div; + n_mod = target - source * n_div; + k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2; + + do_div(k_part, source); + + k = k_part & 0xFFFFFFFF; + + pll_div->k = k; +} +/* + * Calculate internal frequencies and dividers, according to Figure 40 + * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6 + */ +static int wm8978_configure_pll(struct snd_soc_codec *codec) +{ + struct wm8978_priv *wm8978 = codec->private_data; + struct wm8978_pll_div pll_div; + unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk, + f_256fs = wm8978->f_256fs; + unsigned int f2, opclk_div; + + if (!f_mclk) + return -EINVAL; + + if (f_opclk) { + /* + * The user needs OPCLK. Choose OPCLKDIV to put + * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4. + * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where + * prescale = 1, or prescale = 2. Prescale is calculated inside + * pll_factors(). We have to select f_PLLOUT, such that + * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be + * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4. + */ + if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk) + return -EINVAL; + + if (4 * f_opclk < 3 * f_mclk) + /* Have to use OPCLKDIV */ + opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk; + else + opclk_div = 1; + + dev_dbg(codec->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div); + + snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 0x30, + (opclk_div - 1) << 4); + + wm8978->f_pllout = f_opclk * opclk_div; + } else if (f_256fs) { + /* + * Not using OPCLK, choose R: + * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12. + * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where + * prescale = 1, or prescale = 2. Prescale is calculated inside + * pll_factors(). We have to select f_PLLOUT, such that + * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be + * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK + * must be 3.781MHz <= f_MCLK <= 32.768MHz + */ + if (48 * f_256fs < 3 * f_mclk || 4 * f_256fs >= 13 * f_mclk) + return -EINVAL; + + /* + * MCLKDIV will be selected in .hw_params(), just choose a + * suitable f_PLLOUT + */ + if (4 * f_256fs < 3 * f_mclk) + /* Will have to use MCLKDIV */ + wm8978->f_pllout = wm8978->f_mclk * 3 / 4; + else + wm8978->f_pllout = f_256fs; + + /* GPIO1 into default mode as input - before configuring PLL */ + snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); + } else { + return -EINVAL; + } + + f2 = wm8978->f_pllout * 4; + + dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__, + wm8978->f_mclk, wm8978->f_pllout); + + pll_factors(&pll_div, f2, wm8978->f_mclk); + + dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n", + __func__, pll_div.n, pll_div.k, pll_div.div2); + + /* Turn PLL off for configuration... */ + snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0); + + snd_soc_write(codec, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n); + snd_soc_write(codec, WM8978_PLL_K1, pll_div.k >> 18); + snd_soc_write(codec, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8978_PLL_K3, pll_div.k & 0x1ff); + + /* ...and on again */ + snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20); + + if (f_opclk) + /* Output PLL (OPCLK) to GPIO1 */ + snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 4); + + return 0; +} + +/* + * Configure WM8978 clock dividers. + */ +static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai, + int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8978_priv *wm8978 = codec->private_data; + int ret = 0; + + switch (div_id) { + case WM8978_OPCLKRATE: + wm8978->f_opclk = div; + + if (wm8978->f_mclk) + ret = wm8978_configure_pll(codec); + break; + case WM8978_MCLKDIV: + if (div & ~0xe0) + return -EINVAL; + snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, div); + break; + case WM8978_ADCCLK: + if (div & ~8) + return -EINVAL; + snd_soc_update_bits(codec, WM8978_ADC_CONTROL, 8, div); + break; + case WM8978_DACCLK: + if (div & ~8) + return -EINVAL; + snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 8, div); + break; + case WM8978_BCLKDIV: + if (div & ~0x1c) + return -EINVAL; + snd_soc_update_bits(codec, WM8978_CLOCKING, 0x1c, div); + break; + default: + return -EINVAL; + } + + dev_dbg(codec->dev, "%s: ID %d, value %u\n", __func__, div_id, div); + + return ret; +} + +/* + * @freq: when .set_pll() us not used, freq is codec MCLK input frequency + */ +static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8978_priv *wm8978 = codec->private_data; + int ret = 0; + + dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq); + + if (freq) { + wm8978->f_mclk = freq; + + /* Even if MCLK is used for system clock, might have to drive OPCLK */ + if (wm8978->f_opclk) + ret = wm8978_configure_pll(codec); + + /* Our sysclk is fixed to 256 * fs, will configure in .hw_params() */ + + if (!ret) + wm8978->sysclk = clk_id; + } + + if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) { + /* Clock CODEC directly from MCLK */ + snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0); + + /* GPIO1 into default mode as input - before configuring PLL */ + snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); + + /* Turn off PLL */ + snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0); + wm8978->sysclk = WM8978_MCLK; + wm8978->f_pllout = 0; + wm8978->f_opclk = 0; + } + + return ret; +} + +/* + * Set ADC and Voice DAC format. + */ +static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + /* + * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80, + * Data Format mask = 0x18: all will be calculated anew + */ + u16 iface = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x198; + u16 clk = snd_soc_read(codec, WM8978_CLOCKING); + + dev_dbg(codec->dev, "%s\n", __func__); + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + clk |= 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + clk &= ~1; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x8; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x18; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x180; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x100; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x80; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface); + snd_soc_write(codec, WM8978_CLOCKING, clk); + + return 0; +} + +/* MCLK dividers */ +static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12}; +static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1}; + +/* + * Set PCM DAI bit size and sample rate. + */ +static int wm8978_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8978_priv *wm8978 = codec->private_data; + /* Word length mask = 0x60 */ + u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60; + /* Sampling rate mask = 0xe (for filters) */ + u16 add_ctl = snd_soc_read(codec, WM8978_ADDITIONAL_CONTROL) & ~0xe; + u16 clking = snd_soc_read(codec, WM8978_CLOCKING); + enum wm8978_sysclk_src current_clk_id = clking & 0x100 ? + WM8978_PLL : WM8978_MCLK; + unsigned int f_sel, diff, diff_best = INT_MAX; + int i, best = 0; + + if (!wm8978->f_mclk) + return -EINVAL; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface_ctl |= 0x20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface_ctl |= 0x40; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface_ctl |= 0x60; + break; + } + + /* filter coefficient */ + switch (params_rate(params)) { + case 8000: + add_ctl |= 0x5 << 1; + break; + case 11025: + add_ctl |= 0x4 << 1; + break; + case 16000: + add_ctl |= 0x3 << 1; + break; + case 22050: + add_ctl |= 0x2 << 1; + break; + case 32000: + add_ctl |= 0x1 << 1; + break; + case 44100: + case 48000: + break; + } + + /* Sampling rate is known now, can configure the MCLK divider */ + wm8978->f_256fs = params_rate(params) * 256; + + if (wm8978->sysclk == WM8978_MCLK) { + f_sel = wm8978->f_mclk; + } else { + if (!wm8978->f_pllout) { + int ret = wm8978_configure_pll(codec); + if (ret < 0) + return ret; + } + f_sel = wm8978->f_pllout; + } + + /* + * In some cases it is possible to reconfigure PLL to a higher frequency + * by raising OPCLKDIV, but normally OPCLK is configured to 256 * fs or + * 512 * fs, so, we should be fine. + */ + if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { + diff = abs(wm8978->f_256fs * 3 - + f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]); + + if (diff < diff_best) { + diff_best = diff; + best = i; + } + + if (!diff) + break; + } + + if (diff) + dev_warn(codec->dev, "Imprecise clock: %u%s\n", + f_sel * mclk_denominator[best] / mclk_numerator[best], + wm8978->sysclk == WM8978_MCLK ? + ", consider using PLL" : ""); + + dev_dbg(codec->dev, "%s: fmt %d, rate %u, MCLK divisor #%d\n", __func__, + params_format(params), params_rate(params), best); + + /* MCLK divisor mask = 0xe0 */ + snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, best << 5); + + snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface_ctl); + snd_soc_write(codec, WM8978_ADDITIONAL_CONTROL, add_ctl); + + if (wm8978->sysclk != current_clk_id) { + if (wm8978->sysclk == WM8978_PLL) + /* Run CODEC from PLL instead of MCLK */ + snd_soc_update_bits(codec, WM8978_CLOCKING, + 0x100, 0x100); + else + /* Clock CODEC directly from MCLK */ + snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0); + } + + return 0; +} + +static int wm8978_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + dev_dbg(codec->dev, "%s: %d\n", __func__, mute); + + if (mute) + snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0x40); + else + snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0); + + return 0; +} + +static int wm8978_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 power1 = snd_soc_read(codec, WM8978_POWER_MANAGEMENT_1) & ~3; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + power1 |= 1; /* VMID 75k */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1); + break; + case SND_SOC_BIAS_STANDBY: + /* bit 3: enable bias, bit 2: enable I/O tie off buffer */ + power1 |= 0xc; + + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Initial cap charge at VMID 5k */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, + power1 | 0x3); + mdelay(100); + } + + power1 |= 0x2; /* VMID 500k */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1); + break; + case SND_SOC_BIAS_OFF: + /* Preserve PLL - OPCLK may be used by someone */ + snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, ~0x20, 0); + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0); + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_3, 0); + break; + } + + dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1); + + codec->bias_level = level; + return 0; +} + +#define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8978_dai_ops = { + .hw_params = wm8978_hw_params, + .digital_mute = wm8978_mute, + .set_fmt = wm8978_set_dai_fmt, + .set_clkdiv = wm8978_set_dai_clkdiv, + .set_sysclk = wm8978_set_dai_sysclk, +}; + +/* Also supports 12kHz */ +struct snd_soc_dai wm8978_dai = { + .name = "WM8978 HiFi", + .id = 1, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = WM8978_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = WM8978_FORMATS, + }, + .ops = &wm8978_dai_ops, +}; +EXPORT_SYMBOL_GPL(wm8978_dai); + +static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); + /* Also switch PLL off */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); + /* Put to sleep */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0x40); + + return 0; +} + +static int wm8978_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8978_priv *wm8978 = codec->private_data; + int i; + u16 *cache = codec->reg_cache; + + /* Wake up the codec */ + snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0); + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) { + if (i == WM8978_RESET) + continue; + if (cache[i] != wm8978_reg[i]) + snd_soc_write(codec, i, cache[i]); + } + + wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + if (wm8978->f_pllout) + /* Switch PLL on */ + snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20); + + return 0; +} + +static int wm8978_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8978_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8978_codec; + codec = wm8978_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8978_snd_controls, + ARRAY_SIZE(wm8978_snd_controls)); + wm8978_add_widgets(codec); + +pcm_err: + return ret; +} + +/* power down chip */ +static int wm8978_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8978 = { + .probe = wm8978_probe, + .remove = wm8978_remove, + .suspend = wm8978_suspend, + .resume = wm8978_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978); + +/* + * These registers contain an "update" bit - bit 8. This means, for example, + * that one can write new DAC digital volume for both channels, but only when + * the update bit is set, will also the volume be updated - simultaneously for + * both channels. + */ +static const int update_reg[] = { + WM8978_LEFT_DAC_DIGITAL_VOLUME, + WM8978_RIGHT_DAC_DIGITAL_VOLUME, + WM8978_LEFT_ADC_DIGITAL_VOLUME, + WM8978_RIGHT_ADC_DIGITAL_VOLUME, + WM8978_LEFT_INP_PGA_CONTROL, + WM8978_RIGHT_INP_PGA_CONTROL, + WM8978_LOUT1_HP_CONTROL, + WM8978_ROUT1_HP_CONTROL, + WM8978_LOUT2_SPK_CONTROL, + WM8978_ROUT2_SPK_CONTROL, +}; + +static __devinit int wm8978_register(struct wm8978_priv *wm8978) +{ + int ret, i; + struct snd_soc_codec *codec = &wm8978->codec; + + if (wm8978_codec) { + dev_err(codec->dev, "Another WM8978 is registered\n"); + return -EINVAL; + } + + /* + * Set default system clock to PLL, it is more precise, this is also the + * default hardware setting + */ + wm8978->sysclk = WM8978_PLL; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8978; + codec->name = "WM8978"; + codec->owner = THIS_MODULE; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8978_set_bias_level; + codec->dai = &wm8978_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8978_CACHEREGNUM; + codec->reg_cache = &wm8978->reg_cache; + + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg)); + + /* + * Set the update bit in all registers, that have one. This way all + * writes to those registers will also cause the update bit to be + * written. + */ + for (i = 0; i < ARRAY_SIZE(update_reg); i++) + ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100; + + /* Reset the codec */ + ret = snd_soc_write(codec, WM8978_RESET, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err; + } + + wm8978_dai.dev = codec->dev; + + wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8978_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8978_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8978); + return ret; +} + +static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) +{ + wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8978_dai); + snd_soc_unregister_codec(&wm8978->codec); + kfree(wm8978); + wm8978_codec = NULL; +} + +static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8978_priv *wm8978; + struct snd_soc_codec *codec; + + wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL); + if (wm8978 == NULL) + return -ENOMEM; + + codec = &wm8978->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8978); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8978_register(wm8978); +} + +static __devexit int wm8978_i2c_remove(struct i2c_client *client) +{ + struct wm8978_priv *wm8978 = i2c_get_clientdata(client); + wm8978_unregister(wm8978); + return 0; +} + +static const struct i2c_device_id wm8978_i2c_id[] = { + { "wm8978", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); + +static struct i2c_driver wm8978_i2c_driver = { + .driver = { + .name = "WM8978", + .owner = THIS_MODULE, + }, + .probe = wm8978_i2c_probe, + .remove = __devexit_p(wm8978_i2c_remove), + .id_table = wm8978_i2c_id, +}; + +static int __init wm8978_modinit(void) +{ + return i2c_add_driver(&wm8978_i2c_driver); +} +module_init(wm8978_modinit); + +static void __exit wm8978_exit(void) +{ + i2c_del_driver(&wm8978_i2c_driver); +} +module_exit(wm8978_exit); + +MODULE_DESCRIPTION("ASoC WM8978 codec driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h new file mode 100644 index 000000000000..b58f0bf947e7 --- /dev/null +++ b/sound/soc/codecs/wm8978.h @@ -0,0 +1,89 @@ +/* + * wm8978.h -- codec driver for WM8978 + * + * Copyright 2009 Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __WM8978_H__ +#define __WM8978_H__ + +/* + * Register values. + */ +#define WM8978_RESET 0x00 +#define WM8978_POWER_MANAGEMENT_1 0x01 +#define WM8978_POWER_MANAGEMENT_2 0x02 +#define WM8978_POWER_MANAGEMENT_3 0x03 +#define WM8978_AUDIO_INTERFACE 0x04 +#define WM8978_COMPANDING_CONTROL 0x05 +#define WM8978_CLOCKING 0x06 +#define WM8978_ADDITIONAL_CONTROL 0x07 +#define WM8978_GPIO_CONTROL 0x08 +#define WM8978_JACK_DETECT_CONTROL_1 0x09 +#define WM8978_DAC_CONTROL 0x0A +#define WM8978_LEFT_DAC_DIGITAL_VOLUME 0x0B +#define WM8978_RIGHT_DAC_DIGITAL_VOLUME 0x0C +#define WM8978_JACK_DETECT_CONTROL_2 0x0D +#define WM8978_ADC_CONTROL 0x0E +#define WM8978_LEFT_ADC_DIGITAL_VOLUME 0x0F +#define WM8978_RIGHT_ADC_DIGITAL_VOLUME 0x10 +#define WM8978_EQ1 0x12 +#define WM8978_EQ2 0x13 +#define WM8978_EQ3 0x14 +#define WM8978_EQ4 0x15 +#define WM8978_EQ5 0x16 +#define WM8978_DAC_LIMITER_1 0x18 +#define WM8978_DAC_LIMITER_2 0x19 +#define WM8978_NOTCH_FILTER_1 0x1b +#define WM8978_NOTCH_FILTER_2 0x1c +#define WM8978_NOTCH_FILTER_3 0x1d +#define WM8978_NOTCH_FILTER_4 0x1e +#define WM8978_ALC_CONTROL_1 0x20 +#define WM8978_ALC_CONTROL_2 0x21 +#define WM8978_ALC_CONTROL_3 0x22 +#define WM8978_NOISE_GATE 0x23 +#define WM8978_PLL_N 0x24 +#define WM8978_PLL_K1 0x25 +#define WM8978_PLL_K2 0x26 +#define WM8978_PLL_K3 0x27 +#define WM8978_3D_CONTROL 0x29 +#define WM8978_BEEP_CONTROL 0x2b +#define WM8978_INPUT_CONTROL 0x2c +#define WM8978_LEFT_INP_PGA_CONTROL 0x2d +#define WM8978_RIGHT_INP_PGA_CONTROL 0x2e +#define WM8978_LEFT_ADC_BOOST_CONTROL 0x2f +#define WM8978_RIGHT_ADC_BOOST_CONTROL 0x30 +#define WM8978_OUTPUT_CONTROL 0x31 +#define WM8978_LEFT_MIXER_CONTROL 0x32 +#define WM8978_RIGHT_MIXER_CONTROL 0x33 +#define WM8978_LOUT1_HP_CONTROL 0x34 +#define WM8978_ROUT1_HP_CONTROL 0x35 +#define WM8978_LOUT2_SPK_CONTROL 0x36 +#define WM8978_ROUT2_SPK_CONTROL 0x37 +#define WM8978_OUT3_MIXER_CONTROL 0x38 +#define WM8978_OUT4_MIXER_CONTROL 0x39 + +#define WM8978_CACHEREGNUM 58 + +/* Clock divider Id's */ +enum wm8978_clk_id { + WM8978_OPCLKRATE, + WM8978_MCLKDIV, + WM8978_ADCCLK, + WM8978_DACCLK, + WM8978_BCLKDIV, +}; + +enum wm8978_sysclk_src { + WM8978_PLL, + WM8978_MCLK +}; + +extern struct snd_soc_dai wm8978_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8978; + +#endif /* __WM8978_H__ */ -- GitLab From 08d1e2e68da977956ff10735148ac1de21c85afd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Dec 2009 09:46:24 +0100 Subject: [PATCH 1283/3892] ARM: 5852/1: Add COH 901 318 DMA driver platform config for U300 This adds platform configuration for the COH 901 318 DMA driver for the U300 series mobile platforms. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/core.c | 1039 +++++++++++++++++ .../arm/mach-u300/include/mach/dma_channels.h | 69 ++ 2 files changed, 1108 insertions(+) create mode 100644 arch/arm/mach-u300/include/mach/dma_channels.h diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 653e25be3dd8..068526a7ddac 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ #include #include +#include #include "clock.h" #include "mmc.h" @@ -372,6 +374,1031 @@ static struct resource ave_resources[] = { }, }; +static struct resource dma_resource[] = { + { + .start = U300_DMAC_BASE, + .end = U300_DMAC_BASE + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_U300_DMA, + .end = IRQ_U300_DMA, + .flags = IORESOURCE_IRQ, + } +}; + +#ifdef CONFIG_MACH_U300_BS335 +/* points out all dma slave channels. + * Syntax is [A1, B1, A2, B2, .... ,-1,-1] + * Select all channels from A to B, end of list is marked with -1,-1 + */ +static int dma_slave_channels[] = { + U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, + U300_DMA_UART1_TX, U300_DMA_UART1_RX, -1, -1}; + +/* points out all dma memcpy channels. */ +static int dma_memcpy_channels[] = { + U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1}; + +#else /* CONFIG_MACH_U300_BS335 */ + +static int dma_slave_channels[] = {U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, -1, -1}; +static int dma_memcpy_channels[] = { + U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_10, -1, -1}; + +#endif + +/** register dma for memory access + * + * active 1 means dma intends to access memory + * 0 means dma wont access memory + */ +static void coh901318_access_memory_state(struct device *dev, bool active) +{ +} + +#define flags_memcpy_config (COH901318_CX_CFG_CH_DISABLE | \ + COH901318_CX_CFG_RM_MEMORY_TO_MEMORY | \ + COH901318_CX_CFG_LCR_DISABLE | \ + COH901318_CX_CFG_TC_IRQ_ENABLE | \ + COH901318_CX_CFG_BE_IRQ_ENABLE) +#define flags_memcpy_lli_chained (COH901318_CX_CTRL_TC_ENABLE | \ + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \ + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_MASTER_MODE_M1RW | \ + COH901318_CX_CTRL_TCP_DISABLE | \ + COH901318_CX_CTRL_TC_IRQ_DISABLE | \ + COH901318_CX_CTRL_HSP_DISABLE | \ + COH901318_CX_CTRL_HSS_DISABLE | \ + COH901318_CX_CTRL_DDMA_LEGACY | \ + COH901318_CX_CTRL_PRDD_SOURCE) +#define flags_memcpy_lli (COH901318_CX_CTRL_TC_ENABLE | \ + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \ + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_MASTER_MODE_M1RW | \ + COH901318_CX_CTRL_TCP_DISABLE | \ + COH901318_CX_CTRL_TC_IRQ_DISABLE | \ + COH901318_CX_CTRL_HSP_DISABLE | \ + COH901318_CX_CTRL_HSS_DISABLE | \ + COH901318_CX_CTRL_DDMA_LEGACY | \ + COH901318_CX_CTRL_PRDD_SOURCE) +#define flags_memcpy_lli_last (COH901318_CX_CTRL_TC_ENABLE | \ + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \ + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \ + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \ + COH901318_CX_CTRL_MASTER_MODE_M1RW | \ + COH901318_CX_CTRL_TCP_DISABLE | \ + COH901318_CX_CTRL_TC_IRQ_ENABLE | \ + COH901318_CX_CTRL_HSP_DISABLE | \ + COH901318_CX_CTRL_HSS_DISABLE | \ + COH901318_CX_CTRL_DDMA_LEGACY | \ + COH901318_CX_CTRL_PRDD_SOURCE) + +const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { + { + .number = U300_DMA_MSL_TX_0, + .name = "MSL TX 0", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x20, + }, + { + .number = U300_DMA_MSL_TX_1, + .name = "MSL TX 1", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x20, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + }, + { + .number = U300_DMA_MSL_TX_2, + .name = "MSL TX 2", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x20, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .desc_nbr_max = 10, + }, + { + .number = U300_DMA_MSL_TX_3, + .name = "MSL TX 3", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x20, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + }, + { + .number = U300_DMA_MSL_TX_4, + .name = "MSL TX 4", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x20, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1R_M2W | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + }, + { + .number = U300_DMA_MSL_TX_5, + .name = "MSL TX 5", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x20, + }, + { + .number = U300_DMA_MSL_TX_6, + .name = "MSL TX 6", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x20, + }, + { + .number = U300_DMA_MSL_RX_0, + .name = "MSL RX 0", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x220, + }, + { + .number = U300_DMA_MSL_RX_1, + .name = "MSL RX 1", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x220, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_MSL_RX_2, + .name = "MSL RX 2", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x220, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_MSL_RX_3, + .name = "MSL RX 3", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x220, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_MSL_RX_4, + .name = "MSL RX 4", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x220, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_MSL_RX_5, + .name = "MSL RX 5", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x220, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M2R_M1W | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_DEMAND_DMA1 | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_MSL_RX_6, + .name = "MSL RX 6", + .priority_high = 0, + .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x220, + }, + { + .number = U300_DMA_MMCSD_RX_TX, + .name = "MMCSD RX TX", + .priority_high = 0, + .dev_addr = U300_MMCSD_BASE + 0x080, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_32_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY, + + }, + { + .number = U300_DMA_MSPRO_TX, + .name = "MSPRO TX", + .priority_high = 0, + }, + { + .number = U300_DMA_MSPRO_RX, + .name = "MSPRO RX", + .priority_high = 0, + }, + { + .number = U300_DMA_UART0_TX, + .name = "UART0 TX", + .priority_high = 0, + }, + { + .number = U300_DMA_UART0_RX, + .name = "UART0 RX", + .priority_high = 0, + }, + { + .number = U300_DMA_APEX_TX, + .name = "APEX TX", + .priority_high = 0, + }, + { + .number = U300_DMA_APEX_RX, + .name = "APEX RX", + .priority_high = 0, + }, + { + .number = U300_DMA_PCM_I2S0_TX, + .name = "PCM I2S0 TX", + .priority_high = 1, + .dev_addr = U300_PCM_I2S0_BASE + 0x14, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + }, + { + .number = U300_DMA_PCM_I2S0_RX, + .name = "PCM I2S0 RX", + .priority_high = 1, + .dev_addr = U300_PCM_I2S0_BASE + 0x10, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_PCM_I2S1_TX, + .name = "PCM I2S1 TX", + .priority_high = 1, + .dev_addr = U300_PCM_I2S1_BASE + 0x14, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_DISABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_SOURCE, + }, + { + .number = U300_DMA_PCM_I2S1_RX, + .name = "PCM I2S1 RX", + .priority_high = 1, + .dev_addr = U300_PCM_I2S1_BASE + 0x10, + .param.config = COH901318_CX_CFG_CH_DISABLE | + COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | + COH901318_CX_CFG_LCR_DISABLE | + COH901318_CX_CFG_TC_IRQ_ENABLE | + COH901318_CX_CFG_BE_IRQ_ENABLE, + .param.ctrl_lli_chained = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_DISABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + .param.ctrl_lli_last = 0 | + COH901318_CX_CTRL_TC_ENABLE | + COH901318_CX_CTRL_BURST_COUNT_16_BYTES | + COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE | + COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | + COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | + COH901318_CX_CTRL_MASTER_MODE_M1RW | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | + COH901318_CX_CTRL_HSP_ENABLE | + COH901318_CX_CTRL_HSS_DISABLE | + COH901318_CX_CTRL_DDMA_LEGACY | + COH901318_CX_CTRL_PRDD_DEST, + }, + { + .number = U300_DMA_XGAM_CDI, + .name = "XGAM CDI", + .priority_high = 0, + }, + { + .number = U300_DMA_XGAM_PDI, + .name = "XGAM PDI", + .priority_high = 0, + }, + { + .number = U300_DMA_SPI_TX, + .name = "SPI TX", + .priority_high = 0, + }, + { + .number = U300_DMA_SPI_RX, + .name = "SPI RX", + .priority_high = 0, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_0, + .name = "GENERAL 00", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_1, + .name = "GENERAL 01", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_2, + .name = "GENERAL 02", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_3, + .name = "GENERAL 03", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_4, + .name = "GENERAL 04", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_5, + .name = "GENERAL 05", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_6, + .name = "GENERAL 06", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_7, + .name = "GENERAL 07", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_8, + .name = "GENERAL 08", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, +#ifdef CONFIG_MACH_U300_BS335 + { + .number = U300_DMA_UART1_TX, + .name = "UART1 TX", + .priority_high = 0, + }, + { + .number = U300_DMA_UART1_RX, + .name = "UART1 RX", + .priority_high = 0, + } +#else + { + .number = U300_DMA_GENERAL_PURPOSE_9, + .name = "GENERAL 09", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + }, + { + .number = U300_DMA_GENERAL_PURPOSE_10, + .name = "GENERAL 10", + .priority_high = 0, + + .param.config = flags_memcpy_config, + .param.ctrl_lli_chained = flags_memcpy_lli_chained, + .param.ctrl_lli = flags_memcpy_lli, + .param.ctrl_lli_last = flags_memcpy_lli_last, + } +#endif +}; + + +static struct coh901318_platform coh901318_platform = { + .chans_slave = dma_slave_channels, + .chans_memcpy = dma_memcpy_channels, + .access_memory_state = coh901318_access_memory_state, + .chan_conf = chan_config, + .max_channels = U300_DMA_CHANNELS, +}; + static struct platform_device wdog_device = { .name = "wdog", .id = -1, @@ -428,11 +1455,23 @@ static struct platform_device ave_device = { .resource = ave_resources, }; +static struct platform_device dma_device = { + .name = "coh901318", + .id = -1, + .resource = dma_resource, + .num_resources = ARRAY_SIZE(dma_resource), + .dev = { + .platform_data = &coh901318_platform, + .coherent_dma_mask = ~0, + }, +}; + /* * Notice that AMBA devices are initialized before platform devices. * */ static struct platform_device *platform_devs[] __initdata = { + &dma_device, &i2c0_device, &i2c1_device, &keypad_device, diff --git a/arch/arm/mach-u300/include/mach/dma_channels.h b/arch/arm/mach-u300/include/mach/dma_channels.h new file mode 100644 index 000000000000..b239149ba0d0 --- /dev/null +++ b/arch/arm/mach-u300/include/mach/dma_channels.h @@ -0,0 +1,69 @@ +/* + * + * arch/arm/mach-u300/include/mach/dma_channels.h + * + * + * Copyright (C) 2007-2009 ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + * Map file for the U300 dma driver. + * Author: Per Friden + */ + +#ifndef DMA_CHANNELS_H +#define DMA_CHANNELS_H + +#define U300_DMA_MSL_TX_0 0 +#define U300_DMA_MSL_TX_1 1 +#define U300_DMA_MSL_TX_2 2 +#define U300_DMA_MSL_TX_3 3 +#define U300_DMA_MSL_TX_4 4 +#define U300_DMA_MSL_TX_5 5 +#define U300_DMA_MSL_TX_6 6 +#define U300_DMA_MSL_RX_0 7 +#define U300_DMA_MSL_RX_1 8 +#define U300_DMA_MSL_RX_2 9 +#define U300_DMA_MSL_RX_3 10 +#define U300_DMA_MSL_RX_4 11 +#define U300_DMA_MSL_RX_5 12 +#define U300_DMA_MSL_RX_6 13 +#define U300_DMA_MMCSD_RX_TX 14 +#define U300_DMA_MSPRO_TX 15 +#define U300_DMA_MSPRO_RX 16 +#define U300_DMA_UART0_TX 17 +#define U300_DMA_UART0_RX 18 +#define U300_DMA_APEX_TX 19 +#define U300_DMA_APEX_RX 20 +#define U300_DMA_PCM_I2S0_TX 21 +#define U300_DMA_PCM_I2S0_RX 22 +#define U300_DMA_PCM_I2S1_TX 23 +#define U300_DMA_PCM_I2S1_RX 24 +#define U300_DMA_XGAM_CDI 25 +#define U300_DMA_XGAM_PDI 26 +#define U300_DMA_SPI_TX 27 +#define U300_DMA_SPI_RX 28 +#define U300_DMA_GENERAL_PURPOSE_0 29 +#define U300_DMA_GENERAL_PURPOSE_1 30 +#define U300_DMA_GENERAL_PURPOSE_2 31 +#define U300_DMA_GENERAL_PURPOSE_3 32 +#define U300_DMA_GENERAL_PURPOSE_4 33 +#define U300_DMA_GENERAL_PURPOSE_5 34 +#define U300_DMA_GENERAL_PURPOSE_6 35 +#define U300_DMA_GENERAL_PURPOSE_7 36 +#define U300_DMA_GENERAL_PURPOSE_8 37 +#ifdef CONFIG_MACH_U300_BS335 +#define U300_DMA_UART1_TX 38 +#define U300_DMA_UART1_RX 39 +#else +#define U300_DMA_GENERAL_PURPOSE_9 38 +#define U300_DMA_GENERAL_PURPOSE_10 39 +#endif + +#ifdef CONFIG_MACH_U300_BS335 +#define U300_DMA_DEVICE_CHANNELS 32 +#else +#define U300_DMA_DEVICE_CHANNELS 30 +#endif +#define U300_DMA_CHANNELS 40 + + +#endif /* DMA_CHANNELS_H */ -- GitLab From fc05475f867624dddd5ea7089cf8f434f95fbec5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 22 Jan 2010 13:53:30 +0100 Subject: [PATCH 1284/3892] ARM: 5893/1: SPI AMBA PL022: Limit TX FIFO fills Added logic to cap TX FIFO fill size based on current free RX FIFO entries instead of TX status flags. This is to prevent an issue with RX FIFO overflows. Signed-off-by: Kevin Wells Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/spi/amba-pl022.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index ff5bbb9c43c9..9aeb68113100 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -363,6 +363,7 @@ struct pl022 { void *rx_end; enum ssp_reading read; enum ssp_writing write; + u32 exp_fifo_level; }; /** @@ -501,6 +502,9 @@ static int flush(struct pl022 *pl022) while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) readw(SSP_DR(pl022->virtbase)); } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--); + + pl022->exp_fifo_level = 0; + return limit; } @@ -583,10 +587,9 @@ static void readwriter(struct pl022 *pl022) * errons in 8bit wide transfers on ARM variants (just 8 words * FIFO, means only 8x8 = 64 bits in FIFO) at least. * - * FIXME: currently we have no logic to account for this. - * perhaps there is even something broken in HW regarding - * 8bit transfers (it doesn't fail on 16bit) so this needs - * more investigation... + * To prevent this issue, the TX FIFO is only filled to the + * unused RX FIFO fill length, regardless of what the TX + * FIFO status flag indicates. */ dev_dbg(&pl022->adev->dev, "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n", @@ -613,11 +616,12 @@ static void readwriter(struct pl022 *pl022) break; } pl022->rx += (pl022->cur_chip->n_bytes); + pl022->exp_fifo_level--; } /* - * Write as much as you can, while keeping an eye on the RX FIFO! + * Write as much as possible up to the RX FIFO size */ - while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF) + while ((pl022->exp_fifo_level < pl022->vendor->fifodepth) && (pl022->tx < pl022->tx_end)) { switch (pl022->write) { case WRITING_NULL: @@ -634,6 +638,7 @@ static void readwriter(struct pl022 *pl022) break; } pl022->tx += (pl022->cur_chip->n_bytes); + pl022->exp_fifo_level++; /* * This inner reader takes care of things appearing in the RX * FIFO as we're transmitting. This will happen a lot since the @@ -660,6 +665,7 @@ static void readwriter(struct pl022 *pl022) break; } pl022->rx += (pl022->cur_chip->n_bytes); + pl022->exp_fifo_level--; } } /* -- GitLab From 633e81a66b7e6c22a50da860371159cfa2b06d53 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 25 Jan 2010 07:18:16 +0100 Subject: [PATCH 1285/3892] ARM: 5895/2: Alter name of U300 watchdog resource This changes the bus name of the U300 watchdog from just "wdog" to "coh901327_wdog" which is used to match the corresponding driver. This makes the watchdog probe properly. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 068526a7ddac..6869052fe096 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -3,7 +3,7 @@ * arch/arm/mach-u300/core.c * * - * Copyright (C) 2007-2009 ST-Ericsson AB + * Copyright (C) 2007-2010 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 * Core platform support, IRQ handling and device definitions. * Author: Linus Walleij @@ -1400,7 +1400,7 @@ static struct coh901318_platform coh901318_platform = { }; static struct platform_device wdog_device = { - .name = "wdog", + .name = "coh901327_wdog", .id = -1, .num_resources = ARRAY_SIZE(wdog_resources), .resource = wdog_resources, -- GitLab From f28e8a4d027e4e21c3d0a52706527bb87397bea0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 25 Jan 2010 07:14:46 +0100 Subject: [PATCH 1286/3892] ARM: 5896/1: MMCI: work around a hardware bug in U300 In the U300 some hardware bug makes the status flag not come up signalling a successful write (or anything else, like an error, for that matter) on write requests. This little quirk makes the writes work on U300. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 90d168ad03b6..643818a5ac45 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -184,6 +184,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, { if (status & MCI_DATABLOCKEND) { host->data_xfered += data->blksz; +#ifdef CONFIG_ARCH_U300 + /* + * On the U300 some signal or other is + * badly routed so that a data write does + * not properly terminate with a MCI_DATAEND + * status flag. This quirk will make writes + * work again. + */ + if (data->flags & MMC_DATA_WRITE) + status |= MCI_DATAEND; +#endif } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { if (status & MCI_DATACRCFAIL) -- GitLab From a62e90308f7b6965310cf4ec61393aef6861f50d Mon Sep 17 00:00:00 2001 From: wanzongshun Date: Thu, 31 Dec 2009 15:06:05 +0100 Subject: [PATCH 1287/3892] ARM: 5859/1: Add nuc93x platform support The previous nuc932 support patches have been discarded by me and because it belongs to another SoCs series named nuc93x,at present, which included nuc931 and nuc932, I think it is better to create a new mach-nuc93x,So I made the patch,and request your advice.Thanks! Signed-off-by: Wan ZongShun Signed-off-by: Russell King --- arch/arm/Kconfig | 11 ++ arch/arm/Makefile | 1 + arch/arm/mach-nuc93x/Kconfig | 19 +++ arch/arm/mach-nuc93x/Makefile | 14 ++ arch/arm/mach-nuc93x/Makefile.boot | 3 + arch/arm/mach-nuc93x/clock.c | 83 +++++++++++ arch/arm/mach-nuc93x/clock.h | 36 +++++ arch/arm/mach-nuc93x/cpu.c | 135 +++++++++++++++++ arch/arm/mach-nuc93x/cpu.h | 48 ++++++ arch/arm/mach-nuc93x/dev.c | 42 ++++++ arch/arm/mach-nuc93x/include/mach/clkdev.h | 7 + .../mach-nuc93x/include/mach/entry-macro.S | 32 ++++ arch/arm/mach-nuc93x/include/mach/hardware.h | 22 +++ arch/arm/mach-nuc93x/include/mach/io.h | 28 ++++ arch/arm/mach-nuc93x/include/mach/irqs.h | 59 ++++++++ arch/arm/mach-nuc93x/include/mach/map.h | 139 ++++++++++++++++++ arch/arm/mach-nuc93x/include/mach/memory.h | 21 +++ .../arm/mach-nuc93x/include/mach/regs-clock.h | 53 +++++++ arch/arm/mach-nuc93x/include/mach/regs-ebi.h | 33 +++++ arch/arm/mach-nuc93x/include/mach/regs-irq.h | 42 ++++++ .../mach-nuc93x/include/mach/regs-serial.h | 52 +++++++ .../arm/mach-nuc93x/include/mach/regs-timer.h | 28 ++++ arch/arm/mach-nuc93x/include/mach/system.h | 28 ++++ arch/arm/mach-nuc93x/include/mach/timex.h | 25 ++++ .../arm/mach-nuc93x/include/mach/uncompress.h | 50 +++++++ arch/arm/mach-nuc93x/include/mach/vmalloc.h | 23 +++ arch/arm/mach-nuc93x/irq.c | 66 +++++++++ arch/arm/mach-nuc93x/mach-nuc932evb.c | 45 ++++++ arch/arm/mach-nuc93x/nuc932.c | 65 ++++++++ arch/arm/mach-nuc93x/nuc932.h | 29 ++++ arch/arm/mach-nuc93x/time.c | 100 +++++++++++++ 31 files changed, 1339 insertions(+) create mode 100644 arch/arm/mach-nuc93x/Kconfig create mode 100644 arch/arm/mach-nuc93x/Makefile create mode 100644 arch/arm/mach-nuc93x/Makefile.boot create mode 100644 arch/arm/mach-nuc93x/clock.c create mode 100644 arch/arm/mach-nuc93x/clock.h create mode 100644 arch/arm/mach-nuc93x/cpu.c create mode 100644 arch/arm/mach-nuc93x/cpu.h create mode 100644 arch/arm/mach-nuc93x/dev.c create mode 100644 arch/arm/mach-nuc93x/include/mach/clkdev.h create mode 100644 arch/arm/mach-nuc93x/include/mach/entry-macro.S create mode 100644 arch/arm/mach-nuc93x/include/mach/hardware.h create mode 100644 arch/arm/mach-nuc93x/include/mach/io.h create mode 100644 arch/arm/mach-nuc93x/include/mach/irqs.h create mode 100644 arch/arm/mach-nuc93x/include/mach/map.h create mode 100644 arch/arm/mach-nuc93x/include/mach/memory.h create mode 100644 arch/arm/mach-nuc93x/include/mach/regs-clock.h create mode 100644 arch/arm/mach-nuc93x/include/mach/regs-ebi.h create mode 100644 arch/arm/mach-nuc93x/include/mach/regs-irq.h create mode 100644 arch/arm/mach-nuc93x/include/mach/regs-serial.h create mode 100644 arch/arm/mach-nuc93x/include/mach/regs-timer.h create mode 100644 arch/arm/mach-nuc93x/include/mach/system.h create mode 100644 arch/arm/mach-nuc93x/include/mach/timex.h create mode 100644 arch/arm/mach-nuc93x/include/mach/uncompress.h create mode 100644 arch/arm/mach-nuc93x/include/mach/vmalloc.h create mode 100644 arch/arm/mach-nuc93x/irq.c create mode 100644 arch/arm/mach-nuc93x/mach-nuc932evb.c create mode 100644 arch/arm/mach-nuc93x/nuc932.c create mode 100644 arch/arm/mach-nuc93x/nuc932.h create mode 100644 arch/arm/mach-nuc93x/time.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 233a222752c0..79251a9cfb6f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -548,6 +548,15 @@ config ARCH_W90X900 +config ARCH_NUC93X + bool "Nuvoton NUC93X CPU" + select CPU_ARM926T + select HAVE_CLK + select COMMON_CLKDEV + help + Support for Nuvoton (Winbond logic dept.) NUC93X MCU,The NUC93X is a + low-power and high performance MPEG-4/JPEG multimedia controller chip. + config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select CPU_ARM926T @@ -828,6 +837,8 @@ source "arch/arm/mach-u300/Kconfig" source "arch/arm/mach-w90x900/Kconfig" +source "arch/arm/mach-nuc93x/Kconfig" + source "arch/arm/mach-bcmring/Kconfig" source "arch/arm/mach-ux500/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index e9da08483b3c..3eaef160d468 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -170,6 +170,7 @@ machine-$(CONFIG_ARCH_U300) := u300 machine-$(CONFIG_ARCH_U8500) := ux500 machine-$(CONFIG_ARCH_VERSATILE) := versatile machine-$(CONFIG_ARCH_W90X900) := w90x900 +machine-$(CONFIG_ARCH_NUC93X) := nuc93x machine-$(CONFIG_FOOTBRIDGE) := footbridge machine-$(CONFIG_ARCH_MXC91231) := mxc91231 diff --git a/arch/arm/mach-nuc93x/Kconfig b/arch/arm/mach-nuc93x/Kconfig new file mode 100644 index 000000000000..2bc40a280fad --- /dev/null +++ b/arch/arm/mach-nuc93x/Kconfig @@ -0,0 +1,19 @@ +if ARCH_NUC93X + +config CPU_NUC932 + bool + help + Support for NUC932 of Nuvoton NUC93X CPUs. + +menu "NUC932 Machines" + +config MACH_NUC932EVB + bool "Nuvoton NUC932 Evaluation Board" + default y + select CPU_NUC932 + help + Say Y here if you are using the Nuvoton NUC932EVB + +endmenu + +endif diff --git a/arch/arm/mach-nuc93x/Makefile b/arch/arm/mach-nuc93x/Makefile new file mode 100644 index 000000000000..440e2dec6c8a --- /dev/null +++ b/arch/arm/mach-nuc93x/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := irq.o time.o dev.o cpu.o clock.o +# NUC932 CPU support files + +obj-$(CONFIG_CPU_NUC932) += nuc932.o + +# machine support + +obj-$(CONFIG_MACH_NUC932EVB) += mach-nuc932evb.o diff --git a/arch/arm/mach-nuc93x/Makefile.boot b/arch/arm/mach-nuc93x/Makefile.boot new file mode 100644 index 000000000000..a057b546b6e5 --- /dev/null +++ b/arch/arm/mach-nuc93x/Makefile.boot @@ -0,0 +1,3 @@ +zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 + diff --git a/arch/arm/mach-nuc93x/clock.c b/arch/arm/mach-nuc93x/clock.c new file mode 100644 index 000000000000..0521efbc48c9 --- /dev/null +++ b/arch/arm/mach-nuc93x/clock.c @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-nuc93x/clock.c + * + * Copyright (c) 2008 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; either version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clock.h" + +static DEFINE_SPINLOCK(clocks_lock); + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + if (clk->enabled++ == 0) + (clk->enable)(clk, 1); + spin_unlock_irqrestore(&clocks_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + WARN_ON(clk->enabled == 0); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->enabled == 0) + (clk->enable)(clk, 0); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return 27000000; +} +EXPORT_SYMBOL(clk_get_rate); + +void nuc93x_clk_enable(struct clk *clk, int enable) +{ + unsigned int clocks = clk->cken; + unsigned long clken; + + clken = __raw_readl(NUC93X_VA_CLKPWR); + + if (enable) + clken |= clocks; + else + clken &= ~clocks; + + __raw_writel(clken, NUC93X_VA_CLKPWR); +} + +void clks_register(struct clk_lookup *clks, size_t num) +{ + int i; + + for (i = 0; i < num; i++) + clkdev_add(&clks[i]); +} diff --git a/arch/arm/mach-nuc93x/clock.h b/arch/arm/mach-nuc93x/clock.h new file mode 100644 index 000000000000..18e51be4816f --- /dev/null +++ b/arch/arm/mach-nuc93x/clock.h @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/mach-nuc93x/clock.h + * + * Copyright (c) 2008 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; either version 2 of the License. + */ + +#include + +void nuc93x_clk_enable(struct clk *clk, int enable); +void clks_register(struct clk_lookup *clks, size_t num); + +struct clk { + unsigned long cken; + unsigned int enabled; + void (*enable)(struct clk *, int enable); +}; + +#define DEFINE_CLK(_name, _ctrlbit) \ +struct clk clk_##_name = { \ + .enable = nuc93x_clk_enable, \ + .cken = (1 << _ctrlbit), \ + } + +#define DEF_CLKLOOK(_clk, _devname, _conname) \ + { \ + .clk = _clk, \ + .dev_id = _devname, \ + .con_id = _conname, \ + } + diff --git a/arch/arm/mach-nuc93x/cpu.c b/arch/arm/mach-nuc93x/cpu.c new file mode 100644 index 000000000000..f6ff5d87354c --- /dev/null +++ b/arch/arm/mach-nuc93x/cpu.c @@ -0,0 +1,135 @@ +/* + * linux/arch/arm/mach-nuc93x/cpu.c + * + * Copyright (c) 2009 Nuvoton corporation. + * + * Wan ZongShun + * + * NUC93x series cpu common support + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cpu.h" +#include "clock.h" + +/* Initial IO mappings */ + +static struct map_desc nuc93x_iodesc[] __initdata = { + IODESC_ENT(IRQ), + IODESC_ENT(GCR), + IODESC_ENT(UART), + IODESC_ENT(TIMER), + IODESC_ENT(EBI), +}; + +/* Initial nuc932 clock declarations. */ +static DEFINE_CLK(audio, 2); +static DEFINE_CLK(sd, 3); +static DEFINE_CLK(jpg, 4); +static DEFINE_CLK(video, 5); +static DEFINE_CLK(vpost, 6); +static DEFINE_CLK(2d, 7); +static DEFINE_CLK(gpu, 8); +static DEFINE_CLK(gdma, 9); +static DEFINE_CLK(adc, 10); +static DEFINE_CLK(uart, 11); +static DEFINE_CLK(spi, 12); +static DEFINE_CLK(pwm, 13); +static DEFINE_CLK(timer, 14); +static DEFINE_CLK(wdt, 15); +static DEFINE_CLK(ac97, 16); +static DEFINE_CLK(i2s, 16); +static DEFINE_CLK(usbck, 17); +static DEFINE_CLK(usb48, 18); +static DEFINE_CLK(usbh, 19); +static DEFINE_CLK(i2c, 20); +static DEFINE_CLK(ext, 0); + +static struct clk_lookup nuc932_clkregs[] = { + DEF_CLKLOOK(&clk_audio, "nuc932-audio", NULL), + DEF_CLKLOOK(&clk_sd, "nuc932-sd", NULL), + DEF_CLKLOOK(&clk_jpg, "nuc932-jpg", "NULL"), + DEF_CLKLOOK(&clk_video, "nuc932-video", "NULL"), + DEF_CLKLOOK(&clk_vpost, "nuc932-vpost", NULL), + DEF_CLKLOOK(&clk_2d, "nuc932-2d", NULL), + DEF_CLKLOOK(&clk_gpu, "nuc932-gpu", NULL), + DEF_CLKLOOK(&clk_gdma, "nuc932-gdma", "NULL"), + DEF_CLKLOOK(&clk_adc, "nuc932-adc", NULL), + DEF_CLKLOOK(&clk_uart, NULL, "uart"), + DEF_CLKLOOK(&clk_spi, "nuc932-spi", NULL), + DEF_CLKLOOK(&clk_pwm, "nuc932-pwm", NULL), + DEF_CLKLOOK(&clk_timer, NULL, "timer"), + DEF_CLKLOOK(&clk_wdt, "nuc932-wdt", NULL), + DEF_CLKLOOK(&clk_ac97, "nuc932-ac97", NULL), + DEF_CLKLOOK(&clk_i2s, "nuc932-i2s", NULL), + DEF_CLKLOOK(&clk_usbck, "nuc932-usbck", NULL), + DEF_CLKLOOK(&clk_usb48, "nuc932-usb48", NULL), + DEF_CLKLOOK(&clk_usbh, "nuc932-usbh", NULL), + DEF_CLKLOOK(&clk_i2c, "nuc932-i2c", NULL), + DEF_CLKLOOK(&clk_ext, NULL, "ext"), +}; + +/* Initial serial platform data */ + +struct plat_serial8250_port nuc93x_uart_data[] = { + NUC93X_8250PORT(UART0), + {}, +}; + +struct platform_device nuc93x_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = nuc93x_uart_data, + }, +}; + +/*Init NUC93x evb io*/ + +void __init nuc93x_map_io(struct map_desc *mach_desc, int mach_size) +{ + unsigned long idcode = 0x0; + + iotable_init(mach_desc, mach_size); + iotable_init(nuc93x_iodesc, ARRAY_SIZE(nuc93x_iodesc)); + + idcode = __raw_readl(NUC93XPDID); + if (idcode == NUC932_CPUID) + printk(KERN_INFO "CPU type 0x%08lx is NUC910\n", idcode); + else + printk(KERN_ERR "CPU type detect error!\n"); + +} + +/*Init NUC93x clock*/ + +void __init nuc93x_init_clocks(void) +{ + clks_register(nuc932_clkregs, ARRAY_SIZE(nuc932_clkregs)); +} + diff --git a/arch/arm/mach-nuc93x/cpu.h b/arch/arm/mach-nuc93x/cpu.h new file mode 100644 index 000000000000..9def28197bc9 --- /dev/null +++ b/arch/arm/mach-nuc93x/cpu.h @@ -0,0 +1,48 @@ +/* + * arch/arm/mach-nuc93x/cpu.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Header file for NUC93X CPU support + * + * Wan ZongShun + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define IODESC_ENT(y) \ +{ \ + .virtual = (unsigned long)NUC93X_VA_##y, \ + .pfn = __phys_to_pfn(NUC93X_PA_##y), \ + .length = NUC93X_SZ_##y, \ + .type = MT_DEVICE, \ +} + +#define NUC93X_8250PORT(name) \ +{ \ + .membase = name##_BA, \ + .mapbase = name##_PA, \ + .irq = IRQ_##name, \ + .uartclk = 57139200, \ + .regshift = 2, \ + .iotype = UPIO_MEM, \ + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ +} + +/*Cpu identifier register*/ + +#define NUC93XPDID NUC93X_VA_GCR +#define NUC932_CPUID 0x29550091 + +/* extern file from cpu.c */ + +extern void nuc93x_clock_source(struct device *dev, unsigned char *src); +extern void nuc93x_init_clocks(void); +extern void nuc93x_map_io(struct map_desc *mach_desc, int mach_size); +extern void nuc93x_board_init(struct platform_device **device, int size); +extern struct platform_device nuc93x_serial_device; + diff --git a/arch/arm/mach-nuc93x/dev.c b/arch/arm/mach-nuc93x/dev.c new file mode 100644 index 000000000000..a962ae9578d6 --- /dev/null +++ b/arch/arm/mach-nuc93x/dev.c @@ -0,0 +1,42 @@ +/* + * linux/arch/arm/mach-nuc93x/dev.c + * + * Copyright (C) 2009 Nuvoton 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 + +#include +#include +#include +#include + +#include "cpu.h" + +/*Here should be your evb resourse,such as LCD*/ + +static struct platform_device *nuc93x_public_dev[] __initdata = { + &nuc93x_serial_device, +}; + +/* Provide adding specific CPU platform devices API */ + +void __init nuc93x_board_init(struct platform_device **device, int size) +{ + platform_add_devices(device, size); + platform_add_devices(nuc93x_public_dev, ARRAY_SIZE(nuc93x_public_dev)); +} + diff --git a/arch/arm/mach-nuc93x/include/mach/clkdev.h b/arch/arm/mach-nuc93x/include/mach/clkdev.h new file mode 100644 index 000000000000..04b37a89801c --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-nuc93x/include/mach/entry-macro.S b/arch/arm/mach-nuc93x/include/mach/entry-macro.S new file mode 100644 index 000000000000..1352cbda3797 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/entry-macro.S @@ -0,0 +1,32 @@ +/* + * arch/arm/mach-nuc93x/include/mach/entry-macro.S + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + */ + +#include +#include + + .macro get_irqnr_preamble, base, tmp + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mov \base, #AIC_BA + + ldr \irqnr, [ \base, #AIC_IPER] + ldr \irqnr, [ \base, #AIC_ISNR] + cmp \irqnr, #0 + + .endm + + /* currently don't need an disable_fiq macro */ + + .macro disable_fiq + .endm diff --git a/arch/arm/mach-nuc93x/include/mach/hardware.h b/arch/arm/mach-nuc93x/include/mach/hardware.h new file mode 100644 index 000000000000..fb5c6fcb142e --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/hardware.h @@ -0,0 +1,22 @@ +/* + * arch/arm/mach-nuc93x/include/mach/hardware.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/io.h b/arch/arm/mach-nuc93x/include/mach/io.h new file mode 100644 index 000000000000..72e5051c7534 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/io.h @@ -0,0 +1,28 @@ +/* + * arch/arm/mach-nuc93x/include/mach/io.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * 1:1 mapping for ioremapped regions. + */ + +#define __mem_pci(a) (a) +#define __io(a) __typesafe_io(a) + +#endif diff --git a/arch/arm/mach-nuc93x/include/mach/irqs.h b/arch/arm/mach-nuc93x/include/mach/irqs.h new file mode 100644 index 000000000000..7c4aa71edb44 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/irqs.h @@ -0,0 +1,59 @@ +/* + * arch/arm/mach-nuc93x/include/mach/irqs.h + * + * Copyright (c) 2008 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. + * + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#define NUC93X_IRQ(x) (x) + +/* Main cpu interrupts */ + +#define IRQ_WDT NUC93X_IRQ(1) +#define IRQ_IRQ0 NUC93X_IRQ(2) +#define IRQ_IRQ1 NUC93X_IRQ(3) +#define IRQ_IRQ2 NUC93X_IRQ(4) +#define IRQ_IRQ3 NUC93X_IRQ(5) +#define IRQ_USBH NUC93X_IRQ(6) +#define IRQ_APU NUC93X_IRQ(7) +#define IRQ_VPOST NUC93X_IRQ(8) +#define IRQ_ADC NUC93X_IRQ(9) +#define IRQ_UART0 NUC93X_IRQ(10) +#define IRQ_TIMER0 NUC93X_IRQ(11) +#define IRQ_GPU0 NUC93X_IRQ(12) +#define IRQ_GPU1 NUC93X_IRQ(13) +#define IRQ_GPU2 NUC93X_IRQ(14) +#define IRQ_GPU3 NUC93X_IRQ(15) +#define IRQ_GPU4 NUC93X_IRQ(16) +#define IRQ_VIN NUC93X_IRQ(17) +#define IRQ_USBD NUC93X_IRQ(18) +#define IRQ_VRAMLD NUC93X_IRQ(19) +#define IRQ_GDMA0 NUC93X_IRQ(20) +#define IRQ_GDMA1 NUC93X_IRQ(21) +#define IRQ_SDIO NUC93X_IRQ(22) +#define IRQ_FMI NUC93X_IRQ(22) +#define IRQ_JPEG NUC93X_IRQ(23) +#define IRQ_SPI0 NUC93X_IRQ(24) +#define IRQ_SPI1 NUC93X_IRQ(25) +#define IRQ_RTC NUC93X_IRQ(26) +#define IRQ_PWM0 NUC93X_IRQ(27) +#define IRQ_PWM1 NUC93X_IRQ(28) +#define IRQ_PWM2 NUC93X_IRQ(29) +#define IRQ_PWM3 NUC93X_IRQ(30) +#define IRQ_I2SAC97 NUC93X_IRQ(31) +#define IRQ_CAP0 IRQ_PWM0 +#define IRQ_CAP1 IRQ_PWM1 +#define IRQ_CAP2 IRQ_PWM2 +#define IRQ_CAP3 IRQ_PWM3 +#define NR_IRQS (IRQ_I2SAC97 + 1) + +#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/map.h b/arch/arm/mach-nuc93x/include/mach/map.h new file mode 100644 index 000000000000..fd0b5e89f0e7 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/map.h @@ -0,0 +1,139 @@ +/* + * arch/arm/mach-nuc93x/include/mach/map.h + * + * Copyright (c) 2008 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. + * + */ + +#ifndef __ASM_ARCH_MAP_H +#define __ASM_ARCH_MAP_H + +#define MAP_OFFSET (0xfff00000) +#define CLK_OFFSET (0x10) + +#ifndef __ASSEMBLY__ +#define NUC93X_ADDR(x) ((void __iomem *)(0xF0000000 + ((x)&(~MAP_OFFSET)))) +#else +#define NUC93X_ADDR(x) (0xF0000000 + ((x)&(~MAP_OFFSET))) +#endif + + /* + * nuc932 hardware register definition + */ + +#define NUC93X_PA_IRQ (0xFFF83000) +#define NUC93X_PA_GCR (0xFFF00000) +#define NUC93X_PA_EBI (0xFFF01000) +#define NUC93X_PA_UART (0xFFF80000) +#define NUC93X_PA_TIMER (0xFFF81000) +#define NUC93X_PA_GPIO (0xFFF84000) +#define NUC93X_PA_GDMA (0xFFF03000) +#define NUC93X_PA_USBHOST (0xFFF0d000) +#define NUC93X_PA_I2C (0xFFF89000) +#define NUC93X_PA_LCD (0xFFF06000) +#define NUC93X_PA_GE (0xFFF05000) +#define NUC93X_PA_ADC (0xFFF85000) +#define NUC93X_PA_RTC (0xFFF87000) +#define NUC93X_PA_PWM (0xFFF82000) +#define NUC93X_PA_ACTL (0xFFF0a000) +#define NUC93X_PA_USBDEV (0xFFF0C000) +#define NUC93X_PA_JEPEG (0xFFF0e000) +#define NUC93X_PA_CACHE_T (0xFFF60000) +#define NUC93X_PA_VRAM (0xFFF0b000) +#define NUC93X_PA_DMAC (0xFFF09000) +#define NUC93X_PA_I2SM (0xFFF08000) +#define NUC93X_PA_CACHE (0xFFF02000) +#define NUC93X_PA_GPU (0xFFF04000) +#define NUC93X_PA_VIDEOIN (0xFFF07000) +#define NUC93X_PA_SPI0 (0xFFF86000) +#define NUC93X_PA_SPI1 (0xFFF88000) + + /* + * nuc932 virtual address mapping. + * interrupt controller is the first thing we put in, to make + * the assembly code for the irq detection easier + */ + +#define NUC93X_VA_IRQ NUC93X_ADDR(0x00000000) +#define NUC93X_SZ_IRQ SZ_4K + +#define NUC93X_VA_GCR NUC93X_ADDR(NUC93X_PA_IRQ) +#define NUC93X_VA_CLKPWR (NUC93X_VA_GCR+CLK_OFFSET) +#define NUC93X_SZ_GCR SZ_4K + +/* EBI management */ + +#define NUC93X_VA_EBI NUC93X_ADDR(NUC93X_PA_EBI) +#define NUC93X_SZ_EBI SZ_4K + +/* UARTs */ + +#define NUC93X_VA_UART NUC93X_ADDR(NUC93X_PA_UART) +#define NUC93X_SZ_UART SZ_4K + +/* Timers */ + +#define NUC93X_VA_TIMER NUC93X_ADDR(NUC93X_PA_TIMER) +#define NUC93X_SZ_TIMER SZ_4K + +/* GPIO ports */ + +#define NUC93X_VA_GPIO NUC93X_ADDR(NUC93X_PA_GPIO) +#define NUC93X_SZ_GPIO SZ_4K + +/* GDMA control */ + +#define NUC93X_VA_GDMA NUC93X_ADDR(NUC93X_PA_GDMA) +#define NUC93X_SZ_GDMA SZ_4K + +/* I2C hardware controller */ + +#define NUC93X_VA_I2C NUC93X_ADDR(NUC93X_PA_I2C) +#define NUC93X_SZ_I2C SZ_4K + +/* LCD controller*/ + +#define NUC93X_VA_LCD NUC93X_ADDR(NUC93X_PA_LCD) +#define NUC93X_SZ_LCD SZ_4K + +/* 2D controller*/ + +#define NUC93X_VA_GE NUC93X_ADDR(NUC93X_PA_GE) +#define NUC93X_SZ_GE SZ_4K + +/* ADC */ + +#define NUC93X_VA_ADC NUC93X_ADDR(NUC93X_PA_ADC) +#define NUC93X_SZ_ADC SZ_4K + +/* RTC */ + +#define NUC93X_VA_RTC NUC93X_ADDR(NUC93X_PA_RTC) +#define NUC93X_SZ_RTC SZ_4K + +/* Pulse Width Modulation(PWM) Registers */ + +#define NUC93X_VA_PWM NUC93X_ADDR(NUC93X_PA_PWM) +#define NUC93X_SZ_PWM SZ_4K + +/* Audio Controller controller */ + +#define NUC93X_VA_ACTL NUC93X_ADDR(NUC93X_PA_ACTL) +#define NUC93X_SZ_ACTL SZ_4K + +/* USB Device port */ + +#define NUC93X_VA_USBDEV NUC93X_ADDR(NUC93X_PA_USBDEV) +#define NUC93X_SZ_USBDEV SZ_4K + +/* USB host controller*/ +#define NUC93X_VA_USBHOST NUC93X_ADDR(NUC93X_PA_USBHOST) +#define NUC93X_SZ_USBHOST SZ_4K + +#endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/memory.h b/arch/arm/mach-nuc93x/include/mach/memory.h new file mode 100644 index 000000000000..323ab0db3f7d --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/memory.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-nuc93x/include/mach/memory.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define PHYS_OFFSET UL(0x00000000) + +#endif diff --git a/arch/arm/mach-nuc93x/include/mach/regs-clock.h b/arch/arm/mach-nuc93x/include/mach/regs-clock.h new file mode 100644 index 000000000000..5cb2954fbec2 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/regs-clock.h @@ -0,0 +1,53 @@ +/* + * arch/arm/mach-nuc93x/include/mach/regs-clock.h + * + * Copyright (c) 2008 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. + * + */ + +#ifndef __ASM_ARCH_REGS_CLOCK_H +#define __ASM_ARCH_REGS_CLOCK_H + +/* Clock Control Registers */ +#define CLK_BA NUC93X_VA_CLKPWR +#define REG_CLKEN (CLK_BA + 0x00) +#define REG_CLKSEL (CLK_BA + 0x04) +#define REG_CLKDIV (CLK_BA + 0x08) +#define REG_PLLCON0 (CLK_BA + 0x0C) +#define REG_PLLCON1 (CLK_BA + 0x10) +#define REG_PMCON (CLK_BA + 0x14) +#define REG_IRQWAKECON (CLK_BA + 0x18) +#define REG_IRQWAKEFLAG (CLK_BA + 0x1C) +#define REG_IPSRST (CLK_BA + 0x20) +#define REG_CLKEN1 (CLK_BA + 0x24) +#define REG_CLKDIV1 (CLK_BA + 0x28) + +/* Define PLL freq setting */ +#define PLL_DISABLE 0x12B63 +#define PLL_66MHZ 0x2B63 +#define PLL_100MHZ 0x4F64 +#define PLL_120MHZ 0x4F63 +#define PLL_166MHZ 0x4124 +#define PLL_200MHZ 0x4F24 + +/* Define AHB:CPUFREQ ratio */ +#define AHB_CPUCLK_1_1 0x00 +#define AHB_CPUCLK_1_2 0x01 +#define AHB_CPUCLK_1_4 0x02 +#define AHB_CPUCLK_1_8 0x03 + +/* Define APB:AHB ratio */ +#define APB_AHB_1_2 0x01 +#define APB_AHB_1_4 0x02 +#define APB_AHB_1_8 0x03 + +/* Define clock skew */ +#define DEFAULTSKEW 0x48 + +#endif /* __ASM_ARCH_REGS_CLOCK_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/regs-ebi.h b/arch/arm/mach-nuc93x/include/mach/regs-ebi.h new file mode 100644 index 000000000000..3c72550e28e4 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/regs-ebi.h @@ -0,0 +1,33 @@ +/* + * arch/arm/mach-nuc93x/include/mach/regs-ebi.h + * + * Copyright (c) 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. + * + */ + +#ifndef __ASM_ARCH_REGS_EBI_H +#define __ASM_ARCH_REGS_EBI_H + +/* EBI Control Registers */ + +#define EBI_BA NUC93X_VA_EBI +#define REG_EBICON (EBI_BA + 0x00) +#define REG_ROMCON (EBI_BA + 0x04) +#define REG_SDCONF0 (EBI_BA + 0x08) +#define REG_SDCONF1 (EBI_BA + 0x0C) +#define REG_SDTIME0 (EBI_BA + 0x10) +#define REG_SDTIME1 (EBI_BA + 0x14) +#define REG_EXT0CON (EBI_BA + 0x18) +#define REG_EXT1CON (EBI_BA + 0x1C) +#define REG_EXT2CON (EBI_BA + 0x20) +#define REG_EXT3CON (EBI_BA + 0x24) +#define REG_EXT4CON (EBI_BA + 0x28) +#define REG_CKSKEW (EBI_BA + 0x2C) + +#endif /* __ASM_ARCH_REGS_EBI_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/regs-irq.h b/arch/arm/mach-nuc93x/include/mach/regs-irq.h new file mode 100644 index 000000000000..23021592de51 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/regs-irq.h @@ -0,0 +1,42 @@ +/* + * arch/arm/mach-nuc93x/include/mach/regs-irq.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef ___ASM_ARCH_REGS_IRQ_H +#define ___ASM_ARCH_REGS_IRQ_H + +/* Advance Interrupt Controller (AIC) Registers */ + +#define AIC_BA NUC93X_VA_IRQ + +#define REG_AIC_IRQSC (AIC_BA+0x80) +#define REG_AIC_GEN (AIC_BA+0x84) +#define REG_AIC_GASR (AIC_BA+0x88) +#define REG_AIC_GSCR (AIC_BA+0x8C) +#define REG_AIC_IRSR (AIC_BA+0x100) +#define REG_AIC_IASR (AIC_BA+0x104) +#define REG_AIC_ISR (AIC_BA+0x108) +#define REG_AIC_IPER (AIC_BA+0x10C) +#define REG_AIC_ISNR (AIC_BA+0x110) +#define REG_AIC_IMR (AIC_BA+0x114) +#define REG_AIC_OISR (AIC_BA+0x118) +#define REG_AIC_MECR (AIC_BA+0x120) +#define REG_AIC_MDCR (AIC_BA+0x124) +#define REG_AIC_SSCR (AIC_BA+0x128) +#define REG_AIC_SCCR (AIC_BA+0x12C) +#define REG_AIC_EOSCR (AIC_BA+0x130) +#define AIC_IPER (0x10C) +#define AIC_ISNR (0x110) + +#endif /* ___ASM_ARCH_REGS_IRQ_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/regs-serial.h b/arch/arm/mach-nuc93x/include/mach/regs-serial.h new file mode 100644 index 000000000000..767a047a8bc2 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/regs-serial.h @@ -0,0 +1,52 @@ +/* + * arch/arm/mach-nuc93x/include/mach/regs-serial.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARM_REGS_SERIAL_H +#define __ASM_ARM_REGS_SERIAL_H + +#define UART0_BA NUC93X_VA_UART +#define UART1_BA (NUC93X_VA_UART+0x100) + +#define UART0_PA NUC93X_PA_UART +#define UART1_PA (NUC93X_PA_UART+0x100) + + +#ifndef __ASSEMBLY__ + +struct nuc93x_uart_clksrc { + const char *name; + unsigned int divisor; + unsigned int min_baud; + unsigned int max_baud; +}; + +struct nuc93x_uartcfg { + unsigned char hwport; + unsigned char unused; + unsigned short flags; + unsigned long uart_flags; + + unsigned long ucon; + unsigned long ulcon; + unsigned long ufcon; + + struct nuc93x_uart_clksrc *clocks; + unsigned int clocks_size; +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_ARM_REGS_SERIAL_H */ + diff --git a/arch/arm/mach-nuc93x/include/mach/regs-timer.h b/arch/arm/mach-nuc93x/include/mach/regs-timer.h new file mode 100644 index 000000000000..394be9614d36 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/regs-timer.h @@ -0,0 +1,28 @@ +/* + * arch/arm/mach-nuc93x/include/mach/regs-timer.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_REGS_TIMER_H +#define __ASM_ARCH_REGS_TIMER_H + +/* Timer Registers */ + +#define TMR_BA NUC93X_VA_TIMER +#define REG_TCSR0 (TMR_BA+0x00) +#define REG_TICR0 (TMR_BA+0x08) +#define REG_TDR0 (TMR_BA+0x10) +#define REG_TISR (TMR_BA+0x18) +#define REG_WTCR (TMR_BA+0x1C) + +#endif /* __ASM_ARCH_REGS_TIMER_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/system.h b/arch/arm/mach-nuc93x/include/mach/system.h new file mode 100644 index 000000000000..d26bd9a52844 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/system.h @@ -0,0 +1,28 @@ +/* + * arch/arm/machnuc93x/include/mach/system.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun + * + * Based on arch/arm/mach-s3c2410/include/mach/system.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include + +static void arch_idle(void) +{ +} + +static void arch_reset(char mode, const char *cmd) +{ + cpu_reset(0); +} + diff --git a/arch/arm/mach-nuc93x/include/mach/timex.h b/arch/arm/mach-nuc93x/include/mach/timex.h new file mode 100644 index 000000000000..0c719cc91aa9 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/timex.h @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-nuc93x/include/mach/timex.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun + * + * Based on arch/arm/mach-s3c2410/include/mach/timex.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H + +/* CLOCK_TICK_RATE Now, I don't use it. */ + +#define CLOCK_TICK_RATE 27000000 + +#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/uncompress.h b/arch/arm/mach-nuc93x/include/mach/uncompress.h new file mode 100644 index 000000000000..73082cd61e84 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/uncompress.h @@ -0,0 +1,50 @@ +/* + * arch/arm/mach-nuc93x/include/mach/uncompress.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun + * + * Based on arch/arm/mach-s3c2410/include/mach/uncompress.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +/* Defines for UART registers */ + +#include +#include +#include + +#define arch_decomp_wdog() + +#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) +static u32 * uart_base = (u32 *)UART0_PA; + +static void putc(int ch) +{ + /* Check THRE and TEMT bits before we transmit the character. + */ + while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) + barrier(); + + *uart_base = ch; +} + +static inline void flush(void) +{ +} + +static void arch_decomp_setup(void) +{ +} + +#endif/* __ASM_NUC93X_UNCOMPRESS_H */ diff --git a/arch/arm/mach-nuc93x/include/mach/vmalloc.h b/arch/arm/mach-nuc93x/include/mach/vmalloc.h new file mode 100644 index 000000000000..98a21b81dec0 --- /dev/null +++ b/arch/arm/mach-nuc93x/include/mach/vmalloc.h @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-nuc93x/include/mach/vmalloc.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun + * + * Based on arch/arm/mach-s3c2410/include/mach/vmalloc.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_VMALLOC_H +#define __ASM_ARCH_VMALLOC_H + +#define VMALLOC_END (0xE0000000) + +#endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-nuc93x/irq.c b/arch/arm/mach-nuc93x/irq.c new file mode 100644 index 000000000000..a7a88ea4ec31 --- /dev/null +++ b/arch/arm/mach-nuc93x/irq.c @@ -0,0 +1,66 @@ +/* + * linux/arch/arm/mach-nuc93x/irq.c + * + * Copyright (c) 2008 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 + +#include +#include + +#include +#include + +static void nuc93x_irq_mask(unsigned int irq) +{ + __raw_writel(1 << irq, REG_AIC_MDCR); +} + +/* + * By the w90p910 spec,any irq,only write 1 + * to REG_AIC_EOSCR for ACK + */ + +static void nuc93x_irq_ack(unsigned int irq) +{ + __raw_writel(0x01, REG_AIC_EOSCR); +} + +static void nuc93x_irq_unmask(unsigned int irq) +{ + __raw_writel(1 << irq, REG_AIC_MECR); + +} + +static struct irq_chip nuc93x_irq_chip = { + .ack = nuc93x_irq_ack, + .mask = nuc93x_irq_mask, + .unmask = nuc93x_irq_unmask, +}; + +void __init nuc93x_init_irq(void) +{ + int irqno; + + __raw_writel(0xFFFFFFFE, REG_AIC_MDCR); + + for (irqno = IRQ_WDT; irqno <= NR_IRQS; irqno++) { + set_irq_chip(irqno, &nuc93x_irq_chip); + set_irq_handler(irqno, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } +} diff --git a/arch/arm/mach-nuc93x/mach-nuc932evb.c b/arch/arm/mach-nuc93x/mach-nuc932evb.c new file mode 100644 index 000000000000..9f79266f08e2 --- /dev/null +++ b/arch/arm/mach-nuc93x/mach-nuc932evb.c @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/mach-w90x900/mach-nuc910evb.c + * + * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche + * + * Copyright (C) 2008 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 "nuc932.h" + +static void __init nuc932evb_map_io(void) +{ + nuc932_map_io(); + nuc932_init_clocks(); + nuc932_init_uartclk(); +} + +static void __init nuc932evb_init(void) +{ + nuc932_board_init(); +} + +MACHINE_START(NUC932EVB, "NUC932EVB") + /* Maintainer: Wan ZongShun */ + .phys_io = NUC93X_PA_UART, + .io_pg_offst = (((u32)NUC93X_VA_UART) >> 18) & 0xfffc, + .boot_params = 0, + .map_io = nuc932evb_map_io, + .init_irq = nuc93x_init_irq, + .init_machine = nuc932evb_init, + .timer = &nuc93x_timer, +MACHINE_END diff --git a/arch/arm/mach-nuc93x/nuc932.c b/arch/arm/mach-nuc93x/nuc932.c new file mode 100644 index 000000000000..3966ead686fc --- /dev/null +++ b/arch/arm/mach-nuc93x/nuc932.c @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/mach-nuc93x/nuc932.c + * + * Copyright (c) 2009 Nuvoton corporation. + * + * Wan ZongShun + * + * NUC932 cpu support + * + * 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 "cpu.h" +#include "clock.h" + +/* define specific CPU platform device */ + +static struct platform_device *nuc932_dev[] __initdata = { +}; + +/* define specific CPU platform io map */ + +static struct map_desc nuc932evb_iodesc[] __initdata = { +}; + +/*Init NUC932 evb io*/ + +void __init nuc932_map_io(void) +{ + nuc93x_map_io(nuc932evb_iodesc, ARRAY_SIZE(nuc932evb_iodesc)); +} + +/*Init NUC932 clock*/ + +void __init nuc932_init_clocks(void) +{ + nuc93x_init_clocks(); +} + +/*enable NUC932 uart clock*/ + +void __init nuc932_init_uartclk(void) +{ + struct clk *ck_uart = clk_get(NULL, "uart"); + BUG_ON(IS_ERR(ck_uart)); + + clk_enable(ck_uart); +} + +/*Init NUC932 board info*/ + +void __init nuc932_board_init(void) +{ + nuc93x_board_init(nuc932_dev, ARRAY_SIZE(nuc932_dev)); +} diff --git a/arch/arm/mach-nuc93x/nuc932.h b/arch/arm/mach-nuc93x/nuc932.h new file mode 100644 index 000000000000..9a66edd5338f --- /dev/null +++ b/arch/arm/mach-nuc93x/nuc932.h @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-nuc93x/nuc932.h + * + * Copyright (c) 2008 Nuvoton corporation + * + * Header file for NUC93x CPU support + * + * Wan ZongShun + * + * 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. + * + */ + +struct map_desc; +struct sys_timer; + +/* core initialisation functions */ + +extern void nuc93x_init_irq(void); +extern struct sys_timer nuc93x_timer; + +/* extern file from nuc932.c */ + +extern void nuc932_board_init(void); +extern void nuc932_init_clocks(void); +extern void nuc932_map_io(void); +extern void nuc932_init_uartclk(void); diff --git a/arch/arm/mach-nuc93x/time.c b/arch/arm/mach-nuc93x/time.c new file mode 100644 index 000000000000..2f90f9dc6e30 --- /dev/null +++ b/arch/arm/mach-nuc93x/time.c @@ -0,0 +1,100 @@ +/* + * linux/arch/arm/mach-nuc93x/time.c + * + * Copyright (c) 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define RESETINT 0x01 +#define PERIOD (0x01 << 27) +#define ONESHOT (0x00 << 27) +#define COUNTEN (0x01 << 30) +#define INTEN (0x01 << 29) + +#define TICKS_PER_SEC 100 +#define PRESCALE 0x63 /* Divider = prescale + 1 */ + +unsigned int timer0_load; + +static unsigned long nuc93x_gettimeoffset(void) +{ + return 0; +} + +/*IRQ handler for the timer*/ + +static irqreturn_t nuc93x_timer_interrupt(int irq, void *dev_id) +{ + timer_tick(); + __raw_writel(0x01, REG_TISR); /* clear TIF0 */ + return IRQ_HANDLED; +} + +static struct irqaction nuc93x_timer_irq = { + .name = "nuc93x Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = nuc93x_timer_interrupt, +}; + +/*Set up timer reg.*/ + +static void nuc93x_timer_setup(void) +{ + struct clk *ck_ext = clk_get(NULL, "ext"); + struct clk *ck_timer = clk_get(NULL, "timer"); + unsigned int rate, val = 0; + + BUG_ON(IS_ERR(ck_ext) || IS_ERR(ck_timer)); + + clk_enable(ck_timer); + rate = clk_get_rate(ck_ext); + clk_put(ck_ext); + rate = rate / (PRESCALE + 0x01); + + /* set a known state */ + __raw_writel(0x00, REG_TCSR0); + __raw_writel(RESETINT, REG_TISR); + + timer0_load = (rate / TICKS_PER_SEC); + __raw_writel(timer0_load, REG_TICR0); + + val |= (PERIOD | COUNTEN | INTEN | PRESCALE);; + __raw_writel(val, REG_TCSR0); + +} + +static void __init nuc93x_timer_init(void) +{ + nuc93x_timer_setup(); + setup_irq(IRQ_TIMER0, &nuc93x_timer_irq); +} + +struct sys_timer nuc93x_timer = { + .init = nuc93x_timer_init, + .offset = nuc93x_gettimeoffset, + .resume = nuc93x_timer_setup +}; -- GitLab From e00d9d4b1796dae3adf6e39c9a766e760dd1c796 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sat, 9 Jan 2010 13:03:59 +0100 Subject: [PATCH 1288/3892] ARM: 5869/1: ixp4xx: implement sched_clock() Add a better sched_clock() to the ixp4xx platform, implemented via its clocksource support. This is based on the sched_clock() I implemented for the IOP platform. Tested on a ds101 ixp420 machine. Signed-off-by: Mikael Pettersson Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 3bbf40f6d964..71728d36d501 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -426,6 +426,17 @@ static void __init ixp4xx_clocksource_init(void) clocksource_register(&clocksource_ixp4xx); } +/* + * sched_clock() + */ +unsigned long long sched_clock(void) +{ + cycle_t cyc = ixp4xx_get_cycles(NULL); + struct clocksource *cs = &clocksource_ixp4xx; + + return clocksource_cyc2ns(cyc, cs->mult, cs->shift); +} + /* * clockevents */ -- GitLab From b09f3e78ee7bb69171411b75bd9e771fc7f24749 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Jan 2010 00:01:53 +0100 Subject: [PATCH 1289/3892] ALSA: hda - Allow override more fields via patch loader Allow the override of vendor-id, subsystem-id, revision-id and chip name via patch loading. Updated the document, too. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 27 ++++++++++++++ sound/pci/hda/hda_hwdep.c | 53 +++++++++++++++++++-------- 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 6325bec06a72..f4dd3bf99d12 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -452,6 +452,33 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs` sysfs entries, and the lines after `[hint]` are parsed as `hints` sysfs entries, respectively. +Another example to override the codec vendor id from 0x12345678 to +0xdeadbeef is like below: +------------------------------------------------------------------------ + [codec] + 0x12345678 0xabcd1234 2 + + [vendor_id] + 0xdeadbeef +------------------------------------------------------------------------ + +In the similar way, you can override the codec subsystem_id via +`[subsystem_id]`, the revision id via `[revision_id]` line. +Also, the codec chip name can be rewritten via `[chip_name]` line. +------------------------------------------------------------------------ + [codec] + 0x12345678 0xabcd1234 2 + + [subsystem_id] + 0xffff1111 + + [revision_id] + 0x10 + + [chip_name] + My-own NEWS-0002 +------------------------------------------------------------------------ + The hd-audio driver reads the file via request_firmware(). Thus, a patch file has to be located on the appropriate firmware path, typically, /lib/firmware. For example, when you pass the option diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index b36919c0d363..a1fc83753cc6 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -625,6 +625,10 @@ enum { LINE_MODE_PINCFG, LINE_MODE_VERB, LINE_MODE_HINT, + LINE_MODE_VENDOR_ID, + LINE_MODE_SUBSYSTEM_ID, + LINE_MODE_REVISION_ID, + LINE_MODE_CHIP_NAME, NUM_LINE_MODES, }; @@ -654,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus, } /* parse the contents after the other command tags, [pincfg], [verb], - * [hint] and [model] + * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model] * just pass to the sysfs helper (only when any codec was specified) */ static void parse_pincfg_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - if (!*codecp) - return; parse_user_pin_configs(*codecp, buf); } static void parse_verb_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - if (!*codecp) - return; parse_init_verbs(*codecp, buf); } static void parse_hint_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - if (!*codecp) - return; parse_hints(*codecp, buf); } static void parse_model_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - if (!*codecp) - return; kfree((*codecp)->modelname); (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); } +static void parse_chip_name_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + kfree((*codecp)->chip_name); + (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL); +} + +#define DEFINE_PARSE_ID_MODE(name) \ +static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ + struct hda_codec **codecp) \ +{ \ + unsigned long val; \ + if (!strict_strtoul(buf, 0, &val)) \ + (*codecp)->name = val; \ +} + +DEFINE_PARSE_ID_MODE(vendor_id); +DEFINE_PARSE_ID_MODE(subsystem_id); +DEFINE_PARSE_ID_MODE(revision_id); + + struct hda_patch_item { const char *tag; void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); + int need_codec; }; static struct hda_patch_item patch_items[NUM_LINE_MODES] = { - [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode }, - [LINE_MODE_MODEL] = { "[model]", parse_model_mode }, - [LINE_MODE_VERB] = { "[verb]", parse_verb_mode }, - [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode }, - [LINE_MODE_HINT] = { "[hint]", parse_hint_mode }, + [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 }, + [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 }, + [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 }, + [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 }, + [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 }, + [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 }, + [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 }, + [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 }, + [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 }, }; /* check the line starting with '[' -- change the parser mode accodingly */ @@ -783,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch) continue; if (*buf == '[') line_mode = parse_line_mode(buf, bus); - else if (patch_items[line_mode].parser) + else if (patch_items[line_mode].parser && + (codec || !patch_items[line_mode].need_codec)) patch_items[line_mode].parser(buf, bus, &codec); } release_firmware(fw); -- GitLab From 2854e72b58dad82f5248b30a45dda0df49e5fe05 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 27 Jan 2010 17:32:22 +0100 Subject: [PATCH 1290/3892] x86: Use helpers for rlimits Make sure compiler won't do weird things with limits. Fetching them twice may return 2 different values after writable limits are implemented. We can either use rlimit helpers added in 3e10e716abf3c71bdb5d86b8f507f9e72236c9cd or ACCESS_ONCE if not applicable; this patch uses the helpers. Signed-off-by: Jiri Slaby LKML-Reference: <1264609942-24621-1-git-send-email-jslaby@suse.cz> Cc: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: H. Peter Anvin --- arch/x86/ia32/ia32_aout.c | 2 +- arch/x86/mm/mmap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 2a4d073d2cf1..06474788723f 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -297,7 +297,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) * size limits imposed on them by creating programs with large * arrays in the data or bss. */ - rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; + rlim = rlimit(RLIMIT_DATA); if (rlim >= RLIM_INFINITY) rlim = ~0; if (ex.a_data + ex.a_bss > rlim) diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index c8191defc38a..1dab5194fd9d 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -71,7 +71,7 @@ static int mmap_is_legacy(void) if (current->personality & ADDR_COMPAT_LAYOUT) return 1; - if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) + if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) return 1; return sysctl_legacy_va_layout; @@ -96,7 +96,7 @@ static unsigned long mmap_rnd(void) static unsigned long mmap_base(void) { - unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; + unsigned long gap = rlimit(RLIMIT_STACK); if (gap < MIN_GAP) gap = MIN_GAP; -- GitLab From f655f5e956eaf4fcda983f3b3d37c76371556c27 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 28 Jan 2010 15:08:21 +0900 Subject: [PATCH 1291/3892] sh: mach-titan: Kill off unused PIO port mangling. Nothing is using this, kill it off. Fixing up access sizes can be done with trapped I/O for anyone wanting to make use of this for devices that need it, everything else is already pure MMIO. Signed-off-by: Paul Mundt --- arch/sh/Makefile | 1 - arch/sh/boards/Makefile | 1 + .../{mach-titan/setup.c => board-titan.c} | 24 +--- arch/sh/boards/mach-titan/Makefile | 5 - arch/sh/boards/mach-titan/io.c | 108 ------------------ 5 files changed, 3 insertions(+), 136 deletions(-) rename arch/sh/boards/{mach-titan/setup.c => board-titan.c} (56%) delete mode 100644 arch/sh/boards/mach-titan/Makefile delete mode 100644 arch/sh/boards/mach-titan/io.c diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 30c80fd29058..588579ac2e35 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -149,7 +149,6 @@ machdir-$(CONFIG_SH_X3PROTO) += mach-x3proto machdir-$(CONFIG_SH_SH7763RDP) += mach-sh7763rdp machdir-$(CONFIG_SH_SH4202_MICRODEV) += mach-microdev machdir-$(CONFIG_SH_LANDISK) += mach-landisk -machdir-$(CONFIG_SH_TITAN) += mach-titan machdir-$(CONFIG_SH_LBOX_RE2) += mach-lboxre2 machdir-$(CONFIG_SH_CAYMAN) += mach-cayman machdir-$(CONFIG_SH_RSK) += mach-rsk diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile index ce0f26381784..4f90f9b7a922 100644 --- a/arch/sh/boards/Makefile +++ b/arch/sh/boards/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_SH_SHMIN) += board-shmin.o obj-$(CONFIG_SH_EDOSK7760) += board-edosk7760.o obj-$(CONFIG_SH_ESPT) += board-espt.o obj-$(CONFIG_SH_POLARIS) += board-polaris.o +obj-$(CONFIG_SH_TITAN) += board-titan.o diff --git a/arch/sh/boards/mach-titan/setup.c b/arch/sh/boards/board-titan.c similarity index 56% rename from arch/sh/boards/mach-titan/setup.c rename to arch/sh/boards/board-titan.c index 81e7e0f03863..94c36c7bc0b3 100644 --- a/arch/sh/boards/mach-titan/setup.c +++ b/arch/sh/boards/board-titan.c @@ -19,26 +19,6 @@ static void __init init_titan_irq(void) } static struct sh_machine_vector mv_titan __initmv = { - .mv_name = "Titan", - - .mv_inb = titan_inb, - .mv_inw = titan_inw, - .mv_inl = titan_inl, - .mv_outb = titan_outb, - .mv_outw = titan_outw, - .mv_outl = titan_outl, - - .mv_inb_p = titan_inb_p, - .mv_inw_p = titan_inw, - .mv_inl_p = titan_inl, - .mv_outb_p = titan_outb_p, - .mv_outw_p = titan_outw, - .mv_outl_p = titan_outl, - - .mv_insl = titan_insl, - .mv_outsl = titan_outsl, - - .mv_ioport_map = titan_ioport_map, - - .mv_init_irq = init_titan_irq, + .mv_name = "Titan", + .mv_init_irq = init_titan_irq, }; diff --git a/arch/sh/boards/mach-titan/Makefile b/arch/sh/boards/mach-titan/Makefile deleted file mode 100644 index 08d753700062..000000000000 --- a/arch/sh/boards/mach-titan/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the Nimble Microsystems TITAN specific parts of the kernel -# - -obj-y := setup.o io.o diff --git a/arch/sh/boards/mach-titan/io.c b/arch/sh/boards/mach-titan/io.c deleted file mode 100644 index 29754c5091f0..000000000000 --- a/arch/sh/boards/mach-titan/io.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * I/O routines for Titan - */ -#include -#include -#include -#include -#include - -static inline unsigned int port2adr(unsigned int port) -{ - maybebadio((unsigned long)port); - return port; -} - -u8 titan_inb(unsigned long port) -{ - if (PXSEG(port)) - return __raw_readb(port); - return __raw_readw(port2adr(port)) & 0xff; -} - -u8 titan_inb_p(unsigned long port) -{ - u8 v; - - if (PXSEG(port)) - v = __raw_readb(port); - else - v = __raw_readw(port2adr(port)) & 0xff; - ctrl_delay(); - return v; -} - -u16 titan_inw(unsigned long port) -{ - if (PXSEG(port)) - return __raw_readw(port); - else if (port >= 0x2000) - return __raw_readw(port2adr(port)); - else - maybebadio(port); - return 0; -} - -u32 titan_inl(unsigned long port) -{ - if (PXSEG(port)) - return __raw_readl(port); - else if (port >= 0x2000) - return __raw_readw(port2adr(port)); - else - maybebadio(port); - return 0; -} - -void titan_outb(u8 value, unsigned long port) -{ - if (PXSEG(port)) - __raw_writeb(value, port); - else - __raw_writew(value, port2adr(port)); -} - -void titan_outb_p(u8 value, unsigned long port) -{ - if (PXSEG(port)) - __raw_writeb(value, port); - else - __raw_writew(value, port2adr(port)); - ctrl_delay(); -} - -void titan_outw(u16 value, unsigned long port) -{ - if (PXSEG(port)) - __raw_writew(value, port); - else if (port >= 0x2000) - __raw_writew(value, port2adr(port)); - else - maybebadio(port); -} - -void titan_outl(u32 value, unsigned long port) -{ - if (PXSEG(port)) - __raw_writel(value, port); - else - maybebadio(port); -} - -void titan_insl(unsigned long port, void *dst, unsigned long count) -{ - maybebadio(port); -} - -void titan_outsl(unsigned long port, const void *src, unsigned long count) -{ - maybebadio(port); -} - -void __iomem *titan_ioport_map(unsigned long port, unsigned int size) -{ - if (PXSEG(port)) - return (void __iomem *)port; - - return (void __iomem *)port2adr(port); -} -- GitLab From 439913fffd39374c3737186b22d2d56c3a0ae526 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 28 Jan 2010 10:53:19 +0800 Subject: [PATCH 1292/3892] ACPI: replace acpi_integer by u64 acpi_integer is now obsolete and removed from the ACPICA code base, replaced by u64. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- arch/ia64/hp/common/aml_nfw.c | 6 ++-- arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 6 ++-- drivers/acpi/battery.c | 4 +-- drivers/acpi/ec.c | 4 +-- drivers/acpi/glue.c | 4 +-- drivers/acpi/osl.c | 4 +-- drivers/acpi/power_meter.c | 30 ++++++++-------- drivers/acpi/processor_idle.c | 2 +- drivers/acpi/processor_throttling.c | 24 ++++++------- drivers/acpi/utils.c | 16 ++++----- drivers/acpi/video.c | 2 +- drivers/ata/libata-acpi.c | 4 +-- drivers/ide/ide-acpi.c | 8 ++--- drivers/input/misc/atlas_btns.c | 2 +- drivers/pci/pci-acpi.c | 2 +- drivers/platform/x86/toshiba_bluetooth.c | 4 +-- drivers/platform/x86/wmi.c | 4 +-- include/acpi/acpi_bus.h | 6 ++-- include/acpi/processor.h | 42 +++++++++++------------ 19 files changed, 87 insertions(+), 87 deletions(-) diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c index 4abd2c79bb1d..22078486d35d 100644 --- a/arch/ia64/hp/common/aml_nfw.c +++ b/arch/ia64/hp/common/aml_nfw.c @@ -77,7 +77,7 @@ static void aml_nfw_execute(struct ia64_nfw_context *c) c->arg[4], c->arg[5], c->arg[6], c->arg[7]); } -static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value) +static void aml_nfw_read_arg(u8 *offset, u32 bit_width, u64 *value) { switch (bit_width) { case 8: @@ -95,7 +95,7 @@ static void aml_nfw_read_arg(u8 *offset, u32 bit_width, acpi_integer *value) } } -static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value) +static void aml_nfw_write_arg(u8 *offset, u32 bit_width, u64 *value) { switch (bit_width) { case 8: @@ -114,7 +114,7 @@ static void aml_nfw_write_arg(u8 *offset, u32 bit_width, acpi_integer *value) } static acpi_status aml_nfw_handler(u32 function, acpi_physical_address address, - u32 bit_width, acpi_integer *value, void *handler_context, + u32 bit_width, u64 *value, void *handler_context, void *region_context) { struct ia64_nfw_context *context = handler_context; diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index f125e5c551c0..55d42bc443e8 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c @@ -806,7 +806,7 @@ static int find_psb_table(struct powernow_k8_data *data) static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { - acpi_integer control; + u64 control; if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) return; @@ -824,7 +824,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { struct cpufreq_frequency_table *powernow_table; int ret_val = -ENODEV; - acpi_integer control, status; + u64 control, status; if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { dprintk("register performance failed: bad ACPI data\n"); @@ -948,7 +948,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, u32 fid; u32 vid; u32 freq, index; - acpi_integer status, control; + u64 status, control; if (data->exttype) { status = data->acpi_data.states[i].status; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index cada73ffdfa7..58d2c91ba62b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -324,8 +324,8 @@ static int extract_package(struct acpi_battery *battery, strncpy(ptr, element->string.pointer, 32); else if (element->type == ACPI_TYPE_INTEGER) { strncpy(ptr, (u8 *)&element->integer.value, - sizeof(acpi_integer)); - ptr[sizeof(acpi_integer)] = 0; + sizeof(u64)); + ptr[sizeof(u64)] = 0; } else *ptr = 0; /* don't have value */ } else { diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d6471bb6852f..748ced85dec5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -589,7 +589,7 @@ static u32 acpi_ec_gpe_handler(void *data) static acpi_status acpi_ec_space_handler(u32 function, acpi_physical_address address, - u32 bits, acpi_integer *value, + u32 bits, u64 *value, void *handler_context, void *region_context) { struct acpi_ec *ec = handler_context; @@ -620,7 +620,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, ++address; if (function == ACPI_READ) { result = acpi_ec_read(ec, address, &temp); - (*value) |= ((acpi_integer)temp) << i; + (*value) |= ((u64)temp) << i; } else { temp = 0xff & ((*value) >> i); result = acpi_ec_write(ec, address, temp); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 4c8fcff662cf..6d5b64b7d526 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -87,7 +87,7 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) /* Get device's handler per its address under its parent */ struct acpi_find_child { acpi_handle handle; - acpi_integer address; + u64 address; }; static acpi_status @@ -106,7 +106,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) +acpi_handle acpi_get_child(acpi_handle parent, u64 address) { struct acpi_find_child find = { NULL, address }; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 02e8464e480f..8e6d8665f0ae 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -436,7 +436,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) * Running in interpreter thread context, safe to sleep */ -void acpi_os_sleep(acpi_integer ms) +void acpi_os_sleep(u64 ms) { schedule_timeout_interruptible(msecs_to_jiffies(ms)); } @@ -603,7 +603,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, acpi_status acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, - acpi_integer value, u32 width) + u64 value, u32 width) { int result, size; diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c index dc4ffadf8122..834c5af0de4b 100644 --- a/drivers/acpi/power_meter.c +++ b/drivers/acpi/power_meter.c @@ -71,17 +71,17 @@ static const struct acpi_device_id power_meter_ids[] = { MODULE_DEVICE_TABLE(acpi, power_meter_ids); struct acpi_power_meter_capabilities { - acpi_integer flags; - acpi_integer units; - acpi_integer type; - acpi_integer accuracy; - acpi_integer sampling_time; - acpi_integer min_avg_interval; - acpi_integer max_avg_interval; - acpi_integer hysteresis; - acpi_integer configurable_cap; - acpi_integer min_cap; - acpi_integer max_cap; + u64 flags; + u64 units; + u64 type; + u64 accuracy; + u64 sampling_time; + u64 min_avg_interval; + u64 max_avg_interval; + u64 hysteresis; + u64 configurable_cap; + u64 min_cap; + u64 max_cap; }; struct acpi_power_meter_resource { @@ -93,9 +93,9 @@ struct acpi_power_meter_resource { acpi_string model_number; acpi_string serial_number; acpi_string oem_info; - acpi_integer power; - acpi_integer cap; - acpi_integer avg_interval; + u64 power; + u64 cap; + u64 avg_interval; int sensors_valid; unsigned long sensors_last_updated; struct sensor_device_attribute sensors[NUM_SENSORS]; @@ -402,7 +402,7 @@ static ssize_t show_val(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_power_meter_resource *resource = acpi_dev->driver_data; - acpi_integer val = 0; + u64 val = 0; switch (attr->index) { case 0: diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 7c0441f63b39..3455d7abf5f3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -352,7 +352,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr) static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) { acpi_status status = 0; - acpi_integer count; + u64 count; int current_count; int i; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 1c5d7a8b2fdf..7ded7542fc9d 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -660,7 +660,7 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) #ifdef CONFIG_X86 static int acpi_throttling_rdmsr(struct acpi_processor *pr, - acpi_integer * value) + u64 *value) { struct cpuinfo_x86 *c; u64 msr_high, msr_low; @@ -681,13 +681,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr, rdmsr_safe(MSR_IA32_THERM_CONTROL, (u32 *)&msr_low , (u32 *) &msr_high); msr = (msr_high << 32) | msr_low; - *value = (acpi_integer) msr; + *value = (u64) msr; ret = 0; } return ret; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value) +static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) { struct cpuinfo_x86 *c; unsigned int cpu; @@ -711,14 +711,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value) } #else static int acpi_throttling_rdmsr(struct acpi_processor *pr, - acpi_integer * value) + u64 *value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); return -1; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value) +static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); @@ -727,7 +727,7 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value) #endif static int acpi_read_throttling_status(struct acpi_processor *pr, - acpi_integer *value) + u64 *value) { u32 bit_width, bit_offset; u64 ptc_value; @@ -746,7 +746,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, address, (u32 *) &ptc_value, (u32) (bit_width + bit_offset)); ptc_mask = (1 << bit_width) - 1; - *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask); + *value = (u64) ((ptc_value >> bit_offset) & ptc_mask); ret = 0; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: @@ -760,7 +760,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, } static int acpi_write_throttling_state(struct acpi_processor *pr, - acpi_integer value) + u64 value) { u32 bit_width, bit_offset; u64 ptc_value; @@ -793,7 +793,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr, } static int acpi_get_throttling_state(struct acpi_processor *pr, - acpi_integer value) + u64 value) { int i; @@ -808,7 +808,7 @@ static int acpi_get_throttling_state(struct acpi_processor *pr, } static int acpi_get_throttling_value(struct acpi_processor *pr, - int state, acpi_integer *value) + int state, u64 *value) { int ret = -1; @@ -826,7 +826,7 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) { int state = 0; int ret; - acpi_integer value; + u64 value; if (!pr) return -EINVAL; @@ -993,7 +993,7 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, int state, bool force) { int ret; - acpi_integer value; + u64 value; if (!pr) return -EINVAL; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 811fec10462b..11882dbe2094 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -107,12 +107,12 @@ acpi_extract_package(union acpi_object *package, case ACPI_TYPE_INTEGER: switch (format_string[i]) { case 'N': - size_required += sizeof(acpi_integer); - tail_offset += sizeof(acpi_integer); + size_required += sizeof(u64); + tail_offset += sizeof(u64); break; case 'S': size_required += - sizeof(char *) + sizeof(acpi_integer) + + sizeof(char *) + sizeof(u64) + sizeof(char); tail_offset += sizeof(char *); break; @@ -193,17 +193,17 @@ acpi_extract_package(union acpi_object *package, case ACPI_TYPE_INTEGER: switch (format_string[i]) { case 'N': - *((acpi_integer *) head) = + *((u64 *) head) = element->integer.value; - head += sizeof(acpi_integer); + head += sizeof(u64); break; case 'S': pointer = (u8 **) head; *pointer = tail; - *((acpi_integer *) tail) = + *((u64 *) tail) = element->integer.value; - head += sizeof(acpi_integer *); - tail += sizeof(acpi_integer); + head += sizeof(u64 *); + tail += sizeof(u64); /* NULL terminate string */ *tail = (char)0; tail += sizeof(char); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b765790b32be..6e9b49149fce 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -759,7 +759,7 @@ acpi_video_bus_POST_options(struct acpi_video_bus *video, static int acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) { - acpi_integer status = 0; + u64 status = 0; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 1245838ac13d..292fdbc0431a 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -64,7 +64,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap) WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); if (!sata_pmp_attached(ap)) { - acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + u64 adr = SATA_ADR(ap->port_no, NO_PORT_MULT); ap->link.device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); @@ -74,7 +74,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap) ap->link.device->acpi_handle = NULL; ata_for_each_link(link, ap, EDGE) { - acpi_integer adr = SATA_ADR(ap->port_no, link->pmp); + u64 adr = SATA_ADR(ap->port_no, link->pmp); link->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index c0cf45a11b93..5cb01e5c323c 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -108,11 +108,11 @@ bool ide_port_acpi(ide_hwif_t *hwif) * Returns 0 on success, <0 on error. */ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, - acpi_integer *pcidevfn) + u64 *pcidevfn) { struct pci_dev *pdev = to_pci_dev(dev); unsigned int bus, devnum, func; - acpi_integer addr; + u64 addr; acpi_handle dev_handle; acpi_status status; struct acpi_device_info *dinfo = NULL; @@ -122,7 +122,7 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, devnum = PCI_SLOT(pdev->devfn); func = PCI_FUNC(pdev->devfn); /* ACPI _ADR encoding for PCI bus: */ - addr = (acpi_integer)(devnum << 16 | func); + addr = (u64)(devnum << 16 | func); DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); @@ -169,7 +169,7 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) { struct device *dev = hwif->gendev.parent; acpi_handle uninitialized_var(dev_handle); - acpi_integer pcidevfn; + u64 pcidevfn; acpi_handle chan_handle; int err; diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 1b871917340a..dfaa9a045ed8 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -47,7 +47,7 @@ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle, static acpi_status acpi_atlas_button_handler(u32 function, acpi_physical_address address, - u32 bit_width, acpi_integer *value, + u32 bit_width, u64 *value, void *handler_context, void *region_context) { acpi_status status; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 7e2829538a4c..441326c44138 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -143,7 +143,7 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) { struct pci_dev * pci_dev; - acpi_integer addr; + u64 addr; pci_dev = to_pci_dev(dev); /* Please ref to ACPI spec for the syntax of _ADR */ diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index a350418e87ea..944068611919 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -57,7 +57,7 @@ static struct acpi_driver toshiba_bt_rfkill_driver = { static int toshiba_bluetooth_enable(acpi_handle handle) { acpi_status res1, res2; - acpi_integer result; + u64 result; /* * Query ACPI to verify RFKill switch is set to 'on'. @@ -95,7 +95,7 @@ static int toshiba_bt_resume(struct acpi_device *device) static int toshiba_bt_rfkill_add(struct acpi_device *device) { acpi_status status; - acpi_integer bt_present; + u64 bt_present; int result = -ENODEV; /* diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index b104302fea0a..09e9918c69c1 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -796,7 +796,7 @@ static __init acpi_status parse_wdg(acpi_handle handle) */ static acpi_status acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, - u32 bits, acpi_integer * value, + u32 bits, u64 *value, void *handler_context, void *region_context) { int result = 0, i = 0; @@ -813,7 +813,7 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, if (function == ACPI_READ) { result = ec_read(address, &temp); - (*value) |= ((acpi_integer)temp) << i; + (*value) |= ((u64)temp) << i; } else { temp = 0xff & ((*value) >> i); result = ec_write(address, temp); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3cd9ccdcbd8f..71c105c9b0ee 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -250,8 +250,8 @@ struct acpi_device_wakeup_state { struct acpi_device_wakeup { acpi_handle gpe_device; - acpi_integer gpe_number; - acpi_integer sleep_state; + u64 gpe_number; + u64 sleep_state; struct acpi_handle_list resources; struct acpi_device_wakeup_state state; struct acpi_device_wakeup_flags flags; @@ -380,7 +380,7 @@ struct acpi_pci_root { }; /* helper */ -acpi_handle acpi_get_child(acpi_handle, acpi_integer); +acpi_handle acpi_get_child(acpi_handle, u64); int acpi_is_root_bridge(acpi_handle); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 0ea5ef4eb6a9..29831768c0e6 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -92,11 +92,11 @@ struct acpi_processor_power { /* Performance Management */ struct acpi_psd_package { - acpi_integer num_entries; - acpi_integer revision; - acpi_integer domain; - acpi_integer coord_type; - acpi_integer num_processors; + u64 num_entries; + u64 revision; + u64 domain; + u64 coord_type; + u64 num_processors; } __attribute__ ((packed)); struct acpi_pct_register { @@ -110,12 +110,12 @@ struct acpi_pct_register { } __attribute__ ((packed)); struct acpi_processor_px { - acpi_integer core_frequency; /* megahertz */ - acpi_integer power; /* milliWatts */ - acpi_integer transition_latency; /* microseconds */ - acpi_integer bus_master_latency; /* microseconds */ - acpi_integer control; /* control value */ - acpi_integer status; /* success indicator */ + u64 core_frequency; /* megahertz */ + u64 power; /* milliWatts */ + u64 transition_latency; /* microseconds */ + u64 bus_master_latency; /* microseconds */ + u64 control; /* control value */ + u64 status; /* success indicator */ }; struct acpi_processor_performance { @@ -133,11 +133,11 @@ struct acpi_processor_performance { /* Throttling Control */ struct acpi_tsd_package { - acpi_integer num_entries; - acpi_integer revision; - acpi_integer domain; - acpi_integer coord_type; - acpi_integer num_processors; + u64 num_entries; + u64 revision; + u64 domain; + u64 coord_type; + u64 num_processors; } __attribute__ ((packed)); struct acpi_ptc_register { @@ -151,11 +151,11 @@ struct acpi_ptc_register { } __attribute__ ((packed)); struct acpi_processor_tx_tss { - acpi_integer freqpercentage; /* */ - acpi_integer power; /* milliWatts */ - acpi_integer transition_latency; /* microseconds */ - acpi_integer control; /* control value */ - acpi_integer status; /* success indicator */ + u64 freqpercentage; /* */ + u64 power; /* milliWatts */ + u64 transition_latency; /* microseconds */ + u64 control; /* control value */ + u64 status; /* success indicator */ }; struct acpi_processor_tx { u16 power; -- GitLab From 621266bdf4b78fa92f7eabd7688b86f0dbd61d64 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 28 Jan 2010 15:55:37 +0900 Subject: [PATCH 1293/3892] sh: Quiet noisy coherent DMA unmapping on R2D. IRQs are re-enabled at a later stage when doing the unmapping on R2D via the sm501 USB coherent DMA, resulting in the irqs_disabled() check producing considerable noise for this configuration. Just kill off the check, which was blindly copied from x86 anyways. Signed-off-by: Paul Mundt --- arch/sh/include/asm/dma-mapping.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 87ced133a363..bea3337a426a 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -89,8 +89,6 @@ static inline void dma_free_coherent(struct device *dev, size_t size, { struct dma_map_ops *ops = get_dma_ops(dev); - WARN_ON(irqs_disabled()); /* for portability */ - if (dma_release_from_coherent(dev, get_order(size), vaddr)) return; -- GitLab From 849593591ce3b5f9352966c9d410284dc04d03b6 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 28 Jan 2010 18:15:05 +0900 Subject: [PATCH 1294/3892] sh: Fix up read-only variable assignment in pcibios_align_resource(). arch/sh/drivers/pci/pci.c:167: error: assignment of read-only location '*res' Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index c481df639022..191075e91cda 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -162,10 +162,8 @@ void pcibios_align_resource(void *data, struct resource *res, /* * Put everything into 0x00-0xff region modulo 0x400. */ - if (start & 0x300) { + if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; - res->start = start; - } } else if (res->flags & IORESOURCE_MEM) { if (start < PCIBIOS_MIN_MEM + chan->mem_resource->start) start = PCIBIOS_MIN_MEM + chan->mem_resource->start; -- GitLab From d627a2ebd1a303aa4ac1962c553d1e8738735d01 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 28 Jan 2010 18:17:29 +0900 Subject: [PATCH 1295/3892] sh: Fix up the ioremap_fixed() build for nommu. arch/sh/kernel/setup.c:455: error: implicit declaration of function 'ioremap_fixed_init' Signed-off-by: Paul Mundt --- arch/sh/include/asm/io.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 98c62fa168c2..bd5fafa23eb4 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -273,24 +273,6 @@ void __iomem *__ioremap_caller(unsigned long offset, unsigned long size, pgprot_t prot, void *caller); void __iounmap(void __iomem *addr); -#ifdef CONFIG_IOREMAP_FIXED -extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, - unsigned long, pgprot_t); -extern int iounmap_fixed(void __iomem *); -extern void ioremap_fixed_init(void); -#else -static inline void __iomem * -ioremap_fixed(resource_size_t phys_addr, unsigned long offset, - unsigned long size, pgprot_t prot) -{ - BUG(); - return NULL; -} - -static inline void ioremap_fixed_init(void) { } -static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } -#endif - static inline void __iomem * __ioremap(unsigned long offset, unsigned long size, pgprot_t prot) { @@ -365,6 +347,24 @@ ioremap_prot(resource_size_t offset, unsigned long size, unsigned long flags) } #endif +#ifdef CONFIG_IOREMAP_FIXED +extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, + unsigned long, pgprot_t); +extern int iounmap_fixed(void __iomem *); +extern void ioremap_fixed_init(void); +#else +static inline void __iomem * +ioremap_fixed(resource_size_t phys_addr, unsigned long offset, + unsigned long size, pgprot_t prot) +{ + BUG(); + return NULL; +} + +static inline void ioremap_fixed_init(void) { } +static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } +#endif + #define ioremap_nocache ioremap #define iounmap __iounmap -- GitLab From abec86a80247ab3a40d2afc9c8e8c26efcab2391 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 28 Jan 2010 18:26:37 +0900 Subject: [PATCH 1296/3892] sh: Kill off superfluous sh_bios references from compressed loader. The VBR value needs to be initialized in order for any of the bios trapping to work, and as we don't do that until slightly later in the boot process, this has no real chance of working. The only reason for using this in the past was due to the fact that early serial initialization wasn't possible, but now that early sh-sci is supported by everyone, there's no longer any reason to support the sh_bios hacks in the first place. Given that, we just kill off the references completely. Signed-off-by: Paul Mundt --- arch/sh/boot/compressed/Makefile | 4 ---- arch/sh/boot/compressed/misc.c | 19 ------------------- 2 files changed, 23 deletions(-) diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index 6b95a2a48267..5d660b90943b 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -11,10 +11,6 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz \ OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o -ifdef CONFIG_SH_STANDARD_BIOS -OBJECTS += $(obj)/../../kernel/sh_bios.o -endif - # # IMAGE_OFFSET is the load offset of the compression loader # diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index 4b319e9e4f88..d509a5050623 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c @@ -14,7 +14,6 @@ #include #include #include -#include /* * gzip declarations @@ -66,29 +65,11 @@ static unsigned long free_mem_end_ptr; #include "../../../../lib/decompress_unlzo.c" #endif -#ifdef CONFIG_SH_STANDARD_BIOS -size_t strlen(const char *s) -{ - int i = 0; - - while (*s++) - i++; - return i; -} - -int puts(const char *s) -{ - int len = strlen(s); - sh_bios_console_write(s, len); - return len; -} -#else int puts(const char *s) { /* This should be updated to use the sh-sci routines */ return 0; } -#endif void* memset(void* s, int c, size_t n) { -- GitLab From 8fc176d5abb2d92c52df859faac7974b4a1585c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Jan 2010 13:46:16 +0900 Subject: [PATCH 1297/3892] ASoC: fsi: Add spin lock operation for accessing shared area fsi_master_xxx function should be protected by spin lock, because it are used from both FSI-A and FSI-B. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 5f9f2693f4eb..ebf358808db1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -110,6 +110,7 @@ struct fsi_master { struct fsi_priv fsia; struct fsi_priv fsib; struct sh_fsi_platform_info *info; + spinlock_t lock; }; /************************************************************************ @@ -168,30 +169,51 @@ static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { + int ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return -1; - return __fsi_reg_write((u32)(master->base + reg), data); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_write((u32)(master->base + reg), data); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } static u32 fsi_master_read(struct fsi_master *master, u32 reg) { + u32 ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return 0; - return __fsi_reg_read((u32)(master->base + reg)); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_read((u32)(master->base + reg)); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } static int fsi_master_mask_set(struct fsi_master *master, u32 reg, u32 mask, u32 data) { + int ret; + unsigned long flags; + if ((reg < MREG_START) || (reg > MREG_END)) return -1; - return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; } /************************************************************************ @@ -929,6 +951,7 @@ static int fsi_probe(struct platform_device *pdev) master->fsia.master = master; master->fsib.base = master->base + 0x40; master->fsib.master = master; + spin_lock_init(&master->lock); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); -- GitLab From 339ce1a4dc2ca26444c4f65c31b71a5056f3bb0b Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 18 Jan 2010 16:47:07 +1100 Subject: [PATCH 1298/3892] perf: Fix inconsistency between IP and callchain sampling When running perf across all cpus with backtracing (-a -g), sometimes we get samples without associated backtraces: 23.44% init [kernel] [k] restore 11.46% init eeba0c [k] 0x00000000eeba0c 6.77% swapper [kernel] [k] .perf_ctx_adjust_freq 5.73% init [kernel] [k] .__trace_hcall_entry 4.69% perf libc-2.9.so [.] 0x0000000006bb8c | |--11.11%-- 0xfffa941bbbc It turns out the backtrace code has a check for the idle task and the IP sampling does not. This creates problems when profiling an interrupt heavy workload (in my case 10Gbit ethernet) since we get no backtraces for interrupts received while idle (ie most of the workload). Right now x86 and sh check that current is not NULL, which should never happen so remove that too. Idle task's exclusion must be performed from the core code, on top of perf_event_attr:exclude_idle. Signed-off-by: Anton Blanchard Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Benjamin Herrenschmidt Cc: Paul Mundt LKML-Reference: <20100118054707.GT12666@kryten> Signed-off-by: Frederic Weisbecker --- arch/powerpc/kernel/perf_callchain.c | 3 --- arch/sh/kernel/perf_callchain.c | 3 --- arch/x86/kernel/cpu/perf_event.c | 3 --- 3 files changed, 9 deletions(-) diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c index a3c11cac3d71..95ad9dad298e 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/kernel/perf_callchain.c @@ -495,9 +495,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) entry->nr = 0; - if (current->pid == 0) /* idle task? */ - return entry; - if (!user_mode(regs)) { perf_callchain_kernel(regs, entry); if (current->mm) diff --git a/arch/sh/kernel/perf_callchain.c b/arch/sh/kernel/perf_callchain.c index 24ea837eac5b..a9dd3abde28e 100644 --- a/arch/sh/kernel/perf_callchain.c +++ b/arch/sh/kernel/perf_callchain.c @@ -68,9 +68,6 @@ perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) is_user = user_mode(regs); - if (!current || current->pid == 0) - return; - if (is_user && current->state != TASK_RUNNING) return; diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index b1bb8c550526..ed1998b28a7c 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -2425,9 +2425,6 @@ perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) is_user = user_mode(regs); - if (!current || current->pid == 0) - return; - if (is_user && current->state != TASK_RUNNING) return; -- GitLab From 257ddbdad13cd3c4f7d03b85af632c508aa8abc9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 27 Jan 2010 10:17:41 +0000 Subject: [PATCH 1299/3892] netdev: remove HAVE_ leftovers Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- drivers/net/bnx2x_main.c | 4 ++-- drivers/net/cassini.c | 2 +- drivers/net/ixgbevf/ixgbevf_main.c | 18 ------------------ drivers/net/meth.c | 3 --- drivers/staging/wlags49_h2/wl_netdev.c | 6 ------ 6 files changed, 5 insertions(+), 32 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index a7b6b12c1c05..5917b941aca2 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7668,7 +7668,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu) return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size)); } -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +#ifdef CONFIG_NET_POLL_CONTROLLER static void poll_bnx2(struct net_device *dev) { @@ -8280,7 +8280,7 @@ static const struct net_device_ops bnx2_netdev_ops = { #ifdef BCM_VLAN .ndo_vlan_rx_register = bnx2_vlan_rx_register, #endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +#ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2, #endif }; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ca4ed634d55e..ffc7381969ae 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11731,7 +11731,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev, #endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +#ifdef CONFIG_NET_POLL_CONTROLLER static void poll_bnx2x(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); @@ -11755,7 +11755,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { #ifdef BCM_VLAN .ndo_vlan_rx_register = bnx2x_vlan_rx_register, #endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +#ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2x, #endif }; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index b3a038c23af1..ad47e5126fde 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -106,7 +106,7 @@ #define cas_page_unmap(x) kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ) #define CAS_NCPUS num_online_cpus() -#if defined(CONFIG_CASSINI_NAPI) && defined(HAVE_NETDEV_POLL) +#ifdef CONFIG_CASSINI_NAPI #define USE_NAPI #define cas_skb_release(x) netif_receive_skb(x) #else diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 7b3af107ca84..b9f10d05049d 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -3262,7 +3262,6 @@ static void ixgbevf_shutdown(struct pci_dev *pdev) pci_disable_device(pdev); } -#ifdef HAVE_NET_DEVICE_OPS static const struct net_device_ops ixgbe_netdev_ops = { .ndo_open = &ixgbevf_open, .ndo_stop = &ixgbevf_close, @@ -3278,29 +3277,12 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_vlan_rx_add_vid = &ixgbevf_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = &ixgbevf_vlan_rx_kill_vid, }; -#endif /* HAVE_NET_DEVICE_OPS */ static void ixgbevf_assign_netdev_ops(struct net_device *dev) { struct ixgbevf_adapter *adapter; adapter = netdev_priv(dev); -#ifdef HAVE_NET_DEVICE_OPS dev->netdev_ops = &ixgbe_netdev_ops; -#else /* HAVE_NET_DEVICE_OPS */ - dev->open = &ixgbevf_open; - dev->stop = &ixgbevf_close; - - dev->hard_start_xmit = &ixgbevf_xmit_frame; - - dev->get_stats = &ixgbevf_get_stats; - dev->set_multicast_list = &ixgbevf_set_rx_mode; - dev->set_mac_address = &ixgbevf_set_mac; - dev->change_mtu = &ixgbevf_change_mtu; - dev->tx_timeout = &ixgbevf_tx_timeout; - dev->vlan_rx_register = &ixgbevf_vlan_rx_register; - dev->vlan_rx_add_vid = &ixgbevf_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = &ixgbevf_vlan_rx_kill_vid; -#endif /* HAVE_NET_DEVICE_OPS */ ixgbevf_set_ethtool_ops(dev); dev->watchdog_timeo = 5 * HZ; } diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 2af81735386b..9f72cb45f4af 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -51,14 +51,11 @@ static const char *meth_str="SGI O2 Fast Ethernet"; -#define HAVE_TX_TIMEOUT /* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */ #define TX_TIMEOUT (400*HZ/1000) -#ifdef HAVE_TX_TIMEOUT static int timeout = TX_TIMEOUT; module_param(timeout, int, 0); -#endif /* * This structure is private to each device. It is used to pass diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index ac3890247965..0d22e3692fe5 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -1194,9 +1194,7 @@ static const struct net_device_ops wl_netdev_ops = .ndo_stop = &wl_adapter_close, .ndo_do_ioctl = &wl_ioctl, -#ifdef HAVE_TX_TIMEOUT .ndo_tx_timeout = &wl_tx_timeout, -#endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = wl_poll, @@ -1270,9 +1268,7 @@ struct net_device * wl_device_alloc( void ) dev->stop = &wl_adapter_close; dev->do_ioctl = &wl_ioctl; -#ifdef HAVE_TX_TIMEOUT dev->tx_timeout = &wl_tx_timeout; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = wl_poll; @@ -1280,9 +1276,7 @@ struct net_device * wl_device_alloc( void ) #endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)) -#ifdef HAVE_TX_TIMEOUT dev->watchdog_timeo = TX_TIMEOUT; -#endif dev->ethtool_ops = &wl_ethtool_ops; -- GitLab From ce96bc86bf2ee12e8a3bf461ca8027557c1ef42f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 28 Jan 2010 06:13:13 -0800 Subject: [PATCH 1300/3892] net: merge fixup for qlge_main Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 4adca94a521f..5be3ae2f5a16 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4499,7 +4499,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, if (qdev->mpi_coredump == NULL) { dev_err(&pdev->dev, "Coredump alloc failed.\n"); err = -ENOMEM; - goto err_out; + goto err_out2; } if (qlge_force_coredump) set_bit(QL_FRC_COREDUMP, &qdev->flags); -- GitLab From e924960dacdf85d118a98c7262edf2f99c3015cf Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 25 Jan 2010 10:28:21 +0000 Subject: [PATCH 1301/3892] netns xfrm: fixup xfrm6_tunnel error propagation Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv6/xfrm6_tunnel.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 438831d33593..23fb1002124c 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -353,13 +353,19 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { static int __init xfrm6_tunnel_init(void) { - if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) + int rv; + + rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); + if (rv < 0) goto err; - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) + rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); + if (rv < 0) goto unreg; - if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) + rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); + if (rv < 0) goto dereg6; - if (xfrm6_tunnel_spi_init() < 0) + rv = xfrm6_tunnel_spi_init(); + if (rv < 0) goto dereg46; return 0; @@ -370,7 +376,7 @@ dereg6: unreg: xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); err: - return -EAGAIN; + return rv; } static void __exit xfrm6_tunnel_fini(void) -- GitLab From a1664773907a2b69e2a3019598dcbeffa6bc724b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 25 Jan 2010 10:37:54 +0000 Subject: [PATCH 1302/3892] netns xfrm: xfrm6_tunnel in netns I'm not sure about rcu stuff near kmem cache destruction: * checks for non-empty hashes look bogus, they're done _before_ rcu_berrier() * unregistering netns ops is done before kmem_cache destoy (as it should), and unregistering involves rcu barriers by itself So it looks nothing should be done. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/net/xfrm.h | 6 +- net/ipv6/ipcomp6.c | 4 +- net/ipv6/xfrm6_tunnel.c | 140 ++++++++++++++++++++++++---------------- 3 files changed, 88 insertions(+), 62 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 60c27706e7b9..fcee547ca7e3 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1408,9 +1408,9 @@ extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto); extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); -extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); -extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); -extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); +extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); +extern void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr); +extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr); extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_output(struct sk_buff *skb); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 2f2a5ca2c878..1d1faf757c9a 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -81,7 +81,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) goto out; t->id.proto = IPPROTO_IPV6; - t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr); + t->id.spi = xfrm6_tunnel_alloc_spi(&init_net, (xfrm_address_t *)&x->props.saddr); if (!t->id.spi) goto error; @@ -112,7 +112,7 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x) struct xfrm_state *t = NULL; __be32 spi; - spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); + spi = xfrm6_tunnel_spi_lookup(&init_net, (xfrm_address_t *)&x->props.saddr); if (spi) t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr, spi, IPPROTO_IPV6, AF_INET6); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 23fb1002124c..d6f9aeec69f7 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -30,6 +30,25 @@ #include #include #include +#include + +#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 +#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 + +#define XFRM6_TUNNEL_SPI_MIN 1 +#define XFRM6_TUNNEL_SPI_MAX 0xffffffff + +struct xfrm6_tunnel_net { + struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; + struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; + u32 spi; +}; + +static int xfrm6_tunnel_net_id __read_mostly; +static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) +{ + return net_generic(net, xfrm6_tunnel_net_id); +} /* * xfrm_tunnel_spi things are for allocating unique id ("spi") @@ -46,19 +65,8 @@ struct xfrm6_tunnel_spi { static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); -static u32 xfrm6_tunnel_spi; - -#define XFRM6_TUNNEL_SPI_MIN 1 -#define XFRM6_TUNNEL_SPI_MAX 0xffffffff - static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; -#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 -#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 - -static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; -static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; - static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) { unsigned h; @@ -77,49 +85,30 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) } -static int xfrm6_tunnel_spi_init(void) +static int __init xfrm6_tunnel_spi_init(void) { - int i; - - xfrm6_tunnel_spi = 0; xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", sizeof(struct xfrm6_tunnel_spi), 0, SLAB_HWCACHE_ALIGN, NULL); if (!xfrm6_tunnel_spi_kmem) return -ENOMEM; - - for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) - INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); - for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) - INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); return 0; } static void xfrm6_tunnel_spi_fini(void) { - int i; - - for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { - if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) - return; - } - for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { - if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) - return; - } - rcu_barrier(); kmem_cache_destroy(xfrm6_tunnel_spi_kmem); - xfrm6_tunnel_spi_kmem = NULL; } -static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) +static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) { + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; struct hlist_node *pos; hlist_for_each_entry_rcu(x6spi, pos, - &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], + &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], list_byaddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) return x6spi; @@ -128,13 +117,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) return NULL; } -__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) +__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; u32 spi; rcu_read_lock_bh(); - x6spi = __xfrm6_tunnel_spi_lookup(saddr); + x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); spi = x6spi ? x6spi->spi : 0; rcu_read_unlock_bh(); return htonl(spi); @@ -142,14 +131,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); -static int __xfrm6_tunnel_spi_check(u32 spi) +static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) { + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; int index = xfrm6_tunnel_spi_hash_byspi(spi); struct hlist_node *pos; hlist_for_each_entry(x6spi, pos, - &xfrm6_tunnel_spi_byspi[index], + &xfrm6_tn->spi_byspi[index], list_byspi) { if (x6spi->spi == spi) return -1; @@ -157,32 +147,33 @@ static int __xfrm6_tunnel_spi_check(u32 spi) return index; } -static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) +static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) { + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); u32 spi; struct xfrm6_tunnel_spi *x6spi; int index; - if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || - xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) - xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; + if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || + xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) + xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; else - xfrm6_tunnel_spi++; + xfrm6_tn->spi++; - for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { - index = __xfrm6_tunnel_spi_check(spi); + for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { + index = __xfrm6_tunnel_spi_check(net, spi); if (index >= 0) goto alloc_spi; } - for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { - index = __xfrm6_tunnel_spi_check(spi); + for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { + index = __xfrm6_tunnel_spi_check(net, spi); if (index >= 0) goto alloc_spi; } spi = 0; goto out; alloc_spi: - xfrm6_tunnel_spi = spi; + xfrm6_tn->spi = spi; x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); if (!x6spi) goto out; @@ -192,26 +183,26 @@ alloc_spi: x6spi->spi = spi; atomic_set(&x6spi->refcnt, 1); - hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); + hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); index = xfrm6_tunnel_spi_hash_byaddr(saddr); - hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); + hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); out: return spi; } -__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) +__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; u32 spi; spin_lock_bh(&xfrm6_tunnel_spi_lock); - x6spi = __xfrm6_tunnel_spi_lookup(saddr); + x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); if (x6spi) { atomic_inc(&x6spi->refcnt); spi = x6spi->spi; } else - spi = __xfrm6_tunnel_alloc_spi(saddr); + spi = __xfrm6_tunnel_alloc_spi(net, saddr); spin_unlock_bh(&xfrm6_tunnel_spi_lock); return htonl(spi); @@ -225,15 +216,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head) container_of(head, struct xfrm6_tunnel_spi, rcu_head)); } -void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) +void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) { + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; struct hlist_node *pos, *n; spin_lock_bh(&xfrm6_tunnel_spi_lock); hlist_for_each_entry_safe(x6spi, pos, n, - &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], + &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], list_byaddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { @@ -263,10 +255,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) static int xfrm6_tunnel_rcv(struct sk_buff *skb) { + struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = ipv6_hdr(skb); __be32 spi; - spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); + spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; } @@ -326,7 +319,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x) static void xfrm6_tunnel_destroy(struct xfrm_state *x) { - xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); + struct net *net = xs_net(x); + + xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); } static const struct xfrm_type xfrm6_tunnel_type = { @@ -351,6 +346,31 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { .priority = 2, }; +static int __net_init xfrm6_tunnel_net_init(struct net *net) +{ + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); + unsigned int i; + + for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) + INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); + for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) + INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); + xfrm6_tn->spi = 0; + + return 0; +} + +static void __net_exit xfrm6_tunnel_net_exit(struct net *net) +{ +} + +static struct pernet_operations xfrm6_tunnel_net_ops = { + .init = xfrm6_tunnel_net_init, + .exit = xfrm6_tunnel_net_exit, + .id = &xfrm6_tunnel_net_id, + .size = sizeof(struct xfrm6_tunnel_net), +}; + static int __init xfrm6_tunnel_init(void) { int rv; @@ -367,8 +387,13 @@ static int __init xfrm6_tunnel_init(void) rv = xfrm6_tunnel_spi_init(); if (rv < 0) goto dereg46; + rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); + if (rv < 0) + goto deregspi; return 0; +deregspi: + xfrm6_tunnel_spi_fini(); dereg46: xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); dereg6: @@ -381,6 +406,7 @@ err: static void __exit xfrm6_tunnel_fini(void) { + unregister_pernet_subsys(&xfrm6_tunnel_net_ops); xfrm6_tunnel_spi_fini(); xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); -- GitLab From a92df2545402c1a08e7a158f4477a52dea0eeeed Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 25 Jan 2010 10:38:34 +0000 Subject: [PATCH 1303/3892] netns xfrm: ipcomp support Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv4/ipcomp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 38fbf04150ae..b55a0c3df82f 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -25,6 +25,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) { + struct net *net = dev_net(skb->dev); __be32 spi; struct iphdr *iph = (struct iphdr *)skb->data; struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2)); @@ -35,7 +36,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) return; spi = htonl(ntohs(ipch->cpi)); - x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) return; @@ -47,9 +48,10 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) /* We always hold one tunnel user reference to indicate a tunnel */ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) { + struct net *net = xs_net(x); struct xfrm_state *t; - t = xfrm_state_alloc(&init_net); + t = xfrm_state_alloc(net); if (t == NULL) goto out; @@ -82,10 +84,11 @@ error: */ static int ipcomp_tunnel_attach(struct xfrm_state *x) { + struct net *net = xs_net(x); int err = 0; struct xfrm_state *t; - t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr.a4, + t = xfrm_state_lookup(net, (xfrm_address_t *)&x->id.daddr.a4, x->props.saddr.a4, IPPROTO_IPIP, AF_INET); if (!t) { t = ipcomp_tunnel_create(x); -- GitLab From d74340d31bf1dbeb00acadddd8697666528a7846 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 25 Jan 2010 10:39:09 +0000 Subject: [PATCH 1304/3892] netns xfrm: ipcomp6 support Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv6/ipcomp6.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 1d1faf757c9a..a9fbb151bb79 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -53,6 +53,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { + struct net *net = dev_net(skb->dev); __be32 spi; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ip_comp_hdr *ipcomph = @@ -63,7 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; spi = htonl(ntohs(ipcomph->cpi)); - x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); if (!x) return; @@ -74,14 +75,15 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) { + struct net *net = xs_net(x); struct xfrm_state *t = NULL; - t = xfrm_state_alloc(&init_net); + t = xfrm_state_alloc(net); if (!t) goto out; t->id.proto = IPPROTO_IPV6; - t->id.spi = xfrm6_tunnel_alloc_spi(&init_net, (xfrm_address_t *)&x->props.saddr); + t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr); if (!t->id.spi) goto error; @@ -108,13 +110,14 @@ error: static int ipcomp6_tunnel_attach(struct xfrm_state *x) { + struct net *net = xs_net(x); int err = 0; struct xfrm_state *t = NULL; __be32 spi; - spi = xfrm6_tunnel_spi_lookup(&init_net, (xfrm_address_t *)&x->props.saddr); + spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&x->props.saddr); if (spi) - t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr, + t = xfrm_state_lookup(net, (xfrm_address_t *)&x->id.daddr, spi, IPPROTO_IPV6, AF_INET6); if (!t) { t = ipcomp6_tunnel_create(x); -- GitLab From c812459396733b42655e0d656763af02e06f97ed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 28 Jan 2010 15:57:04 +0200 Subject: [PATCH 1305/3892] ASoC: TWL4030: Modify codec default settings Change the legacy default register configuration, which left some internal components on. Now we have either DAPM, or other ways to control these bits, so there is no need to enable them by default. The affected parts: Disable ADCL and ADCR Disable ARXL2 and ARXR2 analog PGA (playback) Disable APLL by default Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 74f0d65f0784..e0106a5fd40b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -64,12 +64,12 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VRXPGA (0x14) */ 0x00, /* REG_VSTPGA (0x15) */ 0x00, /* REG_VRX2ARXPGA (0x16) */ - 0x0c, /* REG_AVDAC_CTL (0x17) */ + 0x00, /* REG_AVDAC_CTL (0x17) */ 0x00, /* REG_ARX2VTXPGA (0x18) */ 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ - 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ - 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ + 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */ + 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */ 0x00, /* REG_ATX2ARXPGA (0x1D) */ 0x00, /* REG_BT_IF (0x1E) */ 0x00, /* REG_BTPGA (0x1F) */ @@ -99,7 +99,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ - 0x16, /* REG_APLL_CTL (0x3A) */ + 0x06, /* REG_APLL_CTL (0x3A) */ 0x00, /* REG_DTMF_CTL (0x3B) */ 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ -- GitLab From fb58a2ff300cb3fd6077484ca7d8c6e6f13a0350 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 28 Jan 2010 10:22:45 +0000 Subject: [PATCH 1306/3892] ASoC: Remove version display from WM9713 The version isn't being updated or used, the kernel revision tracking is enough. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm9713.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index c58aab375edb..96e46d9a0171 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -28,8 +28,6 @@ #include "wm9713.h" -#define WM9713_VERSION "0.15" - struct wm9713_priv { u32 pll_in; /* PLL input frequency */ }; @@ -1186,8 +1184,6 @@ static int wm9713_soc_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0, reg; - printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); - socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (socdev->card->codec == NULL) -- GitLab From e03a8d2cf663429e2480a8db78b132ee300f79af Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 28 Jan 2010 12:36:07 +0000 Subject: [PATCH 1307/3892] ASoC: Add TLV information and additional volumes to WM9713 Also renames a few things to make volumes and switches match up in alsamixer. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm9713.c | 60 ++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 96e46d9a0171..ceb86b4ddb25 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -113,15 +114,27 @@ SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ }; +static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0); +static unsigned int mic_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0), + 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), +}; + static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = { -SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1), +SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv), SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1), -SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), +SOC_DOUBLE_TLV("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1, + out_tlv), SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1), -SOC_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1), -SOC_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1), -SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), -SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), +SOC_DOUBLE_TLV("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1, main_tlv), +SOC_DOUBLE_TLV("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1, main_tlv), +SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv), +SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), +SOC_SINGLE_TLV("Mic 1 Preamp Volume", AC97_3D_CONTROL, 10, 3, 0, mic_tlv), +SOC_SINGLE_TLV("Mic 2 Preamp Volume", AC97_3D_CONTROL, 12, 3, 0, mic_tlv), SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0), SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1), @@ -131,7 +144,7 @@ SOC_ENUM("Capture Volume Steps", wm9713_enum[5]), SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0), SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0), -SOC_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1), +SOC_SINGLE_TLV("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1, misc_tlv), SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0), SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0), @@ -152,28 +165,43 @@ SOC_DOUBLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0), SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1), SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0), -SOC_SINGLE("Out4 Playback Volume", AC97_MASTER_MONO, 8, 63, 1), +SOC_SINGLE_TLV("Out4 Playback Volume", AC97_MASTER_MONO, 8, 31, 1, out_tlv), SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1), SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0), -SOC_SINGLE("Out3 Playback Volume", AC97_MASTER_MONO, 0, 63, 1), +SOC_SINGLE_TLV("Out3 Playback Volume", AC97_MASTER_MONO, 0, 31, 1, out_tlv), -SOC_SINGLE("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1), +SOC_SINGLE_TLV("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1, main_tlv), SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1), SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0), -SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1), +SOC_SINGLE_TLV("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1, out_tlv), -SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), -SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), -SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), +SOC_SINGLE_TLV("Headphone Mixer Beep Playback Volume", AC97_AUX, 12, 7, 1, + misc_tlv), +SOC_SINGLE_TLV("Speaker Mixer Beep Playback Volume", AC97_AUX, 8, 7, 1, + misc_tlv), +SOC_SINGLE_TLV("Mono Mixer Beep Playback Volume", AC97_AUX, 4, 7, 1, misc_tlv), -SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1), +SOC_SINGLE_TLV("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1, + misc_tlv), SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1), SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1), +SOC_SINGLE_TLV("Headphone Mixer Aux Playback Volume", AC97_REC_SEL, 12, 7, 1, + misc_tlv), + +SOC_SINGLE_TLV("Speaker Mixer Voice Playback Volume", AC97_PCM, 8, 7, 1, + misc_tlv), +SOC_SINGLE_TLV("Speaker Mixer Aux Playback Volume", AC97_REC_SEL, 8, 7, 1, + misc_tlv), + +SOC_SINGLE_TLV("Mono Mixer Voice Playback Volume", AC97_PCM, 4, 7, 1, + misc_tlv), +SOC_SINGLE_TLV("Mono Mixer Aux Playback Volume", AC97_REC_SEL, 4, 7, 1, + misc_tlv), + SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1), SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1), -SOC_SINGLE("Aux Playback Mono Volume", AC97_REC_SEL, 4, 7, 1), SOC_ENUM("Bass Control", wm9713_enum[16]), SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1), -- GitLab From 2718625fba1e07bf2ce8a752036658737c1f76a7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 28 Jan 2010 12:36:29 +0000 Subject: [PATCH 1308/3892] ASoC: Set codec->dev for AC97 devices Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9085b40fa04b..ca89c782132d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1368,6 +1368,7 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, codec->ac97->bus->ops = ops; codec->ac97->num = num; + codec->dev = &codec->ac97->dev; mutex_unlock(&codec->mutex); return 0; } -- GitLab From 7b36ea967cc5b5088a57fe225f1f72a3c160058b Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 28 Jan 2010 16:13:07 +0800 Subject: [PATCH 1309/3892] ALSA: hda - Change the AZX_MAX_PCMS to 10 In hda_codec.c, it has define "[HDA_PCM_TYPE_HDMI] = { 3, 7, 8, 9, -1 },", it support up to device 9 for HDMI. But in hda_intel.c, it only define AZX_MAX_PCMS as 8. So if it have 4 hdmi codecs, when run azx_attach_pcm_stream(), it will show error "Invalid PCM device number 8", and "... number 9", and return "-EINVAL". We should change the AZX_MAX_PCMS to 10. Signed-off-by: Wei Ni Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6eeefda63838..170126c28abd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -261,7 +261,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) /* max number of PCM devics per card */ -#define AZX_MAX_PCMS 8 +#define AZX_MAX_PCMS 10 /* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01 -- GitLab From c89362225152fc6f2247f65371bfe3ccced3203b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Jan 2010 17:08:53 +0100 Subject: [PATCH 1310/3892] ALSA: hda - Define max number of PCM devices in hda_codec.h Define the constant rather in the common header file. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/hda_intel.c | 10 ++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 26ceace88c96..98767df4f03a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3275,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { /* * get the empty PCM device number to assign + * + * note the max device number is limited by HDA_MAX_PCMS, currently 10 */ static int get_empty_pcm_device(struct hda_bus *bus, int type) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 0c8f05cc56be..b75da47571e6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -527,6 +527,9 @@ enum { /* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f +/* max number of PCM devics per card */ +#define HDA_MAX_PCMS 10 + /* * generic arrays */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 170126c28abd..12230a2ed4f1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -260,8 +260,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_MAX_FRAG 32 /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) -/* max number of PCM devics per card */ -#define AZX_MAX_PCMS 10 /* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01 @@ -409,7 +407,7 @@ struct azx { struct azx_dev *azx_dev; /* PCM */ - struct snd_pcm *pcm[AZX_MAX_PCMS]; + struct snd_pcm *pcm[HDA_MAX_PCMS]; /* HD codec */ unsigned short codec_mask; @@ -1336,7 +1334,7 @@ static void azx_bus_reset(struct hda_bus *bus) if (chip->initialized) { int i; - for (i = 0; i < AZX_MAX_PCMS; i++) + for (i = 0; i < HDA_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); snd_hda_suspend(chip->bus); snd_hda_resume(chip->bus); @@ -1966,7 +1964,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, int pcm_dev = cpcm->device; int s, err; - if (pcm_dev >= AZX_MAX_PCMS) { + if (pcm_dev >= HDA_MAX_PCMS) { snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", pcm_dev); return -EINVAL; @@ -2122,7 +2120,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); - for (i = 0; i < AZX_MAX_PCMS; i++) + for (i = 0; i < HDA_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->initialized) snd_hda_suspend(chip->bus); -- GitLab From 30ed7ed11cb88fd56d821a67b9aab1e0d50fb626 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Jan 2010 17:11:45 +0100 Subject: [PATCH 1311/3892] ALSA: hda - Fix index of HP Compaq F700 mic amp The amp used for the mic input on HP Compaq F700 with Cxt5051 codec has no multiple inputs, thus its index should be 0 instead of 1. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 9077e4174ee6..745e35992144 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1832,7 +1832,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { static struct hda_verb cxt5051_f700_init_verbs[] = { /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, -- GitLab From e108c7b79e91b45a3f04762c44fd404a5d9be069 Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Thu, 28 Jan 2010 19:21:07 +0100 Subject: [PATCH 1312/3892] ALSA: hda - Add mute LED check for HP laptops with IDT 92HD83xxx codec This patch adds HP mute LED support for IDT 92HD81/3 family of the codecs. Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index dbffb5b5c69d..cb9802f4b063 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5332,6 +5332,11 @@ again: if (spec->board_config == STAC_92HD83XXX_HP) spec->gpio_led = 0x01; + if (find_mute_led_gpio(codec)) + snd_printd("mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); + #ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { spec->gpio_mask |= spec->gpio_led; -- GitLab From c1596b75c29eb5b32c65ef1e186c8b08c289bf05 Mon Sep 17 00:00:00 2001 From: Hamish Guthrie Date: Thu, 28 Jan 2010 12:54:09 +0100 Subject: [PATCH 1313/3892] ps3_gelic_wireless: Remove PS3 gelic legacy wpa support The current PS3 gelic wireless driver has support for wireless extensions. The original PS3 gelic wireless driver exposed a dedicated API for a dedicated wpa_supplicant driver. This old API could be enabled with CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE, however, as this is not being used by any distros, and it is being removed from the driver and from wpa_supplicant. Signed-off-by: Hamish Guthrie Acked-by: Geoff Levand Signed-off-by: John W. Linville --- arch/powerpc/configs/ppc64_defconfig | 1 - arch/powerpc/configs/ps3_defconfig | 1 - drivers/net/Kconfig | 14 --- drivers/net/ps3_gelic_wireless.c | 137 --------------------------- 4 files changed, 153 deletions(-) diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 252401824575..070587ae4f74 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -1000,7 +1000,6 @@ CONFIG_TIGON3=y CONFIG_SPIDER_NET=m CONFIG_GELIC_NET=m CONFIG_GELIC_WIRELESS=y -# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set # CONFIG_ATL1E is not set diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 7de127e4ceef..32f7058bb173 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -593,7 +593,6 @@ CONFIG_MII=m CONFIG_NETDEV_1000=y CONFIG_GELIC_NET=y CONFIG_GELIC_WIRELESS=y -# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set # CONFIG_NETDEV_10000 is not set # diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 18ff622703be..6460505ab24c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2354,20 +2354,6 @@ config GELIC_WIRELESS the driver automatically distinguishes the models, you can safely enable this option even if you have a wireless-less model. -config GELIC_WIRELESS_OLD_PSK_INTERFACE - bool "PS3 Wireless private PSK interface (OBSOLETE)" - depends on GELIC_WIRELESS - select WEXT_PRIV - help - This option retains the obsolete private interface to pass - the PSK from user space programs to the driver. The PSK - stands for 'Pre Shared Key' and is used for WPA[2]-PSK - (WPA-Personal) environment. - If WPA[2]-PSK is used and you need to use old programs that - support only this old interface, say Y. Otherwise N. - - If unsure, say N. - config FSL_PQ_MDIO tristate "Freescale PQ MDIO" depends on FSL_SOC diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 227b141c4fbd..7571dbba6a0a 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1389,113 +1389,6 @@ static int gelic_wl_get_mode(struct net_device *netdev, return 0; } -#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE -/* SIOCIWFIRSTPRIV */ -static int hex2bin(u8 *str, u8 *bin, unsigned int len) -{ - unsigned int i; - static unsigned char *hex = "0123456789ABCDEF"; - unsigned char *p, *q; - u8 tmp; - - if (len != WPA_PSK_LEN * 2) - return -EINVAL; - - for (i = 0; i < WPA_PSK_LEN * 2; i += 2) { - p = strchr(hex, toupper(str[i])); - q = strchr(hex, toupper(str[i + 1])); - if (!p || !q) { - pr_info("%s: unconvertible PSK digit=%d\n", - __func__, i); - return -EINVAL; - } - tmp = ((p - hex) << 4) + (q - hex); - *bin++ = tmp; - } - return 0; -}; - -static int gelic_wl_priv_set_psk(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); - unsigned int len; - unsigned long irqflag; - int ret = 0; - - pr_debug("%s:<- len=%d\n", __func__, data->data.length); - len = data->data.length - 1; - if (len <= 2) - return -EINVAL; - - spin_lock_irqsave(&wl->lock, irqflag); - if (extra[0] == '"' && extra[len - 1] == '"') { - pr_debug("%s: passphrase mode\n", __func__); - /* pass phrase */ - if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) { - pr_info("%s: passphrase too long\n", __func__); - ret = -E2BIG; - goto out; - } - memset(wl->psk, 0, sizeof(wl->psk)); - wl->psk_len = len - 2; - memcpy(wl->psk, &(extra[1]), wl->psk_len); - wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE; - } else { - ret = hex2bin(extra, wl->psk, len); - if (ret) - goto out; - wl->psk_len = WPA_PSK_LEN; - wl->psk_type = GELIC_EURUS_WPA_PSK_BIN; - } - set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat); -out: - spin_unlock_irqrestore(&wl->lock, irqflag); - pr_debug("%s:->\n", __func__); - return ret; -} - -static int gelic_wl_priv_get_psk(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); - char *p; - unsigned long irqflag; - unsigned int i; - - pr_debug("%s:<-\n", __func__); - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - spin_lock_irqsave(&wl->lock, irqflag); - p = extra; - if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) { - if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) { - for (i = 0; i < wl->psk_len; i++) { - sprintf(p, "%02xu", wl->psk[i]); - p += 2; - } - *p = '\0'; - data->data.length = wl->psk_len * 2; - } else { - *p++ = '"'; - memcpy(p, wl->psk, wl->psk_len); - p += wl->psk_len; - *p++ = '"'; - *p = '\0'; - data->data.length = wl->psk_len + 2; - } - } else - /* no psk set */ - data->data.length = 0; - spin_unlock_irqrestore(&wl->lock, irqflag); - pr_debug("%s:-> %d\n", __func__, data->data.length); - return 0; -} -#endif - /* SIOCGIWNICKN */ static int gelic_wl_get_nick(struct net_device *net_dev, struct iw_request_info *info, @@ -2406,40 +2299,10 @@ static const iw_handler gelic_wl_wext_handler[] = IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, }; -#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE -static struct iw_priv_args gelic_wl_private_args[] = -{ - { - .cmd = GELIC_WL_PRIV_SET_PSK, - .set_args = IW_PRIV_TYPE_CHAR | - (GELIC_WL_EURUS_PSK_MAX_LEN + 2), - .name = "set_psk" - }, - { - .cmd = GELIC_WL_PRIV_GET_PSK, - .get_args = IW_PRIV_TYPE_CHAR | - (GELIC_WL_EURUS_PSK_MAX_LEN + 2), - .name = "get_psk" - } -}; - -static const iw_handler gelic_wl_private_handler[] = -{ - gelic_wl_priv_set_psk, - gelic_wl_priv_get_psk, -}; -#endif - static const struct iw_handler_def gelic_wl_wext_handler_def = { .num_standard = ARRAY_SIZE(gelic_wl_wext_handler), .standard = gelic_wl_wext_handler, .get_wireless_stats = gelic_wl_get_wireless_stats, -#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE - .num_private = ARRAY_SIZE(gelic_wl_private_handler), - .num_private_args = ARRAY_SIZE(gelic_wl_private_args), - .private = gelic_wl_private_handler, - .private_args = gelic_wl_private_args, -#endif }; static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card) -- GitLab From f276586a8af410d2b79733daf52471605b6559e9 Mon Sep 17 00:00:00 2001 From: Hamish Guthrie Date: Thu, 28 Jan 2010 12:54:10 +0100 Subject: [PATCH 1314/3892] ps3_gelic_wireless: fix directed ssid scan If the association worker requests a directed ssid scan and a bss list already exists, the directed scan is not done. This patch corrects this and cleans up a few typos and debug messages. Signed-off-by: Hamish Guthrie Acked-by: Geoff Levand Signed-off-by: John W. Linville --- drivers/net/ps3_gelic_wireless.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 7571dbba6a0a..d520e9e8cdb2 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1449,7 +1449,8 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, void *buf = NULL; size_t len; - pr_debug("%s: <- always=%d\n", __func__, always_scan); + pr_debug("%s: <- always=%d essid_len=%d\n", __func__, + always_scan, essid_len); if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; @@ -1464,8 +1465,10 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, init_completion(&wl->scan_done); /* * If we have already a bss list, don't try to get new + * unless we are doing an ESSID scan */ - if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) { + if ((!essid_len && !always_scan) + && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) { pr_debug("%s: already has the list\n", __func__); complete(&wl->scan_done); goto out; @@ -1566,7 +1569,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } } - /* put them in the newtork_list */ + /* put them in the network_list */ for (i = 0, scan_info_size = 0, scan_info = buf; scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), @@ -1902,7 +1905,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) /* PSK type */ wpa->psk_type = cpu_to_be16(wl->psk_type); #ifdef DEBUG - pr_debug("%s: sec=%s psktype=%s\nn", __func__, + pr_debug("%s: sec=%s psktype=%s\n", __func__, wpasecstr(wpa->security), (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? "BIN" : "passphrase"); @@ -1912,9 +1915,9 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) * the debug log because this dumps your precious * passphrase/key. */ - pr_debug("%s: psk=%s\n", + pr_debug("%s: psk=%s\n", __func__, (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? - (char *)"N/A" : (char *)wpa->psk); + "N/A" : wpa->psk); #endif #endif /* issue wpa setup */ -- GitLab From 1f43cfb9474d1c4f22598b6e3213ec035be6dd56 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 13:47:25 -0700 Subject: [PATCH 1315/3892] of: merge machine_is_compatible() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/prom.c | 18 ------------------ arch/powerpc/kernel/prom.c | 19 ------------------- drivers/of/base.c | 21 +++++++++++++++++++++ 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 5505bcffd7dd..16a001c71e2e 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -318,24 +318,6 @@ void __init early_init_devtree(void *params) pr_debug(" <- early_init_devtree()\n"); } -/** - * Indicates whether the root node has a given value in its - * compatible property. - */ -int machine_is_compatible(const char *compat) -{ - struct device_node *root; - int rc = 0; - - root = of_find_node_by_path("/"); - if (root) { - rc = of_device_is_compatible(root, compat); - of_node_put(root); - } - return rc; -} -EXPORT_SYMBOL(machine_is_compatible); - /******* * * New implementation of the OF "find" APIs, return a refcounted diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 877fad9b3745..caeea9a5fcc2 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -754,25 +754,6 @@ void __init early_init_devtree(void *params) DBG(" <- early_init_devtree()\n"); } - -/** - * Indicates whether the root node has a given value in its - * compatible property. - */ -int machine_is_compatible(const char *compat) -{ - struct device_node *root; - int rc = 0; - - root = of_find_node_by_path("/"); - if (root) { - rc = of_device_is_compatible(root, compat); - of_node_put(root); - } - return rc; -} -EXPORT_SYMBOL(machine_is_compatible); - /******* * * New implementation of the OF "find" APIs, return a refcounted diff --git a/drivers/of/base.c b/drivers/of/base.c index ec56739eb247..dba995b70b84 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -143,6 +143,27 @@ int of_device_is_compatible(const struct device_node *device, } EXPORT_SYMBOL(of_device_is_compatible); +/** + * machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node's compatible property. + * + * Returns true if the root node has the given value in its + * compatible property. + */ +int machine_is_compatible(const char *compat) +{ + struct device_node *root; + int rc = 0; + + root = of_find_node_by_path("/"); + if (root) { + rc = of_device_is_compatible(root, compat); + of_node_put(root); + } + return rc; +} +EXPORT_SYMBOL(machine_is_compatible); + /** * of_device_is_available - check if a device is available for use * -- GitLab From 923f7e30b480438f1e86e01e5cde814248b59a39 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 13:52:53 -0700 Subject: [PATCH 1316/3892] of: Merge of_node_get() and of_node_put() Merge common code between PowerPC and MicroBlaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/prom.c | 74 ---------------------------------- arch/powerpc/kernel/prom.c | 73 ---------------------------------- drivers/of/base.c | 75 +++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 147 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 16a001c71e2e..46407e643926 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -350,80 +350,6 @@ struct device_node *of_find_node_by_phandle(phandle handle) } EXPORT_SYMBOL(of_find_node_by_phandle); -/** - * of_node_get - Increment refcount of a node - * @node: Node to inc refcount, NULL is supported to - * simplify writing of callers - * - * Returns node. - */ -struct device_node *of_node_get(struct device_node *node) -{ - if (node) - kref_get(&node->kref); - return node; -} -EXPORT_SYMBOL(of_node_get); - -static inline struct device_node *kref_to_device_node(struct kref *kref) -{ - return container_of(kref, struct device_node, kref); -} - -/** - * of_node_release - release a dynamically allocated node - * @kref: kref element of the node to be released - * - * In of_node_put() this function is passed to kref_put() - * as the destructor. - */ -static void of_node_release(struct kref *kref) -{ - struct device_node *node = kref_to_device_node(kref); - struct property *prop = node->properties; - - /* We should never be releasing nodes that haven't been detached. */ - if (!of_node_check_flag(node, OF_DETACHED)) { - printk(KERN_INFO "WARNING: Bad of_node_put() on %s\n", - node->full_name); - dump_stack(); - kref_init(&node->kref); - return; - } - - if (!of_node_check_flag(node, OF_DYNAMIC)) - return; - - while (prop) { - struct property *next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); - prop = next; - - if (!prop) { - prop = node->deadprops; - node->deadprops = NULL; - } - } - kfree(node->full_name); - kfree(node->data); - kfree(node); -} - -/** - * of_node_put - Decrement refcount of a node - * @node: Node to dec refcount, NULL is supported to - * simplify writing of callers - * - */ -void of_node_put(struct device_node *node) -{ - if (node) - kref_put(&node->kref, of_node_release); -} -EXPORT_SYMBOL(of_node_put); - /* * Plug a device node into the tree and global list. */ diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index caeea9a5fcc2..deccd91d7e81 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -817,79 +817,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np) return NULL; } -/** - * of_node_get - Increment refcount of a node - * @node: Node to inc refcount, NULL is supported to - * simplify writing of callers - * - * Returns node. - */ -struct device_node *of_node_get(struct device_node *node) -{ - if (node) - kref_get(&node->kref); - return node; -} -EXPORT_SYMBOL(of_node_get); - -static inline struct device_node * kref_to_device_node(struct kref *kref) -{ - return container_of(kref, struct device_node, kref); -} - -/** - * of_node_release - release a dynamically allocated node - * @kref: kref element of the node to be released - * - * In of_node_put() this function is passed to kref_put() - * as the destructor. - */ -static void of_node_release(struct kref *kref) -{ - struct device_node *node = kref_to_device_node(kref); - struct property *prop = node->properties; - - /* We should never be releasing nodes that haven't been detached. */ - if (!of_node_check_flag(node, OF_DETACHED)) { - printk("WARNING: Bad of_node_put() on %s\n", node->full_name); - dump_stack(); - kref_init(&node->kref); - return; - } - - if (!of_node_check_flag(node, OF_DYNAMIC)) - return; - - while (prop) { - struct property *next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); - prop = next; - - if (!prop) { - prop = node->deadprops; - node->deadprops = NULL; - } - } - kfree(node->full_name); - kfree(node->data); - kfree(node); -} - -/** - * of_node_put - Decrement refcount of a node - * @node: Node to dec refcount, NULL is supported to - * simplify writing of callers - * - */ -void of_node_put(struct device_node *node) -{ - if (node) - kref_put(&node->kref, of_node_release); -} -EXPORT_SYMBOL(of_node_put); - /* * Plug a device node into the tree and global list. */ diff --git a/drivers/of/base.c b/drivers/of/base.c index dba995b70b84..cf89ee6253f3 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -60,6 +60,81 @@ int of_n_size_cells(struct device_node *np) } EXPORT_SYMBOL(of_n_size_cells); +#if !defined(CONFIG_SPARC) /* SPARC doesn't do ref counting (yet) */ +/** + * of_node_get - Increment refcount of a node + * @node: Node to inc refcount, NULL is supported to + * simplify writing of callers + * + * Returns node. + */ +struct device_node *of_node_get(struct device_node *node) +{ + if (node) + kref_get(&node->kref); + return node; +} +EXPORT_SYMBOL(of_node_get); + +static inline struct device_node *kref_to_device_node(struct kref *kref) +{ + return container_of(kref, struct device_node, kref); +} + +/** + * of_node_release - release a dynamically allocated node + * @kref: kref element of the node to be released + * + * In of_node_put() this function is passed to kref_put() + * as the destructor. + */ +static void of_node_release(struct kref *kref) +{ + struct device_node *node = kref_to_device_node(kref); + struct property *prop = node->properties; + + /* We should never be releasing nodes that haven't been detached. */ + if (!of_node_check_flag(node, OF_DETACHED)) { + pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); + dump_stack(); + kref_init(&node->kref); + return; + } + + if (!of_node_check_flag(node, OF_DYNAMIC)) + return; + + while (prop) { + struct property *next = prop->next; + kfree(prop->name); + kfree(prop->value); + kfree(prop); + prop = next; + + if (!prop) { + prop = node->deadprops; + node->deadprops = NULL; + } + } + kfree(node->full_name); + kfree(node->data); + kfree(node); +} + +/** + * of_node_put - Decrement refcount of a node + * @node: Node to dec refcount, NULL is supported to + * simplify writing of callers + * + */ +void of_node_put(struct device_node *node) +{ + if (node) + kref_put(&node->kref, of_node_release); +} +EXPORT_SYMBOL(of_node_put); +#endif /* !CONFIG_SPARC */ + struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) -- GitLab From 6016a363f6b56b46b24655bcfc0499b715851cf3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 14:06:53 -0700 Subject: [PATCH 1317/3892] of: unify phandle name in struct device_node In struct device_node, the phandle is named 'linux_phandle' for PowerPC and MicroBlaze, and 'node' for SPARC. There is no good reason for the difference, it is just an artifact of the code diverging over a couple of years. This patch renames both to simply .phandle. Note: the .node also existed in PowerPC/MicroBlaze, but the only user seems to be arch/powerpc/platforms/powermac/pfunc_core.c. It doesn't look like the assignment between .linux_phandle and .node is significantly different enough to warrant the separate code paths unless ibm,phandle properties actually appear in Apple device trees. I think it is safe to eliminate the old .node property and use phandle everywhere. Signed-off-by: Grant Likely Acked-by: David S. Miller Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/kernel/of_platform.c | 2 +- arch/microblaze/kernel/prom.c | 2 +- arch/powerpc/kernel/of_platform.c | 2 +- arch/powerpc/kernel/prom.c | 6 +++--- arch/powerpc/platforms/cell/spu_manage.c | 6 +++--- arch/powerpc/platforms/powermac/pfunc_core.c | 2 +- arch/sparc/kernel/devices.c | 2 +- arch/sparc/kernel/of_device_32.c | 2 +- arch/sparc/kernel/of_device_64.c | 2 +- arch/sparc/kernel/prom_common.c | 8 ++++---- arch/sparc/kernel/smp_64.c | 2 +- drivers/of/fdt.c | 7 +++---- drivers/sbus/char/openprom.c | 10 +++++----- drivers/video/aty/atyfb_base.c | 2 +- include/linux/of.h | 5 +---- sound/aoa/fabrics/layout.c | 2 +- 16 files changed, 29 insertions(+), 33 deletions(-) diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c index acf4574d0f18..1c6d684996d7 100644 --- a/arch/microblaze/kernel/of_platform.c +++ b/arch/microblaze/kernel/of_platform.c @@ -185,7 +185,7 @@ EXPORT_SYMBOL(of_find_device_by_node); static int of_dev_phandle_match(struct device *dev, void *data) { phandle *ph = data; - return to_of_device(dev)->node->linux_phandle == *ph; + return to_of_device(dev)->node->phandle == *ph; } struct of_device *of_find_device_by_phandle(phandle ph) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 46407e643926..6eff83a71218 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -342,7 +342,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) read_lock(&devtree_lock); for (np = allnodes; np != NULL; np = np->allnext) - if (np->linux_phandle == handle) + if (np->phandle == handle) break; of_node_get(np); read_unlock(&devtree_lock); diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 1a4fc0d11a03..666d08db319e 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -214,7 +214,7 @@ EXPORT_SYMBOL(of_find_device_by_node); static int of_dev_phandle_match(struct device *dev, void *data) { phandle *ph = data; - return to_of_device(dev)->node->linux_phandle == *ph; + return to_of_device(dev)->node->phandle == *ph; } struct of_device *of_find_device_by_phandle(phandle ph) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index deccd91d7e81..1ed2ec2ea05b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -778,7 +778,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) read_lock(&devtree_lock); for (np = allnodes; np != 0; np = np->allnext) - if (np->linux_phandle == handle) + if (np->phandle == handle) break; of_node_get(np); read_unlock(&devtree_lock); @@ -907,9 +907,9 @@ static int of_finish_dynamic_node(struct device_node *node) if (machine_is(powermac)) return -ENODEV; - /* fix up new node's linux_phandle field */ + /* fix up new node's phandle field */ if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL))) - node->linux_phandle = *ibm_phandle; + node->phandle = *ibm_phandle; out: of_node_put(parent); diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 4c506c1463cd..891f18e337a2 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -457,7 +457,7 @@ neighbour_spu(int cbe, struct device_node *target, struct device_node *avoid) continue; vic_handles = of_get_property(spu_dn, "vicinity", &lenp); for (i=0; i < (lenp / sizeof(phandle)); i++) { - if (vic_handles[i] == target->linux_phandle) + if (vic_handles[i] == target->phandle) return spu; } } @@ -499,7 +499,7 @@ static void init_affinity_node(int cbe) if (strcmp(name, "spe") == 0) { spu = devnode_spu(cbe, vic_dn); - avoid_ph = last_spu_dn->linux_phandle; + avoid_ph = last_spu_dn->phandle; } else { /* * "mic-tm" and "bif0" nodes do not have @@ -514,7 +514,7 @@ static void init_affinity_node(int cbe) last_spu->has_mem_affinity = 1; spu->has_mem_affinity = 1; } - avoid_ph = vic_dn->linux_phandle; + avoid_ph = vic_dn->phandle; } list_add_tail(&spu->aff_list, &last_spu->aff_list); diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index 96d5ce50364e..ede49e78a8da 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -842,7 +842,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target, list_for_each_entry(func, &dev->functions, link) { if (name && strcmp(name, func->name)) continue; - if (func->phandle && target->node != func->phandle) + if (func->phandle && target->phandle != func->phandle) continue; if ((func->flags & flags) == 0) continue; diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index b171ae8de90d..b062de9424a4 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -59,7 +59,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, cur_inst = 0; for_each_node_by_type(dp, "cpu") { - int err = check_cpu_node(dp->node, &cur_inst, + int err = check_cpu_node(dp->phandle, &cur_inst, compare, compare_arg, prom_node, mid); if (!err) { diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index 4c26eb59e742..09138d403c7f 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -433,7 +433,7 @@ build_resources: if (!parent) dev_set_name(&op->dev, "root"); else - dev_set_name(&op->dev, "%08x", dp->node); + dev_set_name(&op->dev, "%08x", dp->phandle); if (of_device_register(op)) { printk("%s: Could not register of device.\n", diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index 881947e59e95..036f18ae59a6 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -666,7 +666,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, if (!parent) dev_set_name(&op->dev, "root"); else - dev_set_name(&op->dev, "%08x", dp->node); + dev_set_name(&op->dev, "%08x", dp->phandle); if (of_device_register(op)) { printk("%s: Could not register of device.\n", diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index d80a65d9e893..5832e13dfeeb 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -42,7 +42,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) struct device_node *np; for (np = allnodes; np; np = np->allnext) - if (np->node == handle) + if (np->phandle == handle) break; return np; @@ -89,7 +89,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len void *old_val = prop->value; int ret; - ret = prom_setprop(dp->node, name, val, len); + ret = prom_setprop(dp->phandle, name, val, len); err = -EINVAL; if (ret >= 0) { @@ -236,7 +236,7 @@ static struct device_node * __init prom_create_node(phandle node, dp->name = get_one_property(node, "name"); dp->type = get_one_property(node, "device_type"); - dp->node = node; + dp->phandle = node; dp->properties = build_prop_list(node); @@ -313,7 +313,7 @@ void __init prom_build_devicetree(void) nextp = &allnodes->allnext; allnodes->child = prom_build_tree(allnodes, - prom_getchild(allnodes->node), + prom_getchild(allnodes->phandle), &nextp); of_console_init(); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index aa36223497b9..eb14844a0021 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -370,7 +370,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) } else { struct device_node *dp = of_find_node_by_cpuid(cpu); - prom_startcpu(dp->node, entry, cookie); + prom_startcpu(dp->phandle, entry, cookie); } for (timeout = 0; timeout < 50000; timeout++) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 616a4767a950..7f8861121a31 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -310,12 +310,11 @@ unsigned long __init unflatten_dt_node(unsigned long mem, __alignof__(struct property)); if (allnextpp) { if (strcmp(pname, "linux,phandle") == 0) { - np->node = *((u32 *)*p); - if (np->linux_phandle == 0) - np->linux_phandle = np->node; + if (np->phandle == 0) + np->phandle = *((u32 *)*p); } if (strcmp(pname, "ibm,phandle") == 0) - np->linux_phandle = *((u32 *)*p); + np->phandle = *((u32 *)*p); pp->name = pname; pp->length = sz; pp->value = (void *)*p; diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 75ac19b1192f..fc2f676e984d 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -233,7 +233,7 @@ static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp ph = 0; if (dp) - ph = dp->node; + ph = dp->phandle; data->current_node = dp; *((int *) op->oprom_array) = ph; @@ -256,7 +256,7 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp dp = pci_device_to_OF_node(pdev); data->current_node = dp; - *((int *)op->oprom_array) = dp->node; + *((int *)op->oprom_array) = dp->phandle; op->oprom_size = sizeof(int); err = copyout(argp, op, bufsize + sizeof(int)); @@ -273,7 +273,7 @@ static int oprompath2node(void __user *argp, struct device_node *dp, struct open dp = of_find_node_by_path(op->oprom_array); if (dp) - ph = dp->node; + ph = dp->phandle; data->current_node = dp; *((int *)op->oprom_array) = ph; op->oprom_size = sizeof(int); @@ -540,7 +540,7 @@ static int opiocgetnext(unsigned int cmd, void __user *argp) } } if (dp) - nd = dp->node; + nd = dp->phandle; if (copy_to_user(argp, &nd, sizeof(phandle))) return -EFAULT; @@ -570,7 +570,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, case OPIOCGETOPTNODE: BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); - if (copy_to_user(argp, &options_node->node, sizeof(phandle))) + if (copy_to_user(argp, &options_node->phandle, sizeof(phandle))) return -EFAULT; return 0; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 913b4a47ae52..bb20987d58af 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -3104,7 +3104,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, } dp = pci_device_to_OF_node(pdev); - if (node == dp->node) { + if (node == dp->phandle) { struct fb_var_screeninfo *var = &default_var; unsigned int N, P, Q, M, T, R; u32 v_total, h_total; diff --git a/include/linux/of.h b/include/linux/of.h index d4c014a35ea5..dbabf86e0b7a 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -39,10 +39,7 @@ struct of_irq_controller; struct device_node { const char *name; const char *type; - phandle node; -#if !defined(CONFIG_SPARC) - phandle linux_phandle; -#endif + phandle phandle; char *full_name; struct property *properties; diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index 586965f9605f..7a437da05646 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -768,7 +768,7 @@ static int check_codec(struct aoa_codec *codec, "required property %s not present\n", propname); return -ENODEV; } - if (*ref != codec->node->linux_phandle) { + if (*ref != codec->node->phandle) { printk(KERN_INFO "snd-aoa-fabric-layout: " "%s doesn't match!\n", propname); return -ENODEV; -- GitLab From 430ad5a600a83956749307b13257c464c3826b55 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 28 Jan 2010 09:32:29 +0800 Subject: [PATCH 1318/3892] perf: Factorize trace events raw sample buffer operations Introduce ftrace_perf_buf_prepare() and ftrace_perf_buf_submit() to gather the common code that operates on raw events sampling buffer. This cleans up redundant code between regular trace events, syscall events and kprobe events. Changelog v1->v2: - Rename function name as per Masami and Frederic's suggestion - Add __kprobes for ftrace_perf_buf_prepare() and make ftrace_perf_buf_submit() inline as per Masami's suggestion - Export ftrace_perf_buf_prepare since modules will use it Signed-off-by: Xiao Guangrong Acked-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Steven Rostedt Cc: Paul Mackerras Cc: Jason Baron Cc: Peter Zijlstra LKML-Reference: <4B60E92D.9000808@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker --- include/linux/ftrace_event.h | 18 +++++-- include/trace/ftrace.h | 48 +++-------------- kernel/trace/trace_event_profile.c | 52 ++++++++++++++++-- kernel/trace/trace_kprobe.c | 86 ++++-------------------------- kernel/trace/trace_syscalls.c | 71 ++++-------------------- 5 files changed, 88 insertions(+), 187 deletions(-) diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 0a09e758c7d3..cd95919d9ff3 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -5,6 +5,7 @@ #include #include #include +#include struct trace_array; struct tracer; @@ -138,9 +139,6 @@ struct ftrace_event_call { #define FTRACE_MAX_PROFILE_SIZE 2048 -extern char *perf_trace_buf; -extern char *perf_trace_buf_nmi; - #define MAX_FILTER_PRED 32 #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ @@ -195,6 +193,20 @@ extern void ftrace_profile_disable(int event_id); extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, char *filter_str); extern void ftrace_profile_free_filter(struct perf_event *event); +extern void * +ftrace_perf_buf_prepare(int size, unsigned short type, int *rctxp, + unsigned long *irq_flags); + +static inline void +ftrace_perf_buf_submit(void *raw_data, int size, int rctx, u64 addr, + u64 count, unsigned long irq_flags) +{ + struct trace_entry *entry = raw_data; + + perf_tp_event(entry->type, addr, count, raw_data, size); + perf_swevent_put_recursion_context(rctx); + local_irq_restore(irq_flags); +} #endif #endif /* _LINUX_FTRACE_EVENT_H */ diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 4a46a60c2077..f2c09e4d656c 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -850,22 +850,12 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ proto) \ { \ struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ - extern int perf_swevent_get_recursion_context(void); \ - extern void perf_swevent_put_recursion_context(int rctx); \ - extern void perf_tp_event(int, u64, u64, void *, int); \ struct ftrace_raw_##call *entry; \ u64 __addr = 0, __count = 1; \ unsigned long irq_flags; \ - struct trace_entry *ent; \ int __entry_size; \ int __data_size; \ - char *trace_buf; \ - char *raw_data; \ - int __cpu; \ int rctx; \ - int pc; \ - \ - pc = preempt_count(); \ \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ @@ -875,42 +865,16 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE, \ "profile buffer not large enough")) \ return; \ - \ - local_irq_save(irq_flags); \ - \ - rctx = perf_swevent_get_recursion_context(); \ - if (rctx < 0) \ - goto end_recursion; \ - \ - __cpu = smp_processor_id(); \ - \ - if (in_nmi()) \ - trace_buf = rcu_dereference(perf_trace_buf_nmi); \ - else \ - trace_buf = rcu_dereference(perf_trace_buf); \ - \ - if (!trace_buf) \ - goto end; \ - \ - raw_data = per_cpu_ptr(trace_buf, __cpu); \ - \ - *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ - entry = (struct ftrace_raw_##call *)raw_data; \ - ent = &entry->ent; \ - tracing_generic_entry_update(ent, irq_flags, pc); \ - ent->type = event_call->id; \ - \ + entry = (struct ftrace_raw_##call *)ftrace_perf_buf_prepare( \ + __entry_size, event_call->id, &rctx, &irq_flags); \ + if (!entry) \ + return; \ tstruct \ \ { assign; } \ \ - perf_tp_event(event_call->id, __addr, __count, entry, \ - __entry_size); \ - \ -end: \ - perf_swevent_put_recursion_context(rctx); \ -end_recursion: \ - local_irq_restore(irq_flags); \ + ftrace_perf_buf_submit(entry, __entry_size, rctx, __addr, \ + __count, irq_flags); \ } #undef DEFINE_EVENT diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index 9e25573242cf..f0d693005075 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c @@ -6,14 +6,12 @@ */ #include +#include #include "trace.h" -char *perf_trace_buf; -EXPORT_SYMBOL_GPL(perf_trace_buf); - -char *perf_trace_buf_nmi; -EXPORT_SYMBOL_GPL(perf_trace_buf_nmi); +static char *perf_trace_buf; +static char *perf_trace_buf_nmi; typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ; @@ -120,3 +118,47 @@ void ftrace_profile_disable(int event_id) } mutex_unlock(&event_mutex); } + +__kprobes void *ftrace_perf_buf_prepare(int size, unsigned short type, + int *rctxp, unsigned long *irq_flags) +{ + struct trace_entry *entry; + char *trace_buf, *raw_data; + int pc, cpu; + + pc = preempt_count(); + + /* Protect the per cpu buffer, begin the rcu read side */ + local_irq_save(*irq_flags); + + *rctxp = perf_swevent_get_recursion_context(); + if (*rctxp < 0) + goto err_recursion; + + cpu = smp_processor_id(); + + if (in_nmi()) + trace_buf = rcu_dereference(perf_trace_buf_nmi); + else + trace_buf = rcu_dereference(perf_trace_buf); + + if (!trace_buf) + goto err; + + raw_data = per_cpu_ptr(trace_buf, cpu); + + /* zero the dead bytes from align to not leak stack to user */ + *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; + + entry = (struct trace_entry *)raw_data; + tracing_generic_entry_update(entry, *irq_flags, pc); + entry->type = type; + + return raw_data; +err: + perf_swevent_put_recursion_context(*rctxp); +err_recursion: + local_irq_restore(*irq_flags); + return NULL; +} +EXPORT_SYMBOL_GPL(ftrace_perf_buf_prepare); diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index d6266cad6953..2e28ee36646f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1243,14 +1243,10 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); struct ftrace_event_call *call = &tp->call; struct kprobe_trace_entry *entry; - struct trace_entry *ent; - int size, __size, i, pc, __cpu; + int size, __size, i; unsigned long irq_flags; - char *trace_buf; - char *raw_data; int rctx; - pc = preempt_count(); __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); size = ALIGN(__size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); @@ -1258,45 +1254,16 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, "profile buffer not large enough")) return 0; - /* - * Protect the non nmi buffer - * This also protects the rcu read side - */ - local_irq_save(irq_flags); - - rctx = perf_swevent_get_recursion_context(); - if (rctx < 0) - goto end_recursion; - - __cpu = smp_processor_id(); - - if (in_nmi()) - trace_buf = rcu_dereference(perf_trace_buf_nmi); - else - trace_buf = rcu_dereference(perf_trace_buf); - - if (!trace_buf) - goto end; - - raw_data = per_cpu_ptr(trace_buf, __cpu); - - /* Zero dead bytes from alignment to avoid buffer leak to userspace */ - *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; - entry = (struct kprobe_trace_entry *)raw_data; - ent = &entry->ent; + entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); + if (!entry) + return 0; - tracing_generic_entry_update(ent, irq_flags, pc); - ent->type = call->id; entry->nargs = tp->nr_args; entry->ip = (unsigned long)kp->addr; for (i = 0; i < tp->nr_args; i++) entry->args[i] = call_fetch(&tp->args[i].fetch, regs); - perf_tp_event(call->id, entry->ip, 1, entry, size); -end: - perf_swevent_put_recursion_context(rctx); -end_recursion: - local_irq_restore(irq_flags); + ftrace_perf_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags); return 0; } @@ -1308,14 +1275,10 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); struct ftrace_event_call *call = &tp->call; struct kretprobe_trace_entry *entry; - struct trace_entry *ent; - int size, __size, i, pc, __cpu; + int size, __size, i; unsigned long irq_flags; - char *trace_buf; - char *raw_data; int rctx; - pc = preempt_count(); __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); size = ALIGN(__size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); @@ -1323,46 +1286,17 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, "profile buffer not large enough")) return 0; - /* - * Protect the non nmi buffer - * This also protects the rcu read side - */ - local_irq_save(irq_flags); - - rctx = perf_swevent_get_recursion_context(); - if (rctx < 0) - goto end_recursion; - - __cpu = smp_processor_id(); - - if (in_nmi()) - trace_buf = rcu_dereference(perf_trace_buf_nmi); - else - trace_buf = rcu_dereference(perf_trace_buf); - - if (!trace_buf) - goto end; - - raw_data = per_cpu_ptr(trace_buf, __cpu); - - /* Zero dead bytes from alignment to avoid buffer leak to userspace */ - *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; - entry = (struct kretprobe_trace_entry *)raw_data; - ent = &entry->ent; + entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); + if (!entry) + return 0; - tracing_generic_entry_update(ent, irq_flags, pc); - ent->type = call->id; entry->nargs = tp->nr_args; entry->func = (unsigned long)tp->rp.kp.addr; entry->ret_ip = (unsigned long)ri->ret_addr; for (i = 0; i < tp->nr_args; i++) entry->args[i] = call_fetch(&tp->args[i].fetch, regs); - perf_tp_event(call->id, entry->ret_ip, 1, entry, size); -end: - perf_swevent_put_recursion_context(rctx); -end_recursion: - local_irq_restore(irq_flags); + ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags); return 0; } diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index f694f66d75b0..4e332b9e449c 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -433,12 +433,9 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) struct syscall_metadata *sys_data; struct syscall_trace_enter *rec; unsigned long flags; - char *trace_buf; - char *raw_data; int syscall_nr; int rctx; int size; - int cpu; syscall_nr = syscall_get_nr(current, regs); if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) @@ -457,37 +454,15 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) "profile buffer not large enough")) return; - /* Protect the per cpu buffer, begin the rcu read side */ - local_irq_save(flags); - - rctx = perf_swevent_get_recursion_context(); - if (rctx < 0) - goto end_recursion; - - cpu = smp_processor_id(); - - trace_buf = rcu_dereference(perf_trace_buf); - - if (!trace_buf) - goto end; - - raw_data = per_cpu_ptr(trace_buf, cpu); - - /* zero the dead bytes from align to not leak stack to user */ - *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; + rec = (struct syscall_trace_enter *)ftrace_perf_buf_prepare(size, + sys_data->enter_event->id, &rctx, &flags); + if (!rec) + return; - rec = (struct syscall_trace_enter *) raw_data; - tracing_generic_entry_update(&rec->ent, 0, 0); - rec->ent.type = sys_data->enter_event->id; rec->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, (unsigned long *)&rec->args); - perf_tp_event(sys_data->enter_event->id, 0, 1, rec, size); - -end: - perf_swevent_put_recursion_context(rctx); -end_recursion: - local_irq_restore(flags); + ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); } int prof_sysenter_enable(struct ftrace_event_call *call) @@ -531,11 +506,8 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) struct syscall_trace_exit *rec; unsigned long flags; int syscall_nr; - char *trace_buf; - char *raw_data; int rctx; int size; - int cpu; syscall_nr = syscall_get_nr(current, regs); if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) @@ -557,38 +529,15 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) "exit event has grown above profile buffer size")) return; - /* Protect the per cpu buffer, begin the rcu read side */ - local_irq_save(flags); - - rctx = perf_swevent_get_recursion_context(); - if (rctx < 0) - goto end_recursion; - - cpu = smp_processor_id(); - - trace_buf = rcu_dereference(perf_trace_buf); - - if (!trace_buf) - goto end; - - raw_data = per_cpu_ptr(trace_buf, cpu); - - /* zero the dead bytes from align to not leak stack to user */ - *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; - - rec = (struct syscall_trace_exit *)raw_data; + rec = (struct syscall_trace_exit *)ftrace_perf_buf_prepare(size, + sys_data->exit_event->id, &rctx, &flags); + if (!rec) + return; - tracing_generic_entry_update(&rec->ent, 0, 0); - rec->ent.type = sys_data->exit_event->id; rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); - perf_tp_event(sys_data->exit_event->id, 0, 1, rec, size); - -end: - perf_swevent_put_recursion_context(rctx); -end_recursion: - local_irq_restore(flags); + ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); } int prof_sysexit_enable(struct ftrace_event_call *call) -- GitLab From 49214640f52506fbba00eb998fc39f10653a840a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:06 -0700 Subject: [PATCH 1319/3892] OMAP2xxx clock: move the APLL clock code into mach-omap2/clkt2xxx_apll.c Move the APLL-related clock functions from clock2xxx.c to mach-omap2/clkt2xxx_apll.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage APLLs are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for APLL clocks alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/ directory, rather than shared with other chip types that don't use this clock type. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Richard Woodruff Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt2xxx_apll.c | 120 ++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock2xxx.c | 86 +------------------- arch/arm/mach-omap2/clock2xxx.h | 1 + 4 files changed, 124 insertions(+), 86 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_apll.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 2b58363a8947..825c303f671f 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -12,7 +12,8 @@ clock-common = clock.o clock_common_data.o \ clockdomain.o clkt_dpll.o \ clkt_clksel.o clock-omap2xxx = clkt2xxx_dpllcore.o \ - clkt2xxx_virt_prcm_set.o + clkt2xxx_virt_prcm_set.o \ + clkt2xxx_apll.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(clock-omap2xxx) diff --git a/arch/arm/mach-omap2/clkt2xxx_apll.c b/arch/arm/mach-omap2/clkt2xxx_apll.c new file mode 100644 index 000000000000..fc32ff8e790f --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_apll.c @@ -0,0 +1,120 @@ +/* + * OMAP2xxx APLL clock control functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include + +#include +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "cm.h" +#include "cm-regbits-24xx.h" + +/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */ +#define EN_APLL_STOPPED 0 +#define EN_APLL_LOCKED 3 + +/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */ +#define APLLS_CLKIN_19_2MHZ 0 +#define APLLS_CLKIN_13MHZ 2 +#define APLLS_CLKIN_12MHZ 3 + +/* Private functions */ + +/* Enable an APLL if off */ +static int omap2_clk_apll_enable(struct clk *clk, u32 status_mask) +{ + u32 cval, apll_mask; + + apll_mask = EN_APLL_LOCKED << clk->enable_bit; + + cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); + + if ((cval & apll_mask) == apll_mask) + return 0; /* apll already enabled */ + + cval &= ~apll_mask; + cval |= apll_mask; + cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); + + omap2_cm_wait_idlest(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), status_mask, + clk->name); + + /* + * REVISIT: Should we return an error code if omap2_wait_clock_ready() + * fails? + */ + return 0; +} + +static int omap2_clk_apll96_enable(struct clk *clk) +{ + return omap2_clk_apll_enable(clk, OMAP24XX_ST_96M_APLL); +} + +static int omap2_clk_apll54_enable(struct clk *clk) +{ + return omap2_clk_apll_enable(clk, OMAP24XX_ST_54M_APLL); +} + +/* Stop APLL */ +static void omap2_clk_apll_disable(struct clk *clk) +{ + u32 cval; + + cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); + cval &= ~(EN_APLL_LOCKED << clk->enable_bit); + cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); +} + +/* Public data */ + +const struct clkops clkops_apll96 = { + .enable = omap2_clk_apll96_enable, + .disable = omap2_clk_apll_disable, +}; + +const struct clkops clkops_apll54 = { + .enable = omap2_clk_apll54_enable, + .disable = omap2_clk_apll_disable, +}; + +/* Public functions */ + +u32 omap2xxx_get_apll_clkin(void) +{ + u32 aplls, srate = 0; + + aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1); + aplls &= OMAP24XX_APLLS_CLKIN_MASK; + aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT; + + if (aplls == APLLS_CLKIN_19_2MHZ) + srate = 19200000; + else if (aplls == APLLS_CLKIN_13MHZ) + srate = 13000000; + else if (aplls == APLLS_CLKIN_12MHZ) + srate = 12000000; + + return srate; +} + diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index 11d6edb0b32f..88077e746966 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -44,16 +44,6 @@ #include "cm.h" #include "cm-regbits-24xx.h" - -/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */ -#define EN_APLL_STOPPED 0 -#define EN_APLL_LOCKED 3 - -/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */ -#define APLLS_CLKIN_19_2MHZ 0 -#define APLLS_CLKIN_13MHZ 2 -#define APLLS_CLKIN_12MHZ 3 - struct clk *vclk, *sclk, *dclk; void __iomem *prcm_clksrc_ctrl; @@ -126,80 +116,6 @@ static void omap2_sys_clk_recalc(struct clk *clk) } #endif /* OLD_CK */ -/* Enable an APLL if off */ -static int omap2_clk_apll_enable(struct clk *clk, u32 status_mask) -{ - u32 cval, apll_mask; - - apll_mask = EN_APLL_LOCKED << clk->enable_bit; - - cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); - - if ((cval & apll_mask) == apll_mask) - return 0; /* apll already enabled */ - - cval &= ~apll_mask; - cval |= apll_mask; - cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); - - omap2_cm_wait_idlest(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), status_mask, - clk->name); - - /* - * REVISIT: Should we return an error code if omap2_wait_clock_ready() - * fails? - */ - return 0; -} - -static int omap2_clk_apll96_enable(struct clk *clk) -{ - return omap2_clk_apll_enable(clk, OMAP24XX_ST_96M_APLL); -} - -static int omap2_clk_apll54_enable(struct clk *clk) -{ - return omap2_clk_apll_enable(clk, OMAP24XX_ST_54M_APLL); -} - -/* Stop APLL */ -static void omap2_clk_apll_disable(struct clk *clk) -{ - u32 cval; - - cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); - cval &= ~(EN_APLL_LOCKED << clk->enable_bit); - cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); -} - -const struct clkops clkops_apll96 = { - .enable = omap2_clk_apll96_enable, - .disable = omap2_clk_apll_disable, -}; - -const struct clkops clkops_apll54 = { - .enable = omap2_clk_apll54_enable, - .disable = omap2_clk_apll_disable, -}; - -static u32 omap2_get_apll_clkin(void) -{ - u32 aplls, srate = 0; - - aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1); - aplls &= OMAP24XX_APLLS_CLKIN_MASK; - aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT; - - if (aplls == APLLS_CLKIN_19_2MHZ) - srate = 19200000; - else if (aplls == APLLS_CLKIN_13MHZ) - srate = 13000000; - else if (aplls == APLLS_CLKIN_12MHZ) - srate = 12000000; - - return srate; -} - static u32 omap2_get_sysclkdiv(void) { u32 div; @@ -213,7 +129,7 @@ static u32 omap2_get_sysclkdiv(void) unsigned long omap2_osc_clk_recalc(struct clk *clk) { - return omap2_get_apll_clkin() * omap2_get_sysclkdiv(); + return omap2xxx_get_apll_clkin() * omap2_get_sysclkdiv(); } unsigned long omap2_sys_clk_recalc(struct clk *clk) diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index e35efde4bd80..3f1672e071c2 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -17,6 +17,7 @@ unsigned long omap2_sys_clk_recalc(struct clk *clk); unsigned long omap2_dpllcore_recalc(struct clk *clk); int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate); unsigned long omap2xxx_clk_get_core_rate(struct clk *clk); +u32 omap2xxx_get_apll_clkin(void); /* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */ #ifdef CONFIG_ARCH_OMAP2420 -- GitLab From 87a1b26c2d31dce62758b78c077ff5a1b5a52ab8 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:07 -0700 Subject: [PATCH 1320/3892] OMAP2xxx clock: move osc_clk code into mach-omap2/clkt2xxx_osc.c Move the osc_clk clock functions from clock2xxx.c to mach-omap2/clkt2xxx_osc. This is intended to make the clock code easier to understand, since all of the functions needed to manage the osc_clk are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for osc_clk clocks alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/ directory, rather than shared with other chip types that don't use this clock type. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clkt2xxx_osc.c | 62 ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock2xxx.c | 34 +--------------- arch/arm/mach-omap2/clock2xxx.h | 1 + 4 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_osc.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 825c303f671f..51178bff698c 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -13,7 +13,7 @@ clock-common = clock.o clock_common_data.o \ clkt_clksel.o clock-omap2xxx = clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ - clkt2xxx_apll.o + clkt2xxx_apll.o clkt2xxx_osc.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(clock-omap2xxx) diff --git a/arch/arm/mach-omap2/clkt2xxx_osc.c b/arch/arm/mach-omap2/clkt2xxx_osc.c new file mode 100644 index 000000000000..2167be84a5bc --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_osc.c @@ -0,0 +1,62 @@ +/* + * OMAP2xxx osc_clk-specific clock code + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include +#include +#include + +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "prm.h" +#include "prm-regbits-24xx.h" + +static int omap2_enable_osc_ck(struct clk *clk) +{ + u32 pcc; + + pcc = __raw_readl(prcm_clksrc_ctrl); + + __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); + + return 0; +} + +static void omap2_disable_osc_ck(struct clk *clk) +{ + u32 pcc; + + pcc = __raw_readl(prcm_clksrc_ctrl); + + __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); +} + +const struct clkops clkops_oscck = { + .enable = omap2_enable_osc_ck, + .disable = omap2_disable_osc_ck, +}; + +unsigned long omap2_osc_clk_recalc(struct clk *clk) +{ + return omap2xxx_get_apll_clkin() * omap2xxx_get_sysclkdiv(); +} + diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index 88077e746966..62c3b022a1e9 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -79,31 +79,6 @@ const struct clkops clkops_omap2430_i2chs_wait = { .find_companion = omap2_clk_dflt_find_companion, }; -static int omap2_enable_osc_ck(struct clk *clk) -{ - u32 pcc; - - pcc = __raw_readl(prcm_clksrc_ctrl); - - __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); - - return 0; -} - -static void omap2_disable_osc_ck(struct clk *clk) -{ - u32 pcc; - - pcc = __raw_readl(prcm_clksrc_ctrl); - - __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); -} - -const struct clkops clkops_oscck = { - .enable = omap2_enable_osc_ck, - .disable = omap2_disable_osc_ck, -}; - #ifdef OLD_CK /* Recalculate SYST_CLK */ static void omap2_sys_clk_recalc(struct clk *clk) @@ -116,7 +91,7 @@ static void omap2_sys_clk_recalc(struct clk *clk) } #endif /* OLD_CK */ -static u32 omap2_get_sysclkdiv(void) +u32 omap2xxx_get_sysclkdiv(void) { u32 div; @@ -127,14 +102,9 @@ static u32 omap2_get_sysclkdiv(void) return div; } -unsigned long omap2_osc_clk_recalc(struct clk *clk) -{ - return omap2xxx_get_apll_clkin() * omap2_get_sysclkdiv(); -} - unsigned long omap2_sys_clk_recalc(struct clk *clk) { - return clk->parent->rate / omap2_get_sysclkdiv(); + return clk->parent->rate / omap2xxx_get_sysclkdiv(); } /* diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index 3f1672e071c2..3b0610dbbd37 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -18,6 +18,7 @@ unsigned long omap2_dpllcore_recalc(struct clk *clk); int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate); unsigned long omap2xxx_clk_get_core_rate(struct clk *clk); u32 omap2xxx_get_apll_clkin(void); +u32 omap2xxx_get_sysclkdiv(void); /* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */ #ifdef CONFIG_ARCH_OMAP2420 -- GitLab From 44da0a51032f3d90a441bd80c2efe68532104980 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:08 -0700 Subject: [PATCH 1321/3892] OMAP2xxx clock: move sys_clk code into mach-omap2/clkt2xxx_sys.c Move the sys_clk clock functions from clock2xxx.c to mach-omap2/clkt2xxx_sys.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage the sys_clk are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for the sys_clk clock alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/ directory, rather than shared with other chip types that don't use this clock type. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt2xxx_sys.c | 50 ++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock2xxx.c | 30 ----------------- arch/arm/mach-omap2/clock2xxx.h | 3 +- arch/arm/mach-omap2/clock2xxx_data.c | 4 +-- 5 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt2xxx_sys.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 51178bff698c..7ce5fea7f2bc 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -13,7 +13,8 @@ clock-common = clock.o clock_common_data.o \ clkt_clksel.o clock-omap2xxx = clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ - clkt2xxx_apll.o clkt2xxx_osc.o + clkt2xxx_apll.o clkt2xxx_osc.o \ + clkt2xxx_sys.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(clock-omap2xxx) diff --git a/arch/arm/mach-omap2/clkt2xxx_sys.c b/arch/arm/mach-omap2/clkt2xxx_sys.c new file mode 100644 index 000000000000..822b5a79f457 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_sys.c @@ -0,0 +1,50 @@ +/* + * OMAP2xxx sys_clk-specific clock code + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include + +#include "clock.h" +#include "clock2xxx.h" +#include "prm.h" +#include "prm-regbits-24xx.h" + +void __iomem *prcm_clksrc_ctrl; + +u32 omap2xxx_get_sysclkdiv(void) +{ + u32 div; + + div = __raw_readl(prcm_clksrc_ctrl); + div &= OMAP_SYSCLKDIV_MASK; + div >>= OMAP_SYSCLKDIV_SHIFT; + + return div; +} + +unsigned long omap2xxx_sys_clk_recalc(struct clk *clk) +{ + return clk->parent->rate / omap2xxx_get_sysclkdiv(); +} + + diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index 62c3b022a1e9..b59cb1d2bf55 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -46,8 +46,6 @@ struct clk *vclk, *sclk, *dclk; -void __iomem *prcm_clksrc_ctrl; - /*------------------------------------------------------------------------- * Omap24xx specific clock functions *-------------------------------------------------------------------------*/ @@ -79,34 +77,6 @@ const struct clkops clkops_omap2430_i2chs_wait = { .find_companion = omap2_clk_dflt_find_companion, }; -#ifdef OLD_CK -/* Recalculate SYST_CLK */ -static void omap2_sys_clk_recalc(struct clk *clk) -{ - u32 div = PRCM_CLKSRC_CTRL; - div &= (1 << 7) | (1 << 6); /* Test if ext clk divided by 1 or 2 */ - div >>= clk->rate_offset; - clk->rate = (clk->parent->rate / div); - propagate_rate(clk); -} -#endif /* OLD_CK */ - -u32 omap2xxx_get_sysclkdiv(void) -{ - u32 div; - - div = __raw_readl(prcm_clksrc_ctrl); - div &= OMAP_SYSCLKDIV_MASK; - div >>= OMAP_SYSCLKDIV_SHIFT; - - return div; -} - -unsigned long omap2_sys_clk_recalc(struct clk *clk) -{ - return clk->parent->rate / omap2xxx_get_sysclkdiv(); -} - /* * Set clocks for bypass mode for reboot to work. */ diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index 3b0610dbbd37..c14061b2b9f1 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -11,9 +11,8 @@ unsigned long omap2_table_mpu_recalc(struct clk *clk); int omap2_select_table_rate(struct clk *clk, unsigned long rate); long omap2_round_to_table_rate(struct clk *clk, unsigned long rate); -unsigned long omap2_sys_clk_recalc(struct clk *clk); +unsigned long omap2xxx_sys_clk_recalc(struct clk *clk); unsigned long omap2_osc_clk_recalc(struct clk *clk); -unsigned long omap2_sys_clk_recalc(struct clk *clk); unsigned long omap2_dpllcore_recalc(struct clk *clk); int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate); unsigned long omap2xxx_clk_get_core_rate(struct clk *clk); diff --git a/arch/arm/mach-omap2/clock2xxx_data.c b/arch/arm/mach-omap2/clock2xxx_data.c index 402115fa9c12..3a435bb8f029 100644 --- a/arch/arm/mach-omap2/clock2xxx_data.c +++ b/arch/arm/mach-omap2/clock2xxx_data.c @@ -79,7 +79,7 @@ static struct clk sys_ck = { /* (*12, *13, 19.2, 26, 38.4)MHz */ .ops = &clkops_null, .parent = &osc_ck, .clkdm_name = "wkup_clkdm", - .recalc = &omap2_sys_clk_recalc, + .recalc = &omap2xxx_sys_clk_recalc, }; static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */ @@ -2264,7 +2264,7 @@ int __init omap2_clk_init(void) osc_ck.rate = omap2_osc_clk_recalc(&osc_ck); propagate_rate(&osc_ck); - sys_ck.rate = omap2_sys_clk_recalc(&sys_ck); + sys_ck.rate = omap2xxx_sys_clk_recalc(&sys_ck); propagate_rate(&sys_ck); for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++) -- GitLab From 6ebe0d88f5fead21d6e1ac328acc683c173d26fc Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:09 -0700 Subject: [PATCH 1322/3892] OMAP2 clock: don't compile OMAP2430-only functions on non-2430 builds omap2430_clk_i2chs_find_idlest() doesn't need to be compiled in on non-2430 builds, so skip it in those cases to save memory. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock2xxx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index b59cb1d2bf55..e5b9851b7419 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -50,6 +50,8 @@ struct clk *vclk, *sclk, *dclk; * Omap24xx specific clock functions *-------------------------------------------------------------------------*/ +#ifdef CONFIG_ARCH_OMAP2430 + /** * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS * @clk: struct clk * being enabled @@ -69,6 +71,10 @@ static void omap2430_clk_i2chs_find_idlest(struct clk *clk, *idlest_bit = clk->enable_bit; } +#else +#define omap2430_clk_i2chs_find_idlest NULL +#endif + /* 2430 I2CHS has non-standard IDLEST register */ const struct clkops clkops_omap2430_i2chs_wait = { .enable = omap2_dflt_clk_enable, -- GitLab From 35e424e2c0229aa1e32776fac23902150bd0ab9a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:09 -0700 Subject: [PATCH 1323/3892] OMAP3 clock: split out DPLL3 M2 divider functions into mach-omap2/clkt34xx_dpll3m2.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the DPLL3 M2 divider clock functions out of clock34xx.c and move them into mach-omap2/clkt34xx_dpll3m2.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage the OMAP3 DPLL3 M2 divider are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for the DPLL3 M2 clock alone. This should reduce unnecessary console noise when debugging DVFS. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap34xx/ directory, rather than shared with other chip types that don't use this clock type. This patch also lays the groundwork to skip compilation of this code on OMAP3 chips that don't support DVFS (e.g., AM35xx) via the Makefile, rather than via #ifdefs. Thanks to Alexander Shishkin for his comments to improve the patch description. Signed-off-by: Paul Walmsley Cc: Jouni Högander Cc: Alexander Shishkin --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt34xx_dpll3m2.c | 120 +++++++++++++++++++++++++ arch/arm/mach-omap2/clock34xx.c | 90 ------------------- 3 files changed, 122 insertions(+), 91 deletions(-) create mode 100644 arch/arm/mach-omap2/clkt34xx_dpll3m2.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 7ce5fea7f2bc..34c2867e0f63 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -15,11 +15,12 @@ clock-omap2xxx = clkt2xxx_dpllcore.o \ clkt2xxx_virt_prcm_set.o \ clkt2xxx_apll.o clkt2xxx_osc.o \ clkt2xxx_sys.o +clock-omap3xxx = clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ $(clock-omap2xxx) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ - $(omap-3-4-common) + $(omap-3-4-common) $(clock-omap3xxx) obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) $(clock-common) obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c new file mode 100644 index 000000000000..8716a01d1f5b --- /dev/null +++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c @@ -0,0 +1,120 @@ +/* + * OMAP34xx M2 divider clock code + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Copyright (C) 2007-2010 Nokia Corporation + * + * Paul Walmsley + * Jouni Högander + * + * Parts of this code are based on code written by + * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu + * + * 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. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" +#include "clock34xx.h" +#include "sdrc.h" + +#define CYCLES_PER_MHZ 1000000 + +/* + * CORE DPLL (DPLL3) M2 divider rate programming functions + * + * These call into SRAM code to do the actual CM writes, since the SDRAM + * is clocked from DPLL3. + */ + +/** + * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider + * @clk: struct clk * of DPLL to set + * @rate: rounded target rate + * + * Program the DPLL M2 divider with the rounded target rate. Returns + * -EINVAL upon error, or 0 upon success. + */ +int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div = 0; + u32 unlock_dll = 0; + u32 c; + unsigned long validrate, sdrcrate, _mpurate; + struct omap_sdrc_params *sdrc_cs0; + struct omap_sdrc_params *sdrc_cs1; + int ret; + + if (!clk || !rate) + return -EINVAL; + + validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + if (validrate != rate) + return -EINVAL; + + sdrcrate = sdrc_ick_p->rate; + if (rate > clk->rate) + sdrcrate <<= ((rate / clk->rate) >> 1); + else + sdrcrate >>= ((clk->rate / rate) >> 1); + + ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1); + if (ret) + return -EINVAL; + + if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { + pr_debug("clock: will unlock SDRC DLL\n"); + unlock_dll = 1; + } + + /* + * XXX This only needs to be done when the CPU frequency changes + */ + _mpurate = arm_fck_p->rate / CYCLES_PER_MHZ; + c = (_mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT; + c += 1; /* for safety */ + c *= SDRC_MPURATE_LOOPS; + c >>= SDRC_MPURATE_SCALE; + if (c == 0) + c = 1; + + pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, + validrate); + pr_debug("clock: SDRC CS0 timing params used:" + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr); + if (sdrc_cs1) + pr_debug("clock: SDRC CS1 timing params used: " + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + + if (sdrc_cs1) + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + else + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + 0, 0, 0, 0); + + return 0; +} + diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 4c4bb3cb79e8..552ad300bb0e 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -42,8 +42,6 @@ #include "cm.h" #include "cm-regbits-34xx.h" -#define CYCLES_PER_MHZ 1000000 - /* * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks * that are sourced by DPLL5, and both of these require this clock @@ -162,94 +160,6 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) return omap3_noncore_dpll_set_rate(clk, rate); } - -/* - * CORE DPLL (DPLL3) rate programming functions - * - * These call into SRAM code to do the actual CM writes, since the SDRAM - * is clocked from DPLL3. - */ - -/** - * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider - * @clk: struct clk * of DPLL to set - * @rate: rounded target rate - * - * Program the DPLL M2 divider with the rounded target rate. Returns - * -EINVAL upon error, or 0 upon success. - */ -int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) -{ - u32 new_div = 0; - u32 unlock_dll = 0; - u32 c; - unsigned long validrate, sdrcrate, _mpurate; - struct omap_sdrc_params *sdrc_cs0; - struct omap_sdrc_params *sdrc_cs1; - int ret; - - if (!clk || !rate) - return -EINVAL; - - validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); - if (validrate != rate) - return -EINVAL; - - sdrcrate = sdrc_ick_p->rate; - if (rate > clk->rate) - sdrcrate <<= ((rate / clk->rate) >> 1); - else - sdrcrate >>= ((clk->rate / rate) >> 1); - - ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1); - if (ret) - return -EINVAL; - - if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { - pr_debug("clock: will unlock SDRC DLL\n"); - unlock_dll = 1; - } - - /* - * XXX This only needs to be done when the CPU frequency changes - */ - _mpurate = arm_fck_p->rate / CYCLES_PER_MHZ; - c = (_mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT; - c += 1; /* for safety */ - c *= SDRC_MPURATE_LOOPS; - c >>= SDRC_MPURATE_SCALE; - if (c == 0) - c = 1; - - pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, - validrate); - pr_debug("clock: SDRC CS0 timing params used:" - " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", - sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, - sdrc_cs0->actim_ctrlb, sdrc_cs0->mr); - if (sdrc_cs1) - pr_debug("clock: SDRC CS1 timing params used: " - " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", - sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, - sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); - - if (sdrc_cs1) - omap3_configure_core_dpll( - new_div, unlock_dll, c, rate > clk->rate, - sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, - sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, - sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, - sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); - else - omap3_configure_core_dpll( - new_div, unlock_dll, c, rate > clk->rate, - sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, - sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, - 0, 0, 0, 0); - - return 0; -} - /* Common clock code */ /* -- GitLab From 1e12a4a7a3a78bc9c3aaf3486dde3b8ab1cdf465 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 28 Jan 2010 09:34:27 +0800 Subject: [PATCH 1324/3892] tracing/kprobe: Cleanup unused return value of tracing functions The return values of the kprobe's tracing functions are meaningless, lets remove these. Signed-off-by: Xiao Guangrong Acked-by: Masami Hiramatsu Cc: Steven Rostedt Cc: Ingo Molnar Cc: Paul Mackerras Cc: Jason Baron Cc: Peter Zijlstra LKML-Reference: <4B60E9A3.2040505@cn.fujitsu.com> [fweisbec@gmail: whitespace fixes, drop useless void returns in end of functions] Signed-off-by: Frederic Weisbecker --- kernel/trace/trace_kprobe.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 2e28ee36646f..6178abf3637e 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -942,7 +942,7 @@ static const struct file_operations kprobe_profile_ops = { }; /* Kprobe handler */ -static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) +static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) { struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); struct kprobe_trace_entry *entry; @@ -962,7 +962,7 @@ static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) event = trace_current_buffer_lock_reserve(&buffer, call->id, size, irq_flags, pc); if (!event) - return 0; + return; entry = ring_buffer_event_data(event); entry->nargs = tp->nr_args; @@ -972,11 +972,10 @@ static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) if (!filter_current_check_discard(buffer, call, entry, event)) trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); - return 0; } /* Kretprobe handler */ -static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri, +static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, struct pt_regs *regs) { struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); @@ -995,7 +994,7 @@ static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri, event = trace_current_buffer_lock_reserve(&buffer, call->id, size, irq_flags, pc); if (!event) - return 0; + return; entry = ring_buffer_event_data(event); entry->nargs = tp->nr_args; @@ -1006,8 +1005,6 @@ static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri, if (!filter_current_check_discard(buffer, call, entry, event)) trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); - - return 0; } /* Event entry printers */ @@ -1237,7 +1234,7 @@ static int kretprobe_event_show_format(struct ftrace_event_call *call, #ifdef CONFIG_PERF_EVENTS /* Kprobe profile handler */ -static __kprobes int kprobe_profile_func(struct kprobe *kp, +static __kprobes void kprobe_profile_func(struct kprobe *kp, struct pt_regs *regs) { struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); @@ -1252,11 +1249,11 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, size -= sizeof(u32); if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, "profile buffer not large enough")) - return 0; + return; entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); if (!entry) - return 0; + return; entry->nargs = tp->nr_args; entry->ip = (unsigned long)kp->addr; @@ -1264,12 +1261,10 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp, entry->args[i] = call_fetch(&tp->args[i].fetch, regs); ftrace_perf_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags); - - return 0; } /* Kretprobe profile handler */ -static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, +static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri, struct pt_regs *regs) { struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); @@ -1284,11 +1279,11 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, size -= sizeof(u32); if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, "profile buffer not large enough")) - return 0; + return; entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); if (!entry) - return 0; + return; entry->nargs = tp->nr_args; entry->func = (unsigned long)tp->rp.kp.addr; @@ -1297,8 +1292,6 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, entry->args[i] = call_fetch(&tp->args[i].fetch, regs); ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags); - - return 0; } static int probe_profile_enable(struct ftrace_event_call *call) -- GitLab From 40f9249a73f6c251adea492b1c3d19d39e2a9bda Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Thu, 28 Jan 2010 16:44:01 +0530 Subject: [PATCH 1325/3892] x86/debug: Clear reserved bits of DR6 in do_debug() Clear the reserved bits from the stored copy of debug status register (DR6). This will help easy bitwise operations such as quick testing of a debug event origin. Signed-off-by: K.Prasad Cc: Roland McGrath Cc: Jan Kiszka Cc: Alan Stern Cc: Ingo Molnar LKML-Reference: <20100128111401.GB13935@in.ibm.com> Signed-off-by: Frederic Weisbecker --- arch/x86/include/asm/debugreg.h | 3 +++ arch/x86/kernel/traps.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 8240f76b531e..b81002f23614 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -14,6 +14,9 @@ which debugging register was responsible for the trap. The other bits are either reserved or not of interest to us. */ +/* Define reserved bits in DR6 which are always set to 1 */ +#define DR6_RESERVED (0xFFFF0FF0) + #define DR_TRAP0 (0x1) /* db0 */ #define DR_TRAP1 (0x2) /* db1 */ #define DR_TRAP2 (0x4) /* db2 */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 33399176512a..1168e4454188 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -534,6 +534,9 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) get_debugreg(dr6, 6); + /* Filter out all the reserved bits which are preset to 1 */ + dr6 &= ~DR6_RESERVED; + /* Catch kmemcheck conditions first of all! */ if ((dr6 & DR_STEP) && kmemcheck_trap(regs)) return; -- GitLab From e0e53db6133c32964fd17f20b17073a402f07ed3 Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Thu, 28 Jan 2010 16:44:15 +0530 Subject: [PATCH 1326/3892] x86/hw-breakpoints: Optimize return code from notifier chain in hw_breakpoint_handler Processing of debug exceptions in do_debug() can stop if it originated from a hw-breakpoint exception by returning NOTIFY_STOP in most cases. But for certain cases such as: a) user-space breakpoints with pending SIGTRAP signal delivery (as in the case of ptrace induced breakpoints). b) exceptions due to other causes than breakpoints We will continue to process the exception by returning NOTIFY_DONE. Signed-off-by: K.Prasad Cc: Ingo Molnar Cc: Roland McGrath Cc: Alan Stern Cc: Jan Kiszka LKML-Reference: <20100128111415.GC13935@in.ibm.com> Signed-off-by: Frederic Weisbecker --- arch/x86/kernel/hw_breakpoint.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 05d5fec64a94..ae90b4739435 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -502,8 +502,6 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_lock(); bp = per_cpu(bp_per_reg[i], cpu); - if (bp) - rc = NOTIFY_DONE; /* * Reset the 'i'th TRAP bit in dr6 to denote completion of * exception handling @@ -522,7 +520,13 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_unlock(); } - if (dr6 & (~DR_TRAP_BITS)) + /* + * Further processing in do_debug() is needed for a) user-space + * breakpoints (to generate signals) and b) when the system has + * taken exception due to multiple causes + */ + if ((current->thread.debugreg6 & DR_TRAP_BITS) || + (dr6 & (~DR_TRAP_BITS))) rc = NOTIFY_DONE; set_debugreg(dr7, 7); -- GitLab From 57dbb2d83d100ea601c54fe129bfde0678db5dee Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Sun, 24 Jan 2010 12:30:59 +0000 Subject: [PATCH 1327/3892] sched: add head drop fifo queue This adds an additional queuing strategy, called pfifo_head_drop, to remove the oldest skb in the case of an overflow within the queue - the head element - instead of the last skb (tail). To remove the oldest skb in congested situations is useful for sensor network environments where newer packets reflect the superior information. Reviewed-by: Florian Westphal Acked-by: Patrick McHardy Signed-off-by: Hagen Paul Pfeifer Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 1 + include/net/sch_generic.h | 19 +++++++++++++++++++ net/sched/sch_api.c | 1 + net/sched/sch_fifo.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 2d567265363e..b6cdc33b39c1 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -71,6 +71,7 @@ extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd); extern struct Qdisc_ops pfifo_qdisc_ops; extern struct Qdisc_ops bfifo_qdisc_ops; +extern struct Qdisc_ops pfifo_head_drop_qdisc_ops; extern int fifo_set_limit(struct Qdisc *q, unsigned int limit); extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index dad558bc06fa..67dc08eaaa45 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -427,6 +427,25 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) return __qdisc_dequeue_head(sch, &sch->q); } +static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, + struct sk_buff_head *list) +{ + struct sk_buff *skb = __qdisc_dequeue_head(sch, list); + + if (likely(skb != NULL)) { + unsigned int len = qdisc_pkt_len(skb); + kfree_skb(skb); + return len; + } + + return 0; +} + +static inline unsigned int qdisc_queue_drop_head(struct Qdisc *sch) +{ + return __qdisc_queue_drop_head(sch, &sch->q); +} + static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch, struct sk_buff_head *list) { diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 75fd1c672c61..6cd491013b50 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1707,6 +1707,7 @@ static int __init pktsched_init(void) { register_qdisc(&pfifo_qdisc_ops); register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&pfifo_head_drop_qdisc_ops); register_qdisc(&mq_qdisc_ops); proc_net_fops_create(&init_net, "psched", 0, &psched_fops); diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 69188e8358b4..4b0a6cc44c77 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -43,6 +43,26 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) return qdisc_reshape_fail(skb, sch); } +static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct sk_buff *skb_head; + struct fifo_sched_data *q = qdisc_priv(sch); + + if (likely(skb_queue_len(&sch->q) < q->limit)) + return qdisc_enqueue_tail(skb, sch); + + /* queue full, remove one skb to fulfill the limit */ + skb_head = qdisc_dequeue_head(sch); + sch->bstats.bytes -= qdisc_pkt_len(skb_head); + sch->bstats.packets--; + sch->qstats.drops++; + kfree_skb(skb_head); + + qdisc_enqueue_tail(skb, sch); + + return NET_XMIT_CN; +} + static int fifo_init(struct Qdisc *sch, struct nlattr *opt) { struct fifo_sched_data *q = qdisc_priv(sch); @@ -108,6 +128,20 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { }; EXPORT_SYMBOL(bfifo_qdisc_ops); +struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = { + .id = "pfifo_head_drop", + .priv_size = sizeof(struct fifo_sched_data), + .enqueue = pfifo_tail_enqueue, + .dequeue = qdisc_dequeue_head, + .peek = qdisc_peek_head, + .drop = qdisc_queue_drop_head, + .init = fifo_init, + .reset = qdisc_reset_queue, + .change = fifo_init, + .dump = fifo_dump, + .owner = THIS_MODULE, +}; + /* Pass size change message down to embedded FIFO */ int fifo_set_limit(struct Qdisc *q, unsigned int limit) { -- GitLab From dcfc32babbece923381bd3bffaf17373b5d97568 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 28 Jan 2010 22:37:39 -0800 Subject: [PATCH 1328/3892] Input: wm97xx - provide coordinate logs for accelerated I/O This aids debug of problematic systems. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mainstone-wm97xx.c | 3 +++ drivers/input/touchscreen/zylonite-wm97xx.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 6cdcf2a6e036..b6b8b1c7ecea 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -153,6 +153,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) if (pressure) p = MODR; + dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n", + x, y, p); + /* are samples valid */ if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index eca54dbdf493..048849867643 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -118,6 +118,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) if (pressure) p = MODR; + dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n", + x, y, p); + /* are samples valid */ if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || -- GitLab From 9762528f37ddc7071509dddb10e7b4b3b957fd01 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 29 Jan 2010 16:14:29 +0900 Subject: [PATCH 1329/3892] sh: Kill off deprecated fixed PCI memory window accessors. This kills off the deprected fixed memory range accessors for the cases of non-translatable ioremapping. Signed-off-by: Paul Mundt --- arch/sh/include/asm/pci.h | 14 -------------- arch/sh/mm/ioremap.c | 15 --------------- 2 files changed, 29 deletions(-) diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index 67f3999b544e..f362d8a045e7 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -99,20 +99,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev, } #endif -#ifdef CONFIG_SUPERH32 -/* - * If we're on an SH7751 or SH7780 PCI controller, PCI memory is mapped - * at the end of the address space in a special non-translatable area. - */ -#define PCI_MEM_FIXED_START 0xfd000000 -#define PCI_MEM_FIXED_END (PCI_MEM_FIXED_START + 0x01000000) - -#define is_pci_memory_fixed_range(s, e) \ - ((s) >= PCI_MEM_FIXED_START && (e) < PCI_MEM_FIXED_END) -#else -#define is_pci_memory_fixed_range(s, e) (0) -#endif - /* Board-specific fixup routines. */ int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin); diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index bb03308e8408..94583c5da855 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -45,18 +45,6 @@ __ioremap_caller(unsigned long phys_addr, unsigned long size, if (!size || last_addr < phys_addr) return NULL; - /* - * If we're in the fixed PCI memory range, mapping through page - * tables is not only pointless, but also fundamentally broken. - * Just return the physical address instead. - * - * For boards that map a small PCI memory aperture somewhere in - * P1/P2 space, ioremap() will already do the right thing, - * and we'll never get this far. - */ - if (is_pci_memory_fixed_range(phys_addr, size)) - return (void __iomem *)phys_addr; - /* * Mappings have to be page-aligned */ @@ -125,9 +113,6 @@ static inline int iomapping_nontranslatable(unsigned long offset) return 1; #endif - if (is_pci_memory_fixed_range(offset, 0)) - return 1; - return 0; } -- GitLab From 1da53e023029c067ba1277a33038c65d6e4c99b3 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 18 Jan 2010 10:58:01 +0200 Subject: [PATCH 1330/3892] perf_events, x86: Improve x86 event scheduling This patch improves event scheduling by maximizing the use of PMU registers regardless of the order in which events are created in a group. The algorithm takes into account the list of counter constraints for each event. It assigns events to counters from the most constrained, i.e., works on only one counter, to the least constrained, i.e., works on any counter. Intel Fixed counter events and the BTS special event are also handled via this algorithm which is designed to be fairly generic. The patch also updates the validation of an event to use the scheduling algorithm. This will cause early failure in perf_event_open(). The 2nd version of this patch follows the model used by PPC, by running the scheduling algorithm and the actual assignment separately. Actual assignment takes place in hw_perf_enable() whereas scheduling is implemented in hw_perf_group_sched_in() and x86_pmu_enable(). Signed-off-by: Stephane Eranian [ fixup whitespace and style nits as well as adding is_x86_event() ] Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <4b5430c6.0f975e0a.1bf9.ffff85fe@mx.google.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/perf_event.h | 16 +- arch/x86/kernel/cpu/perf_event.c | 775 +++++++++++++++++++++--------- 2 files changed, 574 insertions(+), 217 deletions(-) diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 8d9f8548a870..dbc082685d52 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -26,7 +26,14 @@ /* * Includes eventsel and unit mask as well: */ -#define ARCH_PERFMON_EVENT_MASK 0xffff + + +#define INTEL_ARCH_EVTSEL_MASK 0x000000FFULL +#define INTEL_ARCH_UNIT_MASK 0x0000FF00ULL +#define INTEL_ARCH_EDGE_MASK 0x00040000ULL +#define INTEL_ARCH_INV_MASK 0x00800000ULL +#define INTEL_ARCH_CNT_MASK 0xFF000000ULL +#define INTEL_ARCH_EVENT_MASK (INTEL_ARCH_UNIT_MASK|INTEL_ARCH_EVTSEL_MASK) /* * filter mask to validate fixed counter events. @@ -37,7 +44,12 @@ * The other filters are supported by fixed counters. * The any-thread option is supported starting with v3. */ -#define ARCH_PERFMON_EVENT_FILTER_MASK 0xff840000 +#define INTEL_ARCH_FIXED_MASK \ + (INTEL_ARCH_CNT_MASK| \ + INTEL_ARCH_INV_MASK| \ + INTEL_ARCH_EDGE_MASK|\ + INTEL_ARCH_UNIT_MASK|\ + INTEL_ARCH_EVENT_MASK) #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index ed1998b28a7c..995ac4ae379c 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -7,6 +7,7 @@ * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, + * Copyright (C) 2009 Google, Inc., Stephane Eranian * * For licencing details see kernel-base/COPYING */ @@ -68,26 +69,37 @@ struct debug_store { u64 pebs_event_reset[MAX_PEBS_EVENTS]; }; +#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) + +struct event_constraint { + u64 idxmsk[BITS_TO_U64(X86_PMC_IDX_MAX)]; + int code; + int cmask; +}; + struct cpu_hw_events { - struct perf_event *events[X86_PMC_IDX_MAX]; - unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + struct perf_event *events[X86_PMC_IDX_MAX]; /* in counter order */ unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; unsigned long interrupts; int enabled; struct debug_store *ds; -}; -struct event_constraint { - unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; - int code; + int n_events; + int n_added; + int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ + struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ }; -#define EVENT_CONSTRAINT(c, m) { .code = (c), .idxmsk[0] = (m) } -#define EVENT_CONSTRAINT_END { .code = 0, .idxmsk[0] = 0 } +#define EVENT_CONSTRAINT(c, n, m) { \ + .code = (c), \ + .cmask = (m), \ + .idxmsk[0] = (n) } -#define for_each_event_constraint(e, c) \ - for ((e) = (c); (e)->idxmsk[0]; (e)++) +#define EVENT_CONSTRAINT_END \ + { .code = 0, .cmask = 0, .idxmsk[0] = 0 } +#define for_each_event_constraint(e, c) \ + for ((e) = (c); (e)->cmask; (e)++) /* * struct x86_pmu - generic x86 pmu @@ -114,8 +126,9 @@ struct x86_pmu { u64 intel_ctrl; void (*enable_bts)(u64 config); void (*disable_bts)(void); - int (*get_event_idx)(struct cpu_hw_events *cpuc, - struct hw_perf_event *hwc); + void (*get_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event, u64 *idxmsk); + void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); + const struct event_constraint *event_constraints; }; static struct x86_pmu x86_pmu __read_mostly; @@ -124,7 +137,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; -static const struct event_constraint *event_constraints; +static int x86_perf_event_set_period(struct perf_event *event, + struct hw_perf_event *hwc, int idx); /* * Not sure about some of these @@ -171,14 +185,14 @@ static u64 p6_pmu_raw_event(u64 hw_event) return hw_event & P6_EVNTSEL_MASK; } -static const struct event_constraint intel_p6_event_constraints[] = +static struct event_constraint intel_p6_event_constraints[] = { - EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */ - EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ - EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */ - EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ - EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ - EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ + EVENT_CONSTRAINT(0xc1, 0x1, INTEL_ARCH_EVENT_MASK), /* FLOPS */ + EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */ + EVENT_CONSTRAINT(0x11, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */ + EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */ + EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */ + EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */ EVENT_CONSTRAINT_END }; @@ -196,32 +210,43 @@ static const u64 intel_perfmon_event_map[] = [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, }; -static const struct event_constraint intel_core_event_constraints[] = -{ - EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ - EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ - EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ - EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ - EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ - EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */ - EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */ - EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */ - EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */ +static struct event_constraint intel_core_event_constraints[] = +{ + EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ + EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ + EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */ + EVENT_CONSTRAINT(0x11, 0x2, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */ + EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */ + EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */ + EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */ + EVENT_CONSTRAINT(0x18, 0x1, INTEL_ARCH_EVENT_MASK), /* IDLE_DURING_DIV */ + EVENT_CONSTRAINT(0x19, 0x2, INTEL_ARCH_EVENT_MASK), /* DELAYED_BYPASS */ + EVENT_CONSTRAINT(0xa1, 0x1, INTEL_ARCH_EVENT_MASK), /* RS_UOPS_DISPATCH_CYCLES */ + EVENT_CONSTRAINT(0xcb, 0x1, INTEL_ARCH_EVENT_MASK), /* MEM_LOAD_RETIRED */ EVENT_CONSTRAINT_END }; -static const struct event_constraint intel_nehalem_event_constraints[] = -{ - EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */ - EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */ - EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */ - EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */ - EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */ - EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */ - EVENT_CONSTRAINT(0x51, 0x3), /* L1D */ - EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */ - EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */ - EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */ +static struct event_constraint intel_nehalem_event_constraints[] = +{ + EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ + EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ + EVENT_CONSTRAINT(0x40, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LD */ + EVENT_CONSTRAINT(0x41, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_ST */ + EVENT_CONSTRAINT(0x42, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK */ + EVENT_CONSTRAINT(0x43, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_ALL_REF */ + EVENT_CONSTRAINT(0x4e, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_PREFETCH */ + EVENT_CONSTRAINT(0x4c, 0x3, INTEL_ARCH_EVENT_MASK), /* LOAD_HIT_PRE */ + EVENT_CONSTRAINT(0x51, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D */ + EVENT_CONSTRAINT(0x52, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */ + EVENT_CONSTRAINT(0x53, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK_FB_HIT */ + EVENT_CONSTRAINT(0xc5, 0x3, INTEL_ARCH_EVENT_MASK), /* CACHE_LOCK_CYCLES */ + EVENT_CONSTRAINT_END +}; + +static struct event_constraint intel_gen_event_constraints[] = +{ + EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ + EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ EVENT_CONSTRAINT_END }; @@ -527,11 +552,11 @@ static u64 intel_pmu_raw_event(u64 hw_event) #define CORE_EVNTSEL_REG_MASK 0xFF000000ULL #define CORE_EVNTSEL_MASK \ - (CORE_EVNTSEL_EVENT_MASK | \ - CORE_EVNTSEL_UNIT_MASK | \ - CORE_EVNTSEL_EDGE_MASK | \ - CORE_EVNTSEL_INV_MASK | \ - CORE_EVNTSEL_REG_MASK) + (INTEL_ARCH_EVTSEL_MASK | \ + INTEL_ARCH_UNIT_MASK | \ + INTEL_ARCH_EDGE_MASK | \ + INTEL_ARCH_INV_MASK | \ + INTEL_ARCH_CNT_MASK) return hw_event & CORE_EVNTSEL_MASK; } @@ -1120,9 +1145,15 @@ static void amd_pmu_disable_all(void) void hw_perf_disable(void) { + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + if (!x86_pmu_initialized()) return; - return x86_pmu.disable_all(); + + if (cpuc->enabled) + cpuc->n_added = 0; + + x86_pmu.disable_all(); } static void p6_pmu_enable_all(void) @@ -1189,10 +1220,237 @@ static void amd_pmu_enable_all(void) } } +static const struct pmu pmu; + +static inline int is_x86_event(struct perf_event *event) +{ + return event->pmu == &pmu; +} + +static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) +{ + int i, j , w, num; + int weight, wmax; + unsigned long *c; + u64 constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + struct hw_perf_event *hwc; + + bitmap_zero(used_mask, X86_PMC_IDX_MAX); + + for (i = 0; i < n; i++) { + x86_pmu.get_event_constraints(cpuc, + cpuc->event_list[i], + constraints[i]); + } + + /* + * weight = number of possible counters + * + * 1 = most constrained, only works on one counter + * wmax = least constrained, works on any counter + * + * assign events to counters starting with most + * constrained events. + */ + wmax = x86_pmu.num_events; + + /* + * when fixed event counters are present, + * wmax is incremented by 1 to account + * for one more choice + */ + if (x86_pmu.num_events_fixed) + wmax++; + + num = n; + for (w = 1; num && w <= wmax; w++) { + /* for each event */ + for (i = 0; i < n; i++) { + c = (unsigned long *)constraints[i]; + hwc = &cpuc->event_list[i]->hw; + + weight = bitmap_weight(c, X86_PMC_IDX_MAX); + if (weight != w) + continue; + + /* + * try to reuse previous assignment + * + * This is possible despite the fact that + * events or events order may have changed. + * + * What matters is the level of constraints + * of an event and this is constant for now. + * + * This is possible also because we always + * scan from most to least constrained. Thus, + * if a counter can be reused, it means no, + * more constrained events, needed it. And + * next events will either compete for it + * (which cannot be solved anyway) or they + * have fewer constraints, and they can use + * another counter. + */ + j = hwc->idx; + if (j != -1 && !test_bit(j, used_mask)) + goto skip; + + for_each_bit(j, c, X86_PMC_IDX_MAX) { + if (!test_bit(j, used_mask)) + break; + } + + if (j == X86_PMC_IDX_MAX) + break; +skip: + set_bit(j, used_mask); + +#if 0 + pr_debug("CPU%d config=0x%llx idx=%d assign=%c\n", + smp_processor_id(), + hwc->config, + j, + assign ? 'y' : 'n'); +#endif + + if (assign) + assign[i] = j; + num--; + } + } + /* + * scheduling failed or is just a simulation, + * free resources if necessary + */ + if (!assign || num) { + for (i = 0; i < n; i++) { + if (x86_pmu.put_event_constraints) + x86_pmu.put_event_constraints(cpuc, cpuc->event_list[i]); + } + } + return num ? -ENOSPC : 0; +} + +/* + * dogrp: true if must collect siblings events (group) + * returns total number of events and error code + */ +static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, bool dogrp) +{ + struct perf_event *event; + int n, max_count; + + max_count = x86_pmu.num_events + x86_pmu.num_events_fixed; + + /* current number of events already accepted */ + n = cpuc->n_events; + + if (is_x86_event(leader)) { + if (n >= max_count) + return -ENOSPC; + cpuc->event_list[n] = leader; + n++; + } + if (!dogrp) + return n; + + list_for_each_entry(event, &leader->sibling_list, group_entry) { + if (!is_x86_event(event) || + event->state == PERF_EVENT_STATE_OFF) + continue; + + if (n >= max_count) + return -ENOSPC; + + cpuc->event_list[n] = event; + n++; + } + return n; +} + + +static inline void x86_assign_hw_event(struct perf_event *event, + struct hw_perf_event *hwc, int idx) +{ + hwc->idx = idx; + + if (hwc->idx == X86_PMC_IDX_FIXED_BTS) { + hwc->config_base = 0; + hwc->event_base = 0; + } else if (hwc->idx >= X86_PMC_IDX_FIXED) { + hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; + /* + * We set it so that event_base + idx in wrmsr/rdmsr maps to + * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2: + */ + hwc->event_base = + MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED; + } else { + hwc->config_base = x86_pmu.eventsel; + hwc->event_base = x86_pmu.perfctr; + } +} + void hw_perf_enable(void) { + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct perf_event *event; + struct hw_perf_event *hwc; + int i; + if (!x86_pmu_initialized()) return; + if (cpuc->n_added) { + /* + * apply assignment obtained either from + * hw_perf_group_sched_in() or x86_pmu_enable() + * + * step1: save events moving to new counters + * step2: reprogram moved events into new counters + */ + for (i = 0; i < cpuc->n_events; i++) { + + event = cpuc->event_list[i]; + hwc = &event->hw; + + if (hwc->idx == -1 || hwc->idx == cpuc->assign[i]) + continue; + + x86_pmu.disable(hwc, hwc->idx); + + clear_bit(hwc->idx, cpuc->active_mask); + barrier(); + cpuc->events[hwc->idx] = NULL; + + x86_perf_event_update(event, hwc, hwc->idx); + + hwc->idx = -1; + } + + for (i = 0; i < cpuc->n_events; i++) { + + event = cpuc->event_list[i]; + hwc = &event->hw; + + if (hwc->idx == -1) { + x86_assign_hw_event(event, hwc, cpuc->assign[i]); + x86_perf_event_set_period(event, hwc, hwc->idx); + } + /* + * need to mark as active because x86_pmu_disable() + * clear active_mask and eventsp[] yet it preserves + * idx + */ + set_bit(hwc->idx, cpuc->active_mask); + cpuc->events[hwc->idx] = event; + + x86_pmu.enable(hwc, hwc->idx); + perf_event_update_userpage(event); + } + cpuc->n_added = 0; + perf_events_lapic_init(); + } x86_pmu.enable_all(); } @@ -1391,148 +1649,43 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx) x86_pmu_enable_event(hwc, idx); } -static int fixed_mode_idx(struct hw_perf_event *hwc) -{ - unsigned int hw_event; - - hw_event = hwc->config & ARCH_PERFMON_EVENT_MASK; - - if (unlikely((hw_event == - x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) && - (hwc->sample_period == 1))) - return X86_PMC_IDX_FIXED_BTS; - - if (!x86_pmu.num_events_fixed) - return -1; - - /* - * fixed counters do not take all possible filters - */ - if (hwc->config & ARCH_PERFMON_EVENT_FILTER_MASK) - return -1; - - if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS))) - return X86_PMC_IDX_FIXED_INSTRUCTIONS; - if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) - return X86_PMC_IDX_FIXED_CPU_CYCLES; - if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_BUS_CYCLES))) - return X86_PMC_IDX_FIXED_BUS_CYCLES; - - return -1; -} - -/* - * generic counter allocator: get next free counter - */ -static int -gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc) -{ - int idx; - - idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events); - return idx == x86_pmu.num_events ? -1 : idx; -} - /* - * intel-specific counter allocator: check event constraints - */ -static int -intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc) -{ - const struct event_constraint *event_constraint; - int i, code; - - if (!event_constraints) - goto skip; - - code = hwc->config & CORE_EVNTSEL_EVENT_MASK; - - for_each_event_constraint(event_constraint, event_constraints) { - if (code == event_constraint->code) { - for_each_bit(i, event_constraint->idxmsk, X86_PMC_IDX_MAX) { - if (!test_and_set_bit(i, cpuc->used_mask)) - return i; - } - return -1; - } - } -skip: - return gen_get_event_idx(cpuc, hwc); -} - -static int -x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc) -{ - int idx; - - idx = fixed_mode_idx(hwc); - if (idx == X86_PMC_IDX_FIXED_BTS) { - /* BTS is already occupied. */ - if (test_and_set_bit(idx, cpuc->used_mask)) - return -EAGAIN; - - hwc->config_base = 0; - hwc->event_base = 0; - hwc->idx = idx; - } else if (idx >= 0) { - /* - * Try to get the fixed event, if that is already taken - * then try to get a generic event: - */ - if (test_and_set_bit(idx, cpuc->used_mask)) - goto try_generic; - - hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; - /* - * We set it so that event_base + idx in wrmsr/rdmsr maps to - * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2: - */ - hwc->event_base = - MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED; - hwc->idx = idx; - } else { - idx = hwc->idx; - /* Try to get the previous generic event again */ - if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) { -try_generic: - idx = x86_pmu.get_event_idx(cpuc, hwc); - if (idx == -1) - return -EAGAIN; - - set_bit(idx, cpuc->used_mask); - hwc->idx = idx; - } - hwc->config_base = x86_pmu.eventsel; - hwc->event_base = x86_pmu.perfctr; - } - - return idx; -} - -/* - * Find a PMC slot for the freshly enabled / scheduled in event: + * activate a single event + * + * The event is added to the group of enabled events + * but only if it can be scehduled with existing events. + * + * Called with PMU disabled. If successful and return value 1, + * then guaranteed to call perf_enable() and hw_perf_enable() */ static int x86_pmu_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - struct hw_perf_event *hwc = &event->hw; - int idx; + struct hw_perf_event *hwc; + int assign[X86_PMC_IDX_MAX]; + int n, n0, ret; - idx = x86_schedule_event(cpuc, hwc); - if (idx < 0) - return idx; + hwc = &event->hw; - perf_events_lapic_init(); + n0 = cpuc->n_events; + n = collect_events(cpuc, event, false); + if (n < 0) + return n; - x86_pmu.disable(hwc, idx); - - cpuc->events[idx] = event; - set_bit(idx, cpuc->active_mask); + ret = x86_schedule_events(cpuc, n, assign); + if (ret) + return ret; + /* + * copy new assignment, now we know it is possible + * will be used by hw_perf_enable() + */ + memcpy(cpuc->assign, assign, n*sizeof(int)); - x86_perf_event_set_period(event, hwc, idx); - x86_pmu.enable(hwc, idx); + cpuc->n_events = n; + cpuc->n_added = n - n0; - perf_event_update_userpage(event); + if (hwc->idx != -1) + x86_perf_event_set_period(event, hwc, hwc->idx); return 0; } @@ -1576,7 +1729,7 @@ void perf_event_print_debug(void) pr_info("CPU#%d: overflow: %016llx\n", cpu, overflow); pr_info("CPU#%d: fixed: %016llx\n", cpu, fixed); } - pr_info("CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used_mask); + pr_info("CPU#%d: active: %016llx\n", cpu, *(u64 *)cpuc->active_mask); for (idx = 0; idx < x86_pmu.num_events; idx++) { rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl); @@ -1664,7 +1817,7 @@ static void x86_pmu_disable(struct perf_event *event) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; + int i, idx = hwc->idx; /* * Must be done before we disable, otherwise the nmi handler @@ -1690,8 +1843,19 @@ static void x86_pmu_disable(struct perf_event *event) intel_pmu_drain_bts_buffer(cpuc); cpuc->events[idx] = NULL; - clear_bit(idx, cpuc->used_mask); + for (i = 0; i < cpuc->n_events; i++) { + if (event == cpuc->event_list[i]) { + + if (x86_pmu.put_event_constraints) + x86_pmu.put_event_constraints(cpuc, event); + + while (++i < cpuc->n_events) + cpuc->event_list[i-1] = cpuc->event_list[i]; + + --cpuc->n_events; + } + } perf_event_update_userpage(event); } @@ -1962,6 +2126,176 @@ perf_event_nmi_handler(struct notifier_block *self, return NOTIFY_STOP; } +static struct event_constraint bts_constraint = { + .code = 0, + .cmask = 0, + .idxmsk[0] = 1ULL << X86_PMC_IDX_FIXED_BTS +}; + +static int intel_special_constraints(struct perf_event *event, + u64 *idxmsk) +{ + unsigned int hw_event; + + hw_event = event->hw.config & INTEL_ARCH_EVENT_MASK; + + if (unlikely((hw_event == + x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) && + (event->hw.sample_period == 1))) { + + bitmap_copy((unsigned long *)idxmsk, + (unsigned long *)bts_constraint.idxmsk, + X86_PMC_IDX_MAX); + return 1; + } + return 0; +} + +static void intel_get_event_constraints(struct cpu_hw_events *cpuc, + struct perf_event *event, + u64 *idxmsk) +{ + const struct event_constraint *c; + + /* + * cleanup bitmask + */ + bitmap_zero((unsigned long *)idxmsk, X86_PMC_IDX_MAX); + + if (intel_special_constraints(event, idxmsk)) + return; + + if (x86_pmu.event_constraints) { + for_each_event_constraint(c, x86_pmu.event_constraints) { + if ((event->hw.config & c->cmask) == c->code) { + + bitmap_copy((unsigned long *)idxmsk, + (unsigned long *)c->idxmsk, + X86_PMC_IDX_MAX); + return; + } + } + } + /* no constraints, means supports all generic counters */ + bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events); +} + +static void amd_get_event_constraints(struct cpu_hw_events *cpuc, + struct perf_event *event, + u64 *idxmsk) +{ +} + +static int x86_event_sched_in(struct perf_event *event, + struct perf_cpu_context *cpuctx, int cpu) +{ + int ret = 0; + + event->state = PERF_EVENT_STATE_ACTIVE; + event->oncpu = cpu; + event->tstamp_running += event->ctx->time - event->tstamp_stopped; + + if (!is_x86_event(event)) + ret = event->pmu->enable(event); + + if (!ret && !is_software_event(event)) + cpuctx->active_oncpu++; + + if (!ret && event->attr.exclusive) + cpuctx->exclusive = 1; + + return ret; +} + +static void x86_event_sched_out(struct perf_event *event, + struct perf_cpu_context *cpuctx, int cpu) +{ + event->state = PERF_EVENT_STATE_INACTIVE; + event->oncpu = -1; + + if (!is_x86_event(event)) + event->pmu->disable(event); + + event->tstamp_running -= event->ctx->time - event->tstamp_stopped; + + if (!is_software_event(event)) + cpuctx->active_oncpu--; + + if (event->attr.exclusive || !cpuctx->active_oncpu) + cpuctx->exclusive = 0; +} + +/* + * Called to enable a whole group of events. + * Returns 1 if the group was enabled, or -EAGAIN if it could not be. + * Assumes the caller has disabled interrupts and has + * frozen the PMU with hw_perf_save_disable. + * + * called with PMU disabled. If successful and return value 1, + * then guaranteed to call perf_enable() and hw_perf_enable() + */ +int hw_perf_group_sched_in(struct perf_event *leader, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx, int cpu) +{ + struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); + struct perf_event *sub; + int assign[X86_PMC_IDX_MAX]; + int n0, n1, ret; + + /* n0 = total number of events */ + n0 = collect_events(cpuc, leader, true); + if (n0 < 0) + return n0; + + ret = x86_schedule_events(cpuc, n0, assign); + if (ret) + return ret; + + ret = x86_event_sched_in(leader, cpuctx, cpu); + if (ret) + return ret; + + n1 = 1; + list_for_each_entry(sub, &leader->sibling_list, group_entry) { + if (sub->state != PERF_EVENT_STATE_OFF) { + ret = x86_event_sched_in(sub, cpuctx, cpu); + if (ret) + goto undo; + ++n1; + } + } + /* + * copy new assignment, now we know it is possible + * will be used by hw_perf_enable() + */ + memcpy(cpuc->assign, assign, n0*sizeof(int)); + + cpuc->n_events = n0; + cpuc->n_added = n1; + ctx->nr_active += n1; + + /* + * 1 means successful and events are active + * This is not quite true because we defer + * actual activation until hw_perf_enable() but + * this way we* ensure caller won't try to enable + * individual events + */ + return 1; +undo: + x86_event_sched_out(leader, cpuctx, cpu); + n0 = 1; + list_for_each_entry(sub, &leader->sibling_list, group_entry) { + if (sub->state == PERF_EVENT_STATE_ACTIVE) { + x86_event_sched_out(sub, cpuctx, cpu); + if (++n0 == n1) + break; + } + } + return ret; +} + static __read_mostly struct notifier_block perf_event_nmi_notifier = { .notifier_call = perf_event_nmi_handler, .next = NULL, @@ -1993,7 +2327,8 @@ static __initconst struct x86_pmu p6_pmu = { */ .event_bits = 32, .event_mask = (1ULL << 32) - 1, - .get_event_idx = intel_get_event_idx, + .get_event_constraints = intel_get_event_constraints, + .event_constraints = intel_p6_event_constraints }; static __initconst struct x86_pmu intel_pmu = { @@ -2017,7 +2352,7 @@ static __initconst struct x86_pmu intel_pmu = { .max_period = (1ULL << 31) - 1, .enable_bts = intel_pmu_enable_bts, .disable_bts = intel_pmu_disable_bts, - .get_event_idx = intel_get_event_idx, + .get_event_constraints = intel_get_event_constraints }; static __initconst struct x86_pmu amd_pmu = { @@ -2038,7 +2373,7 @@ static __initconst struct x86_pmu amd_pmu = { .apic = 1, /* use highest bit to detect overflow */ .max_period = (1ULL << 47) - 1, - .get_event_idx = gen_get_event_idx, + .get_event_constraints = amd_get_event_constraints }; static __init int p6_pmu_init(void) @@ -2051,12 +2386,9 @@ static __init int p6_pmu_init(void) case 7: case 8: case 11: /* Pentium III */ - event_constraints = intel_p6_event_constraints; - break; case 9: case 13: /* Pentium M */ - event_constraints = intel_p6_event_constraints; break; default: pr_cont("unsupported p6 CPU model %d ", @@ -2121,23 +2453,29 @@ static __init int intel_pmu_init(void) memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, sizeof(hw_cache_event_ids)); + x86_pmu.event_constraints = intel_core_event_constraints; pr_cont("Core2 events, "); - event_constraints = intel_core_event_constraints; break; - default: case 26: memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); - event_constraints = intel_nehalem_event_constraints; + x86_pmu.event_constraints = intel_nehalem_event_constraints; pr_cont("Nehalem/Corei7 events, "); break; case 28: memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, sizeof(hw_cache_event_ids)); + x86_pmu.event_constraints = intel_gen_event_constraints; pr_cont("Atom events, "); break; + default: + /* + * default constraints for v2 and up + */ + x86_pmu.event_constraints = intel_gen_event_constraints; + pr_cont("generic architected perfmon, "); } return 0; } @@ -2234,36 +2572,43 @@ static const struct pmu pmu = { .unthrottle = x86_pmu_unthrottle, }; -static int -validate_event(struct cpu_hw_events *cpuc, struct perf_event *event) -{ - struct hw_perf_event fake_event = event->hw; - - if (event->pmu && event->pmu != &pmu) - return 0; - - return x86_schedule_event(cpuc, &fake_event) >= 0; -} - +/* + * validate a single event group + * + * validation include: + * - check events are compatible which each other + * - events do not compete for the same counter + * - number of events <= number of counters + * + * validation ensures the group can be loaded onto the + * PMU if it was the only group available. + */ static int validate_group(struct perf_event *event) { - struct perf_event *sibling, *leader = event->group_leader; - struct cpu_hw_events fake_pmu; + struct perf_event *leader = event->group_leader; + struct cpu_hw_events fake_cpuc; + int n; - memset(&fake_pmu, 0, sizeof(fake_pmu)); + memset(&fake_cpuc, 0, sizeof(fake_cpuc)); - if (!validate_event(&fake_pmu, leader)) + /* + * the event is not yet connected with its + * siblings therefore we must first collect + * existing siblings, then add the new event + * before we can simulate the scheduling + */ + n = collect_events(&fake_cpuc, leader, true); + if (n < 0) return -ENOSPC; - list_for_each_entry(sibling, &leader->sibling_list, group_entry) { - if (!validate_event(&fake_pmu, sibling)) - return -ENOSPC; - } - - if (!validate_event(&fake_pmu, event)) + fake_cpuc.n_events = n; + n = collect_events(&fake_cpuc, event, false); + if (n < 0) return -ENOSPC; - return 0; + fake_cpuc.n_events = n; + + return x86_schedule_events(&fake_cpuc, n, NULL); } const struct pmu *hw_perf_event_init(struct perf_event *event) -- GitLab From 8113070d6639d2245c6c79afb8df42cedab30540 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Thu, 21 Jan 2010 17:39:01 +0200 Subject: [PATCH 1331/3892] perf_events: Add fast-path to the rescheduling code Implement correct fastpath scheduling, i.e., reuse previous assignment. Signed-off-by: Stephane Eranian [ split from larger patch] Signed-off-by: Peter Zijlstra LKML-Reference: <4b588464.1818d00a.4456.383b@mx.google.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 91 +++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 995ac4ae379c..0bd23d01af34 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1244,6 +1244,46 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) constraints[i]); } + /* + * fastpath, try to reuse previous register + */ + for (i = 0, num = n; i < n; i++, num--) { + hwc = &cpuc->event_list[i]->hw; + c = (unsigned long *)constraints[i]; + + /* never assigned */ + if (hwc->idx == -1) + break; + + /* constraint still honored */ + if (!test_bit(hwc->idx, c)) + break; + + /* not already used */ + if (test_bit(hwc->idx, used_mask)) + break; + +#if 0 + pr_debug("CPU%d fast config=0x%llx idx=%d assign=%c\n", + smp_processor_id(), + hwc->config, + hwc->idx, + assign ? 'y' : 'n'); +#endif + + set_bit(hwc->idx, used_mask); + if (assign) + assign[i] = hwc->idx; + } + if (!num) + goto done; + + /* + * begin slow path + */ + + bitmap_zero(used_mask, X86_PMC_IDX_MAX); + /* * weight = number of possible counters * @@ -1263,10 +1303,9 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (x86_pmu.num_events_fixed) wmax++; - num = n; - for (w = 1; num && w <= wmax; w++) { + for (w = 1, num = n; num && w <= wmax; w++) { /* for each event */ - for (i = 0; i < n; i++) { + for (i = 0; num && i < n; i++) { c = (unsigned long *)constraints[i]; hwc = &cpuc->event_list[i]->hw; @@ -1274,28 +1313,6 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (weight != w) continue; - /* - * try to reuse previous assignment - * - * This is possible despite the fact that - * events or events order may have changed. - * - * What matters is the level of constraints - * of an event and this is constant for now. - * - * This is possible also because we always - * scan from most to least constrained. Thus, - * if a counter can be reused, it means no, - * more constrained events, needed it. And - * next events will either compete for it - * (which cannot be solved anyway) or they - * have fewer constraints, and they can use - * another counter. - */ - j = hwc->idx; - if (j != -1 && !test_bit(j, used_mask)) - goto skip; - for_each_bit(j, c, X86_PMC_IDX_MAX) { if (!test_bit(j, used_mask)) break; @@ -1303,22 +1320,23 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (j == X86_PMC_IDX_MAX) break; -skip: - set_bit(j, used_mask); #if 0 - pr_debug("CPU%d config=0x%llx idx=%d assign=%c\n", + pr_debug("CPU%d slow config=0x%llx idx=%d assign=%c\n", smp_processor_id(), hwc->config, j, assign ? 'y' : 'n'); #endif + set_bit(j, used_mask); + if (assign) assign[i] = j; num--; } } +done: /* * scheduling failed or is just a simulation, * free resources if necessary @@ -1357,7 +1375,7 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, list_for_each_entry(event, &leader->sibling_list, group_entry) { if (!is_x86_event(event) || - event->state == PERF_EVENT_STATE_OFF) + event->state <= PERF_EVENT_STATE_OFF) continue; if (n >= max_count) @@ -2184,6 +2202,8 @@ static void amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, u64 *idxmsk) { + /* no constraints, means supports all generic counters */ + bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events); } static int x86_event_sched_in(struct perf_event *event, @@ -2258,7 +2278,7 @@ int hw_perf_group_sched_in(struct perf_event *leader, n1 = 1; list_for_each_entry(sub, &leader->sibling_list, group_entry) { - if (sub->state != PERF_EVENT_STATE_OFF) { + if (sub->state > PERF_EVENT_STATE_OFF) { ret = x86_event_sched_in(sub, cpuctx, cpu); if (ret) goto undo; @@ -2613,12 +2633,23 @@ static int validate_group(struct perf_event *event) const struct pmu *hw_perf_event_init(struct perf_event *event) { + const struct pmu *tmp; int err; err = __hw_perf_event_init(event); if (!err) { + /* + * we temporarily connect event to its pmu + * such that validate_group() can classify + * it as an x86 event using is_x86_event() + */ + tmp = event->pmu; + event->pmu = &pmu; + if (event->group_leader != event) err = validate_group(event); + + event->pmu = tmp; } if (err) { if (event->destroy) -- GitLab From 502568d563bcc37ac505a83341c0c95b88c015a8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 14:35:46 +0100 Subject: [PATCH 1332/3892] perf_event: x86: Allocate the fake_cpuc GCC was complaining the stack usage was too large, so allocate the structure. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.411197266@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 0bd23d01af34..7bd359a57839 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -2606,10 +2606,13 @@ static const struct pmu pmu = { static int validate_group(struct perf_event *event) { struct perf_event *leader = event->group_leader; - struct cpu_hw_events fake_cpuc; - int n; + struct cpu_hw_events *fake_cpuc; + int ret, n; - memset(&fake_cpuc, 0, sizeof(fake_cpuc)); + ret = -ENOMEM; + fake_cpuc = kmalloc(sizeof(*fake_cpuc), GFP_KERNEL | __GFP_ZERO); + if (!fake_cpuc) + goto out; /* * the event is not yet connected with its @@ -2617,18 +2620,24 @@ static int validate_group(struct perf_event *event) * existing siblings, then add the new event * before we can simulate the scheduling */ - n = collect_events(&fake_cpuc, leader, true); + ret = -ENOSPC; + n = collect_events(fake_cpuc, leader, true); if (n < 0) - return -ENOSPC; + goto out_free; - fake_cpuc.n_events = n; - n = collect_events(&fake_cpuc, event, false); + fake_cpuc->n_events = n; + n = collect_events(fake_cpuc, event, false); if (n < 0) - return -ENOSPC; + goto out_free; - fake_cpuc.n_events = n; + fake_cpuc->n_events = n; - return x86_schedule_events(&fake_cpuc, n, NULL); + ret = x86_schedule_events(fake_cpuc, n, NULL); + +out_free: + kfree(fake_cpuc); +out: + return ret; } const struct pmu *hw_perf_event_init(struct perf_event *event) -- GitLab From 81269a085669b5130058a0275aa7ba9f94abd1fa Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 14:55:22 +0100 Subject: [PATCH 1333/3892] perf_event: x86: Fixup constraints typing issue Constraints gets defined an u64 but in long quantities and then cast to long. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.504916780@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 7bd359a57839..7e181a5097ea 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1232,7 +1232,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) int i, j , w, num; int weight, wmax; unsigned long *c; - u64 constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; struct hw_perf_event *hwc; @@ -1249,7 +1249,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) */ for (i = 0, num = n; i < n; i++, num--) { hwc = &cpuc->event_list[i]->hw; - c = (unsigned long *)constraints[i]; + c = constraints[i]; /* never assigned */ if (hwc->idx == -1) @@ -1306,7 +1306,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) for (w = 1, num = n; num && w <= wmax; w++) { /* for each event */ for (i = 0; num && i < n; i++) { - c = (unsigned long *)constraints[i]; + c = constraints[i]; hwc = &cpuc->event_list[i]->hw; weight = bitmap_weight(c, X86_PMC_IDX_MAX); -- GitLab From c91e0f5da81c6f3a611a1bd6d0cca6717c90fdab Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 15:25:59 +0100 Subject: [PATCH 1334/3892] perf_event: x86: Clean up some of the u64/long bitmask casting We need this to be u64 for direct assigment, but the bitmask functions all work on unsigned long, leading to cast heaven, solve this by using a union. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.595961269@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 47 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 7e181a5097ea..921bbf732e77 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -69,10 +69,11 @@ struct debug_store { u64 pebs_event_reset[MAX_PEBS_EVENTS]; }; -#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) - struct event_constraint { - u64 idxmsk[BITS_TO_U64(X86_PMC_IDX_MAX)]; + union { + unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + u64 idxmsk64[1]; + }; int code; int cmask; }; @@ -90,13 +91,14 @@ struct cpu_hw_events { struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ }; -#define EVENT_CONSTRAINT(c, n, m) { \ - .code = (c), \ - .cmask = (m), \ - .idxmsk[0] = (n) } +#define EVENT_CONSTRAINT(c, n, m) { \ + { .idxmsk64[0] = (n) }, \ + .code = (c), \ + .cmask = (m), \ +} #define EVENT_CONSTRAINT_END \ - { .code = 0, .cmask = 0, .idxmsk[0] = 0 } + EVENT_CONSTRAINT(0, 0, 0) #define for_each_event_constraint(e, c) \ for ((e) = (c); (e)->cmask; (e)++) @@ -126,8 +128,11 @@ struct x86_pmu { u64 intel_ctrl; void (*enable_bts)(u64 config); void (*disable_bts)(void); - void (*get_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event, u64 *idxmsk); - void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); + void (*get_event_constraints)(struct cpu_hw_events *cpuc, + struct perf_event *event, + unsigned long *idxmsk); + void (*put_event_constraints)(struct cpu_hw_events *cpuc, + struct perf_event *event); const struct event_constraint *event_constraints; }; @@ -2144,14 +2149,11 @@ perf_event_nmi_handler(struct notifier_block *self, return NOTIFY_STOP; } -static struct event_constraint bts_constraint = { - .code = 0, - .cmask = 0, - .idxmsk[0] = 1ULL << X86_PMC_IDX_FIXED_BTS -}; +static struct event_constraint bts_constraint = + EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0); static int intel_special_constraints(struct perf_event *event, - u64 *idxmsk) + unsigned long *idxmsk) { unsigned int hw_event; @@ -2171,14 +2173,14 @@ static int intel_special_constraints(struct perf_event *event, static void intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, - u64 *idxmsk) + unsigned long *idxmsk) { const struct event_constraint *c; /* * cleanup bitmask */ - bitmap_zero((unsigned long *)idxmsk, X86_PMC_IDX_MAX); + bitmap_zero(idxmsk, X86_PMC_IDX_MAX); if (intel_special_constraints(event, idxmsk)) return; @@ -2186,10 +2188,7 @@ static void intel_get_event_constraints(struct cpu_hw_events *cpuc, if (x86_pmu.event_constraints) { for_each_event_constraint(c, x86_pmu.event_constraints) { if ((event->hw.config & c->cmask) == c->code) { - - bitmap_copy((unsigned long *)idxmsk, - (unsigned long *)c->idxmsk, - X86_PMC_IDX_MAX); + bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX); return; } } @@ -2200,10 +2199,10 @@ static void intel_get_event_constraints(struct cpu_hw_events *cpuc, static void amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, - u64 *idxmsk) + unsigned long *idxmsk) { /* no constraints, means supports all generic counters */ - bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events); + bitmap_fill(idxmsk, x86_pmu.num_events); } static int x86_event_sched_in(struct perf_event *event, -- GitLab From 8433be1184e4f22c37d4b8ed36cde529a47882f4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 15:38:26 +0100 Subject: [PATCH 1335/3892] perf_event: x86: Reduce some overly long lines with some MACROs Introduce INTEL_EVENT_CONSTRAINT and FIXED_EVENT_CONSTRAINT to reduce some line length and typing work. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.688730371@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 68 +++++++++++++++++--------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 921bbf732e77..4d1ed101c10d 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -97,6 +97,12 @@ struct cpu_hw_events { .cmask = (m), \ } +#define INTEL_EVENT_CONSTRAINT(c, n) \ + EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) + +#define FIXED_EVENT_CONSTRAINT(c, n) \ + EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK) + #define EVENT_CONSTRAINT_END \ EVENT_CONSTRAINT(0, 0, 0) @@ -192,12 +198,12 @@ static u64 p6_pmu_raw_event(u64 hw_event) static struct event_constraint intel_p6_event_constraints[] = { - EVENT_CONSTRAINT(0xc1, 0x1, INTEL_ARCH_EVENT_MASK), /* FLOPS */ - EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */ - EVENT_CONSTRAINT(0x11, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */ - EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */ - EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */ - EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */ + INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */ + INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ + INTEL_EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */ + INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ + INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ + INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ EVENT_CONSTRAINT_END }; @@ -217,41 +223,41 @@ static const u64 intel_perfmon_event_map[] = static struct event_constraint intel_core_event_constraints[] = { - EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ - EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ - EVENT_CONSTRAINT(0x10, 0x1, INTEL_ARCH_EVENT_MASK), /* FP_COMP_OPS_EXE */ - EVENT_CONSTRAINT(0x11, 0x2, INTEL_ARCH_EVENT_MASK), /* FP_ASSIST */ - EVENT_CONSTRAINT(0x12, 0x2, INTEL_ARCH_EVENT_MASK), /* MUL */ - EVENT_CONSTRAINT(0x13, 0x2, INTEL_ARCH_EVENT_MASK), /* DIV */ - EVENT_CONSTRAINT(0x14, 0x1, INTEL_ARCH_EVENT_MASK), /* CYCLES_DIV_BUSY */ - EVENT_CONSTRAINT(0x18, 0x1, INTEL_ARCH_EVENT_MASK), /* IDLE_DURING_DIV */ - EVENT_CONSTRAINT(0x19, 0x2, INTEL_ARCH_EVENT_MASK), /* DELAYED_BYPASS */ - EVENT_CONSTRAINT(0xa1, 0x1, INTEL_ARCH_EVENT_MASK), /* RS_UOPS_DISPATCH_CYCLES */ - EVENT_CONSTRAINT(0xcb, 0x1, INTEL_ARCH_EVENT_MASK), /* MEM_LOAD_RETIRED */ + FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ + FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ + INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ + INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ + INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ + INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ + INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ + INTEL_EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */ + INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */ + INTEL_EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */ + INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */ EVENT_CONSTRAINT_END }; static struct event_constraint intel_nehalem_event_constraints[] = { - EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ - EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ - EVENT_CONSTRAINT(0x40, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LD */ - EVENT_CONSTRAINT(0x41, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_ST */ - EVENT_CONSTRAINT(0x42, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK */ - EVENT_CONSTRAINT(0x43, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_ALL_REF */ - EVENT_CONSTRAINT(0x4e, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_PREFETCH */ - EVENT_CONSTRAINT(0x4c, 0x3, INTEL_ARCH_EVENT_MASK), /* LOAD_HIT_PRE */ - EVENT_CONSTRAINT(0x51, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D */ - EVENT_CONSTRAINT(0x52, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */ - EVENT_CONSTRAINT(0x53, 0x3, INTEL_ARCH_EVENT_MASK), /* L1D_CACHE_LOCK_FB_HIT */ - EVENT_CONSTRAINT(0xc5, 0x3, INTEL_ARCH_EVENT_MASK), /* CACHE_LOCK_CYCLES */ + FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ + FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ + INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */ + INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */ + INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */ + INTEL_EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */ + INTEL_EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */ + INTEL_EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */ + INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */ + INTEL_EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */ + INTEL_EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */ + INTEL_EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */ EVENT_CONSTRAINT_END }; static struct event_constraint intel_gen_event_constraints[] = { - EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32)), INTEL_ARCH_FIXED_MASK), /* INSTRUCTIONS_RETIRED */ - EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33)), INTEL_ARCH_FIXED_MASK), /* UNHALTED_CORE_CYCLES */ + FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ + FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ EVENT_CONSTRAINT_END }; -- GitLab From 9f41699ed067fa695faff8e2e9981b2550abec62 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 15:59:29 +0100 Subject: [PATCH 1336/3892] bitops: Provide compile time HWEIGHT{8,16,32,64} Provide compile time versions of hweight. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner LKML-Reference: <20100122155535.797688466@chello.nl> [ Remove some whitespace damage while we are at it ] Signed-off-by: Ingo Molnar --- include/linux/bitops.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index c05a29cb9bb2..ba0fd1eb4af7 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -25,7 +25,7 @@ static __inline__ int get_bitmask_order(unsigned int count) { int order; - + order = fls(count); return order; /* We could be slightly more clever with -1 here... */ } @@ -33,7 +33,7 @@ static __inline__ int get_bitmask_order(unsigned int count) static __inline__ int get_count_order(unsigned int count) { int order; - + order = fls(count) - 1; if (count & (count - 1)) order++; @@ -45,6 +45,20 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } +#define HWEIGHT8(w) \ + ( (!!((w) & (1ULL << 0))) + \ + (!!((w) & (1ULL << 1))) + \ + (!!((w) & (1ULL << 2))) + \ + (!!((w) & (1ULL << 3))) + \ + (!!((w) & (1ULL << 4))) + \ + (!!((w) & (1ULL << 5))) + \ + (!!((w) & (1ULL << 6))) + \ + (!!((w) & (1ULL << 7))) ) + +#define HWEIGHT16(w) (HWEIGHT8(w) + HWEIGHT8(w >> 8)) +#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16)) +#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32)) + /** * rol32 - rotate a 32-bit value left * @word: value to rotate -- GitLab From 63b146490befc027a7e0923e333269e68b20d380 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 16:32:17 +0100 Subject: [PATCH 1337/3892] perf_event: x86: Optimize the constraint searching bits Instead of copying bitmasks around, pass pointers to the constraint structure. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.887853503@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 75 +++++++++++++++----------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4d1ed101c10d..092ad566734c 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -134,12 +134,14 @@ struct x86_pmu { u64 intel_ctrl; void (*enable_bts)(u64 config); void (*disable_bts)(void); - void (*get_event_constraints)(struct cpu_hw_events *cpuc, - struct perf_event *event, - unsigned long *idxmsk); + + struct event_constraint * + (*get_event_constraints)(struct cpu_hw_events *cpuc, + struct perf_event *event); + void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); - const struct event_constraint *event_constraints; + struct event_constraint *event_constraints; }; static struct x86_pmu x86_pmu __read_mostly; @@ -1242,17 +1244,15 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) { int i, j , w, num; int weight, wmax; - unsigned long *c; - unsigned long constraints[X86_PMC_IDX_MAX][BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; struct hw_perf_event *hwc; bitmap_zero(used_mask, X86_PMC_IDX_MAX); for (i = 0; i < n; i++) { - x86_pmu.get_event_constraints(cpuc, - cpuc->event_list[i], - constraints[i]); + constraints[i] = + x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]); } /* @@ -1267,7 +1267,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) break; /* constraint still honored */ - if (!test_bit(hwc->idx, c)) + if (!test_bit(hwc->idx, c->idxmsk)) break; /* not already used */ @@ -1320,11 +1320,11 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) c = constraints[i]; hwc = &cpuc->event_list[i]->hw; - weight = bitmap_weight(c, X86_PMC_IDX_MAX); + weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX); if (weight != w) continue; - for_each_bit(j, c, X86_PMC_IDX_MAX) { + for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) { if (!test_bit(j, used_mask)) break; } @@ -2155,11 +2155,13 @@ perf_event_nmi_handler(struct notifier_block *self, return NOTIFY_STOP; } +static struct event_constraint unconstrained; + static struct event_constraint bts_constraint = EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0); -static int intel_special_constraints(struct perf_event *event, - unsigned long *idxmsk) +static struct event_constraint * +intel_special_constraints(struct perf_event *event) { unsigned int hw_event; @@ -2169,46 +2171,34 @@ static int intel_special_constraints(struct perf_event *event, x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) && (event->hw.sample_period == 1))) { - bitmap_copy((unsigned long *)idxmsk, - (unsigned long *)bts_constraint.idxmsk, - X86_PMC_IDX_MAX); - return 1; + return &bts_constraint; } - return 0; + return NULL; } -static void intel_get_event_constraints(struct cpu_hw_events *cpuc, - struct perf_event *event, - unsigned long *idxmsk) +static struct event_constraint * +intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { - const struct event_constraint *c; + struct event_constraint *c; - /* - * cleanup bitmask - */ - bitmap_zero(idxmsk, X86_PMC_IDX_MAX); - - if (intel_special_constraints(event, idxmsk)) - return; + c = intel_special_constraints(event); + if (c) + return c; if (x86_pmu.event_constraints) { for_each_event_constraint(c, x86_pmu.event_constraints) { - if ((event->hw.config & c->cmask) == c->code) { - bitmap_copy(idxmsk, c->idxmsk, X86_PMC_IDX_MAX); - return; - } + if ((event->hw.config & c->cmask) == c->code) + return c; } } - /* no constraints, means supports all generic counters */ - bitmap_fill((unsigned long *)idxmsk, x86_pmu.num_events); + + return &unconstrained; } -static void amd_get_event_constraints(struct cpu_hw_events *cpuc, - struct perf_event *event, - unsigned long *idxmsk) +static struct event_constraint * +amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { - /* no constraints, means supports all generic counters */ - bitmap_fill(idxmsk, x86_pmu.num_events); + return &unconstrained; } static int x86_event_sched_in(struct perf_event *event, @@ -2576,6 +2566,9 @@ void __init init_hw_perf_events(void) perf_events_lapic_init(); register_die_notifier(&perf_event_nmi_notifier); + unconstrained = (struct event_constraint) + EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0); + pr_info("... version: %d\n", x86_pmu.version); pr_info("... bit width: %d\n", x86_pmu.event_bits); pr_info("... generic registers: %d\n", x86_pmu.num_events); -- GitLab From 272d30be622c9c6cbd514b1211ff359292001baa Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 16:32:17 +0100 Subject: [PATCH 1338/3892] perf_event: x86: Optimize constraint weight computation Add a weight member to the constraint structure and avoid recomputing the weight at runtime. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155535.963944926@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 092ad566734c..2c22ce4fa784 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,7 @@ struct event_constraint { }; int code; int cmask; + int weight; }; struct cpu_hw_events { @@ -95,6 +97,7 @@ struct cpu_hw_events { { .idxmsk64[0] = (n) }, \ .code = (c), \ .cmask = (m), \ + .weight = HWEIGHT64((u64)(n)), \ } #define INTEL_EVENT_CONSTRAINT(c, n) \ @@ -1242,8 +1245,7 @@ static inline int is_x86_event(struct perf_event *event) static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) { - int i, j , w, num; - int weight, wmax; + int i, j, w, num, wmax; struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; struct hw_perf_event *hwc; @@ -1320,8 +1322,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) c = constraints[i]; hwc = &cpuc->event_list[i]->hw; - weight = bitmap_weight(c->idxmsk, X86_PMC_IDX_MAX); - if (weight != w) + if (c->weight != w) continue; for_each_bit(j, c->idxmsk, X86_PMC_IDX_MAX) { -- GitLab From c933c1a603d5bf700ddce79216c1be0ec3bc0e6c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Jan 2010 16:40:12 +0100 Subject: [PATCH 1339/3892] perf_event: x86: Optimize the fast path a little more Remove num from the fast path and save a few ops. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100122155536.056430539@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 2c22ce4fa784..33c889ff21ae 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1245,9 +1245,9 @@ static inline int is_x86_event(struct perf_event *event) static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) { - int i, j, w, num, wmax; struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + int i, j, w, wmax, num = 0; struct hw_perf_event *hwc; bitmap_zero(used_mask, X86_PMC_IDX_MAX); @@ -1260,7 +1260,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) /* * fastpath, try to reuse previous register */ - for (i = 0, num = n; i < n; i++, num--) { + for (i = 0; i < n; i++) { hwc = &cpuc->event_list[i]->hw; c = constraints[i]; @@ -1288,7 +1288,7 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (assign) assign[i] = hwc->idx; } - if (!num) + if (i == n) goto done; /* -- GitLab From 6c9687abeb24d5b7aae7db5be070c2139ad29e29 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 25 Jan 2010 11:57:25 +0100 Subject: [PATCH 1340/3892] perf_event: x86: Optimize x86_pmu_disable() x86_pmu_disable() removes the event from the cpuc->event_list[], however since an event can only be on that list once, stop looking after we found it. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 33c889ff21ae..66de282ad2fb 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1884,6 +1884,7 @@ static void x86_pmu_disable(struct perf_event *event) cpuc->event_list[i-1] = cpuc->event_list[i]; --cpuc->n_events; + break; } } perf_event_update_userpage(event); -- GitLab From 184f412c3341cd24fbd26604634a5800b83dbdc3 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Jan 2010 08:39:39 +0100 Subject: [PATCH 1341/3892] perf, x86: Clean up event constraints code a bit - Remove stray debug code - Improve ugly macros a bit - Remove some whitespace damage - (Also fix up some accumulated damage in perf_event.h) Signed-off-by: Ingo Molnar Cc: Stephane Eranian Cc: Peter Zijlstra LKML-Reference: --- arch/x86/kernel/cpu/perf_event.c | 37 +++++++------------------------- include/linux/perf_event.h | 24 ++++++++++----------- 2 files changed, 19 insertions(+), 42 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 66de282ad2fb..fdbe24842271 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -93,24 +93,19 @@ struct cpu_hw_events { struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ }; -#define EVENT_CONSTRAINT(c, n, m) { \ +#define EVENT_CONSTRAINT(c, n, m) { \ { .idxmsk64[0] = (n) }, \ .code = (c), \ .cmask = (m), \ .weight = HWEIGHT64((u64)(n)), \ } -#define INTEL_EVENT_CONSTRAINT(c, n) \ - EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) +#define INTEL_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) +#define FIXED_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK) -#define FIXED_EVENT_CONSTRAINT(c, n) \ - EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK) +#define EVENT_CONSTRAINT_END EVENT_CONSTRAINT(0, 0, 0) -#define EVENT_CONSTRAINT_END \ - EVENT_CONSTRAINT(0, 0, 0) - -#define for_each_event_constraint(e, c) \ - for ((e) = (c); (e)->cmask; (e)++) +#define for_each_event_constraint(e, c) for ((e) = (c); (e)->cmask; (e)++) /* * struct x86_pmu - generic x86 pmu @@ -1276,14 +1271,6 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (test_bit(hwc->idx, used_mask)) break; -#if 0 - pr_debug("CPU%d fast config=0x%llx idx=%d assign=%c\n", - smp_processor_id(), - hwc->config, - hwc->idx, - assign ? 'y' : 'n'); -#endif - set_bit(hwc->idx, used_mask); if (assign) assign[i] = hwc->idx; @@ -1333,14 +1320,6 @@ static int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (j == X86_PMC_IDX_MAX) break; -#if 0 - pr_debug("CPU%d slow config=0x%llx idx=%d assign=%c\n", - smp_processor_id(), - hwc->config, - j, - assign ? 'y' : 'n'); -#endif - set_bit(j, used_mask); if (assign) @@ -2596,9 +2575,9 @@ static const struct pmu pmu = { * validate a single event group * * validation include: - * - check events are compatible which each other - * - events do not compete for the same counter - * - number of events <= number of counters + * - check events are compatible which each other + * - events do not compete for the same counter + * - number of events <= number of counters * * validation ensures the group can be loaded onto the * PMU if it was the only group available. diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 72b2615600d8..953c17731e0d 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -290,7 +290,7 @@ struct perf_event_mmap_page { }; #define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0) -#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) +#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) #define PERF_RECORD_MISC_KERNEL (1 << 0) #define PERF_RECORD_MISC_USER (2 << 0) #define PERF_RECORD_MISC_HYPERVISOR (3 << 0) @@ -356,8 +356,8 @@ enum perf_event_type { * u64 stream_id; * }; */ - PERF_RECORD_THROTTLE = 5, - PERF_RECORD_UNTHROTTLE = 6, + PERF_RECORD_THROTTLE = 5, + PERF_RECORD_UNTHROTTLE = 6, /* * struct { @@ -371,10 +371,10 @@ enum perf_event_type { /* * struct { - * struct perf_event_header header; - * u32 pid, tid; + * struct perf_event_header header; + * u32 pid, tid; * - * struct read_format values; + * struct read_format values; * }; */ PERF_RECORD_READ = 8, @@ -412,7 +412,7 @@ enum perf_event_type { * char data[size];}&& PERF_SAMPLE_RAW * }; */ - PERF_RECORD_SAMPLE = 9, + PERF_RECORD_SAMPLE = 9, PERF_RECORD_MAX, /* non-ABI */ }; @@ -752,8 +752,7 @@ extern int perf_max_events; extern const struct pmu *hw_perf_event_init(struct perf_event *event); extern void perf_event_task_sched_in(struct task_struct *task); -extern void perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next); +extern void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next); extern void perf_event_task_tick(struct task_struct *task); extern int perf_event_init_task(struct task_struct *child); extern void perf_event_exit_task(struct task_struct *child); @@ -853,8 +852,7 @@ extern int sysctl_perf_event_mlock; extern int sysctl_perf_event_sample_rate; extern void perf_event_init(void); -extern void perf_tp_event(int event_id, u64 addr, u64 count, - void *record, int entry_size); +extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, int entry_size); extern void perf_bp_event(struct perf_event *event, void *data); #ifndef perf_misc_flags @@ -895,13 +893,13 @@ static inline void perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) { } static inline void -perf_bp_event(struct perf_event *event, void *data) { } +perf_bp_event(struct perf_event *event, void *data) { } static inline void perf_event_mmap(struct vm_area_struct *vma) { } static inline void perf_event_comm(struct task_struct *tsk) { } static inline void perf_event_fork(struct task_struct *tsk) { } static inline void perf_event_init(void) { } -static inline int perf_swevent_get_recursion_context(void) { return -1; } +static inline int perf_swevent_get_recursion_context(void) { return -1; } static inline void perf_swevent_put_recursion_context(int rctx) { } static inline void perf_event_enable(struct perf_event *event) { } static inline void perf_event_disable(struct perf_event *event) { } -- GitLab From 2e8418736dff9c6fdadb2f87dcc2087cebf32167 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 25 Jan 2010 15:58:43 +0100 Subject: [PATCH 1342/3892] perf_event: x86: Deduplicate the disable code Share the meat of the x86_pmu_disable() code with hw_perf_enable(). Also remove the barrier() from that code, since I could not convince myself we actually need it. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index fdbe24842271..07fa0c2faa09 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1401,6 +1401,8 @@ static inline void x86_assign_hw_event(struct perf_event *event, } } +static void __x86_pmu_disable(struct perf_event *event, struct cpu_hw_events *cpuc); + void hw_perf_enable(void) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); @@ -1426,13 +1428,7 @@ void hw_perf_enable(void) if (hwc->idx == -1 || hwc->idx == cpuc->assign[i]) continue; - x86_pmu.disable(hwc, hwc->idx); - - clear_bit(hwc->idx, cpuc->active_mask); - barrier(); - cpuc->events[hwc->idx] = NULL; - - x86_perf_event_update(event, hwc, hwc->idx); + __x86_pmu_disable(event, cpuc); hwc->idx = -1; } @@ -1822,11 +1818,10 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_events *cpuc) event->pending_kill = POLL_IN; } -static void x86_pmu_disable(struct perf_event *event) +static void __x86_pmu_disable(struct perf_event *event, struct cpu_hw_events *cpuc) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - int i, idx = hwc->idx; + int idx = hwc->idx; /* * Must be done before we disable, otherwise the nmi handler @@ -1835,12 +1830,6 @@ static void x86_pmu_disable(struct perf_event *event) clear_bit(idx, cpuc->active_mask); x86_pmu.disable(hwc, idx); - /* - * Make sure the cleared pointer becomes visible before we - * (potentially) free the event: - */ - barrier(); - /* * Drain the remaining delta count out of a event * that we are disabling: @@ -1852,6 +1841,14 @@ static void x86_pmu_disable(struct perf_event *event) intel_pmu_drain_bts_buffer(cpuc); cpuc->events[idx] = NULL; +} + +static void x86_pmu_disable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int i; + + __x86_pmu_disable(event, cpuc); for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event_list[i]) { -- GitLab From ed8777fc132e589d48a0ba854fdbb5d8203b58e5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 27 Jan 2010 23:07:46 +0100 Subject: [PATCH 1343/3892] perf_events, x86: Fix event constraint masks Since constraints are specified on the event number, not number and unit mask shorten the constraint masks so that we'll actually match something. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100127221121.967610372@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/perf_event.h | 2 +- arch/x86/kernel/cpu/perf_event.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index dbc082685d52..ff5ede128bae 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -49,7 +49,7 @@ INTEL_ARCH_INV_MASK| \ INTEL_ARCH_EDGE_MASK|\ INTEL_ARCH_UNIT_MASK|\ - INTEL_ARCH_EVENT_MASK) + INTEL_ARCH_EVTSEL_MASK) #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 07fa0c2faa09..951213a51489 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -100,12 +100,17 @@ struct cpu_hw_events { .weight = HWEIGHT64((u64)(n)), \ } -#define INTEL_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) -#define FIXED_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK) +#define INTEL_EVENT_CONSTRAINT(c, n) \ + EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVTSEL_MASK) -#define EVENT_CONSTRAINT_END EVENT_CONSTRAINT(0, 0, 0) +#define FIXED_EVENT_CONSTRAINT(c, n) \ + EVENT_CONSTRAINT(c, n, INTEL_ARCH_FIXED_MASK) -#define for_each_event_constraint(e, c) for ((e) = (c); (e)->cmask; (e)++) +#define EVENT_CONSTRAINT_END \ + EVENT_CONSTRAINT(0, 0, 0) + +#define for_each_event_constraint(e, c) \ + for ((e) = (c); (e)->cmask; (e)++) /* * struct x86_pmu - generic x86 pmu -- GitLab From 1a6e21f791fe85b40a9ddbafe999ab8ccffc3f78 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 27 Jan 2010 23:07:47 +0100 Subject: [PATCH 1344/3892] perf_events, x86: Clean up hw_perf_*_all() implementation Put the recursion avoidance code in the generic hook instead of replicating it in each implementation. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100127221122.057507285@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 59 ++++++++------------------------ 1 file changed, 14 insertions(+), 45 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 951213a51489..cf10839f20ea 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1099,15 +1099,8 @@ static int __hw_perf_event_init(struct perf_event *event) static void p6_pmu_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); u64 val; - if (!cpuc->enabled) - return; - - cpuc->enabled = 0; - barrier(); - /* p6 only has one enable register */ rdmsrl(MSR_P6_EVNTSEL0, val); val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -1118,12 +1111,6 @@ static void intel_pmu_disable_all(void) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - if (!cpuc->enabled) - return; - - cpuc->enabled = 0; - barrier(); - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) @@ -1135,17 +1122,6 @@ static void amd_pmu_disable_all(void) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int idx; - if (!cpuc->enabled) - return; - - cpuc->enabled = 0; - /* - * ensure we write the disable before we start disabling the - * events proper, so that amd_pmu_enable_event() does the - * right thing. - */ - barrier(); - for (idx = 0; idx < x86_pmu.num_events; idx++) { u64 val; @@ -1166,23 +1142,20 @@ void hw_perf_disable(void) if (!x86_pmu_initialized()) return; - if (cpuc->enabled) - cpuc->n_added = 0; + if (!cpuc->enabled) + return; + + cpuc->n_added = 0; + cpuc->enabled = 0; + barrier(); x86_pmu.disable_all(); } static void p6_pmu_enable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); unsigned long val; - if (cpuc->enabled) - return; - - cpuc->enabled = 1; - barrier(); - /* p6 only has one enable register */ rdmsrl(MSR_P6_EVNTSEL0, val); val |= ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -1193,12 +1166,6 @@ static void intel_pmu_enable_all(void) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - if (cpuc->enabled) - return; - - cpuc->enabled = 1; - barrier(); - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl); if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) { @@ -1217,12 +1184,6 @@ static void amd_pmu_enable_all(void) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int idx; - if (cpuc->enabled) - return; - - cpuc->enabled = 1; - barrier(); - for (idx = 0; idx < x86_pmu.num_events; idx++) { struct perf_event *event = cpuc->events[idx]; u64 val; @@ -1417,6 +1378,10 @@ void hw_perf_enable(void) if (!x86_pmu_initialized()) return; + + if (cpuc->enabled) + return; + if (cpuc->n_added) { /* * apply assignment obtained either from @@ -1461,6 +1426,10 @@ void hw_perf_enable(void) cpuc->n_added = 0; perf_events_lapic_init(); } + + cpuc->enabled = 1; + barrier(); + x86_pmu.enable_all(); } -- GitLab From 452a339a976e7f782c786eb3f73080401e2fa3a6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 27 Jan 2010 23:07:48 +0100 Subject: [PATCH 1345/3892] perf_events, x86: Implement Intel Westmere support The new Intel documentation includes Westmere arch specific event maps that are significantly different from the Nehalem ones. Add support for this generation. Found the CPUID model numbers on wikipedia. Also ammend some Nehalem constraints, spotted those when looking for the differences between Nehalem and Westmere. Signed-off-by: Peter Zijlstra Cc: Arjan van de Ven Cc: "H. Peter Anvin" Cc: Stephane Eranian LKML-Reference: <20100127221122.151865645@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 124 +++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index cf10839f20ea..3fac0bfc2dee 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -244,18 +244,26 @@ static struct event_constraint intel_core_event_constraints[] = static struct event_constraint intel_nehalem_event_constraints[] = { - FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ - FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ + FIXED_EVENT_CONSTRAINT(0xc0, (0xf|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ + FIXED_EVENT_CONSTRAINT(0x3c, (0xf|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */ INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */ INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */ INTEL_EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */ + INTEL_EVENT_CONSTRAINT(0x48, 0x3), /* L1D_PEND_MISS */ INTEL_EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */ - INTEL_EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */ INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */ - INTEL_EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */ - INTEL_EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */ - INTEL_EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */ + INTEL_EVENT_CONSTRAINT(0x63, 0x3), /* CACHE_LOCK_CYCLES */ + EVENT_CONSTRAINT_END +}; + +static struct event_constraint intel_westmere_event_constraints[] = +{ + FIXED_EVENT_CONSTRAINT(0xc0, (0xf|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ + FIXED_EVENT_CONSTRAINT(0x3c, (0xf|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ + INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */ + INTEL_EVENT_CONSTRAINT(0x60, 0x1), /* OFFCORE_REQUESTS_OUTSTANDING */ + INTEL_EVENT_CONSTRAINT(0x63, 0x3), /* CACHE_LOCK_CYCLES */ EVENT_CONSTRAINT_END }; @@ -286,6 +294,97 @@ static u64 __read_mostly hw_cache_event_ids [PERF_COUNT_HW_CACHE_OP_MAX] [PERF_COUNT_HW_CACHE_RESULT_MAX]; +static __initconst u64 westmere_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ + [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPL */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ + [ C(RESULT_MISS) ] = 0x0251, /* L1D.M_REPL */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ + [ C(RESULT_MISS) ] = 0x024e, /* L1D_PREFETCH.MISS */ + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS */ + [ C(RESULT_MISS) ] = 0x0280, /* L1I.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0324, /* L2_RQSTS.LOADS */ + [ C(RESULT_MISS) ] = 0x0224, /* L2_RQSTS.LD_MISS */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0c24, /* L2_RQSTS.RFOS */ + [ C(RESULT_MISS) ] = 0x0824, /* L2_RQSTS.RFO_MISS */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x4f2e, /* LLC Reference */ + [ C(RESULT_MISS) ] = 0x412e, /* LLC Misses */ + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ + [ C(RESULT_MISS) ] = 0x0108, /* DTLB_LOAD_MISSES.ANY */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ + [ C(RESULT_MISS) ] = 0x010c, /* MEM_STORE_RETIRED.DTLB_MISS */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x01c0, /* INST_RETIRED.ANY_P */ + [ C(RESULT_MISS) ] = 0x0185, /* ITLB_MISSES.ANY */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */ + [ C(RESULT_MISS) ] = 0x03e8, /* BPU_CLEARS.ANY */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + static __initconst u64 nehalem_hw_cache_event_ids [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -2423,7 +2522,9 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_core_event_constraints; pr_cont("Core2 events, "); break; - case 26: + + case 26: /* 45 nm nehalem, "Bloomfield" */ + case 30: /* 45 nm nehalem, "Lynnfield" */ memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -2437,6 +2538,15 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_gen_event_constraints; pr_cont("Atom events, "); break; + + case 37: /* 32 nm nehalem, "Clarkdale" */ + case 44: /* 32 nm nehalem, "Gulftown" */ + memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + x86_pmu.event_constraints = intel_westmere_event_constraints; + pr_cont("Westmere events, "); + break; default: /* * default constraints for v2 and up -- GitLab From 18c01f8abff51e4910cc5ffb4b710e8c6eea60c9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 27 Jan 2010 23:07:49 +0100 Subject: [PATCH 1346/3892] perf_events, x86: Remove spurious counter reset from x86_pmu_enable() At enable time the counter might still have a ->idx pointing to a previously occupied location that might now be taken by another event. Resetting the counter at that location with data from this event will destroy the other counter's count. Signed-off-by: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100127221122.261477183@chello.nl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 3fac0bfc2dee..518eb3e39577 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1762,9 +1762,6 @@ static int x86_pmu_enable(struct perf_event *event) cpuc->n_events = n; cpuc->n_added = n - n0; - if (hwc->idx != -1) - x86_perf_event_set_period(event, hwc, hwc->idx); - return 0; } -- GitLab From 488991e28e55b4fbca8067edf0259f69d1a6f92c Mon Sep 17 00:00:00 2001 From: "Alan D. Brunelle" Date: Fri, 29 Jan 2010 09:04:08 +0100 Subject: [PATCH 1347/3892] block: Added in stricter no merge semantics for block I/O Updated 'nomerges' tunable to accept a value of '2' - indicating that _no_ merges at all are to be attempted (not even the simple one-hit cache). The following table illustrates the additional benefit - 5 minute runs of a random I/O load were applied to a dozen devices on a 16-way x86_64 system. nomerges Throughput %System Improvement (tput / %sys) -------- ------------ ----------- ------------------------- 0 12.45 MB/sec 0.669365609 1 12.50 MB/sec 0.641519199 0.40% / 2.71% 2 12.52 MB/sec 0.639849750 0.56% / 2.96% Signed-off-by: Alan D. Brunelle Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block | 14 ++++++++++++++ Documentation/block/queue-sysfs.txt | 10 +++++----- block/blk-sysfs.c | 11 +++++++---- block/elevator.c | 11 ++++++++++- include/linux/blkdev.h | 3 +++ 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index d2f90334bb93..4873c759d535 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -128,3 +128,17 @@ Description: preferred request size for workloads where sustained throughput is desired. If no optimal I/O size is reported this file contains 0. + +What: /sys/block//queue/nomerges +Date: January 2010 +Contact: +Description: + Standard I/O elevator operations include attempts to + merge contiguous I/Os. For known random I/O loads these + attempts will always fail and result in extra cycles + being spent in the kernel. This allows one to turn off + this behavior on one of two ways: When set to 1, complex + merge checks are disabled, but the simple one-shot merges + with the previous I/O request are enabled. When set to 2, + all merge tries are disabled. The default value is 0 - + which enables all types of merge tries. diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index e164403f60e1..f65274081c8d 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -25,11 +25,11 @@ size allowed by the hardware. nomerges (RW) ------------- -This enables the user to disable the lookup logic involved with IO merging -requests in the block layer. Merging may still occur through a direct -1-hit cache, since that comes for (almost) free. The IO scheduler will not -waste cycles doing tree/hash lookups for merges if nomerges is 1. Defaults -to 0, enabling all merges. +This enables the user to disable the lookup logic involved with IO +merging requests in the block layer. By default (0) all merges are +enabled. When set to 1 only simple one-hit merges will be tried. When +set to 2 no merge algorithms will be tried (including one-hit or more +complex tree/hash lookups). nr_requests (RW) ---------------- diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 8606c9543fdd..e85442415db3 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -189,7 +189,8 @@ static ssize_t queue_nonrot_store(struct request_queue *q, const char *page, static ssize_t queue_nomerges_show(struct request_queue *q, char *page) { - return queue_var_show(blk_queue_nomerges(q), page); + return queue_var_show((blk_queue_nomerges(q) << 1) | + blk_queue_noxmerges(q), page); } static ssize_t queue_nomerges_store(struct request_queue *q, const char *page, @@ -199,10 +200,12 @@ static ssize_t queue_nomerges_store(struct request_queue *q, const char *page, ssize_t ret = queue_var_store(&nm, page, count); spin_lock_irq(q->queue_lock); - if (nm) + queue_flag_clear(QUEUE_FLAG_NOMERGES, q); + queue_flag_clear(QUEUE_FLAG_NOXMERGES, q); + if (nm == 2) queue_flag_set(QUEUE_FLAG_NOMERGES, q); - else - queue_flag_clear(QUEUE_FLAG_NOMERGES, q); + else if (nm) + queue_flag_set(QUEUE_FLAG_NOXMERGES, q); spin_unlock_irq(q->queue_lock); return ret; diff --git a/block/elevator.c b/block/elevator.c index 9ad5ccc4c5ee..ee3a883840f2 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -473,6 +473,15 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) struct request *__rq; int ret; + /* + * Levels of merges: + * nomerges: No merges at all attempted + * noxmerges: Only simple one-hit cache try + * merges: All merge tries attempted + */ + if (blk_queue_nomerges(q)) + return ELEVATOR_NO_MERGE; + /* * First try one-hit cache. */ @@ -484,7 +493,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) } } - if (blk_queue_nomerges(q)) + if (blk_queue_noxmerges(q)) return ELEVATOR_NO_MERGE; /* diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ffb13ad35716..f71f5c58620c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -463,6 +463,7 @@ struct request_queue #define QUEUE_FLAG_IO_STAT 15 /* do IO stats */ #define QUEUE_FLAG_CQ 16 /* hardware does queuing */ #define QUEUE_FLAG_DISCARD 17 /* supports DISCARD */ +#define QUEUE_FLAG_NOXMERGES 18 /* No extended merges */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_CLUSTER) | \ @@ -589,6 +590,8 @@ enum { #define blk_queue_queuing(q) test_bit(QUEUE_FLAG_CQ, &(q)->queue_flags) #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) #define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags) +#define blk_queue_noxmerges(q) \ + test_bit(QUEUE_FLAG_NOXMERGES, &(q)->queue_flags) #define blk_queue_nonrot(q) test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags) #define blk_queue_io_stat(q) test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags) #define blk_queue_flushing(q) ((q)->ordseq) -- GitLab From 75c9f3284a7ff957829f44baace82406a6354ceb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 29 Jan 2010 09:04:26 +0100 Subject: [PATCH 1348/3892] perf_events: Fix sample_period transfer on inherit One problem with frequency driven counters is that we cannot predict the rate at which they trigger, therefore we have to start them at period=1, this causes a ramp up effect. However, if we fail to propagate the stable state on fork each new child will have to ramp up again. This can lead to significant artifacts in sample data. Signed-off-by: Peter Zijlstra Cc: eranian@google.com Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <1264752266.4283.2121.camel@laptop> Signed-off-by: Ingo Molnar --- kernel/perf_event.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 251fb9552492..53dc2a362111 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -5002,8 +5002,15 @@ inherit_event(struct perf_event *parent_event, else child_event->state = PERF_EVENT_STATE_OFF; - if (parent_event->attr.freq) - child_event->hw.sample_period = parent_event->hw.sample_period; + if (parent_event->attr.freq) { + u64 sample_period = parent_event->hw.sample_period; + struct hw_perf_event *hwc = &child_event->hw; + + hwc->sample_period = sample_period; + hwc->last_period = sample_period; + + atomic64_set(&hwc->period_left, sample_period); + } child_event->overflow_handler = parent_event->overflow_handler; -- GitLab From 72b8fa1730207274f6818b47b891ce5dff79287e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Jan 2010 21:05:49 -0200 Subject: [PATCH 1349/3892] perf top: Exit if specified --vmlinux can't be used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we do lazy loading of symtabs we only will know if the specified vmlinux file is invalid when we actually have a hit in kernel space and then try to load it. So if we get kernel hits and there are _no_ symbols in the DSO backing the kernel map, bail out. Reported-by: Mike Galbraith Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264633557-17597-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2227b84aa002..78f9c4576a0c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -951,9 +951,31 @@ static void event__process_sample(const event_t *self, } if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || - al.sym == NULL || al.filtered) + al.filtered) return; + if (al.sym == NULL) { + /* + * As we do lazy loading of symtabs we only will know if the + * specified vmlinux file is invalid when we actually have a + * hit in kernel space and then try to load it. So if we get + * here and there are _no_ symbols in the DSO backing the + * kernel map, bail out. + * + * We may never get here, for instance, if we use -K/ + * --hide-kernel-symbols, even if the user specifies an + * invalid --vmlinux ;-) + */ + if (al.map == session->vmlinux_maps[MAP__FUNCTION] && + RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { + pr_err("The %s file can't be used\n", + symbol_conf.vmlinux_name); + exit(1); + } + + return; + } + syme = symbol__priv(al.sym); if (!syme->skip) { syme->count[counter]++; -- GitLab From a19afe46412452fef89cc623873a8931b3685944 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Jan 2010 21:05:50 -0200 Subject: [PATCH 1350/3892] perf symbols: Factor out dso__load_vmlinux_path() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that we can call it directly from regression tests, and also to reduce the size of dso__load_kernel_sym(), making it more clear. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264633557-17597-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 38 ++++++++++++++++++++++++-------------- tools/perf/util/symbol.h | 2 ++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f1f609dcf9a1..26ec603083e0 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1578,6 +1578,27 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return err; } +int dso__load_vmlinux_path(struct dso *self, struct map *map, + struct perf_session *session, symbol_filter_t filter) +{ + int i, err = 0; + + pr_debug("Looking at the vmlinux_path (%d entries long)\n", + vmlinux_path__nr_entries); + + for (i = 0; i < vmlinux_path__nr_entries; ++i) { + err = dso__load_vmlinux(self, map, session, vmlinux_path[i], + filter); + if (err > 0) { + pr_debug("Using %s for symbols\n", vmlinux_path[i]); + dso__set_long_name(self, strdup(vmlinux_path[i])); + break; + } + } + + return err; +} + static int dso__load_kernel_sym(struct dso *self, struct map *map, struct perf_session *session, symbol_filter_t filter) { @@ -1606,20 +1627,9 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } if (vmlinux_path != NULL) { - int i; - pr_debug("Looking at the vmlinux_path (%d entries long)\n", - vmlinux_path__nr_entries); - for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(self, map, session, - vmlinux_path[i], filter); - if (err > 0) { - pr_debug("Using %s for symbols\n", - vmlinux_path[i]); - dso__set_long_name(self, - strdup(vmlinux_path[i])); - goto out_fixup; - } - } + err = dso__load_vmlinux_path(self, map, session, filter); + if (err > 0) + goto out_fixup; } /* diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ffe0b0f2e5d3..a94997aeb334 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -129,6 +129,8 @@ struct perf_session; int dso__load(struct dso *self, struct map *map, struct perf_session *session, symbol_filter_t filter); +int dso__load_vmlinux_path(struct dso *self, struct map *map, + struct perf_session *session, symbol_filter_t filter); void dsos__fprintf(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp, bool with_hits); -- GitLab From fd1d908c543fbdfae82839d24b0872c542fceedc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Jan 2010 21:05:51 -0200 Subject: [PATCH 1351/3892] perf symbols: Split helpers used when creating kernel dso object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make it clear and allow for direct usage by, for instance, regression test suites. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264633557-17597-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 28 +++++++++++++++++++++------- tools/perf/util/symbol.h | 2 ++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 26ec603083e0..f9049d12ead6 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1762,24 +1762,38 @@ size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) __dsos__fprintf_buildid(&dsos__user, fp, with_hits)); } +struct dso *dso__new_kernel(const char *name) +{ + struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); + + if (self != NULL) { + self->short_name = "[kernel]"; + self->kernel = 1; + } + + return self; +} + +void dso__read_running_kernel_build_id(struct dso *self) +{ + if (sysfs__read_build_id("/sys/kernel/notes", self->build_id, + sizeof(self->build_id)) == 0) + self->has_build_id = true; +} + static struct dso *dsos__create_kernel(const char *vmlinux) { - struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); + struct dso *kernel = dso__new_kernel(vmlinux); if (kernel == NULL) return NULL; - kernel->short_name = "[kernel]"; - kernel->kernel = 1; - vdso = dso__new("[vdso]"); if (vdso == NULL) goto out_delete_kernel_dso; dso__set_loaded(vdso, MAP__FUNCTION); - if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, - sizeof(kernel->build_id)) == 0) - kernel->has_build_id = true; + dso__read_running_kernel_build_id(kernel); dsos__add(&dsos__kernel, kernel); dsos__add(&dsos__user, vdso); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index a94997aeb334..124302778c09 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -109,6 +109,7 @@ struct dso { }; struct dso *dso__new(const char *name); +struct dso *dso__new_kernel(const char *name); void dso__delete(struct dso *self); bool dso__loaded(const struct dso *self, enum map_type type); @@ -139,6 +140,7 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); char dso__symtab_origin(const struct dso *self); void dso__set_long_name(struct dso *self, char *name); void dso__set_build_id(struct dso *self, void *build_id); +void dso__read_running_kernel_build_id(struct dso *self); struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, const char *name); -- GitLab From 64abebf731df87e6f4ae7d9ffc340bdf0c033e44 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Jan 2010 21:05:52 -0200 Subject: [PATCH 1352/3892] perf session: Create kernel maps in the constructor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing one extra step needed in the tools that need this, fixing a bug in 'perf probe' where this was not being done. Signed-off-by: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1264633557-17597-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 5 ----- tools/perf/builtin-record.c | 5 ----- tools/perf/builtin-top.c | 5 ----- tools/perf/util/session.c | 13 +++++++++++-- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 7323d9dfbce8..38b8ca900eda 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -491,11 +491,6 @@ static int __cmd_kmem(void) if (!perf_session__has_traces(session, "kmem record")) goto out_delete; - if (perf_session__create_kernel_maps(session) < 0) { - pr_err("Problems creating kernel maps\n"); - return -1; - } - setup_pager(); err = perf_session__process_events(session, &event_ops); if (err != 0) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7bb9ca1b30fa..90345223908c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -477,11 +477,6 @@ static int __cmd_record(int argc, const char **argv) return -1; } - if (perf_session__create_kernel_maps(session) < 0) { - pr_err("Problems creating kernel maps\n"); - return -1; - } - if (!file_new) { err = perf_header__read(&session->header, output); if (err < 0) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 78f9c4576a0c..1fc018e048e1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1191,11 +1191,6 @@ static int __cmd_top(void) if (session == NULL) return -ENOMEM; - if (perf_session__create_kernel_maps(session) < 0) { - pr_err("Problems creating kernel maps\n"); - return -1; - } - if (target_pid != -1) event__synthesize_thread(target_pid, event__process, session); else diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1951e330377c..8e7c1896eaa2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -70,8 +70,17 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc self->unknown_events = 0; map_groups__init(&self->kmaps); - if (mode == O_RDONLY && perf_session__open(self, force) < 0) - goto out_delete; + if (mode == O_RDONLY) { + if (perf_session__open(self, force) < 0) + goto out_delete; + } else if (mode == O_WRONLY) { + /* + * In O_RDONLY mode this will be performed when reading the + * kernel MMAP event, in event__process_mmap(). + */ + if (perf_session__create_kernel_maps(self) < 0) + goto out_delete; + } self->sample_type = perf_header__sample_type(&self->header); out: -- GitLab From 1f5b8f8a2031ae9507eb67743cad4d424739bfff Mon Sep 17 00:00:00 2001 From: john stultz Date: Thu, 28 Jan 2010 15:02:41 -0800 Subject: [PATCH 1353/3892] ntp: Make time_esterror and time_maxerror static Make time_esterror and time_maxerror static as no one uses them outside of ntp.c Signed-off-by: John Stultz Cc: richard@rsk.demon.co.uk LKML-Reference: <1264719761.3437.47.camel@localhost.localdomain> Signed-off-by: Thomas Gleixner --- include/linux/timex.h | 3 --- kernel/time/ntp.c | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/timex.h b/include/linux/timex.h index 94f8faecdcbc..7a082b32d8e1 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -238,9 +238,6 @@ extern int tickadj; /* amount of adjustment per tick */ * phase-lock loop variables */ extern int time_status; /* clock synchronization status bits */ -extern long time_maxerror; /* maximum error */ -extern long time_esterror; /* estimated error */ - extern long time_adjust; /* The amount of adjtime left */ extern void ntp_init(void); diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 4800f933910e..74b1b37b1595 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -58,10 +58,10 @@ static s64 time_offset; static long time_constant = 2; /* maximum error (usecs): */ -long time_maxerror = NTP_PHASE_LIMIT; +static long time_maxerror = NTP_PHASE_LIMIT; /* estimated error (usecs): */ -long time_esterror = NTP_PHASE_LIMIT; +static long time_esterror = NTP_PHASE_LIMIT; /* frequency offset (scaled nsecs/secs): */ static s64 time_freq; -- GitLab From 7e1b584774c6168ca5b27c340fbeff8f67651e4f Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 28 Jan 2010 20:20:44 -0800 Subject: [PATCH 1354/3892] ntp: Cleanup xtime references in ntp.c ntp.c doesn't need to access timekeeping internals directly, so change xtime references to use the get_seconds() timekeeping interface. Signed-off-by: John Stultz Cc: richard@rsk.demon.co.uk LKML-Reference: <1264738844-21935-1-git-send-email-johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner --- kernel/time/ntp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 74b1b37b1595..7c0f180d6e9d 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -142,11 +142,11 @@ static void ntp_update_offset(long offset) * Select how the frequency is to be controlled * and in which mode (PLL or FLL). */ - secs = xtime.tv_sec - time_reftime; + secs = get_seconds() - time_reftime; if (unlikely(time_status & STA_FREQHOLD)) secs = 0; - time_reftime = xtime.tv_sec; + time_reftime = get_seconds(); offset64 = offset; freq_adj = (offset64 * secs) << @@ -368,7 +368,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) * reference time to current time. */ if (!(time_status & STA_PLL) && (txc->status & STA_PLL)) - time_reftime = xtime.tv_sec; + time_reftime = get_seconds(); /* only set allowed bits */ time_status &= STA_RONLY; -- GitLab From 4c574159d03f4d8a136a7adff2d0b1d82cadcb18 Mon Sep 17 00:00:00 2001 From: Thiago Farina Date: Wed, 27 Jan 2010 21:05:55 -0200 Subject: [PATCH 1355/3892] tools/perf/perf.c: Clean up trivial style issues Checked with: ./../scripts/checkpatch.pl --terse --file perf.c perf.c: 51: ERROR: open brace '{' following function declarations go on the next line perf.c: 73: ERROR: "foo*** bar" should be "foo ***bar" perf.c:112: ERROR: space prohibited before that close parenthesis ')' perf.c:127: ERROR: space prohibited before that close parenthesis ')' perf.c:171: ERROR: "foo** bar" should be "foo **bar" perf.c:213: ERROR: "(foo*)" should be "(foo *)" perf.c:216: ERROR: "(foo*)" should be "(foo *)" perf.c:217: ERROR: space required before that '*' (ctx:OxV) perf.c:452: ERROR: do not initialise statics to 0 or NULL perf.c:453: ERROR: do not initialise statics to 0 or NULL Signed-off-by: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Masami Hiramatsu LKML-Reference: <1264633557-17597-7-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/perf.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 05c861c045d5..109b89b30ced 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -48,7 +48,8 @@ int check_pager_config(const char *cmd) return c.val; } -static void commit_pager_choice(void) { +static void commit_pager_choice(void) +{ switch (use_pager) { case 0: setenv("PERF_PAGER", "cat", 1); @@ -70,7 +71,7 @@ static void set_debugfs_path(void) "tracing/events"); } -static int handle_options(const char*** argv, int* argc, int* envchanged) +static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -109,7 +110,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--perf-dir")) { if (*argc < 2) { - fprintf(stderr, "No directory given for --perf-dir.\n" ); + fprintf(stderr, "No directory given for --perf-dir.\n"); usage(perf_usage_string); } setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); @@ -124,7 +125,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { if (*argc < 2) { - fprintf(stderr, "No directory given for --work-tree.\n" ); + fprintf(stderr, "No directory given for --work-tree.\n"); usage(perf_usage_string); } setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); @@ -168,7 +169,7 @@ static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; int count, option_count; - const char** new_argv; + const char **new_argv; const char *alias_command; char *alias_string; @@ -210,11 +211,11 @@ static int handle_alias(int *argcp, const char ***argv) if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); - new_argv = realloc(new_argv, sizeof(char*) * + new_argv = realloc(new_argv, sizeof(char *) * (count + *argcp + 1)); /* insert after command name */ - memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); - new_argv[count+*argcp] = NULL; + memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); + new_argv[count + *argcp] = NULL; *argv = new_argv; *argcp += count - 1; @@ -450,8 +451,8 @@ int main(int argc, const char **argv) setup_path(); while (1) { - static int done_help = 0; - static int was_alias = 0; + static int done_help; + static int was_alias; was_alias = run_argv(&argc, &argv); if (errno != ENOENT) -- GitLab From 6a1b751fb89b61ef7240f2e3ed65a2e2776e7cfd Mon Sep 17 00:00:00 2001 From: John Kacur Date: Wed, 27 Jan 2010 21:05:54 -0200 Subject: [PATCH 1356/3892] perf: Ignore perf-archive temp file Tell git to ignore perf-archive. Signed-off-by: John Kacur Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <1264633557-17597-6-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 124760bb37b5..e1d60d780784 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -14,6 +14,7 @@ perf*.html common-cmds.h perf.data perf.data.old +perf-archive tags TAGS cscope* -- GitLab From 36706005d90642bccabfaacbb24d135155e984a8 Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Fri, 29 Jan 2010 12:05:51 +0100 Subject: [PATCH 1357/3892] ALSA: hda - Add support for IDT 92HD88 family codecs Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index cb9802f4b063..9694675f0b9e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -568,6 +568,11 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = { 0x0f, 0x10, 0x11, 0x1f, 0x20, }; +static hda_nid_t stac92hd88xxx_pin_nids[10] = { + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0f, 0x11, 0x1f, 0x20, +}; + #define STAC92HD71BXX_NUM_PINS 13 static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, @@ -2873,6 +2878,13 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) conn_len = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); + /* 92HD88: trace back up the link of nids to find the DAC */ + while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0])) + != AC_WID_AUD_OUT)) { + nid = conn[0]; + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + } for (j = 0; j < conn_len; j++) { wcaps = get_wcaps(codec, conn[j]); wtype = get_wcaps_type(wcaps); @@ -5318,6 +5330,16 @@ again: stac92hd83xxx_brd_tbl[spec->board_config]); switch (codec->vendor_id) { + case 0x111d7666: + case 0x111d7667: + case 0x111d7668: + case 0x111d7669: + spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); + spec->pin_nids = stac92hd88xxx_pin_nids; + spec->mono_nid = 0; + spec->digbeep_nid = 0; + spec->num_pwrs = 0; + break; case 0x111d7604: case 0x111d7605: case 0x111d76d5: @@ -6243,6 +6265,10 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx}, { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, -- GitLab From a45635dfb08a1fa2cf77bf1f2c4074961ce2e625 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 29 Jan 2010 22:19:04 +0900 Subject: [PATCH 1358/3892] sh: Reworked SH7780 PCI initialization. This consolidates the PCI initialization code for all of the pci-sh7780 users, and sets up the memory window dynamically as opposed to using hardcoded window positions. A number of bugs were fixed at the same time, including the PIO handling and master abort timeout settings being incorrect. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/fixups-r7780rp.c | 12 --- arch/sh/drivers/pci/fixups-sdk7780.c | 19 ---- arch/sh/drivers/pci/pci-sh4.h | 13 ++- arch/sh/drivers/pci/pci-sh7780.c | 149 +++++++++++++++------------ arch/sh/drivers/pci/pci-sh7780.h | 54 ++-------- 5 files changed, 102 insertions(+), 145 deletions(-) diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c index 15ca65cb667e..08b2d8658a00 100644 --- a/arch/sh/drivers/pci/fixups-r7780rp.c +++ b/arch/sh/drivers/pci/fixups-r7780rp.c @@ -22,15 +22,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { return irq_tab[slot]; } - -int pci_fixup_pcic(struct pci_channel *chan) -{ - pci_write_reg(chan, 0x000043ff, SH4_PCIINTM); - pci_write_reg(chan, 0x00000000, SH7780_PCIIBAR); - pci_write_reg(chan, 0x08000000, SH7780_PCICSCR0); - pci_write_reg(chan, 0x0000001b, SH7780_PCICSAR0); - pci_write_reg(chan, 0xfd000000, SH7780_PCICSCR1); - pci_write_reg(chan, 0x0000000f, SH7780_PCICSAR1); - - return 0; -} diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c index 250b0edd7365..0930f988ac29 100644 --- a/arch/sh/drivers/pci/fixups-sdk7780.c +++ b/arch/sh/drivers/pci/fixups-sdk7780.c @@ -31,22 +31,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { return sdk7780_irq_tab[pin-1][slot]; } -int pci_fixup_pcic(struct pci_channel *chan) -{ - /* Enable all interrupts, so we know what to fix */ - pci_write_reg(chan, 0x0000C3FF, SH7780_PCIIMR); - - /* Set up standard PCI config registers */ - pci_write_reg(chan, 0x08000000, SH7780_PCIMBAR0); /* PCI */ - pci_write_reg(chan, 0x08000000, SH4_PCILAR0); /* SHwy */ - pci_write_reg(chan, 0x07F00001, SH4_PCILSR0); /* size 128M w/ MBAR */ - - pci_write_reg(chan, 0x00000000, SH7780_PCIMBAR1); - pci_write_reg(chan, 0x00000000, SH4_PCILAR1); - pci_write_reg(chan, 0x00000000, SH4_PCILSR1); - - pci_write_reg(chan, 0xAB000801, SH7780_PCIIBAR); - pci_write_reg(chan, 0xA5000C01, SH4_PCICR); - - return 0; -} diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h index 4744a7dede0c..43dddd827561 100644 --- a/arch/sh/drivers/pci/pci-sh4.h +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -49,6 +49,17 @@ #define SH4_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */ #define SH4_PCIINT_MRPD 0x00000001 /* Master Read PERR Detect */ #define SH4_PCIINTM 0x118 /* PCI Interrupt Mask */ + #define SH4_PCIINTM_TTADIM BIT(14) /* Target-target abort interrupt */ + #define SH4_PCIINTM_TMTOIM BIT(9) /* Target retry timeout */ + #define SH4_PCIINTM_MDEIM BIT(8) /* Master function disable error */ + #define SH4_PCIINTM_APEDIM BIT(7) /* Address parity error detection */ + #define SH4_PCIINTM_SDIM BIT(6) /* SERR detection */ + #define SH4_PCIINTM_DPEITWM BIT(5) /* Data parity error for target write */ + #define SH4_PCIINTM_PEDITRM BIT(4) /* PERR detection for target read */ + #define SH4_PCIINTM_TADIMM BIT(3) /* Target abort for master */ + #define SH4_PCIINTM_MADIMM BIT(2) /* Master abort for master */ + #define SH4_PCIINTM_MWPDIM BIT(1) /* Master write data parity error */ + #define SH4_PCIINTM_MRDPEIM BIT(0) /* Master read data parity error */ #define SH4_PCIALR 0x11C /* Error Address Register */ #define SH4_PCICLR 0x120 /* Error Command/Data */ #define SH4_PCICLR_MPIO 0x80000000 @@ -61,7 +72,7 @@ #define SH4_PCIAINT 0x130 /* Arbiter Interrupt Register */ #define SH4_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */ #define SH4_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */ - #define SH4_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */ + #define SH4_PCIAINT_MBTO 0x00000800 /* Master Bus Time Out */ #define SH4_PCIAINT_TABT 0x00000008 /* Target Abort */ #define SH4_PCIAINT_MABT 0x00000004 /* Master Abort */ #define SH4_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */ diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 323b92d565fe..019e1afcd0a3 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -1,7 +1,7 @@ /* * Low-Level PCI Support for the SH7780 * - * Copyright (C) 2005 - 2009 Paul Mundt + * Copyright (C) 2005 - 2010 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -14,11 +14,13 @@ #include #include #include "pci-sh4.h" +#include +#include static struct resource sh7785_io_resource = { .name = "SH7785_IO", - .start = SH7780_PCI_IO_BASE, - .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1, + .start = 0x1000, + .end = SH7780_PCI_IO_SIZE - 1, .flags = IORESOURCE_IO }; @@ -38,25 +40,14 @@ static struct pci_channel sh7780_pci_controller = { .io_map_base = SH7780_PCI_IO_BASE, }; -static struct sh4_pci_address_map sh7780_pci_map = { - .window0 = { -#if defined(CONFIG_32BIT) - .base = SH7780_32BIT_DDR_BASE_ADDR, - .size = 0x40000000, -#else - .base = SH7780_CS0_BASE_ADDR, - .size = 0x20000000, -#endif - }, -}; - static int __init sh7780_pci_init(void) { struct pci_channel *chan = &sh7780_pci_controller; + phys_addr_t memphys; + size_t memsize; unsigned int id; - const char *type = NULL; + const char *type; int ret; - u32 word; printk(KERN_NOTICE "PCI: Starting intialization.\n"); @@ -65,17 +56,24 @@ static int __init sh7780_pci_init(void) /* Enable CPU access to the PCIC registers. */ __raw_writel(PCIECR_ENBL, PCIECR); - id = __raw_readw(chan->reg_base + SH7780_PCIVID); - if (id != SH7780_VENDOR_ID) { + /* Reset */ + __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST, + chan->reg_base + SH4_PCICR); + + /* Wait for it to come back up.. */ + mdelay(100); + + id = __raw_readw(chan->reg_base + PCI_VENDOR_ID); + if (id != PCI_VENDOR_ID_RENESAS) { printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id); return -ENODEV; } - id = __raw_readw(chan->reg_base + SH7780_PCIDID); - type = (id == SH7763_DEVICE_ID) ? "SH7763" : - (id == SH7780_DEVICE_ID) ? "SH7780" : - (id == SH7781_DEVICE_ID) ? "SH7781" : - (id == SH7785_DEVICE_ID) ? "SH7785" : + id = __raw_readw(chan->reg_base + PCI_DEVICE_ID); + type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" : + (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" : + (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" : + (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" : NULL; if (unlikely(!type)) { printk(KERN_ERR "PCI: Found an unsupported Renesas host " @@ -85,59 +83,78 @@ static int __init sh7780_pci_init(void) printk(KERN_NOTICE "PCI: Found a Renesas %s host " "controller, revision %d.\n", type, - __raw_readb(chan->reg_base + SH7780_PCIRID)); + __raw_readb(chan->reg_base + PCI_REVISION_ID)); if ((ret = sh4_pci_check_direct(chan)) != 0) return ret; /* - * Set the class and sub-class codes. + * Now throw it in to register initialization mode and + * start the real work. */ - __raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8, - chan->reg_base + SH7780_PCIBCC); - __raw_writeb(PCI_CLASS_BRIDGE_HOST & 0xff, - chan->reg_base + SH7780_PCISUB); + __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR); + + memphys = __pa(memory_start); + memsize = memory_end - memory_start; /* * Set IO and Mem windows to local address * Make PCI and local address the same for easy 1 to 1 mapping */ - pci_write_reg(chan, sh7780_pci_map.window0.size - 0xfffff, SH4_PCILSR0); - /* Set the values on window 0 PCI config registers */ - pci_write_reg(chan, sh7780_pci_map.window0.base, SH4_PCILAR0); - pci_write_reg(chan, sh7780_pci_map.window0.base, SH7780_PCIMBAR0); - - pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM); - - /* Set up standard PCI config registers */ - __raw_writew(0xFB00, chan->reg_base + SH7780_PCISTATUS); - __raw_writew(0x0047, chan->reg_base + SH7780_PCICMD); - __raw_writew(0x1912, chan->reg_base + SH7780_PCISVID); - __raw_writew(0x0001, chan->reg_base + SH7780_PCISID); - - __raw_writeb(0x00, chan->reg_base + SH7780_PCIPIF); - - /* Apply any last-minute PCIC fixups */ - pci_fixup_pcic(chan); - - pci_write_reg(chan, 0xfd000000, SH7780_PCIMBR0); - pci_write_reg(chan, 0x00fc0000, SH7780_PCIMBMR0); - -#ifdef CONFIG_32BIT - pci_write_reg(chan, 0xc0000000, SH7780_PCIMBR2); - pci_write_reg(chan, 0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2); -#endif - - /* Set IOBR for windows containing area specified in pci.h */ - pci_write_reg(chan, chan->io_resource->start & ~(SH7780_PCI_IO_SIZE-1), - SH7780_PCIIOBR); - pci_write_reg(chan, ((SH7780_PCI_IO_SIZE-1) & (7<<18)), - SH7780_PCIIOBMR); - - /* SH7780 init done, set central function init complete */ - /* use round robin mode to stop a device starving/overruning */ - word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO; - pci_write_reg(chan, word, SH4_PCICR); + __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); + + __raw_writel(memphys, chan->reg_base + SH4_PCILAR0); + __raw_writel((memsize - 1) << 9 | 1, + chan->reg_base + SH4_PCILSR0); + + /* Clear out PCI arbiter IRQs */ + __raw_writel(0, chan->reg_base + SH4_PCIAINT); + + /* Unmask all of the arbiter IRQs. */ + __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ + SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ + SH4_PCIAINT_WDPE, chan->reg_base + SH4_PCIAINTM); + + /* Clear all error conditions */ + __raw_writew(PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_SIG_SYSTEM_ERROR | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_SIG_TARGET_ABORT | \ + PCI_STATUS_PARITY, chan->reg_base + PCI_STATUS); + + __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ + PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ + PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); + + /* Unmask all of the PCI IRQs */ + __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ + SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ + SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ + SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ + SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ + SH4_PCIINTM_MRDPEIM, chan->reg_base + SH4_PCIINTM); + + /* + * Disable the cache snoop controller for non-coherent DMA. + */ + __raw_writel(0, chan->reg_base + SH7780_PCICSCR0); + __raw_writel(0, chan->reg_base + SH7780_PCICSAR0); + __raw_writel(0, chan->reg_base + SH7780_PCICSCR1); + __raw_writel(0, chan->reg_base + SH7780_PCICSAR1); + + __raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0); + __raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0); + + __raw_writel(0, chan->reg_base + SH7780_PCIIOBR); + __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); + + /* + * Initialization mode complete, release the control register and + * enable round robin mode to stop device overruns/starvation. + */ + __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO, + chan->reg_base + SH4_PCICR); register_pci_controller(chan); diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h index 4a52478c97cf..dee069c3865d 100644 --- a/arch/sh/drivers/pci/pci-sh7780.h +++ b/arch/sh/drivers/pci/pci-sh7780.h @@ -12,12 +12,11 @@ #ifndef _PCI_SH7780_H_ #define _PCI_SH7780_H_ -/* Platform Specific Values */ -#define SH7780_VENDOR_ID 0x1912 -#define SH7781_DEVICE_ID 0x0001 -#define SH7780_DEVICE_ID 0x0002 -#define SH7763_DEVICE_ID 0x0004 -#define SH7785_DEVICE_ID 0x0007 +#define PCI_VENDOR_ID_RENESAS 0x1912 +#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001 +#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002 +#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004 +#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007 /* SH7780 Control Registers */ #define PCIECR 0xFE000008 @@ -36,35 +35,6 @@ #define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */ /* SH7780 PCI Config Registers */ -#define SH7780_PCIVID 0x000 /* Vendor ID */ -#define SH7780_PCIDID 0x002 /* Device ID */ -#define SH7780_PCICMD 0x004 /* Command */ -#define SH7780_PCISTATUS 0x006 /* Status */ -#define SH7780_PCIRID 0x008 /* Revision ID */ -#define SH7780_PCIPIF 0x009 /* Program Interface */ -#define SH7780_PCISUB 0x00a /* Sub class code */ -#define SH7780_PCIBCC 0x00b /* Base class code */ -#define SH7780_PCICLS 0x00c /* Cache line size */ -#define SH7780_PCILTM 0x00d /* latency timer */ -#define SH7780_PCIHDR 0x00e /* Header type */ -#define SH7780_PCIBIST 0x00f /* BIST */ -#define SH7780_PCIIBAR 0x010 /* IO Base address */ -#define SH7780_PCIMBAR0 0x014 /* Memory base address0 */ -#define SH7780_PCIMBAR1 0x018 /* Memory base address1 */ -#define SH7780_PCISVID 0x02c /* Sub system vendor ID */ -#define SH7780_PCISID 0x02e /* Sub system ID */ -#define SH7780_PCICP 0x034 -#define SH7780_PCIINTLINE 0x03c /* Interrupt line */ -#define SH7780_PCIINTPIN 0x03d /* Interrupt pin */ -#define SH7780_PCIMINGNT 0x03e /* Minumum grand */ -#define SH7780_PCIMAXLAT 0x03f /* Maxmum latency */ -#define SH7780_PCICID 0x040 -#define SH7780_PCINIP 0x041 -#define SH7780_PCIPMC 0x042 -#define SH7780_PCIPMCSR 0x044 -#define SH7780_PCIPMCSR_BSE 0x046 -#define SH7780_PCICDD 0x047 - #define SH7780_PCIIR 0x114 /* PCI Interrupt Register */ #define SH7780_PCIIMR 0x118 /* PCI Interrupt Mask Register */ #define SH7780_PCIAIR 0x11C /* Error Address Register */ @@ -78,6 +48,8 @@ #define SH7780_PCIMBR0 0x1E0 #define SH7780_PCIMBMR0 0x1E4 +#define SH7780_PCIMBR1 0x1E8 +#define SH7780_PCIMBMR1 0x1EC #define SH7780_PCIMBR2 0x1F0 #define SH7780_PCIMBMR2 0x1F4 #define SH7780_PCIIOBR 0x1F8 @@ -87,16 +59,4 @@ #define SH7780_PCICSAR0 0x218 /* Cache Snoop1 Addr. Register */ #define SH7780_PCICSAR1 0x21C /* Cache Snoop2 Addr. Register */ -/* General Memory Config Addresses */ -#define SH7780_CS0_BASE_ADDR 0x0 -#define SH7780_MEM_REGION_SIZE 0x04000000 -#define SH7780_CS1_BASE_ADDR (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS2_BASE_ADDR (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS3_BASE_ADDR (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS4_BASE_ADDR (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS5_BASE_ADDR (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS6_BASE_ADDR (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE) - -#define SH7780_32BIT_DDR_BASE_ADDR 0x40000000 - #endif /* _PCI_SH7780_H_ */ -- GitLab From ac8ab54a8e41a5ed0ee2161d45b6dc855490989f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 29 Jan 2010 22:22:27 +0900 Subject: [PATCH 1359/3892] sh: Bail out early on PCI resource conflicts. Presently we just call in to request_resource() for the ioport and iomem resources without checking for errors. This has already hidden a couple of bugs, so add some error handling in for good measure. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pci.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 191075e91cda..82e59bc6210e 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -53,8 +53,12 @@ static DEFINE_MUTEX(pci_scan_mutex); void __devinit register_pci_controller(struct pci_channel *hose) { - request_resource(&iomem_resource, hose->mem_resource); - request_resource(&ioport_resource, hose->io_resource); + if (request_resource(&iomem_resource, hose->mem_resource) < 0) + goto out; + if (request_resource(&ioport_resource, hose->io_resource) < 0) { + release_resource(hose->mem_resource); + goto out; + } *hose_tail = hose; hose_tail = &hose->next; @@ -76,6 +80,9 @@ void __devinit register_pci_controller(struct pci_channel *hose) pcibios_scanbus(hose); mutex_unlock(&pci_scan_mutex); } + +out: + printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); } static int __init pcibios_init(void) @@ -319,20 +326,9 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) if (flags & IORESOURCE_IO) return ioport_map_pci(dev, start, len); - - /* - * Presently the IORESOURCE_MEM case is a bit special, most - * SH7751 style PCI controllers have PCI memory at a fixed - * location in the address space where no remapping is desired. - * With the IORESOURCE_MEM case more care has to be taken - * to inhibit page table mapping for legacy cores, but this is - * punted off to __ioremap(). - * -- PFM. - */ if (flags & IORESOURCE_MEM) { if (flags & IORESOURCE_CACHEABLE) return ioremap(start, len); - return ioremap_nocache(start, len); } -- GitLab From 320e68da59353fe6ad51b81f6865c4b674ad66ea Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 29 Jan 2010 22:38:13 +0900 Subject: [PATCH 1360/3892] sh: support PCI domains. Newer SH parts are now commonly shipping with multiple controllers, so we wire up PCI domain support to deal with them. Shamelessly cloned from the MIPS implementation. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 4 ++++ arch/sh/drivers/pci/pci.c | 17 +++++++++++++++-- arch/sh/include/asm/pci.h | 13 ++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 352879c1b86b..bae53831c06b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -826,11 +826,15 @@ config MAPLE config PCI bool "PCI support" depends on SYS_SUPPORTS_PCI + select PCI_DOMAINS help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside your box. If you have PCI, say Y, otherwise N. +config PCI_DOMAINS + bool + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig" diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 82e59bc6210e..45a15cab01df 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -33,15 +33,22 @@ static int pci_initialized; static void __devinit pcibios_scanbus(struct pci_channel *hose) { static int next_busno; + static int need_domain_info; struct pci_bus *bus; bus = pci_scan_bus(next_busno, hose->pci_ops, hose); + hose->bus = bus; + + need_domain_info = need_domain_info || hose->index; + hose->need_domain_info = need_domain_info; if (bus) { next_busno = bus->subordinate + 1; /* Don't allow 8-bit bus number overflow inside the hose - reserve some space for bridges. */ - if (next_busno > 224) + if (next_busno > 224) { next_busno = 0; + need_domain_info = 1; + } pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -307,9 +314,15 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev, { struct pci_channel *chan = dev->sysdata; - if (!chan->io_map_base) + if (unlikely(!chan->io_map_base)) { chan->io_map_base = generic_io_base; + if (pci_domains_supported) + panic("To avoid data corruption io_map_base MUST be " + "set with multiple PCI domains."); + } + + return (void __iomem *)(chan->io_map_base + port); } diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index f362d8a045e7..d124a009889f 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -15,6 +15,7 @@ */ struct pci_channel { struct pci_channel *next; + struct pci_bus *bus; struct pci_ops *pci_ops; struct resource *io_resource; @@ -24,8 +25,10 @@ struct pci_channel { unsigned long mem_offset; unsigned long reg_base; - unsigned long io_map_base; + + unsigned int index; + unsigned int need_domain_info; }; extern void register_pci_controller(struct pci_channel *hose); @@ -108,6 +111,14 @@ extern void pcibios_resource_to_bus(struct pci_dev *dev, extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, struct pci_bus_region *region); +#define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + struct pci_channel *hose = bus->sysdata; + return hose->need_domain_info; +} + /* Chances are this interrupt is wired PC-style ... */ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) { -- GitLab From 9e9d04c05fd01018da35fa1daa9bda844cac6162 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 29 Jan 2010 10:57:07 +0900 Subject: [PATCH 1361/3892] ASoC: AC97: SMDK-WM9713: Convert notes from cset to sset It's more robust when references are provided in control names rather than numid. Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk_wm9713.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c index 6fa2c9d17d7a..24fd39f38ccb 100644 --- a/sound/soc/s3c24xx/smdk_wm9713.c +++ b/sound/soc/s3c24xx/smdk_wm9713.c @@ -29,24 +29,15 @@ static struct snd_soc_card smdk; /* Playback (HeadPhone):- - Headphone Playback Switch - On - $ amixer cset numid=4 1 - - Right Headphone Out Mux - Headphone - $ amixer cset numid=92 2 - Left Headphone Out Mux - Headphone - $ amixer cset numid=93 2 - - Right HP Mixer PCM Playback Switch - On - $ amixer cset numid=75 1 - Left HP Mixer PCM Playback Switch - On - $ amixer cset numid=81 1 + $ amixer sset 'Headphone' unmute + $ amixer sset 'Right Headphone Out Mux' 'Headphone' + $ amixer sset 'Left Headphone Out Mux' 'Headphone' + $ amixer sset 'Right HP Mixer PCM' unmute + $ amixer sset 'Left HP Mixer PCM' unmute Capture (LineIn):- - Right Capture Source - Line - $ amixer cset numid=86 2 - Left Capture Source - Line - $ amixer cset numid=87 2 + $ amixer sset 'Right Capture Source' 'Line' + $ amixer sset 'Left Capture Source' 'Line' */ static struct snd_soc_dai_link smdk_dai = { -- GitLab From 9f5b64b767203131a7a3a280859e70d4413c9672 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jan 2010 12:15:00 +0100 Subject: [PATCH 1362/3892] ASoC: add support for the sh7722 Migo-R board Add support for audio on sh7722-based Migo-R boards, using SIU and wm8978 codec, recording via external microphone and playback via headphones are implemented. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 8 ++ sound/soc/sh/Makefile | 2 + sound/soc/sh/migor.c | 222 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 sound/soc/sh/migor.c diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 3f1cd5503342..a86696bbe179 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -61,4 +61,12 @@ config SND_FSI_DA7210 This option enables generic sound support for the FSI - DA7210 unit +config SND_SIU_MIGOR + tristate "SIU sound support on Migo-R" + depends on SH_MIGOR + select SND_SOC_SH4_SIU + select SND_SOC_WM8978 + help + This option enables sound support for the SH7722 Migo-R board + endmenu diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index 5a97d2539d84..8a5a19293bda 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -16,7 +16,9 @@ obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o snd-soc-sh7760-ac97-objs := sh7760-ac97.o snd-soc-fsi-ak4642-objs := fsi-ak4642.o snd-soc-fsi-da7210-objs := fsi-da7210.o +snd-soc-migor-objs := migor.o obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o +obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c new file mode 100644 index 000000000000..3ccd9b393312 --- /dev/null +++ b/sound/soc/sh/migor.c @@ -0,0 +1,222 @@ +/* + * ALSA SoC driver for Migo-R + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski + * + * 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 +#include +#include +#include + +#include "../codecs/wm8978.h" +#include "siu.h" + +/* Default 8000Hz sampling frequency */ +static unsigned long codec_freq = 8000 * 512; + +static unsigned int use_count; + +/* External clock, sourced from the codec at the SIUMCKB pin */ +static unsigned long siumckb_recalc(struct clk *clk) +{ + return codec_freq; +} + +static struct clk_ops siumckb_clk_ops = { + .recalc = siumckb_recalc, +}; + +static struct clk siumckb_clk = { + .name = "siumckb_clk", + .id = -1, + .ops = &siumckb_clk_ops, + .rate = 0, /* initialised at run-time */ +}; + +static int migor_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + int ret; + unsigned int rate = params_rate(params); + + ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_DACCLK, 8); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + codec_freq = rate * 512; + /* + * This propagates the parent frequency change to children and + * recalculates the frequency table + */ + clk_set_rate(&siumckb_clk, codec_freq); + dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq); + + ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT, + codec_freq / 2, SND_SOC_CLOCK_IN); + + if (!ret) + use_count++; + + return ret; +} + +static int migor_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + if (use_count) { + use_count--; + + if (!use_count) + snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0, + SND_SOC_CLOCK_IN); + } else { + dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n"); + } + + return 0; +} + +static struct snd_soc_ops migor_dai_ops = { + .hw_params = migor_hw_params, + .hw_free = migor_hw_free, +}; + +static const struct snd_soc_dapm_widget migor_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Onboard Microphone", NULL), + SND_SOC_DAPM_MIC("External Microphone", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */ + { "Headphone", NULL, "OUT4 VMID" }, + { "OUT4 VMID", NULL, "LHP" }, + { "OUT4 VMID", NULL, "RHP" }, + + /* On-board microphone */ + { "RMICN", NULL, "Mic Bias" }, + { "RMICP", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Onboard Microphone" }, + + /* External microphone */ + { "LMICN", NULL, "Mic Bias" }, + { "LMICP", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "External Microphone" }, +}; + +static int migor_dai_init(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, migor_dapm_widgets, + ARRAY_SIZE(migor_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + return 0; +} + +/* migor digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link migor_dai = { + .name = "wm8978", + .stream_name = "WM8978", + .cpu_dai = &siu_i2s_dai, + .codec_dai = &wm8978_dai, + .ops = &migor_dai_ops, + .init = migor_dai_init, +}; + +/* migor audio machine driver */ +static struct snd_soc_card snd_soc_migor = { + .name = "Migo-R", + .platform = &siu_platform, + .dai_link = &migor_dai, + .num_links = 1, +}; + +/* migor audio subsystem */ +static struct snd_soc_device migor_snd_devdata = { + .card = &snd_soc_migor, + .codec_dev = &soc_codec_dev_wm8978, +}; + +static struct platform_device *migor_snd_device; + +static int __init migor_init(void) +{ + int ret; + + ret = clk_register(&siumckb_clk); + if (ret < 0) + return ret; + + /* Port number used on this machine: port B */ + migor_snd_device = platform_device_alloc("soc-audio", 1); + if (!migor_snd_device) { + ret = -ENOMEM; + goto epdevalloc; + } + + platform_set_drvdata(migor_snd_device, &migor_snd_devdata); + + migor_snd_devdata.dev = &migor_snd_device->dev; + + ret = platform_device_add(migor_snd_device); + if (ret) + goto epdevadd; + + return 0; + +epdevadd: + platform_device_put(migor_snd_device); +epdevalloc: + clk_unregister(&siumckb_clk); + return ret; +} + +static void __exit migor_exit(void) +{ + clk_unregister(&siumckb_clk); + platform_device_unregister(migor_snd_device); +} + +module_init(migor_init); +module_exit(migor_exit); + +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_DESCRIPTION("ALSA SoC Migor"); +MODULE_LICENSE("GPL v2"); -- GitLab From 640b796f2ca88113bf2fefd380bc807092ce6fa1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jan 2010 16:28:55 +0100 Subject: [PATCH 1363/3892] ASoC: remove bogus SLEEP mode from wm8978 driver Tests showed, that bit 6 of the WM8978_POWER_MANAGEMENT_2 register of wm8978 affects codec clocks. Being useless for suspend / resume, it cannot be used in bias-level control either. Remove this bit handling. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d9d4e9dd1adb..8dcebaa8604a 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -873,8 +873,6 @@ static int wm8978_suspend(struct platform_device *pdev, pm_message_t state) wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); /* Also switch PLL off */ snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); - /* Put to sleep */ - snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0x40); return 0; } @@ -887,9 +885,6 @@ static int wm8978_resume(struct platform_device *pdev) int i; u16 *cache = codec->reg_cache; - /* Wake up the codec */ - snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0); - /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) { if (i == WM8978_RESET) -- GitLab From b2c3e923110f6ca60ccb30cf4a6bda5211454c4f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Jan 2010 15:31:06 +0100 Subject: [PATCH 1364/3892] ASoC: clean up wm8974 and wm8978 clock divider handling wm8974 and wm8978 codec drivers control DAC and ADC oversampling rates in their .set_clkdiv() methods, which is wrong, because these are simple boolean switches and not clock dividers. Move these bits to sound controls. Also remove manual configuration of the MCLK divider in wm8978, since it is configured automatically. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 12 ++++-------- sound/soc/codecs/wm8974.h | 12 +----------- sound/soc/codecs/wm8978.c | 19 ++++--------------- sound/soc/codecs/wm8978.h | 3 --- sound/soc/sh/migor.c | 4 ---- 5 files changed, 9 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 8812751da8c9..ee637af4737a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -170,6 +170,10 @@ SOC_ENUM("Aux Mode", wm8974_auxmode), SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1), + +/* DAC / ADC oversampling */ +SOC_SINGLE("DAC 128x Oversampling Switch", WM8974_DAC, 8, 1, 0), +SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0), }; /* Speaker Output Mixer */ @@ -381,14 +385,6 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f; snd_soc_write(codec, WM8974_CLOCK, reg | div); break; - case WM8974_ADCCLK: - reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7; - snd_soc_write(codec, WM8974_ADC, reg | div); - break; - case WM8974_DACCLK: - reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7; - snd_soc_write(codec, WM8974_DAC, reg | div); - break; case WM8974_BCLKDIV: reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3; snd_soc_write(codec, WM8974_CLOCK, reg | div); diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h index 98de9562d4d2..896a7f0f3fc4 100644 --- a/sound/soc/codecs/wm8974.h +++ b/sound/soc/codecs/wm8974.h @@ -57,17 +57,7 @@ /* Clock divider Id's */ #define WM8974_OPCLKDIV 0 #define WM8974_MCLKDIV 1 -#define WM8974_ADCCLK 2 -#define WM8974_DACCLK 3 -#define WM8974_BCLKDIV 4 - -/* DAC clock dividers */ -#define WM8974_DACCLK_F2 (1 << 3) -#define WM8974_DACCLK_F4 (0 << 3) - -/* ADC clock dividers */ -#define WM8974_ADCCLK_F2 (1 << 3) -#define WM8974_ADCCLK_F4 (0 << 3) +#define WM8974_BCLKDIV 2 /* PLL Out dividers */ #define WM8974_OPCLKDIV_1 (0 << 4) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 8dcebaa8604a..ec2624b4c370 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -210,6 +210,10 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = { /* Speaker */ SOC_DOUBLE_R("Speaker Switch", WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1), + + /* DAC / ADC oversampling */ + SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL, 8, 1, 0), + SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL, 8, 1, 0), }; /* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */ @@ -513,21 +517,6 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai, if (wm8978->f_mclk) ret = wm8978_configure_pll(codec); break; - case WM8978_MCLKDIV: - if (div & ~0xe0) - return -EINVAL; - snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, div); - break; - case WM8978_ADCCLK: - if (div & ~8) - return -EINVAL; - snd_soc_update_bits(codec, WM8978_ADC_CONTROL, 8, div); - break; - case WM8978_DACCLK: - if (div & ~8) - return -EINVAL; - snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 8, div); - break; case WM8978_BCLKDIV: if (div & ~0x1c) return -EINVAL; diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h index b58f0bf947e7..56ec83270917 100644 --- a/sound/soc/codecs/wm8978.h +++ b/sound/soc/codecs/wm8978.h @@ -72,9 +72,6 @@ /* Clock divider Id's */ enum wm8978_clk_id { WM8978_OPCLKRATE, - WM8978_MCLKDIV, - WM8978_ADCCLK, - WM8978_DACCLK, WM8978_BCLKDIV, }; diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c index 3ccd9b393312..b823a5c9b9bc 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/sh/migor.c @@ -59,10 +59,6 @@ static int migor_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_DACCLK, 8); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512); if (ret < 0) return ret; -- GitLab From 1dbfd9d46a6df5232ba0b12d2da950da89eff3da Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 29 Jan 2010 16:56:51 +0530 Subject: [PATCH 1365/3892] ath9k: Handle full sleep in ps_restore. IDLE PS (Full Sleep) doesn't work when ifconfig up is done during Idle unassociated state. Fix this by restoring FULL SLEEP in ps_restore if CONF_IDLE is set. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bdbcc70df075..3f8a7e773d55 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -480,6 +480,7 @@ struct ath_softc { u8 nbcnvifs; u16 nvifs; bool ps_enabled; + bool ps_idle; unsigned long ps_usecount; enum ath9k_int imask; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6f3e71c5071e..e04835cb21b5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -143,8 +143,10 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_enabled && - !(sc->ps_flags & (PS_WAIT_FOR_BEACON | + if (sc->ps_idle) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + else if (sc->ps_enabled && + !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK))) @@ -1528,6 +1530,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&sc->wiphy_lock); if (enable_radio) { + sc->ps_idle = false; ath_radio_enable(sc, hw); ath_print(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); @@ -1635,6 +1638,7 @@ skip_chan_change: if (disable_radio) { ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); + sc->ps_idle = true; ath_radio_disable(sc, hw); } -- GitLab From 396c56a9c69ebb0baf9171a6365ac9fda322728d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 30 Jan 2010 01:41:21 +0900 Subject: [PATCH 1366/3892] sh: Kill off broken type 1 PCI config access checks. The host controllers only support type 1, so there's not much else to test for. Some of the older controllers also supported type 2 accesses, but we've never supported those, and likely never will. Beyond that, the P1SEG test is meaningless for 32-bit mode, so rather than refactoring it, just kill the type 1 test off completely. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/ops-sh4.c | 28 ---------------------------- arch/sh/drivers/pci/pci-sh4.h | 1 - arch/sh/drivers/pci/pci-sh7751.c | 4 ---- arch/sh/drivers/pci/pci-sh7780.c | 4 ---- 4 files changed, 37 deletions(-) diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c index 78bebebdc99c..e55e81a71727 100644 --- a/arch/sh/drivers/pci/ops-sh4.c +++ b/arch/sh/drivers/pci/ops-sh4.c @@ -102,34 +102,6 @@ struct pci_ops sh4_pci_ops = { .write = sh4_pci_write, }; -/* - * Not really related to pci_ops, but it's common and not worth shoving - * somewhere else for now.. - */ -int __init sh4_pci_check_direct(struct pci_channel *chan) -{ - /* - * Check if configuration works. - */ - unsigned int tmp = pci_read_reg(chan, SH4_PCIPAR); - - pci_write_reg(chan, P1SEG, SH4_PCIPAR); - - if (pci_read_reg(chan, SH4_PCIPAR) == P1SEG) { - pci_write_reg(chan, tmp, SH4_PCIPAR); - printk(KERN_INFO "PCI: Using configuration type 1\n"); - request_region(chan->reg_base + SH4_PCIPAR, 8, - "PCI conf1"); - return 0; - } - - pci_write_reg(chan, tmp, SH4_PCIPAR); - - printk(KERN_ERR "PCI: %s failed\n", __func__); - - return -EINVAL; -} - int __attribute__((weak)) pci_fixup_pcic(struct pci_channel *chan) { /* Nothing to do. */ diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h index 43dddd827561..cbf763b3015e 100644 --- a/arch/sh/drivers/pci/pci-sh4.h +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -162,7 +162,6 @@ /* arch/sh/kernel/drivers/pci/ops-sh4.c */ extern struct pci_ops sh4_pci_ops; -int sh4_pci_check_direct(struct pci_channel *chan); int pci_fixup_pcic(struct pci_channel *chan); struct sh4_pci_address_space { diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 2455cf32db5a..02306ddb4011 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -79,7 +79,6 @@ static int __init sh7751_pci_init(void) struct pci_channel *chan = &sh7751_pci_controller; unsigned int id; u32 word, reg; - int ret; printk(KERN_NOTICE "PCI: Starting intialization.\n"); @@ -93,9 +92,6 @@ static int __init sh7751_pci_init(void) return -ENODEV; } - if ((ret = sh4_pci_check_direct(chan)) != 0) - return ret; - /* Set the BCR's to enable PCI access */ reg = __raw_readl(SH7751_BCR1); reg |= 0x80000; diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 019e1afcd0a3..40531cd367b7 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -47,7 +47,6 @@ static int __init sh7780_pci_init(void) size_t memsize; unsigned int id; const char *type; - int ret; printk(KERN_NOTICE "PCI: Starting intialization.\n"); @@ -85,9 +84,6 @@ static int __init sh7780_pci_init(void) "controller, revision %d.\n", type, __raw_readb(chan->reg_base + PCI_REVISION_ID)); - if ((ret = sh4_pci_check_direct(chan)) != 0) - return ret; - /* * Now throw it in to register initialization mode and * start the real work. -- GitLab From 4680c29f69e981106da2abfea7f1a3e6f1b03791 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:09 -0700 Subject: [PATCH 1367/3892] OMAP2/3 clock: clean up omap*_clk_arch_init() In the OMAP3xxx clock code, remove the #ifdef CONFIG_ARCH_OMAP3 in clock34xx.c, since this file is only compiled for OMAP3xxx builds. Also, rename omap2_clk_arch_init in this file to omap3xxx_clk_arch_init() to pave the way for multi-OMAP kernels. Ensure that it is not executed on non-OMAP3xxx systems. In the OMAP2xxx clock code, rename omap2_clk_arch_init in this file to omap2xxx_clk_arch_init() to pave the way for multi-OMAP kernels. Ensure that it is not executed on non-OMAP2xxx systems. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock2xxx.c | 7 +++++-- arch/arm/mach-omap2/clock34xx.c | 16 +++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index e5b9851b7419..b7e81ec3d819 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -101,11 +101,14 @@ void omap2_clk_prepare_for_reboot(void) * Switch the MPU rate if specified on cmdline. * We cannot do this early until cmdline is parsed. */ -static int __init omap2_clk_arch_init(void) +static int __init omap2xxx_clk_arch_init(void) { struct clk *virt_prcm_set, *sys_ck, *dpll_ck, *mpu_ck; unsigned long sys_ck_rate; + if (!cpu_is_omap24xx()) + return 0; + if (!mpurate) return -EINVAL; @@ -129,6 +132,6 @@ static int __init omap2_clk_arch_init(void) return 0; } -arch_initcall(omap2_clk_arch_init); +arch_initcall(omap2xxx_clk_arch_init); diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 552ad300bb0e..d38ad44fe0aa 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -162,12 +162,6 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) /* Common clock code */ -/* - * As it is structured now, this will prevent an OMAP2/3 multiboot - * kernel from compiling. This will need further attention. - */ -#if defined(CONFIG_ARCH_OMAP3) - /* * Set clocks for bypass mode for reboot to work. */ @@ -213,11 +207,14 @@ void omap3_clk_lock_dpll5(void) * Switch the MPU rate if specified on cmdline. * We cannot do this early until cmdline is parsed. */ -static int __init omap2_clk_arch_init(void) +static int __init omap3xxx_clk_arch_init(void) { struct clk *osc_sys_ck, *dpll1_ck, *arm_fck, *core_ck; unsigned long osc_sys_rate; + if (!cpu_is_omap34xx()) + return 0; + if (!mpurate) return -EINVAL; @@ -246,9 +243,6 @@ static int __init omap2_clk_arch_init(void) return 0; } -arch_initcall(omap2_clk_arch_init); - - -#endif +arch_initcall(omap3xxx_clk_arch_init); -- GitLab From da4d2904abc0c31ac829e9c6d52106d5a6606507 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:10 -0700 Subject: [PATCH 1368/3892] OMAP2/3 clock: remove unnecessary includes and clean up header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that almost all of the code has been removed from clock2xxx.c and clock34xx.c, many of the includes are now unnecessary and can be removed. While we're here, standardize the initial comment blocks. Signed-off-by: Paul Walmsley Cc: Richard Woodruff Cc: Jouni Högander --- arch/arm/mach-omap2/clock2xxx.c | 35 ++++++++++----------------------- arch/arm/mach-omap2/clock34xx.c | 16 +++------------ 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index b7e81ec3d819..e98f48b0a5c6 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -1,15 +1,15 @@ /* - * linux/arch/arm/mach-omap2/clock.c + * clock2xxx.c - OMAP2xxx-specific clock integration code * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2008 Nokia Corporation + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation * - * Contacts: - * Richard Woodruff - * Paul Walmsley + * Contacts: + * Richard Woodruff + * Paul Walmsley * - * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, - * Gordon McNutt and RidgeRun, Inc. + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,38 +17,23 @@ */ #undef DEBUG -#include #include -#include -#include #include -#include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include "clock.h" #include "clock2xxx.h" -#include "opp2xxx.h" -#include "prm.h" -#include "prm-regbits-24xx.h" #include "cm.h" #include "cm-regbits-24xx.h" struct clk *vclk, *sclk, *dclk; -/*------------------------------------------------------------------------- +/* * Omap24xx specific clock functions - *-------------------------------------------------------------------------*/ + */ #ifdef CONFIG_ARCH_OMAP2430 diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index d38ad44fe0aa..8a7db7a03bec 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -2,10 +2,10 @@ * OMAP3-specific clock framework functions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2009 Nokia Corporation + * Copyright (C) 2007-2010 Nokia Corporation * - * Written by Paul Walmsley - * Testing and integration fixes by Jouni Högander + * Paul Walmsley + * Jouni Högander * * Parts of this code are based on code written by * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu @@ -16,27 +16,17 @@ */ #undef DEBUG -#include #include -#include -#include #include #include #include #include -#include -#include #include #include -#include -#include -#include -#include #include "clock.h" #include "clock34xx.h" -#include "sdrc.h" #include "prm.h" #include "prm-regbits-34xx.h" #include "cm.h" -- GitLab From feec1277a5c599ebca6217bc6bb9f6410e84793b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:11 -0700 Subject: [PATCH 1369/3892] OMAP2/3/4 clock: omap2_clk_prepare_for_reboot() is OMAP2xxx-only omap2_clk_prepare_for_reboot() is only applicable to OMAP2xxx chips, so rename it to omap2xxx_clk_prepare_for_reboot() and only call it when running on OMAP2xxx chips. Remove the old stub in the OMAP3 clock code. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.h | 1 - arch/arm/mach-omap2/clock2xxx.c | 2 +- arch/arm/mach-omap2/clock2xxx.h | 1 + arch/arm/mach-omap2/clock34xx.c | 21 ++------------------- arch/arm/mach-omap2/clock44xx.c | 5 ----- arch/arm/mach-omap2/prcm.c | 8 +++++--- 6 files changed, 9 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index dcd58cde13b6..be5a55f57030 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -84,7 +84,6 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); u32 omap2_get_dpll_rate(struct clk *clk); void omap2_init_dpll_parent(struct clk *clk); int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); -void omap2_clk_prepare_for_reboot(void); int omap2_dflt_clk_enable(struct clk *clk); void omap2_dflt_clk_disable(struct clk *clk); void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index e98f48b0a5c6..a48b01ab0e35 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c @@ -71,7 +71,7 @@ const struct clkops clkops_omap2430_i2chs_wait = { /* * Set clocks for bypass mode for reboot to work. */ -void omap2_clk_prepare_for_reboot(void) +void omap2xxx_clk_prepare_for_reboot(void) { u32 rate; diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index c14061b2b9f1..bed294ac3647 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -18,6 +18,7 @@ int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate); unsigned long omap2xxx_clk_get_core_rate(struct clk *clk); u32 omap2xxx_get_apll_clkin(void); u32 omap2xxx_get_sysclkdiv(void); +void omap2xxx_clk_prepare_for_reboot(void); /* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */ #ifdef CONFIG_ARCH_OMAP2420 diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 8a7db7a03bec..34d395046280 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -150,25 +150,6 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) return omap3_noncore_dpll_set_rate(clk, rate); } -/* Common clock code */ - -/* - * Set clocks for bypass mode for reboot to work. - */ -void omap2_clk_prepare_for_reboot(void) -{ - /* REVISIT: Not ready for 343x */ -#if 0 - u32 rate; - - if (vclk == NULL || sclk == NULL) - return; - - rate = clk_get_rate(sclk); - clk_set_rate(vclk, rate); -#endif -} - void omap3_clk_lock_dpll5(void) { struct clk *dpll5_clk; @@ -191,6 +172,8 @@ void omap3_clk_lock_dpll5(void) return; } +/* Common clock code */ + /* REVISIT: Move this init stuff out into clock.c */ /* diff --git a/arch/arm/mach-omap2/clock44xx.c b/arch/arm/mach-omap2/clock44xx.c index 08dd6427df70..c238717e3760 100644 --- a/arch/arm/mach-omap2/clock44xx.c +++ b/arch/arm/mach-omap2/clock44xx.c @@ -17,8 +17,3 @@ const struct clkops clkops_noncore_dpll_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, }; - -void omap2_clk_prepare_for_reboot(void) -{ - return; -} diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index abafd2298ece..e8e121a41d6d 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -29,6 +29,7 @@ #include #include "clock.h" +#include "clock2xxx.h" #include "cm.h" #include "prm.h" #include "prm-regbits-24xx.h" @@ -133,11 +134,12 @@ EXPORT_SYMBOL(omap_prcm_get_reset_sources); void omap_prcm_arch_reset(char mode) { s16 prcm_offs; - omap2_clk_prepare_for_reboot(); - if (cpu_is_omap24xx()) + if (cpu_is_omap24xx()) { + omap2xxx_clk_prepare_for_reboot(); + prcm_offs = WKUP_MOD; - else if (cpu_is_omap34xx()) { + } else if (cpu_is_omap34xx()) { u32 l; prcm_offs = OMAP3430_GR_MOD; -- GitLab From 60c3f65191d077dc4f69fca8eca39fb47f72d8b0 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:11 -0700 Subject: [PATCH 1370/3892] OMAP3 DPLL: reorganize static functions Move all static functions up to the top of the file to match the practice in other OMAP clock code. Make omap3_noncore_dpll_program() static (noted by sparse) and prepend an underscore to the function name to mark that it is file-local. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/dpll3xxx.c | 113 +++++++++++++++++---------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index f6055b493294..2b559fc64855 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -44,17 +44,7 @@ #define MAX_DPLL_WAIT_TRIES 1000000 - -/** - * omap3_dpll_recalc - recalculate DPLL rate - * @clk: DPLL struct clk - * - * Recalculate and propagate the DPLL rate. - */ -unsigned long omap3_dpll_recalc(struct clk *clk) -{ - return omap2_get_dpll_rate(clk); -} +/* Private functions */ /* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) @@ -136,8 +126,6 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) return f; } -/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ - /* * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness * @clk: pointer to a DPLL struct clk @@ -237,6 +225,63 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) return 0; } +/* + * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly + * @clk: struct clk * of DPLL to set + * @m: DPLL multiplier to set + * @n: DPLL divider to set + * @freqsel: FREQSEL value to set + * + * Program the DPLL with the supplied M, N values, and wait for the DPLL to + * lock.. Returns -EINVAL upon error, or 0 upon success. + */ +static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) +{ + struct dpll_data *dd = clk->dpll_data; + u32 v; + + /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ + _omap3_noncore_dpll_bypass(clk); + + /* Set jitter correction */ + if (!cpu_is_omap44xx()) { + v = __raw_readl(dd->control_reg); + v &= ~dd->freqsel_mask; + v |= freqsel << __ffs(dd->freqsel_mask); + __raw_writel(v, dd->control_reg); + } + + /* Set DPLL multiplier, divider */ + v = __raw_readl(dd->mult_div1_reg); + v &= ~(dd->mult_mask | dd->div1_mask); + v |= m << __ffs(dd->mult_mask); + v |= (n - 1) << __ffs(dd->div1_mask); + __raw_writel(v, dd->mult_div1_reg); + + /* We let the clock framework set the other output dividers later */ + + /* REVISIT: Set ramp-up delay? */ + + _omap3_noncore_dpll_lock(clk); + + return 0; +} + +/* Public functions */ + +/** + * omap3_dpll_recalc - recalculate DPLL rate + * @clk: DPLL struct clk + * + * Recalculate and propagate the DPLL rate. + */ +unsigned long omap3_dpll_recalc(struct clk *clk) +{ + return omap2_get_dpll_rate(clk); +} + +/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ + /** * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode * @clk: pointer to a DPLL struct clk @@ -292,48 +337,6 @@ void omap3_noncore_dpll_disable(struct clk *clk) /* Non-CORE DPLL rate set code */ -/* - * omap3_noncore_dpll_program - set non-core DPLL M,N values directly - * @clk: struct clk * of DPLL to set - * @m: DPLL multiplier to set - * @n: DPLL divider to set - * @freqsel: FREQSEL value to set - * - * Program the DPLL with the supplied M, N values, and wait for the DPLL to - * lock.. Returns -EINVAL upon error, or 0 upon success. - */ -int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) -{ - struct dpll_data *dd = clk->dpll_data; - u32 v; - - /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ - _omap3_noncore_dpll_bypass(clk); - - /* Set jitter correction */ - if (!cpu_is_omap44xx()) { - v = __raw_readl(dd->control_reg); - v &= ~dd->freqsel_mask; - v |= freqsel << __ffs(dd->freqsel_mask); - __raw_writel(v, dd->control_reg); - } - - /* Set DPLL multiplier, divider */ - v = __raw_readl(dd->mult_div1_reg); - v &= ~(dd->mult_mask | dd->div1_mask); - v |= m << __ffs(dd->mult_mask); - v |= (n - 1) << __ffs(dd->div1_mask); - __raw_writel(v, dd->mult_div1_reg); - - /* We let the clock framework set the other output dividers later */ - - /* REVISIT: Set ramp-up delay? */ - - _omap3_noncore_dpll_lock(clk); - - return 0; -} - /** * omap3_noncore_dpll_set_rate - set non-core DPLL rate * @clk: struct clk * of DPLL to set -- GitLab From d3730192294c1c98b17a67aadbbdc4c28ad05c6e Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:11 -0700 Subject: [PATCH 1371/3892] OMAP clock: resolve all remaining sparse warnings Resolve all remaining sparse warnings in the OMAP clock code. Signed-off-by: Paul Walmsley --- arch/arm/plat-omap/clock.c | 2 +- arch/arm/plat-omap/include/plat/clock.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index e0f72f48b8b1..0ae27538385d 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -173,7 +173,7 @@ EXPORT_SYMBOL(clk_get_parent); * OMAP specific clock functions shared between omap1 and omap2 *-------------------------------------------------------------------------*/ -unsigned int __initdata mpurate; +int __initdata mpurate; /* * By default we use the rate set by the bootloader. diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 896cedc923a7..e41313208125 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -123,7 +123,7 @@ struct clk_functions { #endif }; -extern unsigned int mpurate; +extern int mpurate; extern int clk_init(struct clk_functions *custom_clocks); extern void clk_preinit(struct clk *clk); -- GitLab From e80a9729b15f4c2c00ed51d61aa543fb4269d5ca Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:12 -0700 Subject: [PATCH 1372/3892] OMAP2/3/4 clock: rename and clean the omap2_clk_init() functions Rename the omap2_clk_init() in the OMAP2, 3, and 4 clock code to be omap2xxx_clk_init(), omap3xxx_clk_init(), etc. Remove all traces of the (commented) old virt_prcm_set code from omap3xxx_clk_init() and omap4xxx_clk_init(), since this will be handled with the OPP code that is cooking in the PM branch. After this patch, there should be very little else in the clock code that blocks a multi-OMAP 2+3 kernel. (OMAP2420+OMAP2430 still has some outstanding issues that need to be resolved; this is pending on some additions to the hwmod data.) Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.h | 1 - arch/arm/mach-omap2/clock2xxx.h | 1 + arch/arm/mach-omap2/clock2xxx_data.c | 2 +- arch/arm/mach-omap2/clock34xx.c | 2 +- arch/arm/mach-omap2/clock34xx.h | 1 + arch/arm/mach-omap2/clock34xx_data.c | 19 +------------------ arch/arm/mach-omap2/clock44xx.h | 2 ++ arch/arm/mach-omap2/clock44xx_data.c | 4 +--- arch/arm/mach-omap2/io.c | 15 +++++++++++++-- 9 files changed, 21 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index be5a55f57030..7bc344bcbb47 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -47,7 +47,6 @@ #define DPLL_LOW_POWER_BYPASS 0x5 #define DPLL_LOCKED 0x7 -int omap2_clk_init(void); int omap2_clk_enable(struct clk *clk); void omap2_clk_disable(struct clk *clk); long omap2_clk_round_rate(struct clk *clk, unsigned long rate); diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index bed294ac3647..32f3d0aa8fc4 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -19,6 +19,7 @@ unsigned long omap2xxx_clk_get_core_rate(struct clk *clk); u32 omap2xxx_get_apll_clkin(void); u32 omap2xxx_get_sysclkdiv(void); void omap2xxx_clk_prepare_for_reboot(void); +int omap2xxx_clk_init(void); /* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */ #ifdef CONFIG_ARCH_OMAP2420 diff --git a/arch/arm/mach-omap2/clock2xxx_data.c b/arch/arm/mach-omap2/clock2xxx_data.c index 3a435bb8f029..52c7a6c2d9e0 100644 --- a/arch/arm/mach-omap2/clock2xxx_data.c +++ b/arch/arm/mach-omap2/clock2xxx_data.c @@ -2238,7 +2238,7 @@ static struct omap_clk omap24xx_clks[] = { * init code */ -int __init omap2_clk_init(void) +int __init omap2xxx_clk_init(void) { const struct prcm_config *prcm; struct omap_clk *c; diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 34d395046280..1f1b5a6b3eea 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -150,7 +150,7 @@ int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) return omap3_noncore_dpll_set_rate(clk, rate); } -void omap3_clk_lock_dpll5(void) +void __init omap3_clk_lock_dpll5(void) { struct clk *dpll5_clk; struct clk *dpll5_m2_clk; diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index 9a2c07eac9ad..73f2109d6436 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -8,6 +8,7 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_34XX_H #define __ARCH_ARM_MACH_OMAP2_CLOCK_34XX_H +int omap3xxx_clk_init(void); int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate); int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate); void omap3_clk_lock_dpll5(void); diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c index 9e7f68a8fca2..0d04f92f63e1 100644 --- a/arch/arm/mach-omap2/clock34xx_data.c +++ b/arch/arm/mach-omap2/clock34xx_data.c @@ -3212,11 +3212,9 @@ static struct omap_clk omap3xxx_clks[] = { }; -int __init omap2_clk_init(void) +int __init omap3xxx_clk_init(void) { - /* struct prcm_config *prcm; */ struct omap_clk *c; - /* u32 clkrate; */ u32 cpu_clkflg = CK_3XXX; if (cpu_is_omap3517()) { @@ -3254,21 +3252,6 @@ int __init omap2_clk_init(void) omap2_init_clk_clkdm(c->lk.clk); } - /* REVISIT: Not yet ready for OMAP3 */ -#if 0 - /* Check the MPU rate set by bootloader */ - clkrate = omap2_get_dpll_rate_24xx(&dpll_ck); - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - if (prcm->xtal_speed != sys_ck.rate) - continue; - if (prcm->dpll_speed <= clkrate) - break; - } - curr_prcm_set = prcm; -#endif - recalculate_root_clocks(); printk(KERN_INFO "Clocking rate (Crystal/Core/MPU): " diff --git a/arch/arm/mach-omap2/clock44xx.h b/arch/arm/mach-omap2/clock44xx.h index 59b9ced4daa1..1f55b6b574fb 100644 --- a/arch/arm/mach-omap2/clock44xx.h +++ b/arch/arm/mach-omap2/clock44xx.h @@ -10,6 +10,8 @@ #define OMAP4430_MAX_DPLL_MULT 2048 #define OMAP4430_MAX_DPLL_DIV 128 +int omap4xxx_clk_init(void); + extern const struct clkops clkops_noncore_dpll_ops; #endif diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index ae9649f2973d..35ffe638def8 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -2726,11 +2726,9 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "utmi_p2_gfclk_ck", &utmi_p2_gfclk_ck, CK_443X), }; -int __init omap2_clk_init(void) +int __init omap4xxx_clk_init(void) { - /* struct prcm_config *prcm; */ struct omap_clk *c; - /* u32 clkrate; */ u32 cpu_clkflg; if (cpu_is_omap44xx()) { diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 8c58699083f6..01ef2ae93593 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -35,7 +35,9 @@ #include #include -#include "clock.h" +#include "clock2xxx.h" +#include "clock34xx.h" +#include "clock44xx.h" #include #include @@ -320,7 +322,16 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, omap2_mux_init(); omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps); #endif - omap2_clk_init(); + + if (cpu_is_omap24xx()) + omap2xxx_clk_init(); + else if (cpu_is_omap34xx()) + omap3xxx_clk_init(); + else if (cpu_is_omap44xx()) + omap4xxx_clk_init(); + else + pr_err("Could not init clock framework - unknown CPU\n"); + omap_serial_early_init(); #ifndef CONFIG_ARCH_OMAP4 omap_hwmod_late_init(); -- GitLab From 56ef28acf122d30b137851aa6a599ba48319a6b0 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 26 Jan 2010 20:13:12 -0700 Subject: [PATCH 1373/3892] OMAP4: PRCM: Define shift macros as n instead of 1 << n The macros defining the shift bits in registers for various register bit fields are defined as 1 << n. Instead define them as n. They can then be used as val << n. The changes are generated by updating the script which autogenerates the files modifed in the patch. Signed-off-by: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cm-regbits-44xx.h | 536 ++++++------- arch/arm/mach-omap2/prm-regbits-44xx.h | 1010 ++++++++++++------------ 2 files changed, 773 insertions(+), 773 deletions(-) diff --git a/arch/arm/mach-omap2/cm-regbits-44xx.h b/arch/arm/mach-omap2/cm-regbits-44xx.h index 0e67f75aa35c..ac8458e43252 100644 --- a/arch/arm/mach-omap2/cm-regbits-44xx.h +++ b/arch/arm/mach-omap2/cm-regbits-44xx.h @@ -26,7 +26,7 @@ /* Used by CM_L3_1_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */ -#define OMAP4430_ABE_DYNDEP_SHIFT (1 << 3) +#define OMAP4430_ABE_DYNDEP_SHIFT 3 #define OMAP4430_ABE_DYNDEP_MASK BITFIELD(3, 3) /* @@ -34,15 +34,15 @@ * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, * CM_TESLA_STATICDEP */ -#define OMAP4430_ABE_STATDEP_SHIFT (1 << 3) +#define OMAP4430_ABE_STATDEP_SHIFT 3 #define OMAP4430_ABE_STATDEP_MASK BITFIELD(3, 3) /* Used by CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_ALWONCORE_DYNDEP_SHIFT (1 << 16) +#define OMAP4430_ALWONCORE_DYNDEP_SHIFT 16 #define OMAP4430_ALWONCORE_DYNDEP_MASK BITFIELD(16, 16) /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_ALWONCORE_STATDEP_SHIFT (1 << 16) +#define OMAP4430_ALWONCORE_STATDEP_SHIFT 16 #define OMAP4430_ALWONCORE_STATDEP_MASK BITFIELD(16, 16) /* @@ -50,371 +50,371 @@ * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE, * CM_AUTOIDLE_DPLL_DDRPHY, CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU */ -#define OMAP4430_AUTO_DPLL_MODE_SHIFT (1 << 0) +#define OMAP4430_AUTO_DPLL_MODE_SHIFT 0 #define OMAP4430_AUTO_DPLL_MODE_MASK BITFIELD(0, 2) /* Used by CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_CEFUSE_DYNDEP_SHIFT (1 << 17) +#define OMAP4430_CEFUSE_DYNDEP_SHIFT 17 #define OMAP4430_CEFUSE_DYNDEP_MASK BITFIELD(17, 17) /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_CEFUSE_STATDEP_SHIFT (1 << 17) +#define OMAP4430_CEFUSE_STATDEP_SHIFT 17 #define OMAP4430_CEFUSE_STATDEP_MASK BITFIELD(17, 17) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_SHIFT (1 << 13) +#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_SHIFT 13 #define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK BITFIELD(13, 13) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_SHIFT (1 << 12) +#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_SHIFT 12 #define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK BITFIELD(12, 12) /* Used by CM_WKUP_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK BITFIELD(9, 9) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK BITFIELD(11, 11) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK BITFIELD(8, 8) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK BITFIELD(11, 11) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_SHIFT (1 << 12) +#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_SHIFT 12 #define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK BITFIELD(12, 12) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_SHIFT (1 << 13) +#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_SHIFT 13 #define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK BITFIELD(13, 13) /* Used by CM_CAM_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK BITFIELD(9, 9) /* Used by CM_EMU_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK BITFIELD(9, 9) /* Used by CM_CEFUSE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK BITFIELD(9, 9) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DLL_CLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_DLL_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_DLL_CLK_MASK BITFIELD(9, 9) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK BITFIELD(9, 9) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK BITFIELD(10, 10) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK BITFIELD(11, 11) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_SHIFT (1 << 12) +#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_SHIFT 12 #define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK BITFIELD(12, 12) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_SHIFT (1 << 13) +#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_SHIFT 13 #define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK BITFIELD(13, 13) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_SHIFT (1 << 14) +#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_SHIFT 14 #define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK BITFIELD(14, 14) /* Used by CM_DSS_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK BITFIELD(10, 10) /* Used by CM_DSS_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_DSS_FCLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_DSS_FCLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK BITFIELD(9, 9) /* Used by CM_DUCATI_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_MASK BITFIELD(10, 10) /* Used by CM_EMU_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK BITFIELD(8, 8) /* Used by CM_CAM_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK BITFIELD(10, 10) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_SHIFT (1 << 15) +#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_SHIFT 15 #define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK BITFIELD(15, 15) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK BITFIELD(10, 10) /* Used by CM_DSS_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK BITFIELD(11, 11) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_SHIFT (1 << 20) +#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_SHIFT 20 #define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK BITFIELD(20, 20) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_SHIFT (1 << 26) +#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_SHIFT 26 #define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK BITFIELD(26, 26) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_SHIFT (1 << 21) +#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_SHIFT 21 #define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK BITFIELD(21, 21) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_SHIFT (1 << 27) +#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_SHIFT 27 #define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK BITFIELD(27, 27) /* Used by CM_L3INIT_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_SHIFT (1 << 31) +#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_SHIFT 31 #define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_MASK BITFIELD(31, 31) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_SHIFT (1 << 13) +#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_SHIFT 13 #define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK BITFIELD(13, 13) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_SHIFT (1 << 12) +#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_SHIFT 12 #define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK BITFIELD(12, 12) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_SHIFT (1 << 28) +#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_SHIFT 28 #define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK BITFIELD(28, 28) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_SHIFT (1 << 29) +#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_SHIFT 29 #define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK BITFIELD(29, 29) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK BITFIELD(11, 11) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_SHIFT (1 << 16) +#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_SHIFT 16 #define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK BITFIELD(16, 16) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_SHIFT (1 << 17) +#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_SHIFT 17 #define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK BITFIELD(17, 17) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_SHIFT (1 << 18) +#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_SHIFT 18 #define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK BITFIELD(18, 18) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_SHIFT (1 << 19) +#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_SHIFT 19 #define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK BITFIELD(19, 19) /* Used by CM_CAM_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_ISS_GCLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_ISS_GCLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK BITFIELD(8, 8) /* Used by CM_IVAHD_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_SHIFT (1 << 14) +#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_SHIFT 14 #define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_MASK BITFIELD(14, 14) /* Used by CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L3_1_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_1_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L3_2_CLKSTCTRL, CM_L3_2_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L3_2_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_2_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK BITFIELD(8, 8) /* Used by CM_D2D_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK BITFIELD(8, 8) /* Used by CM_SDMA_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK BITFIELD(8, 8) /* Used by CM_DSS_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK BITFIELD(8, 8) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK BITFIELD(8, 8) /* Used by CM_GFX_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L3INSTR_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L4SEC_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK BITFIELD(8, 8) /* Used by CM_ALWON_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK BITFIELD(8, 8) /* Used by CM_CEFUSE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK BITFIELD(8, 8) /* Used by CM_D2D_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK BITFIELD(9, 9) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK BITFIELD(9, 9) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK BITFIELD(8, 8) /* Used by CM_L4SEC_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK BITFIELD(9, 9) /* Used by CM_WKUP_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_SHIFT (1 << 12) +#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_SHIFT 12 #define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK BITFIELD(12, 12) /* Used by CM_MPU_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK BITFIELD(8, 8) /* Used by CM1_ABE_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK BITFIELD(9, 9) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_SHIFT (1 << 16) +#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_SHIFT 16 #define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK BITFIELD(16, 16) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_SHIFT (1 << 17) +#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_SHIFT 17 #define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK BITFIELD(17, 17) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_SHIFT (1 << 18) +#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_SHIFT 18 #define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK BITFIELD(18, 18) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_SHIFT (1 << 19) +#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_SHIFT 19 #define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK BITFIELD(19, 19) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_SHIFT (1 << 25) +#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_SHIFT 25 #define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK BITFIELD(25, 25) /* Used by CM_EMU_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_MASK BITFIELD(10, 10) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_SHIFT (1 << 20) +#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_SHIFT 20 #define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK BITFIELD(20, 20) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_SHIFT (1 << 21) +#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_SHIFT 21 #define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK BITFIELD(21, 21) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_SHIFT (1 << 22) +#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_SHIFT 22 #define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK BITFIELD(22, 22) /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_SHIFT (1 << 24) +#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_SHIFT 24 #define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK BITFIELD(24, 24) /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK BITFIELD(10, 10) /* Used by CM_GFX_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_SGX_GFCLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_SGX_GFCLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK BITFIELD(9, 9) /* Used by CM_ALWON_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK BITFIELD(11, 11) /* Used by CM_ALWON_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK BITFIELD(10, 10) /* Used by CM_ALWON_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_SHIFT (1 << 9) +#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK BITFIELD(9, 9) /* Used by CM_WKUP_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_SYS_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_SYS_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_SYS_CLK_MASK BITFIELD(8, 8) /* Used by CM_TESLA_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_SHIFT (1 << 8) +#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_SHIFT 8 #define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_SHIFT (1 << 22) +#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_SHIFT 22 #define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK BITFIELD(22, 22) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_SHIFT (1 << 23) +#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_SHIFT 23 #define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK BITFIELD(23, 23) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_SHIFT (1 << 24) +#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_SHIFT 24 #define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK BITFIELD(24, 24) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_SHIFT (1 << 15) +#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_SHIFT 15 #define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK BITFIELD(15, 15) /* Used by CM_WKUP_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_USIM_GFCLK_SHIFT (1 << 10) +#define OMAP4430_CLKACTIVITY_USIM_GFCLK_SHIFT 10 #define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK BITFIELD(10, 10) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_SHIFT (1 << 30) +#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_SHIFT 30 #define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK BITFIELD(30, 30) /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_SHIFT (1 << 25) +#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_SHIFT 25 #define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK BITFIELD(25, 25) /* Used by CM_WKUP_CLKSTCTRL */ -#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT (1 << 11) +#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK BITFIELD(11, 11) /* @@ -426,7 +426,7 @@ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, * CM1_ABE_TIMER8_CLKCTRL */ -#define OMAP4430_CLKSEL_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_SHIFT 24 #define OMAP4430_CLKSEL_MASK BITFIELD(24, 24) /* @@ -434,43 +434,43 @@ * CM_DPLL_SYS_REF_CLKSEL, CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT, * CM_CLKSEL_USB_60MHZ */ -#define OMAP4430_CLKSEL_0_0_SHIFT (1 << 0) +#define OMAP4430_CLKSEL_0_0_SHIFT 0 #define OMAP4430_CLKSEL_0_0_MASK BITFIELD(0, 0) /* Renamed from CLKSEL Used by CM_BYPCLK_DPLL_IVA, CM_BYPCLK_DPLL_MPU */ -#define OMAP4430_CLKSEL_0_1_SHIFT (1 << 0) +#define OMAP4430_CLKSEL_0_1_SHIFT 0 #define OMAP4430_CLKSEL_0_1_MASK BITFIELD(0, 1) /* Renamed from CLKSEL Used by CM_L3INIT_HSI_CLKCTRL */ -#define OMAP4430_CLKSEL_24_25_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_24_25_SHIFT 24 #define OMAP4430_CLKSEL_24_25_MASK BITFIELD(24, 25) /* Used by CM_L3INIT_USB_OTG_CLKCTRL */ -#define OMAP4430_CLKSEL_60M_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_60M_SHIFT 24 #define OMAP4430_CLKSEL_60M_MASK BITFIELD(24, 24) /* Used by CM1_ABE_AESS_CLKCTRL */ -#define OMAP4430_CLKSEL_AESS_FCLK_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_AESS_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_AESS_FCLK_MASK BITFIELD(24, 24) /* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */ -#define OMAP4430_CLKSEL_CORE_SHIFT (1 << 0) +#define OMAP4430_CLKSEL_CORE_SHIFT 0 #define OMAP4430_CLKSEL_CORE_MASK BITFIELD(0, 0) /* Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2 */ -#define OMAP4430_CLKSEL_CORE_1_1_SHIFT (1 << 1) +#define OMAP4430_CLKSEL_CORE_1_1_SHIFT 1 #define OMAP4430_CLKSEL_CORE_1_1_MASK BITFIELD(1, 1) /* Used by CM_WKUP_USIM_CLKCTRL */ -#define OMAP4430_CLKSEL_DIV_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_DIV_SHIFT 24 #define OMAP4430_CLKSEL_DIV_MASK BITFIELD(24, 24) /* Used by CM_CAM_FDIF_CLKCTRL */ -#define OMAP4430_CLKSEL_FCLK_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_FCLK_MASK BITFIELD(24, 25) /* Used by CM_L4PER_MCBSP4_CLKCTRL */ -#define OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT (1 << 25) +#define OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT 25 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK BITFIELD(25, 25) /* @@ -478,58 +478,58 @@ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, * CM1_ABE_MCBSP3_CLKCTRL */ -#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_SHIFT (1 << 26) +#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_SHIFT 26 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK BITFIELD(26, 27) /* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */ -#define OMAP4430_CLKSEL_L3_SHIFT (1 << 4) +#define OMAP4430_CLKSEL_L3_SHIFT 4 #define OMAP4430_CLKSEL_L3_MASK BITFIELD(4, 4) /* Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2 */ -#define OMAP4430_CLKSEL_L3_SHADOW_SHIFT (1 << 2) +#define OMAP4430_CLKSEL_L3_SHADOW_SHIFT 2 #define OMAP4430_CLKSEL_L3_SHADOW_MASK BITFIELD(2, 2) /* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */ -#define OMAP4430_CLKSEL_L4_SHIFT (1 << 8) +#define OMAP4430_CLKSEL_L4_SHIFT 8 #define OMAP4430_CLKSEL_L4_MASK BITFIELD(8, 8) /* Used by CM_CLKSEL_ABE */ -#define OMAP4430_CLKSEL_OPP_SHIFT (1 << 0) +#define OMAP4430_CLKSEL_OPP_SHIFT 0 #define OMAP4430_CLKSEL_OPP_MASK BITFIELD(0, 1) /* Used by CM_GFX_GFX_CLKCTRL */ -#define OMAP4430_CLKSEL_PER_192M_SHIFT (1 << 25) +#define OMAP4430_CLKSEL_PER_192M_SHIFT 25 #define OMAP4430_CLKSEL_PER_192M_MASK BITFIELD(25, 26) /* Used by CM_EMU_DEBUGSS_CLKCTRL */ -#define OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT (1 << 27) +#define OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT 27 #define OMAP4430_CLKSEL_PMD_STM_CLK_MASK BITFIELD(27, 29) /* Used by CM_EMU_DEBUGSS_CLKCTRL */ -#define OMAP4430_CLKSEL_PMD_TRACE_CLK_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_PMD_TRACE_CLK_SHIFT 24 #define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK BITFIELD(24, 26) /* Used by CM_GFX_GFX_CLKCTRL */ -#define OMAP4430_CLKSEL_SGX_FCLK_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_SGX_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_SGX_FCLK_MASK BITFIELD(24, 24) /* * Used by CM1_ABE_DMIC_CLKCTRL, CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, * CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL */ -#define OMAP4430_CLKSEL_SOURCE_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_SOURCE_SHIFT 24 #define OMAP4430_CLKSEL_SOURCE_MASK BITFIELD(24, 25) /* Renamed from CLKSEL_SOURCE Used by CM_L4PER_MCBSP4_CLKCTRL */ -#define OMAP4430_CLKSEL_SOURCE_24_24_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_SOURCE_24_24_SHIFT 24 #define OMAP4430_CLKSEL_SOURCE_24_24_MASK BITFIELD(24, 24) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_CLKSEL_UTMI_P1_SHIFT (1 << 24) +#define OMAP4430_CLKSEL_UTMI_P1_SHIFT 24 #define OMAP4430_CLKSEL_UTMI_P1_MASK BITFIELD(24, 24) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_CLKSEL_UTMI_P2_SHIFT (1 << 25) +#define OMAP4430_CLKSEL_UTMI_P2_SHIFT 25 #define OMAP4430_CLKSEL_UTMI_P2_MASK BITFIELD(25, 25) /* @@ -544,23 +544,23 @@ * CM_IVAHD_CLKSTCTRL, CM_DSS_CLKSTCTRL, CM_MPU_CLKSTCTRL, CM_TESLA_CLKSTCTRL, * CM1_ABE_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE */ -#define OMAP4430_CLKTRCTRL_SHIFT (1 << 0) +#define OMAP4430_CLKTRCTRL_SHIFT 0 #define OMAP4430_CLKTRCTRL_MASK BITFIELD(0, 1) /* Used by CM_EMU_OVERRIDE_DPLL_CORE */ -#define OMAP4430_CORE_DPLL_EMU_DIV_SHIFT (1 << 0) +#define OMAP4430_CORE_DPLL_EMU_DIV_SHIFT 0 #define OMAP4430_CORE_DPLL_EMU_DIV_MASK BITFIELD(0, 6) /* Used by CM_EMU_OVERRIDE_DPLL_CORE */ -#define OMAP4430_CORE_DPLL_EMU_MULT_SHIFT (1 << 8) +#define OMAP4430_CORE_DPLL_EMU_MULT_SHIFT 8 #define OMAP4430_CORE_DPLL_EMU_MULT_MASK BITFIELD(8, 18) /* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_D2D_DYNDEP_SHIFT (1 << 18) +#define OMAP4430_D2D_DYNDEP_SHIFT 18 #define OMAP4430_D2D_DYNDEP_MASK BITFIELD(18, 18) /* Used by CM_MPU_STATICDEP */ -#define OMAP4430_D2D_STATDEP_SHIFT (1 << 18) +#define OMAP4430_D2D_STATDEP_SHIFT 18 #define OMAP4430_D2D_STATDEP_MASK BITFIELD(18, 18) /* @@ -570,19 +570,19 @@ * CM_SSC_DELTAMSTEP_DPLL_DDRPHY, CM_SSC_DELTAMSTEP_DPLL_IVA, * CM_SSC_DELTAMSTEP_DPLL_MPU */ -#define OMAP4430_DELTAMSTEP_SHIFT (1 << 0) +#define OMAP4430_DELTAMSTEP_SHIFT 0 #define OMAP4430_DELTAMSTEP_MASK BITFIELD(0, 19) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_DLL_OVERRIDE_SHIFT (1 << 2) +#define OMAP4430_DLL_OVERRIDE_SHIFT 2 #define OMAP4430_DLL_OVERRIDE_MASK BITFIELD(2, 2) /* Renamed from DLL_OVERRIDE Used by CM_DLL_CTRL */ -#define OMAP4430_DLL_OVERRIDE_0_0_SHIFT (1 << 0) +#define OMAP4430_DLL_OVERRIDE_0_0_SHIFT 0 #define OMAP4430_DLL_OVERRIDE_0_0_MASK BITFIELD(0, 0) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_DLL_RESET_SHIFT (1 << 3) +#define OMAP4430_DLL_RESET_SHIFT 3 #define OMAP4430_DLL_RESET_MASK BITFIELD(3, 3) /* @@ -590,40 +590,40 @@ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE, * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU */ -#define OMAP4430_DPLL_BYP_CLKSEL_SHIFT (1 << 23) +#define OMAP4430_DPLL_BYP_CLKSEL_SHIFT 23 #define OMAP4430_DPLL_BYP_CLKSEL_MASK BITFIELD(23, 23) /* Used by CM_CLKDCOLDO_DPLL_USB */ -#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT 8 #define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK BITFIELD(8, 8) /* Used by CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_CORE */ -#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_SHIFT (1 << 20) +#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_SHIFT 20 #define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK BITFIELD(20, 20) /* * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE, * CM_DIV_M3_DPLL_CORE */ -#define OMAP4430_DPLL_CLKOUTHIF_DIV_SHIFT (1 << 0) +#define OMAP4430_DPLL_CLKOUTHIF_DIV_SHIFT 0 #define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK BITFIELD(0, 4) /* * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE, * CM_DIV_M3_DPLL_CORE */ -#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_SHIFT 5 #define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK BITFIELD(5, 5) /* * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE, * CM_DIV_M3_DPLL_CORE */ -#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT 8 #define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK BITFIELD(8, 8) /* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */ -#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_SHIFT (1 << 10) +#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_SHIFT 10 #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BITFIELD(10, 10) /* @@ -631,11 +631,11 @@ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU */ -#define OMAP4430_DPLL_CLKOUT_DIV_SHIFT (1 << 0) +#define OMAP4430_DPLL_CLKOUT_DIV_SHIFT 0 #define OMAP4430_DPLL_CLKOUT_DIV_MASK BITFIELD(0, 4) /* Renamed from DPLL_CLKOUT_DIV Used by CM_DIV_M2_DPLL_USB */ -#define OMAP4430_DPLL_CLKOUT_DIV_0_6_SHIFT (1 << 0) +#define OMAP4430_DPLL_CLKOUT_DIV_0_6_SHIFT 0 #define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK BITFIELD(0, 6) /* @@ -643,11 +643,11 @@ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU */ -#define OMAP4430_DPLL_CLKOUT_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_DPLL_CLKOUT_DIVCHACK_SHIFT 5 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK BITFIELD(5, 5) /* Renamed from DPLL_CLKOUT_DIVCHACK Used by CM_DIV_M2_DPLL_USB */ -#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_SHIFT (1 << 7) +#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_SHIFT 7 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK BITFIELD(7, 7) /* @@ -655,23 +655,23 @@ * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY, * CM_DIV_M2_DPLL_MPU */ -#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT 8 #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BITFIELD(8, 8) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_DPLL_CORE_DPLL_EN_SHIFT (1 << 8) +#define OMAP4430_DPLL_CORE_DPLL_EN_SHIFT 8 #define OMAP4430_DPLL_CORE_DPLL_EN_MASK BITFIELD(8, 10) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_DPLL_CORE_M2_DIV_SHIFT (1 << 11) +#define OMAP4430_DPLL_CORE_M2_DIV_SHIFT 11 #define OMAP4430_DPLL_CORE_M2_DIV_MASK BITFIELD(11, 15) /* Used by CM_SHADOW_FREQ_CONFIG2 */ -#define OMAP4430_DPLL_CORE_M5_DIV_SHIFT (1 << 3) +#define OMAP4430_DPLL_CORE_M5_DIV_SHIFT 3 #define OMAP4430_DPLL_CORE_M5_DIV_MASK BITFIELD(3, 7) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_SHIFT (1 << 1) +#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_SHIFT 1 #define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_MASK BITFIELD(1, 1) /* @@ -679,11 +679,11 @@ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE, * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU */ -#define OMAP4430_DPLL_DIV_SHIFT (1 << 0) +#define OMAP4430_DPLL_DIV_SHIFT 0 #define OMAP4430_DPLL_DIV_MASK BITFIELD(0, 6) /* Renamed from DPLL_DIV Used by CM_CLKSEL_DPLL_USB */ -#define OMAP4430_DPLL_DIV_0_7_SHIFT (1 << 0) +#define OMAP4430_DPLL_DIV_0_7_SHIFT 0 #define OMAP4430_DPLL_DIV_0_7_MASK BITFIELD(0, 7) /* @@ -691,11 +691,11 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_DRIFTGUARD_EN_SHIFT (1 << 8) +#define OMAP4430_DPLL_DRIFTGUARD_EN_SHIFT 8 #define OMAP4430_DPLL_DRIFTGUARD_EN_MASK BITFIELD(8, 8) /* Renamed from DPLL_DRIFTGUARD_EN Used by CM_CLKMODE_DPLL_UNIPRO */ -#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_SHIFT (1 << 3) +#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_SHIFT 3 #define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK BITFIELD(3, 3) /* @@ -703,7 +703,7 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_EN_SHIFT (1 << 0) +#define OMAP4430_DPLL_EN_SHIFT 0 #define OMAP4430_DPLL_EN_MASK BITFIELD(0, 2) /* @@ -711,7 +711,7 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_LPMODE_EN_SHIFT (1 << 10) +#define OMAP4430_DPLL_LPMODE_EN_SHIFT 10 #define OMAP4430_DPLL_LPMODE_EN_MASK BITFIELD(10, 10) /* @@ -719,11 +719,11 @@ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE, * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU */ -#define OMAP4430_DPLL_MULT_SHIFT (1 << 8) +#define OMAP4430_DPLL_MULT_SHIFT 8 #define OMAP4430_DPLL_MULT_MASK BITFIELD(8, 18) /* Renamed from DPLL_MULT Used by CM_CLKSEL_DPLL_USB */ -#define OMAP4430_DPLL_MULT_USB_SHIFT (1 << 8) +#define OMAP4430_DPLL_MULT_USB_SHIFT 8 #define OMAP4430_DPLL_MULT_USB_MASK BITFIELD(8, 19) /* @@ -731,11 +731,11 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_REGM4XEN_SHIFT (1 << 11) +#define OMAP4430_DPLL_REGM4XEN_SHIFT 11 #define OMAP4430_DPLL_REGM4XEN_MASK BITFIELD(11, 11) /* Used by CM_CLKSEL_DPLL_USB */ -#define OMAP4430_DPLL_SD_DIV_SHIFT (1 << 24) +#define OMAP4430_DPLL_SD_DIV_SHIFT 24 #define OMAP4430_DPLL_SD_DIV_MASK BITFIELD(24, 31) /* @@ -743,7 +743,7 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_SSC_ACK_SHIFT (1 << 13) +#define OMAP4430_DPLL_SSC_ACK_SHIFT 13 #define OMAP4430_DPLL_SSC_ACK_MASK BITFIELD(13, 13) /* @@ -751,7 +751,7 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_SSC_DOWNSPREAD_SHIFT (1 << 14) +#define OMAP4430_DPLL_SSC_DOWNSPREAD_SHIFT 14 #define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK BITFIELD(14, 14) /* @@ -759,154 +759,154 @@ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE, * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU */ -#define OMAP4430_DPLL_SSC_EN_SHIFT (1 << 12) +#define OMAP4430_DPLL_SSC_EN_SHIFT 12 #define OMAP4430_DPLL_SSC_EN_MASK BITFIELD(12, 12) /* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */ -#define OMAP4430_DSS_DYNDEP_SHIFT (1 << 8) +#define OMAP4430_DSS_DYNDEP_SHIFT 8 #define OMAP4430_DSS_DYNDEP_MASK BITFIELD(8, 8) /* * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, * CM_MPU_STATICDEP */ -#define OMAP4430_DSS_STATDEP_SHIFT (1 << 8) +#define OMAP4430_DSS_STATDEP_SHIFT 8 #define OMAP4430_DSS_STATDEP_MASK BITFIELD(8, 8) /* Used by CM_L3_2_DYNAMICDEP */ -#define OMAP4430_DUCATI_DYNDEP_SHIFT (1 << 0) +#define OMAP4430_DUCATI_DYNDEP_SHIFT 0 #define OMAP4430_DUCATI_DYNDEP_MASK BITFIELD(0, 0) /* Used by CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP */ -#define OMAP4430_DUCATI_STATDEP_SHIFT (1 << 0) +#define OMAP4430_DUCATI_STATDEP_SHIFT 0 #define OMAP4430_DUCATI_STATDEP_MASK BITFIELD(0, 0) /* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */ -#define OMAP4430_FREQ_UPDATE_SHIFT (1 << 0) +#define OMAP4430_FREQ_UPDATE_SHIFT 0 #define OMAP4430_FREQ_UPDATE_MASK BITFIELD(0, 0) /* Used by CM_L3_2_DYNAMICDEP */ -#define OMAP4430_GFX_DYNDEP_SHIFT (1 << 10) +#define OMAP4430_GFX_DYNDEP_SHIFT 10 #define OMAP4430_GFX_DYNDEP_MASK BITFIELD(10, 10) /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */ -#define OMAP4430_GFX_STATDEP_SHIFT (1 << 10) +#define OMAP4430_GFX_STATDEP_SHIFT 10 #define OMAP4430_GFX_STATDEP_MASK BITFIELD(10, 10) /* Used by CM_SHADOW_FREQ_CONFIG2 */ -#define OMAP4430_GPMC_FREQ_UPDATE_SHIFT (1 << 0) +#define OMAP4430_GPMC_FREQ_UPDATE_SHIFT 0 #define OMAP4430_GPMC_FREQ_UPDATE_MASK BITFIELD(0, 0) /* * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE, * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_SHIFT (1 << 0) +#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_SHIFT 0 #define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK BITFIELD(0, 4) /* * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE, * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_SHIFT 5 #define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK BITFIELD(5, 5) /* * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE, * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_SHIFT 8 #define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK BITFIELD(8, 8) /* * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE, * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_SHIFT (1 << 12) +#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_SHIFT 12 #define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK BITFIELD(12, 12) /* * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE, * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_SHIFT (1 << 0) +#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_SHIFT 0 #define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK BITFIELD(0, 4) /* * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE, * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_SHIFT 5 #define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK BITFIELD(5, 5) /* * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE, * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_SHIFT 8 #define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK BITFIELD(8, 8) /* * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE, * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA */ -#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_SHIFT (1 << 12) +#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_SHIFT 12 #define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK BITFIELD(12, 12) /* * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE, * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY */ -#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_SHIFT (1 << 0) +#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_SHIFT 0 #define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK BITFIELD(0, 4) /* * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE, * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY */ -#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_SHIFT 5 #define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK BITFIELD(5, 5) /* * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE, * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY */ -#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_SHIFT 8 #define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK BITFIELD(8, 8) /* * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE, * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY */ -#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_SHIFT (1 << 12) +#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_SHIFT 12 #define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK BITFIELD(12, 12) /* * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE, * CM_DIV_M7_DPLL_CORE */ -#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_SHIFT (1 << 0) +#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_SHIFT 0 #define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK BITFIELD(0, 4) /* * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE, * CM_DIV_M7_DPLL_CORE */ -#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_SHIFT (1 << 5) +#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_SHIFT 5 #define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK BITFIELD(5, 5) /* * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE, * CM_DIV_M7_DPLL_CORE */ -#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_SHIFT (1 << 8) +#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_SHIFT 8 #define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK BITFIELD(8, 8) /* * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE, * CM_DIV_M7_DPLL_CORE */ -#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_SHIFT (1 << 12) +#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_SHIFT 12 #define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK BITFIELD(12, 12) /* @@ -962,22 +962,22 @@ * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL */ -#define OMAP4430_IDLEST_SHIFT (1 << 16) +#define OMAP4430_IDLEST_SHIFT 16 #define OMAP4430_IDLEST_MASK BITFIELD(16, 17) /* Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_ISS_DYNDEP_SHIFT (1 << 9) +#define OMAP4430_ISS_DYNDEP_SHIFT 9 #define OMAP4430_ISS_DYNDEP_MASK BITFIELD(9, 9) /* * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, * CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_ISS_STATDEP_SHIFT (1 << 9) +#define OMAP4430_ISS_STATDEP_SHIFT 9 #define OMAP4430_ISS_STATDEP_MASK BITFIELD(9, 9) /* Used by CM_L3_2_DYNAMICDEP, CM_TESLA_DYNAMICDEP */ -#define OMAP4430_IVAHD_DYNDEP_SHIFT (1 << 2) +#define OMAP4430_IVAHD_DYNDEP_SHIFT 2 #define OMAP4430_IVAHD_DYNDEP_MASK BITFIELD(2, 2) /* @@ -986,25 +986,25 @@ * CM_SDMA_STATICDEP_RESTORE, CM_DSS_STATICDEP, CM_MPU_STATICDEP, * CM_TESLA_STATICDEP */ -#define OMAP4430_IVAHD_STATDEP_SHIFT (1 << 2) +#define OMAP4430_IVAHD_STATDEP_SHIFT 2 #define OMAP4430_IVAHD_STATDEP_MASK BITFIELD(2, 2) /* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */ -#define OMAP4430_L3INIT_DYNDEP_SHIFT (1 << 7) +#define OMAP4430_L3INIT_DYNDEP_SHIFT 7 #define OMAP4430_L3INIT_DYNDEP_MASK BITFIELD(7, 7) /* * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_L3INIT_STATDEP_SHIFT (1 << 7) +#define OMAP4430_L3INIT_STATDEP_SHIFT 7 #define OMAP4430_L3INIT_STATDEP_MASK BITFIELD(7, 7) /* * Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, * CM_DSS_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */ -#define OMAP4430_L3_1_DYNDEP_SHIFT (1 << 5) +#define OMAP4430_L3_1_DYNDEP_SHIFT 5 #define OMAP4430_L3_1_DYNDEP_MASK BITFIELD(5, 5) /* @@ -1013,7 +1013,7 @@ * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP, * CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_L3_1_STATDEP_SHIFT (1 << 5) +#define OMAP4430_L3_1_STATDEP_SHIFT 5 #define OMAP4430_L3_1_STATDEP_MASK BITFIELD(5, 5) /* @@ -1022,7 +1022,7 @@ * CM_GFX_DYNAMICDEP, CM_L4SEC_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, * CM_CAM_DYNAMICDEP, CM_IVAHD_DYNAMICDEP */ -#define OMAP4430_L3_2_DYNDEP_SHIFT (1 << 6) +#define OMAP4430_L3_2_DYNDEP_SHIFT 6 #define OMAP4430_L3_2_DYNDEP_MASK BITFIELD(6, 6) /* @@ -1031,11 +1031,11 @@ * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP, * CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_L3_2_STATDEP_SHIFT (1 << 6) +#define OMAP4430_L3_2_STATDEP_SHIFT 6 #define OMAP4430_L3_2_STATDEP_MASK BITFIELD(6, 6) /* Used by CM_L3_1_DYNAMICDEP */ -#define OMAP4430_L4CFG_DYNDEP_SHIFT (1 << 12) +#define OMAP4430_L4CFG_DYNDEP_SHIFT 12 #define OMAP4430_L4CFG_DYNDEP_MASK BITFIELD(12, 12) /* @@ -1043,11 +1043,11 @@ * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, * CM_TESLA_STATICDEP */ -#define OMAP4430_L4CFG_STATDEP_SHIFT (1 << 12) +#define OMAP4430_L4CFG_STATDEP_SHIFT 12 #define OMAP4430_L4CFG_STATDEP_MASK BITFIELD(12, 12) /* Used by CM_L3_2_DYNAMICDEP */ -#define OMAP4430_L4PER_DYNDEP_SHIFT (1 << 13) +#define OMAP4430_L4PER_DYNDEP_SHIFT 13 #define OMAP4430_L4PER_DYNDEP_MASK BITFIELD(13, 13) /* @@ -1055,36 +1055,36 @@ * CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, * CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_L4PER_STATDEP_SHIFT (1 << 13) +#define OMAP4430_L4PER_STATDEP_SHIFT 13 #define OMAP4430_L4PER_STATDEP_MASK BITFIELD(13, 13) /* Used by CM_L3_2_DYNAMICDEP, CM_L4PER_DYNAMICDEP */ -#define OMAP4430_L4SEC_DYNDEP_SHIFT (1 << 14) +#define OMAP4430_L4SEC_DYNDEP_SHIFT 14 #define OMAP4430_L4SEC_DYNDEP_MASK BITFIELD(14, 14) /* * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP, * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP */ -#define OMAP4430_L4SEC_STATDEP_SHIFT (1 << 14) +#define OMAP4430_L4SEC_STATDEP_SHIFT 14 #define OMAP4430_L4SEC_STATDEP_MASK BITFIELD(14, 14) /* Used by CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_L4WKUP_DYNDEP_SHIFT (1 << 15) +#define OMAP4430_L4WKUP_DYNDEP_SHIFT 15 #define OMAP4430_L4WKUP_DYNDEP_MASK BITFIELD(15, 15) /* * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP, * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_L4WKUP_STATDEP_SHIFT (1 << 15) +#define OMAP4430_L4WKUP_STATDEP_SHIFT 15 #define OMAP4430_L4WKUP_STATDEP_MASK BITFIELD(15, 15) /* * Used by CM_D2D_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, * CM_MPU_DYNAMICDEP */ -#define OMAP4430_MEMIF_DYNDEP_SHIFT (1 << 4) +#define OMAP4430_MEMIF_DYNDEP_SHIFT 4 #define OMAP4430_MEMIF_DYNDEP_MASK BITFIELD(4, 4) /* @@ -1093,7 +1093,7 @@ * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP, * CM_MPU_STATICDEP, CM_TESLA_STATICDEP */ -#define OMAP4430_MEMIF_STATDEP_SHIFT (1 << 4) +#define OMAP4430_MEMIF_STATDEP_SHIFT 4 #define OMAP4430_MEMIF_STATDEP_MASK BITFIELD(4, 4) /* @@ -1103,7 +1103,7 @@ * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA, * CM_SSC_MODFREQDIV_DPLL_MPU */ -#define OMAP4430_MODFREQDIV_EXPONENT_SHIFT (1 << 8) +#define OMAP4430_MODFREQDIV_EXPONENT_SHIFT 8 #define OMAP4430_MODFREQDIV_EXPONENT_MASK BITFIELD(8, 10) /* @@ -1113,7 +1113,7 @@ * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA, * CM_SSC_MODFREQDIV_DPLL_MPU */ -#define OMAP4430_MODFREQDIV_MANTISSA_SHIFT (1 << 0) +#define OMAP4430_MODFREQDIV_MANTISSA_SHIFT 0 #define OMAP4430_MODFREQDIV_MANTISSA_MASK BITFIELD(0, 6) /* @@ -1169,23 +1169,23 @@ * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL */ -#define OMAP4430_MODULEMODE_SHIFT (1 << 0) +#define OMAP4430_MODULEMODE_SHIFT 0 #define OMAP4430_MODULEMODE_MASK BITFIELD(0, 1) /* Used by CM_DSS_DSS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK BITFIELD(9, 9) /* Used by CM_WKUP_BANDGAP_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT 8 #define OMAP4430_OPTFCLKEN_BGAP_32K_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT 9 #define OMAP4430_OPTFCLKEN_CLK32K_MASK BITFIELD(9, 9) /* Used by CM_CAM_ISS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_CTRLCLK_MASK BITFIELD(8, 8) /* @@ -1195,119 +1195,119 @@ * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE, * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_DBCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_DBCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_DBCLK_MASK BITFIELD(8, 8) /* Used by CM_MEMIF_DLL_CLKCTRL, CM_MEMIF_DLL_H_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_DLL_CLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_DLL_CLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_DLL_CLK_MASK BITFIELD(8, 8) /* Used by CM_DSS_DSS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_DSSCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_DSSCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_DSSCLK_MASK BITFIELD(8, 8) /* Used by CM1_ABE_SLIMBUS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_FCLK0_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_FCLK0_SHIFT 8 #define OMAP4430_OPTFCLKEN_FCLK0_MASK BITFIELD(8, 8) /* Used by CM1_ABE_SLIMBUS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_FCLK1_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_FCLK1_SHIFT 9 #define OMAP4430_OPTFCLKEN_FCLK1_MASK BITFIELD(9, 9) /* Used by CM1_ABE_SLIMBUS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_FCLK2_SHIFT (1 << 10) +#define OMAP4430_OPTFCLKEN_FCLK2_SHIFT 10 #define OMAP4430_OPTFCLKEN_FCLK2_MASK BITFIELD(10, 10) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT (1 << 15) +#define OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT 15 #define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK BITFIELD(15, 15) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT (1 << 13) +#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT 13 #define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK BITFIELD(13, 13) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT (1 << 14) +#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT 14 #define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK BITFIELD(14, 14) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT (1 << 11) +#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT 11 #define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK BITFIELD(11, 11) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT (1 << 12) +#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT 12 #define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK BITFIELD(12, 12) /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK BITFIELD(8, 8) /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK BITFIELD(9, 9) /* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_PHY_48M_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_PHY_48M_SHIFT 8 #define OMAP4430_OPTFCLKEN_PHY_48M_MASK BITFIELD(8, 8) /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT (1 << 10) +#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK BITFIELD(10, 10) /* Renamed from OPTFCLKEN_SLIMBUS_CLK Used by CM1_ABE_SLIMBUS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT (1 << 11) +#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT 11 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK BITFIELD(11, 11) /* Used by CM_DSS_DSS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT (1 << 10) +#define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_SYS_CLK_MASK BITFIELD(10, 10) /* Used by CM_DSS_DSS_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT (1 << 11) +#define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT 11 #define OMAP4430_OPTFCLKEN_TV_CLK_MASK BITFIELD(11, 11) /* Used by CM_L3INIT_UNIPRO1_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_TXPHYCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_TXPHYCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK BITFIELD(9, 9) /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT (1 << 10) +#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK BITFIELD(10, 10) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK BITFIELD(8, 8) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT (1 << 9) +#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK BITFIELD(9, 9) /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */ -#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT (1 << 10) +#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK BITFIELD(10, 10) /* Used by CM_L3INIT_USB_OTG_CLKCTRL */ -#define OMAP4430_OPTFCLKEN_XCLK_SHIFT (1 << 8) +#define OMAP4430_OPTFCLKEN_XCLK_SHIFT 8 #define OMAP4430_OPTFCLKEN_XCLK_MASK BITFIELD(8, 8) /* Used by CM_EMU_OVERRIDE_DPLL_PER, CM_EMU_OVERRIDE_DPLL_CORE */ -#define OMAP4430_OVERRIDE_ENABLE_SHIFT (1 << 19) +#define OMAP4430_OVERRIDE_ENABLE_SHIFT 19 #define OMAP4430_OVERRIDE_ENABLE_MASK BITFIELD(19, 19) /* Used by CM_CLKSEL_ABE */ -#define OMAP4430_PAD_CLKS_GATE_SHIFT (1 << 8) +#define OMAP4430_PAD_CLKS_GATE_SHIFT 8 #define OMAP4430_PAD_CLKS_GATE_MASK BITFIELD(8, 8) /* Used by CM_CORE_DVFS_CURRENT, CM_IVA_DVFS_CURRENT */ -#define OMAP4430_PERF_CURRENT_SHIFT (1 << 0) +#define OMAP4430_PERF_CURRENT_SHIFT 0 #define OMAP4430_PERF_CURRENT_MASK BITFIELD(0, 7) /* @@ -1315,66 +1315,66 @@ * CM_CORE_DVFS_PERF4, CM_IVA_DVFS_PERF_ABE, CM_IVA_DVFS_PERF_IVAHD, * CM_IVA_DVFS_PERF_TESLA */ -#define OMAP4430_PERF_REQ_SHIFT (1 << 0) +#define OMAP4430_PERF_REQ_SHIFT 0 #define OMAP4430_PERF_REQ_MASK BITFIELD(0, 7) /* Used by CM_EMU_OVERRIDE_DPLL_PER */ -#define OMAP4430_PER_DPLL_EMU_DIV_SHIFT (1 << 0) +#define OMAP4430_PER_DPLL_EMU_DIV_SHIFT 0 #define OMAP4430_PER_DPLL_EMU_DIV_MASK BITFIELD(0, 6) /* Used by CM_EMU_OVERRIDE_DPLL_PER */ -#define OMAP4430_PER_DPLL_EMU_MULT_SHIFT (1 << 8) +#define OMAP4430_PER_DPLL_EMU_MULT_SHIFT 8 #define OMAP4430_PER_DPLL_EMU_MULT_MASK BITFIELD(8, 18) /* Used by CM_RESTORE_ST */ -#define OMAP4430_PHASE1_COMPLETED_SHIFT (1 << 0) +#define OMAP4430_PHASE1_COMPLETED_SHIFT 0 #define OMAP4430_PHASE1_COMPLETED_MASK BITFIELD(0, 0) /* Used by CM_RESTORE_ST */ -#define OMAP4430_PHASE2A_COMPLETED_SHIFT (1 << 1) +#define OMAP4430_PHASE2A_COMPLETED_SHIFT 1 #define OMAP4430_PHASE2A_COMPLETED_MASK BITFIELD(1, 1) /* Used by CM_RESTORE_ST */ -#define OMAP4430_PHASE2B_COMPLETED_SHIFT (1 << 2) +#define OMAP4430_PHASE2B_COMPLETED_SHIFT 2 #define OMAP4430_PHASE2B_COMPLETED_MASK BITFIELD(2, 2) /* Used by CM_EMU_DEBUGSS_CLKCTRL */ -#define OMAP4430_PMD_STM_MUX_CTRL_SHIFT (1 << 20) +#define OMAP4430_PMD_STM_MUX_CTRL_SHIFT 20 #define OMAP4430_PMD_STM_MUX_CTRL_MASK BITFIELD(20, 21) /* Used by CM_EMU_DEBUGSS_CLKCTRL */ -#define OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT (1 << 22) +#define OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT 22 #define OMAP4430_PMD_TRACE_MUX_CTRL_MASK BITFIELD(22, 23) /* Used by CM_DYN_DEP_PRESCAL */ -#define OMAP4430_PRESCAL_SHIFT (1 << 0) +#define OMAP4430_PRESCAL_SHIFT 0 #define OMAP4430_PRESCAL_MASK BITFIELD(0, 5) /* Used by REVISION_CM2, REVISION_CM1 */ -#define OMAP4430_REV_SHIFT (1 << 0) +#define OMAP4430_REV_SHIFT 0 #define OMAP4430_REV_MASK BITFIELD(0, 7) /* * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL, * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */ -#define OMAP4430_SAR_MODE_SHIFT (1 << 4) +#define OMAP4430_SAR_MODE_SHIFT 4 #define OMAP4430_SAR_MODE_MASK BITFIELD(4, 4) /* Used by CM_SCALE_FCLK */ -#define OMAP4430_SCALE_FCLK_SHIFT (1 << 0) +#define OMAP4430_SCALE_FCLK_SHIFT 0 #define OMAP4430_SCALE_FCLK_MASK BITFIELD(0, 0) /* Used by CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_SDMA_DYNDEP_SHIFT (1 << 11) +#define OMAP4430_SDMA_DYNDEP_SHIFT 11 #define OMAP4430_SDMA_DYNDEP_MASK BITFIELD(11, 11) /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */ -#define OMAP4430_SDMA_STATDEP_SHIFT (1 << 11) +#define OMAP4430_SDMA_STATDEP_SHIFT 11 #define OMAP4430_SDMA_STATDEP_MASK BITFIELD(11, 11) /* Used by CM_CLKSEL_ABE */ -#define OMAP4430_SLIMBUS_CLK_GATE_SHIFT (1 << 10) +#define OMAP4430_SLIMBUS_CLK_GATE_SHIFT 10 #define OMAP4430_SLIMBUS_CLK_GATE_MASK BITFIELD(10, 10) /* @@ -1390,7 +1390,7 @@ * CM_IVAHD_IVAHD_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL */ -#define OMAP4430_STBYST_SHIFT (1 << 18) +#define OMAP4430_STBYST_SHIFT 18 #define OMAP4430_STBYST_MASK BITFIELD(18, 18) /* @@ -1398,11 +1398,11 @@ * CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY, * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU */ -#define OMAP4430_ST_DPLL_CLK_SHIFT (1 << 0) +#define OMAP4430_ST_DPLL_CLK_SHIFT 0 #define OMAP4430_ST_DPLL_CLK_MASK BITFIELD(0, 0) /* Used by CM_CLKDCOLDO_DPLL_USB */ -#define OMAP4430_ST_DPLL_CLKDCOLDO_SHIFT (1 << 9) +#define OMAP4430_ST_DPLL_CLKDCOLDO_SHIFT 9 #define OMAP4430_ST_DPLL_CLKDCOLDO_MASK BITFIELD(9, 9) /* @@ -1410,58 +1410,58 @@ * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY, * CM_DIV_M2_DPLL_MPU */ -#define OMAP4430_ST_DPLL_CLKOUT_SHIFT (1 << 9) +#define OMAP4430_ST_DPLL_CLKOUT_SHIFT 9 #define OMAP4430_ST_DPLL_CLKOUT_MASK BITFIELD(9, 9) /* * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE, * CM_DIV_M3_DPLL_CORE */ -#define OMAP4430_ST_DPLL_CLKOUTHIF_SHIFT (1 << 9) +#define OMAP4430_ST_DPLL_CLKOUTHIF_SHIFT 9 #define OMAP4430_ST_DPLL_CLKOUTHIF_MASK BITFIELD(9, 9) /* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */ -#define OMAP4430_ST_DPLL_CLKOUTX2_SHIFT (1 << 11) +#define OMAP4430_ST_DPLL_CLKOUTX2_SHIFT 11 #define OMAP4430_ST_DPLL_CLKOUTX2_MASK BITFIELD(11, 11) /* * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE, * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA */ -#define OMAP4430_ST_HSDIVIDER_CLKOUT1_SHIFT (1 << 9) +#define OMAP4430_ST_HSDIVIDER_CLKOUT1_SHIFT 9 #define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK BITFIELD(9, 9) /* * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE, * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA */ -#define OMAP4430_ST_HSDIVIDER_CLKOUT2_SHIFT (1 << 9) +#define OMAP4430_ST_HSDIVIDER_CLKOUT2_SHIFT 9 #define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK BITFIELD(9, 9) /* * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE, * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY */ -#define OMAP4430_ST_HSDIVIDER_CLKOUT3_SHIFT (1 << 9) +#define OMAP4430_ST_HSDIVIDER_CLKOUT3_SHIFT 9 #define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK BITFIELD(9, 9) /* * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE, * CM_DIV_M7_DPLL_CORE */ -#define OMAP4430_ST_HSDIVIDER_CLKOUT4_SHIFT (1 << 9) +#define OMAP4430_ST_HSDIVIDER_CLKOUT4_SHIFT 9 #define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK BITFIELD(9, 9) /* Used by CM_SYS_CLKSEL */ -#define OMAP4430_SYS_CLKSEL_SHIFT (1 << 0) +#define OMAP4430_SYS_CLKSEL_SHIFT 0 #define OMAP4430_SYS_CLKSEL_MASK BITFIELD(0, 2) /* Used by CM_L4CFG_DYNAMICDEP */ -#define OMAP4430_TESLA_DYNDEP_SHIFT (1 << 1) +#define OMAP4430_TESLA_DYNDEP_SHIFT 1 #define OMAP4430_TESLA_DYNDEP_MASK BITFIELD(1, 1) /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */ -#define OMAP4430_TESLA_STATDEP_SHIFT (1 << 1) +#define OMAP4430_TESLA_STATDEP_SHIFT 1 #define OMAP4430_TESLA_STATDEP_MASK BITFIELD(1, 1) /* @@ -1469,6 +1469,6 @@ * CM_L3_1_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, * CM_L4PER_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */ -#define OMAP4430_WINDOWSIZE_SHIFT (1 << 24) +#define OMAP4430_WINDOWSIZE_SHIFT 24 #define OMAP4430_WINDOWSIZE_MASK BITFIELD(24, 27) #endif diff --git a/arch/arm/mach-omap2/prm-regbits-44xx.h b/arch/arm/mach-omap2/prm-regbits-44xx.h index 301c810fb269..597be4a2b9ff 100644 --- a/arch/arm/mach-omap2/prm-regbits-44xx.h +++ b/arch/arm/mach-omap2/prm-regbits-44xx.h @@ -29,412 +29,412 @@ * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ABBOFF_ACT_EXPORT_SHIFT (1 << 1) +#define OMAP4430_ABBOFF_ACT_EXPORT_SHIFT 1 #define OMAP4430_ABBOFF_ACT_EXPORT_MASK BITFIELD(1, 1) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ABBOFF_SLEEP_EXPORT_SHIFT (1 << 2) +#define OMAP4430_ABBOFF_SLEEP_EXPORT_SHIFT 2 #define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK BITFIELD(2, 2) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_ABB_IVA_DONE_EN_SHIFT (1 << 31) +#define OMAP4430_ABB_IVA_DONE_EN_SHIFT 31 #define OMAP4430_ABB_IVA_DONE_EN_MASK BITFIELD(31, 31) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_ABB_IVA_DONE_ST_SHIFT (1 << 31) +#define OMAP4430_ABB_IVA_DONE_ST_SHIFT 31 #define OMAP4430_ABB_IVA_DONE_ST_MASK BITFIELD(31, 31) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_ABB_MPU_DONE_EN_SHIFT (1 << 7) +#define OMAP4430_ABB_MPU_DONE_EN_SHIFT 7 #define OMAP4430_ABB_MPU_DONE_EN_MASK BITFIELD(7, 7) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_ABB_MPU_DONE_ST_SHIFT (1 << 7) +#define OMAP4430_ABB_MPU_DONE_ST_SHIFT 7 #define OMAP4430_ABB_MPU_DONE_ST_MASK BITFIELD(7, 7) /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */ -#define OMAP4430_ACTIVE_FBB_SEL_SHIFT (1 << 2) +#define OMAP4430_ACTIVE_FBB_SEL_SHIFT 2 #define OMAP4430_ACTIVE_FBB_SEL_MASK BITFIELD(2, 2) /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */ -#define OMAP4430_ACTIVE_RBB_SEL_SHIFT (1 << 1) +#define OMAP4430_ACTIVE_RBB_SEL_SHIFT 1 #define OMAP4430_ACTIVE_RBB_SEL_MASK BITFIELD(1, 1) /* Used by PM_ABE_PWRSTCTRL */ -#define OMAP4430_AESSMEM_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_AESSMEM_ONSTATE_SHIFT 16 #define OMAP4430_AESSMEM_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_ABE_PWRSTCTRL */ -#define OMAP4430_AESSMEM_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_AESSMEM_RETSTATE_SHIFT 8 #define OMAP4430_AESSMEM_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_ABE_PWRSTST */ -#define OMAP4430_AESSMEM_STATEST_SHIFT (1 << 4) +#define OMAP4430_AESSMEM_STATEST_SHIFT 4 #define OMAP4430_AESSMEM_STATEST_MASK BITFIELD(4, 5) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_AIPOFF_SHIFT (1 << 8) +#define OMAP4430_AIPOFF_SHIFT 8 #define OMAP4430_AIPOFF_MASK BITFIELD(8, 8) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT (1 << 0) +#define OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT 0 #define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK BITFIELD(0, 1) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT (1 << 4) +#define OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT 4 #define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK BITFIELD(4, 5) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT (1 << 2) +#define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT 2 #define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK BITFIELD(2, 3) /* Used by PM_CAM_PWRSTCTRL */ -#define OMAP4430_CAM_MEM_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_CAM_MEM_ONSTATE_SHIFT 16 #define OMAP4430_CAM_MEM_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_CAM_PWRSTST */ -#define OMAP4430_CAM_MEM_STATEST_SHIFT (1 << 4) +#define OMAP4430_CAM_MEM_STATEST_SHIFT 4 #define OMAP4430_CAM_MEM_STATEST_MASK BITFIELD(4, 5) /* Used by PRM_CLKREQCTRL */ -#define OMAP4430_CLKREQ_COND_SHIFT (1 << 0) +#define OMAP4430_CLKREQ_COND_SHIFT 0 #define OMAP4430_CLKREQ_COND_MASK BITFIELD(0, 2) /* Used by PRM_VC_VAL_SMPS_RA_CMD */ -#define OMAP4430_CMDRA_VDD_CORE_L_SHIFT (1 << 0) +#define OMAP4430_CMDRA_VDD_CORE_L_SHIFT 0 #define OMAP4430_CMDRA_VDD_CORE_L_MASK BITFIELD(0, 7) /* Used by PRM_VC_VAL_SMPS_RA_CMD */ -#define OMAP4430_CMDRA_VDD_IVA_L_SHIFT (1 << 8) +#define OMAP4430_CMDRA_VDD_IVA_L_SHIFT 8 #define OMAP4430_CMDRA_VDD_IVA_L_MASK BITFIELD(8, 15) /* Used by PRM_VC_VAL_SMPS_RA_CMD */ -#define OMAP4430_CMDRA_VDD_MPU_L_SHIFT (1 << 16) +#define OMAP4430_CMDRA_VDD_MPU_L_SHIFT 16 #define OMAP4430_CMDRA_VDD_MPU_L_MASK BITFIELD(16, 23) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_CMD_VDD_CORE_L_SHIFT (1 << 4) +#define OMAP4430_CMD_VDD_CORE_L_SHIFT 4 #define OMAP4430_CMD_VDD_CORE_L_MASK BITFIELD(4, 4) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_CMD_VDD_IVA_L_SHIFT (1 << 12) +#define OMAP4430_CMD_VDD_IVA_L_SHIFT 12 #define OMAP4430_CMD_VDD_IVA_L_MASK BITFIELD(12, 12) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_CMD_VDD_MPU_L_SHIFT (1 << 17) +#define OMAP4430_CMD_VDD_MPU_L_SHIFT 17 #define OMAP4430_CMD_VDD_MPU_L_MASK BITFIELD(17, 17) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_CORE_OCMRAM_ONSTATE_SHIFT (1 << 18) +#define OMAP4430_CORE_OCMRAM_ONSTATE_SHIFT 18 #define OMAP4430_CORE_OCMRAM_ONSTATE_MASK BITFIELD(18, 19) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_CORE_OCMRAM_RETSTATE_SHIFT (1 << 9) +#define OMAP4430_CORE_OCMRAM_RETSTATE_SHIFT 9 #define OMAP4430_CORE_OCMRAM_RETSTATE_MASK BITFIELD(9, 9) /* Used by PM_CORE_PWRSTST */ -#define OMAP4430_CORE_OCMRAM_STATEST_SHIFT (1 << 6) +#define OMAP4430_CORE_OCMRAM_STATEST_SHIFT 6 #define OMAP4430_CORE_OCMRAM_STATEST_MASK BITFIELD(6, 7) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_CORE_OTHER_BANK_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_CORE_OTHER_BANK_ONSTATE_SHIFT 16 #define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_CORE_OTHER_BANK_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_CORE_OTHER_BANK_RETSTATE_SHIFT 8 #define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_CORE_PWRSTST */ -#define OMAP4430_CORE_OTHER_BANK_STATEST_SHIFT (1 << 4) +#define OMAP4430_CORE_OTHER_BANK_STATEST_SHIFT 4 #define OMAP4430_CORE_OTHER_BANK_STATEST_MASK BITFIELD(4, 5) /* Used by PRM_VC_VAL_BYPASS */ -#define OMAP4430_DATA_SHIFT (1 << 16) +#define OMAP4430_DATA_SHIFT 16 #define OMAP4430_DATA_MASK BITFIELD(16, 23) /* Used by PRM_DEVICE_OFF_CTRL */ -#define OMAP4430_DEVICE_OFF_ENABLE_SHIFT (1 << 0) +#define OMAP4430_DEVICE_OFF_ENABLE_SHIFT 0 #define OMAP4430_DEVICE_OFF_ENABLE_MASK BITFIELD(0, 0) /* Used by PRM_VC_CFG_I2C_MODE */ -#define OMAP4430_DFILTEREN_SHIFT (1 << 6) +#define OMAP4430_DFILTEREN_SHIFT 6 #define OMAP4430_DFILTEREN_MASK BITFIELD(6, 6) /* Used by PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */ -#define OMAP4430_DPLL_ABE_RECAL_EN_SHIFT (1 << 4) +#define OMAP4430_DPLL_ABE_RECAL_EN_SHIFT 4 #define OMAP4430_DPLL_ABE_RECAL_EN_MASK BITFIELD(4, 4) /* Used by PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */ -#define OMAP4430_DPLL_ABE_RECAL_ST_SHIFT (1 << 4) +#define OMAP4430_DPLL_ABE_RECAL_ST_SHIFT 4 #define OMAP4430_DPLL_ABE_RECAL_ST_MASK BITFIELD(4, 4) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_CORE_RECAL_EN_SHIFT (1 << 0) +#define OMAP4430_DPLL_CORE_RECAL_EN_SHIFT 0 #define OMAP4430_DPLL_CORE_RECAL_EN_MASK BITFIELD(0, 0) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_CORE_RECAL_ST_SHIFT (1 << 0) +#define OMAP4430_DPLL_CORE_RECAL_ST_SHIFT 0 #define OMAP4430_DPLL_CORE_RECAL_ST_MASK BITFIELD(0, 0) /* Used by PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_DDRPHY_RECAL_EN_SHIFT (1 << 6) +#define OMAP4430_DPLL_DDRPHY_RECAL_EN_SHIFT 6 #define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK BITFIELD(6, 6) /* Used by PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_DDRPHY_RECAL_ST_SHIFT (1 << 6) +#define OMAP4430_DPLL_DDRPHY_RECAL_ST_SHIFT 6 #define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK BITFIELD(6, 6) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */ -#define OMAP4430_DPLL_IVA_RECAL_EN_SHIFT (1 << 2) +#define OMAP4430_DPLL_IVA_RECAL_EN_SHIFT 2 #define OMAP4430_DPLL_IVA_RECAL_EN_MASK BITFIELD(2, 2) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */ -#define OMAP4430_DPLL_IVA_RECAL_ST_SHIFT (1 << 2) +#define OMAP4430_DPLL_IVA_RECAL_ST_SHIFT 2 #define OMAP4430_DPLL_IVA_RECAL_ST_MASK BITFIELD(2, 2) /* Used by PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_MPU_RECAL_EN_SHIFT (1 << 1) +#define OMAP4430_DPLL_MPU_RECAL_EN_SHIFT 1 #define OMAP4430_DPLL_MPU_RECAL_EN_MASK BITFIELD(1, 1) /* Used by PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_MPU_RECAL_ST_SHIFT (1 << 1) +#define OMAP4430_DPLL_MPU_RECAL_ST_SHIFT 1 #define OMAP4430_DPLL_MPU_RECAL_ST_MASK BITFIELD(1, 1) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_PER_RECAL_EN_SHIFT (1 << 3) +#define OMAP4430_DPLL_PER_RECAL_EN_SHIFT 3 #define OMAP4430_DPLL_PER_RECAL_EN_MASK BITFIELD(3, 3) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_PER_RECAL_ST_SHIFT (1 << 3) +#define OMAP4430_DPLL_PER_RECAL_ST_SHIFT 3 #define OMAP4430_DPLL_PER_RECAL_ST_MASK BITFIELD(3, 3) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_UNIPRO_RECAL_EN_SHIFT (1 << 7) +#define OMAP4430_DPLL_UNIPRO_RECAL_EN_SHIFT 7 #define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK BITFIELD(7, 7) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_UNIPRO_RECAL_ST_SHIFT (1 << 7) +#define OMAP4430_DPLL_UNIPRO_RECAL_ST_SHIFT 7 #define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK BITFIELD(7, 7) /* Used by PRM_IRQENABLE_MPU */ -#define OMAP4430_DPLL_USB_RECAL_EN_SHIFT (1 << 5) +#define OMAP4430_DPLL_USB_RECAL_EN_SHIFT 5 #define OMAP4430_DPLL_USB_RECAL_EN_MASK BITFIELD(5, 5) /* Used by PRM_IRQSTATUS_MPU */ -#define OMAP4430_DPLL_USB_RECAL_ST_SHIFT (1 << 5) +#define OMAP4430_DPLL_USB_RECAL_ST_SHIFT 5 #define OMAP4430_DPLL_USB_RECAL_ST_MASK BITFIELD(5, 5) /* Used by PM_DSS_PWRSTCTRL */ -#define OMAP4430_DSS_MEM_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_DSS_MEM_ONSTATE_SHIFT 16 #define OMAP4430_DSS_MEM_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_DSS_PWRSTCTRL */ -#define OMAP4430_DSS_MEM_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_DSS_MEM_RETSTATE_SHIFT 8 #define OMAP4430_DSS_MEM_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_DSS_PWRSTST */ -#define OMAP4430_DSS_MEM_STATEST_SHIFT (1 << 4) +#define OMAP4430_DSS_MEM_STATEST_SHIFT 4 #define OMAP4430_DSS_MEM_STATEST_MASK BITFIELD(4, 5) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_DUCATI_L2RAM_ONSTATE_SHIFT (1 << 20) +#define OMAP4430_DUCATI_L2RAM_ONSTATE_SHIFT 20 #define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK BITFIELD(20, 21) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_DUCATI_L2RAM_RETSTATE_SHIFT (1 << 10) +#define OMAP4430_DUCATI_L2RAM_RETSTATE_SHIFT 10 #define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK BITFIELD(10, 10) /* Used by PM_CORE_PWRSTST */ -#define OMAP4430_DUCATI_L2RAM_STATEST_SHIFT (1 << 8) +#define OMAP4430_DUCATI_L2RAM_STATEST_SHIFT 8 #define OMAP4430_DUCATI_L2RAM_STATEST_MASK BITFIELD(8, 9) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_DUCATI_UNICACHE_ONSTATE_SHIFT (1 << 22) +#define OMAP4430_DUCATI_UNICACHE_ONSTATE_SHIFT 22 #define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK BITFIELD(22, 23) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_DUCATI_UNICACHE_RETSTATE_SHIFT (1 << 11) +#define OMAP4430_DUCATI_UNICACHE_RETSTATE_SHIFT 11 #define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK BITFIELD(11, 11) /* Used by PM_CORE_PWRSTST */ -#define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT (1 << 10) +#define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT 10 #define OMAP4430_DUCATI_UNICACHE_STATEST_MASK BITFIELD(10, 11) /* Used by RM_MPU_RSTST */ -#define OMAP4430_EMULATION_RST_SHIFT (1 << 0) +#define OMAP4430_EMULATION_RST_SHIFT 0 #define OMAP4430_EMULATION_RST_MASK BITFIELD(0, 0) /* Used by RM_DUCATI_RSTST */ -#define OMAP4430_EMULATION_RST1ST_SHIFT (1 << 3) +#define OMAP4430_EMULATION_RST1ST_SHIFT 3 #define OMAP4430_EMULATION_RST1ST_MASK BITFIELD(3, 3) /* Used by RM_DUCATI_RSTST */ -#define OMAP4430_EMULATION_RST2ST_SHIFT (1 << 4) +#define OMAP4430_EMULATION_RST2ST_SHIFT 4 #define OMAP4430_EMULATION_RST2ST_MASK BITFIELD(4, 4) /* Used by RM_IVAHD_RSTST */ -#define OMAP4430_EMULATION_SEQ1_RST1ST_SHIFT (1 << 3) +#define OMAP4430_EMULATION_SEQ1_RST1ST_SHIFT 3 #define OMAP4430_EMULATION_SEQ1_RST1ST_MASK BITFIELD(3, 3) /* Used by RM_IVAHD_RSTST */ -#define OMAP4430_EMULATION_SEQ2_RST2ST_SHIFT (1 << 4) +#define OMAP4430_EMULATION_SEQ2_RST2ST_SHIFT 4 #define OMAP4430_EMULATION_SEQ2_RST2ST_MASK BITFIELD(4, 4) /* Used by PM_EMU_PWRSTCTRL */ -#define OMAP4430_EMU_BANK_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_EMU_BANK_ONSTATE_SHIFT 16 #define OMAP4430_EMU_BANK_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_EMU_PWRSTST */ -#define OMAP4430_EMU_BANK_STATEST_SHIFT (1 << 4) +#define OMAP4430_EMU_BANK_STATEST_SHIFT 4 #define OMAP4430_EMU_BANK_STATEST_MASK BITFIELD(4, 5) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP */ -#define OMAP4430_ENABLE_RTA_EXPORT_SHIFT (1 << 0) +#define OMAP4430_ENABLE_RTA_EXPORT_SHIFT 0 #define OMAP4430_ENABLE_RTA_EXPORT_MASK BITFIELD(0, 0) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ENFUNC1_SHIFT (1 << 3) +#define OMAP4430_ENFUNC1_SHIFT 3 #define OMAP4430_ENFUNC1_MASK BITFIELD(3, 3) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ENFUNC3_SHIFT (1 << 5) +#define OMAP4430_ENFUNC3_SHIFT 5 #define OMAP4430_ENFUNC3_MASK BITFIELD(5, 5) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ENFUNC4_SHIFT (1 << 6) +#define OMAP4430_ENFUNC4_SHIFT 6 #define OMAP4430_ENFUNC4_MASK BITFIELD(6, 6) /* * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP, * PRM_LDO_SRAM_MPU_SETUP */ -#define OMAP4430_ENFUNC5_SHIFT (1 << 7) +#define OMAP4430_ENFUNC5_SHIFT 7 #define OMAP4430_ENFUNC5_MASK BITFIELD(7, 7) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_ERRORGAIN_SHIFT (1 << 16) +#define OMAP4430_ERRORGAIN_SHIFT 16 #define OMAP4430_ERRORGAIN_MASK BITFIELD(16, 23) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_ERROROFFSET_SHIFT (1 << 24) +#define OMAP4430_ERROROFFSET_SHIFT 24 #define OMAP4430_ERROROFFSET_MASK BITFIELD(24, 31) /* Used by PRM_RSTST */ -#define OMAP4430_EXTERNAL_WARM_RST_SHIFT (1 << 5) +#define OMAP4430_EXTERNAL_WARM_RST_SHIFT 5 #define OMAP4430_EXTERNAL_WARM_RST_MASK BITFIELD(5, 5) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_FORCEUPDATE_SHIFT (1 << 1) +#define OMAP4430_FORCEUPDATE_SHIFT 1 #define OMAP4430_FORCEUPDATE_MASK BITFIELD(1, 1) /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */ -#define OMAP4430_FORCEUPDATEWAIT_SHIFT (1 << 8) +#define OMAP4430_FORCEUPDATEWAIT_SHIFT 8 #define OMAP4430_FORCEUPDATEWAIT_MASK BITFIELD(8, 31) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_TESLA */ -#define OMAP4430_FORCEWKUP_EN_SHIFT (1 << 10) +#define OMAP4430_FORCEWKUP_EN_SHIFT 10 #define OMAP4430_FORCEWKUP_EN_MASK BITFIELD(10, 10) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_TESLA */ -#define OMAP4430_FORCEWKUP_ST_SHIFT (1 << 10) +#define OMAP4430_FORCEWKUP_ST_SHIFT 10 #define OMAP4430_FORCEWKUP_ST_MASK BITFIELD(10, 10) /* Used by PM_GFX_PWRSTCTRL */ -#define OMAP4430_GFX_MEM_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_GFX_MEM_ONSTATE_SHIFT 16 #define OMAP4430_GFX_MEM_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_GFX_PWRSTST */ -#define OMAP4430_GFX_MEM_STATEST_SHIFT (1 << 4) +#define OMAP4430_GFX_MEM_STATEST_SHIFT 4 #define OMAP4430_GFX_MEM_STATEST_MASK BITFIELD(4, 5) /* Used by PRM_RSTST */ -#define OMAP4430_GLOBAL_COLD_RST_SHIFT (1 << 0) +#define OMAP4430_GLOBAL_COLD_RST_SHIFT 0 #define OMAP4430_GLOBAL_COLD_RST_MASK BITFIELD(0, 0) /* Used by PRM_RSTST */ -#define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT (1 << 1) +#define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1 #define OMAP4430_GLOBAL_WARM_SW_RST_MASK BITFIELD(1, 1) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_GLOBAL_WUEN_SHIFT (1 << 16) +#define OMAP4430_GLOBAL_WUEN_SHIFT 16 #define OMAP4430_GLOBAL_WUEN_MASK BITFIELD(16, 16) /* Used by PRM_VC_CFG_I2C_MODE */ -#define OMAP4430_HSMCODE_SHIFT (1 << 0) +#define OMAP4430_HSMCODE_SHIFT 0 #define OMAP4430_HSMCODE_MASK BITFIELD(0, 2) /* Used by PRM_VC_CFG_I2C_MODE */ -#define OMAP4430_HSMODEEN_SHIFT (1 << 3) +#define OMAP4430_HSMODEEN_SHIFT 3 #define OMAP4430_HSMODEEN_MASK BITFIELD(3, 3) /* Used by PRM_VC_CFG_I2C_CLK */ -#define OMAP4430_HSSCLH_SHIFT (1 << 16) +#define OMAP4430_HSSCLH_SHIFT 16 #define OMAP4430_HSSCLH_MASK BITFIELD(16, 23) /* Used by PRM_VC_CFG_I2C_CLK */ -#define OMAP4430_HSSCLL_SHIFT (1 << 24) +#define OMAP4430_HSSCLL_SHIFT 24 #define OMAP4430_HSSCLL_MASK BITFIELD(24, 31) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_HWA_MEM_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_HWA_MEM_ONSTATE_SHIFT 16 #define OMAP4430_HWA_MEM_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_HWA_MEM_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_HWA_MEM_RETSTATE_SHIFT 8 #define OMAP4430_HWA_MEM_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_IVAHD_PWRSTST */ -#define OMAP4430_HWA_MEM_STATEST_SHIFT (1 << 4) +#define OMAP4430_HWA_MEM_STATEST_SHIFT 4 #define OMAP4430_HWA_MEM_STATEST_MASK BITFIELD(4, 5) /* Used by RM_MPU_RSTST */ -#define OMAP4430_ICECRUSHER_MPU_RST_SHIFT (1 << 1) +#define OMAP4430_ICECRUSHER_MPU_RST_SHIFT 1 #define OMAP4430_ICECRUSHER_MPU_RST_MASK BITFIELD(1, 1) /* Used by RM_DUCATI_RSTST */ -#define OMAP4430_ICECRUSHER_RST1ST_SHIFT (1 << 5) +#define OMAP4430_ICECRUSHER_RST1ST_SHIFT 5 #define OMAP4430_ICECRUSHER_RST1ST_MASK BITFIELD(5, 5) /* Used by RM_DUCATI_RSTST */ -#define OMAP4430_ICECRUSHER_RST2ST_SHIFT (1 << 6) +#define OMAP4430_ICECRUSHER_RST2ST_SHIFT 6 #define OMAP4430_ICECRUSHER_RST2ST_MASK BITFIELD(6, 6) /* Used by RM_IVAHD_RSTST */ -#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_SHIFT (1 << 5) +#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_SHIFT 5 #define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK BITFIELD(5, 5) /* Used by RM_IVAHD_RSTST */ -#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_SHIFT (1 << 6) +#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_SHIFT 6 #define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK BITFIELD(6, 6) /* Used by PRM_RSTST */ -#define OMAP4430_ICEPICK_RST_SHIFT (1 << 9) +#define OMAP4430_ICEPICK_RST_SHIFT 9 #define OMAP4430_ICEPICK_RST_MASK BITFIELD(9, 9) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_INITVDD_SHIFT (1 << 2) +#define OMAP4430_INITVDD_SHIFT 2 #define OMAP4430_INITVDD_MASK BITFIELD(2, 2) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_INITVOLTAGE_SHIFT (1 << 8) +#define OMAP4430_INITVOLTAGE_SHIFT 8 #define OMAP4430_INITVOLTAGE_MASK BITFIELD(8, 15) /* @@ -442,47 +442,47 @@ * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST, * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST */ -#define OMAP4430_INTRANSITION_SHIFT (1 << 20) +#define OMAP4430_INTRANSITION_SHIFT 20 #define OMAP4430_INTRANSITION_MASK BITFIELD(20, 20) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_IO_EN_SHIFT (1 << 9) +#define OMAP4430_IO_EN_SHIFT 9 #define OMAP4430_IO_EN_MASK BITFIELD(9, 9) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_IO_ON_STATUS_SHIFT (1 << 5) +#define OMAP4430_IO_ON_STATUS_SHIFT 5 #define OMAP4430_IO_ON_STATUS_MASK BITFIELD(5, 5) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_IO_ST_SHIFT (1 << 9) +#define OMAP4430_IO_ST_SHIFT 9 #define OMAP4430_IO_ST_MASK BITFIELD(9, 9) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_ISOCLK_OVERRIDE_SHIFT (1 << 0) +#define OMAP4430_ISOCLK_OVERRIDE_SHIFT 0 #define OMAP4430_ISOCLK_OVERRIDE_MASK BITFIELD(0, 0) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_ISOCLK_STATUS_SHIFT (1 << 1) +#define OMAP4430_ISOCLK_STATUS_SHIFT 1 #define OMAP4430_ISOCLK_STATUS_MASK BITFIELD(1, 1) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_ISOOVR_EXTEND_SHIFT (1 << 4) +#define OMAP4430_ISOOVR_EXTEND_SHIFT 4 #define OMAP4430_ISOOVR_EXTEND_MASK BITFIELD(4, 4) /* Used by PRM_IO_COUNT */ -#define OMAP4430_ISO_2_ON_TIME_SHIFT (1 << 0) +#define OMAP4430_ISO_2_ON_TIME_SHIFT 0 #define OMAP4430_ISO_2_ON_TIME_MASK BITFIELD(0, 7) /* Used by PM_L3INIT_PWRSTCTRL */ -#define OMAP4430_L3INIT_BANK1_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_L3INIT_BANK1_ONSTATE_SHIFT 16 #define OMAP4430_L3INIT_BANK1_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_L3INIT_PWRSTCTRL */ -#define OMAP4430_L3INIT_BANK1_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_L3INIT_BANK1_RETSTATE_SHIFT 8 #define OMAP4430_L3INIT_BANK1_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_L3INIT_PWRSTST */ -#define OMAP4430_L3INIT_BANK1_STATEST_SHIFT (1 << 4) +#define OMAP4430_L3INIT_BANK1_STATEST_SHIFT 4 #define OMAP4430_L3INIT_BANK1_STATEST_MASK BITFIELD(4, 5) /* @@ -490,7 +490,7 @@ * PM_MPU_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL, * PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_LOGICRETSTATE_SHIFT (1 << 2) +#define OMAP4430_LOGICRETSTATE_SHIFT 2 #define OMAP4430_LOGICRETSTATE_MASK BITFIELD(2, 2) /* @@ -498,7 +498,7 @@ * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST, * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST */ -#define OMAP4430_LOGICSTATEST_SHIFT (1 << 2) +#define OMAP4430_LOGICSTATEST_SHIFT 2 #define OMAP4430_LOGICSTATEST_MASK BITFIELD(2, 2) /* @@ -537,7 +537,7 @@ * RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT, * RM_TESLA_TESLA_CONTEXT, RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT */ -#define OMAP4430_LOSTCONTEXT_DFF_SHIFT (1 << 0) +#define OMAP4430_LOSTCONTEXT_DFF_SHIFT 0 #define OMAP4430_LOSTCONTEXT_DFF_MASK BITFIELD(0, 0) /* @@ -558,58 +558,58 @@ * RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT, RM_L4SEC_DES3DES_CONTEXT, * RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT, RM_TESLA_TESLA_CONTEXT */ -#define OMAP4430_LOSTCONTEXT_RFF_SHIFT (1 << 1) +#define OMAP4430_LOSTCONTEXT_RFF_SHIFT 1 #define OMAP4430_LOSTCONTEXT_RFF_MASK BITFIELD(1, 1) /* Used by RM_ABE_AESS_CONTEXT */ -#define OMAP4430_LOSTMEM_AESSMEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_AESSMEM_SHIFT 8 #define OMAP4430_LOSTMEM_AESSMEM_MASK BITFIELD(8, 8) /* Used by RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT */ -#define OMAP4430_LOSTMEM_CAM_MEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_CAM_MEM_SHIFT 8 #define OMAP4430_LOSTMEM_CAM_MEM_MASK BITFIELD(8, 8) /* Used by RM_L3INSTR_OCP_WP1_CONTEXT */ -#define OMAP4430_LOSTMEM_CORE_NRET_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_CORE_NRET_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK BITFIELD(8, 8) /* Renamed from LOSTMEM_CORE_NRET_BANK Used by RM_MEMIF_DMM_CONTEXT */ -#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_SHIFT (1 << 9) +#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_SHIFT 9 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK BITFIELD(9, 9) /* Used by RM_L3_2_OCMC_RAM_CONTEXT */ -#define OMAP4430_LOSTMEM_CORE_OCMRAM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_CORE_OCMRAM_SHIFT 8 #define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK BITFIELD(8, 8) /* * Used by RM_D2D_MODEM_ICR_CONTEXT, RM_MEMIF_DMM_CONTEXT, * RM_SDMA_SDMA_CONTEXT */ -#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK BITFIELD(8, 8) /* Used by RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT */ -#define OMAP4430_LOSTMEM_DSS_MEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_DSS_MEM_SHIFT 8 #define OMAP4430_LOSTMEM_DSS_MEM_MASK BITFIELD(8, 8) /* Used by RM_DUCATI_DUCATI_CONTEXT */ -#define OMAP4430_LOSTMEM_DUCATI_L2RAM_SHIFT (1 << 9) +#define OMAP4430_LOSTMEM_DUCATI_L2RAM_SHIFT 9 #define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK BITFIELD(9, 9) /* Used by RM_DUCATI_DUCATI_CONTEXT */ -#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_SHIFT 8 #define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK BITFIELD(8, 8) /* Used by RM_EMU_DEBUGSS_CONTEXT */ -#define OMAP4430_LOSTMEM_EMU_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_EMU_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_EMU_BANK_MASK BITFIELD(8, 8) /* Used by RM_GFX_GFX_CONTEXT */ -#define OMAP4430_LOSTMEM_GFX_MEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_GFX_MEM_SHIFT 8 #define OMAP4430_LOSTMEM_GFX_MEM_MASK BITFIELD(8, 8) /* Used by RM_IVAHD_IVAHD_CONTEXT */ -#define OMAP4430_LOSTMEM_HWA_MEM_SHIFT (1 << 10) +#define OMAP4430_LOSTMEM_HWA_MEM_SHIFT 10 #define OMAP4430_LOSTMEM_HWA_MEM_MASK BITFIELD(10, 10) /* @@ -619,19 +619,19 @@ * RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT, * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_XHPI_CONTEXT */ -#define OMAP4430_LOSTMEM_L3INIT_BANK1_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_L3INIT_BANK1_SHIFT 8 #define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK BITFIELD(8, 8) /* Used by RM_MPU_MPU_CONTEXT */ -#define OMAP4430_LOSTMEM_MPU_L1_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_MPU_L1_SHIFT 8 #define OMAP4430_LOSTMEM_MPU_L1_MASK BITFIELD(8, 8) /* Used by RM_MPU_MPU_CONTEXT */ -#define OMAP4430_LOSTMEM_MPU_L2_SHIFT (1 << 9) +#define OMAP4430_LOSTMEM_MPU_L2_SHIFT 9 #define OMAP4430_LOSTMEM_MPU_L2_MASK BITFIELD(9, 9) /* Used by RM_MPU_MPU_CONTEXT */ -#define OMAP4430_LOSTMEM_MPU_RAM_SHIFT (1 << 10) +#define OMAP4430_LOSTMEM_MPU_RAM_SHIFT 10 #define OMAP4430_LOSTMEM_MPU_RAM_MASK BITFIELD(10, 10) /* @@ -639,14 +639,14 @@ * RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT, * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT */ -#define OMAP4430_LOSTMEM_NONRETAINED_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_NONRETAINED_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK BITFIELD(8, 8) /* * Used by RM_ABE_DMIC_CONTEXT, RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT, * RM_ABE_MCBSP3_CONTEXT, RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT */ -#define OMAP4430_LOSTMEM_PERIHPMEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_PERIHPMEM_SHIFT 8 #define OMAP4430_LOSTMEM_PERIHPMEM_MASK BITFIELD(8, 8) /* @@ -654,35 +654,35 @@ * RM_L4PER_UART2_CONTEXT, RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT, * RM_L4SEC_CRYPTODMA_CONTEXT */ -#define OMAP4430_LOSTMEM_RETAINED_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_RETAINED_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_RETAINED_BANK_MASK BITFIELD(8, 8) /* Used by RM_IVAHD_SL2_CONTEXT */ -#define OMAP4430_LOSTMEM_SL2_MEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_SL2_MEM_SHIFT 8 #define OMAP4430_LOSTMEM_SL2_MEM_MASK BITFIELD(8, 8) /* Used by RM_IVAHD_IVAHD_CONTEXT */ -#define OMAP4430_LOSTMEM_TCM1_MEM_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_TCM1_MEM_SHIFT 8 #define OMAP4430_LOSTMEM_TCM1_MEM_MASK BITFIELD(8, 8) /* Used by RM_IVAHD_IVAHD_CONTEXT */ -#define OMAP4430_LOSTMEM_TCM2_MEM_SHIFT (1 << 9) +#define OMAP4430_LOSTMEM_TCM2_MEM_SHIFT 9 #define OMAP4430_LOSTMEM_TCM2_MEM_MASK BITFIELD(9, 9) /* Used by RM_TESLA_TESLA_CONTEXT */ -#define OMAP4430_LOSTMEM_TESLA_EDMA_SHIFT (1 << 10) +#define OMAP4430_LOSTMEM_TESLA_EDMA_SHIFT 10 #define OMAP4430_LOSTMEM_TESLA_EDMA_MASK BITFIELD(10, 10) /* Used by RM_TESLA_TESLA_CONTEXT */ -#define OMAP4430_LOSTMEM_TESLA_L1_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_TESLA_L1_SHIFT 8 #define OMAP4430_LOSTMEM_TESLA_L1_MASK BITFIELD(8, 8) /* Used by RM_TESLA_TESLA_CONTEXT */ -#define OMAP4430_LOSTMEM_TESLA_L2_SHIFT (1 << 9) +#define OMAP4430_LOSTMEM_TESLA_L2_SHIFT 9 #define OMAP4430_LOSTMEM_TESLA_L2_MASK BITFIELD(9, 9) /* Used by RM_WKUP_SARRAM_CONTEXT */ -#define OMAP4430_LOSTMEM_WKUP_BANK_SHIFT (1 << 8) +#define OMAP4430_LOSTMEM_WKUP_BANK_SHIFT 8 #define OMAP4430_LOSTMEM_WKUP_BANK_MASK BITFIELD(8, 8) /* @@ -690,164 +690,164 @@ * PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL, * PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_LOWPOWERSTATECHANGE_SHIFT (1 << 4) +#define OMAP4430_LOWPOWERSTATECHANGE_SHIFT 4 #define OMAP4430_LOWPOWERSTATECHANGE_MASK BITFIELD(4, 4) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_MEMORYCHANGE_SHIFT (1 << 3) +#define OMAP4430_MEMORYCHANGE_SHIFT 3 #define OMAP4430_MEMORYCHANGE_MASK BITFIELD(3, 3) /* Used by PRM_MODEM_IF_CTRL */ -#define OMAP4430_MODEM_READY_SHIFT (1 << 1) +#define OMAP4430_MODEM_READY_SHIFT 1 #define OMAP4430_MODEM_READY_MASK BITFIELD(1, 1) /* Used by PRM_MODEM_IF_CTRL */ -#define OMAP4430_MODEM_SHUTDOWN_IRQ_SHIFT (1 << 9) +#define OMAP4430_MODEM_SHUTDOWN_IRQ_SHIFT 9 #define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK BITFIELD(9, 9) /* Used by PRM_MODEM_IF_CTRL */ -#define OMAP4430_MODEM_SLEEP_ST_SHIFT (1 << 16) +#define OMAP4430_MODEM_SLEEP_ST_SHIFT 16 #define OMAP4430_MODEM_SLEEP_ST_MASK BITFIELD(16, 16) /* Used by PRM_MODEM_IF_CTRL */ -#define OMAP4430_MODEM_WAKE_IRQ_SHIFT (1 << 8) +#define OMAP4430_MODEM_WAKE_IRQ_SHIFT 8 #define OMAP4430_MODEM_WAKE_IRQ_MASK BITFIELD(8, 8) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_L1_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_MPU_L1_ONSTATE_SHIFT 16 #define OMAP4430_MPU_L1_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_L1_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_MPU_L1_RETSTATE_SHIFT 8 #define OMAP4430_MPU_L1_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_MPU_PWRSTST */ -#define OMAP4430_MPU_L1_STATEST_SHIFT (1 << 4) +#define OMAP4430_MPU_L1_STATEST_SHIFT 4 #define OMAP4430_MPU_L1_STATEST_MASK BITFIELD(4, 5) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_L2_ONSTATE_SHIFT (1 << 18) +#define OMAP4430_MPU_L2_ONSTATE_SHIFT 18 #define OMAP4430_MPU_L2_ONSTATE_MASK BITFIELD(18, 19) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_L2_RETSTATE_SHIFT (1 << 9) +#define OMAP4430_MPU_L2_RETSTATE_SHIFT 9 #define OMAP4430_MPU_L2_RETSTATE_MASK BITFIELD(9, 9) /* Used by PM_MPU_PWRSTST */ -#define OMAP4430_MPU_L2_STATEST_SHIFT (1 << 6) +#define OMAP4430_MPU_L2_STATEST_SHIFT 6 #define OMAP4430_MPU_L2_STATEST_MASK BITFIELD(6, 7) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_RAM_ONSTATE_SHIFT (1 << 20) +#define OMAP4430_MPU_RAM_ONSTATE_SHIFT 20 #define OMAP4430_MPU_RAM_ONSTATE_MASK BITFIELD(20, 21) /* Used by PM_MPU_PWRSTCTRL */ -#define OMAP4430_MPU_RAM_RETSTATE_SHIFT (1 << 10) +#define OMAP4430_MPU_RAM_RETSTATE_SHIFT 10 #define OMAP4430_MPU_RAM_RETSTATE_MASK BITFIELD(10, 10) /* Used by PM_MPU_PWRSTST */ -#define OMAP4430_MPU_RAM_STATEST_SHIFT (1 << 8) +#define OMAP4430_MPU_RAM_STATEST_SHIFT 8 #define OMAP4430_MPU_RAM_STATEST_MASK BITFIELD(8, 9) /* Used by PRM_RSTST */ -#define OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT (1 << 2) +#define OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT 2 #define OMAP4430_MPU_SECURITY_VIOL_RST_MASK BITFIELD(2, 2) /* Used by PRM_RSTST */ -#define OMAP4430_MPU_WDT_RST_SHIFT (1 << 3) +#define OMAP4430_MPU_WDT_RST_SHIFT 3 #define OMAP4430_MPU_WDT_RST_MASK BITFIELD(3, 3) /* Used by PM_L4PER_PWRSTCTRL */ -#define OMAP4430_NONRETAINED_BANK_ONSTATE_SHIFT (1 << 18) +#define OMAP4430_NONRETAINED_BANK_ONSTATE_SHIFT 18 #define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK BITFIELD(18, 19) /* Used by PM_L4PER_PWRSTCTRL */ -#define OMAP4430_NONRETAINED_BANK_RETSTATE_SHIFT (1 << 9) +#define OMAP4430_NONRETAINED_BANK_RETSTATE_SHIFT 9 #define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK BITFIELD(9, 9) /* Used by PM_L4PER_PWRSTST */ -#define OMAP4430_NONRETAINED_BANK_STATEST_SHIFT (1 << 6) +#define OMAP4430_NONRETAINED_BANK_STATEST_SHIFT 6 #define OMAP4430_NONRETAINED_BANK_STATEST_MASK BITFIELD(6, 7) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_OCP_NRET_BANK_ONSTATE_SHIFT (1 << 24) +#define OMAP4430_OCP_NRET_BANK_ONSTATE_SHIFT 24 #define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK BITFIELD(24, 25) /* Used by PM_CORE_PWRSTCTRL */ -#define OMAP4430_OCP_NRET_BANK_RETSTATE_SHIFT (1 << 12) +#define OMAP4430_OCP_NRET_BANK_RETSTATE_SHIFT 12 #define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK BITFIELD(12, 12) /* Used by PM_CORE_PWRSTST */ -#define OMAP4430_OCP_NRET_BANK_STATEST_SHIFT (1 << 12) +#define OMAP4430_OCP_NRET_BANK_STATEST_SHIFT 12 #define OMAP4430_OCP_NRET_BANK_STATEST_MASK BITFIELD(12, 13) /* * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L, * PRM_VC_VAL_CMD_VDD_MPU_L */ -#define OMAP4430_OFF_SHIFT (1 << 0) +#define OMAP4430_OFF_SHIFT 0 #define OMAP4430_OFF_MASK BITFIELD(0, 7) /* Used by PRM_LDO_BANDGAP_CTRL */ -#define OMAP4430_OFF_ENABLE_SHIFT (1 << 0) +#define OMAP4430_OFF_ENABLE_SHIFT 0 #define OMAP4430_OFF_ENABLE_MASK BITFIELD(0, 0) /* * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L, * PRM_VC_VAL_CMD_VDD_MPU_L */ -#define OMAP4430_ON_SHIFT (1 << 24) +#define OMAP4430_ON_SHIFT 24 #define OMAP4430_ON_MASK BITFIELD(24, 31) /* * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L, * PRM_VC_VAL_CMD_VDD_MPU_L */ -#define OMAP4430_ONLP_SHIFT (1 << 16) +#define OMAP4430_ONLP_SHIFT 16 #define OMAP4430_ONLP_MASK BITFIELD(16, 23) /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */ -#define OMAP4430_OPP_CHANGE_SHIFT (1 << 2) +#define OMAP4430_OPP_CHANGE_SHIFT 2 #define OMAP4430_OPP_CHANGE_MASK BITFIELD(2, 2) /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */ -#define OMAP4430_OPP_SEL_SHIFT (1 << 0) +#define OMAP4430_OPP_SEL_SHIFT 0 #define OMAP4430_OPP_SEL_MASK BITFIELD(0, 1) /* Used by PRM_SRAM_COUNT */ -#define OMAP4430_PCHARGECNT_VALUE_SHIFT (1 << 0) +#define OMAP4430_PCHARGECNT_VALUE_SHIFT 0 #define OMAP4430_PCHARGECNT_VALUE_MASK BITFIELD(0, 5) /* Used by PRM_PSCON_COUNT */ -#define OMAP4430_PCHARGE_TIME_SHIFT (1 << 0) +#define OMAP4430_PCHARGE_TIME_SHIFT 0 #define OMAP4430_PCHARGE_TIME_MASK BITFIELD(0, 7) /* Used by PM_ABE_PWRSTCTRL */ -#define OMAP4430_PERIPHMEM_ONSTATE_SHIFT (1 << 20) +#define OMAP4430_PERIPHMEM_ONSTATE_SHIFT 20 #define OMAP4430_PERIPHMEM_ONSTATE_MASK BITFIELD(20, 21) /* Used by PM_ABE_PWRSTCTRL */ -#define OMAP4430_PERIPHMEM_RETSTATE_SHIFT (1 << 10) +#define OMAP4430_PERIPHMEM_RETSTATE_SHIFT 10 #define OMAP4430_PERIPHMEM_RETSTATE_MASK BITFIELD(10, 10) /* Used by PM_ABE_PWRSTST */ -#define OMAP4430_PERIPHMEM_STATEST_SHIFT (1 << 8) +#define OMAP4430_PERIPHMEM_STATEST_SHIFT 8 #define OMAP4430_PERIPHMEM_STATEST_MASK BITFIELD(8, 9) /* Used by PRM_PHASE1_CNDP */ -#define OMAP4430_PHASE1_CNDP_SHIFT (1 << 0) +#define OMAP4430_PHASE1_CNDP_SHIFT 0 #define OMAP4430_PHASE1_CNDP_MASK BITFIELD(0, 31) /* Used by PRM_PHASE2A_CNDP */ -#define OMAP4430_PHASE2A_CNDP_SHIFT (1 << 0) +#define OMAP4430_PHASE2A_CNDP_SHIFT 0 #define OMAP4430_PHASE2A_CNDP_MASK BITFIELD(0, 31) /* Used by PRM_PHASE2B_CNDP */ -#define OMAP4430_PHASE2B_CNDP_SHIFT (1 << 0) +#define OMAP4430_PHASE2B_CNDP_SHIFT 0 #define OMAP4430_PHASE2B_CNDP_MASK BITFIELD(0, 31) /* Used by PRM_PSCON_COUNT */ -#define OMAP4430_PONOUT_2_PGOODIN_TIME_SHIFT (1 << 8) +#define OMAP4430_PONOUT_2_PGOODIN_TIME_SHIFT 8 #define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK BITFIELD(8, 15) /* @@ -856,7 +856,7 @@ * PM_CEFUSE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, * PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_POWERSTATE_SHIFT (1 << 0) +#define OMAP4430_POWERSTATE_SHIFT 0 #define OMAP4430_POWERSTATE_MASK BITFIELD(0, 1) /* @@ -864,35 +864,35 @@ * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST, * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST */ -#define OMAP4430_POWERSTATEST_SHIFT (1 << 0) +#define OMAP4430_POWERSTATEST_SHIFT 0 #define OMAP4430_POWERSTATEST_MASK BITFIELD(0, 1) /* Used by PRM_PWRREQCTRL */ -#define OMAP4430_PWRREQ_COND_SHIFT (1 << 0) +#define OMAP4430_PWRREQ_COND_SHIFT 0 #define OMAP4430_PWRREQ_COND_MASK BITFIELD(0, 1) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RACEN_VDD_CORE_L_SHIFT (1 << 3) +#define OMAP4430_RACEN_VDD_CORE_L_SHIFT 3 #define OMAP4430_RACEN_VDD_CORE_L_MASK BITFIELD(3, 3) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RACEN_VDD_IVA_L_SHIFT (1 << 11) +#define OMAP4430_RACEN_VDD_IVA_L_SHIFT 11 #define OMAP4430_RACEN_VDD_IVA_L_MASK BITFIELD(11, 11) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RACEN_VDD_MPU_L_SHIFT (1 << 20) +#define OMAP4430_RACEN_VDD_MPU_L_SHIFT 20 #define OMAP4430_RACEN_VDD_MPU_L_MASK BITFIELD(20, 20) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAC_VDD_CORE_L_SHIFT (1 << 2) +#define OMAP4430_RAC_VDD_CORE_L_SHIFT 2 #define OMAP4430_RAC_VDD_CORE_L_MASK BITFIELD(2, 2) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAC_VDD_IVA_L_SHIFT (1 << 10) +#define OMAP4430_RAC_VDD_IVA_L_SHIFT 10 #define OMAP4430_RAC_VDD_IVA_L_MASK BITFIELD(10, 10) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAC_VDD_MPU_L_SHIFT (1 << 19) +#define OMAP4430_RAC_VDD_MPU_L_SHIFT 19 #define OMAP4430_RAC_VDD_MPU_L_MASK BITFIELD(19, 19) /* @@ -900,7 +900,7 @@ * PRM_VOLTSETUP_IVA_OFF, PRM_VOLTSETUP_IVA_RET_SLEEP, PRM_VOLTSETUP_MPU_OFF, * PRM_VOLTSETUP_MPU_RET_SLEEP */ -#define OMAP4430_RAMP_DOWN_COUNT_SHIFT (1 << 16) +#define OMAP4430_RAMP_DOWN_COUNT_SHIFT 16 #define OMAP4430_RAMP_DOWN_COUNT_MASK BITFIELD(16, 21) /* @@ -908,7 +908,7 @@ * PRM_VOLTSETUP_IVA_OFF, PRM_VOLTSETUP_IVA_RET_SLEEP, PRM_VOLTSETUP_MPU_OFF, * PRM_VOLTSETUP_MPU_RET_SLEEP */ -#define OMAP4430_RAMP_DOWN_PRESCAL_SHIFT (1 << 24) +#define OMAP4430_RAMP_DOWN_PRESCAL_SHIFT 24 #define OMAP4430_RAMP_DOWN_PRESCAL_MASK BITFIELD(24, 25) /* @@ -916,7 +916,7 @@ * PRM_VOLTSETUP_IVA_OFF, PRM_VOLTSETUP_IVA_RET_SLEEP, PRM_VOLTSETUP_MPU_OFF, * PRM_VOLTSETUP_MPU_RET_SLEEP */ -#define OMAP4430_RAMP_UP_COUNT_SHIFT (1 << 0) +#define OMAP4430_RAMP_UP_COUNT_SHIFT 0 #define OMAP4430_RAMP_UP_COUNT_MASK BITFIELD(0, 5) /* @@ -924,1282 +924,1282 @@ * PRM_VOLTSETUP_IVA_OFF, PRM_VOLTSETUP_IVA_RET_SLEEP, PRM_VOLTSETUP_MPU_OFF, * PRM_VOLTSETUP_MPU_RET_SLEEP */ -#define OMAP4430_RAMP_UP_PRESCAL_SHIFT (1 << 8) +#define OMAP4430_RAMP_UP_PRESCAL_SHIFT 8 #define OMAP4430_RAMP_UP_PRESCAL_MASK BITFIELD(8, 9) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAV_VDD_CORE_L_SHIFT (1 << 1) +#define OMAP4430_RAV_VDD_CORE_L_SHIFT 1 #define OMAP4430_RAV_VDD_CORE_L_MASK BITFIELD(1, 1) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAV_VDD_IVA_L_SHIFT (1 << 9) +#define OMAP4430_RAV_VDD_IVA_L_SHIFT 9 #define OMAP4430_RAV_VDD_IVA_L_MASK BITFIELD(9, 9) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_RAV_VDD_MPU_L_SHIFT (1 << 18) +#define OMAP4430_RAV_VDD_MPU_L_SHIFT 18 #define OMAP4430_RAV_VDD_MPU_L_MASK BITFIELD(18, 18) /* Used by PRM_VC_VAL_BYPASS */ -#define OMAP4430_REGADDR_SHIFT (1 << 8) +#define OMAP4430_REGADDR_SHIFT 8 #define OMAP4430_REGADDR_MASK BITFIELD(8, 15) /* * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L, * PRM_VC_VAL_CMD_VDD_MPU_L */ -#define OMAP4430_RET_SHIFT (1 << 8) +#define OMAP4430_RET_SHIFT 8 #define OMAP4430_RET_MASK BITFIELD(8, 15) /* Used by PM_L4PER_PWRSTCTRL */ -#define OMAP4430_RETAINED_BANK_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_RETAINED_BANK_ONSTATE_SHIFT 16 #define OMAP4430_RETAINED_BANK_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_L4PER_PWRSTCTRL */ -#define OMAP4430_RETAINED_BANK_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_RETAINED_BANK_RETSTATE_SHIFT 8 #define OMAP4430_RETAINED_BANK_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_L4PER_PWRSTST */ -#define OMAP4430_RETAINED_BANK_STATEST_SHIFT (1 << 4) +#define OMAP4430_RETAINED_BANK_STATEST_SHIFT 4 #define OMAP4430_RETAINED_BANK_STATEST_MASK BITFIELD(4, 5) /* * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL, * PRM_LDO_SRAM_MPU_CTRL */ -#define OMAP4430_RETMODE_ENABLE_SHIFT (1 << 0) +#define OMAP4430_RETMODE_ENABLE_SHIFT 0 #define OMAP4430_RETMODE_ENABLE_MASK BITFIELD(0, 0) /* Used by REVISION_PRM */ -#define OMAP4430_REV_SHIFT (1 << 0) +#define OMAP4430_REV_SHIFT 0 #define OMAP4430_REV_MASK BITFIELD(0, 7) /* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */ -#define OMAP4430_RST1_SHIFT (1 << 0) +#define OMAP4430_RST1_SHIFT 0 #define OMAP4430_RST1_MASK BITFIELD(0, 0) /* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */ -#define OMAP4430_RST1ST_SHIFT (1 << 0) +#define OMAP4430_RST1ST_SHIFT 0 #define OMAP4430_RST1ST_MASK BITFIELD(0, 0) /* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */ -#define OMAP4430_RST2_SHIFT (1 << 1) +#define OMAP4430_RST2_SHIFT 1 #define OMAP4430_RST2_MASK BITFIELD(1, 1) /* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */ -#define OMAP4430_RST2ST_SHIFT (1 << 1) +#define OMAP4430_RST2ST_SHIFT 1 #define OMAP4430_RST2ST_MASK BITFIELD(1, 1) /* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL */ -#define OMAP4430_RST3_SHIFT (1 << 2) +#define OMAP4430_RST3_SHIFT 2 #define OMAP4430_RST3_MASK BITFIELD(2, 2) /* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST */ -#define OMAP4430_RST3ST_SHIFT (1 << 2) +#define OMAP4430_RST3ST_SHIFT 2 #define OMAP4430_RST3ST_MASK BITFIELD(2, 2) /* Used by PRM_RSTTIME */ -#define OMAP4430_RSTTIME1_SHIFT (1 << 0) +#define OMAP4430_RSTTIME1_SHIFT 0 #define OMAP4430_RSTTIME1_MASK BITFIELD(0, 9) /* Used by PRM_RSTTIME */ -#define OMAP4430_RSTTIME2_SHIFT (1 << 10) +#define OMAP4430_RSTTIME2_SHIFT 10 #define OMAP4430_RSTTIME2_MASK BITFIELD(10, 14) /* Used by PRM_RSTCTRL */ -#define OMAP4430_RST_GLOBAL_COLD_SW_SHIFT (1 << 1) +#define OMAP4430_RST_GLOBAL_COLD_SW_SHIFT 1 #define OMAP4430_RST_GLOBAL_COLD_SW_MASK BITFIELD(1, 1) /* Used by PRM_RSTCTRL */ -#define OMAP4430_RST_GLOBAL_WARM_SW_SHIFT (1 << 0) +#define OMAP4430_RST_GLOBAL_WARM_SW_SHIFT 0 #define OMAP4430_RST_GLOBAL_WARM_SW_MASK BITFIELD(0, 0) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_SA_VDD_CORE_L_SHIFT (1 << 0) +#define OMAP4430_SA_VDD_CORE_L_SHIFT 0 #define OMAP4430_SA_VDD_CORE_L_MASK BITFIELD(0, 0) /* Renamed from SA_VDD_CORE_L Used by PRM_VC_SMPS_SA */ -#define OMAP4430_SA_VDD_CORE_L_0_6_SHIFT (1 << 0) +#define OMAP4430_SA_VDD_CORE_L_0_6_SHIFT 0 #define OMAP4430_SA_VDD_CORE_L_0_6_MASK BITFIELD(0, 6) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_SA_VDD_IVA_L_SHIFT (1 << 8) +#define OMAP4430_SA_VDD_IVA_L_SHIFT 8 #define OMAP4430_SA_VDD_IVA_L_MASK BITFIELD(8, 8) /* Renamed from SA_VDD_IVA_L Used by PRM_VC_SMPS_SA */ -#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT (1 << 8) +#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT 8 #define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK BITFIELD(8, 14) /* Used by PRM_VC_CFG_CHANNEL */ -#define OMAP4430_SA_VDD_MPU_L_SHIFT (1 << 16) +#define OMAP4430_SA_VDD_MPU_L_SHIFT 16 #define OMAP4430_SA_VDD_MPU_L_MASK BITFIELD(16, 16) /* Renamed from SA_VDD_MPU_L Used by PRM_VC_SMPS_SA */ -#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT (1 << 16) +#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT 16 #define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK BITFIELD(16, 22) /* Used by PRM_VC_CFG_I2C_CLK */ -#define OMAP4430_SCLH_SHIFT (1 << 0) +#define OMAP4430_SCLH_SHIFT 0 #define OMAP4430_SCLH_MASK BITFIELD(0, 7) /* Used by PRM_VC_CFG_I2C_CLK */ -#define OMAP4430_SCLL_SHIFT (1 << 8) +#define OMAP4430_SCLL_SHIFT 8 #define OMAP4430_SCLL_MASK BITFIELD(8, 15) /* Used by PRM_RSTST */ -#define OMAP4430_SECURE_WDT_RST_SHIFT (1 << 4) +#define OMAP4430_SECURE_WDT_RST_SHIFT 4 #define OMAP4430_SECURE_WDT_RST_MASK BITFIELD(4, 4) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_SL2_MEM_ONSTATE_SHIFT (1 << 18) +#define OMAP4430_SL2_MEM_ONSTATE_SHIFT 18 #define OMAP4430_SL2_MEM_ONSTATE_MASK BITFIELD(18, 19) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_SL2_MEM_RETSTATE_SHIFT (1 << 9) +#define OMAP4430_SL2_MEM_RETSTATE_SHIFT 9 #define OMAP4430_SL2_MEM_RETSTATE_MASK BITFIELD(9, 9) /* Used by PM_IVAHD_PWRSTST */ -#define OMAP4430_SL2_MEM_STATEST_SHIFT (1 << 6) +#define OMAP4430_SL2_MEM_STATEST_SHIFT 6 #define OMAP4430_SL2_MEM_STATEST_MASK BITFIELD(6, 7) /* Used by PRM_VC_VAL_BYPASS */ -#define OMAP4430_SLAVEADDR_SHIFT (1 << 0) +#define OMAP4430_SLAVEADDR_SHIFT 0 #define OMAP4430_SLAVEADDR_MASK BITFIELD(0, 6) /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */ -#define OMAP4430_SLEEP_RBB_SEL_SHIFT (1 << 3) +#define OMAP4430_SLEEP_RBB_SEL_SHIFT 3 #define OMAP4430_SLEEP_RBB_SEL_MASK BITFIELD(3, 3) /* Used by PRM_SRAM_COUNT */ -#define OMAP4430_SLPCNT_VALUE_SHIFT (1 << 16) +#define OMAP4430_SLPCNT_VALUE_SHIFT 16 #define OMAP4430_SLPCNT_VALUE_MASK BITFIELD(16, 23) /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */ -#define OMAP4430_SMPSWAITTIMEMAX_SHIFT (1 << 8) +#define OMAP4430_SMPSWAITTIMEMAX_SHIFT 8 #define OMAP4430_SMPSWAITTIMEMAX_MASK BITFIELD(8, 23) /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */ -#define OMAP4430_SMPSWAITTIMEMIN_SHIFT (1 << 8) +#define OMAP4430_SMPSWAITTIMEMIN_SHIFT 8 #define OMAP4430_SMPSWAITTIMEMIN_MASK BITFIELD(8, 23) /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */ -#define OMAP4430_SR2EN_SHIFT (1 << 0) +#define OMAP4430_SR2EN_SHIFT 0 #define OMAP4430_SR2EN_MASK BITFIELD(0, 0) /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */ -#define OMAP4430_SR2_IN_TRANSITION_SHIFT (1 << 6) +#define OMAP4430_SR2_IN_TRANSITION_SHIFT 6 #define OMAP4430_SR2_IN_TRANSITION_MASK BITFIELD(6, 6) /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */ -#define OMAP4430_SR2_STATUS_SHIFT (1 << 3) +#define OMAP4430_SR2_STATUS_SHIFT 3 #define OMAP4430_SR2_STATUS_MASK BITFIELD(3, 4) /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */ -#define OMAP4430_SR2_WTCNT_VALUE_SHIFT (1 << 8) +#define OMAP4430_SR2_WTCNT_VALUE_SHIFT 8 #define OMAP4430_SR2_WTCNT_VALUE_MASK BITFIELD(8, 15) /* * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL, * PRM_LDO_SRAM_MPU_CTRL */ -#define OMAP4430_SRAMLDO_STATUS_SHIFT (1 << 8) +#define OMAP4430_SRAMLDO_STATUS_SHIFT 8 #define OMAP4430_SRAMLDO_STATUS_MASK BITFIELD(8, 8) /* * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL, * PRM_LDO_SRAM_MPU_CTRL */ -#define OMAP4430_SRAM_IN_TRANSITION_SHIFT (1 << 9) +#define OMAP4430_SRAM_IN_TRANSITION_SHIFT 9 #define OMAP4430_SRAM_IN_TRANSITION_MASK BITFIELD(9, 9) /* Used by PRM_VC_CFG_I2C_MODE */ -#define OMAP4430_SRMODEEN_SHIFT (1 << 4) +#define OMAP4430_SRMODEEN_SHIFT 4 #define OMAP4430_SRMODEEN_MASK BITFIELD(4, 4) /* Used by PRM_VOLTSETUP_WARMRESET */ -#define OMAP4430_STABLE_COUNT_SHIFT (1 << 0) +#define OMAP4430_STABLE_COUNT_SHIFT 0 #define OMAP4430_STABLE_COUNT_MASK BITFIELD(0, 5) /* Used by PRM_VOLTSETUP_WARMRESET */ -#define OMAP4430_STABLE_PRESCAL_SHIFT (1 << 8) +#define OMAP4430_STABLE_PRESCAL_SHIFT 8 #define OMAP4430_STABLE_PRESCAL_MASK BITFIELD(8, 9) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_TCM1_MEM_ONSTATE_SHIFT (1 << 20) +#define OMAP4430_TCM1_MEM_ONSTATE_SHIFT 20 #define OMAP4430_TCM1_MEM_ONSTATE_MASK BITFIELD(20, 21) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_TCM1_MEM_RETSTATE_SHIFT (1 << 10) +#define OMAP4430_TCM1_MEM_RETSTATE_SHIFT 10 #define OMAP4430_TCM1_MEM_RETSTATE_MASK BITFIELD(10, 10) /* Used by PM_IVAHD_PWRSTST */ -#define OMAP4430_TCM1_MEM_STATEST_SHIFT (1 << 8) +#define OMAP4430_TCM1_MEM_STATEST_SHIFT 8 #define OMAP4430_TCM1_MEM_STATEST_MASK BITFIELD(8, 9) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_TCM2_MEM_ONSTATE_SHIFT (1 << 22) +#define OMAP4430_TCM2_MEM_ONSTATE_SHIFT 22 #define OMAP4430_TCM2_MEM_ONSTATE_MASK BITFIELD(22, 23) /* Used by PM_IVAHD_PWRSTCTRL */ -#define OMAP4430_TCM2_MEM_RETSTATE_SHIFT (1 << 11) +#define OMAP4430_TCM2_MEM_RETSTATE_SHIFT 11 #define OMAP4430_TCM2_MEM_RETSTATE_MASK BITFIELD(11, 11) /* Used by PM_IVAHD_PWRSTST */ -#define OMAP4430_TCM2_MEM_STATEST_SHIFT (1 << 10) +#define OMAP4430_TCM2_MEM_STATEST_SHIFT 10 #define OMAP4430_TCM2_MEM_STATEST_MASK BITFIELD(10, 11) /* Used by RM_TESLA_RSTST */ -#define OMAP4430_TESLASS_EMU_RSTST_SHIFT (1 << 2) +#define OMAP4430_TESLASS_EMU_RSTST_SHIFT 2 #define OMAP4430_TESLASS_EMU_RSTST_MASK BITFIELD(2, 2) /* Used by RM_TESLA_RSTST */ -#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_SHIFT (1 << 3) +#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_SHIFT 3 #define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK BITFIELD(3, 3) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_EDMA_ONSTATE_SHIFT (1 << 20) +#define OMAP4430_TESLA_EDMA_ONSTATE_SHIFT 20 #define OMAP4430_TESLA_EDMA_ONSTATE_MASK BITFIELD(20, 21) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_EDMA_RETSTATE_SHIFT (1 << 10) +#define OMAP4430_TESLA_EDMA_RETSTATE_SHIFT 10 #define OMAP4430_TESLA_EDMA_RETSTATE_MASK BITFIELD(10, 10) /* Used by PM_TESLA_PWRSTST */ -#define OMAP4430_TESLA_EDMA_STATEST_SHIFT (1 << 8) +#define OMAP4430_TESLA_EDMA_STATEST_SHIFT 8 #define OMAP4430_TESLA_EDMA_STATEST_MASK BITFIELD(8, 9) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_L1_ONSTATE_SHIFT (1 << 16) +#define OMAP4430_TESLA_L1_ONSTATE_SHIFT 16 #define OMAP4430_TESLA_L1_ONSTATE_MASK BITFIELD(16, 17) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_L1_RETSTATE_SHIFT (1 << 8) +#define OMAP4430_TESLA_L1_RETSTATE_SHIFT 8 #define OMAP4430_TESLA_L1_RETSTATE_MASK BITFIELD(8, 8) /* Used by PM_TESLA_PWRSTST */ -#define OMAP4430_TESLA_L1_STATEST_SHIFT (1 << 4) +#define OMAP4430_TESLA_L1_STATEST_SHIFT 4 #define OMAP4430_TESLA_L1_STATEST_MASK BITFIELD(4, 5) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_L2_ONSTATE_SHIFT (1 << 18) +#define OMAP4430_TESLA_L2_ONSTATE_SHIFT 18 #define OMAP4430_TESLA_L2_ONSTATE_MASK BITFIELD(18, 19) /* Used by PM_TESLA_PWRSTCTRL */ -#define OMAP4430_TESLA_L2_RETSTATE_SHIFT (1 << 9) +#define OMAP4430_TESLA_L2_RETSTATE_SHIFT 9 #define OMAP4430_TESLA_L2_RETSTATE_MASK BITFIELD(9, 9) /* Used by PM_TESLA_PWRSTST */ -#define OMAP4430_TESLA_L2_STATEST_SHIFT (1 << 6) +#define OMAP4430_TESLA_L2_STATEST_SHIFT 6 #define OMAP4430_TESLA_L2_STATEST_MASK BITFIELD(6, 7) /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */ -#define OMAP4430_TIMEOUT_SHIFT (1 << 0) +#define OMAP4430_TIMEOUT_SHIFT 0 #define OMAP4430_TIMEOUT_MASK BITFIELD(0, 15) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_TIMEOUTEN_SHIFT (1 << 3) +#define OMAP4430_TIMEOUTEN_SHIFT 3 #define OMAP4430_TIMEOUTEN_MASK BITFIELD(3, 3) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_TRANSITION_EN_SHIFT (1 << 8) +#define OMAP4430_TRANSITION_EN_SHIFT 8 #define OMAP4430_TRANSITION_EN_MASK BITFIELD(8, 8) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_TRANSITION_ST_SHIFT (1 << 8) +#define OMAP4430_TRANSITION_ST_SHIFT 8 #define OMAP4430_TRANSITION_ST_MASK BITFIELD(8, 8) /* Used by PRM_VC_VAL_BYPASS */ -#define OMAP4430_VALID_SHIFT (1 << 24) +#define OMAP4430_VALID_SHIFT 24 #define OMAP4430_VALID_MASK BITFIELD(24, 24) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VC_BYPASSACK_EN_SHIFT (1 << 14) +#define OMAP4430_VC_BYPASSACK_EN_SHIFT 14 #define OMAP4430_VC_BYPASSACK_EN_MASK BITFIELD(14, 14) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VC_BYPASSACK_ST_SHIFT (1 << 14) +#define OMAP4430_VC_BYPASSACK_ST_SHIFT 14 #define OMAP4430_VC_BYPASSACK_ST_MASK BITFIELD(14, 14) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VC_IVA_VPACK_EN_SHIFT (1 << 30) +#define OMAP4430_VC_IVA_VPACK_EN_SHIFT 30 #define OMAP4430_VC_IVA_VPACK_EN_MASK BITFIELD(30, 30) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VC_IVA_VPACK_ST_SHIFT (1 << 30) +#define OMAP4430_VC_IVA_VPACK_ST_SHIFT 30 #define OMAP4430_VC_IVA_VPACK_ST_MASK BITFIELD(30, 30) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VC_MPU_VPACK_EN_SHIFT (1 << 6) +#define OMAP4430_VC_MPU_VPACK_EN_SHIFT 6 #define OMAP4430_VC_MPU_VPACK_EN_MASK BITFIELD(6, 6) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VC_MPU_VPACK_ST_SHIFT (1 << 6) +#define OMAP4430_VC_MPU_VPACK_ST_SHIFT 6 #define OMAP4430_VC_MPU_VPACK_ST_MASK BITFIELD(6, 6) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VC_RAERR_EN_SHIFT (1 << 12) +#define OMAP4430_VC_RAERR_EN_SHIFT 12 #define OMAP4430_VC_RAERR_EN_MASK BITFIELD(12, 12) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VC_RAERR_ST_SHIFT (1 << 12) +#define OMAP4430_VC_RAERR_ST_SHIFT 12 #define OMAP4430_VC_RAERR_ST_MASK BITFIELD(12, 12) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VC_SAERR_EN_SHIFT (1 << 11) +#define OMAP4430_VC_SAERR_EN_SHIFT 11 #define OMAP4430_VC_SAERR_EN_MASK BITFIELD(11, 11) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VC_SAERR_ST_SHIFT (1 << 11) +#define OMAP4430_VC_SAERR_ST_SHIFT 11 #define OMAP4430_VC_SAERR_ST_MASK BITFIELD(11, 11) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VC_TOERR_EN_SHIFT (1 << 13) +#define OMAP4430_VC_TOERR_EN_SHIFT 13 #define OMAP4430_VC_TOERR_EN_MASK BITFIELD(13, 13) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VC_TOERR_ST_SHIFT (1 << 13) +#define OMAP4430_VC_TOERR_ST_SHIFT 13 #define OMAP4430_VC_TOERR_ST_MASK BITFIELD(13, 13) /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */ -#define OMAP4430_VDDMAX_SHIFT (1 << 24) +#define OMAP4430_VDDMAX_SHIFT 24 #define OMAP4430_VDDMAX_MASK BITFIELD(24, 31) /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */ -#define OMAP4430_VDDMIN_SHIFT (1 << 16) +#define OMAP4430_VDDMIN_SHIFT 16 #define OMAP4430_VDDMIN_MASK BITFIELD(16, 23) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_VDD_CORE_I2C_DISABLE_SHIFT (1 << 12) +#define OMAP4430_VDD_CORE_I2C_DISABLE_SHIFT 12 #define OMAP4430_VDD_CORE_I2C_DISABLE_MASK BITFIELD(12, 12) /* Used by PRM_RSTST */ -#define OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT (1 << 8) +#define OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT 8 #define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK BITFIELD(8, 8) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_VDD_IVA_I2C_DISABLE_SHIFT (1 << 14) +#define OMAP4430_VDD_IVA_I2C_DISABLE_SHIFT 14 #define OMAP4430_VDD_IVA_I2C_DISABLE_MASK BITFIELD(14, 14) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_VDD_IVA_PRESENCE_SHIFT (1 << 9) +#define OMAP4430_VDD_IVA_PRESENCE_SHIFT 9 #define OMAP4430_VDD_IVA_PRESENCE_MASK BITFIELD(9, 9) /* Used by PRM_RSTST */ -#define OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT (1 << 7) +#define OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT 7 #define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK BITFIELD(7, 7) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_VDD_MPU_I2C_DISABLE_SHIFT (1 << 13) +#define OMAP4430_VDD_MPU_I2C_DISABLE_SHIFT 13 #define OMAP4430_VDD_MPU_I2C_DISABLE_MASK BITFIELD(13, 13) /* Used by PRM_VOLTCTRL */ -#define OMAP4430_VDD_MPU_PRESENCE_SHIFT (1 << 8) +#define OMAP4430_VDD_MPU_PRESENCE_SHIFT 8 #define OMAP4430_VDD_MPU_PRESENCE_MASK BITFIELD(8, 8) /* Used by PRM_RSTST */ -#define OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT (1 << 6) +#define OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT 6 #define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK BITFIELD(6, 6) /* Used by PRM_VC_VAL_SMPS_RA_VOL */ -#define OMAP4430_VOLRA_VDD_CORE_L_SHIFT (1 << 0) +#define OMAP4430_VOLRA_VDD_CORE_L_SHIFT 0 #define OMAP4430_VOLRA_VDD_CORE_L_MASK BITFIELD(0, 7) /* Used by PRM_VC_VAL_SMPS_RA_VOL */ -#define OMAP4430_VOLRA_VDD_IVA_L_SHIFT (1 << 8) +#define OMAP4430_VOLRA_VDD_IVA_L_SHIFT 8 #define OMAP4430_VOLRA_VDD_IVA_L_MASK BITFIELD(8, 15) /* Used by PRM_VC_VAL_SMPS_RA_VOL */ -#define OMAP4430_VOLRA_VDD_MPU_L_SHIFT (1 << 16) +#define OMAP4430_VOLRA_VDD_MPU_L_SHIFT 16 #define OMAP4430_VOLRA_VDD_MPU_L_MASK BITFIELD(16, 23) /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */ -#define OMAP4430_VPENABLE_SHIFT (1 << 0) +#define OMAP4430_VPENABLE_SHIFT 0 #define OMAP4430_VPENABLE_MASK BITFIELD(0, 0) /* Used by PRM_VP_CORE_STATUS, PRM_VP_IVA_STATUS, PRM_VP_MPU_STATUS */ -#define OMAP4430_VPINIDLE_SHIFT (1 << 0) +#define OMAP4430_VPINIDLE_SHIFT 0 #define OMAP4430_VPINIDLE_MASK BITFIELD(0, 0) /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */ -#define OMAP4430_VPVOLTAGE_SHIFT (1 << 0) +#define OMAP4430_VPVOLTAGE_SHIFT 0 #define OMAP4430_VPVOLTAGE_MASK BITFIELD(0, 7) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_EQVALUE_EN_SHIFT (1 << 20) +#define OMAP4430_VP_CORE_EQVALUE_EN_SHIFT 20 #define OMAP4430_VP_CORE_EQVALUE_EN_MASK BITFIELD(20, 20) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_EQVALUE_ST_SHIFT (1 << 20) +#define OMAP4430_VP_CORE_EQVALUE_ST_SHIFT 20 #define OMAP4430_VP_CORE_EQVALUE_ST_MASK BITFIELD(20, 20) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_MAXVDD_EN_SHIFT (1 << 18) +#define OMAP4430_VP_CORE_MAXVDD_EN_SHIFT 18 #define OMAP4430_VP_CORE_MAXVDD_EN_MASK BITFIELD(18, 18) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_MAXVDD_ST_SHIFT (1 << 18) +#define OMAP4430_VP_CORE_MAXVDD_ST_SHIFT 18 #define OMAP4430_VP_CORE_MAXVDD_ST_MASK BITFIELD(18, 18) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_MINVDD_EN_SHIFT (1 << 17) +#define OMAP4430_VP_CORE_MINVDD_EN_SHIFT 17 #define OMAP4430_VP_CORE_MINVDD_EN_MASK BITFIELD(17, 17) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_MINVDD_ST_SHIFT (1 << 17) +#define OMAP4430_VP_CORE_MINVDD_ST_SHIFT 17 #define OMAP4430_VP_CORE_MINVDD_ST_MASK BITFIELD(17, 17) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_NOSMPSACK_EN_SHIFT (1 << 19) +#define OMAP4430_VP_CORE_NOSMPSACK_EN_SHIFT 19 #define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK BITFIELD(19, 19) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_NOSMPSACK_ST_SHIFT (1 << 19) +#define OMAP4430_VP_CORE_NOSMPSACK_ST_SHIFT 19 #define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK BITFIELD(19, 19) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_SHIFT (1 << 16) +#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_SHIFT 16 #define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK BITFIELD(16, 16) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_SHIFT (1 << 16) +#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_SHIFT 16 #define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK BITFIELD(16, 16) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_CORE_TRANXDONE_EN_SHIFT (1 << 21) +#define OMAP4430_VP_CORE_TRANXDONE_EN_SHIFT 21 #define OMAP4430_VP_CORE_TRANXDONE_EN_MASK BITFIELD(21, 21) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_CORE_TRANXDONE_ST_SHIFT (1 << 21) +#define OMAP4430_VP_CORE_TRANXDONE_ST_SHIFT 21 #define OMAP4430_VP_CORE_TRANXDONE_ST_MASK BITFIELD(21, 21) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_EQVALUE_EN_SHIFT (1 << 28) +#define OMAP4430_VP_IVA_EQVALUE_EN_SHIFT 28 #define OMAP4430_VP_IVA_EQVALUE_EN_MASK BITFIELD(28, 28) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_EQVALUE_ST_SHIFT (1 << 28) +#define OMAP4430_VP_IVA_EQVALUE_ST_SHIFT 28 #define OMAP4430_VP_IVA_EQVALUE_ST_MASK BITFIELD(28, 28) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_MAXVDD_EN_SHIFT (1 << 26) +#define OMAP4430_VP_IVA_MAXVDD_EN_SHIFT 26 #define OMAP4430_VP_IVA_MAXVDD_EN_MASK BITFIELD(26, 26) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_MAXVDD_ST_SHIFT (1 << 26) +#define OMAP4430_VP_IVA_MAXVDD_ST_SHIFT 26 #define OMAP4430_VP_IVA_MAXVDD_ST_MASK BITFIELD(26, 26) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_MINVDD_EN_SHIFT (1 << 25) +#define OMAP4430_VP_IVA_MINVDD_EN_SHIFT 25 #define OMAP4430_VP_IVA_MINVDD_EN_MASK BITFIELD(25, 25) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_MINVDD_ST_SHIFT (1 << 25) +#define OMAP4430_VP_IVA_MINVDD_ST_SHIFT 25 #define OMAP4430_VP_IVA_MINVDD_ST_MASK BITFIELD(25, 25) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_NOSMPSACK_EN_SHIFT (1 << 27) +#define OMAP4430_VP_IVA_NOSMPSACK_EN_SHIFT 27 #define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK BITFIELD(27, 27) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_NOSMPSACK_ST_SHIFT (1 << 27) +#define OMAP4430_VP_IVA_NOSMPSACK_ST_SHIFT 27 #define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK BITFIELD(27, 27) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_SHIFT (1 << 24) +#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_SHIFT 24 #define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK BITFIELD(24, 24) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_SHIFT (1 << 24) +#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_SHIFT 24 #define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK BITFIELD(24, 24) /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */ -#define OMAP4430_VP_IVA_TRANXDONE_EN_SHIFT (1 << 29) +#define OMAP4430_VP_IVA_TRANXDONE_EN_SHIFT 29 #define OMAP4430_VP_IVA_TRANXDONE_EN_MASK BITFIELD(29, 29) /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */ -#define OMAP4430_VP_IVA_TRANXDONE_ST_SHIFT (1 << 29) +#define OMAP4430_VP_IVA_TRANXDONE_ST_SHIFT 29 #define OMAP4430_VP_IVA_TRANXDONE_ST_MASK BITFIELD(29, 29) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_EQVALUE_EN_SHIFT (1 << 4) +#define OMAP4430_VP_MPU_EQVALUE_EN_SHIFT 4 #define OMAP4430_VP_MPU_EQVALUE_EN_MASK BITFIELD(4, 4) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_EQVALUE_ST_SHIFT (1 << 4) +#define OMAP4430_VP_MPU_EQVALUE_ST_SHIFT 4 #define OMAP4430_VP_MPU_EQVALUE_ST_MASK BITFIELD(4, 4) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_MAXVDD_EN_SHIFT (1 << 2) +#define OMAP4430_VP_MPU_MAXVDD_EN_SHIFT 2 #define OMAP4430_VP_MPU_MAXVDD_EN_MASK BITFIELD(2, 2) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_MAXVDD_ST_SHIFT (1 << 2) +#define OMAP4430_VP_MPU_MAXVDD_ST_SHIFT 2 #define OMAP4430_VP_MPU_MAXVDD_ST_MASK BITFIELD(2, 2) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_MINVDD_EN_SHIFT (1 << 1) +#define OMAP4430_VP_MPU_MINVDD_EN_SHIFT 1 #define OMAP4430_VP_MPU_MINVDD_EN_MASK BITFIELD(1, 1) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_MINVDD_ST_SHIFT (1 << 1) +#define OMAP4430_VP_MPU_MINVDD_ST_SHIFT 1 #define OMAP4430_VP_MPU_MINVDD_ST_MASK BITFIELD(1, 1) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_NOSMPSACK_EN_SHIFT (1 << 3) +#define OMAP4430_VP_MPU_NOSMPSACK_EN_SHIFT 3 #define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK BITFIELD(3, 3) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_NOSMPSACK_ST_SHIFT (1 << 3) +#define OMAP4430_VP_MPU_NOSMPSACK_ST_SHIFT 3 #define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK BITFIELD(3, 3) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_SHIFT (1 << 0) +#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_SHIFT 0 #define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK BITFIELD(0, 0) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_SHIFT (1 << 0) +#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_SHIFT 0 #define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK BITFIELD(0, 0) /* Used by PRM_IRQENABLE_MPU_2 */ -#define OMAP4430_VP_MPU_TRANXDONE_EN_SHIFT (1 << 5) +#define OMAP4430_VP_MPU_TRANXDONE_EN_SHIFT 5 #define OMAP4430_VP_MPU_TRANXDONE_EN_MASK BITFIELD(5, 5) /* Used by PRM_IRQSTATUS_MPU_2 */ -#define OMAP4430_VP_MPU_TRANXDONE_ST_SHIFT (1 << 5) +#define OMAP4430_VP_MPU_TRANXDONE_ST_SHIFT 5 #define OMAP4430_VP_MPU_TRANXDONE_ST_MASK BITFIELD(5, 5) /* Used by PRM_SRAM_COUNT */ -#define OMAP4430_VSETUPCNT_VALUE_SHIFT (1 << 8) +#define OMAP4430_VSETUPCNT_VALUE_SHIFT 8 #define OMAP4430_VSETUPCNT_VALUE_MASK BITFIELD(8, 15) /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */ -#define OMAP4430_VSTEPMAX_SHIFT (1 << 0) +#define OMAP4430_VSTEPMAX_SHIFT 0 #define OMAP4430_VSTEPMAX_MASK BITFIELD(0, 7) /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */ -#define OMAP4430_VSTEPMIN_SHIFT (1 << 0) +#define OMAP4430_VSTEPMIN_SHIFT 0 #define OMAP4430_VSTEPMIN_MASK BITFIELD(0, 7) /* Used by PRM_MODEM_IF_CTRL */ -#define OMAP4430_WAKE_MODEM_SHIFT (1 << 0) +#define OMAP4430_WAKE_MODEM_SHIFT 0 #define OMAP4430_WAKE_MODEM_MASK BITFIELD(0, 0) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DISPC_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_DISPC_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DISPC_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DISPC_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DISPC_MPU_MASK BITFIELD(0, 0) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DISPC_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_DISPC_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_DISPC_SDMA_MASK BITFIELD(3, 3) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DISPC_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_DISPC_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_DISPC_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_DMIC_WKDEP */ -#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_ABE_DMIC_WKDEP */ -#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_ABE_DMIC_WKDEP */ -#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_DMIC_WKDEP */ -#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_DMTIMER10_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER10_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER10_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_DMTIMER11_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_DMTIMER11_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER11_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER11_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_DMTIMER2_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_DMTIMER3_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_DMTIMER3_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_DMTIMER4_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_DMTIMER4_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER4_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER4_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_DMTIMER9_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_DMTIMER9_WKDEP */ -#define OMAP4430_WKUPDEP_DMTIMER9_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_DMTIMER9_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK BITFIELD(0, 0) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI1_DUCATI_SHIFT (1 << 5) +#define OMAP4430_WKUPDEP_DSI1_DUCATI_SHIFT 5 #define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK BITFIELD(5, 5) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI1_MPU_SHIFT (1 << 4) +#define OMAP4430_WKUPDEP_DSI1_MPU_SHIFT 4 #define OMAP4430_WKUPDEP_DSI1_MPU_MASK BITFIELD(4, 4) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI1_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_DSI1_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_DSI1_SDMA_MASK BITFIELD(7, 7) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI1_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_DSI1_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_DSI1_TESLA_MASK BITFIELD(6, 6) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI2_DUCATI_SHIFT (1 << 9) +#define OMAP4430_WKUPDEP_DSI2_DUCATI_SHIFT 9 #define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK BITFIELD(9, 9) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI2_MPU_SHIFT (1 << 8) +#define OMAP4430_WKUPDEP_DSI2_MPU_SHIFT 8 #define OMAP4430_WKUPDEP_DSI2_MPU_MASK BITFIELD(8, 8) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI2_SDMA_SHIFT (1 << 11) +#define OMAP4430_WKUPDEP_DSI2_SDMA_SHIFT 11 #define OMAP4430_WKUPDEP_DSI2_SDMA_MASK BITFIELD(11, 11) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_DSI2_TESLA_SHIFT (1 << 10) +#define OMAP4430_WKUPDEP_DSI2_TESLA_SHIFT 10 #define OMAP4430_WKUPDEP_DSI2_TESLA_MASK BITFIELD(10, 10) /* Used by PM_WKUP_GPIO1_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_WKUP_GPIO1_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_GPIO1_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_GPIO2_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_GPIO2_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_GPIO2_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_GPIO3_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_GPIO3_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_GPIO4_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_GPIO4_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_GPIO5_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_GPIO5_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_GPIO6_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_GPIO6_WKDEP */ -#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK BITFIELD(6, 6) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_SHIFT (1 << 19) +#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_SHIFT 19 #define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK BITFIELD(19, 19) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_SHIFT (1 << 13) +#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_SHIFT 13 #define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK BITFIELD(13, 13) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_SHIFT (1 << 12) +#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_SHIFT 12 #define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK BITFIELD(12, 12) /* Used by PM_DSS_DSS_WKDEP */ -#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_SHIFT (1 << 14) +#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_SHIFT 14 #define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK BITFIELD(14, 14) /* Used by PM_L4PER_HECC1_WKDEP */ -#define OMAP4430_WKUPDEP_HECC1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_HECC1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_HECC1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_HECC2_WKDEP */ -#define OMAP4430_WKUPDEP_HECC2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_HECC2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_HECC2_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_HSI_WKDEP */ -#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L3INIT_HSI_WKDEP */ -#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_HSI_WKDEP */ -#define OMAP4430_WKUPDEP_HSI_MCU_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_HSI_MCU_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_I2C1_WKDEP */ -#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_I2C1_WKDEP */ -#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_I2C1_WKDEP */ -#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_I2C2_WKDEP */ -#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_I2C2_WKDEP */ -#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_I2C2_WKDEP */ -#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_I2C3_WKDEP */ -#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_I2C3_WKDEP */ -#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_I2C3_WKDEP */ -#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_I2C4_WKDEP */ -#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_I2C4_WKDEP */ -#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_I2C4_WKDEP */ -#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_I2C5_WKDEP */ -#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_I2C5_WKDEP */ -#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_KEYBOARD_WKDEP */ -#define OMAP4430_WKUPDEP_KEYBOARD_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_KEYBOARD_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_MCASP_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_ABE_MCASP_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_ABE_MCASP_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_MCASP_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MCASP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_MCASP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_MCASP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCASP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MCASP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_MCASP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_MCASP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCASP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_MCBSP1_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCBSP1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_MCBSP1_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP1_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCBSP1_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK BITFIELD(3, 3) /* Used by PM_ABE_MCBSP1_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP1_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCBSP1_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_MCBSP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCBSP2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_MCBSP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP2_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCBSP2_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK BITFIELD(3, 3) /* Used by PM_ABE_MCBSP2_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP2_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCBSP2_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_MCBSP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCBSP3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_MCBSP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP3_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCBSP3_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK BITFIELD(3, 3) /* Used by PM_ABE_MCBSP3_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP3_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCBSP3_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MCBSP4_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP4_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCBSP4_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCBSP4_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP4_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCBSP4_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MCBSP4_WKDEP */ -#define OMAP4430_WKUPDEP_MCBSP4_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCBSP4_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MCSPI1_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_MCSPI1_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCSPI1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCSPI1_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI1_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCSPI1_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MCSPI1_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI1_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MCSPI1_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MCSPI2_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_MCSPI2_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCSPI2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCSPI2_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI2_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCSPI2_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MCSPI3_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCSPI3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCSPI3_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI3_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCSPI3_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MCSPI4_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI4_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MCSPI4_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MCSPI4_WKDEP */ -#define OMAP4430_WKUPDEP_MCSPI4_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MCSPI4_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L3INIT_MMC1_WKDEP */ -#define OMAP4430_WKUPDEP_MMC1_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMC1_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_MMC1_WKDEP */ -#define OMAP4430_WKUPDEP_MMC1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMC1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMC1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_MMC1_WKDEP */ -#define OMAP4430_WKUPDEP_MMC1_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MMC1_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MMC1_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L3INIT_MMC1_WKDEP */ -#define OMAP4430_WKUPDEP_MMC1_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MMC1_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MMC1_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L3INIT_MMC2_WKDEP */ -#define OMAP4430_WKUPDEP_MMC2_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMC2_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_MMC2_WKDEP */ -#define OMAP4430_WKUPDEP_MMC2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMC2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMC2_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_MMC2_WKDEP */ -#define OMAP4430_WKUPDEP_MMC2_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MMC2_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MMC2_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L3INIT_MMC2_WKDEP */ -#define OMAP4430_WKUPDEP_MMC2_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MMC2_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MMC2_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L3INIT_MMC6_WKDEP */ -#define OMAP4430_WKUPDEP_MMC6_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMC6_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_MMC6_WKDEP */ -#define OMAP4430_WKUPDEP_MMC6_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMC6_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMC6_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_MMC6_WKDEP */ -#define OMAP4430_WKUPDEP_MMC6_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_MMC6_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_MMC6_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_MMCSD3_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_MMCSD3_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMCSD3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MMCSD3_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD3_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MMCSD3_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MMCSD4_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_MMCSD4_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD4_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMCSD4_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MMCSD4_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD4_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MMCSD4_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_MMCSD5_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_MMCSD5_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD5_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_MMCSD5_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_MMCSD5_WKDEP */ -#define OMAP4430_WKUPDEP_MMCSD5_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_MMCSD5_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L3INIT_PCIESS_WKDEP */ -#define OMAP4430_WKUPDEP_PCIESS_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_PCIESS_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_PCIESS_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_PCIESS_WKDEP */ -#define OMAP4430_WKUPDEP_PCIESS_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_PCIESS_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_PDM_WKDEP */ -#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_ABE_PDM_WKDEP */ -#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_ABE_PDM_WKDEP */ -#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_PDM_WKDEP */ -#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_WKUP_RTC_WKDEP */ -#define OMAP4430_WKUPDEP_RTC_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_RTC_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_RTC_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_SATA_WKDEP */ -#define OMAP4430_WKUPDEP_SATA_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SATA_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SATA_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_SATA_WKDEP */ -#define OMAP4430_WKUPDEP_SATA_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_SATA_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_SATA_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_SLIMBUS_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_ABE_SLIMBUS_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_ABE_SLIMBUS_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_SLIMBUS_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_SLIMBUS2_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_SHIFT (1 << 7) +#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_SHIFT 7 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK BITFIELD(7, 7) /* Used by PM_L4PER_SLIMBUS2_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_SHIFT (1 << 6) +#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_SHIFT 6 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK BITFIELD(6, 6) /* Used by PM_L4PER_SLIMBUS2_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_SLIMBUS2_WKDEP */ -#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ALWON_SR_CORE_WKDEP */ -#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_ALWON_SR_CORE_WKDEP */ -#define OMAP4430_WKUPDEP_SR_CORE_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SR_CORE_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK BITFIELD(0, 0) /* Used by PM_ALWON_SR_IVA_WKDEP */ -#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_ALWON_SR_IVA_WKDEP */ -#define OMAP4430_WKUPDEP_SR_IVA_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SR_IVA_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK BITFIELD(0, 0) /* Used by PM_ALWON_SR_MPU_WKDEP */ -#define OMAP4430_WKUPDEP_SR_MPU_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_SR_MPU_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_TIMER12_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER12_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER12_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER12_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_TIMER1_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER1_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_TIMER5_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER5_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER5_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER5_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_TIMER5_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER5_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_TIMER5_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_TIMER6_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER6_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER6_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER6_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_TIMER6_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER6_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_TIMER6_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_TIMER7_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER7_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER7_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER7_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_TIMER7_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER7_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_TIMER7_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK BITFIELD(2, 2) /* Used by PM_ABE_TIMER8_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER8_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_TIMER8_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_TIMER8_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_TIMER8_WKDEP */ -#define OMAP4430_WKUPDEP_TIMER8_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_TIMER8_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_UART1_WKDEP */ -#define OMAP4430_WKUPDEP_UART1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_UART1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_UART1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_UART1_WKDEP */ -#define OMAP4430_WKUPDEP_UART1_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_UART1_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_UART1_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_UART2_WKDEP */ -#define OMAP4430_WKUPDEP_UART2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_UART2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_UART2_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_UART2_WKDEP */ -#define OMAP4430_WKUPDEP_UART2_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_UART2_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_UART2_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_UART3_WKDEP */ -#define OMAP4430_WKUPDEP_UART3_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_UART3_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_UART3_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L4PER_UART3_WKDEP */ -#define OMAP4430_WKUPDEP_UART3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_UART3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_UART3_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_UART3_WKDEP */ -#define OMAP4430_WKUPDEP_UART3_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_UART3_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_UART3_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L4PER_UART3_WKDEP */ -#define OMAP4430_WKUPDEP_UART3_TESLA_SHIFT (1 << 2) +#define OMAP4430_WKUPDEP_UART3_TESLA_SHIFT 2 #define OMAP4430_WKUPDEP_UART3_TESLA_MASK BITFIELD(2, 2) /* Used by PM_L4PER_UART4_WKDEP */ -#define OMAP4430_WKUPDEP_UART4_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_UART4_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_UART4_MPU_MASK BITFIELD(0, 0) /* Used by PM_L4PER_UART4_WKDEP */ -#define OMAP4430_WKUPDEP_UART4_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_UART4_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_UART4_SDMA_MASK BITFIELD(3, 3) /* Used by PM_L3INIT_UNIPRO1_WKDEP */ -#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_UNIPRO1_WKDEP */ -#define OMAP4430_WKUPDEP_UNIPRO1_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_UNIPRO1_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_USB_HOST_WKDEP */ -#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */ -#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */ -#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_USB_HOST_WKDEP */ -#define OMAP4430_WKUPDEP_USB_HOST_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_USB_HOST_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_USB_OTG_WKDEP */ -#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_USB_OTG_WKDEP */ -#define OMAP4430_WKUPDEP_USB_OTG_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_USB_OTG_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_USB_TLL_WKDEP */ -#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_L3INIT_USB_TLL_WKDEP */ -#define OMAP4430_WKUPDEP_USB_TLL_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_USB_TLL_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_USIM_WKDEP */ -#define OMAP4430_WKUPDEP_USIM_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_USIM_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_USIM_MPU_MASK BITFIELD(0, 0) /* Used by PM_WKUP_USIM_WKDEP */ -#define OMAP4430_WKUPDEP_USIM_SDMA_SHIFT (1 << 3) +#define OMAP4430_WKUPDEP_USIM_SDMA_SHIFT 3 #define OMAP4430_WKUPDEP_USIM_SDMA_MASK BITFIELD(3, 3) /* Used by PM_WKUP_WDT2_WKDEP */ -#define OMAP4430_WKUPDEP_WDT2_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_WDT2_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK BITFIELD(1, 1) /* Used by PM_WKUP_WDT2_WKDEP */ -#define OMAP4430_WKUPDEP_WDT2_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_WDT2_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_WDT2_MPU_MASK BITFIELD(0, 0) /* Used by PM_ABE_WDT3_WKDEP */ -#define OMAP4430_WKUPDEP_WDT3_MPU_SHIFT (1 << 0) +#define OMAP4430_WKUPDEP_WDT3_MPU_SHIFT 0 #define OMAP4430_WKUPDEP_WDT3_MPU_MASK BITFIELD(0, 0) /* Used by PM_L3INIT_HSI_WKDEP */ -#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_SHIFT (1 << 8) +#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_SHIFT 8 #define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK BITFIELD(8, 8) /* Used by PM_L3INIT_XHPI_WKDEP */ -#define OMAP4430_WKUPDEP_XHPI_DUCATI_SHIFT (1 << 1) +#define OMAP4430_WKUPDEP_XHPI_DUCATI_SHIFT 1 #define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK BITFIELD(1, 1) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_WUCLK_CTRL_SHIFT (1 << 8) +#define OMAP4430_WUCLK_CTRL_SHIFT 8 #define OMAP4430_WUCLK_CTRL_MASK BITFIELD(8, 8) /* Used by PRM_IO_PMCTRL */ -#define OMAP4430_WUCLK_STATUS_SHIFT (1 << 9) +#define OMAP4430_WUCLK_STATUS_SHIFT 9 #define OMAP4430_WUCLK_STATUS_MASK BITFIELD(9, 9) #endif -- GitLab From 98fa3d8aeabf7a039cc920a9c2ffebc6b4648e2b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 26 Jan 2010 20:13:13 -0700 Subject: [PATCH 1374/3892] OMAP2+ powerdomains/clockdomains: prepare for multi-OMAP configs Convert CONFIG_ARCH_OMAP34XX to CONFIG_ARCH_OMAP3, and CONFIG_ARCH_OMAP24XX to CONFIG_ARCH_OMAP2, in preparation for Tony's multi-OMAP patches. While here, update some copyrights, convert instances of "34xx" to "3xxx" where applicable, and convert preprocessor directives of the form #if defined(CONFIG_ARCH_OMAP2) | defined(CONFIG_ARCH_OMAP3) to #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) for standardization. Signed-off-by: Paul Walmsley Cc: Tony Lindgren --- arch/arm/mach-omap2/clockdomains.h | 50 +++++++++++++------------- arch/arm/mach-omap2/powerdomains.h | 16 ++++----- arch/arm/mach-omap2/powerdomains34xx.h | 14 ++++---- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index fb026dabfc37..7db6298493fd 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -1,8 +1,8 @@ /* * OMAP2/3 clockdomains * - * Copyright (C) 2008 Texas Instruments, Inc. - * Copyright (C) 2008-2009 Nokia Corporation + * Copyright (C) 2008-2009 Texas Instruments, Inc. + * Copyright (C) 2008-2010 Nokia Corporation * * Written by Paul Walmsley and Jouni Högander * @@ -196,9 +196,9 @@ static struct clkdm_dep mdm_2430_wkdeps[] = { #endif /* CONFIG_ARCH_OMAP2430 */ -/* 34XX-specific possible dependencies */ +/* OMAP3-specific possible dependencies */ -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 /* 3430: PM_WKDEP_PER: CORE, IVA2, MPU, WKUP */ static struct clkdm_dep per_wkdeps[] = { @@ -251,7 +251,7 @@ static struct clkdm_dep usbhost_wkdeps[] = { }; /* 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER */ -static struct clkdm_dep mpu_34xx_wkdeps[] = { +static struct clkdm_dep mpu_3xxx_wkdeps[] = { { .clkdm_name = "core_l3_clkdm", .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) @@ -349,7 +349,7 @@ static struct clkdm_dep neon_wkdeps[] = { }; -/* Sleep dependency source arrays for 34xx-specific clkdms - 34XX only */ +/* Sleep dependency source arrays for OMAP3-specific clkdms */ /* 3430: CM_SLEEPDEP_DSS: MPU, IVA */ static struct clkdm_dep dss_sleepdeps[] = { @@ -413,7 +413,7 @@ static struct clkdm_dep gfx_sgx_sleepdeps[] = { { NULL }, }; -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ /* @@ -425,7 +425,7 @@ static struct clkdm_dep gfx_sgx_sleepdeps[] = { * sys_clkout/sys_clkout2. */ -#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) /* This is an implicit clockdomain - it is never defined as such in TRM */ static struct clockdomain wkup_clkdm = { @@ -626,18 +626,18 @@ static struct clockdomain dss_2430_clkdm = { /* - * 34xx clockdomains + * OMAP3 clockdomains */ -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) -static struct clockdomain mpu_34xx_clkdm = { +static struct clockdomain mpu_3xxx_clkdm = { .name = "mpu_clkdm", .pwrdm = { .name = "mpu_pwrdm" }, .flags = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP, .clkstctrl_reg = OMAP34XX_CM_REGADDR(MPU_MOD, OMAP2_CM_CLKSTCTRL), .dep_bit = OMAP3430_EN_MPU_SHIFT, - .wkdep_srcs = mpu_34xx_wkdeps, + .wkdep_srcs = mpu_3xxx_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; @@ -706,10 +706,10 @@ static struct clockdomain d2d_clkdm = { /* * XXX add usecounting for clkdm dependencies, otherwise the presence - * of a single dep bit for core_l3_34xx_clkdm and core_l4_34xx_clkdm + * of a single dep bit for core_l3_3xxx_clkdm and core_l4_3xxx_clkdm * could cause trouble */ -static struct clockdomain core_l3_34xx_clkdm = { +static struct clockdomain core_l3_3xxx_clkdm = { .name = "core_l3_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, @@ -721,10 +721,10 @@ static struct clockdomain core_l3_34xx_clkdm = { /* * XXX add usecounting for clkdm dependencies, otherwise the presence - * of a single dep bit for core_l3_34xx_clkdm and core_l4_34xx_clkdm + * of a single dep bit for core_l3_3xxx_clkdm and core_l4_3xxx_clkdm * could cause trouble */ -static struct clockdomain core_l4_34xx_clkdm = { +static struct clockdomain core_l4_3xxx_clkdm = { .name = "core_l4_clkdm", .pwrdm = { .name = "core_pwrdm" }, .flags = CLKDM_CAN_HWSUP, @@ -735,7 +735,7 @@ static struct clockdomain core_l4_34xx_clkdm = { }; /* Another case of bit name collisions between several registers: EN_DSS */ -static struct clockdomain dss_34xx_clkdm = { +static struct clockdomain dss_3xxx_clkdm = { .name = "dss_clkdm", .pwrdm = { .name = "dss_pwrdm" }, .flags = CLKDM_CAN_HWSUP_SWSUP, @@ -829,12 +829,12 @@ static struct clockdomain dpll5_clkdm = { .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), }; -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ #include "clockdomains44xx.h" /* - * Clockdomain hwsup dependencies (34XX only) + * Clockdomain hwsup dependencies (OMAP3 only) */ static struct clkdm_autodep clkdm_autodeps[] = { @@ -857,7 +857,7 @@ static struct clkdm_autodep clkdm_autodeps[] = { static struct clockdomain *clockdomains_omap[] = { -#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) &wkup_clkdm, &cm_clkdm, &prm_clkdm, @@ -883,16 +883,16 @@ static struct clockdomain *clockdomains_omap[] = { &dss_2430_clkdm, #endif -#ifdef CONFIG_ARCH_OMAP34XX - &mpu_34xx_clkdm, +#ifdef CONFIG_ARCH_OMAP3 + &mpu_3xxx_clkdm, &neon_clkdm, &iva2_clkdm, &gfx_3430es1_clkdm, &sgx_clkdm, &d2d_clkdm, - &core_l3_34xx_clkdm, - &core_l4_34xx_clkdm, - &dss_34xx_clkdm, + &core_l3_3xxx_clkdm, + &core_l4_3xxx_clkdm, + &dss_3xxx_clkdm, &cam_clkdm, &usbhost_clkdm, &per_clkdm, diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h index faa8fc952d95..105cbcaefd3b 100644 --- a/arch/arm/mach-omap2/powerdomains.h +++ b/arch/arm/mach-omap2/powerdomains.h @@ -23,7 +23,7 @@ /* * This file contains all of the powerdomains that have some element - * of software control for the OMAP24xx and OMAP34XX chips. + * of software control for the OMAP24xx and OMAP34xx chips. * * This is not an exhaustive listing of powerdomains on the chips; only * powerdomains that can be controlled in software. @@ -60,7 +60,7 @@ /* OMAP2/3-common powerdomains */ -#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) /* * The GFX powerdomain is not present on 3430ES2, but currently we do not @@ -94,12 +94,12 @@ static struct powerdomain wkup_omap2_pwrdm = { /* As powerdomains are added or removed above, this list must also be changed */ static struct powerdomain *powerdomains_omap[] __initdata = { -#if defined(CONFIG_ARCH_OMAP24XX) | defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) &wkup_omap2_pwrdm, &gfx_omap2_pwrdm, #endif -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 &dsp_pwrdm, &mpu_24xx_pwrdm, &core_24xx_pwrdm, @@ -109,12 +109,12 @@ static struct powerdomain *powerdomains_omap[] __initdata = { &mdm_pwrdm, #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 &iva2_pwrdm, - &mpu_34xx_pwrdm, + &mpu_3xxx_pwrdm, &neon_pwrdm, - &core_34xx_pre_es3_1_pwrdm, - &core_34xx_es3_1_pwrdm, + &core_3xxx_pre_es3_1_pwrdm, + &core_3xxx_es3_1_pwrdm, &cam_pwrdm, &dss_pwrdm, &per_pwrdm, diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index 28228ef20e86..186c0132466b 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -1,8 +1,8 @@ /* - * OMAP34XX powerdomain definitions + * OMAP3 powerdomain definitions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2009 Nokia Corporation + * Copyright (C) 2007-2010 Nokia Corporation * * Written by Paul Walmsley * Debugging and integration fixes by Jouni Högander @@ -32,7 +32,7 @@ * 34XX-specific powerdomains, dependencies */ -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 /* * Powerdomains @@ -59,7 +59,7 @@ static struct powerdomain iva2_pwrdm = { }, }; -static struct powerdomain mpu_34xx_pwrdm = { +static struct powerdomain mpu_3xxx_pwrdm = { .name = "mpu_pwrdm", .prcm_offs = MPU_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), @@ -75,7 +75,7 @@ static struct powerdomain mpu_34xx_pwrdm = { }, }; -static struct powerdomain core_34xx_pre_es3_1_pwrdm = { +static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -93,7 +93,7 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { }, }; -static struct powerdomain core_34xx_es3_1_pwrdm = { +static struct powerdomain core_3xxx_es3_1_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES3_1), @@ -243,7 +243,7 @@ static struct powerdomain dpll5_pwrdm = { }; -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ #endif -- GitLab From 49dcc819b077c2d473062e17d5a1373a8b660e02 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Tue, 19 Jan 2010 10:22:19 -0800 Subject: [PATCH 1375/3892] iwlwifi: optimize power saving In hostap AP mode, every time the client sends the AP a packet the STA_NOTIFY_AWAKE code is sent from mac80211. This results in a command being sent to the uCode even if the client was not asleep. The following simple patch has fixed the issue for me without any degradation that I can find. Signed-off-by: Daniel Halperin Acked-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4a268927377b..380d2087bf3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3007,6 +3007,8 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, break; case STA_NOTIFY_AWAKE: WARN_ON(!sta_priv->client); + if (!sta_priv->asleep) + break; sta_priv->asleep = false; sta_id = iwl_find_station(priv, sta->addr); if (sta_id != IWL_INVALID_STATION) -- GitLab From a7fce6ee8dd693fb2a9d19ddf9ee1fe380893fa1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 19 Jan 2010 16:51:50 -0800 Subject: [PATCH 1376/3892] iwlwifi: sysassert identifier change Change in uCode to include a unique identifier as part of sysassert, in order to tell the difference, add the "ADVANCED SYSASSERT" description when dump nic error to indicate the difference. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 380d2087bf3a..1c54425afe22 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1757,7 +1757,7 @@ static const char *desc_lookup_text[] = { "DEBUG_1", "DEBUG_2", "DEBUG_3", - "UNKNOWN" + "ADVANCED SYSASSERT" }; static const char *desc_lookup(int i) -- GitLab From 47e28f41dce90ea4317d35cf23f232c1a6b07adf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Jan 2010 11:21:06 -0800 Subject: [PATCH 1377/3892] iwlwifi: fix locking in iwl_mac_add_interface The corresponding iwl_mac_remove_interface only acquires the mutex, leading me to believe that the spinlock is not necessary. However, this doesn't actually acquire the mutex around the vif pointer check and assignment, fix that. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1cfabd6be0b8..02bf17ecaf54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2631,23 +2631,21 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; - unsigned long flags; + int err = 0; IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type); + mutex_lock(&priv->mutex); + if (priv->vif) { IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto out; } - spin_lock_irqsave(&priv->lock, flags); priv->vif = vif; priv->iw_mode = vif->type; - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - if (vif->addr) { IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr); memcpy(priv->mac_addr, vif->addr, ETH_ALEN); @@ -2657,10 +2655,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); + out: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; + return err; } EXPORT_SYMBOL(iwl_mac_add_interface); -- GitLab From 2494f63cc7394fc4424c4833b83d1831f52e54c8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 20 Jan 2010 12:22:52 -0800 Subject: [PATCH 1378/3892] iwlwifi: update sensitivity calibration data for 6x00 series Update sensitivity range values for 6000 & 6x50 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 81e03e33ec73..a9f8551e0e40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -108,7 +108,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .auto_corr_max_ofdm = 145, .auto_corr_max_ofdm_mrc = 232, - .auto_corr_max_ofdm_x1 = 145, + .auto_corr_max_ofdm_x1 = 110, .auto_corr_max_ofdm_mrc_x1 = 232, .auto_corr_min_cck = 125, -- GitLab From 9bead7632adb6341548056a80ec36e7ae098f4f4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 20 Jan 2010 12:22:53 -0800 Subject: [PATCH 1379/3892] iwlwifi: update sensitivity calibration data for 5x00 series Update sensitivity range values for 5x00 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6027e2a658d1..6bb433a0e535 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -263,8 +263,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .auto_corr_max_ofdm = 120, .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 155, - .auto_corr_max_ofdm_mrc_x1 = 290, + .auto_corr_max_ofdm_x1 = 120, + .auto_corr_max_ofdm_mrc_x1 = 240, .auto_corr_min_cck = 125, .auto_corr_max_cck = 200, -- GitLab From fac06108701a2a081a47d4dc6f03220aaab54486 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 20 Jan 2010 12:22:54 -0800 Subject: [PATCH 1380/3892] iwlwifi: update sensitivity calibration data for 1000 series Update sensitivity range values for 1000 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-1000.c | 72 ++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 4281999cfaaa..9d1820676f30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -89,8 +89,78 @@ static void iwl1000_nic_config(struct iwl_priv *priv) ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); } +static struct iwl_sensitivity_ranges iwl1000_sensitivity = { + .min_nrg_cck = 95, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 120, + .auto_corr_min_ofdm_mrc_x1 = 240, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 155, + .auto_corr_max_ofdm_mrc_x1 = 290, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) +{ + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + priv->cfg->num_of_queues * + sizeof(struct iwl5000_scd_bc_tbl); + priv->hw_params.tfd_size = sizeof(struct iwl_tfd); + priv->hw_params.max_stations = IWL5000_STATION_COUNT; + priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; + + priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; + + priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; + + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + + /* Set initial sensitivity parameters */ + /* Set initial calibration set */ + priv->hw_params.sens = &iwl1000_sensitivity; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); + + return 0; +} + static struct iwl_lib_ops iwl1000_lib = { - .set_hw_params = iwl5000_hw_set_hw_params, + .set_hw_params = iwl1000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, -- GitLab From 4d6959219bb71aa34383fc1a1a520820aee6292b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 05:24:04 -0800 Subject: [PATCH 1381/3892] iwlwifi: no need to test iw_mode in power saving mac80211 will only enable powersaving for station mode. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-power.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9e3ca0641451..232dd1879baf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -308,8 +308,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { int ret = 0; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && - (priv->hw->conf.flags & IEEE80211_CONF_PS); + bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS; bool update_chains; struct iwl_powertable_cmd cmd; int dtimper; -- GitLab From 9f1f3ceacb7e52d9bc0364b4f26ae418de79656f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 05:28:40 -0800 Subject: [PATCH 1382/3892] iwlagn: simplify ucode loading Move the waiting into iwl5000_load_section instead of duplicating it in the caller. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-5000.c | 63 +++++++++---------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6bb433a0e535..6d5988901341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -412,12 +412,14 @@ static void iwl5000_rx_calib_complete(struct iwl_priv *priv, /* * ucode */ -static int iwl5000_load_section(struct iwl_priv *priv, - struct fw_desc *image, - u32 dst_addr) +static int iwl5000_load_section(struct iwl_priv *priv, const char *name, + struct fw_desc *image, u32 dst_addr) { dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; + int ret; + + priv->ucode_write_complete = 0; iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), @@ -447,57 +449,36 @@ static int iwl5000_load_section(struct iwl_priv *priv, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - return 0; -} - -static int iwl5000_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) -{ - int ret = 0; - - ret = iwl5000_load_section(priv, inst_image, - IWL50_RTC_INST_LOWER_BOUND); - if (ret) - return ret; - - IWL_DEBUG_INFO(priv, "INST uCode section being loaded...\n"); + IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name); ret = wait_event_interruptible_timeout(priv->wait_command_queue, priv->ucode_write_complete, 5 * HZ); if (ret == -ERESTARTSYS) { - IWL_ERR(priv, "Could not load the INST uCode section due " - "to interrupt\n"); + IWL_ERR(priv, "Could not load the %s uCode section due " + "to interrupt\n", name); return ret; } if (!ret) { - IWL_ERR(priv, "Could not load the INST uCode section\n"); + IWL_ERR(priv, "Could not load the %s uCode section\n", + name); return -ETIMEDOUT; } - priv->ucode_write_complete = 0; - - ret = iwl5000_load_section( - priv, data_image, IWL50_RTC_DATA_LOWER_BOUND); - if (ret) - return ret; + return 0; +} - IWL_DEBUG_INFO(priv, "DATA uCode section being loaded...\n"); +static int iwl5000_load_given_ucode(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image) +{ + int ret = 0; - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); - if (ret == -ERESTARTSYS) { - IWL_ERR(priv, "Could not load the INST uCode section due " - "to interrupt\n"); + ret = iwl5000_load_section(priv, "INST", inst_image, + IWL50_RTC_INST_LOWER_BOUND); + if (ret) return ret; - } else if (!ret) { - IWL_ERR(priv, "Could not load the DATA uCode section\n"); - return -ETIMEDOUT; - } else - ret = 0; - - priv->ucode_write_complete = 0; - return ret; + return iwl5000_load_section(priv, "DATA", data_image, + IWL50_RTC_DATA_LOWER_BOUND); } int iwl5000_load_ucode(struct iwl_priv *priv) -- GitLab From 80676518da523e926e70794ac2767829effcf3ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 06:07:17 -0800 Subject: [PATCH 1383/3892] iwlwifi: remove bg_up work There's no need to queue a work struct from within a work struct, just move the code to execute directly. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 21 +++++++-------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 21 +++++++-------------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1c54425afe22..b528a20ade4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2439,18 +2439,6 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) return; } -static void iwl_bg_up(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, up); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); -} - static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -2467,7 +2455,13 @@ static void iwl_bg_restart(struct work_struct *data) ieee80211_restart_hw(priv->hw); } else { iwl_down(priv); - queue_work(priv->workqueue, &priv->up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); } } @@ -3285,7 +3279,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9b0a5cbc20f9..1cd565aef62c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1264,7 +1264,6 @@ struct iwl_priv { struct workqueue_struct *workqueue; - struct work_struct up; struct work_struct restart; struct work_struct calibrated_work; struct work_struct scan_completed; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cd42b5838b38..119da54116de 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3033,18 +3033,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data) mutex_unlock(&priv->mutex); } -static void iwl3945_bg_up(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, up); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl3945_up(priv); - mutex_unlock(&priv->mutex); -} - static void iwl3945_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -3061,7 +3049,13 @@ static void iwl3945_bg_restart(struct work_struct *data) ieee80211_restart_hw(priv->hw); } else { iwl3945_down(priv); - queue_work(priv->workqueue, &priv->up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl3945_up(priv); + mutex_unlock(&priv->mutex); } } @@ -3782,7 +3776,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); -- GitLab From 71d75cf9ab858b99d072fece9784ab338af8e388 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 06:08:19 -0800 Subject: [PATCH 1384/3892] iwlwifi: remove unused work structs auth_work, calibrated_work, update_link_led and report_work are never used, so remove them. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1cd565aef62c..55dc5a866542 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1265,13 +1265,9 @@ struct iwl_priv { struct workqueue_struct *workqueue; struct work_struct restart; - struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; struct work_struct abort_scan; - struct work_struct update_link_led; - struct work_struct auth_work; - struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; struct work_struct tt_work; -- GitLab From 7ae810776a51dc4dc6580013b0f6ba0f34d2b165 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jan 2010 11:47:59 -0800 Subject: [PATCH 1385/3892] iwlwifi: fix typo in IWL_CCK_RATES_MASK Due to a typo, the variable contains OFDM rates as well. The only user doesn't care, so this change doesn't really do anything but fix up my confusion. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 2f0094a43261..e71923961e69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -191,7 +191,7 @@ enum { IWL_RATE_2M_MASK) #define IWL_CCK_RATES_MASK \ - (IWL_BASIC_RATES_MASK | \ + (IWL_CCK_BASIC_RATES_MASK | \ IWL_RATE_5M_MASK | \ IWL_RATE_11M_MASK) -- GitLab From d3a571971e5af241074947fc80f6284677f6e014 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 21 Jan 2010 11:52:28 -0800 Subject: [PATCH 1386/3892] iwlwifi: iwl_power_update_mode always hold mutex iwl_power_update_mode expects to be called with mutex held, for example to protect priv->vif. Only one caller currently does not do this, fix this. Also, add a comment to iwl_power_update_mode to indicate this requirement. Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 5c8377b9ad9b..d134301b553c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -815,7 +815,9 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, priv->power_data.debug_sleep_level_override = value; + mutex_lock(&priv->mutex); iwl_power_update_mode(priv, true); + mutex_unlock(&priv->mutex); return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 232dd1879baf..1a1a9f081cc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -303,7 +303,7 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) sizeof(struct iwl_powertable_cmd), cmd); } - +/* priv->mutex must be held */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { int ret = 0; -- GitLab From 97b19778ee5dd0484493f12f6a9cf9391cf0aefb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 30 Jan 2010 11:04:38 +0900 Subject: [PATCH 1387/3892] sh: mach-se: Fix up irq_desc reference. The irq_desc needs to be accessed with irq_to_desc(), this fixes up a build error with irq_desc being undefined. Signed-off-by: Paul Mundt --- arch/sh/boards/mach-se/7206/irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sh/boards/mach-se/7206/irq.c b/arch/sh/boards/mach-se/7206/irq.c index 79be4bc59933..8d82175d83ab 100644 --- a/arch/sh/boards/mach-se/7206/irq.c +++ b/arch/sh/boards/mach-se/7206/irq.c @@ -89,8 +89,9 @@ static void enable_se7206_irq(unsigned int irq) static void eoi_se7206_irq(unsigned int irq) { unsigned short sts0,sts1; + struct irq_desc *desc = irq_to_desc(irq); - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_se7206_irq(irq); /* FPGA isr clear */ sts0 = __raw_readw(INTSTS0); -- GitLab From 31a090ae0693af189fc7a8ad16cece4878acad33 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 30 Jan 2010 11:29:56 +0900 Subject: [PATCH 1388/3892] sh: Fix up asm/hw_breakpoint.h header check. Presently headers_check complains about linux/kdebug.h being unexported, so just bump the __KERNEL__ ifdef up, as per the x86 change. Signed-off-by: Paul Mundt --- arch/sh/include/asm/hw_breakpoint.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h index 7295d6290249..965dd780d51b 100644 --- a/arch/sh/include/asm/hw_breakpoint.h +++ b/arch/sh/include/asm/hw_breakpoint.h @@ -1,12 +1,12 @@ #ifndef __ASM_SH_HW_BREAKPOINT_H #define __ASM_SH_HW_BREAKPOINT_H -#include -#include - #ifdef __KERNEL__ #define __ARCH_HW_BREAKPOINT_H +#include +#include + struct arch_hw_breakpoint { char *name; /* Contains name of the symbol to set bkpt */ unsigned long address; -- GitLab From 45cdba4d376adfd30cfbda1b7d43110818d967cc Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Fri, 29 Jan 2010 23:53:57 -0800 Subject: [PATCH 1389/3892] Input: uinput - remove BKL from uinput_open function Commit 8702965848ed4bee27486a3e3d2ae34ebba6dd83 pushed down the BKL into uinput open function. However, there's nothing that needs locking in there. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index d3f57245420a..18206e18d1b1 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -284,7 +283,6 @@ static int uinput_open(struct inode *inode, struct file *file) if (!newdev) return -ENOMEM; - lock_kernel(); mutex_init(&newdev->mutex); spin_lock_init(&newdev->requests_lock); init_waitqueue_head(&newdev->requests_waitq); @@ -292,7 +290,6 @@ static int uinput_open(struct inode *inode, struct file *file) newdev->state = UIST_NEW_DEVICE; file->private_data = newdev; - unlock_kernel(); return 0; } -- GitLab From ef7995f4e46b1677f3eaaf547316e1a910b38dcb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Jan 2010 23:59:12 -0800 Subject: [PATCH 1390/3892] Input: implement input filters Sometimes it is desirable to suppress certain events from reaching input handlers and thus user space. One such example is Mac mouse button emulation code which catches certain key presses and converts them into button clicks as if they were emitted by a virtual mouse. The original key press events should be completely suppressed, otherwise user space will be confused, and while keyboard driver does it on its own evdev is blissfully unaware of this arrangement. This patch adds notion of 'filter' to the standard input handlers, which may flag event as filtered thus preventing it from reaching other input handlers. Filters don't (nor will they ever) have a notion of priority relative to each other, input core will run all of them first and any one of them may mark event as filtered. This patch is inspired by similar patch by Matthew Garret but the implementation and intended usage are quite different. Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 41 ++++++++++++++++++++++++++++++++++------- include/linux/input.h | 8 ++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 6c161e220868..7080a9d4b840 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -86,12 +86,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) } /* - * Pass event through all open handles. This function is called with + * Pass event first through all filters and then, if event has not been + * filtered out, through all open handles. This function is called with * dev->event_lock held and interrupts disabled. */ static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + struct input_handler *handler; struct input_handle *handle; rcu_read_lock(); @@ -99,11 +101,25 @@ static void input_pass_event(struct input_dev *dev, handle = rcu_dereference(dev->grab); if (handle) handle->handler->event(handle, type, code, value); - else - list_for_each_entry_rcu(handle, &dev->h_list, d_node) - if (handle->open) - handle->handler->event(handle, - type, code, value); + else { + bool filtered = false; + + list_for_each_entry_rcu(handle, &dev->h_list, d_node) { + if (!handle->open) + continue; + + handler = handle->handler; + if (!handler->filter) { + if (filtered) + break; + + handler->event(handle, type, code, value); + + } else if (handler->filter(handle, type, code, value)) + filtered = true; + } + } + rcu_read_unlock(); } @@ -990,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v) union input_seq_state *state = (union input_seq_state *)&seq->private; seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); + if (handler->filter) + seq_puts(seq, " (filter)"); if (handler->fops) seq_printf(seq, " Minor=%d", handler->minor); seq_putc(seq, '\n'); @@ -1803,7 +1821,16 @@ int input_register_handle(struct input_handle *handle) error = mutex_lock_interruptible(&dev->mutex); if (error) return error; - list_add_tail_rcu(&handle->d_node, &dev->h_list); + + /* + * Filters go to the head of the list, normal handlers + * to the tail. + */ + if (handler->filter) + list_add_rcu(&handle->d_node, &dev->h_list); + else + list_add_tail_rcu(&handle->d_node, &dev->h_list); + mutex_unlock(&dev->mutex); /* diff --git a/include/linux/input.h b/include/linux/input.h index 7be8a6537b57..6c9d3d49fa91 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1198,6 +1198,8 @@ struct input_handle; * @event: event handler. This method is being called by input core with * interrupts disabled and dev->event_lock spinlock held and so * it may not sleep + * @filter: similar to @event; separates normal event handlers from + * "filters". * @connect: called when attaching a handler to an input device * @disconnect: disconnects a handler from input device * @start: starts handler for given handle. This function is called by @@ -1219,6 +1221,11 @@ struct input_handle; * same time. All of them will get their copy of input event generated by * the device. * + * The very same structure is used to implement input filters. Input core + * allows filters to run first and will not pass event to regular handlers + * if any of the filters indicate that the event should be filtered (by + * returning %true from their filter() method). + * * Note that input core serializes calls to connect() and disconnect() * methods. */ @@ -1227,6 +1234,7 @@ struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); -- GitLab From 99b089c3c38a83ebaeb1cc4584ddcde841626467 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 30 Jan 2010 00:53:29 -0800 Subject: [PATCH 1391/3892] Input: Mac button emulation - implement as an input filter Current implementation of Mac mouse button emulation plugs into legacy keyboard driver, converts certain keys into button events on a separate device, and suppresses the real events from reaching tty. This worked well enough until user space started using evdev which was completely unaware of this arrangement and kept sending original key presses to its users. Change the implementation to use newly added input filter framework so that original key presses are not transmitted to any handlers. As a bonus remove SYSCTL dependencies from the code and use Kconfig instead; also do not create the emulated mouse device until user activates emulation. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 5 - drivers/macintosh/Kconfig | 1 + drivers/macintosh/mac_hid.c | 257 ++++++++++++++++++++++++++---------- include/linux/kbd_kern.h | 3 - 4 files changed, 188 insertions(+), 78 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index f706b1dffdb3..cbf64b985ef4 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) rep = (down == 2); -#ifdef CONFIG_MAC_EMUMOUSEBTN - if (mac_hid_mouse_emulate_buttons(1, keycode, down)) - return; -#endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC && printk_ratelimit()) diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 3d906833948d..aa3c27e5255d 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -172,6 +172,7 @@ config INPUT_ADBHID config MAC_EMUMOUSEBTN bool "Support for mouse button 2+3 emulation" + depends on SYSCTL select INPUT help This provides generic support for emulating the 2nd and 3rd mouse diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 7b4ef5bb556b..0b210a90aef5 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -13,17 +13,195 @@ #include #include #include -#include - -static struct input_dev *emumousebtn; -static int emumousebtn_input_register(void); static int mouse_emulate_buttons; static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ -static int mouse_last_keycode; -#if defined(CONFIG_SYSCTL) +static struct input_dev *mac_hid_emumouse_dev; + +static int mac_hid_create_emumouse(void) +{ + static struct lock_class_key mac_hid_emumouse_dev_event_class; + static struct lock_class_key mac_hid_emumouse_dev_mutex_class; + int err; + + mac_hid_emumouse_dev = input_allocate_device(); + if (!mac_hid_emumouse_dev) + return -ENOMEM; + + lockdep_set_class(&mac_hid_emumouse_dev->event_lock, + &mac_hid_emumouse_dev_event_class); + lockdep_set_class(&mac_hid_emumouse_dev->mutex, + &mac_hid_emumouse_dev_mutex_class); + + mac_hid_emumouse_dev->name = "Macintosh mouse button emulation"; + mac_hid_emumouse_dev->id.bustype = BUS_ADB; + mac_hid_emumouse_dev->id.vendor = 0x0001; + mac_hid_emumouse_dev->id.product = 0x0001; + mac_hid_emumouse_dev->id.version = 0x0100; + + mac_hid_emumouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); + mac_hid_emumouse_dev->keybit[BIT_WORD(BTN_MOUSE)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + mac_hid_emumouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + + err = input_register_device(mac_hid_emumouse_dev); + if (err) { + input_free_device(mac_hid_emumouse_dev); + mac_hid_emumouse_dev = NULL; + return err; + } + + return 0; +} + +static void mac_hid_destroy_emumouse(void) +{ + input_unregister_device(mac_hid_emumouse_dev); + mac_hid_emumouse_dev = NULL; +} + +static bool mac_hid_emumouse_filter(struct input_handle *handle, + unsigned int type, unsigned int code, + int value) +{ + unsigned int btn; + + if (type != EV_KEY) + return false; + + if (code == mouse_button2_keycode) + btn = BTN_MIDDLE; + else if (code == mouse_button3_keycode) + btn = BTN_RIGHT; + else + return false; + + input_report_key(mac_hid_emumouse_dev, btn, value); + input_sync(mac_hid_emumouse_dev); + + return true; +} + +static int mac_hid_emumouse_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + /* Don't bind to ourselves */ + if (dev == mac_hid_emumouse_dev) + return -ENODEV; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "mac-button-emul"; + + error = input_register_handle(handle); + if (error) { + printk(KERN_ERR + "mac_hid: Failed to register button emulation handle, " + "error %d\n", error); + goto err_free; + } + + error = input_open_device(handle); + if (error) { + printk(KERN_ERR + "mac_hid: Failed to open input device, error %d\n", + error); + goto err_unregister; + } + + return 0; + + err_unregister: + input_unregister_handle(handle); + err_free: + kfree(handle); + return error; +} + +static void mac_hid_emumouse_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id mac_hid_emumouse_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids); + +static struct input_handler mac_hid_emumouse_handler = { + .filter = mac_hid_emumouse_filter, + .connect = mac_hid_emumouse_connect, + .disconnect = mac_hid_emumouse_disconnect, + .name = "mac-button-emul", + .id_table = mac_hid_emumouse_ids, +}; + +static int mac_hid_start_emulation(void) +{ + int err; + + err = mac_hid_create_emumouse(); + if (err) + return err; + + err = input_register_handler(&mac_hid_emumouse_handler); + if (err) { + mac_hid_destroy_emumouse(); + return err; + } + + return 0; +} + +static void mac_hid_stop_emulation(void) +{ + input_unregister_handler(&mac_hid_emumouse_handler); + mac_hid_destroy_emumouse(); +} + +static int mac_hid_toggle_emumouse(ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int *valp = table->data; + int old_val = *valp; + int rc; + + rc = proc_dointvec(table, write, buffer, lenp, ppos); + + if (rc == 0 && write && *valp != old_val) { + if (*valp == 1) + rc = mac_hid_start_emulation(); + else if (*valp == 0) + mac_hid_stop_emulation(); + else + rc = -EINVAL; + } + + /* Restore the old value in case of error */ + if (rc) + *valp = old_val; + + return rc; +} + /* file(s) in /proc/sys/dev/mac_hid */ static ctl_table mac_hid_files[] = { { @@ -31,7 +209,7 @@ static ctl_table mac_hid_files[] = { .data = &mouse_emulate_buttons, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = mac_hid_toggle_emumouse, }, { .procname = "mouse_button2_keycode", @@ -74,73 +252,12 @@ static ctl_table mac_hid_root_dir[] = { static struct ctl_table_header *mac_hid_sysctl_header; -#endif /* endif CONFIG_SYSCTL */ - -int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) -{ - switch (caller) { - case 1: - /* Called from keyboard.c */ - if (mouse_emulate_buttons - && (keycode == mouse_button2_keycode - || keycode == mouse_button3_keycode)) { - if (mouse_emulate_buttons == 1) { - input_report_key(emumousebtn, - keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, - down); - input_sync(emumousebtn); - return 1; - } - mouse_last_keycode = down ? keycode : 0; - } - break; - } - return 0; -} - -static struct lock_class_key emumousebtn_event_class; -static struct lock_class_key emumousebtn_mutex_class; - -static int emumousebtn_input_register(void) -{ - int ret; - - emumousebtn = input_allocate_device(); - if (!emumousebtn) - return -ENOMEM; - - lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class); - lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class); - - emumousebtn->name = "Macintosh mouse button emulation"; - emumousebtn->id.bustype = BUS_ADB; - emumousebtn->id.vendor = 0x0001; - emumousebtn->id.product = 0x0001; - emumousebtn->id.version = 0x0100; - - emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); - emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - - ret = input_register_device(emumousebtn); - if (ret) - input_free_device(emumousebtn); - - return ret; -} static int __init mac_hid_init(void) { - int err; - - err = emumousebtn_input_register(); - if (err) - return err; - -#if defined(CONFIG_SYSCTL) mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir); -#endif /* CONFIG_SYSCTL */ + if (!mac_hid_sysctl_header) + return -ENOMEM; return 0; } diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index 8bdb16bfe5fb..506ad20c18f8 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -161,7 +161,4 @@ static inline void con_schedule_flip(struct tty_struct *t) schedule_delayed_work(&t->buf.work, 0); } -/* mac_hid.c */ -extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int); - #endif -- GitLab From 429722e19dff319aa87ee552beadee71d41a3655 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 30 Jan 2010 01:44:20 -0800 Subject: [PATCH 1392/3892] Input: Mac button emulation - allow compiling as a module Not all systems require Mac-style button emulation, however distributions enable it by default so it is readily available. Allow compiling it as a module so it can be loaded only on systems that actually require it. Signed-off-by: Dmitry Torokhov --- drivers/macintosh/Kconfig | 8 +++++--- drivers/macintosh/mac_hid.c | 13 +++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index aa3c27e5255d..fd85bde283a0 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -171,9 +171,8 @@ config INPUT_ADBHID If unsure, say Y. config MAC_EMUMOUSEBTN - bool "Support for mouse button 2+3 emulation" - depends on SYSCTL - select INPUT + tristate "Support for mouse button 2+3 emulation" + depends on SYSCTL && INPUT help This provides generic support for emulating the 2nd and 3rd mouse button with keypresses. If you say Y here, the emulation is still @@ -185,6 +184,9 @@ config MAC_EMUMOUSEBTN If you have an Apple machine with a 1-button mouse, say Y here. + To compile this driver as a module, choose M here: the + module will be called mac_hid. + config THERM_WINDTUNNEL tristate "Support for thermal management on Windtunnel G4s" depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64 diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 0b210a90aef5..e943d2a29253 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -14,6 +14,8 @@ #include #include +MODULE_LICENSE("GPL"); + static int mouse_emulate_buttons; static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ @@ -252,7 +254,6 @@ static ctl_table mac_hid_root_dir[] = { static struct ctl_table_header *mac_hid_sysctl_header; - static int __init mac_hid_init(void) { mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir); @@ -261,5 +262,13 @@ static int __init mac_hid_init(void) return 0; } +module_init(mac_hid_init); -device_initcall(mac_hid_init); +static void __exit mac_hid_exit(void) +{ + unregister_sysctl_table(mac_hid_sysctl_header); + + if (mouse_emulate_buttons) + mac_hid_stop_emulation(); +} +module_exit(mac_hid_exit); -- GitLab From a8e6f734ce9a79d44ebb296f2a341f435227b34e Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 30 Jan 2010 20:55:41 +0900 Subject: [PATCH 1393/3892] Revert "perf record: Intercept all events" This reverts commit f5a2c3dce03621b55f84496f58adc2d1a87ca16f. This patch is required for making "perf lock rec" work. The commit f5a2c3dce0 changes write_event() of builtin-record.c . And changed write_event() sometimes doesn't stop with perf lock rec. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: [ that commit also causes perf record to not be Ctrl-C-able, and it's concetually wrong to parse the data at record time (unconditionally - even when not needed), as we eventually want to be able to do zero-copy recording, at least for non-archive recordings. ] Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 90345223908c..eea56910b91c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -113,24 +113,16 @@ static void write_output(void *buf, size_t size) static void write_event(event_t *buf, size_t size) { - size_t processed_size = buf->header.size; - event_t *ev = buf; - - do { - /* - * Add it to the list of DSOs, so that when we finish this - * record session we can pick the available build-ids. - */ - if (ev->header.type == PERF_RECORD_MMAP) { - struct list_head *head = &dsos__user; - if (ev->header.misc == 1) - head = &dsos__kernel; - __dsos__findnew(head, ev->mmap.filename); - } - - ev = ((void *)ev) + ev->header.size; - processed_size += ev->header.size; - } while (processed_size < size); + /* + * Add it to the list of DSOs, so that when we finish this + * record session we can pick the available build-ids. + */ + if (buf->header.type == PERF_RECORD_MMAP) { + struct list_head *head = &dsos__user; + if (buf->mmap.header.misc == 1) + head = &dsos__kernel; + __dsos__findnew(head, buf->mmap.filename); + } write_output(buf, size); } -- GitLab From 86d8d29634de4464d568e7c335c0da6cba64e8ab Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 30 Jan 2010 20:43:23 +0900 Subject: [PATCH 1394/3892] perf tools: Add __data_loc support This patch is required to test the next patch for perf lock. At 064739bc4b3d7f424b2f25547e6611bcf0132415 , support for the modifier "__data_loc" of format is added. But, when I wanted to parse format of lock_acquired (or some event else), raw_field_ptr() did not returned correct pointer. So I modified raw_field_ptr() like this patch. Then raw_field_ptr() works well. Signed-off-by: Hitoshi Mitake Acked-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Tom Zanussi Cc: Steven Rostedt LKML-Reference: <1264851813-8413-2-git-send-email-mitake@dcl.info.waseda.ac.jp> [ v3: fixed minor stylistic detail ] Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index c5c32be040bf..c4b3cb8a02b1 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1925,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data) if (!field) return NULL; + if (field->flags & FIELD_IS_STRING) { + int offset; + + offset = *(int *)(data + field->offset); + offset &= 0xffff; + + return data + offset; + } + return data + field->offset; } -- GitLab From 18e97e06b5fb2d7f6cf272ca07d26d8247db8723 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 30 Jan 2010 20:43:24 +0900 Subject: [PATCH 1395/3892] perf: Add util/include/linuxhash.h to include hash.h of kernel linux/hash.h, hash header of kernel, is also useful for perf. util/include/linuxhash.h includes linux/hash.h, so we can use hash facilities (e.g. hash_long()) in perf now. Signed-off-by: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1264851813-8413-3-git-send-email-mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 + tools/perf/util/include/linux/hash.h | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 tools/perf/util/include/linux/hash.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 9b173e66fb41..b2bce1fb4ae1 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -333,6 +333,7 @@ LIB_FILE=libperf.a LIB_H += ../../include/linux/perf_event.h LIB_H += ../../include/linux/rbtree.h LIB_H += ../../include/linux/list.h +LIB_H += ../../include/linux/hash.h LIB_H += ../../include/linux/stringify.h LIB_H += util/include/linux/bitmap.h LIB_H += util/include/linux/bitops.h diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h new file mode 100644 index 000000000000..201f57397997 --- /dev/null +++ b/tools/perf/util/include/linux/hash.h @@ -0,0 +1,5 @@ +#include "../../../../include/linux/hash.h" + +#ifndef PERF_HASH_H +#define PERF_HASH_H +#endif -- GitLab From c965be10ca3cb0bdd04016c852764afaf8e647c8 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 30 Jan 2010 20:43:32 +0900 Subject: [PATCH 1396/3892] perf lock: Enhance information of lock trace events Add wait time and lock identification details. Signed-off-by: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1264851813-8413-11-git-send-email-mitake@dcl.info.waseda.ac.jp> [ removed the file/line bits as we can do that better via IPs ] Signed-off-by: Ingo Molnar --- include/trace/events/lock.h | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/include/trace/events/lock.h b/include/trace/events/lock.h index a870ba125aa8..5c1dcfc16c60 100644 --- a/include/trace/events/lock.h +++ b/include/trace/events/lock.h @@ -20,14 +20,17 @@ TRACE_EVENT(lock_acquire, TP_STRUCT__entry( __field(unsigned int, flags) __string(name, lock->name) + __field(void *, lockdep_addr) ), TP_fast_assign( __entry->flags = (trylock ? 1 : 0) | (read ? 2 : 0); __assign_str(name, lock->name); + __entry->lockdep_addr = lock; ), - TP_printk("%s%s%s", (__entry->flags & 1) ? "try " : "", + TP_printk("%p %s%s%s", __entry->lockdep_addr, + (__entry->flags & 1) ? "try " : "", (__entry->flags & 2) ? "read " : "", __get_str(name)) ); @@ -40,13 +43,16 @@ TRACE_EVENT(lock_release, TP_STRUCT__entry( __string(name, lock->name) + __field(void *, lockdep_addr) ), TP_fast_assign( __assign_str(name, lock->name); + __entry->lockdep_addr = lock; ), - TP_printk("%s", __get_str(name)) + TP_printk("%p %s", + __entry->lockdep_addr, __get_str(name)) ); #ifdef CONFIG_LOCK_STAT @@ -59,13 +65,16 @@ TRACE_EVENT(lock_contended, TP_STRUCT__entry( __string(name, lock->name) + __field(void *, lockdep_addr) ), TP_fast_assign( __assign_str(name, lock->name); + __entry->lockdep_addr = lock; ), - TP_printk("%s", __get_str(name)) + TP_printk("%p %s", + __entry->lockdep_addr, __get_str(name)) ); TRACE_EVENT(lock_acquired, @@ -75,16 +84,18 @@ TRACE_EVENT(lock_acquired, TP_STRUCT__entry( __string(name, lock->name) - __field(unsigned long, wait_usec) - __field(unsigned long, wait_nsec_rem) + __field(s64, wait_nsec) + __field(void *, lockdep_addr) ), + TP_fast_assign( __assign_str(name, lock->name); - __entry->wait_nsec_rem = do_div(waittime, NSEC_PER_USEC); - __entry->wait_usec = (unsigned long) waittime; + __entry->wait_nsec = waittime; + __entry->lockdep_addr = lock; ), - TP_printk("%s (%lu.%03lu us)", __get_str(name), __entry->wait_usec, - __entry->wait_nsec_rem) + TP_printk("%p %s (%llu ns)", __entry->lockdep_addr, + __get_str(name), + __entry->wait_nsec) ); #endif -- GitLab From 9b5e350c7a46a471d5b452836dbafe9aeaeca435 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Sat, 30 Jan 2010 20:43:33 +0900 Subject: [PATCH 1397/3892] perf lock: Introduce new tool "perf lock", for analyzing lock statistics Adding new subcommand "perf lock" to perf. I have a lot of remaining ToDos, but for now perf lock can already provide minimal functionality for analyzing lock statistics. Signed-off-by: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1264851813-8413-12-git-send-email-mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 + tools/perf/builtin-lock.c | 724 ++++++++++++++++++++++++++++++++++++++ tools/perf/builtin.h | 1 + tools/perf/perf.c | 1 + 4 files changed, 727 insertions(+) create mode 100644 tools/perf/builtin-lock.c diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b2bce1fb4ae1..42969303e20b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -456,6 +456,7 @@ BUILTIN_OBJS += builtin-top.o BUILTIN_OBJS += builtin-trace.o BUILTIN_OBJS += builtin-probe.o BUILTIN_OBJS += builtin-kmem.o +BUILTIN_OBJS += builtin-lock.o PERFLIBS = $(LIB_FILE) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c new file mode 100644 index 000000000000..2b5f88754c26 --- /dev/null +++ b/tools/perf/builtin-lock.c @@ -0,0 +1,724 @@ +#include "builtin.h" +#include "perf.h" + +#include "util/util.h" +#include "util/cache.h" +#include "util/symbol.h" +#include "util/thread.h" +#include "util/header.h" + +#include "util/parse-options.h" +#include "util/trace-event.h" + +#include "util/debug.h" +#include "util/session.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* based on kernel/lockdep.c */ +#define LOCKHASH_BITS 12 +#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS) + +static struct list_head lockhash_table[LOCKHASH_SIZE]; + +#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS) +#define lockhashentry(key) (lockhash_table + __lockhashfn((key))) + +#define LOCK_STATE_UNLOCKED 0 /* initial state */ +#define LOCK_STATE_LOCKED 1 + +struct lock_stat { + struct list_head hash_entry; + struct rb_node rb; /* used for sorting */ + + /* FIXME: raw_field_value() returns unsigned long long, + * so address of lockdep_map should be dealed as 64bit. + * Is there more better solution? */ + void *addr; /* address of lockdep_map, used as ID */ + char *name; /* for strcpy(), we cannot use const */ + char *file; + unsigned int line; + + int state; + u64 prev_event_time; /* timestamp of previous event */ + + unsigned int nr_acquired; + unsigned int nr_acquire; + unsigned int nr_contended; + unsigned int nr_release; + + /* these times are in nano sec. */ + u64 wait_time_total; + u64 wait_time_min; + u64 wait_time_max; +}; + +/* build simple key function one is bigger than two */ +#define SINGLE_KEY(member) \ + static int lock_stat_key_ ## member(struct lock_stat *one, \ + struct lock_stat *two) \ + { \ + return one->member > two->member; \ + } + +SINGLE_KEY(nr_acquired) +SINGLE_KEY(nr_contended) +SINGLE_KEY(wait_time_total) +SINGLE_KEY(wait_time_min) +SINGLE_KEY(wait_time_max) + +struct lock_key { + /* + * name: the value for specify by user + * this should be simpler than raw name of member + * e.g. nr_acquired -> acquired, wait_time_total -> wait_total + */ + const char *name; + int (*key)(struct lock_stat*, struct lock_stat*); +}; + +static const char *sort_key = "acquired"; +static int (*compare)(struct lock_stat *, struct lock_stat *); + +#define DEF_KEY_LOCK(name, fn_suffix) \ + { #name, lock_stat_key_ ## fn_suffix } +struct lock_key keys[] = { + DEF_KEY_LOCK(acquired, nr_acquired), + DEF_KEY_LOCK(contended, nr_contended), + DEF_KEY_LOCK(wait_total, wait_time_total), + DEF_KEY_LOCK(wait_min, wait_time_min), + DEF_KEY_LOCK(wait_max, wait_time_max), + + /* extra comparisons much complicated should be here */ + + { NULL, NULL } +}; + +static void select_key(void) +{ + int i; + + for (i = 0; keys[i].name; i++) { + if (!strcmp(keys[i].name, sort_key)) { + compare = keys[i].key; + return; + } + } + + die("Unknown compare key:%s\n", sort_key); +} + +static struct rb_root result; /* place to store sorted data */ + +static void insert_to_result(struct lock_stat *st, + int (*bigger)(struct lock_stat *, + struct lock_stat *)) +{ + struct rb_node **rb = &result.rb_node; + struct rb_node *parent = NULL; + struct lock_stat *p; + + while (*rb) { + p = container_of(*rb, struct lock_stat, rb); + parent = *rb; + + if (bigger(st, p)) + rb = &(*rb)->rb_left; + else + rb = &(*rb)->rb_right; + } + + rb_link_node(&st->rb, parent, rb); + rb_insert_color(&st->rb, &result); +} + +/* returns left most element of result, and erase it */ +static struct lock_stat *pop_from_result(void) +{ + struct rb_node *node = result.rb_node; + + if (!node) + return NULL; + + while (node->rb_left) + node = node->rb_left; + + rb_erase(node, &result); + return container_of(node, struct lock_stat, rb); +} + +static struct lock_stat *lock_stat_findnew(void *addr, const char *name, + const char *file, unsigned int line) +{ + struct list_head *entry = lockhashentry(addr); + struct lock_stat *ret, *new; + + list_for_each_entry(ret, entry, hash_entry) { + if (ret->addr == addr) + return ret; + } + + new = zalloc(sizeof(struct lock_stat)); + if (!new) + goto alloc_failed; + + new->addr = addr; + new->name = zalloc(sizeof(char) * strlen(name) + 1); + if (!new->name) + goto alloc_failed; + strcpy(new->name, name); + new->file = zalloc(sizeof(char) * strlen(file) + 1); + if (!new->file) + goto alloc_failed; + strcpy(new->file, file); + new->line = line; + + /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */ + new->state = LOCK_STATE_UNLOCKED; + new->wait_time_min = ULLONG_MAX; + + list_add(&new->hash_entry, entry); + return new; + +alloc_failed: + die("memory allocation failed\n"); +} + +static char const *input_name = "perf.data"; + +static int profile_cpu = -1; + +struct raw_event_sample { + u32 size; + char data[0]; +}; + +struct trace_acquire_event { + void *addr; + const char *name; + const char *file; + unsigned int line; +}; + +struct trace_acquired_event { + void *addr; + const char *name; + const char *file; + unsigned int line; +}; + +struct trace_contended_event { + void *addr; + const char *name; + const char *file; + unsigned int line; +}; + +struct trace_release_event { + void *addr; + const char *name; + const char *file; + unsigned int line; +}; + +struct trace_lock_handler { + void (*acquire_event)(struct trace_acquire_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); + + void (*acquired_event)(struct trace_acquired_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); + + void (*contended_event)(struct trace_contended_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); + + void (*release_event)(struct trace_release_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); +}; + +static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event, + struct event *__event __used, + int cpu __used, + u64 timestamp, + struct thread *thread __used) +{ + struct lock_stat *st; + + st = lock_stat_findnew(acquire_event->addr, acquire_event->name, + acquire_event->file, acquire_event->line); + + switch (st->state) { + case LOCK_STATE_UNLOCKED: + break; + case LOCK_STATE_LOCKED: + break; + default: + BUG_ON(1); + break; + } + + st->prev_event_time = timestamp; +} + +static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event, + struct event *__event __used, + int cpu __used, + u64 timestamp, + struct thread *thread __used) +{ + struct lock_stat *st; + + st = lock_stat_findnew(acquired_event->addr, acquired_event->name, + acquired_event->file, acquired_event->line); + + switch (st->state) { + case LOCK_STATE_UNLOCKED: + st->state = LOCK_STATE_LOCKED; + st->nr_acquired++; + break; + case LOCK_STATE_LOCKED: + break; + default: + BUG_ON(1); + break; + } + + st->prev_event_time = timestamp; +} + +static void prof_lock_contended_event(struct trace_contended_event *contended_event, + struct event *__event __used, + int cpu __used, + u64 timestamp, + struct thread *thread __used) +{ + struct lock_stat *st; + + st = lock_stat_findnew(contended_event->addr, contended_event->name, + contended_event->file, contended_event->line); + + switch (st->state) { + case LOCK_STATE_UNLOCKED: + break; + case LOCK_STATE_LOCKED: + st->nr_contended++; + break; + default: + BUG_ON(1); + break; + } + + st->prev_event_time = timestamp; +} + +static void prof_lock_release_event(struct trace_release_event *release_event, + struct event *__event __used, + int cpu __used, + u64 timestamp, + struct thread *thread __used) +{ + struct lock_stat *st; + u64 hold_time; + + st = lock_stat_findnew(release_event->addr, release_event->name, + release_event->file, release_event->line); + + switch (st->state) { + case LOCK_STATE_UNLOCKED: + break; + case LOCK_STATE_LOCKED: + st->state = LOCK_STATE_UNLOCKED; + hold_time = timestamp - st->prev_event_time; + + if (timestamp < st->prev_event_time) { + /* terribly, this can happen... */ + goto end; + } + + if (st->wait_time_min > hold_time) + st->wait_time_min = hold_time; + if (st->wait_time_max < hold_time) + st->wait_time_max = hold_time; + st->wait_time_total += hold_time; + + st->nr_release++; + break; + default: + BUG_ON(1); + break; + } + +end: + st->prev_event_time = timestamp; +} + +/* lock oriented handlers */ +/* TODO: handlers for CPU oriented, thread oriented */ +static struct trace_lock_handler prof_lock_ops = { + .acquire_event = prof_lock_acquire_event, + .acquired_event = prof_lock_acquired_event, + .contended_event = prof_lock_contended_event, + .release_event = prof_lock_release_event, +}; + +static struct trace_lock_handler *trace_handler; + +static void +process_lock_acquire_event(void *data, + struct event *event __used, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_acquire_event acquire_event; + u64 tmp; /* this is required for casting... */ + + tmp = raw_field_value(event, "lockdep_addr", data); + memcpy(&acquire_event.addr, &tmp, sizeof(void *)); + acquire_event.name = (char *)raw_field_ptr(event, "name", data); + acquire_event.file = (char *)raw_field_ptr(event, "file", data); + acquire_event.line = + (unsigned int)raw_field_value(event, "line", data); + + if (trace_handler->acquire_event) { + trace_handler->acquire_event(&acquire_event, + event, cpu, timestamp, thread); + } +} + +static void +process_lock_acquired_event(void *data, + struct event *event __used, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_acquired_event acquired_event; + u64 tmp; /* this is required for casting... */ + + tmp = raw_field_value(event, "lockdep_addr", data); + memcpy(&acquired_event.addr, &tmp, sizeof(void *)); + acquired_event.name = (char *)raw_field_ptr(event, "name", data); + acquired_event.file = (char *)raw_field_ptr(event, "file", data); + acquired_event.line = + (unsigned int)raw_field_value(event, "line", data); + + if (trace_handler->acquire_event) { + trace_handler->acquired_event(&acquired_event, + event, cpu, timestamp, thread); + } +} + +static void +process_lock_contended_event(void *data, + struct event *event __used, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_contended_event contended_event; + u64 tmp; /* this is required for casting... */ + + tmp = raw_field_value(event, "lockdep_addr", data); + memcpy(&contended_event.addr, &tmp, sizeof(void *)); + contended_event.name = (char *)raw_field_ptr(event, "name", data); + contended_event.file = (char *)raw_field_ptr(event, "file", data); + contended_event.line = + (unsigned int)raw_field_value(event, "line", data); + + if (trace_handler->acquire_event) { + trace_handler->contended_event(&contended_event, + event, cpu, timestamp, thread); + } +} + +static void +process_lock_release_event(void *data, + struct event *event __used, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_release_event release_event; + u64 tmp; /* this is required for casting... */ + + tmp = raw_field_value(event, "lockdep_addr", data); + memcpy(&release_event.addr, &tmp, sizeof(void *)); + release_event.name = (char *)raw_field_ptr(event, "name", data); + release_event.file = (char *)raw_field_ptr(event, "file", data); + release_event.line = + (unsigned int)raw_field_value(event, "line", data); + + if (trace_handler->acquire_event) { + trace_handler->release_event(&release_event, + event, cpu, timestamp, thread); + } +} + +static void +process_raw_event(void *data, int cpu, + u64 timestamp, struct thread *thread) +{ + struct event *event; + int type; + + type = trace_parse_common_type(data); + event = trace_find_event(type); + + if (!strcmp(event->name, "lock_acquire")) + process_lock_acquire_event(data, event, cpu, timestamp, thread); + if (!strcmp(event->name, "lock_acquired")) + process_lock_acquired_event(data, event, cpu, timestamp, thread); + if (!strcmp(event->name, "lock_contended")) + process_lock_contended_event(data, event, cpu, timestamp, thread); + if (!strcmp(event->name, "lock_release")) + process_lock_release_event(data, event, cpu, timestamp, thread); +} + +static int process_sample_event(event_t *event, struct perf_session *session) +{ + struct thread *thread; + struct sample_data data; + + bzero(&data, sizeof(struct sample_data)); + event__parse_sample(event, session->sample_type, &data); + thread = perf_session__findnew(session, data.pid); + + /* + * FIXME: this causes warn on 32bit environment + * because of (void *)data.ip (type of data.ip is u64) + */ +/* dump_printf("(IP, %d): %d/%d: %p period: %llu\n", */ +/* event->header.misc, */ +/* data.pid, data.tid, (void *)data.ip, data.period); */ + + if (thread == NULL) { + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + + if (profile_cpu != -1 && profile_cpu != (int) data.cpu) + return 0; + + process_raw_event(data.raw_data, data.cpu, data.time, thread); + + return 0; +} + +/* TODO: various way to print, coloring, nano or milli sec */ +static void print_result(void) +{ + struct lock_stat *st; + char cut_name[20]; + + printf("%18s ", "ID"); + printf("%20s ", "Name"); + printf("%10s ", "acquired"); + printf("%10s ", "contended"); + + printf("%15s ", "total wait (ns)"); + printf("%15s ", "max wait (ns)"); + printf("%15s ", "min wait (ns)"); + + printf("\n\n"); + + while ((st = pop_from_result())) { + bzero(cut_name, 20); + + printf("%p ", st->addr); + + if (strlen(st->name) < 16) { + /* output raw name */ + printf("%20s ", st->name); + } else { + strncpy(cut_name, st->name, 16); + cut_name[16] = '.'; + cut_name[17] = '.'; + cut_name[18] = '.'; + cut_name[19] = '\0'; + /* cut off name for saving output style */ + printf("%20s ", cut_name); + } + + printf("%10u ", st->nr_acquired); + printf("%10u ", st->nr_contended); + + printf("%15llu ", st->wait_time_total); + printf("%15llu ", st->wait_time_max); + printf("%15llu ", st->wait_time_min == ULLONG_MAX ? + 0 : st->wait_time_min); + printf("\n"); + } +} + +static void dump_map(void) +{ + unsigned int i; + struct lock_stat *st; + + for (i = 0; i < LOCKHASH_SIZE; i++) { + list_for_each_entry(st, &lockhash_table[i], hash_entry) { + printf("%p: %s (src: %s, line: %u)\n", + st->addr, st->name, st->file, st->line); + } + } +} + +static struct perf_event_ops eops = { + .sample = process_sample_event, + .comm = event__process_comm, +}; + +static struct perf_session *session; + +static int read_events(void) +{ + session = perf_session__new(input_name, O_RDONLY, 0); + if (!session) + die("Initializing perf session failed\n"); + + return perf_session__process_events(session, &eops); +} + +static void sort_result(void) +{ + unsigned int i; + struct lock_stat *st; + + for (i = 0; i < LOCKHASH_SIZE; i++) { + list_for_each_entry(st, &lockhash_table[i], hash_entry) { + insert_to_result(st, compare); + } + } +} + +static void __cmd_prof(void) +{ + setup_pager(); + select_key(); + read_events(); + sort_result(); + print_result(); +} + +static const char * const prof_usage[] = { + "perf sched prof []", + NULL +}; + +static const struct option prof_options[] = { + OPT_STRING('k', "key", &sort_key, "acquired", + "key for sorting"), + /* TODO: type */ + OPT_END() +}; + +static const char * const lock_usage[] = { + "perf lock [] {record|trace|prof}", + NULL +}; + +static const struct option lock_options[] = { + OPT_STRING('i', "input", &input_name, "file", + "input file name"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, + "dump raw trace in ASCII"), + OPT_END() +}; + +static const char *record_args[] = { + "record", + "-a", + "-R", + "-M", + "-f", + "-m", "1024", + "-c", "1", + "-e", "lock:lock_acquire:r", + "-e", "lock:lock_acquired:r", + "-e", "lock:lock_contended:r", + "-e", "lock:lock_release:r", +}; + +static int __cmd_record(int argc, const char **argv) +{ + unsigned int rec_argc, i, j; + const char **rec_argv; + + rec_argc = ARRAY_SIZE(record_args) + argc - 1; + rec_argv = calloc(rec_argc + 1, sizeof(char *)); + + for (i = 0; i < ARRAY_SIZE(record_args); i++) + rec_argv[i] = strdup(record_args[i]); + + for (j = 1; j < (unsigned int)argc; j++, i++) + rec_argv[i] = argv[j]; + + BUG_ON(i != rec_argc); + + return cmd_record(i, rec_argv, NULL); +} + +int cmd_lock(int argc, const char **argv, const char *prefix __used) +{ + unsigned int i; + + symbol__init(); + for (i = 0; i < LOCKHASH_SIZE; i++) + INIT_LIST_HEAD(lockhash_table + i); + + argc = parse_options(argc, argv, lock_options, lock_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + if (!argc) + usage_with_options(lock_usage, lock_options); + + if (!strncmp(argv[0], "rec", 3)) { + return __cmd_record(argc, argv); + } else if (!strncmp(argv[0], "prof", 4)) { + trace_handler = &prof_lock_ops; + if (argc) { + argc = parse_options(argc, argv, + prof_options, prof_usage, 0); + if (argc) + usage_with_options(prof_usage, prof_options); + } + __cmd_prof(); + } else if (!strcmp(argv[0], "trace")) { + /* Aliased to 'perf trace' */ + return cmd_trace(argc, argv, prefix); + } else if (!strcmp(argv[0], "map")) { + /* recycling prof_lock_ops */ + trace_handler = &prof_lock_ops; + setup_pager(); + read_events(); + dump_map(); + } else { + usage_with_options(lock_usage, lock_options); + } + + return 0; +} diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index dee97cfe3794..10fe49e7048a 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -31,5 +31,6 @@ extern int cmd_trace(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_probe(int argc, const char **argv, const char *prefix); extern int cmd_kmem(int argc, const char **argv, const char *prefix); +extern int cmd_lock(int argc, const char **argv, const char *prefix); #endif diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 109b89b30ced..57cb107c1f13 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -303,6 +303,7 @@ static void handle_internal_command(int argc, const char **argv) { "sched", cmd_sched, 0 }, { "probe", cmd_probe, 0 }, { "kmem", cmd_kmem, 0 }, + { "lock", cmd_lock, 0 }, }; unsigned int i; static const char ext[] = STRIP_EXTENSION; -- GitLab From 59f411b62c9282891274e721fea29026b0eda3cc Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 31 Jan 2010 08:27:58 +0100 Subject: [PATCH 1398/3892] perf lock: Clean up various details Fix up a few small stylistic details: - use consistent vertical spacing/alignment - remove line80 artifacts - group some global variables better - remove dead code Plus rename 'prof' to 'report' to make it more in line with other tools, and remove the line/file keying as we really want to use IPs like the other tools do. Signed-off-by: Ingo Molnar Cc: Hitoshi Mitake Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1264851813-8413-12-git-send-email-mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar --- tools/perf/builtin-lock.c | 210 +++++++++++++++----------------------- 1 file changed, 82 insertions(+), 128 deletions(-) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 2b5f88754c26..fb9ab2ad3f92 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -32,37 +32,37 @@ static struct list_head lockhash_table[LOCKHASH_SIZE]; #define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS) #define lockhashentry(key) (lockhash_table + __lockhashfn((key))) -#define LOCK_STATE_UNLOCKED 0 /* initial state */ -#define LOCK_STATE_LOCKED 1 +#define LOCK_STATE_UNLOCKED 0 /* initial state */ +#define LOCK_STATE_LOCKED 1 struct lock_stat { - struct list_head hash_entry; - struct rb_node rb; /* used for sorting */ + struct list_head hash_entry; + struct rb_node rb; /* used for sorting */ - /* FIXME: raw_field_value() returns unsigned long long, + /* + * FIXME: raw_field_value() returns unsigned long long, * so address of lockdep_map should be dealed as 64bit. - * Is there more better solution? */ - void *addr; /* address of lockdep_map, used as ID */ - char *name; /* for strcpy(), we cannot use const */ - char *file; - unsigned int line; + * Is there more better solution? + */ + void *addr; /* address of lockdep_map, used as ID */ + char *name; /* for strcpy(), we cannot use const */ - int state; - u64 prev_event_time; /* timestamp of previous event */ + int state; + u64 prev_event_time; /* timestamp of previous event */ - unsigned int nr_acquired; - unsigned int nr_acquire; - unsigned int nr_contended; - unsigned int nr_release; + unsigned int nr_acquired; + unsigned int nr_acquire; + unsigned int nr_contended; + unsigned int nr_release; /* these times are in nano sec. */ - u64 wait_time_total; - u64 wait_time_min; - u64 wait_time_max; + u64 wait_time_total; + u64 wait_time_min; + u64 wait_time_max; }; /* build simple key function one is bigger than two */ -#define SINGLE_KEY(member) \ +#define SINGLE_KEY(member) \ static int lock_stat_key_ ## member(struct lock_stat *one, \ struct lock_stat *two) \ { \ @@ -81,12 +81,15 @@ struct lock_key { * this should be simpler than raw name of member * e.g. nr_acquired -> acquired, wait_time_total -> wait_total */ - const char *name; - int (*key)(struct lock_stat*, struct lock_stat*); + const char *name; + int (*key)(struct lock_stat*, struct lock_stat*); }; -static const char *sort_key = "acquired"; -static int (*compare)(struct lock_stat *, struct lock_stat *); +static const char *sort_key = "acquired"; + +static int (*compare)(struct lock_stat *, struct lock_stat *); + +static struct rb_root result; /* place to store sorted data */ #define DEF_KEY_LOCK(name, fn_suffix) \ { #name, lock_stat_key_ ## fn_suffix } @@ -116,11 +119,8 @@ static void select_key(void) die("Unknown compare key:%s\n", sort_key); } -static struct rb_root result; /* place to store sorted data */ - static void insert_to_result(struct lock_stat *st, - int (*bigger)(struct lock_stat *, - struct lock_stat *)) + int (*bigger)(struct lock_stat *, struct lock_stat *)) { struct rb_node **rb = &result.rb_node; struct rb_node *parent = NULL; @@ -155,8 +155,7 @@ static struct lock_stat *pop_from_result(void) return container_of(node, struct lock_stat, rb); } -static struct lock_stat *lock_stat_findnew(void *addr, const char *name, - const char *file, unsigned int line) +static struct lock_stat *lock_stat_findnew(void *addr, const char *name) { struct list_head *entry = lockhashentry(addr); struct lock_stat *ret, *new; @@ -175,11 +174,6 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name, if (!new->name) goto alloc_failed; strcpy(new->name, name); - new->file = zalloc(sizeof(char) * strlen(file) + 1); - if (!new->file) - goto alloc_failed; - strcpy(new->file, file); - new->line = line; /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */ new->state = LOCK_STATE_UNLOCKED; @@ -197,36 +191,28 @@ static char const *input_name = "perf.data"; static int profile_cpu = -1; struct raw_event_sample { - u32 size; - char data[0]; + u32 size; + char data[0]; }; struct trace_acquire_event { - void *addr; - const char *name; - const char *file; - unsigned int line; + void *addr; + const char *name; }; struct trace_acquired_event { - void *addr; - const char *name; - const char *file; - unsigned int line; + void *addr; + const char *name; }; struct trace_contended_event { - void *addr; - const char *name; - const char *file; - unsigned int line; + void *addr; + const char *name; }; struct trace_release_event { - void *addr; - const char *name; - const char *file; - unsigned int line; + void *addr; + const char *name; }; struct trace_lock_handler { @@ -255,7 +241,8 @@ struct trace_lock_handler { struct thread *thread); }; -static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event, +static void +report_lock_acquire_event(struct trace_acquire_event *acquire_event, struct event *__event __used, int cpu __used, u64 timestamp, @@ -263,8 +250,7 @@ static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event, { struct lock_stat *st; - st = lock_stat_findnew(acquire_event->addr, acquire_event->name, - acquire_event->file, acquire_event->line); + st = lock_stat_findnew(acquire_event->addr, acquire_event->name); switch (st->state) { case LOCK_STATE_UNLOCKED: @@ -279,7 +265,8 @@ static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event, st->prev_event_time = timestamp; } -static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event, +static void +report_lock_acquired_event(struct trace_acquired_event *acquired_event, struct event *__event __used, int cpu __used, u64 timestamp, @@ -287,8 +274,7 @@ static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event { struct lock_stat *st; - st = lock_stat_findnew(acquired_event->addr, acquired_event->name, - acquired_event->file, acquired_event->line); + st = lock_stat_findnew(acquired_event->addr, acquired_event->name); switch (st->state) { case LOCK_STATE_UNLOCKED: @@ -305,7 +291,8 @@ static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event st->prev_event_time = timestamp; } -static void prof_lock_contended_event(struct trace_contended_event *contended_event, +static void +report_lock_contended_event(struct trace_contended_event *contended_event, struct event *__event __used, int cpu __used, u64 timestamp, @@ -313,8 +300,7 @@ static void prof_lock_contended_event(struct trace_contended_event *contended_ev { struct lock_stat *st; - st = lock_stat_findnew(contended_event->addr, contended_event->name, - contended_event->file, contended_event->line); + st = lock_stat_findnew(contended_event->addr, contended_event->name); switch (st->state) { case LOCK_STATE_UNLOCKED: @@ -330,7 +316,8 @@ static void prof_lock_contended_event(struct trace_contended_event *contended_ev st->prev_event_time = timestamp; } -static void prof_lock_release_event(struct trace_release_event *release_event, +static void +report_lock_release_event(struct trace_release_event *release_event, struct event *__event __used, int cpu __used, u64 timestamp, @@ -339,8 +326,7 @@ static void prof_lock_release_event(struct trace_release_event *release_event, struct lock_stat *st; u64 hold_time; - st = lock_stat_findnew(release_event->addr, release_event->name, - release_event->file, release_event->line); + st = lock_stat_findnew(release_event->addr, release_event->name); switch (st->state) { case LOCK_STATE_UNLOCKED: @@ -373,11 +359,11 @@ end: /* lock oriented handlers */ /* TODO: handlers for CPU oriented, thread oriented */ -static struct trace_lock_handler prof_lock_ops = { - .acquire_event = prof_lock_acquire_event, - .acquired_event = prof_lock_acquired_event, - .contended_event = prof_lock_contended_event, - .release_event = prof_lock_release_event, +static struct trace_lock_handler report_lock_ops = { + .acquire_event = report_lock_acquire_event, + .acquired_event = report_lock_acquired_event, + .contended_event = report_lock_contended_event, + .release_event = report_lock_release_event, }; static struct trace_lock_handler *trace_handler; @@ -395,14 +381,9 @@ process_lock_acquire_event(void *data, tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&acquire_event.addr, &tmp, sizeof(void *)); acquire_event.name = (char *)raw_field_ptr(event, "name", data); - acquire_event.file = (char *)raw_field_ptr(event, "file", data); - acquire_event.line = - (unsigned int)raw_field_value(event, "line", data); - if (trace_handler->acquire_event) { - trace_handler->acquire_event(&acquire_event, - event, cpu, timestamp, thread); - } + if (trace_handler->acquire_event) + trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread); } static void @@ -418,14 +399,9 @@ process_lock_acquired_event(void *data, tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&acquired_event.addr, &tmp, sizeof(void *)); acquired_event.name = (char *)raw_field_ptr(event, "name", data); - acquired_event.file = (char *)raw_field_ptr(event, "file", data); - acquired_event.line = - (unsigned int)raw_field_value(event, "line", data); - if (trace_handler->acquire_event) { - trace_handler->acquired_event(&acquired_event, - event, cpu, timestamp, thread); - } + if (trace_handler->acquire_event) + trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread); } static void @@ -441,14 +417,9 @@ process_lock_contended_event(void *data, tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&contended_event.addr, &tmp, sizeof(void *)); contended_event.name = (char *)raw_field_ptr(event, "name", data); - contended_event.file = (char *)raw_field_ptr(event, "file", data); - contended_event.line = - (unsigned int)raw_field_value(event, "line", data); - if (trace_handler->acquire_event) { - trace_handler->contended_event(&contended_event, - event, cpu, timestamp, thread); - } + if (trace_handler->acquire_event) + trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread); } static void @@ -464,14 +435,9 @@ process_lock_release_event(void *data, tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&release_event.addr, &tmp, sizeof(void *)); release_event.name = (char *)raw_field_ptr(event, "name", data); - release_event.file = (char *)raw_field_ptr(event, "file", data); - release_event.line = - (unsigned int)raw_field_value(event, "line", data); - if (trace_handler->acquire_event) { - trace_handler->release_event(&release_event, - event, cpu, timestamp, thread); - } + if (trace_handler->acquire_event) + trace_handler->release_event(&release_event, event, cpu, timestamp, thread); } static void @@ -503,14 +469,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) event__parse_sample(event, session->sample_type, &data); thread = perf_session__findnew(session, data.pid); - /* - * FIXME: this causes warn on 32bit environment - * because of (void *)data.ip (type of data.ip is u64) - */ -/* dump_printf("(IP, %d): %d/%d: %p period: %llu\n", */ -/* event->header.misc, */ -/* data.pid, data.tid, (void *)data.ip, data.period); */ - if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", event->header.type); @@ -580,15 +538,14 @@ static void dump_map(void) for (i = 0; i < LOCKHASH_SIZE; i++) { list_for_each_entry(st, &lockhash_table[i], hash_entry) { - printf("%p: %s (src: %s, line: %u)\n", - st->addr, st->name, st->file, st->line); + printf("%p: %s\n", st->addr, st->name); } } } static struct perf_event_ops eops = { - .sample = process_sample_event, - .comm = event__process_comm, + .sample = process_sample_event, + .comm = event__process_comm, }; static struct perf_session *session; @@ -614,7 +571,7 @@ static void sort_result(void) } } -static void __cmd_prof(void) +static void __cmd_report(void) { setup_pager(); select_key(); @@ -623,12 +580,12 @@ static void __cmd_prof(void) print_result(); } -static const char * const prof_usage[] = { - "perf sched prof []", +static const char * const report_usage[] = { + "perf lock report []", NULL }; -static const struct option prof_options[] = { +static const struct option report_options[] = { OPT_STRING('k', "key", &sort_key, "acquired", "key for sorting"), /* TODO: type */ @@ -636,17 +593,14 @@ static const struct option prof_options[] = { }; static const char * const lock_usage[] = { - "perf lock [] {record|trace|prof}", + "perf lock [] {record|trace|report}", NULL }; static const struct option lock_options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_BOOLEAN('v', "verbose", &verbose, - "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, - "dump raw trace in ASCII"), + OPT_STRING('i', "input", &input_name, "file", "input file name"), + OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_END() }; @@ -698,21 +652,21 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used) if (!strncmp(argv[0], "rec", 3)) { return __cmd_record(argc, argv); - } else if (!strncmp(argv[0], "prof", 4)) { - trace_handler = &prof_lock_ops; + } else if (!strncmp(argv[0], "report", 6)) { + trace_handler = &report_lock_ops; if (argc) { argc = parse_options(argc, argv, - prof_options, prof_usage, 0); + report_options, report_usage, 0); if (argc) - usage_with_options(prof_usage, prof_options); + usage_with_options(report_usage, report_options); } - __cmd_prof(); + __cmd_report(); } else if (!strcmp(argv[0], "trace")) { /* Aliased to 'perf trace' */ return cmd_trace(argc, argv, prefix); } else if (!strcmp(argv[0], "map")) { - /* recycling prof_lock_ops */ - trace_handler = &prof_lock_ops; + /* recycling report_lock_ops */ + trace_handler = &report_lock_ops; setup_pager(); read_events(); dump_map(); -- GitLab From 76cdc083f4d1a2a12a961634672fb9ca7adca29c Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Sun, 31 Jan 2010 17:52:07 -0800 Subject: [PATCH 1399/3892] Input: add imx-keypad driver to support the IMX Keypad Port The IMX family of Application Processors is shipped with a Keypad Port supported by this driver. The peripheral can control up to an 8x8 matrix key pad where all the scanning is done via software. The hardware provides two interrupts: one for key presses (KDI) and one for all key releases (KRI). There is also a simple circuit for glitch reduction (said for synchronization) made by two series of 3 D-latches clocked by the keypad-clock that stabilize the interrupts sources. KDI and KRI are fired only if the respective conditions are maintained for at last 4 keypad-clock cycle. Since those circuits are poor for a correct debounce process (the keypad-clock frequency is 32K and bounces longer than 94us are not masked) the driver, when an interrupt arrives, samples the matrix with a period of 10ms until the readins are stable for IMX_KEYPAD_SCANS_FOR_STABILITY times (currently set at 3). After getting stable result appropriate events are sent through the input stack. If some keys are maintained pressed, the driver continues to scan the matrix with a longer period (60ms) to catch possible multiple key presses without overloading the cpu. This process ends when all keys are released. This driver is tested to build in kernel or as a module and follow the specification of Freescale Application processors: i.MX25 i.MX27 i.MX31 i.MX35 i.MX51 especially tested on i.MX31. Signed-off-by: Alberto Panizzo Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 9 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/imx_keypad.c | 594 ++++++++++++++++++++++++++++ 3 files changed, 604 insertions(+) create mode 100644 drivers/input/keyboard/imx_keypad.c diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c72283c6916f..616a3916d187 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -292,6 +292,15 @@ config KEYBOARD_MAX7359 To compile this driver as a module, choose M here: the module will be called max7359_keypad. +config KEYBOARD_IMX + tristate "IMX keypad support" + depends on ARCH_MXC + help + Enable support for IMX keypad port. + + To compile this driver as a module, choose M here: the + module will be called imx_keypad. + config KEYBOARD_NEWTON tristate "Newton keyboard" select SERIO diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 78654ef65206..706c6b5ed5f4 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o +obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c new file mode 100644 index 000000000000..2ee5b798024d --- /dev/null +++ b/drivers/input/keyboard/imx_keypad.c @@ -0,0 +1,594 @@ +/* + * Driver for the IMX keypad port. + * Copyright (C) 2009 Alberto Panizzo + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* + * Keypad Controller registers (halfword) + */ +#define KPCR 0x00 /* Keypad Control Register */ + +#define KPSR 0x02 /* Keypad Status Register */ +#define KBD_STAT_KPKD (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */ +#define KBD_STAT_KPKR (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */ +#define KBD_STAT_KDSC (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/ +#define KBD_STAT_KRSS (0x1 << 3) /* Key Release Synch Status bit (w1c)*/ +#define KBD_STAT_KDIE (0x1 << 8) /* Key Depress Interrupt Enable Status bit */ +#define KBD_STAT_KRIE (0x1 << 9) /* Key Release Interrupt Enable */ +#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */ + +#define KDDR 0x04 /* Keypad Data Direction Register */ +#define KPDR 0x06 /* Keypad Data Register */ + +#define MAX_MATRIX_KEY_ROWS 8 +#define MAX_MATRIX_KEY_COLS 8 +#define MATRIX_ROW_SHIFT 3 + +#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) + +struct imx_keypad { + + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + + int irq; + struct timer_list check_matrix_timer; + + /* + * The matrix is stable only if no changes are detected after + * IMX_KEYPAD_SCANS_FOR_STABILITY scans + */ +#define IMX_KEYPAD_SCANS_FOR_STABILITY 3 + int stable_count; + + bool enabled; + + /* Masks for enabled rows/cols */ + unsigned short rows_en_mask; + unsigned short cols_en_mask; + + unsigned short keycodes[MAX_MATRIX_KEY_NUM]; + + /* + * Matrix states: + * -stable: achieved after a complete debounce process. + * -unstable: used in the debouncing process. + */ + unsigned short matrix_stable_state[MAX_MATRIX_KEY_COLS]; + unsigned short matrix_unstable_state[MAX_MATRIX_KEY_COLS]; +}; + +/* Scan the matrix and return the new state in *matrix_volatile_state. */ +static void imx_keypad_scan_matrix(struct imx_keypad *keypad, + unsigned short *matrix_volatile_state) +{ + int col; + unsigned short reg_val; + + for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { + if ((keypad->cols_en_mask & (1 << col)) == 0) + continue; + /* + * Discharge keypad capacitance: + * 2. write 1s on column data. + * 3. configure columns as totem-pole to discharge capacitance. + * 4. configure columns as open-drain. + */ + reg_val = readw(keypad->mmio_base + KPDR); + reg_val |= 0xff00; + writew(reg_val, keypad->mmio_base + KPDR); + + reg_val = readw(keypad->mmio_base + KPCR); + reg_val &= ~((keypad->cols_en_mask & 0xff) << 8); + writew(reg_val, keypad->mmio_base + KPCR); + + udelay(2); + + reg_val = readw(keypad->mmio_base + KPCR); + reg_val |= (keypad->cols_en_mask & 0xff) << 8; + writew(reg_val, keypad->mmio_base + KPCR); + + /* + * 5. Write a single column to 0, others to 1. + * 6. Sample row inputs and save data. + * 7. Repeat steps 2 - 6 for remaining columns. + */ + reg_val = readw(keypad->mmio_base + KPDR); + reg_val &= ~(1 << (8 + col)); + writew(reg_val, keypad->mmio_base + KPDR); + + /* + * Delay added to avoid propagating the 0 from column to row + * when scanning. + */ + udelay(5); + + /* + * 1s in matrix_volatile_state[col] means key pressures + * throw data from non enabled rows. + */ + reg_val = readw(keypad->mmio_base + KPDR); + matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask; + } + + /* + * Return in standby mode: + * 9. write 0s to columns + */ + reg_val = readw(keypad->mmio_base + KPDR); + reg_val &= 0x00ff; + writew(reg_val, keypad->mmio_base + KPDR); +} + +/* + * Compare the new matrix state (volatile) with the stable one stored in + * keypad->matrix_stable_state and fire events if changes are detected. + */ +static void imx_keypad_fire_events(struct imx_keypad *keypad, + unsigned short *matrix_volatile_state) +{ + struct input_dev *input_dev = keypad->input_dev; + int row, col; + + for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { + unsigned short bits_changed; + int code; + + if ((keypad->cols_en_mask & (1 << col)) == 0) + continue; /* Column is not enabled */ + + bits_changed = keypad->matrix_stable_state[col] ^ + matrix_volatile_state[col]; + + if (bits_changed == 0) + continue; /* Column does not contain changes */ + + for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) { + if ((keypad->rows_en_mask & (1 << row)) == 0) + continue; /* Row is not enabled */ + if ((bits_changed & (1 << row)) == 0) + continue; /* Row does not contain changes */ + + code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, keypad->keycodes[code], + matrix_volatile_state[col] & (1 << row)); + dev_dbg(&input_dev->dev, "Event code: %d, val: %d", + keypad->keycodes[code], + matrix_volatile_state[col] & (1 << row)); + } + } + input_sync(input_dev); +} + +/* + * imx_keypad_check_for_events is the timer handler. + */ +static void imx_keypad_check_for_events(unsigned long data) +{ + struct imx_keypad *keypad = (struct imx_keypad *) data; + unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS]; + unsigned short reg_val; + bool state_changed, is_zero_matrix; + int i; + + memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state)); + + imx_keypad_scan_matrix(keypad, matrix_volatile_state); + + state_changed = false; + for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) { + if ((keypad->cols_en_mask & (1 << i)) == 0) + continue; + + if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) { + state_changed = true; + break; + } + } + + /* + * If the matrix state is changed from the previous scan + * (Re)Begin the debouncing process, saving the new state in + * keypad->matrix_unstable_state. + * else + * Increase the count of number of scans with a stable state. + */ + if (state_changed) { + memcpy(keypad->matrix_unstable_state, matrix_volatile_state, + sizeof(matrix_volatile_state)); + keypad->stable_count = 0; + } else + keypad->stable_count++; + + /* + * If the matrix is not as stable as we want reschedule scan + * in the near future. + */ + if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) { + mod_timer(&keypad->check_matrix_timer, + jiffies + msecs_to_jiffies(10)); + return; + } + + /* + * If the matrix state is stable, fire the events and save the new + * stable state. Note, if the matrix is kept stable for longer + * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all + * events have already been generated. + */ + if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) { + imx_keypad_fire_events(keypad, matrix_volatile_state); + + memcpy(keypad->matrix_stable_state, matrix_volatile_state, + sizeof(matrix_volatile_state)); + } + + is_zero_matrix = true; + for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) { + if (matrix_volatile_state[i] != 0) { + is_zero_matrix = false; + break; + } + } + + + if (is_zero_matrix) { + /* + * All keys have been released. Enable only the KDI + * interrupt for future key presses (clear the KDI + * status bit and its sync chain before that). + */ + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC; + writew(reg_val, keypad->mmio_base + KPSR); + + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KDIE; + reg_val &= ~KBD_STAT_KRIE; + writew(reg_val, keypad->mmio_base + KPSR); + } else { + /* + * Some keys are still pressed. Schedule a rescan in + * attempt to detect multiple key presses and enable + * the KRI interrupt to react quickly to key release + * event. + */ + mod_timer(&keypad->check_matrix_timer, + jiffies + msecs_to_jiffies(60)); + + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS; + writew(reg_val, keypad->mmio_base + KPSR); + + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KRIE; + reg_val &= ~KBD_STAT_KDIE; + writew(reg_val, keypad->mmio_base + KPSR); + } +} + +static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id) +{ + struct imx_keypad *keypad = dev_id; + unsigned short reg_val; + + reg_val = readw(keypad->mmio_base + KPSR); + + /* Disable both interrupt types */ + reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE); + /* Clear interrupts status bits */ + reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD; + writew(reg_val, keypad->mmio_base + KPSR); + + if (keypad->enabled) { + /* The matrix is supposed to be changed */ + keypad->stable_count = 0; + + /* Schedule the scanning procedure near in the future */ + mod_timer(&keypad->check_matrix_timer, + jiffies + msecs_to_jiffies(2)); + } + + return IRQ_HANDLED; +} + +static void imx_keypad_config(struct imx_keypad *keypad) +{ + unsigned short reg_val; + + /* + * Include enabled rows in interrupt generation (KPCR[7:0]) + * Configure keypad columns as open-drain (KPCR[15:8]) + */ + reg_val = readw(keypad->mmio_base + KPCR); + reg_val |= keypad->rows_en_mask & 0xff; /* rows */ + reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */ + writew(reg_val, keypad->mmio_base + KPCR); + + /* Write 0's to KPDR[15:8] (Colums) */ + reg_val = readw(keypad->mmio_base + KPDR); + reg_val &= 0x00ff; + writew(reg_val, keypad->mmio_base + KPDR); + + /* Configure columns as output, rows as input (KDDR[15:0]) */ + writew(0xff00, keypad->mmio_base + KDDR); + + /* + * Clear Key Depress and Key Release status bit. + * Clear both synchronizer chain. + */ + reg_val = readw(keypad->mmio_base + KPSR); + reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD | + KBD_STAT_KDSC | KBD_STAT_KRSS; + writew(reg_val, keypad->mmio_base + KPSR); + + /* Enable KDI and disable KRI (avoid false release events). */ + reg_val |= KBD_STAT_KDIE; + reg_val &= ~KBD_STAT_KRIE; + writew(reg_val, keypad->mmio_base + KPSR); +} + +static void imx_keypad_inhibit(struct imx_keypad *keypad) +{ + unsigned short reg_val; + + /* Inhibit KDI and KRI interrupts. */ + reg_val = readw(keypad->mmio_base + KPSR); + reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE); + writew(reg_val, keypad->mmio_base + KPSR); + + /* Colums as open drain and disable all rows */ + writew(0xff00, keypad->mmio_base + KPCR); +} + +static void imx_keypad_close(struct input_dev *dev) +{ + struct imx_keypad *keypad = input_get_drvdata(dev); + + dev_dbg(&dev->dev, ">%s\n", __func__); + + /* Mark keypad as being inactive */ + keypad->enabled = false; + synchronize_irq(keypad->irq); + del_timer_sync(&keypad->check_matrix_timer); + + imx_keypad_inhibit(keypad); + + /* Disable clock unit */ + clk_disable(keypad->clk); +} + +static int imx_keypad_open(struct input_dev *dev) +{ + struct imx_keypad *keypad = input_get_drvdata(dev); + + dev_dbg(&dev->dev, ">%s\n", __func__); + + /* We became active from now */ + keypad->enabled = true; + + /* Enable the kpp clock */ + clk_enable(keypad->clk); + imx_keypad_config(keypad); + + /* Sanity control, not all the rows must be actived now. */ + if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) { + dev_err(&dev->dev, + "too many keys pressed, control pins initialisation\n"); + goto open_err; + } + + return 0; + +open_err: + imx_keypad_close(dev); + return -EIO; +} + +static int __devinit imx_keypad_probe(struct platform_device *pdev) +{ + const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data; + struct imx_keypad *keypad; + struct input_dev *input_dev; + struct resource *res; + int irq, error, i; + + if (keymap_data == NULL) { + dev_err(&pdev->dev, "no keymap defined\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq defined in platform data\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no I/O memory defined in platform data\n"); + return -EINVAL; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + return -EBUSY; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + error = -ENOMEM; + goto failed_rel_mem; + } + + keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL); + if (!keypad) { + dev_err(&pdev->dev, "not enough memory for driver data\n"); + error = -ENOMEM; + goto failed_free_input; + } + + keypad->input_dev = input_dev; + keypad->irq = irq; + keypad->stable_count = 0; + + setup_timer(&keypad->check_matrix_timer, + imx_keypad_check_for_events, (unsigned long) keypad); + + keypad->mmio_base = ioremap(res->start, resource_size(res)); + if (keypad->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -ENOMEM; + goto failed_free_priv; + } + + keypad->clk = clk_get(&pdev->dev, "kpp"); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + error = PTR_ERR(keypad->clk); + goto failed_unmap; + } + + /* Search for rows and cols enabled */ + for (i = 0; i < keymap_data->keymap_size; i++) { + keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]); + keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]); + } + + if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) || + keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) { + dev_err(&pdev->dev, + "invalid key data (too many rows or colums)\n"); + error = -EINVAL; + goto failed_clock_put; + } + dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask); + dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask); + + /* Init the Input device */ + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &pdev->dev; + input_dev->open = imx_keypad_open; + input_dev->close = imx_keypad_close; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->keycode = keypad->keycodes; + input_dev->keycodesize = sizeof(keypad->keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); + + matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT, + keypad->keycodes, input_dev->keybit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + input_set_drvdata(input_dev, keypad); + + /* Ensure that the keypad will stay dormant until opened */ + imx_keypad_inhibit(keypad); + + error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED, + pdev->name, keypad); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_clock_put; + } + + /* Register the input device */ + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + platform_set_drvdata(pdev, keypad); + device_init_wakeup(&pdev->dev, 1); + + return 0; + +failed_free_irq: + free_irq(irq, pdev); +failed_clock_put: + clk_put(keypad->clk); +failed_unmap: + iounmap(keypad->mmio_base); +failed_free_priv: + kfree(keypad); +failed_free_input: + input_free_device(input_dev); +failed_rel_mem: + release_mem_region(res->start, resource_size(res)); + return error; +} + +static int __devexit imx_keypad_remove(struct platform_device *pdev) +{ + struct imx_keypad *keypad = platform_get_drvdata(pdev); + struct resource *res; + + dev_dbg(&pdev->dev, ">%s\n", __func__); + + platform_set_drvdata(pdev, NULL); + + input_unregister_device(keypad->input_dev); + + free_irq(keypad->irq, keypad); + clk_put(keypad->clk); + + iounmap(keypad->mmio_base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(keypad); + + return 0; +} + +static struct platform_driver imx_keypad_driver = { + .driver = { + .name = "imx-keypad", + .owner = THIS_MODULE, + }, + .probe = imx_keypad_probe, + .remove = __devexit_p(imx_keypad_remove), +}; + +static int __init imx_keypad_init(void) +{ + return platform_driver_register(&imx_keypad_driver); +} + +static void __exit imx_keypad_exit(void) +{ + platform_driver_unregister(&imx_keypad_driver); +} + +module_init(imx_keypad_init); +module_exit(imx_keypad_exit); + +MODULE_AUTHOR("Alberto Panizzo "); +MODULE_DESCRIPTION("IMX Keypad Port Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-keypad"); -- GitLab From aee4467b5ce5047401efb4175b1360ec1734affc Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Feb 2010 11:33:22 +0900 Subject: [PATCH 1400/3892] sh: Fix up large system memory handling for SH7780 PCI. For systems that have more than 512MB we need to set up an additional mapping, this fixes up the rounding to the next power of two and splits out the mapping accordingly between the two local bus mapping windows. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pci-sh7780.c | 34 ++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 40531cd367b7..8405c8fded6f 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "pci-sh4.h" #include #include @@ -59,7 +60,11 @@ static int __init sh7780_pci_init(void) __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST, chan->reg_base + SH4_PCICR); - /* Wait for it to come back up.. */ + /* + * Wait for it to come back up. The spec says to allow for up to + * 1 second after toggling the reset pin, but in practice 100ms + * is more than enough. + */ mdelay(100); id = __raw_readw(chan->reg_base + PCI_VENDOR_ID); @@ -90,17 +95,34 @@ static int __init sh7780_pci_init(void) */ __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR); + __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); + memphys = __pa(memory_start); - memsize = memory_end - memory_start; + memsize = roundup_pow_of_two(memory_end - memory_start); /* - * Set IO and Mem windows to local address - * Make PCI and local address the same for easy 1 to 1 mapping + * If there's more than 512MB of memory, we need to roll over to + * LAR1/LSR1. */ - __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); + if (memsize > SZ_512M) { + __raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1); + __raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1, + chan->reg_base + SH4_PCILSR1); + memsize = SZ_512M; + } else { + /* + * Otherwise just zero it out and disable it. + */ + __raw_writel(0, chan->reg_base + SH4_PCILAR1); + __raw_writel(0, chan->reg_base + SH4_PCILSR1); + } + /* + * LAR0/LSR0 covers up to the first 512MB, which is enough to + * cover all of lowmem on most platforms. + */ __raw_writel(memphys, chan->reg_base + SH4_PCILAR0); - __raw_writel((memsize - 1) << 9 | 1, + __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1, chan->reg_base + SH4_PCILSR0); /* Clear out PCI arbiter IRQs */ -- GitLab From 85b59f5bb24aeca1a987cbb206e228bf630c8327 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Feb 2010 13:01:42 +0900 Subject: [PATCH 1401/3892] sh: Enable PCI66 support for SH7780 host controller. This adds some helper glue for scanning the bus and determining if all of the devices are 66MHz capable or not before flipping on 66MHz mode. This isn't quite to spec, but it's fairly consistent with what other embedded controllers end up having to do. Scanning code cribbed from the MIPS txx9 PCI code. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/Makefile | 2 +- arch/sh/drivers/pci/common.c | 64 ++++++++++++++++++++++++++++++++ arch/sh/drivers/pci/pci-sh7780.c | 29 +++++++++++++++ arch/sh/drivers/pci/pci.c | 2 + arch/sh/include/asm/pci.h | 2 + 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 arch/sh/drivers/pci/common.c diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 2c458b602beb..4a59e6890876 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -1,7 +1,7 @@ # # Makefile for the PCI specific kernel interface routines under Linux. # -obj-y += pci.o +obj-y += common.o pci.o obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c new file mode 100644 index 000000000000..f67c946a8612 --- /dev/null +++ b/arch/sh/drivers/pci/common.c @@ -0,0 +1,64 @@ +#include +#include + +static int __init +early_read_config_word(struct pci_channel *hose, + int top_bus, int bus, int devfn, int offset, u16 *value) +{ + struct pci_dev fake_dev; + struct pci_bus fake_bus; + + fake_dev.bus = &fake_bus; + fake_dev.sysdata = hose; + fake_dev.devfn = devfn; + fake_bus.number = bus; + fake_bus.sysdata = hose; + fake_bus.ops = hose->pci_ops; + + if (bus != top_bus) + /* Fake a parent bus structure. */ + fake_bus.parent = &fake_bus; + else + fake_bus.parent = NULL; + + return pci_read_config_word(&fake_dev, offset, value); +} + +int __init pci_is_66mhz_capable(struct pci_channel *hose, + int top_bus, int current_bus) +{ + u32 pci_devfn; + unsigned short vid; + int cap66 = -1; + u16 stat; + + printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n"); + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { + if (PCI_FUNC(pci_devfn)) + continue; + if (early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_VENDOR_ID, &vid) != + PCIBIOS_SUCCESSFUL) + continue; + if (vid == 0xffff) + continue; + + /* check 66MHz capability */ + if (cap66 < 0) + cap66 = 1; + if (cap66) { + early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, &stat); + if (!(stat & PCI_STATUS_66MHZ)) { + printk(KERN_DEBUG + "PCI: %02x:%02x not 66MHz capable.\n", + current_bus, pci_devfn); + cap66 = 0; + break; + } + } + } + + return cap66 > 0; +} diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 8405c8fded6f..b68f45b6451a 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -41,6 +41,29 @@ static struct pci_channel sh7780_pci_controller = { .io_map_base = SH7780_PCI_IO_BASE, }; +static void __init sh7780_pci66_init(struct pci_channel *hose) +{ + unsigned int tmp; + + if (!pci_is_66mhz_capable(hose, 0, 0)) + return; + + /* Enable register access */ + tmp = __raw_readl(hose->reg_base + SH4_PCICR); + tmp |= SH4_PCICR_PREFIX; + __raw_writel(tmp, hose->reg_base + SH4_PCICR); + + /* Enable 66MHz operation */ + tmp = __raw_readw(hose->reg_base + PCI_STATUS); + tmp |= PCI_STATUS_66MHZ; + __raw_writew(tmp, hose->reg_base + PCI_STATUS); + + /* Done */ + tmp = __raw_readl(hose->reg_base + SH4_PCICR); + tmp |= SH4_PCICR_PREFIX | SH4_PCICR_CFIN; + __raw_writel(tmp, hose->reg_base + SH4_PCICR); +} + static int __init sh7780_pci_init(void) { struct pci_channel *chan = &sh7780_pci_controller; @@ -176,6 +199,12 @@ static int __init sh7780_pci_init(void) register_pci_controller(chan); + sh7780_pci66_init(chan); + + printk(KERN_NOTICE "PCI: Running at %dMHz.\n", + (__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ) ? + 66 : 33); + return 0; } arch_initcall(sh7780_pci_init); diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 45a15cab01df..63b11fddffec 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -88,6 +88,8 @@ void __devinit register_pci_controller(struct pci_channel *hose) mutex_unlock(&pci_scan_mutex); } + return; + out: printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); } diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index d124a009889f..5849d435c441 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -32,6 +32,8 @@ struct pci_channel { }; extern void register_pci_controller(struct pci_channel *hose); +extern int pci_is_66mhz_capable(struct pci_channel *hose, + int top_bus, int current_bus); extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM; -- GitLab From bcf39352eb9e9026f7a1028d4bce3707b65f104b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Feb 2010 13:11:25 +0900 Subject: [PATCH 1402/3892] sh: Handle PCI controller resource conflicts. register_pci_controller() can fail, but presently is a void function. Change this over to an int so that we can bail early before continuing on with post-registration initialization (such as throwing the controller in to 66MHz mode in the case of the SH7780 host controller). Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pci-dreamcast.c | 4 +--- arch/sh/drivers/pci/pci-sh5.c | 4 +--- arch/sh/drivers/pci/pci-sh7751.c | 4 +--- arch/sh/drivers/pci/pci-sh7780.c | 5 ++++- arch/sh/drivers/pci/pci.c | 5 +++-- arch/sh/drivers/pci/pcie-sh7786.c | 4 +--- arch/sh/include/asm/pci.h | 2 +- 7 files changed, 12 insertions(+), 16 deletions(-) diff --git a/arch/sh/drivers/pci/pci-dreamcast.c b/arch/sh/drivers/pci/pci-dreamcast.c index 210f9d4af141..bd5a1e50ebf6 100644 --- a/arch/sh/drivers/pci/pci-dreamcast.c +++ b/arch/sh/drivers/pci/pci-dreamcast.c @@ -95,8 +95,6 @@ static int __init gapspci_init(void) outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); - register_pci_controller(&dreamcast_pci_controller); - - return 0; + return register_pci_controller(&dreamcast_pci_controller); } arch_initcall(gapspci_init); diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c index 873ed2b44055..bce73faabc88 100644 --- a/arch/sh/drivers/pci/pci-sh5.c +++ b/arch/sh/drivers/pci/pci-sh5.c @@ -216,8 +216,6 @@ static int __init sh5pci_init(void) sh5_mem_resource.start = memStart; sh5_mem_resource.end = memStart + memSize; - register_pci_controller(&sh5pci_controller); - - return 0; + return register_pci_controller(&sh5pci_controller); } arch_initcall(sh5pci_init); diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 02306ddb4011..6ad5beb524aa 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -176,8 +176,6 @@ static int __init sh7751_pci_init(void) word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM; pci_write_reg(chan, word, SH4_PCICR); - register_pci_controller(chan); - - return 0; + return register_pci_controller(chan); } arch_initcall(sh7751_pci_init); diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index b68f45b6451a..0e0ddd67e6e1 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -71,6 +71,7 @@ static int __init sh7780_pci_init(void) size_t memsize; unsigned int id; const char *type; + int ret; printk(KERN_NOTICE "PCI: Starting intialization.\n"); @@ -197,7 +198,9 @@ static int __init sh7780_pci_init(void) __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO, chan->reg_base + SH4_PCICR); - register_pci_controller(chan); + ret = register_pci_controller(chan); + if (unlikely(ret)) + return ret; sh7780_pci66_init(chan); diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 63b11fddffec..488331c45033 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -58,7 +58,7 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose) static DEFINE_MUTEX(pci_scan_mutex); -void __devinit register_pci_controller(struct pci_channel *hose) +int __devinit register_pci_controller(struct pci_channel *hose) { if (request_resource(&iomem_resource, hose->mem_resource) < 0) goto out; @@ -88,10 +88,11 @@ void __devinit register_pci_controller(struct pci_channel *hose) mutex_unlock(&pci_scan_mutex); } - return; + return 0; out: printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); + return -1; } static int __init pcibios_init(void) diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index ac37ee879bab..feac1fef21eb 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -296,9 +296,7 @@ static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port) if (unlikely(ret < 0)) return ret; - register_pci_controller(port->hose); - - return 0; + return register_pci_controller(port->hose); } static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = { diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index 5849d435c441..bbd10cf79825 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -31,7 +31,7 @@ struct pci_channel { unsigned int need_domain_info; }; -extern void register_pci_controller(struct pci_channel *hose); +extern int register_pci_controller(struct pci_channel *hose); extern int pci_is_66mhz_capable(struct pci_channel *hose, int top_bus, int current_bus); -- GitLab From d60bec4eb7076acfc940cca3f9f219e7653a1466 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:17 +0000 Subject: [PATCH 1403/3892] tulip_core: Use dev_ and pr_ Convert printks to dev_ where appropriate Convert printks to pr_ Change print formats with %d.dx to %0dx Coalesce long formats Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/tulip_core.c | 162 +++++++++++++++++---------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index da4fc458f90c..e1a5f03a49c5 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -41,7 +41,6 @@ static char version[] __devinitdata = "Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; - /* A few user-configurable values. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ @@ -326,7 +325,8 @@ static void tulip_up(struct net_device *dev) udelay(100); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n", + dev->name, dev->irq); iowrite32(tp->rx_ring_dma, ioaddr + CSR3); iowrite32(tp->tx_ring_dma, ioaddr + CSR4); @@ -387,8 +387,9 @@ static void tulip_up(struct net_device *dev) (dev->if_port == 12 ? 0 : dev->if_port); for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using user-specified media %s.\n", - dev->name, medianame[dev->if_port]); + dev_info(&dev->dev, + "Using user-specified media %s\n", + medianame[dev->if_port]); goto media_picked; } } @@ -396,8 +397,9 @@ static void tulip_up(struct net_device *dev) int looking_for = tp->mtable->defaultmedia & MEDIA_MASK; for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", - dev->name, medianame[looking_for]); + dev_info(&dev->dev, + "Using EEPROM-set media %s\n", + medianame[looking_for]); goto media_picked; } } @@ -424,9 +426,10 @@ media_picked: if (tp->mii_cnt) { tulip_select_media(dev, 1); if (tulip_debug > 1) - printk(KERN_INFO "%s: Using MII transceiver %d, status " - "%4.4x.\n", - dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1)); + dev_info(&dev->dev, + "Using MII transceiver %d, status %04x\n", + tp->phys[0], + tulip_mdio_read(dev, tp->phys[0], 1)); iowrite32(csr6_mask_defstate, ioaddr + CSR6); tp->csr6 = csr6_mask_hdcap; dev->if_port = 11; @@ -490,9 +493,10 @@ media_picked: iowrite32(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", - dev->name, ioread32(ioaddr + CSR0), ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", + dev->name, ioread32(ioaddr + CSR0), + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } /* Set the timer to switch to check for link beat and perhaps switch @@ -540,27 +544,30 @@ static void tulip_tx_timeout(struct net_device *dev) if (tulip_media_cap[dev->if_port] & MediaIsMII) { /* Do nothing -- the media monitor should handle this. */ if (tulip_debug > 1) - printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", - dev->name); + dev_warn(&dev->dev, + "Transmit timeout using MII device\n"); } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 || tp->chip_id == DM910X) { - printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12), - ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); + dev_warn(&dev->dev, + "21140 transmit timed out, status %08x, SIA %08x %08x %08x %08x, resetting...\n", + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12), + ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), + ioread32(ioaddr + CSR15)); tp->timeout_recovery = 1; schedule_work(&tp->media_work); goto out_unlock; } else if (tp->chip_id == PNIC2) { - printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, " - "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n", - dev->name, (int)ioread32(ioaddr + CSR5), (int)ioread32(ioaddr + CSR6), - (int)ioread32(ioaddr + CSR7), (int)ioread32(ioaddr + CSR12)); + dev_warn(&dev->dev, + "PNIC2 transmit timed out, status %08x, CSR6/7 %08x / %08x CSR12 %08x, resetting...\n", + (int)ioread32(ioaddr + CSR5), + (int)ioread32(ioaddr + CSR6), + (int)ioread32(ioaddr + CSR7), + (int)ioread32(ioaddr + CSR12)); } else { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " - "%8.8x, resetting...\n", - dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12)); + dev_warn(&dev->dev, + "Transmit timed out, status %08x, CSR12 %08x, resetting...\n", + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12)); dev->if_port = 0; } @@ -570,26 +577,26 @@ static void tulip_tx_timeout(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); int j; - printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " - "%2.2x %2.2x %2.2x.\n", - i, (unsigned int)tp->rx_ring[i].status, - (unsigned int)tp->rx_ring[i].length, - (unsigned int)tp->rx_ring[i].buffer1, - (unsigned int)tp->rx_ring[i].buffer2, - buf[0], buf[1], buf[2]); + printk(KERN_DEBUG + "%2d: %08x %08x %08x %08x %02x %02x %02x\n", + i, + (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); for (j = 0; buf[j] != 0xee && j < 1600; j++) if (j < 100) - printk(KERN_CONT " %2.2x", buf[j]); - printk(KERN_CONT " j=%d.\n", j); + pr_cont(" %02x", buf[j]); + pr_cont(" j=%d\n", j); } - printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + printk(KERN_DEBUG " Rx ring %08x: ", (int)tp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_CONT " %8.8x", - (unsigned int)tp->rx_ring[i].status); - printk(KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + pr_cont(" %08x", (unsigned int)tp->rx_ring[i].status); + printk(KERN_DEBUG " Tx ring %08x: ", (int)tp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_CONT " %8.8x", (unsigned int)tp->tx_ring[i].status); - printk(KERN_CONT "\n"); + pr_cont(" %08x", (unsigned int)tp->tx_ring[i].status); + pr_cont("\n"); } #endif @@ -832,8 +839,9 @@ static int tulip_close (struct net_device *dev) tulip_down (dev); if (tulip_debug > 1) - printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, ioread32 (ioaddr + CSR5)); + dev_printk(KERN_DEBUG, &dev->dev, + "Shutting down ethercard, status was %02x\n", + ioread32 (ioaddr + CSR5)); free_irq (dev->irq, dev); @@ -1073,10 +1081,10 @@ static void set_rx_mode(struct net_device *dev) filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); if (tulip_debug > 2) - printk(KERN_INFO "%s: Added filter for %pM" - " %8.8x bit %d.\n", - dev->name, mclist->dmi_addr, - ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); + dev_info(&dev->dev, + "Added filter for %pM %08x bit %d\n", + mclist->dmi_addr, + ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); } if (mc_filter[0] == tp->mc_filter[0] && mc_filter[1] == tp->mc_filter[1]) @@ -1288,9 +1296,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, unsigned int force_csr0 = 0; #ifndef MODULE - static int did_version; /* Already printed version info. */ - if (tulip_debug > 0 && did_version++ == 0) - printk (KERN_INFO "%s", version); + if (tulip_debug > 0) + printk_once(KERN_INFO "%s", version); #endif board_idx++; @@ -1301,7 +1308,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { - printk (KERN_ERR PFX "skipping LMC card.\n"); + pr_err(PFX "skipping LMC card\n"); return -ENODEV; } @@ -1317,15 +1324,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (pdev->vendor == 0x1282 && pdev->device == 0x9100 && pdev->revision < 0x30) { - printk(KERN_INFO PFX - "skipping early DM9100 with Crc bug (use dmfe)\n"); + pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n"); return -ENODEV; } dp = pci_device_to_OF_node(pdev); if (!(dp && of_get_property(dp, "local-mac-address", NULL))) { - printk(KERN_INFO PFX - "skipping DM910x expansion card (use dmfe)\n"); + pr_info(PFX "skipping DM910x expansion card (use dmfe)\n"); return -ENODEV; } } @@ -1372,9 +1377,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, i = pci_enable_device(pdev); if (i) { - printk (KERN_ERR PFX - "Cannot enable tulip board #%d, aborting\n", - board_idx); + pr_err(PFX "Cannot enable tulip board #%d, aborting\n", + board_idx); return i; } @@ -1383,22 +1387,22 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* alloc_etherdev ensures aligned and zeroed private structures */ dev = alloc_etherdev (sizeof (*tp)); if (!dev) { - printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); + pr_err(PFX "ether device alloc failed, aborting\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { - printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, " - "aborting\n", pci_name(pdev), - (unsigned long long)pci_resource_len (pdev, 0), - (unsigned long long)pci_resource_start (pdev, 0)); + pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n", + pci_name(pdev), + (unsigned long long)pci_resource_len (pdev, 0), + (unsigned long long)pci_resource_start (pdev, 0)); goto err_out_free_netdev; } /* grab all resources from both PIO and MMIO regions, as we * don't want anyone else messing around with our hardware */ - if (pci_request_regions (pdev, "tulip")) + if (pci_request_regions (pdev, DRV_NAME)) goto err_out_free_netdev; ioaddr = pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size); @@ -1611,8 +1615,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (dev->mem_start & MEDIA_MASK) tp->default_port = dev->mem_start & MEDIA_MASK; if (tp->default_port) { - printk(KERN_INFO "tulip%d: Transceiver selection forced to %s.\n", - board_idx, medianame[tp->default_port & MEDIA_MASK]); + pr_info(DRV_NAME "%d: Transceiver selection forced to %s\n", + board_idx, medianame[tp->default_port & MEDIA_MASK]); tp->medialock = 1; if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) tp->full_duplex = 1; @@ -1627,7 +1631,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } if (tp->flags & HAS_MEDIA_TABLE) { - sprintf(dev->name, "tulip%d", board_idx); /* hack */ + sprintf(dev->name, DRV_NAME "%d", board_idx); /* hack */ tulip_parse_eeprom(dev); strcpy(dev->name, "eth%d"); /* un-hack */ } @@ -1663,20 +1667,18 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (register_netdev(dev)) goto err_out_free_ring; - printk(KERN_INFO "%s: %s rev %d at " + pci_set_drvdata(pdev, dev); + + dev_info(&dev->dev, #ifdef CONFIG_TULIP_MMIO - "MMIO" + "%s rev %d at MMIO %#llx,%s %pM, IRQ %d\n", #else - "Port" + "%s rev %d at Port %#llx,%s %pM, IRQ %d\n", #endif - " %#llx,", dev->name, chip_name, pdev->revision, - (unsigned long long) pci_resource_start(pdev, TULIP_BAR)); - pci_set_drvdata(pdev, dev); - - if (eeprom_missing) - printk(" EEPROM not present,"); - printk(" %pM", dev->dev_addr); - printk(", IRQ %d.\n", irq); + chip_name, pdev->revision, + (unsigned long long)pci_resource_start(pdev, TULIP_BAR), + eeprom_missing ? " EEPROM not present," : "", + dev->dev_addr, irq); if (tp->chip_id == PNIC2) tp->link_change = pnic2_lnk_change; @@ -1799,12 +1801,12 @@ static int tulip_resume(struct pci_dev *pdev) return 0; if ((retval = pci_enable_device(pdev))) { - printk (KERN_ERR "tulip: pci_enable_device failed in resume\n"); + pr_err(PFX "pci_enable_device failed in resume\n"); return retval; } if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) { - printk (KERN_ERR "tulip: request_irq failed in resume\n"); + pr_err(PFX "request_irq failed in resume\n"); return retval; } @@ -1874,7 +1876,7 @@ static struct pci_driver tulip_driver = { static int __init tulip_init (void) { #ifdef MODULE - printk (KERN_INFO "%s", version); + pr_info("%s", version); #endif /* copy module parms into globals */ -- GitLab From 985a63ed3faf0faaba840d806f5ca4d360d13ad3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:18 +0000 Subject: [PATCH 1404/3892] tulip/21142.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/21142.c | 76 ++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 9f6742fad6ca..007d8e75666d 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -43,8 +43,8 @@ void t21142_media_task(struct work_struct *work) if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) csr12 |= 6; if (tulip_debug > 2) - printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", - dev->name, csr12, medianame[dev->if_port]); + dev_info(&dev->dev, "21143 negotiation status %08x, %s\n", + csr12, medianame[dev->if_port]); if (tulip_media_cap[dev->if_port] & MediaIsMII) { if (tulip_check_duplex(dev) < 0) { netif_carrier_off(dev); @@ -56,23 +56,26 @@ void t21142_media_task(struct work_struct *work) } else if (tp->nwayset) { /* Don't screw up a negotiated session! */ if (tulip_debug > 1) - printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", - dev->name, medianame[dev->if_port], csr12); + dev_info(&dev->dev, + "Using NWay-set %s media, csr12 %08x\n", + medianame[dev->if_port], csr12); } else if (tp->medialock) { ; } else if (dev->if_port == 3) { if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ if (tulip_debug > 1) - printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " - "trying NWay.\n", dev->name, csr12); + dev_info(&dev->dev, + "No 21143 100baseTx link beat, %08x, trying NWay\n", + csr12); t21142_start_nway(dev); next_tick = 3*HZ; } } else if ((csr12 & 0x7000) != 0x5000) { /* Negotiation failed. Search media types. */ if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", - dev->name, csr12); + dev_info(&dev->dev, + "21143 negotiation failed, status %08x\n", + csr12); if (!(csr12 & 4)) { /* 10mbps link beat good. */ new_csr6 = 0x82420000; dev->if_port = 0; @@ -90,8 +93,8 @@ void t21142_media_task(struct work_struct *work) iowrite32(1, ioaddr + CSR13); } if (tulip_debug > 1) - printk(KERN_INFO"%s: Testing new 21143 media %s.\n", - dev->name, medianame[dev->if_port]); + dev_info(&dev->dev, "Testing new 21143 media %s\n", + medianame[dev->if_port]); if (new_csr6 != (tp->csr6 & ~0x00D5)) { tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; @@ -119,8 +122,8 @@ void t21142_start_nway(struct net_device *dev) tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", - dev->name, csr14); + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n", + dev->name, csr14); iowrite32(0x0001, ioaddr + CSR13); udelay(100); iowrite32(csr14, ioaddr + CSR14); @@ -147,8 +150,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5) if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) csr12 |= 6; if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, csr14); + dev_info(&dev->dev, + "21143 link status interrupt %08x, CSR5 %x, %08x\n", + csr12, csr5, csr14); /* If NWay finished and we have a negotiated partner capability. */ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { @@ -171,14 +175,15 @@ void t21142_lnk_change(struct net_device *dev, int csr5) if (tulip_debug > 1) { if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link " - "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], tp->sym_advertise, - tp->lpar, negotiated); + dev_info(&dev->dev, + "Switching to %s based on link negotiation %04x & %04x = %04x\n", + medianame[dev->if_port], + tp->sym_advertise, tp->lpar, + negotiated); else - printk(KERN_INFO "%s: Autonegotiation failed, using %s," - " link beat status %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); + dev_info(&dev->dev, + "Autonegotiation failed, using %s, link beat status %04x\n", + medianame[dev->if_port], csr12); } if (tp->mtable) { @@ -201,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5) #if 0 /* Restart shouldn't be needed. */ iowrite32(tp->csr6 | RxOn, ioaddr + CSR6); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", - dev->name, ioread32(ioaddr + CSR5)); + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %08x\n", + dev->name, ioread32(ioaddr + CSR5)); #endif tulip_start_rxtx(tp); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", - dev->name, tp->csr6, ioread32(ioaddr + CSR6), - ioread32(ioaddr + CSR12)); + printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", + dev->name, tp->csr6, ioread32(ioaddr + CSR6), + ioread32(ioaddr + CSR12)); } else if ((tp->nwayset && (csr5 & 0x08000000) && (dev->if_port == 3 || dev->if_port == 5) && (csr12 & 2) == 2) || @@ -220,9 +225,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5) add_timer(&tp->timer); } else if (dev->if_port == 3 || dev->if_port == 5) { if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); + dev_info(&dev->dev, "21143 %s link beat %s\n", + medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); if ((csr12 & 2) && ! tp->medialock) { del_timer_sync(&tp->timer); t21142_start_nway(dev); @@ -232,21 +237,18 @@ void t21142_lnk_change(struct net_device *dev, int csr5) iowrite32(csr14 & ~0x080, ioaddr + CSR14); } else if (dev->if_port == 0 || dev->if_port == 4) { if ((csr12 & 4) == 0) - printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", - dev->name); + dev_info(&dev->dev, "21143 10baseT link beat good\n"); } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ if (tulip_debug) - printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", - dev->name); + dev_info(&dev->dev, "21143 10mbps sensed media\n"); dev->if_port = 0; } else if (tp->nwayset) { if (tulip_debug) - printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", - dev->name, medianame[dev->if_port], tp->csr6); + dev_info(&dev->dev, "21143 using NWay-set %s, csr6 %08x\n", + medianame[dev->if_port], tp->csr6); } else { /* 100mbps link beat good. */ if (tulip_debug) - printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", - dev->name); + dev_info(&dev->dev, "21143 100baseTx sensed media\n"); dev->if_port = 3; tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff); iowrite32(0x0003FF7F, ioaddr + CSR14); -- GitLab From f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:19 +0000 Subject: [PATCH 1405/3892] tulip/de2104x.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/de2104x.c | 138 ++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 87ea39e2037d..29330209ad8b 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -382,9 +382,9 @@ static void de_rx_err_acct (struct de_private *de, unsigned rx_tail, /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (netif_msg_rx_err(de)) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - de->dev->name, status); + dev_warn(&de->dev->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); de->net_stats.rx_length_errors++; } } else if (status & RxError) { @@ -487,7 +487,7 @@ rx_next: } if (!rx_work) - printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name); + dev_warn(&de->dev->dev, "rx work limit reached\n"); de->rx_tail = rx_tail; } @@ -504,7 +504,8 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) if (netif_msg_intr(de)) printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n", - dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail); + dev->name, status, dr32(MacMode), + de->rx_tail, de->tx_head, de->tx_tail); dw32(MacStatus, status); @@ -529,8 +530,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) pci_read_config_word(de->pdev, PCI_STATUS, &pci_status); pci_write_config_word(de->pdev, PCI_STATUS, pci_status); - printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n", - dev->name, status, pci_status); + dev_err(&de->dev->dev, + "PCI bus error, status=%08x, PCI status=%04x\n", + status, pci_status); } return IRQ_HANDLED; @@ -582,7 +584,8 @@ static void de_tx (struct de_private *de) de->net_stats.tx_packets++; de->net_stats.tx_bytes += skb->len; if (netif_msg_tx_done(de)) - printk(KERN_DEBUG "%s: tx done, slot %d\n", de->dev->name, tx_tail); + printk(KERN_DEBUG "%s: tx done, slot %d\n", + de->dev->name, tx_tail); } dev_kfree_skb_irq(skb); } @@ -870,7 +873,7 @@ static void de_stop_rxtx (struct de_private *de) udelay(100); } - printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name); + dev_warn(&de->dev->dev, "timeout expired stopping DMA\n"); } static inline void de_start_rxtx (struct de_private *de) @@ -905,8 +908,8 @@ static void de_link_up(struct de_private *de) if (!netif_carrier_ok(de->dev)) { netif_carrier_on(de->dev); if (netif_msg_link(de)) - printk(KERN_INFO "%s: link up, media %s\n", - de->dev->name, media_name[de->media_type]); + dev_info(&de->dev->dev, "link up, media %s\n", + media_name[de->media_type]); } } @@ -915,7 +918,7 @@ static void de_link_down(struct de_private *de) if (netif_carrier_ok(de->dev)) { netif_carrier_off(de->dev); if (netif_msg_link(de)) - printk(KERN_INFO "%s: link down\n", de->dev->name); + dev_info(&de->dev->dev, "link down\n"); } } @@ -925,7 +928,8 @@ static void de_set_media (struct de_private *de) u32 macmode = dr32(MacMode); if (de_is_running(de)) - printk(KERN_WARNING "%s: chip is running while changing media!\n", de->dev->name); + dev_warn(&de->dev->dev, + "chip is running while changing media!\n"); if (de->de21040) dw32(CSR11, FULL_DUPLEX_MAGIC); @@ -945,15 +949,15 @@ static void de_set_media (struct de_private *de) macmode &= ~FullDuplex; if (netif_msg_link(de)) { - printk(KERN_INFO - "%s: set link %s\n" - "%s: mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n" - "%s: set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", - de->dev->name, media_name[media], - de->dev->name, dr32(MacMode), dr32(SIAStatus), - dr32(CSR13), dr32(CSR14), dr32(CSR15), - de->dev->name, macmode, de->media[media].csr13, - de->media[media].csr14, de->media[media].csr15); + dev_info(&de->dev->dev, "set link %s\n", media_name[media]); + dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", + dr32(MacMode), dr32(SIAStatus), + dr32(CSR13), dr32(CSR14), dr32(CSR15)); + + dev_info(&de->dev->dev, + "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", + macmode, de->media[media].csr13, + de->media[media].csr14, de->media[media].csr15); } if (macmode != dr32(MacMode)) dw32(MacMode, macmode); @@ -992,9 +996,8 @@ static void de21040_media_timer (unsigned long data) de_link_up(de); else if (netif_msg_timer(de)) - printk(KERN_INFO "%s: %s link ok, status %x\n", - dev->name, media_name[de->media_type], - status); + dev_info(&dev->dev, "%s link ok, status %x\n", + media_name[de->media_type], status); return; } @@ -1022,8 +1025,8 @@ no_link_yet: add_timer(&de->media_timer); if (netif_msg_timer(de)) - printk(KERN_INFO "%s: no link, trying media %s, status %x\n", - dev->name, media_name[de->media_type], status); + dev_info(&dev->dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media) @@ -1079,9 +1082,10 @@ static void de21041_media_timer (unsigned long data) de_link_up(de); else if (netif_msg_timer(de)) - printk(KERN_INFO "%s: %s link ok, mode %x status %x\n", - dev->name, media_name[de->media_type], - dr32(MacMode), status); + dev_info(&dev->dev, + "%s link ok, mode %x status %x\n", + media_name[de->media_type], + dr32(MacMode), status); return; } @@ -1150,8 +1154,8 @@ no_link_yet: add_timer(&de->media_timer); if (netif_msg_timer(de)) - printk(KERN_INFO "%s: no link, trying media %s, status %x\n", - dev->name, media_name[de->media_type], status); + dev_info(&dev->dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static void de_media_interrupt (struct de_private *de, u32 status) @@ -1378,8 +1382,7 @@ static int de_open (struct net_device *dev) rc = de_alloc_rings(de); if (rc) { - printk(KERN_ERR "%s: ring allocation failure, err=%d\n", - dev->name, rc); + dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc); return rc; } @@ -1387,15 +1390,14 @@ static int de_open (struct net_device *dev) rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev); if (rc) { - printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n", - dev->name, dev->irq, rc); + dev_err(&dev->dev, "IRQ %d request failure, err=%d\n", + dev->irq, rc); goto err_out_free; } rc = de_init_hw(de); if (rc) { - printk(KERN_ERR "%s: h/w init failure, err=%d\n", - dev->name, rc); + dev_err(&dev->dev, "h/w init failure, err=%d\n", rc); goto err_out_free_irq; } @@ -1666,8 +1668,8 @@ static int de_nway_reset(struct net_device *dev) status = dr32(SIAStatus); dw32(SIAStatus, (status & ~NWayState) | NWayRestart); if (netif_msg_link(de)) - printk(KERN_INFO "%s: link nway restart, status %x,%x\n", - de->dev->name, status, dr32(SIAStatus)); + dev_info(&de->dev->dev, "link nway restart, status %x,%x\n", + status, dr32(SIAStatus)); return 0; } @@ -1711,7 +1713,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de) de->dev->dev_addr[i] = value; udelay(1); if (boguscnt <= 0) - printk(KERN_WARNING PFX "timeout reading 21040 MAC address byte %u\n", i); + pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i); } } @@ -1830,9 +1832,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de) } if (netif_msg_probe(de)) - printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n", - de->board_idx, ofs, - media_name[de->media_type]); + pr_info("de%d: SROM leaf offset %u, default media %s\n", + de->board_idx, ofs, media_name[de->media_type]); /* init SIA register values to defaults */ for (i = 0; i < DE_MAX_MEDIA; i++) { @@ -1879,9 +1880,9 @@ static void __devinit de21041_get_srom_info (struct de_private *de) de->media[idx].type = idx; if (netif_msg_probe(de)) - printk(KERN_INFO "de%d: media block #%u: %s", - de->board_idx, i, - media_name[de->media[idx].type]); + pr_info("de%d: media block #%u: %s", + de->board_idx, i, + media_name[de->media[idx].type]); bufp += sizeof (ib->opts); @@ -1893,13 +1894,13 @@ static void __devinit de21041_get_srom_info (struct de_private *de) sizeof(ib->csr15); if (netif_msg_probe(de)) - printk(" (%x,%x,%x)\n", - de->media[idx].csr13, - de->media[idx].csr14, - de->media[idx].csr15); + pr_cont(" (%x,%x,%x)\n", + de->media[idx].csr13, + de->media[idx].csr14, + de->media[idx].csr15); } else if (netif_msg_probe(de)) - printk("\n"); + pr_cont("\n"); if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3])) break; @@ -2005,7 +2006,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* check for invalid IRQ value */ if (pdev->irq < 2) { rc = -EIO; - printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n", + pr_err(PFX "invalid irq (%d) for pci dev %s\n", pdev->irq, pci_name(pdev)); goto err_out_res; } @@ -2016,14 +2017,14 @@ static int __devinit de_init_one (struct pci_dev *pdev, pciaddr = pci_resource_start(pdev, 1); if (!pciaddr) { rc = -EIO; - printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n", - pci_name(pdev)); + pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev)); goto err_out_res; } if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) { rc = -EIO; - printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n", - (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev)); + pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n", + (unsigned long long)pci_resource_len(pdev, 1), + pci_name(pdev)); goto err_out_res; } @@ -2031,9 +2032,9 @@ static int __devinit de_init_one (struct pci_dev *pdev, regs = ioremap_nocache(pciaddr, DE_REGS_SIZE); if (!regs) { rc = -EIO; - printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", - (unsigned long long)pci_resource_len(pdev, 1), - pciaddr, pci_name(pdev)); + pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", + (unsigned long long)pci_resource_len(pdev, 1), + pciaddr, pci_name(pdev)); goto err_out_res; } dev->base_addr = (unsigned long) regs; @@ -2044,8 +2045,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* make sure hardware is not running */ rc = de_reset_mac(de); if (rc) { - printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n", - pci_name(pdev)); + pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev)); goto err_out_iomap; } @@ -2065,12 +2065,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", - dev->name, - de->de21040 ? "21040" : "21041", - dev->base_addr, - dev->dev_addr, - dev->irq); + dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n", + de->de21040 ? "21040" : "21041", + dev->base_addr, + dev->dev_addr, + dev->irq); pci_set_drvdata(pdev, dev); @@ -2158,8 +2157,7 @@ static int de_resume (struct pci_dev *pdev) if (!netif_running(dev)) goto out_attach; if ((retval = pci_enable_device(pdev))) { - printk (KERN_ERR "%s: pci_enable_device failed in resume\n", - dev->name); + dev_err(&dev->dev, "pci_enable_device failed in resume\n"); goto out; } de_init_hw(de); -- GitLab From dde7c8ef167996689bc464eb65d2b09ef05263c2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:20 +0000 Subject: [PATCH 1406/3892] tulip/dmfe.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Remove 'DRV_NAME ": ' from logging messages Convert commented out printks to pr_debug Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/dmfe.c | 67 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 2d9f09c6189e..5fc61c1012e5 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -61,6 +61,8 @@ Test and make sure PCI latency is now correct for all cases. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "dmfe" #define DRV_VERSION "1.36.4" #define DRV_RELDATE "2002-01-17" @@ -149,16 +151,17 @@ #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_DBUG(dbug_now, msg, value) \ - do { \ - if (dmfe_debug || (dbug_now)) \ - printk(KERN_ERR DRV_NAME ": %s %lx\n",\ - (msg), (long) (value)); \ +#define DMFE_DBUG(dbug_now, msg, value) \ + do { \ + if (dmfe_debug || (dbug_now)) \ + pr_err("%s %lx\n", \ + (msg), (long) (value)); \ } while (0) -#define SHOW_MEDIA_TYPE(mode) \ - printk (KERN_INFO DRV_NAME ": Change Speed to %sMhz %s duplex\n" , \ - (mode & 1) ? "100":"10", (mode & 4) ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) \ + pr_info("Change Speed to %sMhz %s duplex\n" , \ + (mode & 1) ? "100":"10", \ + (mode & 4) ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -391,8 +394,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, struct device_node *dp = pci_device_to_OF_node(pdev); if (dp && of_get_property(dp, "local-mac-address", NULL)) { - printk(KERN_INFO DRV_NAME - ": skipping on-board DM910x (use tulip)\n"); + pr_info("skipping on-board DM910x (use tulip)\n"); return -ENODEV; } } @@ -405,8 +407,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING DRV_NAME - ": 32-bit PCI DMA not available.\n"); + pr_warning("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } @@ -417,13 +418,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, goto err_out_free; if (!pci_resource_start(pdev, 0)) { - printk(KERN_ERR DRV_NAME ": I/O base is zero\n"); + pr_err("I/O base is zero\n"); err = -ENODEV; goto err_out_disable; } if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) { - printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n"); + pr_err("Allocated I/O size too small\n"); err = -ENODEV; goto err_out_disable; } @@ -438,7 +439,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, #endif if (pci_request_regions(pdev, DRV_NAME)) { - printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + pr_err("Failed to request PCI regions\n"); err = -ENODEV; goto err_out_disable; } @@ -497,12 +498,9 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, if (err) goto err_out_free_buf; - printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n", - dev->name, - ent->driver_data >> 16, - pci_name(pdev), - dev->dev_addr, - dev->irq); + dev_info(&dev->dev, "Davicom DM%04lx at pci%s, %pM, irq %d\n", + ent->driver_data >> 16, + pci_name(pdev), dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -696,7 +694,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); + pr_err("big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -706,8 +704,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, /* No Tx resource check, it never happen nromally */ if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", - db->tx_queue_cnt); + pr_err("No Tx resource %ld\n", db->tx_queue_cnt); return NETDEV_TX_BUSY; } @@ -779,12 +776,11 @@ static int dmfe_stop(struct DEVICE *dev) #if 0 /* show statistic counter */ - printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx" - " LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", - db->tx_fifo_underrun, db->tx_excessive_collision, - db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, - db->tx_jabber_timeout, db->reset_count, db->reset_cr8, - db->reset_fatal, db->reset_TXtimeout); + printk("FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + db->tx_fifo_underrun, db->tx_excessive_collision, + db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, + db->tx_jabber_timeout, db->reset_count, db->reset_cr8, + db->reset_fatal, db->reset_TXtimeout); #endif return 0; @@ -885,7 +881,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + pr_debug("tdes0=%x\n", tdes0); if (tdes0 & 0x80000000) break; @@ -895,7 +891,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + pr_debug("tdes0=%x\n", tdes0); dev->stats.collisions += (tdes0 >> 3) & 0xf; dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { @@ -992,7 +988,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* error summary bit check */ if (rdes0 & 0x8000) { /* This is a error packet */ - //printk(DRV_NAME ": rdes0: %lx\n", rdes0); + pr_debug("rdes0: %x\n", rdes0); dev->stats.rx_errors++; if (rdes0 & 1) dev->stats.rx_fifo_errors++; @@ -1191,8 +1187,7 @@ static void dmfe_timer(unsigned long data) if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; - printk(KERN_WARNING "%s: Tx timeout - resetting\n", - dev->name); + dev_warn(&dev->dev, "Tx timeout - resetting\n"); } } @@ -1646,7 +1641,7 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db) else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ + pr_debug("Phy_mode %x\n", phy_mode); switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; -- GitLab From e9cd1cbcda5e21706b03b543b1b73600b07f323f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:21 +0000 Subject: [PATCH 1407/3892] tulip/eeprom.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/eeprom.c | 47 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 889f57aae89b..93f4e8309f81 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -161,15 +161,15 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) if (ee_data[0] == 0xff) { if (last_mediatable) { controller_index++; - printk(KERN_INFO "%s: Controller %d of multiport board.\n", - dev->name, controller_index); + dev_info(&dev->dev, + "Controller %d of multiport board\n", + controller_index); tp->mtable = last_mediatable; ee_data = last_ee_data; goto subsequent_board; } else - printk(KERN_INFO "%s: Missing EEPROM, this interface may " - "not work correctly!\n", - dev->name); + dev_info(&dev->dev, + "Missing EEPROM, this interface may not work correctly!\n"); return; } /* Do a fix-up based on the vendor half of the station address prefix. */ @@ -181,16 +181,15 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); - printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" - " substitute media control info.\n", - dev->name, eeprom_fixups[i].name); + dev_info(&dev->dev, + "Old format EEPROM on '%s' board. Using substitute media control info\n", + eeprom_fixups[i].name); break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk(KERN_INFO "%s: Old style EEPROM with no media selection " - "information.\n", - dev->name); + dev_info(&dev->dev, + "Old style EEPROM with no media selection information\n"); return; } } @@ -218,7 +217,8 @@ subsequent_board: /* there is no phy information, don't even try to build mtable */ if (count == 0) { if (tulip_debug > 0) - printk(KERN_WARNING "%s: no phy info, aborting mtable build\n", dev->name); + dev_warn(&dev->dev, + "no phy info, aborting mtable build\n"); return; } @@ -234,8 +234,8 @@ subsequent_board: mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; mtable->csr15dir = mtable->csr15val = 0; - printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); + dev_info(&dev->dev, "EEPROM default media type %s\n", + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; @@ -298,16 +298,17 @@ subsequent_board: } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; - printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " - "sequences %d/%d long, capabilities %2.2x %2.2x.\n", - dev->name, bp[0], bp[1], bp[2 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + dev_info(&dev->dev, + "MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n", + bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], + bp[4 + bp[2 + bp[1]*2]*2]); } - printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " - "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media & 15], leaf->media, - leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "", - leaf->type); + dev_info(&dev->dev, + "Index #%d - Media %s (#%d) described by a %s (%d) block\n", + i, medianame[leaf->media & 15], leaf->media, + leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "", + leaf->type); } if (new_advertise) tp->sym_advertise = new_advertise; -- GitLab From abe02af8263ae17e201994a1be7fc5eac6642acf Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:22 +0000 Subject: [PATCH 1408/3892] tulip/interrupt.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/interrupt.c | 100 ++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 2e8e8ee893c7..1faf7a4d7202 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget) #endif if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, - tp->rx_ring[entry].status); + printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); do { if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { - printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n"); + printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n"); break; } /* Acknowledge current RX interrupt sources. */ @@ -146,7 +146,7 @@ int tulip_poll(struct napi_struct *napi, int budget) break; if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", dev->name, entry, status); if (++work_done >= budget) @@ -177,15 +177,15 @@ int tulip_poll(struct napi_struct *napi, int budget) /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - dev->name, status); + dev_warn(&dev->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); tp->stats.rx_length_errors++; } } else { /* There was a fatal error. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", dev->name, status); tp->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || @@ -226,12 +226,11 @@ int tulip_poll(struct napi_struct *napi, int budget) #ifndef final_version if (tp->rx_buffers[entry].mapping != le32_to_cpu(tp->rx_ring[entry].buffer1)) { - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %08x vs. %08llx %p / %p.\n", - dev->name, - le32_to_cpu(tp->rx_ring[entry].buffer1), - (unsigned long long)tp->rx_buffers[entry].mapping, - skb->head, temp); + dev_err(&dev->dev, + "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", + le32_to_cpu(tp->rx_ring[entry].buffer1), + (unsigned long long)tp->rx_buffers[entry].mapping, + skb->head, temp); } #endif @@ -365,16 +364,16 @@ static int tulip_rx(struct net_device *dev) int received = 0; if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, - tp->rx_ring[entry].status); + printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); short pkt_len; if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", - dev->name, entry, status); + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", + dev->name, entry, status); if (--rx_work_limit < 0) break; @@ -402,16 +401,16 @@ static int tulip_rx(struct net_device *dev) /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - dev->name, status); + dev_warn(&dev->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); tp->stats.rx_length_errors++; } } else { /* There was a fatal error. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); + printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", + dev->name, status); tp->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || (status & RxDescRunt)) @@ -450,12 +449,11 @@ static int tulip_rx(struct net_device *dev) #ifndef final_version if (tp->rx_buffers[entry].mapping != le32_to_cpu(tp->rx_ring[entry].buffer1)) { - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %08x vs. %Lx %p / %p.\n", - dev->name, - le32_to_cpu(tp->rx_ring[entry].buffer1), - (long long)tp->rx_buffers[entry].mapping, - skb->head, temp); + dev_err(&dev->dev, + "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n", + le32_to_cpu(tp->rx_ring[entry].buffer1), + (long long)tp->rx_buffers[entry].mapping, + skb->head, temp); } #endif @@ -569,7 +567,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) #endif /* CONFIG_TULIP_NAPI */ if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n", dev->name, csr5, ioread32(ioaddr + CSR5)); @@ -601,8 +599,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, status); + printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", + dev->name, status); #endif tp->stats.tx_errors++; if (status & 0x4104) tp->stats.tx_aborted_errors++; @@ -631,8 +629,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) #ifndef final_version if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n", - dev->name, dirty_tx, tp->cur_tx); + dev_err(&dev->dev, + "Out-of-sync dirty pointer, %d vs. %d\n", + dirty_tx, tp->cur_tx); dirty_tx += TX_RING_SIZE; } #endif @@ -643,9 +642,10 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) tp->dirty_tx = dirty_tx; if (csr5 & TxDied) { if (tulip_debug > 2) - printk(KERN_WARNING "%s: The transmitter stopped." - " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", - dev->name, csr5, ioread32(ioaddr + CSR6), tp->csr6); + dev_warn(&dev->dev, + "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", + csr5, ioread32(ioaddr + CSR6), + tp->csr6); tulip_restart_rxtx(tp); } spin_unlock(&tp->lock); @@ -696,8 +696,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) * to the 21142/3 docs that is). * -- rmk */ - printk(KERN_ERR "%s: (%lu) System Error occurred (%d)\n", - dev->name, tp->nir, error); + dev_err(&dev->dev, + "(%lu) System Error occurred (%d)\n", + tp->nir, error); } /* Clear all error sources, included undocumented ones! */ iowrite32(0x0800f7ba, ioaddr + CSR5); @@ -706,16 +707,17 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) if (csr5 & TimerInt) { if (tulip_debug > 2) - printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", - dev->name, csr5); + dev_err(&dev->dev, + "Re-enabling interrupts, %08x\n", + csr5); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; } if (tx > maxtx || rx > maxrx || oi > maxoi) { if (tulip_debug > 1) - printk(KERN_WARNING "%s: Too much work during an interrupt, " - "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); + dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", + csr5, tp->nir, tx, rx, oi); /* Acknowledge all interrupt sources. */ iowrite32(0x8001ffff, ioaddr + CSR5); @@ -764,14 +766,18 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) entry = tp->dirty_rx % RX_RING_SIZE; if (tp->rx_buffers[entry].skb == NULL) { if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); + dev_warn(&dev->dev, + "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", + tp->nir, tp->cur_rx, tp->ttimer, rx); if (tp->chip_id == LC82C168) { iowrite32(0x00, ioaddr + CSR7); mod_timer(&tp->timer, RUN_AT(HZ/50)); } else { if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) { if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + dev_warn(&dev->dev, + "in rx suspend mode: (%lu) set timer\n", + tp->nir); iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, ioaddr + CSR7); iowrite32(TimerInt, ioaddr + CSR5); @@ -787,8 +793,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) } if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", - dev->name, ioread32(ioaddr + CSR5)); + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n", + dev->name, ioread32(ioaddr + CSR5)); return IRQ_HANDLED; } -- GitLab From fa0b9a4c41490d550ebd3bd418f4551c989fec5d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:23 +0000 Subject: [PATCH 1409/3892] tulip/media.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/media.c | 74 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index d8fda83705bf..68b170ae4d15 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -182,9 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup) switch (mleaf->type) { case 0: /* 21140 non-MII xcvr. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" - " with control setting %2.2x.\n", - dev->name, p[1]); + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n", + dev->name, p[1]); dev->if_port = p[0]; if (startup) iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); @@ -205,15 +204,15 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); + printk(KERN_DEBUG "%s: Resetting the transceiver\n", + dev->name); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " - "%4.4x/%4.4x.\n", - dev->name, medianame[dev->if_port], setup[0], setup[1]); + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n", + dev->name, medianame[dev->if_port], + setup[0], setup[1]); if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ csr13val = setup[0]; csr14val = setup[1]; @@ -240,8 +239,8 @@ void tulip_select_media(struct net_device *dev, int startup) if (startup) iowrite32(csr13val, ioaddr + CSR13); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", - dev->name, csr15dir, csr15val); + printk(KERN_DEBUG "%s: Setting CSR15 to %08x/%08x\n", + dev->name, csr15dir, csr15val); if (mleaf->type == 4) new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); else @@ -317,8 +316,9 @@ void tulip_select_media(struct net_device *dev, int startup) if (tp->mii_advertise == 0) tp->mii_advertise = tp->advertising[phy_num]; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on MII %d.\n", - dev->name, tp->mii_advertise, tp->phys[phy_num]); + printk(KERN_DEBUG "%s: Advertising %04x on MII %d\n", + dev->name, tp->mii_advertise, + tp->phys[phy_num]); tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise); } break; @@ -335,8 +335,8 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); + printk(KERN_DEBUG "%s: Resetting the transceiver\n", + dev->name); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } @@ -344,20 +344,20 @@ void tulip_select_media(struct net_device *dev, int startup) break; } default: - printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", - dev->name, mleaf->type); + printk(KERN_DEBUG "%s: Invalid media table selection %d\n", + dev->name, mleaf->type); new_csr6 = 0x020E0000; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n", + dev->name, medianame[dev->if_port], ioread32(ioaddr + CSR12) & 0xff); } else if (tp->chip_id == LC82C168) { if (startup && ! tp->medialock) dev->if_port = tp->mii_cnt ? 11 : 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", - dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]); + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n", + dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]); if (tp->mii_cnt) { new_csr6 = 0x810C0000; iowrite32(0x0001, ioaddr + CSR15); @@ -388,10 +388,9 @@ void tulip_select_media(struct net_device *dev, int startup) } else new_csr6 = 0x03860000; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - ioread32(ioaddr + CSR12)); + printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n", + dev->name, medianame[dev->if_port], + ioread32(ioaddr + CSR12)); } tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); @@ -415,16 +414,17 @@ int tulip_check_duplex(struct net_device *dev) bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA); if (tulip_debug > 1) - printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, bmsr, lpa); + dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n", + bmsr, lpa); if (bmsr == 0xffff) return -2; if ((bmsr & BMSR_LSTATUS) == 0) { int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); if ((new_bmsr & BMSR_LSTATUS) == 0) { if (tulip_debug > 1) - printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_bmsr); + dev_info(&dev->dev, + "No link beat on the MII interface, status %04x\n", + new_bmsr); return -1; } } @@ -443,10 +443,10 @@ int tulip_check_duplex(struct net_device *dev) tulip_restart_rxtx(tp); if (tulip_debug > 0) - printk(KERN_INFO "%s: Setting %s-duplex based on MII" - "#%d link partner capability of %4.4x.\n", - dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], lpa); + dev_info(&dev->dev, + "Setting %s-duplex based on MII#%d link partner capability of %04x\n", + tp->full_duplex ? "full" : "half", + tp->phys[0], lpa); return 1; } @@ -501,15 +501,13 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) tp->phys[phy_idx++] = phy; - printk (KERN_INFO "tulip%d: MII transceiver #%d " - "config %4.4x status %4.4x advertising %4.4x.\n", + pr_info("tulip%d: MII transceiver #%d config %04x status %04x advertising %04x\n", board_idx, phy, mii_reg0, mii_status, mii_advert); /* Fixup for DLink with miswired PHY. */ if (mii_advert != to_advert) { - printk (KERN_DEBUG "tulip%d: Advertising %4.4x on PHY %d," - " previously advertising %4.4x.\n", - board_idx, to_advert, phy, mii_advert); + printk(KERN_DEBUG "tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", + board_idx, to_advert, phy, mii_advert); tulip_mdio_write (dev, phy, 4, to_advert); } @@ -554,7 +552,7 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) } tp->mii_cnt = phy_idx; if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk (KERN_INFO "tulip%d: ***WARNING***: No MII transceiver found!\n", + pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n", board_idx); tp->phys[0] = 1; } -- GitLab From 1df8bbd1420705277cd382b1386cda724d61a678 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:24 +0000 Subject: [PATCH 1410/3892] tulip/pnic.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/pnic.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index d3253ed09dfc..966efa1a27d7 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev) new_csr6 |= 0x00000200; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", - dev->name, phy_reg, medianame[dev->if_port]); + printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n", + dev->name, phy_reg, medianame[dev->if_port]); if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ @@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5) int phy_reg = ioread32(ioaddr + 0xB8); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", - dev->name, phy_reg, csr5); + printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n", + dev->name, phy_reg, csr5); if (ioread32(ioaddr + CSR5) & TPLnkFail) { iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); /* If we use an external MII, then we mustn't use the @@ -114,9 +114,8 @@ void pnic_timer(unsigned long data) int csr5 = ioread32(ioaddr + CSR5); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " - "CSR5 %8.8x.\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); + printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n", + dev->name, phy_reg, medianame[dev->if_port], csr5); if (phy_reg & 0x04000000) { /* Remote link fault */ iowrite32(0x0201F078, ioaddr + 0xB8); next_tick = 1*HZ; @@ -126,10 +125,11 @@ void pnic_timer(unsigned long data) next_tick = 60*HZ; } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " - "CSR5 %8.8x, PHY %3.3x.\n", - dev->name, medianame[dev->if_port], csr12, - ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8)); + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", + dev->name, medianame[dev->if_port], + csr12, + ioread32(ioaddr + CSR5), + ioread32(ioaddr + 0xB8)); next_tick = 3*HZ; if (tp->medialock) { } else if (tp->nwayset && (dev->if_port & 1)) { @@ -151,10 +151,11 @@ void pnic_timer(unsigned long data) tulip_restart_rxtx(tp); dev->trans_start = jiffies; if (tulip_debug > 1) - printk(KERN_INFO "%s: Changing PNIC configuration to %s " - "%s-duplex, CSR6 %8.8x.\n", - dev->name, medianame[dev->if_port], - tp->full_duplex ? "full" : "half", new_csr6); + dev_info(&dev->dev, + "Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n", + medianame[dev->if_port], + tp->full_duplex ? "full" : "half", + new_csr6); } } } @@ -162,7 +163,7 @@ too_good_connection: mod_timer(&tp->timer, RUN_AT(next_tick)); if(!ioread32(ioaddr + CSR7)) { if (tulip_debug > 1) - printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name); + dev_info(&dev->dev, "sw timer wakeup\n"); disable_irq(dev->irq); tulip_refill_rx(dev); enable_irq(dev->irq); -- GitLab From 22086a1172b69b9f6200e169dc99a252a204affb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:25 +0000 Subject: [PATCH 1411/3892] tulip/pnic2.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/pnic2.c | 59 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index d8418694bf46..b8197666021e 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -87,8 +87,8 @@ void pnic2_timer(unsigned long data) int next_tick = 60*HZ; if (tulip_debug > 3) - printk(KERN_INFO"%s: PNIC2 negotiation status %8.8x.\n", - dev->name,ioread32(ioaddr + CSR12)); + dev_info(&dev->dev, "PNIC2 negotiation status %08x\n", + ioread32(ioaddr + CSR12)); if (next_tick) { mod_timer(&tp->timer, RUN_AT(next_tick)); @@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev) csr14 |= 0x00001184; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, " - "csr14=%8.8x.\n", dev->name, csr14); + printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n", + dev->name, csr14); /* tell pnic2_lnk_change we are doing an nway negotiation */ dev->if_port = 0; @@ -137,8 +137,8 @@ void pnic2_start_nway(struct net_device *dev) tp->csr6 = ioread32(ioaddr + CSR6); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: On Entry to Nway, " - "csr6=%8.8x.\n", dev->name, tp->csr6); + printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n", + dev->name, tp->csr6); /* mask off any bits not to touch * comment at top of file explains mask value @@ -181,9 +181,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) int csr12 = ioread32(ioaddr + CSR12); if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC2 link status interrupt %8.8x, " - " CSR5 %x, %8.8x.\n", dev->name, csr12, - csr5, ioread32(ioaddr + CSR14)); + dev_info(&dev->dev, + "PNIC2 link status interrupt %08x, CSR5 %x, %08x\n", + csr12, csr5, ioread32(ioaddr + CSR14)); /* If NWay finished and we have a negotiated partner capability. * check bits 14:12 for bit pattern 101 - all is good @@ -215,9 +215,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) else if (negotiated & 0x0020) dev->if_port = 0; else { if (tulip_debug > 1) - printk(KERN_INFO "%s: funny autonegotiate result " - "csr12 %8.8x advertising %4.4x\n", - dev->name, csr12, tp->sym_advertise); + dev_info(&dev->dev, + "funny autonegotiate result csr12 %08x advertising %04x\n", + csr12, tp->sym_advertise); tp->nwayset = 0; /* so check if 100baseTx link state is okay */ if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180)) @@ -231,10 +231,11 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) if (tulip_debug > 1) { if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link " - "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], - tp->sym_advertise, tp->lpar, negotiated); + dev_info(&dev->dev, + "Switching to %s based on link negotiation %04x & %04x = %04x\n", + medianame[dev->if_port], + tp->sym_advertise, tp->lpar, + negotiated); } /* remember to turn off bit 7 - autonegotiate @@ -270,9 +271,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) iowrite32(1, ioaddr + CSR13); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 " - "%8.8x.\n", dev->name, tp->csr6, - ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12)); + printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", + dev->name, tp->csr6, + ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12)); /* now the following actually writes out the * new csr6 values @@ -282,9 +283,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) return; } else { - printk(KERN_INFO "%s: Autonegotiation failed, " - "using %s, link beat status %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); + dev_info(&dev->dev, + "Autonegotiation failed, using %s, link beat status %04x\n", + medianame[dev->if_port], csr12); /* remember to turn off bit 7 - autonegotiate * enable so we don't forget @@ -339,9 +340,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) /* we are at 100mb and a potential link change occurred */ if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); + dev_info(&dev->dev, "PNIC2 %s link beat %s\n", + medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); /* check 100 link beat */ @@ -364,9 +365,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) /* we are at 10mb and a potential link change occurred */ if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 4) ? "failed" : "good"); + dev_info(&dev->dev, "PNIC2 %s link beat %s\n", + medianame[dev->if_port], + (csr12 & 4) ? "failed" : "good"); tp->nway = 0; @@ -385,7 +386,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC2 Link Change Default?\n",dev->name); + dev_info(&dev->dev, "PNIC2 Link Change Default?\n"); /* if all else fails default to trying 10baseT-HD */ dev->if_port = 0; -- GitLab From 27146c43c4dbb727c4a211541af46577de2984af Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:26 +0000 Subject: [PATCH 1412/3892] tulip/timer.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/timer.c | 52 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index a0e084223082..36c2725ec886 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work) unsigned long flags; if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" - " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", - dev->name, medianame[dev->if_port], ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6), csr12, ioread32(ioaddr + CSR13), - ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); + printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n", + dev->name, medianame[dev->if_port], + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6), + csr12, ioread32(ioaddr + CSR13), + ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); } switch (tp->chip_id) { case DC21140: @@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work) Assume this a generic MII or SYM transceiver. */ next_tick = 60*HZ; if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " - "CSR12 0x%2.2x.\n", - dev->name, ioread32(ioaddr + CSR6), csr12 & 0xff); + printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n", + dev->name, + ioread32(ioaddr + CSR6), csr12 & 0xff); break; } mleaf = &tp->mtable->mleaf[tp->cur_index]; @@ -62,9 +62,8 @@ void tulip_media_task(struct work_struct *work) s8 bitnum = p[offset]; if (p[offset+1] & 0x80) { if (tulip_debug > 1) - printk(KERN_DEBUG"%s: Transceiver monitor tick " - "CSR12=%#2.2x, no media sense.\n", - dev->name, csr12); + printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n", + dev->name, csr12); if (mleaf->type == 4) { if (mleaf->media == 3 && (csr12 & 0x02)) goto select_next_media; @@ -72,16 +71,16 @@ void tulip_media_task(struct work_struct *work) break; } if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" - " bit %d is %d, expecting %d.\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); /* Check that the specified bit has the proper value. */ if ((bitnum < 0) != ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + printk(KERN_DEBUG "%s: Link beat detected for %s\n", + dev->name, medianame[mleaf->media & MEDIA_MASK]); if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ goto actually_mii; @@ -100,9 +99,9 @@ void tulip_media_task(struct work_struct *work) if (tulip_media_cap[dev->if_port] & MediaIsFD) goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & MEDIA_MASK], + printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n", + dev->name, + medianame[mleaf->media & MEDIA_MASK], medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ @@ -151,8 +150,8 @@ void mxic_timer(unsigned long data) int next_tick = 60*HZ; if (tulip_debug > 3) { - printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, - ioread32(ioaddr + CSR12)); + dev_info(&dev->dev, "MXIC negotiation status %08x\n", + ioread32(ioaddr + CSR12)); } if (next_tick) { mod_timer(&tp->timer, RUN_AT(next_tick)); @@ -167,11 +166,10 @@ void comet_timer(unsigned long data) int next_tick = 60*HZ; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " - "%4.4x.\n", - dev->name, - tulip_mdio_read(dev, tp->phys[0], 1), - tulip_mdio_read(dev, tp->phys[0], 5)); + printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n", + dev->name, + tulip_mdio_read(dev, tp->phys[0], 1), + tulip_mdio_read(dev, tp->phys[0], 5)); /* mod_timer synchronizes us with potential add_timer calls * from interrupts. */ -- GitLab From e02fb7aa0714ca9357571bb15ef0fe278a150cc7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:27 +0000 Subject: [PATCH 1413/3892] tulip/uli526x.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Remove DRV_NAME from logging messages Add do {} while(0) to ULI526X_DBUG macro Make SHOW_MEDIA_TYPE macro more readable Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/uli526x.c | 46 ++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index d549042a01df..dc3335d906f6 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -12,6 +12,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "uli526x" #define DRV_VERSION "0.9.3" #define DRV_RELDATE "2005-7-29" @@ -82,9 +84,16 @@ #define ULI526X_TX_TIMEOUT ((16*HZ)/2) /* tx packet time-out time 8 s" */ #define ULI526X_TX_KICK (4*HZ/2) /* tx packet Kick-out time 2 s" */ -#define ULI526X_DBUG(dbug_now, msg, value) if (uli526x_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) +#define ULI526X_DBUG(dbug_now, msg, value) \ +do { \ + if (uli526x_debug || (dbug_now)) \ + pr_err("%s %lx\n", (msg), (long) (value)); \ +} while (0) -#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) \ + pr_err("Change Speed to %sMhz %s duplex\n", \ + mode & 1 ? "100" : "10", \ + mode & 4 ? "full" : "half"); /* CR9 definition: SROM/MII */ @@ -284,7 +293,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n"); + pr_warning("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } @@ -295,19 +304,19 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, goto err_out_free; if (!pci_resource_start(pdev, 0)) { - printk(KERN_ERR DRV_NAME ": I/O base is zero\n"); + pr_err("I/O base is zero\n"); err = -ENODEV; goto err_out_disable; } if (pci_resource_len(pdev, 0) < (ULI526X_IO_SIZE) ) { - printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n"); + pr_err("Allocated I/O size too small\n"); err = -ENODEV; goto err_out_disable; } if (pci_request_regions(pdev, DRV_NAME)) { - printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + pr_err("Failed to request PCI regions\n"); err = -ENODEV; goto err_out_disable; } @@ -382,9 +391,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n", - dev->name,ent->driver_data >> 16,pci_name(pdev), - dev->dev_addr, dev->irq); + dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n", + ent->driver_data >> 16, pci_name(pdev), + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -516,7 +525,7 @@ static void uli526x_init(struct net_device *dev) } } if(phy_tmp == 32) - printk(KERN_WARNING "Can not find the phy address!!!"); + pr_warning("Can not find the phy address!!!"); /* Parser SROM and media mode */ db->media_mode = uli526x_media_mode; @@ -582,7 +591,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); + pr_err("big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -592,7 +601,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* No Tx resource check, it never happen nromally */ if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt); + pr_err("No Tx resource %ld\n", db->tx_packet_cnt); return NETDEV_TX_BUSY; } @@ -1058,7 +1067,7 @@ static void uli526x_timer(unsigned long data) /* Link Failed */ ULI526X_DBUG(0, "Link Failed", tmp_cr12); netif_carrier_off(dev); - printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); + pr_info("%s NIC Link is Down\n",dev->name); db->link_failed = 1; /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ @@ -1090,11 +1099,11 @@ static void uli526x_timer(unsigned long data) } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { - printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); + pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); } else { - printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); + pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); } netif_carrier_on(dev); } @@ -1104,7 +1113,7 @@ static void uli526x_timer(unsigned long data) { if(db->init==1) { - printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); + pr_info("%s NIC Link is Down\n",dev->name); netif_carrier_off(dev); } } @@ -1230,8 +1239,7 @@ static int uli526x_resume(struct pci_dev *pdev) err = pci_set_power_state(pdev, PCI_D0); if (err) { - printk(KERN_WARNING "%s: Could not put device into D0\n", - dev->name); + dev_warn(&dev->dev, "Could not put device into D0\n"); return err; } @@ -1432,7 +1440,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt) update_cr6(db->cr6_data, dev->base_addr); dev->trans_start = jiffies; } else - printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n"); + pr_err("No Tx resource - Send_filter_frame!\n"); } -- GitLab From a1e37bc5e2d0ff8d025221e27c2bfff762072311 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:28 +0000 Subject: [PATCH 1414/3892] tulip/winbond-840.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Convert %d.%d.%d.%d to %pI4 Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/winbond-840.c | 177 ++++++++++++++++---------------- 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 23395e1ff238..9fb89afccf7c 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -376,8 +376,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, irq = pdev->irq; if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n", - pci_name(pdev)); + pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n", + pci_name(pdev)); return -EIO; } dev = alloc_etherdev(sizeof(*np)); @@ -422,8 +422,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (option & 0x200) np->mii_if.full_duplex = 1; if (option & 15) - printk(KERN_INFO "%s: ignoring user supplied media type %d", - dev->name, option & 15); + dev_info(&dev->dev, + "ignoring user supplied media type %d", + option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->mii_if.full_duplex = 1; @@ -440,9 +441,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (i) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, - dev->dev_addr, irq); + dev_info(&dev->dev, "%s at %p, %pM, IRQ %d\n", + pci_id_tbl[chip_idx].name, ioaddr, dev->dev_addr, irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -453,16 +453,17 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+ mdio_read(dev, phy, MII_PHYSID2); - printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, np->mii, phy, mii_status, np->mii_if.advertising); + dev_info(&dev->dev, + "MII PHY %08xh found at address %d, status 0x%04x advertising %04x\n", + np->mii, phy, mii_status, + np->mii_if.advertising); } } np->mii_cnt = phy_idx; np->mii_if.phy_id = np->phys[0]; if (phy_idx == 0) { - printk(KERN_WARNING "%s: MII PHY not found -- this device may " - "not operate correctly.\n", dev->name); + dev_warn(&dev->dev, + "MII PHY not found -- this device may not operate correctly\n"); } } @@ -644,8 +645,8 @@ static int netdev_open(struct net_device *dev) goto out_err; if (debug > 1) - printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n", - dev->name, dev->irq); + printk(KERN_DEBUG "%s: w89c840_open() irq %d\n", + dev->name, dev->irq); if((i=alloc_ringdesc(dev))) goto out_err; @@ -657,7 +658,7 @@ static int netdev_open(struct net_device *dev) netif_start_queue(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); + printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name); /* Set the timer to check for link beat. */ init_timer(&np->timer); @@ -688,16 +689,18 @@ static int update_link(struct net_device *dev) if (!(mii_reg & 0x4)) { if (netif_carrier_ok(dev)) { if (debug) - printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n", - dev->name, np->phys[0]); + dev_info(&dev->dev, + "MII #%d reports no link. Disabling watchdog\n", + np->phys[0]); netif_carrier_off(dev); } return np->csr6; } if (!netif_carrier_ok(dev)) { if (debug) - printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n", - dev->name, np->phys[0]); + dev_info(&dev->dev, + "MII #%d link is back. Enabling watchdog\n", + np->phys[0]); netif_carrier_on(dev); } @@ -729,9 +732,10 @@ static int update_link(struct net_device *dev) if (fasteth) result |= 0x20000000; if (result != np->csr6 && debug) - printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n", - dev->name, fasteth ? 100 : 10, - duplex ? "full" : "half", np->phys[0]); + dev_info(&dev->dev, + "Setting %dMBit-%s-duplex based on MII#%d\n", + fasteth ? 100 : 10, duplex ? "full" : "half", + np->phys[0]); return result; } @@ -763,8 +767,8 @@ static inline void update_csr6(struct net_device *dev, int new) limit--; if(!limit) { - printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n", - dev->name, csr5); + dev_info(&dev->dev, + "couldn't stop rxtx, IntrStatus %xh\n", csr5); break; } udelay(1); @@ -783,10 +787,9 @@ static void netdev_timer(unsigned long data) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " - "config %8.8x.\n", - dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); + printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n", + dev->name, ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); @@ -899,8 +902,8 @@ static void init_registers(struct net_device *dev) /* When not a module we can work around broken '486 PCI boards. */ if (boot_cpu_data.x86 <= 4) { i |= 0x4800; - printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " - "alignment to 8 longwords.\n", dev->name); + dev_info(&dev->dev, + "This is a 386/486 PCI system, setting cache alignment to 8 longwords\n"); } else { i |= 0xE000; } @@ -931,22 +934,23 @@ static void tx_timeout(struct net_device *dev) struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base_addr; - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, ioread32(ioaddr + IntrStatus)); + dev_warn(&dev->dev, "Transmit timed out, status %08x, resetting...\n", + ioread32(ioaddr + IntrStatus)); { int i; printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)np->rx_ring[i].status); - printk(KERN_DEBUG" Tx ring %p: ", np->tx_ring); + printk(KERN_CONT " %08x", (unsigned int)np->rx_ring[i].status); + printk(KERN_CONT "\n"); + printk(KERN_DEBUG " Tx ring %p: ", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", np->tx_ring[i].status); - printk("\n"); + printk(KERN_CONT " %08x", np->tx_ring[i].status); + printk(KERN_CONT "\n"); } - printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n", - np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes); - printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",ioread32(ioaddr+0x4C)); + printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d\n", + np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes); + printk(KERN_DEBUG "Tx Descriptor addr %xh\n", ioread32(ioaddr+0x4C)); disable_irq(dev->irq); spin_lock_irq(&np->lock); @@ -1055,8 +1059,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx, entry); + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n", + dev->name, np->cur_tx, entry); } return NETDEV_TX_OK; } @@ -1073,8 +1077,8 @@ static void netdev_tx_done(struct net_device *dev) if (tx_status & 0x8000) { /* There was an error, log it. */ #ifndef final_version if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, tx_status); + printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", + dev->name, tx_status); #endif np->stats.tx_errors++; if (tx_status & 0x0104) np->stats.tx_aborted_errors++; @@ -1086,8 +1090,8 @@ static void netdev_tx_done(struct net_device *dev) } else { #ifndef final_version if (debug > 3) - printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n", - dev->name, entry, tx_status); + printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n", + dev->name, entry, tx_status); #endif np->stats.tx_bytes += np->tx_skbuff[entry]->len; np->stats.collisions += (tx_status >> 3) & 15; @@ -1130,8 +1134,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus); if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", - dev->name, intr_status); + printk(KERN_DEBUG "%s: Interrupt, status %04x\n", + dev->name, intr_status); if ((intr_status & (NormalIntr|AbnormalIntr)) == 0) break; @@ -1156,8 +1160,9 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) netdev_error(dev, intr_status); if (--work_limit < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", dev->name, intr_status); + dev_warn(&dev->dev, + "Too much work at interrupt, status=0x%04x\n", + intr_status); /* Set the timer to re-enable the other interrupts after 10*82usec ticks. */ spin_lock(&np->lock); @@ -1171,8 +1176,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) } while (1); if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, ioread32(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n", + dev->name, ioread32(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1185,8 +1190,8 @@ static int netdev_rx(struct net_device *dev) int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", - entry, np->rx_ring[entry].status); + printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n", + entry, np->rx_ring[entry].status); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1195,24 +1200,24 @@ static int netdev_rx(struct net_device *dev) s32 status = desc->status; if (debug > 4) - printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", - status); + printk(KERN_DEBUG " netdev_rx() status was %08x\n", + status); if (status < 0) break; if ((status & 0x38008300) != 0x0300) { if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { - printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, entry %#x status %4.4x!\n", - dev->name, np->cur_rx, status); + dev_warn(&dev->dev, + "Oversized Ethernet frame spanned multiple buffers, entry %#x status %04x!\n", + np->cur_rx, status); np->stats.rx_length_errors++; } } else if (status & 0x8000) { /* There was a fatal error. */ if (debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); + printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", + dev->name, status); np->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) np->stats.rx_length_errors++; if (status & 0x004C) np->stats.rx_frame_errors++; @@ -1225,8 +1230,8 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version if (debug > 4) - printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" - " status %x.\n", pkt_len, status); + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d status %x\n", + pkt_len, status); #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1251,11 +1256,10 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5) - printk(KERN_DEBUG " Rx data %pM %pM" - " %2.2x%2.2x %d.%d.%d.%d.\n", + printk(KERN_DEBUG " Rx data %pM %pM %02x%02x %pI4\n", &skb->data[0], &skb->data[6], skb->data[12], skb->data[13], - skb->data[14], skb->data[15], skb->data[16], skb->data[17]); + &skb->data[14]); #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1293,8 +1297,8 @@ static void netdev_error(struct net_device *dev, int intr_status) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n", - dev->name, intr_status); + printk(KERN_DEBUG "%s: Abnormal event, %08x\n", + dev->name, intr_status); if (intr_status == 0xffffffff) return; spin_lock(&np->lock); @@ -1314,8 +1318,8 @@ static void netdev_error(struct net_device *dev, int intr_status) new = 127; /* load full packet before starting */ new = (np->csr6 & ~(0x7F << 14)) | (new<<14); #endif - printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n", - dev->name, new); + printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n", + dev->name, new); update_csr6(dev, new); } if (intr_status & RxDied) { /* Missed a Rx frame. */ @@ -1487,11 +1491,13 @@ static int netdev_close(struct net_device *dev) netif_stop_queue(dev); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x " - "Config %8.8x.\n", dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n", + dev->name, ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d\n", + dev->name, + np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); } /* Stop the chip's Tx and Rx processes. */ @@ -1512,18 +1518,16 @@ static int netdev_close(struct net_device *dev) if (debug > 2) { int i; - printk(KERN_DEBUG" Tx ring at %8.8x:\n", - (int)np->tx_ring); + printk(KERN_DEBUG" Tx ring at %08x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n", - i, np->tx_ring[i].length, - np->tx_ring[i].status, np->tx_ring[i].buffer1); - printk(KERN_DEBUG " Rx ring %8.8x:\n", - (int)np->rx_ring); + printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n", + i, np->tx_ring[i].length, + np->tx_ring[i].status, np->tx_ring[i].buffer1); + printk(KERN_DEBUG " Rx ring %08x:\n", (int)np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", - i, np->rx_ring[i].length, - np->rx_ring[i].status, np->rx_ring[i].buffer1); + printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n", + i, np->rx_ring[i].length, + np->rx_ring[i].status, np->rx_ring[i].buffer1); } } #endif /* __i386__ debugging only */ @@ -1622,9 +1626,8 @@ static int w840_resume (struct pci_dev *pdev) goto out; /* device not suspended */ if (netif_running(dev)) { if ((retval = pci_enable_device(pdev))) { - printk (KERN_ERR - "%s: pci_enable_device failed in resume\n", - dev->name); + dev_err(&dev->dev, + "pci_enable_device failed in resume\n"); goto out; } spin_lock_irq(&np->lock); -- GitLab From 44298ec0f20c45b9be96e181976aef1152d373b2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 28 Jan 2010 20:59:29 +0000 Subject: [PATCH 1415/3892] tulip/xircom_cb.c: Use dev_ and pr_ Convert printks to dev_ where a dev is available Convert printks to pr_ where not Coalesce format strings Change print formats with %d.dx to %0dx Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Remove DRV_NAME and xircom_cb from pr_ Convert embedded function names in logging messages to %s, __func__ Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/tulip/xircom_cb.c | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index c84123fd635c..acfeeb980562 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -14,6 +14,8 @@ * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -234,7 +236,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ pci_write_config_word (pdev, PCI_STATUS,tmp16); if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) { - printk(KERN_ERR "xircom_probe: failed to allocate io-region\n"); + pr_err("%s: failed to allocate io-region\n", __func__); return -ENODEV; } @@ -245,7 +247,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ */ dev = alloc_etherdev(sizeof(struct xircom_private)); if (!dev) { - printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); + pr_err("%s: failed to allocate etherdev\n", __func__); goto device_fail; } private = netdev_priv(dev); @@ -253,12 +255,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ /* Allocate the send/receive buffers */ private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); if (private->rx_buffer == NULL) { - printk(KERN_ERR "xircom_probe: no memory for rx buffer \n"); + pr_err("%s: no memory for rx buffer\n", __func__); goto rx_buf_fail; } private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle); if (private->tx_buffer == NULL) { - printk(KERN_ERR "xircom_probe: no memory for tx buffer \n"); + pr_err("%s: no memory for tx buffer\n", __func__); goto tx_buf_fail; } @@ -281,11 +283,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ pci_set_drvdata(pdev, dev); if (register_netdev(dev)) { - printk(KERN_ERR "xircom_probe: netdevice registration failed.\n"); + pr_err("%s: netdevice registration failed\n", __func__); goto reg_fail; } - printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, pdev->revision, pdev->irq); + dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n", + pdev->revision, pdev->irq); /* start the transmitter to get a heartbeat */ /* TODO: send 2 dummy packets here */ transceiver_voodoo(private); @@ -347,8 +350,10 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) #ifdef DEBUG print_binary(status); - printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]); - printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]); + printk("tx status 0x%08x 0x%08x \n", + card->tx_buffer[0], card->tx_buffer[4]); + printk("rx status 0x%08x 0x%08x \n", + card->rx_buffer[0], card->rx_buffer[4]); #endif /* Handle shared irq and hotplug */ if (status == 0 || status == 0xffffffff) { @@ -358,9 +363,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) if (link_status_changed(card)) { int newlink; - printk(KERN_DEBUG "xircom_cb: Link status has changed \n"); + printk(KERN_DEBUG "xircom_cb: Link status has changed\n"); newlink = link_status(card); - printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); + dev_info(&dev->dev, "Link is %i mbit\n", newlink); if (newlink) netif_carrier_on(dev); else @@ -457,7 +462,8 @@ static int xircom_open(struct net_device *dev) struct xircom_private *xp = netdev_priv(dev); int retval; enter("xircom_open"); - printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); + pr_info("xircom cardbus adaptor found, registering as %s, using irq %i \n", + dev->name, dev->irq); retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); if (retval) { leave("xircom_open - No IRQ"); @@ -770,7 +776,7 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n"); + pr_err("Receiver failed to deactivate\n"); } /* enable the receiver */ @@ -787,7 +793,7 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n"); + pr_err("Receiver failed to re-activate\n"); } leave("activate_receiver"); @@ -818,7 +824,7 @@ static void deactivate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n"); + pr_err("Receiver failed to deactivate\n"); } @@ -861,7 +867,7 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n"); + pr_err("Transmitter failed to deactivate\n"); } /* enable the transmitter */ @@ -878,7 +884,7 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n"); + pr_err("Transmitter failed to re-activate\n"); } leave("activate_transmitter"); @@ -909,7 +915,7 @@ static void deactivate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n"); + pr_err("Transmitter failed to deactivate\n"); } @@ -1184,7 +1190,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri struct sk_buff *skb; if (pkt_len > 1518) { - printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len); + pr_err("Packet length %i is bogus\n", pkt_len); pkt_len = 1518; } @@ -1222,7 +1228,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p status = le32_to_cpu(card->tx_buffer[4*descnr]); #if 0 if (status & 0x8000) { /* Major error */ - printk(KERN_ERR "Major transmit error status %x \n", status); + pr_err("Major transmit error status %x\n", status); card->tx_buffer[4*descnr] = 0; netif_wake_queue (dev); } -- GitLab From ef407beefbd9928792ccc93857e408e0057bc17b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Feb 2010 16:39:46 +0900 Subject: [PATCH 1416/3892] sh: Hook up ERR/PERR/SERR detection for SH7780 PCI host controllers. These were never handled before, so implement some common infrastructure to support them, then make use of that in the SH7780-specific code. In practice there is little here that can not be generalized for SH4 parts, which will be an incremental change as the 7780/7751 code is gradually unified. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/common.c | 79 ++++++++++++ arch/sh/drivers/pci/ops-sh4.c | 2 +- arch/sh/drivers/pci/pci-sh7780.c | 203 ++++++++++++++++++++++++++----- arch/sh/drivers/pci/pci.c | 51 ++++++++ arch/sh/include/asm/pci.h | 11 ++ 5 files changed, 317 insertions(+), 29 deletions(-) diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c index f67c946a8612..25aec005da18 100644 --- a/arch/sh/drivers/pci/common.c +++ b/arch/sh/drivers/pci/common.c @@ -1,4 +1,6 @@ #include +#include +#include #include static int __init @@ -62,3 +64,80 @@ int __init pci_is_66mhz_capable(struct pci_channel *hose, return cap66 > 0; } + +static void pcibios_enable_err(unsigned long __data) +{ + struct pci_channel *hose = (struct pci_channel *)__data; + + del_timer(&hose->err_timer); + printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n"); + enable_irq(hose->err_irq); +} + +static void pcibios_enable_serr(unsigned long __data) +{ + struct pci_channel *hose = (struct pci_channel *)__data; + + del_timer(&hose->serr_timer); + printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n"); + enable_irq(hose->serr_irq); +} + +void pcibios_enable_timers(struct pci_channel *hose) +{ + if (hose->err_irq) { + init_timer(&hose->err_timer); + hose->err_timer.data = (unsigned long)hose; + hose->err_timer.function = pcibios_enable_err; + } + + if (hose->serr_irq) { + init_timer(&hose->serr_timer); + hose->serr_timer.data = (unsigned long)hose; + hose->serr_timer.function = pcibios_enable_serr; + } +} + +/* + * A simple handler for the regular PCI status errors, called from IRQ + * context. + */ +unsigned int pcibios_handle_status_errors(unsigned long addr, + unsigned int status, + struct pci_channel *hose) +{ + unsigned int cmd = 0; + + if (status & PCI_STATUS_REC_MASTER_ABORT) { + printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr); + cmd |= PCI_STATUS_REC_MASTER_ABORT; + } + + if (status & PCI_STATUS_REC_TARGET_ABORT) { + printk(KERN_DEBUG "PCI: target abort: "); + pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT, 1); + printk("\n"); + + cmd |= PCI_STATUS_REC_TARGET_ABORT; + } + + if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) { + printk(KERN_DEBUG "PCI: parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY; + + /* Now back off of the IRQ for awhile */ + if (hose->err_irq) { + disable_irq(hose->err_irq); + hose->err_timer.expires = jiffies + HZ; + add_timer(&hose->err_timer); + } + } + + return cmd; +} diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c index e55e81a71727..0b81999fb88b 100644 --- a/arch/sh/drivers/pci/ops-sh4.c +++ b/arch/sh/drivers/pci/ops-sh4.c @@ -16,7 +16,7 @@ * Direct access to PCI hardware... */ #define CONFIG_CMD(bus, devfn, where) \ - (P1SEG | (bus->number << 16) | (devfn << 8) | (where & ~3)) + (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) static DEFINE_SPINLOCK(sh4_pci_lock); diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 0e0ddd67e6e1..86373314f458 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -39,8 +42,165 @@ static struct pci_channel sh7780_pci_controller = { .io_resource = &sh7785_io_resource, .io_offset = 0x00000000, .io_map_base = SH7780_PCI_IO_BASE, + .serr_irq = evt2irq(0xa00), + .err_irq = evt2irq(0xaa0), }; +struct pci_errors { + unsigned int mask; + const char *str; +} pci_arbiter_errors[] = { + { SH4_PCIAINT_MBKN, "master broken" }, + { SH4_PCIAINT_TBTO, "target bus time out" }, + { SH4_PCIAINT_MBTO, "master bus time out" }, + { SH4_PCIAINT_TABT, "target abort" }, + { SH4_PCIAINT_MABT, "master abort" }, + { SH4_PCIAINT_RDPE, "read data parity error" }, + { SH4_PCIAINT_WDPE, "write data parity error" }, +}, pci_interrupt_errors[] = { + { SH4_PCIINT_MLCK, "master lock error" }, + { SH4_PCIINT_TABT, "target-target abort" }, + { SH4_PCIINT_TRET, "target retry time out" }, + { SH4_PCIINT_MFDE, "master function disable erorr" }, + { SH4_PCIINT_PRTY, "address parity error" }, + { SH4_PCIINT_SERR, "SERR" }, + { SH4_PCIINT_TWDP, "data parity error for target write" }, + { SH4_PCIINT_TRDP, "PERR detected for target read" }, + { SH4_PCIINT_MTABT, "target abort for master" }, + { SH4_PCIINT_MMABT, "master abort for master" }, + { SH4_PCIINT_MWPD, "master write data parity error" }, + { SH4_PCIINT_MRPD, "master read data parity error" }, +}; + +static irqreturn_t sh7780_pci_err_irq(int irq, void *dev_id) +{ + struct pci_channel *hose = dev_id; + unsigned long addr; + unsigned int status; + unsigned int cmd; + int i; + + addr = __raw_readl(hose->reg_base + SH4_PCIALR); + + /* + * Handle status errors. + */ + status = __raw_readw(hose->reg_base + PCI_STATUS); + if (status & (PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT)) { + cmd = pcibios_handle_status_errors(addr, status, hose); + if (likely(cmd)) + __raw_writew(cmd, hose->reg_base + PCI_STATUS); + } + + /* + * Handle arbiter errors. + */ + status = __raw_readl(hose->reg_base + SH4_PCIAINT); + for (i = cmd = 0; i < ARRAY_SIZE(pci_arbiter_errors); i++) { + if (status & pci_arbiter_errors[i].mask) { + printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", + pci_arbiter_errors[i].str, addr); + cmd |= pci_arbiter_errors[i].mask; + } + } + __raw_writel(cmd, hose->reg_base + SH4_PCIAINT); + + /* + * Handle the remaining PCI errors. + */ + status = __raw_readl(hose->reg_base + SH4_PCIINT); + for (i = cmd = 0; i < ARRAY_SIZE(pci_interrupt_errors); i++) { + if (status & pci_interrupt_errors[i].mask) { + printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", + pci_interrupt_errors[i].str, addr); + cmd |= pci_interrupt_errors[i].mask; + } + } + __raw_writel(cmd, hose->reg_base + SH4_PCIINT); + + return IRQ_HANDLED; +} + +static irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id) +{ + struct pci_channel *hose = dev_id; + + printk(KERN_DEBUG "PCI: system error received: "); + pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); + printk("\n"); + + /* Deassert SERR */ + __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); + + /* Back off the IRQ for awhile */ + disable_irq(irq); + hose->serr_timer.expires = jiffies + HZ; + add_timer(&hose->serr_timer); + + return IRQ_HANDLED; +} + +static int __init sh7780_pci_setup_irqs(struct pci_channel *hose) +{ + int ret; + + /* Clear out PCI arbiter IRQs */ + __raw_writel(0, hose->reg_base + SH4_PCIAINT); + + /* Clear all error conditions */ + __raw_writew(PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_SIG_SYSTEM_ERROR | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_SIG_TARGET_ABORT | \ + PCI_STATUS_PARITY, hose->reg_base + PCI_STATUS); + + ret = request_irq(hose->serr_irq, sh7780_pci_serr_irq, IRQF_DISABLED, + "PCI SERR interrupt", hose); + if (unlikely(ret)) { + printk(KERN_ERR "PCI: Failed hooking SERR IRQ\n"); + return ret; + } + + /* + * The PCI ERR IRQ needs to be IRQF_SHARED since all of the power + * down IRQ vectors are routed through the ERR IRQ vector. We + * only request_irq() once as there is only a single masking + * source for multiple events. + */ + ret = request_irq(hose->err_irq, sh7780_pci_err_irq, IRQF_SHARED, + "PCI ERR interrupt", hose); + if (unlikely(ret)) { + free_irq(hose->serr_irq, hose); + return ret; + } + + /* Unmask all of the arbiter IRQs. */ + __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ + SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ + SH4_PCIAINT_WDPE, hose->reg_base + SH4_PCIAINTM); + + /* Unmask all of the PCI IRQs */ + __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ + SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ + SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ + SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ + SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ + SH4_PCIINTM_MRDPEIM, hose->reg_base + SH4_PCIINTM); + + return ret; +} + +static inline void __init sh7780_pci_teardown_irqs(struct pci_channel *hose) +{ + free_irq(hose->err_irq, hose); + free_irq(hose->serr_irq, hose); +} + static void __init sh7780_pci66_init(struct pci_channel *hose) { unsigned int tmp; @@ -149,33 +309,12 @@ static int __init sh7780_pci_init(void) __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1, chan->reg_base + SH4_PCILSR0); - /* Clear out PCI arbiter IRQs */ - __raw_writel(0, chan->reg_base + SH4_PCIAINT); - - /* Unmask all of the arbiter IRQs. */ - __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ - SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ - SH4_PCIAINT_WDPE, chan->reg_base + SH4_PCIAINTM); - - /* Clear all error conditions */ - __raw_writew(PCI_STATUS_DETECTED_PARITY | \ - PCI_STATUS_SIG_SYSTEM_ERROR | \ - PCI_STATUS_REC_MASTER_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_SIG_TARGET_ABORT | \ - PCI_STATUS_PARITY, chan->reg_base + PCI_STATUS); - - __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ - PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ - PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); - - /* Unmask all of the PCI IRQs */ - __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ - SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ - SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ - SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ - SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ - SH4_PCIINTM_MRDPEIM, chan->reg_base + SH4_PCIINTM); + /* + * Hook up the ERR and SERR IRQs. + */ + ret = sh7780_pci_setup_irqs(chan); + if (unlikely(ret)) + return ret; /* * Disable the cache snoop controller for non-coherent DMA. @@ -191,6 +330,10 @@ static int __init sh7780_pci_init(void) __raw_writel(0, chan->reg_base + SH7780_PCIIOBR); __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); + __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ + PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ + PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); + /* * Initialization mode complete, release the control register and * enable round robin mode to stop device overruns/starvation. @@ -200,7 +343,7 @@ static int __init sh7780_pci_init(void) ret = register_pci_controller(chan); if (unlikely(ret)) - return ret; + goto err; sh7780_pci66_init(chan); @@ -209,5 +352,9 @@ static int __init sh7780_pci_init(void) 66 : 33); return 0; + +err: + sh7780_pci_teardown_irqs(chan); + return ret; } arch_initcall(sh7780_pci_init); diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 488331c45033..8e42dfbbe76a 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -78,6 +78,11 @@ int __devinit register_pci_controller(struct pci_channel *hose) "registering PCI controller with io_map_base unset\n"); } + /* + * Setup the ERR/PERR and SERR timers, if available. + */ + pcibios_enable_timers(hose); + /* * Scan the bus if it is register after the PCI subsystem * initialization. @@ -289,6 +294,52 @@ char * __devinit pcibios_setup(char *str) return str; } +/* + * We can't use pci_find_device() here since we are + * called from interrupt context. + */ +static void pcibios_bus_report_status(struct pci_bus *bus, + unsigned int status_mask, int warn) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + /* + * ignore host bridge - we handle + * that separately + */ + if (dev->bus->number == 0 && dev->devfn == 0) + continue; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status == 0xffff) + continue; + + if ((status & status_mask) == 0) + continue; + + /* clear the status errors */ + pci_write_config_word(dev, PCI_STATUS, status & status_mask); + + if (warn) + printk("(%s: %04X) ", pci_name(dev), status); + } + + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->subordinate) + pcibios_bus_report_status(dev->subordinate, status_mask, warn); +} + +void pcibios_report_status(unsigned int status_mask, int warn) +{ + struct pci_channel *hose; + + for (hose = hose_head; hose; hose = hose->next) + pcibios_bus_report_status(hose->bus, status_mask, warn); +} + int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index bbd10cf79825..1de83f2161f7 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -29,9 +29,20 @@ struct pci_channel { unsigned int index; unsigned int need_domain_info; + + /* Optional error handling */ + struct timer_list err_timer, serr_timer; + unsigned int err_irq, serr_irq; }; +/* arch/sh/drivers/pci/pci.c */ extern int register_pci_controller(struct pci_channel *hose); +extern void pcibios_report_status(unsigned int status_mask, int warn); + +/* arch/sh/drivers/pci/common.c */ +extern void pcibios_enable_timers(struct pci_channel *hose); +extern unsigned int pcibios_handle_status_errors(unsigned long addr, + unsigned int status, struct pci_channel *hose); extern int pci_is_66mhz_capable(struct pci_channel *hose, int top_bus, int current_bus); -- GitLab From b6c58b1d987a5795086c5c2babd8c7367d2fdb8c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Feb 2010 20:01:50 +0900 Subject: [PATCH 1417/3892] sh: Improved multi-resource handling for SH7780 PCI. The SH7780 PCI controller supports 3 different ranges of PCI memory in addition to its PCI I/O window. In the case of 29-bit mode, only 2 memory windows are supported, while in 32-bit mode all 3 are visible. This attempts to make the resource handling completely dynamic and to permit platforms to map in as many apertures as they can handle. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/fixups-dreamcast.c | 2 +- arch/sh/drivers/pci/fixups-se7751.c | 6 +- arch/sh/drivers/pci/pci-dreamcast.c | 28 ++++----- arch/sh/drivers/pci/pci-sh5.c | 15 +++-- arch/sh/drivers/pci/pci-sh7751.c | 32 +++++----- arch/sh/drivers/pci/pci-sh7780.c | 86 +++++++++++++++++++------- arch/sh/drivers/pci/pci-sh7780.h | 14 +---- arch/sh/drivers/pci/pci.c | 37 ++++++----- arch/sh/include/asm/pci.h | 5 +- 9 files changed, 133 insertions(+), 92 deletions(-) diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c index ed7f489936f1..942ef4f155f5 100644 --- a/arch/sh/drivers/pci/fixups-dreamcast.c +++ b/arch/sh/drivers/pci/fixups-dreamcast.c @@ -39,7 +39,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev) /* * We also assume that dev->devfn == 0 */ - dev->resource[1].start = p->io_resource->start + 0x100; + dev->resource[1].start = p->resources[0].start + 0x100; dev->resource[1].end = dev->resource[1].start + 0x200 - 1; /* diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c index 475fa9f0fe2c..a4c7d3a4efca 100644 --- a/arch/sh/drivers/pci/fixups-se7751.c +++ b/arch/sh/drivers/pci/fixups-se7751.c @@ -97,12 +97,12 @@ int pci_fixup_pcic(struct pci_channel *chan) * meaning all calls go straight through... use BUG_ON to * catch erroneous assumption. */ - BUG_ON(chan->mem_resource->start != SH7751_PCI_MEMORY_BASE); + BUG_ON(chan->resources[1].start != SH7751_PCI_MEMORY_BASE); - PCIC_WRITE(SH7751_PCIMBR, chan->mem_resource->start); + PCIC_WRITE(SH7751_PCIMBR, chan->resources[1].start); /* Set IOBR for window containing area specified in pci.h */ - PCIC_WRITE(SH7751_PCIIOBR, (chan->io_resource->start & SH7751_PCIIOBR_MASK)); + PCIC_WRITE(SH7751_PCIIOBR, (chan->resources[0].start & SH7751_PCIIOBR_MASK)); /* All done, may as well say so... */ printk("SH7751 PCI: Finished initialization of the PCI controller\n"); diff --git a/arch/sh/drivers/pci/pci-dreamcast.c b/arch/sh/drivers/pci/pci-dreamcast.c index bd5a1e50ebf6..633694193af8 100644 --- a/arch/sh/drivers/pci/pci-dreamcast.c +++ b/arch/sh/drivers/pci/pci-dreamcast.c @@ -25,25 +25,25 @@ #include #include -static struct resource gapspci_io_resource = { - .name = "GAPSPCI IO", - .start = GAPSPCI_BBA_CONFIG, - .end = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1, - .flags = IORESOURCE_IO, -}; - -static struct resource gapspci_mem_resource = { - .name = "GAPSPCI mem", - .start = GAPSPCI_DMA_BASE, - .end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1, - .flags = IORESOURCE_MEM, +static struct resource gapspci_resources[] = { + { + .name = "GAPSPCI IO", + .start = GAPSPCI_BBA_CONFIG, + .end = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1, + .flags = IORESOURCE_IO, + }, { + .name = "GAPSPCI mem", + .start = GAPSPCI_DMA_BASE, + .end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1, + .flags = IORESOURCE_MEM, + }, }; static struct pci_channel dreamcast_pci_controller = { .pci_ops = &gapspci_pci_ops, - .io_resource = &gapspci_io_resource, + .resources = gapspci_resources, + .nr_resources = ARRAY_SIZE(gapspci_resources), .io_offset = 0x00000000, - .mem_resource = &gapspci_mem_resource, .mem_offset = 0x00000000, }; diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c index bce73faabc88..0bf296c78795 100644 --- a/arch/sh/drivers/pci/pci-sh5.c +++ b/arch/sh/drivers/pci/pci-sh5.c @@ -89,14 +89,13 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id) return IRQ_NONE; } -static struct resource sh5_io_resource = { /* place holder */ }; -static struct resource sh5_mem_resource = { /* place holder */ }; +static struct resource sh5_pci_resources[2]; static struct pci_channel sh5pci_controller = { .pci_ops = &sh5_pci_ops, - .mem_resource = &sh5_mem_resource, + .resources = sh5_pci_resources, + .nr_resources = ARRAY_SIZE(sh5_pci_resources), .mem_offset = 0x00000000, - .io_resource = &sh5_io_resource, .io_offset = 0x00000000, }; @@ -210,11 +209,11 @@ static int __init sh5pci_init(void) SH5PCI_WRITE(AINTM, ~0); SH5PCI_WRITE(PINTM, ~0); - sh5_io_resource.start = PCI_IO_AREA; - sh5_io_resource.end = PCI_IO_AREA + 0x10000; + sh5_pci_resources[0].start = PCI_IO_AREA; + sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000; - sh5_mem_resource.start = memStart; - sh5_mem_resource.end = memStart + memSize; + sh5_pci_resources[1].start = memStart; + sh5_pci_resources[1].end = memStart + memSize; return register_pci_controller(&sh5pci_controller); } diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 6ad5beb524aa..17811e5d287b 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -44,25 +44,25 @@ static int __init __area_sdram_check(struct pci_channel *chan, return 1; } -static struct resource sh7751_io_resource = { - .name = "SH7751_IO", - .start = SH7751_PCI_IO_BASE, - .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, - .flags = IORESOURCE_IO -}; - -static struct resource sh7751_mem_resource = { - .name = "SH7751_mem", - .start = SH7751_PCI_MEMORY_BASE, - .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM +static struct resource sh7751_pci_resources[] = { + { + .name = "SH7751_IO", + .start = SH7751_PCI_IO_BASE, + .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO + }, { + .name = "SH7751_mem", + .start = SH7751_PCI_MEMORY_BASE, + .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM + }, }; static struct pci_channel sh7751_pci_controller = { .pci_ops = &sh4_pci_ops, - .mem_resource = &sh7751_mem_resource, + .resources = sh7751_pci_resources, + .nr_resources = ARRAY_SIZE(sh7751_pci_resources), .mem_offset = 0x00000000, - .io_resource = &sh7751_io_resource, .io_offset = 0x00000000, .io_map_base = SH7751_PCI_IO_BASE, }; @@ -128,13 +128,13 @@ static int __init sh7751_pci_init(void) /* Set the local 16MB PCI memory space window to * the lowest PCI mapped address */ - word = chan->mem_resource->start & SH4_PCIMBR_MASK; + word = chan->resources[1].start & SH4_PCIMBR_MASK; pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word); pci_write_reg(chan, word , SH4_PCIMBR); /* Make sure the MSB's of IO window are set to access PCI space * correctly */ - word = chan->io_resource->start & SH4_PCIIOBR_MASK; + word = chan->resources[0].start & SH4_PCIIOBR_MASK; pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word); pci_write_reg(chan, word, SH4_PCIIOBR); diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 86373314f458..472f67aec337 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -21,27 +21,40 @@ #include #include -static struct resource sh7785_io_resource = { - .name = "SH7785_IO", - .start = 0x1000, - .end = SH7780_PCI_IO_SIZE - 1, - .flags = IORESOURCE_IO -}; - -static struct resource sh7785_mem_resource = { - .name = "SH7785_mem", - .start = SH7780_PCI_MEMORY_BASE, - .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM +static struct resource sh7785_pci_resources[] = { + { + .name = "SH7785_IO", + .start = 0x1000, + .end = SZ_4M - 1, + .flags = IORESOURCE_IO, + }, { + .name = "PCI MEM 0", + .start = 0xfd000000, + .end = 0xfd000000 + SZ_16M - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "PCI MEM 1", + .start = 0x10000000, + .end = 0x10000000 + SZ_64M - 1, + .flags = IORESOURCE_MEM, + }, { + /* + * 32-bit only resources must be last. + */ + .name = "PCI MEM 2", + .start = 0xc0000000, + .end = 0xc0000000 + SZ_512M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, }; static struct pci_channel sh7780_pci_controller = { .pci_ops = &sh4_pci_ops, - .mem_resource = &sh7785_mem_resource, - .mem_offset = 0x00000000, - .io_resource = &sh7785_io_resource, - .io_offset = 0x00000000, - .io_map_base = SH7780_PCI_IO_BASE, + .resources = sh7785_pci_resources, + .nr_resources = ARRAY_SIZE(sh7785_pci_resources), + .io_offset = 0, + .mem_offset = 0, + .io_map_base = 0xfe200000, .serr_irq = evt2irq(0xa00), .err_irq = evt2irq(0xaa0), }; @@ -231,7 +244,7 @@ static int __init sh7780_pci_init(void) size_t memsize; unsigned int id; const char *type; - int ret; + int ret, i; printk(KERN_NOTICE "PCI: Starting intialization.\n"); @@ -279,8 +292,6 @@ static int __init sh7780_pci_init(void) */ __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR); - __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); - memphys = __pa(memory_start); memsize = roundup_pow_of_two(memory_end - memory_start); @@ -324,9 +335,40 @@ static int __init sh7780_pci_init(void) __raw_writel(0, chan->reg_base + SH7780_PCICSCR1); __raw_writel(0, chan->reg_base + SH7780_PCICSAR1); - __raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0); - __raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0); + /* + * Setup the memory BARs + */ + for (i = 0; i < chan->nr_resources; i++) { + struct resource *res = chan->resources + (i + 1); + resource_size_t size; + + if (unlikely(res->flags & IORESOURCE_IO)) + continue; + + /* + * Make sure we're in the right physical addressing mode + * for dealing with the resource. + */ + if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) { + chan->nr_resources--; + continue; + } + size = resource_size(res); + + /* + * The MBMR mask is calculated in units of 256kB, which + * keeps things pretty simple. + */ + __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18, + chan->reg_base + SH7780_PCIMBMR(i)); + __raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i)); + } + + /* + * And I/O. + */ + __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); __raw_writel(0, chan->reg_base + SH7780_PCIIOBR); __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h index dee069c3865d..205dcbefe275 100644 --- a/arch/sh/drivers/pci/pci-sh7780.h +++ b/arch/sh/drivers/pci/pci-sh7780.h @@ -26,12 +26,6 @@ #define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */ #define SH7780_PCI_CONFIG_SIZE 0x01000000 /* Config space size */ -#define SH7780_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */ -#define SH7780_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */ - -#define SH7780_PCI_IO_BASE 0xFE200000 /* IO space base address */ -#define SH7780_PCI_IO_SIZE 0x00400000 /* Size of IO window */ - #define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */ /* SH7780 PCI Config Registers */ @@ -46,12 +40,8 @@ #define SH7780_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ #define SH7780_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ -#define SH7780_PCIMBR0 0x1E0 -#define SH7780_PCIMBMR0 0x1E4 -#define SH7780_PCIMBR1 0x1E8 -#define SH7780_PCIMBMR1 0x1EC -#define SH7780_PCIMBR2 0x1F0 -#define SH7780_PCIMBMR2 0x1F4 +#define SH7780_PCIMBR(x) (0x1E0 + ((x) * 8)) +#define SH7780_PCIMBMR(x) (0x1E4 + ((x) * 8)) #define SH7780_PCIIOBR 0x1F8 #define SH7780_PCIIOBMR 0x1FC #define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */ diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 8e42dfbbe76a..f4a69833fce2 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -60,11 +60,18 @@ static DEFINE_MUTEX(pci_scan_mutex); int __devinit register_pci_controller(struct pci_channel *hose) { - if (request_resource(&iomem_resource, hose->mem_resource) < 0) - goto out; - if (request_resource(&ioport_resource, hose->io_resource) < 0) { - release_resource(hose->mem_resource); - goto out; + int i; + + for (i = 0; i < hose->nr_resources; i++) { + struct resource *res = hose->resources + i; + + if (res->flags & IORESOURCE_IO) { + if (request_resource(&ioport_resource, res) < 0) + goto out; + } else { + if (request_resource(&iomem_resource, res) < 0) + goto out; + } } *hose_tail = hose; @@ -96,6 +103,9 @@ int __devinit register_pci_controller(struct pci_channel *hose) return 0; out: + for (--i; i >= 0; i--) + release_resource(&hose->resources[i]); + printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); return -1; } @@ -149,11 +159,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) { struct pci_dev *dev = bus->self; struct list_head *ln; - struct pci_channel *chan = bus->sysdata; + struct pci_channel *hose = bus->sysdata; if (!dev) { - bus->resource[0] = chan->io_resource; - bus->resource[1] = chan->mem_resource; + int i; + + for (i = 0; i < hose->nr_resources; i++) + bus->resource[i] = hose->resources + i; } for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { @@ -174,21 +186,18 @@ void pcibios_align_resource(void *data, struct resource *res, resource_size_t size, resource_size_t align) { struct pci_dev *dev = data; - struct pci_channel *chan = dev->sysdata; + struct pci_channel *hose = dev->sysdata; resource_size_t start = res->start; if (res->flags & IORESOURCE_IO) { - if (start < PCIBIOS_MIN_IO + chan->io_resource->start) - start = PCIBIOS_MIN_IO + chan->io_resource->start; + if (start < PCIBIOS_MIN_IO + hose->resources[0].start) + start = PCIBIOS_MIN_IO + hose->resources[0].start; /* * Put everything into 0x00-0xff region modulo 0x400. */ if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; - } else if (res->flags & IORESOURCE_MEM) { - if (start < PCIBIOS_MIN_MEM + chan->mem_resource->start) - start = PCIBIOS_MIN_MEM + chan->mem_resource->start; } res->start = start; diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index 1de83f2161f7..6d762cca2312 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -18,8 +18,9 @@ struct pci_channel { struct pci_bus *bus; struct pci_ops *pci_ops; - struct resource *io_resource; - struct resource *mem_resource; + + struct resource *resources; + unsigned int nr_resources; unsigned long io_offset; unsigned long mem_offset; -- GitLab From a75d7a4cf50d1cee14d8c9aaa2b971232d10f2c1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 1 Feb 2010 13:29:50 +0100 Subject: [PATCH 1418/3892] sound: control: actually allow TLV command access Creating a control with TLV_COMMAND access was not possible because snd_ctl_new1() forgot to include it in the mask of allowable access bits. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/core/control.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 268ab7471224..6a4764dcb180 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| SNDRV_CTL_ELEM_ACCESS_INACTIVE| - SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); kctl.info = ncontrol->info; kctl.get = ncontrol->get; kctl.put = ncontrol->put; -- GitLab From 6123637fafbf445cc9ce5774dc9516da0b2daa88 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 1 Feb 2010 13:30:56 +0100 Subject: [PATCH 1419/3892] sound: control: fix minimum TLV length Allow TLV blocks that do not have any values; the smallest possible TLV is an empty container or one where the information is only in the tag. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 6a4764dcb180..439ce64f9d82 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1100,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, if (copy_from_user(&tlv, _tlv, sizeof(tlv))) return -EFAULT; - if (tlv.length < sizeof(unsigned int) * 3) + if (tlv.length < sizeof(unsigned int) * 2) return -EINVAL; down_read(&card->controls_rwsem); kctl = snd_ctl_find_numid(card, tlv.numid); -- GitLab From b0580913797034a1001e867b8b492c75226bf77e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Jan 2010 14:51:26 +0100 Subject: [PATCH 1420/3892] ASoC: improve MCLKDIV calculation in wm8978, when OPCLK is not used In case, if OPCLK is not used, and PLL is used for driving the codec, the choice of PLL output frequency could result in a needlessly imprecise system clock frequency. Use an iterative process to select a precise configuration. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 115 ++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 37 deletions(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index ec2624b4c370..28bb59ea6ea1 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -58,6 +58,7 @@ struct wm8978_priv { unsigned int f_mclk; unsigned int f_256fs; unsigned int f_opclk; + int mclk_idx; enum wm8978_sysclk_src sysclk; u16 reg_cache[WM8978_CACHEREGNUM]; }; @@ -402,6 +403,35 @@ static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target, pll_div->k = k; } + +/* MCLK dividers */ +static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12}; +static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1}; + +/* + * find index >= idx, such that, for a given f_out, + * 3 * f_mclk / 4 <= f_PLLOUT < 13 * f_mclk / 4 + * f_out can be f_256fs or f_opclk, currently only used for f_256fs. Can be + * generalised for f_opclk with suitable coefficient arrays, but currently + * the OPCLK divisor is calculated directly, not iteratively. + */ +static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk, + unsigned int *f_pllout) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { + unsigned int f_pllout_x4 = 4 * f_out * mclk_numerator[i] / + mclk_denominator[i]; + if (3 * f_mclk <= f_pllout_x4 && f_pllout_x4 < 13 * f_mclk) { + *f_pllout = f_pllout_x4 / 4; + return i; + } + } + + return -EINVAL; +} + /* * Calculate internal frequencies and dividers, according to Figure 40 * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6 @@ -412,12 +442,16 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) struct wm8978_pll_div pll_div; unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk, f_256fs = wm8978->f_256fs; - unsigned int f2, opclk_div; + unsigned int f2; if (!f_mclk) return -EINVAL; if (f_opclk) { + unsigned int opclk_div; + /* Cannot set up MCLK divider now, do later */ + wm8978->mclk_idx = -1; + /* * The user needs OPCLK. Choose OPCLKDIV to put * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4. @@ -444,7 +478,7 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) wm8978->f_pllout = f_opclk * opclk_div; } else if (f_256fs) { /* - * Not using OPCLK, choose R: + * Not using OPCLK, but PLL is used for the codec, choose R: * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12. * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where * prescale = 1, or prescale = 2. Prescale is calculated inside @@ -453,18 +487,11 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK * must be 3.781MHz <= f_MCLK <= 32.768MHz */ - if (48 * f_256fs < 3 * f_mclk || 4 * f_256fs >= 13 * f_mclk) - return -EINVAL; + int idx = wm8978_enum_mclk(f_256fs, f_mclk, &wm8978->f_pllout); + if (idx < 0) + return idx; - /* - * MCLKDIV will be selected in .hw_params(), just choose a - * suitable f_PLLOUT - */ - if (4 * f_256fs < 3 * f_mclk) - /* Will have to use MCLKDIV */ - wm8978->f_pllout = wm8978->f_mclk * 3 / 4; - else - wm8978->f_pllout = f_256fs; + wm8978->mclk_idx = idx; /* GPIO1 into default mode as input - before configuring PLL */ snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); @@ -515,6 +542,20 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai, wm8978->f_opclk = div; if (wm8978->f_mclk) + /* + * We know the MCLK frequency, the user has requested + * OPCLK, configure the PLL based on that and start it + * and OPCLK immediately. We will configure PLL to match + * user-requested OPCLK frquency as good as possible. + * In fact, it is likely, that matching the sampling + * rate, when it becomes known, is more important, and + * we will not be reconfiguring PLL then, because we + * must not interrupt OPCLK. But it should be fine, + * because typically the user will request OPCLK to run + * at 256fs or 512fs, and for these cases we will also + * find an exact MCLK divider configuration - it will + * be equal to or double the OPCLK divisor. + */ ret = wm8978_configure_pll(codec); break; case WM8978_BCLKDIV: @@ -640,10 +681,6 @@ static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } -/* MCLK dividers */ -static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12}; -static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1}; - /* * Set PCM DAI bit size and sample rate. */ @@ -709,9 +746,11 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream, wm8978->f_256fs = params_rate(params) * 256; if (wm8978->sysclk == WM8978_MCLK) { + wm8978->mclk_idx = -1; f_sel = wm8978->f_mclk; } else { if (!wm8978->f_pllout) { + /* We only enter here, if OPCLK is not used */ int ret = wm8978_configure_pll(codec); if (ret < 0) return ret; @@ -719,32 +758,34 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream, f_sel = wm8978->f_pllout; } - /* - * In some cases it is possible to reconfigure PLL to a higher frequency - * by raising OPCLKDIV, but normally OPCLK is configured to 256 * fs or - * 512 * fs, so, we should be fine. - */ - if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) - return -EINVAL; + if (wm8978->mclk_idx < 0) { + /* Either MCLK is used directly, or OPCLK is used */ + if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { - diff = abs(wm8978->f_256fs * 3 - - f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]); + for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { + diff = abs(wm8978->f_256fs * 3 - + f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]); - if (diff < diff_best) { - diff_best = diff; - best = i; - } + if (diff < diff_best) { + diff_best = diff; + best = i; + } - if (!diff) - break; + if (!diff) + break; + } + } else { + /* OPCLK not used, codec driven by PLL */ + best = wm8978->mclk_idx; + diff = 0; } if (diff) - dev_warn(codec->dev, "Imprecise clock: %u%s\n", - f_sel * mclk_denominator[best] / mclk_numerator[best], - wm8978->sysclk == WM8978_MCLK ? - ", consider using PLL" : ""); + dev_warn(codec->dev, "Imprecise sampling rate: %uHz%s\n", + f_sel * mclk_denominator[best] / mclk_numerator[best] / 256, + wm8978->sysclk == WM8978_MCLK ? + ", consider using PLL" : ""); dev_dbg(codec->dev, "%s: fmt %d, rate %u, MCLK divisor #%d\n", __func__, params_format(params), params_rate(params), best); -- GitLab From 2f1ff6614cb5938e5c5760358752d92deb67fb63 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 Jan 2010 12:02:12 -0800 Subject: [PATCH 1421/3892] ASoC: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 8 ++------ sound/soc/blackfin/bf5xx-i2s-pcm.c | 3 +-- sound/soc/blackfin/bf5xx-tdm-pcm.c | 3 +-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index cf0dfb7ca221..67cbfe7283da 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -349,9 +349,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ size, &sport_handle->tx_dma_phy, GFP_KERNEL); if (!sport_handle->tx_dma_buf) { - pr_err("Failed to allocate memory for tx dma \ - buf - Please increase uncached DMA \ - memory region\n"); + pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n"); return -ENOMEM; } else memset(sport_handle->tx_dma_buf, 0, size); @@ -362,9 +360,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \ size, &sport_handle->rx_dma_phy, GFP_KERNEL); if (!sport_handle->rx_dma_buf) { - pr_err("Failed to allocate memory for rx dma \ - buf - Please increase uncached DMA \ - memory region\n"); + pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n"); return -ENOMEM; } else memset(sport_handle->rx_dma_buf, 0, size); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 62fbb8459569..c6c6a4a7d948 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -207,8 +207,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL); if (!buf->area) { - pr_err("Failed to allocate dma memory \ - Please increase uncached DMA memory region\n"); + pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n"); return -ENOMEM; } buf->bytes = size; diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index a8c73cbbd685..5e03bb2f3cd7 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -244,8 +244,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->area = dma_alloc_coherent(pcm->card->dev, size * 4, &buf->addr, GFP_KERNEL); if (!buf->area) { - pr_err("Failed to allocate dma memory \ - Please increase uncached DMA memory region\n"); + pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n"); return -ENOMEM; } buf->bytes = size; -- GitLab From c6c97bdaa3307d0811f14c99c38c63a8dae36e1f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 1 Feb 2010 09:55:56 -0500 Subject: [PATCH 1422/3892] ps3_gelic_wireless: fix format warning Signed-off-by: John W. Linville --- drivers/net/ps3_gelic_wireless.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index d520e9e8cdb2..448c5b6789d3 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1449,7 +1449,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, void *buf = NULL; size_t len; - pr_debug("%s: <- always=%d essid_len=%d\n", __func__, + pr_debug("%s: <- always=%d essid_len=%z\n", __func__, always_scan, essid_len); if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; -- GitLab From 3ed7074c4cc0de5ba77e180e5d96c23ef96859f0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Jan 2010 17:39:45 +0000 Subject: [PATCH 1423/3892] ASoC: Improved wm_hubs headphone handling Perform DC servo offset calibration using a series update sequence rather than startup update sequence, tuning the configuration of the WM8993 DC servo to make best use of this. Also introduce currently unused data allowing us to correct for any systematic errors in the DC servo calibration results and an alternative startup path for the headphone output which performs better with some chip revisions. The alternative setup sequence is enabled for WM8993. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 8 +++ sound/soc/codecs/wm_hubs.c | 142 ++++++++++++++++++++++++++++++------- sound/soc/codecs/wm_hubs.h | 6 ++ 3 files changed, 130 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 828d8174d5b7..bacfc2f20d70 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -213,6 +213,7 @@ static struct { }; struct wm8993_priv { + struct wm_hubs_data hubs_data; u16 reg_cache[WM8993_REGISTER_COUNT]; struct wm8993_platform_data pdata; struct snd_soc_codec codec; @@ -997,6 +998,11 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Tune DC servo configuration */ + snd_soc_write(codec, 0x44, 3); + snd_soc_write(codec, 0x56, 3); + snd_soc_write(codec, 0x44, 0); + /* Bring up VMID with fast soft start */ snd_soc_update_bits(codec, WM8993_ANTIPOP2, WM8993_STARTUP_BIAS_ENA | @@ -1591,6 +1597,8 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, codec->num_dai = 1; codec->private_data = wm8993; + wm8993->hubs_data.hp_startup_mode = 1; + memcpy(wm8993->reg_cache, wm8993_reg_defaults, sizeof(wm8993->reg_cache)); diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index a67319d9ca7e..0ad9f5d536c6 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -68,24 +68,77 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec) int count = 0; dev_dbg(codec->dev, "Waiting for DC servo...\n"); + do { count++; msleep(1); reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); - dev_dbg(codec->dev, "DC servo status: %x\n", reg); - } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) - != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); + dev_dbg(codec->dev, "DC servo: %x\n", reg); + } while (reg & WM8993_DCS_DATAPATH_BUSY); - if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) - != WM8993_DCS_CAL_COMPLETE_MASK) + if (reg & WM8993_DCS_DATAPATH_BUSY) dev_err(codec->dev, "Timed out waiting for DC Servo\n"); } +/* + * Startup calibration of the DC servo + */ +static void calibrate_dc_servo(struct snd_soc_codec *codec) +{ + struct wm_hubs_data *hubs = codec->private_data; + u16 reg, dcs_cfg; + + /* Set for 32 series updates */ + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_SERIES_NO_01_MASK, + 32 << WM8993_DCS_SERIES_NO_01_SHIFT); + + /* Enable the DC servo. Write all bits to avoid triggering startup + * or write calibration. + */ + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + 0xFFFF, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1 | + WM8993_DCS_TRIG_SERIES_1 | + WM8993_DCS_TRIG_SERIES_0); + + wait_for_dc_servo(codec); + + /* Apply correction to DC servo result */ + if (hubs->dcs_codes) { + dev_dbg(codec->dev, "Applying %d code DC servo correction\n", + hubs->dcs_codes); + + /* HPOUT1L */ + reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) & + WM8993_DCS_INTEG_CHAN_0_MASK;; + reg += hubs->dcs_codes; + dcs_cfg = reg << WM8993_DCS_DAC_WR_VAL_1_SHIFT; + + /* HPOUT1R */ + reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) & + WM8993_DCS_INTEG_CHAN_1_MASK; + reg += hubs->dcs_codes; + dcs_cfg |= reg; + + /* Do it */ + snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg); + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + WM8993_DCS_TRIG_DAC_WR_0 | + WM8993_DCS_TRIG_DAC_WR_1, + WM8993_DCS_TRIG_DAC_WR_0 | + WM8993_DCS_TRIG_DAC_WR_1); + + wait_for_dc_servo(codec); + } +} + /* * Update the DC servo calibration on gain changes */ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int ret; @@ -251,6 +304,47 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, line_tlv), }; +static int hp_supply_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_hubs_data *hubs = codec->private_data; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (hubs->hp_startup_mode) { + case 0: + break; + case 1: + /* Enable the headphone amp */ + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_HPOUT1L_ENA | + WM8993_HPOUT1R_ENA, + WM8993_HPOUT1L_ENA | + WM8993_HPOUT1R_ENA); + + /* Enable the second stage */ + snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, + WM8993_HPOUT1L_DLY | + WM8993_HPOUT1R_DLY, + WM8993_HPOUT1L_DLY | + WM8993_HPOUT1R_DLY); + break; + default: + dev_err(codec->dev, "Unknown HP startup mode %d\n", + hubs->hp_startup_mode); + break; + } + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, + WM8993_CP_ENA, 0); + break; + } + + return 0; +} + static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -271,14 +365,11 @@ static int hp_event(struct snd_soc_dapm_widget *w, reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); - /* Start the DC servo */ - snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - 0xFFFF, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1 | - WM8993_DCS_TRIG_STARTUP_1 | - WM8993_DCS_TRIG_STARTUP_0); - wait_for_dc_servo(codec); + /* Smallest supported update interval */ + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_TIMER_PERIOD_01_MASK, 1); + + calibrate_dc_servo(codec); reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; @@ -286,23 +377,19 @@ static int hp_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: - reg &= ~(WM8993_HPOUT1L_RMV_SHORT | - WM8993_HPOUT1L_DLY | - WM8993_HPOUT1L_OUTP | - WM8993_HPOUT1R_RMV_SHORT | - WM8993_HPOUT1R_DLY | - WM8993_HPOUT1R_OUTP); + snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, + WM8993_HPOUT1L_DLY | + WM8993_HPOUT1R_DLY | + WM8993_HPOUT1L_RMV_SHORT | + WM8993_HPOUT1R_RMV_SHORT, 0); - snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - 0xffff, 0); + snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, + WM8993_HPOUT1L_OUTP | + WM8993_HPOUT1R_OUTP, 0); - snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, 0); - - snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, - WM8993_CP_ENA, 0); break; } @@ -473,6 +560,8 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -626,6 +715,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "Headphone PGA", NULL, "Left Headphone Mux" }, { "Headphone PGA", NULL, "Right Headphone Mux" }, { "Headphone PGA", NULL, "CLK_SYS" }, + { "Headphone PGA", NULL, "Headphone Supply" }, { "HPOUT1L", NULL, "Headphone PGA" }, { "HPOUT1R", NULL, "Headphone PGA" }, diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index 36d3fba1de8b..420104fe9c90 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -18,6 +18,12 @@ struct snd_soc_codec; extern const unsigned int wm_hubs_spkmix_tlv[]; +/* This *must* be the first element of the codec->private_data struct */ +struct wm_hubs_data { + int dcs_codes; + int hp_startup_mode; +}; + extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, -- GitLab From be587ef4f20cb5a0e42264909fa702a24081a160 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Feb 2010 18:31:06 +0000 Subject: [PATCH 1424/3892] ASoC: Activate DCS correction for WM8993 Use a two code correction for optimal performance. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index bacfc2f20d70..61239e0e9556 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1,7 +1,7 @@ /* * wm8993.c -- WM8993 ALSA SoC audio driver * - * Copyright 2009 Wolfson Microelectronics plc + * Copyright 2009, 2010 Wolfson Microelectronics plc * * Author: Mark Brown * @@ -1598,6 +1598,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, codec->private_data = wm8993; wm8993->hubs_data.hp_startup_mode = 1; + wm8993->hubs_data.dcs_codes = -2; memcpy(wm8993->reg_cache, wm8993_reg_defaults, sizeof(wm8993->reg_cache)); -- GitLab From 9e6e96a197a03752d39a63e4f83e0b707ccedad7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Jan 2010 17:47:12 +0000 Subject: [PATCH 1425/3892] ASoC: Add WM8994 CODEC driver The WM8994 is a highly integrated ultra-low power hi-fi audio subsystem designed for smartphones and other portable devices rich in multimedia features. It provides advanced digital mixing facilities enabling low power high quality interconnection of CPU, baseband and other audio sources through flexible digital and analogue routing, and integrates a class W headphone driver and stereo class D speaker drivers. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8994.c | 3870 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8994.h | 26 + 4 files changed, 3902 insertions(+) create mode 100644 sound/soc/codecs/wm8994.c create mode 100644 sound/soc/codecs/wm8994.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0aad72fc1961..6b8a10120f9c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -61,6 +61,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C select SND_SOC_WM8993 if I2C + select SND_SOC_WM8994 if I2C select SND_SOC_WM9081 if I2C select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS @@ -243,6 +244,9 @@ config SND_SOC_WM8990 config SND_SOC_WM8993 tristate +config SND_SOC_WM8994 + tristate + config SND_SOC_WM9081 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fbd290e41e9e..209dd6c7c254 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -48,6 +48,7 @@ snd-soc-wm8978-objs := wm8978.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o snd-soc-wm8993-objs := wm8993.o +snd-soc-wm8994-objs := wm8994.o snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o @@ -108,6 +109,7 @@ obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o +obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c new file mode 100644 index 000000000000..5dd4b299f69e --- /dev/null +++ b/sound/soc/codecs/wm8994.c @@ -0,0 +1,3870 @@ +/* + * wm8994.c -- WM8994 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "wm8994.h" +#include "wm_hubs.h" + +static struct snd_soc_codec *wm8994_codec; +struct snd_soc_codec_device soc_codec_dev_wm8994; + +struct fll_config { + int src; + int in; + int out; +}; + +#define WM8994_NUM_DRC 3 +#define WM8994_NUM_EQ 3 + +static int wm8994_drc_base[] = { + WM8994_AIF1_DRC1_1, + WM8994_AIF1_DRC2_1, + WM8994_AIF2_DRC_1, +}; + +static int wm8994_retune_mobile_base[] = { + WM8994_AIF1_DAC1_EQ_GAINS_1, + WM8994_AIF1_DAC2_EQ_GAINS_1, + WM8994_AIF2_EQ_GAINS_1, +}; + +#define WM8994_REG_CACHE_SIZE 0x621 + +/* codec private data */ +struct wm8994_priv { + struct wm_hubs_data hubs; + struct snd_soc_codec codec; + u16 reg_cache[WM8994_REG_CACHE_SIZE + 1]; + int sysclk[2]; + int sysclk_rate[2]; + int mclk[2]; + int aifclk[2]; + struct fll_config fll[2], fll_suspend[2]; + + int dac_rates[2]; + int lrclk_shared[2]; + + /* Platform dependant DRC configuration */ + const char **drc_texts; + int drc_cfg[WM8994_NUM_DRC]; + struct soc_enum drc_enum; + + /* Platform dependant ReTune mobile configuration */ + int num_retune_mobile_texts; + const char **retune_mobile_texts; + int retune_mobile_cfg[WM8994_NUM_EQ]; + struct soc_enum retune_mobile_enum; + + struct wm8994_pdata *pdata; +}; + +static struct { + unsigned short readable; /* Mask of readable bits */ + unsigned short writable; /* Mask of writable bits */ + unsigned short vol; /* Mask of volatile bits */ +} access_masks[] = { + { 0xFFFF, 0xFFFF, 0x0000 }, /* R0 - Software Reset */ + { 0x3B37, 0x3B37, 0x0000 }, /* R1 - Power Management (1) */ + { 0x6BF0, 0x6BF0, 0x0000 }, /* R2 - Power Management (2) */ + { 0x3FF0, 0x3FF0, 0x0000 }, /* R3 - Power Management (3) */ + { 0x3F3F, 0x3F3F, 0x0000 }, /* R4 - Power Management (4) */ + { 0x3F0F, 0x3F0F, 0x0000 }, /* R5 - Power Management (5) */ + { 0x003F, 0x003F, 0x0000 }, /* R6 - Power Management (6) */ + { 0x0000, 0x0000, 0x0000 }, /* R7 */ + { 0x0000, 0x0000, 0x0000 }, /* R8 */ + { 0x0000, 0x0000, 0x0000 }, /* R9 */ + { 0x0000, 0x0000, 0x0000 }, /* R10 */ + { 0x0000, 0x0000, 0x0000 }, /* R11 */ + { 0x0000, 0x0000, 0x0000 }, /* R12 */ + { 0x0000, 0x0000, 0x0000 }, /* R13 */ + { 0x0000, 0x0000, 0x0000 }, /* R14 */ + { 0x0000, 0x0000, 0x0000 }, /* R15 */ + { 0x0000, 0x0000, 0x0000 }, /* R16 */ + { 0x0000, 0x0000, 0x0000 }, /* R17 */ + { 0x0000, 0x0000, 0x0000 }, /* R18 */ + { 0x0000, 0x0000, 0x0000 }, /* R19 */ + { 0x0000, 0x0000, 0x0000 }, /* R20 */ + { 0x01C0, 0x01C0, 0x0000 }, /* R21 - Input Mixer (1) */ + { 0x0000, 0x0000, 0x0000 }, /* R22 */ + { 0x0000, 0x0000, 0x0000 }, /* R23 */ + { 0x00DF, 0x01DF, 0x0000 }, /* R24 - Left Line Input 1&2 Volume */ + { 0x00DF, 0x01DF, 0x0000 }, /* R25 - Left Line Input 3&4 Volume */ + { 0x00DF, 0x01DF, 0x0000 }, /* R26 - Right Line Input 1&2 Volume */ + { 0x00DF, 0x01DF, 0x0000 }, /* R27 - Right Line Input 3&4 Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R28 - Left Output Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R29 - Right Output Volume */ + { 0x0077, 0x0077, 0x0000 }, /* R30 - Line Outputs Volume */ + { 0x0030, 0x0030, 0x0000 }, /* R31 - HPOUT2 Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R32 - Left OPGA Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R33 - Right OPGA Volume */ + { 0x007F, 0x007F, 0x0000 }, /* R34 - SPKMIXL Attenuation */ + { 0x017F, 0x017F, 0x0000 }, /* R35 - SPKMIXR Attenuation */ + { 0x003F, 0x003F, 0x0000 }, /* R36 - SPKOUT Mixers */ + { 0x003F, 0x003F, 0x0000 }, /* R37 - ClassD */ + { 0x00FF, 0x01FF, 0x0000 }, /* R38 - Speaker Volume Left */ + { 0x00FF, 0x01FF, 0x0000 }, /* R39 - Speaker Volume Right */ + { 0x00FF, 0x00FF, 0x0000 }, /* R40 - Input Mixer (2) */ + { 0x01B7, 0x01B7, 0x0000 }, /* R41 - Input Mixer (3) */ + { 0x01B7, 0x01B7, 0x0000 }, /* R42 - Input Mixer (4) */ + { 0x01C7, 0x01C7, 0x0000 }, /* R43 - Input Mixer (5) */ + { 0x01C7, 0x01C7, 0x0000 }, /* R44 - Input Mixer (6) */ + { 0x01FF, 0x01FF, 0x0000 }, /* R45 - Output Mixer (1) */ + { 0x01FF, 0x01FF, 0x0000 }, /* R46 - Output Mixer (2) */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R47 - Output Mixer (3) */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R48 - Output Mixer (4) */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R49 - Output Mixer (5) */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R50 - Output Mixer (6) */ + { 0x0038, 0x0038, 0x0000 }, /* R51 - HPOUT2 Mixer */ + { 0x0077, 0x0077, 0x0000 }, /* R52 - Line Mixer (1) */ + { 0x0077, 0x0077, 0x0000 }, /* R53 - Line Mixer (2) */ + { 0x03FF, 0x03FF, 0x0000 }, /* R54 - Speaker Mixer */ + { 0x00C1, 0x00C1, 0x0000 }, /* R55 - Additional Control */ + { 0x00F0, 0x00F0, 0x0000 }, /* R56 - AntiPOP (1) */ + { 0x01EF, 0x01EF, 0x0000 }, /* R57 - AntiPOP (2) */ + { 0x00FF, 0x00FF, 0x0000 }, /* R58 - MICBIAS */ + { 0x000F, 0x000F, 0x0000 }, /* R59 - LDO 1 */ + { 0x0007, 0x0007, 0x0000 }, /* R60 - LDO 2 */ + { 0x0000, 0x0000, 0x0000 }, /* R61 */ + { 0x0000, 0x0000, 0x0000 }, /* R62 */ + { 0x0000, 0x0000, 0x0000 }, /* R63 */ + { 0x0000, 0x0000, 0x0000 }, /* R64 */ + { 0x0000, 0x0000, 0x0000 }, /* R65 */ + { 0x0000, 0x0000, 0x0000 }, /* R66 */ + { 0x0000, 0x0000, 0x0000 }, /* R67 */ + { 0x0000, 0x0000, 0x0000 }, /* R68 */ + { 0x0000, 0x0000, 0x0000 }, /* R69 */ + { 0x0000, 0x0000, 0x0000 }, /* R70 */ + { 0x0000, 0x0000, 0x0000 }, /* R71 */ + { 0x0000, 0x0000, 0x0000 }, /* R72 */ + { 0x0000, 0x0000, 0x0000 }, /* R73 */ + { 0x0000, 0x0000, 0x0000 }, /* R74 */ + { 0x0000, 0x0000, 0x0000 }, /* R75 */ + { 0x8000, 0x8000, 0x0000 }, /* R76 - Charge Pump (1) */ + { 0x0000, 0x0000, 0x0000 }, /* R77 */ + { 0x0000, 0x0000, 0x0000 }, /* R78 */ + { 0x0000, 0x0000, 0x0000 }, /* R79 */ + { 0x0000, 0x0000, 0x0000 }, /* R80 */ + { 0x0301, 0x0301, 0x0000 }, /* R81 - Class W (1) */ + { 0x0000, 0x0000, 0x0000 }, /* R82 */ + { 0x0000, 0x0000, 0x0000 }, /* R83 */ + { 0x333F, 0x333F, 0x0000 }, /* R84 - DC Servo (1) */ + { 0x0FEF, 0x0FEF, 0x0000 }, /* R85 - DC Servo (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R86 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R87 - DC Servo (4) */ + { 0x0333, 0x0000, 0x0000 }, /* R88 - DC Servo Readback */ + { 0x0000, 0x0000, 0x0000 }, /* R89 */ + { 0x0000, 0x0000, 0x0000 }, /* R90 */ + { 0x0000, 0x0000, 0x0000 }, /* R91 */ + { 0x0000, 0x0000, 0x0000 }, /* R92 */ + { 0x0000, 0x0000, 0x0000 }, /* R93 */ + { 0x0000, 0x0000, 0x0000 }, /* R94 */ + { 0x0000, 0x0000, 0x0000 }, /* R95 */ + { 0x00EE, 0x00EE, 0x0000 }, /* R96 - Analogue HP (1) */ + { 0x0000, 0x0000, 0x0000 }, /* R97 */ + { 0x0000, 0x0000, 0x0000 }, /* R98 */ + { 0x0000, 0x0000, 0x0000 }, /* R99 */ + { 0x0000, 0x0000, 0x0000 }, /* R100 */ + { 0x0000, 0x0000, 0x0000 }, /* R101 */ + { 0x0000, 0x0000, 0x0000 }, /* R102 */ + { 0x0000, 0x0000, 0x0000 }, /* R103 */ + { 0x0000, 0x0000, 0x0000 }, /* R104 */ + { 0x0000, 0x0000, 0x0000 }, /* R105 */ + { 0x0000, 0x0000, 0x0000 }, /* R106 */ + { 0x0000, 0x0000, 0x0000 }, /* R107 */ + { 0x0000, 0x0000, 0x0000 }, /* R108 */ + { 0x0000, 0x0000, 0x0000 }, /* R109 */ + { 0x0000, 0x0000, 0x0000 }, /* R110 */ + { 0x0000, 0x0000, 0x0000 }, /* R111 */ + { 0x0000, 0x0000, 0x0000 }, /* R112 */ + { 0x0000, 0x0000, 0x0000 }, /* R113 */ + { 0x0000, 0x0000, 0x0000 }, /* R114 */ + { 0x0000, 0x0000, 0x0000 }, /* R115 */ + { 0x0000, 0x0000, 0x0000 }, /* R116 */ + { 0x0000, 0x0000, 0x0000 }, /* R117 */ + { 0x0000, 0x0000, 0x0000 }, /* R118 */ + { 0x0000, 0x0000, 0x0000 }, /* R119 */ + { 0x0000, 0x0000, 0x0000 }, /* R120 */ + { 0x0000, 0x0000, 0x0000 }, /* R121 */ + { 0x0000, 0x0000, 0x0000 }, /* R122 */ + { 0x0000, 0x0000, 0x0000 }, /* R123 */ + { 0x0000, 0x0000, 0x0000 }, /* R124 */ + { 0x0000, 0x0000, 0x0000 }, /* R125 */ + { 0x0000, 0x0000, 0x0000 }, /* R126 */ + { 0x0000, 0x0000, 0x0000 }, /* R127 */ + { 0x0000, 0x0000, 0x0000 }, /* R128 */ + { 0x0000, 0x0000, 0x0000 }, /* R129 */ + { 0x0000, 0x0000, 0x0000 }, /* R130 */ + { 0x0000, 0x0000, 0x0000 }, /* R131 */ + { 0x0000, 0x0000, 0x0000 }, /* R132 */ + { 0x0000, 0x0000, 0x0000 }, /* R133 */ + { 0x0000, 0x0000, 0x0000 }, /* R134 */ + { 0x0000, 0x0000, 0x0000 }, /* R135 */ + { 0x0000, 0x0000, 0x0000 }, /* R136 */ + { 0x0000, 0x0000, 0x0000 }, /* R137 */ + { 0x0000, 0x0000, 0x0000 }, /* R138 */ + { 0x0000, 0x0000, 0x0000 }, /* R139 */ + { 0x0000, 0x0000, 0x0000 }, /* R140 */ + { 0x0000, 0x0000, 0x0000 }, /* R141 */ + { 0x0000, 0x0000, 0x0000 }, /* R142 */ + { 0x0000, 0x0000, 0x0000 }, /* R143 */ + { 0x0000, 0x0000, 0x0000 }, /* R144 */ + { 0x0000, 0x0000, 0x0000 }, /* R145 */ + { 0x0000, 0x0000, 0x0000 }, /* R146 */ + { 0x0000, 0x0000, 0x0000 }, /* R147 */ + { 0x0000, 0x0000, 0x0000 }, /* R148 */ + { 0x0000, 0x0000, 0x0000 }, /* R149 */ + { 0x0000, 0x0000, 0x0000 }, /* R150 */ + { 0x0000, 0x0000, 0x0000 }, /* R151 */ + { 0x0000, 0x0000, 0x0000 }, /* R152 */ + { 0x0000, 0x0000, 0x0000 }, /* R153 */ + { 0x0000, 0x0000, 0x0000 }, /* R154 */ + { 0x0000, 0x0000, 0x0000 }, /* R155 */ + { 0x0000, 0x0000, 0x0000 }, /* R156 */ + { 0x0000, 0x0000, 0x0000 }, /* R157 */ + { 0x0000, 0x0000, 0x0000 }, /* R158 */ + { 0x0000, 0x0000, 0x0000 }, /* R159 */ + { 0x0000, 0x0000, 0x0000 }, /* R160 */ + { 0x0000, 0x0000, 0x0000 }, /* R161 */ + { 0x0000, 0x0000, 0x0000 }, /* R162 */ + { 0x0000, 0x0000, 0x0000 }, /* R163 */ + { 0x0000, 0x0000, 0x0000 }, /* R164 */ + { 0x0000, 0x0000, 0x0000 }, /* R165 */ + { 0x0000, 0x0000, 0x0000 }, /* R166 */ + { 0x0000, 0x0000, 0x0000 }, /* R167 */ + { 0x0000, 0x0000, 0x0000 }, /* R168 */ + { 0x0000, 0x0000, 0x0000 }, /* R169 */ + { 0x0000, 0x0000, 0x0000 }, /* R170 */ + { 0x0000, 0x0000, 0x0000 }, /* R171 */ + { 0x0000, 0x0000, 0x0000 }, /* R172 */ + { 0x0000, 0x0000, 0x0000 }, /* R173 */ + { 0x0000, 0x0000, 0x0000 }, /* R174 */ + { 0x0000, 0x0000, 0x0000 }, /* R175 */ + { 0x0000, 0x0000, 0x0000 }, /* R176 */ + { 0x0000, 0x0000, 0x0000 }, /* R177 */ + { 0x0000, 0x0000, 0x0000 }, /* R178 */ + { 0x0000, 0x0000, 0x0000 }, /* R179 */ + { 0x0000, 0x0000, 0x0000 }, /* R180 */ + { 0x0000, 0x0000, 0x0000 }, /* R181 */ + { 0x0000, 0x0000, 0x0000 }, /* R182 */ + { 0x0000, 0x0000, 0x0000 }, /* R183 */ + { 0x0000, 0x0000, 0x0000 }, /* R184 */ + { 0x0000, 0x0000, 0x0000 }, /* R185 */ + { 0x0000, 0x0000, 0x0000 }, /* R186 */ + { 0x0000, 0x0000, 0x0000 }, /* R187 */ + { 0x0000, 0x0000, 0x0000 }, /* R188 */ + { 0x0000, 0x0000, 0x0000 }, /* R189 */ + { 0x0000, 0x0000, 0x0000 }, /* R190 */ + { 0x0000, 0x0000, 0x0000 }, /* R191 */ + { 0x0000, 0x0000, 0x0000 }, /* R192 */ + { 0x0000, 0x0000, 0x0000 }, /* R193 */ + { 0x0000, 0x0000, 0x0000 }, /* R194 */ + { 0x0000, 0x0000, 0x0000 }, /* R195 */ + { 0x0000, 0x0000, 0x0000 }, /* R196 */ + { 0x0000, 0x0000, 0x0000 }, /* R197 */ + { 0x0000, 0x0000, 0x0000 }, /* R198 */ + { 0x0000, 0x0000, 0x0000 }, /* R199 */ + { 0x0000, 0x0000, 0x0000 }, /* R200 */ + { 0x0000, 0x0000, 0x0000 }, /* R201 */ + { 0x0000, 0x0000, 0x0000 }, /* R202 */ + { 0x0000, 0x0000, 0x0000 }, /* R203 */ + { 0x0000, 0x0000, 0x0000 }, /* R204 */ + { 0x0000, 0x0000, 0x0000 }, /* R205 */ + { 0x0000, 0x0000, 0x0000 }, /* R206 */ + { 0x0000, 0x0000, 0x0000 }, /* R207 */ + { 0x0000, 0x0000, 0x0000 }, /* R208 */ + { 0x0000, 0x0000, 0x0000 }, /* R209 */ + { 0x0000, 0x0000, 0x0000 }, /* R210 */ + { 0x0000, 0x0000, 0x0000 }, /* R211 */ + { 0x0000, 0x0000, 0x0000 }, /* R212 */ + { 0x0000, 0x0000, 0x0000 }, /* R213 */ + { 0x0000, 0x0000, 0x0000 }, /* R214 */ + { 0x0000, 0x0000, 0x0000 }, /* R215 */ + { 0x0000, 0x0000, 0x0000 }, /* R216 */ + { 0x0000, 0x0000, 0x0000 }, /* R217 */ + { 0x0000, 0x0000, 0x0000 }, /* R218 */ + { 0x0000, 0x0000, 0x0000 }, /* R219 */ + { 0x0000, 0x0000, 0x0000 }, /* R220 */ + { 0x0000, 0x0000, 0x0000 }, /* R221 */ + { 0x0000, 0x0000, 0x0000 }, /* R222 */ + { 0x0000, 0x0000, 0x0000 }, /* R223 */ + { 0x0000, 0x0000, 0x0000 }, /* R224 */ + { 0x0000, 0x0000, 0x0000 }, /* R225 */ + { 0x0000, 0x0000, 0x0000 }, /* R226 */ + { 0x0000, 0x0000, 0x0000 }, /* R227 */ + { 0x0000, 0x0000, 0x0000 }, /* R228 */ + { 0x0000, 0x0000, 0x0000 }, /* R229 */ + { 0x0000, 0x0000, 0x0000 }, /* R230 */ + { 0x0000, 0x0000, 0x0000 }, /* R231 */ + { 0x0000, 0x0000, 0x0000 }, /* R232 */ + { 0x0000, 0x0000, 0x0000 }, /* R233 */ + { 0x0000, 0x0000, 0x0000 }, /* R234 */ + { 0x0000, 0x0000, 0x0000 }, /* R235 */ + { 0x0000, 0x0000, 0x0000 }, /* R236 */ + { 0x0000, 0x0000, 0x0000 }, /* R237 */ + { 0x0000, 0x0000, 0x0000 }, /* R238 */ + { 0x0000, 0x0000, 0x0000 }, /* R239 */ + { 0x0000, 0x0000, 0x0000 }, /* R240 */ + { 0x0000, 0x0000, 0x0000 }, /* R241 */ + { 0x0000, 0x0000, 0x0000 }, /* R242 */ + { 0x0000, 0x0000, 0x0000 }, /* R243 */ + { 0x0000, 0x0000, 0x0000 }, /* R244 */ + { 0x0000, 0x0000, 0x0000 }, /* R245 */ + { 0x0000, 0x0000, 0x0000 }, /* R246 */ + { 0x0000, 0x0000, 0x0000 }, /* R247 */ + { 0x0000, 0x0000, 0x0000 }, /* R248 */ + { 0x0000, 0x0000, 0x0000 }, /* R249 */ + { 0x0000, 0x0000, 0x0000 }, /* R250 */ + { 0x0000, 0x0000, 0x0000 }, /* R251 */ + { 0x0000, 0x0000, 0x0000 }, /* R252 */ + { 0x0000, 0x0000, 0x0000 }, /* R253 */ + { 0x0000, 0x0000, 0x0000 }, /* R254 */ + { 0x0000, 0x0000, 0x0000 }, /* R255 */ + { 0x000F, 0x0000, 0x0000 }, /* R256 - Chip Revision */ + { 0x0074, 0x0074, 0x0000 }, /* R257 - Control Interface */ + { 0x0000, 0x0000, 0x0000 }, /* R258 */ + { 0x0000, 0x0000, 0x0000 }, /* R259 */ + { 0x0000, 0x0000, 0x0000 }, /* R260 */ + { 0x0000, 0x0000, 0x0000 }, /* R261 */ + { 0x0000, 0x0000, 0x0000 }, /* R262 */ + { 0x0000, 0x0000, 0x0000 }, /* R263 */ + { 0x0000, 0x0000, 0x0000 }, /* R264 */ + { 0x0000, 0x0000, 0x0000 }, /* R265 */ + { 0x0000, 0x0000, 0x0000 }, /* R266 */ + { 0x0000, 0x0000, 0x0000 }, /* R267 */ + { 0x0000, 0x0000, 0x0000 }, /* R268 */ + { 0x0000, 0x0000, 0x0000 }, /* R269 */ + { 0x0000, 0x0000, 0x0000 }, /* R270 */ + { 0x0000, 0x0000, 0x0000 }, /* R271 */ + { 0x807F, 0x837F, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */ + { 0x017F, 0x0000, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R274 */ + { 0x0000, 0x0000, 0x0000 }, /* R275 */ + { 0x0000, 0x0000, 0x0000 }, /* R276 */ + { 0x0000, 0x0000, 0x0000 }, /* R277 */ + { 0x0000, 0x0000, 0x0000 }, /* R278 */ + { 0x0000, 0x0000, 0x0000 }, /* R279 */ + { 0x0000, 0x0000, 0x0000 }, /* R280 */ + { 0x0000, 0x0000, 0x0000 }, /* R281 */ + { 0x0000, 0x0000, 0x0000 }, /* R282 */ + { 0x0000, 0x0000, 0x0000 }, /* R283 */ + { 0x0000, 0x0000, 0x0000 }, /* R284 */ + { 0x0000, 0x0000, 0x0000 }, /* R285 */ + { 0x0000, 0x0000, 0x0000 }, /* R286 */ + { 0x0000, 0x0000, 0x0000 }, /* R287 */ + { 0x0000, 0x0000, 0x0000 }, /* R288 */ + { 0x0000, 0x0000, 0x0000 }, /* R289 */ + { 0x0000, 0x0000, 0x0000 }, /* R290 */ + { 0x0000, 0x0000, 0x0000 }, /* R291 */ + { 0x0000, 0x0000, 0x0000 }, /* R292 */ + { 0x0000, 0x0000, 0x0000 }, /* R293 */ + { 0x0000, 0x0000, 0x0000 }, /* R294 */ + { 0x0000, 0x0000, 0x0000 }, /* R295 */ + { 0x0000, 0x0000, 0x0000 }, /* R296 */ + { 0x0000, 0x0000, 0x0000 }, /* R297 */ + { 0x0000, 0x0000, 0x0000 }, /* R298 */ + { 0x0000, 0x0000, 0x0000 }, /* R299 */ + { 0x0000, 0x0000, 0x0000 }, /* R300 */ + { 0x0000, 0x0000, 0x0000 }, /* R301 */ + { 0x0000, 0x0000, 0x0000 }, /* R302 */ + { 0x0000, 0x0000, 0x0000 }, /* R303 */ + { 0x0000, 0x0000, 0x0000 }, /* R304 */ + { 0x0000, 0x0000, 0x0000 }, /* R305 */ + { 0x0000, 0x0000, 0x0000 }, /* R306 */ + { 0x0000, 0x0000, 0x0000 }, /* R307 */ + { 0x0000, 0x0000, 0x0000 }, /* R308 */ + { 0x0000, 0x0000, 0x0000 }, /* R309 */ + { 0x0000, 0x0000, 0x0000 }, /* R310 */ + { 0x0000, 0x0000, 0x0000 }, /* R311 */ + { 0x0000, 0x0000, 0x0000 }, /* R312 */ + { 0x0000, 0x0000, 0x0000 }, /* R313 */ + { 0x0000, 0x0000, 0x0000 }, /* R314 */ + { 0x0000, 0x0000, 0x0000 }, /* R315 */ + { 0x0000, 0x0000, 0x0000 }, /* R316 */ + { 0x0000, 0x0000, 0x0000 }, /* R317 */ + { 0x0000, 0x0000, 0x0000 }, /* R318 */ + { 0x0000, 0x0000, 0x0000 }, /* R319 */ + { 0x0000, 0x0000, 0x0000 }, /* R320 */ + { 0x0000, 0x0000, 0x0000 }, /* R321 */ + { 0x0000, 0x0000, 0x0000 }, /* R322 */ + { 0x0000, 0x0000, 0x0000 }, /* R323 */ + { 0x0000, 0x0000, 0x0000 }, /* R324 */ + { 0x0000, 0x0000, 0x0000 }, /* R325 */ + { 0x0000, 0x0000, 0x0000 }, /* R326 */ + { 0x0000, 0x0000, 0x0000 }, /* R327 */ + { 0x0000, 0x0000, 0x0000 }, /* R328 */ + { 0x0000, 0x0000, 0x0000 }, /* R329 */ + { 0x0000, 0x0000, 0x0000 }, /* R330 */ + { 0x0000, 0x0000, 0x0000 }, /* R331 */ + { 0x0000, 0x0000, 0x0000 }, /* R332 */ + { 0x0000, 0x0000, 0x0000 }, /* R333 */ + { 0x0000, 0x0000, 0x0000 }, /* R334 */ + { 0x0000, 0x0000, 0x0000 }, /* R335 */ + { 0x0000, 0x0000, 0x0000 }, /* R336 */ + { 0x0000, 0x0000, 0x0000 }, /* R337 */ + { 0x0000, 0x0000, 0x0000 }, /* R338 */ + { 0x0000, 0x0000, 0x0000 }, /* R339 */ + { 0x0000, 0x0000, 0x0000 }, /* R340 */ + { 0x0000, 0x0000, 0x0000 }, /* R341 */ + { 0x0000, 0x0000, 0x0000 }, /* R342 */ + { 0x0000, 0x0000, 0x0000 }, /* R343 */ + { 0x0000, 0x0000, 0x0000 }, /* R344 */ + { 0x0000, 0x0000, 0x0000 }, /* R345 */ + { 0x0000, 0x0000, 0x0000 }, /* R346 */ + { 0x0000, 0x0000, 0x0000 }, /* R347 */ + { 0x0000, 0x0000, 0x0000 }, /* R348 */ + { 0x0000, 0x0000, 0x0000 }, /* R349 */ + { 0x0000, 0x0000, 0x0000 }, /* R350 */ + { 0x0000, 0x0000, 0x0000 }, /* R351 */ + { 0x0000, 0x0000, 0x0000 }, /* R352 */ + { 0x0000, 0x0000, 0x0000 }, /* R353 */ + { 0x0000, 0x0000, 0x0000 }, /* R354 */ + { 0x0000, 0x0000, 0x0000 }, /* R355 */ + { 0x0000, 0x0000, 0x0000 }, /* R356 */ + { 0x0000, 0x0000, 0x0000 }, /* R357 */ + { 0x0000, 0x0000, 0x0000 }, /* R358 */ + { 0x0000, 0x0000, 0x0000 }, /* R359 */ + { 0x0000, 0x0000, 0x0000 }, /* R360 */ + { 0x0000, 0x0000, 0x0000 }, /* R361 */ + { 0x0000, 0x0000, 0x0000 }, /* R362 */ + { 0x0000, 0x0000, 0x0000 }, /* R363 */ + { 0x0000, 0x0000, 0x0000 }, /* R364 */ + { 0x0000, 0x0000, 0x0000 }, /* R365 */ + { 0x0000, 0x0000, 0x0000 }, /* R366 */ + { 0x0000, 0x0000, 0x0000 }, /* R367 */ + { 0x0000, 0x0000, 0x0000 }, /* R368 */ + { 0x0000, 0x0000, 0x0000 }, /* R369 */ + { 0x0000, 0x0000, 0x0000 }, /* R370 */ + { 0x0000, 0x0000, 0x0000 }, /* R371 */ + { 0x0000, 0x0000, 0x0000 }, /* R372 */ + { 0x0000, 0x0000, 0x0000 }, /* R373 */ + { 0x0000, 0x0000, 0x0000 }, /* R374 */ + { 0x0000, 0x0000, 0x0000 }, /* R375 */ + { 0x0000, 0x0000, 0x0000 }, /* R376 */ + { 0x0000, 0x0000, 0x0000 }, /* R377 */ + { 0x0000, 0x0000, 0x0000 }, /* R378 */ + { 0x0000, 0x0000, 0x0000 }, /* R379 */ + { 0x0000, 0x0000, 0x0000 }, /* R380 */ + { 0x0000, 0x0000, 0x0000 }, /* R381 */ + { 0x0000, 0x0000, 0x0000 }, /* R382 */ + { 0x0000, 0x0000, 0x0000 }, /* R383 */ + { 0x0000, 0x0000, 0x0000 }, /* R384 */ + { 0x0000, 0x0000, 0x0000 }, /* R385 */ + { 0x0000, 0x0000, 0x0000 }, /* R386 */ + { 0x0000, 0x0000, 0x0000 }, /* R387 */ + { 0x0000, 0x0000, 0x0000 }, /* R388 */ + { 0x0000, 0x0000, 0x0000 }, /* R389 */ + { 0x0000, 0x0000, 0x0000 }, /* R390 */ + { 0x0000, 0x0000, 0x0000 }, /* R391 */ + { 0x0000, 0x0000, 0x0000 }, /* R392 */ + { 0x0000, 0x0000, 0x0000 }, /* R393 */ + { 0x0000, 0x0000, 0x0000 }, /* R394 */ + { 0x0000, 0x0000, 0x0000 }, /* R395 */ + { 0x0000, 0x0000, 0x0000 }, /* R396 */ + { 0x0000, 0x0000, 0x0000 }, /* R397 */ + { 0x0000, 0x0000, 0x0000 }, /* R398 */ + { 0x0000, 0x0000, 0x0000 }, /* R399 */ + { 0x0000, 0x0000, 0x0000 }, /* R400 */ + { 0x0000, 0x0000, 0x0000 }, /* R401 */ + { 0x0000, 0x0000, 0x0000 }, /* R402 */ + { 0x0000, 0x0000, 0x0000 }, /* R403 */ + { 0x0000, 0x0000, 0x0000 }, /* R404 */ + { 0x0000, 0x0000, 0x0000 }, /* R405 */ + { 0x0000, 0x0000, 0x0000 }, /* R406 */ + { 0x0000, 0x0000, 0x0000 }, /* R407 */ + { 0x0000, 0x0000, 0x0000 }, /* R408 */ + { 0x0000, 0x0000, 0x0000 }, /* R409 */ + { 0x0000, 0x0000, 0x0000 }, /* R410 */ + { 0x0000, 0x0000, 0x0000 }, /* R411 */ + { 0x0000, 0x0000, 0x0000 }, /* R412 */ + { 0x0000, 0x0000, 0x0000 }, /* R413 */ + { 0x0000, 0x0000, 0x0000 }, /* R414 */ + { 0x0000, 0x0000, 0x0000 }, /* R415 */ + { 0x0000, 0x0000, 0x0000 }, /* R416 */ + { 0x0000, 0x0000, 0x0000 }, /* R417 */ + { 0x0000, 0x0000, 0x0000 }, /* R418 */ + { 0x0000, 0x0000, 0x0000 }, /* R419 */ + { 0x0000, 0x0000, 0x0000 }, /* R420 */ + { 0x0000, 0x0000, 0x0000 }, /* R421 */ + { 0x0000, 0x0000, 0x0000 }, /* R422 */ + { 0x0000, 0x0000, 0x0000 }, /* R423 */ + { 0x0000, 0x0000, 0x0000 }, /* R424 */ + { 0x0000, 0x0000, 0x0000 }, /* R425 */ + { 0x0000, 0x0000, 0x0000 }, /* R426 */ + { 0x0000, 0x0000, 0x0000 }, /* R427 */ + { 0x0000, 0x0000, 0x0000 }, /* R428 */ + { 0x0000, 0x0000, 0x0000 }, /* R429 */ + { 0x0000, 0x0000, 0x0000 }, /* R430 */ + { 0x0000, 0x0000, 0x0000 }, /* R431 */ + { 0x0000, 0x0000, 0x0000 }, /* R432 */ + { 0x0000, 0x0000, 0x0000 }, /* R433 */ + { 0x0000, 0x0000, 0x0000 }, /* R434 */ + { 0x0000, 0x0000, 0x0000 }, /* R435 */ + { 0x0000, 0x0000, 0x0000 }, /* R436 */ + { 0x0000, 0x0000, 0x0000 }, /* R437 */ + { 0x0000, 0x0000, 0x0000 }, /* R438 */ + { 0x0000, 0x0000, 0x0000 }, /* R439 */ + { 0x0000, 0x0000, 0x0000 }, /* R440 */ + { 0x0000, 0x0000, 0x0000 }, /* R441 */ + { 0x0000, 0x0000, 0x0000 }, /* R442 */ + { 0x0000, 0x0000, 0x0000 }, /* R443 */ + { 0x0000, 0x0000, 0x0000 }, /* R444 */ + { 0x0000, 0x0000, 0x0000 }, /* R445 */ + { 0x0000, 0x0000, 0x0000 }, /* R446 */ + { 0x0000, 0x0000, 0x0000 }, /* R447 */ + { 0x0000, 0x0000, 0x0000 }, /* R448 */ + { 0x0000, 0x0000, 0x0000 }, /* R449 */ + { 0x0000, 0x0000, 0x0000 }, /* R450 */ + { 0x0000, 0x0000, 0x0000 }, /* R451 */ + { 0x0000, 0x0000, 0x0000 }, /* R452 */ + { 0x0000, 0x0000, 0x0000 }, /* R453 */ + { 0x0000, 0x0000, 0x0000 }, /* R454 */ + { 0x0000, 0x0000, 0x0000 }, /* R455 */ + { 0x0000, 0x0000, 0x0000 }, /* R456 */ + { 0x0000, 0x0000, 0x0000 }, /* R457 */ + { 0x0000, 0x0000, 0x0000 }, /* R458 */ + { 0x0000, 0x0000, 0x0000 }, /* R459 */ + { 0x0000, 0x0000, 0x0000 }, /* R460 */ + { 0x0000, 0x0000, 0x0000 }, /* R461 */ + { 0x0000, 0x0000, 0x0000 }, /* R462 */ + { 0x0000, 0x0000, 0x0000 }, /* R463 */ + { 0x0000, 0x0000, 0x0000 }, /* R464 */ + { 0x0000, 0x0000, 0x0000 }, /* R465 */ + { 0x0000, 0x0000, 0x0000 }, /* R466 */ + { 0x0000, 0x0000, 0x0000 }, /* R467 */ + { 0x0000, 0x0000, 0x0000 }, /* R468 */ + { 0x0000, 0x0000, 0x0000 }, /* R469 */ + { 0x0000, 0x0000, 0x0000 }, /* R470 */ + { 0x0000, 0x0000, 0x0000 }, /* R471 */ + { 0x0000, 0x0000, 0x0000 }, /* R472 */ + { 0x0000, 0x0000, 0x0000 }, /* R473 */ + { 0x0000, 0x0000, 0x0000 }, /* R474 */ + { 0x0000, 0x0000, 0x0000 }, /* R475 */ + { 0x0000, 0x0000, 0x0000 }, /* R476 */ + { 0x0000, 0x0000, 0x0000 }, /* R477 */ + { 0x0000, 0x0000, 0x0000 }, /* R478 */ + { 0x0000, 0x0000, 0x0000 }, /* R479 */ + { 0x0000, 0x0000, 0x0000 }, /* R480 */ + { 0x0000, 0x0000, 0x0000 }, /* R481 */ + { 0x0000, 0x0000, 0x0000 }, /* R482 */ + { 0x0000, 0x0000, 0x0000 }, /* R483 */ + { 0x0000, 0x0000, 0x0000 }, /* R484 */ + { 0x0000, 0x0000, 0x0000 }, /* R485 */ + { 0x0000, 0x0000, 0x0000 }, /* R486 */ + { 0x0000, 0x0000, 0x0000 }, /* R487 */ + { 0x0000, 0x0000, 0x0000 }, /* R488 */ + { 0x0000, 0x0000, 0x0000 }, /* R489 */ + { 0x0000, 0x0000, 0x0000 }, /* R490 */ + { 0x0000, 0x0000, 0x0000 }, /* R491 */ + { 0x0000, 0x0000, 0x0000 }, /* R492 */ + { 0x0000, 0x0000, 0x0000 }, /* R493 */ + { 0x0000, 0x0000, 0x0000 }, /* R494 */ + { 0x0000, 0x0000, 0x0000 }, /* R495 */ + { 0x0000, 0x0000, 0x0000 }, /* R496 */ + { 0x0000, 0x0000, 0x0000 }, /* R497 */ + { 0x0000, 0x0000, 0x0000 }, /* R498 */ + { 0x0000, 0x0000, 0x0000 }, /* R499 */ + { 0x0000, 0x0000, 0x0000 }, /* R500 */ + { 0x0000, 0x0000, 0x0000 }, /* R501 */ + { 0x0000, 0x0000, 0x0000 }, /* R502 */ + { 0x0000, 0x0000, 0x0000 }, /* R503 */ + { 0x0000, 0x0000, 0x0000 }, /* R504 */ + { 0x0000, 0x0000, 0x0000 }, /* R505 */ + { 0x0000, 0x0000, 0x0000 }, /* R506 */ + { 0x0000, 0x0000, 0x0000 }, /* R507 */ + { 0x0000, 0x0000, 0x0000 }, /* R508 */ + { 0x0000, 0x0000, 0x0000 }, /* R509 */ + { 0x0000, 0x0000, 0x0000 }, /* R510 */ + { 0x0000, 0x0000, 0x0000 }, /* R511 */ + { 0x001F, 0x001F, 0x0000 }, /* R512 - AIF1 Clocking (1) */ + { 0x003F, 0x003F, 0x0000 }, /* R513 - AIF1 Clocking (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R514 */ + { 0x0000, 0x0000, 0x0000 }, /* R515 */ + { 0x001F, 0x001F, 0x0000 }, /* R516 - AIF2 Clocking (1) */ + { 0x003F, 0x003F, 0x0000 }, /* R517 - AIF2 Clocking (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R518 */ + { 0x0000, 0x0000, 0x0000 }, /* R519 */ + { 0x001F, 0x001F, 0x0000 }, /* R520 - Clocking (1) */ + { 0x0777, 0x0777, 0x0000 }, /* R521 - Clocking (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R522 */ + { 0x0000, 0x0000, 0x0000 }, /* R523 */ + { 0x0000, 0x0000, 0x0000 }, /* R524 */ + { 0x0000, 0x0000, 0x0000 }, /* R525 */ + { 0x0000, 0x0000, 0x0000 }, /* R526 */ + { 0x0000, 0x0000, 0x0000 }, /* R527 */ + { 0x00FF, 0x00FF, 0x0000 }, /* R528 - AIF1 Rate */ + { 0x00FF, 0x00FF, 0x0000 }, /* R529 - AIF2 Rate */ + { 0x000F, 0x0000, 0x0000 }, /* R530 - Rate Status */ + { 0x0000, 0x0000, 0x0000 }, /* R531 */ + { 0x0000, 0x0000, 0x0000 }, /* R532 */ + { 0x0000, 0x0000, 0x0000 }, /* R533 */ + { 0x0000, 0x0000, 0x0000 }, /* R534 */ + { 0x0000, 0x0000, 0x0000 }, /* R535 */ + { 0x0000, 0x0000, 0x0000 }, /* R536 */ + { 0x0000, 0x0000, 0x0000 }, /* R537 */ + { 0x0000, 0x0000, 0x0000 }, /* R538 */ + { 0x0000, 0x0000, 0x0000 }, /* R539 */ + { 0x0000, 0x0000, 0x0000 }, /* R540 */ + { 0x0000, 0x0000, 0x0000 }, /* R541 */ + { 0x0000, 0x0000, 0x0000 }, /* R542 */ + { 0x0000, 0x0000, 0x0000 }, /* R543 */ + { 0x0007, 0x0007, 0x0000 }, /* R544 - FLL1 Control (1) */ + { 0x3F77, 0x3F77, 0x0000 }, /* R545 - FLL1 Control (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R546 - FLL1 Control (3) */ + { 0x7FEF, 0x7FEF, 0x0000 }, /* R547 - FLL1 Control (4) */ + { 0x1FDB, 0x1FDB, 0x0000 }, /* R548 - FLL1 Control (5) */ + { 0x0000, 0x0000, 0x0000 }, /* R549 */ + { 0x0000, 0x0000, 0x0000 }, /* R550 */ + { 0x0000, 0x0000, 0x0000 }, /* R551 */ + { 0x0000, 0x0000, 0x0000 }, /* R552 */ + { 0x0000, 0x0000, 0x0000 }, /* R553 */ + { 0x0000, 0x0000, 0x0000 }, /* R554 */ + { 0x0000, 0x0000, 0x0000 }, /* R555 */ + { 0x0000, 0x0000, 0x0000 }, /* R556 */ + { 0x0000, 0x0000, 0x0000 }, /* R557 */ + { 0x0000, 0x0000, 0x0000 }, /* R558 */ + { 0x0000, 0x0000, 0x0000 }, /* R559 */ + { 0x0000, 0x0000, 0x0000 }, /* R560 */ + { 0x0000, 0x0000, 0x0000 }, /* R561 */ + { 0x0000, 0x0000, 0x0000 }, /* R562 */ + { 0x0000, 0x0000, 0x0000 }, /* R563 */ + { 0x0000, 0x0000, 0x0000 }, /* R564 */ + { 0x0000, 0x0000, 0x0000 }, /* R565 */ + { 0x0000, 0x0000, 0x0000 }, /* R566 */ + { 0x0000, 0x0000, 0x0000 }, /* R567 */ + { 0x0000, 0x0000, 0x0000 }, /* R568 */ + { 0x0000, 0x0000, 0x0000 }, /* R569 */ + { 0x0000, 0x0000, 0x0000 }, /* R570 */ + { 0x0000, 0x0000, 0x0000 }, /* R571 */ + { 0x0000, 0x0000, 0x0000 }, /* R572 */ + { 0x0000, 0x0000, 0x0000 }, /* R573 */ + { 0x0000, 0x0000, 0x0000 }, /* R574 */ + { 0x0000, 0x0000, 0x0000 }, /* R575 */ + { 0x0007, 0x0007, 0x0000 }, /* R576 - FLL2 Control (1) */ + { 0x3F77, 0x3F77, 0x0000 }, /* R577 - FLL2 Control (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R578 - FLL2 Control (3) */ + { 0x7FEF, 0x7FEF, 0x0000 }, /* R579 - FLL2 Control (4) */ + { 0x1FDB, 0x1FDB, 0x0000 }, /* R580 - FLL2 Control (5) */ + { 0x0000, 0x0000, 0x0000 }, /* R581 */ + { 0x0000, 0x0000, 0x0000 }, /* R582 */ + { 0x0000, 0x0000, 0x0000 }, /* R583 */ + { 0x0000, 0x0000, 0x0000 }, /* R584 */ + { 0x0000, 0x0000, 0x0000 }, /* R585 */ + { 0x0000, 0x0000, 0x0000 }, /* R586 */ + { 0x0000, 0x0000, 0x0000 }, /* R587 */ + { 0x0000, 0x0000, 0x0000 }, /* R588 */ + { 0x0000, 0x0000, 0x0000 }, /* R589 */ + { 0x0000, 0x0000, 0x0000 }, /* R590 */ + { 0x0000, 0x0000, 0x0000 }, /* R591 */ + { 0x0000, 0x0000, 0x0000 }, /* R592 */ + { 0x0000, 0x0000, 0x0000 }, /* R593 */ + { 0x0000, 0x0000, 0x0000 }, /* R594 */ + { 0x0000, 0x0000, 0x0000 }, /* R595 */ + { 0x0000, 0x0000, 0x0000 }, /* R596 */ + { 0x0000, 0x0000, 0x0000 }, /* R597 */ + { 0x0000, 0x0000, 0x0000 }, /* R598 */ + { 0x0000, 0x0000, 0x0000 }, /* R599 */ + { 0x0000, 0x0000, 0x0000 }, /* R600 */ + { 0x0000, 0x0000, 0x0000 }, /* R601 */ + { 0x0000, 0x0000, 0x0000 }, /* R602 */ + { 0x0000, 0x0000, 0x0000 }, /* R603 */ + { 0x0000, 0x0000, 0x0000 }, /* R604 */ + { 0x0000, 0x0000, 0x0000 }, /* R605 */ + { 0x0000, 0x0000, 0x0000 }, /* R606 */ + { 0x0000, 0x0000, 0x0000 }, /* R607 */ + { 0x0000, 0x0000, 0x0000 }, /* R608 */ + { 0x0000, 0x0000, 0x0000 }, /* R609 */ + { 0x0000, 0x0000, 0x0000 }, /* R610 */ + { 0x0000, 0x0000, 0x0000 }, /* R611 */ + { 0x0000, 0x0000, 0x0000 }, /* R612 */ + { 0x0000, 0x0000, 0x0000 }, /* R613 */ + { 0x0000, 0x0000, 0x0000 }, /* R614 */ + { 0x0000, 0x0000, 0x0000 }, /* R615 */ + { 0x0000, 0x0000, 0x0000 }, /* R616 */ + { 0x0000, 0x0000, 0x0000 }, /* R617 */ + { 0x0000, 0x0000, 0x0000 }, /* R618 */ + { 0x0000, 0x0000, 0x0000 }, /* R619 */ + { 0x0000, 0x0000, 0x0000 }, /* R620 */ + { 0x0000, 0x0000, 0x0000 }, /* R621 */ + { 0x0000, 0x0000, 0x0000 }, /* R622 */ + { 0x0000, 0x0000, 0x0000 }, /* R623 */ + { 0x0000, 0x0000, 0x0000 }, /* R624 */ + { 0x0000, 0x0000, 0x0000 }, /* R625 */ + { 0x0000, 0x0000, 0x0000 }, /* R626 */ + { 0x0000, 0x0000, 0x0000 }, /* R627 */ + { 0x0000, 0x0000, 0x0000 }, /* R628 */ + { 0x0000, 0x0000, 0x0000 }, /* R629 */ + { 0x0000, 0x0000, 0x0000 }, /* R630 */ + { 0x0000, 0x0000, 0x0000 }, /* R631 */ + { 0x0000, 0x0000, 0x0000 }, /* R632 */ + { 0x0000, 0x0000, 0x0000 }, /* R633 */ + { 0x0000, 0x0000, 0x0000 }, /* R634 */ + { 0x0000, 0x0000, 0x0000 }, /* R635 */ + { 0x0000, 0x0000, 0x0000 }, /* R636 */ + { 0x0000, 0x0000, 0x0000 }, /* R637 */ + { 0x0000, 0x0000, 0x0000 }, /* R638 */ + { 0x0000, 0x0000, 0x0000 }, /* R639 */ + { 0x0000, 0x0000, 0x0000 }, /* R640 */ + { 0x0000, 0x0000, 0x0000 }, /* R641 */ + { 0x0000, 0x0000, 0x0000 }, /* R642 */ + { 0x0000, 0x0000, 0x0000 }, /* R643 */ + { 0x0000, 0x0000, 0x0000 }, /* R644 */ + { 0x0000, 0x0000, 0x0000 }, /* R645 */ + { 0x0000, 0x0000, 0x0000 }, /* R646 */ + { 0x0000, 0x0000, 0x0000 }, /* R647 */ + { 0x0000, 0x0000, 0x0000 }, /* R648 */ + { 0x0000, 0x0000, 0x0000 }, /* R649 */ + { 0x0000, 0x0000, 0x0000 }, /* R650 */ + { 0x0000, 0x0000, 0x0000 }, /* R651 */ + { 0x0000, 0x0000, 0x0000 }, /* R652 */ + { 0x0000, 0x0000, 0x0000 }, /* R653 */ + { 0x0000, 0x0000, 0x0000 }, /* R654 */ + { 0x0000, 0x0000, 0x0000 }, /* R655 */ + { 0x0000, 0x0000, 0x0000 }, /* R656 */ + { 0x0000, 0x0000, 0x0000 }, /* R657 */ + { 0x0000, 0x0000, 0x0000 }, /* R658 */ + { 0x0000, 0x0000, 0x0000 }, /* R659 */ + { 0x0000, 0x0000, 0x0000 }, /* R660 */ + { 0x0000, 0x0000, 0x0000 }, /* R661 */ + { 0x0000, 0x0000, 0x0000 }, /* R662 */ + { 0x0000, 0x0000, 0x0000 }, /* R663 */ + { 0x0000, 0x0000, 0x0000 }, /* R664 */ + { 0x0000, 0x0000, 0x0000 }, /* R665 */ + { 0x0000, 0x0000, 0x0000 }, /* R666 */ + { 0x0000, 0x0000, 0x0000 }, /* R667 */ + { 0x0000, 0x0000, 0x0000 }, /* R668 */ + { 0x0000, 0x0000, 0x0000 }, /* R669 */ + { 0x0000, 0x0000, 0x0000 }, /* R670 */ + { 0x0000, 0x0000, 0x0000 }, /* R671 */ + { 0x0000, 0x0000, 0x0000 }, /* R672 */ + { 0x0000, 0x0000, 0x0000 }, /* R673 */ + { 0x0000, 0x0000, 0x0000 }, /* R674 */ + { 0x0000, 0x0000, 0x0000 }, /* R675 */ + { 0x0000, 0x0000, 0x0000 }, /* R676 */ + { 0x0000, 0x0000, 0x0000 }, /* R677 */ + { 0x0000, 0x0000, 0x0000 }, /* R678 */ + { 0x0000, 0x0000, 0x0000 }, /* R679 */ + { 0x0000, 0x0000, 0x0000 }, /* R680 */ + { 0x0000, 0x0000, 0x0000 }, /* R681 */ + { 0x0000, 0x0000, 0x0000 }, /* R682 */ + { 0x0000, 0x0000, 0x0000 }, /* R683 */ + { 0x0000, 0x0000, 0x0000 }, /* R684 */ + { 0x0000, 0x0000, 0x0000 }, /* R685 */ + { 0x0000, 0x0000, 0x0000 }, /* R686 */ + { 0x0000, 0x0000, 0x0000 }, /* R687 */ + { 0x0000, 0x0000, 0x0000 }, /* R688 */ + { 0x0000, 0x0000, 0x0000 }, /* R689 */ + { 0x0000, 0x0000, 0x0000 }, /* R690 */ + { 0x0000, 0x0000, 0x0000 }, /* R691 */ + { 0x0000, 0x0000, 0x0000 }, /* R692 */ + { 0x0000, 0x0000, 0x0000 }, /* R693 */ + { 0x0000, 0x0000, 0x0000 }, /* R694 */ + { 0x0000, 0x0000, 0x0000 }, /* R695 */ + { 0x0000, 0x0000, 0x0000 }, /* R696 */ + { 0x0000, 0x0000, 0x0000 }, /* R697 */ + { 0x0000, 0x0000, 0x0000 }, /* R698 */ + { 0x0000, 0x0000, 0x0000 }, /* R699 */ + { 0x0000, 0x0000, 0x0000 }, /* R700 */ + { 0x0000, 0x0000, 0x0000 }, /* R701 */ + { 0x0000, 0x0000, 0x0000 }, /* R702 */ + { 0x0000, 0x0000, 0x0000 }, /* R703 */ + { 0x0000, 0x0000, 0x0000 }, /* R704 */ + { 0x0000, 0x0000, 0x0000 }, /* R705 */ + { 0x0000, 0x0000, 0x0000 }, /* R706 */ + { 0x0000, 0x0000, 0x0000 }, /* R707 */ + { 0x0000, 0x0000, 0x0000 }, /* R708 */ + { 0x0000, 0x0000, 0x0000 }, /* R709 */ + { 0x0000, 0x0000, 0x0000 }, /* R710 */ + { 0x0000, 0x0000, 0x0000 }, /* R711 */ + { 0x0000, 0x0000, 0x0000 }, /* R712 */ + { 0x0000, 0x0000, 0x0000 }, /* R713 */ + { 0x0000, 0x0000, 0x0000 }, /* R714 */ + { 0x0000, 0x0000, 0x0000 }, /* R715 */ + { 0x0000, 0x0000, 0x0000 }, /* R716 */ + { 0x0000, 0x0000, 0x0000 }, /* R717 */ + { 0x0000, 0x0000, 0x0000 }, /* R718 */ + { 0x0000, 0x0000, 0x0000 }, /* R719 */ + { 0x0000, 0x0000, 0x0000 }, /* R720 */ + { 0x0000, 0x0000, 0x0000 }, /* R721 */ + { 0x0000, 0x0000, 0x0000 }, /* R722 */ + { 0x0000, 0x0000, 0x0000 }, /* R723 */ + { 0x0000, 0x0000, 0x0000 }, /* R724 */ + { 0x0000, 0x0000, 0x0000 }, /* R725 */ + { 0x0000, 0x0000, 0x0000 }, /* R726 */ + { 0x0000, 0x0000, 0x0000 }, /* R727 */ + { 0x0000, 0x0000, 0x0000 }, /* R728 */ + { 0x0000, 0x0000, 0x0000 }, /* R729 */ + { 0x0000, 0x0000, 0x0000 }, /* R730 */ + { 0x0000, 0x0000, 0x0000 }, /* R731 */ + { 0x0000, 0x0000, 0x0000 }, /* R732 */ + { 0x0000, 0x0000, 0x0000 }, /* R733 */ + { 0x0000, 0x0000, 0x0000 }, /* R734 */ + { 0x0000, 0x0000, 0x0000 }, /* R735 */ + { 0x0000, 0x0000, 0x0000 }, /* R736 */ + { 0x0000, 0x0000, 0x0000 }, /* R737 */ + { 0x0000, 0x0000, 0x0000 }, /* R738 */ + { 0x0000, 0x0000, 0x0000 }, /* R739 */ + { 0x0000, 0x0000, 0x0000 }, /* R740 */ + { 0x0000, 0x0000, 0x0000 }, /* R741 */ + { 0x0000, 0x0000, 0x0000 }, /* R742 */ + { 0x0000, 0x0000, 0x0000 }, /* R743 */ + { 0x0000, 0x0000, 0x0000 }, /* R744 */ + { 0x0000, 0x0000, 0x0000 }, /* R745 */ + { 0x0000, 0x0000, 0x0000 }, /* R746 */ + { 0x0000, 0x0000, 0x0000 }, /* R747 */ + { 0x0000, 0x0000, 0x0000 }, /* R748 */ + { 0x0000, 0x0000, 0x0000 }, /* R749 */ + { 0x0000, 0x0000, 0x0000 }, /* R750 */ + { 0x0000, 0x0000, 0x0000 }, /* R751 */ + { 0x0000, 0x0000, 0x0000 }, /* R752 */ + { 0x0000, 0x0000, 0x0000 }, /* R753 */ + { 0x0000, 0x0000, 0x0000 }, /* R754 */ + { 0x0000, 0x0000, 0x0000 }, /* R755 */ + { 0x0000, 0x0000, 0x0000 }, /* R756 */ + { 0x0000, 0x0000, 0x0000 }, /* R757 */ + { 0x0000, 0x0000, 0x0000 }, /* R758 */ + { 0x0000, 0x0000, 0x0000 }, /* R759 */ + { 0x0000, 0x0000, 0x0000 }, /* R760 */ + { 0x0000, 0x0000, 0x0000 }, /* R761 */ + { 0x0000, 0x0000, 0x0000 }, /* R762 */ + { 0x0000, 0x0000, 0x0000 }, /* R763 */ + { 0x0000, 0x0000, 0x0000 }, /* R764 */ + { 0x0000, 0x0000, 0x0000 }, /* R765 */ + { 0x0000, 0x0000, 0x0000 }, /* R766 */ + { 0x0000, 0x0000, 0x0000 }, /* R767 */ + { 0xE1F8, 0xE1F8, 0x0000 }, /* R768 - AIF1 Control (1) */ + { 0xCD1F, 0xCD1F, 0x0000 }, /* R769 - AIF1 Control (2) */ + { 0xF000, 0xF000, 0x0000 }, /* R770 - AIF1 Master/Slave */ + { 0x01F0, 0x01F0, 0x0000 }, /* R771 - AIF1 BCLK */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R772 - AIF1ADC LRCLK */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R773 - AIF1DAC LRCLK */ + { 0x0003, 0x0003, 0x0000 }, /* R774 - AIF1DAC Data */ + { 0x0003, 0x0003, 0x0000 }, /* R775 - AIF1ADC Data */ + { 0x0000, 0x0000, 0x0000 }, /* R776 */ + { 0x0000, 0x0000, 0x0000 }, /* R777 */ + { 0x0000, 0x0000, 0x0000 }, /* R778 */ + { 0x0000, 0x0000, 0x0000 }, /* R779 */ + { 0x0000, 0x0000, 0x0000 }, /* R780 */ + { 0x0000, 0x0000, 0x0000 }, /* R781 */ + { 0x0000, 0x0000, 0x0000 }, /* R782 */ + { 0x0000, 0x0000, 0x0000 }, /* R783 */ + { 0xF1F8, 0xF1F8, 0x0000 }, /* R784 - AIF2 Control (1) */ + { 0xFD1F, 0xFD1F, 0x0000 }, /* R785 - AIF2 Control (2) */ + { 0xF000, 0xF000, 0x0000 }, /* R786 - AIF2 Master/Slave */ + { 0x01F0, 0x01F0, 0x0000 }, /* R787 - AIF2 BCLK */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R788 - AIF2ADC LRCLK */ + { 0x0FFF, 0x0FFF, 0x0000 }, /* R789 - AIF2DAC LRCLK */ + { 0x0003, 0x0003, 0x0000 }, /* R790 - AIF2DAC Data */ + { 0x0003, 0x0003, 0x0000 }, /* R791 - AIF2ADC Data */ + { 0x0000, 0x0000, 0x0000 }, /* R792 */ + { 0x0000, 0x0000, 0x0000 }, /* R793 */ + { 0x0000, 0x0000, 0x0000 }, /* R794 */ + { 0x0000, 0x0000, 0x0000 }, /* R795 */ + { 0x0000, 0x0000, 0x0000 }, /* R796 */ + { 0x0000, 0x0000, 0x0000 }, /* R797 */ + { 0x0000, 0x0000, 0x0000 }, /* R798 */ + { 0x0000, 0x0000, 0x0000 }, /* R799 */ + { 0x0000, 0x0000, 0x0000 }, /* R800 */ + { 0x0000, 0x0000, 0x0000 }, /* R801 */ + { 0x0000, 0x0000, 0x0000 }, /* R802 */ + { 0x0000, 0x0000, 0x0000 }, /* R803 */ + { 0x0000, 0x0000, 0x0000 }, /* R804 */ + { 0x0000, 0x0000, 0x0000 }, /* R805 */ + { 0x0000, 0x0000, 0x0000 }, /* R806 */ + { 0x0000, 0x0000, 0x0000 }, /* R807 */ + { 0x0000, 0x0000, 0x0000 }, /* R808 */ + { 0x0000, 0x0000, 0x0000 }, /* R809 */ + { 0x0000, 0x0000, 0x0000 }, /* R810 */ + { 0x0000, 0x0000, 0x0000 }, /* R811 */ + { 0x0000, 0x0000, 0x0000 }, /* R812 */ + { 0x0000, 0x0000, 0x0000 }, /* R813 */ + { 0x0000, 0x0000, 0x0000 }, /* R814 */ + { 0x0000, 0x0000, 0x0000 }, /* R815 */ + { 0x0000, 0x0000, 0x0000 }, /* R816 */ + { 0x0000, 0x0000, 0x0000 }, /* R817 */ + { 0x0000, 0x0000, 0x0000 }, /* R818 */ + { 0x0000, 0x0000, 0x0000 }, /* R819 */ + { 0x0000, 0x0000, 0x0000 }, /* R820 */ + { 0x0000, 0x0000, 0x0000 }, /* R821 */ + { 0x0000, 0x0000, 0x0000 }, /* R822 */ + { 0x0000, 0x0000, 0x0000 }, /* R823 */ + { 0x0000, 0x0000, 0x0000 }, /* R824 */ + { 0x0000, 0x0000, 0x0000 }, /* R825 */ + { 0x0000, 0x0000, 0x0000 }, /* R826 */ + { 0x0000, 0x0000, 0x0000 }, /* R827 */ + { 0x0000, 0x0000, 0x0000 }, /* R828 */ + { 0x0000, 0x0000, 0x0000 }, /* R829 */ + { 0x0000, 0x0000, 0x0000 }, /* R830 */ + { 0x0000, 0x0000, 0x0000 }, /* R831 */ + { 0x0000, 0x0000, 0x0000 }, /* R832 */ + { 0x0000, 0x0000, 0x0000 }, /* R833 */ + { 0x0000, 0x0000, 0x0000 }, /* R834 */ + { 0x0000, 0x0000, 0x0000 }, /* R835 */ + { 0x0000, 0x0000, 0x0000 }, /* R836 */ + { 0x0000, 0x0000, 0x0000 }, /* R837 */ + { 0x0000, 0x0000, 0x0000 }, /* R838 */ + { 0x0000, 0x0000, 0x0000 }, /* R839 */ + { 0x0000, 0x0000, 0x0000 }, /* R840 */ + { 0x0000, 0x0000, 0x0000 }, /* R841 */ + { 0x0000, 0x0000, 0x0000 }, /* R842 */ + { 0x0000, 0x0000, 0x0000 }, /* R843 */ + { 0x0000, 0x0000, 0x0000 }, /* R844 */ + { 0x0000, 0x0000, 0x0000 }, /* R845 */ + { 0x0000, 0x0000, 0x0000 }, /* R846 */ + { 0x0000, 0x0000, 0x0000 }, /* R847 */ + { 0x0000, 0x0000, 0x0000 }, /* R848 */ + { 0x0000, 0x0000, 0x0000 }, /* R849 */ + { 0x0000, 0x0000, 0x0000 }, /* R850 */ + { 0x0000, 0x0000, 0x0000 }, /* R851 */ + { 0x0000, 0x0000, 0x0000 }, /* R852 */ + { 0x0000, 0x0000, 0x0000 }, /* R853 */ + { 0x0000, 0x0000, 0x0000 }, /* R854 */ + { 0x0000, 0x0000, 0x0000 }, /* R855 */ + { 0x0000, 0x0000, 0x0000 }, /* R856 */ + { 0x0000, 0x0000, 0x0000 }, /* R857 */ + { 0x0000, 0x0000, 0x0000 }, /* R858 */ + { 0x0000, 0x0000, 0x0000 }, /* R859 */ + { 0x0000, 0x0000, 0x0000 }, /* R860 */ + { 0x0000, 0x0000, 0x0000 }, /* R861 */ + { 0x0000, 0x0000, 0x0000 }, /* R862 */ + { 0x0000, 0x0000, 0x0000 }, /* R863 */ + { 0x0000, 0x0000, 0x0000 }, /* R864 */ + { 0x0000, 0x0000, 0x0000 }, /* R865 */ + { 0x0000, 0x0000, 0x0000 }, /* R866 */ + { 0x0000, 0x0000, 0x0000 }, /* R867 */ + { 0x0000, 0x0000, 0x0000 }, /* R868 */ + { 0x0000, 0x0000, 0x0000 }, /* R869 */ + { 0x0000, 0x0000, 0x0000 }, /* R870 */ + { 0x0000, 0x0000, 0x0000 }, /* R871 */ + { 0x0000, 0x0000, 0x0000 }, /* R872 */ + { 0x0000, 0x0000, 0x0000 }, /* R873 */ + { 0x0000, 0x0000, 0x0000 }, /* R874 */ + { 0x0000, 0x0000, 0x0000 }, /* R875 */ + { 0x0000, 0x0000, 0x0000 }, /* R876 */ + { 0x0000, 0x0000, 0x0000 }, /* R877 */ + { 0x0000, 0x0000, 0x0000 }, /* R878 */ + { 0x0000, 0x0000, 0x0000 }, /* R879 */ + { 0x0000, 0x0000, 0x0000 }, /* R880 */ + { 0x0000, 0x0000, 0x0000 }, /* R881 */ + { 0x0000, 0x0000, 0x0000 }, /* R882 */ + { 0x0000, 0x0000, 0x0000 }, /* R883 */ + { 0x0000, 0x0000, 0x0000 }, /* R884 */ + { 0x0000, 0x0000, 0x0000 }, /* R885 */ + { 0x0000, 0x0000, 0x0000 }, /* R886 */ + { 0x0000, 0x0000, 0x0000 }, /* R887 */ + { 0x0000, 0x0000, 0x0000 }, /* R888 */ + { 0x0000, 0x0000, 0x0000 }, /* R889 */ + { 0x0000, 0x0000, 0x0000 }, /* R890 */ + { 0x0000, 0x0000, 0x0000 }, /* R891 */ + { 0x0000, 0x0000, 0x0000 }, /* R892 */ + { 0x0000, 0x0000, 0x0000 }, /* R893 */ + { 0x0000, 0x0000, 0x0000 }, /* R894 */ + { 0x0000, 0x0000, 0x0000 }, /* R895 */ + { 0x0000, 0x0000, 0x0000 }, /* R896 */ + { 0x0000, 0x0000, 0x0000 }, /* R897 */ + { 0x0000, 0x0000, 0x0000 }, /* R898 */ + { 0x0000, 0x0000, 0x0000 }, /* R899 */ + { 0x0000, 0x0000, 0x0000 }, /* R900 */ + { 0x0000, 0x0000, 0x0000 }, /* R901 */ + { 0x0000, 0x0000, 0x0000 }, /* R902 */ + { 0x0000, 0x0000, 0x0000 }, /* R903 */ + { 0x0000, 0x0000, 0x0000 }, /* R904 */ + { 0x0000, 0x0000, 0x0000 }, /* R905 */ + { 0x0000, 0x0000, 0x0000 }, /* R906 */ + { 0x0000, 0x0000, 0x0000 }, /* R907 */ + { 0x0000, 0x0000, 0x0000 }, /* R908 */ + { 0x0000, 0x0000, 0x0000 }, /* R909 */ + { 0x0000, 0x0000, 0x0000 }, /* R910 */ + { 0x0000, 0x0000, 0x0000 }, /* R911 */ + { 0x0000, 0x0000, 0x0000 }, /* R912 */ + { 0x0000, 0x0000, 0x0000 }, /* R913 */ + { 0x0000, 0x0000, 0x0000 }, /* R914 */ + { 0x0000, 0x0000, 0x0000 }, /* R915 */ + { 0x0000, 0x0000, 0x0000 }, /* R916 */ + { 0x0000, 0x0000, 0x0000 }, /* R917 */ + { 0x0000, 0x0000, 0x0000 }, /* R918 */ + { 0x0000, 0x0000, 0x0000 }, /* R919 */ + { 0x0000, 0x0000, 0x0000 }, /* R920 */ + { 0x0000, 0x0000, 0x0000 }, /* R921 */ + { 0x0000, 0x0000, 0x0000 }, /* R922 */ + { 0x0000, 0x0000, 0x0000 }, /* R923 */ + { 0x0000, 0x0000, 0x0000 }, /* R924 */ + { 0x0000, 0x0000, 0x0000 }, /* R925 */ + { 0x0000, 0x0000, 0x0000 }, /* R926 */ + { 0x0000, 0x0000, 0x0000 }, /* R927 */ + { 0x0000, 0x0000, 0x0000 }, /* R928 */ + { 0x0000, 0x0000, 0x0000 }, /* R929 */ + { 0x0000, 0x0000, 0x0000 }, /* R930 */ + { 0x0000, 0x0000, 0x0000 }, /* R931 */ + { 0x0000, 0x0000, 0x0000 }, /* R932 */ + { 0x0000, 0x0000, 0x0000 }, /* R933 */ + { 0x0000, 0x0000, 0x0000 }, /* R934 */ + { 0x0000, 0x0000, 0x0000 }, /* R935 */ + { 0x0000, 0x0000, 0x0000 }, /* R936 */ + { 0x0000, 0x0000, 0x0000 }, /* R937 */ + { 0x0000, 0x0000, 0x0000 }, /* R938 */ + { 0x0000, 0x0000, 0x0000 }, /* R939 */ + { 0x0000, 0x0000, 0x0000 }, /* R940 */ + { 0x0000, 0x0000, 0x0000 }, /* R941 */ + { 0x0000, 0x0000, 0x0000 }, /* R942 */ + { 0x0000, 0x0000, 0x0000 }, /* R943 */ + { 0x0000, 0x0000, 0x0000 }, /* R944 */ + { 0x0000, 0x0000, 0x0000 }, /* R945 */ + { 0x0000, 0x0000, 0x0000 }, /* R946 */ + { 0x0000, 0x0000, 0x0000 }, /* R947 */ + { 0x0000, 0x0000, 0x0000 }, /* R948 */ + { 0x0000, 0x0000, 0x0000 }, /* R949 */ + { 0x0000, 0x0000, 0x0000 }, /* R950 */ + { 0x0000, 0x0000, 0x0000 }, /* R951 */ + { 0x0000, 0x0000, 0x0000 }, /* R952 */ + { 0x0000, 0x0000, 0x0000 }, /* R953 */ + { 0x0000, 0x0000, 0x0000 }, /* R954 */ + { 0x0000, 0x0000, 0x0000 }, /* R955 */ + { 0x0000, 0x0000, 0x0000 }, /* R956 */ + { 0x0000, 0x0000, 0x0000 }, /* R957 */ + { 0x0000, 0x0000, 0x0000 }, /* R958 */ + { 0x0000, 0x0000, 0x0000 }, /* R959 */ + { 0x0000, 0x0000, 0x0000 }, /* R960 */ + { 0x0000, 0x0000, 0x0000 }, /* R961 */ + { 0x0000, 0x0000, 0x0000 }, /* R962 */ + { 0x0000, 0x0000, 0x0000 }, /* R963 */ + { 0x0000, 0x0000, 0x0000 }, /* R964 */ + { 0x0000, 0x0000, 0x0000 }, /* R965 */ + { 0x0000, 0x0000, 0x0000 }, /* R966 */ + { 0x0000, 0x0000, 0x0000 }, /* R967 */ + { 0x0000, 0x0000, 0x0000 }, /* R968 */ + { 0x0000, 0x0000, 0x0000 }, /* R969 */ + { 0x0000, 0x0000, 0x0000 }, /* R970 */ + { 0x0000, 0x0000, 0x0000 }, /* R971 */ + { 0x0000, 0x0000, 0x0000 }, /* R972 */ + { 0x0000, 0x0000, 0x0000 }, /* R973 */ + { 0x0000, 0x0000, 0x0000 }, /* R974 */ + { 0x0000, 0x0000, 0x0000 }, /* R975 */ + { 0x0000, 0x0000, 0x0000 }, /* R976 */ + { 0x0000, 0x0000, 0x0000 }, /* R977 */ + { 0x0000, 0x0000, 0x0000 }, /* R978 */ + { 0x0000, 0x0000, 0x0000 }, /* R979 */ + { 0x0000, 0x0000, 0x0000 }, /* R980 */ + { 0x0000, 0x0000, 0x0000 }, /* R981 */ + { 0x0000, 0x0000, 0x0000 }, /* R982 */ + { 0x0000, 0x0000, 0x0000 }, /* R983 */ + { 0x0000, 0x0000, 0x0000 }, /* R984 */ + { 0x0000, 0x0000, 0x0000 }, /* R985 */ + { 0x0000, 0x0000, 0x0000 }, /* R986 */ + { 0x0000, 0x0000, 0x0000 }, /* R987 */ + { 0x0000, 0x0000, 0x0000 }, /* R988 */ + { 0x0000, 0x0000, 0x0000 }, /* R989 */ + { 0x0000, 0x0000, 0x0000 }, /* R990 */ + { 0x0000, 0x0000, 0x0000 }, /* R991 */ + { 0x0000, 0x0000, 0x0000 }, /* R992 */ + { 0x0000, 0x0000, 0x0000 }, /* R993 */ + { 0x0000, 0x0000, 0x0000 }, /* R994 */ + { 0x0000, 0x0000, 0x0000 }, /* R995 */ + { 0x0000, 0x0000, 0x0000 }, /* R996 */ + { 0x0000, 0x0000, 0x0000 }, /* R997 */ + { 0x0000, 0x0000, 0x0000 }, /* R998 */ + { 0x0000, 0x0000, 0x0000 }, /* R999 */ + { 0x0000, 0x0000, 0x0000 }, /* R1000 */ + { 0x0000, 0x0000, 0x0000 }, /* R1001 */ + { 0x0000, 0x0000, 0x0000 }, /* R1002 */ + { 0x0000, 0x0000, 0x0000 }, /* R1003 */ + { 0x0000, 0x0000, 0x0000 }, /* R1004 */ + { 0x0000, 0x0000, 0x0000 }, /* R1005 */ + { 0x0000, 0x0000, 0x0000 }, /* R1006 */ + { 0x0000, 0x0000, 0x0000 }, /* R1007 */ + { 0x0000, 0x0000, 0x0000 }, /* R1008 */ + { 0x0000, 0x0000, 0x0000 }, /* R1009 */ + { 0x0000, 0x0000, 0x0000 }, /* R1010 */ + { 0x0000, 0x0000, 0x0000 }, /* R1011 */ + { 0x0000, 0x0000, 0x0000 }, /* R1012 */ + { 0x0000, 0x0000, 0x0000 }, /* R1013 */ + { 0x0000, 0x0000, 0x0000 }, /* R1014 */ + { 0x0000, 0x0000, 0x0000 }, /* R1015 */ + { 0x0000, 0x0000, 0x0000 }, /* R1016 */ + { 0x0000, 0x0000, 0x0000 }, /* R1017 */ + { 0x0000, 0x0000, 0x0000 }, /* R1018 */ + { 0x0000, 0x0000, 0x0000 }, /* R1019 */ + { 0x0000, 0x0000, 0x0000 }, /* R1020 */ + { 0x0000, 0x0000, 0x0000 }, /* R1021 */ + { 0x0000, 0x0000, 0x0000 }, /* R1022 */ + { 0x0000, 0x0000, 0x0000 }, /* R1023 */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1024 - AIF1 ADC1 Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1025 - AIF1 ADC1 Right Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1026 - AIF1 DAC1 Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1027 - AIF1 DAC1 Right Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1028 - AIF1 ADC2 Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1029 - AIF1 ADC2 Right Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1030 - AIF1 DAC2 Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1031 - AIF1 DAC2 Right Volume */ + { 0x0000, 0x0000, 0x0000 }, /* R1032 */ + { 0x0000, 0x0000, 0x0000 }, /* R1033 */ + { 0x0000, 0x0000, 0x0000 }, /* R1034 */ + { 0x0000, 0x0000, 0x0000 }, /* R1035 */ + { 0x0000, 0x0000, 0x0000 }, /* R1036 */ + { 0x0000, 0x0000, 0x0000 }, /* R1037 */ + { 0x0000, 0x0000, 0x0000 }, /* R1038 */ + { 0x0000, 0x0000, 0x0000 }, /* R1039 */ + { 0xF800, 0xF800, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */ + { 0x7800, 0x7800, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */ + { 0x0000, 0x0000, 0x0000 }, /* R1042 */ + { 0x0000, 0x0000, 0x0000 }, /* R1043 */ + { 0x0000, 0x0000, 0x0000 }, /* R1044 */ + { 0x0000, 0x0000, 0x0000 }, /* R1045 */ + { 0x0000, 0x0000, 0x0000 }, /* R1046 */ + { 0x0000, 0x0000, 0x0000 }, /* R1047 */ + { 0x0000, 0x0000, 0x0000 }, /* R1048 */ + { 0x0000, 0x0000, 0x0000 }, /* R1049 */ + { 0x0000, 0x0000, 0x0000 }, /* R1050 */ + { 0x0000, 0x0000, 0x0000 }, /* R1051 */ + { 0x0000, 0x0000, 0x0000 }, /* R1052 */ + { 0x0000, 0x0000, 0x0000 }, /* R1053 */ + { 0x0000, 0x0000, 0x0000 }, /* R1054 */ + { 0x0000, 0x0000, 0x0000 }, /* R1055 */ + { 0x02B6, 0x02B6, 0x0000 }, /* R1056 - AIF1 DAC1 Filters (1) */ + { 0x3F00, 0x3F00, 0x0000 }, /* R1057 - AIF1 DAC1 Filters (2) */ + { 0x02B6, 0x02B6, 0x0000 }, /* R1058 - AIF1 DAC2 Filters (1) */ + { 0x3F00, 0x3F00, 0x0000 }, /* R1059 - AIF1 DAC2 Filters (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R1060 */ + { 0x0000, 0x0000, 0x0000 }, /* R1061 */ + { 0x0000, 0x0000, 0x0000 }, /* R1062 */ + { 0x0000, 0x0000, 0x0000 }, /* R1063 */ + { 0x0000, 0x0000, 0x0000 }, /* R1064 */ + { 0x0000, 0x0000, 0x0000 }, /* R1065 */ + { 0x0000, 0x0000, 0x0000 }, /* R1066 */ + { 0x0000, 0x0000, 0x0000 }, /* R1067 */ + { 0x0000, 0x0000, 0x0000 }, /* R1068 */ + { 0x0000, 0x0000, 0x0000 }, /* R1069 */ + { 0x0000, 0x0000, 0x0000 }, /* R1070 */ + { 0x0000, 0x0000, 0x0000 }, /* R1071 */ + { 0x0000, 0x0000, 0x0000 }, /* R1072 */ + { 0x0000, 0x0000, 0x0000 }, /* R1073 */ + { 0x0000, 0x0000, 0x0000 }, /* R1074 */ + { 0x0000, 0x0000, 0x0000 }, /* R1075 */ + { 0x0000, 0x0000, 0x0000 }, /* R1076 */ + { 0x0000, 0x0000, 0x0000 }, /* R1077 */ + { 0x0000, 0x0000, 0x0000 }, /* R1078 */ + { 0x0000, 0x0000, 0x0000 }, /* R1079 */ + { 0x0000, 0x0000, 0x0000 }, /* R1080 */ + { 0x0000, 0x0000, 0x0000 }, /* R1081 */ + { 0x0000, 0x0000, 0x0000 }, /* R1082 */ + { 0x0000, 0x0000, 0x0000 }, /* R1083 */ + { 0x0000, 0x0000, 0x0000 }, /* R1084 */ + { 0x0000, 0x0000, 0x0000 }, /* R1085 */ + { 0x0000, 0x0000, 0x0000 }, /* R1086 */ + { 0x0000, 0x0000, 0x0000 }, /* R1087 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088 - AIF1 DRC1 (1) */ + { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089 - AIF1 DRC1 (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */ + { 0x07FF, 0x07FF, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */ + { 0x03FF, 0x03FF, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */ + { 0x0000, 0x0000, 0x0000 }, /* R1093 */ + { 0x0000, 0x0000, 0x0000 }, /* R1094 */ + { 0x0000, 0x0000, 0x0000 }, /* R1095 */ + { 0x0000, 0x0000, 0x0000 }, /* R1096 */ + { 0x0000, 0x0000, 0x0000 }, /* R1097 */ + { 0x0000, 0x0000, 0x0000 }, /* R1098 */ + { 0x0000, 0x0000, 0x0000 }, /* R1099 */ + { 0x0000, 0x0000, 0x0000 }, /* R1100 */ + { 0x0000, 0x0000, 0x0000 }, /* R1101 */ + { 0x0000, 0x0000, 0x0000 }, /* R1102 */ + { 0x0000, 0x0000, 0x0000 }, /* R1103 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104 - AIF1 DRC2 (1) */ + { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105 - AIF1 DRC2 (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */ + { 0x07FF, 0x07FF, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */ + { 0x03FF, 0x03FF, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */ + { 0x0000, 0x0000, 0x0000 }, /* R1109 */ + { 0x0000, 0x0000, 0x0000 }, /* R1110 */ + { 0x0000, 0x0000, 0x0000 }, /* R1111 */ + { 0x0000, 0x0000, 0x0000 }, /* R1112 */ + { 0x0000, 0x0000, 0x0000 }, /* R1113 */ + { 0x0000, 0x0000, 0x0000 }, /* R1114 */ + { 0x0000, 0x0000, 0x0000 }, /* R1115 */ + { 0x0000, 0x0000, 0x0000 }, /* R1116 */ + { 0x0000, 0x0000, 0x0000 }, /* R1117 */ + { 0x0000, 0x0000, 0x0000 }, /* R1118 */ + { 0x0000, 0x0000, 0x0000 }, /* R1119 */ + { 0x0000, 0x0000, 0x0000 }, /* R1120 */ + { 0x0000, 0x0000, 0x0000 }, /* R1121 */ + { 0x0000, 0x0000, 0x0000 }, /* R1122 */ + { 0x0000, 0x0000, 0x0000 }, /* R1123 */ + { 0x0000, 0x0000, 0x0000 }, /* R1124 */ + { 0x0000, 0x0000, 0x0000 }, /* R1125 */ + { 0x0000, 0x0000, 0x0000 }, /* R1126 */ + { 0x0000, 0x0000, 0x0000 }, /* R1127 */ + { 0x0000, 0x0000, 0x0000 }, /* R1128 */ + { 0x0000, 0x0000, 0x0000 }, /* R1129 */ + { 0x0000, 0x0000, 0x0000 }, /* R1130 */ + { 0x0000, 0x0000, 0x0000 }, /* R1131 */ + { 0x0000, 0x0000, 0x0000 }, /* R1132 */ + { 0x0000, 0x0000, 0x0000 }, /* R1133 */ + { 0x0000, 0x0000, 0x0000 }, /* R1134 */ + { 0x0000, 0x0000, 0x0000 }, /* R1135 */ + { 0x0000, 0x0000, 0x0000 }, /* R1136 */ + { 0x0000, 0x0000, 0x0000 }, /* R1137 */ + { 0x0000, 0x0000, 0x0000 }, /* R1138 */ + { 0x0000, 0x0000, 0x0000 }, /* R1139 */ + { 0x0000, 0x0000, 0x0000 }, /* R1140 */ + { 0x0000, 0x0000, 0x0000 }, /* R1141 */ + { 0x0000, 0x0000, 0x0000 }, /* R1142 */ + { 0x0000, 0x0000, 0x0000 }, /* R1143 */ + { 0x0000, 0x0000, 0x0000 }, /* R1144 */ + { 0x0000, 0x0000, 0x0000 }, /* R1145 */ + { 0x0000, 0x0000, 0x0000 }, /* R1146 */ + { 0x0000, 0x0000, 0x0000 }, /* R1147 */ + { 0x0000, 0x0000, 0x0000 }, /* R1148 */ + { 0x0000, 0x0000, 0x0000 }, /* R1149 */ + { 0x0000, 0x0000, 0x0000 }, /* R1150 */ + { 0x0000, 0x0000, 0x0000 }, /* R1151 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */ + { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154 - AIF1 DAC1 EQ Band 1 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165 - AIF1 DAC1 EQ Band 4 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167 - AIF1 DAC1 EQ Band 4 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */ + { 0x0000, 0x0000, 0x0000 }, /* R1172 */ + { 0x0000, 0x0000, 0x0000 }, /* R1173 */ + { 0x0000, 0x0000, 0x0000 }, /* R1174 */ + { 0x0000, 0x0000, 0x0000 }, /* R1175 */ + { 0x0000, 0x0000, 0x0000 }, /* R1176 */ + { 0x0000, 0x0000, 0x0000 }, /* R1177 */ + { 0x0000, 0x0000, 0x0000 }, /* R1178 */ + { 0x0000, 0x0000, 0x0000 }, /* R1179 */ + { 0x0000, 0x0000, 0x0000 }, /* R1180 */ + { 0x0000, 0x0000, 0x0000 }, /* R1181 */ + { 0x0000, 0x0000, 0x0000 }, /* R1182 */ + { 0x0000, 0x0000, 0x0000 }, /* R1183 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */ + { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186 - AIF1 DAC2 EQ Band 1 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197 - AIF1 DAC2 EQ Band 4 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199 - AIF1 DAC2 EQ Band 4 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */ + { 0x0000, 0x0000, 0x0000 }, /* R1204 */ + { 0x0000, 0x0000, 0x0000 }, /* R1205 */ + { 0x0000, 0x0000, 0x0000 }, /* R1206 */ + { 0x0000, 0x0000, 0x0000 }, /* R1207 */ + { 0x0000, 0x0000, 0x0000 }, /* R1208 */ + { 0x0000, 0x0000, 0x0000 }, /* R1209 */ + { 0x0000, 0x0000, 0x0000 }, /* R1210 */ + { 0x0000, 0x0000, 0x0000 }, /* R1211 */ + { 0x0000, 0x0000, 0x0000 }, /* R1212 */ + { 0x0000, 0x0000, 0x0000 }, /* R1213 */ + { 0x0000, 0x0000, 0x0000 }, /* R1214 */ + { 0x0000, 0x0000, 0x0000 }, /* R1215 */ + { 0x0000, 0x0000, 0x0000 }, /* R1216 */ + { 0x0000, 0x0000, 0x0000 }, /* R1217 */ + { 0x0000, 0x0000, 0x0000 }, /* R1218 */ + { 0x0000, 0x0000, 0x0000 }, /* R1219 */ + { 0x0000, 0x0000, 0x0000 }, /* R1220 */ + { 0x0000, 0x0000, 0x0000 }, /* R1221 */ + { 0x0000, 0x0000, 0x0000 }, /* R1222 */ + { 0x0000, 0x0000, 0x0000 }, /* R1223 */ + { 0x0000, 0x0000, 0x0000 }, /* R1224 */ + { 0x0000, 0x0000, 0x0000 }, /* R1225 */ + { 0x0000, 0x0000, 0x0000 }, /* R1226 */ + { 0x0000, 0x0000, 0x0000 }, /* R1227 */ + { 0x0000, 0x0000, 0x0000 }, /* R1228 */ + { 0x0000, 0x0000, 0x0000 }, /* R1229 */ + { 0x0000, 0x0000, 0x0000 }, /* R1230 */ + { 0x0000, 0x0000, 0x0000 }, /* R1231 */ + { 0x0000, 0x0000, 0x0000 }, /* R1232 */ + { 0x0000, 0x0000, 0x0000 }, /* R1233 */ + { 0x0000, 0x0000, 0x0000 }, /* R1234 */ + { 0x0000, 0x0000, 0x0000 }, /* R1235 */ + { 0x0000, 0x0000, 0x0000 }, /* R1236 */ + { 0x0000, 0x0000, 0x0000 }, /* R1237 */ + { 0x0000, 0x0000, 0x0000 }, /* R1238 */ + { 0x0000, 0x0000, 0x0000 }, /* R1239 */ + { 0x0000, 0x0000, 0x0000 }, /* R1240 */ + { 0x0000, 0x0000, 0x0000 }, /* R1241 */ + { 0x0000, 0x0000, 0x0000 }, /* R1242 */ + { 0x0000, 0x0000, 0x0000 }, /* R1243 */ + { 0x0000, 0x0000, 0x0000 }, /* R1244 */ + { 0x0000, 0x0000, 0x0000 }, /* R1245 */ + { 0x0000, 0x0000, 0x0000 }, /* R1246 */ + { 0x0000, 0x0000, 0x0000 }, /* R1247 */ + { 0x0000, 0x0000, 0x0000 }, /* R1248 */ + { 0x0000, 0x0000, 0x0000 }, /* R1249 */ + { 0x0000, 0x0000, 0x0000 }, /* R1250 */ + { 0x0000, 0x0000, 0x0000 }, /* R1251 */ + { 0x0000, 0x0000, 0x0000 }, /* R1252 */ + { 0x0000, 0x0000, 0x0000 }, /* R1253 */ + { 0x0000, 0x0000, 0x0000 }, /* R1254 */ + { 0x0000, 0x0000, 0x0000 }, /* R1255 */ + { 0x0000, 0x0000, 0x0000 }, /* R1256 */ + { 0x0000, 0x0000, 0x0000 }, /* R1257 */ + { 0x0000, 0x0000, 0x0000 }, /* R1258 */ + { 0x0000, 0x0000, 0x0000 }, /* R1259 */ + { 0x0000, 0x0000, 0x0000 }, /* R1260 */ + { 0x0000, 0x0000, 0x0000 }, /* R1261 */ + { 0x0000, 0x0000, 0x0000 }, /* R1262 */ + { 0x0000, 0x0000, 0x0000 }, /* R1263 */ + { 0x0000, 0x0000, 0x0000 }, /* R1264 */ + { 0x0000, 0x0000, 0x0000 }, /* R1265 */ + { 0x0000, 0x0000, 0x0000 }, /* R1266 */ + { 0x0000, 0x0000, 0x0000 }, /* R1267 */ + { 0x0000, 0x0000, 0x0000 }, /* R1268 */ + { 0x0000, 0x0000, 0x0000 }, /* R1269 */ + { 0x0000, 0x0000, 0x0000 }, /* R1270 */ + { 0x0000, 0x0000, 0x0000 }, /* R1271 */ + { 0x0000, 0x0000, 0x0000 }, /* R1272 */ + { 0x0000, 0x0000, 0x0000 }, /* R1273 */ + { 0x0000, 0x0000, 0x0000 }, /* R1274 */ + { 0x0000, 0x0000, 0x0000 }, /* R1275 */ + { 0x0000, 0x0000, 0x0000 }, /* R1276 */ + { 0x0000, 0x0000, 0x0000 }, /* R1277 */ + { 0x0000, 0x0000, 0x0000 }, /* R1278 */ + { 0x0000, 0x0000, 0x0000 }, /* R1279 */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1280 - AIF2 ADC Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1281 - AIF2 ADC Right Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1282 - AIF2 DAC Left Volume */ + { 0x00FF, 0x01FF, 0x0000 }, /* R1283 - AIF2 DAC Right Volume */ + { 0x0000, 0x0000, 0x0000 }, /* R1284 */ + { 0x0000, 0x0000, 0x0000 }, /* R1285 */ + { 0x0000, 0x0000, 0x0000 }, /* R1286 */ + { 0x0000, 0x0000, 0x0000 }, /* R1287 */ + { 0x0000, 0x0000, 0x0000 }, /* R1288 */ + { 0x0000, 0x0000, 0x0000 }, /* R1289 */ + { 0x0000, 0x0000, 0x0000 }, /* R1290 */ + { 0x0000, 0x0000, 0x0000 }, /* R1291 */ + { 0x0000, 0x0000, 0x0000 }, /* R1292 */ + { 0x0000, 0x0000, 0x0000 }, /* R1293 */ + { 0x0000, 0x0000, 0x0000 }, /* R1294 */ + { 0x0000, 0x0000, 0x0000 }, /* R1295 */ + { 0xF800, 0xF800, 0x0000 }, /* R1296 - AIF2 ADC Filters */ + { 0x0000, 0x0000, 0x0000 }, /* R1297 */ + { 0x0000, 0x0000, 0x0000 }, /* R1298 */ + { 0x0000, 0x0000, 0x0000 }, /* R1299 */ + { 0x0000, 0x0000, 0x0000 }, /* R1300 */ + { 0x0000, 0x0000, 0x0000 }, /* R1301 */ + { 0x0000, 0x0000, 0x0000 }, /* R1302 */ + { 0x0000, 0x0000, 0x0000 }, /* R1303 */ + { 0x0000, 0x0000, 0x0000 }, /* R1304 */ + { 0x0000, 0x0000, 0x0000 }, /* R1305 */ + { 0x0000, 0x0000, 0x0000 }, /* R1306 */ + { 0x0000, 0x0000, 0x0000 }, /* R1307 */ + { 0x0000, 0x0000, 0x0000 }, /* R1308 */ + { 0x0000, 0x0000, 0x0000 }, /* R1309 */ + { 0x0000, 0x0000, 0x0000 }, /* R1310 */ + { 0x0000, 0x0000, 0x0000 }, /* R1311 */ + { 0x02B6, 0x02B6, 0x0000 }, /* R1312 - AIF2 DAC Filters (1) */ + { 0x3F00, 0x3F00, 0x0000 }, /* R1313 - AIF2 DAC Filters (2) */ + { 0x0000, 0x0000, 0x0000 }, /* R1314 */ + { 0x0000, 0x0000, 0x0000 }, /* R1315 */ + { 0x0000, 0x0000, 0x0000 }, /* R1316 */ + { 0x0000, 0x0000, 0x0000 }, /* R1317 */ + { 0x0000, 0x0000, 0x0000 }, /* R1318 */ + { 0x0000, 0x0000, 0x0000 }, /* R1319 */ + { 0x0000, 0x0000, 0x0000 }, /* R1320 */ + { 0x0000, 0x0000, 0x0000 }, /* R1321 */ + { 0x0000, 0x0000, 0x0000 }, /* R1322 */ + { 0x0000, 0x0000, 0x0000 }, /* R1323 */ + { 0x0000, 0x0000, 0x0000 }, /* R1324 */ + { 0x0000, 0x0000, 0x0000 }, /* R1325 */ + { 0x0000, 0x0000, 0x0000 }, /* R1326 */ + { 0x0000, 0x0000, 0x0000 }, /* R1327 */ + { 0x0000, 0x0000, 0x0000 }, /* R1328 */ + { 0x0000, 0x0000, 0x0000 }, /* R1329 */ + { 0x0000, 0x0000, 0x0000 }, /* R1330 */ + { 0x0000, 0x0000, 0x0000 }, /* R1331 */ + { 0x0000, 0x0000, 0x0000 }, /* R1332 */ + { 0x0000, 0x0000, 0x0000 }, /* R1333 */ + { 0x0000, 0x0000, 0x0000 }, /* R1334 */ + { 0x0000, 0x0000, 0x0000 }, /* R1335 */ + { 0x0000, 0x0000, 0x0000 }, /* R1336 */ + { 0x0000, 0x0000, 0x0000 }, /* R1337 */ + { 0x0000, 0x0000, 0x0000 }, /* R1338 */ + { 0x0000, 0x0000, 0x0000 }, /* R1339 */ + { 0x0000, 0x0000, 0x0000 }, /* R1340 */ + { 0x0000, 0x0000, 0x0000 }, /* R1341 */ + { 0x0000, 0x0000, 0x0000 }, /* R1342 */ + { 0x0000, 0x0000, 0x0000 }, /* R1343 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344 - AIF2 DRC (1) */ + { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345 - AIF2 DRC (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346 - AIF2 DRC (3) */ + { 0x07FF, 0x07FF, 0x0000 }, /* R1347 - AIF2 DRC (4) */ + { 0x03FF, 0x03FF, 0x0000 }, /* R1348 - AIF2 DRC (5) */ + { 0x0000, 0x0000, 0x0000 }, /* R1349 */ + { 0x0000, 0x0000, 0x0000 }, /* R1350 */ + { 0x0000, 0x0000, 0x0000 }, /* R1351 */ + { 0x0000, 0x0000, 0x0000 }, /* R1352 */ + { 0x0000, 0x0000, 0x0000 }, /* R1353 */ + { 0x0000, 0x0000, 0x0000 }, /* R1354 */ + { 0x0000, 0x0000, 0x0000 }, /* R1355 */ + { 0x0000, 0x0000, 0x0000 }, /* R1356 */ + { 0x0000, 0x0000, 0x0000 }, /* R1357 */ + { 0x0000, 0x0000, 0x0000 }, /* R1358 */ + { 0x0000, 0x0000, 0x0000 }, /* R1359 */ + { 0x0000, 0x0000, 0x0000 }, /* R1360 */ + { 0x0000, 0x0000, 0x0000 }, /* R1361 */ + { 0x0000, 0x0000, 0x0000 }, /* R1362 */ + { 0x0000, 0x0000, 0x0000 }, /* R1363 */ + { 0x0000, 0x0000, 0x0000 }, /* R1364 */ + { 0x0000, 0x0000, 0x0000 }, /* R1365 */ + { 0x0000, 0x0000, 0x0000 }, /* R1366 */ + { 0x0000, 0x0000, 0x0000 }, /* R1367 */ + { 0x0000, 0x0000, 0x0000 }, /* R1368 */ + { 0x0000, 0x0000, 0x0000 }, /* R1369 */ + { 0x0000, 0x0000, 0x0000 }, /* R1370 */ + { 0x0000, 0x0000, 0x0000 }, /* R1371 */ + { 0x0000, 0x0000, 0x0000 }, /* R1372 */ + { 0x0000, 0x0000, 0x0000 }, /* R1373 */ + { 0x0000, 0x0000, 0x0000 }, /* R1374 */ + { 0x0000, 0x0000, 0x0000 }, /* R1375 */ + { 0x0000, 0x0000, 0x0000 }, /* R1376 */ + { 0x0000, 0x0000, 0x0000 }, /* R1377 */ + { 0x0000, 0x0000, 0x0000 }, /* R1378 */ + { 0x0000, 0x0000, 0x0000 }, /* R1379 */ + { 0x0000, 0x0000, 0x0000 }, /* R1380 */ + { 0x0000, 0x0000, 0x0000 }, /* R1381 */ + { 0x0000, 0x0000, 0x0000 }, /* R1382 */ + { 0x0000, 0x0000, 0x0000 }, /* R1383 */ + { 0x0000, 0x0000, 0x0000 }, /* R1384 */ + { 0x0000, 0x0000, 0x0000 }, /* R1385 */ + { 0x0000, 0x0000, 0x0000 }, /* R1386 */ + { 0x0000, 0x0000, 0x0000 }, /* R1387 */ + { 0x0000, 0x0000, 0x0000 }, /* R1388 */ + { 0x0000, 0x0000, 0x0000 }, /* R1389 */ + { 0x0000, 0x0000, 0x0000 }, /* R1390 */ + { 0x0000, 0x0000, 0x0000 }, /* R1391 */ + { 0x0000, 0x0000, 0x0000 }, /* R1392 */ + { 0x0000, 0x0000, 0x0000 }, /* R1393 */ + { 0x0000, 0x0000, 0x0000 }, /* R1394 */ + { 0x0000, 0x0000, 0x0000 }, /* R1395 */ + { 0x0000, 0x0000, 0x0000 }, /* R1396 */ + { 0x0000, 0x0000, 0x0000 }, /* R1397 */ + { 0x0000, 0x0000, 0x0000 }, /* R1398 */ + { 0x0000, 0x0000, 0x0000 }, /* R1399 */ + { 0x0000, 0x0000, 0x0000 }, /* R1400 */ + { 0x0000, 0x0000, 0x0000 }, /* R1401 */ + { 0x0000, 0x0000, 0x0000 }, /* R1402 */ + { 0x0000, 0x0000, 0x0000 }, /* R1403 */ + { 0x0000, 0x0000, 0x0000 }, /* R1404 */ + { 0x0000, 0x0000, 0x0000 }, /* R1405 */ + { 0x0000, 0x0000, 0x0000 }, /* R1406 */ + { 0x0000, 0x0000, 0x0000 }, /* R1407 */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408 - AIF2 EQ Gains (1) */ + { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409 - AIF2 EQ Gains (2) */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410 - AIF2 EQ Band 1 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411 - AIF2 EQ Band 1 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412 - AIF2 EQ Band 1 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413 - AIF2 EQ Band 2 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414 - AIF2 EQ Band 2 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415 - AIF2 EQ Band 2 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416 - AIF2 EQ Band 2 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417 - AIF2 EQ Band 3 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418 - AIF2 EQ Band 3 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419 - AIF2 EQ Band 3 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420 - AIF2 EQ Band 3 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421 - AIF2 EQ Band 4 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422 - AIF2 EQ Band 4 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423 - AIF2 EQ Band 4 C */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424 - AIF2 EQ Band 4 PG */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425 - AIF2 EQ Band 5 A */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426 - AIF2 EQ Band 5 B */ + { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427 - AIF2 EQ Band 5 PG */ + { 0x0000, 0x0000, 0x0000 }, /* R1428 */ + { 0x0000, 0x0000, 0x0000 }, /* R1429 */ + { 0x0000, 0x0000, 0x0000 }, /* R1430 */ + { 0x0000, 0x0000, 0x0000 }, /* R1431 */ + { 0x0000, 0x0000, 0x0000 }, /* R1432 */ + { 0x0000, 0x0000, 0x0000 }, /* R1433 */ + { 0x0000, 0x0000, 0x0000 }, /* R1434 */ + { 0x0000, 0x0000, 0x0000 }, /* R1435 */ + { 0x0000, 0x0000, 0x0000 }, /* R1436 */ + { 0x0000, 0x0000, 0x0000 }, /* R1437 */ + { 0x0000, 0x0000, 0x0000 }, /* R1438 */ + { 0x0000, 0x0000, 0x0000 }, /* R1439 */ + { 0x0000, 0x0000, 0x0000 }, /* R1440 */ + { 0x0000, 0x0000, 0x0000 }, /* R1441 */ + { 0x0000, 0x0000, 0x0000 }, /* R1442 */ + { 0x0000, 0x0000, 0x0000 }, /* R1443 */ + { 0x0000, 0x0000, 0x0000 }, /* R1444 */ + { 0x0000, 0x0000, 0x0000 }, /* R1445 */ + { 0x0000, 0x0000, 0x0000 }, /* R1446 */ + { 0x0000, 0x0000, 0x0000 }, /* R1447 */ + { 0x0000, 0x0000, 0x0000 }, /* R1448 */ + { 0x0000, 0x0000, 0x0000 }, /* R1449 */ + { 0x0000, 0x0000, 0x0000 }, /* R1450 */ + { 0x0000, 0x0000, 0x0000 }, /* R1451 */ + { 0x0000, 0x0000, 0x0000 }, /* R1452 */ + { 0x0000, 0x0000, 0x0000 }, /* R1453 */ + { 0x0000, 0x0000, 0x0000 }, /* R1454 */ + { 0x0000, 0x0000, 0x0000 }, /* R1455 */ + { 0x0000, 0x0000, 0x0000 }, /* R1456 */ + { 0x0000, 0x0000, 0x0000 }, /* R1457 */ + { 0x0000, 0x0000, 0x0000 }, /* R1458 */ + { 0x0000, 0x0000, 0x0000 }, /* R1459 */ + { 0x0000, 0x0000, 0x0000 }, /* R1460 */ + { 0x0000, 0x0000, 0x0000 }, /* R1461 */ + { 0x0000, 0x0000, 0x0000 }, /* R1462 */ + { 0x0000, 0x0000, 0x0000 }, /* R1463 */ + { 0x0000, 0x0000, 0x0000 }, /* R1464 */ + { 0x0000, 0x0000, 0x0000 }, /* R1465 */ + { 0x0000, 0x0000, 0x0000 }, /* R1466 */ + { 0x0000, 0x0000, 0x0000 }, /* R1467 */ + { 0x0000, 0x0000, 0x0000 }, /* R1468 */ + { 0x0000, 0x0000, 0x0000 }, /* R1469 */ + { 0x0000, 0x0000, 0x0000 }, /* R1470 */ + { 0x0000, 0x0000, 0x0000 }, /* R1471 */ + { 0x0000, 0x0000, 0x0000 }, /* R1472 */ + { 0x0000, 0x0000, 0x0000 }, /* R1473 */ + { 0x0000, 0x0000, 0x0000 }, /* R1474 */ + { 0x0000, 0x0000, 0x0000 }, /* R1475 */ + { 0x0000, 0x0000, 0x0000 }, /* R1476 */ + { 0x0000, 0x0000, 0x0000 }, /* R1477 */ + { 0x0000, 0x0000, 0x0000 }, /* R1478 */ + { 0x0000, 0x0000, 0x0000 }, /* R1479 */ + { 0x0000, 0x0000, 0x0000 }, /* R1480 */ + { 0x0000, 0x0000, 0x0000 }, /* R1481 */ + { 0x0000, 0x0000, 0x0000 }, /* R1482 */ + { 0x0000, 0x0000, 0x0000 }, /* R1483 */ + { 0x0000, 0x0000, 0x0000 }, /* R1484 */ + { 0x0000, 0x0000, 0x0000 }, /* R1485 */ + { 0x0000, 0x0000, 0x0000 }, /* R1486 */ + { 0x0000, 0x0000, 0x0000 }, /* R1487 */ + { 0x0000, 0x0000, 0x0000 }, /* R1488 */ + { 0x0000, 0x0000, 0x0000 }, /* R1489 */ + { 0x0000, 0x0000, 0x0000 }, /* R1490 */ + { 0x0000, 0x0000, 0x0000 }, /* R1491 */ + { 0x0000, 0x0000, 0x0000 }, /* R1492 */ + { 0x0000, 0x0000, 0x0000 }, /* R1493 */ + { 0x0000, 0x0000, 0x0000 }, /* R1494 */ + { 0x0000, 0x0000, 0x0000 }, /* R1495 */ + { 0x0000, 0x0000, 0x0000 }, /* R1496 */ + { 0x0000, 0x0000, 0x0000 }, /* R1497 */ + { 0x0000, 0x0000, 0x0000 }, /* R1498 */ + { 0x0000, 0x0000, 0x0000 }, /* R1499 */ + { 0x0000, 0x0000, 0x0000 }, /* R1500 */ + { 0x0000, 0x0000, 0x0000 }, /* R1501 */ + { 0x0000, 0x0000, 0x0000 }, /* R1502 */ + { 0x0000, 0x0000, 0x0000 }, /* R1503 */ + { 0x0000, 0x0000, 0x0000 }, /* R1504 */ + { 0x0000, 0x0000, 0x0000 }, /* R1505 */ + { 0x0000, 0x0000, 0x0000 }, /* R1506 */ + { 0x0000, 0x0000, 0x0000 }, /* R1507 */ + { 0x0000, 0x0000, 0x0000 }, /* R1508 */ + { 0x0000, 0x0000, 0x0000 }, /* R1509 */ + { 0x0000, 0x0000, 0x0000 }, /* R1510 */ + { 0x0000, 0x0000, 0x0000 }, /* R1511 */ + { 0x0000, 0x0000, 0x0000 }, /* R1512 */ + { 0x0000, 0x0000, 0x0000 }, /* R1513 */ + { 0x0000, 0x0000, 0x0000 }, /* R1514 */ + { 0x0000, 0x0000, 0x0000 }, /* R1515 */ + { 0x0000, 0x0000, 0x0000 }, /* R1516 */ + { 0x0000, 0x0000, 0x0000 }, /* R1517 */ + { 0x0000, 0x0000, 0x0000 }, /* R1518 */ + { 0x0000, 0x0000, 0x0000 }, /* R1519 */ + { 0x0000, 0x0000, 0x0000 }, /* R1520 */ + { 0x0000, 0x0000, 0x0000 }, /* R1521 */ + { 0x0000, 0x0000, 0x0000 }, /* R1522 */ + { 0x0000, 0x0000, 0x0000 }, /* R1523 */ + { 0x0000, 0x0000, 0x0000 }, /* R1524 */ + { 0x0000, 0x0000, 0x0000 }, /* R1525 */ + { 0x0000, 0x0000, 0x0000 }, /* R1526 */ + { 0x0000, 0x0000, 0x0000 }, /* R1527 */ + { 0x0000, 0x0000, 0x0000 }, /* R1528 */ + { 0x0000, 0x0000, 0x0000 }, /* R1529 */ + { 0x0000, 0x0000, 0x0000 }, /* R1530 */ + { 0x0000, 0x0000, 0x0000 }, /* R1531 */ + { 0x0000, 0x0000, 0x0000 }, /* R1532 */ + { 0x0000, 0x0000, 0x0000 }, /* R1533 */ + { 0x0000, 0x0000, 0x0000 }, /* R1534 */ + { 0x0000, 0x0000, 0x0000 }, /* R1535 */ + { 0x01EF, 0x01EF, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */ + { 0x0037, 0x0037, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */ + { 0x0037, 0x0037, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */ + { 0x01EF, 0x01EF, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */ + { 0x0037, 0x0037, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */ + { 0x0037, 0x0037, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */ + { 0x0003, 0x0003, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */ + { 0x0003, 0x0003, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */ + { 0x0003, 0x0003, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */ + { 0x0003, 0x0003, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */ + { 0x0000, 0x0000, 0x0000 }, /* R1546 */ + { 0x0000, 0x0000, 0x0000 }, /* R1547 */ + { 0x0000, 0x0000, 0x0000 }, /* R1548 */ + { 0x0000, 0x0000, 0x0000 }, /* R1549 */ + { 0x0000, 0x0000, 0x0000 }, /* R1550 */ + { 0x0000, 0x0000, 0x0000 }, /* R1551 */ + { 0x02FF, 0x03FF, 0x0000 }, /* R1552 - DAC1 Left Volume */ + { 0x02FF, 0x03FF, 0x0000 }, /* R1553 - DAC1 Right Volume */ + { 0x02FF, 0x03FF, 0x0000 }, /* R1554 - DAC2 Left Volume */ + { 0x02FF, 0x03FF, 0x0000 }, /* R1555 - DAC2 Right Volume */ + { 0x0003, 0x0003, 0x0000 }, /* R1556 - DAC Softmute */ + { 0x0000, 0x0000, 0x0000 }, /* R1557 */ + { 0x0000, 0x0000, 0x0000 }, /* R1558 */ + { 0x0000, 0x0000, 0x0000 }, /* R1559 */ + { 0x0000, 0x0000, 0x0000 }, /* R1560 */ + { 0x0000, 0x0000, 0x0000 }, /* R1561 */ + { 0x0000, 0x0000, 0x0000 }, /* R1562 */ + { 0x0000, 0x0000, 0x0000 }, /* R1563 */ + { 0x0000, 0x0000, 0x0000 }, /* R1564 */ + { 0x0000, 0x0000, 0x0000 }, /* R1565 */ + { 0x0000, 0x0000, 0x0000 }, /* R1566 */ + { 0x0000, 0x0000, 0x0000 }, /* R1567 */ + { 0x0003, 0x0003, 0x0000 }, /* R1568 - Oversampling */ + { 0x03C3, 0x03C3, 0x0000 }, /* R1569 - Sidetone */ +}; + +static int wm8994_readable(unsigned int reg) +{ + if (reg >= ARRAY_SIZE(access_masks)) + return 0; + return access_masks[reg].readable != 0; +} + +static int wm8994_volatile(unsigned int reg) +{ + if (reg >= WM8994_REG_CACHE_SIZE) + return 1; + + switch (reg) { + case WM8994_SOFTWARE_RESET: + case WM8994_CHIP_REVISION: + case WM8994_DC_SERVO_1: + case WM8994_DC_SERVO_READBACK: + case WM8994_RATE_STATUS: + case WM8994_LDO_1: + case WM8994_LDO_2: + return 1; + default: + return 0; + } +} + +static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8994_priv *wm8994 = codec->private_data; + + BUG_ON(reg > WM8994_MAX_REGISTER); + + if (!wm8994_volatile(reg)) + wm8994->reg_cache[reg] = value; + + return wm8994_reg_write(codec->control_data, reg, value); +} + +static unsigned int wm8994_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *reg_cache = codec->reg_cache; + + BUG_ON(reg > WM8994_MAX_REGISTER); + + if (wm8994_volatile(reg)) + return wm8994_reg_read(codec->control_data, reg); + else + return reg_cache[reg]; +} + +static int configure_aif_clock(struct snd_soc_codec *codec, int aif) +{ + struct wm8994_priv *wm8994 = codec->private_data; + int rate; + int reg1 = 0; + int offset; + + if (aif) + offset = 4; + else + offset = 0; + + switch (wm8994->sysclk[aif]) { + case WM8994_SYSCLK_MCLK1: + rate = wm8994->mclk[0]; + break; + + case WM8994_SYSCLK_MCLK2: + reg1 |= 0x8; + rate = wm8994->mclk[1]; + break; + + case WM8994_SYSCLK_FLL1: + reg1 |= 0x10; + rate = wm8994->fll[0].out; + break; + + case WM8994_SYSCLK_FLL2: + reg1 |= 0x18; + rate = wm8994->fll[1].out; + break; + + default: + return -EINVAL; + } + + if (rate >= 13500000) { + rate /= 2; + reg1 |= WM8994_AIF1CLK_DIV; + + dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n", + aif + 1, rate); + } + wm8994->aifclk[aif] = rate; + + snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, + WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV, + reg1); + + return 0; +} + +static int configure_clock(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = codec->private_data; + int old, new; + + /* Bring up the AIF clocks first */ + configure_aif_clock(codec, 0); + configure_aif_clock(codec, 1); + + /* Then switch CLK_SYS over to the higher of them; a change + * can only happen as a result of a clocking change which can + * only be made outside of DAPM so we can safely redo the + * clocking. + */ + + /* If they're equal it doesn't matter which is used */ + if (wm8994->aifclk[0] == wm8994->aifclk[1]) + return 0; + + if (wm8994->aifclk[0] < wm8994->aifclk[1]) + new = WM8994_SYSCLK_SRC; + else + new = 0; + + old = snd_soc_read(codec, WM8994_CLOCKING_1) & WM8994_SYSCLK_SRC; + + /* If there's no change then we're done. */ + if (old == new) + return 0; + + snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new); + + snd_soc_dapm_sync(codec); + + return 0; +} + +static int check_clk_sys(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1); + const char *clk; + + /* Check what we're currently using for CLK_SYS */ + if (reg & WM8994_SYSCLK_SRC) + clk = "AIF2CLK"; + else + clk = "AIF1CLK"; + + return strcmp(source->name, clk) == 0; +} + +static const char *sidetone_hpf_text[] = { + "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" +}; + +static const struct soc_enum sidetone_hpf = + SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); + +static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); +static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); + +#define WM8994_DRC_SWITCH(xname, reg, shift) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = wm8994_put_drc_sw, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, 1, 0) } + +static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mask, ret; + + /* Can't enable both ADC and DAC paths simultaneously */ + if (mc->shift == WM8994_AIF1DAC1_DRC_ENA_SHIFT) + mask = WM8994_AIF1ADC1L_DRC_ENA_MASK | + WM8994_AIF1ADC1R_DRC_ENA_MASK; + else + mask = WM8994_AIF1DAC1_DRC_ENA_MASK; + + ret = snd_soc_read(codec, mc->reg); + if (ret < 0) + return ret; + if (ret & mask) + return -EINVAL; + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + + + +static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) +{ + struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_pdata *pdata = wm8994->pdata; + int base = wm8994_drc_base[drc]; + int cfg = wm8994->drc_cfg[drc]; + int save, i; + + /* Save any enables; the configuration should clear them. */ + save = snd_soc_read(codec, base); + save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA | + WM8994_AIF1ADC1R_DRC_ENA; + + for (i = 0; i < WM8994_DRC_REGS; i++) + snd_soc_update_bits(codec, base + i, 0xffff, + pdata->drc_cfgs[cfg].regs[i]); + + snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_DRC_ENA | + WM8994_AIF1ADC1L_DRC_ENA | + WM8994_AIF1ADC1R_DRC_ENA, save); +} + +/* Icky as hell but saves code duplication */ +static int wm8994_get_drc(const char *name) +{ + if (strcmp(name, "AIF1DRC1 Mode") == 0) + return 0; + if (strcmp(name, "AIF1DRC2 Mode") == 0) + return 1; + if (strcmp(name, "AIF2DRC Mode") == 0) + return 2; + return -EINVAL; +} + +static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_pdata *pdata = wm8994->pdata; + int drc = wm8994_get_drc(kcontrol->id.name); + int value = ucontrol->value.integer.value[0]; + + if (drc < 0) + return drc; + + if (value >= pdata->num_drc_cfgs) + return -EINVAL; + + wm8994->drc_cfg[drc] = value; + + wm8994_set_drc(codec, drc); + + return 0; +} + +static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->private_data; + int drc = wm8994_get_drc(kcontrol->id.name); + + ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc]; + + return 0; +} + +static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) +{ + struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_pdata *pdata = wm8994->pdata; + int base = wm8994_retune_mobile_base[block]; + int iface, best, best_val, save, i, cfg; + + if (!pdata || !wm8994->num_retune_mobile_texts) + return; + + switch (block) { + case 0: + case 1: + iface = 0; + break; + case 2: + iface = 1; + break; + default: + return; + } + + /* Find the version of the currently selected configuration + * with the nearest sample rate. */ + cfg = wm8994->retune_mobile_cfg[block]; + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8994->retune_mobile_texts[cfg]) == 0 && + abs(pdata->retune_mobile_cfgs[i].rate + - wm8994->dac_rates[iface]) < best_val) { + best = i; + best_val = abs(pdata->retune_mobile_cfgs[i].rate + - wm8994->dac_rates[iface]); + } + } + + dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n", + block, + pdata->retune_mobile_cfgs[best].name, + pdata->retune_mobile_cfgs[best].rate, + wm8994->dac_rates[iface]); + + /* The EQ will be disabled while reconfiguring it, remember the + * current configuration. + */ + save = snd_soc_read(codec, base); + save &= WM8994_AIF1DAC1_EQ_ENA; + + for (i = 0; i < WM8994_EQ_REGS; i++) + snd_soc_update_bits(codec, base + i, 0xffff, + pdata->retune_mobile_cfgs[best].regs[i]); + + snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_EQ_ENA, save); +} + +/* Icky as hell but saves code duplication */ +static int wm8994_get_retune_mobile_block(const char *name) +{ + if (strcmp(name, "AIF1.1 EQ Mode") == 0) + return 0; + if (strcmp(name, "AIF1.2 EQ Mode") == 0) + return 1; + if (strcmp(name, "AIF2 EQ Mode") == 0) + return 2; + return -EINVAL; +} + +static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_pdata *pdata = wm8994->pdata; + int block = wm8994_get_retune_mobile_block(kcontrol->id.name); + int value = ucontrol->value.integer.value[0]; + + if (block < 0) + return block; + + if (value >= pdata->num_retune_mobile_cfgs) + return -EINVAL; + + wm8994->retune_mobile_cfg[block] = value; + + wm8994_set_retune_mobile(codec, block); + + return 0; +} + +static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->private_data; + int block = wm8994_get_retune_mobile_block(kcontrol->id.name); + + ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; + + return 0; +} + +static const struct snd_kcontrol_new wm8994_snd_controls[] = { +SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, + WM8994_AIF1_ADC1_RIGHT_VOLUME, + 1, 119, 0, digital_tlv), +SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME, + WM8994_AIF1_ADC2_RIGHT_VOLUME, + 1, 119, 0, digital_tlv), +SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME, + WM8994_AIF2_ADC_RIGHT_VOLUME, + 1, 119, 0, digital_tlv), + +SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME, + WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv), +SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME, + WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv), +SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME, + WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv), + +SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv), +SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv), + +SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0), +SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0), +SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0), + +WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2), +WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1), +WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0), + +WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2), +WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1), +WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0), + +WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2), +WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1), +WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0), + +SOC_SINGLE_TLV("DAC1 Right Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES, + 5, 12, 0, st_tlv), +SOC_SINGLE_TLV("DAC1 Left Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES, + 0, 12, 0, st_tlv), +SOC_SINGLE_TLV("DAC2 Right Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES, + 5, 12, 0, st_tlv), +SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES, + 0, 12, 0, st_tlv), +SOC_ENUM("Sidetone HPF Mux", sidetone_hpf), +SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0), + +SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME, + WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv), +SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME, + WM8994_DAC1_RIGHT_VOLUME, 9, 1, 1), + +SOC_DOUBLE_R_TLV("DAC2 Volume", WM8994_DAC2_LEFT_VOLUME, + WM8994_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv), +SOC_DOUBLE_R("DAC2 Switch", WM8994_DAC2_LEFT_VOLUME, + WM8994_DAC2_RIGHT_VOLUME, 9, 1, 1), + +SOC_SINGLE_TLV("SPKL DAC2 Volume", WM8994_SPKMIXL_ATTENUATION, + 6, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKL DAC1 Volume", WM8994_SPKMIXL_ATTENUATION, + 2, 1, 1, wm_hubs_spkmix_tlv), + +SOC_SINGLE_TLV("SPKR DAC2 Volume", WM8994_SPKMIXR_ATTENUATION, + 6, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION, + 2, 1, 1, wm_hubs_spkmix_tlv), + +SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2, + 10, 15, 0, wm8994_3d_tlv), +SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, + 8, 1, 0), +SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2, + 10, 15, 0, wm8994_3d_tlv), +SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, + 8, 1, 0), +SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2, + 10, 15, 0, wm8994_3d_tlv), +SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2, + 8, 1, 0), +}; + +static const struct snd_kcontrol_new wm8994_eq_controls[] = { +SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC1 EQ2 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 6, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC1 EQ3 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 1, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC1 EQ4 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC1 EQ5 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 6, 31, 0, + eq_tlv), + +SOC_SINGLE_TLV("AIF1DAC2 EQ1 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC2 EQ2 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 6, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC2 EQ3 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 1, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC2 EQ4 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF1DAC2 EQ5 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 6, 31, 0, + eq_tlv), + +SOC_SINGLE_TLV("AIF2 EQ1 Volume", WM8994_AIF2_EQ_GAINS_1, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF2 EQ2 Volume", WM8994_AIF2_EQ_GAINS_1, 6, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF2 EQ3 Volume", WM8994_AIF2_EQ_GAINS_1, 1, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF2 EQ4 Volume", WM8994_AIF2_EQ_GAINS_2, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0, + eq_tlv), +}; + +static int clk_sys_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return configure_clock(codec); + + case SND_SOC_DAPM_POST_PMD: + configure_clock(codec); + break; + } + + return 0; +} + +static void wm8994_update_class_w(struct snd_soc_codec *codec) +{ + int enable = 1; + int source = 0; /* GCC flow analysis can't track enable */ + int reg, reg_r; + + /* Only support direct DAC->headphone paths */ + reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1); + if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) { + dev_dbg(codec->dev, "HPL connected to output mixer\n"); + enable = 0; + } + + reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2); + if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) { + dev_dbg(codec->dev, "HPR connected to output mixer\n"); + enable = 0; + } + + /* We also need the same setting for L/R and only one path */ + reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); + switch (reg) { + case WM8994_AIF2DACL_TO_DAC1L: + dev_dbg(codec->dev, "Class W source AIF2DAC\n"); + source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT; + break; + case WM8994_AIF1DAC2L_TO_DAC1L: + dev_dbg(codec->dev, "Class W source AIF1DAC2\n"); + source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT; + break; + case WM8994_AIF1DAC1L_TO_DAC1L: + dev_dbg(codec->dev, "Class W source AIF1DAC1\n"); + source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT; + break; + default: + dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg); + enable = 0; + break; + } + + reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); + if (reg_r != reg) { + dev_dbg(codec->dev, "Left and right DAC mixers different\n"); + enable = 0; + } + + if (enable) { + dev_dbg(codec->dev, "Class W enabled\n"); + snd_soc_update_bits(codec, WM8994_CLASS_W_1, + WM8994_CP_DYN_PWR | + WM8994_CP_DYN_SRC_SEL_MASK, + source | WM8994_CP_DYN_PWR); + + } else { + dev_dbg(codec->dev, "Class W disabled\n"); + snd_soc_update_bits(codec, WM8994_CLASS_W_1, + WM8994_CP_DYN_PWR, 0); + } +} + +static const char *hp_mux_text[] = { + "Mixer", + "DAC", +}; + +#define WM8994_HP_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_dapm_get_enum_double, \ + .put = wm8994_put_hp_enum, \ + .private_value = (unsigned long)&xenum } + +static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = w->codec; + int ret; + + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + wm8994_update_class_w(codec); + + return ret; +} + +static const struct soc_enum hpl_enum = + SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text); + +static const struct snd_kcontrol_new hpl_mux = + WM8994_HP_ENUM("Left Headphone Mux", hpl_enum); + +static const struct soc_enum hpr_enum = + SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text); + +static const struct snd_kcontrol_new hpr_mux = + WM8994_HP_ENUM("Right Headphone Mux", hpr_enum); + +static const char *adc_mux_text[] = { + "ADC", + "DMIC", +}; + +static const struct soc_enum adc_enum = + SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); + +static const struct snd_kcontrol_new adcl_mux = + SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); + +static const struct snd_kcontrol_new adcr_mux = + SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); + +static const struct snd_kcontrol_new left_speaker_mixer[] = { +SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0), +SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 7, 1, 0), +SOC_DAPM_SINGLE("IN1LP Switch", WM8994_SPEAKER_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 1, 1, 0), +}; + +static const struct snd_kcontrol_new right_speaker_mixer[] = { +SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 8, 1, 0), +SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 6, 1, 0), +SOC_DAPM_SINGLE("IN1RP Switch", WM8994_SPEAKER_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0), +}; + +/* Debugging; dump chip status after DAPM transitions */ +static int post_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + dev_dbg(codec->dev, "SRC status: %x\n", + snd_soc_read(codec, + WM8994_RATE_STATUS)); + return 0; +} + +static const struct snd_kcontrol_new aif1adc1l_mix[] = { +SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new aif1adc1r_mix[] = { +SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new aif2dac2l_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, + 2, 1, 0), +SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new aif2dac2r_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, + 2, 1, 0), +SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, + 0, 1, 0), +}; + +#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } + +static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = w->codec; + int ret; + + ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); + + wm8994_update_class_w(codec); + + return ret; +} + +static const struct snd_kcontrol_new dac1l_mix[] = { +WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, + 5, 1, 0), +WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, + 4, 1, 0), +WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, + 2, 1, 0), +WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, + 1, 1, 0), +WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new dac1r_mix[] = { +WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, + 5, 1, 0), +WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, + 4, 1, 0), +WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, + 2, 1, 0), +WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, + 1, 1, 0), +WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const char *sidetone_text[] = { + "ADC/DMIC1", "DMIC2", +}; + +static const struct soc_enum sidetone1_enum = + SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); + +static const struct snd_kcontrol_new sidetone1_mux = + SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); + +static const struct soc_enum sidetone2_enum = + SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); + +static const struct snd_kcontrol_new sidetone2_mux = + SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); + +static const char *aif1dac_text[] = { + "AIF1DACDAT", "AIF3DACDAT", +}; + +static const struct soc_enum aif1dac_enum = + SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); + +static const struct snd_kcontrol_new aif1dac_mux = + SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); + +static const char *aif2dac_text[] = { + "AIF2DACDAT", "AIF3DACDAT", +}; + +static const struct soc_enum aif2dac_enum = + SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); + +static const struct snd_kcontrol_new aif2dac_mux = + SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); + +static const char *aif2adc_text[] = { + "AIF2ADCDAT", "AIF3DACDAT", +}; + +static const struct soc_enum aif2adc_enum = + SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); + +static const struct snd_kcontrol_new aif2adc_mux = + SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); + +static const char *aif3adc_text[] = { + "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", +}; + +static const struct soc_enum aif3adc_enum = + SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); + +static const struct snd_kcontrol_new aif3adc_mux = + SOC_DAPM_ENUM("AIF3ADC Mux", aif3adc_enum); + +static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("DMIC1DAT"), +SND_SOC_DAPM_INPUT("DMIC2DAT"), + +SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture", + 0, WM8994_POWER_MANAGEMENT_4, 9, 0), +SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture", + 0, WM8994_POWER_MANAGEMENT_4, 8, 0), +SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 9, 0), +SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 8, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture", + 0, WM8994_POWER_MANAGEMENT_4, 11, 0), +SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture", + 0, WM8994_POWER_MANAGEMENT_4, 10, 0), +SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 11, 0), +SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 10, 0), + +SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0, + aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)), +SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, + aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), + +SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, + aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), +SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, + aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)), + +SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux), +SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux), + +SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0, + dac1l_mix, ARRAY_SIZE(dac1l_mix)), +SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0, + dac1r_mix, ARRAY_SIZE(dac1r_mix)), + +SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0, + WM8994_POWER_MANAGEMENT_4, 13, 0), +SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0, + WM8994_POWER_MANAGEMENT_4, 12, 0), +SND_SOC_DAPM_AIF_IN("AIF2DACL", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 13, 0), +SND_SOC_DAPM_AIF_IN("AIF2DACR", NULL, 0, + WM8994_POWER_MANAGEMENT_5, 12, 0), + +SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux), +SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), +SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), +SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &aif3adc_mux), + +SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), + +SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8994_POWER_MANAGEMENT_4, 5, 0), +SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8994_POWER_MANAGEMENT_4, 4, 0), +SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8994_POWER_MANAGEMENT_4, 3, 0), +SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), + +/* Power is done with the muxes since the ADC power also controls the + * downsampling chain, the chip will automatically manage the analogue + * specific portions. + */ +SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), +SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), +SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), + +SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), +SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), +SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), +SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), + +SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), + +SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, + left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), +SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, + right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), + +SND_SOC_DAPM_POST("Debug log", post_ev), +}; + +static const struct snd_soc_dapm_route intercon[] = { + + { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys }, + { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys }, + + { "DSP1CLK", NULL, "CLK_SYS" }, + { "DSP2CLK", NULL, "CLK_SYS" }, + { "DSPINTCLK", NULL, "CLK_SYS" }, + + { "AIF1ADC1L", NULL, "AIF1CLK" }, + { "AIF1ADC1L", NULL, "DSP1CLK" }, + { "AIF1ADC1R", NULL, "AIF1CLK" }, + { "AIF1ADC1R", NULL, "DSP1CLK" }, + { "AIF1ADC1R", NULL, "DSPINTCLK" }, + + { "AIF1DAC1L", NULL, "AIF1CLK" }, + { "AIF1DAC1L", NULL, "DSP1CLK" }, + { "AIF1DAC1R", NULL, "AIF1CLK" }, + { "AIF1DAC1R", NULL, "DSP1CLK" }, + { "AIF1DAC1R", NULL, "DSPINTCLK" }, + + { "AIF1ADC2L", NULL, "AIF1CLK" }, + { "AIF1ADC2L", NULL, "DSP1CLK" }, + { "AIF1ADC2R", NULL, "AIF1CLK" }, + { "AIF1ADC2R", NULL, "DSP1CLK" }, + { "AIF1ADC2R", NULL, "DSPINTCLK" }, + + { "AIF1DAC2L", NULL, "AIF1CLK" }, + { "AIF1DAC2L", NULL, "DSP1CLK" }, + { "AIF1DAC2R", NULL, "AIF1CLK" }, + { "AIF1DAC2R", NULL, "DSP1CLK" }, + { "AIF1DAC2R", NULL, "DSPINTCLK" }, + + { "AIF2ADCL", NULL, "AIF2CLK" }, + { "AIF2ADCL", NULL, "DSP2CLK" }, + { "AIF2ADCR", NULL, "AIF2CLK" }, + { "AIF2ADCR", NULL, "DSP2CLK" }, + { "AIF2ADCR", NULL, "DSPINTCLK" }, + + { "AIF2DACL", NULL, "AIF2CLK" }, + { "AIF2DACL", NULL, "DSP2CLK" }, + { "AIF2DACR", NULL, "AIF2CLK" }, + { "AIF2DACR", NULL, "DSP2CLK" }, + { "AIF2DACR", NULL, "DSPINTCLK" }, + + { "DMIC1L", NULL, "DMIC1DAT" }, + { "DMIC1L", NULL, "CLK_SYS" }, + { "DMIC1R", NULL, "DMIC1DAT" }, + { "DMIC1R", NULL, "CLK_SYS" }, + { "DMIC2L", NULL, "DMIC2DAT" }, + { "DMIC2L", NULL, "CLK_SYS" }, + { "DMIC2R", NULL, "DMIC2DAT" }, + { "DMIC2R", NULL, "CLK_SYS" }, + + { "ADCL", NULL, "AIF1CLK" }, + { "ADCL", NULL, "DSP1CLK" }, + { "ADCL", NULL, "DSPINTCLK" }, + + { "ADCR", NULL, "AIF1CLK" }, + { "ADCR", NULL, "DSP1CLK" }, + { "ADCR", NULL, "DSPINTCLK" }, + + { "ADCL Mux", "ADC", "ADCL" }, + { "ADCL Mux", "DMIC", "DMIC1L" }, + { "ADCR Mux", "ADC", "ADCR" }, + { "ADCR Mux", "DMIC", "DMIC1R" }, + + { "DAC1L", NULL, "AIF1CLK" }, + { "DAC1L", NULL, "DSP1CLK" }, + { "DAC1L", NULL, "DSPINTCLK" }, + + { "DAC1R", NULL, "AIF1CLK" }, + { "DAC1R", NULL, "DSP1CLK" }, + { "DAC1R", NULL, "DSPINTCLK" }, + + { "DAC2L", NULL, "AIF2CLK" }, + { "DAC2L", NULL, "DSP2CLK" }, + { "DAC2L", NULL, "DSPINTCLK" }, + + { "DAC2R", NULL, "AIF2DACR" }, + { "DAC2R", NULL, "AIF2CLK" }, + { "DAC2R", NULL, "DSP2CLK" }, + { "DAC2R", NULL, "DSPINTCLK" }, + + { "TOCLK", NULL, "CLK_SYS" }, + + /* AIF1 outputs */ + { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" }, + { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" }, + { "AIF1ADC1L Mixer", "AIF2 Switch", "AIF2DACL" }, + + { "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" }, + { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, + { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, + + /* Pin level routing for AIF3 */ + { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, + { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, + { "AIF1DAC2L", NULL, "AIF1DAC Mux" }, + { "AIF1DAC2R", NULL, "AIF1DAC Mux" }, + + { "AIF2DACL", NULL, "AIF2DAC Mux" }, + { "AIF2DACR", NULL, "AIF2DAC Mux" }, + + { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" }, + { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, + { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" }, + { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, + { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, + { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, + { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" }, + + /* DAC1 inputs */ + { "DAC1L", NULL, "DAC1L Mixer" }, + { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" }, + { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, + { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, + { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" }, + { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" }, + + { "DAC1R", NULL, "DAC1R Mixer" }, + { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" }, + { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, + { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, + { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" }, + { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" }, + + /* DAC2/AIF2 outputs */ + { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" }, + { "DAC2L", NULL, "AIF2DAC2L Mixer" }, + { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" }, + { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, + { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, + { "AIF2DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" }, + { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, + + { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" }, + { "DAC2R", NULL, "AIF2DAC2R Mixer" }, + { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" }, + { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, + { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, + { "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" }, + { "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" }, + + { "AIF2ADCDAT", NULL, "AIF2ADC Mux" }, + + /* AIF3 output */ + { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1L" }, + { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1R" }, + { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2L" }, + { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2R" }, + { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCL" }, + { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCR" }, + { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, + { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, + + /* Sidetone */ + { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, + { "Left Sidetone", "DMIC2", "DMIC2L" }, + { "Right Sidetone", "ADC/DMIC1", "ADCR Mux" }, + { "Right Sidetone", "DMIC2", "DMIC2R" }, + + /* Output stages */ + { "Left Output Mixer", "DAC Switch", "DAC1L" }, + { "Right Output Mixer", "DAC Switch", "DAC1R" }, + + { "SPKL", "DAC1 Switch", "DAC1L" }, + { "SPKL", "DAC2 Switch", "DAC2L" }, + + { "SPKR", "DAC1 Switch", "DAC1R" }, + { "SPKR", "DAC2 Switch", "DAC2R" }, + + { "Left Headphone Mux", "DAC", "DAC1L" }, + { "Right Headphone Mux", "DAC", "DAC1R" }, +}; + +/* The size in bits of the FLL divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +struct fll_div { + u16 outdiv; + u16 n; + u16 k; + u16 clk_ref_div; + u16 fll_fratio; +}; + +static int wm8994_get_fll_config(struct fll_div *fll, + int freq_in, int freq_out) +{ + u64 Kpart; + unsigned int K, Ndiv, Nmod; + + pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); + + /* Scale the input frequency down to <= 13.5MHz */ + fll->clk_ref_div = 0; + while (freq_in > 13500000) { + fll->clk_ref_div++; + freq_in /= 2; + + if (fll->clk_ref_div > 3) + return -EINVAL; + } + pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in); + + /* Scale the output to give 90MHz<=Fvco<=100MHz */ + fll->outdiv = 3; + while (freq_out * (fll->outdiv + 1) < 90000000) { + fll->outdiv++; + if (fll->outdiv > 63) + return -EINVAL; + } + freq_out *= fll->outdiv + 1; + pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out); + + if (freq_in > 1000000) { + fll->fll_fratio = 0; + } else { + fll->fll_fratio = 3; + freq_in *= 8; + } + pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in); + + /* Now, calculate N.K */ + Ndiv = freq_out / freq_in; + + fll->n = Ndiv; + Nmod = freq_out % freq_in; + pr_debug("Nmod=%d\n", Nmod); + + /* Calculate fractional part - scale up so we can round. */ + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + + do_div(Kpart, freq_in); + + K = Kpart & 0xFFFFFFFF; + + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + fll->k = K / 10; + + pr_debug("N=%x K=%x\n", fll->n, fll->k); + + return 0; +} + +static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8994_priv *wm8994 = codec->private_data; + int reg_offset, ret; + struct fll_div fll; + u16 reg, aif1, aif2; + + aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) + & WM8994_AIF1CLK_ENA; + + aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1) + & WM8994_AIF2CLK_ENA; + + switch (id) { + case WM8994_FLL1: + reg_offset = 0; + id = 0; + break; + case WM8994_FLL2: + reg_offset = 0x20; + id = 1; + break; + default: + return -EINVAL; + } + + /* Are we changing anything? */ + if (wm8994->fll[id].src == src && + wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out) + return 0; + + /* If we're stopping the FLL redo the old config - no + * registers will actually be written but we avoid GCC flow + * analysis bugs spewing warnings. + */ + if (freq_out) + ret = wm8994_get_fll_config(&fll, freq_in, freq_out); + else + ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in, + wm8994->fll[id].out); + if (ret < 0) + return ret; + + /* Gate the AIF clocks while we reclock */ + snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, + WM8994_AIF1CLK_ENA, 0); + snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, + WM8994_AIF2CLK_ENA, 0); + + /* We always need to disable the FLL while reconfiguring */ + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, + WM8994_FLL1_ENA, 0); + + reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) | + (fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT); + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset, + WM8994_FLL1_OUTDIV_MASK | + WM8994_FLL1_FRATIO_MASK, reg); + + snd_soc_write(codec, WM8994_FLL1_CONTROL_3 + reg_offset, fll.k); + + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset, + WM8994_FLL1_N_MASK, + fll.n << WM8994_FLL1_N_SHIFT); + + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, + WM8994_FLL1_REFCLK_DIV_MASK, + fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT); + + /* Enable (with fractional mode if required) */ + if (freq_out) { + if (fll.k) + reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; + else + reg = WM8994_FLL1_ENA; + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, + WM8994_FLL1_ENA | WM8994_FLL1_FRAC, + reg); + } + + wm8994->fll[id].in = freq_in; + wm8994->fll[id].out = freq_out; + + /* Enable any gated AIF clocks */ + snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, + WM8994_AIF1CLK_ENA, aif1); + snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, + WM8994_AIF2CLK_ENA, aif2); + + configure_clock(codec); + + return 0; +} + +static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8994_priv *wm8994 = codec->private_data; + + switch (dai->id) { + case 1: + case 2: + break; + + default: + /* AIF3 shares clocking with AIF1/2 */ + return -EINVAL; + } + + switch (clk_id) { + case WM8994_SYSCLK_MCLK1: + wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1; + wm8994->mclk[0] = freq; + dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n", + dai->id, freq); + break; + + case WM8994_SYSCLK_MCLK2: + /* TODO: Set GPIO AF */ + wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2; + wm8994->mclk[1] = freq; + dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n", + dai->id, freq); + break; + + case WM8994_SYSCLK_FLL1: + wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL1; + dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id); + break; + + case WM8994_SYSCLK_FLL2: + wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL2; + dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); + break; + + default: + return -EINVAL; + } + + configure_clock(codec); + + return 0; +} + +static int wm8994_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VMID=2x40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0x2); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Tweak DC servo configuration for improved + * performance. */ + snd_soc_write(codec, 0x102, 0x3); + snd_soc_write(codec, 0x56, 0x3); + snd_soc_write(codec, 0x102, 0); + + /* Discharge LINEOUT1 & 2 */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_1, + WM8994_LINEOUT1_DISCH | + WM8994_LINEOUT2_DISCH, + WM8994_LINEOUT1_DISCH | + WM8994_LINEOUT2_DISCH); + + /* Startup bias, VMID ramp & buffer */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK, + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + (0x11 << WM8994_VMID_RAMP_SHIFT)); + + /* Main bias enable, VMID=2x40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_BIAS_ENA | + WM8994_VMID_SEL_MASK, + WM8994_BIAS_ENA | 0x2); + + msleep(20); + } + + /* VMID=2x500k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0x4); + + break; + + case SND_SOC_BIAS_OFF: + /* Switch over to startup biases */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK, + WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + (1 << WM8994_VMID_RAMP_SHIFT)); + + /* Disable main biases */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); + + /* Discharge line */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_1, + WM8994_LINEOUT1_DISCH | + WM8994_LINEOUT2_DISCH, + WM8994_LINEOUT1_DISCH | + WM8994_LINEOUT2_DISCH); + + msleep(5); + + /* Switch off startup biases */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK, 0); + + break; + } + codec->bias_level = level; + return 0; +} + +static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int ms_reg; + int aif1_reg; + int ms = 0; + int aif1 = 0; + + switch (dai->id) { + case 1: + ms_reg = WM8994_AIF1_MASTER_SLAVE; + aif1_reg = WM8994_AIF1_CONTROL_1; + break; + case 2: + ms_reg = WM8994_AIF2_MASTER_SLAVE; + aif1_reg = WM8994_AIF2_CONTROL_1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + ms = WM8994_AIF1_MSTR; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif1 |= WM8994_AIF1_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif1 |= 0x18; + break; + case SND_SOC_DAIFMT_I2S: + aif1 |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif1 |= 0x8; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8994_AIF1_BCLK_INV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8994_AIF1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif1 |= WM8994_AIF1_LRCLK_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, aif1_reg, + WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV | + WM8994_AIF1_FMT_MASK, + aif1); + snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR, + ms); + + return 0; +} + +static struct { + int val, rate; +} srs[] = { + { 0, 8000 }, + { 1, 11025 }, + { 2, 12000 }, + { 3, 16000 }, + { 4, 22050 }, + { 5, 24000 }, + { 6, 32000 }, + { 7, 44100 }, + { 8, 48000 }, + { 9, 88200 }, + { 10, 96000 }, +}; + +static int fs_ratios[] = { + 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 +}; + +static int bclk_divs[] = { + 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, + 640, 880, 960, 1280, 1760, 1920 +}; + +static int wm8994_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8994_priv *wm8994 = codec->private_data; + int aif1_reg; + int bclk_reg; + int lrclk_reg; + int rate_reg; + int aif1 = 0; + int bclk = 0; + int lrclk = 0; + int rate_val = 0; + int id = dai->id - 1; + + int i, cur_val, best_val, bclk_rate, best; + + switch (dai->id) { + case 1: + aif1_reg = WM8994_AIF1_CONTROL_1; + bclk_reg = WM8994_AIF1_BCLK; + rate_reg = WM8994_AIF1_RATE; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || + wm8994->lrclk_shared[0]) + lrclk_reg = WM8994_AIF1DAC_LRCLK; + else + lrclk_reg = WM8994_AIF1ADC_LRCLK; + break; + case 2: + aif1_reg = WM8994_AIF2_CONTROL_1; + bclk_reg = WM8994_AIF2_BCLK; + rate_reg = WM8994_AIF2_RATE; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || + wm8994->lrclk_shared[1]) + lrclk_reg = WM8994_AIF2DAC_LRCLK; + else + lrclk_reg = WM8994_AIF2ADC_LRCLK; + break; + default: + return -EINVAL; + } + + bclk_rate = params_rate(params) * 2; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + bclk_rate *= 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + bclk_rate *= 20; + aif1 |= 0x20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bclk_rate *= 24; + aif1 |= 0x40; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bclk_rate *= 32; + aif1 |= 0x60; + break; + default: + return -EINVAL; + } + + /* Try to find an appropriate sample rate; look for an exact match. */ + for (i = 0; i < ARRAY_SIZE(srs); i++) + if (srs[i].rate == params_rate(params)) + break; + if (i == ARRAY_SIZE(srs)) + return -EINVAL; + rate_val |= srs[i].val << WM8994_AIF1_SR_SHIFT; + + dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i].rate); + dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n", + dai->id, wm8994->aifclk[id], bclk_rate); + + if (wm8994->aifclk[id] == 0) { + dev_err(dai->dev, "AIF%dCLK not configured\n", dai->id); + return -EINVAL; + } + + /* AIFCLK/fs ratio; look for a close match in either direction */ + best = 0; + best_val = abs((fs_ratios[0] * params_rate(params)) + - wm8994->aifclk[id]); + for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { + cur_val = abs((fs_ratios[i] * params_rate(params)) + - wm8994->aifclk[id]); + if (cur_val >= best_val) + continue; + best = i; + best_val = cur_val; + } + dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n", + dai->id, fs_ratios[best]); + rate_val |= best; + + /* We may not get quite the right frequency if using + * approximate clocks so look for the closest match that is + * higher than the target (we need to ensure that there enough + * BCLKs to clock out the samples). + */ + best = 0; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + if (bclk_divs[i] < 0) + continue; + cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) + - bclk_rate * 10; + if (cur_val < 0) /* BCLK table is sorted */ + break; + best = i; + } + bclk_rate = wm8994->aifclk[id] / bclk_divs[best]; + dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", + bclk_divs[best], bclk_rate); + bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; + + lrclk = bclk_rate / params_rate(params); + dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", + lrclk, bclk_rate / lrclk); + + snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1); + snd_soc_update_bits(codec, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk); + snd_soc_update_bits(codec, lrclk_reg, WM8994_AIF1DAC_RATE_MASK, + lrclk); + snd_soc_update_bits(codec, rate_reg, WM8994_AIF1_SR_MASK | + WM8994_AIF1CLK_RATE_MASK, rate_val); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (dai->id) { + case 1: + wm8994->dac_rates[0] = params_rate(params); + wm8994_set_retune_mobile(codec, 0); + wm8994_set_retune_mobile(codec, 1); + break; + case 2: + wm8994->dac_rates[1] = params_rate(params); + wm8994_set_retune_mobile(codec, 2); + break; + } + } + + return 0; +} + +static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int mute_reg; + int reg; + + switch (codec_dai->id) { + case 1: + mute_reg = WM8994_AIF1_DAC1_FILTERS_1; + break; + case 2: + mute_reg = WM8994_AIF2_DAC_FILTERS_1; + break; + default: + return -EINVAL; + } + + if (mute) + reg = WM8994_AIF1DAC1_MUTE; + else + reg = 0; + + snd_soc_update_bits(codec, mute_reg, WM8994_AIF1DAC1_MUTE, reg); + + return 0; +} + +#define WM8994_RATES SNDRV_PCM_RATE_8000_96000 + +#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { + .set_sysclk = wm8994_set_dai_sysclk, + .set_fmt = wm8994_set_dai_fmt, + .hw_params = wm8994_hw_params, + .digital_mute = wm8994_aif_mute, + .set_pll = wm8994_set_fll, +}; + +static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { + .set_sysclk = wm8994_set_dai_sysclk, + .set_fmt = wm8994_set_dai_fmt, + .hw_params = wm8994_hw_params, + .digital_mute = wm8994_aif_mute, + .set_pll = wm8994_set_fll, +}; + +struct snd_soc_dai wm8994_dai[] = { + { + .name = "WM8994 AIF1", + .id = 1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .ops = &wm8994_aif1_dai_ops, + }, + { + .name = "WM8994 AIF2", + .id = 2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .ops = &wm8994_aif2_dai_ops, + }, + { + .name = "WM8994 AIF3", + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .playback = { + .stream_name = "AIF3 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + } +}; +EXPORT_SYMBOL_GPL(wm8994_dai); + +#ifdef CONFIG_PM +static int wm8994_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8994_priv *wm8994 = codec->private_data; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { + memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], + sizeof(struct fll_config)); + ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0); + if (ret < 0) + dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", + i + 1, ret); + } + + wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8994_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8994_priv *wm8994 = codec->private_data; + u16 *reg_cache = codec->reg_cache; + int i, ret; + + /* Restore the registers */ + for (i = 1; i < ARRAY_SIZE(wm8994->reg_cache); i++) { + switch (i) { + case WM8994_LDO_1: + case WM8994_LDO_2: + case WM8994_SOFTWARE_RESET: + /* Handled by other MFD drivers */ + continue; + default: + break; + } + + if (!access_masks[i].writable) + continue; + + wm8994_reg_write(codec->control_data, i, reg_cache[i]); + } + + wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { + ret = wm8994_set_fll(&codec->dai[0], i + 1, + wm8994->fll_suspend[i].src, + wm8994->fll_suspend[i].in, + wm8994->fll_suspend[i].out); + if (ret < 0) + dev_warn(codec->dev, "Failed to restore FLL%d: %d\n", + i + 1, ret); + } + + return 0; +} +#else +#define wm8994_suspend NULL +#define wm8994_resume NULL +#endif + +static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) +{ + struct snd_soc_codec *codec = &wm8994->codec; + struct wm8994_pdata *pdata = wm8994->pdata; + struct snd_kcontrol_new controls[] = { + SOC_ENUM_EXT("AIF1.1 EQ Mode", + wm8994->retune_mobile_enum, + wm8994_get_retune_mobile_enum, + wm8994_put_retune_mobile_enum), + SOC_ENUM_EXT("AIF1.2 EQ Mode", + wm8994->retune_mobile_enum, + wm8994_get_retune_mobile_enum, + wm8994_put_retune_mobile_enum), + SOC_ENUM_EXT("AIF2 EQ Mode", + wm8994->retune_mobile_enum, + wm8994_get_retune_mobile_enum, + wm8994_put_retune_mobile_enum), + }; + int ret, i, j; + const char **t; + + /* We need an array of texts for the enum API but the number + * of texts is likely to be less than the number of + * configurations due to the sample rate dependency of the + * configurations. */ + wm8994->num_retune_mobile_texts = 0; + wm8994->retune_mobile_texts = NULL; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + for (j = 0; j < wm8994->num_retune_mobile_texts; j++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8994->retune_mobile_texts[j]) == 0) + break; + } + + if (j != wm8994->num_retune_mobile_texts) + continue; + + /* Expand the array... */ + t = krealloc(wm8994->retune_mobile_texts, + sizeof(char *) * + (wm8994->num_retune_mobile_texts + 1), + GFP_KERNEL); + if (t == NULL) + continue; + + /* ...store the new entry... */ + t[wm8994->num_retune_mobile_texts] = + pdata->retune_mobile_cfgs[i].name; + + /* ...and remember the new version. */ + wm8994->num_retune_mobile_texts++; + wm8994->retune_mobile_texts = t; + } + + dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", + wm8994->num_retune_mobile_texts); + + wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; + wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; + + ret = snd_soc_add_controls(&wm8994->codec, controls, + ARRAY_SIZE(controls)); + if (ret != 0) + dev_err(wm8994->codec.dev, + "Failed to add ReTune Mobile controls: %d\n", ret); +} + +static void wm8994_handle_pdata(struct wm8994_priv *wm8994) +{ + struct snd_soc_codec *codec = &wm8994->codec; + struct wm8994_pdata *pdata = wm8994->pdata; + int ret, i; + + if (!pdata) + return; + + wm_hubs_handle_analogue_pdata(codec, pdata->lineout1_diff, + pdata->lineout2_diff, + pdata->lineout1fb, + pdata->lineout2fb, + pdata->jd_scthr, + pdata->jd_thr, + pdata->micbias1_lvl, + pdata->micbias2_lvl); + + dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs); + + if (pdata->num_drc_cfgs) { + struct snd_kcontrol_new controls[] = { + SOC_ENUM_EXT("AIF1DRC1 Mode", wm8994->drc_enum, + wm8994_get_drc_enum, wm8994_put_drc_enum), + SOC_ENUM_EXT("AIF1DRC2 Mode", wm8994->drc_enum, + wm8994_get_drc_enum, wm8994_put_drc_enum), + SOC_ENUM_EXT("AIF2DRC Mode", wm8994->drc_enum, + wm8994_get_drc_enum, wm8994_put_drc_enum), + }; + + /* We need an array of texts for the enum API */ + wm8994->drc_texts = kmalloc(sizeof(char *) + * pdata->num_drc_cfgs, GFP_KERNEL); + if (!wm8994->drc_texts) { + dev_err(wm8994->codec.dev, + "Failed to allocate %d DRC config texts\n", + pdata->num_drc_cfgs); + return; + } + + for (i = 0; i < pdata->num_drc_cfgs; i++) + wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; + + wm8994->drc_enum.max = pdata->num_drc_cfgs; + wm8994->drc_enum.texts = wm8994->drc_texts; + + ret = snd_soc_add_controls(&wm8994->codec, controls, + ARRAY_SIZE(controls)); + if (ret != 0) + dev_err(wm8994->codec.dev, + "Failed to add DRC mode controls: %d\n", ret); + + for (i = 0; i < WM8994_NUM_DRC; i++) + wm8994_set_drc(codec, i); + } + + dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", + pdata->num_retune_mobile_cfgs); + + if (pdata->num_retune_mobile_cfgs) + wm8994_handle_retune_mobile_pdata(wm8994); + else + snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls, + ARRAY_SIZE(wm8994_eq_controls)); +} + +static int wm8994_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8994_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8994_codec; + codec = wm8994_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + return ret; + } + + wm8994_handle_pdata(codec->private_data); + + wm_hubs_add_analogue_controls(codec); + snd_soc_add_controls(codec, wm8994_snd_controls, + ARRAY_SIZE(wm8994_snd_controls)); + snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets, + ARRAY_SIZE(wm8994_dapm_widgets)); + wm_hubs_add_analogue_routes(codec, 0, 0); + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + return 0; +} + +static int wm8994_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8994 = { + .probe = wm8994_probe, + .remove = wm8994_remove, + .suspend = wm8994_suspend, + .resume = wm8994_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); + +static int wm8994_codec_probe(struct platform_device *pdev) +{ + int ret; + struct wm8994_priv *wm8994; + struct snd_soc_codec *codec; + int i; + u16 rev; + + if (wm8994_codec) { + dev_err(&pdev->dev, "Another WM8994 is registered\n"); + return -EINVAL; + } + + wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); + if (!wm8994) { + dev_err(&pdev->dev, "Failed to allocate private data\n"); + return -ENOMEM; + } + + codec = &wm8994->codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8994; + codec->control_data = dev_get_drvdata(pdev->dev.parent); + codec->name = "WM8994"; + codec->owner = THIS_MODULE; + codec->read = wm8994_read; + codec->write = wm8994_write; + codec->readable_register = wm8994_readable; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8994_set_bias_level; + codec->dai = &wm8994_dai[0]; + codec->num_dai = 3; + codec->reg_cache_size = WM8994_MAX_REGISTER; + codec->reg_cache = &wm8994->reg_cache; + codec->dev = &pdev->dev; + + wm8994->pdata = pdev->dev.parent->platform_data; + + /* Fill the cache with physical values we inherited; don't reset */ + ret = wm8994_bulk_read(codec->control_data, 0, + ARRAY_SIZE(wm8994->reg_cache) - 1, + codec->reg_cache); + if (ret < 0) { + dev_err(codec->dev, "Failed to fill register cache: %d\n", + ret); + goto err; + } + + /* Clear the cached values for unreadable/volatile registers to + * avoid potential confusion. + */ + for (i = 0; i < ARRAY_SIZE(wm8994->reg_cache); i++) + if (wm8994_volatile(i) || !wm8994_readable(i)) + wm8994->reg_cache[i] = 0; + + /* Set revision-specific configuration */ + rev = snd_soc_read(codec, WM8994_CHIP_REVISION); + switch (rev) { + case 2: + case 3: + wm8994->hubs.dcs_codes = -5; + wm8994->hubs.hp_startup_mode = 1; + break; + default: + break; + } + + + /* Remember if AIFnLRCLK is configured as a GPIO. This should be + * configured on init - if a system wants to do this dynamically + * at runtime we can deal with that then. + */ + ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1); + if (ret < 0) { + dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret); + goto err; + } + if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { + wm8994->lrclk_shared[0] = 1; + wm8994_dai[0].symmetric_rates = 1; + } else { + wm8994->lrclk_shared[0] = 0; + } + + ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6); + if (ret < 0) { + dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret); + goto err; + } + if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { + wm8994->lrclk_shared[1] = 1; + wm8994_dai[1].symmetric_rates = 1; + } else { + wm8994->lrclk_shared[1] = 0; + } + + for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++) + wm8994_dai[i].dev = codec->dev; + + wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8994_codec = codec; + + /* Latch volume updates (right only; we always do left then right). */ + snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, + WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, + WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, + WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, + WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, + WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, + WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, + WM8994_DAC1_VU, WM8994_DAC1_VU); + snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, + WM8994_DAC2_VU, WM8994_DAC2_VU); + + /* Set the low bit of the 3D stereo depth so TLV matches */ + snd_soc_update_bits(codec, WM8994_AIF1_DAC1_FILTERS_2, + 1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT, + 1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT); + snd_soc_update_bits(codec, WM8994_AIF1_DAC2_FILTERS_2, + 1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT, + 1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT); + snd_soc_update_bits(codec, WM8994_AIF2_DAC_FILTERS_2, + 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, + 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); + + wm8994_update_class_w(codec); + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); + goto err_codec; + } + + platform_set_drvdata(pdev, wm8994); + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8994); + return ret; +} + +static int __devexit wm8994_codec_remove(struct platform_device *pdev) +{ + struct wm8994_priv *wm8994 = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = &wm8994->codec; + + wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); + snd_soc_unregister_codec(&wm8994->codec); + kfree(wm8994); + wm8994_codec = NULL; + + return 0; +} + +static struct platform_driver wm8994_codec_driver = { + .driver = { + .name = "wm8994-codec", + .owner = THIS_MODULE, + }, + .probe = wm8994_codec_probe, + .remove = __devexit_p(wm8994_codec_remove), +}; + +static __init int wm8994_init(void) +{ + return platform_driver_register(&wm8994_codec_driver); +} +module_init(wm8994_init); + +static __exit void wm8994_exit(void) +{ + platform_driver_unregister(&wm8994_codec_driver); +} +module_exit(wm8994_exit); + + +MODULE_DESCRIPTION("ASoC WM8994 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8994-codec"); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h new file mode 100644 index 000000000000..0a5e1424dea0 --- /dev/null +++ b/sound/soc/codecs/wm8994.h @@ -0,0 +1,26 @@ +/* + * wm8994.h -- WM8994 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8994_H +#define _WM8994_H + +#include + +extern struct snd_soc_codec_device soc_codec_dev_wm8994; +extern struct snd_soc_dai wm8994_dai[]; + +/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ +#define WM8994_SYSCLK_MCLK1 1 +#define WM8994_SYSCLK_MCLK2 2 +#define WM8994_SYSCLK_FLL1 3 +#define WM8994_SYSCLK_FLL2 4 + +#define WM8994_FLL1 1 +#define WM8994_FLL2 2 + +#endif -- GitLab From 3b9cfc0a99f88c0db7c72363620584a9b40b4543 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Sun, 31 Jan 2010 20:16:34 +0100 Subject: [PATCH 1426/3892] x86, mtrr: Constify struct mtrr_ops This is part of the ops structure constification effort started by Arjan van de Ven et al. Benefits of this constification: * prevents modification of data that is shared (referenced) by many other structure instances at runtime * detects/prevents accidental (but not intentional) modification attempts on archs that enforce read-only kernel data at runtime * potentially better optimized code as the compiler can assume that the const data cannot be changed * the compiler/linker move const data into .rodata and therefore exclude them from false sharing Signed-off-by: Emese Revfy LKML-Reference: <4B65D712.3080804@gmail.com> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/mtrr/amd.c | 2 +- arch/x86/kernel/cpu/mtrr/centaur.c | 2 +- arch/x86/kernel/cpu/mtrr/cyrix.c | 2 +- arch/x86/kernel/cpu/mtrr/generic.c | 2 +- arch/x86/kernel/cpu/mtrr/main.c | 6 +++--- arch/x86/kernel/cpu/mtrr/mtrr.h | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c index 33af14110dfd..92ba9cd31c9a 100644 --- a/arch/x86/kernel/cpu/mtrr/amd.c +++ b/arch/x86/kernel/cpu/mtrr/amd.c @@ -108,7 +108,7 @@ amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type) return 0; } -static struct mtrr_ops amd_mtrr_ops = { +static const struct mtrr_ops amd_mtrr_ops = { .vendor = X86_VENDOR_AMD, .set = amd_set_mtrr, .get = amd_get_mtrr, diff --git a/arch/x86/kernel/cpu/mtrr/centaur.c b/arch/x86/kernel/cpu/mtrr/centaur.c index de89f14eff3a..316fe3e60a97 100644 --- a/arch/x86/kernel/cpu/mtrr/centaur.c +++ b/arch/x86/kernel/cpu/mtrr/centaur.c @@ -110,7 +110,7 @@ centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int t return 0; } -static struct mtrr_ops centaur_mtrr_ops = { +static const struct mtrr_ops centaur_mtrr_ops = { .vendor = X86_VENDOR_CENTAUR, .set = centaur_set_mcr, .get = centaur_get_mcr, diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c index 228d982ce09c..68a3343e5798 100644 --- a/arch/x86/kernel/cpu/mtrr/cyrix.c +++ b/arch/x86/kernel/cpu/mtrr/cyrix.c @@ -265,7 +265,7 @@ static void cyrix_set_all(void) post_set(); } -static struct mtrr_ops cyrix_mtrr_ops = { +static const struct mtrr_ops cyrix_mtrr_ops = { .vendor = X86_VENDOR_CYRIX, .set_all = cyrix_set_all, .set = cyrix_set_arr, diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 55da0c5f68dd..4d755846fee6 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -752,7 +752,7 @@ int positive_have_wrcomb(void) /* * Generic structure... */ -struct mtrr_ops generic_mtrr_ops = { +const struct mtrr_ops generic_mtrr_ops = { .use_intel_if = 1, .set_all = generic_set_all, .get = generic_get_mtrr, diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 84e83de54575..fe4622e8c837 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -60,14 +60,14 @@ static DEFINE_MUTEX(mtrr_mutex); u64 size_or_mask, size_and_mask; static bool mtrr_aps_delayed_init; -static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM]; +static const struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM]; -struct mtrr_ops *mtrr_if; +const struct mtrr_ops *mtrr_if; static void set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type); -void set_mtrr_ops(struct mtrr_ops *ops) +void set_mtrr_ops(const struct mtrr_ops *ops) { if (ops->vendor && ops->vendor < X86_VENDOR_NUM) mtrr_ops[ops->vendor] = ops; diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index a501dee9a87a..df5e41f31a27 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h @@ -32,7 +32,7 @@ extern int generic_get_free_region(unsigned long base, unsigned long size, extern int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type); -extern struct mtrr_ops generic_mtrr_ops; +extern const struct mtrr_ops generic_mtrr_ops; extern int positive_have_wrcomb(void); @@ -53,10 +53,10 @@ void fill_mtrr_var_range(unsigned int index, u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi); void get_mtrr_state(void); -extern void set_mtrr_ops(struct mtrr_ops *ops); +extern void set_mtrr_ops(const struct mtrr_ops *ops); extern u64 size_or_mask, size_and_mask; -extern struct mtrr_ops *mtrr_if; +extern const struct mtrr_ops *mtrr_if; #define is_cpu(vnd) (mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd) #define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1) -- GitLab From f643e51d717b52ac28830e8bb98559b006a73bf4 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 29 Jan 2010 17:22:12 -0500 Subject: [PATCH 1427/3892] ath: make gcc check format arguments of ath_print(), fix all misuses Numeric channel is hard to get, so it won't be printed. Replace Mhz with MHz on the affected lines and add commas as needed. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 +++--- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- drivers/net/wireless/ath/debug.h | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e04835cb21b5..12069aac1d6c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -206,7 +206,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, r = ath9k_hw_reset(ah, hchan, fastcc); if (r) { ath_print(common, ATH_DBG_FATAL, - "Unable to reset channel (%u Mhz) " + "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); @@ -869,7 +869,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { ath_print(common, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) ", + "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); } @@ -924,7 +924,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) " + "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 40b5d05edcce..1ca42e5148c8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -429,7 +429,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; ath_print(common, ATH_DBG_PS, "Going back to sleep after having received " - "PS-Poll data (0x%x)\n", + "PS-Poll data (0x%lx)\n", sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a6893cf0c43b..3c790a4f38f7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1857,7 +1857,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; ath_print(common, ATH_DBG_PS, "Going back to sleep after having " - "received TX status (0x%x)\n", + "received TX status (0x%lx)\n", sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index d6b685a06c5e..8263633c003c 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -65,11 +65,11 @@ enum ATH_DEBUG { #define ATH_DBG_DEFAULT (ATH_DBG_FATAL) #ifdef CONFIG_ATH_DEBUG -void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...); +void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); #else -static inline void ath_print(struct ath_common *common, - int dbg_mask, - const char *fmt, ...) +static inline void __attribute__ ((format (printf, 3, 4))) +ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) { } #endif /* CONFIG_ATH_DEBUG */ -- GitLab From 991a0987d9e821df1790bbbc368cf36db0c678d3 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 29 Jan 2010 17:22:26 -0500 Subject: [PATCH 1428/3892] ath9k: allocate string buffer in read_file_dma() by kmalloc() Using stack for that causes warnings with CONFIG_FRAME_WARN=1024 Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 43 ++++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9489b6b25b5f..42d2a506845a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -75,17 +75,24 @@ static const struct file_operations fops_debug = { #endif +#define DMA_BUF_LEN 1024 + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; - char buf[1024]; + char *buf; + int retval; unsigned int len = 0; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; int i, qcuOffset = 0, dcuOffset = 0; u32 *qcuBase = &val[0], *dcuBase = &val[4]; + buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL); + if (!buf) + return 0; + ath9k_ps_wakeup(sc); REG_WRITE_D(ah, AR_MACMISC, @@ -93,20 +100,20 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "Raw DMA Debug values:\n"); for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { if (i % 4 == 0) - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32))); - len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", + len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ", i, val[i]); } - len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n"); + len += snprintf(buf + len, DMA_BUF_LEN - len, "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { @@ -120,7 +127,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, dcuBase++; } - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "%2d %2x %1x %2x %2x\n", i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), @@ -128,35 +135,37 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); } - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "qcu_stitch state: %2x qcu_fetch state: %2x\n", (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "qcu_complete state: %2x dcu_complete state: %2x\n", (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "dcu_arb state: %2x dcu_fp state: %2x\n", (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", + len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n", REG_READ_D(ah, AR_OBS_BUS_1)); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, DMA_BUF_LEN - len, "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR)); ath9k_ps_restore(sc); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return retval; } static const struct file_operations fops_dma = { -- GitLab From 28fd7daabfb35b7a0df2f7eaf460221e16dd2608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 00:12:19 +0100 Subject: [PATCH 1429/3892] b43: N-PHY: update general workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 215 ++++++++++++++++--------------- drivers/net/wireless/b43/phy_n.h | 4 + 2 files changed, 115 insertions(+), 104 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8c39fb126d4f..60e730a6f1dd 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -246,110 +246,6 @@ static void b43_nphy_tables_init(struct b43_wldev *dev) b43_nphy_rev3plus_tables_init(dev); } -static void b43_nphy_workarounds(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - unsigned int i; - - b43_phy_set(dev, B43_NPHY_IQFLIP, - B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); - if (1 /* FIXME band is 2.4GHz */) { - b43_phy_set(dev, B43_NPHY_CLASSCTL, - B43_NPHY_CLASSCTL_CCKEN); - } else { - b43_phy_mask(dev, B43_NPHY_CLASSCTL, - ~B43_NPHY_CLASSCTL_CCKEN); - } - b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); - b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); - - /* Fixup some tables */ - b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); - b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); - b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); - b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); - b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); - b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); - b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); - b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); - - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); - - //TODO set RF sequence - - /* Set narrowband clip threshold */ - b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); - b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); - - /* Set wideband clip 2 threshold */ - b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, - ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, - 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, - ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, - 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); - - /* Set Clip 2 detect */ - b43_phy_set(dev, B43_NPHY_C1_CGAINI, - B43_NPHY_C1_CGAINI_CL2DETECT); - b43_phy_set(dev, B43_NPHY_C2_CGAINI, - B43_NPHY_C2_CGAINI_CL2DETECT); - - if (0 /*FIXME*/) { - /* Set dwell lengths */ - b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); - b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); - b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); - b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); - - /* Set gain backoff */ - b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, - ~B43_NPHY_C1_CGAINI_GAINBKOFF, - 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, - ~B43_NPHY_C2_CGAINI_GAINBKOFF, - 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); - - /* Set HPVGA2 index */ - b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, - ~B43_NPHY_C1_INITGAIN_HPVGA2, - 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, - ~B43_NPHY_C2_INITGAIN_HPVGA2, - 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); - - //FIXME verify that the specs really mean to use autoinc here. - for (i = 0; i < 3; i++) - b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); - } - - /* Set minimum gain value */ - b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, - ~B43_NPHY_C1_MINGAIN, - 23 << B43_NPHY_C1_MINGAIN_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, - ~B43_NPHY_C2_MINGAIN, - 23 << B43_NPHY_C2_MINGAIN_SHIFT); - - if (phy->rev < 2) { - b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, - ~B43_NPHY_SCRAM_SIGCTL_SCM); - } - - /* Set phase track alpha and beta */ - b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); - b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); - b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); - b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); - b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); - b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); -} - /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) { @@ -816,6 +712,117 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ +static void b43_nphy_workarounds(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; + + u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 }; + u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 }; + + u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; + u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_nphy_classifier(dev, 1, 0); + else + b43_nphy_classifier(dev, 1, 1); + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, 1); + + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + + if (dev->phy.rev >= 3) { + /* TODO */ + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ && + nphy->band5g_pwrgain) { + b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8); + b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8); + } else { + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8); + } + + /* TODO: convert to b43_ntab_write? */ + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA); + + if (dev->phy.rev < 2) { + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800); + } + + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + + if (bus->sprom.boardflags2_lo & 0x100 && + bus->boardinfo.type == 0x8B) { + delays1[0] = 0x1; + delays1[5] = 0x14; + } + /*TODO:b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);*/ + /*TODO:b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);*/ + + /*TODO:b43_nphy_gain_crtl_workarounds(dev);*/ + + if (dev->phy.rev < 2) { + if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2) + ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/ + } else if (dev->phy.rev == 2) { + b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0); + b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0); + } + + if (dev->phy.rev < 2) + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); + + b43_phy_mask(dev, B43_NPHY_PIL_DW1, + (u16)~B43_NPHY_PIL_DW_64QAM); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00); + + if (dev->phy.rev == 2) + b43_phy_set(dev, B43_NPHY_FINERX2_CGC, + B43_NPHY_FINERX2_CGC_DECGC); + } + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, 0); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, bool test) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index f5a27661f659..ae82f0fc2096 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -976,6 +976,10 @@ struct b43_phy_n { s32 preamble_override; u32 bb_mult_save; + bool gain_boost; + bool elna_gain_config; + bool band5g_pwrgain; + u8 mphase_cal_phase_id; u16 mphase_txcal_cmdidx; u16 mphase_txcal_numcmds; -- GitLab From ef5127a4d256b9c0f47caae6cdc8ccfceedb09f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 00:12:20 +0100 Subject: [PATCH 1430/3892] b43: N-PHY: add workarounds for gain control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 130 ++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 60e730a6f1dd..d738d769b025 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -712,6 +712,134 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ +static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + u8 i, j; + u8 code; + + /* TODO: for PHY >= 3 + s8 *lna1_gain, *lna2_gain; + u8 *gain_db, *gain_bits; + u16 *rfseq_init; + u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 }; + u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 }; + */ + + u8 rfseq_events[3] = { 6, 8, 7 }; + u8 rfseq_delays[3] = { 10, 30, 1 }; + + if (dev->phy.rev >= 3) { + /* TODO */ + } else { + /* Set Clip 2 detect */ + b43_phy_set(dev, B43_NPHY_C1_CGAINI, + B43_NPHY_C1_CGAINI_CL2DETECT); + b43_phy_set(dev, B43_NPHY_C2_CGAINI, + B43_NPHY_C2_CGAINI_CL2DETECT); + + /* Set narrowband clip threshold */ + b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84); + b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); + + if (!dev->phy.is_40mhz) { + /* Set dwell lengths */ + b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); + b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B); + b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009); + b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009); + } + + /* Set wideband clip 2 threshold */ + b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, + ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, + 21); + b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, + ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, + 21); + + if (!dev->phy.is_40mhz) { + b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, + ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1); + b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, + ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1); + b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI, + ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1); + b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI, + ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1); + } + + b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C); + + if (nphy->gain_boost) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ && + dev->phy.is_40mhz) + code = 4; + else + code = 5; + } else { + code = dev->phy.is_40mhz ? 6 : 7; + } + + /* Set HPVGA2 index */ + b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, + ~B43_NPHY_C1_INITGAIN_HPVGA2, + code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, + ~B43_NPHY_C2_INITGAIN_HPVGA2, + code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x7C)); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x7C)); + + /* TODO: b43_nphy_adjust_lna_gain_table(dev); */ + + if (nphy->elna_gain_config) { + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); + + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x74)); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, + (code << 8 | 0x74)); + } + + if (dev->phy.rev == 2) { + for (i = 0; i < 4; i++) { + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, + (0x0400 * i) + 0x0020); + for (j = 0; j < 21; j++) + b43_phy_write(dev, + B43_NPHY_TABLE_DATALO, 3 * j); + } + + /* TODO: b43_nphy_set_rf_sequence(dev, 5, + rfseq_events, rfseq_delays, 3);*/ + b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1, + (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV, + 0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_PHY_N(0xC5D), + 0xFF80, 4); + } + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ static void b43_nphy_workarounds(struct b43_wldev *dev) { @@ -786,7 +914,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) /*TODO:b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);*/ /*TODO:b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);*/ - /*TODO:b43_nphy_gain_crtl_workarounds(dev);*/ + b43_nphy_gain_crtl_workarounds(dev); if (dev->phy.rev < 2) { if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2) -- GitLab From a2bff2694b02448e1d5873ac010582bc9898021c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 29 Jan 2010 19:58:56 -0500 Subject: [PATCH 1431/3892] cfg80211: avoid flushing the global workqueue for core reg hints When cfg80211 starts it will send a core regulatory hint. This is sent to the global workqueue but we force processing of it by flushing the global workqueue. The flushing was done since cfg80211 needs last_request to always be populated. Avoid flushing the global workqueue by processing the work required immediately instead of putting it into a linked list and processing it after the flush. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5f8071de7950..5dcda28b6f04 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1920,14 +1920,12 @@ static int regulatory_hint_core(const char *alpha2) request->alpha2[1] = alpha2[1]; request->initiator = NL80211_REGDOM_SET_BY_CORE; - queue_regulatory_request(request); - /* * This ensures last_request is populated once modules * come swinging in and calling regulatory hints and * wiphy_apply_custom_regulatory(). */ - flush_scheduled_work(); + reg_process_hint(request); return 0; } -- GitLab From 09d989d179d0c679043556dda77c51b41a2dae7e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 29 Jan 2010 19:58:57 -0500 Subject: [PATCH 1432/3892] cfg80211: add regulatory hint disconnect support This adds a new regulatory hint to be used when we know all devices have been disconnected and idle. This can happen when we suspend, for instance. When we disconnect we can no longer assume the same regulatory rules learned from a country IE or beacon hints are applicable so restore regulatory settings to an initial state. Since driver hints are cached on the wiphy that called the hint, those hints are not reproduced onto cfg80211 as the wiphy will respect its own wiphy->regd regardless. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- include/net/regulatory.h | 1 + net/wireless/reg.c | 157 ++++++++++++++++++++++++++++++++++++++- net/wireless/reg.h | 18 +++++ net/wireless/sme.c | 40 ++++++++++ 4 files changed, 213 insertions(+), 3 deletions(-) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 47995b81c5d7..f873ee37f7e4 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -39,6 +39,7 @@ enum environment_cap { * 00 - World regulatory domain * 99 - built by driver but a specific alpha2 cannot be determined * 98 - result of an intersection between two regulatory domains + * 97 - regulatory domain has not yet been configured * @intersect: indicates whether the wireless core should intersect * the requested regulatory domain with the presently set regulatory * domain. diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5dcda28b6f04..ed89c59bb431 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -134,6 +134,7 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom = &world_regdom; static char *ieee80211_regdom = "00"; +static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); @@ -252,6 +253,27 @@ static bool regdom_changes(const char *alpha2) return true; } +/* + * The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets + * you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER + * has ever been issued. + */ +static bool is_user_regdom_saved(void) +{ + if (user_alpha2[0] == '9' && user_alpha2[1] == '7') + return false; + + /* This would indicate a mistake on the design */ + if (WARN((!is_world_regdom(user_alpha2) && + !is_an_alpha2(user_alpha2)), + "Unexpected user alpha2: %c%c\n", + user_alpha2[0], + user_alpha2[1])) + return false; + + return true; +} + /** * country_ie_integrity_changes - tells us if the country IE has changed * @checksum: checksum of country IE of fields we are interested in @@ -1646,7 +1668,7 @@ static int ignore_request(struct wiphy *wiphy, switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: - return -EINVAL; + return 0; case NL80211_REGDOM_SET_BY_COUNTRY_IE: last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); @@ -1785,6 +1807,11 @@ new_request: pending_request = NULL; + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { + user_alpha2[0] = last_request->alpha2[0]; + user_alpha2[1] = last_request->alpha2[1]; + } + /* When r == REG_INTERSECT we do need to call CRDA */ if (r < 0) { /* @@ -1904,12 +1931,16 @@ static void queue_regulatory_request(struct regulatory_request *request) schedule_work(®_work); } -/* Core regulatory hint -- happens once during cfg80211_init() */ +/* + * Core regulatory hint -- happens during cfg80211_init() + * and when we restore regulatory settings. + */ static int regulatory_hint_core(const char *alpha2) { struct regulatory_request *request; - BUG_ON(last_request); + kfree(last_request); + last_request = NULL; request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); @@ -2107,6 +2138,123 @@ out: mutex_unlock(®_mutex); } +static void restore_alpha2(char *alpha2, bool reset_user) +{ + /* indicates there is no alpha2 to consider for restoration */ + alpha2[0] = '9'; + alpha2[1] = '7'; + + /* The user setting has precedence over the module parameter */ + if (is_user_regdom_saved()) { + /* Unless we're asked to ignore it and reset it */ + if (reset_user) { + REG_DBG_PRINT("cfg80211: Restoring regulatory settings " + "including user preference\n"); + user_alpha2[0] = '9'; + user_alpha2[1] = '7'; + + /* + * If we're ignoring user settings, we still need to + * check the module parameter to ensure we put things + * back as they were for a full restore. + */ + if (!is_world_regdom(ieee80211_regdom)) { + REG_DBG_PRINT("cfg80211: Keeping preference on " + "module parameter ieee80211_regdom: %c%c\n", + ieee80211_regdom[0], + ieee80211_regdom[1]); + alpha2[0] = ieee80211_regdom[0]; + alpha2[1] = ieee80211_regdom[1]; + } + } else { + REG_DBG_PRINT("cfg80211: Restoring regulatory settings " + "while preserving user preference for: %c%c\n", + user_alpha2[0], + user_alpha2[1]); + alpha2[0] = user_alpha2[0]; + alpha2[1] = user_alpha2[1]; + } + } else if (!is_world_regdom(ieee80211_regdom)) { + REG_DBG_PRINT("cfg80211: Keeping preference on " + "module parameter ieee80211_regdom: %c%c\n", + ieee80211_regdom[0], + ieee80211_regdom[1]); + alpha2[0] = ieee80211_regdom[0]; + alpha2[1] = ieee80211_regdom[1]; + } else + REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n"); +} + +/* + * Restoring regulatory settings involves ingoring any + * possibly stale country IE information and user regulatory + * settings if so desired, this includes any beacon hints + * learned as we could have traveled outside to another country + * after disconnection. To restore regulatory settings we do + * exactly what we did at bootup: + * + * - send a core regulatory hint + * - send a user regulatory hint if applicable + * + * Device drivers that send a regulatory hint for a specific country + * keep their own regulatory domain on wiphy->regd so that does does + * not need to be remembered. + */ +static void restore_regulatory_settings(bool reset_user) +{ + char alpha2[2]; + struct reg_beacon *reg_beacon, *btmp; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + reset_regdomains(); + restore_alpha2(alpha2, reset_user); + + /* Clear beacon hints */ + spin_lock_bh(®_pending_beacons_lock); + if (!list_empty(®_pending_beacons)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_pending_beacons, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + spin_unlock_bh(®_pending_beacons_lock); + + if (!list_empty(®_beacon_list)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_beacon_list, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + + /* First restore to the basic regulatory settings */ + cfg80211_regdomain = cfg80211_world_regdom; + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + regulatory_hint_core(cfg80211_regdomain->alpha2); + + /* + * This restores the ieee80211_regdom module parameter + * preference or the last user requested regulatory + * settings, user regulatory settings takes precedence. + */ + if (is_an_alpha2(alpha2)) + regulatory_hint_user(user_alpha2); +} + + +void regulatory_hint_disconnect(void) +{ + REG_DBG_PRINT("cfg80211: All devices are disconnected, going to " + "restore regulatory settings\n"); + restore_regulatory_settings(false); +} + static bool freq_is_chan_12_13_14(u16 freq) { if (freq == ieee80211_channel_to_frequency(12) || @@ -2496,6 +2644,9 @@ int regulatory_init(void) cfg80211_regdomain = cfg80211_world_regdom; + user_alpha2[0] = '9'; + user_alpha2[1] = '7'; + /* We always try to get an update for the static regdomain */ err = regulatory_hint_core(cfg80211_regdomain->alpha2); if (err) { diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3018508226ab..b26224a9f3bc 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -63,4 +63,22 @@ void regulatory_hint_11d(struct wiphy *wiphy, u8 *country_ie, u8 country_ie_len); +/** + * regulatory_hint_disconnect - informs all devices have been disconneted + * + * Regulotory rules can be enhanced further upon scanning and upon + * connection to an AP. These rules become stale if we disconnect + * and go to another country, whether or not we suspend and resume. + * If we suspend, go to another country and resume we'll automatically + * get disconnected shortly after resuming and things will be reset as well. + * This routine is a helper to restore regulatory settings to how they were + * prior to our first connect attempt. This includes ignoring country IE and + * beacon regulatory hints. The ieee80211_regdom module parameter will always + * be respected but if a user had set the regulatory domain that will take + * precedence. + * + * Must be called from process context. + */ +void regulatory_hint_disconnect(void); + #endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 745c37e7992e..17fde0da1b08 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -34,6 +34,44 @@ struct cfg80211_conn { bool auto_auth, prev_bssid_valid; }; +bool cfg80211_is_all_idle(void) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + bool is_all_idle = true; + + mutex_lock(&cfg80211_mutex); + + /* + * All devices must be idle as otherwise if you are actively + * scanning some new beacon hints could be learned and would + * count as new regulatory hints. + */ + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + cfg80211_lock_rdev(rdev); + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev_lock(wdev); + if (wdev->sme_state != CFG80211_SME_IDLE) + is_all_idle = false; + wdev_unlock(wdev); + } + cfg80211_unlock_rdev(rdev); + } + + mutex_unlock(&cfg80211_mutex); + + return is_all_idle; +} + +static void disconnect_work(struct work_struct *work) +{ + if (!cfg80211_is_all_idle()) + return; + + regulatory_hint_disconnect(); +} + +static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); static int cfg80211_conn_scan(struct wireless_dev *wdev) { @@ -658,6 +696,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); wdev->wext.connect.ssid_len = 0; #endif + + schedule_work(&cfg80211_disconnect_work); } void cfg80211_disconnected(struct net_device *dev, u16 reason, -- GitLab From 99b82c419bc685c5ca3d8d815564bac41e2716e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 20:18:03 +0100 Subject: [PATCH 1433/3892] b43: N-PHY: split RSSI selection into two per-PHY-revision functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 101 ++++++++++++++++--------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d738d769b025..558d3c052d95 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1316,66 +1316,69 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ -static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) +static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type) { u16 val; - if (dev->phy.rev >= 3) { - /* TODO */ - } else { - if (type < 3) - val = 0; - else if (type == 6) - val = 1; - else if (type == 3) - val = 2; - else - val = 3; + if (type < 3) + val = 0; + else if (type == 6) + val = 1; + else if (type == 3) + val = 2; + else + val = 3; - val = (val << 12) | (val << 14); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val); + val = (val << 12) | (val << 14); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val); + b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val); + if (type < 3) { + b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF, + (type + 1) << 4); + b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF, + (type + 1) << 4); + } + + /* TODO use some definitions */ + if (code == 0) { + b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0); if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF, - (type + 1) << 4); - b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF, - (type + 1) << 4); + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0); + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0); + udelay(20); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0); } - - /* TODO use some definitions */ - if (code == 0) { - b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0); - if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, - 0xFEC7, 0); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xEFDC, 0); - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, - 0xFFFE, 0); - udelay(20); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xFFFE, 0); - } - } else { - b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, - 0x3000); - if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, - 0xFEC7, 0x0180); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xEFDC, (code << 1 | 0x1021)); - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, - 0xFFFE, 0x0001); - udelay(20); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xFFFE, 0); - } + } else { + b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, + 0x3000); + if (type < 3) { + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, + 0xFEC7, 0x0180); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, + 0xEFDC, (code << 1 | 0x1021)); + b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1); + udelay(20); + b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0); } } } +static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type) +{ + /* TODO */ +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ +static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) +{ + if (dev->phy.rev >= 3) + b43_nphy_rev3_rssi_select(dev, code, type); + else + b43_nphy_rev2_rssi_select(dev, code, type); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf) { -- GitLab From 6e3b15a9e7c3e4f22e9ade658b9e185311078648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 20:18:04 +0100 Subject: [PATCH 1434/3892] b43: N-PHY: add RSSI selection for newer PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 84 +++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 558d3c052d95..0e04a2668ea3 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1367,7 +1367,89 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type) static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type) { - /* TODO */ + struct b43_phy_n *nphy = dev->phy.n; + u8 i; + u16 reg, val; + + if (code == 0) { + b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF); + b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF); + b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF); + b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF); + b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF); + b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF); + b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3); + b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3); + } else { + for (i = 0; i < 2; i++) { + if ((code == 1 && i == 1) || (code == 2 && !i)) + continue; + + reg = (i == 0) ? + B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER; + b43_phy_maskset(dev, reg, 0xFDFF, 0x0200); + + if (type < 3) { + reg = (i == 0) ? + B43_NPHY_AFECTL_C1 : + B43_NPHY_AFECTL_C2; + b43_phy_maskset(dev, reg, 0xFCFF, 0); + + reg = (i == 0) ? + B43_NPHY_RFCTL_LUT_TRSW_UP1 : + B43_NPHY_RFCTL_LUT_TRSW_UP2; + b43_phy_maskset(dev, reg, 0xFFC3, 0); + + if (type == 0) + val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8; + else if (type == 1) + val = 16; + else + val = 32; + b43_phy_set(dev, reg, val); + + reg = (i == 0) ? + B43_NPHY_TXF_40CO_B1S0 : + B43_NPHY_TXF_40CO_B32S1; + b43_phy_set(dev, reg, 0x0020); + } else { + if (type == 6) + val = 0x0100; + else if (type == 3) + val = 0x0200; + else + val = 0x0300; + + reg = (i == 0) ? + B43_NPHY_AFECTL_C1 : + B43_NPHY_AFECTL_C2; + + b43_phy_maskset(dev, reg, 0xFCFF, val); + b43_phy_maskset(dev, reg, 0xF3FF, val << 2); + + if (type != 3 && type != 6) { + enum ieee80211_band band = + b43_current_band(dev->wl); + + if ((nphy->ipa2g_on && + band == IEEE80211_BAND_2GHZ) || + (nphy->ipa5g_on && + band == IEEE80211_BAND_5GHZ)) + val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE; + else + val = 0x11; + reg = (i == 0) ? 0x2000 : 0x3000; + reg |= B2055_PADDRV; + b43_radio_write16(dev, reg, val); + + reg = (i == 0) ? + B43_NPHY_AFECTL_OVER1 : + B43_NPHY_AFECTL_OVER; + b43_phy_set(dev, reg, 0x0200); + } + } + } + } } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ -- GitLab From 38bb902921dc31c15a707b74ebc6896438bb357e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 20:18:05 +0100 Subject: [PATCH 1435/3892] b43: N-PHY: fix Cal TX IQ LO for newer PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 0e04a2668ea3..1dace55d243a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2229,7 +2229,17 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, (dev->phy.rev == 5 && nphy->ipa2g_on && b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); if (phy6or5x) { - /* TODO */ + if (dev->phy.is_40mhz) { + b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, + tbl_tx_iqlo_cal_loft_ladder_40); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, + tbl_tx_iqlo_cal_iqimb_ladder_40); + } else { + b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, + tbl_tx_iqlo_cal_loft_ladder_20); + b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, + tbl_tx_iqlo_cal_iqimb_ladder_20); + } } b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); -- GitLab From 52cb5e978f505ba6436dfe1867da0d2818fdb9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 20:18:06 +0100 Subject: [PATCH 1436/3892] b43: N-PHY: add TX radio setup for newer PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 53 +++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1dace55d243a..78e0cf6c78ca 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1803,9 +1803,60 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; u16 *save = nphy->tx_rx_cal_radio_saveregs; + u16 tmp; + u8 offset, i; if (dev->phy.rev >= 3) { - /* TODO */ + for (i = 0; i < 2; i++) { + tmp = (i == 0) ? 0x2000 : 0x3000; + offset = i * 11; + + save[offset + 0] = b43_radio_read16(dev, B2055_CAL_RVARCTL); + save[offset + 1] = b43_radio_read16(dev, B2055_CAL_LPOCTL); + save[offset + 2] = b43_radio_read16(dev, B2055_CAL_TS); + save[offset + 3] = b43_radio_read16(dev, B2055_CAL_RCCALRTS); + save[offset + 4] = b43_radio_read16(dev, B2055_CAL_RCALRTS); + save[offset + 5] = b43_radio_read16(dev, B2055_PADDRV); + save[offset + 6] = b43_radio_read16(dev, B2055_XOCTL1); + save[offset + 7] = b43_radio_read16(dev, B2055_XOCTL2); + save[offset + 8] = b43_radio_read16(dev, B2055_XOREGUL); + save[offset + 9] = b43_radio_read16(dev, B2055_XOMISC); + save[offset + 10] = b43_radio_read16(dev, B2055_PLL_LFC1); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x0A); + b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40); + b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55); + b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0); + b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0); + if (nphy->ipa5g_on) { + b43_radio_write16(dev, tmp | B2055_PADDRV, 4); + b43_radio_write16(dev, tmp | B2055_XOCTL1, 1); + } else { + b43_radio_write16(dev, tmp | B2055_PADDRV, 0); + b43_radio_write16(dev, tmp | B2055_XOCTL1, 0x2F); + } + b43_radio_write16(dev, tmp | B2055_XOCTL2, 0); + } else { + b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x06); + b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40); + b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55); + b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0); + b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0); + b43_radio_write16(dev, tmp | B2055_XOCTL1, 0); + if (nphy->ipa2g_on) { + b43_radio_write16(dev, tmp | B2055_PADDRV, 6); + b43_radio_write16(dev, tmp | B2055_XOCTL2, + (dev->phy.rev < 5) ? 0x11 : 0x01); + } else { + b43_radio_write16(dev, tmp | B2055_PADDRV, 0); + b43_radio_write16(dev, tmp | B2055_XOCTL2, 0); + } + } + b43_radio_write16(dev, tmp | B2055_XOREGUL, 0); + b43_radio_write16(dev, tmp | B2055_XOMISC, 0); + b43_radio_write16(dev, tmp | B2055_PLL_LFC1, 0); + } } else { save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1); b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29); -- GitLab From 9501fefec6aa9a3319bb61edb99851ba30653f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 30 Jan 2010 20:18:07 +0100 Subject: [PATCH 1437/3892] b43: N-PHY: implement setting RF sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 78e0cf6c78ca..6392da25efed 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -64,6 +64,8 @@ enum b43_nphy_rf_sequence { B43_RFSEQ_UPDATE_GAINU, }; +static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, + u8 *events, u8 *delays, u8 length); static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, enum b43_nphy_rf_sequence seq); @@ -827,8 +829,8 @@ static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev) B43_NPHY_TABLE_DATALO, 3 * j); } - /* TODO: b43_nphy_set_rf_sequence(dev, 5, - rfseq_events, rfseq_delays, 3);*/ + b43_nphy_set_rf_sequence(dev, 5, + rfseq_events, rfseq_delays, 3); b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1, (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV, 0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT); @@ -911,8 +913,8 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) delays1[0] = 0x1; delays1[5] = 0x14; } - /*TODO:b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);*/ - /*TODO:b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);*/ + b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7); + b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7); b43_nphy_gain_crtl_workarounds(dev); @@ -1131,6 +1133,31 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, false); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ +static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, + u8 *events, u8 *delays, u8 length) +{ + struct b43_phy_n *nphy = dev->phy.n; + u8 i; + u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F; + u16 offset1 = cmd << 4; + u16 offset2 = offset1 + 0x80; + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, true); + + b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events); + b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays); + + for (i = length; i < 16; i++) { + b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end); + b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1); + } + + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, false); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, enum b43_nphy_rf_sequence seq) -- GitLab From 4c82bf8e5689b1dddd9bcec70efc3b70edef1670 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sat, 30 Jan 2010 19:55:09 -0500 Subject: [PATCH 1438/3892] mac80211: reduce stack usage in sta_ht_capa_read() The maximal size of the "ht_capa" file is 430 bytes. In most cases, it's much shorter. Use a 512 byte long buffer. 1024 bytes is too much and causes a warning with CONFIG_FRAME_WARN=1024. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 0d4a759ba72c..84865e7ef13b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -165,7 +165,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, if (_cond) \ p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ } while (0) - char buf[1024], *p = buf; + char buf[512], *p = buf; int i; struct sta_info *sta = file->private_data; struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; -- GitLab From e0b20f1c67fc4379fce430ff720969f35e123eed Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sat, 30 Jan 2010 19:55:27 -0500 Subject: [PATCH 1439/3892] mac80211: reduce stack usage in sta_agg_status_read() Use a more compact and readable format for "agg_status" to reduce the stack frame to less than 1024 bytes. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 84865e7ef13b..d92800bb2d2f 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -120,36 +120,38 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[30 + STA_TID_NUM * 70], *p = buf; + char buf[64 + STA_TID_NUM * 40], *p = buf; int i; struct sta_info *sta = file->private_data; spin_lock_bh(&sta->lock); - p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", + p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", sta->ampdu_mlme.dialog_token_allocator + 1); + p += scnprintf(p, sizeof(buf) + buf - p, + "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); for (i = 0; i < STA_TID_NUM; i++) { - p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); - p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", + p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); + p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", sta->ampdu_mlme.tid_state_rx[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", sta->ampdu_mlme.tid_state_rx[i] ? sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", sta->ampdu_mlme.tid_state_rx[i] ? sta->ampdu_mlme.tid_rx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", + p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", sta->ampdu_mlme.tid_state_tx[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", + p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", sta->ampdu_mlme.tid_state_tx[i] ? skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + p += scnprintf(p, sizeof(buf) + buf - p, "\n"); } spin_unlock_bh(&sta->lock); -- GitLab From 4754ffd68bc14de8db01451c49bb07adebe1e422 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 31 Jan 2010 21:50:12 +0100 Subject: [PATCH 1440/3892] mac80211: fix sta lookup for received action frames on an AP VLAN When looking for a matching interface, __ieee80211_rx_handle_packet loops over all active interfaces, looking for matching stations. Because AP VLAN interfaces are not processed as part of this loop, it needs to use sta_info_get_bss instead of sta_info_get in order to find a STA that has been moved to a VLAN. This fixes issues with aggregation setup/teardown. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7e0b3e340389..5709307fcb9b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2359,7 +2359,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } - rx.sta = sta_info_get(prev, hdr->addr2); + rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(prev, &rx, hdr); @@ -2395,7 +2395,7 @@ next: } if (prev) { - rx.sta = sta_info_get(prev, hdr->addr2); + rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(prev, &rx, hdr); -- GitLab From 17ad353b8d9843731258b5d23556667b764939e9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 31 Jan 2010 21:56:25 +0100 Subject: [PATCH 1441/3892] mac80211: fix monitor mode tx radiotap header handling When an injected frame gets buffered for a powersave STA or filtered and retransmitted, mac80211 attempts to parse the radiotap header again, which doesn't work because it's gone at that point. This patch adds a new flag for checking the availability of a radiotap header, so that it only attempts to parse it once, reusing the tx info on the next call to ieee80211_tx(). This fixes severe issues with rekeying in AP mode. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +++ net/mac80211/tx.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1e9c93024cf2..74ccf30fdf8e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -275,6 +275,8 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted * after TX status because the destination was asleep, it must not * be modified again (no seqno assignment, crypto, etc.) + * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still + * has a radiotap header at skb->data. */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -296,6 +298,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), + IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), }; /** diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 14c70452c245..e7b1cdc7651b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1108,7 +1108,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ - if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { + if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; @@ -1117,6 +1117,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, * the radiotap header that was present and pre-filled * 'tx' with tx control information. */ + info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP; } /* @@ -1499,7 +1500,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, int hdrlen; u16 len_rthdr; - info->flags |= IEEE80211_TX_CTL_INJECTED; + info->flags |= IEEE80211_TX_CTL_INJECTED | + IEEE80211_TX_INTFL_HAS_RADIOTAP; len_rthdr = ieee80211_get_radiotap_len(skb->data); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); -- GitLab From b4d57adb727ec7c34020390eeb0eeb9e0a2959bc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 31 Jan 2010 23:25:24 +0100 Subject: [PATCH 1442/3892] mac80211: fix sta lookup with AP VLAN interfaces and injected frames When injecting frames, mac80211 currently looks for the first AP interface that matches the source address of the injected frame. This breaks when such a frame is directed at a STA that has been moved to a VLAN. This patch fixes it by using sta_info_get_bss instead of sta_info_get, which also finds stations belonging to a VLAN interface of the same BSS as the AP interface. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e7b1cdc7651b..85e382aa894e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1133,6 +1133,8 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, tx->sta = rcu_dereference(sdata->u.vlan.sta); if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) return TX_DROP; + } else if (info->flags & IEEE80211_TX_CTL_INJECTED) { + tx->sta = sta_info_get_bss(sdata, hdr->addr1); } if (!tx->sta) tx->sta = sta_info_get(sdata, hdr->addr1); -- GitLab From 3c384053ce4cb1949f5575c28e30e6ceea8cb39b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Date: Mon, 1 Feb 2010 18:49:07 +0530 Subject: [PATCH 1443/3892] mac80211: Don't call rate control when HW handles it Rate control should not be called to update the tx status when HW does the RC. Signed-off-by: Vasanthakumar Signed-off-by: John W. Linville --- net/mac80211/rate.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 669dddd40521..998cf7a935b6 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -44,6 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; + + if (!ref) + return; + ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); } -- GitLab From e389900ed31975f3ce091764bf394b045058dad1 Mon Sep 17 00:00:00 2001 From: Hamish Guthrie Date: Mon, 1 Feb 2010 17:42:38 +0100 Subject: [PATCH 1444/3892] ps3_gelic_wireless: Remove superfluous debug info Signed-off-by: John W. Linville --- drivers/net/ps3_gelic_wireless.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 448c5b6789d3..2663b2fdc0bb 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1449,8 +1449,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, void *buf = NULL; size_t len; - pr_debug("%s: <- always=%d essid_len=%z\n", __func__, - always_scan, essid_len); + pr_debug("%s: <- always=%d\n", __func__, always_scan); if (mutex_lock_interruptible(&wl->scan_lock)) return -ERESTARTSYS; -- GitLab From ab5132a26236e308c6d3d832a3e04fca351656d8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sat, 30 Jan 2010 21:37:24 -0500 Subject: [PATCH 1445/3892] ath9k: fix access to freed data on unload Calling ath_bus_cleanup() after ieee80211_free_hw() resulted in access to common->bus_ops, which is already freed as part of the device data. Remove the cleanup field in struct ath_bus_ops, as it was never used properly. Remove ath_bus_cleanup(). Merge cleanup functions in place of the ath_bus_cleanup() calls. Take care not to use any device data after ieee80211_free_hw(). Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 - drivers/net/wireless/ath/ath9k/ahb.c | 12 ++---------- drivers/net/wireless/ath/ath9k/ath9k.h | 5 ----- drivers/net/wireless/ath/ath9k/pci.c | 18 +++++------------- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 9e05648356fe..71fc960814f0 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -74,7 +74,6 @@ struct ath_common; struct ath_bus_ops { void (*read_cachesize)(struct ath_common *common, int *csz); - void (*cleanup)(struct ath_common *common); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); }; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9e62a569e816..ca4994f13151 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -27,12 +27,6 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) *csz = L1_CACHE_BYTES >> 2; } -static void ath_ahb_cleanup(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *)common->priv; - iounmap(sc->mem); -} - static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_softc *sc = (struct ath_softc *)common->priv; @@ -54,8 +48,6 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) static struct ath_bus_ops ath_ahb_bus_ops = { .read_cachesize = ath_ahb_read_cachesize, - .cleanup = ath_ahb_cleanup, - .eeprom_read = ath_ahb_eeprom_read, }; @@ -164,12 +156,12 @@ static int ath_ahb_remove(struct platform_device *pdev) if (hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + void __iomem *mem = sc->mem; ath9k_deinit_device(sc); free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); - ath_bus_cleanup(common); + iounmap(mem); platform_set_drvdata(pdev, NULL); } diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3f8a7e773d55..0ea340fd071c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -538,11 +538,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) common->bus_ops->read_cachesize(common, csz); } -static inline void ath_bus_cleanup(struct ath_common *common) -{ - common->bus_ops->cleanup(common); -} - extern struct ieee80211_ops ath9k_ops; extern int modparam_nohwcrypt; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 4ae7b5f12029..f2afcbefc076 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -49,16 +49,6 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } -static void ath_pci_cleanup(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct pci_dev *pdev = to_pci_dev(sc->dev); - - pci_iounmap(pdev, sc->mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); -} - static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_hw *ah = (struct ath_hw *) common->ah; @@ -98,7 +88,6 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) static const struct ath_bus_ops ath_pci_bus_ops = { .read_cachesize = ath_pci_read_cachesize, - .cleanup = ath_pci_cleanup, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, }; @@ -245,12 +234,15 @@ static void ath_pci_remove(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + void __iomem *mem = sc->mem; ath9k_deinit_device(sc); free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); - ath_bus_cleanup(common); + + pci_iounmap(pdev, mem); + pci_disable_device(pdev); + pci_release_region(pdev, 0); } #ifdef CONFIG_PM -- GitLab From 20026d92013d7bb3abb295337191def6758fc086 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 4 Feb 2010 09:48:58 +1100 Subject: [PATCH 1446/3892] xfs: kill the unused XFS_QMOPT_* flush flags V2 dquots are never flushed asynchronously. Remove the flag and the async write support from the flush function. Make the default flush a delwri flush to make the inode flush code, which leaves the XFS_QMOPT_SYNC the only flag remaining. Convert that to use SYNC_WAIT instead, just like the inode flush code. V2: - just pass flush flags straight through Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/quota/xfs_dquot.c | 13 ++++++------- fs/xfs/quota/xfs_dquot_item.c | 2 +- fs/xfs/quota/xfs_qm.c | 14 ++++++-------- fs/xfs/xfs_quota.h | 8 +------- 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 1620a56b067e..5f79dd78626b 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1187,7 +1187,7 @@ xfs_qm_dqflush( * block, nada. */ if (!XFS_DQ_IS_DIRTY(dqp) || - (!(flags & XFS_QMOPT_SYNC) && atomic_read(&dqp->q_pincount) > 0)) { + (!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) { xfs_dqfunlock(dqp); return 0; } @@ -1251,18 +1251,17 @@ xfs_qm_dqflush( xfs_log_force(mp, 0); } - if (flags & XFS_QMOPT_DELWRI) { - xfs_bdwrite(mp, bp); - } else { + if (flags & SYNC_WAIT) error = xfs_bwrite(mp, bp); - } + else + xfs_bdwrite(mp, bp); trace_xfs_dqflush_done(dqp); /* * dqp is still locked, but caller is free to unlock it now. */ - return (error); + return error; } @@ -1443,7 +1442,7 @@ xfs_qm_dqpurge( * We don't care about getting disk errors here. We need * to purge this dquot anyway, so we go ahead regardless. */ - error = xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC); + error = xfs_qm_dqflush(dqp, SYNC_WAIT); if (error) xfs_fs_cmn_err(CE_WARN, mp, "xfs_qm_dqpurge: dquot %p flush failed", dqp); diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index dda0fb045c8a..4e4ee9a57194 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -153,7 +153,7 @@ xfs_qm_dquot_logitem_push( * lock without sleeping, then there must not have been * anyone in the process of flushing the dquot. */ - error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + error = xfs_qm_dqflush(dqp, 0); if (error) xfs_fs_cmn_err(CE_WARN, dqp->q_mount, "xfs_qm_dquot_logitem_push: push error %d on dqp %p", diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 11cfd8245c7c..8699e51cb45e 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -450,7 +450,7 @@ xfs_qm_unmount_quotas( STATIC int xfs_qm_dqflush_all( xfs_mount_t *mp, - int flags) + int sync_mode) { int recl; xfs_dquot_t *dqp; @@ -486,7 +486,7 @@ again: * across a disk write. */ xfs_qm_mplist_unlock(mp); - error = xfs_qm_dqflush(dqp, flags); + error = xfs_qm_dqflush(dqp, sync_mode); xfs_dqunlock(dqp); if (error) return error; @@ -926,13 +926,11 @@ xfs_qm_sync( { int recl, restarts; xfs_dquot_t *dqp; - uint flush_flags; int error; if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp)) return 0; - flush_flags = (flags & SYNC_WAIT) ? XFS_QMOPT_SYNC : XFS_QMOPT_DELWRI; restarts = 0; again: @@ -992,7 +990,7 @@ xfs_qm_sync( * across a disk write */ xfs_qm_mplist_unlock(mp); - error = xfs_qm_dqflush(dqp, flush_flags); + error = xfs_qm_dqflush(dqp, flags); xfs_dqunlock(dqp); if (error && XFS_FORCED_SHUTDOWN(mp)) return 0; /* Need to prevent umount failure */ @@ -1796,7 +1794,7 @@ xfs_qm_quotacheck( * successfully. */ if (!error) - error = xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI); + error = xfs_qm_dqflush_all(mp, 0); /* * We can get this error if we couldn't do a dquot allocation inside @@ -2018,7 +2016,7 @@ xfs_qm_shake_freelist( * We flush it delayed write, so don't bother * releasing the mplock. */ - error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + error = xfs_qm_dqflush(dqp, 0); if (error) { xfs_fs_cmn_err(CE_WARN, dqp->q_mount, "xfs_qm_dqflush_all: dquot %p flush failed", dqp); @@ -2201,7 +2199,7 @@ xfs_qm_dqreclaim_one(void) * We flush it delayed write, so don't bother * releasing the freelist lock. */ - error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + error = xfs_qm_dqflush(dqp, 0); if (error) { xfs_fs_cmn_err(CE_WARN, dqp->q_mount, "xfs_qm_dqreclaim: dquot %p flush failed", dqp); diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 21d11d9f48f2..fdcab3f81dde 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -222,16 +222,10 @@ typedef struct xfs_qoff_logformat { #define XFS_QMOPT_DELRTBCOUNT 0x0400000 #define XFS_QMOPT_RES_INOS 0x0800000 -/* - * flags for dqflush and dqflush_all. - */ -#define XFS_QMOPT_SYNC 0x1000000 -#define XFS_QMOPT_DELWRI 0x4000000 - /* * flags for dqalloc. */ -#define XFS_QMOPT_INHERIT 0x8000000 +#define XFS_QMOPT_INHERIT 0x1000000 /* * flags to xfs_trans_mod_dquot. -- GitLab From e8b217e7530c6a073ac69f1c85b922d93fdf5647 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 2 Feb 2010 10:16:26 +1100 Subject: [PATCH 1447/3892] xfs: remove invalid barrier optimization from xfs_fsync We always need to flush the disk write cache and can't skip it just because the no inode attributes have changed. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner --- fs/xfs/xfs_vnodeops.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index fd108b738559..43241e289800 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -597,7 +597,7 @@ xfs_fsync( { xfs_trans_t *tp; int error = 0; - int log_flushed = 0, changed = 1; + int log_flushed = 0; xfs_itrace_entry(ip); @@ -627,18 +627,10 @@ xfs_fsync( * disk yet, the inode will be still be pinned. If it is, * force the log. */ - xfs_iunlock(ip, XFS_ILOCK_SHARED); - if (xfs_ipincount(ip)) { error = _xfs_log_force(ip->i_mount, XFS_LOG_SYNC, &log_flushed); - } else { - /* - * If the inode is not pinned and nothing has changed - * we don't need to flush the cache. - */ - changed = 0; } } else { /* @@ -673,7 +665,7 @@ xfs_fsync( xfs_iunlock(ip, XFS_ILOCK_EXCL); } - if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) { + if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) { /* * If the log write didn't issue an ordered tag we need * to flush the disk cache for the data device now. -- GitLab From c85a400499093b2025238413198e48e4d825723e Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 1 Feb 2010 16:17:01 -0200 Subject: [PATCH 1448/3892] ALSA: trivial: sound seq ioctl dbg: print hexadecimal value padded with 0s Instead of padding with blanks and printing "number=0x a", print "number=0x0a". Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 8ca2be339f3b..48eca9ff9ee7 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, if (p->cmd == cmd) return p->func(client, arg); } - snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n", + snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); return -ENOTTY; } -- GitLab From 61ef2489dbf587258526cfd4ebf4bba3b079f401 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 22 Jan 2010 16:16:19 +0800 Subject: [PATCH 1449/3892] resources: introduce generic page_is_ram() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's based on walk_system_ram_range(), for archs that don't have their own page_is_ram(). The static verions in MIPS and SCORE are also made global. v4: prefer plain 1 instead of PAGE_IS_RAM (H. Peter Anvin) v3: add comment (KAMEZAWA Hiroyuki) "AFAIK, this "System RAM" information has been used for kdump to grab valid memory area and seems good for the kernel itself." v2: add PAGE_IS_RAM macro (Américo Wang) Cc: Chen Liqin Cc: Lennox Wu Cc: Américo Wang Cc: linux-mips@linux-mips.org Cc: Yinghai Lu Acked-by: Ralf Baechle Reviewed-by: KAMEZAWA Hiroyuki Signed-off-by: Wu Fengguang LKML-Reference: <20100122081619.GA6431@localhost> Cc: Andrew Morton Signed-off-by: H. Peter Anvin --- arch/mips/mm/init.c | 2 +- arch/score/mm/init.c | 2 +- include/linux/ioport.h | 2 ++ kernel/resource.c | 13 +++++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 15aa1902a788..4d72aabe8352 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -294,7 +294,7 @@ void __init fixrange_init(unsigned long start, unsigned long end, } #ifndef CONFIG_NEED_MULTIPLE_NODES -static int __init page_is_ram(unsigned long pagenr) +int page_is_ram(unsigned long pagenr) { int i; diff --git a/arch/score/mm/init.c b/arch/score/mm/init.c index 4e3dcd0c4716..f684a590c21d 100644 --- a/arch/score/mm/init.c +++ b/arch/score/mm/init.c @@ -59,7 +59,7 @@ static unsigned long setup_zero_page(void) } #ifndef CONFIG_NEED_MULTIPLE_NODES -static int __init page_is_ram(unsigned long pagenr) +int page_is_ram(unsigned long pagenr) { if (pagenr >= min_low_pfn && pagenr < max_low_pfn) return 1; diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 83aa81297ea3..11ef7952b63a 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -188,5 +188,7 @@ extern int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, void *arg, int (*func)(unsigned long, unsigned long, void *)); +extern int page_is_ram(unsigned long pfn); + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_IOPORT_H */ diff --git a/kernel/resource.c b/kernel/resource.c index fb11a58b9594..b4d637a55256 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -297,6 +297,19 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, #endif +static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg) +{ + return 1; +} +/* + * This generic page_is_ram() returns true if specified address is + * registered as "System RAM" in iomem_resource list. + */ +int __attribute__((weak)) page_is_ram(unsigned long pfn) +{ + return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; +} + /* * Find empty slot in the resource tree given range and alignment. */ -- GitLab From e52730071567ec5b6f57e21d6693b112e01e1d0e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 26 Jan 2010 16:31:19 -0800 Subject: [PATCH 1450/3892] Generic page_is_ram: use __weak Use __weak instead of __attribute__((weak)). Cc: Wu Fengguang Signed-off-by: Andrew Morton Signed-off-by: H. Peter Anvin --- kernel/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/resource.c b/kernel/resource.c index b4d637a55256..e68cd7477c40 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -305,7 +305,7 @@ static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg) * This generic page_is_ram() returns true if specified address is * registered as "System RAM" in iomem_resource list. */ -int __attribute__((weak)) page_is_ram(unsigned long pfn) +int __weak page_is_ram(unsigned long pfn) { return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; } -- GitLab From 53df8fdc15fb646b0219e43c989c2cdab1ab100c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 27 Jan 2010 11:06:39 +0800 Subject: [PATCH 1451/3892] Move page_is_ram() declaration to mm.h Move page_is_ram() declaration to mm.h, it makes no sense in . Signed-off-by: Wu Fengguang LKML-Reference: <20100127030639.GD8132@localhost> Signed-off-by: H. Peter Anvin --- include/linux/ioport.h | 2 -- include/linux/mm.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 11ef7952b63a..83aa81297ea3 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -188,7 +188,5 @@ extern int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, void *arg, int (*func)(unsigned long, unsigned long, void *)); -extern int page_is_ram(unsigned long pfn); - #endif /* __ASSEMBLY__ */ #endif /* _LINUX_IOPORT_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 24c395694f4d..bad433fdbfce 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -265,6 +265,8 @@ static inline int get_page_unless_zero(struct page *page) return atomic_inc_not_zero(&page->_count); } +extern int page_is_ram(unsigned long pfn); + /* Support for virtually mapped pages */ struct page *vmalloc_to_page(const void *addr); unsigned long vmalloc_to_pfn(const void *addr); -- GitLab From 1b5576e69a5fe168c08a159685ac366316ac9bbc Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 22 Jan 2010 11:21:04 +0800 Subject: [PATCH 1452/3892] x86: Remove BIOS data range from e820 In preparation for moving to the generic page_is_ram(), make explicit what we expect to be reserved and not reserved. Tested-by: Wu Fengguang Signed-off-by: Yinghai Lu LKML-Reference: <20100122033004.335813103@intel.com> Cc: Andrew Morton Signed-off-by: H. Peter Anvin --- arch/x86/kernel/e820.c | 8 ++++++++ arch/x86/kernel/setup.c | 19 ++++++++++++++++++- arch/x86/mm/ioremap.c | 16 ---------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index d17d482a04f4..230687ba5ba5 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -517,11 +517,19 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type, int checktype) { int i; + u64 end; u64 real_removed_size = 0; if (size > (ULLONG_MAX - start)) size = ULLONG_MAX - start; + end = start + size; + printk(KERN_DEBUG "e820 remove range: %016Lx - %016Lx ", + (unsigned long long) start, + (unsigned long long) end); + e820_print_type(old_type); + printk(KERN_CONT "\n"); + for (i = 0; i < e820.nr_map; i++) { struct e820entry *ei = &e820.map[i]; u64 final_start, final_end; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index cdb6a8a506dd..f9b1f4e5ab74 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -650,6 +650,23 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = { {} }; +static void __init trim_bios_range(void) +{ + /* + * A special case is the first 4Kb of memory; + * This is a BIOS owned area, not kernel ram, but generally + * not listed as such in the E820 table. + */ + e820_update_range(0, PAGE_SIZE, E820_RAM, E820_RESERVED); + /* + * special case: Some BIOSen report the PC BIOS + * area (640->1Mb) as ram even though it is not. + * take them out. + */ + e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); + sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); +} + /* * Determine if we were loaded by an EFI loader. If so, then we have also been * passed the efi memmap, systab, etc., so we should use these data structures @@ -813,7 +830,7 @@ void __init setup_arch(char **cmdline_p) insert_resource(&iomem_resource, &data_resource); insert_resource(&iomem_resource, &bss_resource); - + trim_bios_range(); #ifdef CONFIG_X86_32 if (ppro_with_ram_bug()) { e820_update_range(0x70000000ULL, 0x40000ULL, E820_RAM, diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 334e63ca7b2b..30e068d6462e 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -29,22 +29,6 @@ int page_is_ram(unsigned long pagenr) resource_size_t addr, end; int i; - /* - * A special case is the first 4Kb of memory; - * This is a BIOS owned area, not kernel ram, but generally - * not listed as such in the E820 table. - */ - if (pagenr == 0) - return 0; - - /* - * Second special case: Some BIOSen report the PC BIOS - * area (640->1Mb) as ram even though it is not. - */ - if (pagenr >= (BIOS_BEGIN >> PAGE_SHIFT) && - pagenr < (BIOS_END >> PAGE_SHIFT)) - return 0; - for (i = 0; i < e820.nr_map; i++) { /* * Not usable memory: -- GitLab From 13ca0fcaa33f6b1984c4111b6ec5df42689fea6f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 22 Jan 2010 11:21:05 +0800 Subject: [PATCH 1453/3892] x86: Use the generic page_is_ram() The generic resource based page_is_ram() works better with memory hotplug/hotremove. So switch the x86 e820map based code to it. CC: Andi Kleen CC: KAMEZAWA Hiroyuki CC: Yinghai Lu Signed-off-by: Wu Fengguang LKML-Reference: <20100122033004.470767217@intel.com> Cc: Andrew Morton Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/page_types.h | 1 - arch/x86/mm/ioremap.c | 21 --------------------- 2 files changed, 22 deletions(-) diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 642fe34b36a2..a667f24c7254 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -40,7 +40,6 @@ #ifndef __ASSEMBLY__ -extern int page_is_ram(unsigned long pagenr); extern int devmem_is_allowed(unsigned long pagenr); extern unsigned long max_low_pfn_mapped; diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 30e068d6462e..1bf9e08ed733 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -24,27 +24,6 @@ #include "physaddr.h" -int page_is_ram(unsigned long pagenr) -{ - resource_size_t addr, end; - int i; - - for (i = 0; i < e820.nr_map; i++) { - /* - * Not usable memory: - */ - if (e820.map[i].type != E820_RAM) - continue; - addr = (e820.map[i].addr + PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT; - - - if ((pagenr >= addr) && (pagenr < end)) - return 1; - } - return 0; -} - /* * Fix up the linear direct mapping of the kernel to avoid cache attribute * conflicts. -- GitLab From b79c7adf82e8b8a6d6ad1dadf7e687a4a030cf8c Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 2 Feb 2010 13:01:25 +0900 Subject: [PATCH 1454/3892] mtd: trivial sh_flctl changes This patch contains a few changes for the sh_flctl driver: - not sh7723-only driver - get rid of kconfig dependency - use dev_err() instead of printk() - use __devinit and __devexit for probe()/remove() - fix probe() return values Signed-off-by: Magnus Damm Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/mtd/nand/Kconfig | 4 ++-- drivers/mtd/nand/sh_flctl.c | 42 ++++++++++++++++++++---------------- include/linux/mtd/sh_flctl.h | 1 + 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 677cd53f18c3..bb6465604235 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -457,10 +457,10 @@ config MTD_NAND_NOMADIK config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" - depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 + depends on MTD_NAND && SUPERH help Several Renesas SuperH CPU has FLCTL. This option enables support - for NAND Flash using FLCTL. This driver support SH7723. + for NAND Flash using FLCTL. config MTD_NAND_DAVINCI tristate "Support NAND on DaVinci SoC" diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 02bef21f2e4b..ab068a503b29 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1,10 +1,10 @@ /* * SuperH FLCTL nand controller * - * Copyright © 2008 Renesas Solutions Corp. - * Copyright © 2008 Atom Create Engineering Co., Ltd. + * Copyright (c) 2008 Renesas Solutions Corp. + * Copyright (c) 2008 Atom Create Engineering Co., Ltd. * - * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor + * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,6 +75,11 @@ static void start_translation(struct sh_flctl *flctl) writeb(TRSTRT, FLTRCR(flctl)); } +static void timeout_error(struct sh_flctl *flctl, const char *str) +{ + dev_err(&flctl->pdev->dev, "Timeout occured in %s\n", str); +} + static void wait_completion(struct sh_flctl *flctl) { uint32_t timeout = LOOP_TIMEOUT_MAX; @@ -87,7 +92,7 @@ static void wait_completion(struct sh_flctl *flctl) udelay(1); } - printk(KERN_ERR "wait_completion(): Timeout occured \n"); + timeout_error(flctl, __func__); writeb(0x0, FLTRCR(flctl)); } @@ -132,7 +137,7 @@ static void wait_rfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static void wait_wfifo_ready(struct sh_flctl *flctl) @@ -146,7 +151,7 @@ static void wait_wfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) @@ -198,7 +203,7 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) writel(0, FL4ECCCR(flctl)); } - printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); return 1; /* timeout */ } @@ -214,7 +219,7 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl) return; udelay(1); } - printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n"); + timeout_error(flctl, __func__); } static void read_datareg(struct sh_flctl *flctl, int offset) @@ -769,38 +774,36 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) return 0; } -static int __init flctl_probe(struct platform_device *pdev) +static int __devinit flctl_probe(struct platform_device *pdev) { struct resource *res; struct sh_flctl *flctl; struct mtd_info *flctl_mtd; struct nand_chip *nand; struct sh_flctl_platform_data *pdata; - int ret; + int ret = -ENXIO; pdata = pdev->dev.platform_data; if (pdata == NULL) { - printk(KERN_ERR "sh_flctl platform_data not found.\n"); - return -ENODEV; + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; } flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); if (!flctl) { - printk(KERN_ERR "Unable to allocate NAND MTD dev structure.\n"); + dev_err(&pdev->dev, "failed to allocate driver data\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - printk(KERN_ERR "%s: resource not found.\n", __func__); - ret = -ENODEV; + dev_err(&pdev->dev, "failed to get I/O memory\n"); goto err; } - flctl->reg = ioremap(res->start, res->end - res->start + 1); + flctl->reg = ioremap(res->start, resource_size(res)); if (flctl->reg == NULL) { - printk(KERN_ERR "%s: ioremap error.\n", __func__); - ret = -ENOMEM; + dev_err(&pdev->dev, "failed to remap I/O memory\n"); goto err; } @@ -808,6 +811,7 @@ static int __init flctl_probe(struct platform_device *pdev) flctl_mtd = &flctl->mtd; nand = &flctl->chip; flctl_mtd->priv = nand; + flctl->pdev = pdev; flctl->hwecc = pdata->has_hwecc; flctl_register_init(flctl, pdata->flcmncr_val); @@ -846,7 +850,7 @@ err: return ret; } -static int __exit flctl_remove(struct platform_device *pdev) +static int __devexit flctl_remove(struct platform_device *pdev) { struct sh_flctl *flctl = platform_get_drvdata(pdev); diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index e77c1cea404d..164c9d4013c0 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -96,6 +96,7 @@ struct sh_flctl { struct mtd_info mtd; struct nand_chip chip; + struct platform_device *pdev; void __iomem *reg; uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ -- GitLab From 010ab820582d03bcd3648416b5837107e8a9c5f3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 27 Jan 2010 09:17:21 +0000 Subject: [PATCH 1455/3892] mtd: sh_flctl SHBUSSEL and SEL_16BIT support This patch extends the sh_flctl driver with support for 16-bit bus configuration using SEL_16BIT and support for multiplexed pins using SHBUSSEL. Signed-off-by: Magnus Damm Acked-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/mtd/nand/sh_flctl.c | 27 ++++++++++++++++++++++++++- include/linux/mtd/sh_flctl.h | 2 ++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index ab068a503b29..1842df8bdd93 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -105,6 +105,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr) addr = page_addr; /* ERASE1 */ } else if (page_addr != -1) { /* SEQIN, READ0, etc.. */ + if (flctl->chip.options & NAND_BUSWIDTH_16) + column >>= 1; if (flctl->page_size) { addr = column & 0x0FFF; addr |= (page_addr & 0xff) << 16; @@ -280,7 +282,7 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - uint32_t flcmncr_val = readl(FLCMNCR(flctl)); + uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT; uint32_t flcmdcr_val, addr_len_bytes = 0; /* Set SNAND bit if page size is 2048byte */ @@ -302,6 +304,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va case NAND_CMD_READOOB: addr_len_bytes = flctl->rw_ADRCNT; flcmdcr_val |= CDSRC_E; + if (flctl->chip.options & NAND_BUSWIDTH_16) + flcmncr_val |= SEL_16BIT; break; case NAND_CMD_SEQIN: /* This case is that cmd is READ0 or READ1 or READ00 */ @@ -310,6 +314,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va case NAND_CMD_PAGEPROG: addr_len_bytes = flctl->rw_ADRCNT; flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW; + if (flctl->chip.options & NAND_BUSWIDTH_16) + flcmncr_val |= SEL_16BIT; break; case NAND_CMD_READID: flcmncr_val &= ~SNAND_E; @@ -528,6 +534,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, set_addr(mtd, 0, page_addr); flctl->read_bytes = mtd->writesize + mtd->oobsize; + if (flctl->chip.options & NAND_BUSWIDTH_16) + column >>= 1; flctl->index += column; goto read_normal_exit; @@ -691,6 +699,18 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd) return data; } +static uint16_t flctl_read_word(struct mtd_info *mtd) +{ + struct sh_flctl *flctl = mtd_to_flctl(mtd); + int index = flctl->index; + uint16_t data; + uint16_t *buf = (uint16_t *)&flctl->done_buff[index]; + + data = *buf; + flctl->index += 2; + return data; +} + static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { int i; @@ -829,6 +849,11 @@ static int __devinit flctl_probe(struct platform_device *pdev) nand->select_chip = flctl_select_chip; nand->cmdfunc = flctl_cmdfunc; + if (pdata->flcmncr_val & SEL_16BIT) { + nand->options |= NAND_BUSWIDTH_16; + nand->read_word = flctl_read_word; + } + ret = nand_scan_ident(flctl_mtd, 1); if (ret) goto err; diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 164c9d4013c0..ab77609ec337 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -51,6 +51,8 @@ #define _4ECCCNTEN (0x1 << 24) #define _4ECCEN (0x1 << 23) #define _4ECCCORRECT (0x1 << 22) +#define SHBUSSEL (0x1 << 20) +#define SEL_16BIT (0x1 << 19) #define SNAND_E (0x1 << 18) /* SNAND (0=512 1=2048)*/ #define QTSEL_E (0x1 << 17) #define ENDIAN (0x1 << 16) /* 1 = little endian */ -- GitLab From b4f74767a04e175c028336e06507fcc05f5a8618 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Jan 2010 07:31:13 +0000 Subject: [PATCH 1456/3892] sh: add high impedance mode management for SIUA pins on sh7722 This improves power management for the SIUA controller on sh7722. Similar patches might be desired for other SIU-enabled SH platforms. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c index cb9d07bd59f8..0688a7502f86 100644 --- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c @@ -278,6 +278,7 @@ enum { HIZA8_LCDC, HIZA8_HIZ, HIZA7_LCDC, HIZA7_HIZ, HIZA6_LCDC, HIZA6_HIZ, + HIZB4_SIUA, HIZB4_HIZ, HIZB1_VIO, HIZB1_HIZ, HIZB0_VIO, HIZB0_HIZ, HIZC15_IRQ7, HIZC15_HIZ, @@ -546,7 +547,7 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(VIO_VD2_MARK, PSE3_VIO, MSELB9_VIO2, HIZB0_VIO, FOE_VIO_VD2), PINMUX_DATA(VIO_HD2_MARK, PSE3_VIO, MSELB9_VIO2, - HIZB1_VIO, HIZB1_VIO, FCE_VIO_HD2), + HIZB1_VIO, FCE_VIO_HD2), PINMUX_DATA(VIO_CLK2_MARK, PSE3_VIO, MSELB9_VIO2, HIZB1_VIO, FRB_VIO_CLK2), @@ -658,14 +659,14 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(SDHICLK_MARK, SDHICLK), /* SIU - Port A */ - PINMUX_DATA(SIUAOLR_MARK, PSC13_SIUAOLR, SIUAOLR_SIOF1_SYNC), - PINMUX_DATA(SIUAOBT_MARK, PSC14_SIUAOBT, SIUAOBT_SIOF1_SCK), - PINMUX_DATA(SIUAISLD_MARK, PSC15_SIUAISLD, SIUAISLD_SIOF1_RXD), - PINMUX_DATA(SIUAILR_MARK, PSC11_SIUAILR, SIUAILR_SIOF1_SS2), - PINMUX_DATA(SIUAIBT_MARK, PSC12_SIUAIBT, SIUAIBT_SIOF1_SS1), - PINMUX_DATA(SIUAOSLD_MARK, PSB0_SIUAOSLD, SIUAOSLD_SIOF1_TXD), - PINMUX_DATA(SIUMCKA_MARK, PSE11_SIUMCKA_SIOF1_MCK, PSB1_SIUMCKA, PTK0), - PINMUX_DATA(SIUFCKA_MARK, PSE11_SIUFCKA, PTK0), + PINMUX_DATA(SIUAOLR_MARK, PSC13_SIUAOLR, HIZB4_SIUA, SIUAOLR_SIOF1_SYNC), + PINMUX_DATA(SIUAOBT_MARK, PSC14_SIUAOBT, HIZB4_SIUA, SIUAOBT_SIOF1_SCK), + PINMUX_DATA(SIUAISLD_MARK, PSC15_SIUAISLD, HIZB4_SIUA, SIUAISLD_SIOF1_RXD), + PINMUX_DATA(SIUAILR_MARK, PSC11_SIUAILR, HIZB4_SIUA, SIUAILR_SIOF1_SS2), + PINMUX_DATA(SIUAIBT_MARK, PSC12_SIUAIBT, HIZB4_SIUA, SIUAIBT_SIOF1_SS1), + PINMUX_DATA(SIUAOSLD_MARK, PSB0_SIUAOSLD, HIZB4_SIUA, SIUAOSLD_SIOF1_TXD), + PINMUX_DATA(SIUMCKA_MARK, PSE11_SIUMCKA_SIOF1_MCK, HIZB4_SIUA, PSB1_SIUMCKA, PTK0), + PINMUX_DATA(SIUFCKA_MARK, PSE11_SIUFCKA, HIZB4_SIUA, PTK0), /* SIU - Port B */ PINMUX_DATA(SIUBOLR_MARK, PSB11_SIUBOLR, SIOSTRB1_SIUBOLR), @@ -1612,7 +1613,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = { 0, 0, 0, 0, 0, 0, - 0, 0, + HIZB4_SIUA, HIZB4_HIZ, 0, 0, 0, 0, HIZB1_VIO, HIZB1_HIZ, -- GitLab From 90fdbdb48442a03c72cae5463e6edb64cb3a3a7d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 31 Jan 2010 20:53:24 +0900 Subject: [PATCH 1457/3892] sched: Use for_each_bit No change in functionality. Signed-off-by: Akinobu Mita Cc: Peter Zijlstra Cc: Andrew Morton LKML-Reference: <1264938810-4173-1-git-send-email-akinobu.mita@gmail.com> Signed-off-by: Ingo Molnar --- kernel/sched_cpupri.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/sched_cpupri.c b/kernel/sched_cpupri.c index 597b33099dfa..eeb3506c4834 100644 --- a/kernel/sched_cpupri.c +++ b/kernel/sched_cpupri.c @@ -47,9 +47,7 @@ static int convert_prio(int prio) } #define for_each_cpupri_active(array, idx) \ - for (idx = find_first_bit(array, CPUPRI_NR_PRIORITIES); \ - idx < CPUPRI_NR_PRIORITIES; \ - idx = find_next_bit(array, CPUPRI_NR_PRIORITIES, idx+1)) + for_each_bit(idx, array, CPUPRI_NR_PRIORITIES) /** * cpupri_find - find the best (lowest-pri) CPU in the system -- GitLab From 4a461c85b643258e305eb5a3aced34009db2f818 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 1 Feb 2010 11:13:39 +0100 Subject: [PATCH 1458/3892] sched: Remove unused update_shares_locked() Commit f492e12ef050e02bf0185b6b57874992591b9be1 ("sched: Remove load_balance_newidle()") removed the only user of this function, so remove it too. Reported-by: Stephen Rothwell Signed-off-by: Peter Zijlstra LKML-Reference: <1265019219.24455.128.camel@laptop> Signed-off-by: Ingo Molnar --- kernel/sched.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index a56ead42d651..2386f5440002 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1633,16 +1633,6 @@ static void update_shares(struct sched_domain *sd) } } -static void update_shares_locked(struct rq *rq, struct sched_domain *sd) -{ - if (root_task_group_empty()) - return; - - raw_spin_unlock(&rq->lock); - update_shares(sd); - raw_spin_lock(&rq->lock); -} - static void update_h_load(long cpu) { if (root_task_group_empty()) @@ -1657,10 +1647,6 @@ static inline void update_shares(struct sched_domain *sd) { } -static inline void update_shares_locked(struct rq *rq, struct sched_domain *sd) -{ -} - #endif #ifdef CONFIG_PREEMPT -- GitLab From 8a349d4b13c41c00564cd79f6fabdec347084758 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 2 Feb 2010 07:22:13 +0000 Subject: [PATCH 1459/3892] spi/spi_s3c64xx.c: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 32db69540fa9..97365815a729 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -634,8 +634,8 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, S3C64XX_SPI_DEACT(sdd); if (status) { - dev_err(&spi->dev, "I/O Error: \ - rx-%d tx-%d res:rx-%c tx-%c len-%d\n", + dev_err(&spi->dev, "I/O Error: " + "rx-%d tx-%d res:rx-%c tx-%c len-%d\n", xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, (sdd->state & RXBUSY) ? 'f' : 'p', (sdd->state & TXBUSY) ? 'f' : 'p', @@ -1039,11 +1039,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err8; } - dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \ - with %d Slaves attached\n", + dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d " + "with %d Slaves attached\n", pdev->id, master->num_chipselect); - dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\ - \tDMA=[Rx-%d, Tx-%d]\n", + dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", mem_res->end, mem_res->start, sdd->rx_dmach, sdd->tx_dmach); -- GitLab From e9867c569970d8afb4b882bafbbe81426bd46333 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 17:35:13 +0900 Subject: [PATCH 1460/3892] sh: Provide create_irq_nr() for dynamic IRQ creation by number. This just reworks the existing create_irq_on_node() in to the new create_irq_nr() which is generally exposed. This permits boards that haven't converted over to sparseirq to try and use their existing ranges, rather than having arbitrary vectors assigned to them. Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index d5d7f23c19a5..7d286aedaeeb 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -872,7 +872,7 @@ device_initcall(register_intc_sysdevs); /* * Dynamic IRQ allocation and deallocation */ -static unsigned int create_irq_on_node(unsigned int irq_want, int node) +unsigned int create_irq_nr(unsigned int irq_want, int node) { unsigned int irq = 0, new; unsigned long flags; @@ -881,24 +881,28 @@ static unsigned int create_irq_on_node(unsigned int irq_want, int node) spin_lock_irqsave(&vector_lock, flags); /* - * First try the wanted IRQ, then scan. + * First try the wanted IRQ */ - if (test_and_set_bit(irq_want, intc_irq_map)) { + if (test_and_set_bit(irq_want, intc_irq_map) == 0) { + new = irq_want; + } else { + /* .. then fall back to scanning. */ new = find_first_zero_bit(intc_irq_map, nr_irqs); if (unlikely(new == nr_irqs)) goto out_unlock; - desc = irq_to_desc_alloc_node(new, node); - if (unlikely(!desc)) { - pr_info("can't get irq_desc for %d\n", new); - goto out_unlock; - } - - desc = move_irq_desc(desc, node); __set_bit(new, intc_irq_map); - irq = new; } + desc = irq_to_desc_alloc_node(new, node); + if (unlikely(!desc)) { + pr_info("can't get irq_desc for %d\n", new); + goto out_unlock; + } + + desc = move_irq_desc(desc, node); + irq = new; + out_unlock: spin_unlock_irqrestore(&vector_lock, flags); @@ -913,7 +917,7 @@ int create_irq(void) int nid = cpu_to_node(smp_processor_id()); int irq; - irq = create_irq_on_node(NR_IRQS_LEGACY, nid); + irq = create_irq_nr(NR_IRQS_LEGACY, nid); if (irq == 0) irq = -1; -- GitLab From c7a967273a539a9a38413753c58125e777e2d30d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 17:38:04 +0900 Subject: [PATCH 1461/3892] sh: mach-se: Convert SH7724 solution engine FPGA to sparseirq. This uses the new create_irq_nr() to build up the FPGA's desired virtual IRQ mapping and permits us to finally flip on sparseirq for this board. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 2 +- arch/sh/boards/mach-se/7724/irq.c | 38 ++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index bae53831c06b..0f023bb62f99 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -731,7 +731,7 @@ config GUSA_RB config SPARSE_IRQ def_bool y depends on SUPERH32 && !SH_DREAMCAST && !SH_HIGHLANDER && \ - !SH_RTS7751R2D && !HD64461 && !SH_7724_SOLUTION_ENGINE + !SH_RTS7751R2D && !HD64461 help This enables support for sparse irqs. This is useful in general as most CPUs have a fairly sparse array of IRQ vectors, which diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c index e5e021a7d1e6..0942be2daef6 100644 --- a/arch/sh/boards/mach-se/7724/irq.c +++ b/arch/sh/boards/mach-se/7724/irq.c @@ -93,18 +93,15 @@ static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) { struct fpga_irq set = get_fpga_irq(irq); unsigned short intv = __raw_readw(set.sraddr); - struct irq_desc *ext_desc; unsigned int ext_irq = set.base; intv &= set.mask; - while (intv) { - if (intv & 0x0001) { - ext_desc = irq_desc + ext_irq; - handle_level_irq(ext_irq, ext_desc); - } - intv >>= 1; - ext_irq++; + for (; intv; intv >>= 1, ext_irq++) { + if (!(intv & 1)) + continue; + + generic_handle_irq(ext_irq); } } @@ -113,7 +110,7 @@ static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) */ void __init init_se7724_IRQ(void) { - int i; + int i, nid = cpu_to_node(boot_cpu_data); __raw_writew(0xffff, IRQ0_MR); /* mask all */ __raw_writew(0xffff, IRQ1_MR); /* mask all */ @@ -123,10 +120,29 @@ void __init init_se7724_IRQ(void) __raw_writew(0x0000, IRQ2_SR); /* clear irq */ __raw_writew(0x002a, IRQ_MODE); /* set irq type */ - for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) - set_irq_chip_and_handler_name(SE7724_FPGA_IRQ_BASE + i, + for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) { + int irq, wanted; + + wanted = SE7724_FPGA_IRQ_BASE + i; + + irq = create_irq_nr(wanted, nid); + if (unlikely(irq == 0)) { + pr_err("%s: failed hooking irq %d for FPGA\n", + __func__, wanted); + return; + } + + if (unlikely(irq != wanted)) { + pr_err("%s: got irq %d but wanted %d, bailing.\n", + __func__, irq, wanted); + destroy_irq(irq); + return; + } + + set_irq_chip_and_handler_name(irq, &se7724_irq_chip, handle_level_irq, "level"); + } set_irq_chained_handler(IRQ0_IRQ, se7724_irq_demux); set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); -- GitLab From 6eb6f98396f7bd653d8fb15b06364c8c7d70e22c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 17:48:17 +0900 Subject: [PATCH 1462/3892] sh: hd6446x: Convert to sparseirq. Follows the se7724 change and converts the hd64461 IRQ handling to sparseirq. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 2 +- arch/sh/cchips/hd6446x/hd64461.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0f023bb62f99..9e565d962dc0 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -731,7 +731,7 @@ config GUSA_RB config SPARSE_IRQ def_bool y depends on SUPERH32 && !SH_DREAMCAST && !SH_HIGHLANDER && \ - !SH_RTS7751R2D && !HD64461 + !SH_RTS7751R2D help This enables support for sparse irqs. This is useful in general as most CPUs have a fairly sparse array of IRQ vectors, which diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c index cbfedfb42e04..b447091fc064 100644 --- a/arch/sh/cchips/hd6446x/hd64461.c +++ b/arch/sh/cchips/hd6446x/hd64461.c @@ -73,7 +73,7 @@ static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc) int __init setup_hd64461(void) { - int i; + int i, nid = cpu_to_node(boot_cpu_data); if (!MACH_HD64461) return 0; @@ -90,9 +90,26 @@ int __init setup_hd64461(void) __raw_writew(0xffff, HD64461_NIMR); /* IRQ 80 -> 95 belongs to HD64461 */ - for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) + for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) { + unsigned int irq; + + irq = create_irq_nr(i, nid); + if (unlikely(irq == 0)) { + pr_err("%s: failed hooking irq %d for HD64461\n", + __func__, i); + return -EBUSY; + } + + if (unlikely(irq != i)) { + pr_err("%s: got irq %d but wanted %d, bailing.\n", + __func__, irq, i); + destroy_irq(irq); + return -EINVAL; + } + set_irq_chip_and_handler(i, &hd64461_irq_chip, handle_level_irq); + } set_irq_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux); set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW); -- GitLab From deb9b22b8968fa0166d89c8ad1346e816cf1aec4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 18:01:55 +0900 Subject: [PATCH 1463/3892] sh: mach-dreamcast: Convert to sparseirq. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 3 +-- arch/sh/boards/mach-dreamcast/irq.c | 27 +++++++++++++++++++ arch/sh/boards/mach-dreamcast/setup.c | 18 +------------ arch/sh/include/mach-dreamcast/mach/sysasic.h | 5 ++++ 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 9e565d962dc0..3b3c036cbc30 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -730,8 +730,7 @@ config GUSA_RB config SPARSE_IRQ def_bool y - depends on SUPERH32 && !SH_DREAMCAST && !SH_HIGHLANDER && \ - !SH_RTS7751R2D + depends on SUPERH32 && !SH_HIGHLANDER && !SH_RTS7751R2D help This enables support for sparse irqs. This is useful in general as most CPUs have a fairly sparse array of IRQ vectors, which diff --git a/arch/sh/boards/mach-dreamcast/irq.c b/arch/sh/boards/mach-dreamcast/irq.c index f55fc8e795e9..d932667410ab 100644 --- a/arch/sh/boards/mach-dreamcast/irq.c +++ b/arch/sh/boards/mach-dreamcast/irq.c @@ -135,3 +135,30 @@ int systemasic_irq_demux(int irq) /* Not reached */ return irq; } + +void systemasic_irq_init(void) +{ + int i, nid = cpu_to_node(boot_cpu_data); + + /* Assign all virtual IRQs to the System ASIC int. handler */ + for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) { + unsigned int irq; + + irq = create_irq_nr(i, nid); + if (unlikely(irq == 0)) { + pr_err("%s: failed hooking irq %d for systemasic\n", + __func__, i); + return; + } + + if (unlikely(irq != i)) { + pr_err("%s: got irq %d but wanted %d, bailing.\n", + __func__, irq, i); + destroy_irq(irq); + return; + } + + set_irq_chip_and_handler(i, &systemasic_int, + handle_level_irq); + } +} diff --git a/arch/sh/boards/mach-dreamcast/setup.c b/arch/sh/boards/mach-dreamcast/setup.c index a4b7402d6176..ad1a4db72e04 100644 --- a/arch/sh/boards/mach-dreamcast/setup.c +++ b/arch/sh/boards/mach-dreamcast/setup.c @@ -28,25 +28,8 @@ #include #include -extern struct irq_chip systemasic_int; -extern void aica_time_init(void); -extern int systemasic_irq_demux(int); - static void __init dreamcast_setup(char **cmdline_p) { - int i; - - /* Mask all hardware events */ - /* XXX */ - - /* Acknowledge any previous events */ - /* XXX */ - - /* Assign all virtual IRQs to the System ASIC int. handler */ - for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) - set_irq_chip_and_handler(i, &systemasic_int, - handle_level_irq); - board_time_init = aica_time_init; } @@ -54,4 +37,5 @@ static struct sh_machine_vector mv_dreamcast __initmv = { .mv_name = "Sega Dreamcast", .mv_setup = dreamcast_setup, .mv_irq_demux = systemasic_irq_demux, + .mv_init_irq = systemasic_irq_init, }; diff --git a/arch/sh/include/mach-dreamcast/mach/sysasic.h b/arch/sh/include/mach-dreamcast/mach/sysasic.h index f33426608a87..58f710e1ebc2 100644 --- a/arch/sh/include/mach-dreamcast/mach/sysasic.h +++ b/arch/sh/include/mach-dreamcast/mach/sysasic.h @@ -39,5 +39,10 @@ #define HW_EVENT_IRQ_MAX (HW_EVENT_IRQ_BASE + 95) +/* arch/sh/boards/mach-dreamcast/irq.c */ +extern int systemasic_irq_demux(int); +extern void systemasic_irq_init(void); +extern void aica_time_init(void); + #endif /* __ASM_SH_DREAMCAST_SYSASIC_H */ -- GitLab From 4b842c8571240d1173eaf00e114cc5cc160f1722 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 19:15:17 +0900 Subject: [PATCH 1464/3892] sh: enable sparseirq for highlander and r2d. highlander and r2d are the only remaining ones that were blocking sparseirq being turned on by default, but it turns out that they already work fine with it by virtue of register_intc_controller(). As such, we can kill off the dependencies and turn it on by default. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 3b3c036cbc30..7354e8da3902 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -87,6 +87,10 @@ config GENERIC_IRQ_PROBE config IRQ_PER_CPU def_bool y +config SPARSE_IRQ + def_bool y + depends on SUPERH32 + config GENERIC_GPIO def_bool n @@ -728,18 +732,6 @@ config GUSA_RB LLSC, this should be more efficient than the other alternative of disabling interrupts around the atomic sequence. -config SPARSE_IRQ - def_bool y - depends on SUPERH32 && !SH_HIGHLANDER && !SH_RTS7751R2D - help - This enables support for sparse irqs. This is useful in general - as most CPUs have a fairly sparse array of IRQ vectors, which - the irq_desc then maps directly on to. Systems with a high - number of off-chip IRQs will want to treat this as - experimental until they have been independently verified. - - If you don't know what to do here, say N. - endmenu menu "Boot options" -- GitLab From 37feecb0ae8c29b713b957c053b05ad10c42c73b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 2 Feb 2010 19:17:42 +0900 Subject: [PATCH 1465/3892] sh: Disable generic IRQ probing. IRQ autoprobing hasn't actually worked for us at all since very early in 2.6, but no one seems to have noticed given that none of the drivers that use it see much testing. yenta_socket is the odd one out, and that depends on PCI IRQs which are fixed on all SH platforms anyways. Consequently, turning off autoprobing fixes up crashes triggered by yenta_socket and at least gets it working again on r7785rp. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 7354e8da3902..05cef5061293 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -81,9 +81,6 @@ config GENERIC_HARDIRQS config GENERIC_HARDIRQS_NO__DO_IRQ def_bool y -config GENERIC_IRQ_PROBE - def_bool y - config IRQ_PER_CPU def_bool y -- GitLab From fead215d1c0a385fc27a1fa96b7abbc4d66fb4c6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Feb 2010 10:06:55 +0000 Subject: [PATCH 1466/3892] ASoC: Fix WM8994 dependency The dependency on MFD_WM8994 rather than I2C went awry. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6b8a10120f9c..5ab59219a8de 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -61,7 +61,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C select SND_SOC_WM8993 if I2C - select SND_SOC_WM8994 if I2C + select SND_SOC_WM8994 if MFD_WM8994 select SND_SOC_WM9081 if I2C select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS -- GitLab From 07cd8ada1aba5556b0d5d2264ce0f40d1ff1d131 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 2 Feb 2010 18:53:19 +0900 Subject: [PATCH 1467/3892] ASoC: Fix BCLK calculation of WM8994 This fixes BCLK calculation and removes unnecessary check code. Signed-off-by: Joonyoung Shim Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 5dd4b299f69e..29f3771c33a4 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3267,15 +3267,12 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, */ best = 0; for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { - if (bclk_divs[i] < 0) - continue; - cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - - bclk_rate * 10; + cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; if (cur_val < 0) /* BCLK table is sorted */ break; best = i; } - bclk_rate = wm8994->aifclk[id] / bclk_divs[best]; + bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best]; dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", bclk_divs[best], bclk_rate); bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; -- GitLab From 59cdd9bc057a54384a7838231dd2672a89dff2ac Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 1 Feb 2010 23:22:16 -0800 Subject: [PATCH 1468/3892] ASoC: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c-pcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c index 9e61a7c2d9ac..a98f40c3cd29 100644 --- a/sound/soc/s3c24xx/s3c-pcm.c +++ b/sound/soc/s3c24xx/s3c-pcm.c @@ -229,8 +229,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, spin_unlock_irqrestore(&pcm->lock, flags); - dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \ - SCLK_DIV=%d SYNC_DIV=%d\n", + dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n", clk_get_rate(clk), pcm->sclk_per_fs, sclk_div, sync_div); -- GitLab From 026384d614b827f368834860c9b623ce08439b7e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 2 Feb 2010 18:45:27 +0800 Subject: [PATCH 1469/3892] ASoC: fix PXA SSP port resume Unconditionally save the register states when suspending and restore them again at resume time. Register contents were not preserved over suspend, and hence the driver takes false assumptions about them. The clock must be enabled to access the register block. Signed-off-by: Daniel Mack Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 3bd7712f029b..e69397f40f72 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -135,10 +135,11 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) struct ssp_priv *priv = cpu_dai->private_data; if (!cpu_dai->active) - return 0; + clk_enable(priv->dev.ssp->clk); ssp_save_state(&priv->dev, &priv->state); clk_disable(priv->dev.ssp->clk); + return 0; } @@ -146,12 +147,13 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; - if (!cpu_dai->active) - return 0; - clk_enable(priv->dev.ssp->clk); ssp_restore_state(&priv->dev, &priv->state); - ssp_enable(&priv->dev); + + if (cpu_dai->active) + ssp_enable(&priv->dev); + else + clk_disable(priv->dev.ssp->clk); return 0; } -- GitLab From c30f540b63047437ffa894b5353216410c480d1a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 2 Feb 2010 15:03:24 +0100 Subject: [PATCH 1470/3892] netfilter: xtables: CONFIG_COMPAT redux Ifdef out struct nf_sockopt_ops::compat_set struct nf_sockopt_ops::compat_get struct xt_match::compat_from_user struct xt_match::compat_to_user struct xt_match::compatsize to make structures smaller on COMPAT=n kernels. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 9 ++++++--- include/linux/netfilter/x_tables.h | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 48c54960773c..78f33d223680 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -114,15 +114,17 @@ struct nf_sockopt_ops { int set_optmin; int set_optmax; int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len); +#ifdef CONFIG_COMPAT int (*compat_set)(struct sock *sk, int optval, void __user *user, unsigned int len); - +#endif int get_optmin; int get_optmax; int (*get)(struct sock *sk, int optval, void __user *user, int *len); +#ifdef CONFIG_COMPAT int (*compat_get)(struct sock *sk, int optval, void __user *user, int *len); - +#endif /* Use the module struct to lock set/get code in place */ struct module *owner; }; @@ -222,11 +224,12 @@ int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, unsigned int len); int nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, int *len); - +#ifdef CONFIG_COMPAT int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, unsigned int len); int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, int *len); +#endif /* Call this before modifying an existing packet: ensures it is modifiable and linear to the point you care about (writable_len). diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 3caf5e151102..026eb78ee83c 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -283,11 +283,11 @@ struct xt_match { /* Called when entry of this type deleted. */ void (*destroy)(const struct xt_mtdtor_param *); - +#ifdef CONFIG_COMPAT /* Called when userspace align differs from kernel space one */ void (*compat_from_user)(void *dst, void *src); int (*compat_to_user)(void __user *dst, void *src); - +#endif /* Set this to THIS_MODULE if you are a module, otherwise NULL */ struct module *me; @@ -296,7 +296,9 @@ struct xt_match { const char *table; unsigned int matchsize; +#ifdef CONFIG_COMPAT unsigned int compatsize; +#endif unsigned int hooks; unsigned short proto; @@ -323,17 +325,19 @@ struct xt_target { /* Called when entry of this type deleted. */ void (*destroy)(const struct xt_tgdtor_param *); - +#ifdef CONFIG_COMPAT /* Called when userspace align differs from kernel space one */ void (*compat_from_user)(void *dst, void *src); int (*compat_to_user)(void __user *dst, void *src); - +#endif /* Set this to THIS_MODULE if you are a module, otherwise NULL */ struct module *me; const char *table; unsigned int targetsize; +#ifdef CONFIG_COMPAT unsigned int compatsize; +#endif unsigned int hooks; unsigned short proto; -- GitLab From 10a199394b8f9b4c4e0be6e14a61109a7d891b1b Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Tue, 2 Feb 2010 15:33:38 +0100 Subject: [PATCH 1471/3892] netfilter: xt_TCPMSS: SYN packets are allowed to contain data The TCPMSS target is dropping SYN packets where: 1) There is data, or 2) The data offset makes the TCP header larger than the packet. Both of these result in an error level printk. This printk has been removed. This change avoids dropping SYN packets containing data. If there is also no MSS option (as well as data), one will not be added because of possible complications due to the increased packet size. Signed-off-by: Simon Arlott Signed-off-by: Patrick McHardy --- net/netfilter/xt_TCPMSS.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index eda64c1cb1e5..6f21b4377dbb 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -60,17 +60,9 @@ tcpmss_mangle_packet(struct sk_buff *skb, tcplen = skb->len - tcphoff; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); - /* Since it passed flags test in tcp match, we know it is is - not a fragment, and has data >= tcp header length. SYN - packets should not contain data: if they did, then we risk - running over MTU, sending Frag Needed and breaking things - badly. --RR */ - if (tcplen != tcph->doff*4) { - if (net_ratelimit()) - printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n", - skb->len); + /* Header cannot be larger than the packet */ + if (tcplen < tcph->doff*4) return -1; - } if (info->mss == XT_TCPMSS_CLAMP_PMTU) { if (dst_mtu(skb_dst(skb)) <= minlen) { @@ -115,6 +107,12 @@ tcpmss_mangle_packet(struct sk_buff *skb, } } + /* There is data after the header so the option can't be added + without moving it, and doing so may make the SYN packet + itself too large. Accept the packet unmodified instead. */ + if (tcplen > tcph->doff*4) + return 0; + /* * MSS Option not found ?! add it.. */ -- GitLab From 8b64056dacf6ec81986d63dff96fca039fe95f6e Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 2 Feb 2010 07:21:34 -0800 Subject: [PATCH 1472/3892] can: deny filterlist access on non-CAN interfaces In commit 20dd3850bcf860561496827b711fa10fecf6e787 "can: Speed up CAN frame receiption by using ml_priv" the formerly used hlist of receiver lists for each CAN netdevice has been replaced. The hlist content ensured only CAN netdevices to be accessed by the can_rx_(un)register() functions which accidently dropped away together with the hlist receiver implementation. This patch re-introduces the check for CAN netdevices in can_rx_(un)register(). Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/can/af_can.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/can/af_can.c b/net/can/af_can.c index bc18b084ffdb..702be5a2c956 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -415,6 +415,9 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, /* insert new receiver (dev,canid,mask) -> (func,data) */ + if (dev && dev->type != ARPHRD_CAN) + return -ENODEV; + r = kmem_cache_alloc(rcv_cache, GFP_KERNEL); if (!r) return -ENOMEM; @@ -478,6 +481,9 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, struct hlist_node *next; struct dev_rcv_lists *d; + if (dev && dev->type != ARPHRD_CAN) + return; + spin_lock(&can_rcvlists_lock); d = find_dev_rcv_lists(dev); -- GitLab From c85bb41e93184bf5494dde6d8fe5a81b564c84c8 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Tue, 2 Feb 2010 07:32:29 -0800 Subject: [PATCH 1473/3892] igmp: fix ip_mc_sf_allow race [v5] Almost all igmp functions accessing inet->mc_list are protected by rtnl_lock(), but there is one exception which is ip_mc_sf_allow(), so there is a chance of either ip_mc_drop_socket or ip_mc_leave_group remove an entry while ip_mc_sf_allow is running causing a crash. Signed-off-by: Flavio Leitner Signed-off-by: David S. Miller --- include/linux/igmp.h | 2 ++ net/ipv4/igmp.c | 83 +++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 724c27e5d173..93fc2449af10 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -153,6 +153,7 @@ extern int sysctl_igmp_max_msf; struct ip_sf_socklist { unsigned int sl_max; unsigned int sl_count; + struct rcu_head rcu; __be32 sl_addr[0]; }; @@ -170,6 +171,7 @@ struct ip_mc_socklist { struct ip_mreqn multi; unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ struct ip_sf_socklist *sflist; + struct rcu_head rcu; }; struct ip_sf_list { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 8f5468393f01..d28363998743 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1799,7 +1799,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) iml->next = inet->mc_list; iml->sflist = NULL; iml->sfmode = MCAST_EXCLUDE; - inet->mc_list = iml; + rcu_assign_pointer(inet->mc_list, iml); ip_mc_inc_group(in_dev, addr); err = 0; done: @@ -1807,24 +1807,46 @@ done: return err; } +static void ip_sf_socklist_reclaim(struct rcu_head *rp) +{ + struct ip_sf_socklist *psf; + + psf = container_of(rp, struct ip_sf_socklist, rcu); + /* sk_omem_alloc should have been decreased by the caller*/ + kfree(psf); +} + static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, struct in_device *in_dev) { + struct ip_sf_socklist *psf = iml->sflist; int err; - if (iml->sflist == NULL) { + if (psf == NULL) { /* any-source empty exclude case */ return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, iml->sfmode, 0, NULL, 0); } err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, - iml->sfmode, iml->sflist->sl_count, - iml->sflist->sl_addr, 0); - sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max)); - iml->sflist = NULL; + iml->sfmode, psf->sl_count, psf->sl_addr, 0); + rcu_assign_pointer(iml->sflist, NULL); + /* decrease mem now to avoid the memleak warning */ + atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); + call_rcu(&psf->rcu, ip_sf_socklist_reclaim); return err; } + +static void ip_mc_socklist_reclaim(struct rcu_head *rp) +{ + struct ip_mc_socklist *iml; + + iml = container_of(rp, struct ip_mc_socklist, rcu); + /* sk_omem_alloc should have been decreased by the caller*/ + kfree(iml); +} + + /* * Ask a socket to leave a group. */ @@ -1854,12 +1876,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) (void) ip_mc_leave_src(sk, iml, in_dev); - *imlp = iml->next; + rcu_assign_pointer(*imlp, iml->next); if (in_dev) ip_mc_dec_group(in_dev, group); rtnl_unlock(); - sock_kfree_s(sk, iml, sizeof(*iml)); + /* decrease mem now to avoid the memleak warning */ + atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); + call_rcu(&iml->rcu, ip_mc_socklist_reclaim); return 0; } if (!in_dev) @@ -1974,9 +1998,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (psl) { for (i=0; isl_count; i++) newpsl->sl_addr[i] = psl->sl_addr[i]; - sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); + /* decrease mem now to avoid the memleak warning */ + atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + call_rcu(&psl->rcu, ip_sf_socklist_reclaim); } - pmc->sflist = psl = newpsl; + rcu_assign_pointer(pmc->sflist, newpsl); + psl = newpsl; } rv = 1; /* > 0 for insert logic below if sl_count is 0 */ for (i=0; isl_count; i++) { @@ -2072,11 +2099,13 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) if (psl) { (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, psl->sl_count, psl->sl_addr, 0); - sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); + /* decrease mem now to avoid the memleak warning */ + atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + call_rcu(&psl->rcu, ip_sf_socklist_reclaim); } else (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 0, NULL, 0); - pmc->sflist = newpsl; + rcu_assign_pointer(pmc->sflist, newpsl); pmc->sfmode = msf->imsf_fmode; err = 0; done: @@ -2209,30 +2238,40 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) struct ip_mc_socklist *pmc; struct ip_sf_socklist *psl; int i; + int ret; + ret = 1; if (!ipv4_is_multicast(loc_addr)) - return 1; + goto out; - for (pmc=inet->mc_list; pmc; pmc=pmc->next) { + rcu_read_lock(); + for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) { if (pmc->multi.imr_multiaddr.s_addr == loc_addr && pmc->multi.imr_ifindex == dif) break; } + ret = inet->mc_all; if (!pmc) - return inet->mc_all; + goto unlock; psl = pmc->sflist; + ret = (pmc->sfmode == MCAST_EXCLUDE); if (!psl) - return pmc->sfmode == MCAST_EXCLUDE; + goto unlock; for (i=0; isl_count; i++) { if (psl->sl_addr[i] == rmt_addr) break; } + ret = 0; if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) - return 0; + goto unlock; if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) - return 0; - return 1; + goto unlock; + ret = 1; +unlock: + rcu_read_unlock(); +out: + return ret; } /* @@ -2251,7 +2290,7 @@ void ip_mc_drop_socket(struct sock *sk) rtnl_lock(); while ((iml = inet->mc_list) != NULL) { struct in_device *in_dev; - inet->mc_list = iml->next; + rcu_assign_pointer(inet->mc_list, iml->next); in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); (void) ip_mc_leave_src(sk, iml, in_dev); @@ -2259,7 +2298,9 @@ void ip_mc_drop_socket(struct sock *sk) ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); in_dev_put(in_dev); } - sock_kfree_s(sk, iml, sizeof(*iml)); + /* decrease mem now to avoid the memleak warning */ + atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); + call_rcu(&iml->rcu, ip_mc_socklist_reclaim); } rtnl_unlock(); } -- GitLab From 2a6ace1b3d4dc65401e71fc01af100692b9f27f8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 2 Feb 2010 07:47:56 -0800 Subject: [PATCH 1474/3892] net/irda: sh_sir: Add SuperH IrDA driver This is very simple IrDA SIR driver for SuperH. This driver was tested by irdaping/ircp on SH7724 EcoVec24 board Signed-off-by: Kuninori Morimoto Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 10 + drivers/net/irda/Makefile | 1 + drivers/net/irda/sh_sir.c | 823 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 834 insertions(+) create mode 100644 drivers/net/irda/sh_sir.c diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index f76384221422..af10e97345ce 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -64,6 +64,16 @@ endchoice comment "Dongle support" +config SH_SIR + tristate "SuperH SIR on UART" + depends on IRDA && SUPERH && \ + (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \ + CPU_SUBTYPE_SH7724) + default n + help + Say Y here if your want to enable SIR function on SuperH UART + devices. + config DONGLE bool "Serial dongle support" depends on IRTTY_SIR diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index d82e1e3bd8c8..e030d47e2793 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_AU1000_FIR) += au1k_ir.o # SIR drivers obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o obj-$(CONFIG_BFIN_SIR) += bfin_sir.o +obj-$(CONFIG_SH_SIR) += sh_sir.o # dongle drivers for SIR drivers obj-$(CONFIG_ESI_DONGLE) += esi-sir.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c new file mode 100644 index 000000000000..d7c983dc91ad --- /dev/null +++ b/drivers/net/irda/sh_sir.c @@ -0,0 +1,823 @@ +/* + * SuperH IrDA Driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on bfin_sir.c + * Copyright 2006-2009 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sh_sir" + +#define RX_PHASE (1 << 0) +#define TX_PHASE (1 << 1) +#define TX_COMP_PHASE (1 << 2) /* tx complete */ +#define NONE_PHASE (1 << 31) + +#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */ +#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */ +#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */ +#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */ +#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */ +#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */ +#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */ +#define IRIF_SIR_EOF 0x002A /* EOF value */ +#define IRIF_SIR_FLG 0x002C /* Flag clear */ +#define IRIF_UART_STS2 0x002E /* UART status 2 */ +#define IRIF_UART0 0x0030 /* UART control */ +#define IRIF_UART1 0x0032 /* UART status */ +#define IRIF_UART2 0x0034 /* UART mode */ +#define IRIF_UART3 0x0036 /* UART transmit data */ +#define IRIF_UART4 0x0038 /* UART receive data */ +#define IRIF_UART5 0x003A /* UART interrupt mask */ +#define IRIF_UART6 0x003C /* UART baud rate error correction */ +#define IRIF_UART7 0x003E /* UART baud rate count set */ +#define IRIF_CRC0 0x0040 /* CRC engine control */ +#define IRIF_CRC1 0x0042 /* CRC engine input data */ +#define IRIF_CRC2 0x0044 /* CRC engine calculation */ +#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */ +#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */ + +/* IRIF_SIR0 */ +#define IRTPW (1 << 1) /* transmit pulse width select */ +#define IRERRC (1 << 0) /* Clear receive pulse width error */ + +/* IRIF_SIR3 */ +#define IRERR (1 << 0) /* received pulse width Error */ + +/* IRIF_SIR_FRM */ +#define EOFD (1 << 9) /* EOF detection flag */ +#define FRER (1 << 8) /* Frame Error bit */ +#define FRP (1 << 0) /* Frame processing set */ + +/* IRIF_UART_STS2 */ +#define IRSME (1 << 6) /* Receive Sum Error flag */ +#define IROVE (1 << 5) /* Receive Overrun Error flag */ +#define IRFRE (1 << 4) /* Receive Framing Error flag */ +#define IRPRE (1 << 3) /* Receive Parity Error flag */ + +/* IRIF_UART0_*/ +#define TBEC (1 << 2) /* Transmit Data Clear */ +#define RIE (1 << 1) /* Receive Enable */ +#define TIE (1 << 0) /* Transmit Enable */ + +/* IRIF_UART1 */ +#define URSME (1 << 6) /* Receive Sum Error Flag */ +#define UROVE (1 << 5) /* Receive Overrun Error Flag */ +#define URFRE (1 << 4) /* Receive Framing Error Flag */ +#define URPRE (1 << 3) /* Receive Parity Error Flag */ +#define RBF (1 << 2) /* Receive Buffer Full Flag */ +#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */ +#define TBE (1 << 0) /* Transmit Buffer Empty flag */ +#define TBCOMP (TSBE | TBE) + +/* IRIF_UART5 */ +#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */ +#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */ +#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */ +#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */ +#define RX_MASK (RSEIM | RBFIM) + +/* IRIF_CRC0 */ +#define CRC_RST (1 << 15) /* CRC Engine Reset */ +#define CRC_CT_MASK 0x0FFF + +/************************************************************************ + + + structure + + +************************************************************************/ +struct sh_sir_self { + void __iomem *membase; + unsigned int irq; + struct clk *clk; + + struct net_device *ndev; + + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; +}; + +/************************************************************************ + + + common function + + +************************************************************************/ +static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data) +{ + iowrite16(data, self->membase + offset); +} + +static u16 sh_sir_read(struct sh_sir_self *self, u32 offset) +{ + return ioread16(self->membase + offset); +} + +static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset, + u16 mask, u16 data) +{ + u16 old, new; + + old = sh_sir_read(self, offset); + new = (old & ~mask) | data; + if (old != new) + sh_sir_write(self, offset, new); +} + +/************************************************************************ + + + CRC function + + +************************************************************************/ +static void sh_sir_crc_reset(struct sh_sir_self *self) +{ + sh_sir_write(self, IRIF_CRC0, CRC_RST); +} + +static void sh_sir_crc_add(struct sh_sir_self *self, u8 data) +{ + sh_sir_write(self, IRIF_CRC1, (u16)data); +} + +static u16 sh_sir_crc_cnt(struct sh_sir_self *self) +{ + return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0); +} + +static u16 sh_sir_crc_out(struct sh_sir_self *self) +{ + return sh_sir_read(self, IRIF_CRC4); +} + +static int sh_sir_crc_init(struct sh_sir_self *self) +{ + struct device *dev = &self->ndev->dev; + int ret = -EIO; + u16 val; + + sh_sir_crc_reset(self); + + sh_sir_crc_add(self, 0xCC); + sh_sir_crc_add(self, 0xF5); + sh_sir_crc_add(self, 0xF1); + sh_sir_crc_add(self, 0xA7); + + val = sh_sir_crc_cnt(self); + if (4 != val) { + dev_err(dev, "CRC count error %x\n", val); + goto crc_init_out; + } + + val = sh_sir_crc_out(self); + if (0x51DF != val) { + dev_err(dev, "CRC result error%x\n", val); + goto crc_init_out; + } + + ret = 0; + +crc_init_out: + + sh_sir_crc_reset(self); + return ret; +} + +/************************************************************************ + + + baud rate functions + + +************************************************************************/ +#define SCLK_BASE 1843200 /* 1.8432MHz */ + +static u32 sh_sir_find_sclk(struct clk *irda_clk) +{ + struct cpufreq_frequency_table *freq_table = irda_clk->freq_table; + struct clk *pclk = clk_get(NULL, "peripheral_clk"); + u32 limit, min = 0xffffffff, tmp; + int i, index = 0; + + limit = clk_get_rate(pclk); + clk_put(pclk); + + /* IrDA can not set over peripheral_clk */ + for (i = 0; + freq_table[i].frequency != CPUFREQ_TABLE_END; + i++) { + u32 freq = freq_table[i].frequency; + + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + + /* IrDA should not over peripheral_clk */ + if (freq > limit) + continue; + + tmp = freq % SCLK_BASE; + if (tmp < min) { + min = tmp; + index = i; + } + } + + return freq_table[index].frequency; +} + +#define ERR_ROUNDING(a) ((a + 5000) / 10000) +static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) +{ + struct clk *clk; + struct device *dev = &self->ndev->dev; + u32 rate; + u16 uabca, uabc; + u16 irbca, irbc; + u32 min, rerr, tmp; + int i; + + /* Baud Rate Error Correction x 10000 */ + u32 rate_err_array[] = { + 0000, 0625, 1250, 1875, + 2500, 3125, 3750, 4375, + 5000, 5625, 6250, 6875, + 7500, 8125, 8750, 9375, + }; + + /* + * FIXME + * + * it support 9600 only now + */ + switch (baudrate) { + case 9600: + break; + default: + dev_err(dev, "un-supported baudrate %d\n", baudrate); + return -EIO; + } + + clk = clk_get(NULL, "irda_clk"); + if (!clk) { + dev_err(dev, "can not get irda_clk\n"); + return -EIO; + } + + clk_set_rate(clk, sh_sir_find_sclk(clk)); + rate = clk_get_rate(clk); + clk_put(clk); + + dev_dbg(dev, "selected sclk = %d\n", rate); + + /* + * CALCULATION + * + * 1843200 = system rate / (irbca + (irbc + 1)) + */ + + irbc = rate / SCLK_BASE; + + tmp = rate - (SCLK_BASE * irbc); + tmp *= 10000; + + rerr = tmp / SCLK_BASE; + + min = 0xffffffff; + irbca = 0; + for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { + tmp = abs(rate_err_array[i] - rerr); + if (min > tmp) { + min = tmp; + irbca = i; + } + } + + tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca])); + if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE)) + dev_warn(dev, "IrDA freq error margin over %d\n", tmp); + + dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n", + SCLK_BASE, tmp, irbc, rate_err_array[irbca]); + + irbca = (irbca & 0xF) << 4; + irbc = (irbc - 1) & 0xF; + + if (!irbc) { + dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n"); + return -EIO; + } + + sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC); + sh_sir_write(self, IRIF_SIR1, irbca); + sh_sir_write(self, IRIF_SIR2, irbc); + + /* + * CALCULATION + * + * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16) + */ + + uabc = rate / baudrate; + uabc = (uabc / 16) - 1; + uabc = (uabc + 1) * 16; + + tmp = rate - (uabc * baudrate); + tmp *= 10000; + + rerr = tmp / baudrate; + + min = 0xffffffff; + uabca = 0; + for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { + tmp = abs(rate_err_array[i] - rerr); + if (min > tmp) { + min = tmp; + uabca = i; + } + } + + tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca])); + if ((baudrate / 100) < abs(tmp - baudrate)) + dev_warn(dev, "UART freq error margin over %d\n", tmp); + + dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n", + baudrate, tmp, + uabc, rate_err_array[uabca]); + + uabca = (uabca & 0xF) << 4; + uabc = (uabc / 16) - 1; + + sh_sir_write(self, IRIF_UART6, uabca); + sh_sir_write(self, IRIF_UART7, uabc); + + return 0; +} + +/************************************************************************ + + + iobuf function + + +************************************************************************/ +static int __sh_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + + return 0; +} + +static void sh_sir_remove_iobuf(struct sh_sir_self *self) +{ + kfree(self->rx_buff.head); + kfree(self->tx_buff.head); + + self->rx_buff.head = NULL; + self->tx_buff.head = NULL; +} + +static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize) +{ + int err = -ENOMEM; + + if (self->rx_buff.head || + self->tx_buff.head) { + dev_err(&self->ndev->dev, "iobuff has already existed."); + return err; + } + + err = __sh_sir_init_iobuf(&self->rx_buff, rxsize); + if (err) + goto iobuf_err; + + err = __sh_sir_init_iobuf(&self->tx_buff, txsize); + +iobuf_err: + if (err) + sh_sir_remove_iobuf(self); + + return err; +} + +/************************************************************************ + + + status function + + +************************************************************************/ +static void sh_sir_clear_all_err(struct sh_sir_self *self) +{ + /* Clear error flag for receive pulse width */ + sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC); + + /* Clear frame / EOF error flag */ + sh_sir_write(self, IRIF_SIR_FLG, 0xffff); + + /* Clear all status error */ + sh_sir_write(self, IRIF_UART_STS2, 0); +} + +static void sh_sir_set_phase(struct sh_sir_self *self, int phase) +{ + u16 uart5 = 0; + u16 uart0 = 0; + + switch (phase) { + case TX_PHASE: + uart5 = TBEIM; + uart0 = TBEC | TIE; + break; + case TX_COMP_PHASE: + uart5 = TSBEIM; + uart0 = TIE; + break; + case RX_PHASE: + uart5 = RX_MASK; + uart0 = RIE; + break; + default: + break; + } + + sh_sir_write(self, IRIF_UART5, uart5); + sh_sir_write(self, IRIF_UART0, uart0); +} + +static int sh_sir_is_which_phase(struct sh_sir_self *self) +{ + u16 val = sh_sir_read(self, IRIF_UART5); + + if (val & TBEIM) + return TX_PHASE; + + if (val & TSBEIM) + return TX_COMP_PHASE; + + if (val & RX_MASK) + return RX_PHASE; + + return NONE_PHASE; +} + +static void sh_sir_tx(struct sh_sir_self *self, int phase) +{ + switch (phase) { + case TX_PHASE: + if (0 >= self->tx_buff.len) { + sh_sir_set_phase(self, TX_COMP_PHASE); + } else { + sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]); + self->tx_buff.len--; + self->tx_buff.data++; + } + break; + case TX_COMP_PHASE: + sh_sir_set_phase(self, RX_PHASE); + netif_wake_queue(self->ndev); + break; + default: + dev_err(&self->ndev->dev, "should not happen\n"); + break; + } +} + +static int sh_sir_read_data(struct sh_sir_self *self) +{ + u16 val; + int timeout = 1024; + + while (timeout--) { + val = sh_sir_read(self, IRIF_UART1); + + /* data get */ + if (val & RBF) { + if (val & (URSME | UROVE | URFRE | URPRE)) + break; + + return (int)sh_sir_read(self, IRIF_UART4); + } + + udelay(1); + } + + dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n", + val, sh_sir_read(self, IRIF_UART_STS2)); + + /* read data register for clear error */ + sh_sir_read(self, IRIF_UART4); + + return -1; +} + +static void sh_sir_rx(struct sh_sir_self *self) +{ + int timeout = 1024; + int data; + + while (timeout--) { + data = sh_sir_read_data(self); + if (data < 0) + break; + + async_unwrap_char(self->ndev, &self->ndev->stats, + &self->rx_buff, (u8)data); + self->ndev->last_rx = jiffies; + + if (EOFD & sh_sir_read(self, IRIF_SIR_FRM)) + continue; + + break; + } +} + +static irqreturn_t sh_sir_irq(int irq, void *dev_id) +{ + struct sh_sir_self *self = dev_id; + struct device *dev = &self->ndev->dev; + int phase = sh_sir_is_which_phase(self); + + switch (phase) { + case TX_COMP_PHASE: + case TX_PHASE: + sh_sir_tx(self, phase); + break; + case RX_PHASE: + if (sh_sir_read(self, IRIF_SIR3)) + dev_err(dev, "rcv pulse width error occurred\n"); + + sh_sir_rx(self); + sh_sir_clear_all_err(self); + break; + default: + dev_err(dev, "unknown interrupt\n"); + } + + return IRQ_HANDLED; +} + +/************************************************************************ + + + net_device_ops function + + +************************************************************************/ +static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + int speed = irda_get_next_speed(skb); + + if ((0 < speed) && + (9600 != speed)) { + dev_err(&ndev->dev, "support 9600 only (%d)\n", speed); + return -EIO; + } + + netif_stop_queue(ndev); + + self->tx_buff.data = self->tx_buff.head; + self->tx_buff.len = 0; + if (skb->len) + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + sh_sir_set_phase(self, TX_PHASE); + dev_kfree_skb(skb); + + return 0; +} + +static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd) +{ + /* + * FIXME + * + * This function is needed for irda framework. + * But nothing to do now + */ + return 0; +} + +static struct net_device_stats *sh_sir_stats(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + + return &self->ndev->stats; +} + +static int sh_sir_open(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + int err; + + clk_enable(self->clk); + err = sh_sir_crc_init(self); + if (err) + goto open_err; + + sh_sir_set_baudrate(self, 9600); + + self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME); + if (!self->irlap) + goto open_err; + + /* + * Now enable the interrupt then start the queue + */ + sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP); + sh_sir_read(self, IRIF_UART1); /* flag clear */ + sh_sir_read(self, IRIF_UART4); /* flag clear */ + sh_sir_set_phase(self, RX_PHASE); + + netif_start_queue(ndev); + + dev_info(&self->ndev->dev, "opened\n"); + + return 0; + +open_err: + clk_disable(self->clk); + + return err; +} + +static int sh_sir_stop(struct net_device *ndev) +{ + struct sh_sir_self *self = netdev_priv(ndev); + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(ndev); + + dev_info(&ndev->dev, "stoped\n"); + + return 0; +} + +static const struct net_device_ops sh_sir_ndo = { + .ndo_open = sh_sir_open, + .ndo_stop = sh_sir_stop, + .ndo_start_xmit = sh_sir_hard_xmit, + .ndo_do_ioctl = sh_sir_ioctl, + .ndo_get_stats = sh_sir_stats, +}; + +/************************************************************************ + + + platform_driver function + + +************************************************************************/ +static int __devinit sh_sir_probe(struct platform_device *pdev) +{ + struct net_device *ndev; + struct sh_sir_self *self; + struct resource *res; + char clk_name[8]; + void __iomem *base; + unsigned int irq; + int err = -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || irq < 0) { + dev_err(&pdev->dev, "Not enough platform resources.\n"); + goto exit; + } + + ndev = alloc_irdadev(sizeof(*self)); + if (!ndev) + goto exit; + + base = ioremap_nocache(res->start, resource_size(res)); + if (!base) { + err = -ENXIO; + dev_err(&pdev->dev, "Unable to ioremap.\n"); + goto err_mem_1; + } + + self = netdev_priv(ndev); + err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_2; + + snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id); + self->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(self->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + goto err_mem_3; + } + + irda_init_max_qos_capabilies(&self->qos); + + ndev->netdev_ops = &sh_sir_ndo; + ndev->irq = irq; + + self->membase = base; + self->ndev = ndev; + self->qos.baud_rate.bits &= IR_9600; /* FIXME */ + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(ndev); + if (err) + goto err_mem_4; + + platform_set_drvdata(pdev, ndev); + + if (request_irq(irq, sh_sir_irq, IRQF_DISABLED, "sh_sir", self)) { + dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n"); + goto err_mem_4; + } + + dev_info(&pdev->dev, "SuperH IrDA probed\n"); + + goto exit; + +err_mem_4: + clk_put(self->clk); +err_mem_3: + sh_sir_remove_iobuf(self); +err_mem_2: + iounmap(self->membase); +err_mem_1: + free_netdev(ndev); +exit: + return err; +} + +static int __devexit sh_sir_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct sh_sir_self *self = netdev_priv(ndev); + + if (!self) + return 0; + + unregister_netdev(ndev); + clk_put(self->clk); + sh_sir_remove_iobuf(self); + iounmap(self->membase); + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver sh_sir_driver = { + .probe = sh_sir_probe, + .remove = __devexit_p(sh_sir_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init sh_sir_init(void) +{ + return platform_driver_register(&sh_sir_driver); +} + +static void __exit sh_sir_exit(void) +{ + platform_driver_unregister(&sh_sir_driver); +} + +module_init(sh_sir_init); +module_exit(sh_sir_exit); + +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_DESCRIPTION("SuperH IrDA driver"); +MODULE_LICENSE("GPL"); -- GitLab From d5e1ca05f758fec2845a97fd7aa1eeca91c51a21 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 2 Feb 2010 17:48:51 +0100 Subject: [PATCH 1475/3892] ALSA: dummy driver - add model parameter This is a cleanup for the dummy driver. The model kernel module parameter is introduced to select the soundcard emulation. Signed-off-by: Jaroslav Kysela --- sound/drivers/dummy.c | 290 ++++++++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 110 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 252e04ce602f..7f41990ed68b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); #define MAX_PCM_SUBSTREAMS 128 #define MAX_MIDI_DEVICES 2 -#if 0 /* emu10k1 emulation */ -#define MAX_BUFFER_SIZE (128 * 1024) -static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) -{ - int err; - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - return err; - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); - if (err < 0) - return err; - return 0; -} -#define add_playback_constraints emu10k1_playback_constraints -#endif - -#if 0 /* RME9652 emulation */ -#define MAX_BUFFER_SIZE (26 * 64 * 1024) -#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE -#define USE_CHANNELS_MIN 26 -#define USE_CHANNELS_MAX 26 -#define USE_PERIODS_MIN 2 -#define USE_PERIODS_MAX 2 -#endif - -#if 0 /* ICE1712 emulation */ -#define MAX_BUFFER_SIZE (256 * 1024) -#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE -#define USE_CHANNELS_MIN 10 -#define USE_CHANNELS_MAX 10 -#define USE_PERIODS_MIN 1 -#define USE_PERIODS_MAX 1024 -#endif - -#if 0 /* UDA1341 emulation */ -#define MAX_BUFFER_SIZE (16380) -#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE -#define USE_CHANNELS_MIN 2 -#define USE_CHANNELS_MAX 2 -#define USE_PERIODS_MIN 2 -#define USE_PERIODS_MAX 255 -#endif - -#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ -#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE -#define USE_CHANNELS_MIN 2 -#define USE_CHANNELS_MAX 2 -#define USE_RATE SNDRV_PCM_RATE_48000 -#define USE_RATE_MIN 48000 -#define USE_RATE_MAX 48000 -#endif - -#if 0 /* CA0106 */ -#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE -#define USE_CHANNELS_MIN 2 -#define USE_CHANNELS_MAX 2 -#define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) -#define USE_RATE_MIN 48000 -#define USE_RATE_MAX 192000 -#define MAX_BUFFER_SIZE ((65536-64)*8) -#define MAX_PERIOD_SIZE (65536-64) -#define USE_PERIODS_MIN 2 -#define USE_PERIODS_MAX 8 -#endif - - /* defaults */ -#ifndef MAX_BUFFER_SIZE #define MAX_BUFFER_SIZE (64*1024) -#endif -#ifndef MAX_PERIOD_SIZE +#define MIN_PERIOD_SIZE 64 #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE -#endif -#ifndef USE_FORMATS #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) -#endif -#ifndef USE_RATE #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 #define USE_RATE_MIN 5500 #define USE_RATE_MAX 48000 -#endif -#ifndef USE_CHANNELS_MIN #define USE_CHANNELS_MIN 1 -#endif -#ifndef USE_CHANNELS_MAX #define USE_CHANNELS_MAX 2 -#endif -#ifndef USE_PERIODS_MIN #define USE_PERIODS_MIN 1 -#endif -#ifndef USE_PERIODS_MAX #define USE_PERIODS_MAX 1024 -#endif -#ifndef add_playback_constraints -#define add_playback_constraints(x) 0 -#endif -#ifndef add_capture_constraints -#define add_capture_constraints(x) 0 -#endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; +static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; @@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for dummy soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); +module_param_array(model, charp, NULL, 0444); +MODULE_PARM_DESC(model, "Soundcard model."); module_param_array(pcm_devs, int, NULL, 0444); MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); module_param_array(pcm_substreams, int, NULL, 0444); @@ -193,15 +109,120 @@ struct dummy_timer_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); }; +struct dummy_model { + const char *name; + int (*playback_constraints)(struct snd_pcm_runtime *runtime); + int (*capture_constraints)(struct snd_pcm_runtime *runtime); + u64 formats; + size_t buffer_bytes_max; + size_t period_bytes_min; + size_t period_bytes_max; + unsigned int periods_min; + unsigned int periods_max; + unsigned int rates; + unsigned int rate_min; + unsigned int rate_max; + unsigned int channels_min; + unsigned int channels_max; +}; + struct snd_dummy { struct snd_card *card; + struct dummy_model *model; struct snd_pcm *pcm; + struct snd_pcm_hardware pcm_hw; spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; const struct dummy_timer_ops *timer_ops; }; +/* + * card models + */ + +static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) +{ + int err; + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); + if (err < 0) + return err; + return 0; +} + +struct dummy_model model_emu10k1 = { + .name = "emu10k1", + .playback_constraints = emu10k1_playback_constraints, + .buffer_bytes_max = 128 * 1024, +}; + +struct dummy_model model_rme9652 = { + .name = "rme9652", + .buffer_bytes_max = 26 * 64 * 1024, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 26, + .channels_max = 26, + .periods_min = 2, + .periods_max = 2, +}; + +struct dummy_model model_ice1712 = { + .name = "ice1712", + .buffer_bytes_max = 256 * 1024, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 10, + .channels_max = 10, + .periods_min = 1, + .periods_max = 1024, +}; + +struct dummy_model model_uda1341 = { + .name = "uda1341", + .buffer_bytes_max = 16380, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 2, + .channels_max = 2, + .periods_min = 2, + .periods_max = 255, +}; + +struct dummy_model model_ac97 = { + .name = "ac97", + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, +}; + +struct dummy_model model_ca0106 = { + .name = "ca0106", + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .buffer_bytes_max = ((65536-64)*8), + .period_bytes_max = (65536-64), + .periods_min = 2, + .periods_max = 8, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000, + .rate_min = 48000, + .rate_max = 192000, +}; + +struct dummy_model *dummy_models[] = { + &model_emu10k1, + &model_rme9652, + &model_ice1712, + &model_uda1341, + &model_ac97, + &model_ca0106, + NULL +}; + /* * system timer interface */ @@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { .channels_min = USE_CHANNELS_MIN, .channels_max = USE_CHANNELS_MAX, .buffer_bytes_max = MAX_BUFFER_SIZE, - .period_bytes_min = 64, + .period_bytes_min = MIN_PERIOD_SIZE, .period_bytes_max = MAX_PERIOD_SIZE, .periods_min = USE_PERIODS_MIN, .periods_max = USE_PERIODS_MAX, @@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) static int dummy_pcm_open(struct snd_pcm_substream *substream) { struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + struct dummy_model *model = dummy->model; struct snd_pcm_runtime *runtime = substream->runtime; int err; @@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) if (err < 0) return err; - runtime->hw = dummy_pcm_hardware; + runtime->hw = dummy->pcm_hw; if (substream->pcm->device & 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; @@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = add_playback_constraints(substream->runtime); - else - err = add_capture_constraints(substream->runtime); + if (model == NULL) + return 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (model->playback_constraints) + err = model->playback_constraints(substream->runtime); + } else { + if (model->capture_constraints) + err = model->capture_constraints(substream->runtime); + } if (err < 0) { dummy->timer_ops->free(substream); return err; @@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) /* * proc interface */ -static void print_formats(struct snd_info_buffer *buffer) +static void print_formats(struct snd_dummy *dummy, + struct snd_info_buffer *buffer) { int i; for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { - if (dummy_pcm_hardware.formats & (1ULL << i)) + if (dummy->pcm_hw.formats & (1ULL << i)) snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); } } -static void print_rates(struct snd_info_buffer *buffer) +static void print_rates(struct snd_dummy *dummy, + struct snd_info_buffer *buffer) { static int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, @@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer) }; int i; - if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) + if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS) snd_iprintf(buffer, " continuous"); - if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) + if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT) snd_iprintf(buffer, " knot"); for (i = 0; i < ARRAY_SIZE(rates); i++) - if (dummy_pcm_hardware.rates & (1 << i)) + if (dummy->pcm_hw.rates & (1 << i)) snd_iprintf(buffer, " %d", rates[i]); } -#define get_dummy_int_ptr(ofs) \ - (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) -#define get_dummy_ll_ptr(ofs) \ - (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) +#define get_dummy_int_ptr(dummy, ofs) \ + (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs)) +#define get_dummy_ll_ptr(dummy, ofs) \ + (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs)) struct dummy_hw_field { const char *name; @@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = { static void dummy_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { + struct snd_dummy *dummy = entry->private_data; int i; for (i = 0; i < ARRAY_SIZE(fields); i++) { snd_iprintf(buffer, "%s ", fields[i].name); if (fields[i].size == sizeof(int)) snd_iprintf(buffer, fields[i].format, - *get_dummy_int_ptr(fields[i].offset)); + *get_dummy_int_ptr(dummy, fields[i].offset)); else snd_iprintf(buffer, fields[i].format, - *get_dummy_ll_ptr(fields[i].offset)); + *get_dummy_ll_ptr(dummy, fields[i].offset)); if (!strcmp(fields[i].name, "formats")) - print_formats(buffer); + print_formats(dummy, buffer); else if (!strcmp(fields[i].name, "rates")) - print_rates(buffer); + print_rates(dummy, buffer); snd_iprintf(buffer, "\n"); } } @@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry, static void dummy_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { + struct snd_dummy *dummy = entry->private_data; char line[64]; while (!snd_info_get_line(buffer, line, sizeof(line))) { @@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry, if (strict_strtoull(item, 0, &val)) continue; if (fields[i].size == sizeof(int)) - *get_dummy_int_ptr(fields[i].offset) = val; + *get_dummy_int_ptr(dummy, fields[i].offset) = val; else - *get_dummy_ll_ptr(fields[i].offset) = val; + *get_dummy_ll_ptr(dummy, fields[i].offset) = val; } } @@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) snd_info_set_text_ops(entry, chip, dummy_proc_read); entry->c.text.write = dummy_proc_write; entry->mode |= S_IWUSR; + entry->private_data = chip; } } #else @@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_dummy *dummy; + struct dummy_model *m = NULL, **mdl; int idx, err; int dev = devptr->id; @@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) return err; dummy = card->private_data; dummy->card = card; + for (mdl = dummy_models; *mdl && model[dev]; mdl++) { + if (strcmp(model[dev], (*mdl)->name) == 0) { + printk(KERN_INFO + "snd-dummy: Using model '%s' for card %i\n", + (*mdl)->name, card->number); + m = dummy->model = *mdl; + break; + } + } for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { if (pcm_substreams[dev] < 1) pcm_substreams[dev] = 1; @@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) if (err < 0) goto __nodev; } + + dummy->pcm_hw = dummy_pcm_hardware; + if (m) { + if (m->formats) + dummy->pcm_hw.formats = m->formats; + if (m->buffer_bytes_max) + dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max; + if (m->period_bytes_min) + dummy->pcm_hw.period_bytes_min = m->period_bytes_min; + if (m->period_bytes_max) + dummy->pcm_hw.period_bytes_max = m->period_bytes_max; + if (m->periods_min) + dummy->pcm_hw.periods_min = m->periods_min; + if (m->periods_max) + dummy->pcm_hw.periods_max = m->periods_max; + if (m->rates) + dummy->pcm_hw.rates = m->rates; + if (m->rate_min) + dummy->pcm_hw.rate_min = m->rate_min; + if (m->rate_max) + dummy->pcm_hw.rate_max = m->rate_max; + if (m->channels_min) + dummy->pcm_hw.channels_min = m->channels_min; + if (m->channels_max) + dummy->pcm_hw.channels_max = m->channels_max; + } + err = snd_card_dummy_new_mixer(dummy); if (err < 0) goto __nodev; -- GitLab From 88f66ea98d7ae6a8b6a34e38b1b4fa51abc1c9ca Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Jan 2010 18:49:44 -0500 Subject: [PATCH 1476/3892] kconfig: Look in both /bin and /sbin for lsmod in streamline_config.pl Distributions now have lsmod in /bin instead of /sbin. But to handle both cases, we look for it in /sbin /bin /usr/bin and /usr/sbin. If lsmod is not found in any of those paths, it defaults to use just lsmod and hopes that it lies in the path of the user. Tested-by: Xavier Chantry Signed-off-by: Steven Rostedt --- scripts/kconfig/streamline_config.pl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 9e66fa8dc52e..d7f7db73e587 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -264,7 +264,20 @@ foreach my $makefile (@makefiles) { my %modules; # see what modules are loaded on this system -open(LIN,"/sbin/lsmod|") || die "Cant lsmod"; +my $lsmod; + +foreach $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) { + if ( -x "$dir/lsmod" ) { + $lsmod = "$dir/lsmod"; + last; + } +} +if (!defined($lsmod)) { + # try just the path + $lsmod = "lsmod"; +} + +open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod"; while () { next if (/^Module/); # Skip the first line. if (/^(\S+)/) { -- GitLab From 7d39e849912f0c3c8c6fc94be7bf7d120b1ee0ba Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 2 Feb 2010 20:46:34 +0100 Subject: [PATCH 1477/3892] HID: update copyright Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- drivers/hid/hid-input.c | 2 +- drivers/hid/usbhid/hid-core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7fe509879fe3..1bbd96d4efe4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -4,7 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina */ /* diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index dad7aae9c975..8430d626511c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina * * HID to Linux Input mapping */ diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e72751d6e3e7..eb7e0019891f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -5,7 +5,7 @@ * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc * Copyright (c) 2007-2008 Oliver Neukum - * Copyright (c) 2006-2009 Jiri Kosina + * Copyright (c) 2006-2010 Jiri Kosina */ /* -- GitLab From d1c9ae6d1e7b95cedc8e39e8949e795379a0669e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 2 Feb 2010 11:46:50 -0800 Subject: [PATCH 1478/3892] ipv4: ip_fragment: fix unbalanced rcu_read_unlock() Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 9f41bd311754..b59430bc041c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -234,10 +234,9 @@ static void ip_expire(unsigned long arg) /* Send an ICMP "Fragment Reassembly Timeout" message. */ icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); - } - out_rcu_unlock: - rcu_read_unlock(); + rcu_read_unlock(); + } out: spin_unlock(&qp->q.lock); ipq_put(qp); -- GitLab From 1c3a02c215a5b955b342f29dc1719e1a5771eaf1 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 2 Feb 2010 18:43:32 +0200 Subject: [PATCH 1479/3892] HID: add NOGET quirk for Prodige Cordless Combo I happen to own a keyboard identified as 05af:3062 which is labeled as "FlatX Coldless Combo" by "Prodige", which exhibits input problems without NOGET quirk. For some reason, lsusb reports this device as "Jing-Mold Enterprise Co., Ltd", which is not mentioned anywhere on the package. A quick search on the intenet shows that there a other people who have this in their lsusb output, but apparently they don't have the problem I am seeing (or they are not such furious typists as myself). Signed-off-by: Alexander Shishkin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6c38359385a9..4e5adc3fac4a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -383,6 +383,9 @@ #define USB_VENDOR_ID_POWERCOM 0x0d9f #define USB_DEVICE_ID_POWERCOM_UPS 0x0002 +#define USB_VENDOR_ID_PRODIGE 0x05af +#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 + #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 38773dc2821b..fc074c11e0d3 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -45,6 +45,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, -- GitLab From d0833a6a2dbc169aba3abcc0904e5aea348bb4d3 Mon Sep 17 00:00:00 2001 From: Andriy Tkachuk Date: Tue, 2 Feb 2010 15:58:53 +0200 Subject: [PATCH 1480/3892] lib80211: Cosmetics - make room for MIC/CRC near the actual calculation Signed-off-by: Andriy V. Tkachuk Signed-off-by: John W. Linville --- net/wireless/lib80211_crypt_ccmp.c | 2 +- net/wireless/lib80211_crypt_tkip.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c index 2301dc1edc4c..b7fa31d5fd13 100644 --- a/net/wireless/lib80211_crypt_ccmp.c +++ b/net/wireless/lib80211_crypt_ccmp.c @@ -237,7 +237,6 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; pos = skb->data + hdr_len + CCMP_HDR_LEN; - mic = skb_put(skb, CCMP_MIC_LEN); hdr = (struct ieee80211_hdr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); @@ -257,6 +256,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += len; } + mic = skb_put(skb, CCMP_MIC_LEN); for (i = 0; i < CCMP_MIC_LEN; i++) mic[i] = b[i] ^ s0[i]; diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index c36287399d7e..c6a3cae1f85e 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -384,9 +384,8 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) return -1; - icv = skb_put(skb, 4); - crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; -- GitLab From 299af9d3db0fd3a4994e5e66717ecd276bdd60da Mon Sep 17 00:00:00 2001 From: Andriy Tkachuk Date: Tue, 2 Feb 2010 16:33:53 +0200 Subject: [PATCH 1481/3892] lib80211: Introduce TKIP_HDR_LEN define for code clarity Introduce TKIP_HDR_LEN define for code clarity (in the same way as CCMP_HDR_LEN). Also odd len variable (not used) dropped from lib80211_tkip_hdr(). Signed-off-by: Andriy V. Tkachuk Signed-off-by: John W. Linville --- net/wireless/lib80211_crypt_tkip.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index c6a3cae1f85e..8cbdb32ff316 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -36,6 +36,8 @@ MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("lib80211 crypt: TKIP"); MODULE_LICENSE("GPL"); +#define TKIP_HDR_LEN 8 + struct lib80211_tkip_data { #define TKIP_KEY_LEN 32 u8 key[TKIP_KEY_LEN]; @@ -314,13 +316,12 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, u8 * rc4key, int keylen, void *priv) { struct lib80211_tkip_data *tkey = priv; - int len; u8 *pos; struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *)skb->data; - if (skb_headroom(skb) < 8 || skb->len < hdr_len) + if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) return -1; if (rc4key == NULL || keylen < 16) @@ -333,9 +334,8 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, } tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); - len = skb->len - hdr_len; - pos = skb_push(skb, 8); - memmove(pos, pos + 8, hdr_len); + pos = skb_push(skb, TKIP_HDR_LEN); + memmove(pos, pos + TKIP_HDR_LEN, hdr_len); pos += hdr_len; *pos++ = *rc4key; @@ -353,7 +353,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, tkey->tx_iv32++; } - return 8; + return TKIP_HDR_LEN; } static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) @@ -433,7 +433,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; } - if (skb->len < hdr_len + 8 + 4) + if (skb->len < hdr_len + TKIP_HDR_LEN + 4) return -1; pos = skb->data + hdr_len; @@ -461,7 +461,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } iv16 = (pos[0] << 8) | pos[2]; iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); - pos += 8; + pos += TKIP_HDR_LEN; if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { #ifdef CONFIG_LIB80211_DEBUG @@ -522,8 +522,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) tkey->rx_iv16_new = iv16; /* Remove IV and ICV */ - memmove(skb->data + 8, skb->data, hdr_len); - skb_pull(skb, 8); + memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, TKIP_HDR_LEN); skb_trim(skb, skb->len - 4); return keyidx; -- GitLab From f09c256375c7cf1e112b8ef6306cdd313490d7c0 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 2 Feb 2010 15:34:50 +0100 Subject: [PATCH 1482/3892] airo: fix setting zero length WEP key Patch prevents call set_wep_key() with zero key length. That fix long standing regression since commit c0380693520b1a1e4f756799a0edc379378b462a "airo: clean up WEP key operations". Additionally print call trace when someone will try to use improper parameters, and remove key.len = 0 assignment, because it is in not possible code path. Reported-by: Chris Siebenmann Bisected-by: Chris Siebenmann Tested-by: Chris Siebenmann Cc: Dan Williams Cc: Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 4331d675fcc6..2a9f029a3c74 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5254,11 +5254,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key, WepKeyRid wkr; int rc; - if (keylen == 0) { - airo_print_err(ai->dev->name, "%s: key length to set was zero", - __func__); - return -1; - } + WARN_ON(keylen == 0); memset(&wkr, 0, sizeof(wkr)); wkr.len = cpu_to_le16(sizeof(wkr)); @@ -6405,11 +6401,7 @@ static int airo_set_encode(struct net_device *dev, if (dwrq->length > MIN_KEY_SIZE) key.len = MAX_KEY_SIZE; else - if (dwrq->length > 0) - key.len = MIN_KEY_SIZE; - else - /* Disable the key */ - key.len = 0; + key.len = MIN_KEY_SIZE; /* Check if the key is not marked as invalid */ if(!(dwrq->flags & IW_ENCODE_NOKEY)) { /* Cleanup */ @@ -6590,12 +6582,22 @@ static int airo_set_encodeext(struct net_device *dev, default: return -EINVAL; } - /* Send the key to the card */ - rc = set_wep_key(local, idx, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, "failed to set WEP key" - " at index %d: %d.", idx, rc); - return rc; + if (key.len == 0) { + rc = set_wep_tx_idx(local, idx, perm, 1); + if (rc < 0) { + airo_print_err(local->dev->name, + "failed to set WEP transmit index to %d: %d.", + idx, rc); + return rc; + } + } else { + rc = set_wep_key(local, idx, key.key, key.len, perm, 1); + if (rc < 0) { + airo_print_err(local->dev->name, + "failed to set WEP key at index %d: %d.", + idx, rc); + return rc; + } } } -- GitLab From 5ffaf8a361b4c9025963959a744f21d8173c7669 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 2 Feb 2010 11:58:33 -0500 Subject: [PATCH 1483/3892] ath9k: add support for 802.11n bonded out AR2427 Some single chip family devices are sold in the market with 802.11n bonded out, these have no hardware capability for 802.11n but ath9k can still support them. These are called AR2427. Cc: stable@kernel.org Reported-by: Rolf Leggewie Tested-by: Bernhard Reiter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 ++++++- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 4 +++- drivers/net/wireless/ath/ath9k/pci.c | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0b1dd10f1d84..0b1b88ffa497 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -334,7 +334,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.pcie_clock_req = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; - ah->config.ht_enable = 1; ah->config.ofdm_trig_low = 200; ah->config.ofdm_trig_high = 500; ah->config.cck_trig_high = 200; @@ -346,6 +345,11 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } + if (ah->hw_version.devid != AR2427_DEVID_PCIE) + ah->config.ht_enable = 1; + else + ah->config.ht_enable = 0; + ah->config.rx_intr_mitigation = true; /* @@ -542,6 +546,7 @@ static bool ath9k_hw_devid_supported(u16 devid) case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: case AR9271_USB: + case AR2427_DEVID_PCIE: return true; default: break; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ab1f1981d857..dbbf7ca5f97d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -40,6 +40,7 @@ #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a #define AR9285_DEVID_PCIE 0x002b +#define AR2427_DEVID_PCIE 0x002c #define AR5416_AR9100_DEVID 0x000b diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index c3066b553546..4b5e54848683 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -620,11 +620,13 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_SPECTRUM_MGMT; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) hw->flags |= IEEE80211_HW_MFP_CAPABLE; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f2afcbefc076..f318b3b1abe9 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -25,6 +25,7 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ { 0 } -- GitLab From 8127f4e883666c9960cfa89cffd36313748f8bab Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 2 Feb 2010 18:09:06 -0200 Subject: [PATCH 1484/3892] HID: use multi input quirk for eTurboTouch touchscreen This device generates ABS_Z and ABS_RX events, while it should be generating ABS_X and ABS_Y instead. Using the MULTI_INPUT quirk solves this issue. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Oliveira Nascimento Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4e5adc3fac4a..bb5f4fa479ad 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -169,6 +169,9 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 +#define USB_DEVICE_ID_ETURBOTOUCH 0x0006 + #define USB_VENDOR_ID_EZKEY 0x0518 #define USB_DEVICE_ID_BTC_8193 0x0002 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index fc074c11e0d3..88a1c693fdcc 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -43,6 +43,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, + { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, -- GitLab From 28aecb9d7728dc26bf03ce7925fe622023a83a2a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Jan 2010 04:05:52 +0000 Subject: [PATCH 1485/3892] xfrm: avoid spinlock in get_acqseq() Use atomic_inc_return() in get_acqseq() to avoid taking a spinlock Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/key/af_key.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 4744b1f6372f..e2aacf0ba013 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3019,12 +3019,11 @@ static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_e static u32 get_acqseq(void) { u32 res; - static u32 acqseq; - static DEFINE_SPINLOCK(acqseq_lock); + static atomic_t acqseq; - spin_lock_bh(&acqseq_lock); - res = (++acqseq ? : ++acqseq); - spin_unlock_bh(&acqseq_lock); + do { + res = atomic_inc_return(&acqseq); + } while (!res); return res; } -- GitLab From f9bfbebf34eab707b065116cdc9699d25ba4252a Mon Sep 17 00:00:00 2001 From: Shirley Ma Date: Fri, 29 Jan 2010 03:19:05 +0000 Subject: [PATCH 1486/3892] virtio: Add ability to detach unused buffers from vrings There's currently no way for a virtio driver to ask for unused buffers, so it has to keep a list itself to reclaim them at shutdown. This is redundant, since virtio_ring stores that information. So add a new hook to do this. Signed-off-by: Shirley Ma Signed-off-by: Amit Shah Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/virtio/virtio_ring.c | 25 +++++++++++++++++++++++++ include/linux/virtio.h | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index fbd2ecde93e4..71929ee00d69 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -334,6 +334,30 @@ static bool vring_enable_cb(struct virtqueue *_vq) return true; } +static void *vring_detach_unused_buf(struct virtqueue *_vq) +{ + struct vring_virtqueue *vq = to_vvq(_vq); + unsigned int i; + void *buf; + + START_USE(vq); + + for (i = 0; i < vq->vring.num; i++) { + if (!vq->data[i]) + continue; + /* detach_buf clears data, so grab it now. */ + buf = vq->data[i]; + detach_buf(vq, i); + END_USE(vq); + return buf; + } + /* That should have freed everything. */ + BUG_ON(vq->num_free != vq->vring.num); + + END_USE(vq); + return NULL; +} + irqreturn_t vring_interrupt(int irq, void *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); @@ -360,6 +384,7 @@ static struct virtqueue_ops vring_vq_ops = { .kick = vring_kick, .disable_cb = vring_disable_cb, .enable_cb = vring_enable_cb, + .detach_unused_buf = vring_detach_unused_buf, }; struct virtqueue *vring_new_virtqueue(unsigned int num, diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 057a2e010758..f508c651e53d 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -51,6 +51,9 @@ struct virtqueue { * This re-enables callbacks; it returns "false" if there are pending * buffers in the queue, to detect a possible race between the driver * checking for more work, and enabling callbacks. + * @detach_unused_buf: detach first unused buffer + * vq: the struct virtqueue we're talking about. + * Returns NULL or the "data" token handed to add_buf * * Locking rules are straightforward: the driver is responsible for * locking. No two operations may be invoked simultaneously, with the exception @@ -71,6 +74,7 @@ struct virtqueue_ops { void (*disable_cb)(struct virtqueue *vq); bool (*enable_cb)(struct virtqueue *vq); + void *(*detach_unused_buf)(struct virtqueue *vq); }; /** -- GitLab From 9ab86bbcf8be755256f0a5e994e0b38af6b4d399 Mon Sep 17 00:00:00 2001 From: Shirley Ma Date: Fri, 29 Jan 2010 03:20:04 +0000 Subject: [PATCH 1487/3892] virtio_net: Defer skb allocation in receive path Date: Wed, 13 Jan 2010 12:53:38 -0800 virtio_net receives packets from its pre-allocated vring buffers, then it delivers these packets to upper layer protocols as skb buffs. So it's not necessary to pre-allocate skb for each mergable buffer, then frees extra skbs when buffers are merged into a large packet. This patch has deferred skb allocation in receiving packets for both big packets and mergeable buffers to reduce skb pre-allocations and skb frees. It frees unused buffers by calling detach_unused_buf in vring, so recv skb queue is not needed. Signed-off-by: Shirley Ma Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 427 +++++++++++++++++++++++---------------- 1 file changed, 248 insertions(+), 179 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6b92e383c653..9d8984a3741c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -56,8 +56,7 @@ struct virtnet_info /* Host will merge rx buffers for big packets (shake it! shake it!) */ bool mergeable_rx_bufs; - /* Receive & send queues. */ - struct sk_buff_head recv; + /* Send queue. */ struct sk_buff_head send; /* Work struct for refilling if we run low on memory. */ @@ -75,34 +74,44 @@ struct skb_vnet_hdr { unsigned int num_sg; }; +struct padded_vnet_hdr { + struct virtio_net_hdr hdr; + /* + * virtio_net_hdr should be in a separated sg buffer because of a + * QEMU bug, and data sg buffer shares same page with this header sg. + * This padding makes next sg 16 byte aligned after virtio_net_hdr. + */ + char padding[6]; +}; + static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb) { return (struct skb_vnet_hdr *)skb->cb; } -static void give_a_page(struct virtnet_info *vi, struct page *page) -{ - page->private = (unsigned long)vi->pages; - vi->pages = page; -} - -static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb) +/* + * private is used to chain pages for big packets, put the whole + * most recent used list in the beginning for reuse + */ +static void give_pages(struct virtnet_info *vi, struct page *page) { - unsigned int i; + struct page *end; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - give_a_page(vi, skb_shinfo(skb)->frags[i].page); - skb_shinfo(skb)->nr_frags = 0; - skb->data_len = 0; + /* Find end of list, sew whole thing into vi->pages. */ + for (end = page; end->private; end = (struct page *)end->private); + end->private = (unsigned long)vi->pages; + vi->pages = page; } static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask) { struct page *p = vi->pages; - if (p) + if (p) { vi->pages = (struct page *)p->private; - else + /* clear private here, it is used to chain pages */ + p->private = 0; + } else p = alloc_page(gfp_mask); return p; } @@ -118,99 +127,142 @@ static void skb_xmit_done(struct virtqueue *svq) netif_wake_queue(vi->dev); } -static void receive_skb(struct net_device *dev, struct sk_buff *skb, - unsigned len) +static void set_skb_frag(struct sk_buff *skb, struct page *page, + unsigned int offset, unsigned int *len) { - struct virtnet_info *vi = netdev_priv(dev); - struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); - int err; - int i; - - if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) { - pr_debug("%s: short packet %i\n", dev->name, len); - dev->stats.rx_length_errors++; - goto drop; - } + int i = skb_shinfo(skb)->nr_frags; + skb_frag_t *f; + + f = &skb_shinfo(skb)->frags[i]; + f->size = min((unsigned)PAGE_SIZE - offset, *len); + f->page_offset = offset; + f->page = page; + + skb->data_len += f->size; + skb->len += f->size; + skb_shinfo(skb)->nr_frags++; + *len -= f->size; +} - if (vi->mergeable_rx_bufs) { - unsigned int copy; - char *p = page_address(skb_shinfo(skb)->frags[0].page); +static struct sk_buff *page_to_skb(struct virtnet_info *vi, + struct page *page, unsigned int len) +{ + struct sk_buff *skb; + struct skb_vnet_hdr *hdr; + unsigned int copy, hdr_len, offset; + char *p; - if (len > PAGE_SIZE) - len = PAGE_SIZE; - len -= sizeof(struct virtio_net_hdr_mrg_rxbuf); + p = page_address(page); - memcpy(&hdr->mhdr, p, sizeof(hdr->mhdr)); - p += sizeof(hdr->mhdr); + /* copy small packet so we can reuse these pages for small data */ + skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN); + if (unlikely(!skb)) + return NULL; - copy = len; - if (copy > skb_tailroom(skb)) - copy = skb_tailroom(skb); + hdr = skb_vnet_hdr(skb); - memcpy(skb_put(skb, copy), p, copy); + if (vi->mergeable_rx_bufs) { + hdr_len = sizeof hdr->mhdr; + offset = hdr_len; + } else { + hdr_len = sizeof hdr->hdr; + offset = sizeof(struct padded_vnet_hdr); + } - len -= copy; + memcpy(hdr, p, hdr_len); - if (!len) { - give_a_page(vi, skb_shinfo(skb)->frags[0].page); - skb_shinfo(skb)->nr_frags--; - } else { - skb_shinfo(skb)->frags[0].page_offset += - sizeof(hdr->mhdr) + copy; - skb_shinfo(skb)->frags[0].size = len; - skb->data_len += len; - skb->len += len; - } + len -= hdr_len; + p += offset; - while (--hdr->mhdr.num_buffers) { - struct sk_buff *nskb; + copy = len; + if (copy > skb_tailroom(skb)) + copy = skb_tailroom(skb); + memcpy(skb_put(skb, copy), p, copy); - i = skb_shinfo(skb)->nr_frags; - if (i >= MAX_SKB_FRAGS) { - pr_debug("%s: packet too long %d\n", dev->name, - len); - dev->stats.rx_length_errors++; - goto drop; - } + len -= copy; + offset += copy; - nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len); - if (!nskb) { - pr_debug("%s: rx error: %d buffers missing\n", - dev->name, hdr->mhdr.num_buffers); - dev->stats.rx_length_errors++; - goto drop; - } + while (len) { + set_skb_frag(skb, page, offset, &len); + page = (struct page *)page->private; + offset = 0; + } - __skb_unlink(nskb, &vi->recv); - vi->num--; + if (page) + give_pages(vi, page); - skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0]; - skb_shinfo(nskb)->nr_frags = 0; - kfree_skb(nskb); + return skb; +} - if (len > PAGE_SIZE) - len = PAGE_SIZE; +static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb) +{ + struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); + struct page *page; + int num_buf, i, len; + + num_buf = hdr->mhdr.num_buffers; + while (--num_buf) { + i = skb_shinfo(skb)->nr_frags; + if (i >= MAX_SKB_FRAGS) { + pr_debug("%s: packet too long\n", skb->dev->name); + skb->dev->stats.rx_length_errors++; + return -EINVAL; + } - skb_shinfo(skb)->frags[i].size = len; - skb_shinfo(skb)->nr_frags++; - skb->data_len += len; - skb->len += len; + page = vi->rvq->vq_ops->get_buf(vi->rvq, &len); + if (!page) { + pr_debug("%s: rx error: %d buffers missing\n", + skb->dev->name, hdr->mhdr.num_buffers); + skb->dev->stats.rx_length_errors++; + return -EINVAL; } - } else { - len -= sizeof(hdr->hdr); + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + set_skb_frag(skb, page, 0, &len); + + --vi->num; + } + return 0; +} + +static void receive_buf(struct net_device *dev, void *buf, unsigned int len) +{ + struct virtnet_info *vi = netdev_priv(dev); + struct sk_buff *skb; + struct page *page; + struct skb_vnet_hdr *hdr; - if (len <= MAX_PACKET_LEN) - trim_pages(vi, skb); + if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) { + pr_debug("%s: short packet %i\n", dev->name, len); + dev->stats.rx_length_errors++; + if (vi->mergeable_rx_bufs || vi->big_packets) + give_pages(vi, buf); + else + dev_kfree_skb(buf); + return; + } - err = pskb_trim(skb, len); - if (err) { - pr_debug("%s: pskb_trim failed %i %d\n", dev->name, - len, err); + if (!vi->mergeable_rx_bufs && !vi->big_packets) { + skb = buf; + len -= sizeof(struct virtio_net_hdr); + skb_trim(skb, len); + } else { + page = buf; + skb = page_to_skb(vi, page, len); + if (unlikely(!skb)) { dev->stats.rx_dropped++; - goto drop; + give_pages(vi, page); + return; } + if (vi->mergeable_rx_bufs) + if (receive_mergeable(vi, skb)) { + dev_kfree_skb(skb); + return; + } } + hdr = skb_vnet_hdr(skb); skb->truesize += skb->data_len; dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; @@ -267,110 +319,119 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, frame_err: dev->stats.rx_frame_errors++; -drop: dev_kfree_skb(skb); } -static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp) +static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) { struct sk_buff *skb; - struct scatterlist sg[2+MAX_SKB_FRAGS]; - int num, err, i; - bool oom = false; - - sg_init_table(sg, 2+MAX_SKB_FRAGS); - do { - struct skb_vnet_hdr *hdr; + struct skb_vnet_hdr *hdr; + struct scatterlist sg[2]; + int err; - skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN); - if (unlikely(!skb)) { - oom = true; - break; - } + skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN); + if (unlikely(!skb)) + return -ENOMEM; - skb_put(skb, MAX_PACKET_LEN); + skb_put(skb, MAX_PACKET_LEN); - hdr = skb_vnet_hdr(skb); - sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); + hdr = skb_vnet_hdr(skb); + sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr); - if (vi->big_packets) { - for (i = 0; i < MAX_SKB_FRAGS; i++) { - skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - f->page = get_a_page(vi, gfp); - if (!f->page) - break; + skb_to_sgvec(skb, sg + 1, 0, skb->len); - f->page_offset = 0; - f->size = PAGE_SIZE; + err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb); + if (err < 0) + dev_kfree_skb(skb); - skb->data_len += PAGE_SIZE; - skb->len += PAGE_SIZE; + return err; +} - skb_shinfo(skb)->nr_frags++; - } +static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) +{ + struct scatterlist sg[MAX_SKB_FRAGS + 2]; + struct page *first, *list = NULL; + char *p; + int i, err, offset; + + /* page in sg[MAX_SKB_FRAGS + 1] is list tail */ + for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { + first = get_a_page(vi, gfp); + if (!first) { + if (list) + give_pages(vi, list); + return -ENOMEM; } + sg_set_buf(&sg[i], page_address(first), PAGE_SIZE); - num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; - skb_queue_head(&vi->recv, skb); + /* chain new page in list head to match sg */ + first->private = (unsigned long)list; + list = first; + } - err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb); - if (err < 0) { - skb_unlink(skb, &vi->recv); - trim_pages(vi, skb); - kfree_skb(skb); - break; - } - vi->num++; - } while (err >= num); - if (unlikely(vi->num > vi->max)) - vi->max = vi->num; - vi->rvq->vq_ops->kick(vi->rvq); - return !oom; + first = get_a_page(vi, gfp); + if (!first) { + give_pages(vi, list); + return -ENOMEM; + } + p = page_address(first); + + /* sg[0], sg[1] share the same page */ + /* a separated sg[0] for virtio_net_hdr only during to QEMU bug*/ + sg_set_buf(&sg[0], p, sizeof(struct virtio_net_hdr)); + + /* sg[1] for data packet, from offset */ + offset = sizeof(struct padded_vnet_hdr); + sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset); + + /* chain first in list head */ + first->private = (unsigned long)list; + err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2, + first); + if (err < 0) + give_pages(vi, first); + + return err; } -/* Returns false if we couldn't fill entirely (OOM). */ -static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) +static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) { - struct sk_buff *skb; - struct scatterlist sg[1]; + struct page *page; + struct scatterlist sg; int err; - bool oom = false; - - if (!vi->mergeable_rx_bufs) - return try_fill_recv_maxbufs(vi, gfp); - do { - skb_frag_t *f; + page = get_a_page(vi, gfp); + if (!page) + return -ENOMEM; - skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN); - if (unlikely(!skb)) { - oom = true; - break; - } + sg_init_one(&sg, page_address(page), PAGE_SIZE); - f = &skb_shinfo(skb)->frags[0]; - f->page = get_a_page(vi, gfp); - if (!f->page) { - oom = true; - kfree_skb(skb); - break; - } + err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page); + if (err < 0) + give_pages(vi, page); - f->page_offset = 0; - f->size = PAGE_SIZE; + return err; +} - skb_shinfo(skb)->nr_frags++; +/* Returns false if we couldn't fill entirely (OOM). */ +static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) +{ + int err; + bool oom = false; - sg_init_one(sg, page_address(f->page), PAGE_SIZE); - skb_queue_head(&vi->recv, skb); + do { + if (vi->mergeable_rx_bufs) + err = add_recvbuf_mergeable(vi, gfp); + else if (vi->big_packets) + err = add_recvbuf_big(vi, gfp); + else + err = add_recvbuf_small(vi, gfp); - err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb); if (err < 0) { - skb_unlink(skb, &vi->recv); - kfree_skb(skb); + oom = true; break; } - vi->num++; + ++vi->num; } while (err > 0); if (unlikely(vi->num > vi->max)) vi->max = vi->num; @@ -407,15 +468,14 @@ static void refill_work(struct work_struct *work) static int virtnet_poll(struct napi_struct *napi, int budget) { struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi); - struct sk_buff *skb = NULL; + void *buf; unsigned int len, received = 0; again: while (received < budget && - (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) { - __skb_unlink(skb, &vi->recv); - receive_skb(vi->dev, skb, len); - vi->num--; + (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) { + receive_buf(vi->dev, buf, len); + --vi->num; received++; } @@ -495,9 +555,9 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) /* Encode metadata header at front. */ if (vi->mergeable_rx_bufs) - sg_set_buf(sg, &hdr->mhdr, sizeof(hdr->mhdr)); + sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr); else - sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); + sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr); hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb); @@ -917,8 +977,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->features |= NETIF_F_HW_VLAN_FILTER; } - /* Initialize our empty receive and send queues. */ - skb_queue_head_init(&vi->recv); + /* Initialize our empty send queue. */ skb_queue_head_init(&vi->send); err = register_netdev(dev); @@ -953,25 +1012,35 @@ free: return err; } +static void free_unused_bufs(struct virtnet_info *vi) +{ + void *buf; + while (1) { + buf = vi->rvq->vq_ops->detach_unused_buf(vi->rvq); + if (!buf) + break; + if (vi->mergeable_rx_bufs || vi->big_packets) + give_pages(vi, buf); + else + dev_kfree_skb(buf); + --vi->num; + } + BUG_ON(vi->num != 0); +} + static void __devexit virtnet_remove(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; - struct sk_buff *skb; /* Stop all the virtqueues. */ vdev->config->reset(vdev); - /* Free our skbs in send and recv queues, if any. */ - while ((skb = __skb_dequeue(&vi->recv)) != NULL) { - kfree_skb(skb); - vi->num--; - } + /* Free our skbs in send queue, if any. */ __skb_queue_purge(&vi->send); - BUG_ON(vi->num != 0); - unregister_netdev(vi->dev); cancel_delayed_work_sync(&vi->refill); + free_unused_bufs(vi); vdev->config->del_vqs(vi->vdev); -- GitLab From 0c2dc318e88100e1abdff07e8a7d60460984a2d2 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 1 Feb 2010 00:19:07 +0000 Subject: [PATCH 1488/3892] sky2: Fix TX_MAP_PAGE misspelling Btw of the dma-debug problem reported by Michael Breuer I spotted a tiny misspelling in TX_MAP_PAGE definition introduced by commit 6b84dacadbdc3. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- drivers/net/sky2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 365d79c7d834..54cb303443e0 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2156,7 +2156,7 @@ struct tx_ring_info { struct sk_buff *skb; unsigned long flags; #define TX_MAP_SINGLE 0x0001 -#define TX_MAP_PAGE 000002 +#define TX_MAP_PAGE 0x0002 DECLARE_PCI_UNMAP_ADDR(mapaddr); DECLARE_PCI_UNMAP_LEN(maplen); }; -- GitLab From 6a902881cc6993f136906559ca04b6a4c9e260fc Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:54 +0000 Subject: [PATCH 1489/3892] qlcnic: use DEFINE_PCI_DEVICE_TABLE Use DEFINE_PCI_DEVICE_TABLE() so we get place PCI ids table into correct section in every case. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 1698b6a68ed1..05275f2153be 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -102,7 +102,7 @@ static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); #define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020 -static const struct pci_device_id qlcnic_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = { ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), {0,} }; -- GitLab From 02420be6fc5fc63526aca43b5bfc571547a1c926 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:55 +0000 Subject: [PATCH 1490/3892] qlcnic: add ethernet identifier in board info Added missing identifier that distinguishes between FCOE/ISCSI/ETHERNET functions. Signed-off-by: Rajesh K Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index abec46846539..9662a37bfc57 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1068,7 +1068,7 @@ int qlcnic_reset_context(struct qlcnic_adapter *); * QLOGIC Board information */ -#define QLCNIC_MAX_BOARD_NAME_LEN 64 +#define QLCNIC_MAX_BOARD_NAME_LEN 100 struct qlcnic_brdinfo { unsigned short vendor; unsigned short device; @@ -1078,8 +1078,12 @@ struct qlcnic_brdinfo { }; static const struct qlcnic_brdinfo qlcnic_boards[] = { - {0x1077, 0x8020, 0x1077, 0x203, "8200 Series Single Port 10GbE CNA"}, - {0x1077, 0x8020, 0x1077, 0x207, "8200 Series Dual Port 10GbE CNA"}, + {0x1077, 0x8020, 0x1077, 0x203, + "8200 Series Single Port 10GbE Converged Network Adapter \ + (TCP/IP Networking)"}, + {0x1077, 0x8020, 0x1077, 0x207, + "8200 Series Dual Port 10GbE Converged Network Adapter \ + (TCP/IP Networking)"}, {0x1077, 0x8020, 0x1077, 0x20b, "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"}, {0x1077, 0x8020, 0x1077, 0x20c, -- GitLab From 1b95a839587f40abab2f9cb3e5254dc821b9829b Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:56 +0000 Subject: [PATCH 1491/3892] qlcnic: clear device reset state after fw recovery o After firmware recovery, clear device reset state transition register. Otherwise firmware reload can occur unnecessary. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 05275f2153be..9a98285ee791 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1866,6 +1866,23 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) qlcnic_api_unlock(adapter); } +static int +qlcnic_clr_drv_state(struct qlcnic_adapter *adapter) +{ + u32 val; + + if (qlcnic_api_lock(adapter)) + return -EBUSY; + + val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); + val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); + + qlcnic_api_unlock(adapter); + + return 0; +} + static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter) { @@ -2119,7 +2136,10 @@ qlcnic_attach_work(struct work_struct *work) done: adapter->fw_fail_cnt = 0; clear_bit(__QLCNIC_RESETTING, &adapter->state); - qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); + + if (!qlcnic_clr_drv_state(adapter)) + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, + FW_POLL_DELAY); } static int -- GitLab From ce6684433fb277406dd861fd8a17133253e7c367 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:57 +0000 Subject: [PATCH 1492/3892] qlcnic: protect resoruce cleanup by rtnl lock o context resources can be in used, while resoruce cleanup is in progress, during fw recover. o Null pointer execption can occur in send_cmd_desc, if fw recovery module frees tx ring without rtnl lock. o Same applies to ethtool register dump and FW health registers should be dump in any case. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_ethtool.c | 6 +++--- drivers/net/qlcnic/qlcnic_main.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 65e9620e28f1..37df5f6cea08 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -326,12 +326,12 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) - return; - for (i = 0; diag_registers[i] != -1; i++) regs_buff[i] = QLCRD32(adapter, diag_registers[i]); + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ regs_buff[i++] = 1; /* No. of tx ring */ diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 9a98285ee791..7259adc32631 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2051,7 +2051,9 @@ qlcnic_detach_work(struct work_struct *work) qlcnic_down(adapter, netdev); + rtnl_lock(); qlcnic_detach(adapter); + rtnl_unlock(); status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); -- GitLab From 897d3596e0dfc4c25963cff00f1159c79eaf38d3 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 1 Feb 2010 05:24:58 +0000 Subject: [PATCH 1493/3892] qlcnic: support LED blink for device identification Added support of device identification by blinking LED for specified time. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 1 + drivers/net/qlcnic/qlcnic_ethtool.c | 26 ++++++++++++++++++++++++++ drivers/net/qlcnic/qlcnic_hw.c | 22 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 9662a37bfc57..514e805f3ab3 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1015,6 +1015,7 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int); int qlcnic_get_board_info(struct qlcnic_adapter *adapter); int qlcnic_wol_supported(struct qlcnic_adapter *adapter); +int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate); /* Functions from qlcnic_init.c */ int qlcnic_phantom_init(struct qlcnic_adapter *adapter); diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 37df5f6cea08..7212319760ba 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -618,6 +618,7 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, u64 *data) { memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + data[0] = qlcnic_reg_test(dev); if (data[0]) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -693,6 +694,30 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data) return 0; } +static int qlcnic_blink_led(struct net_device *dev, u32 val) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int ret; + + ret = qlcnic_config_led(adapter, 1, 0xf); + if (ret) { + dev_err(&adapter->pdev->dev, + "Failed to set LED blink state.\n"); + return ret; + } + + msleep_interruptible(val * 1000); + + ret = qlcnic_config_led(adapter, 0, 0xf); + if (ret) { + dev_err(&adapter->pdev->dev, + "Failed to reset LED blink state.\n"); + return ret; + } + + return 0; +} + static void qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -867,4 +892,5 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_coalesce = qlcnic_set_intr_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = qlcnic_set_flags, + .phys_id = qlcnic_blink_led, }; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 91234e7b39e4..8724e561ed72 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1199,3 +1199,25 @@ qlcnic_wol_supported(struct qlcnic_adapter *adapter) return 0; } + +int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) +{ + struct qlcnic_nic_req req; + int rv; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64((u64)rate << 32); + req.words[1] = cpu_to_le64(state); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv) + dev_err(&adapter->pdev->dev, "LED configuration failed.\n"); + + return rv; +} -- GitLab From 7eb9855d68faabe0004ed18c2af1f0974d3c2c63 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:24:59 +0000 Subject: [PATCH 1494/3892] qlcnic: add interrupt diagnostic test Interrupt test (offline) added in ethtool self test. Register a temporary interrupt handler and then send command to fw to raise an interrupt. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 13 +++- drivers/net/qlcnic/qlcnic_ctx.c | 4 +- drivers/net/qlcnic/qlcnic_ethtool.c | 41 +++++++++- drivers/net/qlcnic/qlcnic_main.c | 112 +++++++++++++++++++++++++--- 4 files changed, 154 insertions(+), 16 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 514e805f3ab3..a5a67e9b5e10 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -560,6 +560,8 @@ struct qlcnic_recv_context { /* * Context state */ +#define QLCHAL_VERSION 1 + #define QLCNIC_HOST_CTX_STATE_ACTIVE 2 /* @@ -894,6 +896,8 @@ struct qlcnic_mac_req { #define __QLCNIC_RESETTING 2 #define __QLCNIC_START_FW 4 +#define QLCNIC_INTERRUPT_TEST 1 + struct qlcnic_adapter { struct qlcnic_hardware_context ahw; @@ -946,9 +950,10 @@ struct qlcnic_adapter { u32 heartbit; u8 dev_state; + u8 diag_test; + u8 diag_cnt; u8 rsrd1; - u32 rsrd2; - + u16 rsrd2; u8 mac_addr[ETH_ALEN]; @@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); +u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, + u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd); +void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); +int qlcnic_diag_alloc_res(struct net_device *netdev, int test); /* * QLOGIC Board information diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 71c16a183458..0a6a39914aec 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -24,8 +24,6 @@ #include "qlcnic.h" -#define QLCHAL_VERSION 1 - static u32 qlcnic_poll_rsp(struct qlcnic_adapter *adapter) { @@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) return rsp; } -static u32 +u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) { diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 7212319760ba..58c50ed791de 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -65,7 +65,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", - "Link_Test_on_offline" + "Link_Test_on_offline", + "Interrupt_Test_offline" }; #define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) @@ -613,12 +614,50 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) } } +static int qlcnic_irq_test(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int max_sds_rings = adapter->max_sds_rings; + int ret; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST); + if (ret) + goto clear_it; + + adapter->diag_cnt = 0; + ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, + QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011); + if (ret) + goto done; + + msleep(10); + + ret = !adapter->diag_cnt; + +done: + qlcnic_diag_free_res(netdev, max_sds_rings); + +clear_it: + adapter->max_sds_rings = max_sds_rings; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return ret; +} + static void qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, u64 *data) { memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + data[2] = qlcnic_irq_test(dev); + if (data[2]) + eth_test->flags |= ETH_TEST_FL_FAILED; + } + data[0] = qlcnic_reg_test(dev); if (data[0]) eth_test->flags |= ETH_TEST_FL_FAILED; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 7259adc32631..a8b07120d362 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -88,6 +88,7 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); +static irqreturn_t qlcnic_tmp_intr(int irq, void *data); static irqreturn_t qlcnic_intr(int irq, void *data); static irqreturn_t qlcnic_msi_intr(int irq, void *data); static irqreturn_t qlcnic_msix_intr(int irq, void *data); @@ -720,13 +721,20 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) struct net_device *netdev = adapter->netdev; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; - if (adapter->flags & QLCNIC_MSIX_ENABLED) - handler = qlcnic_msix_intr; - else if (adapter->flags & QLCNIC_MSI_ENABLED) - handler = qlcnic_msi_intr; - else { - flags |= IRQF_SHARED; - handler = qlcnic_intr; + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + handler = qlcnic_tmp_intr; + if (!QLCNIC_IS_MSI_FAMILY(adapter)) + flags |= IRQF_SHARED; + + } else { + if (adapter->flags & QLCNIC_MSIX_ENABLED) + handler = qlcnic_msix_intr; + else if (adapter->flags & QLCNIC_MSI_ENABLED) + handler = qlcnic_msi_intr; + else { + flags |= IRQF_SHARED; + handler = qlcnic_intr; + } } adapter->irq = netdev->irq; @@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter) adapter->is_up = 0; } +void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_disable_int(sds_ring); + } + + qlcnic_detach(adapter); + + adapter->diag_test = 0; + adapter->max_sds_rings = max_sds_rings; + + if (qlcnic_attach(adapter)) + return; + + if (netif_running(netdev)) + __qlcnic_up(adapter, netdev); + + netif_device_attach(netdev); +} + +int qlcnic_diag_alloc_res(struct net_device *netdev, int test) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + int ret; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + adapter->max_sds_rings = 1; + adapter->diag_test = test; + + ret = qlcnic_attach(adapter); + if (ret) + return ret; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_enable_int(sds_ring); + } + + return 0; +} + int qlcnic_reset_context(struct qlcnic_adapter *adapter) { @@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) return stats; } -static irqreturn_t qlcnic_intr(int irq, void *data) +static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter) { - struct qlcnic_host_sds_ring *sds_ring = data; - struct qlcnic_adapter *adapter = sds_ring->adapter; u32 status; status = readl(adapter->isr_int_vec); @@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data) readl(adapter->isr_int_vec); readl(adapter->isr_int_vec); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_tmp_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) + goto done; + else if (adapter->flags & QLCNIC_MSI_ENABLED) { + writel(0xffffffff, adapter->tgt_status_reg); + goto done; + } + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + +done: + adapter->diag_cnt++; + qlcnic_enable_int(sds_ring); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + napi_schedule(&sds_ring->napi); return IRQ_HANDLED; -- GitLab From cdaff1854f32ac9ddb4733530f617d32188665ed Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 1 Feb 2010 05:25:00 +0000 Subject: [PATCH 1495/3892] qlcnic: add loopback diagnostic test Loopback test (offline) added in ethtool self test. o Set device in loopback mode o Send packets o Process receive packets in qlcnic_process_rcv_ring_diag() o Compare packets o Reset device in normal mode. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 6 +++ drivers/net/qlcnic/qlcnic_ethtool.c | 82 ++++++++++++++++++++++++++++- drivers/net/qlcnic/qlcnic_hw.c | 52 ++++++++++++++++++ drivers/net/qlcnic/qlcnic_init.c | 75 ++++++++++++++++++++++++++ drivers/net/qlcnic/qlcnic_main.c | 20 +++---- 5 files changed, 225 insertions(+), 10 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index a5a67e9b5e10..b40a851ec7d1 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -897,6 +897,7 @@ struct qlcnic_mac_req { #define __QLCNIC_START_FW 4 #define QLCNIC_INTERRUPT_TEST 1 +#define QLCNIC_LOOPBACK_TEST 2 struct qlcnic_adapter { struct qlcnic_hardware_context ahw; @@ -1066,6 +1067,8 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring); int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); +void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter); +int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); @@ -1073,6 +1076,9 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd); void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); int qlcnic_diag_alloc_res(struct net_device *netdev, int test); +int qlcnic_check_loopback_buff(unsigned char *data); +netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring); /* * QLOGIC Board information diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 58c50ed791de..8da6ec8c13b9 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -66,7 +66,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", "Link_Test_on_offline", - "Interrupt_Test_offline" + "Interrupt_Test_offline", + "Loopback_Test_offline" }; #define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) @@ -614,6 +615,80 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) } } +#define QLC_ILB_PKT_SIZE 64 + +static void qlcnic_create_loopback_buff(unsigned char *data) +{ + unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00}; + memset(data, 0x4e, QLC_ILB_PKT_SIZE); + memset(data, 0xff, 12); + memcpy(data + 12, random_data, sizeof(random_data)); +} + +int qlcnic_check_loopback_buff(unsigned char *data) +{ + unsigned char buff[QLC_ILB_PKT_SIZE]; + qlcnic_create_loopback_buff(buff); + return memcmp(data, buff, QLC_ILB_PKT_SIZE); +} + +static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0]; + struct sk_buff *skb; + int i; + + for (i = 0; i < 16; i++) { + skb = dev_alloc_skb(QLC_ILB_PKT_SIZE); + qlcnic_create_loopback_buff(skb->data); + skb_put(skb, QLC_ILB_PKT_SIZE); + + adapter->diag_cnt = 0; + + qlcnic_xmit_frame(skb, adapter->netdev); + + msleep(5); + + qlcnic_process_rcv_ring_diag(sds_ring); + + dev_kfree_skb_any(skb); + if (!adapter->diag_cnt) + return -1; + } + return 0; +} + +static int qlcnic_loopback_test(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + int max_sds_rings = adapter->max_sds_rings; + int ret; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST); + if (ret) + goto clear_it; + + ret = qlcnic_set_ilb_mode(adapter); + if (ret) + goto done; + + ret = qlcnic_do_ilb_test(adapter); + + qlcnic_clear_ilb_mode(adapter); + +done: + qlcnic_diag_free_res(netdev, max_sds_rings); + +clear_it: + adapter->max_sds_rings = max_sds_rings; + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return ret; +} + static int qlcnic_irq_test(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -656,6 +731,11 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, data[2] = qlcnic_irq_test(dev); if (data[2]) eth_test->flags |= ETH_TEST_FL_FAILED; + + data[3] = qlcnic_loopback_test(dev); + if (data[3]) + eth_test->flags |= ETH_TEST_FL_FAILED; + } data[0] = qlcnic_reg_test(dev); diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 8724e561ed72..dc6cd69d6d93 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1221,3 +1221,55 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } + +static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag) +{ + struct qlcnic_nic_req req; + int rv; + u64 word; + + memset(&req, 0, sizeof(struct qlcnic_nic_req)); + req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); + + word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(flag); + + rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv) + dev_err(&adapter->pdev->dev, + "%sting loopback mode failed.\n", + flag ? "Set" : "Reset"); + return rv; +} + +int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter) +{ + if (qlcnic_set_fw_loopback(adapter, 1)) + return -EIO; + + if (qlcnic_nic_set_promisc(adapter, + VPORT_MISS_MODE_ACCEPT_ALL)) { + qlcnic_set_fw_loopback(adapter, 0); + return -EIO; + } + + msleep(1000); + return 0; +} + +void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter) +{ + int mode = VPORT_MISS_MODE_DROP; + struct net_device *netdev = adapter->netdev; + + qlcnic_set_fw_loopback(adapter, 0); + + if (netdev->flags & IFF_PROMISC) + mode = VPORT_MISS_MODE_ACCEPT_ALL; + else if (netdev->flags & IFF_ALLMULTI) + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + + qlcnic_nic_set_promisc(adapter, mode); +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 7ae8bcc1e439..ea00ab4d4feb 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1464,3 +1464,78 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, spin_unlock(&rds_ring->lock); } +static struct qlcnic_rx_buffer * +qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring, + int ring, u64 sts_data0) +{ + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_rx_buffer *buffer; + struct sk_buff *skb; + struct qlcnic_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; + + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = qlcnic_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + length = qlcnic_get_sts_totallength(sts_data0); + cksum = qlcnic_get_sts_status(sts_data0); + pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); + + skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); + if (!skb) + return buffer; + + skb_put(skb, rds_ring->skb_size); + + if (pkt_offset) + skb_pull(skb, pkt_offset); + + skb->truesize = skb->len + sizeof(struct sk_buff); + + if (!qlcnic_check_loopback_buff(skb->data)) + adapter->diag_cnt++; + + dev_kfree_skb_any(skb); + + return buffer; +} + +void +qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) +{ + struct qlcnic_adapter *adapter = sds_ring->adapter; + struct status_desc *desc; + struct qlcnic_rx_buffer *rxbuf; + u64 sts_data0; + + int opcode, ring, desc_cnt; + u32 consumer = sds_ring->consumer; + + desc = &sds_ring->desc_head[consumer]; + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); + + if (!(sts_data0 & STATUS_OWNER_HOST)) + return; + + desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); + opcode = qlcnic_get_sts_opcode(sts_data0); + + ring = qlcnic_get_sts_type(sts_data0); + rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring, + ring, sts_data0); + + desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + + sds_ring->consumer = consumer; + writel(consumer, sds_ring->crb_sts_consumer); +} diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index a8b07120d362..665e8e56b6a8 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -65,8 +65,6 @@ static int __devinit qlcnic_probe(struct pci_dev *pdev, static void __devexit qlcnic_remove(struct pci_dev *pdev); static int qlcnic_open(struct net_device *netdev); static int qlcnic_close(struct net_device *netdev); -static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, - struct net_device *); static void qlcnic_tx_timeout(struct net_device *netdev); static void qlcnic_tx_timeout_task(struct work_struct *work); static void qlcnic_attach_work(struct work_struct *work); @@ -937,9 +935,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) struct qlcnic_host_sds_ring *sds_ring; int ring; - for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; - qlcnic_disable_int(sds_ring); + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_disable_int(sds_ring); + } } qlcnic_detach(adapter); @@ -977,9 +977,11 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) if (ret) return ret; - for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; - qlcnic_enable_int(sds_ring); + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_enable_int(sds_ring); + } } return 0; @@ -1549,7 +1551,7 @@ qlcnic_clear_cmddesc(u64 *desc) desc[2] = 0ULL; } -static netdev_tx_t +netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); -- GitLab From 615f0833aa4c4aa944ceb78895bbffa8bd1884df Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 2 Feb 2010 21:51:27 -0500 Subject: [PATCH 1496/3892] kconfig: Add LSMOD=file to override the lsmod for localmodconfig Doing the following: make LSMOD=file localmodconfig Will make the streamline-config code use the given file instead of lsmod. If the file is an executable, it will execute it, otherwise it will read it as text. make LSMOD=/my/local/path/lsmod localmodconfig The above will execute the lsmod in /my/local/path instead of the lsmods that may be located elsewhere. make LSMOD=embedded_board_lsmod localmodconfig The above will read the "embedded_board_lsmod" as a text file. This is useful if you are doing a cross compile and need to run the config against modules that exist on an embedded device. Note, if the LSMOD= file does is not a path, it will add the path to the object directory. That is, the above example will look for "embedded_board_lsmod" in the directory that the binary will be built in (the O=dir directory). Signed-off-by: Steven Rostedt On branch config/linus --- scripts/kconfig/Makefile | 13 ++++++++-- scripts/kconfig/streamline_config.pl | 38 ++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 006c96f5fcb5..85b906547845 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -30,9 +30,18 @@ silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< -s $(Kconfig) +# if no path is given, then use src directory to find file +ifdef LSMOD +LSMOD_F = $(shell if [ `basename $(LSMOD)` == $(LSMOD) ]; then \ + echo $(objtree)/$(LSMOD); \ + else \ + echo $(LSMOD); \ + fi) +endif + localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -47,7 +56,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf localyesconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index d7f7db73e587..afbd54ac1d83 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -113,6 +113,7 @@ find_config; # Get the build source and top level Kconfig file (passed in) my $ksource = $ARGV[0]; my $kconfig = $ARGV[1]; +my $lsmod_file = $ARGV[2]; my @makefiles = `find $ksource -name Makefile`; my %depends; @@ -263,21 +264,36 @@ foreach my $makefile (@makefiles) { my %modules; -# see what modules are loaded on this system -my $lsmod; - -foreach $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) { - if ( -x "$dir/lsmod" ) { - $lsmod = "$dir/lsmod"; - last; +if (defined($lsmod_file)) { + if ( ! -f $lsmod_file) { + die "$lsmod_file not found"; + } + if ( -x $lsmod_file) { + # the file is executable, run it + open(LIN, "$lsmod_file|"); + } else { + # Just read the contents + open(LIN, "$lsmod_file"); } +} else { + + # see what modules are loaded on this system + my $lsmod; + + foreach $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) { + if ( -x "$dir/lsmod" ) { + $lsmod = "$dir/lsmod"; + last; + } } -if (!defined($lsmod)) { - # try just the path - $lsmod = "lsmod"; + if (!defined($lsmod)) { + # try just the path + $lsmod = "lsmod"; + } + + open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod"; } -open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod"; while () { next if (/^Module/); # Skip the first line. if (/^(\S+)/) { -- GitLab From dc942cee2fcb734d6f3ef7966040e4e034b67d5b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 22 Dec 2009 21:22:59 +0000 Subject: [PATCH 1497/3892] powerpc/viodasd: Remove VIOD_KERN_ macros for printks Use #define pr_fmt(fmt) "viod: " fmt Remove #define VIOD_KERN_WARNING and VIOD_KERN_INFO Convert printk(VIOD_KERN_ to pr_ Coalesce long format strings Signed-off-by: Joe Perches Acked-by: Stephen Rothwell drivers/block/viodasd.c | 86 +++++++++++++++++++--------------------------- 1 files changed, 36 insertions(+), 50 deletions(-) Signed-off-by: Benjamin Herrenschmidt --- drivers/block/viodasd.c | 86 +++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index a8c8b56b275e..1b3def1e8591 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -28,6 +28,9 @@ * All disk operations are performed by sending messages back and forth to * the OS/400 partition. */ + +#define pr_fmt(fmt) "viod: " fmt + #include #include #include @@ -63,9 +66,6 @@ MODULE_LICENSE("GPL"); #define VIOD_VERS "1.64" -#define VIOD_KERN_WARNING KERN_WARNING "viod: " -#define VIOD_KERN_INFO KERN_INFO "viod: " - enum { PARTITION_SHIFT = 3, MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS, @@ -156,7 +156,7 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode) ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING "HV open failed %d\n", (int)hvrc); + pr_warning("HV open failed %d\n", (int)hvrc); return -EIO; } @@ -167,9 +167,8 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode) const struct vio_error_entry *err = vio_lookup_rc(viodasd_err_table, we.sub_result); - printk(VIOD_KERN_WARNING - "bad rc opening disk: %d:0x%04x (%s)\n", - (int)we.rc, we.sub_result, err->msg); + pr_warning("bad rc opening disk: %d:0x%04x (%s)\n", + (int)we.rc, we.sub_result, err->msg); return -EIO; } @@ -195,8 +194,7 @@ static int viodasd_release(struct gendisk *disk, fmode_t mode) ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */, 0, 0, 0); if (hvrc != 0) - printk(VIOD_KERN_WARNING "HV close call failed %d\n", - (int)hvrc); + pr_warning("HV close call failed %d\n", (int)hvrc); return 0; } @@ -288,8 +286,7 @@ static int send_request(struct request *req) bevent = (struct vioblocklpevent *) vio_get_event_buffer(viomajorsubtype_blockio); if (bevent == NULL) { - printk(VIOD_KERN_WARNING - "error allocating disk event buffer\n"); + pr_warning("error allocating disk event buffer\n"); goto error_ret; } @@ -333,9 +330,8 @@ static int send_request(struct request *req) } if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOD_KERN_WARNING - "error sending disk event to OS/400 (rc %d)\n", - (int)hvrc); + pr_warning("error sending disk event to OS/400 (rc %d)\n", + (int)hvrc); goto error_ret; } spin_unlock_irqrestore(&viodasd_spinlock, flags); @@ -402,7 +398,7 @@ retry: ((u64)dev_no << 48) | ((u64)flags<< 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); + pr_warning("bad rc on HV open %d\n", (int)hvrc); return 0; } @@ -416,9 +412,8 @@ retry: goto retry; } if (we.max_disk > (MAX_DISKNO - 1)) { - printk_once(VIOD_KERN_INFO - "Only examining the first %d of %d disks connected\n", - MAX_DISKNO, we.max_disk + 1); + printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"), + MAX_DISKNO, we.max_disk + 1); } /* Send the close event to OS/400. We DON'T expect a response */ @@ -432,17 +427,15 @@ retry: ((u64)dev_no << 48) | ((u64)flags << 32), 0, 0, 0); if (hvrc != 0) { - printk(VIOD_KERN_WARNING - "bad rc sending event to OS/400 %d\n", (int)hvrc); + pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc); return 0; } if (d->dev == NULL) { /* this is when we reprobe for new disks */ if (vio_create_viodasd(dev_no) == NULL) { - printk(VIOD_KERN_WARNING - "cannot allocate virtual device for disk %d\n", - dev_no); + pr_warning("cannot allocate virtual device for disk %d\n", + dev_no); return 0; } /* @@ -457,15 +450,13 @@ retry: spin_lock_init(&d->q_lock); q = blk_init_queue(do_viodasd_request, &d->q_lock); if (q == NULL) { - printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", - dev_no); + pr_warning("cannot allocate queue for disk %d\n", dev_no); return 0; } g = alloc_disk(1 << PARTITION_SHIFT); if (g == NULL) { - printk(VIOD_KERN_WARNING - "cannot allocate disk structure for disk %d\n", - dev_no); + pr_warning("cannot allocate disk structure for disk %d\n", + dev_no); blk_cleanup_queue(q); return 0; } @@ -489,13 +480,12 @@ retry: g->driverfs_dev = d->dev; set_capacity(g, d->size >> 9); - printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) " - "CHS=%d/%d/%d sector size %d%s\n", - dev_no, (unsigned long)(d->size >> 9), - (unsigned long)(d->size >> 20), - (int)d->cylinders, (int)d->tracks, - (int)d->sectors, (int)d->bytes_per_sector, - d->read_only ? " (RO)" : ""); + pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n", + dev_no, (unsigned long)(d->size >> 9), + (unsigned long)(d->size >> 20), + (int)d->cylinders, (int)d->tracks, + (int)d->sectors, (int)d->bytes_per_sector, + d->read_only ? " (RO)" : ""); /* register us in the global list */ add_disk(g); @@ -580,8 +570,8 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) if (error) { const struct vio_error_entry *err; err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); - printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n", - event->xRc, bevent->sub_result, err->msg); + pr_warning("read/write error %d:0x%04x (%s)\n", + event->xRc, bevent->sub_result, err->msg); num_sect = blk_rq_sectors(req); } qlock = req->q->queue_lock; @@ -606,8 +596,7 @@ static void handle_block_event(struct HvLpEvent *event) return; /* First, we should NEVER get an int here...only acks */ if (hvlpevent_is_int(event)) { - printk(VIOD_KERN_WARNING - "Yikes! got an int in viodasd event handler!\n"); + pr_warning("Yikes! got an int in viodasd event handler!\n"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); @@ -650,7 +639,7 @@ static void handle_block_event(struct HvLpEvent *event) break; default: - printk(VIOD_KERN_WARNING "invalid subtype!"); + pr_warning("invalid subtype!"); if (hvlpevent_need_ack(event)) { event->xRc = HvLpEvent_Rc_InvalidSubtype; HvCallEvent_ackLpEvent(event); @@ -739,29 +728,26 @@ static int __init viodasd_init(void) vio_set_hostlp(); if (viopath_hostLp == HvLpIndexInvalid) { - printk(VIOD_KERN_WARNING "invalid hosting partition\n"); + pr_warning("invalid hosting partition\n"); rc = -EIO; goto early_fail; } - printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n", - viopath_hostLp); + pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp); /* register the block device */ rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); if (rc) { - printk(VIOD_KERN_WARNING - "Unable to get major number %d for %s\n", - VIODASD_MAJOR, VIOD_GENHD_NAME); + pr_warning("Unable to get major number %d for %s\n", + VIODASD_MAJOR, VIOD_GENHD_NAME); goto early_fail; } /* Actually open the path to the hosting partition */ rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); if (rc) { - printk(VIOD_KERN_WARNING - "error opening path to host partition %d\n", - viopath_hostLp); + pr_warning("error opening path to host partition %d\n", + viopath_hostLp); goto unregister_blk; } @@ -770,7 +756,7 @@ static int __init viodasd_init(void) rc = vio_register_driver(&viodasd_driver); if (rc) { - printk(VIOD_KERN_WARNING "vio_register_driver failed\n"); + pr_warning("vio_register_driver failed\n"); goto unset_handler; } -- GitLab From 4ba525d134a882e6994bf8f5bd93fd020376588c Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Thu, 31 Dec 2009 10:45:50 +0000 Subject: [PATCH 1498/3892] powerpc: Simplify param.h by including Signed-off-by: Robert P. J. Day Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/param.h | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/arch/powerpc/include/asm/param.h b/arch/powerpc/include/asm/param.h index 094f63d4d5ca..965d45427975 100644 --- a/arch/powerpc/include/asm/param.h +++ b/arch/powerpc/include/asm/param.h @@ -1,22 +1 @@ -#ifndef _ASM_POWERPC_PARAM_H -#define _ASM_POWERPC_PARAM_H - -#ifdef __KERNEL__ -#define HZ CONFIG_HZ /* internal kernel timer frequency */ -#define USER_HZ 100 /* for user interfaces in "ticks" */ -#define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */ -#endif /* __KERNEL__ */ - -#ifndef HZ -#define HZ 100 -#endif - -#define EXEC_PAGESIZE 4096 - -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ - -#endif /* _ASM_POWERPC_PARAM_H */ +#include -- GitLab From 61c03ddbdff2e080702521bc1b757854ca58c46a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 13 Jan 2010 12:04:11 +0000 Subject: [PATCH 1499/3892] powerpc: Replace per_cpu(, smp_processor_id()) with __get_cpu_var() The cputime code has a few places that do per_cpu(, smp_processor_id()). Replace them with __get_cpu_var(). Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/cputime.h | 7 +++---- arch/powerpc/kernel/time.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index fa19f3fe05ff..8bdc6a9e5773 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h @@ -73,10 +73,9 @@ static inline unsigned long cputime_to_jiffies(const cputime_t ct) static inline cputime_t cputime_to_scaled(const cputime_t ct) { if (cpu_has_feature(CPU_FTR_SPURR) && - per_cpu(cputime_last_delta, smp_processor_id())) - return ct * - per_cpu(cputime_scaled_last_delta, smp_processor_id())/ - per_cpu(cputime_last_delta, smp_processor_id()); + __get_cpu_var(cputime_last_delta)) + return ct * __get_cpu_var(cputime_scaled_last_delta) / + __get_cpu_var(cputime_last_delta); return ct; } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 6c6093d67f30..0a5b1081a50e 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -265,8 +265,8 @@ void account_system_vtime(struct task_struct *tsk) account_system_time(tsk, 0, delta, deltascaled); else account_idle_time(delta); - per_cpu(cputime_last_delta, smp_processor_id()) = delta; - per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; + __get_cpu_var(cputime_last_delta) = delta; + __get_cpu_var(cputime_scaled_last_delta) = deltascaled; local_irq_restore(flags); } EXPORT_SYMBOL_GPL(account_system_vtime); -- GitLab From 5be3492f972b73051ead7ecbac6fb9efd1e8e0ec Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 12 Jan 2010 00:50:14 +0000 Subject: [PATCH 1500/3892] powerpc: Mark some variables in the page fault path __read_mostly Using perf to trace L1 dcache misses and dumping data addresses I found a few variables taking a lot of misses. Since they are almost never written, they should go into the __read_mostly section. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/traps.c | 14 +++++++------- arch/powerpc/xmon/xmon.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d069ff8a7e03..4588d1eb18d2 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -60,13 +60,13 @@ #endif #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) -int (*__debugger)(struct pt_regs *regs); -int (*__debugger_ipi)(struct pt_regs *regs); -int (*__debugger_bpt)(struct pt_regs *regs); -int (*__debugger_sstep)(struct pt_regs *regs); -int (*__debugger_iabr_match)(struct pt_regs *regs); -int (*__debugger_dabr_match)(struct pt_regs *regs); -int (*__debugger_fault_handler)(struct pt_regs *regs); +int (*__debugger)(struct pt_regs *regs) __read_mostly; +int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; +int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; +int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; +int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; +int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly; +int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; EXPORT_SYMBOL(__debugger); EXPORT_SYMBOL(__debugger_ipi); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 4e6152c13764..8bad7d5f32af 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -61,7 +61,7 @@ static int xmon_owner; static int xmon_gate; #endif /* CONFIG_SMP */ -static unsigned long in_xmon = 0; +static unsigned long in_xmon __read_mostly = 0; static unsigned long adrs; static int size = 1; -- GitLab From 7b62922a071aea362e879252d7482e448bd63d9c Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Fri, 18 Dec 2009 12:50:37 +0000 Subject: [PATCH 1501/3892] powerpc/85xx: Fix SMP when "cpu-release-addr" is in lowmem Recent U-Boot commit 5ccd29c3679b3669b0bde5c501c1aa0f325a7acb caused the "cpu-release-addr" device tree property to contain the physical RAM location that secondary cores were spinning at. Previously, the "cpu-release-addr" property contained a value referencing the boot page translation address range of 0xfffffxxx, which then indirectly accessed RAM. The "cpu-release-addr" is currently ioremapped and the secondary cores kicked. However, due to the recent change in "cpu-release-addr", it sometimes points to a memory location in low memory that cannot be ioremapped. For example on a P2020-based board with 512MB of RAM the following error occurs on bootup: <...> mpic: requesting IPIs ... __ioremap(): phys addr 0x1ffff000 is RAM lr c05df9a0 Unable to handle kernel paging request for data at address 0x00000014 Faulting instruction address: 0xc05df9b0 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2 P2020 RDB Modules linked in: <... eventual kernel panic> Adding logic to conditionally ioremap or access memory directly resolves the issue. Signed-off-by: Peter Tyser Signed-off-by: Nate Case Reported-by: Dipen Dudhat Tested-by: Dipen Dudhat Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/85xx/smp.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 04160a4cc699..a15f582300d8 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -46,6 +46,7 @@ smp_85xx_kick_cpu(int nr) __iomem u32 *bptr_vaddr; struct device_node *np; int n = 0; + int ioremappable; WARN_ON (nr < 0 || nr >= NR_CPUS); @@ -59,21 +60,37 @@ smp_85xx_kick_cpu(int nr) return; } + /* + * A secondary core could be in a spinloop in the bootpage + * (0xfffff000), somewhere in highmem, or somewhere in lowmem. + * The bootpage and highmem can be accessed via ioremap(), but + * we need to directly access the spinloop if its in lowmem. + */ + ioremappable = *cpu_rel_addr > virt_to_phys(high_memory); + /* Map the spin table */ - bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); + if (ioremappable) + bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); + else + bptr_vaddr = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); + if (!ioremappable) + flush_dcache_range((ulong)bptr_vaddr, + (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY)); + /* Wait a bit for the CPU to ack. */ while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) mdelay(1); local_irq_restore(flags); - iounmap(bptr_vaddr); + if (ioremappable) + iounmap(bptr_vaddr); pr_debug("waited %d msecs for CPU #%d.\n", n, nr); } -- GitLab From b51130685817d8c1b56386f9957405b5be2cdfe0 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 18 Jan 2010 03:44:57 +0000 Subject: [PATCH 1502/3892] hvc_console: Make the ops pointer const. This is nicer for modern R/O protection. And noone needs it non-const, so constify the callers as well. Signed-off-by: Rusty Russell Signed-off-by: Amit Shah To: Christian Borntraeger Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_beat.c | 2 +- drivers/char/hvc_console.c | 7 ++++--- drivers/char/hvc_console.h | 7 ++++--- drivers/char/hvc_iseries.c | 2 +- drivers/char/hvc_iucv.c | 2 +- drivers/char/hvc_rtas.c | 2 +- drivers/char/hvc_udbg.c | 2 +- drivers/char/hvc_vio.c | 2 +- drivers/char/hvc_xen.c | 2 +- 9 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 0afc8b82212e..6913fc33270c 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) return cnt; } -static struct hv_ops hvc_beat_get_put_ops = { +static const struct hv_ops hvc_beat_get_put_ops = { .get_chars = hvc_beat_get_chars, .put_chars = hvc_beat_put_chars, }; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 416d3423150d..d8dac5820f0e 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index) * console interfaces but can still be used as a tty device. This has to be * static because kmalloc will not work during early console init. */ -static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; +static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; @@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref) * vty adapters do NOT get an hvc_instantiate() callback since they * appear after early console init. */ -int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) +int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) { struct hvc_struct *hp; @@ -749,7 +749,8 @@ static const struct tty_operations hvc_ops = { }; struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, - struct hv_ops *ops, int outbuf_size) + const struct hv_ops *ops, + int outbuf_size) { struct hvc_struct *hp; int i; diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 10950ca706d8..52ddf4d3716c 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -55,7 +55,7 @@ struct hvc_struct { int outbuf_size; int n_outbuf; uint32_t vtermno; - struct hv_ops *ops; + const struct hv_ops *ops; int irq_requested; int data; struct winsize ws; @@ -76,11 +76,12 @@ struct hv_ops { }; /* Register a vterm and a slot index for use as a console (console_init) */ -extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); +extern int hvc_instantiate(uint32_t vtermno, int index, + const struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, - struct hv_ops *ops, int outbuf_size); + const struct hv_ops *ops, int outbuf_size); /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int hvc_remove(struct hvc_struct *hp); diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index 936d05bf37fa..fd0242676a2a 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -197,7 +197,7 @@ done: return sent; } -static struct hv_ops hvc_get_put_ops = { +static const struct hv_ops hvc_get_put_ops = { .get_chars = get_chars, .put_chars = put_chars, .notifier_add = notifier_add_irq, diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index fe62bd0e17b7..21681a81cc35 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -922,7 +922,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev) /* HVC operations */ -static struct hv_ops hvc_iucv_ops = { +static const struct hv_ops hvc_iucv_ops = { .get_chars = hvc_iucv_get_chars, .put_chars = hvc_iucv_put_chars, .notifier_add = hvc_iucv_notifier_add, diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index 88590d040046..61c4a61558d9 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c @@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) return i; } -static struct hv_ops hvc_rtas_get_put_ops = { +static const struct hv_ops hvc_rtas_get_put_ops = { .get_chars = hvc_rtas_read_console, .put_chars = hvc_rtas_write_console, }; diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c index bd63ba878a56..b0957e61a7be 100644 --- a/drivers/char/hvc_udbg.c +++ b/drivers/char/hvc_udbg.c @@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) return i; } -static struct hv_ops hvc_udbg_ops = { +static const struct hv_ops hvc_udbg_ops = { .get_chars = hvc_udbg_get, .put_chars = hvc_udbg_put, }; diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 10be343d6ae7..27370e99c66f 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) return got; } -static struct hv_ops hvc_get_put_ops = { +static const struct hv_ops hvc_get_put_ops = { .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, .notifier_add = notifier_add_irq, diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index b1a71638c772..60446f82a3fc 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len) return recv; } -static struct hv_ops hvc_ops = { +static const struct hv_ops hvc_ops = { .get_chars = read_console, .put_chars = write_console, .notifier_add = notifier_add_irq, -- GitLab From 119ea10947cc1402abbf9d6200815b0606536906 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 18 Jan 2010 03:44:58 +0000 Subject: [PATCH 1503/3892] hvc_console: Remove __devinit annotation from hvc_alloc Virtio consoles can be hotplugged, so hvc_alloc gets called from multiple sites: from the initial probe() routine as well as later on from workqueue handlers which aren't __devinit code. So, drop the __devinit annotation for hvc_alloc. Signed-off-by: Amit Shah Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_console.c | 6 +++--- drivers/char/hvc_console.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index d8dac5820f0e..4c3b59be286a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -748,9 +748,9 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, - int outbuf_size) +struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, + int outbuf_size) { struct hvc_struct *hp; int i; diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 52ddf4d3716c..54381eba4e4a 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -80,8 +80,8 @@ extern int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, int outbuf_size); +extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, int outbuf_size); /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int hvc_remove(struct hvc_struct *hp); -- GitLab From 33a470f6d5e1879c26f16f6b34dc09f82d44f6e9 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 31 Jan 2010 04:00:30 +0000 Subject: [PATCH 1504/3892] macintosh/therm_adt746x: Fix sysfs attributes lifetime Looking at drivers/macintosh/therm_adt746x.c, the sysfs files are created in thermostat_init() and removed in thermostat_exit(), which are the driver's init and exit functions. These files are backed-up by a per-device structure, so it looks like the wrong thing to do: the sysfs files have a lifetime longer than the data structure that is backing it up. I think that sysfs files creation should be moved to the end of probe_thermostat() and sysfs files removal should be moved to the beginning of remove_thermostat(). Signed-off-by: Jean Delvare Tested-by: Christian Kujau Cc: Benjamin Herrenschmidt Cc: Colin Leroy Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/therm_adt746x.c | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 5ff47ba7f2d0..58809b0510f9 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -90,6 +90,8 @@ static struct task_struct *thread_therm = NULL; static void write_both_fan_speed(struct thermostat *th, int speed); static void write_fan_speed(struct thermostat *th, int speed, int fan); +static void thermostat_create_files(void); +static void thermostat_remove_files(void); static int write_reg(struct thermostat* th, int reg, u8 data) @@ -161,6 +163,8 @@ remove_thermostat(struct i2c_client *client) struct thermostat *th = i2c_get_clientdata(client); int i; + thermostat_remove_files(); + if (thread_therm != NULL) { kthread_stop(thread_therm); } @@ -449,6 +453,8 @@ static int probe_thermostat(struct i2c_client *client, return -ENOMEM; } + thermostat_create_files(); + return 0; } @@ -566,7 +572,6 @@ thermostat_init(void) struct device_node* np; const u32 *prop; int i = 0, offset = 0; - int err; np = of_find_node_by_name(NULL, "fan"); if (!np) @@ -633,6 +638,17 @@ thermostat_init(void) return -ENODEV; } +#ifndef CONFIG_I2C_POWERMAC + request_module("i2c-powermac"); +#endif + + return i2c_add_driver(&thermostat_driver); +} + +static void thermostat_create_files(void) +{ + int err; + err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); @@ -647,16 +663,9 @@ thermostat_init(void) if (err) printk(KERN_WARNING "Failed to create tempertaure attribute file(s).\n"); - -#ifndef CONFIG_I2C_POWERMAC - request_module("i2c-powermac"); -#endif - - return i2c_add_driver(&thermostat_driver); } -static void __exit -thermostat_exit(void) +static void thermostat_remove_files(void) { if (of_dev) { device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature); @@ -673,9 +682,14 @@ thermostat_exit(void) device_remove_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); - of_device_unregister(of_dev); } +} + +static void __exit +thermostat_exit(void) +{ i2c_del_driver(&thermostat_driver); + of_device_unregister(of_dev); } module_init(thermostat_init); -- GitLab From 98ceb75c7c14eada76b0aa9f03a635a735cee3cb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 31 Jan 2010 04:03:23 +0000 Subject: [PATCH 1505/3892] macintosh/hwmon/ams: Fix device removal sequence Some code that is in ams_exit() (the module exit code) should instead be called when the device (not module) is removed. It probably doesn't make much of a difference in the PMU case, but in the I2C case it does matter. I make no guarantee that my fix isn't racy, I'm not familiar enough with the ams driver code to tell for sure. Signed-off-by: Jean Delvare Tested-by: Christian Kujau Cc: Benjamin Herrenschmidt Cc: Stelian Pop Cc: Michael Hanselmann Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- drivers/hwmon/ams/ams-core.c | 11 +++++++---- drivers/hwmon/ams/ams-i2c.c | 2 ++ drivers/hwmon/ams/ams-pmu.c | 2 ++ drivers/hwmon/ams/ams.h | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c index 6c9ace1b76f6..2ad62c339cd2 100644 --- a/drivers/hwmon/ams/ams-core.c +++ b/drivers/hwmon/ams/ams-core.c @@ -213,7 +213,7 @@ int __init ams_init(void) return -ENODEV; } -void ams_exit(void) +void ams_sensor_detach(void) { /* Remove input device */ ams_input_exit(); @@ -221,9 +221,6 @@ void ams_exit(void) /* Remove attributes */ device_remove_file(&ams_info.of_dev->dev, &dev_attr_current); - /* Shut down implementation */ - ams_info.exit(); - /* Flush interrupt worker * * We do this after ams_info.exit(), because an interrupt might @@ -239,6 +236,12 @@ void ams_exit(void) pmf_unregister_irq_client(&ams_freefall_client); } +static void __exit ams_exit(void) +{ + /* Shut down implementation */ + ams_info.exit(); +} + MODULE_AUTHOR("Stelian Pop, Michael Hanselmann"); MODULE_DESCRIPTION("Apple Motion Sensor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c index 2cbf8a6506c7..abeecd27b484 100644 --- a/drivers/hwmon/ams/ams-i2c.c +++ b/drivers/hwmon/ams/ams-i2c.c @@ -238,6 +238,8 @@ static int ams_i2c_probe(struct i2c_client *client, static int ams_i2c_remove(struct i2c_client *client) { if (ams_info.has_device) { + ams_sensor_detach(); + /* Disable interrupts */ ams_i2c_set_irq(AMS_IRQ_ALL, 0); diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c index fb18b3d3162b..4f61b3ee1b08 100644 --- a/drivers/hwmon/ams/ams-pmu.c +++ b/drivers/hwmon/ams/ams-pmu.c @@ -133,6 +133,8 @@ static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z) static void ams_pmu_exit(void) { + ams_sensor_detach(); + /* Disable interrupts */ ams_pmu_set_irq(AMS_IRQ_ALL, 0); diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index 5ed387b0bd9a..b28d7e27a031 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h @@ -61,6 +61,7 @@ extern struct ams ams_info; extern void ams_sensors(s8 *x, s8 *y, s8 *z); extern int ams_sensor_attach(void); +extern void ams_sensor_detach(void); extern int ams_pmu_init(struct device_node *np); extern int ams_i2c_init(struct device_node *np); -- GitLab From 859aefc5afc6c00dae630680e5470f7a2c27c4a0 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 31 Jan 2010 01:14:03 +0000 Subject: [PATCH 1506/3892] powerpc: Increase NR_IRQS Kconfig maximum to 32768 With dynamic irq descriptors the overhead of a large NR_IRQS is much lower than it used to be. With more MSI-X capable adapters and drivers exploiting multiple vectors we may as well allow the user to increase it beyond the current maximum of 512. 32768 seems large enough that we'd never have to bump it again (although I bet my prediction is horribly wrong). It boot tests OK and the vmlinux footprint increase is only around 500kB due to: struct irq_map_entry irq_map[NR_IRQS]; We format /proc/interrupts correctly with the previous changes: CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 286: 0 0 0 0 0 0 516: 0 0 0 0 0 0 16689: 1833 0 0 0 0 0 17157: 0 0 0 0 0 0 17158: 319 0 0 0 0 0 25092: 0 0 0 0 0 0 Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index ba3948c70072..bf15e7b4cd3d 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -58,7 +58,7 @@ config IRQ_PER_CPU config NR_IRQS int "Number of virtual interrupt numbers" - range 32 512 + range 32 32768 default "512" help This defines the number of virtual interrupt numbers the kernel -- GitLab From 24551f64d47af9539a7f324343bffeea09d9dcfa Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 12 Jan 2010 21:25:24 +0000 Subject: [PATCH 1507/3892] lmb: Add lmb_free() We can free memory allocated with lmb_alloc() by removing it from the list of reserved LMBs. Rework lmb_remove() to allow that possibility and add lmb_free() which exploits it. BenH: Removed some useless parenthesis Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- include/linux/lmb.h | 1 + lib/lmb.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/lmb.h b/include/linux/lmb.h index ef82b8fcbddb..f3d14333ebed 100644 --- a/include/linux/lmb.h +++ b/include/linux/lmb.h @@ -42,6 +42,7 @@ extern void __init lmb_init(void); extern void __init lmb_analyze(void); extern long lmb_add(u64 base, u64 size); extern long lmb_remove(u64 base, u64 size); +extern long __init lmb_free(u64 base, u64 size); extern long __init lmb_reserve(u64 base, u64 size); extern u64 __init lmb_alloc_nid(u64 size, u64 align, int nid, u64 (*nid_range)(u64, u64, int *)); diff --git a/lib/lmb.c b/lib/lmb.c index 9cee17142b2c..b1fc52606524 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -205,9 +205,8 @@ long lmb_add(u64 base, u64 size) } -long lmb_remove(u64 base, u64 size) +static long __lmb_remove(struct lmb_region *rgn, u64 base, u64 size) { - struct lmb_region *rgn = &(lmb.memory); u64 rgnbegin, rgnend; u64 end = base + size; int i; @@ -254,6 +253,16 @@ long lmb_remove(u64 base, u64 size) return lmb_add_region(rgn, end, rgnend - end); } +long lmb_remove(u64 base, u64 size) +{ + return __lmb_remove(&lmb.memory, base, size); +} + +long __init lmb_free(u64 base, u64 size) +{ + return __lmb_remove(&lmb.reserved, base, size); +} + long __init lmb_reserve(u64 base, u64 size) { struct lmb_region *_rgn = &lmb.reserved; -- GitLab From 6c504d423147770d7bd73aab3228726379700786 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Sun, 17 Jan 2010 11:23:14 +0000 Subject: [PATCH 1508/3892] powerpc: Fix typo s/leve/level/ in TLB code Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/tlb_low_64e.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index f288279e679d..8b04c54e596f 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -1,5 +1,5 @@ /* - * Low leve TLB miss handlers for Book3E + * Low level TLB miss handlers for Book3E * * Copyright (C) 2008-2009 * Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. -- GitLab From 28bb9ee13aa0ee4c57dc3568f539cc84920b43aa Mon Sep 17 00:00:00 2001 From: "jschopp@austin.ibm.com" Date: Mon, 1 Feb 2010 12:50:48 +0000 Subject: [PATCH 1509/3892] powerpc: Add static fields to ibm,client-architecture call This patch adds 2 fields to the ibm_architecture_vec array. The first of these fields indicates the number of cores which Linux can boot. It does not account for SMT, so it may result in cpus assigned to Linux which cannot be booted. A second patch follows that dynamically updates this for SMT. The second field just indicates that our OS is Linux, and not another OS. The system may or may not use this hint to performance tune settings for Linux. Signed-off-by: Joel Schopp Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom_init.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index bafac2e41ae1..59d5bd1c064d 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -654,6 +654,9 @@ static void __init early_cmdline_parse(void) #define OV5_CMO 0x00 #endif +/* Option Vector 6: IBM PAPR hints */ +#define OV6_LINUX 0x02 /* Linux is our OS */ + /* * The architecture vector has an array of PVR mask/value pairs, * followed by # option vectors - 1, followed by the option vectors. @@ -665,7 +668,7 @@ static unsigned char ibm_architecture_vec[] = { W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ - 5 - 1, /* 5 option vectors */ + 6 - 1, /* 6 option vectors */ /* option vector 1: processor architectures supported */ 3 - 2, /* length */ @@ -697,12 +700,24 @@ static unsigned char ibm_architecture_vec[] = { 0, /* don't halt */ /* option vector 5: PAPR/OF options */ - 5 - 2, /* length */ + 13 - 2, /* length */ 0, /* don't ignore, don't halt */ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_DONATE_DEDICATE_CPU | OV5_MSI, 0, OV5_CMO, + 0, + 0, + 0, + 0, + W(NR_CPUS), /* number of cores supported*/ + + /* option vector 6: IBM PAPR hints */ + 4 - 2, /* length */ + 0, + 0, + OV6_LINUX, + }; /* Old method - ELF header with PT_NOTE sections */ -- GitLab From 9ad62ec4f752c82b39aa5927f23d894b46ae10b9 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 3 Feb 2010 16:46:20 +0900 Subject: [PATCH 1510/3892] sh: Fix up early PCI PERR/SERR IRQ handling. This adds support for handling early PERR/SERR triggering in between controller registration and the initial bus scan. Buggy cards end up asserting these as soon as the M66EN scan is undertaken, resulting in an early crash. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/common.c | 51 ++++++++++++++++++++++---------- arch/sh/drivers/pci/pci-sh7780.c | 2 +- arch/sh/drivers/pci/pci.c | 51 ++++++++++++++++++++++++++------ arch/sh/include/asm/pci.h | 12 ++++++++ 4 files changed, 90 insertions(+), 26 deletions(-) diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c index 25aec005da18..dbf138199871 100644 --- a/arch/sh/drivers/pci/common.c +++ b/arch/sh/drivers/pci/common.c @@ -3,29 +3,48 @@ #include #include -static int __init -early_read_config_word(struct pci_channel *hose, - int top_bus, int bus, int devfn, int offset, u16 *value) +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +static struct pci_dev *fake_pci_dev(struct pci_channel *hose, + int top_bus, int busnr, int devfn) { - struct pci_dev fake_dev; - struct pci_bus fake_bus; + static struct pci_dev dev; + static struct pci_bus bus; - fake_dev.bus = &fake_bus; - fake_dev.sysdata = hose; - fake_dev.devfn = devfn; - fake_bus.number = bus; - fake_bus.sysdata = hose; - fake_bus.ops = hose->pci_ops; + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.sysdata = hose; + bus.ops = hose->pci_ops; - if (bus != top_bus) + if(busnr != top_bus) /* Fake a parent bus structure. */ - fake_bus.parent = &fake_bus; + bus.parent = &bus; else - fake_bus.parent = NULL; + bus.parent = NULL; - return pci_read_config_word(&fake_dev, offset, value); + return &dev; } +#define EARLY_PCI_OP(rw, size, type) \ +int __init early_##rw##_config_##size(struct pci_channel *hose, \ + int top_bus, int bus, int devfn, int offset, type value) \ +{ \ + return pci_##rw##_config_##size( \ + fake_pci_dev(hose, top_bus, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + int __init pci_is_66mhz_capable(struct pci_channel *hose, int top_bus, int current_bus) { @@ -133,7 +152,7 @@ unsigned int pcibios_handle_status_errors(unsigned long addr, /* Now back off of the IRQ for awhile */ if (hose->err_irq) { - disable_irq(hose->err_irq); + disable_irq_nosync(hose->err_irq); hose->err_timer.expires = jiffies + HZ; add_timer(&hose->err_timer); } diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 472f67aec337..1e147f445c1a 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -150,7 +150,7 @@ static irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id) __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); /* Back off the IRQ for awhile */ - disable_irq(irq); + disable_irq_nosync(irq); hose->serr_timer.expires = jiffies + HZ; add_timer(&hose->serr_timer); diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index f4a69833fce2..41d8f014f1df 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -204,7 +204,7 @@ void pcibios_align_resource(void *data, struct resource *res, } void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, - struct resource *res) + struct resource *res) { struct pci_channel *hose = dev->sysdata; unsigned long offset = 0; @@ -218,9 +218,8 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, region->end = res->end - offset; } -void __devinit -pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, - struct pci_bus_region *region) +void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) { struct pci_channel *hose = dev->sysdata; unsigned long offset = 0; @@ -303,12 +302,41 @@ char * __devinit pcibios_setup(char *str) return str; } +static void __init +pcibios_bus_report_status_early(struct pci_channel *hose, + int top_bus, int current_bus, + unsigned int status_mask, int warn) +{ + unsigned int pci_devfn; + u16 status; + int ret; + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { + if (PCI_FUNC(pci_devfn)) + continue; + ret = early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, &status); + if (ret != PCIBIOS_SUCCESSFUL) + continue; + if (status == 0xffff) + continue; + + early_write_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, + status & status_mask); + if (warn) + printk("(%02x:%02x: %04X) ", current_bus, + pci_devfn, status); + } +} + /* * We can't use pci_find_device() here since we are * called from interrupt context. */ -static void pcibios_bus_report_status(struct pci_bus *bus, - unsigned int status_mask, int warn) +static void __init_refok +pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask, + int warn) { struct pci_dev *dev; @@ -341,12 +369,17 @@ static void pcibios_bus_report_status(struct pci_bus *bus, pcibios_bus_report_status(dev->subordinate, status_mask, warn); } -void pcibios_report_status(unsigned int status_mask, int warn) +void __init_refok pcibios_report_status(unsigned int status_mask, int warn) { struct pci_channel *hose; - for (hose = hose_head; hose; hose = hose->next) - pcibios_bus_report_status(hose->bus, status_mask, warn); + for (hose = hose_head; hose; hose = hose->next) { + if (unlikely(!hose->bus)) + pcibios_bus_report_status_early(hose, hose_head->index, + hose->index, status_mask, warn); + else + pcibios_bus_report_status(hose->bus, status_mask, warn); + } } int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index 6d762cca2312..1042f7f0a48b 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h @@ -41,6 +41,18 @@ extern int register_pci_controller(struct pci_channel *hose); extern void pcibios_report_status(unsigned int status_mask, int warn); /* arch/sh/drivers/pci/common.c */ +extern int early_read_config_byte(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u8 *value); +extern int early_read_config_word(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u16 *value); +extern int early_read_config_dword(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u32 *value); +extern int early_write_config_byte(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u8 value); +extern int early_write_config_word(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u16 value); +extern int early_write_config_dword(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u32 value); extern void pcibios_enable_timers(struct pci_channel *hose); extern unsigned int pcibios_handle_status_errors(unsigned long addr, unsigned int status, struct pci_channel *hose); -- GitLab From b8f46c5a34fa64fd456295388d18f50ae69d9f37 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Wed, 3 Feb 2010 11:53:14 +0800 Subject: [PATCH 1511/3892] perf tools: Use O_LARGEFILE to open perf data file Open perf data file with O_LARGEFILE flag since its size is easily larger that 2G. For example: # rm -rf perf.data # ./perf kmem record sleep 300 [ perf record: Woken up 0 times to write data ] [ perf record: Captured and wrote 3142.147 MB perf.data (~137282513 samples) ] # ll -h perf.data -rw------- 1 root root 3.1G ..... Signed-off-by: Xiao Guangrong Cc: Frederic Weisbecker Cc: Steven Rostedt Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <4B68F32A.9040203@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 5 ++++- tools/perf/util/header.c | 22 +++++++++++++--------- tools/perf/util/session.c | 5 ++++- tools/perf/util/trace-event-read.c | 4 ++-- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index eea56910b91c..949167efa1ed 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -5,6 +5,9 @@ * (or a CPU, or a PID) into the perf.data output file - for * later analysis via perf report. */ +#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + #include "builtin.h" #include "perf.h" @@ -451,7 +454,7 @@ static int __cmd_record(int argc, const char **argv) append_file = 0; } - flags = O_CREAT|O_RDWR; + flags = O_CREAT|O_RDWR|O_LARGEFILE; if (append_file) file_new = 0; else diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2bb2bdb1f456..ed3efd728b41 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1,3 +1,6 @@ +#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + #include #include #include @@ -382,7 +385,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) sec_size = sizeof(*feat_sec) * nr_sections; sec_start = self->data_offset + self->data_size; - lseek(fd, sec_start + sec_size, SEEK_SET); + lseek64(fd, sec_start + sec_size, SEEK_SET); if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { struct perf_file_section *trace_sec; @@ -390,9 +393,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd) trace_sec = &feat_sec[idx++]; /* Write trace info */ - trace_sec->offset = lseek(fd, 0, SEEK_CUR); + trace_sec->offset = lseek64(fd, 0, SEEK_CUR); read_tracing_data(fd, attrs, nr_counters); - trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; + trace_sec->size = lseek64(fd, 0, SEEK_CUR) - trace_sec->offset; } @@ -402,17 +405,18 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; /* Write build-ids */ - buildid_sec->offset = lseek(fd, 0, SEEK_CUR); + buildid_sec->offset = lseek64(fd, 0, SEEK_CUR); err = dsos__write_buildid_table(fd); if (err < 0) { pr_debug("failed to write buildid table\n"); goto out_free; } - buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; + buildid_sec->size = lseek64(fd, 0, SEEK_CUR) - + buildid_sec->offset; dsos__cache_build_ids(); } - lseek(fd, sec_start, SEEK_SET); + lseek64(fd, sec_start, SEEK_SET); err = do_write(fd, feat_sec, sec_size); if (err < 0) pr_debug("failed to write feature section\n"); @@ -506,7 +510,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) pr_debug("failed to write perf header\n"); return err; } - lseek(fd, self->data_offset + self->data_size, SEEK_SET); + lseek64(fd, self->data_offset + self->data_size, SEEK_SET); self->frozen = 1; return 0; @@ -560,7 +564,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, sec_size = sizeof(*feat_sec) * nr_sections; - lseek(fd, self->data_offset + self->data_size, SEEK_SET); + lseek64(fd, self->data_offset + self->data_size, SEEK_SET); if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) goto out_free; @@ -634,7 +638,7 @@ static int perf_file_section__process(struct perf_file_section *self, struct perf_header *ph, int feat, int fd) { - if (lseek(fd, self->offset, SEEK_SET) < 0) { + if (lseek64(fd, self->offset, SEEK_SET) < 0) { pr_debug("Failed to lseek to %Ld offset for feature %d, " "continuing...\n", self->offset, feat); return 0; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8e7c1896eaa2..cf91d099f0aa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,3 +1,6 @@ +#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + #include #include @@ -12,7 +15,7 @@ static int perf_session__open(struct perf_session *self, bool force) { struct stat input_stat; - self->fd = open(self->filename, O_RDONLY); + self->fd = open(self->filename, O_RDONLY|O_LARGEFILE); if (self->fd < 0) { pr_err("failed to open file: %s", self->filename); if (!strcmp(self->filename, "perf.data")) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 1744422cafcb..ca3c26d466f3 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -83,7 +83,7 @@ static char *read_string(void) char *str = NULL; int size = 0; int i; - int r; + s64 r; for (;;) { r = read(input_fd, buf, BUFSIZ); @@ -117,7 +117,7 @@ static char *read_string(void) i++; /* move the file descriptor to the end of the string */ - r = lseek(input_fd, -(r - i), SEEK_CUR); + r = lseek64(input_fd, -(r - i), SEEK_CUR); if (r < 0) die("lseek"); -- GitLab From f54405db66fbec11679241daefd16fd8291a5762 Mon Sep 17 00:00:00 2001 From: Alex Neblett Date: Tue, 2 Feb 2010 21:16:03 -0800 Subject: [PATCH 1512/3892] HID: add support for Pixart Imaging Optical Touch Screen Added support for the Pixart Imaging Inc. Optical Touch Screen found in the MSI AE2220 and other new all in one computers to the Quanta Optical Touch dual-touch panel driver found in the latest git clone git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git. Signed-off-by: Alex Neblett Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quanta.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2dd9b28e39c4..282f4a1e7214 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1343,6 +1343,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 39ff98a5bd61..b29d9da799f4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -400,6 +400,7 @@ #define USB_VENDOR_ID_QUANTA 0x0408 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 +#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c index 244d61c18a47..9ac49287b943 100644 --- a/drivers/hid/hid-quanta.c +++ b/drivers/hid/hid-quanta.c @@ -224,6 +224,8 @@ static void quanta_remove(struct hid_device *hdev) static const struct hid_device_id quanta_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, + USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { } }; MODULE_DEVICE_TABLE(hid, quanta_devices); -- GitLab From 2eff25c18c3d332d3c4dd98f2ac9b7114e9771b0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 13:24:54 +0100 Subject: [PATCH 1513/3892] netfilter: xt_hashlimit: fix race condition and simplify locking As noticed by Shin Hong , there is a race between htable_find_get() and htable_put(): htable_put(): htable_find_get(): spin_lock_bh(&hashlimit_lock); atomic_dec_and_test(&hinfo->use) atomic_inc(&hinfo->use) spin_unlock_bh(&hashlimit_lock) return hinfo; spin_lock_bh(&hashlimit_lock); hlist_del(&hinfo->node); spin_unlock_bh(&hashlimit_lock); htable_destroy(hinfo); The entire locking concept is overly complicated, tables are only created/referenced and released in process context, so a single mutex works just fine. Remove the hashinfo_spinlock and atomic reference count and use the mutex to protect table lookups/creation and reference count changes. Signed-off-by: Patrick McHardy --- net/netfilter/xt_hashlimit.c | 52 +++++++++++++----------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index fb7fcb773a3f..017c95966aa8 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -90,7 +90,7 @@ struct dsthash_ent { struct xt_hashlimit_htable { struct hlist_node node; /* global list of all htables */ - atomic_t use; + int use; u_int8_t family; bool rnd_initialized; @@ -109,8 +109,7 @@ struct xt_hashlimit_htable { struct hlist_head hash[0]; /* hashtable itself */ }; -static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ -static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ +static DEFINE_MUTEX(hashlimit_mutex); /* protects htables list */ static struct kmem_cache *hashlimit_cachep __read_mostly; static inline bool dst_cmp(const struct dsthash_ent *ent, @@ -244,7 +243,7 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_ for (i = 0; i < hinfo->cfg.size; i++) INIT_HLIST_HEAD(&hinfo->hash[i]); - atomic_set(&hinfo->use, 1); + hinfo->use = 1; hinfo->count = 0; hinfo->family = family; hinfo->rnd_initialized = false; @@ -263,9 +262,9 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_ hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); add_timer(&hinfo->timer); - spin_lock_bh(&hashlimit_lock); + mutex_lock(&hashlimit_mutex); hlist_add_head(&hinfo->node, &hashlimit_net->htables); - spin_unlock_bh(&hashlimit_lock); + mutex_unlock(&hashlimit_mutex); return 0; } @@ -308,7 +307,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, for (i = 0; i < hinfo->cfg.size; i++) INIT_HLIST_HEAD(&hinfo->hash[i]); - atomic_set(&hinfo->use, 1); + hinfo->use = 1; hinfo->count = 0; hinfo->family = family; hinfo->rnd_initialized = false; @@ -328,9 +327,9 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); add_timer(&hinfo->timer); - spin_lock_bh(&hashlimit_lock); + mutex_lock(&hashlimit_mutex); hlist_add_head(&hinfo->node, &hashlimit_net->htables); - spin_unlock_bh(&hashlimit_lock); + mutex_unlock(&hashlimit_mutex); return 0; } @@ -402,27 +401,24 @@ static struct xt_hashlimit_htable *htable_find_get(struct net *net, struct xt_hashlimit_htable *hinfo; struct hlist_node *pos; - spin_lock_bh(&hashlimit_lock); hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node) { if (!strcmp(name, hinfo->pde->name) && hinfo->family == family) { - atomic_inc(&hinfo->use); - spin_unlock_bh(&hashlimit_lock); + hinfo->use++; return hinfo; } } - spin_unlock_bh(&hashlimit_lock); return NULL; } static void htable_put(struct xt_hashlimit_htable *hinfo) { - if (atomic_dec_and_test(&hinfo->use)) { - spin_lock_bh(&hashlimit_lock); + mutex_lock(&hashlimit_mutex); + if (--hinfo->use == 0) { hlist_del(&hinfo->node); - spin_unlock_bh(&hashlimit_lock); htable_destroy(hinfo); } + mutex_unlock(&hashlimit_mutex); } /* The algorithm used is the Simple Token Bucket Filter (TBF) @@ -710,19 +706,13 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) if (r->name[sizeof(r->name) - 1] != '\0') return false; - /* This is the best we've got: We cannot release and re-grab lock, - * since checkentry() is called before x_tables.c grabs xt_mutex. - * We also cannot grab the hashtable spinlock, since htable_create will - * call vmalloc, and that can sleep. And we cannot just re-search - * the list of htable's in htable_create(), since then we would - * create duplicate proc files. -HW */ - mutex_lock(&hlimit_mutex); + mutex_lock(&hashlimit_mutex); r->hinfo = htable_find_get(net, r->name, par->match->family); if (!r->hinfo && htable_create_v0(net, r, par->match->family) != 0) { - mutex_unlock(&hlimit_mutex); + mutex_unlock(&hashlimit_mutex); return false; } - mutex_unlock(&hlimit_mutex); + mutex_unlock(&hashlimit_mutex); return true; } @@ -752,19 +742,13 @@ static bool hashlimit_mt_check(const struct xt_mtchk_param *par) return false; } - /* This is the best we've got: We cannot release and re-grab lock, - * since checkentry() is called before x_tables.c grabs xt_mutex. - * We also cannot grab the hashtable spinlock, since htable_create will - * call vmalloc, and that can sleep. And we cannot just re-search - * the list of htable's in htable_create(), since then we would - * create duplicate proc files. -HW */ - mutex_lock(&hlimit_mutex); + mutex_lock(&hashlimit_mutex); info->hinfo = htable_find_get(net, info->name, par->match->family); if (!info->hinfo && htable_create(net, info, par->match->family) != 0) { - mutex_unlock(&hlimit_mutex); + mutex_unlock(&hashlimit_mutex); return false; } - mutex_unlock(&hlimit_mutex); + mutex_unlock(&hashlimit_mutex); return true; } -- GitLab From 794e68716bab578ae8f8912dc934496d7c7abc90 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 13:41:29 +0100 Subject: [PATCH 1514/3892] netfilter: ctnetlink: only assign helpers for matching protocols Make sure not to assign a helper for a different network or transport layer protocol to a connection. Additionally change expectation deletion by helper to compare the name directly - there might be multiple helper registrations using the same name, currently one of them is chosen in an unpredictable manner and only those expectations are removed. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_helper.h | 2 +- net/netfilter/nf_conntrack_helper.c | 8 ++++--- net/netfilter/nf_conntrack_netlink.c | 23 ++++++++++----------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index d015de92e03f..86be7c4816d6 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -40,7 +40,7 @@ struct nf_conntrack_helper { }; extern struct nf_conntrack_helper * -__nf_conntrack_helper_find_byname(const char *name); +__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum); extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 65c2a7bc3afc..c0e461f466ae 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -65,7 +65,7 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) } struct nf_conntrack_helper * -__nf_conntrack_helper_find_byname(const char *name) +__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum) { struct nf_conntrack_helper *h; struct hlist_node *n; @@ -73,13 +73,15 @@ __nf_conntrack_helper_find_byname(const char *name) for (i = 0; i < nf_ct_helper_hsize; i++) { hlist_for_each_entry_rcu(h, n, &nf_ct_helper_hash[i], hnode) { - if (!strcmp(h->name, name)) + if (!strcmp(h->name, name) && + h->tuple.src.l3num == l3num && + h->tuple.dst.protonum == protonum) return h; } } return NULL; } -EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname); +EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find); struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) { diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 79478dfba27e..16f86d61e5d1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1001,7 +1001,8 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) return 0; } - helper = __nf_conntrack_helper_find_byname(helpname); + helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), + nf_ct_protonum(ct)); if (helper == NULL) { #ifdef CONFIG_MODULES spin_unlock_bh(&nf_conntrack_lock); @@ -1012,7 +1013,8 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) } spin_lock_bh(&nf_conntrack_lock); - helper = __nf_conntrack_helper_find_byname(helpname); + helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), + nf_ct_protonum(ct)); if (helper) return -EAGAIN; #endif @@ -1211,7 +1213,8 @@ ctnetlink_create_conntrack(struct net *net, if (err < 0) goto err2; - helper = __nf_conntrack_helper_find_byname(helpname); + helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), + nf_ct_protonum(ct)); if (helper == NULL) { rcu_read_unlock(); #ifdef CONFIG_MODULES @@ -1221,7 +1224,9 @@ ctnetlink_create_conntrack(struct net *net, } rcu_read_lock(); - helper = __nf_conntrack_helper_find_byname(helpname); + helper = __nf_conntrack_helper_find(helpname, + nf_ct_l3num(ct), + nf_ct_protonum(ct)); if (helper) { err = -EAGAIN; goto err2; @@ -1714,7 +1719,6 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, struct net *net = sock_net(ctnl); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; - struct nf_conntrack_helper *h; struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct hlist_node *n, *next; u_int8_t u3 = nfmsg->nfgen_family; @@ -1751,18 +1755,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, /* delete all expectations for this helper */ spin_lock_bh(&nf_conntrack_lock); - h = __nf_conntrack_helper_find_byname(name); - if (!h) { - spin_unlock_bh(&nf_conntrack_lock); - return -EOPNOTSUPP; - } for (i = 0; i < nf_ct_expect_hsize; i++) { hlist_for_each_entry_safe(exp, n, next, &net->ct.expect_hash[i], hnode) { m_help = nfct_help(exp->master); - if (m_help->helper == h - && del_timer(&exp->timeout)) { + if (!strcmp(m_help->helper->name, name) && + del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); } -- GitLab From add67461240c1dadc7c8d97e66f8f92b556ca523 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 13:45:12 +0100 Subject: [PATCH 1515/3892] netfilter: add struct net * to target parameters Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 2 ++ net/bridge/netfilter/ebtables.c | 10 ++++++---- net/ipv4/netfilter/ip_tables.c | 8 +++++--- net/ipv6/netfilter/ip6_tables.c | 8 +++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 026eb78ee83c..365fabe1b16e 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -249,6 +249,7 @@ struct xt_target_param { * Other fields see above. */ struct xt_tgchk_param { + struct net *net; const char *table; const void *entryinfo; const struct xt_target *target; @@ -259,6 +260,7 @@ struct xt_tgchk_param { /* Target destructor parameters */ struct xt_tgdtor_param { + struct net *net; const struct xt_target *target; void *targinfo; u_int8_t family; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 1aa0e4c1f52d..12beb580aa21 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -579,13 +579,14 @@ ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i) } static inline int -ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) +ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i) { struct xt_tgdtor_param par; if (i && (*i)-- == 0) return 1; + par.net = net; par.target = w->u.watcher; par.targinfo = w->data; par.family = NFPROTO_BRIDGE; @@ -606,10 +607,11 @@ ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt) /* we're done */ if (cnt && (*cnt)-- == 0) return 1; - EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); + EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL); EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); + par.net = net; par.target = t->u.target; par.targinfo = t->data; par.family = NFPROTO_BRIDGE; @@ -674,7 +676,7 @@ ebt_check_entry(struct ebt_entry *e, } i = 0; - mtpar.net = net; + mtpar.net = tgpar.net = net; mtpar.table = tgpar.table = name; mtpar.entryinfo = tgpar.entryinfo = e; mtpar.hook_mask = tgpar.hook_mask = hookmask; @@ -730,7 +732,7 @@ ebt_check_entry(struct ebt_entry *e, (*cnt)++; return 0; cleanup_watchers: - EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); + EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j); cleanup_matches: EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i); return ret; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index cfaba0e2e6fc..7fde8f6950d8 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -638,10 +638,11 @@ err: return ret; } -static int check_target(struct ipt_entry *e, const char *name) +static int check_target(struct ipt_entry *e, struct net *net, const char *name) { struct ipt_entry_target *t = ipt_get_target(e); struct xt_tgchk_param par = { + .net = net, .table = name, .entryinfo = e, .target = t->u.kernel.target, @@ -697,7 +698,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, } t->u.kernel.target = target; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto err; @@ -788,6 +789,7 @@ cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); t = ipt_get_target(e); + par.net = net; par.target = t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_IPV4; @@ -1675,7 +1677,7 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, if (ret) goto cleanup_matches; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto cleanup_matches; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 9f1d45f2ba8f..0376ed6d5594 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -669,10 +669,11 @@ err: return ret; } -static int check_target(struct ip6t_entry *e, const char *name) +static int check_target(struct ip6t_entry *e, struct net *net, const char *name) { struct ip6t_entry_target *t = ip6t_get_target(e); struct xt_tgchk_param par = { + .net = net, .table = name, .entryinfo = e, .target = t->u.kernel.target, @@ -729,7 +730,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, } t->u.kernel.target = target; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto err; @@ -820,6 +821,7 @@ cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); t = ip6t_get_target(e); + par.net = net; par.target = t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_IPV6; @@ -1710,7 +1712,7 @@ static int compat_check_entry(struct ip6t_entry *e, struct net *net, if (ret) goto cleanup_matches; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto cleanup_matches; -- GitLab From 858b31330054a9ad259feceea0ad1ce5385c47f0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 13:48:53 +0100 Subject: [PATCH 1516/3892] netfilter: nf_conntrack: split up IPCT_STATUS event Split up the IPCT_STATUS event into an IPCT_REPLY event, which is generated when the IPS_SEEN_REPLY bit is set, and an IPCT_ASSURED event, which is generated when the IPS_ASSURED bit is set. In combination with a following patch to support selective event delivery, this can be used for "sparse" conntrack replication: start replicating the conntrack entry after it reached the ASSURED state and that way it's SYN-flood resistant. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_ecache.h | 21 +++++++++++---------- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_conntrack_netlink.c | 6 ++++-- net/netfilter/nf_conntrack_proto_gre.c | 2 +- net/netfilter/nf_conntrack_proto_sctp.c | 2 +- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_proto_udp.c | 2 +- net/netfilter/nf_conntrack_proto_udplite.c | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 475facc3051a..5e05fb883ab1 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -14,19 +14,20 @@ /* Connection tracking event types */ enum ip_conntrack_events { - IPCT_NEW = 0, /* new conntrack */ - IPCT_RELATED = 1, /* related conntrack */ - IPCT_DESTROY = 2, /* destroyed conntrack */ - IPCT_STATUS = 3, /* status has changed */ - IPCT_PROTOINFO = 4, /* protocol information has changed */ - IPCT_HELPER = 5, /* new helper has been set */ - IPCT_MARK = 6, /* new mark has been set */ - IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */ - IPCT_SECMARK = 8, /* new security mark has been set */ + IPCT_NEW, /* new conntrack */ + IPCT_RELATED, /* related conntrack */ + IPCT_DESTROY, /* destroyed conntrack */ + IPCT_REPLY, /* connection has seen two-way traffic */ + IPCT_ASSURED, /* connection status has changed to assured */ + IPCT_PROTOINFO, /* protocol information has changed */ + IPCT_HELPER, /* new helper has been set */ + IPCT_MARK, /* new mark has been set */ + IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ + IPCT_SECMARK, /* new security mark has been set */ }; enum ip_conntrack_expect_events { - IPEXP_NEW = 0, /* new expectation */ + IPEXP_NEW, /* new expectation */ }; struct nf_conntrack_ecache { diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0e98c3282d42..091ff770eb7b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -825,7 +825,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, } if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_REPLY, ct); return ret; } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 16f86d61e5d1..ff594eb138c1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1371,7 +1371,8 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, else events = IPCT_NEW; - nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + nf_conntrack_eventmask_report((1 << IPCT_REPLY) | + (1 << IPCT_ASSURED) | (1 << IPCT_HELPER) | (1 << IPCT_PROTOINFO) | (1 << IPCT_NATSEQADJ) | @@ -1396,7 +1397,8 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err == 0) { nf_conntrack_get(&ct->ct_general); spin_unlock_bh(&nf_conntrack_lock); - nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + nf_conntrack_eventmask_report((1 << IPCT_REPLY) | + (1 << IPCT_ASSURED) | (1 << IPCT_HELPER) | (1 << IPCT_PROTOINFO) | (1 << IPCT_NATSEQADJ) | diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index c99cfba64ddc..d899b1a69940 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -241,7 +241,7 @@ static int gre_packet(struct nf_conn *ct, ct->proto.gre.stream_timeout); /* Also, more likely to be important, and not a probe. */ set_bit(IPS_ASSURED_BIT, &ct->status); - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_ASSURED, ct); } else nf_ct_refresh_acct(ct, ctinfo, skb, ct->proto.gre.timeout); diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index f9d930f80276..b68ff15ed979 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -377,7 +377,7 @@ static int sctp_packet(struct nf_conn *ct, new_state == SCTP_CONNTRACK_ESTABLISHED) { pr_debug("Setting assured bit\n"); set_bit(IPS_ASSURED_BIT, &ct->status); - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_ASSURED, ct); } return NF_ACCEPT; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 3c96437b45ad..ad118053971a 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1045,7 +1045,7 @@ static int tcp_packet(struct nf_conn *ct, after SYN_RECV or a valid answer for a picked up connection. */ set_bit(IPS_ASSURED_BIT, &ct->status); - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_ASSURED, ct); } nf_ct_refresh_acct(ct, ctinfo, skb, timeout); diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 5c5518bedb4b..8d38f9a4bed8 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -77,7 +77,7 @@ static int udp_packet(struct nf_conn *ct, nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_ASSURED, ct); } else nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout); diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 458655bb2106..0b1bc9ba6678 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -75,7 +75,7 @@ static int udplite_packet(struct nf_conn *ct, nf_ct_udplite_timeout_stream); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) - nf_conntrack_event_cache(IPCT_STATUS, ct); + nf_conntrack_event_cache(IPCT_ASSURED, ct); } else nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout); -- GitLab From 0cebe4b4163b6373c9d24c1a192939777bc27e55 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 13:51:51 +0100 Subject: [PATCH 1517/3892] netfilter: ctnetlink: support selective event delivery Add two masks for conntrack end expectation events to struct nf_conntrack_ecache and use them to filter events. Their default value is "all events" when the event sysctl is on and "no events" when it is off. A following patch will add specific initializations. Expectation events depend on the ecache struct of their master conntrack. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_common.h | 18 ++++++ include/net/netfilter/nf_conntrack_ecache.h | 59 +++++++++---------- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_conntrack_netlink.c | 2 +- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index a374787ed9b0..ebfed90733f7 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -74,6 +74,24 @@ enum ip_conntrack_status { IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), }; +/* Connection tracking event types */ +enum ip_conntrack_events { + IPCT_NEW, /* new conntrack */ + IPCT_RELATED, /* related conntrack */ + IPCT_DESTROY, /* destroyed conntrack */ + IPCT_REPLY, /* connection has seen two-way traffic */ + IPCT_ASSURED, /* connection status has changed to assured */ + IPCT_PROTOINFO, /* protocol information has changed */ + IPCT_HELPER, /* new helper has been set */ + IPCT_MARK, /* new mark has been set */ + IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ + IPCT_SECMARK, /* new security mark has been set */ +}; + +enum ip_conntrack_expect_events { + IPEXP_NEW, /* new expectation */ +}; + #ifdef __KERNEL__ struct ip_conntrack_stat { unsigned int searched; diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 5e05fb883ab1..96ba5f7dcab6 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -12,28 +12,12 @@ #include #include -/* Connection tracking event types */ -enum ip_conntrack_events { - IPCT_NEW, /* new conntrack */ - IPCT_RELATED, /* related conntrack */ - IPCT_DESTROY, /* destroyed conntrack */ - IPCT_REPLY, /* connection has seen two-way traffic */ - IPCT_ASSURED, /* connection status has changed to assured */ - IPCT_PROTOINFO, /* protocol information has changed */ - IPCT_HELPER, /* new helper has been set */ - IPCT_MARK, /* new mark has been set */ - IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ - IPCT_SECMARK, /* new security mark has been set */ -}; - -enum ip_conntrack_expect_events { - IPEXP_NEW, /* new expectation */ -}; - struct nf_conntrack_ecache { - unsigned long cache; /* bitops want long */ - unsigned long missed; /* missed events */ - u32 pid; /* netlink pid of destroyer */ + unsigned long cache; /* bitops want long */ + unsigned long missed; /* missed events */ + u16 ctmask; /* bitmask of ct events to be delivered */ + u16 expmask; /* bitmask of expect events to be delivered */ + u32 pid; /* netlink pid of destroyer */ }; static inline struct nf_conntrack_ecache * @@ -43,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct) } static inline struct nf_conntrack_ecache * -nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp) +nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) { struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *e; - if (!net->ct.sysctl_events) + if (!ctmask && !expmask && net->ct.sysctl_events) { + ctmask = ~0; + expmask = ~0; + } + if (!ctmask && !expmask) return NULL; - return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); + e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); + if (e) { + e->ctmask = ctmask; + e->expmask = expmask; + } + return e; }; #ifdef CONFIG_NF_CONNTRACK_EVENTS @@ -83,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) if (e == NULL) return; + if (!(e->ctmask & (1 << event))) + return; + set_bit(event, &e->cache); } @@ -93,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask, int report) { int ret = 0; - struct net *net = nf_ct_net(ct); struct nf_ct_event_notifier *notify; struct nf_conntrack_ecache *e; @@ -102,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask, if (notify == NULL) goto out_unlock; - if (!net->ct.sysctl_events) - goto out_unlock; - e = nf_ct_ecache_find(ct); if (e == NULL) goto out_unlock; @@ -118,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask, /* This is a resent of a destroy event? If so, skip missed */ unsigned long missed = e->pid ? 0 : e->missed; + if (!((eventmask | missed) & e->ctmask)) + goto out_unlock; + ret = notify->fcn(eventmask | missed, &item); if (unlikely(ret < 0 || missed)) { spin_lock_bh(&ct->lock); @@ -173,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, u32 pid, int report) { - struct net *net = nf_ct_exp_net(exp); struct nf_exp_event_notifier *notify; + struct nf_conntrack_ecache *e; rcu_read_lock(); notify = rcu_dereference(nf_expect_event_cb); if (notify == NULL) goto out_unlock; - if (!net->ct.sysctl_events) + e = nf_ct_ecache_find(exp->master); + if (e == NULL) goto out_unlock; - { + if (e->expmask & (1 << event)) { struct nf_exp_event item = { .exp = exp, .pid = pid, diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 091ff770eb7b..53b8da6ad6b7 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -648,7 +648,7 @@ init_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); - nf_ct_ecache_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, tuple); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ff594eb138c1..f5c0b09e12f1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1281,7 +1281,7 @@ ctnetlink_create_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); - nf_ct_ecache_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) -- GitLab From b2a15a604d379af323645e330638e2cfcc696aff Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 14:13:03 +0100 Subject: [PATCH 1518/3892] netfilter: nf_conntrack: support conntrack templates Support initializing selected parameters of new conntrack entries from a "conntrack template", which is a specially marked conntrack entry attached to the skb. Currently the helper and the event delivery masks can be initialized this way. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_common.h | 4 ++ include/net/netfilter/nf_conntrack.h | 5 ++ include/net/netfilter/nf_conntrack_helper.h | 3 +- net/ipv4/netfilter/nf_defrag_ipv4.c | 2 +- .../netfilter/nf_conntrack_l3proto_ipv6.c | 2 +- net/netfilter/nf_conntrack_core.c | 50 +++++++++++++------ net/netfilter/nf_conntrack_helper.c | 17 +++++-- net/netfilter/nf_conntrack_netlink.c | 2 +- 8 files changed, 61 insertions(+), 24 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index ebfed90733f7..c608677dda60 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -72,6 +72,10 @@ enum ip_conntrack_status { /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), + + /* Conntrack is a template */ + IPS_TEMPLATE_BIT = 11, + IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT), }; /* Connection tracking event types */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index a0904adfb8f7..5043d61c99a7 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -272,6 +272,11 @@ nf_conntrack_alloc(struct net *net, const struct nf_conntrack_tuple *repl, gfp_t gfp); +static inline int nf_ct_is_template(const struct nf_conn *ct) +{ + return test_bit(IPS_TEMPLATE_BIT, &ct->status); +} + /* It's confirmed if it is, or has been in the hash table. */ static inline int nf_ct_is_confirmed(struct nf_conn *ct) { diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 86be7c4816d6..e17aaa3e19fd 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -47,7 +47,8 @@ extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); -extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags); +extern int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, + gfp_t flags); extern void nf_ct_helper_destroy(struct nf_conn *ct); diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index 331ead3ebd1b..77627fa80561 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -59,7 +59,7 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, #if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE) /* Previously seen (loopback)? Ignore. Do this before fragment check. */ - if (skb->nfct) + if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) return NF_ACCEPT; #endif #endif diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 0956ebabbff2..55ce22e5de49 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -212,7 +212,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, struct sk_buff *reasm; /* Previously seen (loopback)? */ - if (skb->nfct) + if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) return NF_ACCEPT; reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 53b8da6ad6b7..471e2a79d26f 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -618,7 +618,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_free); /* Allocate a new conntrack: we return -ENOMEM if classification failed due to stress. Otherwise it really is unclassifiable. */ static struct nf_conntrack_tuple_hash * -init_conntrack(struct net *net, +init_conntrack(struct net *net, struct nf_conn *tmpl, const struct nf_conntrack_tuple *tuple, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, @@ -628,6 +628,7 @@ init_conntrack(struct net *net, struct nf_conn *ct; struct nf_conn_help *help; struct nf_conntrack_tuple repl_tuple; + struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { @@ -648,7 +649,11 @@ init_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); - nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); + + ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; + nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0, + ecache ? ecache->expmask : 0, + GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, tuple); @@ -673,7 +678,7 @@ init_conntrack(struct net *net, nf_conntrack_get(&ct->master->ct_general); NF_CT_STAT_INC(net, expect_new); } else { - __nf_ct_try_assign_helper(ct, GFP_ATOMIC); + __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); NF_CT_STAT_INC(net, new); } @@ -694,7 +699,7 @@ init_conntrack(struct net *net, /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ static inline struct nf_conn * -resolve_normal_ct(struct net *net, +resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, u_int16_t l3num, @@ -718,7 +723,8 @@ resolve_normal_ct(struct net *net, /* look for tuple match */ h = nf_conntrack_find_get(net, &tuple); if (!h) { - h = init_conntrack(net, &tuple, l3proto, l4proto, skb, dataoff); + h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, + skb, dataoff); if (!h) return NULL; if (IS_ERR(h)) @@ -755,7 +761,7 @@ unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, struct sk_buff *skb) { - struct nf_conn *ct; + struct nf_conn *ct, *tmpl = NULL; enum ip_conntrack_info ctinfo; struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; @@ -764,10 +770,14 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, int set_reply = 0; int ret; - /* Previously seen (loopback or untracked)? Ignore. */ if (skb->nfct) { - NF_CT_STAT_INC_ATOMIC(net, ignore); - return NF_ACCEPT; + /* Previously seen (loopback or untracked)? Ignore. */ + tmpl = (struct nf_conn *)skb->nfct; + if (!nf_ct_is_template(tmpl)) { + NF_CT_STAT_INC_ATOMIC(net, ignore); + return NF_ACCEPT; + } + skb->nfct = NULL; } /* rcu_read_lock()ed by nf_hook_slow */ @@ -778,7 +788,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, pr_debug("not prepared to track yet or error occured\n"); NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(net, invalid); - return -ret; + ret = -ret; + goto out; } l4proto = __nf_ct_l4proto_find(pf, protonum); @@ -791,22 +802,25 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, if (ret <= 0) { NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(net, invalid); - return -ret; + ret = -ret; + goto out; } } - ct = resolve_normal_ct(net, skb, dataoff, pf, protonum, + ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, l3proto, l4proto, &set_reply, &ctinfo); if (!ct) { /* Not valid part of a connection */ NF_CT_STAT_INC_ATOMIC(net, invalid); - return NF_ACCEPT; + ret = NF_ACCEPT; + goto out; } if (IS_ERR(ct)) { /* Too stressed to deal. */ NF_CT_STAT_INC_ATOMIC(net, drop); - return NF_DROP; + ret = NF_DROP; + goto out; } NF_CT_ASSERT(skb->nfct); @@ -821,11 +835,15 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, NF_CT_STAT_INC_ATOMIC(net, invalid); if (ret == -NF_DROP) NF_CT_STAT_INC_ATOMIC(net, drop); - return -ret; + ret = -ret; + goto out; } if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_REPLY, ct); +out: + if (tmpl) + nf_ct_put(tmpl); return ret; } @@ -864,7 +882,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, return; rcu_read_lock(); - __nf_ct_try_assign_helper(ct, GFP_ATOMIC); + __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); rcu_read_unlock(); } EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index c0e461f466ae..8144b0da5515 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -96,13 +96,22 @@ struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) } EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); -int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags) +int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, + gfp_t flags) { + struct nf_conntrack_helper *helper = NULL; + struct nf_conn_help *help; int ret = 0; - struct nf_conntrack_helper *helper; - struct nf_conn_help *help = nfct_help(ct); - helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + if (tmpl != NULL) { + help = nfct_help(tmpl); + if (help != NULL) + helper = help->helper; + } + + help = nfct_help(ct); + if (helper == NULL) + helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); if (helper == NULL) { if (help) rcu_assign_pointer(help->helper, NULL); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index f5c0b09e12f1..09044f9f4b2e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1249,7 +1249,7 @@ ctnetlink_create_conntrack(struct net *net, } } else { /* try an implicit helper assignation */ - err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); + err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); if (err < 0) goto err2; } -- GitLab From d4bfa033ed84e0ae446eff445d107ffd5ee78df3 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 29 Jan 2010 15:03:36 +0100 Subject: [PATCH 1519/3892] HID: make raw reports possible for both feature and output reports In commit 2da31939a42 ("Bluetooth: Implement raw output support for HIDP layer"), support for Bluetooth hid_output_raw_report was added, but it pushes the data to the intr socket instead of the ctrl one. This has been fixed by 6bf8268f9a91f1 ("Bluetooth: Use the control channel for raw HID reports") Still, it is necessary to distinguish whether the report in question should be either FEATURE or OUTPUT. For this, we have to extend the generic HID API, so that hid_output_raw_report() callback provides means to specify this value so that it can be passed down to lower level hardware drivers (currently Bluetooth and USB). Based on original patch by Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 2 +- drivers/hid/usbhid/hid-core.c | 5 +++-- include/linux/hid.h | 2 +- net/bluetooth/hidp/core.c | 17 ++++++++++++++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index cdd136942bca..d04476700b7b 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -134,7 +134,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t goto out; } - ret = dev->hid_output_raw_report(dev, buf, count); + ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: kfree(buf); return ret; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e2997a8d5e1b..caa16c057ce2 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -774,7 +774,8 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) return 0; } -static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) +static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count, + unsigned char report_type) { struct usbhid_device *usbhid = hid->driver_data; struct usb_device *dev = hid_to_usb_dev(hid); @@ -785,7 +786,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ((HID_OUTPUT_REPORT + 1) << 8) | *buf, + ((report_type + 1) << 8) | *buf, interface->desc.bInterfaceNumber, buf + 1, count - 1, USB_CTRL_SET_TIMEOUT); diff --git a/include/linux/hid.h b/include/linux/hid.h index 87093652dda8..3661a626941d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -501,7 +501,7 @@ struct hid_device { /* device report descriptor */ void (*hiddev_report_event) (struct hid_device *, struct hid_report *); /* handler for raw output data, used by hidraw */ - int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); + int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char); /* debugging support via debugfs */ unsigned short debug; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 6cf526d06e21..37ba153c4cd4 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -313,10 +313,21 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep return hidp_queue_report(session, buf, rsize); } -static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count) +static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, + unsigned char report_type) { - if (hidp_send_ctrl_message(hid->driver_data, - HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE, + switch (report_type) { + case HID_FEATURE_REPORT: + report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; + break; + case HID_OUTPUT_REPORT: + report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT; + break; + default: + return -EINVAL; + } + + if (hidp_send_ctrl_message(hid->driver_data, report_type, data, count)) return -ENOMEM; return count; -- GitLab From 46a709b900bfcf43244cd19cf3245c77484ec733 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 20 Jan 2010 12:00:53 +0000 Subject: [PATCH 1520/3892] HID: Implement Wacom quirk in the kernel The hid-wacom driver required user-space to poke at the tablet to make it send data about the cursor location. This patch makes it do the same thing but in the kernel. Signed-off-by: Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wacom.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 12dcda529201..b8778db720bc 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -156,7 +156,9 @@ static int wacom_probe(struct hid_device *hdev, struct hid_input *hidinput; struct input_dev *input; struct wacom_data *wdata; + char rep_data[2]; int ret; + int limit; wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); if (wdata == NULL) { @@ -166,6 +168,7 @@ static int wacom_probe(struct hid_device *hdev, hid_set_drvdata(hdev, wdata); + /* Parse the HID report now */ ret = hid_parse(hdev); if (ret) { dev_err(&hdev->dev, "parse failed\n"); @@ -178,6 +181,30 @@ static int wacom_probe(struct hid_device *hdev, goto err_free; } + /* Set Wacom mode2 */ + rep_data[0] = 0x03; rep_data[1] = 0x00; + limit = 3; + do { + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + } while (ret < 0 && limit-- > 0); + if (ret < 0) { + dev_err(&hdev->dev, "failed to poke device #1, %d\n", ret); + goto err_free; + } + + /* 0x06 - high reporting speed, 0x05 - low speed */ + rep_data[0] = 0x06; rep_data[1] = 0x00; + limit = 3; + do { + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + } while (ret < 0 && limit-- > 0); + if (ret < 0) { + dev_err(&hdev->dev, "failed to poke device #2, %d\n", ret); + goto err_free; + } + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; -- GitLab From f9ce7c283c16538955d5d094101889792bcde109 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 20 Jan 2010 12:01:53 +0000 Subject: [PATCH 1521/3892] HID: Enable Sixaxis controller over Bluetooth Now that hid_output_raw_report works, port the PS3 Sixaxis Bluetooth quirk from user-space, into kernel-space. Signed-off-by: Bastien Nocera Acked-by: Marcel Holtmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-sony.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eabe5f87c6c1..f7f80e1f1eef 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1340,6 +1340,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4e8450228a24..6ced140b1411 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -48,7 +48,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, * to "operational". Without this, the ps3 controller will not report any * events. */ -static int sony_set_operational(struct hid_device *hdev) +static int sony_set_operational_usb(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(intf); @@ -73,6 +73,12 @@ static int sony_set_operational(struct hid_device *hdev) return ret; } +static int sony_set_operational_bt(struct hid_device *hdev) +{ + unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; + return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); +} + static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -101,7 +107,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - ret = sony_set_operational(hdev); + switch (hdev->bus) { + case BUS_USB: + ret = sony_set_operational_usb(hdev); + break; + case BUS_BLUETOOTH: + ret = sony_set_operational_bt(hdev); + break; + default: + ret = 0; + } + if (ret < 0) goto err_stop; @@ -121,6 +137,7 @@ static void sony_remove(struct hid_device *hdev) static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, { } -- GitLab From 342f31e84eec9002b75f6fcdec6bd932ac77a390 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Feb 2010 15:52:31 +0100 Subject: [PATCH 1522/3892] HID: make Wacom modesetting failures non-fatal With Wacom tablet mode-setting moved from userspace into kernel, we don't have to consider failures of device queries through the _raw callback as hard failure, as the driver can safely continue anyway. This is consistent with the current USB driver in wacom_sys.c Reported-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/hid-wacom.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index b8778db720bc..8d3b46f5d149 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -181,6 +181,11 @@ static int wacom_probe(struct hid_device *hdev, goto err_free; } + /* + * Note that if the raw queries fail, it's not a hard failure and it + * is safe to continue + */ + /* Set Wacom mode2 */ rep_data[0] = 0x03; rep_data[1] = 0x00; limit = 3; @@ -188,10 +193,8 @@ static int wacom_probe(struct hid_device *hdev, ret = hdev->hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT); } while (ret < 0 && limit-- > 0); - if (ret < 0) { - dev_err(&hdev->dev, "failed to poke device #1, %d\n", ret); - goto err_free; - } + if (ret < 0) + dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret); /* 0x06 - high reporting speed, 0x05 - low speed */ rep_data[0] = 0x06; rep_data[1] = 0x00; @@ -200,10 +203,8 @@ static int wacom_probe(struct hid_device *hdev, ret = hdev->hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT); } while (ret < 0 && limit-- > 0); - if (ret < 0) { - dev_err(&hdev->dev, "failed to poke device #2, %d\n", ret); - goto err_free; - } + if (ret < 0) + dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret); hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; -- GitLab From 2dbf209d7a7ab94266b936bd2da6a4026c279992 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Feb 2010 16:11:12 +0100 Subject: [PATCH 1523/3892] HID: make full-fledged hid-bus drivers properly selectable For historical reasons, we don't have most of the in-tree drivers residing on hid-bus properly selectable in kernel configuration unless CONFIG_EMBEDDED is set. This has been introduced on Linus' request from 14 Oct === As to the Kconfig options - do they really add so much space that you need to ask for the quirks? You didn't use to. Can you make the questions depend on EMBEDDED, or at least on the HID_COMPAT thing or whatever? === This still makes perfect sense for small and tiny drivers, which just fix report descriptors, fix up HID->input mappings that slightly violates HUT standard, send one extra packet to the device that is needed before it becomes functional, etc. Since then, we have been gathering more and more HID-bus drivers, which are full-fledged drivers. For these, the size argument becomes more valid. Plus the devices are much more special than "just violates HID specification in this one or two tiny unimportant points". Therefore I am marking such drivers as properly selectable no matter the setting of CONFIG_EMBEDDED, while keeping all the small and tiny ones compiled by default. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 139668d6382a..617ed7db67d1 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -212,9 +212,8 @@ config HID_MONTEREY Support for Monterey Genius KB29E. config HID_NTRIG - tristate "NTrig" if EMBEDDED + tristate "NTrig" depends on USB_HID - default !EMBEDDED ---help--- Support for N-Trig touch screen. @@ -338,9 +337,8 @@ config THRUSTMASTER_FF Rumble Force or Force Feedback Wheel. config HID_WACOM - tristate "Wacom Bluetooth devices support" if EMBEDDED + tristate "Wacom Bluetooth devices support" depends on BT_HIDP - default !EMBEDDED ---help--- Support for Wacom Graphire Bluetooth tablet. -- GitLab From 84f3bb9ae9db90f7fb15d98b55279a58ab1b2363 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 Feb 2010 17:17:06 +0100 Subject: [PATCH 1524/3892] netfilter: xtables: add CT target Add a new target for the raw table, which can be used to specify conntrack parameters for specific connections, f.i. the conntrack helper. The target attaches a "template" connection tracking entry to the skb, which is used by the conntrack core when initializing a new conntrack. Signed-off-by: Patrick McHardy --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_CT.h | 17 +++ include/net/netfilter/nf_conntrack_helper.h | 3 + net/netfilter/Kconfig | 12 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_helper.c | 19 +++ net/netfilter/xt_CT.c | 158 ++++++++++++++++++++ 7 files changed, 211 insertions(+) create mode 100644 include/linux/netfilter/xt_CT.h create mode 100644 net/netfilter/xt_CT.c diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 2aea50399c0b..a5a63e41b8af 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -6,6 +6,7 @@ header-y += nfnetlink_queue.h header-y += xt_CLASSIFY.h header-y += xt_CONNMARK.h header-y += xt_CONNSECMARK.h +header-y += xt_CT.h header-y += xt_DSCP.h header-y += xt_LED.h header-y += xt_MARK.h diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h new file mode 100644 index 000000000000..7fd0effe1316 --- /dev/null +++ b/include/linux/netfilter/xt_CT.h @@ -0,0 +1,17 @@ +#ifndef _XT_CT_H +#define _XT_CT_H + +#define XT_CT_NOTRACK 0x1 + +struct xt_ct_target_info { + u_int16_t flags; + u_int16_t __unused; + u_int32_t ct_events; + u_int32_t exp_events; + char helper[16]; + + /* Used internally by the kernel */ + struct nf_conn *ct __attribute__((aligned(8))); +}; + +#endif /* _XT_CT_H */ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index e17aaa3e19fd..32c305dbdab6 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -42,6 +42,9 @@ struct nf_conntrack_helper { extern struct nf_conntrack_helper * __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum); +extern struct nf_conntrack_helper * +nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum); + extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 634d14affc8d..4469d45261f4 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -341,6 +341,18 @@ config NETFILTER_XT_TARGET_CONNSECMARK To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_CT + tristate '"CT" target support' + depends on NF_CONNTRACK + depends on IP_NF_RAW || IP6_NF_RAW + depends on NETFILTER_ADVANCED + help + This options adds a `CT' target, which allows to specify initial + connection tracking parameters like events to be delivered and + the helper to be used. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_TARGET_DSCP tristate '"DSCP" and "TOS" target support' depends on IP_NF_MANGLE || IP6_NF_MANGLE diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 49f62ee4e9ff..f873644f02f6 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o +obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 8144b0da5515..a74a5769877b 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -83,6 +83,25 @@ __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum) } EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find); +struct nf_conntrack_helper * +nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum) +{ + struct nf_conntrack_helper *h; + + h = __nf_conntrack_helper_find(name, l3num, protonum); +#ifdef CONFIG_MODULES + if (h == NULL) { + if (request_module("nfct-helper-%s", name) == 0) + h = __nf_conntrack_helper_find(name, l3num, protonum); + } +#endif + if (h != NULL && !try_module_get(h->me)) + h = NULL; + + return h; +} +EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get); + struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) { struct nf_conn_help *help; diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c new file mode 100644 index 000000000000..8183a054256f --- /dev/null +++ b/net/netfilter/xt_CT.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2010 Patrick McHardy + * + * 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 +#include +#include +#include +#include + +static unsigned int xt_ct_target(struct sk_buff *skb, + const struct xt_target_param *par) +{ + const struct xt_ct_target_info *info = par->targinfo; + struct nf_conn *ct = info->ct; + + /* Previously seen (loopback)? Ignore. */ + if (skb->nfct != NULL) + return XT_CONTINUE; + + atomic_inc(&ct->ct_general.use); + skb->nfct = &ct->ct_general; + skb->nfctinfo = IP_CT_NEW; + + return XT_CONTINUE; +} + +static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) +{ + if (par->family == AF_INET) { + const struct ipt_entry *e = par->entryinfo; + + if (e->ip.invflags & IPT_INV_PROTO) + return 0; + return e->ip.proto; + } else if (par->family == AF_INET6) { + const struct ip6t_entry *e = par->entryinfo; + + if (e->ipv6.invflags & IP6T_INV_PROTO) + return 0; + return e->ipv6.proto; + } else + return 0; +} + +static bool xt_ct_tg_check(const struct xt_tgchk_param *par) +{ + struct xt_ct_target_info *info = par->targinfo; + struct nf_conntrack_tuple t; + struct nf_conn_help *help; + struct nf_conn *ct; + u8 proto; + + if (info->flags & ~XT_CT_NOTRACK) + return false; + + if (info->flags & XT_CT_NOTRACK) { + ct = &nf_conntrack_untracked; + atomic_inc(&ct->ct_general.use); + goto out; + } + + if (nf_ct_l3proto_try_module_get(par->family) < 0) + goto err1; + + memset(&t, 0, sizeof(t)); + ct = nf_conntrack_alloc(par->net, &t, &t, GFP_KERNEL); + if (IS_ERR(ct)) + goto err2; + + if ((info->ct_events || info->exp_events) && + !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, + GFP_KERNEL)) + goto err3; + + if (info->helper[0]) { + proto = xt_ct_find_proto(par); + if (!proto) + goto err3; + + help = nf_ct_helper_ext_add(ct, GFP_KERNEL); + if (help == NULL) + goto err3; + + help->helper = nf_conntrack_helper_try_module_get(info->helper, + par->family, + proto); + if (help->helper == NULL) + goto err3; + } + + __set_bit(IPS_TEMPLATE_BIT, &ct->status); + __set_bit(IPS_CONFIRMED_BIT, &ct->status); +out: + info->ct = ct; + return true; + +err3: + nf_conntrack_free(ct); +err2: + nf_ct_l3proto_module_put(par->family); +err1: + return false; +} + +static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) +{ + struct xt_ct_target_info *info = par->targinfo; + struct nf_conn *ct = info->ct; + struct nf_conn_help *help; + + if (ct != &nf_conntrack_untracked) { + help = nfct_help(ct); + if (help) + module_put(help->helper->me); + + nf_ct_l3proto_module_put(par->family); + } + nf_ct_put(info->ct); +} + +static struct xt_target xt_ct_tg __read_mostly = { + .name = "CT", + .family = NFPROTO_UNSPEC, + .targetsize = XT_ALIGN(sizeof(struct xt_ct_target_info)), + .checkentry = xt_ct_tg_check, + .destroy = xt_ct_tg_destroy, + .target = xt_ct_target, + .table = "raw", + .me = THIS_MODULE, +}; + +static int __init xt_ct_tg_init(void) +{ + return xt_register_target(&xt_ct_tg); +} + +static void __exit xt_ct_tg_exit(void) +{ + xt_unregister_target(&xt_ct_tg); +} + +module_init(xt_ct_tg_init); +module_exit(xt_ct_tg_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Xtables: connection tracking target"); +MODULE_ALIAS("ipt_CT"); +MODULE_ALIAS("ip6t_CT"); -- GitLab From 3cebbb81c7e75321e25cc586d07a25a3d98278fc Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 3 Feb 2010 17:20:14 +0100 Subject: [PATCH 1525/3892] kconfig: Simplify LSMOD= handling Signed-off-by: Michal Marek LKML-Reference: <20100203162014.GA10956@sepie.suse.cz> Signed-off-by: Steven Rostedt --- scripts/kconfig/Makefile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 85b906547845..186c46604d06 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -32,11 +32,10 @@ silentoldconfig: $(obj)/conf # if no path is given, then use src directory to find file ifdef LSMOD -LSMOD_F = $(shell if [ `basename $(LSMOD)` == $(LSMOD) ]; then \ - echo $(objtree)/$(LSMOD); \ - else \ - echo $(LSMOD); \ - fi) +LSMOD_F := $(LSMOD) +ifeq ($(findstring /,$(LSMOD)),) + LSMOD_F := $(objtree)/$(LSMOD) +endif endif localmodconfig: $(obj)/streamline_config.pl $(obj)/conf -- GitLab From 0f69d9782c6e6a7b0e60113a850845bc642c3f4e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Feb 2010 17:37:23 +0100 Subject: [PATCH 1526/3892] ASoC: fix compilation breakage in sound/soc/sh/fsi.c ctrl_outl() has become void at some point, which breaks compilation of fsi.c. Make writing functions void, as their output is anyway not evaluated, and use __raw_writel and __raw_readl instead of deprecated ctrl_outl and ctrl_inl respectively. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ebf358808db1..3c36d24a6c20 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -120,35 +120,35 @@ struct fsi_master { ************************************************************************/ -static int __fsi_reg_write(u32 reg, u32 data) +static void __fsi_reg_write(u32 reg, u32 data) { /* valid data area is 24bit */ data &= 0x00ffffff; - return ctrl_outl(data, reg); + __raw_writel(data, reg); } static u32 __fsi_reg_read(u32 reg) { - return ctrl_inl(reg); + return __raw_readl(reg); } -static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) +static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) { u32 val = __fsi_reg_read(reg); val &= ~mask; val |= data & mask; - return __fsi_reg_write(reg, val); + __fsi_reg_write(reg, val); } -static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) +static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) { if (reg > REG_END) - return -1; + return; - return __fsi_reg_write((u32)(fsi->base + reg), data); + __fsi_reg_write((u32)(fsi->base + reg), data); } static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) @@ -159,28 +159,25 @@ static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) return __fsi_reg_read((u32)(fsi->base + reg)); } -static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) +static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) { if (reg > REG_END) - return -1; + return; - return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); + __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); } -static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data) +static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data) { - int ret; unsigned long flags; if ((reg < MREG_START) || (reg > MREG_END)) - return -1; + return; spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_write((u32)(master->base + reg), data); + __fsi_reg_write((u32)(master->base + reg), data); spin_unlock_irqrestore(&master->lock, flags); - - return ret; } static u32 fsi_master_read(struct fsi_master *master, u32 reg) @@ -199,21 +196,18 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg) return ret; } -static int fsi_master_mask_set(struct fsi_master *master, +static void fsi_master_mask_set(struct fsi_master *master, u32 reg, u32 mask, u32 data) { - int ret; unsigned long flags; if ((reg < MREG_START) || (reg > MREG_END)) - return -1; + return; spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_mask_set((u32)(master->base + reg), mask, data); + __fsi_reg_mask_set((u32)(master->base + reg), mask, data); spin_unlock_irqrestore(&master->lock, flags); - - return ret; } /************************************************************************ -- GitLab From 8c961bcca1d10be4f2c06375eb561679167653a0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Feb 2010 18:46:10 +0000 Subject: [PATCH 1527/3892] ASoC: Allow CODECs to ask soc-cache to suppress physical writes Currently the soc-cache code will always write to the device, meaning that we need the device to be powered and active at pretty much all times the system is active. Allowing cache only writes lays some groundwork for future enhancements to allow devices to be put into a full off state when the audio subsystem is idle. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 1 + sound/soc/soc-cache.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4bbeb9f83ece..4e8f14bc8ed3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -423,6 +423,7 @@ struct snd_soc_codec { short reg_cache_step; unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ + unsigned int cache_only:1; /* Suppress writes to hardware */ /* dapm */ u32 pop_time; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 097e33510a7a..84b6916db87d 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -38,6 +38,10 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; + + if (codec->cache_only) + return 0; + ret = codec->hw_write(codec->control_data, data, 2); if (ret == 2) return 0; @@ -100,6 +104,10 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; + + if (codec->cache_only) + return 0; + ret = codec->hw_write(codec->control_data, data, 2); if (ret == 2) return 0; @@ -153,6 +161,9 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; + if (codec->cache_only) + return 0; + if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; else @@ -181,6 +192,9 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, if (!snd_soc_codec_volatile_register(codec, reg)) reg_cache[reg] = value; + if (codec->cache_only) + return 0; + if (codec->hw_write(codec->control_data, data, 3) == 3) return 0; else @@ -193,10 +207,14 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, u16 *cache = codec->reg_cache; if (reg >= codec->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg)) + snd_soc_codec_volatile_register(codec, reg)) { + if (codec->cache_only) + return -EINVAL; + return codec->hw_read(codec, reg); - else + } else { return cache[reg]; + } } #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) @@ -294,6 +312,10 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, reg &= 0xff; if (reg < codec->reg_cache_size) cache[reg] = value; + + if (codec->cache_only) + return 0; + ret = codec->hw_write(codec->control_data, data, 3); if (ret == 3) return 0; -- GitLab From 07fec73625dc0db6f9aed68019918208a2ca53f5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Feb 2010 11:43:49 +1100 Subject: [PATCH 1528/3892] xfs: log changed inodes instead of writing them synchronously When an inode has already be flushed delayed write, xfs_inode_clean() returns true and hence xfs_fs_write_inode() can return on a synchronous inode write without having written the inode. Currently these sycnhronous writes only come sync(1), unmount, a sycnhronous NFS export and cachefiles so should be relatively rare and out of common performance paths. Realistically, a synchronous inode write is not necessary here; we can avoid writing the inode by logging any non-transactional changes that are pending. This needs to be done with synchronous transactions, but it avoids seeking between the log and inode clusters as we do now. We don't force the log if the inode is pinned, though, so this differs from the fsync case. For normal sys_sync and unmount behaviour this is fine because we do a synchronous log force in xfs_sync_data which is called from the ->sync_fs code. It does however break the NFS synchronous export guarantees for now, but work is under way to fix this at a higher level or for the higher level to provide an additional flag in the writeback control to tell us that a log force is needed. Portions of this patch are based on work from Dave Chinner. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Reviewed-by: Alex Elder --- fs/xfs/linux-2.6/xfs_super.c | 111 ++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 3b5b46b8e3b9..25ea2408118f 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1021,12 +1021,45 @@ xfs_fs_dirty_inode( XFS_I(inode)->i_update_core = 1; } -/* - * Attempt to flush the inode, this will actually fail - * if the inode is pinned, but we dirty the inode again - * at the point when it is unpinned after a log write, - * since this is when the inode itself becomes flushable. - */ +STATIC int +xfs_log_inode( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + int error; + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); + error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); + + if (error) { + xfs_trans_cancel(tp, 0); + /* we need to return with the lock hold shared */ + xfs_ilock(ip, XFS_ILOCK_SHARED); + return error; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Note - it's possible that we might have pushed ourselves out of the + * way during trans_reserve which would flush the inode. But there's + * no guarantee that the inode buffer has actually gone out yet (it's + * delwri). Plus the buffer could be pinned anyway if it's part of + * an inode in another recent transaction. So we play it safe and + * fire off the transaction anyway. + */ + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0); + xfs_ilock_demote(ip, XFS_ILOCK_EXCL); + + return error; +} + STATIC int xfs_fs_write_inode( struct inode *inode, @@ -1034,7 +1067,7 @@ xfs_fs_write_inode( { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; - int error = 0; + int error = EAGAIN; xfs_itrace_entry(ip); @@ -1045,35 +1078,55 @@ xfs_fs_write_inode( error = xfs_wait_on_pages(ip, 0, -1); if (error) goto out; - } - - /* - * Bypass inodes which have already been cleaned by - * the inode flush clustering code inside xfs_iflush - */ - if (xfs_inode_clean(ip)) - goto out; - /* - * We make this non-blocking if the inode is contended, return - * EAGAIN to indicate to the caller that they did not succeed. - * This prevents the flush path from blocking on inodes inside - * another operation right now, they get caught later by xfs_sync. - */ - if (sync) { + /* + * Make sure the inode has hit stable storage. By using the + * log and the fsync transactions we reduce the IOs we have + * to do here from two (log and inode) to just the log. + * + * Note: We still need to do a delwri write of the inode after + * this to flush it to the backing buffer so that bulkstat + * works properly if this is the first time the inode has been + * written. Because we hold the ilock atomically over the + * transaction commit and the inode flush we are guaranteed + * that the inode is not pinned when it returns. If the flush + * lock is already held, then the inode has already been + * flushed once and we don't need to flush it again. Hence + * the code will only flush the inode if it isn't already + * being flushed. + */ xfs_ilock(ip, XFS_ILOCK_SHARED); - xfs_iflock(ip); - - error = xfs_iflush(ip, SYNC_WAIT); + if (ip->i_update_core) { + error = xfs_log_inode(ip); + if (error) + goto out_unlock; + } } else { - error = EAGAIN; + /* + * We make this non-blocking if the inode is contended, return + * EAGAIN to indicate to the caller that they did not succeed. + * This prevents the flush path from blocking on inodes inside + * another operation right now, they get caught later by xfs_sync. + */ if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) goto out; - if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) - goto out_unlock; + } + + if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) + goto out_unlock; - error = xfs_iflush(ip, 0); + /* + * Now we have the flush lock and the inode is not pinned, we can check + * if the inode is really clean as we know that there are no pending + * transaction completions, it is not waiting on the delayed write + * queue and there is no IO in progress. + */ + if (xfs_inode_clean(ip)) { + xfs_ifunlock(ip); + error = 0; + goto out_unlock; } + error = xfs_iflush(ip, 0); out_unlock: xfs_iunlock(ip, XFS_ILOCK_SHARED); -- GitLab From 5322892d867e186c6b4c5fff5c99ea4863696a60 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 4 Feb 2010 10:09:14 +1100 Subject: [PATCH 1529/3892] xfs: kill xfs_bawrite There are no more users of this function left in the XFS code now that we've switched everything to delayed write flushing. Remove it. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_buf.c | 19 ------------------- fs/xfs/linux-2.6/xfs_buf.h | 1 - 2 files changed, 20 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 4556a4c31e36..d50df3a8101c 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1078,25 +1078,6 @@ xfs_bwrite( return error; } -int -xfs_bawrite( - void *mp, - struct xfs_buf *bp) -{ - trace_xfs_buf_bawrite(bp, _RET_IP_); - - ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL); - - xfs_buf_delwri_dequeue(bp); - - bp->b_flags &= ~(XBF_READ | XBF_DELWRI | XBF_READ_AHEAD); - bp->b_flags |= (XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES); - - bp->b_mount = mp; - bp->b_strat = xfs_bdstrat_cb; - return xfs_bdstrat_cb(bp); -} - void xfs_bdwrite( void *mp, diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index be45e8c5768d..386e7361e50e 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -233,7 +233,6 @@ extern void xfs_buf_unlock(xfs_buf_t *); /* Buffer Read and Write Routines */ extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); -extern int xfs_bawrite(void *mp, xfs_buf_t *bp); extern void xfs_bdwrite(void *mp, xfs_buf_t *bp); extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *); -- GitLab From e054f1647162d7098a9ff619405a72bd7c417213 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 4 Feb 2010 11:39:13 +1100 Subject: [PATCH 1530/3892] crypto: geode-aes - Fix cip/blk confusion a crypto_cipher cip member was set where a crypto_cipher blk members should have been. Signed-off-by: Roel Kluin Signed-off-by: Herbert Xu --- drivers/crypto/geode-aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 03e71b1a5128..c7a5a43ba691 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -141,7 +141,7 @@ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, ret = crypto_cipher_setkey(op->fallback.cip, key, len); if (ret) { tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK); } return ret; } -- GitLab From 5a1436beec5744029f3ac90b6fe71a698dcd6155 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 4 Feb 2010 11:40:17 +1100 Subject: [PATCH 1531/3892] crypto: pcrypt - call the complete function on error This fixes three forgotten calls to the complete function in the error case. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu --- crypto/pcrypt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index b9527d05e17d..80201241b698 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -114,7 +114,7 @@ static void pcrypt_aead_enc(struct padata_priv *padata) padata->info = crypto_aead_encrypt(req); - if (padata->info) + if (padata->info == -EINPROGRESS) return; padata_do_serial(padata); @@ -158,7 +158,7 @@ static void pcrypt_aead_dec(struct padata_priv *padata) padata->info = crypto_aead_decrypt(req); - if (padata->info) + if (padata->info == -EINPROGRESS) return; padata_do_serial(padata); @@ -202,7 +202,7 @@ static void pcrypt_aead_givenc(struct padata_priv *padata) padata->info = crypto_aead_givencrypt(req); - if (padata->info) + if (padata->info == -EINPROGRESS) return; padata_do_serial(padata); -- GitLab From 76802851b6e1b78b614ba611d6b5d27a83f60ded Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 31 Jan 2010 02:58:19 +0000 Subject: [PATCH 1532/3892] MCS7830 USB-Ether: add Rx error support ChangeLog: - evaluate Rx error statistics from trailing Rx status byte - add driver TODO list - add myself to authors Quilt series run-tested, based on 2.6.33-rc4 (net-2.6.git mcs7830 has idle history, should be good to go). Signed-off-by: Andreas Mohr Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 87374317f480..22cccda33366 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -3,11 +3,27 @@ * * based on usbnet.c, asix.c and the vendor provided mcs7830 driver * + * Copyright (C) 2010 Andreas Mohr * Copyright (C) 2006 Arnd Bergmann * Copyright (C) 2003-2005 David Hollis * Copyright (C) 2005 Phil Chang * Copyright (c) 2002-2003 TiVo Inc. * + * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). + * + * TODO: + * - add .reset_resume support (iface is _gone_ after resume w/ power loss) + * - verify that mcs7830_get_regs() does have same output pre-/post-suspend + * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) + * - implement ethtool_ops get_pauseparam/set_pauseparam + * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!) + * - implement get_eeprom/[set_eeprom] + * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII) + * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs, + * can access only ~ 24, remaining user buffer is uninitialized garbage + * - anything else? + * + * * 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 @@ -83,6 +99,17 @@ enum { HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, }; +/* Trailing status byte in Ethernet Rx frame */ +enum { + MCS7830_RX_SHORT_FRAME = 0x01, /* < 64 bytes */ + MCS7830_RX_LENGTH_ERROR = 0x02, /* framelen != Ethernet length field */ + MCS7830_RX_ALIGNMENT_ERROR = 0x04, /* non-even number of nibbles */ + MCS7830_RX_CRC_ERROR = 0x08, + MCS7830_RX_LARGE_FRAME = 0x10, /* > 1518 bytes */ + MCS7830_RX_FRAME_CORRECT = 0x20, /* frame is correct */ + /* [7:6] reserved */ +}; + struct mcs7830_data { u8 multi_filter[8]; u8 config; @@ -539,9 +566,23 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_trim(skb, skb->len - 1); status = skb->data[skb->len]; - if (status != 0x20) + if (status != MCS7830_RX_FRAME_CORRECT) { dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); + /* hmm, perhaps usbnet.c already sees a globally visible + frame error and increments rx_errors on its own already? */ + dev->net->stats.rx_errors++; + + if (status & (MCS7830_RX_SHORT_FRAME + |MCS7830_RX_LENGTH_ERROR + |MCS7830_RX_LARGE_FRAME)) + dev->net->stats.rx_length_errors++; + if (status & MCS7830_RX_ALIGNMENT_ERROR) + dev->net->stats.rx_frame_errors++; + if (status & MCS7830_RX_CRC_ERROR) + dev->net->stats.rx_crc_errors++; + } + return skb->len > 0; } -- GitLab From 00e499131e250324a89c93d5dd88c8f2b4bf6dbb Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 31 Jan 2010 02:58:26 +0000 Subject: [PATCH 1533/3892] MCS7830 USB-Ether: Spelling corrections ChangeLog: - spelling corrections / whitespace Signed-off-by: Andreas Mohr Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 22cccda33366..cb164d6c9b51 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -1,5 +1,5 @@ /* - * MosChips MCS7830 based USB 2.0 Ethernet Devices + * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices * * based on usbnet.c, asix.c and the vendor provided mcs7830 driver * @@ -71,7 +71,7 @@ ADVERTISE_100HALF | ADVERTISE_10FULL | \ ADVERTISE_10HALF | ADVERTISE_CSMA) -/* HIF_REG_XX coressponding index value */ +/* HIF_REG_XX corresponding index value */ enum { HIF_REG_MULTICAST_HASH = 0x00, HIF_REG_PACKET_GAP1 = 0x08, @@ -92,7 +92,7 @@ enum { HIF_REG_CONFIG_TXENABLE = 0x08, HIF_REG_CONFIG_SLEEPMODE = 0x04, HIF_REG_CONFIG_ALLMULTICAST = 0x02, - HIF_REG_CONFIG_PROMISCIOUS = 0x01, + HIF_REG_CONFIG_PROMISCUOUS = 0x01, HIF_REG_ETHERNET_ADDR = 0x0f, HIF_REG_22 = 0x15, HIF_REG_PAUSE_THRESHOLD = 0x16, @@ -417,7 +417,7 @@ static void mcs7830_set_multicast(struct net_device *net) data->config |= HIF_REG_CONFIG_ALLMULTICAST; if (net->flags & IFF_PROMISC) { - data->config |= HIF_REG_CONFIG_PROMISCIOUS; + data->config |= HIF_REG_CONFIG_PROMISCUOUS; } else if (net->flags & IFF_ALLMULTI || net->mc_count > MCS7830_MAX_MCAST) { data->config |= HIF_REG_CONFIG_ALLMULTICAST; @@ -522,7 +522,7 @@ static const struct net_device_ops mcs7830_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mcs7830_ioctl, .ndo_set_multicast_list = mcs7830_set_multicast, - .ndo_set_mac_address = mcs7830_set_mac_address, + .ndo_set_mac_address = mcs7830_set_mac_address, }; static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) @@ -553,7 +553,7 @@ out: return ret; } -/* The chip always appends a status bytes that we need to strip */ +/* The chip always appends a status byte that we need to strip */ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { u8 status; -- GitLab From c774651a5ffc0250f82d72730753f196c86884c5 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 31 Jan 2010 02:58:33 +0000 Subject: [PATCH 1534/3892] MCS7830 USB-Ether: change register define ChangeLog: - rename register, add comment Signed-off-by: Andreas Mohr Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index cb164d6c9b51..36a029218e3d 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -85,6 +85,7 @@ enum { HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, HIF_REG_CONFIG = 0x0e, + /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */ HIF_REG_CONFIG_CFG = 0x80, HIF_REG_CONFIG_SPEED100 = 0x40, HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, @@ -94,7 +95,7 @@ enum { HIF_REG_CONFIG_ALLMULTICAST = 0x02, HIF_REG_CONFIG_PROMISCUOUS = 0x01, HIF_REG_ETHERNET_ADDR = 0x0f, - HIF_REG_22 = 0x15, + HIF_REG_FRAME_DROP_COUNTER = 0x15, /* 0..ff; reset: 0 */ HIF_REG_PAUSE_THRESHOLD = 0x16, HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, }; @@ -334,7 +335,7 @@ static int mcs7830_get_rev(struct usbnet *dev) { u8 dummy[2]; int ret; - ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); + ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy); if (ret > 0) return 2; /* Rev C or later */ return 1; /* earlier revision */ -- GitLab From ace2a4d0fbf868c00625a8fd91c44ad9fabe7012 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 31 Jan 2010 02:58:42 +0000 Subject: [PATCH 1535/3892] MCS7830 USB-Ether: resume _with_ working link, via .reset_resume support ChangeLog: Implement .reset_resume support to retain a live network connection during suspend despite USB power loss. - rework operation to reference cached data in mcs7830_data and netdev->dev_addr - update netdev->dev_addr only in case new MAC was set successfully . Tests done: . ethtool -d pre-/post-suspend: register values match . running ssh session suspend, resume: works . ifdown device, suspend, resume: works . ifup, suspend, unplug, resume: WORKS (eth1 is removed, re-ifup of eth1 after card replug works) . verified identical MAC in ifconfig post-resume (ok, should be verified on network side to be fully certain...) Keywords: suspend resume network connection dead interface down Signed-off-by: Andreas Mohr Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 190 ++++++++++++++++++++++++-------------- 1 file changed, 123 insertions(+), 67 deletions(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 36a029218e3d..6fc098fe9ff7 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -12,8 +12,6 @@ * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). * * TODO: - * - add .reset_resume support (iface is _gone_ after resume w/ power loss) - * - verify that mcs7830_get_regs() does have same output pre-/post-suspend * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) * - implement ethtool_ops get_pauseparam/set_pauseparam * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!) @@ -137,7 +135,7 @@ static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) return ret; } -static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) +static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data) { struct usb_device *xdev = dev->udev; int ret; @@ -211,13 +209,43 @@ out: usb_free_urb(urb); } -static int mcs7830_get_address(struct usbnet *dev) +static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr) +{ + int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); + if (ret < 0) + return ret; + return 0; +} + +static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr) +{ + int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); + + if (ret < 0) + return ret; + return 0; +} + +static int mcs7830_set_mac_address(struct net_device *netdev, void *p) { int ret; - ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, - dev->net->dev_addr); + struct usbnet *dev = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + ret = mcs7830_hif_set_mac_address(dev, addr->sa_data); + if (ret < 0) return ret; + + /* it worked --> adopt it on netdev side */ + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + return 0; } @@ -359,33 +387,6 @@ static void mcs7830_rev_C_fixup(struct usbnet *dev) } } -static int mcs7830_init_dev(struct usbnet *dev) -{ - int ret; - int retry; - - /* Read MAC address from EEPROM */ - ret = -EINVAL; - for (retry = 0; retry < 5 && ret; retry++) - ret = mcs7830_get_address(dev); - if (ret) { - dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); - goto out; - } - - /* Set up PHY */ - ret = mcs7830_set_autoneg(dev, 0); - if (ret) { - dev_info(&dev->udev->dev, "Cannot set autoneg\n"); - goto out; - } - - mcs7830_rev_C_fixup(dev); - ret = 0; -out: - return ret; -} - static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, int location) { @@ -406,11 +407,33 @@ static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -/* credits go to asix_set_multicast */ -static void mcs7830_set_multicast(struct net_device *net) +static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev) +{ + return (struct mcs7830_data *)&dev->data; +} + +static void mcs7830_hif_update_multicast_hash(struct usbnet *dev) +{ + struct mcs7830_data *data = mcs7830_get_data(dev); + mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, + sizeof data->multi_filter, + data->multi_filter); +} + +static void mcs7830_hif_update_config(struct usbnet *dev) +{ + /* implementation specific to data->config + (argument needs to be heap-based anyway - USB DMA!) */ + struct mcs7830_data *data = mcs7830_get_data(dev); + mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); +} + +static void mcs7830_data_set_multicast(struct net_device *net) { struct usbnet *dev = netdev_priv(net); - struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; + struct mcs7830_data *data = mcs7830_get_data(dev); + + memset(data->multi_filter, 0, sizeof data->multi_filter); data->config = HIF_REG_CONFIG_TXENABLE; @@ -433,21 +456,51 @@ static void mcs7830_set_multicast(struct net_device *net) u32 crc_bits; int i; - memset(data->multi_filter, 0, sizeof data->multi_filter); - /* Build the multicast hash filter. */ for (i = 0; i < net->mc_count; i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); mc_list = mc_list->next; } + } +} - mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, - sizeof data->multi_filter, - data->multi_filter); +static int mcs7830_apply_base_config(struct usbnet *dev) +{ + int ret; + + /* re-configure known MAC (suspend case etc.) */ + ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr); + if (ret) { + dev_info(&dev->udev->dev, "Cannot set MAC address\n"); + goto out; } - mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); + /* Set up PHY */ + ret = mcs7830_set_autoneg(dev, 0); + if (ret) { + dev_info(&dev->udev->dev, "Cannot set autoneg\n"); + goto out; + } + + mcs7830_hif_update_multicast_hash(dev); + mcs7830_hif_update_config(dev); + + mcs7830_rev_C_fixup(dev); + ret = 0; +out: + return ret; +} + +/* credits go to asix_set_multicast */ +static void mcs7830_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + mcs7830_data_set_multicast(net); + + mcs7830_hif_update_multicast_hash(dev); + mcs7830_hif_update_config(dev); } static int mcs7830_get_regs_len(struct net_device *net) @@ -491,29 +544,6 @@ static const struct ethtool_ops mcs7830_ethtool_ops = { .nway_reset = usbnet_nway_reset, }; -static int mcs7830_set_mac_address(struct net_device *netdev, void *p) -{ - int ret; - struct usbnet *dev = netdev_priv(netdev); - struct sockaddr *addr = p; - - if (netif_running(netdev)) - return -EBUSY; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, - netdev->dev_addr); - - if (ret < 0) - return ret; - - return 0; -} - static const struct net_device_ops mcs7830_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, @@ -530,14 +560,25 @@ static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) { struct net_device *net = dev->net; int ret; + int retry; - ret = mcs7830_init_dev(dev); + /* Initial startup: Gather MAC address setting from EEPROM */ + ret = -EINVAL; + for (retry = 0; retry < 5 && ret; retry++) + ret = mcs7830_hif_get_mac_address(dev, net->dev_addr); + if (ret) { + dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); + goto out; + } + + mcs7830_data_set_multicast(net); + + ret = mcs7830_apply_base_config(dev); if (ret) goto out; net->ethtool_ops = &mcs7830_ethtool_ops; net->netdev_ops = &mcs7830_netdev_ops; - mcs7830_set_multicast(net); /* reserve space for the status byte on rx */ dev->rx_urb_size = ETH_FRAME_LEN + 1; @@ -622,6 +663,20 @@ static const struct usb_device_id products[] = { }; MODULE_DEVICE_TABLE(usb, products); +static int mcs7830_reset_resume (struct usb_interface *intf) +{ + /* YES, this function is successful enough that ethtool -d + does show same output pre-/post-suspend */ + + struct usbnet *dev = usb_get_intfdata(intf); + + mcs7830_apply_base_config(dev); + + usbnet_resume(intf); + + return 0; +} + static struct usb_driver mcs7830_driver = { .name = driver_name, .id_table = products, @@ -629,6 +684,7 @@ static struct usb_driver mcs7830_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .reset_resume = mcs7830_reset_resume, }; static int __init mcs7830_init(void) -- GitLab From 2e02644abc4b3574533b027782820b5a6dfe1920 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Mon, 1 Feb 2010 10:29:29 +0000 Subject: [PATCH 1536/3892] cxgb3: add memory barriers Add memory barriers to fix crashes observed on newest PowerPC platforms. The HW and driver state of the receive rings were getting out of sync. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/sge.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index bdbd14727e4b..4cf9b7962afa 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -480,6 +480,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) { if (q->pend_cred >= q->credits / 4) { q->pend_cred = 0; + wmb(); t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); } } @@ -2282,11 +2283,14 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, while (likely(budget_left && is_new_response(r, q))) { int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; struct sk_buff *skb = NULL; - u32 len, flags = ntohl(r->flags); - __be32 rss_hi = *(const __be32 *)r, - rss_lo = r->rss_hdr.rss_hash_val; + u32 len, flags; + __be32 rss_hi, rss_lo; + rmb(); eth = r->rss_hdr.opcode == CPL_RX_PKT; + rss_hi = *(const __be32 *)r; + rss_lo = r->rss_hdr.rss_hash_val; + flags = ntohl(r->flags); if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); @@ -2497,7 +2501,10 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, refill_rspq(adap, q, q->credits); q->credits = 0; } - } while (is_new_response(r, q) && is_pure_response(r)); + if (!is_new_response(r, q)) + break; + rmb(); + } while (is_pure_response(r)); if (sleeping) check_ring_db(adap, qs, sleeping); @@ -2531,6 +2538,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) if (!is_new_response(r, q)) return -1; + rmb(); if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); -- GitLab From 24c4a3b29255f9f8bc48d93597a58256b5a1f83f Mon Sep 17 00:00:00 2001 From: Pavel Cheblakov Date: Mon, 1 Feb 2010 09:42:44 +0000 Subject: [PATCH 1537/3892] can: add support for CAN interface cards based on the PLX90xx PCI bridge This driver is for CAN interface cards based on the PLX90xx PCI bridge. Driver supports now: - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/) - Adlink PCI-7841/cPCI-7841 SE card - Marathon CAN-bus-PCI card (http://www.marathon.ru/) - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) Changes since v1: - Added some defines for static inline int plx_pci_check_sja1000(...) - static struct pci_device_id plx_pci_tbl[] replaced by static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) - Typo fixed Signed-off-by: Pavel Cheblakov Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/sja1000/Kconfig | 12 + drivers/net/can/sja1000/Makefile | 1 + drivers/net/can/sja1000/plx_pci.c | 472 ++++++++++++++++++++++++++++++ 3 files changed, 485 insertions(+) create mode 100644 drivers/net/can/sja1000/plx_pci.c diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 4c674927f247..9e277d64a318 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -44,4 +44,16 @@ config CAN_KVASER_PCI This driver is for the the PCIcanx and PCIcan cards (1, 2 or 4 channel) from Kvaser (http://www.kvaser.com). +config CAN_PLX_PCI + tristate "PLX90xx PCI-bridge based Cards" + depends on PCI + ---help--- + This driver is for CAN interface cards based on + the PLX90xx PCI bridge. + Driver supports now: + - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/) + - Adlink PCI-7841/cPCI-7841 SE card + - Marathon CAN-bus-PCI card (http://www.marathon.ru/) + - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) + endif diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 9d245ac03965..ce924553995d 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o +obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c new file mode 100644 index 000000000000..6b46a6395f80 --- /dev/null +++ b/drivers/net/can/sja1000/plx_pci.c @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2008-2010 Pavel Cheblakov + * + * Derived from the ems_pci.c driver: + * Copyright (C) 2007 Wolfgang Grandegger + * Copyright (C) 2008 Markus Plessing + * Copyright (C) 2008 Sebastian Haas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_plx_pci" + +MODULE_AUTHOR("Pavel Cheblakov "); +MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with " + "the SJA1000 chips"); +MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " + "Adlink PCI-7841/cPCI-7841 SE, " + "Marathon CAN-bus-PCI, " + "TEWS TECHNOLOGIES TPMC810"); +MODULE_LICENSE("GPL v2"); + +#define PLX_PCI_MAX_CHAN 2 + +struct plx_pci_card { + int channels; /* detected channels count */ + struct net_device *net_dev[PLX_PCI_MAX_CHAN]; + void __iomem *conf_addr; +}; + +#define PLX_PCI_CAN_CLOCK (16000000 / 2) + +/* PLX90xx registers */ +#define PLX_INTCSR 0x4c /* Interrupt Control/Status */ +#define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response, + * Serial EEPROM, and Initialization + * Control register + */ + +#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */ +#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */ +#define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */ +#define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */ + +/* + * The board configuration is probably following: + * RX1 is connected to ground. + * TX1 is not connected. + * CLKO is not connected. + * Setting the OCR register to 0xDA is a good idea. + * This means normal output mode, push-pull and the correct polarity. + */ +#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) + +/* + * In the CDR register, you should set CBP to 1. + * You will probably also want to set the clock divider value to 7 + * (meaning direct oscillator output) because the second SJA1000 chip + * is driven by the first one CLKOUT output. + */ +#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) + +/* SJA1000 Control Register in the BasicCAN Mode */ +#define REG_CR 0x00 + +/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/ +#define REG_CR_BASICCAN_INITIAL 0x21 +#define REG_CR_BASICCAN_INITIAL_MASK 0xa1 +#define REG_SR_BASICCAN_INITIAL 0x0c +#define REG_IR_BASICCAN_INITIAL 0xe0 + +/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/ +#define REG_MOD_PELICAN_INITIAL 0x01 +#define REG_SR_PELICAN_INITIAL 0x3c +#define REG_IR_PELICAN_INITIAL 0x00 + +#define ADLINK_PCI_VENDOR_ID 0x144A +#define ADLINK_PCI_DEVICE_ID 0x7841 + +#define MARATHON_PCI_DEVICE_ID 0x2715 + +#define TEWS_PCI_VENDOR_ID 0x1498 +#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A + +static void plx_pci_reset_common(struct pci_dev *pdev); +static void plx_pci_reset_marathon(struct pci_dev *pdev); + +struct plx_pci_channel_map { + u32 bar; + u32 offset; + u32 size; /* 0x00 - auto, e.g. length of entire bar */ +}; + +struct plx_pci_card_info { + const char *name; + int channel_count; + u32 can_clock; + u8 ocr; /* output control register */ + u8 cdr; /* clock divider register */ + + /* Parameters for mapping local configuration space */ + struct plx_pci_channel_map conf_map; + + /* Parameters for mapping the SJA1000 chips */ + struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN]; + + /* Pointer to device-dependent reset function */ + void (*reset_func)(struct pci_dev *pdev); +}; + +static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = { + "Adlink PCI-7841/cPCI-7841", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, + &plx_pci_reset_common + /* based on PLX9052 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = { + "Adlink PCI-7841/cPCI-7841 SE", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, + &plx_pci_reset_common + /* based on PLX9052 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = { + "Marathon CAN-bus-PCI", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, + &plx_pci_reset_marathon + /* based on PLX9052 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = { + "TEWS TECHNOLOGIES TPMC810", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} }, + &plx_pci_reset_common + /* based on PLX9030 */ +}; + +static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { + { + /* Adlink PCI-7841/cPCI-7841 */ + ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_OTHER << 8, ~0, + (kernel_ulong_t)&plx_pci_card_info_adlink + }, + { + /* Adlink PCI-7841/cPCI-7841 SE */ + ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_OTHER << 8, ~0, + (kernel_ulong_t)&plx_pci_card_info_adlink_se + }, + { + /* Marathon CAN-bus-PCI card */ + PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_marathon + }, + { + /* TEWS TECHNOLOGIES TPMC810 card */ + TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_tews + }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, plx_pci_tbl); + +static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port) +{ + return ioread8(priv->reg_base + port); +} + +static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) +{ + iowrite8(val, priv->reg_base + port); +} + +/* + * Check if a CAN controller is present at the specified location + * by trying to switch 'em from the Basic mode into the PeliCAN mode. + * Also check states of some registers in reset mode. + */ +static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) +{ + int flag = 0; + + /* + * Check registers after hardware reset (the Basic mode) + * See states on p. 10 of the Datasheet. + */ + if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) == + REG_CR_BASICCAN_INITIAL && + (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) && + (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL)) + flag = 1; + + /* Bring the SJA1000 into the PeliCAN mode*/ + priv->write_reg(priv, REG_CDR, CDR_PELICAN); + + /* + * Check registers after reset in the PeliCAN mode. + * See states on p. 23 of the Datasheet. + */ + if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL && + priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL && + priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL) + return flag; + + return 0; +} + +/* + * PLX90xx software reset + * Also LRESET# asserts and brings to reset device on the Local Bus (if wired). + * For most cards it's enough for reset the SJA1000 chips. + */ +static void plx_pci_reset_common(struct pci_dev *pdev) +{ + struct plx_pci_card *card = pci_get_drvdata(pdev); + u32 cntrl; + + cntrl = ioread32(card->conf_addr + PLX_CNTRL); + cntrl |= PLX_PCI_RESET; + iowrite32(cntrl, card->conf_addr + PLX_CNTRL); + udelay(100); + cntrl ^= PLX_PCI_RESET; + iowrite32(cntrl, card->conf_addr + PLX_CNTRL); +}; + +/* Special reset function for Marathon card */ +static void plx_pci_reset_marathon(struct pci_dev *pdev) +{ + void __iomem *reset_addr; + int i; + int reset_bar[2] = {3, 5}; + + plx_pci_reset_common(pdev); + + for (i = 0; i < 2; i++) { + reset_addr = pci_iomap(pdev, reset_bar[i], 0); + if (!reset_addr) { + dev_err(&pdev->dev, "Failed to remap reset " + "space %d (BAR%d)\n", i, reset_bar[i]); + } else { + /* reset the SJA1000 chip */ + iowrite8(0x1, reset_addr); + udelay(100); + pci_iounmap(pdev, reset_addr); + } + } +} + +static void plx_pci_del_card(struct pci_dev *pdev) +{ + struct plx_pci_card *card = pci_get_drvdata(pdev); + struct net_device *dev; + struct sja1000_priv *priv; + int i = 0; + + for (i = 0; i < card->channels; i++) { + dev = card->net_dev[i]; + if (!dev) + continue; + + dev_info(&pdev->dev, "Removing %s\n", dev->name); + unregister_sja1000dev(dev); + priv = netdev_priv(dev); + if (priv->reg_base) + pci_iounmap(pdev, priv->reg_base); + free_sja1000dev(dev); + } + + plx_pci_reset_common(pdev); + + /* + * Disable interrupts from PCI-card (PLX90xx) and disable Local_1, + * Local_2 interrupts + */ + iowrite32(0x0, card->conf_addr + PLX_INTCSR); + + if (card->conf_addr) + pci_iounmap(pdev, card->conf_addr); + + kfree(card); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +/* + * Probe PLX90xx based device for the SJA1000 chips and register each + * available CAN channel to SJA1000 Socket-CAN subsystem. + */ +static int __devinit plx_pci_add_card(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct sja1000_priv *priv; + struct net_device *dev; + struct plx_pci_card *card; + struct plx_pci_card_info *ci; + int err, i; + u32 val; + void __iomem *addr; + + ci = (struct plx_pci_card_info *)ent->driver_data; + + if (pci_enable_device(pdev) < 0) { + dev_err(&pdev->dev, "Failed to enable PCI device\n"); + return -ENODEV; + } + + dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n", + ci->name, PCI_SLOT(pdev->devfn)); + + /* Allocate card structures to hold addresses, ... */ + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + dev_err(&pdev->dev, "Unable to allocate memory\n"); + pci_disable_device(pdev); + return -ENOMEM; + } + + pci_set_drvdata(pdev, card); + + card->channels = 0; + + /* Remap PLX90xx configuration space */ + addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size); + if (!addr) { + err = -ENOMEM; + dev_err(&pdev->dev, "Failed to remap configuration space " + "(BAR%d)\n", ci->conf_map.bar); + goto failure_cleanup; + } + card->conf_addr = addr + ci->conf_map.offset; + + ci->reset_func(pdev); + + /* Detect available channels */ + for (i = 0; i < ci->channel_count; i++) { + struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i]; + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto failure_cleanup; + } + + card->net_dev[i] = dev; + priv = netdev_priv(dev); + priv->priv = card; + priv->irq_flags = IRQF_SHARED; + + dev->irq = pdev->irq; + + /* + * Remap IO space of the SJA1000 chips + * This is device-dependent mapping + */ + addr = pci_iomap(pdev, cm->bar, cm->size); + if (!addr) { + err = -ENOMEM; + dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar); + goto failure_cleanup; + } + + priv->reg_base = addr + cm->offset; + priv->read_reg = plx_pci_read_reg; + priv->write_reg = plx_pci_write_reg; + + /* Check if channel is present */ + if (plx_pci_check_sja1000(priv)) { + priv->can.clock.freq = ci->can_clock; + priv->ocr = ci->ocr; + priv->cdr = ci->cdr; + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Register SJA1000 device */ + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "Registering device failed " + "(err=%d)\n", err); + free_sja1000dev(dev); + goto failure_cleanup; + } + + card->channels++; + + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d " + "registered as %s\n", i + 1, priv->reg_base, + dev->irq, dev->name); + } else { + dev_err(&pdev->dev, "Channel #%d not detected\n", + i + 1); + free_sja1000dev(dev); + } + } + + if (!card->channels) { + err = -ENODEV; + goto failure_cleanup; + } + + /* + * Enable interrupts from PCI-card (PLX90xx) and enable Local_1, + * Local_2 interrupts from the SJA1000 chips + */ + val = ioread32(card->conf_addr + PLX_INTCSR); + val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN; + iowrite32(val, card->conf_addr + PLX_INTCSR); + + return 0; + +failure_cleanup: + dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err); + + plx_pci_del_card(pdev); + + return err; +} + +static struct pci_driver plx_pci_driver = { + .name = DRV_NAME, + .id_table = plx_pci_tbl, + .probe = plx_pci_add_card, + .remove = plx_pci_del_card, +}; + +static int __init plx_pci_init(void) +{ + return pci_register_driver(&plx_pci_driver); +} + +static void __exit plx_pci_exit(void) +{ + pci_unregister_driver(&plx_pci_driver); +} + +module_init(plx_pci_init); +module_exit(plx_pci_exit); -- GitLab From 91e83432f8abc1fc93499a2323f6c4bd6026029e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 Jan 2010 10:02:09 +0000 Subject: [PATCH 1538/3892] drivers/net/amd8111e.c: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/amd8111e.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 545c791f477e..bb27b27d9672 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1176,8 +1176,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Schedule a polling routine */ __napi_schedule(&lp->napi); } else if (intren0 & RINTEN0) { - printk("************Driver bug! \ - interrupt while in poll\n"); + printk("************Driver bug! interrupt while in poll\n"); /* Fix by disable receive interrupts */ writel(RINTEN0, mmio + INTEN0); } -- GitLab From 5297a98d5dd6de86fe1e2ffc9ea60cdf59b71443 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:28:14 +0000 Subject: [PATCH 1539/3892] sfc: Update MCDI protocol definitions Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi_pcol.h | 202 ++++++++++++++++++++++++++++++++---- 1 file changed, 179 insertions(+), 23 deletions(-) diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h index 73e71f420624..bd59302695b3 100644 --- a/drivers/net/sfc/mcdi_pcol.h +++ b/drivers/net/sfc/mcdi_pcol.h @@ -786,16 +786,18 @@ #define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0 #define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0 #define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1 -#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1 -#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1 -#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2 -#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN 1 +#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN 2 +#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_WIDTH 1 #define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3 #define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1 #define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4 #define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1 #define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5 #define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_BIST_LBN 6 +#define MC_CMD_GET_PHY_CFG_BIST_WIDTH 1 #define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4 /* Bitmask of supported capabilities */ #define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8 @@ -832,7 +834,7 @@ #define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52 #define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20 -/* MC_CMD_START_PHY_BIST: +/* MC_CMD_START_BIST: * Start a BIST test on the PHY. * * Locks required: PHY_LOCK if doing a PHY BIST @@ -840,34 +842,71 @@ */ #define MC_CMD_START_BIST 0x25 #define MC_CMD_START_BIST_IN_LEN 4 -#define MC_CMD_START_BIST_TYPE_OFST 0 +#define MC_CMD_START_BIST_IN_TYPE_OFST 0 +#define MC_CMD_START_BIST_OUT_LEN 0 -/* Run the PHY's short BIST */ -#define MC_CMD_PHY_BIST_SHORT 1 -/* Run the PHY's long BIST */ -#define MC_CMD_PHY_BIST_LONG 2 +/* Run the PHY's short cable BIST */ +#define MC_CMD_PHY_BIST_CABLE_SHORT 1 +/* Run the PHY's long cable BIST */ +#define MC_CMD_PHY_BIST_CABLE_LONG 2 /* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */ #define MC_CMD_BPX_SERDES_BIST 3 +/* Run the MC loopback tests */ +#define MC_CMD_MC_LOOPBACK_BIST 4 +/* Run the PHY's standard BIST */ +#define MC_CMD_PHY_BIST 5 /* MC_CMD_POLL_PHY_BIST: (variadic output) * Poll for BIST completion * - * Returns a single status code, and a binary blob of phy-specific - * bist output. If the driver can't succesfully parse the BIST output, - * it should still respect the Pass/Fail in OUT.RESULT. + * Returns a single status code, and optionally some PHY specific + * bist output. The driver should only consume the BIST output + * after validating OUTLEN and PHY_CFG.PHY_TYPE. * - * Locks required: PHY_LOCK if doing a PHY BIST + * If a driver can't succesfully parse the BIST output, it should + * still respect the pass/Fail in OUT.RESULT + * + * Locks required: PHY_LOCK if doing a PHY BIST * Return code: 0, EACCES (if PHY_LOCK is not held) */ #define MC_CMD_POLL_BIST 0x26 #define MC_CMD_POLL_BIST_IN_LEN 0 #define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN +#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 40 +#define MC_CMD_POLL_BIST_OUT_MRSFP_LEN 8 #define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0 #define MC_CMD_POLL_BIST_RUNNING 1 #define MC_CMD_POLL_BIST_PASSED 2 #define MC_CMD_POLL_BIST_FAILED 3 #define MC_CMD_POLL_BIST_TIMEOUT 4 +/* Generic: */ #define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4 +/* SFT9001-specific: */ +/* (offset 4 unused?) */ +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 8 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 12 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 16 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 20 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 24 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 28 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 32 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 36 +#define MC_CMD_POLL_BIST_SFT9001_PAIR_OK 1 +#define MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN 2 +#define MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT 3 +#define MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT 4 +#define MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY 9 +/* mrsfp "PHY" driver: */ +#define MC_CMD_POLL_BIST_OUT_MRSFP_TEST_OFST 4 +#define MC_CMD_POLL_BIST_MRSFP_TEST_COMPLETE 0 +#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_WRITE 1 +#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_IO_EXP 2 +#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_MODULE 3 +#define MC_CMD_POLL_BIST_MRSFP_TEST_IO_EXP_I2C_CONFIGURE 4 +#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_I2C_NO_CROSSTALK 5 +#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_PRESENCE 6 +#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_I2C_ACCESS 7 +#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_SANE_VALUE 8 /* MC_CMD_PHY_SPI: (variadic in, variadic out) * Read/Write/Erase the PHY SPI device @@ -1206,6 +1245,13 @@ #define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST \ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178) +#define MC_CMD_WOL_FILTER_SET_IN_LINK_MASK_OFST \ + MC_CMD_WOL_FILTER_SET_IN_DATA_OFST +#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_LBN 0 +#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_WIDTH 1 +#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_LBN 1 +#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_WIDTH 1 + #define MC_CMD_WOL_FILTER_SET_OUT_LEN 4 #define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0 @@ -1216,7 +1262,8 @@ #define MC_CMD_WOL_TYPE_IPV4_SYN 0x3 #define MC_CMD_WOL_TYPE_IPV6_SYN 0x4 #define MC_CMD_WOL_TYPE_BITMAP 0x5 -#define MC_CMD_WOL_TYPE_MAX 0x6 +#define MC_CMD_WOL_TYPE_LINK 0x6 +#define MC_CMD_WOL_TYPE_MAX 0x7 #define MC_CMD_FILTER_MODE_SIMPLE 0x0 #define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff @@ -1357,14 +1404,24 @@ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) */ #define MC_CMD_NVRAM_UPDATE_FINISH 0x3c -#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4 +#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 8 #define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_UPDATE_FINISH_IN_REBOOT_OFST 4 #define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0 /* MC_CMD_REBOOT: - * Reboot the MC. The AFTER_ASSERTION flag is intended to be used - * when the driver notices an assertion failure, to allow two ports to - * both recover (semi-)gracefully. + * Reboot the MC. + * + * The AFTER_ASSERTION flag is intended to be used when the driver notices + * an assertion failure (at which point it is expected to perform a complete + * tear down and reinitialise), to allow both ports to reset the MC once + * in an atomic fashion. + * + * Production mc firmwares are generally compiled with REBOOT_ON_ASSERT=1, + * which means that they will automatically reboot out of the assertion + * handler, so this is in practise an optional operation. It is still + * recommended that drivers execute this to support custom firmwares + * with REBOOT_ON_ASSERT=0. * * Locks required: NONE * Returns: Nothing. You get back a response with ERR=1, DATALEN=0 @@ -1469,11 +1526,10 @@ ((_ofst) + 6) /* MC_CMD_READ_SENSORS - * Returns the current (value, state) for each sensor + * Returns the current reading from each sensor * - * Returns the current (value, state) [each 16bit] of each sensor supported by - * this board, by DMA'ing a sparse array (indexed by the sensor type) into host - * memory. + * Returns a sparse array of sensor readings (indexed by the sensor + * type) into host memory. Each array element is a dword. * * The MC will send a SENSOREVT event every time any sensor changes state. The * driver is responsible for ensuring that it doesn't miss any events. The board @@ -1486,6 +1542,12 @@ #define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4 #define MC_CMD_READ_SENSORS_OUT_LEN 0 +/* Sensor reading fields */ +#define MC_CMD_READ_SENSOR_VALUE_LBN 0 +#define MC_CMD_READ_SENSOR_VALUE_WIDTH 16 +#define MC_CMD_READ_SENSOR_STATE_LBN 16 +#define MC_CMD_READ_SENSOR_STATE_WIDTH 8 + /* MC_CMD_GET_PHY_STATE: * Report current state of PHY. A "zombie" PHY is a PHY that has failed to @@ -1577,4 +1639,98 @@ #define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0 #define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0 + +/* MC_CMD_TEST_ASSERT: + * Deliberately trigger an assert-detonation in the firmware for testing + * purposes (i.e. to allow tests that the driver copes gracefully). + * + * Locks required: None + * Returns: 0 + */ + +#define MC_CMD_TESTASSERT 0x49 +#define MC_CMD_TESTASSERT_IN_LEN 0 +#define MC_CMD_TESTASSERT_OUT_LEN 0 + +/* MC_CMD_WORKAROUND 0x4a + * + * Enable/Disable a given workaround. The mcfw will return EINVAL if it + * doesn't understand the given workaround number - which should not + * be treated as a hard error by client code. + * + * This op does not imply any semantics about each workaround, that's between + * the driver and the mcfw on a per-workaround basis. + * + * Locks required: None + * Returns: 0, EINVAL + */ +#define MC_CMD_WORKAROUND 0x4a +#define MC_CMD_WORKAROUND_IN_LEN 8 +#define MC_CMD_WORKAROUND_IN_TYPE_OFST 0 +#define MC_CMD_WORKAROUND_BUG17230 1 +#define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4 +#define MC_CMD_WORKAROUND_OUT_LEN 0 + +/* MC_CMD_GET_PHY_MEDIA_INFO: + * Read media-specific data from PHY (e.g. SFP/SFP+ module ID information for + * SFP+ PHYs). + * + * The "media type" can be found via GET_PHY_CFG (GET_PHY_CFG_OUT_MEDIA_TYPE); + * the valid "page number" input values, and the output data, are interpreted + * on a per-type basis. + * + * For SFP+: PAGE=0 or 1 returns a 128-byte block read from module I2C address + * 0xA0 offset 0 or 0x80. + * Anything else: currently undefined. + * + * Locks required: None + * Return code: 0 + */ +#define MC_CMD_GET_PHY_MEDIA_INFO 0x4b +#define MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN 4 +#define MC_CMD_GET_PHY_MEDIA_INFO_IN_PAGE_OFST 0 +#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(_num_bytes) (4 + (_num_bytes)) +#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATALEN_OFST 0 +#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST 4 + +/* MC_CMD_NVRAM_TEST: + * Test a particular NVRAM partition for valid contents (where "valid" + * depends on the type of partition). + * + * Locks required: None + * Return code: 0 + */ +#define MC_CMD_NVRAM_TEST 0x4c +#define MC_CMD_NVRAM_TEST_IN_LEN 4 +#define MC_CMD_NVRAM_TEST_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_TEST_OUT_LEN 4 +#define MC_CMD_NVRAM_TEST_OUT_RESULT_OFST 0 +#define MC_CMD_NVRAM_TEST_PASS 0 +#define MC_CMD_NVRAM_TEST_FAIL 1 +#define MC_CMD_NVRAM_TEST_NOTSUPP 2 + +/* MC_CMD_MRSFP_TWEAK: (debug) + * Read status and/or set parameters for the "mrsfp" driver in mr_rusty builds. + * I2C I/O expander bits are always read; if equaliser parameters are supplied, + * they are configured first. + * + * Locks required: None + * Return code: 0, EINVAL + */ +#define MC_CMD_MRSFP_TWEAK 0x4d +#define MC_CMD_MRSFP_TWEAK_IN_LEN_READ_ONLY 0 +#define MC_CMD_MRSFP_TWEAK_IN_LEN_EQ_CONFIG 16 +#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_LEVEL_OFST 0 /* 0-6 low->high de-emph. */ +#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_DT_CFG_OFST 4 /* 0-8 low->high ref.V */ +#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_BOOST_OFST 8 /* 0-8 low->high boost */ +#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_DT_CFG_OFST 12 /* 0-8 low->high ref.V */ +#define MC_CMD_MRSFP_TWEAK_OUT_LEN 12 +#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_INPUTS_OFST 0 /* input bits */ +#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_OUTPUTS_OFST 4 /* output bits */ +#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_DIRECTION_OFST 8 /* dirs: 0=out, 1=in */ + +/* Do NOT add new commands beyond 0x4f as part of 3.0 : 0x50 - 0x7f will be + * used for post-3.0 extensions. If you run out of space, look for gaps or + * commands that are unused in the existing range. */ + #endif /* MCDI_PCOL_H */ -- GitLab From 8b2103add08b79abd3ac7015b4bac744c0af534e Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 3 Feb 2010 09:30:17 +0000 Subject: [PATCH 1540/3892] sfc: Handle firmware assertion failure while resetting This allows the driver to recover if the MC firmware has crashed due to an assertion failure. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi.c | 63 +++++++++++++++++++++++++---------------- drivers/net/sfc/siena.c | 6 ++++ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 9f035b9f0350..e9f0e5ee4519 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -896,29 +896,27 @@ fail: return rc; } -int efx_mcdi_handle_assertion(struct efx_nic *efx) +static int efx_mcdi_read_assertion(struct efx_nic *efx) { - union { - u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN]; - u8 reboot[MC_CMD_REBOOT_IN_LEN]; - } inbuf; - u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN]; + u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN]; + u8 outbuf[MC_CMD_GET_ASSERTS_OUT_LEN]; unsigned int flags, index, ofst; const char *reason; size_t outlen; int retry; int rc; - /* Check if the MC is in the assertion handler, retrying twice. Once + /* Attempt to read any stored assertion state before we reboot + * the mcfw out of the assertion handler. Retry twice, once * because a boot-time assertion might cause this command to fail * with EINTR. And once again because GET_ASSERTS can race with * MC_CMD_REBOOT running on the other port. */ retry = 2; do { - MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0); + MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1); rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS, - inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN, - assertion, sizeof(assertion), &outlen); + inbuf, MC_CMD_GET_ASSERTS_IN_LEN, + outbuf, sizeof(outbuf), &outlen); } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); if (rc) @@ -926,21 +924,11 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx) if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) return -EINVAL; - flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS); + /* Print out any recorded assertion state */ + flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS); if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) return 0; - /* Reset the hardware atomically such that only one port with succeed. - * This command will succeed if a reboot is no longer required (because - * the other port did it first), but fail with EIO if it succeeds. - */ - BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); - MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS, - MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); - efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN, - NULL, 0, NULL); - - /* Print out the assertion */ reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) ? "system-level assertion" : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) @@ -949,20 +937,45 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx) ? "watchdog reset" : "unknown assertion"; EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason, - MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS), - MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS)); + MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS), + MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS)); /* Print out the registers */ ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; for (index = 1; index < 32; index++) { EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index, - MCDI_DWORD2(assertion, ofst)); + MCDI_DWORD2(outbuf, ofst)); ofst += sizeof(efx_dword_t); } return 0; } +static void efx_mcdi_exit_assertion(struct efx_nic *efx) +{ + u8 inbuf[MC_CMD_REBOOT_IN_LEN]; + + /* Atomically reboot the mcfw out of the assertion handler */ + BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); + MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, + MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); + efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN, + NULL, 0, NULL); +} + +int efx_mcdi_handle_assertion(struct efx_nic *efx) +{ + int rc; + + rc = efx_mcdi_read_assertion(efx); + if (rc) + return rc; + + efx_mcdi_exit_assertion(efx); + + return 0; +} + void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN]; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index f8c6771e66d8..0e4c13abf087 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -181,6 +181,12 @@ static int siena_test_registers(struct efx_nic *efx) static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) { + int rc; + + /* Recover from a failed assertion pre-reset */ + rc = efx_mcdi_handle_assertion(efx); + if (rc) + return rc; if (method == RESET_TYPE_WORLD) return efx_mcdi_reset_mc(efx); -- GitLab From 7a6b8f6f7f74085a1330b0f9765d81bcea8c58b7 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 3 Feb 2010 09:30:38 +0000 Subject: [PATCH 1541/3892] sfc: Enable autonegotiated flow-control by default if supported Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon.c | 2 ++ drivers/net/sfc/mcdi_phy.c | 14 +++++++++++++- drivers/net/sfc/siena.c | 7 +------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 9d009c46e962..1e7858511e35 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -909,6 +909,8 @@ static int falcon_probe_port(struct efx_nic *efx) efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; else efx->wanted_fc = EFX_FC_RX; + if (efx->mdio.mmds & MDIO_DEVS_AN) + efx->wanted_fc |= EFX_FC_AUTO; /* Allocate buffer for stats */ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index eb694af7a473..d87e74d3994e 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -381,6 +381,18 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx) * but by convention we don't */ efx->loopback_modes &= ~(1 << LOOPBACK_NONE); + /* Set the initial link mode */ + efx_mcdi_phy_decode_link( + efx, &efx->link_state, + MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), + MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), + MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); + + /* Default to Autonegotiated flow control if the PHY supports it */ + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; + if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) + efx->wanted_fc |= EFX_FC_AUTO; + return 0; fail: @@ -436,7 +448,7 @@ void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) /* The link partner capabilities are only relevent if the * link supports flow control autonegotiation */ - if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) return; /* If flow control autoneg is supported and enabled, then fine */ diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 0e4c13abf087..f6a53895ff27 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -106,16 +106,11 @@ static int siena_probe_port(struct efx_nic *efx) efx->mdio.mdio_read = siena_mdio_read; efx->mdio.mdio_write = siena_mdio_write; - /* Fill out MDIO structure and loopback modes */ + /* Fill out MDIO structure, loopback modes, and initial link state */ rc = efx->phy_op->probe(efx); if (rc != 0) return rc; - /* Initial assumption */ - efx->link_state.speed = 10000; - efx->link_state.fd = true; - efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; - /* Allocate buffer for stats */ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, MC_CMD_MAC_NSTATS * sizeof(u64)); -- GitLab From 4f16c0739145476ba37a7fa9eea0c33850efc2ce Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:30:50 +0000 Subject: [PATCH 1542/3892] sfc: Replace PHY MDIO test with an 'alive' test SFC9000-family boards do not all use MDIO PHYs, so we need a different test for PHY aliveness. Introduce a PHY operation test_alive(). For PHYs attached to Falcon, use a common implementation based on the existing PHY MDIO test. For PHYs managed through MCDI, use the appropriate MCDI request. Change test name in ethtool from 'core mdio' to 'phy alive'. Rename test_results::mdio to phy_alive and test_results::phy to phy_ext. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/ethtool.c | 6 +++--- drivers/net/sfc/mcdi_phy.c | 22 ++++++++++++++++++++ drivers/net/sfc/mdio_10g.c | 24 ++++++++++++++++++++++ drivers/net/sfc/mdio_10g.h | 3 +++ drivers/net/sfc/net_driver.h | 4 +++- drivers/net/sfc/qt202x_phy.c | 1 + drivers/net/sfc/selftest.c | 40 ++++++------------------------------ drivers/net/sfc/selftest.h | 4 ++-- drivers/net/sfc/tenxpress.c | 2 ++ 9 files changed, 66 insertions(+), 40 deletions(-) diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 6c0bbed8c477..635c4205b4fb 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -342,8 +342,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, unsigned int n = 0, i; enum efx_loopback_mode mode; - efx_fill_test(n++, strings, data, &tests->mdio, - "core", 0, "mdio", NULL); + efx_fill_test(n++, strings, data, &tests->phy_alive, + "phy", 0, "alive", NULL); efx_fill_test(n++, strings, data, &tests->nvram, "core", 0, "nvram", NULL); efx_fill_test(n++, strings, data, &tests->interrupt, @@ -379,7 +379,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, if (name == NULL) break; - efx_fill_test(n++, strings, data, &tests->phy[i], + efx_fill_test(n++, strings, data, &tests->phy_ext[i], "phy", 0, name, NULL); } } diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index d87e74d3994e..34c22fa986e2 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -572,6 +572,27 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec return 0; } +static int efx_mcdi_phy_test_alive(struct efx_nic *efx) +{ + u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN]; + size_t outlen; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + + if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN) + return -EMSGSIZE; + if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK) + return -EINVAL; + + return 0; +} + struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, @@ -581,6 +602,7 @@ struct efx_phy_operations efx_mcdi_phy_ops = { .remove = efx_mcdi_phy_remove, .get_settings = efx_mcdi_phy_get_settings, .set_settings = efx_mcdi_phy_set_settings, + .test_alive = efx_mcdi_phy_test_alive, .run_tests = NULL, .test_name = NULL, }; diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 1574e52f0594..0548fcbbdcd0 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -335,3 +335,27 @@ enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) mii_advertise_flowctrl(efx->wanted_fc), efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA)); } + +int efx_mdio_test_alive(struct efx_nic *efx) +{ + int rc; + int devad = __ffs(efx->mdio.mmds); + u16 physid1, physid2; + + mutex_lock(&efx->mac_lock); + + physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); + physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); + + if ((physid1 == 0x0000) || (physid1 == 0xffff) || + (physid2 == 0x0000) || (physid2 == 0xffff)) { + EFX_ERR(efx, "no MDIO PHY present with ID %d\n", + efx->mdio.prtad); + rc = -EINVAL; + } else { + rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); + } + + mutex_unlock(&efx->mac_lock); + return rc; +} diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index f6ac9503339d..f89e71929603 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -106,4 +106,7 @@ efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr, mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state); } +/* Liveness self-test for MDIO PHYs */ +extern int efx_mdio_test_alive(struct efx_nic *efx); + #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index d5aab5b3fa06..8f951e4f15be 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -516,8 +516,9 @@ struct efx_mac_operations { * @set_settings: Set ethtool settings. Serialised by the mac_lock. * @set_npage_adv: Set abilities advertised in (Extended) Next Page * (only needed where AN bit is set in mmds) + * @test_alive: Test that PHY is 'alive' (online) * @test_name: Get the name of a PHY-specific test/result - * @run_tests: Run tests and record results as appropriate. + * @run_tests: Run tests and record results as appropriate (offline). * Flags are the ethtool tests flags. */ struct efx_phy_operations { @@ -532,6 +533,7 @@ struct efx_phy_operations { int (*set_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); void (*set_npage_adv) (struct efx_nic *efx, u32); + int (*test_alive) (struct efx_nic *efx); const char *(*test_name) (struct efx_nic *efx, unsigned int index); int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); }; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index e0d13a451019..14793d8bd661 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -445,4 +445,5 @@ struct efx_phy_operations falcon_qt202x_phy_ops = { .remove = qt202x_phy_remove, .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, + .test_alive = efx_mdio_test_alive, }; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 250c8827b842..8a5a7b6d042d 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -26,7 +26,6 @@ #include "workarounds.h" #include "spi.h" #include "io.h" -#include "mdio_10g.h" /* * Loopback test packet structure @@ -76,42 +75,15 @@ struct efx_loopback_state { * **************************************************************************/ -static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests) { int rc = 0; - int devad; - u16 physid1, physid2; - - if (efx->mdio.mode_support & MDIO_SUPPORTS_C45) - devad = __ffs(efx->mdio.mmds); - else if (efx->mdio.mode_support & MDIO_SUPPORTS_C22) - devad = MDIO_DEVAD_NONE; - else - return 0; - - mutex_lock(&efx->mac_lock); - tests->mdio = -1; - - physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); - physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); - if ((physid1 == 0x0000) || (physid1 == 0xffff) || - (physid2 == 0x0000) || (physid2 == 0xffff)) { - EFX_ERR(efx, "no MDIO PHY present with ID %d\n", - efx->mdio.prtad); - rc = -EINVAL; - goto out; + if (efx->phy_op->test_alive) { + rc = efx->phy_op->test_alive(efx); + tests->phy_alive = rc ? -1 : 1; } - if (EFX_IS10G(efx)) { - rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); - if (rc) - goto out; - } - -out: - mutex_unlock(&efx->mac_lock); - tests->mdio = rc ? -1 : 1; return rc; } @@ -258,7 +230,7 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, return 0; mutex_lock(&efx->mac_lock); - rc = efx->phy_op->run_tests(efx, tests->phy, flags); + rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags); mutex_unlock(&efx->mac_lock); return rc; } @@ -684,7 +656,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* Online (i.e. non-disruptive) testing * This checks interrupt generation, event delivery and PHY presence. */ - rc = efx_test_mdio(efx, tests); + rc = efx_test_phy_alive(efx, tests); if (rc && !rc_test) rc_test = rc; diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index f6feee04c96b..643bef72b99d 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -32,7 +32,7 @@ struct efx_loopback_self_tests { */ struct efx_self_tests { /* online tests */ - int mdio; + int phy_alive; int nvram; int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; @@ -40,7 +40,7 @@ struct efx_self_tests { int eventq_poll[EFX_MAX_CHANNELS]; /* offline tests */ int registers; - int phy[EFX_MAX_PHY_TESTS]; + int phy_ext[EFX_MAX_PHY_TESTS]; struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 3009c297c135..10db071bd837 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -842,6 +842,7 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sfx7101_set_npage_adv, + .test_alive = efx_mdio_test_alive, .test_name = sfx7101_test_name, .run_tests = sfx7101_run_tests, }; @@ -856,6 +857,7 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sft9001_set_npage_adv, + .test_alive = efx_mdio_test_alive, .test_name = sft9001_test_name, .run_tests = sft9001_run_tests, }; -- GitLab From 2e803407400efe592e5294993a5b1e8251f6dd49 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:31:01 +0000 Subject: [PATCH 1543/3892] sfc: Implement NVRAM selftest for SFC9000 family Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi.c | 46 +++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/mcdi.h | 1 + drivers/net/sfc/siena.c | 1 + 3 files changed, 48 insertions(+) diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index e9f0e5ee4519..86610db2cff5 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -896,6 +896,52 @@ fail: return rc; } +static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type) +{ + u8 inbuf[MC_CMD_NVRAM_TEST_IN_LEN]; + u8 outbuf[MC_CMD_NVRAM_TEST_OUT_LEN]; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), NULL); + if (rc) + return rc; + + switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) { + case MC_CMD_NVRAM_TEST_PASS: + case MC_CMD_NVRAM_TEST_NOTSUPP: + return 0; + default: + return -EIO; + } +} + +int efx_mcdi_nvram_test_all(struct efx_nic *efx) +{ + u32 nvram_types; + unsigned int type; + int rc; + + rc = efx_mcdi_nvram_types(efx, &nvram_types); + if (rc) + return rc; + + type = 0; + while (nvram_types != 0) { + if (nvram_types & 1) { + rc = efx_mcdi_nvram_test(efx, type); + if (rc) + return rc; + } + type++; + nvram_types >>= 1; + } + + return 0; +} + static int efx_mcdi_read_assertion(struct efx_nic *efx) { u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN]; diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h index 10ce98f4c0fb..f1f89ad4075a 100644 --- a/drivers/net/sfc/mcdi.h +++ b/drivers/net/sfc/mcdi.h @@ -116,6 +116,7 @@ extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, loff_t offset, size_t length); extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type); +extern int efx_mcdi_nvram_test_all(struct efx_nic *efx); extern int efx_mcdi_handle_assertion(struct efx_nic *efx); extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); extern int efx_mcdi_reset_port(struct efx_nic *efx); diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index f6a53895ff27..8e1311284718 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -583,6 +583,7 @@ struct efx_nic_type siena_a0_nic_type = { .set_wol = siena_set_wol, .resume_wol = siena_init_wol, .test_registers = siena_test_registers, + .test_nvram = efx_mcdi_nvram_test_all, .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, -- GitLab From c91f48d61c5b6fb36a6fc50de923db4db009b0dc Mon Sep 17 00:00:00 2001 From: Guido Barzini Date: Wed, 3 Feb 2010 09:31:24 +0000 Subject: [PATCH 1544/3892] sfc: Survive ISR0=0 bug in the shared IRQ case Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index db44224ed2ca..8d9696a38edf 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1384,6 +1384,15 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) efx->last_irq_cpu = raw_smp_processor_id(); EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); + } else if (EFX_WORKAROUND_15783(efx)) { + /* We can't return IRQ_HANDLED more than once on seeing ISR0=0 + * because this might be a shared interrupt, but we do need to + * check the channel every time and preemptively rearm it if + * it's idle. */ + efx_for_each_channel(channel, efx) { + if (!channel->work_pending) + efx_nic_eventq_read_ack(channel); + } } return result; -- GitLab From 4cddca5484e047fa77ce090bec96fbfb92a6eb19 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 3 Feb 2010 09:31:40 +0000 Subject: [PATCH 1545/3892] sfc: Add some missing bits to register self-test masks Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/siena.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 1e7858511e35..f63a32cc9d24 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1008,7 +1008,7 @@ static int falcon_test_nvram(struct efx_nic *efx) static const struct efx_nic_register_test falcon_b0_register_tests[] = { { FR_AZ_ADR_REGION, - EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, + EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, { FR_AZ_RX_CFG, EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, { FR_AZ_TX_CFG, diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 8e1311284718..1619fb5a64f5 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -134,7 +134,7 @@ void siena_remove_port(struct efx_nic *efx) static const struct efx_nic_register_test siena_register_tests[] = { { FR_AZ_ADR_REGION, - EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, + EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, { FR_CZ_USR_EV_CFG, EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) }, { FR_AZ_RX_CFG, -- GitLab From 2291b20f4bee6a28087cf4f4b2b382a92063c8b5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:31:46 +0000 Subject: [PATCH 1546/3892] sfc: Remove declarations of nonexistent functions Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index a615ac051530..7eff0a615cb3 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -79,8 +79,6 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); -extern void efx_suspend(struct efx_nic *efx); -extern void efx_resume(struct efx_nic *efx); extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, bool rx_adaptive); extern int efx_request_power(struct efx_nic *efx, int mw, const char *name); -- GitLab From 754c653a4e62bfa19b4e015c45198863c4211947 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:31:57 +0000 Subject: [PATCH 1547/3892] sfc: Fix some incorrect or redundant comments In particular, the comment about EVQ_RPTR_REG is based on inconsistent preliminary hardware documentation, though the following code was fixed long before release. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/ethtool.c | 4 ++-- drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/net_driver.h | 12 ++++-------- drivers/net/sfc/nic.c | 4 ---- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 635c4205b4fb..d9f9c02a928e 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -196,7 +196,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, efx->phy_op->get_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); - /* Falcon GMAC does not support 1000Mbps HD */ + /* GMAC does not support 1000Mbps HD */ ecmd->supported &= ~SUPPORTED_1000baseT_Half; /* Both MACs support pause frames (bidirectional and respond-only) */ ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; @@ -216,7 +216,7 @@ int efx_ethtool_set_settings(struct net_device *net_dev, struct efx_nic *efx = netdev_priv(net_dev); int rc; - /* Falcon GMAC does not support 1000Mbps HD */ + /* GMAC does not support 1000Mbps HD */ if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { EFX_LOG(efx, "rejecting unsupported 1000Mbps HD" " setting\n"); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index f63a32cc9d24..1b8d83657aaa 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1730,7 +1730,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) /************************************************************************** * - * Revision-dependent attributes used by efx.c + * Revision-dependent attributes used by efx.c and nic.c * ************************************************************************** */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 8f951e4f15be..ac77a252c7e2 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -101,9 +101,6 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0) * Special buffers are used for the event queues and the TX and RX * descriptor queues for each channel. They are *not* used for the * actual transmit and receive buffers. - * - * Note that for Falcon, TX and RX descriptor queues live in host memory. - * Allocation and freeing procedures must take this into account. */ struct efx_special_buffer { void *addr; @@ -300,7 +297,7 @@ struct efx_rx_queue { * @dma_addr: DMA base address of the buffer * @len: Buffer length, in bytes * - * Falcon uses these buffers for its interrupt status registers and + * The NIC uses these buffers for its interrupt status registers and * MAC stats dumps. */ struct efx_buffer { @@ -674,7 +671,7 @@ union efx_multicast_hash { * @irq_status: Interrupt status buffer * @last_irq_cpu: Last CPU to handle interrupt. * This register is written with the SMP processor ID whenever an - * interrupt is handled. It is used by falcon_test_interrupt() + * interrupt is handled. It is used by efx_nic_test_interrupt() * to verify that an interrupt has occurred. * @spi_flash: SPI flash device * This field will be %NULL if no flash device is present (or for Siena). @@ -723,8 +720,7 @@ union efx_multicast_hash { * @loopback_modes: Supported loopback mode bitmask * @loopback_selftest: Offline self-test private state * - * The @priv field of the corresponding &struct net_device points to - * this. + * This is stored in the private area of the &struct net_device. */ struct efx_nic { char name[IFNAMSIZ]; @@ -997,7 +993,7 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr) * that the net driver will program into the MAC as the maximum frame * length. * - * The 10G MAC used in Falcon requires 8-byte alignment on the frame + * The 10G MAC requires 8-byte alignment on the frame * length, so we round up to the nearest 8. * * Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 8d9696a38edf..b06f8e348307 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -623,10 +623,6 @@ void efx_nic_remove_rx(struct efx_rx_queue *rx_queue) * * This writes the EVQ_RPTR_REG register for the specified channel's * event queue. - * - * Note that EVQ_RPTR_REG contains the index of the "last read" event, - * whereas channel->eventq_read_ptr contains the index of the "next to - * read" event. */ void efx_nic_eventq_read_ack(struct efx_channel *channel) { -- GitLab From a4b97f2054af2e411c414ed4cb5e1d0dbfd24a47 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Feb 2010 09:32:06 +0000 Subject: [PATCH 1548/3892] sfc: Do not include unneeded headers Earlier refactoring has made these inclusions unnecessary. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/net_driver.h | 1 - drivers/net/sfc/selftest.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ac77a252c7e2..cb018e272097 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 8a5a7b6d042d..cf0139a7d9a4 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -24,8 +24,6 @@ #include "nic.h" #include "selftest.h" #include "workarounds.h" -#include "spi.h" -#include "io.h" /* * Loopback test packet structure -- GitLab From efec959f63de850fbd2442189f7dfc9c38efe251 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 4 Feb 2010 14:33:54 +1100 Subject: [PATCH 1549/3892] powerpc/pseries: Pass more accurate number of supported cores to firmware Updated variant of a patch by Joel Schopp. The field containing the number of supported cores which we pass to firmware via the ibm,client-architecture call was set by a previous patch statically as high as is possible (NR_CPUS). However, that value isn't quite right for a system that supports multiple threads per core, thus permitting the firmware to assign more cores to a Linux partition than it can really cope with. This patch improves it by using the device-tree to determine the number of threads supported by the processors in order to adjust the value passed to firmware. Signed-off-by: Joel Schopp Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom_init.c | 64 ++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 59d5bd1c064d..5f306c4946e5 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -710,7 +710,12 @@ static unsigned char ibm_architecture_vec[] = { 0, 0, 0, - W(NR_CPUS), /* number of cores supported*/ + /* WARNING: The offset of the "number of cores" field below + * must match by the macro below. Update the definition if + * the structure layout changes. + */ +#define IBM_ARCH_VEC_NRCORES_OFFSET 100 + W(NR_CPUS), /* number of cores supported */ /* option vector 6: IBM PAPR hints */ 4 - 2, /* length */ @@ -807,13 +812,70 @@ static struct fake_elf { } }; +static int __init prom_count_smt_threads(void) +{ + phandle node; + char type[64]; + unsigned int plen; + + /* Pick up th first CPU node we can find */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + + if (strcmp(type, RELOC("cpu"))) + continue; + /* + * There is an entry for each smt thread, each entry being + * 4 bytes long. All cpus should have the same number of + * smt threads, so return after finding the first. + */ + plen = prom_getproplen(node, "ibm,ppc-interrupt-server#s"); + if (plen == PROM_ERROR) + break; + plen >>= 2; + prom_debug("Found 0x%x smt threads per core\n", (unsigned long)plen); + + /* Sanity check */ + if (plen < 1 || plen > 64) { + prom_printf("Threads per core 0x%x out of bounds, assuming 1\n", + (unsigned long)plen); + return 1; + } + return plen; + } + prom_debug("No threads found, assuming 1 per core\n"); + + return 1; + +} + + static void __init prom_send_capabilities(void) { ihandle elfloader, root; prom_arg_t ret; + u32 *cores; root = call_prom("open", 1, 1, ADDR("/")); if (root != 0) { + /* We need to tell the FW about the number of cores we support. + * + * To do that, we count the number of threads on the first core + * (we assume this is the same for all cores) and use it to + * divide NR_CPUS. + */ + cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]); + if (*cores != NR_CPUS) { + prom_printf("WARNING ! " + "ibm_architecture_vec structure inconsistent: 0x%x !\n", + *cores); + } else { + *cores = NR_CPUS / prom_count_smt_threads(); + prom_printf("Max number of cores passed to firmware: 0x%x\n", + (unsigned long)*cores); + } + /* try calling the ibm,client-architecture-support method */ prom_printf("Calling ibm,client-architecture-support..."); if (call_prom_ret("call-method", 3, 2, &ret, -- GitLab From 10eec95569513206877769ad9336591c08015cfe Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 3 Feb 2010 14:23:32 +0000 Subject: [PATCH 1550/3892] ixgbe: only process one ixgbe_watchdog_task at a time. Processing multiple ixgbe_watchdog_task calls may cause the link_up variable and IXGBE_FLAG_NEED_LINK_UPDATE flag to be set incorrectly. In the worse case this is causing the netif_carrier_off to be called inappropriately which results in an interface that can't be brought up. Although schedule_work() will only schedule the task if it is not already on the work queue the WORK_STRUCT_PENDING bits are cleared just before calling the work function. This allows WORK_STRUCT_PENDING to be cleared, the work function to start and meanwhile schedule another task. This patch adds a mutex to the watchdog task. This bug is actualized by changing DCB settings or doing extended cable pull or reset tests. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 17 ++++++++--------- drivers/net/ixgbe/ixgbe_main.c | 13 +++++++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index e576fb4740bc..55a319e3a57a 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -341,15 +341,14 @@ struct ixgbe_adapter { #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) #define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) -#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) -#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) -#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) -#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) -#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 28) -#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) -#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 30) -#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 31) +#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) +#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) +#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) +#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) u32 flags2; #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f098816d4199..1ec3cbdf8729 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4996,6 +4996,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work) netif_tx_start_all_queues(adapter->netdev); } +static DEFINE_MUTEX(ixgbe_watchdog_lock); + /** * ixgbe_watchdog_task - worker thread to bring link up * @work: pointer to work_struct containing our data @@ -5007,13 +5009,16 @@ static void ixgbe_watchdog_task(struct work_struct *work) watchdog_task); struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed = adapter->link_speed; - bool link_up = adapter->link_up; + u32 link_speed; + bool link_up; int i; struct ixgbe_ring *tx_ring; int some_tx_pending = 0; - adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; + mutex_lock(&ixgbe_watchdog_lock); + + link_up = adapter->link_up; + link_speed = adapter->link_speed; if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { hw->mac.ops.check_link(hw, &link_speed, &link_up, false); @@ -5102,7 +5107,7 @@ static void ixgbe_watchdog_task(struct work_struct *work) } ixgbe_update_stats(adapter); - adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; + mutex_unlock(&ixgbe_watchdog_lock); } static int ixgbe_tso(struct ixgbe_adapter *adapter, -- GitLab From b548192acaebcb05d6a87d1e94f19835b1a18a8b Mon Sep 17 00:00:00 2001 From: Nick Nunley Date: Wed, 3 Feb 2010 14:49:28 +0000 Subject: [PATCH 1551/3892] e1000: Report link status in ethtool when interface is down With this change ethtool will correctly report link status when the interface is down. Currently ethtool reports the link as not detected when the interface is down. Signed-off-by: Nicholas Nunley Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_ethtool.c | 19 ++++++++++++++++++- drivers/net/e1000/e1000_main.c | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index e8932db7ee77..9902b33b7160 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -349,6 +349,7 @@ extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_update_stats(struct e1000_adapter *adapter); +extern bool e1000_has_link(struct e1000_adapter *adapter); extern void e1000_power_up_phy(struct e1000_adapter *); extern void e1000_set_ethtool_ops(struct net_device *netdev); extern void e1000_check_options(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 13e9ece16889..c67e93117271 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -215,6 +215,23 @@ static int e1000_set_settings(struct net_device *netdev, return 0; } +static u32 e1000_get_link(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* + * If the link is not reported up to netdev, interrupts are disabled, + * and so the physical link state may have changed since we last + * looked. Set get_link_status to make sure that the true link + * state is interrogated, rather than pulling a cached and possibly + * stale link state from the driver. + */ + if (!netif_carrier_ok(netdev)) + adapter->hw.get_link_status = 1; + + return e1000_has_link(adapter); +} + static void e1000_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { @@ -1892,7 +1909,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_msglevel = e1000_get_msglevel, .set_msglevel = e1000_set_msglevel, .nway_reset = e1000_nway_reset, - .get_link = ethtool_op_get_link, + .get_link = e1000_get_link, .get_eeprom_len = e1000_get_eeprom_len, .get_eeprom = e1000_get_eeprom, .set_eeprom = e1000_set_eeprom, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b608528f26fc..4ff50d6fe5e4 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2246,7 +2246,7 @@ static void e1000_82547_tx_fifo_stall(unsigned long data) } } -static bool e1000_has_link(struct e1000_adapter *adapter) +bool e1000_has_link(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; bool link_active = false; -- GitLab From dbb5aaebc44ce7f64b12904c58fbc1dd487982a7 Mon Sep 17 00:00:00 2001 From: Nick Nunley Date: Wed, 3 Feb 2010 14:49:48 +0000 Subject: [PATCH 1552/3892] e1000: call pci_save_state after pci_restore_state This patch adds a call to pci_save_state() immediately after the call to pci_restore_state(). Due to a change in the behavior of pci_restore_state() it is necessary to call pci_save_state() to keep the state_saved flag. This patch is based on a similar patch for ixgbe. Signed-off-by: Nicholas Nunley Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4ff50d6fe5e4..3b14dd718ab4 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -847,6 +847,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev, goto err_pci_reg; pci_set_master(pdev); + err = pci_save_state(pdev); + if (err) + goto err_alloc_etherdev; err = -ENOMEM; netdev = alloc_etherdev(sizeof(struct e1000_adapter)); @@ -4596,6 +4599,7 @@ static int e1000_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + pci_save_state(pdev); if (adapter->need_ioport) err = pci_enable_device(pdev); -- GitLab From 1a6c14a2c7c313c584f26730e67f062f474bb744 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 3 Feb 2010 14:18:50 +0000 Subject: [PATCH 1553/3892] ixgbe: Allocate driver resources per NUMA node The default policy for the current driver is to do all its memory allocation on whatever processor is running insmod/modprobe. This is less than optimal. This driver's default mode of operation will be to use each node for each subsequent transmit/receive queue. The most efficient allocation will be to then have the interrupts bound in such a way as to match up the interrupt of the queue to the cpu where its memory was allocated. Signed-off-by: Jesse Brandeburg Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 2 ++ drivers/net/ixgbe/ixgbe_main.c | 37 +++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 55a319e3a57a..33b79e812b4d 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -399,6 +399,8 @@ struct ixgbe_adapter { u32 wol; u16 eeprom_version; + int node; + /* SR-IOV */ DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS); unsigned int num_vfs; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 1ec3cbdf8729..87e1aa5ba788 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3946,7 +3946,11 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) } for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { - q_vector = kzalloc(sizeof(struct ixgbe_q_vector), GFP_KERNEL); + q_vector = kzalloc_node(sizeof(struct ixgbe_q_vector), + GFP_KERNEL, adapter->node); + if (!q_vector) + q_vector = kzalloc(sizeof(struct ixgbe_q_vector), + GFP_KERNEL); if (!q_vector) goto err_out; q_vector->adapter = adapter; @@ -4246,6 +4250,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) /* enable rx csum by default */ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + /* get assigned NUMA node */ + adapter->node = dev_to_node(&pdev->dev); + set_bit(__IXGBE_DOWN, &adapter->state); return 0; @@ -4265,7 +4272,9 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, int size; size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; - tx_ring->tx_buffer_info = vmalloc(size); + tx_ring->tx_buffer_info = vmalloc_node(size, adapter->node); + if (!tx_ring->tx_buffer_info) + tx_ring->tx_buffer_info = vmalloc(size); if (!tx_ring->tx_buffer_info) goto err; memset(tx_ring->tx_buffer_info, 0, size); @@ -4305,8 +4314,15 @@ err: static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) { int i, err = 0; + int orig_node = adapter->node; for (i = 0; i < adapter->num_tx_queues; i++) { + if (orig_node == -1) { + int cur_node = next_online_node(adapter->node); + if (cur_node == MAX_NUMNODES) + cur_node = first_online_node; + adapter->node = cur_node; + } err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); if (!err) continue; @@ -4314,6 +4330,9 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) break; } + /* reset the node back to its starting value */ + adapter->node = orig_node; + return err; } @@ -4331,7 +4350,9 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, int size; size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; - rx_ring->rx_buffer_info = vmalloc(size); + rx_ring->rx_buffer_info = vmalloc_node(size, adapter->node); + if (!rx_ring->rx_buffer_info) + rx_ring->rx_buffer_info = vmalloc(size); if (!rx_ring->rx_buffer_info) { DPRINTK(PROBE, ERR, "vmalloc allocation failed for the rx desc ring\n"); @@ -4375,8 +4396,15 @@ alloc_failed: static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) { int i, err = 0; + int orig_node = adapter->node; for (i = 0; i < adapter->num_rx_queues; i++) { + if (orig_node == -1) { + int cur_node = next_online_node(adapter->node); + if (cur_node == MAX_NUMNODES) + cur_node = first_online_node; + adapter->node = cur_node; + } err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); if (!err) continue; @@ -4384,6 +4412,9 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) break; } + /* reset the node back to its starting value */ + adapter->node = orig_node; + return err; } -- GitLab From 4a0b9ca015bae64df7d97c9e0a1d33159b36e69f Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Wed, 3 Feb 2010 14:19:12 +0000 Subject: [PATCH 1554/3892] ixgbe: Make descriptor ring allocations NUMA-aware This patch allocates the ring structures themselves on each NUMA node along with the buffer_info structures. This way we don't allocate the entire ring memory on a single node in one big block, thus reducing NUMA node memory crosstalk. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 5 +- drivers/net/ixgbe/ixgbe_ethtool.c | 71 ++++---- drivers/net/ixgbe/ixgbe_fcoe.c | 4 +- drivers/net/ixgbe/ixgbe_main.c | 276 ++++++++++++++++-------------- 4 files changed, 189 insertions(+), 167 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 33b79e812b4d..bffbe0d52d33 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -175,6 +175,7 @@ struct ixgbe_ring { struct ixgbe_queue_stats stats; unsigned long reinit_state; + int numa_node; u64 rsc_count; /* stat for coalesced packets */ u64 rsc_flush; /* stats for flushed packets */ u32 restart_queue; /* track tx queue restarts */ @@ -293,7 +294,7 @@ struct ixgbe_adapter { u16 eitr_high; /* TX */ - struct ixgbe_ring *tx_ring ____cacheline_aligned_in_smp; /* One per active queue */ + struct ixgbe_ring *tx_ring[MAX_TX_QUEUES] ____cacheline_aligned_in_smp; int num_tx_queues; u32 tx_timeout_count; bool detect_tx_hung; @@ -302,7 +303,7 @@ struct ixgbe_adapter { u64 lsc_int; /* RX */ - struct ixgbe_ring *rx_ring ____cacheline_aligned_in_smp; /* One per active queue */ + struct ixgbe_ring *rx_ring[MAX_RX_QUEUES] ____cacheline_aligned_in_smp; int num_rx_queues; int num_rx_pools; /* == num_rx_queues in 82598 */ int num_rx_queues_per_pool; /* 1 if 82598, can be many if 82599 */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 1525c86cbccf..07a9410c08d4 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -834,8 +834,8 @@ static void ixgbe_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - struct ixgbe_ring *tx_ring = adapter->tx_ring; - struct ixgbe_ring *rx_ring = adapter->rx_ring; + struct ixgbe_ring *tx_ring = adapter->tx_ring[0]; + struct ixgbe_ring *rx_ring = adapter->rx_ring[0]; ring->rx_max_pending = IXGBE_MAX_RXD; ring->tx_max_pending = IXGBE_MAX_TXD; @@ -867,8 +867,8 @@ static int ixgbe_set_ringparam(struct net_device *netdev, new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD); new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); - if ((new_tx_count == adapter->tx_ring->count) && - (new_rx_count == adapter->rx_ring->count)) { + if ((new_tx_count == adapter->tx_ring[0]->count) && + (new_rx_count == adapter->rx_ring[0]->count)) { /* nothing to do */ return 0; } @@ -878,25 +878,24 @@ static int ixgbe_set_ringparam(struct net_device *netdev, if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) - adapter->tx_ring[i].count = new_tx_count; + adapter->tx_ring[i]->count = new_tx_count; for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].count = new_rx_count; + adapter->rx_ring[i]->count = new_rx_count; adapter->tx_ring_count = new_tx_count; adapter->rx_ring_count = new_rx_count; - goto err_setup; + goto clear_reset; } - temp_tx_ring = kcalloc(adapter->num_tx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); + temp_tx_ring = vmalloc(adapter->num_tx_queues * sizeof(struct ixgbe_ring)); if (!temp_tx_ring) { err = -ENOMEM; - goto err_setup; + goto clear_reset; } if (new_tx_count != adapter->tx_ring_count) { - memcpy(temp_tx_ring, adapter->tx_ring, - adapter->num_tx_queues * sizeof(struct ixgbe_ring)); for (i = 0; i < adapter->num_tx_queues; i++) { + memcpy(&temp_tx_ring[i], adapter->tx_ring[i], + sizeof(struct ixgbe_ring)); temp_tx_ring[i].count = new_tx_count; err = ixgbe_setup_tx_resources(adapter, &temp_tx_ring[i]); @@ -904,28 +903,24 @@ static int ixgbe_set_ringparam(struct net_device *netdev, while (i) { i--; ixgbe_free_tx_resources(adapter, - &temp_tx_ring[i]); + &temp_tx_ring[i]); } - goto err_setup; + goto clear_reset; } } need_update = true; } - temp_rx_ring = kcalloc(adapter->num_rx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); - if ((!temp_rx_ring) && (need_update)) { - for (i = 0; i < adapter->num_tx_queues; i++) - ixgbe_free_tx_resources(adapter, &temp_tx_ring[i]); - kfree(temp_tx_ring); + temp_rx_ring = vmalloc(adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + if (!temp_rx_ring) { err = -ENOMEM; goto err_setup; } if (new_rx_count != adapter->rx_ring_count) { - memcpy(temp_rx_ring, adapter->rx_ring, - adapter->num_rx_queues * sizeof(struct ixgbe_ring)); for (i = 0; i < adapter->num_rx_queues; i++) { + memcpy(&temp_rx_ring[i], adapter->rx_ring[i], + sizeof(struct ixgbe_ring)); temp_rx_ring[i].count = new_rx_count; err = ixgbe_setup_rx_resources(adapter, &temp_rx_ring[i]); @@ -947,22 +942,32 @@ static int ixgbe_set_ringparam(struct net_device *netdev, /* tx */ if (new_tx_count != adapter->tx_ring_count) { - kfree(adapter->tx_ring); - adapter->tx_ring = temp_tx_ring; - temp_tx_ring = NULL; + for (i = 0; i < adapter->num_tx_queues; i++) { + ixgbe_free_tx_resources(adapter, + adapter->tx_ring[i]); + memcpy(adapter->tx_ring[i], &temp_tx_ring[i], + sizeof(struct ixgbe_ring)); + } adapter->tx_ring_count = new_tx_count; } /* rx */ if (new_rx_count != adapter->rx_ring_count) { - kfree(adapter->rx_ring); - adapter->rx_ring = temp_rx_ring; - temp_rx_ring = NULL; + for (i = 0; i < adapter->num_rx_queues; i++) { + ixgbe_free_rx_resources(adapter, + adapter->rx_ring[i]); + memcpy(adapter->rx_ring[i], &temp_rx_ring[i], + sizeof(struct ixgbe_ring)); + } adapter->rx_ring_count = new_rx_count; } ixgbe_up(adapter); } + + vfree(temp_rx_ring); err_setup: + vfree(temp_tx_ring); +clear_reset: clear_bit(__IXGBE_RESETTING, &adapter->state); return err; } @@ -1007,13 +1012,13 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } for (j = 0; j < adapter->num_tx_queues; j++) { - queue_stat = (u64 *)&adapter->tx_ring[j].stats; + queue_stat = (u64 *)&adapter->tx_ring[j]->stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { - queue_stat = (u64 *)&adapter->rx_ring[j].stats; + queue_stat = (u64 *)&adapter->rx_ring[j]->stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; @@ -1627,7 +1632,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) reg_data |= IXGBE_RXDCTL_ENABLE; IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data); if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - int j = adapter->rx_ring[0].reg_idx; + int j = adapter->rx_ring[0]->reg_idx; u32 k; for (k = 0; k < 10; k++) { if (IXGBE_READ_REG(&adapter->hw, @@ -2011,7 +2016,7 @@ static int ixgbe_get_coalesce(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); - ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit; + ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0]->work_limit; /* only valid if in constant ITR mode */ switch (adapter->rx_itr_setting) { @@ -2064,7 +2069,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, return -EINVAL; if (ec->tx_max_coalesced_frames_irq) - adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq; + adapter->tx_ring[0]->work_limit = ec->tx_max_coalesced_frames_irq; if (ec->rx_coalesce_usecs > 1) { /* check the limits */ diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index e9a20c88c155..4123dec0dfb7 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -525,7 +525,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { fcoe_i = f->mask + i % f->indices; fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; - fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); } IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); @@ -533,7 +533,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) } else { /* Use single rx queue for FCoE */ fcoe_i = f->mask; - fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), IXGBE_ETQS_QUEUE_EN | diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 87e1aa5ba788..2a3c8315e357 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -494,7 +494,7 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, { u32 rxctrl; int cpu = get_cpu(); - int q = rx_ring - adapter->rx_ring; + int q = rx_ring->reg_idx; if (rx_ring->cpu != cpu) { rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q)); @@ -522,7 +522,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, { u32 txctrl; int cpu = get_cpu(); - int q = tx_ring - adapter->tx_ring; + int q = tx_ring->reg_idx; struct ixgbe_hw *hw = &adapter->hw; if (tx_ring->cpu != cpu) { @@ -556,12 +556,12 @@ static void ixgbe_setup_dca(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); for (i = 0; i < adapter->num_tx_queues; i++) { - adapter->tx_ring[i].cpu = -1; - ixgbe_update_tx_dca(adapter, &adapter->tx_ring[i]); + adapter->tx_ring[i]->cpu = -1; + ixgbe_update_tx_dca(adapter, adapter->tx_ring[i]); } for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->rx_ring[i].cpu = -1; - ixgbe_update_rx_dca(adapter, &adapter->rx_ring[i]); + adapter->rx_ring[i]->cpu = -1; + ixgbe_update_rx_dca(adapter, adapter->rx_ring[i]); } } @@ -1032,7 +1032,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - j = adapter->rx_ring[r_idx].reg_idx; + j = adapter->rx_ring[r_idx]->reg_idx; ixgbe_set_ivar(adapter, 0, j, v_idx); r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, @@ -1042,7 +1042,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - j = adapter->tx_ring[r_idx].reg_idx; + j = adapter->tx_ring[r_idx]->reg_idx; ixgbe_set_ivar(adapter, 1, j, v_idx); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, @@ -1182,7 +1182,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - tx_ring = &(adapter->tx_ring[r_idx]); + tx_ring = adapter->tx_ring[r_idx]; ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, q_vector->tx_itr, tx_ring->total_packets, @@ -1197,7 +1197,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - rx_ring = &(adapter->rx_ring[r_idx]); + rx_ring = adapter->rx_ring[r_idx]; ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, q_vector->rx_itr, rx_ring->total_packets, @@ -1319,7 +1319,7 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) netif_tx_stop_all_queues(netdev); for (i = 0; i < adapter->num_tx_queues; i++) { struct ixgbe_ring *tx_ring = - &adapter->tx_ring[i]; + adapter->tx_ring[i]; if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE, &tx_ring->reinit_state)) schedule_work(&adapter->fdir_reinit_task); @@ -1378,7 +1378,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - tx_ring = &(adapter->tx_ring[r_idx]); + tx_ring = adapter->tx_ring[r_idx]; tx_ring->total_bytes = 0; tx_ring->total_packets = 0; r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, @@ -1406,7 +1406,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - rx_ring = &(adapter->rx_ring[r_idx]); + rx_ring = adapter->rx_ring[r_idx]; rx_ring->total_bytes = 0; rx_ring->total_packets = 0; r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, @@ -1436,7 +1436,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - ring = &(adapter->tx_ring[r_idx]); + ring = adapter->tx_ring[r_idx]; ring->total_bytes = 0; ring->total_packets = 0; r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, @@ -1445,7 +1445,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - ring = &(adapter->rx_ring[r_idx]); + ring = adapter->rx_ring[r_idx]; ring->total_bytes = 0; ring->total_packets = 0; r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, @@ -1476,7 +1476,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) long r_idx; r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - rx_ring = &(adapter->rx_ring[r_idx]); + rx_ring = adapter->rx_ring[r_idx]; #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ixgbe_update_rx_dca(adapter, rx_ring); @@ -1517,7 +1517,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { - ring = &(adapter->tx_ring[r_idx]); + ring = adapter->tx_ring[r_idx]; #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ixgbe_update_tx_dca(adapter, ring); @@ -1533,7 +1533,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget) budget = max(budget, 1); r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - ring = &(adapter->rx_ring[r_idx]); + ring = adapter->rx_ring[r_idx]; #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ixgbe_update_rx_dca(adapter, ring); @@ -1544,7 +1544,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget) } r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - ring = &(adapter->rx_ring[r_idx]); + ring = adapter->rx_ring[r_idx]; /* If all Rx work done, exit the polling mode */ if (work_done < budget) { napi_complete(napi); @@ -1577,7 +1577,7 @@ static int ixgbe_clean_txonly(struct napi_struct *napi, int budget) long r_idx; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); - tx_ring = &(adapter->tx_ring[r_idx]); + tx_ring = adapter->tx_ring[r_idx]; #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ixgbe_update_tx_dca(adapter, tx_ring); @@ -1762,8 +1762,8 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) struct ixgbe_q_vector *q_vector = adapter->q_vector[0]; u8 current_itr; u32 new_itr = q_vector->eitr; - struct ixgbe_ring *rx_ring = &adapter->rx_ring[0]; - struct ixgbe_ring *tx_ring = &adapter->tx_ring[0]; + struct ixgbe_ring *rx_ring = adapter->rx_ring[0]; + struct ixgbe_ring *tx_ring = adapter->tx_ring[0]; q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr, q_vector->tx_itr, @@ -1875,10 +1875,10 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); if (napi_schedule_prep(&(q_vector->napi))) { - adapter->tx_ring[0].total_packets = 0; - adapter->tx_ring[0].total_bytes = 0; - adapter->rx_ring[0].total_packets = 0; - adapter->rx_ring[0].total_bytes = 0; + adapter->tx_ring[0]->total_packets = 0; + adapter->tx_ring[0]->total_bytes = 0; + adapter->rx_ring[0]->total_packets = 0; + adapter->rx_ring[0]->total_bytes = 0; /* would disable interrupts here but EIAM disabled it */ __napi_schedule(&(q_vector->napi)); } @@ -2010,7 +2010,7 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ for (i = 0; i < adapter->num_tx_queues; i++) { - struct ixgbe_ring *ring = &adapter->tx_ring[i]; + struct ixgbe_ring *ring = adapter->tx_ring[i]; j = ring->reg_idx; tdba = ring->dma; tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc); @@ -2020,8 +2020,8 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen); IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); - adapter->tx_ring[i].head = IXGBE_TDH(j); - adapter->tx_ring[i].tail = IXGBE_TDT(j); + adapter->tx_ring[i]->head = IXGBE_TDH(j); + adapter->tx_ring[i]->tail = IXGBE_TDT(j); /* * Disable Tx Head Writeback RO bit, since this hoses * bookkeeping if things aren't delivered in order. @@ -2168,7 +2168,7 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index) u32 rscctrl; int rx_buf_len; - rx_ring = &adapter->rx_ring[index]; + rx_ring = adapter->rx_ring[index]; j = rx_ring->reg_idx; rx_buf_len = rx_ring->rx_buf_len; rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j)); @@ -2266,7 +2266,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) #endif IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); - rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); + rdlen = adapter->rx_ring[0]->count * sizeof(union ixgbe_adv_rx_desc); /* disable receives while setting up the descriptors */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); @@ -2276,7 +2276,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { - rx_ring = &adapter->rx_ring[i]; + rx_ring = adapter->rx_ring[i]; rdba = rx_ring->dma; j = rx_ring->reg_idx; IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_BIT_MASK(32))); @@ -2483,7 +2483,7 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) { for (i = 0; i < adapter->num_rx_queues; i++) { u32 ctrl; - j = adapter->rx_ring[i].reg_idx; + j = adapter->rx_ring[i]->reg_idx; ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(j)); ctrl |= IXGBE_RXDCTL_VME; IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(j), ctrl); @@ -2646,7 +2646,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); for (i = 0; i < adapter->num_tx_queues; i++) { - j = adapter->tx_ring[i].reg_idx; + j = adapter->tx_ring[i]->reg_idx; txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); /* PThresh workaround for Tx hang with DFP enabled. */ txdctl |= 32; @@ -2663,7 +2663,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); for (i = 0; i < adapter->num_rx_queues; i++) { - j = adapter->rx_ring[i].reg_idx; + j = adapter->rx_ring[i]->reg_idx; vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j)); vlnctrl |= IXGBE_RXDCTL_VME; IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl); @@ -2703,7 +2703,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) #endif /* IXGBE_FCOE */ if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) { for (i = 0; i < adapter->num_tx_queues; i++) - adapter->tx_ring[i].atr_sample_rate = + adapter->tx_ring[i]->atr_sample_rate = adapter->atr_sample_rate; ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) { @@ -2713,8 +2713,8 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) - ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i], - (adapter->rx_ring[i].count - 1)); + ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i], + (adapter->rx_ring[i]->count - 1)); } static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw) @@ -2797,7 +2797,7 @@ link_cfg_out: static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, int rxr) { - int j = adapter->rx_ring[rxr].reg_idx; + int j = adapter->rx_ring[rxr]->reg_idx; int k; for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) { @@ -2811,8 +2811,8 @@ static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d " "not set within the polling period\n", rxr); } - ixgbe_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr], - (adapter->rx_ring[rxr].count - 1)); + ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr], + (adapter->rx_ring[rxr]->count - 1)); } static int ixgbe_up_complete(struct ixgbe_adapter *adapter) @@ -2899,7 +2899,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) } for (i = 0; i < adapter->num_tx_queues; i++) { - j = adapter->tx_ring[i].reg_idx; + j = adapter->tx_ring[i]->reg_idx; txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); /* enable WTHRESH=8 descriptors, to encourage burst writeback */ txdctl |= (8 << 16); @@ -2913,7 +2913,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); } for (i = 0; i < adapter->num_tx_queues; i++) { - j = adapter->tx_ring[i].reg_idx; + j = adapter->tx_ring[i]->reg_idx; txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); txdctl |= IXGBE_TXDCTL_ENABLE; IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); @@ -2932,7 +2932,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) } for (i = 0; i < num_rx_rings; i++) { - j = adapter->rx_ring[i].reg_idx; + j = adapter->rx_ring[i]->reg_idx; rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j)); /* enable PTHRESH=32 descriptors (half the internal cache) * and HTHRESH=0 descriptors (to minimize latency on fetch), @@ -3006,7 +3006,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) set_bit(__IXGBE_FDIR_INIT_DONE, - &(adapter->tx_ring[i].reinit_state)); + &(adapter->tx_ring[i]->reinit_state)); /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -3177,7 +3177,7 @@ static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter) int i; for (i = 0; i < adapter->num_rx_queues; i++) - ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]); + ixgbe_clean_rx_ring(adapter, adapter->rx_ring[i]); } /** @@ -3189,7 +3189,7 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter) int i; for (i = 0; i < adapter->num_tx_queues; i++) - ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]); + ixgbe_clean_tx_ring(adapter, adapter->tx_ring[i]); } void ixgbe_down(struct ixgbe_adapter *adapter) @@ -3240,7 +3240,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { - j = adapter->tx_ring[i].reg_idx; + j = adapter->tx_ring[i]->reg_idx; txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), (txdctl & ~IXGBE_TXDCTL_ENABLE)); @@ -3280,13 +3280,13 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { - ixgbe_update_tx_dca(adapter, adapter->tx_ring); - ixgbe_update_rx_dca(adapter, adapter->rx_ring); + ixgbe_update_tx_dca(adapter, adapter->tx_ring[0]); + ixgbe_update_rx_dca(adapter, adapter->rx_ring[0]); } #endif - tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring); - ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget); + tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring[0]); + ixgbe_clean_rx_irq(q_vector, adapter->rx_ring[0], &work_done, budget); if (!tx_clean_complete) work_done = budget; @@ -3574,9 +3574,9 @@ static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].reg_idx = i; + adapter->rx_ring[i]->reg_idx = i; for (i = 0; i < adapter->num_tx_queues; i++) - adapter->tx_ring[i].reg_idx = i; + adapter->tx_ring[i]->reg_idx = i; ret = true; } else { ret = false; @@ -3603,8 +3603,8 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) if (adapter->hw.mac.type == ixgbe_mac_82598EB) { /* the number of queues is assumed to be symmetric */ for (i = 0; i < dcb_i; i++) { - adapter->rx_ring[i].reg_idx = i << 3; - adapter->tx_ring[i].reg_idx = i << 2; + adapter->rx_ring[i]->reg_idx = i << 3; + adapter->tx_ring[i]->reg_idx = i << 2; } ret = true; } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) { @@ -3622,18 +3622,18 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) * Rx TC0-TC7 are offset by 16 queues each */ for (i = 0; i < 3; i++) { - adapter->tx_ring[i].reg_idx = i << 5; - adapter->rx_ring[i].reg_idx = i << 4; + adapter->tx_ring[i]->reg_idx = i << 5; + adapter->rx_ring[i]->reg_idx = i << 4; } for ( ; i < 5; i++) { - adapter->tx_ring[i].reg_idx = + adapter->tx_ring[i]->reg_idx = ((i + 2) << 4); - adapter->rx_ring[i].reg_idx = i << 4; + adapter->rx_ring[i]->reg_idx = i << 4; } for ( ; i < dcb_i; i++) { - adapter->tx_ring[i].reg_idx = + adapter->tx_ring[i]->reg_idx = ((i + 8) << 3); - adapter->rx_ring[i].reg_idx = i << 4; + adapter->rx_ring[i]->reg_idx = i << 4; } ret = true; @@ -3646,12 +3646,12 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) * * Rx TC0-TC3 are offset by 32 queues each */ - adapter->tx_ring[0].reg_idx = 0; - adapter->tx_ring[1].reg_idx = 64; - adapter->tx_ring[2].reg_idx = 96; - adapter->tx_ring[3].reg_idx = 112; + adapter->tx_ring[0]->reg_idx = 0; + adapter->tx_ring[1]->reg_idx = 64; + adapter->tx_ring[2]->reg_idx = 96; + adapter->tx_ring[3]->reg_idx = 112; for (i = 0 ; i < dcb_i; i++) - adapter->rx_ring[i].reg_idx = i << 5; + adapter->rx_ring[i]->reg_idx = i << 5; ret = true; } else { @@ -3684,9 +3684,9 @@ static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) { for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].reg_idx = i; + adapter->rx_ring[i]->reg_idx = i; for (i = 0; i < adapter->num_tx_queues; i++) - adapter->tx_ring[i].reg_idx = i; + adapter->tx_ring[i]->reg_idx = i; ret = true; } @@ -3714,8 +3714,8 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) ixgbe_cache_ring_dcb(adapter); /* find out queues in TC for FCoE */ - fcoe_rx_i = adapter->rx_ring[fcoe->tc].reg_idx + 1; - fcoe_tx_i = adapter->tx_ring[fcoe->tc].reg_idx + 1; + fcoe_rx_i = adapter->rx_ring[fcoe->tc]->reg_idx + 1; + fcoe_tx_i = adapter->tx_ring[fcoe->tc]->reg_idx + 1; /* * In 82599, the number of Tx queues for each traffic * class for both 8-TC and 4-TC modes are: @@ -3746,8 +3746,8 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) fcoe_tx_i = f->mask; } for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) { - adapter->rx_ring[f->mask + i].reg_idx = fcoe_rx_i; - adapter->tx_ring[f->mask + i].reg_idx = fcoe_tx_i; + adapter->rx_ring[f->mask + i]->reg_idx = fcoe_rx_i; + adapter->tx_ring[f->mask + i]->reg_idx = fcoe_tx_i; } ret = true; } @@ -3765,8 +3765,8 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) */ static inline bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter) { - adapter->rx_ring[0].reg_idx = adapter->num_vfs * 2; - adapter->tx_ring[0].reg_idx = adapter->num_vfs * 2; + adapter->rx_ring[0]->reg_idx = adapter->num_vfs * 2; + adapter->tx_ring[0]->reg_idx = adapter->num_vfs * 2; if (adapter->num_vfs) return true; else @@ -3787,8 +3787,8 @@ static inline bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter) static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) { /* start with default case */ - adapter->rx_ring[0].reg_idx = 0; - adapter->tx_ring[0].reg_idx = 0; + adapter->rx_ring[0]->reg_idx = 0; + adapter->tx_ring[0]->reg_idx = 0; if (ixgbe_cache_ring_sriov(adapter)) return; @@ -3821,33 +3821,63 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter) { int i; - - adapter->tx_ring = kcalloc(adapter->num_tx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); - if (!adapter->tx_ring) - goto err_tx_ring_allocation; - - adapter->rx_ring = kcalloc(adapter->num_rx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); - if (!adapter->rx_ring) - goto err_rx_ring_allocation; + int orig_node = adapter->node; for (i = 0; i < adapter->num_tx_queues; i++) { - adapter->tx_ring[i].count = adapter->tx_ring_count; - adapter->tx_ring[i].queue_index = i; + struct ixgbe_ring *ring = adapter->tx_ring[i]; + if (orig_node == -1) { + int cur_node = next_online_node(adapter->node); + if (cur_node == MAX_NUMNODES) + cur_node = first_online_node; + adapter->node = cur_node; + } + ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL, + adapter->node); + if (!ring) + ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!ring) + goto err_tx_ring_allocation; + ring->count = adapter->tx_ring_count; + ring->queue_index = i; + ring->numa_node = adapter->node; + + adapter->tx_ring[i] = ring; } + /* Restore the adapter's original node */ + adapter->node = orig_node; + for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->rx_ring[i].count = adapter->rx_ring_count; - adapter->rx_ring[i].queue_index = i; + struct ixgbe_ring *ring = adapter->rx_ring[i]; + if (orig_node == -1) { + int cur_node = next_online_node(adapter->node); + if (cur_node == MAX_NUMNODES) + cur_node = first_online_node; + adapter->node = cur_node; + } + ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL, + adapter->node); + if (!ring) + ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!ring) + goto err_rx_ring_allocation; + ring->count = adapter->rx_ring_count; + ring->queue_index = i; + ring->numa_node = adapter->node; + + adapter->rx_ring[i] = ring; } + /* Restore the adapter's original node */ + adapter->node = orig_node; + ixgbe_cache_ring_register(adapter); return 0; err_rx_ring_allocation: - kfree(adapter->tx_ring); + for (i = 0; i < adapter->num_tx_queues; i++) + kfree(adapter->tx_ring[i]); err_tx_ring_allocation: return -ENOMEM; } @@ -4077,10 +4107,16 @@ err_set_interrupt: **/ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) { - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - adapter->tx_ring = NULL; - adapter->rx_ring = NULL; + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) { + kfree(adapter->tx_ring[i]); + adapter->tx_ring[i] = NULL; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + kfree(adapter->rx_ring[i]); + adapter->rx_ring[i] = NULL; + } ixgbe_free_q_vectors(adapter); ixgbe_reset_interrupt_capability(adapter); @@ -4272,7 +4308,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, int size; size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; - tx_ring->tx_buffer_info = vmalloc_node(size, adapter->node); + tx_ring->tx_buffer_info = vmalloc_node(size, tx_ring->numa_node); if (!tx_ring->tx_buffer_info) tx_ring->tx_buffer_info = vmalloc(size); if (!tx_ring->tx_buffer_info) @@ -4314,25 +4350,15 @@ err: static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) { int i, err = 0; - int orig_node = adapter->node; for (i = 0; i < adapter->num_tx_queues; i++) { - if (orig_node == -1) { - int cur_node = next_online_node(adapter->node); - if (cur_node == MAX_NUMNODES) - cur_node = first_online_node; - adapter->node = cur_node; - } - err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); + err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]); if (!err) continue; DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i); break; } - /* reset the node back to its starting value */ - adapter->node = orig_node; - return err; } @@ -4396,25 +4422,15 @@ alloc_failed: static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) { int i, err = 0; - int orig_node = adapter->node; for (i = 0; i < adapter->num_rx_queues; i++) { - if (orig_node == -1) { - int cur_node = next_online_node(adapter->node); - if (cur_node == MAX_NUMNODES) - cur_node = first_online_node; - adapter->node = cur_node; - } - err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); + err = ixgbe_setup_rx_resources(adapter, adapter->rx_ring[i]); if (!err) continue; DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i); break; } - /* reset the node back to its starting value */ - adapter->node = orig_node; - return err; } @@ -4451,8 +4467,8 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter) int i; for (i = 0; i < adapter->num_tx_queues; i++) - if (adapter->tx_ring[i].desc) - ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); + if (adapter->tx_ring[i]->desc) + ixgbe_free_tx_resources(adapter, adapter->tx_ring[i]); } /** @@ -4488,8 +4504,8 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) int i; for (i = 0; i < adapter->num_rx_queues; i++) - if (adapter->rx_ring[i].desc) - ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); + if (adapter->rx_ring[i]->desc) + ixgbe_free_rx_resources(adapter, adapter->rx_ring[i]); } /** @@ -4766,8 +4782,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->hw_rx_no_dma_resources += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); for (i = 0; i < adapter->num_rx_queues; i++) { - rsc_count += adapter->rx_ring[i].rsc_count; - rsc_flush += adapter->rx_ring[i].rsc_flush; + rsc_count += adapter->rx_ring[i]->rsc_count; + rsc_flush += adapter->rx_ring[i]->rsc_flush; } adapter->rsc_total_count = rsc_count; adapter->rsc_total_flush = rsc_flush; @@ -4775,11 +4791,11 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) /* gather some stats to the adapter struct that are per queue */ for (i = 0; i < adapter->num_tx_queues; i++) - restart_queue += adapter->tx_ring[i].restart_queue; + restart_queue += adapter->tx_ring[i]->restart_queue; adapter->restart_queue = restart_queue; for (i = 0; i < adapter->num_rx_queues; i++) - non_eop_descs += adapter->rx_ring[i].non_eop_descs; + non_eop_descs += adapter->rx_ring[i]->non_eop_descs; adapter->non_eop_descs = non_eop_descs; adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); @@ -5018,7 +5034,7 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work) if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { for (i = 0; i < adapter->num_tx_queues; i++) set_bit(__IXGBE_FDIR_INIT_DONE, - &(adapter->tx_ring[i].reinit_state)); + &(adapter->tx_ring[i]->reinit_state)); } else { DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, " "ignored adding FDIR ATR filters \n"); @@ -5120,7 +5136,7 @@ static void ixgbe_watchdog_task(struct work_struct *work) if (!netif_carrier_ok(netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = &adapter->tx_ring[i]; + tx_ring = adapter->tx_ring[i]; if (tx_ring->next_to_use != tx_ring->next_to_clean) { some_tx_pending = 1; break; @@ -5622,7 +5638,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, } } - tx_ring = &adapter->tx_ring[skb->queue_mapping]; + tx_ring = adapter->tx_ring[skb->queue_mapping]; if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && (skb->protocol == htons(ETH_P_FCOE))) { -- GitLab From a112fd4ce3ed965dfb8dc6791622cb4f25ba3619 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 3 Feb 2010 07:24:11 +0000 Subject: [PATCH 1555/3892] qlge: Move reset from eeh io_resume to slot_reset. Issue asic reset and verify functionality before continuing to the resume call. This allows proper error code to be returned in the case the asic does not recover. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5be3ae2f5a16..87ec72064158 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4717,6 +4717,12 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } pci_set_master(pdev); + + if (ql_adapter_reset(qdev)) { + QPRINTK(qdev, DRV, ERR, "reset FAILED!\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_RECOVERED; } @@ -4726,8 +4732,6 @@ static void qlge_io_resume(struct pci_dev *pdev) struct ql_adapter *qdev = netdev_priv(ndev); int err = 0; - if (ql_adapter_reset(qdev)) - QPRINTK(qdev, DRV, ERR, "reset FAILED!\n"); if (netif_running(ndev)) { err = qlge_open(ndev); if (err) { -- GitLab From 4bbd1a1903639f826215d76af74f4901efc34daa Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 3 Feb 2010 07:24:12 +0000 Subject: [PATCH 1556/3892] qlge: Add check for eeh failure when closing device. Fix crash where resources are freed twice on an eeh recovery failure. If eeh recovery fails we set a flag to indicate to close() that resources have been freed. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 1 + drivers/net/qlge/qlge_main.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 9169c4cf413a..780a38731bcc 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2005,6 +2005,7 @@ enum { QL_SELFTEST = 9, QL_LB_LINK_UP = 10, QL_FRC_COREDUMP = 11, + QL_EEH_FATAL = 12, }; /* link_status bit definitions */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 87ec72064158..7e000295f359 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3929,6 +3929,16 @@ static int qlge_close(struct net_device *ndev) { struct ql_adapter *qdev = netdev_priv(ndev); + /* If we hit pci_channel_io_perm_failure + * failure condition, then we already + * brought the adapter down. + */ + if (test_bit(QL_EEH_FATAL, &qdev->flags)) { + QPRINTK(qdev, DRV, ERR, "EEH fatal did unload.\n"); + clear_bit(QL_EEH_FATAL, &qdev->flags); + return 0; + } + /* * Wait for device to recover from a reset. * (Rarely happens, but possible.) @@ -4677,6 +4687,7 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, enum pci_channel_state state) { struct net_device *ndev = pci_get_drvdata(pdev); + struct ql_adapter *qdev = netdev_priv(ndev); switch (state) { case pci_channel_io_normal: @@ -4690,6 +4701,8 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, case pci_channel_io_perm_failure: dev_err(&pdev->dev, "%s: pci_channel_io_perm_failure.\n", __func__); + ql_eeh_close(ndev); + set_bit(QL_EEH_FATAL, &qdev->flags); return PCI_ERS_RESULT_DISCONNECT; } @@ -4720,6 +4733,7 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev) if (ql_adapter_reset(qdev)) { QPRINTK(qdev, DRV, ERR, "reset FAILED!\n"); + set_bit(QL_EEH_FATAL, &qdev->flags); return PCI_ERS_RESULT_DISCONNECT; } -- GitLab From e23e11792a77c7d54f363841cd5e33074fb0c8c9 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 2 Feb 2010 12:43:44 +0000 Subject: [PATCH 1557/3892] hisax: timeout off by one in waitrecmsg() With `while (timeout++ < maxdelay)' timeout reaches maxdelay + 1 after the loop This is probably unlikely a problem in practice. Signed-off-by: Roel Kluin Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hisax/isar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index bfeb9b6aa043..6bde16c00fb5 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -138,7 +138,7 @@ waitrecmsg(struct IsdnCardState *cs, u_char *len, while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && (timeout++ < maxdelay)) udelay(1); - if (timeout >= maxdelay) { + if (timeout > maxdelay) { printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); return(0); } -- GitLab From f0f4d641d4ebfeb4194e9c26dfa6286802e2e8d1 Mon Sep 17 00:00:00 2001 From: Darren Jenkins Date: Tue, 2 Feb 2010 12:43:45 +0000 Subject: [PATCH 1558/3892] hardware/mISDN/mISDNinfineon.c: bail out of loop on error If setup_instance() fails we kfree() the card, and then use it in the next loop iteration. So lets bail out of the loop instead. Coverity CID: 13357 Signed-off-by: Darren Jenkins Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/mISDNinfineon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c index 62441ba53b95..36c6c616a655 100644 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -1133,6 +1133,7 @@ inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) { kfree(sc); release_card(card); + break; } else card->sc[i - 1] = sc; } -- GitLab From 3e5981774755f2f967cd1d3f3898576cff20e565 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Feb 2010 12:43:46 +0000 Subject: [PATCH 1559/3892] isdn: mISDN, don't compile unused stuff Remove these compiler warnings: drivers/isdn/hardware/mISDN/w6692.c:534: warning: `setvolume' defined but not used drivers/isdn/hardware/mISDN/w6692.c:561: warning: `enable_pots' defined but not used by moving the functions inside #if 0 ... #endif. And an alternative is to remove them completely if nobody has plans to use them. Signed-off-by: Jiri Slaby Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/w6692.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index d3f1077b709b..2952a58c7a61 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -529,6 +529,7 @@ W6692_fill_Bfifo(struct w6692_ch *wch) } } +#if 0 static int setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) { @@ -571,6 +572,7 @@ enable_pots(struct w6692_ch *wch) WriteW6692(card, W_PCTL, card->pctl); return 0; } +#endif static int disable_pots(struct w6692_ch *wch) -- GitLab From 650b2ef5d7f1378f65e6a313909d783e4b6477ed Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 2 Feb 2010 12:43:47 +0000 Subject: [PATCH 1560/3892] mISDN: positive error return should be negative in mode_hfcmulti() The error return should be negative. Its only caller that acts upon its return, handle_bmsg(), transmits the positive error but can also return negative errors. Signed-off-by: Roel Kluin Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/hfcmulti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 1a1420d7a828..ad36df9b759c 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -2846,7 +2846,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, int conf; if (ch < 0 || ch > 31) - return EINVAL; + return -EINVAL; oslot_tx = hc->chan[ch].slot_tx; oslot_rx = hc->chan[ch].slot_rx; conf = hc->chan[ch].conf; -- GitLab From 6884b348ed759184032306c9435a727741a72298 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 2 Feb 2010 12:43:59 +0000 Subject: [PATCH 1561/3892] net/rds: remove uses of NIPQUAD, use %pI4 Signed-off-by: Joe Perches Cc: Andy Grover Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/rds/tcp_connect.c | 7 +++---- net/rds/tcp_listen.c | 6 +++--- net/rds/tcp_send.c | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c index 211522f9a9a2..056256285987 100644 --- a/net/rds/tcp_connect.c +++ b/net/rds/tcp_connect.c @@ -90,8 +90,8 @@ int rds_tcp_conn_connect(struct rds_connection *conn) ret = sock->ops->bind(sock, (struct sockaddr *)&src, sizeof(src)); if (ret) { - rdsdebug("bind failed with %d at address %u.%u.%u.%u\n", - ret, NIPQUAD(conn->c_laddr)); + rdsdebug("bind failed with %d at address %pI4\n", + ret, &conn->c_laddr); goto out; } @@ -108,8 +108,7 @@ int rds_tcp_conn_connect(struct rds_connection *conn) O_NONBLOCK); sock = NULL; - rdsdebug("connect to address %u.%u.%u.%u returned %d\n", - NIPQUAD(conn->c_faddr), ret); + rdsdebug("connect to address %pI4 returned %d\n", &conn->c_faddr, ret); if (ret == -EINPROGRESS) ret = 0; diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index 45474a436862..53cb1b54165d 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -66,9 +66,9 @@ static int rds_tcp_accept_one(struct socket *sock) inet = inet_sk(new_sock->sk); - rdsdebug("accepted tcp %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", - NIPQUAD(inet->inet_saddr), ntohs(inet->inet_sport), - NIPQUAD(inet->inet_daddr), ntohs(inet->inet_dport)); + rdsdebug("accepted tcp %pI4:%u -> %pI4:%u\n", + &inet->inet_saddr, ntohs(inet->inet_sport), + &inet->inet_daddr, ntohs(inet->inet_dport)); conn = rds_conn_create(inet->inet_saddr, inet->inet_daddr, &rds_tcp_transport, GFP_KERNEL); diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c index ab545e0cd5d6..34fdcc059e54 100644 --- a/net/rds/tcp_send.c +++ b/net/rds/tcp_send.c @@ -193,9 +193,9 @@ out: rds_tcp_stats_inc(s_tcp_sndbuf_full); ret = 0; } else { - printk(KERN_WARNING "RDS/tcp: send to %u.%u.%u.%u " + printk(KERN_WARNING "RDS/tcp: send to %pI4 " "returned %d, disconnecting and reconnecting\n", - NIPQUAD(conn->c_faddr), ret); + &conn->c_faddr, ret); rds_conn_drop(conn); } } -- GitLab From 8a83a00b0735190384a348156837918271034144 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 30 Jan 2010 12:23:03 +0000 Subject: [PATCH 1562/3892] net: maintain namespace isolation between vlan and real device In the vlan and macvlan drivers, the start_xmit function forwards data to the dev_queue_xmit function for another device, which may potentially belong to a different namespace. To make sure that classification stays within a single namespace, this resets the potentially critical fields. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- include/linux/netdevice.h | 9 +++++++++ net/8021q/vlan_dev.c | 2 +- net/core/dev.c | 35 +++++++++++++++++++++++++++++++---- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index fa0dc514dbaf..d32e0bdfc5e9 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -269,7 +269,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) } xmit_world: - skb->dev = vlan->lowerdev; + skb_set_dev(skb, vlan->lowerdev); return dev_queue_xmit(skb); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 93a32a5ca74f..622ba5aa93c4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1004,6 +1004,15 @@ static inline bool netdev_uses_dsa_tags(struct net_device *dev) return 0; } +#ifndef CONFIG_NET_NS +static inline void skb_set_dev(struct sk_buff *skb, struct net_device *dev) +{ + skb->dev = dev; +} +#else /* CONFIG_NET_NS */ +void skb_set_dev(struct sk_buff *skb, struct net_device *dev); +#endif + static inline bool netdev_uses_trailer_tags(struct net_device *dev) { #ifdef CONFIG_NET_DSA_TAG_TRAILER diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index a9e1f1785614..9e83272fc5b0 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -322,7 +322,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, } - skb->dev = vlan_dev_info(dev)->real_dev; + skb_set_dev(skb, vlan_dev_info(dev)->real_dev); len = skb->len; ret = dev_queue_xmit(skb); diff --git a/net/core/dev.c b/net/core/dev.c index 2cba5c521e56..94c1eeed25e5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1448,13 +1448,10 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) if (skb->len > (dev->mtu + dev->hard_header_len)) return NET_RX_DROP; - skb_dst_drop(skb); + skb_set_dev(skb, dev); skb->tstamp.tv64 = 0; skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, dev); - skb->mark = 0; - secpath_reset(skb); - nf_reset(skb); return netif_rx(skb); } EXPORT_SYMBOL_GPL(dev_forward_skb); @@ -1614,6 +1611,36 @@ static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb) return false; } +/** + * skb_dev_set -- assign a new device to a buffer + * @skb: buffer for the new device + * @dev: network device + * + * If an skb is owned by a device already, we have to reset + * all data private to the namespace a device belongs to + * before assigning it a new device. + */ +#ifdef CONFIG_NET_NS +void skb_set_dev(struct sk_buff *skb, struct net_device *dev) +{ + skb_dst_drop(skb); + if (skb->dev && !net_eq(dev_net(skb->dev), dev_net(dev))) { + secpath_reset(skb); + nf_reset(skb); + skb_init_secmark(skb); + skb->mark = 0; + skb->priority = 0; + skb->nf_trace = 0; + skb->ipvs_property = 0; +#ifdef CONFIG_NET_SCHED + skb->tc_index = 0; +#endif + } + skb->dev = dev; +} +EXPORT_SYMBOL(skb_set_dev); +#endif /* CONFIG_NET_NS */ + /* * Invalidate hardware checksum when packet is to be mangled, and * complete checksum manually on outgoing path. -- GitLab From fc0663d6b5e6d8e9b57f872a644c0aafd82361b7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 30 Jan 2010 12:23:40 +0000 Subject: [PATCH 1563/3892] macvlan: allow multiple driver backends This makes it possible to hook into the macvlan driver from another kernel module. In particular, the goal is to extend it with the macvtap backend that provides a tun/tap compatible interface directly on the macvlan device. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 113 ++++++++++++++++--------------------- include/linux/if_macvlan.h | 70 +++++++++++++++++++++++ 2 files changed, 119 insertions(+), 64 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d32e0bdfc5e9..40faa368b07a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -39,31 +39,6 @@ struct macvlan_port { struct list_head vlans; }; -/** - * struct macvlan_rx_stats - MACVLAN percpu rx stats - * @rx_packets: number of received packets - * @rx_bytes: number of received bytes - * @multicast: number of received multicast packets - * @rx_errors: number of errors - */ -struct macvlan_rx_stats { - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long multicast; - unsigned long rx_errors; -}; - -struct macvlan_dev { - struct net_device *dev; - struct list_head list; - struct hlist_node hlist; - struct macvlan_port *port; - struct net_device *lowerdev; - struct macvlan_rx_stats *rx_stats; - enum macvlan_mode mode; -}; - - static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, const unsigned char *addr) { @@ -118,31 +93,17 @@ static int macvlan_addr_busy(const struct macvlan_port *port, return 0; } -static inline void macvlan_count_rx(const struct macvlan_dev *vlan, - unsigned int len, bool success, - bool multicast) -{ - struct macvlan_rx_stats *rx_stats; - - rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); - if (likely(success)) { - rx_stats->rx_packets++;; - rx_stats->rx_bytes += len; - if (multicast) - rx_stats->multicast++; - } else { - rx_stats->rx_errors++; - } -} -static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, +static int macvlan_broadcast_one(struct sk_buff *skb, + const struct macvlan_dev *vlan, const struct ethhdr *eth, bool local) { + struct net_device *dev = vlan->dev; if (!skb) return NET_RX_DROP; if (local) - return dev_forward_skb(dev, skb); + return vlan->forward(dev, skb); skb->dev = dev; if (!compare_ether_addr_64bits(eth->h_dest, @@ -151,7 +112,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, else skb->pkt_type = PACKET_MULTICAST; - return netif_rx(skb); + return vlan->receive(skb); } static void macvlan_broadcast(struct sk_buff *skb, @@ -175,7 +136,7 @@ static void macvlan_broadcast(struct sk_buff *skb, continue; nskb = skb_clone(skb, GFP_ATOMIC); - err = macvlan_broadcast_one(nskb, vlan->dev, eth, + err = macvlan_broadcast_one(nskb, vlan, eth, mode == MACVLAN_MODE_BRIDGE); macvlan_count_rx(vlan, skb->len + ETH_HLEN, err == NET_RX_SUCCESS, 1); @@ -238,7 +199,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) skb->dev = dev; skb->pkt_type = PACKET_HOST; - netif_rx(skb); + vlan->receive(skb); return NULL; } @@ -260,7 +221,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) dest = macvlan_hash_lookup(port, eth->h_dest); if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { unsigned int length = skb->len + ETH_HLEN; - int ret = dev_forward_skb(dest->dev, skb); + int ret = dest->forward(dest->dev, skb); macvlan_count_rx(dest, length, ret == NET_RX_SUCCESS, 0); @@ -273,8 +234,8 @@ xmit_world: return dev_queue_xmit(skb); } -static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, - struct net_device *dev) +netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, + struct net_device *dev) { int i = skb_get_queue_mapping(skb); struct netdev_queue *txq = netdev_get_tx_queue(dev, i); @@ -290,6 +251,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, return ret; } +EXPORT_SYMBOL_GPL(macvlan_start_xmit); static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, @@ -623,8 +585,11 @@ static int macvlan_get_tx_queues(struct net *net, return 0; } -static int macvlan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +int macvlan_common_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + int (*receive)(struct sk_buff *skb), + int (*forward)(struct net_device *dev, + struct sk_buff *skb)) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_port *port; @@ -664,6 +629,8 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, vlan->lowerdev = lowerdev; vlan->dev = dev; vlan->port = port; + vlan->receive = receive; + vlan->forward = forward; vlan->mode = MACVLAN_MODE_VEPA; if (data && data[IFLA_MACVLAN_MODE]) @@ -677,8 +644,17 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, netif_stacked_transfer_operstate(lowerdev, dev); return 0; } +EXPORT_SYMBOL_GPL(macvlan_common_newlink); -static void macvlan_dellink(struct net_device *dev, struct list_head *head) +static int macvlan_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + return macvlan_common_newlink(src_net, dev, tb, data, + netif_rx, + dev_forward_skb); +} + +void macvlan_dellink(struct net_device *dev, struct list_head *head) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_port *port = vlan->port; @@ -689,6 +665,7 @@ static void macvlan_dellink(struct net_device *dev, struct list_head *head) if (list_empty(&port->vlans)) macvlan_port_destroy(port->dev); } +EXPORT_SYMBOL_GPL(macvlan_dellink); static int macvlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) @@ -720,19 +697,27 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, }; -static struct rtnl_link_ops macvlan_link_ops __read_mostly = { +int macvlan_link_register(struct rtnl_link_ops *ops) +{ + /* common fields */ + ops->priv_size = sizeof(struct macvlan_dev); + ops->get_tx_queues = macvlan_get_tx_queues; + ops->setup = macvlan_setup; + ops->validate = macvlan_validate; + ops->maxtype = IFLA_MACVLAN_MAX; + ops->policy = macvlan_policy; + ops->changelink = macvlan_changelink; + ops->get_size = macvlan_get_size; + ops->fill_info = macvlan_fill_info; + + return rtnl_link_register(ops); +}; +EXPORT_SYMBOL_GPL(macvlan_link_register); + +static struct rtnl_link_ops macvlan_link_ops = { .kind = "macvlan", - .priv_size = sizeof(struct macvlan_dev), - .get_tx_queues = macvlan_get_tx_queues, - .setup = macvlan_setup, - .validate = macvlan_validate, .newlink = macvlan_newlink, .dellink = macvlan_dellink, - .maxtype = IFLA_MACVLAN_MAX, - .policy = macvlan_policy, - .changelink = macvlan_changelink, - .get_size = macvlan_get_size, - .fill_info = macvlan_fill_info, }; static int macvlan_device_event(struct notifier_block *unused, @@ -761,7 +746,7 @@ static int macvlan_device_event(struct notifier_block *unused, break; case NETDEV_UNREGISTER: list_for_each_entry_safe(vlan, next, &port->vlans, list) - macvlan_dellink(vlan->dev, NULL); + vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); break; } return NOTIFY_DONE; @@ -778,7 +763,7 @@ static int __init macvlan_init_module(void) register_netdevice_notifier(&macvlan_notifier_block); macvlan_handle_frame_hook = macvlan_handle_frame; - err = rtnl_link_register(&macvlan_link_ops); + err = macvlan_link_register(&macvlan_link_ops); if (err < 0) goto err1; return 0; diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 5f200bac3749..9a11544bb0b1 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -1,6 +1,76 @@ #ifndef _LINUX_IF_MACVLAN_H #define _LINUX_IF_MACVLAN_H +#include +#include +#include +#include +#include + +struct macvlan_port; +struct macvtap_queue; + +/** + * struct macvlan_rx_stats - MACVLAN percpu rx stats + * @rx_packets: number of received packets + * @rx_bytes: number of received bytes + * @multicast: number of received multicast packets + * @rx_errors: number of errors + */ +struct macvlan_rx_stats { + unsigned long rx_packets; + unsigned long rx_bytes; + unsigned long multicast; + unsigned long rx_errors; +}; + +struct macvlan_dev { + struct net_device *dev; + struct list_head list; + struct hlist_node hlist; + struct macvlan_port *port; + struct net_device *lowerdev; + struct macvlan_rx_stats *rx_stats; + enum macvlan_mode mode; + int (*receive)(struct sk_buff *skb); + int (*forward)(struct net_device *dev, struct sk_buff *skb); +}; + +static inline void macvlan_count_rx(const struct macvlan_dev *vlan, + unsigned int len, bool success, + bool multicast) +{ + struct macvlan_rx_stats *rx_stats; + + rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); + if (likely(success)) { + rx_stats->rx_packets++;; + rx_stats->rx_bytes += len; + if (multicast) + rx_stats->multicast++; + } else { + rx_stats->rx_errors++; + } +} + +extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + int (*receive)(struct sk_buff *skb), + int (*forward)(struct net_device *dev, + struct sk_buff *skb)); + +extern void macvlan_count_rx(const struct macvlan_dev *vlan, + unsigned int len, bool success, + bool multicast); + +extern void macvlan_dellink(struct net_device *dev, struct list_head *head); + +extern int macvlan_link_register(struct rtnl_link_ops *ops); + +extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, + struct net_device *dev); + + extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *); #endif /* _LINUX_IF_MACVLAN_H */ -- GitLab From 20d29d7a916a47bf533b5709437fe735b6b5b79e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 30 Jan 2010 12:24:26 +0000 Subject: [PATCH 1564/3892] net: macvtap driver In order to use macvlan with qemu and other tools that require a tap file descriptor, the macvtap driver adds a small backend with a character device with the same interface as the tun driver, with a minimum set of features. Macvtap interfaces are created in the same way as macvlan interfaces using ip link, but the netif is just used as a handle for configuration and accounting, while the data goes through the chardev. Each macvtap interface has its own character device, simplifying permission management significantly over the generic tun/tap driver. Cc: Patrick McHardy Cc: Stephen Hemminger Cc: David S. Miller" Cc: "Michael S. Tsirkin" Cc: Herbert Xu Cc: Or Gerlitz Cc: netdev@vger.kernel.org Cc: bridge@lists.linux-foundation.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/Kconfig | 12 + drivers/net/Makefile | 1 + drivers/net/macvtap.c | 581 +++++++++++++++++++++++++++++++++++++ include/linux/if_macvlan.h | 1 + 4 files changed, 595 insertions(+) create mode 100644 drivers/net/macvtap.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index cb0e534418e3..411e20703110 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -90,6 +90,18 @@ config MACVLAN To compile this driver as a module, choose M here: the module will be called macvlan. +config MACVTAP + tristate "MAC-VLAN based tap driver (EXPERIMENTAL)" + depends on MACVLAN + help + This adds a specialized tap character device driver that is based + on the MAC-VLAN network interface, called macvtap. A macvtap device + can be added in the same way as a macvlan device, using 'type + macvlan', and then be accessed through the tap user space interface. + + To compile this driver as a module, choose M here: the module + will be called macvtap. + config EQUALIZER tristate "EQL (serial line load balancing) support" ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0b763cbe9b1f..95958032cd31 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -169,6 +169,7 @@ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACVLAN) += macvlan.o +obj-$(CONFIG_MACVTAP) += macvtap.o obj-$(CONFIG_DE600) += de600.o obj-$(CONFIG_DE620) += de620.o obj-$(CONFIG_LANCE) += lance.o diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c new file mode 100644 index 000000000000..ad1f6ef89308 --- /dev/null +++ b/drivers/net/macvtap.c @@ -0,0 +1,581 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * A macvtap queue is the central object of this driver, it connects + * an open character device to a macvlan interface. There can be + * multiple queues on one interface, which map back to queues + * implemented in hardware on the underlying device. + * + * macvtap_proto is used to allocate queues through the sock allocation + * mechanism. + * + * TODO: multiqueue support is currently not implemented, even though + * macvtap is basically prepared for that. We will need to add this + * here as well as in virtio-net and qemu to get line rate on 10gbit + * adapters from a guest. + */ +struct macvtap_queue { + struct sock sk; + struct socket sock; + struct macvlan_dev *vlan; + struct file *file; +}; + +static struct proto macvtap_proto = { + .name = "macvtap", + .owner = THIS_MODULE, + .obj_size = sizeof (struct macvtap_queue), +}; + +/* + * Minor number matches netdev->ifindex, so need a potentially + * large value. This also makes it possible to split the + * tap functionality out again in the future by offering it + * from other drivers besides macvtap. As long as every device + * only has one tap, the interface numbers assure that the + * device nodes are unique. + */ +static unsigned int macvtap_major; +#define MACVTAP_NUM_DEVS 65536 +static struct class *macvtap_class; +static struct cdev macvtap_cdev; + +/* + * RCU usage: + * The macvtap_queue is referenced both from the chardev struct file + * and from the struct macvlan_dev using rcu_read_lock. + * + * We never actually update the contents of a macvtap_queue atomically + * with RCU but it is used for race-free destruction of a queue when + * either the file or the macvlan_dev goes away. Pointers back to + * the dev and the file are implicitly valid as long as the queue + * exists. + * + * The callbacks from macvlan are always done with rcu_read_lock held + * already, while in the file_operations, we get it ourselves. + * + * When destroying a queue, we remove the pointers from the file and + * from the dev and then synchronize_rcu to make sure no thread is + * still using the queue. There may still be references to the struct + * sock inside of the queue from outbound SKBs, but these never + * reference back to the file or the dev. The data structure is freed + * through __sk_free when both our references and any pending SKBs + * are gone. + * + * macvtap_lock is only used to prevent multiple concurrent open() + * calls to assign a new vlan->tap pointer. It could be moved into + * the macvlan_dev itself but is extremely rarely used. + */ +static DEFINE_SPINLOCK(macvtap_lock); + +/* + * Choose the next free queue, for now there is only one + */ +static int macvtap_set_queue(struct net_device *dev, struct file *file, + struct macvtap_queue *q) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + int err = -EBUSY; + + spin_lock(&macvtap_lock); + if (rcu_dereference(vlan->tap)) + goto out; + + err = 0; + q->vlan = vlan; + rcu_assign_pointer(vlan->tap, q); + + q->file = file; + rcu_assign_pointer(file->private_data, q); + +out: + spin_unlock(&macvtap_lock); + return err; +} + +/* + * We must destroy each queue exactly once, when either + * the netdev or the file go away. + * + * Using the spinlock makes sure that we don't get + * to the queue again after destroying it. + * + * synchronize_rcu serializes with the packet flow + * that uses rcu_read_lock. + */ +static void macvtap_del_queue(struct macvtap_queue **qp) +{ + struct macvtap_queue *q; + + spin_lock(&macvtap_lock); + q = rcu_dereference(*qp); + if (!q) { + spin_unlock(&macvtap_lock); + return; + } + + rcu_assign_pointer(q->vlan->tap, NULL); + rcu_assign_pointer(q->file->private_data, NULL); + spin_unlock(&macvtap_lock); + + synchronize_rcu(); + sock_put(&q->sk); +} + +/* + * Since we only support one queue, just dereference the pointer. + */ +static struct macvtap_queue *macvtap_get_queue(struct net_device *dev, + struct sk_buff *skb) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + + return rcu_dereference(vlan->tap); +} + +static void macvtap_del_queues(struct net_device *dev) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + macvtap_del_queue(&vlan->tap); +} + +static inline struct macvtap_queue *macvtap_file_get_queue(struct file *file) +{ + rcu_read_lock_bh(); + return rcu_dereference(file->private_data); +} + +static inline void macvtap_file_put_queue(void) +{ + rcu_read_unlock_bh(); +} + +/* + * Forward happens for data that gets sent from one macvlan + * endpoint to another one in bridge mode. We just take + * the skb and put it into the receive queue. + */ +static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) +{ + struct macvtap_queue *q = macvtap_get_queue(dev, skb); + if (!q) + return -ENOLINK; + + skb_queue_tail(&q->sk.sk_receive_queue, skb); + wake_up(q->sk.sk_sleep); + return 0; +} + +/* + * Receive is for data from the external interface (lowerdev), + * in case of macvtap, we can treat that the same way as + * forward, which macvlan cannot. + */ +static int macvtap_receive(struct sk_buff *skb) +{ + skb_push(skb, ETH_HLEN); + return macvtap_forward(skb->dev, skb); +} + +static int macvtap_newlink(struct net *src_net, + struct net_device *dev, + struct nlattr *tb[], + struct nlattr *data[]) +{ + struct device *classdev; + dev_t devt; + int err; + + err = macvlan_common_newlink(src_net, dev, tb, data, + macvtap_receive, macvtap_forward); + if (err) + goto out; + + devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); + + classdev = device_create(macvtap_class, &dev->dev, devt, + dev, "tap%d", dev->ifindex); + if (IS_ERR(classdev)) { + err = PTR_ERR(classdev); + macvtap_del_queues(dev); + } + +out: + return err; +} + +static void macvtap_dellink(struct net_device *dev, + struct list_head *head) +{ + device_destroy(macvtap_class, + MKDEV(MAJOR(macvtap_major), dev->ifindex)); + + macvtap_del_queues(dev); + macvlan_dellink(dev, head); +} + +static struct rtnl_link_ops macvtap_link_ops __read_mostly = { + .kind = "macvtap", + .newlink = macvtap_newlink, + .dellink = macvtap_dellink, +}; + + +static void macvtap_sock_write_space(struct sock *sk) +{ + if (!sock_writeable(sk) || + !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) + return; + + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_sync(sk->sk_sleep); +} + +static int macvtap_open(struct inode *inode, struct file *file) +{ + struct net *net = current->nsproxy->net_ns; + struct net_device *dev = dev_get_by_index(net, iminor(inode)); + struct macvtap_queue *q; + int err; + + err = -ENODEV; + if (!dev) + goto out; + + /* check if this is a macvtap device */ + err = -EINVAL; + if (dev->rtnl_link_ops != &macvtap_link_ops) + goto out; + + err = -ENOMEM; + q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, + &macvtap_proto); + if (!q) + goto out; + + init_waitqueue_head(&q->sock.wait); + q->sock.type = SOCK_RAW; + q->sock.state = SS_CONNECTED; + sock_init_data(&q->sock, &q->sk); + q->sk.sk_allocation = GFP_ATOMIC; /* for now */ + q->sk.sk_write_space = macvtap_sock_write_space; + + err = macvtap_set_queue(dev, file, q); + if (err) + sock_put(&q->sk); + +out: + if (dev) + dev_put(dev); + + return err; +} + +static int macvtap_release(struct inode *inode, struct file *file) +{ + macvtap_del_queue((struct macvtap_queue **)&file->private_data); + return 0; +} + +static unsigned int macvtap_poll(struct file *file, poll_table * wait) +{ + struct macvtap_queue *q = macvtap_file_get_queue(file); + unsigned int mask = POLLERR; + + if (!q) + goto out; + + mask = 0; + poll_wait(file, &q->sock.wait, wait); + + if (!skb_queue_empty(&q->sk.sk_receive_queue)) + mask |= POLLIN | POLLRDNORM; + + if (sock_writeable(&q->sk) || + (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &q->sock.flags) && + sock_writeable(&q->sk))) + mask |= POLLOUT | POLLWRNORM; + +out: + macvtap_file_put_queue(); + return mask; +} + +/* Get packet from user space buffer */ +static ssize_t macvtap_get_user(struct macvtap_queue *q, + const struct iovec *iv, size_t count, + int noblock) +{ + struct sk_buff *skb; + size_t len = count; + int err; + + if (unlikely(len < ETH_HLEN)) + return -EINVAL; + + skb = sock_alloc_send_skb(&q->sk, NET_IP_ALIGN + len, noblock, &err); + + if (!skb) { + macvlan_count_rx(q->vlan, 0, false, false); + return err; + } + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, count); + + if (skb_copy_datagram_from_iovec(skb, 0, iv, 0, len)) { + macvlan_count_rx(q->vlan, 0, false, false); + kfree_skb(skb); + return -EFAULT; + } + + skb_set_network_header(skb, ETH_HLEN); + + macvlan_start_xmit(skb, q->vlan->dev); + + return count; +} + +static ssize_t macvtap_aio_write(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) +{ + struct file *file = iocb->ki_filp; + ssize_t result = -ENOLINK; + struct macvtap_queue *q = macvtap_file_get_queue(file); + + if (!q) + goto out; + + result = macvtap_get_user(q, iv, iov_length(iv, count), + file->f_flags & O_NONBLOCK); +out: + macvtap_file_put_queue(); + return result; +} + +/* Put packet to the user space buffer */ +static ssize_t macvtap_put_user(struct macvtap_queue *q, + const struct sk_buff *skb, + const struct iovec *iv, int len) +{ + struct macvlan_dev *vlan = q->vlan; + int ret; + + len = min_t(int, skb->len, len); + + ret = skb_copy_datagram_const_iovec(skb, 0, iv, 0, len); + + macvlan_count_rx(vlan, len, ret == 0, 0); + + return ret ? ret : len; +} + +static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct macvtap_queue *q = macvtap_file_get_queue(file); + + DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb; + ssize_t len, ret = 0; + + if (!q) { + ret = -ENOLINK; + goto out; + } + + len = iov_length(iv, count); + if (len < 0) { + ret = -EINVAL; + goto out; + } + + add_wait_queue(q->sk.sk_sleep, &wait); + while (len) { + current->state = TASK_INTERRUPTIBLE; + + /* Read frames from the queue */ + skb = skb_dequeue(&q->sk.sk_receive_queue); + if (!skb) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + /* Nothing to read, let's sleep */ + schedule(); + continue; + } + ret = macvtap_put_user(q, skb, iv, len); + kfree_skb(skb); + break; + } + + current->state = TASK_RUNNING; + remove_wait_queue(q->sk.sk_sleep, &wait); + +out: + macvtap_file_put_queue(); + return ret; +} + +/* + * provide compatibility with generic tun/tap interface + */ +static long macvtap_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct macvtap_queue *q; + void __user *argp = (void __user *)arg; + struct ifreq __user *ifr = argp; + unsigned int __user *up = argp; + unsigned int u; + char devname[IFNAMSIZ]; + + switch (cmd) { + case TUNSETIFF: + /* ignore the name, just look at flags */ + if (get_user(u, &ifr->ifr_flags)) + return -EFAULT; + if (u != (IFF_TAP | IFF_NO_PI)) + return -EINVAL; + return 0; + + case TUNGETIFF: + q = macvtap_file_get_queue(file); + if (!q) + return -ENOLINK; + memcpy(devname, q->vlan->dev->name, sizeof(devname)); + macvtap_file_put_queue(); + + if (copy_to_user(&ifr->ifr_name, q->vlan->dev->name, IFNAMSIZ) || + put_user((TUN_TAP_DEV | TUN_NO_PI), &ifr->ifr_flags)) + return -EFAULT; + return 0; + + case TUNGETFEATURES: + if (put_user((IFF_TAP | IFF_NO_PI), up)) + return -EFAULT; + return 0; + + case TUNSETSNDBUF: + if (get_user(u, up)) + return -EFAULT; + + q = macvtap_file_get_queue(file); + q->sk.sk_sndbuf = u; + macvtap_file_put_queue(); + return 0; + + case TUNSETOFFLOAD: + /* let the user check for future flags */ + if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | + TUN_F_TSO_ECN | TUN_F_UFO)) + return -EINVAL; + + /* TODO: add support for these, so far we don't + support any offload */ + if (arg & (TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | + TUN_F_TSO_ECN | TUN_F_UFO)) + return -EINVAL; + + return 0; + + default: + return -EINVAL; + } +} + +#ifdef CONFIG_COMPAT +static long macvtap_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return macvtap_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static const struct file_operations macvtap_fops = { + .owner = THIS_MODULE, + .open = macvtap_open, + .release = macvtap_release, + .aio_read = macvtap_aio_read, + .aio_write = macvtap_aio_write, + .poll = macvtap_poll, + .llseek = no_llseek, + .unlocked_ioctl = macvtap_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = macvtap_compat_ioctl, +#endif +}; + +static int macvtap_init(void) +{ + int err; + + err = alloc_chrdev_region(&macvtap_major, 0, + MACVTAP_NUM_DEVS, "macvtap"); + if (err) + goto out1; + + cdev_init(&macvtap_cdev, &macvtap_fops); + err = cdev_add(&macvtap_cdev, macvtap_major, MACVTAP_NUM_DEVS); + if (err) + goto out2; + + macvtap_class = class_create(THIS_MODULE, "macvtap"); + if (IS_ERR(macvtap_class)) { + err = PTR_ERR(macvtap_class); + goto out3; + } + + err = macvlan_link_register(&macvtap_link_ops); + if (err) + goto out4; + + return 0; + +out4: + class_unregister(macvtap_class); +out3: + cdev_del(&macvtap_cdev); +out2: + unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); +out1: + return err; +} +module_init(macvtap_init); + +static void macvtap_exit(void) +{ + rtnl_link_unregister(&macvtap_link_ops); + class_unregister(macvtap_class); + cdev_del(&macvtap_cdev); + unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); +} +module_exit(macvtap_exit); + +MODULE_ALIAS_RTNL_LINK("macvtap"); +MODULE_AUTHOR("Arnd Bergmann "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 9a11544bb0b1..51f1512045e9 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -34,6 +34,7 @@ struct macvlan_dev { enum macvlan_mode mode; int (*receive)(struct sk_buff *skb); int (*forward)(struct net_device *dev, struct sk_buff *skb); + struct macvtap_queue *tap; }; static inline void macvlan_count_rx(const struct macvlan_dev *vlan, -- GitLab From 59b26c72914920fd12695033c5a099fb0bfae935 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 1 Feb 2010 07:58:59 +0000 Subject: [PATCH 1565/3892] trivial: remove duplicated "from" in CAN USB EMS Kconfig help Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller --- drivers/net/can/usb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index bbc78e0b8a15..97ff6febad63 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -5,6 +5,6 @@ config CAN_EMS_USB tristate "EMS CPC-USB/ARM7 CAN/USB interface" ---help--- This driver is for the one channel CPC-USB/ARM7 CAN/USB interface - from from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). + from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). endmenu -- GitLab From 235ecb1db09f481840569fd85eda62e70d03580c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 1 Feb 2010 21:22:11 +0000 Subject: [PATCH 1566/3892] drivers/net/davinci_emac.c: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/davinci_emac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 33c4fe26178c..faffad409985 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2672,8 +2672,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; size = res->end - res->start + 1; if (!request_mem_region(res->start, size, ndev->name)) { - dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() \ - for regs\n"); + dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() for regs\n"); rc = -ENXIO; goto probe_quit; } -- GitLab From 35cfabdc5e9b99e732899db8f36c63a215e105bc Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Mon, 1 Feb 2010 14:06:52 +0000 Subject: [PATCH 1567/3892] bonding: Remove net_device_stats from bonding struct There is no need to maintain stats in the bonding structure. Use the instance of net_device_stats in netdevice. Signed-off-by: Ajit Khaparde Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/bonding/bonding.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6221936e957a..1787e3c86573 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3742,7 +3742,7 @@ static int bond_close(struct net_device *bond_dev) static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - struct net_device_stats *stats = &bond->stats; + struct net_device_stats *stats = &bond_dev->stats; struct net_device_stats local_stats; struct slave *slave; int i; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 558ec1352527..257a7a4dfce9 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -197,7 +197,6 @@ struct bonding { s8 send_grat_arp; s8 send_unsol_na; s8 setup_by_slave; - struct net_device_stats stats; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; char proc_file_name[IFNAMSIZ]; -- GitLab From bf66f3736a945dd4e92d86427276c6eeab0a6c1d Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Wed, 3 Feb 2010 07:39:54 +0000 Subject: [PATCH 1568/3892] can: mcp251x: Move to threaded interrupts instead of workqueues. This patch addresses concerns about efficiency of handling incoming packets. Handling of interrupts is done in a threaded interrupt handler which has a smaller latency than workqueues. This change needed a rework of the locking scheme that was much simplified. Some other (more or less longstanding) bugs are fixed: utilization of just half of the RX buffers, useless wait for interrupt on open, more reliable reset sequence. The MERR interrupt is not used anymore: it overloads the CPU in error-passive state without any additional information. One shot mode is disabled because it's not clear if it can be handled efficiently on this CAN controller. Signed-off-by: Christian Pellegrin Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/mcp251x.c | 421 ++++++++++++++++++-------------------- 1 file changed, 203 insertions(+), 218 deletions(-) diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index bbe186b5a0ed..f8cc168ec76c 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -180,6 +180,14 @@ #define RXBEID0_OFF 4 #define RXBDLC_OFF 5 #define RXBDAT_OFF 6 +#define RXFSIDH(n) ((n) * 4) +#define RXFSIDL(n) ((n) * 4 + 1) +#define RXFEID8(n) ((n) * 4 + 2) +#define RXFEID0(n) ((n) * 4 + 3) +#define RXMSIDH(n) ((n) * 4 + 0x20) +#define RXMSIDL(n) ((n) * 4 + 0x21) +#define RXMEID8(n) ((n) * 4 + 0x22) +#define RXMEID0(n) ((n) * 4 + 0x23) #define GET_BYTE(val, byte) \ (((val) >> ((byte) * 8)) & 0xff) @@ -219,7 +227,8 @@ struct mcp251x_priv { struct net_device *net; struct spi_device *spi; - struct mutex spi_lock; /* SPI buffer lock */ + struct mutex mcp_lock; /* SPI device lock */ + u8 *spi_tx_buf; u8 *spi_rx_buf; dma_addr_t spi_tx_dma; @@ -227,11 +236,11 @@ struct mcp251x_priv { struct sk_buff *tx_skb; int tx_len; + struct workqueue_struct *wq; struct work_struct tx_work; - struct work_struct irq_work; - struct completion awake; - int wake; + struct work_struct restart_work; + int force_quit; int after_suspend; #define AFTER_SUSPEND_UP 1 @@ -245,7 +254,8 @@ static void mcp251x_clean(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); - net->stats.tx_errors++; + if (priv->tx_skb || priv->tx_len) + net->stats.tx_errors++; if (priv->tx_skb) dev_kfree_skb(priv->tx_skb); if (priv->tx_len) @@ -300,16 +310,12 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg) struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); u8 val = 0; - mutex_lock(&priv->spi_lock); - priv->spi_tx_buf[0] = INSTRUCTION_READ; priv->spi_tx_buf[1] = reg; mcp251x_spi_trans(spi, 3); val = priv->spi_rx_buf[2]; - mutex_unlock(&priv->spi_lock); - return val; } @@ -317,15 +323,11 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val) { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - mutex_lock(&priv->spi_lock); - priv->spi_tx_buf[0] = INSTRUCTION_WRITE; priv->spi_tx_buf[1] = reg; priv->spi_tx_buf[2] = val; mcp251x_spi_trans(spi, 3); - - mutex_unlock(&priv->spi_lock); } static void mcp251x_write_bits(struct spi_device *spi, u8 reg, @@ -333,16 +335,12 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg, { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - mutex_lock(&priv->spi_lock); - priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY; priv->spi_tx_buf[1] = reg; priv->spi_tx_buf[2] = mask; priv->spi_tx_buf[3] = val; mcp251x_spi_trans(spi, 4); - - mutex_unlock(&priv->spi_lock); } static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, @@ -358,10 +356,8 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i, buf[i]); } else { - mutex_lock(&priv->spi_lock); memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len); mcp251x_spi_trans(spi, TXBDAT_OFF + len); - mutex_unlock(&priv->spi_lock); } } @@ -408,13 +404,9 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, for (; i < (RXBDAT_OFF + len); i++) buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i); } else { - mutex_lock(&priv->spi_lock); - priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx); mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN); memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN); - - mutex_unlock(&priv->spi_lock); } } @@ -467,21 +459,6 @@ static void mcp251x_hw_sleep(struct spi_device *spi) mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); } -static void mcp251x_hw_wakeup(struct spi_device *spi) -{ - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); - - priv->wake = 1; - - /* Can only wake up by generating a wake-up interrupt. */ - mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE); - mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF); - - /* Wait until the device is awake */ - if (!wait_for_completion_timeout(&priv->awake, HZ)) - dev_err(&spi->dev, "MCP251x didn't wake-up\n"); -} - static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -490,7 +467,6 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, if (priv->tx_skb || priv->tx_len) { dev_warn(&spi->dev, "hard_xmit called while tx busy\n"); - netif_stop_queue(net); return NETDEV_TX_BUSY; } @@ -511,12 +487,13 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode) switch (mode) { case CAN_MODE_START: + mcp251x_clean(net); /* We have to delay work since SPI I/O may sleep */ priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->restart_tx = 1; if (priv->can.restart_ms == 0) priv->after_suspend = AFTER_SUSPEND_RESTART; - queue_work(priv->wq, &priv->irq_work); + queue_work(priv->wq, &priv->restart_work); break; default: return -EOPNOTSUPP; @@ -525,7 +502,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode) return 0; } -static void mcp251x_set_normal_mode(struct spi_device *spi) +static int mcp251x_set_normal_mode(struct spi_device *spi) { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); unsigned long timeout; @@ -533,8 +510,7 @@ static void mcp251x_set_normal_mode(struct spi_device *spi) /* Enable interrupts */ mcp251x_write_reg(spi, CANINTE, CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE | - CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE | - CANINTF_MERRF); + CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE); if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { /* Put device into loopback mode */ @@ -544,9 +520,7 @@ static void mcp251x_set_normal_mode(struct spi_device *spi) mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY); } else { /* Put device into normal mode */ - mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL | - (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT ? - CANCTRL_OSM : 0)); + mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); /* Wait for the device to enter normal mode */ timeout = jiffies + HZ; @@ -555,11 +529,12 @@ static void mcp251x_set_normal_mode(struct spi_device *spi) if (time_after(jiffies, timeout)) { dev_err(&spi->dev, "MCP251x didn't" " enter in normal mode\n"); - return; + return -EBUSY; } } } priv->can.state = CAN_STATE_ERROR_ACTIVE; + return 0; } static int mcp251x_do_set_bittiming(struct net_device *net) @@ -590,33 +565,39 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, { mcp251x_do_set_bittiming(net); - /* Enable RX0->RX1 buffer roll over and disable filters */ - mcp251x_write_bits(spi, RXBCTRL(0), - RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1, - RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1); - mcp251x_write_bits(spi, RXBCTRL(1), - RXBCTRL_RXM0 | RXBCTRL_RXM1, - RXBCTRL_RXM0 | RXBCTRL_RXM1); + mcp251x_write_reg(spi, RXBCTRL(0), + RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1); + mcp251x_write_reg(spi, RXBCTRL(1), + RXBCTRL_RXM0 | RXBCTRL_RXM1); return 0; } -static void mcp251x_hw_reset(struct spi_device *spi) +static int mcp251x_hw_reset(struct spi_device *spi) { struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); int ret; - - mutex_lock(&priv->spi_lock); + unsigned long timeout; priv->spi_tx_buf[0] = INSTRUCTION_RESET; - ret = spi_write(spi, priv->spi_tx_buf, 1); - - mutex_unlock(&priv->spi_lock); - - if (ret) + if (ret) { dev_err(&spi->dev, "reset failed: ret = %d\n", ret); + return -EIO; + } + /* Wait for reset to finish */ + timeout = jiffies + HZ; mdelay(10); + while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) + != CANCTRL_REQOP_CONF) { + schedule(); + if (time_after(jiffies, timeout)) { + dev_err(&spi->dev, "MCP251x didn't" + " enter in conf mode after reset\n"); + return -EBUSY; + } + } + return 0; } static int mcp251x_hw_probe(struct spi_device *spi) @@ -640,63 +621,17 @@ static int mcp251x_hw_probe(struct spi_device *spi) return (st1 == 0x80 && st2 == 0x07) ? 1 : 0; } -static irqreturn_t mcp251x_can_isr(int irq, void *dev_id) -{ - struct net_device *net = (struct net_device *)dev_id; - struct mcp251x_priv *priv = netdev_priv(net); - - /* Schedule bottom half */ - if (!work_pending(&priv->irq_work)) - queue_work(priv->wq, &priv->irq_work); - - return IRQ_HANDLED; -} - -static int mcp251x_open(struct net_device *net) +static void mcp251x_open_clean(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); struct spi_device *spi = priv->spi; struct mcp251x_platform_data *pdata = spi->dev.platform_data; - int ret; - - ret = open_candev(net); - if (ret) { - dev_err(&spi->dev, "unable to set initial baudrate!\n"); - return ret; - } + free_irq(spi->irq, priv); + mcp251x_hw_sleep(spi); if (pdata->transceiver_enable) - pdata->transceiver_enable(1); - - priv->force_quit = 0; - priv->tx_skb = NULL; - priv->tx_len = 0; - - ret = request_irq(spi->irq, mcp251x_can_isr, - IRQF_TRIGGER_FALLING, DEVICE_NAME, net); - if (ret) { - dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); - close_candev(net); - return ret; - } - - mcp251x_hw_wakeup(spi); - mcp251x_hw_reset(spi); - ret = mcp251x_setup(net, priv, spi); - if (ret) { - free_irq(spi->irq, net); - mcp251x_hw_sleep(spi); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); - close_candev(net); - return ret; - } - mcp251x_set_normal_mode(spi); - netif_wake_queue(net); - - return 0; + pdata->transceiver_enable(0); + close_candev(net); } static int mcp251x_stop(struct net_device *net) @@ -707,17 +642,19 @@ static int mcp251x_stop(struct net_device *net) close_candev(net); + priv->force_quit = 1; + free_irq(spi->irq, priv); + destroy_workqueue(priv->wq); + priv->wq = NULL; + + mutex_lock(&priv->mcp_lock); + /* Disable and clear pending interrupts */ mcp251x_write_reg(spi, CANINTE, 0x00); mcp251x_write_reg(spi, CANINTF, 0x00); - priv->force_quit = 1; - free_irq(spi->irq, net); - flush_workqueue(priv->wq); - mcp251x_write_reg(spi, TXBCTRL(0), 0); - if (priv->tx_skb || priv->tx_len) - mcp251x_clean(net); + mcp251x_clean(net); mcp251x_hw_sleep(spi); @@ -726,9 +663,27 @@ static int mcp251x_stop(struct net_device *net) priv->can.state = CAN_STATE_STOPPED; + mutex_unlock(&priv->mcp_lock); + return 0; } +static void mcp251x_error_skb(struct net_device *net, int can_id, int data1) +{ + struct sk_buff *skb; + struct can_frame *frame; + + skb = alloc_can_err_skb(net, &frame); + if (skb) { + frame->can_id = can_id; + frame->data[1] = data1; + netif_rx(skb); + } else { + dev_err(&net->dev, + "cannot allocate error skb\n"); + } +} + static void mcp251x_tx_work_handler(struct work_struct *ws) { struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv, @@ -737,33 +692,32 @@ static void mcp251x_tx_work_handler(struct work_struct *ws) struct net_device *net = priv->net; struct can_frame *frame; + mutex_lock(&priv->mcp_lock); if (priv->tx_skb) { - frame = (struct can_frame *)priv->tx_skb->data; - if (priv->can.state == CAN_STATE_BUS_OFF) { mcp251x_clean(net); - netif_wake_queue(net); - return; + } else { + frame = (struct can_frame *)priv->tx_skb->data; + + if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN) + frame->can_dlc = CAN_FRAME_MAX_DATA_LEN; + mcp251x_hw_tx(spi, frame, 0); + priv->tx_len = 1 + frame->can_dlc; + can_put_echo_skb(priv->tx_skb, net, 0); + priv->tx_skb = NULL; } - if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN) - frame->can_dlc = CAN_FRAME_MAX_DATA_LEN; - mcp251x_hw_tx(spi, frame, 0); - priv->tx_len = 1 + frame->can_dlc; - can_put_echo_skb(priv->tx_skb, net, 0); - priv->tx_skb = NULL; } + mutex_unlock(&priv->mcp_lock); } -static void mcp251x_irq_work_handler(struct work_struct *ws) +static void mcp251x_restart_work_handler(struct work_struct *ws) { struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv, - irq_work); + restart_work); struct spi_device *spi = priv->spi; struct net_device *net = priv->net; - u8 txbnctrl; - u8 intf; - enum can_state new_state; + mutex_lock(&priv->mcp_lock); if (priv->after_suspend) { mdelay(10); mcp251x_hw_reset(spi); @@ -772,45 +726,54 @@ static void mcp251x_irq_work_handler(struct work_struct *ws) mcp251x_set_normal_mode(spi); } else if (priv->after_suspend & AFTER_SUSPEND_UP) { netif_device_attach(net); - /* Clean since we lost tx buffer */ - if (priv->tx_skb || priv->tx_len) { - mcp251x_clean(net); - netif_wake_queue(net); - } + mcp251x_clean(net); mcp251x_set_normal_mode(spi); + netif_wake_queue(net); } else { mcp251x_hw_sleep(spi); } priv->after_suspend = 0; + priv->force_quit = 0; } - if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF) - return; + if (priv->restart_tx) { + priv->restart_tx = 0; + mcp251x_write_reg(spi, TXBCTRL(0), 0); + mcp251x_clean(net); + netif_wake_queue(net); + mcp251x_error_skb(net, CAN_ERR_RESTARTED, 0); + } + mutex_unlock(&priv->mcp_lock); +} - while (!priv->force_quit && !freezing(current)) { - u8 eflag = mcp251x_read_reg(spi, EFLG); - int can_id = 0, data1 = 0; +static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) +{ + struct mcp251x_priv *priv = dev_id; + struct spi_device *spi = priv->spi; + struct net_device *net = priv->net; - mcp251x_write_reg(spi, EFLG, 0x00); + mutex_lock(&priv->mcp_lock); + while (!priv->force_quit) { + enum can_state new_state; + u8 intf = mcp251x_read_reg(spi, CANINTF); + u8 eflag; + int can_id = 0, data1 = 0; - if (priv->restart_tx) { - priv->restart_tx = 0; - mcp251x_write_reg(spi, TXBCTRL(0), 0); - if (priv->tx_skb || priv->tx_len) - mcp251x_clean(net); - netif_wake_queue(net); - can_id |= CAN_ERR_RESTARTED; + if (intf & CANINTF_RX0IF) { + mcp251x_hw_rx(spi, 0); + /* Free one buffer ASAP */ + mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF, + 0x00); } - if (priv->wake) { - /* Wait whilst the device wakes up */ - mdelay(10); - priv->wake = 0; - } + if (intf & CANINTF_RX1IF) + mcp251x_hw_rx(spi, 1); - intf = mcp251x_read_reg(spi, CANINTF); mcp251x_write_bits(spi, CANINTF, intf, 0x00); + eflag = mcp251x_read_reg(spi, EFLG); + mcp251x_write_reg(spi, EFLG, 0x00); + /* Update can state */ if (eflag & EFLG_TXBO) { new_state = CAN_STATE_BUS_OFF; @@ -851,59 +814,31 @@ static void mcp251x_irq_work_handler(struct work_struct *ws) } priv->can.state = new_state; - if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) { - struct sk_buff *skb; - struct can_frame *frame; - - /* Create error frame */ - skb = alloc_can_err_skb(net, &frame); - if (skb) { - /* Set error frame flags based on bus state */ - frame->can_id = can_id; - frame->data[1] = data1; - - /* Update net stats for overflows */ - if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) { - if (eflag & EFLG_RX0OVR) - net->stats.rx_over_errors++; - if (eflag & EFLG_RX1OVR) - net->stats.rx_over_errors++; - frame->can_id |= CAN_ERR_CRTL; - frame->data[1] |= - CAN_ERR_CRTL_RX_OVERFLOW; - } - - netif_rx(skb); - } else { - dev_info(&spi->dev, - "cannot allocate error skb\n"); + if (intf & CANINTF_ERRIF) { + /* Handle overflow counters */ + if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) { + if (eflag & EFLG_RX0OVR) + net->stats.rx_over_errors++; + if (eflag & EFLG_RX1OVR) + net->stats.rx_over_errors++; + can_id |= CAN_ERR_CRTL; + data1 |= CAN_ERR_CRTL_RX_OVERFLOW; } + mcp251x_error_skb(net, can_id, data1); } if (priv->can.state == CAN_STATE_BUS_OFF) { if (priv->can.restart_ms == 0) { + priv->force_quit = 1; can_bus_off(net); mcp251x_hw_sleep(spi); - return; + break; } } if (intf == 0) break; - if (intf & CANINTF_WAKIF) - complete(&priv->awake); - - if (intf & CANINTF_MERRF) { - /* If there are pending Tx buffers, restart queue */ - txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0)); - if (!(txbnctrl & TXBCTRL_TXREQ)) { - if (priv->tx_skb || priv->tx_len) - mcp251x_clean(net); - netif_wake_queue(net); - } - } - if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) { net->stats.tx_packets++; net->stats.tx_bytes += priv->tx_len - 1; @@ -914,12 +849,66 @@ static void mcp251x_irq_work_handler(struct work_struct *ws) netif_wake_queue(net); } - if (intf & CANINTF_RX0IF) - mcp251x_hw_rx(spi, 0); + } + mutex_unlock(&priv->mcp_lock); + return IRQ_HANDLED; +} - if (intf & CANINTF_RX1IF) - mcp251x_hw_rx(spi, 1); +static int mcp251x_open(struct net_device *net) +{ + struct mcp251x_priv *priv = netdev_priv(net); + struct spi_device *spi = priv->spi; + struct mcp251x_platform_data *pdata = spi->dev.platform_data; + int ret; + + ret = open_candev(net); + if (ret) { + dev_err(&spi->dev, "unable to set initial baudrate!\n"); + return ret; + } + + mutex_lock(&priv->mcp_lock); + if (pdata->transceiver_enable) + pdata->transceiver_enable(1); + + priv->force_quit = 0; + priv->tx_skb = NULL; + priv->tx_len = 0; + + ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist, + IRQF_TRIGGER_FALLING, DEVICE_NAME, priv); + if (ret) { + dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); + if (pdata->transceiver_enable) + pdata->transceiver_enable(0); + close_candev(net); + goto open_unlock; + } + + priv->wq = create_freezeable_workqueue("mcp251x_wq"); + INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); + INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); + + ret = mcp251x_hw_reset(spi); + if (ret) { + mcp251x_open_clean(net); + goto open_unlock; + } + ret = mcp251x_setup(net, priv, spi); + if (ret) { + mcp251x_open_clean(net); + goto open_unlock; } + ret = mcp251x_set_normal_mode(spi); + if (ret) { + mcp251x_open_clean(net); + goto open_unlock; + } + netif_wake_queue(net); + +open_unlock: + mutex_unlock(&priv->mcp_lock); + return ret; } static const struct net_device_ops mcp251x_netdev_ops = { @@ -955,13 +944,11 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) priv->can.clock.freq = pdata->oscillator_frequency / 2; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; - if (pdata->model == CAN_MCP251X_MCP2515) - priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; priv->net = net; dev_set_drvdata(&spi->dev, priv); priv->spi = spi; - mutex_init(&priv->spi_lock); + mutex_init(&priv->mcp_lock); /* If requested, allocate DMA buffers */ if (mcp251x_enable_dma) { @@ -1010,18 +997,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) SET_NETDEV_DEV(net, &spi->dev); - priv->wq = create_freezeable_workqueue("mcp251x_wq"); - - INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); - INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler); - - init_completion(&priv->awake); - /* Configure the SPI bus */ spi->mode = SPI_MODE_0; spi->bits_per_word = 8; spi_setup(spi); + /* Here is OK to not lock the MCP, no one knows about it yet */ if (!mcp251x_hw_probe(spi)) { dev_info(&spi->dev, "Probe failed\n"); goto error_probe; @@ -1064,10 +1045,6 @@ static int __devexit mcp251x_can_remove(struct spi_device *spi) unregister_candev(net); free_candev(net); - priv->force_quit = 1; - flush_workqueue(priv->wq); - destroy_workqueue(priv->wq); - if (mcp251x_enable_dma) { dma_free_coherent(&spi->dev, PAGE_SIZE, priv->spi_tx_buf, priv->spi_tx_dma); @@ -1089,6 +1066,12 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state) struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); struct net_device *net = priv->net; + priv->force_quit = 1; + disable_irq(spi->irq); + /* + * Note: at this point neither IST nor workqueues are running. + * open/stop cannot be called anyway so locking is not needed + */ if (netif_running(net)) { netif_device_detach(net); @@ -1115,16 +1098,18 @@ static int mcp251x_can_resume(struct spi_device *spi) if (priv->after_suspend & AFTER_SUSPEND_POWER) { pdata->power_enable(1); - queue_work(priv->wq, &priv->irq_work); + queue_work(priv->wq, &priv->restart_work); } else { if (priv->after_suspend & AFTER_SUSPEND_UP) { if (pdata->transceiver_enable) pdata->transceiver_enable(1); - queue_work(priv->wq, &priv->irq_work); + queue_work(priv->wq, &priv->restart_work); } else { priv->after_suspend = 0; } } + priv->force_quit = 0; + enable_irq(spi->irq); return 0; } #else -- GitLab From 1621e0940294c20e302faf401f41204de7252e22 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 1 Feb 2010 09:44:19 +0000 Subject: [PATCH 1569/3892] net: CONFIG_COMPAT redux Ifdef out struct proto_ops::compat_ioctl struct proto_ops::compat_setsockopt struct proto_ops::compat_getsockopt to make structures smaller on COMPAT=n kernels. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/net.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/net.h b/include/linux/net.h index 5e8083cacc8b..4157b5d42bd6 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -174,18 +174,22 @@ struct proto_ops { struct poll_table_struct *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT int (*compat_ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg); +#endif int (*listen) (struct socket *sock, int len); int (*shutdown) (struct socket *sock, int flags); int (*setsockopt)(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen); int (*getsockopt)(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen); +#ifdef CONFIG_COMPAT int (*compat_setsockopt)(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen); int (*compat_getsockopt)(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen); +#endif int (*sendmsg) (struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len); int (*recvmsg) (struct kiocb *iocb, struct socket *sock, -- GitLab From 3fbd9187d004149fb8a98c9cb51ef9f4a4f66aca Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 1 Feb 2010 13:45:41 +0000 Subject: [PATCH 1570/3892] sky2: hand receive DMA mapping failures If receive buffer mapping failed, then it was possible to get stuck with unmapped receive buffer in DMA ring. This would be an extremely rare condition because the driver had just released the map for the last receive so it should be able to get another map again (in soft-irq). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 61 +++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a6ddfc1a9cb2..72c92495a9b3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1103,18 +1103,39 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re, int i; re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(pdev, re->data_addr))) - return -EIO; + if (pci_dma_mapping_error(pdev, re->data_addr)) + goto mapping_error; pci_unmap_len_set(re, data_size, size); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - re->frag_addr[i] = pci_map_page(pdev, - skb_shinfo(skb)->frags[i].page, - skb_shinfo(skb)->frags[i].page_offset, - skb_shinfo(skb)->frags[i].size, + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + re->frag_addr[i] = pci_map_page(pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(pdev, re->frag_addr[i])) + goto map_page_error; + } return 0; + +map_page_error: + while (--i >= 0) { + pci_unmap_page(pdev, re->frag_addr[i], + skb_shinfo(skb)->frags[i].size, + PCI_DMA_FROMDEVICE); + } + + pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size), + PCI_DMA_FROMDEVICE); + +mapping_error: + if (net_ratelimit()) + dev_warn(&pdev->dev, "%s: rx mapping error\n", + skb->dev->name); + return -EIO; } static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re) @@ -2306,30 +2327,32 @@ static struct sk_buff *receive_new(struct sky2_port *sky2, struct rx_ring_info *re, unsigned int length) { - struct sk_buff *skb, *nskb; + struct sk_buff *skb; + struct rx_ring_info nre; unsigned hdr_space = sky2->rx_data_size; - /* Don't be tricky about reusing pages (yet) */ - nskb = sky2_rx_alloc(sky2); - if (unlikely(!nskb)) - return NULL; + nre.skb = sky2_rx_alloc(sky2); + if (unlikely(!nre.skb)) + goto nobuf; + + if (sky2_rx_map_skb(sky2->hw->pdev, &nre, hdr_space)) + goto nomap; skb = re->skb; sky2_rx_unmap_skb(sky2->hw->pdev, re); - prefetch(skb->data); - re->skb = nskb; - if (sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space)) { - dev_kfree_skb(nskb); - re->skb = skb; - return NULL; - } + *re = nre; if (skb_shinfo(skb)->nr_frags) skb_put_frags(skb, hdr_space, length); else skb_put(skb, length); return skb; + +nomap: + dev_kfree_skb(nre.skb); +nobuf: + return NULL; } /* -- GitLab From 90c30335a70e96b8b8493b7deb15e6b30e6d9fce Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 3 Feb 2010 08:31:12 +0000 Subject: [PATCH 1571/3892] sky2: Flow control frames recorded as dropped packets Thanks for your patch. A more general solution would be to move the rx_dropped up into sky2_receive. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 72c92495a9b3..744362272e2d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2404,6 +2404,9 @@ okay: skb = receive_copy(sky2, re, length); else skb = receive_new(sky2, re, length); + + dev->stats.rx_dropped += (skb == NULL); + resubmit: sky2_rx_submit(sky2, re); @@ -2515,11 +2518,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) case OP_RXSTAT: total_packets[port]++; total_bytes[port] += length; + skb = sky2_receive(dev, length, status); - if (unlikely(!skb)) { - dev->stats.rx_dropped++; + if (!skb) break; - } /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { -- GitLab From a9694faa287888b4fb10849649b6c94d0a1c9940 Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Thu, 4 Feb 2010 08:58:23 +0100 Subject: [PATCH 1572/3892] ALSA: hda - Adding support for another IDT 92HD83XXX codec Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9694675f0b9e..693dd14d9ec1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5341,6 +5341,7 @@ again: spec->num_pwrs = 0; break; case 0x111d7604: + case 0x111d76d4: case 0x111d7605: case 0x111d76d5: if (spec->board_config == STAC_92HD83XXX_PWR_REF) @@ -6263,6 +6264,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, -- GitLab From fea4d14b69567e134e1838155a5dc857ebca70cb Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 3 Feb 2010 23:46:48 -0800 Subject: [PATCH 1573/3892] Input: usbtouchscreen - convert from usb_device to usb_interface Convert usbtouchscreen from storing usb_device to usb_interface. This is needed for multi-interface touchscreen devices such as iNexio. Signed-off-by: Ondrej Zary Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index b1b99e931f80..69be77118884 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -104,7 +104,7 @@ struct usbtouch_usb { unsigned char *buffer; int buf_len; struct urb *irq; - struct usb_device *udev; + struct usb_interface *interface; struct input_dev *input; struct usbtouch_device_info *type; char name[128]; @@ -234,8 +234,9 @@ static const struct usb_device_id usbtouch_devices[] = { static int e2i_init(struct usbtouch_usb *usbtouch) { int ret; + struct usb_device *udev = interface_to_usbdev(usbtouch->interface); - ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01, 0x02, 0x0000, 0x0081, NULL, 0, USB_CTRL_SET_TIMEOUT); @@ -344,8 +345,9 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) static int mtouch_init(struct usbtouch_usb *usbtouch) { int ret, i; + struct usb_device *udev = interface_to_usbdev(usbtouch->interface); - ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_RESET, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); @@ -356,7 +358,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) msleep(150); for (i = 0; i < 3; i++) { - ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_ASYNC_REPORT, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); @@ -489,7 +491,7 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt) static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) { - struct usb_device *dev = usbtouch->udev; + struct usb_device *dev = interface_to_usbdev(usbtouch->interface); int ret = -ENOMEM; unsigned char *buf; @@ -1021,7 +1023,7 @@ static int usbtouch_open(struct input_dev *input) { struct usbtouch_usb *usbtouch = input_get_drvdata(input); - usbtouch->irq->dev = usbtouch->udev; + usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface); if (!usbtouch->type->irq_always) { if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) @@ -1094,7 +1096,7 @@ static int usbtouch_probe(struct usb_interface *intf, goto out_free_buffers; } - usbtouch->udev = udev; + usbtouch->interface = intf; usbtouch->input = input_dev; if (udev->manufacturer) @@ -1133,12 +1135,12 @@ static int usbtouch_probe(struct usb_interface *intf, input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, type->max_press, 0, 0); - usb_fill_int_urb(usbtouch->irq, usbtouch->udev, - usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), + usb_fill_int_urb(usbtouch->irq, udev, + usb_rcvintpipe(udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); - usbtouch->irq->dev = usbtouch->udev; + usbtouch->irq->dev = udev; usbtouch->irq->transfer_dma = usbtouch->data_dma; usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -- GitLab From f4a5e359c4bafc2269766ccd74256024160ed7ac Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 3 Feb 2010 23:54:59 -0800 Subject: [PATCH 1574/3892] Input: usbtouchscreen - find input endpoint automatically Find input enpoint automatically instead of assuming that the first one is OK. This is needed for devices with multiple endpoints such as iNexio where the first endpoint might be output. Signed-off-by: Ondrej Zary Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 69be77118884..a2a82351a42f 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -1050,13 +1050,23 @@ static void usbtouch_free_buffers(struct usb_device *udev, kfree(usbtouch->buffer); } +static struct usb_endpoint_descriptor * +usbtouch_get_input_endpoint(struct usb_host_interface *interface) +{ + int i; + + for (i = 0; i < interface->desc.bNumEndpoints; i++) + if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) + return &interface->endpoint[i].desc; + + return NULL; +} static int usbtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usbtouch_usb *usbtouch; struct input_dev *input_dev; - struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); struct usbtouch_device_info *type; @@ -1066,8 +1076,9 @@ static int usbtouch_probe(struct usb_interface *intf, if (id->driver_info == DEVTYPE_IGNORE) return -ENODEV; - interface = intf->cur_altsetting; - endpoint = &interface->endpoint[0].desc; + endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting); + if (!endpoint) + return -ENXIO; usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); input_dev = input_allocate_device(); -- GitLab From 5197424cdcccd2b0b1922babb93969b2515c43ce Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 4 Feb 2010 00:17:18 -0800 Subject: [PATCH 1575/3892] Input: usbtouchscreen - add NEXIO (or iNexio) support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for NEXIO (or iNexio) USB touchscreens to usbtouchscreen driver. Tested with NEX170MRT 17" LCD monitor with integrated touchscreen (with xserver-xorg-input-evtouch 0.8.8-1): T:  Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 54 Spd=12  MxCh= 0 D:  Ver= 1.10 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1 P:  Vendor=1870 ProdID=0001 Rev= 1.00 S:  Manufacturer=iNexio S:  Product=iNexio USB C:* #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=00 Driver=(none) E:  Ad=83(I) Atr=03(Int.) MxPS=   8 Ivl=255ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=(none) E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms No datasheet is available, this was written by capturing some data with SniffUSB in Windows: http://www.rainbow-software.org/linux_files/nexio/ Signed-off-by: Ondrej Zary Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 5 + drivers/input/touchscreen/usbtouchscreen.c | 261 ++++++++++++++++++++- 2 files changed, 264 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index dfafc76da4fb..a1e2d845f680 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -537,6 +537,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH bool "ET&T TC5UH touchscreen controler support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_NEXIO + default y + bool "NEXIO/iNexio device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index a2a82351a42f..07656efee654 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -15,6 +15,7 @@ * - GoTop Super_Q2/GogoPen/PenPower tablets * - JASTEC USB touch controller/DigiTech DTR-02U * - Zytronic capacitive touchscreen + * - NEXIO/iNexio * * Copyright (C) 2004-2007 by Daniel Ritz * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -95,6 +96,7 @@ struct usbtouch_device_info { int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); int (*init) (struct usbtouch_usb *usbtouch); + void (*exit) (struct usbtouch_usb *usbtouch); }; /* a usbtouch device */ @@ -109,6 +111,7 @@ struct usbtouch_usb { struct usbtouch_device_info *type; char name[128]; char phys[64]; + void *priv; int x, y; int touch, press; @@ -133,6 +136,7 @@ enum { DEVTYPE_E2I, DEVTYPE_ZYTRONIC, DEVTYPE_TC5UH, + DEVTYPE_NEXIO, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -222,6 +226,14 @@ static const struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO + /* data interface only */ + {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00), + .driver_info = DEVTYPE_NEXIO}, + {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00), + .driver_info = DEVTYPE_NEXIO}, +#endif + {} }; @@ -691,6 +703,229 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt) } #endif +/***************************************************************************** + * NEXIO Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO + +#define NEXIO_TIMEOUT 5000 +#define NEXIO_BUFSIZE 1024 +#define NEXIO_THRESHOLD 50 + +struct nexio_priv { + struct urb *ack; + unsigned char *ack_buf; +}; + +struct nexio_touch_packet { + u8 flags; /* 0xe1 = touch, 0xe1 = release */ + __be16 data_len; /* total bytes of touch data */ + __be16 x_len; /* bytes for X axis */ + __be16 y_len; /* bytes for Y axis */ + u8 data[]; +} __attribute__ ((packed)); + +static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 }; +static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f }; + +static void nexio_ack_complete(struct urb *urb) +{ +} + +static int nexio_init(struct usbtouch_usb *usbtouch) +{ + struct usb_device *dev = interface_to_usbdev(usbtouch->interface); + struct usb_host_interface *interface = usbtouch->interface->cur_altsetting; + struct nexio_priv *priv; + int ret = -ENOMEM; + int actual_len, i; + unsigned char *buf; + char *firmware_ver = NULL, *device_name = NULL; + int input_ep = 0, output_ep = 0; + + /* find first input and output endpoint */ + for (i = 0; i < interface->desc.bNumEndpoints; i++) { + if (!input_ep && + usb_endpoint_dir_in(&interface->endpoint[i].desc)) + input_ep = interface->endpoint[i].desc.bEndpointAddress; + if (!output_ep && + usb_endpoint_dir_out(&interface->endpoint[i].desc)) + output_ep = interface->endpoint[i].desc.bEndpointAddress; + } + if (!input_ep || !output_ep) + return -ENXIO; + + buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL); + if (!buf) + goto out_buf; + + /* two empty reads */ + for (i = 0; i < 2; i++) { + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep), + buf, NEXIO_BUFSIZE, &actual_len, + NEXIO_TIMEOUT); + if (ret < 0) + goto out_buf; + } + + /* send init command */ + memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt)); + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep), + buf, sizeof(nexio_init_pkt), &actual_len, + NEXIO_TIMEOUT); + if (ret < 0) + goto out_buf; + + /* read replies */ + for (i = 0; i < 3; i++) { + memset(buf, 0, NEXIO_BUFSIZE); + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep), + buf, NEXIO_BUFSIZE, &actual_len, + NEXIO_TIMEOUT); + if (ret < 0 || actual_len < 1 || buf[1] != actual_len) + continue; + switch (buf[0]) { + case 0x83: /* firmware version */ + if (!firmware_ver) + firmware_ver = kstrdup(&buf[2], GFP_KERNEL); + break; + case 0x84: /* device name */ + if (!device_name) + device_name = kstrdup(&buf[2], GFP_KERNEL); + break; + } + } + + printk(KERN_INFO "Nexio device: %s, firmware version: %s\n", + device_name, firmware_ver); + + kfree(firmware_ver); + kfree(device_name); + + /* prepare ACK URB */ + ret = -ENOMEM; + + usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL); + if (!usbtouch->priv) + goto out_buf; + + priv = usbtouch->priv; + + priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL); + if (!priv->ack_buf) + goto err_priv; + + memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt)); + + priv->ack = usb_alloc_urb(0, GFP_KERNEL); + if (!priv->ack) { + dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__); + goto err_ack_buf; + } + + usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep), + priv->ack_buf, sizeof(nexio_ack_pkt), + nexio_ack_complete, usbtouch); + ret = 0; + goto out_buf; + +err_ack_buf: + kfree(priv->ack_buf); +err_priv: + kfree(priv); +out_buf: + kfree(buf); + return ret; +} + +static void nexio_exit(struct usbtouch_usb *usbtouch) +{ + struct nexio_priv *priv = usbtouch->priv; + + usb_kill_urb(priv->ack); + usb_free_urb(priv->ack); + kfree(priv->ack_buf); + kfree(priv); +} + +static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) +{ + int x, y, begin_x, begin_y, end_x, end_y, w, h, ret; + struct nexio_touch_packet *packet = (void *) pkt; + struct nexio_priv *priv = usbtouch->priv; + + /* got touch data? */ + if ((pkt[0] & 0xe0) != 0xe0) + return 0; + + /* send ACK */ + ret = usb_submit_urb(priv->ack, GFP_ATOMIC); + + if (!usbtouch->type->max_xc) { + usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len); + input_set_abs_params(usbtouch->input, ABS_X, 0, + 2 * be16_to_cpu(packet->x_len), 0, 0); + usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len); + input_set_abs_params(usbtouch->input, ABS_Y, 0, + 2 * be16_to_cpu(packet->y_len), 0, 0); + } + /* + * The device reports state of IR sensors on X and Y axes. + * Each byte represents "darkness" percentage (0-100) of one element. + * 17" touchscreen reports only 64 x 52 bytes so the resolution is low. + * This also means that there's a limited multi-touch capability but + * it's disabled (and untested) here as there's no X driver for that. + */ + begin_x = end_x = begin_y = end_y = -1; + for (x = 0; x < be16_to_cpu(packet->x_len); x++) { + if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) { + begin_x = x; + continue; + } + if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) { + end_x = x - 1; + for (y = be16_to_cpu(packet->x_len); + y < be16_to_cpu(packet->data_len); y++) { + if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) { + begin_y = y - be16_to_cpu(packet->x_len); + continue; + } + if (end_y == -1 && + begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) { + end_y = y - 1 - be16_to_cpu(packet->x_len); + w = end_x - begin_x; + h = end_y - begin_y; +#if 0 + /* multi-touch */ + input_report_abs(usbtouch->input, + ABS_MT_TOUCH_MAJOR, max(w,h)); + input_report_abs(usbtouch->input, + ABS_MT_TOUCH_MINOR, min(x,h)); + input_report_abs(usbtouch->input, + ABS_MT_POSITION_X, 2*begin_x+w); + input_report_abs(usbtouch->input, + ABS_MT_POSITION_Y, 2*begin_y+h); + input_report_abs(usbtouch->input, + ABS_MT_ORIENTATION, w > h); + input_mt_sync(usbtouch->input); +#endif + /* single touch */ + usbtouch->x = 2 * begin_x + w; + usbtouch->y = 2 * begin_y + h; + usbtouch->touch = packet->flags & 0x01; + begin_y = end_y = -1; + return 1; + } + } + begin_x = end_x = -1; + } + + } + return 0; +} +#endif + + /***************************************************************************** * the different device descriptors */ @@ -875,6 +1110,16 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = tc5uh_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO + [DEVTYPE_NEXIO] = { + .rept_size = 128, + .irq_always = true, + .read_data = nexio_read_data, + .init = nexio_init, + .exit = nexio_exit, + }, +#endif }; @@ -1000,6 +1245,7 @@ static void usbtouch_irq(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: + case -EPIPE: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __func__, urb->status); @@ -1146,10 +1392,16 @@ static int usbtouch_probe(struct usb_interface *intf, input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, type->max_press, 0, 0); - usb_fill_int_urb(usbtouch->irq, udev, + if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(usbtouch->irq, udev, usb_rcvintpipe(udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); + else + usb_fill_bulk_urb(usbtouch->irq, udev, + usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch); usbtouch->irq->dev = udev; usbtouch->irq->transfer_dma = usbtouch->data_dma; @@ -1167,7 +1419,7 @@ static int usbtouch_probe(struct usb_interface *intf, err = input_register_device(usbtouch->input); if (err) { dbg("%s - input_register_device failed, err: %d", __func__, err); - goto out_free_buffers; + goto out_do_exit; } usb_set_intfdata(intf, usbtouch); @@ -1177,6 +1429,9 @@ static int usbtouch_probe(struct usb_interface *intf, return 0; +out_do_exit: + if (type->exit) + type->exit(usbtouch); out_free_buffers: usbtouch_free_buffers(udev, usbtouch); out_free: @@ -1199,6 +1454,8 @@ static void usbtouch_disconnect(struct usb_interface *intf) /* this will stop IO via close */ input_unregister_device(usbtouch->input); usb_free_urb(usbtouch->irq); + if (usbtouch->type->exit) + usbtouch->type->exit(usbtouch); usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); kfree(usbtouch); } -- GitLab From 1e87a43080a259a0e9739377708ece163b08de8d Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 4 Feb 2010 00:20:35 -0800 Subject: [PATCH 1576/3892] Input: usbtouchscreen - fix leaks and check return value of usb_submit_urb() Fix urb leak in error path of initialization and make sure we handle errors from initial usb_submit_urb(). Signed-off-by: Ondrej Zary Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 07656efee654..7a2d39abc586 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -1412,7 +1412,7 @@ static int usbtouch_probe(struct usb_interface *intf, err = type->init(usbtouch); if (err) { dbg("%s - type->init() failed, err: %d", __func__, err); - goto out_free_buffers; + goto out_free_urb; } } @@ -1424,14 +1424,25 @@ static int usbtouch_probe(struct usb_interface *intf, usb_set_intfdata(intf, usbtouch); - if (usbtouch->type->irq_always) - usb_submit_urb(usbtouch->irq, GFP_KERNEL); + if (usbtouch->type->irq_always) { + err = usb_submit_urb(usbtouch->irq, GFP_KERNEL); + if (err) { + err("%s - usb_submit_urb failed with result: %d", + __func__, err); + goto out_unregister_input; + } + } return 0; +out_unregister_input: + input_unregister_device(input_dev); + input_dev = NULL; out_do_exit: if (type->exit) type->exit(usbtouch); +out_free_urb: + usb_free_urb(usbtouch->irq); out_free_buffers: usbtouch_free_buffers(udev, usbtouch); out_free: -- GitLab From 0b7024ac4df5821347141c18e680b7166bc1cb20 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 2 Feb 2010 21:08:26 -0800 Subject: [PATCH 1577/3892] Input: add match() method to input hanlders Get rid of blacklist in input handler structure and instead allow handlers to define their own match() method to perform fine-grained filtering of supported devices. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 24 ++++++++++++++++-------- drivers/input/input.c | 13 ++++++------- drivers/input/joydev.c | 32 +++++++++++++++----------------- include/linux/input.h | 6 +++--- 4 files changed, 40 insertions(+), 35 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index cbf64b985ef4..ada25bb8941e 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1323,6 +1323,21 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, schedule_console_callback(); } +static bool kbd_match(struct input_handler *handler, struct input_dev *dev) +{ + int i; + + if (test_bit(EV_SND, dev->evbit)) + return true; + + if (test_bit(EV_KEY, dev->evbit)) + for (i = KEY_RESERVED; i < BTN_MISC; i++) + if (test_bit(i, dev->keybit)) + return true; + + return false; +} + /* * When a keyboard (or other input device) is found, the kbd_connect * function is called. The function then looks at the device, and if it @@ -1334,14 +1349,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev, { struct input_handle *handle; int error; - int i; - - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) - break; - - if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) - return -ENODEV; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) @@ -1407,6 +1414,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids); static struct input_handler kbd_handler = { .event = kbd_event, + .match = kbd_match, .connect = kbd_connect, .disconnect = kbd_disconnect, .start = kbd_start, diff --git a/drivers/input/input.c b/drivers/input/input.c index 7080a9d4b840..dae49eba6ccd 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -723,12 +723,13 @@ EXPORT_SYMBOL(input_set_keycode); if (i != BITS_TO_LONGS(max)) \ continue; -static const struct input_device_id *input_match_device(const struct input_device_id *id, +static const struct input_device_id *input_match_device(struct input_handler *handler, struct input_dev *dev) { + const struct input_device_id *id; int i; - for (; id->flags || id->driver_info; id++) { + for (id = handler->id_table; id->flags || id->driver_info; id++) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) if (id->bustype != dev->id.bustype) @@ -756,7 +757,8 @@ static const struct input_device_id *input_match_device(const struct input_devic MATCH_BIT(ffbit, FF_MAX); MATCH_BIT(swbit, SW_MAX); - return id; + if (!handler->match || handler->match(handler, dev)) + return id; } return NULL; @@ -767,10 +769,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han const struct input_device_id *id; int error; - if (handler->blacklist && input_match_device(handler->blacklist, dev)) - return -ENODEV; - - id = input_match_device(handler->id_table, dev); + id = input_match_device(handler, dev); if (!id) return -ENODEV; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index b1bd6dd32286..63e71f2a7acc 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -775,6 +775,20 @@ static void joydev_cleanup(struct joydev *joydev) input_close_device(handle); } + +static bool joydev_match(struct input_handler *handler, struct input_dev *dev) +{ + /* Avoid touchpads and touchscreens */ + if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit)) + return false; + + /* Avoid tablets, digitisers and similar devices */ + if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit)) + return false; + + return true; +} + static int joydev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { @@ -894,22 +908,6 @@ static void joydev_disconnect(struct input_handle *handle) put_device(&joydev->dev); } -static const struct input_device_id joydev_blacklist[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, - }, /* Avoid itouchpads and touchscreens */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) }, - }, /* Avoid tablets, digitisers and similar devices */ - { } /* Terminating entry */ -}; - static const struct input_device_id joydev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | @@ -936,13 +934,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids); static struct input_handler joydev_handler = { .event = joydev_event, + .match = joydev_match, .connect = joydev_connect, .disconnect = joydev_disconnect, .fops = &joydev_fops, .minor = JOYDEV_MINOR_BASE, .name = "joydev", .id_table = joydev_ids, - .blacklist = joydev_blacklist, }; static int __init joydev_init(void) diff --git a/include/linux/input.h b/include/linux/input.h index 6c9d3d49fa91..8dc5d724c703 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1200,6 +1200,8 @@ struct input_handle; * it may not sleep * @filter: similar to @event; separates normal event handlers from * "filters". + * @match: called after comparing device's id with handler's id_table + * to perform fine-grained matching between device and handler * @connect: called when attaching a handler to an input device * @disconnect: disconnects a handler from input device * @start: starts handler for given handle. This function is called by @@ -1211,8 +1213,6 @@ struct input_handle; * @name: name of the handler, to be shown in /proc/bus/input/handlers * @id_table: pointer to a table of input_device_ids this driver can * handle - * @blacklist: pointer to a table of input_device_ids this driver should - * ignore even if they match @id_table * @h_list: list of input handles associated with the handler * @node: for placing the driver onto input_handler_list * @@ -1235,6 +1235,7 @@ struct input_handler { void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + bool (*match)(struct input_handler *handler, struct input_dev *dev); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); @@ -1244,7 +1245,6 @@ struct input_handler { const char *name; const struct input_device_id *id_table; - const struct input_device_id *blacklist; struct list_head h_list; struct list_head node; -- GitLab From f266d7f5f89652a68e21e9882c44ee9104ad8d61 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 3 Feb 2010 21:21:32 +0200 Subject: [PATCH 1578/3892] x86_64: Print modules like i386 does Print modules list during kernel BUG. Signed-off-by: Alexey Dobriyan Cc: Arjan van de Ven Cc: Linus Torvalds Cc: Andrew Morton LKML-Reference: Signed-off-by: Ingo Molnar --- arch/x86/kernel/dumpstack_64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 0ad9597073f5..907a90e2901c 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -291,6 +291,7 @@ void show_registers(struct pt_regs *regs) sp = regs->sp; printk("CPU %d ", cpu); + print_modules(); __show_regs(regs, 1); printk("Process %s (pid: %d, threadinfo %p, task %p)\n", cur->comm, cur->pid, task_thread_info(cur), cur); -- GitLab From daf8a96b2d4a5d4d1d288831be43457c84c55a2f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 4 Feb 2010 00:30:39 -0800 Subject: [PATCH 1579/3892] Input: uinput - mark as non-seekable Seeking does not make sense for uinput so let's use nonseekable_open to mark the device non-seekable. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 18206e18d1b1..1477466076ad 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -290,6 +290,7 @@ static int uinput_open(struct inode *inode, struct file *file) newdev->state = UIST_NEW_DEVICE; file->private_data = newdev; + nonseekable_open(inode, file); return 0; } -- GitLab From 3d7bbd4575cfb23e6ef7368fff1f7d7e198b7930 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 4 Feb 2010 00:30:42 -0800 Subject: [PATCH 1580/3892] Input: mark input interfaces as non-seekable Seeking does not make sense for input interfaces such as evdev and joydev so let's use nonseekable_open to mark them non-seekable. Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 2 ++ drivers/input/joydev.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 258c639571b5..9f9816baeb97 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -278,6 +278,8 @@ static int evdev_open(struct inode *inode, struct file *file) goto err_free_client; file->private_data = client; + nonseekable_open(inode, file); + return 0; err_free_client: diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 63e71f2a7acc..c52bec4d0530 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -286,6 +286,8 @@ static int joydev_open(struct inode *inode, struct file *file) goto err_free_client; file->private_data = client; + nonseekable_open(inode, file); + return 0; err_free_client: -- GitLab From 9de89fe7c577847877ae00ea1aa6315559b10243 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:00 -0200 Subject: [PATCH 1581/3892] perf symbols: Remove perf_session usage in symbols layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed while writing the first test in 'perf regtest' that to just test the symbol handling routines one needs to create a perf session, that is a layer centered on a perf.data file, events, etc, so I untied these layers. This reduces the complexity for the users as the number of parameters to most of the symbols and session APIs now was reduced while not adding more state to all the map instances by only having data that is needed to split the kernel (kallsyms and ELF symtab sections) maps and do vmlinux relocation on the main kernel map. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-probe.c | 5 +- tools/perf/util/event.c | 6 +- tools/perf/util/map.c | 20 +++--- tools/perf/util/map.h | 22 +++++-- tools/perf/util/session.c | 35 +++++++---- tools/perf/util/session.h | 22 ++++--- tools/perf/util/symbol.c | 122 +++++++++++++++++-------------------- tools/perf/util/symbol.h | 19 +++--- tools/perf/util/thread.c | 3 +- tools/perf/util/thread.h | 14 +++-- 11 files changed, 149 insertions(+), 121 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 5d5dc6b09617..924a9518931a 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -369,7 +369,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, if (is_caller) { addr = data->call_site; if (!raw_ip) - sym = map_groups__find_function(&session->kmaps, session, addr, NULL); + sym = map_groups__find_function(&session->kmaps, addr, NULL); } else addr = data->ptr; diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 34f2acb1cc88..4fa73eca1d82 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -122,8 +122,7 @@ static int opt_del_probe_event(const struct option *opt __used, static void evaluate_probe_point(struct probe_point *pp) { struct symbol *sym; - sym = map__find_symbol_by_name(session.kmap, pp->function, - session.psession, NULL); + sym = map__find_symbol_by_name(session.kmap, pp->function, NULL); if (!sym) die("Kernel symbol \'%s\' not found - probe not added.", pp->function); @@ -132,7 +131,7 @@ static void evaluate_probe_point(struct probe_point *pp) #ifndef NO_LIBDWARF static int open_vmlinux(void) { - if (map__load(session.kmap, session.psession, NULL) < 0) { + if (map__load(session.kmap, NULL) < 0) { pr_debug("Failed to load kernel map.\n"); return -EINVAL; } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bbaee61c1683..c3831f633dec 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -374,9 +374,7 @@ int event__process_mmap(event_t *self, struct perf_session *session) goto out_problem; kernel->kernel = 1; - if (__map_groups__create_kernel_maps(&session->kmaps, - session->vmlinux_maps, - kernel) < 0) + if (__perf_session__create_kernel_maps(session, kernel) < 0) goto out_problem; session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; @@ -476,7 +474,7 @@ void thread__find_addr_location(struct thread *self, { thread__find_addr_map(self, session, cpumode, type, addr, al); if (al->map != NULL) - al->sym = map__find_symbol(al->map, session, al->addr, filter); + al->sym = map__find_symbol(al->map, al->addr, filter); else al->sym = NULL; } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index c4d55a0da2ea..36ff0bf0315d 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -104,8 +104,7 @@ void map__fixup_end(struct map *self) #define DSO__DELETED "(deleted)" -int map__load(struct map *self, struct perf_session *session, - symbol_filter_t filter) +int map__load(struct map *self, symbol_filter_t filter) { const char *name = self->dso->long_name; int nr; @@ -113,7 +112,7 @@ int map__load(struct map *self, struct perf_session *session, if (dso__loaded(self->dso, self->type)) return 0; - nr = dso__load(self->dso, self, session, filter); + nr = dso__load(self->dso, self, filter); if (nr < 0) { if (self->dso->has_build_id) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; @@ -144,24 +143,29 @@ int map__load(struct map *self, struct perf_session *session, return -1; } + /* + * Only applies to the kernel, as its symtabs aren't relative like the + * module ones. + */ + if (self->dso->kernel) + map__reloc_vmlinux(self); return 0; } -struct symbol *map__find_symbol(struct map *self, struct perf_session *session, - u64 addr, symbol_filter_t filter) +struct symbol *map__find_symbol(struct map *self, u64 addr, + symbol_filter_t filter) { - if (map__load(self, session, filter) < 0) + if (map__load(self, filter) < 0) return NULL; return dso__find_symbol(self->dso, self->type, addr); } struct symbol *map__find_symbol_by_name(struct map *self, const char *name, - struct perf_session *session, symbol_filter_t filter) { - if (map__load(self, session, filter) < 0) + if (map__load(self, filter) < 0) return NULL; if (!dso__sorted_by_name(self->dso, self->type)) diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 72f0b6ab5ea5..de048399d776 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -14,6 +14,8 @@ enum map_type { #define MAP__NR_TYPES (MAP__VARIABLE + 1) struct dso; +struct ref_reloc_sym; +struct map_groups; struct map { union { @@ -29,6 +31,16 @@ struct map { struct dso *dso; }; +struct kmap { + struct ref_reloc_sym *ref_reloc_sym; + struct map_groups *kmaps; +}; + +static inline struct kmap *map__kmap(struct map *self) +{ + return (struct kmap *)(self + 1); +} + static inline u64 map__map_ip(struct map *map, u64 ip) { return ip - map->start + map->pgoff; @@ -58,16 +70,14 @@ struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); -struct perf_session; - -int map__load(struct map *self, struct perf_session *session, - symbol_filter_t filter); -struct symbol *map__find_symbol(struct map *self, struct perf_session *session, +int map__load(struct map *self, symbol_filter_t filter); +struct symbol *map__find_symbol(struct map *self, u64 addr, symbol_filter_t filter); struct symbol *map__find_symbol_by_name(struct map *self, const char *name, - struct perf_session *session, symbol_filter_t filter); void map__fixup_start(struct map *self); void map__fixup_end(struct map *self); +void map__reloc_vmlinux(struct map *self); + #endif /* __PERF_MAP_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cf91d099f0aa..aa8a03120bbd 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -53,6 +53,11 @@ out_close: return -1; } +static inline int perf_session__create_kernel_maps(struct perf_session *self) +{ + return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps); +} + struct perf_session *perf_session__new(const char *filename, int mode, bool force) { size_t len = filename ? strlen(filename) + 1 : 0; @@ -507,6 +512,7 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, u64 addr) { char *bracket; + enum map_type i; self->ref_reloc_sym.name = strdup(symbol_name); if (self->ref_reloc_sym.name == NULL) @@ -517,6 +523,12 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, *bracket = '\0'; self->ref_reloc_sym.addr = addr; + + for (i = 0; i < MAP__NR_TYPES; ++i) { + struct kmap *kmap = map__kmap(self->vmlinux_maps[i]); + kmap->ref_reloc_sym = &self->ref_reloc_sym; + } + return 0; } @@ -530,20 +542,21 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip) return ip - (s64)map->pgoff; } -void perf_session__reloc_vmlinux_maps(struct perf_session *self, - u64 unrelocated_addr) +void map__reloc_vmlinux(struct map *self) { - enum map_type type; - s64 reloc = unrelocated_addr - self->ref_reloc_sym.addr; + struct kmap *kmap = map__kmap(self); + s64 reloc; - if (!reloc) + if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) return; - for (type = 0; type < MAP__NR_TYPES; ++type) { - struct map *map = self->vmlinux_maps[type]; + reloc = (kmap->ref_reloc_sym->unrelocated_addr - + kmap->ref_reloc_sym->addr); - map->map_ip = map__reloc_map_ip; - map->unmap_ip = map__reloc_unmap_ip; - map->pgoff = reloc; - } + if (!reloc) + return; + + self->map_ip = map__reloc_map_ip; + self->unmap_ip = map__reloc_unmap_ip; + self->pgoff = reloc; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 36d1a80c0b6c..752d75aebade 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -3,13 +3,13 @@ #include "event.h" #include "header.h" +#include "symbol.h" #include "thread.h" #include #include "../../../include/linux/perf_event.h" struct ip_callchain; struct thread; -struct symbol; struct perf_session { struct perf_header header; @@ -24,10 +24,7 @@ struct perf_session { unsigned long unknown_events; struct rb_root hists; u64 sample_type; - struct { - const char *name; - u64 addr; - } ref_reloc_sym; + struct ref_reloc_sym ref_reloc_sym; int fd; int cwdlen; char *cwd; @@ -69,9 +66,20 @@ int perf_header__read_build_ids(struct perf_header *self, int input, int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, const char *symbol_name, u64 addr); -void perf_session__reloc_vmlinux_maps(struct perf_session *self, - u64 unrelocated_addr); void mem_bswap_64(void *src, int byte_size); +static inline int __perf_session__create_kernel_maps(struct perf_session *self, + struct dso *kernel) +{ + return __map_groups__create_kernel_maps(&self->kmaps, + self->vmlinux_maps, kernel); +} + +static inline struct map * + perf_session__new_module_map(struct perf_session *self, + u64 start, const char *filename) +{ + return map_groups__new_module(&self->kmaps, start, filename); +} #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f9049d12ead6..613874260761 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1,6 +1,5 @@ #include "util.h" #include "../perf.h" -#include "session.h" #include "sort.h" #include "string.h" #include "symbol.h" @@ -34,7 +33,7 @@ enum dso_origin { static void dsos__add(struct list_head *head, struct dso *dso); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); static int dso__load_kernel_sym(struct dso *self, struct map *map, - struct perf_session *session, symbol_filter_t filter); + symbol_filter_t filter); static int vmlinux_path__nr_entries; static char **vmlinux_path; @@ -480,8 +479,9 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename, * the original ELF section names vmlinux have. */ static int dso__split_kallsyms(struct dso *self, struct map *map, - struct perf_session *session, symbol_filter_t filter) + symbol_filter_t filter) { + struct map_groups *kmaps = map__kmap(map)->kmaps; struct map *curr_map = map; struct symbol *pos; int count = 0; @@ -503,7 +503,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, *module++ = '\0'; if (strcmp(curr_map->dso->short_name, module)) { - curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); + curr_map = map_groups__find_by_name(kmaps, map->type, module); if (curr_map == NULL) { pr_debug("/proc/{kallsyms,modules} " "inconsistency while looking " @@ -538,7 +538,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, } curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; - map_groups__insert(&session->kmaps, curr_map); + map_groups__insert(kmaps, curr_map); ++kernel_range; } @@ -557,9 +557,8 @@ discard_symbol: rb_erase(&pos->rb_node, root); return count; } - -static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, - struct perf_session *session, symbol_filter_t filter) +int dso__load_kallsyms(struct dso *self, const char *filename, + struct map *map, symbol_filter_t filter) { if (dso__load_all_kallsyms(self, filename, map) < 0) return -1; @@ -567,7 +566,7 @@ static int dso__load_kallsyms(struct dso *self, const char *filename, struct map symbols__fixup_end(&self->symbols[map->type]); self->origin = DSO__ORIG_KERNEL; - return dso__split_kallsyms(self, map, session, filter); + return dso__split_kallsyms(self, map, filter); } static int dso__load_perf_map(struct dso *self, struct map *map, @@ -893,10 +892,10 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type } } -static int dso__load_sym(struct dso *self, struct map *map, - struct perf_session *session, const char *name, int fd, - symbol_filter_t filter, int kernel, int kmodule) +static int dso__load_sym(struct dso *self, struct map *map, const char *name, + int fd, symbol_filter_t filter, int kmodule) { + struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; struct map *curr_map = map; struct dso *curr_dso = self; size_t dso_name_len = strlen(self->short_name); @@ -953,7 +952,7 @@ static int dso__load_sym(struct dso *self, struct map *map, nr_syms = shdr.sh_size / shdr.sh_entsize; memset(&sym, 0, sizeof(sym)); - if (!kernel) { + if (!self->kernel) { self->adjust_symbols = (ehdr.e_type == ET_EXEC || elf_section_by_name(elf, &ehdr, &shdr, ".gnu.prelink_undo", @@ -967,9 +966,9 @@ static int dso__load_sym(struct dso *self, struct map *map, int is_label = elf_sym__is_label(&sym); const char *section_name; - if (kernel && session->ref_reloc_sym.name != NULL && - strcmp(elf_name, session->ref_reloc_sym.name) == 0) - perf_session__reloc_vmlinux_maps(session, sym.st_value); + if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && + strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) + kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; if (!is_label && !elf_sym__is_a(&sym, map->type)) continue; @@ -985,7 +984,7 @@ static int dso__load_sym(struct dso *self, struct map *map, section_name = elf_sec__name(&shdr, secstrs); - if (kernel || kmodule) { + if (self->kernel || kmodule) { char dso_name[PATH_MAX]; if (strcmp(section_name, @@ -1001,7 +1000,7 @@ static int dso__load_sym(struct dso *self, struct map *map, snprintf(dso_name, sizeof(dso_name), "%s%s", self->short_name, section_name); - curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); + curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); if (curr_map == NULL) { u64 start = sym.st_value; @@ -1020,7 +1019,7 @@ static int dso__load_sym(struct dso *self, struct map *map, curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; curr_dso->origin = DSO__ORIG_KERNEL; - map_groups__insert(&session->kmaps, curr_map); + map_groups__insert(kmap->kmaps, curr_map); dsos__add(&dsos__kernel, curr_dso); } else curr_dso = curr_map->dso; @@ -1236,8 +1235,7 @@ char dso__symtab_origin(const struct dso *self) return origin[self->origin]; } -int dso__load(struct dso *self, struct map *map, struct perf_session *session, - symbol_filter_t filter) +int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name; @@ -1249,7 +1247,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session, dso__set_loaded(self, map->type); if (self->kernel) - return dso__load_kernel_sym(self, map, session, filter); + return dso__load_kernel_sym(self, map, filter); name = malloc(size); if (!name) @@ -1320,7 +1318,7 @@ open_file: fd = open(name, O_RDONLY); } while (fd < 0); - ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); + ret = dso__load_sym(self, map, name, fd, filter, 0); close(fd); /* @@ -1376,7 +1374,7 @@ static int dso__kernel_module_get_build_id(struct dso *self) return 0; } -static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) +static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname) { struct dirent *dent; DIR *dir = opendir(dirname); @@ -1396,7 +1394,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d snprintf(path, sizeof(path), "%s/%s", dirname, dent->d_name); - if (perf_session__set_modules_path_dir(self, path) < 0) + if (map_groups__set_modules_path_dir(self, path) < 0) goto failure; } else { char *dot = strrchr(dent->d_name, '.'), @@ -1410,7 +1408,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d (int)(dot - dent->d_name), dent->d_name); strxfrchar(dso_name, '-', '_'); - map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); + map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); if (map == NULL) continue; @@ -1431,7 +1429,7 @@ failure: return -1; } -static int perf_session__set_modules_path(struct perf_session *self) +static int map_groups__set_modules_path(struct map_groups *self) { struct utsname uts; char modules_path[PATH_MAX]; @@ -1442,7 +1440,7 @@ static int perf_session__set_modules_path(struct perf_session *self) snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", uts.release); - return perf_session__set_modules_path_dir(self, modules_path); + return map_groups__set_modules_path_dir(self, modules_path); } /* @@ -1452,8 +1450,8 @@ static int perf_session__set_modules_path(struct perf_session *self) */ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) { - struct map *self = malloc(sizeof(*self)); - + struct map *self = zalloc(sizeof(*self) + + (dso->kernel ? sizeof(struct kmap) : 0)); if (self != NULL) { /* * ->end will be filled after we load all the symbols @@ -1464,8 +1462,8 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) return self; } -struct map *perf_session__new_module_map(struct perf_session *self, u64 start, - const char *filename) +struct map *map_groups__new_module(struct map_groups *self, u64 start, + const char *filename) { struct map *map; struct dso *dso = __dsos__findnew(&dsos__kernel, filename); @@ -1478,11 +1476,11 @@ struct map *perf_session__new_module_map(struct perf_session *self, u64 start, return NULL; dso->origin = DSO__ORIG_KMODULE; - map_groups__insert(&self->kmaps, map); + map_groups__insert(self, map); return map; } -static int perf_session__create_module_maps(struct perf_session *self) +static int map_groups__create_modules(struct map_groups *self) { char *line = NULL; size_t n; @@ -1520,7 +1518,7 @@ static int perf_session__create_module_maps(struct perf_session *self) *sep = '\0'; snprintf(name, sizeof(name), "[%s]", line); - map = perf_session__new_module_map(self, start, name); + map = map_groups__new_module(self, start, name); if (map == NULL) goto out_delete_line; dso__kernel_module_get_build_id(map->dso); @@ -1529,7 +1527,7 @@ static int perf_session__create_module_maps(struct perf_session *self) free(line); fclose(file); - return perf_session__set_modules_path(self); + return map_groups__set_modules_path(self); out_delete_line: free(line); @@ -1538,7 +1536,6 @@ out_failure: } static int dso__load_vmlinux(struct dso *self, struct map *map, - struct perf_session *session, const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; @@ -1572,14 +1569,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return -1; dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, session, vmlinux, fd, filter, 1, 0); + err = dso__load_sym(self, map, vmlinux, fd, filter, 0); close(fd); return err; } int dso__load_vmlinux_path(struct dso *self, struct map *map, - struct perf_session *session, symbol_filter_t filter) + symbol_filter_t filter) { int i, err = 0; @@ -1587,8 +1584,7 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map, vmlinux_path__nr_entries); for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(self, map, session, vmlinux_path[i], - filter); + err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); if (err > 0) { pr_debug("Using %s for symbols\n", vmlinux_path[i]); dso__set_long_name(self, strdup(vmlinux_path[i])); @@ -1600,7 +1596,7 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map, } static int dso__load_kernel_sym(struct dso *self, struct map *map, - struct perf_session *session, symbol_filter_t filter) + symbol_filter_t filter) { int err; const char *kallsyms_filename = NULL; @@ -1621,13 +1617,13 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * match. */ if (symbol_conf.vmlinux_name != NULL) { - err = dso__load_vmlinux(self, map, session, + err = dso__load_vmlinux(self, map, symbol_conf.vmlinux_name, filter); goto out_try_fixup; } if (vmlinux_path != NULL) { - err = dso__load_vmlinux_path(self, map, session, filter); + err = dso__load_vmlinux_path(self, map, filter); if (err > 0) goto out_fixup; } @@ -1675,7 +1671,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } do_kallsyms: - err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter); + err = dso__load_kallsyms(self, kallsyms_filename, map, filter); free(kallsyms_allocated_filename); out_try_fixup: @@ -1812,30 +1808,23 @@ int __map_groups__create_kernel_maps(struct map_groups *self, enum map_type type; for (type = 0; type < MAP__NR_TYPES; ++type) { + struct kmap *kmap; + vmlinux_maps[type] = map__new2(0, kernel, type); if (vmlinux_maps[type] == NULL) return -1; vmlinux_maps[type]->map_ip = vmlinux_maps[type]->unmap_ip = identity__map_ip; + + kmap = map__kmap(vmlinux_maps[type]); + kmap->kmaps = self; map_groups__insert(self, vmlinux_maps[type]); } return 0; } -static int map_groups__create_kernel_maps(struct map_groups *self, - struct map *vmlinux_maps[MAP__NR_TYPES], - const char *vmlinux) -{ - struct dso *kernel = dsos__create_kernel(vmlinux); - - if (kernel == NULL) - return -1; - - return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel); -} - static void vmlinux_path__exit(void) { while (--vmlinux_path__nr_entries >= 0) { @@ -1941,19 +1930,22 @@ out_free_comm_list: return -1; } -int perf_session__create_kernel_maps(struct perf_session *self) +int map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES]) { - if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps, - symbol_conf.vmlinux_name) < 0) + struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name); + + if (kernel == NULL) + return -1; + + if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0) return -1; - if (symbol_conf.use_modules && - perf_session__create_module_maps(self) < 0) - pr_debug("Failed to load list of modules for session %s, " - "continuing...\n", self->filename); + if (symbol_conf.use_modules && map_groups__create_modules(self) < 0) + return -1; /* * Now that we have all the maps created, just set the ->end of them: */ - map_groups__fixup_end(&self->kmaps); + map_groups__fixup_end(self); return 0; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 124302778c09..e6a59e5c2bea 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -80,6 +80,12 @@ static inline void *symbol__priv(struct symbol *self) return ((void *)self) - symbol_conf.priv_size; } +struct ref_reloc_sym { + const char *name; + u64 addr; + u64 unrelocated_addr; +}; + struct addr_location { struct thread *thread; struct map *map; @@ -126,12 +132,11 @@ static inline struct dso *dsos__findnew(const char *name) return __dsos__findnew(&dsos__user, name); } -struct perf_session; - -int dso__load(struct dso *self, struct map *map, struct perf_session *session, - symbol_filter_t filter); +int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); int dso__load_vmlinux_path(struct dso *self, struct map *map, - struct perf_session *session, symbol_filter_t filter); + symbol_filter_t filter); +int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, + symbol_filter_t filter); void dsos__fprintf(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp, bool with_hits); @@ -156,9 +161,5 @@ int kallsyms__parse(const char *filename, void *arg, int symbol__init(void); bool symbol_type__is_a(char symbol_type, enum map_type map_type); -int perf_session__create_kernel_maps(struct perf_session *self); - -struct map *perf_session__new_module_map(struct perf_session *self, u64 start, - const char *filename); extern struct dso *vdso; #endif /* __PERF_SYMBOL */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 4a08dcf50b68..634b7f7140d5 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -282,14 +282,13 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp) } struct symbol *map_groups__find_symbol(struct map_groups *self, - struct perf_session *session, enum map_type type, u64 addr, symbol_filter_t filter) { struct map *map = map_groups__find(self, type, addr); if (map != NULL) - return map__find_symbol(map, session, map->map_ip(map, addr), filter); + return map__find_symbol(map, map->map_ip(map, addr), filter); return NULL; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e35653c1817c..56f317b8a06c 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -59,15 +59,14 @@ void thread__find_addr_location(struct thread *self, struct addr_location *al, symbol_filter_t filter); struct symbol *map_groups__find_symbol(struct map_groups *self, - struct perf_session *session, enum map_type type, u64 addr, symbol_filter_t filter); -static inline struct symbol * -map_groups__find_function(struct map_groups *self, struct perf_session *session, - u64 addr, symbol_filter_t filter) +static inline struct symbol *map_groups__find_function(struct map_groups *self, + u64 addr, + symbol_filter_t filter) { - return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter); + return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); } struct map *map_groups__find_by_name(struct map_groups *self, @@ -76,4 +75,9 @@ struct map *map_groups__find_by_name(struct map_groups *self, int __map_groups__create_kernel_maps(struct map_groups *self, struct map *vmlinux_maps[MAP__NR_TYPES], struct dso *kernel); +int map_groups__create_kernel_maps(struct map_groups *self, + struct map *vmlinux_maps[MAP__NR_TYPES]); + +struct map *map_groups__new_module(struct map_groups *self, u64 start, + const char *filename); #endif /* __PERF_THREAD_H */ -- GitLab From 6275ce2d5f44ae4f8575c24724525cbb2a3a141b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:01 -0200 Subject: [PATCH 1582/3892] perf symbols: Fixup vsyscall maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While debugging a problem reported by Pekka Enberg by printing the IP and all the maps for a thread when we don't find a map for an IP I noticed that dso__load_sym needs to fixup these extra maps it creates to hold symbols in different ELF sections than the main kernel one. Now we're back showing things like: [root@doppio linux-2.6-tip]# perf report | grep vsyscall 0.02% mutt [kernel.kallsyms].vsyscall_fn [.] vread_hpet 0.01% named [kernel.kallsyms].vsyscall_fn [.] vread_hpet 0.01% NetworkManager [kernel.kallsyms].vsyscall_fn [.] vread_hpet 0.01% gconfd-2 [kernel.kallsyms].vsyscall_0 [.] vgettimeofday 0.01% hald-addon-rfki [kernel.kallsyms].vsyscall_fn [.] vread_hpet 0.00% dbus-daemon [kernel.kallsyms].vsyscall_fn [.] vread_hpet [root@doppio linux-2.6-tip]# Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 613874260761..051d71b33df0 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1011,7 +1011,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (curr_dso == NULL) goto out_elf_end; curr_map = map__new2(start, curr_dso, - MAP__FUNCTION); + map->type); if (curr_map == NULL) { dso__delete(curr_dso); goto out_elf_end; @@ -1021,6 +1021,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, curr_dso->origin = DSO__ORIG_KERNEL; map_groups__insert(kmap->kmaps, curr_map); dsos__add(&dsos__kernel, curr_dso); + dso__set_loaded(curr_dso, map->type); } else curr_dso = curr_map->dso; @@ -1058,8 +1059,16 @@ new_symbol: /* * For misannotated, zeroed, ASM function sizes. */ - if (nr > 0) + if (nr > 0) { symbols__fixup_end(&self->symbols[map->type]); + if (kmap) { + /* + * We need to fixup this here too because we create new + * maps here, for things like vsyscall sections. + */ + __map_groups__fixup_end(kmap->kmaps, map->type); + } + } err = nr; out_elf_end: elf_end(elf); -- GitLab From 8d92c02ab07602786eaa6d4e5b519395730b3fd3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:02 -0200 Subject: [PATCH 1583/3892] perf symbols: Ditch vdso global variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can check using strcmp, most DSOs don't start with '[' so the test is cheap enough and we had to test it there anyway since when reading perf.data files we weren't calling the routine that created this global variable and thus weren't setting it as "loaded", which was causing a bogus: Failed to open [vdso], continuing without symbols Message as the first line of 'perf report'. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/map.c | 7 ++++++- tools/perf/util/symbol.c | 26 ++++---------------------- tools/perf/util/symbol.h | 6 +++++- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 36ff0bf0315d..f6626cc3df2e 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -68,8 +68,13 @@ struct map *map__new(struct mmap_event *event, enum map_type type, map__init(self, type, event->start, event->start + event->len, event->pgoff, dso); - if (self->dso == vdso || anon) + if (anon) { +set_identity: self->map_ip = self->unmap_ip = identity__map_ip; + } else if (strcmp(filename, "[vdso]") == 0) { + dso__set_loaded(dso, self->type); + goto set_identity; + } } return self; out_delete: diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 051d71b33df0..e752837363ee 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -53,11 +53,6 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type) return self->sorted_by_name & (1 << type); } -static void dso__set_loaded(struct dso *self, enum map_type type) -{ - self->loaded |= (1 << type); -} - static void dso__set_sorted_by_name(struct dso *self, enum map_type type) { self->sorted_by_name |= (1 << type); @@ -1697,7 +1692,6 @@ out_fixup: LIST_HEAD(dsos__user); LIST_HEAD(dsos__kernel); -struct dso *vdso; static void dsos__add(struct list_head *head, struct dso *dso) { @@ -1790,24 +1784,12 @@ static struct dso *dsos__create_kernel(const char *vmlinux) { struct dso *kernel = dso__new_kernel(vmlinux); - if (kernel == NULL) - return NULL; - - vdso = dso__new("[vdso]"); - if (vdso == NULL) - goto out_delete_kernel_dso; - dso__set_loaded(vdso, MAP__FUNCTION); - - dso__read_running_kernel_build_id(kernel); - - dsos__add(&dsos__kernel, kernel); - dsos__add(&dsos__user, vdso); + if (kernel != NULL) { + dso__read_running_kernel_build_id(kernel); + dsos__add(&dsos__kernel, kernel); + } return kernel; - -out_delete_kernel_dso: - dso__delete(kernel); - return NULL; } int __map_groups__create_kernel_maps(struct map_groups *self, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e6a59e5c2bea..e90568a9e467 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -121,6 +121,11 @@ void dso__delete(struct dso *self); bool dso__loaded(const struct dso *self, enum map_type type); bool dso__sorted_by_name(const struct dso *self, enum map_type type); +static inline void dso__set_loaded(struct dso *self, enum map_type type) +{ + self->loaded |= (1 << type); +} + void dso__sort_by_name(struct dso *self, enum map_type type); extern struct list_head dsos__user, dsos__kernel; @@ -161,5 +166,4 @@ int kallsyms__parse(const char *filename, void *arg, int symbol__init(void); bool symbol_type__is_a(char symbol_type, enum map_type map_type); -extern struct dso *vdso; #endif /* __PERF_SYMBOL */ -- GitLab From 8ad94c6052649a8e32120b464eefa0ffd8f2f04f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:03 -0200 Subject: [PATCH 1584/3892] perf probe: Don't use a perf_session instance just to resolve symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the recent modifications done to untie the session and symbol layers, 'perf probe' now can use just the symbols layer. Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Masami Hiramatsu Cc: Frédéric Weisbecker Cc: Masami Hiramatsu Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Signed-off-by: Ingo Molnar --- tools/perf/builtin-probe.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 4fa73eca1d82..ad47bd4c50ef 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -41,7 +41,6 @@ #include "util/debugfs.h" #include "util/symbol.h" #include "util/thread.h" -#include "util/session.h" #include "util/parse-options.h" #include "util/parse-events.h" /* For debugfs_path */ #include "util/probe-finder.h" @@ -59,8 +58,8 @@ static struct { int nr_probe; struct probe_point probes[MAX_PROBES]; struct strlist *dellist; - struct perf_session *psession; - struct map *kmap; + struct map_groups kmap_groups; + struct map *kmaps[MAP__NR_TYPES]; struct line_range line_range; } session; @@ -122,7 +121,8 @@ static int opt_del_probe_event(const struct option *opt __used, static void evaluate_probe_point(struct probe_point *pp) { struct symbol *sym; - sym = map__find_symbol_by_name(session.kmap, pp->function, NULL); + sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION], + pp->function, NULL); if (!sym) die("Kernel symbol \'%s\' not found - probe not added.", pp->function); @@ -131,12 +131,13 @@ static void evaluate_probe_point(struct probe_point *pp) #ifndef NO_LIBDWARF static int open_vmlinux(void) { - if (map__load(session.kmap, NULL) < 0) { + if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { pr_debug("Failed to load kernel map.\n"); return -EINVAL; } - pr_debug("Try to open %s\n", session.kmap->dso->long_name); - return open(session.kmap->dso->long_name, O_RDONLY); + pr_debug("Try to open %s\n", + session.kmaps[MAP__FUNCTION]->dso->long_name); + return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY); } static int opt_show_lines(const struct option *opt __used, @@ -212,12 +213,11 @@ static void init_vmlinux(void) pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); if (symbol__init() < 0) die("Failed to init symbol map."); - session.psession = perf_session__new(NULL, O_WRONLY, false); - if (session.psession == NULL) - die("Failed to init perf_session."); - session.kmap = session.psession->vmlinux_maps[MAP__FUNCTION]; - if (!session.kmap) - die("Could not find kernel map.\n"); + + map_groups__init(&session.kmap_groups); + if (map_groups__create_kernel_maps(&session.kmap_groups, + session.kmaps) < 0) + die("Failed to create kernel maps."); } int cmd_probe(int argc, const char **argv, const char *prefix __used) -- GitLab From 7b2567c1f57c059de29d3f2ca03aca84473865c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:04 -0200 Subject: [PATCH 1585/3892] perf build-id: Move the routine to find DSOs with hits to the lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because 'perf record' will have to find the build-ids in after we stop recording, so as to reduce even more the impact in the workload while we do the measurement. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-5-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 2 ++ tools/perf/builtin-buildid-list.c | 31 ++---------------------- tools/perf/util/build-id.c | 39 +++++++++++++++++++++++++++++++ tools/perf/util/build-id.h | 8 +++++++ 4 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 tools/perf/util/build-id.c create mode 100644 tools/perf/util/build-id.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 42969303e20b..3a5fb36ccc97 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -357,6 +357,7 @@ LIB_H += util/include/asm/uaccess.h LIB_H += perf.h LIB_H += util/cache.h LIB_H += util/callchain.h +LIB_H += util/build-id.h LIB_H += util/debug.h LIB_H += util/debugfs.h LIB_H += util/event.h @@ -390,6 +391,7 @@ LIB_H += util/probe-event.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o +LIB_OBJS += util/build-id.o LIB_OBJS += util/config.o LIB_OBJS += util/ctype.o LIB_OBJS += util/debugfs.o diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 431f204bde64..d0675c02f81e 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -8,6 +8,7 @@ */ #include "builtin.h" #include "perf.h" +#include "util/build-id.h" #include "util/cache.h" #include "util/debug.h" #include "util/parse-options.h" @@ -33,34 +34,6 @@ static const struct option options[] = { OPT_END() }; -static int build_id_list__process_event(event_t *event, - struct perf_session *session) -{ - struct addr_location al; - u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = perf_session__findnew(session, event->ip.pid); - - if (thread == NULL) { - pr_err("problem processing %d event, skipping it.\n", - event->header.type); - return -1; - } - - thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.ip, &al); - - if (al.map != NULL) - al.map->dso->hit = 1; - - return 0; -} - -static struct perf_event_ops build_id_list__event_ops = { - .sample = build_id_list__process_event, - .mmap = event__process_mmap, - .fork = event__process_task, -}; - static int __cmd_buildid_list(void) { int err = -1; @@ -71,7 +44,7 @@ static int __cmd_buildid_list(void) return -1; if (with_hits) - perf_session__process_events(session, &build_id_list__event_ops); + perf_session__process_events(session, &build_id__mark_dso_hit_ops); dsos__fprintf_buildid(stdout, with_hits); diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c new file mode 100644 index 000000000000..04904b35ba81 --- /dev/null +++ b/tools/perf/util/build-id.c @@ -0,0 +1,39 @@ +/* + * build-id.c + * + * build-id support + * + * Copyright (C) 2009, 2010 Red Hat Inc. + * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo + */ +#include "build-id.h" +#include "event.h" +#include "symbol.h" +#include + +static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) +{ + struct addr_location al; + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct thread *thread = perf_session__findnew(session, event->ip.pid); + + if (thread == NULL) { + pr_err("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.ip, &al); + + if (al.map != NULL) + al.map->dso->hit = 1; + + return 0; +} + +struct perf_event_ops build_id__mark_dso_hit_ops = { + .sample = build_id__mark_dso_hit, + .mmap = event__process_mmap, + .fork = event__process_task, +}; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h new file mode 100644 index 000000000000..1d981d63cf9a --- /dev/null +++ b/tools/perf/util/build-id.h @@ -0,0 +1,8 @@ +#ifndef PERF_BUILD_ID_H_ +#define PERF_BUILD_ID_H_ 1 + +#include "session.h" + +extern struct perf_event_ops build_id__mark_dso_hit_ops; + +#endif -- GitLab From 6122e4e4f5d0913e319ef8a4dc60a47afe4abc0a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:05 -0200 Subject: [PATCH 1586/3892] perf record: Stop intercepting events, use postprocessing to get build-ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to stream events as fast as possible to perf.data, and also in the future we want to have splice working, when no interception will be possible. Using build_id__mark_dso_hit_ops to create the list of DSOs that back MMAPs we also optimize disk usage in the build-id cache by only caching DSOs that had hits. Suggested-by: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo Cc: Xiao Guangrong Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1265223128-11786-6-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 37 +++++++++++---------- tools/perf/util/header.c | 7 ++-- tools/perf/util/session.c | 64 ++++++++++++++++++++++--------------- tools/perf/util/session.h | 3 ++ tools/perf/util/symbol.c | 13 +++++--- tools/perf/util/symbol.h | 2 +- 6 files changed, 73 insertions(+), 53 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 949167efa1ed..706f00196b87 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -12,6 +12,7 @@ #include "perf.h" +#include "util/build-id.h" #include "util/util.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -65,6 +66,7 @@ static int nr_poll = 0; static int nr_cpu = 0; static int file_new = 1; +static off_t post_processing_offset; static struct perf_session *session; @@ -114,26 +116,10 @@ static void write_output(void *buf, size_t size) } } -static void write_event(event_t *buf, size_t size) -{ - /* - * Add it to the list of DSOs, so that when we finish this - * record session we can pick the available build-ids. - */ - if (buf->header.type == PERF_RECORD_MMAP) { - struct list_head *head = &dsos__user; - if (buf->mmap.header.misc == 1) - head = &dsos__kernel; - __dsos__findnew(head, buf->mmap.filename); - } - - write_output(buf, size); -} - static int process_synthesized_event(event_t *event, struct perf_session *self __used) { - write_event(event, event->header.size); + write_output(event, event->header.size); return 0; } @@ -185,14 +171,14 @@ static void mmap_read(struct mmap_data *md) size = md->mask + 1 - (old & md->mask); old += size; - write_event(buf, size); + write_output(buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_event(buf, size); + write_output(buf, size); md->prev = old; mmap_write_tail(md, old); @@ -402,10 +388,21 @@ static void open_counters(int cpu, pid_t pid) nr_cpu++; } +static int process_buildids(void) +{ + u64 size = lseek(output, 0, SEEK_CUR); + + session->fd = output; + return __perf_session__process_events(session, post_processing_offset, + size - post_processing_offset, + size, &build_id__mark_dso_hit_ops); +} + static void atexit_header(void) { session->header.data_size += bytes_written; + process_buildids(); perf_header__write(&session->header, output, true); } @@ -558,6 +555,8 @@ static int __cmd_record(int argc, const char **argv) return err; } + post_processing_offset = lseek(output, 0, SEEK_CUR); + err = event__synthesize_kernel_mmap(process_synthesized_event, session, "_text"); if (err < 0) { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ed3efd728b41..d5facd5ab1f7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -205,8 +205,11 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) dsos__for_each_with_build_id(pos, head) { int err; struct build_id_event b; - size_t len = pos->long_name_len + 1; + size_t len; + if (!pos->hit) + continue; + len = pos->long_name_len + 1; len = ALIGN(len, NAME_ALIGN); memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); @@ -371,7 +374,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) u64 sec_start; int idx = 0, err; - if (dsos__read_build_ids()) + if (dsos__read_build_ids(true)) perf_header__set_feat(self, HEADER_BUILD_ID); nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index aa8a03120bbd..74cbc64a3a3c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -385,8 +385,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se return thread; } -int perf_session__process_events(struct perf_session *self, - struct perf_event_ops *ops) +int __perf_session__process_events(struct perf_session *self, + u64 data_offset, u64 data_size, + u64 file_size, struct perf_event_ops *ops) { int err, mmap_prot, mmap_flags; u64 head, shift; @@ -396,32 +397,11 @@ int perf_session__process_events(struct perf_session *self, uint32_t size; char *buf; - if (perf_session__register_idle_thread(self) == NULL) - return -ENOMEM; - perf_event_ops__fill_defaults(ops); page_size = sysconf(_SC_PAGESIZE); - head = self->header.data_offset; - - if (!symbol_conf.full_paths) { - char bf[PATH_MAX]; - - if (getcwd(bf, sizeof(bf)) == NULL) { - err = -errno; -out_getcwd_err: - pr_err("failed to get the current directory\n"); - goto out_err; - } - self->cwd = strdup(bf); - if (self->cwd == NULL) { - err = -ENOMEM; - goto out_getcwd_err; - } - self->cwdlen = strlen(self->cwd); - } - + head = data_offset; shift = page_size * (head / page_size); offset += shift; head -= shift; @@ -486,10 +466,10 @@ more: head += size; - if (offset + head >= self->header.data_offset + self->header.data_size) + if (offset + head >= data_offset + data_size) goto done; - if (offset + head < self->size) + if (offset + head < file_size) goto more; done: err = 0; @@ -497,6 +477,38 @@ out_err: return err; } +int perf_session__process_events(struct perf_session *self, + struct perf_event_ops *ops) +{ + int err; + + if (perf_session__register_idle_thread(self) == NULL) + return -ENOMEM; + + if (!symbol_conf.full_paths) { + char bf[PATH_MAX]; + + if (getcwd(bf, sizeof(bf)) == NULL) { + err = -errno; +out_getcwd_err: + pr_err("failed to get the current directory\n"); + goto out_err; + } + self->cwd = strdup(bf); + if (self->cwd == NULL) { + err = -ENOMEM; + goto out_getcwd_err; + } + self->cwdlen = strlen(self->cwd); + } + + err = __perf_session__process_events(self, self->header.data_offset, + self->header.data_size, + self->size, ops); +out_err: + return err; +} + bool perf_session__has_traces(struct perf_session *self, const char *msg) { if (!(self->sample_type & PERF_SAMPLE_RAW)) { diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 752d75aebade..31950fcd8a4d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -50,6 +50,9 @@ void perf_session__delete(struct perf_session *self); void perf_event_header__bswap(struct perf_event_header *self); +int __perf_session__process_events(struct perf_session *self, + u64 data_offset, u64 data_size, u64 size, + struct perf_event_ops *ops); int perf_session__process_events(struct perf_session *self, struct perf_event_ops *event_ops); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e752837363ee..bfb055459670 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1076,25 +1076,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id) return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; } -static bool __dsos__read_build_ids(struct list_head *head) +static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) { bool have_build_id = false; struct dso *pos; - list_for_each_entry(pos, head, node) + list_for_each_entry(pos, head, node) { + if (with_hits && !pos->hit) + continue; if (filename__read_build_id(pos->long_name, pos->build_id, sizeof(pos->build_id)) > 0) { have_build_id = true; pos->has_build_id = true; } + } return have_build_id; } -bool dsos__read_build_ids(void) +bool dsos__read_build_ids(bool with_hits) { - bool kbuildids = __dsos__read_build_ids(&dsos__kernel), - ubuildids = __dsos__read_build_ids(&dsos__user); + bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits), + ubuildids = __dsos__read_build_ids(&dsos__user, with_hits); return kbuildids || ubuildids; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e90568a9e467..1b4192ee5300 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -157,7 +157,7 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); -bool dsos__read_build_ids(void); +bool dsos__read_build_ids(bool with_hits); int build_id__sprintf(const u8 *self, int len, char *bf); int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, -- GitLab From 29a9f66d703cb9464e24084e09edab5683e1b6b8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Feb 2010 16:52:06 -0200 Subject: [PATCH 1587/3892] perf tools: Adjust some verbosity levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not to pollute too much 'perf annotate' debugging sessions. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-7-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 33 ++++++++++---------------- tools/perf/util/include/linux/kernel.h | 1 + tools/perf/util/symbol.c | 9 +++---- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 73c202ee0882..4fc3899bf83a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -97,9 +97,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) sym_size = sym->end - sym->start; offset = ip - sym->start; - if (verbose) - fprintf(stderr, "%s: ip=%Lx\n", __func__, - he->map->unmap_ip(he->map, ip)); + pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip)); if (offset >= sym_size) return; @@ -108,12 +106,8 @@ static void hist_hit(struct hist_entry *he, u64 ip) h->sum++; h->ip[offset]++; - if (verbose >= 3) - printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", - (void *)(unsigned long)he->sym->start, - he->sym->name, - (void *)(unsigned long)ip, ip - he->sym->start, - h->ip[offset]); + pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start, + he->sym->name, ip, ip - he->sym->start, h->ip[offset]); } static int perf_session__add_hist_entry(struct perf_session *self, @@ -136,14 +130,14 @@ static int process_sample_event(event_t *event, struct perf_session *session) event->ip.pid, event->ip.ip); if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { - fprintf(stderr, "problem processing %d event, skipping it.\n", - event->header.type); + pr_warning("problem processing %d event, skipping it.\n", + event->header.type); return -1; } if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { - fprintf(stderr, "problem incrementing symbol count, " - "skipping event\n"); + pr_warning("problem incrementing symbol count, " + "skipping event\n"); return -1; } @@ -378,11 +372,9 @@ static void annotate_sym(struct hist_entry *he) if (!filename) return; - if (verbose) - fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", - __func__, filename, sym->name, - map->unmap_ip(map, sym->start), - map->unmap_ip(map, sym->end)); + pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, + filename, sym->name, map->unmap_ip(map, sym->start), + map->unmap_ip(map, sym->end)); if (full_paths) d_filename = filename; @@ -542,9 +534,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) setup_pager(); if (field_sep && *field_sep == '.') { - fputs("'.' is the only non valid --field-separator argument\n", - stderr); - exit(129); + pr_err("'.' is the only non valid --field-separator argument\n"); + return -1; } return __cmd_annotate(); diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 21c0274c02fa..f2611655ab51 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h @@ -101,5 +101,6 @@ simple_strtoul(const char *nptr, char **endptr, int base) eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) #endif diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index bfb055459670..a60ba2ba1044 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -137,7 +137,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name) self->start = start; self->end = len ? start + len - 1 : start; - pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); + pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); memcpy(self->name, name, namelen); @@ -1024,9 +1024,10 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } if (curr_dso->adjust_symbols) { - pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " - "%Lx sh_offset: %Lx\n", (u64)sym.st_value, - (u64)shdr.sh_addr, (u64)shdr.sh_offset); + pr_debug4("%s: adjusting symbol: st_value: %#Lx " + "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, + (u64)sym.st_value, (u64)shdr.sh_addr, + (u64)shdr.sh_offset); sym.st_value -= shdr.sh_addr - shdr.sh_offset; } /* -- GitLab From 7a2b6209863626cf8362e5ff4653491558f91e67 Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Wed, 3 Feb 2010 16:52:07 -0200 Subject: [PATCH 1588/3892] perf annotate: Fix it for non-prelinked *.so The problem was we were incorrectly calculating objdump addresses for sym->start and sym->end, look: For simple ET_DYN type DSO (*.so) with one function, objdump -dS output is something like this: 000004ac : int my_strlen(const char *s) 4ac: 55 push %ebp 4ad: 89 e5 mov %esp,%ebp 4af: 83 ec 10 sub $0x10,%esp { i.e. we have relative-to-dso-mapping IPs (=RIP) there. For ET_EXEC type and probably for prelinked libs as well (sorry can't test - I don't use prelink) objdump outputs absolute IPs, e.g. 08048604 : extern "C" int zz_strlen(const char *s) 8048604: 55 push %ebp 8048605: 89 e5 mov %esp,%ebp 8048607: 83 ec 10 sub $0x10,%esp { So, if sym->start is always relative to dso mapping(*), we'll have to unmap it for ET_EXEC like cases, and leave as is for ET_DYN cases. (*) and it is - we've explicitely made it relative. Look for adjust_symbols handling in dso__load_sym() Previously we were always unmapping sym->start and for ET_DYN dsos resulting addresses were wrong, and so objdump output was empty. The end result was that perf annotate output for symbols from non-prelinked *.so had always 0.00% percents only, which is wrong. To fix it, let's introduce a helper for converting rip to objdump address, and also let's document what map_ip() and unmap_ip() do -- I had to study sources for several hours to understand it. Signed-off-by: Kirill Smelkov Signed-off-by: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 5 +++-- tools/perf/util/map.c | 12 ++++++++++++ tools/perf/util/map.h | 9 +++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4fc3899bf83a..28ea4e0c3658 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -189,7 +189,7 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) line_ip = -1; } - start = he->map->unmap_ip(he->map, sym->start); + start = map__rip_2objdump(he->map, sym->start); if (line_ip != -1) { const char *path = NULL; @@ -397,7 +397,8 @@ static void annotate_sym(struct hist_entry *he) dso, dso->long_name, sym, sym->name); sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", - map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end), + map__rip_2objdump(map, sym->start), + map__rip_2objdump(map, sym->end), filename, filename); if (verbose >= 3) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index f6626cc3df2e..af5805f51314 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -210,3 +210,15 @@ size_t map__fprintf(struct map *self, FILE *fp) return fprintf(fp, " %Lx-%Lx %Lx %s\n", self->start, self->end, self->pgoff, self->dso->name); } + +/* + * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. + * map->dso->adjust_symbols==1 for ET_EXEC-like cases. + */ +u64 map__rip_2objdump(struct map *map, u64 rip) +{ + u64 addr = map->dso->adjust_symbols ? + map->unmap_ip(map, rip) : /* RIP -> IP */ + rip; + return addr; +} diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index de048399d776..9cee9c788dbf 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -26,8 +26,12 @@ struct map { u64 end; enum map_type type; u64 pgoff; + + /* ip -> dso rip */ u64 (*map_ip)(struct map *, u64); + /* dso rip -> ip */ u64 (*unmap_ip)(struct map *, u64); + struct dso *dso; }; @@ -56,6 +60,11 @@ static inline u64 identity__map_ip(struct map *map __used, u64 ip) return ip; } + +/* rip -> addr suitable for passing to `objdump --start-address=` */ +u64 map__rip_2objdump(struct map *map, u64 rip); + + struct symbol; struct mmap_event; -- GitLab From 6cff0e8dbaa4d5d822a814e5028683d7e71c3291 Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Wed, 3 Feb 2010 16:52:08 -0200 Subject: [PATCH 1589/3892] perf top: Teach it to autolocate vmlinux By relying on logic in dso__load_kernel_sym(), we can automatically load vmlinux. The only thing which needs to be adjusted, is how --sym-annotate option is handled - now we can't rely on vmlinux been loaded until full successful pass of dso__load_vmlinux(), but that's not the case if we'll do sym_filter_entry setup in symbol_filter(). So move this step right after event__process_sample() where we know the whole dso__load_kernel_sym() pass is done. By the way, though conceptually similar `perf top` still can't annotate userspace - see next patches with fixes. Signed-off-by: Kirill Smelkov Signed-off-by: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1265223128-11786-9-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf-top.txt | 2 +- tools/perf/builtin-top.c | 39 ++++++++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 4a7d558dc309..785b9fc32a46 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -74,7 +74,7 @@ OPTIONS -s :: --sym-annotate=:: - Annotate this symbol. Requires -k option. + Annotate this symbol. -v:: --verbose:: diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1fc018e048e1..83c09c8f28ed 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -94,6 +94,7 @@ struct source_line { static char *sym_filter = NULL; struct sym_entry *sym_filter_entry = NULL; +struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; static int sym_counter = 0; static int display_weighted = -1; @@ -695,11 +696,9 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); - if (symbol_conf.vmlinux_name) { - fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); - fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); - fprintf(stdout, "\t[S] stop annotation.\n"); - } + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); + fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); + fprintf(stdout, "\t[S] stop annotation.\n"); if (nr_counters > 1) fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); @@ -725,14 +724,13 @@ static int key_mapped(int c) case 'Q': case 'K': case 'U': + case 'F': + case 's': + case 'S': return 1; case 'E': case 'w': return nr_counters > 1 ? 1 : 0; - case 'F': - case 's': - case 'S': - return symbol_conf.vmlinux_name ? 1 : 0; default: break; } @@ -910,8 +908,12 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme = symbol__priv(sym); syme->map = map; syme->src = NULL; - if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) - sym_filter_entry = syme; + + if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { + /* schedule initial sym_filter_entry setup */ + sym_filter_entry_sched = syme; + sym_filter = NULL; + } for (i = 0; skip_symbols[i]; i++) { if (!strcmp(skip_symbols[i], name)) { @@ -976,6 +978,13 @@ static void event__process_sample(const event_t *self, return; } + /* let's see, whether we need to install initial sym_filter_entry */ + if (sym_filter_entry_sched) { + sym_filter_entry = sym_filter_entry_sched; + sym_filter_entry_sched = NULL; + parse_source(sym_filter_entry); + } + syme = symbol__priv(al.sym); if (!syme->skip) { syme->count[counter]++; @@ -1270,7 +1279,7 @@ static const struct option options[] = { OPT_BOOLEAN('i', "inherit", &inherit, "child tasks inherit counters"), OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", - "symbol to annotate - requires -k option"), + "symbol to annotate"), OPT_BOOLEAN('z', "zero", &zero, "zero history across updates"), OPT_INTEGER('F', "freq", &freq, @@ -1306,16 +1315,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) symbol_conf.priv_size = (sizeof(struct sym_entry) + (nr_counters + 1) * sizeof(unsigned long)); - if (symbol_conf.vmlinux_name == NULL) - symbol_conf.try_vmlinux_path = true; + + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init() < 0) return -1; if (delay_secs < 1) delay_secs = 1; - parse_source(sym_filter_entry); - /* * User specified count overrides default frequency. */ -- GitLab From 57d818895f9d294ab9080e5a662675fdee943ff1 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Thu, 4 Feb 2010 07:31:46 +0100 Subject: [PATCH 1590/3892] perf annotate: Fix perf top module symbol annotation Signed-off-by: Mike Galbraith Cc: Kirill Smelkov Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Frederic Weisbecker LKML-Reference: <1265265106.6364.5.camel@marge.simson.net> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 83c09c8f28ed..e4156bc4566d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -204,8 +204,8 @@ static void parse_source(struct sym_entry *syme) sprintf(command, "objdump --start-address=0x%016Lx " "--stop-address=0x%016Lx -dS %s", - map->unmap_ip(map, sym->start), - map->unmap_ip(map, sym->end), path); + map__rip_2objdump(map, sym->start), + map__rip_2objdump(map, sym->end), path); file = popen(command, "r"); if (!file) -- GitLab From 615d0ebbc782b67296e3226c293f520f93f93515 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 2 Feb 2010 16:49:04 -0500 Subject: [PATCH 1591/3892] kprobes: Disable booster when CONFIG_PREEMPT=y Disable kprobe booster when CONFIG_PREEMPT=y at this time, because it can't ensure that all kernel threads preempted on kprobe's boosted slot run out from the slot even using freeze_processes(). The booster on preemptive kernel will be resumed if synchronize_tasks() or something like that is introduced. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Ananth N Mavinakayanahalli Cc: Frederic Weisbecker Cc: Jim Keniston Cc: Mathieu Desnoyers Cc: Steven Rostedt LKML-Reference: <20100202214904.4694.24330.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- arch/ia64/kernel/kprobes.c | 2 +- arch/x86/kernel/kprobes.c | 2 +- kernel/kprobes.c | 29 ++--------------------------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 9adac441ac9b..7026b29e277a 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -870,7 +870,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) return 1; ss_probe: -#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER) +#if !defined(CONFIG_PREEMPT) if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) { /* Boost up -- we can execute copied instructions directly */ ia64_psr(regs)->ri = p->ainsn.slot; diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 5b8c7505b3bc..9453815138fa 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -429,7 +429,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { -#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER) +#if !defined(CONFIG_PREEMPT) if (p->ainsn.boostable == 1 && !p->post_handler) { /* Boost up -- we can execute copied instructions directly */ reset_current_kprobe(); diff --git a/kernel/kprobes.c b/kernel/kprobes.c index b7df302a0204..9907a03c29f6 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -124,30 +124,6 @@ static LIST_HEAD(kprobe_insn_pages); static int kprobe_garbage_slots; static int collect_garbage_slots(void); -static int __kprobes check_safety(void) -{ - int ret = 0; -#if defined(CONFIG_PREEMPT) && defined(CONFIG_FREEZER) - ret = freeze_processes(); - if (ret == 0) { - struct task_struct *p, *q; - do_each_thread(p, q) { - if (p != current && p->state == TASK_RUNNING && - p->pid != 0) { - printk("Check failed: %s is running\n",p->comm); - ret = -1; - goto loop_end; - } - } while_each_thread(p, q); - } -loop_end: - thaw_processes(); -#else - synchronize_sched(); -#endif - return ret; -} - /** * __get_insn_slot() - Find a slot on an executable page for an instruction. * We allocate an executable page if there's no room on existing ones. @@ -235,9 +211,8 @@ static int __kprobes collect_garbage_slots(void) { struct kprobe_insn_page *kip, *next; - /* Ensure no-one is preepmted on the garbages */ - if (check_safety()) - return -EAGAIN; + /* Ensure no-one is interrupted on the garbages */ + synchronize_sched(); list_for_each_entry_safe(kip, next, &kprobe_insn_pages, list) { int i; -- GitLab From 2cfa19780d61740f65790c5bae363b759d7c96fa Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 2 Feb 2010 16:49:11 -0500 Subject: [PATCH 1592/3892] ftrace/alternatives: Introducing *_text_reserved functions Introducing *_text_reserved functions for checking the text address range is partially reserved or not. This patch provides checking routines for x86 smp alternatives and dynamic ftrace. Since both functions modify fixed pieces of kernel text, they should reserve and protect those from other dynamic text modifier, like kprobes. This will also be extended when introducing other subsystems which modify fixed pieces of kernel text. Dynamic text modifiers should avoid those. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Steven Rostedt Cc: przemyslaw@pawelczyk.it Cc: Frederic Weisbecker Cc: Ananth N Mavinakayanahalli Cc: Jim Keniston Cc: Mathieu Desnoyers Cc: Jason Baron LKML-Reference: <20100202214911.4694.16587.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/alternative.h | 5 +++++ arch/x86/kernel/alternative.c | 16 ++++++++++++++++ include/linux/ftrace.h | 6 ++++++ kernel/trace/ftrace.c | 15 +++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 69b74a7b877f..ac80b7d70014 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -65,12 +65,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name, void *text, void *text_end); extern void alternatives_smp_module_del(struct module *mod); extern void alternatives_smp_switch(int smp); +extern int alternatives_text_reserved(void *start, void *end); #else static inline void alternatives_smp_module_add(struct module *mod, char *name, void *locks, void *locks_end, void *text, void *text_end) {} static inline void alternatives_smp_module_del(struct module *mod) {} static inline void alternatives_smp_switch(int smp) {} +static inline int alternatives_text_reserved(void *start, void *end) +{ + return 0; +} #endif /* CONFIG_SMP */ /* alternative assembly primitive: */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index de7353c0ce9c..3c13284ff86d 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -390,6 +390,22 @@ void alternatives_smp_switch(int smp) mutex_unlock(&smp_alt); } +/* Return 1 if the address range is reserved for smp-alternatives */ +int alternatives_text_reserved(void *start, void *end) +{ + struct smp_alt_module *mod; + u8 **ptr; + + list_for_each_entry(mod, &smp_alt_modules, next) { + if (mod->text > end || mod->text_end < start) + continue; + for (ptr = mod->locks; ptr < mod->locks_end; ptr++) + if (start <= *ptr && end >= *ptr) + return 1; + } + + return 0; +} #endif #ifdef CONFIG_PARAVIRT diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 0b4f97d24d7f..9d127efed43c 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -134,6 +134,8 @@ extern void unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops); extern void unregister_ftrace_function_probe_all(char *glob); +extern int ftrace_text_reserved(void *start, void *end); + enum { FTRACE_FL_FREE = (1 << 0), FTRACE_FL_FAILED = (1 << 1), @@ -250,6 +252,10 @@ static inline int unregister_ftrace_command(char *cmd_name) { return -EINVAL; } +static inline int ftrace_text_reserved(void *start, void *end) +{ + return 0; +} #endif /* CONFIG_DYNAMIC_FTRACE */ /* totally disable ftrace - can not re-enable after this */ diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1e6640f80454..3d90661a5f40 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1025,6 +1025,21 @@ static void ftrace_bug(int failed, unsigned long ip) } +/* Return 1 if the address range is reserved for ftrace */ +int ftrace_text_reserved(void *start, void *end) +{ + struct dyn_ftrace *rec; + struct ftrace_page *pg; + + do_for_each_ftrace_rec(pg, rec) { + if (rec->ip <= (unsigned long)end && + rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start) + return 1; + } while_for_each_ftrace_rec(); + return 0; +} + + static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable) { -- GitLab From 4554dbcb85a4ed2abaa2b6fa15649b796699ec89 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 2 Feb 2010 16:49:18 -0500 Subject: [PATCH 1593/3892] kprobes: Check probe address is reserved Check whether the address of new probe is already reserved by ftrace or alternatives (on x86) when registering new probe. If reserved, it returns an error and not register the probe. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Steven Rostedt Cc: przemyslaw@pawelczyk.it Cc: Frederic Weisbecker Cc: Ananth N Mavinakayanahalli Cc: Jim Keniston Cc: Mathieu Desnoyers Cc: Jason Baron LKML-Reference: <20100202214918.4694.94179.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/kprobes.c | 3 +++ kernel/kprobes.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 9453815138fa..5de9f4a9c3fd 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -337,6 +337,9 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p) int __kprobes arch_prepare_kprobe(struct kprobe *p) { + if (alternatives_text_reserved(p->addr, p->addr)) + return -EINVAL; + if (!can_probe((unsigned long)p->addr)) return -EILSEQ; /* insn: must be on special executable page on x86. */ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 9907a03c29f6..c3340e836c37 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -703,7 +704,8 @@ int __kprobes register_kprobe(struct kprobe *p) preempt_disable(); if (!kernel_text_address((unsigned long) p->addr) || - in_kprobes_functions((unsigned long) p->addr)) { + in_kprobes_functions((unsigned long) p->addr) || + ftrace_text_reserved(p->addr, p->addr)) { preempt_enable(); return -EINVAL; } -- GitLab From f24bb999d2b9f2950e5cac5b69bffedf73c24ea4 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 2 Feb 2010 16:49:25 -0500 Subject: [PATCH 1594/3892] ftrace: Remove record freezing Remove record freezing. Because kprobes never puts probe on ftrace's mcount call anymore, it doesn't need ftrace to check whether kprobes on it. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Steven Rostedt Cc: przemyslaw@pawelczyk.it Cc: Frederic Weisbecker LKML-Reference: <20100202214925.4694.73469.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- include/linux/ftrace.h | 1 - kernel/trace/ftrace.c | 39 --------------------------------------- 2 files changed, 40 deletions(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 9d127efed43c..eb054ae95605 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -143,7 +143,6 @@ enum { FTRACE_FL_ENABLED = (1 << 3), FTRACE_FL_NOTRACE = (1 << 4), FTRACE_FL_CONVERTED = (1 << 5), - FTRACE_FL_FROZEN = (1 << 6), }; struct dyn_ftrace { diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 3d90661a5f40..1904797f4a8a 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -898,36 +897,6 @@ static struct dyn_ftrace *ftrace_free_records; } \ } -#ifdef CONFIG_KPROBES - -static int frozen_record_count; - -static inline void freeze_record(struct dyn_ftrace *rec) -{ - if (!(rec->flags & FTRACE_FL_FROZEN)) { - rec->flags |= FTRACE_FL_FROZEN; - frozen_record_count++; - } -} - -static inline void unfreeze_record(struct dyn_ftrace *rec) -{ - if (rec->flags & FTRACE_FL_FROZEN) { - rec->flags &= ~FTRACE_FL_FROZEN; - frozen_record_count--; - } -} - -static inline int record_frozen(struct dyn_ftrace *rec) -{ - return rec->flags & FTRACE_FL_FROZEN; -} -#else -# define freeze_record(rec) ({ 0; }) -# define unfreeze_record(rec) ({ 0; }) -# define record_frozen(rec) ({ 0; }) -#endif /* CONFIG_KPROBES */ - static void ftrace_free_rec(struct dyn_ftrace *rec) { rec->freelist = ftrace_free_records; @@ -1091,14 +1060,6 @@ static void ftrace_replace_code(int enable) !(rec->flags & FTRACE_FL_CONVERTED)) continue; - /* ignore updates to this record's mcount site */ - if (get_kprobe((void *)rec->ip)) { - freeze_record(rec); - continue; - } else { - unfreeze_record(rec); - } - failed = __ftrace_replace_code(rec, enable); if (failed) { rec->flags |= FTRACE_FL_FAILED; -- GitLab From 9e3af04f8787315f63f55b191bb9a06741dbf183 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 4 Feb 2010 00:48:00 -0800 Subject: [PATCH 1595/3892] Input: gpio-keys - add support for disabling gpios through sysfs Now gpio-keys input driver exports 4 new attributes to userland through sysfs: /sys/devices/platform/gpio-keys/keys [ro] /sys/devices/platform/gpio-keys/switches [ro] /sys/devices/platform/gpio-keys/disabled_keys [rw] /sys/devices/platform/gpio-keys/disables_switches [rw] With these attributes, userland program can read which keys and switches can be disabled and then disable/enable them as needed. Keys and switches are exported as stringified bitmap of codes (keycodes or switch codes). For example keys 15, 89, 100, 101, 102 are exported as: '15,89,100-102'. Description of the attributes: keys - bitmap of keys which can be disabled switches - bitmap of switches which can be disabled disabled_keys - bitmap of currently disabled keys (bit 1 means disabled, 0 enabled) disabled_switches - bitmap of currently disabled switches (bit 1 means disabled, 0 enabled) Signed-off-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 318 ++++++++++++++++++++++++++++- include/linux/gpio_keys.h | 1 + 2 files changed, 308 insertions(+), 11 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 1aff3b76effd..2b708aa85553 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -30,13 +30,289 @@ struct gpio_button_data { struct input_dev *input; struct timer_list timer; struct work_struct work; + bool disabled; }; struct gpio_keys_drvdata { struct input_dev *input; + struct mutex disable_lock; + unsigned int n_buttons; struct gpio_button_data data[0]; }; +/* + * SYSFS interface for enabling/disabling keys and switches: + * + * There are 4 attributes under /sys/devices/platform/gpio-keys/ + * keys [ro] - bitmap of keys (EV_KEY) which can be + * disabled + * switches [ro] - bitmap of switches (EV_SW) which can be + * disabled + * disabled_keys [rw] - bitmap of keys currently disabled + * disabled_switches [rw] - bitmap of switches currently disabled + * + * Userland can change these values and hence disable event generation + * for each key (or switch). Disabling a key means its interrupt line + * is disabled. + * + * For example, if we have following switches set up as gpio-keys: + * SW_DOCK = 5 + * SW_CAMERA_LENS_COVER = 9 + * SW_KEYPAD_SLIDE = 10 + * SW_FRONT_PROXIMITY = 11 + * This is read from switches: + * 11-9,5 + * Next we want to disable proximity (11) and dock (5), we write: + * 11,5 + * to file disabled_switches. Now proximity and dock IRQs are disabled. + * This can be verified by reading the file disabled_switches: + * 11,5 + * If we now want to enable proximity (11) switch we write: + * 5 + * to disabled_switches. + * + * We can disable only those keys which don't allow sharing the irq. + */ + +/** + * get_n_events_by_type() - returns maximum number of events per @type + * @type: type of button (%EV_KEY, %EV_SW) + * + * Return value of this function can be used to allocate bitmap + * large enough to hold all bits for given type. + */ +static inline int get_n_events_by_type(int type) +{ + BUG_ON(type != EV_SW && type != EV_KEY); + + return (type == EV_KEY) ? KEY_CNT : SW_CNT; +} + +/** + * gpio_keys_disable_button() - disables given GPIO button + * @bdata: button data for button to be disabled + * + * Disables button pointed by @bdata. This is done by masking + * IRQ line. After this function is called, button won't generate + * input events anymore. Note that one can only disable buttons + * that don't share IRQs. + * + * Make sure that @bdata->disable_lock is locked when entering + * this function to avoid races when concurrent threads are + * disabling buttons at the same time. + */ +static void gpio_keys_disable_button(struct gpio_button_data *bdata) +{ + if (!bdata->disabled) { + /* + * Disable IRQ and possible debouncing timer. + */ + disable_irq(gpio_to_irq(bdata->button->gpio)); + if (bdata->button->debounce_interval) + del_timer_sync(&bdata->timer); + + bdata->disabled = true; + } +} + +/** + * gpio_keys_enable_button() - enables given GPIO button + * @bdata: button data for button to be disabled + * + * Enables given button pointed by @bdata. + * + * Make sure that @bdata->disable_lock is locked when entering + * this function to avoid races with concurrent threads trying + * to enable the same button at the same time. + */ +static void gpio_keys_enable_button(struct gpio_button_data *bdata) +{ + if (bdata->disabled) { + enable_irq(gpio_to_irq(bdata->button->gpio)); + bdata->disabled = false; + } +} + +/** + * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons + * @ddata: pointer to drvdata + * @buf: buffer where stringified bitmap is written + * @type: button type (%EV_KEY, %EV_SW) + * @only_disabled: does caller want only those buttons that are + * currently disabled or all buttons that can be + * disabled + * + * This function writes buttons that can be disabled to @buf. If + * @only_disabled is true, then @buf contains only those buttons + * that are currently disabled. Returns 0 on success or negative + * errno on failure. + */ +static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata, + char *buf, unsigned int type, + bool only_disabled) +{ + int n_events = get_n_events_by_type(type); + unsigned long *bits; + ssize_t ret; + int i; + + bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); + if (!bits) + return -ENOMEM; + + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (only_disabled && !bdata->disabled) + continue; + + __set_bit(bdata->button->code, bits); + } + + ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events); + buf[ret++] = '\n'; + buf[ret] = '\0'; + + kfree(bits); + + return ret; +} + +/** + * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap + * @ddata: pointer to drvdata + * @buf: buffer from userspace that contains stringified bitmap + * @type: button type (%EV_KEY, %EV_SW) + * + * This function parses stringified bitmap from @buf and disables/enables + * GPIO buttons accordinly. Returns 0 on success and negative error + * on failure. + */ +static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, + const char *buf, unsigned int type) +{ + int n_events = get_n_events_by_type(type); + unsigned long *bits; + ssize_t error; + int i; + + bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); + if (!bits) + return -ENOMEM; + + error = bitmap_parselist(buf, bits, n_events); + if (error) + goto out; + + /* First validate */ + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (test_bit(bdata->button->code, bits) && + !bdata->button->can_disable) { + error = -EINVAL; + goto out; + } + } + + mutex_lock(&ddata->disable_lock); + + for (i = 0; i < ddata->n_buttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + + if (bdata->button->type != type) + continue; + + if (test_bit(bdata->button->code, bits)) + gpio_keys_disable_button(bdata); + else + gpio_keys_enable_button(bdata); + } + + mutex_unlock(&ddata->disable_lock); + +out: + kfree(bits); + return error; +} + +#define ATTR_SHOW_FN(name, type, only_disabled) \ +static ssize_t gpio_keys_show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ + \ + return gpio_keys_attr_show_helper(ddata, buf, \ + type, only_disabled); \ +} + +ATTR_SHOW_FN(keys, EV_KEY, false); +ATTR_SHOW_FN(switches, EV_SW, false); +ATTR_SHOW_FN(disabled_keys, EV_KEY, true); +ATTR_SHOW_FN(disabled_switches, EV_SW, true); + +/* + * ATTRIBUTES: + * + * /sys/devices/platform/gpio-keys/keys [ro] + * /sys/devices/platform/gpio-keys/switches [ro] + */ +static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL); +static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL); + +#define ATTR_STORE_FN(name, type) \ +static ssize_t gpio_keys_store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, \ + size_t count) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ + ssize_t error; \ + \ + error = gpio_keys_attr_store_helper(ddata, buf, type); \ + if (error) \ + return error; \ + \ + return count; \ +} + +ATTR_STORE_FN(disabled_keys, EV_KEY); +ATTR_STORE_FN(disabled_switches, EV_SW); + +/* + * ATTRIBUTES: + * + * /sys/devices/platform/gpio-keys/disabled_keys [rw] + * /sys/devices/platform/gpio-keys/disables_switches [rw] + */ +static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO, + gpio_keys_show_disabled_keys, + gpio_keys_store_disabled_keys); +static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO, + gpio_keys_show_disabled_switches, + gpio_keys_store_disabled_switches); + +static struct attribute *gpio_keys_attrs[] = { + &dev_attr_keys.attr, + &dev_attr_switches.attr, + &dev_attr_disabled_keys.attr, + &dev_attr_disabled_switches.attr, + NULL, +}; + +static struct attribute_group gpio_keys_attr_group = { + .attrs = gpio_keys_attrs, +}; + static void gpio_keys_report_event(struct gpio_button_data *bdata) { struct gpio_keys_button *button = bdata->button; @@ -79,11 +355,13 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit gpio_keys_setup_key(struct device *dev, +static int __devinit gpio_keys_setup_key(struct platform_device *pdev, struct gpio_button_data *bdata, struct gpio_keys_button *button) { char *desc = button->desc ? button->desc : "gpio_keys"; + struct device *dev = &pdev->dev; + unsigned long irqflags; int irq, error; setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); @@ -112,10 +390,15 @@ static int __devinit gpio_keys_setup_key(struct device *dev, goto fail3; } - error = request_irq(irq, gpio_keys_isr, - IRQF_SHARED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - desc, bdata); + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + /* + * If platform has specified that the button can be disabled, + * we don't want it to share the interrupt line. + */ + if (!button->can_disable) + irqflags |= IRQF_SHARED; + + error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata); if (error) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, error); @@ -149,6 +432,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) goto fail1; } + ddata->input = input; + ddata->n_buttons = pdata->nbuttons; + mutex_init(&ddata->disable_lock); + platform_set_drvdata(pdev, ddata); input->name = pdev->name; @@ -164,8 +451,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) if (pdata->rep) __set_bit(EV_REP, input->evbit); - ddata->input = input; - for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; @@ -174,7 +459,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) bdata->input = input; bdata->button = button; - error = gpio_keys_setup_key(dev, bdata, button); + error = gpio_keys_setup_key(pdev, bdata, button); if (error) goto fail2; @@ -184,13 +469,20 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input_set_capability(input, type, button->code); } - error = input_register_device(input); + error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); if (error) { - dev_err(dev, "Unable to register input device, " - "error: %d\n", error); + dev_err(dev, "Unable to export keys/switches, error: %d\n", + error); goto fail2; } + error = input_register_device(input); + if (error) { + dev_err(dev, "Unable to register input device, error: %d\n", + error); + goto fail3; + } + /* get current state of buttons */ for (i = 0; i < pdata->nbuttons; i++) gpio_keys_report_event(&ddata->data[i]); @@ -200,6 +492,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) return 0; + fail3: + sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); fail2: while (--i >= 0) { free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); @@ -224,6 +518,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) struct input_dev *input = ddata->input; int i; + sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); + device_init_wakeup(&pdev->dev, 0); for (i = 0; i < pdata->nbuttons; i++) { diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index 1289fa7623ca..cd0b3f30f48e 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -10,6 +10,7 @@ struct gpio_keys_button { int type; /* input event type (EV_KEY, EV_SW) */ int wakeup; /* configure the button as a wake-up source */ int debounce_interval; /* debounce ticks interval in msecs */ + bool can_disable; }; struct gpio_keys_platform_data { -- GitLab From 74b7eb5885415ed41d012f432398d1b697115b5f Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Fri, 29 Jan 2010 14:57:52 +0800 Subject: [PATCH 1596/3892] sched: Change usage of rt_rq->rt_se to rt_rq->tg->rt_se[cpu] This is the first step to remove rt_rq member rt_se because it have the same meaning with tg->rt_se[cpu]. And the latter style is also used by the fair scheduling class. Signed-off-by: Yong Zhang Cc: Rusty Russell Signed-off-by: Peter Zijlstra LKML-Reference: <2674af741001282257r28c97a92o9f90cf16fe8d3d84@mail.gmail.com> Signed-off-by: Ingo Molnar --- kernel/sched_rt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index ca49ceb01201..bf3e38fdbe6d 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -199,8 +199,11 @@ static void dequeue_rt_entity(struct sched_rt_entity *rt_se); static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) { + int this_cpu = smp_processor_id(); struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; - struct sched_rt_entity *rt_se = rt_rq->rt_se; + struct sched_rt_entity *rt_se; + + rt_se = rt_rq->tg->rt_se[this_cpu]; if (rt_rq->rt_nr_running) { if (rt_se && !on_rt_rq(rt_se)) @@ -212,7 +215,10 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) static void sched_rt_rq_dequeue(struct rt_rq *rt_rq) { - struct sched_rt_entity *rt_se = rt_rq->rt_se; + int this_cpu = smp_processor_id(); + struct sched_rt_entity *rt_se; + + rt_se = rt_rq->tg->rt_se[this_cpu]; if (rt_se && on_rt_rq(rt_se)) dequeue_rt_entity(rt_se); -- GitLab From 23577256953c870de9b724c3a2611ce7be6a1e4e Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Fri, 29 Jan 2010 14:58:47 +0800 Subject: [PATCH 1597/3892] sched: Remove member rt_se from struct rt_rq It's a duplicate of tg->rt_se[cpu] and the only usage is sched_rt_rq_dequeue() and sched_rt_rq_enqueue(). After the first patch to those two function. rt_se can be removed. Signed-off-by: Yong Zhang Cc: Rusty Russell Signed-off-by: Peter Zijlstra LKML-Reference: <2674af741001282258q38781619u653ca4a7dd267347@mail.gmail.com> Signed-off-by: Ingo Molnar --- kernel/sched.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 2386f5440002..6cee227b1459 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -436,7 +436,6 @@ struct rt_rq { struct rq *rq; struct list_head leaf_rt_rq_list; struct task_group *tg; - struct sched_rt_entity *rt_se; #endif }; @@ -7592,7 +7591,6 @@ static void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq, tg->rt_rq[cpu] = rt_rq; init_rt_rq(rt_rq, rq); rt_rq->tg = tg; - rt_rq->rt_se = rt_se; rt_rq->rt_runtime = tg->rt_bandwidth.rt_runtime; if (add) list_add(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); -- GitLab From 9717e6cd3db22eade7dbae0fc9235c66325a7132 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 28 Jan 2010 13:57:44 +0100 Subject: [PATCH 1598/3892] perf_events: Optimize perf_event_task_tick() Pretty much all of the calls do perf_disable/perf_enable cycles, pull that out to cut back on hardware programming. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/perf_event.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 40f8b07c5601..087025fe3ba1 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1573,12 +1573,8 @@ static void rotate_ctx(struct perf_event_context *ctx) raw_spin_lock(&ctx->lock); /* Rotate the first entry last of non-pinned groups */ - perf_disable(); - list_rotate_left(&ctx->flexible_groups); - perf_enable(); - raw_spin_unlock(&ctx->lock); } @@ -1593,6 +1589,8 @@ void perf_event_task_tick(struct task_struct *curr) cpuctx = &__get_cpu_var(perf_cpu_context); ctx = curr->perf_event_ctxp; + perf_disable(); + perf_ctx_adjust_freq(&cpuctx->ctx); if (ctx) perf_ctx_adjust_freq(ctx); @@ -1608,6 +1606,8 @@ void perf_event_task_tick(struct task_struct *curr) cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE); if (ctx) task_ctx_sched_in(curr, EVENT_FLEXIBLE); + + perf_enable(); } static int event_enable_on_exec(struct perf_event *event, -- GitLab From 8c48e444191de0ff84e85d41180d7bc3e74f14ef Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 29 Jan 2010 13:25:31 +0100 Subject: [PATCH 1599/3892] perf_events, x86: Implement intel core solo/duo support Implement Intel Core Solo/Duo, aka. Intel Architectural Performance Monitoring Version 1. Signed-off-by: Peter Zijlstra Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Arjan van de Ven LKML-Reference: Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 133 ++++++++++++++----------------- 1 file changed, 61 insertions(+), 72 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 1846ead0576b..5b91992b6b25 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -227,6 +227,17 @@ static const u64 intel_perfmon_event_map[] = }; static struct event_constraint intel_core_event_constraints[] = +{ + INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ + INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ + INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ + INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ + INTEL_EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */ + INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FP_COMP_INSTR_RET */ + EVENT_CONSTRAINT_END +}; + +static struct event_constraint intel_core2_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0xc0, (0x3|(1ULL<<32))), /* INSTRUCTIONS_RETIRED */ FIXED_EVENT_CONSTRAINT(0x3c, (0x3|(1ULL<<33))), /* UNHALTED_CORE_CYCLES */ @@ -1216,7 +1227,7 @@ static void intel_pmu_disable_all(void) intel_pmu_disable_bts(); } -static void amd_pmu_disable_all(void) +static void x86_pmu_disable_all(void) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int idx; @@ -1226,11 +1237,11 @@ static void amd_pmu_disable_all(void) if (!test_bit(idx, cpuc->active_mask)) continue; - rdmsrl(MSR_K7_EVNTSEL0 + idx, val); + rdmsrl(x86_pmu.eventsel + idx, val); if (!(val & ARCH_PERFMON_EVENTSEL0_ENABLE)) continue; val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; - wrmsrl(MSR_K7_EVNTSEL0 + idx, val); + wrmsrl(x86_pmu.eventsel + idx, val); } } @@ -1278,7 +1289,7 @@ static void intel_pmu_enable_all(void) } } -static void amd_pmu_enable_all(void) +static void x86_pmu_enable_all(void) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int idx; @@ -1292,7 +1303,7 @@ static void amd_pmu_enable_all(void) val = event->hw.config; val |= ARCH_PERFMON_EVENTSEL0_ENABLE; - wrmsrl(MSR_K7_EVNTSEL0 + idx, val); + wrmsrl(x86_pmu.eventsel + idx, val); } } @@ -1546,7 +1557,7 @@ static inline void intel_pmu_ack_status(u64 ack) wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack); } -static inline void x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) +static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) { (void)checking_wrmsrl(hwc->config_base + idx, hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE); @@ -1598,12 +1609,6 @@ intel_pmu_disable_event(struct hw_perf_event *hwc, int idx) x86_pmu_disable_event(hwc, idx); } -static inline void -amd_pmu_disable_event(struct hw_perf_event *hwc, int idx) -{ - x86_pmu_disable_event(hwc, idx); -} - static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left); /* @@ -1723,15 +1728,14 @@ static void intel_pmu_enable_event(struct hw_perf_event *hwc, int idx) return; } - x86_pmu_enable_event(hwc, idx); + __x86_pmu_enable_event(hwc, idx); } -static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx) +static void x86_pmu_enable_event(struct hw_perf_event *hwc, int idx) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - if (cpuc->enabled) - x86_pmu_enable_event(hwc, idx); + __x86_pmu_enable_event(hwc, idx); } /* @@ -1988,50 +1992,6 @@ static void intel_pmu_reset(void) local_irq_restore(flags); } -static int p6_pmu_handle_irq(struct pt_regs *regs) -{ - struct perf_sample_data data; - struct cpu_hw_events *cpuc; - struct perf_event *event; - struct hw_perf_event *hwc; - int idx, handled = 0; - u64 val; - - data.addr = 0; - data.raw = NULL; - - cpuc = &__get_cpu_var(cpu_hw_events); - - for (idx = 0; idx < x86_pmu.num_events; idx++) { - if (!test_bit(idx, cpuc->active_mask)) - continue; - - event = cpuc->events[idx]; - hwc = &event->hw; - - val = x86_perf_event_update(event, hwc, idx); - if (val & (1ULL << (x86_pmu.event_bits - 1))) - continue; - - /* - * event overflow - */ - handled = 1; - data.period = event->hw.last_period; - - if (!x86_perf_event_set_period(event, hwc, idx)) - continue; - - if (perf_event_overflow(event, 1, &data, regs)) - p6_pmu_disable_event(hwc, idx); - } - - if (handled) - inc_irq_stat(apic_perf_irqs); - - return handled; -} - /* * This handler is triggered by the local APIC, so the APIC IRQ handling * rules apply: @@ -2098,7 +2058,7 @@ again: return 1; } -static int amd_pmu_handle_irq(struct pt_regs *regs) +static int x86_pmu_handle_irq(struct pt_regs *regs) { struct perf_sample_data data; struct cpu_hw_events *cpuc; @@ -2133,7 +2093,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) continue; if (perf_event_overflow(event, 1, &data, regs)) - amd_pmu_disable_event(hwc, idx); + x86_pmu.disable(hwc, idx); } if (handled) @@ -2374,7 +2334,7 @@ static __read_mostly struct notifier_block perf_event_nmi_notifier = { static __initconst struct x86_pmu p6_pmu = { .name = "p6", - .handle_irq = p6_pmu_handle_irq, + .handle_irq = x86_pmu_handle_irq, .disable_all = p6_pmu_disable_all, .enable_all = p6_pmu_enable_all, .enable = p6_pmu_enable_event, @@ -2401,6 +2361,29 @@ static __initconst struct x86_pmu p6_pmu = { .event_constraints = intel_p6_event_constraints }; +static __initconst struct x86_pmu core_pmu = { + .name = "core", + .handle_irq = x86_pmu_handle_irq, + .disable_all = x86_pmu_disable_all, + .enable_all = x86_pmu_enable_all, + .enable = x86_pmu_enable_event, + .disable = x86_pmu_disable_event, + .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, + .perfctr = MSR_ARCH_PERFMON_PERFCTR0, + .event_map = intel_pmu_event_map, + .raw_event = intel_pmu_raw_event, + .max_events = ARRAY_SIZE(intel_perfmon_event_map), + .apic = 1, + /* + * Intel PMCs cannot be accessed sanely above 32 bit width, + * so we install an artificial 1<<31 period regardless of + * the generic event period: + */ + .max_period = (1ULL << 31) - 1, + .get_event_constraints = intel_get_event_constraints, + .event_constraints = intel_core_event_constraints, +}; + static __initconst struct x86_pmu intel_pmu = { .name = "Intel", .handle_irq = intel_pmu_handle_irq, @@ -2427,11 +2410,11 @@ static __initconst struct x86_pmu intel_pmu = { static __initconst struct x86_pmu amd_pmu = { .name = "AMD", - .handle_irq = amd_pmu_handle_irq, - .disable_all = amd_pmu_disable_all, - .enable_all = amd_pmu_enable_all, - .enable = amd_pmu_enable_event, - .disable = amd_pmu_disable_event, + .handle_irq = x86_pmu_handle_irq, + .disable_all = x86_pmu_disable_all, + .enable_all = x86_pmu_enable_all, + .enable = x86_pmu_enable_event, + .disable = x86_pmu_disable_event, .eventsel = MSR_K7_EVNTSEL0, .perfctr = MSR_K7_PERFCTR0, .event_map = amd_pmu_event_map, @@ -2498,9 +2481,10 @@ static __init int intel_pmu_init(void) version = eax.split.version_id; if (version < 2) - return -ENODEV; + x86_pmu = core_pmu; + else + x86_pmu = intel_pmu; - x86_pmu = intel_pmu; x86_pmu.version = version; x86_pmu.num_events = eax.split.num_events; x86_pmu.event_bits = eax.split.bit_width; @@ -2510,12 +2494,17 @@ static __init int intel_pmu_init(void) * Quirk: v2 perfmon does not report fixed-purpose events, so * assume at least 3 events: */ - x86_pmu.num_events_fixed = max((int)edx.split.num_events_fixed, 3); + if (version > 1) + x86_pmu.num_events_fixed = max((int)edx.split.num_events_fixed, 3); /* * Install the hw-cache-events table: */ switch (boot_cpu_data.x86_model) { + case 14: /* 65 nm core solo/duo, "Yonah" */ + pr_cont("Core events, "); + break; + case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ @@ -2523,7 +2512,7 @@ static __init int intel_pmu_init(void) memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, sizeof(hw_cache_event_ids)); - x86_pmu.event_constraints = intel_core_event_constraints; + x86_pmu.event_constraints = intel_core2_event_constraints; pr_cont("Core2 events, "); break; -- GitLab From fce877e3a429940a986e085a41e8b57f2d922e36 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 29 Jan 2010 13:25:12 +0100 Subject: [PATCH 1600/3892] bitops: Ensure the compile time HWEIGHT is only used for such Avoid accidental misuse by failing to compile things Suggested-by: Andrew Morton Signed-off-by: Peter Zijlstra Cc: Linus Torvalds LKML-Reference: Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 10 +++++++--- include/linux/bitops.h | 33 +++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 5b91992b6b25..96cfc1a4fe9f 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -93,13 +93,16 @@ struct cpu_hw_events { struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ }; -#define EVENT_CONSTRAINT(c, n, m) { \ +#define __EVENT_CONSTRAINT(c, n, m, w) {\ { .idxmsk64[0] = (n) }, \ .code = (c), \ .cmask = (m), \ - .weight = HWEIGHT64((u64)(n)), \ + .weight = (w), \ } +#define EVENT_CONSTRAINT(c, n, m) \ + __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n)) + #define INTEL_EVENT_CONSTRAINT(c, n) \ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVTSEL_MASK) @@ -2622,7 +2625,8 @@ void __init init_hw_perf_events(void) register_die_notifier(&perf_event_nmi_notifier); unconstrained = (struct event_constraint) - EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, 0); + __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_events) - 1, + 0, x86_pmu.num_events); pr_info("... version: %d\n", x86_pmu.version); pr_info("... bit width: %d\n", x86_pmu.event_bits); diff --git a/include/linux/bitops.h b/include/linux/bitops.h index ba0fd1eb4af7..25b8b2f33ae9 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -45,19 +45,30 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } -#define HWEIGHT8(w) \ - ( (!!((w) & (1ULL << 0))) + \ - (!!((w) & (1ULL << 1))) + \ - (!!((w) & (1ULL << 2))) + \ - (!!((w) & (1ULL << 3))) + \ - (!!((w) & (1ULL << 4))) + \ - (!!((w) & (1ULL << 5))) + \ - (!!((w) & (1ULL << 6))) + \ +/* + * Clearly slow versions of the hweightN() functions, their benefit is + * of course compile time evaluation of constant arguments. + */ +#define HWEIGHT8(w) \ + ( BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + \ + (!!((w) & (1ULL << 0))) + \ + (!!((w) & (1ULL << 1))) + \ + (!!((w) & (1ULL << 2))) + \ + (!!((w) & (1ULL << 3))) + \ + (!!((w) & (1ULL << 4))) + \ + (!!((w) & (1ULL << 5))) + \ + (!!((w) & (1ULL << 6))) + \ (!!((w) & (1ULL << 7))) ) -#define HWEIGHT16(w) (HWEIGHT8(w) + HWEIGHT8(w >> 8)) -#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16(w >> 16)) -#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32(w >> 32)) +#define HWEIGHT16(w) (HWEIGHT8(w) + HWEIGHT8((w) >> 8)) +#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16)) +#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32)) + +/* + * Type invariant version that simply casts things to the + * largest type. + */ +#define HWEIGHT(w) HWEIGHT64((u64)(w)) /** * rol32 - rotate a 32-bit value left -- GitLab From 447a194b393f32699607fd99617a40abd6a95114 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 1 Feb 2010 14:50:01 +0200 Subject: [PATCH 1601/3892] perf_events, x86: Fix bug in hw_perf_enable() We cannot assume that because hwc->idx == assign[i], we can avoid reprogramming the counter in hw_perf_enable(). The event may have been scheduled out and another event may have been programmed into this counter. Thus, we need a more robust way of verifying if the counter still contains config/data related to an event. This patch adds a generation number to each counter on each cpu. Using this mechanism we can verify reliabilty whether the content of a counter corresponds to an event. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <4b66dc67.0b38560a.1635.ffffae18@mx.google.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 34 ++++++++++++++++++++++++++------ include/linux/perf_event.h | 2 ++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 96cfc1a4fe9f..a920f173a220 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -90,6 +90,7 @@ struct cpu_hw_events { int n_events; int n_added; int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ + u64 tags[X86_PMC_IDX_MAX]; struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ }; @@ -1142,6 +1143,8 @@ static int __hw_perf_event_init(struct perf_event *event) hwc->config = ARCH_PERFMON_EVENTSEL_INT; hwc->idx = -1; + hwc->last_cpu = -1; + hwc->last_tag = ~0ULL; /* * Count user and OS events unless requested not to. @@ -1457,11 +1460,14 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, return n; } - static inline void x86_assign_hw_event(struct perf_event *event, - struct hw_perf_event *hwc, int idx) + struct cpu_hw_events *cpuc, int i) { - hwc->idx = idx; + struct hw_perf_event *hwc = &event->hw; + + hwc->idx = cpuc->assign[i]; + hwc->last_cpu = smp_processor_id(); + hwc->last_tag = ++cpuc->tags[i]; if (hwc->idx == X86_PMC_IDX_FIXED_BTS) { hwc->config_base = 0; @@ -1480,6 +1486,15 @@ static inline void x86_assign_hw_event(struct perf_event *event, } } +static inline int match_prev_assignment(struct hw_perf_event *hwc, + struct cpu_hw_events *cpuc, + int i) +{ + return hwc->idx == cpuc->assign[i] && + hwc->last_cpu == smp_processor_id() && + hwc->last_tag == cpuc->tags[i]; +} + static void __x86_pmu_disable(struct perf_event *event, struct cpu_hw_events *cpuc); void hw_perf_enable(void) @@ -1508,7 +1523,14 @@ void hw_perf_enable(void) event = cpuc->event_list[i]; hwc = &event->hw; - if (hwc->idx == -1 || hwc->idx == cpuc->assign[i]) + /* + * we can avoid reprogramming counter if: + * - assigned same counter as last time + * - running on same CPU as last time + * - no other event has used the counter since + */ + if (hwc->idx == -1 || + match_prev_assignment(hwc, cpuc, i)) continue; __x86_pmu_disable(event, cpuc); @@ -1522,12 +1544,12 @@ void hw_perf_enable(void) hwc = &event->hw; if (hwc->idx == -1) { - x86_assign_hw_event(event, hwc, cpuc->assign[i]); + x86_assign_hw_event(event, cpuc, i); x86_perf_event_set_period(event, hwc, hwc->idx); } /* * need to mark as active because x86_pmu_disable() - * clear active_mask and eventsp[] yet it preserves + * clear active_mask and events[] yet it preserves * idx */ set_bit(hwc->idx, cpuc->active_mask); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 556b0f4a668e..071a7db52549 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -478,9 +478,11 @@ struct hw_perf_event { union { struct { /* hardware */ u64 config; + u64 last_tag; unsigned long config_base; unsigned long event_base; int idx; + int last_cpu; }; struct { /* software */ s64 remaining; -- GitLab From 34d2819f20782feb60f9434470ecfb200875fd41 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 4 Feb 2010 09:51:28 +0100 Subject: [PATCH 1602/3892] x86, mtrr: Remove unused mtrr/state.c The last reference to the helpers in went away with 9a6b344ea967efa0bb5ca4cb5405f840652b66c4 leaving unused code. Remove it. Signed-off-by: Borislav Petkov LKML-Reference: <20100204085128.GA513@liondog.tnic> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/mtrr/Makefile | 2 +- arch/x86/kernel/cpu/mtrr/state.c | 94 ------------------------------- 2 files changed, 1 insertion(+), 95 deletions(-) delete mode 100644 arch/x86/kernel/cpu/mtrr/state.c diff --git a/arch/x86/kernel/cpu/mtrr/Makefile b/arch/x86/kernel/cpu/mtrr/Makefile index f4361b56f8e9..ad9e5ed81181 100644 --- a/arch/x86/kernel/cpu/mtrr/Makefile +++ b/arch/x86/kernel/cpu/mtrr/Makefile @@ -1,3 +1,3 @@ -obj-y := main.o if.o generic.o state.o cleanup.o +obj-y := main.o if.o generic.o cleanup.o obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c deleted file mode 100644 index dfc80b4e6b0d..000000000000 --- a/arch/x86/kernel/cpu/mtrr/state.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -#include "mtrr.h" - -/* Put the processor into a state where MTRRs can be safely set */ -void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) -{ - unsigned int cr0; - - /* Disable interrupts locally */ - local_irq_save(ctxt->flags); - - if (use_intel() || is_cpu(CYRIX)) { - - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if (cpu_has_pge) { - ctxt->cr4val = read_cr4(); - write_cr4(ctxt->cr4val & ~X86_CR4_PGE); - } - - /* - * Disable and flush caches. Note that wbinvd flushes the TLBs - * as a side-effect - */ - cr0 = read_cr0() | X86_CR0_CD; - wbinvd(); - write_cr0(cr0); - wbinvd(); - - if (use_intel()) { - /* Save MTRR state */ - rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - } else { - /* - * Cyrix ARRs - - * everything else were excluded at the top - */ - ctxt->ccr3 = getCx86(CX86_CCR3); - } - } -} - -void set_mtrr_cache_disable(struct set_mtrr_context *ctxt) -{ - if (use_intel()) { - /* Disable MTRRs, and set the default type to uncached */ - mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, - ctxt->deftype_hi); - } else { - if (is_cpu(CYRIX)) { - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); - } - } -} - -/* Restore the processor after a set_mtrr_prepare */ -void set_mtrr_done(struct set_mtrr_context *ctxt) -{ - if (use_intel() || is_cpu(CYRIX)) { - - /* Flush caches and TLBs */ - wbinvd(); - - /* Restore MTRRdefType */ - if (use_intel()) { - /* Intel (P6) standard MTRRs */ - mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, - ctxt->deftype_hi); - } else { - /* - * Cyrix ARRs - - * everything else was excluded at the top - */ - setCx86(CX86_CCR3, ctxt->ccr3); - } - - /* Enable caches */ - write_cr0(read_cr0() & 0xbfffffff); - - /* Restore value of CR4 */ - if (cpu_has_pge) - write_cr4(ctxt->cr4val); - } - /* Re-enable interrupts locally (if enabled previously) */ - local_irq_restore(ctxt->flags); -} -- GitLab From f887f3019e56389a73617f4e70f512e82cc89adb Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 4 Feb 2010 16:46:42 +0800 Subject: [PATCH 1603/3892] perf tools: Clean up O_LARGEFILE et al usage Setting _FILE_OFFSET_BITS and using O_LARGEFILE, lseek64, etc, is redundant. Thanks H. Peter Anvin for pointing it out. So, this patch removes O_LARGEFILE, lseek64, etc. Suggested-by: "H. Peter Anvin" Signed-off-by: Xiao Guangrong Cc: Frederic Weisbecker Cc: Steven Rostedt Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <4B6A8972.3070605@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 3 +-- tools/perf/util/header.c | 21 ++++++++++----------- tools/perf/util/session.c | 3 +-- tools/perf/util/trace-event-read.c | 20 ++++++++++---------- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 706f00196b87..3ad599b12c91 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -5,7 +5,6 @@ * (or a CPU, or a PID) into the perf.data output file - for * later analysis via perf report. */ -#define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 #include "builtin.h" @@ -451,7 +450,7 @@ static int __cmd_record(int argc, const char **argv) append_file = 0; } - flags = O_CREAT|O_RDWR|O_LARGEFILE; + flags = O_CREAT|O_RDWR; if (append_file) file_new = 0; else diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d5facd5ab1f7..6c9aa16ee51f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1,4 +1,3 @@ -#define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 #include @@ -388,7 +387,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) sec_size = sizeof(*feat_sec) * nr_sections; sec_start = self->data_offset + self->data_size; - lseek64(fd, sec_start + sec_size, SEEK_SET); + lseek(fd, sec_start + sec_size, SEEK_SET); if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { struct perf_file_section *trace_sec; @@ -396,9 +395,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd) trace_sec = &feat_sec[idx++]; /* Write trace info */ - trace_sec->offset = lseek64(fd, 0, SEEK_CUR); + trace_sec->offset = lseek(fd, 0, SEEK_CUR); read_tracing_data(fd, attrs, nr_counters); - trace_sec->size = lseek64(fd, 0, SEEK_CUR) - trace_sec->offset; + trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; } @@ -408,18 +407,18 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; /* Write build-ids */ - buildid_sec->offset = lseek64(fd, 0, SEEK_CUR); + buildid_sec->offset = lseek(fd, 0, SEEK_CUR); err = dsos__write_buildid_table(fd); if (err < 0) { pr_debug("failed to write buildid table\n"); goto out_free; } - buildid_sec->size = lseek64(fd, 0, SEEK_CUR) - - buildid_sec->offset; + buildid_sec->size = lseek(fd, 0, SEEK_CUR) - + buildid_sec->offset; dsos__cache_build_ids(); } - lseek64(fd, sec_start, SEEK_SET); + lseek(fd, sec_start, SEEK_SET); err = do_write(fd, feat_sec, sec_size); if (err < 0) pr_debug("failed to write feature section\n"); @@ -513,7 +512,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) pr_debug("failed to write perf header\n"); return err; } - lseek64(fd, self->data_offset + self->data_size, SEEK_SET); + lseek(fd, self->data_offset + self->data_size, SEEK_SET); self->frozen = 1; return 0; @@ -567,7 +566,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, sec_size = sizeof(*feat_sec) * nr_sections; - lseek64(fd, self->data_offset + self->data_size, SEEK_SET); + lseek(fd, self->data_offset + self->data_size, SEEK_SET); if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) goto out_free; @@ -641,7 +640,7 @@ static int perf_file_section__process(struct perf_file_section *self, struct perf_header *ph, int feat, int fd) { - if (lseek64(fd, self->offset, SEEK_SET) < 0) { + if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { pr_debug("Failed to lseek to %Ld offset for feature %d, " "continuing...\n", self->offset, feat); return 0; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 74cbc64a3a3c..0de7258e70a5 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,4 +1,3 @@ -#define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 #include @@ -15,7 +14,7 @@ static int perf_session__open(struct perf_session *self, bool force) { struct stat input_stat; - self->fd = open(self->filename, O_RDONLY|O_LARGEFILE); + self->fd = open(self->filename, O_RDONLY); if (self->fd < 0) { pr_err("failed to open file: %s", self->filename); if (!strcmp(self->filename, "perf.data")) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index ca3c26d466f3..7cd1193918c7 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -18,7 +18,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 #include #include @@ -83,7 +83,7 @@ static char *read_string(void) char *str = NULL; int size = 0; int i; - s64 r; + off_t r; for (;;) { r = read(input_fd, buf, BUFSIZ); @@ -117,8 +117,8 @@ static char *read_string(void) i++; /* move the file descriptor to the end of the string */ - r = lseek64(input_fd, -(r - i), SEEK_CUR); - if (r < 0) + r = lseek(input_fd, -(r - i), SEEK_CUR); + if (r == (off_t)-1) die("lseek"); if (str) { @@ -282,8 +282,8 @@ static void update_cpu_data_index(int cpu) static void get_next_page(int cpu) { - off64_t save_seek; - off64_t ret; + off_t save_seek; + off_t ret; if (!cpu_data[cpu].page) return; @@ -298,17 +298,17 @@ static void get_next_page(int cpu) update_cpu_data_index(cpu); /* other parts of the code may expect the pointer to not move */ - save_seek = lseek64(input_fd, 0, SEEK_CUR); + save_seek = lseek(input_fd, 0, SEEK_CUR); - ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); - if (ret < 0) + ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); + if (ret == (off_t)-1) die("failed to lseek"); ret = read(input_fd, cpu_data[cpu].page, page_size); if (ret < 0) die("failed to read page"); /* reset the file pointer back */ - lseek64(input_fd, save_seek, SEEK_SET); + lseek(input_fd, save_seek, SEEK_SET); return; } -- GitLab From 2161db969313cb94ffd9377a525fb75c3fee9eeb Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 4 Feb 2010 10:22:01 +0100 Subject: [PATCH 1604/3892] perf tools: Fix session init on non-modular kernels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit perf top and perf record refuses to initialize on non-modular kernels: refuse to initialize: $ perf top -v map_groups__set_modules_path_dir: cannot open /lib/modules/2.6.33-rc6-tip-00586-g398dde3-dirty/ Cc: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1265223128-11786-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a60ba2ba1044..6882e9fec2d6 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1937,7 +1937,7 @@ int map_groups__create_kernel_maps(struct map_groups *self, return -1; if (symbol_conf.use_modules && map_groups__create_modules(self) < 0) - return -1; + return 0; /* * Now that we have all the maps created, just set the ->end of them: */ -- GitLab From 04b5efe5fa7f71c37b938053666fac317b67c636 Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Thu, 4 Feb 2010 10:28:02 +0100 Subject: [PATCH 1605/3892] ALSA: hda - Fix docking output for IDT 92HD8xx codecs This patch fixes docking output support for IDT 92HD81/83/88 family codecs. Typically one of ports 0xE or 0xF is used for docking output, while only port 0xF is common on all the three codec families. We don't want the pin to select the analog mixer here. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 693dd14d9ec1..834c5980fe5d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5291,7 +5291,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; int err; int num_dacs; - hda_nid_t nid; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5387,24 +5386,21 @@ again: return err; } - switch (spec->board_config) { - case STAC_DELL_S14: - nid = 0xf; - break; - default: - nid = 0xe; - break; - } - - num_dacs = snd_hda_get_connections(codec, nid, + /* docking output support */ + num_dacs = snd_hda_get_connections(codec, 0xF, conn, STAC92HD83_DAC_COUNT + 1) - 1; - if (num_dacs < 0) - num_dacs = STAC92HD83_DAC_COUNT; - - /* set port X to select the last DAC - */ - snd_hda_codec_write_cache(codec, nid, 0, + /* skip non-DAC connections */ + while (num_dacs >= 0 && + (get_wcaps_type(get_wcaps(codec, conn[num_dacs])) + != AC_WID_AUD_OUT)) + num_dacs--; + /* set port E and F to select the last DAC */ + if (num_dacs >= 0) { + snd_hda_codec_write_cache(codec, 0xE, 0, + AC_VERB_SET_CONNECT_SEL, num_dacs); + snd_hda_codec_write_cache(codec, 0xF, 0, AC_VERB_SET_CONNECT_SEL, num_dacs); + } codec->proc_widget_hook = stac92hd_proc_hook; -- GitLab From a3032b47c46920ed3f2fd58e64f484e3dab49f23 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Feb 2010 18:48:03 +0000 Subject: [PATCH 1606/3892] ASoC: Add a cache_sync bit to the CODEC structure Add a bit to the CODEC structure indicating if a cache sync is required. By default this will be set if a cache only write is done to a soc-cache register cache. This allows us to avoid syncing the cache back after using cache only writes if there were no changes. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 1 + sound/soc/soc-cache.c | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4e8f14bc8ed3..e6a6d10de1d3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -424,6 +424,7 @@ struct snd_soc_codec { unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ unsigned int cache_only:1; /* Suppress writes to hardware */ + unsigned int cache_sync:1; /* Cache needs to be synced to hardware */ /* dapm */ u32 pop_time; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 84b6916db87d..5869dc3be781 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -39,8 +39,10 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; - if (codec->cache_only) + if (codec->cache_only) { + codec->cache_sync = 1; return 0; + } ret = codec->hw_write(codec->control_data, data, 2); if (ret == 2) @@ -105,8 +107,10 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; - if (codec->cache_only) + if (codec->cache_only) { + codec->cache_sync = 1; return 0; + } ret = codec->hw_write(codec->control_data, data, 2); if (ret == 2) @@ -161,8 +165,10 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; - if (codec->cache_only) + if (codec->cache_only) { + codec->cache_sync = 1; return 0; + } if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; @@ -192,8 +198,10 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, if (!snd_soc_codec_volatile_register(codec, reg)) reg_cache[reg] = value; - if (codec->cache_only) + if (codec->cache_only) { + codec->cache_sync = 1; return 0; + } if (codec->hw_write(codec->control_data, data, 3) == 3) return 0; @@ -313,8 +321,10 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, if (reg < codec->reg_cache_size) cache[reg] = value; - if (codec->cache_only) + if (codec->cache_only) { + codec->cache_sync = 1; return 0; + } ret = codec->hw_write(codec->control_data, data, 3); if (ret == 3) -- GitLab From 3bf6e4217e3c69438f6dc41a009664107eb27ab1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Feb 2010 19:05:09 +0000 Subject: [PATCH 1607/3892] ASoC: Convert WM8993 to use shared cache I/O code Saves a little bit of code duplication. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 152 +++++++++++--------------------------- 1 file changed, 43 insertions(+), 109 deletions(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 61239e0e9556..3c9336cd4eeb 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -231,34 +231,6 @@ struct wm8993_priv { int fll_src; }; -static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *i2c = codec->control_data; - - /* Write register */ - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret != 2) { - dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - static int wm8993_volatile(unsigned int reg) { switch (reg) { @@ -273,48 +245,6 @@ static int wm8993_volatile(unsigned int reg) } } -static unsigned int wm8993_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *reg_cache = codec->reg_cache; - - BUG_ON(reg > WM8993_MAX_REGISTER); - - if (wm8993_volatile(reg)) - return wm8993_read_hw(codec, reg); - else - return reg_cache[reg]; -} - -static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *reg_cache = codec->reg_cache; - u8 data[3]; - int ret; - - BUG_ON(reg > WM8993_MAX_REGISTER); - - /* data is - * D15..D9 WM8993 register offset - * D8...D0 register data - */ - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0x00ff; - - if (!wm8993_volatile(reg)) - reg_cache[reg] = value; - - ret = codec->hw_write(codec->control_data, data, 3); - - if (ret == 3) - return 0; - if (ret < 0) - return ret; - return -EIO; -} - struct _fll_div { u16 fll_fratio; u16 fll_outdiv; @@ -443,9 +373,9 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, wm8993->fll_fref = 0; wm8993->fll_fout = 0; - reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); + reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1); reg1 &= ~WM8993_FLL_ENA; - wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); return 0; } @@ -454,7 +384,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, if (ret != 0) return ret; - reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5); + reg5 = snd_soc_read(codec, WM8993_FLL_CONTROL_5); reg5 &= ~WM8993_FLL_CLK_SRC_MASK; switch (fll_id) { @@ -476,33 +406,33 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, /* Any FLL configuration change requires that the FLL be * disabled first. */ - reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); + reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1); reg1 &= ~WM8993_FLL_ENA; - wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); /* Apply the configuration */ if (fll_div.k) reg1 |= WM8993_FLL_FRAC_MASK; else reg1 &= ~WM8993_FLL_FRAC_MASK; - wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1); - wm8993_write(codec, WM8993_FLL_CONTROL_2, - (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) | - (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT)); - wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k); + snd_soc_write(codec, WM8993_FLL_CONTROL_2, + (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) | + (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT)); + snd_soc_write(codec, WM8993_FLL_CONTROL_3, fll_div.k); - reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4); + reg4 = snd_soc_read(codec, WM8993_FLL_CONTROL_4); reg4 &= ~WM8993_FLL_N_MASK; reg4 |= fll_div.n << WM8993_FLL_N_SHIFT; - wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4); + snd_soc_write(codec, WM8993_FLL_CONTROL_4, reg4); reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK; reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; - wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5); + snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5); /* Enable the FLL */ - wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); + snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); @@ -523,7 +453,7 @@ static int configure_clock(struct snd_soc_codec *codec) case WM8993_SYSCLK_MCLK: dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate); - reg = wm8993_read(codec, WM8993_CLOCKING_2); + reg = snd_soc_read(codec, WM8993_CLOCKING_2); reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); if (wm8993->mclk_rate > 13500000) { reg |= WM8993_MCLK_DIV; @@ -532,14 +462,14 @@ static int configure_clock(struct snd_soc_codec *codec) reg &= ~WM8993_MCLK_DIV; wm8993->sysclk_rate = wm8993->mclk_rate; } - wm8993_write(codec, WM8993_CLOCKING_2, reg); + snd_soc_write(codec, WM8993_CLOCKING_2, reg); break; case WM8993_SYSCLK_FLL: dev_dbg(codec->dev, "Using %dHz FLL clock\n", wm8993->fll_fout); - reg = wm8993_read(codec, WM8993_CLOCKING_2); + reg = snd_soc_read(codec, WM8993_CLOCKING_2); reg |= WM8993_SYSCLK_SRC; if (wm8993->fll_fout > 13500000) { reg |= WM8993_MCLK_DIV; @@ -548,7 +478,7 @@ static int configure_clock(struct snd_soc_codec *codec) reg &= ~WM8993_MCLK_DIV; wm8993->sysclk_rate = wm8993->fll_fout; } - wm8993_write(codec, WM8993_CLOCKING_2, reg); + snd_soc_write(codec, WM8993_CLOCKING_2, reg); break; default: @@ -1083,8 +1013,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, { struct snd_soc_codec *codec = dai->codec; struct wm8993_priv *wm8993 = codec->private_data; - unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); - unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); + unsigned int aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1); + unsigned int aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4); aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK); @@ -1167,8 +1097,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } - wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); - wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); + snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); + snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); return 0; } @@ -1182,16 +1112,16 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, int ret, i, best, best_val, cur_val; unsigned int clocking1, clocking3, aif1, aif4; - clocking1 = wm8993_read(codec, WM8993_CLOCKING_1); + clocking1 = snd_soc_read(codec, WM8993_CLOCKING_1); clocking1 &= ~WM8993_BCLK_DIV_MASK; - clocking3 = wm8993_read(codec, WM8993_CLOCKING_3); + clocking3 = snd_soc_read(codec, WM8993_CLOCKING_3); clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK); - aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); + aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1); aif1 &= ~WM8993_AIF_WL_MASK; - aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); + aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4); aif4 &= ~WM8993_LRCLK_RATE_MASK; /* What BCLK do we need? */ @@ -1284,14 +1214,14 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs); aif4 |= wm8993->bclk / wm8993->fs; - wm8993_write(codec, WM8993_CLOCKING_1, clocking1); - wm8993_write(codec, WM8993_CLOCKING_3, clocking3); - wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); - wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); + snd_soc_write(codec, WM8993_CLOCKING_1, clocking1); + snd_soc_write(codec, WM8993_CLOCKING_3, clocking3); + snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); + snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); /* ReTune Mobile? */ if (wm8993->pdata.num_retune_configs) { - u16 eq1 = wm8993_read(codec, WM8993_EQ1); + u16 eq1 = snd_soc_read(codec, WM8993_EQ1); struct wm8993_retune_mobile_setting *s; best = 0; @@ -1314,7 +1244,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0); for (i = 1; i < ARRAY_SIZE(s->config); i++) - wm8993_write(codec, WM8993_EQ1 + i, s->config[i]); + snd_soc_write(codec, WM8993_EQ1 + i, s->config[i]); snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1); } @@ -1327,14 +1257,14 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; - reg = wm8993_read(codec, WM8993_DAC_CTRL); + reg = snd_soc_read(codec, WM8993_DAC_CTRL); if (mute) reg |= WM8993_DAC_MUTE; else reg &= ~WM8993_DAC_MUTE; - wm8993_write(codec, WM8993_DAC_CTRL, reg); + snd_soc_write(codec, WM8993_DAC_CTRL, reg); return 0; } @@ -1586,9 +1516,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, INIT_LIST_HEAD(&codec->dapm_paths); codec->name = "WM8993"; - codec->read = wm8993_read; - codec->write = wm8993_write; - codec->hw_write = (hw_write_t)i2c_master_send; + codec->volatile_register = wm8993_volatile; codec->reg_cache = wm8993->reg_cache; codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache); codec->bias_level = SND_SOC_BIAS_OFF; @@ -1603,20 +1531,26 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, memcpy(wm8993->reg_cache, wm8993_reg_defaults, sizeof(wm8993->reg_cache)); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + i2c_set_clientdata(i2c, wm8993); codec->control_data = i2c; wm8993_codec = codec; codec->dev = &i2c->dev; - val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET); + val = snd_soc_read(codec, WM8993_SOFTWARE_RESET); if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { dev_err(codec->dev, "Invalid ID register value %x\n", val); ret = -EINVAL; goto err; } - ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff); + ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff); if (ret != 0) goto err; -- GitLab From b37e399bfc7fcb5b523e3e2e74686c8cc95c0cba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Feb 2010 11:51:42 +0000 Subject: [PATCH 1608/3892] ASoC: Initial WM8993 regulator API hookup At the minute the regulators are simply enabled for the entire lifetime of the device. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 41 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 3c9336cd4eeb..e97b3f45b24b 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,16 @@ #include "wm8993.h" #include "wm_hubs.h" +#define WM8993_NUM_SUPPLIES 6 +static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD1", + "AVDD2", + "CPVDD", + "SPKVDD", +}; + static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { 0x8993, /* R0 - Software Reset */ 0x0000, /* R1 - Power Management (1) */ @@ -215,6 +226,7 @@ static struct { struct wm8993_priv { struct wm_hubs_data hubs_data; u16 reg_cache[WM8993_REGISTER_COUNT]; + struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; struct wm8993_platform_data pdata; struct snd_soc_codec codec; int master; @@ -1496,6 +1508,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, struct snd_soc_codec *codec; unsigned int val; int ret; + int i; if (wm8993_codec) { dev_err(&i2c->dev, "A WM8993 is already registered\n"); @@ -1543,16 +1556,33 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; + for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) + wm8993->supplies[i].supply = wm8993_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + val = snd_soc_read(codec, WM8993_SOFTWARE_RESET); if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { dev_err(codec->dev, "Invalid ID register value %x\n", val); ret = -EINVAL; - goto err; + goto err_enable; } ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff); if (ret != 0) - goto err; + goto err_enable; /* By default we're using the output mixers */ wm8993->class_w_users = 2; @@ -1582,7 +1612,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); if (ret != 0) - goto err; + goto err_enable; wm8993_dai.dev = codec->dev; @@ -1596,6 +1626,10 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, err_bias: wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); err: wm8993_codec = NULL; kfree(wm8993); @@ -1610,6 +1644,7 @@ static int wm8993_i2c_remove(struct i2c_client *client) snd_soc_unregister_dai(&wm8993_dai); wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF); + regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); kfree(wm8993); return 0; -- GitLab From cf56f62746c3e2f70bfad3d6fd051427a0022368 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Feb 2010 17:55:55 +0000 Subject: [PATCH 1609/3892] ASoC: Disable WM8993 regulators when turning bias off While the regulators are disabled we cache all register writes. Currently we assume that the regulator disable actually takes effect, after the merge with the regulator tree in 2.6.34 the regulator API will be able to notify us if the power is actually removed (due to constraints or regulator sharing it may not be). Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 54 ++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index e97b3f45b24b..bf022f68b84f 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -923,10 +923,33 @@ static const struct snd_soc_dapm_route routes[] = { { "Right Headphone Mux", "DAC", "DACR" }, }; +static void wm8993_cache_restore(struct snd_soc_codec *codec) +{ + u16 *cache = codec->reg_cache; + int i; + + if (!codec->cache_sync) + return; + + /* Reenable hardware writes */ + codec->cache_only = 0; + + /* Restore the register settings */ + for (i = 1; i < WM8993_MAX_REGISTER; i++) { + if (cache[i] == wm8993_reg_defaults[i]) + continue; + snd_soc_write(codec, i, cache[i]); + } + + /* We're in sync again */ + codec->cache_sync = 0; +} + static int wm8993_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8993_priv *wm8993 = codec->private_data; + int ret; switch (level) { case SND_SOC_BIAS_ON: @@ -940,6 +963,13 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); + if (ret != 0) + return ret; + + wm8993_cache_restore(codec); + /* Tune DC servo configuration */ snd_soc_write(codec, 0x44, 3); snd_soc_write(codec, 0x56, 3); @@ -992,6 +1022,18 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, 0); + +#ifdef CONFIG_REGULATOR + /* Post 2.6.34 we will be able to get a callback when + * the regulators are disabled which we can use but + * for now just assume that the power will be cut if + * the regulator API is in use. + */ + codec->cache_sync = 1; +#endif + + regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); break; } @@ -1460,15 +1502,7 @@ static int wm8993_resume(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; struct wm8993_priv *wm8993 = codec->private_data; - u16 *cache = wm8993->reg_cache; - int i, ret; - - /* Restore the register settings */ - for (i = 1; i < WM8993_MAX_REGISTER; i++) { - if (cache[i] == wm8993_reg_defaults[i]) - continue; - snd_soc_write(codec, i, cache[i]); - } + int ret; wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1584,6 +1618,8 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, if (ret != 0) goto err_enable; + codec->cache_only = 1; + /* By default we're using the output mixers */ wm8993->class_w_users = 2; -- GitLab From c133421800d9d1dfec0c98de6c9da0a7a99e0573 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 26 Jan 2010 22:37:11 +0000 Subject: [PATCH 1610/3892] ASoC: Add support for BIAS_OFF when idle to WM8904 As well as disabling the biases of the CODEC the drop into BIAS_OFF will also disable all the regulators powering the CODEC, allowing even greater power savings on appropriately configured systems. Since the regulator API does not currently provide notification when regulators are disabled we assume that this always happens when we stop using the regulators. Once 2.6.34 is merged this code can be optimised to only sync the cache when power was actually removed. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8904.c | 52 +++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 992a7f23df5c..dc782c43a7cb 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2033,11 +2033,37 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static void wm8904_sync_cache(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = codec->private_data; + int i; + + if (!codec->cache_sync) + return; + + codec->cache_only = 0; + + /* Sync back cached values if they're different from the + * hardware default. + */ + for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { + if (!wm8904_access[i].writable) + continue; + + if (wm8904->reg_cache[i] == wm8904_reg[i]) + continue; + + snd_soc_write(codec, i, wm8904->reg_cache[i]); + } + + codec->cache_sync = 0; +} + static int wm8904_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8904_priv *wm8904 = codec->private_data; - int ret, i; + int ret; switch (level) { case SND_SOC_BIAS_ON: @@ -2065,18 +2091,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, return ret; } - /* Sync back cached values if they're - * different from the hardware default. - */ - for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) { - if (!wm8904_access[i].writable) - continue; - - if (wm8904->reg_cache[i] == wm8904_reg[i]) - continue; - - snd_soc_write(codec, i, wm8904->reg_cache[i]); - } + wm8904_sync_cache(codec); /* Enable bias */ snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, @@ -2112,6 +2127,15 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, WM8904_BIAS_ENA, 0); +#ifdef CONFIG_REGULATOR + /* Post 2.6.34 we will be able to get a callback when + * the regulators are disabled which we can use but + * for now just assume that the power will be cut if + * the regulator API is in use. + */ + codec->cache_sync = 1; +#endif + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); break; @@ -2365,6 +2389,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, codec->reg_cache_size = WM8904_MAX_REGISTER; codec->reg_cache = &wm8904->reg_cache; codec->volatile_register = wm8904_volatile_register; + codec->cache_sync = 1; + codec->idle_bias_off = 1; memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); -- GitLab From e4bc669610d75106a00b0f96f2410ac5898ef1ca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Feb 2010 19:51:33 +0000 Subject: [PATCH 1611/3892] ASoC: Optimise WM8904 output stage power control Handle the output PGAs as part of the output powerup since they can never be powered separately and reorder things so that we remove the output shorts after both line and headphone outputs have been brought up, minimising the opportunity for any issues. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8904.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index dc782c43a7cb..80dd8df0b864 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -979,6 +979,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, int dcs_l, dcs_r; int dcs_l_reg, dcs_r_reg; int timeout; + int pwr_reg; /* This code is shared between HP and LINEOUT; we do all our * power management in stereo pairs to avoid latency issues so @@ -988,6 +989,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, switch (reg) { case WM8904_ANALOGUE_HP_0: + pwr_reg = WM8904_POWER_MANAGEMENT_2; dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1; dcs_r_reg = WM8904_DC_SERVO_8; dcs_l_reg = WM8904_DC_SERVO_9; @@ -995,6 +997,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, dcs_r = 1; break; case WM8904_ANALOGUE_LINEOUT_0: + pwr_reg = WM8904_POWER_MANAGEMENT_3; dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3; dcs_r_reg = WM8904_DC_SERVO_6; dcs_l_reg = WM8904_DC_SERVO_7; @@ -1007,12 +1010,18 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, } switch (event) { - case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMU: + /* Power on the PGAs */ + snd_soc_update_bits(codec, pwr_reg, + WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA, + WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA); + /* Power on the amplifier */ snd_soc_update_bits(codec, reg, WM8904_HPL_ENA | WM8904_HPR_ENA, WM8904_HPL_ENA | WM8904_HPR_ENA); + /* Enable the first stage */ snd_soc_update_bits(codec, reg, WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY, @@ -1064,7 +1073,9 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, reg, WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP); + break; + case SND_SOC_DAPM_POST_PMU: /* Unshort the output itself */ snd_soc_update_bits(codec, reg, WM8904_HPL_RMV_SHORT | @@ -1079,7 +1090,9 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, reg, WM8904_HPL_RMV_SHORT | WM8904_HPR_RMV_SHORT, 0); + break; + case SND_SOC_DAPM_POST_PMD: /* Cache the DC servo configuration; this will be * invalidated if we change the configuration. */ wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg); @@ -1094,6 +1107,11 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY | WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, 0); + + /* PGAs too */ + snd_soc_update_bits(codec, pwr_reg, + WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA, + 0); break; } @@ -1212,18 +1230,20 @@ SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0), SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA("HPL PGA", WM8904_POWER_MANAGEMENT_2, 1, 0, NULL, 0), -SND_SOC_DAPM_PGA("HPR PGA", WM8904_POWER_MANAGEMENT_2, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("HPL PGA", SND_SOC_NOPM, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("HPR PGA", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINEL PGA", WM8904_POWER_MANAGEMENT_3, 1, 0, NULL, 0), -SND_SOC_DAPM_PGA("LINER PGA", WM8904_POWER_MANAGEMENT_3, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("LINEL PGA", SND_SOC_NOPM, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("LINER PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0, 0, NULL, 0, out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0, 0, NULL, 0, out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), -- GitLab From 8c1264740e7c9688c5d11b96d26e4393618ef60e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Feb 2010 19:33:49 +0000 Subject: [PATCH 1612/3892] ASoC: Add WM8912 DAC support The WM8912 is a DAC only device register compatible with the WM8904 CODEC with ADC portions omitted. Support it within the WM8904 driver based on the configured I2C device name. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8904.c | 90 +++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 80dd8df0b864..593e47d0e0eb 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -33,6 +33,11 @@ static struct snd_soc_codec *wm8904_codec; struct snd_soc_codec_device soc_codec_dev_wm8904; +enum wm8904_type { + WM8904, + WM8912, +}; + #define WM8904_NUM_DCS_CHANNELS 4 #define WM8904_NUM_SUPPLIES 5 @@ -49,6 +54,8 @@ struct wm8904_priv { struct snd_soc_codec codec; u16 reg_cache[WM8904_MAX_REGISTER + 1]; + enum wm8904_type devtype; + struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES]; struct wm8904_pdata *pdata; @@ -1411,30 +1418,62 @@ static const struct snd_soc_dapm_route wm8904_intercon[] = { { "LINER PGA", NULL, "LINER Mux" }, }; +static const struct snd_soc_dapm_route wm8912_intercon[] = { + { "HPL PGA", NULL, "DACL" }, + { "HPR PGA", NULL, "DACR" }, + + { "LINEL PGA", NULL, "DACL" }, + { "LINER PGA", NULL, "DACR" }, +}; + static int wm8904_add_widgets(struct snd_soc_codec *codec) { - snd_soc_add_controls(codec, wm8904_adc_snd_controls, - ARRAY_SIZE(wm8904_adc_snd_controls)); - snd_soc_add_controls(codec, wm8904_dac_snd_controls, - ARRAY_SIZE(wm8904_dac_snd_controls)); - snd_soc_add_controls(codec, wm8904_snd_controls, - ARRAY_SIZE(wm8904_snd_controls)); + struct wm8904_priv *wm8904 = codec->private_data; snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets, ARRAY_SIZE(wm8904_core_dapm_widgets)); - snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets, - ARRAY_SIZE(wm8904_adc_dapm_widgets)); - snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, - ARRAY_SIZE(wm8904_dac_dapm_widgets)); - snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets, - ARRAY_SIZE(wm8904_dapm_widgets)); - snd_soc_dapm_add_routes(codec, core_intercon, ARRAY_SIZE(core_intercon)); - snd_soc_dapm_add_routes(codec, adc_intercon, ARRAY_SIZE(adc_intercon)); - snd_soc_dapm_add_routes(codec, dac_intercon, ARRAY_SIZE(dac_intercon)); - snd_soc_dapm_add_routes(codec, wm8904_intercon, - ARRAY_SIZE(wm8904_intercon)); + + switch (wm8904->devtype) { + case WM8904: + snd_soc_add_controls(codec, wm8904_adc_snd_controls, + ARRAY_SIZE(wm8904_adc_snd_controls)); + snd_soc_add_controls(codec, wm8904_dac_snd_controls, + ARRAY_SIZE(wm8904_dac_snd_controls)); + snd_soc_add_controls(codec, wm8904_snd_controls, + ARRAY_SIZE(wm8904_snd_controls)); + + snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets, + ARRAY_SIZE(wm8904_adc_dapm_widgets)); + snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, + ARRAY_SIZE(wm8904_dac_dapm_widgets)); + snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets, + ARRAY_SIZE(wm8904_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, core_intercon, + ARRAY_SIZE(core_intercon)); + snd_soc_dapm_add_routes(codec, adc_intercon, + ARRAY_SIZE(adc_intercon)); + snd_soc_dapm_add_routes(codec, dac_intercon, + ARRAY_SIZE(dac_intercon)); + snd_soc_dapm_add_routes(codec, wm8904_intercon, + ARRAY_SIZE(wm8904_intercon)); + break; + + case WM8912: + snd_soc_add_controls(codec, wm8904_dac_snd_controls, + ARRAY_SIZE(wm8904_dac_snd_controls)); + + snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets, + ARRAY_SIZE(wm8904_dac_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, dac_intercon, + ARRAY_SIZE(dac_intercon)); + snd_soc_dapm_add_routes(codec, wm8912_intercon, + ARRAY_SIZE(wm8912_intercon)); + break; + } snd_soc_dapm_new_widgets(codec); return 0; @@ -2412,6 +2451,18 @@ static int wm8904_register(struct wm8904_priv *wm8904, codec->cache_sync = 1; codec->idle_bias_off = 1; + switch (wm8904->devtype) { + case WM8904: + break; + case WM8912: + memset(&wm8904_dai.capture, 0, sizeof(wm8904_dai.capture)); + break; + default: + dev_err(codec->dev, "Unknown device type %d\n", + wm8904->devtype); + return -EINVAL; + } + memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); @@ -2542,6 +2593,8 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, codec = &wm8904->codec; codec->hw_write = (hw_write_t)i2c_master_send; + wm8904->devtype = id->driver_data; + i2c_set_clientdata(i2c, wm8904); codec->control_data = i2c; wm8904->pdata = i2c->dev.platform_data; @@ -2559,7 +2612,8 @@ static __devexit int wm8904_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id wm8904_i2c_id[] = { - { "wm8904", 0 }, + { "wm8904", WM8904 }, + { "wm8912", WM8912 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); -- GitLab From cb67286d6629ecb5bfc44071d664cf1cbd01a350 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Feb 2010 09:10:10 +0200 Subject: [PATCH 1613/3892] ASoC: TWL4030: Module unloading fix The module unloading path had several problems: - it freed up the private structure twice - it freed up the codec structure, which was allocated as part of the private structure - it did not freed up the reg_cache - it did not unregistered the dais and the codec Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index e0106a5fd40b..b32aeb38e3a6 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2152,8 +2152,6 @@ static int twl4030_soc_remove(struct platform_device *pdev) twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - kfree(codec->private_data); - kfree(codec); return 0; } @@ -2237,6 +2235,9 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev) { struct twl4030_priv *twl4030 = platform_get_drvdata(pdev); + snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + snd_soc_unregister_codec(&twl4030->codec); + kfree(twl4030->codec.reg_cache); kfree(twl4030); twl4030_codec = NULL; -- GitLab From 88102f3f841b680412714d0b0b7da33c2a00c1f9 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 4 Feb 2010 14:12:58 +0100 Subject: [PATCH 1614/3892] ALSA: hda - Remove superfluous init verb entries for ALC88[235] The default values are no need to be set in init_verbs. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 75 ++++++----------------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2f543d3b833..40ebf2746bb1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7332,29 +7332,18 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = { static struct hda_verb alc882_base_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute analog input loopbacks */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -7391,14 +7380,8 @@ static struct hda_verb alc882_base_init_verbs[] = { /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer2 */ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer3 */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* ADC2: mute amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -7442,26 +7425,17 @@ static struct hda_verb alc_hp15_unsol_verbs[] = { static struct hda_verb alc885_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* mute analog input loopbacks */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Front HP Pin: output 0 (0x0c) */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -7495,17 +7469,11 @@ static struct hda_verb alc885_init_verbs[] = { /* Mixer elements: 0x18, , 0x1a, 0x1b */ /* Input mixer1 */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Input mixer2 */ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* ADC2: mute amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* ADC3: mute amp left and right */ @@ -7991,18 +7959,6 @@ static struct hda_verb alc883_auto_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* * Set up output mixers (0x0c - 0x0f) */ @@ -8027,16 +7983,9 @@ static struct hda_verb alc883_auto_init_verbs[] = { /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; -- GitLab From 84898e87cc0fff976202d5b91656f2db949fc2dd Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 4 Feb 2010 14:16:14 +0100 Subject: [PATCH 1615/3892] ALSA: hda - Add ALC269VB support - Add new models ALC269VB_AMIC ALC269VB_DMIC - Add alc269vb_laptop_dmic_setup The record source index Dmic is 0x6 for ALC269VB. - Change eeepc words for ALC269 - Modify init_verb tables of patch_alc269 patch_alc662 patch_alc882 - Modify common patch for ALC270 ALC269VB ALC275 Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 346 ++++++++++++++++++++++++---------- 1 file changed, 246 insertions(+), 100 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 40ebf2746bb1..826ecdbdd2bb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -131,8 +131,10 @@ enum { enum { ALC269_BASIC, ALC269_QUANTA_FL1, - ALC269_ASUS_AMIC, - ALC269_ASUS_DMIC, + ALC269_AMIC, + ALC269_DMIC, + ALC269VB_AMIC, + ALC269VB_DMIC, ALC269_FUJITSU, ALC269_LIFEBOOK, ALC269_AUTO, @@ -13182,6 +13184,15 @@ static hda_nid_t alc269_capsrc_nids[1] = { 0x23, }; +static hda_nid_t alc269vb_adc_nids[1] = { + /* ADC1 */ + 0x09, +}; + +static hda_nid_t alc269vb_capsrc_nids[1] = { + 0x22, +}; + /* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24), * not a mux! */ @@ -13250,7 +13261,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_eeepc_mixer[] = { +static struct snd_kcontrol_new alc269_laptop_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -13258,16 +13269,47 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + /* capture mixer elements */ -static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { +static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), { } /* end */ }; /* FSC amilo */ -#define alc269_fujitsu_mixer alc269_eeepc_mixer +#define alc269_fujitsu_mixer alc269_laptop_mixer static struct hda_verb alc269_quanta_fl1_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, @@ -13410,7 +13452,7 @@ static void alc269_lifebook_init_hook(struct hda_codec *codec) alc269_lifebook_mic_autoswitch(codec); } -static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { +static struct hda_verb alc269_laptop_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -13421,7 +13463,7 @@ static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { {} }; -static struct hda_verb alc269_eeepc_amic_init_verbs[] = { +static struct hda_verb alc269_laptop_amic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -13431,6 +13473,28 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = { {} }; +static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + /* toggle speaker-output according to the hp-jack state */ static void alc269_speaker_automute(struct hda_codec *codec) { @@ -13448,7 +13512,7 @@ static void alc269_speaker_automute(struct hda_codec *codec) } /* unsolicited event for HP jack sensing */ -static void alc269_eeepc_unsol_event(struct hda_codec *codec, +static void alc269_laptop_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { @@ -13461,7 +13525,7 @@ static void alc269_eeepc_unsol_event(struct hda_codec *codec, } } -static void alc269_eeepc_dmic_setup(struct hda_codec *codec) +static void alc269_laptop_dmic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->ext_mic.pin = 0x18; @@ -13471,7 +13535,17 @@ static void alc269_eeepc_dmic_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc269_eeepc_amic_setup(struct hda_codec *codec) +static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + +static void alc269_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->ext_mic.pin = 0x18; @@ -13481,7 +13555,7 @@ static void alc269_eeepc_amic_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc269_eeepc_inithook(struct hda_codec *codec) +static void alc269_laptop_inithook(struct hda_codec *codec) { alc269_speaker_automute(codec); alc_mic_automute(codec); @@ -13494,22 +13568,10 @@ static struct hda_verb alc269_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the - * analog-loopback mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* - * Set up output mixers (0x0c - 0x0e) + * Set up output mixers (0x02 - 0x03) */ /* set vol=0 to output mixers */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -13534,26 +13596,57 @@ static struct hda_verb alc269_init_verbs[] = { {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* FIXME: use matrix-type input source selection */ + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static struct hda_verb alc269vb_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set EAPD */ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; @@ -13601,6 +13694,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int err; static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; + hda_nid_t real_capsrc_nids; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc269_ignore); @@ -13622,11 +13716,20 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (spec->kctls.list) add_mixer(spec, spec->kctls.list); - add_verb(spec, alc269_init_verbs); + if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) { + add_verb(spec, alc269vb_init_verbs); + real_capsrc_nids = alc269vb_capsrc_nids[0]; + alc_ssid_check(codec, 0x21, 0x1b, 0x14); + } else { + add_verb(spec, alc269_init_verbs); + real_capsrc_nids = alc269_capsrc_nids[0]; + alc_ssid_check(codec, 0x15, 0x1b, 0x14); + } + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; /* set default input source */ - snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0], + snd_hda_codec_write_cache(codec, real_capsrc_nids, 0, AC_VERB_SET_CONNECT_SEL, spec->input_mux->items[0].index); @@ -13637,8 +13740,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(codec); - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -13664,8 +13765,8 @@ static void alc269_auto_init(struct hda_codec *codec) static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", - [ALC269_ASUS_AMIC] = "asus-amic", - [ALC269_ASUS_DMIC] = "asus-dmic", + [ALC269_AMIC] = "laptop-amic", + [ALC269_DMIC] = "laptop-dmic", [ALC269_FUJITSU] = "fujitsu", [ALC269_LIFEBOOK] = "lifebook", [ALC269_AUTO] = "auto", @@ -13674,41 +13775,49 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { static struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC), + ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", - ALC269_ASUS_DMIC), + ALC269_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", - ALC269_ASUS_DMIC), - SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC), - SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC), + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), {} @@ -13738,47 +13847,75 @@ static struct alc_config_preset alc269_presets[] = { .setup = alc269_quanta_fl1_setup, .init_hook = alc269_quanta_fl1_init_hook, }, - [ALC269_ASUS_AMIC] = { - .mixers = { alc269_eeepc_mixer }, - .cap_mixer = alc269_epc_capture_mixer, + [ALC269_AMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_analog_capture_mixer, .init_verbs = { alc269_init_verbs, - alc269_eeepc_amic_init_verbs }, + alc269_laptop_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_amic_setup, - .init_hook = alc269_eeepc_inithook, + .unsol_event = alc269_laptop_unsol_event, + .setup = alc269_laptop_amic_setup, + .init_hook = alc269_laptop_inithook, }, - [ALC269_ASUS_DMIC] = { - .mixers = { alc269_eeepc_mixer }, - .cap_mixer = alc269_epc_capture_mixer, + [ALC269_DMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, .init_verbs = { alc269_init_verbs, - alc269_eeepc_dmic_init_verbs }, + alc269_laptop_dmic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_dmic_setup, - .init_hook = alc269_eeepc_inithook, + .unsol_event = alc269_laptop_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc269_laptop_inithook, + }, + [ALC269VB_AMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_analog_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc269_laptop_unsol_event, + .setup = alc269_laptop_amic_setup, + .init_hook = alc269_laptop_inithook, + }, + [ALC269VB_DMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc269_laptop_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc269_laptop_inithook, }, [ALC269_FUJITSU] = { .mixers = { alc269_fujitsu_mixer }, - .cap_mixer = alc269_epc_capture_mixer, + .cap_mixer = alc269_laptop_digital_capture_mixer, .init_verbs = { alc269_init_verbs, - alc269_eeepc_dmic_init_verbs }, + alc269_laptop_dmic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_dmic_setup, - .init_hook = alc269_eeepc_inithook, + .unsol_event = alc269_laptop_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc269_laptop_inithook, }, [ALC269_LIFEBOOK] = { .mixers = { alc269_lifebook_mixer }, @@ -13799,6 +13936,7 @@ static int patch_alc269(struct hda_codec *codec) struct alc_spec *spec; int board_config; int err; + int is_alc269vb = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -13815,6 +13953,7 @@ static int patch_alc269(struct hda_codec *codec) alc_free(codec); return -ENOMEM; } + is_alc269vb = 1; } board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, @@ -13850,7 +13989,7 @@ static int patch_alc269(struct hda_codec *codec) if (board_config != ALC269_AUTO) setup_preset(codec, &alc269_presets[board_config]); - if (codec->subsystem_id == 0x17aa3bf8) { + if (board_config == ALC269_QUANTA_FL1) { /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz */ @@ -13863,9 +14002,16 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture; - spec->adc_nids = alc269_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); - spec->capsrc_nids = alc269_capsrc_nids; + if (!is_alc269vb) { + spec->adc_nids = alc269_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; + } else { + spec->adc_nids = alc269vb_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); + spec->capsrc_nids = alc269vb_capsrc_nids; + } + if (!spec->cap_mixer) set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); -- GitLab From cec27c891b805b2ab2302f9fcbdacb6f179ac0d4 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 4 Feb 2010 14:18:18 +0100 Subject: [PATCH 1616/3892] ALSA: hda - Add support of ALC665 - Add support for ALC665 - Add more ASUS model - Modify common patch for ALC272 ALC273 ALC661 ALC662 ALC663 ALC665 Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 112 +++++++++++++--------------------- 1 file changed, 44 insertions(+), 68 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 826ecdbdd2bb..82772f0ab3e7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16597,13 +16597,6 @@ static struct hda_verb alc662_init_verbs[] = { /* ADC: mute amp left and right */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -16653,6 +16646,28 @@ static struct hda_verb alc662_init_verbs[] = { { } }; +static struct hda_verb alc663_init_verbs[] = { + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } +}; + +static struct hda_verb alc272_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } +}; + static struct hda_verb alc662_sue_init_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, @@ -16672,61 +16687,6 @@ static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { {} }; -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc662_auto_init_verbs[] = { - /* - * Unmute ADC and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { } -}; - -/* additional verbs for ALC663 */ -static struct hda_verb alc663_auto_init_verbs[] = { - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } -}; - static struct hda_verb alc663_m51va_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -17477,6 +17437,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), @@ -17512,6 +17473,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), @@ -18157,9 +18119,13 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - add_verb(spec, alc662_auto_init_verbs); - if (codec->vendor_id == 0x10ec0663) - add_verb(spec, alc663_auto_init_verbs); + add_verb(spec, alc662_init_verbs); + if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || + codec->vendor_id == 0x10ec0665) + add_verb(spec, alc663_init_verbs); + + if (codec->vendor_id == 0x10ec0272) + add_verb(spec, alc272_init_verbs); err = alc_auto_add_mic_boost(codec); if (err < 0) @@ -18251,11 +18217,20 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->cap_mixer) set_capture_mixer(codec); - if (codec->vendor_id == 0x10ec0662) + + switch (codec->vendor_id) { + case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - else + break; + case 0x10ec0272: + case 0x10ec0663: + case 0x10ec0665: set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - + break; + case 0x10ec0273: + set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); + break; + } spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; @@ -18305,6 +18280,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, + { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, -- GitLab From ae06b8330aefb0338017c427d5694fc8ea9144c8 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 4 Feb 2010 09:21:28 -0800 Subject: [PATCH 1617/3892] can: ems_usb: removed duplicated code setting local echo support Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller --- drivers/net/can/usb/ems_usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index bfab283ba9b1..11c87840cc00 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1024,8 +1024,6 @@ static int ems_usb_probe(struct usb_interface *intf, dev->can.do_set_mode = ems_usb_set_mode; dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; - netdev->flags |= IFF_ECHO; /* we support local echo */ - netdev->netdev_ops = &ems_usb_netdev_ops; netdev->flags |= IFF_ECHO; /* we support local echo */ -- GitLab From 1b924032533033a4dae1a239981677bdae21949b Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Thu, 4 Feb 2010 09:33:21 -0800 Subject: [PATCH 1618/3892] stmmac: fix 'lenght' typo in comments and code Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/common.h | 2 +- drivers/net/stmmac/dwmac100.c | 2 +- drivers/net/stmmac/dwmac1000_dma.c | 4 ++-- drivers/net/stmmac/stmmac_ethtool.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h index 7267bcd43d06..2a58172e986a 100644 --- a/drivers/net/stmmac/common.h +++ b/drivers/net/stmmac/common.h @@ -44,7 +44,7 @@ struct stmmac_extra_stats { unsigned long rx_toolong; unsigned long rx_collision; unsigned long rx_crc; - unsigned long rx_lenght; + unsigned long rx_length; unsigned long rx_mii; unsigned long rx_multicast; unsigned long rx_gmac_overflow; diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c index 82dde774d4c5..ac48ed787040 100644 --- a/drivers/net/stmmac/dwmac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -265,7 +265,7 @@ static int dwmac100_get_rx_frame_status(void *data, ret = discard_frame; if (unlikely(p->des01.rx.length_error)) { - x->rx_lenght++; + x->rx_length++; ret = discard_frame; } if (unlikely(p->des01.rx.mii_error)) { diff --git a/drivers/net/stmmac/dwmac1000_dma.c b/drivers/net/stmmac/dwmac1000_dma.c index 68245508e2de..39d436a2da68 100644 --- a/drivers/net/stmmac/dwmac1000_dma.c +++ b/drivers/net/stmmac/dwmac1000_dma.c @@ -230,7 +230,7 @@ static int dwmac1000_coe_rdes0(int ipc_err, int type, int payload_err) /* bits 5 7 0 | Frame status * ---------------------------------------------------------- - * 0 0 0 | IEEE 802.3 Type frame (lenght < 1536 octects) + * 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects) * 1 0 0 | IPv4/6 No CSUM errorS. * 1 0 1 | IPv4/6 CSUM PAYLOAD error * 1 1 0 | IPv4/6 CSUM IP HR error @@ -331,7 +331,7 @@ static int dwmac1000_get_rx_frame_status(void *data, } if (unlikely(p->des01.erx.length_error)) { DBG(KERN_ERR "GMAC RX: length_error error\n"); - x->rx_lenght++; + x->rx_length++; ret = discard_frame; } #ifdef STMMAC_VLAN_TAG_USED diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 0abeff6193a1..c021eaa3ca69 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -62,7 +62,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { STMMAC_STAT(rx_toolong), STMMAC_STAT(rx_collision), STMMAC_STAT(rx_crc), - STMMAC_STAT(rx_lenght), + STMMAC_STAT(rx_length), STMMAC_STAT(rx_mii), STMMAC_STAT(rx_multicast), STMMAC_STAT(rx_gmac_overflow), -- GitLab From c2c3489c5b0fdb8fbf0f5e9424905c2994ab5660 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 4 Feb 2010 13:36:24 -0200 Subject: [PATCH 1619/3892] HID: use multi input quirk for TouchPack touchscreen This device generates ABS_Z and ABS_RX events, while it should be generating ABS_X and ABS_Y instead. Using the MULTI_INPUT quirk solves this issue. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Oliveira Nascimento [jkosina@suse.cz: fixed blacklist ordering while resolving conflict] [jkosina@suse.cz: fixed typo to make it compile] Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b29d9da799f4..282bfe8d95e8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -424,6 +424,9 @@ #define USB_VENDOR_ID_THRUSTMASTER 0x044f +#define USB_VENDOR_ID_TOUCHPACK 0x1bfd +#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 + #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 88a1c693fdcc..7844280897d1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -46,7 +46,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, @@ -59,6 +59,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, -- GitLab From 8e58ed34d926d89969796a0832ab38381a4c90ed Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Feb 2010 12:50:58 +0100 Subject: [PATCH 1620/3892] ARM: 5915/1: Add RTC PL031 derivative platform config for ux500 This configures the PL031 RTC resources for ux500. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-ux500/board-mop500.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index aa5afbcc90f9..f33dbb7b497b 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -108,11 +108,24 @@ static struct amba_device pl022_device = { .periphid = SSP_PER_ID, }; +static struct amba_device pl031_device = { + .dev = { + .init_name = "pl031", + }, + .res = { + .start = U8500_RTC_BASE, + .end = U8500_RTC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_RTC_RTT, NO_IRQ}, +}; + static struct amba_device *amba_devs[] __initdata = { &uart0_device, &uart1_device, &uart2_device, &pl022_device, + &pl031_device, }; static void __init u8500_timer_init(void) -- GitLab From e208c447bd728920e4f3d438a706344ea31249b9 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Mon, 1 Feb 2010 14:58:22 +0100 Subject: [PATCH 1621/3892] ARM: 5908/1: nomadik: add platform specific i2c configuration This adds the platform specific i2c configuration data structures to setup the nomadik/ux500 i2c block. Signed-off-by: srinidhi kasagar Signed-off-by: Russell King --- arch/arm/plat-nomadik/include/plat/i2c.h | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 arch/arm/plat-nomadik/include/plat/i2c.h diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h new file mode 100644 index 000000000000..1621db67a53d --- /dev/null +++ b/arch/arm/plat-nomadik/include/plat/i2c.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 ST-Ericsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#ifndef __PLAT_I2C_H +#define __PLAT_I2C_H + +enum i2c_freq_mode { + I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ + I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ + I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ + I2C_FREQ_MODE_HIGH_SPEED /* up to 3.4 Mb/s */ +}; + +/** + * struct nmk_i2c_controller - client specific controller configuration + * @clk_freq: clock frequency for the operation mode + * @slsu: Slave data setup time in ns. + * The needed setup time for three modes of operation + * are 250ns, 100ns and 10ns respectively thus leading + * to the values of 14, 6, 2 for a 48 MHz i2c clk + * @tft: Tx FIFO Threshold in bytes + * @rft: Rx FIFO Threshold in bytes + * @sm: speed mode + */ +struct nmk_i2c_controller { + unsigned long clk_freq; + unsigned short slsu; + unsigned char tft; + unsigned char rft; + enum i2c_freq_mode sm; +}; + +#endif /* __PLAT_I2C_H */ -- GitLab From d48a41c181c8abdb8b09f746e02839c6161dc3ea Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Wed, 3 Feb 2010 13:02:48 +0100 Subject: [PATCH 1622/3892] ARM: 5913/1: ARM U8500: add I2C platform configurations This adds platform configurations to support four i2c controllers found on early MOP500 platform This depends on the patch 5908/1 for build to succeed. Signed-off-by: Srinidhi Kasagar Signed-off-by: Russell King --- arch/arm/mach-ux500/board-mop500.c | 75 ++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index f33dbb7b497b..803aec1d6728 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -120,6 +121,70 @@ static struct amba_device pl031_device = { .irq = {IRQ_RTC_RTT, NO_IRQ}, }; +#define U8500_I2C_RESOURCES(id, size) \ +static struct resource u8500_i2c_resources_##id[] = { \ + [0] = { \ + .start = U8500_I2C##id##_BASE, \ + .end = U8500_I2C##id##_BASE + size - 1, \ + .flags = IORESOURCE_MEM, \ + }, \ + [1] = { \ + .start = IRQ_I2C##id, \ + .end = IRQ_I2C##id, \ + .flags = IORESOURCE_IRQ \ + } \ +} + +U8500_I2C_RESOURCES(0, SZ_4K); +U8500_I2C_RESOURCES(1, SZ_4K); +U8500_I2C_RESOURCES(2, SZ_4K); +U8500_I2C_RESOURCES(3, SZ_4K); + +#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ +static struct nmk_i2c_controller u8500_i2c_##id = { \ + /* \ + * slave data setup time, which is \ + * 250 ns,100ns,10ns which is 14,6,2 \ + * respectively for a 48 Mhz \ + * i2c clock \ + */ \ + .slsu = _slsu, \ + /* Tx FIFO threshold */ \ + .tft = _tft, \ + /* Rx FIFO threshold */ \ + .rft = _rft, \ + /* std. mode operation */ \ + .clk_freq = clk, \ + .sm = _sm, \ +} + +/* + * The board uses 4 i2c controllers, initialize all of + * them with slave data setup time of 250 ns, + * Tx & Rx FIFO threshold values as 1 and standard + * mode of operation + */ +U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); +U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); +U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); +U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); + +#define U8500_I2C_PDEVICE(cid) \ +static struct platform_device i2c_controller##cid = { \ + .name = "nmk-i2c", \ + .id = cid, \ + .num_resources = 2, \ + .resource = u8500_i2c_resources_##cid, \ + .dev = { \ + .platform_data = &u8500_i2c_##cid \ + } \ +} + +U8500_I2C_PDEVICE(0); +U8500_I2C_PDEVICE(1); +U8500_I2C_PDEVICE(2); +U8500_I2C_PDEVICE(3); + static struct amba_device *amba_devs[] __initdata = { &uart0_device, &uart1_device, @@ -128,6 +193,14 @@ static struct amba_device *amba_devs[] __initdata = { &pl031_device, }; +/* add any platform devices here - TODO */ +static struct platform_device *platform_devs[] __initdata = { + &i2c_controller0, + &i2c_controller1, + &i2c_controller2, + &i2c_controller3, +}; + static void __init u8500_timer_init(void) { #ifdef CONFIG_LOCAL_TIMERS @@ -152,6 +225,8 @@ static void __init u8500_init_machine(void) for (i = 0; i < ARRAY_SIZE(amba_devs); i++) amba_device_register(amba_devs[i], &iomem_resource); + platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); + spi_register_board_info(u8500_spi_devices, ARRAY_SIZE(u8500_spi_devices)); -- GitLab From c72881e8377ca713427486add16fc63256f0231b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Feb 2010 12:50:13 +0100 Subject: [PATCH 1623/3892] ARM: 5914/1: Modify PL031 for Nomadik and U8500 v2 This extends the existing PrimeCell PL031 driver with support for the ST Microelectronics and ST-Ericsson derivatives, in a first and second version as used on the Nomadik and U8500 platforms. It also rids the old ioctl() alarm on/off functions in favor of the new .alarm_irq_enable field of the RTC class ops. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/rtc/rtc-pl031.c | 365 +++++++++++++++++++++++++++++++++++----- 1 file changed, 327 insertions(+), 38 deletions(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 0264b117893b..c256aacfa954 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -7,6 +7,9 @@ * * Copyright 2006 (c) MontaVista Software, Inc. * + * Author: Mian Yousaf Kaukab + * Copyright 2010 (c) ST-Ericsson AB + * * 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 @@ -18,6 +21,9 @@ #include #include #include +#include +#include +#include /* * Register definitions @@ -30,35 +36,207 @@ #define RTC_RIS 0x14 /* Raw interrupt status register */ #define RTC_MIS 0x18 /* Masked interrupt status register */ #define RTC_ICR 0x1c /* Interrupt clear register */ +/* ST variants have additional timer functionality */ +#define RTC_TDR 0x20 /* Timer data read register */ +#define RTC_TLR 0x24 /* Timer data load register */ +#define RTC_TCR 0x28 /* Timer control register */ +#define RTC_YDR 0x30 /* Year data read register */ +#define RTC_YMR 0x34 /* Year match register */ +#define RTC_YLR 0x38 /* Year data load register */ + +#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */ + +#define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */ + +/* Common bit definitions for Interrupt status and control registers */ +#define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */ +#define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */ + +/* Common bit definations for ST v2 for reading/writing time */ +#define RTC_SEC_SHIFT 0 +#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */ +#define RTC_MIN_SHIFT 6 +#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */ +#define RTC_HOUR_SHIFT 12 +#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */ +#define RTC_WDAY_SHIFT 17 +#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */ +#define RTC_MDAY_SHIFT 20 +#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */ +#define RTC_MON_SHIFT 25 +#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */ + +#define RTC_TIMER_FREQ 32768 struct pl031_local { struct rtc_device *rtc; void __iomem *base; + u8 hw_designer; + u8 hw_revision:4; }; -static irqreturn_t pl031_interrupt(int irq, void *dev_id) +static int pl031_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct pl031_local *ldata = dev_get_drvdata(dev); + unsigned long imsc; + + /* Clear any pending alarm interrupts. */ + writel(RTC_BIT_AI, ldata->base + RTC_ICR); + + imsc = readl(ldata->base + RTC_IMSC); + + if (enabled == 1) + writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC); + else + writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC); + + return 0; +} + +/* + * Convert Gregorian date to ST v2 RTC format. + */ +static int pl031_stv2_tm_to_time(struct device *dev, + struct rtc_time *tm, unsigned long *st_time, + unsigned long *bcd_year) +{ + int year = tm->tm_year + 1900; + int wday = tm->tm_wday; + + /* wday masking is not working in hardware so wday must be valid */ + if (wday < -1 || wday > 6) { + dev_err(dev, "invalid wday value %d\n", tm->tm_wday); + return -EINVAL; + } else if (wday == -1) { + /* wday is not provided, calculate it here */ + unsigned long time; + struct rtc_time calc_tm; + + rtc_tm_to_time(tm, &time); + rtc_time_to_tm(time, &calc_tm); + wday = calc_tm.tm_wday; + } + + *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8); + + *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT) + | (tm->tm_mday << RTC_MDAY_SHIFT) + | ((wday + 1) << RTC_WDAY_SHIFT) + | (tm->tm_hour << RTC_HOUR_SHIFT) + | (tm->tm_min << RTC_MIN_SHIFT) + | (tm->tm_sec << RTC_SEC_SHIFT); + + return 0; +} + +/* + * Convert ST v2 RTC format to Gregorian date. + */ +static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year, + struct rtc_time *tm) +{ + tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100); + tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1; + tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT); + tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1; + tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT); + tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT); + tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT); + + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); + tm->tm_year -= 1900; + + return 0; +} + +static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pl031_local *ldata = dev_get_drvdata(dev); + + pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR), + readl(ldata->base + RTC_YDR), tm); + + return 0; +} + +static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long time; + unsigned long bcd_year; + struct pl031_local *ldata = dev_get_drvdata(dev); + int ret; + + ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year); + if (ret == 0) { + writel(bcd_year, ldata->base + RTC_YLR); + writel(time, ldata->base + RTC_LR); + } + + return ret; +} + +static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct rtc_device *rtc = dev_id; + struct pl031_local *ldata = dev_get_drvdata(dev); + int ret; - rtc_update_irq(rtc, 1, RTC_AF); + ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR), + readl(ldata->base + RTC_YMR), &alarm->time); - return IRQ_HANDLED; + alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI; + alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI; + + return ret; } -static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct pl031_local *ldata = dev_get_drvdata(dev); + unsigned long time; + unsigned long bcd_year; + int ret; + + /* At the moment, we can only deal with non-wildcarded alarm times. */ + ret = rtc_valid_tm(&alarm->time); + if (ret == 0) { + ret = pl031_stv2_tm_to_time(dev, &alarm->time, + &time, &bcd_year); + if (ret == 0) { + writel(bcd_year, ldata->base + RTC_YMR); + writel(time, ldata->base + RTC_MR); + + pl031_alarm_irq_enable(dev, alarm->enabled); + } + } + + return ret; +} + +static irqreturn_t pl031_interrupt(int irq, void *dev_id) +{ + struct pl031_local *ldata = dev_id; + unsigned long rtcmis; + unsigned long events = 0; + + rtcmis = readl(ldata->base + RTC_MIS); + if (rtcmis) { + writel(rtcmis, ldata->base + RTC_ICR); + + if (rtcmis & RTC_BIT_AI) + events |= (RTC_AF | RTC_IRQF); + + /* Timer interrupt is only available in ST variants */ + if ((rtcmis & RTC_BIT_PI) && + (ldata->hw_designer == AMBA_VENDOR_ST)) + events |= (RTC_PF | RTC_IRQF); + + rtc_update_irq(ldata->rtc, 1, events); - switch (cmd) { - case RTC_AIE_OFF: - writel(1, ldata->base + RTC_MIS); - return 0; - case RTC_AIE_ON: - writel(0, ldata->base + RTC_MIS); - return 0; + return IRQ_HANDLED; } - return -ENOIOCTLCMD; + return IRQ_NONE; } static int pl031_read_time(struct device *dev, struct rtc_time *tm) @@ -74,11 +252,14 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm) { unsigned long time; struct pl031_local *ldata = dev_get_drvdata(dev); + int ret; - rtc_tm_to_time(tm, &time); - writel(time, ldata->base + RTC_LR); + ret = rtc_tm_to_time(tm, &time); - return 0; + if (ret == 0) + writel(time, ldata->base + RTC_LR); + + return ret; } static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) @@ -86,8 +267,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); + + alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI; + alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI; return 0; } @@ -96,22 +278,71 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct pl031_local *ldata = dev_get_drvdata(dev); unsigned long time; + int ret; + + /* At the moment, we can only deal with non-wildcarded alarm times. */ + ret = rtc_valid_tm(&alarm->time); + if (ret == 0) { + ret = rtc_tm_to_time(&alarm->time, &time); + if (ret == 0) { + writel(time, ldata->base + RTC_MR); + pl031_alarm_irq_enable(dev, alarm->enabled); + } + } + + return ret; +} + +/* Periodic interrupt is only available in ST variants. */ +static int pl031_irq_set_state(struct device *dev, int enabled) +{ + struct pl031_local *ldata = dev_get_drvdata(dev); + + if (enabled == 1) { + /* Clear any pending timer interrupt. */ + writel(RTC_BIT_PI, ldata->base + RTC_ICR); + + writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI, + ldata->base + RTC_IMSC); - rtc_tm_to_time(&alarm->time, &time); + /* Now start the timer */ + writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN, + ldata->base + RTC_TCR); - writel(time, ldata->base + RTC_MR); - writel(!alarm->enabled, ldata->base + RTC_MIS); + } else { + writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI), + ldata->base + RTC_IMSC); + + /* Also stop the timer */ + writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN), + ldata->base + RTC_TCR); + } + /* Wait at least 1 RTC32 clock cycle to ensure next access + * to RTC_TCR will succeed. + */ + udelay(40); return 0; } -static const struct rtc_class_ops pl031_ops = { - .ioctl = pl031_ioctl, - .read_time = pl031_read_time, - .set_time = pl031_set_time, - .read_alarm = pl031_read_alarm, - .set_alarm = pl031_set_alarm, -}; +static int pl031_irq_set_freq(struct device *dev, int freq) +{ + struct pl031_local *ldata = dev_get_drvdata(dev); + + /* Cant set timer if it is already enabled */ + if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) { + dev_err(dev, "can't change frequency while timer enabled\n"); + return -EINVAL; + } + + /* If self start bit in RTC_TCR is set timer will start here, + * but we never set that bit. Instead we start the timer when + * set_state is called with enabled == 1. + */ + writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR); + + return 0; +} static int pl031_remove(struct amba_device *adev) { @@ -131,18 +362,20 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id) { int ret; struct pl031_local *ldata; + struct rtc_class_ops *ops = id->data; ret = amba_request_regions(adev, NULL); if (ret) goto err_req; - ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL); + ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL); if (!ldata) { ret = -ENOMEM; goto out; } ldata->base = ioremap(adev->res.start, resource_size(&adev->res)); + if (!ldata->base) { ret = -ENOMEM; goto out_no_remap; @@ -150,24 +383,36 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id) amba_set_drvdata(adev, ldata); - if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED, - "rtc-pl031", ldata->rtc)) { - ret = -EIO; - goto out_no_irq; - } + ldata->hw_designer = amba_manf(adev); + ldata->hw_revision = amba_rev(adev); + + dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer); + dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision); - ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops, - THIS_MODULE); + /* Enable the clockwatch on ST Variants */ + if ((ldata->hw_designer == AMBA_VENDOR_ST) && + (ldata->hw_revision > 1)) + writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN, + ldata->base + RTC_CR); + + ldata->rtc = rtc_device_register("pl031", &adev->dev, ops, + THIS_MODULE); if (IS_ERR(ldata->rtc)) { ret = PTR_ERR(ldata->rtc); goto out_no_rtc; } + if (request_irq(adev->irq[0], pl031_interrupt, + IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) { + ret = -EIO; + goto out_no_irq; + } + return 0; -out_no_rtc: - free_irq(adev->irq[0], ldata->rtc); out_no_irq: + rtc_device_unregister(ldata->rtc); +out_no_rtc: iounmap(ldata->base); amba_set_drvdata(adev, NULL); out_no_remap: @@ -175,13 +420,57 @@ out_no_remap: out: amba_release_regions(adev); err_req: + return ret; } +/* Operations for the original ARM version */ +static struct rtc_class_ops arm_pl031_ops = { + .read_time = pl031_read_time, + .set_time = pl031_set_time, + .read_alarm = pl031_read_alarm, + .set_alarm = pl031_set_alarm, + .alarm_irq_enable = pl031_alarm_irq_enable, +}; + +/* The First ST derivative */ +static struct rtc_class_ops stv1_pl031_ops = { + .read_time = pl031_read_time, + .set_time = pl031_set_time, + .read_alarm = pl031_read_alarm, + .set_alarm = pl031_set_alarm, + .alarm_irq_enable = pl031_alarm_irq_enable, + .irq_set_state = pl031_irq_set_state, + .irq_set_freq = pl031_irq_set_freq, +}; + +/* And the second ST derivative */ +static struct rtc_class_ops stv2_pl031_ops = { + .read_time = pl031_stv2_read_time, + .set_time = pl031_stv2_set_time, + .read_alarm = pl031_stv2_read_alarm, + .set_alarm = pl031_stv2_set_alarm, + .alarm_irq_enable = pl031_alarm_irq_enable, + .irq_set_state = pl031_irq_set_state, + .irq_set_freq = pl031_irq_set_freq, +}; + static struct amba_id pl031_ids[] __initdata = { { .id = 0x00041031, .mask = 0x000fffff, + .data = &arm_pl031_ops, + }, + /* ST Micro variants */ + { + .id = 0x00180031, + .mask = 0x00ffffff, + .data = &stv1_pl031_ops, + }, + { + .id = 0x00280031, + .mask = 0x00ffffff, + .data = &stv2_pl031_ops, }, {0, 0}, }; -- GitLab From d91a8910d9585950706536a643ece51b67c695ec Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 Feb 2010 18:13:17 +0000 Subject: [PATCH 1624/3892] ARM: Fix badly placed nuc932 Kconfig entry Signed-off-by: Russell King --- arch/arm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 79251a9cfb6f..8e6672acb9c9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -766,6 +766,8 @@ source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-mmp/Kconfig" +source "arch/arm/mach-nuc93x/Kconfig" + source "arch/arm/mach-sa1100/Kconfig" source "arch/arm/plat-omap/Kconfig" @@ -837,8 +839,6 @@ source "arch/arm/mach-u300/Kconfig" source "arch/arm/mach-w90x900/Kconfig" -source "arch/arm/mach-nuc93x/Kconfig" - source "arch/arm/mach-bcmring/Kconfig" source "arch/arm/mach-ux500/Kconfig" -- GitLab From 6683ece36e3531fc8c75f69e7165c5f20930be88 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 4 Feb 2010 10:22:25 -0800 Subject: [PATCH 1625/3892] net: use helpers to access mc list V2 This patch introduces the similar helpers as those already done for uc list. However multicast lists are no list_head lists but "mademanually". The three macros added by this patch will make the transition of mc_list to list_head smooth in two steps: 1) convert all drivers to use these macros (with the original iterator of type "struct dev_mc_list") 2) once all drivers are converted, convert list type and iterators to "struct netdev_hw_addr" in one patch. >From now on, drivers can (and should) use "netdev_for_each_mc_addr" to iterate over the addresses with iterator of type "struct netdev_hw_addr". Also macros "netdev_mc_count" and "netdev_mc_empty" to read list's length. This is the state which should be reached in all drivers. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 622ba5aa93c4..e535700a3b72 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -268,6 +268,12 @@ struct netdev_hw_addr_list { #define netdev_for_each_uc_addr(ha, dev) \ list_for_each_entry(ha, &dev->uc.list, list) +#define netdev_mc_count(dev) ((dev)->mc_count) +#define netdev_mc_empty(dev) (netdev_mc_count(dev) == 0) + +#define netdev_for_each_mc_addr(mclist, dev) \ + for (mclist = dev->mc_list; mclist; mclist = mclist->next) + struct hh_cache { struct hh_cache *hh_next; /* Next entry */ atomic_t hh_refcnt; /* number of users */ -- GitLab From f8f76db1db369f3a130ac3fd33e2eee5f1610d9c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 4 Feb 2010 10:23:02 -0800 Subject: [PATCH 1626/3892] libphy: add phy_find_first function Many drivers do this in them manually. Now they can use this function. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 16 ++++++++++++++++ include/linux/phy.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index adbc0fded130..db1794546c56 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -276,6 +276,22 @@ int phy_device_register(struct phy_device *phydev) } EXPORT_SYMBOL(phy_device_register); +/** + * phy_find_first - finds the first PHY device on the bus + * @bus: the target MII bus + */ +struct phy_device *phy_find_first(struct mii_bus *bus) +{ + int addr; + + for (addr = 0; addr < PHY_MAX_ADDR; addr++) { + if (bus->phy_map[addr]) + return bus->phy_map[addr]; + } + return NULL; +} +EXPORT_SYMBOL(phy_find_first); + /** * phy_prepare_link - prepares the PHY layer to monitor link status * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 6a7eb402165d..14d7fdf6a90a 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -452,6 +452,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, u32 flags, phy_interface_t interface); struct phy_device * phy_attach(struct net_device *dev, const char *bus_id, u32 flags, phy_interface_t interface); +struct phy_device *phy_find_first(struct mii_bus *bus); int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, void (*handler)(struct net_device *), u32 flags, phy_interface_t interface); -- GitLab From f2a4c59df62f4493c7cf7dfd349ec66bdd4b9fec Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Mon, 1 Feb 2010 17:38:53 -0500 Subject: [PATCH 1627/3892] DaVinci - Adding platform & board changes for vpfe capture on DM365 This patch adds following changes:- 1) add sub device configuration data for TVP5146 used by vpfe capture 2) registers platform devices for vpfe_capture, isif and vpss 3) defines hardware resources for the devices listed under 2) 4) defines clock aliase for isif driver 5) adding setup_pinmux() for isif Signed-off-by: Murali Karicheri Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/board-dm365-evm.c | 71 ++++++++++++++ arch/arm/mach-davinci/dm365.c | 102 ++++++++++++++++++++- arch/arm/mach-davinci/include/mach/dm365.h | 2 + 3 files changed, 174 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index b476395d2cd4..38e9033d2e86 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -37,6 +37,8 @@ #include #include +#include + static inline int have_imager(void) { /* REVISIT when it's supported, trigger via Kconfig */ @@ -306,6 +308,73 @@ static void dm365evm_mmc_configure(void) davinci_cfg_reg(DM365_SD1_DATA0); } +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1 +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) +/* Inputs available at the TVP5146 */ +static struct v4l2_input tvp5146_inputs[] = { + { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + { + .index = 1, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, +}; + +/* + * this is the route info for connecting each input to decoder + * ouput that goes to vpfe. There is a one to one correspondence + * with tvp5146_inputs + */ +static struct vpfe_route tvp5146_routes[] = { + { + .input = INPUT_CVBS_VI2B, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + }, +{ + .input = INPUT_SVIDEO_VI2C_VI1C, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + }, +}; + +static struct vpfe_subdev_info vpfe_sub_devs[] = { + { + .name = "tvp5146", + .grp_id = 0, + .num_inputs = ARRAY_SIZE(tvp5146_inputs), + .inputs = tvp5146_inputs, + .routes = tvp5146_routes, + .can_route = 1, + .ccdc_if_params = { + .if_type = VPFE_BT656, + .hdpol = VPFE_PINPOL_POSITIVE, + .vdpol = VPFE_PINPOL_POSITIVE, + }, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + }, +}; + +static struct vpfe_config vpfe_cfg = { + .num_subdevs = ARRAY_SIZE(vpfe_sub_devs), + .sub_devs = vpfe_sub_devs, + .i2c_adapter_id = 1, + .card_name = "DM365 EVM", + .ccdc = "ISIF", +}; + static void __init evm_init_i2c(void) { davinci_init_i2c(&i2c_pdata); @@ -497,6 +566,8 @@ static struct davinci_uart_config uart_config __initdata = { static void __init dm365_evm_map_io(void) { + /* setup input configuration for VPFE input devices */ + dm365_set_vpfe_config(&vpfe_cfg); dm365_init(); } diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index f53735cb922e..ce9da43a628b 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1008,6 +1008,97 @@ void __init dm365_init(void) davinci_common_init(&davinci_soc_info_dm365); } +static struct resource dm365_vpss_resources[] = { + { + /* VPSS ISP5 Base address */ + .name = "isp5", + .start = 0x01c70000, + .end = 0x01c70000 + 0xff, + .flags = IORESOURCE_MEM, + }, + { + /* VPSS CLK Base address */ + .name = "vpss", + .start = 0x01c70200, + .end = 0x01c70200 + 0xff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device dm365_vpss_device = { + .name = "vpss", + .id = -1, + .dev.platform_data = "dm365_vpss", + .num_resources = ARRAY_SIZE(dm365_vpss_resources), + .resource = dm365_vpss_resources, +}; + +static struct resource vpfe_resources[] = { + { + .start = IRQ_VDINT0, + .end = IRQ_VDINT0, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_VDINT1, + .end = IRQ_VDINT1, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); +static struct platform_device vpfe_capture_dev = { + .name = CAPTURE_DRV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(vpfe_resources), + .resource = vpfe_resources, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static void dm365_isif_setup_pinmux(void) +{ + davinci_cfg_reg(DM365_VIN_CAM_WEN); + davinci_cfg_reg(DM365_VIN_CAM_VD); + davinci_cfg_reg(DM365_VIN_CAM_HD); + davinci_cfg_reg(DM365_VIN_YIN4_7_EN); + davinci_cfg_reg(DM365_VIN_YIN0_3_EN); +} + +static struct resource isif_resource[] = { + /* ISIF Base address */ + { + .start = 0x01c71000, + .end = 0x01c71000 + 0x1ff, + .flags = IORESOURCE_MEM, + }, + /* ISIF Linearization table 0 */ + { + .start = 0x1C7C000, + .end = 0x1C7C000 + 0x2ff, + .flags = IORESOURCE_MEM, + }, + /* ISIF Linearization table 1 */ + { + .start = 0x1C7C400, + .end = 0x1C7C400 + 0x2ff, + .flags = IORESOURCE_MEM, + }, +}; +static struct platform_device dm365_isif_dev = { + .name = "isif", + .id = -1, + .num_resources = ARRAY_SIZE(isif_resource), + .resource = isif_resource, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = dm365_isif_setup_pinmux, + }, +}; + static int __init dm365_init_devices(void) { if (!cpu_is_davinci_dm365()) @@ -1016,7 +1107,16 @@ static int __init dm365_init_devices(void) davinci_cfg_reg(DM365_INT_EDMA_CC); platform_device_register(&dm365_edma_device); platform_device_register(&dm365_emac_device); - + /* Add isif clock alias */ + clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL); + platform_device_register(&dm365_vpss_device); + platform_device_register(&dm365_isif_dev); + platform_device_register(&vpfe_capture_dev); return 0; } postcore_initcall(dm365_init_devices); + +void dm365_set_vpfe_config(struct vpfe_config *cfg) +{ + vpfe_capture_dev.dev.platform_data = cfg; +} diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h index f1710a30e7ba..9fc5a64a5364 100644 --- a/arch/arm/mach-davinci/include/mach/dm365.h +++ b/arch/arm/mach-davinci/include/mach/dm365.h @@ -18,6 +18,7 @@ #include #include #include +#include #define DM365_EMAC_BASE (0x01D07000) #define DM365_EMAC_CNTRL_OFFSET (0x0000) @@ -36,4 +37,5 @@ void __init dm365_init_asp(struct snd_platform_data *pdata); void __init dm365_init_ks(struct davinci_ks_platform_data *pdata); void __init dm365_init_rtc(void); +void dm365_set_vpfe_config(struct vpfe_config *cfg); #endif /* __ASM_ARCH_DM365_H */ -- GitLab From d2de05827cce9438dfc61d5a4cf13b6ca82ebdee Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:32 +0530 Subject: [PATCH 1628/3892] davinci: da8xx/omapl1: add support for the second sysconfig module OMAP-L138 adds a second SYSCFG region having useful functionality like deep sleep, pull up/down control and SATA clock stop. This patch makes provision for accessing registers from second SYSCFG region in da8xx code. Note that OMAP-L137 has a single SYSCFG region. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/board-da830-evm.c | 4 ++-- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-davinci/da830.c | 8 ++++---- arch/arm/mach-davinci/da850.c | 20 ++++++++++++-------- arch/arm/mach-davinci/devices-da8xx.c | 3 ++- arch/arm/mach-davinci/include/mach/da8xx.h | 10 +++++++--- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 31dc9901e556..dc19870b23cd 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -112,7 +112,7 @@ static __init void da830_evm_usb_init(void) * Set up USB clock/mode in the CFGCHIP2 register. * FYI: CFGCHIP2 is 0x0000ef00 initially. */ - cfgchip2 = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)); + cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); /* USB2.0 PHY reference clock is 24 MHz */ cfgchip2 &= ~CFGCHIP2_REFFREQ; @@ -139,7 +139,7 @@ static __init void da830_evm_usb_init(void) cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN; #endif - __raw_writel(cfgchip2, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)); + __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); /* USB_REFCLKIN is not used. */ ret = davinci_cfg_reg(DA830_USB0_DRVVBUS); diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 07de8db14581..dba22419db0a 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -537,7 +537,7 @@ static int __init da850_evm_config_emac(void) if (!machine_is_davinci_da850_evm()) return 0; - cfg_chip3_base = DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG); + cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG); val = __raw_readl(cfg_chip3_base); diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index b22b5cf04250..54796050a2ff 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -1208,13 +1208,13 @@ static struct davinci_soc_info davinci_soc_info_da830 = { void __init da830_init(void) { - da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K); - if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module")) + da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K); + if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module")) return; davinci_soc_info_da830.jtag_id_base = - DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG); - davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG_VIRT(0x120); + DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG); + davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120); davinci_common_init(&davinci_soc_info_da830); } diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 717806c6cef9..4f84ab4bb221 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -838,12 +838,12 @@ static void da850_set_async3_src(int pllnum) } } - v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG)); + v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG)); if (pllnum) v |= CFGCHIP3_ASYNC3_CLKSRC; else v &= ~CFGCHIP3_ASYNC3_CLKSRC; - __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG)); + __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG)); } #ifdef CONFIG_CPU_FREQ @@ -996,9 +996,9 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index) postdiv = opp->postdiv; /* Unlock writing to PLL registers */ - v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG)); + v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); v &= ~CFGCHIP0_PLL_MASTER_LOCK; - __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG)); + __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); ret = davinci_set_pllrate(pll, prediv, mult, postdiv); if (WARN_ON(ret)) @@ -1053,13 +1053,17 @@ static struct davinci_soc_info davinci_soc_info_da850 = { void __init da850_init(void) { - da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K); - if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module")) + da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K); + if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module")) + return; + + da8xx_syscfg1_base = ioremap(DA8XX_SYSCFG1_BASE, SZ_4K); + if (WARN(!da8xx_syscfg1_base, "Unable to map syscfg1 module")) return; davinci_soc_info_da850.jtag_id_base = - DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG); - davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG_VIRT(0x120); + DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG); + davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120); davinci_common_init(&davinci_soc_info_da850); diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index a5105f03fd86..745534eb63c7 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -42,7 +42,8 @@ #define DA8XX_MDIO_REG_OFFSET 0x4000 #define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K -void __iomem *da8xx_syscfg_base; +void __iomem *da8xx_syscfg0_base; +void __iomem *da8xx_syscfg1_base; static struct plat_serial8250_port da8xx_serial_pdata[] = { { diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 90704910d343..bddc4d4a806e 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -21,7 +21,8 @@ #include #include -extern void __iomem *da8xx_syscfg_base; +extern void __iomem *da8xx_syscfg0_base; +extern void __iomem *da8xx_syscfg1_base; /* * The cp_intc interrupt controller for the da8xx isn't in the same @@ -34,13 +35,16 @@ extern void __iomem *da8xx_syscfg_base; #define DA8XX_CP_INTC_SIZE SZ_8K #define DA8XX_CP_INTC_VIRT (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K) -#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000) -#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x)) +#define DA8XX_SYSCFG0_BASE (IO_PHYS + 0x14000) +#define DA8XX_SYSCFG0_VIRT(x) (da8xx_syscfg0_base + (x)) #define DA8XX_JTAG_ID_REG 0x18 #define DA8XX_CFGCHIP0_REG 0x17c #define DA8XX_CFGCHIP2_REG 0x184 #define DA8XX_CFGCHIP3_REG 0x188 +#define DA8XX_SYSCFG1_BASE (IO_PHYS + 0x22C000) +#define DA8XX_SYSCFG1_VIRT(x) (da8xx_syscfg1_base + (x)) + #define DA8XX_PSC0_BASE 0x01c10000 #define DA8XX_PLL0_BASE 0x01c11000 #define DA8XX_TIMER64P0_BASE 0x01c20000 -- GitLab From 9a219a9ecf49ab156df4c18267ade4d468d9930e Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:33 +0530 Subject: [PATCH 1629/3892] davinci: move PLL wait time values to clock.h As suspend support is added, the code supporting the suspend operation needs to bypass PLLs and needs to access the same wait time values as the PLL code in clock.c. To facilitate this, move the PLL wait times to clock.h where they can be accessed by suspend code. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/clock.c | 15 +++------------ arch/arm/mach-davinci/clock.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index baece65cb9c0..0fa68c558320 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -376,7 +376,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, locktime = ((2000 * prediv) / 100); prediv = (prediv - 1) | PLLDIV_EN; } else { - locktime = 20; + locktime = PLL_LOCK_TIME; } if (postdiv) postdiv = (postdiv - 1) | PLLDIV_EN; @@ -389,12 +389,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); __raw_writel(ctrl, pll->base + PLLCTL); - /* - * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched - * to bypass mode. Delay of 1us ensures we are good for all > 4MHz - * OSCIN/CLKIN inputs. Typically the input is ~25MHz. - */ - udelay(1); + udelay(PLL_BYPASS_TIME); /* Reset and enable PLL */ ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS); @@ -408,11 +403,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, if (pll->flags & PLL_HAS_POSTDIV) __raw_writel(postdiv, pll->base + POSTDIV); - /* - * Wait for PLL to reset properly, OMAP-L138 datasheet says - * 'min' time = 125ns - */ - udelay(1); + udelay(PLL_RESET_TIME); /* Bring PLL out of reset */ ctrl |= PLLCTL_PLLRST; diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index c92d77a3008d..eca4d9972225 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -53,6 +53,21 @@ #define PLLDIV_EN BIT(15) #define PLLDIV_RATIO_MASK 0x1f +/* + * OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN + * cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us + * ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input + * is ~25MHz. Units are micro seconds. + */ +#define PLL_BYPASS_TIME 1 +/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */ +#define PLL_RESET_TIME 1 +/* + * From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4 + * Units are micro seconds. + */ +#define PLL_LOCK_TIME 20 + struct pll_data { u32 phys_base; void __iomem *base; -- GitLab From 7ec4b24326ec9b0467ab23b0417ec6b63e8e5524 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:34 +0530 Subject: [PATCH 1630/3892] davinci: move DDR2 controller defines to memory.h Move defintions of DDR2 controller registers to memory.h from cpuidle.c. The motivation behind the change is to be able to use these defintions in assembly code that puts DDR2 in self-refresh and enables the SoC to enter suspend state. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/cpuidle.c | 5 +---- arch/arm/mach-davinci/include/mach/memory.h | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index 97a90f36fc92..beda3b579688 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -19,6 +19,7 @@ #include #include +#include #define DAVINCI_CPUIDLE_MAX_STATES 2 @@ -39,10 +40,6 @@ static struct cpuidle_driver davinci_idle_driver = { static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); static void __iomem *ddr2_reg_base; -#define DDR2_SDRCR_OFFSET 0xc -#define DDR2_SRPD_BIT BIT(23) -#define DDR2_LPMODEN_BIT BIT(31) - static void davinci_save_ddr_power(int enter, bool pdown) { u32 val; diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h index 80309aed534a..7aeaf46cade0 100644 --- a/arch/arm/mach-davinci/include/mach/memory.h +++ b/arch/arm/mach-davinci/include/mach/memory.h @@ -31,6 +31,10 @@ #define PHYS_OFFSET DAVINCI_DDR_BASE #endif +#define DDR2_SDRCR_OFFSET 0xc +#define DDR2_SRPD_BIT BIT(23) +#define DDR2_LPMODEN_BIT BIT(31) + /* * Increase size of DMA-consistent memory region */ -- GitLab From c94fa15ba2d736af786ac1e56686d41987b1aba0 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:35 +0530 Subject: [PATCH 1631/3892] davinci: move PSC register definitions from psc.c to psc.h The motivation behind the change is to use the same definitions in the assembly code responsible for suspending the SoC, a part of which is to clock gate the DDR2 clock. Note that the assembly code cannot invoke the C function meant for this. The main reason being that stack in DDR2 cannot be accessed while DDR2 clock is being clock gated. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/include/mach/psc.h | 11 +++++++++++ arch/arm/mach-davinci/psc.c | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 171173c1dbad..2776b2356594 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -180,6 +180,17 @@ #define DA8XX_LPSC1_CR_P3_SS 26 #define DA8XX_LPSC1_L3_CBA_RAM 31 +/* PSC register offsets */ +#define EPCPR 0x070 +#define PTCMD 0x120 +#define PTSTAT 0x128 +#define PDSTAT 0x200 +#define PDCTL1 0x304 +#define MDSTAT 0x800 +#define MDCTL 0xA00 + +#define MDSTAT_STATE_MASK 0x1f + extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id); extern void davinci_psc_config(unsigned int domain, unsigned int ctlr, unsigned int id, char enable); diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index 04a3cb72c5ab..adf6b5c7f1e5 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -25,17 +25,6 @@ #include #include -/* PSC register offsets */ -#define EPCPR 0x070 -#define PTCMD 0x120 -#define PTSTAT 0x128 -#define PDSTAT 0x200 -#define PDCTL1 0x304 -#define MDSTAT 0x800 -#define MDCTL 0xA00 - -#define MDSTAT_STATE_MASK 0x1f - /* Return nonzero iff the domain's clock is active */ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) { -- GitLab From e2da3aaa4254d9e79d9524190fc7e5f0cbdc3c33 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:36 +0530 Subject: [PATCH 1632/3892] davinci: make it possible to include clock.h and psc.h in assembly code psc.h contains register defines for PSC module which need to be accessed in assembly code which helps the DA850/OMAP-L138 SoC go to sleep. Shutting down DDR clock using PSC is a part of the sleep procedure. Also, the PLL related hardware definitions in clock.h are needed in assembly code to bypass the DDR2 PLL. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/clock.h | 10 +++++++--- arch/arm/mach-davinci/include/mach/psc.h | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index eca4d9972225..31fb6eac712c 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -12,9 +12,6 @@ #ifndef __ARCH_ARM_DAVINCI_CLOCK_H #define __ARCH_ARM_DAVINCI_CLOCK_H -#include -#include - #define DAVINCI_PLL1_BASE 0x01c40800 #define DAVINCI_PLL2_BASE 0x01c40c00 #define MAX_PLL 2 @@ -68,6 +65,11 @@ */ #define PLL_LOCK_TIME 20 +#ifndef __ASSEMBLER__ + +#include +#include + struct pll_data { u32 phys_base; void __iomem *base; @@ -124,3 +126,5 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, extern struct platform_device davinci_wdt_device; #endif + +#endif diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 2776b2356594..651f6d8158fa 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -191,8 +191,12 @@ #define MDSTAT_STATE_MASK 0x1f +#ifndef __ASSEMBLER__ + extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id); extern void davinci_psc_config(unsigned int domain, unsigned int ctlr, unsigned int id, char enable); +#endif + #endif /* __ASM_ARCH_PSC_H */ -- GitLab From 948c66df0d5e23dbcb84bee39a11b56c8a0d3e41 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:37 +0530 Subject: [PATCH 1633/3892] davinci: cpuidle: move mapping of DDR2 controller registers out of driver When suspend is supported, both cpuidle and suspend code need to work on DDR2 registers. Instead of mapping the DDR2 registers twice, do it once outside of cpuidle driver and let cpuidle driver get the virtual base address of DDR2 registers. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/cpuidle.c | 33 +++----------------- arch/arm/mach-davinci/devices-da8xx.c | 16 +++++++++- arch/arm/mach-davinci/include/mach/cpuidle.h | 1 + arch/arm/mach-davinci/include/mach/da8xx.h | 1 + 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index beda3b579688..bd59f31b8a95 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -106,8 +106,6 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) int ret; struct cpuidle_device *device; struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; - struct resource *ddr2_regs; - resource_size_t len; device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); @@ -116,28 +114,12 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) return -ENOENT; } - ddr2_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!ddr2_regs) { - dev_err(&pdev->dev, "cannot get DDR2 controller register base"); - return -ENODEV; - } - - len = resource_size(ddr2_regs); - - ddr2_regs = request_mem_region(ddr2_regs->start, len, ddr2_regs->name); - if (!ddr2_regs) - return -EBUSY; - - ddr2_reg_base = ioremap(ddr2_regs->start, len); - if (!ddr2_reg_base) { - ret = -ENOMEM; - goto ioremap_fail; - } + ddr2_reg_base = pdata->ddr2_ctlr_base; ret = cpuidle_register_driver(&davinci_idle_driver); if (ret) { dev_err(&pdev->dev, "failed to register driver\n"); - goto driver_register_fail; + return ret; } /* Wait for interrupt state */ @@ -164,18 +146,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) ret = cpuidle_register_device(device); if (ret) { dev_err(&pdev->dev, "failed to register device\n"); - goto device_register_fail; + cpuidle_unregister_driver(&davinci_idle_driver); + return ret; } return 0; - -device_register_fail: - cpuidle_unregister_driver(&davinci_idle_driver); -driver_register_fail: - iounmap(ddr2_reg_base); -ioremap_fail: - release_mem_region(ddr2_regs->start, len); - return ret; } static struct platform_driver davinci_cpuidle_driver = { diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 745534eb63c7..0c759ad0aeee 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -496,6 +496,19 @@ int da8xx_register_rtc(void) return ret; } +static void __iomem *da8xx_ddr2_ctlr_base; +void __iomem * __init da8xx_get_mem_ctlr(void) +{ + if (da8xx_ddr2_ctlr_base) + return da8xx_ddr2_ctlr_base; + + da8xx_ddr2_ctlr_base = ioremap(DA8XX_DDR2_CTL_BASE, SZ_32K); + if (!da8xx_ddr2_ctlr_base) + pr_warning("%s: Unable to map DDR2 controller", __func__); + + return da8xx_ddr2_ctlr_base; +} + static struct resource da8xx_cpuidle_resources[] = { { .start = DA8XX_DDR2_CTL_BASE, @@ -521,6 +534,7 @@ static struct platform_device da8xx_cpuidle_device = { int __init da8xx_register_cpuidle(void) { + da8xx_cpuidle_pdata.ddr2_ctlr_base = da8xx_get_mem_ctlr(); + return platform_device_register(&da8xx_cpuidle_device); } - diff --git a/arch/arm/mach-davinci/include/mach/cpuidle.h b/arch/arm/mach-davinci/include/mach/cpuidle.h index cbfc6a9c81b4..74f088b0edfb 100644 --- a/arch/arm/mach-davinci/include/mach/cpuidle.h +++ b/arch/arm/mach-davinci/include/mach/cpuidle.h @@ -12,6 +12,7 @@ struct davinci_cpuidle_config { u32 ddr2_pdown; + void __iomem *ddr2_ctlr_base; }; #endif diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index bddc4d4a806e..cab4a25ebe4f 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -94,6 +94,7 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata); int da8xx_register_rtc(void); int da850_register_cpufreq(void); int da8xx_register_cpuidle(void); +void __iomem * __init da8xx_get_mem_ctlr(void); extern struct platform_device da8xx_serial_device; extern struct emac_platform_data da8xx_emac_pdata; -- GitLab From 7aad472bb5602242113718fc170e61b127460cbe Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:38 +0530 Subject: [PATCH 1634/3892] davinci: da850/omap-l138: unlock PLL registers during init On omap-l1 devices the PLL registers can be locked from writes. Currently the cpufreq rate setting code unlocks PLL0 before the write actually happens. With suspend support getting added PLL1 registers need be be unlocked as well. To facilitate this, unlock both PLLs during the init time itself. This also obviates the need to unlock PLL registers for each CPUFreq transtition. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/da850.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 4f84ab4bb221..fcfde2a72f8f 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -40,6 +40,7 @@ #define DA850_REF_FREQ 24000000 #define CFGCHIP3_ASYNC3_CLKSRC BIT(4) +#define CFGCHIP3_PLL1_MASTER_LOCK BIT(5) #define CFGCHIP0_PLL_MASTER_LOCK BIT(4) static int da850_set_armrate(struct clk *clk, unsigned long rate); @@ -987,7 +988,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index) unsigned int prediv, mult, postdiv; struct da850_opp *opp; struct pll_data *pll = clk->pll_data; - unsigned int v; int ret; opp = (struct da850_opp *) da850_freq_table[index].index; @@ -995,11 +995,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index) mult = opp->mult; postdiv = opp->postdiv; - /* Unlock writing to PLL registers */ - v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); - v &= ~CFGCHIP0_PLL_MASTER_LOCK; - __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); - ret = davinci_set_pllrate(pll, prediv, mult, postdiv); if (WARN_ON(ret)) return ret; @@ -1053,6 +1048,8 @@ static struct davinci_soc_info davinci_soc_info_da850 = { void __init da850_init(void) { + unsigned int v; + da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K); if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module")) return; @@ -1075,4 +1072,14 @@ void __init da850_init(void) * be any noticible change even in non-DVFS use cases. */ da850_set_async3_src(1); + + /* Unlock writing to PLL0 registers */ + v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); + v &= ~CFGCHIP0_PLL_MASTER_LOCK; + __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG)); + + /* Unlock writing to PLL1 registers */ + v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG)); + v &= ~CFGCHIP3_PLL1_MASTER_LOCK; + __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG)); } -- GitLab From 60cd02e1f4a1574c26c9ae8d29d63bd3d179c0c2 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 16 Nov 2009 17:21:39 +0530 Subject: [PATCH 1635/3892] davinci: da850/omap-l138: create static map for SRAM Create static map for internal SRAM and populate SRAM base and size in soc_info structure to allow SRAM allocation functions from arch/arm/mach-davinci/sram.c to work. On DA850 SRAM is used for suspend-to-RAM implementation in places where DDR2 cannot be accessed as its clocks are stopped. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/da850.c | 8 ++++++++ arch/arm/mach-davinci/include/mach/da8xx.h | 1 + 2 files changed, 9 insertions(+) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index fcfde2a72f8f..1ac8f6318c1b 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -771,6 +771,12 @@ static struct map_desc da850_io_desc[] = { .length = DA8XX_CP_INTC_SIZE, .type = MT_DEVICE }, + { + .virtual = SRAM_VIRT, + .pfn = __phys_to_pfn(DA8XX_ARM_RAM_BASE), + .length = SZ_8K, + .type = MT_DEVICE + }, }; static void __iomem *da850_psc_bases[] = { @@ -1044,6 +1050,8 @@ static struct davinci_soc_info davinci_soc_info_da850 = { .gpio_irq = IRQ_DA8XX_GPIO0, .serial_dev = &da8xx_serial_device, .emac_pdata = &da8xx_emac_pdata, + .sram_dma = DA8XX_ARM_RAM_BASE, + .sram_len = SZ_8K, }; void __init da850_init(void) diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index cab4a25ebe4f..d43a4b6b6d76 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -57,6 +57,7 @@ extern void __iomem *da8xx_syscfg1_base; #define DA8XX_AEMIF_CS3_BASE 0x62000000 #define DA8XX_AEMIF_CTL_BASE 0x68000000 #define DA8XX_DDR2_CTL_BASE 0xb0000000 +#define DA8XX_ARM_RAM_BASE 0xffff0000 #define PINMUX0 0x00 #define PINMUX1 0x04 -- GitLab From 5b5052e32dc53e6e76da188c547f14c4e5e35624 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Mon, 23 Nov 2009 15:27:15 +0530 Subject: [PATCH 1636/3892] davinci: explain CLOCK_TICK_RATE of 27MHz in include/mach/timex.h Leave a comment explaining the constant value of 27Mhz used in include/mach/timex.h for all DaVinci platforms. Many of the platforms actually run at 24MHz timer frequency (Eg. EVMs of DM355, DM365 and OMAP-L1). The comment also serves as a porting alert. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/include/mach/timex.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/include/mach/timex.h b/arch/arm/mach-davinci/include/mach/timex.h index 52827567841d..9b885298f106 100644 --- a/arch/arm/mach-davinci/include/mach/timex.h +++ b/arch/arm/mach-davinci/include/mach/timex.h @@ -11,7 +11,12 @@ #ifndef __ASM_ARCH_TIMEX_H #define __ASM_ARCH_TIMEX_H -/* The source frequency for the timers is the 27MHz clock */ +/* + * Alert: Not all timers of the DaVinci family run at a frequency of 27MHz, + * but we should be fine as long as CLOCK_TICK_RATE or LATCH (see include/ + * linux/jiffies.h) are not used directly in code. Currently none of the + * code relevant to DaVinci platform depends on these values directly. + */ #define CLOCK_TICK_RATE 27000000 #endif /* __ASM_ARCH_TIMEX_H__ */ -- GitLab From b73b526ec36068b102e735064b61dc724d45d2db Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 24 Nov 2009 18:25:14 +0530 Subject: [PATCH 1637/3892] davinci: board-dm646x-evm.c: arrange related code together Currently all the #defines and static variables in the board-dm646x-evm.c file are located right at the start of the file because of which the related code is not together - making reading the code difficult. This patch moves around the code keeping related code together. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/board-dm646x-evm.c | 90 ++++++++++++------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 8d0b0e01c59b..8c05343bb001 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -40,53 +40,8 @@ #include #include -#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ - defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE) -#define HAS_ATA 1 -#else -#define HAS_ATA 0 -#endif - -#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000 -#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000 - #define NAND_BLOCK_SIZE SZ_128K -/* CPLD Register 0 bits to control ATA */ -#define DM646X_EVM_ATA_RST BIT(0) -#define DM646X_EVM_ATA_PWD BIT(1) - -#define DM646X_EVM_PHY_MASK (0x2) -#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ - -#define VIDCLKCTL_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x38) -#define VSCLKDIS_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x6c) -#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8)) -#define VCH2CLK_SYSCLK8 (BIT(9)) -#define VCH2CLK_AUXCLK (BIT(9) | BIT(8)) -#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12)) -#define VCH3CLK_SYSCLK8 (BIT(13)) -#define VCH3CLK_AUXCLK (BIT(14) | BIT(13)) - -#define VIDCH2CLK (BIT(10)) -#define VIDCH3CLK (BIT(11)) -#define VIDCH1CLK (BIT(4)) -#define TVP7002_INPUT (BIT(4)) -#define TVP5147_INPUT (~BIT(4)) -#define VPIF_INPUT_ONE_CHANNEL (BIT(5)) -#define VPIF_INPUT_TWO_CHANNEL (~BIT(5)) -#define TVP5147_CH0 "tvp514x-0" -#define TVP5147_CH1 "tvp514x-1" - -static void __iomem *vpif_vidclkctl_reg; -static void __iomem *vpif_vsclkdis_reg; -/* spin lock for updating above registers */ -static spinlock_t vpif_reg_lock; - -static struct davinci_uart_config uart_config __initdata = { - .enabled_uarts = (1 << 0), -}; - /* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot * and U-Boot environment this avoids dependency on any particular combination * of UBL, U-Boot or flashing tools etc. @@ -120,6 +75,9 @@ static struct davinci_nand_pdata davinci_nand_data = { .options = 0, }; +#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000 +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000 + static struct resource davinci_nand_resources[] = { { .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, @@ -144,6 +102,17 @@ static struct platform_device davinci_nand_device = { }, }; +#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ + defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE) +#define HAS_ATA 1 +#else +#define HAS_ATA 0 +#endif + +/* CPLD Register 0 bits to control ATA */ +#define DM646X_EVM_ATA_RST BIT(0) +#define DM646X_EVM_ATA_PWD BIT(1) + /* CPLD Register 0 Client: used for I/O Control */ static int cpld_reg0_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -424,6 +393,30 @@ static struct davinci_i2c_platform_data i2c_pdata = { .bus_delay = 0 /* usec */, }; +#define VIDCLKCTL_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x38) +#define VSCLKDIS_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x6c) +#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8)) +#define VCH2CLK_SYSCLK8 (BIT(9)) +#define VCH2CLK_AUXCLK (BIT(9) | BIT(8)) +#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12)) +#define VCH3CLK_SYSCLK8 (BIT(13)) +#define VCH3CLK_AUXCLK (BIT(14) | BIT(13)) + +#define VIDCH2CLK (BIT(10)) +#define VIDCH3CLK (BIT(11)) +#define VIDCH1CLK (BIT(4)) +#define TVP7002_INPUT (BIT(4)) +#define TVP5147_INPUT (~BIT(4)) +#define VPIF_INPUT_ONE_CHANNEL (BIT(5)) +#define VPIF_INPUT_TWO_CHANNEL (~BIT(5)) +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +static void __iomem *vpif_vidclkctl_reg; +static void __iomem *vpif_vsclkdis_reg; +/* spin lock for updating above registers */ +static spinlock_t vpif_reg_lock; + static int set_vpif_clock(int mux_mode, int hd) { unsigned long flags; @@ -690,6 +683,13 @@ static void __init davinci_map_io(void) dm646x_init(); } +static struct davinci_uart_config uart_config __initdata = { + .enabled_uarts = (1 << 0), +}; + +#define DM646X_EVM_PHY_MASK (0x2) +#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ + static __init void evm_init(void) { struct davinci_soc_info *soc_info = &davinci_soc_info; -- GitLab From c1978e1dfb3d171010f6a22eb0a9eed89a245666 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 24 Nov 2009 18:25:15 +0530 Subject: [PATCH 1638/3892] davinci: add support for DM6467T EVM DM6467T (T for Turbo) is a newer and faster DM6467 part from TI. The new part supports 1080p video and has the ARM running at 495MHz. More SoC information: http://focus.ti.com/docs/prod/folders/print/tms320dm6467t.html Spectrum Digital, Inc has a new EVM for this part. It is _mostly_ same as the older DM6467 EVM except for a 33MHz crystal input and THS8200 video encoder for 1080p support. The meat of this patch is dedicated to initializing the crystal frequency from EVM board file. Additional notes: I did consider some alternative ways to make the crystal input board specific including - (1) having board code initialize the crystal frequency using the first member of soc_info->cpu_clks array (2) introducing a new ref_clk_rate member in soc_info structure. But, the current way seems to be the simplest and least intruding considering that both the clock array and SoC info structure are actually private to the SoC file. Also the fact that davinci_common_init() initializes both the soc_info and clocks in one go. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/Kconfig | 4 ++++ arch/arm/mach-davinci/board-dm646x-evm.c | 24 +++++++++++++++++++++ arch/arm/mach-davinci/dm646x.c | 3 +-- arch/arm/mach-davinci/include/mach/dm646x.h | 2 ++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 033bfede6b67..0ebe185610bf 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -91,10 +91,14 @@ config MACH_DAVINCI_DM6467_EVM bool "TI DM6467 EVM" default ARCH_DAVINCI_DM646x depends on ARCH_DAVINCI_DM646x + select MACH_DAVINCI_DM6467TEVM help Configure this option to specify the whether the board used for development is a DM6467 EVM +config MACH_DAVINCI_DM6467TEVM + bool + config MACH_DAVINCI_DM365_EVM bool "TI DM365 EVM" default ARCH_DAVINCI_DM365 diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 8c05343bb001..542bfdbbea0f 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ #include #include +#include "clock.h" + #define NAND_BLOCK_SIZE SZ_128K /* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot @@ -713,6 +716,17 @@ static __init void davinci_dm646x_evm_irq_init(void) davinci_irq_init(); } +#define DM646X_EVM_REF_FREQ 27000000 +#define DM6467T_EVM_REF_FREQ 33000000 + +void __init dm646x_board_setup_refclk(struct clk *clk) +{ + if (machine_is_davinci_dm6467tevm()) + clk->rate = DM6467T_EVM_REF_FREQ; + else + clk->rate = DM646X_EVM_REF_FREQ; +} + MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") .phys_io = IO_PHYS, .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, @@ -723,3 +737,13 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") .init_machine = evm_init, MACHINE_END +MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") + .phys_io = IO_PHYS, + .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, + .boot_params = (0x80000100), + .map_io = davinci_map_io, + .init_irq = davinci_dm646x_evm_irq_init, + .timer = &davinci_timer, + .init_machine = evm_init, +MACHINE_END + diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 829a44bcf799..515d3edb9a33 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -42,7 +42,6 @@ /* * Device specific clocks */ -#define DM646X_REF_FREQ 27000000 #define DM646X_AUX_FREQ 24000000 static struct pll_data pll1_data = { @@ -57,7 +56,6 @@ static struct pll_data pll2_data = { static struct clk ref_clk = { .name = "ref_clk", - .rate = DM646X_REF_FREQ, }; static struct clk aux_clkin = { @@ -925,6 +923,7 @@ void dm646x_setup_vpif(struct vpif_display_config *display_config, void __init dm646x_init(void) { + dm646x_board_setup_refclk(&ref_clk); davinci_common_init(&davinci_soc_info_dm646x); } diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h index 8cec746ae9d2..8221153bb2af 100644 --- a/arch/arm/mach-davinci/include/mach/dm646x.h +++ b/arch/arm/mach-davinci/include/mach/dm646x.h @@ -16,6 +16,7 @@ #include #include #include +#include #define DM646X_EMAC_BASE (0x01C80000) #define DM646X_EMAC_CNTRL_OFFSET (0x0000) @@ -30,6 +31,7 @@ void __init dm646x_init(void); void __init dm646x_init_ide(void); void __init dm646x_init_mcasp0(struct snd_platform_data *pdata); void __init dm646x_init_mcasp1(struct snd_platform_data *pdata); +void __init dm646x_board_setup_refclk(struct clk *clk); void dm646x_video_init(void); -- GitLab From f979aa6e17fe11fb7b603992c742898175327499 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Thu, 3 Dec 2009 15:36:51 +0530 Subject: [PATCH 1639/3892] davinci: make /proc/davinci_clocks display multi-rooted clock tree This patch modifies clock dump to take care of clock tress rooted at multiple oscillators. Current code assumes the entire tree is rooted on a single oscillator. When using off-chip clock synthesizers, some of the clocks can be obtained from a different on-board oscillator. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/clock.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 0fa68c558320..2c27caefa62e 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -516,12 +516,15 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) static int davinci_ck_show(struct seq_file *m, void *v) { - /* Show clock tree; we know the main oscillator is first. - * We trust nonzero usecounts equate to PSC enables... + struct clk *clk; + + /* + * Show clock tree; We trust nonzero usecounts equate to PSC enables... */ mutex_lock(&clocks_mutex); - if (!list_empty(&clocks)) - dump_clock(m, 0, list_first_entry(&clocks, struct clk, node)); + list_for_each_entry(clk, &clocks, node) + if (!clk->parent) + dump_clock(m, 0, clk); mutex_unlock(&clocks_mutex); return 0; -- GitLab From 2f72e8dcc5f528976a8cd631b44dffae0591612a Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Thu, 3 Dec 2009 15:36:52 +0530 Subject: [PATCH 1640/3892] davinci: move /proc/davinci_clocks to debugfs Move /proc/davinci_clocks to /sys/kernel/debug/davinci_clocks (debugfs). debugfs is more suited for this since the clock dump is debug information. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/clock.c | 42 +++++++++-------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 2c27caefa62e..a19bab18318a 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -459,24 +459,10 @@ int __init davinci_clk_init(struct davinci_clk *clocks) return 0; } -#ifdef CONFIG_PROC_FS -#include -#include - -static void *davinci_ck_start(struct seq_file *m, loff_t *pos) -{ - return *pos < 1 ? (void *)1 : NULL; -} - -static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return NULL; -} +#ifdef CONFIG_DEBUG_FS -static void davinci_ck_stop(struct seq_file *m, void *v) -{ -} +#include +#include #define CLKNAME_MAX 10 /* longest clock name */ #define NEST_DELTA 2 @@ -530,30 +516,24 @@ static int davinci_ck_show(struct seq_file *m, void *v) return 0; } -static const struct seq_operations davinci_ck_op = { - .start = davinci_ck_start, - .next = davinci_ck_next, - .stop = davinci_ck_stop, - .show = davinci_ck_show -}; - static int davinci_ck_open(struct inode *inode, struct file *file) { - return seq_open(file, &davinci_ck_op); + return single_open(file, davinci_ck_show, NULL); } -static const struct file_operations proc_davinci_ck_operations = { +static const struct file_operations davinci_ck_operations = { .open = davinci_ck_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; -static int __init davinci_ck_proc_init(void) +static int __init davinci_clk_debugfs_init(void) { - proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations); + debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL, + &davinci_ck_operations); return 0; } -__initcall(davinci_ck_proc_init); -#endif /* CONFIG_DEBUG_PROC_FS */ +device_initcall(davinci_clk_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ -- GitLab From e2abd5a282b2b146aeae7515fb42c3dbd2ff7204 Mon Sep 17 00:00:00 2001 From: Sudhakar Rajashekhara Date: Wed, 18 Nov 2009 11:48:37 +0530 Subject: [PATCH 1641/3892] davinci: da850/omap-l138: Modify NOR partition info On DA850/OMAP-L138, NOR flash partition was starting from offset ZERO erasing the UBL and u-boot when the complete NOR is erased. This patch moves the start of the partition to 512K, after the bootloaders and u-boot env variables. This patch also creates a new partition on NOR Flash to store Linux kernel image. Signed-off-by: Sudhakar Rajashekhara Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/board-da850-evm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index dba22419db0a..ac3b5a3448e5 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -46,8 +46,20 @@ static struct mtd_partition da850_evm_norflash_partition[] = { { - .name = "NOR filesystem", + .name = "bootloaders + env", .offset = 0, + .size = SZ_512K, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0, + }, + { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, .mask_flags = 0, }, -- GitLab From fc42e335ee6a7dd1f740c0fc868d607cc689d7c4 Mon Sep 17 00:00:00 2001 From: Sudhakar Rajashekhara Date: Wed, 18 Nov 2009 12:11:41 +0530 Subject: [PATCH 1642/3892] davinci: da850/omap-l138: Enable 4-bit ecc This patch initializes the platform data to enable 4-bit ecc support on DA850/OMAP-L138. Signed-off-by: Sudhakar Rajashekhara Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/board-da850-evm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index ac3b5a3448e5..76e4347c666f 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -131,6 +131,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = { .parts = da850_evm_nandflash_partition, .nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition), .ecc_mode = NAND_ECC_HW, + .ecc_bits = 4, .options = NAND_USE_FLASH_BBT, }; -- GitLab From 8ee2bf9ab792d0c02b13ca3acbd036debb7745d9 Mon Sep 17 00:00:00 2001 From: Sriramakrishnan Date: Thu, 19 Nov 2009 15:58:25 +0530 Subject: [PATCH 1643/3892] TI Davinci EMAC : Re-use driver for other platforms. The davinci EMAC peripheral is also available on other TI platforms -notably TI AM3517 SoC. This patch modifies the config option and the platform structure header files so that the driver can be reused on non-davinci platforms as well. Signed-off-by: Sriramakrishnan Acked-by: Chaithrika U S Acked-by: David S. Miller Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/common.c | 2 +- arch/arm/mach-davinci/include/mach/da8xx.h | 2 +- arch/arm/mach-davinci/include/mach/dm365.h | 2 +- arch/arm/mach-davinci/include/mach/dm644x.h | 2 +- arch/arm/mach-davinci/include/mach/dm646x.h | 2 +- drivers/net/Kconfig | 2 +- drivers/net/davinci_emac.c | 3 +-- .../include/mach/emac.h => include/linux/davinci_emac.h | 4 ++-- 8 files changed, 9 insertions(+), 10 deletions(-) rename arch/arm/mach-davinci/include/mach/emac.h => include/linux/davinci_emac.h (92%) diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index c2de94cde56a..94f27cbcd55a 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -11,13 +11,13 @@ #include #include #include +#include #include #include #include #include -#include #include "clock.h" diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index d43a4b6b6d76..d9a7f11894c4 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -13,10 +13,10 @@ #include diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a19fac35259a..414d774028ba 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -117,19 +117,6 @@ struct ieee80211_tx_queue_params { bool uapsd; }; -/** - * struct ieee80211_tx_queue_stats - transmit queue statistics - * - * @len: number of packets in queue - * @limit: queue length limit - * @count: number of frames sent - */ -struct ieee80211_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; -}; - struct ieee80211_low_level_stats { unsigned int dot11ACKFailureCount; unsigned int dot11RTSFailureCount; @@ -1548,13 +1535,6 @@ enum ieee80211_ampdu_mlme_action { * Returns a negative error code on failure. * The callback can sleep. * - * @get_tx_stats: Get statistics of the current TX queue status. This is used - * to get number of currently queued packets (queue length), maximum queue - * size (limit), and total number of packets sent using each TX queue - * (count). The 'stats' pointer points to an array that has hw->queues - * items. - * The callback must be atomic. - * * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, * this is only used for IBSS mode BSSID merging and debugging. Is not a * required function. @@ -1648,8 +1628,6 @@ struct ieee80211_ops { enum sta_notify_cmd, struct ieee80211_sta *sta); int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); - int (*get_tx_stats)(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats); u64 (*get_tsf)(struct ieee80211_hw *hw); void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); void (*reset_tsf)(struct ieee80211_hw *hw); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 855e85b55061..c3d844093a2f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -290,14 +290,6 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, return ret; } -static inline int drv_get_tx_stats(struct ieee80211_local *local, - struct ieee80211_tx_queue_stats *stats) -{ - int ret = local->ops->get_tx_stats(&local->hw, stats); - trace_drv_get_tx_stats(local, stats, ret); - return ret; -} - static inline u64 drv_get_tsf(struct ieee80211_local *local) { u64 ret = -1ULL; diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index c984910bf275..41baf730a5c7 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -630,29 +630,6 @@ TRACE_EVENT(drv_conf_tx, ) ); -TRACE_EVENT(drv_get_tx_stats, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_tx_queue_stats *stats, - int ret), - - TP_ARGS(local, stats, ret), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(int, ret) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->ret = ret; - ), - - TP_printk( - LOCAL_PR_FMT " ret:%d", - LOCAL_PR_ARG, __entry->ret - ) -); - TRACE_EVENT(drv_get_tsf, TP_PROTO(struct ieee80211_local *local, u64 ret), -- GitLab From 641eabb0a3717020d1a93d3f91493ab0d826c910 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 7 Feb 2010 16:01:55 +0100 Subject: [PATCH 1754/3892] ath: fix WARN_ON with Polish (Poland) Contry code This patch fixes a WARN_ON which is triggered by Poland's country code. ath: EEPROM regdomain: 0x8268 ath: EEPROM indicates we should expect a country code ath: doing EEPROM country->regdmn map search ath: country maps to regdmn code: 0x37 ath: Country alpha2 being used: PL ath: Regpair used: 0x37 -----------[ cut here ]------------ WARNING: at drivers/net/wireless/ath/regd.c:155 ath_regd_init+0x30b Pid: 12661, comm: firmware/carl91 2.6.33-rc5-wl #18 Call Trace: [<>] ? warn_slowpath_common+0x76/0x8c [<>] ? ar9170_reg_notifier+0x0/0x2d [carl9170usb] [<>] ? ath_regd_init+0x30b/0x377 [ath] [<>] ? ar9170_register+0x3b3/0x3ca [carl9170usb] [...] ---[ end trace ]--- Note: Poland is just an example. But it is very likely that more country codes are affected. Cc: Luis R. Rodriguez Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 039ac490465c..04abd1f556b7 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -110,8 +110,9 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { static inline bool is_wwr_sku(u16 regd) { - return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || - (regd == WORLD); + return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && + (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || + (regd == WORLD)); } static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) -- GitLab From 209c671db7a917740ab9873d442b10ae7e369937 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sun, 7 Feb 2010 21:47:50 -0500 Subject: [PATCH 1755/3892] mac80211: make rate_control_alloc static rate_control_alloc is not used by anything outside of ieee80211_init_rate_ctrl_alg. Both are in rate.c; there's no reason to make rate_control_alloc visible outside of it. Signed-off-by: Andres Salomon Signed-off-by: John W. Linville --- net/mac80211/rate.c | 2 +- net/mac80211/rate.h | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c74b7c85403c..99ab24cc9783 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { }; #endif -struct rate_control_ref *rate_control_alloc(const char *name, +static struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local) { struct dentry *debugfsdir = NULL; diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 998cf7a935b6..b6108bca96d4 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -26,10 +26,6 @@ struct rate_control_ref { struct kref kref; }; -/* Get a reference to the rate control algorithm. If `name' is NULL, get the - * first available algorithm. */ -struct rate_control_ref *rate_control_alloc(const char *name, - struct ieee80211_local *local); void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc); @@ -116,7 +112,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } -/* functions for rate control related to a device */ +/* Get a reference to the rate control algorithm. If `name' is NULL, get the + * first available algorithm. */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name); void rate_control_deinitialize(struct ieee80211_local *local); -- GitLab From e15276a4b220c54db665cf46a92bd9ceb9aeb052 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Mon, 8 Feb 2010 17:47:01 +0530 Subject: [PATCH 1756/3892] mac80211: Reset dynamic ps timer in Rx path. The current mac80211 implementation enables power save if there is no Tx traffic for a specific timeout. Hence, PS is triggered even if there is a continuous Rx only traffic(like UDP) going on. This makes the drivers to wait on the tim bit in the next beacon to awake which leads to redundant sleep-wake cycles. Fix this by restarting the dynamic ps timer on receiving every data packet. Signed-off-by: Vivek Natarajan CC: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/rx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 01dba7618397..c9755f3d986c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1719,6 +1719,7 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_local *local = rx->local; struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; __le16 fc = hdr->frame_control; @@ -1750,6 +1751,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) dev->stats.rx_packets++; dev->stats.rx_bytes += rx->skb->len; + if (ieee80211_is_data(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1) && + local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + } + ieee80211_deliver_skb(rx); return RX_QUEUED; -- GitLab From 0f88009d5cfae890bd3466126d1622ad4f16b798 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 18 Jan 2010 10:14:51 -0600 Subject: [PATCH 1757/3892] [SCSI] scsi_transport_sas: add support for transport layer retries (TLR) The mpt2sas driver wants to use transport layer retries (TLR) so the simplest thing to do seems to be to add the enabling flags and checks to the SAS transport class, since they're a SAS specific protocol feature. Signed-off-by: James Bottomley --- drivers/scsi/scsi_sas_internal.h | 2 +- drivers/scsi/scsi_transport_sas.c | 103 ++++++++++++++++++++++++++++-- include/scsi/scsi_transport_sas.h | 7 ++ 3 files changed, 105 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index 998cb5be6833..6266a5d73d0f 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h @@ -5,7 +5,7 @@ #define SAS_PHY_ATTRS 17 #define SAS_PORT_ATTRS 1 #define SAS_RPORT_ATTRS 7 -#define SAS_END_DEV_ATTRS 3 +#define SAS_END_DEV_ATTRS 5 #define SAS_EXPANDER_ATTRS 7 struct sas_internal { diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index f27e52d963d3..927e99cb7225 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -155,6 +155,17 @@ static struct { sas_bitfield_name_search(linkspeed, sas_linkspeed_names) sas_bitfield_name_set(linkspeed, sas_linkspeed_names) +static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev) +{ + struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); + struct sas_end_device *rdev; + + BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); + + rdev = rphy_to_end_device(rphy); + return rdev; +} + static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, struct sas_rphy *rphy) { @@ -358,6 +369,85 @@ void sas_remove_host(struct Scsi_Host *shost) } EXPORT_SYMBOL(sas_remove_host); +/** + * sas_tlr_supported - checking TLR bit in vpd 0x90 + * @sdev: scsi device struct + * + * Check Transport Layer Retries are supported or not. + * If vpd page 0x90 is present, TRL is supported. + * + */ +unsigned int +sas_tlr_supported(struct scsi_device *sdev) +{ + const int vpd_len = 32; + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + char *buffer = kzalloc(vpd_len, GFP_KERNEL); + int ret = 0; + + if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len)) + goto out; + + /* + * Magic numbers: the VPD Protocol page (0x90) + * has a 4 byte header and then one entry per device port + * the TLR bit is at offset 8 on each port entry + * if we take the first port, that's at total offset 12 + */ + ret = buffer[12] & 0x01; + + out: + kfree(buffer); + rdev->tlr_supported = ret; + return ret; + +} +EXPORT_SYMBOL_GPL(sas_tlr_supported); + +/** + * sas_disable_tlr - setting TLR flags + * @sdev: scsi device struct + * + * Seting tlr_enabled flag to 0. + * + */ +void +sas_disable_tlr(struct scsi_device *sdev) +{ + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + + rdev->tlr_enabled = 0; +} +EXPORT_SYMBOL_GPL(sas_disable_tlr); + +/** + * sas_enable_tlr - setting TLR flags + * @sdev: scsi device struct + * + * Seting tlr_enabled flag 1. + * + */ +void sas_enable_tlr(struct scsi_device *sdev) +{ + unsigned int tlr_supported = 0; + tlr_supported = sas_tlr_supported(sdev); + + if (tlr_supported) { + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + + rdev->tlr_enabled = 1; + } + + return; +} +EXPORT_SYMBOL_GPL(sas_enable_tlr); + +unsigned int sas_is_tlr_enabled(struct scsi_device *sdev) +{ + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); + return rdev->tlr_enabled; +} +EXPORT_SYMBOL_GPL(sas_is_tlr_enabled); /* * SAS Phy attributes @@ -1146,15 +1236,10 @@ sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); int sas_read_port_mode_page(struct scsi_device *sdev) { char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; - struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); - struct sas_end_device *rdev; + struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); struct scsi_mode_data mode_data; int res, error; - BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); - - rdev = rphy_to_end_device(rphy); - if (!buffer) return -ENOMEM; @@ -1207,6 +1292,10 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, "%d\n", int); sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, "%d\n", int); +sas_end_dev_simple_attr(tlr_supported, tlr_supported, + "%d\n", int); +sas_end_dev_simple_attr(tlr_enabled, tlr_enabled, + "%d\n", int); static DECLARE_TRANSPORT_CLASS(sas_expander_class, "sas_expander", NULL, NULL, NULL); @@ -1733,6 +1822,8 @@ sas_attach_transport(struct sas_function_template *ft) SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); + SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported); + SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled); i->end_dev_attrs[count] = NULL; count = 0; diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 61ad3594aad6..ffeebc34a4f7 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h @@ -107,6 +107,8 @@ struct sas_end_device { struct sas_rphy rphy; /* flags */ unsigned ready_led_meaning:1; + unsigned tlr_supported:1; + unsigned tlr_enabled:1; /* parameters */ u16 I_T_nexus_loss_timeout; u16 initiator_response_timeout; @@ -181,6 +183,11 @@ extern int sas_phy_add(struct sas_phy *); extern void sas_phy_delete(struct sas_phy *); extern int scsi_is_sas_phy(const struct device *); +unsigned int sas_tlr_supported(struct scsi_device *); +unsigned int sas_is_tlr_enabled(struct scsi_device *); +void sas_disable_tlr(struct scsi_device *); +void sas_enable_tlr(struct scsi_device *); + extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); void sas_rphy_free(struct sas_rphy *); -- GitLab From d7384b28afb2bf2b7be835ddc8c852bdc5e0ce1c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:50:06 +0530 Subject: [PATCH 1758/3892] [SCSI] mpt2sas: Delete volume before HBA detach. The driver hangs when doing `rmmod mpt2sas` if there are any IR volumes present.The hang is due the scsi midlayer trying to access the IR volumes after the driver releases controller resources. Perhaps when scsi_remove_host is called,the scsi mid layer is sending some request. This doesn't occur for bare drives becuase the driver is already reporting those drives deleted prior to calling mpt2sas_base_detach. To solve this issue, we need to delete the volumes as well. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index efabea1a3ce4..cd551768bfbf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -5998,6 +5998,8 @@ _scsih_remove(struct pci_dev *pdev) struct _sas_port *mpt2sas_port; struct _sas_device *sas_device; struct _sas_node *expander_sibling; + struct _raid_device *raid_device, *next; + struct MPT2SAS_TARGET *sas_target_priv_data; struct workqueue_struct *wq; unsigned long flags; @@ -6011,6 +6013,21 @@ _scsih_remove(struct pci_dev *pdev) if (wq) destroy_workqueue(wq); + /* release all the volumes */ + list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, + list) { + if (raid_device->starget) { + sas_target_priv_data = + raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + scsi_remove_target(&raid_device->starget->dev); + } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); + _scsih_raid_device_remove(ioc, raid_device); + } + /* free ports attached to the sas_host */ retry_again: list_for_each_entry(mpt2sas_port, -- GitLab From b2ff36ba19dec02b05d3e26e36923b71ab64f34a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:51:05 +0530 Subject: [PATCH 1759/3892] [SCSI] mpt2sas: Return -ENODATA on IOCTL timeout The driver was modified to return -ENODATA when there is a timeout via ioctl path. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 84a124f8e21f..198ecdd849a4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -891,6 +891,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, issue_host_reset: if (issue_reset) { + ret = -ENODATA; if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { -- GitLab From 6846e75cdfa76c6609ac0381a6739c9f4af8fd3b Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:51:45 +0530 Subject: [PATCH 1760/3892] [SCSI] mpt2sas: User resource_size_t instead of unsigned long Use resource_size_t to define the type resource for the system interface register set. The existing implementation was using "unsigned long" which would be 32 bit in 32 bit OS. If 32 bit OS is using 64 bit physical address space for the system interface register set, we need to shift to using resource_size_t which takes care of physical address space. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 13 ++++++++----- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 +--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 89d02401b9ec..bbd4f713d332 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1222,6 +1222,8 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) u32 memap_sz; u32 pio_sz; int i, r = 0; + u64 pio_chip = 0; + u64 chip_phys = 0; dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, __func__)); @@ -1255,12 +1257,13 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { if (pio_sz) continue; - ioc->pio_chip = pci_resource_start(pdev, i); + pio_chip = (u64)pci_resource_start(pdev, i); pio_sz = pci_resource_len(pdev, i); } else { if (memap_sz) continue; ioc->chip_phys = pci_resource_start(pdev, i); + chip_phys = (u64)ioc->chip_phys; memap_sz = pci_resource_len(pdev, i); ioc->chip = ioremap(ioc->chip_phys, memap_sz); if (ioc->chip == NULL) { @@ -1280,10 +1283,10 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : "IO-APIC enabled"), ioc->pci_irq); - printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n", - ioc->name, ioc->chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n", - ioc->name, ioc->pio_chip, pio_sz); + printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", + ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); + printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", + ioc->name, (unsigned long long)pio_chip, pio_sz); return 0; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index bb4f14656afa..12fa18be77e1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -464,7 +464,6 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @pdev: pci pdev object * @chip: memory mapped register space * @chip_phys: physical addrss prior to mapping - * @pio_chip: I/O mapped register space * @logging_level: see mpt2sas_debug.h * @fwfault_debug: debuging FW timeouts * @ir_firmware: IR firmware present @@ -587,8 +586,7 @@ struct MPT2SAS_ADAPTER { char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; - unsigned long chip_phys; - unsigned long pio_chip; + resource_size_t chip_phys; int logging_level; int fwfault_debug; u8 ir_firmware; -- GitLab From e75b9b6d9d81e35aed5ef2692285c4948e173c5c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:52:39 +0530 Subject: [PATCH 1761/3892] [SCSI] mpt2sas: Set ioc->fwfault_debug to the cmd line option mpt2sas_fwfault_debug. (1) change the formentioned string from logging_level to fwfault_debug (2) set ioc->fwfault_debug to the command line option mpt2sas_fwfault_debug setting at driver load time. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index bbd4f713d332..88e6eebc3159 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -107,8 +107,7 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) if (ret) return ret; - printk(KERN_INFO "setting logging_level(0x%08x)\n", - mpt2sas_fwfault_debug); + printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) ioc->fwfault_debug = mpt2sas_fwfault_debug; return 0; @@ -3576,6 +3575,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) init_waitqueue_head(&ioc->reset_wq); + ioc->fwfault_debug = mpt2sas_fwfault_debug; + /* base internal command bits */ mutex_init(&ioc->base_cmds.mutex); ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -- GitLab From 22c88425e03e8476176375ab0457c88ff3a5b68c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:53:04 +0530 Subject: [PATCH 1762/3892] [SCSI] mpt2sas: Use compat_ptr to setup the pointer compatibility. On ppc64, an 32bit application was failing due to data buffers not being copied properly from user to kernel memory. The problem due to improper conversion of 32 to 64 bit pointers. The fix is to use compat_ptr to setup the pointer compatibility in the routine _ctl_compat_mpt_command. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 198ecdd849a4..fa9bf83819d5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -2203,14 +2203,10 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) karg.data_out_size = karg32.data_out_size; karg.max_sense_bytes = karg32.max_sense_bytes; karg.data_sge_offset = karg32.data_sge_offset; - memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr, - sizeof(uint32_t)); - memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr, - sizeof(uint32_t)); + karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); + karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); + karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); + karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); } -- GitLab From f7c95ef02b564d9984c0655c9659791b1dd5d7ad Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:54:42 +0530 Subject: [PATCH 1763/3892] [SCSI] mpt2sas: Added raid transport support Adding support for raid transport layer. This will provide sysfs attributes containing raid level, state, and resync rate. MPT2SAS module will select RAID_ATTRS. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/Kconfig | 1 + drivers/scsi/mpt2sas/mpt2sas_base.h | 2 + drivers/scsi/mpt2sas/mpt2sas_scsih.c | 190 ++++++++++++++++++++++++++- include/linux/raid_class.h | 1 + 4 files changed, 190 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index 70c4c2467dd8..ba8e128de238 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -44,6 +44,7 @@ config SCSI_MPT2SAS tristate "LSI MPT Fusion SAS 2.0 Device Driver" depends on PCI && SCSI select SCSI_SAS_ATTRS + select RAID_ATTRS ---help--- This driver supports PCI-Express SAS 6Gb/s Host Adapters. diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 12fa18be77e1..014318fa3b0e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -323,6 +323,7 @@ struct _sas_device { * @device_info: bitfield provides detailed info about the hidden components * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding + * @percent_complete: resync percent complete */ struct _raid_device { struct list_head list; @@ -336,6 +337,7 @@ struct _raid_device { u32 device_info; u8 num_pds; u8 responding; + u8 percent_complete; }; /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index cd551768bfbf..ca984cbc8e2f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "mpt2sas_base.h" @@ -133,6 +134,9 @@ struct fw_event_work { void *event_data; }; +/* raid transport support */ +static struct raid_template *mpt2sas_raid_template; + /** * struct _scsi_io_transfer - scsi io transfer * @handle: sas device handle (assigned by firmware) @@ -1418,6 +1422,140 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); } +/** + * _scsih_is_raid - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int +_scsih_is_raid(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return (sdev->channel == RAID_CHANNEL) ? 1 : 0; +} + +/** + * _scsih_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void +_scsih_get_resync(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volume_status_flags; + u8 percent_complete = 0; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) + percent_complete = raid_device->percent_complete; + out: + raid_set_resync(mpt2sas_raid_template, dev, percent_complete); +} + +/** + * _scsih_get_state - get raid volume level + * @dev the device struct object + */ +static void +_scsih_get_state(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volstate; + enum raid_state state = RAID_STATE_UNKNOWN; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { + state = RAID_STATE_RESYNCING; + goto out; + } + + switch (vol_pg0.VolumeState) { + case MPI2_RAID_VOL_STATE_OPTIMAL: + case MPI2_RAID_VOL_STATE_ONLINE: + state = RAID_STATE_ACTIVE; + break; + case MPI2_RAID_VOL_STATE_DEGRADED: + state = RAID_STATE_DEGRADED; + break; + case MPI2_RAID_VOL_STATE_FAILED: + case MPI2_RAID_VOL_STATE_MISSING: + state = RAID_STATE_OFFLINE; + break; + } + out: + raid_set_state(mpt2sas_raid_template, dev, state); +} + +/** + * _scsih_set_level - set raid level + * @sdev: scsi device struct + * @raid_device: raid_device object + */ +static void +_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) +{ + enum raid_level level = RAID_LEVEL_UNKNOWN; + + switch (raid_device->volume_type) { + case MPI2_RAID_VOL_TYPE_RAID0: + level = RAID_LEVEL_0; + break; + case MPI2_RAID_VOL_TYPE_RAID10: + level = RAID_LEVEL_10; + break; + case MPI2_RAID_VOL_TYPE_RAID1E: + level = RAID_LEVEL_1E; + break; + case MPI2_RAID_VOL_TYPE_RAID1: + level = RAID_LEVEL_1; + break; + } + + raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); +} + /** * _scsih_get_volume_capabilities - volume capabilities * @ioc: per adapter object @@ -1574,6 +1712,8 @@ _scsih_slave_configure(struct scsi_device *sdev) (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + /* raid transport support */ + _scsih_set_level(sdev, raid_device); return 0; } @@ -5170,11 +5310,33 @@ static void _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { + Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data; + static struct _raid_device *raid_device; + unsigned long flags; + u16 handle; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_ir_operation_status_event_debug(ioc, - fw_event->event_data); + event_data); #endif + + /* code added for raid transport support */ + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { + + handle = le16_to_cpu(event_data->VolDevHandle); + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + return; + + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) + raid_device->percent_complete = + event_data->PercentComplete; + } } /** @@ -6390,6 +6552,13 @@ static struct pci_driver scsih_driver = { #endif }; +/* raid transport support */ +static struct raid_function_template mpt2sas_raid_functions = { + .cookie = &scsih_driver_template, + .is_raid = _scsih_is_raid, + .get_resync = _scsih_get_resync, + .get_state = _scsih_get_state, +}; /** * _scsih_init - main entry point for this driver. @@ -6409,6 +6578,12 @@ _scsih_init(void) sas_attach_transport(&mpt2sas_transport_functions); if (!mpt2sas_transport_template) return -ENODEV; + /* raid transport support */ + mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); + if (!mpt2sas_raid_template) { + sas_release_transport(mpt2sas_transport_template); + return -ENODEV; + } mpt2sas_base_initialize_callback_handler(); @@ -6443,8 +6618,11 @@ _scsih_init(void) mpt2sas_ctl_init(); error = pci_register_driver(&scsih_driver); - if (error) + if (error) { + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); sas_release_transport(mpt2sas_transport_template); + } return error; } @@ -6462,7 +6640,8 @@ _scsih_exit(void) pci_unregister_driver(&scsih_driver); - sas_release_transport(mpt2sas_transport_template); + mpt2sas_ctl_exit(); + mpt2sas_base_release_callback_handler(scsi_io_cb_idx); mpt2sas_base_release_callback_handler(tm_cb_idx); mpt2sas_base_release_callback_handler(base_cb_idx); @@ -6474,7 +6653,10 @@ _scsih_exit(void) mpt2sas_base_release_callback_handler(tm_tr_cb_idx); mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); - mpt2sas_ctl_exit(); + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); + sas_release_transport(mpt2sas_transport_template); + } module_init(_scsih_init); diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h index 6b537f1ac96c..31e1ff69efc8 100644 --- a/include/linux/raid_class.h +++ b/include/linux/raid_class.h @@ -32,6 +32,7 @@ enum raid_level { RAID_LEVEL_0, RAID_LEVEL_1, RAID_LEVEL_10, + RAID_LEVEL_1E, RAID_LEVEL_3, RAID_LEVEL_4, RAID_LEVEL_5, -- GitLab From 50d5c60634673a79f8d88564e10345b50fca7378 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:55:26 +0530 Subject: [PATCH 1764/3892] [SCSI] mpt2sas: Added phy_enable and set_phy_speed sysfs callback support. Added new callbacks phy_enable and set_phy_speed in the mpt2sas_transport_functions template. This will allow end user to enable/disable phys and change links rates using the SysFS interface. Current implementation only supports direct attached phys, but we could in the future add support for expander based phys. A new subroutine mpt2sas_config_set_sas_iounit_pg1 was added; this wrapper function used to send request to controller firmware to modify the phys and link rates. A new subroutine _transport_find_local_phy was added; a function for easly obtaining the local phy object for direct attached. Example to disable a phy echo 0 > /sys/class/phy3:0/enable Example to enable the same phy echo 1 > /sys/class/phy3:0/enable Example to change the link rate to 1.5 #echo "1.5 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 1.5 Gbit Example to change the link rate to 3.0 #echo "3.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 3.0 Gbit Example to change the link rate to 6.0 #echo "6.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 6.0 Gbit Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 + drivers/scsi/mpt2sas/mpt2sas_config.c | 51 +++++- drivers/scsi/mpt2sas/mpt2sas_transport.c | 196 +++++++++++++++++++++-- 3 files changed, 232 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 014318fa3b0e..93c067f5dbbc 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -853,6 +853,8 @@ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); +int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page); int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 594a389c6526..411c27d7f787 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -324,7 +324,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t if (r != 0) goto out; if (mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT) { + MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || + mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { ioc->base_add_sg_single(&mpi_request->PageBufferSGE, MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, mem.page_dma); @@ -882,7 +884,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t } /** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0 + * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page @@ -907,7 +909,7 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); @@ -921,6 +923,49 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t return r; } +/** + * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Calling function should call config_get_number_hba_phys prior to + * this function, so enough memory is allocated for config_page. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: + return r; +} + /** * mpt2sas_config_get_expander_pg0 - obtain expander page 0 * @ioc: per adapter object diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 3a82872bad44..789f9ee7f001 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -855,6 +855,17 @@ rphy_to_ioc(struct sas_rphy *rphy) return shost_priv(shost); } +static struct _sas_phy * +_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy) +{ + int i; + + for (i = 0; i < ioc->sas_hba.num_phys; i++) + if (ioc->sas_hba.phy[i].phy == phy) + return(&ioc->sas_hba.phy[i]); + return NULL; +} + /** * _transport_get_linkerrors - * @phy: The sas phy object @@ -870,14 +881,8 @@ _transport_get_linkerrors(struct sas_phy *phy) struct _sas_phy *mpt2sas_phy; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; - int i; - for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && - !mpt2sas_phy; i++) { - if (ioc->sas_hba.phy[i].phy != phy) - continue; - mpt2sas_phy = &ioc->sas_hba.phy[i]; - } + mpt2sas_phy = _transport_find_local_phy(ioc, phy); if (!mpt2sas_phy) /* this phy not on sas_host */ return -EINVAL; @@ -971,14 +976,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) struct _sas_phy *mpt2sas_phy; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; - int i; - for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && - !mpt2sas_phy; i++) { - if (ioc->sas_hba.phy[i].phy != phy) - continue; - mpt2sas_phy = &ioc->sas_hba.phy[i]; - } + mpt2sas_phy = _transport_find_local_phy(ioc, phy); if (!mpt2sas_phy) /* this phy not on sas_host */ return -EINVAL; @@ -1005,6 +1004,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) return 0; } +/** + * _transport_phy_enable - enable/disable phys + * @phy: The sas phy object + * @enable: enable phy when true + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_enable(struct sas_phy *phy, int enable) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int rc = 0; + + mpt2sas_phy = _transport_find_local_phy(ioc, phy); + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + if (enable) + sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + else + sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + + mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); + + out: + kfree(sas_iounit_pg1); + return rc; +} + +/** + * _transport_phy_speed - set phy min/max link rates + * @phy: The sas phy object + * @rates: rates defined in sas_phy_linkrates + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasPhyPage0_t phy_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int i; + int rc = 0; + + mpt2sas_phy = _transport_find_local_phy(ioc, phy); + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + if (!rates->minimum_linkrate) + rates->minimum_linkrate = phy->minimum_linkrate; + else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) + rates->minimum_linkrate = phy->minimum_linkrate_hw; + + if (!rates->maximum_linkrate) + rates->maximum_linkrate = phy->maximum_linkrate; + else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) + rates->maximum_linkrate = phy->maximum_linkrate_hw; + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + for (i = 0; i < ioc->sas_hba.num_phys; i++) { + if (mpt2sas_phy->phy_id != i) { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (ioc->sas_hba.phy[i].phy->minimum_linkrate + + (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); + } else { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (rates->minimum_linkrate + + (rates->maximum_linkrate << 4)); + } + } + + if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, + sz)) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + + /* link reset */ + _transport_phy_reset(phy, 0); + + /* read phy page 0, then update the rates in the sas transport phy */ + if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, + mpt2sas_phy->phy_id)) { + phy->minimum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); + phy->maximum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate >> 4); + phy->negotiated_linkrate = _transport_convert_phy_link_rate( + phy_pg0.NegotiatedLinkRate & + MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); + } + + out: + kfree(sas_iounit_pg1); + return rc; +} + + /** * _transport_smp_handler - transport portal for smp passthru * @shost: shost object @@ -1207,6 +1373,8 @@ struct sas_function_template mpt2sas_transport_functions = { .get_enclosure_identifier = _transport_get_enclosure_identifier, .get_bay_identifier = _transport_get_bay_identifier, .phy_reset = _transport_phy_reset, + .phy_enable = _transport_phy_enable, + .set_phy_speed = _transport_phy_speed, .smp_handler = _transport_smp_handler, }; -- GitLab From f4af3c14113d1b0d98d5a5e717b8aa1f484065b6 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:55:54 +0530 Subject: [PATCH 1765/3892] [SCSI] mpt2sas: Update driver header to latest MPI Spec. Update header to latest MPI SPEC revision. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpi/mpi2.h | 16 +++- drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 25 +++++- drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 93 +++++++++++++++++------ drivers/scsi/mpt2sas/mpi/mpi2_init.h | 24 +++++- drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 77 ++++++++++++++++--- drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 6 +- 6 files changed, 201 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 914168105297..9958d847a88d 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.13 + * mpi2.h Version: 02.00.14 * * Version History * --------------- @@ -53,6 +53,10 @@ * bytes reserved. * Added RAID Accelerator functionality. * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. * -------------------------------------------------------------------------- */ @@ -78,7 +82,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x0D) +#define MPI2_HEADER_VERSION_UNIT (0x0E) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -232,9 +236,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS #define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) /* - * Offset for the Reply Descriptor Post Queue + * Defines for the Reply Descriptor Post Queue */ #define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) +#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) +#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) +#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) /* * Defines for the HCBSize and address @@ -497,12 +504,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ #define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ #define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ +/* Host Based Discovery Action */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Doorbell functions */ #define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */ #define MPI2_FUNCTION_HANDSHAKE (0x42) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 1611c57a6fdf..cf0ac9f40c97 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.12 + * mpi2_cnfg.h Version: 02.00.13 * * Version History * --------------- @@ -107,6 +107,8 @@ * to SAS Device Page 0 Flags field. * Added PhyInfo defines for power condition. * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. * -------------------------------------------------------------------------- */ @@ -712,6 +714,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 #define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) /* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) @@ -2291,6 +2294,26 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { #define MPI2_SASPHY3_PAGEVERSION (0x00) +/* SAS PHY Page 4 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x08 */ + U8 Reserved2; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, + Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; + +#define MPI2_SASPHY4_PAGEVERSION (0x00) + +/* values for the Flags field */ +#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) + + + + /**************************************************************************** * SAS Port Config Pages ****************************************************************************/ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt index 65fcaa31cb30..c4adf76b49d9 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -5,23 +5,24 @@ Copyright (c) 2000-2009 LSI Corporation. --------------------------------------- - Header Set Release Version: 02.00.12 - Header Set Release Date: 05-06-09 + Header Set Release Version: 02.00.14 + Header Set Release Date: 10-28-09 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi2.h 02.00.12 02.00.11 - mpi2_cnfg.h 02.00.11 02.00.10 - mpi2_init.h 02.00.07 02.00.06 - mpi2_ioc.h 02.00.11 02.00.10 - mpi2_raid.h 02.00.03 02.00.03 - mpi2_sas.h 02.00.02 02.00.02 + mpi2.h 02.00.14 02.00.13 + mpi2_cnfg.h 02.00.13 02.00.12 + mpi2_init.h 02.00.08 02.00.07 + mpi2_ioc.h 02.00.13 02.00.12 + mpi2_raid.h 02.00.04 02.00.04 + mpi2_sas.h 02.00.03 02.00.02 mpi2_targ.h 02.00.03 02.00.03 - mpi2_tool.h 02.00.03 02.00.02 + mpi2_tool.h 02.00.04 02.00.04 mpi2_type.h 02.00.00 02.00.00 - mpi2_ra.h 02.00.00 - mpi2_history.txt 02.00.11 02.00.12 + mpi2_ra.h 02.00.00 02.00.00 + mpi2_hbd.h 02.00.00 + mpi2_history.txt 02.00.14 02.00.13 * Date Version Description @@ -65,6 +66,11 @@ mpi2.h * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those * bytes reserved. * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. * -------------------------------------------------------------------------- mpi2_cnfg.h @@ -155,6 +161,15 @@ mpi2_cnfg.h * Added expander reduced functionality data to SAS * Expander Page 0. * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. * -------------------------------------------------------------------------- mpi2_init.h @@ -172,6 +187,10 @@ mpi2_init.h * Query Asynchronous Event. * Defined two new bits in the SlotStatus field of the SCSI * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * -------------------------------------------------------------------------- mpi2_ioc.h @@ -246,6 +265,20 @@ mpi2_ioc.h * Added two new reason codes for SAS Device Status Change * Event. * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). * -------------------------------------------------------------------------- mpi2_raid.h @@ -256,6 +289,8 @@ mpi2_raid.h * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. * -------------------------------------------------------------------------- mpi2_sas.h @@ -264,6 +299,8 @@ mpi2_sas.h * Control Request. * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. * -------------------------------------------------------------------------- mpi2_targ.h @@ -283,6 +320,10 @@ mpi2_tool.h * structures and defines. * 02-29-08 02.00.02 Modified various names to make them 32-character unique. * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. * -------------------------------------------------------------------------- mpi2_type.h @@ -293,20 +334,26 @@ mpi2_ra.h * 05-06-09 02.00.00 Initial version. * -------------------------------------------------------------------------- +mpi2_hbd.h + * 10-28-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + + mpi2_history.txt Parts list history -Filename 02.00.12 ----------- -------- -mpi2.h 02.00.12 -mpi2_cnfg.h 02.00.11 -mpi2_init.h 02.00.07 -mpi2_ioc.h 02.00.11 -mpi2_raid.h 02.00.03 -mpi2_sas.h 02.00.02 -mpi2_targ.h 02.00.03 -mpi2_tool.h 02.00.03 -mpi2_type.h 02.00.00 -mpi2_ra.h 02.00.00 +Filename 02.00.14 02.00.13 02.00.12 +---------- -------- -------- -------- +mpi2.h 02.00.14 02.00.13 02.00.12 +mpi2_cnfg.h 02.00.13 02.00.12 02.00.11 +mpi2_init.h 02.00.08 02.00.07 02.00.07 +mpi2_ioc.h 02.00.13 02.00.12 02.00.11 +mpi2_raid.h 02.00.04 02.00.04 02.00.03 +mpi2_sas.h 02.00.03 02.00.02 02.00.02 +mpi2_targ.h 02.00.03 02.00.03 02.00.03 +mpi2_tool.h 02.00.04 02.00.04 02.00.03 +mpi2_type.h 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.00 Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 563e56d2e945..6541945e97c3 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -6,7 +6,7 @@ * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * - * mpi2_init.h Version: 02.00.07 + * mpi2_init.h Version: 02.00.08 * * Version History * --------------- @@ -27,6 +27,10 @@ * Query Asynchronous Event. * Defined two new bits in the SlotStatus field of the SCSI * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * -------------------------------------------------------------------------- */ @@ -254,6 +258,11 @@ typedef struct _MPI2_SCSI_IO_REPLY #define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) #define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) + #define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) @@ -327,6 +336,7 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY U16 IOCStatus; /* 0x0E */ U32 IOCLogInfo; /* 0x10 */ U32 TerminationCount; /* 0x14 */ + U32 ResponseInfo; /* 0x18 */ } MPI2_SCSI_TASK_MANAGE_REPLY, MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; @@ -339,8 +349,20 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY #define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) #define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) #define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) #define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) + /**************************************************************************** * SCSI Enclosure Processor messages diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index ea51ce868690..754938422f6a 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.12 + * mpi2_ioc.h Version: 02.00.13 * * Version History * --------------- @@ -87,6 +87,17 @@ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). * -------------------------------------------------------------------------- */ @@ -119,8 +130,10 @@ typedef struct _MPI2_IOC_INIT_REQUEST U16 MsgVersion; /* 0x0C */ U16 HeaderVersion; /* 0x0E */ U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ - U16 Reserved7; /* 0x18 */ + U16 Reserved6; /* 0x14 */ + U8 Reserved7; /* 0x16 */ + U8 HostMSIxVectors; /* 0x17 */ + U16 Reserved8; /* 0x18 */ U16 SystemRequestFrameSize; /* 0x1A */ U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ U16 ReplyFreeQueueDepth; /* 0x1E */ @@ -215,7 +228,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxChainDepth; /* 0x14 */ U8 WhoInit; /* 0x15 */ U8 NumberOfPorts; /* 0x16 */ - U8 Reserved2; /* 0x17 */ + U8 MaxMSIxVectors; /* 0x17 */ U16 RequestCredit; /* 0x18 */ U16 ProductID; /* 0x1A */ U32 IOCCapabilities; /* 0x1C */ @@ -233,7 +246,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxVolumes; /* 0x37 */ U16 MaxDevHandle; /* 0x38 */ U16 MaxPersistentEntries; /* 0x3A */ - U32 Reserved4; /* 0x3C */ + U16 MinDevHandle; /* 0x3C */ + U16 Reserved4; /* 0x3E */ } MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; @@ -269,6 +283,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY /* ProductID field uses MPI2_FW_HEADER_PID_ */ /* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) #define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) #define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) #define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) @@ -453,6 +468,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) #define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) #define MPI2_EVENT_GPIO_INTERRUPT (0x0023) +#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) /* Log Entry Added Event data */ @@ -793,6 +809,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; /* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) #define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) #define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) #define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) @@ -878,6 +895,44 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { * */ +/* Host Based Discovery Phy Event data */ + +typedef struct _MPI2_EVENT_HBD_PHY_SAS { + U8 Flags; /* 0x00 */ + U8 NegotiatedLinkRate; /* 0x01 */ + U8 PhyNum; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U32 Reserved1; /* 0x04 */ + U8 InitialFrame[28]; /* 0x08 */ +} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, + Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; + +/* values for the Flags field */ +#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) +#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for + * the NegotiatedLinkRate field */ + +typedef union _MPI2_EVENT_HBD_DESCRIPTOR { + MPI2_EVENT_HBD_PHY_SAS Sas; +} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, + Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; + +typedef struct _MPI2_EVENT_DATA_HBD_PHY { + U8 DescriptorType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ +} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, + Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; + +/* values for the DescriptorType field */ +#define MPI2_EVENT_HBD_DT_SAS (0x01) + + + /**************************************************************************** * EventAck message ****************************************************************************/ @@ -1126,13 +1181,17 @@ typedef struct _MPI2_FW_IMAGE_HEADER #define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) + #define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) /* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010) -#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011) +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) /* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h index 8a42b136cf53..2d8aeed51392 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h @@ -6,7 +6,7 @@ * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: February 9, 2007 * - * mpi2.h Version: 02.00.02 + * mpi2.h Version: 02.00.03 * * Version History * --------------- @@ -18,6 +18,8 @@ * Control Request. * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. * -------------------------------------------------------------------------- */ @@ -160,7 +162,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST U32 Reserved4; /* 0x14 */ U32 DataLength; /* 0x18 */ U8 CommandFIS[20]; /* 0x1C */ - MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ + MPI2_SGE_IO_UNION SGL; /* 0x20 */ } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; -- GitLab From 84f0b04a0e3b279a0b0a851b93eb403a626ca4b8 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:56:28 +0530 Subject: [PATCH 1766/3892] [SCSI] mpt2sas: Enable TLR for SSP TAPE drives (Added SAS Transport APIs) If TLR is supported for end device, MPT2SAS driver will enable the TLR bit in the SCSI_IO for every request. If there is a response with MPI2_SCSITASKMGMT_RSP_INVALID_FRAME, the driver will turn off the TLR logic. [jejb: updated to new transport class TLR API] Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 55 ++++++++++++++++++---------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index ca984cbc8e2f..344a22ad2f33 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1309,7 +1309,6 @@ _scsih_slave_alloc(struct scsi_device *sdev) struct MPT2SAS_DEVICE *sas_device_priv_data; struct scsi_target *starget; struct _raid_device *raid_device; - struct _sas_device *sas_device; unsigned long flags; sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); @@ -1336,21 +1335,8 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (raid_device) raid_device->sdev = sdev; /* raid is single lun */ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } else { - /* set TLR bit for SSP devices */ - if (!(ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TLR)) - goto out; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SSP_TARGET) - sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON; } - out: return 0; } @@ -1616,6 +1602,32 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, kfree(vol_pg0); } +/** + * _scsih_enable_tlr - setting TLR flags + * @ioc: per adapter object + * @sdev: scsi device struct + * + * Enabling Transaction Layer Retries for tape devices when + * vpd page 0x90 is present + * + */ +static void +_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) +{ + /* only for TAPE */ + if (sdev->type != TYPE_TAPE) + return; + + if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) + return; + + sas_enable_tlr(sdev); + sdev_printk(KERN_INFO, sdev, "TLR %s\n", + sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); + return; + +} + /** * _scsih_slave_configure - device configure routine. * @sdev: scsi device struct @@ -1761,8 +1773,10 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); - if (ssp_target) + if (ssp_target) { sas_read_port_mode_page(sdev); + _scsih_enable_tlr(ioc, sdev); + } return 0; } @@ -3049,7 +3063,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } else mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON)) + if (sas_is_tlr_enabled(scmd->device)) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); @@ -3438,10 +3452,11 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; + if (sas_is_tlr_enabled(scmd->device) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { + sas_disable_tlr(scmd->device); + sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); + } } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); -- GitLab From e4b8972c6172950ce226afdf7a921098f7672d5c Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 16 Dec 2009 18:57:02 +0530 Subject: [PATCH 1767/3892] [SCSI] mpt2sas: Bump version 04.100.01.00 Version upgraded to 04.100.01.00. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 93c067f5dbbc..e18b0544c38f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,10 +69,10 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "03.100.03.00" -#define MPT2SAS_MAJOR_VERSION 03 +#define MPT2SAS_DRIVER_VERSION "04.100.01.00" +#define MPT2SAS_MAJOR_VERSION 04 #define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 03 +#define MPT2SAS_BUILD_VERSION 01 #define MPT2SAS_RELEASE_VERSION 00 /* -- GitLab From 48bd86cf213a5780346b603b703c4b83978611a8 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:50:19 +0530 Subject: [PATCH 1768/3892] [SCSI] be2iscsi: Fixing Bug for multiple SGEs The patch fixes a but where the sg_next is not assigned and hence the first sge was being resused wrongly Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 9fc4446b21e0..d611a13dabf0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1711,7 +1711,8 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, io_task->bhs_pa.u.a32.address_hi); l_sg = sg; - for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) { + for (index = 0; (index < num_sg) && (index < 2); index++, + sg = sg_next(sg)) { if (index == 0) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); @@ -1755,7 +1756,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, psgl++; psgl++; offset = 0; - for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) { + for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, -- GitLab From aa3590329fdf789902e3c1383589bad12a74fb09 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:51:04 +0530 Subject: [PATCH 1769/3892] [SCSI] be2iscsi: Fixing the number of SGE's The number of SGE's supported is fixed to what the chip expects. Also, the max sectors set to tested values Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 4cde8f6eb5bc..13ff02c1fcaa 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -56,10 +56,10 @@ #define BE2_DEFPDU_DATA_SZ 8192 #define MAX_CPUS 31 -#define BEISCSI_SGLIST_ELEMENTS BE2_SGE +#define BEISCSI_SGLIST_ELEMENTS 30 #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ +#define BEISCSI_MAX_SECTORS 256 /* scsi_host->max_sectors */ #define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ #define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */ -- GitLab From a3babda5b3b60b5d28dbab127b1ecc8ba707b6e7 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 7 Jan 2010 01:51:44 +0530 Subject: [PATCH 1770/3892] [SCSI] be2iscsi: Fix to allow driver to load when the FW allows more cids This fix allows the driver to load when the FW allows more cids than than the driver supports. The driver will limit the number of cid to what it can support. There was no reason to fail the driver load,so, correcting that Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 18f80411aef6..b0bb54dafbe9 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -49,12 +49,12 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, phba->fw_config.iscsi_cid_count = pfw_cfg->ulp[0].sq_count; if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { - status = 1; - shost_printk(KERN_WARNING, phba->shost, - "FW reported MAX CXNS as %d \t" - "Max Supported = %d. Failing to load \n", - phba->fw_config.iscsi_cid_count, - BE2_MAX_SESSIONS); + SE_DEBUG(DBG_LVL_8, + "FW reported MAX CXNS as %d \t" + "Max Supported = %d.\n", + phba->fw_config.iscsi_cid_count, + BE2_MAX_SESSIONS); + phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2; } } else { shost_printk(KERN_WARNING, phba->shost, -- GitLab From d44a6d2bbffd9e5c87f0a78cbe9c089e21289162 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 17 Jan 2010 16:15:57 +0100 Subject: [PATCH 1771/3892] [SCSI] lpfc: unify two if branches with the same code in lpfc_decode_firmware_rev() Regardless of the flag state, the branches execute the same code Signed-off-by: Roel Kluin Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_ct.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 0ebcd9baca79..bf7bf62e81eb 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1843,12 +1843,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) c = (rev & 0x0000ff00) >> 8; b4 = (rev & 0x000000ff); - if (flag) - sprintf(fwrevision, "%d.%d%d%c%d ", b1, - b2, b3, c, b4); - else - sprintf(fwrevision, "%d.%d%d%c%d ", b1, - b2, b3, c, b4); + sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4); } return; } -- GitLab From fa4698fcf59c3bd01c171e5e558bae9e8eb396f1 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 18 Jan 2010 18:43:18 -0500 Subject: [PATCH 1772/3892] [SCSI] sd: Combine DIF/DIX error handling DIF and DIX errors are handled identically at this point. Collapse the switch cases into one and let scsi_io_completion print result and sense data. Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c5e9a99d4066..908d400b601a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1196,19 +1196,10 @@ static int sd_done(struct scsi_cmnd *SCpnt) SCpnt->result = 0; memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); break; - case ABORTED_COMMAND: - if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */ - scsi_print_result(SCpnt); - scsi_print_sense("sd", SCpnt); + case ABORTED_COMMAND: /* DIF: Target detected corruption */ + case ILLEGAL_REQUEST: /* DIX: Host detected corruption */ + if (sshdr.asc == 0x10) good_bytes = sd_completed_bytes(SCpnt); - } - break; - case ILLEGAL_REQUEST: - if (sshdr.asc == 0x10) { /* DIX: HBA detected corruption */ - scsi_print_result(SCpnt); - scsi_print_sense("sd", SCpnt); - good_bytes = sd_completed_bytes(SCpnt); - } break; default: break; -- GitLab From d0e2ddff7c4b493acff50a9000564b67cbe7d676 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 19 Jan 2010 10:24:40 -0800 Subject: [PATCH 1773/3892] [SCSI] vmw_pvscsi: fix signedness warning with newer compilers pvscsi_setup_msix() expects 'irq' argument to be an int but is being passed unsigned int. Unsigned int is more proper type for IRQ number so let's use it. This shuts off a compile warning with recent compilers. Signed-off-by: Dmitry Torokhov Acked-by: Alok Kataria Signed-off-by: James Bottomley --- drivers/scsi/vmw_pvscsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index d2604c813a20..e4ac5829b637 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -1069,7 +1069,8 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); } -static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq) +static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, + unsigned int *irq) { struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; int ret; -- GitLab From 32951dd8cd70e525eb523c9e2b62d79d9157fae9 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:34:24 +0530 Subject: [PATCH 1774/3892] [SCSI] be2iscsi: Remove Ring mode from driver Ring mode is not used. This patch removes the code. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 181 ++++++-------------------------- 1 file changed, 33 insertions(+), 148 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d611a13dabf0..522e7d526331 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -40,7 +40,6 @@ static unsigned int be_iopoll_budget = 10; static unsigned int be_max_phys_size = 64; static unsigned int enable_msix = 1; -static unsigned int ring_mode; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); @@ -671,9 +670,7 @@ static void free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, struct wrb_handle *pwrb_handle) { - if (!ring_mode) - pwrb_context->pwrb_handle_base[pwrb_context->free_index] = - pwrb_handle; + pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; pwrb_context->wrb_handles_available++; if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->free_index = 0; @@ -865,7 +862,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, { struct hwi_wrb_context *pwrb_context; struct wrb_handle *pwrb_handle = NULL; - struct sgl_handle *psgl_handle = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; struct beiscsi_io_task *io_task; @@ -873,23 +869,14 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - pwrb_context = &phwi_ctrlr->wrb_context[psgl_handle->cid]; - task = psgl_handle->task; - pwrb_handle = NULL; - } else { - pwrb_context = &phwi_ctrlr->wrb_context[((psol-> + pwrb_context = &phwi_ctrlr->wrb_context[((psol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - } + task = pwrb_handle->pio_handle; io_task = task->dd_data; spin_lock(&phba->mgmt_sgl_lock); @@ -930,32 +917,23 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct iscsi_wrb *pwrb = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; - struct sgl_handle *psgl_handle = NULL; unsigned int type; struct iscsi_conn *conn = beiscsi_conn->conn; struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - task = psgl_handle->task; - type = psgl_handle->type; - } else { - pwrb_context = &phwi_ctrlr-> - wrb_context[((psol->dw[offsetof + pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof (struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - pwrb = pwrb_handle->pwrb; - type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & - WRB_TYPE_MASK) >> 28; - } + task = pwrb_handle->pio_handle; + pwrb = pwrb_handle->pwrb; + type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & + WRB_TYPE_MASK) >> 28; + spin_lock_bh(&session->lock); switch (type) { case HWH_TYPE_IO: @@ -986,15 +964,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, break; default: - if (ring_mode) - shost_printk(KERN_WARNING, phba->shost, - "In hwi_complete_cmd, unknown type = %d" - "icd_index 0x%x CID 0x%x\n", type, - ((psol->dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6), - psgl_handle->cid); - else - shost_printk(KERN_WARNING, phba->shost, + shost_printk(KERN_WARNING, phba->shost, "In hwi_complete_cmd, unknown type = %d" "wrb_index 0x%x CID 0x%x\n", type, ((psol->dw[offsetof(struct amap_iscsi_wrb, @@ -1483,7 +1453,6 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) unsigned int num_processed = 0; unsigned int tot_nump = 0; struct beiscsi_conn *beiscsi_conn; - struct sgl_handle *psgl_handle = NULL; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; struct beiscsi_hba *phba; @@ -1496,18 +1465,11 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) CQE_VALID_MASK) { be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((sol-> - dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) - >> 6)]; - ep = phba->ep_array[psgl_handle->cid]; - } else { - ep = phba->ep_array[(u32) ((sol-> + ep = phba->ep_array[(u32) ((sol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK) >> 6) - phba->fw_config.iscsi_cid_start]; - } + beiscsi_ep = ep->dd_data; beiscsi_conn = beiscsi_ep->conn; @@ -1553,21 +1515,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CMD_CXN_KILLED_ITT_INVALID: case CMD_CXN_KILLED_SEQ_OUTOFORDER: case CMD_CXN_KILLED_INVALID_DATASN_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, - "CQ Error notification for cmd.. " - "code %d cid 0x%x\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, + SE_DEBUG(DBG_LVL_1, "CQ Error notification for cmd.. " "code %d cid 0x%x\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK)); - } break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: SE_DEBUG(DBG_LVL_1, @@ -1589,37 +1543,23 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CXN_KILLED_OVER_RUN_RESIDUAL: case CXN_KILLED_UNDER_RUN_RESIDUAL: case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " - "0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " "0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & CQE_CID_MASK)); - } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; case CXN_KILLED_RST_SENT: case CXN_KILLED_RST_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" - "received/sent on CID 0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" "received/sent on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & CQE_CID_MASK)); - } iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; @@ -2848,11 +2788,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) goto error; } - if (phba->fw_config.iscsi_features == 0x1) - ring_mode = 1; - else - ring_mode = 0; - status = beiscsi_create_cqs(phba, phwi_context); if (status != 0) { shost_printk(KERN_ERR, phba->shost, "CQ not created\n"); @@ -2980,17 +2915,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->io_sgl_hndl_avbl = 0; phba->eh_sgl_hndl_avbl = 0; - if (ring_mode) { - phba->sgl_hndl_array = kzalloc(sizeof(struct sgl_handle *) * - phba->params.icds_per_ctrl, - GFP_KERNEL); - if (!phba->sgl_hndl_array) { - shost_printk(KERN_ERR, phba->shost, - "Mem Alloc Failed. Failing to load\n"); - return -ENOMEM; - } - } - mem_descr_sglh = phba->init_mem; mem_descr_sglh += HWI_MEM_SGLH; if (1 == mem_descr_sglh->num_elements) { @@ -2998,8 +2922,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->params.ios_per_ctrl, GFP_KERNEL); if (!phba->io_sgl_hndl_base) { - if (ring_mode) - kfree(phba->sgl_hndl_array); shost_printk(KERN_ERR, phba->shost, "Mem Alloc Failed. Failing to load\n"); return -ENOMEM; @@ -3184,8 +3106,6 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) if (hba_setup_cid_tbls(phba)) { shost_printk(KERN_ERR, phba->shost, "Failed in hba_setup_cid_tbls\n"); - if (ring_mode) - kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); goto do_cleanup_ctrlr; @@ -3242,8 +3162,6 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) hwi_purge_eq(phba); hwi_cleanup(phba); - if (ring_mode) - kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); kfree(phba->cid_array); @@ -3329,8 +3247,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) + doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3417,15 +3334,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> wrb_index << 16) | (unsigned int) (io_task->psgl_handle->sgl_index)); - if (ring_mode) { - phba->sgl_hndl_array[io_task->psgl_handle->sgl_index - - phba->fw_config.iscsi_icd_start] = - io_task->psgl_handle; - io_task->psgl_handle->task = task; - io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start; - } else - io_task->pwrb_handle->pio_handle = task; + io_task->pwrb_handle->pio_handle = task; io_task->cmd_bhs->iscsi_hdr.itt = itt; return 0; @@ -3511,18 +3420,12 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, ISCSI_OPCODE_SCSI_DATA_OUT); AMAP_SET_BITS(struct amap_pdu_data_out, final_bit, &io_task->cmd_bhs->iscsi_data_pdu, 1); - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); } else { - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); } memcpy(&io_task->cmd_bhs->iscsi_data_pdu. @@ -3547,8 +3450,7 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3583,21 +3485,15 @@ static int beiscsi_mtask(struct iscsi_task *task) switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { case ISCSI_OP_LOGIN: - if (ring_mode) - io_task->psgl_handle->type = TGT_DM_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_NOOP_OUT: - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); if (task->hdr->ttt == ISCSI_RESERVED_TAG) AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); else @@ -3605,11 +3501,8 @@ static int beiscsi_mtask(struct iscsi_task *task) hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); @@ -3642,19 +3535,13 @@ static int beiscsi_mtask(struct iscsi_task *task) phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } - if (ring_mode) - io_task->psgl_handle->type = INI_TMF_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_TMF_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_TMF_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_LOGOUT: AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - if (ring_mode) - io_task->psgl_handle->type = HWH_TYPE_LOGOUT; - else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, HWH_TYPE_LOGOUT); hwi_write_buffer(pwrb, task); @@ -3673,8 +3560,7 @@ static int beiscsi_mtask(struct iscsi_task *task) be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); @@ -3999,7 +3885,6 @@ static int __init beiscsi_module_init(void) "beiscsi pci driver.\n"); goto unregister_iscsi_transport; } - ring_mode = 0; return 0; unregister_iscsi_transport: -- GitLab From d2eeb1ac35a7146cbd4b1f6bf09bb6384ccdfb0d Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:35:15 +0530 Subject: [PATCH 1775/3892] [SCSI] be2iscsi: changing copyright to 2010 This patch replaces 2009 with 2010 in copyright statement Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be.h | 2 +- drivers/scsi/be2iscsi/be_cmds.c | 2 +- drivers/scsi/be2iscsi/be_cmds.h | 2 +- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- drivers/scsi/be2iscsi/be_iscsi.h | 2 +- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/be2iscsi/be_main.h | 2 +- drivers/scsi/be2iscsi/be_mgmt.c | 2 +- drivers/scsi/be2iscsi/be_mgmt.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 3861cf44dc15..0063740bbccf 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 44e69bdf359a..67098578fba4 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 69dddfaebe59..49fcc787ee8b 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 95694d3d2089..3847a587d2a8 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index f92ffc5349fb..1f512c28cbf9 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 522e7d526331..2f0027c5605c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 13ff02c1fcaa..8cbe9084bd3e 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index b0bb54dafbe9..39106da6f547 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index f873a66cd48f..ecead6a5aa56 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or -- GitLab From 230dceb4316da9c8e05c82b64f2527aee95da2ff Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:36:10 +0530 Subject: [PATCH 1776/3892] [SCSI] be2iscsi: Fix for first_burst This patch fixes the first_burst being modified instead of max_burst Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 3847a587d2a8..d5712bc19a71 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -274,8 +274,8 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, conn->max_recv_dlength = 65536; break; case ISCSI_PARAM_MAX_BURST: - if (session->first_burst > 262144) - session->first_burst = 262144; + if (session->max_burst > 262144) + session->max_burst = 262144; break; default: return 0; -- GitLab From 5dc1c416b39531e3bcf0651ca4123e64228dd553 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:36:52 +0530 Subject: [PATCH 1777/3892] [SCSI] be2iscsi: Proper checking of state This patch adds proper checking of value in for hba state. We would be adding more states later on Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d5712bc19a71..29a3aaf35f9f 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -561,7 +561,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ERR_PTR(ret); } - if (phba->state) { + if (phba->state != BE_ADAPTER_UP) { ret = -EBUSY; SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); -- GitLab From f55a24f2c24b63f8b4329eb28b4aec02a4bcf5d0 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:37:40 +0530 Subject: [PATCH 1778/3892] [SCSI] be2iscsi: correcting the return This patch fixes an issue where return was not called properly. Thanks to Mike Christie for spotting this Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 2f0027c5605c..6b700ad2bb47 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3873,7 +3873,7 @@ static int __init beiscsi_module_init(void) SE_DEBUG(DBG_LVL_1, "beiscsi_module_init - Unable to register beiscsi" "transport.\n"); - ret = -ENOMEM; + return -ENOMEM; } SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n", &beiscsi_iscsi_transport); -- GitLab From caf818f118b1ea60226a884072f1c3a9d5714766 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:38:18 +0530 Subject: [PATCH 1779/3892] [SCSI] be2iscsi: Ensure clean reuse of wrb This patch ensures that wrb is cleanly resued for io path and is memset to zero for non io path Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 6b700ad2bb47..85c0e80628a8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1663,11 +1663,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, sg_len); sge_len = sg_len; - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 1); } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 0); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, pwrb, sge_len); sg_len = sg_dma_len(sg); @@ -1690,8 +1686,22 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, io_task->bhs_pa.u.a32.address_lo); - if (num_sg == 2) - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1); + if (num_sg == 1) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 1); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } else if (num_sg == 2) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } sg = l_sg; psgl++; psgl++; @@ -3476,6 +3486,7 @@ static int beiscsi_mtask(struct iscsi_task *task) cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; + memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, be32_to_cpu(task->cmdsn)); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, -- GitLab From b30c6dab1d87cc638a7413dd0e778d8c9a5232eb Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:38:56 +0530 Subject: [PATCH 1780/3892] [SCSI] be2iscsi: changing the chip opcode for TEXT This patch corrects the chipopcode for text and chooses correct paramters for that command Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 85c0e80628a8..932cb8ab8db6 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3513,9 +3513,8 @@ static int beiscsi_mtask(struct iscsi_task *task) break; case ISCSI_OP_TEXT: AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + TGT_DM_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_SCSI_TMFUNC: -- GitLab From 7c56533cf4fb072abc39e850e7ef4fb6166cc83b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 23 Jan 2010 05:39:37 +0530 Subject: [PATCH 1781/3892] [SCSI] be2iscsi: correction in the claculation for num_cxn_wrb This patch correct the math done for num_cxn_wrb Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 932cb8ab8db6..687d535894a9 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2042,10 +2042,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } idx = 0; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = - ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); - + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) { pwrb_context = &phwi_ctrlr->wrb_context[index]; if (num_cxn_wrb) { @@ -2058,9 +2057,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } else { idx++; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) / - (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (j = 0; j < phba->params.wrbs_per_cxn; j++) { pwrb_handle = pwrb_context->pwrb_handle_base[j]; pwrb_handle->pwrb = pwrb; -- GitLab From 2cec802980727f1daa46d8c31b411e083d49d7a2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 23 Jan 2010 18:40:29 +0000 Subject: [PATCH 1782/3892] [SCSI] qla1280: Drop host_lock while requesting firmware request_firmware() may sleep and it appears to be safe to release the spinlock here. Signed-off-by: Ben Hutchings Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 8371d917a9a2..49ac4148493b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1640,8 +1640,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha) uint16_t mb[MAILBOX_REGISTER_COUNT], i; int err; + spin_unlock_irq(ha->host->host_lock); err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, &ha->pdev->dev); + spin_lock_irq(ha->host->host_lock); if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", ql1280_board_tbl[ha->devnum].fwname, err); @@ -1699,8 +1701,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) return -ENOMEM; #endif + spin_unlock_irq(ha->host->host_lock); err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, &ha->pdev->dev); + spin_lock_irq(ha->host->host_lock); if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", ql1280_board_tbl[ha->devnum].fwname, err); -- GitLab From 341af10239c4c87192bf762f53c7bcb1f3a1e767 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:07:37 -0500 Subject: [PATCH 1783/3892] [SCSI] lpfc 8.3.8: BugFixes: SLI relates changes Fix hardware/SLI relates issues: - Handle XB bit so that ELS XRIs are not prematurely released. - Handle XB bit so that FCP XRIs are not prematurely released. - Define new security SLI Commands. - Remove unused security SLI commands - Skip receive data size parameter check on received FLOGI. - Added LPFC_USE_FCPWQIDX flag to iocb to force SLI layer to submit abort WQE on same WQ as the command WQE. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hw.h | 18 ++--- drivers/scsi/lpfc/lpfc_nportdisc.c | 83 +++++++++++---------- drivers/scsi/lpfc/lpfc_scsi.c | 29 +++++--- drivers/scsi/lpfc/lpfc_scsi.h | 1 + drivers/scsi/lpfc/lpfc_sli.c | 112 +++++++++++++++++++++++------ drivers/scsi/lpfc/lpfc_sli.h | 10 +-- 8 files changed, 170 insertions(+), 87 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 650494d622c1..14ee7d4f71ba 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, - struct serv_parm *, uint32_t); + struct serv_parm *, uint32_t, int); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); void lpfc_more_plogi(struct lpfc_vport *); void lpfc_more_adisc(struct lpfc_vport *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2cc39684ce97..32e3c8df22c5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, did = Fabric_DID; - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) { + if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { /* For a FLOGI we accept, then if our portname is greater * then the remote portname we initiate Nport login. */ diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c9faa1d8c3c8..44c258730b07 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1465,17 +1465,13 @@ typedef struct { /* FireFly BIU registers */ #define CMD_IOCB_LOGENTRY_CN 0x94 #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 -/* Unhandled Data Security SLI Commands */ -#define DSSCMD_IWRITE64_CR 0xD8 -#define DSSCMD_IWRITE64_CX 0xD9 -#define DSSCMD_IREAD64_CR 0xDA -#define DSSCMD_IREAD64_CX 0xDB -#define DSSCMD_INVALIDATE_DEK 0xDC -#define DSSCMD_SET_KEK 0xDD -#define DSSCMD_GET_KEK_ID 0xDE -#define DSSCMD_GEN_XFER 0xDF - -#define CMD_MAX_IOCB_CMD 0xE6 +/* Data Security SLI Commands */ +#define DSSCMD_IWRITE64_CR 0xF8 +#define DSSCMD_IWRITE64_CX 0xF9 +#define DSSCMD_IREAD64_CR 0xFA +#define DSSCMD_IREAD64_CX 0xFB + +#define CMD_MAX_IOCB_CMD 0xFB #define CMD_IOCB_MASK 0xff #define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 2ed6af194932..293234a5a944 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm * sp, uint32_t class) + struct serv_parm *sp, uint32_t class, int flogi) { volatile struct serv_parm *hsp = &vport->fc_sparam; uint16_t hsp_value, ssp_value = 0; @@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * correcting the byte values. */ if (sp->cls1.classValid) { - hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) | - hsp->cls1.rcvDataSizeLsb; - ssp_value = (sp->cls1.rcvDataSizeMsb << 8) | - sp->cls1.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; - sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) | + hsp->cls1.rcvDataSizeLsb); + ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) | + sp->cls1.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls1.rcvDataSizeLsb = + hsp->cls1.rcvDataSizeLsb; + sp->cls1.rcvDataSizeMsb = + hsp->cls1.rcvDataSizeMsb; + } } - } else if (class == CLASS1) { + } else if (class == CLASS1) goto bad_service_param; - } - if (sp->cls2.classValid) { - hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) | - hsp->cls2.rcvDataSizeLsb; - ssp_value = (sp->cls2.rcvDataSizeMsb << 8) | - sp->cls2.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; - sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) | + hsp->cls2.rcvDataSizeLsb); + ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) | + sp->cls2.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls2.rcvDataSizeLsb = + hsp->cls2.rcvDataSizeLsb; + sp->cls2.rcvDataSizeMsb = + hsp->cls2.rcvDataSizeMsb; + } } - } else if (class == CLASS2) { + } else if (class == CLASS2) goto bad_service_param; - } - if (sp->cls3.classValid) { - hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) | - hsp->cls3.rcvDataSizeLsb; - ssp_value = (sp->cls3.rcvDataSizeMsb << 8) | - sp->cls3.rcvDataSizeLsb; - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; - sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; + if (!flogi) { + hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) | + hsp->cls3.rcvDataSizeLsb); + ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) | + sp->cls3.rcvDataSizeLsb); + if (!ssp_value) + goto bad_service_param; + if (ssp_value > hsp_value) { + sp->cls3.rcvDataSizeLsb = + hsp->cls3.rcvDataSizeLsb; + sp->cls3.rcvDataSizeMsb = + hsp->cls3.rcvDataSizeMsb; + } } - } else if (class == CLASS3) { + } else if (class == CLASS3) goto bad_service_param; - } /* * Preserve the upper four bits of the MSB from the PLOGI response. @@ -295,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, NULL); return 0; } - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { + if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; @@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, "0142 PLOGI RSP: Invalid WWN.\n"); goto out; } - if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) + if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0)) goto out; /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a246410ce9df..d5cc6b8d32f2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { if (psb->cur_iocbq.sli4_xritag == xri) { list_del(&psb->list); + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; spin_unlock_irqrestore( &phba->sli4_hba.abts_scsi_buf_list_lock, @@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) list); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); } @@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) psb->cur_iocbq.sli4_xritag); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); break; @@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) list); if (status) { /* Put this back on the abort scsi list */ - psb->status = IOSTAT_LOCAL_REJECT; - psb->result = IOERR_ABORT_REQUESTED; + psb->exch_busy = 1; rc++; - } else + } else { + psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + } /* Put it back into the SCSI buffer list */ lpfc_release_scsi_buf_s4(phba, psb); } @@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) { unsigned long iflag = 0; - if (psb->status == IOSTAT_LOCAL_REJECT - && psb->result == IOERR_ABORT_REQUESTED) { + if (psb->exch_busy) { spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag); psb->pCmd = NULL; @@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; + /* pick up SLI4 exhange busy status from HBA */ + lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; + if (pnode && NLP_CHK_NODE_ACT(pnode)) atomic_dec(&pnode->cmd_pending); @@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocb->fcp_wqidx = iocb->fcp_wqidx; + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; if (lpfc_is_link_up(phba)) icmd->ulpCommand = CMD_ABORT_XRI_CN; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 65dfc8bd5b49..5932273870a5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -118,6 +118,7 @@ struct lpfc_scsi_buf { uint32_t timeout; + uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */ uint16_t status; /* From IOCB Word 7- ulpStatus */ uint32_t result; /* From IOCB Word 4. */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 589549b2bf0e..dc7c5c1231df 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) else sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); if (sglq) { - if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED - && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) - && (iocbq->iocb.un.ulpWord[4] - == IOERR_ABORT_REQUESTED))) { + if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) { spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag); list_add(&sglq->list, @@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case DSSCMD_IWRITE64_CX: case DSSCMD_IREAD64_CR: case DSSCMD_IREAD64_CX: - case DSSCMD_INVALIDATE_DEK: - case DSSCMD_SET_KEK: - case DSSCMD_GET_KEK_ID: - case DSSCMD_GEN_XFER: type = LPFC_SOL_IOCB; break; case CMD_ABORT_XRI_CN: @@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * All other are passed to the completion callback. */ if (pring->ringno == LPFC_ELS_RING) { - if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { + if ((phba->sli_rev < LPFC_SLI_REV4) && + (cmdiocbp->iocb_flag & + LPFC_DRIVER_ABORTED)) { + spin_lock_irqsave(&phba->hbalock, + iflag); cmdiocbp->iocb_flag &= ~LPFC_DRIVER_ABORTED; + spin_unlock_irqrestore(&phba->hbalock, + iflag); saveq->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; saveq->iocb.un.ulpWord[4] = @@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * of DMAing payload, so don't free data * buffer till after a hbeat. */ + spin_lock_irqsave(&phba->hbalock, + iflag); saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; + spin_unlock_irqrestore(&phba->hbalock, + iflag); + } + if ((phba->sli_rev == LPFC_SLI_REV4) && + (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) { + /* Set cmdiocb flag for the exchange + * busy so sgl (xri) will not be + * released until the abort xri is + * received from hba, clear the + * LPFC_DRIVER_ABORTED bit in case + * it was driver initiated abort. + */ + spin_lock_irqsave(&phba->hbalock, + iflag); + cmdiocbp->iocb_flag &= + ~LPFC_DRIVER_ABORTED; + cmdiocbp->iocb_flag |= + LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, + iflag); + cmdiocbp->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + cmdiocbp->iocb.un.ulpWord[4] = + IOERR_ABORT_REQUESTED; + /* + * For SLI4, irsiocb contains NO_XRI + * in sli_xritag, it shall not affect + * releasing sgl (xri) process. + */ + saveq->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + saveq->iocb.un.ulpWord[4] = + IOERR_SLI_ABORTED; + spin_lock_irqsave(&phba->hbalock, + iflag); + saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; + spin_unlock_irqrestore(&phba->hbalock, + iflag); } } (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); @@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, else bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - abort_tag = iocbq->iocb.un.acxri.abortIoTag; wqe->words[5] = 0; bf_set(lpfc_wqe_gen_ct, &wqe->generic, ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); abort_tag = iocbq->iocb.un.acxri.abortIoTag; - wqe->generic.abort_tag = abort_tag; /* * The abort handler will send us CMD_ABORT_XRI_CN or * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX @@ -6121,15 +6158,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) return IOCB_ERROR; - if (piocb->iocb_flag & LPFC_IO_FCP) { + if ((piocb->iocb_flag & LPFC_IO_FCP) || + (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { /* * For FCP command IOCB, get a new WQ index to distribute * WQE across the WQsr. On the other hand, for abort IOCB, * it carries the same WQ index to the original command * IOCB. */ - if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) + if (piocb->iocb_flag & LPFC_IO_FCP) piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], &wqe)) @@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, abort_iocb->iocb.ulpContext != abort_context || (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) spin_unlock_irq(&phba->hbalock); - else { + else if (phba->sli_rev < LPFC_SLI_REV4) { + /* + * leave the SLI4 aborted command on the txcmplq + * list and the command complete WCQE's XB bit + * will tell whether the SGL (XRI) can be released + * immediately or to the aborted SGL list for the + * following abort XRI from the HBA. + */ list_del_init(&abort_iocb->list); pring->txcmplq_cnt--; spin_unlock_irq(&phba->hbalock); @@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * payload, so don't free data buffer till after * a hbeat. */ + spin_lock_irq(&phba->hbalock); abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; - abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + spin_unlock_irq(&phba->hbalock); + abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; + abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED; (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); } } @@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 0; /* This signals the response to set the correct status - * before calling the completion handler. + * before calling the completion handler */ cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; @@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; + if (cmdiocb->iocb_flag & LPFC_IO_FCP) + abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; if (phba->link_state >= LPFC_LINK_UP) iabt->ulpCommand = CMD_ABORT_XRI_CN; @@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; + if (iocbq->iocb_flag & LPFC_IO_FCP) + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; if (lpfc_is_link_up(phba)) abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; @@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) } } +/** + * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn + * @phba: pointer to lpfc hba data structure + * @pIocbIn: pointer to the rspiocbq + * @pIocbOut: pointer to the cmdiocbq + * @wcqe: pointer to the complete wcqe + * + * This routine transfers the fields of a command iocbq to a response iocbq + * by copying all the IOCB fields from command iocbq and transferring the + * completion status information from the complete wcqe. + **/ static void -lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, +lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, + struct lpfc_iocbq *pIocbIn, struct lpfc_iocbq *pIocbOut, struct lpfc_wcqe_complete *wcqe) { + unsigned long iflags; size_t offset = offsetof(struct lpfc_iocbq, iocb); memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, @@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; else pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + + /* Pick up HBA exchange busy condition */ + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + spin_lock_irqsave(&phba->hbalock, iflags); + pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, iflags); + } } /** @@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, } /* Fake the irspiocbq and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); + lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); return irspiocbq; } @@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, } /* Fake the irspiocb and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe); + lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); /* Pass the cmd_iocb and the rsp state to the upper layer */ (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index ba38de3c28f1..dfcf5437d1f5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -53,17 +53,19 @@ struct lpfc_iocbq { IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ - uint8_t iocb_flag; + uint16_t iocb_flag; #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ -#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */ -#define LPFC_FIP_ELS_ID_SHIFT 6 +#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ +#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ + +#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ +#define LPFC_FIP_ELS_ID_SHIFT 14 - uint8_t abort_count; uint8_t rsvd2; uint32_t drvrTimeout; /* driver timeout in seconds */ uint32_t fcp_wqidx; /* index to FCP work queue */ -- GitLab From 695a814e18561c52456acf5051fac0ea4b8111da Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:03 -0500 Subject: [PATCH 1784/3892] [SCSI] lpfc 8.3.8: BugFixes: Discovery relates changes Discovery relates changes: - Separated VPI_REGISTERED state of physical port into VFI_REGISTERED and VPI_REGISTERED state so that driver can unregister physical port VPI independent of VFI. - Add code to unregister, re-init and re-register physical port VPI when physical port NportID change. - Add code to unregister and re-register VPI of a vport when its Nport ID change. - Add code in FDISC completion path to re-start FLOGI discovery when a FDISC complete with LOGIN_REQUIRED reason code. - Fix a memory leak in lpfc_init_vpi_cmpl - Add code to start a timer for vport to retry FDISC when CVL is received by a vport or physical port. If all Nports receive CVLs, then all timers are cancelled and a logical link level discovery will be started after one second. - Flush ELS commands after killing all delayed ELS commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 3 + drivers/scsi/lpfc/lpfc_crtn.h | 5 ++ drivers/scsi/lpfc/lpfc_els.c | 129 ++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 36 +++++++- drivers/scsi/lpfc/lpfc_init.c | 44 +++++++++- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 62 +++++++++++++- drivers/scsi/lpfc/lpfc_vport.c | 2 +- 8 files changed, 265 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1cc23a69db5e..197dc3e3bdc9 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -315,6 +315,9 @@ struct lpfc_vport { #define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ #define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ #define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */ +#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ +#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ +#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ uint32_t ct_flags; #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 14ee7d4f71ba..b9e8cd5b818a 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -44,6 +44,8 @@ int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *); +void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, + struct lpfc_nodelist *); void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); @@ -52,10 +54,13 @@ struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); void lpfc_cleanup_rpis(struct lpfc_vport *, int); +void lpfc_cleanup_pending_mbox(struct lpfc_vport *); int lpfc_linkdown(struct lpfc_hba *); void lpfc_linkdown_port(struct lpfc_vport *); void lpfc_port_link_failure(struct lpfc_vport *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_retry_pport_discovery(struct lpfc_hba *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 32e3c8df22c5..2c62349a1041 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry); static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb); -static void lpfc_register_new_vport(struct lpfc_hba *phba, - struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp); static int lpfc_max_els_tries = 3; @@ -604,10 +601,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } else { ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if (vport->vpi_state & LPFC_VPI_REGISTERED) { + if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) && + (vport->vpi_state & LPFC_VPI_REGISTERED)) { lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); - } else + } else if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_register_new_vport(phba, vport, ndlp); + else lpfc_issue_reg_vfi(vport); } return 0; @@ -804,6 +804,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpTimeout); goto flogifail; } + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; + spin_unlock_irq(shost->host_lock); /* * The FLogI succeeded. Sync the data for the CPU before @@ -2720,7 +2723,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; - if ((cmd == ELS_CMD_FLOGI) && + if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) && (phba->fc_topology != TOPOLOGY_LOOP) && !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ @@ -5915,6 +5918,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; MAILBOX_t *mb = &pmb->u.mb; + int rc; spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; @@ -5936,6 +5940,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); break; + /* If reg_vpi fail with invalid VPI status, re-init VPI */ + case 0x20: + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); + lpfc_init_vpi(phba, pmb, vport->vpi); + pmb->vport = vport; + pmb->mbox_cmpl = lpfc_init_vpi_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, + MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_vlog(vport, + KERN_ERR, LOG_MBOX, + "2732 Failed to issue INIT_VPI" + " mailbox command\n"); + } else { + lpfc_nlp_put(ndlp); + return; + } + default: /* Try to recover from this error */ lpfc_mbx_unreg_vpi(vport); @@ -5949,13 +5973,17 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) break; } } else { + spin_lock_irq(shost->host_lock); vport->vpi_state |= LPFC_VPI_REGISTERED; - if (vport == phba->pport) + spin_unlock_irq(shost->host_lock); + if (vport == phba->pport) { if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); - else - lpfc_issue_reg_vfi(vport); - else + else { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } + } else lpfc_do_scr_ns_plogi(phba, vport); } @@ -5977,7 +6005,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * This routine registers the @vport as a new virtual port with a HBA. * It is done through a registering vpi mailbox command. **/ -static void +void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -6017,6 +6045,78 @@ mbox_err_exit: return; } +/** + * lpfc_retry_pport_discovery - Start timer to retry FLOGI. + * @phba: pointer to lpfc hba data structure. + * + * This routine abort all pending discovery commands and + * start a timer to retry FLOGI for the physical port + * discovery. + **/ +void +lpfc_retry_pport_discovery(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; + int i; + uint32_t link_state; + + /* Treat this failure as linkdown for all vports */ + link_state = phba->link_state; + lpfc_linkdown(phba); + phba->link_state = link_state; + + vports = lpfc_create_vport_work_array(phba); + + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + ndlp = lpfc_findnode_did(vports[i], Fabric_DID); + if (ndlp) + lpfc_cancel_retry_delay_tmo(vports[i], ndlp); + lpfc_els_flush_cmd(vports[i]); + } + lpfc_destroy_vport_work_array(phba, vports); + } + + /* If fabric require FLOGI, then re-instantiate physical login */ + ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); + if (!ndlp) + return; + + + shost = lpfc_shost_from_vport(phba->pport); + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; + phba->pport->port_state = LPFC_FLOGI; + return; +} + +/** + * lpfc_fabric_login_reqd - Check if FLOGI required. + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to FDISC command iocb. + * @rspiocb: pointer to FDISC response iocb. + * + * This routine checks if a FLOGI is reguired for FDISC + * to succeed. + **/ +static int +lpfc_fabric_login_reqd(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + + if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) || + (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED)) + return 0; + else + return 1; +} + /** * lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command * @phba: pointer to lpfc hba data structure. @@ -6066,6 +6166,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID); if (irsp->ulpStatus) { + + if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) { + lpfc_retry_pport_discovery(phba); + goto out; + } + /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; @@ -6076,6 +6182,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto fdisc_failed; } spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; vport->fc_flag |= FC_FABRIC; if (vport->phba->fc_topology == TOPOLOGY_LOOP) vport->fc_flag |= FC_PUBLIC_LOOP; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2445e399fd60..7143d71c501f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -706,6 +706,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) void lpfc_port_link_failure(struct lpfc_vport *vport) { + lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); + /* Cleanup any outstanding received buffers */ lpfc_cleanup_rcv_buffers(vport); @@ -1695,10 +1697,11 @@ out: * * This function handles completion of init vpi mailbox command. */ -static void +void lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; + struct lpfc_nodelist *ndlp; if (mboxq->u.mb.mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -1712,6 +1715,20 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(&phba->hbalock); + /* If this port is physical port or FDISC is done, do reg_vpi */ + if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) { + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + lpfc_printf_vlog(vport, KERN_ERR, + LOG_DISCOVERY, + "2731 Cannot find fabric " + "controller node\n"); + else + lpfc_register_new_vport(phba, vport, ndlp); + mempool_free(mboxq, phba->mbox_mem_pool); + return; + } + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) lpfc_initial_fdisc(vport); else { @@ -1719,6 +1736,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "2606 No NPIV Fabric support\n"); } + mempool_free(mboxq, phba->mbox_mem_pool); return; } @@ -1814,6 +1832,9 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } /* The VPI is implicitly registered when the VFI is registered */ vport->vpi_state |= LPFC_VPI_REGISTERED; + vport->fc_flag |= FC_VFI_REGISTERED; + + vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; if (vport->port_state == LPFC_FABRIC_CFG_LINK) { lpfc_start_fdiscs(phba); @@ -2333,6 +2354,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } vport->vpi_state |= LPFC_VPI_REGISTERED; + vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ if (vport->fc_npr_cnt) @@ -4462,6 +4484,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) int rc; struct lpfc_vport **vports; int i; + struct lpfc_nodelist *ndlp; spin_lock_irq(&phba->hbalock); /* @@ -4489,6 +4512,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + /* Stop FLOGI/FDISC retries */ + ndlp = lpfc_findnode_did(vports[i], Fabric_DID); + if (ndlp) + lpfc_cancel_retry_delay_tmo(vports[i], ndlp); lpfc_mbx_unreg_vpi(vports[i]); spin_lock_irq(&phba->hbalock); vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; @@ -4497,6 +4524,9 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) } lpfc_destroy_vport_work_array(phba, vports); + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_all_cmd(phba); + /* Unregister VFI */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { @@ -4521,6 +4551,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) return; } + spin_lock_irq(&phba->hbalock); + phba->pport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(&phba->hbalock); + /* Unregister FCF */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b8eb1b6e5e77..4d20c4148fae 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2246,6 +2246,9 @@ lpfc_offline_prep(struct lpfc_hba * phba) if (vports[i]->load_flag & FC_UNLOADING) continue; vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; + vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + vports[i]->fc_flag &= ~FC_VFI_REGISTERED; + shost = lpfc_shost_from_vport(vports[i]); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, @@ -3007,6 +3010,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp; struct Scsi_Host *shost; uint32_t link_state; + int active_vlink_present; + struct lpfc_vport **vports; + int i; phba->fc_eventTag = acqe_fcoe->event_tag; phba->fcoe_eventtag = acqe_fcoe->event_tag; @@ -3074,14 +3080,46 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, if (!ndlp) break; shost = lpfc_shost_from_vport(vport); + if (phba->pport->port_state <= LPFC_FLOGI) + break; + /* If virtual link is not yet instantiated ignore CVL */ + if (vport->port_state <= LPFC_FDISC) + break; + lpfc_linkdown_port(vport); - if (vport->port_type != LPFC_NPIV_PORT) { + lpfc_cleanup_pending_mbox(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_CVL_RCVD; + spin_unlock_irq(shost->host_lock); + active_vlink_present = 0; + + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; + i++) { + if ((!(vports[i]->fc_flag & + FC_VPORT_CVL_RCVD)) && + (vports[i]->port_state > LPFC_FDISC)) { + active_vlink_present = 1; + break; + } + } + lpfc_destroy_vport_work_array(phba, vports); + } + + if (active_vlink_present) { + /* + * If there are other active VLinks present, + * re-instantiate the Vlink using FDISC. + */ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_DELAY_TMO; spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; - vport->port_state = LPFC_FLOGI; + ndlp->nlp_last_elscmd = ELS_CMD_FDISC; + vport->port_state = LPFC_FDISC; + } else { + lpfc_retry_pport_discovery(phba); } break; default: diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 293234a5a944..d20ae6b3b3cf 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -254,7 +254,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int rc; memset(&stat, 0, sizeof (struct ls_rjt)); - if (vport->port_state <= LPFC_FLOGI) { + if (vport->port_state <= LPFC_FDISC) { /* Before responding to PLOGI, check for pt2pt mode. * If we are pt2pt, with an outstanding FLOGI, abort * the FLOGI and resend it first. diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dc7c5c1231df..8d666d9fabb4 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1710,6 +1710,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp; uint16_t rpi, vpi; int rc; + struct lpfc_vport *vport = pmb->vport; mp = (struct lpfc_dmabuf *) (pmb->context1); @@ -1738,6 +1739,18 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } + /* Unreg VPI, if the REG_VPI succeed after VLink failure */ + if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) && + !(phba->pport->load_flag & FC_UNLOADING) && + !pmb->u.mb.mbxStatus) { + lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb); + pmb->vport = vport; + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_NOT_FINISHED) + return; + } + if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) lpfc_sli4_mbox_cmd_free(phba, pmb); else @@ -8440,8 +8453,10 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, wcqe->total_data_placed; else pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - else + else { pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed; + } /* Pick up HBA exchange busy condition */ if (bf_get(lpfc_wcqe_c_xb, wcqe)) { @@ -12139,3 +12154,48 @@ out: kfree(rgn23_data); return; } + +/** + * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands. + * @vport: pointer to vport data structure. + * + * This function iterate through the mailboxq and clean up all REG_LOGIN + * and REG_VPI mailbox commands associated with the vport. This function + * is called when driver want to restart discovery of the vport due to + * a Clear Virtual Link event. + **/ +void +lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mb, *nextmb; + struct lpfc_dmabuf *mp; + + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { + if (mb->vport != vport) + continue; + + if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) && + (mb->u.mb.mbxCommand != MBX_REG_VPI)) + continue; + + if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { + mp = (struct lpfc_dmabuf *) (mb->context1); + if (mp) { + __lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + } + list_del(&mb->list); + mempool_free(mb, phba->mbox_mem_pool); + } + mb = phba->sli.mbox_active; + if (mb && (mb->vport == vport)) { + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) || + (mb->u.mb.mbxCommand == MBX_REG_VPI)) + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + } + spin_unlock_irq(&phba->hbalock); +} + diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index e3c7fa642306..281ff033a7b2 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -389,7 +389,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * by the port. */ if ((phba->sli_rev == LPFC_SLI_REV4) && - (pport->vpi_state & LPFC_VPI_REGISTERED)) { + (pport->fc_flag & FC_VFI_REGISTERED)) { rc = lpfc_sli4_init_vpi(phba, vpi); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, -- GitLab From 65467b6bdffd3efde111444663bc9de35b59b22a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:29 -0500 Subject: [PATCH 1785/3892] [SCSI] lpfc 8.3.8: Add code to display logical link speed Display Logical Link Speed when supported and is non-zero. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hw4.h | 3 +++ drivers/scsi/lpfc/lpfc_init.c | 2 ++ drivers/scsi/lpfc/lpfc_scsi.c | 7 +++++++ drivers/scsi/lpfc/lpfc_sli4.h | 1 + 4 files changed, 13 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8a2a1c5935c6..c2bec6e6222f 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1959,6 +1959,9 @@ struct lpfc_acqe_link { #define LPFC_ASYNC_LINK_FAULT_NONE 0x0 #define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1 #define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2 +#define lpfc_acqe_qos_link_speed_SHIFT 16 +#define lpfc_acqe_qos_link_speed_MASK 0x0000FFFF +#define lpfc_acqe_qos_link_speed_WORD word1 uint32_t event_tag; uint32_t trailer; }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4d20c4148fae..e80e95d95cde 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2981,6 +2981,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, bf_get(lpfc_acqe_link_physical, acqe_link); phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_link); + phba->sli4_hba.link_state.logical_speed = + bf_get(lpfc_acqe_qos_link_speed, acqe_link); /* Invoke the lpfc_handle_latt mailbox command callback function */ lpfc_mbx_cmpl_read_la(phba, pmb); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index d5cc6b8d32f2..8f4b90a9d151 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2701,6 +2701,13 @@ lpfc_info(struct Scsi_Host *host) " port %s", phba->Port); } + len = strlen(lpfcinfobuf); + if (phba->sli4_hba.link_state.logical_speed) { + snprintf(lpfcinfobuf + len, + 384-len, + " Logical Link Speed: %d Mbps", + phba->sli4_hba.link_state.logical_speed * 10); + } } return lpfcinfobuf; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 44e5f574236b..2e5e40576864 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -126,6 +126,7 @@ struct lpfc_sli4_link { uint8_t status; uint8_t physical; uint8_t fault; + uint16_t logical_speed; }; struct lpfc_fcf { -- GitLab From 4fede78f7552479c4bb3bab221133ec5244e4154 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:08:55 -0500 Subject: [PATCH 1786/3892] [SCSI] lpfc 8.3.8: (BSG1) Update BSG infrastructure Update BSG infrastructure to handle new vendor specific BSG commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 6 ++-- drivers/scsi/lpfc/lpfc_bsg.c | 52 +++++++++++++++++++---------------- drivers/scsi/lpfc/lpfc_crtn.h | 4 +-- drivers/scsi/lpfc/lpfc_ct.c | 8 ++++-- drivers/scsi/lpfc/lpfc_hw.h | 5 +++- drivers/scsi/lpfc/lpfc_init.c | 4 +-- drivers/scsi/lpfc/lpfc_nl.h | 22 +-------------- 7 files changed, 47 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 197dc3e3bdc9..a40a45b8aede 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -451,6 +451,8 @@ struct unsol_rcv_ct_ctx { uint32_t ctxt_id; uint32_t SID; uint32_t oxid; + uint32_t flags; +#define UNSOL_VALID 0x00000001 }; struct lpfc_hba { @@ -793,7 +795,7 @@ struct lpfc_hba { uint16_t vlan_id; struct list_head fcf_conn_rec_list; - struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */ + spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */ struct list_head ct_ev_waiters; struct unsol_rcv_ct_ctx ct_ctx[64]; uint32_t ctx_idx; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a5d9048235d9..dfb1f73252a1 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009 Emulex. All rights reserved. * + * Copyright (C) 2009-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -33,6 +33,7 @@ #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" +#include "lpfc_bsg.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" #include "lpfc.h" @@ -476,7 +477,7 @@ enum ELX_LOOPBACK_CMD { * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registerd to receive CT events. */ -void +int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) { @@ -496,6 +497,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; struct lpfc_hbq_entry *hbqe; struct lpfc_sli_ct_request *ct_req; + unsigned long flags; INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); @@ -519,7 +521,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->req_id != evt_req_id) continue; @@ -535,7 +537,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { /* take accumulated byte count from the last iocbq */ @@ -556,9 +558,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "CT event data, size %d\n", evt_dat->len); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } @@ -601,9 +603,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iocbq); kfree(evt_dat->data); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, + flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore( + &phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } memcpy((char *)(evt_dat->data) + offset, @@ -638,7 +642,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); if (phba->sli_rev == LPFC_SLI_REV4) { evt_dat->immed_dat = phba->ctx_idx; phba->ctx_idx = (phba->ctx_idx + 1) % 64; @@ -656,13 +660,13 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (evt_req_id == SLI_CT_ELX_LOOPBACK) break; } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - return; + return 1; } /** @@ -676,6 +680,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) struct lpfc_hba *phba = vport->phba; struct set_ct_event *event_req; struct lpfc_ct_event *evt; + unsigned long flags; int rc = 0; if (job->request_len < @@ -689,7 +694,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) event_req = (struct set_ct_event *) job->request->rqst_data.h_vendor.vendor_cmd; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { lpfc_ct_event_ref(evt); @@ -697,7 +702,7 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) break; } } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (&evt->node == &phba->ct_ev_waiters) { /* no event waiting struct yet - first call */ @@ -710,19 +715,19 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) return -ENOMEM; } - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_add(&evt->node, &phba->ct_ev_waiters); lpfc_ct_event_ref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } evt->waiting = 1; if (wait_event_interruptible(evt->wq, !list_empty(&evt->events_to_see))) { - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); /* release ref */ lpfc_ct_event_unref(evt); /* delete */ - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); rc = -EINTR; goto set_event_out; } @@ -730,10 +735,10 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) evt->wait_time_stamp = jiffies; evt->waiting = 0; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); lpfc_ct_event_unref(evt); /* release ref */ - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); set_event_out: /* set_event carries no reply payload */ @@ -759,6 +764,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) struct get_ct_event_reply *event_reply; struct lpfc_ct_event *evt; struct event_data *evt_dat = NULL; + unsigned long flags; int rc = 0; if (job->request_len < @@ -775,7 +781,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) event_reply = (struct get_ct_event_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { if (list_empty(&evt->events_to_get)) @@ -788,7 +794,7 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) break; } } - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); if (!evt_dat) { job->reply->reply_payload_rcv_len = 0; @@ -818,9 +824,9 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) if (evt_dat) kfree(evt_dat->data); kfree(evt_dat); - mutex_lock(&phba->ct_event_mutex); + spin_lock_irqsave(&phba->ct_ev_lock, flags); lpfc_ct_event_unref(evt); - mutex_unlock(&phba->ct_event_mutex); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_get_event_exit: /* make error code available to userspace */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b9e8cd5b818a..107899dc3f3e 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -383,5 +383,5 @@ struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t); /* functions to support SGIOv4/bsg interface */ int lpfc_bsg_request(struct fc_bsg_job *); int lpfc_bsg_timeout(struct fc_bsg_job *); -void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, +int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index bf7bf62e81eb..c7e921973f66 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -97,7 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct list_head head; struct lpfc_dmabuf *bdeBuf; - lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) + return; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -181,7 +182,8 @@ lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba, uint32_t size; /* Forward abort event to any process registered to receive ct event */ - lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) + return; /* If there is no BDE associated with IOCB, there is nothing to do */ if (icmd->ulpBdeCount == 0) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 44c258730b07..89ff7c09e298 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -1346,6 +1346,9 @@ typedef struct { /* FireFly BIU registers */ #define MBX_HEARTBEAT 0x31 #define MBX_WRITE_VPARMS 0x32 #define MBX_ASYNCEVT_ENABLE 0x33 +#define MBX_READ_EVENT_LOG_STATUS 0x37 +#define MBX_READ_EVENT_LOG 0x38 +#define MBX_WRITE_EVENT_LOG 0x39 #define MBX_PORT_CAPABILITIES 0x3B #define MBX_PORT_IOV_CONTROL 0x3C diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e80e95d95cde..52fc758b8f77 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -4331,7 +4331,7 @@ lpfc_hba_alloc(struct pci_dev *pdev) return NULL; } - mutex_init(&phba->ct_event_mutex); + spin_lock_init(&phba->ct_ev_lock); INIT_LIST_HEAD(&phba->ct_ev_waiters); return phba; diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h index d655ed3eebef..f3cfbe2ce986 100644 --- a/drivers/scsi/lpfc/lpfc_nl.h +++ b/drivers/scsi/lpfc/lpfc_nl.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2008 Emulex. All rights reserved. * + * Copyright (C) 2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -177,23 +177,3 @@ struct temp_event { uint32_t data; }; -/* bsg definitions */ -#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 -#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 - -struct set_ct_event { - uint32_t command; - uint32_t ev_req_id; - uint32_t ev_reg_id; -}; - -struct get_ct_event { - uint32_t command; - uint32_t ev_reg_id; - uint32_t ev_req_id; -}; - -struct get_ct_event_reply { - uint32_t immed_data; - uint32_t type; -}; -- GitLab From c79c1292df87fa9c63383ca551fa719c0c2fda7c Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:09:22 -0500 Subject: [PATCH 1787/3892] [SCSI] lpfc 8.3.8: (BSG2) Create lpfc_bsg.h Create lpfc_bsg.h - structures, etc used by bsg-related routines. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.h | 98 ++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 drivers/scsi/lpfc/lpfc_bsg.h diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h new file mode 100644 index 000000000000..6c8f87e39b98 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -0,0 +1,98 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2010 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ +/* bsg definitions + * No pointers to user data are allowed, all application buffers and sizes will + * derived through the bsg interface. + * + * These are the vendor unique structures passed in using the bsg + * FC_BSG_HST_VENDOR message code type. + */ +#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 +#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 +#define LPFC_BSG_VENDOR_SEND_MGMT_RESP 3 +#define LPFC_BSG_VENDOR_DIAG_MODE 4 +#define LPFC_BSG_VENDOR_DIAG_TEST 5 +#define LPFC_BSG_VENDOR_GET_MGMT_REV 6 +#define LPFC_BSG_VENDOR_MBOX 7 + +struct set_ct_event { + uint32_t command; + uint32_t type_mask; + uint32_t ev_req_id; + uint32_t ev_reg_id; +}; + +struct get_ct_event { + uint32_t command; + uint32_t ev_reg_id; + uint32_t ev_req_id; +}; + +struct get_ct_event_reply { + uint32_t immed_data; + uint32_t type; +}; + +struct send_mgmt_resp { + uint32_t command; + uint32_t tag; +}; + + +#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */ +#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */ + +struct diag_mode_set { + uint32_t command; + uint32_t type; + uint32_t timeout; +}; + +struct diag_mode_test { + uint32_t command; +}; + +#define LPFC_WWNN_TYPE 0 +#define LPFC_WWPN_TYPE 1 + +struct get_mgmt_rev { + uint32_t command; +}; + +#define MANAGEMENT_MAJOR_REV 1 +#define MANAGEMENT_MINOR_REV 0 + +/* the MgmtRevInfo structure */ +struct MgmtRevInfo { + uint32_t a_Major; + uint32_t a_Minor; +}; + +struct get_mgmt_rev_reply { + struct MgmtRevInfo info; +}; + +struct dfc_mbox_req { + uint32_t command; + uint32_t inExtWLen; + uint32_t outExtWLen; + uint8_t mbOffset; +}; + -- GitLab From 4cc0e56e977f12e6f400cbab3df7cf1e11d6f58a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:09:48 -0500 Subject: [PATCH 1788/3892] [SCSI] lpfc 8.3.8: (BSG3) Modify BSG commands to operate asynchronously Modify the following BSG commands to operate asynchronously. - FC_BSG_RPT_ELS - FC_BSG_RPT_CT - LPFC_BSG_VENDOR_GET_CT_EVENT - LPFC_BSG_VENDOR_SET_CT_EVENT Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 863 ++++++++++++++++++++++++----------- 1 file changed, 592 insertions(+), 271 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index dfb1f73252a1..a7e8921015eb 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -42,14 +42,169 @@ #include "lpfc_vport.h" #include "lpfc_version.h" +struct lpfc_bsg_event { + struct list_head node; + struct kref kref; + wait_queue_head_t wq; + + /* Event type and waiter identifiers */ + uint32_t type_mask; + uint32_t req_id; + uint32_t reg_id; + + /* next two flags are here for the auto-delete logic */ + unsigned long wait_time_stamp; + int waiting; + + /* seen and not seen events */ + struct list_head events_to_get; + struct list_head events_to_see; + + /* job waiting for this event to finish */ + struct fc_bsg_job *set_job; +}; + +struct lpfc_bsg_iocb { + struct lpfc_iocbq *cmdiocbq; + struct lpfc_iocbq *rspiocbq; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + + /* job waiting for this iocb to finish */ + struct fc_bsg_job *set_job; +}; + +#define TYPE_EVT 1 +#define TYPE_IOCB 2 +struct bsg_job_data { + uint32_t type; + union { + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb iocb; + } context_un; +}; + +struct event_data { + struct list_head node; + uint32_t type; + uint32_t immed_dat; + void *data; + uint32_t len; +}; + +#define SLI_CT_ELX_LOOPBACK 0x10 + +enum ELX_LOOPBACK_CMD { + ELX_LOOPBACK_XRI_SETUP, + ELX_LOOPBACK_DATA, +}; + +struct lpfc_dmabufext { + struct lpfc_dmabuf dma; + uint32_t size; + uint32_t flag; +}; + +/** + * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_bsg_send_mgmt_cmd function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from another thread which + * cleans up the SLI layer objects. + * This function copies the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + unsigned long iflags; + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + struct lpfc_bsg_iocb *iocb; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; + } + + iocb = &dd_data->context_un.iocb; + job = iocb->set_job; + job->dd_data = NULL; /* so timeout handler does not reply */ + + spin_lock_irqsave(&phba->hbalock, iflags); + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; + if (cmdiocbq->context2 && rspiocbq) + memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, + &rspiocbq->iocb, sizeof(IOCB_t)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + bmp = iocb->bmp; + rspiocbq = iocb->rspiocbq; + rsp = &rspiocbq->iocb; + ndlp = iocb->ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + + if (rsp->ulpStatus) { + if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (rsp->un.ulpWord[4] & 0xff) { + case IOERR_SEQUENCE_TIMEOUT: + rc = -ETIMEDOUT; + break; + case IOERR_INVALID_RPI: + rc = -EFAULT; + break; + default: + rc = -EACCES; + break; + } + } else + rc = -EACCES; + } else + job->reply->reply_payload_rcv_len = + rsp->un.genreq64.bdl.bdeSize; + + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + lpfc_sli_release_iocbq(phba, rspiocbq); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(bmp); + kfree(dd_data); + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; +} + /** - * lpfc_bsg_rport_ct - send a CT command from a bsg request + * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request * @job: fc_bsg_job to handle */ static int -lpfc_bsg_rport_ct(struct fc_bsg_job *job) +lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) { - struct Scsi_Host *shost = job->shost; struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = job->rport->dd_data; @@ -66,57 +221,60 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) struct scatterlist *sgel = NULL; int numbde; dma_addr_t busaddr; + struct bsg_job_data *dd_data; + uint32_t creg_val; int rc = 0; /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2733 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } + if (!lpfc_nlp_get(ndlp)) { - job->reply->result = -ENODEV; - return 0; + rc = -ENODEV; + goto no_ndlp; + } + + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!bmp) { + rc = -ENOMEM; + goto free_ndlp; } if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { rc = -ENODEV; - goto free_ndlp_exit; + goto free_bmp; } - spin_lock_irq(shost->host_lock); cmdiocbq = lpfc_sli_get_iocbq(phba); if (!cmdiocbq) { rc = -ENOMEM; - spin_unlock_irq(shost->host_lock); - goto free_ndlp_exit; + goto free_bmp; } - cmd = &cmdiocbq->iocb; + cmd = &cmdiocbq->iocb; rspiocbq = lpfc_sli_get_iocbq(phba); if (!rspiocbq) { rc = -ENOMEM; goto free_cmdiocbq; } - spin_unlock_irq(shost->host_lock); rsp = &rspiocbq->iocb; - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - spin_lock_irq(shost->host_lock); - goto free_rspiocbq; - } - - spin_lock_irq(shost->host_lock); bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); if (!bmp->virt) { rc = -ENOMEM; - goto free_bmp; + goto free_rspiocbq; } - spin_unlock_irq(shost->host_lock); INIT_LIST_HEAD(&bmp->list); bpl = (struct ulp_bde64 *) bmp->virt; - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { @@ -158,72 +316,146 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) cmd->ulpContext = ndlp->nlp_rpi; cmd->ulpOwner = OWN_CHIP; cmdiocbq->vport = phba->pport; - cmdiocbq->context1 = NULL; - cmdiocbq->context2 = NULL; + cmdiocbq->context3 = bmp; cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - timeout = phba->fc_ratov * 2; - job->dd_data = cmdiocbq; - - rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, - timeout + LPFC_DRVR_TIMEOUT); - - if (rc != IOCB_TIMEDOUT) { - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + cmd->ulpTimeout = timeout; + + cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; + cmdiocbq->context1 = dd_data; + cmdiocbq->context2 = rspiocbq; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = cmdiocbq; + dd_data->context_un.iocb.rspiocbq = rspiocbq; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = bmp; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ } - if (rc == IOCB_TIMEDOUT) { - lpfc_sli_release_iocbq(phba, rspiocbq); - rc = -EACCES; - goto free_ndlp_exit; - } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - if (rc != IOCB_SUCCESS) { - rc = -EACCES; - goto free_outdmp; - } + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - goto free_outdmp; - } - } else - job->reply->reply_payload_rcv_len = - rsp->un.genreq64.bdl.bdeSize; + /* iocb failed so cleanup */ + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -free_outdmp: - spin_lock_irq(shost->host_lock); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); -free_bmp: - kfree(bmp); + free_rspiocbq: lpfc_sli_release_iocbq(phba, rspiocbq); free_cmdiocbq: lpfc_sli_release_iocbq(phba, cmdiocbq); - spin_unlock_irq(shost->host_lock); -free_ndlp_exit: +free_bmp: + kfree(bmp); +free_ndlp: lpfc_nlp_put(ndlp); +no_ndlp: + kfree(dd_data); +no_dd_data: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + return rc; +} + +/** + * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_bsg_rport_els_cmp function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from other thread which + * cleans up the SLI layer objects. + * This function copy the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *pbuflist = NULL; + struct fc_bsg_ctels_reply *els_reply; + uint8_t *rjt_data; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + /* normal completion and timeout crossed paths, already done */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; + if (cmdiocbq->context2 && rspiocbq) + memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, + &rspiocbq->iocb, sizeof(IOCB_t)); + + job = dd_data->context_un.iocb.set_job; + cmdiocbq = dd_data->context_un.iocb.cmdiocbq; + rspiocbq = dd_data->context_un.iocb.rspiocbq; + rsp = &rspiocbq->iocb; + ndlp = dd_data->context_un.iocb.ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + + if (job->reply->result == -EAGAIN) + rc = -EAGAIN; + else if (rsp->ulpStatus == IOSTAT_SUCCESS) + job->reply->reply_payload_rcv_len = + rsp->un.elsreq64.bdl.bdeSize; + else if (rsp->ulpStatus == IOSTAT_LS_RJT) { + job->reply->reply_payload_rcv_len = + sizeof(struct fc_bsg_ctels_reply); + /* LS_RJT data returned in word 4 */ + rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; + els_reply = &job->reply->reply_data.ctels_reply; + els_reply->status = FC_CTELS_STATUS_REJECT; + els_reply->rjt_data.action = rjt_data[3]; + els_reply->rjt_data.reason_code = rjt_data[2]; + els_reply->rjt_data.reason_explanation = rjt_data[1]; + els_reply->rjt_data.vendor_unique = rjt_data[0]; + } else + rc = -EIO; + pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; + lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); + lpfc_sli_release_iocbq(phba, rspiocbq); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(dd_data); /* make error code available to userspace */ job->reply->result = rc; + job->dd_data = NULL; /* complete the job back to userspace */ job->job_done(job); - - return 0; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; } /** @@ -237,7 +469,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = job->rport->dd_data; struct lpfc_nodelist *ndlp = rdata->pnode; - uint32_t elscmd; uint32_t cmdsize; uint32_t rspsize; @@ -249,20 +480,30 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) struct lpfc_dmabuf *prsp; struct lpfc_dmabuf *pbuflist = NULL; struct ulp_bde64 *bpl; - int iocb_status; int request_nseg; int reply_nseg; struct scatterlist *sgel = NULL; int numbde; dma_addr_t busaddr; + struct bsg_job_data *dd_data; + uint32_t creg_val; int rc = 0; /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2735 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } + if (!lpfc_nlp_get(ndlp)) { rc = -ENODEV; - goto out; + goto free_dd_data; } elscmd = job->request->rqst_data.r_els.els_code; @@ -272,24 +513,24 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) if (!rspiocbq) { lpfc_nlp_put(ndlp); rc = -ENOMEM; - goto out; + goto free_dd_data; } rsp = &rspiocbq->iocb; rpi = ndlp->nlp_rpi; - cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp, + cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID, elscmd); - if (!cmdiocbq) { - lpfc_sli_release_iocbq(phba, rspiocbq); - return -EIO; + rc = -EIO; + goto free_rspiocbq; } - job->dd_data = cmdiocbq; + /* prep els iocb set context1 to the ndlp, context2 to the command + * dmabuf, context3 holds the data dmabuf + */ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; prsp = (struct lpfc_dmabuf *) pcmd->list.next; - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); lpfc_mbuf_free(phba, prsp->virt, prsp->phys); @@ -301,7 +542,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { busaddr = sg_dma_address(sgel); bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; @@ -323,7 +563,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); bpl++; } - cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); cmdiocbq->iocb.ulpContext = rpi; @@ -331,102 +570,54 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) cmdiocbq->context1 = NULL; cmdiocbq->context2 = NULL; - iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, - rspiocbq, (phba->fc_ratov * 2) - + LPFC_DRVR_TIMEOUT); - - /* release the new ndlp once the iocb completes */ + cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; + cmdiocbq->context1 = dd_data; + cmdiocbq->context2 = rspiocbq; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = cmdiocbq; + dd_data->context_un.iocb.rspiocbq = rspiocbq; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = NULL;; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); lpfc_nlp_put(ndlp); - if (iocb_status != IOCB_TIMEDOUT) { - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - } - - if (iocb_status == IOCB_SUCCESS) { - if (rsp->ulpStatus == IOSTAT_SUCCESS) { - job->reply->reply_payload_rcv_len = - rsp->un.elsreq64.bdl.bdeSize; - rc = 0; - } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { - struct fc_bsg_ctels_reply *els_reply; - /* LS_RJT data returned in word 4 */ - uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; - - els_reply = &job->reply->reply_data.ctels_reply; - job->reply->result = 0; - els_reply->status = FC_CTELS_STATUS_REJECT; - els_reply->rjt_data.action = rjt_data[0]; - els_reply->rjt_data.reason_code = rjt_data[1]; - els_reply->rjt_data.reason_explanation = rjt_data[2]; - els_reply->rjt_data.vendor_unique = rjt_data[3]; - } else - rc = -EIO; - } else - rc = -EIO; - - if (iocb_status != IOCB_TIMEDOUT) - lpfc_els_free_iocb(phba, cmdiocbq); - - lpfc_sli_release_iocbq(phba, rspiocbq); - -out: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); - - return 0; -} - -struct lpfc_ct_event { - struct list_head node; - int ref; - wait_queue_head_t wq; - - /* Event type and waiter identifiers */ - uint32_t type_mask; - uint32_t req_id; - uint32_t reg_id; + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ - /* next two flags are here for the auto-delete logic */ - unsigned long wait_time_stamp; - int waiting; + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - /* seen and not seen events */ - struct list_head events_to_get; - struct list_head events_to_see; -}; + lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); -struct event_data { - struct list_head node; - uint32_t type; - uint32_t immed_dat; - void *data; - uint32_t len; -}; + lpfc_sli_release_iocbq(phba, cmdiocbq); -static struct lpfc_ct_event * -lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id) -{ - struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); - if (!evt) - return NULL; +free_rspiocbq: + lpfc_sli_release_iocbq(phba, rspiocbq); - INIT_LIST_HEAD(&evt->events_to_get); - INIT_LIST_HEAD(&evt->events_to_see); - evt->req_id = ev_req_id; - evt->reg_id = ev_reg_id; - evt->wait_time_stamp = jiffies; - init_waitqueue_head(&evt->wq); +free_dd_data: + kfree(dd_data); - return evt; +no_dd_data: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + return rc; } static void -lpfc_ct_event_free(struct lpfc_ct_event *evt) +lpfc_bsg_event_free(struct kref *kref) { + struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, + kref); struct event_data *ed; list_del(&evt->node); @@ -449,24 +640,62 @@ lpfc_ct_event_free(struct lpfc_ct_event *evt) } static inline void -lpfc_ct_event_ref(struct lpfc_ct_event *evt) +lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) { - evt->ref++; + kref_get(&evt->kref); } static inline void -lpfc_ct_event_unref(struct lpfc_ct_event *evt) +lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) { - if (--evt->ref < 0) - lpfc_ct_event_free(evt); + kref_put(&evt->kref, lpfc_bsg_event_free); } -#define SLI_CT_ELX_LOOPBACK 0x10 +static struct lpfc_bsg_event * +lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) +{ + struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); -enum ELX_LOOPBACK_CMD { - ELX_LOOPBACK_XRI_SETUP, - ELX_LOOPBACK_DATA, -}; + if (!evt) + return NULL; + + INIT_LIST_HEAD(&evt->events_to_get); + INIT_LIST_HEAD(&evt->events_to_see); + evt->type_mask = ev_mask; + evt->req_id = ev_req_id; + evt->reg_id = ev_reg_id; + evt->wait_time_stamp = jiffies; + init_waitqueue_head(&evt->wq); + kref_init(&evt->kref); + return evt; +} + +static int +dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) +{ + struct lpfc_dmabufext *mlast; + struct pci_dev *pcidev; + struct list_head head, *curr, *next; + + if ((!mlist) || (!lpfc_is_link_up(phba) && + (phba->link_flag & LS_LOOPBACK_MODE))) { + return 0; + } + + pcidev = phba->pcidev; + list_add_tail(&head, &mlist->dma.list); + + list_for_each_safe(curr, next, &head) { + mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); + if (mlast->dma.virt) + dma_free_coherent(&pcidev->dev, + mlast->size, + mlast->dma.virt, + mlast->dma.phys); + kfree(mlast); + } + return 0; +} /** * lpfc_bsg_ct_unsol_event - process an unsolicited CT command @@ -475,7 +704,7 @@ enum ELX_LOOPBACK_CMD { * @piocbq: * * This function is called when an unsolicited CT command is received. It - * forwards the event to any processes registerd to receive CT events. + * forwards the event to any processes registered to receive CT events. */ int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -485,7 +714,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t cmd; uint32_t len; struct lpfc_dmabuf *dmabuf = NULL; - struct lpfc_ct_event *evt; + struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; struct lpfc_iocbq *iocbq; size_t offset = 0; @@ -497,7 +726,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; struct lpfc_hbq_entry *hbqe; struct lpfc_sli_ct_request *ct_req; + struct fc_bsg_job *job = NULL; unsigned long flags; + int size = 0; INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); @@ -506,6 +737,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) goto error_ct_unsol_exit; + if (phba->link_state == LPFC_HBA_ERROR || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) + goto error_ct_unsol_exit; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) dmabuf = bdeBuf1; else { @@ -513,7 +748,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, piocbq->iocb.un.cont64[0].addrLow); dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); } - + if (dmabuf == NULL) + goto error_ct_unsol_exit; ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; @@ -523,22 +759,22 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { - if (evt->req_id != evt_req_id) + if (!(evt->type_mask & FC_REG_CT_EVENT) || + evt->req_id != evt_req_id) continue; - lpfc_ct_event_ref(evt); - + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); - if (!evt_dat) { - lpfc_ct_event_unref(evt); + if (evt_dat == NULL) { + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2614 Memory allocation failed for " "CT event\n"); break; } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { /* take accumulated byte count from the last iocbq */ iocbq = list_entry(head.prev, typeof(*iocbq), list); @@ -552,25 +788,25 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); - if (!evt_dat->data) { + if (evt_dat->data == NULL) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2615 Memory allocation failed for " "CT event data, size %d\n", evt_dat->len); kfree(evt_dat); spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); goto error_ct_unsol_exit; } list_for_each_entry(iocbq, &head, list) { + size = 0; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { bdeBuf1 = iocbq->context2; bdeBuf2 = iocbq->context3; } for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { - int size = 0; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (i == 0) { @@ -605,7 +841,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, kfree(evt_dat); spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore( &phba->ct_ev_lock, flags); goto error_ct_unsol_exit; @@ -620,15 +856,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, dmabuf); } else { switch (cmd) { + case ELX_LOOPBACK_DATA: + dfc_cmd_data_free(phba, + (struct lpfc_dmabufext *) + dmabuf); + break; case ELX_LOOPBACK_XRI_SETUP: - if (!(phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED)) + if ((phba->sli_rev == + LPFC_SLI_REV2) || + (phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED + )) { + lpfc_in_buf_free(phba, + dmabuf); + } else { lpfc_post_buffer(phba, pring, 1); - else - lpfc_in_buf_free(phba, - dmabuf); + } break; default: if (!(phba->sli3_options & @@ -655,49 +900,79 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, evt_dat->type = FC_REG_CT_EVENT; list_add(&evt_dat->node, &evt->events_to_see); - wake_up_interruptible(&evt->wq); - lpfc_ct_event_unref(evt); - if (evt_req_id == SLI_CT_ELX_LOOPBACK) + if (evt_req_id == SLI_CT_ELX_LOOPBACK) { + wake_up_interruptible(&evt->wq); + lpfc_bsg_event_unref(evt); break; + } + + list_move(evt->events_to_see.prev, &evt->events_to_get); + lpfc_bsg_event_unref(evt); + + job = evt->set_job; + evt->set_job = NULL; + if (job) { + job->reply->reply_payload_rcv_len = size; + /* make error code available to userspace */ + job->reply->result = 0; + job->dd_data = NULL; + /* complete the job back to userspace */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + spin_lock_irqsave(&phba->ct_ev_lock, flags); + } } spin_unlock_irqrestore(&phba->ct_ev_lock, flags); error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - + if (evt_req_id == SLI_CT_ELX_LOOPBACK) + return 0; return 1; } /** - * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command + * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command * @job: SET_EVENT fc_bsg_job */ static int -lpfc_bsg_set_event(struct fc_bsg_job *job) +lpfc_bsg_hba_set_event(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct set_ct_event *event_req; - struct lpfc_ct_event *evt; - unsigned long flags; + struct lpfc_bsg_event *evt; int rc = 0; + struct bsg_job_data *dd_data = NULL; + uint32_t ev_mask; + unsigned long flags; if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2612 Received SET_CT_EVENT below minimum " "size\n"); - return -EINVAL; + rc = -EINVAL; + goto job_error; + } + + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (dd_data == NULL) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2734 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto job_error; } event_req = (struct set_ct_event *) job->request->rqst_data.h_vendor.vendor_cmd; - + ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & + FC_REG_EVENT_MASK); spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); evt->wait_time_stamp = jiffies; break; } @@ -706,73 +981,63 @@ lpfc_bsg_set_event(struct fc_bsg_job *job) if (&evt->node == &phba->ct_ev_waiters) { /* no event waiting struct yet - first call */ - evt = lpfc_ct_event_new(event_req->ev_reg_id, + evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, event_req->ev_req_id); if (!evt) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2617 Failed allocation of event " "waiter\n"); - return -ENOMEM; + rc = -ENOMEM; + goto job_error; } spin_lock_irqsave(&phba->ct_ev_lock, flags); list_add(&evt->node, &phba->ct_ev_waiters); - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); + evt->wait_time_stamp = jiffies; spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } - evt->waiting = 1; - if (wait_event_interruptible(evt->wq, - !list_empty(&evt->events_to_see))) { - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); /* release ref */ - lpfc_ct_event_unref(evt); /* delete */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - rc = -EINTR; - goto set_event_out; - } - - evt->wait_time_stamp = jiffies; - evt->waiting = 0; - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_move(evt->events_to_see.prev, &evt->events_to_get); - lpfc_ct_event_unref(evt); /* release ref */ + evt->waiting = 1; + dd_data->type = TYPE_EVT; + dd_data->context_un.evt = evt; + evt->set_job = job; /* for unsolicited command */ + job->dd_data = dd_data; /* for fc transport timeout callback*/ spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; /* call job done later */ -set_event_out: - /* set_event carries no reply payload */ - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); +job_error: + if (dd_data != NULL) + kfree(dd_data); - return 0; + job->dd_data = NULL; + return rc; } /** - * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command + * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command * @job: GET_EVENT fc_bsg_job */ static int -lpfc_bsg_get_event(struct fc_bsg_job *job) +lpfc_bsg_hba_get_event(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; struct get_ct_event *event_req; struct get_ct_event_reply *event_reply; - struct lpfc_ct_event *evt; + struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; unsigned long flags; - int rc = 0; + uint32_t rc = 0; if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2613 Received GET_CT_EVENT request below " "minimum size\n"); - return -EINVAL; + rc = -EINVAL; + goto job_error; } event_req = (struct get_ct_event *) @@ -780,13 +1045,12 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) event_reply = (struct get_ct_event_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; - spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { if (evt->reg_id == event_req->ev_reg_id) { if (list_empty(&evt->events_to_get)) break; - lpfc_ct_event_ref(evt); + lpfc_bsg_event_ref(evt); evt->wait_time_stamp = jiffies; evt_dat = list_entry(evt->events_to_get.prev, struct event_data, node); @@ -796,44 +1060,49 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) } spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - if (!evt_dat) { + /* The app may continue to ask for event data until it gets + * an error indicating that there isn't anymore + */ + if (evt_dat == NULL) { job->reply->reply_payload_rcv_len = 0; rc = -ENOENT; - goto error_get_event_exit; + goto job_error; } - if (evt_dat->len > job->reply_payload.payload_len) { - evt_dat->len = job->reply_payload.payload_len; - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2618 Truncated event data at %d " - "bytes\n", - job->reply_payload.payload_len); + if (evt_dat->len > job->request_payload.payload_len) { + evt_dat->len = job->request_payload.payload_len; + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2618 Truncated event data at %d " + "bytes\n", + job->request_payload.payload_len); } + event_reply->type = evt_dat->type; event_reply->immed_data = evt_dat->immed_dat; - if (evt_dat->len > 0) job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, + sg_copy_from_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, evt_dat->data, evt_dat->len); else job->reply->reply_payload_rcv_len = 0; - rc = 0; - if (evt_dat) + if (evt_dat) { kfree(evt_dat->data); - kfree(evt_dat); + kfree(evt_dat); + } + spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_ct_event_unref(evt); + lpfc_bsg_event_unref(evt); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - -error_get_event_exit: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ + job->dd_data = NULL; + job->reply->result = 0; job->job_done(job); + return 0; +job_error: + job->dd_data = NULL; + job->reply->result = rc; return rc; } @@ -845,19 +1114,25 @@ static int lpfc_bsg_hst_vendor(struct fc_bsg_job *job) { int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; + int rc; switch (command) { case LPFC_BSG_VENDOR_SET_CT_EVENT: - return lpfc_bsg_set_event(job); + rc = lpfc_bsg_hba_set_event(job); break; case LPFC_BSG_VENDOR_GET_CT_EVENT: - return lpfc_bsg_get_event(job); + rc = lpfc_bsg_hba_get_event(job); break; - default: - return -EINVAL; + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; } + + return rc; } /** @@ -868,10 +1143,9 @@ int lpfc_bsg_request(struct fc_bsg_job *job) { uint32_t msgcode; - int rc = -EINVAL; + int rc; msgcode = job->request->msgcode; - switch (msgcode) { case FC_BSG_HST_VENDOR: rc = lpfc_bsg_hst_vendor(job); @@ -880,9 +1154,13 @@ lpfc_bsg_request(struct fc_bsg_job *job) rc = lpfc_bsg_rport_els(job); break; case FC_BSG_RPT_CT: - rc = lpfc_bsg_rport_ct(job); + rc = lpfc_bsg_send_mgmt_cmd(job); break; default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; break; } @@ -901,11 +1179,54 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data; + struct lpfc_iocbq *cmdiocb; + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb *iocb; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct bsg_job_data *dd_data; + unsigned long flags; - if (cmdiocb) + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = (struct bsg_job_data *)job->dd_data; + /* timeout and completion crossed paths if no dd_data */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; + } + + switch (dd_data->type) { + case TYPE_IOCB: + iocb = &dd_data->context_un.iocb; + cmdiocb = iocb->cmdiocbq; + /* hint to completion handler that the job timed out */ + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + /* this will call our completion handler */ + spin_lock_irq(&phba->hbalock); lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + spin_unlock_irq(&phba->hbalock); + break; + case TYPE_EVT: + evt = dd_data->context_un.evt; + /* this event has no job anymore */ + evt->set_job = NULL; + job->dd_data = NULL; + job->reply->reply_payload_rcv_len = 0; + /* Return -EAGAIN which is our way of signallying the + * app to retry. + */ + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + break; + default: + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + break; + } + /* scsi transport fc fc_bsg_job_timeout expects a zero return code, + * otherwise an error message will be displayed on the console + * so always return success (zero) + */ return 0; } -- GitLab From 3b5dd52aaffd291edea9f939ed46a960b240bb45 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:10:15 -0500 Subject: [PATCH 1789/3892] [SCSI] lpfc 8.3.8: (BSG4) Add new vendor specific BSG Commands Add the following new vendor specific BSG commands. - Add LPFC_BSG_VENDOR_GET_MGMT_REV command - Add LPFC_BSG_VENDOR_MBOX command - Add LPFC_BSG_VENDOR_DIAG_MODE command - Add LPFC_BSG_VENDOR_DIAG_TEST command Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 1697 ++++++++++++++++++++++++++++++++-- 1 file changed, 1626 insertions(+), 71 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a7e8921015eb..64ab075a3656 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -74,13 +74,23 @@ struct lpfc_bsg_iocb { struct fc_bsg_job *set_job; }; +struct lpfc_bsg_mbox { + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *mb; + + /* job waiting for this mbox command to finish */ + struct fc_bsg_job *set_job; +}; + #define TYPE_EVT 1 #define TYPE_IOCB 2 +#define TYPE_MBOX 3 struct bsg_job_data { uint32_t type; union { struct lpfc_bsg_event *evt; struct lpfc_bsg_iocb iocb; + struct lpfc_bsg_mbox mbox; } context_un; }; @@ -92,6 +102,7 @@ struct event_data { uint32_t len; }; +#define BUF_SZ_4K 4096 #define SLI_CT_ELX_LOOPBACK 0x10 enum ELX_LOOPBACK_CMD { @@ -99,6 +110,9 @@ enum ELX_LOOPBACK_CMD { ELX_LOOPBACK_DATA, }; +#define ELX_LOOPBACK_HEADER_SZ \ + (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) + struct lpfc_dmabufext { struct lpfc_dmabuf dma; uint32_t size; @@ -201,7 +215,7 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, /** * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request * @job: fc_bsg_job to handle - */ + **/ static int lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) { @@ -380,7 +394,7 @@ no_dd_data: * can be called from both worker thread context and interrupt * context. This function also can be called from other thread which * cleans up the SLI layer objects. - * This function copy the contents of the response iocb to the + * This function copies the contents of the response iocb to the * response iocb memory object provided by the caller of * lpfc_sli_issue_iocb_wait and then wakes up the thread which * sleeps for the iocb completion. @@ -461,7 +475,7 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, /** * lpfc_bsg_rport_els - send an ELS command from a bsg request * @job: fc_bsg_job to handle - */ + **/ static int lpfc_bsg_rport_els(struct fc_bsg_job *job) { @@ -527,8 +541,8 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) } /* prep els iocb set context1 to the ndlp, context2 to the command - * dmabuf, context3 holds the data dmabuf - */ + * dmabuf, context3 holds the data dmabuf + */ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; prsp = (struct lpfc_dmabuf *) pcmd->list.next; lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); @@ -613,6 +627,14 @@ no_dd_data: return rc; } +/** + * lpfc_bsg_event_free - frees an allocated event structure + * @kref: Pointer to a kref. + * + * Called from kref_put. Back cast the kref into an event structure address. + * Free any events to get, delete associated nodes, free any events to see, + * free any data then free the event itself. + **/ static void lpfc_bsg_event_free(struct kref *kref) { @@ -639,18 +661,32 @@ lpfc_bsg_event_free(struct kref *kref) kfree(evt); } +/** + * lpfc_bsg_event_ref - increments the kref for an event + * @evt: Pointer to an event structure. + **/ static inline void lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) { kref_get(&evt->kref); } +/** + * lpfc_bsg_event_unref - Uses kref_put to free an event structure + * @evt: Pointer to an event structure. + **/ static inline void lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) { kref_put(&evt->kref, lpfc_bsg_event_free); } +/** + * lpfc_bsg_event_new - allocate and initialize a event structure + * @ev_mask: Mask of events. + * @ev_reg_id: Event reg id. + * @ev_req_id: Event request id. + **/ static struct lpfc_bsg_event * lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) { @@ -670,8 +706,13 @@ lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) return evt; } +/** + * diag_cmd_data_free - Frees an lpfc dma buffer extension + * @phba: Pointer to HBA context object. + * @mlist: Pointer to an lpfc dma buffer extension. + **/ static int -dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) +diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) { struct lpfc_dmabufext *mlast; struct pci_dev *pcidev; @@ -705,7 +746,7 @@ dfc_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) * * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registered to receive CT events. - */ + **/ int lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) @@ -857,7 +898,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { switch (cmd) { case ELX_LOOPBACK_DATA: - dfc_cmd_data_free(phba, + diag_cmd_data_free(phba, (struct lpfc_dmabufext *) dmabuf); break; @@ -935,7 +976,7 @@ error_ct_unsol_exit: /** * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command * @job: SET_EVENT fc_bsg_job - */ + **/ static int lpfc_bsg_hba_set_event(struct fc_bsg_job *job) { @@ -1018,7 +1059,7 @@ job_error: /** * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command * @job: GET_EVENT fc_bsg_job - */ + **/ static int lpfc_bsg_hba_get_event(struct fc_bsg_job *job) { @@ -1107,91 +1148,1595 @@ job_error: } /** - * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job - * @job: fc_bsg_job to handle - */ + * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler + * @phba: Pointer to HBA context object. + * @cmdiocbq: Pointer to command iocb. + * @rspiocbq: Pointer to response iocb. + * + * This function is the completion handler for iocbs issued using + * lpfc_issue_ct_rsp_cmp function. This function is called by the + * ring event handler function without any lock held. This function + * can be called from both worker thread context and interrupt + * context. This function also can be called from other thread which + * cleans up the SLI layer objects. + * This function copy the contents of the response iocb to the + * response iocb memory object provided by the caller of + * lpfc_sli_issue_iocb_wait and then wakes up the thread which + * sleeps for the iocb completion. + **/ +static void +lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + struct bsg_job_data *dd_data; + struct fc_bsg_job *job; + IOCB_t *rsp; + struct lpfc_dmabuf *bmp; + struct lpfc_nodelist *ndlp; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = cmdiocbq->context1; + /* normal completion and timeout crossed paths, already done */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + job = dd_data->context_un.iocb.set_job; + bmp = dd_data->context_un.iocb.bmp; + rsp = &rspiocbq->iocb; + ndlp = dd_data->context_un.iocb.ndlp; + + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + + if (rsp->ulpStatus) { + if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (rsp->un.ulpWord[4] & 0xff) { + case IOERR_SEQUENCE_TIMEOUT: + rc = -ETIMEDOUT; + break; + case IOERR_INVALID_RPI: + rc = -EFAULT; + break; + default: + rc = -EACCES; + break; + } + } else + rc = -EACCES; + } else + job->reply->reply_payload_rcv_len = + rsp->un.genreq64.bdl.bdeSize; + + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + lpfc_sli_release_iocbq(phba, cmdiocbq); + lpfc_nlp_put(ndlp); + kfree(bmp); + kfree(dd_data); + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + /* complete the job back to userspace */ + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; +} + +/** + * lpfc_issue_ct_rsp - issue a ct response + * @phba: Pointer to HBA context object. + * @job: Pointer to the job object. + * @tag: tag index value into the ports context exchange array. + * @bmp: Pointer to a dma buffer descriptor. + * @num_entry: Number of enties in the bde. + **/ static int -lpfc_bsg_hst_vendor(struct fc_bsg_job *job) +lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, + struct lpfc_dmabuf *bmp, int num_entry) { - int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; - int rc; + IOCB_t *icmd; + struct lpfc_iocbq *ctiocb = NULL; + int rc = 0; + struct lpfc_nodelist *ndlp = NULL; + struct bsg_job_data *dd_data; + uint32_t creg_val; - switch (command) { - case LPFC_BSG_VENDOR_SET_CT_EVENT: - rc = lpfc_bsg_hba_set_event(job); - break; + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2736 Failed allocation of dd_data\n"); + rc = -ENOMEM; + goto no_dd_data; + } - case LPFC_BSG_VENDOR_GET_CT_EVENT: - rc = lpfc_bsg_hba_get_event(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; + /* Allocate buffer for command iocb */ + ctiocb = lpfc_sli_get_iocbq(phba); + if (!ctiocb) { + rc = ENOMEM; + goto no_ctiocb; + } + + icmd = &ctiocb->iocb; + icmd->un.xseq64.bdl.ulpIoTag32 = 0; + icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); + icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); + icmd->un.xseq64.w5.hcsw.Dfctl = 0; + icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; + icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + /* Fill in rest of iocb */ + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + if (phba->sli_rev == LPFC_SLI_REV4) { + /* Do not issue unsol response if oxid not marked as valid */ + if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) { + rc = IOCB_ERROR; + goto issue_ct_rsp_exit; + } + icmd->ulpContext = phba->ct_ctx[tag].oxid; + ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); + if (!ndlp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2721 ndlp null for oxid %x SID %x\n", + icmd->ulpContext, + phba->ct_ctx[tag].SID); + rc = IOCB_ERROR; + goto issue_ct_rsp_exit; + } + icmd->un.ulpWord[3] = ndlp->nlp_rpi; + /* The exchange is done, mark the entry as invalid */ + phba->ct_ctx[tag].flags &= ~UNSOL_VALID; + } else + icmd->ulpContext = (ushort) tag; + + icmd->ulpTimeout = phba->fc_ratov * 2; + + /* Xmit CT response on exchange */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "2722 Xmit CT response on exchange x%x Data: x%x x%x\n", + icmd->ulpContext, icmd->ulpIoTag, phba->link_state); + + ctiocb->iocb_cmpl = NULL; + ctiocb->iocb_flag |= LPFC_IO_LIBDFC; + ctiocb->vport = phba->pport; + ctiocb->context3 = bmp; + + ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; + ctiocb->context1 = dd_data; + ctiocb->context2 = NULL; + dd_data->type = TYPE_IOCB; + dd_data->context_un.iocb.cmdiocbq = ctiocb; + dd_data->context_un.iocb.rspiocbq = NULL; + dd_data->context_un.iocb.set_job = job; + dd_data->context_un.iocb.bmp = bmp; + dd_data->context_un.iocb.ndlp = ndlp; + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + creg_val = readl(phba->HCregaddr); + creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); + writel(creg_val, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); + + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ + +issue_ct_rsp_exit: + lpfc_sli_release_iocbq(phba, ctiocb); +no_ctiocb: + kfree(dd_data); +no_dd_data: return rc; } /** - * lpfc_bsg_request - handle a bsg request from the FC transport - * @job: fc_bsg_job to handle - */ -int -lpfc_bsg_request(struct fc_bsg_job *job) + * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command + * @job: SEND_MGMT_RESP fc_bsg_job + **/ +static int +lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) { - uint32_t msgcode; - int rc; + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) + job->request->rqst_data.h_vendor.vendor_cmd; + struct ulp_bde64 *bpl; + struct lpfc_dmabuf *bmp = NULL; + struct scatterlist *sgel = NULL; + int request_nseg; + int numbde; + dma_addr_t busaddr; + uint32_t tag = mgmt_resp->tag; + unsigned long reqbfrcnt = + (unsigned long)job->request_payload.payload_len; + int rc = 0; - msgcode = job->request->msgcode; - switch (msgcode) { - case FC_BSG_HST_VENDOR: - rc = lpfc_bsg_hst_vendor(job); - break; - case FC_BSG_RPT_ELS: - rc = lpfc_bsg_rport_els(job); - break; - case FC_BSG_RPT_CT: - rc = lpfc_bsg_send_mgmt_cmd(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + + if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { + rc = -ERANGE; + goto send_mgmt_rsp_exit; + } + + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!bmp) { + rc = -ENOMEM; + goto send_mgmt_rsp_exit; + } + + bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); + if (!bmp->virt) { + rc = -ENOMEM; + goto send_mgmt_rsp_free_bmp; + } + + INIT_LIST_HEAD(&bmp->list); + bpl = (struct ulp_bde64 *) bmp->virt; + request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; } + rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg); + + if (rc == IOCB_SUCCESS) + return 0; /* done for now */ + + /* TBD need to handle a timeout */ + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + rc = -EACCES; + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + +send_mgmt_rsp_free_bmp: + kfree(bmp); +send_mgmt_rsp_exit: + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; return rc; } /** - * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport - * @job: fc_bsg_job that has timed out + * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command + * @job: LPFC_BSG_VENDOR_DIAG_MODE * - * This function just aborts the job's IOCB. The aborted IOCB will return to - * the waiting function which will handle passing the error back to userspace + * This function is responsible for placing a port into diagnostic loopback + * mode in order to perform a diagnostic loopback test. + * All new scsi requests are blocked, a small delay is used to allow the + * scsi requests to complete then the link is brought down. If the link is + * is placed in loopback mode then scsi requests are again allowed + * so the scsi mid-layer doesn't give up on the port. + * All of this is done in-line. */ -int -lpfc_bsg_timeout(struct fc_bsg_job *job) +static int +lpfc_bsg_diag_mode(struct fc_bsg_job *job) { + struct Scsi_Host *shost = job->shost; struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb; - struct lpfc_bsg_event *evt; - struct lpfc_bsg_iocb *iocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct bsg_job_data *dd_data; - unsigned long flags; + struct diag_mode_set *loopback_mode; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; + uint32_t link_flags; + uint32_t timeout; + struct lpfc_vport **vports; + LPFC_MBOXQ_t *pmboxq; + int mbxstatus; + int i = 0; + int rc = 0; - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = (struct bsg_job_data *)job->dd_data; - /* timeout and completion crossed paths if no dd_data */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return 0; + /* no data to return just the return code */ + job->reply->reply_payload_rcv_len = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2738 Received DIAG MODE request below minimum " + "size\n"); + rc = -EINVAL; + goto job_error; + } + + loopback_mode = (struct diag_mode_set *) + job->request->rqst_data.h_vendor.vendor_cmd; + link_flags = loopback_mode->type; + timeout = loopback_mode->timeout; + + if ((phba->link_state == LPFC_HBA_ERROR) || + (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + rc = -EACCES; + goto job_error; + } + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) { + rc = -ENOMEM; + goto job_error; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_block_requests(shost); + } + + lpfc_destroy_vport_work_array(phba, vports); + } else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_block_requests(shost); + } + + while (pring->txcmplq_cnt) { + if (i++ > 500) /* wait up to 5 seconds */ + break; + + msleep(10); + } + + memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; + pmboxq->u.mb.mbxOwner = OWN_HOST; + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); + + if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { + /* wait for link down before proceeding */ + i = 0; + while (phba->link_state != LPFC_LINK_DOWN) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + goto loopback_mode_exit; + } + + msleep(10); + } + + memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + if (link_flags == INTERNAL_LOOP_BACK) + pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; + else + pmboxq->u.mb.un.varInitLnk.link_flags = + FLAGS_TOPOLOGY_MODE_LOOP; + + pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; + pmboxq->u.mb.mbxOwner = OWN_HOST; + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, + LPFC_MBOX_TMO); + + if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) + rc = -ENODEV; + else { + phba->link_flag |= LS_LOOPBACK_MODE; + /* wait for the link attention interrupt */ + msleep(100); + + i = 0; + while (phba->link_state != LPFC_HBA_READY) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + break; + } + + msleep(10); + } + } + + } else + rc = -ENODEV; + +loopback_mode_exit: + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_unblock_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); + } else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_unblock_requests(shost); + } + + /* + * Let SLI layer release mboxq if mbox command completed after timeout. + */ + if (mbxstatus != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + +job_error: + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfcdiag_loop_self_reg - obtains a remote port login id + * @phba: Pointer to HBA context object + * @rpi: Pointer to a remote port login id + * + * This function obtains a remote port login id so the diag loopback test + * can send and receive its own unsolicited CT command. + **/ +static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) +{ + LPFC_MBOXQ_t *mbox; + struct lpfc_dmabuf *dmabuff; + int status; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return ENOMEM; + + status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, mbox, 0); + if (status) { + mempool_free(mbox, phba->mbox_mem_pool); + return ENOMEM; + } + + dmabuff = (struct lpfc_dmabuf *) mbox->context1; + mbox->context1 = NULL; + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + + if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { + lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); + kfree(dmabuff); + if (status != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return ENODEV; + } + + *rpi = mbox->u.mb.un.varWords[0]; + + lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); + kfree(dmabuff); + mempool_free(mbox, phba->mbox_mem_pool); + return 0; +} + +/** + * lpfcdiag_loop_self_unreg - unregs from the rpi + * @phba: Pointer to HBA context object + * @rpi: Remote port login id + * + * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg + **/ +static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) +{ + LPFC_MBOXQ_t *mbox; + int status; + + /* Allocate mboxq structure */ + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mbox == NULL) + return ENOMEM; + + lpfc_unreg_login(phba, 0, rpi, mbox); + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + + if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { + if (status != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return EIO; + } + + mempool_free(mbox, phba->mbox_mem_pool); + return 0; +} + +/** + * lpfcdiag_loop_get_xri - obtains the transmit and receive ids + * @phba: Pointer to HBA context object + * @rpi: Remote port login id + * @txxri: Pointer to transmit exchange id + * @rxxri: Pointer to response exchabge id + * + * This function obtains the transmit and receive ids required to send + * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp + * flags are used to the unsolicted response handler is able to process + * the ct command sent on the same port. + **/ +static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, + uint16_t *txxri, uint16_t * rxxri) +{ + struct lpfc_bsg_event *evt; + struct lpfc_iocbq *cmdiocbq, *rspiocbq; + IOCB_t *cmd, *rsp; + struct lpfc_dmabuf *dmabuf; + struct ulp_bde64 *bpl = NULL; + struct lpfc_sli_ct_request *ctreq = NULL; + int ret_val = 0; + unsigned long flags; + + *txxri = 0; + *rxxri = 0; + evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, + SLI_CT_ELX_LOOPBACK); + if (!evt) + return ENOMEM; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_add(&evt->node, &phba->ct_ev_waiters); + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rspiocbq = lpfc_sli_get_iocbq(phba); + + dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (dmabuf) { + dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); + INIT_LIST_HEAD(&dmabuf->list); + bpl = (struct ulp_bde64 *) dmabuf->virt; + memset(bpl, 0, sizeof(*bpl)); + ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); + bpl->addrHigh = + le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); + bpl->addrLow = + le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); + bpl->tus.f.bdeFlags = 0; + bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + } + + if (cmdiocbq == NULL || rspiocbq == NULL || + dmabuf == NULL || bpl == NULL || ctreq == NULL) { + ret_val = ENOMEM; + goto err_get_xri_exit; + } + + cmd = &cmdiocbq->iocb; + rsp = &rspiocbq->iocb; + + memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); + + ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; + ctreq->RevisionId.bits.InId = 0; + ctreq->FsType = SLI_CT_ELX_LOOPBACK; + ctreq->FsSubType = 0; + ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; + ctreq->CommandResponse.bits.Size = 0; + + + cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); + cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); + cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); + + cmd->un.xseq64.w5.hcsw.Fctl = LA; + cmd->un.xseq64.w5.hcsw.Dfctl = 0; + cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + cmd->ulpContext = rpi; + + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->vport = phba->pport; + + ret_val = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, + rspiocbq, + (phba->fc_ratov * 2) + + LPFC_DRVR_TIMEOUT); + if (ret_val) + goto err_get_xri_exit; + + *txxri = rsp->ulpContext; + + evt->waiting = 1; + evt->wait_time_stamp = jiffies; + ret_val = wait_event_interruptible_timeout( + evt->wq, !list_empty(&evt->events_to_see), + ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); + if (list_empty(&evt->events_to_see)) + ret_val = (ret_val) ? EINTR : ETIMEDOUT; + else { + ret_val = IOCB_SUCCESS; + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_move(evt->events_to_see.prev, &evt->events_to_get); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + *rxxri = (list_entry(evt->events_to_get.prev, + typeof(struct event_data), + node))->immed_dat; + } + evt->waiting = 0; + +err_get_xri_exit: + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); /* release ref */ + lpfc_bsg_event_unref(evt); /* delete */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + if (dmabuf) { + if (dmabuf->virt) + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + + if (cmdiocbq && (ret_val != IOCB_TIMEDOUT)) + lpfc_sli_release_iocbq(phba, cmdiocbq); + if (rspiocbq) + lpfc_sli_release_iocbq(phba, rspiocbq); + return ret_val; +} + +/** + * diag_cmd_data_alloc - fills in a bde struct with dma buffers + * @phba: Pointer to HBA context object + * @bpl: Pointer to 64 bit bde structure + * @size: Number of bytes to process + * @nocopydata: Flag to copy user data into the allocated buffer + * + * This function allocates page size buffers and populates an lpfc_dmabufext. + * If allowed the user data pointed to with indataptr is copied into the kernel + * memory. The chained list of page size buffers is returned. + **/ +static struct lpfc_dmabufext * +diag_cmd_data_alloc(struct lpfc_hba *phba, + struct ulp_bde64 *bpl, uint32_t size, + int nocopydata) +{ + struct lpfc_dmabufext *mlist = NULL; + struct lpfc_dmabufext *dmp; + int cnt, offset = 0, i = 0; + struct pci_dev *pcidev; + + pcidev = phba->pcidev; + + while (size) { + /* We get chunks of 4K */ + if (size > BUF_SZ_4K) + cnt = BUF_SZ_4K; + else + cnt = size; + + /* allocate struct lpfc_dmabufext buffer header */ + dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); + if (!dmp) + goto out; + + INIT_LIST_HEAD(&dmp->dma.list); + + /* Queue it to a linked list */ + if (mlist) + list_add_tail(&dmp->dma.list, &mlist->dma.list); + else + mlist = dmp; + + /* allocate buffer */ + dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, + cnt, + &(dmp->dma.phys), + GFP_KERNEL); + + if (!dmp->dma.virt) + goto out; + + dmp->size = cnt; + + if (nocopydata) { + bpl->tus.f.bdeFlags = 0; + pci_dma_sync_single_for_device(phba->pcidev, + dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); + + } else { + memset((uint8_t *)dmp->dma.virt, 0, cnt); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; + } + + /* build buffer ptr list for IOCB */ + bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); + bpl->tus.f.bdeSize = (ushort) cnt; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + bpl++; + + i++; + offset += cnt; + size -= cnt; + } + + mlist->flag = i; + return mlist; +out: + diag_cmd_data_free(phba, mlist); + return NULL; +} + +/** + * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd + * @phba: Pointer to HBA context object + * @rxxri: Receive exchange id + * @len: Number of data bytes + * + * This function allocates and posts a data buffer of sufficient size to recieve + * an unsolicted CT command. + **/ +static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, + size_t len) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; + struct lpfc_iocbq *cmdiocbq; + IOCB_t *cmd = NULL; + struct list_head head, *curr, *next; + struct lpfc_dmabuf *rxbmp; + struct lpfc_dmabuf *dmp; + struct lpfc_dmabuf *mp[2] = {NULL, NULL}; + struct ulp_bde64 *rxbpl = NULL; + uint32_t num_bde; + struct lpfc_dmabufext *rxbuffer = NULL; + int ret_val = 0; + int i = 0; + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (rxbmp != NULL) { + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); + } + + if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { + ret_val = ENOMEM; + goto err_post_rxbufs_exit; + } + + /* Queue buffers for the receive exchange */ + num_bde = (uint32_t)rxbuffer->flag; + dmp = &rxbuffer->dma; + + cmd = &cmdiocbq->iocb; + i = 0; + + INIT_LIST_HEAD(&head); + list_add_tail(&head, &dmp->list); + list_for_each_safe(curr, next, &head) { + mp[i] = list_entry(curr, struct lpfc_dmabuf, list); + list_del(curr); + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); + cmd->un.quexri64cx.buff.bde.addrHigh = + putPaddrHigh(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.addrLow = + putPaddrLow(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; + cmd->ulpCommand = CMD_QUE_XRI64_CX; + cmd->ulpPU = 0; + cmd->ulpLe = 1; + cmd->ulpBdeCount = 1; + cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; + + } else { + cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); + cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); + cmd->un.cont64[i].tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->ulpBdeCount = ++i; + + if ((--num_bde > 0) && (i < 2)) + continue; + + cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; + cmd->ulpLe = 1; + } + + cmd->ulpClass = CLASS3; + cmd->ulpContext = rxxri; + + ret_val = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + + if (ret_val == IOCB_ERROR) { + diag_cmd_data_free(phba, + (struct lpfc_dmabufext *)mp[0]); + if (mp[1]) + diag_cmd_data_free(phba, + (struct lpfc_dmabufext *)mp[1]); + dmp = list_entry(next, struct lpfc_dmabuf, list); + ret_val = EIO; + goto err_post_rxbufs_exit; + } + + lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); + if (mp[1]) { + lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); + mp[1] = NULL; + } + + /* The iocb was freed by lpfc_sli_issue_iocb */ + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + dmp = list_entry(next, struct lpfc_dmabuf, list); + ret_val = EIO; + goto err_post_rxbufs_exit; + } + + cmd = &cmdiocbq->iocb; + i = 0; + } + list_del(&head); + +err_post_rxbufs_exit: + + if (rxbmp) { + if (rxbmp->virt) + lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); + kfree(rxbmp); + } + + if (cmdiocbq) + lpfc_sli_release_iocbq(phba, cmdiocbq); + return ret_val; +} + +/** + * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself + * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job + * + * This function receives a user data buffer to be transmitted and received on + * the same port, the link must be up and in loopback mode prior + * to being called. + * 1. A kernel buffer is allocated to copy the user data into. + * 2. The port registers with "itself". + * 3. The transmit and receive exchange ids are obtained. + * 4. The receive exchange id is posted. + * 5. A new els loopback event is created. + * 6. The command and response iocbs are allocated. + * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. + * + * This function is meant to be called n times while the port is in loopback + * so it is the apps responsibility to issue a reset to take the port out + * of loopback mode. + **/ +static int +lpfc_bsg_diag_test(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct diag_mode_test *diag_mode; + struct lpfc_bsg_event *evt; + struct event_data *evdat; + struct lpfc_sli *psli = &phba->sli; + uint32_t size; + uint32_t full_size; + size_t segment_len = 0, segment_offset = 0, current_offset = 0; + uint16_t rpi; + struct lpfc_iocbq *cmdiocbq, *rspiocbq; + IOCB_t *cmd, *rsp; + struct lpfc_sli_ct_request *ctreq; + struct lpfc_dmabuf *txbmp; + struct ulp_bde64 *txbpl = NULL; + struct lpfc_dmabufext *txbuffer = NULL; + struct list_head head; + struct lpfc_dmabuf *curr; + uint16_t txxri, rxxri; + uint32_t num_bde; + uint8_t *ptr = NULL, *rx_databuf = NULL; + int rc = 0; + unsigned long flags; + void *dataout = NULL; + uint32_t total_mem; + + /* in case no data is returned return just the return code */ + job->reply->reply_payload_rcv_len = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2739 Received DIAG TEST request below minimum " + "size\n"); + rc = -EINVAL; + goto loopback_test_exit; + } + + if (job->request_payload.payload_len != + job->reply_payload.payload_len) { + rc = -EINVAL; + goto loopback_test_exit; + } + + diag_mode = (struct diag_mode_test *) + job->request->rqst_data.h_vendor.vendor_cmd; + + if ((phba->link_state == LPFC_HBA_ERROR) || + (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { + rc = -EACCES; + goto loopback_test_exit; + } + + if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { + rc = -EACCES; + goto loopback_test_exit; + } + + size = job->request_payload.payload_len; + full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ + + if ((size == 0) || (size > 80 * BUF_SZ_4K)) { + rc = -ERANGE; + goto loopback_test_exit; + } + + if (size >= BUF_SZ_4K) { + /* + * Allocate memory for ioctl data. If buffer is bigger than 64k, + * then we allocate 64k and re-use that buffer over and over to + * xfer the whole block. This is because Linux kernel has a + * problem allocating more than 120k of kernel space memory. Saw + * problem with GET_FCPTARGETMAPPING... + */ + if (size <= (64 * 1024)) + total_mem = size; + else + total_mem = 64 * 1024; + } else + /* Allocate memory for ioctl data */ + total_mem = BUF_SZ_4K; + + dataout = kmalloc(total_mem, GFP_KERNEL); + if (dataout == NULL) { + rc = -ENOMEM; + goto loopback_test_exit; + } + + ptr = dataout; + ptr += ELX_LOOPBACK_HEADER_SZ; + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + ptr, size); + + rc = lpfcdiag_loop_self_reg(phba, &rpi); + if (rc) { + rc = -ENOMEM; + goto loopback_test_exit; + } + + rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, + SLI_CT_ELX_LOOPBACK); + if (!evt) { + lpfcdiag_loop_self_unreg(phba, rpi); + rc = -ENOMEM; + goto loopback_test_exit; + } + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_add(&evt->node, &phba->ct_ev_waiters); + lpfc_bsg_event_ref(evt); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + cmdiocbq = lpfc_sli_get_iocbq(phba); + rspiocbq = lpfc_sli_get_iocbq(phba); + txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + + if (txbmp) { + txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); + INIT_LIST_HEAD(&txbmp->list); + txbpl = (struct ulp_bde64 *) txbmp->virt; + if (txbpl) + txbuffer = diag_cmd_data_alloc(phba, + txbpl, full_size, 0); + } + + if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) { + rc = -ENOMEM; + goto err_loopback_test_exit; + } + + cmd = &cmdiocbq->iocb; + rsp = &rspiocbq->iocb; + + INIT_LIST_HEAD(&head); + list_add_tail(&head, &txbuffer->dma.list); + list_for_each_entry(curr, &head, list) { + segment_len = ((struct lpfc_dmabufext *)curr)->size; + if (current_offset == 0) { + ctreq = curr->virt; + memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); + ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; + ctreq->RevisionId.bits.InId = 0; + ctreq->FsType = SLI_CT_ELX_LOOPBACK; + ctreq->FsSubType = 0; + ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; + ctreq->CommandResponse.bits.Size = size; + segment_offset = ELX_LOOPBACK_HEADER_SZ; + } else + segment_offset = 0; + + BUG_ON(segment_offset >= segment_len); + memcpy(curr->virt + segment_offset, + ptr + current_offset, + segment_len - segment_offset); + + current_offset += segment_len - segment_offset; + BUG_ON(current_offset > size); + } + list_del(&head); + + /* Build the XMIT_SEQUENCE iocb */ + + num_bde = (uint32_t)txbuffer->flag; + + cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); + cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); + cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); + + cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); + cmd->un.xseq64.w5.hcsw.Dfctl = 0; + cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + cmd->ulpContext = txxri; + + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->vport = phba->pport; + + rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, + (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); + + if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { + rc = -EIO; + goto err_loopback_test_exit; + } + + evt->waiting = 1; + rc = wait_event_interruptible_timeout( + evt->wq, !list_empty(&evt->events_to_see), + ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); + evt->waiting = 0; + if (list_empty(&evt->events_to_see)) + rc = (rc) ? -EINTR : -ETIMEDOUT; + else { + spin_lock_irqsave(&phba->ct_ev_lock, flags); + list_move(evt->events_to_see.prev, &evt->events_to_get); + evdat = list_entry(evt->events_to_get.prev, + typeof(*evdat), node); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + rx_databuf = evdat->data; + if (evdat->len != full_size) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "1603 Loopback test did not receive expected " + "data length. actual length 0x%x expected " + "length 0x%x\n", + evdat->len, full_size); + rc = -EIO; + } else if (rx_databuf == NULL) + rc = -EIO; + else { + rc = IOCB_SUCCESS; + /* skip over elx loopback header */ + rx_databuf += ELX_LOOPBACK_HEADER_SZ; + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + rx_databuf, size); + job->reply->reply_payload_rcv_len = size; + } + } + +err_loopback_test_exit: + lpfcdiag_loop_self_unreg(phba, rpi); + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + lpfc_bsg_event_unref(evt); /* release ref */ + lpfc_bsg_event_unref(evt); /* delete */ + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + if (cmdiocbq != NULL) + lpfc_sli_release_iocbq(phba, cmdiocbq); + + if (rspiocbq != NULL) + lpfc_sli_release_iocbq(phba, rspiocbq); + + if (txbmp != NULL) { + if (txbpl != NULL) { + if (txbuffer != NULL) + diag_cmd_data_free(phba, txbuffer); + lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); + } + kfree(txbmp); + } + +loopback_test_exit: + kfree(dataout); + /* make error code available to userspace */ + job->reply->result = rc; + job->dd_data = NULL; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command + * @job: GET_DFC_REV fc_bsg_job + **/ +static int +lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct get_mgmt_rev *event_req; + struct get_mgmt_rev_reply *event_reply; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2740 Received GET_DFC_REV request below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + event_req = (struct get_mgmt_rev *) + job->request->rqst_data.h_vendor.vendor_cmd; + + event_reply = (struct get_mgmt_rev_reply *) + job->reply->reply_data.vendor_reply.vendor_rsp; + + if (job->reply_len < + sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2741 Received GET_DFC_REV reply below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; + event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; +job_error: + job->reply->result = rc; + if (rc == 0) + job->job_done(job); + return rc; +} + +/** + * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler + * @phba: Pointer to HBA context object. + * @pmboxq: Pointer to mailbox command. + * + * This is completion handler function for mailbox commands issued from + * lpfc_bsg_issue_mbox function. This function is called by the + * mailbox event handler function with no lock held. This function + * will wake up thread waiting on the wait queue pointed by context1 + * of the mailbox. + **/ +void +lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) +{ + struct bsg_job_data *dd_data; + MAILBOX_t *pmb; + MAILBOX_t *mb; + struct fc_bsg_job *job; + uint32_t size; + unsigned long flags; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = pmboxq->context1; + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return; + } + + pmb = &dd_data->context_un.mbox.pmboxq->u.mb; + mb = dd_data->context_un.mbox.mb; + job = dd_data->context_un.mbox.set_job; + memcpy(mb, pmb, sizeof(*pmb)); + size = job->request_payload.payload_len; + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + mb, size); + job->reply->result = 0; + dd_data->context_un.mbox.set_job = NULL; + job->dd_data = NULL; + job->job_done(job); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); + kfree(mb); + kfree(dd_data); + return; +} + +/** + * lpfc_bsg_check_cmd_access - test for a supported mailbox command + * @phba: Pointer to HBA context object. + * @mb: Pointer to a mailbox object. + * @vport: Pointer to a vport object. + * + * Some commands require the port to be offline, some may not be called from + * the application. + **/ +static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, + MAILBOX_t *mb, struct lpfc_vport *vport) +{ + /* return negative error values for bsg job */ + switch (mb->mbxCommand) { + /* Offline only */ + case MBX_INIT_LINK: + case MBX_DOWN_LINK: + case MBX_CONFIG_LINK: + case MBX_CONFIG_RING: + case MBX_RESET_RING: + case MBX_UNREG_LOGIN: + case MBX_CLEAR_LA: + case MBX_DUMP_CONTEXT: + case MBX_RUN_DIAGS: + case MBX_RESTART: + case MBX_SET_MASK: + if (!(vport->fc_flag & FC_OFFLINE_MODE)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2743 Command 0x%x is illegal in on-line " + "state\n", + mb->mbxCommand); + return -EPERM; + } + case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: + case MBX_LOAD_SM: + case MBX_READ_NV: + case MBX_READ_CONFIG: + case MBX_READ_RCONFIG: + case MBX_READ_STATUS: + case MBX_READ_XRI: + case MBX_READ_REV: + case MBX_READ_LNK_STAT: + case MBX_DUMP_MEMORY: + case MBX_DOWN_LOAD: + case MBX_UPDATE_CFG: + case MBX_KILL_BOARD: + case MBX_LOAD_AREA: + case MBX_LOAD_EXP_ROM: + case MBX_BEACON: + case MBX_DEL_LD_ENTRY: + case MBX_SET_DEBUG: + case MBX_WRITE_WWN: + case MBX_SLI4_CONFIG: + case MBX_READ_EVENT_LOG_STATUS: + case MBX_WRITE_EVENT_LOG: + case MBX_PORT_CAPABILITIES: + case MBX_PORT_IOV_CONTROL: + break; + case MBX_SET_VARIABLE: + case MBX_RUN_BIU_DIAG64: + case MBX_READ_EVENT_LOG: + case MBX_READ_SPARM64: + case MBX_READ_LA: + case MBX_READ_LA64: + case MBX_REG_LOGIN: + case MBX_REG_LOGIN64: + case MBX_CONFIG_PORT: + case MBX_RUN_BIU_DIAG: + default: + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2742 Unknown Command 0x%x\n", + mb->mbxCommand); + return -EPERM; + } + + return 0; /* ok */ +} + +/** + * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app + * @phba: Pointer to HBA context object. + * @mb: Pointer to a mailbox object. + * @vport: Pointer to a vport object. + * + * Allocate a tracking object, mailbox command memory, get a mailbox + * from the mailbox pool, copy the caller mailbox command. + * + * If offline and the sli is active we need to poll for the command (port is + * being reset) and com-plete the job, otherwise issue the mailbox command and + * let our completion handler finish the command. + **/ +static uint32_t +lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, + struct lpfc_vport *vport) +{ + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *pmb; + MAILBOX_t *mb; + struct bsg_job_data *dd_data; + uint32_t size; + int rc = 0; + + /* allocate our bsg tracking structure */ + dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); + if (!dd_data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2727 Failed allocation of dd_data\n"); + return -ENOMEM; + } + + mb = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!mb) { + kfree(dd_data); + return -ENOMEM; + } + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) { + kfree(dd_data); + kfree(mb); + return -ENOMEM; + } + + size = job->request_payload.payload_len; + job->reply->reply_payload_rcv_len = + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + mb, size); + + rc = lpfc_bsg_check_cmd_access(phba, mb, vport); + if (rc != 0) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + return rc; /* must be negative */ + } + + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmb = &pmboxq->u.mb; + memcpy(pmb, mb, sizeof(*pmb)); + pmb->mbxOwner = OWN_HOST; + pmboxq->context1 = NULL; + pmboxq->vport = vport; + + if ((vport->fc_flag & FC_OFFLINE_MODE) || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + } + return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + } + + memcpy(mb, pmb, sizeof(*pmb)); + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + mb, size); + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + /* not waiting mbox already done */ + return 0; + } + + /* setup wake call as IOCB callback */ + pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; + /* setup context field to pass wait_queue pointer to wake function */ + pmboxq->context1 = dd_data; + dd_data->type = TYPE_MBOX; + dd_data->context_un.mbox.pmboxq = pmboxq; + dd_data->context_un.mbox.mb = mb; + dd_data->context_un.mbox.set_job = job; + job->dd_data = dd_data; + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { + kfree(dd_data); + kfree(mb); + mempool_free(pmboxq, phba->mbox_mem_pool); + return -EIO; + } + + return 1; +} + +/** + * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command + * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. + **/ +static int +lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc = 0; + + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2737 Received MBOX_REQ request below " + "minimum size\n"); + rc = -EINVAL; + goto job_error; + } + + if (job->request_payload.payload_len != PAGE_SIZE) { + rc = -EINVAL; + goto job_error; + } + + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { + rc = -EAGAIN; + goto job_error; + } + + rc = lpfc_bsg_issue_mbox(phba, job, vport); + +job_error: + if (rc == 0) { + /* job done */ + job->reply->result = 0; + job->dd_data = NULL; + job->job_done(job); + } else if (rc == 1) + /* job submitted, will complete later*/ + rc = 0; /* return zero, no error */ + else { + /* some error occurred */ + job->reply->result = rc; + job->dd_data = NULL; + } + + return rc; +} + +/** + * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job + * @job: fc_bsg_job to handle + **/ +static int +lpfc_bsg_hst_vendor(struct fc_bsg_job *job) +{ + int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; + int rc; + + switch (command) { + case LPFC_BSG_VENDOR_SET_CT_EVENT: + rc = lpfc_bsg_hba_set_event(job); + break; + case LPFC_BSG_VENDOR_GET_CT_EVENT: + rc = lpfc_bsg_hba_get_event(job); + break; + case LPFC_BSG_VENDOR_SEND_MGMT_RESP: + rc = lpfc_bsg_send_mgmt_rsp(job); + break; + case LPFC_BSG_VENDOR_DIAG_MODE: + rc = lpfc_bsg_diag_mode(job); + break; + case LPFC_BSG_VENDOR_DIAG_TEST: + rc = lpfc_bsg_diag_test(job); + break; + case LPFC_BSG_VENDOR_GET_MGMT_REV: + rc = lpfc_bsg_get_dfc_rev(job); + break; + case LPFC_BSG_VENDOR_MBOX: + rc = lpfc_bsg_mbox_cmd(job); + break; + default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; + } + + return rc; +} + +/** + * lpfc_bsg_request - handle a bsg request from the FC transport + * @job: fc_bsg_job to handle + **/ +int +lpfc_bsg_request(struct fc_bsg_job *job) +{ + uint32_t msgcode; + int rc; + + msgcode = job->request->msgcode; + switch (msgcode) { + case FC_BSG_HST_VENDOR: + rc = lpfc_bsg_hst_vendor(job); + break; + case FC_BSG_RPT_ELS: + rc = lpfc_bsg_rport_els(job); + break; + case FC_BSG_RPT_CT: + rc = lpfc_bsg_send_mgmt_cmd(job); + break; + default: + rc = -EINVAL; + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + break; + } + + return rc; +} + +/** + * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport + * @job: fc_bsg_job that has timed out + * + * This function just aborts the job's IOCB. The aborted IOCB will return to + * the waiting function which will handle passing the error back to userspace + **/ +int +lpfc_bsg_timeout(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *cmdiocb; + struct lpfc_bsg_event *evt; + struct lpfc_bsg_iocb *iocb; + struct lpfc_bsg_mbox *mbox; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct bsg_job_data *dd_data; + unsigned long flags; + + spin_lock_irqsave(&phba->ct_ev_lock, flags); + dd_data = (struct bsg_job_data *)job->dd_data; + /* timeout and completion crossed paths if no dd_data */ + if (!dd_data) { + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + return 0; } switch (dd_data->type) { @@ -1219,6 +2764,16 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) spin_unlock_irqrestore(&phba->ct_ev_lock, flags); job->job_done(job); break; + case TYPE_MBOX: + mbox = &dd_data->context_un.mbox; + /* this mbox has no job anymore */ + mbox->set_job = NULL; + job->dd_data = NULL; + job->reply->reply_payload_rcv_len = 0; + job->reply->result = -EAGAIN; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + job->job_done(job); + break; default: spin_unlock_irqrestore(&phba->ct_ev_lock, flags); break; -- GitLab From 7c0616b85ba23d0467bf0b5a6f288f5296eb05ff Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 26 Jan 2010 23:10:40 -0500 Subject: [PATCH 1790/3892] [SCSI] lpfc 8.3.8: Update Driver version to 8.3.8 Update Driver version to 8.3.8 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 792f72263f1a..e550d02bb34a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2010 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.7" +#define LPFC_DRIVER_VERSION "8.3.8" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- GitLab From 25ef231de2678690198d95dca949c3caa67a76de Mon Sep 17 00:00:00 2001 From: Will Schmidt Date: Wed, 25 Nov 2009 06:12:09 +0000 Subject: [PATCH 1791/3892] powerpc/pseries: Hypervisor call tracepoints hcall_stats touchup The tb_total and purr_total values reported via the hcall_stats code should be cumulative, rather than being replaced by the latest delta tb or purr value. Tested-by: Will Schmidt Signed-off-by: Will Schmidt Acked-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/hvCall_inst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 2f58c71b7259..1fefae76e295 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -124,8 +124,8 @@ static void probe_hcall_exit(unsigned long opcode, unsigned long retval, h = &__get_cpu_var(hcall_stats)[opcode / 4]; h->num_calls++; - h->tb_total = mftb() - h->tb_start; - h->purr_total = mfspr(SPRN_PURR) - h->purr_start; + h->tb_total += mftb() - h->tb_start; + h->purr_total += mfspr(SPRN_PURR) - h->purr_start; put_cpu_var(hcall_stats); } -- GitLab From 5a2ad98e920dd8ac4cfbc0c1556e930ba2d65427 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 Jan 2010 10:02:03 +0000 Subject: [PATCH 1792/3892] arch/powerpc: Fix continuation line formats String constants that are continued on subsequent lines with \ are not good. Signed-off-by: Joe Perches Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/nvram_64.c | 6 +++--- arch/powerpc/platforms/pseries/hotplug-cpu.c | 8 ++++---- arch/powerpc/platforms/pseries/smp.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index ad461e735aec..9cf197f01e94 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -338,8 +338,8 @@ static int __init nvram_create_os_partition(void) rc = nvram_write_header(new_part); if (rc <= 0) { - printk(KERN_ERR "nvram_create_os_partition: nvram_write_header \ - failed (%d)\n", rc); + printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " + "failed (%d)\n", rc); return rc; } @@ -349,7 +349,7 @@ static int __init nvram_create_os_partition(void) rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index); if (rc <= 0) { printk(KERN_ERR "nvram_create_os_partition: nvram_write " - "failed (%d)\n", rc); + "failed (%d)\n", rc); return rc; } diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 6ea4698d9176..a70de10332d8 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -397,12 +397,12 @@ static int parse_cede_parameters(void) CEDE_LATENCY_PARAM_MAX_LENGTH); if (call_status != 0) - printk(KERN_INFO "CEDE_LATENCY: \ - %s %s Error calling get-system-parameter(0x%x)\n", + printk(KERN_INFO "CEDE_LATENCY: " + "%s %s Error calling get-system-parameter(0x%x)\n", __FILE__, __func__, call_status); else - printk(KERN_INFO "CEDE_LATENCY: \ - get-system-parameter successful.\n"); + printk(KERN_INFO "CEDE_LATENCY: " + "get-system-parameter successful.\n"); return call_status; } diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index b4886635972c..4e7f89a84561 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -144,8 +144,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr) hcpuid = get_hard_smp_processor_id(nr); rc = plpar_hcall_norets(H_PROD, hcpuid); if (rc != H_SUCCESS) - printk(KERN_ERR "Error: Prod to wake up processor %d\ - Ret= %ld\n", nr, rc); + printk(KERN_ERR "Error: Prod to wake up processor %d " + "Ret= %ld\n", nr, rc); } } -- GitLab From 20a8ab97372e453f58a7b49e0d5e0f832406cffe Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 13:52:05 +0000 Subject: [PATCH 1793/3892] powerpc/pseries: Quieten cede latency printk The cede latency stuff is relatively new and we don't need to complain about it not working on older firmware. Signed-off-by: Anton Blanchard Acked-by: Balbir Singh Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/hotplug-cpu.c | 22 +++++--------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index a70de10332d8..d1b124e44d77 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -387,24 +387,12 @@ static char cede_parameters[CEDE_LATENCY_PARAM_MAX_LENGTH]; static int parse_cede_parameters(void) { - int call_status; - memset(cede_parameters, 0, CEDE_LATENCY_PARAM_MAX_LENGTH); - call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, - NULL, - CEDE_LATENCY_TOKEN, - __pa(cede_parameters), - CEDE_LATENCY_PARAM_MAX_LENGTH); - - if (call_status != 0) - printk(KERN_INFO "CEDE_LATENCY: " - "%s %s Error calling get-system-parameter(0x%x)\n", - __FILE__, __func__, call_status); - else - printk(KERN_INFO "CEDE_LATENCY: " - "get-system-parameter successful.\n"); - - return call_status; + return rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, + NULL, + CEDE_LATENCY_TOKEN, + __pa(cede_parameters), + CEDE_LATENCY_PARAM_MAX_LENGTH); } static int __init pseries_cpu_hotplug_init(void) -- GitLab From b926a88a7b77bc27c0e7f67166f34b854fe21ccc Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 12:26:28 +0000 Subject: [PATCH 1794/3892] powerpc: Reduce differences between pseries and ppc64 defconfigs The pseries and ppc64 defconfigs have drifted apart over the years. Reduce some of the differences while still keeping the idea that the ppc64 defconfig is cross platform but enables fewer features than pseries, eg NR_CPUS is lower. Also enable a number of common adapters as modules. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/configs/ppc64_defconfig | 75 +++++++++++++++----------- arch/powerpc/configs/pseries_defconfig | 63 ++++++++++++---------- 2 files changed, 79 insertions(+), 59 deletions(-) diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 7b3804a6e363..b5b259960794 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -137,8 +137,9 @@ CONFIG_TRACEPOINTS=y CONFIG_MARKERS=y CONFIG_OPROFILE=y CONFIG_HAVE_OPROFILE=y -# CONFIG_KPROBES is not set +CONFIG_KPROBES=y CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y CONFIG_HAVE_IOREMAP_PROT=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y @@ -191,6 +192,7 @@ CONFIG_SCANLOG=m CONFIG_LPARCFG=y CONFIG_PPC_SMLPAR=y CONFIG_CMM=y +CONFIG_DTL=y CONFIG_PPC_ISERIES=y # @@ -328,9 +330,10 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y CONFIG_KEXEC=y # CONFIG_PHYP_DUMP is not set CONFIG_IRQ_ALL_CPUS=y -# CONFIG_NUMA is not set +CONFIG_NUMA=y +CONFIG_NODES_SHIFT=8 +CONFIG_MAX_ACTIVE_REGIONS=256 CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -339,6 +342,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_DISCONTIGMEM_MANUAL is not set CONFIG_SPARSEMEM_MANUAL=y CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y @@ -354,11 +358,12 @@ CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_UNEVICTABLE_LRU=y +CONFIG_NODES_SPAN_OTHER_NODES=y CONFIG_ARCH_MEMORY_PROBE=y CONFIG_PPC_HAS_HASH_64K=y # CONFIG_PPC_64K_PAGES is not set CONFIG_FORCE_MAX_ZONEORDER=13 -# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set CONFIG_EXTRA_TARGETS="" @@ -790,12 +795,12 @@ CONFIG_SCSI_IPR=y CONFIG_SCSI_IPR_TRACE=y CONFIG_SCSI_IPR_DUMP=y # CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLA_FC is not set +CONFIG_SCSI_QLA_FC=m # CONFIG_SCSI_QLA_ISCSI is not set CONFIG_SCSI_LPFC=m # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -CONFIG_SCSI_DEBUG=m +# CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_SRP is not set # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set # CONFIG_SCSI_DH is not set @@ -867,9 +872,8 @@ CONFIG_MD_AUTODETECT=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y -CONFIG_MD_RAID10=y -CONFIG_MD_RAID456=y -CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m CONFIG_MD_MULTIPATH=m CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y @@ -984,7 +988,7 @@ CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y # CONFIG_DL2K is not set CONFIG_E1000=y -# CONFIG_E1000E is not set +CONFIG_E1000E=m # CONFIG_IP1000 is not set # CONFIG_IGB is not set # CONFIG_NS83820 is not set @@ -1006,19 +1010,19 @@ CONFIG_GELIC_WIRELESS=y # CONFIG_ATL1E is not set # CONFIG_JME is not set CONFIG_NETDEV_10000=y -# CONFIG_CHELSIO_T1 is not set -# CONFIG_CHELSIO_T3 is not set +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T3=m CONFIG_EHEA=m # CONFIG_ENIC is not set -# CONFIG_IXGBE is not set +CONFIG_IXGBE=m CONFIG_IXGB=m -# CONFIG_S2IO is not set -# CONFIG_MYRI10GE is not set -# CONFIG_NETXEN_NIC is not set +CONFIG_S2IO=m +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m # CONFIG_NIU is not set CONFIG_PASEMI_MAC=y -# CONFIG_MLX4_EN is not set -# CONFIG_MLX4_CORE is not set +CONFIG_MLX4_EN=m +CONFIG_MLX4_CORE=m # CONFIG_TEHUTI is not set # CONFIG_BNX2X is not set # CONFIG_QLGE is not set @@ -1169,7 +1173,7 @@ CONFIG_SERIAL_TXX9=y CONFIG_HAS_TXX9_SERIAL=y CONFIG_SERIAL_TXX9_NR_UARTS=6 CONFIG_SERIAL_TXX9_CONSOLE=y -# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_JSM=m # CONFIG_SERIAL_OF_PLATFORM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y @@ -1586,7 +1590,7 @@ CONFIG_USB_DEVICEFS=y CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG is not set -# CONFIG_USB_MON is not set +CONFIG_USB_MON=m # CONFIG_USB_WUSB is not set # CONFIG_USB_WUSB_CBAF is not set @@ -1686,21 +1690,22 @@ CONFIG_USB_APPLEDISPLAY=m # CONFIG_NEW_LEDS is not set # CONFIG_ACCESSIBILITY is not set CONFIG_INFINIBAND=m -# CONFIG_INFINIBAND_USER_MAD is not set -# CONFIG_INFINIBAND_USER_ACCESS is not set +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y CONFIG_INFINIBAND_ADDR_TRANS=y CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_MTHCA_DEBUG=y -# CONFIG_INFINIBAND_IPATH is not set +CONFIG_INFINIBAND_IPATH=m CONFIG_INFINIBAND_EHCA=m # CONFIG_INFINIBAND_AMSO1100 is not set -# CONFIG_MLX4_INFINIBAND is not set +CONFIG_MLX4_INFINIBAND=m # CONFIG_INFINIBAND_NES is not set CONFIG_INFINIBAND_IPOIB=m -# CONFIG_INFINIBAND_IPOIB_CM is not set +CONFIG_INFINIBAND_IPOIB_CM=y CONFIG_INFINIBAND_IPOIB_DEBUG=y # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set -# CONFIG_INFINIBAND_SRP is not set +CONFIG_INFINIBAND_SRP=m CONFIG_INFINIBAND_ISER=m CONFIG_EDAC=y @@ -1798,7 +1803,7 @@ CONFIG_REISERFS_FS=y CONFIG_REISERFS_FS_XATTR=y CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=y +CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y CONFIG_JFS_SECURITY=y # CONFIG_JFS_DEBUG is not set @@ -1811,14 +1816,22 @@ CONFIG_XFS_POSIX_ACL=y # CONFIG_XFS_RT is not set # CONFIG_XFS_DEBUG is not set # CONFIG_GFS2_FS is not set -# CONFIG_OCFS2_FS is not set +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_FS_O2CB=m +CONFIG_OCFS2_FS_STATS=y +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +# CONFIG_OCFS2_COMPAT_JBD is not set +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set CONFIG_AUTOFS4_FS=m -# CONFIG_FUSE_FS is not set +CONFIG_FUSE_FS=m # # CD-ROM/DVD Filesystems @@ -1851,7 +1864,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=m # # Miscellaneous filesystems @@ -2075,7 +2088,7 @@ CONFIG_XMON=y CONFIG_XMON_DISASSEMBLY=y CONFIG_DEBUGGER=y CONFIG_IRQSTACKS=y -# CONFIG_VIRQ_DEBUG is not set +CONFIG_VIRQ_DEBUG=y CONFIG_BOOTX_TEXT=y # CONFIG_PPC_EARLY_DEBUG is not set diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index ca9ff9aad74a..41de3ddc9f24 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -159,7 +159,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y -# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set CONFIG_BLOCK_COMPAT=y @@ -191,6 +191,7 @@ CONFIG_SCANLOG=m CONFIG_LPARCFG=y CONFIG_PPC_SMLPAR=y CONFIG_CMM=y +CONFIG_DTL=y # CONFIG_PPC_ISERIES is not set # CONFIG_PPC_PMAC is not set # CONFIG_PPC_MAPLE is not set @@ -255,7 +256,8 @@ CONFIG_KEXEC=y # CONFIG_PHYP_DUMP is not set CONFIG_IRQ_ALL_CPUS=y CONFIG_NUMA=y -CONFIG_NODES_SHIFT=4 +CONFIG_NODES_SHIFT=8 +CONFIG_MAX_ACTIVE_REGIONS=256 CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y @@ -270,7 +272,9 @@ CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y CONFIG_SPARSEMEM_VMEMMAP=y -# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y +CONFIG_MEMORY_HOTREMOVE=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y @@ -705,7 +709,7 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_MD_RAID10=m -# CONFIG_MD_RAID456 is not set +CONFIG_MD_RAID456=m CONFIG_MD_MULTIPATH=m CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y @@ -800,7 +804,7 @@ CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y # CONFIG_DL2K is not set CONFIG_E1000=y -# CONFIG_E1000E is not set +CONFIG_E1000E=m # CONFIG_IP1000 is not set # CONFIG_IGB is not set # CONFIG_NS83820 is not set @@ -818,18 +822,18 @@ CONFIG_TIGON3=y # CONFIG_ATL1E is not set # CONFIG_JME is not set CONFIG_NETDEV_10000=y -# CONFIG_CHELSIO_T1 is not set -# CONFIG_CHELSIO_T3 is not set +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T3=m CONFIG_EHEA=y # CONFIG_ENIC is not set -# CONFIG_IXGBE is not set +CONFIG_IXGBE=m CONFIG_IXGB=m CONFIG_S2IO=m -# CONFIG_MYRI10GE is not set -# CONFIG_NETXEN_NIC is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m # CONFIG_NIU is not set -# CONFIG_MLX4_EN is not set -# CONFIG_MLX4_CORE is not set +CONFIG_MLX4_EN=m +CONFIG_MLX4_CORE=m # CONFIG_TEHUTI is not set # CONFIG_BNX2X is not set # CONFIG_QLGE is not set @@ -894,7 +898,7 @@ CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_EVBUG is not set # @@ -1271,7 +1275,7 @@ CONFIG_USB_DEVICEFS=y CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG is not set -CONFIG_USB_MON=y +CONFIG_USB_MON=m # CONFIG_USB_WUSB is not set # CONFIG_USB_WUSB_CBAF is not set @@ -1311,7 +1315,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # # may also be needed; see USB_STORAGE Help for more information # -CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set @@ -1322,7 +1326,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_ALAUDA is not set -CONFIG_USB_STORAGE_ONETOUCH=y +# CONFIG_USB_STORAGE_ONETOUCH is not set # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_LIBUSUAL is not set @@ -1377,17 +1381,17 @@ CONFIG_INFINIBAND_USER_MEM=y CONFIG_INFINIBAND_ADDR_TRANS=y CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_MTHCA_DEBUG=y -# CONFIG_INFINIBAND_IPATH is not set +CONFIG_INFINIBAND_IPATH=m CONFIG_INFINIBAND_EHCA=m # CONFIG_INFINIBAND_AMSO1100 is not set -# CONFIG_MLX4_INFINIBAND is not set +CONFIG_MLX4_INFINIBAND=m # CONFIG_INFINIBAND_NES is not set CONFIG_INFINIBAND_IPOIB=m -# CONFIG_INFINIBAND_IPOIB_CM is not set +CONFIG_INFINIBAND_IPOIB_CM=y CONFIG_INFINIBAND_IPOIB_DEBUG=y # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set CONFIG_INFINIBAND_SRP=m -# CONFIG_INFINIBAND_ISER is not set +CONFIG_INFINIBAND_ISER=m # CONFIG_EDAC is not set # CONFIG_RTC_CLASS is not set # CONFIG_DMADEVICES is not set @@ -1443,6 +1447,9 @@ CONFIG_OCFS2_FS_STATS=y CONFIG_OCFS2_DEBUG_MASKLOG=y # CONFIG_OCFS2_DEBUG_FS is not set # CONFIG_OCFS2_COMPAT_JBD is not set +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -1455,8 +1462,8 @@ CONFIG_FUSE_FS=m # CD-ROM/DVD Filesystems # CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set CONFIG_UDF_FS=m CONFIG_UDF_NLS=y @@ -1508,14 +1515,14 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_V2_ACL=y CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_NFS_ACL_SUPPORT=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y @@ -1681,12 +1688,12 @@ CONFIG_DYNAMIC_PRINTK_DEBUG=y CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set CONFIG_DEBUG_STACKOVERFLOW=y -# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_STACK_USAGE=y # CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_HCALL_STATS is not set -# CONFIG_CODE_PATCHING_SELFTEST is not set -# CONFIG_FTR_FIXUP_SELFTEST is not set -# CONFIG_MSI_BITMAP_SELFTEST is not set +CONFIG_CODE_PATCHING_SELFTEST=y +CONFIG_FTR_FIXUP_SELFTEST=y +CONFIG_MSI_BITMAP_SELFTEST=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_XMON_DISASSEMBLY=y -- GitLab From 66fcb1059deeae072c1bf1536a8e2613028bce3e Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 14:44:16 +0000 Subject: [PATCH 1795/3892] powerpc: Add last sysfs file and dump of ftrace buffer to oops printout Add printout of last accessed sysfs file, added to x86 in ae87221d3ce49d9de1e43756da834fd0bf05a2ad (sysfs: crash debugging) Also add the notify_die hook that allows us to print out the ftrace buffer on oops. This is useful in conjunction with ftrace function_graph: Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=128 NUMA pSeries last sysfs file: /sys/class/net/tunl0/type Dumping ftrace buffer: ... 0) | .sysrq_handle_crash() { 0) 0.476 us | .hash_page(); 0) 0.488 us | .xmon_fault_handler(); 0) | .bad_page_fault() { 0) | .search_exception_tables() { 0) 0.590 us | .search_module_extables(); 0) 2.546 us | } 0) | .printk() { 0) | .vprintk() { 0) 0.488 us | ._raw_spin_lock(); 0) 0.572 us | .emit_log_char(); Showing the function graph of a sysrq-c crash. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/traps.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4588d1eb18d2..0a320dbd950a 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -146,6 +146,11 @@ int die(const char *str, struct pt_regs *regs, long err) #endif printk("%s\n", ppc_md.name ? ppc_md.name : ""); + sysfs_printk_last_file(); + if (notify_die(DIE_OOPS, str, regs, err, 255, + SIGSEGV) == NOTIFY_STOP) + return 1; + print_modules(); show_regs(regs); } else { -- GitLab From 7317ac87119dfb6fac36af4bcc64a25b62b5898d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 12:30:12 +0000 Subject: [PATCH 1796/3892] powerpc: Convert mmu context allocator from idr to ida We can use the much more lightweight ida allocator since we don't need the pointer storage idr provides. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/mmu_context_hash64.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index b910d37aea1a..51622daae09d 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -23,7 +23,7 @@ #include static DEFINE_SPINLOCK(mmu_context_lock); -static DEFINE_IDR(mmu_context_idr); +static DEFINE_IDA(mmu_context_ida); /* * The proto-VSID space has 2^35 - 1 segments available for user mappings. @@ -39,11 +39,11 @@ int __init_new_context(void) int err; again: - if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) + if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL)) return -ENOMEM; spin_lock(&mmu_context_lock); - err = idr_get_new_above(&mmu_context_idr, NULL, 1, &index); + err = ida_get_new_above(&mmu_context_ida, 1, &index); spin_unlock(&mmu_context_lock); if (err == -EAGAIN) @@ -53,7 +53,7 @@ again: if (index > MAX_CONTEXT) { spin_lock(&mmu_context_lock); - idr_remove(&mmu_context_idr, index); + ida_remove(&mmu_context_ida, index); spin_unlock(&mmu_context_lock); return -ENOMEM; } @@ -85,7 +85,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) void __destroy_context(int context_id) { spin_lock(&mmu_context_lock); - idr_remove(&mmu_context_idr, context_id); + ida_remove(&mmu_context_ida, context_id); spin_unlock(&mmu_context_lock); } EXPORT_SYMBOL_GPL(__destroy_context); -- GitLab From a13672fb30b46eaf9fa50357e1e863de00631401 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 13:23:30 +0000 Subject: [PATCH 1797/3892] powerpc: Reformat SD_NODE_INIT to match x86 Clean up SD_NODE_INITS so we can easily compare it to x86. Similar to the work in 47734f89be0614b5acbd6a532390f9c72f019648 (sched: Clean up topology.h) Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 48 ++++++++++++++++------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index bbf89701d7a4..8eaec310a25b 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -38,27 +38,33 @@ static inline int pcibus_to_node(struct pci_bus *bus) cpumask_of_node(pcibus_to_node(bus))) /* sched_domains SD_NODE_INIT for PPC64 machines */ -#define SD_NODE_INIT (struct sched_domain) { \ - .parent = NULL, \ - .child = NULL, \ - .groups = NULL, \ - .min_interval = 8, \ - .max_interval = 32, \ - .busy_factor = 32, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 1, \ - .busy_idx = 3, \ - .idle_idx = 1, \ - .newidle_idx = 0, \ - .wake_idx = 0, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_EXEC \ - | SD_BALANCE_FORK \ - | SD_BALANCE_NEWIDLE \ - | SD_SERIALIZE, \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .nr_balance_failed = 0, \ +#define SD_NODE_INIT (struct sched_domain) { \ + .min_interval = 8, \ + .max_interval = 32, \ + .busy_factor = 32, \ + .imbalance_pct = 125, \ + .cache_nice_tries = 1, \ + .busy_idx = 3, \ + .idle_idx = 1, \ + .newidle_idx = 0, \ + .wake_idx = 0, \ + .forkexec_idx = 0, \ + \ + .flags = 1*SD_LOAD_BALANCE \ + | 1*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_EXEC \ + | 1*SD_BALANCE_FORK \ + | 0*SD_BALANCE_WAKE \ + | 0*SD_WAKE_AFFINE \ + | 0*SD_PREFER_LOCAL \ + | 0*SD_SHARE_CPUPOWER \ + | 0*SD_POWERSAVINGS_BALANCE \ + | 0*SD_SHARE_PKG_RESOURCES \ + | 1*SD_SERIALIZE \ + | 0*SD_PREFER_SIBLING \ + , \ + .last_balance = jiffies, \ + .balance_interval = 1, \ } extern void __init dump_numa_cpu_topology(void); -- GitLab From 0b9612c210f6bf6efb32ab84b8f34018eaacb08d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 13:07:36 +0000 Subject: [PATCH 1798/3892] powerpc: Make powerpc_firmware_features __read_mostly We use firmware_has_feature quite a lot these days, so it's worth putting powerpc_firmware_features into __read_mostly. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c index 1679a70bbcad..6b1f4271eb53 100644 --- a/arch/powerpc/kernel/firmware.c +++ b/arch/powerpc/kernel/firmware.c @@ -17,5 +17,5 @@ #include -unsigned long powerpc_firmware_features; +unsigned long powerpc_firmware_features __read_mostly; EXPORT_SYMBOL_GPL(powerpc_firmware_features); -- GitLab From 8354be9c104db8e92bb079e29540fbafb7f09b5c Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Sat, 6 Feb 2010 07:47:20 +0000 Subject: [PATCH 1799/3892] powerpc: Remove trailing space in messages Signed-off-by: Frans Pop Cc: linuxppc-dev@ozlabs.org Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/lparcfg.c | 10 +++++----- arch/powerpc/kernel/pci_of_scan.c | 2 +- arch/powerpc/platforms/85xx/stx_gp3.c | 2 +- arch/powerpc/platforms/iseries/proc.c | 2 +- arch/powerpc/platforms/iseries/setup.c | 2 +- arch/powerpc/platforms/powermac/bootx_init.c | 4 ++-- arch/powerpc/platforms/pseries/eeh_driver.c | 6 +++--- arch/powerpc/platforms/pseries/pci_dlpar.c | 2 +- arch/powerpc/platforms/pseries/phyp_dump.c | 6 +++--- arch/powerpc/platforms/pseries/xics.c | 2 +- arch/powerpc/sysdev/mpic.c | 2 +- arch/powerpc/sysdev/qe_lib/qe_ic.c | 2 +- arch/powerpc/sysdev/qe_lib/qe_io.c | 8 ++++---- drivers/macintosh/therm_adt746x.c | 2 +- drivers/ps3/ps3av.c | 2 +- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 79a00bb9c64c..d09d1c615150 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -359,7 +359,7 @@ static void parse_system_parameter_string(struct seq_file *m) unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!local_buffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n", + printk(KERN_ERR "%s %s kmalloc failure at line %d\n", __FILE__, __func__, __LINE__); return; } @@ -383,13 +383,13 @@ static void parse_system_parameter_string(struct seq_file *m) int idx, w_idx; char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!workbuffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n", + printk(KERN_ERR "%s %s kmalloc failure at line %d\n", __FILE__, __func__, __LINE__); kfree(local_buffer); return; } #ifdef LPARCFG_DEBUG - printk(KERN_INFO "success calling get-system-parameter \n"); + printk(KERN_INFO "success calling get-system-parameter\n"); #endif splpar_strlen = local_buffer[0] * 256 + local_buffer[1]; local_buffer += 2; /* step over strlen value */ @@ -440,7 +440,7 @@ static int lparcfg_count_active_processors(void) while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) { #ifdef LPARCFG_DEBUG - printk(KERN_ERR "cpus_dn %p \n", cpus_dn); + printk(KERN_ERR "cpus_dn %p\n", cpus_dn); #endif count++; } @@ -725,7 +725,7 @@ static int lparcfg_data(struct seq_file *m, void *v) const unsigned int *lp_index_ptr; unsigned int lp_index = 0; - seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); + seq_printf(m, "%s %s\n", MODULE_NAME, MODULE_VERS); rootdn = of_find_node_by_path("/"); if (rootdn) { diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 4aa17401657b..cd11d5ca80df 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -304,7 +304,7 @@ static void __devinit __of_scan_bus(struct device_node *node, int reglen, devfn; struct pci_dev *dev; - pr_debug("of_scan_bus(%s) bus no %d... \n", + pr_debug("of_scan_bus(%s) bus no %d...\n", node->full_name, bus->number); /* Scan direct children */ diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index f559918f3c6f..bc33d1859ae7 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -134,7 +134,7 @@ static void stx_gp3_show_cpuinfo(struct seq_file *m) pvid = mfspr(SPRN_PVR); svid = mfspr(SPRN_SVR); - seq_printf(m, "Vendor\t\t: RPC Electronics STx \n"); + seq_printf(m, "Vendor\t\t: RPC Electronics STx\n"); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c index 91f4c6cd4b99..06763682db47 100644 --- a/arch/powerpc/platforms/iseries/proc.c +++ b/arch/powerpc/platforms/iseries/proc.c @@ -85,7 +85,7 @@ static int proc_titantod_show(struct seq_file *m, void *v) seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); - seq_printf(m, " titan jiffies = %lu.%04lu \n", titan_jiffies, + seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies, titan_jiff_rem_usec); seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec); diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index a6cd3394feaa..b0863410517f 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -256,7 +256,7 @@ static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, max_entries); - printk("Mainstore_VPD: numMemoryBlocks = %ld \n", mem_blocks); + printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks); for (i = 0; i < mem_blocks; ++i) { printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" " abs chunks %016lx - %016lx\n", diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 9dd789a7370d..84d7fd9bcc69 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -539,7 +539,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) if (model && (strcmp(model, "iMac,1") == 0 || strcmp(model, "PowerMac1,1") == 0)) { - bootx_printf("iMac,1 detected, shutting down USB \n"); + bootx_printf("iMac,1 detected, shutting down USB\n"); out_le32((unsigned __iomem *)0x80880008, 1); /* XXX */ } } @@ -554,7 +554,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) } else space = bi->totalParamsSize; - bootx_printf("Total space used by parameters & ramdisk: 0x%x \n", space); + bootx_printf("Total space used by parameters & ramdisk: 0x%x\n", space); /* New BootX will have flushed all TLBs and enters kernel with * MMU switched OFF, so this should not be useful anymore. diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index ef8e45448480..0c252c3a5f9f 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -478,9 +478,9 @@ excess_failures: * due to actual, failed cards. */ printk(KERN_ERR - "EEH: PCI device at location=%s driver=%s pci addr=%s \n" + "EEH: PCI device at location=%s driver=%s pci addr=%s\n" "has failed %d times in the last hour " - "and has been permanently disabled. \n" + "and has been permanently disabled.\n" "Please try reseating this device or replacing it.\n", location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); goto perm_error; @@ -488,7 +488,7 @@ excess_failures: hard_fail: printk(KERN_ERR "EEH: Unable to recover from failure of PCI device " - "at location=%s driver=%s pci addr=%s \n" + "at location=%s driver=%s pci addr=%s\n" "Please try reseating this device or replacing it.\n", location, drv_str, pci_str); diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index b6fa3e4b51b5..4b7a062dee15 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -165,7 +165,7 @@ int remove_phb_dynamic(struct pci_controller *phb) struct resource *res; int rc, i; - pr_debug("PCI: Removing PHB %04x:%02x... \n", + pr_debug("PCI: Removing PHB %04x:%02x...\n", pci_domain_nr(b), b->number); /* We cannot to remove a root bus that has children */ diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index 15eb6107bcd2..225a50ab14be 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -150,7 +150,7 @@ static void print_dump_header(const struct phyp_dump_header *ph) printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); /*set cpu state and hpte states as well scratch pad area */ - printk(KERN_INFO " CPU AREA \n"); + printk(KERN_INFO " CPU AREA\n"); printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); @@ -161,7 +161,7 @@ static void print_dump_header(const struct phyp_dump_header *ph) printk(KERN_INFO "cpu length_copied =%llx\n", ph->cpu_data.length_copied); - printk(KERN_INFO " HPTE AREA \n"); + printk(KERN_INFO " HPTE AREA\n"); printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); @@ -172,7 +172,7 @@ static void print_dump_header(const struct phyp_dump_header *ph) printk(KERN_INFO "HPTE length_copied =%llx\n", ph->hpte_data.length_copied); - printk(KERN_INFO " SRSD AREA \n"); + printk(KERN_INFO " SRSD AREA\n"); printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 1ee66db003be..e9a52ec05a0f 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -127,7 +127,7 @@ static inline unsigned int lpar_xirr_info_get(void) lpar_rc = plpar_xirr(&return_value); if (lpar_rc != H_SUCCESS) - panic(" bad return code xirr - rc = %lx \n", lpar_rc); + panic(" bad return code xirr - rc = %lx\n", lpar_rc); return (unsigned int)return_value; } diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 470dc6c11d57..314f0fa46924 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1575,7 +1575,7 @@ void mpic_request_ipis(void) int i; BUG_ON(mpic == NULL); - printk(KERN_INFO "mpic: requesting IPIs ... \n"); + printk(KERN_INFO "mpic: requesting IPIs...\n"); for (i = 0; i < 4; i++) { unsigned int vipi = irq_create_mapping(mpic->irqhost, diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 2acc928d1920..5f0b0368a209 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -256,7 +256,7 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, struct irq_chip *chip; if (qe_ic_info[hw].mask == 0) { - printk(KERN_ERR "Can't map reserved IRQ \n"); + printk(KERN_ERR "Can't map reserved IRQ\n"); return -EINVAL; } /* Default chip */ diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index 7c87460179ef..77e4934b88c5 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -157,13 +157,13 @@ int par_io_of_config(struct device_node *np) const unsigned int *pio_map; if (par_io == NULL) { - printk(KERN_ERR "par_io not initialized \n"); + printk(KERN_ERR "par_io not initialized\n"); return -1; } ph = of_get_property(np, "pio-handle", NULL); if (ph == NULL) { - printk(KERN_ERR "pio-handle not available \n"); + printk(KERN_ERR "pio-handle not available\n"); return -1; } @@ -171,12 +171,12 @@ int par_io_of_config(struct device_node *np) pio_map = of_get_property(pio, "pio-map", &pio_map_len); if (pio_map == NULL) { - printk(KERN_ERR "pio-map is not set! \n"); + printk(KERN_ERR "pio-map is not set!\n"); return -1; } pio_map_len /= sizeof(unsigned int); if ((pio_map_len % 6) != 0) { - printk(KERN_ERR "pio-map format wrong! \n"); + printk(KERN_ERR "pio-map format wrong!\n"); return -1; } diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 58809b0510f9..c42eeb43042d 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -316,7 +316,7 @@ static void update_fans_speed (struct thermostat *th) if (verbose) printk(KERN_DEBUG "adt746x: Setting fans speed to %d " - "(limit exceeded by %d on %s) \n", + "(limit exceeded by %d on %s)\n", new_speed, var, sensor_location[fan_number+1]); write_both_fan_speed(th, new_speed); diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index e82d8c9c6cda..95a689befc84 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -532,7 +532,7 @@ static void ps3av_set_videomode_packet(u32 id) res = ps3av_cmd_avb_param(&avb_param, len); if (res == PS3AV_STATUS_NO_SYNC_HEAD) printk(KERN_WARNING - "%s: Command failed. Please try your request again. \n", + "%s: Command failed. Please try your request again.\n", __func__); else if (res) dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); -- GitLab From 44c9f3cc1a07503b653b571eac5792436da39a30 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 19:37:29 +0000 Subject: [PATCH 1800/3892] powerpc: Clear MSR_RI during RTAS calls RTAS should never cause an exception but if it does (for example accessing outside our RMO) then we might go a long way through the kernel before oopsing. If we unset MSR_RI we should at least stop things on exception exit. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/entry_64.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bdcb557d470a..07109d843787 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -791,9 +791,8 @@ _GLOBAL(enter_rtas) li r9,1 rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG) - ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP + ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP|MSR_RI andc r6,r0,r9 - ori r6,r6,MSR_RI sync /* disable interrupts so SRR0/1 */ mtmsrd r0 /* don't get trashed */ -- GitLab From b919ee827e048826786fd7e889a2b04f63382fe6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 7 Feb 2010 19:26:29 +0000 Subject: [PATCH 1801/3892] powerpc: Only print clockevent settings once The clockevent multiplier and shift is useful information, but we only need to print it once. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 0a5b1081a50e..ed1c0f58344a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -935,8 +935,8 @@ static void register_decrementer_clockevent(int cpu) *dec = decrementer_clockevent; dec->cpumask = cpumask_of(cpu); - printk(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n", - dec->name, dec->mult, dec->shift, cpu); + printk_once(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n", + dec->name, dec->mult, dec->shift, cpu); clockevents_register_device(dec); } -- GitLab From dce17d4ff366230aeeaaf42512bba3711243cf1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Feb 2010 09:25:26 +0100 Subject: [PATCH 1802/3892] ALSA: hda - Fix default polarity of mute-LED GPIO on 92HD83x/88x codecs The previous commit caused a regression on HP laptops with 92HD83x/88x codecs. The default polarity of mute-LED GPIO is inverted on these devices. Reference: Novell bnc#578190 https://bugzilla.novell.com/show_bug.cgi?id=578190 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ec0637e7d488..8c416bb18a57 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4790,7 +4790,7 @@ static void set_hp_led_gpio(struct hda_codec *codec) * Need more information on whether it is true across the entire series. * -- kunal */ -static int find_mute_led_gpio(struct hda_codec *codec) +static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity) { struct sigmatel_spec *spec = codec->spec; const struct dmi_device *dev = NULL; @@ -4817,7 +4817,7 @@ static int find_mute_led_gpio(struct hda_codec *codec) */ if (!hp_blike_system(codec->subsystem_id)) { set_hp_led_gpio(codec); - spec->gpio_led_polarity = 1; + spec->gpio_led_polarity = default_polarity; return 1; } } @@ -5343,7 +5343,7 @@ again: codec->patch_ops = stac92xx_patch_ops; - if (find_mute_led_gpio(codec)) + if (find_mute_led_gpio(codec, 0)) snd_printd("mute LED gpio %d polarity %d\n", spec->gpio_led, spec->gpio_led_polarity); @@ -5705,7 +5705,7 @@ again: } } - if (find_mute_led_gpio(codec)) + if (find_mute_led_gpio(codec, 1)) snd_printd("mute LED gpio %d polarity %d\n", spec->gpio_led, spec->gpio_led_polarity); -- GitLab From 577cd7584cf5199f1ea22cca0ad1fa129a98effa Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 04:24:46 +0000 Subject: [PATCH 1803/3892] sh: extend INTC with struct intc_hw_desc This patch updates the INTC code by moving all vectors, groups and registers from struct intc_desc to struct intc_hw_desc. The idea is that INTC tables should go from using the macro(s) DECLARE_INTC_DESC..() only to using struct intc_desc with name and hw initialized using the macro INTC_HW_DESC(). This move makes it easy to initialize an extended struct intc_desc in the future. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 88 +++++++++++++++++++++-------------------- include/linux/sh_intc.h | 31 +++++++++------ 2 files changed, 65 insertions(+), 54 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index d5d7f23c19a5..5ec0fffa7db4 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -400,11 +400,11 @@ static unsigned int __init intc_get_reg(struct intc_desc_int *d, static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) { - struct intc_group *g = desc->groups; + struct intc_group *g = desc->hw.groups; unsigned int i, j; - for (i = 0; g && enum_id && i < desc->nr_groups; i++) { - g = desc->groups + i; + for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) { + g = desc->hw.groups + i; for (j = 0; g->enum_ids[j]; j++) { if (g->enum_ids[j] != enum_id) @@ -421,12 +421,12 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps) { - struct intc_mask_reg *mr = desc->mask_regs; + struct intc_mask_reg *mr = desc->hw.mask_regs; unsigned int i, j, fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { - mr = desc->mask_regs + i; + for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) { + mr = desc->hw.mask_regs + i; for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { if (mr->enum_ids[j] != enum_id) @@ -469,12 +469,12 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id, int do_grps) { - struct intc_prio_reg *pr = desc->prio_regs; + struct intc_prio_reg *pr = desc->hw.prio_regs; unsigned int i, j, fn, mode, bit; unsigned long reg_e, reg_d; - for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { - pr = desc->prio_regs + i; + for (i = 0; pr && enum_id && i < desc->hw.nr_prio_regs; i++) { + pr = desc->hw.prio_regs + i; for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { if (pr->enum_ids[j] != enum_id) @@ -517,12 +517,12 @@ static unsigned int __init intc_ack_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) { - struct intc_mask_reg *mr = desc->ack_regs; + struct intc_mask_reg *mr = desc->hw.ack_regs; unsigned int i, j, fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) { - mr = desc->ack_regs + i; + for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) { + mr = desc->hw.ack_regs + i; for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { if (mr->enum_ids[j] != enum_id) @@ -549,11 +549,11 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) { - struct intc_sense_reg *sr = desc->sense_regs; + struct intc_sense_reg *sr = desc->hw.sense_regs; unsigned int i, j, fn, bit; - for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) { - sr = desc->sense_regs + i; + for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) { + sr = desc->hw.sense_regs + i; for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { if (sr->enum_ids[j] != enum_id) @@ -656,7 +656,7 @@ static void __init intc_register_irq(struct intc_desc *desc, /* irq should be disabled by default */ d->chip.mask(irq); - if (desc->ack_regs) + if (desc->hw.ack_regs) ack_handle[irq] = intc_ack_data(desc, d, enum_id); } @@ -684,6 +684,7 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) void __init register_intc_controller(struct intc_desc *desc) { unsigned int i, k, smp; + struct intc_hw_desc *hw = &desc->hw; struct intc_desc_int *d; d = kzalloc(sizeof(*d), GFP_NOWAIT); @@ -691,10 +692,10 @@ void __init register_intc_controller(struct intc_desc *desc) INIT_LIST_HEAD(&d->list); list_add(&d->list, &intc_list); - d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; - d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; - d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; - d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0; + d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; + d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; + d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; + d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); #ifdef CONFIG_SMP @@ -702,30 +703,31 @@ void __init register_intc_controller(struct intc_desc *desc) #endif k = 0; - if (desc->mask_regs) { - for (i = 0; i < desc->nr_mask_regs; i++) { - smp = IS_SMP(desc->mask_regs[i]); - k += save_reg(d, k, desc->mask_regs[i].set_reg, smp); - k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp); + if (hw->mask_regs) { + for (i = 0; i < hw->nr_mask_regs; i++) { + smp = IS_SMP(hw->mask_regs[i]); + k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); + k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); } } - if (desc->prio_regs) { - d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT); + if (hw->prio_regs) { + d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), + GFP_NOWAIT); - for (i = 0; i < desc->nr_prio_regs; i++) { - smp = IS_SMP(desc->prio_regs[i]); - k += save_reg(d, k, desc->prio_regs[i].set_reg, smp); - k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp); + for (i = 0; i < hw->nr_prio_regs; i++) { + smp = IS_SMP(hw->prio_regs[i]); + k += save_reg(d, k, hw->prio_regs[i].set_reg, smp); + k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp); } } - if (desc->sense_regs) { - d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT); + if (hw->sense_regs) { + d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), + GFP_NOWAIT); - for (i = 0; i < desc->nr_sense_regs; i++) { - k += save_reg(d, k, desc->sense_regs[i].reg, 0); - } + for (i = 0; i < hw->nr_sense_regs; i++) + k += save_reg(d, k, hw->sense_regs[i].reg, 0); } d->chip.name = desc->name; @@ -738,9 +740,9 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.set_type = intc_set_sense; d->chip.set_wake = intc_set_wake; - if (desc->ack_regs) { - for (i = 0; i < desc->nr_ack_regs; i++) - k += save_reg(d, k, desc->ack_regs[i].set_reg, 0); + if (hw->ack_regs) { + for (i = 0; i < hw->nr_ack_regs; i++) + k += save_reg(d, k, hw->ack_regs[i].set_reg, 0); d->chip.mask_ack = intc_mask_ack; } @@ -748,8 +750,8 @@ void __init register_intc_controller(struct intc_desc *desc) BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ /* register the vectors one by one */ - for (i = 0; i < desc->nr_vectors; i++) { - struct intc_vect *vect = desc->vectors + i; + for (i = 0; i < hw->nr_vectors; i++) { + struct intc_vect *vect = hw->vectors + i; unsigned int irq = evt2irq(vect->vect); struct irq_desc *irq_desc; @@ -764,8 +766,8 @@ void __init register_intc_controller(struct intc_desc *desc) intc_register_irq(desc, d, vect->enum_id, irq); - for (k = i + 1; k < desc->nr_vectors; k++) { - struct intc_vect *vect2 = desc->vectors + k; + for (k = i + 1; k < hw->nr_vectors; k++) { + struct intc_vect *vect2 = hw->vectors + k; unsigned int irq2 = evt2irq(vect2->vect); if (vect->enum_id != vect2->enum_id) diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h index 4ef246f14654..7b37526bb73f 100644 --- a/include/linux/sh_intc.h +++ b/include/linux/sh_intc.h @@ -45,7 +45,7 @@ struct intc_sense_reg { #define INTC_SMP(stride, nr) #endif -struct intc_desc { +struct intc_hw_desc { struct intc_vect *vectors; unsigned int nr_vectors; struct intc_group *groups; @@ -56,29 +56,38 @@ struct intc_desc { unsigned int nr_prio_regs; struct intc_sense_reg *sense_regs; unsigned int nr_sense_regs; - char *name; struct intc_mask_reg *ack_regs; unsigned int nr_ack_regs; }; #define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) +#define INTC_HW_DESC(vectors, groups, mask_regs, \ + prio_regs, sense_regs, ack_regs) \ +{ \ + _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \ + _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \ + _INTC_ARRAY(sense_regs), _INTC_ARRAY(ack_regs), \ +} + +struct intc_desc { + char *name; + struct intc_hw_desc hw; +}; + #define DECLARE_INTC_DESC(symbol, chipname, vectors, groups, \ mask_regs, prio_regs, sense_regs) \ struct intc_desc symbol __initdata = { \ - _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \ - _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \ - _INTC_ARRAY(sense_regs), \ - chipname, \ + .name = chipname, \ + .hw = INTC_HW_DESC(vectors, groups, mask_regs, \ + prio_regs, sense_regs, NULL), \ } #define DECLARE_INTC_DESC_ACK(symbol, chipname, vectors, groups, \ mask_regs, prio_regs, sense_regs, ack_regs) \ struct intc_desc symbol __initdata = { \ - _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \ - _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \ - _INTC_ARRAY(sense_regs), \ - chipname, \ - _INTC_ARRAY(ack_regs), \ + .name = chipname, \ + .hw = INTC_HW_DESC(vectors, groups, mask_regs, \ + prio_regs, sense_regs, ack_regs), \ } void __init register_intc_controller(struct intc_desc *desc); -- GitLab From d519095344fda705c9840a579acf6aa6205c37cc Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 04:29:22 +0000 Subject: [PATCH 1804/3892] sh: extend INTC with force_enable Extend the shared INTC code with force_enable support to allow keeping mask bits statically enabled. Needed by upcoming INTC SDHI patches that mux together a bunch of vectors to a single linux interrupt which is masked by a priority register, but needs individual mask bits constantly enabled. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 151 +++++++++++++++++++++++++++++++++++----- include/linux/sh_intc.h | 1 + 2 files changed, 133 insertions(+), 19 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 5ec0fffa7db4..ccee18945d91 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -259,6 +259,43 @@ static void intc_disable(unsigned int irq) } } +static void (*intc_enable_noprio_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_field, + [MODE_MASK_REG] = intc_mode_zero, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_field, + [MODE_PCLR_REG] = intc_mode_field, +}; + +static void intc_enable_disable(struct intc_desc_int *d, + unsigned long handle, int do_enable) +{ + unsigned long addr; + unsigned int cpu; + void (*fn)(unsigned long, unsigned long, + void (*)(unsigned long, unsigned long, unsigned long), + unsigned int); + + if (do_enable) { + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); + fn = intc_enable_noprio_fns[_INTC_MODE(handle)]; + fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); + } + } else { + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); + fn = intc_disable_fns[_INTC_MODE(handle)]; + fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0); + } + } +} + static int intc_set_wake(unsigned int irq, unsigned int on) { return 0; /* allow wakeup, but setup hardware in intc_suspend() */ @@ -417,19 +454,21 @@ static intc_enum __init intc_grp_id(struct intc_desc *desc, return 0; } -static unsigned int __init intc_mask_data(struct intc_desc *desc, - struct intc_desc_int *d, - intc_enum enum_id, int do_grps) +static unsigned int __init _intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, + unsigned int *reg_idx, + unsigned int *fld_idx) { struct intc_mask_reg *mr = desc->hw.mask_regs; - unsigned int i, j, fn, mode; + unsigned int fn, mode; unsigned long reg_e, reg_d; - for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) { - mr = desc->hw.mask_regs + i; + while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) { + mr = desc->hw.mask_regs + *reg_idx; - for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { - if (mr->enum_ids[j] != enum_id) + for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) { + if (mr->enum_ids[*fld_idx] != enum_id) continue; if (mr->set_reg && mr->clr_reg) { @@ -455,29 +494,49 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), 1, - (mr->reg_width - 1) - j); + (mr->reg_width - 1) - *fld_idx); } + + *fld_idx = 0; + (*reg_idx)++; } + return 0; +} + +static unsigned int __init intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + unsigned int i = 0; + unsigned int j = 0; + unsigned int ret; + + ret = _intc_mask_data(desc, d, enum_id, &i, &j); + if (ret) + return ret; + if (do_grps) return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } -static unsigned int __init intc_prio_data(struct intc_desc *desc, - struct intc_desc_int *d, - intc_enum enum_id, int do_grps) +static unsigned int __init _intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, + unsigned int *reg_idx, + unsigned int *fld_idx) { struct intc_prio_reg *pr = desc->hw.prio_regs; - unsigned int i, j, fn, mode, bit; + unsigned int fn, n, mode, bit; unsigned long reg_e, reg_d; - for (i = 0; pr && enum_id && i < desc->hw.nr_prio_regs; i++) { - pr = desc->hw.prio_regs + i; + while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) { + pr = desc->hw.prio_regs + *reg_idx; - for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { - if (pr->enum_ids[j] != enum_id) + for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) { + if (pr->enum_ids[*fld_idx] != enum_id) continue; if (pr->set_reg && pr->clr_reg) { @@ -495,24 +554,69 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc, } fn += (pr->reg_width >> 3) - 1; + n = *fld_idx + 1; - BUG_ON((j + 1) * pr->field_width > pr->reg_width); + BUG_ON(n * pr->field_width > pr->reg_width); - bit = pr->reg_width - ((j + 1) * pr->field_width); + bit = pr->reg_width - (n * pr->field_width); return _INTC_MK(fn, mode, intc_get_reg(d, reg_e), intc_get_reg(d, reg_d), pr->field_width, bit); } + + *fld_idx = 0; + (*reg_idx)++; } + return 0; +} + +static unsigned int __init intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + unsigned int i = 0; + unsigned int j = 0; + unsigned int ret; + + ret = _intc_prio_data(desc, d, enum_id, &i, &j); + if (ret) + return ret; + if (do_grps) return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0); return 0; } +static void __init intc_enable_disable_enum(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int enable) +{ + unsigned int i, j, data; + + /* go through and enable/disable all mask bits */ + i = j = 0; + do { + data = _intc_mask_data(desc, d, enum_id, &i, &j); + if (data) + intc_enable_disable(d, data, enable); + j++; + } while (data); + + /* go through and enable/disable all priority fields */ + i = j = 0; + do { + data = _intc_prio_data(desc, d, enum_id, &i, &j); + if (data) + intc_enable_disable(d, data, enable); + + j++; + } while (data); +} + static unsigned int __init intc_ack_data(struct intc_desc *desc, struct intc_desc_int *d, intc_enum enum_id) @@ -747,6 +851,11 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.mask_ack = intc_mask_ack; } + + /* disable bits matching force_enable before registering irqs */ + if (desc->force_enable) + intc_enable_disable_enum(desc, d, desc->force_enable, 0); + BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ /* register the vectors one by one */ @@ -792,6 +901,10 @@ void __init register_intc_controller(struct intc_desc *desc) set_irq_data(irq2, (void *)irq); } } + + /* enable bits matching force_enable after registering irqs */ + if (desc->force_enable) + intc_enable_disable_enum(desc, d, desc->force_enable, 1); } static int intc_suspend(struct sys_device *dev, pm_message_t state) diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h index 7b37526bb73f..66b4b0c45e71 100644 --- a/include/linux/sh_intc.h +++ b/include/linux/sh_intc.h @@ -71,6 +71,7 @@ struct intc_hw_desc { struct intc_desc { char *name; + intc_enum force_enable; struct intc_hw_desc hw; }; -- GitLab From 8d9adabac3a3a3742c7a47da9e456108a0fd2efb Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 06:49:48 +0000 Subject: [PATCH 1805/3892] sh: sh7722/Migo-R SDHI vector merge Merge the SDHI vectors in the sh7722 INTC table and update the SDHI platform data for Migo-R. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/sh/boards/mach-migor/setup.c | 2 +- arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index ed2eeeb390a5..d1e51a9baf9c 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -397,7 +397,7 @@ static struct resource sdhi_cn9_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 101, + .start = 100, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index b5335b5e309c..0949135a125c 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -446,6 +446,7 @@ void __init plat_early_device_setup(void) enum { UNUSED=0, + ENABLED, /* interrupt sources */ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, @@ -461,7 +462,6 @@ enum { SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO, FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI, - SDHI0, SDHI1, SDHI2, SDHI3, CMT, TSIF, SIU, TWODG, TMU0, TMU1, TMU2, IRDA, JPU, LCDC, @@ -494,8 +494,8 @@ static struct intc_vect vectors[] __initdata = { INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0), INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20), INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60), - INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0), - INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0), + INTC_VECT(SDHI, 0xe80), INTC_VECT(SDHI, 0xea0), + INTC_VECT(SDHI, 0xec0), INTC_VECT(SDHI, 0xee0), INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20), INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0), INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), @@ -513,7 +513,6 @@ static struct intc_group groups[] __initdata = { INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I), INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI), - INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3), }; static struct intc_mask_reg mask_registers[] __initdata = { @@ -535,7 +534,7 @@ static struct intc_mask_reg mask_registers[] __initdata = { { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI, FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } }, { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */ - { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, TWODG, SIU } }, + { 0, 0, ENABLED, ENABLED, 0, 0, TWODG, SIU } }, { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */ { 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } }, { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */ @@ -573,9 +572,12 @@ static struct intc_mask_reg ack_registers[] __initdata = { { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static DECLARE_INTC_DESC_ACK(intc_desc, "sh7722", vectors, groups, - mask_registers, prio_registers, sense_registers, - ack_registers); +static struct intc_desc intc_desc __initdata = { + .name = "sh7722", + .force_enable = ENABLED, + .hw = INTC_HW_DESC(vectors, groups, mask_registers, + prio_registers, sense_registers, ack_registers), +}; void __init plat_irq_setup(void) { -- GitLab From e3e80046e0ce2a595e607a62b650a9b4efea6558 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 06:49:56 +0000 Subject: [PATCH 1806/3892] sh: sh7723/AP325 SDHI vector merge Merge the SDHI vectors in the sh7723 INTC table and update the SDHI platform data for AP325. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ap325rxa/setup.c | 4 ++-- arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 32 ++++++++++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 27277cbdb636..b5980696abbe 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -420,7 +420,7 @@ static struct resource sdhi0_cn3_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 101, + .start = 100, .flags = IORESOURCE_IRQ, }, }; @@ -443,7 +443,7 @@ static struct resource sdhi1_cn7_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 24, + .start = 23, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index 9e8620e3ad3e..7b90ebcfa20e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -601,6 +601,7 @@ void l2_cache_init(void) enum { UNUSED=0, + ENABLED, /* interrupt sources */ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, @@ -623,7 +624,6 @@ enum { SCIFA_SCIFA1, FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I, I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI, - SDHI0_SDHII0,SDHI0_SDHII1,SDHI0_SDHII2, CMT_CMTI, TSIF_TSIFI, SIU_SIUI, @@ -631,7 +631,6 @@ enum { TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2, IRDA_IRDAI, ATAPI_ATAPII, - SDHI1_SDHII0,SDHI1_SDHII1,SDHI1_SDHII2, VEU2H1_VEU2HI, LCDC_LCDCI, TMU1_TUNI0,TMU1_TUNI1,TMU1_TUNI2, @@ -702,9 +701,9 @@ static struct intc_vect vectors[] __initdata = { INTC_VECT(I2C_WAITI,0xE40), INTC_VECT(I2C_DTEI,0xE60), - INTC_VECT(SDHI0_SDHII0,0xE80), - INTC_VECT(SDHI0_SDHII1,0xEA0), - INTC_VECT(SDHI0_SDHII2,0xEC0), + INTC_VECT(SDHI0, 0xE80), + INTC_VECT(SDHI0, 0xEA0), + INTC_VECT(SDHI0, 0xEC0), INTC_VECT(CMT_CMTI,0xF00), INTC_VECT(TSIF_TSIFI,0xF20), @@ -718,9 +717,9 @@ static struct intc_vect vectors[] __initdata = { INTC_VECT(IRDA_IRDAI,0x480), INTC_VECT(ATAPI_ATAPII,0x4A0), - INTC_VECT(SDHI1_SDHII0,0x4E0), - INTC_VECT(SDHI1_SDHII1,0x500), - INTC_VECT(SDHI1_SDHII2,0x520), + INTC_VECT(SDHI1, 0x4E0), + INTC_VECT(SDHI1, 0x500), + INTC_VECT(SDHI1, 0x520), INTC_VECT(VEU2H1_VEU2HI,0x560), INTC_VECT(LCDC_LCDCI,0x580), @@ -739,15 +738,14 @@ static struct intc_group groups[] __initdata = { INTC_GROUP(FLCTL,FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I), INTC_GROUP(I2C,I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI), INTC_GROUP(_2DG, _2DG_TRI,_2DG_INI,_2DG_CEI), - INTC_GROUP(SDHI1, SDHI1_SDHII0,SDHI1_SDHII1,SDHI1_SDHII2), INTC_GROUP(RTC, RTC_ATI,RTC_PRI,RTC_CUI), INTC_GROUP(DMAC1B, DMAC1B_DEI4,DMAC1B_DEI5,DMAC1B_DADERR), - INTC_GROUP(SDHI0,SDHI0_SDHII0,SDHI0_SDHII1,SDHI0_SDHII2), }; static struct intc_mask_reg mask_registers[] __initdata = { { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */ - { 0, TMU1_TUNI2,TMU1_TUNI1,TMU1_TUNI0,0,SDHI1_SDHII2,SDHI1_SDHII1,SDHI1_SDHII0} }, + { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0, + 0, 0, ENABLED, ENABLED } }, { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */ { VIO_VOUI, VIO_VEU2HI,VIO_BEUI,VIO_CEUI,DMAC0A_DEI3,DMAC0A_DEI2,DMAC0A_DEI1,DMAC0A_DEI0 } }, { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */ @@ -764,7 +762,8 @@ static struct intc_mask_reg mask_registers[] __initdata = { { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI, FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } }, { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */ - { 0,SDHI0_SDHII2,SDHI0_SDHII1,SDHI0_SDHII0,0,0,SCIFA_SCIFA2,SIU_SIUI } }, + { 0, 0, ENABLED, ENABLED, + 0, 0, SCIFA_SCIFA2, SIU_SIUI } }, { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */ { 0, 0, 0, CMT_CMTI, 0, 0, USB_USI0,0 } }, { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */ @@ -804,9 +803,12 @@ static struct intc_mask_reg ack_registers[] __initdata = { { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static DECLARE_INTC_DESC_ACK(intc_desc, "sh7723", vectors, groups, - mask_registers, prio_registers, sense_registers, - ack_registers); +static struct intc_desc intc_desc __initdata = { + .name = "sh7723", + .force_enable = ENABLED, + .hw = INTC_HW_DESC(vectors, groups, mask_registers, + prio_registers, sense_registers, ack_registers), +}; void __init plat_irq_setup(void) { -- GitLab From 3844eadcfd2ba975110e3ca8479efa8c093129ce Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 06:50:04 +0000 Subject: [PATCH 1807/3892] sh: sh7724/Ecovec24/KFR2R09/MS7724SE SDHI vector merge Merge the SDHI vectors in the sh7724 INTC table and update the SDHI platform data for Ecovec24, KFR2R09 and MS7724SE. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ecovec24/setup.c | 4 ++-- arch/sh/boards/mach-kfr2r09/setup.c | 2 +- arch/sh/boards/mach-se/7724/setup.c | 4 ++-- arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 32 +++++++++++++------------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 1135c3b848f2..8e3b05f93a65 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -453,7 +453,7 @@ static struct resource sdhi0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 101, + .start = 100, .flags = IORESOURCE_IRQ, }, }; @@ -489,7 +489,7 @@ static struct resource sdhi1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 24, + .start = 23, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index ca9e82d77d0a..b2cd0ed8664e 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -351,7 +351,7 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 101, + .start = 100, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index c7dbbece44b0..50e4d1599576 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -451,7 +451,7 @@ static struct resource sdhi0_cn7_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 101, + .start = 100, .flags = IORESOURCE_IRQ, }, }; @@ -474,7 +474,7 @@ static struct resource sdhi1_cn8_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 24, + .start = 23, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index aa0f6e9bb89e..c0815a43b6a3 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -723,6 +723,7 @@ void l2_cache_init(void) enum { UNUSED = 0, + ENABLED, /* interrupt sources */ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, @@ -751,14 +752,12 @@ enum { ETHI, I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI, I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI, - SDHI0_SDHII0, SDHI0_SDHII1, SDHI0_SDHII2, SDHI0_SDHII3, CMT, TSIF, FSI, SCIFA5, TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2, IRDA, - SDHI1_SDHII0, SDHI1_SDHII1, SDHI1_SDHII2, JPU, _2DDMAC, MMC_MMC2I, MMC_MMC3I, @@ -840,10 +839,10 @@ static struct intc_vect vectors[] __initdata = { INTC_VECT(I2C0_WAITI, 0xE40), INTC_VECT(I2C0_DTEI, 0xE60), - INTC_VECT(SDHI0_SDHII0, 0xE80), - INTC_VECT(SDHI0_SDHII1, 0xEA0), - INTC_VECT(SDHI0_SDHII2, 0xEC0), - INTC_VECT(SDHI0_SDHII3, 0xEE0), + INTC_VECT(SDHI0, 0xE80), + INTC_VECT(SDHI0, 0xEA0), + INTC_VECT(SDHI0, 0xEC0), + INTC_VECT(SDHI0, 0xEE0), INTC_VECT(CMT, 0xF00), INTC_VECT(TSIF, 0xF20), @@ -856,9 +855,9 @@ static struct intc_vect vectors[] __initdata = { INTC_VECT(IRDA, 0x480), - INTC_VECT(SDHI1_SDHII0, 0x4E0), - INTC_VECT(SDHI1_SDHII1, 0x500), - INTC_VECT(SDHI1_SDHII2, 0x520), + INTC_VECT(SDHI1, 0x4E0), + INTC_VECT(SDHI1, 0x500), + INTC_VECT(SDHI1, 0x520), INTC_VECT(JPU, 0x560), INTC_VECT(_2DDMAC, 0x4A0), @@ -884,8 +883,6 @@ static struct intc_group groups[] __initdata = { INTC_GROUP(DMAC0B, DMAC0B_DEI4, DMAC0B_DEI5, DMAC0B_DADERR), INTC_GROUP(I2C0, I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI), INTC_GROUP(I2C1, I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI), - INTC_GROUP(SDHI0, SDHI0_SDHII0, SDHI0_SDHII1, SDHI0_SDHII2, SDHI0_SDHII3), - INTC_GROUP(SDHI1, SDHI1_SDHII0, SDHI1_SDHII1, SDHI1_SDHII2), INTC_GROUP(SPU, SPU_SPUI0, SPU_SPUI1), INTC_GROUP(MMCIF, MMC_MMC2I, MMC_MMC3I), }; @@ -893,7 +890,7 @@ static struct intc_group groups[] __initdata = { static struct intc_mask_reg mask_registers[] __initdata = { { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */ { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0, - 0, SDHI1_SDHII2, SDHI1_SDHII1, SDHI1_SDHII0 } }, + 0, 0, ENABLED, ENABLED } }, { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */ { VIO_VOU, VIO_VEU1, VIO_BEU0, VIO_CEU0, DMAC0A_DEI3, DMAC0A_DEI2, DMAC0A_DEI1, DMAC0A_DEI0 } }, @@ -915,7 +912,7 @@ static struct intc_mask_reg mask_registers[] __initdata = { { I2C0_DTEI, I2C0_WAITI, I2C0_TACKI, I2C0_ALI, I2C1_DTEI, I2C1_WAITI, I2C1_TACKI, I2C1_ALI } }, { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */ - { SDHI0_SDHII3, SDHI0_SDHII2, SDHI0_SDHII1, SDHI0_SDHII0, + { 0, 0, ENABLED, ENABLED, 0, 0, SCIFA5, FSI } }, { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */ { 0, 0, 0, CMT, 0, USB1, USB0, 0 } }, @@ -962,9 +959,12 @@ static struct intc_mask_reg ack_registers[] __initdata = { { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, }; -static DECLARE_INTC_DESC_ACK(intc_desc, "sh7724", vectors, groups, - mask_registers, prio_registers, sense_registers, - ack_registers); +static struct intc_desc intc_desc __initdata = { + .name = "sh7724", + .force_enable = ENABLED, + .hw = INTC_HW_DESC(vectors, groups, mask_registers, + prio_registers, sense_registers, ack_registers), +}; void __init plat_irq_setup(void) { -- GitLab From e6f077592d1de2f6a4fc760e7b5d6f20b37d3a27 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 07:17:20 +0000 Subject: [PATCH 1808/3892] sh: fix INTC to use set_irq_chained_handler() for redirects This patch updates the shared INTC code to use set_irq_chained_handler() for intc_redirect_irq(). With this in place request_irq() on a merged irq which has been redirected will now return -EINVAL instead of 0 together with a crash. This thanks to the protection of the IRQ_NOREQUEST flag set for chained interrupt handlers. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 3a687396dfa2..66594eb4477d 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -896,8 +896,8 @@ void __init register_intc_controller(struct intc_desc *desc) vect2->enum_id = 0; /* redirect this interrupts to the first one */ - set_irq_chip_and_handler_name(irq2, &d->chip, - intc_redirect_irq, "redirect"); + set_irq_chained_handler(irq2, intc_redirect_irq); + set_irq_chip(irq2, &d->chip); set_irq_data(irq2, (void *)irq); } } -- GitLab From 801cd56e3e2c2b727399d2c50c50139b2d7c98e8 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Feb 2010 08:22:30 +0000 Subject: [PATCH 1809/3892] sh: break out enable/reparent div4 clocks on sh7723 Break out sh7723 div4 clocks for SIU and IRDA as reparent / enable clocks. Similar to the SIU clock patch for sh7722 by Guennadi. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh4a/clock-sh7723.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c index 20a31c2255a8..76731b61998e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c @@ -117,8 +117,7 @@ static struct clk_div_mult_table div4_table = { .nr_multipliers = ARRAY_SIZE(multipliers), }; -enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, - DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR }; +enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR }; #define DIV4(_str, _reg, _bit, _mask, _flags) \ SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags) @@ -130,11 +129,20 @@ struct clk div4_clks[DIV4_NR] = { [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x0dbf, CLK_ENABLE_ON_INIT), [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x0db4, CLK_ENABLE_ON_INIT), [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x0dbf, 0), - [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x0dbf, 0), - [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x0dbf, 0), +}; + +enum { DIV4_IRDA, DIV4_ENABLE_NR }; + +struct clk div4_enable_clks[DIV4_ENABLE_NR] = { [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x0dbf, 0), }; +enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR }; + +struct clk div4_reparent_clks[DIV4_REPARENT_NR] = { + [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x0dbf, 0), + [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x0dbf, 0), +}; struct clk div6_clks[] = { SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), }; @@ -215,6 +223,14 @@ int __init arch_clk_init(void) if (!ret) ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + if (!ret) + ret = sh_clk_div4_enable_register(div4_enable_clks, + DIV4_ENABLE_NR, &div4_table); + + if (!ret) + ret = sh_clk_div4_reparent_register(div4_reparent_clks, + DIV4_REPARENT_NR, &div4_table); + if (!ret) ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); -- GitLab From cebe41d4b8f8092359de31e241815fcb4b4dc0be Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 6 Feb 2010 00:21:03 +0200 Subject: [PATCH 1810/3892] sound: use DEFINE_PCI_DEVICE_TABLE Use DEFINE_PCI_DEVICE_TABLE() to make PCI device ids go to .devinit.rodata section, so they can be discarded in some cases, and make them const. Signed-off-by: Alexey Dobriyan Signed-off-by: Takashi Iwai --- sound/oss/kahlua.c | 2 +- sound/pci/ad1889.c | 2 +- sound/pci/ali5451/ali5451.c | 2 +- sound/pci/als300.c | 2 +- sound/pci/als4000.c | 2 +- sound/pci/atiixp.c | 2 +- sound/pci/atiixp_modem.c | 2 +- sound/pci/au88x0/au8810.c | 2 +- sound/pci/au88x0/au8820.c | 2 +- sound/pci/au88x0/au8830.c | 2 +- sound/pci/aw2/aw2-alsa.c | 2 +- sound/pci/azt3328.c | 2 +- sound/pci/bt87x.c | 4 ++-- sound/pci/ca0106/ca0106_main.c | 2 +- sound/pci/cmipci.c | 4 ++-- sound/pci/cs4281.c | 2 +- sound/pci/cs46xx/cs46xx.c | 2 +- sound/pci/cs5530.c | 2 +- sound/pci/cs5535audio/cs5535audio.c | 2 +- sound/pci/ctxfi/xfi.c | 2 +- sound/pci/echoaudio/darla20.c | 2 +- sound/pci/echoaudio/darla24.c | 2 +- sound/pci/echoaudio/echo3g.c | 2 +- sound/pci/echoaudio/gina20.c | 2 +- sound/pci/echoaudio/gina24.c | 2 +- sound/pci/echoaudio/indigo.c | 2 +- sound/pci/echoaudio/indigodj.c | 2 +- sound/pci/echoaudio/indigodjx.c | 2 +- sound/pci/echoaudio/indigoio.c | 2 +- sound/pci/echoaudio/indigoiox.c | 2 +- sound/pci/echoaudio/layla20.c | 2 +- sound/pci/echoaudio/layla24.c | 2 +- sound/pci/echoaudio/mia.c | 2 +- sound/pci/echoaudio/mona.c | 2 +- sound/pci/emu10k1/emu10k1.c | 2 +- sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/ens1370.c | 2 +- sound/pci/es1938.c | 2 +- sound/pci/es1968.c | 2 +- sound/pci/fm801.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/ice1712/ice1712.c | 2 +- sound/pci/ice1712/ice1724.c | 2 +- sound/pci/intel8x0.c | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/korg1212/korg1212.c | 2 +- sound/pci/lx6464es/lx6464es.c | 2 +- sound/pci/maestro3.c | 2 +- sound/pci/mixart/mixart.c | 2 +- sound/pci/nm256/nm256.c | 2 +- sound/pci/oxygen/hifier.c | 2 +- sound/pci/oxygen/oxygen.c | 2 +- sound/pci/oxygen/virtuoso.c | 2 +- sound/pci/pcxhr/pcxhr.c | 2 +- sound/pci/riptide/riptide.c | 4 ++-- sound/pci/rme32.c | 2 +- sound/pci/rme96.c | 2 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- sound/pci/rme9652/rme9652.c | 2 +- sound/pci/sis7019.c | 2 +- sound/pci/sonicvibes.c | 2 +- sound/pci/trident/trident.c | 2 +- sound/pci/via82xx.c | 2 +- sound/pci/via82xx_modem.c | 2 +- sound/pci/vx222/vx222.c | 2 +- sound/pci/ymfpci/ymfpci.c | 2 +- 67 files changed, 70 insertions(+), 70 deletions(-) diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 89466b056be7..24d152ccf80d 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c @@ -198,7 +198,7 @@ MODULE_LICENSE("GPL"); * 5530 only. The 5510/5520 decode is different. */ -static struct pci_device_id id_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(id_tbl) = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, { } }; diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 8f5098f92c37..4382d0fa6b9a 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_device_id snd_ad1889_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, { 0, }, }; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index aaf4da68969c..5c6e322a48f0 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -275,7 +275,7 @@ struct snd_ali { #endif }; -static struct pci_device_id snd_ali_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, {0, } }; diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 3aa35af7ca91..d7653cb7ac60 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -145,7 +145,7 @@ struct snd_als300_substream_data { int block_counter_register; }; -static struct pci_device_id snd_als300_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = { { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, { 0, } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 3dbacde1a5af..d75cf7b06426 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -117,7 +117,7 @@ struct snd_card_als4000 { #endif }; -static struct pci_device_id snd_als4000_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = { { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ { 0, } }; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index d6752dff2a44..81e2bfc11257 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -286,7 +286,7 @@ struct atiixp { /* */ -static struct pci_device_id snd_atiixp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index e7e147bf8eb2..91d7036b6411 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -261,7 +261,7 @@ struct atiixp_modem { /* */ -static struct pci_device_id snd_atiixp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ { 0, } diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c index c0e8c6b295cb..aa51cc7771dd 100644 --- a/sound/pci/au88x0/au8810.c +++ b/sound/pci/au88x0/au8810.c @@ -1,6 +1,6 @@ #include "au8810.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, {0,} }; diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c index a6527330df58..2f321e7306cd 100644 --- a/sound/pci/au88x0/au8820.c +++ b/sound/pci/au88x0/au8820.c @@ -1,6 +1,6 @@ #include "au8820.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, {0,} }; diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c index 6c702ad4352a..279b78f06d22 100644 --- a/sound/pci/au88x0/au8830.c +++ b/sound/pci/au88x0/au8830.c @@ -1,6 +1,6 @@ #include "au8830.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, {0,} }; diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 4d34bb0d99d3..67921f93a41e 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); -static struct pci_device_id snd_aw2_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, 0, 0, 0}, {0} diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 69867ace7860..4679ed83a43b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -350,7 +350,7 @@ struct snd_azf3328 { #endif }; -static const struct pci_device_id snd_azf3328_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = { { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ { 0, } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 4e2b925a94cc..37e1b5df5ab8 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -795,7 +795,7 @@ fail: .driver_data = SND_BT87X_BOARD_ ## id } /* driver_data is the card id for that device */ -static struct pci_device_id snd_bt87x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { /* Hauppauge WinTV series */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), /* Hauppauge WinTV series */ @@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci) /* default entries for all Bt87x cards - it's not exported */ /* driver_data is set to 0 to call detection */ -static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), { } diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 15e4138bce17..0a3d3d6e77b4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) #endif // PCI IDs -static struct pci_device_id snd_ca0106_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ { 0, } }; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index a312bae08f52..1ded64e05643 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} #endif -static struct pci_device_id snd_cmipci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, @@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc int integrated_midi = 0; char modelstr[16]; int pcm_index, pcm_spdif_index; - static struct pci_device_id intel_82437vx[] = { + static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, { }, }; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index e2e0359bb056..9edc65059e3e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -494,7 +494,7 @@ struct cs4281 { static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_cs4281_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = { { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ { 0, } }; diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 033aec430117..767fa7f06cd0 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); module_param_array(mmap_valid, bool, NULL, 0444); MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); -static struct pci_device_id snd_cs46xx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index dc464321d0f3..207479a641cf 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -58,7 +58,7 @@ struct snd_cs5530 { unsigned long pci_base; }; -static struct pci_device_id snd_cs5530_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = { {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0}, {0,} diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 91e7faf69bbb..afb803708416 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); -static struct pci_device_id snd_cs5535audio_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, {} diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index ed44ed788b60..f42e7e1a1074 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); module_param_array(subsystem, int, NULL, 0444); MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); -static struct pci_device_id ct_pci_dev_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { /* only X-Fi is supported, so... */ { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), .driver_data = ATC20K1, diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 8c6db3aa3c1a..a65bafe0800f 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -63,7 +63,7 @@ static const struct firmware card_fw[] = { {0, "darla20_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 04cbf3eaf05a..0a6c50bcd758 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "darla24_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 4022e43a0053..f5142796989b 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -81,7 +81,7 @@ static const struct firmware card_fw[] = { {0, "3g_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ {0,} }; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index c0e64b8f52a4..2364f8a1bc21 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "gina20_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index c36a78dd0b5e..616b55825a19 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -85,7 +85,7 @@ static const struct firmware card_fw[] = { {0, "gina24_361_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 0a58a7c1fd7c..776175c0bdad 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ {0,} }; diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 2db24d29332b..8816b0bd2ba6 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dj_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ {0,} }; diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index 2e44316530a2..b1e3652f2f48 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_djx_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a60c0a0a89b7..1035125336d6 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_io_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index eb3819f9654a..60b7cb2753cf 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_iox_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ {0,} }; diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 506194688995..8c3f5c5b5301 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -76,7 +76,7 @@ static const struct firmware card_fw[] = { {0, "layla20_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index e09e3ea7781e..ed1cc0abc2b8 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -87,7 +87,7 @@ static const struct firmware card_fw[] = { {0, "layla24_2S_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index f05c8c097aa8..cc2bbfc65327 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -77,7 +77,7 @@ static const struct firmware card_fw[] = { {0, "mia_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ {0,} diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index b05bad944901..3e7e01824b40 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -92,7 +92,7 @@ static const struct firmware card_fw[] = { {0, "mona_2_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 168af67d938e..4203782d7cb7 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -76,7 +76,7 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ -static struct pci_device_id snd_emu10k1_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1d369ff73805..df47f738098d 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1605,7 +1605,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) } // PCI IDs -static struct pci_device_id snd_emu10k1x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ { 0, } }; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 2b82c5c723e1..c7fba5379813 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -443,7 +443,7 @@ struct ensoniq { static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_audiopci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = { #ifdef CHIP1370 { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ #endif diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb83e1ffa5cb..553b75217259 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -243,7 +243,7 @@ struct es1938 { static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_es1938_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ { 0, } }; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a11f453a6b6d..ecaea9fb48ec 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -551,7 +551,7 @@ struct es1968 { static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_es1968_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = { /* Maestro 1 */ { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, /* Maestro 2 */ diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 83508b3964fb..e1baad74ea4b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -205,7 +205,7 @@ struct fm801 { #endif }; -static struct pci_device_id snd_fm801_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1f516e668d88..ac05bef7c2ec 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2664,7 +2664,7 @@ static void __devexit azx_remove(struct pci_dev *pci) } /* PCI IDs */ -static struct pci_device_id azx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* ICH 6..10 */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index fb61943fc4dc..4fc6d8bc637e 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -106,7 +106,7 @@ module_param_array(dxr_enable, int, NULL, 0444); MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); -static const struct pci_device_id snd_ice1712_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ { 0, } }; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ae29073eea93..c1498fa5545f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); /* Both VT1720 and VT1724 have the same PCI IDs */ -static const struct pci_device_id snd_vt1724_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, { 0, } }; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b990143636f1..6433e65c9507 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -420,7 +420,7 @@ struct intel8x0 { u32 int_sta_mask; /* interrupt status mask */ }; -static struct pci_device_id snd_intel8x0_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = { { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e7d12e7673f..13cec1e5ced9 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -219,7 +219,7 @@ struct intel8x0m { unsigned int pcm_pos_shift; }; -static struct pci_device_id snd_intel8x0m_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 7cc38a11e997..6d795700be79 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); MODULE_AUTHOR("Haroldo Gamal "); -static struct pci_device_id snd_korg1212_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = { { .vendor = 0x10b5, .device = 0x906d, diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 11b8c6514b3d..0cca56038cd9 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -55,7 +55,7 @@ static const char card_name[] = "LX6464ES"; #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 -static struct pci_device_id snd_lx6464es_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), .subvendor = PCI_VENDOR_ID_DIGIGRAM, .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 75283fbb4b3f..b64e78139d63 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -861,7 +861,7 @@ struct snd_m3 { /* * pci ids */ -static struct pci_device_id snd_m3_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a83d1968a845..7e8e7da592a9 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); /* */ -static struct pci_device_id snd_mixart_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = { { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ { 0, } }; diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 97a0731331a1..5a60492ac7b3 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -262,7 +262,7 @@ struct nm256 { /* * PCI ids */ -static struct pci_device_id snd_nm256_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = { {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index e3c229b63311..5a87d683691f 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static struct pci_device_id hifier_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index acbedebcffd9..289cb4dacfc7 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -72,7 +72,7 @@ enum { MODEL_CLARO_HALO, /* HT-Omega Claro halo */ }; -static struct pci_device_id oxygen_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 563b6f50821f..f03a2f2cffee 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static struct pci_device_id xonar_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 833e9c7b27c7..95cfde27d25c 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -94,7 +94,7 @@ enum { PCI_ID_LAST }; -static struct pci_device_id pcxhr_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = { { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index b5ca02e2038c..bb08a2855fce 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -506,7 +506,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); /* */ -static struct pci_device_id snd_riptide_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { { PCI_DEVICE(0x127a, 0x4310) }, { PCI_DEVICE(0x127a, 0x4320) }, { PCI_DEVICE(0x127a, 0x4330) }, @@ -515,7 +515,7 @@ static struct pci_device_id snd_riptide_ids[] = { }; #ifdef SUPPORT_JOYSTICK -static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = { { PCI_DEVICE(0x127a, 0x4312) }, { PCI_DEVICE(0x127a, 0x4322) }, { PCI_DEVICE(0x127a, 0x4332) }, diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f977dba7cbd0..d5e1c6eb7b7b 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -226,7 +226,7 @@ struct rme32 { struct snd_kcontrol *spdif_ctl; }; -static struct pci_device_id snd_rme32_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = { {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2ba5c0fd55db..9d5252bc870c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -231,7 +231,7 @@ struct rme96 { struct snd_kcontrol *spdif_ctl; }; -static struct pci_device_id snd_rme96_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = { { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7bb827c7d806..52c6eb57cc3f 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -585,7 +585,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static struct pci_device_id snd_hdsp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a1b10d1a384d..3d72c1effeef 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -512,7 +512,7 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { }; -static struct pci_device_id snd_hdspm_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index bc539abb2105..44a3e2d8c556 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -314,7 +314,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static struct pci_device_id snd_rme9652_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = { { .vendor = 0x10ee, .device = 0x3fc4, diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 1a5ff0611072..7e3e8fbc90fe 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); -static struct pci_device_id snd_sis7019_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, { 0, } }; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 1f6406c4534d..337b9facadfd 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -242,7 +242,7 @@ struct sonicvibes { #endif }; -static struct pci_device_id snd_sonic_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = { { PCI_VDEVICE(S3, 0xca00), 0, }, { 0, } }; diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 21cef97d478d..6d0581841d7a 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); module_param_array(wavetable_size, int, NULL, 0444); MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); -static struct pci_device_id snd_trident_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 8a332d2f615c..9595b5b535f3 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -401,7 +401,7 @@ struct via82xx { #endif }; -static struct pci_device_id snd_via82xx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = { /* 0x1106, 0x3058 */ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ /* 0x1106, 0x3059 */ diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 47eb61561dfc..f7e8bbbe3953 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -260,7 +260,7 @@ struct via82xx_modem { struct snd_info_entry *proc_entry; }; -static struct pci_device_id snd_via82xx_modem_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = { { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, { 0, } }; diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fc9136c3e0d7..99a9a814be0b 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -60,7 +60,7 @@ enum { VX_PCI_VX222_NEW }; -static struct pci_device_id snd_vx222_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = { { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ { 0, } diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e6b18b90d451..80c682113381 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); module_param_array(rear_switch, bool, NULL, 0444); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); -static struct pci_device_id snd_ymfpci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ -- GitLab From 0690535d6bcec5eb28573824df5c8a49ec85b696 Mon Sep 17 00:00:00 2001 From: Leo P White Date: Mon, 8 Feb 2010 13:02:05 +0000 Subject: [PATCH 1811/3892] HID: add mapping for "AL Network Chat" usage Adding a mapping for the 'AL Network Chat' usage from the 'Consumer' usage page (USB HID Usage Tables v1.11). This usage is used by some keyboards for a multimedia key. Signed-off-by: Leo P White Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8430d626511c..a01a1b0de1c3 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -405,6 +405,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x192: map_key_clear(KEY_CALC); break; case 0x194: map_key_clear(KEY_FILE); break; case 0x196: map_key_clear(KEY_WWW); break; + case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; case 0x1a6: map_key_clear(KEY_HELP); break; -- GitLab From eabe5c90580a065aed8ce6a5ba53eb443d317fae Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 9 Feb 2010 11:43:19 +0100 Subject: [PATCH 1812/3892] HID: fix typo in error message Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4e8450228a24..96d723ea5131 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -81,7 +81,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) sc = kzalloc(sizeof(*sc), GFP_KERNEL); if (sc == NULL) { - dev_err(&hdev->dev, "can't alloc apple descriptor\n"); + dev_err(&hdev->dev, "can't alloc sony descriptor\n"); return -ENOMEM; } -- GitLab From 301ba0457f1ed853fc08e57785f8c87fe7e49c68 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 9 Feb 2010 15:07:40 +1100 Subject: [PATCH 1813/3892] kthread, sched: Remove reference to kthread_create_on_cpu kthread_create_on_cpu doesn't exist so update a comment in kthread.c to reflect this. Signed-off-by: Anton Blanchard Acked-by: Rusty Russell Cc: Peter Zijlstra LKML-Reference: <20100209040740.GB3702@kryten> Signed-off-by: Ingo Molnar --- kernel/kthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kthread.c b/kernel/kthread.c index fbb6222fe7e0..82ed0ea15194 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -101,7 +101,7 @@ static void create_kthread(struct kthread_create_info *create) * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start - * it. See also kthread_run(), kthread_create_on_cpu(). + * it. See also kthread_run(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a -- GitLab From 580537140568caddbc8a727d4c2f238d38707f68 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 28 Jan 2010 22:18:56 -0700 Subject: [PATCH 1814/3892] microblaze: remove early_init_dt_scan_cpus() and phyp_dump_*() Microblaze only has one CPU, it isn't SMP at all. early_init_dt_scan_cpus() is effectively just a no-op, so remove it. Microblaze doesn't support hypervisor assisted dump either, so the phyp stuff can also go. Signed-off-by: Grant Likely Acked-by: Michal Simek --- arch/microblaze/kernel/prom.c | 153 ---------------------------------- 1 file changed, 153 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 6eff83a71218..cd158ef5b583 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -47,67 +47,6 @@ struct device_node *of_chosen; #define early_init_dt_scan_drconf_memory(node) 0 -static int __init early_init_dt_scan_cpus(unsigned long node, - const char *uname, int depth, - void *data) -{ - static int logical_cpuid; - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - const u32 *intserv; - int i, nthreads; - int found = 0; - - /* We are scanning "cpu" nodes only */ - if (type == NULL || strcmp(type, "cpu") != 0) - return 0; - - /* Get physical cpuid */ - intserv = of_get_flat_dt_prop(node, "reg", NULL); - nthreads = 1; - - /* - * Now see if any of these threads match our boot cpu. - * NOTE: This must match the parsing done in smp_setup_cpu_maps. - */ - for (i = 0; i < nthreads; i++) { - /* - * version 2 of the kexec param format adds the phys cpuid of - * booted proc. - */ - if (initial_boot_params && initial_boot_params->version >= 2) { - if (intserv[i] == - initial_boot_params->boot_cpuid_phys) { - found = 1; - break; - } - } else { - /* - * Check if it's the boot-cpu, set it's hw index now, - * unfortunately this format did not support booting - * off secondary threads. - */ - if (of_get_flat_dt_prop(node, - "linux,boot-cpu", NULL) != NULL) { - found = 1; - break; - } - } - -#ifdef CONFIG_SMP - /* logical cpu id is always 0 on UP kernels */ - logical_cpuid++; -#endif - } - - if (found) { - pr_debug("boot cpu: logical %d physical %d\n", logical_cpuid, - intserv[i]); - boot_cpuid = logical_cpuid; - } - - return 0; -} - void __init early_init_dt_scan_chosen_arch(unsigned long node) { /* No Microblaze specific code here */ @@ -163,86 +102,6 @@ static int __init early_init_dt_scan_memory(unsigned long node, return 0; } -#ifdef CONFIG_PHYP_DUMP -/** - * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg - * - * Function to find the largest size we need to reserve - * during early boot process. - * - * It either looks for boot param and returns that OR - * returns larger of 256 or 5% rounded down to multiples of 256MB. - * - */ -static inline unsigned long phyp_dump_calculate_reserve_size(void) -{ - unsigned long tmp; - - if (phyp_dump_info->reserve_bootvar) - return phyp_dump_info->reserve_bootvar; - - /* divide by 20 to get 5% of value */ - tmp = lmb_end_of_DRAM(); - do_div(tmp, 20); - - /* round it down in multiples of 256 */ - tmp = tmp & ~0x0FFFFFFFUL; - - return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); -} - -/** - * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory - * - * This routine may reserve memory regions in the kernel only - * if the system is supported and a dump was taken in last - * boot instance or if the hardware is supported and the - * scratch area needs to be setup. In other instances it returns - * without reserving anything. The memory in case of dump being - * active is freed when the dump is collected (by userland tools). - */ -static void __init phyp_dump_reserve_mem(void) -{ - unsigned long base, size; - unsigned long variable_reserve_size; - - if (!phyp_dump_info->phyp_dump_configured) { - printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); - return; - } - - if (!phyp_dump_info->phyp_dump_at_boot) { - printk(KERN_INFO "Phyp-dump disabled at boot time\n"); - return; - } - - variable_reserve_size = phyp_dump_calculate_reserve_size(); - - if (phyp_dump_info->phyp_dump_is_active) { - /* Reserve *everything* above RMR.Area freed by userland tools*/ - base = variable_reserve_size; - size = lmb_end_of_DRAM() - base; - - /* XXX crashed_ram_end is wrong, since it may be beyond - * the memory_limit, it will need to be adjusted. */ - lmb_reserve(base, size); - - phyp_dump_info->init_reserve_start = base; - phyp_dump_info->init_reserve_size = size; - } else { - size = phyp_dump_info->cpu_state_size + - phyp_dump_info->hpte_region_size + - variable_reserve_size; - base = lmb_end_of_DRAM() - size; - lmb_reserve(base, size); - phyp_dump_info->init_reserve_start = base; - phyp_dump_info->init_reserve_size = size; - } -} -#else -static inline void __init phyp_dump_reserve_mem(void) {} -#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ - #ifdef CONFIG_EARLY_PRINTK /* MS this is Microblaze specifig function */ static int __init early_init_dt_scan_serial(unsigned long node, @@ -284,11 +143,6 @@ void __init early_init_devtree(void *params) /* Setup flat device-tree pointer */ initial_boot_params = params; -#ifdef CONFIG_PHYP_DUMP - /* scan tree to see if dump occured during last boot */ - of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); -#endif - /* Retrieve various informations from the /chosen node of the * device-tree, including the platform type, initrd location and * size, TCE reserve, and more ... @@ -308,13 +162,6 @@ void __init early_init_devtree(void *params) pr_debug("Phys. mem: %lx\n", (unsigned long) lmb_phys_mem_size()); - pr_debug("Scanning CPUs ...\n"); - - /* Retreive CPU related informations from the flat tree - * (altivec support, boot CPU ID, ...) - */ - of_scan_flat_dt(early_init_dt_scan_cpus, NULL); - pr_debug(" <- early_init_devtree()\n"); } -- GitLab From fcdeb7fedf89f4bbc2e11959794968080cd8426e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 29 Jan 2010 05:04:33 -0700 Subject: [PATCH 1815/3892] of: merge of_attach_node() & of_detach_node() Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely Tested-by: Wolfram Sang Acked-by: Benjamin Herrenschmidt --- arch/microblaze/include/asm/prom.h | 4 -- arch/microblaze/kernel/prom.c | 59 ------------------------- arch/powerpc/include/asm/prom.h | 4 -- arch/powerpc/kernel/prom.c | 59 ------------------------- drivers/of/Kconfig | 4 ++ drivers/of/base.c | 71 ++++++++++++++++++++++++++++++ include/linux/of.h | 6 +++ 7 files changed, 81 insertions(+), 126 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 07d1063f9aae..6c6b386cf3c6 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -39,10 +39,6 @@ extern struct device_node *of_chosen; extern rwlock_t devtree_lock; /* temporary while merging */ -/* For updating the device tree at runtime */ -extern void of_attach_node(struct device_node *); -extern void of_detach_node(struct device_node *); - /* Other Prototypes */ extern int early_uartlite_console(void); diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index cd158ef5b583..8171282a0b0d 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -197,65 +197,6 @@ struct device_node *of_find_node_by_phandle(phandle handle) } EXPORT_SYMBOL(of_find_node_by_phandle); -/* - * Plug a device node into the tree and global list. - */ -void of_attach_node(struct device_node *np) -{ - unsigned long flags; - - write_lock_irqsave(&devtree_lock, flags); - np->sibling = np->parent->child; - np->allnext = allnodes; - np->parent->child = np; - allnodes = np; - write_unlock_irqrestore(&devtree_lock, flags); -} - -/* - * "Unplug" a node from the device tree. The caller must hold - * a reference to the node. The memory associated with the node - * is not freed until its refcount goes to zero. - */ -void of_detach_node(struct device_node *np) -{ - struct device_node *parent; - unsigned long flags; - - write_lock_irqsave(&devtree_lock, flags); - - parent = np->parent; - if (!parent) - goto out_unlock; - - if (allnodes == np) - allnodes = np->allnext; - else { - struct device_node *prev; - for (prev = allnodes; - prev->allnext != np; - prev = prev->allnext) - ; - prev->allnext = np->allnext; - } - - if (parent->child == np) - parent->child = np->sibling; - else { - struct device_node *prevsib; - for (prevsib = np->parent->child; - prevsib->sibling != np; - prevsib = prevsib->sibling) - ; - prevsib->sibling = np->sibling; - } - - of_node_set_flag(np, OF_DETACHED); - -out_unlock: - write_unlock_irqrestore(&devtree_lock, flags); -} - #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) static struct debugfs_blob_wrapper flat_dt_blob; diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 2ab9cbd98826..f384db815ea8 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -34,10 +34,6 @@ extern struct device_node *of_chosen; #define HAVE_ARCH_DEVTREE_FIXUPS -/* For updating the device tree at runtime */ -extern void of_attach_node(struct device_node *); -extern void of_detach_node(struct device_node *); - #ifdef CONFIG_PPC32 /* * PCI <-> OF matching functions diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1ed2ec2ea05b..f954c718d7eb 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -817,65 +817,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np) return NULL; } -/* - * Plug a device node into the tree and global list. - */ -void of_attach_node(struct device_node *np) -{ - unsigned long flags; - - write_lock_irqsave(&devtree_lock, flags); - np->sibling = np->parent->child; - np->allnext = allnodes; - np->parent->child = np; - allnodes = np; - write_unlock_irqrestore(&devtree_lock, flags); -} - -/* - * "Unplug" a node from the device tree. The caller must hold - * a reference to the node. The memory associated with the node - * is not freed until its refcount goes to zero. - */ -void of_detach_node(struct device_node *np) -{ - struct device_node *parent; - unsigned long flags; - - write_lock_irqsave(&devtree_lock, flags); - - parent = np->parent; - if (!parent) - goto out_unlock; - - if (allnodes == np) - allnodes = np->allnext; - else { - struct device_node *prev; - for (prev = allnodes; - prev->allnext != np; - prev = prev->allnext) - ; - prev->allnext = np->allnext; - } - - if (parent->child == np) - parent->child = np->sibling; - else { - struct device_node *prevsib; - for (prevsib = np->parent->child; - prevsib->sibling != np; - prevsib = prevsib->sibling) - ; - prevsib->sibling = np->sibling; - } - - of_node_set_flag(np, OF_DETACHED); - -out_unlock: - write_unlock_irqrestore(&devtree_lock, flags); -} - #ifdef CONFIG_PPC_PSERIES /* * Fix up the uninitialized fields in a new device node: diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 462825e03123..7cecc8fea9bd 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -2,6 +2,10 @@ config OF_FLATTREE bool depends on OF +config OF_DYNAMIC + def_bool y + depends on OF && PPC_OF + config OF_DEVICE def_bool y depends on OF && (SPARC || PPC_OF || MICROBLAZE) diff --git a/drivers/of/base.c b/drivers/of/base.c index cf89ee6253f3..2ce58be314af 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -870,3 +870,74 @@ int prom_update_property(struct device_node *np, return 0; } + +#if defined(CONFIG_OF_DYNAMIC) +/* + * Support for dynamic device trees. + * + * On some platforms, the device tree can be manipulated at runtime. + * The routines in this section support adding, removing and changing + * device tree nodes. + */ + +/** + * of_attach_node - Plug a device node into the tree and global list. + */ +void of_attach_node(struct device_node *np) +{ + unsigned long flags; + + write_lock_irqsave(&devtree_lock, flags); + np->sibling = np->parent->child; + np->allnext = allnodes; + np->parent->child = np; + allnodes = np; + write_unlock_irqrestore(&devtree_lock, flags); +} + +/** + * of_detach_node - "Unplug" a node from the device tree. + * + * The caller must hold a reference to the node. The memory associated with + * the node is not freed until its refcount goes to zero. + */ +void of_detach_node(struct device_node *np) +{ + struct device_node *parent; + unsigned long flags; + + write_lock_irqsave(&devtree_lock, flags); + + parent = np->parent; + if (!parent) + goto out_unlock; + + if (allnodes == np) + allnodes = np->allnext; + else { + struct device_node *prev; + for (prev = allnodes; + prev->allnext != np; + prev = prev->allnext) + ; + prev->allnext = np->allnext; + } + + if (parent->child == np) + parent->child = np->sibling; + else { + struct device_node *prevsib; + for (prevsib = np->parent->child; + prevsib->sibling != np; + prevsib = prevsib->sibling) + ; + prevsib->sibling = np->sibling; + } + + of_node_set_flag(np, OF_DETACHED); + +out_unlock: + write_unlock_irqrestore(&devtree_lock, flags); +} +#endif /* defined(CONFIG_OF_DYNAMIC) */ + diff --git a/include/linux/of.h b/include/linux/of.h index dbabf86e0b7a..3cc0d7ae290e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -184,4 +184,10 @@ extern int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const char *cells_name, int index, struct device_node **out_node, const void **out_args); +#if defined(CONFIG_OF_DYNAMIC) +/* For updating the device tree at runtime */ +extern void of_attach_node(struct device_node *); +extern void of_detach_node(struct device_node *); +#endif + #endif /* _LINUX_OF_H */ -- GitLab From 89751a7cb70a20f0d604dd7c4be29dd7b0011718 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:11 -0700 Subject: [PATCH 1816/3892] of: merge of_find_node_by_phandle Merge common function between powerpc, sparc and microblaze. Code is identical for powerpc and microblaze, but adds a lock (and release) of the devtree_lock on sparc. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- arch/microblaze/kernel/prom.c | 21 --------------------- arch/powerpc/kernel/prom.c | 21 --------------------- arch/sparc/kernel/prom_common.c | 12 ------------ drivers/of/base.c | 21 +++++++++++++++++++++ 4 files changed, 21 insertions(+), 54 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 8171282a0b0d..f7bd0ee8d481 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -176,27 +176,6 @@ void __init early_init_devtree(void *params) * *******/ -/** - * of_find_node_by_phandle - Find a node given a phandle - * @handle: phandle of the node to find - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_phandle(phandle handle) -{ - struct device_node *np; - - read_lock(&devtree_lock); - for (np = allnodes; np != NULL; np = np->allnext) - if (np->phandle == handle) - break; - of_node_get(np); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_phandle); - #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) static struct debugfs_blob_wrapper flat_dt_blob; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f954c718d7eb..28be19ab0f18 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -765,27 +765,6 @@ void __init early_init_devtree(void *params) * *******/ -/** - * of_find_node_by_phandle - Find a node given a phandle - * @handle: phandle of the node to find - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_phandle(phandle handle) -{ - struct device_node *np; - - read_lock(&devtree_lock); - for (np = allnodes; np != 0; np = np->allnext) - if (np->phandle == handle) - break; - of_node_get(np); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_phandle); - /** * of_find_next_cache_node - Find a node's subsidiary cache * @np: node of type "cpu" or "cache" diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 5832e13dfeeb..57ac9e28be0c 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -37,18 +37,6 @@ EXPORT_SYMBOL(of_console_path); char *of_console_options; EXPORT_SYMBOL(of_console_options); -struct device_node *of_find_node_by_phandle(phandle handle) -{ - struct device_node *np; - - for (np = allnodes; np; np = np->allnext) - if (np->phandle == handle) - break; - - return np; -} -EXPORT_SYMBOL(of_find_node_by_phandle); - int of_getintprop_default(struct device_node *np, const char *name, int def) { struct property *prop; diff --git a/drivers/of/base.c b/drivers/of/base.c index 2ce58be314af..785e9cc1b207 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -614,6 +614,27 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) } EXPORT_SYMBOL_GPL(of_modalias_node); +/** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np; np = np->allnext) + if (np->phandle == handle) + break; + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + /** * of_parse_phandle - Resolve a phandle property to a device_node pointer * @np: Pointer to device node holding phandle property -- GitLab From 71a157e8edca55198e808f8561dd49017a54ee34 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1817/3892] of: add 'of_' prefix to machine_is_compatible() machine is compatible is an OF-specific call. It should have the of_ prefix to protect the global namespace. Signed-off-by: Grant Likely Acked-by: Michal Simek --- arch/powerpc/kernel/pci_64.c | 2 +- arch/powerpc/platforms/85xx/xes_mpc85xx.c | 4 +- arch/powerpc/platforms/cell/cbe_powerbutton.c | 2 +- arch/powerpc/platforms/cell/ras.c | 2 +- arch/powerpc/platforms/pasemi/cpufreq.c | 4 +- arch/powerpc/platforms/powermac/cpufreq_32.c | 14 +++--- arch/powerpc/platforms/powermac/cpufreq_64.c | 14 +++--- arch/powerpc/platforms/powermac/feature.c | 2 +- arch/powerpc/platforms/powermac/smp.c | 12 ++--- arch/powerpc/platforms/powermac/time.c | 8 ++-- arch/powerpc/platforms/powermac/udbg_scc.c | 6 +-- arch/powerpc/sysdev/grackle.c | 4 +- drivers/char/hvc_beat.c | 2 +- drivers/gpu/drm/radeon/radeon_combios.c | 44 +++++++++---------- drivers/macintosh/adb.c | 4 +- drivers/macintosh/therm_pm72.c | 8 ++-- drivers/macintosh/therm_windtunnel.c | 2 +- drivers/macintosh/via-pmu-backlight.c | 8 ++-- drivers/macintosh/via-pmu.c | 8 ++-- drivers/macintosh/windfarm_core.c | 6 +-- drivers/macintosh/windfarm_cpufreq_clamp.c | 6 +-- drivers/macintosh/windfarm_lm75_sensor.c | 6 +-- drivers/macintosh/windfarm_max6690_sensor.c | 6 +-- drivers/macintosh/windfarm_pm112.c | 2 +- drivers/macintosh/windfarm_pm121.c | 2 +- drivers/macintosh/windfarm_pm81.c | 4 +- drivers/macintosh/windfarm_pm91.c | 2 +- drivers/macintosh/windfarm_smu_sensors.c | 6 +-- drivers/net/mace.c | 2 +- drivers/of/base.c | 6 +-- drivers/serial/pmac_zilog.c | 6 +-- drivers/video/aty/aty128fb.c | 14 +++--- drivers/video/aty/atyfb_base.c | 8 ++-- drivers/video/aty/radeon_backlight.c | 6 +-- include/linux/of_fdt.h | 2 +- sound/ppc/awacs.c | 24 +++++----- sound/ppc/burgundy.c | 4 +- sound/ppc/pmac.c | 18 ++++---- sound/soc/fsl/efika-audio-fabric.c | 2 +- sound/soc/fsl/pcm030-audio-fabric.c | 2 +- 40 files changed, 142 insertions(+), 142 deletions(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index ccf56ac92de5..d43fc65749c1 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -224,7 +224,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus, * G5 machines... So when something asks for bus 0 io base * (bus 0 is HT root), we return the AGP one instead. */ - if (in_bus == 0 && machine_is_compatible("MacRISC4")) { + if (in_bus == 0 && of_machine_is_compatible("MacRISC4")) { struct device_node *agp; agp = of_find_compatible_node(NULL, NULL, "u3-agp"); diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 1b426050a2f9..0125604d096e 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -80,8 +80,8 @@ static void xes_mpc85xx_configure_l2(void __iomem *l2_base) printk(KERN_INFO "xes_mpc85xx: Enabling L2 as cache\n"); ctl = MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2I; - if (machine_is_compatible("MPC8540") || - machine_is_compatible("MPC8560")) + if (of_machine_is_compatible("MPC8540") || + of_machine_is_compatible("MPC8560")) /* * Assume L2 SRAM is used fully for cache, so set * L2BLKSZ (bits 4:5) to match L2SIZ (bits 2:3). diff --git a/arch/powerpc/platforms/cell/cbe_powerbutton.c b/arch/powerpc/platforms/cell/cbe_powerbutton.c index dcddaa5fcb66..f75a4daa4ca2 100644 --- a/arch/powerpc/platforms/cell/cbe_powerbutton.c +++ b/arch/powerpc/platforms/cell/cbe_powerbutton.c @@ -48,7 +48,7 @@ static int __init cbe_powerbutton_init(void) int ret = 0; struct input_dev *dev; - if (!machine_is_compatible("IBM,CBPLUS-1.0")) { + if (!of_machine_is_compatible("IBM,CBPLUS-1.0")) { printk(KERN_ERR "%s: Not a cell blade.\n", __func__); ret = -ENODEV; goto out; diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 5e0a191764fc..608fd2b584c9 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -255,7 +255,7 @@ static int __init cbe_sysreset_init(void) { struct cbe_pmd_regs __iomem *regs; - sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); + sysreset_hack = of_machine_is_compatible("IBM,CBPLUS-1.0"); if (!sysreset_hack) return 0; diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index be2527a516ea..d35e0520abf0 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -304,8 +304,8 @@ static struct cpufreq_driver pas_cpufreq_driver = { static int __init pas_cpufreq_init(void) { - if (!machine_is_compatible("PA6T-1682M") && - !machine_is_compatible("pasemi,pwrficient")) + if (!of_machine_is_compatible("PA6T-1682M") && + !of_machine_is_compatible("pasemi,pwrficient")) return -ENODEV; return cpufreq_register_driver(&pas_cpufreq_driver); diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 08d94e4cedd3..d4f127d18141 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -657,31 +657,31 @@ static int __init pmac_cpufreq_setup(void) cur_freq = (*value) / 1000; /* Check for 7447A based MacRISC3 */ - if (machine_is_compatible("MacRISC3") && + if (of_machine_is_compatible("MacRISC3") && of_get_property(cpunode, "dynamic-power-step", NULL) && PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { pmac_cpufreq_init_7447A(cpunode); /* Check for other MacRISC3 machines */ - } else if (machine_is_compatible("PowerBook3,4") || - machine_is_compatible("PowerBook3,5") || - machine_is_compatible("MacRISC3")) { + } else if (of_machine_is_compatible("PowerBook3,4") || + of_machine_is_compatible("PowerBook3,5") || + of_machine_is_compatible("MacRISC3")) { pmac_cpufreq_init_MacRISC3(cpunode); /* Else check for iBook2 500/600 */ - } else if (machine_is_compatible("PowerBook4,1")) { + } else if (of_machine_is_compatible("PowerBook4,1")) { hi_freq = cur_freq; low_freq = 400000; set_speed_proc = pmu_set_cpu_speed; is_pmu_based = 1; } /* Else check for TiPb 550 */ - else if (machine_is_compatible("PowerBook3,3") && cur_freq == 550000) { + else if (of_machine_is_compatible("PowerBook3,3") && cur_freq == 550000) { hi_freq = cur_freq; low_freq = 500000; set_speed_proc = pmu_set_cpu_speed; is_pmu_based = 1; } /* Else check for TiPb 400 & 500 */ - else if (machine_is_compatible("PowerBook3,2")) { + else if (of_machine_is_compatible("PowerBook3,2")) { /* We only know about the 400 MHz and the 500Mhz model * they both have 300 MHz as low frequency */ diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 708c75133377..3ed288e68ec4 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -398,11 +398,11 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) int rc = -ENODEV; /* Check supported platforms */ - if (machine_is_compatible("PowerMac8,1") || - machine_is_compatible("PowerMac8,2") || - machine_is_compatible("PowerMac9,1")) + if (of_machine_is_compatible("PowerMac8,1") || + of_machine_is_compatible("PowerMac8,2") || + of_machine_is_compatible("PowerMac9,1")) use_volts_smu = 1; - else if (machine_is_compatible("PowerMac11,2")) + else if (of_machine_is_compatible("PowerMac11,2")) use_volts_vdnap = 1; else return -ENODEV; @@ -729,9 +729,9 @@ static int __init g5_cpufreq_init(void) return -ENODEV; } - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) rc = g5_pm72_cpufreq_init(cpus); #ifdef CONFIG_PMAC_SMU else diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index fbc9bbd74dbd..33e815f4466c 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2426,7 +2426,7 @@ static int __init probe_motherboard(void) } } for(i=0; imode_info.connector_table = radeon_connector_table; if (rdev->mode_info.connector_table == CT_NONE) { #ifdef CONFIG_PPC_PMAC - if (machine_is_compatible("PowerBook3,3")) { + if (of_machine_is_compatible("PowerBook3,3")) { /* powerbook with VGA */ rdev->mode_info.connector_table = CT_POWERBOOK_VGA; - } else if (machine_is_compatible("PowerBook3,4") || - machine_is_compatible("PowerBook3,5")) { + } else if (of_machine_is_compatible("PowerBook3,4") || + of_machine_is_compatible("PowerBook3,5")) { /* powerbook with internal tmds */ rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL; - } else if (machine_is_compatible("PowerBook5,1") || - machine_is_compatible("PowerBook5,2") || - machine_is_compatible("PowerBook5,3") || - machine_is_compatible("PowerBook5,4") || - machine_is_compatible("PowerBook5,5")) { + } else if (of_machine_is_compatible("PowerBook5,1") || + of_machine_is_compatible("PowerBook5,2") || + of_machine_is_compatible("PowerBook5,3") || + of_machine_is_compatible("PowerBook5,4") || + of_machine_is_compatible("PowerBook5,5")) { /* powerbook with external single link tmds (sil164) */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook5,6")) { + } else if (of_machine_is_compatible("PowerBook5,6")) { /* powerbook with external dual or single link tmds */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook5,7") || - machine_is_compatible("PowerBook5,8") || - machine_is_compatible("PowerBook5,9")) { + } else if (of_machine_is_compatible("PowerBook5,7") || + of_machine_is_compatible("PowerBook5,8") || + of_machine_is_compatible("PowerBook5,9")) { /* PowerBook6,2 ? */ /* powerbook with external dual link tmds (sil1178?) */ rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; - } else if (machine_is_compatible("PowerBook4,1") || - machine_is_compatible("PowerBook4,2") || - machine_is_compatible("PowerBook4,3") || - machine_is_compatible("PowerBook6,3") || - machine_is_compatible("PowerBook6,5") || - machine_is_compatible("PowerBook6,7")) { + } else if (of_machine_is_compatible("PowerBook4,1") || + of_machine_is_compatible("PowerBook4,2") || + of_machine_is_compatible("PowerBook4,3") || + of_machine_is_compatible("PowerBook6,3") || + of_machine_is_compatible("PowerBook6,5") || + of_machine_is_compatible("PowerBook6,7")) { /* ibook */ rdev->mode_info.connector_table = CT_IBOOK; - } else if (machine_is_compatible("PowerMac4,4")) { + } else if (of_machine_is_compatible("PowerMac4,4")) { /* emac */ rdev->mode_info.connector_table = CT_EMAC; - } else if (machine_is_compatible("PowerMac10,1")) { + } else if (of_machine_is_compatible("PowerMac10,1")) { /* mini with internal tmds */ rdev->mode_info.connector_table = CT_MINI_INTERNAL; - } else if (machine_is_compatible("PowerMac10,2")) { + } else if (of_machine_is_compatible("PowerMac10,2")) { /* mini with external tmds */ rdev->mode_info.connector_table = CT_MINI_EXTERNAL; - } else if (machine_is_compatible("PowerMac12,1")) { + } else if (of_machine_is_compatible("PowerMac12,1")) { /* PowerMac8,1 ? */ /* imac g5 isight */ rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT; diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 23741cec45e3..d840a109f833 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -322,8 +322,8 @@ static int __init adb_init(void) adb_controller = NULL; } else { #ifdef CONFIG_PPC - if (machine_is_compatible("AAPL,PowerBook1998") || - machine_is_compatible("PowerBook1,1")) + if (of_machine_is_compatible("AAPL,PowerBook1998") || + of_machine_is_compatible("PowerBook1,1")) sleepy_trackpad = 1; #endif /* CONFIG_PPC */ diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 454bc501df3c..5738d8bf2d97 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -1899,7 +1899,7 @@ static int create_control_loops(void) */ if (rackmac) cpu_pid_type = CPU_PID_TYPE_RACKMAC; - else if (machine_is_compatible("PowerMac7,3") + else if (of_machine_is_compatible("PowerMac7,3") && (cpu_count > 1) && fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID && fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) { @@ -2234,10 +2234,10 @@ static int __init therm_pm72_init(void) { struct device_node *np; - rackmac = machine_is_compatible("RackMac3,1"); + rackmac = of_machine_is_compatible("RackMac3,1"); - if (!machine_is_compatible("PowerMac7,2") && - !machine_is_compatible("PowerMac7,3") && + if (!of_machine_is_compatible("PowerMac7,2") && + !of_machine_is_compatible("PowerMac7,3") && !rackmac) return -ENODEV; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index ba48fd76396e..7fb8b4da35a7 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -490,7 +490,7 @@ g4fan_init( void ) info = of_get_property(np, "thermal-info", NULL); of_node_put(np); - if( !info || !machine_is_compatible("PowerMac3,6") ) + if( !info || !of_machine_is_compatible("PowerMac3,6") ) return -ENODEV; if( info->id != 3 ) { diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index a348bb0791d3..4f3c4479c16a 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -150,13 +150,13 @@ void __init pmu_backlight_init() /* Special case for the old PowerBook since I can't test on it */ autosave = - machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500"); + of_machine_is_compatible("AAPL,3400/2400") || + of_machine_is_compatible("AAPL,3500"); if (!autosave && !pmac_has_backlight_type("pmu") && - !machine_is_compatible("AAPL,PowerBook1998") && - !machine_is_compatible("PowerBook1,1")) + !of_machine_is_compatible("AAPL,PowerBook1998") && + !of_machine_is_compatible("PowerBook1,1")) return; snprintf(name, sizeof(name), "pmubl"); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index db379c381432..42764849eb78 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -463,8 +463,8 @@ static int __init via_pmu_dev_init(void) #endif #ifdef CONFIG_PPC32 - if (machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500")) { + if (of_machine_is_compatible("AAPL,3400/2400") || + of_machine_is_compatible("AAPL,3500")) { int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_MODEL, 0); pmu_battery_count = 1; @@ -472,8 +472,8 @@ static int __init via_pmu_dev_init(void) pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET; else pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER; - } else if (machine_is_compatible("AAPL,PowerBook1998") || - machine_is_compatible("PowerBook1,1")) { + } else if (of_machine_is_compatible("AAPL,PowerBook1998") || + of_machine_is_compatible("PowerBook1,1")) { pmu_battery_count = 2; pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 075b4d99e354..437f55c5d18d 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -468,9 +468,9 @@ static int __init windfarm_core_init(void) DBG("wf: core loaded\n"); /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; platform_device_register(&wf_platform_device); return 0; diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c index 900aade06198..1a77a7c97d0e 100644 --- a/drivers/macintosh/windfarm_cpufreq_clamp.c +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c @@ -76,9 +76,9 @@ static int __init wf_cpufreq_clamp_init(void) struct wf_control *clamp; /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index ed6426a10773..d8257d35afde 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -239,9 +239,9 @@ static struct i2c_driver wf_lm75_driver = { static int __init wf_lm75_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; return i2c_add_driver(&wf_lm75_driver); } diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index a67b349319e9..b486eb929fde 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -188,9 +188,9 @@ static struct i2c_driver wf_max6690_driver = { static int __init wf_max6690_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ - if (machine_is_compatible("PowerMac7,2") || - machine_is_compatible("PowerMac7,3") || - machine_is_compatible("RackMac3,1")) + if (of_machine_is_compatible("PowerMac7,2") || + of_machine_is_compatible("PowerMac7,3") || + of_machine_is_compatible("RackMac3,1")) return -ENODEV; return i2c_add_driver(&wf_max6690_driver); } diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index 73d695dc9e50..e0ee80700cde 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -676,7 +676,7 @@ static int __init wf_pm112_init(void) { struct device_node *cpu; - if (!machine_is_compatible("PowerMac11,2")) + if (!of_machine_is_compatible("PowerMac11,2")) return -ENODEV; /* Count the number of CPU cores */ diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index 66ec4fb115bb..947d4afa25ca 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -1008,7 +1008,7 @@ static int __init pm121_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac12,1")) + if (of_machine_is_compatible("PowerMac12,1")) rc = pm121_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index abbe206474f5..565d5b2adc95 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -779,8 +779,8 @@ static int __init wf_smu_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac8,1") || - machine_is_compatible("PowerMac8,2")) + if (of_machine_is_compatible("PowerMac8,1") || + of_machine_is_compatible("PowerMac8,2")) rc = wf_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 764c525b2117..bea99168ff35 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -711,7 +711,7 @@ static int __init wf_smu_init(void) { int rc = -ENODEV; - if (machine_is_compatible("PowerMac9,1")) + if (of_machine_is_compatible("PowerMac9,1")) rc = wf_init_pm(); if (rc == 0) { diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index 9c567b93f417..3c193504bb80 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -363,9 +363,9 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps) * I yet have to figure out what's up with 8,2 and will have to * adjust for later, unless we can 100% trust the SDB partition... */ - if ((machine_is_compatible("PowerMac8,1") || - machine_is_compatible("PowerMac8,2") || - machine_is_compatible("PowerMac9,1")) && + if ((of_machine_is_compatible("PowerMac8,1") || + of_machine_is_compatible("PowerMac8,2") || + of_machine_is_compatible("PowerMac9,1")) && cpuvcp_version >= 2) { pow->quadratic = 1; DBG("windfarm: CPU Power using quadratic transform\n"); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index d9fbad386389..43aea91e3369 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -206,7 +206,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i mp->port_aaui = port_aaui; else { /* Apple Network Server uses the AAUI port */ - if (machine_is_compatible("AAPL,ShinerESB")) + if (of_machine_is_compatible("AAPL,ShinerESB")) mp->port_aaui = 1; else { #ifdef CONFIG_MACE_AAUI_PORT diff --git a/drivers/of/base.c b/drivers/of/base.c index 785e9cc1b207..6bc8740c21ad 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -219,13 +219,13 @@ int of_device_is_compatible(const struct device_node *device, EXPORT_SYMBOL(of_device_is_compatible); /** - * machine_is_compatible - Test root of device tree for a given compatible value + * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. * * Returns true if the root node has the given value in its * compatible property. */ -int machine_is_compatible(const char *compat) +int of_machine_is_compatible(const char *compat) { struct device_node *root; int rc = 0; @@ -237,7 +237,7 @@ int machine_is_compatible(const char *compat) } return rc; } -EXPORT_SYMBOL(machine_is_compatible); +EXPORT_SYMBOL(of_machine_is_compatible); /** * of_device_is_available - check if a device is available for use diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 683e66f18e8c..3e2ae4807ae2 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -2031,9 +2031,9 @@ static int __init pmz_console_setup(struct console *co, char *options) /* * XServe's default to 57600 bps */ - if (machine_is_compatible("RackMac1,1") - || machine_is_compatible("RackMac1,2") - || machine_is_compatible("MacRISC4")) + if (of_machine_is_compatible("RackMac1,1") + || of_machine_is_compatible("RackMac1,2") + || of_machine_is_compatible("MacRISC4")) baud = 57600; /* diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index e4e4d433b007..9ee67d6da710 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1931,22 +1931,22 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i * PowerMac2,2 summer 2000 iMacs * PowerMac4,1 january 2001 iMacs "flower power" */ - if (machine_is_compatible("PowerMac2,1") || - machine_is_compatible("PowerMac2,2") || - machine_is_compatible("PowerMac4,1")) + if (of_machine_is_compatible("PowerMac2,1") || + of_machine_is_compatible("PowerMac2,2") || + of_machine_is_compatible("PowerMac4,1")) default_vmode = VMODE_1024_768_75; /* iBook SE */ - if (machine_is_compatible("PowerBook2,2")) + if (of_machine_is_compatible("PowerBook2,2")) default_vmode = VMODE_800_600_60; /* PowerBook Firewire (Pismo), iBook Dual USB */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook4,1")) + if (of_machine_is_compatible("PowerBook3,1") || + of_machine_is_compatible("PowerBook4,1")) default_vmode = VMODE_1024_768_60; /* PowerBook Titanium */ - if (machine_is_compatible("PowerBook3,2")) + if (of_machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; if (default_cmode > 16) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 5f1b5807a48f..e45ab8db2ddc 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2439,7 +2439,7 @@ static int __devinit aty_init(struct fb_info *info) * The Apple iBook1 uses non-standard memory frequencies. * We detect it and set the frequency manually. */ - if (machine_is_compatible("PowerBook2,1")) { + if (of_machine_is_compatible("PowerBook2,1")) { par->pll_limits.mclk = 70; par->pll_limits.xclk = 53; } @@ -2659,7 +2659,7 @@ static int __devinit aty_init(struct fb_info *info) FBINFO_HWACCEL_YPAN; #ifdef CONFIG_PMAC_BACKLIGHT - if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { + if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) { /* * these bits let the 101 powerbook * wake up from sleep -- paulus @@ -2690,9 +2690,9 @@ static int __devinit aty_init(struct fb_info *info) if (M64_HAS(G3_PB_1024x768)) /* G3 PowerBook with 1024x768 LCD */ default_vmode = VMODE_1024_768_60; - else if (machine_is_compatible("iMac")) + else if (of_machine_is_compatible("iMac")) default_vmode = VMODE_1024_768_75; - else if (machine_is_compatible("PowerBook2,1")) + else if (of_machine_is_compatible("PowerBook2,1")) /* iBook with 800x600 LCD */ default_vmode = VMODE_800_600_60; else diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 1a056adb61c8..fa1198c4ccc5 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -175,9 +175,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) #ifdef CONFIG_PMAC_BACKLIGHT pdata->negative = pdata->negative || - machine_is_compatible("PowerBook4,3") || - machine_is_compatible("PowerBook6,3") || - machine_is_compatible("PowerBook6,5"); + of_machine_is_compatible("PowerBook4,3") || + of_machine_is_compatible("PowerBook6,3") || + of_machine_is_compatible("PowerBook6,5"); #endif rinfo->info->bl_dev = bd; diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 8118d4559dd5..fbf29610616d 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -85,7 +85,7 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname, extern void finish_device_tree(void); extern void unflatten_device_tree(void); extern void early_init_devtree(void *); -extern int machine_is_compatible(const char *compat); +extern int of_machine_is_compatible(const char *compat); extern void print_properties(struct device_node *node); extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 2e156467b814..b36679384b27 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -751,8 +751,8 @@ static void snd_pmac_awacs_suspend(struct snd_pmac *chip) static void snd_pmac_awacs_resume(struct snd_pmac *chip) { - if (machine_is_compatible("PowerBook3,1") - || machine_is_compatible("PowerBook3,2")) { + if (of_machine_is_compatible("PowerBook3,1") + || of_machine_is_compatible("PowerBook3,2")) { msleep(100); snd_pmac_awacs_write_reg(chip, 1, chip->awacs_reg[1] & ~MASK_PAROUT); @@ -780,16 +780,16 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip) } #endif /* CONFIG_PM */ -#define IS_PM7500 (machine_is_compatible("AAPL,7500") \ - || machine_is_compatible("AAPL,8500") \ - || machine_is_compatible("AAPL,9500")) -#define IS_PM5500 (machine_is_compatible("AAPL,e411")) -#define IS_BEIGE (machine_is_compatible("AAPL,Gossamer")) -#define IS_IMAC1 (machine_is_compatible("PowerMac2,1")) -#define IS_IMAC2 (machine_is_compatible("PowerMac2,2") \ - || machine_is_compatible("PowerMac4,1")) -#define IS_G4AGP (machine_is_compatible("PowerMac3,1")) -#define IS_LOMBARD (machine_is_compatible("PowerBook1,1")) +#define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \ + || of_machine_is_compatible("AAPL,8500") \ + || of_machine_is_compatible("AAPL,9500")) +#define IS_PM5500 (of_machine_is_compatible("AAPL,e411")) +#define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer")) +#define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1")) +#define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \ + || of_machine_is_compatible("PowerMac4,1")) +#define IS_G4AGP (of_machine_is_compatible("PowerMac3,1")) +#define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1")) static int imac1, imac2; diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 0accfe49735b..1f72e1c786bf 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -582,7 +582,7 @@ static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip) static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) { if (chip->auto_mute) { - int imac = machine_is_compatible("iMac"); + int imac = of_machine_is_compatible("iMac"); int reg, oreg; reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); @@ -620,7 +620,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti */ int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) { - int imac = machine_is_compatible("iMac"); + int imac = of_machine_is_compatible("iMac"); int i, err; /* Checks to see the chip is alive and kicking */ diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 7bc492ee77ec..85081172403f 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -922,11 +922,11 @@ static void __devinit detect_byte_swap(struct snd_pmac *chip) } /* it seems the Pismo & iBook can't byte-swap in hardware. */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook2,1")) + if (of_machine_is_compatible("PowerBook3,1") || + of_machine_is_compatible("PowerBook2,1")) chip->can_byte_swap = 0 ; - if (machine_is_compatible("PowerBook2,1")) + if (of_machine_is_compatible("PowerBook2,1")) chip->can_duplex = 0; } @@ -959,11 +959,11 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip) chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */ /* check machine type */ - if (machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500")) + if (of_machine_is_compatible("AAPL,3400/2400") + || of_machine_is_compatible("AAPL,3500")) chip->is_pbook_3400 = 1; - else if (machine_is_compatible("PowerBook1,1") - || machine_is_compatible("AAPL,PowerBook1998")) + else if (of_machine_is_compatible("PowerBook1,1") + || of_machine_is_compatible("AAPL,PowerBook1998")) chip->is_pbook_G3 = 1; chip->node = of_find_node_by_name(NULL, "awacs"); sound = of_node_get(chip->node); @@ -1033,8 +1033,8 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip) } if (of_device_is_compatible(sound, "tumbler")) { chip->model = PMAC_TUMBLER; - chip->can_capture = machine_is_compatible("PowerMac4,2") - || machine_is_compatible("PowerBook4,1"); + chip->can_capture = of_machine_is_compatible("PowerMac4,2") + || of_machine_is_compatible("PowerBook4,1"); chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index 3326e2a1e863..1a5b8e0d6a34 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -55,7 +55,7 @@ static __init int efika_fabric_init(void) struct platform_device *pdev; int rc; - if (!machine_is_compatible("bplan,efika")) + if (!of_machine_is_compatible("bplan,efika")) return -ENODEV; card.platform = &mpc5200_audio_dma_platform; diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index b928ef7d28eb..6644cba7cbf2 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -55,7 +55,7 @@ static __init int pcm030_fabric_init(void) struct platform_device *pdev; int rc; - if (!machine_is_compatible("phytec,pcm030")) + if (!of_machine_is_compatible("phytec,pcm030")) return -ENODEV; card.platform = &mpc5200_audio_dma_platform; -- GitLab From 51975db0b7333cf389b64b5040c2a910341d241a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1818/3892] of/flattree: merge early_init_dt_scan_memory() common code Merge common code between PowerPC and Microblaze architectures. Signed-off-by: Grant Likely Acked-by: Michal Simek --- arch/microblaze/kernel/prom.c | 51 +------------------------- arch/powerpc/kernel/prom.c | 69 +++++++++-------------------------- drivers/of/fdt.c | 50 +++++++++++++++++++++++++ include/linux/of_fdt.h | 3 ++ 4 files changed, 73 insertions(+), 100 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index f7bd0ee8d481..459c32e4a5fe 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -45,61 +45,14 @@ /* export that to outside world */ struct device_node *of_chosen; -#define early_init_dt_scan_drconf_memory(node) 0 - void __init early_init_dt_scan_chosen_arch(unsigned long node) { /* No Microblaze specific code here */ } -static int __init early_init_dt_scan_memory(unsigned long node, - const char *uname, int depth, void *data) +void __init early_init_dt_add_memory_arch(u64 base, u64 size) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *reg, *endp; - unsigned long l; - - /* Look for the ibm,dynamic-reconfiguration-memory node */ -/* if (depth == 1 && - strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) - return early_init_dt_scan_drconf_memory(node); -*/ - /* We are scanning "memory" nodes only */ - if (type == NULL) { - /* - * The longtrail doesn't have a device_type on the - * /memory node, so look for the node called /memory@0. - */ - if (depth != 1 || strcmp(uname, "memory@0") != 0) - return 0; - } else if (strcmp(type, "memory") != 0) - return 0; - - reg = (__be32 *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); - if (reg == NULL) - reg = (__be32 *)of_get_flat_dt_prop(node, "reg", &l); - if (reg == NULL) - return 0; - - endp = reg + (l / sizeof(__be32)); - - pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", - uname, l, reg[0], reg[1], reg[2], reg[3]); - - while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { - u64 base, size; - - base = dt_mem_next_cell(dt_root_addr_cells, ®); - size = dt_mem_next_cell(dt_root_size_cells, ®); - - if (size == 0) - continue; - pr_debug(" - %llx , %llx\n", (unsigned long long)base, - (unsigned long long)size); - - lmb_add(base, size); - } - return 0; + lmb_add(base, size); } #ifdef CONFIG_EARLY_PRINTK diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 28be19ab0f18..e0f368ff8d12 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -483,64 +483,31 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node) #define early_init_dt_scan_drconf_memory(node) 0 #endif /* CONFIG_PPC_PSERIES */ -static int __init early_init_dt_scan_memory(unsigned long node, - const char *uname, int depth, void *data) +static int __init early_init_dt_scan_memory_ppc(unsigned long node, + const char *uname, + int depth, void *data) { - char *type = of_get_flat_dt_prop(node, "device_type", NULL); - __be32 *reg, *endp; - unsigned long l; - - /* Look for the ibm,dynamic-reconfiguration-memory node */ if (depth == 1 && strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) return early_init_dt_scan_drconf_memory(node); + + return early_init_dt_scan_memory(node, uname, depth, data); +} - /* We are scanning "memory" nodes only */ - if (type == NULL) { - /* - * The longtrail doesn't have a device_type on the - * /memory node, so look for the node called /memory@0. - */ - if (depth != 1 || strcmp(uname, "memory@0") != 0) - return 0; - } else if (strcmp(type, "memory") != 0) - return 0; - - reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); - if (reg == NULL) - reg = of_get_flat_dt_prop(node, "reg", &l); - if (reg == NULL) - return 0; - - endp = reg + (l / sizeof(__be32)); - - DBG("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", - uname, l, reg[0], reg[1], reg[2], reg[3]); - - while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { - u64 base, size; - - base = dt_mem_next_cell(dt_root_addr_cells, ®); - size = dt_mem_next_cell(dt_root_size_cells, ®); - - if (size == 0) - continue; - DBG(" - %llx , %llx\n", (unsigned long long)base, - (unsigned long long)size); -#ifdef CONFIG_PPC64 - if (iommu_is_off) { - if (base >= 0x80000000ul) - continue; - if ((base + size) > 0x80000000ul) - size = 0x80000000ul - base; - } +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ +#if defined(CONFIG_PPC64) + if (iommu_is_off) { + if (base >= 0x80000000ul) + return; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } #endif - lmb_add(base, size); - memstart_addr = min((u64)memstart_addr, base); - } + lmb_add(base, size); - return 0; + memstart_addr = min((u64)memstart_addr, base); } static void __init early_reserve_mem(void) @@ -706,7 +673,7 @@ void __init early_init_devtree(void *params) /* Scan memory nodes and rebuild LMBs */ lmb_init(); of_scan_flat_dt(early_init_dt_scan_root, NULL); - of_scan_flat_dt(early_init_dt_scan_memory, NULL); + of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); /* Save command line for /proc/cmdline and then parse parameters */ strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 7f8861121a31..f84152d112b0 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -15,6 +15,7 @@ #include #include + #ifdef CONFIG_PPC #include #endif /* CONFIG_PPC */ @@ -443,6 +444,55 @@ u64 __init dt_mem_next_cell(int s, u32 **cellp) return of_read_number(p, s); } +/** + * early_init_dt_scan_memory - Look for an parse memory nodes + */ +int __init early_init_dt_scan_memory(unsigned long node, const char *uname, + int depth, void *data) +{ + char *type = of_get_flat_dt_prop(node, "device_type", NULL); + __be32 *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL) { + /* + * The longtrail doesn't have a device_type on the + * /memory node, so look for the node called /memory@0. + */ + if (depth != 1 || strcmp(uname, "memory@0") != 0) + return 0; + } else if (strcmp(type, "memory") != 0) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); + if (reg == NULL) + reg = of_get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(__be32)); + + pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", + uname, l, reg[0], reg[1], reg[2], reg[3]); + + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + u64 base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + pr_debug(" - %llx , %llx\n", (unsigned long long)base, + (unsigned long long)size); + + early_init_dt_add_memory_arch(base, size); + } + + return 0; +} + int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index fbf29610616d..bf26bd5df9f1 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -75,6 +75,9 @@ extern void early_init_dt_scan_chosen_arch(unsigned long node); extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data); extern void early_init_dt_check_for_initrd(unsigned long node); +extern int early_init_dt_scan_memory(unsigned long node, const char *uname, + int depth, void *data); +extern void early_init_dt_add_memory_arch(u64 base, u64 size); extern u64 dt_mem_next_cell(int s, u32 **cellp); /* Early flat tree scan hooks */ -- GitLab From a9f2f63a671d5e91ed89ade408d87f1692a373de Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1819/3892] of: include linux/proc_fs.h We use a few procfs-specific functions (eg, proc_device_tree_*) which aren't covered by the current includes. This causes the following build error on arm: drivers/of/base.c: In function 'prom_add_property': drivers/of/base.c:861: error: implicit declaration of function 'proc_device_tree_add_prop' drivers/of/base.c: In function 'prom_remove_property': drivers/of/base.c:902: error: implicit declaration of function 'proc_device_tree_remove_prop' drivers/of/base.c: In function 'prom_update_property': drivers/of/base.c:946: error: implicit declaration of function 'proc_device_tree_update_prop' Add proc_fs.h for these prototypes. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 6bc8740c21ad..524645ab42a4 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -20,6 +20,7 @@ #include #include #include +#include struct device_node *allnodes; -- GitLab From 8cfb3343f70bcf9403218df120ecf345f06dd585 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1820/3892] of: make set_node_proc_entry private to proc_devtree.c We only need set_node_proc_entry in proc_devtree.c, so move it there. This fixes the !HAVE_ARCH_DEVTREE_FIXUPS build, as we can't make make the definition in linux/of.h conditional on this #define (definitions in asm/prom.h can't be exposed to linux/of.h, due to the enforced #include ordering). Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- fs/proc/proc_devtree.c | 5 +++-- include/linux/of.h | 6 ------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 123257bb356b..2309bf17203f 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -14,12 +14,13 @@ #include #include "internal.h" -#ifndef HAVE_ARCH_DEVTREE_FIXUPS static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) { -} +#ifdef HAVE_ARCH_DEVTREE_FIXUPS + np->pde = de; #endif +} static struct proc_dir_entry *proc_device_tree; diff --git a/include/linux/of.h b/include/linux/of.h index 3cc0d7ae290e..fd47c81d7a25 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -73,12 +73,6 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag) set_bit(flag, &n->_flags); } -static inline void -set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) -{ - dn->pde = de; -} - extern struct device_node *of_find_all_nodes(struct device_node *prev); #if defined(CONFIG_SPARC) -- GitLab From 50ab2fe147e22c8786552cda1791a61ae81b84d2 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1821/3892] proc_devtree: include linux/of.h Currenly, proc_devtree.c depends on asm/prom.h to include linux/of.h, to provide some device-tree definitions (eg, struct property). Instead, include linux/of.h directly. We still need asm/prom.h for HAVE_ARCH_DEVTREE_FIXUPS. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- fs/proc/proc_devtree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 2309bf17203f..0ec45110e15e 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "internal.h" -- GitLab From 1406bc2f57787797d1f6a3675c019a7093769275 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:31:21 -0700 Subject: [PATCH 1822/3892] of/flattree: use callback to setup initrd from /chosen At present, the fdt code sets the kernel-wide initrd_start and initrd_end variables when parsing /chosen. On ARM, we only set these once the bootmem has been reserved. This change adds an arch hook to setup the initrd from the device tree: void early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end); The arch-specific code can then setup the initrd however it likes. Compiled on powerpc, with CONFIG_BLK_DEV_INITRD=y and =n. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- arch/microblaze/kernel/prom.c | 10 ++++++++++ arch/powerpc/kernel/prom.c | 10 ++++++++++ drivers/of/fdt.c | 27 +++++++++++---------------- include/linux/of_fdt.h | 10 ++++++++++ 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 459c32e4a5fe..050b7993c51c 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -118,6 +118,16 @@ void __init early_init_devtree(void *params) pr_debug(" <- early_init_devtree()\n"); } +#ifdef CONFIG_BLK_DEV_INITRD +void __init early_init_dt_setup_initrd_arch(unsigned long start, + unsigned long end) +{ + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; +} +#endif + /******* * * New implementation of the OF "find" APIs, return a refcounted diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index e0f368ff8d12..40fce1c2f33b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -510,6 +510,16 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memstart_addr = min((u64)memstart_addr, base); } +#ifdef CONFIG_BLK_DEV_INITRD +void __init early_init_dt_setup_initrd_arch(unsigned long start, + unsigned long end) +{ + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; +} +#endif + static void __init early_reserve_mem(void) { u64 base, size; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index f84152d112b0..9290ca5aa892 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -384,28 +384,23 @@ unsigned long __init unflatten_dt_node(unsigned long mem, */ void __init early_init_dt_check_for_initrd(unsigned long node) { - unsigned long len; + unsigned long start, end, len; u32 *prop; pr_debug("Looking for initrd properties... "); prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); - if (prop) { - initrd_start = (unsigned long) - __va(of_read_ulong(prop, len/4)); - - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); - if (prop) { - initrd_end = (unsigned long) - __va(of_read_ulong(prop, len/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } + if (!prop) + return; + start = of_read_ulong(prop, len/4); + + prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); + if (!prop) + return; + end = of_read_ulong(prop, len/4); - pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", - initrd_start, initrd_end); + early_init_dt_setup_initrd_arch(start, end); + pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end); } #else inline void early_init_dt_check_for_initrd(unsigned long node) diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index bf26bd5df9f1..f32f0fc5314a 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -80,6 +80,16 @@ extern int early_init_dt_scan_memory(unsigned long node, const char *uname, extern void early_init_dt_add_memory_arch(u64 base, u64 size); extern u64 dt_mem_next_cell(int s, u32 **cellp); +/* + * If BLK_DEV_INITRD, the fdt early init code will call this function, + * to be provided by the arch code. start and end are specified as + * physical addresses. + */ +#ifdef CONFIG_BLK_DEV_INITRD +extern void early_init_dt_setup_initrd_arch(unsigned long start, + unsigned long end); +#endif + /* Early flat tree scan hooks */ extern int early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data); -- GitLab From 36b9d3070d653af5807cef74ff129721d9047107 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 1 Feb 2010 21:34:14 -0700 Subject: [PATCH 1823/3892] of/flattree: use OF_ROOT_NODE_{SIZE,ADDR}_CELLS DEFAULT for fdt parsing At present we're using hard-coded values for defaults when parsing the FDT. This change uses the #defines instead. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9290ca5aa892..56fbd6e3122a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -420,11 +420,11 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 0; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = (prop == NULL) ? 1 : *prop; + dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT; pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT; pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ -- GitLab From 2e89e685a8fd0e8334de967739d11e2e28c1a4dd Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:41:49 -0700 Subject: [PATCH 1824/3892] of: use __be32 for cell value accessors Currently, we're using u32 for cell values, and hence assuming host-endian device trees. As we'd like to support little-endian platforms, use a __be32 for cell values, and convert in the cell accessors. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/fdt.c | 4 ++-- include/linux/of.h | 8 +++++--- include/linux/of_fdt.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 56fbd6e3122a..968a86af5301 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -431,9 +431,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } -u64 __init dt_mem_next_cell(int s, u32 **cellp) +u64 __init dt_mem_next_cell(int s, __be32 **cellp) { - u32 *p = *cellp; + __be32 *p = *cellp; *cellp = p + s; return of_read_number(p, s); diff --git a/include/linux/of.h b/include/linux/of.h index fd47c81d7a25..fa5571b6e219 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -20,6 +20,8 @@ #include #include +#include + typedef u32 phandle; typedef u32 ihandle; @@ -95,16 +97,16 @@ extern void of_node_put(struct device_node *node); */ /* Helper to read a big number; size is in cells (not bytes) */ -static inline u64 of_read_number(const u32 *cell, int size) +static inline u64 of_read_number(const __be32 *cell, int size) { u64 r = 0; while (size--) - r = (r << 32) | *(cell++); + r = (r << 32) | be32_to_cpu(*(cell++)); return r; } /* Like of_read_number, but we want an unsigned long result */ -static inline unsigned long of_read_ulong(const u32 *cell, int size) +static inline unsigned long of_read_ulong(const __be32 *cell, int size) { /* toss away upper bits if unsigned long is smaller than u64 */ return of_read_number(cell, size); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index f32f0fc5314a..6a35d91a53a6 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -78,7 +78,7 @@ extern void early_init_dt_check_for_initrd(unsigned long node); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data); extern void early_init_dt_add_memory_arch(u64 base, u64 size); -extern u64 dt_mem_next_cell(int s, u32 **cellp); +extern u64 dt_mem_next_cell(int s, __be32 **cellp); /* * If BLK_DEV_INITRD, the fdt early init code will call this function, -- GitLab From 337148812f97368a8ec4a69f1691e4c5ce3af494 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 01:45:26 -0700 Subject: [PATCH 1825/3892] of: assume big-endian properties, adding conversions where necessary Properties in the device tree are specified as big-endian. At present, the only platforms to support device trees are also big-endian, so we've been acessing the properties as raw values. We'd like to add device tree support to little-endian platforms too, so add endian conversion to the sites where we access property values in the common of code. Compiled on powerpc (ppc44x_defconfig & ppc64_defconfig) and arm (fdt support only for now). Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- drivers/of/base.c | 12 ++++++------ drivers/of/fdt.c | 45 ++++++++++++++++++++++++-------------------- drivers/of/gpio.c | 13 +++++++------ drivers/of/of_i2c.c | 4 ++-- drivers/of/of_mdio.c | 8 ++++---- drivers/of/of_spi.c | 6 +++--- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 524645ab42a4..873479a21c80 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -38,7 +38,7 @@ int of_n_addr_cells(struct device_node *np) np = np->parent; ip = of_get_property(np, "#address-cells", NULL); if (ip) - return *ip; + return be32_to_cpup(ip); } while (np->parent); /* No #address-cells property for the root node */ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; @@ -54,7 +54,7 @@ int of_n_size_cells(struct device_node *np) np = np->parent; ip = of_get_property(np, "#size-cells", NULL); if (ip) - return *ip; + return be32_to_cpup(ip); } while (np->parent); /* No #size-cells property for the root node */ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; @@ -696,8 +696,8 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const void **out_args) { int ret = -EINVAL; - const u32 *list; - const u32 *list_end; + const __be32 *list; + const __be32 *list_end; int size; int cur_index = 0; struct device_node *node = NULL; @@ -711,7 +711,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, list_end = list + size / sizeof(*list); while (list < list_end) { - const u32 *cells; + const __be32 *cells; const phandle *phandle; phandle = list++; @@ -735,7 +735,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, goto err1; } - list += *cells; + list += be32_to_cpup(cells); if (list > list_end) { pr_debug("%s: insufficient arguments length\n", np->full_name); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 968a86af5301..5c5f03ef7f06 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -51,7 +51,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, int depth = -1; do { - u32 tag = *((u32 *)p); + u32 tag = be32_to_cpup((__be32 *)p); char *pathp; p += 4; @@ -64,7 +64,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, if (tag == OF_DT_END) break; if (tag == OF_DT_PROP) { - u32 sz = *((u32 *)p); + u32 sz = be32_to_cpup((__be32 *)p); p += 8; if (initial_boot_params->version < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); @@ -103,9 +103,9 @@ unsigned long __init of_get_flat_dt_root(void) unsigned long p = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; - while (*((u32 *)p) == OF_DT_NOP) + while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) p += 4; - BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); + BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); p += 4; return _ALIGN(p + strlen((char *)p) + 1, 4); } @@ -122,7 +122,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long p = node; do { - u32 tag = *((u32 *)p); + u32 tag = be32_to_cpup((__be32 *)p); u32 sz, noff; const char *nstr; @@ -132,8 +132,8 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, if (tag != OF_DT_PROP) return NULL; - sz = *((u32 *)p); - noff = *((u32 *)(p + 4)); + sz = be32_to_cpup((__be32 *)p); + noff = be32_to_cpup((__be32 *)(p + 4)); p += 8; if (initial_boot_params->version < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); @@ -210,7 +210,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, int has_name = 0; int new_format = 0; - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); if (tag != OF_DT_BEGIN_NODE) { pr_err("Weird tag at start of node: %x\n", tag); return mem; @@ -285,7 +285,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, u32 sz, noff; char *pname; - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); if (tag == OF_DT_NOP) { *p += 4; continue; @@ -293,8 +293,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (tag != OF_DT_PROP) break; *p += 4; - sz = *((u32 *)(*p)); - noff = *((u32 *)((*p) + 4)); + sz = be32_to_cpup((__be32 *)(*p)); + noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; if (initial_boot_params->version < 0x10) *p = _ALIGN(*p, sz >= 8 ? 8 : 4); @@ -367,7 +367,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, } while (tag == OF_DT_BEGIN_NODE) { mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); - tag = *((u32 *)(*p)); + tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { pr_err("Weird tag at end of node: %x\n", tag); @@ -385,7 +385,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, void __init early_init_dt_check_for_initrd(unsigned long node) { unsigned long start, end, len; - u32 *prop; + __be32 *prop; pr_debug("Looking for initrd properties... "); @@ -414,17 +414,22 @@ inline void early_init_dt_check_for_initrd(unsigned long node) int __init early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data) { - u32 *prop; + __be32 *prop; if (depth != 0) return 0; + dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + if (prop) + dt_root_size_cells = be32_to_cpup(prop); pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + if (prop) + dt_root_addr_cells = be32_to_cpup(prop); pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ @@ -549,7 +554,7 @@ void __init unflatten_device_tree(void) mem = lmb_alloc(size + 4, __alignof__(struct device_node)); mem = (unsigned long) __va(mem); - ((u32 *)mem)[size / 4] = 0xdeadbeef; + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); pr_debug(" unflattening %lx...\n", mem); @@ -557,11 +562,11 @@ void __init unflatten_device_tree(void) start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; unflatten_dt_node(mem, &start, NULL, &allnextp, 0); - if (*((u32 *)start) != OF_DT_END) + if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (((u32 *)mem)[size / 4] != 0xdeadbeef) + if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", - ((u32 *)mem)[size / 4]); + be32_to_cpu(((__be32 *)mem)[size / 4])); *allnextp = NULL; /* Get pointer to OF "/chosen" node for use everywhere */ diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 6eea601a9204..24c3606217f8 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -36,7 +36,7 @@ int of_get_gpio_flags(struct device_node *np, int index, struct of_gpio_chip *of_gc = NULL; int size; const void *gpio_spec; - const u32 *gpio_cells; + const __be32 *gpio_cells; ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, &gc, &gpio_spec); @@ -55,7 +55,7 @@ int of_get_gpio_flags(struct device_node *np, int index, gpio_cells = of_get_property(gc, "#gpio-cells", &size); if (!gpio_cells || size != sizeof(*gpio_cells) || - *gpio_cells != of_gc->gpio_cells) { + be32_to_cpup(gpio_cells) != of_gc->gpio_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", np->full_name, gc->full_name); ret = -EINVAL; @@ -127,7 +127,8 @@ EXPORT_SYMBOL(of_gpio_count); int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, const void *gpio_spec, enum of_gpio_flags *flags) { - const u32 *gpio = gpio_spec; + const __be32 *gpio = gpio_spec; + const u32 n = be32_to_cpup(gpio); /* * We're discouraging gpio_cells < 2, since that way you'll have to @@ -140,13 +141,13 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, return -EINVAL; } - if (*gpio > of_gc->gc.ngpio) + if (n > of_gc->gc.ngpio) return -EINVAL; if (flags) - *flags = gpio[1]; + *flags = be32_to_cpu(gpio[1]); - return *gpio; + return n; } EXPORT_SYMBOL(of_gpio_simple_xlate); diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index fa65a2b2ae2e..a3a708e590d0 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -25,7 +25,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, for_each_child_of_node(adap_node, node) { struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; - const u32 *addr; + const __be32 *addr; int len; if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) @@ -40,7 +40,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.irq = irq_of_parse_and_map(node, 0); - info.addr = *addr; + info.addr = be32_to_cpup(addr); dev_archdata_set_node(&dev_ad, node); info.archdata = &dev_ad; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 4b22ba568b19..18ecae4a4375 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -51,7 +51,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Loop over the child nodes and register a phy_device for each one */ for_each_child_of_node(np, child) { - const u32 *addr; + const __be32 *addr; int len; /* A PHY must have a reg property in the range [0-31] */ @@ -68,7 +68,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) mdio->irq[*addr] = PHY_POLL; } - phy = get_phy_device(mdio, *addr); + phy = get_phy_device(mdio, be32_to_cpup(addr)); if (!phy) { dev_err(&mdio->dev, "error probing PHY at address %i\n", *addr); @@ -160,7 +160,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, struct device_node *net_np; char bus_id[MII_BUS_ID_SIZE + 3]; struct phy_device *phy; - const u32 *phy_id; + const __be32 *phy_id; int sz; if (!dev->dev.parent) @@ -174,7 +174,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, if (!phy_id || sz < sizeof(*phy_id)) return NULL; - sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]); + sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0])); phy = phy_connect(dev, bus_id, hndlr, 0, iface); return IS_ERR(phy) ? NULL : phy; diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index bed0ed6dcdc1..f65f48b98448 100644 --- a/drivers/of/of_spi.c +++ b/drivers/of/of_spi.c @@ -23,7 +23,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) { struct spi_device *spi; struct device_node *nc; - const u32 *prop; + const __be32 *prop; int rc; int len; @@ -54,7 +54,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) spi_dev_put(spi); continue; } - spi->chip_select = *prop; + spi->chip_select = be32_to_cpup(prop); /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) @@ -72,7 +72,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) spi_dev_put(spi); continue; } - spi->max_speed_hz = *prop; + spi->max_speed_hz = be32_to_cpup(prop); /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); -- GitLab From 087f79c48c090a2c0cd9ee45231d63290d2036d2 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 30 Jan 2010 04:14:19 -0700 Subject: [PATCH 1826/3892] of/flattree: endian-convert members of boot_param_header The boot_param_header has big-endian fields, so change the types to __be32, and perform endian conversion when we access them. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely --- arch/powerpc/kernel/prom.c | 2 +- drivers/of/fdt.c | 16 ++++++++-------- include/linux/of_fdt.h | 20 ++++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 40fce1c2f33b..43c78d74ddcb 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -98,7 +98,7 @@ static void __init move_device_tree(void) DBG("-> move_device_tree\n"); start = __pa(initial_boot_params); - size = initial_boot_params->totalsize; + size = be32_to_cpu(initial_boot_params->totalsize); if ((memory_limit && (start + size) > memory_limit) || overlaps_crashkernel(start, size)) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 5c5f03ef7f06..18d282fefe58 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -28,7 +28,7 @@ struct boot_param_header *initial_boot_params; char *find_flat_dt_string(u32 offset) { return ((char *)initial_boot_params) + - initial_boot_params->off_dt_strings + offset; + be32_to_cpu(initial_boot_params->off_dt_strings) + offset; } /** @@ -46,7 +46,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, void *data) { unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); int rc = 0; int depth = -1; @@ -66,7 +66,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, if (tag == OF_DT_PROP) { u32 sz = be32_to_cpup((__be32 *)p); p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); p += sz; p = _ALIGN(p, 4); @@ -101,7 +101,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, unsigned long __init of_get_flat_dt_root(void) { unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) p += 4; @@ -135,7 +135,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, sz = be32_to_cpup((__be32 *)p); noff = be32_to_cpup((__be32 *)(p + 4)); p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) p = _ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); @@ -296,7 +296,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, sz = be32_to_cpup((__be32 *)(*p)); noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; - if (initial_boot_params->version < 0x10) + if (be32_to_cpu(initial_boot_params->version) < 0x10) *p = _ALIGN(*p, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); @@ -544,7 +544,7 @@ void __init unflatten_device_tree(void) /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); size = unflatten_dt_node(0, &start, NULL, NULL, 0); size = (size | 3) + 1; @@ -560,7 +560,7 @@ void __init unflatten_device_tree(void) /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; + be32_to_cpu(initial_boot_params->off_dt_struct); unflatten_dt_node(mem, &start, NULL, &allnextp, 0); if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 6a35d91a53a6..0007187ab59b 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -42,19 +42,19 @@ * ends when size is 0 */ struct boot_param_header { - u32 magic; /* magic word OF_DT_HEADER */ - u32 totalsize; /* total size of DT block */ - u32 off_dt_struct; /* offset to structure */ - u32 off_dt_strings; /* offset to strings */ - u32 off_mem_rsvmap; /* offset to memory reserve map */ - u32 version; /* format version */ - u32 last_comp_version; /* last compatible version */ + __be32 magic; /* magic word OF_DT_HEADER */ + __be32 totalsize; /* total size of DT block */ + __be32 off_dt_struct; /* offset to structure */ + __be32 off_dt_strings; /* offset to strings */ + __be32 off_mem_rsvmap; /* offset to memory reserve map */ + __be32 version; /* format version */ + __be32 last_comp_version; /* last compatible version */ /* version 2 fields below */ - u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + __be32 boot_cpuid_phys; /* Physical CPU id we're booting on */ /* version 3 fields below */ - u32 dt_strings_size; /* size of the DT strings block */ + __be32 dt_strings_size; /* size of the DT strings block */ /* version 17 fields below */ - u32 dt_struct_size; /* size of the DT structure block */ + __be32 dt_struct_size; /* size of the DT structure block */ }; /* TBD: Temporary export of fdt globals - remove when code fully merged */ -- GitLab From 04b954a673dd02f585a2769c4945a43880faa989 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 1 Feb 2010 21:34:15 -0700 Subject: [PATCH 1827/3892] of/flattree: Make the kernel accept ePAPR style phandle information Currently when processing flattened device trees, the kernel expects the phandle in a property called "linux,phandle". The ePAPR spec - not being Linux specific - instead requires phandles to be encoded in a property named simply "phandle". This patch makes the kernel accept either form when unflattening the device tree. Signed-off-by: David Gibson Signed-off-by: Grant Likely --- drivers/of/fdt.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 18d282fefe58..b51f797d9d9d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -310,10 +310,19 @@ unsigned long __init unflatten_dt_node(unsigned long mem, pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); if (allnextpp) { - if (strcmp(pname, "linux,phandle") == 0) { + /* We accept flattened tree phandles either in + * ePAPR-style "phandle" properties, or the + * legacy "linux,phandle" properties. If both + * appear and have different values, things + * will get weird. Don't do that. */ + if ((strcmp(pname, "phandle") == 0) || + (strcmp(pname, "linux,phandle") == 0)) { if (np->phandle == 0) np->phandle = *((u32 *)*p); } + /* And we process the "ibm,phandle" property + * used in pSeries dynamic device tree + * stuff */ if (strcmp(pname, "ibm,phandle") == 0) np->phandle = *((u32 *)*p); pp->name = pname; -- GitLab From 375177bf35efc08e1bd37bbda4cc0c8cc4db8500 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 9 Feb 2010 14:50:28 +0530 Subject: [PATCH 1828/3892] mac80211: Retry null data frame for power save. Even if the null data frame is not acked by the AP, mac80211 goes into power save. This might lead to loss of frames from the AP. Prevent this by restarting dynamic_ps_timer when ack is not received for null data frames. Cc: Johannes Berg Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- include/net/mac80211.h | 6 ++++++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 20 +++++++++++++++----- net/mac80211/status.c | 17 +++++++++++++++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 414d774028ba..314e98173166 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -945,6 +945,11 @@ enum ieee80211_tkip_key_type { * Hardware supports Unscheduled Automatic Power Save Delivery * (U-APSD) in managed mode. The mode is configured with * conf_tx() operation. + * + * @IEEE80211_HW_REPORTS_TX_ACK_STATUS: + * Hardware can provide ack status reports of Tx frames to + * the stack. + * */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -965,6 +970,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, + IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a5911191f224..9dd98b674cbc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -316,6 +316,7 @@ enum ieee80211_sta_flags { IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), IEEE80211_STA_UAPSD_ENABLED = BIT(7), + IEEE80211_STA_NULLFUNC_ACKED = BIT(8), }; struct ieee80211_if_managed { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7a7921476582..ee9443dc20ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -434,8 +434,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, } else { if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) ieee80211_send_nullfunc(local, sdata, 1); - conf->flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + + if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } } } @@ -541,6 +544,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) container_of(work, struct ieee80211_local, dynamic_ps_enable_work); struct ieee80211_sub_if_data *sdata = local->ps_sdata; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; /* can only happen when PS was just disabled anyway */ if (!sdata) @@ -549,11 +553,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if (local->hw.conf.flags & IEEE80211_CONF_PS) return; - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && + (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) ieee80211_send_nullfunc(local, sdata, 1); - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) || + (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { + ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } } void ieee80211_dynamic_ps_timer(unsigned long data) @@ -1892,6 +1901,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, return -ENOMEM; ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; + ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e57ad6b1d7ea..ded98730c111 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -188,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_lock(); sband = local->hw.wiphy->bands[info->band]; + fc = hdr->frame_control; for_each_sta_info(local, hdr->addr1, sta, tmp) { /* skip wrong virtual interface */ @@ -205,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) return; } - fc = hdr->frame_control; - if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && (ieee80211_is_data_qos(fc))) { u16 tid, ssn; @@ -275,6 +274,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) local->dot11FailedCount++; } + if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && + (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && + !(info->flags & IEEE80211_TX_CTL_INJECTED) && + local->ps_sdata && !(local->scanning)) { + if (info->flags & IEEE80211_TX_STAT_ACK) { + local->ps_sdata->u.mgd.flags |= + IEEE80211_STA_NULLFUNC_ACKED; + ieee80211_queue_work(&local->hw, + &local->dynamic_ps_enable_work); + } else + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(10)); + } + /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); -- GitLab From 05df49865be08b30e7ba91b9d3d94d7d52dd3033 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 9 Feb 2010 11:34:50 +0530 Subject: [PATCH 1829/3892] ath9k: Enable IEEE80211_HW_REPORTS_TX_ACK_STATUS flag for ath9k. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4b5e54848683..623c2f884987 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -622,7 +622,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_REPORTS_TX_ACK_STATUS; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; -- GitLab From 7578a4c625a5cc32812946338a4549f3090be113 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 10 Feb 2010 16:00:58 +0900 Subject: [PATCH 1830/3892] sh: Fix up multi-resource mapping for SH7786 PCIe. This reworks some of the SH7786 PCIe initialization code to dynamically setup and size the various resource windows, as opposed to the original code that simply wired in a couple of them statically. At the same time, we tidy up the initialization code a bit, kill off some read-only register twiddling that was gleaned from the bus analyzer, and also propagate the physical slot/channel mapping. Signed-off-by: Paul Mundt --- arch/sh/drivers/pci/pcie-sh7786.c | 89 +++++++++++++++++++++++++------ arch/sh/drivers/pci/pcie-sh7786.h | 36 +++---------- 2 files changed, 82 insertions(+), 43 deletions(-) diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index 95d095f26d66..ae91a2dd9183 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -204,7 +204,9 @@ static int pcie_init(struct sh7786_pcie_port *port) { struct pci_channel *chan = port->hose; unsigned int data; - int ret; + phys_addr_t memphys; + size_t memsize; + int ret, i; /* Begin initialization */ pci_write_reg(chan, 0, SH4A_PCIETCTLR); @@ -227,15 +229,24 @@ static int pcie_init(struct sh7786_pcie_port *port) data |= PCI_CAP_ID_EXP; pci_write_reg(chan, data, SH4A_PCIEEXPCAP0); - /* Enable x4 link width and extended sync. */ + /* Enable data link layer active state reporting */ + pci_write_reg(chan, PCI_EXP_LNKCAP_DLLLARC, SH4A_PCIEEXPCAP3); + + /* Enable extended sync and ASPM L0s support */ data = pci_read_reg(chan, SH4A_PCIEEXPCAP4); - data &= ~(PCI_EXP_LNKSTA_NLW << 16); - data |= (1 << 22) | PCI_EXP_LNKCTL_ES; + data &= ~PCI_EXP_LNKCTL_ASPMC; + data |= PCI_EXP_LNKCTL_ES | 1; pci_write_reg(chan, data, SH4A_PCIEEXPCAP4); + /* Write out the physical slot number */ + data = pci_read_reg(chan, SH4A_PCIEEXPCAP5); + data &= ~PCI_EXP_SLTCAP_PSN; + data |= (port->index + 1) << 19; + pci_write_reg(chan, data, SH4A_PCIEEXPCAP5); + /* Set the completion timer timeout to the maximum 32ms. */ data = pci_read_reg(chan, SH4A_PCIETLCTLR); - data &= ~0xffff; + data &= ~0x3f00; data |= 0x32 << 8; pci_write_reg(chan, data, SH4A_PCIETLCTLR); @@ -248,6 +259,33 @@ static int pcie_init(struct sh7786_pcie_port *port) data |= (0xff << 16); pci_write_reg(chan, data, SH4A_PCIEMACCTLR); + memphys = __pa(memory_start); + memsize = roundup_pow_of_two(memory_end - memory_start); + + /* + * If there's more than 512MB of memory, we need to roll over to + * LAR1/LAMR1. + */ + if (memsize > SZ_512M) { + __raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1); + __raw_writel(((memsize - SZ_512M) - SZ_256) | 1, + chan->reg_base + SH4A_PCIELAMR1); + memsize = SZ_512M; + } else { + /* + * Otherwise just zero it out and disable it. + */ + __raw_writel(0, chan->reg_base + SH4A_PCIELAR1); + __raw_writel(0, chan->reg_base + SH4A_PCIELAMR1); + } + + /* + * LAR0/LAMR0 covers up to the first 512MB, which is enough to + * cover all of lowmem on most platforms. + */ + __raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0); + __raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0); + /* Finish initialization */ data = pci_read_reg(chan, SH4A_PCIETCTLR); data |= 0x1; @@ -267,10 +305,14 @@ static int pcie_init(struct sh7786_pcie_port *port) if (unlikely(ret != 0)) return -ENODEV; - pci_write_reg(chan, 0x00100007, SH4A_PCIEPCICONF1); + data = pci_read_reg(chan, SH4A_PCIEPCICONF1); + data &= ~(PCI_STATUS_DEVSEL_MASK << 16); + data |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + (PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST) << 16; + pci_write_reg(chan, data, SH4A_PCIEPCICONF1); + pci_write_reg(chan, 0x80888000, SH4A_PCIETXVC0DCTLR); pci_write_reg(chan, 0x00222000, SH4A_PCIERXVC0DCTLR); - pci_write_reg(chan, 0x000050A0, SH4A_PCIEEXPCAP2); wmb(); @@ -278,15 +320,32 @@ static int pcie_init(struct sh7786_pcie_port *port) printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n", port->index, (data >> 20) & 0x3f); - pci_write_reg(chan, 0x007c0000, SH4A_PCIEPAMR0); - pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH0); - pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL0); - pci_write_reg(chan, 0x80000100, SH4A_PCIEPTCTLR0); - pci_write_reg(chan, 0x03fc0000, SH4A_PCIEPAMR2); - pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH2); - pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL2); - pci_write_reg(chan, 0x80000000, SH4A_PCIEPTCTLR2); + for (i = 0; i < chan->nr_resources; i++) { + struct resource *res = chan->resources + i; + resource_size_t size; + u32 enable_mask; + + pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i)); + + size = resource_size(res); + + /* + * The PAMR mask is calculated in units of 256kB, which + * keeps things pretty simple. + */ + __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18, + chan->reg_base + SH4A_PCIEPAMR(i)); + + pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i)); + pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i)); + + enable_mask = MASK_PARE; + if (res->flags & IORESOURCE_IO) + enable_mask |= MASK_SPC; + + pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i)); + } return 0; } diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h index 6666ea29cba8..90a6992576b0 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.h +++ b/arch/sh/drivers/pci/pcie-sh7786.h @@ -312,23 +312,23 @@ #define SH4A_PCIECSAR5 (0x0202B4) /* R/W R/W 0x0000 0000 32 */ #define SH4A_PCIESTCTLR5 (0x0202B8) /* R/W R/W 0x0000 0000 32 */ -/* PCIEPARL0 */ -#define SH4A_PCIEPARL0 (0x020400) /* R/W R/W 0x0000 0000 32 */ +/* PCIEPARL */ +#define SH4A_PCIEPARL(x) (0x020400 + ((x) * 0x20)) /* R/W R/W 0x0000 0000 32 */ #define BITS_PAL (18) #define MASK_PAL (0x3fff< Date: Wed, 10 Feb 2010 16:06:42 +0900 Subject: [PATCH 1831/3892] sh: update sdk7786 defconfig. This plugs in USB and PCI and other bits for SDK7786. Signed-off-by: Paul Mundt --- arch/sh/configs/sdk7786_defconfig | 360 ++++++++++++++++++++++++++++-- 1 file changed, 337 insertions(+), 23 deletions(-) diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig index 1721d2c5c7e8..9b331eab968e 100644 --- a/arch/sh/configs/sdk7786_defconfig +++ b/arch/sh/configs/sdk7786_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc3 -# Thu Jan 14 20:37:44 2010 +# Linux kernel version: 2.6.33-rc7 +# Tue Feb 9 15:27:06 2010 # CONFIG_SUPERH=y CONFIG_SUPERH32=y @@ -13,8 +13,8 @@ CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y -CONFIG_GENERIC_IRQ_PROBE=y CONFIG_IRQ_PER_CPU=y +CONFIG_SPARSE_IRQ=y # CONFIG_GENERIC_GPIO is not set CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CLOCKEVENTS=y @@ -23,6 +23,7 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_SYS_SUPPORTS_HUGETLBFS=y CONFIG_SYS_SUPPORTS_SMP=y CONFIG_SYS_SUPPORTS_NUMA=y +CONFIG_SYS_SUPPORTS_PCI=y CONFIG_SYS_SUPPORTS_TMU=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y @@ -134,6 +135,7 @@ CONFIG_EVENT_PROFILE=y # CONFIG_PERF_COUNTERS is not set # CONFIG_DEBUG_PERF_USE_VMALLOC is not set CONFIG_VM_EVENT_COUNTERS=y +CONFIG_PCI_QUIRKS=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y # CONFIG_SLUB is not set @@ -143,7 +145,6 @@ CONFIG_TRACEPOINTS=y # CONFIG_OPROFILE is not set CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set -CONFIG_HAVE_IOREMAP_PROT=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y @@ -267,7 +268,7 @@ CONFIG_MMU=y CONFIG_PAGE_OFFSET=0x80000000 CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_MEMORY_START=0x60000000 -CONFIG_MEMORY_SIZE=0x08000000 +CONFIG_MEMORY_SIZE=0x20000000 # CONFIG_29BIT is not set CONFIG_32BIT=y CONFIG_PMB=y @@ -284,6 +285,7 @@ CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y CONFIG_ARCH_MEMORY_PROBE=y +CONFIG_IOREMAP_FIXED=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_16KB is not set @@ -341,9 +343,7 @@ CONFIG_SH_SDK7786=y # Timer and clock configuration # CONFIG_SH_TIMER_TMU=y -CONFIG_SH_PCLK_FREQ=50000000 CONFIG_SH_CLK_CPG=y -CONFIG_SH_CLK_CPG_LEGACY=y CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -401,7 +401,6 @@ CONFIG_SECCOMP=y # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y CONFIG_GUSA=y -CONFIG_SPARSE_IRQ=y # # Boot options @@ -411,13 +410,26 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000 CONFIG_ENTRY_OFFSET=0x00001000 CONFIG_CMDLINE_OVERWRITE=y # CONFIG_CMDLINE_EXTEND is not set -CONFIG_CMDLINE="console=ttySC1,115200 earlyprintk=sh-sci.1,115200 root=/dev/nfs ip=dhcp" +CONFIG_CMDLINE="console=ttySC1,115200 earlyprintk=sh-sci.1,115200 root=/dev/sda1 nmi_debug=state,debounce rootdelay=10" # # Bus options # +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +CONFIG_PCIEAER_INJECT=y +CONFIG_PCIEASPM=y +CONFIG_PCIEASPM_DEBUG=y # CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCI_LEGACY is not set +CONFIG_PCI_DEBUG=y +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set # CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -430,8 +442,14 @@ CONFIG_BINFMT_MISC=y # # Power management options (EXPERIMENTAL) # -# CONFIG_PM is not set -# CONFIG_CPU_IDLE is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_VERBOSE=y +# CONFIG_HIBERNATION is not set +CONFIG_PM_RUNTIME=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_NET=y # @@ -538,6 +556,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_MTD is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set @@ -545,6 +566,7 @@ CONFIG_BLK_DEV=y # DRBD disabled because PROC_FS, INET or CONNECTOR not selected # # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 @@ -555,8 +577,12 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_HD is not set CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set +# CONFIG_PHANTOM is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set # CONFIG_ISL29003 is not set # CONFIG_DS1682 is not set # CONFIG_TI_DAC7512 is not set @@ -570,6 +596,7 @@ CONFIG_MISC_DEVICES=y # CONFIG_EEPROM_LEGACY is not set # CONFIG_EEPROM_MAX6875 is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -608,19 +635,131 @@ CONFIG_SCSI_WAIT_SCAN=m # CONFIG_SCSI_SRP_ATTRS is not set CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_HPTIOP is not set # CONFIG_LIBFC is not set # CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set # CONFIG_SCSI_DH is not set # CONFIG_SCSI_OSD_INITIATOR is not set CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set CONFIG_ATA_VERBOSE_ERROR=y CONFIG_SATA_PMP=y +# CONFIG_SATA_AHCI is not set +CONFIG_SATA_SIL24=y CONFIG_ATA_SFF=y +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set # CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set CONFIG_PATA_PLATFORM=y +# CONFIG_PATA_SCH is not set # CONFIG_MD is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# You can enable one or both FireWire driver stacks. +# + +# +# The newer stack is recommended. +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -628,6 +767,7 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_VETH is not set +# CONFIG_ARCNET is not set CONFIG_PHYLIB=y # @@ -652,12 +792,18 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_AX88796 is not set # CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set CONFIG_SMC91X=y # CONFIG_ENC28J60 is not set # CONFIG_ETHOC is not set # CONFIG_SMC911X is not set CONFIG_SMSC911X=y # CONFIG_DNET is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set # CONFIG_IBM_NEW_EMAC_ZMII is not set # CONFIG_IBM_NEW_EMAC_RGMII is not set # CONFIG_IBM_NEW_EMAC_TAH is not set @@ -665,13 +811,18 @@ CONFIG_SMSC911X=y # CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set # CONFIG_B44 is not set # CONFIG_KS8842 is not set # CONFIG_KS8851 is not set # CONFIG_KS8851_MLL is not set +# CONFIG_ATL2 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set # CONFIG_USB_ZD1201 is not set # CONFIG_HOSTAP is not set @@ -688,31 +839,94 @@ CONFIG_WLAN=y # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set # CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set +# CONFIG_NET_FC is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_VMXNET3 is not set # CONFIG_ISDN is not set # CONFIG_PHONE is not set # # Input device support # -# CONFIG_INPUT is not set +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set # # Hardware I/O ports # -# CONFIG_SERIO is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set # CONFIG_GAMEPORT is not set # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # # Serial drivers @@ -728,14 +942,17 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=6 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set # CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_COMPAT is not set @@ -746,12 +963,29 @@ CONFIG_I2C_HELPER_AUTO=y # I2C Hardware Bus support # +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + # # I2C system bus drivers (mostly embedded / system-on-chip) # # CONFIG_I2C_DESIGNWARE is not set # CONFIG_I2C_OCORES is not set -CONFIG_I2C_SDK7786=y # CONFIG_I2C_SH_MOBILE is not set # CONFIG_I2C_SIMTEC is not set @@ -772,10 +1006,10 @@ CONFIG_I2C_SDK7786=y # Miscellaneous I2C Chip support # # CONFIG_SENSORS_TSL2550 is not set -CONFIG_I2C_DEBUG_CORE=y -CONFIG_I2C_DEBUG_ALGO=y -CONFIG_I2C_DEBUG_BUS=y -CONFIG_I2C_DEBUG_CHIP=y +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set CONFIG_SPI=y # CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y @@ -810,8 +1044,15 @@ CONFIG_WATCHDOG=y # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set # CONFIG_SH_WDT is not set +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + # # USB-based Watchdog Cards # @@ -849,6 +1090,8 @@ CONFIG_SSB_POSSIBLE=y # # Graphics support # +CONFIG_VGA_ARB=y +# CONFIG_DRM is not set # CONFIG_VGASTATE is not set CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_FB is not set @@ -858,11 +1101,56 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m # Display device support # # CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y # CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_ZEROPLUS is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y -# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y # CONFIG_USB_DEBUG is not set # CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set @@ -873,6 +1161,7 @@ CONFIG_USB=y # CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set # CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set @@ -884,13 +1173,20 @@ CONFIG_USB_MON=y # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_ISP1760_HCD is not set # CONFIG_USB_ISP1362_HCD is not set -# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set -CONFIG_USB_R8A66597_HCD=m +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_WHCI_HCD is not set # CONFIG_USB_HWA_HCD is not set # CONFIG_USB_GADGET_MUSB_HDRC is not set @@ -909,7 +1205,19 @@ CONFIG_USB_R8A66597_HCD=m # # also be needed; see USB_STORAGE Help for more info # -# CONFIG_USB_STORAGE is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_LIBUSUAL is not set # @@ -989,10 +1297,12 @@ CONFIG_USB_GADGET_DUALSPEED=y # OTG and related infrastructure # # CONFIG_NOP_USB_XCEIV is not set +# CONFIG_UWB is not set # CONFIG_MMC is not set # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set # CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y CONFIG_RTC_HCTOSYS=y @@ -1063,10 +1373,13 @@ CONFIG_RTC_DRV_SH=y # CONFIG_DMADEVICES is not set # CONFIG_AUXDISPLAY is not set CONFIG_UIO=m +# CONFIG_UIO_CIF is not set # CONFIG_UIO_PDRV is not set # CONFIG_UIO_PDRV_GENIRQ is not set # CONFIG_UIO_SMX is not set +# CONFIG_UIO_AEC is not set # CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set # # TI VLYNQ @@ -1418,6 +1731,7 @@ CONFIG_CRYPTO=y # # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set CONFIG_BINARY_PRINTF=y # -- GitLab From 22313eafe92aeec1db9839f5afb71675bf2a5c33 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Feb 2010 10:42:33 +0000 Subject: [PATCH 1832/3892] ASoC: add phycore-ac97 sound support This patch adds sound support for Phytec PhyCORE / PhyCARD modules in AC97 mode. Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/Makefile | 2 + sound/soc/imx/phycore-ac97.c | 90 ++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 sound/soc/imx/phycore-ac97.c diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index d05cc95c5cc4..9f8bb92ddfcc 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -8,3 +8,5 @@ endif obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o # i.MX Machine Support +snd-soc-phycore-ac97-objs := phycore-ac97.o +obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c new file mode 100644 index 000000000000..a8307d55c70e --- /dev/null +++ b/sound/soc/imx/phycore-ac97.c @@ -0,0 +1,90 @@ +/* + * phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode + * + * Copyright 2009 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm9712.h" +#include "imx-ssi.h" + +static struct snd_soc_card imx_phycore; + +static struct snd_soc_ops imx_phycore_hifi_ops = { +}; + +static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { + { + .name = "HiFi", + .stream_name = "HiFi", + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], + .ops = &imx_phycore_hifi_ops, + }, +}; + +static struct snd_soc_card imx_phycore = { + .name = "PhyCORE-audio", + .platform = &imx_soc_platform, + .dai_link = imx_phycore_dai_ac97, + .num_links = ARRAY_SIZE(imx_phycore_dai_ac97), +}; + +static struct snd_soc_device imx_phycore_snd_devdata = { + .card = &imx_phycore, + .codec_dev = &soc_codec_dev_wm9712, +}; + +static struct platform_device *imx_phycore_snd_device; + +static int __init imx_phycore_init(void) +{ + int ret; + + if (!machine_is_pcm043() && !machine_is_pca100()) + /* return happy. We might run on a totally different machine */ + return 0; + + imx_phycore_snd_device = platform_device_alloc("soc-audio", -1); + if (!imx_phycore_snd_device) + return -ENOMEM; + + imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0]; + + platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata); + imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev; + ret = platform_device_add(imx_phycore_snd_device); + + if (ret) { + printk(KERN_ERR "ASoC: Platform device allocation failed\n"); + platform_device_put(imx_phycore_snd_device); + } + + return ret; +} + +static void __exit imx_phycore_exit(void) +{ + platform_device_unregister(imx_phycore_snd_device); +} + +late_initcall(imx_phycore_init); +module_exit(imx_phycore_exit); + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("PhyCORE ALSA SoC driver"); +MODULE_LICENSE("GPL"); -- GitLab From c0ff4bcd2e8505b09e0bedc74d08ad2da1e326f8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 9 Feb 2010 02:32:59 +0800 Subject: [PATCH 1833/3892] ASoC: cs4270: enable regulators at probe time Enable the bulk regulators at probe time so we can safely disable them again when going to suspend without confusing the reference counter. Signed-off-by: Daniel Mack Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 593bfc7a6986..dfbeb2db61b3 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -629,8 +629,17 @@ static int cs4270_probe(struct platform_device *pdev) if (ret < 0) goto error_free_pcms; + ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + if (ret < 0) + goto error_free_regulators; + return 0; +error_free_regulators: + regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), + cs4270->supplies); + error_free_pcms: snd_soc_free_pcms(socdev); @@ -650,6 +659,7 @@ static int cs4270_remove(struct platform_device *pdev) struct cs4270_private *cs4270 = codec->private_data; snd_soc_free_pcms(socdev); + regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); return 0; -- GitLab From b32758c7216f337044ceb6dcaa754b8eda95a59f Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Wed, 10 Feb 2010 12:09:17 +0100 Subject: [PATCH 1834/3892] HID: fixed bug in single-touch emulation on the stantum panel Fixed stupid copy-paste bug in touchscreen emulation for the Stantum multitouch panel: a flag was reset just before being tested. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-stantum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index add965dab932..1b7b1659e7bb 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -147,7 +147,6 @@ static void stantum_filter_event(struct stantum_data *sd, input_mt_sync(input); sd->valid = false; - sd->first = false; /* touchscreen emulation */ if (sd->first) { @@ -158,6 +157,7 @@ static void stantum_filter_event(struct stantum_data *sd, input_event(input, EV_ABS, ABS_X, sd->x); input_event(input, EV_ABS, ABS_Y, sd->y); } + sd->first = false; } -- GitLab From 580363db92572cccbe6226bf83321e50a9ea50ea Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Sat, 6 Feb 2010 15:20:03 +0100 Subject: [PATCH 1835/3892] HID: add pressure support for the Stantum multitouch panel Added pressure handling for Stantum multitouch panels Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-stantum.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index 1b7b1659e7bb..04b0b986f5f4 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -66,7 +66,6 @@ static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_DEVICEINDEX: case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTMAX: - case HID_DG_TIPPRESSURE: return -1; case HID_DG_TIPSWITCH: @@ -84,6 +83,11 @@ static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 1, 1, 0, 0); return 1; + case HID_DG_TIPPRESSURE: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_PRESSURE); + return 1; + case HID_DG_CONTACTID: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID); @@ -140,10 +144,7 @@ static void stantum_filter_event(struct stantum_data *sd, input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); -#if 0 - /* MT_PRESSURE does not exist yet */ input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); -#endif input_mt_sync(input); sd->valid = false; -- GitLab From c42a59ea277a8898b8f7c83fc89b00be225ea6aa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Feb 2010 15:24:04 +0200 Subject: [PATCH 1836/3892] ASoC: TWL4030: Add supply for audio serial interface control The serial interface (TDM/I2S) for the audio block have been constantly enabled. Introduce a new DAPM_SUPPLY for handling the AIF_EN bit, so the interface is only enabled, when there is a need for it. For example when only the analog loopback is enabled, there is no need to keep the serial interface active. I have added the persons who contributed to the Voice path of twl4030 codec driver, so they might have the ability to test this patch, and send an update for the Voice path, if it is necessary Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b32aeb38e3a6..277862e480e2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -55,7 +55,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x0c, /* REG_ATXR1PGA (0xB) */ 0x00, /* REG_AVTXL2PGA (0xC) */ 0x00, /* REG_AVTXR2PGA (0xD) */ - 0x01, /* REG_AUDIO_IF (0xE) */ + 0x00, /* REG_AUDIO_IF (0xE) */ 0x00, /* REG_VOICE_IF (0xF) */ 0x00, /* REG_ARXR1PGA (0x10) */ 0x00, /* REG_ARXL1PGA (0x11) */ @@ -1203,6 +1203,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0), + /* Output MIXER controls */ /* Earpiece */ SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, @@ -1337,6 +1339,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"Digital L2 Playback Mixer", NULL, "APLL Enable"}, {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, + {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, + {"Digital L1 Playback Mixer", NULL, "AIF Enable"}, + {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, + {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, + {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, @@ -1455,6 +1462,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"ADC Virtual Left2", NULL, "APLL Enable"}, {"ADC Virtual Right2", NULL, "APLL Enable"}, + {"ADC Virtual Left1", NULL, "AIF Enable"}, + {"ADC Virtual Right1", NULL, "AIF Enable"}, + {"ADC Virtual Left2", NULL, "AIF Enable"}, + {"ADC Virtual Right2", NULL, "AIF Enable"}, + /* Analog bypass routes */ {"Right1 Analog Loopback", "Switch", "Analog Right"}, {"Left1 Analog Loopback", "Switch", "Analog Left"}, -- GitLab From c6848bf566c7217a6090693ff5cc47091fa772f5 Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Tue, 9 Feb 2010 11:42:27 +0100 Subject: [PATCH 1837/3892] ASoC: Typo. s/Freecale/Freescale/ Signed-off-by: Paul Menzel Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 5f006f0d03dc..c7d0fd9b7de8 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,5 +1,5 @@ config SND_IMX_SOC - tristate "SoC Audio for Freecale i.MX CPUs" + tristate "SoC Audio for Freescale i.MX CPUs" depends on ARCH_MXC && BROKEN select SND_PCM select FIQ -- GitLab From 28ef35eb33d7e291bf0e1fe1137915a7e38805ff Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 9 Feb 2010 23:08:17 +0000 Subject: [PATCH 1838/3892] powerpc/44x: Fix L2-cache support for 460GT Also set L2C_CFG_RDBW on 460GT platforms and not only on 460EX. Signed-off-by: Stefan Roese Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/sysdev/ppc4xx_soc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c index 5b32adc9a9b2..5c014350bf16 100644 --- a/arch/powerpc/sysdev/ppc4xx_soc.c +++ b/arch/powerpc/sysdev/ppc4xx_soc.c @@ -174,7 +174,8 @@ static int __init ppc4xx_l2c_probe(void) | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM; /* Check for 460EX/GT special handling */ - if (of_device_is_compatible(np, "ibm,l2-cache-460ex")) + if (of_device_is_compatible(np, "ibm,l2-cache-460ex") || + of_device_is_compatible(np, "ibm,l2-cache-460gt")) r |= L2C_CFG_RDBW; mtdcr(dcrbase_l2c + DCRN_L2C0_CFG, r); -- GitLab From 036f290d8952fdcafa9d6c9e2d94efbcb793d123 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 26 Jan 2010 05:56:30 +0000 Subject: [PATCH 1839/3892] powerpc/44x: Add MTD support (NOR FLASH) to Katmai dts This patch adds NOR FLASH MTD support to the Katmai (440SPe) dts file. For this the OPB ranges address is mapped differently (base 0x00000000 -> 0xe0000000). This results in the address being identical to the lower 32bit of its physical address. This is needed for the MTD mapping to work correctly, since U-Boot will insert the physical addresses of the EBC chip selects into the EBC ranges property. This is the way its done in most other 4xx dts files as well. Additionally with a small whitespace cleanup. Signed-off-by: Stefan Roese Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/katmai.dts | 71 +++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts index 8f345de960cd..8cf2c0c88c05 100644 --- a/arch/powerpc/boot/dts/katmai.dts +++ b/arch/powerpc/boot/dts/katmai.dts @@ -156,7 +156,7 @@ compatible = "ibm,opb-440spe", "ibm,opb-440gp", "ibm,opb"; #address-cells = <1>; #size-cells = <1>; - ranges = <0x00000000 0x00000004 0xe0000000 0x20000000>; + ranges = <0xe0000000 0x00000004 0xe0000000 0x20000000>; clock-frequency = <0>; /* Filled in by zImage */ EBC0: ebc { @@ -165,14 +165,47 @@ #address-cells = <2>; #size-cells = <1>; clock-frequency = <0>; /* Filled in by zImage */ + /* ranges property is supplied by U-Boot */ interrupts = <0x5 0x1>; interrupt-parent = <&UIC1>; + + nor_flash@0,0 { + compatible = "cfi-flash"; + bank-width = <2>; + reg = <0x00000000 0x00000000 0x01000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "kernel"; + reg = <0x00000000 0x001e0000>; + }; + partition@1e0000 { + label = "dtb"; + reg = <0x001e0000 0x00020000>; + }; + partition@200000 { + label = "root"; + reg = <0x00200000 0x00200000>; + }; + partition@400000 { + label = "user"; + reg = <0x00400000 0x00b60000>; + }; + partition@f60000 { + label = "env"; + reg = <0x00f60000 0x00040000>; + }; + partition@fa0000 { + label = "u-boot"; + reg = <0x00fa0000 0x00060000>; + }; + }; }; - UART0: serial@10000200 { + UART0: serial@f0000200 { device_type = "serial"; compatible = "ns16550"; - reg = <0x10000200 0x00000008>; + reg = <0xf0000200 0x00000008>; virtual-reg = <0xa0000200>; clock-frequency = <0>; /* Filled in by zImage */ current-speed = <115200>; @@ -180,10 +213,10 @@ interrupts = <0x0 0x4>; }; - UART1: serial@10000300 { + UART1: serial@f0000300 { device_type = "serial"; compatible = "ns16550"; - reg = <0x10000300 0x00000008>; + reg = <0xf0000300 0x00000008>; virtual-reg = <0xa0000300>; clock-frequency = <0>; current-speed = <0>; @@ -192,10 +225,10 @@ }; - UART2: serial@10000600 { + UART2: serial@f0000600 { device_type = "serial"; compatible = "ns16550"; - reg = <0x10000600 0x00000008>; + reg = <0xf0000600 0x00000008>; virtual-reg = <0xa0000600>; clock-frequency = <0>; current-speed = <0>; @@ -203,27 +236,27 @@ interrupts = <0x5 0x4>; }; - IIC0: i2c@10000400 { + IIC0: i2c@f0000400 { compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic"; - reg = <0x10000400 0x00000014>; + reg = <0xf0000400 0x00000014>; interrupt-parent = <&UIC0>; interrupts = <0x2 0x4>; }; - IIC1: i2c@10000500 { + IIC1: i2c@f0000500 { compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic"; - reg = <0x10000500 0x00000014>; + reg = <0xf0000500 0x00000014>; interrupt-parent = <&UIC0>; interrupts = <0x3 0x4>; }; - EMAC0: ethernet@10000800 { + EMAC0: ethernet@f0000800 { linux,network-index = <0x0>; device_type = "network"; compatible = "ibm,emac-440spe", "ibm,emac4"; interrupt-parent = <&UIC1>; interrupts = <0x1c 0x4 0x1d 0x4>; - reg = <0x10000800 0x00000074>; + reg = <0xf0000800 0x00000074>; local-mac-address = [000000000000]; mal-device = <&MAL0>; mal-tx-channel = <0>; @@ -248,11 +281,11 @@ primary; large-inbound-windows; enable-msi-hole; - reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */ - 0x00000000 0x00000000 0x00000000 /* no IACK cycles */ - 0x0000000c 0x0ed00000 0x00000004 /* Special cycles */ - 0x0000000c 0x0ec80000 0x00000100 /* Internal registers */ - 0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */ + reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */ + 0x00000000 0x00000000 0x00000000 /* no IACK cycles */ + 0x0000000c 0x0ed00000 0x00000004 /* Special cycles */ + 0x0000000c 0x0ec80000 0x00000100 /* Internal registers */ + 0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */ /* Outbound ranges, one memory and one IO, * later cannot be changed @@ -453,6 +486,6 @@ }; chosen { - linux,stdout-path = "/plb/opb/serial@10000200"; + linux,stdout-path = "/plb/opb/serial@f0000200"; }; }; -- GitLab From 6f57518cfa097b170a8f500d6d70651e81589e30 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 9 Feb 2010 23:08:34 +0000 Subject: [PATCH 1840/3892] powerpc/44x: Update Arches dts Sync Arches dts with latest Canyonlands version: - Add 16k FIFO size to supported EMAC nodes - Add next-level-cache property - Add Crypto device node Signed-off-by: Stefan Roese Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/arches.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/powerpc/boot/dts/arches.dts b/arch/powerpc/boot/dts/arches.dts index 414ef8b7e575..30f41204acfa 100644 --- a/arch/powerpc/boot/dts/arches.dts +++ b/arch/powerpc/boot/dts/arches.dts @@ -60,6 +60,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; + next-level-cache = <&L2C0>; }; }; @@ -146,6 +147,13 @@ dcr-reg = <0x010 0x002>; }; + CRYPTO: crypto@180000 { + compatible = "amcc,ppc460gt-crypto", "amcc,ppc4xx-crypto"; + reg = <4 0x00180000 0x80400>; + interrupt-parent = <&UIC0>; + interrupts = <0x1d 0x4>; + }; + MAL0: mcmal { compatible = "ibm,mcmal-460gt", "ibm,mcmal2"; dcr-reg = <0x180 0x062>; @@ -274,6 +282,7 @@ max-frame-size = <9000>; rx-fifo-size = <4096>; tx-fifo-size = <2048>; + rx-fifo-size-gige = <16384>; phy-mode = "sgmii"; phy-map = <0xffffffff>; gpcs-address = <0x0000000a>; @@ -302,6 +311,7 @@ max-frame-size = <9000>; rx-fifo-size = <4096>; tx-fifo-size = <2048>; + rx-fifo-size-gige = <16384>; phy-mode = "sgmii"; phy-map = <0x00000000>; gpcs-address = <0x0000000b>; @@ -331,6 +341,8 @@ max-frame-size = <9000>; rx-fifo-size = <4096>; tx-fifo-size = <2048>; + rx-fifo-size-gige = <16384>; + tx-fifo-size-gige = <16384>; /* emac2&3 only */ phy-mode = "sgmii"; phy-map = <0x00000001>; gpcs-address = <0x0000000C>; -- GitLab From 5a6543e8da6e338fef3cd42cc79ac85f6f53a8e7 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 9 Feb 2010 23:08:28 +0000 Subject: [PATCH 1841/3892] powerpc/44x: Update Glacier dts Sync Glacier dts with latest Canyonlands version: - Add l2 cache support - Add NDFC support - Add RTC support - Add AD7414 hwmon support - Change EMAC compatible node from emac4 to emac4sync and correct the register size - Add support for ISA holes on 4xx PCI/X/E (as done in Benjamin Herrenschmidt's patch for Canyonlands) - Add Crypto device node Signed-off-by: Stefan Roese Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/glacier.dts | 76 +++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts index f6f618939293..d62a4fb6f93c 100644 --- a/arch/powerpc/boot/dts/glacier.dts +++ b/arch/powerpc/boot/dts/glacier.dts @@ -1,7 +1,7 @@ /* * Device Tree Source for AMCC Glacier (460GT) * - * Copyright 2008 DENX Software Engineering, Stefan Roese + * Copyright 2008-2010 DENX Software Engineering, Stefan Roese * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without @@ -42,6 +42,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; + next-level-cache = <&L2C0>; }; }; @@ -106,6 +107,16 @@ dcr-reg = <0x00c 0x002>; }; + L2C0: l2c { + compatible = "ibm,l2-cache-460gt", "ibm,l2-cache"; + dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */ + 0x030 0x008>; /* L2 cache DCR's */ + cache-line-size = <32>; /* 32 bytes */ + cache-size = <262144>; /* L2, 256K */ + interrupt-parent = <&UIC1>; + interrupts = <11 1>; + }; + plb { compatible = "ibm,plb-460gt", "ibm,plb4"; #address-cells = <2>; @@ -118,6 +129,13 @@ dcr-reg = <0x010 0x002>; }; + CRYPTO: crypto@180000 { + compatible = "amcc,ppc460gt-crypto", "amcc,ppc4xx-crypto"; + reg = <4 0x00180000 0x80400>; + interrupt-parent = <&UIC0>; + interrupts = <0x1d 0x4>; + }; + MAL0: mcmal { compatible = "ibm,mcmal-460gt", "ibm,mcmal2"; dcr-reg = <0x180 0x062>; @@ -186,6 +204,29 @@ reg = <0x03fa0000 0x00060000>; }; }; + + ndfc@3,0 { + compatible = "ibm,ndfc"; + reg = <0x00000003 0x00000000 0x00002000>; + ccr = <0x00001000>; + bank-settings = <0x80002222>; + #address-cells = <1>; + #size-cells = <1>; + + nand { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x00000000 0x00100000>; + }; + partition@100000 { + label = "user"; + reg = <0x00000000 0x03f00000>; + }; + }; + }; }; UART0: serial@ef600300 { @@ -237,6 +278,20 @@ reg = <0xef600700 0x00000014>; interrupt-parent = <&UIC0>; interrupts = <0x2 0x4>; + #address-cells = <1>; + #size-cells = <0>; + rtc@68 { + compatible = "stm,m41t80"; + reg = <0x68>; + interrupt-parent = <&UIC2>; + interrupts = <0x19 0x8>; + }; + sttm@48 { + compatible = "ad,ad7414"; + reg = <0x48>; + interrupt-parent = <&UIC1>; + interrupts = <0x14 0x8>; + }; }; IIC1: i2c@ef600800 { @@ -275,7 +330,7 @@ EMAC0: ethernet@ef600e00 { device_type = "network"; - compatible = "ibm,emac-460gt", "ibm,emac4"; + compatible = "ibm,emac-460gt", "ibm,emac4sync"; interrupt-parent = <&EMAC0>; interrupts = <0x0 0x1>; #interrupt-cells = <1>; @@ -283,7 +338,7 @@ #size-cells = <0>; interrupt-map = ; - reg = <0xef600e00 0x00000074>; + reg = <0xef600e00 0x000000c4>; local-mac-address = [000000000000]; /* Filled in by U-Boot */ mal-device = <&MAL0>; mal-tx-channel = <0>; @@ -305,7 +360,7 @@ EMAC1: ethernet@ef600f00 { device_type = "network"; - compatible = "ibm,emac-460gt", "ibm,emac4"; + compatible = "ibm,emac-460gt", "ibm,emac4sync"; interrupt-parent = <&EMAC1>; interrupts = <0x0 0x1>; #interrupt-cells = <1>; @@ -313,7 +368,7 @@ #size-cells = <0>; interrupt-map = ; - reg = <0xef600f00 0x00000074>; + reg = <0xef600f00 0x000000c4>; local-mac-address = [000000000000]; /* Filled in by U-Boot */ mal-device = <&MAL0>; mal-tx-channel = <1>; @@ -336,7 +391,7 @@ EMAC2: ethernet@ef601100 { device_type = "network"; - compatible = "ibm,emac-460gt", "ibm,emac4"; + compatible = "ibm,emac-460gt", "ibm,emac4sync"; interrupt-parent = <&EMAC2>; interrupts = <0x0 0x1>; #interrupt-cells = <1>; @@ -344,7 +399,7 @@ #size-cells = <0>; interrupt-map = ; - reg = <0xef601100 0x00000074>; + reg = <0xef601100 0x000000c4>; local-mac-address = [000000000000]; /* Filled in by U-Boot */ mal-device = <&MAL0>; mal-tx-channel = <2>; @@ -366,7 +421,7 @@ EMAC3: ethernet@ef601200 { device_type = "network"; - compatible = "ibm,emac-460gt", "ibm,emac4"; + compatible = "ibm,emac-460gt", "ibm,emac4sync"; interrupt-parent = <&EMAC3>; interrupts = <0x0 0x1>; #interrupt-cells = <1>; @@ -374,7 +429,7 @@ #size-cells = <0>; interrupt-map = ; - reg = <0xef601200 0x00000074>; + reg = <0xef601200 0x000000c4>; local-mac-address = [000000000000]; /* Filled in by U-Boot */ mal-device = <&MAL0>; mal-tx-channel = <3>; @@ -414,6 +469,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ @@ -444,6 +500,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ @@ -485,6 +542,7 @@ * later cannot be changed */ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; /* Inbound 2GB range starting at 0 */ -- GitLab From 573bff5ab9437b4e59ba9be34a7b08bca5ff054a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 26 Jan 2010 05:53:20 +0000 Subject: [PATCH 1842/3892] powerpc/44x: Add MTD support to katmai defconfig Signed-off-by: Stefan Roese Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/configs/44x/katmai_defconfig | 94 +++++++++++++++++++++-- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig index dec901f9cc84..af244e1d255e 100644 --- a/arch/powerpc/configs/44x/katmai_defconfig +++ b/arch/powerpc/configs/44x/katmai_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc1 -# Mon Jan 4 14:55:34 2010 +# Linux kernel version: 2.6.33-rc5 +# Tue Jan 26 14:40:58 2010 # # CONFIG_PPC64 is not set @@ -106,6 +106,7 @@ CONFIG_INITRAMFS_SOURCE="" CONFIG_RD_GZIP=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y @@ -442,7 +443,90 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_SYS_HYPERVISOR is not set CONFIG_CONNECTOR=y CONFIG_PROC_EVENTS=y -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y @@ -500,7 +584,7 @@ CONFIG_HAVE_IDE=y # # -# See the help texts for more information. +# The newer stack is recommended. # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set @@ -763,7 +847,6 @@ CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XIP is not set # CONFIG_EXT3_FS is not set # CONFIG_EXT4_FS is not set -CONFIG_EXT4_USE_FOR_EXT23=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set @@ -820,6 +903,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set CONFIG_CRAMFS=y # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set -- GitLab From 77f720b71d88a3cbf574c113566a31c93099f97d Mon Sep 17 00:00:00 2001 From: Stephane Chatty Date: Sat, 6 Feb 2010 15:17:13 +0100 Subject: [PATCH 1843/3892] HID: Support for MosArt multitouch panel Added support for MosArt dual-touch panels, present in the Asus T91MT notebook. Signed-off-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 5 +- drivers/hid/hid-ids.h | 9 +- drivers/hid/hid-mosart.c | 274 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+), 5 deletions(-) create mode 100644 drivers/hid/hid-mosart.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 617ed7db67d1..2b93d7f647ee 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -204,6 +204,12 @@ config HID_MICROSOFT ---help--- Support for Microsoft devices that are not fully compliant with HID standard. +config HID_MOSART + tristate "MosArt" + depends on USB_HID + ---help--- + Support for MosArt dual-touch panels. + config HID_MONTEREY tristate "Monterey" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b62d4b3afdc2..03051694d546 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o +obj-$(CONFIG_HID_MOSART) += hid-mosart.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_QUANTA) += hid-quanta.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 282f4a1e7214..da97195474ff 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1550,8 +1550,9 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 282bfe8d95e8..ab370f1c4b6e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -99,9 +99,12 @@ #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -#define USB_VENDOR_ID_ASUS 0x0b05 -#define USB_DEVICE_ID_ASUS_LCM 0x1726 -#define USB_DEVICE_ID_ASUS_LCM2 0x175b +#define USB_VENDOR_ID_ASUS 0x0486 +#define USB_DEVICE_ID_ASUS_T91MT 0x0185 + +#define USB_VENDOR_ID_ASUSTEK 0x0b05 +#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 +#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b #define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c new file mode 100644 index 000000000000..f6ec4f150859 --- /dev/null +++ b/drivers/hid/hid-mosart.c @@ -0,0 +1,274 @@ +/* + * HID driver for the multitouch panel on the ASUS EeePC T91MT + * + * Copyright (c) 2009-2010 Stephane Chatty + * Copyright (c) 2010 Teemu Tuominen + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include "usbhid/usbhid.h" + +MODULE_VERSION("1.00"); +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("MosArt dual-touch panel"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +struct mosart_data { + __u16 x, y; + __u8 id; + bool valid; /* valid finger data, or just placeholder? */ + bool first; /* is this the first finger in this frame? */ + bool activity_now; /* at least one active finger in this frame? */ + bool activity; /* at least one active finger previously? */ +}; + +static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_TIPPRESSURE: + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + return -1; + case HID_DG_INRANGE: + /* touchscreen emulation */ + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + return 1; + + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TRACKING_ID); + return 1; + + } + return 0; + + case 0xff000000: + /* ignore HID features */ + return -1; + } + + return 0; +} + +static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +/* + * this function is called when a whole finger has been parsed, + * so that it can decide what to send to the input layer. + */ +static void mosart_filter_event(struct mosart_data *td, struct input_dev *input) +{ + td->first = !td->first; /* touchscreen emulation */ + + if (!td->valid) { + /* + * touchscreen emulation: if no finger in this frame is valid + * and there previously was finger activity, this is a release + */ + if (!td->first && !td->activity_now && td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 0); + td->activity = false; + } + return; + } + + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); + + input_mt_sync(input); + td->valid = false; + + /* touchscreen emulation: if first active finger in this frame... */ + if (!td->activity_now) { + /* if there was no previous activity, emit touch event */ + if (!td->activity) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + td->activity = true; + } + td->activity_now = true; + /* and in any case this is our preferred finger */ + input_event(input, EV_ABS, ABS_X, td->x); + input_event(input, EV_ABS, ABS_Y, td->y); + } +} + + +static int mosart_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mosart_data *td = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; + switch (usage->hid) { + case HID_DG_INRANGE: + td->valid = !!value; + break; + case HID_GD_X: + td->x = value; + break; + case HID_GD_Y: + td->y = value; + mosart_filter_event(td, input); + break; + case HID_DG_CONTACTID: + td->id = value; + break; + case HID_DG_CONTACTCOUNT: + /* touch emulation: this is the last field in a frame */ + td->first = false; + td->activity_now = false; + break; + case HID_DG_CONFIDENCE: + case HID_DG_TIPSWITCH: + /* avoid interference from generic hidinput handling */ + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mosart_data *td; + + + td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate MosArt data\n"); + return -ENOMEM; + } + td->valid = false; + td->activity = false; + td->activity_now = false; + td->first = false; + hid_set_drvdata(hdev, td); + + /* currently, it's better to have one evdev device only */ +#if 0 + hdev->quirks |= HID_QUIRK_MULTI_INPUT; +#endif + + ret = hid_parse(hdev); + if (ret == 0) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret == 0) { + struct hid_report_enum *re = hdev->report_enum + + HID_FEATURE_REPORT; + struct hid_report *r = re->report_id_hash[7]; + + r->field[0]->value[0] = 0x02; + usbhid_submit_report(hdev, r, USB_DIR_OUT); + } else + kfree(td); + + return ret; +} + +static void mosart_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mosart_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mosart_devices); + +static const struct hid_usage_id mosart_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mosart_driver = { + .name = "mosart", + .id_table = mosart_devices, + .probe = mosart_probe, + .remove = mosart_remove, + .input_mapping = mosart_input_mapping, + .input_mapped = mosart_input_mapped, + .usage_table = mosart_grabbed_usages, + .event = mosart_event, +}; + +static int __init mosart_init(void) +{ + return hid_register_driver(&mosart_driver); +} + +static void __exit mosart_exit(void) +{ + hid_unregister_driver(&mosart_driver); +} + +module_init(mosart_init); +module_exit(mosart_exit); + -- GitLab From 90a006abf8015c8cab893555244d8fc673b24839 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sun, 24 Jan 2010 22:32:29 -0500 Subject: [PATCH 1844/3892] HID: Export hid_register_report The Apple Magic Mouse (and probably other devices) publish reports that are not called out in their HID report descriptors -- they only send them when enabled through other writes to the device. This allows a driver to handle these unlisted reports. Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- include/linux/hid.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f7f80e1f1eef..66a91eb3e4c4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(hid_debug); * Register a new report for a device. */ -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) +struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) { struct hid_report_enum *report_enum = device->report_enum + type; struct hid_report *report; @@ -75,6 +75,7 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne return report; } +EXPORT_SYMBOL_GPL(hid_register_report); /* * Register a new field for this report. diff --git a/include/linux/hid.h b/include/linux/hid.h index 3661a626941d..456838c8884e 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -690,6 +690,7 @@ int hid_input_report(struct hid_device *, int type, u8 *, int, int); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); void hid_output_report(struct hid_report *report, __u8 *data); struct hid_device *hid_allocate_device(void); +struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); int hid_check_keys_pressed(struct hid_device *hid); int hid_connect(struct hid_device *hid, unsigned int connect_mask); -- GitLab From 128537cea464d919febeaea2000e256749f317eb Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sat, 6 Feb 2010 12:24:36 -0500 Subject: [PATCH 1845/3892] HID: add a device driver for the Apple Magic Mouse. The Magic Mouse requires that a driver send an unlock Report(Feature) command, similar to the Wacom wireless tablet and Sixaxis controller quirks. This turns on an Input Report that isn't published in the input Report descriptor that contains touch data (and usually overrides the normal motion and click Report). Because the mouse has only one switch and no scroll wheel, the driver (under control of parameters) emulates a middle button and scroll wheel. User space could also ignore and/or re-synthesize those events based on the reported events. Some user-space tools to talk to the mouse directly (that is, when it is not associated with the host's HIDP stack) are at http://github.com/entrope/linux-magicmouse Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 10 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-magicmouse.c | 469 +++++++++++++++++++++++++++++++++++ 5 files changed, 482 insertions(+) create mode 100644 drivers/hid/hid-magicmouse.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 24d90ea246ce..ba14ec898258 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -183,6 +183,16 @@ config LOGIRUMBLEPAD2_FF Say Y here if you want to enable force feedback support for Logitech Rumblepad 2 devices. +config HID_MAGICMOUSE + tristate "Apple" if EMBEDDED + depends on BT_HIDP + default !EMBEDDED + ---help--- + Support for the Apple Magic Mouse. + + Say Y here if you want support for the multi-touch features of the + Apple Wireless "Magic" Mouse. + config HID_MICROSOFT tristate "Microsoft" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0de2dff5542c..45d81e9cd2de 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o +obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 66a91eb3e4c4..f038422f432c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1254,6 +1254,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 010368e649ed..11e521864abb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -56,6 +56,7 @@ #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 +#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c new file mode 100644 index 000000000000..f94b3e43c5b6 --- /dev/null +++ b/drivers/hid/hid-magicmouse.c @@ -0,0 +1,469 @@ +/* + * Apple "Magic" Wireless Mouse driver + * + * Copyright (c) 2010 Michael Poole + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +static bool emulate_3button = 1; +module_param(emulate_3button, bool, 0644); +MODULE_PARM_DESC(emulate_3button, "Emulate a middle button"); + +static int middle_button_start = -350; +static int middle_button_stop = +350; + +static bool emulate_scroll_wheel = 1; +module_param(emulate_scroll_wheel, bool, 0644); +MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); + +static bool report_touches = 1; +module_param(report_touches, bool, 0644); +MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); + +static bool report_undeciphered = 0; +module_param(report_undeciphered, bool, 0644); +MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); + +#define TOUCH_REPORT_ID 0x29 +/* These definitions are not precise, but they're close enough. (Bits + * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem + * to be some kind of bit mask -- 0x20 may be a near-field reading, + * and 0x40 is actual contact, and 0x10 may be a start/stop or change + * indication.) + */ +#define TOUCH_STATE_MASK 0xf0 +#define TOUCH_STATE_NONE 0x00 +#define TOUCH_STATE_START 0x30 +#define TOUCH_STATE_DRAG 0x40 + +/** + * struct magicmouse_sc - Tracks Magic Mouse-specific data. + * @input: Input device through which we report events. + * @quirks: Currently unused. + * @last_timestamp: Timestamp from most recent (18-bit) touch report + * (units of milliseconds over short windows, but seems to + * increase faster when there are no touches). + * @delta_time: 18-bit difference between the two most recent touch + * reports from the mouse. + * @ntouches: Number of touches in most recent touch report. + * @scroll_accel: Number of consecutive scroll motions. + * @scroll_jiffies: Time of last scroll motion. + * @touches: Most recent data for a touch, indexed by tracking ID. + * @tracking_ids: Mapping of current touch input data to @touches. + */ +struct magicmouse_sc { + struct input_dev *input; + unsigned long quirks; + + int last_timestamp; + int delta_time; + int ntouches; + int scroll_accel; + unsigned long scroll_jiffies; + + struct { + short x; + short y; + short scroll_y; + u8 size; + } touches[16]; + int tracking_ids[16]; +}; + +static int magicmouse_firm_touch(struct magicmouse_sc *msc) +{ + int touch = -1; + int ii; + + /* If there is only one "firm" touch, set touch to its + * tracking ID. + */ + for (ii = 0; ii < msc->ntouches; ii++) { + int idx = msc->tracking_ids[ii]; + if (msc->touches[idx].size < 8) { + /* Ignore this touch. */ + } else if (touch >= 0) { + touch = -1; + break; + } else { + touch = idx; + } + } + + return touch; +} + +static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) +{ + int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | + test_bit(BTN_RIGHT, msc->input->key) << 1 | + test_bit(BTN_MIDDLE, msc->input->key) << 2; + + if (emulate_3button) { + int id; + + /* If some button was pressed before, keep it held + * down. Otherwise, if there's exactly one firm + * touch, use that to override the mouse's guess. + */ + if (state == 0) { + /* The button was released. */ + } else if (last_state != 0) { + state = last_state; + } else if ((id = magicmouse_firm_touch(msc)) >= 0) { + int x = msc->touches[id].x; + if (x < middle_button_start) + state = 1; + else if (x > middle_button_stop) + state = 2; + else + state = 4; + } /* else: we keep the mouse's guess */ + + input_report_key(msc->input, BTN_MIDDLE, state & 4); + } + + input_report_key(msc->input, BTN_LEFT, state & 1); + input_report_key(msc->input, BTN_RIGHT, state & 2); + + if (state != last_state) + msc->scroll_accel = 0; +} + +static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) +{ + struct input_dev *input = msc->input; + __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24; + int misc = tdata[5] | tdata[6] << 8; + int id = (misc >> 6) & 15; + int x = x_y << 12 >> 20; + int y = -(x_y >> 20); + + /* Store tracking ID and other fields. */ + msc->tracking_ids[raw_id] = id; + msc->touches[id].x = x; + msc->touches[id].y = y; + msc->touches[id].size = misc & 63; + + /* If requested, emulate a scroll wheel by detecting small + * vertical touch motions along the middle of the mouse. + */ + if (emulate_scroll_wheel && + middle_button_start < x && x < middle_button_stop) { + static const int accel_profile[] = { + 256, 228, 192, 160, 128, 96, 64, 32, + }; + unsigned long now = jiffies; + int step = msc->touches[id].scroll_y - y; + + /* Reset acceleration after half a second. */ + if (time_after(now, msc->scroll_jiffies + HZ / 2)) + msc->scroll_accel = 0; + + /* Calculate and apply the scroll motion. */ + switch (tdata[7] & TOUCH_STATE_MASK) { + case TOUCH_STATE_START: + msc->touches[id].scroll_y = y; + msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + ARRAY_SIZE(accel_profile) - 1); + break; + case TOUCH_STATE_DRAG: + step = step / accel_profile[msc->scroll_accel]; + if (step != 0) { + msc->touches[id].scroll_y = y; + msc->scroll_jiffies = now; + input_report_rel(input, REL_WHEEL, step); + } + break; + } + } + + /* Generate the input events for this touch. */ + if (report_touches) { + int orientation = (misc >> 10) - 32; + + input_report_abs(input, ABS_MT_TRACKING_ID, id); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); + input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); + input_report_abs(input, ABS_MT_ORIENTATION, orientation); + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + + if (report_undeciphered) { + input_event(input, EV_MSC, MSC_RAW, tdata[7]); + } + + input_mt_sync(input); + } +} + +static int magicmouse_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct magicmouse_sc *msc = hid_get_drvdata(hdev); + struct input_dev *input = msc->input; + int x, y, ts, ii, clicks; + + switch (data[0]) { + case 0x10: + if (size != 6) + return 0; + x = (__s16)(data[2] | data[3] << 8); + y = (__s16)(data[4] | data[5] << 8); + clicks = data[1]; + break; + case TOUCH_REPORT_ID: + /* Expect six bytes of prefix, and N*8 bytes of touch data. */ + if (size < 6 || ((size - 6) % 8) != 0) + return 0; + ts = data[3] >> 6 | data[4] << 2 | data[5] << 10; + msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff; + msc->last_timestamp = ts; + msc->ntouches = (size - 6) / 8; + for (ii = 0; ii < msc->ntouches; ii++) + magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); + /* When emulating three-button mode, it is important + * to have the current touch information before + * generating a click event. + */ + x = (signed char)data[1]; + y = (signed char)data[2]; + clicks = data[3]; + break; + case 0x20: /* Theoretically battery status (0-100), but I have + * never seen it -- maybe it is only upon request. + */ + case 0x60: /* Unknown, maybe laser on/off. */ + case 0x61: /* Laser reflection status change. + * data[1]: 0 = spotted, 1 = lost + */ + default: + return 0; + } + + magicmouse_emit_buttons(msc, clicks & 3); + input_report_rel(input, REL_X, x); + input_report_rel(input, REL_Y, y); + input_sync(input); + return 1; +} + +static int magicmouse_input_open(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + return hid->ll_driver->open(hid); +} + +static void magicmouse_input_close(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + hid->ll_driver->close(hid); +} + +static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) +{ + input_set_drvdata(input, hdev); + input->event = hdev->ll_driver->hidinput_input_event; + input->open = magicmouse_input_open; + input->close = magicmouse_input_close; + + input->name = hdev->name; + input->phys = hdev->phys; + input->uniq = hdev->uniq; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + input->dev.parent = hdev->dev.parent; + + set_bit(EV_KEY, input->evbit); + set_bit(BTN_LEFT, input->keybit); + set_bit(BTN_RIGHT, input->keybit); + if (emulate_3button) + set_bit(BTN_MIDDLE, input->keybit); + set_bit(BTN_TOOL_FINGER, input->keybit); + + set_bit(EV_REL, input->evbit); + set_bit(REL_X, input->relbit); + set_bit(REL_Y, input->relbit); + if (emulate_scroll_wheel) + set_bit(REL_WHEEL, input->relbit); + + if (report_touches) { + set_bit(EV_ABS, input->evbit); + + set_bit(ABS_MT_TRACKING_ID, input->absbit); + input->absmin[ABS_MT_TRACKING_ID] = 0; + input->absmax[ABS_MT_TRACKING_ID] = 15; + input->absfuzz[ABS_MT_TRACKING_ID] = 0; + + set_bit(ABS_MT_TOUCH_MAJOR, input->absbit); + input->absmin[ABS_MT_TOUCH_MAJOR] = 0; + input->absmax[ABS_MT_TOUCH_MAJOR] = 255; + input->absfuzz[ABS_MT_TOUCH_MAJOR] = 4; + + set_bit(ABS_MT_TOUCH_MINOR, input->absbit); + input->absmin[ABS_MT_TOUCH_MINOR] = 0; + input->absmax[ABS_MT_TOUCH_MINOR] = 255; + input->absfuzz[ABS_MT_TOUCH_MINOR] = 4; + + set_bit(ABS_MT_ORIENTATION, input->absbit); + input->absmin[ABS_MT_ORIENTATION] = -32; + input->absmax[ABS_MT_ORIENTATION] = 31; + input->absfuzz[ABS_MT_ORIENTATION] = 1; + + set_bit(ABS_MT_POSITION_X, input->absbit); + input->absmin[ABS_MT_POSITION_X] = -1100; + input->absmax[ABS_MT_POSITION_X] = 1358; + input->absfuzz[ABS_MT_POSITION_X] = 4; + + /* Note: Touch Y position from the device is inverted relative + * to how pointer motion is reported (and relative to how USB + * HID recommends the coordinates work). This driver keeps + * the origin at the same position, and just uses the additive + * inverse of the reported Y. + */ + set_bit(ABS_MT_POSITION_Y, input->absbit); + input->absmin[ABS_MT_POSITION_Y] = -1589; + input->absmax[ABS_MT_POSITION_Y] = 2047; + input->absfuzz[ABS_MT_POSITION_Y] = 4; + } + + if (report_undeciphered) { + set_bit(EV_MSC, input->evbit); + set_bit(MSC_RAW, input->mscbit); + } +} + +static int magicmouse_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + __u8 feature_1[] = { 0xd7, 0x01 }; + __u8 feature_2[] = { 0xf8, 0x01, 0x32 }; + struct input_dev *input; + struct magicmouse_sc *msc; + struct hid_report *report; + int ret; + + msc = kzalloc(sizeof(*msc), GFP_KERNEL); + if (msc == NULL) { + dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n"); + return -ENOMEM; + } + + msc->quirks = id->driver_data; + hid_set_drvdata(hdev, msc); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "magicmouse hid parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "magicmouse hw start failed\n"); + goto err_free; + } + + report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); + if (!report) { + dev_err(&hdev->dev, "unable to register touch report\n"); + ret = -ENOMEM; + goto err_free; + } + report->size = 6; + + ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1), + HID_FEATURE_REPORT); + if (ret != sizeof(feature_1)) { + dev_err(&hdev->dev, "unable to request touch data (1:%d)\n", + ret); + goto err_free; + } + ret = hdev->hid_output_raw_report(hdev, feature_2, + sizeof(feature_2), HID_FEATURE_REPORT); + if (ret != sizeof(feature_2)) { + dev_err(&hdev->dev, "unable to request touch data (2:%d)\n", + ret); + goto err_free; + } + + input = input_allocate_device(); + if (!input) { + dev_err(&hdev->dev, "can't alloc input device\n"); + ret = -ENOMEM; + goto err_free; + } + magicmouse_setup_input(input, hdev); + + ret = input_register_device(input); + if (ret) { + dev_err(&hdev->dev, "input device registration failed\n"); + goto err_both; + } + msc->input = input; + + return 0; + err_both: + input_free_device(input); + err_free: + kfree(msc); + return ret; +} + +static void magicmouse_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + +static const struct hid_device_id magic_mice[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), + .driver_data = 0 }, + { } +}; +MODULE_DEVICE_TABLE(hid, magic_mice); + +static struct hid_driver magicmouse_driver = { + .name = "magicmouse", + .id_table = magic_mice, + .probe = magicmouse_probe, + .remove = magicmouse_remove, + .raw_event = magicmouse_raw_event, +}; + +static int __init magicmouse_init(void) +{ + int ret; + + ret = hid_register_driver(&magicmouse_driver); + if (ret) + printk(KERN_ERR "can't register magicmouse driver\n"); + + return ret; +} + +static void __exit magicmouse_exit(void) +{ + hid_unregister_driver(&magicmouse_driver); +} + +module_init(magicmouse_init); +module_exit(magicmouse_exit); +MODULE_LICENSE("GPL"); -- GitLab From 9f5231472340ebcaf2dec75428b67d5d0d872857 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Feb 2010 14:59:03 +0100 Subject: [PATCH 1846/3892] HID: fix up Kconfig entry for MagicMouse Make Apple MagicMouse Kconfig entry consistent with other dirvers. Also expand the tristate text a little bit more, so that it doesn't clash with already existing HID_APPLE. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ba14ec898258..0e668ccc2511 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -184,11 +184,10 @@ config LOGIRUMBLEPAD2_FF Rumblepad 2 devices. config HID_MAGICMOUSE - tristate "Apple" if EMBEDDED + tristate "Apple MagicMouse multi-touch support" depends on BT_HIDP - default !EMBEDDED ---help--- - Support for the Apple Magic Mouse. + Support for the Apple Magic Mouse multi-touch. Say Y here if you want support for the multi-touch features of the Apple Wireless "Magic" Mouse. -- GitLab From 0a02604628c49037e1de2091d75462fd856b26ed Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 10 Feb 2010 15:00:32 +0100 Subject: [PATCH 1847/3892] netfilter: xtables: consistent struct compat_xt_counters definition There is compat_u64 type which deals with different u64 type alignment on different compat-capable platforms, so use it and removed some hardcoded assumptions. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 365fabe1b16e..8b6c0e7d2657 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -562,11 +562,7 @@ struct compat_xt_entry_target { * current task alignment */ struct compat_xt_counters { -#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) - u_int32_t cnt[4]; -#else - u_int64_t cnt[2]; -#endif + compat_u64 pcnt, bcnt; /* Packet and byte counters */ }; struct compat_xt_counters_info { -- GitLab From 42107f5009da223daa800d6da6904d77297ae829 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 10 Feb 2010 15:03:27 +0100 Subject: [PATCH 1848/3892] netfilter: xtables: symmetric COMPAT_XT_ALIGN definition Rewrite COMPAT_XT_ALIGN in terms of dummy structure hack. Compat counters logically have nothing to do with it. Use ALIGN() macro while I'm at it for same types. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 13 +++++++++---- net/netfilter/x_tables.c | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 8b6c0e7d2657..9d671ebf0605 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -93,8 +93,7 @@ struct _xt_align { __u64 u64; }; -#define XT_ALIGN(s) (((s) + (__alignof__(struct _xt_align)-1)) \ - & ~(__alignof__(struct _xt_align)-1)) +#define XT_ALIGN(s) ALIGN((s), __alignof__(struct _xt_align)) /* Standard return verdict, or do jump. */ #define XT_STANDARD_TARGET "" @@ -571,8 +570,14 @@ struct compat_xt_counters_info { struct compat_xt_counters counters[0]; }; -#define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \ - & ~(__alignof__(struct compat_xt_counters)-1)) +struct _compat_xt_align { + __u8 u8; + __u16 u16; + __u32 u32; + compat_u64 u64; +}; + +#define COMPAT_XT_ALIGN(s) ALIGN((s), __alignof__(struct _compat_xt_align)) extern void xt_compat_lock(u_int8_t af); extern void xt_compat_unlock(u_int8_t af); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index f01955cce314..5c564ff10a3b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -364,7 +364,7 @@ int xt_check_match(struct xt_mtchk_param *par, * ebt_among is exempt from centralized matchsize checking * because it uses a dynamic-size data set. */ - pr_err("%s_tables: %s match: invalid size %Zu != %u\n", + pr_err("%s_tables: %s match: invalid size %u != %u\n", xt_prefix[par->family], par->match->name, XT_ALIGN(par->match->matchsize), size); return -EINVAL; @@ -514,7 +514,7 @@ int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { if (XT_ALIGN(par->target->targetsize) != size) { - pr_err("%s_tables: %s target: invalid size %Zu != %u\n", + pr_err("%s_tables: %s target: invalid size %u != %u\n", xt_prefix[par->family], par->target->name, XT_ALIGN(par->target->targetsize), size); return -EINVAL; -- GitLab From c8a8602b76b6703df1243e31be01cf0e4451e4a6 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Feb 2010 15:29:02 +0100 Subject: [PATCH 1849/3892] HID: remove MODULE_VERSION from new drivers MODULE_VERSION doesn't make too much sense for drivers merged into main tree, as git is much better tracking revisions than any developer might ever be. Signed-off-by: Jiri Kosina --- drivers/hid/hid-3m-pct.c | 1 - drivers/hid/hid-mosart.c | 1 - drivers/hid/hid-quanta.c | 1 - drivers/hid/hid-stantum.c | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index 6d11e3dbbbff..2370aefc86b2 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c @@ -17,7 +17,6 @@ #include #include -MODULE_VERSION("0.6"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("3M PCT multitouch panels"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index f6ec4f150859..c8718168fe42 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -19,7 +19,6 @@ #include #include "usbhid/usbhid.h" -MODULE_VERSION("1.00"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("MosArt dual-touch panel"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c index 9ac49287b943..01dd51c4986c 100644 --- a/drivers/hid/hid-quanta.c +++ b/drivers/hid/hid-quanta.c @@ -16,7 +16,6 @@ #include #include -MODULE_VERSION("1.00"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("Quanta dual-touch panel"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index 04b0b986f5f4..2e592a06654e 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -16,7 +16,6 @@ #include #include -MODULE_VERSION("0.6"); MODULE_AUTHOR("Stephane Chatty "); MODULE_DESCRIPTION("Stantum HID multitouch panels"); MODULE_LICENSE("GPL"); -- GitLab From d0b0268fddea3235a8df35e52167c3b206bf2f5a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 10 Feb 2010 15:38:33 +0100 Subject: [PATCH 1850/3892] netfilter: ctnetlink: add missing netlink attribute policies Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_netlink.c | 41 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 327c5174440c..5c103b8c7df0 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -708,6 +708,11 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, return ret; } +static const struct nla_policy tuple_nla_policy[CTA_TUPLE_MAX+1] = { + [CTA_TUPLE_IP] = { .type = NLA_NESTED }, + [CTA_TUPLE_PROTO] = { .type = NLA_NESTED }, +}; + static int ctnetlink_parse_tuple(const struct nlattr * const cda[], struct nf_conntrack_tuple *tuple, @@ -718,7 +723,7 @@ ctnetlink_parse_tuple(const struct nlattr * const cda[], memset(tuple, 0, sizeof(*tuple)); - nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], NULL); + nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], tuple_nla_policy); if (!tb[CTA_TUPLE_IP]) return -EINVAL; @@ -745,12 +750,16 @@ ctnetlink_parse_tuple(const struct nlattr * const cda[], return 0; } +static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = { + [CTA_HELP_NAME] = { .type = NLA_NUL_STRING }, +}; + static inline int ctnetlink_parse_help(const struct nlattr *attr, char **helper_name) { struct nlattr *tb[CTA_HELP_MAX+1]; - nla_parse_nested(tb, CTA_HELP_MAX, attr, NULL); + nla_parse_nested(tb, CTA_HELP_MAX, attr, help_nla_policy); if (!tb[CTA_HELP_NAME]) return -EINVAL; @@ -761,11 +770,17 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name) } static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { + [CTA_TUPLE_ORIG] = { .type = NLA_NESTED }, + [CTA_TUPLE_REPLY] = { .type = NLA_NESTED }, [CTA_STATUS] = { .type = NLA_U32 }, + [CTA_PROTOINFO] = { .type = NLA_NESTED }, + [CTA_HELP] = { .type = NLA_NESTED }, + [CTA_NAT_SRC] = { .type = NLA_NESTED }, [CTA_TIMEOUT] = { .type = NLA_U32 }, [CTA_MARK] = { .type = NLA_U32 }, - [CTA_USE] = { .type = NLA_U32 }, [CTA_ID] = { .type = NLA_U32 }, + [CTA_NAT_DST] = { .type = NLA_NESTED }, + [CTA_TUPLE_MASTER] = { .type = NLA_NESTED }, }; static int @@ -1053,6 +1068,12 @@ ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) return 0; } +static const struct nla_policy protoinfo_policy[CTA_PROTOINFO_MAX+1] = { + [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED }, + [CTA_PROTOINFO_DCCP] = { .type = NLA_NESTED }, + [CTA_PROTOINFO_SCTP] = { .type = NLA_NESTED }, +}; + static inline int ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[]) { @@ -1061,7 +1082,7 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[] struct nf_conntrack_l4proto *l4proto; int err = 0; - nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); + nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, protoinfo_policy); rcu_read_lock(); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); @@ -1073,12 +1094,18 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[] } #ifdef CONFIG_NF_NAT_NEEDED +static const struct nla_policy nat_seq_policy[CTA_NAT_SEQ_MAX+1] = { + [CTA_NAT_SEQ_CORRECTION_POS] = { .type = NLA_U32 }, + [CTA_NAT_SEQ_OFFSET_BEFORE] = { .type = NLA_U32 }, + [CTA_NAT_SEQ_OFFSET_AFTER] = { .type = NLA_U32 }, +}; + static inline int change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) { struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; - nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, NULL); + nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, nat_seq_policy); if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) return -EINVAL; @@ -1648,8 +1675,12 @@ out: } static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + [CTA_EXPECT_MASTER] = { .type = NLA_NESTED }, + [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED }, + [CTA_EXPECT_MASK] = { .type = NLA_NESTED }, [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 }, [CTA_EXPECT_ID] = { .type = NLA_U32 }, + [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, }; static int -- GitLab From 737535c5cf3524e4bfaa91e22edefd52eccabbce Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 06:46:36 +0200 Subject: [PATCH 1851/3892] netfilter: xtables: compact table hook functions (1/2) This patch combines all the per-hook functions in a given table into a single function. Together with the 2nd patch, further simplifications are possible up to the point of output code reduction. Signed-off-by: Jan Engelhardt --- net/ipv4/netfilter/arptable_filter.c | 30 +++++------ net/ipv4/netfilter/iptable_filter.c | 50 ++++++------------ net/ipv4/netfilter/iptable_mangle.c | 71 ++++++++------------------ net/ipv4/netfilter/iptable_raw.c | 26 ++++------ net/ipv4/netfilter/iptable_security.c | 50 ++++++------------ net/ipv6/netfilter/ip6table_filter.c | 40 ++++----------- net/ipv6/netfilter/ip6table_mangle.c | 50 ++++++++---------- net/ipv6/netfilter/ip6table_raw.c | 26 ++++------ net/ipv6/netfilter/ip6table_security.c | 41 ++++----------- 9 files changed, 126 insertions(+), 258 deletions(-) diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 97337601827a..e9d823b149cd 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -53,43 +53,37 @@ static const struct xt_table packet_filter = { }; /* The work comes in here from netfilter.c */ -static unsigned int arpt_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +static unsigned int +arptable_filter_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return arpt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.arptable_filter); -} + if (hook == NF_ARP_OUT) + return arpt_do_table(skb, hook, in, out, + dev_net(out)->ipv4.arptable_filter); -static unsigned int arpt_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ + /* INPUT/FORWARD: */ return arpt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.arptable_filter); + dev_net(in)->ipv4.arptable_filter); } static struct nf_hook_ops arpt_ops[] __read_mostly = { { - .hook = arpt_in_hook, + .hook = arptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_ARP, .hooknum = NF_ARP_IN, .priority = NF_IP_PRI_FILTER, }, { - .hook = arpt_out_hook, + .hook = arptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_ARP, .hooknum = NF_ARP_OUT, .priority = NF_IP_PRI_FILTER, }, { - .hook = arpt_in_hook, + .hook = arptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_ARP, .hooknum = NF_ARP_FORWARD, diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index dee90eb8aa47..5369833ad56a 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -60,61 +60,43 @@ static const struct xt_table packet_filter = { .af = NFPROTO_IPV4, }; -/* The work comes in here from netfilter.c. */ static unsigned int -ipt_local_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +iptable_filter_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_filter); -} + if (hook == NF_INET_LOCAL_OUT) { + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) + /* root is playing with raw sockets. */ + return NF_ACCEPT; + + return ipt_do_table(skb, hook, in, out, + dev_net(out)->ipv4.iptable_filter); + } -static unsigned int -ipt_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ + /* LOCAL_IN/FORWARD: */ return ipt_do_table(skb, hook, in, out, dev_net(in)->ipv4.iptable_filter); } -static unsigned int -ipt_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) - return NF_ACCEPT; - return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_filter); -} - static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_local_in_hook, + .hook = iptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_FILTER, }, { - .hook = ipt_hook, + .hook = iptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_FILTER, }, { - .hook = ipt_local_out_hook, + .hook = iptable_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index e07bf242343a..4e699cd275c6 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -71,51 +71,6 @@ static const struct xt_table packet_mangler = { .af = NFPROTO_IPV4, }; -/* The work comes in here from netfilter.c. */ -static unsigned int -ipt_pre_routing_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_mangle); -} - -static unsigned int -ipt_post_routing_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_mangle); -} - -static unsigned int -ipt_local_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_mangle); -} - -static unsigned int -ipt_forward_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_mangle); -} - static unsigned int ipt_local_hook(unsigned int hook, struct sk_buff *skb, @@ -158,37 +113,53 @@ ipt_local_hook(unsigned int hook, return ret; } +/* The work comes in here from netfilter.c. */ +static unsigned int +iptable_mangle_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + if (hook == NF_INET_LOCAL_OUT) + return ipt_local_hook(hook, skb, in, out, okfn); + + /* PREROUTING/INPUT/FORWARD: */ + return ipt_do_table(skb, hook, in, out, + dev_net(in)->ipv4.iptable_mangle); +} + static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_pre_routing_hook, + .hook = iptable_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_local_in_hook, + .hook = iptable_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_forward_hook, + .hook = iptable_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_local_hook, + .hook = iptable_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_post_routing_hook, + .hook = iptable_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_POST_ROUTING, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 40f2b9f611a2..2c55575e89f5 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -45,23 +45,15 @@ static const struct xt_table packet_raw = { /* The work comes in here from netfilter.c. */ static unsigned int -ipt_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +iptable_raw_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_raw); -} + if (hook == NF_INET_PRE_ROUTING) + return ipt_do_table(skb, hook, in, out, + dev_net(in)->ipv4.iptable_raw); -static unsigned int -ipt_local_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ + /* OUTPUT: */ /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) @@ -73,14 +65,14 @@ ipt_local_hook(unsigned int hook, /* 'raw' is the very first table. */ static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_hook, + .hook = iptable_raw_hook, .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_RAW, .owner = THIS_MODULE, }, { - .hook = ipt_local_hook, + .hook = iptable_raw_hook, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_RAW, diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 7ce2366e4305..1c666bab3269 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -65,59 +65,43 @@ static const struct xt_table security_table = { }; static unsigned int -ipt_local_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +iptable_security_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_security); -} + if (hook == NF_INET_LOCAL_OUT) { + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) + /* Somebody is playing with raw sockets. */ + return NF_ACCEPT; -static unsigned int -ipt_forward_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_security); -} + return ipt_do_table(skb, hook, in, out, + dev_net(out)->ipv4.iptable_security); + } -static unsigned int -ipt_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - /* Somebody is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) - return NF_ACCEPT; + /* INPUT/FORWARD: */ return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_security); + dev_net(in)->ipv4.iptable_security); } static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_local_in_hook, + .hook = iptable_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_SECURITY, }, { - .hook = ipt_forward_hook, + .hook = iptable_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_SECURITY, }, { - .hook = ipt_local_out_hook, + .hook = iptable_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 33ddfe53e18d..38074e933f67 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -60,54 +60,36 @@ static const struct xt_table packet_filter = { /* The work comes in here from netfilter.c. */ static unsigned int -ip6t_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_filter); -} - -static unsigned int -ip6t_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ -#if 0 - /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) { - if (net_ratelimit()) - printk("ip6t_hook: happy cracking.\n"); - return NF_ACCEPT; - } -#endif + if (hook == NF_INET_LOCAL_OUT) + return ip6t_do_table(skb, hook, in, out, + dev_net(out)->ipv6.ip6table_filter); + /* INPUT/FORWARD: */ return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_filter); + dev_net(in)->ipv6.ip6table_filter); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_in_hook, + .hook = ip6table_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_FILTER, }, { - .hook = ip6t_in_hook, + .hook = ip6table_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_FILTER, }, { - .hook = ip6t_local_out_hook, + .hook = ip6table_filter_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 9bc483f000e5..405ac1f76390 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -64,33 +64,9 @@ static const struct xt_table packet_mangler = { .af = NFPROTO_IPV6, }; -/* The work comes in here from netfilter.c. */ -static unsigned int -ip6t_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_mangle); -} - -static unsigned int -ip6t_post_routing_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_mangle); -} - static unsigned int ip6t_local_out_hook(unsigned int hook, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { @@ -119,7 +95,7 @@ ip6t_local_out_hook(unsigned int hook, /* flowlabel and prio (includes version, which shouldn't change either */ flowlabel = *((u_int32_t *)ipv6_hdr(skb)); - ret = ip6t_do_table(skb, hook, in, out, + ret = ip6t_do_table(skb, hook, NULL, out, dev_net(out)->ipv6.ip6table_mangle); if (ret != NF_DROP && ret != NF_STOLEN && @@ -132,37 +108,51 @@ ip6t_local_out_hook(unsigned int hook, return ret; } +/* The work comes in here from netfilter.c. */ +static unsigned int +ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + if (hook == NF_INET_LOCAL_OUT) + return ip6t_local_out_hook(hook, skb, out, okfn); + + /* INPUT/FORWARD */ + return ip6t_do_table(skb, hook, in, out, + dev_net(in)->ipv6.ip6table_mangle); +} + static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_in_hook, + .hook = ip6table_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_MANGLE, }, { - .hook = ip6t_in_hook, + .hook = ip6table_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_MANGLE, }, { - .hook = ip6t_in_hook, + .hook = ip6table_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_MANGLE, }, { - .hook = ip6t_local_out_hook, + .hook = ip6table_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_MANGLE, }, { - .hook = ip6t_post_routing_hook, + .hook = ip6table_mangle_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_POST_ROUTING, diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 4c90b552e433..985e27cf1e0c 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -44,37 +44,29 @@ static const struct xt_table packet_raw = { /* The work comes in here from netfilter.c. */ static unsigned int -ip6t_pre_routing_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_raw); -} + if (hook == NF_INET_PRE_ROUTING) + return ip6t_do_table(skb, hook, in, out, + dev_net(in)->ipv6.ip6table_raw); -static unsigned int -ip6t_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ + /* OUTPUT: */ return ip6t_do_table(skb, hook, in, out, dev_net(out)->ipv6.ip6table_raw); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_pre_routing_hook, + .hook = ip6table_raw_hook, .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_FIRST, .owner = THIS_MODULE, }, { - .hook = ip6t_local_out_hook, + .hook = ip6table_raw_hook, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_FIRST, diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index baa8d4ef3b0a..835858929358 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -64,56 +64,37 @@ static const struct xt_table security_table = { }; static unsigned int -ip6t_local_in_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ip6table_security_hook(unsigned int hook, struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) { - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_security); -} + if (hook == NF_INET_LOCAL_OUT) + return ip6t_do_table(skb, hook, in, out, + dev_net(out)->ipv6.ip6table_security); -static unsigned int -ip6t_forward_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ + /* INPUT/FORWARD: */ return ip6t_do_table(skb, hook, in, out, dev_net(in)->ipv6.ip6table_security); } -static unsigned int -ip6t_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - /* TBD: handle short packets via raw socket */ - return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_security); -} - static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_local_in_hook, + .hook = ip6table_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_SECURITY, }, { - .hook = ip6t_forward_hook, + .hook = ip6table_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_SECURITY, }, { - .hook = ip6t_local_out_hook, + .hook = ip6table_security_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, -- GitLab From 2b21e051472fdb4680076278b2ccf63ebc1cc3bc Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 06:57:10 +0200 Subject: [PATCH 1852/3892] netfilter: xtables: compact table hook functions (2/2) The calls to ip6t_do_table only show minimal differences, so it seems like a good cleanup to merge them to a single one too. Space saving obtained by both patches: 6807725->6807373 ("Total" column from `size -A`.) Signed-off-by: Jan Engelhardt --- net/ipv4/netfilter/arptable_filter.c | 8 ++------ net/ipv4/netfilter/iptable_filter.c | 21 +++++++++------------ net/ipv4/netfilter/iptable_raw.c | 19 +++++++++---------- net/ipv4/netfilter/iptable_security.c | 23 ++++++++++------------- net/ipv6/netfilter/ip6table_filter.c | 8 ++------ net/ipv6/netfilter/ip6table_raw.c | 8 ++------ net/ipv6/netfilter/ip6table_security.c | 8 ++------ 7 files changed, 36 insertions(+), 59 deletions(-) diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index e9d823b149cd..deeda9b2cf05 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -58,13 +58,9 @@ arptable_filter_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_ARP_OUT) - return arpt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.arptable_filter); + const struct net *net = dev_net((in != NULL) ? in : out); - /* INPUT/FORWARD: */ - return arpt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.arptable_filter); + return arpt_do_table(skb, hook, in, out, net->ipv4.arptable_filter); } static struct nf_hook_ops arpt_ops[] __read_mostly = { diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 5369833ad56a..1bfeaae6f624 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -65,19 +65,16 @@ iptable_filter_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_LOCAL_OUT) { - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) - /* root is playing with raw sockets. */ - return NF_ACCEPT; - - return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_filter); - } + const struct net *net; + + if (hook == NF_INET_LOCAL_OUT && + (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr))) + /* root is playing with raw sockets. */ + return NF_ACCEPT; - /* LOCAL_IN/FORWARD: */ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_filter); + net = dev_net((in != NULL) ? in : out); + return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_filter); } static struct nf_hook_ops ipt_ops[] __read_mostly = { diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 2c55575e89f5..d16e43777c31 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -49,17 +49,16 @@ iptable_raw_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_PRE_ROUTING) - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_raw); - - /* OUTPUT: */ - /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) + const struct net *net; + + if (hook == NF_INET_LOCAL_OUT && + (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr))) + /* root is playing with raw sockets. */ return NF_ACCEPT; - return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_raw); + + net = dev_net((in != NULL) ? in : out); + return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_raw); } /* 'raw' is the very first table. */ diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 1c666bab3269..324505aaaa73 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -70,19 +70,16 @@ iptable_security_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_LOCAL_OUT) { - if (skb->len < sizeof(struct iphdr) || - ip_hdrlen(skb) < sizeof(struct iphdr)) - /* Somebody is playing with raw sockets. */ - return NF_ACCEPT; - - return ipt_do_table(skb, hook, in, out, - dev_net(out)->ipv4.iptable_security); - } - - /* INPUT/FORWARD: */ - return ipt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.iptable_security); + const struct net *net; + + if (hook == NF_INET_LOCAL_OUT && + (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr))) + /* Somebody is playing with raw sockets. */ + return NF_ACCEPT; + + net = dev_net((in != NULL) ? in : out); + return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_security); } static struct nf_hook_ops ipt_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 38074e933f67..866f34ae236b 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -64,13 +64,9 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_LOCAL_OUT) - return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_filter); + const struct net *net = dev_net((in != NULL) ? in : out); - /* INPUT/FORWARD: */ - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_filter); + return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 985e27cf1e0c..5451a36fbc21 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -48,13 +48,9 @@ ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_PRE_ROUTING) - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_raw); + const struct net *net = dev_net((in != NULL) ? in : out); - /* OUTPUT: */ - return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_raw); + return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 835858929358..841ea77f5218 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -69,13 +69,9 @@ ip6table_security_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (hook == NF_INET_LOCAL_OUT) - return ip6t_do_table(skb, hook, in, out, - dev_net(out)->ipv6.ip6table_security); + const struct net *net = dev_net((in != NULL) ? in : out); - /* INPUT/FORWARD: */ - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_security); + return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); } static struct nf_hook_ops ip6t_ops[] __read_mostly = { -- GitLab From 2b95efe7f6bb750256a702cc32d33b0cb2cd8223 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 17 Jun 2009 13:57:48 +0200 Subject: [PATCH 1853/3892] netfilter: xtables: use xt_table for hook instantiation The respective xt_table structures already have most of the metadata needed for hook setup. Add a 'priority' field to struct xt_table so that xt_hook_link() can be called with a reduced number of arguments. So should we be having more tables in the future, it comes at no static cost (only runtime, as before) - space saved: 6807373->6806555. Signed-off-by: Jan Engelhardt --- include/linux/netfilter/x_tables.h | 4 ++ net/ipv4/netfilter/arptable_filter.c | 33 ++++------------ net/ipv4/netfilter/iptable_filter.c | 33 ++++------------ net/ipv4/netfilter/iptable_mangle.c | 47 ++++------------------ net/ipv4/netfilter/iptable_raw.c | 27 ++++--------- net/ipv4/netfilter/iptable_security.c | 33 ++++------------ net/ipv6/netfilter/ip6table_filter.c | 33 ++++------------ net/ipv6/netfilter/ip6table_mangle.c | 48 ++++------------------- net/ipv6/netfilter/ip6table_raw.c | 26 ++++--------- net/ipv6/netfilter/ip6table_security.c | 33 ++++------------ net/netfilter/x_tables.c | 54 ++++++++++++++++++++++++++ 11 files changed, 121 insertions(+), 250 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 365fabe1b16e..fdd3342c1235 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -361,6 +361,7 @@ struct xt_table { struct module *me; u_int8_t af; /* address/protocol family */ + int priority; /* hook order */ /* A unique name... */ const char name[XT_TABLE_MAXNAMELEN]; @@ -522,6 +523,9 @@ static inline unsigned long ifname_compare_aligned(const char *_a, return ret; } +extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *); +extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *); + #ifdef CONFIG_COMPAT #include diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index deeda9b2cf05..b361de0dac4c 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -50,6 +50,7 @@ static const struct xt_table packet_filter = { .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_ARP, + .priority = NF_IP_PRI_FILTER, }; /* The work comes in here from netfilter.c */ @@ -63,29 +64,7 @@ arptable_filter_hook(unsigned int hook, struct sk_buff *skb, return arpt_do_table(skb, hook, in, out, net->ipv4.arptable_filter); } -static struct nf_hook_ops arpt_ops[] __read_mostly = { - { - .hook = arptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_ARP, - .hooknum = NF_ARP_IN, - .priority = NF_IP_PRI_FILTER, - }, - { - .hook = arptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_ARP, - .hooknum = NF_ARP_OUT, - .priority = NF_IP_PRI_FILTER, - }, - { - .hook = arptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_ARP, - .hooknum = NF_ARP_FORWARD, - .priority = NF_IP_PRI_FILTER, - }, -}; +static struct nf_hook_ops *arpfilter_ops __read_mostly; static int __net_init arptable_filter_net_init(struct net *net) { @@ -115,9 +94,11 @@ static int __init arptable_filter_init(void) if (ret < 0) return ret; - ret = nf_register_hooks(arpt_ops, ARRAY_SIZE(arpt_ops)); - if (ret < 0) + arpfilter_ops = xt_hook_link(&packet_filter, arptable_filter_hook); + if (IS_ERR(arpfilter_ops)) { + ret = PTR_ERR(arpfilter_ops); goto cleanup_table; + } return ret; cleanup_table: @@ -127,7 +108,7 @@ cleanup_table: static void __exit arptable_filter_fini(void) { - nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops)); + xt_hook_unlink(&packet_filter, arpfilter_ops); unregister_pernet_subsys(&arptable_filter_net_ops); } diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 1bfeaae6f624..c14bb85db1d9 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -58,6 +58,7 @@ static const struct xt_table packet_filter = { .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_FILTER, }; static unsigned int @@ -77,29 +78,7 @@ iptable_filter_hook(unsigned int hook, struct sk_buff *skb, return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_filter); } -static struct nf_hook_ops ipt_ops[] __read_mostly = { - { - .hook = iptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_FILTER, - }, - { - .hook = iptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP_PRI_FILTER, - }, - { - .hook = iptable_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_FILTER, - }, -}; +static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ static int forward = NF_ACCEPT; @@ -142,9 +121,11 @@ static int __init iptable_filter_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - if (ret < 0) + filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook); + if (IS_ERR(filter_ops)) { + ret = PTR_ERR(filter_ops); goto cleanup_table; + } return ret; @@ -155,7 +136,7 @@ static int __init iptable_filter_init(void) static void __exit iptable_filter_fini(void) { - nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + xt_hook_unlink(&packet_filter, filter_ops); unregister_pernet_subsys(&iptable_filter_net_ops); } diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 4e699cd275c6..2355a229f8ee 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -69,6 +69,7 @@ static const struct xt_table packet_mangler = { .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_MANGLE, }; static unsigned int @@ -129,43 +130,7 @@ iptable_mangle_hook(unsigned int hook, dev_net(in)->ipv4.iptable_mangle); } -static struct nf_hook_ops ipt_ops[] __read_mostly = { - { - .hook = iptable_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP_PRI_MANGLE, - }, - { - .hook = iptable_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_MANGLE, - }, - { - .hook = iptable_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP_PRI_MANGLE, - }, - { - .hook = iptable_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_MANGLE, - }, - { - .hook = iptable_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_MANGLE, - }, -}; +static struct nf_hook_ops *mangle_ops __read_mostly; static int __net_init iptable_mangle_net_init(struct net *net) { @@ -196,9 +161,11 @@ static int __init iptable_mangle_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - if (ret < 0) + mangle_ops = xt_hook_link(&packet_mangler, iptable_mangle_hook); + if (IS_ERR(mangle_ops)) { + ret = PTR_ERR(mangle_ops); goto cleanup_table; + } return ret; @@ -209,7 +176,7 @@ static int __init iptable_mangle_init(void) static void __exit iptable_mangle_fini(void) { - nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + xt_hook_unlink(&packet_mangler, mangle_ops); unregister_pernet_subsys(&iptable_mangle_net_ops); } diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index d16e43777c31..62a99154f14c 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -41,6 +41,7 @@ static const struct xt_table packet_raw = { .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_RAW, }; /* The work comes in here from netfilter.c. */ @@ -61,23 +62,7 @@ iptable_raw_hook(unsigned int hook, struct sk_buff *skb, return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_raw); } -/* 'raw' is the very first table. */ -static struct nf_hook_ops ipt_ops[] __read_mostly = { - { - .hook = iptable_raw_hook, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP_PRI_RAW, - .owner = THIS_MODULE, - }, - { - .hook = iptable_raw_hook, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_RAW, - .owner = THIS_MODULE, - }, -}; +static struct nf_hook_ops *rawtable_ops __read_mostly; static int __net_init iptable_raw_net_init(struct net *net) { @@ -108,9 +93,11 @@ static int __init iptable_raw_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - if (ret < 0) + rawtable_ops = xt_hook_link(&packet_raw, iptable_raw_hook); + if (IS_ERR(rawtable_ops)) { + ret = PTR_ERR(rawtable_ops); goto cleanup_table; + } return ret; @@ -121,7 +108,7 @@ static int __init iptable_raw_init(void) static void __exit iptable_raw_fini(void) { - nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + xt_hook_unlink(&packet_raw, rawtable_ops); unregister_pernet_subsys(&iptable_raw_net_ops); } diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 324505aaaa73..b1bf3ca2c6c7 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -62,6 +62,7 @@ static const struct xt_table security_table = { .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_SECURITY, }; static unsigned int @@ -82,29 +83,7 @@ iptable_security_hook(unsigned int hook, struct sk_buff *skb, return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_security); } -static struct nf_hook_ops ipt_ops[] __read_mostly = { - { - .hook = iptable_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_SECURITY, - }, - { - .hook = iptable_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP_PRI_SECURITY, - }, - { - .hook = iptable_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV4, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_SECURITY, - }, -}; +static struct nf_hook_ops *sectbl_ops __read_mostly; static int __net_init iptable_security_net_init(struct net *net) { @@ -135,9 +114,11 @@ static int __init iptable_security_init(void) if (ret < 0) return ret; - ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - if (ret < 0) + sectbl_ops = xt_hook_link(&security_table, iptable_security_hook); + if (IS_ERR(sectbl_ops)) { + ret = PTR_ERR(sectbl_ops); goto cleanup_table; + } return ret; @@ -148,7 +129,7 @@ cleanup_table: static void __exit iptable_security_fini(void) { - nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); + xt_hook_unlink(&security_table, sectbl_ops); unregister_pernet_subsys(&iptable_security_net_ops); } diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 866f34ae236b..6e95d0614ca9 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -56,6 +56,7 @@ static const struct xt_table packet_filter = { .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_FILTER, }; /* The work comes in here from netfilter.c. */ @@ -69,29 +70,7 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); } -static struct nf_hook_ops ip6t_ops[] __read_mostly = { - { - .hook = ip6table_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP6_PRI_FILTER, - }, - { - .hook = ip6table_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP6_PRI_FILTER, - }, - { - .hook = ip6table_filter_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP6_PRI_FILTER, - }, -}; +static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ static int forward = NF_ACCEPT; @@ -134,9 +113,11 @@ static int __init ip6table_filter_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); - if (ret < 0) + filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook); + if (IS_ERR(filter_ops)) { + ret = PTR_ERR(filter_ops); goto cleanup_table; + } return ret; @@ -147,7 +128,7 @@ static int __init ip6table_filter_init(void) static void __exit ip6table_filter_fini(void) { - nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + xt_hook_unlink(&packet_filter, filter_ops); unregister_pernet_subsys(&ip6table_filter_net_ops); } diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 405ac1f76390..5023ac52ffec 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -62,6 +62,7 @@ static const struct xt_table packet_mangler = { .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_MANGLE, }; static unsigned int @@ -122,44 +123,7 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, dev_net(in)->ipv6.ip6table_mangle); } -static struct nf_hook_ops ip6t_ops[] __read_mostly = { - { - .hook = ip6table_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP6_PRI_MANGLE, - }, - { - .hook = ip6table_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP6_PRI_MANGLE, - }, - { - .hook = ip6table_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP6_PRI_MANGLE, - }, - { - .hook = ip6table_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP6_PRI_MANGLE, - }, - { - .hook = ip6table_mangle_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP6_PRI_MANGLE, - }, -}; - +static struct nf_hook_ops *mangle_ops __read_mostly; static int __net_init ip6table_mangle_net_init(struct net *net) { /* Register table */ @@ -189,9 +153,11 @@ static int __init ip6table_mangle_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); - if (ret < 0) + mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook); + if (IS_ERR(mangle_ops)) { + ret = PTR_ERR(mangle_ops); goto cleanup_table; + } return ret; @@ -202,7 +168,7 @@ static int __init ip6table_mangle_init(void) static void __exit ip6table_mangle_fini(void) { - nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + xt_hook_unlink(&packet_mangler, mangle_ops); unregister_pernet_subsys(&ip6table_mangle_net_ops); } diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 5451a36fbc21..3bfa69511641 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -40,6 +40,7 @@ static const struct xt_table packet_raw = { .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_FIRST, }; /* The work comes in here from netfilter.c. */ @@ -53,22 +54,7 @@ ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); } -static struct nf_hook_ops ip6t_ops[] __read_mostly = { - { - .hook = ip6table_raw_hook, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP6_PRI_FIRST, - .owner = THIS_MODULE, - }, - { - .hook = ip6table_raw_hook, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP6_PRI_FIRST, - .owner = THIS_MODULE, - }, -}; +static struct nf_hook_ops *rawtable_ops __read_mostly; static int __net_init ip6table_raw_net_init(struct net *net) { @@ -99,9 +85,11 @@ static int __init ip6table_raw_init(void) return ret; /* Register hooks */ - ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); - if (ret < 0) + rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook); + if (IS_ERR(rawtable_ops)) { + ret = PTR_ERR(rawtable_ops); goto cleanup_table; + } return ret; @@ -112,7 +100,7 @@ static int __init ip6table_raw_init(void) static void __exit ip6table_raw_fini(void) { - nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + xt_hook_unlink(&packet_raw, rawtable_ops); unregister_pernet_subsys(&ip6table_raw_net_ops); } diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 841ea77f5218..dd2200f17a6c 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -61,6 +61,7 @@ static const struct xt_table security_table = { .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_SECURITY, }; static unsigned int @@ -74,29 +75,7 @@ ip6table_security_hook(unsigned int hook, struct sk_buff *skb, return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); } -static struct nf_hook_ops ip6t_ops[] __read_mostly = { - { - .hook = ip6table_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP6_PRI_SECURITY, - }, - { - .hook = ip6table_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_FORWARD, - .priority = NF_IP6_PRI_SECURITY, - }, - { - .hook = ip6table_security_hook, - .owner = THIS_MODULE, - .pf = NFPROTO_IPV6, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP6_PRI_SECURITY, - }, -}; +static struct nf_hook_ops *sectbl_ops __read_mostly; static int __net_init ip6table_security_net_init(struct net *net) { @@ -127,9 +106,11 @@ static int __init ip6table_security_init(void) if (ret < 0) return ret; - ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); - if (ret < 0) + sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook); + if (IS_ERR(sectbl_ops)) { + ret = PTR_ERR(sectbl_ops); goto cleanup_table; + } return ret; @@ -140,7 +121,7 @@ cleanup_table: static void __exit ip6table_security_fini(void) { - nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); + xt_hook_unlink(&security_table, sectbl_ops); unregister_pernet_subsys(&ip6table_security_net_ops); } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index f01955cce314..b51cb0d7234a 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1091,6 +1091,60 @@ static const struct file_operations xt_target_ops = { #endif /* CONFIG_PROC_FS */ +/** + * xt_hook_link - set up hooks for a new table + * @table: table with metadata needed to set up hooks + * @fn: Hook function + * + * This function will take care of creating and registering the necessary + * Netfilter hooks for XT tables. + */ +struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn) +{ + unsigned int hook_mask = table->valid_hooks; + uint8_t i, num_hooks = hweight32(hook_mask); + uint8_t hooknum; + struct nf_hook_ops *ops; + int ret; + + ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); + if (ops == NULL) + return ERR_PTR(-ENOMEM); + + for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0; + hook_mask >>= 1, ++hooknum) { + if (!(hook_mask & 1)) + continue; + ops[i].hook = fn; + ops[i].owner = table->me; + ops[i].pf = table->af; + ops[i].hooknum = hooknum; + ops[i].priority = table->priority; + ++i; + } + + ret = nf_register_hooks(ops, num_hooks); + if (ret < 0) { + kfree(ops); + return ERR_PTR(ret); + } + + return ops; +} +EXPORT_SYMBOL_GPL(xt_hook_link); + +/** + * xt_hook_unlink - remove hooks for a table + * @ops: nf_hook_ops array as returned by nf_hook_link + * @hook_mask: the very same mask that was passed to nf_hook_link + */ +void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops) +{ + nf_unregister_hooks(ops, hweight32(table->valid_hooks)); + kfree(ops); +} +EXPORT_SYMBOL_GPL(xt_hook_unlink); + int xt_proto_init(struct net *net, u_int8_t af) { #ifdef CONFIG_PROC_FS -- GitLab From e3eaa9910b380530cfd2c0670fcd3f627674da8a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 17 Jun 2009 22:14:54 +0200 Subject: [PATCH 1854/3892] netfilter: xtables: generate initial table on-demand The static initial tables are pretty large, and after the net namespace has been instantiated, they just hang around for nothing. This commit removes them and creates tables on-demand at runtime when needed. Size shrinks by 7735 bytes (x86_64). Signed-off-by: Jan Engelhardt --- include/linux/netfilter_arp/arp_tables.h | 1 + include/linux/netfilter_ipv4/ip_tables.h | 1 + include/linux/netfilter_ipv6/ip6_tables.h | 1 + net/ipv4/netfilter/arp_tables.c | 7 ++++ net/ipv4/netfilter/arptable_filter.c | 40 ++++---------------- net/ipv4/netfilter/ip_tables.c | 7 ++++ net/ipv4/netfilter/iptable_filter.c | 46 ++++++----------------- net/ipv4/netfilter/iptable_mangle.c | 46 ++++------------------- net/ipv4/netfilter/iptable_raw.c | 36 ++++-------------- net/ipv4/netfilter/iptable_security.c | 39 ++++--------------- net/ipv4/netfilter/nf_nat_rule.c | 39 ++++--------------- net/ipv6/netfilter/ip6_tables.c | 7 ++++ net/ipv6/netfilter/ip6table_filter.c | 46 ++++++----------------- net/ipv6/netfilter/ip6table_mangle.c | 45 ++++------------------ net/ipv6/netfilter/ip6table_raw.c | 36 ++++-------------- net/ipv6/netfilter/ip6table_security.c | 39 ++++--------------- net/netfilter/x_tables.c | 4 +- net/netfilter/xt_repldata.h | 35 +++++++++++++++++ 18 files changed, 141 insertions(+), 334 deletions(-) create mode 100644 net/netfilter/xt_repldata.h diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index f2336523a9df..0b33980611b2 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -258,6 +258,7 @@ struct arpt_error { .target.errorname = "ERROR", \ } +extern void *arpt_alloc_initial_table(const struct xt_table *); extern struct xt_table *arpt_register_table(struct net *net, const struct xt_table *table, const struct arpt_replace *repl); diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 8d1f273d350b..364973b42133 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -282,6 +282,7 @@ struct ipt_error { .target.errorname = "ERROR", \ } +extern void *ipt_alloc_initial_table(const struct xt_table *); extern unsigned int ipt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index d2952d2fa658..8031eb486a10 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -297,6 +297,7 @@ ip6t_get_target(struct ip6t_entry *e) #include extern void ip6t_init(void) __init; +extern void *ip6t_alloc_initial_table(const struct xt_table *); extern struct xt_table *ip6t_register_table(struct net *net, const struct xt_table *table, const struct ip6t_replace *repl); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 90203e1b9187..72723ea1054b 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -27,6 +27,7 @@ #include #include +#include "../../netfilter/xt_repldata.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("David S. Miller "); @@ -58,6 +59,12 @@ do { \ #define ARP_NF_ASSERT(x) #endif +void *arpt_alloc_initial_table(const struct xt_table *info) +{ + return xt_alloc_initial_table(arpt, ARPT); +} +EXPORT_SYMBOL_GPL(arpt_alloc_initial_table); + static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, const char *hdr_addr, int len) { diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index b361de0dac4c..bfe26f32b930 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -6,6 +6,7 @@ */ #include +#include #include MODULE_LICENSE("GPL"); @@ -15,36 +16,6 @@ MODULE_DESCRIPTION("arptables filter table"); #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ (1 << NF_ARP_FORWARD)) -static const struct -{ - struct arpt_replace repl; - struct arpt_standard entries[3]; - struct arpt_error term; -} initial_table __net_initdata = { - .repl = { - .name = "filter", - .valid_hooks = FILTER_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), - .hook_entry = { - [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard), - [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), - }, - .underflow = { - [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard), - [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), - }, - }, - .entries = { - ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_IN */ - ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_OUT */ - ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_FORWARD */ - }, - .term = ARPT_ERROR_INIT, -}; - static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, @@ -68,9 +39,14 @@ static struct nf_hook_ops *arpfilter_ops __read_mostly; static int __net_init arptable_filter_net_init(struct net *net) { - /* Register table */ + struct arpt_replace *repl; + + repl = arpt_alloc_initial_table(&packet_filter); + if (repl == NULL) + return -ENOMEM; net->ipv4.arptable_filter = - arpt_register_table(net, &packet_filter, &initial_table.repl); + arpt_register_table(net, &packet_filter, repl); + kfree(repl); if (IS_ERR(net->ipv4.arptable_filter)) return PTR_ERR(net->ipv4.arptable_filter); return 0; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 5bf7de1527a5..2057b1bb6178 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -28,6 +28,7 @@ #include #include #include +#include "../../netfilter/xt_repldata.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); @@ -66,6 +67,12 @@ do { \ #define inline #endif +void *ipt_alloc_initial_table(const struct xt_table *info) +{ + return xt_alloc_initial_table(ipt, IPT); +} +EXPORT_SYMBOL_GPL(ipt_alloc_initial_table); + /* We keep a set of rules for each CPU, so we can avoid write-locking them in the softirq when updating the counters and therefore diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index c14bb85db1d9..c8dc9800d620 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -23,36 +23,6 @@ MODULE_DESCRIPTION("iptables filter table"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT)) -static struct -{ - struct ipt_replace repl; - struct ipt_standard entries[3]; - struct ipt_error term; -} initial_table __net_initdata = { - .repl = { - .name = "filter", - .valid_hooks = FILTER_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), - .hook_entry = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, - }, - .underflow = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, - }, - }, - .entries = { - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IPT_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, @@ -86,9 +56,18 @@ module_param(forward, bool, 0000); static int __net_init iptable_filter_net_init(struct net *net) { - /* Register table */ + struct ipt_replace *repl; + + repl = ipt_alloc_initial_table(&packet_filter); + if (repl == NULL) + return -ENOMEM; + /* Entry 1 is the FORWARD hook */ + ((struct ipt_standard *)repl->entries)[1].target.verdict = + -forward - 1; + net->ipv4.iptable_filter = - ipt_register_table(net, &packet_filter, &initial_table.repl); + ipt_register_table(net, &packet_filter, repl); + kfree(repl); if (IS_ERR(net->ipv4.iptable_filter)) return PTR_ERR(net->ipv4.iptable_filter); return 0; @@ -113,9 +92,6 @@ static int __init iptable_filter_init(void) return -EINVAL; } - /* Entry 1 is the FORWARD hook */ - initial_table.entries[1].target.verdict = -forward - 1; - ret = register_pernet_subsys(&iptable_filter_net_ops); if (ret < 0) return ret; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 2355a229f8ee..58d7097baa3d 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -27,43 +27,6 @@ MODULE_DESCRIPTION("iptables mangle table"); (1 << NF_INET_LOCAL_OUT) | \ (1 << NF_INET_POST_ROUTING)) -/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */ -static const struct -{ - struct ipt_replace repl; - struct ipt_standard entries[5]; - struct ipt_error term; -} initial_table __net_initdata = { - .repl = { - .name = "mangle", - .valid_hooks = MANGLE_VALID_HOOKS, - .num_entries = 6, - .size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error), - .hook_entry = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_IN] = sizeof(struct ipt_standard), - [NF_INET_FORWARD] = sizeof(struct ipt_standard) * 2, - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, - [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 4, - }, - .underflow = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_IN] = sizeof(struct ipt_standard), - [NF_INET_FORWARD] = sizeof(struct ipt_standard) * 2, - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, - [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 4, - }, - }, - .entries = { - IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ - }, - .term = IPT_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, @@ -134,9 +97,14 @@ static struct nf_hook_ops *mangle_ops __read_mostly; static int __net_init iptable_mangle_net_init(struct net *net) { - /* Register table */ + struct ipt_replace *repl; + + repl = ipt_alloc_initial_table(&packet_mangler); + if (repl == NULL) + return -ENOMEM; net->ipv4.iptable_mangle = - ipt_register_table(net, &packet_mangler, &initial_table.repl); + ipt_register_table(net, &packet_mangler, repl); + kfree(repl); if (IS_ERR(net->ipv4.iptable_mangle)) return PTR_ERR(net->ipv4.iptable_mangle); return 0; diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 62a99154f14c..06fb9d11953c 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -9,33 +9,6 @@ #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) -static const struct -{ - struct ipt_replace repl; - struct ipt_standard entries[2]; - struct ipt_error term; -} initial_table __net_initdata = { - .repl = { - .name = "raw", - .valid_hooks = RAW_VALID_HOOKS, - .num_entries = 3, - .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), - .hook_entry = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) - }, - .underflow = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) - }, - }, - .entries = { - IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IPT_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, @@ -66,9 +39,14 @@ static struct nf_hook_ops *rawtable_ops __read_mostly; static int __net_init iptable_raw_net_init(struct net *net) { - /* Register table */ + struct ipt_replace *repl; + + repl = ipt_alloc_initial_table(&packet_raw); + if (repl == NULL) + return -ENOMEM; net->ipv4.iptable_raw = - ipt_register_table(net, &packet_raw, &initial_table.repl); + ipt_register_table(net, &packet_raw, repl); + kfree(repl); if (IS_ERR(net->ipv4.iptable_raw)) return PTR_ERR(net->ipv4.iptable_raw); return 0; diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index b1bf3ca2c6c7..cce2f64e6f21 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -27,36 +27,6 @@ MODULE_DESCRIPTION("iptables security table, for MAC rules"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT) -static const struct -{ - struct ipt_replace repl; - struct ipt_standard entries[3]; - struct ipt_error term; -} initial_table __net_initdata = { - .repl = { - .name = "security", - .valid_hooks = SECURITY_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), - .hook_entry = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, - }, - .underflow = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, - }, - }, - .entries = { - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IPT_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, @@ -87,9 +57,14 @@ static struct nf_hook_ops *sectbl_ops __read_mostly; static int __net_init iptable_security_net_init(struct net *net) { - net->ipv4.iptable_security = - ipt_register_table(net, &security_table, &initial_table.repl); + struct ipt_replace *repl; + repl = ipt_alloc_initial_table(&security_table); + if (repl == NULL) + return -ENOMEM; + net->ipv4.iptable_security = + ipt_register_table(net, &security_table, repl); + kfree(repl); if (IS_ERR(net->ipv4.iptable_security)) return PTR_ERR(net->ipv4.iptable_security); diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 85da34fdc755..ab74cc0535e2 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -28,36 +28,6 @@ (1 << NF_INET_POST_ROUTING) | \ (1 << NF_INET_LOCAL_OUT)) -static const struct -{ - struct ipt_replace repl; - struct ipt_standard entries[3]; - struct ipt_error term; -} nat_initial_table __net_initdata = { - .repl = { - .name = "nat", - .valid_hooks = NAT_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), - .hook_entry = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 - }, - .underflow = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 - }, - }, - .entries = { - IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ - IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ - IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IPT_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, @@ -186,8 +156,13 @@ static struct xt_target ipt_dnat_reg __read_mostly = { static int __net_init nf_nat_rule_net_init(struct net *net) { - net->ipv4.nat_table = ipt_register_table(net, &nat_table, - &nat_initial_table.repl); + struct ipt_replace *repl; + + repl = ipt_alloc_initial_table(&nat_table); + if (repl == NULL) + return -ENOMEM; + net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl); + kfree(repl); if (IS_ERR(net->ipv4.nat_table)) return PTR_ERR(net->ipv4.nat_table); return 0; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 4332f4591482..dcd7825fe7b6 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -29,6 +29,7 @@ #include #include #include +#include "../../netfilter/xt_repldata.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); @@ -67,6 +68,12 @@ do { \ #define inline #endif +void *ip6t_alloc_initial_table(const struct xt_table *info) +{ + return xt_alloc_initial_table(ip6t, IP6T); +} +EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); + /* We keep a set of rules for each CPU, so we can avoid write-locking them in the softirq when updating the counters and therefore diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 6e95d0614ca9..36b72cafc227 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -21,36 +21,6 @@ MODULE_DESCRIPTION("ip6tables filter table"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT)) -static struct -{ - struct ip6t_replace repl; - struct ip6t_standard entries[3]; - struct ip6t_error term; -} initial_table __net_initdata = { - .repl = { - .name = "filter", - .valid_hooks = FILTER_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), - .hook_entry = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ip6t_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 - }, - .underflow = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ip6t_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 - }, - }, - .entries = { - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IP6T_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, @@ -78,9 +48,18 @@ module_param(forward, bool, 0000); static int __net_init ip6table_filter_net_init(struct net *net) { - /* Register table */ + struct ip6t_replace *repl; + + repl = ip6t_alloc_initial_table(&packet_filter); + if (repl == NULL) + return -ENOMEM; + /* Entry 1 is the FORWARD hook */ + ((struct ip6t_standard *)repl->entries)[1].target.verdict = + -forward - 1; + net->ipv6.ip6table_filter = - ip6t_register_table(net, &packet_filter, &initial_table.repl); + ip6t_register_table(net, &packet_filter, repl); + kfree(repl); if (IS_ERR(net->ipv6.ip6table_filter)) return PTR_ERR(net->ipv6.ip6table_filter); return 0; @@ -105,9 +84,6 @@ static int __init ip6table_filter_init(void) return -EINVAL; } - /* Entry 1 is the FORWARD hook */ - initial_table.entries[1].target.verdict = -forward - 1; - ret = register_pernet_subsys(&ip6table_filter_net_ops); if (ret < 0) return ret; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 5023ac52ffec..dc803b7e8e54 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -21,42 +21,6 @@ MODULE_DESCRIPTION("ip6tables mangle table"); (1 << NF_INET_LOCAL_OUT) | \ (1 << NF_INET_POST_ROUTING)) -static const struct -{ - struct ip6t_replace repl; - struct ip6t_standard entries[5]; - struct ip6t_error term; -} initial_table __net_initdata = { - .repl = { - .name = "mangle", - .valid_hooks = MANGLE_VALID_HOOKS, - .num_entries = 6, - .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), - .hook_entry = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), - [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, - [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, - }, - .underflow = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), - [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, - [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, - }, - }, - .entries = { - IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ - }, - .term = IP6T_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, @@ -126,9 +90,14 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, static struct nf_hook_ops *mangle_ops __read_mostly; static int __net_init ip6table_mangle_net_init(struct net *net) { - /* Register table */ + struct ip6t_replace *repl; + + repl = ip6t_alloc_initial_table(&packet_mangler); + if (repl == NULL) + return -ENOMEM; net->ipv6.ip6table_mangle = - ip6t_register_table(net, &packet_mangler, &initial_table.repl); + ip6t_register_table(net, &packet_mangler, repl); + kfree(repl); if (IS_ERR(net->ipv6.ip6table_mangle)) return PTR_ERR(net->ipv6.ip6table_mangle); return 0; diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 3bfa69511641..aef31a29de9e 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -8,33 +8,6 @@ #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) -static const struct -{ - struct ip6t_replace repl; - struct ip6t_standard entries[2]; - struct ip6t_error term; -} initial_table __net_initdata = { - .repl = { - .name = "raw", - .valid_hooks = RAW_VALID_HOOKS, - .num_entries = 3, - .size = sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), - .hook_entry = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) - }, - .underflow = { - [NF_INET_PRE_ROUTING] = 0, - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) - }, - }, - .entries = { - IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IP6T_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, @@ -58,9 +31,14 @@ static struct nf_hook_ops *rawtable_ops __read_mostly; static int __net_init ip6table_raw_net_init(struct net *net) { - /* Register table */ + struct ip6t_replace *repl; + + repl = ip6t_alloc_initial_table(&packet_raw); + if (repl == NULL) + return -ENOMEM; net->ipv6.ip6table_raw = - ip6t_register_table(net, &packet_raw, &initial_table.repl); + ip6t_register_table(net, &packet_raw, repl); + kfree(repl); if (IS_ERR(net->ipv6.ip6table_raw)) return PTR_ERR(net->ipv6.ip6table_raw); return 0; diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index dd2200f17a6c..0824d865aa9b 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -26,36 +26,6 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT) -static const struct -{ - struct ip6t_replace repl; - struct ip6t_standard entries[3]; - struct ip6t_error term; -} initial_table __net_initdata = { - .repl = { - .name = "security", - .valid_hooks = SECURITY_VALID_HOOKS, - .num_entries = 4, - .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), - .hook_entry = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ip6t_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, - }, - .underflow = { - [NF_INET_LOCAL_IN] = 0, - [NF_INET_FORWARD] = sizeof(struct ip6t_standard), - [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, - }, - }, - .entries = { - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ - IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ - }, - .term = IP6T_ERROR_INIT, /* ERROR */ -}; - static const struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, @@ -79,9 +49,14 @@ static struct nf_hook_ops *sectbl_ops __read_mostly; static int __net_init ip6table_security_net_init(struct net *net) { - net->ipv6.ip6table_security = - ip6t_register_table(net, &security_table, &initial_table.repl); + struct ip6t_replace *repl; + repl = ip6t_alloc_initial_table(&security_table); + if (repl == NULL) + return -ENOMEM; + net->ipv6.ip6table_security = + ip6t_register_table(net, &security_table, repl); + kfree(repl); if (IS_ERR(net->ipv6.ip6table_security)) return PTR_ERR(net->ipv6.ip6table_security); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index b51cb0d7234a..dc2e05cb54c0 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -26,7 +26,9 @@ #include #include - +#include +#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); diff --git a/net/netfilter/xt_repldata.h b/net/netfilter/xt_repldata.h new file mode 100644 index 000000000000..6efe4e5a81c6 --- /dev/null +++ b/net/netfilter/xt_repldata.h @@ -0,0 +1,35 @@ +/* + * Today's hack: quantum tunneling in structs + * + * 'entries' and 'term' are never anywhere referenced by word in code. In fact, + * they serve as the hanging-off data accessed through repl.data[]. + */ + +#define xt_alloc_initial_table(type, typ2) ({ \ + unsigned int hook_mask = info->valid_hooks; \ + unsigned int nhooks = hweight32(hook_mask); \ + unsigned int bytes = 0, hooknum = 0, i = 0; \ + struct { \ + struct type##_replace repl; \ + struct type##_standard entries[nhooks]; \ + struct type##_error term; \ + } *tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); \ + if (tbl == NULL) \ + return NULL; \ + strncpy(tbl->repl.name, info->name, sizeof(tbl->repl.name)); \ + tbl->term = (struct type##_error)typ2##_ERROR_INIT; \ + tbl->repl.valid_hooks = hook_mask; \ + tbl->repl.num_entries = nhooks + 1; \ + tbl->repl.size = nhooks * sizeof(struct type##_standard) + \ + sizeof(struct type##_error); \ + for (; hook_mask != 0; hook_mask >>= 1, ++hooknum) { \ + if (!(hook_mask & 1)) \ + continue; \ + tbl->repl.hook_entry[hooknum] = bytes; \ + tbl->repl.underflow[hooknum] = bytes; \ + tbl->entries[i++] = (struct type##_standard) \ + typ2##_STANDARD_INIT(NF_ACCEPT); \ + bytes += sizeof(struct type##_standard); \ + } \ + tbl; \ +}) -- GitLab From 0271f91003d3703675be13b8865618359a6caa1f Mon Sep 17 00:00:00 2001 From: Haicheng Li Date: Thu, 4 Feb 2010 19:06:33 +0800 Subject: [PATCH 1855/3892] x86, acpi: Map hotadded cpu to correct node. When hotadd new cpu to system, if its affinitive node is online, should map the cpu to its own node. Otherwise, let kernel select one online node for the new cpu later. Signed-off-by: Haicheng Li LKML-Reference: <4B6AAA39.6000300@linux.intel.com> Tested-by: Thomas Renninger Signed-off-by: H. Peter Anvin --- arch/x86/kernel/acpi/boot.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 036d28adf59d..7db15e161aa0 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -49,6 +49,7 @@ EXPORT_SYMBOL(acpi_disabled); #ifdef CONFIG_X86_64 # include +# include #endif /* X86 */ #define BAD_MADT_ENTRY(entry, end) ( \ @@ -482,6 +483,25 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) */ #ifdef CONFIG_ACPI_HOTPLUG_CPU +static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +{ +#ifdef CONFIG_ACPI_NUMA + int nid; + + nid = acpi_get_node(handle); + if (nid == -1 || !node_online(nid)) + return; +#ifdef CONFIG_X86_64 + apicid_to_node[physid] = nid; + numa_set_node(cpu, nid); +#else /* CONFIG_X86_32 */ + apicid_2_node[physid] = nid; + cpu_to_node_map[cpu] = nid; +#endif + +#endif +} + static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -540,6 +560,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) } cpu = cpumask_first(new_map); + acpi_map_cpu2node(handle, cpu, physid); *pcpu = cpu; retval = 0; -- GitLab From 66655de6d132b726be64c324bc3f9ea366d20697 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:18:22 +0000 Subject: [PATCH 1856/3892] seq_file: Add helpers for iteration over a hlist Some places in kernel need to iterate over a hlist in seq_file, so provide some common helpers. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- fs/seq_file.c | 59 ++++++++++++++++++++++++++++++++++++++-- include/linux/seq_file.h | 11 ++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/fs/seq_file.c b/fs/seq_file.c index eae7d9dbf3ff..f65b16f02da3 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -674,7 +674,6 @@ struct list_head *seq_list_start(struct list_head *head, loff_t pos) return NULL; } - EXPORT_SYMBOL(seq_list_start); struct list_head *seq_list_start_head(struct list_head *head, loff_t pos) @@ -684,7 +683,6 @@ struct list_head *seq_list_start_head(struct list_head *head, loff_t pos) return seq_list_start(head, pos - 1); } - EXPORT_SYMBOL(seq_list_start_head); struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) @@ -695,5 +693,60 @@ struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) ++*ppos; return lh == head ? NULL : lh; } - EXPORT_SYMBOL(seq_list_next); + +/** + * seq_hlist_start - start an iteration of a hlist + * @head: the head of the hlist + * @pos: the start position of the sequence + * + * Called at seq_file->op->start(). + */ +struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos) +{ + struct hlist_node *node; + + hlist_for_each(node, head) + if (pos-- == 0) + return node; + return NULL; +} +EXPORT_SYMBOL(seq_hlist_start); + +/** + * seq_hlist_start_head - start an iteration of a hlist + * @head: the head of the hlist + * @pos: the start position of the sequence + * + * Called at seq_file->op->start(). Call this function if you want to + * print a header at the top of the output. + */ +struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos) +{ + if (!pos) + return SEQ_START_TOKEN; + + return seq_hlist_start(head, pos - 1); +} +EXPORT_SYMBOL(seq_hlist_start_head); + +/** + * seq_hlist_next - move to the next position of the hlist + * @v: the current iterator + * @head: the head of the hlist + * @pos: the current posision + * + * Called at seq_file->op->next(). + */ +struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, + loff_t *ppos) +{ + struct hlist_node *node = v; + + ++*ppos; + if (v == SEQ_START_TOKEN) + return head->first; + else + return node->next; +} +EXPORT_SYMBOL(seq_hlist_next); diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 8366d8f12e53..c95bcdc18f4c 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -135,4 +135,15 @@ extern struct list_head *seq_list_start_head(struct list_head *head, extern struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); +/* + * Helpers for iteration over hlist_head-s in seq_files + */ + +extern struct hlist_node *seq_hlist_start(struct hlist_head *head, + loff_t pos); +extern struct hlist_node *seq_hlist_start_head(struct hlist_head *head, + loff_t pos); +extern struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, + loff_t *ppos); + #endif -- GitLab From c4146644a56b1f213c4c5567c75771883bec33c7 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:18:45 +0000 Subject: [PATCH 1857/3892] net: add a wrapper sk_entry() Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- include/net/sock.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/net/sock.h b/include/net/sock.h index 3f1a4804bb3f..c8d400063c16 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -317,6 +317,11 @@ struct sock { /* * Hashed lists helper routines */ +static inline struct sock *sk_entry(const struct hlist_node *node) +{ + return hlist_entry(node, struct sock, sk_node); +} + static inline struct sock *__sk_head(const struct hlist_head *head) { return hlist_entry(head->first, struct sock, sk_node); -- GitLab From 32d2e3a149772441a6a146ad96cbae319e27742a Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:19:04 +0000 Subject: [PATCH 1858/3892] net: x25: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/x25/x25_proc.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 0a04e62e0e18..c4cd3226a053 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -93,40 +93,16 @@ out: return 0; } -static __inline__ struct sock *x25_get_socket_idx(loff_t pos) -{ - struct sock *s; - struct hlist_node *node; - - sk_for_each(s, node, &x25_list) - if (!pos--) - goto found; - s = NULL; -found: - return s; -} - static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos) __acquires(x25_list_lock) { - loff_t l = *pos; - read_lock_bh(&x25_list_lock); - return l ? x25_get_socket_idx(--l) : SEQ_START_TOKEN; + return seq_hlist_start_head(&x25_list, *pos); } static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) { - struct sock *s; - - ++*pos; - if (v == SEQ_START_TOKEN) { - s = sk_head(&x25_list); - goto out; - } - s = sk_next(v); -out: - return s; + return seq_hlist_next(v, &x25_list, pos); } static void x25_seq_socket_stop(struct seq_file *seq, void *v) @@ -148,7 +124,7 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v) goto out; } - s = v; + s = sk_entry(v); x25 = x25_sk(s); if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) -- GitLab From b999748acce739675a5e9420f21e54b8cbad9d81 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:19:17 +0000 Subject: [PATCH 1859/3892] net: rose: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/rose/af_rose.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8feb9e5d6623..e90b9b6c16ae 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1404,29 +1404,13 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static void *rose_info_start(struct seq_file *seq, loff_t *pos) __acquires(rose_list_lock) { - int i; - struct sock *s; - struct hlist_node *node; - spin_lock_bh(&rose_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - i = 1; - sk_for_each(s, node, &rose_list) { - if (i == *pos) - return s; - ++i; - } - return NULL; + return seq_hlist_start_head(&rose_list, *pos); } static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - - return (v == SEQ_START_TOKEN) ? sk_head(&rose_list) - : sk_next((struct sock *)v); + return seq_hlist_next(v, &rose_list, pos); } static void rose_info_stop(struct seq_file *seq, void *v) @@ -1444,7 +1428,7 @@ static int rose_info_show(struct seq_file *seq, void *v) "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); else { - struct sock *s = v; + struct sock *s = sk_entry(v); struct rose_sock *rose = rose_sk(s); const char *devname, *callsign; const struct net_device *dev = rose->device; -- GitLab From b7ceabd9b528417973619c5b655bc5b21857ac36 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:19:29 +0000 Subject: [PATCH 1860/3892] net: packet: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/packet/af_packet.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6ecb426bc0cf..10f7295bcefb 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2510,33 +2510,19 @@ static struct notifier_block packet_netdev_notifier = { }; #ifdef CONFIG_PROC_FS -static inline struct sock *packet_seq_idx(struct net *net, loff_t off) -{ - struct sock *s; - struct hlist_node *node; - - sk_for_each(s, node, &net->packet.sklist) { - if (!off--) - return s; - } - return NULL; -} static void *packet_seq_start(struct seq_file *seq, loff_t *pos) __acquires(seq_file_net(seq)->packet.sklist_lock) { struct net *net = seq_file_net(seq); read_lock(&net->packet.sklist_lock); - return *pos ? packet_seq_idx(net, *pos - 1) : SEQ_START_TOKEN; + return seq_hlist_start_head(&net->packet.sklist, *pos); } static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct net *net = seq_file_net(seq); - ++*pos; - return (v == SEQ_START_TOKEN) - ? sk_head(&net->packet.sklist) - : sk_next((struct sock *)v) ; + return seq_hlist_next(v, &net->packet.sklist, pos); } static void packet_seq_stop(struct seq_file *seq, void *v) @@ -2551,7 +2537,7 @@ static int packet_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_puts(seq, "sk RefCnt Type Proto Iface R Rmem User Inode\n"); else { - struct sock *s = v; + struct sock *s = sk_entry(v); const struct packet_sock *po = pkt_sk(s); seq_printf(seq, -- GitLab From 90dd7f5ace558314fa431ae0f59388ed3e5c7695 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:19:42 +0000 Subject: [PATCH 1861/3892] net: netrom: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/netrom/af_netrom.c | 21 +++-------------- net/netrom/nr_route.c | 53 +++++++----------------------------------- 2 files changed, 12 insertions(+), 62 deletions(-) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 71604c6613b5..a249127020a5 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1267,28 +1267,13 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static void *nr_info_start(struct seq_file *seq, loff_t *pos) { - struct sock *s; - struct hlist_node *node; - int i = 1; - spin_lock_bh(&nr_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - sk_for_each(s, node, &nr_list) { - if (i == *pos) - return s; - ++i; - } - return NULL; + return seq_hlist_start_head(&nr_list, *pos); } static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - - return (v == SEQ_START_TOKEN) ? sk_head(&nr_list) - : sk_next((struct sock *)v); + return seq_hlist_next(v, &nr_list, pos); } static void nr_info_stop(struct seq_file *seq, void *v) @@ -1298,7 +1283,7 @@ static void nr_info_stop(struct seq_file *seq, void *v) static int nr_info_show(struct seq_file *seq, void *v) { - struct sock *s = v; + struct sock *s = sk_entry(v); struct net_device *dev; struct nr_sock *nr; const char *devname; diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index e2e2d33cafdf..5cc648012f50 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -863,33 +863,13 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) static void *nr_node_start(struct seq_file *seq, loff_t *pos) { - struct nr_node *nr_node; - struct hlist_node *node; - int i = 1; - spin_lock_bh(&nr_node_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - nr_node_for_each(nr_node, node, &nr_node_list) { - if (i == *pos) - return nr_node; - ++i; - } - - return NULL; + return seq_hlist_start_head(&nr_node_list, *pos); } static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos) { - struct hlist_node *node; - ++*pos; - - node = (v == SEQ_START_TOKEN) - ? nr_node_list.first - : ((struct nr_node *)v)->node_node.next; - - return hlist_entry(node, struct nr_node, node_node); + return seq_hlist_next(v, &nr_node_list, pos); } static void nr_node_stop(struct seq_file *seq, void *v) @@ -906,7 +886,9 @@ static int nr_node_show(struct seq_file *seq, void *v) seq_puts(seq, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); else { - struct nr_node *nr_node = v; + struct nr_node *nr_node = hlist_entry(v, struct nr_node, + node_node); + nr_node_lock(nr_node); seq_printf(seq, "%-9s %-7s %d %d", ax2asc(buf, &nr_node->callsign), @@ -949,31 +931,13 @@ const struct file_operations nr_nodes_fops = { static void *nr_neigh_start(struct seq_file *seq, loff_t *pos) { - struct nr_neigh *nr_neigh; - struct hlist_node *node; - int i = 1; - spin_lock_bh(&nr_neigh_list_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) { - if (i == *pos) - return nr_neigh; - } - return NULL; + return seq_hlist_start_head(&nr_neigh_list, *pos); } static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos) { - struct hlist_node *node; - ++*pos; - - node = (v == SEQ_START_TOKEN) - ? nr_neigh_list.first - : ((struct nr_neigh *)v)->neigh_node.next; - - return hlist_entry(node, struct nr_neigh, neigh_node); + return seq_hlist_next(v, &nr_neigh_list, pos); } static void nr_neigh_stop(struct seq_file *seq, void *v) @@ -989,8 +953,9 @@ static int nr_neigh_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n"); else { - struct nr_neigh *nr_neigh = v; + struct nr_neigh *nr_neigh; + nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node); seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", nr_neigh->number, ax2asc(buf, &nr_neigh->callsign), -- GitLab From b512f3d841370aedee9a2c24a14a0ab5fc0a02b2 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:19:59 +0000 Subject: [PATCH 1862/3892] net: ax25: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 18 +++--------------- net/ax25/ax25_uid.c | 25 ++++--------------------- 2 files changed, 7 insertions(+), 36 deletions(-) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 5588ba69c468..a5beedf43e2d 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1863,25 +1863,13 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static void *ax25_info_start(struct seq_file *seq, loff_t *pos) __acquires(ax25_list_lock) { - struct ax25_cb *ax25; - struct hlist_node *node; - int i = 0; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(ax25, node, &ax25_list) { - if (i == *pos) - return ax25; - ++i; - } - return NULL; + return seq_hlist_start(&ax25_list, *pos); } static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - - return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, - struct ax25_cb, ax25_node); + return seq_hlist_next(v, &ax25_list, pos); } static void ax25_info_stop(struct seq_file *seq, void *v) @@ -1892,7 +1880,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v) static int ax25_info_show(struct seq_file *seq, void *v) { - ax25_cb *ax25 = v; + ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node); char buf[11]; int k; diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index 832bcf092a01..9f13f6eefcba 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -146,31 +146,13 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) __acquires(ax25_uid_lock) { - struct ax25_uid_assoc *pt; - struct hlist_node *node; - int i = 1; - read_lock(&ax25_uid_lock); - - if (*pos == 0) - return SEQ_START_TOKEN; - - ax25_uid_for_each(pt, node, &ax25_uid_list) { - if (i == *pos) - return pt; - ++i; - } - return NULL; + return seq_hlist_start_head(&ax25_uid_list, *pos); } static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - if (v == SEQ_START_TOKEN) - return ax25_uid_list.first; - else - return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next, - ax25_uid_assoc, uid_node); + return seq_hlist_next(v, &ax25_uid_list, pos); } static void ax25_uid_seq_stop(struct seq_file *seq, void *v) @@ -186,8 +168,9 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_printf(seq, "Policy: %d\n", ax25_uid_policy); else { - struct ax25_uid_assoc *pt = v; + struct ax25_uid_assoc *pt; + pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call)); } return 0; -- GitLab From efaffb78d875a155b9f327532c2ddccf28c592b4 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:20:15 +0000 Subject: [PATCH 1863/3892] net: appletalk: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/appletalk/atalk_proc.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index 80caad1a31a5..6ef0e761e5de 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c @@ -144,40 +144,16 @@ out: return 0; } -static __inline__ struct sock *atalk_get_socket_idx(loff_t pos) -{ - struct sock *s; - struct hlist_node *node; - - sk_for_each(s, node, &atalk_sockets) - if (!pos--) - goto found; - s = NULL; -found: - return s; -} - static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) __acquires(atalk_sockets_lock) { - loff_t l = *pos; - read_lock_bh(&atalk_sockets_lock); - return l ? atalk_get_socket_idx(--l) : SEQ_START_TOKEN; + return seq_hlist_start_head(&atalk_sockets, *pos); } static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) { - struct sock *i; - - ++*pos; - if (v == SEQ_START_TOKEN) { - i = sk_head(&atalk_sockets); - goto out; - } - i = sk_next(v); -out: - return i; + return seq_hlist_next(v, &atalk_sockets, pos); } static void atalk_seq_socket_stop(struct seq_file *seq, void *v) @@ -197,7 +173,7 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v) goto out; } - s = v; + s = sk_entry(v); at = at_sk(s); seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " -- GitLab From 27b5b8657a2aa761f76e45fa60c20b7bafc249dc Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:20:29 +0000 Subject: [PATCH 1864/3892] net: af_key: use seq_hlist_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/key/af_key.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 41dd2cb07ef3..79d2c0f3c334 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3654,9 +3654,8 @@ static const struct net_proto_family pfkey_family_ops = { #ifdef CONFIG_PROC_FS static int pfkey_seq_show(struct seq_file *f, void *v) { - struct sock *s; + struct sock *s = sk_entry(v); - s = (struct sock *)v; if (v == SEQ_START_TOKEN) seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n"); else @@ -3675,19 +3674,9 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) { struct net *net = seq_file_net(f); struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); - struct sock *s; - struct hlist_node *node; - loff_t pos = *ppos; read_lock(&pfkey_table_lock); - if (pos == 0) - return SEQ_START_TOKEN; - - sk_for_each(s, node, &net_pfkey->table) - if (pos-- == 1) - return s; - - return NULL; + return seq_hlist_start_head(&net_pfkey->table, *ppos); } static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) @@ -3695,10 +3684,7 @@ static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) struct net *net = seq_file_net(f); struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); - ++*ppos; - return (v == SEQ_START_TOKEN) ? - sk_head(&net_pfkey->table) : - sk_next((struct sock *)v); + return seq_hlist_next(v, &net_pfkey->table, ppos); } static void pfkey_seq_stop(struct seq_file *f, void *v) -- GitLab From 4f134204f740d9fbf992843a6615175f5105f49e Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:20:42 +0000 Subject: [PATCH 1865/3892] net: x25: use seq_list_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/x25/x25_proc.c | 84 +++++----------------------------------------- 1 file changed, 8 insertions(+), 76 deletions(-) diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index c4cd3226a053..7ff373792324 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -25,49 +25,17 @@ #include #ifdef CONFIG_PROC_FS -static __inline__ struct x25_route *x25_get_route_idx(loff_t pos) -{ - struct list_head *route_entry; - struct x25_route *rt = NULL; - - list_for_each(route_entry, &x25_route_list) { - rt = list_entry(route_entry, struct x25_route, node); - if (!pos--) - goto found; - } - rt = NULL; -found: - return rt; -} static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos) __acquires(x25_route_list_lock) { - loff_t l = *pos; - read_lock_bh(&x25_route_list_lock); - return l ? x25_get_route_idx(--l) : SEQ_START_TOKEN; + return seq_list_start_head(&x25_route_list, *pos); } static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) { - struct x25_route *rt; - - ++*pos; - if (v == SEQ_START_TOKEN) { - rt = NULL; - if (!list_empty(&x25_route_list)) - rt = list_entry(x25_route_list.next, - struct x25_route, node); - goto out; - } - rt = v; - if (rt->node.next != &x25_route_list) - rt = list_entry(rt->node.next, struct x25_route, node); - else - rt = NULL; -out: - return rt; + return seq_list_next(v, &x25_route_list, pos); } static void x25_seq_route_stop(struct seq_file *seq, void *v) @@ -78,9 +46,9 @@ static void x25_seq_route_stop(struct seq_file *seq, void *v) static int x25_seq_route_show(struct seq_file *seq, void *v) { - struct x25_route *rt; + struct x25_route *rt = list_entry(v, struct x25_route, node); - if (v == SEQ_START_TOKEN) { + if (v == &x25_route_list) { seq_puts(seq, "Address Digits Device\n"); goto out; } @@ -146,51 +114,16 @@ out: return 0; } -static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos) -{ - struct x25_forward *f; - struct list_head *entry; - - list_for_each(entry, &x25_forward_list) { - f = list_entry(entry, struct x25_forward, node); - if (!pos--) - goto found; - } - - f = NULL; -found: - return f; -} - static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos) __acquires(x25_forward_list_lock) { - loff_t l = *pos; - read_lock_bh(&x25_forward_list_lock); - return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN; + return seq_list_start_head(&x25_forward_list, *pos); } static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos) { - struct x25_forward *f; - - ++*pos; - if (v == SEQ_START_TOKEN) { - f = NULL; - if (!list_empty(&x25_forward_list)) - f = list_entry(x25_forward_list.next, - struct x25_forward, node); - goto out; - } - f = v; - if (f->node.next != &x25_forward_list) - f = list_entry(f->node.next, struct x25_forward, node); - else - f = NULL; -out: - return f; - + return seq_list_next(v, &x25_forward_list, pos); } static void x25_seq_forward_stop(struct seq_file *seq, void *v) @@ -201,9 +134,9 @@ static void x25_seq_forward_stop(struct seq_file *seq, void *v) static int x25_seq_forward_show(struct seq_file *seq, void *v) { - struct x25_forward *f; + struct x25_forward *f = list_entry(v, struct x25_forward, node); - if (v == SEQ_START_TOKEN) { + if (v == &x25_forward_list) { seq_printf(seq, "lci dev1 dev2\n"); goto out; } @@ -212,7 +145,6 @@ static int x25_seq_forward_show(struct seq_file *seq, void *v) seq_printf(seq, "%d %-10s %-10s\n", f->lci, f->dev1->name, f->dev2->name); - out: return 0; } -- GitLab From 1349ea08e8de7b3e09998f33ea4e6c74f3e0db1a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 10 Feb 2010 11:47:57 -0800 Subject: [PATCH 1866/3892] sparc: remove redundant return statements Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller --- arch/sparc/kernel/devices.c | 2 -- arch/sparc/kernel/pcic.c | 2 -- arch/sparc/kernel/setup_32.c | 2 -- arch/sparc/kernel/unaligned_64.c | 2 -- arch/sparc/prom/console_32.c | 1 - arch/sparc/prom/console_64.c | 1 - arch/sparc/prom/devmap.c | 1 - arch/sparc/prom/devops_32.c | 2 -- arch/sparc/prom/init_32.c | 1 - arch/sparc/prom/palloc.c | 1 - arch/sparc/prom/ranges.c | 2 -- arch/sparc/prom/segment.c | 1 - arch/sparc/prom/tree_32.c | 1 - arch/sparc/prom/tree_64.c | 1 - 14 files changed, 20 deletions(-) diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index b171ae8de90d..89c22a2c085b 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -143,6 +143,4 @@ void __init device_scan(void) if (ARCH_SUN4C) sun4c_probe_memerr_reg(); - - return; } diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 4e2724ec2bb6..0610e2edaa78 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -585,8 +585,6 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); } } - - return; } /* diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 9be2af55c5cd..b22ce6100403 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -95,8 +95,6 @@ static void prom_sync_me(void) "nop\n\t" "nop\n\t" : : "r" (prom_tbr)); local_irq_restore(flags); - - return; } static unsigned int boot_flags __initdata = 0; diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 378ca82b9ccc..a9bc6c696ca6 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -636,7 +636,6 @@ daex: return; } advance(regs); - return; } void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) @@ -685,5 +684,4 @@ daex: return; } advance(regs); - return; } diff --git a/arch/sparc/prom/console_32.c b/arch/sparc/prom/console_32.c index b3075d73fc19..5340264b78f5 100644 --- a/arch/sparc/prom/console_32.c +++ b/arch/sparc/prom/console_32.c @@ -94,5 +94,4 @@ void prom_putchar(char c) { while(prom_nbputchar(c) == -1) ; - return; } diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c index e1c3fc87484d..f55d58a8a156 100644 --- a/arch/sparc/prom/console_64.c +++ b/arch/sparc/prom/console_64.c @@ -62,7 +62,6 @@ void prom_putchar(char c) { prom_nbputchar(c); - return; } void diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c index 1e517915b0df..46157d2aba0d 100644 --- a/arch/sparc/prom/devmap.c +++ b/arch/sparc/prom/devmap.c @@ -50,5 +50,4 @@ prom_unmapio(char *vaddr, unsigned int num_bytes) (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes); restore_current(); spin_unlock_irqrestore(&prom_lock, flags); - return; } diff --git a/arch/sparc/prom/devops_32.c b/arch/sparc/prom/devops_32.c index 9f1a95c91ad1..9c5d4687242a 100644 --- a/arch/sparc/prom/devops_32.c +++ b/arch/sparc/prom/devops_32.c @@ -84,6 +84,4 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) }; restore_current(); spin_unlock_irqrestore(&prom_lock, flags); - - return; } diff --git a/arch/sparc/prom/init_32.c b/arch/sparc/prom/init_32.c index 6193c33ed4d4..ccb36c7f9b8c 100644 --- a/arch/sparc/prom/init_32.c +++ b/arch/sparc/prom/init_32.c @@ -75,5 +75,4 @@ void __init prom_init(struct linux_romvec *rp) romvec->pv_romvers, prom_rev); /* Initialization successful. */ - return; } diff --git a/arch/sparc/prom/palloc.c b/arch/sparc/prom/palloc.c index 20be339cc2ce..2e2a88b211fb 100644 --- a/arch/sparc/prom/palloc.c +++ b/arch/sparc/prom/palloc.c @@ -40,5 +40,4 @@ prom_free(char *vaddr, unsigned int num_bytes) { if((prom_vers == PROM_V0) || (num_bytes == 0x0)) return; (*(romvec->pv_v2devops.v2_dumb_mem_free))(vaddr, num_bytes); - return; } diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c index cd5790853ff6..aeff43e44e45 100644 --- a/arch/sparc/prom/ranges.c +++ b/arch/sparc/prom/ranges.c @@ -87,8 +87,6 @@ void __init prom_ranges_init(void) if(num_obio_ranges) prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges); - - return; } void diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c index 04fd03a7f926..86a663f1d3c5 100644 --- a/arch/sparc/prom/segment.c +++ b/arch/sparc/prom/segment.c @@ -25,5 +25,4 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment) (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); restore_current(); spin_unlock_irqrestore(&prom_lock, flags); - return; } diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c index 646d244b1fdb..b21592f8e3fe 100644 --- a/arch/sparc/prom/tree_32.c +++ b/arch/sparc/prom/tree_32.c @@ -173,7 +173,6 @@ void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) len = prom_getproperty(node, prop, user_buf, ubuf_size); if(len != -1) return; user_buf[0] = 0; - return; } EXPORT_SYMBOL(prom_getstring); diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 8ea73ddc61dc..3c0d2dd9f693 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -154,7 +154,6 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) len = prom_getproperty(node, prop, user_buf, ubuf_size); if(len != -1) return; user_buf[0] = 0; - return; } EXPORT_SYMBOL(prom_getstring); -- GitLab From 216437eb8b5adf12ab91e1f0c046ffba22c63431 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:21:05 +0000 Subject: [PATCH 1867/3892] net: irda: use seq_list_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/irda/irlan/irlan_common.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 315ead3cb926..e486dc89ea59 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -1128,34 +1128,14 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) */ static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) { - int i = 1; - struct irlan_cb *self; - rcu_read_lock(); - if (*pos == 0) - return SEQ_START_TOKEN; - - list_for_each_entry(self, &irlans, dev_list) { - if (*pos == i) - return self; - ++i; - } - return NULL; + return seq_list_start_head(&irlans, *pos); } /* Return entry after v, and increment pos */ static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct list_head *nxt; - - ++*pos; - if (v == SEQ_START_TOKEN) - nxt = irlans.next; - else - nxt = ((struct irlan_cb *)v)->dev_list.next; - - return (nxt == &irlans) ? NULL - : list_entry(nxt, struct irlan_cb, dev_list); + return seq_list_next(v, &irlans, pos); } /* End of reading /proc file */ @@ -1170,10 +1150,10 @@ static void irlan_seq_stop(struct seq_file *seq, void *v) */ static int irlan_seq_show(struct seq_file *seq, void *v) { - if (v == SEQ_START_TOKEN) + if (v == &irlans) seq_puts(seq, "IrLAN instances:\n"); else { - struct irlan_cb *self = v; + struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); -- GitLab From a2b79b414df97a70c33f874b631e06830431d233 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:21:22 +0000 Subject: [PATCH 1868/3892] net: ipx: use seq_list_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/ipx/ipx_proc.c | 90 +++++++--------------------------------------- 1 file changed, 12 insertions(+), 78 deletions(-) diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 576178482f89..26b5bfcf1d03 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -13,45 +13,15 @@ #include #include -static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos) -{ - struct ipx_interface *i; - - list_for_each_entry(i, &ipx_interfaces, node) - if (!pos--) - goto out; - i = NULL; -out: - return i; -} - -static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i) -{ - struct ipx_interface *rc = NULL; - - if (i->node.next != &ipx_interfaces) - rc = list_entry(i->node.next, struct ipx_interface, node); - return rc; -} - static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) { - loff_t l = *pos; - spin_lock_bh(&ipx_interfaces_lock); - return l ? ipx_get_interface_idx(--l) : SEQ_START_TOKEN; + return seq_list_start_head(&ipx_interfaces, *pos); } static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) { - struct ipx_interface *i; - - ++*pos; - if (v == SEQ_START_TOKEN) - i = ipx_interfaces_head(); - else - i = ipx_interfaces_next(v); - return i; + return seq_list_next(v, &ipx_interfaces, pos); } static void ipx_seq_interface_stop(struct seq_file *seq, void *v) @@ -63,7 +33,7 @@ static int ipx_seq_interface_show(struct seq_file *seq, void *v) { struct ipx_interface *i; - if (v == SEQ_START_TOKEN) { + if (v == &ipx_interfaces) { seq_puts(seq, "Network Node_Address Primary Device " "Frame_Type"); #ifdef IPX_REFCNT_DEBUG @@ -73,7 +43,7 @@ static int ipx_seq_interface_show(struct seq_file *seq, void *v) goto out; } - i = v; + i = list_entry(v, struct ipx_interface, node); seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum)); seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", i->if_node[0], i->if_node[1], i->if_node[2], @@ -89,53 +59,15 @@ out: return 0; } -static struct ipx_route *ipx_routes_head(void) -{ - struct ipx_route *rc = NULL; - - if (!list_empty(&ipx_routes)) - rc = list_entry(ipx_routes.next, struct ipx_route, node); - return rc; -} - -static struct ipx_route *ipx_routes_next(struct ipx_route *r) -{ - struct ipx_route *rc = NULL; - - if (r->node.next != &ipx_routes) - rc = list_entry(r->node.next, struct ipx_route, node); - return rc; -} - -static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos) -{ - struct ipx_route *r; - - list_for_each_entry(r, &ipx_routes, node) - if (!pos--) - goto out; - r = NULL; -out: - return r; -} - static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) { - loff_t l = *pos; read_lock_bh(&ipx_routes_lock); - return l ? ipx_get_route_idx(--l) : SEQ_START_TOKEN; + return seq_list_start_head(&ipx_routes, *pos); } static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) { - struct ipx_route *r; - - ++*pos; - if (v == SEQ_START_TOKEN) - r = ipx_routes_head(); - else - r = ipx_routes_next(v); - return r; + return seq_list_next(v, &ipx_routes, pos); } static void ipx_seq_route_stop(struct seq_file *seq, void *v) @@ -147,11 +79,13 @@ static int ipx_seq_route_show(struct seq_file *seq, void *v) { struct ipx_route *rt; - if (v == SEQ_START_TOKEN) { + if (v == &ipx_routes) { seq_puts(seq, "Network Router_Net Router_Node\n"); goto out; } - rt = v; + + rt = list_entry(v, struct ipx_route, node); + seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net)); if (rt->ir_routed) seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n", @@ -226,9 +160,9 @@ static void *ipx_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) spin_unlock_bh(&i->if_sklist_lock); sk = NULL; for (;;) { - i = ipx_interfaces_next(i); - if (!i) + if (i->node.next == &ipx_interfaces) break; + i = list_entry(i->node.next, struct ipx_interface, node); spin_lock_bh(&i->if_sklist_lock); if (!hlist_empty(&i->if_sklist)) { sk = sk_head(&i->if_sklist); -- GitLab From 67de792420be2daa1c6fec07ec8552af9ea0bde3 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 8 Feb 2010 23:21:51 +0000 Subject: [PATCH 1869/3892] net: atm: use seq_list_foo() helpers Simplify seq_file code. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/atm/proc.c | 2 +- net/atm/resources.c | 18 ++---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/net/atm/proc.c b/net/atm/proc.c index 476779d845eb..7a96b2376bd7 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -238,7 +238,7 @@ static int atm_dev_seq_show(struct seq_file *seq, void *v) "Itf Type ESI/\"MAC\"addr " "AAL(TX,err,RX,err,drop) ... [refcnt]\n"; - if (v == SEQ_START_TOKEN) + if (v == &atm_devs) seq_puts(seq, atm_dev_banner); else { struct atm_dev *dev = list_entry(v, struct atm_dev, dev_list); diff --git a/net/atm/resources.c b/net/atm/resources.c index 447ed89205d8..90082904f20d 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -444,21 +444,10 @@ done: return error; } -static inline void *dev_get_idx(loff_t left) -{ - struct list_head *p; - - list_for_each(p, &atm_devs) { - if (!--left) - break; - } - return (p != &atm_devs) ? p : NULL; -} - void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) { mutex_lock(&atm_dev_mutex); - return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN; + return seq_list_start_head(&atm_devs, *pos); } void atm_dev_seq_stop(struct seq_file *seq, void *v) @@ -468,8 +457,5 @@ void atm_dev_seq_stop(struct seq_file *seq, void *v) void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - v = (v == SEQ_START_TOKEN) - ? atm_devs.next : ((struct list_head *)v)->next; - return (v == &atm_devs) ? NULL : v; + return seq_list_next(v, &atm_devs, pos); } -- GitLab From 633e7533cec78b99d806248e832fc83e689d2453 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 5 Feb 2010 08:56:20 +0000 Subject: [PATCH 1870/3892] fec: fix uninitialized rx buffer usage The fec driver was enabling receive buffer descriptor without allocating the buffers. Make sure the buffer descriptors are initialized to not start receiving packets. Open also calls fec_restart after the rx buffers are allocated. With the code in fec_restart, it zeroes out the buffer descriptors that have just been setup. Signed-off-by: Rob Herring Signed-off-by: Amit Kucheria Acked-by: Grant Likely Acked-by: Greg Ungerer Signed-off-by: David S. Miller --- drivers/net/fec.c | 57 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 16a1d58419d9..9a8743daa3e5 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1658,6 +1658,7 @@ static int fec_enet_init(struct net_device *dev, int index) { struct fec_enet_private *fep = netdev_priv(dev); struct bufdesc *cbd_base; + struct bufdesc *bdp; int i; /* Allocate memory for buffer descriptors. */ @@ -1710,6 +1711,34 @@ static int fec_enet_init(struct net_device *dev, int index) /* Set MII speed to 2.5 MHz */ fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1; + + /* Initialize the receive buffer descriptors. */ + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + + /* Initialize the BD for every fragment in the page. */ + bdp->cbd_sc = 0; + bdp++; + } + + /* Set the last buffer to wrap */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmit */ + bdp = fep->tx_bd_base; + for (i = 0; i < TX_RING_SIZE; i++) { + + /* Initialize the BD for every fragment in the page. */ + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + fec_restart(dev, 0); /* Queue up command to detect the PHY and initialize the @@ -1730,7 +1759,6 @@ static void fec_restart(struct net_device *dev, int duplex) { struct fec_enet_private *fep = netdev_priv(dev); - struct bufdesc *bdp; int i; /* Whack a reset. We should wait for this. */ @@ -1768,33 +1796,6 @@ fec_restart(struct net_device *dev, int duplex) } } - /* Initialize the receive buffer descriptors. */ - bdp = fep->rx_bd_base; - for (i = 0; i < RX_RING_SIZE; i++) { - - /* Initialize the BD for every fragment in the page. */ - bdp->cbd_sc = BD_ENET_RX_EMPTY; - bdp++; - } - - /* Set the last buffer to wrap */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* ...and the same for transmit */ - bdp = fep->tx_bd_base; - for (i = 0; i < TX_RING_SIZE; i++) { - - /* Initialize the BD for every fragment in the page. */ - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp++; - } - - /* Set the last buffer to wrap */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - /* Enable MII mode */ if (duplex) { /* MII enable / FD enable */ -- GitLab From fceb2919192d7a667be81c17c0bfa227fd7fa992 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Fri, 5 Feb 2010 08:56:21 +0000 Subject: [PATCH 1871/3892] fec: Add LAN8700 phy support The i.MX51 babbage board has a FEC ethernet controller with this phy. In the long term we should resurrect the phylib patches for fec. Signed-off-by: Amit Kucheria Acked-by: Grant Likely Signed-off-by: David S. Miller --- drivers/net/fec.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 9a8743daa3e5..5d0d33268155 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1128,6 +1128,26 @@ static phy_info_t phy_info_dp83848= { }, }; +static phy_info_t phy_info_lan8700 = { + 0x0007C0C, + "LAN8700", + (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup */ + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* act_int */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown */ + { mk_mii_end, } + }, +}; /* ------------------------------------------------------------------------- */ static phy_info_t const * const phy_info[] = { @@ -1137,6 +1157,7 @@ static phy_info_t const * const phy_info[] = { &phy_info_am79c874, &phy_info_ks8721bl, &phy_info_dp83848, + &phy_info_lan8700, NULL }; -- GitLab From bd011e8826978b0f6cd0f929edec353fd755f49b Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Fri, 5 Feb 2010 08:56:22 +0000 Subject: [PATCH 1872/3892] fec: Add ARCH_MX5 as a dependency i.MX51 babbage board has a FEC ethernet controller Signed-off-by: Amit Kucheria Signed-off-by: David S. Miller --- drivers/net/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ef662e15c3d3..1bf1987571ff 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1895,7 +1895,8 @@ config 68360_ENET config FEC bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35 || ARCH_MX25 + depends on M523x || M527x || M5272 || M528x || M520x || M532x || \ + MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. -- GitLab From 2ac2927a953a01c83df255118922cce1523d1a18 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 9 Feb 2010 13:06:54 -0500 Subject: [PATCH 1873/3892] ath5k: use correct packet type when transmitting The hardware needs to know what type of frames are being sent in order to fill in various fields, for example the timestamp in probe responses (before this patch, it was always 0). Set it correctly when initializing the TX descriptor. Signed-off-by: Bob Copeland Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 - drivers/net/wireless/ath/ath5k/base.c | 26 +++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ad4d446f0264..ac67f02e26d8 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -541,7 +541,6 @@ struct ath5k_txq_info { /* * Transmit packet types. * used on tx control descriptor - * TODO: Use them inside base.c corectly */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 97d642575550..2468c64d6c12 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1246,6 +1246,29 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) return 0; } +static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + enum ath5k_pkt_type htype; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_beacon(fc)) + htype = AR5K_PKT_TYPE_BEACON; + else if (ieee80211_is_probe_resp(fc)) + htype = AR5K_PKT_TYPE_PROBE_RESP; + else if (ieee80211_is_atim(fc)) + htype = AR5K_PKT_TYPE_ATIM; + else if (ieee80211_is_pspoll(fc)) + htype = AR5K_PKT_TYPE_PSPOLL; + else + htype = AR5K_PKT_TYPE_NORMAL; + + return htype; +} + static int ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, struct ath5k_txq *txq) @@ -1300,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, sc->vif, pktlen, info)); } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, + ieee80211_get_hdrlen_from_skb(skb), + get_hw_packet_type(skb), (sc->power_level * 2), hw_rate, info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, -- GitLab From f32338319f10c4ca5499c19edc5b3618896920ba Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 9 Feb 2010 13:35:43 -0800 Subject: [PATCH 1874/3892] Add Station and AdHoc mode support to libertas_tf Add support for using the libertas_tf driver on a managed or ad-hoc network. Signed-off-by: Deepak Saxena Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index ba3eb0101d55..6ab30033c26c 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -555,6 +555,9 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) priv->band.n_channels = ARRAY_SIZE(lbtf_channels); priv->band.channels = priv->channels; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); skb_queue_head_init(&priv->bc_ps_buf); SET_IEEE80211_DEV(hw, dmdev); -- GitLab From 4cad6c7c38930618d77e65af82c1403d63879eee Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 10 Feb 2010 14:52:21 +0530 Subject: [PATCH 1875/3892] mac80211: Deny TX BA session requests during disassociation In associated state, when bringing an interface down, existing BA sessions are torn down. When this is in progress, nothing prevents mac80211 from accepting another BA session start request. Use a new station flag to fix this. Signed-off-by: Sujith Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 8 ++++++++ net/mac80211/mlme.c | 4 +++- net/mac80211/sta_info.h | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 718fbcff84d2..5538e1b4a697 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -237,6 +237,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) sdata->vif.type != NL80211_IFTYPE_AP) return -EINVAL; + if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Disassociation is in progress. " + "Denying BA session request\n"); +#endif + return -EINVAL; + } + if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Suspend in progress. " diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ee9443dc20ff..bfc4a5070013 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -797,8 +797,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); sta = sta_info_get(sdata, bssid); - if (sta) + if (sta) { + set_sta_flags(sta, WLAN_STA_DISASSOC); ieee80211_sta_tear_down_BA_sessions(sta); + } rcu_read_unlock(); changed |= ieee80211_reset_erp_info(sdata); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5ff611a35979..822d84522937 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -42,6 +42,9 @@ * be in the queues * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping * station in power-save mode, reply when the driver unblocks. + * @WLAN_STA_DISASSOC: Disassociation in progress. + * This is used to reject TX BA session requests when disassociation + * is in progress. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -57,6 +60,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_SUSPEND = 1<<11, WLAN_STA_PS_DRIVER = 1<<12, WLAN_STA_PSPOLL = 1<<13, + WLAN_STA_DISASSOC = 1<<14, }; #define STA_TID_NUM 16 -- GitLab From a0db28b898266265c1cc2ff84f041a561a265504 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sun, 7 Feb 2010 06:23:53 +0000 Subject: [PATCH 1876/3892] sky2: resume clocks Change the resume path to use pci write config for a couple of reasons: 1. pci_write_config_dword() allows for more error checking of PCI health after resume. 2. better to toggle this register on all chip types, since that is what vendor driver does. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 744362272e2d..1593ed49e8fe 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4859,10 +4859,11 @@ static int sky2_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); /* Re-enable all clocks */ - if (hw->chip_id == CHIP_ID_YUKON_EX || - hw->chip_id == CHIP_ID_YUKON_EC_U || - hw->chip_id == CHIP_ID_YUKON_FE_P) - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + err = pci_write_config_dword(pdev, PCI_DEV_REG3, 0); + if (err) { + dev_err(&pdev->dev, "PCI write config failed\n"); + goto out; + } sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); -- GitLab From acd12dde26eef5186a9d2ead9399d136932d2398 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sun, 7 Feb 2010 06:24:50 +0000 Subject: [PATCH 1877/3892] sky2: disable ASF on Yukon Supreme Clone of vendor code to disable ASF on Extreme and Supreme chips. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1593ed49e8fe..1aa1f3316702 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3035,11 +3035,20 @@ static void sky2_reset(struct sky2_hw *hw) u32 hwe_mask = Y2_HWE_ALL_MASK; /* disable ASF */ - if (hw->chip_id == CHIP_ID_YUKON_EX) { + if (hw->chip_id == CHIP_ID_YUKON_EX + || hw->chip_id == CHIP_ID_YUKON_SUPR) { + sky2_write32(hw, CPU_WDOG, 0); status = sky2_read16(hw, HCU_CCSR); status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE | HCU_CCSR_UC_STATE_MSK); + /* + * CPU clock divider shouldn't be used because + * - ASF firmware may malfunction + * - Yukon-Supreme: Parallel FLASH doesn't support divided clocks + */ + status &= ~HCU_CCSR_CPU_CLK_DIVIDE_MSK; sky2_write16(hw, HCU_CCSR, status); + sky2_write32(hw, CPU_WDOG, 0); } else sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE); -- GitLab From 375c568844e49d292885c7485d4a255f71680e56 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sun, 7 Feb 2010 06:28:36 +0000 Subject: [PATCH 1878/3892] sky2: receive checksum refactoring Break the largish case for handling receive checksum into a separate function, and if there is a problem use dev_XXX routines to show which hardware is the problem. Turn one corner case into a BUG(). This only happens if the driver is expecting one behavior but the chip does the old behavior; only ever saw this when bringing up a new chip type and driver was buggy. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 59 ++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1aa1f3316702..478288b8bc21 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2484,6 +2484,32 @@ static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port, } } +static void sky2_rx_checksum(struct sky2_port *sky2, u32 status) +{ + /* If this happens then driver assuming wrong format for chip type */ + BUG_ON(sky2->hw->flags & SKY2_HW_NEW_LE); + + /* Both checksum counters are programmed to start at + * the same offset, so unless there is a problem they + * should match. This failure is an early indication that + * hardware receive checksumming won't work. + */ + if (likely((u16)(status >> 16) == (u16)status)) { + struct sk_buff *skb = sky2->rx_ring[sky2->rx_next].skb; + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = le16_to_cpu(status); + } else { + dev_notice(&sky2->hw->pdev->dev, + "%s: receive checksum problem (status = %#x)\n", + sky2->netdev->name, status); + + /* Disable checksum offload */ + sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), + BMU_DIS_RX_CHKSUM); + } +} + /* Process status response ring */ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) { @@ -2552,37 +2578,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* fall through */ #endif case OP_RXCHKS: - if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) - break; - - /* If this happens then driver assuming wrong format */ - if (unlikely(hw->flags & SKY2_HW_NEW_LE)) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: unexpected" - " checksum status\n", - dev->name); - break; - } - - /* Both checksum counters are programmed to start at - * the same offset, so unless there is a problem they - * should match. This failure is an early indication that - * hardware receive checksumming won't work. - */ - if (likely(status >> 16 == (status & 0xffff))) { - skb = sky2->rx_ring[sky2->rx_next].skb; - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = le16_to_cpu(status); - } else { - printk(KERN_NOTICE PFX "%s: hardware receive " - "checksum problem (status = %#x)\n", - dev->name, status); - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; - - sky2_write32(sky2->hw, - Q_ADDR(rxqaddr[port], Q_CSR), - BMU_DIS_RX_CHKSUM); - } + if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) + sky2_rx_checksum(sky2, status); break; case OP_TXINDEXLE: -- GitLab From 15682bc488d4af8c9bb998844a94281025e0a333 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Wed, 10 Feb 2010 20:03:05 -0800 Subject: [PATCH 1879/3892] ethtool: Introduce n-tuple filter programming support This patchset enables the ethtool layer to program n-tuple filters to an underlying device. The idea is to allow capable hardware to have static rules applied that can assist steering flows into appropriate queues. Hardware that is known to support these types of filters today are ixgbe and niu. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/ethtool.h | 50 ++++++ include/linux/netdevice.h | 3 + net/core/dev.c | 5 + net/core/ethtool.c | 329 +++++++++++++++++++++++++++++++++++++- 4 files changed, 386 insertions(+), 1 deletion(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ef4a2d84d922..a3cac53a0766 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -14,6 +14,7 @@ #define _LINUX_ETHTOOL_H #include +#include /* This should work for both 32 and 64 bit userland. */ struct ethtool_cmd { @@ -242,6 +243,7 @@ enum ethtool_stringset { ETH_SS_TEST = 0, ETH_SS_STATS, ETH_SS_PRIV_FLAGS, + ETH_SS_NTUPLE_FILTERS, }; /* for passing string sets for data tagging */ @@ -290,6 +292,7 @@ struct ethtool_perm_addr { */ enum ethtool_flags { ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ + ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */ }; /* The following structures are for supporting RX network flow @@ -363,6 +366,35 @@ struct ethtool_rxnfc { __u32 rule_locs[0]; }; +struct ethtool_rx_ntuple_flow_spec { + __u32 flow_type; + union { + struct ethtool_tcpip4_spec tcp_ip4_spec; + struct ethtool_tcpip4_spec udp_ip4_spec; + struct ethtool_tcpip4_spec sctp_ip4_spec; + struct ethtool_ah_espip4_spec ah_ip4_spec; + struct ethtool_ah_espip4_spec esp_ip4_spec; + struct ethtool_rawip4_spec raw_ip4_spec; + struct ethtool_ether_spec ether_spec; + struct ethtool_usrip4_spec usr_ip4_spec; + __u8 hdata[64]; + } h_u, m_u; /* entry, mask */ + + __u16 vlan_tag; + __u16 vlan_tag_mask; + __u64 data; /* user-defined flow spec data */ + __u64 data_mask; /* user-defined flow spec mask */ + + /* signed to distinguish between queue and actions (DROP) */ + __s32 action; +#define ETHTOOL_RXNTUPLE_ACTION_DROP -1 +}; + +struct ethtool_rx_ntuple { + __u32 cmd; + struct ethtool_rx_ntuple_flow_spec fs; +}; + #define ETHTOOL_FLASH_MAX_FILENAME 128 enum ethtool_flash_op_type { ETHTOOL_FLASH_ALL_REGIONS = 0, @@ -377,6 +409,18 @@ struct ethtool_flash { #ifdef __KERNEL__ +struct ethtool_rx_ntuple_flow_spec_container { + struct ethtool_rx_ntuple_flow_spec fs; + struct list_head list; +}; + +struct ethtool_rx_ntuple_list { +#define ETHTOOL_MAX_NTUPLE_LIST_ENTRY 1024 +#define ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY 14 + struct list_head list; + unsigned int count; +}; + struct net_device; /* Some generic methods drivers may use in their ethtool_ops */ @@ -394,6 +438,7 @@ u32 ethtool_op_get_ufo(struct net_device *dev); int ethtool_op_set_ufo(struct net_device *dev, u32 data); u32 ethtool_op_get_flags(struct net_device *dev); int ethtool_op_set_flags(struct net_device *dev, u32 data); +void ethtool_ntuple_flush(struct net_device *dev); /** * ðtool_ops - Alter and report network device settings @@ -500,6 +545,8 @@ struct ethtool_ops { int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); int (*flash_device)(struct net_device *, struct ethtool_flash *); int (*reset)(struct net_device *, u32 *); + int (*set_rx_ntuple)(struct net_device *, struct ethtool_rx_ntuple *); + int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *); }; #endif /* __KERNEL__ */ @@ -559,6 +606,9 @@ struct ethtool_ops { #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ #define ETHTOOL_RESET 0x00000034 /* Reset hardware */ +#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ +#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ + /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_SSET ETHTOOL_SSET diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e535700a3b72..cdf53a8d9ff5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -746,6 +746,7 @@ struct net_device { #define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ #define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */ #define NETIF_F_FCOE_MTU (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/ +#define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 @@ -954,6 +955,8 @@ struct net_device { /* max exchange id for FCoE LRO by ddp */ unsigned int fcoe_ddp_xid; #endif + /* n-tuple filter list attached to this device */ + struct ethtool_rx_ntuple_list ethtool_ntuple_list; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/net/core/dev.c b/net/core/dev.c index 94c1eeed25e5..ae75f25ac0a5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5419,6 +5419,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, netdev_init_queues(dev); + INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list); + dev->ethtool_ntuple_list.count = 0; INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); INIT_LIST_HEAD(&dev->link_watch_list); @@ -5455,6 +5457,9 @@ void free_netdev(struct net_device *dev) /* Flush device addresses */ dev_addr_flush(dev); + /* Clear ethtool n-tuple list */ + ethtool_ntuple_flush(dev); + list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) netif_napi_del(p); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d8aee584e8d1..6ec73d3983a3 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -120,7 +120,7 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data) * NETIF_F_xxx values in include/linux/netdevice.h */ static const u32 flags_dup_features = - ETH_FLAG_LRO; + (ETH_FLAG_LRO | ETH_FLAG_NTUPLE); u32 ethtool_op_get_flags(struct net_device *dev) { @@ -139,9 +139,26 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data) else dev->features &= ~NETIF_F_LRO; + if (data & ETH_FLAG_NTUPLE) + dev->features |= NETIF_F_NTUPLE; + else + dev->features &= ~NETIF_F_NTUPLE; + return 0; } +void ethtool_ntuple_flush(struct net_device *dev) +{ + struct ethtool_rx_ntuple_flow_spec_container *fsc, *f; + + list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) { + list_del(&fsc->list); + kfree(fsc); + } + dev->ethtool_ntuple_list.count = 0; +} +EXPORT_SYMBOL(ethtool_ntuple_flush); + /* Handlers for each ethtool command */ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) @@ -266,6 +283,307 @@ err_out: return ret; } +static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, + struct ethtool_rx_ntuple_flow_spec *spec) +{ + struct ethtool_rx_ntuple_flow_spec_container *fsc; + + /* don't add filters forever */ + if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) + return 0; + + fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); + if (!fsc) + return -ENOMEM; + + /* Copy the whole filter over */ + fsc->fs.flow_type = spec->flow_type; + memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u)); + memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u)); + + fsc->fs.vlan_tag = spec->vlan_tag; + fsc->fs.vlan_tag_mask = spec->vlan_tag_mask; + fsc->fs.data = spec->data; + fsc->fs.data_mask = spec->data_mask; + fsc->fs.action = spec->action; + + /* add to the list */ + list_add_tail_rcu(&fsc->list, &list->list); + list->count++; + + return 0; +} + +static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_rx_ntuple cmd; + const struct ethtool_ops *ops = dev->ethtool_ops; + int ret; + + if (!ops->set_rx_ntuple) + return -EOPNOTSUPP; + + if (!(dev->features & NETIF_F_NTUPLE)) + return -EINVAL; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + ret = ops->set_rx_ntuple(dev, &cmd); + + /* + * Cache filter in dev struct for GET operation only if + * the underlying driver doesn't have its own GET operation, and + * only if the filter was added successfully. + */ + if (!ops->get_rx_ntuple && !ret) + if (__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs)) + return -ENOMEM; + + return ret; +} + +static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_gstrings gstrings; + const struct ethtool_ops *ops = dev->ethtool_ops; + struct ethtool_rx_ntuple_flow_spec_container *fsc; + u8 *data; + char *p; + int ret, i, num_strings = 0; + + if (!ops->get_sset_count) + return -EOPNOTSUPP; + + if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) + return -EFAULT; + + ret = ops->get_sset_count(dev, gstrings.string_set); + if (ret < 0) + return ret; + + gstrings.len = ret; + + data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); + if (!data) + return -ENOMEM; + + if (ops->get_rx_ntuple) { + /* driver-specific filter grab */ + ret = ops->get_rx_ntuple(dev, gstrings.string_set, data); + goto copy; + } + + /* default ethtool filter grab */ + i = 0; + p = (char *)data; + list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) { + sprintf(p, "Filter %d:\n", i); + p += ETH_GSTRING_LEN; + num_strings++; + + switch (fsc->fs.flow_type) { + case TCP_V4_FLOW: + sprintf(p, "\tFlow Type: TCP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case UDP_V4_FLOW: + sprintf(p, "\tFlow Type: UDP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case SCTP_V4_FLOW: + sprintf(p, "\tFlow Type: SCTP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case AH_ESP_V4_FLOW: + sprintf(p, "\tFlow Type: AH ESP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case ESP_V4_FLOW: + sprintf(p, "\tFlow Type: ESP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case IP_USER_FLOW: + sprintf(p, "\tFlow Type: Raw IP\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case IPV4_FLOW: + sprintf(p, "\tFlow Type: IPv4\n"); + p += ETH_GSTRING_LEN; + num_strings++; + break; + default: + sprintf(p, "\tFlow Type: Unknown\n"); + p += ETH_GSTRING_LEN; + num_strings++; + goto unknown_filter; + }; + + /* now the rest of the filters */ + switch (fsc->fs.flow_type) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + case SCTP_V4_FLOW: + sprintf(p, "\tSrc IP addr: 0x%x\n", + fsc->fs.h_u.tcp_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSrc IP mask: 0x%x\n", + fsc->fs.m_u.tcp_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP addr: 0x%x\n", + fsc->fs.h_u.tcp_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP mask: 0x%x\n", + fsc->fs.m_u.tcp_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSrc Port: %d, mask: 0x%x\n", + fsc->fs.h_u.tcp_ip4_spec.psrc, + fsc->fs.m_u.tcp_ip4_spec.psrc); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest Port: %d, mask: 0x%x\n", + fsc->fs.h_u.tcp_ip4_spec.pdst, + fsc->fs.m_u.tcp_ip4_spec.pdst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tTOS: %d, mask: 0x%x\n", + fsc->fs.h_u.tcp_ip4_spec.tos, + fsc->fs.m_u.tcp_ip4_spec.tos); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case AH_ESP_V4_FLOW: + case ESP_V4_FLOW: + sprintf(p, "\tSrc IP addr: 0x%x\n", + fsc->fs.h_u.ah_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSrc IP mask: 0x%x\n", + fsc->fs.m_u.ah_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP addr: 0x%x\n", + fsc->fs.h_u.ah_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP mask: 0x%x\n", + fsc->fs.m_u.ah_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSPI: %d, mask: 0x%x\n", + fsc->fs.h_u.ah_ip4_spec.spi, + fsc->fs.m_u.ah_ip4_spec.spi); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tTOS: %d, mask: 0x%x\n", + fsc->fs.h_u.ah_ip4_spec.tos, + fsc->fs.m_u.ah_ip4_spec.tos); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case IP_USER_FLOW: + sprintf(p, "\tSrc IP addr: 0x%x\n", + fsc->fs.h_u.raw_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSrc IP mask: 0x%x\n", + fsc->fs.m_u.raw_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP addr: 0x%x\n", + fsc->fs.h_u.raw_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP mask: 0x%x\n", + fsc->fs.m_u.raw_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + break; + case IPV4_FLOW: + sprintf(p, "\tSrc IP addr: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tSrc IP mask: 0x%x\n", + fsc->fs.m_u.usr_ip4_spec.ip4src); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP addr: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tDest IP mask: 0x%x\n", + fsc->fs.m_u.usr_ip4_spec.ip4dst); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.l4_4_bytes, + fsc->fs.m_u.usr_ip4_spec.l4_4_bytes); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tTOS: %d, mask: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.tos, + fsc->fs.m_u.usr_ip4_spec.tos); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tIP Version: %d, mask: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.ip_ver, + fsc->fs.m_u.usr_ip4_spec.ip_ver); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tProtocol: %d, mask: 0x%x\n", + fsc->fs.h_u.usr_ip4_spec.proto, + fsc->fs.m_u.usr_ip4_spec.proto); + p += ETH_GSTRING_LEN; + num_strings++; + break; + }; + sprintf(p, "\tVLAN: %d, mask: 0x%x\n", + fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data); + p += ETH_GSTRING_LEN; + num_strings++; + sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask); + p += ETH_GSTRING_LEN; + num_strings++; + if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) + sprintf(p, "\tAction: Drop\n"); + else + sprintf(p, "\tAction: Direct to queue %d\n", + fsc->fs.action); + p += ETH_GSTRING_LEN; + num_strings++; +unknown_filter: + i++; + } +copy: + /* indicate to userspace how many strings we actually have */ + gstrings.len = num_strings; + ret = -EFAULT; + if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) + goto out; + useraddr += sizeof(gstrings); + if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) + goto out; + ret = 0; + +out: + kfree(data); + return ret; +} + static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) { struct ethtool_regs regs; @@ -313,6 +631,9 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) if (copy_from_user(&reset, useraddr, sizeof(reset))) return -EFAULT; + /* Clear ethtool n-tuple list */ + ethtool_ntuple_flush(dev); + ret = dev->ethtool_ops->reset(dev, &reset.data); if (ret) return ret; @@ -1112,6 +1433,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_RESET: rc = ethtool_reset(dev, useraddr); break; + case ETHTOOL_SRXNTUPLE: + rc = ethtool_set_rx_ntuple(dev, useraddr); + break; + case ETHTOOL_GRXNTUPLE: + rc = ethtool_get_rx_ntuple(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- GitLab From 9a713e7c7cca2f31c89367bb7b48310ab8a3e630 Mon Sep 17 00:00:00 2001 From: Peter Waskiewicz Date: Wed, 10 Feb 2010 16:07:54 +0000 Subject: [PATCH 1880/3892] ixgbe: Add support for the new ethtool n-tuple programming interface This patch adds n-tuple filter programming to 82599. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 4 ++ drivers/net/ixgbe/ixgbe_82599.c | 106 ++++++++++++++++++++++++---- drivers/net/ixgbe/ixgbe_ethtool.c | 111 +++++++++++++++++++++++++++++- drivers/net/ixgbe/ixgbe_main.c | 16 ++++- drivers/net/ixgbe/ixgbe_type.h | 9 +++ 5 files changed, 228 insertions(+), 18 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index bffbe0d52d33..19e94ee155a2 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -453,6 +453,10 @@ extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, struct ixgbe_atr_input *input, u8 queue); +extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + struct ixgbe_atr_input_masks *input_masks, + u16 soft_id, u8 queue); extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan_id); extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index d4ed6adb7975..4fa8633fae3c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1439,6 +1439,9 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) /* Send interrupt when 64 filters are left */ fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + /* Initialize the drop queue to Rx queue 127 */ + fdirctrl |= (127 << IXGBE_FDIRCTRL_DROP_Q_SHIFT); + switch (pballoc) { case IXGBE_FDIR_PBALLOC_64K: /* 2k - 1 perfect filters */ @@ -1628,6 +1631,7 @@ static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream * @input: input stream to modify * @vlan: the VLAN id to load + * @vlan_mask: bitwise mask for the VLAN **/ s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan) { @@ -1641,6 +1645,7 @@ s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan) * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address * @input: input stream to modify * @src_addr: the IP address to load + * @src_addr_mask: bitwise mask for the source IP address **/ s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr) { @@ -1658,6 +1663,7 @@ s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr) * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address * @input: input stream to modify * @dst_addr: the IP address to load + * @dst_addr_mask: bitwise mask for the destination IP address **/ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) { @@ -1680,8 +1686,8 @@ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) * @src_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 src_addr_1, u32 src_addr_2, - u32 src_addr_3, u32 src_addr_4) + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) { input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = @@ -1723,8 +1729,8 @@ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, * @dst_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 dst_addr_1, u32 dst_addr_2, - u32 dst_addr_3, u32 dst_addr_4) + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) { input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = @@ -1761,6 +1767,7 @@ s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, * ixgbe_atr_set_src_port_82599 - Sets the source port * @input: input stream to modify * @src_port: the source port to load + * @src_port_mask: bitwise mask for the source port **/ s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port) { @@ -1774,6 +1781,7 @@ s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port) * ixgbe_atr_set_dst_port_82599 - Sets the destination port * @input: input stream to modify * @dst_port: the destination port to load + * @dst_port_mask: bitwise mask for the destination port **/ s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port) { @@ -1802,7 +1810,7 @@ s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) * @vm_pool: the Virtual Machine pool to load **/ s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, - u8 vm_pool) + u8 vm_pool) { input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; @@ -1826,8 +1834,7 @@ s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) * @input: input stream to search * @vlan: the VLAN id to load **/ -static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, - u16 *vlan) +static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) { *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; @@ -2083,23 +2090,26 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, * ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter * @hw: pointer to hardware structure * @input: input bitstream + * @input_masks: bitwise masks for relevant fields + * @soft_id: software index into the silicon hash tables for filter storage * @queue: queue index to direct traffic to * * Note that the caller to this function must lock before calling, since the * hardware writes must be protected from one another. **/ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, - struct ixgbe_atr_input *input, - u16 soft_id, - u8 queue) + struct ixgbe_atr_input *input, + struct ixgbe_atr_input_masks *input_masks, + u16 soft_id, u8 queue) { u32 fdircmd = 0; u32 fdirhash; - u32 src_ipv4, dst_ipv4; + u32 src_ipv4 = 0, dst_ipv4 = 0; u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4; u16 src_port, dst_port, vlan_id, flex_bytes; u16 bucket_hash; u8 l4type; + u8 fdirm = 0; /* Get our input values */ ixgbe_atr_get_l4type_82599(input, &l4type); @@ -2154,7 +2164,6 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, /* IPv4 */ ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4); IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4); - } ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4); @@ -2163,7 +2172,78 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id | (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT))); IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port | - (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT))); + (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT))); + + /* + * Program the relevant mask registers. If src/dst_port or src/dst_addr + * are zero, then assume a full mask for that field. Also assume that + * a VLAN of 0 is unspecified, so mask that out as well. L4type + * cannot be masked out in this implementation. + * + * This also assumes IPv4 only. IPv6 masking isn't supported at this + * point in time. + */ + if (src_ipv4 == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, 0xffffffff); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask); + + if (dst_ipv4 == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, 0xffffffff); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask); + + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + if (src_port == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, 0xffff); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, + input_masks->src_port_mask); + + if (dst_port == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, + (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) | + (0xffff << 16))); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, + (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) | + (input_masks->dst_port_mask << 16))); + break; + case IXGBE_ATR_L4TYPE_UDP: + if (src_port == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, 0xffff); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, + input_masks->src_port_mask); + + if (dst_port == 0) + IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, + (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) | + (0xffff << 16))); + else + IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, + (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) | + (input_masks->src_port_mask << 16))); + break; + default: + /* this already would have failed above */ + break; + } + + /* Program the last mask register, FDIRM */ + if (input_masks->vlan_id_mask || !vlan_id) + /* Mask both VLAN and VLANP - bits 0 and 1 */ + fdirm |= 0x3; + + if (input_masks->data_mask || !flex_bytes) + /* Flex bytes need masking, so mask the whole thing - bit 4 */ + fdirm |= 0x10; + + /* Now mask VM pool and destination IPv6 - bits 5 and 2 */ + fdirm |= 0x24; + + IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm); fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW; fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 07a9410c08d4..0d234346a4ea 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -979,6 +979,9 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset) return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; + case ETH_SS_NTUPLE_FILTERS: + return (ETHTOOL_MAX_NTUPLE_LIST_ENTRY * + ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY); default: return -EOPNOTSUPP; } @@ -2150,23 +2153,124 @@ static int ixgbe_set_coalesce(struct net_device *netdev, static int ixgbe_set_flags(struct net_device *netdev, u32 data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + bool need_reset = false; ethtool_op_set_flags(netdev, data); - if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) - return 0; - /* if state changes we need to update adapter->flags and reset */ if ((!!(data & ETH_FLAG_LRO)) != (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) { adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED; + need_reset = true; + } + + /* + * Check if Flow Director n-tuple support was enabled or disabled. If + * the state changed, we need to reset. + */ + if ((adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) && + (!(data & ETH_FLAG_NTUPLE))) { + /* turn off Flow Director perfect, set hash and reset */ + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + need_reset = true; + } else if ((!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) && + (data & ETH_FLAG_NTUPLE)) { + /* turn off Flow Director hash, enable perfect and reset */ + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + need_reset = true; + } else { + /* no state change */ + } + + if (need_reset) { if (netif_running(netdev)) ixgbe_reinit_locked(adapter); else ixgbe_reset(adapter); } + return 0; +} + +static int ixgbe_set_rx_ntuple(struct net_device *dev, + struct ethtool_rx_ntuple *cmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ethtool_rx_ntuple_flow_spec fs = cmd->fs; + struct ixgbe_atr_input input_struct; + struct ixgbe_atr_input_masks input_masks; + int target_queue; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + return -EOPNOTSUPP; + + /* + * Don't allow programming if the action is a queue greater than + * the number of online Tx queues. + */ + if ((fs.action >= adapter->num_tx_queues) || + (fs.action < ETHTOOL_RXNTUPLE_ACTION_DROP)) + return -EINVAL; + + memset(&input_struct, 0, sizeof(struct ixgbe_atr_input)); + memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks)); + + input_masks.src_ip_mask = fs.m_u.tcp_ip4_spec.ip4src; + input_masks.dst_ip_mask = fs.m_u.tcp_ip4_spec.ip4dst; + input_masks.src_port_mask = fs.m_u.tcp_ip4_spec.psrc; + input_masks.dst_port_mask = fs.m_u.tcp_ip4_spec.pdst; + input_masks.vlan_id_mask = fs.vlan_tag_mask; + /* only use the lowest 2 bytes for flex bytes */ + input_masks.data_mask = (fs.data_mask & 0xffff); + + switch (fs.flow_type) { + case TCP_V4_FLOW: + ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_TCP); + break; + case UDP_V4_FLOW: + ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_UDP); + break; + case SCTP_V4_FLOW: + ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_SCTP); + break; + default: + return -1; + } + /* Mask bits from the inputs based on user-supplied mask */ + ixgbe_atr_set_src_ipv4_82599(&input_struct, + (fs.h_u.tcp_ip4_spec.ip4src & ~fs.m_u.tcp_ip4_spec.ip4src)); + ixgbe_atr_set_dst_ipv4_82599(&input_struct, + (fs.h_u.tcp_ip4_spec.ip4dst & ~fs.m_u.tcp_ip4_spec.ip4dst)); + /* 82599 expects these to be byte-swapped for perfect filtering */ + ixgbe_atr_set_src_port_82599(&input_struct, + ((ntohs(fs.h_u.tcp_ip4_spec.psrc)) & ~fs.m_u.tcp_ip4_spec.psrc)); + ixgbe_atr_set_dst_port_82599(&input_struct, + ((ntohs(fs.h_u.tcp_ip4_spec.pdst)) & ~fs.m_u.tcp_ip4_spec.pdst)); + + /* VLAN and Flex bytes are either completely masked or not */ + if (!fs.vlan_tag_mask) + ixgbe_atr_set_vlan_id_82599(&input_struct, fs.vlan_tag); + + if (!input_masks.data_mask) + /* make sure we only use the first 2 bytes of user data */ + ixgbe_atr_set_flex_byte_82599(&input_struct, + (fs.data & 0xffff)); + + /* determine if we need to drop or route the packet */ + if (fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) + target_queue = MAX_RX_QUEUES - 1; + else + target_queue = fs.action; + + spin_lock(&adapter->fdir_perfect_lock); + ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, &input_struct, + &input_masks, 0, target_queue); + spin_unlock(&adapter->fdir_perfect_lock); + + return 0; } static const struct ethtool_ops ixgbe_ethtool_ops = { @@ -2204,6 +2308,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_coalesce = ixgbe_set_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = ixgbe_set_flags, + .set_rx_ntuple = ixgbe_set_rx_ntuple, }; void ixgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2a3c8315e357..f04b5396e057 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3253,6 +3253,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter) netif_carrier_off(netdev); + /* clear n-tuple filters that are cached */ + ethtool_ntuple_flush(netdev); + if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); ixgbe_clean_all_tx_rings(adapter); @@ -4187,6 +4190,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; + struct net_device *dev = adapter->netdev; unsigned int rss; #ifdef CONFIG_IXGBE_DCB int j; @@ -4214,10 +4218,18 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE; adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED; - adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + if (dev->features & NETIF_F_NTUPLE) { + /* Flow Director perfect filter enabled */ + adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; + spin_lock_init(&adapter->fdir_perfect_lock); + } else { + /* Flow Director hash filters enabled */ + adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->atr_sample_rate = 20; + } adapter->ring_feature[RING_F_FDIR].indices = IXGBE_MAX_FDIR_INDICES; - adapter->atr_sample_rate = 20; adapter->fdir_pballoc = 0; #ifdef IXGBE_FCOE adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 0db67c19b2c4..2be907466593 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2129,6 +2129,15 @@ struct ixgbe_atr_input { u8 byte_stream[42]; }; +struct ixgbe_atr_input_masks { + u32 src_ip_mask; + u32 dst_ip_mask; + u16 src_port_mask; + u16 dst_port_mask; + u16 vlan_id_mask; + u16 data_mask; +}; + enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, ixgbe_eeprom_spi, -- GitLab From 92eb879ff59c5995bf18f76eb0a00cb7db758e42 Mon Sep 17 00:00:00 2001 From: Peter Waskiewicz Date: Wed, 10 Feb 2010 16:08:13 +0000 Subject: [PATCH 1881/3892] ixgbe: Bump driver version up Driver has gone under significant changes, the version should reflect that. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f04b5396e057..382bf8945d11 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -51,7 +51,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.44-k2" +#define DRV_VERSION "2.0.62-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation."; -- GitLab From 74e7e725e4766a2045708d274d4d07cd4fae8adc Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Sun, 7 Feb 2010 23:10:05 -0800 Subject: [PATCH 1882/3892] Input: mark {corgi,spitz,tosa}kbd drivers deprecated Provided that now keyboards on these devices are fully supported by generic GPIO based matrix keypad driver, mark these hardcoded and difficult to maintain drivers as deprecated. Signed-off-by: Eric Miao Acked-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- Documentation/feature-removal-schedule.txt | 11 +++++++++++ drivers/input/keyboard/Kconfig | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0a46833c1b76..f8dc4d92e114 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -542,3 +542,14 @@ Why: Duplicate functionality with the gspca_zc3xx driver, zc0301 only sensors) wich are also supported by the gspca_zc3xx driver (which supports 53 USB-ID's in total) Who: Hans de Goede + +---------------------------- + +What: corgikbd, spitzkbd, tosakbd driver +When: 2.6.35 +Files: drivers/input/keyboard/{corgi,spitz,tosa}kbd.c +Why: We now have a generic GPIO based matrix keyboard driver that + are fully capable of handling all the keys on these devices. + The original drivers manipulate the GPIO registers directly + and so are difficult to maintain. +Who: Eric Miao diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 616a3916d187..1ad9435d30aa 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -144,13 +144,15 @@ config KEYBOARD_BFIN module will be called bf54x-keys. config KEYBOARD_CORGI - tristate "Corgi keyboard" + tristate "Corgi keyboard (deprecated)" depends on PXA_SHARPSL - default y help Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx series of PDAs. + This driver is now deprecated, use generic GPIO based matrix + keyboard driver instead. + To compile this driver as a module, choose M here: the module will be called corgikbd. @@ -338,13 +340,15 @@ config KEYBOARD_PXA930_ROTARY module will be called pxa930_rotary. config KEYBOARD_SPITZ - tristate "Spitz keyboard" + tristate "Spitz keyboard (deprecated)" depends on PXA_SHARPSL - default y help Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000, SL-C3000 and Sl-C3100 series of PDAs. + This driver is now deprecated, use generic GPIO based matrix + keyboard driver instead. + To compile this driver as a module, choose M here: the module will be called spitzkbd. @@ -411,12 +415,14 @@ config KEYBOARD_TWL4030 module will be called twl4030_keypad. config KEYBOARD_TOSA - tristate "Tosa keyboard" + tristate "Tosa keyboard (deprecated)" depends on MACH_TOSA - default y help Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa) + This driver is now deprecated, use generic GPIO based matrix + keyboard driver instead. + To compile this driver as a module, choose M here: the module will be called tosakbd. -- GitLab From b63de38591605916fff5d483e0bedc65dfe3d395 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Sun, 7 Feb 2010 23:10:05 -0800 Subject: [PATCH 1883/3892] Input: schedule corgi_ssp and corgi_ts to be removed Signed-off-by: Eric Miao Acked-by: Richard Purdie Acked-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- Documentation/feature-removal-schedule.txt | 12 ++++++++++++ drivers/input/touchscreen/Kconfig | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f8dc4d92e114..54d2d7795544 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -553,3 +553,15 @@ Why: We now have a generic GPIO based matrix keyboard driver that The original drivers manipulate the GPIO registers directly and so are difficult to maintain. Who: Eric Miao + +---------------------------- + +What: corgi_ssp and corgi_ts driver +When: 2.6.35 +Files: arch/arm/mach-pxa/corgi_ssp.c, drivers/input/touchscreen/corgi_ts.c +Why: The corgi touchscreen is now deprecated in favour of the generic + ads7846.c driver. The noise reduction technique used in corgi_ts.c, + that's to wait till vsync before ADC sampling, is also integrated into + ads7846 driver now. Provided that the original driver is not generic + and is difficult to maintain, it will be removed later. +Who: Eric Miao diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a1e2d845f680..6457e060ae49 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -90,7 +90,6 @@ config TOUCHSCREEN_CORGI tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)" depends on PXA_SHARPSL select CORGI_SSP_DEPRECATED - default y help Say Y here to enable the driver for the touchscreen on the Sharp SL-C7xx and SL-Cxx00 series of PDAs. -- GitLab From 2b14a808fbbb042d0de323260d939bdf95e9efdf Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 10 Feb 2010 22:13:21 -0800 Subject: [PATCH 1884/3892] Input: sh_keysc - factor out hw access functions Update the sh_keysc driver to factor out the register access functions sh_keysc_read(), sh_keysc_write() together with sh_keysc_level_mode(). This makes the code a bit easier to follow. Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 69 +++++++++++++++++++------------ 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index efcc3a3b9b53..6218b2f02495 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -22,14 +22,6 @@ #include #include -#define KYCR1_OFFS 0x00 -#define KYCR2_OFFS 0x04 -#define KYINDR_OFFS 0x08 -#define KYOUTDR_OFFS 0x0c - -#define KYCR2_IRQ_LEVEL 0x10 -#define KYCR2_IRQ_DISABLED 0x00 - static const struct { unsigned char kymd, keyout, keyin; } sh_keysc_mode[] = { @@ -48,6 +40,37 @@ struct sh_keysc_priv { struct sh_keysc_info pdata; }; +#define KYCR1 0 +#define KYCR2 1 +#define KYINDR 2 +#define KYOUTDR 3 + +#define KYCR2_IRQ_LEVEL 0x10 +#define KYCR2_IRQ_DISABLED 0x00 + +static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr) +{ + return ioread16(p->iomem_base + (reg_nr << 2)); +} + +static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr, + unsigned long value) +{ + iowrite16(value, p->iomem_base + (reg_nr << 2)); +} + +static void sh_keysc_level_mode(struct sh_keysc_priv *p, + unsigned long keys_set) +{ + struct sh_keysc_info *pdata = &p->pdata; + + sh_keysc_write(p, KYOUTDR, 0); + sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8)); + + if (pdata->kycr2_delay) + udelay(pdata->kycr2_delay); +} + static irqreturn_t sh_keysc_isr(int irq, void *dev_id) { struct platform_device *pdev = dev_id; @@ -66,24 +89,19 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) keys = 0; keyin_set = 0; - iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS); + sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED); for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) { - iowrite16(0xfff ^ (3 << (i * 2)), - priv->iomem_base + KYOUTDR_OFFS); + sh_keysc_write(priv, KYOUTDR, 0xfff ^ (3 << (i * 2))); udelay(pdata->delay); - tmp = ioread16(priv->iomem_base + KYINDR_OFFS); + tmp = sh_keysc_read(priv, KYINDR); + keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i); tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1; keyin_set |= tmp; } - iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); - iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8), - priv->iomem_base + KYCR2_OFFS); - - if (pdata->kycr2_delay) - udelay(pdata->kycr2_delay); + sh_keysc_level_mode(priv, keyin_set); keys ^= ~0; keys &= (1 << (sh_keysc_mode[pdata->mode].keyin * @@ -93,7 +111,7 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys); - } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01); + } while (sh_keysc_read(priv, KYCR2) & 0x01); dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n", priv->last_keys, keys0, keys1); @@ -220,10 +238,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) clk_enable(priv->clk); - iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) | - pdata->scan_timing, priv->iomem_base + KYCR1_OFFS); - iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); - iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS); + sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) | + pdata->scan_timing); + sh_keysc_level_mode(priv, 0); device_init_wakeup(&pdev->dev, 1); @@ -248,7 +265,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) { struct sh_keysc_priv *priv = platform_get_drvdata(pdev); - iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS); + sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED); input_unregister_device(priv->input); free_irq(platform_get_irq(pdev, 0), pdev); @@ -270,7 +287,7 @@ static int sh_keysc_suspend(struct device *dev) int irq = platform_get_irq(pdev, 0); unsigned short value; - value = ioread16(priv->iomem_base + KYCR1_OFFS); + value = sh_keysc_read(priv, KYCR1); if (device_may_wakeup(dev)) { value |= 0x80; @@ -279,7 +296,7 @@ static int sh_keysc_suspend(struct device *dev) value &= ~0x80; } - iowrite16(value, priv->iomem_base + KYCR1_OFFS); + sh_keysc_write(priv, KYCR1, value); return 0; } -- GitLab From 324e5ade1569111a40c349726d8a2694b28d7943 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 10 Feb 2010 22:13:21 -0800 Subject: [PATCH 1885/3892] Input: sh_keysc - switch to using bitmaps Use bitmaps instead of using 32-bit integers to keep track of the key states. With this change in place the driver supports key pads with more than 32 keys. Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 69 ++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 6218b2f02495..c2fc97732f0c 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -35,7 +36,7 @@ static const struct { struct sh_keysc_priv { void __iomem *iomem_base; struct clk *clk; - unsigned long last_keys; + DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS); struct input_dev *input; struct sh_keysc_info pdata; }; @@ -71,69 +72,87 @@ static void sh_keysc_level_mode(struct sh_keysc_priv *p, udelay(pdata->kycr2_delay); } +static void sh_keysc_map_dbg(struct device *dev, unsigned long *map, + const char *str) +{ + int k; + + for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++) + dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]); +} + static irqreturn_t sh_keysc_isr(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct sh_keysc_priv *priv = platform_get_drvdata(pdev); struct sh_keysc_info *pdata = &priv->pdata; - unsigned long keys, keys1, keys0, mask; + int keyout_nr = sh_keysc_mode[pdata->mode].keyout; + int keyin_nr = sh_keysc_mode[pdata->mode].keyin; + DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS); + DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS); + DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS); unsigned char keyin_set, tmp; - int i, k; + int i, k, n; dev_dbg(&pdev->dev, "isr!\n"); - keys1 = ~0; - keys0 = 0; + bitmap_fill(keys1, SH_KEYSC_MAXKEYS); + bitmap_zero(keys0, SH_KEYSC_MAXKEYS); do { - keys = 0; + bitmap_zero(keys, SH_KEYSC_MAXKEYS); keyin_set = 0; sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED); - for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) { + for (i = 0; i < keyout_nr; i++) { + n = keyin_nr * i; + + /* drive one KEYOUT pin low, read KEYIN pins */ sh_keysc_write(priv, KYOUTDR, 0xfff ^ (3 << (i * 2))); udelay(pdata->delay); tmp = sh_keysc_read(priv, KYINDR); - keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i); - tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1; - keyin_set |= tmp; + /* set bit if key press has been detected */ + for (k = 0; k < keyin_nr; k++) { + if (tmp & (1 << k)) + __set_bit(n + k, keys); + } + + /* keep track of which KEYIN bits that have been set */ + keyin_set |= tmp ^ ((1 << keyin_nr) - 1); } sh_keysc_level_mode(priv, keyin_set); - keys ^= ~0; - keys &= (1 << (sh_keysc_mode[pdata->mode].keyin * - sh_keysc_mode[pdata->mode].keyout)) - 1; - keys1 &= keys; - keys0 |= keys; + bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS); + bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS); + bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS); - dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys); + sh_keysc_map_dbg(&pdev->dev, keys, "keys"); } while (sh_keysc_read(priv, KYCR2) & 0x01); - dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n", - priv->last_keys, keys0, keys1); + sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys"); + sh_keysc_map_dbg(&pdev->dev, keys0, "keys0"); + sh_keysc_map_dbg(&pdev->dev, keys1, "keys1"); for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { k = pdata->keycodes[i]; if (!k) continue; - mask = 1 << i; - - if (!((priv->last_keys ^ keys0) & mask)) + if (test_bit(i, keys0) == test_bit(i, priv->last_keys)) continue; - if ((keys1 | keys0) & mask) { + if (test_bit(i, keys1) || test_bit(i, keys0)) { input_event(priv->input, EV_KEY, k, 1); - priv->last_keys |= mask; + __set_bit(i, priv->last_keys); } - if (!(keys1 & mask)) { + if (!test_bit(i, keys1)) { input_event(priv->input, EV_KEY, k, 0); - priv->last_keys &= ~mask; + __clear_bit(i, priv->last_keys); } } -- GitLab From 8f8be2439cd368cc6ba94888919ee90b5a26f0cb Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 10 Feb 2010 23:03:22 -0800 Subject: [PATCH 1886/3892] Input: sh_keysc - update the driver with mode 6 Add mode 6 support to the sh_keysc driver. Also update the KYOUTDR mask value to include all 16 register bits. Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 3 ++- include/linux/input/sh_keysc.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index c2fc97732f0c..854e2035cd6e 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -31,6 +31,7 @@ static const struct { [SH_KEYSC_MODE_3] = { 2, 4, 7 }, [SH_KEYSC_MODE_4] = { 3, 6, 6 }, [SH_KEYSC_MODE_5] = { 4, 6, 7 }, + [SH_KEYSC_MODE_6] = { 5, 7, 7 }, }; struct sh_keysc_priv { @@ -109,7 +110,7 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) n = keyin_nr * i; /* drive one KEYOUT pin low, read KEYIN pins */ - sh_keysc_write(priv, KYOUTDR, 0xfff ^ (3 << (i * 2))); + sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2))); udelay(pdata->delay); tmp = sh_keysc_read(priv, KYINDR); diff --git a/include/linux/input/sh_keysc.h b/include/linux/input/sh_keysc.h index 2aff38bcf2ba..649dc7f12925 100644 --- a/include/linux/input/sh_keysc.h +++ b/include/linux/input/sh_keysc.h @@ -1,15 +1,15 @@ #ifndef __SH_KEYSC_H__ #define __SH_KEYSC_H__ -#define SH_KEYSC_MAXKEYS 42 +#define SH_KEYSC_MAXKEYS 49 struct sh_keysc_info { enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3, - SH_KEYSC_MODE_4, SH_KEYSC_MODE_5 } mode; + SH_KEYSC_MODE_4, SH_KEYSC_MODE_5, SH_KEYSC_MODE_6 } mode; int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */ int delay; int kycr2_delay; - int keycodes[SH_KEYSC_MAXKEYS]; + int keycodes[SH_KEYSC_MAXKEYS]; /* KEYIN * KEYOUT */ }; #endif /* __SH_KEYSC_H__ */ -- GitLab From 5deeac99fe1146532eb7c64f9adb17d17628d751 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Wed, 10 Feb 2010 23:18:05 -0800 Subject: [PATCH 1887/3892] Input: rotary-encoder - set gpio direction for each requested gpio Even with the correct pin mux settings, you still need to explicitly set the gpio direction. Call gpio_direction_input() after each requested gpio. Signed-off-by: Andrew Clayton Signed-off-by: Mark Somerville Tested-by: H Hartley Sweeten Acked-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 3b9f588fc747..4ae07935985e 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -152,6 +152,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) goto exit_unregister_input; } + err = gpio_direction_input(pdata->gpio_a); + if (err) { + dev_err(&pdev->dev, "unable to set GPIO %d for input\n", + pdata->gpio_a); + goto exit_unregister_input; + } + err = gpio_request(pdata->gpio_b, DRV_NAME); if (err) { dev_err(&pdev->dev, "unable to request GPIO %d\n", @@ -159,6 +166,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) goto exit_free_gpio_a; } + err = gpio_direction_input(pdata->gpio_b); + if (err) { + dev_err(&pdev->dev, "unable to set GPIO %d for input\n", + pdata->gpio_b); + goto exit_free_gpio_a; + } + /* request the IRQs */ err = request_irq(encoder->irq_a, &rotary_encoder_irq, IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE, -- GitLab From b036f6fb3aa23a52d90da5fc57e0803f08292e82 Mon Sep 17 00:00:00 2001 From: Bastian Blank Date: Wed, 10 Feb 2010 23:06:23 -0800 Subject: [PATCH 1888/3892] Input: wacom - get features from driver info Get the features information from the driver info of the usb device id structure provided by the caller. The device ids and feature structs are strong coupled using indices. Signed-off-by: Bastian Blank Tested-by: Jason Childs Acked-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom.h | 5 +- drivers/input/tablet/wacom_sys.c | 10 +- drivers/input/tablet/wacom_wac.c | 342 ++++++++++++++++++------------- 3 files changed, 205 insertions(+), 152 deletions(-) diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 16310f368dab..8fef1b689c69 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,8 @@ struct wacom_combo { struct urb *urb; }; +extern const struct usb_device_id wacom_ids[]; + extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo); extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data); extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); @@ -142,7 +145,5 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern __u16 wacom_le16_to_cpu(unsigned char *data); extern __u16 wacom_be16_to_cpu(unsigned char *data); -extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id); -extern const struct usb_device_id *get_device_table(void); #endif diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 072f33b3b2b0..be4b76f264a7 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -530,10 +530,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct wacom_wac *wacom_wac; - struct wacom_features *features; + struct wacom_features *features = (void *)id->driver_info; struct input_dev *input_dev; int error = -ENOMEM; + if (!features) + return -EINVAL; + wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); input_dev = input_allocate_device(); @@ -555,7 +558,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); - wacom_wac->features = features = get_wacom_feature(id); + wacom_wac->features = features; BUG_ON(features->pktlen > WACOM_PKGLEN_MAX); input_dev->name = wacom_wac->features->name; @@ -663,6 +666,7 @@ static int wacom_reset_resume(struct usb_interface *intf) static struct usb_driver wacom_driver = { .name = "wacom", + .id_table = wacom_ids, .probe = wacom_probe, .disconnect = wacom_disconnect, .suspend = wacom_suspend, @@ -674,7 +678,7 @@ static struct usb_driver wacom_driver = { static int __init wacom_init(void) { int result; - wacom_driver.id_table = get_device_table(); + result = usb_register(&wacom_driver); if (result == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 1056f149fe31..56aaf0164a56 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -903,153 +903,201 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w return; } -static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER }, - { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }, - { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }, - { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE }, - { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE }, - { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }, - { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 }, - { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 }, - { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }, - { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO }, - { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }, - { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE }, - { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE }, - { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE }, - { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }, - { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }, - { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }, - { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, - { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }, - { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }, - { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL }, - { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL }, - { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL }, - { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL }, - { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL }, - { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL }, - { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL }, - { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }, - { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL }, - { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }, - { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }, - { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }, - { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU }, - { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }, - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, - { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }, - { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }, - { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S }, - { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L }, - { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L }, - { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S }, - { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S }, - { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 }, - { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }, - { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }, - { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }, - { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE }, - { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }, - { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }, - { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC }, - { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }, - { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }, - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, +static struct wacom_features wacom_features_0x00 = + { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER }; +static struct wacom_features wacom_features_0x10 = + { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x11 = + { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x12 = + { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x13 = + { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x14 = + { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x15 = + { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 }; +static struct wacom_features wacom_features_0x16 = + { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 }; +static struct wacom_features wacom_features_0x17 = + { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; +static struct wacom_features wacom_features_0x18 = + { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO }; +static struct wacom_features wacom_features_0x19 = + { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x60 = + { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x61 = + { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x62 = + { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x63 = + { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x64 = + { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x65 = + { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; +static struct wacom_features wacom_features_0x69 = + { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; +static struct wacom_features wacom_features_0x20 = + { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x21 = + { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x22 = + { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x23 = + { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x24 = + { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x30 = + { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL }; +static struct wacom_features wacom_features_0x31 = + { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL }; +static struct wacom_features wacom_features_0x32 = + { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL }; +static struct wacom_features wacom_features_0x33 = + { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL }; +static struct wacom_features wacom_features_0x34 = + { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL }; +static struct wacom_features wacom_features_0x35 = + { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL }; +static struct wacom_features wacom_features_0x37 = + { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL }; +static struct wacom_features wacom_features_0x38 = + { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; +static struct wacom_features wacom_features_0x39 = + { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL }; +static struct wacom_features wacom_features_0xC4 = + { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; +static struct wacom_features wacom_features_0xC0 = + { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; +static struct wacom_features wacom_features_0xC2 = + { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; +static struct wacom_features wacom_features_0x03 = + { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU }; +static struct wacom_features wacom_features_0x41 = + { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x42 = + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x43 = + { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x44 = + { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0x45 = + { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; +static struct wacom_features wacom_features_0xB0 = + { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S }; +static struct wacom_features wacom_features_0xB1 = + { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 }; +static struct wacom_features wacom_features_0xB2 = + { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 }; +static struct wacom_features wacom_features_0xB3 = + { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L }; +static struct wacom_features wacom_features_0xB4 = + { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L }; +static struct wacom_features wacom_features_0xB5 = + { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 }; +static struct wacom_features wacom_features_0xB7 = + { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S }; +static struct wacom_features wacom_features_0xB8 = + { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S }; +static struct wacom_features wacom_features_0xB9 = + { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 }; +static struct wacom_features wacom_features_0xBA = + { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }; +static struct wacom_features wacom_features_0xBB = + { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }; +static struct wacom_features wacom_features_0x3F = + { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }; +static struct wacom_features wacom_features_0xC5 = + { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE }; +static struct wacom_features wacom_features_0xC6 = + { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }; +static struct wacom_features wacom_features_0xC7 = + { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }; +static struct wacom_features wacom_features_0x90 = + { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; +static struct wacom_features wacom_features_0x93 = + { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; +static struct wacom_features wacom_features_0x9A = + { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; +static struct wacom_features wacom_features_0x9F = + { "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC }; +static struct wacom_features wacom_features_0xE2 = + { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; +static struct wacom_features wacom_features_0xE3 = + { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; +static struct wacom_features wacom_features_0x47 = + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + +#define USB_DEVICE_WACOM(prod) \ + USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ + .driver_info = (kernel_ulong_t)&wacom_features_##prod + +const struct usb_device_id wacom_ids[] = { + { USB_DEVICE_WACOM(0x00) }, + { USB_DEVICE_WACOM(0x10) }, + { USB_DEVICE_WACOM(0x11) }, + { USB_DEVICE_WACOM(0x12) }, + { USB_DEVICE_WACOM(0x13) }, + { USB_DEVICE_WACOM(0x14) }, + { USB_DEVICE_WACOM(0x15) }, + { USB_DEVICE_WACOM(0x16) }, + { USB_DEVICE_WACOM(0x17) }, + { USB_DEVICE_WACOM(0x18) }, + { USB_DEVICE_WACOM(0x19) }, + { USB_DEVICE_WACOM(0x60) }, + { USB_DEVICE_WACOM(0x61) }, + { USB_DEVICE_WACOM(0x62) }, + { USB_DEVICE_WACOM(0x63) }, + { USB_DEVICE_WACOM(0x64) }, + { USB_DEVICE_WACOM(0x65) }, + { USB_DEVICE_WACOM(0x69) }, + { USB_DEVICE_WACOM(0x20) }, + { USB_DEVICE_WACOM(0x21) }, + { USB_DEVICE_WACOM(0x22) }, + { USB_DEVICE_WACOM(0x23) }, + { USB_DEVICE_WACOM(0x24) }, + { USB_DEVICE_WACOM(0x30) }, + { USB_DEVICE_WACOM(0x31) }, + { USB_DEVICE_WACOM(0x32) }, + { USB_DEVICE_WACOM(0x33) }, + { USB_DEVICE_WACOM(0x34) }, + { USB_DEVICE_WACOM(0x35) }, + { USB_DEVICE_WACOM(0x37) }, + { USB_DEVICE_WACOM(0x38) }, + { USB_DEVICE_WACOM(0x39) }, + { USB_DEVICE_WACOM(0xC4) }, + { USB_DEVICE_WACOM(0xC0) }, + { USB_DEVICE_WACOM(0xC2) }, + { USB_DEVICE_WACOM(0x03) }, + { USB_DEVICE_WACOM(0x41) }, + { USB_DEVICE_WACOM(0x42) }, + { USB_DEVICE_WACOM(0x43) }, + { USB_DEVICE_WACOM(0x44) }, + { USB_DEVICE_WACOM(0x45) }, + { USB_DEVICE_WACOM(0xB0) }, + { USB_DEVICE_WACOM(0xB1) }, + { USB_DEVICE_WACOM(0xB2) }, + { USB_DEVICE_WACOM(0xB3) }, + { USB_DEVICE_WACOM(0xB4) }, + { USB_DEVICE_WACOM(0xB5) }, + { USB_DEVICE_WACOM(0xB7) }, + { USB_DEVICE_WACOM(0xB8) }, + { USB_DEVICE_WACOM(0xB9) }, + { USB_DEVICE_WACOM(0xBA) }, + { USB_DEVICE_WACOM(0xBB) }, + { USB_DEVICE_WACOM(0x3F) }, + { USB_DEVICE_WACOM(0xC5) }, + { USB_DEVICE_WACOM(0xC6) }, + { USB_DEVICE_WACOM(0xC7) }, + { USB_DEVICE_WACOM(0x90) }, + { USB_DEVICE_WACOM(0x93) }, + { USB_DEVICE_WACOM(0x9A) }, + { USB_DEVICE_WACOM(0x9F) }, + { USB_DEVICE_WACOM(0xE2) }, + { USB_DEVICE_WACOM(0xE3) }, + { USB_DEVICE_WACOM(0x47) }, { } }; - -static struct usb_device_id wacom_ids[] = { - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, - { } -}; - -const struct usb_device_id *get_device_table(void) -{ - const struct usb_device_id *id_table = wacom_ids; - - return id_table; -} - -struct wacom_features * get_wacom_feature(const struct usb_device_id *id) -{ - int index = id - wacom_ids; - struct wacom_features *wf = &wacom_features[index]; - - return wf; -} - MODULE_DEVICE_TABLE(usb, wacom_ids); -- GitLab From 71b38bd4c1cc4f2b653064357e4efab77dfd711d Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Thu, 11 Feb 2010 00:32:57 -0500 Subject: [PATCH 1889/3892] HID: magicmouse: coding style and probe failure fixes Use proper values to initialize bool configuration variables, tabs rather than spaces, no braces for one-line else clause, __set_bit() when the operation doesn't have to be atomic, input_set_abs_params() rather than writing the fields directly, and call hid_hw_stop() when appropriate to handle failures in the probe. Signed-off-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 100 ++++++++++++++--------------------- 1 file changed, 40 insertions(+), 60 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index f94b3e43c5b6..4a3a94f2b10c 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -18,22 +18,22 @@ #include "hid-ids.h" -static bool emulate_3button = 1; +static bool emulate_3button = true; module_param(emulate_3button, bool, 0644); MODULE_PARM_DESC(emulate_3button, "Emulate a middle button"); static int middle_button_start = -350; static int middle_button_stop = +350; -static bool emulate_scroll_wheel = 1; +static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); -static bool report_touches = 1; +static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); -static bool report_undeciphered = 0; +static bool report_undeciphered; module_param(report_undeciphered, bool, 0644); MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); @@ -108,9 +108,9 @@ static int magicmouse_firm_touch(struct magicmouse_sc *msc) static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) { - int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | - test_bit(BTN_RIGHT, msc->input->key) << 1 | - test_bit(BTN_MIDDLE, msc->input->key) << 2; + int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 | + test_bit(BTN_RIGHT, msc->input->key) << 1 | + test_bit(BTN_MIDDLE, msc->input->key) << 2; if (emulate_3button) { int id; @@ -177,7 +177,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_y = y; - msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + msc->scroll_accel = min_t(int, msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); break; case TOUCH_STATE_DRAG: @@ -193,7 +193,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda /* Generate the input events for this touch. */ if (report_touches) { - int orientation = (misc >> 10) - 32; + int orientation = (misc >> 10) - 32; input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); @@ -202,9 +202,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - if (report_undeciphered) { + if (report_undeciphered) input_event(input, EV_MSC, MSC_RAW, tdata[7]); - } input_mt_sync(input); } @@ -291,62 +290,41 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h input->id.version = hdev->version; input->dev.parent = hdev->dev.parent; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_LEFT, input->keybit); - set_bit(BTN_RIGHT, input->keybit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); + __set_bit(BTN_RIGHT, input->keybit); if (emulate_3button) - set_bit(BTN_MIDDLE, input->keybit); - set_bit(BTN_TOOL_FINGER, input->keybit); + __set_bit(BTN_MIDDLE, input->keybit); + __set_bit(BTN_TOOL_FINGER, input->keybit); - set_bit(EV_REL, input->evbit); - set_bit(REL_X, input->relbit); - set_bit(REL_Y, input->relbit); + __set_bit(EV_REL, input->evbit); + __set_bit(REL_X, input->relbit); + __set_bit(REL_Y, input->relbit); if (emulate_scroll_wheel) - set_bit(REL_WHEEL, input->relbit); + __set_bit(REL_WHEEL, input->relbit); if (report_touches) { - set_bit(EV_ABS, input->evbit); - - set_bit(ABS_MT_TRACKING_ID, input->absbit); - input->absmin[ABS_MT_TRACKING_ID] = 0; - input->absmax[ABS_MT_TRACKING_ID] = 15; - input->absfuzz[ABS_MT_TRACKING_ID] = 0; - - set_bit(ABS_MT_TOUCH_MAJOR, input->absbit); - input->absmin[ABS_MT_TOUCH_MAJOR] = 0; - input->absmax[ABS_MT_TOUCH_MAJOR] = 255; - input->absfuzz[ABS_MT_TOUCH_MAJOR] = 4; - - set_bit(ABS_MT_TOUCH_MINOR, input->absbit); - input->absmin[ABS_MT_TOUCH_MINOR] = 0; - input->absmax[ABS_MT_TOUCH_MINOR] = 255; - input->absfuzz[ABS_MT_TOUCH_MINOR] = 4; - - set_bit(ABS_MT_ORIENTATION, input->absbit); - input->absmin[ABS_MT_ORIENTATION] = -32; - input->absmax[ABS_MT_ORIENTATION] = 31; - input->absfuzz[ABS_MT_ORIENTATION] = 1; - - set_bit(ABS_MT_POSITION_X, input->absbit); - input->absmin[ABS_MT_POSITION_X] = -1100; - input->absmax[ABS_MT_POSITION_X] = 1358; - input->absfuzz[ABS_MT_POSITION_X] = 4; - + __set_bit(EV_ABS, input->evbit); + + input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358, + 4, 0); /* Note: Touch Y position from the device is inverted relative * to how pointer motion is reported (and relative to how USB * HID recommends the coordinates work). This driver keeps * the origin at the same position, and just uses the additive * inverse of the reported Y. */ - set_bit(ABS_MT_POSITION_Y, input->absbit); - input->absmin[ABS_MT_POSITION_Y] = -1589; - input->absmax[ABS_MT_POSITION_Y] = 2047; - input->absfuzz[ABS_MT_POSITION_Y] = 4; + input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047, + 4, 0); } if (report_undeciphered) { - set_bit(EV_MSC, input->evbit); - set_bit(MSC_RAW, input->mscbit); + __set_bit(EV_MSC, input->evbit); + __set_bit(MSC_RAW, input->mscbit); } } @@ -385,7 +363,7 @@ static int magicmouse_probe(struct hid_device *hdev, if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); ret = -ENOMEM; - goto err_free; + goto err_stop_hw; } report->size = 6; @@ -394,35 +372,37 @@ static int magicmouse_probe(struct hid_device *hdev, if (ret != sizeof(feature_1)) { dev_err(&hdev->dev, "unable to request touch data (1:%d)\n", ret); - goto err_free; + goto err_stop_hw; } ret = hdev->hid_output_raw_report(hdev, feature_2, sizeof(feature_2), HID_FEATURE_REPORT); if (ret != sizeof(feature_2)) { dev_err(&hdev->dev, "unable to request touch data (2:%d)\n", ret); - goto err_free; + goto err_stop_hw; } input = input_allocate_device(); if (!input) { dev_err(&hdev->dev, "can't alloc input device\n"); ret = -ENOMEM; - goto err_free; + goto err_stop_hw; } magicmouse_setup_input(input, hdev); ret = input_register_device(input); if (ret) { dev_err(&hdev->dev, "input device registration failed\n"); - goto err_both; + goto err_input; } msc->input = input; return 0; - err_both: +err_input: input_free_device(input); - err_free: +err_stop_hw: + hid_hw_stop(hdev); +err_free: kfree(msc); return ret; } -- GitLab From d1e7a03f4fee4059ee3fa7ce0edb7c48c1a75fcf Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:22:28 +0100 Subject: [PATCH 1890/3892] netfilter: ctnetlink: dump expectation helper name Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_netlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 5c103b8c7df0..db35edac307b 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1512,6 +1512,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; + struct nf_conntrack_helper *helper; long timeout = (exp->timeout.expires - jiffies) / HZ; if (timeout < 0) @@ -1528,6 +1529,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); + helper = rcu_dereference(nfct_help(master)->helper); + if (helper) + NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); return 0; -- GitLab From b87921bdf25485afd8f5a5f25e86b5acef32a9cf Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:22:48 +0100 Subject: [PATCH 1891/3892] netfilter: nf_conntrack: show helper and class in /proc/net/nf_conntrack_expect Make the output a bit more informative by showing the helper an expectation belongs to and the expectation class. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_expect.h | 1 + net/netfilter/nf_conntrack_expect.c | 9 +++++++++ net/netfilter/nf_conntrack_sip.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 9a2b9cb52271..917e170fa752 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -66,6 +66,7 @@ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) struct nf_conntrack_expect_policy { unsigned int max_expected; unsigned int timeout; + const char *name; }; #define NF_CT_EXPECT_CLASS_DEFAULT 0 diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 2f25ff610982..33b85f834c06 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -500,6 +500,7 @@ static void exp_seq_stop(struct seq_file *seq, void *v) static int exp_seq_show(struct seq_file *s, void *v) { struct nf_conntrack_expect *expect; + struct nf_conntrack_helper *helper; struct hlist_node *n = v; char *delim = ""; @@ -525,6 +526,14 @@ static int exp_seq_show(struct seq_file *s, void *v) if (expect->flags & NF_CT_EXPECT_INACTIVE) seq_printf(s, "%sINACTIVE", delim); + helper = rcu_dereference(nfct_help(expect->master)->helper); + if (helper) { + seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name); + if (helper->expect_policy[expect->class].name) + seq_printf(s, "/%s", + helper->expect_policy[expect->class].name); + } + return seq_putc(s, '\n'); } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 023966b569bf..419c5cabb332 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1305,14 +1305,17 @@ static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { [SIP_EXPECT_SIGNALLING] = { + .name = "signalling", .max_expected = 1, .timeout = 3 * 60, }, [SIP_EXPECT_AUDIO] = { + .name = "audio", .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, [SIP_EXPECT_VIDEO] = { + .name = "video", .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, -- GitLab From 54101f4f3bed87fa968b57f77f8ff3b09fd88bcf Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:23:12 +0100 Subject: [PATCH 1892/3892] netfilter: nf_conntrack_sip: fix ct_sip_parse_request() REGISTER request parsing When requests are parsed, the "sip:" part of the SIP URI should be skipped. Usually this doesn't matter because address parsing skips forward until after the username part, but in case REGISTER requests it doesn't contain a username and the address can not be parsed. Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_sip.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 419c5cabb332..0ca2f2b5c2fa 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -236,12 +236,13 @@ int ct_sip_parse_request(const struct nf_conn *ct, return 0; /* Find SIP URI */ - limit -= strlen("sip:"); - for (; dptr < limit; dptr++) { + for (; dptr < limit - strlen("sip:"); dptr++) { if (*dptr == '\r' || *dptr == '\n') return -1; - if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) + if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) { + dptr += strlen("sip:"); break; + } } if (!skp_epaddr_len(ct, dptr, limit, &shift)) return 0; -- GitLab From 3b6b9fab42fe98358d70735cf98d43fc18dc79c9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:23:53 +0100 Subject: [PATCH 1893/3892] netfilter: nf_conntrack_sip: pass data offset to NAT functions When using TCP multiple SIP messages might be present in a single packet. A following patch will parse them by setting the dptr to the beginning of each message. The NAT helper needs to reload the dptr value after mangling the packet however, so it needs to know the offset of the message to the beginning of the packet. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_sip.h | 14 ++- net/ipv4/netfilter/nf_nat_sip.c | 101 +++++++++++---------- net/netfilter/nf_conntrack_sip.c | 82 +++++++++-------- 3 files changed, 105 insertions(+), 92 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 23aa2ec6b7b7..2c6950b8bf7e 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -34,10 +34,10 @@ struct sdp_media_type { struct sip_handler { const char *method; unsigned int len; - int (*request)(struct sk_buff *skb, + int (*request)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq); - int (*response)(struct sk_buff *skb, + int (*response)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code); }; @@ -100,33 +100,39 @@ enum sdp_header_types { }; extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, + unsigned int dataoff, const char **dptr, unsigned int *datalen); extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + unsigned int dataoff, const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *exp, unsigned int matchoff, unsigned int matchlen); extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, - const char **dptr, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr); extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, + unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, u_int16_t port); extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, - const char **dptr, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, const union nf_inet_addr *addr); extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, + unsigned int dataoff, const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *rtp_exp, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 07d61a57613c..2454ea5abb79 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -29,7 +29,7 @@ MODULE_DESCRIPTION("SIP NAT helper"); MODULE_ALIAS("ip_nat_sip"); -static unsigned int mangle_packet(struct sk_buff *skb, +static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, const char *buffer, unsigned int buflen) @@ -42,12 +42,12 @@ static unsigned int mangle_packet(struct sk_buff *skb, return 0; /* Reload data pointer and adjust datalen value */ - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); + *dptr = skb->data + dataoff; *datalen += buflen - matchlen; return 1; } -static int map_addr(struct sk_buff *skb, +static int map_addr(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, union nf_inet_addr *addr, __be16 port) @@ -76,11 +76,11 @@ static int map_addr(struct sk_buff *skb, buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport)); - return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); } -static int map_sip_addr(struct sk_buff *skb, +static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, enum sip_header_types type) { @@ -93,16 +93,17 @@ static int map_sip_addr(struct sk_buff *skb, if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, &matchoff, &matchlen, &addr, &port) <= 0) return 1; - return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port); + return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, + &addr, port); } -static unsigned int ip_nat_sip(struct sk_buff *skb, +static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int dataoff, matchoff, matchlen; + unsigned int coff, matchoff, matchlen; union nf_inet_addr addr; __be16 port; int request, in_header; @@ -112,7 +113,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, if (ct_sip_parse_request(ct, *dptr, *datalen, &matchoff, &matchlen, &addr, &port) > 0 && - !map_addr(skb, dptr, datalen, matchoff, matchlen, + !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) return NF_DROP; request = 1; @@ -138,7 +139,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, goto next; } - if (!map_addr(skb, dptr, datalen, matchoff, matchlen, + if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) return NF_DROP; @@ -153,8 +154,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { buflen = sprintf(buffer, "%pI4", &ct->tuplehash[!dir].tuple.dst.u3.ip); - if (!mangle_packet(skb, dptr, datalen, poff, plen, - buffer, buflen)) + if (!mangle_packet(skb, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) return NF_DROP; } @@ -167,8 +168,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { buflen = sprintf(buffer, "%pI4", &ct->tuplehash[!dir].tuple.src.u3.ip); - if (!mangle_packet(skb, dptr, datalen, poff, plen, - buffer, buflen)) + if (!mangle_packet(skb, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) return NF_DROP; } @@ -181,27 +182,27 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; buflen = sprintf(buffer, "%u", ntohs(p)); - if (!mangle_packet(skb, dptr, datalen, poff, plen, - buffer, buflen)) + if (!mangle_packet(skb, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) return NF_DROP; } } next: /* Translate Contact headers */ - dataoff = 0; + coff = 0; in_header = 0; - while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, + while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, SIP_HDR_CONTACT, &in_header, &matchoff, &matchlen, &addr, &port) > 0) { - if (!map_addr(skb, dptr, datalen, matchoff, matchlen, + if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) return NF_DROP; } - if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO)) + if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) || + !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO)) return NF_DROP; return NF_ACCEPT; } @@ -232,7 +233,7 @@ static void ip_nat_sip_expected(struct nf_conn *ct, } } -static unsigned int ip_nat_sip_expect(struct sk_buff *skb, +static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *exp, unsigned int matchoff, @@ -279,8 +280,8 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, if (exp->tuple.dst.u3.ip != exp->saved_ip || exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { buflen = sprintf(buffer, "%pI4:%u", &newip, port); - if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, - buffer, buflen)) + if (!mangle_packet(skb, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) goto err; } return NF_ACCEPT; @@ -290,7 +291,7 @@ err: return NF_DROP; } -static int mangle_content_len(struct sk_buff *skb, +static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; @@ -312,12 +313,13 @@ static int mangle_content_len(struct sk_buff *skb, return 0; buflen = sprintf(buffer, "%u", c_len); - return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); } -static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr, - unsigned int dataoff, unsigned int *datalen, +static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, enum sdp_header_types type, enum sdp_header_types term, char *buffer, int buflen) @@ -326,16 +328,16 @@ static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; - if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term, + if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term, &matchoff, &matchlen) <= 0) return -ENOENT; - return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL; } -static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, - unsigned int dataoff, - unsigned int *datalen, +static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr) @@ -344,16 +346,15 @@ static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, unsigned int buflen; buflen = sprintf(buffer, "%pI4", &addr->ip); - if (mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, + if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term, buffer, buflen)) return 0; - return mangle_content_len(skb, dptr, datalen); + return mangle_content_len(skb, dataoff, dptr, datalen); } -static unsigned int ip_nat_sdp_port(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, +static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, u_int16_t port) @@ -362,16 +363,16 @@ static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int buflen; buflen = sprintf(buffer, "%u", port); - if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) return 0; - return mangle_content_len(skb, dptr, datalen); + return mangle_content_len(skb, dataoff, dptr, datalen); } -static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, - unsigned int dataoff, - unsigned int *datalen, +static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, const union nf_inet_addr *addr) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; @@ -379,12 +380,12 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, /* Mangle session description owner and contact addresses */ buflen = sprintf(buffer, "%pI4", &addr->ip); - if (mangle_sdp_packet(skb, dptr, dataoff, datalen, + if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, buffer, buflen)) return 0; - switch (mangle_sdp_packet(skb, dptr, dataoff, datalen, + switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, buffer, buflen)) { case 0: @@ -401,14 +402,13 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, return 0; } - return mangle_content_len(skb, dptr, datalen); + return mangle_content_len(skb, dataoff, dptr, datalen); } /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ -static unsigned int ip_nat_sdp_media(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, +static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *rtp_exp, struct nf_conntrack_expect *rtcp_exp, unsigned int mediaoff, @@ -456,7 +456,8 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, /* Update media port. */ if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && - !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port)) + !ip_nat_sdp_port(skb, dataoff, dptr, datalen, + mediaoff, medialen, port)) goto err2; return NF_ACCEPT; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 0ca2f2b5c2fa..0ec37d6a2df7 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -50,12 +50,13 @@ module_param(sip_direct_media, int, 0600); MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " "endpoints only (default 1)"); -unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, +unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + unsigned int dataoff, const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *exp, @@ -63,17 +64,17 @@ unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, unsigned int matchlen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); -unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, +unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, - unsigned int dataoff, unsigned int *datalen, + unsigned int sdpoff, enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); -unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, +unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, @@ -82,14 +83,15 @@ unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, - const char **dptr, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int sdpoff, const union nf_inet_addr *addr) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); -unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, +unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *rtp_exp, @@ -729,7 +731,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) spin_unlock_bh(&nf_conntrack_lock); } -static int set_expected_rtp_rtcp(struct sk_buff *skb, +static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, union nf_inet_addr *daddr, __be16 port, enum sip_expectation_classes class, @@ -806,7 +808,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, if (direct_rtp) { nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); if (nf_nat_sdp_port && - !nf_nat_sdp_port(skb, dptr, datalen, + !nf_nat_sdp_port(skb, dataoff, dptr, datalen, mediaoff, medialen, ntohs(rtp_port))) goto err1; } @@ -828,7 +830,8 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) - ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, + ret = nf_nat_sdp_media(skb, dataoff, dptr, datalen, + rtp_exp, rtcp_exp, mediaoff, medialen, daddr); else { if (nf_ct_expect_related(rtp_exp) == 0) { @@ -867,7 +870,7 @@ static const struct sdp_media_type *sdp_media_type(const char *dptr, return NULL; } -static int process_sdp(struct sk_buff *skb, +static int process_sdp(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq) { @@ -942,7 +945,7 @@ static int process_sdp(struct sk_buff *skb, else return NF_DROP; - ret = set_expected_rtp_rtcp(skb, dptr, datalen, + ret = set_expected_rtp_rtcp(skb, dataoff, dptr, datalen, &rtp_addr, htons(port), t->class, mediaoff, medialen); if (ret != NF_ACCEPT) @@ -950,8 +953,9 @@ static int process_sdp(struct sk_buff *skb, /* Update media connection address if present */ if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { - ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, - c_hdr, SDP_HDR_MEDIA, &rtp_addr); + ret = nf_nat_sdp_addr(skb, dataoff, dptr, datalen, + mediaoff, c_hdr, SDP_HDR_MEDIA, + &rtp_addr); if (ret != NF_ACCEPT) return ret; } @@ -961,14 +965,15 @@ static int process_sdp(struct sk_buff *skb, /* Update session connection and owner addresses */ nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr); + ret = nf_nat_sdp_session(skb, dataoff, dptr, datalen, sdpoff, + &rtp_addr); if (ret == NF_ACCEPT && i > 0) help->help.ct_sip_info.invite_cseq = cseq; return ret; } -static int process_invite_response(struct sk_buff *skb, +static int process_invite_response(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { @@ -978,13 +983,13 @@ static int process_invite_response(struct sk_buff *skb, if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) - return process_sdp(skb, dptr, datalen, cseq); + return process_sdp(skb, dataoff, dptr, datalen, cseq); else if (help->help.ct_sip_info.invite_cseq == cseq) flush_expectations(ct, true); return NF_ACCEPT; } -static int process_update_response(struct sk_buff *skb, +static int process_update_response(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { @@ -994,13 +999,13 @@ static int process_update_response(struct sk_buff *skb, if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) - return process_sdp(skb, dptr, datalen, cseq); + return process_sdp(skb, dataoff, dptr, datalen, cseq); else if (help->help.ct_sip_info.invite_cseq == cseq) flush_expectations(ct, true); return NF_ACCEPT; } -static int process_prack_response(struct sk_buff *skb, +static int process_prack_response(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { @@ -1010,13 +1015,13 @@ static int process_prack_response(struct sk_buff *skb, if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) - return process_sdp(skb, dptr, datalen, cseq); + return process_sdp(skb, dataoff, dptr, datalen, cseq); else if (help->help.ct_sip_info.invite_cseq == cseq) flush_expectations(ct, true); return NF_ACCEPT; } -static int process_bye_request(struct sk_buff *skb, +static int process_bye_request(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq) { @@ -1031,7 +1036,7 @@ static int process_bye_request(struct sk_buff *skb, * signalling connections. The expectation is marked inactive and is activated * when receiving a response indicating success from the registrar. */ -static int process_register_request(struct sk_buff *skb, +static int process_register_request(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq) { @@ -1101,7 +1106,7 @@ static int process_register_request(struct sk_buff *skb, nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) - ret = nf_nat_sip_expect(skb, dptr, datalen, exp, + ret = nf_nat_sip_expect(skb, dataoff, dptr, datalen, exp, matchoff, matchlen); else { if (nf_ct_expect_related(exp) != 0) @@ -1117,7 +1122,7 @@ store_cseq: return ret; } -static int process_register_response(struct sk_buff *skb, +static int process_register_response(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { @@ -1127,7 +1132,7 @@ static int process_register_response(struct sk_buff *skb, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); union nf_inet_addr addr; __be16 port; - unsigned int matchoff, matchlen, dataoff = 0; + unsigned int matchoff, matchlen, coff = 0; unsigned int expires = 0; int in_contact = 0, ret; @@ -1154,7 +1159,7 @@ static int process_register_response(struct sk_buff *skb, while (1) { unsigned int c_expires = expires; - ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, + ret = ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, SIP_HDR_CONTACT, &in_contact, &matchoff, &matchlen, &addr, &port); @@ -1193,13 +1198,13 @@ static const struct sip_handler sip_handlers[] = { SIP_HANDLER("REGISTER", process_register_request, process_register_response), }; -static int process_sip_response(struct sk_buff *skb, +static int process_sip_response(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - unsigned int matchoff, matchlen; - unsigned int code, cseq, dataoff, i; + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; if (*datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; @@ -1213,7 +1218,7 @@ static int process_sip_response(struct sk_buff *skb, cseq = simple_strtoul(*dptr + matchoff, NULL, 10); if (!cseq) return NF_DROP; - dataoff = matchoff + matchlen + 1; + matchend = matchoff + matchlen + 1; for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { const struct sip_handler *handler; @@ -1221,15 +1226,16 @@ static int process_sip_response(struct sk_buff *skb, handler = &sip_handlers[i]; if (handler->response == NULL) continue; - if (*datalen < dataoff + handler->len || - strnicmp(*dptr + dataoff, handler->method, handler->len)) + if (*datalen < matchend + handler->len || + strnicmp(*dptr + matchend, handler->method, handler->len)) continue; - return handler->response(skb, dptr, datalen, cseq, code); + return handler->response(skb, dataoff, dptr, datalen, + cseq, code); } return NF_ACCEPT; } -static int process_sip_request(struct sk_buff *skb, +static int process_sip_request(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; @@ -1254,7 +1260,7 @@ static int process_sip_request(struct sk_buff *skb, if (!cseq) return NF_DROP; - return handler->request(skb, dptr, datalen, cseq); + return handler->request(skb, dataoff, dptr, datalen, cseq); } return NF_ACCEPT; } @@ -1288,13 +1294,13 @@ static int sip_help(struct sk_buff *skb, return NF_ACCEPT; if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) - ret = process_sip_request(skb, &dptr, &datalen); + ret = process_sip_request(skb, dataoff, &dptr, &datalen); else - ret = process_sip_response(skb, &dptr, &datalen); + ret = process_sip_response(skb, dataoff, &dptr, &datalen); if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { nf_nat_sip = rcu_dereference(nf_nat_sip_hook); - if (nf_nat_sip && !nf_nat_sip(skb, &dptr, &datalen)) + if (nf_nat_sip && !nf_nat_sip(skb, dataoff, &dptr, &datalen)) ret = NF_DROP; } -- GitLab From f5b321bd37fbec9188feb1f721ab46a5ac0b35da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:26:19 +0100 Subject: [PATCH 1894/3892] netfilter: nf_conntrack_sip: add TCP support Add TCP support, which is mandated by RFC3261 for all SIP elements. SIP over TCP is similar to UDP, except that messages are delimited by Content-Length: headers and multiple messages may appear in one packet. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_sip.h | 3 +- net/ipv4/netfilter/nf_nat_sip.c | 2 +- net/netfilter/nf_conntrack_sip.c | 205 ++++++++++++++++++--- 3 files changed, 179 insertions(+), 31 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 2c6950b8bf7e..fa9bb8981450 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -84,7 +84,8 @@ enum sip_header_types { SIP_HDR_FROM, SIP_HDR_TO, SIP_HDR_CONTACT, - SIP_HDR_VIA, + SIP_HDR_VIA_UDP, + SIP_HDR_VIA_TCP, SIP_HDR_EXPIRES, SIP_HDR_CONTENT_LENGTH, }; diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 2454ea5abb79..b232e4040dc6 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -122,7 +122,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, /* Translate topmost Via header and parameters */ if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, - SIP_HDR_VIA, NULL, &matchoff, &matchlen, + SIP_HDR_VIA_UDP, NULL, &matchoff, &matchlen, &addr, &port) > 0) { unsigned int matchend, poff, plen, buflen, n; char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 0ec37d6a2df7..1cc75c5a822b 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -287,7 +288,8 @@ static const struct sip_header ct_sip_hdrs[] = { [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), - [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_VIA_UDP] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len), [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), }; @@ -519,6 +521,33 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); +static int ct_sip_parse_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen) +{ + const char *limit = dptr + datalen; + const char *start; + const char *end; + + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); + if (!limit) + limit = dptr + datalen; + + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); + if (!start) + return 0; + start += strlen(name); + + end = ct_sip_header_search(start, limit, ";", strlen(";")); + if (!end) + end = limit; + + *matchoff = start - dptr; + *matchlen = end - start; + return 1; +} + /* Parse address from header parameter and return address, offset and length */ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, @@ -577,6 +606,29 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); +static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + u8 *proto) +{ + unsigned int matchoff, matchlen; + + if (ct_sip_parse_param(ct, dptr, dataoff, datalen, "transport=", + &matchoff, &matchlen)) { + if (!strnicmp(dptr + matchoff, "TCP", strlen("TCP"))) + *proto = IPPROTO_TCP; + else if (!strnicmp(dptr + matchoff, "UDP", strlen("UDP"))) + *proto = IPPROTO_UDP; + else + return 0; + + if (*proto != nf_ct_protonum(ct)) + return 0; + } else + *proto = nf_ct_protonum(ct); + + return 1; +} + /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, * optionally followed by multiple media descriptions. @@ -685,7 +737,7 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, static int refresh_signalling_expectation(struct nf_conn *ct, union nf_inet_addr *addr, - __be16 port, + u8 proto, __be16 port, unsigned int expires) { struct nf_conn_help *help = nfct_help(ct); @@ -697,6 +749,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct, hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { if (exp->class != SIP_EXPECT_SIGNALLING || !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || + exp->tuple.dst.protonum != proto || exp->tuple.dst.u.udp.port != port) continue; if (!del_timer(&exp->timeout)) @@ -1048,6 +1101,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff, struct nf_conntrack_expect *exp; union nf_inet_addr *saddr, daddr; __be16 port; + u8 proto; unsigned int expires = 0; int ret; typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; @@ -1080,6 +1134,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff, if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) return NF_ACCEPT; + if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, *datalen, + &proto) == 0) + return NF_ACCEPT; + if (ct_sip_parse_numerical_param(ct, *dptr, matchoff + matchlen, *datalen, "expires=", NULL, NULL, &expires) < 0) @@ -1099,7 +1157,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff, saddr = &ct->tuplehash[!dir].tuple.src.u3; nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), - saddr, &daddr, IPPROTO_UDP, NULL, &port); + saddr, &daddr, proto, NULL, &port); exp->timeout.expires = sip_timeout * HZ; exp->helper = nfct_help(ct)->helper; exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; @@ -1132,6 +1190,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); union nf_inet_addr addr; __be16 port; + u8 proto; unsigned int matchoff, matchlen, coff = 0; unsigned int expires = 0; int in_contact = 0, ret; @@ -1172,6 +1231,10 @@ static int process_register_response(struct sk_buff *skb, unsigned int dataoff, if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) continue; + if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, + *datalen, &proto) == 0) + continue; + ret = ct_sip_parse_numerical_param(ct, *dptr, matchoff + matchlen, *datalen, "expires=", @@ -1180,7 +1243,8 @@ static int process_register_response(struct sk_buff *skb, unsigned int dataoff, return NF_DROP; if (c_expires == 0) break; - if (refresh_signalling_expectation(ct, &addr, port, c_expires)) + if (refresh_signalling_expectation(ct, &addr, proto, port, + c_expires)) return NF_ACCEPT; } @@ -1265,50 +1329,123 @@ static int process_sip_request(struct sk_buff *skb, unsigned int dataoff, return NF_ACCEPT; } -static int sip_help(struct sk_buff *skb, - unsigned int protoff, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo) +static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, + unsigned int dataoff, const char **dptr, + unsigned int *datalen) +{ + typeof(nf_nat_sip_hook) nf_nat_sip; + int ret; + + if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) + ret = process_sip_request(skb, dataoff, dptr, datalen); + else + ret = process_sip_response(skb, dataoff, dptr, datalen); + + if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { + nf_nat_sip = rcu_dereference(nf_nat_sip_hook); + if (nf_nat_sip && !nf_nat_sip(skb, dataoff, dptr, datalen)) + ret = NF_DROP; + } + + return ret; +} + +static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) { + struct tcphdr *th, _tcph; unsigned int dataoff, datalen; - const char *dptr; + unsigned int matchoff, matchlen, clen; + unsigned int msglen, origlen; + const char *dptr, *end; + s16 diff, tdiff = 0; int ret; - typeof(nf_nat_sip_hook) nf_nat_sip; + + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + return NF_ACCEPT; /* No Data ? */ - dataoff = protoff + sizeof(struct udphdr); + th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return NF_ACCEPT; + dataoff = protoff + th->doff * 4; if (dataoff >= skb->len) return NF_ACCEPT; nf_ct_refresh(ct, skb, sip_timeout * HZ); - if (!skb_is_nonlinear(skb)) - dptr = skb->data + dataoff; - else { + if (skb_is_nonlinear(skb)) { pr_debug("Copy of skbuff not supported yet.\n"); return NF_ACCEPT; } + dptr = skb->data + dataoff; datalen = skb->len - dataoff; if (datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; - if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) - ret = process_sip_request(skb, dataoff, &dptr, &datalen); - else - ret = process_sip_response(skb, dataoff, &dptr, &datalen); + while (1) { + if (ct_sip_get_header(ct, dptr, 0, datalen, + SIP_HDR_CONTENT_LENGTH, + &matchoff, &matchlen) <= 0) + break; - if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { - nf_nat_sip = rcu_dereference(nf_nat_sip_hook); - if (nf_nat_sip && !nf_nat_sip(skb, dataoff, &dptr, &datalen)) - ret = NF_DROP; + clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); + if (dptr + matchoff == end) + break; + + if (end + strlen("\r\n\r\n") > dptr + datalen) + break; + if (end[0] != '\r' || end[1] != '\n' || + end[2] != '\r' || end[3] != '\n') + break; + end += strlen("\r\n\r\n") + clen; + + msglen = origlen = end - dptr; + + ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen); + if (ret != NF_ACCEPT) + break; + diff = msglen - origlen; + tdiff += diff; + + dataoff += msglen; + dptr += msglen; + datalen = datalen + diff - msglen; } return ret; } -static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; -static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; +static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + unsigned int dataoff, datalen; + const char *dptr; + + /* No Data ? */ + dataoff = protoff + sizeof(struct udphdr); + if (dataoff >= skb->len) + return NF_ACCEPT; + + nf_ct_refresh(ct, skb, sip_timeout * HZ); + + if (skb_is_nonlinear(skb)) { + pr_debug("Copy of skbuff not supported yet.\n"); + return NF_ACCEPT; + } + + dptr = skb->data + dataoff; + datalen = skb->len - dataoff; + if (datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; + + return process_sip_msg(skb, ct, dataoff, &dptr, &datalen); +} + +static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; +static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly; static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { [SIP_EXPECT_SIGNALLING] = { @@ -1333,7 +1470,7 @@ static void nf_conntrack_sip_fini(void) int i, j; for (i = 0; i < ports_c; i++) { - for (j = 0; j < 2; j++) { + for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { if (sip[i][j].me == NULL) continue; nf_conntrack_helper_unregister(&sip[i][j]); @@ -1353,14 +1490,24 @@ static int __init nf_conntrack_sip_init(void) memset(&sip[i], 0, sizeof(sip[i])); sip[i][0].tuple.src.l3num = AF_INET; - sip[i][1].tuple.src.l3num = AF_INET6; - for (j = 0; j < 2; j++) { - sip[i][j].tuple.dst.protonum = IPPROTO_UDP; + sip[i][0].tuple.dst.protonum = IPPROTO_UDP; + sip[i][0].help = sip_help_udp; + sip[i][1].tuple.src.l3num = AF_INET; + sip[i][1].tuple.dst.protonum = IPPROTO_TCP; + sip[i][1].help = sip_help_tcp; + + sip[i][2].tuple.src.l3num = AF_INET6; + sip[i][2].tuple.dst.protonum = IPPROTO_UDP; + sip[i][2].help = sip_help_udp; + sip[i][3].tuple.src.l3num = AF_INET6; + sip[i][3].tuple.dst.protonum = IPPROTO_TCP; + sip[i][3].help = sip_help_tcp; + + for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { sip[i][j].tuple.src.u.udp.port = htons(ports[i]); sip[i][j].expect_policy = sip_exp_policy; sip[i][j].expect_class_max = SIP_EXPECT_MAX; sip[i][j].me = THIS_MODULE; - sip[i][j].help = sip_help; tmpname = &sip_names[i][j][0]; if (ports[i] == SIP_PORT) -- GitLab From 010c0b9f34a4c567b431f8b49a58b7332ed42e47 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:27:09 +0100 Subject: [PATCH 1895/3892] netfilter: nf_nat: support mangling a single TCP packet multiple times nf_nat_mangle_tcp_packet() can currently only handle a single mangling per window because it only maintains two sequence adjustment positions: the one before the last adjustment and the one after. This patch makes sequence number adjustment tracking in nf_nat_mangle_tcp_packet() optional and allows a helper to manually update the offsets after the packet has been fully handled. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_helper.h | 32 +++++++++++++++++----- net/ipv4/netfilter/nf_nat_helper.c | 39 ++++++++++++++++----------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h index 4222220920a5..02bb6c29dc3d 100644 --- a/include/net/netfilter/nf_nat_helper.h +++ b/include/net/netfilter/nf_nat_helper.h @@ -7,13 +7,27 @@ struct sk_buff; /* These return true or false. */ -extern int nf_nat_mangle_tcp_packet(struct sk_buff *skb, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - unsigned int match_offset, - unsigned int match_len, - const char *rep_buffer, - unsigned int rep_len); +extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len, bool adjust); + +static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo, + match_offset, match_len, + rep_buffer, rep_len, true); +} + extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, @@ -21,6 +35,10 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, unsigned int match_len, const char *rep_buffer, unsigned int rep_len); + +extern void nf_nat_set_seq_adjust(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + __be32 seq, s16 off); extern int nf_nat_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 7f10a6be0191..4b6af4bb1f50 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -141,6 +141,17 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra) return 1; } +void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + __be32 seq, s16 off) +{ + if (!off) + return; + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); + adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo); + nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); +} +EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust); + /* Generic function for mangling variable-length address changes inside * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX * command in FTP). @@ -149,14 +160,13 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra) * skb enlargement, ... * * */ -int -nf_nat_mangle_tcp_packet(struct sk_buff *skb, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - unsigned int match_offset, - unsigned int match_len, - const char *rep_buffer, - unsigned int rep_len) +int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len, bool adjust) { struct rtable *rt = skb_rtable(skb); struct iphdr *iph; @@ -202,16 +212,13 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, inet_proto_csum_replace2(&tcph->check, skb, htons(oldlen), htons(datalen), 1); - if (rep_len != match_len) { - set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); - adjust_tcp_sequence(ntohl(tcph->seq), - (int)rep_len - (int)match_len, - ct, ctinfo); - nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); - } + if (adjust && rep_len != match_len) + nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, + (int)rep_len - (int)match_len); + return 1; } -EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); +EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet); /* Generic function for mangling variable-length address changes inside * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX -- GitLab From 48f8ac26537c1b7b1a2422f5232f45d06c945348 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:29:38 +0100 Subject: [PATCH 1896/3892] netfilter: nf_nat_sip: add TCP support Add support for mangling TCP SIP packets. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_sip.h | 1 + net/ipv4/netfilter/nf_nat_sip.c | 53 +++++++++++++++++++--- net/netfilter/nf_conntrack_sip.c | 10 ++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index fa9bb8981450..cd84d6f44d11 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -104,6 +104,7 @@ extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen); +extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off); extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b232e4040dc6..11b538deaaec 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -1,4 +1,4 @@ -/* SIP extension for UDP NAT alteration. +/* SIP extension for NAT alteration. * * (C) 2005 by Christian Hentschel * based on RR's ip_nat_ftp.c and other modules. @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -36,10 +37,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen, - buffer, buflen)) - return 0; + struct tcphdr *th; + unsigned int baseoff; + + if (nf_ct_protonum(ct) == IPPROTO_TCP) { + th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); + baseoff = ip_hdrlen(skb) + th->doff * 4; + matchoff += dataoff - baseoff; + + if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, + matchoff, matchlen, + buffer, buflen, false)) + return 0; + } else { + baseoff = ip_hdrlen(skb) + sizeof(struct udphdr); + matchoff += dataoff - baseoff; + + if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, + matchoff, matchlen, + buffer, buflen)) + return 0; + } /* Reload data pointer and adjust datalen value */ *dptr = skb->data + dataoff; @@ -104,6 +122,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int coff, matchoff, matchlen; + enum sip_header_types hdr; union nf_inet_addr addr; __be16 port; int request, in_header; @@ -120,9 +139,14 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, } else request = 0; + if (nf_ct_protonum(ct) == IPPROTO_TCP) + hdr = SIP_HDR_VIA_TCP; + else + hdr = SIP_HDR_VIA_UDP; + /* Translate topmost Via header and parameters */ if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, - SIP_HDR_VIA_UDP, NULL, &matchoff, &matchlen, + hdr, NULL, &matchoff, &matchlen, &addr, &port) > 0) { unsigned int matchend, poff, plen, buflen, n; char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; @@ -204,9 +228,23 @@ next: if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) || !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO)) return NF_DROP; + return NF_ACCEPT; } +static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + const struct tcphdr *th; + + if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) + return; + + th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); + nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); +} + /* Handles expected signalling connections and media streams */ static void ip_nat_sip_expected(struct nf_conn *ct, struct nf_conntrack_expect *exp) @@ -472,6 +510,7 @@ err1: static void __exit nf_nat_sip_fini(void) { rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); @@ -483,12 +522,14 @@ static void __exit nf_nat_sip_fini(void) static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); + BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sdp_addr_hook != NULL); BUG_ON(nf_nat_sdp_port_hook != NULL); BUG_ON(nf_nat_sdp_session_hook != NULL); BUG_ON(nf_nat_sdp_media_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 1cc75c5a822b..3bb3aaff76e9 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -56,6 +56,9 @@ unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int dataoff, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); +void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); + unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, unsigned int dataoff, const char **dptr, @@ -1360,6 +1363,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, const char *dptr, *end; s16 diff, tdiff = 0; int ret; + typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) @@ -1415,6 +1419,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, datalen = datalen + diff - msglen; } + if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { + nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook); + if (nf_nat_sip_seq_adjust) + nf_nat_sip_seq_adjust(skb, tdiff); + } + return ret; } -- GitLab From 9d288dffe3a276e1f06ba556845c456d696c5a4f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Feb 2010 12:30:21 +0100 Subject: [PATCH 1897/3892] netfilter: nf_conntrack_sip: add T.38 FAX support Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_sip.h | 1 + include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_sip.c | 28 ++++++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index cd84d6f44d11..ff8cfbcf3b81 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -14,6 +14,7 @@ enum sip_expectation_classes { SIP_EXPECT_SIGNALLING, SIP_EXPECT_AUDIO, SIP_EXPECT_VIDEO, + SIP_EXPECT_IMAGE, __SIP_EXPECT_MAX }; #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 5043d61c99a7..5b7d8835523f 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -70,7 +70,7 @@ union nf_conntrack_help { struct nf_conntrack_helper; /* Must be kept in sync with the classes defined by helpers */ -#define NF_CT_MAX_EXPECT_CLASSES 3 +#define NF_CT_MAX_EXPECT_CLASSES 4 /* nf_conn feature for connections that have a helper */ struct nf_conn_help { diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 3bb3aaff76e9..fbe8ff5a420a 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -907,6 +907,7 @@ err1: static const struct sdp_media_type sdp_media_types[] = { SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO), SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO), + SDP_MEDIA_TYPE("image ", SIP_EXPECT_IMAGE), }; static const struct sdp_media_type *sdp_media_type(const char *dptr, @@ -932,7 +933,6 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - struct nf_conn_help *help = nfct_help(ct); unsigned int matchoff, matchlen; unsigned int mediaoff, medialen; unsigned int sdpoff; @@ -1024,9 +1024,6 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff, ret = nf_nat_sdp_session(skb, dataoff, dptr, datalen, sdpoff, &rtp_addr); - if (ret == NF_ACCEPT && i > 0) - help->help.ct_sip_info.invite_cseq = cseq; - return ret; } static int process_invite_response(struct sk_buff *skb, unsigned int dataoff, @@ -1077,6 +1074,22 @@ static int process_prack_response(struct sk_buff *skb, unsigned int dataoff, return NF_ACCEPT; } +static int process_invite_request(struct sk_buff *skb, unsigned int dataoff, + const char **dptr, unsigned int *datalen, + unsigned int cseq) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + unsigned int ret; + + flush_expectations(ct, true); + ret = process_sdp(skb, dataoff, dptr, datalen, cseq); + if (ret == NF_ACCEPT) + help->help.ct_sip_info.invite_cseq = cseq; + return ret; +} + static int process_bye_request(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int cseq) @@ -1257,7 +1270,7 @@ flush: } static const struct sip_handler sip_handlers[] = { - SIP_HANDLER("INVITE", process_sdp, process_invite_response), + SIP_HANDLER("INVITE", process_invite_request, process_invite_response), SIP_HANDLER("UPDATE", process_sdp, process_update_response), SIP_HANDLER("ACK", process_sdp, NULL), SIP_HANDLER("PRACK", process_sdp, process_prack_response), @@ -1473,6 +1486,11 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, + [SIP_EXPECT_IMAGE] = { + .name = "image", + .max_expected = IP_CT_DIR_MAX, + .timeout = 3 * 60, + }, }; static void nf_conntrack_sip_fini(void) -- GitLab From c3a3e040f01457d2ea4f199f75ca205401001a3b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 11 Feb 2010 17:50:44 +0100 Subject: [PATCH 1898/3892] ALSA: usbmixer - add possibility to remap dB values USB devices tends to represent dB ranges in different way than ALSA expects. Add possibility to override these values and add guessed values for SoundBlaster MP3+. Also rename 'Capture Input Source' control to 'Capture Source' for SoundBlaster MP3+ and Extigy. Signed-off-by: Jaroslav Kysela --- sound/usb/usbmixer.c | 125 +++++++++++++++++++++++--------------- sound/usb/usbmixer_maps.c | 23 +++++-- 2 files changed, 93 insertions(+), 55 deletions(-) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220b99c6..c72ad0c82581 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -123,6 +123,7 @@ struct usb_mixer_elem_info { int channels; int val_type; int min, max, res; + int dBmin, dBmax; int cached; int cache_val[MAX_CHANNELS]; u8 initialized; @@ -194,42 +195,50 @@ enum { */ #include "usbmixer_maps.c" -/* get the mapped name if the unit matches */ -static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) +static const struct usbmix_name_map * +find_map(struct mixer_build *state, int unitid, int control) { - const struct usbmix_name_map *p; + const struct usbmix_name_map *p = state->map; - if (! state->map) - return 0; + if (!p) + return NULL; for (p = state->map; p->id; p++) { - if (p->id == unitid && p->name && - (! control || ! p->control || control == p->control)) { - buflen--; - return strlcpy(buf, p->name, buflen); - } + if (p->id == unitid && + (!control || !p->control || control == p->control)) + return p; } - return 0; + return NULL; } -/* check whether the control should be ignored */ -static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) +/* get the mapped name if the unit matches */ +static int +check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) { - const struct usbmix_name_map *p; + if (!p || !p->name) + return 0; - if (! state->map) + buflen--; + return strlcpy(buf, p->name, buflen); +} + +/* check whether the control should be ignored */ +static inline int +check_ignored_ctl(const struct usbmix_name_map *p) +{ + if (!p || p->name || p->dB) return 0; - for (p = state->map; p->id; p++) { - if (p->id == unitid && ! p->name && - (! control || ! p->control || control == p->control)) { - /* - printk(KERN_DEBUG "ignored control %d:%d\n", - unitid, control); - */ - return 1; - } + return 1; +} + +/* dB mapping */ +static inline void check_mapped_dB(const struct usbmix_name_map *p, + struct usb_mixer_elem_info *cval) +{ + if (p && p->dB) { + cval->dBmin = p->dB->min; + cval->dBmax = p->dB->max; } - return 0; } /* get the mapped selector source name */ @@ -466,20 +475,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, if (size < sizeof(scale)) return -ENOMEM; - /* USB descriptions contain the dB scale in 1/256 dB unit - * while ALSA TLV contains in 1/100 dB unit - */ - scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; - scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; - if (scale[3] <= scale[2]) { - /* something is wrong; assume it's either from/to 0dB */ - if (scale[2] < 0) - scale[3] = 0; - else if (scale[2] > 0) - scale[2] = 0; - else /* totally crap, return an error */ - return -EINVAL; - } + scale[2] = cval->dBmin; + scale[3] = cval->dBmax; if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; @@ -720,6 +717,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->min = default_min; cval->max = cval->min + 1; cval->res = 1; + cval->dBmin = cval->dBmax = 0; if (cval->val_type == USB_MIXER_BOOLEAN || cval->val_type == USB_MIXER_INV_BOOLEAN) { @@ -787,6 +785,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->initialized = 1; } + + /* USB descriptions contain the dB scale in 1/256 dB unit + * while ALSA TLV contains in 1/100 dB unit + */ + cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; + cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; + if (cval->dBmin > cval->dBmax) { + /* something is wrong; assume it's either from/to 0dB */ + if (cval->dBmin < 0) + cval->dBmax = 0; + else if (cval->dBmin > 0) + cval->dBmin = 0; + if (cval->dBmin > cval->dBmax) { + /* totally crap, return an error */ + return -EINVAL; + } + } + return 0; } @@ -912,6 +928,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, int nameid = desc[desc[0] - 1]; struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; + const struct usbmix_name_map *map; control++; /* change from zero-based to 1-based value */ @@ -920,7 +937,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, return; } - if (check_ignored_ctl(state, unitid, control)) + map = find_map(state, unitid, control); + if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); @@ -954,10 +972,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; - len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); + len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); mapped_name = len != 0; if (! len && nameid) - len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); + len = snd_usb_copy_string_desc(state, nameid, + kctl->id.name, sizeof(kctl->id.name)); switch (control) { case USB_FEATURE_MUTE: @@ -995,6 +1014,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + check_mapped_dB(map, cval); } break; @@ -1122,8 +1142,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, unsigned int num_outs = desc[5 + input_pins]; unsigned int i, len; struct snd_kcontrol *kctl; + const struct usbmix_name_map *map; - if (check_ignored_ctl(state, unitid, 0)) + map = find_map(state, unitid, 0); + if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); @@ -1152,7 +1174,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; - len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); + len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (! len) len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (! len) @@ -1342,6 +1364,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned int i, err, nameid, type, len; struct procunit_info *info; struct procunit_value_info *valinfo; + const struct usbmix_name_map *map; static struct procunit_value_info default_value_info[] = { { 0x01, "Switch", USB_MIXER_BOOLEAN }, { 0 } @@ -1371,7 +1394,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned /* FIXME: bitmap might be longer than 8bit */ if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) continue; - if (check_ignored_ctl(state, unitid, valinfo->control)) + map = find_map(state, unitid, valinfo->control); + if (check_ignored_ctl(map)) continue; cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { @@ -1402,8 +1426,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned } kctl->private_free = usb_mixer_elem_free; - if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) - ; + if (check_mapped_name(map, kctl->id.name, + sizeof(kctl->id.name))) + /* nothing */ ; else if (info->name) strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); else { @@ -1542,6 +1567,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi int err; struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; + const struct usbmix_name_map *map; char **namelist; if (! num_ins || desc[0] < 5 + num_ins) { @@ -1557,7 +1583,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi if (num_ins == 1) /* only one ? nonsense! */ return 0; - if (check_ignored_ctl(state, unitid, 0)) + map = find_map(state, unitid, 0); + if (check_ignored_ctl(map)) return 0; cval = kzalloc(sizeof(*cval), GFP_KERNEL); @@ -1612,7 +1639,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi kctl->private_free = usb_mixer_selector_elem_free; nameid = desc[desc[0] - 1]; - len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); + len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (len) ; else if (nameid) diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 77c35885e21c..79e903a60862 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -19,11 +19,16 @@ * */ +struct usbmix_dB_map { + u32 min; + u32 max; +}; struct usbmix_name_map { int id; const char *name; int control; + struct usbmix_dB_map *dB; }; struct usbmix_selector_map { @@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { { 8, "Line Playback" }, /* FU */ /* 9: IT mic */ { 10, "Mic Playback" }, /* FU */ - { 11, "Capture Input Source" }, /* SU */ + { 11, "Capture Source" }, /* SU */ { 12, "Capture" }, /* FU */ /* 13: OT pcm capture */ /* 14: MU (w/o controls) */ @@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { * e.g. no Master and fake PCM volume * Pavel Mihaylov */ +static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ +static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ + static struct usbmix_name_map mp3plus_map[] = { /* 1: IT pcm */ /* 2: IT mic */ @@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { /* 5: OT digital out */ /* 6: OT speaker */ /* 7: OT pcm capture */ - { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ + { 8, "Capture Source" }, /* FU, default PCM Capture Source */ /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ { 9, "Master Playback" }, /* FU, default Speaker 1 */ /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ - /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ + { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 }, + /* FU, Mic Capture */ { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ - { 11, "Line Capture" }, /* FU, default PCM Capture */ + { 11, "Line Capture", .dB = &mp3plus_dB_2 }, + /* FU, default PCM Capture */ { 12, "Digital In Playback" }, /* FU, default PCM 1 */ - /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ - { 14, "Line Playback" }, /* FU, default Speaker */ + { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 }, + /* FU, default Mic Playback */ + { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */ /* 15: MU */ { 0 } /* terminator */ }; -- GitLab From b2907e501945d5d13326a6a7441c13e41cd0e799 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 11 Feb 2010 18:41:35 +0100 Subject: [PATCH 1899/3892] netfilter: xtables: fix mangle tables In POST_ROUTING hook, calling dev_net(in) is going to oops. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/iptable_mangle.c | 4 +++- net/ipv6/netfilter/ip6table_mangle.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 58d7097baa3d..c8333305d631 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -87,7 +87,9 @@ iptable_mangle_hook(unsigned int hook, { if (hook == NF_INET_LOCAL_OUT) return ipt_local_hook(hook, skb, in, out, okfn); - + if (hook == NF_INET_POST_ROUTING) + return ipt_do_table(skb, hook, in, out, + dev_net(out)->ipv4.iptable_mangle); /* PREROUTING/INPUT/FORWARD: */ return ipt_do_table(skb, hook, in, out, dev_net(in)->ipv4.iptable_mangle); diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index dc803b7e8e54..b6216dede52c 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -81,7 +81,9 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, { if (hook == NF_INET_LOCAL_OUT) return ip6t_local_out_hook(hook, skb, out, okfn); - + if (hook == NF_INET_POST_ROUTING) + return ip6t_do_table(skb, hook, in, out, + dev_net(out)->ipv6.ip6table_mangle); /* INPUT/FORWARD */ return ip6t_do_table(skb, hook, in, out, dev_net(in)->ipv6.ip6table_mangle); -- GitLab From dff010ac8e57e43669518a14c0e945dfeb80c2a7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 2 Feb 2010 16:58:34 -0800 Subject: [PATCH 1900/3892] iwlwifi: clear all tx queues when firmware ready Reset and clear all the tx queues when finished downloading runtime uCode and ready to go into operation mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index aebe8c51d3e1..e4794885d079 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -581,6 +581,8 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* reset to 0 to enable all the queue first */ + priv->txq_ctx_active_msk = 0; /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f3d662c8cbcf..a7fa1ad7e6e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -648,6 +648,8 @@ int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* reset to 0 to enable all the queue first */ + priv->txq_ctx_active_msk = 0; /* map qos queues to fifos one-to-one */ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { int ac = iwl5000_default_queue_to_tx_fifo[i]; -- GitLab From a93e7973d0983d22fcbe5f691244736211639fe7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 3 Feb 2010 11:47:19 -0800 Subject: [PATCH 1901/3892] iwlwifi: multiple force reset mode Provide the function to perform different type of uCode reset/reload operation. When uCode detect error and can not fix itself, this iwl_force_reset() function allow driver to perform the necessary reset/reload functions and help to bring uCode back to normal operation state. Currently only 2 type of force reset are available: - reset radio - reload firmware Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-core.c | 44 +++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 9 ++++- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 10 ------ 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d390eef2efe5..500ced452098 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) } EXPORT_SYMBOL(iwl_dump_fh); -void iwl_force_rf_reset(struct iwl_priv *priv) +static void iwl_force_rf_reset(struct iwl_priv *priv) { if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -3356,7 +3356,47 @@ void iwl_force_rf_reset(struct iwl_priv *priv) iwl_internal_short_hw_scan(priv); return; } -EXPORT_SYMBOL(iwl_force_rf_reset); + +#define IWL_DELAY_NEXT_FORCE_RESET (HZ*3) + +int iwl_force_reset(struct iwl_priv *priv, int mode) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EINVAL; + + if (priv->last_force_reset_jiffies && + time_after(priv->last_force_reset_jiffies + + IWL_DELAY_NEXT_FORCE_RESET, jiffies)) { + IWL_DEBUG_INFO(priv, "force reset rejected\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode); + + switch (mode) { + case IWL_RF_RESET: + iwl_force_rf_reset(priv); + break; + case IWL_FW_RESET: + IWL_ERR(priv, "On demand firmware reload\n"); + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + /* + * Keep the restart process from trying to send host + * commands by clearing the INIT status bit + */ + clear_bit(STATUS_READY, &priv->status); + queue_work(priv->workqueue, &priv->restart); + break; + default: + IWL_DEBUG_INFO(priv, "invalid reset request.\n"); + return -EINVAL; + } + priv->last_force_reset_jiffies = jiffies; + + return 0; +} #ifdef CONFIG_PM diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8f0c564e68b0..df558796fbe6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -501,7 +501,7 @@ int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); int iwl_internal_short_hw_scan(struct iwl_priv *priv); -void iwl_force_rf_reset(struct iwl_priv *priv); +int iwl_force_reset(struct iwl_priv *priv, int mode); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 55dc5a866542..9f1d302e3a34 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1035,6 +1035,11 @@ struct iwl_event_log { #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) +enum iwl_reset { + IWL_RF_RESET = 0, + IWL_FW_RESET, +}; + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1066,6 +1071,9 @@ struct iwl_priv { /* storing the jiffies when the plcp error rate is received */ unsigned long plcp_jiffies; + /* force reset */ + unsigned long last_force_reset_jiffies; + /* we allocate array of iwl4965_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ struct iwl_channel_info *channel_info; /* channel info array */ @@ -1087,7 +1095,6 @@ struct iwl_priv { unsigned long scan_start; unsigned long scan_pass_start; unsigned long scan_start_tsf; - unsigned long last_internal_scan_jiffies; void *scan; int scan_bands; struct cfg80211_scan_request *scan_request; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5df66382d922..909d9c9b9ad8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -689,7 +689,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, * Reset the RF radio due to the high plcp * error rate */ - iwl_force_rf_reset(priv); + iwl_force_reset(priv, IWL_RF_RESET); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index f786a407638f..501477464e07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, if (!priv->is_internal_short_scan) priv->next_scan_jiffies = 0; - else - priv->last_internal_scan_jiffies = jiffies; IWL_DEBUG_INFO(priv, "Setting scan to off\n"); @@ -551,8 +549,6 @@ EXPORT_SYMBOL(iwl_mac_hw_scan); * internal short scan, this function should only been called while associated. * It will reset and tune the radio to prevent possible RF related problem */ -#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1) - int iwl_internal_short_hw_scan(struct iwl_priv *priv) { int ret = 0; @@ -572,12 +568,6 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv) ret = -EAGAIN; goto out; } - if (priv->last_internal_scan_jiffies && - time_after(priv->last_internal_scan_jiffies + - IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) { - IWL_DEBUG_SCAN(priv, "internal scan rejected\n"); - goto out; - } priv->scan_bands = 0; if (priv->band == IEEE80211_BAND_5GHZ) -- GitLab From 04cafd7fa74d5f70efc93bef36f118177057ff74 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 3 Feb 2010 11:47:20 -0800 Subject: [PATCH 1902/3892] iwlwifi: add debug function to reset/reload radio/firmware Adding function to force reset radio or reload firmware from debugfs. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index d134301b553c..78298be0bdb6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2223,6 +2223,32 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_force_reset_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int reset, ret; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &reset) != 1) + return -EINVAL; + switch (reset) { + case IWL_RF_RESET: + case IWL_FW_RESET: + ret = iwl_force_reset(priv, reset); + break; + default: + return -EINVAL; + } + return ret ? ret : count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2243,6 +2269,7 @@ DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); DEBUGFS_WRITE_FILE_OPS(internal_scan); DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); +DEBUGFS_WRITE_FILE_OPS(force_reset); /* * Create the debugfs files and directories @@ -2296,6 +2323,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); -- GitLab From 45d427001b5eec03cecaacddb53c73af46bb263e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 3 Feb 2010 12:24:44 -0800 Subject: [PATCH 1903/3892] iwlwifi: check for aggregation frame and queue Error checking for aggregation frames should go into aggregation queue, if aggregation queue not available, use legacy queue instead. Also make sure the aggregation queue is available to activate, if driver and mac80211 is out-of-sync, try to disable the queue and sync-up with mac80211. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 15 ++++++++++++++- drivers/net/wireless/iwlwifi/iwl-tx.c | 18 ++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 6aebcedaca8d..8bf7c20b9d39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -298,10 +298,23 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { + int ret; + if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ieee80211_start_tx_ba_session(sta, tid); + ret = ieee80211_start_tx_ba_session(sta, tid); + if (ret == -EAGAIN) { + /* + * driver and mac80211 is out of sync + * this might be cause by reloading firmware + * stop the tx ba session here + */ + IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n", + tid); + ret = ieee80211_stop_tx_ba_session(sta, tid, + WLAN_BACK_INITIATOR); + } } } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d365d13e3291..3788a3d4ddc2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -806,8 +806,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) + if (info->flags & IEEE80211_TX_CTL_AMPDU && + priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) { txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; + } } txq = &priv->txq[txq_id]; @@ -1328,7 +1330,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) { int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl_tid_data *tid_data; - int ret, write_ptr, read_ptr; + int write_ptr, read_ptr; unsigned long flags; if (!ra) { @@ -1380,13 +1382,17 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; spin_lock_irqsave(&priv->lock, flags); - ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, + /* + * the only reason this call can fail is queue number out of range, + * which can happen if uCode is reloaded and all the station + * information are lost. if it is outside the range, there is no need + * to deactivate the uCode queue, just return "success" to allow + * mac80211 to clean up it own data. + */ + priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); - if (ret) - return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); return 0; -- GitLab From a24dd27c47fcb31ba5c906b66e5cbc28bfa3fa5e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 3 Feb 2010 12:51:07 -0800 Subject: [PATCH 1904/3892] iwlwifi: remove unused op-code in PHY Calibration command Number of calibration op-code are not used by driver, remove those from iwl-commands.h Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index c2f31eb26bef..ab3c77b92cc8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3470,11 +3470,7 @@ enum { IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, IWL_PHY_CALIBRATE_DC_CMD = 8, IWL_PHY_CALIBRATE_LO_CMD = 9, - IWL_PHY_CALIBRATE_RX_BB_CMD = 10, IWL_PHY_CALIBRATE_TX_IQ_CMD = 11, - IWL_PHY_CALIBRATE_RX_IQ_CMD = 12, - IWL_PHY_CALIBRATION_NOISE_CMD = 13, - IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, -- GitLab From 7bfedc59ee350727b115bbc79780c69b114f162d Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Feb 2010 13:47:56 -0800 Subject: [PATCH 1905/3892] iwlwifi: cleanup return values Cleanup return values and removes unnecessary code. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-rx.c | 11 +++-------- drivers/net/wireless/iwlwifi/iwl-tx.c | 21 +++++++-------------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 16 ++++------------ 4 files changed, 17 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index df558796fbe6..530fae8cf16d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -414,13 +414,13 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_cmd_queue_free(struct iwl_priv *priv); int iwl_rx_queue_alloc(struct iwl_priv *priv); void iwl_rx_handle(struct iwl_priv *priv); -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, +void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); void iwl_rx_replenish_now(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -int iwl_rx_queue_restock(struct iwl_priv *priv); +void iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -450,7 +450,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq); -int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); +void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id); void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 909d9c9b9ad8..428c9d689d4c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -123,12 +123,11 @@ EXPORT_SYMBOL(iwl_rx_queue_space); /** * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) { unsigned long flags; u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg; u32 reg; - int ret = 0; spin_lock_irqsave(&q->lock, flags); @@ -161,7 +160,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) exit_unlock: spin_unlock_irqrestore(&q->lock, flags); - return ret; } EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); /** @@ -184,14 +182,13 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, * also updates the memory address in the firmware to reference the new * target buffer. */ -int iwl_rx_queue_restock(struct iwl_priv *priv) +void iwl_rx_queue_restock(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; int write; - int ret = 0; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; @@ -220,10 +217,8 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - ret = iwl_rx_queue_update_write_ptr(priv, rxq); + iwl_rx_queue_update_write_ptr(priv, rxq); } - - return ret; } EXPORT_SYMBOL(iwl_rx_queue_restock); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 3788a3d4ddc2..2199b1bc1c28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -80,14 +80,13 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv, /** * iwl_txq_update_write_ptr - Send new write index to hardware */ -int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u32 reg = 0; - int ret = 0; int txq_id = txq->q.id; if (txq->need_update == 0) - return ret; + return; /* if we're trying to save power */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { @@ -101,7 +100,7 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) txq_id, reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return ret; + return; } iwl_write_direct32(priv, HBUS_TARG_WRPTR, @@ -114,8 +113,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) txq->q.write_ptr | (txq_id << 8)); txq->need_update = 0; - - return ret; } EXPORT_SYMBOL(iwl_txq_update_write_ptr); @@ -731,7 +728,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u8 tid = 0; u8 *qc = NULL; unsigned long flags; - int ret; spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { @@ -951,7 +947,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl_txq_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); /* @@ -965,9 +961,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (sta_priv && sta_priv->client) atomic_inc(&sta_priv->pending_frames); - if (ret) - return ret; - if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); @@ -1006,7 +999,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; - int len, ret; + int len; u32 idx; u16 fix_size; @@ -1103,10 +1096,10 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - ret = iwl_txq_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return ret ? ret : idx; + return idx; } static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index eac2b9a95711..f6e8f45ff7f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -478,7 +478,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u8 wait_write_ptr = 0; u8 *qc = NULL; unsigned long flags; - int rc; spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { @@ -663,12 +662,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - rc = iwl_txq_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); - if (rc) - return rc; - if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { @@ -1063,13 +1059,13 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv, * also updates the memory address in the firmware to reference the new * target buffer. */ -static int iwl3945_rx_queue_restock(struct iwl_priv *priv) +static void iwl3945_rx_queue_restock(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - int write, rc; + int write; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; @@ -1099,12 +1095,8 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - rc = iwl_rx_queue_update_write_ptr(priv, rxq); - if (rc) - return rc; + iwl_rx_queue_update_write_ptr(priv, rxq); } - - return 0; } /** -- GitLab From bbcbb9ef9735c67da303d30bd6beb9e699f0f508 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Tue, 2 Feb 2010 10:57:12 -0800 Subject: [PATCH 1906/3892] iwlwifi: fix scan race There is a problem if an "internal short scan" is in progress when a mac80211 requested scan arrives. If this new scan request arrives within the "next_scan_jiffies" period then driver will immediately return success and complete the scan. The problem here is that the scan has not been fully initialized at this time (is_internal_short_scan is still set to true because of the currently running scan), which results in the scan completion never to be sent to mac80211. At this time also, evan though the internal short scan is still running the state (is_internal_short_scan) will be set to false, so when the internal scan does complete then mac80211 will receive a scan completion. Fix this by checking right away if a scan is in progress when a scan request arrives from mac80211. Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-scan.c | 27 +++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 501477464e07..dd9ff2ed645a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -469,21 +469,6 @@ EXPORT_SYMBOL(iwl_init_scan_params); static int iwl_scan_initiate(struct iwl_priv *priv) { - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); - return -EIO; - } - - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); - return -EAGAIN; - } - - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); - return -EAGAIN; - } - IWL_DEBUG_INFO(priv, "Starting scan...\n"); set_bit(STATUS_SCANNING, &priv->status); priv->is_internal_short_scan = false; @@ -515,6 +500,18 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); + ret = -EAGAIN; + goto out_unlock; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); + ret = -EAGAIN; + goto out_unlock; + } + /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. -- GitLab From 4843b5a731b31916d100cfc5ba4d03ae78462ed9 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 3 Feb 2010 09:38:59 -0800 Subject: [PATCH 1907/3892] iwlwifi: reset card during probe To ensure that card is in a sane state during probe we add a reset call. This change was prompted by users of kdump who was not able to bring up the wireless driver in the kdump kernel. The problem here was that the primary kernel, which is not running at the time, left the wireless card up and running. When the kdump kernel starts it is thus possible to immediately receive interrupts from firmware after registering interrupt, but without being ready to deal with interrupts from firmware yet. Reported-by: Stanislaw Gruszka Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1eff4c5b448..31b156d58d7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3540,6 +3540,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ spin_lock_init(&priv->reg_lock); spin_lock_init(&priv->lock); + + /* + * stop and reset the on-board processor just in case it is in a + * strange state ... like being left stranded by a primary kernel + * and this is now the kdump kernel trying to start up + */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + iwl_hw_detect(priv); IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f6e8f45ff7f0..7af8ab80dcf1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4039,6 +4039,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e spin_lock_init(&priv->reg_lock); spin_lock_init(&priv->lock); + /* + * stop and reset the on-board processor just in case it is in a + * strange state ... like being left stranded by a primary kernel + * and this is now the kdump kernel trying to start up + */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + /*********************** * 4. Read EEPROM * ********************/ -- GitLab From 6c3872e1d52290dcd506473028867cacc6b7393d Mon Sep 17 00:00:00 2001 From: Trieu 'Andrew' Nguyen Date: Mon, 8 Feb 2010 13:53:05 -0800 Subject: [PATCH 1908/3892] iwlwifi: Adjusting PLCP error threshold for 1000 NIC While testing the station with the NIC 1000 family, it is found that the plcp error can easily exceed 50 value in 100mSecs. This creates unneccessary radio reset/tuning. This patch raises the PLCP error threshold of the NIC 1000 from 50 to 200 error count. Signed-off-by: Trieu 'Andrew' Nguyen Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 694ceef88590..3bf2e6e9b2d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -246,7 +246,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, }; @@ -274,7 +274,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9f1d302e3a34..71cf1558e640 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1033,6 +1033,7 @@ struct iwl_event_log { #define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0) #define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) +#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200) #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) enum iwl_reset { -- GitLab From f36d04abe684f9e2b07c6ebe9f77ae20eb5c1e84 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 10 Feb 2010 05:07:45 -0800 Subject: [PATCH 1909/3892] iwlwifi: use dma_alloc_coherent Change pci_alloc_consistent() to dma_alloc_coherent() so we can use GFP_KERNEL flag. Signed-off-by: Stanislaw Gruszka Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-3945.c | 8 +++---- drivers/net/wireless/iwlwifi/iwl-core.c | 12 +++++------ drivers/net/wireless/iwlwifi/iwl-helpers.h | 7 ++++--- drivers/net/wireless/iwlwifi/iwl-rx.c | 21 ++++++++++--------- drivers/net/wireless/iwlwifi/iwl-tx.c | 23 +++++++++++---------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 16 +++++++------- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 57194bbd2762..5913418872ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2470,11 +2470,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) memset((void *)&priv->hw_params, 0, sizeof(struct iwl_hw_params)); - priv->shared_virt = - pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl3945_shared), - &priv->shared_phys); - + priv->shared_virt = dma_alloc_coherent(&priv->pci_dev->dev, + sizeof(struct iwl3945_shared), + &priv->shared_phys, GFP_KERNEL); if (!priv->shared_virt) { IWL_ERR(priv, "failed to allocate pci memory\n"); mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 500ced452098..bd56827b8fef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1670,9 +1670,9 @@ EXPORT_SYMBOL(iwl_set_tx_power); void iwl_free_isr_ict(struct iwl_priv *priv) { if (priv->ict_tbl_vir) { - pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + - PAGE_SIZE, priv->ict_tbl_vir, - priv->ict_tbl_dma); + dma_free_coherent(&priv->pci_dev->dev, + (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, + priv->ict_tbl_vir, priv->ict_tbl_dma); priv->ict_tbl_vir = NULL; } } @@ -1688,9 +1688,9 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv) if (priv->cfg->use_isr_legacy) return 0; /* allocate shrared data table */ - priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * - ICT_COUNT) + PAGE_SIZE, - &priv->ict_tbl_dma); + priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, + (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, + &priv->ict_tbl_dma, GFP_KERNEL); if (!priv->ict_tbl_vir) return -ENOMEM; diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 45af5bbc1c56..51a67fb2e185 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -80,8 +80,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { if (desc->v_addr) - pci_free_consistent(pci_dev, desc->len, - desc->v_addr, desc->p_addr); + dma_free_coherent(&pci_dev->dev, desc->len, + desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; } @@ -89,7 +89,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { - desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr); + desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, + &desc->p_addr, GFP_KERNEL); return (desc->v_addr != NULL) ? 0 : -ENOMEM; } diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 428c9d689d4c..aba8f4c20c1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -345,10 +345,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) } } - pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); + dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; rxq->rb_stts = NULL; } @@ -357,7 +357,7 @@ EXPORT_SYMBOL(iwl_rx_queue_free); int iwl_rx_queue_alloc(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; - struct pci_dev *dev = priv->pci_dev; + struct device *dev = &priv->pci_dev->dev; int i; spin_lock_init(&rxq->lock); @@ -365,12 +365,13 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) INIT_LIST_HEAD(&rxq->rx_used); /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr, + GFP_KERNEL); if (!rxq->bd) goto err_bd; - rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status), - &rxq->rb_stts_dma); + rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma, GFP_KERNEL); if (!rxq->rb_stts) goto err_rb; @@ -387,8 +388,8 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) return 0; err_rb: - pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); + dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); err_bd: return -ENOMEM; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 2199b1bc1c28..d8c11f955e42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -60,7 +60,8 @@ static const u16 default_tid_to_tx_fifo[] = { static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv, struct iwl_dma_ptr *ptr, size_t size) { - ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma); + ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma, + GFP_KERNEL); if (!ptr->addr) return -ENOMEM; ptr->size = size; @@ -73,7 +74,7 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv, if (unlikely(!ptr->addr)) return; - pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma); + dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma); memset(ptr, 0, sizeof(*ptr)); } @@ -129,7 +130,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; + struct device *dev = &priv->pci_dev->dev; int i; if (q->n_bd == 0) @@ -146,8 +147,8 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, priv->hw_params.tfd_size * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); + dma_free_coherent(dev, priv->hw_params.tfd_size * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -176,7 +177,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; + struct device *dev = &priv->pci_dev->dev; int i; if (q->n_bd == 0) @@ -188,8 +189,8 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, priv->hw_params.tfd_size * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); + dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd, + txq->tfds, txq->q.dma_addr); /* deallocate arrays */ kfree(txq->cmd); @@ -280,7 +281,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, static int iwl_tx_queue_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq, u32 id) { - struct pci_dev *dev = priv->pci_dev; + struct device *dev = &priv->pci_dev->dev; size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; /* Driver private data, only for Tx (not command) queues, @@ -299,8 +300,8 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr); - + txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr, + GFP_KERNEL); if (!txq->tfds) { IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz); goto error; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7af8ab80dcf1..3df488a8cf75 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -352,10 +352,10 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv) static void iwl3945_unset_hw_params(struct iwl_priv *priv) { if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl3945_shared), - priv->shared_virt, - priv->shared_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct iwl3945_shared), + priv->shared_virt, + priv->shared_phys); } static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, @@ -1241,10 +1241,10 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx } } - pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); + dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; rxq->rb_stts = NULL; } -- GitLab From a9e10fb9b1c6ad16e73cf2656951fce3a817611e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 9 Feb 2010 08:14:11 -0800 Subject: [PATCH 1910/3892] iwlwifi: clear all the stop_queue flag after load firmware All the queues are awake and ready to use after loading firmware, for firmware reload case, if any queues was stopped before reload, mac80211 will wake those queues after restart hardware, so make sure all the flag used to keep track of the queue status are reset correctly. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-4965.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e4794885d079..17e91ad3496c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -581,6 +581,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* make sure all queue are not stopped */ + memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); + for (i = 0; i < 4; i++) + atomic_set(&priv->queue_stop_count[i], 0); + /* reset to 0 to enable all the queue first */ priv->txq_ctx_active_msk = 0; /* Map each Tx/cmd queue to its corresponding fifo */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a7fa1ad7e6e5..94fc83671f20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -648,6 +648,11 @@ int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* make sure all queue are not stopped */ + memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); + for (i = 0; i < 4; i++) + atomic_set(&priv->queue_stop_count[i], 0); + /* reset to 0 to enable all the queue first */ priv->txq_ctx_active_msk = 0; /* map qos queues to fifos one-to-one */ -- GitLab From 1db5950f1d0b82e07371b211a48317b8972da063 Mon Sep 17 00:00:00 2001 From: Trieu 'Andrew' Nguyen Date: Wed, 10 Feb 2010 10:27:34 -0800 Subject: [PATCH 1911/3892] iwlwifi: Monitor and recover the aggregation TX flow failure This change monitors the tx statistics to detect the drop in throughput. When the throughput drops, the ratio of the actual_ack_count and the expected_ ack_count also drops. At the same time, the aggregated ba_timeout (the number of ba timeout retries) also rises. If the actual_ack_count/expected_ack_count ratio is 0 and the number of ba timeout retries rises to 16, no tx packets (tcp, udp, or ping - icmp) can be delivered. The driver recovers from this situation by reseting the uCode firmware. If the actual_ack_count/expected_ ack_count ratio drops below 50% (but not 0) and the aggregated ba_timeout retries just exceed 5 (but not 16), then the driver can reset the radio to bring the throughput up. Signed-off-by: Trieu 'Andrew' Nguyen Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 14 +++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 46 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 31b156d58d7f..4157c6c8645f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2941,10 +2941,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return ret; case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT(priv, "start Tx\n"); - return iwl_tx_agg_start(priv, sta->addr, tid, ssn); + ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn); + if (ret == 0) { + priv->agg_tids_count++; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); + } + return ret; case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT(priv, "stop Tx\n"); ret = iwl_tx_agg_stop(priv, sta->addr, tid); + if ((ret == 0) && (priv->agg_tids_count > 0)) { + priv->agg_tids_count--; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); + } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; else @@ -3364,6 +3375,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; + priv->agg_tids_count = 0; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 71cf1558e640..f81317d478ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1072,6 +1072,9 @@ struct iwl_priv { /* storing the jiffies when the plcp error rate is received */ unsigned long plcp_jiffies; + /* reporting the number of tids has AGG on. 0 means no AGGREGATION */ + u8 agg_tids_count; + /* force reset */ unsigned long last_force_reset_jiffies; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index aba8f4c20c1b..fed554accedc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -616,6 +616,11 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, #define REG_RECALIB_PERIOD (60) +/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ +#define ACK_CNT_RATIO (50) +#define BA_TIMEOUT_CNT (5) +#define BA_TIMEOUT_MAX (16) + #define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -625,6 +630,9 @@ void iwl_rx_statistics(struct iwl_priv *priv, int combined_plcp_delta; unsigned int plcp_msec; unsigned long plcp_received_jiffies; + int actual_ack_cnt_delta; + int expected_ack_cnt_delta; + int ba_timeout_delta; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(priv->statistics), @@ -639,6 +647,44 @@ void iwl_rx_statistics(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); #endif + actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - + le32_to_cpu(priv->statistics.tx.actual_ack_cnt); + expected_ack_cnt_delta = le32_to_cpu( + pkt->u.stats.tx.expected_ack_cnt) - + le32_to_cpu(priv->statistics.tx.expected_ack_cnt); + ba_timeout_delta = le32_to_cpu( + pkt->u.stats.tx.agg.ba_timeout) - + le32_to_cpu(priv->statistics.tx.agg.ba_timeout); + if ((priv->agg_tids_count > 0) && + (expected_ack_cnt_delta > 0) && + (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) < + ACK_CNT_RATIO) && + (ba_timeout_delta > BA_TIMEOUT_CNT)) { + IWL_DEBUG_RADIO(priv, + "actual_ack_cnt delta = %d, expected_ack_cnt = %d\n", + actual_ack_cnt_delta, expected_ack_cnt_delta); + +#ifdef CONFIG_IWLWIFI_DEBUG + IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", + priv->delta_statistics.tx.rx_detected_cnt); + IWL_DEBUG_RADIO(priv, + "ack_or_ba_timeout_collision delta = %d\n", + priv->delta_statistics.tx.ack_or_ba_timeout_collision); +#endif + IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", + ba_timeout_delta); + if ((actual_ack_cnt_delta == 0) && + (ba_timeout_delta >= + BA_TIMEOUT_MAX)) { + IWL_DEBUG_RADIO(priv, + "call iwl_force_reset(IWL_FW_RESET)\n"); + iwl_force_reset(priv, IWL_FW_RESET); + } else { + IWL_DEBUG_RADIO(priv, + "call iwl_force_reset(IWL_RF_RESET)\n"); + iwl_force_reset(priv, IWL_RF_RESET); + } + } /* * check for plcp_err and trigger radio reset if it exceeds * the plcp error threshold plcp_delta. -- GitLab From 867af973a3b38f2a564d612326efd2694d931f30 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Thu, 11 Feb 2010 16:13:59 +0100 Subject: [PATCH 1912/3892] Add ASoC support for Devkit8000 This patch expands the omap3beagle sound soc for the beagle board clone DevKit8000. Signed-off-by: Thomas Weber Acked-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 8 +++++--- sound/soc/omap/omap3beagle.c | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 61952aa6cd5a..18ebdc7d0a51 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -94,12 +94,14 @@ config SND_OMAP_SOC_OMAP3_PANDORA Say Y if you want to add support for SoC audio on the OMAP3 Pandora. config SND_OMAP_SOC_OMAP3_BEAGLE - tristate "SoC Audio support for OMAP3 Beagle" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE + tristate "SoC Audio support for OMAP3 Beagle and Devkit8000" + depends on TWL4030_CORE && SND_OMAP_SOC + depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000) select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help - Say Y if you want to add support for SoC audio on the Beagleboard. + Say Y if you want to add support for SoC audio on the Beagleboard or + the clone Devkit8000. config SND_OMAP_SOC_ZOOM2 tristate "SoC Audio support for Zoom2" diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index d88ad5ca526c..240e0975dd6a 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -117,11 +117,11 @@ static int __init omap3beagle_soc_init(void) { int ret; - if (!machine_is_omap3_beagle()) { - pr_debug("Not OMAP3 Beagle!\n"); + if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) { + pr_debug("Not OMAP3 Beagle or Devkit8000!\n"); return -ENODEV; } - pr_info("OMAP3 Beagle SoC init\n"); + pr_info("OMAP3 Beagle/Devkit8000 SoC init\n"); omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); if (!omap3beagle_snd_device) { -- GitLab From 8e5574211d96c0552f84c757718475fdb4021be7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 11 Feb 2010 12:14:23 -0800 Subject: [PATCH 1913/3892] ethtool: Use explicit designated initializers for .cmd Initialize the .cmd member of various ethtool using a designated struct initializer rather. This makes things a teeny bit more robust, although the chance of a struct layout changing is extremely remote, and also makes the code a little easier to read. Signed-off-by: Roland Dreier Signed-off-by: David S. Miller --- net/core/ethtool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 6ec73d3983a3..a1280f643bf4 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -163,7 +163,7 @@ EXPORT_SYMBOL(ethtool_ntuple_flush); static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; int err; if (!dev->ethtool_ops->get_settings) @@ -645,7 +645,7 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) { - struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; + struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; if (!dev->ethtool_ops->get_wol) return -EOPNOTSUPP; @@ -779,7 +779,7 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) { - struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; + struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; if (!dev->ethtool_ops->get_coalesce) return -EOPNOTSUPP; @@ -806,7 +806,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) { - struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; + struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM }; if (!dev->ethtool_ops->get_ringparam) return -EOPNOTSUPP; @@ -1160,7 +1160,7 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) static int ethtool_get_value(struct net_device *dev, char __user *useraddr, u32 cmd, u32 (*actor)(struct net_device *)) { - struct ethtool_value edata = { cmd }; + struct ethtool_value edata = { .cmd = cmd }; if (!actor) return -EOPNOTSUPP; -- GitLab From 5b3efd500854d45d305b53c54c97db5970959980 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Thu, 11 Feb 2010 11:50:59 -0800 Subject: [PATCH 1914/3892] x86, ptrace: regset extensions to support xstate Add the xstate regset support which helps extend the kernel ptrace and the core-dump interfaces to support AVX state etc. This regset interface is designed to support all the future state that gets supported using xsave/xrstor infrastructure. Looking at the memory layout saved by "xsave", one can't say which state is represented in the memory layout. This is because if a particular state is in init state, in the xsave hdr it can be represented by bit '0'. And hence we can't really say by the xsave header wether a state is in init state or the state is not saved in the memory layout. And hence the xsave memory layout available through this regset interface uses SW usable bytes [464..511] to convey what state is represented in the memory layout. First 8 bytes of the sw_usable_bytes[464..467] will be set to OS enabled xstate mask(which is same as the 64bit mask returned by the xgetbv's xCR0). The note NT_X86_XSTATE represents the extended state information in the core file, using the above mentioned memory layout. Signed-off-by: Suresh Siddha LKML-Reference: <20100211195614.802495327@sbs-t61.sc.intel.com> Signed-off-by: Hongjiu Lu Cc: Roland McGrath Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/i387.h | 12 +++++- arch/x86/include/asm/user.h | 58 +++++++++++++++++++++++++ arch/x86/include/asm/xsave.h | 2 + arch/x86/kernel/i387.c | 83 ++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ptrace.c | 34 ++++++++++++++- arch/x86/kernel/xsave.c | 1 + include/linux/elf.h | 1 + 7 files changed, 187 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index ebfb8a9e11f7..da2930924501 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -33,8 +33,16 @@ extern void init_thread_xstate(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); extern user_regset_active_fn fpregs_active, xfpregs_active; -extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; -extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; +extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, + xstateregs_get; +extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set, + xstateregs_set; + +/* + * xstateregs_active == fpregs_active. Please refer to the comment + * at the definition of fpregs_active. + */ +#define xstateregs_active fpregs_active extern struct _fpx_sw_bytes fx_sw_reserved; #ifdef CONFIG_IA32_EMULATION diff --git a/arch/x86/include/asm/user.h b/arch/x86/include/asm/user.h index 999873b22e7f..24532c7da3d6 100644 --- a/arch/x86/include/asm/user.h +++ b/arch/x86/include/asm/user.h @@ -1,5 +1,63 @@ +#ifndef _ASM_X86_USER_H +#define _ASM_X86_USER_H + #ifdef CONFIG_X86_32 # include "user_32.h" #else # include "user_64.h" #endif + +#include + +struct user_ymmh_regs { + /* 16 * 16 bytes for each YMMH-reg */ + __u32 ymmh_space[64]; +}; + +struct user_xsave_hdr { + __u64 xstate_bv; + __u64 reserved1[2]; + __u64 reserved2[5]; +}; + +/* + * The structure layout of user_xstateregs, used for exporting the + * extended register state through ptrace and core-dump (NT_X86_XSTATE note) + * interfaces will be same as the memory layout of xsave used by the processor + * (except for the bytes 464..511, which can be used by the software) and hence + * the size of this structure varies depending on the features supported by the + * processor and OS. The size of the structure that users need to use can be + * obtained by doing: + * cpuid_count(0xd, 0, &eax, &ptrace_xstateregs_struct_size, &ecx, &edx); + * i.e., cpuid.(eax=0xd,ecx=0).ebx will be the size that user (debuggers, etc.) + * need to use. + * + * For now, only the first 8 bytes of the software usable bytes[464..471] will + * be used and will be set to OS enabled xstate mask (which is same as the + * 64bit mask returned by the xgetbv's xCR0). Users (analyzing core dump + * remotely, etc.) can use this mask as well as the mask saved in the + * xstate_hdr bytes and interpret what states the processor/OS supports + * and what states are in modified/initialized conditions for the + * particular process/thread. + * + * Also when the user modifies certain state FP/SSE/etc through the + * ptrace interface, they must ensure that the xsave_hdr.xstate_bv + * bytes[512..519] of the memory layout are updated correspondingly. + * i.e., for example when FP state is modified to a non-init state, + * xsave_hdr.xstate_bv's bit 0 must be set to '1', when SSE is modified to + * non-init state, xsave_hdr.xstate_bv's bit 1 must to be set to '1', etc. + */ +#define USER_XSTATE_FX_SW_WORDS 6 +#define USER_XSTATE_XCR0_WORD 0 + +struct user_xstateregs { + struct { + __u64 fpx_space[58]; + __u64 xstate_fx_sw[USER_XSTATE_FX_SW_WORDS]; + } i387; + struct user_xsave_hdr xsave_hdr; + struct user_ymmh_regs ymmh; + /* further processor state extensions go here */ +}; + +#endif /* _ASM_X86_USER_H */ diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h index 727acc152344..ddc04ccad03b 100644 --- a/arch/x86/include/asm/xsave.h +++ b/arch/x86/include/asm/xsave.h @@ -27,9 +27,11 @@ extern unsigned int xstate_size; extern u64 pcntxt_mask; extern struct xsave_struct *init_xstate_buf; +extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; extern void xsave_cntxt_init(void); extern void xsave_init(void); +extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); extern int init_fpu(struct task_struct *child); extern int check_for_xstate(struct i387_fxsave_struct __user *buf, void __user *fpstate, diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index f2f8540a7f3d..7a8a193b5144 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -164,6 +164,11 @@ int init_fpu(struct task_struct *tsk) return 0; } +/* + * The xstateregs_active() routine is the same as the fpregs_active() routine, + * as the "regset->n" for the xstate regset will be updated based on the feature + * capabilites supported by the xsave. + */ int fpregs_active(struct task_struct *target, const struct user_regset *regset) { return tsk_used_math(target) ? regset->n : 0; @@ -224,6 +229,84 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, return ret; } +int xstateregs_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + if (!cpu_has_xsave) + return -ENODEV; + + ret = init_fpu(target); + if (ret) + return ret; + + /* + * First copy the fxsave bytes 0..463. + */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.xstate->xsave, 0, + offsetof(struct user_xstateregs, + i387.xstate_fx_sw)); + if (ret) + return ret; + + /* + * Copy the 48bytes defined by software. + */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + xstate_fx_sw_bytes, + offsetof(struct user_xstateregs, + i387.xstate_fx_sw), + offsetof(struct user_xstateregs, + xsave_hdr)); + if (ret) + return ret; + + /* + * Copy the rest of xstate memory layout. + */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.xstate->xsave.xsave_hdr, + offsetof(struct user_xstateregs, + xsave_hdr), -1); + return ret; +} + +int xstateregs_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + struct xsave_hdr_struct *xsave_hdr; + + if (!cpu_has_xsave) + return -ENODEV; + + ret = init_fpu(target); + if (ret) + return ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.xstate->xsave, 0, -1); + + /* + * mxcsr reserved bits must be masked to zero for security reasons. + */ + target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; + + xsave_hdr = &target->thread.xstate->xsave.xsave_hdr; + + xsave_hdr->xstate_bv &= pcntxt_mask; + /* + * These bits must be zero. + */ + xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; + + return ret; +} + #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION /* diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 017d937639fe..16433a59b396 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -48,6 +48,7 @@ enum x86_regset { REGSET_FP, REGSET_XFP, REGSET_IOPERM64 = REGSET_XFP, + REGSET_XSTATE, REGSET_TLS, REGSET_IOPERM32, }; @@ -1584,7 +1585,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, #ifdef CONFIG_X86_64 -static const struct user_regset x86_64_regsets[] = { +static struct user_regset x86_64_regsets[] __read_mostly = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, .n = sizeof(struct user_regs_struct) / sizeof(long), @@ -1597,6 +1598,12 @@ static const struct user_regset x86_64_regsets[] = { .size = sizeof(long), .align = sizeof(long), .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set }, + [REGSET_XSTATE] = { + .core_note_type = NT_X86_XSTATE, + .size = sizeof(u64), .align = sizeof(u64), + .active = xstateregs_active, .get = xstateregs_get, + .set = xstateregs_set + }, [REGSET_IOPERM64] = { .core_note_type = NT_386_IOPERM, .n = IO_BITMAP_LONGS, @@ -1622,7 +1629,7 @@ static const struct user_regset_view user_x86_64_view = { #endif /* CONFIG_X86_64 */ #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION -static const struct user_regset x86_32_regsets[] = { +static struct user_regset x86_32_regsets[] __read_mostly = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, .n = sizeof(struct user_regs_struct32) / sizeof(u32), @@ -1641,6 +1648,12 @@ static const struct user_regset x86_32_regsets[] = { .size = sizeof(u32), .align = sizeof(u32), .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set }, + [REGSET_XSTATE] = { + .core_note_type = NT_X86_XSTATE, + .size = sizeof(u64), .align = sizeof(u64), + .active = xstateregs_active, .get = xstateregs_get, + .set = xstateregs_set + }, [REGSET_TLS] = { .core_note_type = NT_386_TLS, .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN, @@ -1663,6 +1676,23 @@ static const struct user_regset_view user_x86_32_view = { }; #endif +/* + * This represents bytes 464..511 in the memory layout exported through + * the REGSET_XSTATE interface. + */ +u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; + +void update_regset_xstate_info(unsigned int size, u64 xstate_mask) +{ +#ifdef CONFIG_X86_64 + x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64); +#endif +#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION + x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64); +#endif + xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask; +} + const struct user_regset_view *task_user_regset_view(struct task_struct *task) { #ifdef CONFIG_IA32_EMULATION diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index c5ee17e8c6d9..782c3a362ec6 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -337,6 +337,7 @@ void __ref xsave_cntxt_init(void) cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); xstate_size = ebx; + update_regset_xstate_info(xstate_size, pcntxt_mask); prepare_fx_sw_frame(); setup_xstate_init(); diff --git a/include/linux/elf.h b/include/linux/elf.h index 0cc4d55151b7..a8c4af073ce9 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -361,6 +361,7 @@ typedef struct elf64_shdr { #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ #define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ -- GitLab From 2225a122ae26d542bdce523d9d87a4a7ba10e07b Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Thu, 11 Feb 2010 11:51:00 -0800 Subject: [PATCH 1915/3892] ptrace: Add support for generic PTRACE_GETREGSET/PTRACE_SETREGSET Generic support for PTRACE_GETREGSET/PTRACE_SETREGSET commands which export the regsets supported by each architecture using the correponding NT_* types. These NT_* types are already part of the userland ABI, used in representing the architecture specific register sets as different NOTES in an ELF core file. 'addr' parameter for the ptrace system call encode the REGSET type (using the corresppnding NT_* type) and the 'data' parameter points to the struct iovec having the user buffer and the length of that buffer. struct iovec iov = { buf, len}; ret = ptrace(PTRACE_GETREGSET/PTRACE_SETREGSET, pid, NT_XXX_TYPE, &iov); On successful completion, iov.len will be updated by the kernel specifying how much the kernel has written/read to/from the user's iov.buf. x86 extended state registers are primarily exported using this interface. Signed-off-by: Suresh Siddha LKML-Reference: <20100211195614.886724710@sbs-t61.sc.intel.com> Acked-by: Hongjiu Lu Cc: Roland McGrath Signed-off-by: H. Peter Anvin --- include/linux/elf.h | 6 ++- include/linux/ptrace.h | 15 +++++++ kernel/ptrace.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/include/linux/elf.h b/include/linux/elf.h index a8c4af073ce9..d8e6e61ad9ff 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -349,7 +349,11 @@ typedef struct elf64_shdr { #define ELF_OSABI ELFOSABI_NONE #endif -/* Notes used in ET_CORE */ +/* + * Notes used in ET_CORE. Architectures export some of the arch register sets + * using the corresponding note types via the PTRACE_GETREGSET and + * PTRACE_SETREGSET requests. + */ #define NT_PRSTATUS 1 #define NT_PRFPREG 2 #define NT_PRPSINFO 3 diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 56f2d63a5cbb..dbfa821d5a6e 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -27,6 +27,21 @@ #define PTRACE_GETSIGINFO 0x4202 #define PTRACE_SETSIGINFO 0x4203 +/* + * Generic ptrace interface that exports the architecture specific regsets + * using the corresponding NT_* types (which are also used in the core dump). + * + * This interface usage is as follows: + * struct iovec iov = { buf, len}; + * + * ret = ptrace(PTRACE_GETREGSET/PTRACE_SETREGSET, pid, NT_XXX_TYPE, &iov); + * + * On the successful completion, iov.len will be updated by the kernel, + * specifying how much the kernel has written/read to/from the user's iov.buf. + */ +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 + /* options set using PTRACE_SETOPTIONS */ #define PTRACE_O_TRACESYSGOOD 0x00000001 #define PTRACE_O_TRACEFORK 0x00000002 diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 23bd09cd042e..13b4554d8fbb 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -22,6 +22,7 @@ #include #include #include +#include /* @@ -511,6 +512,47 @@ static int ptrace_resume(struct task_struct *child, long request, long data) return 0; } +#ifdef CONFIG_HAVE_ARCH_TRACEHOOK + +static const struct user_regset * +find_regset(const struct user_regset_view *view, unsigned int type) +{ + const struct user_regset *regset; + int n; + + for (n = 0; n < view->n; ++n) { + regset = view->regsets + n; + if (regset->core_note_type == type) + return regset; + } + + return NULL; +} + +static int ptrace_regset(struct task_struct *task, int req, unsigned int type, + struct iovec *kiov) +{ + const struct user_regset_view *view = task_user_regset_view(task); + const struct user_regset *regset = find_regset(view, type); + int regset_no; + + if (!regset || (kiov->iov_len % regset->size) != 0) + return -EIO; + + regset_no = regset - view->regsets; + kiov->iov_len = min(kiov->iov_len, + (__kernel_size_t) (regset->n * regset->size)); + + if (req == PTRACE_GETREGSET) + return copy_regset_to_user(task, view, regset_no, 0, + kiov->iov_len, kiov->iov_base); + else + return copy_regset_from_user(task, view, regset_no, 0, + kiov->iov_len, kiov->iov_base); +} + +#endif + int ptrace_request(struct task_struct *child, long request, long addr, long data) { @@ -573,6 +615,26 @@ int ptrace_request(struct task_struct *child, long request, return 0; return ptrace_resume(child, request, SIGKILL); +#ifdef CONFIG_HAVE_ARCH_TRACEHOOK + case PTRACE_GETREGSET: + case PTRACE_SETREGSET: + { + struct iovec kiov; + struct iovec __user *uiov = (struct iovec __user *) data; + + if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) + return -EFAULT; + + if (__get_user(kiov.iov_base, &uiov->iov_base) || + __get_user(kiov.iov_len, &uiov->iov_len)) + return -EFAULT; + + ret = ptrace_regset(child, request, addr, &kiov); + if (!ret) + ret = __put_user(kiov.iov_len, &uiov->iov_len); + break; + } +#endif default: break; } @@ -711,6 +773,32 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, else ret = ptrace_setsiginfo(child, &siginfo); break; +#ifdef CONFIG_HAVE_ARCH_TRACEHOOK + case PTRACE_GETREGSET: + case PTRACE_SETREGSET: + { + struct iovec kiov; + struct compat_iovec __user *uiov = + (struct compat_iovec __user *) datap; + compat_uptr_t ptr; + compat_size_t len; + + if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) + return -EFAULT; + + if (__get_user(ptr, &uiov->iov_base) || + __get_user(len, &uiov->iov_len)) + return -EFAULT; + + kiov.iov_base = compat_ptr(ptr); + kiov.iov_len = len; + + ret = ptrace_regset(child, request, addr, &kiov); + if (!ret) + ret = __put_user(kiov.iov_len, &uiov->iov_len); + break; + } +#endif default: ret = ptrace_request(child, request, addr, data); -- GitLab From 857b409a48bdc33e824dff2d730e271b964e78bd Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 12 Feb 2010 06:24:46 +0100 Subject: [PATCH 1916/3892] netfilter: nf_conntrack: elegantly simplify nf_ct_exp_net() Remove #ifdef at nf_ct_exp_net() by using nf_ct_net(). Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_expect.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 917e170fa752..4b47ec19ef39 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -56,11 +56,7 @@ struct nf_conntrack_expect { static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) { -#ifdef CONFIG_NET_NS - return exp->master->ct_net; /* by definition */ -#else - return &init_net; -#endif + return nf_ct_net(exp->master); } struct nf_conntrack_expect_policy { -- GitLab From ca1c2e2da9637c131436bf6d6ae41b58f5353afe Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 12 Feb 2010 06:25:36 +0100 Subject: [PATCH 1917/3892] netfilter: don't use INIT_RCU_HEAD() call_rcu() will unconditionally reinitialize RCU head anyway. Signed-off-by: Alexey Dobriyan Reviewed-by: Paul E. McKenney Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_expect.c | 1 - net/netfilter/nf_conntrack_extend.c | 1 - net/netfilter/nfnetlink_queue.c | 1 - 3 files changed, 3 deletions(-) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 33b85f834c06..6182fb1b55de 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -232,7 +232,6 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) new->master = me; atomic_set(&new->use, 1); - INIT_RCU_HEAD(&new->rcu); return new; } EXPORT_SYMBOL_GPL(nf_ct_expect_alloc); diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index fef95be334bd..fdc8fb4ae10f 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -59,7 +59,6 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp) if (!*ext) return NULL; - INIT_RCU_HEAD(&(*ext)->rcu); (*ext)->offset[id] = off; (*ext)->len = len; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 90cf36decea3..7ba4abc405c9 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -112,7 +112,6 @@ instance_create(u_int16_t queue_num, int pid) inst->copy_mode = NFQNL_COPY_NONE; spin_lock_init(&inst->lock); INIT_LIST_HEAD(&inst->queue_list); - INIT_RCU_HEAD(&inst->rcu); if (!try_module_get(THIS_MODULE)) { err = -EAGAIN; -- GitLab From b0f3ae03aca0f331b851ae94bc066124e7f104df Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 12 Feb 2010 15:40:00 +0900 Subject: [PATCH 1918/3892] sh: Isolate uncached mapping support. This splits out the uncached mapping support under its own config option, presently only used by 29-bit mode and 32-bit + PMB. This will make it possible to optionally add an uncached mapping on sh64 as well as booting without an uncached mapping for 32-bit. Signed-off-by: Paul Mundt --- arch/sh/include/asm/ptrace.h | 19 +++++++++++++------ arch/sh/include/asm/system.h | 3 ++- arch/sh/include/asm/system_64.h | 1 + arch/sh/mm/Kconfig | 5 +++++ arch/sh/mm/init.c | 11 ++++++++--- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index 201d11ef211f..e879dffa324b 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h @@ -102,13 +102,15 @@ struct pt_dspregs { #define PTRACE_GETDSPREGS 55 /* DSP registers */ #define PTRACE_SETDSPREGS 56 -#define PT_TEXT_END_ADDR 240 -#define PT_TEXT_ADDR 244 /* &(struct user)->start_code */ -#define PT_DATA_ADDR 248 /* &(struct user)->start_data */ +#define PT_TEXT_END_ADDR 240 +#define PT_TEXT_ADDR 244 /* &(struct user)->start_code */ +#define PT_DATA_ADDR 248 /* &(struct user)->start_data */ #define PT_TEXT_LEN 252 #ifdef __KERNEL__ #include +#include +#include #define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define instruction_pointer(regs) ((unsigned long)(regs)->pc) @@ -137,9 +139,14 @@ static inline unsigned long profile_pc(struct pt_regs *regs) { unsigned long pc = instruction_pointer(regs); -#ifdef P2SEG - if (pc >= P2SEG && pc < P3SEG) - pc -= 0x20000000; +#ifdef CONFIG_UNCACHED_MAPPING + /* + * If PC points in to the uncached mapping, fix it up and hand + * back the cached equivalent. + */ + if ((pc >= (memory_start + cached_to_uncached)) && + (pc < (memory_start + cached_to_uncached + uncached_size))) + pc -= cached_to_uncached; #endif return pc; diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index 6442f1783fe0..0bd7a17d5e1a 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h @@ -10,7 +10,6 @@ #include #include #include -#include #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */ @@ -114,6 +113,8 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, (unsigned long)_n_, sizeof(*(ptr))); \ }) +struct pt_regs; + extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn)); void free_initmem(void); void free_initrd_mem(unsigned long start, unsigned long end); diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h index 3391bb6b21d8..36338646dfc8 100644 --- a/arch/sh/include/asm/system_64.h +++ b/arch/sh/include/asm/system_64.h @@ -18,6 +18,7 @@ /* * switch_to() should switch tasks to task nr n, first */ +struct thread_struct; struct task_struct *sh64_switch_to(struct task_struct *prev, struct thread_struct *prev_thread, struct task_struct *next, diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index b89075256b70..65cb5b83e072 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -75,6 +75,7 @@ config MEMORY_SIZE config 29BIT def_bool !32BIT depends on SUPERH32 + select UNCACHED_MAPPING config 32BIT bool @@ -84,6 +85,7 @@ config PMB bool "Support 32-bit physical addressing through PMB" depends on MMU && EXPERIMENTAL && CPU_SH4A && !CPU_SH4AL_DSP select 32BIT + select UNCACHED_MAPPING help If you say Y here, physical addressing will be extended to 32-bits through the SH-4A PMB. If this is not set, legacy @@ -173,6 +175,9 @@ config IOREMAP_FIXED def_bool y depends on X2TLB || SUPERH64 +config UNCACHED_MAPPING + bool + choice prompt "Kernel page size" default PAGE_SIZE_4KB diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index dffa6c749489..58012b6bbe76 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -21,11 +21,12 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); pgd_t swapper_pg_dir[PTRS_PER_PGD]; -#ifdef CONFIG_SUPERH32 +#ifdef CONFIG_UNCACHED_MAPPING /* * This is the offset of the uncached section from its cached alias. * @@ -36,8 +37,8 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD]; * Default value only valid in 29 bit mode, in 32bit mode this will be * updated by the early PMB initialization code. */ -unsigned long cached_to_uncached = P2SEG - P1SEG; -unsigned long uncached_size = 0x20000000; +unsigned long cached_to_uncached = 0x20000000; +unsigned long uncached_size = SZ_512M; #endif #ifdef CONFIG_MMU @@ -281,7 +282,9 @@ void __init mem_init(void) #endif " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" " lowmem : 0x%08lx - 0x%08lx (%4ld MB) (cached)\n" +#ifdef CONFIG_UNCACHED_MAPPING " : 0x%08lx - 0x%08lx (%4ld MB) (uncached)\n" +#endif " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", @@ -299,9 +302,11 @@ void __init mem_init(void) (unsigned long)memory_start, (unsigned long)high_memory, ((unsigned long)high_memory - (unsigned long)memory_start) >> 20, +#ifdef CONFIG_UNCACHED_MAPPING (unsigned long)memory_start + cached_to_uncached, (unsigned long)memory_start + cached_to_uncached + uncached_size, uncached_size >> 20, +#endif (unsigned long)&__init_begin, (unsigned long)&__init_end, ((unsigned long)&__init_end - -- GitLab From 19f6b8b44e3f633d5d7d1ed68848b1eb89a1e800 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 12 Feb 2010 15:41:45 +0900 Subject: [PATCH 1919/3892] sh64: fix up memory offset calculation. The linker script offsets were broken by the recent 29/32-bit integration, so this fixes it up for sh64. Signed-off-by: Paul Mundt --- arch/sh/include/asm/vmlinux.lds.h | 8 ++++++++ arch/sh/kernel/vmlinux.lds.S | 19 +++++-------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/arch/sh/include/asm/vmlinux.lds.h b/arch/sh/include/asm/vmlinux.lds.h index 244ec4ad9a79..d58ad493b3a6 100644 --- a/arch/sh/include/asm/vmlinux.lds.h +++ b/arch/sh/include/asm/vmlinux.lds.h @@ -14,4 +14,12 @@ #define DWARF_EH_FRAME #endif +#ifdef CONFIG_SUPERH64 +#define EXTRA_TEXT \ + *(.text64) \ + *(.text..SHmedia32) +#else +#define EXTRA_TEXT +#endif + #endif /* __ASM_SH_VMLINUX_LDS_H */ diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index f0bc6b886eed..dcf48915e2ea 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -3,10 +3,12 @@ * Written by Niibe Yutaka and Paul Mundt */ #ifdef CONFIG_SUPERH64 -#define LOAD_OFFSET CONFIG_PAGE_OFFSET +#define LOAD_OFFSET PAGE_OFFSET +#define MEMORY_OFFSET __MEMORY_START OUTPUT_ARCH(sh:sh5) #else #define LOAD_OFFSET 0 +#define MEMORY_OFFSET 0 OUTPUT_ARCH(sh) #endif @@ -14,16 +16,10 @@ OUTPUT_ARCH(sh) #include #include -#if defined(CONFIG_32BIT) && !defined(CONFIG_PMB_LEGACY) -#define MEMORY_OFFSET 0 -#else -#define MEMORY_OFFSET (CONFIG_MEMORY_START & 0x1fffffff) -#endif - ENTRY(_start) SECTIONS { - . = CONFIG_PAGE_OFFSET + MEMORY_OFFSET + CONFIG_ZERO_PAGE_OFFSET; + . = PAGE_OFFSET + MEMORY_OFFSET + CONFIG_ZERO_PAGE_OFFSET; _text = .; /* Text and read-only data */ @@ -34,12 +30,7 @@ SECTIONS .text : AT(ADDR(.text) - LOAD_OFFSET) { HEAD_TEXT TEXT_TEXT - -#ifdef CONFIG_SUPERH64 - *(.text64) - *(.text..SHmedia32) -#endif - + EXTRA_TEXT SCHED_TEXT LOCK_TEXT KPROBES_TEXT -- GitLab From 6db29675b1cb60e878d04a1f69aba265189b2e33 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Feb 2010 18:11:10 +0100 Subject: [PATCH 1920/3892] ASoC: fix compile breakage if CONFIG_SH_DMA_API=y && CONFIG_SND_SIU_MIGOR!=n Audio on Migo-R cannot work if CONFIG_SH_DMA_API=y, but compilation should not break anyway. Signed-off-by: Guennadi Liakhovetski Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index a86696bbe179..106674979b53 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_SH4_FSI config SND_SOC_SH4_SIU tristate depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + select DMA_ENGINE select DMADEVICES select SH_DMAE -- GitLab From 703e3061a043a7b87df2460044666d68394bdb69 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 4 Jan 2010 15:34:16 +0100 Subject: [PATCH 1921/3892] OMAP: Enable DSS2 for OMAP3EVM board Signed-off-by: Vaibhav Hiremath [tomi.valkeinen@nokia.com: removed evm defconfig changes] Signed-off-by: Tomi Valkeinen --- arch/arm/mach-omap2/board-omap3evm.c | 246 +++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 34de17851572..822df79ce891 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" @@ -147,6 +148,187 @@ static inline void __init omap3evm_init_smsc911x(void) static inline void __init omap3evm_init_smsc911x(void) { return; } #endif +/* + * OMAP3EVM LCD Panel control signals + */ +#define OMAP3EVM_LCD_PANEL_LR 2 +#define OMAP3EVM_LCD_PANEL_UD 3 +#define OMAP3EVM_LCD_PANEL_INI 152 +#define OMAP3EVM_LCD_PANEL_ENVDD 153 +#define OMAP3EVM_LCD_PANEL_QVGA 154 +#define OMAP3EVM_LCD_PANEL_RESB 155 +#define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO 210 +#define OMAP3EVM_DVI_PANEL_EN_GPIO 199 + +static int lcd_enabled; +static int dvi_enabled; + +static void __init omap3_evm_display_init(void) +{ + int r; + + r = gpio_request(OMAP3EVM_LCD_PANEL_RESB, "lcd_panel_resb"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_resb\n"); + return; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_RESB, 1); + + r = gpio_request(OMAP3EVM_LCD_PANEL_INI, "lcd_panel_ini"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_ini\n"); + goto err_1; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_INI, 1); + + r = gpio_request(OMAP3EVM_LCD_PANEL_QVGA, "lcd_panel_qvga"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_qvga\n"); + goto err_2; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_QVGA, 0); + + r = gpio_request(OMAP3EVM_LCD_PANEL_LR, "lcd_panel_lr"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_lr\n"); + goto err_3; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_LR, 1); + + r = gpio_request(OMAP3EVM_LCD_PANEL_UD, "lcd_panel_ud"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_ud\n"); + goto err_4; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_UD, 1); + + r = gpio_request(OMAP3EVM_LCD_PANEL_ENVDD, "lcd_panel_envdd"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_envdd\n"); + goto err_5; + } + gpio_direction_output(OMAP3EVM_LCD_PANEL_ENVDD, 0); + + return; + +err_5: + gpio_free(OMAP3EVM_LCD_PANEL_UD); +err_4: + gpio_free(OMAP3EVM_LCD_PANEL_LR); +err_3: + gpio_free(OMAP3EVM_LCD_PANEL_QVGA); +err_2: + gpio_free(OMAP3EVM_LCD_PANEL_INI); +err_1: + gpio_free(OMAP3EVM_LCD_PANEL_RESB); + +} + +static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 0); + + if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) + gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0); + else + gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1); + + lcd_enabled = 1; + return 0; +} + +static void omap3_evm_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 1); + + if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) + gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1); + else + gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0); + + lcd_enabled = 0; +} + +static struct omap_dss_device omap3_evm_lcd_device = { + .name = "lcd", + .driver_name = "sharp_ls_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 18, + .platform_enable = omap3_evm_enable_lcd, + .platform_disable = omap3_evm_disable_lcd, +}; + +static int omap3_evm_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void omap3_evm_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device omap3_evm_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = omap3_evm_enable_tv, + .platform_disable = omap3_evm_disable_tv, +}; + +static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + + gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 1); + + dvi_enabled = 1; + return 0; +} + +static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 0); + + dvi_enabled = 0; +} + +static struct omap_dss_device omap3_evm_dvi_device = { + .name = "dvi", + .driver_name = "generic_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 24, + .platform_enable = omap3_evm_enable_dvi, + .platform_disable = omap3_evm_disable_dvi, +}; + +static struct omap_dss_device *omap3_evm_dss_devices[] = { + &omap3_evm_lcd_device, + &omap3_evm_tv_device, + &omap3_evm_dvi_device, +}; + +static struct omap_dss_board_info omap3_evm_dss_data = { + .num_devices = ARRAY_SIZE(omap3_evm_dss_devices), + .devices = omap3_evm_dss_devices, + .default_device = &omap3_evm_lcd_device, +}; + +static struct platform_device omap3_evm_dss_device = { + .name = "omapdss", + .id = -1, + .dev = { + .platform_data = &omap3_evm_dss_data, + }, +}; + static struct regulator_consumer_supply omap3evm_vmmc1_supply = { .supply = "vmmc", }; @@ -236,6 +418,14 @@ static int omap3evm_twl_gpio_setup(struct device *dev, * the P2 connector; notably LEDA for the LCD backlight. */ + /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */ + gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL"); + gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0); + + /* gpio + 7 == DVI Enable */ + gpio_request(gpio + 7, "EN_DVI"); + gpio_direction_output(gpio + 7, 0); + /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; @@ -300,6 +490,47 @@ static struct twl4030_codec_data omap3evm_codec_data = { .audio = &omap3evm_audio_data, }; +static struct regulator_consumer_supply omap3_evm_vdda_dac_supply = { + .supply = "vdda_dac", + .dev = &omap3_evm_dss_device.dev, +}; + +/* VDAC for DSS driving S-Video */ +static struct regulator_init_data omap3_evm_vdac = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &omap3_evm_vdda_dac_supply, +}; + +/* VPLL2 for digital video outputs */ +static struct regulator_consumer_supply omap3_evm_vpll2_supply = { + .supply = "vdvi", + .dev = &omap3_evm_lcd_device.dev, +}; + +static struct regulator_init_data omap3_evm_vpll2 = { + .constraints = { + .name = "VDVI", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &omap3_evm_vpll2_supply, +}; + static struct twl4030_platform_data omap3evm_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, @@ -310,6 +541,8 @@ static struct twl4030_platform_data omap3evm_twldata = { .usb = &omap3evm_usb_data, .gpio = &omap3evm_gpio_data, .codec = &omap3evm_codec_data, + .vdac = &omap3_evm_vdac, + .vpll2 = &omap3_evm_vpll2, }; static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = { @@ -337,15 +570,6 @@ static int __init omap3_evm_i2c_init(void) return 0; } -static struct platform_device omap3_evm_lcd_device = { - .name = "omap3evm_lcd", - .id = -1, -}; - -static struct omap_lcd_config omap3_evm_lcd_config __initdata = { - .ctrl_name = "internal", -}; - static void ads7846_dev_init(void) { if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0) @@ -393,7 +617,6 @@ struct spi_board_info omap3evm_spi_board_info[] = { }; static struct omap_board_config_kernel omap3_evm_config[] __initdata = { - { OMAP_TAG_LCD, &omap3_evm_lcd_config }, }; static void __init omap3_evm_init_irq(void) @@ -406,7 +629,7 @@ static void __init omap3_evm_init_irq(void) } static struct platform_device *omap3_evm_devices[] __initdata = { - &omap3_evm_lcd_device, + &omap3_evm_dss_device, }; static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = { @@ -473,6 +696,7 @@ static void __init omap3_evm_init(void) usb_ehci_init(&ehci_pdata); ads7846_dev_init(); omap3evm_init_smsc911x(); + omap3_evm_display_init(); } static void __init omap3_evm_map_io(void) -- GitLab From c3d33329f400587976613c0224ffa2e266677cfb Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Wed, 13 Jan 2010 17:17:10 +0530 Subject: [PATCH 1922/3892] OMAP: AM3517: Enable DSS2 for AM3517EVM board Signed-off-by: Vaibhav Hiremath [tomi.valkeinen@nokia.com: removed defconfig changes] Signed-off-by: Tomi Valkeinen --- arch/arm/mach-omap2/board-am3517evm.c | 145 ++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index b4e6eca0e8a9..54af5f8d8184 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -29,9 +29,151 @@ #include #include #include +#include #include "mux.h" +#define LCD_PANEL_PWR 176 +#define LCD_PANEL_BKLIGHT_PWR 182 +#define LCD_PANEL_PWM 181 + +static int lcd_enabled; +static int dvi_enabled; + +static void __init am3517_evm_display_init(void) +{ + int r; + + omap_mux_init_gpio(LCD_PANEL_PWR, OMAP_PIN_INPUT_PULLUP); + omap_mux_init_gpio(LCD_PANEL_BKLIGHT_PWR, OMAP_PIN_INPUT_PULLDOWN); + omap_mux_init_gpio(LCD_PANEL_PWM, OMAP_PIN_INPUT_PULLDOWN); + /* + * Enable GPIO 182 = LCD Backlight Power + */ + r = gpio_request(LCD_PANEL_BKLIGHT_PWR, "lcd_backlight_pwr"); + if (r) { + printk(KERN_ERR "failed to get lcd_backlight_pwr\n"); + return; + } + gpio_direction_output(LCD_PANEL_BKLIGHT_PWR, 1); + /* + * Enable GPIO 181 = LCD Panel PWM + */ + r = gpio_request(LCD_PANEL_PWM, "lcd_pwm"); + if (r) { + printk(KERN_ERR "failed to get lcd_pwm\n"); + goto err_1; + } + gpio_direction_output(LCD_PANEL_PWM, 1); + /* + * Enable GPIO 176 = LCD Panel Power enable pin + */ + r = gpio_request(LCD_PANEL_PWR, "lcd_panel_pwr"); + if (r) { + printk(KERN_ERR "failed to get lcd_panel_pwr\n"); + goto err_2; + } + gpio_direction_output(LCD_PANEL_PWR, 1); + + printk(KERN_INFO "Display initialized successfully\n"); + return; + +err_2: + gpio_free(LCD_PANEL_PWM); +err_1: + gpio_free(LCD_PANEL_BKLIGHT_PWR); +} + +static int am3517_evm_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + gpio_set_value(LCD_PANEL_PWR, 1); + lcd_enabled = 1; + + return 0; +} + +static void am3517_evm_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_set_value(LCD_PANEL_PWR, 0); + lcd_enabled = 0; +} + +static struct omap_dss_device am3517_evm_lcd_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "lcd", + .driver_name = "sharp_lq_panel", + .phy.dpi.data_lines = 16, + .platform_enable = am3517_evm_panel_enable_lcd, + .platform_disable = am3517_evm_panel_disable_lcd, +}; + +static int am3517_evm_panel_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void am3517_evm_panel_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device am3517_evm_tv_device = { + .type = OMAP_DISPLAY_TYPE_VENC, + .name = "tv", + .driver_name = "venc", + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = am3517_evm_panel_enable_tv, + .platform_disable = am3517_evm_panel_disable_tv, +}; + +static int am3517_evm_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + dvi_enabled = 1; + + return 0; +} + +static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + dvi_enabled = 0; +} + +static struct omap_dss_device am3517_evm_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "generic_panel", + .phy.dpi.data_lines = 24, + .platform_enable = am3517_evm_panel_enable_dvi, + .platform_disable = am3517_evm_panel_disable_dvi, +}; + +static struct omap_dss_device *am3517_evm_dss_devices[] = { + &am3517_evm_lcd_device, + &am3517_evm_tv_device, + &am3517_evm_dvi_device, +}; + +static struct omap_dss_board_info am3517_evm_dss_data = { + .num_devices = ARRAY_SIZE(am3517_evm_dss_devices), + .devices = am3517_evm_dss_devices, + .default_device = &am3517_evm_lcd_device, +}; + +struct platform_device am3517_evm_dss_device = { + .name = "omapdss", + .id = -1, + .dev = { + .platform_data = &am3517_evm_dss_data, + }, +}; + /* * Board initialization */ @@ -39,6 +181,7 @@ static struct omap_board_config_kernel am3517_evm_config[] __initdata = { }; static struct platform_device *am3517_evm_devices[] __initdata = { + &am3517_evm_dss_device, }; static void __init am3517_evm_init_irq(void) @@ -78,6 +221,8 @@ static void __init am3517_evm_init(void) omap_serial_init(); usb_ehci_init(&ehci_pdata); + /* DSS */ + am3517_evm_display_init(); } static void __init am3517_evm_map_io(void) -- GitLab From 7f049ad15ece7f63b59ad438b51629434cdc0198 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 14 Dec 2009 09:01:08 +0100 Subject: [PATCH 1923/3892] omap3: cm-t35: add DSS2 display support Signed-off-by: Mike Rapoport Signed-off-by: Tomi Valkeinen --- arch/arm/mach-omap2/board-cm-t35.c | 239 ++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 2626a9f8a73a..85b45437d51a 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -32,6 +32,9 @@ #include #include +#include +#include + #include #include #include @@ -41,6 +44,7 @@ #include #include #include +#include #include @@ -248,7 +252,6 @@ static inline void cm_t35_init_nand(void) {} #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) -#include #include #include @@ -304,6 +307,193 @@ static void __init cm_t35_init_ads7846(void) static inline void cm_t35_init_ads7846(void) {} #endif +#define CM_T35_LCD_EN_GPIO 157 +#define CM_T35_LCD_BL_GPIO 58 +#define CM_T35_DVI_EN_GPIO 54 + +static int lcd_bl_gpio; +static int lcd_en_gpio; +static int dvi_en_gpio; + +static int lcd_enabled; +static int dvi_enabled; + +static int cm_t35_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + + gpio_set_value(lcd_en_gpio, 1); + gpio_set_value(lcd_bl_gpio, 1); + + lcd_enabled = 1; + + return 0; +} + +static void cm_t35_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + lcd_enabled = 0; + + gpio_set_value(lcd_bl_gpio, 0); + gpio_set_value(lcd_en_gpio, 0); +} + +static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + + gpio_set_value(dvi_en_gpio, 0); + dvi_enabled = 1; + + return 0; +} + +static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(dvi_en_gpio, 1); + dvi_enabled = 0; +} + +static int cm_t35_panel_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void cm_t35_panel_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device cm_t35_lcd_device = { + .name = "lcd", + .driver_name = "toppoly_tdo35s_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 18, + .platform_enable = cm_t35_panel_enable_lcd, + .platform_disable = cm_t35_panel_disable_lcd, +}; + +static struct omap_dss_device cm_t35_dvi_device = { + .name = "dvi", + .driver_name = "generic_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 24, + .platform_enable = cm_t35_panel_enable_dvi, + .platform_disable = cm_t35_panel_disable_dvi, +}; + +static struct omap_dss_device cm_t35_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = cm_t35_panel_enable_tv, + .platform_disable = cm_t35_panel_disable_tv, +}; + +static struct omap_dss_device *cm_t35_dss_devices[] = { + &cm_t35_lcd_device, + &cm_t35_dvi_device, + &cm_t35_tv_device, +}; + +static struct omap_dss_board_info cm_t35_dss_data = { + .num_devices = ARRAY_SIZE(cm_t35_dss_devices), + .devices = cm_t35_dss_devices, + .default_device = &cm_t35_dvi_device, +}; + +static struct platform_device cm_t35_dss_device = { + .name = "omapdss", + .id = -1, + .dev = { + .platform_data = &cm_t35_dss_data, + }, +}; + +static struct omap2_mcspi_device_config tdo24m_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct tdo24m_platform_data tdo24m_config = { + .model = TDO35S, +}; + +static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = { + { + .modalias = "tdo24m", + .bus_num = 4, + .chip_select = 0, + .max_speed_hz = 1000000, + .controller_data = &tdo24m_mcspi_config, + .platform_data = &tdo24m_config, + }, +}; + +static void __init cm_t35_init_display(void) +{ + int err; + + lcd_en_gpio = CM_T35_LCD_EN_GPIO; + lcd_bl_gpio = CM_T35_LCD_BL_GPIO; + dvi_en_gpio = CM_T35_DVI_EN_GPIO; + + spi_register_board_info(cm_t35_lcd_spi_board_info, + ARRAY_SIZE(cm_t35_lcd_spi_board_info)); + + err = gpio_request(lcd_en_gpio, "LCD RST"); + if (err) { + pr_err("CM-T35: failed to get LCD reset GPIO\n"); + goto out; + } + + err = gpio_request(lcd_bl_gpio, "LCD BL"); + if (err) { + pr_err("CM-T35: failed to get LCD backlight control GPIO\n"); + goto err_lcd_bl; + } + + err = gpio_request(dvi_en_gpio, "DVI EN"); + if (err) { + pr_err("CM-T35: failed to get DVI reset GPIO\n"); + goto err_dvi_en; + } + + gpio_export(lcd_en_gpio, 0); + gpio_export(lcd_bl_gpio, 0); + gpio_export(dvi_en_gpio, 0); + gpio_direction_output(lcd_en_gpio, 0); + gpio_direction_output(lcd_bl_gpio, 0); + gpio_direction_output(dvi_en_gpio, 1); + + msleep(50); + gpio_set_value(lcd_en_gpio, 1); + + err = platform_device_register(&cm_t35_dss_device); + if (err) { + pr_err("CM-T35: failed to register DSS device\n"); + goto err_dev_reg; + } + + return; + +err_dev_reg: + gpio_free(dvi_en_gpio); +err_dvi_en: + gpio_free(lcd_bl_gpio); +err_lcd_bl: + gpio_free(lcd_en_gpio); +out: + + return; +} + static struct regulator_consumer_supply cm_t35_vmmc1_supply = { .supply = "vmmc", }; @@ -312,6 +502,16 @@ static struct regulator_consumer_supply cm_t35_vsim_supply = { .supply = "vmmc_aux", }; +static struct regulator_consumer_supply cm_t35_vdac_supply = { + .supply = "vdda_dac", + .dev = &cm_t35_dss_device.dev, +}; + +static struct regulator_consumer_supply cm_t35_vdvi_supply = { + .supply = "vdvi", + .dev = &cm_t35_dss_device.dev, +}; + /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ static struct regulator_init_data cm_t35_vmmc1 = { .constraints = { @@ -342,6 +542,35 @@ static struct regulator_init_data cm_t35_vsim = { .consumer_supplies = &cm_t35_vsim_supply, }; +/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */ +static struct regulator_init_data cm_t35_vdac = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &cm_t35_vdac_supply, +}; + +/* VPLL2 for digital video outputs */ +static struct regulator_init_data cm_t35_vpll2 = { + .constraints = { + .name = "VDVI", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &cm_t35_vdvi_supply, +}; + static struct twl4030_usb_data cm_t35_usb_data = { .usb_mode = T2_USB_MODE_ULPI, }; @@ -445,6 +674,8 @@ static struct twl4030_platform_data cm_t35_twldata = { .gpio = &cm_t35_gpio_data, .vmmc1 = &cm_t35_vmmc1, .vsim = &cm_t35_vsim, + .vdac = &cm_t35_vdac, + .vpll2 = &cm_t35_vpll2, }; static struct i2c_board_info __initdata cm_t35_i2c_boardinfo[] = { @@ -568,6 +799,11 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + /* display controls */ + OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(GPMC_NCS7, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + /* TPS IRQ */ OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_WAKEUP_EN | \ OMAP_PIN_INPUT_PULLUP), @@ -584,6 +820,7 @@ static void __init cm_t35_init(void) cm_t35_init_ads7846(); cm_t35_init_ethernet(); cm_t35_init_led(); + cm_t35_init_display(); usb_musb_init(); } -- GitLab From 3a66d3877eaa4ab9818000a15c07326adaa9ca79 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Feb 2010 13:27:19 +0000 Subject: [PATCH 1924/3892] ASoC: Add WM2000 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The WM2000 is a low power, high quality handset receiver speaker driver with Wolfson myZoneâ„¢ Ambient Noise Cancellation (ANC). It provides enhanced voice communication quality in a noisy environment if the handset acoustics are designed appropriately. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/wm2000.h | 26 ++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm2000.c | 888 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm2000.h | 79 ++++ 5 files changed, 999 insertions(+) create mode 100644 include/sound/wm2000.h create mode 100644 sound/soc/codecs/wm2000.c create mode 100644 sound/soc/codecs/wm2000.h diff --git a/include/sound/wm2000.h b/include/sound/wm2000.h new file mode 100644 index 000000000000..aa388ca9ec64 --- /dev/null +++ b/include/sound/wm2000.h @@ -0,0 +1,26 @@ +/* + * linux/sound/wm2000.h -- Platform data for WM2000 + * + * Copyright 2010 Wolfson Microelectronics. PLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_WM2000_H +#define __LINUX_SND_WM2000_H + +struct wm2000_platform_data { + /** Filename for system-specific image to download to device. */ + const char *download_file; + + /** Divide MCLK by 2 for system clock? */ + unsigned int mclkdiv2:1; + + /** Disable speech clarity enhancement, for use when an + * external algorithm is used. */ + unsigned int speech_enh_disable:1; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5ab59219a8de..1743d565e996 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C + select SND_SOC_WM2000 if I2C select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI @@ -265,3 +266,6 @@ config SND_SOC_MAX9877 config SND_SOC_TPA6130A2 tristate + +config SND_SOC_WM2000 + tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 209dd6c7c254..dd5ce6df6292 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -58,6 +58,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o # Amp snd-soc-max9877-objs := max9877.o snd-soc-tpa6130a2-objs := tpa6130a2.o +snd-soc-wm2000-objs := wm2000.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o @@ -119,3 +120,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c new file mode 100644 index 000000000000..217b02680597 --- /dev/null +++ b/sound/soc/codecs/wm2000.c @@ -0,0 +1,888 @@ +/* + * wm2000.c -- WM2000 ALSA Soc Audio driver + * + * Copyright 2008-2010 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * 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. + * + * The download image for the WM2000 will be requested as + * 'wm2000_anc.bin' by default (overridable via platform data) at + * runtime and is expected to be in flat binary format. This is + * generated by Wolfson configuration tools and includes + * system-specific callibration information. If supplied as a + * sequence of ASCII-encoded hexidecimal bytes this can be converted + * into a flat binary with a command such as this on the command line: + * + * perl -e 'while (<>) { s/[\r\n]+// ; printf("%c", hex($_)); }' + * < file > wm2000_anc.bin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "wm2000.h" + +enum wm2000_anc_mode { + ANC_ACTIVE = 0, + ANC_BYPASS = 1, + ANC_STANDBY = 2, + ANC_OFF = 3, +}; + +struct wm2000_priv { + struct i2c_client *i2c; + + enum wm2000_anc_mode anc_mode; + + unsigned int anc_active:1; + unsigned int anc_eng_ena:1; + unsigned int spk_ena:1; + + unsigned int mclk_div:1; + unsigned int speech_clarity:1; + + int anc_download_size; + char *anc_download; +}; + +static struct i2c_client *wm2000_i2c; + +static int wm2000_write(struct i2c_client *i2c, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + int ret; + + data[0] = (reg >> 8) & 0xff; + data[1] = reg & 0xff; + data[2] = value & 0xff; + + dev_vdbg(&i2c->dev, "write %x = %x\n", reg, value); + + ret = i2c_master_send(i2c, data, 3); + if (ret == 3) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r) +{ + struct i2c_msg xfer[2]; + u8 reg[2]; + u8 data; + int ret; + + /* Write register */ + reg[0] = (r >> 8) & 0xff; + reg[1] = r & 0xff; + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = sizeof(reg); + xfer[0].buf = ®[0]; + + /* Read data */ + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 1; + xfer[1].buf = &data; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + dev_vdbg(&i2c->dev, "read %x from %x\n", data, r); + + return data; +} + +static void wm2000_reset(struct wm2000_priv *wm2000) +{ + struct i2c_client *i2c = wm2000->i2c; + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); + wm2000_write(i2c, WM2000_REG_ID1, 0); + + wm2000->anc_mode = ANC_OFF; +} + +static int wm2000_poll_bit(struct i2c_client *i2c, + unsigned int reg, u8 mask, int timeout) +{ + int val; + + val = wm2000_read(i2c, reg); + + while (!(val & mask) && --timeout) { + msleep(1); + val = wm2000_read(i2c, reg); + } + + if (timeout == 0) + return 0; + else + return 1; +} + +static int wm2000_power_up(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + int ret, timeout; + + BUG_ON(wm2000->anc_mode != ANC_OFF); + + dev_dbg(&i2c->dev, "Beginning power up\n"); + + if (!wm2000->mclk_div) { + dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, + WM2000_MCLK_DIV2_ENA_CLR); + } else { + dev_dbg(&i2c->dev, "Enabling MCLK divider\n"); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, + WM2000_MCLK_DIV2_ENA_SET); + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_SET); + + /* Wait for ANC engine to become ready */ + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, + WM2000_ANC_ENG_IDLE, 1)) { + dev_err(&i2c->dev, "ANC engine failed to reset\n"); + return -ETIMEDOUT; + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_BOOT_COMPLETE, 1)) { + dev_err(&i2c->dev, "ANC engine failed to initialise\n"); + return -ETIMEDOUT; + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); + + /* Open code download of the data since it is the only bulk + * write we do. */ + dev_dbg(&i2c->dev, "Downloading %d bytes\n", + wm2000->anc_download_size - 2); + + ret = i2c_master_send(i2c, wm2000->anc_download, + wm2000->anc_download_size); + if (ret < 0) { + dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); + return ret; + } + if (ret != wm2000->anc_download_size) { + dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n", + ret, wm2000->anc_download_size); + return -EIO; + } + + dev_dbg(&i2c->dev, "Download complete\n"); + + if (analogue) { + timeout = 248; + wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_MOUSE_ENABLE | + WM2000_MODE_THERMAL_ENABLE); + } else { + timeout = 10; + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_MOUSE_ENABLE | + WM2000_MODE_THERMAL_ENABLE); + } + + ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); + if (wm2000->speech_clarity) + ret &= ~WM2000_SPEECH_CLARITY; + else + ret |= WM2000_SPEECH_CLARITY; + wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); + + wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); + wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02); + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_MOUSE_ACTIVE, timeout)) { + dev_err(&i2c->dev, "Timed out waiting for device after %dms\n", + timeout * 10); + return -ETIMEDOUT; + } + + dev_dbg(&i2c->dev, "ANC active\n"); + if (analogue) + dev_dbg(&i2c->dev, "Analogue active\n"); + wm2000->anc_mode = ANC_ACTIVE; + + return 0; +} + +static int wm2000_power_down(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + int timeout; + + if (analogue) { + timeout = 248; + wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_POWER_DOWN); + } else { + timeout = 10; + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_POWER_DOWN); + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_POWER_DOWN_COMPLETE, timeout)) { + dev_err(&i2c->dev, "Timeout waiting for ANC power down\n"); + return -ETIMEDOUT; + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, + WM2000_ANC_ENG_IDLE, 1)) { + dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); + return -ETIMEDOUT; + } + + dev_dbg(&i2c->dev, "powered off\n"); + wm2000->anc_mode = ANC_OFF; + + return 0; +} + +static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + BUG_ON(wm2000->anc_mode != ANC_ACTIVE); + + if (analogue) { + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_BYPASS_ENTRY); + } else { + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_BYPASS_ENTRY); + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_ANC_DISABLED, 10)) { + dev_err(&i2c->dev, "Timeout waiting for ANC disable\n"); + return -ETIMEDOUT; + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, + WM2000_ANC_ENG_IDLE, 1)) { + dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); + return -ETIMEDOUT; + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); + + wm2000->anc_mode = ANC_BYPASS; + dev_dbg(&i2c->dev, "bypass enabled\n"); + + return 0; +} + +static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + BUG_ON(wm2000->anc_mode != ANC_BYPASS); + + wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); + + if (analogue) { + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_MOUSE_ENABLE | + WM2000_MODE_THERMAL_ENABLE); + } else { + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_MOUSE_ENABLE | + WM2000_MODE_THERMAL_ENABLE); + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_MOUSE_ACTIVE, 10)) { + dev_err(&i2c->dev, "Timed out waiting for MOUSE\n"); + return -ETIMEDOUT; + } + + wm2000->anc_mode = ANC_ACTIVE; + dev_dbg(&i2c->dev, "MOUSE active\n"); + + return 0; +} + +static int wm2000_enter_standby(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + int timeout; + + BUG_ON(wm2000->anc_mode != ANC_ACTIVE); + + if (analogue) { + timeout = 248; + wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_STANDBY_ENTRY); + } else { + timeout = 10; + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_STANDBY_ENTRY); + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_ANC_DISABLED, timeout)) { + dev_err(&i2c->dev, + "Timed out waiting for ANC disable after 1ms\n"); + return -ETIMEDOUT; + } + + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, WM2000_ANC_ENG_IDLE, + 1)) { + dev_err(&i2c->dev, + "Timed out waiting for standby after %dms\n", + timeout * 10); + return -ETIMEDOUT; + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); + + wm2000->anc_mode = ANC_STANDBY; + dev_dbg(&i2c->dev, "standby\n"); + if (analogue) + dev_dbg(&i2c->dev, "Analogue disabled\n"); + + return 0; +} + +static int wm2000_exit_standby(struct i2c_client *i2c, int analogue) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + int timeout; + + BUG_ON(wm2000->anc_mode != ANC_STANDBY); + + wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); + + if (analogue) { + timeout = 248; + wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_ANA_SEQ_INCLUDE | + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_MOUSE_ENABLE); + } else { + timeout = 10; + + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, + WM2000_MODE_THERMAL_ENABLE | + WM2000_MODE_MOUSE_ENABLE); + } + + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); + + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, + WM2000_STATUS_MOUSE_ACTIVE, timeout)) { + dev_err(&i2c->dev, "Timed out waiting for MOUSE after %dms\n", + timeout * 10); + return -ETIMEDOUT; + } + + wm2000->anc_mode = ANC_ACTIVE; + dev_dbg(&i2c->dev, "MOUSE active\n"); + if (analogue) + dev_dbg(&i2c->dev, "Analogue enabled\n"); + + return 0; +} + +typedef int (*wm2000_mode_fn)(struct i2c_client *i2c, int analogue); + +static struct { + enum wm2000_anc_mode source; + enum wm2000_anc_mode dest; + int analogue; + wm2000_mode_fn step[2]; +} anc_transitions[] = { + { + .source = ANC_OFF, + .dest = ANC_ACTIVE, + .analogue = 1, + .step = { + wm2000_power_up, + }, + }, + { + .source = ANC_OFF, + .dest = ANC_STANDBY, + .step = { + wm2000_power_up, + wm2000_enter_standby, + }, + }, + { + .source = ANC_OFF, + .dest = ANC_BYPASS, + .analogue = 1, + .step = { + wm2000_power_up, + wm2000_enter_bypass, + }, + }, + { + .source = ANC_ACTIVE, + .dest = ANC_BYPASS, + .analogue = 1, + .step = { + wm2000_enter_bypass, + }, + }, + { + .source = ANC_ACTIVE, + .dest = ANC_STANDBY, + .analogue = 1, + .step = { + wm2000_enter_standby, + }, + }, + { + .source = ANC_ACTIVE, + .dest = ANC_OFF, + .analogue = 1, + .step = { + wm2000_power_down, + }, + }, + { + .source = ANC_BYPASS, + .dest = ANC_ACTIVE, + .analogue = 1, + .step = { + wm2000_exit_bypass, + }, + }, + { + .source = ANC_BYPASS, + .dest = ANC_STANDBY, + .analogue = 1, + .step = { + wm2000_exit_bypass, + wm2000_enter_standby, + }, + }, + { + .source = ANC_BYPASS, + .dest = ANC_OFF, + .step = { + wm2000_exit_bypass, + wm2000_power_down, + }, + }, + { + .source = ANC_STANDBY, + .dest = ANC_ACTIVE, + .analogue = 1, + .step = { + wm2000_exit_standby, + }, + }, + { + .source = ANC_STANDBY, + .dest = ANC_BYPASS, + .analogue = 1, + .step = { + wm2000_exit_standby, + wm2000_enter_bypass, + }, + }, + { + .source = ANC_STANDBY, + .dest = ANC_OFF, + .step = { + wm2000_exit_standby, + wm2000_power_down, + }, + }, +}; + +static int wm2000_anc_transition(struct wm2000_priv *wm2000, + enum wm2000_anc_mode mode) +{ + struct i2c_client *i2c = wm2000->i2c; + int i, j; + int ret; + + if (wm2000->anc_mode == mode) + return 0; + + for (i = 0; i < ARRAY_SIZE(anc_transitions); i++) + if (anc_transitions[i].source == wm2000->anc_mode && + anc_transitions[i].dest == mode) + break; + if (i == ARRAY_SIZE(anc_transitions)) { + dev_err(&i2c->dev, "No transition for %d->%d\n", + wm2000->anc_mode, mode); + return -EINVAL; + } + + for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) { + if (!anc_transitions[i].step[j]) + break; + ret = anc_transitions[i].step[j](i2c, + anc_transitions[i].analogue); + if (ret != 0) + return ret; + } + + return 0; +} + +static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) +{ + struct i2c_client *i2c = wm2000->i2c; + enum wm2000_anc_mode mode; + + if (wm2000->anc_eng_ena && wm2000->spk_ena) + if (wm2000->anc_active) + mode = ANC_ACTIVE; + else + mode = ANC_BYPASS; + else + mode = ANC_STANDBY; + + dev_dbg(&i2c->dev, "Set mode %d (enabled %d, mute %d, active %d)\n", + mode, wm2000->anc_eng_ena, !wm2000->spk_ena, + wm2000->anc_active); + + return wm2000_anc_transition(wm2000, mode); +} + +static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); + + ucontrol->value.enumerated.item[0] = wm2000->anc_active; + + return 0; +} + +static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); + int anc_active = ucontrol->value.enumerated.item[0]; + + if (anc_active > 1) + return -EINVAL; + + wm2000->anc_active = anc_active; + + return wm2000_anc_set_mode(wm2000); +} + +static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); + + ucontrol->value.enumerated.item[0] = wm2000->spk_ena; + + return 0; +} + +static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); + int val = ucontrol->value.enumerated.item[0]; + + if (val > 1) + return -EINVAL; + + wm2000->spk_ena = val; + + return wm2000_anc_set_mode(wm2000); +} + +static const struct snd_kcontrol_new wm2000_controls[] = { + SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0, + wm2000_anc_mode_get, + wm2000_anc_mode_put), + SOC_SINGLE_BOOL_EXT("WM2000 Switch", 0, + wm2000_speaker_get, + wm2000_speaker_put), +}; + +static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); + + if (SND_SOC_DAPM_EVENT_ON(event)) + wm2000->anc_eng_ena = 1; + + if (SND_SOC_DAPM_EVENT_OFF(event)) + wm2000->anc_eng_ena = 0; + + return wm2000_anc_set_mode(wm2000); +} + +static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { +/* Externally visible pins */ +SND_SOC_DAPM_OUTPUT("WM2000 SPKN"), +SND_SOC_DAPM_OUTPUT("WM2000 SPKP"), + +SND_SOC_DAPM_INPUT("WM2000 LINN"), +SND_SOC_DAPM_INPUT("WM2000 LINP"), + +SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0, + wm2000_anc_power_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +}; + +/* Target, Path, Source */ +static const struct snd_soc_dapm_route audio_map[] = { + { "WM2000 SPKN", NULL, "ANC Engine" }, + { "WM2000 SPKP", NULL, "ANC Engine" }, + { "ANC Engine", NULL, "WM2000 LINN" }, + { "ANC Engine", NULL, "WM2000 LINP" }, +}; + +/* Called from the machine driver */ +int wm2000_add_controls(struct snd_soc_codec *codec) +{ + int ret; + + if (!wm2000_i2c) { + pr_err("WM2000 not yet probed\n"); + return -ENODEV; + } + + ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets, + ARRAY_SIZE(wm2000_dapm_widgets)); + if (ret < 0) + return ret; + + ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + if (ret < 0) + return ret; + + return snd_soc_add_controls(codec, wm2000_controls, + ARRAY_SIZE(wm2000_controls)); +} +EXPORT_SYMBOL_GPL(wm2000_add_controls); + +static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) +{ + struct wm2000_priv *wm2000; + struct wm2000_platform_data *pdata; + const char *filename; + const struct firmware *fw; + int reg, ret; + u16 id; + + if (wm2000_i2c) { + dev_err(&i2c->dev, "Another WM2000 is already registered\n"); + return -EINVAL; + } + + wm2000 = kzalloc(sizeof(struct wm2000_priv), GFP_KERNEL); + if (wm2000 == NULL) { + dev_err(&i2c->dev, "Unable to allocate private data\n"); + return -ENOMEM; + } + + /* Verify that this is a WM2000 */ + reg = wm2000_read(i2c, WM2000_REG_ID1); + id = reg << 8; + reg = wm2000_read(i2c, WM2000_REG_ID2); + id |= reg & 0xff; + + if (id != 0x2000) { + dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); + ret = -ENODEV; + goto err; + } + + reg = wm2000_read(i2c, WM2000_REG_REVISON); + dev_info(&i2c->dev, "revision %c\n", reg + 'A'); + + filename = "wm2000_anc.bin"; + pdata = dev_get_platdata(&i2c->dev); + if (pdata) { + wm2000->mclk_div = pdata->mclkdiv2; + wm2000->speech_clarity = !pdata->speech_enh_disable; + + if (pdata->download_file) + filename = pdata->download_file; + } + + ret = request_firmware(&fw, filename, &i2c->dev); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); + goto err; + } + + /* Pre-cook the concatenation of the register address onto the image */ + wm2000->anc_download_size = fw->size + 2; + wm2000->anc_download = kmalloc(wm2000->anc_download_size, GFP_KERNEL); + if (wm2000->anc_download == NULL) { + dev_err(&i2c->dev, "Out of memory\n"); + ret = -ENOMEM; + goto err_fw; + } + + wm2000->anc_download[0] = 0x80; + wm2000->anc_download[1] = 0x00; + memcpy(wm2000->anc_download + 2, fw->data, fw->size); + + release_firmware(fw); + + dev_set_drvdata(&i2c->dev, wm2000); + wm2000->anc_eng_ena = 1; + wm2000->i2c = i2c; + + wm2000_reset(wm2000); + + /* This will trigger a transition to standby mode by default */ + wm2000_anc_set_mode(wm2000); + + wm2000_i2c = i2c; + + return 0; + +err_fw: + release_firmware(fw); +err: + kfree(wm2000); + return ret; +} + +static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + wm2000_anc_transition(wm2000, ANC_OFF); + + wm2000_i2c = NULL; + kfree(wm2000->anc_download); + kfree(wm2000); + + return 0; +} + +static void wm2000_i2c_shutdown(struct i2c_client *i2c) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + wm2000_anc_transition(wm2000, ANC_OFF); +} + +#ifdef CONFIG_PM +static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + return wm2000_anc_transition(wm2000, ANC_OFF); +} + +static int wm2000_i2c_resume(struct i2c_client *i2c) +{ + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); + + return wm2000_anc_set_mode(wm2000); +} +#else +#define wm2000_i2c_suspend NULL +#define wm2000_i2c_resume NULL +#endif + +static const struct i2c_device_id wm2000_i2c_id[] = { + { "wm2000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id); + +static struct i2c_driver wm2000_i2c_driver = { + .driver = { + .name = "wm2000", + .owner = THIS_MODULE, + }, + .probe = wm2000_i2c_probe, + .remove = __devexit_p(wm2000_i2c_remove), + .suspend = wm2000_i2c_suspend, + .resume = wm2000_i2c_resume, + .shutdown = wm2000_i2c_shutdown, + .id_table = wm2000_i2c_id, +}; + +static int __init wm2000_init(void) +{ + return i2c_add_driver(&wm2000_i2c_driver); +} +module_init(wm2000_init); + +static void __exit wm2000_exit(void) +{ + i2c_del_driver(&wm2000_i2c_driver); +} +module_exit(wm2000_exit); + +MODULE_DESCRIPTION("ASoC WM2000 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h new file mode 100644 index 000000000000..c18e261c3c7f --- /dev/null +++ b/sound/soc/codecs/wm2000.h @@ -0,0 +1,79 @@ +/* + * wm2000.h -- WM2000 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM2000_H +#define _WM2000_H + +struct wm2000_setup_data { + unsigned short i2c_address; + int mclk_div; /* Set to a non-zero value if MCLK_DIV_2 required */ +}; + +extern int wm2000_add_controls(struct snd_soc_codec *codec); + +extern struct snd_soc_dai wm2000_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm2000; + +#define WM2000_REG_SYS_START 0x8000 +#define WM2000_REG_SPEECH_CLARITY 0x8fef +#define WM2000_REG_SYS_WATCHDOG 0x8ff6 +#define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7 +#define WM2000_REG_ANA_VMID_PU_TIME 0x8ff8 +#define WM2000_REG_CAT_FLTR_INDX 0x8ff9 +#define WM2000_REG_CAT_GAIN_0 0x8ffa +#define WM2000_REG_SYS_STATUS 0x8ffc +#define WM2000_REG_SYS_MODE_CNTRL 0x8ffd +#define WM2000_REG_SYS_START0 0x8ffe +#define WM2000_REG_SYS_START1 0x8fff +#define WM2000_REG_ID1 0xf000 +#define WM2000_REG_ID2 0xf001 +#define WM2000_REG_REVISON 0xf002 +#define WM2000_REG_SYS_CTL1 0xf003 +#define WM2000_REG_SYS_CTL2 0xf004 +#define WM2000_REG_ANC_STAT 0xf005 +#define WM2000_REG_IF_CTL 0xf006 + +/* SPEECH_CLARITY */ +#define WM2000_SPEECH_CLARITY 0x01 + +/* SYS_STATUS */ +#define WM2000_STATUS_MOUSE_ACTIVE 0x40 +#define WM2000_STATUS_CAT_FREQ_COMPLETE 0x20 +#define WM2000_STATUS_CAT_GAIN_COMPLETE 0x10 +#define WM2000_STATUS_THERMAL_SHUTDOWN_COMPLETE 0x08 +#define WM2000_STATUS_ANC_DISABLED 0x04 +#define WM2000_STATUS_POWER_DOWN_COMPLETE 0x02 +#define WM2000_STATUS_BOOT_COMPLETE 0x01 + +/* SYS_MODE_CNTRL */ +#define WM2000_MODE_ANA_SEQ_INCLUDE 0x80 +#define WM2000_MODE_MOUSE_ENABLE 0x40 +#define WM2000_MODE_CAT_FREQ_ENABLE 0x20 +#define WM2000_MODE_CAT_GAIN_ENABLE 0x10 +#define WM2000_MODE_BYPASS_ENTRY 0x08 +#define WM2000_MODE_STANDBY_ENTRY 0x04 +#define WM2000_MODE_THERMAL_ENABLE 0x02 +#define WM2000_MODE_POWER_DOWN 0x01 + +/* SYS_CTL1 */ +#define WM2000_SYS_STBY 0x01 + +/* SYS_CTL2 */ +#define WM2000_MCLK_DIV2_ENA_CLR 0x80 +#define WM2000_MCLK_DIV2_ENA_SET 0x40 +#define WM2000_ANC_ENG_CLR 0x20 +#define WM2000_ANC_ENG_SET 0x10 +#define WM2000_ANC_INT_N_CLR 0x08 +#define WM2000_ANC_INT_N_SET 0x04 +#define WM2000_RAM_CLR 0x02 +#define WM2000_RAM_SET 0x01 + +/* ANC_STAT */ +#define WM2000_ANC_ENG_IDLE 0x01 + +#endif -- GitLab From 751ef159c5600e7ee53e64c3d04f3e2d78908ce5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 14 Dec 2009 09:01:07 +0100 Subject: [PATCH 1925/3892] OMAP: DSS2: add Toppoly TDO35S panel Signed-off-by: Mike Rapoport Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 6 + drivers/video/omap2/displays/Makefile | 1 + .../omap2/displays/panel-toppoly-tdo35s.c | 112 ++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 drivers/video/omap2/displays/panel-toppoly-tdo35s.c diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 4ce47ddffd3c..4d95ed52886c 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -25,4 +25,10 @@ config PANEL_TAAL help Taal DSI command mode panel from TPO. +config PANEL_TOPPOLY_TDO35S + tristate "Toppoly TDO35S LCD Panel support" + depends on OMAP2_DSS + help + LCD Panel used in CM-T35 + endmenu diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 8f3d0adc7612..e75cc70415ff 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o +obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o \ No newline at end of file diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c new file mode 100644 index 000000000000..e744b8c83817 --- /dev/null +++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c @@ -0,0 +1,112 @@ +/* + * LCD panel driver for Toppoly TDO35S + * + * Copyright (C) 2009 CompuLab, Ltd. + * Author: Mike Rapoport + * + * Based on generic panel support + * Copyright (C) 2008 Nokia Corporation + * Author: Tomi Valkeinen + * + * 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, see . + */ + +#include +#include + +#include + +static struct omap_video_timings toppoly_tdo_panel_timings = { + /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ + .x_res = 480, + .y_res = 640, + + .pixel_clock = 26000, + + .hfp = 104, + .hsw = 8, + .hbp = 8, + + .vfp = 4, + .vsw = 2, + .vbp = 2, +}; + +static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) +{ + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS; + dssdev->panel.timings = toppoly_tdo_panel_timings; + + return 0; +} + +static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev) +{ +} + +static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + if (dssdev->platform_enable) + r = dssdev->platform_enable(dssdev); + + return r; +} + +static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev) +{ + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev) +{ + toppoly_tdo_panel_disable(dssdev); + return 0; +} + +static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev) +{ + return toppoly_tdo_panel_enable(dssdev); +} + +static struct omap_dss_driver generic_driver = { + .probe = toppoly_tdo_panel_probe, + .remove = toppoly_tdo_panel_remove, + + .enable = toppoly_tdo_panel_enable, + .disable = toppoly_tdo_panel_disable, + .suspend = toppoly_tdo_panel_suspend, + .resume = toppoly_tdo_panel_resume, + + .driver = { + .name = "toppoly_tdo35s_panel", + .owner = THIS_MODULE, + }, +}; + +static int __init toppoly_tdo_panel_drv_init(void) +{ + return omap_dss_register_driver(&generic_driver); +} + +static void __exit toppoly_tdo_panel_drv_exit(void) +{ + omap_dss_unregister_driver(&generic_driver); +} + +module_init(toppoly_tdo_panel_drv_init); +module_exit(toppoly_tdo_panel_drv_exit); +MODULE_LICENSE("GPL"); -- GitLab From 9ce4ad0a7b2e21363ce1d1d4c8eb4c2ae213cb59 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Fri, 11 Dec 2009 21:30:14 +0200 Subject: [PATCH 1926/3892] OMAP: DSS: add TPO TD043MTEA1 panel Add support of TPO TD043MTEA1 TFT LCD panel to DSS2 driver. This panel is used by OMAP3 Pandora device. Signed-off-by: Grazvydas Ignotas Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 6 + drivers/video/omap2/displays/Makefile | 3 +- .../omap2/displays/panel-tpo-td043mtea1.c | 489 ++++++++++++++++++ 3 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 drivers/video/omap2/displays/panel-tpo-td043mtea1.c diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 4d95ed52886c..dfb57ee50861 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -31,4 +31,10 @@ config PANEL_TOPPOLY_TDO35S help LCD Panel used in CM-T35 +config PANEL_TPO_TD043MTEA1 + tristate "TPO TD043MTEA1 LCD Panel" + depends on OMAP2_DSS && I2C + help + LCD Panel used in OMAP3 Pandora + endmenu diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index e75cc70415ff..e2bb32168dee 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o -obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o \ No newline at end of file +obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o +obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c new file mode 100644 index 000000000000..f297a46f2b1a --- /dev/null +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -0,0 +1,489 @@ +/* + * LCD panel driver for TPO TD043MTEA1 + * + * Author: Gražvydas Ignotas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define TPO_R02_MODE(x) ((x) & 7) +#define TPO_R02_MODE_800x480 7 +#define TPO_R02_NCLK_RISING BIT(3) +#define TPO_R02_HSYNC_HIGH BIT(4) +#define TPO_R02_VSYNC_HIGH BIT(5) + +#define TPO_R03_NSTANDBY BIT(0) +#define TPO_R03_EN_CP_CLK BIT(1) +#define TPO_R03_EN_VGL_PUMP BIT(2) +#define TPO_R03_EN_PWM BIT(3) +#define TPO_R03_DRIVING_CAP_100 BIT(4) +#define TPO_R03_EN_PRE_CHARGE BIT(6) +#define TPO_R03_SOFTWARE_CTL BIT(7) + +#define TPO_R04_NFLIP_H BIT(0) +#define TPO_R04_NFLIP_V BIT(1) +#define TPO_R04_CP_CLK_FREQ_1H BIT(2) +#define TPO_R04_VGL_FREQ_1H BIT(4) + +#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \ + TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \ + TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ + TPO_R03_SOFTWARE_CTL) + +#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \ + TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) + +static const u16 tpo_td043_def_gamma[12] = { + 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020 +}; + +struct tpo_td043_device { + struct spi_device *spi; + struct regulator *vcc_reg; + u16 gamma[12]; + u32 mode; + u32 hmirror:1; + u32 vmirror:1; +}; + +static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) +{ + struct spi_message m; + struct spi_transfer xfer; + u16 w; + int r; + + spi_message_init(&m); + + memset(&xfer, 0, sizeof(xfer)); + + w = ((u16)addr << 10) | (1 << 8) | data; + xfer.tx_buf = &w; + xfer.bits_per_word = 16; + xfer.len = 2; + spi_message_add_tail(&xfer, &m); + + r = spi_sync(spi, &m); + if (r < 0) + dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r); + return r; +} + +static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12]) +{ + u8 i, val; + + /* gamma bits [9:8] */ + for (val = i = 0; i < 4; i++) + val |= (gamma[i] & 0x300) >> ((i + 1) * 2); + tpo_td043_write(spi, 0x11, val); + + for (val = i = 0; i < 4; i++) + val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2); + tpo_td043_write(spi, 0x12, val); + + for (val = i = 0; i < 4; i++) + val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2); + tpo_td043_write(spi, 0x13, val); + + /* gamma bits [7:0] */ + for (val = i = 0; i < 12; i++) + tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff); +} + +static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) +{ + u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \ + TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; + if (h) + reg4 &= ~TPO_R04_NFLIP_H; + if (v) + reg4 &= ~TPO_R04_NFLIP_V; + + return tpo_td043_write(spi, 4, reg4); +} + +static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + + tpo_td043->hmirror = enable; + return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, + tpo_td043->vmirror); +} + +static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + + return tpo_td043->hmirror; +} + +static ssize_t tpo_td043_vmirror_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror); +} + +static ssize_t tpo_td043_vmirror_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + long val; + int ret; + + ret = strict_strtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val); + if (ret < 0) + return ret; + + tpo_td043->vmirror = val; + + return count; +} + +static ssize_t tpo_td043_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode); +} + +static ssize_t tpo_td043_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + long val; + int ret; + + ret = strict_strtol(buf, 0, &val); + if (ret != 0 || val & ~7) + return -EINVAL; + + tpo_td043->mode = val; + + val |= TPO_R02_NCLK_RISING; + tpo_td043_write(tpo_td043->spi, 2, val); + + return count; +} + +static ssize_t tpo_td043_gamma_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + ssize_t len = 0; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) { + ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", + tpo_td043->gamma[i]); + if (ret < 0) + return ret; + len += ret; + } + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t tpo_td043_gamma_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); + unsigned int g[12]; + int ret; + int i; + + ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", + &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], + &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); + + if (ret != 12) + return -EINVAL; + + for (i = 0; i < 12; i++) + tpo_td043->gamma[i] = g[i]; + + tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); + + return count; +} + +static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR, + tpo_td043_vmirror_show, tpo_td043_vmirror_store); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + tpo_td043_mode_show, tpo_td043_mode_store); +static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR, + tpo_td043_gamma_show, tpo_td043_gamma_store); + +static struct attribute *tpo_td043_attrs[] = { + &dev_attr_vmirror.attr, + &dev_attr_mode.attr, + &dev_attr_gamma.attr, + NULL, +}; + +static struct attribute_group tpo_td043_attr_group = { + .attrs = tpo_td043_attrs, +}; + +static const struct omap_video_timings tpo_td043_timings = { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 36000, + + .hsw = 1, + .hfp = 68, + .hbp = 214, + + .vsw = 1, + .vfp = 39, + .vbp = 34, +}; + +static int tpo_td043_enable(struct omap_dss_device *dssdev) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + int nreset_gpio = dssdev->reset_gpio; + int ret; + + dev_dbg(&dssdev->dev, "enable\n"); + + if (dssdev->platform_enable) { + ret = dssdev->platform_enable(dssdev); + if (ret) + return ret; + } + + regulator_enable(tpo_td043->vcc_reg); + + /* wait for power up */ + msleep(160); + + if (gpio_is_valid(nreset_gpio)) + gpio_set_value(nreset_gpio, 1); + + tpo_td043_write(tpo_td043->spi, 2, + TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); + tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL); + tpo_td043_write(tpo_td043->spi, 0x20, 0xf0); + tpo_td043_write(tpo_td043->spi, 0x21, 0xf0); + tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, + tpo_td043->vmirror); + tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); + + return 0; +} + +static void tpo_td043_disable(struct omap_dss_device *dssdev) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + int nreset_gpio = dssdev->reset_gpio; + + dev_dbg(&dssdev->dev, "disable\n"); + + tpo_td043_write(tpo_td043->spi, 3, + TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); + + if (gpio_is_valid(nreset_gpio)) + gpio_set_value(nreset_gpio, 0); + + /* wait for at least 2 vsyncs before cutting off power */ + msleep(50); + + tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY); + + regulator_disable(tpo_td043->vcc_reg); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +static int tpo_td043_suspend(struct omap_dss_device *dssdev) +{ + tpo_td043_disable(dssdev); + return 0; +} + +static int tpo_td043_resume(struct omap_dss_device *dssdev) +{ + return tpo_td043_enable(dssdev); +} + +static int tpo_td043_probe(struct omap_dss_device *dssdev) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + int nreset_gpio = dssdev->reset_gpio; + int ret = 0; + + dev_dbg(&dssdev->dev, "probe\n"); + + if (tpo_td043 == NULL) { + dev_err(&dssdev->dev, "missing tpo_td043_device\n"); + return -ENODEV; + } + + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS | + OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC; + dssdev->panel.timings = tpo_td043_timings; + dssdev->ctrl.pixel_size = 24; + + tpo_td043->mode = TPO_R02_MODE_800x480; + memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma)); + + tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc"); + if (IS_ERR(tpo_td043->vcc_reg)) { + dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n"); + ret = PTR_ERR(tpo_td043->vcc_reg); + goto fail_regulator; + } + + if (gpio_is_valid(nreset_gpio)) { + ret = gpio_request(nreset_gpio, "lcd reset"); + if (ret < 0) { + dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); + goto fail_gpio_req; + } + + ret = gpio_direction_output(nreset_gpio, 0); + if (ret < 0) { + dev_err(&dssdev->dev, "couldn't set GPIO direction\n"); + goto fail_gpio_direction; + } + } + + ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); + if (ret) + dev_warn(&dssdev->dev, "failed to create sysfs files\n"); + + return 0; + +fail_gpio_direction: + gpio_free(nreset_gpio); +fail_gpio_req: + regulator_put(tpo_td043->vcc_reg); +fail_regulator: + kfree(tpo_td043); + return ret; +} + +static void tpo_td043_remove(struct omap_dss_device *dssdev) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + int nreset_gpio = dssdev->reset_gpio; + + dev_dbg(&dssdev->dev, "remove\n"); + + sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); + regulator_put(tpo_td043->vcc_reg); + if (gpio_is_valid(nreset_gpio)) + gpio_free(nreset_gpio); +} + +static struct omap_dss_driver tpo_td043_driver = { + .probe = tpo_td043_probe, + .remove = tpo_td043_remove, + + .enable = tpo_td043_enable, + .disable = tpo_td043_disable, + .suspend = tpo_td043_suspend, + .resume = tpo_td043_resume, + .set_mirror = tpo_td043_set_hmirror, + .get_mirror = tpo_td043_get_hmirror, + + .driver = { + .name = "tpo_td043mtea1_panel", + .owner = THIS_MODULE, + }, +}; + +static int tpo_td043_spi_probe(struct spi_device *spi) +{ + struct omap_dss_device *dssdev = spi->dev.platform_data; + struct tpo_td043_device *tpo_td043; + int ret; + + if (dssdev == NULL) { + dev_err(&spi->dev, "missing dssdev\n"); + return -ENODEV; + } + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_0; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi_setup failed: %d\n", ret); + return ret; + } + + tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL); + if (tpo_td043 == NULL) + return -ENOMEM; + + tpo_td043->spi = spi; + dev_set_drvdata(&spi->dev, tpo_td043); + dev_set_drvdata(&dssdev->dev, tpo_td043); + + omap_dss_register_driver(&tpo_td043_driver); + + return 0; +} + +static int __devexit tpo_td043_spi_remove(struct spi_device *spi) +{ + struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); + + omap_dss_unregister_driver(&tpo_td043_driver); + kfree(tpo_td043); + + return 0; +} + +static struct spi_driver tpo_td043_spi_driver = { + .driver = { + .name = "tpo_td043mtea1_panel_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = tpo_td043_spi_probe, + .remove = __devexit_p(tpo_td043_spi_remove), +}; + +static int __init tpo_td043_init(void) +{ + return spi_register_driver(&tpo_td043_spi_driver); +} + +static void __exit tpo_td043_exit(void) +{ + spi_unregister_driver(&tpo_td043_spi_driver); +} + +module_init(tpo_td043_init); +module_exit(tpo_td043_exit); + +MODULE_AUTHOR("Gražvydas Ignotas "); +MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); +MODULE_LICENSE("GPL"); -- GitLab From 60596045ac3d73ab6aac85d1eca617ba4c97b020 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 14 Jan 2010 15:12:47 +0200 Subject: [PATCH 1927/3892] OMAP: DSS2: Improve Kconfig help texts Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Kconfig | 26 ++++++++++++++++++++++---- drivers/video/omap2/omapfb/Kconfig | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index c63ce767b277..87afb81b2c44 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -30,19 +30,29 @@ config OMAP2_DSS_COLLECT_IRQ_STATS depends on OMAP2_DSS_DEBUG_SUPPORT default n help - Collect DSS IRQ statistics, printable via debugfs + Collect DSS IRQ statistics, printable via debugfs. + + The statistics can be found from + /omapdss/dispc_irq for DISPC interrupts, and + /omapdss/dsi_irq for DSI interrupts. config OMAP2_DSS_RFBI bool "RFBI support" default n help - MIPI DBI, or RFBI (Remote Framebuffer Interface), support. + MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas + Instrument's terminology). + + DBI is a bus between the host processor and a peripheral, + such as a display or a framebuffer chip. + + See http://www.mipi.org/ for DBI spesifications. config OMAP2_DSS_VENC bool "VENC support" default y help - OMAP Video Encoder support. + OMAP Video Encoder support for S-Video and composite TV-out. config OMAP2_DSS_SDI bool "SDI support" @@ -51,12 +61,20 @@ config OMAP2_DSS_SDI help SDI (Serial Display Interface) support. + SDI is a high speed one-way display serial bus between the host + processor and a display. + config OMAP2_DSS_DSI bool "DSI support" depends on ARCH_OMAP3 default n help - MIPI DSI support. + MIPI DSI (Display Serial Interface) support. + + DSI is a high speed half-duplex serial interface between the host + processor and a peripheral, such as a display or a framebuffer chip. + + See http://www.mipi.org/ for DSI spesifications. config OMAP2_DSS_USE_DSI_PLL bool "Use DSI PLL for PCLK (EXPERIMENTAL)" diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index bb694cc52a50..5effa1d4d0e6 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -16,7 +16,7 @@ config FB_OMAP2_DEBUG_SUPPORT depends on FB_OMAP2 help Support for debug output. You have to enable the actual printing - with debug module parameter. + with 'debug' module parameter. config FB_OMAP2_FORCE_AUTO_UPDATE bool "Force main display to automatic update mode" -- GitLab From 3e9ff04408483b7972240cf433c7fb4b6b88cf0a Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 14 Jan 2010 21:25:43 +0100 Subject: [PATCH 1928/3892] omapfb: Fix 12-bit display (RGB444 color mode) handling Support for RGB444 (12-bit) pixel format has been introduced into omapfb/lcdc by Mark Underwood on 2006-05-26 (commit f74edb6668aad9fc8e81585861b18f996c78a574) in preparation for Amstrad Delta (E3) videophone LCD display support. Before the Amstrad Delta LCD patch by Jonathan McDowell was applied (on 2006-08-04, commit 8d22fb2ea004cdb6379b54c1a8fd1546cfe40ed7), omapfb and lcdc code was changed substantially (commit e563dc81aa01bd8bbb01bc53975a15c398715f62 dated 2006-06-26) in a way that broke Mark's 12-bit display support. Than, a patch by Jonathan, that supposed to correct the problem, was introduced immediatelly (on 2006-08-04, commit e10a75b49e7a57ae17c28b705153c70eba15a8ef). As a result, the Amstrad Delta display was working correctly at boot time, with fbset reporting: geometry 480 320 480 320 16 ... rgba 4/8,4/4,4/0,0/0 However, after first framebuffer reinitialization, colors were no longer being displayed correctly and fbset was reporting: rgba 5/11,6/5,5/0,0/0 The patch tries to correct the issue by setting plane->color_mode depending on panel->bpp, not var->bits_per_pixel. Created and tested on Amstrad Delta against linux-2.6.33-rc3. Signed-off-by: Janusz Krzysztofik Signed-off-by: Tomi Valkeinen --- drivers/video/omap/omapfb_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 2c4f470fa086..8ce60e1b220a 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -486,10 +486,11 @@ static int set_color_mode(struct omapfb_plane_struct *plane, return 0; case 12: var->bits_per_pixel = 16; - plane->color_mode = OMAPFB_COLOR_RGB444; - return 0; case 16: - plane->color_mode = OMAPFB_COLOR_RGB565; + if (plane->fbdev->panel->bpp == 12) + plane->color_mode = OMAPFB_COLOR_RGB444; + else + plane->color_mode = OMAPFB_COLOR_RGB565; return 0; default: return -EINVAL; -- GitLab From e721032785b72afbc3da14c5525ca570bc2ed108 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 11 Dec 2009 13:21:46 +0000 Subject: [PATCH 1929/3892] omapfb: lcd_ams_delta: add support for contrast control The patch extends the Amstrad Delta LCD panel driver with optional support for changing contrast using standard LCD class device API instead of setting it silently to a default value at panel enable. It also allows for lowering power consumption by turning off OMAP_PWL_CLK_ENABLE via lcd_ops.set_power callback. Created and tested against linux-omap for-next, commit 155a75d9725e66e5ec8a383822957dee52427057. Signed-off-by: Janusz Krzysztofik Signed-off-by: Tomi Valkeinen --- drivers/video/omap/lcd_ams_delta.c | 93 ++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c index 567db6ac32c8..6978ae4ef83a 100644 --- a/drivers/video/omap/lcd_ams_delta.c +++ b/drivers/video/omap/lcd_ams_delta.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,71 @@ #define AMS_DELTA_DEFAULT_CONTRAST 112 +#define AMS_DELTA_MAX_CONTRAST 0x00FF +#define AMS_DELTA_LCD_POWER 0x0100 + + +/* LCD class device section */ + +static int ams_delta_lcd; + +static int ams_delta_lcd_set_power(struct lcd_device *dev, int power) +{ + if (power == FB_BLANK_UNBLANK) { + if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) { + omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST, + OMAP_PWL_ENABLE); + omap_writeb(1, OMAP_PWL_CLK_ENABLE); + ams_delta_lcd |= AMS_DELTA_LCD_POWER; + } + } else { + if (ams_delta_lcd & AMS_DELTA_LCD_POWER) { + omap_writeb(0, OMAP_PWL_ENABLE); + omap_writeb(0, OMAP_PWL_CLK_ENABLE); + ams_delta_lcd &= ~AMS_DELTA_LCD_POWER; + } + } + return 0; +} + +static int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value) +{ + if ((value >= 0) && (value <= AMS_DELTA_MAX_CONTRAST)) { + omap_writeb(value, OMAP_PWL_ENABLE); + ams_delta_lcd &= ~AMS_DELTA_MAX_CONTRAST; + ams_delta_lcd |= value; + } + return 0; +} + +#ifdef CONFIG_LCD_CLASS_DEVICE +static int ams_delta_lcd_get_power(struct lcd_device *dev) +{ + if (ams_delta_lcd & AMS_DELTA_LCD_POWER) + return FB_BLANK_UNBLANK; + else + return FB_BLANK_POWERDOWN; +} + +static int ams_delta_lcd_get_contrast(struct lcd_device *dev) +{ + if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) + return 0; + + return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST; +} + +static struct lcd_ops ams_delta_lcd_ops = { + .get_power = ams_delta_lcd_get_power, + .set_power = ams_delta_lcd_set_power, + .get_contrast = ams_delta_lcd_get_contrast, + .set_contrast = ams_delta_lcd_set_contrast, +}; +#endif + + +/* omapfb panel section */ + static int ams_delta_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) { @@ -48,10 +114,6 @@ static int ams_delta_panel_enable(struct lcd_panel *panel) AMS_DELTA_LATCH2_LCD_NDISP); ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, AMS_DELTA_LATCH2_LCD_VBLEN); - - omap_writeb(1, OMAP_PWL_CLK_ENABLE); - omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE); - return 0; } @@ -91,8 +153,31 @@ static struct lcd_panel ams_delta_panel = { .get_caps = ams_delta_panel_get_caps, }; + +/* platform driver section */ + static int ams_delta_panel_probe(struct platform_device *pdev) { + struct lcd_device *lcd_device = NULL; +#ifdef CONFIG_LCD_CLASS_DEVICE + int ret; + + lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL, + &ams_delta_lcd_ops); + + if (IS_ERR(lcd_device)) { + ret = PTR_ERR(lcd_device); + dev_err(&pdev->dev, "failed to register device\n"); + return ret; + } + + platform_set_drvdata(pdev, lcd_device); + lcd_device->props.max_contrast = AMS_DELTA_MAX_CONTRAST; +#endif + + ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST); + ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); + omapfb_register_panel(&ams_delta_panel); return 0; } -- GitLab From 8a2cfea8ccb6292dc43c37968fe08475ae7c2576 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 4 Feb 2010 17:03:41 +0200 Subject: [PATCH 1930/3892] OMAP: DSS2: enable VDDS_DSI when using DPI It looks like on OMAP3 some DSS pins need VDDS_DSI to function properly. This has not been confirmed from TI, but looking at figure 15-1 "Display subsystem highlight" from the TRM, some data pins come near the DSI and SDI blocks. This is not very hard evidence, but the fact remains that with the power on, pixels are ok, and with the power off, pixels are not ok. It may also be that VDDS_SDI is needed to power some pins, but as normally both VDDS_SDI and VDDS_DSI come from the same power source, this hasn't been shown. It seems that a single driver can only get a regulator once. This patch solves it by getting all the required regulators in one place, and from which the submodules then get the regulators they need. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 66 +++++++++++++++++++++++++++++++++- drivers/video/omap2/dss/dpi.c | 55 +++++++++++++++++++++++----- drivers/video/omap2/dss/dsi.c | 4 +-- drivers/video/omap2/dss/dss.h | 5 ++- drivers/video/omap2/dss/venc.c | 4 +-- 5 files changed, 117 insertions(+), 17 deletions(-) diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 82918eec6d2e..791e1cb7c0bc 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,10 @@ static struct { struct clk *dss_54m_fck; struct clk *dss_96m_fck; unsigned num_clks_enabled; + + struct regulator *vdds_dsi_reg; + struct regulator *vdds_sdi_reg; + struct regulator *vdda_dac_reg; } core; static void dss_clk_enable_all_no_ctx(void); @@ -352,6 +357,50 @@ static void dss_clk_disable_all(void) dss_clk_disable(clks); } +/* REGULATORS */ + +struct regulator *dss_get_vdds_dsi(void) +{ + struct regulator *reg; + + if (core.vdds_dsi_reg != NULL) + return core.vdds_dsi_reg; + + reg = regulator_get(&core.pdev->dev, "vdds_dsi"); + if (!IS_ERR(reg)) + core.vdds_dsi_reg = reg; + + return reg; +} + +struct regulator *dss_get_vdds_sdi(void) +{ + struct regulator *reg; + + if (core.vdds_sdi_reg != NULL) + return core.vdds_sdi_reg; + + reg = regulator_get(&core.pdev->dev, "vdds_sdi"); + if (!IS_ERR(reg)) + core.vdds_sdi_reg = reg; + + return reg; +} + +struct regulator *dss_get_vdda_dac(void) +{ + struct regulator *reg; + + if (core.vdda_dac_reg != NULL) + return core.vdda_dac_reg; + + reg = regulator_get(&core.pdev->dev, "vdda_dac"); + if (!IS_ERR(reg)) + core.vdda_dac_reg = reg; + + return reg; +} + /* DEBUGFS */ #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) static void dss_debug_dump_clocks(struct seq_file *s) @@ -473,7 +522,7 @@ static int omap_dss_probe(struct platform_device *pdev) } #endif - r = dpi_init(); + r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); goto fail0; @@ -901,6 +950,21 @@ static int __init omap_dss_init(void) static void __exit omap_dss_exit(void) { + if (core.vdds_dsi_reg != NULL) { + regulator_put(core.vdds_dsi_reg); + core.vdds_dsi_reg = NULL; + } + + if (core.vdds_sdi_reg != NULL) { + regulator_put(core.vdds_sdi_reg); + core.vdds_sdi_reg = NULL; + } + + if (core.vdda_dac_reg != NULL) { + regulator_put(core.vdda_dac_reg); + core.vdda_dac_reg = NULL; + } + platform_driver_unregister(&omap_dss_driver); omap_dss_bus_unregister(); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 2d71031baa25..69ce31ae2a2f 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -25,7 +25,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -34,6 +37,7 @@ static struct { int update_enabled; + struct regulator *vdds_dsi_reg; } dpi; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL @@ -166,21 +170,27 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) goto err1; } + if (cpu_is_omap34xx()) { + r = regulator_enable(dpi.vdds_dsi_reg); + if (r) + goto err2; + } + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); r = dpi_basic_init(dssdev); if (r) - goto err2; + goto err3; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL dss_clk_enable(DSS_CLK_FCK2); r = dsi_pll_init(dssdev, 0, 1); if (r) - goto err3; + goto err4; #endif r = dpi_set_mode(dssdev); if (r) - goto err4; + goto err5; mdelay(2); @@ -188,22 +198,25 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) r = dssdev->driver->enable(dssdev); if (r) - goto err5; + goto err6; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; return 0; -err5: +err6: dispc_enable_lcd_out(0); -err4: +err5: #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL dsi_pll_uninit(); -err3: +err4: dss_clk_disable(DSS_CLK_FCK2); #endif -err2: +err3: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); +err2: + if (cpu_is_omap34xx()) + regulator_disable(dpi.vdds_dsi_reg); err1: omap_dss_stop_device(dssdev); err0: @@ -232,6 +245,9 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + if (cpu_is_omap34xx()) + regulator_disable(dpi.vdds_dsi_reg); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; omap_dss_stop_device(dssdev); @@ -251,6 +267,9 @@ static int dpi_display_suspend(struct omap_dss_device *dssdev) dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + if (cpu_is_omap34xx()) + regulator_disable(dpi.vdds_dsi_reg); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; return 0; @@ -258,11 +277,19 @@ static int dpi_display_suspend(struct omap_dss_device *dssdev) static int dpi_display_resume(struct omap_dss_device *dssdev) { + int r; + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) return -EINVAL; DSSDBG("dpi_display_resume\n"); + if (cpu_is_omap34xx()) { + r = regulator_enable(dpi.vdds_dsi_reg); + if (r) + goto err0; + } + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); dispc_enable_lcd_out(1); @@ -273,6 +300,8 @@ static int dpi_display_resume(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; return 0; +err0: + return r; } static void dpi_set_timings(struct omap_dss_device *dssdev, @@ -388,8 +417,16 @@ int dpi_init_display(struct omap_dss_device *dssdev) return 0; } -int dpi_init(void) +int dpi_init(struct platform_device *pdev) { + if (cpu_is_omap34xx()) { + dpi.vdds_dsi_reg = dss_get_vdds_dsi(); + if (IS_ERR(dpi.vdds_dsi_reg)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(dpi.vdds_dsi_reg); + } + } + return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 6122178f5f85..036f4221e3df 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3799,7 +3799,7 @@ int dsi_init(struct platform_device *pdev) goto err1; } - dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi"); + dsi.vdds_dsi_reg = dss_get_vdds_dsi(); if (IS_ERR(dsi.vdds_dsi_reg)) { iounmap(dsi.base); DSSERR("can't get VDDS_DSI regulator\n"); @@ -3830,8 +3830,6 @@ void dsi_exit(void) { kthread_stop(dsi.thread); - regulator_put(dsi.vdds_dsi_reg); - iounmap(dsi.base); DSSDBG("omap_dsi_exit\n"); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 2bcb1245d6c2..41145af36353 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -169,6 +169,9 @@ unsigned long dss_clk_get_rate(enum dss_clock clk); int dss_need_ctx_restore(void); void dss_dump_clocks(struct seq_file *s); struct bus_type *dss_get_bus(void); +struct regulator *dss_get_vdds_dsi(void); +struct regulator *dss_get_vdds_sdi(void); +struct regulator *dss_get_vdda_dac(void); /* display */ int dss_suspend_all_devices(void); @@ -261,7 +264,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high); /* DPI */ -int dpi_init(void); +int dpi_init(struct platform_device *pdev); void dpi_exit(void); int dpi_init_display(struct omap_dss_device *dssdev); diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 749a5a0f5be4..44b4998c2052 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -482,7 +482,7 @@ int venc_init(struct platform_device *pdev) return -ENOMEM; } - venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac"); + venc.vdda_dac_reg = dss_get_vdda_dac(); if (IS_ERR(venc.vdda_dac_reg)) { iounmap(venc.base); DSSERR("can't get VDDA_DAC regulator\n"); @@ -503,8 +503,6 @@ void venc_exit(void) { omap_dss_unregister_driver(&venc_driver); - regulator_put(venc.vdda_dac_reg); - iounmap(venc.base); } -- GitLab From 80b1cc23ac96373bd5ff17f8959f2587d6fc37dd Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 4 Feb 2010 17:13:16 +0200 Subject: [PATCH 1931/3892] OMAP: 3430SDP: remove vdvi regulator The regulator is now enabled by DSS driver, and thus the panel driver doesn't need to touch it. Signed-off-by: Tomi Valkeinen --- arch/arm/mach-omap2/board-3430sdp.c | 4 --- .../omap2/displays/panel-sharp-ls037v7dw01.c | 35 ------------------- 2 files changed, 39 deletions(-) diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index c90b0d0b1927..964c390c2f39 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -519,10 +519,6 @@ static struct regulator_init_data sdp3430_vdac = { /* VPLL2 for digital video outputs */ static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = { - { - .supply = "vdvi", - .dev = &sdp3430_lcd_device.dev, - }, { .supply = "vdds_dsi", .dev = &sdp3430_dss_device.dev, diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index bbe880bbe795..e207d66908d6 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -25,14 +25,6 @@ #include -struct sharp_data { - /* XXX This regulator should actually be in SDP board file, not here, - * as it doesn't actually power the LCD, but something else that - * affects the output to LCD (I think. Somebody clarify). It doesn't do - * harm here, as SDP is the only board using this currently */ - struct regulator *vdvi_reg; -}; - static struct omap_video_timings sharp_ls_timings = { .x_res = 480, .y_res = 640, @@ -50,48 +42,25 @@ static struct omap_video_timings sharp_ls_timings = { static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) { - struct sharp_data *sd; - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; dssdev->panel.acb = 0x28; dssdev->panel.timings = sharp_ls_timings; - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) - return -ENOMEM; - - dev_set_drvdata(&dssdev->dev, sd); - - sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi"); - if (IS_ERR(sd->vdvi_reg)) { - kfree(sd); - pr_err("failed to get VDVI regulator\n"); - return PTR_ERR(sd->vdvi_reg); - } - return 0; } static void sharp_ls_panel_remove(struct omap_dss_device *dssdev) { - struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); - - regulator_put(sd->vdvi_reg); - - kfree(sd); } static int sharp_ls_panel_enable(struct omap_dss_device *dssdev) { - struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); int r = 0; /* wait couple of vsyncs until enabling the LCD */ msleep(50); - regulator_enable(sd->vdvi_reg); - if (dssdev->platform_enable) r = dssdev->platform_enable(dssdev); @@ -100,13 +69,9 @@ static int sharp_ls_panel_enable(struct omap_dss_device *dssdev) static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) { - struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); - if (dssdev->platform_disable) dssdev->platform_disable(dssdev); - regulator_disable(sd->vdvi_reg); - /* wait at least 5 vsyncs after disabling the LCD */ msleep(100); -- GitLab From 92fe0ff16a9299233104187bd6ceb2101501badc Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 9 Dec 2009 17:26:25 +0100 Subject: [PATCH 1932/3892] OMAP: DSS: Taal: fix error returns in taal_probe() The workqueue creation error branch attempted to destroy a NULL wq, and, in turn, a failed registration does not destroy the newly created workqueue. The problem was reported by a static analysis tool. Signed-off-by: Aaro Koskinen Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 1f01dfc5e52e..0aaaa8a8e0f5 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -510,7 +510,7 @@ static int taal_probe(struct omap_dss_device *dssdev) if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); r = -ENOMEM; - goto err2; + goto err1; } INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); @@ -528,7 +528,7 @@ static int taal_probe(struct omap_dss_device *dssdev) &taal_bl_ops); if (IS_ERR(bldev)) { r = PTR_ERR(bldev); - goto err1; + goto err2; } td->bldev = bldev; -- GitLab From 858155fbcc0cd713f6382c527bb1c3abc0ed6d00 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 12 Feb 2010 13:02:28 +0100 Subject: [PATCH 1933/3892] HID: usbhid: introduce timeout for stuck ctrl/out URBs Some devices do not react to a control request (seen on APC UPS's) resulting in a slow stream of messages, "generic-usb ... control queue full". Therefore request needs a timeout. Cc: stable@kernel.org Signed-off-by: Oliver Neukum Signed-off-by: David Fries Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 28 ++++++++++++++++++++++++++-- drivers/hid/usbhid/usbhid.h | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 54060741d45b..74bd3ca220d3 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } + usbhid->last_out = jiffies; } else { /* * queue work to wake up the device. @@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } + usbhid->last_ctrl = jiffies; } else { /* * queue work to wake up the device. @@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->out[usbhid->outhead].report = report; usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_out + HZ * 5)) + usb_unlink_urb(usbhid->urbout); + } return; } @@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->ctrl[usbhid->ctrlhead].dir = dir; usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + usb_unlink_urb(usbhid->urbctrl); + } } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 08f505ca2e3d..ec20400c7f29 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -80,12 +80,14 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + unsigned long last_ctrl; /* record of last output for timeouts */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ + unsigned long last_out; /* record of last output for timeouts */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ -- GitLab From c7b66698122796623f1838c0ee6a8e12ec832468 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 10 Feb 2010 03:54:59 +0000 Subject: [PATCH 1934/3892] powerpc/40x: Add support for PPC40x boards with > 512MB SDRAM This patch adds support for boards with more that 512MByte RAM. Currently only 512MB of memory are enabled in the DCCR/ICCR real-mode cache control registers. This patch now enables caching in real-mode for 2GByte. Signed-off-by: Stefan Roese Cc: Benjamin Herrenschmidt Cc: Josh Boyer Signed-off-by: Josh Boyer --- arch/powerpc/mm/40x_mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c index 08dfa8e6d86f..65abfcfaaa9e 100644 --- a/arch/powerpc/mm/40x_mmu.c +++ b/arch/powerpc/mm/40x_mmu.c @@ -84,8 +84,8 @@ void __init MMU_init_hw(void) * vectors and the kernel live in real-mode. */ - mtspr(SPRN_DCCR, 0xF0000000); /* 512 MB of data space at 0x0. */ - mtspr(SPRN_ICCR, 0xF0000000); /* 512 MB of instr. space at 0x0. */ + mtspr(SPRN_DCCR, 0xFFFF0000); /* 2GByte of data space at 0x0. */ + mtspr(SPRN_ICCR, 0xFFFF0000); /* 2GByte of instr. space at 0x0. */ } #define LARGE_PAGE_SIZE_16M (1<<24) -- GitLab From 0f4f0672ac950c96cffaf84a666d35e817d7c3ca Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 2 Feb 2010 20:23:15 +0100 Subject: [PATCH 1935/3892] ARM: 5899/2: arm: provide a mechanism to reserve performance counters To add support for perf events and to allow the hardware counters to be shared with oprofile, we need a way to reserve access to the pmu (performance monitor unit). Platforms with PMU interrupts should register the interrupts in arch/arm/kernel/pmu.c Signed-off-by: Jamie Iles Signed-off-by: Russell King --- arch/arm/Kconfig | 5 ++ arch/arm/include/asm/pmu.h | 75 +++++++++++++++++++++++++++ arch/arm/kernel/Makefile | 1 + arch/arm/kernel/pmu.c | 103 +++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 arch/arm/include/asm/pmu.h create mode 100644 arch/arm/kernel/pmu.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 233a222752c0..9e08891062bf 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -863,6 +863,11 @@ config XSCALE_PMU depends on CPU_XSCALE && !XSCALE_PMU_TIMER default y +config CPU_HAS_PMU + depends on CPU_V6 || CPU_V7 || XSCALE_PMU + default y + bool + if !MMU source "arch/arm/Kconfig-nommu" endif diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h new file mode 100644 index 000000000000..2829b9f981a1 --- /dev/null +++ b/arch/arm/include/asm/pmu.h @@ -0,0 +1,75 @@ +/* + * linux/arch/arm/include/asm/pmu.h + * + * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __ARM_PMU_H__ +#define __ARM_PMU_H__ + +#ifdef CONFIG_CPU_HAS_PMU + +struct pmu_irqs { + const int *irqs; + int num_irqs; +}; + +/** + * reserve_pmu() - reserve the hardware performance counters + * + * Reserve the hardware performance counters in the system for exclusive use. + * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR() + * encoded error on failure. + */ +extern const struct pmu_irqs * +reserve_pmu(void); + +/** + * release_pmu() - Relinquish control of the performance counters + * + * Release the performance counters and allow someone else to use them. + * Callers must have disabled the counters and released IRQs before calling + * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as + * a cookie. + */ +extern int +release_pmu(const struct pmu_irqs *irqs); + +/** + * init_pmu() - Initialise the PMU. + * + * Initialise the system ready for PMU enabling. This should typically set the + * IRQ affinity and nothing else. The users (oprofile/perf events etc) will do + * the actual hardware initialisation. + */ +extern int +init_pmu(void); + +#else /* CONFIG_CPU_HAS_PMU */ + +static inline const struct pmu_irqs * +reserve_pmu(void) +{ + return ERR_PTR(-ENODEV); +} + +static inline int +release_pmu(const struct pmu_irqs *irqs) +{ + return -ENODEV; +} + +static inline int +init_pmu(void) +{ + return -ENODEV; +} + +#endif /* CONFIG_CPU_HAS_PMU */ + +#endif /* __ARM_PMU_H__ */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index dd00f747e2ad..216890d804c2 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o obj-$(CONFIG_IWMMXT) += iwmmxt.o +obj-$(CONFIG_CPU_HAS_PMU) += pmu.o AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt ifneq ($(CONFIG_ARCH_EBSA110),y) diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c new file mode 100644 index 000000000000..a124312e343f --- /dev/null +++ b/arch/arm/kernel/pmu.c @@ -0,0 +1,103 @@ +/* + * linux/arch/arm/kernel/pmu.c + * + * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles + * + * 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 the IRQs for the system. We could use something like a platform + * device but that seems fairly heavyweight for this. Also, the performance + * counters can't be removed or hotplugged. + * + * Ordering is important: init_pmu() will use the ordering to set the affinity + * to the corresponding core. e.g. the first interrupt will go to cpu 0, the + * second goes to cpu 1 etc. + */ +static const int irqs[] = { +#if defined(CONFIG_ARCH_OMAP2) + 3, +#elif defined(CONFIG_ARCH_BCMRING) + IRQ_PMUIRQ, +#elif defined(CONFIG_MACH_REALVIEW_EB) + IRQ_EB11MP_PMU_CPU0, + IRQ_EB11MP_PMU_CPU1, + IRQ_EB11MP_PMU_CPU2, + IRQ_EB11MP_PMU_CPU3, +#elif defined(CONFIG_ARCH_OMAP3) + INT_34XX_BENCH_MPU_EMUL, +#elif defined(CONFIG_ARCH_IOP32X) + IRQ_IOP32X_CORE_PMU, +#elif defined(CONFIG_ARCH_IOP33X) + IRQ_IOP33X_CORE_PMU, +#elif defined(CONFIG_ARCH_PXA) + IRQ_PMU, +#endif +}; + +static const struct pmu_irqs pmu_irqs = { + .irqs = irqs, + .num_irqs = ARRAY_SIZE(irqs), +}; + +static volatile long pmu_lock; + +const struct pmu_irqs * +reserve_pmu(void) +{ + return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) : + &pmu_irqs; +} +EXPORT_SYMBOL_GPL(reserve_pmu); + +int +release_pmu(const struct pmu_irqs *irqs) +{ + if (WARN_ON(irqs != &pmu_irqs)) + return -EINVAL; + clear_bit_unlock(0, &pmu_lock); + return 0; +} +EXPORT_SYMBOL_GPL(release_pmu); + +static int +set_irq_affinity(int irq, + unsigned int cpu) +{ +#ifdef CONFIG_SMP + int err = irq_set_affinity(irq, cpumask_of(cpu)); + if (err) + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, cpu); + return err; +#else + return 0; +#endif +} + +int +init_pmu(void) +{ + int i, err = 0; + + for (i = 0; i < pmu_irqs.num_irqs; ++i) { + err = set_irq_affinity(pmu_irqs.irqs[i], i); + if (err) + break; + } + + return err; +} +EXPORT_SYMBOL_GPL(init_pmu); -- GitLab From 1618fdd9602c689de2f820a88cb3e283a39c3d90 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 2 Feb 2010 20:24:07 +0100 Subject: [PATCH 1936/3892] ARM: 5901/2: arm/oprofile: reserve the PMU when starting Make sure that we have access to the performance counters and that they aren't being used by perf events or anything else. Cc: Will Deacon Cc: Jean Pihet Signed-off-by: Jamie Iles Signed-off-by: Russell King --- arch/arm/oprofile/op_model_arm11_core.c | 4 +-- arch/arm/oprofile/op_model_arm11_core.h | 4 +-- arch/arm/oprofile/op_model_mpcore.c | 42 +++++++++++++------------ arch/arm/oprofile/op_model_v6.c | 30 +++++++++++------- arch/arm/oprofile/op_model_v7.c | 30 +++++++++++------- arch/arm/oprofile/op_model_v7.h | 4 +-- arch/arm/oprofile/op_model_xscale.c | 35 +++++++++++---------- 7 files changed, 85 insertions(+), 64 deletions(-) diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c index ad80752cb9fb..ef3e2653b90c 100644 --- a/arch/arm/oprofile/op_model_arm11_core.c +++ b/arch/arm/oprofile/op_model_arm11_core.c @@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg) return IRQ_HANDLED; } -int arm11_request_interrupts(int *irqs, int nr) +int arm11_request_interrupts(const int *irqs, int nr) { unsigned int i; int ret = 0; @@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr) return ret; } -void arm11_release_interrupts(int *irqs, int nr) +void arm11_release_interrupts(const int *irqs, int nr) { unsigned int i; diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h index 6f8538e5a960..1902b99d9dfd 100644 --- a/arch/arm/oprofile/op_model_arm11_core.h +++ b/arch/arm/oprofile/op_model_arm11_core.h @@ -39,7 +39,7 @@ int arm11_setup_pmu(void); int arm11_start_pmu(void); int arm11_stop_pmu(void); -int arm11_request_interrupts(int *, int); -void arm11_release_interrupts(int *, int); +int arm11_request_interrupts(const int *, int); +void arm11_release_interrupts(const int *, int); #endif diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c index 4ce0f9801e2e..f73ce875a395 100644 --- a/arch/arm/oprofile/op_model_mpcore.c +++ b/arch/arm/oprofile/op_model_mpcore.c @@ -32,6 +32,7 @@ /* #define DEBUG */ #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include "op_counter.h" #include "op_arm_model.h" @@ -58,6 +60,7 @@ * Bitmask of used SCU counters */ static unsigned int scu_em_used; +static const struct pmu_irqs *pmu_irqs; /* * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) @@ -225,33 +228,40 @@ static int em_setup_ctrs(void) return 0; } -static int arm11_irqs[] = { - [0] = IRQ_EB11MP_PMU_CPU0, - [1] = IRQ_EB11MP_PMU_CPU1, - [2] = IRQ_EB11MP_PMU_CPU2, - [3] = IRQ_EB11MP_PMU_CPU3 -}; - static int em_start(void) { int ret; - ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + pmu_irqs = reserve_pmu(); + if (IS_ERR(pmu_irqs)) { + ret = PTR_ERR(pmu_irqs); + goto out; + } + + ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); if (ret == 0) { em_call_function(arm11_start_pmu); ret = scu_start(); - if (ret) - arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + if (ret) { + arm11_release_interrupts(pmu_irqs->irqs, + pmu_irqs->num_irqs); + } else { + release_pmu(pmu_irqs); + pmu_irqs = NULL; + } } + +out: return ret; } static void em_stop(void) { em_call_function(arm11_stop_pmu); - arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); + arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); scu_stop(); + release_pmu(pmu_irqs); } /* @@ -283,15 +293,7 @@ static int em_setup(void) em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); - /* - * Send CP15 PMU interrupts to the owner CPU. - */ - em_route_irq(IRQ_EB11MP_PMU_CPU0, 0); - em_route_irq(IRQ_EB11MP_PMU_CPU1, 1); - em_route_irq(IRQ_EB11MP_PMU_CPU2, 2); - em_route_irq(IRQ_EB11MP_PMU_CPU3, 3); - - return 0; + return init_pmu(); } struct op_arm_model_spec op_mpcore_spec = { diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c index f7d2ec5ee9a1..a22357a2fd08 100644 --- a/arch/arm/oprofile/op_model_v6.c +++ b/arch/arm/oprofile/op_model_v6.c @@ -19,39 +19,47 @@ /* #define DEBUG */ #include #include +#include #include #include #include #include #include +#include #include "op_counter.h" #include "op_arm_model.h" #include "op_model_arm11_core.h" -static int irqs[] = { -#ifdef CONFIG_ARCH_OMAP2 - 3, -#endif -#ifdef CONFIG_ARCH_BCMRING - IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */ -#endif -}; +static const struct pmu_irqs *pmu_irqs; static void armv6_pmu_stop(void) { arm11_stop_pmu(); - arm11_release_interrupts(irqs, ARRAY_SIZE(irqs)); + arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); + release_pmu(pmu_irqs); + pmu_irqs = NULL; } static int armv6_pmu_start(void) { int ret; - ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs)); - if (ret >= 0) + pmu_irqs = reserve_pmu(); + if (IS_ERR(pmu_irqs)) { + ret = PTR_ERR(pmu_irqs); + goto out; + } + + ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); + if (ret >= 0) { ret = arm11_start_pmu(); + } else { + release_pmu(pmu_irqs); + pmu_irqs = NULL; + } +out: return ret; } diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c index 2088a6c0cc0e..8642d0891ae1 100644 --- a/arch/arm/oprofile/op_model_v7.c +++ b/arch/arm/oprofile/op_model_v7.c @@ -11,11 +11,14 @@ */ #include #include +#include #include #include #include #include +#include + #include "op_counter.h" #include "op_arm_model.h" #include "op_model_v7.h" @@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg) return IRQ_HANDLED; } -int armv7_request_interrupts(int *irqs, int nr) +int armv7_request_interrupts(const int *irqs, int nr) { unsigned int i; int ret = 0; @@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr) return ret; } -void armv7_release_interrupts(int *irqs, int nr) +void armv7_release_interrupts(const int *irqs, int nr) { unsigned int i; @@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void) } #endif - -static int irqs[] = { -#ifdef CONFIG_ARCH_OMAP3 - INT_34XX_BENCH_MPU_EMUL, -#endif -}; +static const struct pmu_irqs *pmu_irqs; static void armv7_pmnc_stop(void) { @@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void) armv7_pmnc_dump_regs(); #endif armv7_stop_pmnc(); - armv7_release_interrupts(irqs, ARRAY_SIZE(irqs)); + armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); + release_pmu(pmu_irqs); + pmu_irqs = NULL; } static int armv7_pmnc_start(void) { int ret; + pmu_irqs = reserve_pmu(); + if (IS_ERR(pmu_irqs)) + return PTR_ERR(pmu_irqs); + #ifdef DEBUG armv7_pmnc_dump_regs(); #endif - ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs)); - if (ret >= 0) + ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); + if (ret >= 0) { armv7_start_pmnc(); + } else { + release_pmu(pmu_irqs); + pmu_irqs = NULL; + } return ret; } diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h index 0e19bcc2e100..9ca334b39c75 100644 --- a/arch/arm/oprofile/op_model_v7.h +++ b/arch/arm/oprofile/op_model_v7.h @@ -97,7 +97,7 @@ int armv7_setup_pmu(void); int armv7_start_pmu(void); int armv7_stop_pmu(void); -int armv7_request_interrupts(int *, int); -void armv7_release_interrupts(int *, int); +int armv7_request_interrupts(const int *, int); +void armv7_release_interrupts(const int *, int); #endif diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c index 724ab9ce2526..1d34a02048bd 100644 --- a/arch/arm/oprofile/op_model_xscale.c +++ b/arch/arm/oprofile/op_model_xscale.c @@ -17,12 +17,14 @@ /* #define DEBUG */ #include #include +#include #include #include #include #include #include +#include #include "op_counter.h" #include "op_arm_model.h" @@ -33,17 +35,6 @@ #define PMU_RESET (CCNT_RESET | PMN_RESET) #define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */ -/* TODO do runtime detection */ -#ifdef CONFIG_ARCH_IOP32X -#define XSCALE_PMU_IRQ IRQ_IOP32X_CORE_PMU -#endif -#ifdef CONFIG_ARCH_IOP33X -#define XSCALE_PMU_IRQ IRQ_IOP33X_CORE_PMU -#endif -#ifdef CONFIG_ARCH_PXA -#define XSCALE_PMU_IRQ IRQ_PMU -#endif - /* * Different types of events that can be counted by the XScale PMU * as used by Oprofile userspace. Here primarily for documentation @@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg) return IRQ_HANDLED; } +static const struct pmu_irqs *pmu_irqs; + static void xscale_pmu_stop(void) { u32 pmnc = read_pmnc(); @@ -374,20 +367,30 @@ static void xscale_pmu_stop(void) pmnc &= ~PMU_ENABLE; write_pmnc(pmnc); - free_irq(XSCALE_PMU_IRQ, results); + free_irq(pmu_irqs->irqs[0], results); + release_pmu(pmu_irqs); + pmu_irqs = NULL; } static int xscale_pmu_start(void) { int ret; - u32 pmnc = read_pmnc(); + u32 pmnc; + + pmu_irqs = reserve_pmu(); + if (IS_ERR(pmu_irqs)) + return PTR_ERR(pmu_irqs); + + pmnc = read_pmnc(); - ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED, - "XScale PMU", (void *)results); + ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt, + IRQF_DISABLED, "XScale PMU", (void *)results); if (ret < 0) { printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n", - XSCALE_PMU_IRQ); + pmu_irqs->irqs[0]); + release_pmu(pmu_irqs); + pmu_irqs = NULL; return ret; } -- GitLab From 7ada189f5c8627662c23f49b3e68463f86fc511e Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 2 Feb 2010 20:24:58 +0100 Subject: [PATCH 1937/3892] ARM: 5900/2: arm: enable support for software perf events The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events. Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Jamie Iles Signed-off-by: Russell King --- arch/arm/Kconfig | 2 ++ arch/arm/include/asm/perf_event.h | 31 +++++++++++++++++++++++++++++++ arch/arm/mm/fault.c | 7 +++++++ 3 files changed, 40 insertions(+) create mode 100644 arch/arm/include/asm/perf_event.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9e08891062bf..74d1e767f0b7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -18,6 +18,8 @@ config ARM select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_GENERIC_DMA_COHERENT + select HAVE_PERF_EVENTS + select PERF_USE_VMALLOC help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h new file mode 100644 index 000000000000..49e3049aba32 --- /dev/null +++ b/arch/arm/include/asm/perf_event.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/include/asm/perf_event.h + * + * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __ARM_PERF_EVENT_H__ +#define __ARM_PERF_EVENT_H__ + +/* + * NOP: on *most* (read: all supported) ARM platforms, the performance + * counter interrupts are regular interrupts and not an NMI. This + * means that when we receive the interrupt we can call + * perf_event_do_pending() that handles all of the work with + * interrupts enabled. + */ +static inline void +set_perf_event_pending(void) +{ +} + +/* ARM performance counters start from 1 (in the cp15 accesses) so use the + * same indexes here for consistency. */ +#define PERF_EVENT_INDEX_OFFSET 1 + +#endif /* __ARM_PERF_EVENT_H__ */ diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 10e06801afb3..9d40c341e07e 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -302,6 +303,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) fault = __do_page_fault(mm, addr, fsr, tsk); up_read(&mm->mmap_sem); + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, addr); + if (fault & VM_FAULT_MAJOR) + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, addr); + else if (fault & VM_FAULT_MINOR) + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, addr); + /* * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR */ -- GitLab From 1b8873a0c6ec511870c106c80b94658f857c47f2 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 2 Feb 2010 20:25:44 +0100 Subject: [PATCH 1938/3892] ARM: 5902/4: arm/perfevents: implement perf event support for ARMv6 This patch implements support for ARMv6 performance counters in the Linux performance events subsystem. ARMv6 architectures that have the performance counters should enable HW_PERF_EVENTS to get hardware performance events support in addition to the software events. Note: only ARM Ltd ARM cores are supported. This implementation also provides an ARM PMU abstraction layer to allow ARMv7 and others to be supported in the future by adding new a 'struct arm_pmu'. Cc: Jean Pihet Cc: Will Deacon Signed-off-by: Jamie Iles Signed-off-by: Russell King --- arch/arm/Kconfig | 8 + arch/arm/kernel/Makefile | 1 + arch/arm/kernel/perf_event.c | 1348 ++++++++++++++++++++++++++++++++++ 3 files changed, 1357 insertions(+) create mode 100644 arch/arm/kernel/perf_event.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 74d1e767f0b7..9fb91ce106bc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1174,6 +1174,14 @@ config HIGHPTE depends on HIGHMEM depends on !OUTER_CACHE +config HW_PERF_EVENTS + bool "Enable hardware performance counter support for perf events" + depends on PERF_EVENTS && CPU_HAS_PMU && CPU_V6 + default y + help + Enable hardware performance counter support for perf events. If + disabled, perf events will use software events only. + source "mm/Kconfig" config LEDS diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 216890d804c2..c76e6d2679b8 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o obj-$(CONFIG_IWMMXT) += iwmmxt.o obj-$(CONFIG_CPU_HAS_PMU) += pmu.o +obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt ifneq ($(CONFIG_ARCH_EBSA110),y) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c new file mode 100644 index 000000000000..7b1022b9aa52 --- /dev/null +++ b/arch/arm/kernel/perf_event.c @@ -0,0 +1,1348 @@ +#undef DEBUG + +/* + * ARM performance counter support. + * + * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles + * + * This code is based on the sparc64 perf event code, which is in turn based + * on the x86 code. Callchain code is based on the ARM OProfile backtrace + * code. + */ +#define pr_fmt(fmt) "hw perfevents: " fmt + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static const struct pmu_irqs *pmu_irqs; + +/* + * Hardware lock to serialize accesses to PMU registers. Needed for the + * read/modify/write sequences. + */ +DEFINE_SPINLOCK(pmu_lock); + +/* + * ARMv6 supports a maximum of 3 events, starting from index 1. If we add + * another platform that supports more, we need to increase this to be the + * largest of all platforms. + */ +#define ARMPMU_MAX_HWEVENTS 4 + +/* The events for a given CPU. */ +struct cpu_hw_events { + /* + * The events that are active on the CPU for the given index. Index 0 + * is reserved. + */ + struct perf_event *events[ARMPMU_MAX_HWEVENTS]; + + /* + * A 1 bit for an index indicates that the counter is being used for + * an event. A 0 means that the counter can be used. + */ + unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; + + /* + * A 1 bit for an index indicates that the counter is actively being + * used. + */ + unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; +}; +DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); + +struct arm_pmu { + const char *name; + irqreturn_t (*handle_irq)(int irq_num, void *dev); + void (*enable)(struct hw_perf_event *evt, int idx); + void (*disable)(struct hw_perf_event *evt, int idx); + int (*event_map)(int evt); + u64 (*raw_event)(u64); + int (*get_event_idx)(struct cpu_hw_events *cpuc, + struct hw_perf_event *hwc); + u32 (*read_counter)(int idx); + void (*write_counter)(int idx, u32 val); + void (*start)(void); + void (*stop)(void); + int num_events; + u64 max_period; +}; + +/* Set at runtime when we know what CPU type we are. */ +static const struct arm_pmu *armpmu; + +#define HW_OP_UNSUPPORTED 0xFFFF + +#define C(_x) \ + PERF_COUNT_HW_CACHE_##_x + +#define CACHE_OP_UNSUPPORTED 0xFFFF + +static unsigned armpmu_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + +static int +armpmu_map_cache_event(u64 config) +{ + unsigned int cache_type, cache_op, cache_result, ret; + + cache_type = (config >> 0) & 0xff; + if (cache_type >= PERF_COUNT_HW_CACHE_MAX) + return -EINVAL; + + cache_op = (config >> 8) & 0xff; + if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) + return -EINVAL; + + cache_result = (config >> 16) & 0xff; + if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) + return -EINVAL; + + ret = (int)armpmu_perf_cache_map[cache_type][cache_op][cache_result]; + + if (ret == CACHE_OP_UNSUPPORTED) + return -ENOENT; + + return ret; +} + +static int +armpmu_event_set_period(struct perf_event *event, + struct hw_perf_event *hwc, + int idx) +{ + s64 left = atomic64_read(&hwc->period_left); + s64 period = hwc->sample_period; + int ret = 0; + + if (unlikely(left <= -period)) { + left = period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (unlikely(left <= 0)) { + left += period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (left > (s64)armpmu->max_period) + left = armpmu->max_period; + + atomic64_set(&hwc->prev_count, (u64)-left); + + armpmu->write_counter(idx, (u64)(-left) & 0xffffffff); + + perf_event_update_userpage(event); + + return ret; +} + +static u64 +armpmu_event_update(struct perf_event *event, + struct hw_perf_event *hwc, + int idx) +{ + int shift = 64 - 32; + s64 prev_raw_count, new_raw_count; + s64 delta; + +again: + prev_raw_count = atomic64_read(&hwc->prev_count); + new_raw_count = armpmu->read_counter(idx); + + if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + delta = (new_raw_count << shift) - (prev_raw_count << shift); + delta >>= shift; + + atomic64_add(delta, &event->count); + atomic64_sub(delta, &hwc->period_left); + + return new_raw_count; +} + +static void +armpmu_disable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + WARN_ON(idx < 0); + + clear_bit(idx, cpuc->active_mask); + armpmu->disable(hwc, idx); + + barrier(); + + armpmu_event_update(event, hwc, idx); + cpuc->events[idx] = NULL; + clear_bit(idx, cpuc->used_mask); + + perf_event_update_userpage(event); +} + +static void +armpmu_read(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + /* Don't read disabled counters! */ + if (hwc->idx < 0) + return; + + armpmu_event_update(event, hwc, hwc->idx); +} + +static void +armpmu_unthrottle(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + /* + * Set the period again. Some counters can't be stopped, so when we + * were throttled we simply disabled the IRQ source and the counter + * may have been left counting. If we don't do this step then we may + * get an interrupt too soon or *way* too late if the overflow has + * happened since disabling. + */ + armpmu_event_set_period(event, hwc, hwc->idx); + armpmu->enable(hwc, hwc->idx); +} + +static int +armpmu_enable(struct perf_event *event) +{ + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx; + int err = 0; + + /* If we don't have a space for the counter then finish early. */ + idx = armpmu->get_event_idx(cpuc, hwc); + if (idx < 0) { + err = idx; + goto out; + } + + /* + * If there is an event in the counter we are going to use then make + * sure it is disabled. + */ + event->hw.idx = idx; + armpmu->disable(hwc, idx); + cpuc->events[idx] = event; + set_bit(idx, cpuc->active_mask); + + /* Set the period for the event. */ + armpmu_event_set_period(event, hwc, idx); + + /* Enable the event. */ + armpmu->enable(hwc, idx); + + /* Propagate our changes to the userspace mapping. */ + perf_event_update_userpage(event); + +out: + return err; +} + +static struct pmu pmu = { + .enable = armpmu_enable, + .disable = armpmu_disable, + .unthrottle = armpmu_unthrottle, + .read = armpmu_read, +}; + +static int +validate_event(struct cpu_hw_events *cpuc, + struct perf_event *event) +{ + struct hw_perf_event fake_event = event->hw; + + if (event->pmu && event->pmu != &pmu) + return 0; + + return armpmu->get_event_idx(cpuc, &fake_event) >= 0; +} + +static int +validate_group(struct perf_event *event) +{ + struct perf_event *sibling, *leader = event->group_leader; + struct cpu_hw_events fake_pmu; + + memset(&fake_pmu, 0, sizeof(fake_pmu)); + + if (!validate_event(&fake_pmu, leader)) + return -ENOSPC; + + list_for_each_entry(sibling, &leader->sibling_list, group_entry) { + if (!validate_event(&fake_pmu, sibling)) + return -ENOSPC; + } + + if (!validate_event(&fake_pmu, event)) + return -ENOSPC; + + return 0; +} + +static int +armpmu_reserve_hardware(void) +{ + int i; + int err; + + pmu_irqs = reserve_pmu(); + if (IS_ERR(pmu_irqs)) { + pr_warning("unable to reserve pmu\n"); + return PTR_ERR(pmu_irqs); + } + + init_pmu(); + + if (pmu_irqs->num_irqs < 1) { + pr_err("no irqs for PMUs defined\n"); + return -ENODEV; + } + + for (i = 0; i < pmu_irqs->num_irqs; ++i) { + err = request_irq(pmu_irqs->irqs[i], armpmu->handle_irq, + IRQF_DISABLED, "armpmu", NULL); + if (err) { + pr_warning("unable to request IRQ%d for ARM " + "perf counters\n", pmu_irqs->irqs[i]); + break; + } + } + + if (err) { + for (i = i - 1; i >= 0; --i) + free_irq(pmu_irqs->irqs[i], NULL); + release_pmu(pmu_irqs); + pmu_irqs = NULL; + } + + return err; +} + +static void +armpmu_release_hardware(void) +{ + int i; + + for (i = pmu_irqs->num_irqs - 1; i >= 0; --i) + free_irq(pmu_irqs->irqs[i], NULL); + armpmu->stop(); + + release_pmu(pmu_irqs); + pmu_irqs = NULL; +} + +static atomic_t active_events = ATOMIC_INIT(0); +static DEFINE_MUTEX(pmu_reserve_mutex); + +static void +hw_perf_event_destroy(struct perf_event *event) +{ + if (atomic_dec_and_mutex_lock(&active_events, &pmu_reserve_mutex)) { + armpmu_release_hardware(); + mutex_unlock(&pmu_reserve_mutex); + } +} + +static int +__hw_perf_event_init(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int mapping, err; + + /* Decode the generic type into an ARM event identifier. */ + if (PERF_TYPE_HARDWARE == event->attr.type) { + mapping = armpmu->event_map(event->attr.config); + } else if (PERF_TYPE_HW_CACHE == event->attr.type) { + mapping = armpmu_map_cache_event(event->attr.config); + } else if (PERF_TYPE_RAW == event->attr.type) { + mapping = armpmu->raw_event(event->attr.config); + } else { + pr_debug("event type %x not supported\n", event->attr.type); + return -EOPNOTSUPP; + } + + if (mapping < 0) { + pr_debug("event %x:%llx not supported\n", event->attr.type, + event->attr.config); + return mapping; + } + + /* + * Check whether we need to exclude the counter from certain modes. + * The ARM performance counters are on all of the time so if someone + * has asked us for some excludes then we have to fail. + */ + if (event->attr.exclude_kernel || event->attr.exclude_user || + event->attr.exclude_hv || event->attr.exclude_idle) { + pr_debug("ARM performance counters do not support " + "mode exclusion\n"); + return -EPERM; + } + + /* + * We don't assign an index until we actually place the event onto + * hardware. Use -1 to signify that we haven't decided where to put it + * yet. For SMP systems, each core has it's own PMU so we can't do any + * clever allocation or constraints checking at this point. + */ + hwc->idx = -1; + + /* + * Store the event encoding into the config_base field. config and + * event_base are unused as the only 2 things we need to know are + * the event mapping and the counter to use. The counter to use is + * also the indx and the config_base is the event type. + */ + hwc->config_base = (unsigned long)mapping; + hwc->config = 0; + hwc->event_base = 0; + + if (!hwc->sample_period) { + hwc->sample_period = armpmu->max_period; + hwc->last_period = hwc->sample_period; + atomic64_set(&hwc->period_left, hwc->sample_period); + } + + err = 0; + if (event->group_leader != event) { + err = validate_group(event); + if (err) + return -EINVAL; + } + + return err; +} + +const struct pmu * +hw_perf_event_init(struct perf_event *event) +{ + int err = 0; + + if (!armpmu) + return ERR_PTR(-ENODEV); + + event->destroy = hw_perf_event_destroy; + + if (!atomic_inc_not_zero(&active_events)) { + if (atomic_read(&active_events) > perf_max_events) { + atomic_dec(&active_events); + return ERR_PTR(-ENOSPC); + } + + mutex_lock(&pmu_reserve_mutex); + if (atomic_read(&active_events) == 0) { + err = armpmu_reserve_hardware(); + } + + if (!err) + atomic_inc(&active_events); + mutex_unlock(&pmu_reserve_mutex); + } + + if (err) + return ERR_PTR(err); + + err = __hw_perf_event_init(event); + if (err) + hw_perf_event_destroy(event); + + return err ? ERR_PTR(err) : &pmu; +} + +void +hw_perf_enable(void) +{ + /* Enable all of the perf events on hardware. */ + int idx; + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + + if (!armpmu) + return; + + for (idx = 0; idx <= armpmu->num_events; ++idx) { + struct perf_event *event = cpuc->events[idx]; + + if (!event) + continue; + + armpmu->enable(&event->hw, idx); + } + + armpmu->start(); +} + +void +hw_perf_disable(void) +{ + if (armpmu) + armpmu->stop(); +} + +/* + * ARMv6 Performance counter handling code. + * + * ARMv6 has 2 configurable performance counters and a single cycle counter. + * They all share a single reset bit but can be written to zero so we can use + * that for a reset. + * + * The counters can't be individually enabled or disabled so when we remove + * one event and replace it with another we could get spurious counts from the + * wrong event. However, we can take advantage of the fact that the + * performance counters can export events to the event bus, and the event bus + * itself can be monitored. This requires that we *don't* export the events to + * the event bus. The procedure for disabling a configurable counter is: + * - change the counter to count the ETMEXTOUT[0] signal (0x20). This + * effectively stops the counter from counting. + * - disable the counter's interrupt generation (each counter has it's + * own interrupt enable bit). + * Once stopped, the counter value can be written as 0 to reset. + * + * To enable a counter: + * - enable the counter's interrupt generation. + * - set the new event type. + * + * Note: the dedicated cycle counter only counts cycles and can't be + * enabled/disabled independently of the others. When we want to disable the + * cycle counter, we have to just disable the interrupt reporting and start + * ignoring that counter. When re-enabling, we have to reset the value and + * enable the interrupt. + */ + +enum armv6_perf_types { + ARMV6_PERFCTR_ICACHE_MISS = 0x0, + ARMV6_PERFCTR_IBUF_STALL = 0x1, + ARMV6_PERFCTR_DDEP_STALL = 0x2, + ARMV6_PERFCTR_ITLB_MISS = 0x3, + ARMV6_PERFCTR_DTLB_MISS = 0x4, + ARMV6_PERFCTR_BR_EXEC = 0x5, + ARMV6_PERFCTR_BR_MISPREDICT = 0x6, + ARMV6_PERFCTR_INSTR_EXEC = 0x7, + ARMV6_PERFCTR_DCACHE_HIT = 0x9, + ARMV6_PERFCTR_DCACHE_ACCESS = 0xA, + ARMV6_PERFCTR_DCACHE_MISS = 0xB, + ARMV6_PERFCTR_DCACHE_WBACK = 0xC, + ARMV6_PERFCTR_SW_PC_CHANGE = 0xD, + ARMV6_PERFCTR_MAIN_TLB_MISS = 0xF, + ARMV6_PERFCTR_EXPL_D_ACCESS = 0x10, + ARMV6_PERFCTR_LSU_FULL_STALL = 0x11, + ARMV6_PERFCTR_WBUF_DRAINED = 0x12, + ARMV6_PERFCTR_CPU_CYCLES = 0xFF, + ARMV6_PERFCTR_NOP = 0x20, +}; + +enum armv6_counters { + ARMV6_CYCLE_COUNTER = 1, + ARMV6_COUNTER0, + ARMV6_COUNTER1, +}; + +/* + * The hardware events that we support. We do support cache operations but + * we have harvard caches and no way to combine instruction and data + * accesses/misses in hardware. + */ +static const unsigned armv6_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV6_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6_PERFCTR_INSTR_EXEC, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6_PERFCTR_BR_EXEC, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6_PERFCTR_BR_MISPREDICT, + [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, +}; + +static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + /* + * The performance counters don't differentiate between read + * and write accesses/misses so this isn't strictly correct, + * but it's the best we can do. Writes and reads get + * combined. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + /* + * The ARM performance counters can count micro DTLB misses, + * micro ITLB misses and main TLB misses. There isn't an event + * for TLB misses, so use the micro misses here and if users + * want the main TLB misses they can use a raw counter. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +enum armv6mpcore_perf_types { + ARMV6MPCORE_PERFCTR_ICACHE_MISS = 0x0, + ARMV6MPCORE_PERFCTR_IBUF_STALL = 0x1, + ARMV6MPCORE_PERFCTR_DDEP_STALL = 0x2, + ARMV6MPCORE_PERFCTR_ITLB_MISS = 0x3, + ARMV6MPCORE_PERFCTR_DTLB_MISS = 0x4, + ARMV6MPCORE_PERFCTR_BR_EXEC = 0x5, + ARMV6MPCORE_PERFCTR_BR_NOTPREDICT = 0x6, + ARMV6MPCORE_PERFCTR_BR_MISPREDICT = 0x7, + ARMV6MPCORE_PERFCTR_INSTR_EXEC = 0x8, + ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS = 0xA, + ARMV6MPCORE_PERFCTR_DCACHE_RDMISS = 0xB, + ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS = 0xC, + ARMV6MPCORE_PERFCTR_DCACHE_WRMISS = 0xD, + ARMV6MPCORE_PERFCTR_DCACHE_EVICTION = 0xE, + ARMV6MPCORE_PERFCTR_SW_PC_CHANGE = 0xF, + ARMV6MPCORE_PERFCTR_MAIN_TLB_MISS = 0x10, + ARMV6MPCORE_PERFCTR_EXPL_MEM_ACCESS = 0x11, + ARMV6MPCORE_PERFCTR_LSU_FULL_STALL = 0x12, + ARMV6MPCORE_PERFCTR_WBUF_DRAINED = 0x13, + ARMV6MPCORE_PERFCTR_CPU_CYCLES = 0xFF, +}; + +/* + * The hardware events that we support. We do support cache operations but + * we have harvard caches and no way to combine instruction and data + * accesses/misses in hardware. + */ +static const unsigned armv6mpcore_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV6MPCORE_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_INSTR_EXEC, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_BR_EXEC, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6MPCORE_PERFCTR_BR_MISPREDICT, + [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, +}; + +static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = + ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS, + [C(RESULT_MISS)] = + ARMV6MPCORE_PERFCTR_DCACHE_RDMISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = + ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS, + [C(RESULT_MISS)] = + ARMV6MPCORE_PERFCTR_DCACHE_WRMISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + /* + * The ARM performance counters can count micro DTLB misses, + * micro ITLB misses and main TLB misses. There isn't an event + * for TLB misses, so use the micro misses here and if users + * want the main TLB misses they can use a raw counter. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +static inline unsigned long +armv6_pmcr_read(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r"(val)); + return val; +} + +static inline void +armv6_pmcr_write(unsigned long val) +{ + asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r"(val)); +} + +#define ARMV6_PMCR_ENABLE (1 << 0) +#define ARMV6_PMCR_CTR01_RESET (1 << 1) +#define ARMV6_PMCR_CCOUNT_RESET (1 << 2) +#define ARMV6_PMCR_CCOUNT_DIV (1 << 3) +#define ARMV6_PMCR_COUNT0_IEN (1 << 4) +#define ARMV6_PMCR_COUNT1_IEN (1 << 5) +#define ARMV6_PMCR_CCOUNT_IEN (1 << 6) +#define ARMV6_PMCR_COUNT0_OVERFLOW (1 << 8) +#define ARMV6_PMCR_COUNT1_OVERFLOW (1 << 9) +#define ARMV6_PMCR_CCOUNT_OVERFLOW (1 << 10) +#define ARMV6_PMCR_EVT_COUNT0_SHIFT 20 +#define ARMV6_PMCR_EVT_COUNT0_MASK (0xFF << ARMV6_PMCR_EVT_COUNT0_SHIFT) +#define ARMV6_PMCR_EVT_COUNT1_SHIFT 12 +#define ARMV6_PMCR_EVT_COUNT1_MASK (0xFF << ARMV6_PMCR_EVT_COUNT1_SHIFT) + +#define ARMV6_PMCR_OVERFLOWED_MASK \ + (ARMV6_PMCR_COUNT0_OVERFLOW | ARMV6_PMCR_COUNT1_OVERFLOW | \ + ARMV6_PMCR_CCOUNT_OVERFLOW) + +static inline int +armv6_pmcr_has_overflowed(unsigned long pmcr) +{ + return (pmcr & ARMV6_PMCR_OVERFLOWED_MASK); +} + +static inline int +armv6_pmcr_counter_has_overflowed(unsigned long pmcr, + enum armv6_counters counter) +{ + int ret = 0; + + if (ARMV6_CYCLE_COUNTER == counter) + ret = pmcr & ARMV6_PMCR_CCOUNT_OVERFLOW; + else if (ARMV6_COUNTER0 == counter) + ret = pmcr & ARMV6_PMCR_COUNT0_OVERFLOW; + else if (ARMV6_COUNTER1 == counter) + ret = pmcr & ARMV6_PMCR_COUNT1_OVERFLOW; + else + WARN_ONCE(1, "invalid counter number (%d)\n", counter); + + return ret; +} + +static inline u32 +armv6pmu_read_counter(int counter) +{ + unsigned long value = 0; + + if (ARMV6_CYCLE_COUNTER == counter) + asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(value)); + else if (ARMV6_COUNTER0 == counter) + asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r"(value)); + else if (ARMV6_COUNTER1 == counter) + asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r"(value)); + else + WARN_ONCE(1, "invalid counter number (%d)\n", counter); + + return value; +} + +static inline void +armv6pmu_write_counter(int counter, + u32 value) +{ + if (ARMV6_CYCLE_COUNTER == counter) + asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r"(value)); + else if (ARMV6_COUNTER0 == counter) + asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r"(value)); + else if (ARMV6_COUNTER1 == counter) + asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r"(value)); + else + WARN_ONCE(1, "invalid counter number (%d)\n", counter); +} + +void +armv6pmu_enable_event(struct hw_perf_event *hwc, + int idx) +{ + unsigned long val, mask, evt, flags; + + if (ARMV6_CYCLE_COUNTER == idx) { + mask = 0; + evt = ARMV6_PMCR_CCOUNT_IEN; + } else if (ARMV6_COUNTER0 == idx) { + mask = ARMV6_PMCR_EVT_COUNT0_MASK; + evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT0_SHIFT) | + ARMV6_PMCR_COUNT0_IEN; + } else if (ARMV6_COUNTER1 == idx) { + mask = ARMV6_PMCR_EVT_COUNT1_MASK; + evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT1_SHIFT) | + ARMV6_PMCR_COUNT1_IEN; + } else { + WARN_ONCE(1, "invalid counter number (%d)\n", idx); + return; + } + + /* + * Mask out the current event and set the counter to count the event + * that we're interested in. + */ + spin_lock_irqsave(&pmu_lock, flags); + val = armv6_pmcr_read(); + val &= ~mask; + val |= evt; + armv6_pmcr_write(val); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static irqreturn_t +armv6pmu_handle_irq(int irq_num, + void *dev) +{ + unsigned long pmcr = armv6_pmcr_read(); + struct perf_sample_data data; + struct cpu_hw_events *cpuc; + struct pt_regs *regs; + int idx; + + if (!armv6_pmcr_has_overflowed(pmcr)) + return IRQ_NONE; + + regs = get_irq_regs(); + + /* + * The interrupts are cleared by writing the overflow flags back to + * the control register. All of the other bits don't have any effect + * if they are rewritten, so write the whole value back. + */ + armv6_pmcr_write(pmcr); + + data.addr = 0; + + cpuc = &__get_cpu_var(cpu_hw_events); + for (idx = 0; idx <= armpmu->num_events; ++idx) { + struct perf_event *event = cpuc->events[idx]; + struct hw_perf_event *hwc; + + if (!test_bit(idx, cpuc->active_mask)) + continue; + + /* + * We have a single interrupt for all counters. Check that + * each counter has overflowed before we process it. + */ + if (!armv6_pmcr_counter_has_overflowed(pmcr, idx)) + continue; + + hwc = &event->hw; + armpmu_event_update(event, hwc, idx); + data.period = event->hw.last_period; + if (!armpmu_event_set_period(event, hwc, idx)) + continue; + + if (perf_event_overflow(event, 0, &data, regs)) + armpmu->disable(hwc, idx); + } + + /* + * Handle the pending perf events. + * + * Note: this call *must* be run with interrupts enabled. For + * platforms that can have the PMU interrupts raised as a PMI, this + * will not work. + */ + perf_event_do_pending(); + + return IRQ_HANDLED; +} + +static void +armv6pmu_start(void) +{ + unsigned long flags, val; + + spin_lock_irqsave(&pmu_lock, flags); + val = armv6_pmcr_read(); + val |= ARMV6_PMCR_ENABLE; + armv6_pmcr_write(val); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +void +armv6pmu_stop(void) +{ + unsigned long flags, val; + + spin_lock_irqsave(&pmu_lock, flags); + val = armv6_pmcr_read(); + val &= ~ARMV6_PMCR_ENABLE; + armv6_pmcr_write(val); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static inline int +armv6pmu_event_map(int config) +{ + int mapping = armv6_perf_map[config]; + if (HW_OP_UNSUPPORTED == mapping) + mapping = -EOPNOTSUPP; + return mapping; +} + +static inline int +armv6mpcore_pmu_event_map(int config) +{ + int mapping = armv6mpcore_perf_map[config]; + if (HW_OP_UNSUPPORTED == mapping) + mapping = -EOPNOTSUPP; + return mapping; +} + +static u64 +armv6pmu_raw_event(u64 config) +{ + return config & 0xff; +} + +static int +armv6pmu_get_event_idx(struct cpu_hw_events *cpuc, + struct hw_perf_event *event) +{ + /* Always place a cycle counter into the cycle counter. */ + if (ARMV6_PERFCTR_CPU_CYCLES == event->config_base) { + if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask)) + return -EAGAIN; + + return ARMV6_CYCLE_COUNTER; + } else { + /* + * For anything other than a cycle counter, try and use + * counter0 and counter1. + */ + if (!test_and_set_bit(ARMV6_COUNTER1, cpuc->used_mask)) { + return ARMV6_COUNTER1; + } + + if (!test_and_set_bit(ARMV6_COUNTER0, cpuc->used_mask)) { + return ARMV6_COUNTER0; + } + + /* The counters are all in use. */ + return -EAGAIN; + } +} + +static void +armv6pmu_disable_event(struct hw_perf_event *hwc, + int idx) +{ + unsigned long val, mask, evt, flags; + + if (ARMV6_CYCLE_COUNTER == idx) { + mask = ARMV6_PMCR_CCOUNT_IEN; + evt = 0; + } else if (ARMV6_COUNTER0 == idx) { + mask = ARMV6_PMCR_COUNT0_IEN | ARMV6_PMCR_EVT_COUNT0_MASK; + evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT0_SHIFT; + } else if (ARMV6_COUNTER1 == idx) { + mask = ARMV6_PMCR_COUNT1_IEN | ARMV6_PMCR_EVT_COUNT1_MASK; + evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT1_SHIFT; + } else { + WARN_ONCE(1, "invalid counter number (%d)\n", idx); + return; + } + + /* + * Mask out the current event and set the counter to count the number + * of ETM bus signal assertion cycles. The external reporting should + * be disabled and so this should never increment. + */ + spin_lock_irqsave(&pmu_lock, flags); + val = armv6_pmcr_read(); + val &= ~mask; + val |= evt; + armv6_pmcr_write(val); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static void +armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc, + int idx) +{ + unsigned long val, mask, flags, evt = 0; + + if (ARMV6_CYCLE_COUNTER == idx) { + mask = ARMV6_PMCR_CCOUNT_IEN; + } else if (ARMV6_COUNTER0 == idx) { + mask = ARMV6_PMCR_COUNT0_IEN; + } else if (ARMV6_COUNTER1 == idx) { + mask = ARMV6_PMCR_COUNT1_IEN; + } else { + WARN_ONCE(1, "invalid counter number (%d)\n", idx); + return; + } + + /* + * Unlike UP ARMv6, we don't have a way of stopping the counters. We + * simply disable the interrupt reporting. + */ + spin_lock_irqsave(&pmu_lock, flags); + val = armv6_pmcr_read(); + val &= ~mask; + val |= evt; + armv6_pmcr_write(val); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static const struct arm_pmu armv6pmu = { + .name = "v6", + .handle_irq = armv6pmu_handle_irq, + .enable = armv6pmu_enable_event, + .disable = armv6pmu_disable_event, + .event_map = armv6pmu_event_map, + .raw_event = armv6pmu_raw_event, + .read_counter = armv6pmu_read_counter, + .write_counter = armv6pmu_write_counter, + .get_event_idx = armv6pmu_get_event_idx, + .start = armv6pmu_start, + .stop = armv6pmu_stop, + .num_events = 3, + .max_period = (1LLU << 32) - 1, +}; + +/* + * ARMv6mpcore is almost identical to single core ARMv6 with the exception + * that some of the events have different enumerations and that there is no + * *hack* to stop the programmable counters. To stop the counters we simply + * disable the interrupt reporting and update the event. When unthrottling we + * reset the period and enable the interrupt reporting. + */ +static const struct arm_pmu armv6mpcore_pmu = { + .name = "v6mpcore", + .handle_irq = armv6pmu_handle_irq, + .enable = armv6pmu_enable_event, + .disable = armv6mpcore_pmu_disable_event, + .event_map = armv6mpcore_pmu_event_map, + .raw_event = armv6pmu_raw_event, + .read_counter = armv6pmu_read_counter, + .write_counter = armv6pmu_write_counter, + .get_event_idx = armv6pmu_get_event_idx, + .start = armv6pmu_start, + .stop = armv6pmu_stop, + .num_events = 3, + .max_period = (1LLU << 32) - 1, +}; + +static int __init +init_hw_perf_events(void) +{ + unsigned long cpuid = read_cpuid_id(); + unsigned long implementor = (cpuid & 0xFF000000) >> 24; + unsigned long part_number = (cpuid & 0xFFF0); + + /* We only support ARM CPUs implemented by ARM at the moment. */ + if (0x41 == implementor) { + switch (part_number) { + case 0xB360: /* ARM1136 */ + case 0xB560: /* ARM1156 */ + case 0xB760: /* ARM1176 */ + armpmu = &armv6pmu; + memcpy(armpmu_perf_cache_map, armv6_perf_cache_map, + sizeof(armv6_perf_cache_map)); + perf_max_events = armv6pmu.num_events; + break; + case 0xB020: /* ARM11mpcore */ + armpmu = &armv6mpcore_pmu; + memcpy(armpmu_perf_cache_map, + armv6mpcore_perf_cache_map, + sizeof(armv6mpcore_perf_cache_map)); + perf_max_events = armv6mpcore_pmu.num_events; + break; + default: + pr_info("no hardware support available\n"); + perf_max_events = -1; + } + } + + if (armpmu) + pr_info("enabled with %s PMU driver\n", + armpmu->name); + + return 0; +} +arch_initcall(init_hw_perf_events); + +/* + * Callchain handling code. + */ +static inline void +callchain_store(struct perf_callchain_entry *entry, + u64 ip) +{ + if (entry->nr < PERF_MAX_STACK_DEPTH) + entry->ip[entry->nr++] = ip; +} + +/* + * The registers we're interested in are at the end of the variable + * length saved register structure. The fp points at the end of this + * structure so the address of this struct is: + * (struct frame_tail *)(xxx->fp)-1 + * + * This code has been adapted from the ARM OProfile support. + */ +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +/* + * Get the return address for a single stackframe and return a pointer to the + * next frame tail. + */ +static struct frame_tail * +user_backtrace(struct frame_tail *tail, + struct perf_callchain_entry *entry) +{ + struct frame_tail buftail; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) + return NULL; + if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail))) + return NULL; + + callchain_store(entry, buftail.lr); + + /* + * Frame pointers should strictly progress back up the stack + * (towards higher addresses). + */ + if (tail >= buftail.fp) + return NULL; + + return buftail.fp - 1; +} + +static void +perf_callchain_user(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + struct frame_tail *tail; + + callchain_store(entry, PERF_CONTEXT_USER); + + if (!user_mode(regs)) + regs = task_pt_regs(current); + + tail = (struct frame_tail *)regs->ARM_fp - 1; + + while (tail && !((unsigned long)tail & 0x3)) + tail = user_backtrace(tail, entry); +} + +/* + * Gets called by walk_stackframe() for every stackframe. This will be called + * whist unwinding the stackframe and is like a subroutine return so we use + * the PC. + */ +static int +callchain_trace(struct stackframe *fr, + void *data) +{ + struct perf_callchain_entry *entry = data; + callchain_store(entry, fr->pc); + return 0; +} + +static void +perf_callchain_kernel(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + struct stackframe fr; + + callchain_store(entry, PERF_CONTEXT_KERNEL); + fr.fp = regs->ARM_fp; + fr.sp = regs->ARM_sp; + fr.lr = regs->ARM_lr; + fr.pc = regs->ARM_pc; + walk_stackframe(&fr, callchain_trace, entry); +} + +static void +perf_do_callchain(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + int is_user; + + if (!regs) + return; + + is_user = user_mode(regs); + + if (!current || !current->pid) + return; + + if (is_user && current->state != TASK_RUNNING) + return; + + if (!is_user) + perf_callchain_kernel(regs, entry); + + if (current->mm) + perf_callchain_user(regs, entry); +} + +static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); + +struct perf_callchain_entry * +perf_callchain(struct pt_regs *regs) +{ + struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry); + + entry->nr = 0; + perf_do_callchain(regs, entry); + return entry; +} -- GitLab From 796d12959ad374cae8eb77faaf4243455a305433 Mon Sep 17 00:00:00 2001 From: Jean PIHET Date: Tue, 26 Jan 2010 18:51:05 +0100 Subject: [PATCH 1939/3892] ARM: 5903/1: arm/perfevents: add support for ARMv7 Adds the Performance Events support for ARMv7 processor, using the PMNC unit in HW. Supports the following: - Cortex-A8 and Cortex-A9 processors, - dynamic detection of the number of available counters, based on the PMCR value, - runtime detection of the CPU arch (v6 or v7) and model (Cortex-A8 or Cortex-A9) Tested on OMAP3 (Cortex-A8) only. Signed-off-by: Jean Pihet Signed-off-by: Russell King --- arch/arm/Kconfig | 2 +- arch/arm/kernel/perf_event.c | 936 ++++++++++++++++++++++++++++++++++- 2 files changed, 933 insertions(+), 5 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9fb91ce106bc..1d10b9064567 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1176,7 +1176,7 @@ config HIGHPTE config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" - depends on PERF_EVENTS && CPU_HAS_PMU && CPU_V6 + depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7) default y help Enable hardware performance counter support for perf events. If diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 7b1022b9aa52..c54ceb3d1f97 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -5,6 +5,9 @@ * * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles * + * ARMv7 support: Jean Pihet + * 2010 (c) MontaVista Software, LLC. + * * This code is based on the sparc64 perf event code, which is in turn based * on the x86 code. Callchain code is based on the ARM OProfile backtrace * code. @@ -35,8 +38,12 @@ DEFINE_SPINLOCK(pmu_lock); * ARMv6 supports a maximum of 3 events, starting from index 1. If we add * another platform that supports more, we need to increase this to be the * largest of all platforms. + * + * ARMv7 supports up to 32 events: + * cycle counter CCNT + 31 events counters CNT0..30. + * Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters. */ -#define ARMPMU_MAX_HWEVENTS 4 +#define ARMPMU_MAX_HWEVENTS 33 /* The events for a given CPU. */ struct cpu_hw_events { @@ -61,7 +68,7 @@ struct cpu_hw_events { DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); struct arm_pmu { - const char *name; + char *name; irqreturn_t (*handle_irq)(int irq_num, void *dev); void (*enable)(struct hw_perf_event *evt, int idx); void (*disable)(struct hw_perf_event *evt, int idx); @@ -1174,6 +1181,903 @@ static const struct arm_pmu armv6mpcore_pmu = { .max_period = (1LLU << 32) - 1, }; +/* + * ARMv7 Cortex-A8 and Cortex-A9 Performance Events handling code. + * + * Copied from ARMv6 code, with the low level code inspired + * by the ARMv7 Oprofile code. + * + * Cortex-A8 has up to 4 configurable performance counters and + * a single cycle counter. + * Cortex-A9 has up to 31 configurable performance counters and + * a single cycle counter. + * + * All counters can be enabled/disabled and IRQ masked separately. The cycle + * counter and all 4 performance counters together can be reset separately. + */ + +#define ARMV7_PMU_CORTEX_A8_NAME "ARMv7 Cortex-A8" + +#define ARMV7_PMU_CORTEX_A9_NAME "ARMv7 Cortex-A9" + +/* Common ARMv7 event types */ +enum armv7_perf_types { + ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, + ARMV7_PERFCTR_IFETCH_MISS = 0x01, + ARMV7_PERFCTR_ITLB_MISS = 0x02, + ARMV7_PERFCTR_DCACHE_REFILL = 0x03, + ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, + ARMV7_PERFCTR_DTLB_REFILL = 0x05, + ARMV7_PERFCTR_DREAD = 0x06, + ARMV7_PERFCTR_DWRITE = 0x07, + + ARMV7_PERFCTR_EXC_TAKEN = 0x09, + ARMV7_PERFCTR_EXC_EXECUTED = 0x0A, + ARMV7_PERFCTR_CID_WRITE = 0x0B, + /* ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS. + * It counts: + * - all branch instructions, + * - instructions that explicitly write the PC, + * - exception generating instructions. + */ + ARMV7_PERFCTR_PC_WRITE = 0x0C, + ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D, + ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F, + ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, + ARMV7_PERFCTR_CLOCK_CYCLES = 0x11, + + ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12, + + ARMV7_PERFCTR_CPU_CYCLES = 0xFF +}; + +/* ARMv7 Cortex-A8 specific event types */ +enum armv7_a8_perf_types { + ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, + + ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, + + ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40, + ARMV7_PERFCTR_L2_STORE_MERGED = 0x41, + ARMV7_PERFCTR_L2_STORE_BUFF = 0x42, + ARMV7_PERFCTR_L2_ACCESS = 0x43, + ARMV7_PERFCTR_L2_CACH_MISS = 0x44, + ARMV7_PERFCTR_AXI_READ_CYCLES = 0x45, + ARMV7_PERFCTR_AXI_WRITE_CYCLES = 0x46, + ARMV7_PERFCTR_MEMORY_REPLAY = 0x47, + ARMV7_PERFCTR_UNALIGNED_ACCESS_REPLAY = 0x48, + ARMV7_PERFCTR_L1_DATA_MISS = 0x49, + ARMV7_PERFCTR_L1_INST_MISS = 0x4A, + ARMV7_PERFCTR_L1_DATA_COLORING = 0x4B, + ARMV7_PERFCTR_L1_NEON_DATA = 0x4C, + ARMV7_PERFCTR_L1_NEON_CACH_DATA = 0x4D, + ARMV7_PERFCTR_L2_NEON = 0x4E, + ARMV7_PERFCTR_L2_NEON_HIT = 0x4F, + ARMV7_PERFCTR_L1_INST = 0x50, + ARMV7_PERFCTR_PC_RETURN_MIS_PRED = 0x51, + ARMV7_PERFCTR_PC_BRANCH_FAILED = 0x52, + ARMV7_PERFCTR_PC_BRANCH_TAKEN = 0x53, + ARMV7_PERFCTR_PC_BRANCH_EXECUTED = 0x54, + ARMV7_PERFCTR_OP_EXECUTED = 0x55, + ARMV7_PERFCTR_CYCLES_INST_STALL = 0x56, + ARMV7_PERFCTR_CYCLES_INST = 0x57, + ARMV7_PERFCTR_CYCLES_NEON_DATA_STALL = 0x58, + ARMV7_PERFCTR_CYCLES_NEON_INST_STALL = 0x59, + ARMV7_PERFCTR_NEON_CYCLES = 0x5A, + + ARMV7_PERFCTR_PMU0_EVENTS = 0x70, + ARMV7_PERFCTR_PMU1_EVENTS = 0x71, + ARMV7_PERFCTR_PMU_EVENTS = 0x72, +}; + +/* ARMv7 Cortex-A9 specific event types */ +enum armv7_a9_perf_types { + ARMV7_PERFCTR_JAVA_HW_BYTECODE_EXEC = 0x40, + ARMV7_PERFCTR_JAVA_SW_BYTECODE_EXEC = 0x41, + ARMV7_PERFCTR_JAZELLE_BRANCH_EXEC = 0x42, + + ARMV7_PERFCTR_COHERENT_LINE_MISS = 0x50, + ARMV7_PERFCTR_COHERENT_LINE_HIT = 0x51, + + ARMV7_PERFCTR_ICACHE_DEP_STALL_CYCLES = 0x60, + ARMV7_PERFCTR_DCACHE_DEP_STALL_CYCLES = 0x61, + ARMV7_PERFCTR_TLB_MISS_DEP_STALL_CYCLES = 0x62, + ARMV7_PERFCTR_STREX_EXECUTED_PASSED = 0x63, + ARMV7_PERFCTR_STREX_EXECUTED_FAILED = 0x64, + ARMV7_PERFCTR_DATA_EVICTION = 0x65, + ARMV7_PERFCTR_ISSUE_STAGE_NO_INST = 0x66, + ARMV7_PERFCTR_ISSUE_STAGE_EMPTY = 0x67, + ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE = 0x68, + + ARMV7_PERFCTR_PREDICTABLE_FUNCT_RETURNS = 0x6E, + + ARMV7_PERFCTR_MAIN_UNIT_EXECUTED_INST = 0x70, + ARMV7_PERFCTR_SECOND_UNIT_EXECUTED_INST = 0x71, + ARMV7_PERFCTR_LD_ST_UNIT_EXECUTED_INST = 0x72, + ARMV7_PERFCTR_FP_EXECUTED_INST = 0x73, + ARMV7_PERFCTR_NEON_EXECUTED_INST = 0x74, + + ARMV7_PERFCTR_PLD_FULL_DEP_STALL_CYCLES = 0x80, + ARMV7_PERFCTR_DATA_WR_DEP_STALL_CYCLES = 0x81, + ARMV7_PERFCTR_ITLB_MISS_DEP_STALL_CYCLES = 0x82, + ARMV7_PERFCTR_DTLB_MISS_DEP_STALL_CYCLES = 0x83, + ARMV7_PERFCTR_MICRO_ITLB_MISS_DEP_STALL_CYCLES = 0x84, + ARMV7_PERFCTR_MICRO_DTLB_MISS_DEP_STALL_CYCLES = 0x85, + ARMV7_PERFCTR_DMB_DEP_STALL_CYCLES = 0x86, + + ARMV7_PERFCTR_INTGR_CLK_ENABLED_CYCLES = 0x8A, + ARMV7_PERFCTR_DATA_ENGINE_CLK_EN_CYCLES = 0x8B, + + ARMV7_PERFCTR_ISB_INST = 0x90, + ARMV7_PERFCTR_DSB_INST = 0x91, + ARMV7_PERFCTR_DMB_INST = 0x92, + ARMV7_PERFCTR_EXT_INTERRUPTS = 0x93, + + ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_COMPLETED = 0xA0, + ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_SKIPPED = 0xA1, + ARMV7_PERFCTR_PLE_FIFO_FLUSH = 0xA2, + ARMV7_PERFCTR_PLE_RQST_COMPLETED = 0xA3, + ARMV7_PERFCTR_PLE_FIFO_OVERFLOW = 0xA4, + ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5 +}; + +/* + * Cortex-A8 HW events mapping + * + * The hardware events that we support. We do support cache operations but + * we have harvard caches and no way to combine instruction and data + * accesses/misses in hardware. + */ +static const unsigned armv7_a8_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, +}; + +static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + /* + * The performance counters don't differentiate between read + * and write accesses/misses so this isn't strictly correct, + * but it's the best we can do. Writes and reads get + * combined. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + /* + * Only ITLB misses and DTLB refills are supported. + * If users want the DTLB refills misses a raw counter + * must be used. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +/* + * Cortex-A9 HW events mapping + */ +static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = + ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE, + [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT, + [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, +}; + +static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + /* + * The performance counters don't differentiate between read + * and write accesses/misses so this isn't strictly correct, + * but it's the best we can do. Writes and reads get + * combined. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + /* + * Only ITLB misses and DTLB refills are supported. + * If users want the DTLB refills misses a raw counter + * must be used. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +/* + * Perf Events counters + */ +enum armv7_counters { + ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */ + ARMV7_COUNTER0 = 2, /* First event counter */ +}; + +/* + * The cycle counter is ARMV7_CYCLE_COUNTER. + * The first event counter is ARMV7_COUNTER0. + * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1). + */ +#define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1) + +/* + * ARMv7 low level PMNC access + */ + +/* + * Per-CPU PMNC: config reg + */ +#define ARMV7_PMNC_E (1 << 0) /* Enable all counters */ +#define ARMV7_PMNC_P (1 << 1) /* Reset all counters */ +#define ARMV7_PMNC_C (1 << 2) /* Cycle counter reset */ +#define ARMV7_PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */ +#define ARMV7_PMNC_X (1 << 4) /* Export to ETM */ +#define ARMV7_PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ +#define ARMV7_PMNC_N_SHIFT 11 /* Number of counters supported */ +#define ARMV7_PMNC_N_MASK 0x1f +#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */ + +/* + * Available counters + */ +#define ARMV7_CNT0 0 /* First event counter */ +#define ARMV7_CCNT 31 /* Cycle counter */ + +/* Perf Event to low level counters mapping */ +#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0) + +/* + * CNTENS: counters enable reg + */ +#define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) +#define ARMV7_CNTENS_C (1 << ARMV7_CCNT) + +/* + * CNTENC: counters disable reg + */ +#define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) +#define ARMV7_CNTENC_C (1 << ARMV7_CCNT) + +/* + * INTENS: counters overflow interrupt enable reg + */ +#define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) +#define ARMV7_INTENS_C (1 << ARMV7_CCNT) + +/* + * INTENC: counters overflow interrupt disable reg + */ +#define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) +#define ARMV7_INTENC_C (1 << ARMV7_CCNT) + +/* + * EVTSEL: Event selection reg + */ +#define ARMV7_EVTSEL_MASK 0x7f /* Mask for writable bits */ + +/* + * SELECT: Counter selection reg + */ +#define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */ + +/* + * FLAG: counters overflow flag status reg + */ +#define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) +#define ARMV7_FLAG_C (1 << ARMV7_CCNT) +#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */ +#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK + +static inline unsigned long armv7_pmnc_read(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + return val; +} + +static inline void armv7_pmnc_write(unsigned long val) +{ + val &= ARMV7_PMNC_MASK; + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline int armv7_pmnc_has_overflowed(unsigned long pmnc) +{ + return pmnc & ARMV7_OVERFLOWED_MASK; +} + +static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc, + enum armv7_counters counter) +{ + int ret; + + if (counter == ARMV7_CYCLE_COUNTER) + ret = pmnc & ARMV7_FLAG_C; + else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST)) + ret = pmnc & ARMV7_FLAG_P(counter); + else + pr_err("CPU%u checking wrong counter %d overflow status\n", + smp_processor_id(), counter); + + return ret; +} + +static inline int armv7_pmnc_select_counter(unsigned int idx) +{ + u32 val; + + if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) { + pr_err("CPU%u selecting wrong PMNC counter" + " %d\n", smp_processor_id(), idx); + return -1; + } + + val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK; + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); + + return idx; +} + +static inline u32 armv7pmu_read_counter(int idx) +{ + unsigned long value = 0; + + if (idx == ARMV7_CYCLE_COUNTER) + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value)); + else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { + if (armv7_pmnc_select_counter(idx) == idx) + asm volatile("mrc p15, 0, %0, c9, c13, 2" + : "=r" (value)); + } else + pr_err("CPU%u reading wrong counter %d\n", + smp_processor_id(), idx); + + return value; +} + +static inline void armv7pmu_write_counter(int idx, u32 value) +{ + if (idx == ARMV7_CYCLE_COUNTER) + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value)); + else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { + if (armv7_pmnc_select_counter(idx) == idx) + asm volatile("mcr p15, 0, %0, c9, c13, 2" + : : "r" (value)); + } else + pr_err("CPU%u writing wrong counter %d\n", + smp_processor_id(), idx); +} + +static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val) +{ + if (armv7_pmnc_select_counter(idx) == idx) { + val &= ARMV7_EVTSEL_MASK; + asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); + } +} + +static inline u32 armv7_pmnc_enable_counter(unsigned int idx) +{ + u32 val; + + if ((idx != ARMV7_CYCLE_COUNTER) && + ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { + pr_err("CPU%u enabling wrong PMNC counter" + " %d\n", smp_processor_id(), idx); + return -1; + } + + if (idx == ARMV7_CYCLE_COUNTER) + val = ARMV7_CNTENS_C; + else + val = ARMV7_CNTENS_P(idx); + + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); + + return idx; +} + +static inline u32 armv7_pmnc_disable_counter(unsigned int idx) +{ + u32 val; + + + if ((idx != ARMV7_CYCLE_COUNTER) && + ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { + pr_err("CPU%u disabling wrong PMNC counter" + " %d\n", smp_processor_id(), idx); + return -1; + } + + if (idx == ARMV7_CYCLE_COUNTER) + val = ARMV7_CNTENC_C; + else + val = ARMV7_CNTENC_P(idx); + + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); + + return idx; +} + +static inline u32 armv7_pmnc_enable_intens(unsigned int idx) +{ + u32 val; + + if ((idx != ARMV7_CYCLE_COUNTER) && + ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { + pr_err("CPU%u enabling wrong PMNC counter" + " interrupt enable %d\n", smp_processor_id(), idx); + return -1; + } + + if (idx == ARMV7_CYCLE_COUNTER) + val = ARMV7_INTENS_C; + else + val = ARMV7_INTENS_P(idx); + + asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); + + return idx; +} + +static inline u32 armv7_pmnc_disable_intens(unsigned int idx) +{ + u32 val; + + if ((idx != ARMV7_CYCLE_COUNTER) && + ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { + pr_err("CPU%u disabling wrong PMNC counter" + " interrupt enable %d\n", smp_processor_id(), idx); + return -1; + } + + if (idx == ARMV7_CYCLE_COUNTER) + val = ARMV7_INTENC_C; + else + val = ARMV7_INTENC_P(idx); + + asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); + + return idx; +} + +static inline u32 armv7_pmnc_getreset_flags(void) +{ + u32 val; + + /* Read */ + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); + + /* Write to clear flags */ + val &= ARMV7_FLAG_MASK; + asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val)); + + return val; +} + +#ifdef DEBUG +static void armv7_pmnc_dump_regs(void) +{ + u32 val; + unsigned int cnt; + + printk(KERN_INFO "PMNC registers dump:\n"); + + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); + printk(KERN_INFO "PMNC =0x%08x\n", val); + + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val)); + printk(KERN_INFO "CNTENS=0x%08x\n", val); + + asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val)); + printk(KERN_INFO "INTENS=0x%08x\n", val); + + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); + printk(KERN_INFO "FLAGS =0x%08x\n", val); + + asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val)); + printk(KERN_INFO "SELECT=0x%08x\n", val); + + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); + printk(KERN_INFO "CCNT =0x%08x\n", val); + + for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) { + armv7_pmnc_select_counter(cnt); + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); + printk(KERN_INFO "CNT[%d] count =0x%08x\n", + cnt-ARMV7_EVENT_CNT_TO_CNTx, val); + asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val)); + printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", + cnt-ARMV7_EVENT_CNT_TO_CNTx, val); + } +} +#endif + +void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) +{ + unsigned long flags; + + /* + * Enable counter and interrupt, and set the counter to count + * the event that we're interested in. + */ + spin_lock_irqsave(&pmu_lock, flags); + + /* + * Disable counter + */ + armv7_pmnc_disable_counter(idx); + + /* + * Set event (if destined for PMNx counters) + * We don't need to set the event if it's a cycle count + */ + if (idx != ARMV7_CYCLE_COUNTER) + armv7_pmnc_write_evtsel(idx, hwc->config_base); + + /* + * Enable interrupt for this counter + */ + armv7_pmnc_enable_intens(idx); + + /* + * Enable counter + */ + armv7_pmnc_enable_counter(idx); + + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) +{ + unsigned long flags; + + /* + * Disable counter and interrupt + */ + spin_lock_irqsave(&pmu_lock, flags); + + /* + * Disable counter + */ + armv7_pmnc_disable_counter(idx); + + /* + * Disable interrupt for this counter + */ + armv7_pmnc_disable_intens(idx); + + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) +{ + unsigned long pmnc; + struct perf_sample_data data; + struct cpu_hw_events *cpuc; + struct pt_regs *regs; + int idx; + + /* + * Get and reset the IRQ flags + */ + pmnc = armv7_pmnc_getreset_flags(); + + /* + * Did an overflow occur? + */ + if (!armv7_pmnc_has_overflowed(pmnc)) + return IRQ_NONE; + + /* + * Handle the counter(s) overflow(s) + */ + regs = get_irq_regs(); + + data.addr = 0; + + cpuc = &__get_cpu_var(cpu_hw_events); + for (idx = 0; idx <= armpmu->num_events; ++idx) { + struct perf_event *event = cpuc->events[idx]; + struct hw_perf_event *hwc; + + if (!test_bit(idx, cpuc->active_mask)) + continue; + + /* + * We have a single interrupt for all counters. Check that + * each counter has overflowed before we process it. + */ + if (!armv7_pmnc_counter_has_overflowed(pmnc, idx)) + continue; + + hwc = &event->hw; + armpmu_event_update(event, hwc, idx); + data.period = event->hw.last_period; + if (!armpmu_event_set_period(event, hwc, idx)) + continue; + + if (perf_event_overflow(event, 0, &data, regs)) + armpmu->disable(hwc, idx); + } + + /* + * Handle the pending perf events. + * + * Note: this call *must* be run with interrupts enabled. For + * platforms that can have the PMU interrupts raised as a PMI, this + * will not work. + */ + perf_event_do_pending(); + + return IRQ_HANDLED; +} + +static void armv7pmu_start(void) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_lock, flags); + /* Enable all counters */ + armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static void armv7pmu_stop(void) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_lock, flags); + /* Disable all counters */ + armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E); + spin_unlock_irqrestore(&pmu_lock, flags); +} + +static inline int armv7_a8_pmu_event_map(int config) +{ + int mapping = armv7_a8_perf_map[config]; + if (HW_OP_UNSUPPORTED == mapping) + mapping = -EOPNOTSUPP; + return mapping; +} + +static inline int armv7_a9_pmu_event_map(int config) +{ + int mapping = armv7_a9_perf_map[config]; + if (HW_OP_UNSUPPORTED == mapping) + mapping = -EOPNOTSUPP; + return mapping; +} + +static u64 armv7pmu_raw_event(u64 config) +{ + return config & 0xff; +} + +static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, + struct hw_perf_event *event) +{ + int idx; + + /* Always place a cycle counter into the cycle counter. */ + if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) { + if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask)) + return -EAGAIN; + + return ARMV7_CYCLE_COUNTER; + } else { + /* + * For anything other than a cycle counter, try and use + * the events counters + */ + for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) { + if (!test_and_set_bit(idx, cpuc->used_mask)) + return idx; + } + + /* The counters are all in use. */ + return -EAGAIN; + } +} + +static struct arm_pmu armv7pmu = { + .handle_irq = armv7pmu_handle_irq, + .enable = armv7pmu_enable_event, + .disable = armv7pmu_disable_event, + .raw_event = armv7pmu_raw_event, + .read_counter = armv7pmu_read_counter, + .write_counter = armv7pmu_write_counter, + .get_event_idx = armv7pmu_get_event_idx, + .start = armv7pmu_start, + .stop = armv7pmu_stop, + .max_period = (1LLU << 32) - 1, +}; + +static u32 __init armv7_reset_read_pmnc(void) +{ + u32 nb_cnt; + + /* Initialize & Reset PMNC: C and P bits */ + armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); + + /* Read the nb of CNTx counters supported from PMNC */ + nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK; + + /* Add the CPU cycles counter and return */ + return nb_cnt + 1; +} + static int __init init_hw_perf_events(void) { @@ -1199,6 +2103,30 @@ init_hw_perf_events(void) sizeof(armv6mpcore_perf_cache_map)); perf_max_events = armv6mpcore_pmu.num_events; break; + case 0xC080: /* Cortex-A8 */ + armv7pmu.name = ARMV7_PMU_CORTEX_A8_NAME; + memcpy(armpmu_perf_cache_map, armv7_a8_perf_cache_map, + sizeof(armv7_a8_perf_cache_map)); + armv7pmu.event_map = armv7_a8_pmu_event_map; + armpmu = &armv7pmu; + + /* Reset PMNC and read the nb of CNTx counters + supported */ + armv7pmu.num_events = armv7_reset_read_pmnc(); + perf_max_events = armv7pmu.num_events; + break; + case 0xC090: /* Cortex-A9 */ + armv7pmu.name = ARMV7_PMU_CORTEX_A9_NAME; + memcpy(armpmu_perf_cache_map, armv7_a9_perf_cache_map, + sizeof(armv7_a9_perf_cache_map)); + armv7pmu.event_map = armv7_a9_pmu_event_map; + armpmu = &armv7pmu; + + /* Reset PMNC and read the nb of CNTx counters + supported */ + armv7pmu.num_events = armv7_reset_read_pmnc(); + perf_max_events = armv7pmu.num_events; + break; default: pr_info("no hardware support available\n"); perf_max_events = -1; @@ -1206,8 +2134,8 @@ init_hw_perf_events(void) } if (armpmu) - pr_info("enabled with %s PMU driver\n", - armpmu->name); + pr_info("enabled with %s PMU driver, %d counters available\n", + armpmu->name, armpmu->num_events); return 0; } -- GitLab From 4e6d488af37980d224cbf298224db6173673f362 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 1 Feb 2010 23:26:53 +0100 Subject: [PATCH 1940/3892] ARM: 5910/1: ARM: Add tmp register for addruart and loadsp Otherwise more complicated uart configuration won't be possible. We can use r1 for tmp register for both head.S and debug.S. NOTE: This patch depends on another patch to add the the tmp register into all debug-macro.S files. That can be done with: $ sed -i -e "s/addruart,rx|addruart, rx/addruart, rx, tmp/" arch/arm/*/include/*/debug-macro.S Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/boot/compressed/head.S | 20 +++++++++---------- arch/arm/kernel/debug.S | 12 +++++------ .../mach-aaec2000/include/mach/debug-macro.S | 2 +- arch/arm/mach-at91/include/mach/debug-macro.S | 2 +- .../mach-clps711x/include/mach/debug-macro.S | 2 +- .../mach-davinci/include/mach/debug-macro.S | 2 +- arch/arm/mach-dove/include/mach/debug-macro.S | 2 +- .../mach-ebsa110/include/mach/debug-macro.S | 2 +- .../mach-ep93xx/include/mach/debug-macro.S | 2 +- .../include/mach/debug-macro.S | 4 ++-- .../mach-gemini/include/mach/debug-macro.S | 2 +- .../arm/mach-h720x/include/mach/debug-macro.S | 2 +- .../include/mach/debug-macro.S | 2 +- .../mach-iop13xx/include/mach/debug-macro.S | 2 +- .../mach-iop32x/include/mach/debug-macro.S | 2 +- .../mach-iop33x/include/mach/debug-macro.S | 2 +- .../mach-ixp2000/include/mach/debug-macro.S | 2 +- .../mach-ixp23xx/include/mach/debug-macro.S | 2 +- .../mach-ixp4xx/include/mach/debug-macro.S | 2 +- .../mach-kirkwood/include/mach/debug-macro.S | 2 +- .../mach-ks8695/include/mach/debug-macro.S | 2 +- .../arm/mach-l7200/include/mach/debug-macro.S | 2 +- .../mach-lh7a40x/include/mach/debug-macro.S | 2 +- arch/arm/mach-loki/include/mach/debug-macro.S | 2 +- arch/arm/mach-mmp/include/mach/debug-macro.S | 2 +- arch/arm/mach-msm/include/mach/debug-macro.S | 4 ++-- .../mach-mv78xx0/include/mach/debug-macro.S | 2 +- arch/arm/mach-netx/include/mach/debug-macro.S | 2 +- .../mach-nomadik/include/mach/debug-macro.S | 2 +- .../mach-ns9xxx/include/mach/debug-macro.S | 2 +- .../arm/mach-omap1/include/mach/debug-macro.S | 2 +- .../arm/mach-omap2/include/mach/debug-macro.S | 2 +- .../mach-orion5x/include/mach/debug-macro.S | 2 +- .../mach-pnx4008/include/mach/debug-macro.S | 2 +- arch/arm/mach-pxa/include/mach/debug-macro.S | 2 +- .../mach-realview/include/mach/debug-macro.S | 2 +- arch/arm/mach-rpc/include/mach/debug-macro.S | 2 +- .../mach-s3c2410/include/mach/debug-macro.S | 2 +- .../mach-s3c24a0/include/mach/debug-macro.S | 2 +- .../mach-s3c6400/include/mach/debug-macro.S | 2 +- .../mach-s5pc100/include/mach/debug-macro.S | 2 +- .../mach-sa1100/include/mach/debug-macro.S | 2 +- .../arm/mach-shark/include/mach/debug-macro.S | 2 +- arch/arm/mach-u300/include/mach/debug-macro.S | 2 +- .../arm/mach-ux500/include/mach/debug-macro.S | 2 +- .../mach-versatile/include/mach/debug-macro.S | 2 +- arch/arm/plat-mxc/include/mach/debug-macro.S | 2 +- .../plat-stmp3xxx/include/mach/debug-macro.S | 2 +- 48 files changed, 64 insertions(+), 64 deletions(-) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 4fddc509e78e..99b75aa1c2ec 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -22,13 +22,13 @@ #if defined(CONFIG_DEBUG_ICEDCC) #ifdef CONFIG_CPU_V6 - .macro loadsp, rb + .macro loadsp, rb, tmp .endm .macro writeb, ch, rb mcr p14, 0, \ch, c0, c5, 0 .endm #elif defined(CONFIG_CPU_V7) - .macro loadsp, rb + .macro loadsp, rb, tmp .endm .macro writeb, ch, rb wait: mrc p14, 0, pc, c0, c1, 0 @@ -36,13 +36,13 @@ wait: mrc p14, 0, pc, c0, c1, 0 mcr p14, 0, \ch, c0, c5, 0 .endm #elif defined(CONFIG_CPU_XSCALE) - .macro loadsp, rb + .macro loadsp, rb, tmp .endm .macro writeb, ch, rb mcr p14, 0, \ch, c8, c0, 0 .endm #else - .macro loadsp, rb + .macro loadsp, rb, tmp .endm .macro writeb, ch, rb mcr p14, 0, \ch, c1, c0, 0 @@ -58,7 +58,7 @@ wait: mrc p14, 0, pc, c0, c1, 0 .endm #if defined(CONFIG_ARCH_SA1100) - .macro loadsp, rb + .macro loadsp, rb, tmp mov \rb, #0x80000000 @ physical base address #ifdef CONFIG_DEBUG_LL_SER3 add \rb, \rb, #0x00050000 @ Ser3 @@ -67,13 +67,13 @@ wait: mrc p14, 0, pc, c0, c1, 0 #endif .endm #elif defined(CONFIG_ARCH_S3C2410) - .macro loadsp, rb + .macro loadsp, rb, tmp mov \rb, #0x50000000 add \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT .endm #else - .macro loadsp, rb - addruart \rb + .macro loadsp, rb, tmp + addruart \rb, \tmp .endm #endif #endif @@ -1025,7 +1025,7 @@ phex: adr r3, phexbuf strb r2, [r3, r1] b 1b -puts: loadsp r3 +puts: loadsp r3, r1 1: ldrb r2, [r0], #1 teq r2, #0 moveq pc, lr @@ -1042,7 +1042,7 @@ puts: loadsp r3 putc: mov r2, r0 mov r0, #0 - loadsp r3 + loadsp r3, r1 b 2b memdump: mov r12, r0 diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index 5c91addcaebc..a38b4879441d 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S @@ -24,7 +24,7 @@ #if defined(CONFIG_CPU_V6) - .macro addruart, rx + .macro addruart, rx, tmp .endm .macro senduart, rd, rx @@ -51,7 +51,7 @@ #elif defined(CONFIG_CPU_V7) - .macro addruart, rx + .macro addruart, rx, tmp .endm .macro senduart, rd, rx @@ -71,7 +71,7 @@ wait: mrc p14, 0, pc, c0, c1, 0 #elif defined(CONFIG_CPU_XSCALE) - .macro addruart, rx + .macro addruart, rx, tmp .endm .macro senduart, rd, rx @@ -98,7 +98,7 @@ wait: mrc p14, 0, pc, c0, c1, 0 #else - .macro addruart, rx + .macro addruart, rx, tmp .endm .macro senduart, rd, rx @@ -164,7 +164,7 @@ ENDPROC(printhex2) .ltorg ENTRY(printascii) - addruart r3 + addruart r3, r1 b 2f 1: waituart r2, r3 senduart r1, r3 @@ -180,7 +180,7 @@ ENTRY(printascii) ENDPROC(printascii) ENTRY(printch) - addruart r3 + addruart r3, r1 mov r1, r0 mov r0, #0 b 1b diff --git a/arch/arm/mach-aaec2000/include/mach/debug-macro.S b/arch/arm/mach-aaec2000/include/mach/debug-macro.S index 0b6351d7c389..a9cac368bfe6 100644 --- a/arch/arm/mach-aaec2000/include/mach/debug-macro.S +++ b/arch/arm/mach-aaec2000/include/mach/debug-macro.S @@ -10,7 +10,7 @@ */ #include "hardware.h" - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x80000000 @ physical diff --git a/arch/arm/mach-at91/include/mach/debug-macro.S b/arch/arm/mach-at91/include/mach/debug-macro.S index 29052ba66ada..9e750a1c1b5a 100644 --- a/arch/arm/mach-at91/include/mach/debug-macro.S +++ b/arch/arm/mach-at91/include/mach/debug-macro.S @@ -14,7 +14,7 @@ #include #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =(AT91_BASE_SYS + AT91_DBGU) @ System peripherals (phys address) diff --git a/arch/arm/mach-clps711x/include/mach/debug-macro.S b/arch/arm/mach-clps711x/include/mach/debug-macro.S index 64baf9f87408..fedd8076a689 100644 --- a/arch/arm/mach-clps711x/include/mach/debug-macro.S +++ b/arch/arm/mach-clps711x/include/mach/debug-macro.S @@ -13,7 +13,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #CLPS7111_PHYS_BASE diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S index 17ab5236da66..3cd93a801d9b 100644 --- a/arch/arm/mach-davinci/include/mach/debug-macro.S +++ b/arch/arm/mach-davinci/include/mach/debug-macro.S @@ -19,7 +19,7 @@ #include #define UART_SHIFT 2 - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x01000000 @ physical base address diff --git a/arch/arm/mach-dove/include/mach/debug-macro.S b/arch/arm/mach-dove/include/mach/debug-macro.S index 9b89ec7d3040..1521d13f1d14 100644 --- a/arch/arm/mach-dove/include/mach/debug-macro.S +++ b/arch/arm/mach-dove/include/mach/debug-macro.S @@ -8,7 +8,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =DOVE_SB_REGS_PHYS_BASE diff --git a/arch/arm/mach-ebsa110/include/mach/debug-macro.S b/arch/arm/mach-ebsa110/include/mach/debug-macro.S index 1dde8227f3a2..ebbd89f0e6c0 100644 --- a/arch/arm/mach-ebsa110/include/mach/debug-macro.S +++ b/arch/arm/mach-ebsa110/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * **/ - .macro addruart,rx + .macro addruart, rx, tmp mov \rx, #0xf0000000 orr \rx, \rx, #0x00000be0 .endm diff --git a/arch/arm/mach-ep93xx/include/mach/debug-macro.S b/arch/arm/mach-ep93xx/include/mach/debug-macro.S index 802858bc8095..5cd22444e223 100644 --- a/arch/arm/mach-ep93xx/include/mach/debug-macro.S +++ b/arch/arm/mach-ep93xx/include/mach/debug-macro.S @@ -11,7 +11,7 @@ */ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =EP93XX_APB_PHYS_BASE @ Physical base diff --git a/arch/arm/mach-footbridge/include/mach/debug-macro.S b/arch/arm/mach-footbridge/include/mach/debug-macro.S index 4329b8123570..60dda1318f22 100644 --- a/arch/arm/mach-footbridge/include/mach/debug-macro.S +++ b/arch/arm/mach-footbridge/include/mach/debug-macro.S @@ -15,7 +15,7 @@ #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x7c000000 @ physical @@ -32,7 +32,7 @@ .equ dc21285_high, ARMCSR_BASE & 0xff000000 .equ dc21285_low, ARMCSR_BASE & 0x00ffffff - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x42000000 diff --git a/arch/arm/mach-gemini/include/mach/debug-macro.S b/arch/arm/mach-gemini/include/mach/debug-macro.S index d04a6eaeae14..ad477047069d 100644 --- a/arch/arm/mach-gemini/include/mach/debug-macro.S +++ b/arch/arm/mach-gemini/include/mach/debug-macro.S @@ -11,7 +11,7 @@ */ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =GEMINI_UART_BASE @ physical diff --git a/arch/arm/mach-h720x/include/mach/debug-macro.S b/arch/arm/mach-h720x/include/mach/debug-macro.S index 6294a1344dda..a9ee8f0d48b7 100644 --- a/arch/arm/mach-h720x/include/mach/debug-macro.S +++ b/arch/arm/mach-h720x/include/mach/debug-macro.S @@ -14,7 +14,7 @@ .equ io_virt, IO_BASE .equ io_phys, IO_START - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #io_phys @ physical base address diff --git a/arch/arm/mach-integrator/include/mach/debug-macro.S b/arch/arm/mach-integrator/include/mach/debug-macro.S index d347d659ea30..87a6888ae011 100644 --- a/arch/arm/mach-integrator/include/mach/debug-macro.S +++ b/arch/arm/mach-integrator/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x16000000 @ physical base address diff --git a/arch/arm/mach-iop13xx/include/mach/debug-macro.S b/arch/arm/mach-iop13xx/include/mach/debug-macro.S index 9037d2e8557c..c9d6ba46963d 100644 --- a/arch/arm/mach-iop13xx/include/mach/debug-macro.S +++ b/arch/arm/mach-iop13xx/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * published by the Free Software Foundation. */ - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ mmu enabled? moveq \rx, #0xff000000 @ physical diff --git a/arch/arm/mach-iop32x/include/mach/debug-macro.S b/arch/arm/mach-iop32x/include/mach/debug-macro.S index 58b01664ffba..736afe1edd1f 100644 --- a/arch/arm/mach-iop32x/include/mach/debug-macro.S +++ b/arch/arm/mach-iop32x/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * published by the Free Software Foundation. */ - .macro addruart, rx + .macro addruart, rx, tmp mov \rx, #0xfe000000 @ physical as well as virtual orr \rx, \rx, #0x00800000 @ location of the UART .endm diff --git a/arch/arm/mach-iop33x/include/mach/debug-macro.S b/arch/arm/mach-iop33x/include/mach/debug-macro.S index a60c9ef05cc3..addb2da78422 100644 --- a/arch/arm/mach-iop33x/include/mach/debug-macro.S +++ b/arch/arm/mach-iop33x/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * published by the Free Software Foundation. */ - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ mmu enabled? moveq \rx, #0xff000000 @ physical diff --git a/arch/arm/mach-ixp2000/include/mach/debug-macro.S b/arch/arm/mach-ixp2000/include/mach/debug-macro.S index 904ff56d2246..6a827681680f 100644 --- a/arch/arm/mach-ixp2000/include/mach/debug-macro.S +++ b/arch/arm/mach-ixp2000/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0xc0000000 @ Physical base diff --git a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S b/arch/arm/mach-ixp23xx/include/mach/debug-macro.S index 905db3188724..a82e375465e2 100644 --- a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S +++ b/arch/arm/mach-ixp23xx/include/mach/debug-macro.S @@ -12,7 +12,7 @@ */ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ mmu enabled? ldreq \rx, =IXP23XX_PERIPHERAL_PHYS @ physical diff --git a/arch/arm/mach-ixp4xx/include/mach/debug-macro.S b/arch/arm/mach-ixp4xx/include/mach/debug-macro.S index 7c6a6912acde..893873eb2a0d 100644 --- a/arch/arm/mach-ixp4xx/include/mach/debug-macro.S +++ b/arch/arm/mach-ixp4xx/include/mach/debug-macro.S @@ -10,7 +10,7 @@ * published by the Free Software Foundation. */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0xc8000000 diff --git a/arch/arm/mach-kirkwood/include/mach/debug-macro.S b/arch/arm/mach-kirkwood/include/mach/debug-macro.S index a4a55c199d77..d0606774dea7 100644 --- a/arch/arm/mach-kirkwood/include/mach/debug-macro.S +++ b/arch/arm/mach-kirkwood/include/mach/debug-macro.S @@ -8,7 +8,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =KIRKWOOD_REGS_PHYS_BASE diff --git a/arch/arm/mach-ks8695/include/mach/debug-macro.S b/arch/arm/mach-ks8695/include/mach/debug-macro.S index 3782c3559497..cf2095da2372 100644 --- a/arch/arm/mach-ks8695/include/mach/debug-macro.S +++ b/arch/arm/mach-ks8695/include/mach/debug-macro.S @@ -14,7 +14,7 @@ #include #include - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =KS8695_UART_PA @ physical base address diff --git a/arch/arm/mach-l7200/include/mach/debug-macro.S b/arch/arm/mach-l7200/include/mach/debug-macro.S index 34eed2a63e69..b69ed344c7c9 100644 --- a/arch/arm/mach-l7200/include/mach/debug-macro.S +++ b/arch/arm/mach-l7200/include/mach/debug-macro.S @@ -14,7 +14,7 @@ .equ io_virt, IO_BASE .equ io_phys, IO_START - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #io_phys @ physical base address diff --git a/arch/arm/mach-lh7a40x/include/mach/debug-macro.S b/arch/arm/mach-lh7a40x/include/mach/debug-macro.S index 85141ed5383d..c0dcbbba22ba 100644 --- a/arch/arm/mach-lh7a40x/include/mach/debug-macro.S +++ b/arch/arm/mach-lh7a40x/include/mach/debug-macro.S @@ -14,7 +14,7 @@ @ It is not known if this will be appropriate for every 40x @ board. - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? mov \rx, #0x00000700 @ offset from base diff --git a/arch/arm/mach-loki/include/mach/debug-macro.S b/arch/arm/mach-loki/include/mach/debug-macro.S index a8c20bd2f951..3136c913a92c 100644 --- a/arch/arm/mach-loki/include/mach/debug-macro.S +++ b/arch/arm/mach-loki/include/mach/debug-macro.S @@ -8,7 +8,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =LOKI_REGS_PHYS_BASE diff --git a/arch/arm/mach-mmp/include/mach/debug-macro.S b/arch/arm/mach-mmp/include/mach/debug-macro.S index a850f87de51d..76deff238e1c 100644 --- a/arch/arm/mach-mmp/include/mach/debug-macro.S +++ b/arch/arm/mach-mmp/include/mach/debug-macro.S @@ -11,7 +11,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =APB_PHYS_BASE @ physical diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S index d48747ebcd3d..528750f307e9 100644 --- a/arch/arm/mach-msm/include/mach/debug-macro.S +++ b/arch/arm/mach-msm/include/mach/debug-macro.S @@ -20,7 +20,7 @@ #include #ifdef CONFIG_MSM_DEBUG_UART - .macro addruart,rx + .macro addruart, rx, tmp @ see if the MMU is enabled and select appropriate base address mrc p15, 0, \rx, c1, c0 tst \rx, #1 @@ -40,7 +40,7 @@ beq 1001b .endm #else - .macro addruart,rx + .macro addruart, rx, tmp .endm .macro senduart,rd,rx diff --git a/arch/arm/mach-mv78xx0/include/mach/debug-macro.S b/arch/arm/mach-mv78xx0/include/mach/debug-macro.S index a06442fbd341..cd81689c4621 100644 --- a/arch/arm/mach-mv78xx0/include/mach/debug-macro.S +++ b/arch/arm/mach-mv78xx0/include/mach/debug-macro.S @@ -8,7 +8,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =MV78XX0_REGS_PHYS_BASE diff --git a/arch/arm/mach-netx/include/mach/debug-macro.S b/arch/arm/mach-netx/include/mach/debug-macro.S index 11b9d5b46390..e96339e71d88 100644 --- a/arch/arm/mach-netx/include/mach/debug-macro.S +++ b/arch/arm/mach-netx/include/mach/debug-macro.S @@ -13,7 +13,7 @@ #include "hardware.h" - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x00100000 @ physical diff --git a/arch/arm/mach-nomadik/include/mach/debug-macro.S b/arch/arm/mach-nomadik/include/mach/debug-macro.S index e876990e1569..4f92acfba954 100644 --- a/arch/arm/mach-nomadik/include/mach/debug-macro.S +++ b/arch/arm/mach-nomadik/include/mach/debug-macro.S @@ -10,7 +10,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x10000000 @ physical base address diff --git a/arch/arm/mach-ns9xxx/include/mach/debug-macro.S b/arch/arm/mach-ns9xxx/include/mach/debug-macro.S index c9530fba00aa..0859336a8e6d 100644 --- a/arch/arm/mach-ns9xxx/include/mach/debug-macro.S +++ b/arch/arm/mach-ns9xxx/include/mach/debug-macro.S @@ -11,7 +11,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, =NS9XXX_CSxSTAT_PHYS(0) diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S index aedb746fc33c..8c74cab2fa8b 100644 --- a/arch/arm/mach-omap1/include/mach/debug-macro.S +++ b/arch/arm/mach-omap1/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0xff000000 @ physical base address diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S index e9f255df9163..86979d7bd871 100644 --- a/arch/arm/mach-omap2/include/mach/debug-macro.S +++ b/arch/arm/mach-omap2/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? #ifdef CONFIG_ARCH_OMAP2 diff --git a/arch/arm/mach-orion5x/include/mach/debug-macro.S b/arch/arm/mach-orion5x/include/mach/debug-macro.S index c7f808bfe272..91e0e39bb23f 100644 --- a/arch/arm/mach-orion5x/include/mach/debug-macro.S +++ b/arch/arm/mach-orion5x/include/mach/debug-macro.S @@ -10,7 +10,7 @@ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =ORION5X_REGS_PHYS_BASE diff --git a/arch/arm/mach-pnx4008/include/mach/debug-macro.S b/arch/arm/mach-pnx4008/include/mach/debug-macro.S index 6d1407f319f8..6ca8bd30bf46 100644 --- a/arch/arm/mach-pnx4008/include/mach/debug-macro.S +++ b/arch/arm/mach-pnx4008/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? mov \rx, #0x00090000 diff --git a/arch/arm/mach-pxa/include/mach/debug-macro.S b/arch/arm/mach-pxa/include/mach/debug-macro.S index 55d6a175ab19..01cf81393fe2 100644 --- a/arch/arm/mach-pxa/include/mach/debug-macro.S +++ b/arch/arm/mach-pxa/include/mach/debug-macro.S @@ -13,7 +13,7 @@ #include "hardware.h" - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x40000000 @ physical diff --git a/arch/arm/mach-realview/include/mach/debug-macro.S b/arch/arm/mach-realview/include/mach/debug-macro.S index 932d8af18062..86622289b74e 100644 --- a/arch/arm/mach-realview/include/mach/debug-macro.S +++ b/arch/arm/mach-realview/include/mach/debug-macro.S @@ -33,7 +33,7 @@ #error "Unknown RealView platform" #endif - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x10000000 diff --git a/arch/arm/mach-rpc/include/mach/debug-macro.S b/arch/arm/mach-rpc/include/mach/debug-macro.S index b2a939ffdcde..6fc8d66395dc 100644 --- a/arch/arm/mach-rpc/include/mach/debug-macro.S +++ b/arch/arm/mach-rpc/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x03000000 diff --git a/arch/arm/mach-s3c2410/include/mach/debug-macro.S b/arch/arm/mach-s3c2410/include/mach/debug-macro.S index 4c29a89ad077..0eef78b4a6ed 100644 --- a/arch/arm/mach-s3c2410/include/mach/debug-macro.S +++ b/arch/arm/mach-s3c2410/include/mach/debug-macro.S @@ -19,7 +19,7 @@ #define S3C2410_UART1_OFF (0x4000) #define SHIFT_2440TXF (14-9) - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, = S3C24XX_PA_UART diff --git a/arch/arm/mach-s3c24a0/include/mach/debug-macro.S b/arch/arm/mach-s3c24a0/include/mach/debug-macro.S index f0ef0ab475f6..239476b81f3b 100644 --- a/arch/arm/mach-s3c24a0/include/mach/debug-macro.S +++ b/arch/arm/mach-s3c24a0/include/mach/debug-macro.S @@ -10,7 +10,7 @@ #include #include - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, = S3C24XX_PA_UART diff --git a/arch/arm/mach-s3c6400/include/mach/debug-macro.S b/arch/arm/mach-s3c6400/include/mach/debug-macro.S index b18ac5266dfc..5c88875d6a3f 100644 --- a/arch/arm/mach-s3c6400/include/mach/debug-macro.S +++ b/arch/arm/mach-s3c6400/include/mach/debug-macro.S @@ -21,7 +21,7 @@ * aligned and add in the offset when we load the value here. */ - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, = S3C_PA_UART diff --git a/arch/arm/mach-s5pc100/include/mach/debug-macro.S b/arch/arm/mach-s5pc100/include/mach/debug-macro.S index 9d142ccf654b..e181f5789482 100644 --- a/arch/arm/mach-s5pc100/include/mach/debug-macro.S +++ b/arch/arm/mach-s5pc100/include/mach/debug-macro.S @@ -22,7 +22,7 @@ * aligned and add in the offset when we load the value here. */ - .macro addruart, rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, = S3C_PA_UART diff --git a/arch/arm/mach-sa1100/include/mach/debug-macro.S b/arch/arm/mach-sa1100/include/mach/debug-macro.S index 1f0634d92702..336adccea542 100644 --- a/arch/arm/mach-sa1100/include/mach/debug-macro.S +++ b/arch/arm/mach-sa1100/include/mach/debug-macro.S @@ -12,7 +12,7 @@ */ #include - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x80000000 @ physical base address diff --git a/arch/arm/mach-shark/include/mach/debug-macro.S b/arch/arm/mach-shark/include/mach/debug-macro.S index f97a7626bd58..50f071c5bf4d 100644 --- a/arch/arm/mach-shark/include/mach/debug-macro.S +++ b/arch/arm/mach-shark/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mov \rx, #0xe0000000 orr \rx, \rx, #0x000003f8 .endm diff --git a/arch/arm/mach-u300/include/mach/debug-macro.S b/arch/arm/mach-u300/include/mach/debug-macro.S index f3a1cbbeeab3..ca4a028c2661 100644 --- a/arch/arm/mach-u300/include/mach/debug-macro.S +++ b/arch/arm/mach-u300/include/mach/debug-macro.S @@ -10,7 +10,7 @@ */ #include - .macro addruart,rx + .macro addruart, rx, tmp /* If we move the adress using MMU, use this. */ mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S index 8f21b6a95dce..494408b96785 100644 --- a/arch/arm/mach-ux500/include/mach/debug-macro.S +++ b/arch/arm/mach-ux500/include/mach/debug-macro.S @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @MMU enabled? moveq \rx, #0x80000000 @MMU off, Physical address diff --git a/arch/arm/mach-versatile/include/mach/debug-macro.S b/arch/arm/mach-versatile/include/mach/debug-macro.S index b4ac00eacf68..6fea7199c626 100644 --- a/arch/arm/mach-versatile/include/mach/debug-macro.S +++ b/arch/arm/mach-versatile/include/mach/debug-macro.S @@ -11,7 +11,7 @@ * */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x10000000 diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S index 15b2b148a105..5a6ae1b9e1e8 100644 --- a/arch/arm/plat-mxc/include/mach/debug-macro.S +++ b/arch/arm/plat-mxc/include/mach/debug-macro.S @@ -52,7 +52,7 @@ #define UART_PADDR MXC91231_UART2_BASE_ADDR #define UART_VADDR MXC91231_AIPS1_IO_ADDRESS(MXC91231_UART2_BASE_ADDR) #endif - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? ldreq \rx, =UART_PADDR @ physical diff --git a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S index fb3b969bf0a2..1b9348bf0e49 100644 --- a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S +++ b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S @@ -16,7 +16,7 @@ * http://www.gnu.org/copyleft/gpl.html */ - .macro addruart,rx + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x80000000 @ physical base address -- GitLab From 0a0300dc8c4b3f3ce5c9ef5a0a4be5442590398f Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 12 Jan 2010 12:28:00 +0000 Subject: [PATCH 1941/3892] ARM: Consolidate clks_register() and similar Most machine classes want some way to register a block of clk_lookup structures, and most do it by implementing a clks_register() type function which walks an array, or by open-coding a loop. Consolidate all this into clkdev_add_table(). Acked-by: H Hartley Sweeten Reviewed-by: Kevin Hilman Acked-by: Eric Miao Signed-off-by: Russell King --- arch/arm/common/clkdev.c | 10 ++++++++++ arch/arm/include/asm/clkdev.h | 3 +++ arch/arm/mach-bcmring/core.c | 3 +-- arch/arm/mach-ep93xx/clock.c | 4 +--- arch/arm/mach-integrator/core.c | 3 +-- arch/arm/mach-integrator/integrator_cp.c | 4 +--- arch/arm/mach-mmp/clock.c | 8 -------- arch/arm/mach-mmp/clock.h | 2 -- arch/arm/mach-mmp/pxa168.c | 2 +- arch/arm/mach-mmp/pxa910.c | 2 +- arch/arm/mach-mx1/clock.c | 4 +--- arch/arm/mach-mx2/clock_imx21.c | 4 +--- arch/arm/mach-mx2/clock_imx27.c | 4 +--- arch/arm/mach-mx25/clock.c | 6 +----- arch/arm/mach-mx3/clock-imx35.c | 4 +--- arch/arm/mach-mx3/clock.c | 4 +--- arch/arm/mach-mxc91231/clock.c | 4 +--- arch/arm/mach-pxa/clock.c | 8 -------- arch/arm/mach-pxa/clock.h | 4 ---- arch/arm/mach-pxa/eseries.c | 2 +- arch/arm/mach-pxa/pxa25x.c | 4 ++-- arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/pxa300.c | 4 ++-- arch/arm/mach-pxa/pxa320.c | 2 +- arch/arm/mach-pxa/pxa3xx.c | 2 +- arch/arm/mach-realview/core.c | 5 +---- arch/arm/mach-u300/clock.c | 5 +---- arch/arm/mach-ux500/clock.c | 5 +---- arch/arm/mach-versatile/core.c | 3 +-- arch/arm/mach-w90x900/clock.c | 9 --------- arch/arm/mach-w90x900/clock.h | 1 - arch/arm/mach-w90x900/cpu.c | 2 +- arch/arm/plat-stmp3xxx/clock.c | 3 +-- 33 files changed, 40 insertions(+), 92 deletions(-) diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c index aae5bc01acc8..446b696196e3 100644 --- a/arch/arm/common/clkdev.c +++ b/arch/arm/common/clkdev.c @@ -99,6 +99,16 @@ void clkdev_add(struct clk_lookup *cl) } EXPORT_SYMBOL(clkdev_add); +void __init clkdev_add_table(struct clk_lookup *cl, size_t num) +{ + mutex_lock(&clocks_mutex); + while (num--) { + list_add_tail(&cl->node, &clocks); + cl++; + } + mutex_unlock(&clocks_mutex); +} + #define MAX_DEV_ID 20 #define MAX_CON_ID 16 diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index b6ec7c627b39..7a0690da5e63 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -27,4 +27,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, void clkdev_add(struct clk_lookup *cl); void clkdev_drop(struct clk_lookup *cl); +void clkdev_add_table(struct clk_lookup *, size_t); +int clk_add_alias(const char *, const char *, char *, struct device *); + #endif diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c index e590bbe0a7b4..72e405df0fb0 100644 --- a/arch/arm/mach-bcmring/core.c +++ b/arch/arm/mach-bcmring/core.c @@ -142,8 +142,7 @@ void __init bcmring_amba_init(void) chipcHw_busInterfaceClockEnable(bus_clock); - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 1d0f9d8aff2e..bb3c62196442 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -445,7 +445,6 @@ static void __init ep93xx_dma_clock_init(void) static int __init ep93xx_clock_init(void) { u32 value; - int i; value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); if (!(value & 0x00800000)) { /* PLL1 bypassed? */ @@ -474,8 +473,7 @@ static int __init ep93xx_clock_init(void) clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); - for (i = 0; i < ARRAY_SIZE(clocks); i++) - clkdev_add(&clocks[i]); + clkdev_add_table(clocks, ARRAY_SIZE(clocks)); return 0; } arch_initcall(ep93xx_clock_init); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index a0f60e55da6a..8b390e36ba69 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -144,8 +144,7 @@ static int __init integrator_init(void) { int i; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 3f35293d457a..66ef86d6d9e3 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -558,9 +558,7 @@ static void __init intcp_init(void) { int i; - for (i = 0; i < ARRAY_SIZE(cp_lookups); i++) - clkdev_add(&cp_lookups[i]); - + clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups)); platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs)); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c index 2a46ed5cc2a2..886e05648f08 100644 --- a/arch/arm/mach-mmp/clock.c +++ b/arch/arm/mach-mmp/clock.c @@ -88,11 +88,3 @@ unsigned long clk_get_rate(struct clk *clk) return rate; } EXPORT_SYMBOL(clk_get_rate); - -void clks_register(struct clk_lookup *clks, size_t num) -{ - int i; - - for (i = 0; i < num; i++) - clkdev_add(&clks[i]); -} diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h index eefffbe683b0..016ae94691c0 100644 --- a/arch/arm/mach-mmp/clock.h +++ b/arch/arm/mach-mmp/clock.h @@ -68,5 +68,3 @@ struct clk clk_##_name = { \ extern struct clk clk_pxa168_gpio; extern struct clk clk_pxa168_timers; - -extern void clks_register(struct clk_lookup *, size_t); diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c index 37dbdde17fac..1873c821df90 100644 --- a/arch/arm/mach-mmp/pxa168.c +++ b/arch/arm/mach-mmp/pxa168.c @@ -94,7 +94,7 @@ static int __init pxa168_init(void) mfp_init_base(MFPR_VIRT_BASE); mfp_init_addr(pxa168_mfp_addr_map); pxa_init_dma(IRQ_PXA168_DMA_INT0, 32); - clks_register(ARRAY_AND_SIZE(pxa168_clkregs)); + clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs)); } return 0; diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index d4049508a4df..46f2d69bef3c 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -131,7 +131,7 @@ static int __init pxa910_init(void) mfp_init_base(MFPR_VIRT_BASE); mfp_init_addr(pxa910_mfp_addr_map); pxa_init_dma(IRQ_PXA910_DMA_INT0, 32); - clks_register(ARRAY_AND_SIZE(pxa910_clkregs)); + clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs)); } return 0; diff --git a/arch/arm/mach-mx1/clock.c b/arch/arm/mach-mx1/clock.c index d1b588519ad2..6cf2d4a7511d 100644 --- a/arch/arm/mach-mx1/clock.c +++ b/arch/arm/mach-mx1/clock.c @@ -570,7 +570,6 @@ static struct clk_lookup lookups[] __initdata = { int __init mx1_clocks_init(unsigned long fref) { unsigned int reg; - int i; /* disable clocks we are able to */ __raw_writel(0, SCM_GCCR); @@ -592,8 +591,7 @@ int __init mx1_clocks_init(unsigned long fref) reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET; clko_clk.parent = (struct clk *)clko_clocks[reg]; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); clk_enable(&hclk); clk_enable(&fclk); diff --git a/arch/arm/mach-mx2/clock_imx21.c b/arch/arm/mach-mx2/clock_imx21.c index 91901b5d56c2..e82b489d1215 100644 --- a/arch/arm/mach-mx2/clock_imx21.c +++ b/arch/arm/mach-mx2/clock_imx21.c @@ -968,7 +968,6 @@ static struct clk_lookup lookups[] = { */ int __init mx21_clocks_init(unsigned long lref, unsigned long href) { - int i; u32 cscr; external_low_reference = lref; @@ -986,8 +985,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) else spll_clk.parent = &fpm_clk; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); /* Turn off all clock gates */ __raw_writel(0, CCM_PCCR0); diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c index b010bf9ceaab..18c53a6487fa 100644 --- a/arch/arm/mach-mx2/clock_imx27.c +++ b/arch/arm/mach-mx2/clock_imx27.c @@ -719,7 +719,6 @@ static void __init to2_adjust_clocks(void) int __init mx27_clocks_init(unsigned long fref) { u32 cscr = __raw_readl(CCM_CSCR); - int i; external_high_reference = fref; @@ -736,8 +735,7 @@ int __init mx27_clocks_init(unsigned long fref) to2_adjust_clocks(); - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); /* Turn off all clocks we do not need */ __raw_writel(0, CCM_PCCR0); diff --git a/arch/arm/mach-mx25/clock.c b/arch/arm/mach-mx25/clock.c index 6e838b857712..66916f104812 100644 --- a/arch/arm/mach-mx25/clock.c +++ b/arch/arm/mach-mx25/clock.c @@ -210,11 +210,7 @@ static struct clk_lookup lookups[] = { int __init mx25_clocks_init(unsigned long fref) { - int i; - - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); - + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); return 0; diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index 7584b4c6c556..f3f41fa4f21b 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -485,15 +485,13 @@ static struct clk_lookup lookups[] = { int __init mx35_clocks_init() { - int i; unsigned int ll = 0; #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) ll = (3 << 16); #endif - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); /* Turn off all clocks except the ones we need to survive, namely: * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c index 27a318af0d20..b5c39a016db7 100644 --- a/arch/arm/mach-mx3/clock.c +++ b/arch/arm/mach-mx3/clock.c @@ -578,12 +578,10 @@ static struct clk_lookup lookups[] = { int __init mx31_clocks_init(unsigned long fref) { u32 reg; - int i; ckih_rate = fref; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); /* change the csi_clk parent if necessary */ reg = __raw_readl(MXC_CCM_CCMR); diff --git a/arch/arm/mach-mxc91231/clock.c b/arch/arm/mach-mxc91231/clock.c index ecfa37fef8ad..5c85075d8a56 100644 --- a/arch/arm/mach-mxc91231/clock.c +++ b/arch/arm/mach-mxc91231/clock.c @@ -624,7 +624,6 @@ static struct clk_lookup lookups[] = { int __init mxc91231_clocks_init(unsigned long fref) { void __iomem *gpt_base; - int i; ckih_rate = fref; @@ -632,8 +631,7 @@ int __init mxc91231_clocks_init(unsigned long fref) sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]); sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]); - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR); mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT); diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index 49ae38292310..abba0089a2ae 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c @@ -78,11 +78,3 @@ const struct clkops clk_cken_ops = { .enable = clk_cken_enable, .disable = clk_cken_disable, }; - -void clks_register(struct clk_lookup *clks, size_t num) -{ - int i; - - for (i = 0; i < num; i++) - clkdev_add(&clks[i]); -} diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h index 978a3667e90d..d8488742b807 100644 --- a/arch/arm/mach-pxa/clock.h +++ b/arch/arm/mach-pxa/clock.h @@ -67,7 +67,3 @@ extern void clk_pxa3xx_cken_enable(struct clk *); extern void clk_pxa3xx_cken_disable(struct clk *); #endif -void clks_register(struct clk_lookup *clks, size_t num); -int clk_add_alias(const char *alias, const char *alias_name, char *id, - struct device *dev); - diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index 91417f035069..96ed13081639 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -128,6 +128,6 @@ static struct clk_lookup eseries_clkregs[] = { void eseries_register_clks(void) { - clks_register(eseries_clkregs, ARRAY_SIZE(eseries_clkregs)); + clkdev_add_table(eseries_clkregs, ARRAY_SIZE(eseries_clkregs)); } diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 2c1b0b70d01d..0b9ad30bfd51 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -349,7 +349,7 @@ static int __init pxa25x_init(void) reset_status = RCSR; - clks_register(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs)); + clkdev_add_table(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs)); if ((ret = pxa_init_dma(IRQ_DMA, 16))) return ret; @@ -370,7 +370,7 @@ static int __init pxa25x_init(void) /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */ if (cpu_is_pxa255()) - clks_register(&pxa25x_hwuart_clkreg, 1); + clkdev_add(&pxa25x_hwuart_clkreg); return ret; } diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 6a0b73167e03..d783123e2d48 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -392,7 +392,7 @@ static int __init pxa27x_init(void) reset_status = RCSR; - clks_register(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs)); + clkdev_add_table(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs)); if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c index f4af6e2bef89..40bb16501d86 100644 --- a/arch/arm/mach-pxa/pxa300.c +++ b/arch/arm/mach-pxa/pxa300.c @@ -102,12 +102,12 @@ static int __init pxa300_init(void) if (cpu_is_pxa300() || cpu_is_pxa310()) { mfp_init_base(io_p2v(MFPR_BASE)); mfp_init_addr(pxa300_mfp_addr_map); - clks_register(ARRAY_AND_SIZE(common_clkregs)); + clkdev_add_table(ARRAY_AND_SIZE(common_clkregs)); } if (cpu_is_pxa310()) { mfp_init_addr(pxa310_mfp_addr_map); - clks_register(ARRAY_AND_SIZE(pxa310_clkregs)); + clkdev_add_table(ARRAY_AND_SIZE(pxa310_clkregs)); } return 0; diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c index c7373e74a109..8d614ecd8e99 100644 --- a/arch/arm/mach-pxa/pxa320.c +++ b/arch/arm/mach-pxa/pxa320.c @@ -90,7 +90,7 @@ static int __init pxa320_init(void) if (cpu_is_pxa320()) { mfp_init_base(io_p2v(MFPR_BASE)); mfp_init_addr(pxa320_mfp_addr_map); - clks_register(ARRAY_AND_SIZE(pxa320_clkregs)); + clkdev_add_table(ARRAY_AND_SIZE(pxa320_clkregs)); } return 0; diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index fcb0721f4669..4d7c03e72504 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -634,7 +634,7 @@ static int __init pxa3xx_init(void) */ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); - clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs)); + clkdev_add_table(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs)); if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 9f293438e020..90bd4ef71b2c 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -346,10 +346,7 @@ static struct clk_lookup lookups[] = { static int __init clk_init(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); return 0; } arch_initcall(clk_init); diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c index 111f7ea32b38..c174ed1f3691 100644 --- a/arch/arm/mach-u300/clock.c +++ b/arch/arm/mach-u300/clock.c @@ -1276,11 +1276,8 @@ static struct clk_lookup lookups[] = { static void __init clk_register(void) { - int i; - /* Register the lookups */ - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); } /* diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 20b6ebb6783a..8359a73d0041 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -85,11 +85,8 @@ static struct clk_lookup lookups[] = { static int __init clk_init(void) { - int i; - /* register the clock lookups */ - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); return 0; } arch_initcall(clk_init); diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index e13be7c444ca..9ddb49b1cb71 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -851,8 +851,7 @@ void __init versatile_init(void) { int i; - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); platform_device_register(&versatile_flash_device); platform_device_register(&versatile_i2c_device); diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c index b785994bab0a..2c371ff22e51 100644 --- a/arch/arm/mach-w90x900/clock.c +++ b/arch/arm/mach-w90x900/clock.c @@ -90,12 +90,3 @@ void nuc900_subclk_enable(struct clk *clk, int enable) __raw_writel(clken, W90X900_VA_CLKPWR + SUBCLK); } - - -void clks_register(struct clk_lookup *clks, size_t num) -{ - int i; - - for (i = 0; i < num; i++) - clkdev_add(&clks[i]); -} diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h index f5816a06eed6..c56ddab3d912 100644 --- a/arch/arm/mach-w90x900/clock.h +++ b/arch/arm/mach-w90x900/clock.h @@ -14,7 +14,6 @@ void nuc900_clk_enable(struct clk *clk, int enable); void nuc900_subclk_enable(struct clk *clk, int enable); -void clks_register(struct clk_lookup *clks, size_t num); struct clk { unsigned long cken; diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c index 20dc0c96214d..6f5ca532883f 100644 --- a/arch/arm/mach-w90x900/cpu.c +++ b/arch/arm/mach-w90x900/cpu.c @@ -208,6 +208,6 @@ void __init nuc900_map_io(struct map_desc *mach_desc, int mach_size) void __init nuc900_init_clocks(void) { - clks_register(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs)); + clkdev_add_table(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs)); } diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c index 5d2f19a09e44..e593a2a801c6 100644 --- a/arch/arm/plat-stmp3xxx/clock.c +++ b/arch/arm/plat-stmp3xxx/clock.c @@ -1126,9 +1126,8 @@ static int __init clk_init(void) if (ops && ops->set_parent) ops->set_parent(cl->clk, cl->clk->parent); } - - clkdev_add(cl); } + clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks)); return 0; } -- GitLab From 6985a5ad0d719d8c8d584a69f6e5d7138a2e19ab Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 10:32:41 +0000 Subject: [PATCH 1942/3892] ARM: PNX4008: convert to clkdev Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + arch/arm/mach-pnx4008/clock.c | 66 +++++++++++---------- arch/arm/mach-pnx4008/clock.h | 2 - arch/arm/mach-pnx4008/include/mach/clkdev.h | 7 +++ 4 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 arch/arm/mach-pnx4008/include/mach/clkdev.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4c33ca82f9b1..fb2a51b0ec15 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -554,6 +554,7 @@ config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select CPU_ARM926T select HAVE_CLK + select COMMON_CLKDEV help This enables support for Philips PNX4008 mobile platform. diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 898c0e88acbc..6f5d2e502654 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -22,8 +22,9 @@ #include #include -#include +#include +#include #include #include "clock.h" @@ -747,7 +748,7 @@ static struct clk wdt_ck = { /* These clocks are visible outside this module * and can be initialized */ -static struct clk *onchip_clks[] = { +static struct clk *onchip_clks[] __initdata = { &ck_13MHz, &ck_pll1, &ck_pll4, @@ -777,6 +778,36 @@ static struct clk *onchip_clks[] = { &wdt_ck, }; +static struct clk_lookup onchip_clkreg[] = { + { .clk = &ck_13MHz, .con_id = "ck_13MHz" }, + { .clk = &ck_pll1, .con_id = "ck_pll1" }, + { .clk = &ck_pll4, .con_id = "ck_pll4" }, + { .clk = &ck_pll5, .con_id = "ck_pll5" }, + { .clk = &ck_pll3, .con_id = "ck_pll3" }, + { .clk = &vfp9_ck, .con_id = "vfp9_ck" }, + { .clk = &m2hclk_ck, .con_id = "m2hclk_ck" }, + { .clk = &hclk_ck, .con_id = "hclk_ck" }, + { .clk = &dma_ck, .con_id = "dma_ck" }, + { .clk = &flash_ck, .con_id = "flash_ck" }, + { .clk = &dum_ck, .con_id = "dum_ck" }, + { .clk = &keyscan_ck, .con_id = "keyscan_ck" }, + { .clk = &pwm1_ck, .con_id = "pwm1_ck" }, + { .clk = &pwm2_ck, .con_id = "pwm2_ck" }, + { .clk = &jpeg_ck, .con_id = "jpeg_ck" }, + { .clk = &ms_ck, .con_id = "ms_ck" }, + { .clk = &touch_ck, .con_id = "touch_ck" }, + { .clk = &i2c0_ck, .con_id = "i2c0_ck" }, + { .clk = &i2c1_ck, .con_id = "i2c1_ck" }, + { .clk = &i2c2_ck, .con_id = "i2c2_ck" }, + { .clk = &spi0_ck, .con_id = "spi0_ck" }, + { .clk = &spi1_ck, .con_id = "spi1_ck" }, + { .clk = &uart3_ck, .con_id = "uart3_ck" }, + { .clk = &uart4_ck, .con_id = "uart4_ck" }, + { .clk = &uart5_ck, .con_id = "uart5_ck" }, + { .clk = &uart6_ck, .con_id = "uart6_ck" }, + { .clk = &wdt_ck, .con_id = "wdt_ck" }, +}; + static int local_clk_enable(struct clk *clk) { int ret = 0; @@ -866,35 +897,6 @@ out: EXPORT_SYMBOL(clk_set_rate); -struct clk *clk_get(struct device *dev, const char *id) -{ - struct clk *clk = ERR_PTR(-ENOENT); - struct clk **clkp; - - clock_lock(); - for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); - clkp++) { - if (strcmp(id, (*clkp)->name) == 0 - && try_module_get((*clkp)->owner)) { - clk = (*clkp); - break; - } - } - clock_unlock(); - - return clk; -} -EXPORT_SYMBOL(clk_get); - -void clk_put(struct clk *clk) -{ - clock_lock(); - if (clk && !IS_ERR(clk)) - module_put(clk->owner); - clock_unlock(); -} -EXPORT_SYMBOL(clk_put); - unsigned long clk_get_rate(struct clk *clk) { unsigned long ret; @@ -987,6 +989,8 @@ static int __init clk_init(void) /* Disable autoclocking */ __raw_writeb(0xff, AUTOCLK_CTRL); + clkdev_add_table(onchip_clkreg, ARRAY_SIZE(onchip_clkreg)); + return 0; } diff --git a/arch/arm/mach-pnx4008/clock.h b/arch/arm/mach-pnx4008/clock.h index cd58f372cfd0..933e18133b96 100644 --- a/arch/arm/mach-pnx4008/clock.h +++ b/arch/arm/mach-pnx4008/clock.h @@ -14,8 +14,6 @@ #define __ARCH_ARM_PNX4008_CLOCK_H__ struct clk { - struct list_head node; - struct module *owner; const char *name; struct clk *parent; struct clk *propagate_next; diff --git a/arch/arm/mach-pnx4008/include/mach/clkdev.h b/arch/arm/mach-pnx4008/include/mach/clkdev.h new file mode 100644 index 000000000000..04b37a89801c --- /dev/null +++ b/arch/arm/mach-pnx4008/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif -- GitLab From 5413f7464e976e2c2ddb20686fc2e66ae8795b6e Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 11:25:44 +0000 Subject: [PATCH 1943/3892] ARM: PNX4008: simplify clk enable/disable paths Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 55 +++++++++++++++-------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 6f5d2e502654..f0cc91909090 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -808,49 +808,40 @@ static struct clk_lookup onchip_clkreg[] = { { .clk = &wdt_ck, .con_id = "wdt_ck" }, }; -static int local_clk_enable(struct clk *clk) -{ - int ret = 0; - - if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate - && clk->user_rate) - ret = clk->set_rate(clk, clk->user_rate); - return ret; -} - static void local_clk_disable(struct clk *clk) { - if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate) - clk->set_rate(clk, 0); -} + if (WARN_ON(clk->usecount == 0)) + return; -static void local_clk_unuse(struct clk *clk) -{ - if (clk->usecount > 0 && !(--clk->usecount)) { - local_clk_disable(clk); + if (!(--clk->usecount)) { + if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate) + clk->set_rate(clk, 0); if (clk->parent) - local_clk_unuse(clk->parent); + local_clk_disable(clk->parent); } } -static int local_clk_use(struct clk *clk) +static int local_clk_enable(struct clk *clk) { int ret = 0; - if (clk->usecount++ == 0) { - if (clk->parent) - ret = local_clk_use(clk->parent); - if (ret != 0) { - clk->usecount--; - goto out; + if (clk->usecount == 0) { + if (clk->parent) { + ret = local_clk_enable(clk->parent); + if (ret != 0) + goto out; } - ret = local_clk_enable(clk); + if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate + && clk->user_rate) + ret = clk->set_rate(clk, clk->user_rate); if (ret != 0 && clk->parent) { - local_clk_unuse(clk->parent); - clk->usecount--; + local_clk_disable(clk->parent); + goto out; } + + clk->usecount++; } out: return ret; @@ -909,10 +900,10 @@ EXPORT_SYMBOL(clk_get_rate); int clk_enable(struct clk *clk) { - int ret = 0; + int ret; clock_lock(); - ret = local_clk_use(clk); + ret = local_clk_enable(clk); clock_unlock(); return ret; } @@ -922,7 +913,7 @@ EXPORT_SYMBOL(clk_enable); void clk_disable(struct clk *clk) { clock_lock(); - local_clk_unuse(clk); + local_clk_disable(clk); clock_unlock(); } @@ -980,7 +971,7 @@ static int __init clk_init(void) __func__, (*clkp)->name, (*clkp)->rate); } - local_clk_use(&ck_pll4); + local_clk_enable(&ck_pll4); /* if ck_13MHz is not used, disable it. */ if (ck_13MHz.usecount == 0) -- GitLab From 0c452df9f08d4f0b829802cec3501d987390ada2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 11:28:59 +0000 Subject: [PATCH 1944/3892] ARM: PNX4008: provide clock enable/disable methods and initialization Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 35 +++++++++++++++++++++++------------ arch/arm/mach-pnx4008/clock.h | 4 +++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index f0cc91909090..3ad694e15968 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -57,18 +57,19 @@ static void propagate_rate(struct clk *clk) } } -static inline void clk_reg_disable(struct clk *clk) +static void clk_reg_disable(struct clk *clk) { if (clk->enable_reg) __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_shift), clk->enable_reg); } -static inline void clk_reg_enable(struct clk *clk) +static int clk_reg_enable(struct clk *clk) { if (clk->enable_reg) __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_shift), clk->enable_reg); + return 0; } static inline void clk_reg_disable1(struct clk *clk) @@ -814,7 +815,9 @@ static void local_clk_disable(struct clk *clk) return; if (!(--clk->usecount)) { - if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate) + if (clk->disable) + clk->disable(clk); + else if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate) clk->set_rate(clk, 0); if (clk->parent) local_clk_disable(clk->parent); @@ -832,8 +835,10 @@ static int local_clk_enable(struct clk *clk) goto out; } - if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate - && clk->user_rate) + if (clk->enable) + ret = clk->enable(clk); + else if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate + && clk->user_rate) ret = clk->set_rate(clk, clk->user_rate); if (ret != 0 && clk->parent) { @@ -960,15 +965,21 @@ static int __init clk_init(void) for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); clkp++) { - if (((*clkp)->flags & NEEDS_INITIALIZATION) - && ((*clkp)->set_rate)) { - (*clkp)->user_rate = (*clkp)->rate; - local_set_rate((*clkp), (*clkp)->user_rate); - if ((*clkp)->set_parent) - (*clkp)->set_parent((*clkp), (*clkp)->parent); + struct clk *clk = *clkp; + if (clk->flags & NEEDS_INITIALIZATION) { + if (clk->set_rate) { + clk->user_rate = clk->rate; + local_set_rate(clk, clk->user_rate); + if (clk->set_parent) + clk->set_parent(clk, clk->parent); + } + if (clk->enable && clk->usecount) + clk->enable(clk); + if (clk->disable && !clk->usecount) + clk->disable(clk); } pr_debug("%s: clock %s, rate %ld\n", - __func__, (*clkp)->name, (*clkp)->rate); + __func__, clk->name, clk->rate); } local_clk_enable(&ck_pll4); diff --git a/arch/arm/mach-pnx4008/clock.h b/arch/arm/mach-pnx4008/clock.h index 933e18133b96..39720d6c0d01 100644 --- a/arch/arm/mach-pnx4008/clock.h +++ b/arch/arm/mach-pnx4008/clock.h @@ -27,9 +27,11 @@ struct clk { u8 enable_shift1; u32 enable_reg1; u32 parent_switch_reg; - u32(*round_rate) (struct clk *, u32); + u32(*round_rate) (struct clk *, u32); int (*set_rate) (struct clk *, u32); int (*set_parent) (struct clk * clk, struct clk * parent); + int (*enable)(struct clk *); + void (*disable)(struct clk *); }; /* Flags */ -- GitLab From 9bb787f435c86ffed079b66efa3ef6a8c577568c Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 13:07:28 +0000 Subject: [PATCH 1945/3892] ARM: PNX4008: convert watchdog clocks to match by device only Acked-by: Wim Van Sebroeck Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 2 +- drivers/watchdog/pnx4008_wdt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 3ad694e15968..e5140237fb15 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -806,7 +806,7 @@ static struct clk_lookup onchip_clkreg[] = { { .clk = &uart4_ck, .con_id = "uart4_ck" }, { .clk = &uart5_ck, .con_id = "uart5_ck" }, { .clk = &uart6_ck, .con_id = "uart6_ck" }, - { .clk = &wdt_ck, .con_id = "wdt_ck" }, + { .clk = &wdt_ck, .dev_id = "pnx4008-watchdog" }, }; static void local_clk_disable(struct clk *clk) diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 430a5848a9a5..8c5367fc4e50 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -273,7 +273,7 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) } wdt_base = (void __iomem *)IO_ADDRESS(res->start); - wdt_clk = clk_get(&pdev->dev, "wdt_ck"); + wdt_clk = clk_get(&pdev->dev, NULL); if (IS_ERR(wdt_clk)) { ret = PTR_ERR(wdt_clk); release_resource(wdt_mem); -- GitLab From 24fd1edaac79fe9554c557f9f93b3197c136c236 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 13:04:14 +0000 Subject: [PATCH 1946/3892] ARM: PNX4008: convert watchdog to use clk API enable/disable calls clk_set_rate() is not supposed to be used to turn clocks on and off. That's what clk_enable/clk_disable is for. Acked-by: Wim Van Sebroeck Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 4 ++-- drivers/watchdog/pnx4008_wdt.c | 37 ++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index e5140237fb15..944ffa94d325 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -740,10 +740,10 @@ static struct clk wdt_ck = { .name = "wdt_ck", .parent = &per_ck, .flags = NEEDS_INITIALIZATION, - .round_rate = &on_off_round_rate, - .set_rate = &on_off_set_rate, .enable_shift = 0, .enable_reg = TIMCLKCTRL_REG, + .enable = clk_reg_enable, + .disable = clk_reg_disable, }; /* These clocks are visible outside this module diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 8c5367fc4e50..c7a9479934af 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -96,9 +96,6 @@ static void wdt_enable(void) { spin_lock(&io_lock); - if (wdt_clk) - clk_set_rate(wdt_clk, 1); - /* stop counter, initiate counter reset */ __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base)); /*wait for reset to complete. 100% guarantee event */ @@ -125,19 +122,25 @@ static void wdt_disable(void) spin_lock(&io_lock); __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */ - if (wdt_clk) - clk_set_rate(wdt_clk, 0); spin_unlock(&io_lock); } static int pnx4008_wdt_open(struct inode *inode, struct file *file) { + int ret; + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) return -EBUSY; clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + ret = clk_enable(wdt_clk); + if (ret) { + clear_bit(WDT_IN_USE, &wdt_status); + return ret; + } + wdt_enable(); return nonseekable_open(inode, file); @@ -225,6 +228,7 @@ static int pnx4008_wdt_release(struct inode *inode, struct file *file) printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n"); wdt_disable(); + clk_disable(wdt_clk); clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status); @@ -279,19 +283,27 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) release_resource(wdt_mem); kfree(wdt_mem); goto out; - } else - clk_set_rate(wdt_clk, 1); + } + + ret = clk_enable(wdt_clk); + if (ret) { + release_resource(wdt_mem); + kfree(wdt_mem); + goto out; + } ret = misc_register(&pnx4008_wdt_miscdev); if (ret < 0) { printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); release_resource(wdt_mem); kfree(wdt_mem); - clk_set_rate(wdt_clk, 0); + clk_disable(wdt_clk); + clk_put(wdt_clk); } else { boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? WDIOF_CARDRESET : 0; wdt_disable(); /*disable for now */ + clk_disable(wdt_clk); set_bit(WDT_DEVICE_INITED, &wdt_status); } @@ -302,11 +314,10 @@ out: static int __devexit pnx4008_wdt_remove(struct platform_device *pdev) { misc_deregister(&pnx4008_wdt_miscdev); - if (wdt_clk) { - clk_set_rate(wdt_clk, 0); - clk_put(wdt_clk); - wdt_clk = NULL; - } + + clk_disable(wdt_clk); + clk_put(wdt_clk); + if (wdt_mem) { release_resource(wdt_mem); kfree(wdt_mem); -- GitLab From bba2be480b981bc1e7bea24c2a2552b0ad7e9774 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 10:46:24 +0000 Subject: [PATCH 1947/3892] ARM: PNX4008: convert i2c clocks to match by device only Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 6 +++--- arch/arm/mach-pnx4008/i2c.c | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 944ffa94d325..5a1515210969 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -797,9 +797,9 @@ static struct clk_lookup onchip_clkreg[] = { { .clk = &jpeg_ck, .con_id = "jpeg_ck" }, { .clk = &ms_ck, .con_id = "ms_ck" }, { .clk = &touch_ck, .con_id = "touch_ck" }, - { .clk = &i2c0_ck, .con_id = "i2c0_ck" }, - { .clk = &i2c1_ck, .con_id = "i2c1_ck" }, - { .clk = &i2c2_ck, .con_id = "i2c2_ck" }, + { .clk = &i2c0_ck, .dev_id = "pnx-i2c.0" }, + { .clk = &i2c1_ck, .dev_id = "pnx-i2c.1" }, + { .clk = &i2c2_ck, .dev_id = "pnx-i2c.2" }, { .clk = &spi0_ck, .con_id = "spi0_ck" }, { .clk = &spi1_ck, .con_id = "spi1_ck" }, { .clk = &uart3_ck, .con_id = "uart3_ck" }, diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index f3fea29c00d3..c986b3a61311 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -21,11 +21,9 @@ static int set_clock_run(struct platform_device *pdev) { struct clk *clk; - char name[10]; int retval = 0; - snprintf(name, 10, "i2c%d_ck", pdev->id); - clk = clk_get(&pdev->dev, name); + clk = clk_get(&pdev->dev, NULL); if (!IS_ERR(clk)) { clk_set_rate(clk, 1); clk_put(clk); @@ -38,11 +36,9 @@ static int set_clock_run(struct platform_device *pdev) static int set_clock_stop(struct platform_device *pdev) { struct clk *clk; - char name[10]; int retval = 0; - snprintf(name, 10, "i2c%d_ck", pdev->id); - clk = clk_get(&pdev->dev, name); + clk = clk_get(&pdev->dev, NULL); if (!IS_ERR(clk)) { clk_set_rate(clk, 0); clk_put(clk); -- GitLab From a0dcf19f59d4f37150a6b7e115925d72aca15293 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 10:50:34 +0000 Subject: [PATCH 1948/3892] ARM: PNX4008: move i2c suspend/resume callbacks into driver Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/i2c.c | 24 ------------------------ drivers/i2c/busses/i2c-pnx.c | 9 +++++++-- include/linux/i2c-pnx.h | 4 ---- 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index c986b3a61311..707d819f1280 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -48,24 +48,6 @@ static int set_clock_stop(struct platform_device *pdev) return retval; } -static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state) -{ - int retval = 0; -#ifdef CONFIG_PM - retval = set_clock_run(pdev); -#endif - return retval; -} - -static int i2c_pnx_resume(struct platform_device *pdev) -{ - int retval = 0; -#ifdef CONFIG_PM - retval = set_clock_run(pdev); -#endif - return retval; -} - static u32 calculate_input_freq(struct platform_device *pdev) { return HCLK_MHZ; @@ -102,8 +84,6 @@ static struct i2c_adapter pnx_adapter2 = { }; static struct i2c_pnx_data i2c0_data = { - .suspend = i2c_pnx_suspend, - .resume = i2c_pnx_resume, .calculate_input_freq = calculate_input_freq, .set_clock_run = set_clock_run, .set_clock_stop = set_clock_stop, @@ -111,8 +91,6 @@ static struct i2c_pnx_data i2c0_data = { }; static struct i2c_pnx_data i2c1_data = { - .suspend = i2c_pnx_suspend, - .resume = i2c_pnx_resume, .calculate_input_freq = calculate_input_freq, .set_clock_run = set_clock_run, .set_clock_stop = set_clock_stop, @@ -120,8 +98,6 @@ static struct i2c_pnx_data i2c1_data = { }; static struct i2c_pnx_data i2c2_data = { - .suspend = i2c_pnx_suspend, - .resume = i2c_pnx_resume, .calculate_input_freq = calculate_input_freq, .set_clock_run = set_clock_run, .set_clock_stop = set_clock_stop, diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 5d1c2603a130..bc8075514e53 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -545,18 +545,23 @@ static struct i2c_algorithm pnx_algorithm = { .functionality = i2c_pnx_func, }; +#ifdef CONFIG_PM static int i2c_pnx_controller_suspend(struct platform_device *pdev, pm_message_t state) { struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->suspend(pdev, state); + return i2c_pnx->set_clock_run(pdev); } static int i2c_pnx_controller_resume(struct platform_device *pdev) { struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->resume(pdev); + return i2c_pnx->set_clock_run(pdev); } +#else +#define i2c_pnx_controller_suspend NULL +#define i2c_pnx_controller_resume NULL +#endif static int __devinit i2c_pnx_probe(struct platform_device *pdev) { diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 9eb07bbc6522..71de7f976adf 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -12,8 +12,6 @@ #ifndef __I2C_PNX_H__ #define __I2C_PNX_H__ -#include - struct platform_device; struct i2c_pnx_mif { @@ -34,8 +32,6 @@ struct i2c_pnx_algo_data { }; struct i2c_pnx_data { - int (*suspend) (struct platform_device *pdev, pm_message_t state); - int (*resume) (struct platform_device *pdev); u32 (*calculate_input_freq) (struct platform_device *pdev); int (*set_clock_run) (struct platform_device *pdev); int (*set_clock_stop) (struct platform_device *pdev); -- GitLab From 0321cb83e1c3f3a4282bd620c6cec78c5b80b572 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 11:12:26 +0000 Subject: [PATCH 1949/3892] ARM: PNX4008: move i2c clock start/stop into driver Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/i2c.c | 36 --------------------------------- drivers/i2c/busses/i2c-pnx.c | 39 +++++++++++++++++++++++++++--------- include/linux/i2c-pnx.h | 4 ++-- 3 files changed, 32 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index 707d819f1280..14b4906bec2f 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -18,36 +18,6 @@ #include #include -static int set_clock_run(struct platform_device *pdev) -{ - struct clk *clk; - int retval = 0; - - clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 1); - clk_put(clk); - } else - retval = -ENOENT; - - return retval; -} - -static int set_clock_stop(struct platform_device *pdev) -{ - struct clk *clk; - int retval = 0; - - clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 0); - clk_put(clk); - } else - retval = -ENOENT; - - return retval; -} - static u32 calculate_input_freq(struct platform_device *pdev) { return HCLK_MHZ; @@ -85,22 +55,16 @@ static struct i2c_adapter pnx_adapter2 = { static struct i2c_pnx_data i2c0_data = { .calculate_input_freq = calculate_input_freq, - .set_clock_run = set_clock_run, - .set_clock_stop = set_clock_stop, .adapter = &pnx_adapter0, }; static struct i2c_pnx_data i2c1_data = { .calculate_input_freq = calculate_input_freq, - .set_clock_run = set_clock_run, - .set_clock_stop = set_clock_stop, .adapter = &pnx_adapter1, }; static struct i2c_pnx_data i2c2_data = { .calculate_input_freq = calculate_input_freq, - .set_clock_run = set_clock_run, - .set_clock_stop = set_clock_stop, .adapter = &pnx_adapter2, }; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index bc8075514e53..98462671cdf7 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -20,6 +20,9 @@ #include #include #include +#include +#include + #include #include #include @@ -550,13 +553,22 @@ static int i2c_pnx_controller_suspend(struct platform_device *pdev, pm_message_t state) { struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->set_clock_run(pdev); + struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; + + /* FIXME: disable clock? */ + clk_set_rate(alg_data->clk, 1); + + return 0; } static int i2c_pnx_controller_resume(struct platform_device *pdev) { struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->set_clock_run(pdev); + struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; + + clk_set_rate(alg_data->clk, 1); + + return 0; } #else #define i2c_pnx_controller_suspend NULL @@ -580,6 +592,15 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c_pnx); + i2c_pnx->adapter->algo = &pnx_algorithm; + alg_data = i2c_pnx->adapter->algo_data; + + alg_data->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(alg_data->clk)) { + ret = PTR_ERR(alg_data->clk); + goto out_drvdata; + } + if (i2c_pnx->calculate_input_freq) freq_mhz = i2c_pnx->calculate_input_freq(pdev); else { @@ -588,9 +609,6 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) "%d MHz\n", freq_mhz); } - i2c_pnx->adapter->algo = &pnx_algorithm; - - alg_data = i2c_pnx->adapter->algo_data; init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; @@ -602,7 +620,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) "I/O region 0x%08x for I2C already in use.\n", alg_data->base); ret = -ENODEV; - goto out_drvdata; + goto out_clkget; } if (!(alg_data->ioaddr = @@ -612,7 +630,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out_release; } - i2c_pnx->set_clock_run(pdev); + clk_set_rate(alg_data->clk, 1); /* * Clock Divisor High This value is the number of system clocks @@ -658,11 +676,13 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) out_irq: free_irq(alg_data->irq, i2c_pnx->adapter); out_clock: - i2c_pnx->set_clock_stop(pdev); + clk_set_rate(alg_data->clk, 0); out_unmap: iounmap((void *)alg_data->ioaddr); out_release: release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); +out_clkget: + clk_put(alg_data->clk); out_drvdata: platform_set_drvdata(pdev, NULL); out: @@ -677,9 +697,10 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) free_irq(alg_data->irq, i2c_pnx->adapter); i2c_del_adapter(adap); - i2c_pnx->set_clock_stop(pdev); + clk_set_rate(alg_data->clk, 0); iounmap((void *)alg_data->ioaddr); release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); + clk_put(alg_data->clk); platform_set_drvdata(pdev, NULL); return 0; diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 71de7f976adf..688e29262a43 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -13,6 +13,7 @@ #define __I2C_PNX_H__ struct platform_device; +struct clk; struct i2c_pnx_mif { int ret; /* Return value */ @@ -29,12 +30,11 @@ struct i2c_pnx_algo_data { int irq; struct i2c_pnx_mif mif; int last; + struct clk *clk; }; struct i2c_pnx_data { u32 (*calculate_input_freq) (struct platform_device *pdev); - int (*set_clock_run) (struct platform_device *pdev); - int (*set_clock_stop) (struct platform_device *pdev); struct i2c_adapter *adapter; }; -- GitLab From ebdbbf2003ae2342147c87c2a6c6ed8984b9cede Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 11:44:46 +0000 Subject: [PATCH 1950/3892] ARM: PNX4008: convert i2c-pnx to use clk API enable/disable calls clk_set_rate() is not supposed to be used to turn clocks on and off. That's what clk_enable/clk_disable is for. Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 12 ++++++------ drivers/i2c/busses/i2c-pnx.c | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 5a1515210969..692625cd2001 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -639,30 +639,30 @@ static struct clk i2c0_ck = { .name = "i2c0_ck", .parent = &per_ck, .flags = NEEDS_INITIALIZATION, - .round_rate = &on_off_round_rate, - .set_rate = &on_off_set_rate, .enable_shift = 0, .enable_reg = I2CCLKCTRL_REG, + .enable = clk_reg_enable, + .disable = clk_reg_disable, }; static struct clk i2c1_ck = { .name = "i2c1_ck", .parent = &per_ck, .flags = NEEDS_INITIALIZATION, - .round_rate = &on_off_round_rate, - .set_rate = &on_off_set_rate, .enable_shift = 1, .enable_reg = I2CCLKCTRL_REG, + .enable = clk_reg_enable, + .disable = clk_reg_disable, }; static struct clk i2c2_ck = { .name = "i2c2_ck", .parent = &per_ck, .flags = NEEDS_INITIALIZATION, - .round_rate = &on_off_round_rate, - .set_rate = &on_off_set_rate, .enable_shift = 2, .enable_reg = USB_OTG_CLKCTRL_REG, + .enable = clk_reg_enable, + .disable = clk_reg_disable, }; static struct clk spi0_ck = { diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 98462671cdf7..29f91774c4df 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -555,8 +555,8 @@ static int i2c_pnx_controller_suspend(struct platform_device *pdev, struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; - /* FIXME: disable clock? */ - clk_set_rate(alg_data->clk, 1); + /* FIXME: shouldn't this be clk_disable? */ + clk_enable(alg_data->clk); return 0; } @@ -566,9 +566,7 @@ static int i2c_pnx_controller_resume(struct platform_device *pdev) struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; - clk_set_rate(alg_data->clk, 1); - - return 0; + return clk_enable(alg_data->clk); } #else #define i2c_pnx_controller_suspend NULL @@ -630,7 +628,9 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out_release; } - clk_set_rate(alg_data->clk, 1); + ret = clk_enable(alg_data->clk); + if (ret) + goto out_unmap; /* * Clock Divisor High This value is the number of system clocks @@ -650,7 +650,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { ret = -ENODEV; - goto out_unmap; + goto out_clock; } init_completion(&alg_data->mif.complete); @@ -676,7 +676,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) out_irq: free_irq(alg_data->irq, i2c_pnx->adapter); out_clock: - clk_set_rate(alg_data->clk, 0); + clk_disable(alg_data->clk); out_unmap: iounmap((void *)alg_data->ioaddr); out_release: @@ -697,7 +697,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) free_irq(alg_data->irq, i2c_pnx->adapter); i2c_del_adapter(adap); - clk_set_rate(alg_data->clk, 0); + clk_disable(alg_data->clk); iounmap((void *)alg_data->ioaddr); release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); clk_put(alg_data->clk); -- GitLab From 6fff3da998ac3cc9ed8a84bf4f19911bd63c8c32 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Nov 2009 12:46:07 +0000 Subject: [PATCH 1951/3892] ARM: PNX4008: get i2c clock rate from clk API Acked-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/clock.c | 9 ++++++--- arch/arm/mach-pnx4008/i2c.c | 9 --------- drivers/i2c/busses/i2c-pnx.c | 15 ++++----------- include/linux/i2c-pnx.h | 1 - 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 692625cd2001..9d1975fa4d9f 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -638,9 +638,10 @@ static struct clk flash_ck = { static struct clk i2c0_ck = { .name = "i2c0_ck", .parent = &per_ck, - .flags = NEEDS_INITIALIZATION, + .flags = NEEDS_INITIALIZATION | FIXED_RATE, .enable_shift = 0, .enable_reg = I2CCLKCTRL_REG, + .rate = 13000000, .enable = clk_reg_enable, .disable = clk_reg_disable, }; @@ -648,9 +649,10 @@ static struct clk i2c0_ck = { static struct clk i2c1_ck = { .name = "i2c1_ck", .parent = &per_ck, - .flags = NEEDS_INITIALIZATION, + .flags = NEEDS_INITIALIZATION | FIXED_RATE, .enable_shift = 1, .enable_reg = I2CCLKCTRL_REG, + .rate = 13000000, .enable = clk_reg_enable, .disable = clk_reg_disable, }; @@ -658,9 +660,10 @@ static struct clk i2c1_ck = { static struct clk i2c2_ck = { .name = "i2c2_ck", .parent = &per_ck, - .flags = NEEDS_INITIALIZATION, + .flags = NEEDS_INITIALIZATION | FIXED_RATE, .enable_shift = 2, .enable_reg = USB_OTG_CLKCTRL_REG, + .rate = 13000000, .enable = clk_reg_enable, .disable = clk_reg_disable, }; diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index 14b4906bec2f..23ec335a4bc0 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -18,12 +18,6 @@ #include #include -static u32 calculate_input_freq(struct platform_device *pdev) -{ - return HCLK_MHZ; -} - - static struct i2c_pnx_algo_data pnx_algo_data0 = { .base = PNX4008_I2C1_BASE, .irq = I2C_1_INT, @@ -54,17 +48,14 @@ static struct i2c_adapter pnx_adapter2 = { }; static struct i2c_pnx_data i2c0_data = { - .calculate_input_freq = calculate_input_freq, .adapter = &pnx_adapter0, }; static struct i2c_pnx_data i2c1_data = { - .calculate_input_freq = calculate_input_freq, .adapter = &pnx_adapter1, }; static struct i2c_pnx_data i2c2_data = { - .calculate_input_freq = calculate_input_freq, .adapter = &pnx_adapter2, }; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 29f91774c4df..bfcd079e885c 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -31,7 +31,6 @@ #define I2C_PNX_TIMEOUT 10 /* msec */ #define I2C_PNX_SPEED_KHZ 100 #define I2C_PNX_REGION_SIZE 0x100 -#define PNX_DEFAULT_FREQ 13 /* MHz */ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) { @@ -578,7 +577,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) unsigned long tmp; int ret = 0; struct i2c_pnx_algo_data *alg_data; - int freq_mhz; + unsigned long freq; struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; if (!i2c_pnx || !i2c_pnx->adapter) { @@ -599,14 +598,6 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out_drvdata; } - if (i2c_pnx->calculate_input_freq) - freq_mhz = i2c_pnx->calculate_input_freq(pdev); - else { - freq_mhz = PNX_DEFAULT_FREQ; - dev_info(&pdev->dev, "Setting bus frequency to default value: " - "%d MHz\n", freq_mhz); - } - init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; @@ -632,6 +623,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) if (ret) goto out_unmap; + freq = clk_get_rate(alg_data->clk); + /* * Clock Divisor High This value is the number of system clocks * the serial clock (SCL) will be high. @@ -643,7 +636,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) * the deglitching filter length. */ - tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; iowrite32(tmp, I2C_REG_CKH(alg_data)); iowrite32(tmp, I2C_REG_CKL(alg_data)); diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 688e29262a43..9035711cb3b1 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -34,7 +34,6 @@ struct i2c_pnx_algo_data { }; struct i2c_pnx_data { - u32 (*calculate_input_freq) (struct platform_device *pdev); struct i2c_adapter *adapter; }; -- GitLab From 2781681ea6629ac0a685f5afe2011f916ab3c8ba Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 11:43:33 +0000 Subject: [PATCH 1952/3892] ARM: PNX4008: remove platform definitions from mach/timex.h mach/timex.h is only supposed to contain a definition for CLOCK_TICK_RATE. Remove additional includes, and move private definitions to a private header file. Signed-off-by: Russell King --- arch/arm/mach-pnx4008/include/mach/timex.h | 54 ----------------- arch/arm/mach-pnx4008/pm.c | 2 + arch/arm/mach-pnx4008/time.c | 2 + arch/arm/mach-pnx4008/time.h | 70 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 54 deletions(-) create mode 100644 arch/arm/mach-pnx4008/time.h diff --git a/arch/arm/mach-pnx4008/include/mach/timex.h b/arch/arm/mach-pnx4008/include/mach/timex.h index 5ff0196c0f16..b383c7de7ab4 100644 --- a/arch/arm/mach-pnx4008/include/mach/timex.h +++ b/arch/arm/mach-pnx4008/include/mach/timex.h @@ -14,60 +14,6 @@ #ifndef __PNX4008_TIMEX_H #define __PNX4008_TIMEX_H -#include -#include - #define CLOCK_TICK_RATE 1000000 -#define TICKS2USECS(x) (x) - -/* MilliSecond Timer - Chapter 21 Page 202 */ - -#define MSTIM_INT IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0)) -#define MSTIM_CTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4)) -#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8)) -#define MSTIM_MCTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14)) -#define MSTIM_MATCH0 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18)) -#define MSTIM_MATCH1 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c)) - -/* High Speed Timer - Chpater 22, Page 205 */ - -#define HSTIM_INT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0)) -#define HSTIM_CTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4)) -#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8)) -#define HSTIM_PMATCH IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC)) -#define HSTIM_PCOUNT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10)) -#define HSTIM_MCTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14)) -#define HSTIM_MATCH0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18)) -#define HSTIM_MATCH1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c)) -#define HSTIM_MATCH2 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20)) -#define HSTIM_CCR IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28)) -#define HSTIM_CR0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C)) -#define HSTIM_CR1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30)) - -/* IMPORTANT: both timers are UPCOUNTING */ - -/* xSTIM_MCTRL bit definitions */ -#define MR0_INT 1 -#define RESET_COUNT0 (1<<1) -#define STOP_COUNT0 (1<<2) -#define MR1_INT (1<<3) -#define RESET_COUNT1 (1<<4) -#define STOP_COUNT1 (1<<5) -#define MR2_INT (1<<6) -#define RESET_COUNT2 (1<<7) -#define STOP_COUNT2 (1<<8) - -/* xSTIM_CTRL bit definitions */ -#define COUNT_ENAB 1 -#define RESET_COUNT (1<<1) -#define DEBUG_EN (1<<2) - -/* xSTIM_INT bit definitions */ -#define MATCH0_INT 1 -#define MATCH1_INT (1<<1) -#define MATCH2_INT (1<<2) -#define RTC_TICK0 (1<<4) -#define RTC_TICK1 (1<<5) - #endif diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c index b3d8d53e32ef..1f0585329be4 100644 --- a/arch/arm/mach-pnx4008/pm.c +++ b/arch/arm/mach-pnx4008/pm.c @@ -21,6 +21,8 @@ #include #include + +#include #include #include diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c index fc0ba183fe12..0c8aad4bb0dc 100644 --- a/arch/arm/mach-pnx4008/time.c +++ b/arch/arm/mach-pnx4008/time.c @@ -30,6 +30,8 @@ #include #include +#include "time.h" + /*! Note: all timers are UPCOUNTING */ /*! diff --git a/arch/arm/mach-pnx4008/time.h b/arch/arm/mach-pnx4008/time.h new file mode 100644 index 000000000000..75e88c570aa7 --- /dev/null +++ b/arch/arm/mach-pnx4008/time.h @@ -0,0 +1,70 @@ +/* + * arch/arm/mach-pnx4008/include/mach/timex.h + * + * PNX4008 timers header file + * + * Author: Dmitry Chigirev + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef PNX_TIME_H +#define PNX_TIME_H + +#include +#include + +#define TICKS2USECS(x) (x) + +/* MilliSecond Timer - Chapter 21 Page 202 */ + +#define MSTIM_INT IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0)) +#define MSTIM_CTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4)) +#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8)) +#define MSTIM_MCTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14)) +#define MSTIM_MATCH0 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18)) +#define MSTIM_MATCH1 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c)) + +/* High Speed Timer - Chpater 22, Page 205 */ + +#define HSTIM_INT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0)) +#define HSTIM_CTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4)) +#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8)) +#define HSTIM_PMATCH IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC)) +#define HSTIM_PCOUNT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10)) +#define HSTIM_MCTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14)) +#define HSTIM_MATCH0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18)) +#define HSTIM_MATCH1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c)) +#define HSTIM_MATCH2 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20)) +#define HSTIM_CCR IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28)) +#define HSTIM_CR0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C)) +#define HSTIM_CR1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30)) + +/* IMPORTANT: both timers are UPCOUNTING */ + +/* xSTIM_MCTRL bit definitions */ +#define MR0_INT 1 +#define RESET_COUNT0 (1<<1) +#define STOP_COUNT0 (1<<2) +#define MR1_INT (1<<3) +#define RESET_COUNT1 (1<<4) +#define STOP_COUNT1 (1<<5) +#define MR2_INT (1<<6) +#define RESET_COUNT2 (1<<7) +#define STOP_COUNT2 (1<<8) + +/* xSTIM_CTRL bit definitions */ +#define COUNT_ENAB 1 +#define RESET_COUNT (1<<1) +#define DEBUG_EN (1<<2) + +/* xSTIM_INT bit definitions */ +#define MATCH0_INT 1 +#define MATCH1_INT (1<<1) +#define MATCH2_INT (1<<2) +#define RTC_TICK0 (1<<4) +#define RTC_TICK1 (1<<5) + +#endif -- GitLab From 88d968b22fa26d5e3a8cab46fc7c3a21c89a91d3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 11:58:36 +0000 Subject: [PATCH 1953/3892] ARM: PNX4008: Make ioaddr 'void __iomem *' rather than 'u32' This avoids unnecessary casting. Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pnx.c | 8 ++++---- include/linux/i2c-pnx.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index bfcd079e885c..882579e64111 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -612,8 +612,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out_clkget; } - if (!(alg_data->ioaddr = - (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) { + alg_data->ioaddr = ioremap(alg_data->base, I2C_PNX_REGION_SIZE); + if (!alg_data->ioaddr) { dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); ret = -ENOMEM; goto out_release; @@ -671,7 +671,7 @@ out_irq: out_clock: clk_disable(alg_data->clk); out_unmap: - iounmap((void *)alg_data->ioaddr); + iounmap(alg_data->ioaddr); out_release: release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); out_clkget: @@ -691,7 +691,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) free_irq(alg_data->irq, i2c_pnx->adapter); i2c_del_adapter(adap); clk_disable(alg_data->clk); - iounmap((void *)alg_data->ioaddr); + iounmap(alg_data->ioaddr); release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); clk_put(alg_data->clk); platform_set_drvdata(pdev, NULL); diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 9035711cb3b1..5a48f33046fb 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -26,7 +26,7 @@ struct i2c_pnx_mif { struct i2c_pnx_algo_data { u32 base; - u32 ioaddr; + void __iomem *ioaddr; int irq; struct i2c_pnx_mif mif; int last; -- GitLab From 44c5d739181886cff8e3903dfa38cd704f3d9640 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:10:54 +0000 Subject: [PATCH 1954/3892] ARM: PNX4008: kzalloc i2c drivers internal data Signed-off-by: Russell King --- arch/arm/mach-pnx4008/i2c.c | 25 +++++++------------------ drivers/i2c/busses/i2c-pnx.c | 29 +++++++++++++++++++---------- include/linux/i2c-pnx.h | 4 ++-- 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index 23ec335a4bc0..33146e832dd7 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -18,45 +18,34 @@ #include #include -static struct i2c_pnx_algo_data pnx_algo_data0 = { - .base = PNX4008_I2C1_BASE, - .irq = I2C_1_INT, -}; - -static struct i2c_pnx_algo_data pnx_algo_data1 = { - .base = PNX4008_I2C2_BASE, - .irq = I2C_2_INT, -}; - -static struct i2c_pnx_algo_data pnx_algo_data2 = { - .base = (PNX4008_USB_CONFIG_BASE + 0x300), - .irq = USB_I2C_INT, -}; - static struct i2c_adapter pnx_adapter0 = { .name = I2C_CHIP_NAME "0", - .algo_data = &pnx_algo_data0, }; + static struct i2c_adapter pnx_adapter1 = { .name = I2C_CHIP_NAME "1", - .algo_data = &pnx_algo_data1, }; static struct i2c_adapter pnx_adapter2 = { .name = "USB-I2C", - .algo_data = &pnx_algo_data2, }; static struct i2c_pnx_data i2c0_data = { .adapter = &pnx_adapter0, + .base = PNX4008_I2C1_BASE, + .irq = I2C_1_INT, }; static struct i2c_pnx_data i2c1_data = { .adapter = &pnx_adapter1, + .base = PNX4008_I2C2_BASE, + .irq = I2C_2_INT, }; static struct i2c_pnx_data i2c2_data = { .adapter = &pnx_adapter2, + .base = (PNX4008_USB_CONFIG_BASE + 0x300), + .irq = USB_I2C_INT, }; static struct platform_device i2c0_device = { diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 882579e64111..1d66856a22fd 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -587,10 +587,16 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out; } + alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); + if (!alg_data) { + ret = -ENOMEM; + goto err_kzalloc; + } + platform_set_drvdata(pdev, i2c_pnx); i2c_pnx->adapter->algo = &pnx_algorithm; - alg_data = i2c_pnx->adapter->algo_data; + i2c_pnx->adapter->algo_data = alg_data; alg_data->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(alg_data->clk)) { @@ -603,16 +609,16 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; /* Register I/O resource */ - if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE, + if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE, pdev->name)) { dev_err(&pdev->dev, "I/O region 0x%08x for I2C already in use.\n", - alg_data->base); + i2c_pnx->base); ret = -ENODEV; goto out_clkget; } - alg_data->ioaddr = ioremap(alg_data->base, I2C_PNX_REGION_SIZE); + alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE); if (!alg_data->ioaddr) { dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); ret = -ENOMEM; @@ -647,7 +653,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) } init_completion(&alg_data->mif.complete); - ret = request_irq(alg_data->irq, i2c_pnx_interrupt, + ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt, 0, pdev->name, i2c_pnx->adapter); if (ret) goto out_clock; @@ -662,21 +668,23 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", - i2c_pnx->adapter->name, alg_data->base, alg_data->irq); + i2c_pnx->adapter->name, i2c_pnx->base, i2c_pnx->irq); return 0; out_irq: - free_irq(alg_data->irq, i2c_pnx->adapter); + free_irq(i2c_pnx->irq, i2c_pnx->adapter); out_clock: clk_disable(alg_data->clk); out_unmap: iounmap(alg_data->ioaddr); out_release: - release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); + release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); out_clkget: clk_put(alg_data->clk); out_drvdata: + kfree(alg_data); +err_kzalloc: platform_set_drvdata(pdev, NULL); out: return ret; @@ -688,12 +696,13 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) struct i2c_adapter *adap = i2c_pnx->adapter; struct i2c_pnx_algo_data *alg_data = adap->algo_data; - free_irq(alg_data->irq, i2c_pnx->adapter); + free_irq(i2c_pnx->irq, i2c_pnx->adapter); i2c_del_adapter(adap); clk_disable(alg_data->clk); iounmap(alg_data->ioaddr); - release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); + release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); clk_put(alg_data->clk); + kfree(alg_data); platform_set_drvdata(pdev, NULL); return 0; diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 5a48f33046fb..9ebdf882d032 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -25,9 +25,7 @@ struct i2c_pnx_mif { }; struct i2c_pnx_algo_data { - u32 base; void __iomem *ioaddr; - int irq; struct i2c_pnx_mif mif; int last; struct clk *clk; @@ -35,6 +33,8 @@ struct i2c_pnx_algo_data { struct i2c_pnx_data { struct i2c_adapter *adapter; + u32 base; + int irq; }; #endif /* __I2C_PNX_H__ */ -- GitLab From 9d7f73632c87ef1b6187eb539d1efd63c3cf0e36 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:25:27 +0000 Subject: [PATCH 1955/3892] ARM: PNX4008: move i2c_adapter structure inside the drivers private data Signed-off-by: Russell King --- arch/arm/mach-pnx4008/i2c.c | 18 +++------------- drivers/i2c/busses/i2c-pnx.c | 40 ++++++++++++++++++------------------ include/linux/i2c-pnx.h | 4 +++- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index 33146e832dd7..8103f9644e2d 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -18,32 +18,20 @@ #include #include -static struct i2c_adapter pnx_adapter0 = { - .name = I2C_CHIP_NAME "0", -}; - -static struct i2c_adapter pnx_adapter1 = { - .name = I2C_CHIP_NAME "1", -}; - -static struct i2c_adapter pnx_adapter2 = { - .name = "USB-I2C", -}; - static struct i2c_pnx_data i2c0_data = { - .adapter = &pnx_adapter0, + .name = I2C_CHIP_NAME "0", .base = PNX4008_I2C1_BASE, .irq = I2C_1_INT, }; static struct i2c_pnx_data i2c1_data = { - .adapter = &pnx_adapter1, + .name = I2C_CHIP_NAME "1", .base = PNX4008_I2C2_BASE, .irq = I2C_2_INT, }; static struct i2c_pnx_data i2c2_data = { - .adapter = &pnx_adapter2, + .name = "USB-I2C", .base = (PNX4008_USB_CONFIG_BASE + 0x300), .irq = USB_I2C_INT, }; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 1d66856a22fd..6b413c5300d3 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -551,8 +551,7 @@ static struct i2c_algorithm pnx_algorithm = { static int i2c_pnx_controller_suspend(struct platform_device *pdev, pm_message_t state) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); /* FIXME: shouldn't this be clk_disable? */ clk_enable(alg_data->clk); @@ -562,8 +561,7 @@ static int i2c_pnx_controller_suspend(struct platform_device *pdev, static int i2c_pnx_controller_resume(struct platform_device *pdev) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - struct i2c_pnx_algo_data *alg_data = i2c_pnx->adapter->algo_data; + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); return clk_enable(alg_data->clk); } @@ -580,7 +578,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) unsigned long freq; struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; - if (!i2c_pnx || !i2c_pnx->adapter) { + if (!i2c_pnx || !i2c_pnx->name) { dev_err(&pdev->dev, "%s: no platform data supplied\n", __func__); ret = -EINVAL; @@ -593,10 +591,15 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto err_kzalloc; } - platform_set_drvdata(pdev, i2c_pnx); + platform_set_drvdata(pdev, alg_data); - i2c_pnx->adapter->algo = &pnx_algorithm; - i2c_pnx->adapter->algo_data = alg_data; + strlcpy(alg_data->adapter.name, i2c_pnx->name, + sizeof(alg_data->adapter.name)); + alg_data->adapter.dev.parent = &pdev->dev; + alg_data->adapter.algo = &pnx_algorithm; + alg_data->adapter.algo_data = alg_data; + alg_data->adapter.nr = pdev->id; + alg_data->i2c_pnx = i2c_pnx; alg_data->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(alg_data->clk)) { @@ -606,7 +609,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; - alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; + alg_data->mif.timer.data = (unsigned long)&alg_data->adapter; /* Register I/O resource */ if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE, @@ -654,26 +657,24 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) init_completion(&alg_data->mif.complete); ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt, - 0, pdev->name, i2c_pnx->adapter); + 0, pdev->name, &alg_data->adapter); if (ret) goto out_clock; /* Register this adapter with the I2C subsystem */ - i2c_pnx->adapter->dev.parent = &pdev->dev; - i2c_pnx->adapter->nr = pdev->id; - ret = i2c_add_numbered_adapter(i2c_pnx->adapter); + ret = i2c_add_numbered_adapter(&alg_data->adapter); if (ret < 0) { dev_err(&pdev->dev, "I2C: Failed to add bus\n"); goto out_irq; } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", - i2c_pnx->adapter->name, i2c_pnx->base, i2c_pnx->irq); + alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq); return 0; out_irq: - free_irq(i2c_pnx->irq, i2c_pnx->adapter); + free_irq(i2c_pnx->irq, &alg_data->adapter); out_clock: clk_disable(alg_data->clk); out_unmap: @@ -692,12 +693,11 @@ out: static int __devexit i2c_pnx_remove(struct platform_device *pdev) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - struct i2c_adapter *adap = i2c_pnx->adapter; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx; - free_irq(i2c_pnx->irq, i2c_pnx->adapter); - i2c_del_adapter(adap); + free_irq(i2c_pnx->irq, &alg_data->adapter); + i2c_del_adapter(&alg_data->adapter); clk_disable(alg_data->clk); iounmap(alg_data->ioaddr); release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 9ebdf882d032..a87124d4d533 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -29,10 +29,12 @@ struct i2c_pnx_algo_data { struct i2c_pnx_mif mif; int last; struct clk *clk; + struct i2c_pnx_data *i2c_pnx; + struct i2c_adapter adapter; }; struct i2c_pnx_data { - struct i2c_adapter *adapter; + const char *name; u32 base; int irq; }; -- GitLab From 81d6724a564fa5bd20b006eae0da4462d599bb92 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:40:00 +0000 Subject: [PATCH 1956/3892] ARM: PNX4008: Use i2c driver data for passing between internal functions Since the drivers data now contains the i2c adapter structure, we can pass around the drivers data between internal functions (which is what they want) rather than using the i2c adapter structure and having an additional pointer dereference each time. Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pnx.c | 132 ++++++++++++++++------------------- 1 file changed, 62 insertions(+), 70 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 6b413c5300d3..181e69211e4f 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -52,10 +52,9 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) return (timeout <= 0); } -static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) +static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *data = adap->algo_data; - struct timer_list *timer = &data->mif.timer; + struct timer_list *timer = &alg_data->mif.timer; int expires = I2C_PNX_TIMEOUT / (1000 / HZ); if (expires <= 1) @@ -63,11 +62,11 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) del_timer_sync(timer); - dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", + dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %u jiffies.\n", jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)adap; + timer->data = (unsigned long)&alg_data; add_timer(timer); } @@ -79,34 +78,33 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) * * Generate a START signal in the desired mode. */ -static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) +static int i2c_pnx_start(unsigned char slave_addr, + struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; - - dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__, slave_addr, alg_data->mif.mode); /* Check for 7 bit slave addresses only */ if (slave_addr & ~0x7f) { - dev_err(&adap->dev, "%s: Invalid slave address %x. " + dev_err(&alg_data->adapter.dev, "%s: Invalid slave address %x. " "Only 7-bit addresses are supported\n", - adap->name, slave_addr); + alg_data->adapter.name, slave_addr); return -EINVAL; } /* First, make sure bus is idle */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { /* Somebody else is monopolizing the bus */ - dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, " + dev_err(&alg_data->adapter.dev, "%s: Bus busy. Slave addr = %02x, " "cntrl = %x, stat = %x\n", - adap->name, slave_addr, + alg_data->adapter.name, slave_addr, ioread32(I2C_REG_CTL(alg_data)), ioread32(I2C_REG_STS(alg_data))); return -EBUSY; } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { /* Sorry, we lost the bus */ - dev_err(&adap->dev, "%s: Arbitration failure. " - "Slave addr = %02x\n", adap->name, slave_addr); + dev_err(&alg_data->adapter.dev, "%s: Arbitration failure. " + "Slave addr = %02x\n", alg_data->adapter.name, slave_addr); return -EIO; } @@ -117,14 +115,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__, (slave_addr << 1) | start_bit | alg_data->mif.mode); /* Write the slave address, START bit and R/W bit */ iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, I2C_REG_TX(alg_data)); - dev_dbg(&adap->dev, "%s(): exit\n", __func__); + dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__); return 0; } @@ -135,13 +133,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) * * Generate a STOP signal to terminate the master transaction. */ -static void i2c_pnx_stop(struct i2c_adapter *adap) +static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; /* Only 1 msec max timeout due to interrupt context */ long timeout = 1000; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); /* Write a STOP bit to TX FIFO */ @@ -155,7 +152,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap) timeout--; } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); } @@ -165,12 +162,11 @@ static void i2c_pnx_stop(struct i2c_adapter *adap) * * Sends one byte of data to the slave */ -static int i2c_pnx_master_xmit(struct i2c_adapter *adap) +static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 val; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); if (alg_data->mif.len > 0) { @@ -186,14 +182,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) alg_data->mif.len--; iowrite32(val, I2C_REG_TX(alg_data)); - dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n", __func__, val, alg_data->mif.len + 1); if (alg_data->mif.len == 0) { if (alg_data->last) { /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&adap->dev, "The bus is still " + dev_err(&alg_data->adapter.dev, "The bus is still " "active after timeout\n"); } /* Disable master interrupts */ @@ -203,14 +199,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) del_timer_sync(&alg_data->mif.timer); - dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine.\n", __func__); complete(&alg_data->mif.complete); } } else if (alg_data->mif.len == 0) { /* zero-sized transfer */ - i2c_pnx_stop(adap); + i2c_pnx_stop(alg_data); /* Disable master interrupts. */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) & @@ -219,13 +215,13 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) /* Stop timer. */ del_timer_sync(&alg_data->mif.timer); - dev_dbg(&adap->dev, "%s(): Waking up xfer routine after " + dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine after " "zero-xfer.\n", __func__); complete(&alg_data->mif.complete); } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); return 0; @@ -237,20 +233,19 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) * * Reads one byte data from the slave */ -static int i2c_pnx_master_rcv(struct i2c_adapter *adap) +static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; unsigned int val = 0; u32 ctl = 0; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); /* Check, whether there is already data, * or we didn't 'ask' for it yet. */ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { - dev_dbg(&adap->dev, "%s(): Write dummy data to fill " + dev_dbg(&alg_data->adapter.dev, "%s(): Write dummy data to fill " "Rx-fifo...\n", __func__); if (alg_data->mif.len == 1) { @@ -283,7 +278,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) if (alg_data->mif.len > 0) { val = ioread32(I2C_REG_RX(alg_data)); *alg_data->mif.buf++ = (u8) (val & 0xff); - dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val, + dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n", __func__, val, alg_data->mif.len); alg_data->mif.len--; @@ -291,7 +286,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) if (alg_data->last) /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&adap->dev, "The bus is still " + dev_err(&alg_data->adapter.dev, "The bus is still " "active after timeout\n"); /* Disable master interrupts */ @@ -306,7 +301,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) } } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); return 0; @@ -314,11 +309,10 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) { + struct i2c_pnx_algo_data *alg_data = dev_id; u32 stat, ctl; - struct i2c_adapter *adap = dev_id; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; - dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", + dev_dbg(&alg_data->adapter.dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data)), @@ -341,10 +335,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) complete(&alg_data->mif.complete); } else if (stat & mstatus_nai) { /* Slave did not acknowledge, generate a STOP */ - dev_dbg(&adap->dev, "%s(): " + dev_dbg(&alg_data->adapter.dev, "%s(): " "Slave did not acknowledge, generating a STOP.\n", __func__); - i2c_pnx_stop(adap); + i2c_pnx_stop(alg_data); /* Disable master interrupts. */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -370,9 +364,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) */ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { if (alg_data->mif.mode == I2C_SMBUS_WRITE) { - i2c_pnx_master_xmit(adap); + i2c_pnx_master_xmit(alg_data); } else if (alg_data->mif.mode == I2C_SMBUS_READ) { - i2c_pnx_master_rcv(adap); + i2c_pnx_master_rcv(alg_data); } } } @@ -381,7 +375,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) stat = ioread32(I2C_REG_STS(alg_data)); iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x ctrl = %x.\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data))); @@ -390,11 +384,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) static void i2c_pnx_timeout(unsigned long data) { - struct i2c_adapter *adap = (struct i2c_adapter *)data; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; + struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; u32 ctl; - dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. " + dev_err(&alg_data->adapter.dev, "Master timed out. stat = %04x, cntrl = %04x. " "Resetting master...\n", ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data))); @@ -411,15 +404,14 @@ static void i2c_pnx_timeout(unsigned long data) complete(&alg_data->mif.complete); } -static inline void bus_reset_if_active(struct i2c_adapter *adap) +static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat; if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { - dev_err(&adap->dev, + dev_err(&alg_data->adapter.dev, "%s: Bus is still active after xfer. Reset it...\n", - adap->name); + alg_data->adapter.name); iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); wait_reset(I2C_PNX_TIMEOUT, alg_data); @@ -453,10 +445,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat = ioread32(I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: %d messages, stat = %04x.\n", __func__, num, ioread32(I2C_REG_STS(alg_data))); - bus_reset_if_active(adap); + bus_reset_if_active(alg_data); /* Process transactions in a loop. */ for (i = 0; rc >= 0 && i < num; i++) { @@ -466,9 +458,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) addr = pmsg->addr; if (pmsg->flags & I2C_M_TEN) { - dev_err(&adap->dev, + dev_err(&alg_data->adapter.dev, "%s: 10 bits addr not supported!\n", - adap->name); + alg_data->adapter.name); rc = -EINVAL; break; } @@ -480,11 +472,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) alg_data->mif.ret = 0; alg_data->last = (i == num - 1); - dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", __func__, alg_data->mif.mode, alg_data->mif.len); - i2c_pnx_arm_timer(adap); + i2c_pnx_arm_timer(alg_data); /* initialize the completion var */ init_completion(&alg_data->mif.complete); @@ -495,7 +487,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) I2C_REG_CTL(alg_data)); /* Put start-code and slave-address on the bus. */ - rc = i2c_pnx_start(addr, adap); + rc = i2c_pnx_start(addr, alg_data); if (rc < 0) break; @@ -504,31 +496,31 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (!(rc = alg_data->mif.ret)) completed++; - dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): Complete, return code = %d.\n", __func__, rc); /* Clear TDI and AFI bits in case they are set. */ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { - dev_dbg(&adap->dev, + dev_dbg(&alg_data->adapter.dev, "%s: TDI still set... clearing now.\n", - adap->name); + alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { - dev_dbg(&adap->dev, + dev_dbg(&alg_data->adapter.dev, "%s: AFI still set... clearing now.\n", - adap->name); + alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } } - bus_reset_if_active(adap); + bus_reset_if_active(alg_data); /* Cleanup to be sure... */ alg_data->mif.buf = NULL; alg_data->mif.len = 0; - dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", __func__, ioread32(I2C_REG_STS(alg_data))); if (completed != num) @@ -609,7 +601,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; - alg_data->mif.timer.data = (unsigned long)&alg_data->adapter; + alg_data->mif.timer.data = (unsigned long)alg_data; /* Register I/O resource */ if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE, @@ -657,7 +649,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) init_completion(&alg_data->mif.complete); ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt, - 0, pdev->name, &alg_data->adapter); + 0, pdev->name, alg_data); if (ret) goto out_clock; @@ -674,7 +666,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) return 0; out_irq: - free_irq(i2c_pnx->irq, &alg_data->adapter); + free_irq(i2c_pnx->irq, alg_data); out_clock: clk_disable(alg_data->clk); out_unmap: @@ -696,7 +688,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx; - free_irq(i2c_pnx->irq, &alg_data->adapter); + free_irq(i2c_pnx->irq, alg_data); i2c_del_adapter(&alg_data->adapter); clk_disable(alg_data->clk); iounmap(alg_data->ioaddr); -- GitLab From 4be53dbe74818a12cc737a89b5d0aec6095956e0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:46:31 +0000 Subject: [PATCH 1957/3892] ARM: PNX4008: i2c-pnx: don't split messages across several lines It makes them harder to grep for. Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pnx.c | 81 ++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 181e69211e4f..afc9c968deec 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -86,25 +86,26 @@ static int i2c_pnx_start(unsigned char slave_addr, /* Check for 7 bit slave addresses only */ if (slave_addr & ~0x7f) { - dev_err(&alg_data->adapter.dev, "%s: Invalid slave address %x. " - "Only 7-bit addresses are supported\n", - alg_data->adapter.name, slave_addr); + dev_err(&alg_data->adapter.dev, + "%s: Invalid slave address %x. Only 7-bit addresses are supported\n", + alg_data->adapter.name, slave_addr); return -EINVAL; } /* First, make sure bus is idle */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { /* Somebody else is monopolizing the bus */ - dev_err(&alg_data->adapter.dev, "%s: Bus busy. Slave addr = %02x, " - "cntrl = %x, stat = %x\n", - alg_data->adapter.name, slave_addr, - ioread32(I2C_REG_CTL(alg_data)), - ioread32(I2C_REG_STS(alg_data))); + dev_err(&alg_data->adapter.dev, + "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", + alg_data->adapter.name, slave_addr, + ioread32(I2C_REG_CTL(alg_data)), + ioread32(I2C_REG_STS(alg_data))); return -EBUSY; } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { /* Sorry, we lost the bus */ - dev_err(&alg_data->adapter.dev, "%s: Arbitration failure. " - "Slave addr = %02x\n", alg_data->adapter.name, slave_addr); + dev_err(&alg_data->adapter.dev, + "%s: Arbitration failure. Slave addr = %02x\n", + alg_data->adapter.name, slave_addr); return -EIO; } @@ -182,15 +183,15 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) alg_data->mif.len--; iowrite32(val, I2C_REG_TX(alg_data)); - dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n", __func__, - val, alg_data->mif.len + 1); + dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n", + __func__, val, alg_data->mif.len + 1); if (alg_data->mif.len == 0) { if (alg_data->last) { /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&alg_data->adapter.dev, "The bus is still " - "active after timeout\n"); + dev_err(&alg_data->adapter.dev, + "The bus is still active after timeout\n"); } /* Disable master interrupts */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) & @@ -199,7 +200,8 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) del_timer_sync(&alg_data->mif.timer); - dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Waking up xfer routine.\n", __func__); complete(&alg_data->mif.complete); @@ -215,8 +217,9 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) /* Stop timer. */ del_timer_sync(&alg_data->mif.timer); - dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine after " - "zero-xfer.\n", __func__); + dev_dbg(&alg_data->adapter.dev, + "%s(): Waking up xfer routine after zero-xfer.\n", + __func__); complete(&alg_data->mif.complete); } @@ -245,8 +248,9 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) * or we didn't 'ask' for it yet. */ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { - dev_dbg(&alg_data->adapter.dev, "%s(): Write dummy data to fill " - "Rx-fifo...\n", __func__); + dev_dbg(&alg_data->adapter.dev, + "%s(): Write dummy data to fill Rx-fifo...\n", + __func__); if (alg_data->mif.len == 1) { /* Last byte, do not acknowledge next rcv. */ @@ -278,16 +282,16 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) if (alg_data->mif.len > 0) { val = ioread32(I2C_REG_RX(alg_data)); *alg_data->mif.buf++ = (u8) (val & 0xff); - dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n", __func__, val, - alg_data->mif.len); + dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n", + __func__, val, alg_data->mif.len); alg_data->mif.len--; if (alg_data->mif.len == 0) { if (alg_data->last) /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&alg_data->adapter.dev, "The bus is still " - "active after timeout\n"); + dev_err(&alg_data->adapter.dev, + "The bus is still active after timeout\n"); /* Disable master interrupts */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -312,7 +316,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) struct i2c_pnx_algo_data *alg_data = dev_id; u32 stat, ctl; - dev_dbg(&alg_data->adapter.dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): mstat = %x mctrl = %x, mode = %d\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data)), @@ -335,8 +340,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) complete(&alg_data->mif.complete); } else if (stat & mstatus_nai) { /* Slave did not acknowledge, generate a STOP */ - dev_dbg(&alg_data->adapter.dev, "%s(): " - "Slave did not acknowledge, generating a STOP.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Slave did not acknowledge, generating a STOP.\n", __func__); i2c_pnx_stop(alg_data); @@ -375,7 +380,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) stat = ioread32(I2C_REG_STS(alg_data)); iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); - dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x ctrl = %x.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): exiting, stat = %x ctrl = %x.\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data))); @@ -387,10 +393,10 @@ static void i2c_pnx_timeout(unsigned long data) struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; u32 ctl; - dev_err(&alg_data->adapter.dev, "Master timed out. stat = %04x, cntrl = %04x. " - "Resetting master...\n", - ioread32(I2C_REG_STS(alg_data)), - ioread32(I2C_REG_CTL(alg_data))); + dev_err(&alg_data->adapter.dev, + "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n", + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); /* Reset master and disable interrupts */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -411,7 +417,7 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { dev_err(&alg_data->adapter.dev, "%s: Bus is still active after xfer. Reset it...\n", - alg_data->adapter.name); + alg_data->adapter.name); iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); wait_reset(I2C_PNX_TIMEOUT, alg_data); @@ -445,7 +451,8 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat = ioread32(I2C_REG_STS(alg_data)); - dev_dbg(&alg_data->adapter.dev, "%s(): entering: %d messages, stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): entering: %d messages, stat = %04x.\n", __func__, num, ioread32(I2C_REG_STS(alg_data))); bus_reset_if_active(alg_data); @@ -472,9 +479,8 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) alg_data->mif.ret = 0; alg_data->last = (i == num - 1); - dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", __func__, - alg_data->mif.mode, - alg_data->mif.len); + dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", + __func__, alg_data->mif.mode, alg_data->mif.len); i2c_pnx_arm_timer(alg_data); @@ -496,7 +502,8 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (!(rc = alg_data->mif.ret)) completed++; - dev_dbg(&alg_data->adapter.dev, "%s(): Complete, return code = %d.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Complete, return code = %d.\n", __func__, rc); /* Clear TDI and AFI bits in case they are set. */ -- GitLab From 7e20c837208f6fdd553d04f5fe3e80f44570698b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:56:13 +0000 Subject: [PATCH 1958/3892] ARM: PNX4008: i2c-pnx makes no use of asm/uaccess.h nor asm/irq.h Remove unnecessary includes Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pnx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index afc9c968deec..ecdd5230ae36 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -25,8 +25,6 @@ #include #include -#include -#include #define I2C_PNX_TIMEOUT 10 /* msec */ #define I2C_PNX_SPEED_KHZ 100 -- GitLab From eed18b5fa4d297c681b00144e8c6942dd35d39a7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Nov 2009 12:58:13 +0000 Subject: [PATCH 1959/3892] ARM: PNX4008: use msecs_to_jiffies() rather than open-coding it Signed-off-by: Russell King --- drivers/i2c/busses/i2c-pnx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index ecdd5230ae36..2b0bd0b042d6 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -53,14 +53,14 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) { struct timer_list *timer = &alg_data->mif.timer; - int expires = I2C_PNX_TIMEOUT / (1000 / HZ); + unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT); if (expires <= 1) expires = 2; del_timer_sync(timer); - dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %u jiffies.\n", + dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", jiffies, expires); timer->expires = jiffies + expires; -- GitLab From 42c4568a4ace0adc27a9d6f02936e2047ba6fc7e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Feb 2010 18:07:19 +0100 Subject: [PATCH 1960/3892] ath9k: add a workaround for ack timeout issues Adding support for setting the coverage class in some cases broke association and data transfer, as it overwrote the initial ACK timeout value from the initvals with a smaller value. I don't know why the new value works in 5 GHz (matches the initval there), but not in 2.4 GHz (initvals use 64us here), so until the problem is fully understood, the value should be increased again. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f15fee76a4e2..f00f5c744f48 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1217,6 +1217,17 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) /* As defined by IEEE 802.11-2007 17.3.8.6 */ slottime = ah->slottime + 3 * ah->coverage_class; acktimeout = slottime + sifstime; + + /* + * Workaround for early ACK timeouts, add an offset to match the + * initval's 64us ack timeout value. + * This was initially only meant to work around an issue with delayed + * BA frames in some implementations, but it has been found to fix ACK + * timeout issues in other cases as well. + */ + if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) + acktimeout += 64 - sifstime - ah->slottime; + ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); ath9k_hw_set_cts_timeout(ah, acktimeout); -- GitLab From 4cd24eaf0c6ee7f0242e34ee77ec899f255e66b5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Feb 2010 04:30:35 +0000 Subject: [PATCH 1961/3892] net: use netdev_mc_count and netdev_mc_empty when appropriate This patch replaces dev->mc_count in all drivers (hopefully I didn't miss anything). Used spatch and did small tweaks and conding style changes when it was suitable. Jirka Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- arch/xtensa/platforms/iss/network.c | 2 +- drivers/infiniband/hw/nes/nes_nic.c | 2 +- drivers/media/dvb/dvb-core/dvb_net.c | 7 +++---- drivers/net/3c505.c | 6 +++--- drivers/net/3c509.c | 10 ++++++---- drivers/net/3c523.c | 4 ++-- drivers/net/3c527.c | 11 ++++++----- drivers/net/7990.c | 2 +- drivers/net/82596.c | 8 ++++---- drivers/net/a2065.c | 2 +- drivers/net/acenic.c | 2 +- drivers/net/amd8111e.c | 7 ++++--- drivers/net/ariadne.c | 2 +- drivers/net/arm/at91_ether.c | 4 ++-- drivers/net/arm/ether3.c | 2 +- drivers/net/arm/ixp4xx_eth.c | 2 +- drivers/net/arm/ks8695net.c | 4 ++-- drivers/net/at1700.c | 6 +++--- drivers/net/atarilance.c | 2 +- drivers/net/atp.c | 7 ++++--- drivers/net/au1000_eth.c | 4 ++-- drivers/net/b44.c | 4 ++-- drivers/net/bcm63xx_enet.c | 4 ++-- drivers/net/benet/be_main.c | 5 +++-- drivers/net/bfin_mac.c | 4 ++-- drivers/net/bmac.c | 8 ++++---- drivers/net/bnx2.c | 2 +- drivers/net/bnx2x_main.c | 7 ++++--- drivers/net/chelsio/common.h | 4 ++-- drivers/net/cpmac.c | 2 +- drivers/net/cris/eth_v10.c | 2 +- drivers/net/davinci_emac.c | 4 ++-- drivers/net/de620.c | 2 +- drivers/net/declance.c | 2 +- drivers/net/defxx.c | 4 ++-- drivers/net/depca.c | 2 +- drivers/net/dl2k.c | 6 +++--- drivers/net/dm9000.c | 2 +- drivers/net/e100.c | 6 +++--- drivers/net/eepro.c | 15 ++++++++------- drivers/net/eexpress.c | 6 +++--- drivers/net/ehea/ehea_main.c | 6 +++--- drivers/net/enc28j60.c | 2 +- drivers/net/enic/enic_main.c | 4 ++-- drivers/net/epic100.c | 6 +++--- drivers/net/eth16i.c | 2 +- drivers/net/ewrk3.c | 2 +- drivers/net/fealnx.c | 4 ++-- drivers/net/fec.c | 2 +- drivers/net/fec_mpc52xx.c | 2 +- drivers/net/fs_enet/mac-fcc.c | 2 +- drivers/net/fs_enet/mac-fec.c | 2 +- drivers/net/fs_enet/mac-scc.c | 2 +- drivers/net/gianfar.c | 2 +- drivers/net/hamachi.c | 6 +++--- drivers/net/hp100.c | 7 ++++--- drivers/net/ibm_newemac/core.c | 6 +++--- drivers/net/ibmveth.c | 5 +++-- drivers/net/igb/igb_main.c | 8 ++++---- drivers/net/igbvf/netdev.c | 6 +++--- drivers/net/ioc3-eth.c | 5 +++-- drivers/net/ipg.c | 4 ++-- drivers/net/isa-skeleton.c | 5 +++-- drivers/net/iseries_veth.c | 4 ++-- drivers/net/ixgb/ixgb_main.c | 6 +++--- drivers/net/ixgbe/ixgbe_main.c | 2 +- drivers/net/ixgbevf/ixgbevf_main.c | 2 +- drivers/net/jme.c | 2 +- drivers/net/korina.c | 6 +++--- drivers/net/ks8851.c | 4 ++-- drivers/net/ks8851_mll.c | 4 ++-- drivers/net/lance.c | 2 +- drivers/net/lib82596.c | 6 +++--- drivers/net/ll_temac_main.c | 6 +++--- drivers/net/lp486e.c | 12 +++++++----- drivers/net/macb.c | 4 ++-- drivers/net/mace.c | 2 +- drivers/net/macmace.c | 2 +- drivers/net/natsemi.c | 4 ++-- drivers/net/netxen/netxen_nic_hw.c | 10 +++++----- drivers/net/ni52.c | 2 +- drivers/net/ni65.c | 2 +- drivers/net/niu.c | 4 ++-- drivers/net/ns83820.c | 2 +- drivers/net/octeon/octeon_mgmt.c | 6 +++--- drivers/net/pci-skeleton.c | 4 ++-- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/3c589_cs.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 6 +++--- drivers/net/pcmcia/nmclan_cs.c | 14 +++++++------- drivers/net/pcmcia/smc91c92_cs.c | 4 ++-- drivers/net/pcmcia/xirc2ps_cs.c | 8 ++++---- drivers/net/pcnet32.c | 2 +- drivers/net/ps3_gelic_net.c | 2 +- drivers/net/qlcnic/qlcnic_hw.c | 4 ++-- drivers/net/qlge/qlge_main.c | 4 ++-- drivers/net/r6040.c | 11 ++++++----- drivers/net/r8169.c | 4 ++-- drivers/net/s2io.c | 8 ++++---- drivers/net/sc92031.c | 2 +- drivers/net/sfc/efx.c | 2 +- drivers/net/sgiseeq.c | 2 +- drivers/net/sis190.c | 4 ++-- drivers/net/sis900.c | 4 ++-- drivers/net/skfp/skfddi.c | 6 +++--- drivers/net/skge.c | 6 +++--- drivers/net/sky2.c | 4 ++-- drivers/net/smc911x.c | 6 +++--- drivers/net/smc9194.c | 4 ++-- drivers/net/smc91x.c | 6 +++--- drivers/net/smsc911x.c | 4 ++-- drivers/net/smsc9420.c | 2 +- drivers/net/sonic.c | 8 +++++--- drivers/net/starfire.c | 8 ++++---- drivers/net/stmmac/dwmac100.c | 6 +++--- drivers/net/stmmac/dwmac1000_core.c | 8 ++++---- drivers/net/sun3_82586.c | 2 +- drivers/net/sun3lance.c | 2 +- drivers/net/sunbmac.c | 4 ++-- drivers/net/sundance.c | 6 +++--- drivers/net/sungem.c | 4 ++-- drivers/net/sunhme.c | 8 ++++---- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 4 ++-- drivers/net/tc35815.c | 6 +++--- drivers/net/tehuti.c | 4 ++-- drivers/net/tg3.c | 4 ++-- drivers/net/tlan.c | 2 +- drivers/net/tokenring/3c359.c | 2 +- drivers/net/tokenring/ibmtr.c | 2 +- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tokenring/olympic.c | 2 +- drivers/net/tokenring/tms380tr.c | 2 +- drivers/net/tsi108_eth.c | 2 +- drivers/net/tulip/de2104x.c | 8 ++++---- drivers/net/tulip/de4x5.c | 6 +++--- drivers/net/tulip/dmfe.c | 15 ++++++++------- drivers/net/tulip/tulip_core.c | 18 +++++++++++------- drivers/net/tulip/uli526x.c | 12 +++++++----- drivers/net/tulip/winbond-840.c | 7 ++++--- drivers/net/typhoon.c | 9 +++++---- drivers/net/ucc_geth.c | 3 ++- drivers/net/usb/asix.c | 12 ++++++------ drivers/net/usb/catc.c | 4 +++- drivers/net/usb/int51x1.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/usb/mcs7830.c | 6 +++--- drivers/net/usb/pegasus.c | 2 +- drivers/net/usb/rtl8150.c | 2 +- drivers/net/usb/smsc95xx.c | 4 ++-- drivers/net/via-rhine.c | 5 +++-- drivers/net/via-velocity.c | 6 ++++-- drivers/net/virtio_net.c | 13 ++++++++----- drivers/net/vmxnet3/vmxnet3_drv.c | 8 ++++---- drivers/net/vxge/vxge-main.c | 6 +++--- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/orinoco/main.c | 4 ++-- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/rndis_wlan.c | 6 +++--- drivers/net/wireless/zd1201.c | 7 +++---- drivers/net/yellowfin.c | 7 ++++--- drivers/staging/et131x/et131x_netdev.c | 10 +++++----- drivers/staging/netwave/netwave_cs.c | 8 ++++---- drivers/staging/slicoss/slicoss.c | 2 +- drivers/staging/vt6655/device_main.c | 4 ++-- drivers/staging/vt6656/main_usb.c | 5 +++-- drivers/staging/wavelan/wavelan.c | 8 ++++---- drivers/staging/wavelan/wavelan_cs.c | 11 ++++++----- drivers/staging/wlags49_h2/wl_netdev.c | 12 ++++++------ net/bluetooth/bnep/netdev.c | 6 ++++-- net/core/dev.c | 2 +- net/irda/irlan/irlan_eth.c | 5 +++-- net/mac80211/iface.c | 2 +- 173 files changed, 440 insertions(+), 401 deletions(-) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 2f0b86b37cf9..87e218f98ef4 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -560,7 +560,7 @@ static void iss_net_set_multicast_list(struct net_device *dev) #if 0 if (dev->flags & IFF_PROMISC) return; - else if (dev->mc_count) + else if (!netdev_mc_empty(dev)) dev->flags |= IFF_ALLMULTI; else dev->flags &= ~IFF_ALLMULTI; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index ab1102780186..c04f8fc6fc2d 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -862,7 +862,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) } nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n", - netdev->mc_count, !!(netdev->flags & IFF_PROMISC), + netdev_mc_count(netdev), !!(netdev->flags & IFF_PROMISC), !!(netdev->flags & IFF_ALLMULTI)); if (!mc_all_on) { multicast_addr = netdev->mc_list; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index da6552d32cfe..37d8579fc7a9 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1138,18 +1138,18 @@ static void wq_set_multicast_list (struct work_struct *work) } else if ((dev->flags & IFF_ALLMULTI)) { dprintk("%s: allmulti mode\n", dev->name); priv->rx_mode = RX_MODE_ALL_MULTI; - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { int mci; struct dev_mc_list *mc; dprintk("%s: set_mc_list, %d entries\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); priv->rx_mode = RX_MODE_MULTI; priv->multi_num = 0; for (mci = 0, mc=dev->mc_list; - mci < dev->mc_count; + mci < netdev_mc_count(dev); mc = mc->next, mci++) { dvb_set_mc_filter(dev, mc); } @@ -1236,7 +1236,6 @@ static void dvb_net_setup(struct net_device *dev) dev->header_ops = &dvb_header_ops; dev->netdev_ops = &dvb_netdev_ops; dev->mtu = 4096; - dev->mc_count = 0; dev->flags |= IFF_NOARP; } diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 9257d7ce0378..dadb46a8833a 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1229,8 +1229,8 @@ static void elp_set_mc_list(struct net_device *dev) /* send a "load multicast list" command to the board, max 10 addrs/cmd */ /* if num_addrs==0 the list will be cleared */ adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST; - adapter->tx_pcb.length = 6 * dev->mc_count; - for (i = 0; i < dev->mc_count; i++) { + adapter->tx_pcb.length = 6 * netdev_mc_count(dev); + for (i = 0; i < netdev_mc_count(dev); i++) { memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr, 6); dmi = dmi->next; } @@ -1244,7 +1244,7 @@ static void elp_set_mc_list(struct net_device *dev) TIMEOUT_MSG(__LINE__); } } - if (dev->mc_count) + if (!netdev_mc_empty(dev)) adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI; else /* num_addrs == 0 */ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 9d85efce5916..902435a76466 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1111,12 +1111,14 @@ set_multicast_list(struct net_device *dev) unsigned long flags; struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; + int mc_count = netdev_mc_count(dev); if (el3_debug > 1) { static int old; - if (old != dev->mc_count) { - old = dev->mc_count; - pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); + if (old != mc_count) { + old = mc_count; + pr_debug("%s: Setting Rx mode to %d addresses.\n", + dev->name, mc_count); } } spin_lock_irqsave(&lp->lock, flags); @@ -1124,7 +1126,7 @@ set_multicast_list(struct net_device *dev) outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); } - else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) { + else if (mc_count || (dev->flags&IFF_ALLMULTI)) { outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); } else diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 27d80ca5e4c0..6948d667fc5e 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -626,7 +626,7 @@ static int init586(struct net_device *dev) volatile struct tdr_cmd_struct *tdr_cmd; volatile struct mcsetup_cmd_struct *mc_cmd; struct dev_mc_list *dmi = dev->mc_list; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct)); @@ -771,7 +771,7 @@ static int init586(struct net_device *dev) * Multicast setup */ - if (dev->mc_count) { + if (num_addrs) { /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if (len <= 0) { diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 36c4191e7bca..ce9826980517 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1526,10 +1526,10 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) if ((dev->flags&IFF_PROMISC) || (dev->flags&IFF_ALLMULTI) || - dev->mc_count > 10) + netdev_mc_count(dev) > 10) /* Enable promiscuous mode */ filt |= 1; - else if(dev->mc_count) + else if (!netdev_mc_empty(dev)) { unsigned char block[62]; unsigned char *bp; @@ -1542,16 +1542,17 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) if(!lp->mc_list_valid) { block[1]=0; - block[0]=dev->mc_count; + block[0]=netdev_mc_count(dev); bp=block+2; - for(i=0;imc_count;i++) + for(i=0;idmi_addr, 6); bp+=6; dmc=dmc->next; } - if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1) + if(mc32_command_nowait(dev, 2, block, + 2+6*netdev_mc_count(dev))==-1) { lp->mc_reload_wait = 1; return; diff --git a/drivers/net/7990.c b/drivers/net/7990.c index b1e5764628c6..079d0be37821 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -611,7 +611,7 @@ static void lance_load_multicast (struct net_device *dev) ib->filter [1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++){ + for (i = 0; i < netdev_mc_count(dev); i++){ addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 1663bc9e45de..638ce3b29854 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1505,7 +1505,7 @@ static void set_multicast_list(struct net_device *dev) int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", - dev->name, dev->mc_count, + dev->name, netdev_mc_count(dev), dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); @@ -1533,7 +1533,7 @@ static void set_multicast_list(struct net_device *dev) i596_add_cmd(dev, &lp->cf_cmd.cmd); } - cnt = dev->mc_count; + cnt = netdev_mc_count(dev); if (cnt > MAX_MC_CNT) { cnt = MAX_MC_CNT; @@ -1541,7 +1541,7 @@ static void set_multicast_list(struct net_device *dev) dev->name, cnt); } - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; @@ -1550,7 +1550,7 @@ static void set_multicast_list(struct net_device *dev) return; cmd = &lp->mc_cmd; cmd->cmd.command = CmdMulticastList; - cmd->mc_cnt = dev->mc_count * 6; + cmd->mc_cnt = netdev_mc_count(dev) * 6; cp = cmd->mc_addrs; for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index b7ec0368d7e8..6a65f660c192 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -619,7 +619,7 @@ static void lance_load_multicast (struct net_device *dev) ib->filter [1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++){ + for (i = 0; i < netdev_mc_count(dev); i++){ addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ec624ab03e88..4ae750ef1e10 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2845,7 +2845,7 @@ static void ace_set_multicast_list(struct net_device *dev) * set the entire multicast list at a time and keeping track of * it here is going to be messy. */ - if ((dev->mc_count) && !(ap->mcast_all)) { + if (!netdev_mc_empty(dev) && !ap->mcast_all) { cmd.evt = C_SET_MULTICAST_MODE; cmd.code = C_C_MCAST_ENABLE; cmd.idx = 0; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index bb27b27d9672..bdffdfb4c88b 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1387,7 +1387,8 @@ static void amd8111e_set_multicast_list(struct net_device *dev) } else writel( PROM, lp->mmio + CMD2); - if(dev->flags & IFF_ALLMULTI || dev->mc_count > MAX_FILTER_SIZE){ + if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MAX_FILTER_SIZE) { /* get all multicast packet */ mc_filter[1] = mc_filter[0] = 0xffffffff; lp->mc_list = dev->mc_list; @@ -1395,7 +1396,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); return; } - if( dev->mc_count == 0 ){ + if (netdev_mc_empty(dev)) { /* get only own packets */ mc_filter[1] = mc_filter[0] = 0; lp->mc_list = NULL; @@ -1409,7 +1410,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) lp->options |= OPTION_MULTICAST_ENABLE; lp->mc_list = dev->mc_list; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count; + for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < netdev_mc_count(dev); i++, mc_ptr = mc_ptr->next) { bit_num = (ether_crc_le(ETH_ALEN, mc_ptr->dmi_addr) >> 26) & 0x3f; mc_filter[bit_num >> 5] |= 1 << (bit_num & 31); diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index e2c202493fa7..08d8be47dae0 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -819,7 +819,7 @@ static void set_multicast_list(struct net_device *dev) lance->RDP = PROM; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer filtering. */ memset(multicast_table, (num_addrs == 0) ? 0 : -1, diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index c8bc60a7040c..17d85d98987d 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -563,7 +563,7 @@ static void at91ether_sethashtable(struct net_device *dev) mc_filter[0] = mc_filter[1] = 0; curr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, curr = curr->next) { if (!curr) break; /* unexpected end of list */ bitnr = hash_get_index(curr->dmi_addr); @@ -592,7 +592,7 @@ static void at91ether_set_multicast_list(struct net_device *dev) at91_emac_write(AT91_EMAC_HSH, -1); at91_emac_write(AT91_EMAC_HSL, -1); cfg |= AT91_EMAC_MTI; - } else if (dev->mc_count > 0) { /* Enable specific multicasts */ + } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ at91ether_sethashtable(dev); cfg |= AT91_EMAC_MTI; } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 1f7a69c929a6..d9de9bce2395 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -463,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ priv(dev)->regs.config1 |= CFG1_RECVPROMISC; - } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) { + } else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) { priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; } else priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index c3dfbdd2cdcf..1a5f78b160f9 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -737,7 +737,7 @@ static void eth_set_mcast_list(struct net_device *dev) struct port *port = netdev_priv(dev); struct dev_mc_list *mclist = dev->mc_list; u8 diffs[ETH_ALEN], *addr; - int cnt = dev->mc_count, i; + int cnt = netdev_mc_count(dev), i; if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) { __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN, diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index be256b34cea8..1dc181a9fbc3 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1207,7 +1207,7 @@ ks8695_set_multicast(struct net_device *ndev) if (ndev->flags & IFF_ALLMULTI) { /* enable all multicast mode */ ctrl |= DRXC_RM; - } else if (ndev->mc_count > KS8695_NR_ADDRESSES) { + } else if (netdev_mc_count(ndev) > KS8695_NR_ADDRESSES) { /* more specific multicast addresses than can be * handled in hardware */ @@ -1216,7 +1216,7 @@ ks8695_set_multicast(struct net_device *ndev) /* enable specific multicasts */ ctrl &= ~DRXC_RM; ks8695_init_partial_multicast(ksp, ndev->mc_list, - ndev->mc_count); + netdev_mc_count(ndev)); } ks8695_writereg(ksp, KS8695_DRXC, ctrl); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index b14f4799d5d1..fe60cd02c86c 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -839,12 +839,12 @@ set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK || + } else if (netdev_mc_count(dev) > MC_FILTERBREAK || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { memset(mc_filter, 0x00, sizeof(mc_filter)); outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ } else { @@ -852,7 +852,7 @@ set_rx_mode(struct net_device *dev) int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index cc9ed8643910..280cfff48b49 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -1097,7 +1097,7 @@ static void set_multicast_list( struct net_device *dev ) REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer * filtering. */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 2f8261c9614a..a841feb5df20 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -861,7 +861,7 @@ static void set_rx_mode_8002(struct net_device *dev) struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; - if (dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) + if (!netdev_mc_empty(dev) || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) lp->addr_mode = CMR2h_PROMISC; else lp->addr_mode = CMR2h_Normal; @@ -877,7 +877,8 @@ static void set_rx_mode_8012(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ new_mode = CMR2h_PROMISC; - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 1000) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); new_mode = CMR2h_Normal; @@ -885,7 +886,7 @@ static void set_rx_mode_8012(struct net_device *dev) struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 6bac04603a88..9337d023919c 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1013,7 +1013,7 @@ static void au1000_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > MULTICAST_FILTER_LIMIT) { + netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) { aup->mac->control |= MAC_PASS_ALL_MULTI; aup->mac->control &= ~MAC_PROMISCUOUS; printk(KERN_INFO "%s: Pass all multicast\n", dev->name); @@ -1023,7 +1023,7 @@ static void au1000_multicast_list(struct net_device *dev) u32 mc_filter[2]; /* Multicast hash filter */ mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, (long *)mc_filter); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 44b66be38134..9091c6574b1c 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1691,7 +1691,7 @@ static int __b44_load_mcast(struct b44 *bp, struct net_device *dev) struct dev_mc_list *mclist; int i, num_ents; - num_ents = min_t(int, dev->mc_count, B44_MCAST_TABLE_SIZE); + num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE); mclist = dev->mc_list; for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) { __b44_cam_write(bp, mclist->dmi_addr, i + 1); @@ -1716,7 +1716,7 @@ static void __b44_set_rx_mode(struct net_device *dev) __b44_set_mac_addr(bp); if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > B44_MCAST_TABLE_SIZE)) + (netdev_mc_count(dev) > B44_MCAST_TABLE_SIZE)) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index 0bd47d32ec42..0927ffa0d753 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -619,7 +619,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev) /* only 3 perfect match registers left, first one is used for * own mac address */ - if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 3) + if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > 3) val |= ENET_RXCFG_ALLMCAST_MASK; else val &= ~ENET_RXCFG_ALLMCAST_MASK; @@ -632,7 +632,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev) } for (i = 0, mc_list = dev->mc_list; - (mc_list != NULL) && (i < dev->mc_count) && (i < 3); + (mc_list != NULL) && (i < netdev_mc_count(dev)) && (i < 3); i++, mc_list = mc_list->next) { u8 *dmi_addr; u32 tmp; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 626b76c0ebc7..0014a4e86446 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -565,14 +565,15 @@ static void be_set_multicast_list(struct net_device *netdev) } /* Enable multicast promisc if num configured exceeds what we support */ - if (netdev->flags & IFF_ALLMULTI || netdev->mc_count > BE_MAX_MC) { + if (netdev->flags & IFF_ALLMULTI || + netdev_mc_count(netdev) > BE_MAX_MC) { be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0, &adapter->mc_cmd_mem); goto done; } be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, - netdev->mc_count, &adapter->mc_cmd_mem); + netdev_mc_count(netdev), &adapter->mc_cmd_mem); done: return; } diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 0b23bc4f56c6..ef7f77113e26 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -819,7 +819,7 @@ static void bfin_mac_multicast_hash(struct net_device *dev) emac_hashhi = emac_hashlo = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; @@ -862,7 +862,7 @@ static void bfin_mac_set_multicast_list(struct net_device *dev) sysctl = bfin_read_EMAC_OPMODE(); sysctl |= PAM; bfin_write_EMAC_OPMODE(sysctl); - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { /* set up multicast hash table */ sysctl = bfin_read_EMAC_OPMODE(); sysctl |= HM; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9b587c344194..189fa69c2094 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -973,7 +973,7 @@ static void bmac_set_multicast(struct net_device *dev) { struct dev_mc_list *dmi; struct bmac_data *bp = netdev_priv(dev); - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); unsigned short rx_cfg; int i; @@ -982,7 +982,7 @@ static void bmac_set_multicast(struct net_device *dev) XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs)); - if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff; bmac_update_hash_table_mask(dev, bp); rx_cfg = bmac_rx_on(dev, 1, 0); @@ -1021,7 +1021,7 @@ static void bmac_set_multicast(struct net_device *dev) unsigned short rx_cfg; u32 crc; - if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { bmwrite(dev, BHASH0, 0xffff); bmwrite(dev, BHASH1, 0xffff); bmwrite(dev, BHASH2, 0xffff); @@ -1039,7 +1039,7 @@ static void bmac_set_multicast(struct net_device *dev) for(i = 0; i < 4; i++) hash_table[i] = 0; - for(i = 0; i < dev->mc_count; i++) { + for(i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5917b941aca2..c7f5515ddaa4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3560,7 +3560,7 @@ bnx2_set_rx_mode(struct net_device *dev) memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ffc7381969ae..6d8559052ee6 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11471,7 +11471,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev) rx_mode = BNX2X_RX_MODE_PROMISC; else if ((dev->flags & IFF_ALLMULTI) || - ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp))) + ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) && + CHIP_IS_E1(bp))) rx_mode = BNX2X_RX_MODE_ALLMULTI; else { /* some multicasts */ @@ -11482,7 +11483,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev) bnx2x_sp(bp, mcast_config); for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); + mclist && (i < netdev_mc_count(dev)); i++, mclist = mclist->next) { config->config_table[i]. @@ -11554,7 +11555,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev) memset(mc_filter, 0, 4 * MC_HASH_SIZE); for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); + mclist && (i < netdev_mc_count(dev)); i++, mclist = mclist->next) { DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index f6462b54f823..bb159d9603bf 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -97,13 +97,13 @@ struct t1_rx_mode { #define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC) #define t1_rx_mode_allmulti(rm) (rm->dev->flags & IFF_ALLMULTI) -#define t1_rx_mode_mc_cnt(rm) (rm->dev->mc_count) +#define t1_rx_mode_mc_cnt(rm) (netdev_mc_count(rm->dev)) static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm) { u8 *addr = NULL; - if (rm->idx++ < rm->dev->mc_count) { + if (rm->idx++ < t1_rx_mode_mc_cnt(rm)) { addr = rm->list->dmi_addr; rm->list = rm->list->next; } diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 8d0be26f94e3..c9c537be4ab9 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -340,7 +340,7 @@ static void cpmac_set_multicast_list(struct net_device *dev) * cpmac uses some strange mac address hashing * (not crc32) */ - for (i = 0, iter = dev->mc_list; i < dev->mc_count; + for (i = 0, iter = dev->mc_list; i < netdev_mc_count(dev); i++, iter = iter->next) { bit = 0; tmp = iter->dmi_addr[0]; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index a24be34a3f7a..c9309eadebc1 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1564,7 +1564,7 @@ static void set_multicast_list(struct net_device *dev) { struct net_local *lp = netdev_priv(dev); - int num_addr = dev->mc_count; + int num_addr = netdev_mc_count(dev); unsigned long int lo_bits; unsigned long int hi_bits; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index faffad409985..d1e03b5984c0 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -956,11 +956,11 @@ static void emac_dev_mcast_set(struct net_device *ndev) } else { mbp_enable = (mbp_enable & ~EMAC_MBP_RXPROMISC); if ((ndev->flags & IFF_ALLMULTI) || - (ndev->mc_count > EMAC_DEF_MAX_MULTICAST_ADDRESSES)) { + netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) { mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL); } - if (ndev->mc_count > 0) { + if (!netdev_mc_empty(ndev)) { struct dev_mc_list *mc_ptr; mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 45794f6cb0f6..a0a6830b5e6d 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -464,7 +464,7 @@ static int de620_close(struct net_device *dev) static void de620_set_multicast_list(struct net_device *dev) { - if (dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { /* Enable promiscuous mode */ de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL); } diff --git a/drivers/net/declance.c b/drivers/net/declance.c index be9590253aa1..76e0de6a4263 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -960,7 +960,7 @@ static void lance_load_multicast(struct net_device *dev) *lib_ptr(ib, filter[3], lp->type) = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 98da085445e6..5adb1e03956d 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -2227,7 +2227,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) * perfect filtering will be used. */ - if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) + if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) { bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ bp->mc_count = 0; /* Don't add mc addrs to CAM */ @@ -2235,7 +2235,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) else { bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ - bp->mc_count = dev->mc_count; /* Add mc addrs to CAM */ + bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ } /* Copy addresses to multicast address table, then update adapter CAM */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 0c1f491d20bf..314bc96689f4 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1287,7 +1287,7 @@ static void SetMulticastFilter(struct net_device *dev) lp->init_block.mcast_table[i] = 0; } /* Add multicast addresses */ - for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev); i++) { /* for each address in the list */ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 2a8b6a7c0b87..dea40953ed1b 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1128,17 +1128,17 @@ set_multicast (struct net_device *dev) /* Receive all frames promiscuously. */ rx_mode = ReceiveAllFrames; } else if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > multicast_filter_limit)) { + (netdev_mc_count(dev) > multicast_filter_limit)) { /* Receive broadcast and multicast frames */ rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *mclist; /* Receive broadcast frames and multicast frames filtering by Hashtable */ rx_mode = ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast; - for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i=0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist=mclist->next) { int bit, index = 0; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index b37730065688..da0985a7a87a 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -725,7 +725,7 @@ dm9000_hash_table(struct net_device *dev) { board_info_t *db = netdev_priv(dev); struct dev_mc_list *mcptr = dev->mc_list; - int mc_cnt = dev->mc_count; + int mc_cnt = netdev_mc_count(dev); int i, oft; u32 hash_val; u16 hash_table[4]; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 5c7a155e849a..e8c0e823a06f 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1538,7 +1538,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) { struct net_device *netdev = nic->netdev; struct dev_mc_list *list = netdev->mc_list; - u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + u16 i, count = min(netdev_mc_count(netdev), E100_MAX_MULTICAST_ADDRS); cb->command = cpu_to_le16(cb_multi); cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); @@ -1552,7 +1552,7 @@ static void e100_set_multicast_list(struct net_device *netdev) struct nic *nic = netdev_priv(netdev); DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", - netdev->mc_count, netdev->flags); + netdev_mc_count(netdev), netdev->flags); if (netdev->flags & IFF_PROMISC) nic->flags |= promiscuous; @@ -1560,7 +1560,7 @@ static void e100_set_multicast_list(struct net_device *netdev) nic->flags &= ~promiscuous; if (netdev->flags & IFF_ALLMULTI || - netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + netdev_mc_count(netdev) > E100_MAX_MULTICAST_ADDRS) nic->flags |= multicast_all; else nic->flags &= ~multicast_all; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 94c59498cdb6..488bc13cc7e6 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1288,8 +1288,9 @@ set_multicast_list(struct net_device *dev) short ioaddr = dev->base_addr; unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; + int mc_count = mc_count; - if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1299,7 +1300,7 @@ set_multicast_list(struct net_device *dev) eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } - else if (dev->mc_count==0 ) + else if (mc_count == 0) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1329,9 +1330,9 @@ set_multicast_list(struct net_device *dev) outw(MC_SETUP, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); - outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); + outw(6 * (mc_count + 1), ioaddr + IO_PORT); - for (i = 0; i < dev->mc_count; i++) + for (i = 0; i < mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; @@ -1348,7 +1349,7 @@ set_multicast_list(struct net_device *dev) outb(MC_SETUP, ioaddr); /* Update the transmit queue */ - i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); + i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1); if (lp->tx_start != lp->tx_end) { @@ -1380,8 +1381,8 @@ set_multicast_list(struct net_device *dev) break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n", - dev->name, dev->mc_count, - dev->mc_count > 1 ? "es":""); + dev->name, mc_count, + mc_count > 1 ? "es":""); break; } } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 6fbfc8eee632..d804ff18eda8 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1578,7 +1578,7 @@ static void eexp_setup_filter(struct net_device *dev) { struct dev_mc_list *dmi; unsigned short ioaddr = dev->base_addr; - int count = dev->mc_count; + int count = netdev_mc_count(dev); int i; if (count > 8) { printk(KERN_INFO "%s: too many multicast addresses (%d)\n", @@ -1627,9 +1627,9 @@ eexp_set_multicast(struct net_device *dev) } if (!(dev->flags & IFF_PROMISC)) { eexp_setup_filter(dev); - if (lp->old_mc_count != dev->mc_count) { + if (lp->old_mc_count != netdev_mc_count(dev)) { kick = 1; - lp->old_mc_count = dev->mc_count; + lp->old_mc_count = netdev_mc_count(dev); } } if (kick) { diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 7b62336e6736..99e4f8360d2f 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1981,7 +1981,7 @@ static void ehea_set_multicast_list(struct net_device *dev) } ehea_allmulti(dev, 0); - if (dev->mc_count) { + if (!netdev_mc_empty(dev)) { ret = ehea_drop_multicast_list(dev); if (ret) { /* Dropping the current multicast list failed. @@ -1990,14 +1990,14 @@ static void ehea_set_multicast_list(struct net_device *dev) ehea_allmulti(dev, 1); } - if (dev->mc_count > port->adapter->max_mc_mac) { + if (netdev_mc_count(dev) > port->adapter->max_mc_mac) { ehea_info("Mcast registration limit reached (0x%llx). " "Use ALLMULTI!", port->adapter->max_mc_mac); goto out; } - for (i = 0, k_mcl_entry = dev->mc_list; i < dev->mc_count; i++, + for (i = 0, k_mcl_entry = dev->mc_list; i < netdev_mc_count(dev); i++, k_mcl_entry = k_mcl_entry->next) ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr); diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 66813c91a720..3ee32e58c7ec 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1413,7 +1413,7 @@ static void enc28j60_set_multicast_list(struct net_device *dev) if (netif_msg_link(priv)) dev_info(&dev->dev, "promiscuous mode\n"); priv->rxfilter = RXFILTER_PROMISC; - } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) { + } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { if (netif_msg_link(priv)) dev_info(&dev->dev, "%smulticast mode\n", (dev->flags & IFF_ALLMULTI) ? "all-" : ""); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index c81bc4b1816f..94749ebaaea8 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -827,11 +827,11 @@ static void enic_set_multicast_list(struct net_device *netdev) int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; + unsigned int mc_count = netdev_mc_count(netdev); int allmulti = (netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); + mc_count > ENIC_MULTICAST_PERFECT_FILTERS; unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; - unsigned int mc_count = netdev->mc_count; unsigned int i, j; if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 1f8b11449fad..31a3adb65566 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1390,20 +1390,20 @@ static void set_rx_mode(struct net_device *dev) outl(0x002C, ioaddr + RxCtrl); /* Unconditionally log net taps. */ memset(mc_filter, 0xff, sizeof(mc_filter)); - } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) { + } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) { /* There is apparently a chip bug, so the multicast filter is never enabled. */ /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outl(0x000C, ioaddr + RxCtrl); - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { outl(0x0004, ioaddr + RxCtrl); return; } else { /* Never executed, for now. */ struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 71bfeec33a0b..d3abeee3f110 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1359,7 +1359,7 @@ static void eth16i_multicast(struct net_device *dev) { int ioaddr = dev->base_addr; - if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { outb(3, ioaddr + RECEIVE_MODE_REG); } else { diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index dd4ba01fd92d..96817a872f47 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1213,7 +1213,7 @@ static void SetMulticastFilter(struct net_device *dev) } /* Update table */ - for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev); i++) { /* for each address in the list */ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e6a98129d787..f95b5ff0587d 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1786,7 +1786,7 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); @@ -1796,7 +1796,7 @@ static void __set_rx_mode(struct net_device *dev) int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit; bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5d0d33268155..d9d14c83f51c 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1606,7 +1606,7 @@ static void set_multicast_list(struct net_device *dev) dmi = dev->mc_list; - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { + for (j = 0; j < netdev_mc_count(dev); j++, dmi = dmi->next) { /* Only support group multicast for now */ if (!(dmi->dmi_addr[0] & 1)) continue; diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 848e8407ea8f..10903b75802f 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -581,7 +581,7 @@ static void mpc52xx_fec_set_multicast_list(struct net_device *dev) u32 gaddr2 = 0x00000000; dmi = dev->mc_list; - for (i=0; imc_count; i++) { + for (i=0; idmi_addr) >> 26; if (crc >= 32) gaddr1 |= 1 << (crc-32); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 22e5a847a588..482f27d5f7d4 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -218,7 +218,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > FCC_MAX_MULTICAST_ADDRS) { W32(ep, fen_gaddrh, 0xffffffff); W32(ep, fen_gaddrl, 0xffffffff); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index ca7bcb8ab3a1..ddf13ef8ac87 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -220,7 +220,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > FEC_MAX_MULTICAST_ADDRS) { fep->fec.hthi = 0xffffffffU; fep->fec.htlo = 0xffffffffU; } diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 008cdd9cc536..141dbc91e5e7 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -213,7 +213,7 @@ static void set_multicast_finish(struct net_device *dev) /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || - dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { + netdev_mc_count(dev) > SCC_MAX_MULTICAST_ADDRS) { W16(ep, sen_gaddr1, 0xffff); W16(ep, sen_gaddr2, 0xffff); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 8bd3c9f17532..c9be090485dd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2863,7 +2863,7 @@ static void gfar_set_multi(struct net_device *dev) em_num = 0; } - if (dev->mc_count == 0) + if (netdev_mc_empty(dev)) return; /* Parse the list, and set the appropriate bits */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index dd72c5025e6a..c70b147b4feb 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1854,13 +1854,13 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ writew(0x000F, ioaddr + AddrMode); - } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ writew(0x000B, ioaddr + AddrMode); - } else if (dev->mc_count > 0) { /* Must use the CAM filter. */ + } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */ struct dev_mc_list *mclist; int i; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8); writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]), diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 0c2f2e8b1c47..debac1bc6799 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2090,7 +2090,7 @@ static void hp100_set_multicast_list(struct net_device *dev) lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ memset(&lp->hash_bytes, 0xff, 8); - } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ #ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ @@ -2104,9 +2104,10 @@ static void hp100_set_multicast_list(struct net_device *dev) memset(&lp->hash_bytes, 0x00, 8); #ifdef HP100_DEBUG - printk("hp100: %s: computing hash filter - mc_count = %i\n", dev->name, dev->mc_count); + printk("hp100: %s: computing hash filter - mc_count = %i\n", + dev->name, netdev_mc_count(dev)); #endif - for (i = 0, dmi = dev->mc_list; i < dev->mc_count; i++, dmi = dmi->next) { + for (i = 0, dmi = dev->mc_list; i < netdev_mc_count(dev); i++, dmi = dmi->next) { addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index fb5e019169ee..b75d27e82a3d 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -391,7 +391,7 @@ static void emac_hash_mc(struct emac_instance *dev) struct dev_mc_list *dmi; int i; - DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count); + DBG(dev, "hash_mc %d" NL, netdev_mc_count(dev->ndev)); memset(gaht_temp, 0, sizeof (gaht_temp)); @@ -425,9 +425,9 @@ static inline u32 emac_iff2rmr(struct net_device *ndev) if (ndev->flags & IFF_PROMISC) r |= EMAC_RMR_PME; else if (ndev->flags & IFF_ALLMULTI || - (ndev->mc_count > EMAC_XAHT_SLOTS(dev))) + (netdev_mc_count(ndev) > EMAC_XAHT_SLOTS(dev))) r |= EMAC_RMR_PMME; - else if (ndev->mc_count > 0) + else if (!netdev_mc_empty(ndev)) r |= EMAC_RMR_MAE; return r; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index a86693906ac8..41b9c0efcbdd 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1062,7 +1062,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; - if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) { + if ((netdev->flags & IFF_PROMISC) || + (netdev_mc_count(netdev) > adapter->mcastFilterSize)) { lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastEnableRecv | IbmVethMcastDisableFiltering, @@ -1083,7 +1084,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc); } /* add the addresses to the filter table */ - for(i = 0; i < netdev->mc_count; ++i, mclist = mclist->next) { + for(i = 0; i < netdev_mc_count(netdev); ++i, mclist = mclist->next) { // add the multicast address to the filter table unsigned long mcast_addr = 0; memcpy(((char *)&mcast_addr)+2, mclist->dmi_addr, 6); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 83cd0d7417d0..28371d648208 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2848,14 +2848,14 @@ static int igb_write_mc_addr_list(struct net_device *netdev) u32 vmolr = 0; int i; - if (!netdev->mc_count) { + if (netdev_mc_empty(netdev)) { /* nothing to program, so clear mc list */ igb_update_mc_addr_list(hw, NULL, 0); igb_restore_vf_multicasts(adapter); return 0; } - mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); + mta_list = kzalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); if (!mta_list) return -ENOMEM; @@ -2865,7 +2865,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev) /* The shared function expects a packed array of only addresses. */ mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { if (!mc_ptr) break; memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); @@ -2874,7 +2874,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev) igb_update_mc_addr_list(hw, mta_list, i); kfree(mta_list); - return netdev->mc_count; + return netdev_mc_count(netdev); } /** diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 23ce07d3de08..6029c400f2be 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1403,8 +1403,8 @@ static void igbvf_set_multi(struct net_device *netdev) u8 *mta_list = NULL; int i; - if (netdev->mc_count) { - mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!netdev_mc_empty(netdev)) { + mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); if (!mta_list) { dev_err(&adapter->pdev->dev, "failed to allocate multicast filter list\n"); @@ -1415,7 +1415,7 @@ static void igbvf_set_multi(struct net_device *netdev) /* prepare a packed array of only addresses. */ mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { if (!mc_ptr) break; memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 81a4c5d30733..0bd5fef22d49 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1681,14 +1681,15 @@ static void ioc3_set_multicast_list(struct net_device *dev) ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */ (void) ioc3_r_emcr(); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 64)) { /* Too many for hashing to make sense or we want all multicast packets anyway, so skip computing all the hashes and just accept all packets. */ ip->ehar_h = 0xffffffff; ip->ehar_l = 0xffffffff; } else { - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addr = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 49f35e2ed19f..dbdebd5efe86 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -585,11 +585,11 @@ static void ipg_nic_set_multicast_list(struct net_device *dev) receivemode = IPG_RM_RECEIVEALLFRAMES; } else if ((dev->flags & IFF_ALLMULTI) || ((dev->flags & IFF_MULTICAST) && - (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) { + (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) { /* NIC to be configured to receive all multicast * frames. */ receivemode |= IPG_RM_RECEIVEMULTICAST; - } else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) { + } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { /* NIC to be configured to receive selected * multicast addresses. */ receivemode |= IPG_RM_RECEIVEMULTICASTHASH; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 04d0502726c0..bb4a3cda6e4b 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -655,14 +655,15 @@ set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ outw(MULTICAST|PROMISC, ioaddr); } - else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) + else if ((dev->flags&IFF_ALLMULTI) || + netdev_mc_count(dev) > HW_MAX_ADDRS) { /* Disable promiscuous mode, use normal mode. */ hardware_set_filter(NULL); outw(MULTICAST, ioaddr); } - else if(dev->mc_count) + else if (!netdev_mc_empty(dev)) { /* Walk the address list, and load the filter */ hardware_set_filter(dev->mc_list); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 16c91910d6c1..ff015e15f5d1 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -958,7 +958,7 @@ static void veth_set_multicast_list(struct net_device *dev) write_lock_irqsave(&port->mcast_gate, flags); if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > VETH_MAX_MCAST)) { + (netdev_mc_count(dev) > VETH_MAX_MCAST)) { port->promiscuous = 1; } else { struct dev_mc_list *dmi = dev->mc_list; @@ -969,7 +969,7 @@ static void veth_set_multicast_list(struct net_device *dev) /* Update table */ port->num_mcast = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { u8 *addr = dmi->dmi_addr; u64 xaddr = 0; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index c56ea69762cd..6a7b2ccef72c 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1077,7 +1077,7 @@ ixgb_set_multi(struct net_device *netdev) rctl |= IXGB_RCTL_VFE; } - if (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { + if (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES) { rctl |= IXGB_RCTL_MPE; IXGB_WRITE_REG(hw, RCTL, rctl); } else { @@ -1092,7 +1092,7 @@ ixgb_set_multi(struct net_device *netdev) memcpy(&mta[i * IXGB_ETH_LENGTH_OF_ADDRESS], mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS); - ixgb_mc_addr_list_update(hw, mta, netdev->mc_count, 0); + ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0); } } @@ -1616,7 +1616,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter) return; if ((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { + (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL); u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL); u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 382bf8945d11..0792f151de99 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2571,7 +2571,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) hw->mac.ops.update_uc_addr_list(hw, netdev); /* reprogram multicast list */ - addr_count = netdev->mc_count; + addr_count = netdev_mc_count(netdev); if (addr_count) addr_list = netdev->mc_list->dmi_addr; hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index b9f10d05049d..235b5fd4b8d4 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1527,7 +1527,7 @@ static void ixgbevf_set_rx_mode(struct net_device *netdev) int addr_count = 0; /* reprogram multicast list */ - addr_count = netdev->mc_count; + addr_count = netdev_mc_count(netdev); if (addr_count) addr_list = netdev->mc_list->dmi_addr; if (hw->mac.ops.update_mc_addr_list) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 26eed49d3208..d44c39dfbef1 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2013,7 +2013,7 @@ jme_set_multi(struct net_device *netdev) jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED; for (i = 0, mclist = netdev->mc_list; - mclist && i < netdev->mc_count; + mclist && i < netdev_mc_count(netdev); ++i, mclist = mclist->next) { bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F; diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 25e2af6997e4..af0c764130e6 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -490,19 +490,19 @@ static void korina_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) recognise |= ETH_ARC_PRO; - else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 4)) + else if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 4)) /* All multicast and broadcast */ recognise |= ETH_ARC_AM; /* Build the hash table */ - if (dev->mc_count > 4) { + if (netdev_mc_count(dev) > 4) { u16 hash_table[4]; u32 crc; for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 6d3ac65bc35c..9845ab1e5573 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -965,14 +965,14 @@ static void ks8851_set_rx_mode(struct net_device *dev) rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE | RXCR1_RXPAFMA | RXCR1_RXMAFMA); - } else if (dev->flags & IFF_MULTICAST && dev->mc_count > 0) { + } else if (dev->flags & IFF_MULTICAST && !netdev_mc_empty(dev)) { struct dev_mc_list *mcptr = dev->mc_list; u32 crc; int i; /* accept some multicast */ - for (i = dev->mc_count; i > 0; i--) { + for (i = netdev_mc_count(dev); i > 0; i--) { crc = ether_crc(ETH_ALEN, mcptr->dmi_addr); crc >>= (32 - 6); /* get top six bits */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index c0ceebccaa49..ffffb3889704 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -1193,8 +1193,8 @@ static void ks_set_rx_mode(struct net_device *netdev) else ks_set_promis(ks, false); - if ((netdev->flags & IFF_MULTICAST) && netdev->mc_count) { - if (netdev->mc_count <= MAX_MCAST_LST) { + if ((netdev->flags & IFF_MULTICAST) && netdev_mc_count(netdev)) { + if (netdev_mc_count(netdev) <= MAX_MCAST_LST) { int i = 0; for (ptr = netdev->mc_list; ptr; ptr = ptr->next) { if (!(*ptr->dmi_addr & 1)) diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 8d7d3d4625f6..7b9447646f8a 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1288,7 +1288,7 @@ static void set_multicast_list(struct net_device *dev) } else { short multicast_table[4]; int i; - int num_addrs=dev->mc_count; + int num_addrs=netdev_mc_count(dev); if(dev->flags&IFF_ALLMULTI) num_addrs=1; /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index b60efd4bd017..371b58b1d151 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1380,21 +1380,21 @@ static void set_multicast_list(struct net_device *dev) } } - cnt = dev->mc_count; + cnt = netdev_mc_count(dev); if (cnt > MAX_MC_CNT) { cnt = MAX_MC_CNT; printk(KERN_NOTICE "%s: Only %d multicast addresses supported", dev->name, cnt); } - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; cmd = &dma->mc_cmd; cmd->cmd.command = SWAP16(CmdMulticastList); - cmd->mc_cnt = SWAP16(dev->mc_count * 6); + cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6); cp = cmd->mc_addrs; for (dmi = dev->mc_list; cnt && dmi != NULL; diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index a8522bd73ae7..8442c47e93e8 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -232,7 +232,7 @@ static void temac_set_multicast_list(struct net_device *ndev) mutex_lock(&lp->indirect_mutex); if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || - ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { + netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on @@ -242,9 +242,9 @@ static void temac_set_multicast_list(struct net_device *ndev) ndev->flags |= IFF_PROMISC; temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); - } else if (ndev->mc_count) { + } else if (!netdev_mc_empty(ndev)) { struct dev_mc_list *mclist = ndev->mc_list; - for (i = 0; mclist && i < ndev->mc_count; i++) { + for (i = 0; mclist && i < netdev_mc_count(ndev); i++) { if (i >= MULTICAST_CAM_TABLE_NUM) break; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index e20fefc73c8b..b1f5d79af61f 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1253,18 +1253,19 @@ static void set_multicast_list(struct net_device *dev) { if (i596_debug > 1) printk ("%s: set multicast list %d\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); - if (dev->mc_count > 0) { + if (!netdev_mc_empty(dev)) { struct dev_mc_list *dmi; char *cp; - cmd = kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); + cmd = kmalloc(sizeof(struct i596_cmd) + 2 + + netdev_mc_count(dev) * 6, GFP_ATOMIC); if (cmd == NULL) { printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name); return; } cmd->command = CmdMulticastList; - *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; + *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6; cp = ((char *)(cmd + 1))+2; for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { memcpy(cp, dmi,6); @@ -1277,7 +1278,8 @@ static void set_multicast_list(struct net_device *dev) { if (lp->set_conf.pa_next != I596_NULL) { return; } - if (dev->mc_count == 0 && !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + if (netdev_mc_empty(dev) && + !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { lp->i596_config[8] &= ~0x01; } else { lp->i596_config[8] |= 0x01; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 1d0d4d9ab623..fbc371fa19b5 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -901,7 +901,7 @@ static void macb_sethashtable(struct net_device *dev) mc_filter[0] = mc_filter[1] = 0; curr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, curr = curr->next) { if (!curr) break; /* unexpected end of list */ bitnr = hash_get_index(curr->dmi_addr); @@ -934,7 +934,7 @@ static void macb_set_rx_mode(struct net_device *dev) macb_writel(bp, HRB, -1); macb_writel(bp, HRT, -1); cfg |= MACB_BIT(NCFGR_MTI); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ macb_sethashtable(dev); cfg |= MACB_BIT(NCFGR_MTI); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index d9fbad386389..fdb0bbdd6782 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -606,7 +606,7 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 44f3c2896f20..740accbf0806 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -518,7 +518,7 @@ static void mace_set_multicast(struct net_device *dev) } else { for (i = 0; i < 8; i++) multicast_filter[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 2d7b3bbfed01..c64e5b0d3596 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2488,7 +2488,7 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; @@ -2496,7 +2496,7 @@ static void __set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; mc_filter[b/8] |= (1 << (b & 0x07)); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index dd45c7a9122e..25f4414cc33e 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -554,7 +554,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) return; } - if (netdev->mc_count == 0) { + if (netdev_mc_empty(netdev)) { adapter->set_promisc(adapter, NETXEN_NIU_NON_PROMISC_MODE); netxen_nic_disable_mcast_filter(adapter); @@ -563,7 +563,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE); if (netdev->flags & IFF_ALLMULTI || - netdev->mc_count > adapter->max_mc_count) { + netdev_mc_count(netdev) > adapter->max_mc_count) { netxen_nic_disable_mcast_filter(adapter); return; } @@ -573,7 +573,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++) netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr); - if (index != netdev->mc_count) + if (index != netdev_mc_count(netdev)) printk(KERN_WARNING "%s: %s multicast address count mismatch\n", netxen_nic_driver_name, netdev->name); @@ -704,12 +704,12 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) } if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > adapter->max_mc_count)) { + (netdev_mc_count(netdev) > adapter->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; goto send_fw_cmd; } - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index b42f5e522f90..497c6d514a68 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -597,7 +597,7 @@ static int init586(struct net_device *dev) struct tdr_cmd_struct __iomem *tdr_cmd; struct mcsetup_cmd_struct __iomem *mc_cmd; struct dev_mc_list *dmi = dev->mc_list; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); ptr = p->scb + 1; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index ae19aafd2c7e..9225c76cac40 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -849,7 +849,7 @@ static int ni65_lance_reinit(struct net_device *dev) if(dev->flags & IFF_PROMISC) ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); - else if(dev->mc_count || dev->flags & IFF_ALLMULTI) + else if (netdev_mc_count(dev) || dev->flags & IFF_ALLMULTI) ni65_init_lance(p,dev->dev_addr,0xff,0x0); else ni65_init_lance(p,dev->dev_addr,0x00,0x00); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index af9a8647c7e8..7b52d9762b00 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6369,7 +6369,7 @@ static void niu_set_rx_mode(struct net_device *dev) np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC); if (dev->flags & IFF_PROMISC) np->flags |= NIU_FLAGS_PROMISC; - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) + if ((dev->flags & IFF_ALLMULTI) || (!netdev_mc_empty(dev))) np->flags |= NIU_FLAGS_MCAST; alt_cnt = netdev_uc_count(dev); @@ -6412,7 +6412,7 @@ static void niu_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { for (i = 0; i < 16; i++) hash[i] = 0xffff; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { for (addr = dev->mc_list; addr; addr = addr->next) { u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index a3b6aa0f375d..8dd509c09bc8 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1719,7 +1719,7 @@ static void ns83820_set_multicast(struct net_device *ndev) else and_mask &= ~(RFCR_AAU | RFCR_AAM); - if (ndev->flags & IFF_ALLMULTI || ndev->mc_count) + if (ndev->flags & IFF_ALLMULTI || netdev_mc_count(ndev)) or_mask |= RFCR_AAM; else and_mask &= ~RFCR_AAM; diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c index 6fd8789ef487..3a0f910924a5 100644 --- a/drivers/net/octeon/octeon_mgmt.c +++ b/drivers/net/octeon/octeon_mgmt.c @@ -493,8 +493,8 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) } if (netdev->flags & IFF_MULTICAST) { - if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) - || netdev->mc_count > available_cam_entries) + if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) || + netdev_mc_count(netdev) > available_cam_entries) multicast_mode = 2; /* 1 - Accept all multicast. */ else multicast_mode = 0; /* 0 - Use CAM. */ @@ -511,7 +511,7 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) } } if (multicast_mode == 0) { - i = netdev->mc_count; + i = netdev_mc_count(netdev); list = netdev->mc_list; while (i--) { octeon_mgmt_cam_state_add(&cam_state, list->da_addr); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 20273832bfce..bbdf0398c93f 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1820,7 +1820,7 @@ static void netdrv_set_rx_mode (struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -1829,7 +1829,7 @@ static void netdrv_set_rx_mode (struct net_device *dev) struct dev_mc_list *mclist; rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 98938ea9e0bd..3d1d3a7b7ed3 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1148,7 +1148,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); - else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); else outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 322e11df0097..091e0b00043e 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -886,7 +886,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) opts |= RxMulticast | RxProm; - else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) opts |= RxMulticast; outw(opts, ioaddr + EL3_CMD); } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 7b17404d0858..3d573ed5f7c5 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -1187,19 +1187,19 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK || + } else if (netdev_mc_count(dev) > MC_FILTERBREAK || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ - } else if (dev->mc_count == 0) { + } else if (netdev_mc_empty(dev)) { memset(mc_filter, 0x00, sizeof(mc_filter)); outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ } else { struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 12e3233868e9..c42a31a97fa3 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -1481,8 +1481,8 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { static int old; - if (dev->mc_count != old) { - old = dev->mc_count; + if (netdev_mc_count(dev) != old) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } @@ -1490,13 +1490,13 @@ static void set_multicast_list(struct net_device *dev) #endif /* Set multicast_num_addrs. */ - lp->multicast_num_addrs = dev->mc_count; + lp->multicast_num_addrs = netdev_mc_count(dev); /* Set multicast_ladrf. */ if (num_addrs > 0) { /* Calculate multicast logical address filter */ memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN); - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN); dmi = dmi->next; BuildLAF(lp->multicast_ladrf, adr); @@ -1537,15 +1537,15 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { static int old; - if (dev->mc_count != old) { - old = dev->mc_count; + if (netdev_mc_count(dev) != old) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } } #endif - lp->multicast_num_addrs = dev->mc_count; + lp->multicast_num_addrs = netdev_mc_count(dev); restore_multicast_list(dev); } /* set_multicast_list */ diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6dd486d2977b..d2e86b8887c8 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1638,8 +1638,8 @@ static void set_rx_mode(struct net_device *dev) } else if (dev->flags & IFF_ALLMULTI) rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti; else { - if (dev->mc_count) { - fill_multicast_tbl(dev->mc_count, dev->mc_list, + if (!netdev_mc_empty(dev)) { + fill_multicast_tbl(netdev_mc_count(dev), dev->mc_list, (u_char *)multicast_table); } rx_cfg_setting = RxStripCRC | RxEnable; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 466fc72698c0..4ace18a71152 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1384,7 +1384,7 @@ set_addresses(struct net_device *dev) if (++n > 9) break; i = 0; - if (n > 1 && n <= dev->mc_count && dmi) { + if (n > 1 && n <= netdev_mc_count(dev) && dmi) { dmi = dmi->next; } } @@ -1394,7 +1394,7 @@ set_addresses(struct net_device *dev) SelectPage(k); } - if (n && n <= dev->mc_count && dmi) + if (n && n <= netdev_mc_count(dev) && dmi) addr = dmi->dmi_addr; else addr = dev->dev_addr; @@ -1424,9 +1424,9 @@ set_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* snoop */ PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */ - } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) { + } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) { PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */ - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { /* the chip can filter 9 addresses perfectly */ PutByte(XIRCREG42_SWC1, value | 0x01); SelectPage(0x40); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 0dc7ff896eeb..3522794550dd 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2698,7 +2698,7 @@ static void pcnet32_load_multicast(struct net_device *dev) ib->filter[1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 0c768593aad0..c19dd4a6cd76 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -568,7 +568,7 @@ void gelic_net_set_multi(struct net_device *netdev) status); if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > GELIC_NET_MC_COUNT_MAX)) { + (netdev_mc_count(netdev) > GELIC_NET_MC_COUNT_MAX)) { status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), 0, 1); diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index dc6cd69d6d93..8ea7f869e293 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -447,12 +447,12 @@ void qlcnic_set_multi(struct net_device *netdev) } if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > adapter->max_mc_count)) { + (netdev_mc_count(netdev) > adapter->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; goto send_fw_cmd; } - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 3cb60e10d456..dd3e0f1b2965 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4221,7 +4221,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) * transition is taking place. */ if ((ndev->flags & IFF_ALLMULTI) || - (ndev->mc_count > MAX_MULTICAST_ENTRIES)) { + (netdev_mc_count(ndev) > MAX_MULTICAST_ENTRIES)) { if (!test_bit(QL_ALLMULTI, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) { @@ -4243,7 +4243,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) } } - if (ndev->mc_count) { + if (!netdev_mc_empty(ndev)) { status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); if (status) goto exit; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index d68ba7a58631..b8103425facb 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -958,21 +958,22 @@ static void r6040_multicast_list(struct net_device *dev) } /* Too many multicast addresses * accept all traffic */ - else if ((dev->mc_count > MCAST_MAX) || (dev->flags & IFF_ALLMULTI)) + else if ((netdev_mc_count(dev) > MCAST_MAX) || + (dev->flags & IFF_ALLMULTI)) reg |= 0x0020; iowrite16(reg, ioaddr); spin_unlock_irqrestore(&lp->lock, flags); /* Build the hash table */ - if (dev->mc_count > MCAST_MAX) { + if (netdev_mc_count(dev) > MCAST_MAX) { u16 hash_table[4]; u32 crc; for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; @@ -994,14 +995,14 @@ static void r6040_multicast_list(struct net_device *dev) iowrite16(hash_table[3], ioaddr + MAR3); } /* Multicast Address 1~4 case */ - for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) { + for (i = 0, dmi; (i < netdev_mc_count(dev)) && (i < MCAST_MAX); i++) { adrp = (u16 *)dmi->dmi_addr; iowrite16(adrp[0], ioaddr + MID_1L + 8*i); iowrite16(adrp[1], ioaddr + MID_1M + 8*i); iowrite16(adrp[2], ioaddr + MID_1H + 8*i); dmi = dmi->next; } - for (i = dev->mc_count; i < MCAST_MAX; i++) { + for (i = netdev_mc_count(dev); i < MCAST_MAX; i++) { iowrite16(0xffff, ioaddr + MID_0L + 8*i); iowrite16(0xffff, ioaddr + MID_0M + 8*i); iowrite16(0xffff, ioaddr + MID_0H + 8*i); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c1bb24cf0793..85c635f354b5 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4758,7 +4758,7 @@ static void rtl_set_rx_mode(struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -4769,7 +4769,7 @@ static void rtl_set_rx_mode(struct net_device *dev) rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d1664586e8ff..102be16e9b52 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5055,8 +5055,8 @@ static void s2io_set_multicast(struct net_device *dev) } /* Update individual M_CAST address list */ - if ((!sp->m_cast_flg) && dev->mc_count) { - if (dev->mc_count > + if ((!sp->m_cast_flg) && netdev_mc_count(dev)) { + if (netdev_mc_count(dev) > (config->max_mc_addr - config->max_mac_addr)) { DBG_PRINT(ERR_DBG, "%s: No more Rx filters can be added - " @@ -5066,7 +5066,7 @@ static void s2io_set_multicast(struct net_device *dev) } prev_cnt = sp->mc_addr_count; - sp->mc_addr_count = dev->mc_count; + sp->mc_addr_count = netdev_mc_count(dev); /* Clear out the previous list of Mc in the H/W. */ for (i = 0; i < prev_cnt; i++) { @@ -5092,7 +5092,7 @@ static void s2io_set_multicast(struct net_device *dev) } /* Create the new Rx filter list and update the same in H/W. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index fd8cb506a2bb..00ff8995ad69 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -429,7 +429,7 @@ static void _sc92031_set_mar(struct net_device *dev) u32 mar0 = 0, mar1 = 0; if ((dev->flags & IFF_PROMISC) || - dev->mc_count > multicast_filter_limit || + netdev_mc_count(dev) > multicast_filter_limit || (dev->flags & IFF_ALLMULTI)) mar0 = mar1 = 0xffffffff; else if (dev->flags & IFF_MULTICAST) { diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 62d5cd51a9dd..fafaf30ecd9a 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1615,7 +1615,7 @@ static void efx_set_multicast_list(struct net_device *net_dev) memset(mc_hash, 0xff, sizeof(*mc_hash)); } else { memset(mc_hash, 0x00, sizeof(*mc_hash)); - for (i = 0; i < net_dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net_dev); i++) { crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr); bit = crc & (EFX_MCAST_HASH_ENTRIES - 1); set_bit_le(bit, mc_hash->byte); diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 6b364a6c6c60..ed999d31f1fa 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -660,7 +660,7 @@ static void sgiseeq_set_multicast(struct net_device *dev) if(dev->flags & IFF_PROMISC) sp->mode = SEEQ_RCMD_RANY; - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) + else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) sp->mode = SEEQ_RCMD_RBMCAST; else sp->mode = SEEQ_RCMD_RBCAST; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 626de766443a..8c4e38f9ebf7 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -841,7 +841,7 @@ static void sis190_set_rx_mode(struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -852,7 +852,7 @@ static void sis190_set_rx_mode(struct net_device *dev) rx_mode = AcceptBroadcast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 20c5ce474891..32ae87c09f5e 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2288,7 +2288,7 @@ static void set_rx_mode(struct net_device *net_dev) rx_mode = RFPromiscuous; for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; - } else if ((net_dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(net_dev) > multicast_filter_limit) || (net_dev->flags & IFF_ALLMULTI)) { /* too many multicast addresses or accept all multicast packet */ rx_mode = RFAAB | RFAAM; @@ -2301,7 +2301,7 @@ static void set_rx_mode(struct net_device *net_dev) struct dev_mc_list *mclist; rx_mode = RFAAB; for (i = 0, mclist = net_dev->mc_list; - mclist && i < net_dev->mc_count; + mclist && i < netdev_mc_count(net_dev); i++, mclist = mclist->next) { unsigned int bit_nr = sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 6b955a4f19b2..346adfae986f 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -872,14 +872,14 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); - } else if (dev->mc_count > 0) { - if (dev->mc_count <= FPMAX_MULTICAST) { + } else if (!netdev_mc_empty(dev)) { + if (netdev_mc_count(dev) <= FPMAX_MULTICAST) { /* use exact filtering */ // point to first multicast addr dmi = dev->mc_list; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { mac_add_multicast(smc, (struct fddi_addr *)dmi->dmi_addr, 1); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 5ff46eb18d0c..36ead52dea71 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2932,7 +2932,7 @@ static void genesis_set_multicast(struct net_device *dev) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; - int i, count = dev->mc_count; + int i, count = netdev_mc_count(dev); struct dev_mc_list *list = dev->mc_list; u32 mode; u8 filter[8]; @@ -2987,7 +2987,7 @@ static void yukon_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0 && !rx_pause)/* no multicast */ + else if (netdev_mc_empty(dev) && !rx_pause)/* no multicast */ reg &= ~GM_RXCR_MCF_ENA; else { int i; @@ -2996,7 +2996,7 @@ static void yukon_set_multicast(struct net_device *dev) if (rx_pause) yukon_add_filter(filter, pause_mc_addr); - for (i = 0; list && i < dev->mc_count; i++, list = list->next) + for (i = 0; list && i < netdev_mc_count(dev); i++, list = list->next) yukon_add_filter(filter, list->dmi_addr); } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 478288b8bc21..45299d663498 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3626,7 +3626,7 @@ static void sky2_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0 && !rx_pause) + else if (netdev_mc_empty(dev) && !rx_pause) reg &= ~GM_RXCR_MCF_ENA; else { int i; @@ -3635,7 +3635,7 @@ static void sky2_set_multicast(struct net_device *dev) if (rx_pause) sky2_add_filter(filter, pause_mc_addr); - for (i = 0; list && i < dev->mc_count; i++, list = list->next) + for (i = 0; list && i < netdev_mc_count(dev); i++, list = list->next) sky2_add_filter(filter, list->dmi_addr); } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 3c5a4f52345c..ef9674c6713f 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1323,7 +1323,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) * I don't need to zero the multicast table, because the flag is * checked before the table is */ - else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { + else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name); mcr |= MAC_CR_MCPAS_; } @@ -1340,7 +1340,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) * the number of the 32 bit register, while the low 5 bits are the bit * within that register. */ - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *cur_addr; @@ -1351,7 +1351,7 @@ static void smc911x_set_multicast_list(struct net_device *dev) memset(multicast_table, 0, sizeof(multicast_table)); cur_addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { u32 position; /* do we have a pointer here? */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 8371b82323ac..41c3dddeab50 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -1542,7 +1542,7 @@ static void smc_set_multicast_list(struct net_device *dev) /* We just get all multicast packets even if we only want them . from one source. This will be changed at some future . point. */ - else if (dev->mc_count ) { + else if (!netdev_mc_empty(dev)) { /* support hardware multicasting */ /* be sure I get rid of flags I might have set */ @@ -1550,7 +1550,7 @@ static void smc_set_multicast_list(struct net_device *dev) ioaddr + RCR ); /* NOTE: this has to set the bank, so make sure it is the last thing called. The bank is set to zero at the top */ - smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); + smc_setmulticast(ioaddr, netdev_mc_count(dev), dev->mc_list); } else { outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index ea4fae79d6ec..66450127c5a1 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1395,7 +1395,7 @@ static void smc_set_multicast_list(struct net_device *dev) * I don't need to zero the multicast table, because the flag is * checked before the table is */ - else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { + else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { DBG(2, "%s: RCR_ALMUL\n", dev->name); lp->rcr_cur_mode |= RCR_ALMUL; } @@ -1412,7 +1412,7 @@ static void smc_set_multicast_list(struct net_device *dev) * the number of the 8 bit register, while the low 3 bits are the bit * within that register. */ - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { int i; struct dev_mc_list *cur_addr; @@ -1423,7 +1423,7 @@ static void smc_set_multicast_list(struct net_device *dev) memset(multicast_table, 0, sizeof(multicast_table)); cur_addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { int position; /* do we have a pointer here? */ diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 494cd91ea39c..3c1f9aa84cf5 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1383,7 +1383,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); pdata->hashhi = 0; pdata->hashlo = 0; - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { /* Enabling specific multicast addresses */ unsigned int hash_high = 0; unsigned int hash_low = 0; @@ -1408,7 +1408,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) } mc_list = mc_list->next; } - if (count != (unsigned int)dev->mc_count) + if (count != (unsigned int)netdev_mc_count(dev)) SMSC_WARNING(DRV, "mc_count != dev->mc_count"); pdata->hashhi = hash_high; diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 1495a5dd4b46..2bd3c986559a 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -1062,7 +1062,7 @@ static void smsc9420_set_multicast_list(struct net_device *dev) mac_cr &= (~MAC_CR_PRMS_); mac_cr |= MAC_CR_MCPAS_; mac_cr &= (~MAC_CR_HPFILT_); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mc_list = dev->mc_list; u32 hash_lo = 0, hash_hi = 0; diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 9599ce77ef85..bd8bc66f2e00 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -541,13 +541,15 @@ static void sonic_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ rcr |= SONIC_RCR_PRO; } else { - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { + if ((dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 15)) { rcr |= SONIC_RCR_AMC; } else { if (sonic_debug > 2) - printk("sonic_multicast_list: mc_count %d\n", dev->mc_count); + printk("sonic_multicast_list: mc_count %d\n", + netdev_mc_count(dev)); sonic_set_cam_enable(dev, 1); /* always enable our own address */ - for (i = 1; i <= dev->mc_count; i++) { + for (i = 1; i <= netdev_mc_count(dev); i++) { addr = dmi->dmi_addr; dmi = dmi->next; sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index d0556a9b456c..58bc7ac086cf 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1796,15 +1796,15 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode |= AcceptAll; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter; - } else if (dev->mc_count <= 14) { + } else if (netdev_mc_count(dev) <= 14) { /* Use the 16 element perfect filter, skip first two entries. */ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16; __be16 *eaddrs; - for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2; + for (i = 2, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev) + 2; i++, mclist = mclist->next) { eaddrs = (__be16 *)mclist->dmi_addr; writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4; @@ -1825,7 +1825,7 @@ static void set_rx_mode(struct net_device *dev) __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The chip uses the upper 9 CRC bits as index into the hash table */ diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c index ac48ed787040..576b256ee388 100644 --- a/drivers/net/stmmac/dwmac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -305,13 +305,13 @@ static void dwmac100_set_filter(struct net_device *dev) value |= MAC_CONTROL_PR; value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO | MAC_CONTROL_HP); - } else if ((dev->mc_count > HASH_TABLE_SIZE) + } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) || (dev->flags & IFF_ALLMULTI)) { value |= MAC_CONTROL_PM; value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO); writel(0xffffffff, ioaddr + MAC_HASH_HIGH); writel(0xffffffff, ioaddr + MAC_HASH_LOW); - } else if (dev->mc_count == 0) { /* no multicast */ + } else if (netdev_mc_empty(dev)) { /* no multicast */ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO | MAC_CONTROL_HP); } else { @@ -327,7 +327,7 @@ static void dwmac100_set_filter(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; - mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The upper 6 bits of the calculated CRC are used to * index the contens of the hash table */ int bit_nr = diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index d812e9cdb3db..90dbb4f41ef3 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -83,16 +83,16 @@ static void dwmac1000_set_filter(struct net_device *dev) unsigned int value = 0; DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", - __func__, dev->mc_count, netdev_uc_count(dev)); + __func__, netdev_mc_count(dev), netdev_uc_count(dev)); if (dev->flags & IFF_PROMISC) value = GMAC_FRAME_FILTER_PR; - else if ((dev->mc_count > HASH_TABLE_SIZE) + else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) || (dev->flags & IFF_ALLMULTI)) { value = GMAC_FRAME_FILTER_PM; /* pass all multi */ writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); writel(0xffffffff, ioaddr + GMAC_HASH_LOW); - } else if (dev->mc_count > 0) { + } else if (!netdev_mc_empty(dev)) { int i; u32 mc_filter[2]; struct dev_mc_list *mclist; @@ -102,7 +102,7 @@ static void dwmac1000_set_filter(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; - mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { /* The upper 6 bits of the calculated CRC are used to index the contens of the hash table */ int bit_nr = diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index b447a8719427..efedc252e4be 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -414,7 +414,7 @@ static int init586(struct net_device *dev) volatile struct tdr_cmd_struct *tdr_cmd; volatile struct mcsetup_cmd_struct *mc_cmd; struct dev_mc_list *dmi=dev->mc_list; - int num_addrs=dev->mc_count; + int num_addrs=netdev_mc_count(dev); ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 0ca4241b4f63..99998862c22e 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -917,7 +917,7 @@ static void set_multicast_list( struct net_device *dev ) REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ } else { short multicast_table[4]; - int num_addrs = dev->mc_count; + int num_addrs = netdev_mc_count(dev); int i; /* We don't use the multicast table, but rely on upper-layer * filtering. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 25e81ebd9cd8..dfea56fa39e3 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1013,7 +1013,7 @@ static void bigmac_set_multicast(struct net_device *dev) while ((sbus_readl(bregs + BMAC_RXCFG) & BIGMAC_RXCFG_ENABLE) != 0) udelay(20); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { sbus_writel(0xffff, bregs + BMAC_HTABLE0); sbus_writel(0xffff, bregs + BMAC_HTABLE1); sbus_writel(0xffff, bregs + BMAC_HTABLE2); @@ -1028,7 +1028,7 @@ static void bigmac_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 0c972e560cf3..4171259590b2 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1517,18 +1517,18 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mclist; int bit; int index; int crc; memset (mc_filter, 0, sizeof (mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr); for (index=0, bit=0; bit < 6; bit++, crc <<= 1) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index b55ceb88d93f..d497ec053953 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1837,7 +1837,7 @@ static u32 gem_setup_multicast(struct gem *gp) int i; if ((gp->dev->flags & IFF_ALLMULTI) || - (gp->dev->mc_count > 256)) { + (netdev_mc_count(gp->dev) > 256)) { for (i=0; i<16; i++) writel(0xffff, gp->regs + MAC_HASH0 + (i << 2)); rxcfg |= MAC_RXCFG_HFE; @@ -1852,7 +1852,7 @@ static u32 gem_setup_multicast(struct gem *gp) for (i = 0; i < 16; i++) hash_table[i] = 0; - for (i = 0; i < gp->dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(gp->dev); i++) { char *addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 76ccd31cbf50..905df35ff78a 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1516,7 +1516,7 @@ static int happy_meal_init(struct happy_meal *hp) HMD(("htable, ")); if ((hp->dev->flags & IFF_ALLMULTI) || - (hp->dev->mc_count > 64)) { + (netdev_mc_count(hp->dev) > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); @@ -1531,7 +1531,7 @@ static int happy_meal_init(struct happy_meal *hp) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < hp->dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(hp->dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; @@ -2373,7 +2373,7 @@ static void happy_meal_set_multicast(struct net_device *dev) spin_lock_irq(&hp->happy_lock); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); @@ -2387,7 +2387,7 @@ static void happy_meal_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 64e7d08c878f..cf9d5bb9e1e9 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1196,7 +1196,7 @@ static void lance_load_multicast(struct net_device *dev) return; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 45c383f285ee..3bc35d86ed66 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -636,7 +636,7 @@ static void qe_set_multicast(struct net_device *dev) /* Lock out others. */ netif_stop_queue(dev); - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { sbus_writeb(MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET, qep->mregs + MREGS_IACONFIG); while ((sbus_readb(qep->mregs + MREGS_IACONFIG) & MREGS_IACONFIG_ACHNGE) != 0) @@ -653,7 +653,7 @@ static void qe_set_multicast(struct net_device *dev) for (i = 0; i < 4; i++) hash_table[i] = 0; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { addrs = dmi->dmi_addr; dmi = dmi->next; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 033408f589fb..d838d4015c63 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1941,18 +1941,18 @@ tc35815_set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > CAM_ENTRY_MAX - 3) { + netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) { /* CAM 0, 1, 20 are reserved. */ /* Disable promiscuous mode, use normal mode. */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl); - } else if (dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *cur_addr = dev->mc_list; int i; int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE); tc_writel(0, &tr->CAM_Ctl); /* Walk the address list, and load the filter */ - for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) { if (!cur_addr) break; /* entry 0,1 is reserved. */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index b907bee31fd5..ab9b0280317e 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -808,7 +808,7 @@ static void bdx_setmulti(struct net_device *ndev) /* set IMF to accept all multicast frmaes */ for (i = 0; i < MAC_MCST_HASH_NUM; i++) WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0); - } else if (ndev->mc_count) { + } else if (!netdev_mc_empty(ndev)) { u8 hash; struct dev_mc_list *mclist; u32 reg, val; @@ -840,7 +840,7 @@ static void bdx_setmulti(struct net_device *ndev) } } else { - DBG("only own mac %d\n", ndev->mc_count); + DBG("only own mac %d\n", netdev_mc_count(ndev)); rxf_val |= GMAC_RX_FILTER_AB; } WRITE_REG(priv, regGMAC_RXF_A, rxf_val); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7195bdec17f3..d29282f01c23 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9430,7 +9430,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) } else if (dev->flags & IFF_ALLMULTI) { /* Accept all multicast. */ tg3_set_multi (tp, 1); - } else if (dev->mc_count < 1) { + } else if (netdev_mc_empty(dev)) { /* Reject all multicast. */ tg3_set_multi (tp, 0); } else { @@ -9442,7 +9442,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) u32 bit; u32 crc; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { crc = calc_crc (mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 3ec31dce99f9..e44d5a074c69 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1335,7 +1335,7 @@ static void TLan_SetMulticastList( struct net_device *dev ) TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); } else { - for ( i = 0; i < dev->mc_count; i++ ) { + for ( i = 0; i < netdev_mc_count(dev); i++ ) { if ( i < 3 ) { TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index b0d7db9d8bb4..eff68e1d107b 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1408,7 +1408,7 @@ static void xl_set_rx_mode(struct net_device *dev) dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; dev_mc_address[2] |= dmi->dmi_addr[4] ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 66272f2a0758..1ce8f85a89aa 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -996,7 +996,7 @@ static void tok_set_multicast_list(struct net_device *dev) if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return; address[0] = address[1] = address[2] = address[3] = 0; mclist = dev->mc_list; - for (i = 0; i < dev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(dev); i++) { address[0] |= mclist->dmi_addr[2]; address[1] |= mclist->dmi_addr[3]; address[2] |= mclist->dmi_addr[4]; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 3f9d5a25562e..26d84daf660b 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1303,7 +1303,7 @@ static void streamer_set_rx_mode(struct net_device *dev) writel(streamer_priv->srb,streamer_mmio+LAPA); dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index f010a4dc5f19..a242d125b34c 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1178,7 +1178,7 @@ static void olympic_set_rx_mode(struct net_device *dev) dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + for (i=0,dmi=dev->mc_list;i < netdev_mc_count(dev); i++,dmi = dmi->next) { dev_mc_address[0] |= dmi->dmi_addr[2] ; dev_mc_address[1] |= dmi->dmi_addr[3] ; dev_mc_address[2] |= dmi->dmi_addr[4] ; diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index e3c42f5ac4a9..6b8868959b85 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1214,7 +1214,7 @@ static void tms380tr_set_multicast_list(struct net_device *dev) { int i; struct dev_mc_list *mclist = dev->mc_list; - for (i=0; i< dev->mc_count; i++) + for (i=0; i< netdev_mc_count(dev); i++) { ((char *)(&tp->ocpl.FunctAddr))[0] |= mclist->dmi_addr[2]; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index a69c4a48bab9..f4b30c4826fb 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1184,7 +1184,7 @@ static void tsi108_set_rx_mode(struct net_device *dev) rxcfg &= ~(TSI108_EC_RXCFG_UFE | TSI108_EC_RXCFG_MFE); - if (dev->flags & IFF_ALLMULTI || dev->mc_count) { + if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) { int i; struct dev_mc_list *mc = dev->mc_list; rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 29330209ad8b..a4cff23dcdf9 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -677,7 +677,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) memset(hash_table, 0, sizeof(hash_table)); set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff; @@ -706,7 +706,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) /* We have <= 14 addresses so we can use the wonderful 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; @@ -741,7 +741,7 @@ static void __de_set_rx_mode (struct net_device *dev) goto out; } - if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ macmode |= AcceptAllMulticast; goto out; @@ -749,7 +749,7 @@ static void __de_set_rx_mode (struct net_device *dev) /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) /* Must use a multicast hash table. */ + if (netdev_mc_count(dev) > 14) /* Must use a multicast hash table. */ build_setup_frame_hash (de->setup_frame, dev); else build_setup_frame_perfect (de->setup_frame, dev); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index a8349b7200b5..0b6a9731091c 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1963,10 +1963,10 @@ SetMulticastFilter(struct net_device *dev) omr &= ~(OMR_PR | OMR_PM); pa = build_setup_frame(dev, ALL); /* Build the basic frame */ - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) { + if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 14)) { omr |= OMR_PM; /* Pass all multicasts */ } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */ - for (i=0;imc_count;i++) { /* for each address in the list */ + for (i = 0; i < netdev_mc_count(dev) ;i++) { addrs=dmi->dmi_addr; dmi=dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ @@ -1984,7 +1984,7 @@ SetMulticastFilter(struct net_device *dev) } } } else { /* Perfect filtering */ - for (j=0; jmc_count; j++) { + for (j=0; jdmi_addr; dmi=dmi->next; for (i=0; ichip_id == PCI_DM9132_ID) - dm9132_id_table(dev, dev->mc_count); /* DM9132 */ + dm9132_id_table(dev, netdev_mc_count(dev)); /* DM9132 */ else - send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ + send_filter_frame(dev, netdev_mc_count(dev)); /* DM9102/DM9102A */ /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; @@ -1052,6 +1052,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) { struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; + int mc_count = netdev_mc_count(dev); DMFE_DBUG(0, "dmfe_set_filter_mode()", 0); spin_lock_irqsave(&db->lock, flags); @@ -1064,19 +1065,19 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) return; } - if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) { - DMFE_DBUG(0, "Pass all multicast address", dev->mc_count); + if (dev->flags & IFF_ALLMULTI || mc_count > DMFE_MAX_MULTICAST) { + DMFE_DBUG(0, "Pass all multicast address", mc_count); db->cr6_data &= ~(CR6_PM | CR6_PBF); db->cr6_data |= CR6_PAM; spin_unlock_irqrestore(&db->lock, flags); return; } - DMFE_DBUG(0, "Set multicast address", dev->mc_count); + DMFE_DBUG(0, "Set multicast address", mc_count); if (db->chip_id == PCI_DM9132_ID) - dm9132_id_table(dev, dev->mc_count); /* DM9132 */ + dm9132_id_table(dev, mc_count); /* DM9132 */ else - send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ + send_filter_frame(dev, mc_count); /* DM9102/DM9102A */ spin_unlock_irqrestore(&db->lock, flags); } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e1a5f03a49c5..cce2ada07950 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -997,7 +997,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) memset(hash_table, 0, sizeof(hash_table)); set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff; @@ -1026,7 +1026,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) /* We have <= 14 addresses so we can use the wonderful 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { eaddrs = (u16 *)mclist->dmi_addr; *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++; @@ -1057,7 +1057,8 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; csr6 |= AcceptAllMulticast | AcceptAllPhys; - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 1000) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= AcceptAllMulticast; csr6 |= AcceptAllMulticast; @@ -1066,14 +1067,16 @@ static void set_rx_mode(struct net_device *dev) /* Should verify correctness on big-endian/__powerpc__ */ struct dev_mc_list *mclist; int i; - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + if (netdev_mc_count(dev) > 64) { + /* Arbitrary non-effective limit. */ tp->csr6 |= AcceptAllMulticast; csr6 |= AcceptAllMulticast; } else { u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ int filterbit; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { if (tp->flags & COMET_MAC_ADDR) filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr); else @@ -1107,7 +1110,8 @@ static void set_rx_mode(struct net_device *dev) /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + if (netdev_mc_count(dev) > 14) { + /* Must use a multicast hash table. */ build_setup_frame_hash(tp->setup_frame, dev); tx_flags = 0x08400000 | 192; } else { diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index dc3335d906f6..216ceb322ed4 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -557,7 +557,7 @@ static void uli526x_init(struct net_device *dev) update_cr6(db->cr6_data, ioaddr); /* Send setup frame */ - send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */ /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; @@ -906,16 +906,18 @@ static void uli526x_set_filter_mode(struct net_device * dev) return; } - if (dev->flags & IFF_ALLMULTI || dev->mc_count > ULI5261_MAX_MULTICAST) { - ULI526X_DBUG(0, "Pass all multicast address", dev->mc_count); + if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > ULI5261_MAX_MULTICAST) { + ULI526X_DBUG(0, "Pass all multicast address", + netdev_mc_count(dev)); db->cr6_data &= ~(CR6_PM | CR6_PBF); db->cr6_data |= CR6_PAM; spin_unlock_irqrestore(&db->lock, flags); return; } - ULI526X_DBUG(0, "Set multicast address", dev->mc_count); - send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + ULI526X_DBUG(0, "Set multicast address", netdev_mc_count(dev)); + send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */ spin_unlock_irqrestore(&db->lock, flags); } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 9fb89afccf7c..98711a9f35ac 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1361,7 +1361,7 @@ static u32 __set_rx_mode(struct net_device *dev) memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); @@ -1370,8 +1370,9 @@ static u32 __set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 6e4f754c4baf..edabc49a49bc 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -924,17 +924,18 @@ typhoon_set_rx_mode(struct net_device *dev) filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST; if(dev->flags & IFF_PROMISC) { filter |= TYPHOON_RX_FILTER_PROMISCOUS; - } else if((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ filter |= TYPHOON_RX_FILTER_ALL_MCAST; - } else if(dev->mc_count) { + } else if (!netdev_mc_empty(dev)) { struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit >> 5] |= 1 << (bit & 0x1f); } diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 225f65812f2e..a05720289c7e 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2031,7 +2031,8 @@ static void ucc_geth_set_multi(struct net_device *dev) dmi = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) { + for (i = 0; i < netdev_mc_count(dev); + i++, dmi = dmi->next) { /* Only support group multicast for now. */ diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index a516185cbc9f..f02551713b13 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -542,9 +542,9 @@ static void asix_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= AX_RX_CTL_PRO; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > AX_MAX_MCAST) { + netdev_mc_count(net) > AX_MAX_MCAST) { rx_ctl |= AX_RX_CTL_AMALL; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -558,7 +558,7 @@ static void asix_set_multicast(struct net_device *net) memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; @@ -754,9 +754,9 @@ static void ax88172_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= 0x01; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > AX_MAX_MCAST) { + netdev_mc_count(net) > AX_MAX_MCAST) { rx_ctl |= 0x02; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -770,7 +770,7 @@ static void ax88172_set_multicast(struct net_device *net) memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 7d3fa06980c1..5a13660ebd17 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -648,7 +648,9 @@ static void catc_set_multicast_list(struct net_device *netdev) if (netdev->flags & IFF_ALLMULTI) { memset(catc->multicast, 0xff, 64); } else { - for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { + for (i = 0, mc = netdev->mc_list; + mc && i < netdev_mc_count(netdev); + i++, mc = mc->next) { u32 crc = ether_crc_le(6, mc->dmi_addr); if (!catc->is_f5u011) { catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index 55cf7081de10..9ab5c1983a7d 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -139,7 +139,7 @@ static void int51x1_set_multicast(struct net_device *netdev) /* do not expect to see traffic of other PLCs */ filter |= PACKET_TYPE_PROMISCUOUS; devinfo(dev, "promiscuous mode enabled"); - } else if (netdev->mc_count || + } else if (!netdev_mc_empty(netdev) || (netdev->flags & IFF_ALLMULTI)) { filter |= PACKET_TYPE_ALL_MULTICAST; devdbg(dev, "receive all multicast enabled"); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index f1d64ef67efa..52671ea043a7 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -881,7 +881,7 @@ static void kaweth_set_rx_mode(struct net_device *net) if (net->flags & IFF_PROMISC) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; } - else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { + else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; } diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 6fc098fe9ff7..34665137f2c3 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -443,9 +443,9 @@ static void mcs7830_data_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { data->config |= HIF_REG_CONFIG_PROMISCUOUS; } else if (net->flags & IFF_ALLMULTI || - net->mc_count > MCS7830_MAX_MCAST) { + netdev_mc_count(net) > MCS7830_MAX_MCAST) { data->config |= HIF_REG_CONFIG_ALLMULTICAST; - } else if (net->mc_count == 0) { + } else if (netdev_mc_empty(net)) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data @@ -457,7 +457,7 @@ static void mcs7830_data_set_multicast(struct net_device *net) int i; /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { + for (i = 0; i < netdev_mc_count(net); i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); mc_list = mc_list->next; diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index ed4a508ef262..44ae8f6d3135 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1232,7 +1232,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; if (netif_msg_link(pegasus)) pr_info("%s: Promiscuous mode enabled.\n", net->name); - } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) { + } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; if (netif_msg_link(pegasus)) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 21ac103fbb71..e85c89c6706d 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -711,7 +711,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { dev->rx_creg |= cpu_to_le16(0x0001); dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); - } else if (netdev->mc_count || + } else if (!netdev_mc_empty(netdev) || (netdev->flags & IFF_ALLMULTI)) { dev->rx_creg &= cpu_to_le16(0xfffe); dev->rx_creg |= cpu_to_le16(0x0002); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 0c3c738d7419..48555d0e374d 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -384,7 +384,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev) devdbg(dev, "receive all multicast enabled"); pdata->mac_cr |= MAC_CR_MCPAS_; pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_); - } else if (dev->net->mc_count > 0) { + } else if (!netdev_mc_empty(dev->net)) { struct dev_mc_list *mc_list = dev->net->mc_list; int count = 0; @@ -406,7 +406,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev) mc_list = mc_list->next; } - if (count != ((u32)dev->net->mc_count)) + if (count != ((u32) netdev_mc_count(dev->net))) devwarn(dev, "mc_count != dev->mc_count"); if (netif_msg_drv(dev)) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index a7e0c84426ea..85df7ac636b5 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1697,7 +1697,7 @@ static void rhine_set_rx_mode(struct net_device *dev) rx_mode = 0x1C; iowrite32(0xffffffff, ioaddr + MulticastFilter0); iowrite32(0xffffffff, ioaddr + MulticastFilter1); - } else if ((dev->mc_count > multicast_filter_limit) || + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ iowrite32(0xffffffff, ioaddr + MulticastFilter0); @@ -1707,7 +1707,8 @@ static void rhine_set_rx_mode(struct net_device *dev) struct dev_mc_list *mclist; int i; memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index f15485efe40e..bdb19c3d6568 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1132,7 +1132,7 @@ static void velocity_set_multi(struct net_device *dev) writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); rx_mode = (RCR_AM | RCR_AB | RCR_PROM); - } else if ((dev->mc_count > vptr->multicast_limit) || + } else if ((netdev_mc_count(dev) > vptr->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); @@ -1141,7 +1141,9 @@ static void velocity_set_multi(struct net_device *dev) int offset = MCAM_SIZE - vptr->multicast_limit; mac_get_cam_mask(regs, vptr->mCAMmask); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { + for (i = 0, mclist = dev->mc_list; + mclist && i < netdev_mc_count(dev); + i++, mclist = mclist->next) { mac_set_cam(regs, i + offset, mclist->dmi_addr); vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9d8984a3741c..4c347a3df657 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -735,6 +735,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) struct dev_addr_list *addr; struct netdev_hw_addr *ha; int uc_count; + int mc_count; void *buf; int i; @@ -762,9 +763,11 @@ static void virtnet_set_rx_mode(struct net_device *dev) allmulti ? "en" : "dis"); uc_count = netdev_uc_count(dev); + mc_count = netdev_mc_count(dev); /* MAC filter - use one buffer for both lists */ - mac_data = buf = kzalloc(((uc_count + dev->mc_count) * ETH_ALEN) + - (2 * sizeof(mac_data->entries)), GFP_ATOMIC); + buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) + + (2 * sizeof(mac_data->entries)), GFP_ATOMIC); + mac_data = buf; if (!buf) { dev_warn(&dev->dev, "No memory for MAC address buffer\n"); return; @@ -784,13 +787,13 @@ static void virtnet_set_rx_mode(struct net_device *dev) /* multicast list and count fill the end */ mac_data = (void *)&mac_data->macs[uc_count][0]; - mac_data->entries = dev->mc_count; + mac_data->entries = mc_count; addr = dev->mc_list; - for (i = 0; i < dev->mc_count; i++, addr = addr->next) + for (i = 0; i < mc_count; i++, addr = addr->next) memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); sg_set_buf(&sg[1], mac_data, - sizeof(mac_data->entries) + (dev->mc_count * ETH_ALEN)); + sizeof(mac_data->entries) + (mc_count * ETH_ALEN)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_TABLE_SET, diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index b896f9386110..ee1b397417f3 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1668,7 +1668,7 @@ static u8 * vmxnet3_copy_mc(struct net_device *netdev) { u8 *buf = NULL; - u32 sz = netdev->mc_count * ETH_ALEN; + u32 sz = netdev_mc_count(netdev) * ETH_ALEN; /* struct Vmxnet3_RxFilterConf.mfTableLen is u16. */ if (sz <= 0xffff) { @@ -1678,7 +1678,7 @@ vmxnet3_copy_mc(struct net_device *netdev) int i; struct dev_mc_list *mc = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { + for (i = 0; i < netdev_mc_count(netdev); i++) { BUG_ON(!mc); memcpy(buf + i * ETH_ALEN, mc->dmi_addr, ETH_ALEN); @@ -1708,12 +1708,12 @@ vmxnet3_set_mc(struct net_device *netdev) if (netdev->flags & IFF_ALLMULTI) new_mode |= VMXNET3_RXM_ALL_MULTI; else - if (netdev->mc_count > 0) { + if (!netdev_mc_empty(netdev)) { new_table = vmxnet3_copy_mc(netdev); if (new_table) { new_mode |= VMXNET3_RXM_MCAST; rxConf->mfTableLen = cpu_to_le16( - netdev->mc_count * ETH_ALEN); + netdev_mc_count(netdev) * ETH_ALEN); rxConf->mfTablePA = cpu_to_le64(virt_to_phys( new_table)); } else { diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index a6606b8948e9..c248b01218a1 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -1178,11 +1178,11 @@ static void vxge_set_multicast(struct net_device *dev) memset(&mac_info, 0, sizeof(struct macInfo)); /* Update individual M_CAST address list */ - if ((!vdev->all_multi_flg) && dev->mc_count) { + if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) { mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; list_head = &vdev->vpaths[0].mac_addr_list; - if ((dev->mc_count + + if ((netdev_mc_count(dev) + (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) > vdev->vpaths[0].max_mac_addr_cnt) goto _set_all_mcast; @@ -1217,7 +1217,7 @@ static void vxge_set_multicast(struct net_device *dev) } /* Add new ones */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev); i++, mclist = mclist->next) { memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ef6b78da370f..c22a34c7639c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2310,7 +2310,7 @@ static void airo_set_multicast_list(struct net_device *dev) { airo_set_promisc(ai); } - if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) { + if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { /* Turn on multicast. (Should be already setup...) */ } } diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 753a1804eee7..a9e9cea2d767 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1668,12 +1668,12 @@ __orinoco_set_multicast_list(struct net_device *dev) /* The Hermes doesn't seem to have an allmulti mode, so we go * into promiscuous mode and let the upper levels deal. */ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST(priv))) { + (netdev_mc_count(dev) > MAX_MULTICAST(priv))) { promisc = 1; mc_count = 0; } else { promisc = 0; - mc_count = dev->mc_count; + mc_count = netdev_mc_count(dev); } err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88e1e4e32b22..85905cab4f16 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1950,7 +1950,7 @@ static void set_multicast_list(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1); else { - if (local->num_multi != dev->mc_count) + if (local->num_multi != netdev_mc_count(dev)) ray_update_multi_list(dev, 0); } } /* end set_multicast_list */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 305c106fdc1c..14692bc51b51 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1492,10 +1492,10 @@ static void set_multicast_list(struct usbnet *usbdev) filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | RNDIS_PACKET_TYPE_ALL_LOCAL; } else if (usbdev->net->flags & IFF_ALLMULTI || - usbdev->net->mc_count > priv->multicast_size) { + netdev_mc_count(usbdev->net) > priv->multicast_size) { filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - } else if (usbdev->net->mc_count > 0) { - size = min(priv->multicast_size, usbdev->net->mc_count); + } else if (!netdev_mc_empty(usbdev->net)) { + size = min(priv->multicast_size, netdev_mc_count(usbdev->net)); buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); if (!buf) { devwarn(usbdev, diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 33c8be7ec8e6..5d2b52f4717f 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -879,16 +879,15 @@ static void zd1201_set_multicast(struct net_device *dev) unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; int i; - if (dev->mc_count > ZD1201_MAXMULTI) + if (netdev_mc_count(dev) > ZD1201_MAXMULTI) return; - for (i=0; imc_count; i++) { + for (i=0; idmi_addr, ETH_ALEN); mc = mc->next; } zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - dev->mc_count*ETH_ALEN, 0); - + netdev_mc_count(dev) * ETH_ALEN, 0); } static int zd1201_config_commit(struct net_device *dev, diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 8b231b30fd12..5c880240a642 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1301,15 +1301,16 @@ static void set_rx_mode(struct net_device *dev) iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ iowrite16(0x000F, ioaddr + AddrMode); - } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) { + } else if ((netdev_mc_count(dev) > 64) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well, or accept all multicasts. */ iowrite16(0x000B, ioaddr + AddrMode); - } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */ + } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */ struct dev_mc_list *mclist; u16 hash_table[4]; int i; memset(hash_table, 0, sizeof(hash_table)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { unsigned int bit; diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index 24d97b4fa6fb..bc1fad248952 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -444,11 +444,11 @@ void et131x_multicast(struct net_device *netdev) adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; } - if (netdev->mc_count > NIC_MAX_MCAST_LIST) { + if (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST) { adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; } - if (netdev->mc_count < 1) { + if (netdev_mc_count(netdev) < 1) { adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; } else { @@ -456,10 +456,10 @@ void et131x_multicast(struct net_device *netdev) } /* Set values in the private adapter struct */ - adapter->MCAddressCount = netdev->mc_count; + adapter->MCAddressCount = netdev_mc_count(netdev); - if (netdev->mc_count) { - count = netdev->mc_count - 1; + if (!netdev_mc_empty(netdev)) { + count = netdev_mc_count(netdev) - 1; memcpy(adapter->MCList[count], mclist->dmi_addr, ETH_ALEN); } diff --git a/drivers/staging/netwave/netwave_cs.c b/drivers/staging/netwave/netwave_cs.c index e61e6b9440ab..e936717d1f4b 100644 --- a/drivers/staging/netwave/netwave_cs.c +++ b/drivers/staging/netwave/netwave_cs.c @@ -1341,15 +1341,15 @@ static void set_multicast_list(struct net_device *dev) #ifdef PCMCIA_DEBUG { xstatic int old; - if (old != dev->mc_count) { - old = dev->mc_count; + if (old != netdev_mc_count(dev)) { + old = netdev_mc_count(dev); pr_debug("%s: setting Rx mode to %d addresses.\n", - dev->name, dev->mc_count); + dev->name, netdev_mc_count(dev)); } } #endif - if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { /* Multicast Mode */ rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; } else if (dev->flags & IFF_PROMISC) { diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 5b191afc1442..8c9d5e5c7702 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -1365,7 +1365,7 @@ static void slic_mcast_set_list(struct net_device *dev) int i; char *addresses; struct dev_mc_list *mc_list = dev->mc_list; - int mc_count = dev->mc_count; + int mc_count = netdev_mc_count(dev); ASSERT(adapter); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 0db8d7b6e79c..82b3a6e0b15a 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -3093,7 +3093,7 @@ static void device_set_multi(struct net_device *dev) { /* Unconditionally log net taps. */ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST); } - else if ((dev->mc_count > pDevice->multicast_limit) + else if ((netdev_mc_count(dev) > pDevice->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { MACvSelectPage1(pDevice->PortOffset); VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff); @@ -3103,7 +3103,7 @@ static void device_set_multi(struct net_device *dev) { } else { memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index ef17c4958c67..2c6a5350547c 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -1619,7 +1619,8 @@ static void device_set_multi(struct net_device *dev) { // Unconditionally log net taps. pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST); } - else if ((dev->mc_count > pDevice->multicast_limit) || (dev->flags & IFF_ALLMULTI)) { + else if ((netdev_mc_count(dev) > pDevice->multicast_limit) || + (dev->flags & IFF_ALLMULTI)) { CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_WRITE, MAC_REG_MAR0, @@ -1631,7 +1632,7 @@ static void device_set_multi(struct net_device *dev) { } else { memset(mc_filter, 0, sizeof(mc_filter)); - for (ii = 0, mclist = dev->mc_list; mclist && ii < dev->mc_count; + for (ii = 0, mclist = dev->mc_list; mclist && ii < netdev_mc_count(dev); ii++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); diff --git a/drivers/staging/wavelan/wavelan.c b/drivers/staging/wavelan/wavelan.c index d634b2da3b84..961f1417fb58 100644 --- a/drivers/staging/wavelan/wavelan.c +++ b/drivers/staging/wavelan/wavelan.c @@ -1367,7 +1367,7 @@ static void wavelan_set_multicast_list(struct net_device * dev) #ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); + dev->name, dev->flags, netdev_mc_count(dev)); #endif /* Are we asking for promiscuous mode, @@ -1375,7 +1375,7 @@ static void wavelan_set_multicast_list(struct net_device * dev) * or too many multicast addresses for the hardware filter? */ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { + (netdev_mc_count(dev) > I82586_MAX_MULTICAST_ADDRESSES)) { /* * Enable promiscuous mode: receive all packets. */ @@ -1393,11 +1393,11 @@ static void wavelan_set_multicast_list(struct net_device * dev) * in multicast list */ #ifdef MULTICAST_AVOID - if (lp->promiscuous || (dev->mc_count != lp->mc_count)) + if (lp->promiscuous || (netdev_mc_count(dev) != lp->mc_count)) #endif { lp->promiscuous = 0; - lp->mc_count = dev->mc_count; + lp->mc_count = netdev_mc_count(dev); wv_82586_reconfig(dev); } diff --git a/drivers/staging/wavelan/wavelan_cs.c b/drivers/staging/wavelan/wavelan_cs.c index 10c702b5be4a..08fcb226d7d6 100644 --- a/drivers/staging/wavelan/wavelan_cs.c +++ b/drivers/staging/wavelan/wavelan_cs.c @@ -1373,7 +1373,7 @@ wavelan_set_multicast_list(struct net_device * dev) #ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); + dev->name, dev->flags, netdev_mc_count(dev)); #endif if(dev->flags & IFF_PROMISC) @@ -1394,7 +1394,7 @@ wavelan_set_multicast_list(struct net_device * dev) /* If all multicast addresses * or too much multicast addresses for the hardware filter */ if((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + (netdev_mc_count(dev) > I82593_MAX_MULTICAST_ADDRESSES)) { /* * Disable promiscuous mode, but active the all multicast mode @@ -1418,12 +1418,12 @@ wavelan_set_multicast_list(struct net_device * dev) */ #ifdef MULTICAST_AVOID if(lp->promiscuous || lp->allmulticast || - (dev->mc_count != lp->mc_count)) + (netdev_mc_count(dev) != lp->mc_count)) #endif { lp->promiscuous = 0; lp->allmulticast = 0; - lp->mc_count = dev->mc_count; + lp->mc_count = netdev_mc_count(dev); wv_82593_reconfig(dev); } @@ -3622,7 +3622,8 @@ wv_82593_config(struct net_device * dev) if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", OP0_MC_SETUP, SR0_MC_SETUP_DONE)) ret = FALSE; - lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + /* remember to avoid repeated reset */ + lp->mc_count = netdev_mc_count(dev); } /* Job done, clear the flag */ diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index 0d22e3692fe5..a95ebf881fcd 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -1070,9 +1070,9 @@ void wl_multicast( struct net_device *dev ) ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "", ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" ); - DBG_PRINT( " mc_count: %d\n", dev->mc_count ); + DBG_PRINT( " mc_count: %d\n", netdev_mc_count(dev)); - for( x = 0, mclist = dev->mc_list; mclist && x < dev->mc_count; + for( x = 0, mclist = dev->mc_list; mclist && x < netdev_mc_count(dev); x++, mclist = mclist->next ) { DBG_PRINT( " %s (%d)\n", DbgHwAddr(mclist->dmi_addr), mclist->dmi_addrlen ); @@ -1103,7 +1103,7 @@ void wl_multicast( struct net_device *dev ) DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" ); hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); } - else if(( dev->mc_count > HCF_MAX_MULTICAST ) || + else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) || ( dev->flags & IFF_ALLMULTI )) { /* Shutting off this filter will enable all multicast frames to be sent up from the device; however, this is a static RID, so @@ -1115,13 +1115,13 @@ void wl_multicast( struct net_device *dev ) hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); wl_apply( lp ); } - else if( dev->mc_count != 0 ) { + else if (!netdev_mc_empty(dev)) { /* Set the multicast addresses */ - lp->ltvRecord.len = ( dev->mc_count * 3 ) + 1; + lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1; lp->ltvRecord.typ = CFG_GROUP_ADDR; for( x = 0, mclist = dev->mc_list; - ( x < dev->mc_count ) && ( mclist != NULL ); + ( x < netdev_mc_count(dev)) && ( mclist != NULL ); x++, mclist = mclist->next ) { memcpy( &( lp->ltvRecord.u.u8[x * ETH_ALEN] ), mclist->dmi_addr, ETH_ALEN ); diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 26fb831ef7e0..b6234b73c4cf 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -64,7 +64,7 @@ static void bnep_net_set_mc_list(struct net_device *dev) struct sk_buff *skb; int size; - BT_DBG("%s mc_count %d", dev->name, dev->mc_count); + BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev)); size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; skb = alloc_skb(size, GFP_ATOMIC); @@ -97,7 +97,9 @@ static void bnep_net_set_mc_list(struct net_device *dev) /* FIXME: We should group addresses here. */ - for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) { + for (i = 0; + i < netdev_mc_count(dev) && i < BNEP_MAX_MULTICAST_FILTERS; + i++) { memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); dmi = dmi->next; diff --git a/net/core/dev.c b/net/core/dev.c index ae75f25ac0a5..d1cf53d0d597 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4263,7 +4263,7 @@ static void dev_addr_discard(struct net_device *dev) netif_addr_lock_bh(dev); __dev_addr_discard(&dev->mc_list); - dev->mc_count = 0; + netdev_mc_count(dev) = 0; netif_addr_unlock_bh(dev); } diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index d340110f5c0c..9616c32d1076 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -321,14 +321,15 @@ static void irlan_eth_set_multicast_list(struct net_device *dev) /* Enable promiscuous mode */ IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n"); } - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) { + else if ((dev->flags & IFF_ALLMULTI) || + netdev_mc_count(dev) > HW_MAX_ADDRS) { /* Disable promiscuous mode, use normal mode. */ IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* hardware_set_filter(NULL); */ irlan_set_multicast_filter(self, TRUE); } - else if (dev->mc_count) { + else if (!netdev_mc_empty(dev)) { IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* Walk the address list, and load the filter */ /* hardware_set_filter(dev->mc_list); */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 09fff4662e80..f943f5fa7286 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -413,7 +413,7 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_lock_bh(dev); spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, - &dev->mc_list, &dev->mc_count); + &dev->mc_list, dev->mc_count); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); -- GitLab From 7455a76f170f794498d26081a5f15b797ef1a2aa Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Feb 2010 05:12:08 +0000 Subject: [PATCH 1962/3892] macb: straighten out macb_mii_probe function Use "phy_find_first" instead of manual lookup. Also use "phy_connect_direct" instead of "phy_connect" since we already have phy_device pointer here. Signed-off-by: Jiri Pirko Acked-by: Haavard Skinnemoen Signed-off-by: David S. Miller --- drivers/net/macb.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index fbc371fa19b5..7a5f89728a81 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -189,18 +189,11 @@ static void macb_handle_link_change(struct net_device *dev) static int macb_mii_probe(struct net_device *dev) { struct macb *bp = netdev_priv(dev); - struct phy_device *phydev = NULL; + struct phy_device *phydev; struct eth_platform_data *pdata; - int phy_addr; - - /* find the first phy */ - for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (bp->mii_bus->phy_map[phy_addr]) { - phydev = bp->mii_bus->phy_map[phy_addr]; - break; - } - } + int ret; + phydev = phy_find_first(bp->mii_bus); if (!phydev) { printk (KERN_ERR "%s: no PHY found\n", dev->name); return -1; @@ -210,17 +203,13 @@ static int macb_mii_probe(struct net_device *dev) /* TODO : add pin_irq */ /* attach the mac to the phy */ - if (pdata && pdata->is_rmii) { - phydev = phy_connect(dev, dev_name(&phydev->dev), - &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); - } else { - phydev = phy_connect(dev, dev_name(&phydev->dev), - &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII); - } - - if (IS_ERR(phydev)) { + ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, + pdata && pdata->is_rmii ? + PHY_INTERFACE_MODE_RMII : + PHY_INTERFACE_MODE_MII); + if (ret) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); + return ret; } /* mask with MAC supported features */ -- GitLab From 87185517de81101da5afbc82cefdeed6eeaa38fb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 3 Feb 2010 19:43:31 +0000 Subject: [PATCH 1963/3892] xfs: only clear the suid bit once in xfs_write file_remove_suid already calls into ->setattr to clear the suid and sgid bits if needed, no need to start a second transaction to do it ourselves. Note that xfs_write_clear_setuid issues a sync transaction while the path through ->setattr doesn't, but that is consistant with the other filesystems. Signed-off-by: Christoph Hellwig Reviewed-by: Alex Elder Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_lrw.c | 15 +++----------- fs/xfs/xfs_rw.c | 42 -------------------------------------- fs/xfs/xfs_rw.h | 1 - 3 files changed, 3 insertions(+), 55 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index c80fa00d2ad7..eac6f80d786d 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -630,18 +630,9 @@ start: * by root. This keeps people from modifying setuid and * setgid binaries. */ - - if (((xip->i_d.di_mode & S_ISUID) || - ((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) == - (S_ISGID | S_IXGRP))) && - !capable(CAP_FSETID)) { - error = xfs_write_clear_setuid(xip); - if (likely(!error)) - error = -file_remove_suid(file); - if (unlikely(error)) { - goto out_unlock_internal; - } - } + error = -file_remove_suid(file); + if (unlikely(error)) + goto out_unlock_internal; /* We can write back this queue in page reclaim */ current->backing_dev_info = mapping->backing_dev_info; diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index abb2c458b148..e336742a58a4 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c @@ -46,48 +46,6 @@ #include "xfs_rw.h" #include "xfs_trace.h" -/* - * This is a subroutine for xfs_write() and other writers (xfs_ioctl) - * which clears the setuid and setgid bits when a file is written. - */ -int -xfs_write_clear_setuid( - xfs_inode_t *ip) -{ - xfs_mount_t *mp; - xfs_trans_t *tp; - int error; - - mp = ip->i_mount; - tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); - if ((error = xfs_trans_reserve(tp, 0, - XFS_WRITEID_LOG_RES(mp), - 0, 0, 0))) { - xfs_trans_cancel(tp, 0); - return error; - } - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_ihold(tp, ip); - ip->i_d.di_mode &= ~S_ISUID; - - /* - * Note that we don't have to worry about mandatory - * file locking being disabled here because we only - * clear the S_ISGID bit if the Group execute bit is - * on, but if it was on then mandatory locking wouldn't - * have been enabled. - */ - if (ip->i_d.di_mode & S_IXGRP) { - ip->i_d.di_mode &= ~S_ISGID; - } - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - xfs_trans_set_sync(tp); - error = xfs_trans_commit(tp, 0); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; -} - /* * Force a shutdown of the filesystem instantly while keeping * the filesystem consistent. We don't do an unmount here; just shutdown diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index a54c3b7cd376..11c41ec6ed75 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h @@ -39,7 +39,6 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) /* * Prototypes for functions in xfs_rw.c. */ -extern int xfs_write_clear_setuid(struct xfs_inode *ip); extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp, xfs_daddr_t blkno, int len, uint flags, struct xfs_buf **bpp); -- GitLab From 180040b89ee2aed88c0a0b1fcf7ada9a512b12e3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 5 Feb 2010 09:57:55 +0000 Subject: [PATCH 1964/3892] xfs: optimize log flushing in xfs_fsync If we have a pinned inode it must have a log item attached to it. Usually that log item will have ili_last_lsn already set, in which case we only need to flush the log up to that LSN instead of doing a full log force. This gives speedups of about 5% in some fsync heavy workloads. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_vnodeops.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 43241e289800..ddd2c5d1b854 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -629,8 +629,14 @@ xfs_fsync( */ xfs_iunlock(ip, XFS_ILOCK_SHARED); if (xfs_ipincount(ip)) { - error = _xfs_log_force(ip->i_mount, XFS_LOG_SYNC, - &log_flushed); + if (ip->i_itemp->ili_last_lsn) { + error = _xfs_log_force_lsn(ip->i_mount, + ip->i_itemp->ili_last_lsn, + XFS_LOG_SYNC, &log_flushed); + } else { + error = _xfs_log_force(ip->i_mount, + XFS_LOG_SYNC, &log_flushed); + } } } else { /* -- GitLab From 69a6a0b38a139ccceef32222108caca8a9b0b795 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 7 Feb 2010 20:20:28 +0000 Subject: [PATCH 1965/3892] dccp: allow probing of CCID-array length This fixes a problem in the DCCP getsockopt() API: currently there is no way for a user to a priori know the number of built-in CCIDs, other than trying DCCP_SOCKOPT_AVAILABLE_CCIDS in a loop, incrementing the option length until EINVAL is no longer returned. This patch truncates the array to the user-provided length. No copy is made when the length is <= 0. Due to the length restriction in do_dccp_getsockopt() to sizeof(int), the minimum array length remains 4, which is a reasonable default (only 3 CCIDs, CCID-2..4, are currently defined). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- Documentation/networking/dccp.txt | 6 ++++-- net/dccp/ccid.c | 9 ++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index b132e4a3cf0f..a62fdf7a6bff 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -58,8 +58,10 @@ DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet size (application payload size) in bytes, see RFC 4340, section 14. DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs -supported by the endpoint (see include/linux/dccp.h for symbolic constants). -The caller needs to provide a sufficiently large (> 2) array of type uint8_t. +supported by the endpoint. The option value is an array of type uint8_t whose +size is passed as option length. The minimum array size is 4 elements, the +value returned in the optlen argument always reflects the true number of +built-in CCIDs. DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same time, combining the operation of the next two socket options. This option is diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index ff16e9df1969..49d27c556bec 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c @@ -63,14 +63,13 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, u8 *ccid_array, array_len; int err = 0; - if (len < ARRAY_SIZE(ccids)) - return -EINVAL; - if (ccid_get_builtin_ccids(&ccid_array, &array_len)) return -ENOBUFS; - if (put_user(array_len, optlen) || - copy_to_user(optval, ccid_array, array_len)) + if (put_user(array_len, optlen)) + err = -EFAULT; + else if (len > 0 && copy_to_user(optval, ccid_array, + len > array_len ? array_len : len)) err = -EFAULT; kfree(ccid_array); -- GitLab From 2bec5a369ee79576a3eea2c23863325089785a2c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 8 Feb 2010 05:19:03 +0000 Subject: [PATCH 1966/3892] ipv6: fib: fix crash when changing large fib while dumping it When the fib size exceeds what can be dumped in a single skb, the dump is suspended and resumed once the last skb has been received by userspace. When the fib is changed while the dump is suspended, the walker might contain stale pointers, causing a crash when the dump is resumed. BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [] fib6_walk_continue+0xbb/0x124 [ipv6] PGD 5347a067 PUD 65c7067 PMD 0 Oops: 0000 [#1] PREEMPT SMP ... RIP: 0010:[] [] fib6_walk_continue+0xbb/0x124 [ipv6] ... Call Trace: [] ? mutex_spin_on_owner+0x59/0x71 [] inet6_dump_fib+0x11b/0x1b9 [ipv6] [] netlink_dump+0x5b/0x19e [] ? consume_skb+0x28/0x2a [] netlink_recvmsg+0x1ab/0x2c6 [] ? netlink_unicast+0xfa/0x151 [] __sock_recvmsg+0x6d/0x79 [] sock_recvmsg+0xca/0xe3 [] ? autoremove_wake_function+0x0/0x38 [] ? radix_tree_lookup_slot+0xe/0x10 [] ? find_get_page+0x90/0xa5 [] ? filemap_fault+0x201/0x34f [] ? fget_light+0x2f/0xac [] ? verify_iovec+0x4f/0x94 [] sys_recvmsg+0x14d/0x223 Store the serial number when beginning to walk the fib and reload pointers when continuing to walk after a change occured. Similar to other dumping functions, this might cause unrelated entries to be missed when entries are deleted. Tested-by: Ben Greear Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 2 ++ net/ipv6/ip6_fib.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 257808188add..8f279ddb3593 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -129,6 +129,8 @@ struct fib6_walker_t { struct rt6_info *leaf; unsigned char state; unsigned char prune; + unsigned int skip; + unsigned int count; int (*func)(struct fib6_walker_t *); void *args; }; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f626ea2b304f..77e122f53ea6 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -319,12 +319,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, w->root = &table->tb6_root; if (cb->args[4] == 0) { + w->count = 0; + w->skip = 0; + read_lock_bh(&table->tb6_lock); res = fib6_walk(w); read_unlock_bh(&table->tb6_lock); - if (res > 0) + if (res > 0) { cb->args[4] = 1; + cb->args[5] = w->root->fn_sernum; + } } else { + if (cb->args[5] != w->root->fn_sernum) { + /* Begin at the root if the tree changed */ + cb->args[5] = w->root->fn_sernum; + w->state = FWS_INIT; + w->node = w->root; + w->skip = w->count; + } else + w->skip = 0; + read_lock_bh(&table->tb6_lock); res = fib6_walk_continue(w); read_unlock_bh(&table->tb6_lock); @@ -1250,9 +1264,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) w->leaf = fn->leaf; case FWS_C: if (w->leaf && fn->fn_flags&RTN_RTINFO) { - int err = w->func(w); + int err; + + if (w->count < w->skip) { + w->count++; + continue; + } + + err = w->func(w); if (err) return err; + + w->count++; continue; } w->state = FWS_U; @@ -1346,6 +1369,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, c.w.root = root; c.w.func = fib6_clean_node; c.w.prune = prune; + c.w.count = 0; + c.w.skip = 0; c.func = func; c.arg = arg; c.net = net; -- GitLab From 0da2b300b91ddeb9944c3fb4faaf78c1c482c0af Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Fri, 12 Feb 2010 12:08:51 -0800 Subject: [PATCH 1967/3892] sparc: remove trailing space in messages Also fixes a typo in one message. Signed-off-by: Frans Pop Signed-off-by: David S. Miller --- arch/sparc/kernel/leon_kernel.c | 2 +- arch/sparc/kernel/leon_smp.c | 4 ++-- arch/sparc/kernel/sun4d_smp.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 87f1760c0aa2..0409d62d8ca2 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -124,7 +124,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & (1<mpstatus)); @@ -226,7 +226,7 @@ int __cpuinit leon_boot_one_cpu(int i) break; udelay(200); } - printk(KERN_INFO "Started CPU %d \n", (unsigned int)i); + printk(KERN_INFO "Started CPU %d\n", (unsigned int)i); if (!(cpu_callin_map[i])) { printk(KERN_ERR "Processor %d is stuck.\n", i); diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 68791cad7b74..482f2ab92692 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -194,7 +194,7 @@ int __cpuinit smp4d_boot_one_cpu(int i) smp_penguin_ctable.reg_size = 0; /* whirrr, whirrr, whirrrrrrrrr... */ - SMP_PRINTK(("Starting CPU %d at %p \n", i, entry)); + SMP_PRINTK(("Starting CPU %d at %p\n", i, entry)); local_flush_cache_all(); prom_startcpu(cpu_node, &smp_penguin_ctable, 0, (char *)entry); -- GitLab From 447d8c2603a417cca68240059fbf1babfd27774f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Feb 2010 12:10:47 -0800 Subject: [PATCH 1968/3892] net: move am79c961's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to am79c961_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Signed-off-by: David S. Miller --- drivers/net/arm/am79c961a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 164b37e85eea..1c3c1f94268e 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -680,7 +680,7 @@ static const struct net_device_ops am79c961_netdev_ops = { #endif }; -static int __init am79c961_probe(struct platform_device *pdev) +static int __devinit am79c961_probe(struct platform_device *pdev) { struct resource *res; struct net_device *dev; -- GitLab From 8ca86fd83eae6c73db5f6b23ee3a63b77d52c8ee Mon Sep 17 00:00:00 2001 From: Tristram Ha Date: Mon, 8 Feb 2010 11:36:53 +0000 Subject: [PATCH 1969/3892] net: Micrel KSZ8841/2 PCI Ethernet driver This is a new network driver for Micrel KSZ8841/KSZ8842 PCI Ethernet chips. The same driver can run both chips at the same time. It supports IPv4 TCP hardware checksumming and so can use scatter/gather transmission. The KSZ8842 switch has 2 ports. Some users like to take direct control of those ports. So KSZ8842 has a multiple devices mode in which the driver creates another network device so that users can specify which port to send packets. This mode is enabled by passing the "multi_dev=1" parameter to the driver during loading. The KSZ884X can receive huge frames with size up to 1916 bytes. To use this feature change the network device MTU from 1500 to 1898. The KSZ884X driver has 3 packet receive processing functions for the normal mode, multiple devices mode, and huge frame mode. Those functions are identical except for more checking for the new features. In normal programming point of view the huge frame version is the one to use because it covers all the cases, but this is done for performance consideration because the target clients for the KSZ884X chips are embedded systems, which unlike desktop PC may not have powerful CPU. Signed-off-by: Tristram Ha Signed-off-by: David S. Miller --- drivers/net/ksz884x.c | 7335 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 7335 insertions(+) create mode 100644 drivers/net/ksz884x.c diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c new file mode 100644 index 000000000000..6f187c7e61fa --- /dev/null +++ b/drivers/net/ksz884x.c @@ -0,0 +1,7335 @@ +/** + * drivers/net/ksx884x.c - Micrel KSZ8841/2 PCI Ethernet driver + * + * Copyright (c) 2009-2010 Micrel, Inc. + * Tristram Ha + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* DMA Registers */ + +#define KS_DMA_TX_CTRL 0x0000 +#define DMA_TX_ENABLE 0x00000001 +#define DMA_TX_CRC_ENABLE 0x00000002 +#define DMA_TX_PAD_ENABLE 0x00000004 +#define DMA_TX_LOOPBACK 0x00000100 +#define DMA_TX_FLOW_ENABLE 0x00000200 +#define DMA_TX_CSUM_IP 0x00010000 +#define DMA_TX_CSUM_TCP 0x00020000 +#define DMA_TX_CSUM_UDP 0x00040000 +#define DMA_TX_BURST_SIZE 0x3F000000 + +#define KS_DMA_RX_CTRL 0x0004 +#define DMA_RX_ENABLE 0x00000001 +#define KS884X_DMA_RX_MULTICAST 0x00000002 +#define DMA_RX_PROMISCUOUS 0x00000004 +#define DMA_RX_ERROR 0x00000008 +#define DMA_RX_UNICAST 0x00000010 +#define DMA_RX_ALL_MULTICAST 0x00000020 +#define DMA_RX_BROADCAST 0x00000040 +#define DMA_RX_FLOW_ENABLE 0x00000200 +#define DMA_RX_CSUM_IP 0x00010000 +#define DMA_RX_CSUM_TCP 0x00020000 +#define DMA_RX_CSUM_UDP 0x00040000 +#define DMA_RX_BURST_SIZE 0x3F000000 + +#define DMA_BURST_SHIFT 24 +#define DMA_BURST_DEFAULT 8 + +#define KS_DMA_TX_START 0x0008 +#define KS_DMA_RX_START 0x000C +#define DMA_START 0x00000001 + +#define KS_DMA_TX_ADDR 0x0010 +#define KS_DMA_RX_ADDR 0x0014 + +#define DMA_ADDR_LIST_MASK 0xFFFFFFFC +#define DMA_ADDR_LIST_SHIFT 2 + +/* MTR0 */ +#define KS884X_MULTICAST_0_OFFSET 0x0020 +#define KS884X_MULTICAST_1_OFFSET 0x0021 +#define KS884X_MULTICAST_2_OFFSET 0x0022 +#define KS884x_MULTICAST_3_OFFSET 0x0023 +/* MTR1 */ +#define KS884X_MULTICAST_4_OFFSET 0x0024 +#define KS884X_MULTICAST_5_OFFSET 0x0025 +#define KS884X_MULTICAST_6_OFFSET 0x0026 +#define KS884X_MULTICAST_7_OFFSET 0x0027 + +/* Interrupt Registers */ + +/* INTEN */ +#define KS884X_INTERRUPTS_ENABLE 0x0028 +/* INTST */ +#define KS884X_INTERRUPTS_STATUS 0x002C + +#define KS884X_INT_RX_STOPPED 0x02000000 +#define KS884X_INT_TX_STOPPED 0x04000000 +#define KS884X_INT_RX_OVERRUN 0x08000000 +#define KS884X_INT_TX_EMPTY 0x10000000 +#define KS884X_INT_RX 0x20000000 +#define KS884X_INT_TX 0x40000000 +#define KS884X_INT_PHY 0x80000000 + +#define KS884X_INT_RX_MASK \ + (KS884X_INT_RX | KS884X_INT_RX_OVERRUN) +#define KS884X_INT_TX_MASK \ + (KS884X_INT_TX | KS884X_INT_TX_EMPTY) +#define KS884X_INT_MASK (KS884X_INT_RX | KS884X_INT_TX | KS884X_INT_PHY) + +/* MAC Additional Station Address */ + +/* MAAL0 */ +#define KS_ADD_ADDR_0_LO 0x0080 +/* MAAH0 */ +#define KS_ADD_ADDR_0_HI 0x0084 +/* MAAL1 */ +#define KS_ADD_ADDR_1_LO 0x0088 +/* MAAH1 */ +#define KS_ADD_ADDR_1_HI 0x008C +/* MAAL2 */ +#define KS_ADD_ADDR_2_LO 0x0090 +/* MAAH2 */ +#define KS_ADD_ADDR_2_HI 0x0094 +/* MAAL3 */ +#define KS_ADD_ADDR_3_LO 0x0098 +/* MAAH3 */ +#define KS_ADD_ADDR_3_HI 0x009C +/* MAAL4 */ +#define KS_ADD_ADDR_4_LO 0x00A0 +/* MAAH4 */ +#define KS_ADD_ADDR_4_HI 0x00A4 +/* MAAL5 */ +#define KS_ADD_ADDR_5_LO 0x00A8 +/* MAAH5 */ +#define KS_ADD_ADDR_5_HI 0x00AC +/* MAAL6 */ +#define KS_ADD_ADDR_6_LO 0x00B0 +/* MAAH6 */ +#define KS_ADD_ADDR_6_HI 0x00B4 +/* MAAL7 */ +#define KS_ADD_ADDR_7_LO 0x00B8 +/* MAAH7 */ +#define KS_ADD_ADDR_7_HI 0x00BC +/* MAAL8 */ +#define KS_ADD_ADDR_8_LO 0x00C0 +/* MAAH8 */ +#define KS_ADD_ADDR_8_HI 0x00C4 +/* MAAL9 */ +#define KS_ADD_ADDR_9_LO 0x00C8 +/* MAAH9 */ +#define KS_ADD_ADDR_9_HI 0x00CC +/* MAAL10 */ +#define KS_ADD_ADDR_A_LO 0x00D0 +/* MAAH10 */ +#define KS_ADD_ADDR_A_HI 0x00D4 +/* MAAL11 */ +#define KS_ADD_ADDR_B_LO 0x00D8 +/* MAAH11 */ +#define KS_ADD_ADDR_B_HI 0x00DC +/* MAAL12 */ +#define KS_ADD_ADDR_C_LO 0x00E0 +/* MAAH12 */ +#define KS_ADD_ADDR_C_HI 0x00E4 +/* MAAL13 */ +#define KS_ADD_ADDR_D_LO 0x00E8 +/* MAAH13 */ +#define KS_ADD_ADDR_D_HI 0x00EC +/* MAAL14 */ +#define KS_ADD_ADDR_E_LO 0x00F0 +/* MAAH14 */ +#define KS_ADD_ADDR_E_HI 0x00F4 +/* MAAL15 */ +#define KS_ADD_ADDR_F_LO 0x00F8 +/* MAAH15 */ +#define KS_ADD_ADDR_F_HI 0x00FC + +#define ADD_ADDR_HI_MASK 0x0000FFFF +#define ADD_ADDR_ENABLE 0x80000000 +#define ADD_ADDR_INCR 8 + +/* Miscellaneous Registers */ + +/* MARL */ +#define KS884X_ADDR_0_OFFSET 0x0200 +#define KS884X_ADDR_1_OFFSET 0x0201 +/* MARM */ +#define KS884X_ADDR_2_OFFSET 0x0202 +#define KS884X_ADDR_3_OFFSET 0x0203 +/* MARH */ +#define KS884X_ADDR_4_OFFSET 0x0204 +#define KS884X_ADDR_5_OFFSET 0x0205 + +/* OBCR */ +#define KS884X_BUS_CTRL_OFFSET 0x0210 + +#define BUS_SPEED_125_MHZ 0x0000 +#define BUS_SPEED_62_5_MHZ 0x0001 +#define BUS_SPEED_41_66_MHZ 0x0002 +#define BUS_SPEED_25_MHZ 0x0003 + +/* EEPCR */ +#define KS884X_EEPROM_CTRL_OFFSET 0x0212 + +#define EEPROM_CHIP_SELECT 0x0001 +#define EEPROM_SERIAL_CLOCK 0x0002 +#define EEPROM_DATA_OUT 0x0004 +#define EEPROM_DATA_IN 0x0008 +#define EEPROM_ACCESS_ENABLE 0x0010 + +/* MBIR */ +#define KS884X_MEM_INFO_OFFSET 0x0214 + +#define RX_MEM_TEST_FAILED 0x0008 +#define RX_MEM_TEST_FINISHED 0x0010 +#define TX_MEM_TEST_FAILED 0x0800 +#define TX_MEM_TEST_FINISHED 0x1000 + +/* GCR */ +#define KS884X_GLOBAL_CTRL_OFFSET 0x0216 +#define GLOBAL_SOFTWARE_RESET 0x0001 + +#define KS8841_POWER_MANAGE_OFFSET 0x0218 + +/* WFCR */ +#define KS8841_WOL_CTRL_OFFSET 0x021A +#define KS8841_WOL_MAGIC_ENABLE 0x0080 +#define KS8841_WOL_FRAME3_ENABLE 0x0008 +#define KS8841_WOL_FRAME2_ENABLE 0x0004 +#define KS8841_WOL_FRAME1_ENABLE 0x0002 +#define KS8841_WOL_FRAME0_ENABLE 0x0001 + +/* WF0 */ +#define KS8841_WOL_FRAME_CRC_OFFSET 0x0220 +#define KS8841_WOL_FRAME_BYTE0_OFFSET 0x0224 +#define KS8841_WOL_FRAME_BYTE2_OFFSET 0x0228 + +/* IACR */ +#define KS884X_IACR_P 0x04A0 +#define KS884X_IACR_OFFSET KS884X_IACR_P + +/* IADR1 */ +#define KS884X_IADR1_P 0x04A2 +#define KS884X_IADR2_P 0x04A4 +#define KS884X_IADR3_P 0x04A6 +#define KS884X_IADR4_P 0x04A8 +#define KS884X_IADR5_P 0x04AA + +#define KS884X_ACC_CTRL_SEL_OFFSET KS884X_IACR_P +#define KS884X_ACC_CTRL_INDEX_OFFSET (KS884X_ACC_CTRL_SEL_OFFSET + 1) + +#define KS884X_ACC_DATA_0_OFFSET KS884X_IADR4_P +#define KS884X_ACC_DATA_1_OFFSET (KS884X_ACC_DATA_0_OFFSET + 1) +#define KS884X_ACC_DATA_2_OFFSET KS884X_IADR5_P +#define KS884X_ACC_DATA_3_OFFSET (KS884X_ACC_DATA_2_OFFSET + 1) +#define KS884X_ACC_DATA_4_OFFSET KS884X_IADR2_P +#define KS884X_ACC_DATA_5_OFFSET (KS884X_ACC_DATA_4_OFFSET + 1) +#define KS884X_ACC_DATA_6_OFFSET KS884X_IADR3_P +#define KS884X_ACC_DATA_7_OFFSET (KS884X_ACC_DATA_6_OFFSET + 1) +#define KS884X_ACC_DATA_8_OFFSET KS884X_IADR1_P + +/* P1MBCR */ +#define KS884X_P1MBCR_P 0x04D0 +#define KS884X_P1MBSR_P 0x04D2 +#define KS884X_PHY1ILR_P 0x04D4 +#define KS884X_PHY1IHR_P 0x04D6 +#define KS884X_P1ANAR_P 0x04D8 +#define KS884X_P1ANLPR_P 0x04DA + +/* P2MBCR */ +#define KS884X_P2MBCR_P 0x04E0 +#define KS884X_P2MBSR_P 0x04E2 +#define KS884X_PHY2ILR_P 0x04E4 +#define KS884X_PHY2IHR_P 0x04E6 +#define KS884X_P2ANAR_P 0x04E8 +#define KS884X_P2ANLPR_P 0x04EA + +#define KS884X_PHY_1_CTRL_OFFSET KS884X_P1MBCR_P +#define PHY_CTRL_INTERVAL (KS884X_P2MBCR_P - KS884X_P1MBCR_P) + +#define KS884X_PHY_CTRL_OFFSET 0x00 + +/* Mode Control Register */ +#define PHY_REG_CTRL 0 + +#define PHY_RESET 0x8000 +#define PHY_LOOPBACK 0x4000 +#define PHY_SPEED_100MBIT 0x2000 +#define PHY_AUTO_NEG_ENABLE 0x1000 +#define PHY_POWER_DOWN 0x0800 +#define PHY_MII_DISABLE 0x0400 +#define PHY_AUTO_NEG_RESTART 0x0200 +#define PHY_FULL_DUPLEX 0x0100 +#define PHY_COLLISION_TEST 0x0080 +#define PHY_HP_MDIX 0x0020 +#define PHY_FORCE_MDIX 0x0010 +#define PHY_AUTO_MDIX_DISABLE 0x0008 +#define PHY_REMOTE_FAULT_DISABLE 0x0004 +#define PHY_TRANSMIT_DISABLE 0x0002 +#define PHY_LED_DISABLE 0x0001 + +#define KS884X_PHY_STATUS_OFFSET 0x02 + +/* Mode Status Register */ +#define PHY_REG_STATUS 1 + +#define PHY_100BT4_CAPABLE 0x8000 +#define PHY_100BTX_FD_CAPABLE 0x4000 +#define PHY_100BTX_CAPABLE 0x2000 +#define PHY_10BT_FD_CAPABLE 0x1000 +#define PHY_10BT_CAPABLE 0x0800 +#define PHY_MII_SUPPRESS_CAPABLE 0x0040 +#define PHY_AUTO_NEG_ACKNOWLEDGE 0x0020 +#define PHY_REMOTE_FAULT 0x0010 +#define PHY_AUTO_NEG_CAPABLE 0x0008 +#define PHY_LINK_STATUS 0x0004 +#define PHY_JABBER_DETECT 0x0002 +#define PHY_EXTENDED_CAPABILITY 0x0001 + +#define KS884X_PHY_ID_1_OFFSET 0x04 +#define KS884X_PHY_ID_2_OFFSET 0x06 + +/* PHY Identifier Registers */ +#define PHY_REG_ID_1 2 +#define PHY_REG_ID_2 3 + +#define KS884X_PHY_AUTO_NEG_OFFSET 0x08 + +/* Auto-Negotiation Advertisement Register */ +#define PHY_REG_AUTO_NEGOTIATION 4 + +#define PHY_AUTO_NEG_NEXT_PAGE 0x8000 +#define PHY_AUTO_NEG_REMOTE_FAULT 0x2000 +/* Not supported. */ +#define PHY_AUTO_NEG_ASYM_PAUSE 0x0800 +#define PHY_AUTO_NEG_SYM_PAUSE 0x0400 +#define PHY_AUTO_NEG_100BT4 0x0200 +#define PHY_AUTO_NEG_100BTX_FD 0x0100 +#define PHY_AUTO_NEG_100BTX 0x0080 +#define PHY_AUTO_NEG_10BT_FD 0x0040 +#define PHY_AUTO_NEG_10BT 0x0020 +#define PHY_AUTO_NEG_SELECTOR 0x001F +#define PHY_AUTO_NEG_802_3 0x0001 + +#define PHY_AUTO_NEG_PAUSE (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE) + +#define KS884X_PHY_REMOTE_CAP_OFFSET 0x0A + +/* Auto-Negotiation Link Partner Ability Register */ +#define PHY_REG_REMOTE_CAPABILITY 5 + +#define PHY_REMOTE_NEXT_PAGE 0x8000 +#define PHY_REMOTE_ACKNOWLEDGE 0x4000 +#define PHY_REMOTE_REMOTE_FAULT 0x2000 +#define PHY_REMOTE_SYM_PAUSE 0x0400 +#define PHY_REMOTE_100BTX_FD 0x0100 +#define PHY_REMOTE_100BTX 0x0080 +#define PHY_REMOTE_10BT_FD 0x0040 +#define PHY_REMOTE_10BT 0x0020 + +/* P1VCT */ +#define KS884X_P1VCT_P 0x04F0 +#define KS884X_P1PHYCTRL_P 0x04F2 + +/* P2VCT */ +#define KS884X_P2VCT_P 0x04F4 +#define KS884X_P2PHYCTRL_P 0x04F6 + +#define KS884X_PHY_SPECIAL_OFFSET KS884X_P1VCT_P +#define PHY_SPECIAL_INTERVAL (KS884X_P2VCT_P - KS884X_P1VCT_P) + +#define KS884X_PHY_LINK_MD_OFFSET 0x00 + +#define PHY_START_CABLE_DIAG 0x8000 +#define PHY_CABLE_DIAG_RESULT 0x6000 +#define PHY_CABLE_STAT_NORMAL 0x0000 +#define PHY_CABLE_STAT_OPEN 0x2000 +#define PHY_CABLE_STAT_SHORT 0x4000 +#define PHY_CABLE_STAT_FAILED 0x6000 +#define PHY_CABLE_10M_SHORT 0x1000 +#define PHY_CABLE_FAULT_COUNTER 0x01FF + +#define KS884X_PHY_PHY_CTRL_OFFSET 0x02 + +#define PHY_STAT_REVERSED_POLARITY 0x0020 +#define PHY_STAT_MDIX 0x0010 +#define PHY_FORCE_LINK 0x0008 +#define PHY_POWER_SAVING_DISABLE 0x0004 +#define PHY_REMOTE_LOOPBACK 0x0002 + +/* SIDER */ +#define KS884X_SIDER_P 0x0400 +#define KS884X_CHIP_ID_OFFSET KS884X_SIDER_P +#define KS884X_FAMILY_ID_OFFSET (KS884X_CHIP_ID_OFFSET + 1) + +#define REG_FAMILY_ID 0x88 + +#define REG_CHIP_ID_41 0x8810 +#define REG_CHIP_ID_42 0x8800 + +#define KS884X_CHIP_ID_MASK_41 0xFF10 +#define KS884X_CHIP_ID_MASK 0xFFF0 +#define KS884X_CHIP_ID_SHIFT 4 +#define KS884X_REVISION_MASK 0x000E +#define KS884X_REVISION_SHIFT 1 +#define KS8842_START 0x0001 + +#define CHIP_IP_41_M 0x8810 +#define CHIP_IP_42_M 0x8800 +#define CHIP_IP_61_M 0x8890 +#define CHIP_IP_62_M 0x8880 + +#define CHIP_IP_41_P 0x8850 +#define CHIP_IP_42_P 0x8840 +#define CHIP_IP_61_P 0x88D0 +#define CHIP_IP_62_P 0x88C0 + +/* SGCR1 */ +#define KS8842_SGCR1_P 0x0402 +#define KS8842_SWITCH_CTRL_1_OFFSET KS8842_SGCR1_P + +#define SWITCH_PASS_ALL 0x8000 +#define SWITCH_TX_FLOW_CTRL 0x2000 +#define SWITCH_RX_FLOW_CTRL 0x1000 +#define SWITCH_CHECK_LENGTH 0x0800 +#define SWITCH_AGING_ENABLE 0x0400 +#define SWITCH_FAST_AGING 0x0200 +#define SWITCH_AGGR_BACKOFF 0x0100 +#define SWITCH_PASS_PAUSE 0x0008 +#define SWITCH_LINK_AUTO_AGING 0x0001 + +/* SGCR2 */ +#define KS8842_SGCR2_P 0x0404 +#define KS8842_SWITCH_CTRL_2_OFFSET KS8842_SGCR2_P + +#define SWITCH_VLAN_ENABLE 0x8000 +#define SWITCH_IGMP_SNOOP 0x4000 +#define IPV6_MLD_SNOOP_ENABLE 0x2000 +#define IPV6_MLD_SNOOP_OPTION 0x1000 +#define PRIORITY_SCHEME_SELECT 0x0800 +#define SWITCH_MIRROR_RX_TX 0x0100 +#define UNICAST_VLAN_BOUNDARY 0x0080 +#define MULTICAST_STORM_DISABLE 0x0040 +#define SWITCH_BACK_PRESSURE 0x0020 +#define FAIR_FLOW_CTRL 0x0010 +#define NO_EXC_COLLISION_DROP 0x0008 +#define SWITCH_HUGE_PACKET 0x0004 +#define SWITCH_LEGAL_PACKET 0x0002 +#define SWITCH_BUF_RESERVE 0x0001 + +/* SGCR3 */ +#define KS8842_SGCR3_P 0x0406 +#define KS8842_SWITCH_CTRL_3_OFFSET KS8842_SGCR3_P + +#define BROADCAST_STORM_RATE_LO 0xFF00 +#define SWITCH_REPEATER 0x0080 +#define SWITCH_HALF_DUPLEX 0x0040 +#define SWITCH_FLOW_CTRL 0x0020 +#define SWITCH_10_MBIT 0x0010 +#define SWITCH_REPLACE_NULL_VID 0x0008 +#define BROADCAST_STORM_RATE_HI 0x0007 + +#define BROADCAST_STORM_RATE 0x07FF + +/* SGCR4 */ +#define KS8842_SGCR4_P 0x0408 + +/* SGCR5 */ +#define KS8842_SGCR5_P 0x040A +#define KS8842_SWITCH_CTRL_5_OFFSET KS8842_SGCR5_P + +#define LED_MODE 0x8200 +#define LED_SPEED_DUPLEX_ACT 0x0000 +#define LED_SPEED_DUPLEX_LINK_ACT 0x8000 +#define LED_DUPLEX_10_100 0x0200 + +/* SGCR6 */ +#define KS8842_SGCR6_P 0x0410 +#define KS8842_SWITCH_CTRL_6_OFFSET KS8842_SGCR6_P + +#define KS8842_PRIORITY_MASK 3 +#define KS8842_PRIORITY_SHIFT 2 + +/* SGCR7 */ +#define KS8842_SGCR7_P 0x0412 +#define KS8842_SWITCH_CTRL_7_OFFSET KS8842_SGCR7_P + +#define SWITCH_UNK_DEF_PORT_ENABLE 0x0008 +#define SWITCH_UNK_DEF_PORT_3 0x0004 +#define SWITCH_UNK_DEF_PORT_2 0x0002 +#define SWITCH_UNK_DEF_PORT_1 0x0001 + +/* MACAR1 */ +#define KS8842_MACAR1_P 0x0470 +#define KS8842_MACAR2_P 0x0472 +#define KS8842_MACAR3_P 0x0474 +#define KS8842_MAC_ADDR_1_OFFSET KS8842_MACAR1_P +#define KS8842_MAC_ADDR_0_OFFSET (KS8842_MAC_ADDR_1_OFFSET + 1) +#define KS8842_MAC_ADDR_3_OFFSET KS8842_MACAR2_P +#define KS8842_MAC_ADDR_2_OFFSET (KS8842_MAC_ADDR_3_OFFSET + 1) +#define KS8842_MAC_ADDR_5_OFFSET KS8842_MACAR3_P +#define KS8842_MAC_ADDR_4_OFFSET (KS8842_MAC_ADDR_5_OFFSET + 1) + +/* TOSR1 */ +#define KS8842_TOSR1_P 0x0480 +#define KS8842_TOSR2_P 0x0482 +#define KS8842_TOSR3_P 0x0484 +#define KS8842_TOSR4_P 0x0486 +#define KS8842_TOSR5_P 0x0488 +#define KS8842_TOSR6_P 0x048A +#define KS8842_TOSR7_P 0x0490 +#define KS8842_TOSR8_P 0x0492 +#define KS8842_TOS_1_OFFSET KS8842_TOSR1_P +#define KS8842_TOS_2_OFFSET KS8842_TOSR2_P +#define KS8842_TOS_3_OFFSET KS8842_TOSR3_P +#define KS8842_TOS_4_OFFSET KS8842_TOSR4_P +#define KS8842_TOS_5_OFFSET KS8842_TOSR5_P +#define KS8842_TOS_6_OFFSET KS8842_TOSR6_P + +#define KS8842_TOS_7_OFFSET KS8842_TOSR7_P +#define KS8842_TOS_8_OFFSET KS8842_TOSR8_P + +/* P1CR1 */ +#define KS8842_P1CR1_P 0x0500 +#define KS8842_P1CR2_P 0x0502 +#define KS8842_P1VIDR_P 0x0504 +#define KS8842_P1CR3_P 0x0506 +#define KS8842_P1IRCR_P 0x0508 +#define KS8842_P1ERCR_P 0x050A +#define KS884X_P1SCSLMD_P 0x0510 +#define KS884X_P1CR4_P 0x0512 +#define KS884X_P1SR_P 0x0514 + +/* P2CR1 */ +#define KS8842_P2CR1_P 0x0520 +#define KS8842_P2CR2_P 0x0522 +#define KS8842_P2VIDR_P 0x0524 +#define KS8842_P2CR3_P 0x0526 +#define KS8842_P2IRCR_P 0x0528 +#define KS8842_P2ERCR_P 0x052A +#define KS884X_P2SCSLMD_P 0x0530 +#define KS884X_P2CR4_P 0x0532 +#define KS884X_P2SR_P 0x0534 + +/* P3CR1 */ +#define KS8842_P3CR1_P 0x0540 +#define KS8842_P3CR2_P 0x0542 +#define KS8842_P3VIDR_P 0x0544 +#define KS8842_P3CR3_P 0x0546 +#define KS8842_P3IRCR_P 0x0548 +#define KS8842_P3ERCR_P 0x054A + +#define KS8842_PORT_1_CTRL_1 KS8842_P1CR1_P +#define KS8842_PORT_2_CTRL_1 KS8842_P2CR1_P +#define KS8842_PORT_3_CTRL_1 KS8842_P3CR1_P + +#define PORT_CTRL_ADDR(port, addr) \ + (addr = KS8842_PORT_1_CTRL_1 + (port) * \ + (KS8842_PORT_2_CTRL_1 - KS8842_PORT_1_CTRL_1)) + +#define KS8842_PORT_CTRL_1_OFFSET 0x00 + +#define PORT_BROADCAST_STORM 0x0080 +#define PORT_DIFFSERV_ENABLE 0x0040 +#define PORT_802_1P_ENABLE 0x0020 +#define PORT_BASED_PRIORITY_MASK 0x0018 +#define PORT_BASED_PRIORITY_BASE 0x0003 +#define PORT_BASED_PRIORITY_SHIFT 3 +#define PORT_BASED_PRIORITY_0 0x0000 +#define PORT_BASED_PRIORITY_1 0x0008 +#define PORT_BASED_PRIORITY_2 0x0010 +#define PORT_BASED_PRIORITY_3 0x0018 +#define PORT_INSERT_TAG 0x0004 +#define PORT_REMOVE_TAG 0x0002 +#define PORT_PRIO_QUEUE_ENABLE 0x0001 + +#define KS8842_PORT_CTRL_2_OFFSET 0x02 + +#define PORT_INGRESS_VLAN_FILTER 0x4000 +#define PORT_DISCARD_NON_VID 0x2000 +#define PORT_FORCE_FLOW_CTRL 0x1000 +#define PORT_BACK_PRESSURE 0x0800 +#define PORT_TX_ENABLE 0x0400 +#define PORT_RX_ENABLE 0x0200 +#define PORT_LEARN_DISABLE 0x0100 +#define PORT_MIRROR_SNIFFER 0x0080 +#define PORT_MIRROR_RX 0x0040 +#define PORT_MIRROR_TX 0x0020 +#define PORT_USER_PRIORITY_CEILING 0x0008 +#define PORT_VLAN_MEMBERSHIP 0x0007 + +#define KS8842_PORT_CTRL_VID_OFFSET 0x04 + +#define PORT_DEFAULT_VID 0x0001 + +#define KS8842_PORT_CTRL_3_OFFSET 0x06 + +#define PORT_INGRESS_LIMIT_MODE 0x000C +#define PORT_INGRESS_ALL 0x0000 +#define PORT_INGRESS_UNICAST 0x0004 +#define PORT_INGRESS_MULTICAST 0x0008 +#define PORT_INGRESS_BROADCAST 0x000C +#define PORT_COUNT_IFG 0x0002 +#define PORT_COUNT_PREAMBLE 0x0001 + +#define KS8842_PORT_IN_RATE_OFFSET 0x08 +#define KS8842_PORT_OUT_RATE_OFFSET 0x0A + +#define PORT_PRIORITY_RATE 0x0F +#define PORT_PRIORITY_RATE_SHIFT 4 + +#define KS884X_PORT_LINK_MD 0x10 + +#define PORT_CABLE_10M_SHORT 0x8000 +#define PORT_CABLE_DIAG_RESULT 0x6000 +#define PORT_CABLE_STAT_NORMAL 0x0000 +#define PORT_CABLE_STAT_OPEN 0x2000 +#define PORT_CABLE_STAT_SHORT 0x4000 +#define PORT_CABLE_STAT_FAILED 0x6000 +#define PORT_START_CABLE_DIAG 0x1000 +#define PORT_FORCE_LINK 0x0800 +#define PORT_POWER_SAVING_DISABLE 0x0400 +#define PORT_PHY_REMOTE_LOOPBACK 0x0200 +#define PORT_CABLE_FAULT_COUNTER 0x01FF + +#define KS884X_PORT_CTRL_4_OFFSET 0x12 + +#define PORT_LED_OFF 0x8000 +#define PORT_TX_DISABLE 0x4000 +#define PORT_AUTO_NEG_RESTART 0x2000 +#define PORT_REMOTE_FAULT_DISABLE 0x1000 +#define PORT_POWER_DOWN 0x0800 +#define PORT_AUTO_MDIX_DISABLE 0x0400 +#define PORT_FORCE_MDIX 0x0200 +#define PORT_LOOPBACK 0x0100 +#define PORT_AUTO_NEG_ENABLE 0x0080 +#define PORT_FORCE_100_MBIT 0x0040 +#define PORT_FORCE_FULL_DUPLEX 0x0020 +#define PORT_AUTO_NEG_SYM_PAUSE 0x0010 +#define PORT_AUTO_NEG_100BTX_FD 0x0008 +#define PORT_AUTO_NEG_100BTX 0x0004 +#define PORT_AUTO_NEG_10BT_FD 0x0002 +#define PORT_AUTO_NEG_10BT 0x0001 + +#define KS884X_PORT_STATUS_OFFSET 0x14 + +#define PORT_HP_MDIX 0x8000 +#define PORT_REVERSED_POLARITY 0x2000 +#define PORT_RX_FLOW_CTRL 0x0800 +#define PORT_TX_FLOW_CTRL 0x1000 +#define PORT_STATUS_SPEED_100MBIT 0x0400 +#define PORT_STATUS_FULL_DUPLEX 0x0200 +#define PORT_REMOTE_FAULT 0x0100 +#define PORT_MDIX_STATUS 0x0080 +#define PORT_AUTO_NEG_COMPLETE 0x0040 +#define PORT_STATUS_LINK_GOOD 0x0020 +#define PORT_REMOTE_SYM_PAUSE 0x0010 +#define PORT_REMOTE_100BTX_FD 0x0008 +#define PORT_REMOTE_100BTX 0x0004 +#define PORT_REMOTE_10BT_FD 0x0002 +#define PORT_REMOTE_10BT 0x0001 + +/* +#define STATIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF +#define STATIC_MAC_TABLE_FWD_PORTS 00-00070000-00000000 +#define STATIC_MAC_TABLE_VALID 00-00080000-00000000 +#define STATIC_MAC_TABLE_OVERRIDE 00-00100000-00000000 +#define STATIC_MAC_TABLE_USE_FID 00-00200000-00000000 +#define STATIC_MAC_TABLE_FID 00-03C00000-00000000 +*/ + +#define STATIC_MAC_TABLE_ADDR 0x0000FFFF +#define STATIC_MAC_TABLE_FWD_PORTS 0x00070000 +#define STATIC_MAC_TABLE_VALID 0x00080000 +#define STATIC_MAC_TABLE_OVERRIDE 0x00100000 +#define STATIC_MAC_TABLE_USE_FID 0x00200000 +#define STATIC_MAC_TABLE_FID 0x03C00000 + +#define STATIC_MAC_FWD_PORTS_SHIFT 16 +#define STATIC_MAC_FID_SHIFT 22 + +/* +#define VLAN_TABLE_VID 00-00000000-00000FFF +#define VLAN_TABLE_FID 00-00000000-0000F000 +#define VLAN_TABLE_MEMBERSHIP 00-00000000-00070000 +#define VLAN_TABLE_VALID 00-00000000-00080000 +*/ + +#define VLAN_TABLE_VID 0x00000FFF +#define VLAN_TABLE_FID 0x0000F000 +#define VLAN_TABLE_MEMBERSHIP 0x00070000 +#define VLAN_TABLE_VALID 0x00080000 + +#define VLAN_TABLE_FID_SHIFT 12 +#define VLAN_TABLE_MEMBERSHIP_SHIFT 16 + +/* +#define DYNAMIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF +#define DYNAMIC_MAC_TABLE_FID 00-000F0000-00000000 +#define DYNAMIC_MAC_TABLE_SRC_PORT 00-00300000-00000000 +#define DYNAMIC_MAC_TABLE_TIMESTAMP 00-00C00000-00000000 +#define DYNAMIC_MAC_TABLE_ENTRIES 03-FF000000-00000000 +#define DYNAMIC_MAC_TABLE_MAC_EMPTY 04-00000000-00000000 +#define DYNAMIC_MAC_TABLE_RESERVED 78-00000000-00000000 +#define DYNAMIC_MAC_TABLE_NOT_READY 80-00000000-00000000 +*/ + +#define DYNAMIC_MAC_TABLE_ADDR 0x0000FFFF +#define DYNAMIC_MAC_TABLE_FID 0x000F0000 +#define DYNAMIC_MAC_TABLE_SRC_PORT 0x00300000 +#define DYNAMIC_MAC_TABLE_TIMESTAMP 0x00C00000 +#define DYNAMIC_MAC_TABLE_ENTRIES 0xFF000000 + +#define DYNAMIC_MAC_TABLE_ENTRIES_H 0x03 +#define DYNAMIC_MAC_TABLE_MAC_EMPTY 0x04 +#define DYNAMIC_MAC_TABLE_RESERVED 0x78 +#define DYNAMIC_MAC_TABLE_NOT_READY 0x80 + +#define DYNAMIC_MAC_FID_SHIFT 16 +#define DYNAMIC_MAC_SRC_PORT_SHIFT 20 +#define DYNAMIC_MAC_TIMESTAMP_SHIFT 22 +#define DYNAMIC_MAC_ENTRIES_SHIFT 24 +#define DYNAMIC_MAC_ENTRIES_H_SHIFT 8 + +/* +#define MIB_COUNTER_VALUE 00-00000000-3FFFFFFF +#define MIB_COUNTER_VALID 00-00000000-40000000 +#define MIB_COUNTER_OVERFLOW 00-00000000-80000000 +*/ + +#define MIB_COUNTER_VALUE 0x3FFFFFFF +#define MIB_COUNTER_VALID 0x40000000 +#define MIB_COUNTER_OVERFLOW 0x80000000 + +#define MIB_PACKET_DROPPED 0x0000FFFF + +#define KS_MIB_PACKET_DROPPED_TX_0 0x100 +#define KS_MIB_PACKET_DROPPED_TX_1 0x101 +#define KS_MIB_PACKET_DROPPED_TX 0x102 +#define KS_MIB_PACKET_DROPPED_RX_0 0x103 +#define KS_MIB_PACKET_DROPPED_RX_1 0x104 +#define KS_MIB_PACKET_DROPPED_RX 0x105 + +/* Change default LED mode. */ +#define SET_DEFAULT_LED LED_SPEED_DUPLEX_ACT + +#define MAC_ADDR_LEN 6 +#define MAC_ADDR_ORDER(i) (MAC_ADDR_LEN - 1 - (i)) + +#define MAX_ETHERNET_BODY_SIZE 1500 +#define ETHERNET_HEADER_SIZE 14 + +#define MAX_ETHERNET_PACKET_SIZE \ + (MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE) + +#define REGULAR_RX_BUF_SIZE (MAX_ETHERNET_PACKET_SIZE + 4) +#define MAX_RX_BUF_SIZE (1912 + 4) + +#define ADDITIONAL_ENTRIES 16 +#define MAX_MULTICAST_LIST 32 + +#define HW_MULTICAST_SIZE 8 + +#define HW_TO_DEV_PORT(port) (port - 1) + +enum { + media_connected, + media_disconnected +}; + +enum { + OID_COUNTER_UNKOWN, + + OID_COUNTER_FIRST, + + /* total transmit errors */ + OID_COUNTER_XMIT_ERROR, + + /* total receive errors */ + OID_COUNTER_RCV_ERROR, + + OID_COUNTER_LAST +}; + +/* + * Hardware descriptor definitions + */ + +#define DESC_ALIGNMENT 16 +#define BUFFER_ALIGNMENT 8 + +#define NUM_OF_RX_DESC 64 +#define NUM_OF_TX_DESC 64 + +#define KS_DESC_RX_FRAME_LEN 0x000007FF +#define KS_DESC_RX_FRAME_TYPE 0x00008000 +#define KS_DESC_RX_ERROR_CRC 0x00010000 +#define KS_DESC_RX_ERROR_RUNT 0x00020000 +#define KS_DESC_RX_ERROR_TOO_LONG 0x00040000 +#define KS_DESC_RX_ERROR_PHY 0x00080000 +#define KS884X_DESC_RX_PORT_MASK 0x00300000 +#define KS_DESC_RX_MULTICAST 0x01000000 +#define KS_DESC_RX_ERROR 0x02000000 +#define KS_DESC_RX_ERROR_CSUM_UDP 0x04000000 +#define KS_DESC_RX_ERROR_CSUM_TCP 0x08000000 +#define KS_DESC_RX_ERROR_CSUM_IP 0x10000000 +#define KS_DESC_RX_LAST 0x20000000 +#define KS_DESC_RX_FIRST 0x40000000 +#define KS_DESC_RX_ERROR_COND \ + (KS_DESC_RX_ERROR_CRC | \ + KS_DESC_RX_ERROR_RUNT | \ + KS_DESC_RX_ERROR_PHY | \ + KS_DESC_RX_ERROR_TOO_LONG) + +#define KS_DESC_HW_OWNED 0x80000000 + +#define KS_DESC_BUF_SIZE 0x000007FF +#define KS884X_DESC_TX_PORT_MASK 0x00300000 +#define KS_DESC_END_OF_RING 0x02000000 +#define KS_DESC_TX_CSUM_GEN_UDP 0x04000000 +#define KS_DESC_TX_CSUM_GEN_TCP 0x08000000 +#define KS_DESC_TX_CSUM_GEN_IP 0x10000000 +#define KS_DESC_TX_LAST 0x20000000 +#define KS_DESC_TX_FIRST 0x40000000 +#define KS_DESC_TX_INTERRUPT 0x80000000 + +#define KS_DESC_PORT_SHIFT 20 + +#define KS_DESC_RX_MASK (KS_DESC_BUF_SIZE) + +#define KS_DESC_TX_MASK \ + (KS_DESC_TX_INTERRUPT | \ + KS_DESC_TX_FIRST | \ + KS_DESC_TX_LAST | \ + KS_DESC_TX_CSUM_GEN_IP | \ + KS_DESC_TX_CSUM_GEN_TCP | \ + KS_DESC_TX_CSUM_GEN_UDP | \ + KS_DESC_BUF_SIZE) + +struct ksz_desc_rx_stat { +#ifdef __BIG_ENDIAN_BITFIELD + u32 hw_owned:1; + u32 first_desc:1; + u32 last_desc:1; + u32 csum_err_ip:1; + u32 csum_err_tcp:1; + u32 csum_err_udp:1; + u32 error:1; + u32 multicast:1; + u32 src_port:4; + u32 err_phy:1; + u32 err_too_long:1; + u32 err_runt:1; + u32 err_crc:1; + u32 frame_type:1; + u32 reserved1:4; + u32 frame_len:11; +#else + u32 frame_len:11; + u32 reserved1:4; + u32 frame_type:1; + u32 err_crc:1; + u32 err_runt:1; + u32 err_too_long:1; + u32 err_phy:1; + u32 src_port:4; + u32 multicast:1; + u32 error:1; + u32 csum_err_udp:1; + u32 csum_err_tcp:1; + u32 csum_err_ip:1; + u32 last_desc:1; + u32 first_desc:1; + u32 hw_owned:1; +#endif +}; + +struct ksz_desc_tx_stat { +#ifdef __BIG_ENDIAN_BITFIELD + u32 hw_owned:1; + u32 reserved1:31; +#else + u32 reserved1:31; + u32 hw_owned:1; +#endif +}; + +struct ksz_desc_rx_buf { +#ifdef __BIG_ENDIAN_BITFIELD + u32 reserved4:6; + u32 end_of_ring:1; + u32 reserved3:14; + u32 buf_size:11; +#else + u32 buf_size:11; + u32 reserved3:14; + u32 end_of_ring:1; + u32 reserved4:6; +#endif +}; + +struct ksz_desc_tx_buf { +#ifdef __BIG_ENDIAN_BITFIELD + u32 intr:1; + u32 first_seg:1; + u32 last_seg:1; + u32 csum_gen_ip:1; + u32 csum_gen_tcp:1; + u32 csum_gen_udp:1; + u32 end_of_ring:1; + u32 reserved4:1; + u32 dest_port:4; + u32 reserved3:9; + u32 buf_size:11; +#else + u32 buf_size:11; + u32 reserved3:9; + u32 dest_port:4; + u32 reserved4:1; + u32 end_of_ring:1; + u32 csum_gen_udp:1; + u32 csum_gen_tcp:1; + u32 csum_gen_ip:1; + u32 last_seg:1; + u32 first_seg:1; + u32 intr:1; +#endif +}; + +union desc_stat { + struct ksz_desc_rx_stat rx; + struct ksz_desc_tx_stat tx; + u32 data; +}; + +union desc_buf { + struct ksz_desc_rx_buf rx; + struct ksz_desc_tx_buf tx; + u32 data; +}; + +/** + * struct ksz_hw_desc - Hardware descriptor data structure + * @ctrl: Descriptor control value. + * @buf: Descriptor buffer value. + * @addr: Physical address of memory buffer. + * @next: Pointer to next hardware descriptor. + */ +struct ksz_hw_desc { + union desc_stat ctrl; + union desc_buf buf; + u32 addr; + u32 next; +}; + +/** + * struct ksz_sw_desc - Software descriptor data structure + * @ctrl: Descriptor control value. + * @buf: Descriptor buffer value. + * @buf_size: Current buffers size value in hardware descriptor. + */ +struct ksz_sw_desc { + union desc_stat ctrl; + union desc_buf buf; + u32 buf_size; +}; + +/** + * struct ksz_dma_buf - OS dependent DMA buffer data structure + * @skb: Associated socket buffer. + * @dma: Associated physical DMA address. + * len: Actual len used. + */ +struct ksz_dma_buf { + struct sk_buff *skb; + dma_addr_t dma; + int len; +}; + +/** + * struct ksz_desc - Descriptor structure + * @phw: Hardware descriptor pointer to uncached physical memory. + * @sw: Cached memory to hold hardware descriptor values for + * manipulation. + * @dma_buf: Operating system dependent data structure to hold physical + * memory buffer allocation information. + */ +struct ksz_desc { + struct ksz_hw_desc *phw; + struct ksz_sw_desc sw; + struct ksz_dma_buf dma_buf; +}; + +#define DMA_BUFFER(desc) ((struct ksz_dma_buf *)(&(desc)->dma_buf)) + +/** + * struct ksz_desc_info - Descriptor information data structure + * @ring: First descriptor in the ring. + * @cur: Current descriptor being manipulated. + * @ring_virt: First hardware descriptor in the ring. + * @ring_phys: The physical address of the first descriptor of the ring. + * @size: Size of hardware descriptor. + * @alloc: Number of descriptors allocated. + * @avail: Number of descriptors available for use. + * @last: Index for last descriptor released to hardware. + * @next: Index for next descriptor available for use. + * @mask: Mask for index wrapping. + */ +struct ksz_desc_info { + struct ksz_desc *ring; + struct ksz_desc *cur; + struct ksz_hw_desc *ring_virt; + u32 ring_phys; + int size; + int alloc; + int avail; + int last; + int next; + int mask; +}; + +/* + * KSZ8842 switch definitions + */ + +enum { + TABLE_STATIC_MAC = 0, + TABLE_VLAN, + TABLE_DYNAMIC_MAC, + TABLE_MIB +}; + +#define LEARNED_MAC_TABLE_ENTRIES 1024 +#define STATIC_MAC_TABLE_ENTRIES 8 + +/** + * struct ksz_mac_table - Static MAC table data structure + * @mac_addr: MAC address to filter. + * @vid: VID value. + * @fid: FID value. + * @ports: Port membership. + * @override: Override setting. + * @use_fid: FID use setting. + * @valid: Valid setting indicating the entry is being used. + */ +struct ksz_mac_table { + u8 mac_addr[MAC_ADDR_LEN]; + u16 vid; + u8 fid; + u8 ports; + u8 override:1; + u8 use_fid:1; + u8 valid:1; +}; + +#define VLAN_TABLE_ENTRIES 16 + +/** + * struct ksz_vlan_table - VLAN table data structure + * @vid: VID value. + * @fid: FID value. + * @member: Port membership. + */ +struct ksz_vlan_table { + u16 vid; + u8 fid; + u8 member; +}; + +#define DIFFSERV_ENTRIES 64 +#define PRIO_802_1P_ENTRIES 8 +#define PRIO_QUEUES 4 + +#define SWITCH_PORT_NUM 2 +#define TOTAL_PORT_NUM (SWITCH_PORT_NUM + 1) +#define HOST_MASK (1 << SWITCH_PORT_NUM) +#define PORT_MASK 7 + +#define MAIN_PORT 0 +#define OTHER_PORT 1 +#define HOST_PORT SWITCH_PORT_NUM + +#define PORT_COUNTER_NUM 0x20 +#define TOTAL_PORT_COUNTER_NUM (PORT_COUNTER_NUM + 2) + +#define MIB_COUNTER_RX_LO_PRIORITY 0x00 +#define MIB_COUNTER_RX_HI_PRIORITY 0x01 +#define MIB_COUNTER_RX_UNDERSIZE 0x02 +#define MIB_COUNTER_RX_FRAGMENT 0x03 +#define MIB_COUNTER_RX_OVERSIZE 0x04 +#define MIB_COUNTER_RX_JABBER 0x05 +#define MIB_COUNTER_RX_SYMBOL_ERR 0x06 +#define MIB_COUNTER_RX_CRC_ERR 0x07 +#define MIB_COUNTER_RX_ALIGNMENT_ERR 0x08 +#define MIB_COUNTER_RX_CTRL_8808 0x09 +#define MIB_COUNTER_RX_PAUSE 0x0A +#define MIB_COUNTER_RX_BROADCAST 0x0B +#define MIB_COUNTER_RX_MULTICAST 0x0C +#define MIB_COUNTER_RX_UNICAST 0x0D +#define MIB_COUNTER_RX_OCTET_64 0x0E +#define MIB_COUNTER_RX_OCTET_65_127 0x0F +#define MIB_COUNTER_RX_OCTET_128_255 0x10 +#define MIB_COUNTER_RX_OCTET_256_511 0x11 +#define MIB_COUNTER_RX_OCTET_512_1023 0x12 +#define MIB_COUNTER_RX_OCTET_1024_1522 0x13 +#define MIB_COUNTER_TX_LO_PRIORITY 0x14 +#define MIB_COUNTER_TX_HI_PRIORITY 0x15 +#define MIB_COUNTER_TX_LATE_COLLISION 0x16 +#define MIB_COUNTER_TX_PAUSE 0x17 +#define MIB_COUNTER_TX_BROADCAST 0x18 +#define MIB_COUNTER_TX_MULTICAST 0x19 +#define MIB_COUNTER_TX_UNICAST 0x1A +#define MIB_COUNTER_TX_DEFERRED 0x1B +#define MIB_COUNTER_TX_TOTAL_COLLISION 0x1C +#define MIB_COUNTER_TX_EXCESS_COLLISION 0x1D +#define MIB_COUNTER_TX_SINGLE_COLLISION 0x1E +#define MIB_COUNTER_TX_MULTI_COLLISION 0x1F + +#define MIB_COUNTER_RX_DROPPED_PACKET 0x20 +#define MIB_COUNTER_TX_DROPPED_PACKET 0x21 + +/** + * struct ksz_port_mib - Port MIB data structure + * @cnt_ptr: Current pointer to MIB counter index. + * @link_down: Indication the link has just gone down. + * @state: Connection status of the port. + * @mib_start: The starting counter index. Some ports do not start at 0. + * @counter: 64-bit MIB counter value. + * @dropped: Temporary buffer to remember last read packet dropped values. + * + * MIB counters needs to be read periodically so that counters do not get + * overflowed and give incorrect values. A right balance is needed to + * satisfy this condition and not waste too much CPU time. + * + * It is pointless to read MIB counters when the port is disconnected. The + * @state provides the connection status so that MIB counters are read only + * when the port is connected. The @link_down indicates the port is just + * disconnected so that all MIB counters are read one last time to update the + * information. + */ +struct ksz_port_mib { + u8 cnt_ptr; + u8 link_down; + u8 state; + u8 mib_start; + + u64 counter[TOTAL_PORT_COUNTER_NUM]; + u32 dropped[2]; +}; + +/** + * struct ksz_port_cfg - Port configuration data structure + * @vid: VID value. + * @member: Port membership. + * @port_prio: Port priority. + * @rx_rate: Receive priority rate. + * @tx_rate: Transmit priority rate. + * @stp_state: Current Spanning Tree Protocol state. + */ +struct ksz_port_cfg { + u16 vid; + u8 member; + u8 port_prio; + u32 rx_rate[PRIO_QUEUES]; + u32 tx_rate[PRIO_QUEUES]; + int stp_state; +}; + +/** + * struct ksz_switch - KSZ8842 switch data structure + * @mac_table: MAC table entries information. + * @vlan_table: VLAN table entries information. + * @port_cfg: Port configuration information. + * @diffserv: DiffServ priority settings. Possible values from 6-bit of ToS + * (bit7 ~ bit2) field. + * @p_802_1p: 802.1P priority settings. Possible values from 3-bit of 802.1p + * Tag priority field. + * @br_addr: Bridge address. Used for STP. + * @other_addr: Other MAC address. Used for multiple network device mode. + * @broad_per: Broadcast storm percentage. + * @member: Current port membership. Used for STP. + */ +struct ksz_switch { + struct ksz_mac_table mac_table[STATIC_MAC_TABLE_ENTRIES]; + struct ksz_vlan_table vlan_table[VLAN_TABLE_ENTRIES]; + struct ksz_port_cfg port_cfg[TOTAL_PORT_NUM]; + + u8 diffserv[DIFFSERV_ENTRIES]; + u8 p_802_1p[PRIO_802_1P_ENTRIES]; + + u8 br_addr[MAC_ADDR_LEN]; + u8 other_addr[MAC_ADDR_LEN]; + + u8 broad_per; + u8 member; +}; + +#define TX_RATE_UNIT 10000 + +/** + * struct ksz_port_info - Port information data structure + * @state: Connection status of the port. + * @tx_rate: Transmit rate divided by 10000 to get Mbit. + * @duplex: Duplex mode. + * @advertised: Advertised auto-negotiation setting. Used to determine link. + * @partner: Auto-negotiation partner setting. Used to determine link. + * @port_id: Port index to access actual hardware register. + * @pdev: Pointer to OS dependent network device. + */ +struct ksz_port_info { + uint state; + uint tx_rate; + u8 duplex; + u8 advertised; + u8 partner; + u8 port_id; + void *pdev; +}; + +#define MAX_TX_HELD_SIZE 52000 + +/* Hardware features and bug fixes. */ +#define LINK_INT_WORKING (1 << 0) +#define SMALL_PACKET_TX_BUG (1 << 1) +#define HALF_DUPLEX_SIGNAL_BUG (1 << 2) +#define IPV6_CSUM_GEN_HACK (1 << 3) +#define RX_HUGE_FRAME (1 << 4) +#define STP_SUPPORT (1 << 8) + +/* Software overrides. */ +#define PAUSE_FLOW_CTRL (1 << 0) +#define FAST_AGING (1 << 1) + +/** + * struct ksz_hw - KSZ884X hardware data structure + * @io: Virtual address assigned. + * @ksz_switch: Pointer to KSZ8842 switch. + * @port_info: Port information. + * @port_mib: Port MIB information. + * @dev_count: Number of network devices this hardware supports. + * @dst_ports: Destination ports in switch for transmission. + * @id: Hardware ID. Used for display only. + * @mib_cnt: Number of MIB counters this hardware has. + * @mib_port_cnt: Number of ports with MIB counters. + * @tx_cfg: Cached transmit control settings. + * @rx_cfg: Cached receive control settings. + * @intr_mask: Current interrupt mask. + * @intr_set: Current interrup set. + * @intr_blocked: Interrupt blocked. + * @rx_desc_info: Receive descriptor information. + * @tx_desc_info: Transmit descriptor information. + * @tx_int_cnt: Transmit interrupt count. Used for TX optimization. + * @tx_int_mask: Transmit interrupt mask. Used for TX optimization. + * @tx_size: Transmit data size. Used for TX optimization. + * The maximum is defined by MAX_TX_HELD_SIZE. + * @perm_addr: Permanent MAC address. + * @override_addr: Overrided MAC address. + * @address: Additional MAC address entries. + * @addr_list_size: Additional MAC address list size. + * @mac_override: Indication of MAC address overrided. + * @promiscuous: Counter to keep track of promiscuous mode set. + * @all_multi: Counter to keep track of all multicast mode set. + * @multi_list: Multicast address entries. + * @multi_bits: Cached multicast hash table settings. + * @multi_list_size: Multicast address list size. + * @enabled: Indication of hardware enabled. + * @rx_stop: Indication of receive process stop. + * @features: Hardware features to enable. + * @overrides: Hardware features to override. + * @parent: Pointer to parent, network device private structure. + */ +struct ksz_hw { + void __iomem *io; + + struct ksz_switch *ksz_switch; + struct ksz_port_info port_info[SWITCH_PORT_NUM]; + struct ksz_port_mib port_mib[TOTAL_PORT_NUM]; + int dev_count; + int dst_ports; + int id; + int mib_cnt; + int mib_port_cnt; + + u32 tx_cfg; + u32 rx_cfg; + u32 intr_mask; + u32 intr_set; + uint intr_blocked; + + struct ksz_desc_info rx_desc_info; + struct ksz_desc_info tx_desc_info; + + int tx_int_cnt; + int tx_int_mask; + int tx_size; + + u8 perm_addr[MAC_ADDR_LEN]; + u8 override_addr[MAC_ADDR_LEN]; + u8 address[ADDITIONAL_ENTRIES][MAC_ADDR_LEN]; + u8 addr_list_size; + u8 mac_override; + u8 promiscuous; + u8 all_multi; + u8 multi_list[MAX_MULTICAST_LIST][MAC_ADDR_LEN]; + u8 multi_bits[HW_MULTICAST_SIZE]; + u8 multi_list_size; + + u8 enabled; + u8 rx_stop; + u8 reserved2[1]; + + uint features; + uint overrides; + + void *parent; +}; + +enum { + PHY_NO_FLOW_CTRL, + PHY_FLOW_CTRL, + PHY_TX_ONLY, + PHY_RX_ONLY +}; + +/** + * struct ksz_port - Virtual port data structure + * @duplex: Duplex mode setting. 1 for half duplex, 2 for full + * duplex, and 0 for auto, which normally results in full + * duplex. + * @speed: Speed setting. 10 for 10 Mbit, 100 for 100 Mbit, and + * 0 for auto, which normally results in 100 Mbit. + * @force_link: Force link setting. 0 for auto-negotiation, and 1 for + * force. + * @flow_ctrl: Flow control setting. PHY_NO_FLOW_CTRL for no flow + * control, and PHY_FLOW_CTRL for flow control. + * PHY_TX_ONLY and PHY_RX_ONLY are not supported for 100 + * Mbit PHY. + * @first_port: Index of first port this port supports. + * @mib_port_cnt: Number of ports with MIB counters. + * @port_cnt: Number of ports this port supports. + * @counter: Port statistics counter. + * @hw: Pointer to hardware structure. + * @linked: Pointer to port information linked to this port. + */ +struct ksz_port { + u8 duplex; + u8 speed; + u8 force_link; + u8 flow_ctrl; + + int first_port; + int mib_port_cnt; + int port_cnt; + u64 counter[OID_COUNTER_LAST]; + + struct ksz_hw *hw; + struct ksz_port_info *linked; +}; + +/** + * struct ksz_timer_info - Timer information data structure + * @timer: Kernel timer. + * @cnt: Running timer counter. + * @max: Number of times to run timer; -1 for infinity. + * @period: Timer period in jiffies. + */ +struct ksz_timer_info { + struct timer_list timer; + int cnt; + int max; + int period; +}; + +/** + * struct ksz_shared_mem - OS dependent shared memory data structure + * @dma_addr: Physical DMA address allocated. + * @alloc_size: Allocation size. + * @phys: Actual physical address used. + * @alloc_virt: Virtual address allocated. + * @virt: Actual virtual address used. + */ +struct ksz_shared_mem { + dma_addr_t dma_addr; + uint alloc_size; + uint phys; + u8 *alloc_virt; + u8 *virt; +}; + +/** + * struct ksz_counter_info - OS dependent counter information data structure + * @counter: Wait queue to wakeup after counters are read. + * @time: Next time in jiffies to read counter. + * @read: Indication of counters read in full or not. + */ +struct ksz_counter_info { + wait_queue_head_t counter; + unsigned long time; + int read; +}; + +/** + * struct dev_info - Network device information data structure + * @dev: Pointer to network device. + * @pdev: Pointer to PCI device. + * @hw: Hardware structure. + * @desc_pool: Physical memory used for descriptor pool. + * @hwlock: Spinlock to prevent hardware from accessing. + * @lock: Mutex lock to prevent device from accessing. + * @dev_rcv: Receive process function used. + * @last_skb: Socket buffer allocated for descriptor rx fragments. + * @skb_index: Buffer index for receiving fragments. + * @skb_len: Buffer length for receiving fragments. + * @mib_read: Workqueue to read MIB counters. + * @mib_timer_info: Timer to read MIB counters. + * @counter: Used for MIB reading. + * @mtu: Current MTU used. The default is REGULAR_RX_BUF_SIZE; + * the maximum is MAX_RX_BUF_SIZE. + * @opened: Counter to keep track of device open. + * @rx_tasklet: Receive processing tasklet. + * @tx_tasklet: Transmit processing tasklet. + * @wol_enable: Wake-on-LAN enable set by ethtool. + * @wol_support: Wake-on-LAN support used by ethtool. + * @pme_wait: Used for KSZ8841 power management. + */ +struct dev_info { + struct net_device *dev; + struct pci_dev *pdev; + + struct ksz_hw hw; + struct ksz_shared_mem desc_pool; + + spinlock_t hwlock; + struct mutex lock; + + int (*dev_rcv)(struct dev_info *); + + struct sk_buff *last_skb; + int skb_index; + int skb_len; + + struct work_struct mib_read; + struct ksz_timer_info mib_timer_info; + struct ksz_counter_info counter[TOTAL_PORT_NUM]; + + int mtu; + int opened; + + struct tasklet_struct rx_tasklet; + struct tasklet_struct tx_tasklet; + + int wol_enable; + int wol_support; + unsigned long pme_wait; +}; + +/** + * struct dev_priv - Network device private data structure + * @adapter: Adapter device information. + * @port: Port information. + * @monitor_time_info: Timer to monitor ports. + * @stats: Network statistics. + * @proc_sem: Semaphore for proc accessing. + * @id: Device ID. + * @mii_if: MII interface information. + * @advertising: Temporary variable to store advertised settings. + * @msg_enable: The message flags controlling driver output. + * @media_state: The connection status of the device. + * @multicast: The all multicast state of the device. + * @promiscuous: The promiscuous state of the device. + */ +struct dev_priv { + struct dev_info *adapter; + struct ksz_port port; + struct ksz_timer_info monitor_timer_info; + struct net_device_stats stats; + + struct semaphore proc_sem; + int id; + + struct mii_if_info mii_if; + u32 advertising; + + u32 msg_enable; + int media_state; + int multicast; + int promiscuous; +}; + +#define ks_info(_ks, _msg...) dev_info(&(_ks)->pdev->dev, _msg) +#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->pdev->dev, _msg) +#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg) +#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg) + +#define DRV_NAME "KSZ884X PCI" +#define DEVICE_NAME "KSZ884x PCI" +#define DRV_VERSION "1.0.0" +#define DRV_RELDATE "Feb 8, 2010" + +static char version[] __devinitdata = + "Micrel " DEVICE_NAME " " DRV_VERSION " (" DRV_RELDATE ")"; + +static u8 DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x88, 0x42, 0x01 }; + +/* + * Interrupt processing primary routines + */ + +static inline void hw_ack_intr(struct ksz_hw *hw, uint interrupt) +{ + writel(interrupt, hw->io + KS884X_INTERRUPTS_STATUS); +} + +static inline void hw_dis_intr(struct ksz_hw *hw) +{ + hw->intr_blocked = hw->intr_mask; + writel(0, hw->io + KS884X_INTERRUPTS_ENABLE); + hw->intr_set = readl(hw->io + KS884X_INTERRUPTS_ENABLE); +} + +static inline void hw_set_intr(struct ksz_hw *hw, uint interrupt) +{ + hw->intr_set = interrupt; + writel(interrupt, hw->io + KS884X_INTERRUPTS_ENABLE); +} + +static inline void hw_ena_intr(struct ksz_hw *hw) +{ + hw->intr_blocked = 0; + hw_set_intr(hw, hw->intr_mask); +} + +static inline void hw_dis_intr_bit(struct ksz_hw *hw, uint bit) +{ + hw->intr_mask &= ~(bit); +} + +static inline void hw_turn_off_intr(struct ksz_hw *hw, uint interrupt) +{ + u32 read_intr; + + read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE); + hw->intr_set = read_intr & ~interrupt; + writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE); + hw_dis_intr_bit(hw, interrupt); +} + +/** + * hw_turn_on_intr - turn on specified interrupts + * @hw: The hardware instance. + * @bit: The interrupt bits to be on. + * + * This routine turns on the specified interrupts in the interrupt mask so that + * those interrupts will be enabled. + */ +static void hw_turn_on_intr(struct ksz_hw *hw, u32 bit) +{ + hw->intr_mask |= bit; + + if (!hw->intr_blocked) + hw_set_intr(hw, hw->intr_mask); +} + +static inline void hw_ena_intr_bit(struct ksz_hw *hw, uint interrupt) +{ + u32 read_intr; + + read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE); + hw->intr_set = read_intr | interrupt; + writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE); +} + +static inline void hw_read_intr(struct ksz_hw *hw, uint *status) +{ + *status = readl(hw->io + KS884X_INTERRUPTS_STATUS); + *status = *status & hw->intr_set; +} + +static inline void hw_restore_intr(struct ksz_hw *hw, uint interrupt) +{ + if (interrupt) + hw_ena_intr(hw); +} + +/** + * hw_block_intr - block hardware interrupts + * + * This function blocks all interrupts of the hardware and returns the current + * interrupt enable mask so that interrupts can be restored later. + * + * Return the current interrupt enable mask. + */ +static uint hw_block_intr(struct ksz_hw *hw) +{ + uint interrupt = 0; + + if (!hw->intr_blocked) { + hw_dis_intr(hw); + interrupt = hw->intr_blocked; + } + return interrupt; +} + +/* + * Hardware descriptor routines + */ + +static inline void reset_desc(struct ksz_desc *desc, union desc_stat status) +{ + status.rx.hw_owned = 0; + desc->phw->ctrl.data = cpu_to_le32(status.data); +} + +static inline void release_desc(struct ksz_desc *desc) +{ + desc->sw.ctrl.tx.hw_owned = 1; + if (desc->sw.buf_size != desc->sw.buf.data) { + desc->sw.buf_size = desc->sw.buf.data; + desc->phw->buf.data = cpu_to_le32(desc->sw.buf.data); + } + desc->phw->ctrl.data = cpu_to_le32(desc->sw.ctrl.data); +} + +static void get_rx_pkt(struct ksz_desc_info *info, struct ksz_desc **desc) +{ + *desc = &info->ring[info->last]; + info->last++; + info->last &= info->mask; + info->avail--; + (*desc)->sw.buf.data &= ~KS_DESC_RX_MASK; +} + +static inline void set_rx_buf(struct ksz_desc *desc, u32 addr) +{ + desc->phw->addr = cpu_to_le32(addr); +} + +static inline void set_rx_len(struct ksz_desc *desc, u32 len) +{ + desc->sw.buf.rx.buf_size = len; +} + +static inline void get_tx_pkt(struct ksz_desc_info *info, + struct ksz_desc **desc) +{ + *desc = &info->ring[info->next]; + info->next++; + info->next &= info->mask; + info->avail--; + (*desc)->sw.buf.data &= ~KS_DESC_TX_MASK; +} + +static inline void set_tx_buf(struct ksz_desc *desc, u32 addr) +{ + desc->phw->addr = cpu_to_le32(addr); +} + +static inline void set_tx_len(struct ksz_desc *desc, u32 len) +{ + desc->sw.buf.tx.buf_size = len; +} + +/* Switch functions */ + +#define TABLE_READ 0x10 +#define TABLE_SEL_SHIFT 2 + +#define HW_DELAY(hw, reg) \ + do { \ + u16 dummy; \ + dummy = readw(hw->io + reg); \ + } while (0) + +/** + * sw_r_table - read 4 bytes of data from switch table + * @hw: The hardware instance. + * @table: The table selector. + * @addr: The address of the table entry. + * @data: Buffer to store the read data. + * + * This routine reads 4 bytes of data from the table of the switch. + * Hardware interrupts are disabled to minimize corruption of read data. + */ +static void sw_r_table(struct ksz_hw *hw, int table, u16 addr, u32 *data) +{ + u16 ctrl_addr; + uint interrupt; + + ctrl_addr = (((table << TABLE_SEL_SHIFT) | TABLE_READ) << 8) | addr; + + interrupt = hw_block_intr(hw); + + writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); + HW_DELAY(hw, KS884X_IACR_OFFSET); + *data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); + + hw_restore_intr(hw, interrupt); +} + +/** + * sw_w_table_64 - write 8 bytes of data to the switch table + * @hw: The hardware instance. + * @table: The table selector. + * @addr: The address of the table entry. + * @data_hi: The high part of data to be written (bit63 ~ bit32). + * @data_lo: The low part of data to be written (bit31 ~ bit0). + * + * This routine writes 8 bytes of data to the table of the switch. + * Hardware interrupts are disabled to minimize corruption of written data. + */ +static void sw_w_table_64(struct ksz_hw *hw, int table, u16 addr, u32 data_hi, + u32 data_lo) +{ + u16 ctrl_addr; + uint interrupt; + + ctrl_addr = ((table << TABLE_SEL_SHIFT) << 8) | addr; + + interrupt = hw_block_intr(hw); + + writel(data_hi, hw->io + KS884X_ACC_DATA_4_OFFSET); + writel(data_lo, hw->io + KS884X_ACC_DATA_0_OFFSET); + + writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); + HW_DELAY(hw, KS884X_IACR_OFFSET); + + hw_restore_intr(hw, interrupt); +} + +/** + * sw_w_sta_mac_table - write to the static MAC table + * @hw: The hardware instance. + * @addr: The address of the table entry. + * @mac_addr: The MAC address. + * @ports: The port members. + * @override: The flag to override the port receive/transmit settings. + * @valid: The flag to indicate entry is valid. + * @use_fid: The flag to indicate the FID is valid. + * @fid: The FID value. + * + * This routine writes an entry of the static MAC table of the switch. It + * calls sw_w_table_64() to write the data. + */ +static void sw_w_sta_mac_table(struct ksz_hw *hw, u16 addr, u8 *mac_addr, + u8 ports, int override, int valid, int use_fid, u8 fid) +{ + u32 data_hi; + u32 data_lo; + + data_lo = ((u32) mac_addr[2] << 24) | + ((u32) mac_addr[3] << 16) | + ((u32) mac_addr[4] << 8) | mac_addr[5]; + data_hi = ((u32) mac_addr[0] << 8) | mac_addr[1]; + data_hi |= (u32) ports << STATIC_MAC_FWD_PORTS_SHIFT; + + if (override) + data_hi |= STATIC_MAC_TABLE_OVERRIDE; + if (use_fid) { + data_hi |= STATIC_MAC_TABLE_USE_FID; + data_hi |= (u32) fid << STATIC_MAC_FID_SHIFT; + } + if (valid) + data_hi |= STATIC_MAC_TABLE_VALID; + + sw_w_table_64(hw, TABLE_STATIC_MAC, addr, data_hi, data_lo); +} + +/** + * sw_r_vlan_table - read from the VLAN table + * @hw: The hardware instance. + * @addr: The address of the table entry. + * @vid: Buffer to store the VID. + * @fid: Buffer to store the VID. + * @member: Buffer to store the port membership. + * + * This function reads an entry of the VLAN table of the switch. It calls + * sw_r_table() to get the data. + * + * Return 0 if the entry is valid; otherwise -1. + */ +static int sw_r_vlan_table(struct ksz_hw *hw, u16 addr, u16 *vid, u8 *fid, + u8 *member) +{ + u32 data; + + sw_r_table(hw, TABLE_VLAN, addr, &data); + if (data & VLAN_TABLE_VALID) { + *vid = (u16)(data & VLAN_TABLE_VID); + *fid = (u8)((data & VLAN_TABLE_FID) >> VLAN_TABLE_FID_SHIFT); + *member = (u8)((data & VLAN_TABLE_MEMBERSHIP) >> + VLAN_TABLE_MEMBERSHIP_SHIFT); + return 0; + } + return -1; +} + +/** + * port_r_mib_cnt - read MIB counter + * @hw: The hardware instance. + * @port: The port index. + * @addr: The address of the counter. + * @cnt: Buffer to store the counter. + * + * This routine reads a MIB counter of the port. + * Hardware interrupts are disabled to minimize corruption of read data. + */ +static void port_r_mib_cnt(struct ksz_hw *hw, int port, u16 addr, u64 *cnt) +{ + u32 data; + u16 ctrl_addr; + uint interrupt; + int timeout; + + ctrl_addr = addr + PORT_COUNTER_NUM * port; + + interrupt = hw_block_intr(hw); + + ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) << 8); + writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); + HW_DELAY(hw, KS884X_IACR_OFFSET); + + for (timeout = 100; timeout > 0; timeout--) { + data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); + + if (data & MIB_COUNTER_VALID) { + if (data & MIB_COUNTER_OVERFLOW) + *cnt += MIB_COUNTER_VALUE + 1; + *cnt += data & MIB_COUNTER_VALUE; + break; + } + } + + hw_restore_intr(hw, interrupt); +} + +/** + * port_r_mib_pkt - read dropped packet counts + * @hw: The hardware instance. + * @port: The port index. + * @cnt: Buffer to store the receive and transmit dropped packet counts. + * + * This routine reads the dropped packet counts of the port. + * Hardware interrupts are disabled to minimize corruption of read data. + */ +static void port_r_mib_pkt(struct ksz_hw *hw, int port, u32 *last, u64 *cnt) +{ + u32 cur; + u32 data; + u16 ctrl_addr; + uint interrupt; + int index; + + index = KS_MIB_PACKET_DROPPED_RX_0 + port; + do { + interrupt = hw_block_intr(hw); + + ctrl_addr = (u16) index; + ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) + << 8); + writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); + HW_DELAY(hw, KS884X_IACR_OFFSET); + data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); + + hw_restore_intr(hw, interrupt); + + data &= MIB_PACKET_DROPPED; + cur = *last; + if (data != cur) { + *last = data; + if (data < cur) + data += MIB_PACKET_DROPPED + 1; + data -= cur; + *cnt += data; + } + ++last; + ++cnt; + index -= KS_MIB_PACKET_DROPPED_TX - + KS_MIB_PACKET_DROPPED_TX_0 + 1; + } while (index >= KS_MIB_PACKET_DROPPED_TX_0 + port); +} + +/** + * port_r_cnt - read MIB counters periodically + * @hw: The hardware instance. + * @port: The port index. + * + * This routine is used to read the counters of the port periodically to avoid + * counter overflow. The hardware should be acquired first before calling this + * routine. + * + * Return non-zero when not all counters not read. + */ +static int port_r_cnt(struct ksz_hw *hw, int port) +{ + struct ksz_port_mib *mib = &hw->port_mib[port]; + + if (mib->mib_start < PORT_COUNTER_NUM) + while (mib->cnt_ptr < PORT_COUNTER_NUM) { + port_r_mib_cnt(hw, port, mib->cnt_ptr, + &mib->counter[mib->cnt_ptr]); + ++mib->cnt_ptr; + } + if (hw->mib_cnt > PORT_COUNTER_NUM) + port_r_mib_pkt(hw, port, mib->dropped, + &mib->counter[PORT_COUNTER_NUM]); + mib->cnt_ptr = 0; + return 0; +} + +/** + * port_init_cnt - initialize MIB counter values + * @hw: The hardware instance. + * @port: The port index. + * + * This routine is used to initialize all counters to zero if the hardware + * cannot do it after reset. + */ +static void port_init_cnt(struct ksz_hw *hw, int port) +{ + struct ksz_port_mib *mib = &hw->port_mib[port]; + + mib->cnt_ptr = 0; + if (mib->mib_start < PORT_COUNTER_NUM) + do { + port_r_mib_cnt(hw, port, mib->cnt_ptr, + &mib->counter[mib->cnt_ptr]); + ++mib->cnt_ptr; + } while (mib->cnt_ptr < PORT_COUNTER_NUM); + if (hw->mib_cnt > PORT_COUNTER_NUM) + port_r_mib_pkt(hw, port, mib->dropped, + &mib->counter[PORT_COUNTER_NUM]); + memset((void *) mib->counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM); + mib->cnt_ptr = 0; +} + +/* + * Port functions + */ + +/** + * port_chk - check port register bits + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the port register. + * @bits: The data bits to check. + * + * This function checks whether the specified bits of the port register are set + * or not. + * + * Return 0 if the bits are not set. + */ +static int port_chk(struct ksz_hw *hw, int port, int offset, u16 bits) +{ + u32 addr; + u16 data; + + PORT_CTRL_ADDR(port, addr); + addr += offset; + data = readw(hw->io + addr); + return (data & bits) == bits; +} + +/** + * port_cfg - set port register bits + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the port register. + * @bits: The data bits to set. + * @set: The flag indicating whether the bits are to be set or not. + * + * This routine sets or resets the specified bits of the port register. + */ +static void port_cfg(struct ksz_hw *hw, int port, int offset, u16 bits, + int set) +{ + u32 addr; + u16 data; + + PORT_CTRL_ADDR(port, addr); + addr += offset; + data = readw(hw->io + addr); + if (set) + data |= bits; + else + data &= ~bits; + writew(data, hw->io + addr); +} + +/** + * port_chk_shift - check port bit + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the register. + * @shift: Number of bits to shift. + * + * This function checks whether the specified port is set in the register or + * not. + * + * Return 0 if the port is not set. + */ +static int port_chk_shift(struct ksz_hw *hw, int port, u32 addr, int shift) +{ + u16 data; + u16 bit = 1 << port; + + data = readw(hw->io + addr); + data >>= shift; + return (data & bit) == bit; +} + +/** + * port_cfg_shift - set port bit + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the register. + * @shift: Number of bits to shift. + * @set: The flag indicating whether the port is to be set or not. + * + * This routine sets or resets the specified port in the register. + */ +static void port_cfg_shift(struct ksz_hw *hw, int port, u32 addr, int shift, + int set) +{ + u16 data; + u16 bits = 1 << port; + + data = readw(hw->io + addr); + bits <<= shift; + if (set) + data |= bits; + else + data &= ~bits; + writew(data, hw->io + addr); +} + +/** + * port_r8 - read byte from port register + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the port register. + * @data: Buffer to store the data. + * + * This routine reads a byte from the port register. + */ +static void port_r8(struct ksz_hw *hw, int port, int offset, u8 *data) +{ + u32 addr; + + PORT_CTRL_ADDR(port, addr); + addr += offset; + *data = readb(hw->io + addr); +} + +/** + * port_r16 - read word from port register. + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the port register. + * @data: Buffer to store the data. + * + * This routine reads a word from the port register. + */ +static void port_r16(struct ksz_hw *hw, int port, int offset, u16 *data) +{ + u32 addr; + + PORT_CTRL_ADDR(port, addr); + addr += offset; + *data = readw(hw->io + addr); +} + +/** + * port_w16 - write word to port register. + * @hw: The hardware instance. + * @port: The port index. + * @offset: The offset of the port register. + * @data: Data to write. + * + * This routine writes a word to the port register. + */ +static void port_w16(struct ksz_hw *hw, int port, int offset, u16 data) +{ + u32 addr; + + PORT_CTRL_ADDR(port, addr); + addr += offset; + writew(data, hw->io + addr); +} + +/** + * sw_chk - check switch register bits + * @hw: The hardware instance. + * @addr: The address of the switch register. + * @bits: The data bits to check. + * + * This function checks whether the specified bits of the switch register are + * set or not. + * + * Return 0 if the bits are not set. + */ +static int sw_chk(struct ksz_hw *hw, u32 addr, u16 bits) +{ + u16 data; + + data = readw(hw->io + addr); + return (data & bits) == bits; +} + +/** + * sw_cfg - set switch register bits + * @hw: The hardware instance. + * @addr: The address of the switch register. + * @bits: The data bits to set. + * @set: The flag indicating whether the bits are to be set or not. + * + * This function sets or resets the specified bits of the switch register. + */ +static void sw_cfg(struct ksz_hw *hw, u32 addr, u16 bits, int set) +{ + u16 data; + + data = readw(hw->io + addr); + if (set) + data |= bits; + else + data &= ~bits; + writew(data, hw->io + addr); +} + +/* Bandwidth */ + +static inline void port_cfg_broad_storm(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM, set); +} + +static inline int port_chk_broad_storm(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM); +} + +/* Driver set switch broadcast storm protection at 10% rate. */ +#define BROADCAST_STORM_PROTECTION_RATE 10 + +/* 148,800 frames * 67 ms / 100 */ +#define BROADCAST_STORM_VALUE 9969 + +/** + * sw_cfg_broad_storm - configure broadcast storm threshold + * @hw: The hardware instance. + * @percent: Broadcast storm threshold in percent of transmit rate. + * + * This routine configures the broadcast storm threshold of the switch. + */ +static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent) +{ + u16 data; + u32 value = ((u32) BROADCAST_STORM_VALUE * (u32) percent / 100); + + if (value > BROADCAST_STORM_RATE) + value = BROADCAST_STORM_RATE; + + data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); + data &= ~(BROADCAST_STORM_RATE_LO | BROADCAST_STORM_RATE_HI); + data |= ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8); + writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET); +} + +/** + * sw_get_board_storm - get broadcast storm threshold + * @hw: The hardware instance. + * @percent: Buffer to store the broadcast storm threshold percentage. + * + * This routine retrieves the broadcast storm threshold of the switch. + */ +static void sw_get_broad_storm(struct ksz_hw *hw, u8 *percent) +{ + int num; + u16 data; + + data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); + num = (data & BROADCAST_STORM_RATE_HI); + num <<= 8; + num |= (data & BROADCAST_STORM_RATE_LO) >> 8; + num = (num * 100 + BROADCAST_STORM_VALUE / 2) / BROADCAST_STORM_VALUE; + *percent = (u8) num; +} + +/** + * sw_dis_broad_storm - disable broadstorm + * @hw: The hardware instance. + * @port: The port index. + * + * This routine disables the broadcast storm limit function of the switch. + */ +static void sw_dis_broad_storm(struct ksz_hw *hw, int port) +{ + port_cfg_broad_storm(hw, port, 0); +} + +/** + * sw_ena_broad_storm - enable broadcast storm + * @hw: The hardware instance. + * @port: The port index. + * + * This routine enables the broadcast storm limit function of the switch. + */ +static void sw_ena_broad_storm(struct ksz_hw *hw, int port) +{ + sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per); + port_cfg_broad_storm(hw, port, 1); +} + +/** + * sw_init_broad_storm - initialize broadcast storm + * @hw: The hardware instance. + * + * This routine initializes the broadcast storm limit function of the switch. + */ +static void sw_init_broad_storm(struct ksz_hw *hw) +{ + int port; + + hw->ksz_switch->broad_per = 1; + sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per); + for (port = 0; port < TOTAL_PORT_NUM; port++) + sw_dis_broad_storm(hw, port); + sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, MULTICAST_STORM_DISABLE, 1); +} + +/** + * hw_cfg_broad_storm - configure broadcast storm + * @hw: The hardware instance. + * @percent: Broadcast storm threshold in percent of transmit rate. + * + * This routine configures the broadcast storm threshold of the switch. + * It is called by user functions. The hardware should be acquired first. + */ +static void hw_cfg_broad_storm(struct ksz_hw *hw, u8 percent) +{ + if (percent > 100) + percent = 100; + + sw_cfg_broad_storm(hw, percent); + sw_get_broad_storm(hw, &percent); + hw->ksz_switch->broad_per = percent; +} + +/** + * sw_dis_prio_rate - disable switch priority rate + * @hw: The hardware instance. + * @port: The port index. + * + * This routine disables the priority rate function of the switch. + */ +static void sw_dis_prio_rate(struct ksz_hw *hw, int port) +{ + u32 addr; + + PORT_CTRL_ADDR(port, addr); + addr += KS8842_PORT_IN_RATE_OFFSET; + writel(0, hw->io + addr); +} + +/** + * sw_init_prio_rate - initialize switch prioirty rate + * @hw: The hardware instance. + * + * This routine initializes the priority rate function of the switch. + */ +static void sw_init_prio_rate(struct ksz_hw *hw) +{ + int port; + int prio; + struct ksz_switch *sw = hw->ksz_switch; + + for (port = 0; port < TOTAL_PORT_NUM; port++) { + for (prio = 0; prio < PRIO_QUEUES; prio++) { + sw->port_cfg[port].rx_rate[prio] = + sw->port_cfg[port].tx_rate[prio] = 0; + } + sw_dis_prio_rate(hw, port); + } +} + +/* Communication */ + +static inline void port_cfg_back_pressure(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE, set); +} + +static inline void port_cfg_force_flow_ctrl(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL, set); +} + +static inline int port_chk_back_pressure(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE); +} + +static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL); +} + +/* Spanning Tree */ + +static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set); +} + +static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_RX_ENABLE, set); +} + +static inline void port_cfg_tx(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_TX_ENABLE, set); +} + +static inline void sw_cfg_fast_aging(struct ksz_hw *hw, int set) +{ + sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, SWITCH_FAST_AGING, set); +} + +static inline void sw_flush_dyn_mac_table(struct ksz_hw *hw) +{ + if (!(hw->overrides & FAST_AGING)) { + sw_cfg_fast_aging(hw, 1); + mdelay(1); + sw_cfg_fast_aging(hw, 0); + } +} + +/* VLAN */ + +static inline void port_cfg_ins_tag(struct ksz_hw *hw, int p, int insert) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG, insert); +} + +static inline void port_cfg_rmv_tag(struct ksz_hw *hw, int p, int remove) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG, remove); +} + +static inline int port_chk_ins_tag(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG); +} + +static inline int port_chk_rmv_tag(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG); +} + +static inline void port_cfg_dis_non_vid(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID, set); +} + +static inline void port_cfg_in_filter(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER, set); +} + +static inline int port_chk_dis_non_vid(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID); +} + +static inline int port_chk_in_filter(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER); +} + +/* Mirroring */ + +static inline void port_cfg_mirror_sniffer(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_SNIFFER, set); +} + +static inline void port_cfg_mirror_rx(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_RX, set); +} + +static inline void port_cfg_mirror_tx(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_TX, set); +} + +static inline void sw_cfg_mirror_rx_tx(struct ksz_hw *hw, int set) +{ + sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, SWITCH_MIRROR_RX_TX, set); +} + +static void sw_init_mirror(struct ksz_hw *hw) +{ + int port; + + for (port = 0; port < TOTAL_PORT_NUM; port++) { + port_cfg_mirror_sniffer(hw, port, 0); + port_cfg_mirror_rx(hw, port, 0); + port_cfg_mirror_tx(hw, port, 0); + } + sw_cfg_mirror_rx_tx(hw, 0); +} + +static inline void sw_cfg_unk_def_deliver(struct ksz_hw *hw, int set) +{ + sw_cfg(hw, KS8842_SWITCH_CTRL_7_OFFSET, + SWITCH_UNK_DEF_PORT_ENABLE, set); +} + +static inline int sw_cfg_chk_unk_def_deliver(struct ksz_hw *hw) +{ + return sw_chk(hw, KS8842_SWITCH_CTRL_7_OFFSET, + SWITCH_UNK_DEF_PORT_ENABLE); +} + +static inline void sw_cfg_unk_def_port(struct ksz_hw *hw, int port, int set) +{ + port_cfg_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0, set); +} + +static inline int sw_chk_unk_def_port(struct ksz_hw *hw, int port) +{ + return port_chk_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0); +} + +/* Priority */ + +static inline void port_cfg_diffserv(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE, set); +} + +static inline void port_cfg_802_1p(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE, set); +} + +static inline void port_cfg_replace_vid(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING, set); +} + +static inline void port_cfg_prio(struct ksz_hw *hw, int p, int set) +{ + port_cfg(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE, set); +} + +static inline int port_chk_diffserv(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE); +} + +static inline int port_chk_802_1p(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE); +} + +static inline int port_chk_replace_vid(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING); +} + +static inline int port_chk_prio(struct ksz_hw *hw, int p) +{ + return port_chk(hw, p, + KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE); +} + +/** + * sw_dis_diffserv - disable switch DiffServ priority + * @hw: The hardware instance. + * @port: The port index. + * + * This routine disables the DiffServ priority function of the switch. + */ +static void sw_dis_diffserv(struct ksz_hw *hw, int port) +{ + port_cfg_diffserv(hw, port, 0); +} + +/** + * sw_dis_802_1p - disable switch 802.1p priority + * @hw: The hardware instance. + * @port: The port index. + * + * This routine disables the 802.1p priority function of the switch. + */ +static void sw_dis_802_1p(struct ksz_hw *hw, int port) +{ + port_cfg_802_1p(hw, port, 0); +} + +/** + * sw_cfg_replace_null_vid - + * @hw: The hardware instance. + * @set: The flag to disable or enable. + * + */ +static void sw_cfg_replace_null_vid(struct ksz_hw *hw, int set) +{ + sw_cfg(hw, KS8842_SWITCH_CTRL_3_OFFSET, SWITCH_REPLACE_NULL_VID, set); +} + +/** + * sw_cfg_replace_vid - enable switch 802.10 priority re-mapping + * @hw: The hardware instance. + * @port: The port index. + * @set: The flag to disable or enable. + * + * This routine enables the 802.1p priority re-mapping function of the switch. + * That allows 802.1p priority field to be replaced with the port's default + * tag's priority value if the ingress packet's 802.1p priority has a higher + * priority than port's default tag's priority. + */ +static void sw_cfg_replace_vid(struct ksz_hw *hw, int port, int set) +{ + port_cfg_replace_vid(hw, port, set); +} + +/** + * sw_cfg_port_based - configure switch port based priority + * @hw: The hardware instance. + * @port: The port index. + * @prio: The priority to set. + * + * This routine configures the port based priority of the switch. + */ +static void sw_cfg_port_based(struct ksz_hw *hw, int port, u8 prio) +{ + u16 data; + + if (prio > PORT_BASED_PRIORITY_BASE) + prio = PORT_BASED_PRIORITY_BASE; + + hw->ksz_switch->port_cfg[port].port_prio = prio; + + port_r16(hw, port, KS8842_PORT_CTRL_1_OFFSET, &data); + data &= ~PORT_BASED_PRIORITY_MASK; + data |= prio << PORT_BASED_PRIORITY_SHIFT; + port_w16(hw, port, KS8842_PORT_CTRL_1_OFFSET, data); +} + +/** + * sw_dis_multi_queue - disable transmit multiple queues + * @hw: The hardware instance. + * @port: The port index. + * + * This routine disables the transmit multiple queues selection of the switch + * port. Only single transmit queue on the port. + */ +static void sw_dis_multi_queue(struct ksz_hw *hw, int port) +{ + port_cfg_prio(hw, port, 0); +} + +/** + * sw_init_prio - initialize switch priority + * @hw: The hardware instance. + * + * This routine initializes the switch QoS priority functions. + */ +static void sw_init_prio(struct ksz_hw *hw) +{ + int port; + int tos; + struct ksz_switch *sw = hw->ksz_switch; + + /* + * Init all the 802.1p tag priority value to be assigned to different + * priority queue. + */ + sw->p_802_1p[0] = 0; + sw->p_802_1p[1] = 0; + sw->p_802_1p[2] = 1; + sw->p_802_1p[3] = 1; + sw->p_802_1p[4] = 2; + sw->p_802_1p[5] = 2; + sw->p_802_1p[6] = 3; + sw->p_802_1p[7] = 3; + + /* + * Init all the DiffServ priority value to be assigned to priority + * queue 0. + */ + for (tos = 0; tos < DIFFSERV_ENTRIES; tos++) + sw->diffserv[tos] = 0; + + /* All QoS functions disabled. */ + for (port = 0; port < TOTAL_PORT_NUM; port++) { + sw_dis_multi_queue(hw, port); + sw_dis_diffserv(hw, port); + sw_dis_802_1p(hw, port); + sw_cfg_replace_vid(hw, port, 0); + + sw->port_cfg[port].port_prio = 0; + sw_cfg_port_based(hw, port, sw->port_cfg[port].port_prio); + } + sw_cfg_replace_null_vid(hw, 0); +} + +/** + * port_get_def_vid - get port default VID. + * @hw: The hardware instance. + * @port: The port index. + * @vid: Buffer to store the VID. + * + * This routine retrieves the default VID of the port. + */ +static void port_get_def_vid(struct ksz_hw *hw, int port, u16 *vid) +{ + u32 addr; + + PORT_CTRL_ADDR(port, addr); + addr += KS8842_PORT_CTRL_VID_OFFSET; + *vid = readw(hw->io + addr); +} + +/** + * sw_init_vlan - initialize switch VLAN + * @hw: The hardware instance. + * + * This routine initializes the VLAN function of the switch. + */ +static void sw_init_vlan(struct ksz_hw *hw) +{ + int port; + int entry; + struct ksz_switch *sw = hw->ksz_switch; + + /* Read 16 VLAN entries from device's VLAN table. */ + for (entry = 0; entry < VLAN_TABLE_ENTRIES; entry++) { + sw_r_vlan_table(hw, entry, + &sw->vlan_table[entry].vid, + &sw->vlan_table[entry].fid, + &sw->vlan_table[entry].member); + } + + for (port = 0; port < TOTAL_PORT_NUM; port++) { + port_get_def_vid(hw, port, &sw->port_cfg[port].vid); + sw->port_cfg[port].member = PORT_MASK; + } +} + +/** + * sw_cfg_port_base_vlan - configure port-based VLAN membership + * @hw: The hardware instance. + * @port: The port index. + * @member: The port-based VLAN membership. + * + * This routine configures the port-based VLAN membership of the port. + */ +static void sw_cfg_port_base_vlan(struct ksz_hw *hw, int port, u8 member) +{ + u32 addr; + u8 data; + + PORT_CTRL_ADDR(port, addr); + addr += KS8842_PORT_CTRL_2_OFFSET; + + data = readb(hw->io + addr); + data &= ~PORT_VLAN_MEMBERSHIP; + data |= (member & PORT_MASK); + writeb(data, hw->io + addr); + + hw->ksz_switch->port_cfg[port].member = member; +} + +/** + * sw_get_addr - get the switch MAC address. + * @hw: The hardware instance. + * @mac_addr: Buffer to store the MAC address. + * + * This function retrieves the MAC address of the switch. + */ +static inline void sw_get_addr(struct ksz_hw *hw, u8 *mac_addr) +{ + int i; + + for (i = 0; i < 6; i += 2) { + mac_addr[i] = readb(hw->io + KS8842_MAC_ADDR_0_OFFSET + i); + mac_addr[1 + i] = readb(hw->io + KS8842_MAC_ADDR_1_OFFSET + i); + } +} + +/** + * sw_set_addr - configure switch MAC address + * @hw: The hardware instance. + * @mac_addr: The MAC address. + * + * This function configures the MAC address of the switch. + */ +static void sw_set_addr(struct ksz_hw *hw, u8 *mac_addr) +{ + int i; + + for (i = 0; i < 6; i += 2) { + writeb(mac_addr[i], hw->io + KS8842_MAC_ADDR_0_OFFSET + i); + writeb(mac_addr[1 + i], hw->io + KS8842_MAC_ADDR_1_OFFSET + i); + } +} + +/** + * sw_set_global_ctrl - set switch global control + * @hw: The hardware instance. + * + * This routine sets the global control of the switch function. + */ +static void sw_set_global_ctrl(struct ksz_hw *hw) +{ + u16 data; + + /* Enable switch MII flow control. */ + data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); + data |= SWITCH_FLOW_CTRL; + writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET); + + data = readw(hw->io + KS8842_SWITCH_CTRL_1_OFFSET); + + /* Enable aggressive back off algorithm in half duplex mode. */ + data |= SWITCH_AGGR_BACKOFF; + + /* Enable automatic fast aging when link changed detected. */ + data |= SWITCH_AGING_ENABLE; + data |= SWITCH_LINK_AUTO_AGING; + + if (hw->overrides & FAST_AGING) + data |= SWITCH_FAST_AGING; + else + data &= ~SWITCH_FAST_AGING; + writew(data, hw->io + KS8842_SWITCH_CTRL_1_OFFSET); + + data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET); + + /* Enable no excessive collision drop. */ + data |= NO_EXC_COLLISION_DROP; + writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET); +} + +enum { + STP_STATE_DISABLED = 0, + STP_STATE_LISTENING, + STP_STATE_LEARNING, + STP_STATE_FORWARDING, + STP_STATE_BLOCKED, + STP_STATE_SIMPLE +}; + +/** + * port_set_stp_state - configure port spanning tree state + * @hw: The hardware instance. + * @port: The port index. + * @state: The spanning tree state. + * + * This routine configures the spanning tree state of the port. + */ +static void port_set_stp_state(struct ksz_hw *hw, int port, int state) +{ + u16 data; + + port_r16(hw, port, KS8842_PORT_CTRL_2_OFFSET, &data); + switch (state) { + case STP_STATE_DISABLED: + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE); + data |= PORT_LEARN_DISABLE; + break; + case STP_STATE_LISTENING: +/* + * No need to turn on transmit because of port direct mode. + * Turning on receive is required if static MAC table is not setup. + */ + data &= ~PORT_TX_ENABLE; + data |= PORT_RX_ENABLE; + data |= PORT_LEARN_DISABLE; + break; + case STP_STATE_LEARNING: + data &= ~PORT_TX_ENABLE; + data |= PORT_RX_ENABLE; + data &= ~PORT_LEARN_DISABLE; + break; + case STP_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + data &= ~PORT_LEARN_DISABLE; + break; + case STP_STATE_BLOCKED: +/* + * Need to setup static MAC table with override to keep receiving BPDU + * messages. See sw_init_stp routine. + */ + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE); + data |= PORT_LEARN_DISABLE; + break; + case STP_STATE_SIMPLE: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + data |= PORT_LEARN_DISABLE; + break; + } + port_w16(hw, port, KS8842_PORT_CTRL_2_OFFSET, data); + hw->ksz_switch->port_cfg[port].stp_state = state; +} + +#define STP_ENTRY 0 +#define BROADCAST_ENTRY 1 +#define BRIDGE_ADDR_ENTRY 2 +#define IPV6_ADDR_ENTRY 3 + +/** + * sw_clr_sta_mac_table - clear static MAC table + * @hw: The hardware instance. + * + * This routine clears the static MAC table. + */ +static void sw_clr_sta_mac_table(struct ksz_hw *hw) +{ + struct ksz_mac_table *entry; + int i; + + for (i = 0; i < STATIC_MAC_TABLE_ENTRIES; i++) { + entry = &hw->ksz_switch->mac_table[i]; + sw_w_sta_mac_table(hw, i, + entry->mac_addr, entry->ports, + entry->override, 0, + entry->use_fid, entry->fid); + } +} + +/** + * sw_init_stp - initialize switch spanning tree support + * @hw: The hardware instance. + * + * This routine initializes the spanning tree support of the switch. + */ +static void sw_init_stp(struct ksz_hw *hw) +{ + struct ksz_mac_table *entry; + + entry = &hw->ksz_switch->mac_table[STP_ENTRY]; + entry->mac_addr[0] = 0x01; + entry->mac_addr[1] = 0x80; + entry->mac_addr[2] = 0xC2; + entry->mac_addr[3] = 0x00; + entry->mac_addr[4] = 0x00; + entry->mac_addr[5] = 0x00; + entry->ports = HOST_MASK; + entry->override = 1; + entry->valid = 1; + sw_w_sta_mac_table(hw, STP_ENTRY, + entry->mac_addr, entry->ports, + entry->override, entry->valid, + entry->use_fid, entry->fid); +} + +/** + * sw_block_addr - block certain packets from the host port + * @hw: The hardware instance. + * + * This routine blocks certain packets from reaching to the host port. + */ +static void sw_block_addr(struct ksz_hw *hw) +{ + struct ksz_mac_table *entry; + int i; + + for (i = BROADCAST_ENTRY; i <= IPV6_ADDR_ENTRY; i++) { + entry = &hw->ksz_switch->mac_table[i]; + entry->valid = 0; + sw_w_sta_mac_table(hw, i, + entry->mac_addr, entry->ports, + entry->override, entry->valid, + entry->use_fid, entry->fid); + } +} + +#define PHY_LINK_SUPPORT \ + (PHY_AUTO_NEG_ASYM_PAUSE | \ + PHY_AUTO_NEG_SYM_PAUSE | \ + PHY_AUTO_NEG_100BT4 | \ + PHY_AUTO_NEG_100BTX_FD | \ + PHY_AUTO_NEG_100BTX | \ + PHY_AUTO_NEG_10BT_FD | \ + PHY_AUTO_NEG_10BT) + +static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET); +} + +static inline void hw_w_phy_ctrl(struct ksz_hw *hw, int phy, u16 data) +{ + writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET); +} + +static inline void hw_r_phy_link_stat(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_STATUS_OFFSET); +} + +static inline void hw_r_phy_auto_neg(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET); +} + +static inline void hw_w_phy_auto_neg(struct ksz_hw *hw, int phy, u16 data) +{ + writew(data, hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET); +} + +static inline void hw_r_phy_rem_cap(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_REMOTE_CAP_OFFSET); +} + +static inline void hw_r_phy_crossover(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET); +} + +static inline void hw_w_phy_crossover(struct ksz_hw *hw, int phy, u16 data) +{ + writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET); +} + +static inline void hw_r_phy_polarity(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET); +} + +static inline void hw_w_phy_polarity(struct ksz_hw *hw, int phy, u16 data) +{ + writew(data, hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET); +} + +static inline void hw_r_phy_link_md(struct ksz_hw *hw, int phy, u16 *data) +{ + *data = readw(hw->io + phy + KS884X_PHY_LINK_MD_OFFSET); +} + +static inline void hw_w_phy_link_md(struct ksz_hw *hw, int phy, u16 data) +{ + writew(data, hw->io + phy + KS884X_PHY_LINK_MD_OFFSET); +} + +/** + * hw_r_phy - read data from PHY register + * @hw: The hardware instance. + * @port: Port to read. + * @reg: PHY register to read. + * @val: Buffer to store the read data. + * + * This routine reads data from the PHY register. + */ +static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val) +{ + int phy; + + phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg; + *val = readw(hw->io + phy); +} + +/** + * port_w_phy - write data to PHY register + * @hw: The hardware instance. + * @port: Port to write. + * @reg: PHY register to write. + * @val: Word data to write. + * + * This routine writes data to the PHY register. + */ +static void hw_w_phy(struct ksz_hw *hw, int port, u16 reg, u16 val) +{ + int phy; + + phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg; + writew(val, hw->io + phy); +} + +/* + * EEPROM access functions + */ + +#define AT93C_CODE 0 +#define AT93C_WR_OFF 0x00 +#define AT93C_WR_ALL 0x10 +#define AT93C_ER_ALL 0x20 +#define AT93C_WR_ON 0x30 + +#define AT93C_WRITE 1 +#define AT93C_READ 2 +#define AT93C_ERASE 3 + +#define EEPROM_DELAY 4 + +static inline void drop_gpio(struct ksz_hw *hw, u8 gpio) +{ + u16 data; + + data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); + data &= ~gpio; + writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET); +} + +static inline void raise_gpio(struct ksz_hw *hw, u8 gpio) +{ + u16 data; + + data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); + data |= gpio; + writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET); +} + +static inline u8 state_gpio(struct ksz_hw *hw, u8 gpio) +{ + u16 data; + + data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); + return (u8)(data & gpio); +} + +static void eeprom_clk(struct ksz_hw *hw) +{ + raise_gpio(hw, EEPROM_SERIAL_CLOCK); + udelay(EEPROM_DELAY); + drop_gpio(hw, EEPROM_SERIAL_CLOCK); + udelay(EEPROM_DELAY); +} + +static u16 spi_r(struct ksz_hw *hw) +{ + int i; + u16 temp = 0; + + for (i = 15; i >= 0; i--) { + raise_gpio(hw, EEPROM_SERIAL_CLOCK); + udelay(EEPROM_DELAY); + + temp |= (state_gpio(hw, EEPROM_DATA_IN)) ? 1 << i : 0; + + drop_gpio(hw, EEPROM_SERIAL_CLOCK); + udelay(EEPROM_DELAY); + } + return temp; +} + +static void spi_w(struct ksz_hw *hw, u16 data) +{ + int i; + + for (i = 15; i >= 0; i--) { + (data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : + drop_gpio(hw, EEPROM_DATA_OUT); + eeprom_clk(hw); + } +} + +static void spi_reg(struct ksz_hw *hw, u8 data, u8 reg) +{ + int i; + + /* Initial start bit */ + raise_gpio(hw, EEPROM_DATA_OUT); + eeprom_clk(hw); + + /* AT93C operation */ + for (i = 1; i >= 0; i--) { + (data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : + drop_gpio(hw, EEPROM_DATA_OUT); + eeprom_clk(hw); + } + + /* Address location */ + for (i = 5; i >= 0; i--) { + (reg & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : + drop_gpio(hw, EEPROM_DATA_OUT); + eeprom_clk(hw); + } +} + +#define EEPROM_DATA_RESERVED 0 +#define EEPROM_DATA_MAC_ADDR_0 1 +#define EEPROM_DATA_MAC_ADDR_1 2 +#define EEPROM_DATA_MAC_ADDR_2 3 +#define EEPROM_DATA_SUBSYS_ID 4 +#define EEPROM_DATA_SUBSYS_VEN_ID 5 +#define EEPROM_DATA_PM_CAP 6 + +/* User defined EEPROM data */ +#define EEPROM_DATA_OTHER_MAC_ADDR 9 + +/** + * eeprom_read - read from AT93C46 EEPROM + * @hw: The hardware instance. + * @reg: The register offset. + * + * This function reads a word from the AT93C46 EEPROM. + * + * Return the data value. + */ +static u16 eeprom_read(struct ksz_hw *hw, u8 reg) +{ + u16 data; + + raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); + + spi_reg(hw, AT93C_READ, reg); + data = spi_r(hw); + + drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); + + return data; +} + +/** + * eeprom_write - write to AT93C46 EEPROM + * @hw: The hardware instance. + * @reg: The register offset. + * @data: The data value. + * + * This procedure writes a word to the AT93C46 EEPROM. + */ +static void eeprom_write(struct ksz_hw *hw, u8 reg, u16 data) +{ + int timeout; + + raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); + + /* Enable write. */ + spi_reg(hw, AT93C_CODE, AT93C_WR_ON); + drop_gpio(hw, EEPROM_CHIP_SELECT); + udelay(1); + + /* Erase the register. */ + raise_gpio(hw, EEPROM_CHIP_SELECT); + spi_reg(hw, AT93C_ERASE, reg); + drop_gpio(hw, EEPROM_CHIP_SELECT); + udelay(1); + + /* Check operation complete. */ + raise_gpio(hw, EEPROM_CHIP_SELECT); + timeout = 8; + mdelay(2); + do { + mdelay(1); + } while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout); + drop_gpio(hw, EEPROM_CHIP_SELECT); + udelay(1); + + /* Write the register. */ + raise_gpio(hw, EEPROM_CHIP_SELECT); + spi_reg(hw, AT93C_WRITE, reg); + spi_w(hw, data); + drop_gpio(hw, EEPROM_CHIP_SELECT); + udelay(1); + + /* Check operation complete. */ + raise_gpio(hw, EEPROM_CHIP_SELECT); + timeout = 8; + mdelay(2); + do { + mdelay(1); + } while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout); + drop_gpio(hw, EEPROM_CHIP_SELECT); + udelay(1); + + /* Disable write. */ + raise_gpio(hw, EEPROM_CHIP_SELECT); + spi_reg(hw, AT93C_CODE, AT93C_WR_OFF); + + drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); +} + +/* + * Link detection routines + */ + +static u16 advertised_flow_ctrl(struct ksz_port *port, u16 ctrl) +{ + ctrl &= ~PORT_AUTO_NEG_SYM_PAUSE; + switch (port->flow_ctrl) { + case PHY_FLOW_CTRL: + ctrl |= PORT_AUTO_NEG_SYM_PAUSE; + break; + /* Not supported. */ + case PHY_TX_ONLY: + case PHY_RX_ONLY: + default: + break; + } + return ctrl; +} + +static void set_flow_ctrl(struct ksz_hw *hw, int rx, int tx) +{ + u32 rx_cfg; + u32 tx_cfg; + + rx_cfg = hw->rx_cfg; + tx_cfg = hw->tx_cfg; + if (rx) + hw->rx_cfg |= DMA_RX_FLOW_ENABLE; + else + hw->rx_cfg &= ~DMA_RX_FLOW_ENABLE; + if (tx) + hw->tx_cfg |= DMA_TX_FLOW_ENABLE; + else + hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE; + if (hw->enabled) { + if (rx_cfg != hw->rx_cfg) + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + if (tx_cfg != hw->tx_cfg) + writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); + } +} + +static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port, + u16 local, u16 remote) +{ + int rx; + int tx; + + if (hw->overrides & PAUSE_FLOW_CTRL) + return; + + rx = tx = 0; + if (port->force_link) + rx = tx = 1; + if (remote & PHY_AUTO_NEG_SYM_PAUSE) { + if (local & PHY_AUTO_NEG_SYM_PAUSE) { + rx = tx = 1; + } else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) && + (local & PHY_AUTO_NEG_PAUSE) == + PHY_AUTO_NEG_ASYM_PAUSE) { + tx = 1; + } + } else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) { + if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE) + rx = 1; + } + if (!hw->ksz_switch) + set_flow_ctrl(hw, rx, tx); +} + +static inline void port_cfg_change(struct ksz_hw *hw, struct ksz_port *port, + struct ksz_port_info *info, u16 link_status) +{ + if ((hw->features & HALF_DUPLEX_SIGNAL_BUG) && + !(hw->overrides & PAUSE_FLOW_CTRL)) { + u32 cfg = hw->tx_cfg; + + /* Disable flow control in the half duplex mode. */ + if (1 == info->duplex) + hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE; + if (hw->enabled && cfg != hw->tx_cfg) + writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); + } +} + +/** + * port_get_link_speed - get current link status + * @port: The port instance. + * + * This routine reads PHY registers to determine the current link status of the + * switch ports. + */ +static void port_get_link_speed(struct ksz_port *port) +{ + uint interrupt; + struct ksz_port_info *info; + struct ksz_port_info *linked = NULL; + struct ksz_hw *hw = port->hw; + u16 data; + u16 status; + u8 local; + u8 remote; + int i; + int p; + int change = 0; + + interrupt = hw_block_intr(hw); + + for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { + info = &hw->port_info[p]; + port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data); + port_r16(hw, p, KS884X_PORT_STATUS_OFFSET, &status); + + /* + * Link status is changing all the time even when there is no + * cable connection! + */ + remote = status & (PORT_AUTO_NEG_COMPLETE | + PORT_STATUS_LINK_GOOD); + local = (u8) data; + + /* No change to status. */ + if (local == info->advertised && remote == info->partner) + continue; + + info->advertised = local; + info->partner = remote; + if (status & PORT_STATUS_LINK_GOOD) { + + /* Remember the first linked port. */ + if (!linked) + linked = info; + + info->tx_rate = 10 * TX_RATE_UNIT; + if (status & PORT_STATUS_SPEED_100MBIT) + info->tx_rate = 100 * TX_RATE_UNIT; + + info->duplex = 1; + if (status & PORT_STATUS_FULL_DUPLEX) + info->duplex = 2; + + if (media_connected != info->state) { + hw_r_phy(hw, p, KS884X_PHY_AUTO_NEG_OFFSET, + &data); + hw_r_phy(hw, p, KS884X_PHY_REMOTE_CAP_OFFSET, + &status); + determine_flow_ctrl(hw, port, data, status); + if (hw->ksz_switch) { + port_cfg_back_pressure(hw, p, + (1 == info->duplex)); + } + change |= 1 << i; + port_cfg_change(hw, port, info, status); + } + info->state = media_connected; + } else { + if (media_disconnected != info->state) { + change |= 1 << i; + + /* Indicate the link just goes down. */ + hw->port_mib[p].link_down = 1; + } + info->state = media_disconnected; + } + hw->port_mib[p].state = (u8) info->state; + } + + if (linked && media_disconnected == port->linked->state) + port->linked = linked; + + hw_restore_intr(hw, interrupt); +} + +#define PHY_RESET_TIMEOUT 10 + +/** + * port_set_link_speed - set port speed + * @port: The port instance. + * + * This routine sets the link speed of the switch ports. + */ +static void port_set_link_speed(struct ksz_port *port) +{ + struct ksz_port_info *info; + struct ksz_hw *hw = port->hw; + u16 data; + u16 cfg; + u8 status; + int i; + int p; + + for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { + info = &hw->port_info[p]; + + port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data); + port_r8(hw, p, KS884X_PORT_STATUS_OFFSET, &status); + + cfg = 0; + if (status & PORT_STATUS_LINK_GOOD) + cfg = data; + + data |= PORT_AUTO_NEG_ENABLE; + data = advertised_flow_ctrl(port, data); + + data |= PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX | + PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT; + + /* Check if manual configuration is specified by the user. */ + if (port->speed || port->duplex) { + if (10 == port->speed) + data &= ~(PORT_AUTO_NEG_100BTX_FD | + PORT_AUTO_NEG_100BTX); + else if (100 == port->speed) + data &= ~(PORT_AUTO_NEG_10BT_FD | + PORT_AUTO_NEG_10BT); + if (1 == port->duplex) + data &= ~(PORT_AUTO_NEG_100BTX_FD | + PORT_AUTO_NEG_10BT_FD); + else if (2 == port->duplex) + data &= ~(PORT_AUTO_NEG_100BTX | + PORT_AUTO_NEG_10BT); + } + if (data != cfg) { + data |= PORT_AUTO_NEG_RESTART; + port_w16(hw, p, KS884X_PORT_CTRL_4_OFFSET, data); + } + } +} + +/** + * port_force_link_speed - force port speed + * @port: The port instance. + * + * This routine forces the link speed of the switch ports. + */ +static void port_force_link_speed(struct ksz_port *port) +{ + struct ksz_hw *hw = port->hw; + u16 data; + int i; + int phy; + int p; + + for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { + phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL; + hw_r_phy_ctrl(hw, phy, &data); + + data &= ~PHY_AUTO_NEG_ENABLE; + + if (10 == port->speed) + data &= ~PHY_SPEED_100MBIT; + else if (100 == port->speed) + data |= PHY_SPEED_100MBIT; + if (1 == port->duplex) + data &= ~PHY_FULL_DUPLEX; + else if (2 == port->duplex) + data |= PHY_FULL_DUPLEX; + hw_w_phy_ctrl(hw, phy, data); + } +} + +static void port_set_power_saving(struct ksz_port *port, int enable) +{ + struct ksz_hw *hw = port->hw; + int i; + int p; + + for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) + port_cfg(hw, p, + KS884X_PORT_CTRL_4_OFFSET, PORT_POWER_DOWN, enable); +} + +/* + * KSZ8841 power management functions + */ + +/** + * hw_chk_wol_pme_status - check PMEN pin + * @hw: The hardware instance. + * + * This function is used to check PMEN pin is asserted. + * + * Return 1 if PMEN pin is asserted; otherwise, 0. + */ +static int hw_chk_wol_pme_status(struct ksz_hw *hw) +{ + struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); + struct pci_dev *pdev = hw_priv->pdev; + u16 data; + + if (!pdev->pm_cap) + return 0; + pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); + return (data & PCI_PM_CTRL_PME_STATUS) == PCI_PM_CTRL_PME_STATUS; +} + +/** + * hw_clr_wol_pme_status - clear PMEN pin + * @hw: The hardware instance. + * + * This routine is used to clear PME_Status to deassert PMEN pin. + */ +static void hw_clr_wol_pme_status(struct ksz_hw *hw) +{ + struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); + struct pci_dev *pdev = hw_priv->pdev; + u16 data; + + if (!pdev->pm_cap) + return; + + /* Clear PME_Status to deassert PMEN pin. */ + pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); + data |= PCI_PM_CTRL_PME_STATUS; + pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data); +} + +/** + * hw_cfg_wol_pme - enable or disable Wake-on-LAN + * @hw: The hardware instance. + * @set: The flag indicating whether to enable or disable. + * + * This routine is used to enable or disable Wake-on-LAN. + */ +static void hw_cfg_wol_pme(struct ksz_hw *hw, int set) +{ + struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); + struct pci_dev *pdev = hw_priv->pdev; + u16 data; + + if (!pdev->pm_cap) + return; + pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); + data &= ~PCI_PM_CTRL_STATE_MASK; + if (set) + data |= PCI_PM_CTRL_PME_ENABLE | PCI_D3hot; + else + data &= ~PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data); +} + +/** + * hw_cfg_wol - configure Wake-on-LAN features + * @hw: The hardware instance. + * @frame: The pattern frame bit. + * @set: The flag indicating whether to enable or disable. + * + * This routine is used to enable or disable certain Wake-on-LAN features. + */ +static void hw_cfg_wol(struct ksz_hw *hw, u16 frame, int set) +{ + u16 data; + + data = readw(hw->io + KS8841_WOL_CTRL_OFFSET); + if (set) + data |= frame; + else + data &= ~frame; + writew(data, hw->io + KS8841_WOL_CTRL_OFFSET); +} + +/** + * hw_set_wol_frame - program Wake-on-LAN pattern + * @hw: The hardware instance. + * @i: The frame index. + * @mask_size: The size of the mask. + * @mask: Mask to ignore certain bytes in the pattern. + * @frame_size: The size of the frame. + * @pattern: The frame data. + * + * This routine is used to program Wake-on-LAN pattern. + */ +static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size, + u8 *mask, uint frame_size, u8 *pattern) +{ + int bits; + int from; + int len; + int to; + u32 crc; + u8 data[64]; + u8 val = 0; + + if (frame_size > mask_size * 8) + frame_size = mask_size * 8; + if (frame_size > 64) + frame_size = 64; + + i *= 0x10; + writel(0, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i); + writel(0, hw->io + KS8841_WOL_FRAME_BYTE2_OFFSET + i); + + bits = len = from = to = 0; + do { + if (bits) { + if ((val & 1)) + data[to++] = pattern[from]; + val >>= 1; + ++from; + --bits; + } else { + val = mask[len]; + writeb(val, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i + + len); + ++len; + if (val) + bits = 8; + else + from += 8; + } + } while (from < (int) frame_size); + if (val) { + bits = mask[len - 1]; + val <<= (from % 8); + bits &= ~val; + writeb(bits, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i + len - + 1); + } + crc = ether_crc(to, data); + writel(crc, hw->io + KS8841_WOL_FRAME_CRC_OFFSET + i); +} + +/** + * hw_add_wol_arp - add ARP pattern + * @hw: The hardware instance. + * @ip_addr: The IPv4 address assigned to the device. + * + * This routine is used to add ARP pattern for waking up the host. + */ +static void hw_add_wol_arp(struct ksz_hw *hw, u8 *ip_addr) +{ + u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 }; + u8 pattern[42] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x06, + 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + memcpy(&pattern[38], ip_addr, 4); + hw_set_wol_frame(hw, 3, 6, mask, 42, pattern); +} + +/** + * hw_add_wol_bcast - add broadcast pattern + * @hw: The hardware instance. + * + * This routine is used to add broadcast pattern for waking up the host. + */ +static void hw_add_wol_bcast(struct ksz_hw *hw) +{ + u8 mask[] = { 0x3F }; + u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern); +} + +/** + * hw_add_wol_mcast - add multicast pattern + * @hw: The hardware instance. + * + * This routine is used to add multicast pattern for waking up the host. + * + * It is assumed the multicast packet is the ICMPv6 neighbor solicitation used + * by IPv6 ping command. Note that multicast packets are filtred through the + * multicast hash table, so not all multicast packets can wake up the host. + */ +static void hw_add_wol_mcast(struct ksz_hw *hw) +{ + u8 mask[] = { 0x3F }; + u8 pattern[] = { 0x33, 0x33, 0xFF, 0x00, 0x00, 0x00 }; + + memcpy(&pattern[3], &hw->override_addr[3], 3); + hw_set_wol_frame(hw, 1, 1, mask, 6, pattern); +} + +/** + * hw_add_wol_ucast - add unicast pattern + * @hw: The hardware instance. + * + * This routine is used to add unicast pattern to wakeup the host. + * + * It is assumed the unicast packet is directed to the device, as the hardware + * can only receive them in normal case. + */ +static void hw_add_wol_ucast(struct ksz_hw *hw) +{ + u8 mask[] = { 0x3F }; + + hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr); +} + +/** + * hw_enable_wol - enable Wake-on-LAN + * @hw: The hardware instance. + * @wol_enable: The Wake-on-LAN settings. + * @net_addr: The IPv4 address assigned to the device. + * + * This routine is used to enable Wake-on-LAN depending on driver settings. + */ +static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, u8 *net_addr) +{ + hw_cfg_wol(hw, KS8841_WOL_MAGIC_ENABLE, (wol_enable & WAKE_MAGIC)); + hw_cfg_wol(hw, KS8841_WOL_FRAME0_ENABLE, (wol_enable & WAKE_UCAST)); + hw_add_wol_ucast(hw); + hw_cfg_wol(hw, KS8841_WOL_FRAME1_ENABLE, (wol_enable & WAKE_MCAST)); + hw_add_wol_mcast(hw); + hw_cfg_wol(hw, KS8841_WOL_FRAME2_ENABLE, (wol_enable & WAKE_BCAST)); + hw_cfg_wol(hw, KS8841_WOL_FRAME3_ENABLE, (wol_enable & WAKE_ARP)); + hw_add_wol_arp(hw, net_addr); +} + +/** + * hw_init - check driver is correct for the hardware + * @hw: The hardware instance. + * + * This function checks the hardware is correct for this driver and sets the + * hardware up for proper initialization. + * + * Return number of ports or 0 if not right. + */ +static int hw_init(struct ksz_hw *hw) +{ + int rc = 0; + u16 data; + u16 revision; + + /* Set bus speed to 125MHz. */ + writew(BUS_SPEED_125_MHZ, hw->io + KS884X_BUS_CTRL_OFFSET); + + /* Check KSZ884x chip ID. */ + data = readw(hw->io + KS884X_CHIP_ID_OFFSET); + + revision = (data & KS884X_REVISION_MASK) >> KS884X_REVISION_SHIFT; + data &= KS884X_CHIP_ID_MASK_41; + if (REG_CHIP_ID_41 == data) + rc = 1; + else if (REG_CHIP_ID_42 == data) + rc = 2; + else + return 0; + + /* Setup hardware features or bug workarounds. */ + if (revision <= 1) { + hw->features |= SMALL_PACKET_TX_BUG; + if (1 == rc) + hw->features |= HALF_DUPLEX_SIGNAL_BUG; + } + hw->features |= IPV6_CSUM_GEN_HACK; + return rc; +} + +/** + * hw_reset - reset the hardware + * @hw: The hardware instance. + * + * This routine resets the hardware. + */ +static void hw_reset(struct ksz_hw *hw) +{ + writew(GLOBAL_SOFTWARE_RESET, hw->io + KS884X_GLOBAL_CTRL_OFFSET); + + /* Wait for device to reset. */ + mdelay(10); + + /* Write 0 to clear device reset. */ + writew(0, hw->io + KS884X_GLOBAL_CTRL_OFFSET); +} + +/** + * hw_setup - setup the hardware + * @hw: The hardware instance. + * + * This routine setup the hardware for proper operation. + */ +static void hw_setup(struct ksz_hw *hw) +{ +#if SET_DEFAULT_LED + u16 data; + + /* Change default LED mode. */ + data = readw(hw->io + KS8842_SWITCH_CTRL_5_OFFSET); + data &= ~LED_MODE; + data |= SET_DEFAULT_LED; + writew(data, hw->io + KS8842_SWITCH_CTRL_5_OFFSET); +#endif + + /* Setup transmit control. */ + hw->tx_cfg = (DMA_TX_PAD_ENABLE | DMA_TX_CRC_ENABLE | + (DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_TX_ENABLE); + + /* Setup receive control. */ + hw->rx_cfg = (DMA_RX_BROADCAST | DMA_RX_UNICAST | + (DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_RX_ENABLE); + hw->rx_cfg |= KS884X_DMA_RX_MULTICAST; + + /* Hardware cannot handle UDP packet in IP fragments. */ + hw->rx_cfg |= (DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); + + if (hw->all_multi) + hw->rx_cfg |= DMA_RX_ALL_MULTICAST; + if (hw->promiscuous) + hw->rx_cfg |= DMA_RX_PROMISCUOUS; +} + +/** + * hw_setup_intr - setup interrupt mask + * @hw: The hardware instance. + * + * This routine setup the interrupt mask for proper operation. + */ +static void hw_setup_intr(struct ksz_hw *hw) +{ + hw->intr_mask = KS884X_INT_MASK | KS884X_INT_RX_OVERRUN; +} + +static void ksz_check_desc_num(struct ksz_desc_info *info) +{ +#define MIN_DESC_SHIFT 2 + + int alloc = info->alloc; + int shift; + + shift = 0; + while (!(alloc & 1)) { + shift++; + alloc >>= 1; + } + if (alloc != 1 || shift < MIN_DESC_SHIFT) { + printk(KERN_ALERT "Hardware descriptor numbers not right!\n"); + while (alloc) { + shift++; + alloc >>= 1; + } + if (shift < MIN_DESC_SHIFT) + shift = MIN_DESC_SHIFT; + alloc = 1 << shift; + info->alloc = alloc; + } + info->mask = info->alloc - 1; +} + +static void hw_init_desc(struct ksz_desc_info *desc_info, int transmit) +{ + int i; + u32 phys = desc_info->ring_phys; + struct ksz_hw_desc *desc = desc_info->ring_virt; + struct ksz_desc *cur = desc_info->ring; + struct ksz_desc *previous = NULL; + + for (i = 0; i < desc_info->alloc; i++) { + cur->phw = desc++; + phys += desc_info->size; + previous = cur++; + previous->phw->next = cpu_to_le32(phys); + } + previous->phw->next = cpu_to_le32(desc_info->ring_phys); + previous->sw.buf.rx.end_of_ring = 1; + previous->phw->buf.data = cpu_to_le32(previous->sw.buf.data); + + desc_info->avail = desc_info->alloc; + desc_info->last = desc_info->next = 0; + + desc_info->cur = desc_info->ring; +} + +/** + * hw_set_desc_base - set descriptor base addresses + * @hw: The hardware instance. + * @tx_addr: The transmit descriptor base. + * @rx_addr: The receive descriptor base. + * + * This routine programs the descriptor base addresses after reset. + */ +static void hw_set_desc_base(struct ksz_hw *hw, u32 tx_addr, u32 rx_addr) +{ + /* Set base address of Tx/Rx descriptors. */ + writel(tx_addr, hw->io + KS_DMA_TX_ADDR); + writel(rx_addr, hw->io + KS_DMA_RX_ADDR); +} + +static void hw_reset_pkts(struct ksz_desc_info *info) +{ + info->cur = info->ring; + info->avail = info->alloc; + info->last = info->next = 0; +} + +static inline void hw_resume_rx(struct ksz_hw *hw) +{ + writel(DMA_START, hw->io + KS_DMA_RX_START); +} + +/** + * hw_start_rx - start receiving + * @hw: The hardware instance. + * + * This routine starts the receive function of the hardware. + */ +static void hw_start_rx(struct ksz_hw *hw) +{ + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + + /* Notify when the receive stops. */ + hw->intr_mask |= KS884X_INT_RX_STOPPED; + + writel(DMA_START, hw->io + KS_DMA_RX_START); + hw_ack_intr(hw, KS884X_INT_RX_STOPPED); + hw->rx_stop++; + + /* Variable overflows. */ + if (0 == hw->rx_stop) + hw->rx_stop = 2; +} + +/* + * hw_stop_rx - stop receiving + * @hw: The hardware instance. + * + * This routine stops the receive function of the hardware. + */ +static void hw_stop_rx(struct ksz_hw *hw) +{ + hw->rx_stop = 0; + hw_turn_off_intr(hw, KS884X_INT_RX_STOPPED); + writel((hw->rx_cfg & ~DMA_RX_ENABLE), hw->io + KS_DMA_RX_CTRL); +} + +/** + * hw_start_tx - start transmitting + * @hw: The hardware instance. + * + * This routine starts the transmit function of the hardware. + */ +static void hw_start_tx(struct ksz_hw *hw) +{ + writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); +} + +/** + * hw_stop_tx - stop transmitting + * @hw: The hardware instance. + * + * This routine stops the transmit function of the hardware. + */ +static void hw_stop_tx(struct ksz_hw *hw) +{ + writel((hw->tx_cfg & ~DMA_TX_ENABLE), hw->io + KS_DMA_TX_CTRL); +} + +/** + * hw_disable - disable hardware + * @hw: The hardware instance. + * + * This routine disables the hardware. + */ +static void hw_disable(struct ksz_hw *hw) +{ + hw_stop_rx(hw); + hw_stop_tx(hw); + hw->enabled = 0; +} + +/** + * hw_enable - enable hardware + * @hw: The hardware instance. + * + * This routine enables the hardware. + */ +static void hw_enable(struct ksz_hw *hw) +{ + hw_start_tx(hw); + hw_start_rx(hw); + hw->enabled = 1; +} + +/** + * hw_alloc_pkt - allocate enough descriptors for transmission + * @hw: The hardware instance. + * @length: The length of the packet. + * @physical: Number of descriptors required. + * + * This function allocates descriptors for transmission. + * + * Return 0 if not successful; 1 for buffer copy; or number of descriptors. + */ +static int hw_alloc_pkt(struct ksz_hw *hw, int length, int physical) +{ + /* Always leave one descriptor free. */ + if (hw->tx_desc_info.avail <= 1) + return 0; + + /* Allocate a descriptor for transmission and mark it current. */ + get_tx_pkt(&hw->tx_desc_info, &hw->tx_desc_info.cur); + hw->tx_desc_info.cur->sw.buf.tx.first_seg = 1; + + /* Keep track of number of transmit descriptors used so far. */ + ++hw->tx_int_cnt; + hw->tx_size += length; + + /* Cannot hold on too much data. */ + if (hw->tx_size >= MAX_TX_HELD_SIZE) + hw->tx_int_cnt = hw->tx_int_mask + 1; + + if (physical > hw->tx_desc_info.avail) + return 1; + + return hw->tx_desc_info.avail; +} + +/** + * hw_send_pkt - mark packet for transmission + * @hw: The hardware instance. + * + * This routine marks the packet for transmission in PCI version. + */ +static void hw_send_pkt(struct ksz_hw *hw) +{ + struct ksz_desc *cur = hw->tx_desc_info.cur; + + cur->sw.buf.tx.last_seg = 1; + + /* Interrupt only after specified number of descriptors used. */ + if (hw->tx_int_cnt > hw->tx_int_mask) { + cur->sw.buf.tx.intr = 1; + hw->tx_int_cnt = 0; + hw->tx_size = 0; + } + + /* KSZ8842 supports port directed transmission. */ + cur->sw.buf.tx.dest_port = hw->dst_ports; + + release_desc(cur); + + writel(0, hw->io + KS_DMA_TX_START); +} + +static int empty_addr(u8 *addr) +{ + u32 *addr1 = (u32 *) addr; + u16 *addr2 = (u16 *) &addr[4]; + + return 0 == *addr1 && 0 == *addr2; +} + +/** + * hw_set_addr - set MAC address + * @hw: The hardware instance. + * + * This routine programs the MAC address of the hardware when the address is + * overrided. + */ +static void hw_set_addr(struct ksz_hw *hw) +{ + int i; + + for (i = 0; i < MAC_ADDR_LEN; i++) + writeb(hw->override_addr[MAC_ADDR_ORDER(i)], + hw->io + KS884X_ADDR_0_OFFSET + i); + + sw_set_addr(hw, hw->override_addr); +} + +/** + * hw_read_addr - read MAC address + * @hw: The hardware instance. + * + * This routine retrieves the MAC address of the hardware. + */ +static void hw_read_addr(struct ksz_hw *hw) +{ + int i; + + for (i = 0; i < MAC_ADDR_LEN; i++) + hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io + + KS884X_ADDR_0_OFFSET + i); + + if (!hw->mac_override) { + memcpy(hw->override_addr, hw->perm_addr, MAC_ADDR_LEN); + if (empty_addr(hw->override_addr)) { + memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS, + MAC_ADDR_LEN); + memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS, + MAC_ADDR_LEN); + hw->override_addr[5] += hw->id; + hw_set_addr(hw); + } + } +} + +static void hw_ena_add_addr(struct ksz_hw *hw, int index, u8 *mac_addr) +{ + int i; + u32 mac_addr_lo; + u32 mac_addr_hi; + + mac_addr_hi = 0; + for (i = 0; i < 2; i++) { + mac_addr_hi <<= 8; + mac_addr_hi |= mac_addr[i]; + } + mac_addr_hi |= ADD_ADDR_ENABLE; + mac_addr_lo = 0; + for (i = 2; i < 6; i++) { + mac_addr_lo <<= 8; + mac_addr_lo |= mac_addr[i]; + } + index *= ADD_ADDR_INCR; + + writel(mac_addr_lo, hw->io + index + KS_ADD_ADDR_0_LO); + writel(mac_addr_hi, hw->io + index + KS_ADD_ADDR_0_HI); +} + +static void hw_set_add_addr(struct ksz_hw *hw) +{ + int i; + + for (i = 0; i < ADDITIONAL_ENTRIES; i++) { + if (empty_addr(hw->address[i])) + writel(0, hw->io + ADD_ADDR_INCR * i + + KS_ADD_ADDR_0_HI); + else + hw_ena_add_addr(hw, i, hw->address[i]); + } +} + +static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr) +{ + int i; + int j = ADDITIONAL_ENTRIES; + + if (!memcmp(hw->override_addr, mac_addr, MAC_ADDR_LEN)) + return 0; + for (i = 0; i < hw->addr_list_size; i++) { + if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) + return 0; + if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i])) + j = i; + } + if (j < ADDITIONAL_ENTRIES) { + memcpy(hw->address[j], mac_addr, MAC_ADDR_LEN); + hw_ena_add_addr(hw, j, hw->address[j]); + return 0; + } + return -1; +} + +static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr) +{ + int i; + + for (i = 0; i < hw->addr_list_size; i++) { + if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) { + memset(hw->address[i], 0, MAC_ADDR_LEN); + writel(0, hw->io + ADD_ADDR_INCR * i + + KS_ADD_ADDR_0_HI); + return 0; + } + } + return -1; +} + +/** + * hw_clr_multicast - clear multicast addresses + * @hw: The hardware instance. + * + * This routine removes all multicast addresses set in the hardware. + */ +static void hw_clr_multicast(struct ksz_hw *hw) +{ + int i; + + for (i = 0; i < HW_MULTICAST_SIZE; i++) { + hw->multi_bits[i] = 0; + + writeb(0, hw->io + KS884X_MULTICAST_0_OFFSET + i); + } +} + +/** + * hw_set_grp_addr - set multicast addresses + * @hw: The hardware instance. + * + * This routine programs multicast addresses for the hardware to accept those + * addresses. + */ +static void hw_set_grp_addr(struct ksz_hw *hw) +{ + int i; + int index; + int position; + int value; + + memset(hw->multi_bits, 0, sizeof(u8) * HW_MULTICAST_SIZE); + + for (i = 0; i < hw->multi_list_size; i++) { + position = (ether_crc(6, hw->multi_list[i]) >> 26) & 0x3f; + index = position >> 3; + value = 1 << (position & 7); + hw->multi_bits[index] |= (u8) value; + } + + for (i = 0; i < HW_MULTICAST_SIZE; i++) + writeb(hw->multi_bits[i], hw->io + KS884X_MULTICAST_0_OFFSET + + i); +} + +/** + * hw_set_multicast - enable or disable all multicast receiving + * @hw: The hardware instance. + * @multicast: To turn on or off the all multicast feature. + * + * This routine enables/disables the hardware to accept all multicast packets. + */ +static void hw_set_multicast(struct ksz_hw *hw, u8 multicast) +{ + /* Stop receiving for reconfiguration. */ + hw_stop_rx(hw); + + if (multicast) + hw->rx_cfg |= DMA_RX_ALL_MULTICAST; + else + hw->rx_cfg &= ~DMA_RX_ALL_MULTICAST; + + if (hw->enabled) + hw_start_rx(hw); +} + +/** + * hw_set_promiscuous - enable or disable promiscuous receiving + * @hw: The hardware instance. + * @prom: To turn on or off the promiscuous feature. + * + * This routine enables/disables the hardware to accept all packets. + */ +static void hw_set_promiscuous(struct ksz_hw *hw, u8 prom) +{ + /* Stop receiving for reconfiguration. */ + hw_stop_rx(hw); + + if (prom) + hw->rx_cfg |= DMA_RX_PROMISCUOUS; + else + hw->rx_cfg &= ~DMA_RX_PROMISCUOUS; + + if (hw->enabled) + hw_start_rx(hw); +} + +/** + * sw_enable - enable the switch + * @hw: The hardware instance. + * @enable: The flag to enable or disable the switch + * + * This routine is used to enable/disable the switch in KSZ8842. + */ +static void sw_enable(struct ksz_hw *hw, int enable) +{ + int port; + + for (port = 0; port < SWITCH_PORT_NUM; port++) { + if (hw->dev_count > 1) { + /* Set port-base vlan membership with host port. */ + sw_cfg_port_base_vlan(hw, port, + HOST_MASK | (1 << port)); + port_set_stp_state(hw, port, STP_STATE_DISABLED); + } else { + sw_cfg_port_base_vlan(hw, port, PORT_MASK); + port_set_stp_state(hw, port, STP_STATE_FORWARDING); + } + } + if (hw->dev_count > 1) + port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE); + else + port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_FORWARDING); + + if (enable) + enable = KS8842_START; + writew(enable, hw->io + KS884X_CHIP_ID_OFFSET); +} + +/** + * sw_setup - setup the switch + * @hw: The hardware instance. + * + * This routine setup the hardware switch engine for default operation. + */ +static void sw_setup(struct ksz_hw *hw) +{ + int port; + + sw_set_global_ctrl(hw); + + /* Enable switch broadcast storm protection at 10% percent rate. */ + sw_init_broad_storm(hw); + hw_cfg_broad_storm(hw, BROADCAST_STORM_PROTECTION_RATE); + for (port = 0; port < SWITCH_PORT_NUM; port++) + sw_ena_broad_storm(hw, port); + + sw_init_prio(hw); + + sw_init_mirror(hw); + + sw_init_prio_rate(hw); + + sw_init_vlan(hw); + + if (hw->features & STP_SUPPORT) + sw_init_stp(hw); + if (!sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_TX_FLOW_CTRL | SWITCH_RX_FLOW_CTRL)) + hw->overrides |= PAUSE_FLOW_CTRL; + sw_enable(hw, 1); +} + +/** + * ksz_start_timer - start kernel timer + * @info: Kernel timer information. + * @time: The time tick. + * + * This routine starts the kernel timer after the specified time tick. + */ +static void ksz_start_timer(struct ksz_timer_info *info, int time) +{ + info->cnt = 0; + info->timer.expires = jiffies + time; + add_timer(&info->timer); + + /* infinity */ + info->max = -1; +} + +/** + * ksz_stop_timer - stop kernel timer + * @info: Kernel timer information. + * + * This routine stops the kernel timer. + */ +static void ksz_stop_timer(struct ksz_timer_info *info) +{ + if (info->max) { + info->max = 0; + del_timer_sync(&info->timer); + } +} + +static void ksz_init_timer(struct ksz_timer_info *info, int period, + void (*function)(unsigned long), void *data) +{ + info->max = 0; + info->period = period; + init_timer(&info->timer); + info->timer.function = function; + info->timer.data = (unsigned long) data; +} + +static void ksz_update_timer(struct ksz_timer_info *info) +{ + ++info->cnt; + if (info->max > 0) { + if (info->cnt < info->max) { + info->timer.expires = jiffies + info->period; + add_timer(&info->timer); + } else + info->max = 0; + } else if (info->max < 0) { + info->timer.expires = jiffies + info->period; + add_timer(&info->timer); + } +} + +/** + * ksz_alloc_soft_desc - allocate software descriptors + * @desc_info: Descriptor information structure. + * @transmit: Indication that descriptors are for transmit. + * + * This local function allocates software descriptors for manipulation in + * memory. + * + * Return 0 if successful. + */ +static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit) +{ + desc_info->ring = kmalloc(sizeof(struct ksz_desc) * desc_info->alloc, + GFP_KERNEL); + if (!desc_info->ring) + return 1; + memset((void *) desc_info->ring, 0, + sizeof(struct ksz_desc) * desc_info->alloc); + hw_init_desc(desc_info, transmit); + return 0; +} + +/** + * ksz_alloc_desc - allocate hardware descriptors + * @adapter: Adapter information structure. + * + * This local function allocates hardware descriptors for receiving and + * transmitting. + * + * Return 0 if successful. + */ +static int ksz_alloc_desc(struct dev_info *adapter) +{ + struct ksz_hw *hw = &adapter->hw; + int offset; + + /* Allocate memory for RX & TX descriptors. */ + adapter->desc_pool.alloc_size = + hw->rx_desc_info.size * hw->rx_desc_info.alloc + + hw->tx_desc_info.size * hw->tx_desc_info.alloc + + DESC_ALIGNMENT; + + adapter->desc_pool.alloc_virt = + pci_alloc_consistent( + adapter->pdev, adapter->desc_pool.alloc_size, + &adapter->desc_pool.dma_addr); + if (adapter->desc_pool.alloc_virt == NULL) { + adapter->desc_pool.alloc_size = 0; + return 1; + } + memset(adapter->desc_pool.alloc_virt, 0, adapter->desc_pool.alloc_size); + + /* Align to the next cache line boundary. */ + offset = (((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT) ? + (DESC_ALIGNMENT - + ((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT)) : 0); + adapter->desc_pool.virt = adapter->desc_pool.alloc_virt + offset; + adapter->desc_pool.phys = adapter->desc_pool.dma_addr + offset; + + /* Allocate receive/transmit descriptors. */ + hw->rx_desc_info.ring_virt = (struct ksz_hw_desc *) + adapter->desc_pool.virt; + hw->rx_desc_info.ring_phys = adapter->desc_pool.phys; + offset = hw->rx_desc_info.alloc * hw->rx_desc_info.size; + hw->tx_desc_info.ring_virt = (struct ksz_hw_desc *) + (adapter->desc_pool.virt + offset); + hw->tx_desc_info.ring_phys = adapter->desc_pool.phys + offset; + + if (ksz_alloc_soft_desc(&hw->rx_desc_info, 0)) + return 1; + if (ksz_alloc_soft_desc(&hw->tx_desc_info, 1)) + return 1; + + return 0; +} + +/** + * free_dma_buf - release DMA buffer resources + * @adapter: Adapter information structure. + * + * This routine is just a helper function to release the DMA buffer resources. + */ +static void free_dma_buf(struct dev_info *adapter, struct ksz_dma_buf *dma_buf, + int direction) +{ + pci_unmap_single(adapter->pdev, dma_buf->dma, dma_buf->len, direction); + dev_kfree_skb(dma_buf->skb); + dma_buf->skb = NULL; + dma_buf->dma = 0; +} + +/** + * ksz_init_rx_buffers - initialize receive descriptors + * @adapter: Adapter information structure. + * + * This routine initializes DMA buffers for receiving. + */ +static void ksz_init_rx_buffers(struct dev_info *adapter) +{ + int i; + struct ksz_desc *desc; + struct ksz_dma_buf *dma_buf; + struct ksz_hw *hw = &adapter->hw; + struct ksz_desc_info *info = &hw->rx_desc_info; + + for (i = 0; i < hw->rx_desc_info.alloc; i++) { + get_rx_pkt(info, &desc); + + dma_buf = DMA_BUFFER(desc); + if (dma_buf->skb && dma_buf->len != adapter->mtu) + free_dma_buf(adapter, dma_buf, PCI_DMA_FROMDEVICE); + dma_buf->len = adapter->mtu; + if (!dma_buf->skb) + dma_buf->skb = alloc_skb(dma_buf->len, GFP_ATOMIC); + if (dma_buf->skb && !dma_buf->dma) { + dma_buf->skb->dev = adapter->dev; + dma_buf->dma = pci_map_single( + adapter->pdev, + skb_tail_pointer(dma_buf->skb), + dma_buf->len, + PCI_DMA_FROMDEVICE); + } + + /* Set descriptor. */ + set_rx_buf(desc, dma_buf->dma); + set_rx_len(desc, dma_buf->len); + release_desc(desc); + } +} + +/** + * ksz_alloc_mem - allocate memory for hardware descriptors + * @adapter: Adapter information structure. + * + * This function allocates memory for use by hardware descriptors for receiving + * and transmitting. + * + * Return 0 if successful. + */ +static int ksz_alloc_mem(struct dev_info *adapter) +{ + struct ksz_hw *hw = &adapter->hw; + + /* Determine the number of receive and transmit descriptors. */ + hw->rx_desc_info.alloc = NUM_OF_RX_DESC; + hw->tx_desc_info.alloc = NUM_OF_TX_DESC; + + /* Determine how many descriptors to skip transmit interrupt. */ + hw->tx_int_cnt = 0; + hw->tx_int_mask = NUM_OF_TX_DESC / 4; + if (hw->tx_int_mask > 8) + hw->tx_int_mask = 8; + while (hw->tx_int_mask) { + hw->tx_int_cnt++; + hw->tx_int_mask >>= 1; + } + if (hw->tx_int_cnt) { + hw->tx_int_mask = (1 << (hw->tx_int_cnt - 1)) - 1; + hw->tx_int_cnt = 0; + } + + /* Determine the descriptor size. */ + hw->rx_desc_info.size = + (((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) / + DESC_ALIGNMENT) * DESC_ALIGNMENT); + hw->tx_desc_info.size = + (((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) / + DESC_ALIGNMENT) * DESC_ALIGNMENT); + if (hw->rx_desc_info.size != sizeof(struct ksz_hw_desc)) + printk(KERN_ALERT + "Hardware descriptor size not right!\n"); + ksz_check_desc_num(&hw->rx_desc_info); + ksz_check_desc_num(&hw->tx_desc_info); + + /* Allocate descriptors. */ + if (ksz_alloc_desc(adapter)) + return 1; + + return 0; +} + +/** + * ksz_free_desc - free software and hardware descriptors + * @adapter: Adapter information structure. + * + * This local routine frees the software and hardware descriptors allocated by + * ksz_alloc_desc(). + */ +static void ksz_free_desc(struct dev_info *adapter) +{ + struct ksz_hw *hw = &adapter->hw; + + /* Reset descriptor. */ + hw->rx_desc_info.ring_virt = NULL; + hw->tx_desc_info.ring_virt = NULL; + hw->rx_desc_info.ring_phys = 0; + hw->tx_desc_info.ring_phys = 0; + + /* Free memory. */ + if (adapter->desc_pool.alloc_virt) + pci_free_consistent( + adapter->pdev, + adapter->desc_pool.alloc_size, + adapter->desc_pool.alloc_virt, + adapter->desc_pool.dma_addr); + + /* Reset resource pool. */ + adapter->desc_pool.alloc_size = 0; + adapter->desc_pool.alloc_virt = NULL; + + kfree(hw->rx_desc_info.ring); + hw->rx_desc_info.ring = NULL; + kfree(hw->tx_desc_info.ring); + hw->tx_desc_info.ring = NULL; +} + +/** + * ksz_free_buffers - free buffers used in the descriptors + * @adapter: Adapter information structure. + * @desc_info: Descriptor information structure. + * + * This local routine frees buffers used in the DMA buffers. + */ +static void ksz_free_buffers(struct dev_info *adapter, + struct ksz_desc_info *desc_info, int direction) +{ + int i; + struct ksz_dma_buf *dma_buf; + struct ksz_desc *desc = desc_info->ring; + + for (i = 0; i < desc_info->alloc; i++) { + dma_buf = DMA_BUFFER(desc); + if (dma_buf->skb) + free_dma_buf(adapter, dma_buf, direction); + desc++; + } +} + +/** + * ksz_free_mem - free all resources used by descriptors + * @adapter: Adapter information structure. + * + * This local routine frees all the resources allocated by ksz_alloc_mem(). + */ +static void ksz_free_mem(struct dev_info *adapter) +{ + /* Free transmit buffers. */ + ksz_free_buffers(adapter, &adapter->hw.tx_desc_info, + PCI_DMA_TODEVICE); + + /* Free receive buffers. */ + ksz_free_buffers(adapter, &adapter->hw.rx_desc_info, + PCI_DMA_FROMDEVICE); + + /* Free descriptors. */ + ksz_free_desc(adapter); +} + +static void get_mib_counters(struct ksz_hw *hw, int first, int cnt, + u64 *counter) +{ + int i; + int mib; + int port; + struct ksz_port_mib *port_mib; + + memset(counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM); + for (i = 0, port = first; i < cnt; i++, port++) { + port_mib = &hw->port_mib[port]; + for (mib = port_mib->mib_start; mib < hw->mib_cnt; mib++) + counter[mib] += port_mib->counter[mib]; + } +} + +/** + * send_packet - send packet + * @skb: Socket buffer. + * @dev: Network device. + * + * This routine is used to send a packet out to the network. + */ +static void send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct ksz_desc *desc; + struct ksz_desc *first; + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_desc_info *info = &hw->tx_desc_info; + struct ksz_dma_buf *dma_buf; + int len; + int last_frag = skb_shinfo(skb)->nr_frags; + + /* + * KSZ8842 with multiple device interfaces needs to be told which port + * to send. + */ + if (hw->dev_count > 1) + hw->dst_ports = 1 << priv->port.first_port; + + /* Hardware will pad the length to 60. */ + len = skb->len; + + /* Remember the very first descriptor. */ + first = info->cur; + desc = first; + + dma_buf = DMA_BUFFER(desc); + if (last_frag) { + int frag; + skb_frag_t *this_frag; + + dma_buf->len = skb->len - skb->data_len; + + dma_buf->dma = pci_map_single( + hw_priv->pdev, skb->data, dma_buf->len, + PCI_DMA_TODEVICE); + set_tx_buf(desc, dma_buf->dma); + set_tx_len(desc, dma_buf->len); + + frag = 0; + do { + this_frag = &skb_shinfo(skb)->frags[frag]; + + /* Get a new descriptor. */ + get_tx_pkt(info, &desc); + + /* Keep track of descriptors used so far. */ + ++hw->tx_int_cnt; + + dma_buf = DMA_BUFFER(desc); + dma_buf->len = this_frag->size; + + dma_buf->dma = pci_map_single( + hw_priv->pdev, + page_address(this_frag->page) + + this_frag->page_offset, + dma_buf->len, + PCI_DMA_TODEVICE); + set_tx_buf(desc, dma_buf->dma); + set_tx_len(desc, dma_buf->len); + + frag++; + if (frag == last_frag) + break; + + /* Do not release the last descriptor here. */ + release_desc(desc); + } while (1); + + /* current points to the last descriptor. */ + info->cur = desc; + + /* Release the first descriptor. */ + release_desc(first); + } else { + dma_buf->len = len; + + dma_buf->dma = pci_map_single( + hw_priv->pdev, skb->data, dma_buf->len, + PCI_DMA_TODEVICE); + set_tx_buf(desc, dma_buf->dma); + set_tx_len(desc, dma_buf->len); + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + (desc)->sw.buf.tx.csum_gen_tcp = 1; + (desc)->sw.buf.tx.csum_gen_udp = 1; + } + + /* + * The last descriptor holds the packet so that it can be returned to + * network subsystem after all descriptors are transmitted. + */ + dma_buf->skb = skb; + + hw_send_pkt(hw); + + /* Update transmit statistics. */ + priv->stats.tx_packets++; + priv->stats.tx_bytes += len; +} + +/** + * transmit_cleanup - clean up transmit descriptors + * @dev: Network device. + * + * This routine is called to clean up the transmitted buffers. + */ +static void transmit_cleanup(struct dev_info *hw_priv, int normal) +{ + int last; + union desc_stat status; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_desc_info *info = &hw->tx_desc_info; + struct ksz_desc *desc; + struct ksz_dma_buf *dma_buf; + struct net_device *dev = NULL; + + spin_lock(&hw_priv->hwlock); + last = info->last; + + while (info->avail < info->alloc) { + /* Get next descriptor which is not hardware owned. */ + desc = &info->ring[last]; + status.data = le32_to_cpu(desc->phw->ctrl.data); + if (status.tx.hw_owned) { + if (normal) + break; + else + reset_desc(desc, status); + } + + dma_buf = DMA_BUFFER(desc); + pci_unmap_single( + hw_priv->pdev, dma_buf->dma, dma_buf->len, + PCI_DMA_TODEVICE); + + /* This descriptor contains the last buffer in the packet. */ + if (dma_buf->skb) { + dev = dma_buf->skb->dev; + + /* Release the packet back to network subsystem. */ + dev_kfree_skb_irq(dma_buf->skb); + dma_buf->skb = NULL; + } + + /* Free the transmitted descriptor. */ + last++; + last &= info->mask; + info->avail++; + } + info->last = last; + spin_unlock(&hw_priv->hwlock); + + /* Notify the network subsystem that the packet has been sent. */ + if (dev) + dev->trans_start = jiffies; +} + +/** + * transmit_done - transmit done processing + * @dev: Network device. + * + * This routine is called when the transmit interrupt is triggered, indicating + * either a packet is sent successfully or there are transmit errors. + */ +static void tx_done(struct dev_info *hw_priv) +{ + struct ksz_hw *hw = &hw_priv->hw; + int port; + + transmit_cleanup(hw_priv, 1); + + for (port = 0; port < hw->dev_count; port++) { + struct net_device *dev = hw->port_info[port].pdev; + + if (netif_running(dev) && netif_queue_stopped(dev)) + netif_wake_queue(dev); + } +} + +static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb) +{ + skb->dev = old->dev; + skb->protocol = old->protocol; + skb->ip_summed = old->ip_summed; + skb->csum = old->csum; + skb_set_network_header(skb, ETH_HLEN); + + dev_kfree_skb(old); +} + +/** + * netdev_tx - send out packet + * @skb: Socket buffer. + * @dev: Network device. + * + * This function is used by the upper network layer to send out a packet. + * + * Return 0 if successful; otherwise an error code indicating failure. + */ +static int netdev_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + int left; + int num = 1; + int rc = 0; + + if (hw->features & SMALL_PACKET_TX_BUG) { + struct sk_buff *org_skb = skb; + + if (skb->len <= 48) { + if (skb_end_pointer(skb) - skb->data >= 50) { + memset(&skb->data[skb->len], 0, 50 - skb->len); + skb->len = 50; + } else { + skb = dev_alloc_skb(50); + if (!skb) + return NETDEV_TX_BUSY; + memcpy(skb->data, org_skb->data, org_skb->len); + memset(&skb->data[org_skb->len], 0, + 50 - org_skb->len); + skb->len = 50; + copy_old_skb(org_skb, skb); + } + } + } + + spin_lock_irq(&hw_priv->hwlock); + + num = skb_shinfo(skb)->nr_frags + 1; + left = hw_alloc_pkt(hw, skb->len, num); + if (left) { + if (left < num || + ((hw->features & IPV6_CSUM_GEN_HACK) && + (CHECKSUM_PARTIAL == skb->ip_summed) && + (ETH_P_IPV6 == htons(skb->protocol)))) { + struct sk_buff *org_skb = skb; + + skb = dev_alloc_skb(org_skb->len); + if (!skb) + return NETDEV_TX_BUSY; + skb_copy_and_csum_dev(org_skb, skb->data); + org_skb->ip_summed = 0; + skb->len = org_skb->len; + copy_old_skb(org_skb, skb); + } + send_packet(skb, dev); + if (left <= num) + netif_stop_queue(dev); + } else { + /* Stop the transmit queue until packet is allocated. */ + netif_stop_queue(dev); + rc = NETDEV_TX_BUSY; + } + + spin_unlock_irq(&hw_priv->hwlock); + + return rc; +} + +/** + * netdev_tx_timeout - transmit timeout processing + * @dev: Network device. + * + * This routine is called when the transmit timer expires. That indicates the + * hardware is not running correctly because transmit interrupts are not + * triggered to free up resources so that the transmit routine can continue + * sending out packets. The hardware is reset to correct the problem. + */ +static void netdev_tx_timeout(struct net_device *dev) +{ + static unsigned long last_reset; + + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + int port; + + if (hw->dev_count > 1) { + /* + * Only reset the hardware if time between calls is long + * enough. + */ + if (jiffies - last_reset <= dev->watchdog_timeo) + hw_priv = NULL; + } + + last_reset = jiffies; + if (hw_priv) { + hw_dis_intr(hw); + hw_disable(hw); + + transmit_cleanup(hw_priv, 0); + hw_reset_pkts(&hw->rx_desc_info); + hw_reset_pkts(&hw->tx_desc_info); + ksz_init_rx_buffers(hw_priv); + + hw_reset(hw); + + hw_set_desc_base(hw, + hw->tx_desc_info.ring_phys, + hw->rx_desc_info.ring_phys); + hw_set_addr(hw); + if (hw->all_multi) + hw_set_multicast(hw, hw->all_multi); + else if (hw->multi_list_size) + hw_set_grp_addr(hw); + + if (hw->dev_count > 1) { + hw_set_add_addr(hw); + for (port = 0; port < SWITCH_PORT_NUM; port++) { + struct net_device *port_dev; + + port_set_stp_state(hw, port, + STP_STATE_DISABLED); + + port_dev = hw->port_info[port].pdev; + if (netif_running(port_dev)) + port_set_stp_state(hw, port, + STP_STATE_SIMPLE); + } + } + + hw_enable(hw); + hw_ena_intr(hw); + } + + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static inline void csum_verified(struct sk_buff *skb) +{ + unsigned short protocol; + struct iphdr *iph; + + protocol = skb->protocol; + skb_reset_network_header(skb); + iph = (struct iphdr *) skb_network_header(skb); + if (protocol == htons(ETH_P_8021Q)) { + protocol = iph->tot_len; + skb_set_network_header(skb, VLAN_HLEN); + iph = (struct iphdr *) skb_network_header(skb); + } + if (protocol == htons(ETH_P_IP)) { + if (iph->protocol == IPPROTO_TCP) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +} + +static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw, + struct ksz_desc *desc, union desc_stat status) +{ + int packet_len; + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_dma_buf *dma_buf; + struct sk_buff *skb; + int rx_status; + + /* Received length includes 4-byte CRC. */ + packet_len = status.rx.frame_len - 4; + + dma_buf = DMA_BUFFER(desc); + pci_dma_sync_single_for_cpu( + hw_priv->pdev, dma_buf->dma, packet_len + 4, + PCI_DMA_FROMDEVICE); + + do { + /* skb->data != skb->head */ + skb = dev_alloc_skb(packet_len + 2); + if (!skb) { + priv->stats.rx_dropped++; + return -ENOMEM; + } + + /* + * Align socket buffer in 4-byte boundary for better + * performance. + */ + skb_reserve(skb, 2); + + memcpy(skb_put(skb, packet_len), + dma_buf->skb->data, packet_len); + } while (0); + + skb->dev = dev; + + skb->protocol = eth_type_trans(skb, dev); + + if (hw->rx_cfg & (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP)) + csum_verified(skb); + + /* Update receive statistics. */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += packet_len; + + /* Notify upper layer for received packet. */ + dev->last_rx = jiffies; + + rx_status = netif_rx(skb); + + return 0; +} + +static int dev_rcv_packets(struct dev_info *hw_priv) +{ + int next; + union desc_stat status; + struct ksz_hw *hw = &hw_priv->hw; + struct net_device *dev = hw->port_info[0].pdev; + struct ksz_desc_info *info = &hw->rx_desc_info; + int left = info->alloc; + struct ksz_desc *desc; + int received = 0; + + next = info->next; + while (left--) { + /* Get next descriptor which is not hardware owned. */ + desc = &info->ring[next]; + status.data = le32_to_cpu(desc->phw->ctrl.data); + if (status.rx.hw_owned) + break; + + /* Status valid only when last descriptor bit is set. */ + if (status.rx.last_desc && status.rx.first_desc) { + if (rx_proc(dev, hw, desc, status)) + goto release_packet; + received++; + } + +release_packet: + release_desc(desc); + next++; + next &= info->mask; + } + info->next = next; + + return received; +} + +static int port_rcv_packets(struct dev_info *hw_priv) +{ + int next; + union desc_stat status; + struct ksz_hw *hw = &hw_priv->hw; + struct net_device *dev = hw->port_info[0].pdev; + struct ksz_desc_info *info = &hw->rx_desc_info; + int left = info->alloc; + struct ksz_desc *desc; + int received = 0; + + next = info->next; + while (left--) { + /* Get next descriptor which is not hardware owned. */ + desc = &info->ring[next]; + status.data = le32_to_cpu(desc->phw->ctrl.data); + if (status.rx.hw_owned) + break; + + if (hw->dev_count > 1) { + /* Get received port number. */ + int p = HW_TO_DEV_PORT(status.rx.src_port); + + dev = hw->port_info[p].pdev; + if (!netif_running(dev)) + goto release_packet; + } + + /* Status valid only when last descriptor bit is set. */ + if (status.rx.last_desc && status.rx.first_desc) { + if (rx_proc(dev, hw, desc, status)) + goto release_packet; + received++; + } + +release_packet: + release_desc(desc); + next++; + next &= info->mask; + } + info->next = next; + + return received; +} + +static int dev_rcv_special(struct dev_info *hw_priv) +{ + int next; + union desc_stat status; + struct ksz_hw *hw = &hw_priv->hw; + struct net_device *dev = hw->port_info[0].pdev; + struct ksz_desc_info *info = &hw->rx_desc_info; + int left = info->alloc; + struct ksz_desc *desc; + int received = 0; + + next = info->next; + while (left--) { + /* Get next descriptor which is not hardware owned. */ + desc = &info->ring[next]; + status.data = le32_to_cpu(desc->phw->ctrl.data); + if (status.rx.hw_owned) + break; + + if (hw->dev_count > 1) { + /* Get received port number. */ + int p = HW_TO_DEV_PORT(status.rx.src_port); + + dev = hw->port_info[p].pdev; + if (!netif_running(dev)) + goto release_packet; + } + + /* Status valid only when last descriptor bit is set. */ + if (status.rx.last_desc && status.rx.first_desc) { + /* + * Receive without error. With receive errors + * disabled, packets with receive errors will be + * dropped, so no need to check the error bit. + */ + if (!status.rx.error || (status.data & + KS_DESC_RX_ERROR_COND) == + KS_DESC_RX_ERROR_TOO_LONG) { + if (rx_proc(dev, hw, desc, status)) + goto release_packet; + received++; + } else { + struct dev_priv *priv = netdev_priv(dev); + + /* Update receive error statistics. */ + priv->port.counter[OID_COUNTER_RCV_ERROR]++; + } + } + +release_packet: + release_desc(desc); + next++; + next &= info->mask; + } + info->next = next; + + return received; +} + +static void rx_proc_task(unsigned long data) +{ + struct dev_info *hw_priv = (struct dev_info *) data; + struct ksz_hw *hw = &hw_priv->hw; + + if (!hw->enabled) + return; + if (unlikely(!hw_priv->dev_rcv(hw_priv))) { + + /* In case receive process is suspended because of overrun. */ + hw_resume_rx(hw); + + /* tasklets are interruptible. */ + spin_lock_irq(&hw_priv->hwlock); + hw_turn_on_intr(hw, KS884X_INT_RX_MASK); + spin_unlock_irq(&hw_priv->hwlock); + } else { + hw_ack_intr(hw, KS884X_INT_RX); + tasklet_schedule(&hw_priv->rx_tasklet); + } +} + +static void tx_proc_task(unsigned long data) +{ + struct dev_info *hw_priv = (struct dev_info *) data; + struct ksz_hw *hw = &hw_priv->hw; + + hw_ack_intr(hw, KS884X_INT_TX_MASK); + + tx_done(hw_priv); + + /* tasklets are interruptible. */ + spin_lock_irq(&hw_priv->hwlock); + hw_turn_on_intr(hw, KS884X_INT_TX); + spin_unlock_irq(&hw_priv->hwlock); +} + +static inline void handle_rx_stop(struct ksz_hw *hw) +{ + /* Receive just has been stopped. */ + if (0 == hw->rx_stop) + hw->intr_mask &= ~KS884X_INT_RX_STOPPED; + else if (hw->rx_stop > 1) { + if (hw->enabled && (hw->rx_cfg & DMA_RX_ENABLE)) { + hw_start_rx(hw); + } else { + hw->intr_mask &= ~KS884X_INT_RX_STOPPED; + hw->rx_stop = 0; + } + } else + /* Receive just has been started. */ + hw->rx_stop++; +} + +/** + * netdev_intr - interrupt handling + * @irq: Interrupt number. + * @dev_id: Network device. + * + * This function is called by upper network layer to signal interrupt. + * + * Return IRQ_HANDLED if interrupt is handled. + */ +static irqreturn_t netdev_intr(int irq, void *dev_id) +{ + uint int_enable = 0; + struct net_device *dev = (struct net_device *) dev_id; + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + hw_read_intr(hw, &int_enable); + + /* Not our interrupt! */ + if (!int_enable) + return IRQ_NONE; + + do { + hw_ack_intr(hw, int_enable); + int_enable &= hw->intr_mask; + + if (unlikely(int_enable & KS884X_INT_TX_MASK)) { + hw_dis_intr_bit(hw, KS884X_INT_TX_MASK); + tasklet_schedule(&hw_priv->tx_tasklet); + } + + if (likely(int_enable & KS884X_INT_RX)) { + hw_dis_intr_bit(hw, KS884X_INT_RX); + tasklet_schedule(&hw_priv->rx_tasklet); + } + + if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) { + priv->stats.rx_fifo_errors++; + hw_resume_rx(hw); + } + + if (unlikely(int_enable & KS884X_INT_PHY)) { + struct ksz_port *port = &priv->port; + + hw->features |= LINK_INT_WORKING; + port_get_link_speed(port); + } + + if (unlikely(int_enable & KS884X_INT_RX_STOPPED)) { + handle_rx_stop(hw); + break; + } + + if (unlikely(int_enable & KS884X_INT_TX_STOPPED)) { + u32 data; + + hw->intr_mask &= ~KS884X_INT_TX_STOPPED; + printk(KERN_INFO "Tx stopped\n"); + data = readl(hw->io + KS_DMA_TX_CTRL); + if (!(data & DMA_TX_ENABLE)) + printk(KERN_INFO "Tx disabled\n"); + break; + } + } while (0); + + hw_ena_intr(hw); + + return IRQ_HANDLED; +} + +/* + * Linux network device functions + */ + +static unsigned long next_jiffies; + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void netdev_netpoll(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + + hw_dis_intr(&hw_priv->hw); + netdev_intr(dev->irq, dev); +} +#endif + +static void bridge_change(struct ksz_hw *hw) +{ + int port; + u8 member; + struct ksz_switch *sw = hw->ksz_switch; + + /* No ports in forwarding state. */ + if (!sw->member) { + port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE); + sw_block_addr(hw); + } + for (port = 0; port < SWITCH_PORT_NUM; port++) { + if (STP_STATE_FORWARDING == sw->port_cfg[port].stp_state) + member = HOST_MASK | sw->member; + else + member = HOST_MASK | (1 << port); + if (member != sw->port_cfg[port].member) + sw_cfg_port_base_vlan(hw, port, member); + } +} + +/** + * netdev_close - close network device + * @dev: Network device. + * + * This function process the close operation of network device. This is caused + * by the user command "ifconfig ethX down." + * + * Return 0 if successful; otherwise an error code indicating failure. + */ +static int netdev_close(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_port *port = &priv->port; + struct ksz_hw *hw = &hw_priv->hw; + int pi; + + netif_stop_queue(dev); + + ksz_stop_timer(&priv->monitor_timer_info); + + /* Need to shut the port manually in multiple device interfaces mode. */ + if (hw->dev_count > 1) { + port_set_stp_state(hw, port->first_port, STP_STATE_DISABLED); + + /* Port is closed. Need to change bridge setting. */ + if (hw->features & STP_SUPPORT) { + pi = 1 << port->first_port; + if (hw->ksz_switch->member & pi) { + hw->ksz_switch->member &= ~pi; + bridge_change(hw); + } + } + } + if (port->first_port > 0) + hw_del_addr(hw, dev->dev_addr); + if (!hw_priv->wol_enable) + port_set_power_saving(port, true); + + if (priv->multicast) + --hw->all_multi; + if (priv->promiscuous) + --hw->promiscuous; + + hw_priv->opened--; + if (!(hw_priv->opened)) { + ksz_stop_timer(&hw_priv->mib_timer_info); + flush_work(&hw_priv->mib_read); + + hw_dis_intr(hw); + hw_disable(hw); + hw_clr_multicast(hw); + + /* Delay for receive task to stop scheduling itself. */ + msleep(2000 / HZ); + + tasklet_disable(&hw_priv->rx_tasklet); + tasklet_disable(&hw_priv->tx_tasklet); + free_irq(dev->irq, hw_priv->dev); + + transmit_cleanup(hw_priv, 0); + hw_reset_pkts(&hw->rx_desc_info); + hw_reset_pkts(&hw->tx_desc_info); + + /* Clean out static MAC table when the switch is shutdown. */ + if (hw->features & STP_SUPPORT) + sw_clr_sta_mac_table(hw); + } + + return 0; +} + +static void hw_cfg_huge_frame(struct dev_info *hw_priv, struct ksz_hw *hw) +{ + if (hw->ksz_switch) { + u32 data; + + data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET); + if (hw->features & RX_HUGE_FRAME) + data |= SWITCH_HUGE_PACKET; + else + data &= ~SWITCH_HUGE_PACKET; + writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET); + } + if (hw->features & RX_HUGE_FRAME) { + hw->rx_cfg |= DMA_RX_ERROR; + hw_priv->dev_rcv = dev_rcv_special; + } else { + hw->rx_cfg &= ~DMA_RX_ERROR; + if (hw->dev_count > 1) + hw_priv->dev_rcv = port_rcv_packets; + else + hw_priv->dev_rcv = dev_rcv_packets; + } +} + +static int prepare_hardware(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + int rc = 0; + + /* Remember the network device that requests interrupts. */ + hw_priv->dev = dev; + rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev); + if (rc) + return rc; + tasklet_enable(&hw_priv->rx_tasklet); + tasklet_enable(&hw_priv->tx_tasklet); + + hw->promiscuous = 0; + hw->all_multi = 0; + hw->multi_list_size = 0; + + hw_reset(hw); + + hw_set_desc_base(hw, + hw->tx_desc_info.ring_phys, hw->rx_desc_info.ring_phys); + hw_set_addr(hw); + hw_cfg_huge_frame(hw_priv, hw); + ksz_init_rx_buffers(hw_priv); + return 0; +} + +/** + * netdev_open - open network device + * @dev: Network device. + * + * This function process the open operation of network device. This is caused + * by the user command "ifconfig ethX up." + * + * Return 0 if successful; otherwise an error code indicating failure. + */ +static int netdev_open(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port *port = &priv->port; + int i; + int p; + int rc = 0; + + priv->multicast = 0; + priv->promiscuous = 0; + + /* Reset device statistics. */ + memset(&priv->stats, 0, sizeof(struct net_device_stats)); + memset((void *) port->counter, 0, + (sizeof(u64) * OID_COUNTER_LAST)); + + if (!(hw_priv->opened)) { + rc = prepare_hardware(dev); + if (rc) + return rc; + for (i = 0; i < hw->mib_port_cnt; i++) { + if (next_jiffies < jiffies) + next_jiffies = jiffies + HZ * 2; + else + next_jiffies += HZ * 1; + hw_priv->counter[i].time = next_jiffies; + hw->port_mib[i].state = media_disconnected; + port_init_cnt(hw, i); + } + if (hw->ksz_switch) + hw->port_mib[HOST_PORT].state = media_connected; + else { + hw_add_wol_bcast(hw); + hw_cfg_wol_pme(hw, 0); + hw_clr_wol_pme_status(&hw_priv->hw); + } + } + port_set_power_saving(port, false); + + for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { + /* + * Initialize to invalid value so that link detection + * is done. + */ + hw->port_info[p].partner = 0xFF; + hw->port_info[p].state = media_disconnected; + } + + /* Need to open the port in multiple device interfaces mode. */ + if (hw->dev_count > 1) { + port_set_stp_state(hw, port->first_port, STP_STATE_SIMPLE); + if (port->first_port > 0) + hw_add_addr(hw, dev->dev_addr); + } + + port_get_link_speed(port); + if (port->force_link) + port_force_link_speed(port); + else + port_set_link_speed(port); + + if (!(hw_priv->opened)) { + hw_setup_intr(hw); + hw_enable(hw); + hw_ena_intr(hw); + + if (hw->mib_port_cnt) + ksz_start_timer(&hw_priv->mib_timer_info, + hw_priv->mib_timer_info.period); + } + + hw_priv->opened++; + + ksz_start_timer(&priv->monitor_timer_info, + priv->monitor_timer_info.period); + + priv->media_state = port->linked->state; + + if (media_connected == priv->media_state) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + if (netif_msg_link(priv)) + printk(KERN_INFO "%s link %s\n", dev->name, + (media_connected == priv->media_state ? + "on" : "off")); + + netif_start_queue(dev); + + return 0; +} + +/* RX errors = rx_errors */ +/* RX dropped = rx_dropped */ +/* RX overruns = rx_fifo_errors */ +/* RX frame = rx_crc_errors + rx_frame_errors + rx_length_errors */ +/* TX errors = tx_errors */ +/* TX dropped = tx_dropped */ +/* TX overruns = tx_fifo_errors */ +/* TX carrier = tx_aborted_errors + tx_carrier_errors + tx_window_errors */ +/* collisions = collisions */ + +/** + * netdev_query_statistics - query network device statistics + * @dev: Network device. + * + * This function returns the statistics of the network device. The device + * needs not be opened. + * + * Return network device statistics. + */ +static struct net_device_stats *netdev_query_statistics(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct ksz_port *port = &priv->port; + struct ksz_hw *hw = &priv->adapter->hw; + struct ksz_port_mib *mib; + int i; + int p; + + priv->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR]; + priv->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR]; + + /* Reset to zero to add count later. */ + priv->stats.multicast = 0; + priv->stats.collisions = 0; + priv->stats.rx_length_errors = 0; + priv->stats.rx_crc_errors = 0; + priv->stats.rx_frame_errors = 0; + priv->stats.tx_window_errors = 0; + + for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) { + mib = &hw->port_mib[p]; + + priv->stats.multicast += (unsigned long) + mib->counter[MIB_COUNTER_RX_MULTICAST]; + + priv->stats.collisions += (unsigned long) + mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION]; + + priv->stats.rx_length_errors += (unsigned long)( + mib->counter[MIB_COUNTER_RX_UNDERSIZE] + + mib->counter[MIB_COUNTER_RX_FRAGMENT] + + mib->counter[MIB_COUNTER_RX_OVERSIZE] + + mib->counter[MIB_COUNTER_RX_JABBER]); + priv->stats.rx_crc_errors += (unsigned long) + mib->counter[MIB_COUNTER_RX_CRC_ERR]; + priv->stats.rx_frame_errors += (unsigned long)( + mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] + + mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]); + + priv->stats.tx_window_errors += (unsigned long) + mib->counter[MIB_COUNTER_TX_LATE_COLLISION]; + } + + return &priv->stats; +} + +/** + * netdev_set_mac_address - set network device MAC address + * @dev: Network device. + * @addr: Buffer of MAC address. + * + * This function is used to set the MAC address of the network device. + * + * Return 0 to indicate success. + */ +static int netdev_set_mac_address(struct net_device *dev, void *addr) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct sockaddr *mac = addr; + uint interrupt; + + if (priv->port.first_port > 0) + hw_del_addr(hw, dev->dev_addr); + else { + hw->mac_override = 1; + memcpy(hw->override_addr, mac->sa_data, MAC_ADDR_LEN); + } + + memcpy(dev->dev_addr, mac->sa_data, MAX_ADDR_LEN); + + interrupt = hw_block_intr(hw); + + if (priv->port.first_port > 0) + hw_add_addr(hw, dev->dev_addr); + else + hw_set_addr(hw); + hw_restore_intr(hw, interrupt); + + return 0; +} + +static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv, + struct ksz_hw *hw, int promiscuous) +{ + if (promiscuous != priv->promiscuous) { + u8 prev_state = hw->promiscuous; + + if (promiscuous) + ++hw->promiscuous; + else + --hw->promiscuous; + priv->promiscuous = promiscuous; + + /* Turn on/off promiscuous mode. */ + if (hw->promiscuous <= 1 && prev_state <= 1) + hw_set_promiscuous(hw, hw->promiscuous); + + /* + * Port is not in promiscuous mode, meaning it is released + * from the bridge. + */ + if ((hw->features & STP_SUPPORT) && !promiscuous && + dev->br_port) { + struct ksz_switch *sw = hw->ksz_switch; + int port = priv->port.first_port; + + port_set_stp_state(hw, port, STP_STATE_DISABLED); + port = 1 << port; + if (sw->member & port) { + sw->member &= ~port; + bridge_change(hw); + } + } + } +} + +static void dev_set_multicast(struct dev_priv *priv, struct ksz_hw *hw, + int multicast) +{ + if (multicast != priv->multicast) { + u8 all_multi = hw->all_multi; + + if (multicast) + ++hw->all_multi; + else + --hw->all_multi; + priv->multicast = multicast; + + /* Turn on/off all multicast mode. */ + if (hw->all_multi <= 1 && all_multi <= 1) + hw_set_multicast(hw, hw->all_multi); + } +} + +/** + * netdev_set_rx_mode + * @dev: Network device. + * + * This routine is used to set multicast addresses or put the network device + * into promiscuous mode. + */ +static void netdev_set_rx_mode(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct dev_mc_list *mc_ptr; + int multicast = (dev->flags & IFF_ALLMULTI); + + dev_set_promiscuous(dev, priv, hw, (dev->flags & IFF_PROMISC)); + + if (hw_priv->hw.dev_count > 1) + multicast |= (dev->flags & IFF_MULTICAST); + dev_set_multicast(priv, hw, multicast); + + /* Cannot use different hashes in multiple device interfaces mode. */ + if (hw_priv->hw.dev_count > 1) + return; + + if ((dev->flags & IFF_MULTICAST) && dev->mc_count) { + int i = 0; + + /* List too big to support so turn on all multicast mode. */ + if (dev->mc_count > MAX_MULTICAST_LIST) { + if (MAX_MULTICAST_LIST != hw->multi_list_size) { + hw->multi_list_size = MAX_MULTICAST_LIST; + ++hw->all_multi; + hw_set_multicast(hw, hw->all_multi); + } + return; + } + + for (mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + if (!(*mc_ptr->dmi_addr & 1)) + continue; + if (i >= MAX_MULTICAST_LIST) + break; + memcpy(hw->multi_list[i++], mc_ptr->dmi_addr, + MAC_ADDR_LEN); + } + hw->multi_list_size = (u8) i; + hw_set_grp_addr(hw); + } else { + if (MAX_MULTICAST_LIST == hw->multi_list_size) { + --hw->all_multi; + hw_set_multicast(hw, hw->all_multi); + } + hw->multi_list_size = 0; + hw_clr_multicast(hw); + } +} + +static int netdev_change_mtu(struct net_device *dev, int new_mtu) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + int hw_mtu; + + if (netif_running(dev)) + return -EBUSY; + + /* Cannot use different MTU in multiple device interfaces mode. */ + if (hw->dev_count > 1) + if (dev != hw_priv->dev) + return 0; + if (new_mtu < 60) + return -EINVAL; + + if (dev->mtu != new_mtu) { + hw_mtu = new_mtu + ETHERNET_HEADER_SIZE + 4; + if (hw_mtu > MAX_RX_BUF_SIZE) + return -EINVAL; + if (hw_mtu > REGULAR_RX_BUF_SIZE) { + hw->features |= RX_HUGE_FRAME; + hw_mtu = MAX_RX_BUF_SIZE; + } else { + hw->features &= ~RX_HUGE_FRAME; + hw_mtu = REGULAR_RX_BUF_SIZE; + } + hw_mtu = (hw_mtu + 3) & ~3; + hw_priv->mtu = hw_mtu; + dev->mtu = new_mtu; + } + return 0; +} + +/** + * netdev_ioctl - I/O control processing + * @dev: Network device. + * @ifr: Interface request structure. + * @cmd: I/O control code. + * + * This function is used to process I/O control calls. + * + * Return 0 to indicate success. + */ +static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port *port = &priv->port; + int rc; + int result = 0; + struct mii_ioctl_data *data = if_mii(ifr); + + if (down_interruptible(&priv->proc_sem)) + return -ERESTARTSYS; + + /* assume success */ + rc = 0; + switch (cmd) { + /* Get address of MII PHY in use. */ + case SIOCGMIIPHY: + data->phy_id = priv->id; + + /* Fallthrough... */ + + /* Read MII PHY register. */ + case SIOCGMIIREG: + if (data->phy_id != priv->id || data->reg_num >= 6) + result = -EIO; + else + hw_r_phy(hw, port->linked->port_id, data->reg_num, + &data->val_out); + break; + + /* Write MII PHY register. */ + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + result = -EPERM; + else if (data->phy_id != priv->id || data->reg_num >= 6) + result = -EIO; + else + hw_w_phy(hw, port->linked->port_id, data->reg_num, + data->val_in); + break; + + default: + result = -EOPNOTSUPP; + } + + up(&priv->proc_sem); + + return result; +} + +/* + * MII support + */ + +/** + * mdio_read - read PHY register + * @dev: Network device. + * @phy_id: The PHY id. + * @reg_num: The register number. + * + * This function returns the PHY register value. + * + * Return the register value. + */ +static int mdio_read(struct net_device *dev, int phy_id, int reg_num) +{ + struct dev_priv *priv = netdev_priv(dev); + struct ksz_port *port = &priv->port; + struct ksz_hw *hw = port->hw; + u16 val_out; + + hw_r_phy(hw, port->linked->port_id, reg_num << 1, &val_out); + return val_out; +} + +/** + * mdio_write - set PHY register + * @dev: Network device. + * @phy_id: The PHY id. + * @reg_num: The register number. + * @val: The register value. + * + * This procedure sets the PHY register value. + */ +static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) +{ + struct dev_priv *priv = netdev_priv(dev); + struct ksz_port *port = &priv->port; + struct ksz_hw *hw = port->hw; + int i; + int pi; + + for (i = 0, pi = port->first_port; i < port->port_cnt; i++, pi++) + hw_w_phy(hw, pi, reg_num << 1, val); +} + +/* + * ethtool support + */ + +#define EEPROM_SIZE 0x40 + +static u16 eeprom_data[EEPROM_SIZE] = { 0 }; + +#define ADVERTISED_ALL \ + (ADVERTISED_10baseT_Half | \ + ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | \ + ADVERTISED_100baseT_Full) + +/* These functions use the MII functions in mii.c. */ + +/** + * netdev_get_settings - get network device settings + * @dev: Network device. + * @cmd: Ethtool command. + * + * This function queries the PHY and returns its state in the ethtool command. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + + mutex_lock(&hw_priv->lock); + mii_ethtool_gset(&priv->mii_if, cmd); + cmd->advertising |= SUPPORTED_TP; + mutex_unlock(&hw_priv->lock); + + /* Save advertised settings for workaround in next function. */ + priv->advertising = cmd->advertising; + return 0; +} + +/** + * netdev_set_settings - set network device settings + * @dev: Network device. + * @cmd: Ethtool command. + * + * This function sets the PHY according to the ethtool command. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_port *port = &priv->port; + int rc; + + /* + * ethtool utility does not change advertised setting if auto + * negotiation is not specified explicitly. + */ + if (cmd->autoneg && priv->advertising == cmd->advertising) { + cmd->advertising |= ADVERTISED_ALL; + if (10 == cmd->speed) + cmd->advertising &= + ~(ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half); + else if (100 == cmd->speed) + cmd->advertising &= + ~(ADVERTISED_10baseT_Full | + ADVERTISED_10baseT_Half); + if (0 == cmd->duplex) + cmd->advertising &= + ~(ADVERTISED_100baseT_Full | + ADVERTISED_10baseT_Full); + else if (1 == cmd->duplex) + cmd->advertising &= + ~(ADVERTISED_100baseT_Half | + ADVERTISED_10baseT_Half); + } + mutex_lock(&hw_priv->lock); + if (cmd->autoneg && + (cmd->advertising & ADVERTISED_ALL) == + ADVERTISED_ALL) { + port->duplex = 0; + port->speed = 0; + port->force_link = 0; + } else { + port->duplex = cmd->duplex + 1; + if (cmd->speed != 1000) + port->speed = cmd->speed; + if (cmd->autoneg) + port->force_link = 0; + else + port->force_link = 1; + } + rc = mii_ethtool_sset(&priv->mii_if, cmd); + mutex_unlock(&hw_priv->lock); + return rc; +} + +/** + * netdev_nway_reset - restart auto-negotiation + * @dev: Network device. + * + * This function restarts the PHY for auto-negotiation. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_nway_reset(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + int rc; + + mutex_lock(&hw_priv->lock); + rc = mii_nway_restart(&priv->mii_if); + mutex_unlock(&hw_priv->lock); + return rc; +} + +/** + * netdev_get_link - get network device link status + * @dev: Network device. + * + * This function gets the link status from the PHY. + * + * Return true if PHY is linked and false otherwise. + */ +static u32 netdev_get_link(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + int rc; + + rc = mii_link_ok(&priv->mii_if); + return rc; +} + +/** + * netdev_get_drvinfo - get network driver information + * @dev: Network device. + * @info: Ethtool driver info data structure. + * + * This procedure returns the driver information. + */ +static void netdev_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(hw_priv->pdev)); +} + +/** + * netdev_get_regs_len - get length of register dump + * @dev: Network device. + * + * This function returns the length of the register dump. + * + * Return length of the register dump. + */ +static struct hw_regs { + int start; + int end; +} hw_regs_range[] = { + { KS_DMA_TX_CTRL, KS884X_INTERRUPTS_STATUS }, + { KS_ADD_ADDR_0_LO, KS_ADD_ADDR_F_HI }, + { KS884X_ADDR_0_OFFSET, KS8841_WOL_FRAME_BYTE2_OFFSET }, + { KS884X_SIDER_P, KS8842_SGCR7_P }, + { KS8842_MACAR1_P, KS8842_TOSR8_P }, + { KS884X_P1MBCR_P, KS8842_P3ERCR_P }, + { 0, 0 } +}; + +static int netdev_get_regs_len(struct net_device *dev) +{ + struct hw_regs *range = hw_regs_range; + int regs_len = 0x10 * sizeof(u32); + + while (range->end > range->start) { + regs_len += (range->end - range->start + 3) / 4 * 4; + range++; + } + return regs_len; +} + +/** + * netdev_get_regs - get register dump + * @dev: Network device. + * @regs: Ethtool registers data structure. + * @ptr: Buffer to store the register values. + * + * This procedure dumps the register values in the provided buffer. + */ +static void netdev_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *ptr) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + int *buf = (int *) ptr; + struct hw_regs *range = hw_regs_range; + int len; + + mutex_lock(&hw_priv->lock); + regs->version = 0; + for (len = 0; len < 0x40; len += 4) { + pci_read_config_dword(hw_priv->pdev, len, buf); + buf++; + } + while (range->end > range->start) { + for (len = range->start; len < range->end; len += 4) { + *buf = readl(hw->io + len); + buf++; + } + range++; + } + mutex_unlock(&hw_priv->lock); +} + +#define WOL_SUPPORT \ + (WAKE_PHY | WAKE_MAGIC | \ + WAKE_UCAST | WAKE_MCAST | \ + WAKE_BCAST | WAKE_ARP) + +/** + * netdev_get_wol - get Wake-on-LAN support + * @dev: Network device. + * @wol: Ethtool Wake-on-LAN data structure. + * + * This procedure returns Wake-on-LAN support. + */ +static void netdev_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + + wol->supported = hw_priv->wol_support; + wol->wolopts = hw_priv->wol_enable; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +/** + * netdev_set_wol - set Wake-on-LAN support + * @dev: Network device. + * @wol: Ethtool Wake-on-LAN data structure. + * + * This function sets Wake-on-LAN support. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + + /* Need to find a way to retrieve the device IP address. */ + u8 net_addr[] = { 192, 168, 1, 1 }; + + if (wol->wolopts & ~hw_priv->wol_support) + return -EINVAL; + + hw_priv->wol_enable = wol->wolopts; + + /* Link wakeup cannot really be disabled. */ + if (wol->wolopts) + hw_priv->wol_enable |= WAKE_PHY; + hw_enable_wol(&hw_priv->hw, hw_priv->wol_enable, net_addr); + return 0; +} + +/** + * netdev_get_msglevel - get debug message level + * @dev: Network device. + * + * This function returns current debug message level. + * + * Return current debug message flags. + */ +static u32 netdev_get_msglevel(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + + return priv->msg_enable; +} + +/** + * netdev_set_msglevel - set debug message level + * @dev: Network device. + * @value: Debug message flags. + * + * This procedure sets debug message level. + */ +static void netdev_set_msglevel(struct net_device *dev, u32 value) +{ + struct dev_priv *priv = netdev_priv(dev); + + priv->msg_enable = value; +} + +/** + * netdev_get_eeprom_len - get EEPROM length + * @dev: Network device. + * + * This function returns the length of the EEPROM. + * + * Return length of the EEPROM. + */ +static int netdev_get_eeprom_len(struct net_device *dev) +{ + return EEPROM_SIZE * 2; +} + +/** + * netdev_get_eeprom - get EEPROM data + * @dev: Network device. + * @eeprom: Ethtool EEPROM data structure. + * @data: Buffer to store the EEPROM data. + * + * This function dumps the EEPROM data in the provided buffer. + * + * Return 0 if successful; otherwise an error code. + */ +#define EEPROM_MAGIC 0x10A18842 + +static int netdev_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + u8 *eeprom_byte = (u8 *) eeprom_data; + int i; + int len; + + len = (eeprom->offset + eeprom->len + 1) / 2; + for (i = eeprom->offset / 2; i < len; i++) + eeprom_data[i] = eeprom_read(&hw_priv->hw, i); + eeprom->magic = EEPROM_MAGIC; + memcpy(data, &eeprom_byte[eeprom->offset], eeprom->len); + + return 0; +} + +/** + * netdev_set_eeprom - write EEPROM data + * @dev: Network device. + * @eeprom: Ethtool EEPROM data structure. + * @data: Data buffer. + * + * This function modifies the EEPROM data one byte at a time. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + u16 eeprom_word[EEPROM_SIZE]; + u8 *eeprom_byte = (u8 *) eeprom_word; + int i; + int len; + + if (eeprom->magic != EEPROM_MAGIC) + return 1; + + len = (eeprom->offset + eeprom->len + 1) / 2; + for (i = eeprom->offset / 2; i < len; i++) + eeprom_data[i] = eeprom_read(&hw_priv->hw, i); + memcpy(eeprom_word, eeprom_data, EEPROM_SIZE * 2); + memcpy(&eeprom_byte[eeprom->offset], data, eeprom->len); + for (i = 0; i < EEPROM_SIZE; i++) + if (eeprom_word[i] != eeprom_data[i]) { + eeprom_data[i] = eeprom_word[i]; + eeprom_write(&hw_priv->hw, i, eeprom_data[i]); + } + + return 0; +} + +/** + * netdev_get_pauseparam - get flow control parameters + * @dev: Network device. + * @pause: Ethtool PAUSE settings data structure. + * + * This procedure returns the PAUSE control flow settings. + */ +static void netdev_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + pause->autoneg = (hw->overrides & PAUSE_FLOW_CTRL) ? 0 : 1; + if (!hw->ksz_switch) { + pause->rx_pause = + (hw->rx_cfg & DMA_RX_FLOW_ENABLE) ? 1 : 0; + pause->tx_pause = + (hw->tx_cfg & DMA_TX_FLOW_ENABLE) ? 1 : 0; + } else { + pause->rx_pause = + (sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_RX_FLOW_CTRL)) ? 1 : 0; + pause->tx_pause = + (sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_TX_FLOW_CTRL)) ? 1 : 0; + } +} + +/** + * netdev_set_pauseparam - set flow control parameters + * @dev: Network device. + * @pause: Ethtool PAUSE settings data structure. + * + * This function sets the PAUSE control flow settings. + * Not implemented yet. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port *port = &priv->port; + + mutex_lock(&hw_priv->lock); + if (pause->autoneg) { + if (!pause->rx_pause && !pause->tx_pause) + port->flow_ctrl = PHY_NO_FLOW_CTRL; + else + port->flow_ctrl = PHY_FLOW_CTRL; + hw->overrides &= ~PAUSE_FLOW_CTRL; + port->force_link = 0; + if (hw->ksz_switch) { + sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_RX_FLOW_CTRL, 1); + sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_TX_FLOW_CTRL, 1); + } + port_set_link_speed(port); + } else { + hw->overrides |= PAUSE_FLOW_CTRL; + if (hw->ksz_switch) { + sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_RX_FLOW_CTRL, pause->rx_pause); + sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, + SWITCH_TX_FLOW_CTRL, pause->tx_pause); + } else + set_flow_ctrl(hw, pause->rx_pause, pause->tx_pause); + } + mutex_unlock(&hw_priv->lock); + + return 0; +} + +/** + * netdev_get_ringparam - get tx/rx ring parameters + * @dev: Network device. + * @pause: Ethtool RING settings data structure. + * + * This procedure returns the TX/RX ring settings. + */ +static void netdev_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + ring->tx_max_pending = (1 << 9); + ring->tx_pending = hw->tx_desc_info.alloc; + ring->rx_max_pending = (1 << 9); + ring->rx_pending = hw->rx_desc_info.alloc; +} + +#define STATS_LEN (TOTAL_PORT_COUNTER_NUM) + +static struct { + char string[ETH_GSTRING_LEN]; +} ethtool_stats_keys[STATS_LEN] = { + { "rx_lo_priority_octets" }, + { "rx_hi_priority_octets" }, + { "rx_undersize_packets" }, + { "rx_fragments" }, + { "rx_oversize_packets" }, + { "rx_jabbers" }, + { "rx_symbol_errors" }, + { "rx_crc_errors" }, + { "rx_align_errors" }, + { "rx_mac_ctrl_packets" }, + { "rx_pause_packets" }, + { "rx_bcast_packets" }, + { "rx_mcast_packets" }, + { "rx_ucast_packets" }, + { "rx_64_or_less_octet_packets" }, + { "rx_65_to_127_octet_packets" }, + { "rx_128_to_255_octet_packets" }, + { "rx_256_to_511_octet_packets" }, + { "rx_512_to_1023_octet_packets" }, + { "rx_1024_to_1522_octet_packets" }, + + { "tx_lo_priority_octets" }, + { "tx_hi_priority_octets" }, + { "tx_late_collisions" }, + { "tx_pause_packets" }, + { "tx_bcast_packets" }, + { "tx_mcast_packets" }, + { "tx_ucast_packets" }, + { "tx_deferred" }, + { "tx_total_collisions" }, + { "tx_excessive_collisions" }, + { "tx_single_collisions" }, + { "tx_mult_collisions" }, + + { "rx_discards" }, + { "tx_discards" }, +}; + +/** + * netdev_get_strings - get statistics identity strings + * @dev: Network device. + * @stringset: String set identifier. + * @buf: Buffer to store the strings. + * + * This procedure returns the strings used to identify the statistics. + */ +static void netdev_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + if (ETH_SS_STATS == stringset) + memcpy(buf, ðtool_stats_keys, + ETH_GSTRING_LEN * hw->mib_cnt); +} + +/** + * netdev_get_sset_count - get statistics size + * @dev: Network device. + * @sset: The statistics set number. + * + * This function returns the size of the statistics to be reported. + * + * Return size of the statistics to be reported. + */ +static int netdev_get_sset_count(struct net_device *dev, int sset) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + switch (sset) { + case ETH_SS_STATS: + return hw->mib_cnt; + default: + return -EOPNOTSUPP; + } +} + +/** + * netdev_get_ethtool_stats - get network device statistics + * @dev: Network device. + * @stats: Ethtool statistics data structure. + * @data: Buffer to store the statistics. + * + * This procedure returns the statistics. + */ +static void netdev_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port *port = &priv->port; + int n_stats = stats->n_stats; + int i; + int n; + int p; + int rc; + u64 counter[TOTAL_PORT_COUNTER_NUM]; + + mutex_lock(&hw_priv->lock); + n = SWITCH_PORT_NUM; + for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) { + if (media_connected == hw->port_mib[p].state) { + hw_priv->counter[p].read = 1; + + /* Remember first port that requests read. */ + if (n == SWITCH_PORT_NUM) + n = p; + } + } + mutex_unlock(&hw_priv->lock); + + if (n < SWITCH_PORT_NUM) + schedule_work(&hw_priv->mib_read); + + if (1 == port->mib_port_cnt && n < SWITCH_PORT_NUM) { + p = n; + rc = wait_event_interruptible_timeout( + hw_priv->counter[p].counter, + 2 == hw_priv->counter[p].read, + HZ * 1); + } else + for (i = 0, p = n; i < port->mib_port_cnt - n; i++, p++) { + if (0 == i) { + rc = wait_event_interruptible_timeout( + hw_priv->counter[p].counter, + 2 == hw_priv->counter[p].read, + HZ * 2); + } else if (hw->port_mib[p].cnt_ptr) { + rc = wait_event_interruptible_timeout( + hw_priv->counter[p].counter, + 2 == hw_priv->counter[p].read, + HZ * 1); + } + } + + get_mib_counters(hw, port->first_port, port->mib_port_cnt, counter); + n = hw->mib_cnt; + if (n > n_stats) + n = n_stats; + n_stats -= n; + for (i = 0; i < n; i++) + *data++ = counter[i]; +} + +/** + * netdev_get_rx_csum - get receive checksum support + * @dev: Network device. + * + * This function gets receive checksum support setting. + * + * Return true if receive checksum is enabled; false otherwise. + */ +static u32 netdev_get_rx_csum(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + + return hw->rx_cfg & + (DMA_RX_CSUM_UDP | + DMA_RX_CSUM_TCP | + DMA_RX_CSUM_IP); +} + +/** + * netdev_set_rx_csum - set receive checksum support + * @dev: Network device. + * @data: Zero to disable receive checksum support. + * + * This function sets receive checksum support setting. + * + * Return 0 if successful; otherwise an error code. + */ +static int netdev_set_rx_csum(struct net_device *dev, u32 data) +{ + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + u32 new_setting = hw->rx_cfg; + + if (data) + new_setting |= + (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | + DMA_RX_CSUM_IP); + else + new_setting &= + ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | + DMA_RX_CSUM_IP); + new_setting &= ~DMA_RX_CSUM_UDP; + mutex_lock(&hw_priv->lock); + if (new_setting != hw->rx_cfg) { + hw->rx_cfg = new_setting; + if (hw->enabled) + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + } + mutex_unlock(&hw_priv->lock); + return 0; +} + +static struct ethtool_ops netdev_ethtool_ops = { + .get_settings = netdev_get_settings, + .set_settings = netdev_set_settings, + .nway_reset = netdev_nway_reset, + .get_link = netdev_get_link, + .get_drvinfo = netdev_get_drvinfo, + .get_regs_len = netdev_get_regs_len, + .get_regs = netdev_get_regs, + .get_wol = netdev_get_wol, + .set_wol = netdev_set_wol, + .get_msglevel = netdev_get_msglevel, + .set_msglevel = netdev_set_msglevel, + .get_eeprom_len = netdev_get_eeprom_len, + .get_eeprom = netdev_get_eeprom, + .set_eeprom = netdev_set_eeprom, + .get_pauseparam = netdev_get_pauseparam, + .set_pauseparam = netdev_set_pauseparam, + .get_ringparam = netdev_get_ringparam, + .get_strings = netdev_get_strings, + .get_sset_count = netdev_get_sset_count, + .get_ethtool_stats = netdev_get_ethtool_stats, + .get_rx_csum = netdev_get_rx_csum, + .set_rx_csum = netdev_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +}; + +/* + * Hardware monitoring + */ + +static void update_link(struct net_device *dev, struct dev_priv *priv, + struct ksz_port *port) +{ + if (priv->media_state != port->linked->state) { + priv->media_state = port->linked->state; + if (netif_running(dev)) { + if (media_connected == priv->media_state) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + if (netif_msg_link(priv)) + printk(KERN_INFO "%s link %s\n", dev->name, + (media_connected == priv->media_state ? + "on" : "off")); + } + } +} + +static void mib_read_work(struct work_struct *work) +{ + struct dev_info *hw_priv = + container_of(work, struct dev_info, mib_read); + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port_mib *mib; + int i; + + next_jiffies = jiffies; + for (i = 0; i < hw->mib_port_cnt; i++) { + mib = &hw->port_mib[i]; + + /* Reading MIB counters or requested to read. */ + if (mib->cnt_ptr || 1 == hw_priv->counter[i].read) { + + /* Need to process receive interrupt. */ + if (port_r_cnt(hw, i)) + break; + hw_priv->counter[i].read = 0; + + /* Finish reading counters. */ + if (0 == mib->cnt_ptr) { + hw_priv->counter[i].read = 2; + wake_up_interruptible( + &hw_priv->counter[i].counter); + } + } else if (jiffies >= hw_priv->counter[i].time) { + /* Only read MIB counters when the port is connected. */ + if (media_connected == mib->state) + hw_priv->counter[i].read = 1; + next_jiffies += HZ * 1 * hw->mib_port_cnt; + hw_priv->counter[i].time = next_jiffies; + + /* Port is just disconnected. */ + } else if (mib->link_down) { + mib->link_down = 0; + + /* Read counters one last time after link is lost. */ + hw_priv->counter[i].read = 1; + } + } +} + +static void mib_monitor(unsigned long ptr) +{ + struct dev_info *hw_priv = (struct dev_info *) ptr; + + mib_read_work(&hw_priv->mib_read); + + /* This is used to verify Wake-on-LAN is working. */ + if (hw_priv->pme_wait) { + if (hw_priv->pme_wait <= jiffies) { + hw_clr_wol_pme_status(&hw_priv->hw); + hw_priv->pme_wait = 0; + } + } else if (hw_chk_wol_pme_status(&hw_priv->hw)) { + + /* PME is asserted. Wait 2 seconds to clear it. */ + hw_priv->pme_wait = jiffies + HZ * 2; + } + + ksz_update_timer(&hw_priv->mib_timer_info); +} + +/** + * dev_monitor - periodic monitoring + * @ptr: Network device pointer. + * + * This routine is run in a kernel timer to monitor the network device. + */ +static void dev_monitor(unsigned long ptr) +{ + struct net_device *dev = (struct net_device *) ptr; + struct dev_priv *priv = netdev_priv(dev); + struct dev_info *hw_priv = priv->adapter; + struct ksz_hw *hw = &hw_priv->hw; + struct ksz_port *port = &priv->port; + + if (!(hw->features & LINK_INT_WORKING)) + port_get_link_speed(port); + update_link(dev, priv, port); + + ksz_update_timer(&priv->monitor_timer_info); +} + +/* + * Linux network device interface functions + */ + +/* Driver exported variables */ + +static int msg_enable; + +static char *macaddr = ":"; +static char *mac1addr = ":"; + +/* + * This enables multiple network device mode for KSZ8842, which contains a + * switch with two physical ports. Some users like to take control of the + * ports for running Spanning Tree Protocol. The driver will create an + * additional eth? device for the other port. + * + * Some limitations are the network devices cannot have different MTU and + * multicast hash tables. + */ +static int multi_dev; + +/* + * As most users select multiple network device mode to use Spanning Tree + * Protocol, this enables a feature in which most unicast and multicast packets + * are forwarded inside the switch and not passed to the host. Only packets + * that need the host's attention are passed to it. This prevents the host + * wasting CPU time to examine each and every incoming packets and do the + * forwarding itself. + * + * As the hack requires the private bridge header, the driver cannot compile + * with just the kernel headers. + * + * Enabling STP support also turns on multiple network device mode. + */ +static int stp; + +/* + * This enables fast aging in the KSZ8842 switch. Not sure what situation + * needs that. However, fast aging is used to flush the dynamic MAC table when + * STP suport is enabled. + */ +static int fast_aging; + +/** + * netdev_init - initalize network device. + * @dev: Network device. + * + * This function initializes the network device. + * + * Return 0 if successful; otherwise an error code indicating failure. + */ +static int __init netdev_init(struct net_device *dev) +{ + struct dev_priv *priv = netdev_priv(dev); + + /* 500 ms timeout */ + ksz_init_timer(&priv->monitor_timer_info, 500 * HZ / 1000, + dev_monitor, dev); + + /* 500 ms timeout */ + dev->watchdog_timeo = HZ / 2; + + dev->features |= NETIF_F_IP_CSUM; + + /* + * Hardware does not really support IPv6 checksum generation, but + * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK. + */ + dev->features |= NETIF_F_IPV6_CSUM; + dev->features |= NETIF_F_SG; + + sema_init(&priv->proc_sem, 1); + + priv->mii_if.phy_id_mask = 0x1; + priv->mii_if.reg_num_mask = 0x7; + priv->mii_if.dev = dev; + priv->mii_if.mdio_read = mdio_read; + priv->mii_if.mdio_write = mdio_write; + priv->mii_if.phy_id = priv->port.first_port + 1; + + priv->msg_enable = netif_msg_init(msg_enable, + (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)); + + return 0; +} + +static const struct net_device_ops netdev_ops = { + .ndo_init = netdev_init, + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_get_stats = netdev_query_statistics, + .ndo_start_xmit = netdev_tx, + .ndo_tx_timeout = netdev_tx_timeout, + .ndo_change_mtu = netdev_change_mtu, + .ndo_set_mac_address = netdev_set_mac_address, + .ndo_do_ioctl = netdev_ioctl, + .ndo_set_rx_mode = netdev_set_rx_mode, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = netdev_netpoll, +#endif +}; + +static void netdev_free(struct net_device *dev) +{ + if (dev->watchdog_timeo) + unregister_netdev(dev); + + free_netdev(dev); +} + +struct platform_info { + struct dev_info dev_info; + struct net_device *netdev[SWITCH_PORT_NUM]; +}; + +static int net_device_present; + +static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port) +{ + int i; + int j; + int got_num; + int num; + + i = j = num = got_num = 0; + while (j < MAC_ADDR_LEN) { + if (macaddr[i]) { + got_num = 1; + if ('0' <= macaddr[i] && macaddr[i] <= '9') + num = num * 16 + macaddr[i] - '0'; + else if ('A' <= macaddr[i] && macaddr[i] <= 'F') + num = num * 16 + 10 + macaddr[i] - 'A'; + else if ('a' <= macaddr[i] && macaddr[i] <= 'f') + num = num * 16 + 10 + macaddr[i] - 'a'; + else if (':' == macaddr[i]) + got_num = 2; + else + break; + } else if (got_num) + got_num = 2; + else + break; + if (2 == got_num) { + if (MAIN_PORT == port) { + hw_priv->hw.override_addr[j++] = (u8) num; + hw_priv->hw.override_addr[5] += + hw_priv->hw.id; + } else { + hw_priv->hw.ksz_switch->other_addr[j++] = + (u8) num; + hw_priv->hw.ksz_switch->other_addr[5] += + hw_priv->hw.id; + } + num = got_num = 0; + } + i++; + } + if (MAC_ADDR_LEN == j) { + if (MAIN_PORT == port) + hw_priv->hw.mac_override = 1; + } +} + +#define KS884X_DMA_MASK (~0x0UL) + +static void read_other_addr(struct ksz_hw *hw) +{ + int i; + u16 data[3]; + struct ksz_switch *sw = hw->ksz_switch; + + for (i = 0; i < 3; i++) + data[i] = eeprom_read(hw, i + EEPROM_DATA_OTHER_MAC_ADDR); + if ((data[0] || data[1] || data[2]) && data[0] != 0xffff) { + sw->other_addr[5] = (u8) data[0]; + sw->other_addr[4] = (u8)(data[0] >> 8); + sw->other_addr[3] = (u8) data[1]; + sw->other_addr[2] = (u8)(data[1] >> 8); + sw->other_addr[1] = (u8) data[2]; + sw->other_addr[0] = (u8)(data[2] >> 8); + } +} + +#ifndef PCI_VENDOR_ID_MICREL_KS +#define PCI_VENDOR_ID_MICREL_KS 0x16c6 +#endif + +static int __init pcidev_init(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct net_device *dev; + struct dev_priv *priv; + struct dev_info *hw_priv; + struct ksz_hw *hw; + struct platform_info *info; + struct ksz_port *port; + unsigned long reg_base; + unsigned long reg_len; + int cnt; + int i; + int mib_port_count; + int pi; + int port_count; + int result; + char banner[80]; + struct ksz_switch *sw = NULL; + + result = pci_enable_device(pdev); + if (result) + return result; + + result = -ENODEV; + + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) + return result; + + reg_base = pci_resource_start(pdev, 0); + reg_len = pci_resource_len(pdev, 0); + if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) + return result; + + if (!request_mem_region(reg_base, reg_len, DRV_NAME)) + return result; + pci_set_master(pdev); + + result = -ENOMEM; + + info = kmalloc(sizeof(struct platform_info), GFP_KERNEL); + if (!info) + goto pcidev_init_dev_err; + memset(info, 0, sizeof(struct platform_info)); + + hw_priv = &info->dev_info; + hw_priv->pdev = pdev; + + hw = &hw_priv->hw; + + hw->io = ioremap(reg_base, reg_len); + if (!hw->io) + goto pcidev_init_io_err; + + cnt = hw_init(hw); + if (!cnt) { + if (msg_enable & NETIF_MSG_PROBE) + printk(KERN_ALERT "chip not detected\n"); + result = -ENODEV; + goto pcidev_init_alloc_err; + } + + sprintf(banner, "%s\n", version); + banner[13] = cnt + '0'; + ks_info(hw_priv, "%s", banner); + ks_dbg(hw_priv, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq); + + /* Assume device is KSZ8841. */ + hw->dev_count = 1; + port_count = 1; + mib_port_count = 1; + hw->addr_list_size = 0; + hw->mib_cnt = PORT_COUNTER_NUM; + hw->mib_port_cnt = 1; + + /* KSZ8842 has a switch with multiple ports. */ + if (2 == cnt) { + if (fast_aging) + hw->overrides |= FAST_AGING; + + hw->mib_cnt = TOTAL_PORT_COUNTER_NUM; + + /* Multiple network device interfaces are required. */ + if (multi_dev) { + hw->dev_count = SWITCH_PORT_NUM; + hw->addr_list_size = SWITCH_PORT_NUM - 1; + } + + /* Single network device has multiple ports. */ + if (1 == hw->dev_count) { + port_count = SWITCH_PORT_NUM; + mib_port_count = SWITCH_PORT_NUM; + } + hw->mib_port_cnt = TOTAL_PORT_NUM; + hw->ksz_switch = kmalloc(sizeof(struct ksz_switch), GFP_KERNEL); + if (!hw->ksz_switch) + goto pcidev_init_alloc_err; + memset(hw->ksz_switch, 0, sizeof(struct ksz_switch)); + + sw = hw->ksz_switch; + } + for (i = 0; i < hw->mib_port_cnt; i++) + hw->port_mib[i].mib_start = 0; + + hw->parent = hw_priv; + + /* Default MTU is 1500. */ + hw_priv->mtu = (REGULAR_RX_BUF_SIZE + 3) & ~3; + + if (ksz_alloc_mem(hw_priv)) + goto pcidev_init_mem_err; + + hw_priv->hw.id = net_device_present; + + spin_lock_init(&hw_priv->hwlock); + mutex_init(&hw_priv->lock); + + /* tasklet is enabled. */ + tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, + (unsigned long) hw_priv); + tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, + (unsigned long) hw_priv); + + /* tasklet_enable will decrement the atomic counter. */ + tasklet_disable(&hw_priv->rx_tasklet); + tasklet_disable(&hw_priv->tx_tasklet); + + for (i = 0; i < TOTAL_PORT_NUM; i++) + init_waitqueue_head(&hw_priv->counter[i].counter); + + if (macaddr[0] != ':') + get_mac_addr(hw_priv, macaddr, MAIN_PORT); + + /* Read MAC address and initialize override address if not overrided. */ + hw_read_addr(hw); + + /* Multiple device interfaces mode requires a second MAC address. */ + if (hw->dev_count > 1) { + memcpy(sw->other_addr, hw->override_addr, MAC_ADDR_LEN); + read_other_addr(hw); + if (mac1addr[0] != ':') + get_mac_addr(hw_priv, mac1addr, OTHER_PORT); + } + + hw_setup(hw); + if (hw->ksz_switch) + sw_setup(hw); + else { + hw_priv->wol_support = WOL_SUPPORT; + hw_priv->wol_enable = 0; + } + + INIT_WORK(&hw_priv->mib_read, mib_read_work); + + /* 500 ms timeout */ + ksz_init_timer(&hw_priv->mib_timer_info, 500 * HZ / 1000, + mib_monitor, hw_priv); + + for (i = 0; i < hw->dev_count; i++) { + dev = alloc_etherdev(sizeof(struct dev_priv)); + if (!dev) + goto pcidev_init_reg_err; + info->netdev[i] = dev; + + priv = netdev_priv(dev); + priv->adapter = hw_priv; + priv->id = net_device_present++; + + port = &priv->port; + port->port_cnt = port_count; + port->mib_port_cnt = mib_port_count; + port->first_port = i; + port->flow_ctrl = PHY_FLOW_CTRL; + + port->hw = hw; + port->linked = &hw->port_info[port->first_port]; + + for (cnt = 0, pi = i; cnt < port_count; cnt++, pi++) { + hw->port_info[pi].port_id = pi; + hw->port_info[pi].pdev = dev; + hw->port_info[pi].state = media_disconnected; + } + + dev->mem_start = (unsigned long) hw->io; + dev->mem_end = dev->mem_start + reg_len - 1; + dev->irq = pdev->irq; + if (MAIN_PORT == i) + memcpy(dev->dev_addr, hw_priv->hw.override_addr, + MAC_ADDR_LEN); + else { + memcpy(dev->dev_addr, sw->other_addr, + MAC_ADDR_LEN); + if (!memcmp(sw->other_addr, hw->override_addr, + MAC_ADDR_LEN)) + dev->dev_addr[5] += port->first_port; + } + + dev->netdev_ops = &netdev_ops; + SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); + if (register_netdev(dev)) + goto pcidev_init_reg_err; + port_set_power_saving(port, true); + } + + pci_dev_get(hw_priv->pdev); + pci_set_drvdata(pdev, info); + return 0; + +pcidev_init_reg_err: + for (i = 0; i < hw->dev_count; i++) { + if (info->netdev[i]) { + netdev_free(info->netdev[i]); + info->netdev[i] = NULL; + } + } + +pcidev_init_mem_err: + ksz_free_mem(hw_priv); + kfree(hw->ksz_switch); + +pcidev_init_alloc_err: + iounmap(hw->io); + +pcidev_init_io_err: + kfree(info); + +pcidev_init_dev_err: + release_mem_region(reg_base, reg_len); + + return result; +} + +static void pcidev_exit(struct pci_dev *pdev) +{ + int i; + struct platform_info *info = pci_get_drvdata(pdev); + struct dev_info *hw_priv = &info->dev_info; + + pci_set_drvdata(pdev, NULL); + + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + for (i = 0; i < hw_priv->hw.dev_count; i++) { + if (info->netdev[i]) + netdev_free(info->netdev[i]); + } + if (hw_priv->hw.io) + iounmap(hw_priv->hw.io); + ksz_free_mem(hw_priv); + kfree(hw_priv->hw.ksz_switch); + pci_dev_put(hw_priv->pdev); + kfree(info); +} + +#ifdef CONFIG_PM +static int pcidev_resume(struct pci_dev *pdev) +{ + int i; + struct platform_info *info = pci_get_drvdata(pdev); + struct dev_info *hw_priv = &info->dev_info; + struct ksz_hw *hw = &hw_priv->hw; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_enable_wake(pdev, PCI_D0, 0); + + if (hw_priv->wol_enable) + hw_cfg_wol_pme(hw, 0); + for (i = 0; i < hw->dev_count; i++) { + if (info->netdev[i]) { + struct net_device *dev = info->netdev[i]; + + if (netif_running(dev)) { + netdev_open(dev); + netif_device_attach(dev); + } + } + } + return 0; +} + +static int pcidev_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int i; + struct platform_info *info = pci_get_drvdata(pdev); + struct dev_info *hw_priv = &info->dev_info; + struct ksz_hw *hw = &hw_priv->hw; + + /* Need to find a way to retrieve the device IP address. */ + u8 net_addr[] = { 192, 168, 1, 1 }; + + for (i = 0; i < hw->dev_count; i++) { + if (info->netdev[i]) { + struct net_device *dev = info->netdev[i]; + + if (netif_running(dev)) { + netif_device_detach(dev); + netdev_close(dev); + } + } + } + if (hw_priv->wol_enable) { + hw_enable_wol(hw, hw_priv->wol_enable, net_addr); + hw_cfg_wol_pme(hw, 1); + } + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} +#endif + +static char pcidev_name[] = "ksz884xp"; + +static struct pci_device_id pcidev_table[] = { + { PCI_VENDOR_ID_MICREL_KS, 0x8841, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MICREL_KS, 0x8842, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, pcidev_table); + +static struct pci_driver pci_device_driver = { +#ifdef CONFIG_PM + .suspend = pcidev_suspend, + .resume = pcidev_resume, +#endif + .name = pcidev_name, + .id_table = pcidev_table, + .probe = pcidev_init, + .remove = pcidev_exit +}; + +static int __init ksz884x_init_module(void) +{ + return pci_register_driver(&pci_device_driver); +} + +static void __exit ksz884x_cleanup_module(void) +{ + pci_unregister_driver(&pci_device_driver); +} + +module_init(ksz884x_init_module); +module_exit(ksz884x_cleanup_module); + +MODULE_DESCRIPTION("KSZ8841/2 PCI network driver"); +MODULE_AUTHOR("Tristram Ha "); +MODULE_LICENSE("GPL"); + +module_param_named(message, msg_enable, int, 0); +MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)"); + +module_param(macaddr, charp, 0); +module_param(mac1addr, charp, 0); +module_param(fast_aging, int, 0); +module_param(multi_dev, int, 0); +module_param(stp, int, 0); +MODULE_PARM_DESC(macaddr, "MAC address"); +MODULE_PARM_DESC(mac1addr, "Second MAC address"); +MODULE_PARM_DESC(fast_aging, "Fast aging"); +MODULE_PARM_DESC(multi_dev, "Multiple device interfaces"); +MODULE_PARM_DESC(stp, "STP support"); -- GitLab From 1eb1cc7a209f9593312ba014f1b1f02c31eda4fb Mon Sep 17 00:00:00 2001 From: Tristram Ha Date: Mon, 8 Feb 2010 11:38:28 +0000 Subject: [PATCH 1970/3892] net: Kconfig change for KSZ884X driver Add Micrel KSZ8841/KSZ8842 PCI Ethernet chip support. Signed-off-by: Tristram Ha Signed-off-by: David S. Miller --- drivers/net/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1bf1987571ff..5f646523c5ae 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1380,6 +1380,17 @@ config AC3200 To compile this driver as a module, choose M here. The module will be called ac3200. +config KSZ884X_PCI + tristate "Micrel KSZ8841/2 PCI" + depends on NET_PCI && PCI + select MII + select CRC32 + help + This PCI driver is for Micrel KSZ8841/KSZ8842 PCI Ethernet chip. + + To compile this driver as a module, choose M here. The module + will be called ksz884x. + config APRICOT tristate "Apricot Xen-II on board Ethernet" depends on NET_PCI && ISA -- GitLab From b25822ca5e3d6551b74506e2c69afada7c29c967 Mon Sep 17 00:00:00 2001 From: Tristram Ha Date: Mon, 8 Feb 2010 11:40:04 +0000 Subject: [PATCH 1971/3892] net: Makefile change for KSZ884X driver Add Micrel KSZ884X network driver for KSZ8841/KSZ8842 PCI Ethernet chips. Signed-off-by: Tristram Ha Signed-off-by: David S. Miller --- drivers/net/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 95958032cd31..622cfd450d48 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_KS8851) += ks8851.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o +obj-$(CONFIG_KSZ884X_PCI) += ksz884x.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o -- GitLab From 830a8a976ff2236ebc383e9a06f7872ed9243bfb Mon Sep 17 00:00:00 2001 From: Shirley Ma Date: Mon, 8 Feb 2010 14:14:42 +0000 Subject: [PATCH 1972/3892] virtio_net: remove send queue Now we have a virtio detach API (in commit f9bfbebf34eab707b065116cdc9699d25ba4252a), we don't need to track xmit skbs in the virio_net driver, which improves transmission performance. Signed-off-by: Shirley Ma Acked-by: Rusty Russell Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4c347a3df657..ce35b42cc2cb 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -56,9 +56,6 @@ struct virtnet_info /* Host will merge rx buffers for big packets (shake it! shake it!) */ bool mergeable_rx_bufs; - /* Send queue. */ - struct sk_buff_head send; - /* Work struct for refilling if we run low on memory. */ struct delayed_work refill; @@ -505,7 +502,6 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi) while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { pr_debug("Sent skb %p\n", skb); - __skb_unlink(skb, &vi->send); vi->dev->stats.tx_bytes += skb->len; vi->dev->stats.tx_packets++; tot_sgs += skb_vnet_hdr(skb)->num_sg; @@ -588,15 +584,6 @@ again: } vi->svq->vq_ops->kick(vi->svq); - /* - * Put new one in send queue. You'd expect we'd need this before - * xmit_skb calls add_buf(), since the callback can be triggered - * immediately after that. But since the callback just triggers - * another call back here, normal network xmit locking prevents the - * race. - */ - __skb_queue_head(&vi->send, skb); - /* Don't wait up for transmitted skbs to be freed. */ skb_orphan(skb); nf_reset(skb); @@ -980,9 +967,6 @@ static int virtnet_probe(struct virtio_device *vdev) dev->features |= NETIF_F_HW_VLAN_FILTER; } - /* Initialize our empty send queue. */ - skb_queue_head_init(&vi->send); - err = register_netdev(dev); if (err) { pr_debug("virtio_net: registering device failed\n"); @@ -1018,6 +1002,12 @@ free: static void free_unused_bufs(struct virtnet_info *vi) { void *buf; + while (1) { + buf = vi->svq->vq_ops->detach_unused_buf(vi->svq); + if (!buf) + break; + dev_kfree_skb(buf); + } while (1) { buf = vi->rvq->vq_ops->detach_unused_buf(vi->rvq); if (!buf) @@ -1038,11 +1028,11 @@ static void __devexit virtnet_remove(struct virtio_device *vdev) /* Stop all the virtqueues. */ vdev->config->reset(vdev); - /* Free our skbs in send queue, if any. */ - __skb_queue_purge(&vi->send); unregister_netdev(vi->dev); cancel_delayed_work_sync(&vi->refill); + + /* Free unused buffers in both send and recv, if any. */ free_unused_bufs(vi); vdev->config->del_vqs(vi->vdev); -- GitLab From e254f6ecaeb4e7c0588e739bf4641df0e8c22bba Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:28:35 +0000 Subject: [PATCH 1973/3892] be2net: remove unused pci device id We are not going to use this device id. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 6 ++---- drivers/net/benet/be_main.c | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 5bc74590c73e..242013157f20 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -44,16 +44,14 @@ #define BE_DEVICE_ID1 0x211 #define BE_DEVICE_ID2 0x221 #define OC_DEVICE_ID1 0x700 -#define OC_DEVICE_ID2 0x701 -#define OC_DEVICE_ID3 0x710 +#define OC_DEVICE_ID2 0x710 static inline char *nic_name(struct pci_dev *pdev) { switch (pdev->device) { case OC_DEVICE_ID1: - case OC_DEVICE_ID2: return OC_NAME; - case OC_DEVICE_ID3: + case OC_DEVICE_ID2: return OC_NAME1; case BE_DEVICE_ID2: return BE3_NAME; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 0014a4e86446..0779f6b5e29b 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -34,7 +34,6 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, { 0 } }; MODULE_DEVICE_TABLE(pci, be_dev_ids); -- GitLab From 3f0d4560aedaa67546eaeb3dc75fcdf68ec21036 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:30:35 +0000 Subject: [PATCH 1974/3892] be2net: bug fix for flashing the BladeEngine3 ASIC Now flashing both BE2 and BE3 devices is supported. From: Naresh G Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 9 +- drivers/net/benet/be_cmds.h | 3 +- drivers/net/benet/be_hw.h | 119 ++++++++++++------ drivers/net/benet/be_main.c | 239 +++++++++++++++++++----------------- 4 files changed, 217 insertions(+), 153 deletions(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 3227b11131c4..d1a0e5ede4b3 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1374,7 +1374,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_type, u32 flash_opcode, u32 buf_size) { struct be_mcc_wrb *wrb; - struct be_cmd_write_flashrom *req = cmd->va; + struct be_cmd_write_flashrom *req; struct be_sge *sge; int status; @@ -1408,7 +1408,8 @@ err: return status; } -int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc) +int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + int offset) { struct be_mcc_wrb *wrb; struct be_cmd_write_flashrom *req; @@ -1429,9 +1430,9 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4); - req->params.op_type = cpu_to_le32(FLASHROM_TYPE_REDBOOT); + req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT); req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); - req->params.offset = 0x3FFFC; + req->params.offset = offset; req->params.data_buf_size = 0x4; status = be_mcc_notify_wait(adapter); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index c622a968c379..7297b5a47657 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -931,7 +931,8 @@ extern int be_cmd_read_port_type(struct be_adapter *adapter, u32 port, extern int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 buf_size); -extern int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc); +int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + int offset); extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd); extern int be_cmd_fw_init(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index e2b3beffd49d..bb2ae6f924db 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -99,6 +99,63 @@ /* Number of entries posted */ #define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */ +/* Flashrom related descriptors */ +#define IMAGE_TYPE_FIRMWARE 160 +#define IMAGE_TYPE_BOOTCODE 224 +#define IMAGE_TYPE_OPTIONROM 32 + +#define NUM_FLASHDIR_ENTRIES 32 + +#define IMG_TYPE_ISCSI_ACTIVE 0 +#define IMG_TYPE_REDBOOT 1 +#define IMG_TYPE_BIOS 2 +#define IMG_TYPE_PXE_BIOS 3 +#define IMG_TYPE_FCOE_BIOS 8 +#define IMG_TYPE_ISCSI_BACKUP 9 +#define IMG_TYPE_FCOE_FW_ACTIVE 10 +#define IMG_TYPE_FCOE_FW_BACKUP 11 +#define IMG_TYPE_NCSI_BITFILE 13 +#define IMG_TYPE_NCSI_8051 14 + +#define FLASHROM_OPER_FLASH 1 +#define FLASHROM_OPER_SAVE 2 +#define FLASHROM_OPER_REPORT 4 + +#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image sz */ +#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM img sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */ +#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max fw image size */ +#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM img sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */ + +#define FLASH_NCSI_MAGIC (0x16032009) +#define FLASH_NCSI_DISABLED (0) +#define FLASH_NCSI_ENABLED (1) + +#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000) + +/* Offsets for components on Flash. */ +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576) +#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296) +#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016) +#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736) +#define FLASH_iSCSI_BIOS_START_g2 (7340032) +#define FLASH_PXE_BIOS_START_g2 (7864320) +#define FLASH_FCoE_BIOS_START_g2 (524288) +#define FLASH_REDBOOT_START_g2 (0) + +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152) +#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304) +#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456) +#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608) +#define FLASH_iSCSI_BIOS_START_g3 (12582912) +#define FLASH_PXE_BIOS_START_g3 (13107200) +#define FLASH_FCoE_BIOS_START_g3 (13631488) +#define FLASH_REDBOOT_START_g3 (262144) + + + + /* * BE descriptors: host memory data structures whose formats * are hardwired in BE silicon. @@ -107,6 +164,7 @@ #define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */ #define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */ #define EQ_ENTRY_RES_ID_SHIFT 16 + struct be_eq_entry { u32 evt; }; @@ -221,41 +279,6 @@ struct be_eth_rx_compl { u32 dw[4]; }; -/* Flashrom related descriptors */ -#define IMAGE_TYPE_FIRMWARE 160 -#define IMAGE_TYPE_BOOTCODE 224 -#define IMAGE_TYPE_OPTIONROM 32 - -#define NUM_FLASHDIR_ENTRIES 32 - -#define FLASHROM_TYPE_ISCSI_ACTIVE 0 -#define FLASHROM_TYPE_REDBOOT 1 -#define FLASHROM_TYPE_BIOS 2 -#define FLASHROM_TYPE_PXE_BIOS 3 -#define FLASHROM_TYPE_FCOE_BIOS 8 -#define FLASHROM_TYPE_ISCSI_BACKUP 9 -#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10 -#define FLASHROM_TYPE_FCOE_FW_BACKUP 11 - -#define FLASHROM_OPER_FLASH 1 -#define FLASHROM_OPER_SAVE 2 -#define FLASHROM_OPER_REPORT 4 - -#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */ -#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */ -#define FLASH_REDBOOT_IMAGE_MAX_SIZE (262144) /* Max redboot image sz */ - -/* Offsets for components on Flash. */ -#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576) -#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296) -#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016) -#define FLASH_FCoE_BACKUP_IMAGE_START (4980736) -#define FLASH_iSCSI_BIOS_START (7340032) -#define FLASH_PXE_BIOS_START (7864320) -#define FLASH_FCoE_BIOS_START (524288) -#define FLASH_REDBOOT_START (32768) -#define FLASH_REDBOOT_ISM_START (0) - struct controller_id { u32 vendor; u32 device; @@ -263,7 +286,20 @@ struct controller_id { u32 subdevice; }; -struct flash_file_hdr { +struct flash_comp { + unsigned long offset; + int optype; + int size; +}; + +struct image_hdr { + u32 imageid; + u32 imageoffset; + u32 imagelength; + u32 image_checksum; + u8 image_version[32]; +}; +struct flash_file_hdr_g2 { u8 sign[32]; u32 cksum; u32 antidote; @@ -275,6 +311,17 @@ struct flash_file_hdr { u8 build[24]; }; +struct flash_file_hdr_g3 { + u8 sign[52]; + u8 ufi_version[4]; + u32 file_len; + u32 cksum; + u32 antidote; + u32 num_imgs; + u8 build[24]; + u8 rsvd[32]; +}; + struct flash_section_hdr { u32 format_rev; u32 cksum; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 0779f6b5e29b..99061488eeb3 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1798,15 +1798,19 @@ char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; static bool be_flash_redboot(struct be_adapter *adapter, - const u8 *p) + const u8 *p, u32 img_start, int image_size, + int hdr_size) { u32 crc_offset; u8 flashed_crc[4]; int status; - crc_offset = FLASH_REDBOOT_START + FLASH_REDBOOT_IMAGE_MAX_SIZE - 4 - + sizeof(struct flash_file_hdr) - 32*1024; + + crc_offset = hdr_size + img_start + image_size - 4; + p += crc_offset; - status = be_cmd_get_flash_crc(adapter, flashed_crc); + + status = be_cmd_get_flash_crc(adapter, flashed_crc, + (img_start + image_size - 4)); if (status) { dev_err(&adapter->pdev->dev, "could not get crc from flash, not flashing redboot\n"); @@ -1818,102 +1822,124 @@ static bool be_flash_redboot(struct be_adapter *adapter, return false; else return true; - } -static int be_flash_image(struct be_adapter *adapter, +static int be_flash_data(struct be_adapter *adapter, const struct firmware *fw, - struct be_dma_mem *flash_cmd, u32 flash_type) + struct be_dma_mem *flash_cmd, int num_of_images) + { - int status; - u32 flash_op, image_offset = 0, total_bytes, image_size = 0; + int status = 0, i, filehdr_size = 0; + u32 total_bytes = 0, flash_op; int num_bytes; const u8 *p = fw->data; struct be_cmd_write_flashrom *req = flash_cmd->va; - - switch (flash_type) { - case FLASHROM_TYPE_ISCSI_ACTIVE: - image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START; - image_size = FLASH_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_ISCSI_BACKUP: - image_offset = FLASH_iSCSI_BACKUP_IMAGE_START; - image_size = FLASH_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_FCOE_FW_ACTIVE: - image_offset = FLASH_FCoE_PRIMARY_IMAGE_START; - image_size = FLASH_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_FCOE_FW_BACKUP: - image_offset = FLASH_FCoE_BACKUP_IMAGE_START; - image_size = FLASH_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_BIOS: - image_offset = FLASH_iSCSI_BIOS_START; - image_size = FLASH_BIOS_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_FCOE_BIOS: - image_offset = FLASH_FCoE_BIOS_START; - image_size = FLASH_BIOS_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_PXE_BIOS: - image_offset = FLASH_PXE_BIOS_START; - image_size = FLASH_BIOS_IMAGE_MAX_SIZE; - break; - case FLASHROM_TYPE_REDBOOT: - if (!be_flash_redboot(adapter, fw->data)) - return 0; - image_offset = FLASH_REDBOOT_ISM_START; - image_size = FLASH_REDBOOT_IMAGE_MAX_SIZE; - break; - default: - return 0; + struct flash_comp *pflashcomp; + + struct flash_comp gen3_flash_types[8] = { + { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g3}, + { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT, + FLASH_REDBOOT_IMAGE_MAX_SIZE_g3}, + { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3}, + { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3}, + { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3}, + { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP, + FLASH_IMAGE_MAX_SIZE_g3}, + { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g3}, + { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP, + FLASH_IMAGE_MAX_SIZE_g3} + }; + struct flash_comp gen2_flash_types[8] = { + { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g2}, + { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT, + FLASH_REDBOOT_IMAGE_MAX_SIZE_g2}, + { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2}, + { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2}, + { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2}, + { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP, + FLASH_IMAGE_MAX_SIZE_g2}, + { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g2}, + { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP, + FLASH_IMAGE_MAX_SIZE_g2} + }; + + if (adapter->generation == BE_GEN3) { + pflashcomp = gen3_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g3); + } else { + pflashcomp = gen2_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g2); } - - p += sizeof(struct flash_file_hdr) + image_offset; - if (p + image_size > fw->data + fw->size) + for (i = 0; i < 8; i++) { + if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && + (!be_flash_redboot(adapter, fw->data, + pflashcomp[i].offset, pflashcomp[i].size, + filehdr_size))) + continue; + p = fw->data; + p += filehdr_size + pflashcomp[i].offset + + (num_of_images * sizeof(struct image_hdr)); + if (p + pflashcomp[i].size > fw->data + fw->size) return -1; - - total_bytes = image_size; - - while (total_bytes) { - if (total_bytes > 32*1024) - num_bytes = 32*1024; - else - num_bytes = total_bytes; - total_bytes -= num_bytes; - - if (!total_bytes) - flash_op = FLASHROM_OPER_FLASH; - else - flash_op = FLASHROM_OPER_SAVE; - memcpy(req->params.data_buf, p, num_bytes); - p += num_bytes; - status = be_cmd_write_flashrom(adapter, flash_cmd, - flash_type, flash_op, num_bytes); - if (status) { - dev_err(&adapter->pdev->dev, - "cmd to write to flash rom failed. type/op %d/%d\n", - flash_type, flash_op); - return -1; + total_bytes = pflashcomp[i].size; + while (total_bytes) { + if (total_bytes > 32*1024) + num_bytes = 32*1024; + else + num_bytes = total_bytes; + total_bytes -= num_bytes; + + if (!total_bytes) + flash_op = FLASHROM_OPER_FLASH; + else + flash_op = FLASHROM_OPER_SAVE; + memcpy(req->params.data_buf, p, num_bytes); + p += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, + pflashcomp[i].optype, flash_op, num_bytes); + if (status) { + dev_err(&adapter->pdev->dev, + "cmd to write to flash rom failed.\n"); + return -1; + } + yield(); } - yield(); } - return 0; } +static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr) +{ + if (fhdr == NULL) + return 0; + if (fhdr->build[0] == '3') + return BE_GEN3; + else if (fhdr->build[0] == '2') + return BE_GEN2; + else + return 0; +} + int be_load_fw(struct be_adapter *adapter, u8 *func) { char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; const struct firmware *fw; - struct flash_file_hdr *fhdr; - struct flash_section_info *fsec = NULL; + struct flash_file_hdr_g2 *fhdr; + struct flash_file_hdr_g3 *fhdr3; + struct image_hdr *img_hdr_ptr = NULL; struct be_dma_mem flash_cmd; - int status; + int status, i = 0; const u8 *p; - bool entry_found = false; - int flash_type; char fw_ver[FW_VER_LEN]; char fw_cfg; @@ -1931,34 +1957,9 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) goto fw_exit; p = fw->data; - fhdr = (struct flash_file_hdr *) p; - if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) { - dev_err(&adapter->pdev->dev, - "Firmware(%s) load error (signature did not match)\n", - fw_file); - status = -1; - goto fw_exit; - } - + fhdr = (struct flash_file_hdr_g2 *) p; dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); - p += sizeof(struct flash_file_hdr); - while (p < (fw->data + fw->size)) { - fsec = (struct flash_section_info *)p; - if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) { - entry_found = true; - break; - } - p += 32; - } - - if (!entry_found) { - status = -1; - dev_err(&adapter->pdev->dev, - "Flash cookie not found in firmware image\n"); - goto fw_exit; - } - flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, &flash_cmd.dma); @@ -1969,12 +1970,26 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) goto fw_exit; } - for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE; - flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) { - status = be_flash_image(adapter, fw, &flash_cmd, - flash_type); - if (status) - break; + if ((adapter->generation == BE_GEN3) && + (get_ufigen_type(fhdr) == BE_GEN3)) { + fhdr3 = (struct flash_file_hdr_g3 *) fw->data; + for (i = 0; i < fhdr3->num_imgs; i++) { + img_hdr_ptr = (struct image_hdr *) (fw->data + + (sizeof(struct flash_file_hdr_g3) + + i * sizeof(struct image_hdr))); + if (img_hdr_ptr->imageid == 1) { + status = be_flash_data(adapter, fw, + &flash_cmd, fhdr3->num_imgs); + } + + } + } else if ((adapter->generation == BE_GEN2) && + (get_ufigen_type(fhdr) == BE_GEN2)) { + status = be_flash_data(adapter, fw, &flash_cmd, 0); + } else { + dev_err(&adapter->pdev->dev, + "UFI and Interface are not compatible for flashing\n"); + status = -1; } pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, -- GitLab From 34a89b8c75abe2873a95524552cc266fdd3b6a85 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:32:43 +0000 Subject: [PATCH 1975/3892] be2net: bug fix in be_change_mtu Current code allows the new mtu to cross the supported value. This patch fixes the boundary checks. From: Suresh R Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 99061488eeb3..c65c63427d41 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -473,10 +473,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) { struct be_adapter *adapter = netdev_priv(netdev); if (new_mtu < BE_MIN_MTU || - new_mtu > BE_MAX_JUMBO_FRAME_SIZE) { + new_mtu > (BE_MAX_JUMBO_FRAME_SIZE - + (ETH_HLEN + ETH_FCS_LEN))) { dev_info(&adapter->pdev->dev, "MTU must be between %d and %d bytes\n", - BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE); + BE_MIN_MTU, + (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN))); return -EINVAL; } dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n", -- GitLab From 205859a2ff922d0587a819b08007398cbd0a6a30 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:34:21 +0000 Subject: [PATCH 1976/3892] be2net: minor code optimizations Couple of code optimizations in the Rx path (to avoid a memset). From: Sathya P Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c65c63427d41..1951d7620a88 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -636,9 +636,11 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); - if (rx_page_info->last_page_user) + if (rx_page_info->last_page_user) { pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus), adapter->big_page_size, PCI_DMA_FROMDEVICE); + rx_page_info->last_page_user = false; + } atomic_dec(&rxq->used); return rx_page_info; @@ -706,7 +708,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, skb->data_len = curr_frag_len - hdr_len; skb->tail += hdr_len; } - memset(page_info, 0, sizeof(*page_info)); + page_info->page = NULL; if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); @@ -739,7 +741,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, skb->len += curr_frag_len; skb->data_len += curr_frag_len; - memset(page_info, 0, sizeof(*page_info)); + page_info->page = NULL; } BUG_ON(j > MAX_SKB_FRAGS); -- GitLab From 82903e4bfca1578336a91c0c17839b484c12295d Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:34:57 +0000 Subject: [PATCH 1977/3892] be2net: fix to limit max vlans supported in certain skews In certain skews the ASIC can support only 16 vlans per interface. Once the limit is crossed, the ASIC is programmed in vlan promiscuous mode. Switch off the vlan promiscuous mode once the number of vlans falls back to the max vlans supported. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 3 ++- drivers/net/benet/be_main.c | 30 +++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 242013157f20..476a5c455794 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -250,7 +250,8 @@ struct be_adapter { bool rx_post_starved; /* Zero rx frags have been posted to BE */ struct vlan_group *vlan_grp; - u16 num_vlans; + u16 vlans_added; + u16 max_vlans; /* Number of vlans supported */ u8 vlan_tag[VLAN_GROUP_ARRAY_LEN]; struct be_dma_mem mc_cmd_mem; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 1951d7620a88..92c55f679466 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -488,17 +488,16 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) } /* - * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured, - * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured, - * set the BE in promiscuous VLAN mode. + * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE. + * If the user configures more, place BE in vlan promiscuous mode. */ static int be_vid_config(struct be_adapter *adapter) { u16 vtag[BE_NUM_VLANS_SUPPORTED]; u16 ntags = 0, i; - int status; + int status = 0; - if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED) { + if (adapter->vlans_added <= adapter->max_vlans) { /* Construct VLAN Table to give to HW */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { if (adapter->vlan_tag[i]) { @@ -532,21 +531,21 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); - adapter->num_vlans++; adapter->vlan_tag[vid] = 1; - - be_vid_config(adapter); + adapter->vlans_added++; + if (adapter->vlans_added <= (adapter->max_vlans + 1)) + be_vid_config(adapter); } static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); - adapter->num_vlans--; adapter->vlan_tag[vid] = 0; - vlan_group_set_device(adapter->vlan_grp, vid, NULL); - be_vid_config(adapter); + adapter->vlans_added--; + if (adapter->vlans_added <= adapter->max_vlans) + be_vid_config(adapter); } static void be_set_multicast_list(struct net_device *netdev) @@ -786,7 +785,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb->dev = adapter->netdev; if (vlanf) { - if (!adapter->vlan_grp || adapter->num_vlans == 0) { + if (!adapter->vlan_grp || adapter->vlans_added == 0) { kfree_skb(skb); return; } @@ -866,7 +865,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); vid = be16_to_cpu(vid); - if (!adapter->vlan_grp || adapter->num_vlans == 0) + if (!adapter->vlan_grp || adapter->vlans_added == 0) return; vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); @@ -2241,6 +2240,11 @@ static int be_get_config(struct be_adapter *adapter) memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); + if (adapter->cap & 0x400) + adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4; + else + adapter->max_vlans = BE_NUM_VLANS_SUPPORTED; + return 0; } -- GitLab From 35ecf03c833d9aae35df9f1d86e6efa86d3d2628 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:38:06 +0000 Subject: [PATCH 1978/3892] be2net: change the driver description Since the driver is supporting multiple generations of the ASIC remove ASIC generation information from the driver description. This information is displayed by modinfo. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 476a5c455794..b39b38542623 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -38,7 +38,7 @@ #define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" #define OC_NAME "Emulex OneConnect 10Gbps NIC" #define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)" -#define DRV_DESC BE_NAME "Driver" +#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver" #define BE_VENDOR_ID 0x19a2 #define BE_DEVICE_ID1 0x211 -- GitLab From 1a8cdc5d49cdbd79dedce8db3840fca825304d8d Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 9 Feb 2010 01:39:05 +0000 Subject: [PATCH 1979/3892] be2net: remove ASIC generation number from Kconfig Since the driver is supporting multiple generations of the ASIC don't mention any ASIC generation number. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig index fdb6e81a4374..1a41a49bb619 100644 --- a/drivers/net/benet/Kconfig +++ b/drivers/net/benet/Kconfig @@ -1,6 +1,6 @@ config BE2NET - tristate "ServerEngines' 10Gbps NIC - BladeEngine 2" + tristate "ServerEngines' 10Gbps NIC - BladeEngine" depends on PCI && INET help This driver implements the NIC functionality for ServerEngines' - 10Gbps network adapter - BladeEngine 2. + 10Gbps network adapter - BladeEngine. -- GitLab From c0ad98453f23b98f73a1f1be2a75303a6c0dee4c Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Mon, 8 Feb 2010 17:51:26 +0000 Subject: [PATCH 1980/3892] be2net: bug fix in be_read_eeprom The offset to read the eeprom data was missing and wrong eeprom data was being dumped. This patch fixes this. >From Suresh R Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 09d8899b2de9..dcc7f37b5428 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -614,7 +614,7 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, if (!status) { resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va; - memcpy(data, resp->seeprom_data, eeprom->len); + memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len); } pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va, eeprom_cmd.dma); -- GitLab From dc2b99f71ef477a31020511876ab4403fb7c4420 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 8 Feb 2010 19:48:05 +0000 Subject: [PATCH 1981/3892] IPv6: keep permanent addresses on admin down Permanent IPV6 addresses should not be removed when the link is set to admin down, only when device is removed. When link is lost permanent addresses should be marked as tentative so that when link comes back they are subject to duplicate address detection (if DAD was enabled for that address). Other routing systems keep manually configured IPv6 addresses when link is set down. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1593289155ff..b0e1430b64f1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2646,7 +2646,8 @@ static int addrconf_ifdown(struct net_device *dev, int how) write_lock_bh(&addrconf_hash_lock); while ((ifa = *bifa) != NULL) { - if (ifa->idev == idev) { + if (ifa->idev == idev && + (how || !(ifa->flags&IFA_F_PERMANENT))) { *bifa = ifa->lst_next; ifa->lst_next = NULL; addrconf_del_timer(ifa); @@ -2686,18 +2687,30 @@ static int addrconf_ifdown(struct net_device *dev, int how) write_lock_bh(&idev->lock); } #endif - while ((ifa = idev->addr_list) != NULL) { - idev->addr_list = ifa->if_next; - ifa->if_next = NULL; - ifa->dead = 1; - addrconf_del_timer(ifa); - write_unlock_bh(&idev->lock); + bifa = &idev->addr_list; + while ((ifa = *bifa) != NULL) { + if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { + /* Retain permanent address on admin down */ + bifa = &ifa->if_next; + + /* Restart DAD if needed when link comes back up */ + if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || + idev->cnf.accept_dad <= 0 || + (ifa->flags & IFA_F_NODAD))) + ifa->flags |= IFA_F_TENTATIVE; + } else { + *bifa = ifa->if_next; + ifa->if_next = NULL; - __ipv6_ifa_notify(RTM_DELADDR, ifa); - atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); - in6_ifa_put(ifa); + ifa->dead = 1; + write_unlock_bh(&idev->lock); - write_lock_bh(&idev->lock); + __ipv6_ifa_notify(RTM_DELADDR, ifa); + atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); + in6_ifa_put(ifa); + + write_lock_bh(&idev->lock); + } } write_unlock_bh(&idev->lock); -- GitLab From 21809fafa042fcfff3f788419bed99f3c289745c Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 8 Feb 2010 19:48:52 +0000 Subject: [PATCH 1982/3892] IPv6: remove trivial nested _bh suffix Don't need to disable bottom half it is already down in the previous lock. Move some blank lines to group locking in same context. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b0e1430b64f1..764ad37ca070 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2802,14 +2802,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) read_lock_bh(&idev->lock); if (ifp->dead) goto out; - spin_lock_bh(&ifp->lock); + spin_lock(&ifp->lock); if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || idev->cnf.accept_dad < 1 || !(ifp->flags&IFA_F_TENTATIVE) || ifp->flags & IFA_F_NODAD) { ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); read_unlock_bh(&idev->lock); addrconf_dad_completed(ifp); @@ -2817,7 +2817,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) } if (!(idev->if_flags & IF_READY)) { - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); read_unlock_bh(&idev->lock); /* * If the device is not ready: @@ -2837,7 +2837,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) ip6_ins_rt(ifp->rt); addrconf_dad_kick(ifp); - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); out: read_unlock_bh(&idev->lock); } @@ -2853,14 +2853,15 @@ static void addrconf_dad_timer(unsigned long data) read_unlock_bh(&idev->lock); goto out; } - spin_lock_bh(&ifp->lock); + + spin_lock(&ifp->lock); if (ifp->probes == 0) { /* * DAD was successful */ ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); read_unlock_bh(&idev->lock); addrconf_dad_completed(ifp); @@ -2870,7 +2871,7 @@ static void addrconf_dad_timer(unsigned long data) ifp->probes--; addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); read_unlock_bh(&idev->lock); /* send a neighbour solicitation for our addr */ @@ -2918,12 +2919,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) { read_lock_bh(&idev->lock); for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { - spin_lock_bh(&ifp->lock); + spin_lock(&ifp->lock); if (!(ifp->flags & IFA_F_TENTATIVE)) { - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); continue; } - spin_unlock_bh(&ifp->lock); + spin_unlock(&ifp->lock); addrconf_dad_kick(ifp); } read_unlock_bh(&idev->lock); -- GitLab From 571ba42303813106d533bf6bda929d8e289f51bf Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:47 +0000 Subject: [PATCH 1983/3892] netdevice.h: Add netdev_printk helpers like dev_printk These netdev_printk routines take a struct net_device * and emit dev_printk logging messages adding "%s: " ... netdev->dev.parent to the dev_printk format and arguments. This can create some uniformity in the output message log. These helpers should not be used until a successful alloc_netdev. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/netdevice.h | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cdf53a8d9ff5..a51228ac9331 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2095,6 +2095,77 @@ static inline u32 dev_ethtool_get_flags(struct net_device *dev) return 0; return dev->ethtool_ops->get_flags(dev); } + +/* Logging, debugging and troubleshooting/diagnostic helpers. */ + +/* netdev_printk helpers, similar to dev_printk */ + +static inline const char *netdev_name(const struct net_device *dev) +{ + if (dev->reg_state != NETREG_REGISTERED) + return "(unregistered net_device)"; + return dev->name; +} + +#define netdev_printk(level, netdev, format, args...) \ + dev_printk(level, (netdev)->dev.parent, \ + "%s: " format, \ + netdev_name(netdev), ##args) + +#define netdev_emerg(dev, format, args...) \ + netdev_printk(KERN_EMERG, dev, format, ##args) +#define netdev_alert(dev, format, args...) \ + netdev_printk(KERN_ALERT, dev, format, ##args) +#define netdev_crit(dev, format, args...) \ + netdev_printk(KERN_CRIT, dev, format, ##args) +#define netdev_err(dev, format, args...) \ + netdev_printk(KERN_ERR, dev, format, ##args) +#define netdev_warn(dev, format, args...) \ + netdev_printk(KERN_WARNING, dev, format, ##args) +#define netdev_notice(dev, format, args...) \ + netdev_printk(KERN_NOTICE, dev, format, ##args) +#define netdev_info(dev, format, args...) \ + netdev_printk(KERN_INFO, dev, format, ##args) + +#if defined(DEBUG) +#define netdev_dbg(__dev, format, args...) \ + netdev_printk(KERN_DEBUG, __dev, format, ##args) +#elif defined(CONFIG_DYNAMIC_DEBUG) +#define netdev_dbg(__dev, format, args...) \ +do { \ + dynamic_dev_dbg((__dev)->dev.parent, "%s: " format, \ + netdev_name(__dev), ##args); \ +} while (0) +#else +#define netdev_dbg(__dev, format, args...) \ +({ \ + if (0) \ + netdev_printk(KERN_DEBUG, __dev, format, ##args); \ + 0; \ +}) +#endif + +#if defined(VERBOSE_DEBUG) +#define netdev_vdbg netdev_dbg +#else + +#define netdev_vdbg(dev, format, args...) \ +({ \ + if (0) \ + netdev_printk(KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif + +/* + * netdev_WARN() acts like dev_printk(), but with the key difference + * of using a WARN/WARN_ON to get the message out, including the + * file/line information and a backtrace. + */ +#define netdev_WARN(dev, format, args...) \ + WARN(1, "netdevice: %s\n" format, netdev_name(dev), ##args); + + #endif /* __KERNEL__ */ #endif /* _LINUX_NETDEVICE_H */ -- GitLab From ba211e3ec35820eced89bfe12e2d94e6352a4c5f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:48 +0000 Subject: [PATCH 1984/3892] drivers/net/atl1e: Use netdev_printk helpers Logging messages sometimes had duplicated "ATL1E" output. For instance: ATL1E 0000:03:00.0: ATL1E: eth0 NIC Link is Up<100 Mbps Full Duplex> is now: ATL1E 0000:03:00.0: eth0: NIC Link is Up <100 Mbps Full Duplex> Add some consistency to logging messages Add some missing \n's to logging messages Miscellaneous typo spelling corrections Change atl1e_validate_option argument from pdev to adapter Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/atl1e/atl1e_hw.c | 23 +++-- drivers/net/atl1e/atl1e_main.c | 153 ++++++++++++++------------------ drivers/net/atl1e/atl1e_param.c | 35 ++++---- 3 files changed, 99 insertions(+), 112 deletions(-) diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c index 4a7700620119..76cc043def8c 100644 --- a/drivers/net/atl1e/atl1e_hw.c +++ b/drivers/net/atl1e/atl1e_hw.c @@ -394,7 +394,6 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) int atl1e_phy_commit(struct atl1e_hw *hw) { struct atl1e_adapter *adapter = hw->adapter; - struct pci_dev *pdev = adapter->pdev; int ret_val; u16 phy_data; @@ -415,12 +414,12 @@ int atl1e_phy_commit(struct atl1e_hw *hw) } if (0 != (val & (MDIO_START | MDIO_BUSY))) { - dev_err(&pdev->dev, - "pcie linkdown at least for 25ms\n"); + netdev_err(adapter->netdev, + "pcie linkdown at least for 25ms\n"); return ret_val; } - dev_err(&pdev->dev, "pcie linkup after %d ms\n", i); + netdev_err(adapter->netdev, "pcie linkup after %d ms\n", i); } return 0; } @@ -428,7 +427,6 @@ int atl1e_phy_commit(struct atl1e_hw *hw) int atl1e_phy_init(struct atl1e_hw *hw) { struct atl1e_adapter *adapter = hw->adapter; - struct pci_dev *pdev = adapter->pdev; s32 ret_val; u16 phy_val; @@ -492,20 +490,22 @@ int atl1e_phy_init(struct atl1e_hw *hw) /*Enable PHY LinkChange Interrupt */ ret_val = atl1e_write_phy_reg(hw, MII_INT_CTRL, 0xC00); if (ret_val) { - dev_err(&pdev->dev, "Error enable PHY linkChange Interrupt\n"); + netdev_err(adapter->netdev, + "Error enable PHY linkChange Interrupt\n"); return ret_val; } /* setup AutoNeg parameters */ ret_val = atl1e_phy_setup_autoneg_adv(hw); if (ret_val) { - dev_err(&pdev->dev, "Error Setting up Auto-Negotiation\n"); + netdev_err(adapter->netdev, + "Error Setting up Auto-Negotiation\n"); return ret_val; } /* SW.Reset & En-Auto-Neg to restart Auto-Neg*/ - dev_dbg(&pdev->dev, "Restarting Auto-Neg"); + netdev_dbg(adapter->netdev, "Restarting Auto-Negotiation\n"); ret_val = atl1e_phy_commit(hw); if (ret_val) { - dev_err(&pdev->dev, "Error Resetting the phy"); + netdev_err(adapter->netdev, "Error resetting the phy\n"); return ret_val; } @@ -559,9 +559,8 @@ int atl1e_reset_hw(struct atl1e_hw *hw) } if (timeout >= AT_HW_MAX_IDLE_DELAY) { - dev_err(&pdev->dev, - "MAC state machine cann't be idle since" - " disabled for 10ms second\n"); + netdev_err(adapter->netdev, + "MAC state machine can't be idle since disabled for 10ms second\n"); return AT_ERR_TIMEOUT; } diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index d59f8e89c65d..7d8de10ba628 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -164,11 +164,10 @@ static int atl1e_check_link(struct atl1e_adapter *adapter) { struct atl1e_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - struct pci_dev *pdev = adapter->pdev; int err = 0; u16 speed, duplex, phy_data; - /* MII_BMSR must read twise */ + /* MII_BMSR must read twice */ atl1e_read_phy_reg(hw, MII_BMSR, &phy_data); atl1e_read_phy_reg(hw, MII_BMSR, &phy_data); if ((phy_data & BMSR_LSTATUS) == 0) { @@ -195,12 +194,11 @@ static int atl1e_check_link(struct atl1e_adapter *adapter) adapter->link_speed = speed; adapter->link_duplex = duplex; atl1e_setup_mac_ctrl(adapter); - dev_info(&pdev->dev, - "%s: %s NIC Link is Up<%d Mbps %s>\n", - atl1e_driver_name, netdev->name, - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? - "Full Duplex" : "Half Duplex"); + netdev_info(netdev, + "NIC Link is Up <%d Mbps %s Duplex>\n", + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full" : "Half"); } if (!netif_carrier_ok(netdev)) { @@ -230,7 +228,6 @@ static void atl1e_link_chg_task(struct work_struct *work) static void atl1e_link_chg_event(struct atl1e_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct pci_dev *pdev = adapter->pdev; u16 phy_data = 0; u16 link_up = 0; @@ -243,8 +240,7 @@ static void atl1e_link_chg_event(struct atl1e_adapter *adapter) if (!link_up) { if (netif_carrier_ok(netdev)) { /* old link state: Up */ - dev_info(&pdev->dev, "%s: %s NIC Link is Down\n", - atl1e_driver_name, netdev->name); + netdev_info(netdev, "NIC Link is Down\n"); adapter->link_speed = SPEED_0; netif_stop_queue(netdev); } @@ -321,10 +317,9 @@ static void atl1e_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { struct atl1e_adapter *adapter = netdev_priv(netdev); - struct pci_dev *pdev = adapter->pdev; u32 mac_ctrl_data = 0; - dev_dbg(&pdev->dev, "atl1e_vlan_rx_register\n"); + netdev_dbg(adapter->netdev, "%s\n", __func__); atl1e_irq_disable(adapter); @@ -345,9 +340,7 @@ static void atl1e_vlan_rx_register(struct net_device *netdev, static void atl1e_restore_vlan(struct atl1e_adapter *adapter) { - struct pci_dev *pdev = adapter->pdev; - - dev_dbg(&pdev->dev, "atl1e_restore_vlan !"); + netdev_dbg(adapter->netdev, "%s\n", __func__); atl1e_vlan_rx_register(adapter->netdev, adapter->vlgrp); } /* @@ -391,7 +384,7 @@ static int atl1e_change_mtu(struct net_device *netdev, int new_mtu) if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { - dev_warn(&adapter->pdev->dev, "invalid MTU setting\n"); + netdev_warn(adapter->netdev, "invalid MTU setting\n"); return -EINVAL; } /* set MTU */ @@ -438,7 +431,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct atl1e_adapter *adapter = netdev_priv(netdev); - struct pci_dev *pdev = adapter->pdev; struct mii_ioctl_data *data = if_mii(ifr); unsigned long flags; int retval = 0; @@ -466,8 +458,8 @@ static int atl1e_mii_ioctl(struct net_device *netdev, goto out; } - dev_dbg(&pdev->dev, " write %x %x", - data->reg_num, data->val_in); + netdev_dbg(adapter->netdev, " write %x %x\n", + data->reg_num, data->val_in); if (atl1e_write_phy_reg(&adapter->hw, data->reg_num, data->val_in)) { retval = -EIO; @@ -602,7 +594,7 @@ static int __devinit atl1e_sw_init(struct atl1e_adapter *adapter) hw->dmaw_dly_cnt = 4; if (atl1e_alloc_queues(adapter)) { - dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + netdev_err(adapter->netdev, "Unable to allocate memory for queues\n"); return -ENOMEM; } @@ -800,8 +792,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) adapter->ring_size, &adapter->ring_dma); if (adapter->ring_vir_addr == NULL) { - dev_err(&pdev->dev, "pci_alloc_consistent failed, " - "size = D%d", size); + netdev_err(adapter->netdev, + "pci_alloc_consistent failed, size = D%d\n", size); return -ENOMEM; } @@ -817,7 +809,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count); tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL); if (tx_ring->tx_buffer == NULL) { - dev_err(&pdev->dev, "kzalloc failed , size = D%d", size); + netdev_err(adapter->netdev, "kzalloc failed, size = D%d\n", + size); err = -ENOMEM; goto failed; } @@ -852,8 +845,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) } if (unlikely(offset > adapter->ring_size)) { - dev_err(&pdev->dev, "offset(%d) > ring size(%d) !!\n", - offset, adapter->ring_size); + netdev_err(adapter->netdev, "offset(%d) > ring size(%d) !!\n", + offset, adapter->ring_size); err = -1; goto failed; } @@ -1077,7 +1070,6 @@ static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter) static int atl1e_configure(struct atl1e_adapter *adapter) { struct atl1e_hw *hw = &adapter->hw; - struct pci_dev *pdev = adapter->pdev; u32 intr_status_data = 0; @@ -1130,8 +1122,8 @@ static int atl1e_configure(struct atl1e_adapter *adapter) intr_status_data = AT_READ_REG(hw, REG_ISR); if (unlikely((intr_status_data & ISR_PHY_LINKDOWN) != 0)) { - dev_err(&pdev->dev, "atl1e_configure failed," - "PCIE phy link down\n"); + netdev_err(adapter->netdev, + "atl1e_configure failed, PCIE phy link down\n"); return -1; } @@ -1262,7 +1254,6 @@ static irqreturn_t atl1e_intr(int irq, void *data) { struct net_device *netdev = data; struct atl1e_adapter *adapter = netdev_priv(netdev); - struct pci_dev *pdev = adapter->pdev; struct atl1e_hw *hw = &adapter->hw; int max_ints = AT_MAX_INT_WORK; int handled = IRQ_NONE; @@ -1285,8 +1276,8 @@ static irqreturn_t atl1e_intr(int irq, void *data) handled = IRQ_HANDLED; /* check if PCIE PHY Link down */ if (status & ISR_PHY_LINKDOWN) { - dev_err(&pdev->dev, - "pcie phy linkdown %x\n", status); + netdev_err(adapter->netdev, + "pcie phy linkdown %x\n", status); if (netif_running(adapter->netdev)) { /* reset MAC */ atl1e_irq_reset(adapter); @@ -1297,9 +1288,9 @@ static irqreturn_t atl1e_intr(int irq, void *data) /* check if DMA read/write error */ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { - dev_err(&pdev->dev, - "PCIE DMA RW error (status = 0x%x)\n", - status); + netdev_err(adapter->netdev, + "PCIE DMA RW error (status = 0x%x)\n", + status); atl1e_irq_reset(adapter); schedule_work(&adapter->reset_task); break; @@ -1382,7 +1373,6 @@ static struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter, static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, int *work_done, int work_to_do) { - struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; struct atl1e_rx_ring *rx_ring = (struct atl1e_rx_ring *) &adapter->rx_ring; @@ -1404,11 +1394,10 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, rx_page->read_offset); /* check sequence number */ if (prrs->seq_num != rx_page_desc[que].rx_nxseq) { - dev_err(&pdev->dev, - "rx sequence number" - " error (rx=%d) (expect=%d)\n", - prrs->seq_num, - rx_page_desc[que].rx_nxseq); + netdev_err(netdev, + "rx sequence number error (rx=%d) (expect=%d)\n", + prrs->seq_num, + rx_page_desc[que].rx_nxseq); rx_page_desc[que].rx_nxseq++; /* just for debug use */ AT_WRITE_REG(&adapter->hw, REG_DEBUG_DATA0, @@ -1424,9 +1413,9 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, RRS_ERR_DRIBBLE | RRS_ERR_CODE | RRS_ERR_TRUNC)) { /* hardware error, discard this packet*/ - dev_err(&pdev->dev, - "rx packet desc error %x\n", - *((u32 *)prrs + 1)); + netdev_err(netdev, + "rx packet desc error %x\n", + *((u32 *)prrs + 1)); goto skip_pkt; } } @@ -1435,8 +1424,8 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, RRS_PKT_SIZE_MASK) - 4; /* CRC */ skb = netdev_alloc_skb_ip_align(netdev, packet_size); if (skb == NULL) { - dev_warn(&pdev->dev, "%s: Memory squeeze," - "deferring packet.\n", netdev->name); + netdev_warn(netdev, + "Memory squeeze, deferring packet\n"); goto skip_pkt; } skb->dev = netdev; @@ -1450,9 +1439,9 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, u16 vlan_tag = (prrs->vtag >> 4) | ((prrs->vtag & 7) << 13) | ((prrs->vtag & 8) << 9); - dev_dbg(&pdev->dev, - "RXD VLAN TAG=0x%04x\n", - prrs->vtag); + netdev_dbg(netdev, + "RXD VLAN TAG=0x%04x\n", + prrs->vtag); vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vlan_tag); } else { @@ -1500,7 +1489,6 @@ static int atl1e_clean(struct napi_struct *napi, int budget) { struct atl1e_adapter *adapter = container_of(napi, struct atl1e_adapter, napi); - struct pci_dev *pdev = adapter->pdev; u32 imr_data; int work_done = 0; @@ -1519,8 +1507,8 @@ quit_polling: /* test debug */ if (test_bit(__AT_DOWN, &adapter->flags)) { atomic_dec(&adapter->irq_sem); - dev_err(&pdev->dev, - "atl1e_clean is called when AT_DOWN\n"); + netdev_err(adapter->netdev, + "atl1e_clean is called when AT_DOWN\n"); } /* reenable RX intr */ /*atl1e_irq_enable(adapter); */ @@ -1618,7 +1606,6 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb) static int atl1e_tso_csum(struct atl1e_adapter *adapter, struct sk_buff *skb, struct atl1e_tpd_desc *tpd) { - struct pci_dev *pdev = adapter->pdev; u8 hdr_len; u32 real_len; unsigned short offload_type; @@ -1642,8 +1629,8 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter, hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); if (unlikely(skb->len == hdr_len)) { /* only xsum need */ - dev_warn(&pdev->dev, - "IPV4 tso with zero data??\n"); + netdev_warn(adapter->netdev, + "IPV4 tso with zero data??\n"); goto check_sum; } else { ip_hdr(skb)->check = 0; @@ -1672,8 +1659,8 @@ check_sum: cso = skb_transport_offset(skb); if (unlikely(cso & 0x1)) { - dev_err(&adapter->pdev->dev, - "pay load offset should not ant event number\n"); + netdev_err(adapter->netdev, + "payload offset should not ant event number\n"); return -1; } else { css = cso + skb->csum_offset; @@ -1886,8 +1873,8 @@ static int atl1e_request_irq(struct atl1e_adapter *adapter) adapter->have_msi = true; err = pci_enable_msi(adapter->pdev); if (err) { - dev_dbg(&pdev->dev, - "Unable to allocate MSI interrupt Error: %d\n", err); + netdev_dbg(adapter->netdev, + "Unable to allocate MSI interrupt Error: %d\n", err); adapter->have_msi = false; } else netdev->irq = pdev->irq; @@ -1898,13 +1885,13 @@ static int atl1e_request_irq(struct atl1e_adapter *adapter) err = request_irq(adapter->pdev->irq, atl1e_intr, flags, netdev->name, netdev); if (err) { - dev_dbg(&pdev->dev, - "Unable to allocate interrupt Error: %d\n", err); + netdev_dbg(adapter->netdev, + "Unable to allocate interrupt Error: %d\n", err); if (adapter->have_msi) pci_disable_msi(adapter->pdev); return err; } - dev_dbg(&pdev->dev, "atl1e_request_irq OK\n"); + netdev_dbg(adapter->netdev, "atl1e_request_irq OK\n"); return err; } @@ -2078,7 +2065,7 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) (atl1e_write_phy_reg(hw, MII_ADVERTISE, mii_advertise_data) != 0) || (atl1e_phy_commit(hw)) != 0) { - dev_dbg(&pdev->dev, "set phy register failed\n"); + netdev_dbg(adapter->netdev, "set phy register failed\n"); goto wol_dis; } @@ -2100,17 +2087,14 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) } if ((mii_bmsr_data & BMSR_LSTATUS) == 0) - dev_dbg(&pdev->dev, - "%s: Link may change" - "when suspend\n", - atl1e_driver_name); + netdev_dbg(adapter->netdev, + "Link may change when suspend\n"); } wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; /* only link up can wake up */ if (atl1e_write_phy_reg(hw, MII_INT_CTRL, 0x400) != 0) { - dev_dbg(&pdev->dev, "%s: read write phy " - "register failed.\n", - atl1e_driver_name); + netdev_dbg(adapter->netdev, + "read write phy register failed\n"); goto wol_dis; } } @@ -2131,9 +2115,8 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) if (wufc & AT_WUFC_MAG) mac_ctrl_data |= MAC_CTRL_BC_EN; - dev_dbg(&pdev->dev, - "%s: suspend MAC=0x%x\n", - atl1e_driver_name, mac_ctrl_data); + netdev_dbg(adapter->netdev, "suspend MAC=0x%x\n", + mac_ctrl_data); AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); @@ -2183,8 +2166,8 @@ static int atl1e_resume(struct pci_dev *pdev) err = pci_enable_device(pdev); if (err) { - dev_err(&pdev->dev, "ATL1e: Cannot enable PCI" - " device from suspend\n"); + netdev_err(adapter->netdev, + "Cannot enable PCI device from suspend\n"); return err; } @@ -2315,7 +2298,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, err = atl1e_init_netdev(netdev, pdev); if (err) { - dev_err(&pdev->dev, "init netdevice failed\n"); + netdev_err(netdev, "init netdevice failed\n"); goto err_init_netdev; } adapter = netdev_priv(netdev); @@ -2326,7 +2309,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0); if (!adapter->hw.hw_addr) { err = -EIO; - dev_err(&pdev->dev, "cannot map device registers\n"); + netdev_err(netdev, "cannot map device registers\n"); goto err_ioremap; } netdev->base_addr = (unsigned long)adapter->hw.hw_addr; @@ -2356,7 +2339,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, /* setup the private structure */ err = atl1e_sw_init(adapter); if (err) { - dev_err(&pdev->dev, "net device private data init failed\n"); + netdev_err(netdev, "net device private data init failed\n"); goto err_sw_init; } @@ -2372,19 +2355,19 @@ static int __devinit atl1e_probe(struct pci_dev *pdev, if (atl1e_read_mac_addr(&adapter->hw) != 0) { err = -EIO; - dev_err(&pdev->dev, "get mac address failed\n"); + netdev_err(netdev, "get mac address failed\n"); goto err_eeprom; } memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - dev_dbg(&pdev->dev, "mac address : %pM\n", adapter->hw.mac_addr); + netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr); INIT_WORK(&adapter->reset_task, atl1e_reset_task); INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task); err = register_netdev(netdev); if (err) { - dev_err(&pdev->dev, "register netdevice failed\n"); + netdev_err(netdev, "register netdevice failed\n"); goto err_register; } @@ -2485,8 +2468,8 @@ static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) struct atl1e_adapter *adapter = netdev_priv(netdev); if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, - "ATL1e: Cannot re-enable PCI device after reset.\n"); + netdev_err(adapter->netdev, + "Cannot re-enable PCI device after reset\n"); return PCI_ERS_RESULT_DISCONNECT; } pci_set_master(pdev); @@ -2514,8 +2497,8 @@ static void atl1e_io_resume(struct pci_dev *pdev) if (netif_running(netdev)) { if (atl1e_up(adapter)) { - dev_err(&pdev->dev, - "ATL1e: can't bring device back up after reset\n"); + netdev_err(adapter->netdev, + "can't bring device back up after reset\n"); return; } } diff --git a/drivers/net/atl1e/atl1e_param.c b/drivers/net/atl1e/atl1e_param.c index b3be59fd3fb5..0ce60b6e7ef0 100644 --- a/drivers/net/atl1e/atl1e_param.c +++ b/drivers/net/atl1e/atl1e_param.c @@ -116,7 +116,7 @@ struct atl1e_option { } arg; }; -static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, struct pci_dev *pdev) +static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, struct atl1e_adapter *adapter) { if (*value == OPTION_UNSET) { *value = opt->def; @@ -127,16 +127,19 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, case enable_option: switch (*value) { case OPTION_ENABLED: - dev_info(&pdev->dev, "%s Enabled\n", opt->name); + netdev_info(adapter->netdev, + "%s Enabled\n", opt->name); return 0; case OPTION_DISABLED: - dev_info(&pdev->dev, "%s Disabled\n", opt->name); + netdev_info(adapter->netdev, + "%s Disabled\n", opt->name); return 0; } break; case range_option: if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { - dev_info(&pdev->dev, "%s set to %i\n", opt->name, *value); + netdev_info(adapter->netdev, "%s set to %i\n", + opt->name, *value); return 0; } break; @@ -148,8 +151,8 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, ent = &opt->arg.l.p[i]; if (*value == ent->i) { if (ent->str[0] != '\0') - dev_info(&pdev->dev, "%s\n", - ent->str); + netdev_info(adapter->netdev, + "%s\n", ent->str); return 0; } } @@ -159,8 +162,8 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, BUG(); } - dev_info(&pdev->dev, "Invalid %s specified (%i) %s\n", - opt->name, *value, opt->err); + netdev_info(adapter->netdev, "Invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); *value = opt->def; return -1; } @@ -176,11 +179,13 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, */ void __devinit atl1e_check_options(struct atl1e_adapter *adapter) { - struct pci_dev *pdev = adapter->pdev; int bd = adapter->bd_number; + if (bd >= ATL1E_MAX_NIC) { - dev_notice(&pdev->dev, "no configuration for board #%i\n", bd); - dev_notice(&pdev->dev, "Using defaults for all values\n"); + netdev_notice(adapter->netdev, + "no configuration for board #%i\n", bd); + netdev_notice(adapter->netdev, + "Using defaults for all values\n"); } { /* Transmit Ring Size */ @@ -196,7 +201,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter) int val; if (num_tx_desc_cnt > bd) { val = tx_desc_cnt[bd]; - atl1e_validate_option(&val, &opt, pdev); + atl1e_validate_option(&val, &opt, adapter); adapter->tx_ring.count = (u16) val & 0xFFFC; } else adapter->tx_ring.count = (u16)opt.def; @@ -215,7 +220,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter) int val; if (num_rx_mem_size > bd) { val = rx_mem_size[bd]; - atl1e_validate_option(&val, &opt, pdev); + atl1e_validate_option(&val, &opt, adapter); adapter->rx_ring.page_size = (u32)val * 1024; } else { adapter->rx_ring.page_size = (u32)opt.def * 1024; @@ -235,7 +240,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter) int val; if (num_int_mod_timer > bd) { val = int_mod_timer[bd]; - atl1e_validate_option(&val, &opt, pdev); + atl1e_validate_option(&val, &opt, adapter); adapter->hw.imt = (u16) val; } else adapter->hw.imt = (u16)(opt.def); @@ -254,7 +259,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter) int val; if (num_media_type > bd) { val = media_type[bd]; - atl1e_validate_option(&val, &opt, pdev); + atl1e_validate_option(&val, &opt, adapter); adapter->hw.media_type = (u16) val; } else adapter->hw.media_type = (u16)(opt.def); -- GitLab From b3d95c5c93d4b57eaea0ad3f582b08a6b5fb3eb1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:49 +0000 Subject: [PATCH 1985/3892] include/linux/netdevice.h: Add netif_printk helpers Add macros to test a private structure for msg_enable bits and the netif_msg_##bit to test and call netdev_printk if set Simplifies logic in callers and adds message logging consistency Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/netdevice.h | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a51228ac9331..1412dde16d00 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2165,6 +2165,59 @@ do { \ #define netdev_WARN(dev, format, args...) \ WARN(1, "netdevice: %s\n" format, netdev_name(dev), ##args); +/* netif printk helpers, similar to netdev_printk */ + +#define netif_printk(priv, type, level, dev, fmt, args...) \ +do { \ + if (netif_msg_##type(priv)) \ + netdev_printk(level, (dev), fmt, ##args); \ +} while (0) + +#define netif_emerg(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_EMERG, dev, fmt, ##args) +#define netif_alert(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_ALERT, dev, fmt, ##args) +#define netif_crit(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_CRIT, dev, fmt, ##args) +#define netif_err(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_ERR, dev, fmt, ##args) +#define netif_warn(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_WARNING, dev, fmt, ##args) +#define netif_notice(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_NOTICE, dev, fmt, ##args) +#define netif_info(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_INFO, (dev), fmt, ##args) + +#if defined(DEBUG) +#define netif_dbg(priv, type, dev, format, args...) \ + netif_printk(priv, type, KERN_DEBUG, dev, format, ##args) +#elif defined(CONFIG_DYNAMIC_DEBUG) +#define netif_dbg(priv, type, netdev, format, args...) \ +do { \ + if (netif_msg_##type(priv)) \ + dynamic_dev_dbg((netdev)->dev.parent, \ + "%s: " format, \ + netdev_name(netdev), ##args); \ +} while (0) +#else +#define netif_dbg(priv, type, dev, format, args...) \ +({ \ + if (0) \ + netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif + +#if defined(VERBOSE_DEBUG) +#define netif_vdbg netdev_dbg +#else +#define netif_vdbg(priv, type, dev, format, args...) \ +({ \ + if (0) \ + netif_printk(KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif #endif /* __KERNEL__ */ -- GitLab From bf82c189a92f06967cf790d3ab0fc9827a9d00ff Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:50 +0000 Subject: [PATCH 1986/3892] drivers/net/r8196.c: Use netif_printk macros Simplify the logic a bit, make the message logs a bit more consistent. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/r8169.c | 136 ++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 88 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 85c635f354b5..616ae5aa66aa 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -744,12 +744,10 @@ static void rtl8169_check_link_status(struct net_device *dev, spin_lock_irqsave(&tp->lock, flags); if (tp->link_ok(ioaddr)) { netif_carrier_on(dev); - if (netif_msg_ifup(tp)) - printk(KERN_INFO PFX "%s: link up\n", dev->name); + netif_info(tp, ifup, dev, "link up\n"); } else { - if (netif_msg_ifdown(tp)) - printk(KERN_INFO PFX "%s: link down\n", dev->name); netif_carrier_off(dev); + netif_info(tp, ifdown, dev, "link down\n"); } spin_unlock_irqrestore(&tp->lock, flags); } @@ -862,11 +860,8 @@ static int rtl8169_set_speed_tbi(struct net_device *dev, } else if (autoneg == AUTONEG_ENABLE) RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); else { - if (netif_msg_link(tp)) { - printk(KERN_WARNING "%s: " - "incorrect speed setting refused in TBI mode\n", - dev->name); - } + netif_warn(tp, link, dev, + "incorrect speed setting refused in TBI mode\n"); ret = -EOPNOTSUPP; } @@ -901,9 +896,9 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, (tp->mac_version != RTL_GIGA_MAC_VER_15) && (tp->mac_version != RTL_GIGA_MAC_VER_16)) { giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else if (netif_msg_link(tp)) { - printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", - dev->name); + } else { + netif_info(tp, link, dev, + "PHY does not support 1000Mbps\n"); } bmcr = BMCR_ANENABLE | BMCR_ANRESTART; @@ -2705,8 +2700,7 @@ static void rtl8169_phy_timer(unsigned long __opaque) if (tp->link_ok(ioaddr)) goto out_unlock; - if (netif_msg_link(tp)) - printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name); + netif_warn(tp, link, dev, "PHY reset until link up\n"); tp->phy_reset_enable(ioaddr); @@ -2776,8 +2770,7 @@ static void rtl8169_phy_reset(struct net_device *dev, return; msleep(1); } - if (netif_msg_link(tp)) - printk(KERN_ERR "%s: PHY reset failed.\n", dev->name); + netif_err(tp, link, dev, "PHY reset failed\n"); } static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) @@ -2811,8 +2804,8 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) */ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL); - if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp)) - printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); + if (RTL_R8(PHYstatus) & TBI_Enable) + netif_info(tp, link, dev, "TBI auto-negotiating\n"); } static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) @@ -3012,8 +3005,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pci_enable_device(pdev); if (rc < 0) { - if (netif_msg_probe(tp)) - dev_err(&pdev->dev, "enable failure\n"); + netif_err(tp, probe, dev, "enable failure\n"); goto err_out_free_dev_1; } @@ -3023,29 +3015,24 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* make sure PCI base addr 1 is MMIO */ if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) { - if (netif_msg_probe(tp)) { - dev_err(&pdev->dev, - "region #%d not an MMIO resource, aborting\n", - region); - } + netif_err(tp, probe, dev, + "region #%d not an MMIO resource, aborting\n", + region); rc = -ENODEV; goto err_out_mwi_3; } /* check for weird/broken PCI region reporting */ if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) { - if (netif_msg_probe(tp)) { - dev_err(&pdev->dev, - "Invalid PCI region size(s), aborting\n"); - } + netif_err(tp, probe, dev, + "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; goto err_out_mwi_3; } rc = pci_request_regions(pdev, MODULENAME); if (rc < 0) { - if (netif_msg_probe(tp)) - dev_err(&pdev->dev, "could not request regions.\n"); + netif_err(tp, probe, dev, "could not request regions\n"); goto err_out_mwi_3; } @@ -3058,10 +3045,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc < 0) { - if (netif_msg_probe(tp)) { - dev_err(&pdev->dev, - "DMA configuration failed.\n"); - } + netif_err(tp, probe, dev, "DMA configuration failed\n"); goto err_out_free_res_4; } } @@ -3069,15 +3053,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* ioremap MMIO region */ ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE); if (!ioaddr) { - if (netif_msg_probe(tp)) - dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); + netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res_4; } tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (!tp->pcie_cap && netif_msg_probe(tp)) - dev_info(&pdev->dev, "no PCI Express capability\n"); + if (!tp->pcie_cap) + netif_info(tp, probe, dev, "no PCI Express capability\n"); RTL_W16(IntrMask, 0x0000); @@ -3100,10 +3083,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Use appropriate default if unknown */ if (tp->mac_version == RTL_GIGA_MAC_NONE) { - if (netif_msg_probe(tp)) { - dev_notice(&pdev->dev, - "unknown MAC, using family default\n"); - } + netif_notice(tp, probe, dev, + "unknown MAC, using family default\n"); tp->mac_version = cfg->default_ver; } @@ -3185,14 +3166,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - if (netif_msg_probe(tp)) { - u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff; - - printk(KERN_INFO "%s: %s at 0x%lx, %pM, XID %08x IRQ %d\n", - dev->name, - rtl_chip_info[tp->chipset].name, - dev->base_addr, dev->dev_addr, xid, dev->irq); - } + netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n", + rtl_chip_info[tp->chipset].name, + dev->base_addr, dev->dev_addr, + (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); rtl8169_init_phy(dev, tp); @@ -4131,10 +4108,10 @@ static void rtl8169_reinit_task(struct work_struct *work) ret = rtl8169_open(dev); if (unlikely(ret < 0)) { - if (net_ratelimit() && netif_msg_drv(tp)) { - printk(KERN_ERR PFX "%s: reinit failure (status = %d)." - " Rescheduling.\n", dev->name, ret); - } + if (net_ratelimit()) + netif_err(tp, drv, dev, + "reinit failure (status = %d). Rescheduling\n", + ret); rtl8169_schedule_work(dev, rtl8169_reinit_task); } @@ -4164,10 +4141,8 @@ static void rtl8169_reset_task(struct work_struct *work) netif_wake_queue(dev); rtl8169_check_link_status(dev, tp, tp->mmio_addr); } else { - if (net_ratelimit() && netif_msg_intr(tp)) { - printk(KERN_EMERG PFX "%s: Rx buffers shortage\n", - dev->name); - } + if (net_ratelimit()) + netif_emerg(tp, intr, dev, "Rx buffers shortage\n"); rtl8169_schedule_work(dev, rtl8169_reset_task); } @@ -4255,11 +4230,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 opts1; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { - if (netif_msg_drv(tp)) { - printk(KERN_ERR - "%s: BUG! Tx Ring full when queue awake!\n", - dev->name); - } + netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); goto err_stop; } @@ -4321,11 +4292,8 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); pci_read_config_word(pdev, PCI_STATUS, &pci_status); - if (netif_msg_intr(tp)) { - printk(KERN_ERR - "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n", - dev->name, pci_cmd, pci_status); - } + netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n", + pci_cmd, pci_status); /* * The recovery sequence below admits a very elaborated explanation: @@ -4349,8 +4317,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) /* The infamous DAC f*ckup only happens at boot time */ if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) { - if (netif_msg_intr(tp)) - printk(KERN_INFO "%s: disabling PCI DAC.\n", dev->name); + netif_info(tp, intr, dev, "disabling PCI DAC\n"); tp->cp_cmd &= ~PCIDAC; RTL_W16(CPlusCmd, tp->cp_cmd); dev->features &= ~NETIF_F_HIGHDMA; @@ -4477,11 +4444,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev, if (status & DescOwn) break; if (unlikely(status & RxRES)) { - if (netif_msg_rx_err(tp)) { - printk(KERN_INFO - "%s: Rx ERROR. status = %08x\n", - dev->name, status); - } + netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n", + status); dev->stats.rx_errors++; if (status & (RxRWT | RxRUNT)) dev->stats.rx_length_errors++; @@ -4544,8 +4508,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev, tp->cur_rx = cur_rx; delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); - if (!delta && count && netif_msg_intr(tp)) - printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + if (!delta && count) + netif_info(tp, intr, dev, "no Rx buffer allocated\n"); tp->dirty_rx += delta; /* @@ -4555,8 +4519,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev, * after refill ? * - how do others driver handle this condition (Uh oh...). */ - if ((tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) && netif_msg_intr(tp)) - printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + netif_emerg(tp, intr, dev, "Rx buffers exhausted\n"); return count; } @@ -4611,10 +4575,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) if (likely(napi_schedule_prep(&tp->napi))) __napi_schedule(&tp->napi); - else if (netif_msg_intr(tp)) { - printk(KERN_INFO "%s: interrupt %04x in poll\n", - dev->name, status); - } + else + netif_info(tp, intr, dev, + "interrupt %04x in poll\n", status); } /* We only get a new MSI interrupt when all active irq @@ -4750,10 +4713,7 @@ static void rtl_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ - if (netif_msg_link(tp)) { - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", - dev->name); - } + netif_notice(tp, link, dev, "Promiscuous mode enabled\n"); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; -- GitLab From f8502ce4f986a8fd486302980285b5e786b8dabe Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:51 +0000 Subject: [PATCH 1987/3892] drivers/net/jme: Use netif_printk helpers Convert uses of msg_ to netif_( Remove msg_ macros Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/jme.c | 54 +++++++++++++++++++++++------------------------ drivers/net/jme.h | 41 ++++++----------------------------- 2 files changed, 34 insertions(+), 61 deletions(-) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index d44c39dfbef1..558b6a0b15fc 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -288,7 +288,7 @@ jme_set_rx_pcc(struct jme_adapter *jme, int p) wmb(); if (!(test_bit(JME_FLAG_POLL, &jme->flags))) - msg_rx_status(jme, "Switched to PCC_P%d\n", p); + netif_info(jme, rx_status, jme->dev, "Switched to PCC_P%d\n", p); } static void @@ -483,13 +483,13 @@ jme_check_link(struct net_device *netdev, int testonly) strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ? "MDI-X" : "MDI"); - msg_link(jme, "Link is up at %s.\n", linkmsg); + netif_info(jme, link, jme->dev, "Link is up at %s.\n", linkmsg); netif_carrier_on(netdev); } else { if (testonly) goto out; - msg_link(jme, "Link is down.\n"); + netif_info(jme, link, jme->dev, "Link is down.\n"); jme->phylink = 0; netif_carrier_off(netdev); } @@ -883,20 +883,20 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS)) == RXWBFLAG_TCPON)) { if (flags & RXWBFLAG_IPV4) - msg_rx_err(jme, "TCP Checksum error\n"); + netif_err(jme, rx_err, jme->dev, "TCP Checksum error\n"); return false; } if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) == RXWBFLAG_UDPON)) { if (flags & RXWBFLAG_IPV4) - msg_rx_err(jme, "UDP Checksum error.\n"); + netif_err(jme, rx_err, jme->dev, "UDP Checksum error.\n"); return false; } if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS)) == RXWBFLAG_IPV4)) { - msg_rx_err(jme, "IPv4 Checksum error.\n"); + netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error.\n"); return false; } @@ -1186,9 +1186,9 @@ jme_link_change_tasklet(unsigned long arg) while (!atomic_dec_and_test(&jme->link_changing)) { atomic_inc(&jme->link_changing); - msg_intr(jme, "Get link change lock failed.\n"); + netif_info(jme, intr, jme->dev, "Get link change lock failed.\n"); while (atomic_read(&jme->link_changing) != 1) - msg_intr(jme, "Waiting link change lock.\n"); + netif_info(jme, intr, jme->dev, "Waiting link change lock.\n"); } if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu) @@ -1305,7 +1305,7 @@ jme_rx_empty_tasklet(unsigned long arg) if (unlikely(!netif_carrier_ok(jme->dev))) return; - msg_rx_status(jme, "RX Queue Full!\n"); + netif_info(jme, rx_status, jme->dev, "RX Queue Full!\n"); jme_rx_clean_tasklet(arg); @@ -1325,7 +1325,7 @@ jme_wake_queue_if_stopped(struct jme_adapter *jme) smp_wmb(); if (unlikely(netif_queue_stopped(jme->dev) && atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) { - msg_tx_done(jme, "TX Queue Waked.\n"); + netif_info(jme, tx_done, jme->dev, "TX Queue Waked.\n"); netif_wake_queue(jme->dev); } @@ -1835,7 +1835,7 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags) *flags |= TXFLAG_UDPCS; break; default: - msg_tx_err(jme, "Error upper layer protocol.\n"); + netif_err(jme, tx_err, jme->dev, "Error upper layer protocol.\n"); break; } } @@ -1910,12 +1910,12 @@ jme_stop_queue_if_full(struct jme_adapter *jme) smp_wmb(); if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) { netif_stop_queue(jme->dev); - msg_tx_queued(jme, "TX Queue Paused.\n"); + netif_info(jme, tx_queued, jme->dev, "TX Queue Paused.\n"); smp_wmb(); if (atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold)) { netif_wake_queue(jme->dev); - msg_tx_queued(jme, "TX Queue Fast Waked.\n"); + netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked.\n"); } } @@ -1923,7 +1923,7 @@ jme_stop_queue_if_full(struct jme_adapter *jme) (jiffies - txbi->start_xmit) >= TX_TIMEOUT && txbi->skb)) { netif_stop_queue(jme->dev); - msg_tx_queued(jme, "TX Queue Stopped %d@%lu.\n", idx, jiffies); + netif_info(jme, tx_queued, jme->dev, "TX Queue Stopped %d@%lu.\n", idx, jiffies); } } @@ -1946,7 +1946,7 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (unlikely(idx < 0)) { netif_stop_queue(netdev); - msg_tx_err(jme, "BUG! Tx ring full when queue awake!\n"); + netif_err(jme, tx_err, jme->dev, "BUG! Tx ring full when queue awake!\n"); return NETDEV_TX_BUSY; } @@ -2473,7 +2473,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr) val = jread32(jme, JME_SMBCSR); } if (!to) { - msg_hw(jme, "SMB Bus Busy.\n"); + netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n"); return 0xFF; } @@ -2489,7 +2489,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr) val = jread32(jme, JME_SMBINTF); } if (!to) { - msg_hw(jme, "SMB Bus Busy.\n"); + netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n"); return 0xFF; } @@ -2509,7 +2509,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data) val = jread32(jme, JME_SMBCSR); } if (!to) { - msg_hw(jme, "SMB Bus Busy.\n"); + netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n"); return; } @@ -2526,7 +2526,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data) val = jread32(jme, JME_SMBINTF); } if (!to) { - msg_hw(jme, "SMB Bus Busy.\n"); + netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n"); return; } @@ -2876,14 +2876,14 @@ jme_init_one(struct pci_dev *pdev, goto err_out_unmap; } - msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n", - (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ? - "JMC250 Gigabit Ethernet" : - (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ? - "JMC260 Fast Ethernet" : "Unknown", - (jme->fpgaver != 0) ? " (FPGA)" : "", - (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, - jme->rev, netdev->dev_addr); + netif_info(jme, probe, jme->dev, "%s%s ver:%x rev:%x macaddr:%pM\n", + (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ? + "JMC250 Gigabit Ethernet" : + (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ? + "JMC260 Fast Ethernet" : "Unknown", + (jme->fpgaver != 0) ? " (FPGA)" : "", + (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, + jme->rev, netdev->dev_addr); return 0; diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 251abed3817e..c19db9146a2f 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -45,43 +45,16 @@ printk(KERN_ERR PFX fmt, ## args) #ifdef TX_DEBUG -#define tx_dbg(priv, fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ## args) +#define tx_dbg(priv, fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args) #else -#define tx_dbg(priv, fmt, args...) +#define tx_dbg(priv, fmt, args...) \ +do { \ + if (0) \ + printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args); \ +} while (0) #endif -#define jme_msg(msglvl, type, priv, fmt, args...) \ - if (netif_msg_##type(priv)) \ - printk(msglvl "%s: " fmt, (priv)->dev->name, ## args) - -#define msg_probe(priv, fmt, args...) \ - jme_msg(KERN_INFO, probe, priv, fmt, ## args) - -#define msg_link(priv, fmt, args...) \ - jme_msg(KERN_INFO, link, priv, fmt, ## args) - -#define msg_intr(priv, fmt, args...) \ - jme_msg(KERN_INFO, intr, priv, fmt, ## args) - -#define msg_rx_err(priv, fmt, args...) \ - jme_msg(KERN_ERR, rx_err, priv, fmt, ## args) - -#define msg_rx_status(priv, fmt, args...) \ - jme_msg(KERN_INFO, rx_status, priv, fmt, ## args) - -#define msg_tx_err(priv, fmt, args...) \ - jme_msg(KERN_ERR, tx_err, priv, fmt, ## args) - -#define msg_tx_done(priv, fmt, args...) \ - jme_msg(KERN_INFO, tx_done, priv, fmt, ## args) - -#define msg_tx_queued(priv, fmt, args...) \ - jme_msg(KERN_INFO, tx_queued, priv, fmt, ## args) - -#define msg_hw(priv, fmt, args...) \ - jme_msg(KERN_ERR, hw, priv, fmt, ## args) - /* * Extra PCI Configuration space interface */ -- GitLab From ae9540f75d5a69e7604cc5391cc0726b3aa82ff6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:52 +0000 Subject: [PATCH 1988/3892] drivers/net/qlge: Use netif_printk helpers Convert QPRINTK macros to netif_ equivalents. Expands and standardizes the logging message output. Removes __func__ from most logging messages. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 8 - drivers/net/qlge/qlge_dbg.c | 58 +-- drivers/net/qlge/qlge_ethtool.c | 49 +- drivers/net/qlge/qlge_main.c | 841 +++++++++++++++++--------------- drivers/net/qlge/qlge_mpi.c | 183 ++++--- 5 files changed, 580 insertions(+), 559 deletions(-) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index ebfd17776b53..57d135e3bfaf 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -19,14 +19,6 @@ #define DRV_VERSION "v1.00.00.23.00.00-01" #define PFX "qlge: " -#define QPRINTK(qdev, nlevel, klevel, fmt, args...) \ - do { \ - if (!((qdev)->msg_enable & NETIF_MSG_##nlevel)) \ - ; \ - else \ - dev_printk(KERN_##klevel, &((qdev)->pdev->dev), \ - "%s: " fmt, __func__, ##args); \ - } while (0) #define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 57df835147eb..ff8550d2ca82 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -443,8 +443,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf) status = ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed read of mac index register.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed read of mac index register.\n"); goto err; } *buf++ = value[0]; /* lower MAC address */ @@ -455,8 +455,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf) status = ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_MULTI_MAC, i, value); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed read of mac index register.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed read of mac index register.\n"); goto err; } *buf++ = value[0]; /* lower Mcast address */ @@ -479,8 +479,8 @@ static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf) for (i = 0; i < 16; i++) { status = ql_get_routing_reg(qdev, i, &value); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed read of routing index register.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed read of routing index register.\n"); goto err; } else { *buf++ = value; @@ -736,8 +736,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) int i; if (!mpi_coredump) { - QPRINTK(qdev, DRV, ERR, - "No memory available.\n"); + netif_err(qdev, drv, qdev->ndev, "No memory available.\n"); return -ENOMEM; } @@ -749,8 +748,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) status = ql_pause_mpi_risc(qdev); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed RISC pause. Status = 0x%.08x\n", status); + netif_err(qdev, drv, qdev->ndev, + "Failed RISC pause. Status = 0x%.08x\n", status); goto err; } @@ -911,9 +910,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) status = ql_get_serdes_regs(qdev, mpi_coredump); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed Dump of Serdes Registers. Status = 0x%.08x\n", - status); + netif_err(qdev, drv, qdev->ndev, + "Failed Dump of Serdes Registers. Status = 0x%.08x\n", + status); goto err; } @@ -1177,16 +1176,16 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* clear the pause */ status = ql_unpause_mpi_risc(qdev); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed RISC unpause. Status = 0x%.08x\n", status); + netif_err(qdev, drv, qdev->ndev, + "Failed RISC unpause. Status = 0x%.08x\n", status); goto err; } /* Reset the RISC so we can dump RAM */ status = ql_hard_reset_mpi_risc(qdev); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed RISC reset. Status = 0x%.08x\n", status); + netif_err(qdev, drv, qdev->ndev, + "Failed RISC reset. Status = 0x%.08x\n", status); goto err; } @@ -1198,8 +1197,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0], CODE_RAM_ADDR, CODE_RAM_CNT); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed Dump of CODE RAM. Status = 0x%.08x\n", status); + netif_err(qdev, drv, qdev->ndev, + "Failed Dump of CODE RAM. Status = 0x%.08x\n", + status); goto err; } @@ -1212,8 +1212,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0], MEMC_RAM_ADDR, MEMC_RAM_CNT); if (status) { - QPRINTK(qdev, DRV, ERR, - "Failed Dump of MEMC RAM. Status = 0x%.08x\n", status); + netif_err(qdev, drv, qdev->ndev, + "Failed Dump of MEMC RAM. Status = 0x%.08x\n", + status); goto err; } err: @@ -1225,21 +1226,19 @@ err: static void ql_get_core_dump(struct ql_adapter *qdev) { if (!ql_own_firmware(qdev)) { - QPRINTK(qdev, DRV, ERR, "%s: Don't own firmware!\n", - qdev->ndev->name); + netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n"); return; } if (!netif_running(qdev->ndev)) { - QPRINTK(qdev, IFUP, ERR, - "Force Coredump can only be done from interface " - "that is up.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Force Coredump can only be done from interface that is up.\n"); return; } if (ql_mb_sys_err(qdev)) { - QPRINTK(qdev, IFUP, ERR, - "Fail force coredump with ql_mb_sys_err().\n"); + netif_err(qdev, ifup, qdev->ndev, + "Fail force coredump with ql_mb_sys_err().\n"); return; } } @@ -1334,7 +1333,8 @@ void ql_mpi_core_to_log(struct work_struct *work) count = sizeof(struct ql_mpi_coredump) / sizeof(u32); tmp = (u32 *)qdev->mpi_coredump; - QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n"); + netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev, + "Core is dumping to log file!\n"); for (i = 0; i < count; i += 8) { printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x " diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 058fa0a48c6f..4f26afeb0f38 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -67,8 +67,8 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb), CFG_LCQ, rx_ring->cq_id); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to load CQICB.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to load CQICB.\n"); goto exit; } } @@ -89,8 +89,8 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb), CFG_LCQ, rx_ring->cq_id); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to load CQICB.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to load CQICB.\n"); goto exit; } } @@ -107,8 +107,8 @@ static void ql_update_stats(struct ql_adapter *qdev) spin_lock(&qdev->stats_lock); if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) { - QPRINTK(qdev, DRV, ERR, - "Couldn't get xgmac sem.\n"); + netif_err(qdev, drv, qdev->ndev, + "Couldn't get xgmac sem.\n"); goto quit; } /* @@ -116,8 +116,9 @@ static void ql_update_stats(struct ql_adapter *qdev) */ for (i = 0x200; i < 0x280; i += 8) { if (ql_read_xgmac_reg64(qdev, i, &data)) { - QPRINTK(qdev, DRV, ERR, - "Error reading status register 0x%.04x.\n", i); + netif_err(qdev, drv, qdev->ndev, + "Error reading status register 0x%.04x.\n", + i); goto end; } else *iter = data; @@ -129,8 +130,9 @@ static void ql_update_stats(struct ql_adapter *qdev) */ for (i = 0x300; i < 0x3d0; i += 8) { if (ql_read_xgmac_reg64(qdev, i, &data)) { - QPRINTK(qdev, DRV, ERR, - "Error reading status register 0x%.04x.\n", i); + netif_err(qdev, drv, qdev->ndev, + "Error reading status register 0x%.04x.\n", + i); goto end; } else *iter = data; @@ -142,8 +144,9 @@ static void ql_update_stats(struct ql_adapter *qdev) */ for (i = 0x500; i < 0x540; i += 8) { if (ql_read_xgmac_reg64(qdev, i, &data)) { - QPRINTK(qdev, DRV, ERR, - "Error reading status register 0x%.04x.\n", i); + netif_err(qdev, drv, qdev->ndev, + "Error reading status register 0x%.04x.\n", + i); goto end; } else *iter = data; @@ -155,8 +158,9 @@ static void ql_update_stats(struct ql_adapter *qdev) */ for (i = 0x568; i < 0x5a8; i += 8) { if (ql_read_xgmac_reg64(qdev, i, &data)) { - QPRINTK(qdev, DRV, ERR, - "Error reading status register 0x%.04x.\n", i); + netif_err(qdev, drv, qdev->ndev, + "Error reading status register 0x%.04x.\n", + i); goto end; } else *iter = data; @@ -167,8 +171,8 @@ static void ql_update_stats(struct ql_adapter *qdev) * Get RX NIC FIFO DROP statistics. */ if (ql_read_xgmac_reg64(qdev, 0x5b8, &data)) { - QPRINTK(qdev, DRV, ERR, - "Error reading status register 0x%.04x.\n", i); + netif_err(qdev, drv, qdev->ndev, + "Error reading status register 0x%.04x.\n", i); goto end; } else *iter = data; @@ -396,14 +400,13 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) return -EINVAL; qdev->wol = wol->wolopts; - QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n", - qdev->wol, ndev->name); + netif_info(qdev, drv, qdev->ndev, "Set wol option 0x%x\n", qdev->wol); if (!qdev->wol) { u32 wol = 0; status = ql_mb_wol_mode(qdev, wol); - QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n", - (status == 0) ? "cleared sucessfully" : "clear failed", - wol, qdev->ndev->name); + netif_err(qdev, drv, qdev->ndev, "WOL %s (wol code 0x%x)\n", + status == 0 ? "cleared sucessfully" : "clear failed", + wol); } return 0; @@ -534,8 +537,8 @@ static void ql_self_test(struct net_device *ndev, } clear_bit(QL_SELFTEST, &qdev->flags); } else { - QPRINTK(qdev, DRV, ERR, - "%s: is down, Loopback test will fail.\n", ndev->name); + netif_err(qdev, drv, qdev->ndev, + "is down, Loopback test will fail.\n"); eth_test->flags |= ETH_TEST_FL_FAILED; } } diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index dd3e0f1b2965..2c052caee884 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -128,7 +128,7 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask) sem_bits = SEM_SET << SEM_PROC_REG_SHIFT; break; default: - QPRINTK(qdev, PROBE, ALERT, "Bad Semaphore mask!.\n"); + netif_alert(qdev, probe, qdev->ndev, "bad Semaphore mask!.\n"); return -EINVAL; } @@ -168,17 +168,17 @@ int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit) /* check for errors */ if (temp & err_bit) { - QPRINTK(qdev, PROBE, ALERT, - "register 0x%.08x access error, value = 0x%.08x!.\n", - reg, temp); + netif_alert(qdev, probe, qdev->ndev, + "register 0x%.08x access error, value = 0x%.08x!.\n", + reg, temp); return -EIO; } else if (temp & bit) return 0; udelay(UDELAY_DELAY); count--; } - QPRINTK(qdev, PROBE, ALERT, - "Timed out waiting for reg %x to come ready.\n", reg); + netif_alert(qdev, probe, qdev->ndev, + "Timed out waiting for reg %x to come ready.\n", reg); return -ETIMEDOUT; } @@ -221,7 +221,7 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, map = pci_map_single(qdev->pdev, ptr, size, direction); if (pci_dma_mapping_error(qdev->pdev, map)) { - QPRINTK(qdev, IFUP, ERR, "Couldn't map DMA area.\n"); + netif_err(qdev, ifup, qdev->ndev, "Couldn't map DMA area.\n"); return -ENOMEM; } @@ -231,8 +231,8 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, status = ql_wait_cfg(qdev, bit); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Timed out waiting for CFG to come ready.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Timed out waiting for CFG to come ready.\n"); goto exit; } @@ -313,8 +313,8 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, case MAC_ADDR_TYPE_VLAN: case MAC_ADDR_TYPE_MULTI_FLTR: default: - QPRINTK(qdev, IFUP, CRIT, - "Address type %d not yet supported.\n", type); + netif_crit(qdev, ifup, qdev->ndev, + "Address type %d not yet supported.\n", type); status = -EPERM; } exit: @@ -371,12 +371,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | (addr[5]); - QPRINTK(qdev, IFUP, DEBUG, - "Adding %s address %pM" - " at index %d in the CAM.\n", - ((type == - MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" : - "UNICAST"), addr, index); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Adding %s address %pM at index %d in the CAM.\n", + type == MAC_ADDR_TYPE_MULTI_MAC ? + "MULTICAST" : "UNICAST", + addr, index); status = ql_wait_reg_rdy(qdev, @@ -426,9 +425,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, * addressing. It's either MAC_ADDR_E on or off. * That's bit-27 we're talking about. */ - QPRINTK(qdev, IFUP, INFO, "%s VLAN ID %d %s the CAM.\n", - (enable_bit ? "Adding" : "Removing"), - index, (enable_bit ? "to" : "from")); + netif_info(qdev, ifup, qdev->ndev, + "%s VLAN ID %d %s the CAM.\n", + enable_bit ? "Adding" : "Removing", + index, + enable_bit ? "to" : "from"); status = ql_wait_reg_rdy(qdev, @@ -443,8 +444,8 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, } case MAC_ADDR_TYPE_MULTI_FLTR: default: - QPRINTK(qdev, IFUP, CRIT, - "Address type %d not yet supported.\n", type); + netif_crit(qdev, ifup, qdev->ndev, + "Address type %d not yet supported.\n", type); status = -EPERM; } exit: @@ -463,14 +464,13 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set) if (set) { addr = &qdev->ndev->dev_addr[0]; - QPRINTK(qdev, IFUP, DEBUG, - "Set Mac addr %pM\n", addr); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Set Mac addr %pM\n", addr); } else { memset(zero_mac_addr, 0, ETH_ALEN); addr = &zero_mac_addr[0]; - QPRINTK(qdev, IFUP, DEBUG, - "Clearing MAC address on %s\n", - qdev->ndev->name); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Clearing MAC address\n"); } status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); if (status) @@ -479,23 +479,21 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set) MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); if (status) - QPRINTK(qdev, IFUP, ERR, "Failed to init mac " - "address.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init mac address.\n"); return status; } void ql_link_on(struct ql_adapter *qdev) { - QPRINTK(qdev, LINK, ERR, "%s: Link is up.\n", - qdev->ndev->name); + netif_err(qdev, link, qdev->ndev, "Link is up.\n"); netif_carrier_on(qdev->ndev); ql_set_mac_addr(qdev, 1); } void ql_link_off(struct ql_adapter *qdev) { - QPRINTK(qdev, LINK, ERR, "%s: Link is down.\n", - qdev->ndev->name); + netif_err(qdev, link, qdev->ndev, "Link is down.\n"); netif_carrier_off(qdev->ndev); ql_set_mac_addr(qdev, 0); } @@ -532,27 +530,27 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask, int status = -EINVAL; /* Return error if no mask match. */ u32 value = 0; - QPRINTK(qdev, IFUP, DEBUG, - "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n", - (enable ? "Adding" : "Removing"), - ((index == RT_IDX_ALL_ERR_SLOT) ? "MAC ERROR/ALL ERROR" : ""), - ((index == RT_IDX_IP_CSUM_ERR_SLOT) ? "IP CSUM ERROR" : ""), - ((index == - RT_IDX_TCP_UDP_CSUM_ERR_SLOT) ? "TCP/UDP CSUM ERROR" : ""), - ((index == RT_IDX_BCAST_SLOT) ? "BROADCAST" : ""), - ((index == RT_IDX_MCAST_MATCH_SLOT) ? "MULTICAST MATCH" : ""), - ((index == RT_IDX_ALLMULTI_SLOT) ? "ALL MULTICAST MATCH" : ""), - ((index == RT_IDX_UNUSED6_SLOT) ? "UNUSED6" : ""), - ((index == RT_IDX_UNUSED7_SLOT) ? "UNUSED7" : ""), - ((index == RT_IDX_RSS_MATCH_SLOT) ? "RSS ALL/IPV4 MATCH" : ""), - ((index == RT_IDX_RSS_IPV6_SLOT) ? "RSS IPV6" : ""), - ((index == RT_IDX_RSS_TCP4_SLOT) ? "RSS TCP4" : ""), - ((index == RT_IDX_RSS_TCP6_SLOT) ? "RSS TCP6" : ""), - ((index == RT_IDX_CAM_HIT_SLOT) ? "CAM HIT" : ""), - ((index == RT_IDX_UNUSED013) ? "UNUSED13" : ""), - ((index == RT_IDX_UNUSED014) ? "UNUSED14" : ""), - ((index == RT_IDX_PROMISCUOUS_SLOT) ? "PROMISCUOUS" : ""), - (enable ? "to" : "from")); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "%s %s mask %s the routing reg.\n", + enable ? "Adding" : "Removing", + index == RT_IDX_ALL_ERR_SLOT ? "MAC ERROR/ALL ERROR" : + index == RT_IDX_IP_CSUM_ERR_SLOT ? "IP CSUM ERROR" : + index == RT_IDX_TCP_UDP_CSUM_ERR_SLOT ? "TCP/UDP CSUM ERROR" : + index == RT_IDX_BCAST_SLOT ? "BROADCAST" : + index == RT_IDX_MCAST_MATCH_SLOT ? "MULTICAST MATCH" : + index == RT_IDX_ALLMULTI_SLOT ? "ALL MULTICAST MATCH" : + index == RT_IDX_UNUSED6_SLOT ? "UNUSED6" : + index == RT_IDX_UNUSED7_SLOT ? "UNUSED7" : + index == RT_IDX_RSS_MATCH_SLOT ? "RSS ALL/IPV4 MATCH" : + index == RT_IDX_RSS_IPV6_SLOT ? "RSS IPV6" : + index == RT_IDX_RSS_TCP4_SLOT ? "RSS TCP4" : + index == RT_IDX_RSS_TCP6_SLOT ? "RSS TCP6" : + index == RT_IDX_CAM_HIT_SLOT ? "CAM HIT" : + index == RT_IDX_UNUSED013 ? "UNUSED13" : + index == RT_IDX_UNUSED014 ? "UNUSED14" : + index == RT_IDX_PROMISCUOUS_SLOT ? "PROMISCUOUS" : + "(Bad index != RT_IDX)", + enable ? "to" : "from"); switch (mask) { case RT_IDX_CAM_HIT: @@ -612,8 +610,8 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask, break; } default: - QPRINTK(qdev, IFUP, ERR, "Mask type %d not yet supported.\n", - mask); + netif_err(qdev, ifup, qdev->ndev, + "Mask type %d not yet supported.\n", mask); status = -EPERM; goto exit; } @@ -719,7 +717,7 @@ static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str) status = strncmp((char *)&qdev->flash, str, 4); if (status) { - QPRINTK(qdev, IFUP, ERR, "Invalid flash signature.\n"); + netif_err(qdev, ifup, qdev->ndev, "Invalid flash signature.\n"); return status; } @@ -727,8 +725,8 @@ static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str) csum += le16_to_cpu(*flash++); if (csum) - QPRINTK(qdev, IFUP, ERR, - "Invalid flash checksum, csum = 0x%.04x.\n", csum); + netif_err(qdev, ifup, qdev->ndev, + "Invalid flash checksum, csum = 0x%.04x.\n", csum); return csum; } @@ -780,7 +778,8 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) for (i = 0; i < size; i++, p++) { status = ql_read_flash_word(qdev, i+offset, p); if (status) { - QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Error reading flash.\n"); goto exit; } } @@ -789,7 +788,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) sizeof(struct flash_params_8000) / sizeof(u16), "8000"); if (status) { - QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n"); + netif_err(qdev, ifup, qdev->ndev, "Invalid flash.\n"); status = -EINVAL; goto exit; } @@ -807,7 +806,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) qdev->ndev->addr_len); if (!is_valid_ether_addr(mac_addr)) { - QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n"); + netif_err(qdev, ifup, qdev->ndev, "Invalid MAC address.\n"); status = -EINVAL; goto exit; } @@ -841,7 +840,8 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev) for (i = 0; i < size; i++, p++) { status = ql_read_flash_word(qdev, i+offset, p); if (status) { - QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Error reading flash.\n"); goto exit; } @@ -851,7 +851,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev) sizeof(struct flash_params_8012) / sizeof(u16), "8012"); if (status) { - QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n"); + netif_err(qdev, ifup, qdev->ndev, "Invalid flash.\n"); status = -EINVAL; goto exit; } @@ -969,17 +969,17 @@ static int ql_8012_port_initialize(struct ql_adapter *qdev) /* Another function has the semaphore, so * wait for the port init bit to come ready. */ - QPRINTK(qdev, LINK, INFO, - "Another function has the semaphore, so wait for the port init bit to come ready.\n"); + netif_info(qdev, link, qdev->ndev, + "Another function has the semaphore, so wait for the port init bit to come ready.\n"); status = ql_wait_reg_rdy(qdev, STS, qdev->port_init, 0); if (status) { - QPRINTK(qdev, LINK, CRIT, - "Port initialize timed out.\n"); + netif_crit(qdev, link, qdev->ndev, + "Port initialize timed out.\n"); } return status; } - QPRINTK(qdev, LINK, INFO, "Got xgmac semaphore!.\n"); + netif_info(qdev, link, qdev->ndev, "Got xgmac semaphore!.\n"); /* Set the core reset. */ status = ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data); if (status) @@ -1109,8 +1109,8 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring, GFP_ATOMIC, qdev->lbq_buf_order); if (unlikely(!rx_ring->pg_chunk.page)) { - QPRINTK(qdev, DRV, ERR, - "page allocation failed.\n"); + netif_err(qdev, drv, qdev->ndev, + "page allocation failed.\n"); return -ENOMEM; } rx_ring->pg_chunk.offset = 0; @@ -1120,8 +1120,8 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring, if (pci_dma_mapping_error(qdev->pdev, map)) { __free_pages(rx_ring->pg_chunk.page, qdev->lbq_buf_order); - QPRINTK(qdev, DRV, ERR, - "PCI mapping failed.\n"); + netif_err(qdev, drv, qdev->ndev, + "PCI mapping failed.\n"); return -ENOMEM; } rx_ring->pg_chunk.map = map; @@ -1158,15 +1158,15 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) while (rx_ring->lbq_free_cnt > 32) { for (i = 0; i < 16; i++) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "lbq: try cleaning clean_idx = %d.\n", - clean_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "lbq: try cleaning clean_idx = %d.\n", + clean_idx); lbq_desc = &rx_ring->lbq[clean_idx]; if (ql_get_next_chunk(qdev, rx_ring, lbq_desc)) { - QPRINTK(qdev, IFUP, ERR, - "Could not get a page chunk.\n"); - return; - } + netif_err(qdev, ifup, qdev->ndev, + "Could not get a page chunk.\n"); + return; + } map = lbq_desc->p.pg_chunk.map + lbq_desc->p.pg_chunk.offset; @@ -1191,9 +1191,9 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) } if (start_idx != clean_idx) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "lbq: updating prod idx = %d.\n", - rx_ring->lbq_prod_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "lbq: updating prod idx = %d.\n", + rx_ring->lbq_prod_idx); ql_write_db_reg(rx_ring->lbq_prod_idx, rx_ring->lbq_prod_idx_db_reg); } @@ -1211,19 +1211,20 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) while (rx_ring->sbq_free_cnt > 16) { for (i = 0; i < 16; i++) { sbq_desc = &rx_ring->sbq[clean_idx]; - QPRINTK(qdev, RX_STATUS, DEBUG, - "sbq: try cleaning clean_idx = %d.\n", - clean_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "sbq: try cleaning clean_idx = %d.\n", + clean_idx); if (sbq_desc->p.skb == NULL) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "sbq: getting new skb for index %d.\n", - sbq_desc->index); + netif_printk(qdev, rx_status, KERN_DEBUG, + qdev->ndev, + "sbq: getting new skb for index %d.\n", + sbq_desc->index); sbq_desc->p.skb = netdev_alloc_skb(qdev->ndev, SMALL_BUFFER_SIZE); if (sbq_desc->p.skb == NULL) { - QPRINTK(qdev, PROBE, ERR, - "Couldn't get an skb.\n"); + netif_err(qdev, probe, qdev->ndev, + "Couldn't get an skb.\n"); rx_ring->sbq_clean_idx = clean_idx; return; } @@ -1233,7 +1234,8 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->sbq_buf_size, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(qdev->pdev, map)) { - QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "PCI mapping failed.\n"); rx_ring->sbq_clean_idx = clean_idx; dev_kfree_skb_any(sbq_desc->p.skb); sbq_desc->p.skb = NULL; @@ -1257,9 +1259,9 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) } if (start_idx != clean_idx) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "sbq: updating prod idx = %d.\n", - rx_ring->sbq_prod_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "sbq: updating prod idx = %d.\n", + rx_ring->sbq_prod_idx); ql_write_db_reg(rx_ring->sbq_prod_idx, rx_ring->sbq_prod_idx_db_reg); } @@ -1291,8 +1293,9 @@ static void ql_unmap_send(struct ql_adapter *qdev, * then its an OAL. */ if (i == 7) { - QPRINTK(qdev, TX_DONE, DEBUG, - "unmapping OAL area.\n"); + netif_printk(qdev, tx_done, KERN_DEBUG, + qdev->ndev, + "unmapping OAL area.\n"); } pci_unmap_single(qdev->pdev, pci_unmap_addr(&tx_ring_desc->map[i], @@ -1301,8 +1304,8 @@ static void ql_unmap_send(struct ql_adapter *qdev, maplen), PCI_DMA_TODEVICE); } else { - QPRINTK(qdev, TX_DONE, DEBUG, "unmapping frag %d.\n", - i); + netif_printk(qdev, tx_done, KERN_DEBUG, qdev->ndev, + "unmapping frag %d.\n", i); pci_unmap_page(qdev->pdev, pci_unmap_addr(&tx_ring_desc->map[i], mapaddr), @@ -1327,7 +1330,8 @@ static int ql_map_send(struct ql_adapter *qdev, int frag_cnt = skb_shinfo(skb)->nr_frags; if (frag_cnt) { - QPRINTK(qdev, TX_QUEUED, DEBUG, "frag_cnt = %d.\n", frag_cnt); + netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev, + "frag_cnt = %d.\n", frag_cnt); } /* * Map the skb buffer first. @@ -1336,8 +1340,8 @@ static int ql_map_send(struct ql_adapter *qdev, err = pci_dma_mapping_error(qdev->pdev, map); if (err) { - QPRINTK(qdev, TX_QUEUED, ERR, - "PCI mapping failed with error: %d\n", err); + netif_err(qdev, tx_queued, qdev->ndev, + "PCI mapping failed with error: %d\n", err); return NETDEV_TX_BUSY; } @@ -1383,9 +1387,9 @@ static int ql_map_send(struct ql_adapter *qdev, PCI_DMA_TODEVICE); err = pci_dma_mapping_error(qdev->pdev, map); if (err) { - QPRINTK(qdev, TX_QUEUED, ERR, - "PCI mapping outbound address list with error: %d\n", - err); + netif_err(qdev, tx_queued, qdev->ndev, + "PCI mapping outbound address list with error: %d\n", + err); goto map_error; } @@ -1413,9 +1417,9 @@ static int ql_map_send(struct ql_adapter *qdev, err = pci_dma_mapping_error(qdev->pdev, map); if (err) { - QPRINTK(qdev, TX_QUEUED, ERR, - "PCI mapping frags failed with error: %d.\n", - err); + netif_err(qdev, tx_queued, qdev->ndev, + "PCI mapping frags failed with error: %d.\n", + err); goto map_error; } @@ -1460,7 +1464,8 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev, skb = napi_get_frags(napi); if (!skb) { - QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, exiting.\n"); + netif_err(qdev, drv, qdev->ndev, + "Couldn't get an skb, exiting.\n"); rx_ring->rx_dropped++; put_page(lbq_desc->p.pg_chunk.page); return; @@ -1503,8 +1508,8 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, skb = netdev_alloc_skb(ndev, length); if (!skb) { - QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, " - "need to unwind!.\n"); + netif_err(qdev, drv, qdev->ndev, + "Couldn't get an skb, need to unwind!.\n"); rx_ring->rx_dropped++; put_page(lbq_desc->p.pg_chunk.page); return; @@ -1516,8 +1521,8 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, /* Frame error, so drop the packet. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { - QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", - ib_mac_rsp->flags2); + netif_err(qdev, drv, qdev->ndev, + "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2); rx_ring->rx_errors++; goto err_out; } @@ -1526,14 +1531,15 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, * MTU since FCoE uses 2k frames. */ if (skb->len > ndev->mtu + ETH_HLEN) { - QPRINTK(qdev, DRV, ERR, "Segment too small, dropping.\n"); + netif_err(qdev, drv, qdev->ndev, + "Segment too small, dropping.\n"); rx_ring->rx_dropped++; goto err_out; } memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN); - QPRINTK(qdev, RX_STATUS, DEBUG, - "%d bytes of headers and data in large. Chain " - "page to new skb and pull tail.\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", + length); skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page, lbq_desc->p.pg_chunk.offset+ETH_HLEN, length-ETH_HLEN); @@ -1550,8 +1556,8 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "TCP checksum done!\n"); skb->ip_summed = CHECKSUM_UNNECESSARY; } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { @@ -1560,8 +1566,9 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, if (!(iph->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, + qdev->ndev, + "TCP checksum done!\n"); } } } @@ -1600,8 +1607,8 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, /* Allocate new_skb and copy */ new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN); if (new_skb == NULL) { - QPRINTK(qdev, PROBE, ERR, - "No skb available, drop the packet.\n"); + netif_err(qdev, probe, qdev->ndev, + "No skb available, drop the packet.\n"); rx_ring->rx_dropped++; return; } @@ -1611,8 +1618,8 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, /* Frame error, so drop the packet. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { - QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", - ib_mac_rsp->flags2); + netif_err(qdev, drv, qdev->ndev, + "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2); dev_kfree_skb_any(skb); rx_ring->rx_errors++; return; @@ -1637,16 +1644,18 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { - QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_REG ? "Registered" : "", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "%s Multicast.\n", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_HASH ? "Hash" : + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_REG ? "Registered" : + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); } if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) - QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Promiscuous Packet.\n"); rx_ring->rx_packets++; rx_ring->rx_bytes += skb->len; @@ -1660,8 +1669,8 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "TCP checksum done!\n"); skb->ip_summed = CHECKSUM_UNNECESSARY; } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { @@ -1670,8 +1679,9 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, if (!(iph->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, + qdev->ndev, + "TCP checksum done!\n"); } } } @@ -1725,7 +1735,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, */ if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV && ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { - QPRINTK(qdev, RX_STATUS, DEBUG, "Header of %d bytes in small buffer.\n", hdr_len); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Header of %d bytes in small buffer.\n", hdr_len); /* * Headers fit nicely into a small buffer. */ @@ -1744,15 +1755,16 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, * Handle the data buffer(s). */ if (unlikely(!length)) { /* Is there data too? */ - QPRINTK(qdev, RX_STATUS, DEBUG, - "No Data buffer in this packet.\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "No Data buffer in this packet.\n"); return skb; } if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) { if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "Headers in small, data of %d bytes in small, combine them.\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Headers in small, data of %d bytes in small, combine them.\n", + length); /* * Data is less than small buffer size so it's * stuffed in a small buffer. @@ -1778,8 +1790,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, maplen), PCI_DMA_FROMDEVICE); } else { - QPRINTK(qdev, RX_STATUS, DEBUG, - "%d bytes in a single small buffer.\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "%d bytes in a single small buffer.\n", + length); sbq_desc = ql_get_curr_sbuf(rx_ring); skb = sbq_desc->p.skb; ql_realign_skb(skb, length); @@ -1794,18 +1807,18 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, } } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) { if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "Header in small, %d bytes in large. Chain large to small!\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Header in small, %d bytes in large. Chain large to small!\n", + length); /* * The data is in a single large buffer. We * chain it to the header buffer's skb and let * it rip. */ lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); - QPRINTK(qdev, RX_STATUS, DEBUG, - "Chaining page at offset = %d," - "for %d bytes to skb.\n", - lbq_desc->p.pg_chunk.offset, length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Chaining page at offset = %d, for %d bytes to skb.\n", + lbq_desc->p.pg_chunk.offset, length); skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page, lbq_desc->p.pg_chunk.offset, length); @@ -1821,8 +1834,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); skb = netdev_alloc_skb(qdev->ndev, length); if (skb == NULL) { - QPRINTK(qdev, PROBE, DEBUG, - "No skb available, drop the packet.\n"); + netif_printk(qdev, probe, KERN_DEBUG, qdev->ndev, + "No skb available, drop the packet.\n"); return NULL; } pci_unmap_page(qdev->pdev, @@ -1831,8 +1844,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, pci_unmap_len(lbq_desc, maplen), PCI_DMA_FROMDEVICE); skb_reserve(skb, NET_IP_ALIGN); - QPRINTK(qdev, RX_STATUS, DEBUG, - "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", + length); skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page, lbq_desc->p.pg_chunk.offset, @@ -1873,8 +1887,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, * a local buffer and use it to find the * pages to chain. */ - QPRINTK(qdev, RX_STATUS, DEBUG, - "%d bytes of headers & data in chain of large.\n", length); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "%d bytes of headers & data in chain of large.\n", + length); skb = sbq_desc->p.skb; sbq_desc->p.skb = NULL; skb_reserve(skb, NET_IP_ALIGN); @@ -1884,9 +1899,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, size = (length < rx_ring->lbq_buf_size) ? length : rx_ring->lbq_buf_size; - QPRINTK(qdev, RX_STATUS, DEBUG, - "Adding page %d to skb for %d bytes.\n", - i, size); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Adding page %d to skb for %d bytes.\n", + i, size); skb_fill_page_desc(skb, i, lbq_desc->p.pg_chunk.page, lbq_desc->p.pg_chunk.offset, @@ -1916,16 +1931,16 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, skb = ql_build_rx_skb(qdev, rx_ring, ib_mac_rsp); if (unlikely(!skb)) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "No skb available, drop packet.\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "No skb available, drop packet.\n"); rx_ring->rx_dropped++; return; } /* Frame error, so drop the packet. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { - QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", - ib_mac_rsp->flags2); + netif_err(qdev, drv, qdev->ndev, + "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2); dev_kfree_skb_any(skb); rx_ring->rx_errors++; return; @@ -1950,17 +1965,18 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { - QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_REG ? "Registered" : "", - (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == - IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, "%s Multicast.\n", + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_HASH ? "Hash" : + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_REG ? "Registered" : + (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) == + IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : ""); rx_ring->rx_multicast++; } if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) { - QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Promiscuous Packet.\n"); } skb->protocol = eth_type_trans(skb, ndev); @@ -1973,8 +1989,8 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "TCP checksum done!\n"); skb->ip_summed = CHECKSUM_UNNECESSARY; } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { @@ -1983,8 +1999,8 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, if (!(iph->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - QPRINTK(qdev, RX_STATUS, DEBUG, - "TCP checksum done!\n"); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "TCP checksum done!\n"); } } } @@ -2054,8 +2070,9 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev, /* Free small buffer that holds the IAL */ lbq_desc = ql_get_curr_sbuf(rx_ring); - QPRINTK(qdev, RX_ERR, ERR, "Dropping frame, len %d > mtu %d\n", - length, qdev->ndev->mtu); + netif_err(qdev, rx_err, qdev->ndev, + "Dropping frame, len %d > mtu %d\n", + length, qdev->ndev->mtu); /* Unwind the large buffers for this frame. */ while (length > 0) { @@ -2090,20 +2107,20 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev, OB_MAC_IOCB_RSP_L | OB_MAC_IOCB_RSP_P | OB_MAC_IOCB_RSP_B))) { if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_E) { - QPRINTK(qdev, TX_DONE, WARNING, - "Total descriptor length did not match transfer length.\n"); + netif_warn(qdev, tx_done, qdev->ndev, + "Total descriptor length did not match transfer length.\n"); } if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_S) { - QPRINTK(qdev, TX_DONE, WARNING, - "Frame too short to be legal, not sent.\n"); + netif_warn(qdev, tx_done, qdev->ndev, + "Frame too short to be valid, not sent.\n"); } if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_L) { - QPRINTK(qdev, TX_DONE, WARNING, - "Frame too long, but sent anyway.\n"); + netif_warn(qdev, tx_done, qdev->ndev, + "Frame too long, but sent anyway.\n"); } if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_B) { - QPRINTK(qdev, TX_DONE, WARNING, - "PCI backplane error. Frame not sent.\n"); + netif_warn(qdev, tx_done, qdev->ndev, + "PCI backplane error. Frame not sent.\n"); } } atomic_inc(&tx_ring->tx_count); @@ -2133,33 +2150,35 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev, { switch (ib_ae_rsp->event) { case MGMT_ERR_EVENT: - QPRINTK(qdev, RX_ERR, ERR, - "Management Processor Fatal Error.\n"); + netif_err(qdev, rx_err, qdev->ndev, + "Management Processor Fatal Error.\n"); ql_queue_fw_error(qdev); return; case CAM_LOOKUP_ERR_EVENT: - QPRINTK(qdev, LINK, ERR, - "Multiple CAM hits lookup occurred.\n"); - QPRINTK(qdev, DRV, ERR, "This event shouldn't occur.\n"); + netif_err(qdev, link, qdev->ndev, + "Multiple CAM hits lookup occurred.\n"); + netif_err(qdev, drv, qdev->ndev, + "This event shouldn't occur.\n"); ql_queue_asic_error(qdev); return; case SOFT_ECC_ERROR_EVENT: - QPRINTK(qdev, RX_ERR, ERR, "Soft ECC error detected.\n"); + netif_err(qdev, rx_err, qdev->ndev, + "Soft ECC error detected.\n"); ql_queue_asic_error(qdev); break; case PCI_ERR_ANON_BUF_RD: - QPRINTK(qdev, RX_ERR, ERR, - "PCI error occurred when reading anonymous buffers from rx_ring %d.\n", - ib_ae_rsp->q_id); + netif_err(qdev, rx_err, qdev->ndev, + "PCI error occurred when reading anonymous buffers from rx_ring %d.\n", + ib_ae_rsp->q_id); ql_queue_asic_error(qdev); break; default: - QPRINTK(qdev, DRV, ERR, "Unexpected event %d.\n", - ib_ae_rsp->event); + netif_err(qdev, drv, qdev->ndev, "Unexpected event %d.\n", + ib_ae_rsp->event); ql_queue_asic_error(qdev); break; } @@ -2176,9 +2195,9 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) /* While there are entries in the completion queue. */ while (prod != rx_ring->cnsmr_idx) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id, - prod, rx_ring->cnsmr_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "cq_id = %d, prod = %d, cnsmr = %d.\n.", + rx_ring->cq_id, prod, rx_ring->cnsmr_idx); net_rsp = (struct ob_mac_iocb_rsp *)rx_ring->curr_entry; rmb(); @@ -2189,9 +2208,9 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) ql_process_mac_tx_intr(qdev, net_rsp); break; default: - QPRINTK(qdev, RX_STATUS, DEBUG, - "Hit default case, not handled! dropping the packet, opcode = %x.\n", - net_rsp->opcode); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Hit default case, not handled! dropping the packet, opcode = %x.\n", + net_rsp->opcode); } count++; ql_update_cq(rx_ring); @@ -2223,9 +2242,9 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) /* While there are entries in the completion queue. */ while (prod != rx_ring->cnsmr_idx) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id, - prod, rx_ring->cnsmr_idx); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "cq_id = %d, prod = %d, cnsmr = %d.\n.", + rx_ring->cq_id, prod, rx_ring->cnsmr_idx); net_rsp = rx_ring->curr_entry; rmb(); @@ -2241,11 +2260,10 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) net_rsp); break; default: - { - QPRINTK(qdev, RX_STATUS, DEBUG, - "Hit default case, not handled! dropping the packet, opcode = %x.\n", - net_rsp->opcode); - } + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Hit default case, not handled! dropping the packet, opcode = %x.\n", + net_rsp->opcode); + break; } count++; ql_update_cq(rx_ring); @@ -2266,8 +2284,8 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) int i, work_done = 0; struct intr_context *ctx = &qdev->intr_context[rx_ring->cq_id]; - QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n", - rx_ring->cq_id); + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "Enter, NAPI POLL cq_id = %d.\n", rx_ring->cq_id); /* Service the TX rings first. They start * right after the RSS rings. */ @@ -2279,9 +2297,9 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) if ((ctx->irq_mask & (1 << trx_ring->cq_id)) && (ql_read_sh_reg(trx_ring->prod_idx_sh_reg) != trx_ring->cnsmr_idx)) { - QPRINTK(qdev, INTR, DEBUG, - "%s: Servicing TX completion ring %d.\n", - __func__, trx_ring->cq_id); + netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev, + "%s: Servicing TX completion ring %d.\n", + __func__, trx_ring->cq_id); ql_clean_outbound_rx_ring(trx_ring); } } @@ -2291,9 +2309,9 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) */ if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { - QPRINTK(qdev, INTR, DEBUG, - "%s: Servicing RX completion ring %d.\n", - __func__, rx_ring->cq_id); + netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev, + "%s: Servicing RX completion ring %d.\n", + __func__, rx_ring->cq_id); work_done = ql_clean_inbound_rx_ring(rx_ring, budget); } @@ -2310,12 +2328,13 @@ static void qlge_vlan_rx_register(struct net_device *ndev, struct vlan_group *gr qdev->vlgrp = grp; if (grp) { - QPRINTK(qdev, IFUP, DEBUG, "Turning on VLAN in NIC_RCV_CFG.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Turning on VLAN in NIC_RCV_CFG.\n"); ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK | NIC_RCV_CFG_VLAN_MATCH_AND_NON); } else { - QPRINTK(qdev, IFUP, DEBUG, - "Turning off VLAN in NIC_RCV_CFG.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Turning off VLAN in NIC_RCV_CFG.\n"); ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK); } } @@ -2331,7 +2350,8 @@ static void qlge_vlan_rx_add_vid(struct net_device *ndev, u16 vid) return; if (ql_set_mac_addr_reg (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { - QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init vlan address.\n"); } ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); } @@ -2348,7 +2368,8 @@ static void qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) if (ql_set_mac_addr_reg (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { - QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to clear vlan address.\n"); } ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); @@ -2377,7 +2398,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) spin_lock(&qdev->hw_lock); if (atomic_read(&qdev->intr_context[0].irq_cnt)) { - QPRINTK(qdev, INTR, DEBUG, "Shared Interrupt, Not ours!\n"); + netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev, + "Shared Interrupt, Not ours!\n"); spin_unlock(&qdev->hw_lock); return IRQ_NONE; } @@ -2390,10 +2412,11 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) */ if (var & STS_FE) { ql_queue_asic_error(qdev); - QPRINTK(qdev, INTR, ERR, "Got fatal error, STS = %x.\n", var); + netif_err(qdev, intr, qdev->ndev, + "Got fatal error, STS = %x.\n", var); var = ql_read32(qdev, ERR_STS); - QPRINTK(qdev, INTR, ERR, - "Resetting chip. Error Status Register = 0x%x\n", var); + netif_err(qdev, intr, qdev->ndev, + "Resetting chip. Error Status Register = 0x%x\n", var); return IRQ_HANDLED; } @@ -2406,7 +2429,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) * We've got an async event or mailbox completion. * Handle it and clear the source of the interrupt. */ - QPRINTK(qdev, INTR, ERR, "Got MPI processor interrupt.\n"); + netif_err(qdev, intr, qdev->ndev, + "Got MPI processor interrupt.\n"); ql_disable_completion_interrupt(qdev, intr_context->intr); ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); queue_delayed_work_on(smp_processor_id(), @@ -2421,8 +2445,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) */ var = ql_read32(qdev, ISR1); if (var & intr_context->irq_mask) { - QPRINTK(qdev, INTR, INFO, - "Waking handler for rx_ring[0].\n"); + netif_info(qdev, intr, qdev->ndev, + "Waking handler for rx_ring[0].\n"); ql_disable_completion_interrupt(qdev, intr_context->intr); napi_schedule(&rx_ring->napi); work_done++; @@ -2519,9 +2543,9 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) { - QPRINTK(qdev, TX_QUEUED, INFO, - "%s: shutting down tx queue %d du to lack of resources.\n", - __func__, tx_ring_idx); + netif_info(qdev, tx_queued, qdev->ndev, + "%s: shutting down tx queue %d du to lack of resources.\n", + __func__, tx_ring_idx); netif_stop_subqueue(ndev, tx_ring->wq_id); atomic_inc(&tx_ring->queue_stopped); tx_ring->tx_errors++; @@ -2542,8 +2566,8 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len); if (qdev->vlgrp && vlan_tx_tag_present(skb)) { - QPRINTK(qdev, TX_QUEUED, DEBUG, "Adding a vlan tag %d.\n", - vlan_tx_tag_get(skb)); + netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev, + "Adding a vlan tag %d.\n", vlan_tx_tag_get(skb)); mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V; mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb)); } @@ -2557,8 +2581,8 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) } if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) != NETDEV_TX_OK) { - QPRINTK(qdev, TX_QUEUED, ERR, - "Could not map the segments.\n"); + netif_err(qdev, tx_queued, qdev->ndev, + "Could not map the segments.\n"); tx_ring->tx_errors++; return NETDEV_TX_BUSY; } @@ -2569,8 +2593,9 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) wmb(); ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg); - QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n", - tx_ring->prod_idx, skb->len); + netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev, + "tx queued, slot %d, len %d\n", + tx_ring->prod_idx, skb->len); atomic_dec(&tx_ring->tx_count); return NETDEV_TX_OK; @@ -2601,8 +2626,8 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) pci_alloc_consistent(qdev->pdev, PAGE_SIZE, &qdev->rx_ring_shadow_reg_dma); if (qdev->rx_ring_shadow_reg_area == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Allocation of RX shadow space failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Allocation of RX shadow space failed.\n"); return -ENOMEM; } memset(qdev->rx_ring_shadow_reg_area, 0, PAGE_SIZE); @@ -2610,8 +2635,8 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) pci_alloc_consistent(qdev->pdev, PAGE_SIZE, &qdev->tx_ring_shadow_reg_dma); if (qdev->tx_ring_shadow_reg_area == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Allocation of TX shadow space failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Allocation of TX shadow space failed.\n"); goto err_wqp_sh_area; } memset(qdev->tx_ring_shadow_reg_area, 0, PAGE_SIZE); @@ -2665,7 +2690,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, if ((tx_ring->wq_base == NULL) || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { - QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); + netif_err(qdev, ifup, qdev->ndev, "tx_ring alloc failed.\n"); return -ENOMEM; } tx_ring->q = @@ -2716,7 +2741,8 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring for (i = 0; i < rx_ring->sbq_len; i++) { sbq_desc = &rx_ring->sbq[i]; if (sbq_desc == NULL) { - QPRINTK(qdev, IFUP, ERR, "sbq_desc %d is NULL.\n", i); + netif_err(qdev, ifup, qdev->ndev, + "sbq_desc %d is NULL.\n", i); return; } if (sbq_desc->p.skb) { @@ -2843,7 +2869,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, &rx_ring->cq_base_dma); if (rx_ring->cq_base == NULL) { - QPRINTK(qdev, IFUP, ERR, "rx_ring alloc failed.\n"); + netif_err(qdev, ifup, qdev->ndev, "rx_ring alloc failed.\n"); return -ENOMEM; } @@ -2856,8 +2882,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, &rx_ring->sbq_base_dma); if (rx_ring->sbq_base == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Small buffer queue allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Small buffer queue allocation failed.\n"); goto err_mem; } @@ -2868,8 +2894,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc), GFP_KERNEL); if (rx_ring->sbq == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Small buffer queue control block allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Small buffer queue control block allocation failed.\n"); goto err_mem; } @@ -2885,8 +2911,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, &rx_ring->lbq_base_dma); if (rx_ring->lbq_base == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Large buffer queue allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Large buffer queue allocation failed.\n"); goto err_mem; } /* @@ -2896,8 +2922,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc), GFP_KERNEL); if (rx_ring->lbq == NULL) { - QPRINTK(qdev, IFUP, ERR, - "Large buffer queue control block allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Large buffer queue control block allocation failed.\n"); goto err_mem; } @@ -2926,10 +2952,10 @@ static void ql_tx_ring_clean(struct ql_adapter *qdev) for (i = 0; i < tx_ring->wq_len; i++) { tx_ring_desc = &tx_ring->q[i]; if (tx_ring_desc && tx_ring_desc->skb) { - QPRINTK(qdev, IFDOWN, ERR, - "Freeing lost SKB %p, from queue %d, index %d.\n", - tx_ring_desc->skb, j, - tx_ring_desc->index); + netif_err(qdev, ifdown, qdev->ndev, + "Freeing lost SKB %p, from queue %d, index %d.\n", + tx_ring_desc->skb, j, + tx_ring_desc->index); ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt); dev_kfree_skb(tx_ring_desc->skb); @@ -2960,16 +2986,16 @@ static int ql_alloc_mem_resources(struct ql_adapter *qdev) for (i = 0; i < qdev->rx_ring_count; i++) { if (ql_alloc_rx_resources(qdev, &qdev->rx_ring[i]) != 0) { - QPRINTK(qdev, IFUP, ERR, - "RX resource allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "RX resource allocation failed.\n"); goto err_mem; } } /* Allocate tx queue resources */ for (i = 0; i < qdev->tx_ring_count; i++) { if (ql_alloc_tx_resources(qdev, &qdev->tx_ring[i]) != 0) { - QPRINTK(qdev, IFUP, ERR, - "TX resource allocation failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "TX resource allocation failed.\n"); goto err_mem; } } @@ -3104,14 +3130,15 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames); break; default: - QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n", - rx_ring->type); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Invalid rx_ring->type = %d.\n", rx_ring->type); } - QPRINTK(qdev, IFUP, DEBUG, "Initializing rx work queue.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Initializing rx work queue.\n"); err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb), CFG_LCQ, rx_ring->cq_id); if (err) { - QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to load CQICB.\n"); return err; } return err; @@ -3157,10 +3184,11 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) err = ql_write_cfg(qdev, wqicb, sizeof(*wqicb), CFG_LRQ, (u16) tx_ring->wq_id); if (err) { - QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to load tx_ring.\n"); return err; } - QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded WQICB.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Successfully loaded WQICB.\n"); return err; } @@ -3214,15 +3242,15 @@ static void ql_enable_msix(struct ql_adapter *qdev) if (err < 0) { kfree(qdev->msi_x_entry); qdev->msi_x_entry = NULL; - QPRINTK(qdev, IFUP, WARNING, - "MSI-X Enable failed, trying MSI.\n"); + netif_warn(qdev, ifup, qdev->ndev, + "MSI-X Enable failed, trying MSI.\n"); qdev->intr_count = 1; qlge_irq_type = MSI_IRQ; } else if (err == 0) { set_bit(QL_MSIX_ENABLED, &qdev->flags); - QPRINTK(qdev, IFUP, INFO, - "MSI-X Enabled, got %d vectors.\n", - qdev->intr_count); + netif_info(qdev, ifup, qdev->ndev, + "MSI-X Enabled, got %d vectors.\n", + qdev->intr_count); return; } } @@ -3231,13 +3259,14 @@ msi: if (qlge_irq_type == MSI_IRQ) { if (!pci_enable_msi(qdev->pdev)) { set_bit(QL_MSI_ENABLED, &qdev->flags); - QPRINTK(qdev, IFUP, INFO, - "Running with MSI interrupts.\n"); + netif_info(qdev, ifup, qdev->ndev, + "Running with MSI interrupts.\n"); return; } } qlge_irq_type = LEG_IRQ; - QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Running with legacy interrupts.\n"); } /* Each vector services 1 RSS ring and and 1 or more @@ -3409,12 +3438,12 @@ static void ql_free_irq(struct ql_adapter *qdev) if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { free_irq(qdev->msi_x_entry[i].vector, &qdev->rx_ring[i]); - QPRINTK(qdev, IFDOWN, DEBUG, - "freeing msix interrupt %d.\n", i); + netif_printk(qdev, ifdown, KERN_DEBUG, qdev->ndev, + "freeing msix interrupt %d.\n", i); } else { free_irq(qdev->pdev->irq, &qdev->rx_ring[0]); - QPRINTK(qdev, IFDOWN, DEBUG, - "freeing msi interrupt %d.\n", i); + netif_printk(qdev, ifdown, KERN_DEBUG, qdev->ndev, + "freeing msi interrupt %d.\n", i); } } } @@ -3439,32 +3468,33 @@ static int ql_request_irq(struct ql_adapter *qdev) intr_context->name, &qdev->rx_ring[i]); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed request for MSIX interrupt %d.\n", - i); + netif_err(qdev, ifup, qdev->ndev, + "Failed request for MSIX interrupt %d.\n", + i); goto err_irq; } else { - QPRINTK(qdev, IFUP, DEBUG, - "Hooked intr %d, queue type %s%s%s, with name %s.\n", - i, - qdev->rx_ring[i].type == - DEFAULT_Q ? "DEFAULT_Q" : "", - qdev->rx_ring[i].type == - TX_Q ? "TX_Q" : "", - qdev->rx_ring[i].type == - RX_Q ? "RX_Q" : "", intr_context->name); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Hooked intr %d, queue type %s, with name %s.\n", + i, + qdev->rx_ring[i].type == DEFAULT_Q ? + "DEFAULT_Q" : + qdev->rx_ring[i].type == TX_Q ? + "TX_Q" : + qdev->rx_ring[i].type == RX_Q ? + "RX_Q" : "", + intr_context->name); } } else { - QPRINTK(qdev, IFUP, DEBUG, - "trying msi or legacy interrupts.\n"); - QPRINTK(qdev, IFUP, DEBUG, - "%s: irq = %d.\n", __func__, pdev->irq); - QPRINTK(qdev, IFUP, DEBUG, - "%s: context->name = %s.\n", __func__, - intr_context->name); - QPRINTK(qdev, IFUP, DEBUG, - "%s: dev_id = 0x%p.\n", __func__, - &qdev->rx_ring[0]); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "trying msi or legacy interrupts.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "%s: irq = %d.\n", __func__, pdev->irq); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "%s: context->name = %s.\n", __func__, + intr_context->name); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "%s: dev_id = 0x%p.\n", __func__, + &qdev->rx_ring[0]); status = request_irq(pdev->irq, qlge_isr, test_bit(QL_MSI_ENABLED, @@ -3474,20 +3504,20 @@ static int ql_request_irq(struct ql_adapter *qdev) if (status) goto err_irq; - QPRINTK(qdev, IFUP, ERR, - "Hooked intr %d, queue type %s%s%s, with name %s.\n", - i, - qdev->rx_ring[0].type == - DEFAULT_Q ? "DEFAULT_Q" : "", - qdev->rx_ring[0].type == TX_Q ? "TX_Q" : "", - qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "", - intr_context->name); + netif_err(qdev, ifup, qdev->ndev, + "Hooked intr %d, queue type %s, with name %s.\n", + i, + qdev->rx_ring[0].type == DEFAULT_Q ? + "DEFAULT_Q" : + qdev->rx_ring[0].type == TX_Q ? "TX_Q" : + qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "", + intr_context->name); } intr_context->hooked = 1; } return status; err_irq: - QPRINTK(qdev, IFUP, ERR, "Failed to get the interrupts!!!/n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!/n"); ql_free_irq(qdev); return status; } @@ -3521,14 +3551,15 @@ static int ql_start_rss(struct ql_adapter *qdev) memcpy((void *)&ricb->ipv6_hash_key[0], init_hash_seed, 40); memcpy((void *)&ricb->ipv4_hash_key[0], init_hash_seed, 16); - QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, "Initializing RSS.\n"); status = ql_write_cfg(qdev, ricb, sizeof(*ricb), CFG_LR, 0); if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to load RICB.\n"); return status; } - QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded RICB.\n"); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Successfully loaded RICB.\n"); return status; } @@ -3543,9 +3574,8 @@ static int ql_clear_routing_entries(struct ql_adapter *qdev) for (i = 0; i < 16; i++) { status = ql_set_routing_reg(qdev, i, 0, 0); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for CAM " - "packets.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init routing register for CAM packets.\n"); break; } } @@ -3569,14 +3599,14 @@ static int ql_route_initialize(struct ql_adapter *qdev) status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for error packets.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init routing register for error packets.\n"); goto exit; } status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for broadcast packets.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init routing register for broadcast packets.\n"); goto exit; } /* If we have more than one inbound queue, then turn on RSS in the @@ -3586,8 +3616,8 @@ static int ql_route_initialize(struct ql_adapter *qdev) status = ql_set_routing_reg(qdev, RT_IDX_RSS_MATCH_SLOT, RT_IDX_RSS_MATCH, 1); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for MATCH RSS packets.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init routing register for MATCH RSS packets.\n"); goto exit; } } @@ -3595,8 +3625,8 @@ static int ql_route_initialize(struct ql_adapter *qdev) status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT, RT_IDX_CAM_HIT, 1); if (status) - QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for CAM packets.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init routing register for CAM packets.\n"); exit: ql_sem_unlock(qdev, SEM_RT_IDX_MASK); return status; @@ -3614,13 +3644,13 @@ int ql_cam_route_initialize(struct ql_adapter *qdev) set &= qdev->port_link_up; status = ql_set_mac_addr(qdev, set); if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to init mac address.\n"); return status; } status = ql_route_initialize(qdev); if (status) - QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to init routing table.\n"); return status; } @@ -3685,8 +3715,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) for (i = 0; i < qdev->rx_ring_count; i++) { status = ql_start_rx_ring(qdev, &qdev->rx_ring[i]); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to start rx ring[%d].\n", i); + netif_err(qdev, ifup, qdev->ndev, + "Failed to start rx ring[%d].\n", i); return status; } } @@ -3697,7 +3727,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) if (qdev->rss_ring_count > 1) { status = ql_start_rss(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to start RSS.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to start RSS.\n"); return status; } } @@ -3706,8 +3736,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) for (i = 0; i < qdev->tx_ring_count; i++) { status = ql_start_tx_ring(qdev, &qdev->tx_ring[i]); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to start tx ring[%d].\n", i); + netif_err(qdev, ifup, qdev->ndev, + "Failed to start tx ring[%d].\n", i); return status; } } @@ -3715,20 +3745,20 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) /* Initialize the port and set the max framesize. */ status = qdev->nic_ops->port_initialize(qdev); if (status) - QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to start port.\n"); /* Set up the MAC address and frame routing filter. */ status = ql_cam_route_initialize(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init CAM/Routing tables.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init CAM/Routing tables.\n"); return status; } /* Start NAPI for the RSS queues. */ for (i = 0; i < qdev->rss_ring_count; i++) { - QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n", - i); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "Enabling NAPI for rx_ring[%d].\n", i); napi_enable(&qdev->rx_ring[i].napi); } @@ -3745,7 +3775,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev) /* Clear all the entries in the routing table. */ status = ql_clear_routing_entries(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to clear routing bits.\n"); + netif_err(qdev, ifup, qdev->ndev, "Failed to clear routing bits.\n"); return status; } @@ -3768,8 +3798,8 @@ static int ql_adapter_reset(struct ql_adapter *qdev) } while (time_before(jiffies, end_jiffies)); if (value & RST_FO_FR) { - QPRINTK(qdev, IFDOWN, ERR, - "ETIMEDOUT!!! errored out of resetting the chip!\n"); + netif_err(qdev, ifdown, qdev->ndev, + "ETIMEDOUT!!! errored out of resetting the chip!\n"); status = -ETIMEDOUT; } @@ -3782,16 +3812,17 @@ static void ql_display_dev_info(struct net_device *ndev) { struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); - QPRINTK(qdev, PROBE, INFO, - "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, " - "XG Roll = %d, XG Rev = %d.\n", - qdev->func, - qdev->port, - qdev->chip_rev_id & 0x0000000f, - qdev->chip_rev_id >> 4 & 0x0000000f, - qdev->chip_rev_id >> 8 & 0x0000000f, - qdev->chip_rev_id >> 12 & 0x0000000f); - QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); + netif_info(qdev, probe, qdev->ndev, + "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, " + "XG Roll = %d, XG Rev = %d.\n", + qdev->func, + qdev->port, + qdev->chip_rev_id & 0x0000000f, + qdev->chip_rev_id >> 4 & 0x0000000f, + qdev->chip_rev_id >> 8 & 0x0000000f, + qdev->chip_rev_id >> 12 & 0x0000000f); + netif_info(qdev, probe, qdev->ndev, + "MAC address %pM\n", ndev->dev_addr); } int ql_wol(struct ql_adapter *qdev) @@ -3808,23 +3839,23 @@ int ql_wol(struct ql_adapter *qdev) if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) { - QPRINTK(qdev, IFDOWN, ERR, - "Unsupported WOL paramter. qdev->wol = 0x%x.\n", - qdev->wol); + netif_err(qdev, ifdown, qdev->ndev, + "Unsupported WOL paramter. qdev->wol = 0x%x.\n", + qdev->wol); return -EINVAL; } if (qdev->wol & WAKE_MAGIC) { status = ql_mb_wol_set_magic(qdev, 1); if (status) { - QPRINTK(qdev, IFDOWN, ERR, - "Failed to set magic packet on %s.\n", - qdev->ndev->name); + netif_err(qdev, ifdown, qdev->ndev, + "Failed to set magic packet on %s.\n", + qdev->ndev->name); return status; } else - QPRINTK(qdev, DRV, INFO, - "Enabled magic packet successfully on %s.\n", - qdev->ndev->name); + netif_info(qdev, drv, qdev->ndev, + "Enabled magic packet successfully on %s.\n", + qdev->ndev->name); wol |= MB_WOL_MAGIC_PKT; } @@ -3832,9 +3863,10 @@ int ql_wol(struct ql_adapter *qdev) if (qdev->wol) { wol |= MB_WOL_MODE_ON; status = ql_mb_wol_mode(qdev, wol); - QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n", - (status == 0) ? "Sucessfully set" : "Failed", wol, - qdev->ndev->name); + netif_err(qdev, drv, qdev->ndev, + "WOL %s (wol code 0x%x) on %s\n", + (status == 0) ? "Sucessfully set" : "Failed", + wol, qdev->ndev->name); } return status; @@ -3875,8 +3907,8 @@ static int ql_adapter_down(struct ql_adapter *qdev) status = ql_adapter_reset(qdev); if (status) - QPRINTK(qdev, IFDOWN, ERR, "reset(func #%d) FAILED!\n", - qdev->func); + netif_err(qdev, ifdown, qdev->ndev, "reset(func #%d) FAILED!\n", + qdev->func); return status; } @@ -3886,7 +3918,7 @@ static int ql_adapter_up(struct ql_adapter *qdev) err = ql_adapter_initialize(qdev); if (err) { - QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); + netif_info(qdev, ifup, qdev->ndev, "Unable to initialize adapter.\n"); goto err_init; } set_bit(QL_ADAPTER_UP, &qdev->flags); @@ -3918,7 +3950,7 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev) int status = 0; if (ql_alloc_mem_resources(qdev)) { - QPRINTK(qdev, IFUP, ERR, "Unable to allocate memory.\n"); + netif_err(qdev, ifup, qdev->ndev, "Unable to allocate memory.\n"); return -ENOMEM; } status = ql_request_irq(qdev); @@ -3934,7 +3966,7 @@ static int qlge_close(struct net_device *ndev) * brought the adapter down. */ if (test_bit(QL_EEH_FATAL, &qdev->flags)) { - QPRINTK(qdev, DRV, ERR, "EEH fatal did unload.\n"); + netif_err(qdev, drv, qdev->ndev, "EEH fatal did unload.\n"); clear_bit(QL_EEH_FATAL, &qdev->flags); return 0; } @@ -4008,9 +4040,10 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->lbq_size = rx_ring->lbq_len * sizeof(__le64); rx_ring->lbq_buf_size = (u16)lbq_buf_len; - QPRINTK(qdev, IFUP, DEBUG, - "lbq_buf_size %d, order = %d\n", - rx_ring->lbq_buf_size, qdev->lbq_buf_order); + netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, + "lbq_buf_size %d, order = %d\n", + rx_ring->lbq_buf_size, + qdev->lbq_buf_order); rx_ring->sbq_len = NUM_SMALL_BUFFERS; rx_ring->sbq_size = rx_ring->sbq_len * sizeof(__le64); @@ -4074,14 +4107,14 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev) if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) { int i = 3; while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) { - QPRINTK(qdev, IFUP, ERR, - "Waiting for adapter UP...\n"); + netif_err(qdev, ifup, qdev->ndev, + "Waiting for adapter UP...\n"); ssleep(1); } if (!i) { - QPRINTK(qdev, IFUP, ERR, - "Timed out waiting for adapter UP\n"); + netif_err(qdev, ifup, qdev->ndev, + "Timed out waiting for adapter UP\n"); return -ETIMEDOUT; } } @@ -4107,8 +4140,8 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev) return status; error: - QPRINTK(qdev, IFUP, ALERT, - "Driver up/down cycle failed, closing device.\n"); + netif_alert(qdev, ifup, qdev->ndev, + "Driver up/down cycle failed, closing device.\n"); set_bit(QL_ADAPTER_UP, &qdev->flags); dev_close(qdev->ndev); return status; @@ -4120,9 +4153,9 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu) int status; if (ndev->mtu == 1500 && new_mtu == 9000) { - QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n"); + netif_err(qdev, ifup, qdev->ndev, "Changing to jumbo MTU.\n"); } else if (ndev->mtu == 9000 && new_mtu == 1500) { - QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n"); + netif_err(qdev, ifup, qdev->ndev, "Changing to normal MTU.\n"); } else return -EINVAL; @@ -4137,8 +4170,8 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu) status = ql_change_rx_buffers(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Changing MTU failed.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Changing MTU failed.\n"); } return status; @@ -4198,8 +4231,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (!test_bit(QL_PROMISCUOUS, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 1)) { - QPRINTK(qdev, HW, ERR, - "Failed to set promiscous mode.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to set promiscous mode.\n"); } else { set_bit(QL_PROMISCUOUS, &qdev->flags); } @@ -4208,8 +4241,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (test_bit(QL_PROMISCUOUS, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 0)) { - QPRINTK(qdev, HW, ERR, - "Failed to clear promiscous mode.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to clear promiscous mode.\n"); } else { clear_bit(QL_PROMISCUOUS, &qdev->flags); } @@ -4225,8 +4258,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (!test_bit(QL_ALLMULTI, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) { - QPRINTK(qdev, HW, ERR, - "Failed to set all-multi mode.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to set all-multi mode.\n"); } else { set_bit(QL_ALLMULTI, &qdev->flags); } @@ -4235,8 +4268,8 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (test_bit(QL_ALLMULTI, &qdev->flags)) { if (ql_set_routing_reg (qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 0)) { - QPRINTK(qdev, HW, ERR, - "Failed to clear all-multi mode.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to clear all-multi mode.\n"); } else { clear_bit(QL_ALLMULTI, &qdev->flags); } @@ -4251,16 +4284,16 @@ static void qlge_set_multicast_list(struct net_device *ndev) i++, mc_ptr = mc_ptr->next) if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr, MAC_ADDR_TYPE_MULTI_MAC, i)) { - QPRINTK(qdev, HW, ERR, - "Failed to loadmulticast address.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to loadmulticast address.\n"); ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); goto exit; } ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); if (ql_set_routing_reg (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) { - QPRINTK(qdev, HW, ERR, - "Failed to set multicast match mode.\n"); + netif_err(qdev, hw, qdev->ndev, + "Failed to set multicast match mode.\n"); } else { set_bit(QL_ALLMULTI, &qdev->flags); } @@ -4285,7 +4318,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); if (status) - QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); + netif_err(qdev, hw, qdev->ndev, "Failed to load MAC address.\n"); ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); return status; } @@ -4318,8 +4351,8 @@ static void ql_asic_reset_work(struct work_struct *work) rtnl_unlock(); return; error: - QPRINTK(qdev, IFUP, ALERT, - "Driver up/down cycle failed, closing device\n"); + netif_alert(qdev, ifup, qdev->ndev, + "Driver up/down cycle failed, closing device\n"); set_bit(QL_ADAPTER_UP, &qdev->flags); dev_close(qdev->ndev); @@ -4578,7 +4611,7 @@ static void ql_timer(unsigned long data) var = ql_read32(qdev, STS); if (pci_channel_offline(qdev->pdev)) { - QPRINTK(qdev, IFUP, ERR, "EEH STS = 0x%.08x.\n", var); + netif_err(qdev, ifup, qdev->ndev, "EEH STS = 0x%.08x.\n", var); return; } @@ -4747,14 +4780,14 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); if (pci_enable_device(pdev)) { - QPRINTK(qdev, IFUP, ERR, - "Cannot re-enable PCI device after reset.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } pci_set_master(pdev); if (ql_adapter_reset(qdev)) { - QPRINTK(qdev, DRV, ERR, "reset FAILED!\n"); + netif_err(qdev, drv, qdev->ndev, "reset FAILED!\n"); set_bit(QL_EEH_FATAL, &qdev->flags); return PCI_ERS_RESULT_DISCONNECT; } @@ -4771,13 +4804,13 @@ static void qlge_io_resume(struct pci_dev *pdev) if (netif_running(ndev)) { err = qlge_open(ndev); if (err) { - QPRINTK(qdev, IFUP, ERR, - "Device initialization failed after reset.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Device initialization failed after reset.\n"); return; } } else { - QPRINTK(qdev, IFUP, ERR, - "Device was not running prior to EEH.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Device was not running prior to EEH.\n"); } qdev->timer.expires = jiffies + (5*HZ); add_timer(&qdev->timer); @@ -4828,7 +4861,7 @@ static int qlge_resume(struct pci_dev *pdev) pci_restore_state(pdev); err = pci_enable_device(pdev); if (err) { - QPRINTK(qdev, IFUP, ERR, "Cannot enable PCI device from suspend\n"); + netif_err(qdev, ifup, qdev->ndev, "Cannot enable PCI device from suspend\n"); return err; } pci_set_master(pdev); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index e2c846f17fc7..3c00462a5d22 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -135,7 +135,7 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) ql_read_mpi_reg(qdev, qdev->mailbox_out + i, &mbcp->mbox_out[i]); if (status) { - QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n"); + netif_err(qdev, drv, qdev->ndev, "Failed mailbox read.\n"); break; } } @@ -208,7 +208,7 @@ static int ql_idc_req_aen(struct ql_adapter *qdev) int status; struct mbox_params *mbcp = &qdev->idc_mbc; - QPRINTK(qdev, DRV, ERR, "Enter!\n"); + netif_err(qdev, drv, qdev->ndev, "Enter!\n"); /* Get the status data and start up a thread to * handle the request. */ @@ -216,8 +216,8 @@ static int ql_idc_req_aen(struct ql_adapter *qdev) mbcp->out_count = 4; status = ql_get_mb_sts(qdev, mbcp); if (status) { - QPRINTK(qdev, DRV, ERR, - "Could not read MPI, resetting ASIC!\n"); + netif_err(qdev, drv, qdev->ndev, + "Could not read MPI, resetting ASIC!\n"); ql_queue_asic_error(qdev); } else { /* Begin polled mode early so @@ -240,8 +240,8 @@ static int ql_idc_cmplt_aen(struct ql_adapter *qdev) mbcp->out_count = 4; status = ql_get_mb_sts(qdev, mbcp); if (status) { - QPRINTK(qdev, DRV, ERR, - "Could not read MPI, resetting RISC!\n"); + netif_err(qdev, drv, qdev->ndev, + "Could not read MPI, resetting RISC!\n"); ql_queue_fw_error(qdev); } else /* Wake up the sleeping mpi_idc_work thread that is @@ -259,13 +259,13 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) { - QPRINTK(qdev, DRV, ERR, - "%s: Could not get mailbox status.\n", __func__); + netif_err(qdev, drv, qdev->ndev, + "%s: Could not get mailbox status.\n", __func__); return; } qdev->link_status = mbcp->mbox_out[1]; - QPRINTK(qdev, DRV, ERR, "Link Up.\n"); + netif_err(qdev, drv, qdev->ndev, "Link Up.\n"); /* If we're coming back from an IDC event * then set up the CAM and frame routing. @@ -273,8 +273,8 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) if (test_bit(QL_CAM_RT_SET, &qdev->flags)) { status = ql_cam_route_initialize(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, - "Failed to init CAM/Routing tables.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init CAM/Routing tables.\n"); return; } else clear_bit(QL_CAM_RT_SET, &qdev->flags); @@ -285,7 +285,7 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) * to our liking. */ if (!test_bit(QL_PORT_CFG, &qdev->flags)) { - QPRINTK(qdev, DRV, ERR, "Queue Port Config Worker!\n"); + netif_err(qdev, drv, qdev->ndev, "Queue Port Config Worker!\n"); set_bit(QL_PORT_CFG, &qdev->flags); /* Begin polled mode early so * we don't get another interrupt @@ -307,7 +307,7 @@ static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) - QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n"); + netif_err(qdev, drv, qdev->ndev, "Link down AEN broken!\n"); ql_link_off(qdev); } @@ -320,9 +320,9 @@ static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) - QPRINTK(qdev, DRV, ERR, "SFP in AEN broken!\n"); + netif_err(qdev, drv, qdev->ndev, "SFP in AEN broken!\n"); else - QPRINTK(qdev, DRV, ERR, "SFP insertion detected.\n"); + netif_err(qdev, drv, qdev->ndev, "SFP insertion detected.\n"); return status; } @@ -335,9 +335,9 @@ static int ql_sfp_out(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) - QPRINTK(qdev, DRV, ERR, "SFP out AEN broken!\n"); + netif_err(qdev, drv, qdev->ndev, "SFP out AEN broken!\n"); else - QPRINTK(qdev, DRV, ERR, "SFP removal detected.\n"); + netif_err(qdev, drv, qdev->ndev, "SFP removal detected.\n"); return status; } @@ -350,13 +350,13 @@ static int ql_aen_lost(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) - QPRINTK(qdev, DRV, ERR, "Lost AEN broken!\n"); + netif_err(qdev, drv, qdev->ndev, "Lost AEN broken!\n"); else { int i; - QPRINTK(qdev, DRV, ERR, "Lost AEN detected.\n"); + netif_err(qdev, drv, qdev->ndev, "Lost AEN detected.\n"); for (i = 0; i < mbcp->out_count; i++) - QPRINTK(qdev, DRV, ERR, "mbox_out[%d] = 0x%.08x.\n", - i, mbcp->mbox_out[i]); + netif_err(qdev, drv, qdev->ndev, "mbox_out[%d] = 0x%.08x.\n", + i, mbcp->mbox_out[i]); } @@ -371,15 +371,15 @@ static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); if (status) { - QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n"); + netif_err(qdev, drv, qdev->ndev, "Firmware did not initialize!\n"); } else { - QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n", - mbcp->mbox_out[1]); + netif_err(qdev, drv, qdev->ndev, "Firmware Revision = 0x%.08x.\n", + mbcp->mbox_out[1]); qdev->fw_rev_id = mbcp->mbox_out[1]; status = ql_cam_route_initialize(qdev); if (status) - QPRINTK(qdev, IFUP, ERR, - "Failed to init CAM/Routing tables.\n"); + netif_err(qdev, ifup, qdev->ndev, + "Failed to init CAM/Routing tables.\n"); } } @@ -398,8 +398,8 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) mbcp->out_count = 1; status = ql_get_mb_sts(qdev, mbcp); if (status) { - QPRINTK(qdev, DRV, ERR, - "Could not read MPI, resetting ASIC!\n"); + netif_err(qdev, drv, qdev->ndev, + "Could not read MPI, resetting ASIC!\n"); ql_queue_asic_error(qdev); goto end; } @@ -488,15 +488,14 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) mbcp->mbox_out[0] = MB_CMD_STS_ERR; return status; } - QPRINTK(qdev, DRV, ERR, - "Firmware initialization failed.\n"); + netif_err(qdev, drv, qdev->ndev, + "Firmware initialization failed.\n"); status = -EIO; ql_queue_fw_error(qdev); break; case AEN_SYS_ERR: - QPRINTK(qdev, DRV, ERR, - "System Error.\n"); + netif_err(qdev, drv, qdev->ndev, "System Error.\n"); ql_queue_fw_error(qdev); status = -EIO; break; @@ -509,8 +508,8 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) /* Need to support AEN 8110 */ break; default: - QPRINTK(qdev, DRV, ERR, - "Unsupported AE %.08x.\n", mbcp->mbox_out[0]); + netif_err(qdev, drv, qdev->ndev, + "Unsupported AE %.08x.\n", mbcp->mbox_out[0]); /* Clear the MPI firmware status. */ } end: @@ -583,8 +582,8 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp) goto done; } while (time_before(jiffies, count)); - QPRINTK(qdev, DRV, ERR, - "Timed out waiting for mailbox complete.\n"); + netif_err(qdev, drv, qdev->ndev, + "Timed out waiting for mailbox complete.\n"); status = -ETIMEDOUT; goto end; @@ -646,8 +645,8 @@ int ql_mb_about_fw(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed about firmware command\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed about firmware command\n"); status = -EIO; } @@ -678,8 +677,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed Get Firmware State.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed Get Firmware State.\n"); status = -EIO; } @@ -688,8 +687,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev) * happen. */ if (mbcp->mbox_out[1] & 1) { - QPRINTK(qdev, DRV, ERR, - "Firmware waiting for initialization.\n"); + netif_err(qdev, drv, qdev->ndev, + "Firmware waiting for initialization.\n"); status = -EIO; } @@ -721,8 +720,7 @@ int ql_mb_idc_ack(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed IDC ACK send.\n"); + netif_err(qdev, drv, qdev->ndev, "Failed IDC ACK send.\n"); status = -EIO; } return status; @@ -753,11 +751,11 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) { - QPRINTK(qdev, DRV, ERR, - "Port Config sent, wait for IDC.\n"); + netif_err(qdev, drv, qdev->ndev, + "Port Config sent, wait for IDC.\n"); } else if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed Set Port Configuration.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed Set Port Configuration.\n"); status = -EIO; } return status; @@ -791,8 +789,7 @@ int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr, return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed to dump risc RAM.\n"); + netif_err(qdev, drv, qdev->ndev, "Failed to dump risc RAM.\n"); status = -EIO; } return status; @@ -842,12 +839,12 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed Get Port Configuration.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed Get Port Configuration.\n"); status = -EIO; } else { - QPRINTK(qdev, DRV, DEBUG, - "Passed Get Port Configuration.\n"); + netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev, + "Passed Get Port Configuration.\n"); qdev->link_config = mbcp->mbox_out[1]; qdev->max_frame_size = mbcp->mbox_out[2]; } @@ -874,8 +871,7 @@ int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed to set WOL mode.\n"); + netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n"); status = -EIO; } return status; @@ -917,8 +913,7 @@ int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed to set WOL mode.\n"); + netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n"); status = -EIO; } return status; @@ -944,8 +939,7 @@ static int ql_idc_wait(struct ql_adapter *qdev) wait_for_completion_timeout(&qdev->ide_completion, wait_time); if (!wait_time) { - QPRINTK(qdev, DRV, ERR, - "IDC Timeout.\n"); + netif_err(qdev, drv, qdev->ndev, "IDC Timeout.\n"); break; } /* Now examine the response from the IDC process. @@ -953,18 +947,17 @@ static int ql_idc_wait(struct ql_adapter *qdev) * more wait time. */ if (mbcp->mbox_out[0] == AEN_IDC_EXT) { - QPRINTK(qdev, DRV, ERR, - "IDC Time Extension from function.\n"); + netif_err(qdev, drv, qdev->ndev, + "IDC Time Extension from function.\n"); wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f; } else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) { - QPRINTK(qdev, DRV, ERR, - "IDC Success.\n"); + netif_err(qdev, drv, qdev->ndev, "IDC Success.\n"); status = 0; break; } else { - QPRINTK(qdev, DRV, ERR, - "IDC: Invalid State 0x%.04x.\n", - mbcp->mbox_out[0]); + netif_err(qdev, drv, qdev->ndev, + "IDC: Invalid State 0x%.04x.\n", + mbcp->mbox_out[0]); status = -EIO; break; } @@ -993,8 +986,8 @@ int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed to set LED Configuration.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed to set LED Configuration.\n"); status = -EIO; } @@ -1019,8 +1012,8 @@ int ql_mb_get_led_cfg(struct ql_adapter *qdev) return status; if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { - QPRINTK(qdev, DRV, ERR, - "Failed to get LED Configuration.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed to get LED Configuration.\n"); status = -EIO; } else qdev->led_config = mbcp->mbox_out[1]; @@ -1050,16 +1043,16 @@ int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control) return status; if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) { - QPRINTK(qdev, DRV, ERR, - "Command not supported by firmware.\n"); + netif_err(qdev, drv, qdev->ndev, + "Command not supported by firmware.\n"); status = -EINVAL; } else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) { /* This indicates that the firmware is * already in the state we are trying to * change it to. */ - QPRINTK(qdev, DRV, ERR, - "Command parameters make no change.\n"); + netif_err(qdev, drv, qdev->ndev, + "Command parameters make no change.\n"); } return status; } @@ -1089,12 +1082,12 @@ static int ql_mb_get_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 *control) } if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) { - QPRINTK(qdev, DRV, ERR, - "Command not supported by firmware.\n"); + netif_err(qdev, drv, qdev->ndev, + "Command not supported by firmware.\n"); status = -EINVAL; } else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) { - QPRINTK(qdev, DRV, ERR, - "Failed to get MPI traffic control.\n"); + netif_err(qdev, drv, qdev->ndev, + "Failed to get MPI traffic control.\n"); status = -EIO; } return status; @@ -1150,8 +1143,8 @@ void ql_mpi_port_cfg_work(struct work_struct *work) status = ql_mb_get_port_cfg(qdev); rtnl_unlock(); if (status) { - QPRINTK(qdev, DRV, ERR, - "Bug: Failed to get port config data.\n"); + netif_err(qdev, drv, qdev->ndev, + "Bug: Failed to get port config data.\n"); goto err; } @@ -1164,8 +1157,8 @@ void ql_mpi_port_cfg_work(struct work_struct *work) qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE; status = ql_set_port_cfg(qdev); if (status) { - QPRINTK(qdev, DRV, ERR, - "Bug: Failed to set port config data.\n"); + netif_err(qdev, drv, qdev->ndev, + "Bug: Failed to set port config data.\n"); goto err; } end: @@ -1197,8 +1190,8 @@ void ql_mpi_idc_work(struct work_struct *work) switch (aen) { default: - QPRINTK(qdev, DRV, ERR, - "Bug: Unhandled IDC action.\n"); + netif_err(qdev, drv, qdev->ndev, + "Bug: Unhandled IDC action.\n"); break; case MB_CMD_PORT_RESET: case MB_CMD_STOP_FW: @@ -1213,11 +1206,11 @@ void ql_mpi_idc_work(struct work_struct *work) if (timeout) { status = ql_mb_idc_ack(qdev); if (status) - QPRINTK(qdev, DRV, ERR, - "Bug: No pending IDC!\n"); + netif_err(qdev, drv, qdev->ndev, + "Bug: No pending IDC!\n"); } else { - QPRINTK(qdev, DRV, DEBUG, - "IDC ACK not required\n"); + netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev, + "IDC ACK not required\n"); status = 0; /* success */ } break; @@ -1246,11 +1239,11 @@ void ql_mpi_idc_work(struct work_struct *work) if (timeout) { status = ql_mb_idc_ack(qdev); if (status) - QPRINTK(qdev, DRV, ERR, - "Bug: No pending IDC!\n"); + netif_err(qdev, drv, qdev->ndev, + "Bug: No pending IDC!\n"); } else { - QPRINTK(qdev, DRV, DEBUG, - "IDC ACK not required\n"); + netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev, + "IDC ACK not required\n"); status = 0; /* success */ } break; @@ -1298,12 +1291,12 @@ void ql_mpi_reset_work(struct work_struct *work) * then there is nothing to do. */ if (!ql_own_firmware(qdev)) { - QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n"); + netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n"); return; } if (!ql_core_dump(qdev, qdev->mpi_coredump)) { - QPRINTK(qdev, DRV, ERR, "Core is dumped!\n"); + netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n"); qdev->core_is_dumped = 1; queue_delayed_work(qdev->workqueue, &qdev->mpi_core_to_log, 5 * HZ); -- GitLab From d707204c1fd21ab49242aad17f92f949538e1507 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Feb 2010 11:49:53 +0000 Subject: [PATCH 1989/3892] drivers/net/skge.c: Use netif_printk macros Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/skge.c | 73 ++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 36ead52dea71..ffa55df4d607 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -1074,13 +1074,11 @@ static void skge_link_up(struct skge_port *skge) netif_carrier_on(skge->netdev); netif_wake_queue(skge->netdev); - if (netif_msg_link(skge)) { - printk(KERN_INFO PFX - "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", - skge->netdev->name, skge->speed, - skge->duplex == DUPLEX_FULL ? "full" : "half", - skge_pause(skge->flow_status)); - } + netif_info(skge, link, skge->netdev, + "Link is up at %d Mbps, %s duplex, flow control %s\n", + skge->speed, + skge->duplex == DUPLEX_FULL ? "full" : "half", + skge_pause(skge->flow_status)); } static void skge_link_down(struct skge_port *skge) @@ -1089,8 +1087,7 @@ static void skge_link_down(struct skge_port *skge) netif_carrier_off(skge->netdev); netif_stop_queue(skge->netdev); - if (netif_msg_link(skge)) - printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); + netif_info(skge, link, skge->netdev, "Link is down\n"); } @@ -1792,9 +1789,8 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) struct skge_port *skge = netdev_priv(dev); u16 status = xm_read16(hw, port, XM_ISRC); - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", - dev->name, status); + netif_printk(skge, intr, KERN_DEBUG, skge->netdev, + "mac interrupt status 0x%x\n", status); if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) { xm_link_down(hw, port); @@ -1898,9 +1894,8 @@ static inline void bcom_phy_intr(struct skge_port *skge) u16 isrc; isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT); - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n", - skge->netdev->name, isrc); + netif_printk(skge, intr, KERN_DEBUG, skge->netdev, + "phy interrupt status 0x%x\n", isrc); if (isrc & PHY_B_IS_PSE) printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n", @@ -2298,9 +2293,8 @@ static void yukon_mac_intr(struct skge_hw *hw, int port) struct skge_port *skge = netdev_priv(dev); u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC)); - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", - dev->name, status); + netif_printk(skge, intr, KERN_DEBUG, skge->netdev, + "mac interrupt status 0x%x\n", status); if (status & GM_IS_RX_FF_OR) { ++dev->stats.rx_fifo_errors; @@ -2379,9 +2373,8 @@ static void yukon_phy_intr(struct skge_port *skge) istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n", - skge->netdev->name, istatus, phystat); + netif_printk(skge, intr, KERN_DEBUG, skge->netdev, + "phy interrupt status 0x%x 0x%x\n", istatus, phystat); if (istatus & PHY_M_IS_AN_COMPL) { if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP) @@ -2571,8 +2564,7 @@ static int skge_up(struct net_device *dev) if (!is_valid_ether_addr(dev->dev_addr)) return -EINVAL; - if (netif_msg_ifup(skge)) - printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); + netif_info(skge, ifup, skge->netdev, "enabling interface\n"); if (dev->mtu > RX_BUF_SIZE) skge->rx_buf_size = dev->mtu + ETH_HLEN; @@ -2670,8 +2662,7 @@ static int skge_down(struct net_device *dev) if (skge->mem == NULL) return 0; - if (netif_msg_ifdown(skge)) - printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); + netif_info(skge, ifdown, skge->netdev, "disabling interface\n"); netif_tx_disable(dev); @@ -2825,9 +2816,9 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START); - if (unlikely(netif_msg_tx_queued(skge))) - printk(KERN_DEBUG "%s: tx queued, slot %td, len %d\n", - dev->name, e - skge->tx_ring.start, skb->len); + netif_printk(skge, tx_queued, KERN_DEBUG, skge->netdev, + "tx queued, slot %td, len %d\n", + e - skge->tx_ring.start, skb->len); skge->tx_ring.to_use = e->next; smp_wmb(); @@ -2858,9 +2849,8 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, PCI_DMA_TODEVICE); if (control & BMU_EOF) { - if (unlikely(netif_msg_tx_done(skge))) - printk(KERN_DEBUG PFX "%s: tx done slot %td\n", - skge->netdev->name, e - skge->tx_ring.start); + netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev, + "tx done slot %td\n", e - skge->tx_ring.start); dev_kfree_skb(e->skb); } @@ -2885,8 +2875,7 @@ static void skge_tx_timeout(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); - if (netif_msg_timer(skge)) - printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name); + netif_printk(skge, timer, KERN_DEBUG, skge->netdev, "tx timeout\n"); skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP); skge_tx_clean(dev); @@ -3054,10 +3043,9 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, struct sk_buff *skb; u16 len = control & BMU_BBC; - if (unlikely(netif_msg_rx_status(skge))) - printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", - dev->name, e - skge->rx_ring.start, - status, len); + netif_printk(skge, rx_status, KERN_DEBUG, skge->netdev, + "rx slot %td status 0x%x len %d\n", + e - skge->rx_ring.start, status, len); if (len > skge->rx_buf_size) goto error; @@ -3111,10 +3099,9 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, return skb; error: - if (netif_msg_rx_err(skge)) - printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n", - dev->name, e - skge->rx_ring.start, - control, status); + netif_printk(skge, rx_err, KERN_DEBUG, skge->netdev, + "rx err, slot %td control 0x%x status 0x%x\n", + e - skge->rx_ring.start, control, status); if (skge->hw->chip_id == CHIP_ID_GENESIS) { if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) @@ -3885,9 +3872,7 @@ static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); - if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %pM\n", - dev->name, dev->dev_addr); + netif_info(skge, probe, skge->netdev, "addr %pM\n", dev->dev_addr); } static int __devinit skge_probe(struct pci_dev *pdev, -- GitLab From c28e93040b497e895d5c41b54abef3bc8db17fa9 Mon Sep 17 00:00:00 2001 From: jamal Date: Tue, 9 Feb 2010 03:59:38 +0000 Subject: [PATCH 1990/3892] xfrm: validate attributes Some XFRM attributes were not going through basic validation. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d5a712976004..943c8712bd97 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2054,6 +2054,10 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { #undef XMSGSIZE static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { + [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, + [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, + [XFRMA_LASTUSED] = { .type = NLA_U64}, + [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, -- GitLab From a63374631e7192a64648ecc6672619a7abf9ebcd Mon Sep 17 00:00:00 2001 From: jamal Date: Tue, 9 Feb 2010 13:21:17 +0000 Subject: [PATCH 1991/3892] xfrm: use proper kernel types kernel side should use uxx instead of __uxx types Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/net/xfrm.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index fcee547ca7e3..0beb413c01c4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -317,8 +317,8 @@ extern void xfrm_state_delete_tunnel(struct xfrm_state *x); struct xfrm_type { char *description; struct module *owner; - __u8 proto; - __u8 flags; + u8 proto; + u8 flags; #define XFRM_TYPE_NON_FRAGMENT 1 #define XFRM_TYPE_REPLAY_PROT 2 #define XFRM_TYPE_LOCAL_COADDR 4 @@ -434,24 +434,24 @@ struct xfrm_tmpl { unsigned short encap_family; - __u32 reqid; + u32 reqid; /* Mode: transport, tunnel etc. */ - __u8 mode; + u8 mode; /* Sharing mode: unique, this session only, this user only etc. */ - __u8 share; + u8 share; /* May skip this transfomration if no SA is found */ - __u8 optional; + u8 optional; /* Skip aalgos/ealgos/calgos checks. */ - __u8 allalgs; + u8 allalgs; /* Bit mask of algos allowed for acquisition */ - __u32 aalgos; - __u32 ealgos; - __u32 calgos; + u32 aalgos; + u32 ealgos; + u32 calgos; }; #define XFRM_MAX_DEPTH 6 @@ -770,7 +770,7 @@ static __inline__ int addr_match(void *token1, void *token2, int prefixlen) int pdw; int pbi; - pdw = prefixlen >> 5; /* num of whole __u32 in prefix */ + pdw = prefixlen >> 5; /* num of whole u32 in prefix */ pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ if (pdw) @@ -1259,7 +1259,7 @@ struct xfrm_algo_desc { /* XFRM tunnel handlers. */ struct xfrm_tunnel { int (*handler)(struct sk_buff *skb); - int (*err_handler)(struct sk_buff *skb, __u32 info); + int (*err_handler)(struct sk_buff *skb, u32 info); struct xfrm_tunnel *next; int priority; @@ -1500,7 +1500,7 @@ static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b, switch (family) { default: case AF_INET: - return (__force __u32)a->a4 - (__force __u32)b->a4; + return (__force u32)a->a4 - (__force u32)b->a4; case AF_INET6: return ipv6_addr_cmp((struct in6_addr *)a, (struct in6_addr *)b); -- GitLab From 8b05543129a5f216e08625e947a16b844bc4766d Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 12 Feb 2010 06:57:58 +0000 Subject: [PATCH 1992/3892] sky2: fix sparse warning Warning about hidden variable Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 45299d663498..92f7ba0953ee 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3128,7 +3128,7 @@ static void sky2_reset(struct sky2_hw *hw) /* check if PSMv2 was running before */ reg = sky2_pci_read16(hw, PSM_CONFIG_REG3); if (reg & PCI_EXP_LNKCTL_ASPMC) { - int cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); /* restore the PCIe Link Control register */ sky2_pci_write16(hw, cap + PCI_EXP_LNKCTL, reg); } -- GitLab From 5f8ae5c537d937bab9cfeb83a30a9b670c3cfb35 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 12 Feb 2010 06:57:59 +0000 Subject: [PATCH 1993/3892] sky2: WoL changes Change Wake On Lan code to be similar to vendor driver. The definition of Y2_HW_WOL_ON is confusing; what it means is transition to firmware SPI setting when doing power change. Since same code is done for both shutdown and suspend, use common code path. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 65 +++++++--------------------------------------- 1 file changed, 9 insertions(+), 56 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 92f7ba0953ee..edf37aaf67f8 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -251,6 +251,8 @@ static void sky2_power_on(struct sky2_hw *hw) sky2_pci_write32(hw, PCI_CFG_REG_1, 0); + sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON); + /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */ reg = sky2_read32(hw, B2_GP_IO); reg |= GLB_GPIO_STAT_RACE_DIS; @@ -782,6 +784,9 @@ static void sky2_wol_init(struct sky2_port *sky2) ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); + /* Disable PiG firmware */ + sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF); + /* Turn on legacy PCI-Express PME mode */ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); reg1 |= PCI_Y2_PME_LEGACY; @@ -789,7 +794,6 @@ static void sky2_wol_init(struct sky2_port *sky2) /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); - } static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) @@ -3272,27 +3276,6 @@ static inline u8 sky2_wol_supported(const struct sky2_hw *hw) return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; } -static void sky2_hw_set_wol(struct sky2_hw *hw) -{ - int wol = 0; - int i; - - for (i = 0; i < hw->ports; i++) { - struct net_device *dev = hw->dev[i]; - struct sky2_port *sky2 = netdev_priv(dev); - - if (sky2->wol) - wol = 1; - } - - if (hw->chip_id == CHIP_ID_YUKON_EC_U || - hw->chip_id == CHIP_ID_YUKON_EX || - hw->chip_id == CHIP_ID_YUKON_FE_P) - sky2_write32(hw, B0_CTST, wol ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); - - device_set_wakeup_enable(&hw->pdev->dev, wol); -} - static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { const struct sky2_port *sky2 = netdev_priv(dev); @@ -3311,11 +3294,6 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return -EOPNOTSUPP; sky2->wol = wol->wolopts; - - sky2_hw_set_wol(hw); - - if (!netif_running(dev)) - sky2_wol_init(sky2); return 0; } @@ -4809,7 +4787,6 @@ static void __devexit sky2_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -#ifdef CONFIG_PM static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) { struct sky2_hw *hw = pci_get_drvdata(pdev); @@ -4834,6 +4811,8 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) wol |= sky2->wol; } + device_set_wakeup_enable(&pdev->dev, wol != 0); + sky2_write32(hw, B0_IMSK, 0); napi_disable(&hw->napi); sky2_power_aux(hw); @@ -4846,6 +4825,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } +#ifdef CONFIG_PM static int sky2_resume(struct pci_dev *pdev) { struct sky2_hw *hw = pci_get_drvdata(pdev); @@ -4895,34 +4875,7 @@ out: static void sky2_shutdown(struct pci_dev *pdev) { - struct sky2_hw *hw = pci_get_drvdata(pdev); - int i, wol = 0; - - if (!hw) - return; - - rtnl_lock(); - del_timer_sync(&hw->watchdog_timer); - - for (i = 0; i < hw->ports; i++) { - struct net_device *dev = hw->dev[i]; - struct sky2_port *sky2 = netdev_priv(dev); - - if (sky2->wol) { - wol = 1; - sky2_wol_init(sky2); - } - } - - if (wol) - sky2_power_aux(hw); - rtnl_unlock(); - - pci_enable_wake(pdev, PCI_D3hot, wol); - pci_enable_wake(pdev, PCI_D3cold, wol); - - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); + sky2_suspend(pdev, PMSG_SUSPEND); } static struct pci_driver sky2_driver = { -- GitLab From 87b09f1f25cd1e01d7c50bf423c7fe33027d7511 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 12 Feb 2010 06:58:00 +0000 Subject: [PATCH 1994/3892] sky2: dont enable PME legacy mode This bit is not changed by vendor driver, and should be left alone. The documentation implies this a debug bit. 0 = WAKE# only asserted when VMAIN not available 1 = WAKE# is depend on wake events and independent of VMAIN. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index edf37aaf67f8..249484220a5f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -733,7 +733,6 @@ static void sky2_wol_init(struct sky2_port *sky2) unsigned port = sky2->port; enum flow_control save_mode; u16 ctrl; - u32 reg1; /* Bring hardware out of reset */ sky2_write16(hw, B0_CTST, CS_RST_CLR); @@ -787,11 +786,6 @@ static void sky2_wol_init(struct sky2_port *sky2) /* Disable PiG firmware */ sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF); - /* Turn on legacy PCI-Express PME mode */ - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - reg1 |= PCI_Y2_PME_LEGACY; - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); } -- GitLab From 44dde56d37787cbad2e867a41fe87d6b0aa37fc8 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 12 Feb 2010 06:58:01 +0000 Subject: [PATCH 1995/3892] sky2: jumbo packet changes Change how FIFO is programmed in jumbo mode (to match vendor driver). Mostly cosmetic, the only register change is that the bits 22,23 are not programemd used. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 36 ++++++++++++++---------------------- drivers/net/sky2.h | 8 ++++---- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 249484220a5f..8a87e16e732f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -798,29 +798,15 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) hw->chip_rev != CHIP_REV_YU_EX_A0) || hw->chip_id >= CHIP_ID_YUKON_FE_P) { /* Yukon-Extreme B0 and further Extreme devices */ - /* enable Store & Forward mode for TX */ + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA); + } else if (dev->mtu > ETH_DATA_LEN) { + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); - if (dev->mtu <= ETH_DATA_LEN) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); - - else - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_ENA| TX_STFW_ENA); - } else { - if (dev->mtu <= ETH_DATA_LEN) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA); - else { - /* set Tx GMAC FIFO Almost Empty Threshold */ - sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), - (ECU_JUMBO_WM << 16) | ECU_AE_THR); - - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS); - - /* Can't do offload because of lack of store/forward */ - dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); - } - } + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS); + } else + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA); } static void sky2_mac_init(struct sky2_hw *hw, unsigned port) @@ -2206,14 +2192,20 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) u16 ctl, mode; u32 imask; + /* MTU size outside the spec */ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; + /* MTU > 1500 on yukon FE and FE+ not allowed */ if (new_mtu > ETH_DATA_LEN && (hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_FE_P)) return -EINVAL; + /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */ + if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) + dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); + if (!netif_running(dev)) { dev->mtu = new_mtu; return 0; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 54cb303443e0..a5e182dd9819 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1895,14 +1895,14 @@ enum { /* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */ enum { - TX_STFW_DIS = 1<<31,/* Disable Store & Forward (Yukon-EC Ultra) */ - TX_STFW_ENA = 1<<30,/* Enable Store & Forward (Yukon-EC Ultra) */ + TX_STFW_DIS = 1<<31,/* Disable Store & Forward */ + TX_STFW_ENA = 1<<30,/* Enable Store & Forward */ TX_VLAN_TAG_ON = 1<<25,/* enable VLAN tagging */ TX_VLAN_TAG_OFF = 1<<24,/* disable VLAN tagging */ - TX_JUMBO_ENA = 1<<23,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */ - TX_JUMBO_DIS = 1<<22,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */ + TX_PCI_JUM_ENA = 1<<23,/* PCI Jumbo Mode enable */ + TX_PCI_JUM_DIS = 1<<22,/* PCI Jumbo Mode enable */ GMF_WSP_TST_ON = 1<<18,/* Write Shadow Pointer Test On */ GMF_WSP_TST_OFF = 1<<17,/* Write Shadow Pointer Test Off */ -- GitLab From 39ef110ba859f44efeb9a88d0e85316cd1bbecda Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 12 Feb 2010 06:58:02 +0000 Subject: [PATCH 1996/3892] sky2: Factor out code to calculate packet sizes Move code to calculate receive threshold and packet size out of sky2_rx_start() so that is can be called from elsewhere easily. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 57 ++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 8a87e16e732f..c5de65c6f6e1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1049,6 +1049,40 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2) return le; } +static unsigned sky2_get_rx_threshold(struct sky2_port* sky2) +{ + unsigned size; + + /* Space needed for frame data + headers rounded up */ + size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8); + + /* Stopping point for hardware truncation */ + return (size - 8) / sizeof(u32); +} + +static unsigned sky2_get_rx_data_size(struct sky2_port* sky2) +{ + struct rx_ring_info *re; + unsigned size; + + /* Space needed for frame data + headers rounded up */ + size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8); + + sky2->rx_nfrags = size >> PAGE_SHIFT; + BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr)); + + /* Compute residue after pages */ + size -= sky2->rx_nfrags << PAGE_SHIFT; + + /* Optimize to handle small packets and headers */ + if (size < copybreak) + size = copybreak; + if (size < ETH_HLEN) + size = ETH_HLEN; + + return size; +} + /* Build description to hardware for one receive segment */ static void sky2_rx_add(struct sky2_port *sky2, u8 op, dma_addr_t map, unsigned len) @@ -1343,7 +1377,7 @@ static int sky2_rx_start(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; struct rx_ring_info *re; unsigned rxq = rxqaddr[sky2->port]; - unsigned i, size, thresh; + unsigned i, thresh; sky2->rx_put = sky2->rx_next = 0; sky2_qset(hw, rxq); @@ -1364,25 +1398,7 @@ static int sky2_rx_start(struct sky2_port *sky2) if (!(hw->flags & SKY2_HW_NEW_LE)) rx_set_checksum(sky2); - /* Space needed for frame data + headers rounded up */ - size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8); - - /* Stopping point for hardware truncation */ - thresh = (size - 8) / sizeof(u32); - - sky2->rx_nfrags = size >> PAGE_SHIFT; - BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr)); - - /* Compute residue after pages */ - size -= sky2->rx_nfrags << PAGE_SHIFT; - - /* Optimize to handle small packets and headers */ - if (size < copybreak) - size = copybreak; - if (size < ETH_HLEN) - size = ETH_HLEN; - - sky2->rx_data_size = size; + sky2->rx_data_size = sky2_get_rx_data_size(sky2); /* Fill Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { @@ -1407,6 +1423,7 @@ static int sky2_rx_start(struct sky2_port *sky2) * the register is limited to 9 bits, so if you do frames > 2052 * you better get the MTU right! */ + thresh = sky2_get_rx_threshold(sky2); if (thresh > 0x1ff) sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF); else { -- GitLab From 200ac492b3c366346fcabd11897fadbd1a7a6599 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 12 Feb 2010 06:58:03 +0000 Subject: [PATCH 1997/3892] sky2: Allocate initial skbs in sky2_alloc_buffers Allocate everything in one place so there's a single point of failure in sky2_up, and sky2_rx_start can no longer fail. Don't leave the hardware in a partially initialized state in the case rx ring allocation fails. As with the old code, the rx ring still needs to be fully allocated for sky2_up to succeed. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 66 +++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c5de65c6f6e1..493a82018cbd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1363,8 +1363,32 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq) sky2_put_idx(sky2->hw, rxq, sky2->rx_put); } +static int sky2_alloc_rx_skbs(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + unsigned i; + + sky2->rx_data_size = sky2_get_rx_data_size(sky2); + + /* Fill Rx ring */ + for (i = 0; i < sky2->rx_pending; i++) { + struct rx_ring_info *re = sky2->rx_ring + i; + + re->skb = sky2_rx_alloc(sky2); + if (!re->skb) + return -ENOMEM; + + if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) { + dev_kfree_skb(re->skb); + re->skb = NULL; + return -ENOMEM; + } + } + return 0; +} + /* - * Allocate and setup receiver buffer pool. + * Setup receiver buffer pool. * Normal case this ends up creating one list element for skb * in the receive ring. Worst case if using large MTU and each * allocation falls on a different 64 bit region, that results @@ -1372,7 +1396,7 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq) * One element is used for checksum enable/disable, and one * extra to avoid wrap. */ -static int sky2_rx_start(struct sky2_port *sky2) +static void sky2_rx_start(struct sky2_port *sky2) { struct sky2_hw *hw = sky2->hw; struct rx_ring_info *re; @@ -1398,22 +1422,9 @@ static int sky2_rx_start(struct sky2_port *sky2) if (!(hw->flags & SKY2_HW_NEW_LE)) rx_set_checksum(sky2); - sky2->rx_data_size = sky2_get_rx_data_size(sky2); - - /* Fill Rx ring */ + /* submit Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i; - - re->skb = sky2_rx_alloc(sky2); - if (!re->skb) - goto nomem; - - if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) { - dev_kfree_skb(re->skb); - re->skb = NULL; - goto nomem; - } - sky2_rx_submit(sky2, re); } @@ -1455,13 +1466,6 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2_write32(hw, Q_ADDR(txqaddr[sky2->port], Q_TEST), TBMU_TEST_HOME_ADD_FIX_EN | TBMU_TEST_ROUTING_ADD_FIX_EN); } - - - - return 0; -nomem: - sky2_rx_clean(sky2); - return -ENOMEM; } static int sky2_alloc_buffers(struct sky2_port *sky2) @@ -1492,7 +1496,7 @@ static int sky2_alloc_buffers(struct sky2_port *sky2) if (!sky2->rx_ring) goto nomem; - return 0; + return sky2_alloc_rx_skbs(sky2); nomem: return -ENOMEM; } @@ -1501,6 +1505,8 @@ static void sky2_free_buffers(struct sky2_port *sky2) { struct sky2_hw *hw = sky2->hw; + sky2_rx_clean(sky2); + if (sky2->rx_le) { pci_free_consistent(hw->pdev, RX_LE_BYTES, sky2->rx_le, sky2->rx_le_map); @@ -1590,9 +1596,7 @@ static int sky2_up(struct net_device *dev) sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); #endif - err = sky2_rx_start(sky2); - if (err) - goto err_out; + sky2_rx_start(sky2); /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); @@ -1960,8 +1964,6 @@ static int sky2_down(struct net_device *dev) /* Free any pending frames stuck in HW queue */ sky2_tx_complete(sky2, sky2->tx_prod); - sky2_rx_clean(sky2); - sky2_free_buffers(sky2); return 0; @@ -2257,7 +2259,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD); - err = sky2_rx_start(sky2); + err = sky2_alloc_rx_skbs(sky2); + if (!err) + sky2_rx_start(sky2); + else + sky2_rx_clean(sky2); sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_Y2_SP_LISR); -- GitLab From ea0f71e59c20ea1e413cacfc971e051b3d6c6f64 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 12 Feb 2010 06:58:04 +0000 Subject: [PATCH 1998/3892] sky2: Refactor sky2_up into two functions Move hardware initialization into sky2_hw_up. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 493a82018cbd..1f0180f1f0c3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1525,16 +1525,16 @@ static void sky2_free_buffers(struct sky2_port *sky2) sky2->rx_ring = NULL; } -/* Bring up network interface. */ -static int sky2_up(struct net_device *dev) +static void sky2_hw_up(struct sky2_port *sky2) { - struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 imask, ramsize; - int cap, err; + u32 ramsize; + int cap; struct net_device *otherdev = hw->dev[sky2->port^1]; + tx_init(sky2); + /* * On dual port PCI-X card, there is an problem where status * can be received out of order due to split transactions @@ -1546,16 +1546,7 @@ static int sky2_up(struct net_device *dev) cmd = sky2_pci_read16(hw, cap + PCI_X_CMD); cmd &= ~PCI_X_CMD_MAX_SPLIT; sky2_pci_write16(hw, cap + PCI_X_CMD, cmd); - - } - - netif_carrier_off(dev); - - err = sky2_alloc_buffers(sky2); - if (err) - goto err_out; - - tx_init(sky2); + } sky2_mac_init(hw, port); @@ -1564,7 +1555,7 @@ static int sky2_up(struct net_device *dev) if (ramsize > 0) { u32 rxspace; - pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize); + pr_debug(PFX "%s: ram buffer %dK\n", sky2->netdev->name, ramsize); if (ramsize < 16) rxspace = ramsize / 2; else @@ -1597,6 +1588,24 @@ static int sky2_up(struct net_device *dev) #endif sky2_rx_start(sky2); +} + +/* Bring up network interface. */ +static int sky2_up(struct net_device *dev) +{ + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; + u32 imask; + int err; + + netif_carrier_off(dev); + + err = sky2_alloc_buffers(sky2); + if (err) + goto err_out; + + sky2_hw_up(sky2); /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); -- GitLab From f2b31cb3ae491f9e82443cf25cc5a9ebdbc63619 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 12 Feb 2010 06:58:05 +0000 Subject: [PATCH 1999/3892] sky2: Refactor sky2_down into two functions Create a sky2_hw_down that brings the hardware down. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminber Signed-off-by: David S. Miller --- drivers/net/sky2.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1f0180f1f0c3..61a0451957b0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1908,21 +1908,12 @@ static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); } -/* Network shutdown */ -static int sky2_down(struct net_device *dev) +static void sky2_hw_down(struct sky2_port *sky2) { - struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u16 ctrl; u32 imask; - - /* Never really got started! */ - if (!sky2->tx_le) - return 0; - - if (netif_msg_ifdown(sky2)) - printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); + u16 ctrl; /* Force flow control off */ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -1972,6 +1963,21 @@ static int sky2_down(struct net_device *dev) /* Free any pending frames stuck in HW queue */ sky2_tx_complete(sky2, sky2->tx_prod); +} + +/* Network shutdown */ +static int sky2_down(struct net_device *dev) +{ + struct sky2_port *sky2 = netdev_priv(dev); + + /* Never really got started! */ + if (!sky2->tx_le) + return 0; + + if (netif_msg_ifdown(sky2)) + printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); + + sky2_hw_down(sky2); sky2_free_buffers(sky2); -- GitLab From 8a0c9228f110218f443d9ef8f9ab629251959733 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 12 Feb 2010 06:58:06 +0000 Subject: [PATCH 2000/3892] sky2: Avoid down and up during sky2_reset Rewrite sky2_reset to work with interrupts disabled and avoid freeing and reallocing memory. The old code used sky2_down and sky2_up to implement sky2_reset, which meant interrupts could not be disabled, and the transmit and receive ring buffers would be free'd and reallocated. To avoid the interrupt handler waking the transmit queue while we're doing a reset, it's better to have interrupts and NAPI polls disabled. Note: Modified Mike's patch to do IRQ disable in sky2_down before calling sky2_hw_down - Stephen Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 68 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 61a0451957b0..4147530cee02 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1880,10 +1880,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) sky2->tx_cons = idx; smp_mb(); - - /* Wake unless it's detached, and called e.g. from sky2_down() */ - if (tx_avail(sky2) > MAX_SKB_TX_LE + 4 && netif_device_present(dev)) - netif_wake_queue(dev); } static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) @@ -1912,7 +1908,6 @@ static void sky2_hw_down(struct sky2_port *sky2) { struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 imask; u16 ctrl; /* Force flow control off */ @@ -1946,15 +1941,6 @@ static void sky2_hw_down(struct sky2_port *sky2) sky2_rx_stop(sky2); - /* Disable port IRQ */ - imask = sky2_read32(hw, B0_IMSK); - imask &= ~portirq_msk[port]; - sky2_write32(hw, B0_IMSK, imask); - sky2_read32(hw, B0_IMSK); - - synchronize_irq(hw->pdev->irq); - napi_synchronize(&hw->napi); - spin_lock_bh(&sky2->phy_lock); sky2_phy_power_down(hw, port); spin_unlock_bh(&sky2->phy_lock); @@ -1969,6 +1955,7 @@ static void sky2_hw_down(struct sky2_port *sky2) static int sky2_down(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; /* Never really got started! */ if (!sky2->tx_le) @@ -1977,6 +1964,14 @@ static int sky2_down(struct net_device *dev) if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); + /* Disable port IRQ */ + sky2_write32(hw, B0_IMSK, + sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]); + sky2_read32(hw, B0_IMSK); + + synchronize_irq(hw->pdev->irq); + napi_synchronize(&hw->napi); + sky2_hw_down(sky2); sky2_free_buffers(sky2); @@ -2475,8 +2470,13 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (netif_running(dev)) + if (netif_running(dev)) { sky2_tx_complete(sky2, last); + + /* Wake unless it's detached, and called e.g. from sky2_down() */ + if (tx_avail(sky2) > MAX_SKB_TX_LE + 4) + netif_wake_queue(dev); + } } static inline void sky2_skb_rx(const struct sky2_port *sky2, @@ -3277,20 +3277,46 @@ static int sky2_reattach(struct net_device *dev) static void sky2_restart(struct work_struct *work) { struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); + u32 imask; int i; rtnl_lock(); - for (i = 0; i < hw->ports; i++) - sky2_detach(hw->dev[i]); napi_disable(&hw->napi); + synchronize_irq(hw->pdev->irq); + imask = sky2_read32(hw, B0_IMSK); sky2_write32(hw, B0_IMSK, 0); + + for (i = 0; i < hw->ports; i++) { + struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); + + if (!netif_running(dev)) + continue; + + netif_carrier_off(dev); + netif_tx_disable(dev); + sky2_hw_down(sky2); + } + sky2_reset(hw); - sky2_write32(hw, B0_IMSK, Y2_IS_BASE); - napi_enable(&hw->napi); - for (i = 0; i < hw->ports; i++) - sky2_reattach(hw->dev[i]); + for (i = 0; i < hw->ports; i++) { + struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); + + if (!netif_running(dev)) + continue; + + sky2_hw_up(sky2); + netif_wake_queue(dev); + } + + sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); + + sky2_read32(hw, B0_Y2_SP_LISR); + napi_enable(&hw->napi); rtnl_unlock(); } -- GitLab From cfc0861ba32643c63901832a583054bea0445961 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 12 Feb 2010 06:58:07 +0000 Subject: [PATCH 2001/3892] sky2: version 1.27 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4147530cee02..dfff8e56a51e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.26" +#define DRV_VERSION "1.27" #define PFX DRV_NAME " " /* -- GitLab From 55d955902a7f78e3e7c9ddbc71a4a050d9d44810 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 10 Feb 2010 20:26:18 +0000 Subject: [PATCH 2002/3892] dccp: support for passing MSG_TRUNC DCCP is datagram-oriented but lacks UDP's support for MSG_TRUNC as defined in recvmsg(2)/recv(2). Hence the following 'Hello world\0' receiver len = recv(fd, buf, 10, MSG_PEEK | MSG_TRUNC); wrongly (always) returns 10, while in UDP it returns 12 as expected. This patch adds the missing MSG_TRUNC support to recvmsg(). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/dccp/proto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 671cd1413d59..85ec1cb7fd41 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -835,6 +835,8 @@ verify_sock_status: len = -EFAULT; break; } + if (flags & MSG_TRUNC) + len = skb->len; found_fin_ok: if (!(flags & MSG_PEEK)) sk_eat_skb(sk, skb, 0); -- GitLab From 81d54ec8479a2c695760da81f05b5a9fb2dbe40a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 10 Feb 2010 20:26:19 +0000 Subject: [PATCH 2003/3892] udp: remove redundant variable The variable 'copied' is used in udp_recvmsg() to emphasize that the passed 'len' is adjusted to fit the actual datagram length. But the same can be done by adjusting 'len' directly. This patch thus removes the indirection. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/udp.c | 15 +++++++-------- net/ipv6/udp.c | 15 +++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4f7d2122d818..608a5446d05b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1117,7 +1117,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; - unsigned int ulen, copied; + unsigned int ulen; int peeked; int err; int is_udplite = IS_UDPLITE(sk); @@ -1138,10 +1138,9 @@ try_again: goto out; ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) + if (len > ulen) + len = ulen; + else if (len < ulen) msg->msg_flags |= MSG_TRUNC; /* @@ -1150,14 +1149,14 @@ try_again: * coverage checksum (UDP-Lite), do it before the copy. */ - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { if (udp_lib_checksum_complete(skb)) goto csum_copy_err; } if (skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied); + msg->msg_iov, len); else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), @@ -1186,7 +1185,7 @@ try_again: if (inet->cmsg_flags) ip_cmsg_recv(msg, skb); - err = copied; + err = len; if (flags & MSG_TRUNC) err = ulen; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 34efb3589ffa..a7af9d68cd6c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -322,7 +322,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct ipv6_pinfo *np = inet6_sk(sk); struct inet_sock *inet = inet_sk(sk); struct sk_buff *skb; - unsigned int ulen, copied; + unsigned int ulen; int peeked; int err; int is_udplite = IS_UDPLITE(sk); @@ -341,10 +341,9 @@ try_again: goto out; ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) + if (len > ulen) + len = ulen; + else if (len < ulen) msg->msg_flags |= MSG_TRUNC; is_udp4 = (skb->protocol == htons(ETH_P_IP)); @@ -355,14 +354,14 @@ try_again: * coverage checksum (UDP-Lite), do it before the copy. */ - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { if (udp_lib_checksum_complete(skb)) goto csum_copy_err; } if (skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); + msg->msg_iov,len); else { err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); if (err == -EINVAL) @@ -411,7 +410,7 @@ try_again: datagram_recv_ctl(sk, msg, skb); } - err = copied; + err = len; if (flags & MSG_TRUNC) err = ulen; -- GitLab From fb8a0d9d1bfd1e4355f307e86a6da7209eefd5f3 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:43:04 +0000 Subject: [PATCH 2004/3892] pci: Add SR-IOV convenience functions and macros Add and export pci_num_vf to allow other subsystems to determine how many virtual function devices are associated with an SR-IOV physical function device. Add macros dev_is_pci, dev_is_ps, and dev_num_vf to make it easier for non-PCI specific code to determine SR-IOV capabilities. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/pci/iov.c | 15 +++++++++++++++ include/linux/pci.h | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b2a448e19fe6..3e5ab2bf6a5c 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -706,6 +706,21 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_sriov_migration); +/** + * pci_num_vf - return number of VFs associated with a PF device_release_driver + * @dev: the PCI device + * + * Returns number of VFs, or 0 if SR-IOV is not enabled. + */ +int pci_num_vf(struct pci_dev *dev) +{ + if (!dev || !dev->is_physfn) + return 0; + else + return dev->sriov->nr_virtfn; +} +EXPORT_SYMBOL_GPL(pci_num_vf); + static int ats_alloc_one(struct pci_dev *dev, int ps) { int pos; diff --git a/include/linux/pci.h b/include/linux/pci.h index 174e5392e51e..59a98e2ee2c6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -612,6 +612,9 @@ extern void pci_remove_bus_device(struct pci_dev *dev); extern void pci_stop_bus_device(struct pci_dev *dev); void pci_setup_cardbus(struct pci_bus *bus); extern void pci_sort_breadthfirst(void); +#define dev_is_pci(d) ((d)->bus == &pci_bus_type) +#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false)) +#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0)) /* Generic PCI functions exported to card drivers */ @@ -1129,6 +1132,9 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) { return NULL; } +#define dev_is_pci(d) (false) +#define dev_is_pf(d) (false) +#define dev_num_vf(d) (0) #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ @@ -1286,6 +1292,7 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar); extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn); extern void pci_disable_sriov(struct pci_dev *dev); extern irqreturn_t pci_sriov_migration(struct pci_dev *dev); +extern int pci_num_vf(struct pci_dev *dev); #else static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) { @@ -1298,6 +1305,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev) { return IRQ_NONE; } +static inline int pci_num_vf(struct pci_dev *dev) +{ + return 0; +} #endif #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) -- GitLab From b280da8d54b8d82b52f368a8703b7ada6c1744d5 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:43:24 +0000 Subject: [PATCH 2005/3892] if_link: Add SR-IOV configuration methods Add SR-IOV VF management methods to IFLA_LINKINFO. This allows userspace to use rtnetlink to configure VF network devices. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/if_link.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 6674791622ca..c9bf92cd7653 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -78,6 +78,11 @@ enum { #define IFLA_LINKINFO IFLA_LINKINFO IFLA_NET_NS_PID, IFLA_IFALIAS, + IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ + IFLA_VF_MAC, /* Hardware queue specific attributes */ + IFLA_VF_VLAN, + IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */ + IFLA_VFINFO, __IFLA_MAX }; @@ -196,4 +201,29 @@ enum macvlan_mode { MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ }; +/* SR-IOV virtual function managment section */ + +struct ifla_vf_mac { + __u32 vf; + __u8 mac[32]; /* MAX_ADDR_LEN */ +}; + +struct ifla_vf_vlan { + __u32 vf; + __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + __u32 qos; +}; + +struct ifla_vf_tx_rate { + __u32 vf; + __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */ +}; + +struct ifla_vf_info { + __u32 vf; + __u8 mac[32]; + __u32 vlan; + __u32 qos; + __u32 tx_rate; +}; #endif /* _LINUX_IF_LINK_H */ -- GitLab From 95c26df829ba4a25f40595cadb4c9433883cbe28 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:43:46 +0000 Subject: [PATCH 2006/3892] net: Add netdev ops for SR-IOV configuration Add netdev ops for configuring SR-IOV VF devices through the PF driver. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/netdevice.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1412dde16d00..682d02521bbc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef __KERNEL__ #include @@ -621,6 +622,13 @@ struct netdev_queue { * this function is called when a VLAN id is unregistered. * * void (*ndo_poll_controller)(struct net_device *dev); + * + * SR-IOV management functions. + * int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac); + * int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, u8 qos); + * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate); + * int (*ndo_get_vf_config)(struct net_device *dev, + * int vf, struct ifla_vf_info *ivf); */ #define HAVE_NET_DEVICE_OPS struct net_device_ops { @@ -660,6 +668,15 @@ struct net_device_ops { #ifdef CONFIG_NET_POLL_CONTROLLER void (*ndo_poll_controller)(struct net_device *dev); #endif + int (*ndo_set_vf_mac)(struct net_device *dev, + int queue, u8 *mac); + int (*ndo_set_vf_vlan)(struct net_device *dev, + int queue, u16 vlan, u8 qos); + int (*ndo_set_vf_tx_rate)(struct net_device *dev, + int vf, int rate); + int (*ndo_get_vf_config)(struct net_device *dev, + int vf, + struct ifla_vf_info *ivf); #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) int (*ndo_fcoe_enable)(struct net_device *dev); int (*ndo_fcoe_disable)(struct net_device *dev); -- GitLab From ebc08a6f47ee76ecad8e9f26c26e6ec9b46ca659 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:44:05 +0000 Subject: [PATCH 2007/3892] rtnetlink: Add VF config code to rtnetlink Add code to allow rtnetlink clients to query and set VF information through the PF driver. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 62f3878a6010..42da96a4eeee 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -580,6 +581,15 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, a->tx_compressed = b->tx_compressed; }; +static inline int rtnl_vfinfo_size(const struct net_device *dev) +{ + if (dev->dev.parent && dev_is_pci(dev->dev.parent)) + return dev_num_vf(dev->dev.parent) * + sizeof(struct ifla_vf_info); + else + return 0; +} + static inline size_t if_nlmsg_size(const struct net_device *dev) { return NLMSG_ALIGN(sizeof(struct ifinfomsg)) @@ -597,6 +607,8 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) + nla_total_size(4) /* IFLA_MASTER */ + nla_total_size(1) /* IFLA_OPERSTATE */ + nla_total_size(1) /* IFLA_LINKMODE */ + + nla_total_size(4) /* IFLA_NUM_VF */ + + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */ + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ } @@ -665,6 +677,17 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, stats = dev_get_stats(dev); copy_rtnl_link_stats(nla_data(attr), stats); + if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { + int i; + struct ifla_vf_info ivi; + + NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); + for (i = 0; i < dev_num_vf(dev->dev.parent); i++) { + if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) + break; + NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi); + } + } if (dev->rtnl_link_ops) { if (rtnl_link_fill(skb, dev) < 0) goto nla_put_failure; @@ -725,6 +748,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_LINKINFO] = { .type = NLA_NESTED }, [IFLA_NET_NS_PID] = { .type = NLA_U32 }, [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, + [IFLA_VF_MAC] = { .type = NLA_BINARY, + .len = sizeof(struct ifla_vf_mac) }, + [IFLA_VF_VLAN] = { .type = NLA_BINARY, + .len = sizeof(struct ifla_vf_vlan) }, + [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, + .len = sizeof(struct ifla_vf_tx_rate) }, }; EXPORT_SYMBOL(ifla_policy); @@ -898,6 +927,44 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, write_unlock_bh(&dev_base_lock); } + if (tb[IFLA_VF_MAC]) { + struct ifla_vf_mac *ivm; + ivm = nla_data(tb[IFLA_VF_MAC]); + write_lock_bh(&dev_base_lock); + if (ops->ndo_set_vf_mac) + err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac); + write_unlock_bh(&dev_base_lock); + if (err < 0) + goto errout; + modified = 1; + } + + if (tb[IFLA_VF_VLAN]) { + struct ifla_vf_vlan *ivv; + ivv = nla_data(tb[IFLA_VF_VLAN]); + write_lock_bh(&dev_base_lock); + if (ops->ndo_set_vf_vlan) + err = ops->ndo_set_vf_vlan(dev, ivv->vf, + (u16)ivv->vlan, + (u8)ivv->qos); + write_unlock_bh(&dev_base_lock); + if (err < 0) + goto errout; + modified = 1; + } + err = 0; + + if (tb[IFLA_VF_TX_RATE]) { + struct ifla_vf_tx_rate *ivt; + ivt = nla_data(tb[IFLA_VF_TX_RATE]); + write_lock_bh(&dev_base_lock); + if (ops->ndo_set_vf_tx_rate) + err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate); + write_unlock_bh(&dev_base_lock); + if (err < 0) + goto errout; + modified = 1; + } err = 0; errout: -- GitLab From 8151d2948e088c20b7d29c793cf1fd744b6a2699 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:44:24 +0000 Subject: [PATCH 2008/3892] igb: support for VF configuration tools Add support to the igb driver for VF configuration mechanisms through the PF interface. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.h | 3 + drivers/net/igb/e1000_regs.h | 1 + drivers/net/igb/igb.h | 3 + drivers/net/igb/igb_main.c | 130 +++++++++++++++++++++++++++++++--- 4 files changed, 126 insertions(+), 11 deletions(-) diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index d51c9927c819..bb53083ec61f 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -219,6 +219,9 @@ struct e1000_adv_tx_context_desc { #define E1000_VLVF_LVLAN 0x00100000 #define E1000_VLVF_VLANID_ENABLE 0x80000000 +#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */ +#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */ + #define E1000_IOVCTL 0x05BBC #define E1000_IOVCTL_REUSE_VFQ 0x00000001 diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index dd4e6ffd29f5..abb7333a1fbf 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -310,6 +310,7 @@ #define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n))) #define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine * Filter - RW */ +#define E1000_VMVIR(_n) (0x03700 + (4 * (_n))) #define wr32(reg, value) (writel(value, hw->hw_addr + reg)) #define rd32(reg) (readl(hw->hw_addr + reg)) diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index b1c1eb88893f..83ea11701f45 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -75,11 +75,14 @@ struct vf_data_storage { u16 vlans_enabled; u32 flags; unsigned long last_nack; + u16 pf_vlan; /* When set, guest VLAN config not allowed. */ + u16 pf_qos; }; #define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */ #define IGB_VF_FLAG_UNI_PROMISC 0x00000002 /* VF has unicast promisc */ #define IGB_VF_FLAG_MULTI_PROMISC 0x00000004 /* VF has multicast promisc */ +#define IGB_VF_FLAG_PF_SET_MAC 0x00000008 /* PF has set MAC address */ /* RX descriptor control thresholds. * PTHRESH - MAC will consider prefetch if it has fewer than this number of diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 28371d648208..4fe7b0ba6310 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -133,6 +133,12 @@ static void igb_msg_task(struct igb_adapter *); static void igb_vmm_control(struct igb_adapter *); static int igb_set_vf_mac(struct igb_adapter *, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); +static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac); +static int igb_ndo_set_vf_vlan(struct net_device *netdev, + int vf, u16 vlan, u8 qos); +static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate); +static int igb_ndo_get_vf_config(struct net_device *netdev, int vf, + struct ifla_vf_info *ivi); #ifdef CONFIG_PM static int igb_suspend(struct pci_dev *, pm_message_t); @@ -1352,6 +1358,10 @@ static const struct net_device_ops igb_netdev_ops = { .ndo_vlan_rx_register = igb_vlan_rx_register, .ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid, + .ndo_set_vf_mac = igb_ndo_set_vf_mac, + .ndo_set_vf_vlan = igb_ndo_set_vf_vlan, + .ndo_set_vf_tx_rate = igb_ndo_set_vf_bw, + .ndo_get_vf_config = igb_ndo_get_vf_config, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = igb_netpoll, #endif @@ -2479,7 +2489,8 @@ static void igb_rlpml_set(struct igb_adapter *adapter) wr32(E1000_RLPML, max_frame_size); } -static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn) +static inline void igb_set_vmolr(struct igb_adapter *adapter, + int vfn, bool aupe) { struct e1000_hw *hw = &adapter->hw; u32 vmolr; @@ -2492,8 +2503,11 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn) return; vmolr = rd32(E1000_VMOLR(vfn)); - vmolr |= E1000_VMOLR_AUPE | /* Accept untagged packets */ - E1000_VMOLR_STRVLAN; /* Strip vlan tags */ + vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */ + if (aupe) + vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */ + else + vmolr &= ~(E1000_VMOLR_AUPE); /* Tagged packets ONLY */ /* clear all bits that might not be set */ vmolr &= ~(E1000_VMOLR_BAM | E1000_VMOLR_RSSE); @@ -2564,7 +2578,7 @@ void igb_configure_rx_ring(struct igb_adapter *adapter, wr32(E1000_SRRCTL(reg_idx), srrctl); /* set filtering for VMDQ pools */ - igb_set_vmolr(adapter, reg_idx & 0x7); + igb_set_vmolr(adapter, reg_idx & 0x7, true); /* enable receive descriptor fetching */ rxdctl = rd32(E1000_RXDCTL(reg_idx)); @@ -4490,10 +4504,57 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) reg |= size; wr32(E1000_VMOLR(vf), reg); } - return 0; } } - return -1; + return 0; +} + +static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf) +{ + struct e1000_hw *hw = &adapter->hw; + + if (vid) + wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT)); + else + wr32(E1000_VMVIR(vf), 0); +} + +static int igb_ndo_set_vf_vlan(struct net_device *netdev, + int vf, u16 vlan, u8 qos) +{ + int err = 0; + struct igb_adapter *adapter = netdev_priv(netdev); + + if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7)) + return -EINVAL; + if (vlan || qos) { + err = igb_vlvf_set(adapter, vlan, !!vlan, vf); + if (err) + goto out; + igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf); + igb_set_vmolr(adapter, vf, !vlan); + adapter->vf_data[vf].pf_vlan = vlan; + adapter->vf_data[vf].pf_qos = qos; + dev_info(&adapter->pdev->dev, + "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf); + if (test_bit(__IGB_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, + "The VF VLAN has been set," + " but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, + "Bring the PF device up before" + " attempting to use the VF device.\n"); + } + } else { + igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan, + false, vf); + igb_set_vmvir(adapter, vlan, vf); + igb_set_vmolr(adapter, vf, true); + adapter->vf_data[vf].pf_vlan = 0; + adapter->vf_data[vf].pf_qos = 0; + } +out: + return err; } static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf) @@ -4506,15 +4567,21 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf) static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf) { - /* clear all flags */ - adapter->vf_data[vf].flags = 0; + /* clear flags */ + adapter->vf_data[vf].flags &= ~(IGB_VF_FLAG_PF_SET_MAC); adapter->vf_data[vf].last_nack = jiffies; /* reset offloads to defaults */ - igb_set_vmolr(adapter, vf); + igb_set_vmolr(adapter, vf, true); /* reset vlans for device */ igb_clear_vf_vfta(adapter, vf); + if (adapter->vf_data[vf].pf_vlan) + igb_ndo_set_vf_vlan(adapter->netdev, vf, + adapter->vf_data[vf].pf_vlan, + adapter->vf_data[vf].pf_qos); + else + igb_clear_vf_vfta(adapter, vf); /* reset multicast table array for vf */ adapter->vf_data[vf].num_vf_mc_hashes = 0; @@ -4528,7 +4595,8 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf) unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses; /* generate a new mac address as we were hotplug removed/added */ - random_ether_addr(vf_mac); + if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC)) + random_ether_addr(vf_mac); /* process remaining reset events */ igb_vf_reset(adapter, vf); @@ -4641,7 +4709,10 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf) retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf); break; case E1000_VF_SET_VLAN: - retval = igb_set_vf_vlan(adapter, msgbuf, vf); + if (adapter->vf_data[vf].pf_vlan) + retval = -1; + else + retval = igb_set_vf_vlan(adapter, msgbuf, vf); break; default: dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]); @@ -6003,6 +6074,43 @@ static int igb_set_vf_mac(struct igb_adapter *adapter, return 0; } +static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count)) + return -EINVAL; + adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC; + dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf); + dev_info(&adapter->pdev->dev, "Reload the VF driver to make this" + " change effective."); + if (test_bit(__IGB_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, "The VF MAC address has been set," + " but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, "Bring the PF device up before" + " attempting to use the VF device.\n"); + } + return igb_set_vf_mac(adapter, vf, mac); +} + +static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate) +{ + return -EOPNOTSUPP; +} + +static int igb_ndo_get_vf_config(struct net_device *netdev, + int vf, struct ifla_vf_info *ivi) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + if (vf >= adapter->vfs_allocated_count) + return -EINVAL; + ivi->vf = vf; + memcpy(&ivi->mac, adapter->vf_data[vf].vf_mac_addresses, ETH_ALEN); + ivi->tx_rate = 0; + ivi->vlan = adapter->vf_data[vf].pf_vlan; + ivi->qos = adapter->vf_data[vf].pf_qos; + return 0; +} + static void igb_vmm_control(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; -- GitLab From e4af1af900328e4aa71cd5df75bb22669ab11522 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:05 +0000 Subject: [PATCH 2009/3892] tg3: Give MSI-X vec 1 rx backlog space RSS ring 1 is responsible for submitting new rx buffers to the hardware on behalf of all the other RSS rx return rings. Up until now this ring submitted its new rx buffers to the producer ring directly. The following patch will require that this ring have a place to put backlogged rx packets. As a consequence, it can no longer submit new buffers to the producer ring. This patch adds code to allocate an extra shadow producer ring for this RSS ring and adds RSS ring 1 to the list of rings needing buffer transfers. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 46 +++++++++++++++++++++------------------------- drivers/net/tg3.h | 2 +- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d29282f01c23..661e9ddd1401 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4733,7 +4733,7 @@ next_pkt_nopost: tw32_rx_mbox(tnapi->consmbox, sw_idx); /* Refill RX ring(s). */ - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) || tnapi == &tp->napi[1]) { + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) { if (work_mask & RXD_OPAQUE_RING_STD) { tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE; tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, @@ -4755,7 +4755,8 @@ next_pkt_nopost: tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE; tpr->rx_jmb_prod_idx = jmb_prod_idx % TG3_RX_JUMBO_RING_SIZE; - napi_schedule(&tp->napi[1].napi); + if (tnapi != &tp->napi[1]) + napi_schedule(&tp->napi[1].napi); } return received; @@ -4893,25 +4894,23 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) work_done += tg3_rx(tnapi, budget - work_done); if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) { + struct tg3_rx_prodring_set *dpr = &tp->prodring[0]; int i; - u32 std_prod_idx = tp->prodring[0].rx_std_prod_idx; - u32 jmb_prod_idx = tp->prodring[0].rx_jmb_prod_idx; + u32 std_prod_idx = dpr->rx_std_prod_idx; + u32 jmb_prod_idx = dpr->rx_jmb_prod_idx; - for (i = 2; i < tp->irq_cnt; i++) - tg3_rx_prodring_xfer(tp, tnapi->prodring, - tp->napi[i].prodring); + for (i = 1; i < tp->irq_cnt; i++) + tg3_rx_prodring_xfer(tp, dpr, tp->napi[i].prodring); wmb(); - if (std_prod_idx != tp->prodring[0].rx_std_prod_idx) { - u32 mbox = TG3_RX_STD_PROD_IDX_REG; - tw32_rx_mbox(mbox, tp->prodring[0].rx_std_prod_idx); - } + if (std_prod_idx != dpr->rx_std_prod_idx) + tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, + dpr->rx_std_prod_idx); - if (jmb_prod_idx != tp->prodring[0].rx_jmb_prod_idx) { - u32 mbox = TG3_RX_JMB_PROD_IDX_REG; - tw32_rx_mbox(mbox, tp->prodring[0].rx_jmb_prod_idx); - } + if (jmb_prod_idx != dpr->rx_jmb_prod_idx) + tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, + dpr->rx_jmb_prod_idx); mmiowb(); } @@ -6173,8 +6172,7 @@ static void tg3_free_rings(struct tg3 *tp) dev_kfree_skb_any(skb); } - if (tp->irq_cnt == 1 || j != tp->irq_cnt - 1) - tg3_rx_prodring_free(tp, &tp->prodring[j]); + tg3_rx_prodring_free(tp, &tp->prodring[j]); } } @@ -6210,9 +6208,10 @@ static int tg3_init_rings(struct tg3 *tp) if (tnapi->rx_rcb) memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - if ((tp->irq_cnt == 1 || i != tp->irq_cnt - 1) && - tg3_rx_prodring_alloc(tp, &tp->prodring[i])) + if (tg3_rx_prodring_alloc(tp, &tp->prodring[i])) { + tg3_free_rings(tp); return -ENOMEM; + } } return 0; @@ -6259,7 +6258,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->hw_stats = NULL; } - for (i = 0; i < (tp->irq_cnt == 1 ? 1 : tp->irq_cnt - 1); i++) + for (i = 0; i < tp->irq_cnt; i++) tg3_rx_prodring_fini(tp, &tp->prodring[i]); } @@ -6271,7 +6270,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) { int i; - for (i = 0; i < (tp->irq_cnt == 1 ? 1 : tp->irq_cnt - 1); i++) { + for (i = 0; i < tp->irq_cnt; i++) { if (tg3_rx_prodring_init(tp, &tp->prodring[i])) goto err_out; } @@ -6336,10 +6335,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) break; } - if (tp->irq_cnt == 1) - tnapi->prodring = &tp->prodring[0]; - else if (i) - tnapi->prodring = &tp->prodring[i - 1]; + tnapi->prodring = &tp->prodring[i]; /* * If multivector RSS is enabled, vector 0 does not handle diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index e7f6214a1680..88a87bb618c0 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2717,7 +2717,7 @@ struct tg3 { struct vlan_group *vlgrp; #endif - struct tg3_rx_prodring_set prodring[TG3_IRQ_MAX_VECS - 1]; + struct tg3_rx_prodring_set prodring[TG3_IRQ_MAX_VECS]; /* begin "everything else" cacheline(s) section */ -- GitLab From e92967bfb1f4fa7da7c425df9239c4bb615dec30 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:06 +0000 Subject: [PATCH 2010/3892] tg3: Prevent rx producer ring overruns When operating in RSS mode, it is possible for one rx return ring to submit enough rx buffers back to the hardware such that it inadvertently overwrites data needed by another rx return ring. This patch addresses the problem by looking for non-NULL skb pointers in the rx_[std|jmb]_buffers rings that parallel the rx producer rings. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 661e9ddd1401..a46c26764ba7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4552,6 +4552,12 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi, pci_unmap_addr(src_map, mapping)); dest_desc->addr_hi = src_desc->addr_hi; dest_desc->addr_lo = src_desc->addr_lo; + + /* Ensure that the update to the skb happens after the physical + * addresses have been transferred to the new BD location. + */ + smp_wmb(); + src_map->skb = NULL; } @@ -4816,6 +4822,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, si = spr->rx_std_cons_idx; di = dpr->rx_std_prod_idx; + for (i = di; i < di + cpycnt; i++) { + if (dpr->rx_std_buffers[i].skb) { + cpycnt = i - di; + break; + } + } + + if (!cpycnt) + break; + + /* Ensure that updates to the rx_std_buffers ring and the + * shadowed hardware producer ring from tg3_recycle_skb() are + * ordered correctly WRT the skb check above. + */ + smp_rmb(); + memcpy(&dpr->rx_std_buffers[di], &spr->rx_std_buffers[si], cpycnt * sizeof(struct ring_info)); @@ -4856,6 +4878,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, si = spr->rx_jmb_cons_idx; di = dpr->rx_jmb_prod_idx; + for (i = di; i < di + cpycnt; i++) { + if (dpr->rx_jmb_buffers[i].skb) { + cpycnt = i - di; + break; + } + } + + if (!cpycnt) + break; + + /* Ensure that updates to the rx_jmb_buffers ring and the + * shadowed hardware producer ring from tg3_recycle_skb() are + * ordered correctly WRT the skb check above. + */ + smp_rmb(); + memcpy(&dpr->rx_jmb_buffers[di], &spr->rx_jmb_buffers[si], cpycnt * sizeof(struct ring_info)); -- GitLab From f89f38b8ec3171664314669a1396ab70b43e8961 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:07 +0000 Subject: [PATCH 2011/3892] tg3: Unwedge stuck MSI-X vectors The previous patch changed the code so that new rx buffer submissions to the hardware stall if a new submission would overwrite data needed by an unserviced rx packet. On very busy 5717 and 57765 asic rev devices, there is a corner case where the hardware will fail to assert an MSI-X interrupt for rx traffic. If that vector's interrupt never has another reason to assert, any rx buffers held will never be serviced. If the buffers are never serviced and the hardware consumes all the available rx packets for other rx rings, deadlock will result. The most reliable and least intrusive way to work around the problem is to detect the case where new submissions would overwrite existing data and force all rx interrupt vectors to fire. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 29 +++++++++++++++++++---------- drivers/net/tg3.h | 1 + 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a46c26764ba7..c140e1bf6e02 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -642,7 +642,6 @@ static void tg3_disable_ints(struct tg3 *tp) static void tg3_enable_ints(struct tg3 *tp) { int i; - u32 coal_now = 0; tp->irq_sync = 0; wmb(); @@ -650,13 +649,14 @@ static void tg3_enable_ints(struct tg3 *tp) tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); + tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE; for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - coal_now |= tnapi->coal_now; + tp->coal_now |= tnapi->coal_now; } /* Force an initial interrupt */ @@ -664,8 +664,9 @@ static void tg3_enable_ints(struct tg3 *tp) (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); else - tw32(HOSTCC_MODE, tp->coalesce_mode | - HOSTCC_MODE_ENABLE | coal_now); + tw32(HOSTCC_MODE, tp->coal_now); + + tp->coal_now &= ~(tp->napi[0].coal_now | tp->napi[1].coal_now); } static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) @@ -4794,12 +4795,12 @@ static void tg3_poll_link(struct tg3 *tp) } } -static void tg3_rx_prodring_xfer(struct tg3 *tp, - struct tg3_rx_prodring_set *dpr, - struct tg3_rx_prodring_set *spr) +static int tg3_rx_prodring_xfer(struct tg3 *tp, + struct tg3_rx_prodring_set *dpr, + struct tg3_rx_prodring_set *spr) { u32 si, di, cpycnt, src_prod_idx; - int i; + int i, err = 0; while (1) { src_prod_idx = spr->rx_std_prod_idx; @@ -4825,6 +4826,7 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, for (i = di; i < di + cpycnt; i++) { if (dpr->rx_std_buffers[i].skb) { cpycnt = i - di; + err = -ENOSPC; break; } } @@ -4881,6 +4883,7 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, for (i = di; i < di + cpycnt; i++) { if (dpr->rx_jmb_buffers[i].skb) { cpycnt = i - di; + err = -ENOSPC; break; } } @@ -4911,6 +4914,8 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) % TG3_RX_JUMBO_RING_SIZE; } + + return err; } static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) @@ -4933,12 +4938,13 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) { struct tg3_rx_prodring_set *dpr = &tp->prodring[0]; - int i; + int i, err = 0; u32 std_prod_idx = dpr->rx_std_prod_idx; u32 jmb_prod_idx = dpr->rx_jmb_prod_idx; for (i = 1; i < tp->irq_cnt; i++) - tg3_rx_prodring_xfer(tp, dpr, tp->napi[i].prodring); + err |= tg3_rx_prodring_xfer(tp, dpr, + tp->napi[i].prodring); wmb(); @@ -4951,6 +4957,9 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) dpr->rx_jmb_prod_idx); mmiowb(); + + if (err) + tw32_f(HOSTCC_MODE, tp->coal_now); } return work_done; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 88a87bb618c0..cc8bf7d6823a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2699,6 +2699,7 @@ struct tg3 { struct net_device *dev; struct pci_dev *pdev; + u32 coal_now; u32 msg_enable; /* begin "tx thread" cacheline section */ -- GitLab From 6b10c1653e425e30cff7f41d0e6f9743bfa9810f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:08 +0000 Subject: [PATCH 2012/3892] tg3: Fix 57765 A0 bootcode race condition On A0 revision of 57765 asic rev devices, the bootcode will perform some hardware operations, after the magic signature is presented, that will collide with setup operations performed by the driver. The best way to avoid the contention is to have the driver delay an additional 10 milliseconds. B0 revisions of the chip will make this workaround unnecessary. Signed-off-by: Matt Carlson Signed-off-by: Benjamin Li Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 7 +++++++ drivers/net/tg3.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c140e1bf6e02..2c5e1b7e1088 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6721,6 +6721,13 @@ static int tg3_poll_fw(struct tg3 *tp) tp->dev->name); } + if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) { + /* The 57765 A0 needs a little more + * time to do some important work. + */ + mdelay(10); + } + return 0; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index cc8bf7d6823a..46db4ad46bbc 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -110,6 +110,7 @@ #define CHIPREV_ID_57780_A0 0x57780000 #define CHIPREV_ID_57780_A1 0x57780001 #define CHIPREV_ID_5717_A0 0x05717000 +#define CHIPREV_ID_57765_A0 0x57785000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 -- GitLab From 0339e4e3effeae71e2b19c6340ef9672fb7a2cb3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:09 +0000 Subject: [PATCH 2013/3892] tg3: Turn off multiple DMA reads for 5717 The 5717's DMA read engine has a bug when initiating multiple DMA reads across the PCIe bus. This patch disables the feature. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +++ drivers/net/tg3.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2c5e1b7e1088..673ea314aa18 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7915,6 +7915,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_LNGREAD_ENAB); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 46db4ad46bbc..a8fb53aaf742 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1258,6 +1258,7 @@ #define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000 #define RDMAC_MODE_FIFO_SIZE_128 0x00020000 #define RDMAC_MODE_FIFO_LONG_BURST 0x00030000 +#define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000 #define RDMAC_MODE_IPV4_LSO_EN 0x08000000 #define RDMAC_MODE_IPV6_LSO_EN 0x10000000 #define RDMAC_STATUS 0x00004804 -- GitLab From 603f11738cee4d46a2a1d394ae80d718f8d37cba Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:10 +0000 Subject: [PATCH 2014/3892] tg3: Reset phy during bringup when using phylib The driver puts the phy into low-power mode when it releases the device. If the device were to be reacquired, the phy needs a reset to bring it back to full powered operation. This patch allows phylib-enabled devices to reset the phy. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 673ea314aa18..33dfb7fda8cc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7595,8 +7595,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_abort_hw(tp, 1); } - if (reset_phy && - !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) + if (reset_phy) tg3_phy_reset(tp); err = tg3_chip_reset(tp); -- GitLab From c88734054e787542ea093b02120e324e92cad882 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:11 +0000 Subject: [PATCH 2015/3892] tg3: Fix napi assignments in loopback test The 57765 lacks TSS support. This renders the napi assignments incorrect in the loopback test function. This patch fixes the problem. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 33dfb7fda8cc..cb6967947c30 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10780,12 +10780,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) struct tg3_napi *tnapi, *rnapi; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; + tnapi = &tp->napi[0]; + rnapi = &tp->napi[0]; if (tp->irq_cnt > 1) { - tnapi = &tp->napi[1]; rnapi = &tp->napi[1]; - } else { - tnapi = &tp->napi[0]; - rnapi = &tp->napi[0]; + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + tnapi = &tp->napi[1]; } coal_now = tnapi->coal_now | rnapi->coal_now; -- GitLab From 1061b7c56482310bbb8197045d51e2986afabfce Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:12 +0000 Subject: [PATCH 2016/3892] tg3: Fix AC131 loopback test errors for 5785 The AC131 does not enable the forced transmit clock settings immediately. The workaround is to read the register again to get the setting to take effect. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 ++++++-- drivers/net/tg3.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cb6967947c30..128126a87c34 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10822,8 +10822,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); + tg3_writephy(tp, MII_TG3_FET_PTEST, + MII_TG3_FET_PTEST_FRC_TX_LINK | + MII_TG3_FET_PTEST_FRC_TX_LOCK); + /* The write needs to be flushed for the AC131 */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_readphy(tp, MII_TG3_FET_PTEST, &val); mac_mode |= MAC_MODE_PORT_MODE_MII; } else mac_mode |= MAC_MODE_PORT_MODE_GMII; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a8fb53aaf742..b4fd59623cfb 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2112,6 +2112,9 @@ /* Fast Ethernet Tranceiver definitions */ #define MII_TG3_FET_PTEST 0x17 +#define MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000 +#define MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800 + #define MII_TG3_FET_TEST 0x1f #define MII_TG3_FET_SHADOW_EN 0x0080 -- GitLab From b3b3f04fb587ecb61b5baa6c1c5f0e666fd12d73 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 12 Feb 2010 14:47:13 +0000 Subject: [PATCH 2017/3892] tg3: Update driver version to 3.107 This patch updates the tg3 version to 3.107. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 128126a87c34..385434ff3960 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.106" -#define DRV_MODULE_RELDATE "January 12, 2010" +#define DRV_MODULE_VERSION "3.107" +#define DRV_MODULE_RELDATE "February 12, 2010" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- GitLab From cfd3d8dcf7b4fc783db0806ac3936a7b44735bf7 Mon Sep 17 00:00:00 2001 From: Greg Alexander Date: Sat, 13 Feb 2010 02:02:25 -0500 Subject: [PATCH 2018/3892] ALSA: hda - Add support for Lenovo IdeaPad U150 Add patch for the Conexant 5066 HDA codec to support the Lenovo IdeaPad U150 Signed-off-by: Greg Alexander Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_conexant.c | 130 ++++++++++++++++++- 2 files changed, 127 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 8f06f20096f4..0c7ebef62893 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -288,6 +288,7 @@ Conexant 5066 laptop Basic Laptop config (default) dell-laptop Dell laptops olpc-xo-1_5 OLPC XO 1.5 + ideapad Lenovo IdeaPad U150 STAC9200 ======== diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 745e35992144..194a28c54992 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -113,7 +113,8 @@ struct conexant_spec { unsigned int dell_automute; unsigned int port_d_mode; - unsigned int dell_vostro; + unsigned int dell_vostro:1; + unsigned int ideapad:1; unsigned int ext_mic_present; unsigned int recording; @@ -2167,6 +2168,34 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) } } +/* toggle input of built-in digital mic and mic jack appropriately */ +static void cxt5066_ideapad_automic(struct hda_codec *codec) +{ + unsigned int present; + + struct hda_verb ext_mic_present[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb ext_mic_absent[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + + present = snd_hda_jack_detect(codec, 0x1b); + if (present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent); + } +} + /* mute internal speaker if HP is plugged */ static void cxt5066_hp_automute(struct hda_codec *codec) { @@ -2216,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) } } +/* unsolicited event for jack sensing */ +static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_ideapad_automic(codec); + break; + } +} + static const struct hda_input_mux cxt5066_analog_mic_boost = { .num_items = 5, .items = { @@ -2227,13 +2270,21 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { }, }; -static int cxt5066_set_mic_boost(struct hda_codec *codec) +static void cxt5066_set_mic_boost(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - return snd_hda_codec_write_cache(codec, 0x17, 0, + snd_hda_codec_write_cache(codec, 0x17, 0, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | cxt5066_analog_mic_boost.items[spec->mic_boost].index); + if (spec->ideapad) { + /* adjust the internal mic as well...it is not through 0x17 */ + snd_hda_codec_write_cache(codec, 0x23, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | + cxt5066_analog_mic_boost. + items[spec->mic_boost].index); + } } static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, @@ -2664,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { { } /* end */ }; +static struct hda_verb cxt5066_init_verbs_ideapad[] = { + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ + + /* Speakers */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* HP, Amp */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ + + /* Audio input selector */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ + + /* SPDIF route: PCM */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* internal microphone */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ + + /* EAPD */ + {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + { } /* end */ +}; + static struct hda_verb cxt5066_init_verbs_portd_lo[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } /* end */ @@ -2680,6 +2781,8 @@ static int cxt5066_init(struct hda_codec *codec) cxt5066_hp_automute(codec); if (spec->dell_vostro) cxt5066_vostro_automic(codec); + else if (spec->ideapad) + cxt5066_ideapad_automic(codec); } cxt5066_set_mic_boost(codec); return 0; @@ -2705,6 +2808,7 @@ enum { CXT5066_DELL_LAPTOP, /* Dell Laptop */ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ + CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_MODELS }; @@ -2712,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", - [CXT5066_DELL_VOSTO] = "dell-vostro" + [CXT5066_DELL_VOSTO] = "dell-vostro", + [CXT5066_IDEAPAD] = "ideapad", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -2722,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), {} }; @@ -2810,6 +2916,22 @@ static int patch_cxt5066(struct hda_codec *codec) /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ + spec->input_mux = NULL; + break; + case CXT5066_IDEAPAD: + codec->patch_ops.init = cxt5066_init; + codec->patch_ops.unsol_event = cxt5066_ideapad_event; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->init_verbs[0] = cxt5066_init_verbs_ideapad; + spec->port_d_mode = 0; + spec->ideapad = 1; + spec->mic_boost = 2; /* default 20dB gain */ + + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ spec->input_mux = NULL; break; -- GitLab From d67b1b03254c501fef371b0e5916c94a52bfc2c5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 6 Feb 2010 08:45:15 +0000 Subject: [PATCH 2019/3892] fs/xfs: Correct NULL test Test the value that was just allocated rather than the previously tested one. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ expression *x; expression e; identifier l; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != goto l; when != x = e when != &x *x == NULL // Signed-off-by: Julia Lawall Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/quota/xfs_qm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 8699e51cb45e..417e61e3d9dd 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -123,7 +123,7 @@ xfs_Gqm_init(void) goto out; gdqhash = kmem_zalloc_large(hsize); - if (!udqhash) + if (!gdqhash) goto out_free_udqhash; hsize /= sizeof(xfs_dqhash_t); -- GitLab From 0d1622d7f526311d87d7da2ee7dd14b73e45d3fc Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sat, 13 Feb 2010 10:33:12 +0200 Subject: [PATCH 2020/3892] x86-64, rwsem: Avoid store forwarding hazard in __downgrade_write The Intel Architecture Optimization Reference Manual states that a short load that follows a long store to the same object will suffer a store forwading penalty, particularly if the two accesses use different addresses. Trivially, a long load that follows a short store will also suffer a penalty. __downgrade_write() in rwsem incurs both penalties: the increment operation will not be able to reuse a recently-loaded rwsem value, and its result will not be reused by any recently-following rwsem operation. A comment in the code states that this is because 64-bit immediates are special and expensive; but while they are slightly special (only a single instruction allows them), they aren't expensive: a test shows that two loops, one loading a 32-bit immediate and one loading a 64-bit immediate, both take 1.5 cycles per iteration. Fix this by changing __downgrade_write to use the same add instruction on i386 and on x86_64, so that it uses the same operand size as all the other rwsem functions. Signed-off-by: Avi Kivity LKML-Reference: <1266049992-17419-1-git-send-email-avi@redhat.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/rwsem.h | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 10204a25bf93..606ede126972 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -232,34 +232,19 @@ static inline void __up_write(struct rw_semaphore *sem) */ static inline void __downgrade_write(struct rw_semaphore *sem) { -#ifdef CONFIG_X86_64 -# if RWSEM_WAITING_BIAS != -0x100000000 -# error "This code assumes RWSEM_WAITING_BIAS == -2^32" -# endif - - /* 64-bit immediates are special and expensive, and not needed here */ - asm volatile("# beginning __downgrade_write\n\t" - LOCK_PREFIX "incl 4(%1)\n\t" - /* transitions 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 */ - " jns 1f\n\t" - " call call_rwsem_downgrade_wake\n" - "1:\n\t" - "# ending __downgrade_write\n" - : "+m" (sem->count) - : "a" (sem) - : "memory", "cc"); -#else asm volatile("# beginning __downgrade_write\n\t" LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t" - /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ + /* + * transitions 0xZZZZ0001 -> 0xYYYY0001 (i386) + * 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 (x86_64) + */ " jns 1f\n\t" " call call_rwsem_downgrade_wake\n" "1:\n\t" "# ending __downgrade_write\n" : "+m" (sem->count) - : "a" (sem), "i" (-RWSEM_WAITING_BIAS) + : "a" (sem), "er" (-RWSEM_WAITING_BIAS) : "memory", "cc"); -#endif } /* -- GitLab From 414bb144efa2d2fe16d104d836d0d6b6e9265788 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 14 Dec 2009 13:08:41 +0100 Subject: [PATCH 2021/3892] x86, cpu: Print AMD virtualization features in /proc/cpuinfo This patch adds code to cpu initialization path to detect the extended virtualization features of AMD cpus to show them in /proc/cpuinfo. Signed-off-by: Joerg Roedel LKML-Reference: <1260792521-15212-1-git-send-email-joerg.roedel@amd.com> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/cpufeature.h | 4 ++++ arch/x86/kernel/cpu/addon_cpuid_features.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 637e1ec963c3..0cd82d068613 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -168,6 +168,10 @@ #define X86_FEATURE_FLEXPRIORITY (8*32+ 2) /* Intel FlexPriority */ #define X86_FEATURE_EPT (8*32+ 3) /* Intel Extended Page Table */ #define X86_FEATURE_VPID (8*32+ 4) /* Intel Virtual Processor ID */ +#define X86_FEATURE_NPT (8*32+5) /* AMD Nested Page Table support */ +#define X86_FEATURE_LBRV (8*32+6) /* AMD LBR Virtualization support */ +#define X86_FEATURE_SVML (8*32+7) /* "svm_lock" AMD SVM locking MSR */ +#define X86_FEATURE_NRIPS (8*32+8) /* "nrip_save" AMD SVM next_rip save */ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c index 468489b57aae..97ad79cdf688 100644 --- a/arch/x86/kernel/cpu/addon_cpuid_features.c +++ b/arch/x86/kernel/cpu/addon_cpuid_features.c @@ -32,6 +32,10 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) static const struct cpuid_bit __cpuinitconst cpuid_bits[] = { { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 }, { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006 }, + { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a }, + { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a }, + { X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a }, + { X86_FEATURE_NRIPS, CR_EDX, 3, 0x8000000a }, { 0, 0, 0, 0 } }; -- GitLab From 21b082ecdd7e6b8a5eba2cc013cae41b24de7f51 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 07:13:38 -0700 Subject: [PATCH 2022/3892] of: Remove old and misplaced function declarations The following functions don't exist: finish_device_tree() print_properties() prom_n_intr_cells() prom_get_irq_senses() The following functions are in drivers/of/base.c, so the declaration belongs in of.h instead of of_fdt.h of_machine_is_compatible() prom_add_property() prom_remove_property() prom_update_property() Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- include/linux/of.h | 8 ++++++++ include/linux/of_fdt.h | 10 ---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/linux/of.h b/include/linux/of.h index fa5571b6e219..5c7b6a64acd9 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -180,6 +180,14 @@ extern int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const char *cells_name, int index, struct device_node **out_node, const void **out_args); +extern int of_machine_is_compatible(const char *compat); + +extern int prom_add_property(struct device_node* np, struct property* prop); +extern int prom_remove_property(struct device_node *np, struct property *prop); +extern int prom_update_property(struct device_node *np, + struct property *newprop, + struct property *oldprop); + #if defined(CONFIG_OF_DYNAMIC) /* For updating the device tree at runtime */ extern void of_attach_node(struct device_node *); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 0007187ab59b..c9cb8a7bc065 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -95,18 +95,8 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data); /* Other Prototypes */ -extern void finish_device_tree(void); extern void unflatten_device_tree(void); extern void early_init_devtree(void *); -extern int of_machine_is_compatible(const char *compat); -extern void print_properties(struct device_node *node); -extern int prom_n_intr_cells(struct device_node* np); -extern void prom_get_irq_senses(unsigned char *senses, int off, int max); -extern int prom_add_property(struct device_node* np, struct property* prop); -extern int prom_remove_property(struct device_node *np, struct property *prop); -extern int prom_update_property(struct device_node *np, - struct property *newprop, - struct property *oldprop); #endif /* __ASSEMBLY__ */ #endif /* _LINUX_OF_FDT_H */ -- GitLab From 7c540d9e3da38c3d1c15fb8059e4577a84ac0066 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sun, 14 Feb 2010 07:13:41 -0700 Subject: [PATCH 2023/3892] proc_devtree: fix THIS_MODULE without module.h Commit e22f628395432b967f2f505858c64450f7835365 introduced a build breakage for ARM devtree work: the THIS_MODULE macro was added, but we don't have module.h This change adds the necessary #include to get THIS_MODULE defined. While we could just replace it with NULL (PROC_FS is a bool, not a tristate), using THIS_MODULE will prevent unexpected breakage if we ever do compile this as a module. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- fs/proc/proc_devtree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 0ec45110e15e..f8650dce74fb 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "internal.h" -- GitLab From 9dfbf207802c7e8cda9d081a8d750b50633c82d2 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sun, 14 Feb 2010 07:13:43 -0700 Subject: [PATCH 2024/3892] of: protect linux/of.h with CONFIG_OF For platforms that have CONFIG_OF optional, we need to make the contents of linux/of.h conditional on CONFIG_OF. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- include/linux/of.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/of.h b/include/linux/of.h index 5c7b6a64acd9..48b0ee6d0f76 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -22,6 +22,8 @@ #include +#ifdef CONFIG_OF + typedef u32 phandle; typedef u32 ihandle; @@ -194,4 +196,5 @@ extern void of_attach_node(struct device_node *); extern void of_detach_node(struct device_node *); #endif +#endif /* CONFIG_OF */ #endif /* _LINUX_OF_H */ -- GitLab From 4ef7b373df330bc0ff037dc4792d373c9346375f Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sun, 14 Feb 2010 07:13:47 -0700 Subject: [PATCH 2025/3892] of/flattree: Don't assume HAVE_LMB We don't always have lmb available, so make arches provide an early_init_dt_alloc_memory_arch() to handle the allocation of memory in the fdt code. When we don't have lmb.h included, we need asm/page.h for __va. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- arch/microblaze/kernel/prom.c | 5 +++++ arch/powerpc/kernel/prom.c | 5 +++++ drivers/of/fdt.c | 9 ++++++--- include/linux/of_fdt.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index 050b7993c51c..a7dcaf092200 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -55,6 +55,11 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) lmb_add(base, size); } +u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return lmb_alloc(size, align); +} + #ifdef CONFIG_EARLY_PRINTK /* MS this is Microblaze specifig function */ static int __init early_init_dt_scan_serial(unsigned long node, diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 43c78d74ddcb..5bbbdb29f603 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -510,6 +510,11 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memstart_addr = min((u64)memstart_addr, base); } +u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return lmb_alloc(size, align); +} + #ifdef CONFIG_BLK_DEV_INITRD void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b51f797d9d9d..406757a9d7ea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -10,16 +10,18 @@ */ #include -#include #include #include #include - +#include +#include #ifdef CONFIG_PPC #include #endif /* CONFIG_PPC */ +#include + int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -560,7 +562,8 @@ void __init unflatten_device_tree(void) pr_debug(" size is %lx, allocating...\n", size); /* Allocate memory for the expanded device tree */ - mem = lmb_alloc(size + 4, __alignof__(struct device_node)); + mem = early_init_dt_alloc_memory_arch(size + 4, + __alignof__(struct device_node)); mem = (unsigned long) __va(mem); ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index c9cb8a7bc065..a1ca92ccb0ff 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -78,6 +78,7 @@ extern void early_init_dt_check_for_initrd(unsigned long node); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data); extern void early_init_dt_add_memory_arch(u64 base, u64 size); +extern u64 early_init_dt_alloc_memory_arch(u64 size, u64 align); extern u64 dt_mem_next_cell(int s, __be32 **cellp); /* -- GitLab From 7c7b60cb87547b1664a4385c187f029bf514a737 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 07:13:50 -0700 Subject: [PATCH 2026/3892] of: put default string compare and #a/s-cell values into common header Most architectures don't need to change these. Put them into common code to eliminate some duplication Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- arch/microblaze/include/asm/prom.h | 7 ------- arch/powerpc/include/asm/prom.h | 7 ------- include/linux/of.h | 13 +++++++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 6c6b386cf3c6..ddc5c57eb240 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -26,13 +26,6 @@ #include #include -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 - -#define of_compat_cmp(s1, s2, l) strncasecmp((s1), (s2), (l)) -#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) -#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) - extern struct device_node *of_chosen; #define HAVE_ARCH_DEVTREE_FIXUPS diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index f384db815ea8..4a5070edb4d3 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -23,13 +23,6 @@ #include #include -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 - -#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) -#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) -#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) - extern struct device_node *of_chosen; #define HAVE_ARCH_DEVTREE_FIXUPS diff --git a/include/linux/of.h b/include/linux/of.h index 48b0ee6d0f76..5cd284002bf1 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -116,6 +116,19 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) #include +/* Default #address and #size cells. Allow arch asm/prom.h to override */ +#if !defined(OF_ROOT_NODE_ADDR_CELLS_DEFAULT) +#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 +#endif + +/* Default string compare functions, Allow arch asm/prom.h to override */ +#if !defined(of_compat_cmp) +#define of_compat_cmp(s1, s2, l) strncasecmp((s1), (s2), (l)) +#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) +#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) +#endif + /* flag descriptions */ #define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ #define OF_DETACHED 2 /* node has been detached from the device tree */ -- GitLab From 22d5579e66101162fd1119f2e7f4f999ca8b48c7 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 07:13:52 -0700 Subject: [PATCH 2027/3892] of: remove unused extern reference to devtree_lock Neither the powerpc nor the microblaze code use devtree_lock anymore. Remove the extern reference. Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- arch/microblaze/include/asm/prom.h | 2 -- arch/powerpc/kernel/prom.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index ddc5c57eb240..8b1ebd39971a 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -30,8 +30,6 @@ extern struct device_node *of_chosen; #define HAVE_ARCH_DEVTREE_FIXUPS -extern rwlock_t devtree_lock; /* temporary while merging */ - /* Other Prototypes */ extern int early_uartlite_console(void); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 5bbbdb29f603..4869c937b6cf 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -67,8 +67,6 @@ int __initdata iommu_force_on; unsigned long tce_alloc_start, tce_alloc_end; #endif -extern rwlock_t devtree_lock; /* temporary while merging */ - /* export that to outside world */ struct device_node *of_chosen; -- GitLab From fc0bdae49d810e4cb32d7b547bc6d4dfb08f9e2e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 07:13:55 -0700 Subject: [PATCH 2028/3892] of: move definition of of_chosen into common code. Rather than defining of_chosen in each arch, it can be defined for all in driver/of/base.c Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- arch/microblaze/include/asm/prom.h | 2 -- arch/microblaze/kernel/prom.c | 3 --- arch/powerpc/include/asm/prom.h | 2 -- arch/powerpc/kernel/prom.c | 3 --- drivers/of/base.c | 1 + include/linux/of.h | 1 + 6 files changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 8b1ebd39971a..aa1a437ac87d 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -26,8 +26,6 @@ #include #include -extern struct device_node *of_chosen; - #define HAVE_ARCH_DEVTREE_FIXUPS /* Other Prototypes */ diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index a7dcaf092200..a15ef6d67ca9 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -42,9 +42,6 @@ #include #include -/* export that to outside world */ -struct device_node *of_chosen; - void __init early_init_dt_scan_chosen_arch(unsigned long node) { /* No Microblaze specific code here */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 4a5070edb4d3..7f9a50aab157 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -23,8 +23,6 @@ #include #include -extern struct device_node *of_chosen; - #define HAVE_ARCH_DEVTREE_FIXUPS #ifdef CONFIG_PPC32 diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4869c937b6cf..43238b2054b6 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -67,9 +67,6 @@ int __initdata iommu_force_on; unsigned long tce_alloc_start, tce_alloc_end; #endif -/* export that to outside world */ -struct device_node *of_chosen; - static int __init early_parse_mem(char *p) { if (!p) diff --git a/drivers/of/base.c b/drivers/of/base.c index 873479a21c80..cb96888d1427 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -23,6 +23,7 @@ #include struct device_node *allnodes; +struct device_node *of_chosen; /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. diff --git a/include/linux/of.h b/include/linux/of.h index 5cd284002bf1..d34cc5d9d81e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -66,6 +66,7 @@ struct device_node { /* Pointer for first entry in chain of all nodes. */ extern struct device_node *allnodes; +extern struct device_node *of_chosen; static inline int of_node_check_flag(struct device_node *n, unsigned long flag) { -- GitLab From 0d351c3e932c2e155ef5e4c3f5b87223abd4eea6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 14:13:57 -0700 Subject: [PATCH 2029/3892] of/sparc: Remove sparc-local declaration of allnodes and devtree_lock Both allnodes and devtree_lock are defined in common code. The extern declaration should be in the common header too so that the compiler can type check. allnodes is already in of.h, but devtree_lock should be declared there too. This patch removes the SPARC declarations and uses decls in of.h instead. Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek Acked-by: David S. Miller --- arch/sparc/kernel/prom.h | 3 --- include/linux/of.h | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index 453397fe5e14..a8591ef2636d 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -4,9 +4,6 @@ #include #include -extern struct device_node *allnodes; /* temporary while merging */ -extern rwlock_t devtree_lock; /* temporary while merging */ - extern void * prom_early_alloc(unsigned long size); extern void irq_trans_init(struct device_node *dp); diff --git a/include/linux/of.h b/include/linux/of.h index d34cc5d9d81e..f6d9cbc39c9c 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -67,6 +68,7 @@ struct device_node { /* Pointer for first entry in chain of all nodes. */ extern struct device_node *allnodes; extern struct device_node *of_chosen; +extern rwlock_t devtree_lock; static inline int of_node_check_flag(struct device_node *n, unsigned long flag) { -- GitLab From df0edeb59eb559be0bee53452fda2f5cc0ae133f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 14 Feb 2010 14:14:00 -0700 Subject: [PATCH 2030/3892] of: remove undefined request_OF_resource & release_OF_resource Neither request_OF_resource or release_OF_resource are defined anywhere. Remove the declarations. Signed-off-by: Grant Likely Acked-by: Benjamin Herrenschmidt Acked-by: Michal Simek --- arch/microblaze/include/asm/prom.h | 4 ---- arch/powerpc/include/asm/prom.h | 5 ----- 2 files changed, 9 deletions(-) diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index aa1a437ac87d..03f45a963204 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -31,10 +31,6 @@ /* Other Prototypes */ extern int early_uartlite_console(void); -extern struct resource *request_OF_resource(struct device_node *node, - int index, const char *name_postfix); -extern int release_OF_resource(struct device_node *node, int index); - /* * OF address retreival & translation */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 7f9a50aab157..ddd408a93b5a 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -39,11 +39,6 @@ extern struct device_node* pci_device_to_OF_node(struct pci_dev *); extern void pci_create_OF_bus_map(void); #endif -extern struct resource *request_OF_resource(struct device_node* node, - int index, const char* name_postfix); -extern int release_OF_resource(struct device_node* node, int index); - - /* * OF address retreival & translation */ -- GitLab From 59778fb6c402d48b1efa154e0e79d5e94726365e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 12 Feb 2010 06:23:07 +0100 Subject: [PATCH 2031/3892] ARM: 5932/1: ux500: fix DEBUG_LL/earlyprintk Add a static mapping for the UART and correct its virtual address in debug-macro.S, to make DEBUG_LL/earlyprintk work. Acked-by: Srinidhi Kasagar Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- arch/arm/mach-ux500/cpu-u8500.c | 1 + arch/arm/mach-ux500/include/mach/debug-macro.S | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-ux500/cpu-u8500.c b/arch/arm/mach-ux500/cpu-u8500.c index 5f05e5850f71..397bc1f9ed94 100644 --- a/arch/arm/mach-ux500/cpu-u8500.c +++ b/arch/arm/mach-ux500/cpu-u8500.c @@ -33,6 +33,7 @@ static struct platform_device *platform_devs[] __initdata = { /* minimum static i/o mapping required to boot U8500 platforms */ static struct map_desc u8500_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K), __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S index 8f21b6a95dce..8de225e02235 100644 --- a/arch/arm/mach-ux500/include/mach/debug-macro.S +++ b/arch/arm/mach-ux500/include/mach/debug-macro.S @@ -8,12 +8,13 @@ * published by the Free Software Foundation. * */ +#include + .macro addruart,rx mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @MMU enabled? - moveq \rx, #0x80000000 @MMU off, Physical address - movne \rx, #0xF0000000 @MMU on, Virtual address - orr \rx, \rx, #0x7000 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =U8500_UART2_BASE @ no, physical address + ldrne \rx, =IO_ADDRESS(U8500_UART2_BASE) @ yes, virtual address .endm #include -- GitLab From d40956665dc0c2fe2608268c2e7cff561ddcce11 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 14 Feb 2010 19:41:35 +0100 Subject: [PATCH 2032/3892] ARM: 5935/1: [U300] Fix the DMA configuration This fixes a few bugs in the DMA configuration for the COH 901 318 DMA engine used in U300. It also removes the directional parameter for each channel: separate DMA engine patches (submitted to the DMA engine maintainer) switches that mechanism over to using dynamic configuration of this, to handle bidirectional DMA channels. Cc: Dan Williams Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/core.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 6869052fe096..01b50313914c 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -475,7 +475,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x20, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -528,7 +527,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x20, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -582,7 +580,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x20, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -635,7 +632,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x20, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -706,7 +702,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x220, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -746,7 +741,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x220, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -799,7 +793,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x220, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -852,7 +845,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x220, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -905,7 +897,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x220, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -964,7 +955,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 0, .dev_addr = U300_MMCSD_BASE + 0x080, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -974,8 +964,8 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | COH901318_CX_CTRL_MASTER_MODE_M1RW | - COH901318_CX_CTRL_TCP_DISABLE | - COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | COH901318_CX_CTRL_HSP_ENABLE | COH901318_CX_CTRL_HSS_DISABLE | COH901318_CX_CTRL_DDMA_LEGACY, @@ -986,7 +976,7 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | COH901318_CX_CTRL_MASTER_MODE_M1RW | COH901318_CX_CTRL_TCP_ENABLE | - COH901318_CX_CTRL_TC_IRQ_DISABLE | + COH901318_CX_CTRL_TC_IRQ_ENABLE | COH901318_CX_CTRL_HSP_ENABLE | COH901318_CX_CTRL_HSS_DISABLE | COH901318_CX_CTRL_DDMA_LEGACY, @@ -996,7 +986,7 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | COH901318_CX_CTRL_MASTER_MODE_M1RW | - COH901318_CX_CTRL_TCP_ENABLE | + COH901318_CX_CTRL_TCP_DISABLE | COH901318_CX_CTRL_TC_IRQ_ENABLE | COH901318_CX_CTRL_HSP_ENABLE | COH901318_CX_CTRL_HSS_DISABLE | @@ -1039,7 +1029,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 1, .dev_addr = U300_PCM_I2S0_BASE + 0x14, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -1092,7 +1081,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 1, .dev_addr = U300_PCM_I2S0_BASE + 0x10, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -1145,7 +1133,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 1, .dev_addr = U300_PCM_I2S1_BASE + 0x14, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, @@ -1198,7 +1185,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = { .priority_high = 1, .dev_addr = U300_PCM_I2S1_BASE + 0x10, .param.config = COH901318_CX_CFG_CH_DISABLE | - COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY | COH901318_CX_CFG_LCR_DISABLE | COH901318_CX_CFG_TC_IRQ_ENABLE | COH901318_CX_CFG_BE_IRQ_ENABLE, -- GitLab From 8b833c506c05c498d4215e2c260be44225daf6de Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 5 Feb 2010 01:24:34 -0500 Subject: [PATCH 2033/3892] kprobes: Add mcount to the kprobes blacklist Since mcount function can be called from everywhere, it should be blacklisted. Moreover, the "mcount" symbol is a special symbol name. So, it is better to put it in the generic blacklist. Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Ananth N Mavinakayanahalli Cc: Steven Rostedt LKML-Reference: <20100205062433.3745.36726.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index b7df302a0204..c4b43430d393 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -93,6 +93,7 @@ static struct kprobe_blackpoint kprobe_blacklist[] = { {"native_get_debugreg",}, {"irq_entries_start",}, {"common_interrupt",}, + {"mcount",}, /* mcount can be called from everywhere */ {NULL} /* Terminator */ }; -- GitLab From 1a5778aa000ebfec7f07eed0ffa2852ffb5d16bb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 14 Feb 2010 22:35:47 -0800 Subject: [PATCH 2034/3892] net: Fix first line of kernel-doc for a few functions The function name must be followed by a space, hypen, space, and a short description. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- include/net/sock.h | 2 +- net/sunrpc/rpc_pipe.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ae836fded530..ba0f8e3a9cda 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -738,7 +738,7 @@ static inline struct sk_buff *skb_unshare(struct sk_buff *skb, } /** - * skb_peek + * skb_peek - peek at the head of an &sk_buff_head * @list_: list to peek at * * Peek an &sk_buff. Unlike most other operations you _MUST_ @@ -759,7 +759,7 @@ static inline struct sk_buff *skb_peek(struct sk_buff_head *list_) } /** - * skb_peek_tail + * skb_peek_tail - peek at the tail of an &sk_buff_head * @list_: list to peek at * * Peek an &sk_buff. Unlike most other operations you _MUST_ diff --git a/include/net/sock.h b/include/net/sock.h index c8d400063c16..580d51fa28e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1049,7 +1049,7 @@ extern void sk_common_release(struct sock *sk); extern void sock_init_data(struct socket *sock, struct sock *sk); /** - * sk_filter_release: Release a socket filter + * sk_filter_release - release a socket filter * @fp: filter to remove * * Remove a filter from a socket and release its resources. diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 49278f830367..9ea45383480e 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -78,7 +78,7 @@ rpc_timeout_upcall_queue(struct work_struct *work) } /** - * rpc_queue_upcall + * rpc_queue_upcall - queue an upcall message to userspace * @inode: inode of upcall pipe on which to queue given message * @msg: message to queue * -- GitLab From a1467085dcad8214bbb1d7edafbaa295cbd8c0e7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 14 Feb 2010 22:38:54 -0800 Subject: [PATCH 2035/3892] ethtool: Fix includes build break Based upon a patch by Oliver Hartkopp . Signed-off-by: David S. Miller --- include/linux/ethtool.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index a3cac53a0766..cca1c3de140d 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -14,7 +14,6 @@ #define _LINUX_ETHTOOL_H #include -#include /* This should work for both 32 and 64 bit userland. */ struct ethtool_cmd { @@ -409,6 +408,8 @@ struct ethtool_flash { #ifdef __KERNEL__ +#include + struct ethtool_rx_ntuple_flow_spec_container { struct ethtool_rx_ntuple_flow_spec fs; struct list_head list; -- GitLab From f10a1f2e7e93a35cb603b63090ff0e70a576a641 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Feb 2010 22:40:39 -0800 Subject: [PATCH 2036/3892] niu: Use pr_, netdev_ and netif_ macros Remove #define PFX Add pr_fmt(fmt) KBUILD_MODNAME ": " fmt Convert printks to pr_ Convert printks without levels to pr_cont Convert pr_ with np->dev to netdev_ Convert dev_ to netdev_ Convert niudbg to netif_printk Convert niuinfo, niuwarn macros to netif_(priv, type, dev... Coalesce long formats Convert embedded function names to "%s", __func__ Always use "%s()..." when __func__ is printed Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/niu.c | 703 ++++++++++++++++++++-------------------------- 1 file changed, 311 insertions(+), 392 deletions(-) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 7b52d9762b00..347788f11c74 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -3,6 +3,8 @@ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -33,7 +35,6 @@ #include "niu.h" #define DRV_MODULE_NAME "niu" -#define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "1.0" #define DRV_MODULE_RELDATE "Nov 14, 2008" @@ -89,21 +90,6 @@ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "NIU debug level"); -#define niudbg(TYPE, f, a...) \ -do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_DEBUG PFX f, ## a); \ -} while (0) - -#define niuinfo(TYPE, f, a...) \ -do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_INFO PFX f, ## a); \ -} while (0) - -#define niuwarn(TYPE, f, a...) \ -do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_WARNING PFX f, ## a); \ -} while (0) - #define niu_lock_parent(np, flags) \ spin_lock_irqsave(&np->parent->lock, flags) #define niu_unlock_parent(np, flags) \ @@ -135,10 +121,9 @@ static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg, nw64_mac(reg, bits); err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay); if (err) - dev_err(np->device, PFX "%s: bits (%llx) of register %s " - "would not clear, val[%llx]\n", - np->dev->name, (unsigned long long) bits, reg_name, - (unsigned long long) nr64_mac(reg)); + netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n", + (unsigned long long)bits, reg_name, + (unsigned long long)nr64_mac(reg)); return err; } @@ -175,10 +160,9 @@ static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg, err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay); if (err) - dev_err(np->device, PFX "%s: bits (%llx) of register %s " - "would not clear, val[%llx]\n", - np->dev->name, (unsigned long long) bits, reg_name, - (unsigned long long) nr64_ipp(reg)); + netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n", + (unsigned long long)bits, reg_name, + (unsigned long long)nr64_ipp(reg)); return err; } @@ -216,10 +200,9 @@ static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg, nw64(reg, bits); err = __niu_wait_bits_clear(np, reg, bits, limit, delay); if (err) - dev_err(np->device, PFX "%s: bits (%llx) of register %s " - "would not clear, val[%llx]\n", - np->dev->name, (unsigned long long) bits, reg_name, - (unsigned long long) nr64(reg)); + netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n", + (unsigned long long)bits, reg_name, + (unsigned long long)nr64(reg)); return err; } @@ -475,9 +458,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np) err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, ESR2_TI_PLL_CFG_L, pll_cfg); if (err) { - dev_err(np->device, PFX "NIU Port %d " - "serdes_init_niu_1g_serdes: " - "mdio write to ESR2_TI_PLL_CFG_L failed", np->port); + netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n", + np->port, __func__); return err; } @@ -486,9 +468,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np) err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, ESR2_TI_PLL_STS_L, pll_sts); if (err) { - dev_err(np->device, PFX "NIU Port %d " - "serdes_init_niu_1g_serdes: " - "mdio write to ESR2_TI_PLL_STS_L failed", np->port); + netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n", + np->port, __func__); return err; } @@ -531,8 +512,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np) } if ((sig & mask) != val) { - dev_err(np->device, PFX "Port %u signal bits [%08x] are not " - "[%08x]\n", np->port, (int) (sig & mask), (int) val); + netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n", + np->port, (int)(sig & mask), (int)val); return -ENODEV; } @@ -569,9 +550,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np) err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, ESR2_TI_PLL_CFG_L, pll_cfg & 0xffff); if (err) { - dev_err(np->device, PFX "NIU Port %d " - "serdes_init_niu_10g_serdes: " - "mdio write to ESR2_TI_PLL_CFG_L failed", np->port); + netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n", + np->port, __func__); return err; } @@ -580,9 +560,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np) err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, ESR2_TI_PLL_STS_L, pll_sts & 0xffff); if (err) { - dev_err(np->device, PFX "NIU Port %d " - "serdes_init_niu_10g_serdes: " - "mdio write to ESR2_TI_PLL_STS_L failed", np->port); + netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n", + np->port, __func__); return err; } @@ -639,9 +618,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np) } if ((sig & mask) != val) { - pr_info(PFX "NIU Port %u signal bits [%08x] are not " - "[%08x] for 10G...trying 1G\n", - np->port, (int) (sig & mask), (int) val); + pr_info("NIU Port %u signal bits [%08x] are not [%08x] for 10G...trying 1G\n", + np->port, (int)(sig & mask), (int)val); /* 10G failed, try initializing at 1G */ err = serdes_init_niu_1g_serdes(np); @@ -649,8 +627,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np) np->flags &= ~NIU_FLAGS_10G; np->mac_xcvr = MAC_XCVR_PCS; } else { - dev_err(np->device, PFX "Port %u 10G/1G SERDES " - "Link Failed \n", np->port); + netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n", + np->port); return -ENODEV; } } @@ -764,9 +742,8 @@ static int esr_reset(struct niu *np) if (err) return err; if (reset != 0) { - dev_err(np->device, PFX "Port %u ESR_RESET " - "did not clear [%08x]\n", - np->port, reset); + netdev_err(np->dev, "Port %u ESR_RESET did not clear [%08x]\n", + np->port, reset); return -ENODEV; } @@ -890,8 +867,8 @@ static int serdes_init_10g(struct niu *np) np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; return 0; } - dev_err(np->device, PFX "Port %u signal bits [%08x] are not " - "[%08x]\n", np->port, (int) (sig & mask), (int) val); + netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n", + np->port, (int)(sig & mask), (int)val); return -ENODEV; } if (np->flags & NIU_FLAGS_HOTPLUG_PHY) @@ -1039,8 +1016,8 @@ static int serdes_init_1g_serdes(struct niu *np) } if ((sig & mask) != val) { - dev_err(np->device, PFX "Port %u signal bits [%08x] are not " - "[%08x]\n", np->port, (int) (sig & mask), (int) val); + netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n", + np->port, (int)(sig & mask), (int)val); return -ENODEV; } @@ -1332,8 +1309,8 @@ static int bcm8704_reset(struct niu *np) break; } if (limit < 0) { - dev_err(np->device, PFX "Port %u PHY will not reset " - "(bmcr=%04x)\n", np->port, (err & 0xffff)); + netdev_err(np->dev, "Port %u PHY will not reset (bmcr=%04x)\n", + np->port, (err & 0xffff)); return -ENODEV; } return 0; @@ -1515,21 +1492,18 @@ static int xcvr_diag_bcm870x(struct niu *np) MII_STAT1000); if (err < 0) return err; - pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n", - np->port, err); + pr_info("Port %u PMA_PMD(MII_STAT1000) [%04x]\n", np->port, err); err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20); if (err < 0) return err; - pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n", - np->port, err); + pr_info("Port %u USER_DEV3(0x20) [%04x]\n", np->port, err); err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_NWAYTEST); if (err < 0) return err; - pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n", - np->port, err); + pr_info("Port %u PHYXS(MII_NWAYTEST) [%04x]\n", np->port, err); #endif /* XXX dig this out it might not be so useful XXX */ @@ -1555,11 +1529,11 @@ static int xcvr_diag_bcm870x(struct niu *np) if (analog_stat0 != 0x03fc) { if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) { - pr_info(PFX "Port %u cable not connected " - "or bad cable.\n", np->port); + pr_info("Port %u cable not connected or bad cable\n", + np->port); } else if (analog_stat0 == 0x639c) { - pr_info(PFX "Port %u optical module is bad " - "or missing.\n", np->port); + pr_info("Port %u optical module is bad or missing\n", + np->port); } } @@ -1699,8 +1673,8 @@ static int mii_reset(struct niu *np) break; } if (limit < 0) { - dev_err(np->device, PFX "Port %u MII would not reset, " - "bmcr[%04x]\n", np->port, err); + netdev_err(np->dev, "Port %u MII would not reset, bmcr[%04x]\n", + np->port, err); return -ENODEV; } @@ -1895,7 +1869,7 @@ static int mii_init_common(struct niu *np) return err; bmsr = err; - pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", + pr_info("Port %u after MII init bmcr[%04x] bmsr[%04x]\n", np->port, bmcr, bmsr); #endif @@ -1948,16 +1922,12 @@ static int niu_link_status_common(struct niu *np, int link_up) unsigned long flags; if (!netif_carrier_ok(dev) && link_up) { - niuinfo(LINK, "%s: Link is up at %s, %s duplex\n", - dev->name, - (lp->active_speed == SPEED_10000 ? - "10Gb/sec" : - (lp->active_speed == SPEED_1000 ? - "1Gb/sec" : - (lp->active_speed == SPEED_100 ? - "100Mbit/sec" : "10Mbit/sec"))), - (lp->active_duplex == DUPLEX_FULL ? - "full" : "half")); + netif_info(np, link, dev, "Link is up at %s, %s duplex\n", + lp->active_speed == SPEED_10000 ? "10Gb/sec" : + lp->active_speed == SPEED_1000 ? "1Gb/sec" : + lp->active_speed == SPEED_100 ? "100Mbit/sec" : + "10Mbit/sec", + lp->active_duplex == DUPLEX_FULL ? "full" : "half"); spin_lock_irqsave(&np->lock, flags); niu_init_xif(np); @@ -1966,7 +1936,7 @@ static int niu_link_status_common(struct niu *np, int link_up) netif_carrier_on(dev); } else if (netif_carrier_ok(dev) && !link_up) { - niuwarn(LINK, "%s: Link is down\n", dev->name); + netif_warn(np, link, dev, "Link is down\n"); spin_lock_irqsave(&np->lock, flags); niu_handle_led(np, 0); spin_unlock_irqrestore(&np->lock, flags); @@ -2232,8 +2202,8 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) } else { np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; *link_up_p = 0; - niuwarn(LINK, "%s: Hotplug PHY Removed\n", - np->dev->name); + netif_warn(np, link, np->dev, + "Hotplug PHY Removed\n"); } } out: @@ -2531,8 +2501,8 @@ static int serdes_init_10g_serdes(struct niu *np) np->flags &= ~NIU_FLAGS_10G; np->mac_xcvr = MAC_XCVR_PCS; } else { - dev_err(np->device, PFX "Port %u 10G/1G SERDES Link Failed \n", - np->port); + netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n", + np->port); return -ENODEV; } } @@ -3234,23 +3204,25 @@ static int fflp_early_init(struct niu *np) parent = np->parent; err = 0; if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) { - niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n", - np->port); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() Initting hw on port %u\n", + __func__, np->port); if (np->parent->plat_type != PLAT_TYPE_NIU) { fflp_reset(np); fflp_set_timings(np); err = fflp_disable_all_partitions(np); if (err) { - niudbg(PROBE, "fflp_disable_all_partitions " - "failed, err=%d\n", err); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "fflp_disable_all_partitions failed, err=%d\n", + err); goto out; } } err = tcam_early_init(np); if (err) { - niudbg(PROBE, "tcam_early_init failed, err=%d\n", - err); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "tcam_early_init failed, err=%d\n", err); goto out; } fflp_llcsnap_enable(np, 1); @@ -3260,22 +3232,24 @@ static int fflp_early_init(struct niu *np) err = tcam_flush_all(np); if (err) { - niudbg(PROBE, "tcam_flush_all failed, err=%d\n", - err); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "tcam_flush_all failed, err=%d\n", err); goto out; } if (np->parent->plat_type != PLAT_TYPE_NIU) { err = fflp_hash_clear(np); if (err) { - niudbg(PROBE, "fflp_hash_clear failed, " - "err=%d\n", err); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "fflp_hash_clear failed, err=%d\n", + err); goto out; } } vlan_tbl_clear(np); - niudbg(PROBE, "fflp_early_init: Success\n"); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() Success\n", __func__); parent->flags |= PARENT_FLGS_CLS_HWINIT; } out: @@ -3665,8 +3639,8 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) cons = rp->cons; - niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n", - np->dev->name, pkt_cnt, cons); + netif_printk(np, tx_done, KERN_DEBUG, np->dev, + "%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons); while (pkt_cnt--) cons = release_tx_packet(np, rp, cons); @@ -3714,11 +3688,12 @@ static inline void niu_sync_rx_discard_stats(struct niu *np, rp->rx_errors += misc & RXMISC_COUNT; if (unlikely(misc & RXMISC_OFLOW)) - dev_err(np->device, "rx-%d: Counter overflow " - "RXMISC discard\n", rx_channel); + dev_err(np->device, "rx-%d: Counter overflow RXMISC discard\n", + rx_channel); - niudbg(RX_ERR, "%s-rx-%d: MISC drop=%u over=%u\n", - np->dev->name, rx_channel, misc, misc-limit); + netif_printk(np, rx_err, KERN_DEBUG, np->dev, + "rx-%d: MISC drop=%u over=%u\n", + rx_channel, misc, misc-limit); } /* WRED (Weighted Random Early Discard) by hardware */ @@ -3728,11 +3703,11 @@ static inline void niu_sync_rx_discard_stats(struct niu *np, rp->rx_dropped += wred & RED_DIS_CNT_COUNT; if (unlikely(wred & RED_DIS_CNT_OFLOW)) - dev_err(np->device, "rx-%d: Counter overflow " - "WRED discard\n", rx_channel); + dev_err(np->device, "rx-%d: Counter overflow WRED discard\n", rx_channel); - niudbg(RX_ERR, "%s-rx-%d: WRED drop=%u over=%u\n", - np->dev->name, rx_channel, wred, wred-limit); + netif_printk(np, rx_err, KERN_DEBUG, np->dev, + "rx-%d: WRED drop=%u over=%u\n", + rx_channel, wred, wred-limit); } } @@ -3753,8 +3728,9 @@ static int niu_rx_work(struct napi_struct *napi, struct niu *np, mbox->rx_dma_ctl_stat = 0; mbox->rcrstat_a = 0; - niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n", - np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen); + netif_printk(np, rx_status, KERN_DEBUG, np->dev, + "%s(chan[%d]), stat[%llx] qlen=%d\n", + __func__, rp->rx_channel, (unsigned long long)stat, qlen); rcr_done = work_done = 0; qlen = min(qlen, budget); @@ -3791,8 +3767,8 @@ static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget) u32 rx_vec = (v0 & 0xffffffff); int i, work_done = 0; - niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n", - np->dev->name, (unsigned long long) v0); + netif_printk(np, intr, KERN_DEBUG, np->dev, + "%s() v0[%016llx]\n", __func__, (unsigned long long)v0); for (i = 0; i < np->num_tx_rings; i++) { struct tx_ring_info *rp = &np->tx_rings[i]; @@ -3837,39 +3813,38 @@ static int niu_poll(struct napi_struct *napi, int budget) static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp, u64 stat) { - dev_err(np->device, PFX "%s: RX channel %u errors ( ", - np->dev->name, rp->rx_channel); + netdev_err(np->dev, "RX channel %u errors ( ", rp->rx_channel); if (stat & RX_DMA_CTL_STAT_RBR_TMOUT) - printk("RBR_TMOUT "); + pr_cont("RBR_TMOUT "); if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR) - printk("RSP_CNT "); + pr_cont("RSP_CNT "); if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS) - printk("BYTE_EN_BUS "); + pr_cont("BYTE_EN_BUS "); if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR) - printk("RSP_DAT "); + pr_cont("RSP_DAT "); if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR) - printk("RCR_ACK "); + pr_cont("RCR_ACK "); if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR) - printk("RCR_SHA_PAR "); + pr_cont("RCR_SHA_PAR "); if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR) - printk("RBR_PRE_PAR "); + pr_cont("RBR_PRE_PAR "); if (stat & RX_DMA_CTL_STAT_CONFIG_ERR) - printk("CONFIG "); + pr_cont("CONFIG "); if (stat & RX_DMA_CTL_STAT_RCRINCON) - printk("RCRINCON "); + pr_cont("RCRINCON "); if (stat & RX_DMA_CTL_STAT_RCRFULL) - printk("RCRFULL "); + pr_cont("RCRFULL "); if (stat & RX_DMA_CTL_STAT_RBRFULL) - printk("RBRFULL "); + pr_cont("RBRFULL "); if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE) - printk("RBRLOGPAGE "); + pr_cont("RBRLOGPAGE "); if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE) - printk("CFIGLOGPAGE "); + pr_cont("CFIGLOGPAGE "); if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR) - printk("DC_FIDO "); + pr_cont("DC_FIDO "); - printk(")\n"); + pr_cont(")\n"); } static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) @@ -3883,9 +3858,9 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) err = -EINVAL; if (err) { - dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", - np->dev->name, rp->rx_channel, - (unsigned long long) stat); + netdev_err(np->dev, "RX channel %u error, stat[%llx]\n", + rp->rx_channel, + (unsigned long long) stat); niu_log_rxchan_errors(np, rp, stat); } @@ -3899,27 +3874,26 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp, u64 cs) { - dev_err(np->device, PFX "%s: TX channel %u errors ( ", - np->dev->name, rp->tx_channel); + netdev_err(np->dev, "TX channel %u errors ( ", rp->tx_channel); if (cs & TX_CS_MBOX_ERR) - printk("MBOX "); + pr_cont("MBOX "); if (cs & TX_CS_PKT_SIZE_ERR) - printk("PKT_SIZE "); + pr_cont("PKT_SIZE "); if (cs & TX_CS_TX_RING_OFLOW) - printk("TX_RING_OFLOW "); + pr_cont("TX_RING_OFLOW "); if (cs & TX_CS_PREF_BUF_PAR_ERR) - printk("PREF_BUF_PAR "); + pr_cont("PREF_BUF_PAR "); if (cs & TX_CS_NACK_PREF) - printk("NACK_PREF "); + pr_cont("NACK_PREF "); if (cs & TX_CS_NACK_PKT_RD) - printk("NACK_PKT_RD "); + pr_cont("NACK_PKT_RD "); if (cs & TX_CS_CONF_PART_ERR) - printk("CONF_PART "); + pr_cont("CONF_PART "); if (cs & TX_CS_PKT_PRT_ERR) - printk("PKT_PTR "); + pr_cont("PKT_PTR "); - printk(")\n"); + pr_cont(")\n"); } static int niu_tx_error(struct niu *np, struct tx_ring_info *rp) @@ -3930,12 +3904,11 @@ static int niu_tx_error(struct niu *np, struct tx_ring_info *rp) logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel)); logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel)); - dev_err(np->device, PFX "%s: TX channel %u error, " - "cs[%llx] logh[%llx] logl[%llx]\n", - np->dev->name, rp->tx_channel, - (unsigned long long) cs, - (unsigned long long) logh, - (unsigned long long) logl); + netdev_err(np->dev, "TX channel %u error, cs[%llx] logh[%llx] logl[%llx]\n", + rp->tx_channel, + (unsigned long long)cs, + (unsigned long long)logh, + (unsigned long long)logl); niu_log_txchan_errors(np, rp, cs); @@ -3954,9 +3927,8 @@ static int niu_mif_interrupt(struct niu *np) phy_mdint = 1; } - dev_err(np->device, PFX "%s: MIF interrupt, " - "stat[%llx] phy_mdint(%d)\n", - np->dev->name, (unsigned long long) mif_status, phy_mdint); + netdev_err(np->dev, "MIF interrupt, stat[%llx] phy_mdint(%d)\n", + (unsigned long long)mif_status, phy_mdint); return -ENODEV; } @@ -4081,41 +4053,40 @@ static int niu_mac_interrupt(struct niu *np) static void niu_log_device_error(struct niu *np, u64 stat) { - dev_err(np->device, PFX "%s: Core device errors ( ", - np->dev->name); + netdev_err(np->dev, "Core device errors ( "); if (stat & SYS_ERR_MASK_META2) - printk("META2 "); + pr_cont("META2 "); if (stat & SYS_ERR_MASK_META1) - printk("META1 "); + pr_cont("META1 "); if (stat & SYS_ERR_MASK_PEU) - printk("PEU "); + pr_cont("PEU "); if (stat & SYS_ERR_MASK_TXC) - printk("TXC "); + pr_cont("TXC "); if (stat & SYS_ERR_MASK_RDMC) - printk("RDMC "); + pr_cont("RDMC "); if (stat & SYS_ERR_MASK_TDMC) - printk("TDMC "); + pr_cont("TDMC "); if (stat & SYS_ERR_MASK_ZCP) - printk("ZCP "); + pr_cont("ZCP "); if (stat & SYS_ERR_MASK_FFLP) - printk("FFLP "); + pr_cont("FFLP "); if (stat & SYS_ERR_MASK_IPP) - printk("IPP "); + pr_cont("IPP "); if (stat & SYS_ERR_MASK_MAC) - printk("MAC "); + pr_cont("MAC "); if (stat & SYS_ERR_MASK_SMX) - printk("SMX "); + pr_cont("SMX "); - printk(")\n"); + pr_cont(")\n"); } static int niu_device_error(struct niu *np) { u64 stat = nr64(SYS_ERR_STAT); - dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n", - np->dev->name, (unsigned long long) stat); + netdev_err(np->dev, "Core device error, stat[%llx]\n", + (unsigned long long)stat); niu_log_device_error(np, stat); @@ -4197,8 +4168,8 @@ static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, RX_DMA_CTL_STAT_RCRTO); nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write); - niudbg(INTR, "%s: rxchan_intr stat[%llx]\n", - np->dev->name, (unsigned long long) stat); + netif_printk(np, intr, KERN_DEBUG, np->dev, + "%s() stat[%llx]\n", __func__, (unsigned long long)stat); } static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp, @@ -4206,8 +4177,8 @@ static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp, { rp->tx_cs = nr64(TX_CS(rp->tx_channel)); - niudbg(INTR, "%s: txchan_intr cs[%llx]\n", - np->dev->name, (unsigned long long) rp->tx_cs); + netif_printk(np, intr, KERN_DEBUG, np->dev, + "%s() cs[%llx]\n", __func__, (unsigned long long)rp->tx_cs); } static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0) @@ -4265,8 +4236,8 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id) u64 v0, v1, v2; if (netif_msg_intr(np)) - printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ", - lp, ldg); + printk(KERN_DEBUG KBUILD_MODNAME ": " "%s() ldg[%p](%d)", + __func__, lp, ldg); spin_lock_irqsave(&np->lock, flags); @@ -4275,11 +4246,13 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id) v2 = nr64(LDSV2(ldg)); if (netif_msg_intr(np)) - printk("v0[%llx] v1[%llx] v2[%llx]\n", + pr_cont(" v0[%llx] v1[%llx] v2[%llx]", (unsigned long long) v0, (unsigned long long) v1, (unsigned long long) v2); + pr_cont("\n"); + if (unlikely(!v0 && !v1 && !v2)) { spin_unlock_irqrestore(&np->lock, flags); return IRQ_NONE; @@ -4400,8 +4373,8 @@ static int niu_alloc_rx_ring_info(struct niu *np, if (!rp->mbox) return -ENOMEM; if ((unsigned long)rp->mbox & (64UL - 1)) { - dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " - "RXDMA mailbox %p\n", np->dev->name, rp->mbox); + netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA mailbox %p\n", + rp->mbox); return -EINVAL; } @@ -4411,8 +4384,8 @@ static int niu_alloc_rx_ring_info(struct niu *np, if (!rp->rcr) return -ENOMEM; if ((unsigned long)rp->rcr & (64UL - 1)) { - dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " - "RXDMA RCR table %p\n", np->dev->name, rp->rcr); + netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RCR table %p\n", + rp->rcr); return -EINVAL; } rp->rcr_table_size = MAX_RCR_RING_SIZE; @@ -4424,8 +4397,8 @@ static int niu_alloc_rx_ring_info(struct niu *np, if (!rp->rbr) return -ENOMEM; if ((unsigned long)rp->rbr & (64UL - 1)) { - dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " - "RXDMA RBR table %p\n", np->dev->name, rp->rbr); + netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RBR table %p\n", + rp->rbr); return -EINVAL; } rp->rbr_table_size = MAX_RBR_RING_SIZE; @@ -4458,8 +4431,8 @@ static int niu_alloc_tx_ring_info(struct niu *np, if (!rp->mbox) return -ENOMEM; if ((unsigned long)rp->mbox & (64UL - 1)) { - dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " - "TXDMA mailbox %p\n", np->dev->name, rp->mbox); + netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA mailbox %p\n", + rp->mbox); return -EINVAL; } @@ -4469,8 +4442,8 @@ static int niu_alloc_tx_ring_info(struct niu *np, if (!rp->descr) return -ENOMEM; if ((unsigned long)rp->descr & (64UL - 1)) { - dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " - "TXDMA descr table %p\n", np->dev->name, rp->descr); + netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA descr table %p\n", + rp->descr); return -EINVAL; } @@ -4726,10 +4699,8 @@ static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp) if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE | TX_RNG_CFIG_STADDR)) { - dev_err(np->device, PFX "%s: TX ring channel %d " - "DMA addr (%llx) is not aligned.\n", - np->dev->name, channel, - (unsigned long long) rp->descr_dma); + netdev_err(np->dev, "TX ring channel %d DMA addr (%llx) is not aligned\n", + channel, (unsigned long long)rp->descr_dma); return -EINVAL; } @@ -4746,10 +4717,8 @@ static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp) if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) || ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) { - dev_err(np->device, PFX "%s: TX ring channel %d " - "MBOX addr (%llx) is has illegal bits.\n", - np->dev->name, channel, - (unsigned long long) rp->mbox_dma); + netdev_err(np->dev, "TX ring channel %d MBOX addr (%llx) has invalid bits\n", + channel, (unsigned long long)rp->mbox_dma); return -EINVAL; } nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32); @@ -5146,9 +5115,8 @@ static int niu_zcp_read(struct niu *np, int index, u64 *data) err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, 1000, 100); if (err) { - dev_err(np->device, PFX "%s: ZCP read busy won't clear, " - "ZCP_RAM_ACC[%llx]\n", np->dev->name, - (unsigned long long) nr64(ZCP_RAM_ACC)); + netdev_err(np->dev, "ZCP read busy won't clear, ZCP_RAM_ACC[%llx]\n", + (unsigned long long)nr64(ZCP_RAM_ACC)); return err; } @@ -5160,9 +5128,8 @@ static int niu_zcp_read(struct niu *np, int index, u64 *data) err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, 1000, 100); if (err) { - dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, " - "ZCP_RAM_ACC[%llx]\n", np->dev->name, - (unsigned long long) nr64(ZCP_RAM_ACC)); + netdev_err(np->dev, "ZCP read busy2 won't clear, ZCP_RAM_ACC[%llx]\n", + (unsigned long long)nr64(ZCP_RAM_ACC)); return err; } @@ -5527,8 +5494,7 @@ static int niu_reset_tx_bmac(struct niu *np) udelay(100); } if (limit < 0) { - dev_err(np->device, PFX "Port %u TX BMAC would not reset, " - "BTXMAC_SW_RST[%llx]\n", + dev_err(np->device, "Port %u TX BMAC would not reset, BTXMAC_SW_RST[%llx]\n", np->port, (unsigned long long) nr64_mac(BTXMAC_SW_RST)); return -ENODEV; @@ -5629,12 +5595,11 @@ static int niu_reset_rx_xmac(struct niu *np) while (--limit >= 0) { if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST))) - break; + break; udelay(100); } if (limit < 0) { - dev_err(np->device, PFX "Port %u RX XMAC would not reset, " - "XRXMAC_SW_RST[%llx]\n", + dev_err(np->device, "Port %u RX XMAC would not reset, XRXMAC_SW_RST[%llx]\n", np->port, (unsigned long long) nr64_mac(XRXMAC_SW_RST)); return -ENODEV; @@ -5655,8 +5620,7 @@ static int niu_reset_rx_bmac(struct niu *np) udelay(100); } if (limit < 0) { - dev_err(np->device, PFX "Port %u RX BMAC would not reset, " - "BRXMAC_SW_RST[%llx]\n", + dev_err(np->device, "Port %u RX BMAC would not reset, BRXMAC_SW_RST[%llx]\n", np->port, (unsigned long long) nr64_mac(BRXMAC_SW_RST)); return -ENODEV; @@ -5960,11 +5924,9 @@ static void niu_disable_ipp(struct niu *np) } if (limit < 0 && (rd != 0 && wr != 1)) { - dev_err(np->device, PFX "%s: IPP would not quiesce, " - "rd_ptr[%llx] wr_ptr[%llx]\n", - np->dev->name, - (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR), - (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR)); + netdev_err(np->dev, "IPP would not quiesce, rd_ptr[%llx] wr_ptr[%llx]\n", + (unsigned long long)nr64_ipp(IPP_DFIFO_RD_PTR), + (unsigned long long)nr64_ipp(IPP_DFIFO_WR_PTR)); } val = nr64_ipp(IPP_CFIG); @@ -5981,12 +5943,12 @@ static int niu_init_hw(struct niu *np) { int i, err; - niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TXC\n"); niu_txc_enable_port(np, 1); niu_txc_port_dma_enable(np, 1); niu_txc_set_imask(np, 0); - niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TX channels\n"); for (i = 0; i < np->num_tx_rings; i++) { struct tx_ring_info *rp = &np->tx_rings[i]; @@ -5995,27 +5957,27 @@ static int niu_init_hw(struct niu *np) return err; } - niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize RX channels\n"); err = niu_init_rx_channels(np); if (err) goto out_uninit_tx_channels; - niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize classifier\n"); err = niu_init_classifier_hw(np); if (err) goto out_uninit_rx_channels; - niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize ZCP\n"); err = niu_init_zcp(np); if (err) goto out_uninit_rx_channels; - niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize IPP\n"); err = niu_init_ipp(np); if (err) goto out_uninit_rx_channels; - niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize MAC\n"); err = niu_init_mac(np); if (err) goto out_uninit_ipp; @@ -6023,16 +5985,16 @@ static int niu_init_hw(struct niu *np) return 0; out_uninit_ipp: - niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit IPP\n"); niu_disable_ipp(np); out_uninit_rx_channels: - niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit RX channels\n"); niu_stop_rx_channels(np); niu_reset_rx_channels(np); out_uninit_tx_channels: - niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name); + netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit TX channels\n"); niu_stop_tx_channels(np); niu_reset_tx_channels(np); @@ -6041,25 +6003,25 @@ out_uninit_tx_channels: static void niu_stop_hw(struct niu *np) { - niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable interrupts\n"); niu_enable_interrupts(np, 0); - niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable RX MAC\n"); niu_enable_rx_mac(np, 0); - niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable IPP\n"); niu_disable_ipp(np); - niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop TX channels\n"); niu_stop_tx_channels(np); - niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop RX channels\n"); niu_stop_rx_channels(np); - niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset TX channels\n"); niu_reset_tx_channels(np); - niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name); + netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset RX channels\n"); niu_reset_rx_channels(np); } @@ -6384,14 +6346,12 @@ static void niu_set_rx_mode(struct net_device *dev) netdev_for_each_uc_addr(ha, dev) { err = niu_set_alt_mac(np, index, ha->addr); if (err) - printk(KERN_WARNING PFX "%s: Error %d " - "adding alt mac %d\n", - dev->name, err, index); + netdev_warn(dev, "Error %d adding alt mac %d\n", + err, index); err = niu_enable_alt_mac(np, index, 1); if (err) - printk(KERN_WARNING PFX "%s: Error %d " - "enabling alt mac %d\n", - dev->name, err, index); + netdev_warn(dev, "Error %d enabling alt mac %d\n", + err, index); index++; } @@ -6404,9 +6364,8 @@ static void niu_set_rx_mode(struct net_device *dev) for (i = alt_start; i < niu_num_alt_addr(np); i++) { err = niu_enable_alt_mac(np, i, 0); if (err) - printk(KERN_WARNING PFX "%s: Error %d " - "disabling alt mac %d\n", - dev->name, err, i); + netdev_warn(dev, "Error %d disabling alt mac %d\n", + err, i); } } if (dev->flags & IFF_ALLMULTI) { @@ -6570,7 +6529,7 @@ static void niu_tx_timeout(struct net_device *dev) { struct niu *np = netdev_priv(dev); - dev_err(np->device, PFX "%s: Transmit timed out, resetting\n", + dev_err(np->device, "%s: Transmit timed out, resetting\n", dev->name); schedule_work(&np->reset_task); @@ -6672,8 +6631,7 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb, if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_tx_stop_queue(txq); - dev_err(np->device, PFX "%s: BUG! Tx ring full when " - "queue awake!\n", dev->name); + dev_err(np->device, "%s: BUG! Tx ring full when queue awake!\n", dev->name); rp->tx_errors++; return NETDEV_TX_BUSY; } @@ -7237,8 +7195,8 @@ static int niu_get_ethtool_tcam_entry(struct niu *np, tp = &parent->tcam[idx]; if (!tp->valid) { - pr_info(PFX "niu%d: %s entry [%d] invalid for idx[%d]\n", - parent->index, np->dev->name, (u16)nfc->fs.location, idx); + netdev_info(np->dev, "niu%d: entry [%d] invalid for idx[%d]\n", + parent->index, (u16)nfc->fs.location, idx); return -EINVAL; } @@ -7248,8 +7206,8 @@ static int niu_get_ethtool_tcam_entry(struct niu *np, ret = niu_class_to_ethflow(class, &fsp->flow_type); if (ret < 0) { - pr_info(PFX "niu%d: %s niu_class_to_ethflow failed\n", - parent->index, np->dev->name); + netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n", + parent->index); ret = -EINVAL; goto out; } @@ -7332,9 +7290,8 @@ static int niu_get_ethtool_tcam_all(struct niu *np, if (n_entries != cnt) { /* print warning, this should not happen */ - pr_info(PFX "niu%d: %s In niu_get_ethtool_tcam_all, " - "n_entries[%d] != cnt[%d]!!!\n\n", - np->parent->index, np->dev->name, n_entries, cnt); + netdev_info(np->dev, "niu%d: In %s(): n_entries[%d] != cnt[%d]!!!\n", + np->parent->index, __func__, n_entries, cnt); } return 0; @@ -7561,9 +7518,8 @@ static int niu_add_ethtool_tcam_entry(struct niu *np, } } if (!add_usr_cls) { - pr_info(PFX "niu%d: %s niu_add_ethtool_tcam_entry: " - "Could not find/insert class for pid %d\n", - parent->index, np->dev->name, uspec->proto); + netdev_info(np->dev, "niu%d: %s(): Could not find/insert class for pid %d\n", + parent->index, __func__, uspec->proto); ret = -EINVAL; goto out; } @@ -7596,9 +7552,8 @@ static int niu_add_ethtool_tcam_entry(struct niu *np, case AH_V6_FLOW: case ESP_V6_FLOW: /* Not yet implemented */ - pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " - "flow %d for IPv6 not implemented\n\n", - parent->index, np->dev->name, fsp->flow_type); + netdev_info(np->dev, "niu%d: In %s(): flow %d for IPv6 not implemented\n", + parent->index, __func__, fsp->flow_type); ret = -EINVAL; goto out; case IP_USER_FLOW: @@ -7607,17 +7562,15 @@ static int niu_add_ethtool_tcam_entry(struct niu *np, class); } else { /* Not yet implemented */ - pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " - "usr flow for IPv6 not implemented\n\n", - parent->index, np->dev->name); + netdev_info(np->dev, "niu%d: In %s(): usr flow for IPv6 not implemented\n", + parent->index, __func__); ret = -EINVAL; goto out; } break; default: - pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " - "Unknown flow type %d\n\n", - parent->index, np->dev->name, fsp->flow_type); + netdev_info(np->dev, "niu%d: In %s(): Unknown flow type %d\n", + parent->index, __func__, fsp->flow_type); ret = -EINVAL; goto out; } @@ -7627,10 +7580,9 @@ static int niu_add_ethtool_tcam_entry(struct niu *np, tp->assoc_data = TCAM_ASSOCDATA_DISC; } else { if (fsp->ring_cookie >= np->num_rx_rings) { - pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: " - "Invalid RX ring %lld\n\n", - parent->index, np->dev->name, - (long long) fsp->ring_cookie); + netdev_info(np->dev, "niu%d: In %s(): Invalid RX ring %lld\n", + parent->index, __func__, + (long long)fsp->ring_cookie); ret = -EINVAL; goto out; } @@ -7699,10 +7651,9 @@ static int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc) } } if (i == NIU_L3_PROG_CLS) { - pr_info(PFX "niu%d: %s In niu_del_ethtool_tcam_entry," - "Usr class 0x%llx not found \n", - parent->index, np->dev->name, - (unsigned long long) class); + netdev_info(np->dev, "niu%d: In %s(): Usr class 0x%llx not found\n", + parent->index, __func__, + (unsigned long long)class); ret = -EINVAL; goto out; } @@ -8001,9 +7952,7 @@ static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, * won't get any interrupts and that's painful to debug. */ if (nr64(LDG_NUM(ldn)) != ldg) { - dev_err(np->device, PFX "Port %u, mis-matched " - "LDG assignment " - "for ldn %d, should be %d is %llu\n", + dev_err(np->device, "Port %u, mis-matched LDG assignment for ldn %d, should be %d is %llu\n", np->port, ldn, ldg, (unsigned long long) nr64(LDG_NUM(ldn))); return -EINVAL; @@ -8056,7 +8005,7 @@ static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr) break; } while (limit--); if (!(frame & ESPC_PIO_STAT_READ_END)) { - dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + dev_err(np->device, "EEPROM read timeout frame[%llx]\n", (unsigned long long) frame); return -ENODEV; } @@ -8071,7 +8020,7 @@ static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr) break; } while (limit--); if (!(frame & ESPC_PIO_STAT_READ_END)) { - dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + dev_err(np->device, "EEPROM read timeout frame[%llx]\n", (unsigned long long) frame); return -ENODEV; } @@ -8152,8 +8101,9 @@ static void __devinit niu_vpd_parse_version(struct niu *np) s += i + 5; sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor); - niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n", - vpd->fcode_major, vpd->fcode_minor); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "VPD_SCAN: FCODE major(%d) minor(%d)\n", + vpd->fcode_major, vpd->fcode_minor); if (vpd->fcode_major > NIU_VPD_MIN_MAJOR || (vpd->fcode_major == NIU_VPD_MIN_MAJOR && vpd->fcode_minor >= NIU_VPD_MIN_MINOR)) @@ -8173,8 +8123,8 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, #define FOUND_MASK_PHY 0x00000020 #define FOUND_MASK_ALL 0x0000003f - niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n", - start, end); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "VPD_SCAN: start[%x] end[%x]\n", start, end); while (start < end) { int len, err, instance, type, prop_len; char namebuf[64]; @@ -8228,8 +8178,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, } if (max_len && prop_len > max_len) { - dev_err(np->device, PFX "Property '%s' length (%d) is " - "too long.\n", namebuf, prop_len); + dev_err(np->device, "Property '%s' length (%d) is too long\n", namebuf, prop_len); return -EINVAL; } @@ -8237,8 +8186,9 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, u32 off = start + 5 + err; int i; - niudbg(PROBE, "VPD_SCAN: Reading in property [%s] " - "len[%d]\n", namebuf, prop_len); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "VPD_SCAN: Reading in property [%s] len[%d]\n", + namebuf, prop_len); for (i = 0; i < prop_len; i++) *prop_buf++ = niu_pci_eeprom_read(np, off + i); } @@ -8402,8 +8352,7 @@ static void __devinit niu_pci_vpd_validate(struct niu *np) u8 val8; if (!is_valid_ether_addr(&vpd->local_mac[0])) { - dev_err(np->device, PFX "VPD MAC invalid, " - "falling back to SPROM.\n"); + dev_err(np->device, "VPD MAC invalid, falling back to SPROM\n"); np->flags &= ~NIU_FLAGS_VPD_VALID; return; @@ -8420,14 +8369,14 @@ static void __devinit niu_pci_vpd_validate(struct niu *np) np->flags &= ~NIU_FLAGS_10G; } if (np->flags & NIU_FLAGS_10G) - np->mac_xcvr = MAC_XCVR_XPCS; + np->mac_xcvr = MAC_XCVR_XPCS; } else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) { np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER | NIU_FLAGS_HOTPLUG_PHY); } else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { - dev_err(np->device, PFX "Illegal phy string [%s].\n", + dev_err(np->device, "Illegal phy string [%s]\n", np->vpd.phy_type); - dev_err(np->device, PFX "Falling back to SPROM.\n"); + dev_err(np->device, "Falling back to SPROM\n"); np->flags &= ~NIU_FLAGS_VPD_VALID; return; } @@ -8455,7 +8404,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) np->eeprom_len = len; - niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: Image size %llu\n", (unsigned long long)val); sum = 0; for (i = 0; i < len; i++) { @@ -8465,10 +8415,10 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) sum += (val >> 16) & 0xff; sum += (val >> 24) & 0xff; } - niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff)); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: Checksum %x\n", (int)(sum & 0xff)); if ((sum & 0xff) != 0xab) { - dev_err(np->device, PFX "Bad SPROM checksum " - "(%x, should be 0xab)\n", (int) (sum & 0xff)); + dev_err(np->device, "Bad SPROM checksum (%x, should be 0xab)\n", (int)(sum & 0xff)); return -EINVAL; } @@ -8491,11 +8441,12 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) ESPC_PHY_TYPE_PORT3_SHIFT; break; default: - dev_err(np->device, PFX "Bogus port number %u\n", + dev_err(np->device, "Bogus port number %u\n", np->port); return -EINVAL; } - niudbg(PROBE, "SPROM: PHY type %x\n", val8); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: PHY type %x\n", val8); switch (val8) { case ESPC_PHY_TYPE_1G_COPPER: @@ -8527,30 +8478,27 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) break; default: - dev_err(np->device, PFX "Bogus SPROM phy type %u\n", val8); + dev_err(np->device, "Bogus SPROM phy type %u\n", val8); return -EINVAL; } val = nr64(ESPC_MAC_ADDR0); - niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n", - (unsigned long long) val); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val); dev->perm_addr[0] = (val >> 0) & 0xff; dev->perm_addr[1] = (val >> 8) & 0xff; dev->perm_addr[2] = (val >> 16) & 0xff; dev->perm_addr[3] = (val >> 24) & 0xff; val = nr64(ESPC_MAC_ADDR1); - niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n", - (unsigned long long) val); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val); dev->perm_addr[4] = (val >> 0) & 0xff; dev->perm_addr[5] = (val >> 8) & 0xff; if (!is_valid_ether_addr(&dev->perm_addr[0])) { - dev_err(np->device, PFX "SPROM MAC address invalid\n"); - dev_err(np->device, PFX "[ \n"); - for (i = 0; i < 6; i++) - printk("%02x ", dev->perm_addr[i]); - printk("]\n"); + dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n", + dev->perm_addr); return -EINVAL; } @@ -8562,8 +8510,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); val = nr64(ESPC_MOD_STR_LEN); - niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n", - (unsigned long long) val); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: MOD_STR_LEN[%llu]\n", (unsigned long long)val); if (val >= 8 * 4) return -EINVAL; @@ -8578,8 +8526,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) np->vpd.model[val] = '\0'; val = nr64(ESPC_BD_MOD_STR_LEN); - niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n", - (unsigned long long) val); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: BD_MOD_STR_LEN[%llu]\n", (unsigned long long)val); if (val >= 4 * 4) return -EINVAL; @@ -8595,8 +8543,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np) np->vpd.mac_num = nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL; - niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n", - np->vpd.mac_num); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "SPROM: NUM_PORTS_MACS[%d]\n", np->vpd.mac_num); return 0; } @@ -8629,8 +8577,9 @@ static int __devinit niu_get_and_validate_port(struct niu *np) } } - niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n", - np->port, parent->num_ports); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() port[%d] num_ports[%d]\n", + __func__, np->port, parent->num_ports); if (np->port >= parent->num_ports) return -ENODEV; @@ -8659,14 +8608,12 @@ static int __devinit phy_record(struct niu_parent *parent, pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n", parent->index, id, - (type == PHY_TYPE_PMA_PMD ? - "PMA/PMD" : - (type == PHY_TYPE_PCS ? - "PCS" : "MII")), + type == PHY_TYPE_PMA_PMD ? "PMA/PMD" : + type == PHY_TYPE_PCS ? "PCS" : "MII", phy_port); if (p->cur[type] >= NIU_MAX_PORTS) { - printk(KERN_ERR PFX "Too many PHY ports.\n"); + pr_err("Too many PHY ports\n"); return -EINVAL; } idx = p->cur[type]; @@ -8727,8 +8674,7 @@ static void __devinit niu_n2_divide_channels(struct niu_parent *parent) parent->rxchan_per_port[i] = (16 / num_ports); parent->txchan_per_port[i] = (16 / num_ports); - pr_info(PFX "niu%d: Port %u [%u RX chans] " - "[%u TX chans]\n", + pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n", parent->index, i, parent->rxchan_per_port[i], parent->txchan_per_port[i]); @@ -8771,8 +8717,7 @@ static void __devinit niu_divide_channels(struct niu_parent *parent, parent->rxchan_per_port[i] = rx_chans_per_1g; parent->txchan_per_port[i] = tx_chans_per_1g; } - pr_info(PFX "niu%d: Port %u [%u RX chans] " - "[%u TX chans]\n", + pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n", parent->index, i, parent->rxchan_per_port[i], parent->txchan_per_port[i]); @@ -8781,23 +8726,20 @@ static void __devinit niu_divide_channels(struct niu_parent *parent, } if (tot_rx > NIU_NUM_RXCHAN) { - printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), " - "resetting to one per port.\n", + pr_err("niu%d: Too many RX channels (%d), resetting to one per port\n", parent->index, tot_rx); for (i = 0; i < num_ports; i++) parent->rxchan_per_port[i] = 1; } if (tot_tx > NIU_NUM_TXCHAN) { - printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), " - "resetting to one per port.\n", + pr_err("niu%d: Too many TX channels (%d), resetting to one per port\n", parent->index, tot_tx); for (i = 0; i < num_ports; i++) parent->txchan_per_port[i] = 1; } if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) { - printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, " - "RX[%d] TX[%d]\n", - parent->index, tot_rx, tot_tx); + pr_warning("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n", + parent->index, tot_rx, tot_tx); } } @@ -8825,18 +8767,18 @@ static void __devinit niu_divide_rdc_groups(struct niu_parent *parent, struct rdc_table *rt = &tp->tables[grp]; int slot; - pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ", + pr_info("niu%d: Port %d RDC tbl(%d) [ ", parent->index, i, tp->first_table_num + grp); for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) { rt->rxdma_channel[slot] = rdc_channel_base + this_channel_offset; - printk("%d ", rt->rxdma_channel[slot]); + pr_cont("%d ", rt->rxdma_channel[slot]); if (++this_channel_offset == num_channels) this_channel_offset = 0; } - printk("]\n"); + pr_cont("]\n"); } parent->rdc_default[i] = rdc_channel_base; @@ -8996,8 +8938,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) break; default: - printk(KERN_ERR PFX "Unsupported port config " - "10G[%d] 1G[%d]\n", + pr_err("Unsupported port config 10G[%d] 1G[%d]\n", num_10g, num_1g); return -EINVAL; } @@ -9015,8 +8956,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) return 0; unknown_vg_1g_port: - printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n", - lowest_1g); + pr_err("Cannot identify platform type, 1gport=%d\n", lowest_1g); return -EINVAL; } @@ -9025,8 +8965,8 @@ static int __devinit niu_probe_ports(struct niu *np) struct niu_parent *parent = np->parent; int err, i; - niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n", - parent->port_phy); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() port_phy[%08x]\n", __func__, parent->port_phy); if (parent->port_phy == PORT_PHY_UNKNOWN) { err = walk_phys(np, parent); @@ -9048,8 +8988,9 @@ static int __devinit niu_classifier_swstate_init(struct niu *np) { struct niu_classifier *cp = &np->clas; - niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", - np->parent->tcam_num_entries); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() num_tcam(%d)\n", + __func__, np->parent->tcam_num_entries); cp->tcam_top = (u16) np->port; cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports; @@ -9116,8 +9057,7 @@ static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np) break; default: - dev_err(np->device, PFX "Port %u is invalid, cannot " - "compute MAC block offset.\n", np->port); + dev_err(np->device, "Port %u is invalid, cannot compute MAC block offset\n", np->port); return -EINVAL; } @@ -9327,9 +9267,8 @@ static int __devinit niu_get_of_props(struct niu *np) phy_type = of_get_property(dp, "phy-type", &prop_len); if (!phy_type) { - dev_err(np->device, PFX "%s: OF node lacks " - "phy-type property\n", - dp->full_name); + netdev_err(dev, "%s: OF node lacks phy-type property\n", + dp->full_name); return -EINVAL; } @@ -9339,34 +9278,26 @@ static int __devinit niu_get_of_props(struct niu *np) strcpy(np->vpd.phy_type, phy_type); if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { - dev_err(np->device, PFX "%s: Illegal phy string [%s].\n", - dp->full_name, np->vpd.phy_type); + netdev_err(dev, "%s: Illegal phy string [%s]\n", + dp->full_name, np->vpd.phy_type); return -EINVAL; } mac_addr = of_get_property(dp, "local-mac-address", &prop_len); if (!mac_addr) { - dev_err(np->device, PFX "%s: OF node lacks " - "local-mac-address property\n", - dp->full_name); + netdev_err(dev, "%s: OF node lacks local-mac-address property\n", + dp->full_name); return -EINVAL; } if (prop_len != dev->addr_len) { - dev_err(np->device, PFX "%s: OF MAC address prop len (%d) " - "is wrong.\n", - dp->full_name, prop_len); + netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n", + dp->full_name, prop_len); } memcpy(dev->perm_addr, mac_addr, dev->addr_len); if (!is_valid_ether_addr(&dev->perm_addr[0])) { - int i; - - dev_err(np->device, PFX "%s: OF MAC address is invalid\n", - dp->full_name); - dev_err(np->device, PFX "%s: [ \n", - dp->full_name); - for (i = 0; i < 6; i++) - printk("%02x ", dev->perm_addr[i]); - printk("]\n"); + netdev_err(dev, "%s: OF MAC address is invalid\n", + dp->full_name); + netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr); return -EINVAL; } @@ -9414,8 +9345,8 @@ static int __devinit niu_get_invariants(struct niu *np) nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE); offset = niu_pci_vpd_offset(np); - niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n", - offset); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() VPD offset [%08x]\n", __func__, offset); if (offset) niu_pci_vpd_fetch(np, offset); nw64(ESPC_PIO_EN, 0); @@ -9575,7 +9506,8 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np, struct niu_parent *p; int i; - niudbg(PROBE, "niu_new_parent: Creating new parent.\n"); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() Creating new parent\n", __func__); plat_dev = platform_device_register_simple("niu", niu_parent_index, NULL, 0); @@ -9641,8 +9573,9 @@ static struct niu_parent * __devinit niu_get_parent(struct niu *np, struct niu_parent *p, *tmp; int port = np->port; - niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n", - ptype, port); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() platform_type[%u] port[%u]\n", + __func__, ptype, port); mutex_lock(&niu_parent_lock); p = NULL; @@ -9681,7 +9614,8 @@ static void niu_put_parent(struct niu *np) BUG_ON(!p || p->ports[port] != np); - niudbg(PROBE, "niu_put_parent: port[%u]\n", port); + netif_printk(np, probe, KERN_DEBUG, np->dev, + "%s() port[%u]\n", __func__, port); sprintf(port_name, "port%d", port); @@ -9772,7 +9706,7 @@ static struct net_device * __devinit niu_alloc_and_init( dev = alloc_etherdev_mq(sizeof(struct niu), NIU_NUM_TXCHAN); if (!dev) { - dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n"); + dev_err(gen_dev, "Etherdev alloc failed, aborting\n"); return NULL; } @@ -9858,30 +9792,26 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev, err = pci_enable_device(pdev); if (err) { - dev_err(&pdev->dev, PFX "Cannot enable PCI device, " - "aborting.\n"); + dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n"); return err; } if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, PFX "Cannot find proper PCI device " - "base addresses, aborting.\n"); + dev_err(&pdev->dev, "Cannot find proper PCI device base addresses, aborting\n"); err = -ENODEV; goto err_out_disable_pdev; } err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { - dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, " - "aborting.\n"); + dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n"); goto err_out_disable_pdev; } pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (pos <= 0) { - dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " - "aborting.\n"); + dev_err(&pdev->dev, "Cannot find PCI Express capability, aborting\n"); goto err_out_free_res; } @@ -9920,17 +9850,14 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev, dev->features |= NETIF_F_HIGHDMA; err = pci_set_consistent_dma_mask(pdev, dma_mask); if (err) { - dev_err(&pdev->dev, PFX "Unable to obtain 44 bit " - "DMA for consistent allocations, " - "aborting.\n"); + dev_err(&pdev->dev, "Unable to obtain 44 bit DMA for consistent allocations, aborting\n"); goto err_out_release_parent; } } if (err || dma_mask == DMA_BIT_MASK(32)) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { - dev_err(&pdev->dev, PFX "No usable DMA configuration, " - "aborting.\n"); + dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); goto err_out_release_parent; } } @@ -9939,8 +9866,7 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev, np->regs = pci_ioremap_bar(pdev, 0); if (!np->regs) { - dev_err(&pdev->dev, PFX "Cannot map device registers, " - "aborting.\n"); + dev_err(&pdev->dev, "Cannot map device registers, aborting\n"); err = -ENOMEM; goto err_out_release_parent; } @@ -9955,15 +9881,13 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev, err = niu_get_invariants(np); if (err) { if (err != -ENODEV) - dev_err(&pdev->dev, PFX "Problem fetching invariants " - "of chip, aborting.\n"); + dev_err(&pdev->dev, "Problem fetching invariants of chip, aborting\n"); goto err_out_iounmap; } err = register_netdev(dev); if (err) { - dev_err(&pdev->dev, PFX "Cannot register net device, " - "aborting.\n"); + dev_err(&pdev->dev, "Cannot register net device, aborting\n"); goto err_out_iounmap; } @@ -10157,7 +10081,7 @@ static int __devinit niu_of_probe(struct of_device *op, reg = of_get_property(op->node, "reg", NULL); if (!reg) { - dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n", + dev_err(&op->dev, "%s: No 'reg' property, aborting\n", op->node->full_name); return -ENODEV; } @@ -10186,8 +10110,7 @@ static int __devinit niu_of_probe(struct of_device *op, resource_size(&op->resource[1]), "niu regs"); if (!np->regs) { - dev_err(&op->dev, PFX "Cannot map device registers, " - "aborting.\n"); + dev_err(&op->dev, "Cannot map device registers, aborting\n"); err = -ENOMEM; goto err_out_release_parent; } @@ -10196,8 +10119,7 @@ static int __devinit niu_of_probe(struct of_device *op, resource_size(&op->resource[2]), "niu vregs-1"); if (!np->vir_regs_1) { - dev_err(&op->dev, PFX "Cannot map device vir registers 1, " - "aborting.\n"); + dev_err(&op->dev, "Cannot map device vir registers 1, aborting\n"); err = -ENOMEM; goto err_out_iounmap; } @@ -10206,8 +10128,7 @@ static int __devinit niu_of_probe(struct of_device *op, resource_size(&op->resource[3]), "niu vregs-2"); if (!np->vir_regs_2) { - dev_err(&op->dev, PFX "Cannot map device vir registers 2, " - "aborting.\n"); + dev_err(&op->dev, "Cannot map device vir registers 2, aborting\n"); err = -ENOMEM; goto err_out_iounmap; } @@ -10217,15 +10138,13 @@ static int __devinit niu_of_probe(struct of_device *op, err = niu_get_invariants(np); if (err) { if (err != -ENODEV) - dev_err(&op->dev, PFX "Problem fetching invariants " - "of chip, aborting.\n"); + dev_err(&op->dev, "Problem fetching invariants of chip, aborting\n"); goto err_out_iounmap; } err = register_netdev(dev); if (err) { - dev_err(&op->dev, PFX "Cannot register net device, " - "aborting.\n"); + dev_err(&op->dev, "Cannot register net device, aborting\n"); goto err_out_iounmap; } -- GitLab From 5659338c88963ea791118e5e11e314b24f90c3eb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 1 Feb 2010 07:21:02 +0000 Subject: [PATCH 2037/3892] vhost-net: switch to smp barriers vhost-net only uses memory barriers to control SMP effects (communication with userspace potentially running on a different CPU), so it should use SMP barriers and not mandatory barriers for memory access ordering, as suggested by Documentation/memory-barriers.txt Signed-off-by: Michael S. Tsirkin Acked-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/vhost/vhost.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c8c25dbc5857..6eb15259f5ae 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -685,7 +685,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, int i, r; /* Make sure data written is seen before log. */ - wmb(); + smp_wmb(); for (i = 0; i < log_num; ++i) { u64 l = min(log[i].len, len); r = log_write(vq->log_base, log[i].addr, l); @@ -884,7 +884,7 @@ unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, return vq->num; /* Only get avail ring entries after they have been exposed by guest. */ - rmb(); + smp_rmb(); /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ @@ -996,14 +996,14 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len) return -EFAULT; } /* Make sure buffer is written before we update index. */ - wmb(); + smp_wmb(); if (put_user(vq->last_used_idx + 1, &vq->used->idx)) { vq_err(vq, "Failed to increment used idx"); return -EFAULT; } if (unlikely(vq->log_used)) { /* Make sure data is seen before log. */ - wmb(); + smp_wmb(); log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring * (vq->last_used_idx % vq->num), sizeof *vq->used->ring); @@ -1060,7 +1060,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) } /* They could have slipped one in as we were doing that: make * sure it's written, then check again. */ - mb(); + smp_mb(); r = get_user(avail_idx, &vq->avail->idx); if (r) { vq_err(vq, "Failed to check avail idx at %p: %d\n", -- GitLab From 228da6c2e63b3b2064492b24ef83c07bcc48abbd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 14 Feb 2010 22:49:52 -0800 Subject: [PATCH 2038/3892] mac80211: Fix error introduced in netdev_mc_count() changes. Commit 4cd24eaf0c6ee7f0242e34ee77ec899f255e66b5 ("net: use netdev_mc_count and netdev_mc_empty when appropriate") added this hunk to net/mac80211/iface.c: __dev_addr_unsync(&local->mc_list, &local->mc_count, - &dev->mc_list, &dev->mc_count); + &dev->mc_list, dev->mc_count); which is definitely not correct, introduced a warning (reported by Stephen Rothwell): net/mac80211/iface.c: In function 'ieee80211_stop': net/mac80211/iface.c:416: warning: passing argument 4 of '__dev_addr_unsync' makes pointer from integer without a cast include/linux/netdevice.h:1967: note: expected 'int *' but argument is of type 'int' and is thus reverted here. Signed-off-by: David S. Miller --- net/mac80211/iface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f943f5fa7286..09fff4662e80 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -413,7 +413,7 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_lock_bh(dev); spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, - &dev->mc_list, dev->mc_count); + &dev->mc_list, &dev->mc_count); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); -- GitLab From 04c869735541c27dd137c55f35f8a18bb372bbe1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 15 Feb 2010 16:10:57 +0900 Subject: [PATCH 2039/3892] sh: Fix up legacy PMB mode offset calculation. The change for fixing up sh64 inadvertently inverted the logic for legacy PMB, fix that back up. Signed-off-by: Paul Mundt --- arch/sh/kernel/vmlinux.lds.S | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index dcf48915e2ea..0e66c7b30e0f 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -4,11 +4,9 @@ */ #ifdef CONFIG_SUPERH64 #define LOAD_OFFSET PAGE_OFFSET -#define MEMORY_OFFSET __MEMORY_START OUTPUT_ARCH(sh:sh5) #else #define LOAD_OFFSET 0 -#define MEMORY_OFFSET 0 OUTPUT_ARCH(sh) #endif @@ -16,6 +14,13 @@ OUTPUT_ARCH(sh) #include #include +#if defined(CONFIG_29BIT) || defined(CONFIG_SUPERH64) || \ + defined(CONFIG_PMB_LEGACY) + #define MEMORY_OFFSET __MEMORY_START +#else + #define MEMORY_OFFSET 0 +#endif + ENTRY(_start) SECTIONS { -- GitLab From 02b1bae5e1c0f810168037be0134685085e95e88 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 15 Feb 2010 00:07:00 -0800 Subject: [PATCH 2040/3892] niu: Refinements to kernel logging. Fix unconditional empty kerne log message every interrupt. Kill some informational log messages that are superfluous and anyways occur before the netdev is registered. Signed-off-by: David S. Miller --- drivers/net/niu.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 347788f11c74..5e604e305d95 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -3204,9 +3204,6 @@ static int fflp_early_init(struct niu *np) parent = np->parent; err = 0; if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) { - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() Initting hw on port %u\n", - __func__, np->port); if (np->parent->plat_type != PLAT_TYPE_NIU) { fflp_reset(np); fflp_set_timings(np); @@ -3248,8 +3245,6 @@ static int fflp_early_init(struct niu *np) vlan_tbl_clear(np); - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() Success\n", __func__); parent->flags |= PARENT_FLGS_CLS_HWINIT; } out: @@ -4246,13 +4241,11 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id) v2 = nr64(LDSV2(ldg)); if (netif_msg_intr(np)) - pr_cont(" v0[%llx] v1[%llx] v2[%llx]", + pr_cont(" v0[%llx] v1[%llx] v2[%llx]\n", (unsigned long long) v0, (unsigned long long) v1, (unsigned long long) v2); - pr_cont("\n"); - if (unlikely(!v0 && !v1 && !v2)) { spin_unlock_irqrestore(&np->lock, flags); return IRQ_NONE; @@ -8577,9 +8570,6 @@ static int __devinit niu_get_and_validate_port(struct niu *np) } } - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() port[%d] num_ports[%d]\n", - __func__, np->port, parent->num_ports); if (np->port >= parent->num_ports) return -ENODEV; @@ -8965,9 +8955,6 @@ static int __devinit niu_probe_ports(struct niu *np) struct niu_parent *parent = np->parent; int err, i; - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() port_phy[%08x]\n", __func__, parent->port_phy); - if (parent->port_phy == PORT_PHY_UNKNOWN) { err = walk_phys(np, parent); if (err) @@ -8988,10 +8975,6 @@ static int __devinit niu_classifier_swstate_init(struct niu *np) { struct niu_classifier *cp = &np->clas; - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() num_tcam(%d)\n", - __func__, np->parent->tcam_num_entries); - cp->tcam_top = (u16) np->port; cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports; cp->h1_init = 0xffffffff; @@ -9506,9 +9489,6 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np, struct niu_parent *p; int i; - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() Creating new parent\n", __func__); - plat_dev = platform_device_register_simple("niu", niu_parent_index, NULL, 0); if (IS_ERR(plat_dev)) @@ -9573,10 +9553,6 @@ static struct niu_parent * __devinit niu_get_parent(struct niu *np, struct niu_parent *p, *tmp; int port = np->port; - netif_printk(np, probe, KERN_DEBUG, np->dev, - "%s() platform_type[%u] port[%u]\n", - __func__, ptype, port); - mutex_lock(&niu_parent_lock); p = NULL; list_for_each_entry(tmp, &niu_parent_list, list) { -- GitLab From 19b50063780953563e3c3a2867c39aad7b9e64cf Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:34 +0100 Subject: [PATCH 2041/3892] ALSA: Echoaudio - Add firmware cache #1 Changes the way the firmware is passed through functions. When CONFIG_PM is enabled the firmware cannot be released because the driver will need it again to resume the card. With this patch the firmware is passed as an index of the struct firmware card_fw[] in place of a pointer. That same index is then used to locate the firmware in the firmware cache. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/darla20_dsp.c | 2 +- sound/pci/echoaudio/darla24_dsp.c | 2 +- sound/pci/echoaudio/echo3g_dsp.c | 2 +- sound/pci/echoaudio/echoaudio.c | 8 +++++- sound/pci/echoaudio/echoaudio.h | 6 ++--- sound/pci/echoaudio/echoaudio_3g.c | 5 ++-- sound/pci/echoaudio/echoaudio_dsp.c | 12 +++++---- sound/pci/echoaudio/gina20_dsp.c | 2 +- sound/pci/echoaudio/gina24_dsp.c | 18 ++++++------- sound/pci/echoaudio/indigo_dsp.c | 2 +- sound/pci/echoaudio/indigodj_dsp.c | 2 +- sound/pci/echoaudio/indigodjx_dsp.c | 2 +- sound/pci/echoaudio/indigoio_dsp.c | 2 +- sound/pci/echoaudio/indigoiox_dsp.c | 2 +- sound/pci/echoaudio/layla20_dsp.c | 7 +++--- sound/pci/echoaudio/layla24_dsp.c | 19 +++++++------- sound/pci/echoaudio/mia_dsp.c | 2 +- sound/pci/echoaudio/mona_dsp.c | 39 ++++++++++++++--------------- 18 files changed, 69 insertions(+), 65 deletions(-) diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 29043301ebb8..a44135d6acbb 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP]; + chip->dsp_code_to_load = FW_DARLA20_DSP; chip->spdif_status = GD_SPDIF_STATUS_UNDEF; chip->clock_state = GD_CLOCK_UNDEF; /* Since this card has no ASIC, mark it as loaded so everything diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 60228731841f..d681da180829 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP]; + chip->dsp_code_to_load = FW_DARLA24_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 57967e580571..f0071935c0cb 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP]; + chip->dsp_code_to_load = FW_ECHO3G_DSP; /* Load the DSP code and the ASIC on the PCI card and get what type of external box is attached */ diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1305f7ca02c3..78fc2637bfa6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -36,11 +36,15 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); + + static int get_firmware(const struct firmware **fw_entry, - const struct firmware *frm, struct echoaudio *chip) + struct echoaudio *chip, const short fw_index) { int err; char name[30]; + const struct firmware *frm = &card_fw[fw_index]; + DE_ACT(("firmware requested: %s\n", frm->data)); snprintf(name, sizeof(name), "ea/%s", frm->data); if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) @@ -48,6 +52,8 @@ static int get_firmware(const struct firmware **fw_entry, return err; } + + static void free_firmware(const struct firmware *fw_entry) { release_firmware(fw_entry); diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index f9490ae36c2e..be76ef3b829a 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -442,8 +442,8 @@ struct echoaudio { u16 device_id, subdevice_id; u16 *dsp_code; /* Current DSP code loaded, * NULL if nothing loaded */ - const struct firmware *dsp_code_to_load;/* DSP code to load */ - const struct firmware *asic_code; /* Current ASIC code */ + short dsp_code_to_load; /* DSP code to load */ + short asic_code; /* Current ASIC code */ u32 comm_page_phys; /* Physical address of the * memory seen by DSP */ volatile u32 __iomem *dsp_registers; /* DSP's register base */ @@ -464,7 +464,7 @@ static int load_firmware(struct echoaudio *chip); static int wait_handshake(struct echoaudio *chip); static int send_vector(struct echoaudio *chip, u32 command); static int get_firmware(const struct firmware **fw_entry, - const struct firmware *frm, struct echoaudio *chip); + struct echoaudio *chip, const short fw_index); static void free_firmware(const struct firmware *fw_entry); #ifdef ECHOCARD_HAS_MIDI diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index e32a74897921..658db44ef746 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip) /* Give the DSP a few milliseconds to settle down */ mdelay(2); - err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, - &card_fw[FW_3G_ASIC]); + err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC); if (err < 0) return err; - chip->asic_code = &card_fw[FW_3G_ASIC]; + chip->asic_code = FW_3G_ASIC; /* Now give the new ASIC some time to set up */ msleep(1000); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 4df51ef5e095..031ef7e9da91 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip) #ifdef ECHOCARD_HAS_ASIC /* Load ASIC code - done after the DSP is loaded */ -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic) +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) { const struct firmware *fw; int err; u32 i, size; u8 *code; - if ((err = get_firmware(&fw, asic, chip)) < 0) { + err = get_firmware(&fw, chip, asic); + if (err < 0) { snd_printk(KERN_WARNING "Firmware not found !\n"); return err; } @@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip) return 0; } - if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) { + i = get_firmware(&fw, chip, FW_361_LOADER); + if (i < 0) { snd_printk(KERN_WARNING "Firmware not found !\n"); return i; } @@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip) chip->dsp_code = NULL; } - if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0) + err = get_firmware(&fw, chip, chip->dsp_code_to_load); + if (err < 0) return err; err = load_dsp(chip, (u16 *)fw->data); free_firmware(fw); diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index 3f1e7475faea..c5de88b6792d 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP]; + chip->dsp_code_to_load = FW_GINA20_DSP; chip->spdif_status = GD_SPDIF_STATUS_UNDEF; chip->clock_state = GD_CLOCK_UNDEF; /* Since this card has no ASIC, mark it as loaded so everything diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 2fef37a2a5b9..093dd7ba0e81 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -64,13 +63,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) /* Gina24 comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) { - chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP]; + chip->dsp_code_to_load = FW_GINA24_361_DSP; chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; } else { - chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP]; + chip->dsp_code_to_load = FW_GINA24_301_DSP; chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | @@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip) { u32 control_reg; int err; - const struct firmware *fw; + short asic; if (chip->asic_loaded) return 1; @@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip) /* Pick the correct ASIC for '301 or '361 Gina24 */ if (chip->device_id == DEVICE_ID_56361) - fw = &card_fw[FW_GINA24_361_ASIC]; + asic = FW_GINA24_361_ASIC; else - fw = &card_fw[FW_GINA24_301_ASIC]; + asic = FW_GINA24_301_ASIC; - if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0) + err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic); + if (err < 0) return err; - chip->asic_code = fw; + chip->asic_code = asic; /* Now give the new ASIC a little time to set up */ mdelay(10); diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 0b2cd9c86277..8799d2e6536a 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 08392916691e..cb1c92ca9fef 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DJ_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index f591fc2ed960..91dbfeb586a7 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DJX_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 0604c8a85223..134e783d3486 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP]; + chip->dsp_code_to_load = FW_INDIGO_IO_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index f357521c79e6..766cf501799d 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP]; + chip->dsp_code_to_load = FW_INDIGO_IOX_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 83750e9fd7b4..07f32454757e 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -31,8 +31,7 @@ static int read_dsp(struct echoaudio *chip, u32 *data); static int set_professional_spdif(struct echoaudio *chip, char prof); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); static int update_flags(struct echoaudio *chip); @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP]; + chip->dsp_code_to_load = FW_LAYLA20_DSP; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; @@ -144,7 +143,7 @@ static int load_asic(struct echoaudio *chip) return 0; err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, - &card_fw[FW_LAYLA20_ASIC]); + FW_LAYLA20_ASIC); if (err < 0) return err; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index d61b5cbcccad..12dc00adca9f 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -32,8 +32,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP]; + chip->dsp_code_to_load = FW_LAYLA24_DSP; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; @@ -123,18 +122,18 @@ static int load_asic(struct echoaudio *chip) /* Load the ASIC for the PCI card */ err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, - &card_fw[FW_LAYLA24_1_ASIC]); + FW_LAYLA24_1_ASIC); if (err < 0) return err; - chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC]; + chip->asic_code = FW_LAYLA24_2S_ASIC; /* Now give the new ASIC a little time to set up */ mdelay(10); /* Do the external one */ err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, - &card_fw[FW_LAYLA24_2S_ASIC]); + FW_LAYLA24_2S_ASIC); if (err < 0) return FALSE; @@ -299,7 +298,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) /* Depending on what digital mode you want, Layla24 needs different ASICs loaded. This function checks the ASIC needed for the new mode and sees if it matches the one already loaded. */ -static int switch_asic(struct echoaudio *chip, const struct firmware *asic) +static int switch_asic(struct echoaudio *chip, short asic) { s8 *monitors; @@ -335,7 +334,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) { u32 control_reg; int err, incompatible_clock; - const struct firmware *asic; + short asic; /* Set clock to "internal" if it's not compatible with the new mode */ incompatible_clock = FALSE; @@ -344,12 +343,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) case DIGITAL_MODE_SPDIF_RCA: if (chip->input_clock == ECHO_CLOCK_ADAT) incompatible_clock = TRUE; - asic = &card_fw[FW_LAYLA24_2S_ASIC]; + asic = FW_LAYLA24_2S_ASIC; break; case DIGITAL_MODE_ADAT: if (chip->input_clock == ECHO_CLOCK_SPDIF) incompatible_clock = TRUE; - asic = &card_fw[FW_LAYLA24_2A_ASIC]; + asic = FW_LAYLA24_2A_ASIC; break; default: DE_ACT(("Digital mode not supported: %d\n", mode)); diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 551405114cbc..d0302f2f00db 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -53,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_MIA_DSP]; + chip->dsp_code_to_load = FW_MIA_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index eaa619bd2a03..b28b8e4703cf 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -64,9 +63,9 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) /* Mona comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) - chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP]; + chip->dsp_code_to_load = FW_MONA_361_DSP; else - chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP]; + chip->dsp_code_to_load = FW_MONA_301_DSP; chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; chip->professional_spdif = FALSE; @@ -120,7 +119,7 @@ static int load_asic(struct echoaudio *chip) { u32 control_reg; int err; - const struct firmware *asic; + short asic; if (chip->asic_loaded) return 0; @@ -128,9 +127,9 @@ static int load_asic(struct echoaudio *chip) mdelay(10); if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); if (err < 0) @@ -141,7 +140,7 @@ static int load_asic(struct echoaudio *chip) /* Do the external one */ err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, - &card_fw[FW_MONA_2_ASIC]); + FW_MONA_2_ASIC); if (err < 0) return err; @@ -165,22 +164,22 @@ loaded. This function checks the ASIC needed for the new mode and sees if it matches the one already loaded. */ static int switch_asic(struct echoaudio *chip, char double_speed) { - const struct firmware *asic; int err; + short asic; /* Check the clock detect bits to see if this is a single-speed clock or a double-speed clock; load a new ASIC if necessary. */ if (chip->device_id == DEVICE_ID_56361) { if (double_speed) - asic = &card_fw[FW_MONA_361_1_ASIC96]; + asic = FW_MONA_361_1_ASIC96; else - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; } else { if (double_speed) - asic = &card_fw[FW_MONA_301_1_ASIC96]; + asic = FW_MONA_301_1_ASIC96; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; } if (asic != chip->asic_code) { @@ -200,7 +199,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed) static int set_sample_rate(struct echoaudio *chip, u32 rate) { u32 control_reg, clock; - const struct firmware *asic; + short asic; char force_write; /* Only set the clock for internal mode. */ @@ -218,14 +217,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EINVAL; if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC96]; + asic = FW_MONA_361_1_ASIC96; else - asic = &card_fw[FW_MONA_301_1_ASIC96]; + asic = FW_MONA_301_1_ASIC96; } else { if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; } force_write = 0; @@ -410,8 +409,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) case DIGITAL_MODE_ADAT: /* If the current ASIC is the 96KHz ASIC, switch the ASIC and set to 48 KHz */ - if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] || - chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) { + if (chip->asic_code == FW_MONA_361_1_ASIC96 || + chip->asic_code == FW_MONA_301_1_ASIC96) { set_sample_rate(chip, 48000); } control_reg |= GML_ADAT_MODE; -- GitLab From 4f8ada444cc7a7ea70cdc81f098b34c5f1f2df41 Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:51 +0100 Subject: [PATCH 2042/3892] ALSA: Echoaudio - Add firmware cache #2 This patch implements a simple cache for the firmware files when CONFIG_PM is defined. This patch changes get_firmware(), free_firmware() and adds free_firmware_cache(). The first two functions implement a very simple cache and the latter is used to actually release all the stored firmwares when the module is unloaded. When CONFIG_PM is not enabled those functions act as before, that is free_firmware() releases the firmware immediately and free_firmware_cache() does nothing. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 42 +++++++++++++++++++++++++++++---- sound/pci/echoaudio/echoaudio.h | 3 +++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 78fc2637bfa6..79dde9592847 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -43,12 +43,24 @@ static int get_firmware(const struct firmware **fw_entry, { int err; char name[30]; - const struct firmware *frm = &card_fw[fw_index]; - DE_ACT(("firmware requested: %s\n", frm->data)); - snprintf(name, sizeof(name), "ea/%s", frm->data); - if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) +#ifdef CONFIG_PM + if (chip->fw_cache[fw_index]) { + DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data)); + *fw_entry = chip->fw_cache[fw_index]; + return 0; + } +#endif + + DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data)); + snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); + err = request_firmware(fw_entry, name, pci_device(chip)); + if (err < 0) snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); +#ifdef CONFIG_PM + else + chip->fw_cache[fw_index] = *fw_entry; +#endif return err; } @@ -56,8 +68,29 @@ static int get_firmware(const struct firmware **fw_entry, static void free_firmware(const struct firmware *fw_entry) { +#ifdef CONFIG_PM + DE_ACT(("firmware not released (kept in cache)\n")); +#else release_firmware(fw_entry); DE_ACT(("firmware released\n")); +#endif +} + + + +static void free_firmware_cache(struct echoaudio *chip) +{ +#ifdef CONFIG_PM + int i; + + for (i = 0; i < 8 ; i++) + if (chip->fw_cache[i]) { + release_firmware(chip->fw_cache[i]); + DE_ACT(("release_firmware(%d)\n", i)); + } + + DE_ACT(("firmware_cache released\n")); +#endif } @@ -1880,6 +1913,7 @@ static int snd_echo_free(struct echoaudio *chip) pci_disable_device(chip->pci); /* release chip data */ + free_firmware_cache(chip); kfree(chip); DE_INIT(("Chip freed.\n")); return 0; diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index be76ef3b829a..a84c0d15cc50 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -449,6 +449,9 @@ struct echoaudio { volatile u32 __iomem *dsp_registers; /* DSP's register base */ u32 active_mask; /* Chs. active mask or * punks out */ +#ifdef CONFIG_PM + const struct firmware *fw_cache[8]; /* Cached firmwares */ +#endif #ifdef ECHOCARD_HAS_MIDI u16 mtc_state; /* State for MIDI input parsing state machine */ -- GitLab From ad3499f4668f684ef6e5d0222ae14d5e4ade1fdd Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:59 +0100 Subject: [PATCH 2043/3892] ALSA: Echoaudio - Add suspend support #1 Move the controls init code outside the init_hw() function because is must not be called during resume. This patch moves the code that initializes the card's controls with default valued from the init_hw() function into a separated set_mixer_defaults() function (one for each of the 16 supported cards). This change is necessary because during resume we must resurrect the hardware without losing the previous settings. set_mixer_defaults() must be called only once when the module is loaded. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/darla20_dsp.c | 10 ++++++--- sound/pci/echoaudio/darla24_dsp.c | 10 ++++++--- sound/pci/echoaudio/echo3g_dsp.c | 26 +++++++++++------------- sound/pci/echoaudio/gina20_dsp.c | 13 +++++++----- sound/pci/echoaudio/gina24_dsp.c | 20 +++++++++--------- sound/pci/echoaudio/indigo_dsp.c | 10 ++++++--- sound/pci/echoaudio/indigo_express_dsp.c | 1 + sound/pci/echoaudio/indigodj_dsp.c | 10 ++++++--- sound/pci/echoaudio/indigodjx_dsp.c | 11 ++++++---- sound/pci/echoaudio/indigoio_dsp.c | 10 ++++++--- sound/pci/echoaudio/indigoiox_dsp.c | 11 ++++++---- sound/pci/echoaudio/layla20_dsp.c | 13 +++++++----- sound/pci/echoaudio/layla24_dsp.c | 18 ++++++++-------- sound/pci/echoaudio/mia_dsp.c | 10 ++++++--- sound/pci/echoaudio/mona_dsp.c | 22 +++++++++----------- 15 files changed, 115 insertions(+), 80 deletions(-) diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index a44135d6acbb..20c7cbc89bb3 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + /* The Darla20 has no external clock sources */ static u32 detect_input_clocks(const struct echoaudio *chip) { diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index d681da180829..6da6663e9176 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index f0071935c0cb..3cdc2ee2d1dd 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->non_audio_spdif = FALSE; - chip->bad_board = FALSE; - - if ((err = init_line_levels(chip)) < 0) - return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_phantom_power(chip, 0); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); DE_INIT(("init_hw done\n")); return err; @@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->non_audio_spdif = FALSE; + chip->bad_board = FALSE; + chip->phantom_power = FALSE; + return init_line_levels(chip); +} + + + static int set_phantom_power(struct echoaudio *chip, char on) { u32 control_reg = le32_to_cpu(chip->comm_page->control_register); diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index c5de88b6792d..d1615a0579d1 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->professional_spdif = FALSE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 093dd7ba0e81..98f7cfa81b5f 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -57,9 +57,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | ECHO_CLOCK_BIT_ADAT; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; /* Gina24 comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) { @@ -81,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 8799d2e6536a..5e85f14fe5a8 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c index 9ab625e15652..2e4ab3e34a74 100644 --- a/sound/pci/echoaudio/indigo_express_dsp.c +++ b/sound/pci/echoaudio/indigo_express_dsp.c @@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg |= clock; if (control_reg != old_control_reg) { + DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); chip->comm_page->control_register = cpu_to_le32(control_reg); chip->sample_rate = rate; clear_handshake(chip); diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index cb1c92ca9fef..68f3c8ccc1bf 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index 91dbfeb586a7..bb9632c752a9 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - err = init_line_levels(chip); - if (err < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } + + + +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 134e783d3486..beb9a5b69892 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index 766cf501799d..394c6e76bcbc 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - err = init_line_levels(chip); - if (err < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } + + + +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 07f32454757e..53ce94605044 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -64,17 +64,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->professional_spdif = FALSE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index 12dc00adca9f..8c041647f285 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -61,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; if ((err = load_firmware(chip)) < 0) return err; @@ -72,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if ((err = init_line_levels(chip)) < 0) return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index d0302f2f00db..6ebfa6e7ab9e 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -66,15 +66,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip))) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index b28b8e4703cf..6e6a7eb555b8 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -67,28 +67,26 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) else chip->dsp_code_to_load = FW_MONA_301_DSP; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; - if ((err = load_firmware(chip)) < 0) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; -- GitLab From 47b5d028fdce8f809bf22852ac900338fb90e8aa Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:16:10 +0100 Subject: [PATCH 2044/3892] ALSA: Echoaudio - Add suspend support #2 This patch adds rearranges parts of the initialization code and adds suspend and resume callbacks. This patch adds suspend and resume callbacks. It also rearranges parts of the initialization code so it can be used in both the first initialization (when the module is loaded we also have to load default settings) and the resume callback (where we have to restore the previous settings). Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 153 +++++++++++++++++++++++++--- sound/pci/echoaudio/echoaudio.h | 2 + sound/pci/echoaudio/echoaudio_dsp.c | 145 ++++++++++++++------------ 3 files changed, 222 insertions(+), 78 deletions(-) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 79dde9592847..2783ce6c236e 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -753,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->lock); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + DE_ACT(("pcm_trigger resume\n")); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: DE_ACT(("pcm_trigger start\n")); @@ -776,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) err = start_transport(chip, channelmask, chip->pipe_cyclic_mask); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + DE_ACT(("pcm_trigger suspend\n")); case SNDRV_PCM_TRIGGER_STOP: DE_ACT(("pcm_trigger stop\n")); for (i = 0; i < DSP_MAXPIPES; i++) { @@ -1951,18 +1955,27 @@ static __devinit int snd_echo_create(struct snd_card *card, return err; pci_set_master(pci); - /* allocate a chip-specific data */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - pci_disable_device(pci); - return -ENOMEM; + /* Allocate chip if needed */ + if (!*rchip) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + pci_disable_device(pci); + return -ENOMEM; + } + DE_INIT(("chip=%p\n", chip)); + spin_lock_init(&chip->lock); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + atomic_set(&chip->opencount, 0); + mutex_init(&chip->mode_mutex); + chip->can_set_rate = 1; + } else { + /* If this was called from the resume function, chip is + * already allocated and it contains current card settings. + */ + chip = *rchip; } - DE_INIT(("chip=%p\n", chip)); - - spin_lock_init(&chip->lock); - chip->card = card; - chip->pci = pci; - chip->irq = -1; /* PCI resource allocation */ chip->dsp_registers_phys = pci_resource_start(pci, 0); @@ -2002,7 +2015,9 @@ static __devinit int snd_echo_create(struct snd_card *card, chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); - if (err) { + if (err >= 0) + err = set_mixer_defaults(chip); + if (err < 0) { DE_INIT(("init_hw err=%d\n", err)); snd_echo_free(chip); return err; @@ -2013,9 +2028,6 @@ static __devinit int snd_echo_create(struct snd_card *card, snd_echo_free(chip); return err; } - atomic_set(&chip->opencount, 0); - mutex_init(&chip->mode_mutex); - chip->can_set_rate = 1; *rchip = chip; /* Init done ! */ return 0; @@ -2048,6 +2060,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); + chip = NULL; /* Tells snd_echo_create to allocate chip */ if ((err = snd_echo_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; @@ -2187,6 +2200,112 @@ ctl_error: +#if defined(CONFIG_PM) + +static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct echoaudio *chip = pci_get_drvdata(pci); + + DE_INIT(("suspend start\n")); + snd_pcm_suspend_all(chip->analog_pcm); + snd_pcm_suspend_all(chip->digital_pcm); + +#ifdef ECHOCARD_HAS_MIDI + /* This call can sleep */ + if (chip->midi_out) + snd_echo_midi_output_trigger(chip->midi_out, 0); +#endif + spin_lock_irq(&chip->lock); + if (wait_handshake(chip)) { + spin_unlock_irq(&chip->lock); + return -EIO; + } + clear_handshake(chip); + if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { + spin_unlock_irq(&chip->lock); + return -EIO; + } + spin_unlock_irq(&chip->lock); + + chip->dsp_code = NULL; + free_irq(chip->irq, chip); + chip->irq = -1; + pci_save_state(pci); + pci_disable_device(pci); + + DE_INIT(("suspend done\n")); + return 0; +} + + + +static int snd_echo_resume(struct pci_dev *pci) +{ + struct echoaudio *chip = pci_get_drvdata(pci); + struct comm_page *commpage, *commpage_bak; + u32 pipe_alloc_mask; + int err; + + DE_INIT(("resume start\n")); + pci_restore_state(pci); + commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); + commpage = chip->comm_page; + memcpy(commpage_bak, commpage, sizeof(struct comm_page)); + + err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); + if (err < 0) { + kfree(commpage_bak); + DE_INIT(("resume init_hw err=%d\n", err)); + snd_echo_free(chip); + return err; + } + DE_INIT(("resume init OK\n")); + + /* Temporarily set chip->pipe_alloc_mask=0 otherwise + * restore_dsp_settings() fails. + */ + pipe_alloc_mask = chip->pipe_alloc_mask; + chip->pipe_alloc_mask = 0; + err = restore_dsp_rettings(chip); + chip->pipe_alloc_mask = pipe_alloc_mask; + if (err < 0) { + kfree(commpage_bak); + return err; + } + DE_INIT(("resume restore OK\n")); + + memcpy(&commpage->audio_format, &commpage_bak->audio_format, + sizeof(commpage->audio_format)); + memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, + sizeof(commpage->sglist_addr)); + memcpy(&commpage->midi_output, &commpage_bak->midi_output, + sizeof(commpage->midi_output)); + kfree(commpage_bak); + + if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, + ECHOCARD_NAME, chip)) { + snd_echo_free(chip); + snd_printk(KERN_ERR "cannot grab irq\n"); + return -EBUSY; + } + chip->irq = pci->irq; + DE_INIT(("resume irq=%d\n", chip->irq)); + +#ifdef ECHOCARD_HAS_MIDI + if (chip->midi_input_enabled) + enable_midi_input(chip, TRUE); + if (chip->midi_out) + snd_echo_midi_output_trigger(chip->midi_out, 1); +#endif + + DE_INIT(("resume done\n")); + return 0; +} + +#endif /* CONFIG_PM */ + + + static void __devexit snd_echo_remove(struct pci_dev *pci) { struct echoaudio *chip; @@ -2209,6 +2328,10 @@ static struct pci_driver driver = { .id_table = snd_echo_ids, .probe = snd_echo_probe, .remove = __devexit_p(snd_echo_remove), +#ifdef CONFIG_PM + .suspend = snd_echo_suspend, + .resume = snd_echo_resume, +#endif /* CONFIG_PM */ }; diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index a84c0d15cc50..1df974dcb5f4 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -472,6 +472,8 @@ static void free_firmware(const struct firmware *fw_entry); #ifdef ECHOCARD_HAS_MIDI static int enable_midi_input(struct echoaudio *chip, char enable); +static void snd_echo_midi_output_trigger( + struct snd_rawmidi_substream *substream, int up); static int midi_service_irq(struct echoaudio *chip); static int __devinit snd_echo_midi_create(struct snd_card *card, struct echoaudio *chip); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 031ef7e9da91..64417a733220 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -497,9 +497,6 @@ static int load_firmware(struct echoaudio *chip) if ((box_type = load_asic(chip)) < 0) return box_type; /* error */ - if ((err = restore_dsp_rettings(chip)) < 0) - return err; - return box_type; } @@ -659,51 +656,106 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) static int restore_dsp_rettings(struct echoaudio *chip) { - int err; + int i, o, err; DE_INIT(("restore_dsp_settings\n")); if ((err = check_asic_status(chip)) < 0) return err; - /* @ Gina20/Darla20 only. Should be harmless for other cards. */ + /* Gina20/Darla20 only. Should be harmless for other cards. */ chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; chip->comm_page->handshake = 0xffffffff; - if ((err = set_sample_rate(chip, chip->sample_rate)) < 0) + /* Restore output busses */ + for (i = 0; i < num_busses_out(chip); i++) { + err = set_output_gain(chip, i, chip->output_gain[i]); + if (err < 0) + return err; + } + +#ifdef ECHOCARD_HAS_VMIXER + for (i = 0; i < num_pipes_out(chip); i++) + for (o = 0; o < num_busses_out(chip); o++) { + err = set_vmixer_gain(chip, o, i, + chip->vmixer_gain[o][i]); + if (err < 0) + return err; + } + if (update_vmixer_level(chip) < 0) + return -EIO; +#endif /* ECHOCARD_HAS_VMIXER */ + +#ifdef ECHOCARD_HAS_MONITOR + for (o = 0; o < num_busses_out(chip); o++) + for (i = 0; i < num_busses_in(chip); i++) { + err = set_monitor_gain(chip, o, i, + chip->monitor_gain[o][i]); + if (err < 0) + return err; + } +#endif /* ECHOCARD_HAS_MONITOR */ + +#ifdef ECHOCARD_HAS_INPUT_GAIN + for (i = 0; i < num_busses_in(chip); i++) { + err = set_input_gain(chip, i, chip->input_gain[i]); + if (err < 0) + return err; + } +#endif /* ECHOCARD_HAS_INPUT_GAIN */ + + err = update_output_line_level(chip); + if (err < 0) return err; - if (chip->meters_enabled) - if (send_vector(chip, DSP_VC_METERS_ON) < 0) - return -EIO; + err = update_input_line_level(chip); + if (err < 0) + return err; -#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK - if (set_input_clock(chip, chip->input_clock) < 0) + err = set_sample_rate(chip, chip->sample_rate); + if (err < 0) + return err; + + if (chip->meters_enabled) { + err = send_vector(chip, DSP_VC_METERS_ON); + if (err < 0) + return err; + } + +#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH + if (set_digital_mode(chip, chip->digital_mode) < 0) return -EIO; #endif -#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH - if (set_output_clock(chip, chip->output_clock) < 0) +#ifdef ECHOCARD_HAS_DIGITAL_IO + if (set_professional_spdif(chip, chip->professional_spdif) < 0) return -EIO; #endif - if (update_output_line_level(chip) < 0) +#ifdef ECHOCARD_HAS_PHANTOM_POWER + if (set_phantom_power(chip, chip->phantom_power) < 0) return -EIO; +#endif - if (update_input_line_level(chip) < 0) +#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK + /* set_input_clock() also restores automute setting */ + if (set_input_clock(chip, chip->input_clock) < 0) return -EIO; +#endif -#ifdef ECHOCARD_HAS_VMIXER - if (update_vmixer_level(chip) < 0) +#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH + if (set_output_clock(chip, chip->output_clock) < 0) return -EIO; #endif if (wait_handshake(chip) < 0) return -EIO; clear_handshake(chip); + if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) + return -EIO; DE_INIT(("restore_dsp_rettings done\n")); - return send_vector(chip, DSP_VC_UPDATE_FLAGS); + return 0; } @@ -920,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) chip->card_name = ECHOCARD_NAME; chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ chip->dsp_code = NULL; /* Current DSP code not loaded */ - chip->digital_mode = DIGITAL_MODE_NONE; - chip->input_clock = ECHO_CLOCK_INTERNAL; - chip->output_clock = ECHO_CLOCK_WORD; chip->asic_loaded = FALSE; memset(chip->comm_page, 0, sizeof(struct comm_page)); @@ -933,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) chip->comm_page->midi_out_free_count = cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); chip->comm_page->sample_rate = cpu_to_le32(44100); - chip->sample_rate = 44100; /* Set line levels so we don't blast any inputs on startup */ memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); @@ -944,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip) -/* This function initializes the several volume controls for busses and pipes. -This MUST be called after the DSP is up and running ! */ +/* This function initializes the chip structure with default values, ie. all + * muted and internal clock source. Then it copies the settings to the DSP. + * This MUST be called after the DSP is up and running ! + */ static int init_line_levels(struct echoaudio *chip) { - int st, i, o; - DE_INIT(("init_line_levels\n")); - - /* Mute output busses */ - for (i = 0; i < num_busses_out(chip); i++) - if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_output_line_level(chip))) - return st; - -#ifdef ECHOCARD_HAS_VMIXER - /* Mute the Vmixer */ - for (i = 0; i < num_pipes_out(chip); i++) - for (o = 0; o < num_busses_out(chip); o++) - if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_vmixer_level(chip))) - return st; -#endif /* ECHOCARD_HAS_VMIXER */ - -#ifdef ECHOCARD_HAS_MONITOR - /* Mute the monitor mixer */ - for (o = 0; o < num_busses_out(chip); o++) - for (i = 0; i < num_busses_in(chip); i++) - if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_output_line_level(chip))) - return st; -#endif /* ECHOCARD_HAS_MONITOR */ - -#ifdef ECHOCARD_HAS_INPUT_GAIN - for (i = 0; i < num_busses_in(chip); i++) - if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_input_line_level(chip))) - return st; -#endif /* ECHOCARD_HAS_INPUT_GAIN */ - - return 0; + memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); + memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); + memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); + memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain)); + chip->input_clock = ECHO_CLOCK_INTERNAL; + chip->output_clock = ECHO_CLOCK_WORD; + chip->sample_rate = 44100; + return restore_dsp_rettings(chip); } -- GitLab From 6dd2e42bd892b2e16080ceba451fd9c3ed633145 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 14 Jan 2010 17:32:13 +0200 Subject: [PATCH 2045/3892] OMAP: DSS2: OMAPFB: implement OMAPFB_GET_DISPLAY_INFO Previously the only place to get the size of the display was from the DSS's sysfs interface, making, for example, configuring overlays and doing updates on manual displays more difficult. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 24 +++++++++++++++++++++++ include/linux/omapfb.h | 9 +++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 4c4bafdfaa43..33fc1459a7c9 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -483,6 +483,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_memory_read memory_read; struct omapfb_vram_info vram_info; struct omapfb_tearsync_info tearsync_info; + struct omapfb_display_info display_info; } p; int r = 0; @@ -741,6 +742,29 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } + case OMAPFB_GET_DISPLAY_INFO: { + u16 xres, yres; + + DBG("ioctl GET_DISPLAY_INFO\n"); + + if (display == NULL) { + r = -ENODEV; + break; + } + + display->get_resolution(display, &xres, &yres); + + p.display_info.xres = xres; + p.display_info.yres = yres; + p.display_info.width = 0; + p.display_info.height = 0; + + if (copy_to_user((void __user *)arg, &p.display_info, + sizeof(p.display_info))) + r = -EFAULT; + break; + } + default: dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); r = -EINVAL; diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h index f46c40ac6d45..9bdd91486b49 100644 --- a/include/linux/omapfb.h +++ b/include/linux/omapfb.h @@ -57,6 +57,7 @@ #define OMAPFB_WAITFORGO OMAP_IO(60) #define OMAPFB_GET_VRAM_INFO OMAP_IOR(61, struct omapfb_vram_info) #define OMAPFB_SET_TEARSYNC OMAP_IOW(62, struct omapfb_tearsync_info) +#define OMAPFB_GET_DISPLAY_INFO OMAP_IOR(63, struct omapfb_display_info) #define OMAPFB_CAPS_GENERIC_MASK 0x00000fff #define OMAPFB_CAPS_LCDC_MASK 0x00fff000 @@ -206,6 +207,14 @@ struct omapfb_tearsync_info { __u16 reserved2; }; +struct omapfb_display_info { + __u16 xres; + __u16 yres; + __u32 width; /* phys width of the display in micrometers */ + __u32 height; /* phys height of the display in micrometers */ + __u32 reserved[5]; +}; + #ifdef __KERNEL__ #include -- GitLab From 853525d7785761d2d9c121b41326ab19d3af4a22 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 8 Feb 2010 12:19:46 +0200 Subject: [PATCH 2046/3892] OMAP: DSS2: fix irq-stats compilation Fix compilation of the CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS feature. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 4 +++- drivers/video/omap2/dss/dispc.c | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 791e1cb7c0bc..5939da9cf021 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -446,10 +446,12 @@ static int dss_initialize_debugfs(void) debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, &dss_debug_dump_clocks, &dss_debug_fops); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir, &dispc_dump_irqs, &dss_debug_fops); +#endif -#ifdef CONFIG_OMAP2_DSS_DSI +#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS) debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir, &dsi_dump_irqs, &dss_debug_fops); #endif diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index de8bfbac9e26..7781c65bbeba 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2301,8 +2301,6 @@ void dispc_dump_irqs(struct seq_file *s) PIS(WAKEUP); #undef PIS } -#else -void dispc_dump_irqs(struct seq_file *s) { } #endif void dispc_dump_regs(struct seq_file *s) -- GitLab From b63c97f5184684c841be84ec80928e3c5fe57fbe Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Feb 2010 14:46:19 +0200 Subject: [PATCH 2047/3892] OMAP: DSS2: OMAPFB: Add omapfb_update_window prototype Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index f7c9c739e5ef..4ae0b64b3f43 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -105,6 +105,9 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev); int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); +int omapfb_update_window(struct fb_info *fbi, + u32 x, u32 y, u32 w, u32 h); + int dss_mode_to_fb_mode(enum omap_color_mode dssmode, struct fb_var_screeninfo *var); -- GitLab From 2f18c4d89861fc1abdfa2531ba76017acb78edc5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 8 Jan 2010 18:00:36 +0200 Subject: [PATCH 2048/3892] OMAP: DSS2: improve DSS clk src selection dss_select_clk_source() was rather confusing. Selecting the source with enums is much clearer. The clk source selection is also stored into memory, so that we know what is the selected source, even when clocks are off. This is important during setup, as we need to what clocks to turn on before the clocks are turned on. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dpi.c | 4 ++-- drivers/video/omap2/dss/dsi.c | 9 +++++--- drivers/video/omap2/dss/dss.c | 42 ++++++++++++++++++++++++++--------- drivers/video/omap2/dss/dss.h | 14 +++++++++--- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 69ce31ae2a2f..c5091ed12a7d 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -57,7 +57,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, if (r) return r; - dss_select_clk_source(0, 1); + dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); r = dispc_set_clock_div(&dispc_cinfo); if (r) @@ -238,7 +238,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) dispc_enable_lcd_out(0); #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - dss_select_clk_source(0, 0); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_pll_uninit(); dss_clk_disable(DSS_CLK_FCK2); #endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 036f4221e3df..4fdb628427e0 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3203,7 +3203,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (r) goto err1; - dss_select_clk_source(true, true); + dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK); DSSDBG("PLL OK\n"); @@ -3247,7 +3248,8 @@ err4: err3: dsi_complexio_uninit(); err2: - dss_select_clk_source(false, false); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); err1: dsi_pll_uninit(); err0: @@ -3259,7 +3261,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) if (dssdev->driver->disable) dssdev->driver->disable(dssdev); - dss_select_clk_source(false, false); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_complexio_uninit(); dsi_pll_uninit(); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 0a26b7d84d41..8254a4232a53 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -68,6 +68,9 @@ static struct { struct dss_clock_info cache_dss_cinfo; struct dispc_clock_info cache_dispc_cinfo; + enum dss_clk_source dsi_clk_source; + enum dss_clk_source dispc_clk_source; + u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; @@ -247,23 +250,42 @@ void dss_dump_regs(struct seq_file *s) #undef DUMPREG } -void dss_select_clk_source(bool dsi, bool dispc) +void dss_select_dispc_clk_source(enum dss_clk_source clk_src) +{ + int b; + + BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK && + clk_src != DSS_SRC_DSS1_ALWON_FCLK); + + b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + + REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ + + dss.dispc_clk_source = clk_src; +} + +void dss_select_dsi_clk_source(enum dss_clk_source clk_src) { - u32 r; - r = dss_read_reg(DSS_CONTROL); - r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */ - r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */ - dss_write_reg(DSS_CONTROL, r); + int b; + + BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK && + clk_src != DSS_SRC_DSS1_ALWON_FCLK); + + b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + + REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ + + dss.dsi_clk_source = clk_src; } -int dss_get_dsi_clk_source(void) +enum dss_clk_source dss_get_dispc_clk_source(void) { - return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1); + return dss.dispc_clk_source; } -int dss_get_dispc_clk_source(void) +enum dss_clk_source dss_get_dsi_clk_source(void) { - return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0); + return dss.dsi_clk_source; } /* calculate clock rates using dividers in cinfo */ diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 41145af36353..3713dc698259 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -119,6 +119,12 @@ enum dss_clock { DSS_CLK_96M = 1 << 4, }; +enum dss_clk_source { + DSS_SRC_DSI1_PLL_FCLK, + DSS_SRC_DSI2_PLL_FCLK, + DSS_SRC_DSS1_ALWON_FCLK, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -219,9 +225,11 @@ void dss_sdi_init(u8 datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); -void dss_select_clk_source(bool dsi, bool dispc); -int dss_get_dsi_clk_source(void); -int dss_get_dispc_clk_source(void); +void dss_select_dispc_clk_source(enum dss_clk_source clk_src); +void dss_select_dsi_clk_source(enum dss_clk_source clk_src); +enum dss_clk_source dss_get_dispc_clk_source(void); +enum dss_clk_source dss_get_dsi_clk_source(void); + void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); -- GitLab From 4f76502374ff91bc80a48a32cabb1009087a3b9d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 18 Jan 2010 16:27:52 +0200 Subject: [PATCH 2049/3892] OMAP: DSS2: DSI: add dsi_bus_is_locked() Helper function to clean up the checking of the bus lock. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 4fdb628427e0..b38974523d48 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -309,6 +309,11 @@ void dsi_bus_unlock(void) } EXPORT_SYMBOL(dsi_bus_unlock); +static bool dsi_bus_is_locked(void) +{ + return mutex_is_locked(&dsi.bus_lock); +} + static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum, int value) { @@ -1959,7 +1964,7 @@ static int dsi_vc_send_bta(int channel) (dsi.debug_write || dsi.debug_read)) DSSDBG("dsi_vc_send_bta %d\n", channel); - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ DSSERR("rx fifo not empty when sending BTA, dumping data:\n"); @@ -2010,7 +2015,7 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type, u32 val; u8 data_id; - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); /*data_id = data_type | channel << 6; */ data_id = data_type | dsi.vc[channel].dest_per << 6; @@ -2105,7 +2110,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) u32 r; u8 data_id; - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); if (dsi.debug_write) DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n", @@ -2895,7 +2900,7 @@ static int dsi_set_update_mode(struct omap_dss_device *dssdev, int r = 0; int i; - WARN_ON(!mutex_is_locked(&dsi.bus_lock)); + WARN_ON(!dsi_bus_is_locked()); if (dsi.update_mode != mode) { dsi.update_mode = mode; -- GitLab From 828c48f8c51ebfc2a00e1a834b0bc9e7fd35060f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 16 Dec 2009 14:53:15 +0200 Subject: [PATCH 2050/3892] OMAP: DSS2: DSI: add helpers for DCS read/write Add helper functions for most common DCS read and write operations. Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 3 +++ drivers/video/omap2/dss/dsi.c | 30 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index c66e464732df..47df5f6fbf89 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -233,8 +233,11 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode, void dsi_bus_lock(void); void dsi_bus_unlock(void); int dsi_vc_dcs_write(int channel, u8 *data, int len); +int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd); +int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param); int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len); int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen); +int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data); int dsi_vc_set_max_rx_packet_size(int channel, u16 len); int dsi_vc_send_null(int channel); int dsi_vc_send_bta_sync(int channel); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b38974523d48..e49f063fb615 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2176,6 +2176,21 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) } EXPORT_SYMBOL(dsi_vc_dcs_write); +int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd) +{ + return dsi_vc_dcs_write(channel, &dcs_cmd, 1); +} +EXPORT_SYMBOL(dsi_vc_dcs_write_0); + +int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param) +{ + u8 buf[2]; + buf[0] = dcs_cmd; + buf[1] = param; + return dsi_vc_dcs_write(channel, buf, 2); +} +EXPORT_SYMBOL(dsi_vc_dcs_write_1); + int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) { u32 val; @@ -2268,6 +2283,21 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) } EXPORT_SYMBOL(dsi_vc_dcs_read); +int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) +{ + int r; + + r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1); + + if (r < 0) + return r; + + if (r != 1) + return -EIO; + + return 0; +} +EXPORT_SYMBOL(dsi_vc_dcs_read_1); int dsi_vc_set_max_rx_packet_size(int channel, u16 len) { -- GitLab From 61140c9a88ce1f1dee4e98a0c442f9a84b4c5e6b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 12 Jan 2010 16:00:30 +0200 Subject: [PATCH 2051/3892] OMAP: DSS2: DSI: export dsi_vc_enable_hs() Rename and export dsi_vc_enable_hs() so that the display drivers can control the mode of the DSI link. Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 2 ++ drivers/video/omap2/dss/dsi.c | 13 ++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 47df5f6fbf89..8c3688b45f3d 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -575,4 +575,6 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver) #define to_dss_device(x) container_of((x), struct omap_dss_device, dev) +void omapdss_dsi_vc_enable_hs(int channel, bool enable); + #endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index e49f063fb615..e003fe9ee9c4 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1864,10 +1864,12 @@ static void dsi_vc_config_vp(int channel) } -static void dsi_vc_enable_hs(int channel, bool enable) +void omapdss_dsi_vc_enable_hs(int channel, bool enable) { DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); + WARN_ON(!dsi_bus_is_locked()); + dsi_vc_enable(channel, 0); dsi_if_enable(0); @@ -1878,6 +1880,7 @@ static void dsi_vc_enable_hs(int channel, bool enable) dsi_force_tx_stop_mode_io(); } +EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); static void dsi_vc_flush_long_data(int channel) { @@ -3275,7 +3278,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) } /* enable high-speed after initial config */ - dsi_vc_enable_hs(0, 1); + omapdss_dsi_vc_enable_hs(0, 1); return 0; err4: @@ -3688,7 +3691,7 @@ static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num) dsi_bus_lock(); /* run test first in low speed mode */ - dsi_vc_enable_hs(0, 0); + omapdss_dsi_vc_enable_hs(0, 0); if (dssdev->driver->run_test) { r = dssdev->driver->run_test(dssdev, test_num); @@ -3697,7 +3700,7 @@ static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num) } /* then in high speed */ - dsi_vc_enable_hs(0, 1); + omapdss_dsi_vc_enable_hs(0, 1); if (dssdev->driver->run_test) { r = dssdev->driver->run_test(dssdev, test_num); @@ -3706,7 +3709,7 @@ static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num) } end: - dsi_vc_enable_hs(0, 1); + omapdss_dsi_vc_enable_hs(0, 1); dsi_bus_unlock(); -- GitLab From dd8079d6a9c2aa292dacaf1b42f526558e20379f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 16 Dec 2009 16:49:03 +0200 Subject: [PATCH 2052/3892] OMAP: DSS2: DSI: configure all DSI VCs Instead of configuring only VC0 to be usable, configure all four VCs similarly. This is needed to utilize the other VCs. Setting the FIFO sizes evenly for all VCs, regardless of how many VCs are actually used, is not optimal. However, this affects only cases when larger amounts of data are written or read via L4, meaning that normal use cases are not affected. At some point this could be optimized better to suit different use cases. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 39 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index e003fe9ee9c4..131bd53b6b6d 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -224,7 +224,6 @@ static struct enum dsi_vc_mode mode; struct omap_dss_device *dssdev; enum fifo_size fifo_size; - int dest_per; /* destination peripheral 0-3 */ } vc[4]; struct mutex lock; @@ -2020,8 +2019,7 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type, WARN_ON(!dsi_bus_is_locked()); - /*data_id = data_type | channel << 6; */ - data_id = data_type | dsi.vc[channel].dest_per << 6; + data_id = data_type | channel << 6; val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | FLD_VAL(ecc, 31, 24); @@ -2127,7 +2125,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) return -EINVAL; } - data_id = data_type | dsi.vc[channel].dest_per << 6; + data_id = data_type | channel << 6; r = (data_id << 0) | (data << 8) | (ecc << 24); @@ -2529,15 +2527,15 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) u32 r; int buswidth = 0; - dsi_config_tx_fifo(DSI_FIFO_SIZE_128, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0); + dsi_config_tx_fifo(DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); - dsi_config_rx_fifo(DSI_FIFO_SIZE_128, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0, - DSI_FIFO_SIZE_0); + dsi_config_rx_fifo(DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ dsi_set_stop_state_counter(1000); @@ -2575,12 +2573,9 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(DSI_CTRL, r); dsi_vc_initial_config(0); - - /* set all vc targets to peripheral 0 */ - dsi.vc[0].dest_per = 0; - dsi.vc[1].dest_per = 0; - dsi.vc[2].dest_per = 0; - dsi.vc[3].dest_per = 0; + dsi_vc_initial_config(1); + dsi_vc_initial_config(2); + dsi_vc_initial_config(3); return 0; } @@ -2846,9 +2841,6 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, if (bytespf % packet_payload) total_len += (bytespf % packet_payload) + 1; - if (0) - dsi_vc_print_status(1); - l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ dsi_write_reg(DSI_VC_TE(channel), l); @@ -3014,7 +3006,7 @@ static void dsi_handle_framedone(void) /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { DSSERR("Received error during frame transfer:\n"); - dsi_vc_flush_receive_data(0); + dsi_vc_flush_receive_data(channel); } #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC @@ -3268,6 +3260,9 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) /* enable interface */ dsi_vc_enable(0, 1); + dsi_vc_enable(1, 1); + dsi_vc_enable(2, 1); + dsi_vc_enable(3, 1); dsi_if_enable(1); dsi_force_tx_stop_mode_io(); -- GitLab From 6eed73debf5840a42ebe9ea90958d2ce4a38c6b0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Feb 2010 14:44:05 +0200 Subject: [PATCH 2053/3892] OMAP: DSS2: DSI: remove dsi_vc_print_status() It was not used. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 131bd53b6b6d..4b85ed202d50 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1760,24 +1760,6 @@ static int dsi_force_tx_stop_mode_io(void) return 0; } -static void dsi_vc_print_status(int channel) -{ - u32 r; - - r = dsi_read_reg(DSI_VC_CTRL(channel)); - DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, " - "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ", - channel, - FLD_GET(r, 5, 5), - FLD_GET(r, 6, 6), - FLD_GET(r, 15, 15), - FLD_GET(r, 16, 16), - FLD_GET(r, 20, 20)); - - r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS); - DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff); -} - static int dsi_vc_enable(int channel, bool enable) { if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO) @@ -2062,13 +2044,10 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len, dsi_vc_write_long_header(channel, data_type, len, ecc); - /*dsi_vc_print_status(0); */ - p = data; for (i = 0; i < len >> 2; i++) { if (dsi.debug_write) DSSDBG("\tsending full packet %d\n", i); - /*dsi_vc_print_status(0); */ b1 = *p++; b2 = *p++; -- GitLab From e296264977f68ddf395b8f93f8e174930f88499a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 1 Dec 2009 13:23:25 +0200 Subject: [PATCH 2054/3892] OMAP: DSS2: Check ctx loss count only when starting the first clock When OMAP PM layer is no-op/debug, the PM layer will increment context loss count with every call. This resulted DSS2 to restore context whenever a clock was enabled. This commit checks the context loss count only when the context actually could have been lost, ie. when enabling a clock when no clocks had been previously enabled. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 5939da9cf021..72547dfc56b8 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -289,9 +289,11 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks) void dss_clk_enable(enum dss_clock clks) { + bool check_ctx = core.num_clks_enabled == 0; + dss_clk_enable_no_ctx(clks); - if (cpu_is_omap34xx() && dss_need_ctx_restore()) + if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) restore_all_ctx(); } -- GitLab From 18eabe2347ae7a11b3db768695913724166dfb0e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 31 Oct 2009 16:52:16 +0000 Subject: [PATCH 2055/3892] ARM: dma-mapping: introduce the idea of buffer ownership The DMA API has the notion of buffer ownership; make it explicit in the ARM implementation of this API. This gives us a set of hooks to allow us to deal with CPU cache issues arising from non-cache coherent DMA. Signed-off-by: Russell King Tested-By: Santosh Shilimkar Tested-By: Jamie Iles --- arch/arm/common/dmabounce.c | 4 +- arch/arm/include/asm/dma-mapping.h | 64 ++++++++++++++++++++++-------- arch/arm/mm/dma-mapping.c | 13 +++--- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index bc90364a96c7..51499d68b161 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -277,7 +277,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, * We don't need to sync the DMA buffer since * it was allocated via the coherent allocators. */ - dma_cache_maint(ptr, size, dir); + __dma_single_cpu_to_dev(ptr, size, dir); } return dma_addr; @@ -315,6 +315,8 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, __cpuc_flush_kernel_dcache_area(ptr, size); } free_safe_buffer(dev->archdata.dmabounce, buf); + } else { + __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); } } diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index a96300bf83fd..e850f5c1607b 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -57,19 +57,48 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) #endif /* - * DMA-consistent mapping functions. These allocate/free a region of - * uncached, unwrite-buffered mapped memory space for use with DMA - * devices. This is the "generic" version. The PCI specific version - * is in pci.h - * - * Note: Drivers should NOT use this function directly, as it will break - * platforms with CONFIG_DMABOUNCE. - * Use the driver DMA support - see dma-mapping.h (dma_sync_*) + * Private support functions: these are not part of the API and are + * liable to change. Drivers must not use these. */ extern void dma_cache_maint(const void *kaddr, size_t size, int rw); extern void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, int rw); +/* + * The DMA API is built upon the notion of "buffer ownership". A buffer + * is either exclusively owned by the CPU (and therefore may be accessed + * by it) or exclusively owned by the DMA device. These helper functions + * represent the transitions between these two ownership states. + * + * As above, these are private support functions and not part of the API. + * Drivers must not use these. + */ +static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ + if (!arch_is_coherent()) + dma_cache_maint(kaddr, size, dir); +} + +static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ + /* nothing to do */ +} + +static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + if (!arch_is_coherent()) + dma_cache_maint_page(page, off, size, dir); +} + +static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + /* nothing to do */ +} + /* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits @@ -304,8 +333,7 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, { BUG_ON(!valid_dma_direction(dir)); - if (!arch_is_coherent()) - dma_cache_maint(cpu_addr, size, dir); + __dma_single_cpu_to_dev(cpu_addr, size, dir); return virt_to_dma(dev, cpu_addr); } @@ -329,8 +357,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, { BUG_ON(!valid_dma_direction(dir)); - if (!arch_is_coherent()) - dma_cache_maint_page(page, offset, size, dir); + __dma_page_cpu_to_dev(page, offset, size, dir); return page_to_dma(dev, page) + offset; } @@ -352,7 +379,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); } /** @@ -372,7 +399,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + __dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK, + size, dir); } #endif /* CONFIG_DMABOUNCE */ @@ -400,7 +428,10 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev, { BUG_ON(!valid_dma_direction(dir)); - dmabounce_sync_for_cpu(dev, handle, offset, size, dir); + if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir)) + return; + + __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir); } static inline void dma_sync_single_range_for_device(struct device *dev, @@ -412,8 +443,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev, if (!dmabounce_sync_for_device(dev, handle, offset, size, dir)) return; - if (!arch_is_coherent()) - dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir); + __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir); } static inline void dma_sync_single_for_cpu(struct device *dev, diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 26325cb5d368..a316c9459526 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -573,8 +573,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int i; for_each_sg(sg, s, nents, i) { - dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0, - sg_dma_len(s), dir); + if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0, + sg_dma_len(s), dir)) + continue; + + __dma_page_dev_to_cpu(sg_page(s), s->offset, + s->length, dir); } } EXPORT_SYMBOL(dma_sync_sg_for_cpu); @@ -597,9 +601,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, sg_dma_len(s), dir)) continue; - if (!arch_is_coherent()) - dma_cache_maint_page(sg_page(s), s->offset, - s->length, dir); + __dma_page_cpu_to_dev(sg_page(s), s->offset, + s->length, dir); } } EXPORT_SYMBOL(dma_sync_sg_for_device); -- GitLab From 4ea0d7371e808628d11154b0d44140b70f05b998 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Nov 2009 16:27:17 +0000 Subject: [PATCH 2056/3892] ARM: dma-mapping: push buffer ownership down into dma-mapping.c Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/include/asm/dma-mapping.h | 39 +++++++++++++++++++----------- arch/arm/mm/dma-mapping.c | 34 +++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index e850f5c1607b..256ee1c9f51a 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -56,47 +56,58 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) } #endif -/* - * Private support functions: these are not part of the API and are - * liable to change. Drivers must not use these. - */ -extern void dma_cache_maint(const void *kaddr, size_t size, int rw); -extern void dma_cache_maint_page(struct page *page, unsigned long offset, - size_t size, int rw); - /* * The DMA API is built upon the notion of "buffer ownership". A buffer * is either exclusively owned by the CPU (and therefore may be accessed * by it) or exclusively owned by the DMA device. These helper functions * represent the transitions between these two ownership states. * - * As above, these are private support functions and not part of the API. - * Drivers must not use these. + * Note, however, that on later ARMs, this notion does not work due to + * speculative prefetches. We model our approach on the assumption that + * the CPU does do speculative prefetches, which means we clean caches + * before transfers and delay cache invalidation until transfer completion. + * + * Private support functions: these are not part of the API and are + * liable to change. Drivers must not use these. */ static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size, enum dma_data_direction dir) { + extern void ___dma_single_cpu_to_dev(const void *, size_t, + enum dma_data_direction); + if (!arch_is_coherent()) - dma_cache_maint(kaddr, size, dir); + ___dma_single_cpu_to_dev(kaddr, size, dir); } static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + extern void ___dma_single_dev_to_cpu(const void *, size_t, + enum dma_data_direction); + + if (!arch_is_coherent()) + ___dma_single_dev_to_cpu(kaddr, size, dir); } static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { + extern void ___dma_page_cpu_to_dev(struct page *, unsigned long, + size_t, enum dma_data_direction); + if (!arch_is_coherent()) - dma_cache_maint_page(page, off, size, dir); + ___dma_page_cpu_to_dev(page, off, size, dir); } static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + extern void ___dma_page_dev_to_cpu(struct page *, unsigned long, + size_t, enum dma_data_direction); + + if (!arch_is_coherent()) + ___dma_page_dev_to_cpu(page, off, size, dir); } /* diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index a316c9459526..bbf87880b915 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -404,7 +404,7 @@ EXPORT_SYMBOL(dma_free_coherent); * platforms with CONFIG_DMABOUNCE. * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ -void dma_cache_maint(const void *start, size_t size, int direction) +static void dma_cache_maint(const void *start, size_t size, int direction) { void (*inner_op)(const void *, const void *); void (*outer_op)(unsigned long, unsigned long); @@ -431,7 +431,20 @@ void dma_cache_maint(const void *start, size_t size, int direction) inner_op(start, start + size); outer_op(__pa(start), __pa(start) + size); } -EXPORT_SYMBOL(dma_cache_maint); + +void ___dma_single_cpu_to_dev(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ + dma_cache_maint(kaddr, size, dir); +} +EXPORT_SYMBOL(___dma_single_cpu_to_dev); + +void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(___dma_single_dev_to_cpu); static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, size_t size, int direction) @@ -474,7 +487,7 @@ static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, outer_op(paddr, paddr + size); } -void dma_cache_maint_page(struct page *page, unsigned long offset, +static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, int dir) { /* @@ -499,7 +512,20 @@ void dma_cache_maint_page(struct page *page, unsigned long offset, left -= len; } while (left); } -EXPORT_SYMBOL(dma_cache_maint_page); + +void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + dma_cache_maint_page(page, off, size, dir); +} +EXPORT_SYMBOL(___dma_page_cpu_to_dev); + +void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(___dma_page_dev_to_cpu); /** * dma_map_sg - map a set of SG buffers for streaming mode DMA -- GitLab From 65af191a0414d0e1145f67c153e1b63d122dfbb4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Nov 2009 17:53:33 +0000 Subject: [PATCH 2057/3892] ARM: dma-mapping: move selection of page ops out of dma_cache_maint_contiguous Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/mm/dma-mapping.c | 59 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index bbf87880b915..77dc483e64c1 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -447,48 +447,25 @@ void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, EXPORT_SYMBOL(___dma_single_dev_to_cpu); static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, - size_t size, int direction) + size_t size, void (*op)(const void *, const void *)) { void *vaddr; - unsigned long paddr; - void (*inner_op)(const void *, const void *); - void (*outer_op)(unsigned long, unsigned long); - - switch (direction) { - case DMA_FROM_DEVICE: /* invalidate only */ - inner_op = dmac_inv_range; - outer_op = outer_inv_range; - break; - case DMA_TO_DEVICE: /* writeback only */ - inner_op = dmac_clean_range; - outer_op = outer_clean_range; - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - inner_op = dmac_flush_range; - outer_op = outer_flush_range; - break; - default: - BUG(); - } if (!PageHighMem(page)) { vaddr = page_address(page) + offset; - inner_op(vaddr, vaddr + size); + op(vaddr, vaddr + size); } else { vaddr = kmap_high_get(page); if (vaddr) { vaddr += offset; - inner_op(vaddr, vaddr + size); + op(vaddr, vaddr + size); kunmap_high(page); } } - - paddr = page_to_phys(page) + offset; - outer_op(paddr, paddr + size); } static void dma_cache_maint_page(struct page *page, unsigned long offset, - size_t size, int dir) + size_t size, void (*op)(const void *, const void *)) { /* * A single sg entry may refer to multiple physically contiguous @@ -506,7 +483,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, } len = PAGE_SIZE - offset; } - dma_cache_maint_contiguous(page, offset, len, dir); + dma_cache_maint_contiguous(page, offset, len, op); offset = 0; page++; left -= len; @@ -516,7 +493,31 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { - dma_cache_maint_page(page, off, size, dir); + unsigned long paddr; + void (*inner_op)(const void *, const void *); + void (*outer_op)(unsigned long, unsigned long); + + switch (direction) { + case DMA_FROM_DEVICE: /* invalidate only */ + inner_op = dmac_inv_range; + outer_op = outer_inv_range; + break; + case DMA_TO_DEVICE: /* writeback only */ + inner_op = dmac_clean_range; + outer_op = outer_clean_range; + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + inner_op = dmac_flush_range; + outer_op = outer_flush_range; + break; + default: + BUG(); + } + + dma_cache_maint_page(page, off, size, inner_op); + + paddr = page_to_phys(page) + off; + outer_op(paddr, paddr + size); } EXPORT_SYMBOL(___dma_page_cpu_to_dev); -- GitLab From 93f1d629e22b08642eb713ad96ac2cb9ade0641c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Nov 2009 14:41:01 +0000 Subject: [PATCH 2058/3892] ARM: dma-mapping: simplify dma_cache_maint_page dma_cache_maint_contiguous is now simple enough to live inside dma_cache_maint_page, so move it there. Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/mm/dma-mapping.c | 42 +++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 77dc483e64c1..0d68d2c83cda 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -446,24 +446,6 @@ void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, } EXPORT_SYMBOL(___dma_single_dev_to_cpu); -static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, - size_t size, void (*op)(const void *, const void *)) -{ - void *vaddr; - - if (!PageHighMem(page)) { - vaddr = page_address(page) + offset; - op(vaddr, vaddr + size); - } else { - vaddr = kmap_high_get(page); - if (vaddr) { - vaddr += offset; - op(vaddr, vaddr + size); - kunmap_high(page); - } - } -} - static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, void (*op)(const void *, const void *)) { @@ -476,14 +458,26 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t left = size; do { size_t len = left; - if (PageHighMem(page) && len + offset > PAGE_SIZE) { - if (offset >= PAGE_SIZE) { - page += offset / PAGE_SIZE; - offset %= PAGE_SIZE; + void *vaddr; + + if (PageHighMem(page)) { + if (len + offset > PAGE_SIZE) { + if (offset >= PAGE_SIZE) { + page += offset / PAGE_SIZE; + offset %= PAGE_SIZE; + } + len = PAGE_SIZE - offset; + } + vaddr = kmap_high_get(page); + if (vaddr) { + vaddr += offset; + op(vaddr, vaddr + len); + kunmap_high(page); } - len = PAGE_SIZE - offset; + } else { + vaddr = page_address(page) + offset; + op(vaddr, vaddr + len); } - dma_cache_maint_contiguous(page, offset, len, op); offset = 0; page++; left -= len; -- GitLab From a9c9147eb9b1dba0ce567a41897c7773b4d1b0bc Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Nov 2009 16:19:58 +0000 Subject: [PATCH 2059/3892] ARM: dma-mapping: provide per-cpu type map/unmap functions Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/include/asm/cacheflush.h | 9 +++++++ arch/arm/kernel/asm-offsets.c | 5 ++++ arch/arm/mm/cache-fa.S | 26 +++++++++++++++++++ arch/arm/mm/cache-v3.S | 24 ++++++++++++++++++ arch/arm/mm/cache-v4.S | 24 ++++++++++++++++++ arch/arm/mm/cache-v4wb.S | 26 +++++++++++++++++++ arch/arm/mm/cache-v4wt.S | 25 ++++++++++++++++++ arch/arm/mm/cache-v6.S | 26 +++++++++++++++++++ arch/arm/mm/cache-v7.S | 26 +++++++++++++++++++ arch/arm/mm/dma-mapping.c | 29 +++++++++------------ arch/arm/mm/proc-arm1020.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm1020e.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm1022.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm1026.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm920.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm922.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm925.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm926.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm940.S | 26 +++++++++++++++++++ arch/arm/mm/proc-arm946.S | 26 +++++++++++++++++++ arch/arm/mm/proc-feroceon.S | 42 +++++++++++++++++++++++++++++++ arch/arm/mm/proc-mohawk.S | 26 +++++++++++++++++++ arch/arm/mm/proc-xsc3.S | 26 +++++++++++++++++++ arch/arm/mm/proc-xscale.S | 41 ++++++++++++++++++++++++++++++ 24 files changed, 598 insertions(+), 17 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 730aefcfbee3..4c733236e342 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -213,6 +213,9 @@ struct cpu_cache_fns { void (*coherent_user_range)(unsigned long, unsigned long); void (*flush_kern_dcache_area)(void *, size_t); + void (*dma_map_area)(const void *, size_t, int); + void (*dma_unmap_area)(const void *, size_t, int); + void (*dma_inv_range)(const void *, const void *); void (*dma_clean_range)(const void *, const void *); void (*dma_flush_range)(const void *, const void *); @@ -244,6 +247,8 @@ extern struct cpu_cache_fns cpu_cache; * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ +#define dmac_map_area cpu_cache.dma_map_area +#define dmac_unmap_area cpu_cache.dma_unmap_area #define dmac_inv_range cpu_cache.dma_inv_range #define dmac_clean_range cpu_cache.dma_clean_range #define dmac_flush_range cpu_cache.dma_flush_range @@ -270,10 +275,14 @@ extern void __cpuc_flush_dcache_area(void *, size_t); * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ +#define dmac_map_area __glue(_CACHE,_dma_map_area) +#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area) #define dmac_inv_range __glue(_CACHE,_dma_inv_range) #define dmac_clean_range __glue(_CACHE,_dma_clean_range) #define dmac_flush_range __glue(_CACHE,_dma_flush_range) +extern void dmac_map_area(const void *, size_t, int); +extern void dmac_unmap_area(const void *, size_t, int); extern void dmac_inv_range(const void *, const void *); extern void dmac_clean_range(const void *, const void *); extern void dmac_flush_range(const void *, const void *); diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 4a881258bb17..883511522fca 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -112,5 +113,9 @@ int main(void) #ifdef MULTI_PABORT DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); #endif + BLANK(); + DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); + DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); + DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE); return 0; } diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S index a89444a3c016..8ebffdd6fcff 100644 --- a/arch/arm/mm/cache-fa.S +++ b/arch/arm/mm/cache-fa.S @@ -205,6 +205,30 @@ ENTRY(fa_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(fa_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq fa_dma_clean_range + bcs fa_dma_inv_range + b fa_dma_flush_range +ENDPROC(fa_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(fa_dma_unmap_area) + mov pc, lr +ENDPROC(fa_dma_unmap_area) + __INITDATA .type fa_cache_fns, #object @@ -215,6 +239,8 @@ ENTRY(fa_cache_fns) .long fa_coherent_kern_range .long fa_coherent_user_range .long fa_flush_kern_dcache_area + .long fa_dma_map_area + .long fa_dma_unmap_area .long fa_dma_inv_range .long fa_dma_clean_range .long fa_dma_flush_range diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index 2a482731ea36..6df52dc014be 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -121,6 +121,28 @@ ENTRY(v3_dma_flush_range) ENTRY(v3_dma_clean_range) mov pc, lr +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v3_dma_unmap_area) + teq r2, #DMA_TO_DEVICE + bne v3_dma_inv_range + /* FALLTHROUGH */ + +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v3_dma_map_area) + mov pc, lr +ENDPROC(v3_dma_unmap_area) +ENDPROC(v3_dma_map_area) + __INITDATA .type v3_cache_fns, #object @@ -131,6 +153,8 @@ ENTRY(v3_cache_fns) .long v3_coherent_kern_range .long v3_coherent_user_range .long v3_flush_kern_dcache_area + .long v3_dma_map_area + .long v3_dma_unmap_area .long v3_dma_inv_range .long v3_dma_clean_range .long v3_dma_flush_range diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index 5c7da3e372e9..df3b423713b9 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -133,6 +133,28 @@ ENTRY(v4_dma_flush_range) ENTRY(v4_dma_clean_range) mov pc, lr +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4_dma_unmap_area) + teq r2, #DMA_TO_DEVICE + bne v4_dma_inv_range + /* FALLTHROUGH */ + +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4_dma_map_area) + mov pc, lr +ENDPROC(v4_dma_unmap_area) +ENDPROC(v4_dma_map_area) + __INITDATA .type v4_cache_fns, #object @@ -143,6 +165,8 @@ ENTRY(v4_cache_fns) .long v4_coherent_kern_range .long v4_coherent_user_range .long v4_flush_kern_dcache_area + .long v4_dma_map_area + .long v4_dma_unmap_area .long v4_dma_inv_range .long v4_dma_clean_range .long v4_dma_flush_range diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 3dbedf1ec0e7..32e7a7448496 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -216,6 +216,30 @@ ENTRY(v4wb_dma_clean_range) .globl v4wb_dma_flush_range .set v4wb_dma_flush_range, v4wb_coherent_kern_range +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4wb_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq v4wb_dma_clean_range + bcs v4wb_dma_inv_range + b v4wb_dma_flush_range +ENDPROC(v4wb_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4wb_dma_unmap_area) + mov pc, lr +ENDPROC(v4wb_dma_unmap_area) + __INITDATA .type v4wb_cache_fns, #object @@ -226,6 +250,8 @@ ENTRY(v4wb_cache_fns) .long v4wb_coherent_kern_range .long v4wb_coherent_user_range .long v4wb_flush_kern_dcache_area + .long v4wb_dma_map_area + .long v4wb_dma_unmap_area .long v4wb_dma_inv_range .long v4wb_dma_clean_range .long v4wb_dma_flush_range diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index b3b7410270b4..3d8dad5b2650 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S @@ -172,6 +172,29 @@ ENTRY(v4wt_dma_clean_range) .globl v4wt_dma_flush_range .equ v4wt_dma_flush_range, v4wt_dma_inv_range +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4wt_dma_unmap_area) + add r1, r1, r0 + teq r2, #DMA_TO_DEVICE + bne v4wt_dma_inv_range + /* FALLTHROUGH */ + +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v4wt_dma_map_area) + mov pc, lr +ENDPROC(v4wt_dma_unmap_area) +ENDPROC(v4wt_dma_map_area) + __INITDATA .type v4wt_cache_fns, #object @@ -182,6 +205,8 @@ ENTRY(v4wt_cache_fns) .long v4wt_coherent_kern_range .long v4wt_coherent_user_range .long v4wt_flush_kern_dcache_area + .long v4wt_dma_map_area + .long v4wt_dma_unmap_area .long v4wt_dma_inv_range .long v4wt_dma_clean_range .long v4wt_dma_flush_range diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 4ba0a24ce6f5..6f926dd0e0f7 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -263,6 +263,30 @@ ENTRY(v6_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v6_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq v6_dma_clean_range + bcs v6_dma_inv_range + b v6_dma_flush_range +ENDPROC(v6_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v6_dma_unmap_area) + mov pc, lr +ENDPROC(v6_dma_unmap_area) + __INITDATA .type v6_cache_fns, #object @@ -273,6 +297,8 @@ ENTRY(v6_cache_fns) .long v6_coherent_kern_range .long v6_coherent_user_range .long v6_flush_kern_dcache_area + .long v6_dma_map_area + .long v6_dma_unmap_area .long v6_dma_inv_range .long v6_dma_clean_range .long v6_dma_flush_range diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 9073db849fb4..e30d8bc67182 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -271,6 +271,30 @@ ENTRY(v7_dma_flush_range) mov pc, lr ENDPROC(v7_dma_flush_range) +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v7_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq v7_dma_clean_range + bcs v7_dma_inv_range + b v7_dma_flush_range +ENDPROC(v7_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(v7_dma_unmap_area) + mov pc, lr +ENDPROC(v7_dma_unmap_area) + __INITDATA .type v7_cache_fns, #object @@ -281,6 +305,8 @@ ENTRY(v7_cache_fns) .long v7_coherent_kern_range .long v7_coherent_user_range .long v7_flush_kern_dcache_area + .long v7_dma_map_area + .long v7_dma_unmap_area .long v7_dma_inv_range .long v7_dma_clean_range .long v7_dma_flush_range diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 0d68d2c83cda..efa8efa33f5e 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -406,35 +406,31 @@ EXPORT_SYMBOL(dma_free_coherent); */ static void dma_cache_maint(const void *start, size_t size, int direction) { - void (*inner_op)(const void *, const void *); void (*outer_op)(unsigned long, unsigned long); - BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1)); - switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ - inner_op = dmac_inv_range; outer_op = outer_inv_range; break; case DMA_TO_DEVICE: /* writeback only */ - inner_op = dmac_clean_range; outer_op = outer_clean_range; break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - inner_op = dmac_flush_range; outer_op = outer_flush_range; break; default: BUG(); } - inner_op(start, start + size); outer_op(__pa(start), __pa(start) + size); } void ___dma_single_cpu_to_dev(const void *kaddr, size_t size, enum dma_data_direction dir) { + BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); + + dmac_map_area(kaddr, size, dir); dma_cache_maint(kaddr, size, dir); } EXPORT_SYMBOL(___dma_single_cpu_to_dev); @@ -442,12 +438,15 @@ EXPORT_SYMBOL(___dma_single_cpu_to_dev); void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); + + dmac_unmap_area(kaddr, size, dir); } EXPORT_SYMBOL(___dma_single_dev_to_cpu); static void dma_cache_maint_page(struct page *page, unsigned long offset, - size_t size, void (*op)(const void *, const void *)) + size_t size, enum dma_data_direction dir, + void (*op)(const void *, size_t, int)) { /* * A single sg entry may refer to multiple physically contiguous @@ -471,12 +470,12 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, vaddr = kmap_high_get(page); if (vaddr) { vaddr += offset; - op(vaddr, vaddr + len); + op(vaddr, len, dir); kunmap_high(page); } } else { vaddr = page_address(page) + offset; - op(vaddr, vaddr + len); + op(vaddr, len, dir); } offset = 0; page++; @@ -488,27 +487,23 @@ void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { unsigned long paddr; - void (*inner_op)(const void *, const void *); void (*outer_op)(unsigned long, unsigned long); switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ - inner_op = dmac_inv_range; outer_op = outer_inv_range; break; case DMA_TO_DEVICE: /* writeback only */ - inner_op = dmac_clean_range; outer_op = outer_clean_range; break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - inner_op = dmac_flush_range; outer_op = outer_flush_range; break; default: BUG(); } - dma_cache_maint_page(page, off, size, inner_op); + dma_cache_maint_page(page, off, size, dir, dmac_map_area); paddr = page_to_phys(page) + off; outer_op(paddr, paddr + size); @@ -518,7 +513,7 @@ EXPORT_SYMBOL(___dma_page_cpu_to_dev); void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { - /* nothing to do */ + dma_cache_maint_page(page, off, size, dir, dmac_unmap_area); } EXPORT_SYMBOL(___dma_page_dev_to_cpu); diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 8012e24282b2..c85f5eb42634 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -330,6 +330,30 @@ ENTRY(arm1020_dma_flush_range) mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1020_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm1020_dma_clean_range + bcs arm1020_dma_inv_range + b arm1020_dma_flush_range +ENDPROC(arm1020_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1020_dma_unmap_area) + mov pc, lr +ENDPROC(arm1020_dma_unmap_area) + ENTRY(arm1020_cache_fns) .long arm1020_flush_kern_cache_all .long arm1020_flush_user_cache_all @@ -337,6 +361,8 @@ ENTRY(arm1020_cache_fns) .long arm1020_coherent_kern_range .long arm1020_coherent_user_range .long arm1020_flush_kern_dcache_area + .long arm1020_dma_map_area + .long arm1020_dma_unmap_area .long arm1020_dma_inv_range .long arm1020_dma_clean_range .long arm1020_dma_flush_range diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 41fe25d234f5..5a3cf7620a2c 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -316,6 +316,30 @@ ENTRY(arm1020e_dma_flush_range) mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1020e_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm1020e_dma_clean_range + bcs arm1020e_dma_inv_range + b arm1020e_dma_flush_range +ENDPROC(arm1020e_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1020e_dma_unmap_area) + mov pc, lr +ENDPROC(arm1020e_dma_unmap_area) + ENTRY(arm1020e_cache_fns) .long arm1020e_flush_kern_cache_all .long arm1020e_flush_user_cache_all @@ -323,6 +347,8 @@ ENTRY(arm1020e_cache_fns) .long arm1020e_coherent_kern_range .long arm1020e_coherent_user_range .long arm1020e_flush_kern_dcache_area + .long arm1020e_dma_map_area + .long arm1020e_dma_unmap_area .long arm1020e_dma_inv_range .long arm1020e_dma_clean_range .long arm1020e_dma_flush_range diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 20a5b1b31a70..fec8f5878438 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -305,6 +305,30 @@ ENTRY(arm1022_dma_flush_range) mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1022_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm1022_dma_clean_range + bcs arm1022_dma_inv_range + b arm1022_dma_flush_range +ENDPROC(arm1022_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1022_dma_unmap_area) + mov pc, lr +ENDPROC(arm1022_dma_unmap_area) + ENTRY(arm1022_cache_fns) .long arm1022_flush_kern_cache_all .long arm1022_flush_user_cache_all @@ -312,6 +336,8 @@ ENTRY(arm1022_cache_fns) .long arm1022_coherent_kern_range .long arm1022_coherent_user_range .long arm1022_flush_kern_dcache_area + .long arm1022_dma_map_area + .long arm1022_dma_unmap_area .long arm1022_dma_inv_range .long arm1022_dma_clean_range .long arm1022_dma_flush_range diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 96aedb10fcc4..9ece6f666497 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -299,6 +299,30 @@ ENTRY(arm1026_dma_flush_range) mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1026_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm1026_dma_clean_range + bcs arm1026_dma_inv_range + b arm1026_dma_flush_range +ENDPROC(arm1026_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm1026_dma_unmap_area) + mov pc, lr +ENDPROC(arm1026_dma_unmap_area) + ENTRY(arm1026_cache_fns) .long arm1026_flush_kern_cache_all .long arm1026_flush_user_cache_all @@ -306,6 +330,8 @@ ENTRY(arm1026_cache_fns) .long arm1026_coherent_kern_range .long arm1026_coherent_user_range .long arm1026_flush_kern_dcache_area + .long arm1026_dma_map_area + .long arm1026_dma_unmap_area .long arm1026_dma_inv_range .long arm1026_dma_clean_range .long arm1026_dma_flush_range diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 471669e2d7cb..6f6ab2747da6 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -288,6 +288,30 @@ ENTRY(arm920_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm920_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm920_dma_clean_range + bcs arm920_dma_inv_range + b arm920_dma_flush_range +ENDPROC(arm920_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm920_dma_unmap_area) + mov pc, lr +ENDPROC(arm920_dma_unmap_area) + ENTRY(arm920_cache_fns) .long arm920_flush_kern_cache_all .long arm920_flush_user_cache_all @@ -295,6 +319,8 @@ ENTRY(arm920_cache_fns) .long arm920_coherent_kern_range .long arm920_coherent_user_range .long arm920_flush_kern_dcache_area + .long arm920_dma_map_area + .long arm920_dma_unmap_area .long arm920_dma_inv_range .long arm920_dma_clean_range .long arm920_dma_flush_range diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index ee111b00fa41..4e4396b121ca 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -290,6 +290,30 @@ ENTRY(arm922_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm922_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm922_dma_clean_range + bcs arm922_dma_inv_range + b arm922_dma_flush_range +ENDPROC(arm922_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm922_dma_unmap_area) + mov pc, lr +ENDPROC(arm922_dma_unmap_area) + ENTRY(arm922_cache_fns) .long arm922_flush_kern_cache_all .long arm922_flush_user_cache_all @@ -297,6 +321,8 @@ ENTRY(arm922_cache_fns) .long arm922_coherent_kern_range .long arm922_coherent_user_range .long arm922_flush_kern_dcache_area + .long arm922_dma_map_area + .long arm922_dma_unmap_area .long arm922_dma_inv_range .long arm922_dma_clean_range .long arm922_dma_flush_range diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 8deb5bde58e4..7c01c5d1108c 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -341,6 +341,30 @@ ENTRY(arm925_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm925_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm925_dma_clean_range + bcs arm925_dma_inv_range + b arm925_dma_flush_range +ENDPROC(arm925_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm925_dma_unmap_area) + mov pc, lr +ENDPROC(arm925_dma_unmap_area) + ENTRY(arm925_cache_fns) .long arm925_flush_kern_cache_all .long arm925_flush_user_cache_all @@ -348,6 +372,8 @@ ENTRY(arm925_cache_fns) .long arm925_coherent_kern_range .long arm925_coherent_user_range .long arm925_flush_kern_dcache_area + .long arm925_dma_map_area + .long arm925_dma_unmap_area .long arm925_dma_inv_range .long arm925_dma_clean_range .long arm925_dma_flush_range diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 64db6e275a44..72a01a4b80ab 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -304,6 +304,30 @@ ENTRY(arm926_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm926_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm926_dma_clean_range + bcs arm926_dma_inv_range + b arm926_dma_flush_range +ENDPROC(arm926_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm926_dma_unmap_area) + mov pc, lr +ENDPROC(arm926_dma_unmap_area) + ENTRY(arm926_cache_fns) .long arm926_flush_kern_cache_all .long arm926_flush_user_cache_all @@ -311,6 +335,8 @@ ENTRY(arm926_cache_fns) .long arm926_coherent_kern_range .long arm926_coherent_user_range .long arm926_flush_kern_dcache_area + .long arm926_dma_map_area + .long arm926_dma_unmap_area .long arm926_dma_inv_range .long arm926_dma_clean_range .long arm926_dma_flush_range diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S index 8196b9f401fb..6bb58fca7270 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S @@ -233,6 +233,30 @@ ENTRY(arm940_dma_flush_range) mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm940_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm940_dma_clean_range + bcs arm940_dma_inv_range + b arm940_dma_flush_range +ENDPROC(arm940_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm940_dma_unmap_area) + mov pc, lr +ENDPROC(arm940_dma_unmap_area) + ENTRY(arm940_cache_fns) .long arm940_flush_kern_cache_all .long arm940_flush_user_cache_all @@ -240,6 +264,8 @@ ENTRY(arm940_cache_fns) .long arm940_coherent_kern_range .long arm940_coherent_user_range .long arm940_flush_kern_dcache_area + .long arm940_dma_map_area + .long arm940_dma_unmap_area .long arm940_dma_inv_range .long arm940_dma_clean_range .long arm940_dma_flush_range diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S index 9a951239c86c..ac0f9ba719d7 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S @@ -275,6 +275,30 @@ ENTRY(arm946_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm946_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq arm946_dma_clean_range + bcs arm946_dma_inv_range + b arm946_dma_flush_range +ENDPROC(arm946_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(arm946_dma_unmap_area) + mov pc, lr +ENDPROC(arm946_dma_unmap_area) + ENTRY(arm946_cache_fns) .long arm946_flush_kern_cache_all .long arm946_flush_user_cache_all @@ -282,6 +306,8 @@ ENTRY(arm946_cache_fns) .long arm946_coherent_kern_range .long arm946_coherent_user_range .long arm946_flush_kern_dcache_area + .long arm946_dma_map_area + .long arm946_dma_unmap_area .long arm946_dma_inv_range .long arm946_dma_clean_range .long arm946_dma_flush_range diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index dbc39383e66a..97e1d784f152 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S @@ -367,6 +367,44 @@ ENTRY(feroceon_range_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(feroceon_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq feroceon_dma_clean_range + bcs feroceon_dma_inv_range + b feroceon_dma_flush_range +ENDPROC(feroceon_dma_map_area) + +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(feroceon_range_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq feroceon_range_dma_clean_range + bcs feroceon_range_dma_inv_range + b feroceon_range_dma_flush_range +ENDPROC(feroceon_range_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(feroceon_dma_unmap_area) + mov pc, lr +ENDPROC(feroceon_dma_unmap_area) + ENTRY(feroceon_cache_fns) .long feroceon_flush_kern_cache_all .long feroceon_flush_user_cache_all @@ -374,6 +412,8 @@ ENTRY(feroceon_cache_fns) .long feroceon_coherent_kern_range .long feroceon_coherent_user_range .long feroceon_flush_kern_dcache_area + .long feroceon_dma_map_area + .long feroceon_dma_unmap_area .long feroceon_dma_inv_range .long feroceon_dma_clean_range .long feroceon_dma_flush_range @@ -385,6 +425,8 @@ ENTRY(feroceon_range_cache_fns) .long feroceon_coherent_kern_range .long feroceon_coherent_user_range .long feroceon_range_flush_kern_dcache_area + .long feroceon_range_dma_map_area + .long feroceon_dma_unmap_area .long feroceon_range_dma_inv_range .long feroceon_range_dma_clean_range .long feroceon_range_dma_flush_range diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S index 9674d36cc97d..55b7fbec6548 100644 --- a/arch/arm/mm/proc-mohawk.S +++ b/arch/arm/mm/proc-mohawk.S @@ -268,6 +268,30 @@ ENTRY(mohawk_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(mohawk_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq mohawk_dma_clean_range + bcs mohawk_dma_inv_range + b mohawk_dma_flush_range +ENDPROC(mohawk_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(mohawk_dma_unmap_area) + mov pc, lr +ENDPROC(mohawk_dma_unmap_area) + ENTRY(mohawk_cache_fns) .long mohawk_flush_kern_cache_all .long mohawk_flush_user_cache_all @@ -275,6 +299,8 @@ ENTRY(mohawk_cache_fns) .long mohawk_coherent_kern_range .long mohawk_coherent_user_range .long mohawk_flush_kern_dcache_area + .long mohawk_dma_map_area + .long mohawk_dma_unmap_area .long mohawk_dma_inv_range .long mohawk_dma_clean_range .long mohawk_dma_flush_range diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 96456f548798..4e4ce889b3e6 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -304,6 +304,30 @@ ENTRY(xsc3_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ data write barrier mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(xsc3_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq xsc3_dma_clean_range + bcs xsc3_dma_inv_range + b xsc3_dma_flush_range +ENDPROC(xsc3_dma_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(xsc3_dma_unmap_area) + mov pc, lr +ENDPROC(xsc3_dma_unmap_area) + ENTRY(xsc3_cache_fns) .long xsc3_flush_kern_cache_all .long xsc3_flush_user_cache_all @@ -311,6 +335,8 @@ ENTRY(xsc3_cache_fns) .long xsc3_coherent_kern_range .long xsc3_coherent_user_range .long xsc3_flush_kern_dcache_area + .long xsc3_dma_map_area + .long xsc3_dma_unmap_area .long xsc3_dma_inv_range .long xsc3_dma_clean_range .long xsc3_dma_flush_range diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 93df47265f2d..a7999f94bf27 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -363,6 +363,43 @@ ENTRY(xscale_dma_flush_range) mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer mov pc, lr +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(xscale_dma_map_area) + add r1, r1, r0 + cmp r2, #DMA_TO_DEVICE + beq xscale_dma_clean_range + bcs xscale_dma_inv_range + b xscale_dma_flush_range +ENDPROC(xscale_dma_map_area) + +/* + * dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(xscale_dma_a0_map_area) + add r1, r1, r0 + teq r2, #DMA_TO_DEVICE + beq xscale_dma_clean_range + b xscale_dma_flush_range +ENDPROC(xscsale_dma_a0_map_area) + +/* + * dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(xscale_dma_unmap_area) + mov pc, lr +ENDPROC(xscale_dma_unmap_area) + ENTRY(xscale_cache_fns) .long xscale_flush_kern_cache_all .long xscale_flush_user_cache_all @@ -370,6 +407,8 @@ ENTRY(xscale_cache_fns) .long xscale_coherent_kern_range .long xscale_coherent_user_range .long xscale_flush_kern_dcache_area + .long xscale_dma_map_area + .long xscale_dma_unmap_area .long xscale_dma_inv_range .long xscale_dma_clean_range .long xscale_dma_flush_range @@ -394,6 +433,8 @@ ENTRY(xscale_80200_A0_A1_cache_fns) .long xscale_coherent_kern_range .long xscale_coherent_user_range .long xscale_flush_kern_dcache_area + .long xscale_dma_a0_map_area + .long xscale_dma_unmap_area .long xscale_dma_flush_range .long xscale_dma_clean_range .long xscale_dma_flush_range -- GitLab From 702b94bff3c50542a6e4ab9a4f4cef093262fe65 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Nov 2009 16:24:19 +0000 Subject: [PATCH 2060/3892] ARM: dma-mapping: remove dmac_clean_range and dmac_inv_range These are now unused, and so can be removed. Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/include/asm/cacheflush.h | 23 ----------------------- arch/arm/mm/cache-fa.S | 6 ++---- arch/arm/mm/cache-v3.S | 29 +---------------------------- arch/arm/mm/cache-v4.S | 29 +---------------------------- arch/arm/mm/cache-v4wb.S | 6 ++---- arch/arm/mm/cache-v4wt.S | 15 +-------------- arch/arm/mm/cache-v6.S | 6 ++---- arch/arm/mm/cache-v7.S | 6 ++---- arch/arm/mm/proc-arm1020.S | 6 ++---- arch/arm/mm/proc-arm1020e.S | 6 ++---- arch/arm/mm/proc-arm1022.S | 6 ++---- arch/arm/mm/proc-arm1026.S | 6 ++---- arch/arm/mm/proc-arm920.S | 6 ++---- arch/arm/mm/proc-arm922.S | 6 ++---- arch/arm/mm/proc-arm925.S | 6 ++---- arch/arm/mm/proc-arm926.S | 6 ++---- arch/arm/mm/proc-arm940.S | 6 ++---- arch/arm/mm/proc-arm946.S | 6 ++---- arch/arm/mm/proc-feroceon.S | 12 ++++-------- arch/arm/mm/proc-mohawk.S | 6 ++---- arch/arm/mm/proc-xsc3.S | 6 ++---- arch/arm/mm/proc-xscale.S | 8 ++------ 22 files changed, 41 insertions(+), 171 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 4c733236e342..e29088587412 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -182,21 +182,6 @@ * DMA Cache Coherency * =================== * - * dma_inv_range(start, end) - * - * Invalidate (discard) the specified virtual address range. - * May not write back any entries. If 'start' or 'end' - * are not cache line aligned, those lines must be written - * back. - * - start - virtual start address - * - end - virtual end address - * - * dma_clean_range(start, end) - * - * Clean (write back) the specified virtual address range. - * - start - virtual start address - * - end - virtual end address - * * dma_flush_range(start, end) * * Clean and invalidate the specified virtual address range. @@ -216,8 +201,6 @@ struct cpu_cache_fns { void (*dma_map_area)(const void *, size_t, int); void (*dma_unmap_area)(const void *, size_t, int); - void (*dma_inv_range)(const void *, const void *); - void (*dma_clean_range)(const void *, const void *); void (*dma_flush_range)(const void *, const void *); }; @@ -249,8 +232,6 @@ extern struct cpu_cache_fns cpu_cache; */ #define dmac_map_area cpu_cache.dma_map_area #define dmac_unmap_area cpu_cache.dma_unmap_area -#define dmac_inv_range cpu_cache.dma_inv_range -#define dmac_clean_range cpu_cache.dma_clean_range #define dmac_flush_range cpu_cache.dma_flush_range #else @@ -277,14 +258,10 @@ extern void __cpuc_flush_dcache_area(void *, size_t); */ #define dmac_map_area __glue(_CACHE,_dma_map_area) #define dmac_unmap_area __glue(_CACHE,_dma_unmap_area) -#define dmac_inv_range __glue(_CACHE,_dma_inv_range) -#define dmac_clean_range __glue(_CACHE,_dma_clean_range) #define dmac_flush_range __glue(_CACHE,_dma_flush_range) extern void dmac_map_area(const void *, size_t, int); extern void dmac_unmap_area(const void *, size_t, int); -extern void dmac_inv_range(const void *, const void *); -extern void dmac_clean_range(const void *, const void *); extern void dmac_flush_range(const void *, const void *); #endif diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S index 8ebffdd6fcff..7148e53e6078 100644 --- a/arch/arm/mm/cache-fa.S +++ b/arch/arm/mm/cache-fa.S @@ -157,7 +157,7 @@ ENTRY(fa_flush_kern_dcache_area) * - start - virtual start address * - end - virtual end address */ -ENTRY(fa_dma_inv_range) +fa_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry @@ -180,7 +180,7 @@ ENTRY(fa_dma_inv_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(fa_dma_clean_range) +fa_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -241,7 +241,5 @@ ENTRY(fa_cache_fns) .long fa_flush_kern_dcache_area .long fa_dma_map_area .long fa_dma_unmap_area - .long fa_dma_inv_range - .long fa_dma_clean_range .long fa_dma_flush_range .size fa_cache_fns, . - fa_cache_fns diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index 6df52dc014be..c2ff3c599fee 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -83,20 +83,6 @@ ENTRY(v3_coherent_user_range) ENTRY(v3_flush_kern_dcache_area) /* FALLTHROUGH */ -/* - * dma_inv_range(start, end) - * - * Invalidate (discard) the specified virtual address range. - * May not write back any entries. If 'start' or 'end' - * are not cache line aligned, those lines must be written - * back. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(v3_dma_inv_range) - /* FALLTHROUGH */ - /* * dma_flush_range(start, end) * @@ -108,17 +94,6 @@ ENTRY(v3_dma_inv_range) ENTRY(v3_dma_flush_range) mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ flush ID cache - /* FALLTHROUGH */ - -/* - * dma_clean_range(start, end) - * - * Clean (write back) the specified virtual address range. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(v3_dma_clean_range) mov pc, lr /* @@ -129,7 +104,7 @@ ENTRY(v3_dma_clean_range) */ ENTRY(v3_dma_unmap_area) teq r2, #DMA_TO_DEVICE - bne v3_dma_inv_range + bne v3_dma_flush_range /* FALLTHROUGH */ /* @@ -155,7 +130,5 @@ ENTRY(v3_cache_fns) .long v3_flush_kern_dcache_area .long v3_dma_map_area .long v3_dma_unmap_area - .long v3_dma_inv_range - .long v3_dma_clean_range .long v3_dma_flush_range .size v3_cache_fns, . - v3_cache_fns diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index df3b423713b9..4810f7e3e813 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -93,20 +93,6 @@ ENTRY(v4_coherent_user_range) ENTRY(v4_flush_kern_dcache_area) /* FALLTHROUGH */ -/* - * dma_inv_range(start, end) - * - * Invalidate (discard) the specified virtual address range. - * May not write back any entries. If 'start' or 'end' - * are not cache line aligned, those lines must be written - * back. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(v4_dma_inv_range) - /* FALLTHROUGH */ - /* * dma_flush_range(start, end) * @@ -120,17 +106,6 @@ ENTRY(v4_dma_flush_range) mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ flush ID cache #endif - /* FALLTHROUGH */ - -/* - * dma_clean_range(start, end) - * - * Clean (write back) the specified virtual address range. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(v4_dma_clean_range) mov pc, lr /* @@ -141,7 +116,7 @@ ENTRY(v4_dma_clean_range) */ ENTRY(v4_dma_unmap_area) teq r2, #DMA_TO_DEVICE - bne v4_dma_inv_range + bne v4_dma_flush_range /* FALLTHROUGH */ /* @@ -167,7 +142,5 @@ ENTRY(v4_cache_fns) .long v4_flush_kern_dcache_area .long v4_dma_map_area .long v4_dma_unmap_area - .long v4_dma_inv_range - .long v4_dma_clean_range .long v4_dma_flush_range .size v4_cache_fns, . - v4_cache_fns diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 32e7a7448496..df8368afa102 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -173,7 +173,7 @@ ENTRY(v4wb_coherent_user_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(v4wb_dma_inv_range) +v4wb_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -194,7 +194,7 @@ ENTRY(v4wb_dma_inv_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(v4wb_dma_clean_range) +v4wb_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -252,7 +252,5 @@ ENTRY(v4wb_cache_fns) .long v4wb_flush_kern_dcache_area .long v4wb_dma_map_area .long v4wb_dma_unmap_area - .long v4wb_dma_inv_range - .long v4wb_dma_clean_range .long v4wb_dma_flush_range .size v4wb_cache_fns, . - v4wb_cache_fns diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index 3d8dad5b2650..45c70312f43b 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S @@ -142,23 +142,12 @@ ENTRY(v4wt_flush_kern_dcache_area) * - start - virtual start address * - end - virtual end address */ -ENTRY(v4wt_dma_inv_range) +v4wt_dma_inv_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry add r0, r0, #CACHE_DLINESIZE cmp r0, r1 blo 1b - /* FALLTHROUGH */ - -/* - * dma_clean_range(start, end) - * - * Clean the specified virtual address range. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(v4wt_dma_clean_range) mov pc, lr /* @@ -207,7 +196,5 @@ ENTRY(v4wt_cache_fns) .long v4wt_flush_kern_dcache_area .long v4wt_dma_map_area .long v4wt_dma_unmap_area - .long v4wt_dma_inv_range - .long v4wt_dma_clean_range .long v4wt_dma_flush_range .size v4wt_cache_fns, . - v4wt_cache_fns diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 6f926dd0e0f7..a11934e53fbd 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -195,7 +195,7 @@ ENTRY(v6_flush_kern_dcache_area) * - start - virtual start address of region * - end - virtual end address of region */ -ENTRY(v6_dma_inv_range) +v6_dma_inv_range: tst r0, #D_CACHE_LINE_SIZE - 1 bic r0, r0, #D_CACHE_LINE_SIZE - 1 #ifdef HARVARD_CACHE @@ -228,7 +228,7 @@ ENTRY(v6_dma_inv_range) * - start - virtual start address of region * - end - virtual end address of region */ -ENTRY(v6_dma_clean_range) +v6_dma_clean_range: bic r0, r0, #D_CACHE_LINE_SIZE - 1 1: #ifdef HARVARD_CACHE @@ -299,7 +299,5 @@ ENTRY(v6_cache_fns) .long v6_flush_kern_dcache_area .long v6_dma_map_area .long v6_dma_unmap_area - .long v6_dma_inv_range - .long v6_dma_clean_range .long v6_dma_flush_range .size v6_cache_fns, . - v6_cache_fns diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index e30d8bc67182..b1cd0fd91207 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -216,7 +216,7 @@ ENDPROC(v7_flush_kern_dcache_area) * - start - virtual start address of region * - end - virtual end address of region */ -ENTRY(v7_dma_inv_range) +v7_dma_inv_range: dcache_line_size r2, r3 sub r3, r2, #1 tst r0, r3 @@ -240,7 +240,7 @@ ENDPROC(v7_dma_inv_range) * - start - virtual start address of region * - end - virtual end address of region */ -ENTRY(v7_dma_clean_range) +v7_dma_clean_range: dcache_line_size r2, r3 sub r3, r2, #1 bic r0, r0, r3 @@ -307,7 +307,5 @@ ENTRY(v7_cache_fns) .long v7_flush_kern_dcache_area .long v7_dma_map_area .long v7_dma_unmap_area - .long v7_dma_inv_range - .long v7_dma_clean_range .long v7_dma_flush_range .size v7_cache_fns, . - v7_cache_fns diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index c85f5eb42634..72507c630ceb 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -265,7 +265,7 @@ ENTRY(arm1020_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm1020_dma_inv_range) +arm1020_dma_inv_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE tst r0, #CACHE_DLINESIZE - 1 @@ -295,7 +295,7 @@ ENTRY(arm1020_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm1020_dma_clean_range) +arm1020_dma_clean_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CACHE_DLINESIZE - 1 @@ -363,8 +363,6 @@ ENTRY(arm1020_cache_fns) .long arm1020_flush_kern_dcache_area .long arm1020_dma_map_area .long arm1020_dma_unmap_area - .long arm1020_dma_inv_range - .long arm1020_dma_clean_range .long arm1020_dma_flush_range .align 5 diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 5a3cf7620a2c..d27829805609 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -258,7 +258,7 @@ ENTRY(arm1020e_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm1020e_dma_inv_range) +arm1020e_dma_inv_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE tst r0, #CACHE_DLINESIZE - 1 @@ -284,7 +284,7 @@ ENTRY(arm1020e_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm1020e_dma_clean_range) +arm1020e_dma_clean_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CACHE_DLINESIZE - 1 @@ -349,8 +349,6 @@ ENTRY(arm1020e_cache_fns) .long arm1020e_flush_kern_dcache_area .long arm1020e_dma_map_area .long arm1020e_dma_unmap_area - .long arm1020e_dma_inv_range - .long arm1020e_dma_clean_range .long arm1020e_dma_flush_range .align 5 diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index fec8f5878438..ce13e4a827de 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -247,7 +247,7 @@ ENTRY(arm1022_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm1022_dma_inv_range) +arm1022_dma_inv_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE tst r0, #CACHE_DLINESIZE - 1 @@ -273,7 +273,7 @@ ENTRY(arm1022_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm1022_dma_clean_range) +arm1022_dma_clean_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CACHE_DLINESIZE - 1 @@ -338,8 +338,6 @@ ENTRY(arm1022_cache_fns) .long arm1022_flush_kern_dcache_area .long arm1022_dma_map_area .long arm1022_dma_unmap_area - .long arm1022_dma_inv_range - .long arm1022_dma_clean_range .long arm1022_dma_flush_range .align 5 diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 9ece6f666497..636672a29c6d 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -241,7 +241,7 @@ ENTRY(arm1026_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm1026_dma_inv_range) +arm1026_dma_inv_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE tst r0, #CACHE_DLINESIZE - 1 @@ -267,7 +267,7 @@ ENTRY(arm1026_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm1026_dma_clean_range) +arm1026_dma_clean_range: mov ip, #0 #ifndef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CACHE_DLINESIZE - 1 @@ -332,8 +332,6 @@ ENTRY(arm1026_cache_fns) .long arm1026_flush_kern_dcache_area .long arm1026_dma_map_area .long arm1026_dma_unmap_area - .long arm1026_dma_inv_range - .long arm1026_dma_clean_range .long arm1026_dma_flush_range .align 5 diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 6f6ab2747da6..8be81992645d 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -239,7 +239,7 @@ ENTRY(arm920_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm920_dma_inv_range) +arm920_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -262,7 +262,7 @@ ENTRY(arm920_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm920_dma_clean_range) +arm920_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -321,8 +321,6 @@ ENTRY(arm920_cache_fns) .long arm920_flush_kern_dcache_area .long arm920_dma_map_area .long arm920_dma_unmap_area - .long arm920_dma_inv_range - .long arm920_dma_clean_range .long arm920_dma_flush_range #endif diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 4e4396b121ca..c0ff8e4b1074 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -241,7 +241,7 @@ ENTRY(arm922_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm922_dma_inv_range) +arm922_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -264,7 +264,7 @@ ENTRY(arm922_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm922_dma_clean_range) +arm922_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -323,8 +323,6 @@ ENTRY(arm922_cache_fns) .long arm922_flush_kern_dcache_area .long arm922_dma_map_area .long arm922_dma_unmap_area - .long arm922_dma_inv_range - .long arm922_dma_clean_range .long arm922_dma_flush_range #endif diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 7c01c5d1108c..3c6cffe400f6 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -283,7 +283,7 @@ ENTRY(arm925_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm925_dma_inv_range) +arm925_dma_inv_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH tst r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -308,7 +308,7 @@ ENTRY(arm925_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm925_dma_clean_range) +arm925_dma_clean_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -374,8 +374,6 @@ ENTRY(arm925_cache_fns) .long arm925_flush_kern_dcache_area .long arm925_dma_map_area .long arm925_dma_unmap_area - .long arm925_dma_inv_range - .long arm925_dma_clean_range .long arm925_dma_flush_range ENTRY(cpu_arm925_dcache_clean_area) diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 72a01a4b80ab..75b707c9cce1 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -246,7 +246,7 @@ ENTRY(arm926_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(arm926_dma_inv_range) +arm926_dma_inv_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH tst r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -271,7 +271,7 @@ ENTRY(arm926_dma_inv_range) * * (same as v4wb) */ -ENTRY(arm926_dma_clean_range) +arm926_dma_clean_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -337,8 +337,6 @@ ENTRY(arm926_cache_fns) .long arm926_flush_kern_dcache_area .long arm926_dma_map_area .long arm926_dma_unmap_area - .long arm926_dma_inv_range - .long arm926_dma_clean_range .long arm926_dma_flush_range ENTRY(cpu_arm926_dcache_clean_area) diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S index 6bb58fca7270..1af1657819eb 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S @@ -171,7 +171,7 @@ ENTRY(arm940_flush_kern_dcache_area) * - start - virtual start address * - end - virtual end address */ -ENTRY(arm940_dma_inv_range) +arm940_dma_inv_range: mov ip, #0 mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments 1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries @@ -192,7 +192,7 @@ ENTRY(arm940_dma_inv_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(arm940_dma_clean_range) +arm940_dma_clean_range: ENTRY(cpu_arm940_dcache_clean_area) mov ip, #0 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH @@ -266,8 +266,6 @@ ENTRY(arm940_cache_fns) .long arm940_flush_kern_dcache_area .long arm940_dma_map_area .long arm940_dma_unmap_area - .long arm940_dma_inv_range - .long arm940_dma_clean_range .long arm940_dma_flush_range __INIT diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S index ac0f9ba719d7..1664b6aaff79 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S @@ -215,7 +215,7 @@ ENTRY(arm946_flush_kern_dcache_area) * - end - virtual end address * (same as arm926) */ -ENTRY(arm946_dma_inv_range) +arm946_dma_inv_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH tst r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -240,7 +240,7 @@ ENTRY(arm946_dma_inv_range) * * (same as arm926) */ -ENTRY(arm946_dma_clean_range) +arm946_dma_clean_range: #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -308,8 +308,6 @@ ENTRY(arm946_cache_fns) .long arm946_flush_kern_dcache_area .long arm946_dma_map_area .long arm946_dma_unmap_area - .long arm946_dma_inv_range - .long arm946_dma_clean_range .long arm946_dma_flush_range diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index 97e1d784f152..53e632343849 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S @@ -274,7 +274,7 @@ ENTRY(feroceon_range_flush_kern_dcache_area) * (same as v4wb) */ .align 5 -ENTRY(feroceon_dma_inv_range) +feroceon_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -288,7 +288,7 @@ ENTRY(feroceon_dma_inv_range) mov pc, lr .align 5 -ENTRY(feroceon_range_dma_inv_range) +feroceon_range_dma_inv_range: mrs r2, cpsr tst r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -314,7 +314,7 @@ ENTRY(feroceon_range_dma_inv_range) * (same as v4wb) */ .align 5 -ENTRY(feroceon_dma_clean_range) +feroceon_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -324,7 +324,7 @@ ENTRY(feroceon_dma_clean_range) mov pc, lr .align 5 -ENTRY(feroceon_range_dma_clean_range) +feroceon_range_dma_clean_range: mrs r2, cpsr cmp r1, r0 subne r1, r1, #1 @ top address is inclusive @@ -414,8 +414,6 @@ ENTRY(feroceon_cache_fns) .long feroceon_flush_kern_dcache_area .long feroceon_dma_map_area .long feroceon_dma_unmap_area - .long feroceon_dma_inv_range - .long feroceon_dma_clean_range .long feroceon_dma_flush_range ENTRY(feroceon_range_cache_fns) @@ -427,8 +425,6 @@ ENTRY(feroceon_range_cache_fns) .long feroceon_range_flush_kern_dcache_area .long feroceon_range_dma_map_area .long feroceon_dma_unmap_area - .long feroceon_range_dma_inv_range - .long feroceon_range_dma_clean_range .long feroceon_range_dma_flush_range .align 5 diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S index 55b7fbec6548..caa31154e7db 100644 --- a/arch/arm/mm/proc-mohawk.S +++ b/arch/arm/mm/proc-mohawk.S @@ -218,7 +218,7 @@ ENTRY(mohawk_flush_kern_dcache_area) * * (same as v4wb) */ -ENTRY(mohawk_dma_inv_range) +mohawk_dma_inv_range: tst r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry tst r1, #CACHE_DLINESIZE - 1 @@ -241,7 +241,7 @@ ENTRY(mohawk_dma_inv_range) * * (same as v4wb) */ -ENTRY(mohawk_dma_clean_range) +mohawk_dma_clean_range: bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -301,8 +301,6 @@ ENTRY(mohawk_cache_fns) .long mohawk_flush_kern_dcache_area .long mohawk_dma_map_area .long mohawk_dma_unmap_area - .long mohawk_dma_inv_range - .long mohawk_dma_clean_range .long mohawk_dma_flush_range ENTRY(cpu_mohawk_dcache_clean_area) diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 4e4ce889b3e6..046b3d88955e 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -257,7 +257,7 @@ ENTRY(xsc3_flush_kern_dcache_area) * - start - virtual start address * - end - virtual end address */ -ENTRY(xsc3_dma_inv_range) +xsc3_dma_inv_range: tst r0, #CACHELINESIZE - 1 bic r0, r0, #CACHELINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line @@ -278,7 +278,7 @@ ENTRY(xsc3_dma_inv_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(xsc3_dma_clean_range) +xsc3_dma_clean_range: bic r0, r0, #CACHELINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line add r0, r0, #CACHELINESIZE @@ -337,8 +337,6 @@ ENTRY(xsc3_cache_fns) .long xsc3_flush_kern_dcache_area .long xsc3_dma_map_area .long xsc3_dma_unmap_area - .long xsc3_dma_inv_range - .long xsc3_dma_clean_range .long xsc3_dma_flush_range ENTRY(cpu_xsc3_dcache_clean_area) diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index a7999f94bf27..63037e2162f2 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -315,7 +315,7 @@ ENTRY(xscale_flush_kern_dcache_area) * - start - virtual start address * - end - virtual end address */ -ENTRY(xscale_dma_inv_range) +xscale_dma_inv_range: tst r0, #CACHELINESIZE - 1 bic r0, r0, #CACHELINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -336,7 +336,7 @@ ENTRY(xscale_dma_inv_range) * - start - virtual start address * - end - virtual end address */ -ENTRY(xscale_dma_clean_range) +xscale_dma_clean_range: bic r0, r0, #CACHELINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHELINESIZE @@ -409,8 +409,6 @@ ENTRY(xscale_cache_fns) .long xscale_flush_kern_dcache_area .long xscale_dma_map_area .long xscale_dma_unmap_area - .long xscale_dma_inv_range - .long xscale_dma_clean_range .long xscale_dma_flush_range /* @@ -436,8 +434,6 @@ ENTRY(xscale_80200_A0_A1_cache_fns) .long xscale_dma_a0_map_area .long xscale_dma_unmap_area .long xscale_dma_flush_range - .long xscale_dma_clean_range - .long xscale_dma_flush_range ENTRY(cpu_xscale_dcache_clean_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry -- GitLab From 2ffe2da3e71652d4f4cae19539b5c78c2a239136 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 31 Oct 2009 16:52:16 +0000 Subject: [PATCH 2061/3892] ARM: dma-mapping: fix for speculative prefetching ARMv6 and ARMv7 CPUs can perform speculative prefetching, which makes DMA cache coherency handling slightly more interesting. Rather than being able to rely upon the CPU not accessing the DMA buffer until DMA has completed, we now must expect that the cache could be loaded with possibly stale data from the DMA buffer. Where DMA involves data being transferred to the device, we clean the cache before handing it over for DMA, otherwise we invalidate the buffer to get rid of potential writebacks. On DMA Completion, if data was transferred from the device, we invalidate the buffer to get rid of any stale speculative prefetches. Signed-off-by: Russell King Tested-By: Santosh Shilimkar --- arch/arm/mm/cache-v6.S | 10 +++--- arch/arm/mm/cache-v7.S | 10 +++--- arch/arm/mm/dma-mapping.c | 68 +++++++++++++++++---------------------- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index a11934e53fbd..9d89c67a1cc3 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -271,10 +271,9 @@ ENTRY(v6_dma_flush_range) */ ENTRY(v6_dma_map_area) add r1, r1, r0 - cmp r2, #DMA_TO_DEVICE - beq v6_dma_clean_range - bcs v6_dma_inv_range - b v6_dma_flush_range + teq r2, #DMA_FROM_DEVICE + beq v6_dma_inv_range + b v6_dma_clean_range ENDPROC(v6_dma_map_area) /* @@ -284,6 +283,9 @@ ENDPROC(v6_dma_map_area) * - dir - DMA direction */ ENTRY(v6_dma_unmap_area) + add r1, r1, r0 + teq r2, #DMA_TO_DEVICE + bne v6_dma_inv_range mov pc, lr ENDPROC(v6_dma_unmap_area) diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index b1cd0fd91207..bcd64f265870 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -279,10 +279,9 @@ ENDPROC(v7_dma_flush_range) */ ENTRY(v7_dma_map_area) add r1, r1, r0 - cmp r2, #DMA_TO_DEVICE - beq v7_dma_clean_range - bcs v7_dma_inv_range - b v7_dma_flush_range + teq r2, #DMA_FROM_DEVICE + beq v7_dma_inv_range + b v7_dma_clean_range ENDPROC(v7_dma_map_area) /* @@ -292,6 +291,9 @@ ENDPROC(v7_dma_map_area) * - dir - DMA direction */ ENTRY(v7_dma_unmap_area) + add r1, r1, r0 + teq r2, #DMA_TO_DEVICE + bne v7_dma_inv_range mov pc, lr ENDPROC(v7_dma_unmap_area) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index efa8efa33f5e..64daef2173bd 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -404,34 +404,22 @@ EXPORT_SYMBOL(dma_free_coherent); * platforms with CONFIG_DMABOUNCE. * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ -static void dma_cache_maint(const void *start, size_t size, int direction) -{ - void (*outer_op)(unsigned long, unsigned long); - - switch (direction) { - case DMA_FROM_DEVICE: /* invalidate only */ - outer_op = outer_inv_range; - break; - case DMA_TO_DEVICE: /* writeback only */ - outer_op = outer_clean_range; - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - outer_op = outer_flush_range; - break; - default: - BUG(); - } - - outer_op(__pa(start), __pa(start) + size); -} - void ___dma_single_cpu_to_dev(const void *kaddr, size_t size, enum dma_data_direction dir) { + unsigned long paddr; + BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); dmac_map_area(kaddr, size, dir); - dma_cache_maint(kaddr, size, dir); + + paddr = __pa(kaddr); + if (dir == DMA_FROM_DEVICE) { + outer_inv_range(paddr, paddr + size); + } else { + outer_clean_range(paddr, paddr + size); + } + /* FIXME: non-speculating: flush on bidirectional mappings? */ } EXPORT_SYMBOL(___dma_single_cpu_to_dev); @@ -440,6 +428,13 @@ void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, { BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); + /* FIXME: non-speculating: not required */ + /* don't bother invalidating if DMA to device */ + if (dir != DMA_TO_DEVICE) { + unsigned long paddr = __pa(kaddr); + outer_inv_range(paddr, paddr + size); + } + dmac_unmap_area(kaddr, size, dir); } EXPORT_SYMBOL(___dma_single_dev_to_cpu); @@ -487,32 +482,29 @@ void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { unsigned long paddr; - void (*outer_op)(unsigned long, unsigned long); - - switch (direction) { - case DMA_FROM_DEVICE: /* invalidate only */ - outer_op = outer_inv_range; - break; - case DMA_TO_DEVICE: /* writeback only */ - outer_op = outer_clean_range; - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - outer_op = outer_flush_range; - break; - default: - BUG(); - } dma_cache_maint_page(page, off, size, dir, dmac_map_area); paddr = page_to_phys(page) + off; - outer_op(paddr, paddr + size); + if (dir == DMA_FROM_DEVICE) { + outer_inv_range(paddr, paddr + size); + } else { + outer_clean_range(paddr, paddr + size); + } + /* FIXME: non-speculating: flush on bidirectional mappings? */ } EXPORT_SYMBOL(___dma_page_cpu_to_dev); void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { + unsigned long paddr = page_to_phys(page) + off; + + /* FIXME: non-speculating: not required */ + /* don't bother invalidating if DMA to device */ + if (dir != DMA_TO_DEVICE) + outer_inv_range(paddr, paddr + size); + dma_cache_maint_page(page, off, size, dir, dmac_unmap_area); } EXPORT_SYMBOL(___dma_page_dev_to_cpu); -- GitLab From 98e6d2d5ee26bf56850a10eb64139c68fb09ba19 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 15 Feb 2010 16:31:35 +0100 Subject: [PATCH 2062/3892] netfilter: xt_recent: inform user when hitcount is too large It is one of these things that iptables cannot catch and which can cause "Invalid argument" to be printed. Without a hint in dmesg, it is not going to be helpful. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/netfilter/xt_recent.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 203333107367..132cfaa84cdc 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -53,7 +53,7 @@ module_param(ip_list_perms, uint, 0400); module_param(ip_list_uid, uint, 0400); module_param(ip_list_gid, uint, 0400); MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); -MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)"); +MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)"); MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files"); MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/xt_recent/* files"); @@ -306,8 +306,12 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) && (info->seconds || info->hit_count)) return false; - if (info->hit_count > ip_pkt_list_tot) + if (info->hit_count > ip_pkt_list_tot) { + pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than " + "packets to be remembered (%u)\n", + info->hit_count, ip_pkt_list_tot); return false; + } if (info->name[0] == '\0' || strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) return false; -- GitLab From fa96a0e2e67fe34a3d994e3f354a5c229dd14286 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 1 Nov 2009 00:36:40 +0100 Subject: [PATCH 2063/3892] netfilter: iptables: remove unused function arguments Signed-off-by: Jan Engelhardt --- net/ipv4/netfilter/iptable_mangle.c | 10 +++------- net/ipv6/netfilter/ip6table_mangle.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index c8333305d631..b9b83464cbf4 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -36,11 +36,7 @@ static const struct xt_table packet_mangler = { }; static unsigned int -ipt_local_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) { unsigned int ret; const struct iphdr *iph; @@ -60,7 +56,7 @@ ipt_local_hook(unsigned int hook, daddr = iph->daddr; tos = iph->tos; - ret = ipt_do_table(skb, hook, in, out, + ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, dev_net(out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { @@ -86,7 +82,7 @@ iptable_mangle_hook(unsigned int hook, int (*okfn)(struct sk_buff *)) { if (hook == NF_INET_LOCAL_OUT) - return ipt_local_hook(hook, skb, in, out, okfn); + return ipt_mangle_out(skb, out); if (hook == NF_INET_POST_ROUTING) return ipt_do_table(skb, hook, in, out, dev_net(out)->ipv4.iptable_mangle); diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index b6216dede52c..7844e557c0ec 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -30,12 +30,8 @@ static const struct xt_table packet_mangler = { }; static unsigned int -ip6t_local_out_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) +ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) { - unsigned int ret; struct in6_addr saddr, daddr; u_int8_t hop_limit; @@ -60,7 +56,7 @@ ip6t_local_out_hook(unsigned int hook, /* flowlabel and prio (includes version, which shouldn't change either */ flowlabel = *((u_int32_t *)ipv6_hdr(skb)); - ret = ip6t_do_table(skb, hook, NULL, out, + ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, dev_net(out)->ipv6.ip6table_mangle); if (ret != NF_DROP && ret != NF_STOLEN && @@ -80,7 +76,7 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, int (*okfn)(struct sk_buff *)) { if (hook == NF_INET_LOCAL_OUT) - return ip6t_local_out_hook(hook, skb, out, okfn); + return ip6t_mangle_out(skb, out); if (hook == NF_INET_POST_ROUTING) return ip6t_do_table(skb, hook, in, out, dev_net(out)->ipv6.ip6table_mangle); -- GitLab From 23f3733d440b918ccb7746718f77256334cf6176 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 5 Jun 2009 17:31:46 +0200 Subject: [PATCH 2064/3892] netfilter: reduce NF_HOOK by one argument No changes in vmlinux filesize. Signed-off-by: Jan Engelhardt --- include/linux/netfilter.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 78f33d223680..2f22816a5514 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -163,11 +163,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh, - int cond) + int (*okfn)(struct sk_buff *), int thresh) { - if (!cond) - return 1; #ifndef CONFIG_NETFILTER_DEBUG if (list_empty(&nf_hooks[pf][hook])) return 1; @@ -179,7 +176,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *)) { - return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN, 1); + return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN); } /* Activate hook; either okfn or kfree_skb called, unless a hook @@ -206,13 +203,13 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ ({int __ret; \ -if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\ +if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh)) == 1)\ __ret = (okfn)(skb); \ __ret;}) #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \ ({int __ret; \ -if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\ +if ((cond) || (__ret = nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN)) == 1)\ __ret = (okfn)(skb); \ __ret;}) @@ -328,8 +325,7 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh, - int cond) + int (*okfn)(struct sk_buff *), int thresh) { return okfn(skb); } -- GitLab From 2249065f4b22b493bae2caf549b86f175f33188e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 04:13:26 +0200 Subject: [PATCH 2065/3892] netfilter: get rid of the grossness in netfilter.h GCC is now smart enough to follow the inline trail correctly. vmlinux size remain the same. Signed-off-by: Jan Engelhardt --- include/linux/netfilter.h | 45 ++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 2f22816a5514..70079454ffd0 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -196,25 +196,36 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, coders :) */ -/* This is gross, but inline doesn't cut it for avoiding the function - call in fast path: gcc doesn't inline (needs value tracking?). --RR */ - -/* HX: It's slightly less gross now. */ - -#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ -({int __ret; \ -if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh)) == 1)\ - __ret = (okfn)(skb); \ -__ret;}) +static inline int +NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb, + struct net_device *in, struct net_device *out, + int (*okfn)(struct sk_buff *), int thresh) +{ + int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh); + if (ret == 1) + ret = okfn(skb); + return ret; +} -#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \ -({int __ret; \ -if ((cond) || (__ret = nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN)) == 1)\ - __ret = (okfn)(skb); \ -__ret;}) +static inline int +NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb, + struct net_device *in, struct net_device *out, + int (*okfn)(struct sk_buff *), bool cond) +{ + int ret = 1; + if (cond || + (ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1)) + ret = okfn(skb); + return ret; +} -#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ - NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN) +static inline int +NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb, + struct net_device *in, struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN); +} /* Call setsockopt() */ int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, -- GitLab From b402405d71beed8e4df354844353f66b4e18269f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 25 Jun 2009 18:32:12 +0200 Subject: [PATCH 2066/3892] netfilter: xtables: print details on size mismatch Print which revision has been used and which size are which (kernel/user) for easier debugging. Signed-off-by: Jan Engelhardt --- net/netfilter/x_tables.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 255ab0657ce8..12503199826f 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -366,8 +366,10 @@ int xt_check_match(struct xt_mtchk_param *par, * ebt_among is exempt from centralized matchsize checking * because it uses a dynamic-size data set. */ - pr_err("%s_tables: %s match: invalid size %u != %u\n", + pr_err("%s_tables: %s.%u match: invalid size " + "%u (kernel) != (user) %u\n", xt_prefix[par->family], par->match->name, + par->match->revision, XT_ALIGN(par->match->matchsize), size); return -EINVAL; } @@ -516,8 +518,10 @@ int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { if (XT_ALIGN(par->target->targetsize) != size) { - pr_err("%s_tables: %s target: invalid size %u != %u\n", + pr_err("%s_tables: %s.%u target: invalid size " + "%u (kernel) != (user) %u\n", xt_prefix[par->family], par->target->name, + par->target->revision, XT_ALIGN(par->target->targetsize), size); return -EINVAL; } -- GitLab From 739674fb7febf116e7d647031fab16989a08a965 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 26 Jun 2009 08:23:19 +0200 Subject: [PATCH 2067/3892] netfilter: xtables: constify args in compat copying functions Signed-off-by: Jan Engelhardt --- include/linux/netfilter/x_tables.h | 12 ++++++------ net/ipv4/netfilter/arp_tables.c | 4 ++-- net/ipv4/netfilter/ip_tables.c | 4 ++-- net/ipv4/netfilter/ipt_ULOG.c | 4 ++-- net/ipv6/netfilter/ip6_tables.c | 4 ++-- net/netfilter/x_tables.c | 8 ++++---- net/netfilter/xt_hashlimit.c | 4 ++-- net/netfilter/xt_limit.c | 4 ++-- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index a0a144a6c6d9..c61758f4be31 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -286,8 +286,8 @@ struct xt_match { void (*destroy)(const struct xt_mtdtor_param *); #ifdef CONFIG_COMPAT /* Called when userspace align differs from kernel space one */ - void (*compat_from_user)(void *dst, void *src); - int (*compat_to_user)(void __user *dst, void *src); + void (*compat_from_user)(void *dst, const void *src); + int (*compat_to_user)(void __user *dst, const void *src); #endif /* Set this to THIS_MODULE if you are a module, otherwise NULL */ struct module *me; @@ -328,8 +328,8 @@ struct xt_target { void (*destroy)(const struct xt_tgdtor_param *); #ifdef CONFIG_COMPAT /* Called when userspace align differs from kernel space one */ - void (*compat_from_user)(void *dst, void *src); - int (*compat_to_user)(void __user *dst, void *src); + void (*compat_from_user)(void *dst, const void *src); + int (*compat_to_user)(void __user *dst, const void *src); #endif /* Set this to THIS_MODULE if you are a module, otherwise NULL */ struct module *me; @@ -593,13 +593,13 @@ extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset); extern int xt_compat_match_offset(const struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size); -extern int xt_compat_match_to_user(struct xt_entry_match *m, +extern int xt_compat_match_to_user(const struct xt_entry_match *m, void __user **dstptr, unsigned int *size); extern int xt_compat_target_offset(const struct xt_target *target); extern void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size); -extern int xt_compat_target_to_user(struct xt_entry_target *t, +extern int xt_compat_target_to_user(const struct xt_entry_target *t, void __user **dstptr, unsigned int *size); #endif /* CONFIG_COMPAT */ diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 72723ea1054b..2303dc92a277 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -842,7 +842,7 @@ static int copy_entries_to_user(unsigned int total_size, } #ifdef CONFIG_COMPAT -static void compat_standard_from_user(void *dst, void *src) +static void compat_standard_from_user(void *dst, const void *src) { int v = *(compat_int_t *)src; @@ -851,7 +851,7 @@ static void compat_standard_from_user(void *dst, void *src) memcpy(dst, &v, sizeof(v)); } -static int compat_standard_to_user(void __user *dst, void *src) +static int compat_standard_to_user(void __user *dst, const void *src) { compat_int_t cv = *(int *)src; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2057b1bb6178..2a4f745ce36e 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1047,7 +1047,7 @@ copy_entries_to_user(unsigned int total_size, } #ifdef CONFIG_COMPAT -static void compat_standard_from_user(void *dst, void *src) +static void compat_standard_from_user(void *dst, const void *src) { int v = *(compat_int_t *)src; @@ -1056,7 +1056,7 @@ static void compat_standard_from_user(void *dst, void *src) memcpy(dst, &v, sizeof(v)); } -static int compat_standard_to_user(void __user *dst, void *src) +static int compat_standard_to_user(void __user *dst, const void *src) { compat_int_t cv = *(int *)src; diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 399061c3fd7d..09a5d3f7cc41 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -338,7 +338,7 @@ struct compat_ipt_ulog_info { char prefix[ULOG_PREFIX_LEN]; }; -static void ulog_tg_compat_from_user(void *dst, void *src) +static void ulog_tg_compat_from_user(void *dst, const void *src) { const struct compat_ipt_ulog_info *cl = src; struct ipt_ulog_info l = { @@ -351,7 +351,7 @@ static void ulog_tg_compat_from_user(void *dst, void *src) memcpy(dst, &l, sizeof(l)); } -static int ulog_tg_compat_to_user(void __user *dst, void *src) +static int ulog_tg_compat_to_user(void __user *dst, const void *src) { const struct ipt_ulog_info *l = src; struct compat_ipt_ulog_info cl = { diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index dcd7825fe7b6..3ff4fd50e96e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1079,7 +1079,7 @@ copy_entries_to_user(unsigned int total_size, } #ifdef CONFIG_COMPAT -static void compat_standard_from_user(void *dst, void *src) +static void compat_standard_from_user(void *dst, const void *src) { int v = *(compat_int_t *)src; @@ -1088,7 +1088,7 @@ static void compat_standard_from_user(void *dst, void *src) memcpy(dst, &v, sizeof(v)); } -static int compat_standard_to_user(void __user *dst, void *src) +static int compat_standard_to_user(void __user *dst, const void *src) { compat_int_t cv = *(int *)src; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 12503199826f..69c56287d518 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -485,8 +485,8 @@ int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, } EXPORT_SYMBOL_GPL(xt_compat_match_from_user); -int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, - unsigned int *size) +int xt_compat_match_to_user(const struct xt_entry_match *m, + void __user **dstptr, unsigned int *size) { const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match __user *cm = *dstptr; @@ -588,8 +588,8 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, } EXPORT_SYMBOL_GPL(xt_compat_target_from_user); -int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr, - unsigned int *size) +int xt_compat_target_to_user(const struct xt_entry_target *t, + void __user **dstptr, unsigned int *size) { const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target __user *ct = *dstptr; diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 017c95966aa8..e47fb805ffb4 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -775,7 +775,7 @@ struct compat_xt_hashlimit_info { compat_uptr_t master; }; -static void hashlimit_mt_compat_from_user(void *dst, void *src) +static void hashlimit_mt_compat_from_user(void *dst, const void *src) { int off = offsetof(struct compat_xt_hashlimit_info, hinfo); @@ -783,7 +783,7 @@ static void hashlimit_mt_compat_from_user(void *dst, void *src) memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off); } -static int hashlimit_mt_compat_to_user(void __user *dst, void *src) +static int hashlimit_mt_compat_to_user(void __user *dst, const void *src) { int off = offsetof(struct compat_xt_hashlimit_info, hinfo); diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 2773be6a71dd..a0ca5339af41 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -148,7 +148,7 @@ struct compat_xt_rateinfo { /* To keep the full "prev" timestamp, the upper 32 bits are stored in the * master pointer, which does not need to be preserved. */ -static void limit_mt_compat_from_user(void *dst, void *src) +static void limit_mt_compat_from_user(void *dst, const void *src) { const struct compat_xt_rateinfo *cm = src; struct xt_rateinfo m = { @@ -162,7 +162,7 @@ static void limit_mt_compat_from_user(void *dst, void *src) memcpy(dst, &m, sizeof(m)); } -static int limit_mt_compat_to_user(void __user *dst, void *src) +static int limit_mt_compat_to_user(void __user *dst, const void *src) { const struct xt_rateinfo *m = src; struct compat_xt_rateinfo cm = { -- GitLab From d5d1baa15f5b05e9110403724d5dc72d6d541e04 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 26 Jun 2009 07:51:59 +0200 Subject: [PATCH 2068/3892] netfilter: xtables: add const qualifiers This should make it easier to remove redundant arguments later. Signed-off-by: Jan Engelhardt --- net/bridge/netfilter/ebtables.c | 59 ++++++++++++---------- net/ipv4/netfilter/arp_tables.c | 69 +++++++++++++++----------- net/ipv4/netfilter/ip_tables.c | 88 ++++++++++++++++++--------------- net/ipv6/netfilter/ip6_tables.c | 88 ++++++++++++++++++--------------- 4 files changed, 168 insertions(+), 136 deletions(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 208f4e32e732..bcdf02d866b8 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -82,7 +82,8 @@ static inline int ebt_do_match (struct ebt_entry_match *m, return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH; } -static inline int ebt_dev_check(char *entry, const struct net_device *device) +static inline int +ebt_dev_check(const char *entry, const struct net_device *device) { int i = 0; const char *devname; @@ -100,8 +101,9 @@ static inline int ebt_dev_check(char *entry, const struct net_device *device) #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) /* process standard matches */ -static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, - const struct net_device *in, const struct net_device *out) +static inline int +ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, + const struct net_device *in, const struct net_device *out) { int verdict, i; @@ -156,12 +158,12 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, int i, nentries; struct ebt_entry *point; struct ebt_counter *counter_base, *cb_base; - struct ebt_entry_target *t; + const struct ebt_entry_target *t; int verdict, sp = 0; struct ebt_chainstack *cs; struct ebt_entries *chaininfo; - char *base; - struct ebt_table_info *private; + const char *base; + const struct ebt_table_info *private; bool hotdrop = false; struct xt_match_param mtpar; struct xt_target_param tgpar; @@ -395,7 +397,7 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par, return 0; } -static int ebt_verify_pointers(struct ebt_replace *repl, +static int ebt_verify_pointers(const struct ebt_replace *repl, struct ebt_table_info *newinfo) { unsigned int limit = repl->entries_size; @@ -466,8 +468,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl, * to parse the userspace data */ static inline int -ebt_check_entry_size_and_hooks(struct ebt_entry *e, - struct ebt_table_info *newinfo, +ebt_check_entry_size_and_hooks(const struct ebt_entry *e, + const struct ebt_table_info *newinfo, unsigned int *n, unsigned int *cnt, unsigned int *totalcnt, unsigned int *udc_cnt) { @@ -622,9 +624,8 @@ ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt) } static inline int -ebt_check_entry(struct ebt_entry *e, - struct net *net, - struct ebt_table_info *newinfo, +ebt_check_entry(struct ebt_entry *e, struct net *net, + const struct ebt_table_info *newinfo, const char *name, unsigned int *cnt, struct ebt_cl_stack *cl_s, unsigned int udc_cnt) { @@ -743,12 +744,12 @@ cleanup_matches: * the hook mask for udc tells us from which base chains the udc can be * accessed. This mask is a parameter to the check() functions of the extensions */ -static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s, +static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s, unsigned int udc_cnt, unsigned int hooknr, char *base) { int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; - struct ebt_entry *e = (struct ebt_entry *)chain->data; - struct ebt_entry_target *t; + const struct ebt_entry *e = (struct ebt_entry *)chain->data; + const struct ebt_entry_target *t; while (pos < nentries || chain_nr != -1) { /* end of udc, go back one 'recursion' step */ @@ -814,7 +815,7 @@ letscontinue: } /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */ -static int translate_table(struct net *net, char *name, +static int translate_table(struct net *net, const char *name, struct ebt_table_info *newinfo) { unsigned int i, j, k, udc_cnt; @@ -934,7 +935,7 @@ static int translate_table(struct net *net, char *name, } /* called under write_lock */ -static void get_counters(struct ebt_counter *oldcounters, +static void get_counters(const struct ebt_counter *oldcounters, struct ebt_counter *counters, unsigned int nentries) { int i, cpu; @@ -957,7 +958,8 @@ static void get_counters(struct ebt_counter *oldcounters, } /* replace the table */ -static int do_replace(struct net *net, void __user *user, unsigned int len) +static int do_replace(struct net *net, const void __user *user, + unsigned int len) { int ret, i, countersize; struct ebt_table_info *newinfo; @@ -1237,7 +1239,8 @@ void ebt_unregister_table(struct net *net, struct ebt_table *table) } /* userspace just supplied us with counters */ -static int update_counters(struct net *net, void __user *user, unsigned int len) +static int update_counters(struct net *net, const void __user *user, + unsigned int len) { int i, ret; struct ebt_counter *tmp; @@ -1292,8 +1295,8 @@ free_tmp: return ret; } -static inline int ebt_make_matchname(struct ebt_entry_match *m, - char *base, char __user *ubase) +static inline int ebt_make_matchname(const struct ebt_entry_match *m, + const char *base, char __user *ubase) { char __user *hlp = ubase + ((char *)m - base); if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) @@ -1301,8 +1304,8 @@ static inline int ebt_make_matchname(struct ebt_entry_match *m, return 0; } -static inline int ebt_make_watchername(struct ebt_entry_watcher *w, - char *base, char __user *ubase) +static inline int ebt_make_watchername(const struct ebt_entry_watcher *w, + const char *base, char __user *ubase) { char __user *hlp = ubase + ((char *)w - base); if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) @@ -1310,11 +1313,12 @@ static inline int ebt_make_watchername(struct ebt_entry_watcher *w, return 0; } -static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase) +static inline int +ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase) { int ret; char __user *hlp; - struct ebt_entry_target *t; + const struct ebt_entry_target *t; if (e->bitmask == 0) return 0; @@ -1335,10 +1339,11 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *u /* called with ebt_mutex locked */ static int copy_everything_to_user(struct ebt_table *t, void __user *user, - int *len, int cmd) + const int *len, int cmd) { struct ebt_replace tmp; - struct ebt_counter *counterstmp, *oldcounters; + struct ebt_counter *counterstmp; + const struct ebt_counter *oldcounters; unsigned int entries_size, nentries; char *entries; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 2303dc92a277..4db5c1ece0f9 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -233,7 +233,14 @@ arpt_error(struct sk_buff *skb, const struct xt_target_param *par) return NF_DROP; } -static inline struct arpt_entry *get_entry(void *base, unsigned int offset) +static inline const struct arpt_entry_target * +arpt_get_target_c(const struct arpt_entry *e) +{ + return arpt_get_target((struct arpt_entry *)e); +} + +static inline struct arpt_entry * +get_entry(const void *base, unsigned int offset) { return (struct arpt_entry *)(base + offset); } @@ -280,7 +287,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, arp = arp_hdr(skb); do { - struct arpt_entry_target *t; + const struct arpt_entry_target *t; int hdr_len; if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { @@ -292,7 +299,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, (2 * skb->dev->addr_len); ADD_COUNTER(e->counters, hdr_len, 1); - t = arpt_get_target(e); + t = arpt_get_target_c(e); /* Standard target? */ if (!t->u.kernel.target->target) { @@ -358,7 +365,7 @@ static inline bool unconditional(const struct arpt_arp *arp) /* Figures out from what hook each rule can be called: returns 0 if * there are loops. Puts hook bitmask in comefrom. */ -static int mark_source_chains(struct xt_table_info *newinfo, +static int mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { unsigned int hook; @@ -379,7 +386,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, for (;;) { const struct arpt_standard_target *t - = (void *)arpt_get_target(e); + = (void *)arpt_get_target_c(e); int visited = e->comefrom & (1 << hook); if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) { @@ -463,7 +470,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, return 1; } -static inline int check_entry(struct arpt_entry *e, const char *name) +static inline int check_entry(const struct arpt_entry *e, const char *name) { const struct arpt_entry_target *t; @@ -475,7 +482,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name) if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset) return -EINVAL; - t = arpt_get_target(e); + t = arpt_get_target_c(e); if (e->target_offset + t->u.target_size > e->next_offset) return -EINVAL; @@ -540,14 +547,14 @@ out: return ret; } -static bool check_underflow(struct arpt_entry *e) +static bool check_underflow(const struct arpt_entry *e) { const struct arpt_entry_target *t; unsigned int verdict; if (!unconditional(&e->arp)) return false; - t = arpt_get_target(e); + t = arpt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) return false; verdict = ((struct arpt_standard_target *)t)->verdict; @@ -557,8 +564,8 @@ static bool check_underflow(struct arpt_entry *e) static inline int check_entry_size_and_hooks(struct arpt_entry *e, struct xt_table_info *newinfo, - unsigned char *base, - unsigned char *limit, + const unsigned char *base, + const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, unsigned int valid_hooks, @@ -768,11 +775,11 @@ static void get_counters(const struct xt_table_info *t, local_bh_enable(); } -static struct xt_counters *alloc_counters(struct xt_table *table) +static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change * (other than comefrom, which userspace doesn't care @@ -790,11 +797,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) } static int copy_entries_to_user(unsigned int total_size, - struct xt_table *table, + const struct xt_table *table, void __user *userptr) { unsigned int off, num; - struct arpt_entry *e; + const struct arpt_entry *e; struct xt_counters *counters; struct xt_table_info *private = table->private; int ret = 0; @@ -814,7 +821,7 @@ static int copy_entries_to_user(unsigned int total_size, /* FIXME: use iterator macros --RR */ /* ... then go back and fix counters and names */ for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ - struct arpt_entry_target *t; + const struct arpt_entry_target *t; e = (struct arpt_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off @@ -825,7 +832,7 @@ static int copy_entries_to_user(unsigned int total_size, goto free_counters; } - t = arpt_get_target(e); + t = arpt_get_target_c(e); if (copy_to_user(userptr + off + e->target_offset + offsetof(struct arpt_entry_target, u.user.name), @@ -860,18 +867,18 @@ static int compat_standard_to_user(void __user *dst, const void *src) return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; } -static int compat_calc_entry(struct arpt_entry *e, +static int compat_calc_entry(const struct arpt_entry *e, const struct xt_table_info *info, - void *base, struct xt_table_info *newinfo) + const void *base, struct xt_table_info *newinfo) { - struct arpt_entry_target *t; + const struct arpt_entry_target *t; unsigned int entry_offset; int off, i, ret; off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); entry_offset = (void *)e - base; - t = arpt_get_target(e); + t = arpt_get_target_c(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off); @@ -907,7 +914,8 @@ static int compat_table_info(const struct xt_table_info *info, } #endif -static int get_info(struct net *net, void __user *user, int *len, int compat) +static int get_info(struct net *net, void __user *user, + const int *len, int compat) { char name[ARPT_TABLE_MAXNAMELEN]; struct xt_table *t; @@ -966,7 +974,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) } static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, - int *len) + const int *len) { int ret; struct arpt_get_entries get; @@ -1080,7 +1088,8 @@ static int __do_replace(struct net *net, const char *name, return ret; } -static int do_replace(struct net *net, void __user *user, unsigned int len) +static int do_replace(struct net *net, const void __user *user, + unsigned int len) { int ret; struct arpt_replace tmp; @@ -1140,8 +1149,8 @@ add_counter_to_entry(struct arpt_entry *e, return 0; } -static int do_add_counters(struct net *net, void __user *user, unsigned int len, - int compat) +static int do_add_counters(struct net *net, const void __user *user, + unsigned int len, int compat) { unsigned int i, curcpu; struct xt_counters_info tmp; @@ -1245,10 +1254,10 @@ static inline int check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, struct xt_table_info *newinfo, unsigned int *size, - unsigned char *base, - unsigned char *limit, - unsigned int *hook_entries, - unsigned int *underflows, + const unsigned char *base, + const unsigned char *limit, + const unsigned int *hook_entries, + const unsigned int *underflows, unsigned int *i, const char *name) { diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2a4f745ce36e..e94c18bdfc68 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -176,7 +176,7 @@ ipt_error(struct sk_buff *skb, const struct xt_target_param *par) /* Performance critical - called for every packet */ static inline bool -do_match(struct ipt_entry_match *m, const struct sk_buff *skb, +do_match(const struct ipt_entry_match *m, const struct sk_buff *skb, struct xt_match_param *par) { par->match = m->u.kernel.match; @@ -191,7 +191,7 @@ do_match(struct ipt_entry_match *m, const struct sk_buff *skb, /* Performance critical */ static inline struct ipt_entry * -get_entry(void *base, unsigned int offset) +get_entry(const void *base, unsigned int offset) { return (struct ipt_entry *)(base + offset); } @@ -206,6 +206,13 @@ static inline bool unconditional(const struct ipt_ip *ip) #undef FWINV } +/* for const-correctness */ +static inline const struct ipt_entry_target * +ipt_get_target_c(const struct ipt_entry *e) +{ + return ipt_get_target((struct ipt_entry *)e); +} + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) static const char *const hooknames[] = { @@ -240,11 +247,11 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int -get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, +get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e, const char *hookname, const char **chainname, const char **comment, unsigned int *rulenum) { - struct ipt_standard_target *t = (void *)ipt_get_target(s); + const struct ipt_standard_target *t = (void *)ipt_get_target_c(s); if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) { /* Head of user chain: ERROR target with chainname */ @@ -270,15 +277,15 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, return 0; } -static void trace_packet(struct sk_buff *skb, +static void trace_packet(const struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, const char *tablename, - struct xt_table_info *private, - struct ipt_entry *e) + const struct xt_table_info *private, + const struct ipt_entry *e) { - void *table_base; + const void *table_base; const struct ipt_entry *root; const char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -322,9 +329,9 @@ ipt_do_table(struct sk_buff *skb, /* Initializing verdict to NF_DROP keeps gcc happy. */ unsigned int verdict = NF_DROP; const char *indev, *outdev; - void *table_base; + const void *table_base; struct ipt_entry *e, *back; - struct xt_table_info *private; + const struct xt_table_info *private; struct xt_match_param mtpar; struct xt_target_param tgpar; @@ -357,7 +364,7 @@ ipt_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { - struct ipt_entry_target *t; + const struct ipt_entry_target *t; IP_NF_ASSERT(e); IP_NF_ASSERT(back); @@ -450,7 +457,7 @@ ipt_do_table(struct sk_buff *skb, /* Figures out from what hook each rule can be called: returns 0 if there are loops. Puts hook bitmask in comefrom. */ static int -mark_source_chains(struct xt_table_info *newinfo, +mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { unsigned int hook; @@ -468,8 +475,8 @@ mark_source_chains(struct xt_table_info *newinfo, e->counters.pcnt = pos; for (;;) { - struct ipt_standard_target *t - = (void *)ipt_get_target(e); + const struct ipt_standard_target *t + = (void *)ipt_get_target_c(e); int visited = e->comefrom & (1 << hook); if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { @@ -578,9 +585,9 @@ cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) } static int -check_entry(struct ipt_entry *e, const char *name) +check_entry(const struct ipt_entry *e, const char *name) { - struct ipt_entry_target *t; + const struct ipt_entry_target *t; if (!ip_checkentry(&e->ip)) { duprintf("ip_tables: ip check failed %p %s.\n", e, name); @@ -591,7 +598,7 @@ check_entry(struct ipt_entry *e, const char *name) e->next_offset) return -EINVAL; - t = ipt_get_target(e); + t = ipt_get_target_c(e); if (e->target_offset + t->u.target_size > e->next_offset) return -EINVAL; @@ -718,14 +725,14 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, return ret; } -static bool check_underflow(struct ipt_entry *e) +static bool check_underflow(const struct ipt_entry *e) { const struct ipt_entry_target *t; unsigned int verdict; if (!unconditional(&e->ip)) return false; - t = ipt_get_target(e); + t = ipt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) return false; verdict = ((struct ipt_standard_target *)t)->verdict; @@ -736,8 +743,8 @@ static bool check_underflow(struct ipt_entry *e) static int check_entry_size_and_hooks(struct ipt_entry *e, struct xt_table_info *newinfo, - unsigned char *base, - unsigned char *limit, + const unsigned char *base, + const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, unsigned int valid_hooks, @@ -952,11 +959,11 @@ get_counters(const struct xt_table_info *t, local_bh_enable(); } -static struct xt_counters * alloc_counters(struct xt_table *table) +static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -974,11 +981,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table) static int copy_entries_to_user(unsigned int total_size, - struct xt_table *table, + const struct xt_table *table, void __user *userptr) { unsigned int off, num; - struct ipt_entry *e; + const struct ipt_entry *e; struct xt_counters *counters; const struct xt_table_info *private = table->private; int ret = 0; @@ -1030,7 +1037,7 @@ copy_entries_to_user(unsigned int total_size, } } - t = ipt_get_target(e); + t = ipt_get_target_c(e); if (copy_to_user(userptr + off + e->target_offset + offsetof(struct ipt_entry_target, u.user.name), @@ -1066,24 +1073,24 @@ static int compat_standard_to_user(void __user *dst, const void *src) } static inline int -compat_calc_match(struct ipt_entry_match *m, int *size) +compat_calc_match(const struct ipt_entry_match *m, int *size) { *size += xt_compat_match_offset(m->u.kernel.match); return 0; } -static int compat_calc_entry(struct ipt_entry *e, +static int compat_calc_entry(const struct ipt_entry *e, const struct xt_table_info *info, - void *base, struct xt_table_info *newinfo) + const void *base, struct xt_table_info *newinfo) { - struct ipt_entry_target *t; + const struct ipt_entry_target *t; unsigned int entry_offset; int off, i, ret; off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); entry_offset = (void *)e - base; IPT_MATCH_ITERATE(e, compat_calc_match, &off); - t = ipt_get_target(e); + t = ipt_get_target_c(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(AF_INET, entry_offset, off); @@ -1119,7 +1126,8 @@ static int compat_table_info(const struct xt_table_info *info, } #endif -static int get_info(struct net *net, void __user *user, int *len, int compat) +static int get_info(struct net *net, void __user *user, + const int *len, int compat) { char name[IPT_TABLE_MAXNAMELEN]; struct xt_table *t; @@ -1179,7 +1187,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) } static int -get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len) +get_entries(struct net *net, struct ipt_get_entries __user *uptr, + const int *len) { int ret; struct ipt_get_entries get; @@ -1289,7 +1298,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, } static int -do_replace(struct net *net, void __user *user, unsigned int len) +do_replace(struct net *net, const void __user *user, unsigned int len) { int ret; struct ipt_replace tmp; @@ -1350,7 +1359,8 @@ add_counter_to_entry(struct ipt_entry *e, } static int -do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) +do_add_counters(struct net *net, const void __user *user, + unsigned int len, int compat) { unsigned int i, curcpu; struct xt_counters_info tmp; @@ -1546,10 +1556,10 @@ static int check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, struct xt_table_info *newinfo, unsigned int *size, - unsigned char *base, - unsigned char *limit, - unsigned int *hook_entries, - unsigned int *underflows, + const unsigned char *base, + const unsigned char *limit, + const unsigned int *hook_entries, + const unsigned int *underflows, unsigned int *i, const char *name) { diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3ff4fd50e96e..4185099c2943 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -208,7 +208,7 @@ ip6t_error(struct sk_buff *skb, const struct xt_target_param *par) /* Performance critical - called for every packet */ static inline bool -do_match(struct ip6t_entry_match *m, const struct sk_buff *skb, +do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb, struct xt_match_param *par) { par->match = m->u.kernel.match; @@ -222,7 +222,7 @@ do_match(struct ip6t_entry_match *m, const struct sk_buff *skb, } static inline struct ip6t_entry * -get_entry(void *base, unsigned int offset) +get_entry(const void *base, unsigned int offset) { return (struct ip6t_entry *)(base + offset); } @@ -236,6 +236,12 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6) return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; } +static inline const struct ip6t_entry_target * +ip6t_get_target_c(const struct ip6t_entry *e) +{ + return ip6t_get_target((struct ip6t_entry *)e); +} + #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) /* This cries for unification! */ @@ -271,11 +277,11 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int -get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, +get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, const char *hookname, const char **chainname, const char **comment, unsigned int *rulenum) { - struct ip6t_standard_target *t = (void *)ip6t_get_target(s); + const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s); if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { /* Head of user chain: ERROR target with chainname */ @@ -301,15 +307,15 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, return 0; } -static void trace_packet(struct sk_buff *skb, +static void trace_packet(const struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, const char *tablename, - struct xt_table_info *private, - struct ip6t_entry *e) + const struct xt_table_info *private, + const struct ip6t_entry *e) { - void *table_base; + const void *table_base; const struct ip6t_entry *root; const char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -352,9 +358,9 @@ ip6t_do_table(struct sk_buff *skb, /* Initializing verdict to NF_DROP keeps gcc happy. */ unsigned int verdict = NF_DROP; const char *indev, *outdev; - void *table_base; + const void *table_base; struct ip6t_entry *e, *back; - struct xt_table_info *private; + const struct xt_table_info *private; struct xt_match_param mtpar; struct xt_target_param tgpar; @@ -385,7 +391,7 @@ ip6t_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { - struct ip6t_entry_target *t; + const struct ip6t_entry_target *t; IP_NF_ASSERT(e); IP_NF_ASSERT(back); @@ -400,7 +406,7 @@ ip6t_do_table(struct sk_buff *skb, ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr), 1); - t = ip6t_get_target(e); + t = ip6t_get_target_c(e); IP_NF_ASSERT(t->u.kernel.target); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ @@ -482,7 +488,7 @@ ip6t_do_table(struct sk_buff *skb, /* Figures out from what hook each rule can be called: returns 0 if there are loops. Puts hook bitmask in comefrom. */ static int -mark_source_chains(struct xt_table_info *newinfo, +mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { unsigned int hook; @@ -500,8 +506,8 @@ mark_source_chains(struct xt_table_info *newinfo, e->counters.pcnt = pos; for (;;) { - struct ip6t_standard_target *t - = (void *)ip6t_get_target(e); + const struct ip6t_standard_target *t + = (void *)ip6t_get_target_c(e); int visited = e->comefrom & (1 << hook); if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { @@ -610,9 +616,9 @@ cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) } static int -check_entry(struct ip6t_entry *e, const char *name) +check_entry(const struct ip6t_entry *e, const char *name) { - struct ip6t_entry_target *t; + const struct ip6t_entry_target *t; if (!ip6_checkentry(&e->ipv6)) { duprintf("ip_tables: ip check failed %p %s.\n", e, name); @@ -623,7 +629,7 @@ check_entry(struct ip6t_entry *e, const char *name) e->next_offset) return -EINVAL; - t = ip6t_get_target(e); + t = ip6t_get_target_c(e); if (e->target_offset + t->u.target_size > e->next_offset) return -EINVAL; @@ -750,14 +756,14 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, return ret; } -static bool check_underflow(struct ip6t_entry *e) +static bool check_underflow(const struct ip6t_entry *e) { const struct ip6t_entry_target *t; unsigned int verdict; if (!unconditional(&e->ipv6)) return false; - t = ip6t_get_target(e); + t = ip6t_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) return false; verdict = ((struct ip6t_standard_target *)t)->verdict; @@ -768,8 +774,8 @@ static bool check_underflow(struct ip6t_entry *e) static int check_entry_size_and_hooks(struct ip6t_entry *e, struct xt_table_info *newinfo, - unsigned char *base, - unsigned char *limit, + const unsigned char *base, + const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, unsigned int valid_hooks, @@ -984,11 +990,11 @@ get_counters(const struct xt_table_info *t, local_bh_enable(); } -static struct xt_counters *alloc_counters(struct xt_table *table) +static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -1006,11 +1012,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) static int copy_entries_to_user(unsigned int total_size, - struct xt_table *table, + const struct xt_table *table, void __user *userptr) { unsigned int off, num; - struct ip6t_entry *e; + const struct ip6t_entry *e; struct xt_counters *counters; const struct xt_table_info *private = table->private; int ret = 0; @@ -1062,7 +1068,7 @@ copy_entries_to_user(unsigned int total_size, } } - t = ip6t_get_target(e); + t = ip6t_get_target_c(e); if (copy_to_user(userptr + off + e->target_offset + offsetof(struct ip6t_entry_target, u.user.name), @@ -1098,24 +1104,24 @@ static int compat_standard_to_user(void __user *dst, const void *src) } static inline int -compat_calc_match(struct ip6t_entry_match *m, int *size) +compat_calc_match(const struct ip6t_entry_match *m, int *size) { *size += xt_compat_match_offset(m->u.kernel.match); return 0; } -static int compat_calc_entry(struct ip6t_entry *e, +static int compat_calc_entry(const struct ip6t_entry *e, const struct xt_table_info *info, - void *base, struct xt_table_info *newinfo) + const void *base, struct xt_table_info *newinfo) { - struct ip6t_entry_target *t; + const struct ip6t_entry_target *t; unsigned int entry_offset; int off, i, ret; off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); entry_offset = (void *)e - base; IP6T_MATCH_ITERATE(e, compat_calc_match, &off); - t = ip6t_get_target(e); + t = ip6t_get_target_c(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(AF_INET6, entry_offset, off); @@ -1151,7 +1157,8 @@ static int compat_table_info(const struct xt_table_info *info, } #endif -static int get_info(struct net *net, void __user *user, int *len, int compat) +static int get_info(struct net *net, void __user *user, + const int *len, int compat) { char name[IP6T_TABLE_MAXNAMELEN]; struct xt_table *t; @@ -1211,7 +1218,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) } static int -get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len) +get_entries(struct net *net, struct ip6t_get_entries __user *uptr, + const int *len) { int ret; struct ip6t_get_entries get; @@ -1322,7 +1330,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, } static int -do_replace(struct net *net, void __user *user, unsigned int len) +do_replace(struct net *net, const void __user *user, unsigned int len) { int ret; struct ip6t_replace tmp; @@ -1383,7 +1391,7 @@ add_counter_to_entry(struct ip6t_entry *e, } static int -do_add_counters(struct net *net, void __user *user, unsigned int len, +do_add_counters(struct net *net, const void __user *user, unsigned int len, int compat) { unsigned int i, curcpu; @@ -1582,10 +1590,10 @@ static int check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, struct xt_table_info *newinfo, unsigned int *size, - unsigned char *base, - unsigned char *limit, - unsigned int *hook_entries, - unsigned int *underflows, + const unsigned char *base, + const unsigned char *limit, + const unsigned int *hook_entries, + const unsigned int *underflows, unsigned int *i, const char *name) { -- GitLab From 8fea97ec1772bbf553d89187340ef624d548e115 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 15 Feb 2010 17:45:08 +0100 Subject: [PATCH 2069/3892] netfilter: nf_conntrack: pass template to l4proto ->error() handler The error handlers might need the template to get the conntrack zone introduced in the next patches to perform a conntrack lookup. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_l4proto.h | 4 ++-- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 3 ++- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 3 ++- net/netfilter/nf_conntrack_core.c | 3 ++- net/netfilter/nf_conntrack_proto_dccp.c | 5 +++-- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_proto_udp.c | 4 ++-- net/netfilter/nf_conntrack_proto_udplite.c | 2 +- 8 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index ca6dcf3445ab..e3d3ee3c06a2 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -49,8 +49,8 @@ struct nf_conntrack_l4proto { /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); - int (*error)(struct net *net, struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info *ctinfo, + int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum); /* Print out the per-protocol part of the tuple. Return like seq_* */ diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 7afd39b5b781..327826a968a8 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -163,7 +163,8 @@ icmp_error_message(struct net *net, struct sk_buff *skb, /* Small and modified version of icmp_rcv */ static int -icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, +icmp_error(struct net *net, struct nf_conn *tmpl, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) { const struct icmphdr *icmph; diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index c7b8bd1d7984..d772dc21857f 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -179,7 +179,8 @@ icmpv6_error_message(struct net *net, } static int -icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, +icmpv6_error(struct net *net, struct nf_conn *tmpl, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) { const struct icmp6hdr *icmp6h; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index bd831410a396..65351ed5d815 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -799,7 +799,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, * inverse of the return code tells to the netfilter * core what to do with the packet. */ if (l4proto->error != NULL) { - ret = l4proto->error(net, skb, dataoff, &ctinfo, pf, hooknum); + ret = l4proto->error(net, tmpl, skb, dataoff, &ctinfo, + pf, hooknum); if (ret <= 0) { NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(net, invalid); diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index dd375500dccc..9a2815549375 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -561,8 +561,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, return NF_ACCEPT; } -static int dccp_error(struct net *net, struct sk_buff *skb, - unsigned int dataoff, enum ip_conntrack_info *ctinfo, +static int dccp_error(struct net *net, struct nf_conn *tmpl, + struct sk_buff *skb, unsigned int dataoff, + enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) { struct dccp_hdr _dh, *dh; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index ad118053971a..9dd8cd4fb6e6 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -760,7 +760,7 @@ static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] = }; /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ -static int tcp_error(struct net *net, +static int tcp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 8d38f9a4bed8..8289088b8218 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -91,8 +91,8 @@ static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, return true; } -static int udp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info *ctinfo, +static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) { diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 0b1bc9ba6678..263b5a72588d 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -89,7 +89,7 @@ static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, return true; } -static int udplite_error(struct net *net, +static int udplite_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, -- GitLab From 4f2c49fedf833e522001bc51824b894732900a3d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 08:48:53 -0800 Subject: [PATCH 2070/3892] omap: Clean the serial port defines This way we don't have conflicts with the defines with compiling in multiple omaps. Set the addresses for uarts in struct omap_globals for the early serial init code. Signed-off-by: Tony Lindgren --- .../arm/mach-omap1/include/mach/debug-macro.S | 16 ++-- arch/arm/mach-omap1/serial.c | 6 +- arch/arm/mach-omap2/board-3630sdp.c | 2 +- arch/arm/mach-omap2/board-zoom3.c | 2 +- .../arm/mach-omap2/include/mach/debug-macro.S | 15 ++-- arch/arm/mach-omap2/serial.c | 15 +++- arch/arm/plat-omap/common.c | 29 +++++++- arch/arm/plat-omap/include/plat/common.h | 6 ++ arch/arm/plat-omap/include/plat/omap16xx.h | 74 +++++++++---------- arch/arm/plat-omap/include/plat/serial.h | 45 +++++------ arch/arm/plat-omap/include/plat/uncompress.h | 7 +- 11 files changed, 130 insertions(+), 87 deletions(-) diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S index 8c74cab2fa8b..9ea12f29e0b6 100644 --- a/arch/arm/mach-omap1/include/mach/debug-macro.S +++ b/arch/arm/mach-omap1/include/mach/debug-macro.S @@ -11,6 +11,10 @@ * */ +#include + +#include + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? @@ -30,13 +34,13 @@ .endm .macro busyuart,rd,rx -1001: ldrb \rd, [\rx, #(0x5 << 2)] @ OMAP-1510 and friends - and \rd, \rd, #0x60 - teq \rd, #0x60 +1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)] + and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) + teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) beq 1002f - ldrb \rd, [\rx, #(0x5 << 0)] @ OMAP-730 only - and \rd, \rd, #0x60 - teq \rd, #0x60 + ldrb \rd, [\rx, #(UART_LSR << OMAP7XX_PORT_SHIFT)] + and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) + teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) bne 1001b 1002: .endm diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 6e5207c81cf4..349de90194e3 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -64,7 +64,7 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p) static struct plat_serial8250_port serial_platform_data[] = { { - .mapbase = OMAP_UART1_BASE, + .mapbase = OMAP1_UART1_BASE, .irq = INT_UART1, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -72,7 +72,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .uartclk = OMAP16XX_BASE_BAUD * 16, }, { - .mapbase = OMAP_UART2_BASE, + .mapbase = OMAP1_UART2_BASE, .irq = INT_UART2, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -80,7 +80,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .uartclk = OMAP16XX_BASE_BAUD * 16, }, { - .mapbase = OMAP_UART3_BASE, + .mapbase = OMAP1_UART3_BASE, .irq = INT_UART3, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index 739059632811..c178e68472f8 100755 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -68,7 +68,7 @@ static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = { static void __init omap_sdp_map_io(void) { - omap2_set_globals_343x(); + omap2_set_globals_36xx(); omap2_map_common_io(); } diff --git a/arch/arm/mach-omap2/board-zoom3.c b/arch/arm/mach-omap2/board-zoom3.c index a9fe9181b010..456b69072679 100644 --- a/arch/arm/mach-omap2/board-zoom3.c +++ b/arch/arm/mach-omap2/board-zoom3.c @@ -26,7 +26,7 @@ static void __init omap_zoom_map_io(void) { - omap2_set_globals_343x(); + omap2_set_globals_36xx(); omap2_map_common_io(); } diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S index 86979d7bd871..8d6da9a39d63 100644 --- a/arch/arm/mach-omap2/include/mach/debug-macro.S +++ b/arch/arm/mach-omap2/include/mach/debug-macro.S @@ -11,6 +11,10 @@ * */ +#include + +#include + .macro addruart, rx, tmp mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? @@ -44,15 +48,10 @@ .endm .macro busyuart,rd,rx -1001: ldrb \rd, [\rx, #(0x5 << 2)] @ OMAP-1510 and friends - and \rd, \rd, #0x60 - teq \rd, #0x60 - beq 1002f - ldrb \rd, [\rx, #(0x5 << 0)] @ OMAP-730 only - and \rd, \rd, #0x60 - teq \rd, #0x60 +1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)] + and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) + teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) bne 1001b -1002: .endm .macro waituart,rd,rx diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 8c964bec8159..eb56e193998d 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -74,7 +74,6 @@ static LIST_HEAD(uart_list); static struct plat_serial8250_port serial_platform_data0[] = { { - .mapbase = OMAP_UART1_BASE, .irq = 72, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -87,7 +86,6 @@ static struct plat_serial8250_port serial_platform_data0[] = { static struct plat_serial8250_port serial_platform_data1[] = { { - .mapbase = OMAP_UART2_BASE, .irq = 73, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -100,7 +98,6 @@ static struct plat_serial8250_port serial_platform_data1[] = { static struct plat_serial8250_port serial_platform_data2[] = { { - .mapbase = OMAP_UART3_BASE, .irq = 74, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -114,7 +111,6 @@ static struct plat_serial8250_port serial_platform_data2[] = { #ifdef CONFIG_ARCH_OMAP4 static struct plat_serial8250_port serial_platform_data3[] = { { - .mapbase = OMAP_UART4_BASE, .irq = 70, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, @@ -125,6 +121,17 @@ static struct plat_serial8250_port serial_platform_data3[] = { } }; #endif + +void __init omap2_set_globals_uart(struct omap_globals *omap2_globals) +{ + serial_platform_data0[0].mapbase = omap2_globals->uart1_phys; + serial_platform_data1[0].mapbase = omap2_globals->uart2_phys; + serial_platform_data2[0].mapbase = omap2_globals->uart3_phys; +#ifdef CONFIG_ARCH_OMAP4 + serial_platform_data3[0].mapbase = omap2_globals->uart4_phys; +#endif +} + static inline unsigned int __serial_read_reg(struct uart_port *up, int offset) { diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index bf1eaf3a27d4..dddce037ab12 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -219,6 +220,7 @@ static void __init __omap2_set_globals(struct omap_globals *omap2_globals) omap2_set_globals_sdrc(omap2_globals); omap2_set_globals_control(omap2_globals); omap2_set_globals_prcm(omap2_globals); + omap2_set_globals_uart(omap2_globals); } #endif @@ -233,6 +235,9 @@ static struct omap_globals omap242x_globals = { .ctrl = OMAP2_L4_IO_ADDRESS(OMAP2420_CTRL_BASE), .prm = OMAP2_L4_IO_ADDRESS(OMAP2420_PRM_BASE), .cm = OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE), + .uart1_phys = OMAP2_UART1_BASE, + .uart2_phys = OMAP2_UART2_BASE, + .uart3_phys = OMAP2_UART3_BASE, }; void __init omap2_set_globals_242x(void) @@ -251,6 +256,9 @@ static struct omap_globals omap243x_globals = { .ctrl = OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE), .prm = OMAP2_L4_IO_ADDRESS(OMAP2430_PRM_BASE), .cm = OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE), + .uart1_phys = OMAP2_UART1_BASE, + .uart2_phys = OMAP2_UART2_BASE, + .uart3_phys = OMAP2_UART3_BASE, }; void __init omap2_set_globals_243x(void) @@ -259,9 +267,9 @@ void __init omap2_set_globals_243x(void) } #endif -#if defined(CONFIG_ARCH_OMAP3430) +#if defined(CONFIG_ARCH_OMAP3) -static struct omap_globals omap343x_globals = { +static struct omap_globals omap3_globals = { .class = OMAP343X_CLASS, .tap = OMAP2_L4_IO_ADDRESS(0x4830A000), .sdrc = OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE), @@ -269,11 +277,21 @@ static struct omap_globals omap343x_globals = { .ctrl = OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE), .prm = OMAP2_L4_IO_ADDRESS(OMAP3430_PRM_BASE), .cm = OMAP2_L4_IO_ADDRESS(OMAP3430_CM_BASE), + .uart1_phys = OMAP3_UART1_BASE, + .uart2_phys = OMAP3_UART2_BASE, + .uart3_phys = OMAP3_UART3_BASE, }; void __init omap2_set_globals_343x(void) { - __omap2_set_globals(&omap343x_globals); + __omap2_set_globals(&omap3_globals); +} + +void __init omap2_set_globals_36xx(void) +{ + omap3_globals.uart4_phys = OMAP3_UART4_BASE; + + __omap2_set_globals(&omap3_globals); } #endif @@ -285,6 +303,10 @@ static struct omap_globals omap4_globals = { .prm = OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE), .cm = OMAP2_L4_IO_ADDRESS(OMAP4430_CM_BASE), .cm2 = OMAP2_L4_IO_ADDRESS(OMAP4430_CM2_BASE), + .uart1_phys = OMAP4_UART1_BASE, + .uart2_phys = OMAP4_UART2_BASE, + .uart3_phys = OMAP4_UART3_BASE, + .uart4_phys = OMAP4_UART4_BASE, }; void __init omap2_set_globals_443x(void) @@ -292,6 +314,7 @@ void __init omap2_set_globals_443x(void) omap2_set_globals_tap(&omap4_globals); omap2_set_globals_control(&omap4_globals); omap2_set_globals_prcm(&omap4_globals); + omap2_set_globals_uart(&omap4_globals); } #endif diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h index 32c22272425d..e04a58ec53a2 100644 --- a/arch/arm/plat-omap/include/plat/common.h +++ b/arch/arm/plat-omap/include/plat/common.h @@ -47,11 +47,16 @@ struct omap_globals { void __iomem *prm; /* Power and Reset Management */ void __iomem *cm; /* Clock Management */ void __iomem *cm2; + unsigned long uart1_phys; + unsigned long uart2_phys; + unsigned long uart3_phys; + unsigned long uart4_phys; }; void omap2_set_globals_242x(void); void omap2_set_globals_243x(void); void omap2_set_globals_343x(void); +void omap2_set_globals_36xx(void); void omap2_set_globals_443x(void); /* These get called from omap2_set_globals_xxxx(), do not call these */ @@ -59,6 +64,7 @@ void omap2_set_globals_tap(struct omap_globals *); void omap2_set_globals_sdrc(struct omap_globals *); void omap2_set_globals_control(struct omap_globals *); void omap2_set_globals_prcm(struct omap_globals *); +void omap2_set_globals_uart(struct omap_globals *); /** * omap_test_timeout - busy-loop, testing a condition diff --git a/arch/arm/plat-omap/include/plat/omap16xx.h b/arch/arm/plat-omap/include/plat/omap16xx.h index 7560b4d583a3..e69e1d857b45 100644 --- a/arch/arm/plat-omap/include/plat/omap16xx.h +++ b/arch/arm/plat-omap/include/plat/omap16xx.h @@ -125,43 +125,43 @@ #define OMAP16XX_MMCSD2_SSW_MPU_CONF (TIPB_SWITCH_BASE + 0x160) /* UART3 Registers Mapping through MPU bus */ -#define UART3_RHR (OMAP_UART3_BASE + 0) -#define UART3_THR (OMAP_UART3_BASE + 0) -#define UART3_DLL (OMAP_UART3_BASE + 0) -#define UART3_IER (OMAP_UART3_BASE + 4) -#define UART3_DLH (OMAP_UART3_BASE + 4) -#define UART3_IIR (OMAP_UART3_BASE + 8) -#define UART3_FCR (OMAP_UART3_BASE + 8) -#define UART3_EFR (OMAP_UART3_BASE + 8) -#define UART3_LCR (OMAP_UART3_BASE + 0x0C) -#define UART3_MCR (OMAP_UART3_BASE + 0x10) -#define UART3_XON1_ADDR1 (OMAP_UART3_BASE + 0x10) -#define UART3_XON2_ADDR2 (OMAP_UART3_BASE + 0x14) -#define UART3_LSR (OMAP_UART3_BASE + 0x14) -#define UART3_TCR (OMAP_UART3_BASE + 0x18) -#define UART3_MSR (OMAP_UART3_BASE + 0x18) -#define UART3_XOFF1 (OMAP_UART3_BASE + 0x18) -#define UART3_XOFF2 (OMAP_UART3_BASE + 0x1C) -#define UART3_SPR (OMAP_UART3_BASE + 0x1C) -#define UART3_TLR (OMAP_UART3_BASE + 0x1C) -#define UART3_MDR1 (OMAP_UART3_BASE + 0x20) -#define UART3_MDR2 (OMAP_UART3_BASE + 0x24) -#define UART3_SFLSR (OMAP_UART3_BASE + 0x28) -#define UART3_TXFLL (OMAP_UART3_BASE + 0x28) -#define UART3_RESUME (OMAP_UART3_BASE + 0x2C) -#define UART3_TXFLH (OMAP_UART3_BASE + 0x2C) -#define UART3_SFREGL (OMAP_UART3_BASE + 0x30) -#define UART3_RXFLL (OMAP_UART3_BASE + 0x30) -#define UART3_SFREGH (OMAP_UART3_BASE + 0x34) -#define UART3_RXFLH (OMAP_UART3_BASE + 0x34) -#define UART3_BLR (OMAP_UART3_BASE + 0x38) -#define UART3_ACREG (OMAP_UART3_BASE + 0x3C) -#define UART3_DIV16 (OMAP_UART3_BASE + 0x3C) -#define UART3_SCR (OMAP_UART3_BASE + 0x40) -#define UART3_SSR (OMAP_UART3_BASE + 0x44) -#define UART3_EBLR (OMAP_UART3_BASE + 0x48) -#define UART3_OSC_12M_SEL (OMAP_UART3_BASE + 0x4C) -#define UART3_MVR (OMAP_UART3_BASE + 0x50) +#define UART3_RHR (OMAP1_UART3_BASE + 0) +#define UART3_THR (OMAP1_UART3_BASE + 0) +#define UART3_DLL (OMAP1_UART3_BASE + 0) +#define UART3_IER (OMAP1_UART3_BASE + 4) +#define UART3_DLH (OMAP1_UART3_BASE + 4) +#define UART3_IIR (OMAP1_UART3_BASE + 8) +#define UART3_FCR (OMAP1_UART3_BASE + 8) +#define UART3_EFR (OMAP1_UART3_BASE + 8) +#define UART3_LCR (OMAP1_UART3_BASE + 0x0C) +#define UART3_MCR (OMAP1_UART3_BASE + 0x10) +#define UART3_XON1_ADDR1 (OMAP1_UART3_BASE + 0x10) +#define UART3_XON2_ADDR2 (OMAP1_UART3_BASE + 0x14) +#define UART3_LSR (OMAP1_UART3_BASE + 0x14) +#define UART3_TCR (OMAP1_UART3_BASE + 0x18) +#define UART3_MSR (OMAP1_UART3_BASE + 0x18) +#define UART3_XOFF1 (OMAP1_UART3_BASE + 0x18) +#define UART3_XOFF2 (OMAP1_UART3_BASE + 0x1C) +#define UART3_SPR (OMAP1_UART3_BASE + 0x1C) +#define UART3_TLR (OMAP1_UART3_BASE + 0x1C) +#define UART3_MDR1 (OMAP1_UART3_BASE + 0x20) +#define UART3_MDR2 (OMAP1_UART3_BASE + 0x24) +#define UART3_SFLSR (OMAP1_UART3_BASE + 0x28) +#define UART3_TXFLL (OMAP1_UART3_BASE + 0x28) +#define UART3_RESUME (OMAP1_UART3_BASE + 0x2C) +#define UART3_TXFLH (OMAP1_UART3_BASE + 0x2C) +#define UART3_SFREGL (OMAP1_UART3_BASE + 0x30) +#define UART3_RXFLL (OMAP1_UART3_BASE + 0x30) +#define UART3_SFREGH (OMAP1_UART3_BASE + 0x34) +#define UART3_RXFLH (OMAP1_UART3_BASE + 0x34) +#define UART3_BLR (OMAP1_UART3_BASE + 0x38) +#define UART3_ACREG (OMAP1_UART3_BASE + 0x3C) +#define UART3_DIV16 (OMAP1_UART3_BASE + 0x3C) +#define UART3_SCR (OMAP1_UART3_BASE + 0x40) +#define UART3_SSR (OMAP1_UART3_BASE + 0x44) +#define UART3_EBLR (OMAP1_UART3_BASE + 0x48) +#define UART3_OSC_12M_SEL (OMAP1_UART3_BASE + 0x4C) +#define UART3_MVR (OMAP1_UART3_BASE + 0x50) /* * --------------------------------------------------------------------------- diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h index f5a4a92393ef..7f5a7a88a6eb 100644 --- a/arch/arm/plat-omap/include/plat/serial.h +++ b/arch/arm/plat-omap/include/plat/serial.h @@ -15,37 +15,40 @@ #include -#if defined(CONFIG_ARCH_OMAP1) /* OMAP1 serial ports */ -#define OMAP_UART1_BASE 0xfffb0000 -#define OMAP_UART2_BASE 0xfffb0800 -#define OMAP_UART3_BASE 0xfffb9800 -#elif defined(CONFIG_ARCH_OMAP2) +#define OMAP1_UART1_BASE 0xfffb0000 +#define OMAP1_UART2_BASE 0xfffb0800 +#define OMAP1_UART3_BASE 0xfffb9800 + /* OMAP2 serial ports */ -#define OMAP_UART1_BASE 0x4806a000 -#define OMAP_UART2_BASE 0x4806c000 -#define OMAP_UART3_BASE 0x4806e000 -#elif defined(CONFIG_ARCH_OMAP3) +#define OMAP2_UART1_BASE 0x4806a000 +#define OMAP2_UART2_BASE 0x4806c000 +#define OMAP2_UART3_BASE 0x4806e000 + /* OMAP3 serial ports */ -#define OMAP_UART1_BASE 0x4806a000 -#define OMAP_UART2_BASE 0x4806c000 -#define OMAP_UART3_BASE 0x49020000 -#elif defined(CONFIG_ARCH_OMAP4) +#define OMAP3_UART1_BASE 0x4806a000 +#define OMAP3_UART2_BASE 0x4806c000 +#define OMAP3_UART3_BASE 0x49020000 +#define OMAP3_UART4_BASE 0x49042000 /* Only on 36xx */ + /* OMAP4 serial ports */ -#define OMAP_UART1_BASE 0x4806a000 -#define OMAP_UART2_BASE 0x4806c000 -#define OMAP_UART3_BASE 0x48020000 -#define OMAP_UART4_BASE 0x4806e000 -#endif +#define OMAP4_UART1_BASE 0x4806a000 +#define OMAP4_UART2_BASE 0x4806c000 +#define OMAP4_UART3_BASE 0x48020000 +#define OMAP4_UART4_BASE 0x4806e000 + +#define OMAP_PORT_SHIFT 2 +#define OMAP7XX_PORT_SHIFT 0 #define OMAP1510_BASE_BAUD (12000000/16) #define OMAP16XX_BASE_BAUD (48000000/16) #define OMAP24XX_BASE_BAUD (48000000/16) +/* This is only used by 8250.c for omap1510 */ #define is_omap_port(pt) ({int __ret = 0; \ - if ((pt)->port.mapbase == OMAP_UART1_BASE || \ - (pt)->port.mapbase == OMAP_UART2_BASE || \ - (pt)->port.mapbase == OMAP_UART3_BASE) \ + if ((pt)->port.mapbase == OMAP1_UART1_BASE || \ + (pt)->port.mapbase == OMAP1_UART2_BASE || \ + (pt)->port.mapbase == OMAP1_UART3_BASE) \ __ret = 1; \ __ret; \ }) diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h index 13c305d62127..e5723c3e3418 100644 --- a/arch/arm/plat-omap/include/plat/uncompress.h +++ b/arch/arm/plat-omap/include/plat/uncompress.h @@ -40,12 +40,13 @@ static void putc(int c) #endif #ifdef CONFIG_ARCH_OMAP + /* Will get removed in the next patch, set to OMAP3 to compile */ #ifdef CONFIG_OMAP_LL_DEBUG_UART3 - uart = (volatile u8 *)(OMAP_UART3_BASE); + uart = (volatile u8 *)(OMAP3_UART3_BASE); #elif defined(CONFIG_OMAP_LL_DEBUG_UART2) - uart = (volatile u8 *)(OMAP_UART2_BASE); + uart = (volatile u8 *)(OMAP3_UART2_BASE); #elif defined(CONFIG_OMAP_LL_DEBUG_UART1) - uart = (volatile u8 *)(OMAP_UART1_BASE); + uart = (volatile u8 *)(OMAP3_UART1_BASE); #elif defined(CONFIG_OMAP_LL_DEBUG_NONE) return; #else -- GitLab From 0c8219f0302d0d27fda52c790d38406801e547ec Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 08:49:01 -0800 Subject: [PATCH 2071/3892] omap: Make uncompress code and DEBUG_LL code generic Define arch_decomp_setup() the same way as some other architectures do. Use arch_id to configure the debug uart based on the machine_is by storing it into the uart scratchpad register for DEBUG_LL code to use. Signed-off-by: Tony Lindgren --- .../arm/mach-omap1/include/mach/debug-macro.S | 72 ++++++- .../arm/mach-omap2/include/mach/debug-macro.S | 117 ++++++++--- arch/arm/plat-omap/include/plat/serial.h | 33 +++- arch/arm/plat-omap/include/plat/uncompress.h | 182 +++++++++++++----- 4 files changed, 322 insertions(+), 82 deletions(-) diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S index 9ea12f29e0b6..b6d9584544b4 100644 --- a/arch/arm/mach-omap1/include/mach/debug-macro.S +++ b/arch/arm/mach-omap1/include/mach/debug-macro.S @@ -15,18 +15,76 @@ #include + .pushsection .data +omap_uart_phys: .word 0x0 +omap_uart_virt: .word 0x0 + .popsection + + /* + * Note that this code won't work if the bootloader passes + * a wrong machine ID number in r1. To debug, just hardcode + * the desired UART phys and virt addresses temporarily into + * the omap_uart_phys and omap_uart_virt above. + */ .macro addruart, rx, tmp + + /* Use omap_uart_phys/virt if already configured */ +9: mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =omap_uart_phys @ physical base address + ldrne \rx, =omap_uart_virt @ virtual base + ldr \rx, [\rx, #0] + cmp \rx, #0 @ is port configured? + bne 99f @ already configured + + /* Check 7XX UART1 scratchpad register for uart to use */ + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0xff000000 @ physical base address + movne \rx, #0xfe000000 @ virtual base + orr \rx, \rx, #0x00fb0000 @ OMAP1UART1 + ldrb \rx, [\rx, #(UART_SCR << OMAP7XX_PORT_SHIFT)] + cmp \rx, #0 @ anything in 7XX scratchpad? + bne 10f @ found 7XX uart + + /* Check 15xx/16xx UART1 scratchpad register for uart to use */ mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0xff000000 @ physical base address movne \rx, #0xfe000000 @ virtual base - orr \rx, \rx, #0x00fb0000 -#ifdef CONFIG_OMAP_LL_DEBUG_UART3 - orr \rx, \rx, #0x00009000 @ UART 3 -#endif -#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3) - orr \rx, \rx, #0x00000800 @ UART 2 & 3 -#endif + orr \rx, \rx, #0x00fb0000 @ OMAP1UART1 + ldrb \rx, [\rx, #(UART_SCR << OMAP_PORT_SHIFT)] + + /* Select the UART to use based on the UART1 scratchpad value */ +10: cmp \rx, #0 @ no port configured? + beq 11f @ if none, try to use UART1 + cmp \rx, #OMAP1UART1 + beq 11f @ configure OMAP1UART1 + cmp \rx, #OMAP1UART2 + beq 12f @ configure OMAP1UART2 + cmp \rx, #OMAP1UART3 + beq 13f @ configure OMAP2UART3 + + /* Configure the UART offset from the phys/virt base */ +11: mov \rx, #0x00fb0000 @ OMAP1UART1 + b 98f +12: mov \rx, #0x00fb0000 @ OMAP1UART1 + orr \rx, \rx, #0x00000800 @ OMAP1UART2 + b 98f +13: mov \rx, #0x00fb0000 @ OMAP1UART1 + orr \rx, \rx, #0x00000800 @ OMAP1UART2 + orr \rx, \rx, #0x00009000 @ OMAP1UART3 + + /* Store both phys and virt address for the uart */ +98: add \rx, \rx, #0xff000000 @ phys base + ldr \tmp, =omap_uart_phys + str \rx, [\tmp, #0] + sub \rx, \rx, #0xff000000 @ phys base + add \rx, \rx, #0xfe000000 @ virt base + ldr \tmp, =omap_uart_virt + str \rx, [\tmp, #0] + b 9b +99: .endm .macro senduart,rd,rx diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S index 8d6da9a39d63..4a63a2ea484d 100644 --- a/arch/arm/mach-omap2/include/mach/debug-macro.S +++ b/arch/arm/mach-omap2/include/mach/debug-macro.S @@ -15,32 +15,103 @@ #include +#define UART_OFFSET(addr) ((addr) & 0x00ffffff) + + .pushsection .data +omap_uart_phys: .word 0 +omap_uart_virt: .word 0 +omap_uart_lsr: .word 0 + .popsection + + /* + * Note that this code won't work if the bootloader passes + * a wrong machine ID number in r1. To debug, just hardcode + * the desired UART phys and virt addresses temporarily into + * the omap_uart_phys and omap_uart_virt above. + */ .macro addruart, rx, tmp + + /* Use omap_uart_phys/virt if already configured */ +10: mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =omap_uart_phys @ physical base address + ldrne \rx, =omap_uart_virt @ virtual base address + ldr \rx, [\rx, #0] + cmp \rx, #0 @ is port configured? + bne 99f @ already configured + + /* Check UART1 scratchpad register for uart to use */ mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? -#ifdef CONFIG_ARCH_OMAP2 moveq \rx, #0x48000000 @ physical base address movne \rx, #0xfa000000 @ virtual base - orr \rx, \rx, #0x0006a000 -#ifdef CONFIG_OMAP_LL_DEBUG_UART2 - add \rx, \rx, #0x00002000 @ UART 2 -#endif -#ifdef CONFIG_OMAP_LL_DEBUG_UART3 - add \rx, \rx, #0x00004000 @ UART 3 -#endif - -#elif defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) - moveq \rx, #0x48000000 @ physical base address - movne \rx, #0xfa000000 @ virtual base - orr \rx, \rx, #0x0006a000 -#ifdef CONFIG_OMAP_LL_DEBUG_UART2 - add \rx, \rx, #0x00002000 @ UART 2 -#endif -#ifdef CONFIG_OMAP_LL_DEBUG_UART3 - add \rx, \rx, #0x00fb0000 @ UART 3 - add \rx, \rx, #0x00006000 -#endif -#endif + orr \rx, \rx, #0x0006a000 @ uart1 on omap2/3/4 + ldrb \rx, [\rx, #(UART_SCR << OMAP_PORT_SHIFT)] @ scratchpad + + /* Select the UART to use based on the UART1 scratchpad value */ + cmp \rx, #0 @ no port configured? + beq 21f @ if none, try to use UART1 + cmp \rx, #OMAP2UART1 @ OMAP2/3/4UART1 + beq 21f @ configure OMAP2/3/4UART1 + cmp \rx, #OMAP2UART2 @ OMAP2/3/4UART2 + beq 22f @ configure OMAP2/3/4UART2 + cmp \rx, #OMAP2UART3 @ only on 24xx + beq 23f @ configure OMAP2UART3 + cmp \rx, #OMAP3UART3 @ only on 34xx + beq 33f @ configure OMAP3UART3 + cmp \rx, #OMAP4UART3 @ only on 44xx + beq 43f @ configure OMAP4UART3 + cmp \rx, #OMAP3UART4 @ only on 36xx + beq 34f @ configure OMAP3UART4 + cmp \rx, #OMAP4UART4 @ only on 44xx + beq 44f @ configure OMAP4UART4 + cmp \rx, #ZOOM_UART @ only on zoom2/3 + beq 95f @ configure ZOOM_UART + + /* Configure the UART offset from the phys/virt base */ +21: mov \rx, #UART_OFFSET(OMAP2_UART1_BASE) @ omap2/3/4 + b 98f +22: mov \rx, #UART_OFFSET(OMAP2_UART2_BASE) @ omap2/3/4 + b 98f +23: mov \rx, #UART_OFFSET(OMAP2_UART3_BASE) + b 98f +33: mov \rx, #UART_OFFSET(OMAP3_UART1_BASE) + add \rx, \rx, #0x00fb0000 + add \rx, \rx, #0x00006000 @ OMAP3_UART3_BASE + b 98f +34: mov \rx, #UART_OFFSET(OMAP3_UART1_BASE) + add \rx, \rx, #0x00fb0000 + add \rx, \rx, #0x00028000 @ OMAP3_UART4_BASE + b 98f +43: mov \rx, #UART_OFFSET(OMAP4_UART3_BASE) + b 98f +44: mov \rx, #UART_OFFSET(OMAP4_UART4_BASE) + b 98f +95: mov \rx, #ZOOM_UART_BASE + ldr \tmp, =omap_uart_phys + str \rx, [\tmp, #0] + mov \rx, #ZOOM_UART_VIRT + ldr \tmp, =omap_uart_virt + str \rx, [\tmp, #0] + mov \rx, #(UART_LSR << ZOOM_PORT_SHIFT) + ldr \tmp, =omap_uart_lsr + str \rx, [\tmp, #0] + b 10b + + /* Store both phys and virt address for the uart */ +98: add \rx, \rx, #0x48000000 @ phys base + ldr \tmp, =omap_uart_phys + str \rx, [\tmp, #0] + sub \rx, \rx, #0x48000000 @ phys base + add \rx, \rx, #0xfa000000 @ virt base + ldr \tmp, =omap_uart_virt + str \rx, [\tmp, #0] + mov \rx, #(UART_LSR << OMAP_PORT_SHIFT) + ldr \tmp, =omap_uart_lsr + str \rx, [\tmp, #0] + + b 10b +99: .endm .macro senduart,rd,rx @@ -48,7 +119,9 @@ .endm .macro busyuart,rd,rx -1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)] +1001: ldr \rd, =omap_uart_lsr + ldr \rd, [\rd, #0] + ldrb \rd, [\rx, \rd] and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) bne 1001b diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h index 7f5a7a88a6eb..83dce4c4f7e6 100644 --- a/arch/arm/plat-omap/include/plat/serial.h +++ b/arch/arm/plat-omap/include/plat/serial.h @@ -26,24 +26,49 @@ #define OMAP2_UART3_BASE 0x4806e000 /* OMAP3 serial ports */ -#define OMAP3_UART1_BASE 0x4806a000 -#define OMAP3_UART2_BASE 0x4806c000 +#define OMAP3_UART1_BASE OMAP2_UART1_BASE +#define OMAP3_UART2_BASE OMAP2_UART2_BASE #define OMAP3_UART3_BASE 0x49020000 #define OMAP3_UART4_BASE 0x49042000 /* Only on 36xx */ /* OMAP4 serial ports */ -#define OMAP4_UART1_BASE 0x4806a000 -#define OMAP4_UART2_BASE 0x4806c000 +#define OMAP4_UART1_BASE OMAP2_UART1_BASE +#define OMAP4_UART2_BASE OMAP2_UART2_BASE #define OMAP4_UART3_BASE 0x48020000 #define OMAP4_UART4_BASE 0x4806e000 +/* External port on Zoom2/3 */ +#define ZOOM_UART_BASE 0x10000000 +#define ZOOM_UART_VIRT 0xfb000000 + #define OMAP_PORT_SHIFT 2 #define OMAP7XX_PORT_SHIFT 0 +#define ZOOM_PORT_SHIFT 1 #define OMAP1510_BASE_BAUD (12000000/16) #define OMAP16XX_BASE_BAUD (48000000/16) #define OMAP24XX_BASE_BAUD (48000000/16) +/* + * DEBUG_LL port encoding stored into the UART1 scratchpad register by + * decomp_setup in uncompress.h + */ +#define OMAP1UART1 11 +#define OMAP1UART2 12 +#define OMAP1UART3 13 +#define OMAP2UART1 21 +#define OMAP2UART2 22 +#define OMAP2UART3 23 +#define OMAP3UART1 OMAP2UART1 +#define OMAP3UART2 OMAP2UART2 +#define OMAP3UART3 33 +#define OMAP3UART4 34 /* Only on 36xx */ +#define OMAP4UART1 OMAP2UART1 +#define OMAP4UART2 OMAP2UART2 +#define OMAP4UART3 43 +#define OMAP4UART4 44 +#define ZOOM_UART 95 /* Only on zoom2/3 */ + /* This is only used by 8250.c for omap1510 */ #define is_omap_port(pt) ({int __ret = 0; \ if ((pt)->port.mapbase == OMAP1_UART1_BASE || \ diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h index e5723c3e3418..81d9ec540fcf 100644 --- a/arch/arm/plat-omap/include/plat/uncompress.h +++ b/arch/arm/plat-omap/include/plat/uncompress.h @@ -19,71 +19,155 @@ #include #include + +#include + #include -unsigned int system_rev; +static volatile u8 *uart1_base; +static int uart1_shift; -#define UART_OMAP_MDR1 0x08 /* mode definition register */ -#define OMAP_ID_730 0x355F -#define OMAP_ID_850 0x362C -#define ID_MASK 0x7fff -#define check_port(base, shift) ((base[UART_OMAP_MDR1 << shift] & 7) == 0) -#define omap_get_id() ((*(volatile unsigned int *)(0xfffed404)) >> 12) & ID_MASK +static volatile u8 *uart_base; +static int uart_shift; -static void putc(int c) +/* + * Store the DEBUG_LL uart number into UART1 scratchpad register. + * See also debug-macro.S, and serial.c for related code. + * + * Please note that we currently assume that: + * - UART1 clocks are enabled for register access + * - UART1 scratchpad register can be used + */ +static void set_uart1_scratchpad(unsigned char port) { - volatile u8 * uart = 0; - int shift = 2; - -#ifdef CONFIG_MACH_OMAP_PALMTE - return; -#endif - -#ifdef CONFIG_ARCH_OMAP - /* Will get removed in the next patch, set to OMAP3 to compile */ -#ifdef CONFIG_OMAP_LL_DEBUG_UART3 - uart = (volatile u8 *)(OMAP3_UART3_BASE); -#elif defined(CONFIG_OMAP_LL_DEBUG_UART2) - uart = (volatile u8 *)(OMAP3_UART2_BASE); -#elif defined(CONFIG_OMAP_LL_DEBUG_UART1) - uart = (volatile u8 *)(OMAP3_UART1_BASE); -#elif defined(CONFIG_OMAP_LL_DEBUG_NONE) - return; -#else - return; -#endif - -#ifdef CONFIG_ARCH_OMAP1 - /* Determine which serial port to use */ - do { - /* MMU is not on, so cpu_is_omapXXXX() won't work here */ - unsigned int omap_id = omap_get_id(); - - if (omap_id == OMAP_ID_730 || omap_id == OMAP_ID_850) - shift = 0; + uart1_base[UART_SCR << uart1_shift] = port; +} - if (check_port(uart, shift)) - break; - /* Silent boot if no serial ports are enabled. */ +static void putc(int c) +{ + if (!uart_base) return; - } while (0); -#endif /* CONFIG_ARCH_OMAP1 */ -#endif - /* - * Now, xmit each character - */ - while (!(uart[UART_LSR << shift] & UART_LSR_THRE)) + while (!(uart_base[UART_LSR << uart_shift] & UART_LSR_THRE)) barrier(); - uart[UART_TX << shift] = c; + uart_base[UART_TX << uart_shift] = c; } static inline void flush(void) { } +/* + * Macros to configure UART1 and debug UART + */ +#define _DEBUG_LL_ENTRY(mach, uart1_phys, uart1_shft, \ + dbg_uart, dbg_shft, dbg_id) \ + if (machine_is_##mach()) { \ + uart1_base = (volatile u8 *)(uart1_phys); \ + uart1_shift = (uart1_shft); \ + uart_base = (volatile u8 *)(dbg_uart); \ + uart_shift = (dbg_shft); \ + port = (dbg_id); \ + set_uart1_scratchpad(port); \ + break; \ + } + +#define DEBUG_LL_OMAP7XX(p, mach) \ + _DEBUG_LL_ENTRY(mach, OMAP1_UART1_BASE, OMAP7XX_PORT_SHIFT, \ + OMAP1_UART##p##_BASE, OMAP7XX_PORT_SHIFT, OMAP1UART##p) + +#define DEBUG_LL_OMAP1(p, mach) \ + _DEBUG_LL_ENTRY(mach, OMAP1_UART1_BASE, OMAP_PORT_SHIFT, \ + OMAP1_UART##p##_BASE, OMAP_PORT_SHIFT, OMAP1UART##p) + +#define DEBUG_LL_OMAP2(p, mach) \ + _DEBUG_LL_ENTRY(mach, OMAP2_UART1_BASE, OMAP_PORT_SHIFT, \ + OMAP2_UART##p##_BASE, OMAP_PORT_SHIFT, OMAP2UART##p) + +#define DEBUG_LL_OMAP3(p, mach) \ + _DEBUG_LL_ENTRY(mach, OMAP3_UART1_BASE, OMAP_PORT_SHIFT, \ + OMAP3_UART##p##_BASE, OMAP_PORT_SHIFT, OMAP3UART##p) + +#define DEBUG_LL_OMAP4(p, mach) \ + _DEBUG_LL_ENTRY(mach, OMAP4_UART1_BASE, OMAP_PORT_SHIFT, \ + OMAP4_UART##p##_BASE, OMAP_PORT_SHIFT, OMAP4UART##p) + +/* Zoom2/3 shift is different for UART1 and external port */ +#define DEBUG_LL_ZOOM(mach) \ + _DEBUG_LL_ENTRY(mach, OMAP2_UART1_BASE, OMAP_PORT_SHIFT, \ + ZOOM_UART_BASE, ZOOM_PORT_SHIFT, ZOOM_UART) + +static inline void __arch_decomp_setup(unsigned long arch_id) +{ + int port = 0; + + /* + * Initialize the port based on the machine ID from the bootloader. + * Note that we're using macros here instead of switch statement + * as machine_is functions are optimized out for the boards that + * are not selected. + */ + do { + /* omap7xx/8xx based boards using UART1 with shift 0 */ + DEBUG_LL_OMAP7XX(1, herald); + DEBUG_LL_OMAP7XX(1, omap_perseus2); + + /* omap15xx/16xx based boards using UART1 */ + DEBUG_LL_OMAP1(1, ams_delta); + DEBUG_LL_OMAP1(1, nokia770); + DEBUG_LL_OMAP1(1, omap_h2); + DEBUG_LL_OMAP1(1, omap_h3); + DEBUG_LL_OMAP1(1, omap_innovator); + DEBUG_LL_OMAP1(1, omap_osk); + DEBUG_LL_OMAP1(1, omap_palmte); + DEBUG_LL_OMAP1(1, omap_palmz71); + + /* omap15xx/16xx based boards using UART2 */ + DEBUG_LL_OMAP1(2, omap_palmtt); + + /* omap15xx/16xx based boards using UART3 */ + DEBUG_LL_OMAP1(3, sx1); + + /* omap2 based boards using UART1 */ + DEBUG_LL_OMAP2(1, omap2evm); + DEBUG_LL_OMAP2(1, omap_2430sdp); + DEBUG_LL_OMAP2(1, omap_apollon); + DEBUG_LL_OMAP2(1, omap_h4); + + /* omap2 based boards using UART3 */ + DEBUG_LL_OMAP2(3, nokia_n800); + DEBUG_LL_OMAP2(3, nokia_n810); + DEBUG_LL_OMAP2(3, nokia_n810_wimax); + + /* omap3 based boards using UART1 */ + DEBUG_LL_OMAP2(1, omap3evm); + DEBUG_LL_OMAP3(1, omap_3430sdp); + DEBUG_LL_OMAP3(1, omap_3630sdp); + + /* omap3 based boards using UART3 */ + DEBUG_LL_OMAP3(3, cm_t35); + DEBUG_LL_OMAP3(3, igep0020); + DEBUG_LL_OMAP3(3, nokia_rx51); + DEBUG_LL_OMAP3(3, omap3517evm); + DEBUG_LL_OMAP3(3, omap3_beagle); + DEBUG_LL_OMAP3(3, omap3_pandora); + DEBUG_LL_OMAP3(3, omap_ldp); + DEBUG_LL_OMAP3(3, overo); + DEBUG_LL_OMAP3(3, touchbook); + + /* omap4 based boards using UART3 */ + DEBUG_LL_OMAP4(3, omap_4430sdp); + + /* zoom2/3 external uart */ + DEBUG_LL_ZOOM(omap_zoom2); + DEBUG_LL_ZOOM(omap_zoom3); + + } while (0); +} + +#define arch_decomp_setup() __arch_decomp_setup(arch_id) + /* * nothing to do */ -#define arch_decomp_setup() #define arch_decomp_wdog() -- GitLab From 61b603b4ee0c70708539e2fa5c3d47f17b7c7849 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 08:49:14 -0800 Subject: [PATCH 2072/3892] omap: Remove old DEBUG_LL serial port options These are no longer needed. Note that zoom boards should now set their own function in uncompress.h and debug-macro.S for the external UART. Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/Kconfig | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index e2ea04a4c8a1..484d6a91524f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -141,25 +141,6 @@ config OMAP_DM_TIMER help Select this option if you want to use OMAP Dual-Mode timers. -choice - prompt "Low-level debug console UART" - depends on ARCH_OMAP - default OMAP_LL_DEBUG_NONE - -config OMAP_LL_DEBUG_UART1 - bool "UART1" - -config OMAP_LL_DEBUG_UART2 - bool "UART2" - -config OMAP_LL_DEBUG_UART3 - bool "UART3" - -config OMAP_LL_DEBUG_NONE - bool "None" - -endchoice - config OMAP_SERIAL_WAKE bool "Enable wake-up events for serial ports" depends on ARCH_OMAP1 && OMAP_MUX -- GitLab From 5d0aa2ccd4699a01cfdf14886191c249d7b45a01 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 15 Feb 2010 18:13:33 +0100 Subject: [PATCH 2073/3892] netfilter: nf_conntrack: add support for "conntrack zones" Normally, each connection needs a unique identity. Conntrack zones allow to specify a numerical zone using the CT target, connections in different zones can use the same identity. Example: iptables -t raw -A PREROUTING -i veth0 -j CT --zone 1 iptables -t raw -A OUTPUT -o veth1 -j CT --zone 1 Signed-off-by: Patrick McHardy --- include/linux/netfilter/xt_CT.h | 2 +- include/net/ip.h | 3 + include/net/ipv6.h | 3 + include/net/netfilter/nf_conntrack.h | 5 +- include/net/netfilter/nf_conntrack_core.h | 3 +- include/net/netfilter/nf_conntrack_expect.h | 9 +- include/net/netfilter/nf_conntrack_extend.h | 2 + include/net/netfilter/nf_conntrack_zones.h | 23 ++++ .../netfilter/nf_conntrack_l3proto_ipv4.c | 3 +- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 8 +- net/ipv4/netfilter/nf_defrag_ipv4.c | 12 +- net/ipv4/netfilter/nf_nat_core.c | 24 ++-- net/ipv4/netfilter/nf_nat_pptp.c | 3 +- .../netfilter/nf_conntrack_l3proto_ipv6.c | 12 +- .../netfilter/nf_conntrack_proto_icmpv6.c | 8 +- net/netfilter/Kconfig | 13 +++ net/netfilter/nf_conntrack_core.c | 109 +++++++++++++----- net/netfilter/nf_conntrack_expect.c | 21 ++-- net/netfilter/nf_conntrack_h323_main.c | 3 +- net/netfilter/nf_conntrack_netlink.c | 20 ++-- net/netfilter/nf_conntrack_pptp.c | 14 ++- net/netfilter/nf_conntrack_sip.c | 3 +- net/netfilter/nf_conntrack_standalone.c | 6 + net/netfilter/xt_CT.c | 8 +- net/netfilter/xt_connlimit.c | 4 +- 25 files changed, 236 insertions(+), 85 deletions(-) create mode 100644 include/net/netfilter/nf_conntrack_zones.h diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h index 7fd0effe1316..1b564106891d 100644 --- a/include/linux/netfilter/xt_CT.h +++ b/include/linux/netfilter/xt_CT.h @@ -5,7 +5,7 @@ struct xt_ct_target_info { u_int16_t flags; - u_int16_t __unused; + u_int16_t zone; u_int32_t ct_events; u_int32_t exp_events; char helper[16]; diff --git a/include/net/ip.h b/include/net/ip.h index fb63371c07a8..7bc47873e3fc 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -352,8 +352,11 @@ enum ip_defrag_users { IP_DEFRAG_LOCAL_DELIVER, IP_DEFRAG_CALL_RA_CHAIN, IP_DEFRAG_CONNTRACK_IN, + __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX, IP_DEFRAG_CONNTRACK_OUT, + __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX, IP_DEFRAG_CONNTRACK_BRIDGE_IN, + __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX, IP_DEFRAG_VS_IN, IP_DEFRAG_VS_OUT, IP_DEFRAG_VS_FWD diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 299bbf5adfb6..639ec53ea081 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -355,8 +355,11 @@ struct inet_frag_queue; enum ip6_defrag_users { IP6_DEFRAG_LOCAL_DELIVER, IP6_DEFRAG_CONNTRACK_IN, + __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX, IP6_DEFRAG_CONNTRACK_OUT, + __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX, IP6_DEFRAG_CONNTRACK_BRIDGE_IN, + __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX, }; struct ip6_create_arg { diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 5b7d8835523f..bde095f7e845 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -198,7 +198,8 @@ extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int null extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); extern struct nf_conntrack_tuple_hash * -__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); +__nf_conntrack_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); extern void nf_conntrack_hash_insert(struct nf_conn *ct); extern void nf_ct_delete_from_lists(struct nf_conn *ct); @@ -267,7 +268,7 @@ extern void nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data); extern void nf_conntrack_free(struct nf_conn *ct); extern struct nf_conn * -nf_conntrack_alloc(struct net *net, +nf_conntrack_alloc(struct net *net, u16 zone, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_tuple *repl, gfp_t gfp); diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 5a449b44ba33..dffde8e6920e 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -49,7 +49,8 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, /* Find a connection corresponding to a tuple. */ extern struct nf_conntrack_tuple_hash * -nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); +nf_conntrack_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); extern int __nf_conntrack_confirm(struct sk_buff *skb); diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 4b47ec19ef39..11e815084fcf 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -74,13 +74,16 @@ int nf_conntrack_expect_init(struct net *net); void nf_conntrack_expect_fini(struct net *net); struct nf_conntrack_expect * -__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple); +__nf_ct_expect_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * -nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); +nf_ct_expect_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); struct nf_conntrack_expect * -nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple); +nf_ct_find_expectation(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); void nf_ct_remove_expectations(struct nf_conn *ct); diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h index e192dc17c583..2d2a1f9a61d8 100644 --- a/include/net/netfilter/nf_conntrack_extend.h +++ b/include/net/netfilter/nf_conntrack_extend.h @@ -8,6 +8,7 @@ enum nf_ct_ext_id { NF_CT_EXT_NAT, NF_CT_EXT_ACCT, NF_CT_EXT_ECACHE, + NF_CT_EXT_ZONE, NF_CT_EXT_NUM, }; @@ -15,6 +16,7 @@ enum nf_ct_ext_id { #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat #define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache +#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone /* Extensions: optional stuff which isn't permanently in struct. */ struct nf_ct_ext { diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h new file mode 100644 index 000000000000..0bbb2bd51e89 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_zones.h @@ -0,0 +1,23 @@ +#ifndef _NF_CONNTRACK_ZONES_H +#define _NF_CONNTRACK_ZONES_H + +#include + +#define NF_CT_DEFAULT_ZONE 0 + +struct nf_conntrack_zone { + u16 id; +}; + +static inline u16 nf_ct_zone(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_ZONES + struct nf_conntrack_zone *nf_ct_zone; + nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE); + if (nf_ct_zone) + return nf_ct_zone->id; +#endif + return NF_CT_DEFAULT_ZONE; +} + +#endif /* _NF_CONNTRACK_ZONES_H */ diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index d1ea38a7c490..2bb1f87051c4 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -266,7 +267,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) return -EINVAL; } - h = nf_conntrack_find_get(sock_net(sk), &tuple); + h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple); if (h) { struct sockaddr_in sin; struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 327826a968a8..7404bde95994 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; @@ -114,13 +115,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ static int -icmp_error_message(struct net *net, struct sk_buff *skb, +icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, enum ip_conntrack_info *ctinfo, unsigned int hooknum) { struct nf_conntrack_tuple innertuple, origtuple; const struct nf_conntrack_l4proto *innerproto; const struct nf_conntrack_tuple_hash *h; + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; NF_CT_ASSERT(skb->nfct == NULL); @@ -146,7 +148,7 @@ icmp_error_message(struct net *net, struct sk_buff *skb, *ctinfo = IP_CT_RELATED; - h = nf_conntrack_find_get(net, &innertuple); + h = nf_conntrack_find_get(net, zone, &innertuple); if (!h) { pr_debug("icmp_error_message: no match\n"); return -NF_ACCEPT; @@ -209,7 +211,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, icmph->type != ICMP_REDIRECT) return NF_ACCEPT; - return icmp_error_message(net, skb, ctinfo, hooknum); + return icmp_error_message(net, tmpl, skb, ctinfo, hooknum); } #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index f6f46686cbc0..d498a704d456 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -39,15 +40,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, struct sk_buff *skb) { + u16 zone = NF_CT_DEFAULT_ZONE; + + if (skb->nfct) + zone = nf_ct_zone((struct nf_conn *)skb->nfct); + #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge && skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) - return IP_DEFRAG_CONNTRACK_BRIDGE_IN; + return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone; #endif if (hooknum == NF_INET_PRE_ROUTING) - return IP_DEFRAG_CONNTRACK_IN; + return IP_DEFRAG_CONNTRACK_IN + zone; else - return IP_DEFRAG_CONNTRACK_OUT; + return IP_DEFRAG_CONNTRACK_OUT + zone; } static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 26066a2327ad..4595281c2863 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -30,6 +30,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(nf_nat_lock); @@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put); /* We keep an extra hash for each conntrack, for fast searching. */ static inline unsigned int -hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple) +hash_by_src(const struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { unsigned int hash; /* Original src, to ensure we map it consistently if poss. */ hash = jhash_3words((__force u32)tuple->src.u3.ip, - (__force u32)tuple->src.u.all, + (__force u32)tuple->src.u.all ^ zone, tuple->dst.protonum, 0); return ((u64)hash * net->ipv4.nat_htable_size) >> 32; } @@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct, /* Only called for SRC manip */ static int -find_appropriate_src(struct net *net, +find_appropriate_src(struct net *net, u16 zone, const struct nf_conntrack_tuple *tuple, struct nf_conntrack_tuple *result, const struct nf_nat_range *range) { - unsigned int h = hash_by_src(net, tuple); + unsigned int h = hash_by_src(net, zone, tuple); const struct nf_conn_nat *nat; const struct nf_conn *ct; const struct hlist_node *n; @@ -152,7 +154,7 @@ find_appropriate_src(struct net *net, rcu_read_lock(); hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { ct = nat->ct; - if (same_src(ct, tuple)) { + if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) { /* Copy source part from reply tuple. */ nf_ct_invert_tuplepr(result, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); @@ -175,7 +177,7 @@ find_appropriate_src(struct net *net, the ip with the lowest src-ip/dst-ip/proto usage. */ static void -find_best_ips_proto(struct nf_conntrack_tuple *tuple, +find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, const struct nf_conn *ct, enum nf_nat_manip_type maniptype) @@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple, maxip = ntohl(range->max_ip); j = jhash_2words((__force u32)tuple->src.u3.ip, range->flags & IP_NAT_RANGE_PERSISTENT ? - 0 : (__force u32)tuple->dst.u3.ip, 0); + 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0); j = ((u64)j * (maxip - minip + 1)) >> 32; *var_ipp = htonl(minip + j); } @@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, { struct net *net = nf_ct_net(ct); const struct nf_nat_protocol *proto; + u16 zone = nf_ct_zone(ct); /* 1) If this srcip/proto/src-proto-part is currently mapped, and that same mapping gives a unique tuple within the given @@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, manips not an issue. */ if (maniptype == IP_NAT_MANIP_SRC && !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { - if (find_appropriate_src(net, orig_tuple, tuple, range)) { + if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) { pr_debug("get_unique_tuple: Found current src map\n"); if (!nf_nat_used_tuple(tuple, ct)) return; @@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, /* 2) Select the least-used IP/proto combination in the given range. */ *tuple = *orig_tuple; - find_best_ips_proto(tuple, range, ct, maniptype); + find_best_ips_proto(zone, tuple, range, ct, maniptype); /* 3) The per-protocol part of the manip is made to map into the range to make a unique tuple. */ @@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct, if (have_to_hash) { unsigned int srchash; - srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + srchash = hash_by_src(net, nf_ct_zone(ct), + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); spin_lock_bh(&nf_nat_lock); /* nf_conntrack_alter_reply might re-allocate exntension aera */ nat = nfct_nat(ct); diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c index 9eb171056c63..4c060038d29f 100644 --- a/net/ipv4/netfilter/nf_nat_pptp.c +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,7 @@ static void pptp_nat_expected(struct nf_conn *ct, pr_debug("trying to unexpect other dir: "); nf_ct_dump_tuple_ip(&t); - other_exp = nf_ct_expect_find_get(net, &t); + other_exp = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t); if (other_exp) { nf_ct_unexpect_related(other_exp); nf_ct_expect_put(other_exp); diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 55ce22e5de49..996c3f41fecd 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -191,15 +192,20 @@ out: static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, struct sk_buff *skb) { + u16 zone = NF_CT_DEFAULT_ZONE; + + if (skb->nfct) + zone = nf_ct_zone((struct nf_conn *)skb->nfct); + #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge && skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) - return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; + return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; #endif if (hooknum == NF_INET_PRE_ROUTING) - return IP6_DEFRAG_CONNTRACK_IN; + return IP6_DEFRAG_CONNTRACK_IN + zone; else - return IP6_DEFRAG_CONNTRACK_OUT; + return IP6_DEFRAG_CONNTRACK_OUT + zone; } diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index d772dc21857f..9be81776415e 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -128,7 +129,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, } static int -icmpv6_error_message(struct net *net, +icmpv6_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, unsigned int icmp6off, enum ip_conntrack_info *ctinfo, @@ -137,6 +138,7 @@ icmpv6_error_message(struct net *net, struct nf_conntrack_tuple intuple, origtuple; const struct nf_conntrack_tuple_hash *h; const struct nf_conntrack_l4proto *inproto; + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; NF_CT_ASSERT(skb->nfct == NULL); @@ -163,7 +165,7 @@ icmpv6_error_message(struct net *net, *ctinfo = IP_CT_RELATED; - h = nf_conntrack_find_get(net, &intuple); + h = nf_conntrack_find_get(net, zone, &intuple); if (!h) { pr_debug("icmpv6_error: no match\n"); return -NF_ACCEPT; @@ -216,7 +218,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, if (icmp6h->icmp6_type >= 128) return NF_ACCEPT; - return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum); + return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); } #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 4469d45261f4..18d77b5c351a 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -83,6 +83,19 @@ config NF_CONNTRACK_SECMARK If unsure, say 'N'. +config NF_CONNTRACK_ZONES + bool 'Connection tracking zones' + depends on NETFILTER_ADVANCED + depends on NETFILTER_XT_TARGET_CT + help + This option enables support for connection tracking zones. + Normally, each connection needs to have a unique system wide + identity. Connection tracking zones allow to have multiple + connections using the same identity, as long as they are + contained in different zones. + + If unsure, say `N'. + config NF_CONNTRACK_EVENTS bool "Connection tracking events" depends on NETFILTER_ADVANCED diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 65351ed5d815..0c9bbe93cc16 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,7 @@ static int nf_conntrack_hash_rnd_initted; static unsigned int nf_conntrack_hash_rnd; static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, - unsigned int size, unsigned int rnd) + u16 zone, unsigned int size, unsigned int rnd) { unsigned int n; u_int32_t h; @@ -79,16 +80,16 @@ static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, */ n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32); h = jhash2((u32 *)tuple, n, - rnd ^ (((__force __u16)tuple->dst.u.all << 16) | - tuple->dst.protonum)); + zone ^ rnd ^ (((__force __u16)tuple->dst.u.all << 16) | + tuple->dst.protonum)); return ((u64)h * size) >> 32; } -static inline u_int32_t hash_conntrack(const struct net *net, +static inline u_int32_t hash_conntrack(const struct net *net, u16 zone, const struct nf_conntrack_tuple *tuple) { - return __hash_conntrack(tuple, net->ct.htable_size, + return __hash_conntrack(tuple, zone, net->ct.htable_size, nf_conntrack_hash_rnd); } @@ -292,11 +293,12 @@ static void death_by_timeout(unsigned long ul_conntrack) * - Caller must lock nf_conntrack_lock before calling this function */ struct nf_conntrack_tuple_hash * -__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) +__nf_conntrack_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; - unsigned int hash = hash_conntrack(net, tuple); + unsigned int hash = hash_conntrack(net, zone, tuple); /* Disable BHs the entire time since we normally need to disable them * at least once for the stats anyway. @@ -304,7 +306,8 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) local_bh_disable(); begin: hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { - if (nf_ct_tuple_equal(tuple, &h->tuple)) { + if (nf_ct_tuple_equal(tuple, &h->tuple) && + nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) { NF_CT_STAT_INC(net, found); local_bh_enable(); return h; @@ -326,21 +329,23 @@ EXPORT_SYMBOL_GPL(__nf_conntrack_find); /* Find a connection corresponding to a tuple. */ struct nf_conntrack_tuple_hash * -nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) +nf_conntrack_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; rcu_read_lock(); begin: - h = __nf_conntrack_find(net, tuple); + h = __nf_conntrack_find(net, zone, tuple); if (h) { ct = nf_ct_tuplehash_to_ctrack(h); if (unlikely(nf_ct_is_dying(ct) || !atomic_inc_not_zero(&ct->ct_general.use))) h = NULL; else { - if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { + if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) || + nf_ct_zone(ct) != zone)) { nf_ct_put(ct); goto begin; } @@ -368,9 +373,11 @@ void nf_conntrack_hash_insert(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); unsigned int hash, repl_hash; + u16 zone; - hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + zone = nf_ct_zone(ct); + hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); __nf_conntrack_hash_insert(ct, hash, repl_hash); } @@ -387,6 +394,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) struct hlist_nulls_node *n; enum ip_conntrack_info ctinfo; struct net *net; + u16 zone; ct = nf_ct_get(skb, &ctinfo); net = nf_ct_net(ct); @@ -398,8 +406,9 @@ __nf_conntrack_confirm(struct sk_buff *skb) if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) return NF_ACCEPT; - hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); + zone = nf_ct_zone(ct); + hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); /* We're not in hash table, and we refuse to set up related connections for unconfirmed conns. But packet copies and @@ -418,11 +427,13 @@ __nf_conntrack_confirm(struct sk_buff *skb) not in the hash. If there is, we lost race. */ hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, - &h->tuple)) + &h->tuple) && + zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) goto out; hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, - &h->tuple)) + &h->tuple) && + zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) goto out; /* Remove from unconfirmed list */ @@ -469,15 +480,19 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, struct net *net = nf_ct_net(ignored_conntrack); struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; - unsigned int hash = hash_conntrack(net, tuple); + struct nf_conn *ct; + u16 zone = nf_ct_zone(ignored_conntrack); + unsigned int hash = hash_conntrack(net, zone, tuple); /* Disable BHs the entire time since we need to disable them at * least once for the stats anyway. */ rcu_read_lock_bh(); hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { - if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && - nf_ct_tuple_equal(tuple, &h->tuple)) { + ct = nf_ct_tuplehash_to_ctrack(h); + if (ct != ignored_conntrack && + nf_ct_tuple_equal(tuple, &h->tuple) && + nf_ct_zone(ct) == zone) { NF_CT_STAT_INC(net, found); rcu_read_unlock_bh(); return 1; @@ -540,7 +555,7 @@ static noinline int early_drop(struct net *net, unsigned int hash) return dropped; } -struct nf_conn *nf_conntrack_alloc(struct net *net, +struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_tuple *repl, gfp_t gfp) @@ -558,7 +573,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, if (nf_conntrack_max && unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { - unsigned int hash = hash_conntrack(net, orig); + unsigned int hash = hash_conntrack(net, zone, orig); if (!early_drop(net, hash)) { atomic_dec(&net->ct.count); if (net_ratelimit()) @@ -595,13 +610,28 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, #ifdef CONFIG_NET_NS ct->ct_net = net; #endif - +#ifdef CONFIG_NF_CONNTRACK_ZONES + if (zone) { + struct nf_conntrack_zone *nf_ct_zone; + + nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC); + if (!nf_ct_zone) + goto out_free; + nf_ct_zone->id = zone; + } +#endif /* * changes to lookup keys must be done before setting refcnt to 1 */ smp_wmb(); atomic_set(&ct->ct_general.use, 1); return ct; + +#ifdef CONFIG_NF_CONNTRACK_ZONES +out_free: + kmem_cache_free(net->ct.nf_conntrack_cachep, ct); + return ERR_PTR(-ENOMEM); +#endif } EXPORT_SYMBOL_GPL(nf_conntrack_alloc); @@ -631,13 +661,14 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_tuple repl_tuple; struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { pr_debug("Can't invert tuple.\n"); return NULL; } - ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC); + ct = nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC); if (IS_ERR(ct)) { pr_debug("Can't allocate conntrack.\n"); return (struct nf_conntrack_tuple_hash *)ct; @@ -657,7 +688,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); - exp = nf_ct_find_expectation(net, tuple); + exp = nf_ct_find_expectation(net, zone, tuple); if (exp) { pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", ct, exp); @@ -713,6 +744,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, protonum, &tuple, l3proto, @@ -722,7 +754,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, } /* look for tuple match */ - h = nf_conntrack_find_get(net, &tuple); + h = nf_conntrack_find_get(net, zone, &tuple); if (!h) { h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, skb, dataoff); @@ -958,6 +990,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, } EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); +#ifdef CONFIG_NF_CONNTRACK_ZONES +static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = { + .len = sizeof(struct nf_conntrack_zone), + .align = __alignof__(struct nf_conntrack_zone), + .id = NF_CT_EXT_ZONE, +}; +#endif + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) #include @@ -1139,6 +1179,9 @@ static void nf_conntrack_cleanup_init_net(void) nf_conntrack_helper_fini(); nf_conntrack_proto_fini(); +#ifdef CONFIG_NF_CONNTRACK_ZONES + nf_ct_extend_unregister(&nf_ct_zone_extend); +#endif } static void nf_conntrack_cleanup_net(struct net *net) @@ -1214,6 +1257,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) unsigned int hashsize, old_size; struct hlist_nulls_head *hash, *old_hash; struct nf_conntrack_tuple_hash *h; + struct nf_conn *ct; if (current->nsproxy->net_ns != &init_net) return -EOPNOTSUPP; @@ -1240,8 +1284,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) while (!hlist_nulls_empty(&init_net.ct.hash[i])) { h = hlist_nulls_entry(init_net.ct.hash[i].first, struct nf_conntrack_tuple_hash, hnnode); + ct = nf_ct_tuplehash_to_ctrack(h); hlist_nulls_del_rcu(&h->hnnode); - bucket = __hash_conntrack(&h->tuple, hashsize, + bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct), + hashsize, nf_conntrack_hash_rnd); hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); } @@ -1299,6 +1345,11 @@ static int nf_conntrack_init_init_net(void) if (ret < 0) goto err_helper; +#ifdef CONFIG_NF_CONNTRACK_ZONES + ret = nf_ct_extend_register(&nf_ct_zone_extend); + if (ret < 0) + goto err_extend; +#endif /* Set up fake conntrack: to never be deleted, not in any hashes */ #ifdef CONFIG_NET_NS nf_conntrack_untracked.ct_net = &init_net; @@ -1309,6 +1360,10 @@ static int nf_conntrack_init_init_net(void) return 0; +#ifdef CONFIG_NF_CONNTRACK_ZONES +err_extend: + nf_conntrack_helper_fini(); +#endif err_helper: nf_conntrack_proto_fini(); err_proto: diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 6182fb1b55de..acb29ccaa41f 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -27,6 +27,7 @@ #include #include #include +#include unsigned int nf_ct_expect_hsize __read_mostly; EXPORT_SYMBOL_GPL(nf_ct_expect_hsize); @@ -84,7 +85,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple } struct nf_conntrack_expect * -__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple) +__nf_ct_expect_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_expect *i; struct hlist_node *n; @@ -95,7 +97,8 @@ __nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple) h = nf_ct_expect_dst_hash(tuple); hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) { - if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) + if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) && + nf_ct_zone(i->master) == zone) return i; } return NULL; @@ -104,12 +107,13 @@ EXPORT_SYMBOL_GPL(__nf_ct_expect_find); /* Just find a expectation corresponding to a tuple. */ struct nf_conntrack_expect * -nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) +nf_ct_expect_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_expect *i; rcu_read_lock(); - i = __nf_ct_expect_find(net, tuple); + i = __nf_ct_expect_find(net, zone, tuple); if (i && !atomic_inc_not_zero(&i->use)) i = NULL; rcu_read_unlock(); @@ -121,7 +125,8 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get); /* If an expectation for this connection is found, it gets delete from * global list then returned. */ struct nf_conntrack_expect * -nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple) +nf_ct_find_expectation(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_expect *i, *exp = NULL; struct hlist_node *n; @@ -133,7 +138,8 @@ nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple) h = nf_ct_expect_dst_hash(tuple); hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { if (!(i->flags & NF_CT_EXPECT_INACTIVE) && - nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { + nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) && + nf_ct_zone(i->master) == zone) { exp = i; break; } @@ -204,7 +210,8 @@ static inline int expect_matches(const struct nf_conntrack_expect *a, { return a->master == b->master && a->class == b->class && nf_ct_tuple_equal(&a->tuple, &b->tuple) && - nf_ct_tuple_mask_equal(&a->mask, &b->mask); + nf_ct_tuple_mask_equal(&a->mask, &b->mask) && + nf_ct_zone(a->master) == nf_ct_zone(b->master); } /* Generally a bad idea to call this: could have matched already. */ diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 66369490230e..a1c8dd917e12 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include /* Parameters */ @@ -1216,7 +1217,7 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct, tuple.dst.u.tcp.port = port; tuple.dst.protonum = IPPROTO_TCP; - exp = __nf_ct_expect_find(net, &tuple); + exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); if (exp && exp->master == ct) return exp; return NULL; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index db35edac307b..51089cfe1167 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -811,7 +811,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(net, &tuple); + h = nf_conntrack_find_get(net, 0, &tuple); if (!h) return -ENOENT; @@ -872,7 +872,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(net, &tuple); + h = nf_conntrack_find_get(net, 0, &tuple); if (!h) return -ENOENT; @@ -1221,7 +1221,7 @@ ctnetlink_create_conntrack(struct net *net, int err = -EINVAL; struct nf_conntrack_helper *helper; - ct = nf_conntrack_alloc(net, otuple, rtuple, GFP_ATOMIC); + ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC); if (IS_ERR(ct)) return ERR_PTR(-ENOMEM); @@ -1325,7 +1325,7 @@ ctnetlink_create_conntrack(struct net *net, if (err < 0) goto err2; - master_h = nf_conntrack_find_get(net, &master); + master_h = nf_conntrack_find_get(net, 0, &master); if (master_h == NULL) { err = -ENOENT; goto err2; @@ -1374,9 +1374,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, spin_lock_bh(&nf_conntrack_lock); if (cda[CTA_TUPLE_ORIG]) - h = __nf_conntrack_find(net, &otuple); + h = __nf_conntrack_find(net, 0, &otuple); else if (cda[CTA_TUPLE_REPLY]) - h = __nf_conntrack_find(net, &rtuple); + h = __nf_conntrack_find(net, 0, &rtuple); if (h == NULL) { err = -ENOENT; @@ -1714,7 +1714,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = nf_ct_expect_find_get(net, &tuple); + exp = nf_ct_expect_find_get(net, 0, &tuple); if (!exp) return -ENOENT; @@ -1770,7 +1770,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = nf_ct_expect_find_get(net, &tuple); + exp = nf_ct_expect_find_get(net, 0, &tuple); if (!exp) return -ENOENT; @@ -1855,7 +1855,7 @@ ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[], return err; /* Look for master conntrack of this expectation */ - h = nf_conntrack_find_get(net, &master_tuple); + h = nf_conntrack_find_get(net, 0, &master_tuple); if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); @@ -1912,7 +1912,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, return err; spin_lock_bh(&nf_conntrack_lock); - exp = __nf_ct_expect_find(net, &tuple); + exp = __nf_ct_expect_find(net, 0, &tuple); if (!exp) { spin_unlock_bh(&nf_conntrack_lock); diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index 3807ac7faf4c..088944824e13 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -123,7 +124,7 @@ static void pptp_expectfn(struct nf_conn *ct, pr_debug("trying to unexpect other dir: "); nf_ct_dump_tuple(&inv_t); - exp_other = nf_ct_expect_find_get(net, &inv_t); + exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t); if (exp_other) { /* delete other expectation. */ pr_debug("found\n"); @@ -136,17 +137,18 @@ static void pptp_expectfn(struct nf_conn *ct, rcu_read_unlock(); } -static int destroy_sibling_or_exp(struct net *net, +static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct, const struct nf_conntrack_tuple *t) { const struct nf_conntrack_tuple_hash *h; struct nf_conntrack_expect *exp; struct nf_conn *sibling; + u16 zone = nf_ct_zone(ct); pr_debug("trying to timeout ct or exp for tuple "); nf_ct_dump_tuple(t); - h = nf_conntrack_find_get(net, t); + h = nf_conntrack_find_get(net, zone, t); if (h) { sibling = nf_ct_tuplehash_to_ctrack(h); pr_debug("setting timeout of conntrack %p to 0\n", sibling); @@ -157,7 +159,7 @@ static int destroy_sibling_or_exp(struct net *net, nf_ct_put(sibling); return 1; } else { - exp = nf_ct_expect_find_get(net, t); + exp = nf_ct_expect_find_get(net, zone, t); if (exp) { pr_debug("unexpect_related of expect %p\n", exp); nf_ct_unexpect_related(exp); @@ -182,7 +184,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct) t.dst.protonum = IPPROTO_GRE; t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; - if (!destroy_sibling_or_exp(net, &t)) + if (!destroy_sibling_or_exp(net, ct, &t)) pr_debug("failed to timeout original pns->pac ct/exp\n"); /* try reply (pac->pns) tuple */ @@ -190,7 +192,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct) t.dst.protonum = IPPROTO_GRE; t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; - if (!destroy_sibling_or_exp(net, &t)) + if (!destroy_sibling_or_exp(net, ct, &t)) pr_debug("failed to timeout reply pac->pns ct/exp\n"); } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index fbe8ff5a420a..8dd75d90efc0 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -23,6 +23,7 @@ #include #include #include +#include #include MODULE_LICENSE("GPL"); @@ -836,7 +837,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff, rcu_read_lock(); do { - exp = __nf_ct_expect_find(net, &tuple); + exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); if (!exp || exp->master == ct || nfct_help(exp->master)->helper != nfct_help(ct)->helper || diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e310f1561bb2..24a42efe62ef 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -26,6 +26,7 @@ #include #include #include +#include MODULE_LICENSE("GPL"); @@ -171,6 +172,11 @@ static int ct_seq_show(struct seq_file *s, void *v) goto release; #endif +#ifdef CONFIG_NF_CONNTRACK_ZONES + if (seq_printf(s, "zone=%u ", nf_ct_zone(ct))) + goto release; +#endif + if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) goto release; diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 8183a054256f..61c50fa84703 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -16,6 +16,7 @@ #include #include #include +#include static unsigned int xt_ct_target(struct sk_buff *skb, const struct xt_target_param *par) @@ -69,11 +70,16 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par) goto out; } +#ifndef CONFIG_NF_CONNTRACK_ZONES + if (info->zone) + goto err1; +#endif + if (nf_ct_l3proto_try_module_get(par->family) < 0) goto err1; memset(&t, 0, sizeof(t)); - ct = nf_conntrack_alloc(par->net, &t, &t, GFP_KERNEL); + ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); if (IS_ERR(ct)) goto err2; diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 0d9d18ea2b09..26997ce90e48 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -28,6 +28,7 @@ #include #include #include +#include /* we will save the tuples of all connections we care about */ struct xt_connlimit_conn { @@ -114,7 +115,8 @@ static int count_them(struct net *net, /* check the saved connections */ list_for_each_entry_safe(conn, tmp, hash, list) { - found = nf_conntrack_find_get(net, &conn->tuple); + found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, + &conn->tuple); found_ct = NULL; if (found != NULL) -- GitLab From ef00f89f1eb7e056aab9dfe068521e6f2320c94a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 15 Feb 2010 18:14:57 +0100 Subject: [PATCH 2074/3892] netfilter: ctnetlink: add zone support Parse and dump the conntrack zone in ctnetlink. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nfnetlink_conntrack.h | 2 + net/netfilter/nf_conntrack_netlink.c | 92 +++++++++++++++---- 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index ed4ef8d0b11b..9ed534c991b9 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -40,6 +40,7 @@ enum ctattr_type { CTA_NAT_SEQ_ADJ_ORIG, CTA_NAT_SEQ_ADJ_REPLY, CTA_SECMARK, + CTA_ZONE, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) @@ -159,6 +160,7 @@ enum ctattr_expect { CTA_EXPECT_TIMEOUT, CTA_EXPECT_ID, CTA_EXPECT_HELP_NAME, + CTA_EXPECT_ZONE, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 51089cfe1167..8b05f364b2f2 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include #include @@ -379,6 +380,9 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, goto nla_put_failure; nla_nest_end(skb, nest_parms); + if (nf_ct_zone(ct)) + NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct))); + if (ctnetlink_dump_status(skb, ct) < 0 || ctnetlink_dump_timeout(skb, ct) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || @@ -517,6 +521,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) goto nla_put_failure; nla_nest_end(skb, nest_parms); + if (nf_ct_zone(ct)) + NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct))); + if (ctnetlink_dump_id(skb, ct) < 0) goto nla_put_failure; @@ -750,6 +757,21 @@ ctnetlink_parse_tuple(const struct nlattr * const cda[], return 0; } +static int +ctnetlink_parse_zone(const struct nlattr *attr, u16 *zone) +{ + if (attr) +#ifdef CONFIG_NF_CONNTRACK_ZONES + *zone = ntohs(nla_get_be16(attr)); +#else + return -EOPNOTSUPP; +#endif + else + *zone = 0; + + return 0; +} + static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = { [CTA_HELP_NAME] = { .type = NLA_NUL_STRING }, }; @@ -781,6 +803,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { [CTA_ID] = { .type = NLA_U32 }, [CTA_NAT_DST] = { .type = NLA_NESTED }, [CTA_TUPLE_MASTER] = { .type = NLA_NESTED }, + [CTA_ZONE] = { .type = NLA_U16 }, }; static int @@ -794,7 +817,12 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conn *ct; struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; - int err = 0; + u16 zone; + int err; + + err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); + if (err < 0) + return err; if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); @@ -811,7 +839,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(net, 0, &tuple); + h = nf_conntrack_find_get(net, zone, &tuple); if (!h) return -ENOENT; @@ -856,12 +884,17 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct sk_buff *skb2 = NULL; struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; - int err = 0; + u16 zone; + int err; if (nlh->nlmsg_flags & NLM_F_DUMP) return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, ctnetlink_done); + err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); + if (err < 0) + return err; + if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); else if (cda[CTA_TUPLE_REPLY]) @@ -872,7 +905,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - h = nf_conntrack_find_get(net, 0, &tuple); + h = nf_conntrack_find_get(net, zone, &tuple); if (!h) return -ENOENT; @@ -1211,7 +1244,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, } static struct nf_conn * -ctnetlink_create_conntrack(struct net *net, +ctnetlink_create_conntrack(struct net *net, u16 zone, const struct nlattr * const cda[], struct nf_conntrack_tuple *otuple, struct nf_conntrack_tuple *rtuple, @@ -1221,7 +1254,7 @@ ctnetlink_create_conntrack(struct net *net, int err = -EINVAL; struct nf_conntrack_helper *helper; - ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC); + ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC); if (IS_ERR(ct)) return ERR_PTR(-ENOMEM); @@ -1325,7 +1358,7 @@ ctnetlink_create_conntrack(struct net *net, if (err < 0) goto err2; - master_h = nf_conntrack_find_get(net, 0, &master); + master_h = nf_conntrack_find_get(net, zone, &master); if (master_h == NULL) { err = -ENOENT; goto err2; @@ -1358,7 +1391,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple_hash *h = NULL; struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; - int err = 0; + u16 zone; + int err; + + err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); + if (err < 0) + return err; if (cda[CTA_TUPLE_ORIG]) { err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); @@ -1374,9 +1412,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, spin_lock_bh(&nf_conntrack_lock); if (cda[CTA_TUPLE_ORIG]) - h = __nf_conntrack_find(net, 0, &otuple); + h = __nf_conntrack_find(net, zone, &otuple); else if (cda[CTA_TUPLE_REPLY]) - h = __nf_conntrack_find(net, 0, &rtuple); + h = __nf_conntrack_find(net, zone, &rtuple); if (h == NULL) { err = -ENOENT; @@ -1384,7 +1422,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conn *ct; enum ip_conntrack_events events; - ct = ctnetlink_create_conntrack(net, cda, &otuple, + ct = ctnetlink_create_conntrack(net, zone, cda, &otuple, &rtuple, u3); if (IS_ERR(ct)) { err = PTR_ERR(ct); @@ -1698,7 +1736,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, struct sk_buff *skb2; struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; - int err = 0; + u16 zone; + int err; if (nlh->nlmsg_flags & NLM_F_DUMP) { return netlink_dump_start(ctnl, skb, nlh, @@ -1706,6 +1745,10 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, ctnetlink_exp_done); } + err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); + if (err < 0) + return err; + if (cda[CTA_EXPECT_MASTER]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3); else @@ -1714,7 +1757,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = nf_ct_expect_find_get(net, 0, &tuple); + exp = nf_ct_expect_find_get(net, zone, &tuple); if (!exp) return -ENOENT; @@ -1761,16 +1804,21 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, struct hlist_node *n, *next; u_int8_t u3 = nfmsg->nfgen_family; unsigned int i; + u16 zone; int err; if (cda[CTA_EXPECT_TUPLE]) { /* delete a single expect by tuple */ + err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); + if (err < 0) + return err; + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); if (err < 0) return err; /* bump usage count to 2 */ - exp = nf_ct_expect_find_get(net, 0, &tuple); + exp = nf_ct_expect_find_get(net, zone, &tuple); if (!exp) return -ENOENT; @@ -1832,7 +1880,8 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, } static int -ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[], +ctnetlink_create_expect(struct net *net, u16 zone, + const struct nlattr * const cda[], u_int8_t u3, u32 pid, int report) { @@ -1855,7 +1904,7 @@ ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[], return err; /* Look for master conntrack of this expectation */ - h = nf_conntrack_find_get(net, 0, &master_tuple); + h = nf_conntrack_find_get(net, zone, &master_tuple); if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); @@ -1900,25 +1949,30 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_expect *exp; struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; - int err = 0; + u16 zone; + int err; if (!cda[CTA_EXPECT_TUPLE] || !cda[CTA_EXPECT_MASK] || !cda[CTA_EXPECT_MASTER]) return -EINVAL; + err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); + if (err < 0) + return err; + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); if (err < 0) return err; spin_lock_bh(&nf_conntrack_lock); - exp = __nf_ct_expect_find(net, 0, &tuple); + exp = __nf_ct_expect_find(net, zone, &tuple); if (!exp) { spin_unlock_bh(&nf_conntrack_lock); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) { - err = ctnetlink_create_expect(net, cda, + err = ctnetlink_create_expect(net, zone, cda, u3, NETLINK_CB(skb).pid, nlmsg_report(nlh)); -- GitLab From 1756de262e41112a8a8927808eb2f03d21fd4786 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 15 Feb 2010 18:15:55 +0100 Subject: [PATCH 2075/3892] netfilter: ebtables: abort if next_offset is too small next_offset must be > 0, otherwise this loops forever. The offset also contains the size of the ebt_entry structure itself, so anything smaller is invalid. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy --- net/bridge/netfilter/ebtables.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index bcdf02d866b8..4370e9680487 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -444,6 +444,8 @@ static int ebt_verify_pointers(const struct ebt_replace *repl, break; if (left < e->next_offset) break; + if (e->next_offset < sizeof(struct ebt_entry)) + return -EINVAL; offset += e->next_offset; } } -- GitLab From fc0e3df4f00a5f62c2f2fce84bf496136b58c474 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 15 Feb 2010 18:16:26 +0100 Subject: [PATCH 2076/3892] netfilter: ebtables: avoid explicit XT_ALIGN() in match/targets This will cause trouble once CONFIG_COMPAT support is added to ebtables. xt_compat_*_offset() calculate the kernel/userland structure size delta using: XT_ALIGN(size) - COMPAT_XT_ALIGN(size) If the match/target sizes are aligned at registration time, delta is always zero. Should have zero effect for existing systems: xtables uses XT_ALIGN() whenever it deals with match/target sizes. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy --- net/bridge/netfilter/ebt_802_3.c | 2 +- net/bridge/netfilter/ebt_arp.c | 2 +- net/bridge/netfilter/ebt_arpreply.c | 2 +- net/bridge/netfilter/ebt_dnat.c | 2 +- net/bridge/netfilter/ebt_ip.c | 2 +- net/bridge/netfilter/ebt_ip6.c | 2 +- net/bridge/netfilter/ebt_limit.c | 2 +- net/bridge/netfilter/ebt_log.c | 2 +- net/bridge/netfilter/ebt_mark.c | 2 +- net/bridge/netfilter/ebt_mark_m.c | 2 +- net/bridge/netfilter/ebt_nflog.c | 2 +- net/bridge/netfilter/ebt_pkttype.c | 2 +- net/bridge/netfilter/ebt_redirect.c | 2 +- net/bridge/netfilter/ebt_snat.c | 2 +- net/bridge/netfilter/ebt_stp.c | 2 +- net/bridge/netfilter/ebt_ulog.c | 2 +- net/bridge/netfilter/ebt_vlan.c | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c index bd91dc58d49b..5d1176758ca5 100644 --- a/net/bridge/netfilter/ebt_802_3.c +++ b/net/bridge/netfilter/ebt_802_3.c @@ -52,7 +52,7 @@ static struct xt_match ebt_802_3_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_802_3_mt, .checkentry = ebt_802_3_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)), + .matchsize = sizeof(struct ebt_802_3_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index b7ad60419f9a..e727697c5847 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -120,7 +120,7 @@ static struct xt_match ebt_arp_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_arp_mt, .checkentry = ebt_arp_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)), + .matchsize = sizeof(struct ebt_arp_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c index 76584cd72e57..f392e9d93f53 100644 --- a/net/bridge/netfilter/ebt_arpreply.c +++ b/net/bridge/netfilter/ebt_arpreply.c @@ -78,7 +78,7 @@ static struct xt_target ebt_arpreply_tg_reg __read_mostly = { .hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING), .target = ebt_arpreply_tg, .checkentry = ebt_arpreply_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)), + .targetsize = sizeof(struct ebt_arpreply_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index 6b49ea9e31fb..2bb40d728a35 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c @@ -54,7 +54,7 @@ static struct xt_target ebt_dnat_tg_reg __read_mostly = { (1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING), .target = ebt_dnat_tg, .checkentry = ebt_dnat_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), + .targetsize = sizeof(struct ebt_nat_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c index d771bbfbcbe6..5de6df6f86b8 100644 --- a/net/bridge/netfilter/ebt_ip.c +++ b/net/bridge/netfilter/ebt_ip.c @@ -110,7 +110,7 @@ static struct xt_match ebt_ip_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_ip_mt, .checkentry = ebt_ip_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)), + .matchsize = sizeof(struct ebt_ip_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c index 784a6573876c..bbf2534ef026 100644 --- a/net/bridge/netfilter/ebt_ip6.c +++ b/net/bridge/netfilter/ebt_ip6.c @@ -122,7 +122,7 @@ static struct xt_match ebt_ip6_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_ip6_mt, .checkentry = ebt_ip6_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)), + .matchsize = sizeof(struct ebt_ip6_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c index f7bd9192ff0c..9dd16e6b10e7 100644 --- a/net/bridge/netfilter/ebt_limit.c +++ b/net/bridge/netfilter/ebt_limit.c @@ -90,7 +90,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_limit_mt, .checkentry = ebt_limit_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)), + .matchsize = sizeof(struct ebt_limit_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index e4ea3fdd1d41..e873924ddb5d 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -195,7 +195,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = { .family = NFPROTO_BRIDGE, .target = ebt_log_tg, .checkentry = ebt_log_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_log_info)), + .targetsize = sizeof(struct ebt_log_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index 2fee7e8e2e93..153e167374a2 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -59,7 +59,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = { .family = NFPROTO_BRIDGE, .target = ebt_mark_tg, .checkentry = ebt_mark_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)), + .targetsize = sizeof(struct ebt_mark_t_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c index ea570f214b1d..89abf4030399 100644 --- a/net/bridge/netfilter/ebt_mark_m.c +++ b/net/bridge/netfilter/ebt_mark_m.c @@ -41,7 +41,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_mark_mt, .checkentry = ebt_mark_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)), + .matchsize = sizeof(struct ebt_mark_m_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c index 2a63d996dd4e..40dbd248b9ae 100644 --- a/net/bridge/netfilter/ebt_nflog.c +++ b/net/bridge/netfilter/ebt_nflog.c @@ -51,7 +51,7 @@ static struct xt_target ebt_nflog_tg_reg __read_mostly = { .family = NFPROTO_BRIDGE, .target = ebt_nflog_tg, .checkentry = ebt_nflog_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)), + .targetsize = sizeof(struct ebt_nflog_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c index 883e96e2a542..e2a07e6cbef3 100644 --- a/net/bridge/netfilter/ebt_pkttype.c +++ b/net/bridge/netfilter/ebt_pkttype.c @@ -36,7 +36,7 @@ static struct xt_match ebt_pkttype_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_pkttype_mt, .checkentry = ebt_pkttype_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)), + .matchsize = sizeof(struct ebt_pkttype_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index c8a49f7a57ba..9be8fbcd370b 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -59,7 +59,7 @@ static struct xt_target ebt_redirect_tg_reg __read_mostly = { (1 << NF_BR_BROUTING), .target = ebt_redirect_tg, .checkentry = ebt_redirect_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)), + .targetsize = sizeof(struct ebt_redirect_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index 8d04d4c302bd..9c7b520765a2 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -67,7 +67,7 @@ static struct xt_target ebt_snat_tg_reg __read_mostly = { .hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_POST_ROUTING), .target = ebt_snat_tg, .checkentry = ebt_snat_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), + .targetsize = sizeof(struct ebt_nat_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 75e29a9cebda..92a93d363765 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -177,7 +177,7 @@ static struct xt_match ebt_stp_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_stp_mt, .checkentry = ebt_stp_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)), + .matchsize = sizeof(struct ebt_stp_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ce50688a6431..c6ac657074a6 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -275,7 +275,7 @@ static struct xt_target ebt_ulog_tg_reg __read_mostly = { .family = NFPROTO_BRIDGE, .target = ebt_ulog_tg, .checkentry = ebt_ulog_tg_check, - .targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)), + .targetsize = sizeof(struct ebt_ulog_info), .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index 3dddd489328e..be1dd2e1f615 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c @@ -163,7 +163,7 @@ static struct xt_match ebt_vlan_mt_reg __read_mostly = { .family = NFPROTO_BRIDGE, .match = ebt_vlan_mt, .checkentry = ebt_vlan_mt_check, - .matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)), + .matchsize = sizeof(struct ebt_vlan_info), .me = THIS_MODULE, }; -- GitLab From 3e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 15 Feb 2010 18:17:10 +0100 Subject: [PATCH 2077/3892] netfilter: CONFIG_COMPAT: allow delta to exceed 32767 with 32 bit userland and 64 bit kernels, it is unlikely but possible that insertion of new rules fails even tough there are only about 2000 iptables rules. This happens because the compat delta is using a short int. Easily reproducible via "iptables -m limit" ; after about 2050 rules inserting new ones fails with -ELOOP. Note that compat_delta included 2 bytes of padding on x86_64, so structure size remains the same. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 2 +- net/netfilter/x_tables.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index c61758f4be31..a18119fb88f0 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -588,7 +588,7 @@ extern void xt_compat_unlock(u_int8_t af); extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta); extern void xt_compat_flush_offsets(u_int8_t af); -extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset); +extern int xt_compat_calc_jump(u_int8_t af, unsigned int offset); extern int xt_compat_match_offset(const struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 69c56287d518..0a12cedfe9e3 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -39,7 +39,7 @@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); struct compat_delta { struct compat_delta *next; unsigned int offset; - short delta; + int delta; }; struct xt_af { @@ -439,10 +439,10 @@ void xt_compat_flush_offsets(u_int8_t af) } EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); -short xt_compat_calc_jump(u_int8_t af, unsigned int offset) +int xt_compat_calc_jump(u_int8_t af, unsigned int offset) { struct compat_delta *tmp; - short delta; + int delta; for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) if (tmp->offset < offset) -- GitLab From 9556175183ddf19e9a7afa449c259a0a5081fa29 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:26:51 -0800 Subject: [PATCH 2078/3892] omap2/3: Make get_irqnr_and_base common for mach-omap2 multiboot Make get_irqnr_and_base common for mach-omap2 multiboot Thanks to a tip from Russell King , this also optimizes the code for non-multiboot configurations by using get_irqnr_preamble. Note that this will only work currently for 24xx and 34xx. Support for 44xx can be added later on for basic multiboot, and similar patch should be done for mach-omap1/entry-macro.S. Signed-off-by: Tony Lindgren --- .../arm/mach-omap2/include/mach/entry-macro.S | 77 ++++++++++++++----- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index c7f1720bf282..4fd6b1bdcb2b 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -17,47 +17,84 @@ #include #include - -/* REVISIT: This should be set dynamically if CONFIG_MULTI_OMAP2 is selected */ -#if defined(CONFIG_ARCH_OMAP2420) || defined(CONFIG_ARCH_OMAP2430) -#define OMAP2_VA_IC_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE) -#elif defined(CONFIG_ARCH_OMAP34XX) -#define OMAP2_VA_IC_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) -#endif -#if defined(CONFIG_ARCH_OMAP4) #include -#endif -#define INTCPS_SIR_IRQ_OFFSET 0x0040 /* Active interrupt offset */ -#define ACTIVEIRQ_MASK 0x7f /* Active interrupt bits */ .macro disable_fiq .endm - .macro get_irqnr_preamble, base, tmp - .endm - .macro arch_ret_to_user, tmp1, tmp2 .endm -#ifndef CONFIG_ARCH_OMAP4 +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) + +#define OMAP2_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE) +#define OMAP3_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) +#define INTCPS_SIR_IRQ_OFFSET 0x0040 /* Active interrupt offset */ +#define ACTIVEIRQ_MASK 0x7f /* Active interrupt bits */ + + .pushsection .data +omap_irq_base: .word 0 + .popsection + +#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_ARCH_OMAP3) + /* Configure the interrupt base on the first interrupt */ + .macro get_irqnr_preamble, base, tmp +9: + ldr \base, =omap_irq_base @ irq base address + ldr \base, [\base, #0] @ irq base value + cmp \base, #0 @ already configured? + bne 9998f @ nothing to do + + mrc p15, 0, \tmp, c0, c0, 0 @ get processor revision + and \tmp, \tmp, #0x000f0000 @ only check architecture + cmp \tmp, #0x00060000 @ is v6? + beq 2400f @ found v6 so it's omap24xx + cmp \tmp, #0x000f0000 @ is cortex? + beq 3400f @ found v7 so it's omap34xx +2400: ldr \base, =OMAP2_IRQ_BASE + ldr \tmp, =omap_irq_base + str \base, [\tmp, #0] + b 9b +3400: ldr \base, =OMAP3_IRQ_BASE + ldr \tmp, =omap_irq_base + str \base, [\tmp, #0] + b 9b +9998: + .endm +#else + .macro get_irqnr_preamble, base, tmp +#ifdef CONFIG_ARCH_OMAP2 + ldr \base, =OMAP2_IRQ_BASE +#else + ldr \base, =OMAP3_IRQ_BASE +#endif + .endm +#endif + /* Check the pending interrupts. Note that base already set */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =OMAP2_VA_IC_BASE ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */ cmp \irqnr, #0x0 - bne 2222f + bne 9999f ldr \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */ cmp \irqnr, #0x0 - bne 2222f + bne 9999f ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */ cmp \irqnr, #0x0 -2222: +9999: ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET] and \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */ .endm -#else +#endif + + +#ifdef CONFIG_ARCH_OMAP4 + #define OMAP44XX_VA_GIC_CPU_BASE OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE) + .macro get_irqnr_preamble, base, tmp + .endm + /* * The interrupt numbering scheme is defined in the * interrupt controller spec. To wit: -- GitLab From 56213ca4e440c0b6e56a48f5901c55c4ce3cf1ba Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:46 -0800 Subject: [PATCH 2079/3892] omap2/3: Multiboot compile fixes to compile in omap2 and omap3 Allows compiling in omap2 and omap3. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 8 ++++++++ arch/arm/mach-omap2/clock.h | 26 ++++++++++++++++++++++++++ arch/arm/mach-omap2/opp2xxx.h | 5 +++++ arch/arm/plat-omap/Kconfig | 16 ++++++++++++---- arch/arm/plat-omap/gpio.c | 2 +- 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 34c2867e0f63..f6f151c4f089 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -34,6 +34,10 @@ obj-$(CONFIG_ARCH_OMAP2420) += sram242x.o obj-$(CONFIG_ARCH_OMAP2430) += sram243x.o obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o +AFLAGS_sram242x.o :=-Wa,-march=armv6 +AFLAGS_sram243x.o :=-Wa,-march=armv6 +AFLAGS_sram34xx.o :=-Wa,-march=armv7-a + # Pin multiplexing obj-$(CONFIG_ARCH_OMAP3) += mux34xx.o @@ -47,6 +51,10 @@ obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o + +AFLAGS_sleep24xx.o :=-Wa,-march=armv6 +AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a + endif # PRCM diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 7bc344bcbb47..a6e85f46a65c 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -83,6 +83,32 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); u32 omap2_get_dpll_rate(struct clk *clk); void omap2_init_dpll_parent(struct clk *clk); int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); + + +#ifdef CONFIG_ARCH_OMAP2 +void omap2xxx_clk_prepare_for_reboot(void); +#else +static inline void omap2xxx_clk_prepare_for_reboot(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP3 +void omap3_clk_prepare_for_reboot(void); +#else +static inline void omap3_clk_prepare_for_reboot(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP4 +void omap4_clk_prepare_for_reboot(void); +#else +static inline void omap4_clk_prepare_for_reboot(void) +{ +} +#endif + int omap2_dflt_clk_enable(struct clk *clk); void omap2_dflt_clk_disable(struct clk *clk); void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, diff --git a/arch/arm/mach-omap2/opp2xxx.h b/arch/arm/mach-omap2/opp2xxx.h index ed6df04e2f29..38b730550506 100644 --- a/arch/arm/mach-omap2/opp2xxx.h +++ b/arch/arm/mach-omap2/opp2xxx.h @@ -417,7 +417,12 @@ struct prcm_config { extern const struct prcm_config omap2420_rate_table[]; + +#ifdef CONFIG_ARCH_OMAP2430 extern const struct prcm_config omap2430_rate_table[]; +#else +#define omap2430_rate_table NULL +#endif extern const struct prcm_config *rate_table; extern const struct prcm_config *curr_prcm_set; diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 484d6a91524f..f195457d1b03 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -7,27 +7,35 @@ config ARCH_OMAP_OTG choice prompt "OMAP System Type" - default ARCH_OMAP1 + default ARCH_OMAP2PLUS config ARCH_OMAP1 bool "TI OMAP1" select COMMON_CLKDEV + help + "Systems based on omap7xx, omap15xx or omap16xx" + +config ARCH_OMAP2PLUS + bool "TI OMAP2/3/4" + select COMMON_CLKDEV + help + "Systems based on omap24xx, omap34xx or omap44xx" config ARCH_OMAP2 bool "TI OMAP2" + depends on ARCH_OMAP2PLUS select CPU_V6 - select COMMON_CLKDEV config ARCH_OMAP3 bool "TI OMAP3" + depends on ARCH_OMAP2PLUS select CPU_V7 - select COMMON_CLKDEV config ARCH_OMAP4 bool "TI OMAP4" + depends on ARCH_OMAP2PLUS select CPU_V7 select ARM_GIC - select COMMON_CLKDEV endchoice diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index d2422c766cca..c09b3d9bcd3b 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1630,7 +1630,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset) /*---------------------------------------------------------------------*/ static int initialized; -#if !(defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)) +#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2) static struct clk * gpio_ick; #endif -- GitLab From 882c0518e5317a41834d0fceee07ae6ada2d7429 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:46 -0800 Subject: [PATCH 2080/3892] omap: Fix dmtimer.c for multi-omap boot Fix dmtimer.c for multi-omap boot. Also remove legacy clk_enable/disable wrappers that are no longer needed. Note that the clock handling should be further improved to make use of the clock aliases. Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 90 ++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 08ccf8922520..c588cdf35db1 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -163,20 +163,9 @@ struct omap_dm_timer { unsigned posted:1; }; -#ifdef CONFIG_ARCH_OMAP1 - -#define omap_dm_clk_enable(x) -#define omap_dm_clk_disable(x) -#define omap2_dm_timers NULL -#define omap2_dm_source_names NULL -#define omap2_dm_source_clocks NULL -#define omap3_dm_timers NULL -#define omap3_dm_source_names NULL -#define omap3_dm_source_clocks NULL -#define omap4_dm_timers NULL -#define omap4_dm_source_names NULL -#define omap4_dm_source_clocks NULL +static int dm_timer_count; +#ifdef CONFIG_ARCH_OMAP1 static struct omap_dm_timer omap1_dm_timers[] = { { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, @@ -188,20 +177,14 @@ static struct omap_dm_timer omap1_dm_timers[] = { { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 }, }; -static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers); - -#elif defined(CONFIG_ARCH_OMAP2) +static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers); -#define omap_dm_clk_enable(x) clk_enable(x) -#define omap_dm_clk_disable(x) clk_disable(x) +#else #define omap1_dm_timers NULL -#define omap3_dm_timers NULL -#define omap3_dm_source_names NULL -#define omap3_dm_source_clocks NULL -#define omap4_dm_timers NULL -#define omap4_dm_source_names NULL -#define omap4_dm_source_clocks NULL +#define omap1_dm_timer_count 0 +#endif /* CONFIG_ARCH_OMAP1 */ +#ifdef CONFIG_ARCH_OMAP2 static struct omap_dm_timer omap2_dm_timers[] = { { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, @@ -225,20 +208,16 @@ static const char *omap2_dm_source_names[] __initdata = { }; static struct clk *omap2_dm_source_clocks[3]; -static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers); - -#elif defined(CONFIG_ARCH_OMAP3) +static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers); -#define omap_dm_clk_enable(x) clk_enable(x) -#define omap_dm_clk_disable(x) clk_disable(x) -#define omap1_dm_timers NULL +#else #define omap2_dm_timers NULL +#define omap2_dm_timer_count 0 #define omap2_dm_source_names NULL #define omap2_dm_source_clocks NULL -#define omap4_dm_timers NULL -#define omap4_dm_source_names NULL -#define omap4_dm_source_clocks NULL +#endif /* CONFIG_ARCH_OMAP2 */ +#ifdef CONFIG_ARCH_OMAP3 static struct omap_dm_timer omap3_dm_timers[] = { { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 }, { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 }, @@ -261,20 +240,16 @@ static const char *omap3_dm_source_names[] __initdata = { }; static struct clk *omap3_dm_source_clocks[2]; -static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers); - -#elif defined(CONFIG_ARCH_OMAP4) +static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers); -#define omap_dm_clk_enable(x) clk_enable(x) -#define omap_dm_clk_disable(x) clk_disable(x) -#define omap1_dm_timers NULL -#define omap2_dm_timers NULL -#define omap2_dm_source_names NULL -#define omap2_dm_source_clocks NULL +#else #define omap3_dm_timers NULL +#define omap3_dm_timer_count 0 #define omap3_dm_source_names NULL #define omap3_dm_source_clocks NULL +#endif /* CONFIG_ARCH_OMAP3 */ +#ifdef CONFIG_ARCH_OMAP4 static struct omap_dm_timer omap4_dm_timers[] = { { .phys_base = 0x4a318000, .irq = INT_44XX_GPTIMER1 }, { .phys_base = 0x48032000, .irq = INT_44XX_GPTIMER2 }, @@ -295,13 +270,14 @@ static const char *omap4_dm_source_names[] __initdata = { NULL }; static struct clk *omap4_dm_source_clocks[2]; -static const int dm_timer_count = ARRAY_SIZE(omap4_dm_timers); +static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers); #else - -#error OMAP architecture not supported! - -#endif +#define omap4_dm_timers NULL +#define omap4_dm_timer_count 0 +#define omap4_dm_source_names NULL +#define omap4_dm_source_clocks NULL +#endif /* CONFIG_ARCH_OMAP4 */ static struct omap_dm_timer *dm_timers; static const char **dm_source_names; @@ -450,8 +426,12 @@ void omap_dm_timer_enable(struct omap_dm_timer *timer) if (timer->enabled) return; - omap_dm_clk_enable(timer->fclk); - omap_dm_clk_enable(timer->iclk); +#ifdef CONFIG_ARCH_OMAP2PLUS + if (cpu_class_is_omap2()) { + clk_enable(timer->fclk); + clk_enable(timer->iclk); + } +#endif timer->enabled = 1; } @@ -462,8 +442,12 @@ void omap_dm_timer_disable(struct omap_dm_timer *timer) if (!timer->enabled) return; - omap_dm_clk_disable(timer->iclk); - omap_dm_clk_disable(timer->fclk); +#ifdef CONFIG_ARCH_OMAP2PLUS + if (cpu_class_is_omap2()) { + clk_disable(timer->iclk); + clk_disable(timer->fclk); + } +#endif timer->enabled = 0; } @@ -764,17 +748,21 @@ int __init omap_dm_timer_init(void) if (cpu_class_is_omap1()) { dm_timers = omap1_dm_timers; + dm_timer_count = omap1_dm_timer_count; map_size = SZ_2K; } else if (cpu_is_omap24xx()) { dm_timers = omap2_dm_timers; + dm_timer_count = omap2_dm_timer_count; dm_source_names = omap2_dm_source_names; dm_source_clocks = omap2_dm_source_clocks; } else if (cpu_is_omap34xx()) { dm_timers = omap3_dm_timers; + dm_timer_count = omap3_dm_timer_count; dm_source_names = omap3_dm_source_names; dm_source_clocks = omap3_dm_source_clocks; } else if (cpu_is_omap44xx()) { dm_timers = omap4_dm_timers; + dm_timer_count = omap4_dm_timer_count; dm_source_names = omap4_dm_source_names; dm_source_clocks = omap4_dm_source_clocks; } -- GitLab From 6fbd55d077cdf2aeb7a170ff9f5779d19506bf9e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:47 -0800 Subject: [PATCH 2081/3892] omap2/3/4: Fix omap2_map_common_io for multi-omap Fix omap2_map_common_io for multi-omap Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-2430sdp.c | 2 +- arch/arm/mach-omap2/board-3430sdp.c | 2 +- arch/arm/mach-omap2/board-3630sdp.c | 2 +- arch/arm/mach-omap2/board-4430sdp.c | 2 +- arch/arm/mach-omap2/board-am3517evm.c | 2 +- arch/arm/mach-omap2/board-apollon.c | 2 +- arch/arm/mach-omap2/board-cm-t35.c | 2 +- arch/arm/mach-omap2/board-generic.c | 2 +- arch/arm/mach-omap2/board-h4.c | 2 +- arch/arm/mach-omap2/board-igep0020.c | 2 +- arch/arm/mach-omap2/board-ldp.c | 2 +- arch/arm/mach-omap2/board-n8x0.c | 2 +- arch/arm/mach-omap2/board-omap3beagle.c | 2 +- arch/arm/mach-omap2/board-omap3evm.c | 2 +- arch/arm/mach-omap2/board-omap3pandora.c | 2 +- arch/arm/mach-omap2/board-omap3touchbook.c | 2 +- arch/arm/mach-omap2/board-overo.c | 2 +- arch/arm/mach-omap2/board-rx51.c | 2 +- arch/arm/mach-omap2/board-zoom2.c | 2 +- arch/arm/mach-omap2/board-zoom3.c | 2 +- arch/arm/mach-omap2/io.c | 51 ++++++++++++++-------- arch/arm/plat-omap/include/plat/io.h | 33 +++++++++++++- 22 files changed, 86 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index e508904fb67e..1a619787bd80 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -215,7 +215,7 @@ static void __init omap_2430sdp_init(void) static void __init omap_2430sdp_map_io(void) { omap2_set_globals_243x(); - omap2_map_common_io(); + omap243x_map_common_io(); } MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board") diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index c90b0d0b1927..eda4f6448cce 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -674,7 +674,7 @@ static void __init omap_3430sdp_init(void) static void __init omap_3430sdp_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board") diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index c178e68472f8..4386d2b4a785 100755 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -69,7 +69,7 @@ static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = { static void __init omap_sdp_map_io(void) { omap2_set_globals_36xx(); - omap2_map_common_io(); + omap34xx_map_common_io(); } static struct omap_board_config_kernel sdp_config[] __initdata = { diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 0c6be6b4a7e2..cc4c00de32b3 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -87,7 +87,7 @@ static void __init omap_4430sdp_init(void) static void __init omap_4430sdp_map_io(void) { omap2_set_globals_443x(); - omap2_map_common_io(); + omap44xx_map_common_io(); } MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 54af5f8d8184..07b857de2500 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -228,7 +228,7 @@ static void __init am3517_evm_init(void) static void __init am3517_evm_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM") diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index fbbd68d69cc8..aa69fb999748 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -337,7 +337,7 @@ static void __init omap_apollon_init(void) static void __init omap_apollon_map_io(void) { omap2_set_globals_242x(); - omap2_map_common_io(); + omap242x_map_common_io(); } MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon") diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 85b45437d51a..0e292317c0ca 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -710,7 +710,7 @@ static void __init cm_t35_init_irq(void) static void __init cm_t35_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } static struct omap_board_mux board_mux[] __initdata = { diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 7e6e6ca88be5..16cc06860670 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -50,7 +50,7 @@ static void __init omap_generic_init(void) static void __init omap_generic_map_io(void) { omap2_set_globals_242x(); /* should be 242x, 243x, or 343x */ - omap2_map_common_io(); + omap242x_map_common_io(); } MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx") diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index cfb7f1257d20..5c49c407dd51 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -370,7 +370,7 @@ static void __init omap_h4_init(void) static void __init omap_h4_map_io(void) { omap2_set_globals_242x(); - omap2_map_common_io(); + omap242x_map_common_io(); } MACHINE_START(OMAP_H4, "OMAP2420 H4 board") diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 117b8fd7e3a6..9f7543384498 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -246,7 +246,7 @@ static void __init igep2_init(void) static void __init igep2_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(IGEP0020, "IGEP v2 board") diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index 995d4a2b2dfd..f1699674a2fc 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -404,7 +404,7 @@ static void __init omap_ldp_init(void) static void __init omap_ldp_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP_LDP, "OMAP LDP board") diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 764ab1ed576d..9de03f8e2e68 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -99,7 +99,7 @@ static void __init n8x0_onenand_init(void) {} static void __init n8x0_map_io(void) { omap2_set_globals_242x(); - omap2_map_common_io(); + omap242x_map_common_io(); } static void __init n8x0_init_irq(void) diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 231cb4ec1847..bf91bf7bd921 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -455,7 +455,7 @@ static void __init omap3_beagle_init(void) static void __init omap3_beagle_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 822df79ce891..a221b7a1fcc6 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -702,7 +702,7 @@ static void __init omap3_evm_init(void) static void __init omap3_evm_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP3EVM, "OMAP3 EVM") diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index ef17cf1ab6d7..bc482abdd5d4 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -423,7 +423,7 @@ static void __init omap3pandora_init(void) static void __init omap3pandora_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console") diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index fe3d22cb2457..63436e9c2069 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -557,7 +557,7 @@ static void __init omap3_touchbook_init(void) static void __init omap3_touchbook_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board") diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index d192dd98a591..61abe0907265 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -469,7 +469,7 @@ static void __init overo_init(void) static void __init overo_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OVERO, "Gumstix Overo") diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 67bb3476b707..6a49f916103d 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -93,7 +93,7 @@ static void __init rx51_init(void) static void __init rx51_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(NOKIA_RX51, "Nokia RX-51 board") diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c index bb87cf7878ff..9a26f84b1141 100644 --- a/arch/arm/mach-omap2/board-zoom2.c +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -87,7 +87,7 @@ static void __init omap_zoom2_init(void) static void __init omap_zoom2_map_io(void) { omap2_set_globals_343x(); - omap2_map_common_io(); + omap34xx_map_common_io(); } MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board") diff --git a/arch/arm/mach-omap2/board-zoom3.c b/arch/arm/mach-omap2/board-zoom3.c index 456b69072679..5e208942ca71 100644 --- a/arch/arm/mach-omap2/board-zoom3.c +++ b/arch/arm/mach-omap2/board-zoom3.c @@ -27,7 +27,7 @@ static void __init omap_zoom_map_io(void) { omap2_set_globals_36xx(); - omap2_map_common_io(); + omap34xx_map_common_io(); } static struct omap_board_config_kernel zoom_config[] __initdata = { diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 01ef2ae93593..31296cbecb0b 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -236,37 +236,54 @@ static struct map_desc omap44xx_io_desc[] __initdata = { }; #endif -void __init omap2_map_common_io(void) +static void __init _omap2_map_common_io(void) +{ + /* Normally devicemaps_init() would flush caches and tlb after + * mdesc->map_io(), but we must also do it here because of the CPU + * revision check below. + */ + local_flush_tlb_all(); + flush_cache_all(); + + omap2_check_revision(); + omap_sram_init(); + omapfb_reserve_sdram(); + omap_vram_reserve_sdram(); +} + +#ifdef CONFIG_ARCH_OMAP2420 +void __init omap242x_map_common_io() { -#if defined(CONFIG_ARCH_OMAP2420) iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc)); + _omap2_map_common_io(); +} #endif -#if defined(CONFIG_ARCH_OMAP2430) +#ifdef CONFIG_ARCH_OMAP2430 +void __init omap243x_map_common_io() +{ iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc)); iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc)); + _omap2_map_common_io(); +} #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#ifdef CONFIG_ARCH_OMAP34XX +void __init omap34xx_map_common_io() +{ iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc)); + _omap2_map_common_io(); +} #endif -#if defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP4 +void __init omap44xx_map_common_io() +{ iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc)); -#endif - /* Normally devicemaps_init() would flush caches and tlb after - * mdesc->map_io(), but we must also do it here because of the CPU - * revision check below. - */ - local_flush_tlb_all(); - flush_cache_all(); - - omap2_check_revision(); - omap_sram_init(); - omapfb_reserve_sdram(); - omap_vram_reserve_sdram(); + _omap2_map_common_io(); } +#endif /* * omap2_init_reprogram_sdrc - reprogram SDRC timing parameters diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h index a3e7b471bcba..19257bbbc9f3 100644 --- a/arch/arm/plat-omap/include/plat/io.h +++ b/arch/arm/plat-omap/include/plat/io.h @@ -268,7 +268,38 @@ struct omap_sdrc_params; extern void omap1_map_common_io(void); extern void omap1_init_common_hw(void); -extern void omap2_map_common_io(void); +#ifdef CONFIG_ARCH_OMAP2420 +extern void omap242x_map_common_io(void); +#else +static inline void omap242x_map_common_io(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP2430 +extern void omap243x_map_common_io(void); +#else +static inline void omap243x_map_common_io(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP34XX +extern void omap34xx_map_common_io(void); +#else +static inline void omap34xx_map_common_io(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP4 +extern void omap44xx_map_common_io(void); +#else +static inline void omap44xx_map_common_io(void) +{ +} +#endif + extern void omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, struct omap_sdrc_params *sdrc_cs1); -- GitLab From d10f2b6e745f1232ff6517b335faf3bfd7005bec Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:47 -0800 Subject: [PATCH 2082/3892] omap2/3/4: Fix mbox init for multi-omap Fix mbox init for multi-omap Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 18ad93160abb..935e36c3a5e9 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -141,7 +141,7 @@ static inline void omap_init_camera(void) #define MBOX_REG_SIZE 0x120 #ifdef CONFIG_ARCH_OMAP2 -static struct resource omap_mbox_resources[] = { +static struct resource omap2_mbox_resources[] = { { .start = OMAP24XX_MAILBOX_BASE, .end = OMAP24XX_MAILBOX_BASE + MBOX_REG_SIZE - 1, @@ -156,10 +156,14 @@ static struct resource omap_mbox_resources[] = { .flags = IORESOURCE_IRQ, }, }; +static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources); +#else +#define omap2_mbox_resources NULL +#define omap2_mbox_resources_sz 0 #endif #ifdef CONFIG_ARCH_OMAP3 -static struct resource omap_mbox_resources[] = { +static struct resource omap3_mbox_resources[] = { { .start = OMAP34XX_MAILBOX_BASE, .end = OMAP34XX_MAILBOX_BASE + MBOX_REG_SIZE - 1, @@ -170,12 +174,16 @@ static struct resource omap_mbox_resources[] = { .flags = IORESOURCE_IRQ, }, }; +static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources); +#else +#define omap3_mbox_resources NULL +#define omap3_mbox_resources_sz 0 #endif #ifdef CONFIG_ARCH_OMAP4 #define OMAP4_MBOX_REG_SIZE 0x130 -static struct resource omap_mbox_resources[] = { +static struct resource omap4_mbox_resources[] = { { .start = OMAP44XX_MAILBOX_BASE, .end = OMAP44XX_MAILBOX_BASE + @@ -187,6 +195,10 @@ static struct resource omap_mbox_resources[] = { .flags = IORESOURCE_IRQ, }, }; +static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources); +#else +#define omap4_mbox_resources NULL +#define omap4_mbox_resources_sz 0 #endif static struct platform_device mbox_device = { @@ -196,9 +208,15 @@ static struct platform_device mbox_device = { static inline void omap_init_mbox(void) { - if (cpu_is_omap2420() || cpu_is_omap3430() || cpu_is_omap44xx()) { - mbox_device.num_resources = ARRAY_SIZE(omap_mbox_resources); - mbox_device.resource = omap_mbox_resources; + if (cpu_is_omap24xx()) { + mbox_device.resource = omap2_mbox_resources; + mbox_device.num_resources = omap2_mbox_resources_sz; + } else if (cpu_is_omap34xx()) { + mbox_device.resource = omap3_mbox_resources; + mbox_device.num_resources = omap3_mbox_resources_sz; + } else if (cpu_is_omap44xx()) { + mbox_device.resource = omap4_mbox_resources; + mbox_device.num_resources = omap4_mbox_resources_sz; } else { pr_err("%s: platform not supported\n", __func__); return; -- GitLab From 088ef950dc0dd58d2f339e1616c9092fea923f06 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:47 -0800 Subject: [PATCH 2083/3892] omap2: Convert ARCH_OMAP24XX to ARCH_OMAP2 Convert ARCH_OMAP24XX to ARCH_OMAP2 Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 16 +++---- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clock.h | 2 +- arch/arm/mach-omap2/clockdomains.h | 2 +- arch/arm/mach-omap2/io.c | 2 +- arch/arm/mach-omap2/mux.c | 2 +- arch/arm/mach-omap2/powerdomains24xx.h | 4 +- arch/arm/plat-omap/Kconfig | 4 +- arch/arm/plat-omap/devices.c | 2 +- arch/arm/plat-omap/gpio.c | 56 +++++++++++----------- arch/arm/plat-omap/i2c.c | 4 +- arch/arm/plat-omap/include/plat/cpu.h | 8 ++-- arch/arm/plat-omap/include/plat/mcbsp.h | 2 +- arch/arm/plat-omap/include/plat/menelaus.h | 2 +- arch/arm/plat-omap/include/plat/mux.h | 2 +- arch/arm/plat-omap/include/plat/omap24xx.h | 6 +-- arch/arm/plat-omap/sram.c | 2 +- drivers/char/hw_random/Kconfig | 2 +- drivers/mfd/Kconfig | 2 +- drivers/net/smc911x.h | 2 +- drivers/spi/Kconfig | 2 +- drivers/watchdog/Kconfig | 2 +- sound/soc/omap/omap-mcbsp.c | 2 +- 23 files changed, 63 insertions(+), 67 deletions(-) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 606bf04f51b6..69a6b2baabfe 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -1,19 +1,15 @@ comment "OMAP Core Type" depends on ARCH_OMAP2 -config ARCH_OMAP24XX - bool "OMAP24xx Based System" - depends on ARCH_OMAP2 - config ARCH_OMAP2420 bool "OMAP2420 support" - depends on ARCH_OMAP24XX + depends on ARCH_OMAP2 select OMAP_DM_TIMER select ARCH_OMAP_OTG config ARCH_OMAP2430 bool "OMAP2430 support" - depends on ARCH_OMAP24XX + depends on ARCH_OMAP2 config ARCH_OMAP34XX bool "OMAP34xx Based System" @@ -42,7 +38,7 @@ comment "OMAP Board Type" config MACH_OMAP_GENERIC bool "Generic OMAP board" - depends on ARCH_OMAP2 && ARCH_OMAP24XX + depends on ARCH_OMAP2 config MACH_OMAP2_TUSB6010 bool @@ -51,16 +47,16 @@ config MACH_OMAP2_TUSB6010 config MACH_OMAP_H4 bool "OMAP 2420 H4 board" - depends on ARCH_OMAP2 && ARCH_OMAP24XX + depends on ARCH_OMAP2 select OMAP_DEBUG_DEVICES config MACH_OMAP_APOLLON bool "OMAP 2420 Apollon board" - depends on ARCH_OMAP2 && ARCH_OMAP24XX + depends on ARCH_OMAP2 config MACH_OMAP_2430SDP bool "OMAP 2430 SDP board" - depends on ARCH_OMAP2 && ARCH_OMAP24XX + depends on ARCH_OMAP2 config MACH_OMAP3_BEAGLE bool "OMAP3 BEAGLE board" diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index f6f151c4f089..492cf164e000 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o # Power Management ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o -obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o +obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index a6e85f46a65c..fcb99cce5fc8 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -129,7 +129,7 @@ extern const struct clksel_rate gpt_32k_rates[]; extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; -#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_CPU_FREQ) +#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); #else diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 7db6298493fd..8fc19ff2cd89 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -84,7 +84,7 @@ static struct clkdm_dep gfx_sgx_wkdeps[] = { /* 24XX-specific possible dependencies */ -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 /* Wakeup dependency source arrays */ diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 31296cbecb0b..103fc0915fb9 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -55,7 +55,7 @@ * default mapping provided here. */ -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 static struct map_desc omap24xx_io_desc[] __initdata = { { .virtual = L3_24XX_VIRT, diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 5fedc50c58e4..fa7c8dad35ef 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -75,7 +75,7 @@ void omap_mux_write_array(struct omap_board_mux *board_mux) } } -#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_OMAP_MUX) +#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_OMAP_MUX) static struct omap_mux_cfg arch_mux_cfg; diff --git a/arch/arm/mach-omap2/powerdomains24xx.h b/arch/arm/mach-omap2/powerdomains24xx.h index 652a01b729e9..775093add9b6 100644 --- a/arch/arm/mach-omap2/powerdomains24xx.h +++ b/arch/arm/mach-omap2/powerdomains24xx.h @@ -30,7 +30,7 @@ /* 24XX powerdomains and dependencies */ -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 /* Powerdomains */ @@ -82,7 +82,7 @@ static struct powerdomain core_24xx_pwrdm = { }, }; -#endif /* CONFIG_ARCH_OMAP24XX */ +#endif /* CONFIG_ARCH_OMAP2 */ diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index f195457d1b03..df497fc33f2b 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -124,7 +124,7 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX || ARCH_OMAP4 help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has @@ -145,7 +145,7 @@ config OMAP_32K_TIMER_HZ config OMAP_DM_TIMER bool "Use dual-mode timer" - depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX || ARCH_OMAP4 help Select this option if you want to use OMAP Dual-Mode timers. diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 30b5db73017a..59f92c8bfc6d 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -244,7 +244,7 @@ fail: #if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE) -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 #define OMAP_RNG_BASE 0x480A0000 #else #define OMAP_RNG_BASE 0xfffe5000 diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index c09b3d9bcd3b..0fb0e58fec93 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -177,12 +177,12 @@ struct gpio_bank { u16 irq; u16 virtual_irq_start; int method; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \ +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) u32 suspend_wakeup; u32 saved_wakeup; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -248,7 +248,7 @@ static struct gpio_bank gpio_bank_7xx[7] = { }; #endif -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 static struct gpio_bank gpio_bank_242x[4] = { { OMAP242X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, @@ -426,7 +426,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) reg += OMAP7XX_GPIO_DIR_CONTROL; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_OE; break; @@ -493,7 +493,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) l &= ~(1 << gpio); break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETDATAOUT; @@ -546,7 +546,7 @@ static int _get_gpio_datain(struct gpio_bank *bank, int gpio) reg += OMAP7XX_GPIO_DATA_INPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAIN; break; @@ -592,7 +592,7 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) reg += OMAP7XX_GPIO_DATA_OUTPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAOUT; @@ -684,7 +684,7 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time) } EXPORT_SYMBOL(omap_set_gpio_debounce_time); -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) @@ -856,7 +856,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) goto bad; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: set_24xx_gpio_triggering(bank, gpio, trigger); @@ -937,7 +937,7 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) reg += OMAP7XX_GPIO_INT_STATUS; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQSTATUS1; break; @@ -954,7 +954,7 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; #endif #if defined(CONFIG_ARCH_OMAP4) @@ -1008,7 +1008,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) inv = 1; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; mask = 0xffffffff; @@ -1077,7 +1077,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab l |= gpio_mask; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETIRQENABLE1; @@ -1131,7 +1131,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_unlock_irqrestore(&bank->lock, flags); return 0; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: if (bank->non_wakeup_gpios & (1 << gpio)) { @@ -1227,7 +1227,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) __raw_writel(1 << offset, reg); } #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) if (bank->method == METHOD_GPIO_24XX) { /* Disable wake-up during idle for dynamic tick */ @@ -1286,7 +1286,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->method == METHOD_GPIO_7XX) isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif @@ -1756,7 +1756,7 @@ static int __init _omap_gpio_init(void) bank_size = SZ_2K; } #endif -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 if (cpu_is_omap242x()) { gpio_bank_count = 4; gpio_bank = gpio_bank_242x; @@ -1809,7 +1809,7 @@ static int __init _omap_gpio_init(void) gpio_count = 32; /* 7xx has 32-bit GPIOs */ } -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) if (bank->method == METHOD_GPIO_24XX) { static const u32 non_wakeup_gpios[] = { @@ -1903,7 +1903,7 @@ static int __init _omap_gpio_init(void) return 0; } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \ +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) { @@ -1927,7 +1927,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN; wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; @@ -1975,7 +1975,7 @@ static int omap_gpio_resume(struct sys_device *dev) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; @@ -2013,7 +2013,7 @@ static struct sys_device omap_gpio_device = { #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) static int workaround_enabled; @@ -2030,7 +2030,7 @@ void omap2_gpio_prepare_for_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); @@ -2045,7 +2045,7 @@ void omap2_gpio_prepare_for_retention(void) bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); #endif @@ -2074,7 +2074,7 @@ void omap2_gpio_resume_after_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) __raw_writel(bank->saved_fallingdetect, bank->base + OMAP24XX_GPIO_FALLINGDETECT); __raw_writel(bank->saved_risingdetect, @@ -2113,7 +2113,7 @@ void omap2_gpio_resume_after_retention(void) if (gen) { u32 old0, old1; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); __raw_writel(old0 | gen, bank->base + @@ -2240,7 +2240,7 @@ static int __init omap_gpio_sysinit(void) mpuio_init(); -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \ +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) if (cpu_is_omap16xx() || cpu_class_is_omap2()) { if (ret == 0) { @@ -2300,7 +2300,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) /* FIXME for at least omap2, show pullup/pulldown state */ irqstat = irq_desc[irq].status; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \ +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) if (is_in && ((bank->suspend_wakeup & mask) || irqstat & IRQ_TYPE_SENSE_MASK)) { diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 33fff4ef382d..7773bceca442 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -50,7 +50,7 @@ static const char name[] = "i2c_omap"; static struct resource i2c_resources[][2] = { { I2C_RESOURCE_BUILDER(0, 0) }, -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) }, #endif #if defined(CONFIG_ARCH_OMAP34XX) @@ -72,7 +72,7 @@ static struct resource i2c_resources[][2] = { static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; static struct platform_device omap_i2c_devices[] = { I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), #endif #if defined(CONFIG_ARCH_OMAP34XX) diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index ccd78fd473d1..527aaae61720 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -114,7 +114,7 @@ unsigned int omap_rev(void); # define OMAP_NAME omap16xx # endif #endif -#if (defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)) +#if (defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX)) # if (defined(OMAP_NAME) || defined(MULTI_OMAP1)) # error "OMAP1 and OMAP2 can't be selected at the same time" # endif @@ -233,7 +233,7 @@ IS_OMAP_SUBCLASS(443x, 0x443) #endif #if defined(MULTI_OMAP2) -# if defined(CONFIG_ARCH_OMAP24XX) +# if defined(CONFIG_ARCH_OMAP2) # undef cpu_is_omap24xx # undef cpu_is_omap242x # undef cpu_is_omap243x @@ -248,7 +248,7 @@ IS_OMAP_SUBCLASS(443x, 0x443) # define cpu_is_omap343x() is_omap343x() # endif #else -# if defined(CONFIG_ARCH_OMAP24XX) +# if defined(CONFIG_ARCH_OMAP2) # undef cpu_is_omap24xx # define cpu_is_omap24xx() 1 # endif @@ -374,7 +374,7 @@ IS_OMAP_TYPE(3517, 0x3517) # define cpu_is_omap1710() is_omap1710() #endif -#if defined(CONFIG_ARCH_OMAP24XX) +#if defined(CONFIG_ARCH_OMAP2) # undef cpu_is_omap2420 # undef cpu_is_omap2422 # undef cpu_is_omap2423 diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 4f22e5bb7ff7..951506277ec8 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -103,7 +103,7 @@ #define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX #define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX -#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \ +#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ defined(CONFIG_ARCH_OMAP4) #define OMAP_MCBSP_REG_DRR2 0x00 diff --git a/arch/arm/plat-omap/include/plat/menelaus.h b/arch/arm/plat-omap/include/plat/menelaus.h index 3122bf68c7ce..4a970ec62dd1 100644 --- a/arch/arm/plat-omap/include/plat/menelaus.h +++ b/arch/arm/plat-omap/include/plat/menelaus.h @@ -40,7 +40,7 @@ extern int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV); extern int menelaus_set_regulator_sleep(int enable, u32 val); -#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS) +#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_MENELAUS) #define omap_has_menelaus() 1 #else #define omap_has_menelaus() 0 diff --git a/arch/arm/plat-omap/include/plat/mux.h b/arch/arm/plat-omap/include/plat/mux.h index 692c90e89ac3..c7472a28ce24 100644 --- a/arch/arm/plat-omap/include/plat/mux.h +++ b/arch/arm/plat-omap/include/plat/mux.h @@ -135,7 +135,7 @@ struct pin_config { const unsigned int mux_reg; unsigned char debug; -#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP24XX) +#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2) const unsigned char mask_offset; const unsigned char mask; diff --git a/arch/arm/plat-omap/include/plat/omap24xx.h b/arch/arm/plat-omap/include/plat/omap24xx.h index 696edfc145a6..7055672a8c68 100644 --- a/arch/arm/plat-omap/include/plat/omap24xx.h +++ b/arch/arm/plat-omap/include/plat/omap24xx.h @@ -23,8 +23,8 @@ * */ -#ifndef __ASM_ARCH_OMAP24XX_H -#define __ASM_ARCH_OMAP24XX_H +#ifndef __ASM_ARCH_OMAP2_H +#define __ASM_ARCH_OMAP2_H /* * Please place only base defines here and put the rest in device @@ -85,5 +85,5 @@ #define OMAP24XX_SEC_AES_BASE (OMAP24XX_SEC_BASE + 0x6000) #define OMAP24XX_SEC_PKA_BASE (OMAP24XX_SEC_BASE + 0x8000) -#endif /* __ASM_ARCH_OMAP24XX_H */ +#endif /* __ASM_ARCH_OMAP2_H */ diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index d8d5094b37ed..e0cbb9349bc1 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -53,7 +53,7 @@ #define OMAP4_SRAM_PUB_PA (OMAP4_SRAM_PA + 0x4000) #define OMAP4_SRAM_PUB_VA (OMAP4_SRAM_VA + 0x4000) -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) #define SRAM_BOOTLOADER_SZ 0x00 #else #define SRAM_BOOTLOADER_SZ 0x80 diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 87060266ef91..c0df30faa66a 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -114,7 +114,7 @@ config HW_RANDOM_IXP4XX config HW_RANDOM_OMAP tristate "OMAP Random Number Generator support" - depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) + depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2) default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 87829789243e..1380e1c44e4b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -94,7 +94,7 @@ config TPS65010 config MENELAUS bool "Texas Instruments TWL92330/Menelaus PM chip" - depends on I2C=y && ARCH_OMAP24XX + depends on I2C=y && ARCH_OMAP2 help If you say yes here you get support for the Texas Instruments TWL92330/Menelaus Power Management chip. This include voltage diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 05adb6a666cf..1477ff8f85f6 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -47,7 +47,7 @@ #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW #define SMC_MEM_RESERVED 1 -#elif defined(CONFIG_ARCH_OMAP24XX) +#elif defined(CONFIG_ARCH_OMAP2) #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f55eb0107336..23bd252f3a44 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -164,7 +164,7 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP24xx/OMAP34xx" - depends on ARCH_OMAP24XX || ARCH_OMAP34XX + depends on ARCH_OMAP2 || ARCH_OMAP34XX help SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI (McSPI) modules. diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 050ee147592f..b45e2896ac87 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -194,7 +194,7 @@ config EP93XX_WATCHDOG config OMAP_WATCHDOG tristate "OMAP Watchdog" - depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX help Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y' here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer. diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6bbbd2ab0ee7..26e728dc1337 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -82,7 +82,7 @@ static const int omap1_dma_reqs[][2] = {}; static const unsigned long omap1_mcbsp_port[][2] = {}; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) static const int omap24xx_dma_reqs[][2] = { { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, -- GitLab From a8eb7ca0cbb41c9cd379b8d2a2a5efb503aa65e9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:48 -0800 Subject: [PATCH 2084/3892] omap3: Replace ARCH_OMAP34XX with ARCH_OMAP3 Replace ARCH_OMAP34XX with ARCH_OMAP3 Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 37 ++++++-------- arch/arm/mach-omap2/io.c | 4 +- arch/arm/mach-omap2/mcbsp.c | 2 +- arch/arm/mach-omap2/mux.c | 4 +- arch/arm/mach-omap2/mux.h | 2 +- arch/arm/mach-omap2/omap_hwmod_34xx.h | 2 +- arch/arm/plat-omap/Kconfig | 5 +- arch/arm/plat-omap/common.c | 2 +- arch/arm/plat-omap/gpio.c | 58 +++++++++++----------- arch/arm/plat-omap/i2c.c | 8 +-- arch/arm/plat-omap/include/plat/cpu.h | 8 +-- arch/arm/plat-omap/include/plat/io.h | 2 +- arch/arm/plat-omap/include/plat/mcbsp.h | 8 +-- arch/arm/plat-omap/include/plat/omap34xx.h | 6 +-- arch/arm/plat-omap/mcbsp.c | 6 +-- arch/arm/plat-omap/sram.c | 2 +- drivers/net/smc911x.h | 2 +- drivers/spi/Kconfig | 2 +- drivers/spi/omap2_mcspi.c | 2 +- drivers/usb/Kconfig | 2 +- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/musb/Kconfig | 6 +-- drivers/usb/musb/musb_core.c | 2 +- drivers/usb/musb/musb_core.h | 2 +- drivers/w1/masters/Kconfig | 2 +- drivers/watchdog/Kconfig | 2 +- sound/soc/omap/omap-mcbsp.c | 6 +-- sound/soc/omap/omap-mcbsp.h | 2 +- 28 files changed, 92 insertions(+), 96 deletions(-) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 69a6b2baabfe..317b8cb375be 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -11,14 +11,9 @@ config ARCH_OMAP2430 bool "OMAP2430 support" depends on ARCH_OMAP2 -config ARCH_OMAP34XX - bool "OMAP34xx Based System" - depends on ARCH_OMAP3 - select USB_ARCH_HAS_EHCI - config ARCH_OMAP3430 bool "OMAP3430 support" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select ARCH_OMAP_OTG config OMAP_PACKAGE_CBC @@ -60,42 +55,42 @@ config MACH_OMAP_2430SDP config MACH_OMAP3_BEAGLE bool "OMAP3 BEAGLE board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP_LDP bool "OMAP3 LDP board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OVERO bool "Gumstix Overo board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP3EVM bool "OMAP 3530 EVM board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP3517EVM bool "OMAP3517/ AM3517 EVM board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP3_PANDORA bool "OMAP3 Pandora" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP3_TOUCHBOOK bool "OMAP3 Touch Book" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select BACKLIGHT_CLASS_DEVICE config MACH_OMAP_3430SDP bool "OMAP 3430 SDP board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_NOKIA_N800 @@ -116,33 +111,33 @@ config MACH_NOKIA_N8X0 config MACH_NOKIA_RX51 bool "Nokia RX-51 board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP_ZOOM2 bool "OMAP3 Zoom2 board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP_ZOOM3 bool "OMAP3630 Zoom3 board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBP config MACH_CM_T35 bool "CompuLab CM-T35 module" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CUS select OMAP_MUX config MACH_IGEP0020 bool "IGEP0020" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBB config MACH_OMAP_3630SDP bool "OMAP3630 SDP board" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 select OMAP_PACKAGE_CBP config MACH_OMAP_4430SDP @@ -158,7 +153,7 @@ config OMAP3_EMU config OMAP3_SDRC_AC_TIMING bool "Enable SDRC AC timing register changes" - depends on ARCH_OMAP3 && ARCH_OMAP34XX + depends on ARCH_OMAP3 default n help If you know that none of your system initiators will attempt to diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 103fc0915fb9..5a3d6f9107e4 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -125,7 +125,7 @@ static struct map_desc omap243x_io_desc[] __initdata = { #endif #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static struct map_desc omap34xx_io_desc[] __initdata = { { .virtual = L3_34XX_VIRT, @@ -269,7 +269,7 @@ void __init omap243x_map_common_io() } #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 void __init omap34xx_map_common_io() { iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc)); diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index baa451733850..4b6e5157520f 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -119,7 +119,7 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = { #define OMAP2430_MCBSP_PDATA_SZ 0 #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { { .phys_base = OMAP34XX_MCBSP1_BASE, diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index fa7c8dad35ef..5ee2372f3b42 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -369,7 +369,7 @@ int __init omap2_mux_init(void) /*----------------------------------------------------------------------------*/ -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static LIST_HEAD(muxmodes); static DEFINE_MUTEX(muxmode_mutex); @@ -1018,5 +1018,5 @@ int __init omap_mux_init(u32 mux_pbase, u32 mux_size, return 0; } -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h index f8c2e7a8f063..480abc56e605 100644 --- a/arch/arm/mach-omap2/mux.h +++ b/arch/arm/mach-omap2/mux.h @@ -102,7 +102,7 @@ struct omap_board_mux { u16 value; }; -#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_ARCH_OMAP3) /** * omap_mux_init_gpio - initialize a signal based on the GPIO number diff --git a/arch/arm/mach-omap2/omap_hwmod_34xx.h b/arch/arm/mach-omap2/omap_hwmod_34xx.h index b6076b9c364e..2e629dcb2fb1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_34xx.h +++ b/arch/arm/mach-omap2/omap_hwmod_34xx.h @@ -12,7 +12,7 @@ #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD34XX_H #define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD34XX_H -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 #include #include diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index df497fc33f2b..1e223924da8a 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -30,6 +30,7 @@ config ARCH_OMAP3 bool "TI OMAP3" depends on ARCH_OMAP2PLUS select CPU_V7 + select USB_ARCH_HAS_EHCI config ARCH_OMAP4 bool "TI OMAP4" @@ -124,7 +125,7 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has @@ -145,7 +146,7 @@ config OMAP_32K_TIMER_HZ config OMAP_DM_TIMER bool "Use dual-mode timer" - depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 help Select this option if you want to use OMAP Dual-Mode timers. diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 7cbc0a214aab..4f29e8c0f539 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -127,7 +127,7 @@ static cycle_t omap2430_32k_read(struct clocksource *cs) #define omap2430_32k_read NULL #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static cycle_t omap34xx_32k_read(struct clocksource *cs) { return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10); diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 0fb0e58fec93..9608019fd6e4 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -178,11 +178,11 @@ struct gpio_bank { u16 virtual_irq_start; int method; #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) + defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) u32 suspend_wakeup; u32 saved_wakeup; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -276,7 +276,7 @@ static struct gpio_bank gpio_bank_243x[5] = { #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static struct gpio_bank gpio_bank_34xx[6] = { { OMAP34XX_GPIO1_BASE, NULL, INT_34XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, @@ -426,7 +426,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) reg += OMAP7XX_GPIO_DIR_CONTROL; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_OE; break; @@ -493,7 +493,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) l &= ~(1 << gpio); break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETDATAOUT; @@ -546,7 +546,7 @@ static int _get_gpio_datain(struct gpio_bank *bank, int gpio) reg += OMAP7XX_GPIO_DATA_INPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAIN; break; @@ -592,7 +592,7 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) reg += OMAP7XX_GPIO_DATA_OUTPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAOUT; @@ -684,7 +684,7 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time) } EXPORT_SYMBOL(omap_set_gpio_debounce_time); -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) @@ -856,7 +856,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) goto bad; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: set_24xx_gpio_triggering(bank, gpio, trigger); @@ -937,7 +937,7 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) reg += OMAP7XX_GPIO_INT_STATUS; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQSTATUS1; break; @@ -954,7 +954,7 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; #endif #if defined(CONFIG_ARCH_OMAP4) @@ -1008,7 +1008,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) inv = 1; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; mask = 0xffffffff; @@ -1077,7 +1077,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab l |= gpio_mask; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETIRQENABLE1; @@ -1131,7 +1131,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_unlock_irqrestore(&bank->lock, flags); return 0; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) case METHOD_GPIO_24XX: if (bank->non_wakeup_gpios & (1 << gpio)) { @@ -1227,7 +1227,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) __raw_writel(1 << offset, reg); } #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) if (bank->method == METHOD_GPIO_24XX) { /* Disable wake-up during idle for dynamic tick */ @@ -1286,7 +1286,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->method == METHOD_GPIO_7XX) isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif @@ -1766,7 +1766,7 @@ static int __init _omap_gpio_init(void) gpio_bank = gpio_bank_243x; } #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 if (cpu_is_omap34xx()) { gpio_bank_count = OMAP34XX_NR_GPIOS; gpio_bank = gpio_bank_34xx; @@ -1809,7 +1809,7 @@ static int __init _omap_gpio_init(void) gpio_count = 32; /* 7xx has 32-bit GPIOs */ } -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) if (bank->method == METHOD_GPIO_24XX) { static const u32 non_wakeup_gpios[] = { @@ -1904,7 +1904,7 @@ static int __init _omap_gpio_init(void) } #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) + defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) { int i; @@ -1927,7 +1927,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN; wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; @@ -1975,7 +1975,7 @@ static int omap_gpio_resume(struct sys_device *dev) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; @@ -2013,7 +2013,7 @@ static struct sys_device omap_gpio_device = { #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) static int workaround_enabled; @@ -2030,7 +2030,7 @@ void omap2_gpio_prepare_for_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); @@ -2045,7 +2045,7 @@ void omap2_gpio_prepare_for_retention(void) bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); #endif @@ -2074,7 +2074,7 @@ void omap2_gpio_resume_after_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) __raw_writel(bank->saved_fallingdetect, bank->base + OMAP24XX_GPIO_FALLINGDETECT); __raw_writel(bank->saved_risingdetect, @@ -2113,7 +2113,7 @@ void omap2_gpio_resume_after_retention(void) if (gen) { u32 old0, old1; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); __raw_writel(old0 | gen, bank->base + @@ -2144,7 +2144,7 @@ void omap2_gpio_resume_after_retention(void) #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 /* save the registers of bank 2-6 */ void omap_gpio_save_context(void) { @@ -2241,7 +2241,7 @@ static int __init omap_gpio_sysinit(void) mpuio_init(); #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) + defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) if (cpu_is_omap16xx() || cpu_class_is_omap2()) { if (ret == 0) { ret = sysdev_class_register(&omap_gpio_sysclass); @@ -2301,7 +2301,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) irqstat = irq_desc[irq].status; #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) + defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) if (is_in && ((bank->suspend_wakeup & mask) || irqstat & IRQ_TYPE_SENSE_MASK)) { char *trigger = NULL; diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 7773bceca442..96d2781ac4f5 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -50,10 +50,10 @@ static const char name[] = "i2c_omap"; static struct resource i2c_resources[][2] = { { I2C_RESOURCE_BUILDER(0, 0) }, -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) }, #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) }, #endif }; @@ -72,10 +72,10 @@ static struct resource i2c_resources[][2] = { static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; static struct platform_device omap_i2c_devices[] = { I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]), #endif }; diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 527aaae61720..995466d0432a 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -114,7 +114,7 @@ unsigned int omap_rev(void); # define OMAP_NAME omap16xx # endif #endif -#if (defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX)) +#if (defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)) # if (defined(OMAP_NAME) || defined(MULTI_OMAP1)) # error "OMAP1 and OMAP2 can't be selected at the same time" # endif @@ -241,7 +241,7 @@ IS_OMAP_SUBCLASS(443x, 0x443) # define cpu_is_omap242x() is_omap242x() # define cpu_is_omap243x() is_omap243x() # endif -# if defined(CONFIG_ARCH_OMAP34XX) +# if defined(CONFIG_ARCH_OMAP3) # undef cpu_is_omap34xx # undef cpu_is_omap343x # define cpu_is_omap34xx() is_omap34xx() @@ -260,7 +260,7 @@ IS_OMAP_SUBCLASS(443x, 0x443) # undef cpu_is_omap243x # define cpu_is_omap243x() 1 # endif -# if defined(CONFIG_ARCH_OMAP34XX) +# if defined(CONFIG_ARCH_OMAP3) # undef cpu_is_omap34xx # define cpu_is_omap34xx() 1 # endif @@ -385,7 +385,7 @@ IS_OMAP_TYPE(3517, 0x3517) # define cpu_is_omap2430() is_omap2430() #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) # undef cpu_is_omap3430 # undef cpu_is_omap3503 # undef cpu_is_omap3515 diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h index 19257bbbc9f3..eef914d53971 100644 --- a/arch/arm/plat-omap/include/plat/io.h +++ b/arch/arm/plat-omap/include/plat/io.h @@ -284,7 +284,7 @@ static inline void omap243x_map_common_io(void) } #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 extern void omap34xx_map_common_io(void); #else static inline void omap34xx_map_common_io(void) diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 951506277ec8..0d7e536a3c95 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -103,7 +103,7 @@ #define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX #define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX -#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) || \ +#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) #define OMAP_MCBSP_REG_DRR2 0x00 @@ -374,7 +374,7 @@ struct omap_mcbsp_platform_data { u8 dma_rx_sync, dma_tx_sync; u16 rx_irq, tx_irq; struct omap_mcbsp_ops *ops; -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 u16 buffer_size; #endif }; @@ -410,7 +410,7 @@ struct omap_mcbsp { struct omap_mcbsp_platform_data *pdata; struct clk *iclk; struct clk *fclk; -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 int dma_op_mode; u16 max_tx_thres; u16 max_rx_thres; @@ -423,7 +423,7 @@ int omap_mcbsp_init(void); void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, int size); void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold); void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold); u16 omap_mcbsp_get_max_tx_threshold(unsigned int id); diff --git a/arch/arm/plat-omap/include/plat/omap34xx.h b/arch/arm/plat-omap/include/plat/omap34xx.h index 077f05979f86..2845fdc658b0 100644 --- a/arch/arm/plat-omap/include/plat/omap34xx.h +++ b/arch/arm/plat-omap/include/plat/omap34xx.h @@ -21,8 +21,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_OMAP34XX_H -#define __ASM_ARCH_OMAP34XX_H +#ifndef __ASM_ARCH_OMAP3_H +#define __ASM_ARCH_OMAP3_H /* * Please place only base defines here and put the rest in device @@ -82,5 +82,5 @@ #define OMAP34XX_MAILBOX_BASE (L4_34XX_BASE + 0x94000) -#endif /* __ASM_ARCH_OMAP34XX_H */ +#endif /* __ASM_ARCH_OMAP3_H */ diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f75767278fc3..c1eb61529394 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -198,7 +198,7 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) } EXPORT_SYMBOL(omap_mcbsp_config); -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 /* * omap_mcbsp_set_tx_threshold configures how to deal * with transmit threshold. the threshold value and handler can be @@ -1107,7 +1107,7 @@ void omap_mcbsp_set_spi_mode(unsigned int id, } EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 #define max_thres(m) (mcbsp->pdata->buffer_size) #define valid_threshold(m, val) ((val) <= max_thres(m)) #define THRESHOLD_PROP_BUILDER(prop) \ @@ -1246,7 +1246,7 @@ static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) #else static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {} -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ /* * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index e0cbb9349bc1..51f4dfb82e2b 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -53,7 +53,7 @@ #define OMAP4_SRAM_PUB_PA (OMAP4_SRAM_PA + 0x4000) #define OMAP4_SRAM_PUB_VA (OMAP4_SRAM_VA + 0x4000) -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) #define SRAM_BOOTLOADER_SZ 0x00 #else #define SRAM_BOOTLOADER_SZ 0x80 diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 1477ff8f85f6..3269292efecc 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -42,7 +42,7 @@ #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW -#elif defined(CONFIG_ARCH_OMAP34XX) +#elif defined(CONFIG_ARCH_OMAP3) #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 23bd252f3a44..66c35d74a76b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -164,7 +164,7 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP24xx/OMAP34xx" - depends on ARCH_OMAP2 || ARCH_OMAP34XX + depends on ARCH_OMAP2 || ARCH_OMAP3 help SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI (McSPI) modules. diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index bf5f95a19413..715c518b1b68 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -1014,7 +1014,7 @@ static u8 __initdata spi2_txdma_id[] = { OMAP24XX_DMA_SPI2_TX1, }; -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) \ +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ || defined(CONFIG_ARCH_OMAP4) static u8 __initdata spi3_rxdma_id[] = { OMAP24XX_DMA_SPI3_RX0, diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 81aac7f4ca59..4f5bb5698f5d 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -61,7 +61,7 @@ config USB_ARCH_HAS_EHCI default y if ARCH_W90X900 default y if ARCH_AT91SAM9G45 default y if ARCH_MXC - default y if ARCH_OMAP34XX + default y if ARCH_OMAP3 default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 1ec3857f22e6..d8d6d3461d32 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1118,7 +1118,7 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 #include "ehci-omap.c" #define PLATFORM_DRIVER ehci_hcd_omap_driver #endif diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index d9db86498022..b4c783c284ba 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -37,7 +37,7 @@ config USB_MUSB_SOC depends on USB_MUSB_HDRC default y if ARCH_DAVINCI default y if ARCH_OMAP2430 - default y if ARCH_OMAP34XX + default y if ARCH_OMAP3 default y if (BF54x && !BF544) default y if (BF52x && !BF522 && !BF523) @@ -48,7 +48,7 @@ comment "OMAP 243x high speed USB support" depends on USB_MUSB_HDRC && ARCH_OMAP2430 comment "OMAP 343x high speed USB support" - depends on USB_MUSB_HDRC && ARCH_OMAP34XX + depends on USB_MUSB_HDRC && ARCH_OMAP3 comment "Blackfin high speed USB Support" depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523)) @@ -153,7 +153,7 @@ config MUSB_PIO_ONLY config USB_INVENTRA_DMA bool depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY - default ARCH_OMAP2430 || ARCH_OMAP34XX || BLACKFIN + default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN help Enable DMA transfers using Mentor's engine. diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 5eb9318cff77..738efd8063b5 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1000,7 +1000,7 @@ static void musb_shutdown(struct platform_device *pdev) * more than selecting one of a bunch of predefined configurations. */ #if defined(CONFIG_USB_TUSB6010) || \ - defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) + defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) static ushort __initdata fifo_mode = 4; #else static ushort __initdata fifo_mode = 2; diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 03d50909b078..5514c7ee85bd 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -562,7 +562,7 @@ extern void musb_hnp_stop(struct musb *musb); extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode); #if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \ - defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) + defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); #else #define musb_platform_try_idle(x, y) do {} while (0) diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 3195fb8b7d9a..80b3b123dd7f 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -60,7 +60,7 @@ config W1_MASTER_GPIO config HDQ_MASTER_OMAP tristate "OMAP HDQ driver" - depends on ARCH_OMAP2430 || ARCH_OMAP34XX + depends on ARCH_OMAP2430 || ARCH_OMAP3 help Say Y here if you want support for the 1-wire or HDQ Interface on an OMAP processor. diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b45e2896ac87..3da3f48720a7 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -194,7 +194,7 @@ config EP93XX_WATCHDOG config OMAP_WATCHDOG tristate "OMAP Watchdog" - depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP34XX + depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3 help Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y' here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer. diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 26e728dc1337..c0039b35fb25 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -82,11 +82,11 @@ static const int omap1_dma_reqs[][2] = {}; static const unsigned long omap1_mcbsp_port[][2] = {}; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) static const int omap24xx_dma_reqs[][2] = { { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, @@ -124,7 +124,7 @@ static const unsigned long omap2430_mcbsp_port[][2] = { static const unsigned long omap2430_mcbsp_port[][2] = {}; #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) static const unsigned long omap34xx_mcbsp_port[][2] = { { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 647d2f981ab0..1968d03bc532 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -50,7 +50,7 @@ enum omap_mcbsp_div { #undef NUM_LINKS #define NUM_LINKS 3 #endif -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) #undef NUM_LINKS #define NUM_LINKS 5 #endif -- GitLab From 140455fa007a618d2d1bf5e6e888206534035e6f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:48 -0800 Subject: [PATCH 2085/3892] omap2/3/4: Replace orred CONFIG_ARCH_OMAP2/3/4 with CONFIG_ARCH_OMAP2PLUS omap: Replace orred CONFIG_ARCH_OMAP2/3/4 with CONFIG_ARCH_OMAP2PLUS Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 2 +- arch/arm/plat-omap/Kconfig | 4 +-- arch/arm/plat-omap/dma.c | 3 +- arch/arm/plat-omap/dmtimer.c | 12 +++----- arch/arm/plat-omap/gpio.c | 36 ++++++++--------------- arch/arm/plat-omap/include/plat/clock.h | 6 ++-- arch/arm/plat-omap/include/plat/control.h | 3 +- arch/arm/plat-omap/include/plat/mcbsp.h | 3 +- arch/arm/plat-omap/include/plat/memory.h | 3 +- 9 files changed, 25 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 317b8cb375be..f90b225ef888 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -29,7 +29,7 @@ config OMAP_PACKAGE_CBP bool comment "OMAP Board Type" - depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP2PLUS config MACH_OMAP_GENERIC bool "Generic OMAP board" diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 1e223924da8a..97d0c79ffd2b 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -125,7 +125,7 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has @@ -146,7 +146,7 @@ config OMAP_32K_TIMER_HZ config OMAP_DM_TIMER bool "Use dual-mode timer" - depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS help Select this option if you want to use OMAP Dual-Mode timers. diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 728c64204184..30ff525fe33c 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1870,8 +1870,7 @@ static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id) #define omap1_dma_irq_handler NULL #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS static int omap2_dma_handle_ch(int ch) { diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index c588cdf35db1..24bf692fe65e 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -153,8 +153,7 @@ struct omap_dm_timer { unsigned long phys_base; int irq; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS struct clk *iclk, *fclk; #endif void __iomem *io_base; @@ -490,8 +489,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) } EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); -#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#else struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) { @@ -535,8 +533,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer) if (l & OMAP_TIMER_CTRL_ST) { l &= ~0x1; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS /* Readback to make sure write has completed */ omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); /* @@ -781,8 +778,7 @@ int __init omap_dm_timer_init(void) timer->io_base = ioremap(timer->phys_base, map_size); BUG_ON(!timer->io_base); -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS if (cpu_class_is_omap2()) { char clk_name[16]; sprintf(clk_name, "gpt%d_ick", i + 1); diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 9608019fd6e4..a888304b8383 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -177,13 +177,11 @@ struct gpio_bank { u16 irq; u16 virtual_irq_start; int method; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) u32 suspend_wakeup; u32 saved_wakeup; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -592,8 +590,7 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) reg += OMAP7XX_GPIO_DATA_OUTPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAOUT; break; @@ -684,8 +681,7 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time) } EXPORT_SYMBOL(omap_set_gpio_debounce_time); -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) { @@ -856,8 +852,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) goto bad; break; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: set_24xx_gpio_triggering(bank, gpio, trigger); break; @@ -1131,8 +1126,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_unlock_irqrestore(&bank->lock, flags); return 0; #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: if (bank->non_wakeup_gpios & (1 << gpio)) { printk(KERN_ERR "Unable to modify wakeup on " @@ -1227,8 +1221,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) __raw_writel(1 << offset, reg); } #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS if (bank->method == METHOD_GPIO_24XX) { /* Disable wake-up during idle for dynamic tick */ void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; @@ -1809,8 +1802,7 @@ static int __init _omap_gpio_init(void) gpio_count = 32; /* 7xx has 32-bit GPIOs */ } -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS if (bank->method == METHOD_GPIO_24XX) { static const u32 non_wakeup_gpios[] = { 0xe203ffc0, 0x08700040 @@ -1903,8 +1895,7 @@ static int __init _omap_gpio_init(void) return 0; } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) { int i; @@ -2013,8 +2004,7 @@ static struct sys_device omap_gpio_device = { #endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS static int workaround_enabled; @@ -2240,8 +2230,7 @@ static int __init omap_gpio_sysinit(void) mpuio_init(); -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) if (cpu_is_omap16xx() || cpu_class_is_omap2()) { if (ret == 0) { ret = sysdev_class_register(&omap_gpio_sysclass); @@ -2300,8 +2289,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) /* FIXME for at least omap2, show pullup/pulldown state */ irqstat = irq_desc[irq].status; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2) || \ - defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) if (is_in && ((bank->suspend_wakeup & mask) || irqstat & IRQ_TYPE_SENSE_MASK)) { char *trigger = NULL; diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index e41313208125..8a86df4ad99c 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -26,8 +26,7 @@ struct clkops { void (*find_companion)(struct clk *, void __iomem **, u8 *); }; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS struct clksel_rate { u32 val; @@ -89,8 +88,7 @@ struct clk { __u8 enable_bit; __s8 usecount; u8 fixed_div; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS void __iomem *clksel_reg; u32 clksel_mask; const struct clksel *clksel; diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index 61e7b8a8c993..fcdc71bf4c6e 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -309,8 +309,7 @@ #ifndef __ASSEMBLY__ -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#ifdef CONFIG_ARCH_OMAP2PLUS extern void __iomem *omap_ctrl_base_get(void); extern u8 omap_ctrl_readb(u16 offset); extern u16 omap_ctrl_readw(u16 offset); diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 0d7e536a3c95..d93fa44b1c9a 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -103,8 +103,7 @@ #define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX #define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX -#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#else #define OMAP_MCBSP_REG_DRR2 0x00 #define OMAP_MCBSP_REG_DRR1 0x04 diff --git a/arch/arm/plat-omap/include/plat/memory.h b/arch/arm/plat-omap/include/plat/memory.h index 3325f7b49eaa..d5306bee44b2 100644 --- a/arch/arm/plat-omap/include/plat/memory.h +++ b/arch/arm/plat-omap/include/plat/memory.h @@ -38,8 +38,7 @@ */ #if defined(CONFIG_ARCH_OMAP1) #define PHYS_OFFSET UL(0x10000000) -#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ - defined(CONFIG_ARCH_OMAP4) +#else #define PHYS_OFFSET UL(0x80000000) #endif -- GitLab From 4323e9f71903f654abc6d21a3ef81c08e0ac2288 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:48 -0800 Subject: [PATCH 2086/3892] omap2/3: Fix initcalls for multi-omap Otherwise the wrong initcalls can run. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 7 ++++++- arch/arm/mach-omap2/emu.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 935e36c3a5e9..c104d5ca65b2 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -510,7 +510,12 @@ static struct platform_device dummy_pdev = { **/ static void __init omap_hsmmc_reset(void) { - u32 i, nr_controllers = cpu_is_omap44xx() ? OMAP44XX_NR_MMC : + u32 i, nr_controllers; + + if (cpu_is_omap242x()) + return; + + nr_controllers = cpu_is_omap44xx() ? OMAP44XX_NR_MMC : (cpu_is_omap34xx() ? OMAP34XX_NR_MMC : OMAP24XX_NR_MMC); for (i = 0; i < nr_controllers; i++) { diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c index ec0d984a26fc..9c442e290ccb 100644 --- a/arch/arm/mach-omap2/emu.c +++ b/arch/arm/mach-omap2/emu.c @@ -56,6 +56,9 @@ static struct amba_device omap3_etm_device = { static int __init emu_init(void) { + if (!cpu_is_omap34xx()) + return -ENODEV; + amba_device_register(&omap3_etb_device, &iomem_resource); amba_device_register(&omap3_etm_device, &iomem_resource); -- GitLab From 78aee23f32447bff0ef8dd012d9b0eaf1e3a79a1 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 12 Feb 2010 12:26:49 -0800 Subject: [PATCH 2087/3892] omap2/3: Update omap3_defconfig to build in all the 2420 based boards Note that booting 2420 depends on another patch posted earlier to not select CONFIG_CPU_32v6K if CONFIG_ARCH_OMAP2 is selected. Also note that we cannot add omap2430 in yet because of the different clock addresses compared to 2420. Also note that we cannot have CONFIG_CPU_32v6K=y in order to boot on 24xx. Signed-off-by: Tony Lindgren --- arch/arm/configs/omap3_defconfig | 174 ++++++++++++++++++++++++------- 1 file changed, 138 insertions(+), 36 deletions(-) diff --git a/arch/arm/configs/omap3_defconfig b/arch/arm/configs/omap3_defconfig index 367be98a6aef..2bc80d7532b9 100644 --- a/arch/arm/configs/omap3_defconfig +++ b/arch/arm/configs/omap3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.32-rc8 -# Tue Dec 1 14:04:02 2009 +# Linux kernel version: 2.6.33-rc5 +# Tue Jan 26 11:05:31 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -20,6 +20,8 @@ CONFIG_ARCH_HAS_CPUFREQ=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_OPROFILE_ARMV6=y +CONFIG_OPROFILE_ARM11_CORE=y CONFIG_OPROFILE_ARMV7=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -33,6 +35,12 @@ CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y @@ -48,6 +56,7 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_TREE_RCU=y # CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set @@ -69,6 +78,7 @@ CONFIG_INITRAMFS_SOURCE="" CONFIG_RD_GZIP=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_ANON_INODES=y @@ -133,14 +143,41 @@ CONFIG_LBDAF=y # IO Schedulers # CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y -# CONFIG_DEFAULT_AS is not set # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set CONFIG_FREEZER=y # @@ -169,6 +206,7 @@ CONFIG_MMU=y # CONFIG_ARCH_IXP2000 is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_DOVE is not set # CONFIG_ARCH_KIRKWOOD is not set # CONFIG_ARCH_LOKI is not set # CONFIG_ARCH_MV78XX0 is not set @@ -191,21 +229,23 @@ CONFIG_MMU=y # CONFIG_ARCH_DAVINCI is not set CONFIG_ARCH_OMAP=y # CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_U8500 is not set # # TI OMAP Implementations # CONFIG_ARCH_OMAP_OTG=y # CONFIG_ARCH_OMAP1 is not set -# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP2PLUS=y +CONFIG_ARCH_OMAP2=y CONFIG_ARCH_OMAP3=y # CONFIG_ARCH_OMAP4 is not set # # OMAP Feature Selections # -# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set -# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set +CONFIG_OMAP_DEBUG_DEVICES=y +CONFIG_OMAP_DEBUG_LEDS=y CONFIG_OMAP_RESET_CLOCKS=y CONFIG_OMAP_MUX=y CONFIG_OMAP_MUX_DEBUG=y @@ -216,43 +256,65 @@ CONFIG_OMAP_MCBSP=y CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_32K_TIMER_HZ=128 CONFIG_OMAP_DM_TIMER=y -# CONFIG_OMAP_LL_DEBUG_UART1 is not set -# CONFIG_OMAP_LL_DEBUG_UART2 is not set -# CONFIG_OMAP_LL_DEBUG_UART3 is not set -CONFIG_OMAP_LL_DEBUG_NONE=y # CONFIG_OMAP_PM_NONE is not set CONFIG_OMAP_PM_NOOP=y -CONFIG_ARCH_OMAP34XX=y +CONFIG_MACH_OMAP_GENERIC=y + +# +# OMAP Core Type +# +CONFIG_ARCH_OMAP2420=y +# CONFIG_ARCH_OMAP2430 is not set CONFIG_ARCH_OMAP3430=y +CONFIG_OMAP_PACKAGE_CBB=y +CONFIG_OMAP_PACKAGE_CUS=y +CONFIG_OMAP_PACKAGE_CBP=y # # OMAP Board Type # +CONFIG_MACH_OMAP2_TUSB6010=y +CONFIG_MACH_OMAP_H4=y +CONFIG_MACH_OMAP_APOLLON=y +# CONFIG_MACH_OMAP_2430SDP is not set CONFIG_MACH_OMAP3_BEAGLE=y CONFIG_MACH_OMAP_LDP=y CONFIG_MACH_OVERO=y CONFIG_MACH_OMAP3EVM=y CONFIG_MACH_OMAP3517EVM=y CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP3_TOUCHBOOK=y CONFIG_MACH_OMAP_3430SDP=y +CONFIG_MACH_NOKIA_N800=y +CONFIG_MACH_NOKIA_N810=y +CONFIG_MACH_NOKIA_N810_WIMAX=y +CONFIG_MACH_NOKIA_N8X0=y CONFIG_MACH_NOKIA_RX51=y CONFIG_MACH_OMAP_ZOOM2=y CONFIG_MACH_OMAP_ZOOM3=y CONFIG_MACH_CM_T35=y CONFIG_MACH_IGEP0020=y CONFIG_MACH_OMAP_3630SDP=y +# CONFIG_OMAP3_EMU is not set +# CONFIG_OMAP3_SDRC_AC_TIMING is not set # # Processor Type # -CONFIG_CPU_32v6K=y +CONFIG_CPU_V6=y +# CONFIG_CPU_32v6K is not set CONFIG_CPU_V7=y +CONFIG_CPU_32v6=y CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV6=y CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V6=y CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V6=y CONFIG_CPU_CACHE_V7=y CONFIG_CPU_CACHE_VIPT=y CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V6=y CONFIG_CPU_TLB_V7=y CONFIG_CPU_HAS_ASID=y CONFIG_CPU_CP15=y @@ -268,6 +330,7 @@ CONFIG_ARM_THUMBEE=y # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_HAS_TLS_REG=y CONFIG_ARM_L1_CACHE_SHIFT=6 +# CONFIG_ARM_ERRATA_411920 is not set # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set @@ -308,12 +371,10 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SPLIT_PTLOCK_CPUS=999999 # CONFIG_PHYS_ADDR_T_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 CONFIG_VIRT_TO_BUS=y -CONFIG_HAVE_MLOCK=y -CONFIG_HAVE_MLOCKED_PAGE_BIT=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_LEDS=y @@ -509,15 +570,18 @@ CONFIG_BT_HCIBPA10X=y # CONFIG_BT_MRVL is not set # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set CONFIG_CFG80211_DEFAULT_PS=y -CONFIG_CFG80211_DEFAULT_PS_VALUE=1 # CONFIG_CFG80211_DEBUGFS is not set CONFIG_WIRELESS_OLD_REGULATORY=y -CONFIG_WIRELESS_EXT=y +CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y # CONFIG_LIB80211_DEBUG is not set @@ -671,6 +735,7 @@ CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y @@ -681,9 +746,12 @@ CONFIG_BLK_DEV_RAM_SIZE=16384 # CONFIG_ATA_OVER_ETH is not set # CONFIG_MG_DISK is not set CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set # CONFIG_ISL29003 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set # CONFIG_C2PORT is not set # @@ -694,6 +762,7 @@ CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y # CONFIG_EEPROM_MAX6875 is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -792,28 +861,26 @@ CONFIG_SMSC911X=y CONFIG_NETDEV_1000=y CONFIG_NETDEV_10000=y CONFIG_WLAN=y -# CONFIG_WLAN_PRE80211 is not set -CONFIG_WLAN_80211=y -CONFIG_LIBERTAS=y -CONFIG_LIBERTAS_USB=y -CONFIG_LIBERTAS_SDIO=y -# CONFIG_LIBERTAS_SPI is not set -CONFIG_LIBERTAS_DEBUG=y # CONFIG_LIBERTAS_THINFIRM is not set # CONFIG_AT76C50X_USB is not set # CONFIG_USB_ZD1201 is not set # CONFIG_USB_NET_RNDIS_WLAN is not set # CONFIG_RTL8187 is not set # CONFIG_MAC80211_HWSIM is not set -# CONFIG_P54_COMMON is not set # CONFIG_ATH_COMMON is not set -# CONFIG_HOSTAP is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set -# CONFIG_ZD1211RW is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +CONFIG_LIBERTAS=y +CONFIG_LIBERTAS_USB=y +CONFIG_LIBERTAS_SDIO=y +# CONFIG_LIBERTAS_SPI is not set +CONFIG_LIBERTAS_DEBUG=y +# CONFIG_P54_COMMON is not set # CONFIG_RT2X00 is not set # CONFIG_WL12XX is not set -# CONFIG_IWM is not set +# CONFIG_ZD1211RW is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -861,6 +928,7 @@ CONFIG_USB_NET_ZAURUS=y CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set # CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set # # Userland interfaces @@ -889,6 +957,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_OPENCORES is not set # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP is not set CONFIG_KEYBOARD_TWL4030=y # CONFIG_KEYBOARD_XTKBD is not set CONFIG_INPUT_MOUSE=y @@ -914,6 +983,7 @@ CONFIG_TOUCHSCREEN_ADS7846=y # CONFIG_TOUCHSCREEN_AD7879_I2C is not set # CONFIG_TOUCHSCREEN_AD7879_SPI is not set # CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set # CONFIG_TOUCHSCREEN_EETI is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set @@ -948,6 +1018,7 @@ CONFIG_SERIO=y CONFIG_SERIO_SERPORT=y CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set # CONFIG_GAMEPORT is not set # @@ -986,6 +1057,7 @@ CONFIG_UNIX98_PTYS=y # CONFIG_IPMI_HANDLER is not set CONFIG_HW_RANDOM=y # CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_OMAP=y # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set @@ -1024,7 +1096,6 @@ CONFIG_I2C_OMAP=y # # Miscellaneous I2C Chip support # -# CONFIG_DS1682 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set @@ -1040,6 +1111,8 @@ CONFIG_SPI_MASTER=y # CONFIG_SPI_BITBANG is not set # CONFIG_SPI_GPIO is not set CONFIG_SPI_OMAP24XX=y +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set # # SPI Protocol Masters @@ -1067,6 +1140,7 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_PCA953X is not set # CONFIG_GPIO_PCF857X is not set CONFIG_GPIO_TWL4030=y +# CONFIG_GPIO_ADP5588 is not set # # PCI GPIO expanders: @@ -1141,6 +1215,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set # CONFIG_SENSORS_LM75 is not set # CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set @@ -1166,6 +1241,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set # CONFIG_SENSORS_THMC50 is not set # CONFIG_SENSORS_TMP401 is not set # CONFIG_SENSORS_TMP421 is not set @@ -1179,6 +1255,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set # CONFIG_THERMAL is not set CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y @@ -1204,20 +1281,22 @@ CONFIG_SSB_POSSIBLE=y # # Multifunction device drivers # -# CONFIG_MFD_CORE is not set +CONFIG_MFD_CORE=y # CONFIG_MFD_SM501 is not set # CONFIG_MFD_ASIC3 is not set # CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_TPS65010 is not set +# CONFIG_MENELAUS is not set CONFIG_TWL4030_CORE=y # CONFIG_TWL4030_POWER is not set -# CONFIG_TWL4030_CODEC is not set +CONFIG_TWL4030_CODEC=y # CONFIG_MFD_TMIO is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC6387XB is not set # CONFIG_MFD_TC6393XB is not set # CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_WM8400 is not set # CONFIG_MFD_WM831X is not set # CONFIG_MFD_WM8350_I2C is not set @@ -1225,6 +1304,8 @@ CONFIG_TWL4030_CORE=y # CONFIG_MFD_MC13783 is not set # CONFIG_AB3100_CORE is not set # CONFIG_EZX_PCAP is not set +# CONFIG_MFD_88PM8607 is not set +# CONFIG_AB4500_CORE is not set CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -1232,6 +1313,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y # CONFIG_REGULATOR_USERSPACE_CONSUMER is not set # CONFIG_REGULATOR_BQ24022 is not set # CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8660 is not set CONFIG_REGULATOR_TWL4030=y # CONFIG_REGULATOR_LP3971 is not set # CONFIG_REGULATOR_TPS65023 is not set @@ -1267,6 +1349,7 @@ CONFIG_FB_TILEBLITTING=y # # CONFIG_FB_UVESA is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set @@ -1281,6 +1364,7 @@ CONFIG_FB_OMAP_079M3R=y # CONFIG_FB_OMAP_LCD_MIPID is not set # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2 +# CONFIG_OMAP2_DSS is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y # CONFIG_LCD_LMS283GF05 is not set @@ -1364,12 +1448,15 @@ CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_SND_OMAP_SOC=y CONFIG_SND_OMAP_SOC_MCBSP=y +# CONFIG_SND_OMAP_SOC_N810 is not set # CONFIG_SND_OMAP_SOC_OVERO is not set # CONFIG_SND_OMAP_SOC_OMAP3EVM is not set +# CONFIG_SND_OMAP_SOC_AM3517EVM is not set # CONFIG_SND_OMAP_SOC_SDP3430 is not set CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y # CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE is not set # CONFIG_SND_OMAP_SOC_ZOOM2 is not set +# CONFIG_SND_OMAP_SOC_IGEP0020 is not set CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set CONFIG_SND_SOC_TWL4030=y @@ -1418,7 +1505,7 @@ CONFIG_USB_HID=y CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y -# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y CONFIG_USB_DEBUG=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -1441,6 +1528,7 @@ CONFIG_USB_MON=y # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_ISP1760_HCD is not set @@ -1556,16 +1644,18 @@ CONFIG_USB_GADGET_SELECTED=y # CONFIG_USB_GADGET_LANGWELL is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set CONFIG_USB_GADGET_DUALSPEED=y -CONFIG_USB_ZERO=y +CONFIG_USB_ZERO=m # CONFIG_USB_ZERO_HNPTEST is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ETH is not set # CONFIG_USB_GADGETFS is not set # CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set # CONFIG_USB_G_SERIAL is not set # CONFIG_USB_MIDI_GADGET is not set # CONFIG_USB_G_PRINTER is not set # CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set # # OTG and related infrastructure @@ -1573,6 +1663,7 @@ CONFIG_USB_ZERO=y CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_ISP1301_OMAP is not set +# CONFIG_USB_ULPI is not set CONFIG_TWL4030_USB=y CONFIG_NOP_USB_XCEIV=y CONFIG_MMC=y @@ -1609,7 +1700,9 @@ CONFIG_LEDS_GPIO_PLATFORM=y # CONFIG_LEDS_LP3944 is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set # CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set # # LED Triggers @@ -1653,6 +1746,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_PCF8583 is not set # CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set CONFIG_RTC_DRV_TWL4030=y # CONFIG_RTC_DRV_S35390A is not set # CONFIG_RTC_DRV_FM3130 is not set @@ -1683,7 +1777,9 @@ CONFIG_RTC_DRV_TWL4030=y # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set # CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set # CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set # CONFIG_RTC_DRV_V3020 is not set # @@ -1951,6 +2047,7 @@ CONFIG_DEBUG_INFO=y # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set # CONFIG_PAGE_POISONING is not set CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y @@ -1983,7 +2080,9 @@ CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_STACK_USAGE is not set CONFIG_DEBUG_LL=y +# CONFIG_EARLY_PRINTK is not set # CONFIG_DEBUG_ICEDCC is not set +# CONFIG_OC_ETM is not set # # Security options @@ -1993,9 +2092,12 @@ CONFIG_SECURITY=y # CONFIG_SECURITYFS is not set # CONFIG_SECURITY_NETWORK is not set # CONFIG_SECURITY_PATH is not set -# CONFIG_SECURITY_FILE_CAPABILITIES is not set -# CONFIG_SECURITY_ROOTPLUG is not set # CONFIG_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" CONFIG_CRYPTO=y # -- GitLab From 1cf9d079637e1479842dad0b25f445b5ceec0bab Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:24 -0800 Subject: [PATCH 2088/3892] omap: Move multi-omap ifdeffery into it's own header file This way we can include it easily as needed also for .S files. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/cpu.h | 70 +----------------- arch/arm/plat-omap/include/plat/multi.h | 94 +++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 69 deletions(-) create mode 100644 arch/arm/plat-omap/include/plat/multi.h diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 995466d0432a..b80151c1ee61 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -31,6 +31,7 @@ #define __ASM_ARCH_OMAP_CPU_H #include +#include /* * Omap device type i.e. EMU/HS/TST/GP/BAD @@ -75,75 +76,6 @@ unsigned int omap_rev(void); */ #define GET_OMAP_REVISION() ((omap_rev() >> 8) & 0xff) -/* - * Test if multicore OMAP support is needed - */ -#undef MULTI_OMAP1 -#undef MULTI_OMAP2 -#undef OMAP_NAME - -#ifdef CONFIG_ARCH_OMAP730 -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap730 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP850 -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap850 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP15XX -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap1510 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP16XX -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap16xx -# endif -#endif -#if (defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)) -# if (defined(OMAP_NAME) || defined(MULTI_OMAP1)) -# error "OMAP1 and OMAP2 can't be selected at the same time" -# endif -#endif -#ifdef CONFIG_ARCH_OMAP2420 -# ifdef OMAP_NAME -# undef MULTI_OMAP2 -# define MULTI_OMAP2 -# else -# define OMAP_NAME omap2420 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP2430 -# ifdef OMAP_NAME -# undef MULTI_OMAP2 -# define MULTI_OMAP2 -# else -# define OMAP_NAME omap2430 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP3430 -# ifdef OMAP_NAME -# undef MULTI_OMAP2 -# define MULTI_OMAP2 -# else -# define OMAP_NAME omap3430 -# endif -#endif - /* * Macros to group OMAP into cpu classes. * These can be used in most places. diff --git a/arch/arm/plat-omap/include/plat/multi.h b/arch/arm/plat-omap/include/plat/multi.h new file mode 100644 index 000000000000..f235d32cd942 --- /dev/null +++ b/arch/arm/plat-omap/include/plat/multi.h @@ -0,0 +1,94 @@ +/* + * Support for compiling in multiple OMAP processors + * + * Copyright (C) 2010 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __PLAT_OMAP_MULTI_H +#define __PLAT_OMAP_MULTI_H + +/* + * Test if multicore OMAP support is needed + */ +#undef MULTI_OMAP1 +#undef MULTI_OMAP2 +#undef OMAP_NAME + +#ifdef CONFIG_ARCH_OMAP730 +# ifdef OMAP_NAME +# undef MULTI_OMAP1 +# define MULTI_OMAP1 +# else +# define OMAP_NAME omap730 +# endif +#endif +#ifdef CONFIG_ARCH_OMAP850 +# ifdef OMAP_NAME +# undef MULTI_OMAP1 +# define MULTI_OMAP1 +# else +# define OMAP_NAME omap850 +# endif +#endif +#ifdef CONFIG_ARCH_OMAP15XX +# ifdef OMAP_NAME +# undef MULTI_OMAP1 +# define MULTI_OMAP1 +# else +# define OMAP_NAME omap1510 +# endif +#endif +#ifdef CONFIG_ARCH_OMAP16XX +# ifdef OMAP_NAME +# undef MULTI_OMAP1 +# define MULTI_OMAP1 +# else +# define OMAP_NAME omap16xx +# endif +#endif +#if (defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)) +# if (defined(OMAP_NAME) || defined(MULTI_OMAP1)) +# error "OMAP1 and OMAP2 can't be selected at the same time" +# endif +#endif +#ifdef CONFIG_ARCH_OMAP2420 +# ifdef OMAP_NAME +# undef MULTI_OMAP2 +# define MULTI_OMAP2 +# else +# define OMAP_NAME omap2420 +# endif +#endif +#ifdef CONFIG_ARCH_OMAP2430 +# ifdef OMAP_NAME +# undef MULTI_OMAP2 +# define MULTI_OMAP2 +# else +# define OMAP_NAME omap2430 +# endif +#endif +#ifdef CONFIG_ARCH_OMAP3430 +# ifdef OMAP_NAME +# undef MULTI_OMAP2 +# define MULTI_OMAP2 +# else +# define OMAP_NAME omap3430 +# endif +#endif + +#endif /* __PLAT_OMAP_MULTI_H */ -- GitLab From 95d2b4e9cbba4c9a2ac63205e846e7ccfebe69b4 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:24 -0800 Subject: [PATCH 2089/3892] omap2/3/4: Clean up defines for entry-macro.S Define the irq base the same way as for omap2 and omap3, and start using get_irqnr_preamble. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/include/mach/entry-macro.S | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index 4fd6b1bdcb2b..3e63aaabebe7 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -19,6 +19,12 @@ #include #include +#define OMAP2_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE) +#define OMAP3_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) +#define OMAP4_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE) +#define INTCPS_SIR_IRQ_OFFSET 0x0040 /* omap2/3 active interrupt offset */ +#define ACTIVEIRQ_MASK 0x7f /* omap2/3 active interrupt bits */ + .macro disable_fiq .endm @@ -27,11 +33,6 @@ #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) -#define OMAP2_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE) -#define OMAP3_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) -#define INTCPS_SIR_IRQ_OFFSET 0x0040 /* Active interrupt offset */ -#define ACTIVEIRQ_MASK 0x7f /* Active interrupt bits */ - .pushsection .data omap_irq_base: .word 0 .popsection @@ -90,8 +91,6 @@ omap_irq_base: .word 0 #ifdef CONFIG_ARCH_OMAP4 -#define OMAP44XX_VA_GIC_CPU_BASE OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE) - .macro get_irqnr_preamble, base, tmp .endm @@ -115,7 +114,7 @@ omap_irq_base: .word 0 * valid range for an IRQ (30-1020 inclusive). */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =OMAP44XX_VA_GIC_CPU_BASE + ldr \base, =OMAP4_IRQ_BASE ldr \irqstat, [\base, #GIC_CPU_INTACK] ldr \tmp, =1021 -- GitLab From be8f317740f218bda59cc5ae5aefcdd7a333762a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2090/3892] omap4: Use get_irqnr_preamble Use get_irqnr_preamble Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/include/mach/entry-macro.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index 3e63aaabebe7..101ed79deec4 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -92,6 +92,7 @@ omap_irq_base: .word 0 #ifdef CONFIG_ARCH_OMAP4 .macro get_irqnr_preamble, base, tmp + ldr \base, =OMAP4_IRQ_BASE .endm /* @@ -114,7 +115,6 @@ omap_irq_base: .word 0 * valid range for an IRQ (30-1020 inclusive). */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =OMAP4_IRQ_BASE ldr \irqstat, [\base, #GIC_CPU_INTACK] ldr \tmp, =1021 -- GitLab From e735aa8a20fdc60439141b7b0c0382a3ce031f3b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2091/3892] omap2/3/4: Clean up entry-macro.s for adding support for omap4 multiboot Move defines around and set up handlers based on MULTI_OMAP2. Note that this will only allow compiling in omap4 with omap2 and omap3. It will not yet make omap4 boot with multi-omap. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- .../arm/mach-omap2/include/mach/entry-macro.S | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index 101ed79deec4..fe3c9ad59450 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -19,6 +19,8 @@ #include #include +#include + #define OMAP2_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE) #define OMAP3_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) #define OMAP4_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE) @@ -31,13 +33,15 @@ .macro arch_ret_to_user, tmp1, tmp2 .endm -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) +/* + * Unoptimized irq functions for multi-omap2, 3 and 4 + */ +#ifdef MULTI_OMAP2 .pushsection .data omap_irq_base: .word 0 .popsection -#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_ARCH_OMAP3) /* Configure the interrupt base on the first interrupt */ .macro get_irqnr_preamble, base, tmp 9: @@ -62,7 +66,32 @@ omap_irq_base: .word 0 b 9b 9998: .endm -#else + + /* Check the pending interrupts. Note that base already set */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */ + cmp \irqnr, #0x0 + bne 9999f + ldr \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */ + cmp \irqnr, #0x0 + bne 9999f + ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */ + cmp \irqnr, #0x0 +9999: + ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET] + and \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */ + + .endm + + +#else /* MULTI_OMAP2 */ + + +/* + * Optimized irq functions for omap2, 3 and 4 + */ + +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) .macro get_irqnr_preamble, base, tmp #ifdef CONFIG_ARCH_OMAP2 ldr \base, =OMAP2_IRQ_BASE @@ -70,7 +99,7 @@ omap_irq_base: .word 0 ldr \base, =OMAP3_IRQ_BASE #endif .endm -#endif + /* Check the pending interrupts. Note that base already set */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */ @@ -155,6 +184,7 @@ omap_irq_base: .word 0 cmp \tmp, #0 .endm #endif +#endif /* MULTI_OMAP2 */ .macro irq_prio_table .endm -- GitLab From 61a07c80a7cf7333475e7eda9934dac9a8a9c8b9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2092/3892] omap2/3/4: Allow booting omap4 with multi-omap configuration Allow booting omap4 with multi-omap configuration. Tested only on omap2 and omap3, please somebody test on omap4 and ack. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- .../arm/mach-omap2/include/mach/entry-macro.S | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index fe3c9ad59450..ff25c7e4e606 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -48,14 +48,18 @@ omap_irq_base: .word 0 ldr \base, =omap_irq_base @ irq base address ldr \base, [\base, #0] @ irq base value cmp \base, #0 @ already configured? - bne 9998f @ nothing to do + bne 9997f @ nothing to do mrc p15, 0, \tmp, c0, c0, 0 @ get processor revision and \tmp, \tmp, #0x000f0000 @ only check architecture cmp \tmp, #0x00060000 @ is v6? beq 2400f @ found v6 so it's omap24xx - cmp \tmp, #0x000f0000 @ is cortex? - beq 3400f @ found v7 so it's omap34xx + mrc p15, 0, \tmp, c0, c0, 0 @ get processor revision + and \tmp, \tmp, #0x000000f0 @ check cortex 8 or 9 + cmp \tmp, #0x00000080 @ cortex A-8? + beq 3400f @ found A-8 so it's omap34xx + cmp \tmp, #0x00000090 @ cortex A-9? + beq 4400f @ found A-9 so it's omap44xx 2400: ldr \base, =OMAP2_IRQ_BASE ldr \tmp, =omap_irq_base str \base, [\tmp, #0] @@ -64,23 +68,41 @@ omap_irq_base: .word 0 ldr \tmp, =omap_irq_base str \base, [\tmp, #0] b 9b -9998: +4400: ldr \base, =OMAP4_IRQ_BASE + ldr \tmp, =omap_irq_base + str \base, [\tmp, #0] + b 9b +9997: .endm /* Check the pending interrupts. Note that base already set */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + tst \base, #0x100 @ gic address? + bne 4401f @ found gic + + /* Handle omap2 and omap3 */ ldr \irqnr, [\base, #0x98] /* IRQ pending reg 1 */ cmp \irqnr, #0x0 - bne 9999f + bne 9998f ldr \irqnr, [\base, #0xb8] /* IRQ pending reg 2 */ cmp \irqnr, #0x0 - bne 9999f + bne 9998f ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */ cmp \irqnr, #0x0 -9999: +9998: ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET] and \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */ + b 9999f + /* Handle omap4 */ +4401: ldr \irqstat, [\base, #GIC_CPU_INTACK] + ldr \tmp, =1021 + bic \irqnr, \irqstat, #0x1c00 + cmp \irqnr, #29 + cmpcc \irqnr, \irqnr + cmpne \irqnr, \tmp + cmpcs \irqnr, \irqnr +9999: .endm -- GitLab From 4751227df948582e82f19df30efa662ab71fa980 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2093/3892] omap3/4: Fix compile for multi-omap for clkops_noncore_dpll_ops Rename clkops_noncore_dpll_ops for omap3 and omap4. Acked-by: Santosh Shilimkar Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock34xx.c | 2 +- arch/arm/mach-omap2/clock34xx.h | 2 +- arch/arm/mach-omap2/clock34xx_data.c | 6 +++--- arch/arm/mach-omap2/clock44xx.c | 2 +- arch/arm/mach-omap2/clock44xx.h | 2 +- arch/arm/mach-omap2/clock44xx_data.c | 12 ++++++------ 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 1f1b5a6b3eea..ae9e2c82eb6a 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -130,7 +130,7 @@ const struct clkops clkops_omap3430es2_hsotgusb_wait = { .find_companion = omap2_clk_dflt_find_companion, }; -const struct clkops clkops_noncore_dpll_ops = { +const struct clkops omap3_clkops_noncore_dpll_ops = { .enable = omap3_noncore_dpll_enable, .disable = omap3_noncore_dpll_disable, }; diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index 73f2109d6436..313efc0e5a0f 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -20,6 +20,6 @@ extern struct clk *arm_fck_p; extern const struct clkops clkops_omap3430es2_ssi_wait; extern const struct clkops clkops_omap3430es2_hsotgusb_wait; extern const struct clkops clkops_omap3430es2_dss_usbhost_wait; -extern const struct clkops clkops_noncore_dpll_ops; +extern const struct clkops omap3_clkops_noncore_dpll_ops; #endif diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c index 0d04f92f63e1..8728f1fbc5b1 100644 --- a/arch/arm/mach-omap2/clock34xx_data.c +++ b/arch/arm/mach-omap2/clock34xx_data.c @@ -337,7 +337,7 @@ static struct dpll_data dpll2_dd = { static struct clk dpll2_ck = { .name = "dpll2_ck", - .ops = &clkops_noncore_dpll_ops, + .ops = &omap3_clkops_noncore_dpll_ops, .parent = &sys_ck, .dpll_data = &dpll2_dd, .round_rate = &omap2_dpll_round_rate, @@ -554,7 +554,7 @@ static struct dpll_data dpll4_dd = { static struct clk dpll4_ck = { .name = "dpll4_ck", - .ops = &clkops_noncore_dpll_ops, + .ops = &omap3_clkops_noncore_dpll_ops, .parent = &sys_ck, .dpll_data = &dpll4_dd, .round_rate = &omap2_dpll_round_rate, @@ -854,7 +854,7 @@ static struct dpll_data dpll5_dd = { static struct clk dpll5_ck = { .name = "dpll5_ck", - .ops = &clkops_noncore_dpll_ops, + .ops = &omap3_clkops_noncore_dpll_ops, .parent = &sys_ck, .dpll_data = &dpll5_dd, .round_rate = &omap2_dpll_round_rate, diff --git a/arch/arm/mach-omap2/clock44xx.c b/arch/arm/mach-omap2/clock44xx.c index c238717e3760..84ee6b0c7995 100644 --- a/arch/arm/mach-omap2/clock44xx.c +++ b/arch/arm/mach-omap2/clock44xx.c @@ -13,7 +13,7 @@ #include #include "clock.h" -const struct clkops clkops_noncore_dpll_ops = { +const struct clkops omap4_clkops_noncore_dpll_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, }; diff --git a/arch/arm/mach-omap2/clock44xx.h b/arch/arm/mach-omap2/clock44xx.h index 1f55b6b574fb..efe849416aac 100644 --- a/arch/arm/mach-omap2/clock44xx.h +++ b/arch/arm/mach-omap2/clock44xx.h @@ -12,6 +12,6 @@ int omap4xxx_clk_init(void); -extern const struct clkops clkops_noncore_dpll_ops; +extern const struct clkops omap4_clkops_noncore_dpll_ops; #endif diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 35ffe638def8..86af31d80a34 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -279,7 +279,7 @@ static struct clk dpll_abe_ck = { .parent = &abe_dpll_refclk_mux_ck, .dpll_data = &dpll_abe_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, @@ -668,7 +668,7 @@ static struct clk dpll_iva_ck = { .parent = &dpll_sys_ref_clk, .dpll_data = &dpll_iva_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, @@ -731,7 +731,7 @@ static struct clk dpll_mpu_ck = { .parent = &dpll_sys_ref_clk, .dpll_data = &dpll_mpu_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, @@ -807,7 +807,7 @@ static struct clk dpll_per_ck = { .parent = &dpll_sys_ref_clk, .dpll_data = &dpll_per_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, @@ -930,7 +930,7 @@ static struct clk dpll_unipro_ck = { .parent = &dpll_sys_ref_clk, .dpll_data = &dpll_unipro_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, @@ -988,7 +988,7 @@ static struct clk dpll_usb_ck = { .parent = &dpll_sys_ref_clk, .dpll_data = &dpll_usb_dd, .init = &omap2_init_dpll_parent, - .ops = &clkops_noncore_dpll_ops, + .ops = &omap4_clkops_noncore_dpll_ops, .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, -- GitLab From 3f1686a9bfe74979c6ad538c78039730f665f77e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2094/3892] omap: Fix gpio.c for multi-omap for omap4 Set up METHOD_GPIO_44XX instead of trying to use the METHOD_GPIO_24XX. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/gpio.c | 224 ++++++++++++++++++++++---------------- 1 file changed, 133 insertions(+), 91 deletions(-) diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index a888304b8383..6055028dff1e 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -202,6 +202,7 @@ struct gpio_bank { #define METHOD_GPIO_1610 2 #define METHOD_GPIO_7XX 3 #define METHOD_GPIO_24XX 5 +#define METHOD_GPIO_44XX 6 #ifdef CONFIG_ARCH_OMAP16XX static struct gpio_bank gpio_bank_1610[5] = { @@ -312,17 +313,17 @@ static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; #ifdef CONFIG_ARCH_OMAP4 static struct gpio_bank gpio_bank_44xx[6] = { { OMAP44XX_GPIO1_BASE, NULL, INT_44XX_GPIO_BANK1, IH_GPIO_BASE, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, { OMAP44XX_GPIO2_BASE, NULL, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, { OMAP44XX_GPIO3_BASE, NULL, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, { OMAP44XX_GPIO4_BASE, NULL, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, { OMAP44XX_GPIO5_BASE, NULL, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, { OMAP44XX_GPIO6_BASE, NULL, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160, - METHOD_GPIO_24XX }, + METHOD_GPIO_44XX }, }; #endif @@ -430,7 +431,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) break; #endif #if defined(CONFIG_ARCH_OMAP4) - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP4_GPIO_OE; break; #endif @@ -501,7 +502,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) break; #endif #ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: if (enable) reg += OMAP4_GPIO_SETDATAOUT; else @@ -550,7 +551,7 @@ static int _get_gpio_datain(struct gpio_bank *bank, int gpio) break; #endif #ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP4_GPIO_DATAIN; break; #endif @@ -592,6 +593,7 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) #endif #ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP24XX_GPIO_DATAOUT; break; #endif @@ -622,11 +624,12 @@ void omap_set_gpio_debounce(int gpio, int enable) bank = get_gpio_bank(gpio); reg = bank->base; -#ifdef CONFIG_ARCH_OMAP4 - reg += OMAP4_GPIO_DEBOUNCENABLE; -#else - reg += OMAP24XX_GPIO_DEBOUNCE_EN; -#endif + + if (cpu_is_omap44xx()) + reg += OMAP4_GPIO_DEBOUNCENABLE; + else + reg += OMAP24XX_GPIO_DEBOUNCE_EN; + if (!(bank->mod_usage & l)) { printk(KERN_ERR "GPIO %d not requested\n", gpio); return; @@ -672,11 +675,12 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time) } enc_time &= 0xff; -#ifdef CONFIG_ARCH_OMAP4 - reg += OMAP4_GPIO_DEBOUNCINGTIME; -#else - reg += OMAP24XX_GPIO_DEBOUNCE_VAL; -#endif + + if (cpu_is_omap44xx()) + reg += OMAP4_GPIO_DEBOUNCINGTIME; + else + reg += OMAP24XX_GPIO_DEBOUNCE_VAL; + __raw_writel(enc_time, reg); } EXPORT_SYMBOL(omap_set_gpio_debounce_time); @@ -854,6 +858,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) #endif #ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: set_24xx_gpio_triggering(bank, gpio, trigger); break; #endif @@ -938,7 +943,7 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) break; #endif #if defined(CONFIG_ARCH_OMAP4) - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP4_GPIO_IRQSTATUS0; break; #endif @@ -949,12 +954,11 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; -#endif -#if defined(CONFIG_ARCH_OMAP4) - reg = bank->base + OMAP4_GPIO_IRQSTATUS1; -#endif + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; + else if (cpu_is_omap44xx()) + reg = bank->base + OMAP4_GPIO_IRQSTATUS1; + if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap44xx()) { __raw_writel(gpio_mask, reg); @@ -1010,7 +1014,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) break; #endif #if defined(CONFIG_ARCH_OMAP4) - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP4_GPIO_IRQSTATUSSET0; mask = 0xffffffff; break; @@ -1082,7 +1086,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab break; #endif #ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: if (enable) reg += OMAP4_GPIO_IRQSTATUSSET0; else @@ -1128,6 +1132,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) #endif #ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: if (bank->non_wakeup_gpios & (1 << gpio)) { printk(KERN_ERR "Unable to modify wakeup on " "non-wakeup GPIO%d\n", @@ -1222,7 +1227,8 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) } #endif #ifdef CONFIG_ARCH_OMAP2PLUS - if (bank->method == METHOD_GPIO_24XX) { + if ((bank->method == METHOD_GPIO_24XX) || + (bank->method == METHOD_GPIO_44XX)) { /* Disable wake-up during idle for dynamic tick */ void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; __raw_writel(1 << offset, reg); @@ -1284,7 +1290,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif #if defined(CONFIG_ARCH_OMAP4) - if (bank->method == METHOD_GPIO_24XX) + if (bank->method == METHOD_GPIO_44XX) isr_reg = bank->base + OMAP4_GPIO_IRQSTATUS0; #endif while(1) { @@ -1564,6 +1570,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) reg += OMAP7XX_GPIO_DIR_CONTROL; break; case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: reg += OMAP24XX_GPIO_OE; break; } @@ -1803,28 +1810,41 @@ static int __init _omap_gpio_init(void) } #ifdef CONFIG_ARCH_OMAP2PLUS - if (bank->method == METHOD_GPIO_24XX) { + if ((bank->method == METHOD_GPIO_24XX) || + (bank->method == METHOD_GPIO_44XX)) { static const u32 non_wakeup_gpios[] = { 0xe203ffc0, 0x08700040 }; - if (cpu_is_omap44xx()) { - __raw_writel(0xffffffff, bank->base + + + if (cpu_is_omap44xx()) { + __raw_writel(0xffffffff, bank->base + OMAP4_GPIO_IRQSTATUSCLR0); - __raw_writew(0x0015, bank->base + + __raw_writew(0x0015, bank->base + OMAP4_GPIO_SYSCONFIG); - __raw_writel(0x00000000, bank->base + + __raw_writel(0x00000000, bank->base + OMAP4_GPIO_DEBOUNCENABLE); - /* Initialize interface clock ungated, module enabled */ - __raw_writel(0, bank->base + OMAP4_GPIO_CTRL); - } else { - __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1); - __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG); - __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_DEBOUNCE_EN); - - /* Initialize interface clock ungated, module enabled */ - __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); - } + /* + * Initialize interface clock ungated, + * module enabled + */ + __raw_writel(0, bank->base + OMAP4_GPIO_CTRL); + } else { + __raw_writel(0x00000000, bank->base + + OMAP24XX_GPIO_IRQENABLE1); + __raw_writel(0xffffffff, bank->base + + OMAP24XX_GPIO_IRQSTATUS1); + __raw_writew(0x0015, bank->base + + OMAP24XX_GPIO_SYSCONFIG); + __raw_writel(0x00000000, bank->base + + OMAP24XX_GPIO_DEBOUNCE_EN); + + /* + * Initialize interface clock ungated, + * module enabled + */ + __raw_writel(0, bank->base + + OMAP24XX_GPIO_CTRL); + } if (i < ARRAY_SIZE(non_wakeup_gpios)) bank->non_wakeup_gpios = non_wakeup_gpios[i]; gpio_count = 32; @@ -1926,7 +1946,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) break; #endif #ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0; wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; @@ -1973,7 +1993,7 @@ static int omap_gpio_resume(struct sys_device *dev) break; #endif #ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; break; @@ -2020,29 +2040,42 @@ void omap2_gpio_prepare_for_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); - l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); -#endif -#ifdef CONFIG_ARCH_OMAP4 - bank->saved_datain = __raw_readl(bank->base + - OMAP4_GPIO_DATAIN); - l1 = __raw_readl(bank->base + OMAP4_GPIO_FALLINGDETECT); - l2 = __raw_readl(bank->base + OMAP4_GPIO_RISINGDETECT); -#endif + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + bank->saved_datain = __raw_readl(bank->base + + OMAP24XX_GPIO_DATAIN); + l1 = __raw_readl(bank->base + + OMAP24XX_GPIO_FALLINGDETECT); + l2 = __raw_readl(bank->base + + OMAP24XX_GPIO_RISINGDETECT); + } + + if (cpu_is_omap44xx()) { + bank->saved_datain = __raw_readl(bank->base + + OMAP4_GPIO_DATAIN); + l1 = __raw_readl(bank->base + + OMAP4_GPIO_FALLINGDETECT); + l2 = __raw_readl(bank->base + + OMAP4_GPIO_RISINGDETECT); + } + bank->saved_fallingdetect = l1; bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); -#endif -#ifdef CONFIG_ARCH_OMAP4 - __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); -#endif + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + __raw_writel(l1, bank->base + + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + + OMAP24XX_GPIO_RISINGDETECT); + } + + if (cpu_is_omap44xx()) { + __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); + } + c++; } if (!c) { @@ -2064,20 +2097,23 @@ void omap2_gpio_resume_after_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - __raw_writel(bank->saved_fallingdetect, + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + __raw_writel(bank->saved_fallingdetect, bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, + __raw_writel(bank->saved_risingdetect, bank->base + OMAP24XX_GPIO_RISINGDETECT); - l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); -#endif -#ifdef CONFIG_ARCH_OMAP4 - __raw_writel(bank->saved_fallingdetect, + l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); + } + + if (cpu_is_omap44xx()) { + __raw_writel(bank->saved_fallingdetect, bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, + __raw_writel(bank->saved_risingdetect, bank->base + OMAP4_GPIO_RISINGDETECT); - l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN); -#endif + l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN); + } + /* Check if any of the non-wakeup interrupt GPIOs have changed * state. If so, generate an IRQ by software. This is * horribly racy, but it's the best we can do to work around @@ -2103,30 +2139,36 @@ void omap2_gpio_resume_after_retention(void) if (gen) { u32 old0, old1; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); - old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + + if (cpu_is_omap24xx() || cpu_is_omap44xx()) { + old0 = __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT0); + old1 = __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT1); __raw_writel(old0 | gen, bank->base + OMAP24XX_GPIO_LEVELDETECT0); __raw_writel(old1 | gen, bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1); -#endif -#ifdef CONFIG_ARCH_OMAP4 - old0 = __raw_readl(bank->base + + __raw_writel(old0, bank->base + + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(old1, bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + } + + if (cpu_is_omap44xx()) { + old0 = __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0); - old1 = __raw_readl(bank->base + + old1 = __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1); - __raw_writel(old0 | l, bank->base + + __raw_writel(old0 | l, bank->base + OMAP4_GPIO_LEVELDETECT0); - __raw_writel(old1 | l, bank->base + + __raw_writel(old1 | l, bank->base + OMAP4_GPIO_LEVELDETECT1); - __raw_writel(old0, bank->base + + __raw_writel(old0, bank->base + OMAP4_GPIO_LEVELDETECT0); - __raw_writel(old1, bank->base + + __raw_writel(old1, bank->base + OMAP4_GPIO_LEVELDETECT1); -#endif + } } } -- GitLab From a3a9b36e6b1c420088460af8e83ba7b83330669f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2095/3892] omap2/3/4: Fix mach-omap2/serial.c for multiboot Initialize UART4 only for 3630 and 44xx. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/serial.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index e657674d5490..2b784002bf77 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -114,7 +114,7 @@ static struct plat_serial8250_port serial_platform_data2[] = { } }; -#ifdef CONFIG_ARCH_OMAP4 +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) static struct plat_serial8250_port serial_platform_data3[] = { { .irq = 70, @@ -126,6 +126,15 @@ static struct plat_serial8250_port serial_platform_data3[] = { .flags = 0 } }; + +static inline void omap2_set_globals_uart4(struct omap_globals *omap2_globals) +{ + serial_platform_data3[0].mapbase = omap2_globals->uart4_phys; +} +#else +static inline void omap2_set_globals_uart4(struct omap_globals *omap2_globals) +{ +} #endif void __init omap2_set_globals_uart(struct omap_globals *omap2_globals) @@ -133,9 +142,8 @@ void __init omap2_set_globals_uart(struct omap_globals *omap2_globals) serial_platform_data0[0].mapbase = omap2_globals->uart1_phys; serial_platform_data1[0].mapbase = omap2_globals->uart2_phys; serial_platform_data2[0].mapbase = omap2_globals->uart3_phys; -#ifdef CONFIG_ARCH_OMAP4 - serial_platform_data3[0].mapbase = omap2_globals->uart4_phys; -#endif + if (cpu_is_omap3630() || cpu_is_omap44xx()) + omap2_set_globals_uart4(omap2_globals); } static inline unsigned int __serial_read_reg(struct uart_port *up, @@ -581,7 +589,7 @@ static struct omap_uart_state omap_uart[] = { }, }, }, -#ifdef CONFIG_ARCH_OMAP4 +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) { .pdev = { .name = "serial8250", @@ -728,8 +736,13 @@ void __init omap_serial_init_port(int port) */ void __init omap_serial_init(void) { - int i; + int i, nr_ports; + + if (!(cpu_is_omap3630() || cpu_is_omap4430())) + nr_ports = 3; + else + nr_ports = ARRAY_SIZE(omap_uart); - for (i = 0; i < ARRAY_SIZE(omap_uart); i++) + for (i = 0; i < nr_ports; i++) omap_serial_init_port(i); } -- GitLab From fd17a25fe9423bbde16a326466330ad486321dfc Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 09:27:25 -0800 Subject: [PATCH 2096/3892] omap2/3/4: Add omap4 into omap3_defconfig Add omap4 into omap3_defconfig. Note that this does not yet boot on omap4, but boots on omap2 and omap3. Also note that CONFIG_SMP does not currently work on uniprocessor ARMs. Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/configs/omap3_defconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/omap3_defconfig b/arch/arm/configs/omap3_defconfig index 2bc80d7532b9..714835e5ebec 100644 --- a/arch/arm/configs/omap3_defconfig +++ b/arch/arm/configs/omap3_defconfig @@ -239,7 +239,7 @@ CONFIG_ARCH_OMAP_OTG=y CONFIG_ARCH_OMAP2PLUS=y CONFIG_ARCH_OMAP2=y CONFIG_ARCH_OMAP3=y -# CONFIG_ARCH_OMAP4 is not set +CONFIG_ARCH_OMAP4=y # # OMAP Feature Selections @@ -295,6 +295,7 @@ CONFIG_MACH_OMAP_ZOOM3=y CONFIG_MACH_CM_T35=y CONFIG_MACH_IGEP0020=y CONFIG_MACH_OMAP_3630SDP=y +CONFIG_MACH_OMAP_4430SDP=y # CONFIG_OMAP3_EMU is not set # CONFIG_OMAP3_SDRC_AC_TIMING is not set @@ -334,6 +335,7 @@ CONFIG_ARM_L1_CACHE_SHIFT=6 # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set +CONFIG_ARM_GIC=y CONFIG_COMMON_CLKDEV=y # @@ -350,6 +352,7 @@ CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_SMP is not set CONFIG_VMSPLIT_3G=y # CONFIG_VMSPLIT_2G is not set # CONFIG_VMSPLIT_1G is not set @@ -361,6 +364,7 @@ CONFIG_HZ=128 # CONFIG_THUMB2_KERNEL is not set CONFIG_AEABI=y CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set # CONFIG_HIGHMEM is not set -- GitLab From 561b036ad9d0b4f0cd311d2e38025919c2cb437f Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2097/3892] omap: convert boards to use physmap-flash Convert OMAP based boards to use physmap-flash. Refreshed against today's Linux omap kernel tree Cc: linux-mtd@lists.infradead.org Signed-off-by: Ladislav Michl Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/Makefile | 2 +- arch/arm/mach-omap1/board-fsample.c | 9 ++++--- arch/arm/mach-omap1/board-h2.c | 9 ++++--- arch/arm/mach-omap1/board-h3.c | 9 ++++--- arch/arm/mach-omap1/board-innovator.c | 9 ++++--- arch/arm/mach-omap1/board-osk.c | 9 ++++--- arch/arm/mach-omap1/board-palmte.c | 9 ++++--- arch/arm/mach-omap1/board-palmtt.c | 9 ++++--- arch/arm/mach-omap1/board-palmz71.c | 10 ++++---- arch/arm/mach-omap1/board-perseus2.c | 9 ++++--- arch/arm/mach-omap1/board-sx1.c | 11 +++++---- arch/arm/mach-omap1/board-voiceblue.c | 9 ++++--- arch/arm/mach-omap1/flash.c | 33 +++++++++++++++++++++++++ arch/arm/mach-omap2/board-2430sdp.c | 7 +++--- arch/arm/mach-omap2/board-h4.c | 7 +++--- arch/arm/plat-omap/include/plat/flash.h | 16 ++++++++++++ 16 files changed, 112 insertions(+), 55 deletions(-) create mode 100644 arch/arm/mach-omap1/flash.c create mode 100644 arch/arm/plat-omap/include/plat/flash.h diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 9ce17f13d3f1..b6a537c875b8 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := io.o id.o sram.o irq.o mux.o serial.o devices.o +obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o obj-y += clock.o clock_data.o opp_data.o obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c index 7e70c3c08da6..096f2ed102cb 100644 --- a/arch/arm/mach-omap1/board-fsample.c +++ b/arch/arm/mach-omap1/board-fsample.c @@ -18,18 +18,19 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -150,9 +151,9 @@ static struct mtd_partition nor_partitions[] = { }, }; -static struct flash_platform_data nor_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data nor_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = nor_partitions, .nr_parts = ARRAY_SIZE(nor_partitions), }; @@ -164,7 +165,7 @@ static struct resource nor_resource = { }; static struct platform_device nor_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &nor_data, diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index fa7cecea19f9..d1100e4f65ac 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include -#include #include #include @@ -45,6 +45,7 @@ #include #include #include +#include #include "board-h2.h" @@ -121,9 +122,9 @@ static struct mtd_partition h2_nor_partitions[] = { } }; -static struct flash_platform_data h2_nor_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data h2_nor_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = h2_nor_partitions, .nr_parts = ARRAY_SIZE(h2_nor_partitions), }; @@ -134,7 +135,7 @@ static struct resource h2_nor_resource = { }; static struct platform_device h2_nor_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &h2_nor_data, diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 6a7f9c391cf1..a53ab8297d25 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ #include #include -#include #include #include @@ -47,6 +47,7 @@ #include #include #include +#include #include "board-h3.h" @@ -126,9 +127,9 @@ static struct mtd_partition nor_partitions[] = { } }; -static struct flash_platform_data nor_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data nor_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = nor_partitions, .nr_parts = ARRAY_SIZE(nor_partitions), }; @@ -139,7 +140,7 @@ static struct resource nor_resource = { }; static struct platform_device nor_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &nor_data, diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index 2133b006f6a3..5d12fd35681b 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -22,16 +22,17 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -94,9 +95,9 @@ static struct mtd_partition innovator_partitions[] = { } }; -static struct flash_platform_data innovator_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data innovator_flash_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = innovator_partitions, .nr_parts = ARRAY_SIZE(innovator_partitions), }; @@ -108,7 +109,7 @@ static struct resource innovator_flash_resource = { }; static struct platform_device innovator_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &innovator_flash_data, diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index ccea4f448e9a..80d862001def 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -37,6 +37,7 @@ #include #include +#include #include @@ -46,8 +47,8 @@ #include #include #include -#include +#include #include #include #include @@ -94,9 +95,9 @@ static struct mtd_partition osk_partitions[] = { } }; -static struct flash_platform_data osk_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data osk_flash_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = osk_partitions, .nr_parts = ARRAY_SIZE(osk_partitions), }; @@ -107,7 +108,7 @@ static struct resource osk_flash_resource = { }; static struct platform_device osk5912_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &osk_flash_data, diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c index 9fe887262bdf..569b4c9085cd 100644 --- a/arch/arm/mach-omap1/board-palmte.c +++ b/arch/arm/mach-omap1/board-palmte.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -31,9 +32,9 @@ #include #include #include -#include #include +#include #include #include #include @@ -126,9 +127,9 @@ static struct mtd_partition palmte_rom_partitions[] = { }, }; -static struct flash_platform_data palmte_rom_data = { - .map_name = "map_rom", +static struct physmap_flash_data palmte_rom_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = palmte_rom_partitions, .nr_parts = ARRAY_SIZE(palmte_rom_partitions), }; @@ -140,7 +141,7 @@ static struct resource palmte_rom_resource = { }; static struct platform_device palmte_rom_device = { - .name = "omapflash", + .name = "physmap-flash", .id = -1, .dev = { .platform_data = &palmte_rom_data, diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c index af068e3e0fe7..6ad49a2cc1a0 100644 --- a/arch/arm/mach-omap1/board-palmtt.c +++ b/arch/arm/mach-omap1/board-palmtt.c @@ -21,16 +21,17 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -104,9 +105,9 @@ static struct mtd_partition palmtt_partitions[] = { } }; -static struct flash_platform_data palmtt_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data palmtt_flash_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = palmtt_partitions, .nr_parts = ARRAY_SIZE(palmtt_partitions), }; @@ -118,7 +119,7 @@ static struct resource palmtt_flash_resource = { }; static struct platform_device palmtt_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &palmtt_flash_data, diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c index c7a3b6f36500..6641de9257ef 100644 --- a/arch/arm/mach-omap1/board-palmz71.c +++ b/arch/arm/mach-omap1/board-palmz71.c @@ -25,14 +25,15 @@ #include #include #include +#include #include #include #include #include -#include #include +#include #include #include #include @@ -126,10 +127,9 @@ static struct mtd_partition palmz71_rom_partitions[] = { }, }; -static struct flash_platform_data palmz71_rom_data = { - .map_name = "map_rom", - .name = "onboardrom", +static struct physmap_flash_data palmz71_rom_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = palmz71_rom_partitions, .nr_parts = ARRAY_SIZE(palmz71_rom_partitions), }; @@ -141,7 +141,7 @@ static struct resource palmz71_rom_resource = { }; static struct platform_device palmz71_rom_device = { - .name = "omapflash", + .name = "physmap-flash", .id = -1, .dev = { .platform_data = &palmz71_rom_data, diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 1387a4f15da9..e854d5741c88 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -18,19 +18,20 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -117,9 +118,9 @@ static struct mtd_partition nor_partitions[] = { }, }; -static struct flash_platform_data nor_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data nor_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = nor_partitions, .nr_parts = ARRAY_SIZE(nor_partitions), }; @@ -131,7 +132,7 @@ static struct resource nor_resource = { }; static struct platform_device nor_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &nor_data, diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c index 7a97fac83d8d..2fb1e5f8e2ec 100644 --- a/arch/arm/mach-omap1/board-sx1.c +++ b/arch/arm/mach-omap1/board-sx1.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -29,10 +30,10 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -287,9 +288,9 @@ static struct mtd_partition sx1_partitions[] = { } }; -static struct flash_platform_data sx1_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data sx1_flash_data = { .width = 2, + .set_vpp = omap1_set_vpp, .parts = sx1_partitions, .nr_parts = ARRAY_SIZE(sx1_partitions), }; @@ -310,7 +311,7 @@ static struct resource sx1_old_flash_resource[] = { }; static struct platform_device sx1_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &sx1_flash_data, @@ -327,7 +328,7 @@ static struct resource sx1_new_flash_resource = { }; static struct platform_device sx1_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &sx1_flash_data, diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 169183537997..87b9436fe7c0 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,11 +28,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -86,9 +87,9 @@ static int __init ext_uart_init(void) } arch_initcall(ext_uart_init); -static struct flash_platform_data voiceblue_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data voiceblue_flash_data = { .width = 2, + .set_vpp = omap1_set_vpp, }; static struct resource voiceblue_flash_resource = { @@ -98,7 +99,7 @@ static struct resource voiceblue_flash_resource = { }; static struct platform_device voiceblue_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &voiceblue_flash_data, diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c new file mode 100644 index 000000000000..0b07a78eeaa7 --- /dev/null +++ b/arch/arm/mach-omap1/flash.c @@ -0,0 +1,33 @@ +/* + * Flash support for OMAP1 + * + * 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 + +void omap1_set_vpp(struct map_info *map, int enable) +{ + static int count; + u32 l; + + if (enable) { + if (count++ == 0) { + l = omap_readl(EMIFS_CONFIG); + l |= OMAP_EMIFS_CONFIG_WP; + omap_writel(l, EMIFS_CONFIG); + } + } else { + if (count && (--count == 0)) { + l = omap_readl(EMIFS_CONFIG); + l &= ~OMAP_EMIFS_CONFIG_WP; + omap_writel(l, EMIFS_CONFIG); + } + } +} diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 1a619787bd80..18497b7a8278 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include @@ -74,8 +74,7 @@ static struct mtd_partition sdp2430_partitions[] = { } }; -static struct flash_platform_data sdp2430_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data sdp2430_flash_data = { .width = 2, .parts = sdp2430_partitions, .nr_parts = ARRAY_SIZE(sdp2430_partitions), @@ -88,7 +87,7 @@ static struct resource sdp2430_flash_resource = { }; static struct platform_device sdp2430_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &sdp2430_flash_data, diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 5c49c407dd51..0665f2c8dc8e 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include @@ -115,8 +115,7 @@ static struct mtd_partition h4_partitions[] = { } }; -static struct flash_platform_data h4_flash_data = { - .map_name = "cfi_probe", +static struct physmap_flash_data h4_flash_data = { .width = 2, .parts = h4_partitions, .nr_parts = ARRAY_SIZE(h4_partitions), @@ -127,7 +126,7 @@ static struct resource h4_flash_resource = { }; static struct platform_device h4_flash_device = { - .name = "omapflash", + .name = "physmap-flash", .id = 0, .dev = { .platform_data = &h4_flash_data, diff --git a/arch/arm/plat-omap/include/plat/flash.h b/arch/arm/plat-omap/include/plat/flash.h new file mode 100644 index 000000000000..3e6327016b40 --- /dev/null +++ b/arch/arm/plat-omap/include/plat/flash.h @@ -0,0 +1,16 @@ +/* + * Flash support for OMAP1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __OMAP_FLASH_H +#define __OMAP_FLASH_H + +#include + +extern void omap1_set_vpp(struct map_info *map, int enable); + +#endif -- GitLab From cc87edb173effdf74e680ee6d622a935ff0c1d6f Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2098/3892] MTD: remove no longer used OMAP flash map All OMAP boards are now using physmap-flash. Cc: linux-mtd@lists.infradead.org Signed-off-by: Ladislav Michl Signed-off-by: Tony Lindgren --- drivers/mtd/maps/Kconfig | 9 -- drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/omap_nor.c | 188 ------------------------------------ 3 files changed, 198 deletions(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 2de0cc823d60..9605cb87c746 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -428,15 +428,6 @@ config MTD_H720X This enables access to the flash chips on the Hynix evaluation boards. If you have such a board, say 'Y'. -config MTD_OMAP_NOR - tristate "TI OMAP board mappings" - depends on MTD_CFI && ARCH_OMAP - help - This enables access to the NOR flash chips on TI OMAP-based - boards defining flash platform devices and flash platform data. - These boards include the Innovator, H2, H3, OSK, Perseus2, and - more. If you have such a board, say 'Y'. - # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index ce315214ff2b..faa9fef19585 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o -obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index ead0b2fab670..e69de29bb2d1 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -1,188 +0,0 @@ -/* - * Flash memory support for various TI OMAP boards - * - * Copyright (C) 2001-2002 MontaVista Software Inc. - * Copyright (C) 2003-2004 Texas Instruments - * Copyright (C) 2004 Nokia Corporation - * - * Assembled using driver code copyright the companies above - * and written by David Brownell, Jian Zhang , - * Tony Lindgren and others. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL }; -#endif - -struct omapflash_info { - struct mtd_partition *parts; - struct mtd_info *mtd; - struct map_info map; -}; - -static void omap_set_vpp(struct map_info *map, int enable) -{ - static int count; - u32 l; - - if (cpu_class_is_omap1()) { - if (enable) { - if (count++ == 0) { - l = omap_readl(EMIFS_CONFIG); - l |= OMAP_EMIFS_CONFIG_WP; - omap_writel(l, EMIFS_CONFIG); - } - } else { - if (count && (--count == 0)) { - l = omap_readl(EMIFS_CONFIG); - l &= ~OMAP_EMIFS_CONFIG_WP; - omap_writel(l, EMIFS_CONFIG); - } - } - } -} - -static int __init omapflash_probe(struct platform_device *pdev) -{ - int err; - struct omapflash_info *info; - struct flash_platform_data *pdata = pdev->dev.platform_data; - struct resource *res = pdev->resource; - unsigned long size = res->end - res->start + 1; - - info = kzalloc(sizeof(struct omapflash_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - if (!request_mem_region(res->start, size, "flash")) { - err = -EBUSY; - goto out_free_info; - } - - info->map.virt = ioremap(res->start, size); - if (!info->map.virt) { - err = -ENOMEM; - goto out_release_mem_region; - } - info->map.name = dev_name(&pdev->dev); - info->map.phys = res->start; - info->map.size = size; - info->map.bankwidth = pdata->width; - info->map.set_vpp = omap_set_vpp; - - simple_map_init(&info->map); - info->mtd = do_map_probe(pdata->map_name, &info->map); - if (!info->mtd) { - err = -EIO; - goto out_iounmap; - } - info->mtd->owner = THIS_MODULE; - - info->mtd->dev.parent = &pdev->dev; - -#ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0); - if (err > 0) - add_mtd_partitions(info->mtd, info->parts, err); - else if (err <= 0 && pdata->parts) - add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts); - else -#endif - add_mtd_device(info->mtd); - - platform_set_drvdata(pdev, info); - - return 0; - -out_iounmap: - iounmap(info->map.virt); -out_release_mem_region: - release_mem_region(res->start, size); -out_free_info: - kfree(info); - - return err; -} - -static int __exit omapflash_remove(struct platform_device *pdev) -{ - struct omapflash_info *info = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (info) { - if (info->parts) { - del_mtd_partitions(info->mtd); - kfree(info->parts); - } else - del_mtd_device(info->mtd); - map_destroy(info->mtd); - release_mem_region(info->map.phys, info->map.size); - iounmap((void __iomem *) info->map.virt); - kfree(info); - } - - return 0; -} - -static struct platform_driver omapflash_driver = { - .remove = __exit_p(omapflash_remove), - .driver = { - .name = "omapflash", - .owner = THIS_MODULE, - }, -}; - -static int __init omapflash_init(void) -{ - return platform_driver_probe(&omapflash_driver, omapflash_probe); -} - -static void __exit omapflash_exit(void) -{ - platform_driver_unregister(&omapflash_driver); -} - -module_init(omapflash_init); -module_exit(omapflash_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards"); -MODULE_ALIAS("platform:omapflash"); -- GitLab From 97ec7d585b33bbcc2be92dafa05b540959b4ea47 Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2099/3892] omap iommu: cleanup iommu page address mask and definitions This is just a cleanup, but adds a few macros here, which can be used in the proceeding patches. Signed-off-by: Hiroshi DOYU Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/iopgtable.h | 50 ++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h index 37dac434c7a1..ab23b6a140fd 100644 --- a/arch/arm/plat-omap/iopgtable.h +++ b/arch/arm/plat-omap/iopgtable.h @@ -1,7 +1,7 @@ /* * omap iommu: pagetable definitions * - * Copyright (C) 2008-2009 Nokia Corporation + * Copyright (C) 2008-2010 Nokia Corporation * * Written by Hiroshi DOYU * @@ -13,26 +13,52 @@ #ifndef __PLAT_OMAP_IOMMU_H #define __PLAT_OMAP_IOMMU_H +/* + * "L2 table" address mask and size definitions. + */ #define IOPGD_SHIFT 20 -#define IOPGD_SIZE (1 << IOPGD_SHIFT) +#define IOPGD_SIZE (1UL << IOPGD_SHIFT) #define IOPGD_MASK (~(IOPGD_SIZE - 1)) -#define IOSECTION_MASK IOPGD_MASK -#define PTRS_PER_IOPGD (1 << (32 - IOPGD_SHIFT)) -#define IOPGD_TABLE_SIZE (PTRS_PER_IOPGD * sizeof(u32)) -#define IOSUPER_SIZE (IOPGD_SIZE << 4) +/* + * "section" address mask and size definitions. + */ +#define IOSECTION_SHIFT 20 +#define IOSECTION_SIZE (1UL << IOSECTION_SHIFT) +#define IOSECTION_MASK (~(IOSECTION_SIZE - 1)) + +/* + * "supersection" address mask and size definitions. + */ +#define IOSUPER_SHIFT 24 +#define IOSUPER_SIZE (1UL << IOSUPER_SHIFT) #define IOSUPER_MASK (~(IOSUPER_SIZE - 1)) +#define PTRS_PER_IOPGD (1UL << (32 - IOPGD_SHIFT)) +#define IOPGD_TABLE_SIZE (PTRS_PER_IOPGD * sizeof(u32)) + +/* + * "small page" address mask and size definitions. + */ #define IOPTE_SHIFT 12 -#define IOPTE_SIZE (1 << IOPTE_SHIFT) +#define IOPTE_SIZE (1UL << IOPTE_SHIFT) #define IOPTE_MASK (~(IOPTE_SIZE - 1)) -#define IOPAGE_MASK IOPTE_MASK -#define PTRS_PER_IOPTE (1 << (IOPGD_SHIFT - IOPTE_SHIFT)) -#define IOPTE_TABLE_SIZE (PTRS_PER_IOPTE * sizeof(u32)) -#define IOLARGE_SIZE (IOPTE_SIZE << 4) +/* + * "large page" address mask and size definitions. + */ +#define IOLARGE_SHIFT 16 +#define IOLARGE_SIZE (1UL << IOLARGE_SHIFT) #define IOLARGE_MASK (~(IOLARGE_SIZE - 1)) +#define PTRS_PER_IOPTE (1UL << (IOPGD_SHIFT - IOPTE_SHIFT)) +#define IOPTE_TABLE_SIZE (PTRS_PER_IOPTE * sizeof(u32)) + +#define IOPAGE_MASK IOPTE_MASK + +/* + * some descriptor attributes. + */ #define IOPGD_TABLE (1 << 0) #define IOPGD_SECTION (2 << 0) #define IOPGD_SUPER (1 << 18 | 2 << 0) @@ -40,12 +66,14 @@ #define IOPTE_SMALL (2 << 0) #define IOPTE_LARGE (1 << 0) +/* to find an entry in a page-table-directory */ #define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1)) #define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da)) #define iopte_paddr(iopgd) (*iopgd & ~((1 << 10) - 1)) #define iopte_vaddr(iopgd) ((u32 *)phys_to_virt(iopte_paddr(iopgd))) +/* to find an entry in the second-level page table. */ #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) #define iopte_offset(iopgd, da) (iopte_vaddr(iopgd) + iopte_index(da)) -- GitLab From 8d33ea5881bce56f85de7fcc90e1c5618fa5b62d Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2100/3892] omap: iommu: fix incorrect address for supersection 1st entry There was a potential risk that the following "memset" could override its range if a given address was not the 1st entry of a supersection. This is not the case for "iovmm". Signed-off-by: Hiroshi DOYU Signed-off-by: Hari Nagalla Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 463d6386aff2..e74811920668 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -667,7 +667,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da) if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) { nent *= 16; /* rewind to the 1st entry */ - iopgd = (u32 *)((u32)iopgd & IOSUPER_MASK); + iopgd = iopgd_offset(obj, (da & IOSUPER_MASK)); } bytes *= nent; } -- GitLab From c127c7dc1abb7f02dcfbbea173e7abb4f2d4585e Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2101/3892] omap iommu: fix incorrect address for largepage 1st entry There was a potential risk that the following "memset" could override its range if a given address was not the 1st entry of a largepage. This is not the case for "iovmm". Reported-by: Hari Nagalla Signed-off-by: Hiroshi DOYU Signed-off-by: Hari Nagalla Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index e74811920668..905ed832df56 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -1,7 +1,7 @@ /* * omap iommu: tlb and pagetable primitives * - * Copyright (C) 2008-2009 Nokia Corporation + * Copyright (C) 2008-2010 Nokia Corporation * * Written by Hiroshi DOYU , * Paul Mundt and Toshihiro Kobayashi @@ -646,7 +646,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da) if (*iopte & IOPTE_LARGE) { nent *= 16; /* rewind to the 1st entry */ - iopte = (u32 *)((u32)iopte & IOLARGE_MASK); + iopte = iopte_offset(iopgd, (da & IOLARGE_MASK)); } bytes *= nent; memset(iopte, 0, nent * sizeof(*iopte)); -- GitLab From 14f796375b5c2bcc27986de12b6f769ec3827f36 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2102/3892] omap: McBSP: Use macros for all register read/write operations There are several places where readw()/writew() functions are used instead of OMAP_MCBSP_READ()/WRITE() macros for manipulating McBSP registers. Replace them with macros to ensure consistent behaviour after caching is introduced. Tested on OMAP1510 based Amstrad Delta. Compile-tested with omap_3430sdp_defconfig. Signed-off-by: Janusz Krzysztofik Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/mcbsp.c | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index c1eb61529394..eaaf53bb8395 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -636,26 +636,26 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) mcbsp = id_to_mcbsp_ptr(id); base = mcbsp->io_base; - writew(buf, base + OMAP_MCBSP_REG_DXR1); + OMAP_MCBSP_WRITE(base, DXR1, buf); /* if frame sync error - clear the error */ - if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) { + if (OMAP_MCBSP_READ(base, SPCR2) & XSYNC_ERR) { /* clear error */ - writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR), - base + OMAP_MCBSP_REG_SPCR2); + OMAP_MCBSP_WRITE(base, SPCR2, + OMAP_MCBSP_READ(base, SPCR2) & (~XSYNC_ERR)); /* resend */ return -1; } else { /* wait for transmit confirmation */ int attemps = 0; - while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) { + while (!(OMAP_MCBSP_READ(base, SPCR2) & XRDY)) { if (attemps++ > 1000) { - writew(readw(base + OMAP_MCBSP_REG_SPCR2) & - (~XRST), - base + OMAP_MCBSP_REG_SPCR2); + OMAP_MCBSP_WRITE(base, SPCR2, + OMAP_MCBSP_READ(base, SPCR2) & + (~XRST)); udelay(10); - writew(readw(base + OMAP_MCBSP_REG_SPCR2) | - (XRST), - base + OMAP_MCBSP_REG_SPCR2); + OMAP_MCBSP_WRITE(base, SPCR2, + OMAP_MCBSP_READ(base, SPCR2) | + (XRST)); udelay(10); dev_err(mcbsp->dev, "Could not write to" " McBSP%d Register\n", mcbsp->id); @@ -681,24 +681,24 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) base = mcbsp->io_base; /* if frame sync error - clear the error */ - if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { + if (OMAP_MCBSP_READ(base, SPCR1) & RSYNC_ERR) { /* clear error */ - writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), - base + OMAP_MCBSP_REG_SPCR1); + OMAP_MCBSP_WRITE(base, SPCR1, + OMAP_MCBSP_READ(base, SPCR1) & (~RSYNC_ERR)); /* resend */ return -1; } else { /* wait for recieve confirmation */ int attemps = 0; - while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { + while (!(OMAP_MCBSP_READ(base, SPCR1) & RRDY)) { if (attemps++ > 1000) { - writew(readw(base + OMAP_MCBSP_REG_SPCR1) & - (~RRST), - base + OMAP_MCBSP_REG_SPCR1); + OMAP_MCBSP_WRITE(base, SPCR1, + OMAP_MCBSP_READ(base, SPCR1) & + (~RRST)); udelay(10); - writew(readw(base + OMAP_MCBSP_REG_SPCR1) | - (RRST), - base + OMAP_MCBSP_REG_SPCR1); + OMAP_MCBSP_WRITE(base, SPCR1, + OMAP_MCBSP_READ(base, SPCR1) | + (RRST)); udelay(10); dev_err(mcbsp->dev, "Could not read from" " McBSP%d Register\n", mcbsp->id); @@ -706,7 +706,7 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) } } } - *buf = readw(base + OMAP_MCBSP_REG_DRR1); + *buf = OMAP_MCBSP_READ(base, DRR1); return 0; } -- GitLab From 8ea3200f1de1c3d8f3c884a704107fb1e7449547 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 15 Feb 2010 10:03:32 -0800 Subject: [PATCH 2103/3892] omap: McBSP: Modify macros/functions API for easy cache access OMAP_MCBSP_READ()/_WRITE() macros and omap_mcbsp_read()/_write() functions accept McBSP register base address as an argument. In order to support caching, that must be replaced with an address of the omap_mcbsp structure that would provide addresses for both register AND cache access. Since OMAP_ prefix seems obvious in macro names, drop it off in order to minimize line wrapping throughout the file. Tested on OMAP1510 based Amstrad Delta using linux-omap for-next, commit fb7380d70e041e4b3892f6b19dff7efb609d15a4 (2.6.33-rc3+ dated 2010-01-11). Compile-tested with omap_3430sdp_defconfig. Signed-off-by: Janusz Krzysztofik Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/mcbsp.c | 281 +++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 156 deletions(-) diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index eaaf53bb8395..f8245f25825b 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -30,26 +30,26 @@ struct omap_mcbsp **mcbsp_ptr; int omap_mcbsp_count; -void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val) +void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) { if (cpu_class_is_omap1() || cpu_is_omap2420()) - __raw_writew((u16)val, io_base + reg); + __raw_writew((u16)val, mcbsp->io_base + reg); else - __raw_writel(val, io_base + reg); + __raw_writel(val, mcbsp->io_base + reg); } -int omap_mcbsp_read(void __iomem *io_base, u16 reg) +int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg) { if (cpu_class_is_omap1() || cpu_is_omap2420()) - return __raw_readw(io_base + reg); + return __raw_readw(mcbsp->io_base + reg); else - return __raw_readl(io_base + reg); + return __raw_readl(mcbsp->io_base + reg); } -#define OMAP_MCBSP_READ(base, reg) \ - omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg) -#define OMAP_MCBSP_WRITE(base, reg, val) \ - omap_mcbsp_write(base, OMAP_MCBSP_REG_##reg, val) +#define MCBSP_READ(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg) +#define MCBSP_WRITE(mcbsp, reg, val) \ + omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) #define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; @@ -60,31 +60,31 @@ static void omap_mcbsp_dump_reg(u8 id) dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DRR2)); + MCBSP_READ(mcbsp, DRR2)); dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DRR1)); + MCBSP_READ(mcbsp, DRR1)); dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DXR2)); + MCBSP_READ(mcbsp, DXR2)); dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DXR1)); + MCBSP_READ(mcbsp, DXR1)); dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SPCR2)); + MCBSP_READ(mcbsp, SPCR2)); dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SPCR1)); + MCBSP_READ(mcbsp, SPCR1)); dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, RCR2)); + MCBSP_READ(mcbsp, RCR2)); dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, RCR1)); + MCBSP_READ(mcbsp, RCR1)); dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, XCR2)); + MCBSP_READ(mcbsp, XCR2)); dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, XCR1)); + MCBSP_READ(mcbsp, XCR1)); dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SRGR2)); + MCBSP_READ(mcbsp, SRGR2)); dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SRGR1)); + MCBSP_READ(mcbsp, SRGR1)); dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, PCR0)); + MCBSP_READ(mcbsp, PCR0)); dev_dbg(mcbsp->dev, "***********************\n"); } @@ -93,15 +93,14 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) struct omap_mcbsp *mcbsp_tx = dev_id; u16 irqst_spcr2; - irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2); + irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2); dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); if (irqst_spcr2 & XSYNC_ERR) { dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", irqst_spcr2); /* Writing zero to XSYNC_ERR clears the IRQ */ - OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2, - irqst_spcr2 & ~(XSYNC_ERR)); + MCBSP_WRITE(mcbsp_tx, SPCR2, irqst_spcr2 & ~(XSYNC_ERR)); } else { complete(&mcbsp_tx->tx_irq_completion); } @@ -114,15 +113,14 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) struct omap_mcbsp *mcbsp_rx = dev_id; u16 irqst_spcr1; - irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1); + irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1); dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); if (irqst_spcr1 & RSYNC_ERR) { dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", irqst_spcr1); /* Writing zero to RSYNC_ERR clears the IRQ */ - OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1, - irqst_spcr1 & ~(RSYNC_ERR)); + MCBSP_WRITE(mcbsp_rx, SPCR1, irqst_spcr1 & ~(RSYNC_ERR)); } else { complete(&mcbsp_rx->tx_irq_completion); } @@ -135,7 +133,7 @@ static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) struct omap_mcbsp *mcbsp_dma_tx = data; dev_dbg(mcbsp_dma_tx->dev, "TX DMA callback : 0x%x\n", - OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2)); + MCBSP_READ(mcbsp_dma_tx, SPCR2)); /* We can free the channels */ omap_free_dma(mcbsp_dma_tx->dma_tx_lch); @@ -149,7 +147,7 @@ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) struct omap_mcbsp *mcbsp_dma_rx = data; dev_dbg(mcbsp_dma_rx->dev, "RX DMA callback : 0x%x\n", - OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2)); + MCBSP_READ(mcbsp_dma_rx, SPCR2)); /* We can free the channels */ omap_free_dma(mcbsp_dma_rx->dma_rx_lch); @@ -167,7 +165,6 @@ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -175,25 +172,24 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", mcbsp->id, mcbsp->phys_base); /* We write the given config */ - OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2); - OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1); - OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2); - OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1); - OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2); - OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1); - OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2); - OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1); - OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2); - OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1); - OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0); + MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); + MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); + MCBSP_WRITE(mcbsp, RCR2, config->rcr2); + MCBSP_WRITE(mcbsp, RCR1, config->rcr1); + MCBSP_WRITE(mcbsp, XCR2, config->xcr2); + MCBSP_WRITE(mcbsp, XCR1, config->xcr1); + MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); + MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); + MCBSP_WRITE(mcbsp, MCR2, config->mcr2); + MCBSP_WRITE(mcbsp, MCR1, config->mcr1); + MCBSP_WRITE(mcbsp, PCR0, config->pcr0); if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { - OMAP_MCBSP_WRITE(io_base, XCCR, config->xccr); - OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr); + MCBSP_WRITE(mcbsp, XCCR, config->xccr); + MCBSP_WRITE(mcbsp, RCCR, config->rccr); } } EXPORT_SYMBOL(omap_mcbsp_config); @@ -207,7 +203,6 @@ EXPORT_SYMBOL(omap_mcbsp_config); void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!cpu_is_omap34xx()) return; @@ -217,9 +212,8 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - OMAP_MCBSP_WRITE(io_base, THRSH2, threshold); + MCBSP_WRITE(mcbsp, THRSH2, threshold); } EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); @@ -231,7 +225,6 @@ EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!cpu_is_omap34xx()) return; @@ -241,9 +234,8 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - OMAP_MCBSP_WRITE(io_base, THRSH1, threshold); + MCBSP_WRITE(mcbsp, THRSH1, threshold); } EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); @@ -313,19 +305,18 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) if (cpu_is_omap34xx()) { u16 syscon; - syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon = MCBSP_READ(mcbsp, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | CLOCKACTIVITY(0x02)); - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, - XRDYEN | RRDYEN); + MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); } else { syscon |= SIDLEMODE(0x01); } - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); } } @@ -337,7 +328,7 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) if (cpu_is_omap34xx()) { u16 syscon; - syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon = MCBSP_READ(mcbsp, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); /* * HW bug workaround - If no_idle mode is taken, we need to @@ -345,12 +336,12 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) * device will not hit retention anymore. */ syscon |= SIDLEMODE(0x02); - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); syscon &= ~(SIDLEMODE(0x03)); - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); + MCBSP_WRITE(mcbsp, WAKEUPEN, 0); } } #else @@ -424,8 +415,8 @@ int omap_mcbsp_request(unsigned int id) * Make sure that transmitter, receiver and sample-rate generator are * not running before activating IRQs. */ - OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR1, 0); - OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR2, 0); + MCBSP_WRITE(mcbsp, SPCR1, 0); + MCBSP_WRITE(mcbsp, SPCR2, 0); if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) { /* We need to get IRQs here */ @@ -515,7 +506,6 @@ EXPORT_SYMBOL(omap_mcbsp_free); void omap_mcbsp_start(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; int idle; u16 w; @@ -524,28 +514,26 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; - mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; + mcbsp->rx_word_length = (MCBSP_READ(mcbsp, RCR1) >> 5) & 0x7; + mcbsp->tx_word_length = (MCBSP_READ(mcbsp, XCR1) >> 5) & 0x7; - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + idle = !((MCBSP_READ(mcbsp, SPCR2) | MCBSP_READ(mcbsp, SPCR1)) & 1); if (idle) { /* Start the sample generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + w = MCBSP_READ(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); } /* Enable transmitter and receiver */ tx &= 1; - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); + w = MCBSP_READ(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | tx); rx &= 1; - w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); + w = MCBSP_READ(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w | rx); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec @@ -557,18 +545,18 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) if (idle) { /* Start frame sync */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + w = MCBSP_READ(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); } if (cpu_is_omap2430() || cpu_is_omap34xx()) { /* Release the transmitter and receiver */ - w = OMAP_MCBSP_READ(io_base, XCCR); + w = MCBSP_READ(mcbsp, XCCR); w &= ~(tx ? XDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, XCCR, w); - w = OMAP_MCBSP_READ(io_base, RCCR); + MCBSP_WRITE(mcbsp, XCCR, w); + w = MCBSP_READ(mcbsp, RCCR); w &= ~(rx ? RDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, RCCR, w); + MCBSP_WRITE(mcbsp, RCCR, w); } /* Dump McBSP Regs */ @@ -579,7 +567,6 @@ EXPORT_SYMBOL(omap_mcbsp_start); void omap_mcbsp_stop(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; int idle; u16 w; @@ -589,35 +576,33 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; /* Reset transmitter */ tx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = OMAP_MCBSP_READ(io_base, XCCR); + w = MCBSP_READ(mcbsp, XCCR); w |= (tx ? XDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, XCCR, w); + MCBSP_WRITE(mcbsp, XCCR, w); } - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx); + w = MCBSP_READ(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); /* Reset receiver */ rx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = OMAP_MCBSP_READ(io_base, RCCR); + w = MCBSP_READ(mcbsp, RCCR); w |= (rx ? RDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, RCCR, w); + MCBSP_WRITE(mcbsp, RCCR, w); } - w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx); + w = MCBSP_READ(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + idle = !((MCBSP_READ(mcbsp, SPCR2) | MCBSP_READ(mcbsp, SPCR1)) & 1); if (idle) { /* Reset the sample rate generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); + w = MCBSP_READ(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); } } EXPORT_SYMBOL(omap_mcbsp_stop); @@ -626,7 +611,6 @@ EXPORT_SYMBOL(omap_mcbsp_stop); int omap_mcbsp_pollwrite(unsigned int id, u16 buf) { struct omap_mcbsp *mcbsp; - void __iomem *base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -634,28 +618,25 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) } mcbsp = id_to_mcbsp_ptr(id); - base = mcbsp->io_base; - OMAP_MCBSP_WRITE(base, DXR1, buf); + MCBSP_WRITE(mcbsp, DXR1, buf); /* if frame sync error - clear the error */ - if (OMAP_MCBSP_READ(base, SPCR2) & XSYNC_ERR) { + if (MCBSP_READ(mcbsp, SPCR2) & XSYNC_ERR) { /* clear error */ - OMAP_MCBSP_WRITE(base, SPCR2, - OMAP_MCBSP_READ(base, SPCR2) & (~XSYNC_ERR)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ(mcbsp, SPCR2) & (~XSYNC_ERR)); /* resend */ return -1; } else { /* wait for transmit confirmation */ int attemps = 0; - while (!(OMAP_MCBSP_READ(base, SPCR2) & XRDY)) { + while (!(MCBSP_READ(mcbsp, SPCR2) & XRDY)) { if (attemps++ > 1000) { - OMAP_MCBSP_WRITE(base, SPCR2, - OMAP_MCBSP_READ(base, SPCR2) & - (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ(mcbsp, SPCR2) & (~XRST)); udelay(10); - OMAP_MCBSP_WRITE(base, SPCR2, - OMAP_MCBSP_READ(base, SPCR2) | - (XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ(mcbsp, SPCR2) | (XRST)); udelay(10); dev_err(mcbsp->dev, "Could not write to" " McBSP%d Register\n", mcbsp->id); @@ -671,7 +652,6 @@ EXPORT_SYMBOL(omap_mcbsp_pollwrite); int omap_mcbsp_pollread(unsigned int id, u16 *buf) { struct omap_mcbsp *mcbsp; - void __iomem *base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -679,26 +659,23 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) } mcbsp = id_to_mcbsp_ptr(id); - base = mcbsp->io_base; /* if frame sync error - clear the error */ - if (OMAP_MCBSP_READ(base, SPCR1) & RSYNC_ERR) { + if (MCBSP_READ(mcbsp, SPCR1) & RSYNC_ERR) { /* clear error */ - OMAP_MCBSP_WRITE(base, SPCR1, - OMAP_MCBSP_READ(base, SPCR1) & (~RSYNC_ERR)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ(mcbsp, SPCR1) & (~RSYNC_ERR)); /* resend */ return -1; } else { /* wait for recieve confirmation */ int attemps = 0; - while (!(OMAP_MCBSP_READ(base, SPCR1) & RRDY)) { + while (!(MCBSP_READ(mcbsp, SPCR1) & RRDY)) { if (attemps++ > 1000) { - OMAP_MCBSP_WRITE(base, SPCR1, - OMAP_MCBSP_READ(base, SPCR1) & - (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ(mcbsp, SPCR1) & (~RRST)); udelay(10); - OMAP_MCBSP_WRITE(base, SPCR1, - OMAP_MCBSP_READ(base, SPCR1) | - (RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ(mcbsp, SPCR1) | (RRST)); udelay(10); dev_err(mcbsp->dev, "Could not read from" " McBSP%d Register\n", mcbsp->id); @@ -706,7 +683,7 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) } } } - *buf = OMAP_MCBSP_READ(base, DRR1); + *buf = MCBSP_READ(mcbsp, DRR1); return 0; } @@ -718,7 +695,6 @@ EXPORT_SYMBOL(omap_mcbsp_pollread); void omap_mcbsp_xmit_word(unsigned int id, u32 word) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; omap_mcbsp_word_length word_length; if (!omap_mcbsp_check_valid_id(id)) { @@ -727,21 +703,19 @@ void omap_mcbsp_xmit_word(unsigned int id, u32 word) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; word_length = mcbsp->tx_word_length; wait_for_completion(&mcbsp->tx_irq_completion); if (word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + MCBSP_WRITE(mcbsp, DXR2, word >> 16); + MCBSP_WRITE(mcbsp, DXR1, word & 0xffff); } EXPORT_SYMBOL(omap_mcbsp_xmit_word); u32 omap_mcbsp_recv_word(unsigned int id) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; u16 word_lsb, word_msb = 0; omap_mcbsp_word_length word_length; @@ -752,13 +726,12 @@ u32 omap_mcbsp_recv_word(unsigned int id) mcbsp = id_to_mcbsp_ptr(id); word_length = mcbsp->rx_word_length; - io_base = mcbsp->io_base; wait_for_completion(&mcbsp->rx_irq_completion); if (word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); return (word_lsb | (word_msb << 16)); } @@ -767,7 +740,6 @@ EXPORT_SYMBOL(omap_mcbsp_recv_word); int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; omap_mcbsp_word_length tx_word_length; omap_mcbsp_word_length rx_word_length; u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; @@ -777,7 +749,6 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) return -ENODEV; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; tx_word_length = mcbsp->tx_word_length; rx_word_length = mcbsp->rx_word_length; @@ -785,14 +756,14 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) return -EINVAL; /* First we wait for the transmitter to be ready */ - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); while (!(spcr2 & XRDY)) { - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, spcr2 & (~XRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, spcr2 | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -802,18 +773,18 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) /* Now we can push the data */ if (tx_word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + MCBSP_WRITE(mcbsp, DXR2, word >> 16); + MCBSP_WRITE(mcbsp, DXR1, word & 0xffff); /* We wait for the receiver to be ready */ - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); while (!(spcr1 & RRDY)) { - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, spcr1 & (~RRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, spcr1 | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); @@ -823,8 +794,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) /* Receiver is ready, let's read the dummy data */ if (rx_word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); return 0; } @@ -834,7 +805,6 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) { struct omap_mcbsp *mcbsp; u32 clock_word = 0; - void __iomem *io_base; omap_mcbsp_word_length tx_word_length; omap_mcbsp_word_length rx_word_length; u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; @@ -845,7 +815,6 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; tx_word_length = mcbsp->tx_word_length; rx_word_length = mcbsp->rx_word_length; @@ -854,14 +823,14 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) return -EINVAL; /* First we wait for the transmitter to be ready */ - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); while (!(spcr2 & XRDY)) { - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, spcr2 & (~XRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, spcr2 | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -871,18 +840,18 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) /* We first need to enable the bus clock */ if (tx_word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); + MCBSP_WRITE(mcbsp, DXR2, clock_word >> 16); + MCBSP_WRITE(mcbsp, DXR1, clock_word & 0xffff); /* We wait for the receiver to be ready */ - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); while (!(spcr1 & RRDY)) { - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, spcr1 & (~RRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, spcr1 | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); @@ -892,8 +861,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) /* Receiver is ready, there is something for us */ if (rx_word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); word[0] = (word_lsb | (word_msb << 16)); -- GitLab From c8c99699bd25d8b238ba75d2530d1be90e3c39ea Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2104/3892] omap: McBSP: Introduce caching in register write operations Determine cache size required per McBSP port at init time, based on processor type running on. Allocate space for storing cached copies of McBSP register values at port request. Modify omap_msbcp_write() function to update the cache with every register write operation. Modify omap_mcbsp_read() to support reading from cache or hardware. Update MCBSP_READ() macro for modified omap_mcbsp_read() function API. Introduce a new macro that reads from the cache. Tested on OMAP1510 based Amstrad Delta using linux-omap for-next, commit fb7380d70e041e4b3892f6b19dff7efb609d15a4 (2.6.33-rc3+ dated 2010-01-11). Compile-tested with: omap_perseus2_730_defconfig, omap_generic_1610_defconfig, omap_generic_2420_defconfig, omap_2430sdp_defconfig, omap_3430sdp_defconfig, omap_4430sdp_defconfig with CONFIG_OMAP_MCBSP=y selected. Signed-off-by: Janusz Krzysztofik Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/mcbsp.c | 16 ++++- arch/arm/mach-omap2/mcbsp.c | 20 +++++-- arch/arm/plat-omap/include/plat/mcbsp.h | 3 +- arch/arm/plat-omap/mcbsp.c | 77 +++++++++++++++++-------- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index 6bddce104ee9..f9a5cf750b59 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -99,9 +99,11 @@ static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = { }, }; #define OMAP7XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap7xx_mcbsp_pdata) +#define OMAP7XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1) #else #define omap7xx_mcbsp_pdata NULL #define OMAP7XX_MCBSP_PDATA_SZ 0 +#define OMAP7XX_MCBSP_REG_NUM 0 #endif #ifdef CONFIG_ARCH_OMAP15XX @@ -132,9 +134,11 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { }, }; #define OMAP15XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap15xx_mcbsp_pdata) +#define OMAP15XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1) #else #define omap15xx_mcbsp_pdata NULL #define OMAP15XX_MCBSP_PDATA_SZ 0 +#define OMAP15XX_MCBSP_REG_NUM 0 #endif #ifdef CONFIG_ARCH_OMAP16XX @@ -165,19 +169,25 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { }, }; #define OMAP16XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap16xx_mcbsp_pdata) +#define OMAP16XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1) #else #define omap16xx_mcbsp_pdata NULL #define OMAP16XX_MCBSP_PDATA_SZ 0 +#define OMAP16XX_MCBSP_REG_NUM 0 #endif int __init omap1_mcbsp_init(void) { - if (cpu_is_omap7xx()) + if (cpu_is_omap7xx()) { omap_mcbsp_count = OMAP7XX_MCBSP_PDATA_SZ; - if (cpu_is_omap15xx()) + omap_mcbsp_cache_size = OMAP7XX_MCBSP_REG_NUM * sizeof(u16); + } else if (cpu_is_omap15xx()) { omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ; - if (cpu_is_omap16xx()) + omap_mcbsp_cache_size = OMAP15XX_MCBSP_REG_NUM * sizeof(u16); + } else if (cpu_is_omap16xx()) { omap_mcbsp_count = OMAP16XX_MCBSP_PDATA_SZ; + omap_mcbsp_cache_size = OMAP16XX_MCBSP_REG_NUM * sizeof(u16); + } mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), GFP_KERNEL); diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 4b6e5157520f..d601f9405d11 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -65,9 +65,11 @@ static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = { }, }; #define OMAP2420_MCBSP_PDATA_SZ ARRAY_SIZE(omap2420_mcbsp_pdata) +#define OMAP2420_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1) #else #define omap2420_mcbsp_pdata NULL #define OMAP2420_MCBSP_PDATA_SZ 0 +#define OMAP2420_MCBSP_REG_NUM 0 #endif #ifdef CONFIG_ARCH_OMAP2430 @@ -114,9 +116,11 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = { }, }; #define OMAP2430_MCBSP_PDATA_SZ ARRAY_SIZE(omap2430_mcbsp_pdata) +#define OMAP2430_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1) #else #define omap2430_mcbsp_pdata NULL #define OMAP2430_MCBSP_PDATA_SZ 0 +#define OMAP2430_MCBSP_REG_NUM 0 #endif #ifdef CONFIG_ARCH_OMAP3 @@ -168,9 +172,11 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { }, }; #define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata) +#define OMAP34XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1) #else #define omap34xx_mcbsp_pdata NULL #define OMAP34XX_MCBSP_PDATA_SZ 0 +#define OMAP34XX_MCBSP_REG_NUM 0 #endif static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = { @@ -208,17 +214,23 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = { }, }; #define OMAP44XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap44xx_mcbsp_pdata) +#define OMAP44XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1) static int __init omap2_mcbsp_init(void) { - if (cpu_is_omap2420()) + if (cpu_is_omap2420()) { omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ; - if (cpu_is_omap2430()) + omap_mcbsp_cache_size = OMAP2420_MCBSP_REG_NUM * sizeof(u16); + } else if (cpu_is_omap2430()) { omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ; - if (cpu_is_omap34xx()) + omap_mcbsp_cache_size = OMAP2430_MCBSP_REG_NUM * sizeof(u32); + } else if (cpu_is_omap34xx()) { omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ; - if (cpu_is_omap44xx()) + omap_mcbsp_cache_size = OMAP34XX_MCBSP_REG_NUM * sizeof(u32); + } else if (cpu_is_omap44xx()) { omap_mcbsp_count = OMAP44XX_MCBSP_PDATA_SZ; + omap_mcbsp_cache_size = OMAP44XX_MCBSP_REG_NUM * sizeof(u32); + } mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), GFP_KERNEL); diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index d93fa44b1c9a..4df957b1d252 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -414,9 +414,10 @@ struct omap_mcbsp { u16 max_tx_thres; u16 max_rx_thres; #endif + void *reg_cache; }; extern struct omap_mcbsp **mcbsp_ptr; -extern int omap_mcbsp_count; +extern int omap_mcbsp_count, omap_mcbsp_cache_size; int omap_mcbsp_init(void); void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f8245f25825b..61e440a0f7cd 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -28,28 +28,42 @@ #include struct omap_mcbsp **mcbsp_ptr; -int omap_mcbsp_count; +int omap_mcbsp_count, omap_mcbsp_cache_size; void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) { - if (cpu_class_is_omap1() || cpu_is_omap2420()) + if (cpu_class_is_omap1()) { + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val; __raw_writew((u16)val, mcbsp->io_base + reg); - else + } else if (cpu_is_omap2420()) { + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)] = (u16)val; + __raw_writew((u16)val, mcbsp->io_base + reg); + } else { + ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)] = val; __raw_writel(val, mcbsp->io_base + reg); + } } -int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg) +int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) { - if (cpu_class_is_omap1() || cpu_is_omap2420()) - return __raw_readw(mcbsp->io_base + reg); - else - return __raw_readl(mcbsp->io_base + reg); + if (cpu_class_is_omap1()) { + return !from_cache ? __raw_readw(mcbsp->io_base + reg) : + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)]; + } else if (cpu_is_omap2420()) { + return !from_cache ? __raw_readw(mcbsp->io_base + reg) : + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)]; + } else { + return !from_cache ? __raw_readl(mcbsp->io_base + reg) : + ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)]; + } } #define MCBSP_READ(mcbsp, reg) \ - omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg) + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) #define MCBSP_WRITE(mcbsp, reg, val) \ omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) +#define MCBSP_READ_CACHE(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) #define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; @@ -383,6 +397,7 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type); int omap_mcbsp_request(unsigned int id) { struct omap_mcbsp *mcbsp; + void *reg_cache; int err; if (!omap_mcbsp_check_valid_id(id)) { @@ -391,15 +406,21 @@ int omap_mcbsp_request(unsigned int id) } mcbsp = id_to_mcbsp_ptr(id); + reg_cache = kzalloc(omap_mcbsp_cache_size, GFP_KERNEL); + if (!reg_cache) { + return -ENOMEM; + } + spin_lock(&mcbsp->lock); if (!mcbsp->free) { dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id); - spin_unlock(&mcbsp->lock); - return -EBUSY; + err = -EBUSY; + goto err_kfree; } mcbsp->free = 0; + mcbsp->reg_cache = reg_cache; spin_unlock(&mcbsp->lock); if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) @@ -427,7 +448,7 @@ int omap_mcbsp_request(unsigned int id) dev_err(mcbsp->dev, "Unable to request TX IRQ %d " "for McBSP%d\n", mcbsp->tx_irq, mcbsp->id); - goto error; + goto err_clk_disable; } init_completion(&mcbsp->rx_irq_completion); @@ -437,16 +458,16 @@ int omap_mcbsp_request(unsigned int id) dev_err(mcbsp->dev, "Unable to request RX IRQ %d " "for McBSP%d\n", mcbsp->rx_irq, mcbsp->id); - goto tx_irq; + goto err_free_irq; } } return 0; -tx_irq: +err_free_irq: free_irq(mcbsp->tx_irq, (void *)mcbsp); -error: +err_clk_disable: if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(id); + mcbsp->pdata->ops->free(id); /* Do procedure specific to omap34xx arch, if applicable */ omap34xx_mcbsp_free(mcbsp); @@ -454,7 +475,12 @@ error: clk_disable(mcbsp->fclk); clk_disable(mcbsp->iclk); + spin_lock(&mcbsp->lock); mcbsp->free = 1; + mcbsp->reg_cache = NULL; +err_kfree: + spin_unlock(&mcbsp->lock); + kfree(reg_cache); return err; } @@ -463,6 +489,7 @@ EXPORT_SYMBOL(omap_mcbsp_request); void omap_mcbsp_free(unsigned int id) { struct omap_mcbsp *mcbsp; + void *reg_cache; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -485,16 +512,18 @@ void omap_mcbsp_free(unsigned int id) free_irq(mcbsp->tx_irq, (void *)mcbsp); } - spin_lock(&mcbsp->lock); - if (mcbsp->free) { - dev_err(mcbsp->dev, "McBSP%d was not reserved\n", - mcbsp->id); - spin_unlock(&mcbsp->lock); - return; - } + reg_cache = mcbsp->reg_cache; - mcbsp->free = 1; + spin_lock(&mcbsp->lock); + if (mcbsp->free) + dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); + else + mcbsp->free = 1; + mcbsp->reg_cache = NULL; spin_unlock(&mcbsp->lock); + + if (reg_cache) + kfree(reg_cache); } EXPORT_SYMBOL(omap_mcbsp_free); -- GitLab From 96fbd74551e9cae8fd5e9cb62a0a19336a3064fa Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2105/3892] omap: McBSP: Use cache when modifying individual register bits Change the way McBSP registers are updated: use cached values instead of relying upon those read back from the device. With this patch, I have finally managed to get rid of all random playback/recording hangups on my OMAP1510 based Amstrad Delta hardware. Before that, values read back from McBSP registers to be used for updating them happened to be errornous. From the hardware side, the issue appeared to be caused by a relatively high power requirements of an external USB adapter connected to the board's printer dedicated USB port. I think there is one important point that makes this patch worth of applying, apart from my hardware quality. With the current code, if it ever happens to any machine, no matter if OMAP1510 or newer, to read incorrect value from a McBSP register, this wrong value will get written back without any checking. That can lead to hardware damage if, for example, an input pin is turned into output as a result. Applies on top of patch 3 from this series: [PATCH v9 3/4] OMAP: McBSP: Introduce caching in register write operations Tested on OMAP1510 based Amstrad Delta using linux-omap for-next, commit fb7380d70e041e4b3892f6b19dff7efb609d15a4 (2.6.33-rc3+ dated 2010-01-11). Compile-tested with omap_3430sdp_defconfig. Signed-off-by: Janusz Krzysztofik Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/mcbsp.c | 78 +++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 61e440a0f7cd..473be3dc2cf5 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -114,7 +114,8 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", irqst_spcr2); /* Writing zero to XSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp_tx, SPCR2, irqst_spcr2 & ~(XSYNC_ERR)); + MCBSP_WRITE(mcbsp_tx, SPCR2, + MCBSP_READ_CACHE(mcbsp_tx, SPCR2) & ~(XSYNC_ERR)); } else { complete(&mcbsp_tx->tx_irq_completion); } @@ -134,7 +135,8 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", irqst_spcr1); /* Writing zero to RSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp_rx, SPCR1, irqst_spcr1 & ~(RSYNC_ERR)); + MCBSP_WRITE(mcbsp_rx, SPCR1, + MCBSP_READ_CACHE(mcbsp_rx, SPCR1) & ~(RSYNC_ERR)); } else { complete(&mcbsp_rx->tx_irq_completion); } @@ -544,24 +546,25 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) } mcbsp = id_to_mcbsp_ptr(id); - mcbsp->rx_word_length = (MCBSP_READ(mcbsp, RCR1) >> 5) & 0x7; - mcbsp->tx_word_length = (MCBSP_READ(mcbsp, XCR1) >> 5) & 0x7; + mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7; + mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7; - idle = !((MCBSP_READ(mcbsp, SPCR2) | MCBSP_READ(mcbsp, SPCR1)) & 1); + idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (idle) { /* Start the sample generator */ - w = MCBSP_READ(mcbsp, SPCR2); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); } /* Enable transmitter and receiver */ tx &= 1; - w = MCBSP_READ(mcbsp, SPCR2); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | tx); rx &= 1; - w = MCBSP_READ(mcbsp, SPCR1); + w = MCBSP_READ_CACHE(mcbsp, SPCR1); MCBSP_WRITE(mcbsp, SPCR1, w | rx); /* @@ -574,16 +577,16 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) if (idle) { /* Start frame sync */ - w = MCBSP_READ(mcbsp, SPCR2); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); } if (cpu_is_omap2430() || cpu_is_omap34xx()) { /* Release the transmitter and receiver */ - w = MCBSP_READ(mcbsp, XCCR); + w = MCBSP_READ_CACHE(mcbsp, XCCR); w &= ~(tx ? XDISABLE : 0); MCBSP_WRITE(mcbsp, XCCR, w); - w = MCBSP_READ(mcbsp, RCCR); + w = MCBSP_READ_CACHE(mcbsp, RCCR); w &= ~(rx ? RDISABLE : 0); MCBSP_WRITE(mcbsp, RCCR, w); } @@ -609,28 +612,29 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) /* Reset transmitter */ tx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = MCBSP_READ(mcbsp, XCCR); + w = MCBSP_READ_CACHE(mcbsp, XCCR); w |= (tx ? XDISABLE : 0); MCBSP_WRITE(mcbsp, XCCR, w); } - w = MCBSP_READ(mcbsp, SPCR2); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); /* Reset receiver */ rx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = MCBSP_READ(mcbsp, RCCR); + w = MCBSP_READ_CACHE(mcbsp, RCCR); w |= (rx ? RDISABLE : 0); MCBSP_WRITE(mcbsp, RCCR, w); } - w = MCBSP_READ(mcbsp, SPCR1); + w = MCBSP_READ_CACHE(mcbsp, SPCR1); MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); - idle = !((MCBSP_READ(mcbsp, SPCR2) | MCBSP_READ(mcbsp, SPCR1)) & 1); + idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (idle) { /* Reset the sample rate generator */ - w = MCBSP_READ(mcbsp, SPCR2); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); } } @@ -653,7 +657,7 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) if (MCBSP_READ(mcbsp, SPCR2) & XSYNC_ERR) { /* clear error */ MCBSP_WRITE(mcbsp, SPCR2, - MCBSP_READ(mcbsp, SPCR2) & (~XSYNC_ERR)); + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XSYNC_ERR)); /* resend */ return -1; } else { @@ -662,10 +666,12 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) while (!(MCBSP_READ(mcbsp, SPCR2) & XRDY)) { if (attemps++ > 1000) { MCBSP_WRITE(mcbsp, SPCR2, - MCBSP_READ(mcbsp, SPCR2) & (~XRST)); + MCBSP_READ_CACHE(mcbsp, SPCR2) & + (~XRST)); udelay(10); MCBSP_WRITE(mcbsp, SPCR2, - MCBSP_READ(mcbsp, SPCR2) | (XRST)); + MCBSP_READ_CACHE(mcbsp, SPCR2) | + (XRST)); udelay(10); dev_err(mcbsp->dev, "Could not write to" " McBSP%d Register\n", mcbsp->id); @@ -692,7 +698,7 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) if (MCBSP_READ(mcbsp, SPCR1) & RSYNC_ERR) { /* clear error */ MCBSP_WRITE(mcbsp, SPCR1, - MCBSP_READ(mcbsp, SPCR1) & (~RSYNC_ERR)); + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RSYNC_ERR)); /* resend */ return -1; } else { @@ -701,10 +707,12 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) while (!(MCBSP_READ(mcbsp, SPCR1) & RRDY)) { if (attemps++ > 1000) { MCBSP_WRITE(mcbsp, SPCR1, - MCBSP_READ(mcbsp, SPCR1) & (~RRST)); + MCBSP_READ_CACHE(mcbsp, SPCR1) & + (~RRST)); udelay(10); MCBSP_WRITE(mcbsp, SPCR1, - MCBSP_READ(mcbsp, SPCR1) | (RRST)); + MCBSP_READ_CACHE(mcbsp, SPCR1) | + (RRST)); udelay(10); dev_err(mcbsp->dev, "Could not read from" " McBSP%d Register\n", mcbsp->id); @@ -790,9 +798,11 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - MCBSP_WRITE(mcbsp, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); udelay(10); - MCBSP_WRITE(mcbsp, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -811,9 +821,11 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - MCBSP_WRITE(mcbsp, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); udelay(10); - MCBSP_WRITE(mcbsp, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); @@ -857,9 +869,11 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - MCBSP_WRITE(mcbsp, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); udelay(10); - MCBSP_WRITE(mcbsp, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -878,9 +892,11 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - MCBSP_WRITE(mcbsp, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); udelay(10); - MCBSP_WRITE(mcbsp, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); -- GitLab From d761585a0571c9d508b26735a3d268ff3ec3a548 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2106/3892] omap1: mailbox: kill compile warning use ioremap and remove unused variable to get rid of compile warnings. Signed-off-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/devices.c | 2 +- arch/arm/mach-omap1/mailbox.c | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index a2d07aa75c9e..379100c17639 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -73,7 +73,7 @@ static inline void omap_init_rtc(void) {} # define INT_DSP_MAILBOX1 INT_1610_DSP_MAILBOX1 #endif -#define OMAP1_MBOX_BASE OMAP1_IO_ADDRESS(OMAP16XX_MAILBOX_BASE) +#define OMAP1_MBOX_BASE OMAP16XX_MAILBOX_BASE static struct resource mbox_resources[] = { { diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c index caf889aaa248..4f5b3da3d559 100644 --- a/arch/arm/mach-omap1/mailbox.c +++ b/arch/arm/mach-omap1/mailbox.c @@ -146,7 +146,6 @@ EXPORT_SYMBOL(mbox_dsp_info); static int __devinit omap1_mbox_probe(struct platform_device *pdev) { struct resource *res; - int ret = 0; if (pdev->num_resources != 2) { dev_err(&pdev->dev, "invalid number of resources: %d\n", @@ -160,12 +159,18 @@ static int __devinit omap1_mbox_probe(struct platform_device *pdev) dev_err(&pdev->dev, "invalid mem resource\n"); return -ENODEV; } - mbox_base = res->start; + + mbox_base = ioremap(res->start, resource_size(res)); + if (!mbox_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -ENODEV; + } /* DSP IRQ */ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { dev_err(&pdev->dev, "invalid irq resource\n"); + iounmap(mbox_base); return -ENODEV; } mbox_dsp_info.irq = res->start; -- GitLab From 0cd7e1cc76c38b29ec459294750660855fa11ca8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2107/3892] omap2/3/4: mailbox: kill compile warning in mailbox.c Change %d to %ld to avoid the compile warning. Signed-off-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 281ab6342448..2c9fd1c2a7c7 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -93,7 +93,7 @@ static int omap2_mbox_startup(struct omap_mbox *mbox) mbox_ick_handle = clk_get(NULL, "mailboxes_ick"); if (IS_ERR(mbox_ick_handle)) { - printk(KERN_ERR "Could not get mailboxes_ick: %d\n", + printk(KERN_ERR "Could not get mailboxes_ick: %ld\n", PTR_ERR(mbox_ick_handle)); return PTR_ERR(mbox_ick_handle); } -- GitLab From b2fa3b7c602258c1ab9d1cb66c30d72e9085c762 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2108/3892] omap2/3/4: gpmc: kill compile warning Get rid of the following warnings: arch/arm/mach-omap2/gpmc.c:550:30: warning: non-ANSI function declaration of function 'omap3_gpmc_save_context' arch/arm/mach-omap2/gpmc.c:581:33: warning: non-ANSI function declaration of function 'omap3_gpmc_restore_context' Signed-off-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 7027cdc1ba49..5bc3ca03551c 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -552,9 +552,10 @@ void __init gpmc_init(void) #ifdef CONFIG_ARCH_OMAP3 static struct omap3_gpmc_regs gpmc_context; -void omap3_gpmc_save_context() +void omap3_gpmc_save_context(void) { int i; + gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG); gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE); gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL); @@ -583,9 +584,10 @@ void omap3_gpmc_save_context() } } -void omap3_gpmc_restore_context() +void omap3_gpmc_restore_context(void) { int i; + gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig); gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable); gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl); -- GitLab From 2586ef0d1db6d606e5ceb7fbf97f34c8b402e90c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2109/3892] omap2/3/4: gpmc: avoid section definitions on headers trivial patch, no functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/gpmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index e081338e0b23..3f3609aa277f 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -110,6 +110,6 @@ extern void gpmc_prefetch_reset(void); extern int gpmc_prefetch_status(void); extern void omap3_gpmc_save_context(void); extern void omap3_gpmc_restore_context(void); -extern void __init gpmc_init(void); +extern void gpmc_init(void); #endif -- GitLab From 30e53bccfa15c6c0839c87705a66d478bb10baf5 Mon Sep 17 00:00:00 2001 From: vikram pandita Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2110/3892] omap2/3/4: serial: fix coding style indentaion No logical code change Fix coding style indentaion as per checkpatch.pl Fix multi-line comment style reported by Nishanth Menon Signed-off-by: Vikram Pandita Cc: Nishanth Menon Acked-by: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/serial.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 2b784002bf77..5f3035ec0d6f 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -716,15 +716,16 @@ void __init omap_serial_init_port(int port) DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout); } - /* omap44xx: Never read empty UART fifo - * omap3xxx: Never read empty UART fifo on UARTs - * with IP rev >=0x52 - */ - if (cpu_is_omap44xx()) - uart->p->serial_in = serial_in_override; - else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF) - >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV) - uart->p->serial_in = serial_in_override; + /* + * omap44xx: Never read empty UART fifo + * omap3xxx: Never read empty UART fifo on UARTs + * with IP rev >=0x52 + */ + if (cpu_is_omap44xx()) + uart->p->serial_in = serial_in_override; + else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF) + >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV) + uart->p->serial_in = serial_in_override; } /** -- GitLab From 2f70a1e93657bea0baa7d449aa49e44a08582dc8 Mon Sep 17 00:00:00 2001 From: Vimal Singh Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2111/3892] omap2/3/4: Introducing 'gpmc-nand.c' for GPMC specific NAND init Introducing 'gpmc-nand.c' for GPMC specific NAND init. For example: GPMC timing parameters and all. This patch also migrates gpmc related calls from 'nand/omap2.c' to 'gpmc-nand.c'. Signed-off-by: Vimal Singh Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 3 + arch/arm/mach-omap2/gpmc-nand.c | 139 +++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/nand.h | 10 +- drivers/mtd/nand/omap2.c | 35 +------ 4 files changed, 155 insertions(+), 32 deletions(-) create mode 100644 arch/arm/mach-omap2/gpmc-nand.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 492cf164e000..0b17dca695fd 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -135,5 +135,8 @@ obj-y += usb-ehci.o onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o obj-y += $(onenand-m) $(onenand-y) +nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o +obj-y += $(nand-m) $(nand-y) + smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o obj-y += $(smc91x-m) $(smc91x-y) diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c new file mode 100644 index 000000000000..64d74f05abbe --- /dev/null +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -0,0 +1,139 @@ +/* + * gpmc-nand.c + * + * Copyright (C) 2009 Texas Instruments + * Vimal Singh + * + * 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 +#include + +#define WR_RD_PIN_MONITORING 0x00600000 + +static struct omap_nand_platform_data *gpmc_nand_data; + +static struct resource gpmc_nand_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device gpmc_nand_device = { + .name = "omap2-nand", + .id = 0, + .num_resources = 1, + .resource = &gpmc_nand_resource, +}; + +static int omap2_nand_gpmc_retime(void) +{ + struct gpmc_timings t; + int err; + + memset(&t, 0, sizeof(t)); + t.sync_clk = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->sync_clk); + t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on); + t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on); + + /* Read */ + t.adv_rd_off = gpmc_round_ns_to_ticks( + gpmc_nand_data->gpmc_t->adv_rd_off); + t.oe_on = t.adv_on; + t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access); + t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off); + t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off); + t.rd_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle); + + /* Write */ + t.adv_wr_off = gpmc_round_ns_to_ticks( + gpmc_nand_data->gpmc_t->adv_wr_off); + t.we_on = t.oe_on; + if (cpu_is_omap34xx()) { + t.wr_data_mux_bus = gpmc_round_ns_to_ticks( + gpmc_nand_data->gpmc_t->wr_data_mux_bus); + t.wr_access = gpmc_round_ns_to_ticks( + gpmc_nand_data->gpmc_t->wr_access); + } + t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off); + t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off); + t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle); + + /* Configure GPMC */ + gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1, + GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) | + GPMC_CONFIG1_DEVICETYPE_NAND); + + err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); + if (err) + return err; + + return 0; +} + +static int gpmc_nand_setup(void) +{ + struct device *dev = &gpmc_nand_device.dev; + + /* Set timings in GPMC */ + if (omap2_nand_gpmc_retime() < 0) { + dev_err(dev, "Unable to set gpmc timings\n"); + return -EINVAL; + } + + return 0; +} + +int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data) +{ + unsigned int val; + int err = 0; + struct device *dev = &gpmc_nand_device.dev; + + gpmc_nand_data = _nand_data; + gpmc_nand_data->nand_setup = gpmc_nand_setup; + gpmc_nand_device.dev.platform_data = gpmc_nand_data; + + err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, + &gpmc_nand_data->phys_base); + if (err < 0) { + dev_err(dev, "Cannot request GPMC CS\n"); + return err; + } + + err = gpmc_nand_setup(); + if (err < 0) { + dev_err(dev, "NAND platform setup failed: %d\n", err); + return err; + } + + /* Enable RD PIN Monitoring Reg */ + if (gpmc_nand_data->dev_ready) { + val = gpmc_cs_read_reg(gpmc_nand_data->cs, + GPMC_CS_CONFIG1); + val |= WR_RD_PIN_MONITORING; + gpmc_cs_write_reg(gpmc_nand_data->cs, + GPMC_CS_CONFIG1, val); + } + + err = platform_device_register(&gpmc_nand_device); + if (err < 0) { + dev_err(dev, "Unable to register NAND device\n"); + goto out_free_cs; + } + + return 0; + +out_free_cs: + gpmc_cs_free(gpmc_nand_data->cs); + + return err; +} diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index 631a7bed1eef..6ba88d2630d9 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -15,10 +15,18 @@ struct omap_nand_platform_data { int cs; int gpio_irq; struct mtd_partition *parts; + struct gpmc_timings *gpmc_t; int nr_parts; - int (*nand_setup)(void __iomem *); + int (*nand_setup)(void); int (*dev_ready)(struct omap_nand_platform_data *); int dma_channel; + unsigned long phys_base; void __iomem *gpmc_cs_baseaddr; void __iomem *gpmc_baseaddr; + int devsize; }; + +/* size (4 KiB) for IO mapping */ +#define NAND_IO_SIZE SZ_4K + +extern int gpmc_nand_init(struct omap_nand_platform_data *d); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1bb799f0125c..26aec0080184 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -30,12 +30,8 @@ #define DRIVER_NAME "omap2-nand" -/* size (4 KiB) for IO mapping */ -#define NAND_IO_SIZE SZ_4K - #define NAND_WP_OFF 0 #define NAND_WP_BIT 0x00000010 -#define WR_RD_PIN_MONITORING 0x00600000 #define GPMC_BUF_FULL 0x00000001 #define GPMC_BUF_EMPTY 0x00000000 @@ -882,8 +878,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) struct omap_nand_info *info; struct omap_nand_platform_data *pdata; int err; - unsigned long val; - pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -905,28 +899,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->gpmc_cs = pdata->cs; info->gpmc_baseaddr = pdata->gpmc_baseaddr; info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr; + info->phys_base = pdata->phys_base; info->mtd.priv = &info->nand; info->mtd.name = dev_name(&pdev->dev); info->mtd.owner = THIS_MODULE; - err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base); - if (err < 0) { - dev_err(&pdev->dev, "Cannot request GPMC CS\n"); - goto out_free_info; - } - - /* Enable RD PIN Monitoring Reg */ - if (pdata->dev_ready) { - val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1); - val |= WR_RD_PIN_MONITORING; - gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val); - } - - val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7); - val &= ~(0xf << 8); - val |= (0xc & 0xf) << 8; - gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val); + info->nand.options |= pdata->devsize ? NAND_BUSWIDTH_16 : 0; + info->nand.options |= NAND_SKIP_BBTSCAN; /* NAND write protect off */ omap_nand_wp(&info->mtd, NAND_WP_OFF); @@ -934,7 +914,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) if (!request_mem_region(info->phys_base, NAND_IO_SIZE, pdev->dev.driver->name)) { err = -EBUSY; - goto out_free_cs; + goto out_free_info; } info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE); @@ -963,11 +943,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.chip_delay = 50; } - info->nand.options |= NAND_SKIP_BBTSCAN; - if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000) - == 0x1000) - info->nand.options |= NAND_BUSWIDTH_16; - if (use_prefetch) { /* copy the virtual address of nand base for fifo access */ info->nand_pref_fifo_add = info->nand.IO_ADDR_R; @@ -1043,8 +1018,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) out_release_mem_region: release_mem_region(info->phys_base, NAND_IO_SIZE); -out_free_cs: - gpmc_cs_free(info->gpmc_cs); out_free_info: kfree(info); -- GitLab From c2798e9342a1394de966c31703e0410ee3988378 Mon Sep 17 00:00:00 2001 From: Vimal Singh Date: Mon, 15 Feb 2010 10:03:33 -0800 Subject: [PATCH 2112/3892] omap3: SDP: Introducing 'board-sdp-flash.c' for flash init This patch adds 'board-sdp-flash.c', which could be utilized by boards similar to 3430SDP. (For ex: 2430sdp, 36030sdp). This file does initialization for all three flash devices present in SDP boards (NOR, NAND, OneNAND), by finding there 'cs' number dynamically using switch setting information (S8: 1-4). This also expects partition information from core board files (for ex: board-3430sdp.c). Which allows to choose different default partitions for different boards. A new structure is created for this purpose: 'flash_partitions' in 'mach/board-sdp.h'. This has two members: 1. struct mtd_partition *parts 2. int nr_parts A board file is expected to fill this structure and pass it to 'sdp-flsash-init'. Partition information should be passed in structure array of 'flash_partitions'. Partition information should be passed in below sequence in array: NOR OneNAND NAND Signed-off-by: Vimal Singh Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-sdp-flash.c | 272 +++++++++++++++++++ arch/arm/mach-omap2/include/mach/board-sdp.h | 21 ++ arch/arm/plat-omap/include/plat/gpmc.h | 2 + 3 files changed, 295 insertions(+) create mode 100644 arch/arm/mach-omap2/board-sdp-flash.c create mode 100644 arch/arm/mach-omap2/include/mach/board-sdp.h diff --git a/arch/arm/mach-omap2/board-sdp-flash.c b/arch/arm/mach-omap2/board-sdp-flash.c new file mode 100644 index 000000000000..b1b88deec7f2 --- /dev/null +++ b/arch/arm/mach-omap2/board-sdp-flash.c @@ -0,0 +1,272 @@ +/* + * board-sdp-flash.c + * Modified from mach-omap2/board-3430sdp-flash.c + * + * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2009 Texas Instruments + * + * Vimal Singh + * + * 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 +#include +#include +#include + +#define REG_FPGA_REV 0x10 +#define REG_FPGA_DIP_SWITCH_INPUT2 0x60 +#define MAX_SUPPORTED_GPMC_CONFIG 3 + +#define DEBUG_BASE 0x08000000 /* debug board */ + +#define PDC_NOR 1 +#define PDC_NAND 2 +#define PDC_ONENAND 3 +#define DBG_MPDB 4 + +/* various memory sizes */ +#define FLASH_SIZE_SDPV1 SZ_64M /* NOR flash (64 Meg aligned) */ +#define FLASH_SIZE_SDPV2 SZ_128M /* NOR flash (256 Meg aligned) */ + +/* + * SDP3430 V2 Board CS organization + * Different from SDP3430 V1. Now 4 switches used to specify CS + * + * See also the Switch S8 settings in the comments. + * + * REVISIT: Add support for 2430 SDP + */ +static const unsigned char chip_sel_sdp[][GPMC_CS_NUM] = { + {PDC_NOR, PDC_NAND, PDC_ONENAND, DBG_MPDB, 0, 0, 0, 0}, /* S8:1111 */ + {PDC_ONENAND, PDC_NAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1110 */ + {PDC_NAND, PDC_ONENAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1101 */ +}; + +static struct physmap_flash_data sdp_nor_data = { + .width = 2, +}; + +static struct resource sdp_nor_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device sdp_nor_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &sdp_nor_data, + }, + .num_resources = 1, + .resource = &sdp_nor_resource, +}; + +static void +__init board_nor_init(struct flash_partitions sdp_nor_parts, u8 cs) +{ + int err; + + sdp_nor_data.parts = sdp_nor_parts.parts; + sdp_nor_data.nr_parts = sdp_nor_parts.nr_parts; + + /* Configure start address and size of NOR device */ + if (omap_rev() >= OMAP3430_REV_ES1_0) { + err = gpmc_cs_request(cs, FLASH_SIZE_SDPV2 - 1, + (unsigned long *)&sdp_nor_resource.start); + sdp_nor_resource.end = sdp_nor_resource.start + + FLASH_SIZE_SDPV2 - 1; + } else { + err = gpmc_cs_request(cs, FLASH_SIZE_SDPV1 - 1, + (unsigned long *)&sdp_nor_resource.start); + sdp_nor_resource.end = sdp_nor_resource.start + + FLASH_SIZE_SDPV1 - 1; + } + if (err < 0) { + printk(KERN_ERR "NOR: Can't request GPMC CS\n"); + return; + } + if (platform_device_register(&sdp_nor_device) < 0) + printk(KERN_ERR "Unable to register NOR device\n"); +} + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) +static struct omap_onenand_platform_data board_onenand_data = { + .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */ +}; + +static void +__init board_onenand_init(struct flash_partitions sdp_onenand_parts, u8 cs) +{ + board_onenand_data.cs = cs; + board_onenand_data.parts = sdp_onenand_parts.parts; + board_onenand_data.nr_parts = sdp_onenand_parts.nr_parts; + + gpmc_onenand_init(&board_onenand_data); +} +#else +static void +__init board_onenand_init(struct flash_partitions sdp_onenand_parts, u8 cs) +{ +} +#endif /* CONFIG_MTD_ONENAND_OMAP2 || CONFIG_MTD_ONENAND_OMAP2_MODULE */ + +#if defined(CONFIG_MTD_NAND_OMAP2) || \ + defined(CONFIG_MTD_NAND_OMAP2_MODULE) + +/* Note that all values in this struct are in nanoseconds */ +static struct gpmc_timings nand_timings = { + + .sync_clk = 0, + + .cs_on = 0, + .cs_rd_off = 36, + .cs_wr_off = 36, + + .adv_on = 6, + .adv_rd_off = 24, + .adv_wr_off = 36, + + .we_off = 30, + .oe_off = 48, + + .access = 54, + .rd_cycle = 72, + .wr_cycle = 72, + + .wr_access = 30, + .wr_data_mux_bus = 0, +}; + +static struct omap_nand_platform_data sdp_nand_data = { + .nand_setup = NULL, + .gpmc_t = &nand_timings, + .dma_channel = -1, /* disable DMA in OMAP NAND driver */ + .dev_ready = NULL, + .devsize = 0, /* '0' for 8-bit, '1' for 16-bit device */ +}; + +static void +__init board_nand_init(struct flash_partitions sdp_nand_parts, u8 cs) +{ + sdp_nand_data.cs = cs; + sdp_nand_data.parts = sdp_nand_parts.parts; + sdp_nand_data.nr_parts = sdp_nand_parts.nr_parts; + + sdp_nand_data.gpmc_cs_baseaddr = (void *)(OMAP34XX_GPMC_VIRT + + GPMC_CS0_BASE + + cs * GPMC_CS_SIZE); + sdp_nand_data.gpmc_baseaddr = (void *) (OMAP34XX_GPMC_VIRT); + + gpmc_nand_init(&sdp_nand_data); +} +#else +static void +__init board_nand_init(struct flash_partitions sdp_nand_parts, u8 cs) +{ +} +#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */ + +/** + * get_gpmc0_type - Reads the FPGA DIP_SWITCH_INPUT_REGISTER2 to get + * the various cs values. + */ +static u8 get_gpmc0_type(void) +{ + u8 cs = 0; + void __iomem *fpga_map_addr; + + fpga_map_addr = ioremap(DEBUG_BASE, 4096); + if (!fpga_map_addr) + return -ENOMEM; + + if (!(__raw_readw(fpga_map_addr + REG_FPGA_REV))) + /* we dont have an DEBUG FPGA??? */ + /* Depend on #defines!! default to strata boot return param */ + goto unmap; + + /* S8-DIP-OFF = 1, S8-DIP-ON = 0 */ + cs = __raw_readw(fpga_map_addr + REG_FPGA_DIP_SWITCH_INPUT2) & 0xf; + + /* ES2.0 SDP's onwards 4 dip switches are provided for CS */ + if (omap_rev() >= OMAP3430_REV_ES1_0) + /* change (S8-1:4=DS-2:0) to (S8-4:1=DS-2:0) */ + cs = ((cs & 8) >> 3) | ((cs & 4) >> 1) | + ((cs & 2) << 1) | ((cs & 1) << 3); + else + /* change (S8-1:3=DS-2:0) to (S8-3:1=DS-2:0) */ + cs = ((cs & 4) >> 2) | (cs & 2) | ((cs & 1) << 2); +unmap: + iounmap(fpga_map_addr); + return cs; +} + +/** + * sdp3430_flash_init - Identify devices connected to GPMC and register. + * + * @return - void. + */ +void __init sdp_flash_init(struct flash_partitions sdp_partition_info[]) +{ + u8 cs = 0; + u8 norcs = GPMC_CS_NUM + 1; + u8 nandcs = GPMC_CS_NUM + 1; + u8 onenandcs = GPMC_CS_NUM + 1; + u8 idx; + unsigned char *config_sel = NULL; + + /* REVISIT: Is this return correct idx for 2430 SDP? + * for which cs configuration matches for 2430 SDP? + */ + idx = get_gpmc0_type(); + if (idx >= MAX_SUPPORTED_GPMC_CONFIG) { + printk(KERN_ERR "%s: Invalid chip select: %d\n", __func__, cs); + return; + } + config_sel = (unsigned char *)(chip_sel_sdp[idx]); + + while (cs < GPMC_CS_NUM) { + switch (config_sel[cs]) { + case PDC_NOR: + if (norcs > GPMC_CS_NUM) + norcs = cs; + break; + case PDC_NAND: + if (nandcs > GPMC_CS_NUM) + nandcs = cs; + break; + case PDC_ONENAND: + if (onenandcs > GPMC_CS_NUM) + onenandcs = cs; + break; + }; + cs++; + } + + if (norcs > GPMC_CS_NUM) + printk(KERN_INFO "OneNAND: Unable to find configuration " + " in GPMC\n "); + else + board_nor_init(sdp_partition_info[0], norcs); + + if (onenandcs > GPMC_CS_NUM) + printk(KERN_INFO "OneNAND: Unable to find configuration " + " in GPMC\n "); + else + board_onenand_init(sdp_partition_info[1], onenandcs); + + if (nandcs > GPMC_CS_NUM) + printk(KERN_INFO "NAND: Unable to find configuration " + " in GPMC\n "); + else + board_nand_init(sdp_partition_info[2], nandcs); +} diff --git a/arch/arm/mach-omap2/include/mach/board-sdp.h b/arch/arm/mach-omap2/include/mach/board-sdp.h new file mode 100644 index 000000000000..465169c0908a --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/board-sdp.h @@ -0,0 +1,21 @@ +/* + * board-sdp.h + * + * Information structures for SDP-specific board config data + * + * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2009 Texas Instruments + * + * 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 + +struct flash_partitions { + struct mtd_partition *parts; + int nr_parts; +}; + +extern void sdp_flash_init(struct flash_partitions []); diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index 3f3609aa277f..145838a81ef6 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -27,6 +27,8 @@ #define GPMC_CONFIG 0x50 #define GPMC_STATUS 0x54 +#define GPMC_CS0_BASE 0x60 +#define GPMC_CS_SIZE 0x30 #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31) #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30) -- GitLab From 88c8460ac32283e2a25e36e4670ff5ab02f3b521 Mon Sep 17 00:00:00 2001 From: Vimal Singh Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2113/3892] omap3: Add support for flash on 3430SDP board This patch adds support for flashes on 3430SDP boards. All three NAND, NOR and OneNAND are supported. I have tested it on 3430SDP (ES2 and ES3.1). This patch can be treated as an example to "how to utilize": 'gpmc-nand.c' and 'board-sdp-flash.c'. Similar patches can be created for 2430sdp and 3630sdp or any other similar board. Signed-off-by: Vimal Singh Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/board-3430sdp.c | 111 ++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 0b17dca695fd..af5853f13c7a 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -100,7 +100,8 @@ obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \ obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \ mmc-twl4030.o obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ - mmc-twl4030.o + mmc-twl4030.o \ + board-sdp-flash.o obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ board-rx51-sdram.o \ diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index eda4f6448cce..2e38e5bc1cc8 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -41,6 +41,8 @@ #include #include +#include + #include "mux.h" #include "sdram-qimonda-hyb18m512160af-6.h" #include "mmc-twl4030.h" @@ -650,6 +652,114 @@ static struct omap_board_mux board_mux[] __initdata = { #define board_mux NULL #endif +static struct mtd_partition sdp_nor_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "Bootloader-NOR", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "Params-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "Kernel-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* file system */ + { + .name = "Filesystem-NOR", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct mtd_partition sdp_onenand_partitions[] = { + { + .name = "X-Loader-OneNAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 2 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot Environment-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 1 * (64 * 2048), + }, + { + .name = "Kernel-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 16 * (64 * 2048), + }, + { + .name = "File System-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct mtd_partition sdp_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader-NAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 10 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "Boot Env-NAND", + + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */ + .size = 6 * (64 * 2048), + }, + { + .name = "Kernel-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 40 * (64 * 2048), + }, + { + .name = "File System - NAND", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, /* Offset = 0x780000 */ + }, +}; + +static struct flash_partitions sdp_flash_partitions[] = { + { + .parts = sdp_nor_partitions, + .nr_parts = ARRAY_SIZE(sdp_nor_partitions), + }, + { + .parts = sdp_onenand_partitions, + .nr_parts = ARRAY_SIZE(sdp_onenand_partitions), + }, + { + .parts = sdp_nand_partitions, + .nr_parts = ARRAY_SIZE(sdp_nand_partitions), + }, +}; + static void __init omap_3430sdp_init(void) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); @@ -666,6 +776,7 @@ static void __init omap_3430sdp_init(void) omap_serial_init(); usb_musb_init(); board_smc91x_init(); + sdp_flash_init(sdp_flash_partitions); sdp3430_display_init(); enable_board_wakeup_source(); usb_ehci_init(&ehci_pdata); -- GitLab From db0fefc5119e2cfaa8f57565331e0abe47f0801e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2114/3892] omap_hsmmc: Move gpio and regulator control from board file This patch moves the setup code for GPIO's and Voltage Regulators from the board file mmc-twl4030.c to the driver omap_hsmmc.c. PBIAS and other system control configuration remains in the board file. Moving GPIO code to the driver makes the board initialisation code independent of when GPIO's are defined. That makes the board initialisation now entirely independent of its original twl4030 roots. Moving Voltage Regulator code to the driver allows for further development of regulator support in the core MMC code. It also permits the MMC core to be compiled as a module, because the board code no longer calls MMC core functions. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/configs/rx51_defconfig | 4 +- arch/arm/mach-omap2/mmc-twl4030.c | 352 +++----------------------- arch/arm/mach-omap2/mmc-twl4030.h | 4 +- arch/arm/plat-omap/include/plat/mmc.h | 28 +- drivers/mmc/host/omap_hsmmc.c | 352 +++++++++++++++++++++++++- 5 files changed, 391 insertions(+), 349 deletions(-) diff --git a/arch/arm/configs/rx51_defconfig b/arch/arm/configs/rx51_defconfig index b6eeebb31761..426ae948aefe 100644 --- a/arch/arm/configs/rx51_defconfig +++ b/arch/arm/configs/rx51_defconfig @@ -1354,7 +1354,7 @@ CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_ISP1301_OMAP is not set CONFIG_TWL4030_USB=y -CONFIG_MMC=y +CONFIG_MMC=m # CONFIG_MMC_DEBUG is not set # CONFIG_MMC_UNSAFE_RESUME is not set @@ -1362,7 +1362,7 @@ CONFIG_MMC=y # MMC/SD/SDIO Card Drivers # CONFIG_MMC_BLOCK=m -CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_BOUNCE is not set # CONFIG_SDIO_UART is not set # CONFIG_MMC_TEST is not set diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c index 8afe9dd3f150..6f8f29e99ff2 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -9,26 +9,17 @@ * 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 +#include +#include #include -#include -#include -#include - #include #include #include -#include #include "mmc-twl4030.h" - -#if defined(CONFIG_REGULATOR) && \ - (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) +#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) static u16 control_pbias_offset; static u16 control_devconf1_offset; @@ -36,168 +27,9 @@ static u16 control_devconf1_offset; #define HSMMC_NAME_LEN 9 static struct twl_mmc_controller { - struct omap_mmc_platform_data *mmc; - /* Vcc == configured supply - * Vcc_alt == optional - * - MMC1, supply for DAT4..DAT7 - * - MMC2/MMC2, external level shifter voltage supply, for - * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) - */ - struct regulator *vcc; - struct regulator *vcc_aux; char name[HSMMC_NAME_LEN + 1]; } hsmmc[OMAP34XX_NR_MMC]; -static int twl_mmc_card_detect(int irq) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { - struct omap_mmc_platform_data *mmc; - - mmc = hsmmc[i].mmc; - if (!mmc) - continue; - if (irq != mmc->slots[0].card_detect_irq) - continue; - - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); - } - return -ENOSYS; -} - -static int twl_mmc_get_ro(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - /* NOTE: assumes write protect signal is active-high */ - return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); -} - -static int twl_mmc_get_cover_state(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); -} - -/* - * MMC Slot Initialization. - */ -static int twl_mmc_late_init(struct device *dev) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - int ret = 0; - int i; - - /* MMC/SD/SDIO doesn't require a card detect switch */ - if (gpio_is_valid(mmc->slots[0].switch_pin)) { - ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); - if (ret) - goto done; - ret = gpio_direction_input(mmc->slots[0].switch_pin); - if (ret) - goto err; - } - - /* require at least main regulator */ - for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { - if (hsmmc[i].name == mmc->slots[0].name) { - struct regulator *reg; - - hsmmc[i].mmc = mmc; - - reg = regulator_get(dev, "vmmc"); - if (IS_ERR(reg)) { - dev_dbg(dev, "vmmc regulator missing\n"); - /* HACK: until fixed.c regulator is usable, - * we don't require a main regulator - * for MMC2 or MMC3 - */ - if (i != 0) - break; - ret = PTR_ERR(reg); - hsmmc[i].vcc = NULL; - goto err; - } - hsmmc[i].vcc = reg; - mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg); - - /* allow an aux regulator */ - reg = regulator_get(dev, "vmmc_aux"); - hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg; - - /* UGLY HACK: workaround regulator framework bugs. - * When the bootloader leaves a supply active, it's - * initialized with zero usecount ... and we can't - * disable it without first enabling it. Until the - * framework is fixed, we need a workaround like this - * (which is safe for MMC, but not in general). - */ - if (regulator_is_enabled(hsmmc[i].vcc) > 0) { - regulator_enable(hsmmc[i].vcc); - regulator_disable(hsmmc[i].vcc); - } - if (hsmmc[i].vcc_aux) { - if (regulator_is_enabled(reg) > 0) { - regulator_enable(reg); - regulator_disable(reg); - } - } - - break; - } - } - - return 0; - -err: - gpio_free(mmc->slots[0].switch_pin); -done: - mmc->slots[0].card_detect_irq = 0; - mmc->slots[0].card_detect = NULL; - - dev_err(dev, "err %d configuring card detect\n", ret); - return ret; -} - -static void twl_mmc_cleanup(struct device *dev) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - int i; - - gpio_free(mmc->slots[0].switch_pin); - for(i = 0; i < ARRAY_SIZE(hsmmc); i++) { - regulator_put(hsmmc[i].vcc); - regulator_put(hsmmc[i].vcc_aux); - } -} - -#ifdef CONFIG_PM - -static int twl_mmc_suspend(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - disable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -static int twl_mmc_resume(struct device *dev, int slot) -{ - struct omap_mmc_platform_data *mmc = dev->platform_data; - - enable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -#else -#define twl_mmc_suspend NULL -#define twl_mmc_resume NULL -#endif - #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) static int twl4030_mmc_get_context_loss(struct device *dev) @@ -210,12 +42,10 @@ static int twl4030_mmc_get_context_loss(struct device *dev) #define twl4030_mmc_get_context_loss NULL #endif -static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, - int vdd) +static void hsmmc1_before_set_reg(struct device *dev, int slot, + int power_on, int vdd) { u32 reg, prog_io; - int ret = 0; - struct twl_mmc_controller *c = &hsmmc[0]; struct omap_mmc_platform_data *mmc = dev->platform_data; /* @@ -255,11 +85,22 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, } reg &= ~OMAP2_PBIASLITEPWRDNZ0; omap_ctrl_writel(reg, control_pbias_offset); + } else { + reg = omap_ctrl_readl(control_pbias_offset); + reg &= ~OMAP2_PBIASLITEPWRDNZ0; + omap_ctrl_writel(reg, control_pbias_offset); + } +} + +static void hsmmc1_after_set_reg(struct device *dev, int slot, + int power_on, int vdd) +{ + u32 reg; - ret = mmc_regulator_set_ocr(c->vcc, vdd); + /* 100ms delay required for PBIAS configuration */ + msleep(100); - /* 100ms delay required for PBIAS configuration */ - msleep(100); + if (power_on) { reg = omap_ctrl_readl(control_pbias_offset); reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); if ((1 << vdd) <= MMC_VDD_165_195) @@ -268,61 +109,20 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, reg |= OMAP2_PBIASLITEVMODE0; omap_ctrl_writel(reg, control_pbias_offset); } else { - reg = omap_ctrl_readl(control_pbias_offset); - reg &= ~OMAP2_PBIASLITEPWRDNZ0; - omap_ctrl_writel(reg, control_pbias_offset); - - ret = mmc_regulator_set_ocr(c->vcc, 0); - - /* 100ms delay required for PBIAS configuration */ - msleep(100); reg = omap_ctrl_readl(control_pbias_offset); reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASLITEVMODE0); omap_ctrl_writel(reg, control_pbias_offset); } - - return ret; } -static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd) +static void hsmmc23_before_set_reg(struct device *dev, int slot, + int power_on, int vdd) { - int ret = 0; - struct twl_mmc_controller *c = NULL; struct omap_mmc_platform_data *mmc = dev->platform_data; - int i; - - for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { - if (mmc == hsmmc[i].mmc) { - c = &hsmmc[i]; - break; - } - } - - if (c == NULL) - return -ENODEV; - - /* If we don't see a Vcc regulator, assume it's a fixed - * voltage always-on regulator. - */ - if (!c->vcc) - return 0; - /* - * Assume Vcc regulator is used only to power the card ... OMAP - * VDDS is used to power the pins, optionally with a transceiver to - * support cards using voltages other than VDDS (1.8V nominal). When a - * transceiver is used, DAT3..7 are muxed as transceiver control pins. - * - * In some cases this regulator won't support enable/disable; - * e.g. it's a fixed rail for a WLAN chip. - * - * In other cases vcc_aux switches interface power. Example, for - * eMMC cards it represents VccQ. Sometimes transceivers or SDIO - * chips/cards need an interface voltage rail too. - */ if (power_on) { - /* only MMC2 supports a CLKIN */ + /* Only MMC2 supports a CLKIN */ if (mmc->slots[0].internal_clock) { u32 reg; @@ -330,76 +130,7 @@ static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int v reg |= OMAP2_MMCSDIO2ADPCLKISEL; omap_ctrl_writel(reg, control_devconf1_offset); } - ret = mmc_regulator_set_ocr(c->vcc, vdd); - /* enable interface voltage rail, if needed */ - if (ret == 0 && c->vcc_aux) { - ret = regulator_enable(c->vcc_aux); - if (ret < 0) - ret = mmc_regulator_set_ocr(c->vcc, 0); - } - } else { - if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0) - ret = regulator_disable(c->vcc_aux); - if (ret == 0) - ret = mmc_regulator_set_ocr(c->vcc, 0); - } - - return ret; -} - -static int twl_mmc1_set_sleep(struct device *dev, int slot, int sleep, int vdd, - int cardsleep) -{ - struct twl_mmc_controller *c = &hsmmc[0]; - int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; - - return regulator_set_mode(c->vcc, mode); -} - -static int twl_mmc23_set_sleep(struct device *dev, int slot, int sleep, int vdd, - int cardsleep) -{ - struct twl_mmc_controller *c = NULL; - struct omap_mmc_platform_data *mmc = dev->platform_data; - int i, err, mode; - - for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { - if (mmc == hsmmc[i].mmc) { - c = &hsmmc[i]; - break; - } } - - if (c == NULL) - return -ENODEV; - - /* - * If we don't see a Vcc regulator, assume it's a fixed - * voltage always-on regulator. - */ - if (!c->vcc) - return 0; - - mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; - - if (!c->vcc_aux) - return regulator_set_mode(c->vcc, mode); - - if (cardsleep) { - /* VCC can be turned off if card is asleep */ - struct regulator *vcc_aux = c->vcc_aux; - - c->vcc_aux = NULL; - if (sleep) - err = twl_mmc23_set_power(dev, slot, 0, 0); - else - err = twl_mmc23_set_power(dev, slot, 1, vdd); - c->vcc_aux = vcc_aux; - } else - err = regulator_set_mode(c->vcc, mode); - if (err) - return err; - return regulator_set_mode(c->vcc_aux, mode); } static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; @@ -413,7 +144,6 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) if (cpu_is_omap2430()) { control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; - nr_hsmmc = 2; } else { control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; @@ -448,35 +178,15 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) mmc->slots[0].wires = c->wires; mmc->slots[0].internal_clock = !c->ext_clock; mmc->dma_mask = 0xffffffff; - mmc->init = twl_mmc_late_init; - - /* note: twl4030 card detect GPIOs can disable VMMCx ... */ - if (gpio_is_valid(c->gpio_cd)) { - mmc->cleanup = twl_mmc_cleanup; - mmc->suspend = twl_mmc_suspend; - mmc->resume = twl_mmc_resume; - - mmc->slots[0].switch_pin = c->gpio_cd; - mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd); - if (c->cover_only) - mmc->slots[0].get_cover_state = twl_mmc_get_cover_state; - else - mmc->slots[0].card_detect = twl_mmc_card_detect; - } else - mmc->slots[0].switch_pin = -EINVAL; mmc->get_context_loss_count = twl4030_mmc_get_context_loss; - /* write protect normally uses an OMAP gpio */ - if (gpio_is_valid(c->gpio_wp)) { - gpio_request(c->gpio_wp, "mmc_wp"); - gpio_direction_input(c->gpio_wp); + mmc->slots[0].switch_pin = c->gpio_cd; + mmc->slots[0].gpio_wp = c->gpio_wp; - mmc->slots[0].gpio_wp = c->gpio_wp; - mmc->slots[0].get_ro = twl_mmc_get_ro; - } else - mmc->slots[0].gpio_wp = -EINVAL; + if (c->cover_only) + mmc->slots[0].cover = 1; if (c->nonremovable) mmc->slots[0].nonremovable = 1; @@ -495,8 +205,8 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) switch (c->mmc) { case 1: /* on-chip level shifting via PBIAS0/PBIAS1 */ - mmc->slots[0].set_power = twl_mmc1_set_power; - mmc->slots[0].set_sleep = twl_mmc1_set_sleep; + mmc->slots[0].before_set_reg = hsmmc1_before_set_reg; + mmc->slots[0].after_set_reg = hsmmc1_after_set_reg; /* Omap3630 HSMMC1 supports only 4-bit */ if (cpu_is_omap3630() && c->wires > 4) { @@ -512,8 +222,8 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) /* FALLTHROUGH */ case 3: /* off-chip level shifting, or none */ - mmc->slots[0].set_power = twl_mmc23_set_power; - mmc->slots[0].set_sleep = twl_mmc23_set_sleep; + mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; + mmc->slots[0].after_set_reg = NULL; break; default: pr_err("MMC%d configuration not supported!\n", c->mmc); diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h index a47e68563fb6..87d67c10bdec 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.h +++ b/arch/arm/mach-omap2/mmc-twl4030.h @@ -21,9 +21,7 @@ struct twl4030_hsmmc_info { int ocr_mask; /* temporary HACK */ }; -#if defined(CONFIG_REGULATOR) && \ - (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ - defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) +#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) void twl4030_mmc_init(struct twl4030_hsmmc_info *); diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 29937137bf3e..515701bb47d2 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -55,12 +55,12 @@ struct omap_mmc_platform_data { unsigned int max_freq; /* switch the bus to a new slot */ - int (* switch_slot)(struct device *dev, int slot); + int (*switch_slot)(struct device *dev, int slot); /* initialize board-specific MMC functionality, can be NULL if * not supported */ - int (* init)(struct device *dev); - void (* cleanup)(struct device *dev); - void (* shutdown)(struct device *dev); + int (*init)(struct device *dev); + void (*cleanup)(struct device *dev); + void (*shutdown)(struct device *dev); /* To handle board related suspend/resume functionality for MMC */ int (*suspend)(struct device *dev, int slot); @@ -99,11 +99,18 @@ struct omap_mmc_platform_data { int switch_pin; /* gpio (card detect) */ int gpio_wp; /* gpio (write protect) */ - int (* set_bus_mode)(struct device *dev, int slot, int bus_mode); - int (* set_power)(struct device *dev, int slot, int power_on, int vdd); - int (* get_ro)(struct device *dev, int slot); + int (*set_bus_mode)(struct device *dev, int slot, int bus_mode); + int (*set_power)(struct device *dev, int slot, + int power_on, int vdd); + int (*get_ro)(struct device *dev, int slot); int (*set_sleep)(struct device *dev, int slot, int sleep, int vdd, int cardsleep); + /* Call back before enabling / disabling regulators */ + void (*before_set_reg)(struct device *dev, int slot, + int power_on, int vdd); + /* Call back after enabling / disabling regulators */ + void (*after_set_reg)(struct device *dev, int slot, + int power_on, int vdd); /* return MMC cover switch state, can be NULL if not supported. * @@ -111,14 +118,14 @@ struct omap_mmc_platform_data { * 0 - closed * 1 - open */ - int (* get_cover_state)(struct device *dev, int slot); + int (*get_cover_state)(struct device *dev, int slot); const char *name; u32 ocr_mask; /* Card detection IRQs */ int card_detect_irq; - int (* card_detect)(int irq); + int (*card_detect)(struct device *dev, int slot); unsigned int ban_openended:1; @@ -126,7 +133,8 @@ struct omap_mmc_platform_data { }; /* called from board-specific card detection service routine */ -extern void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed); +extern void omap_mmc_notify_cover_event(struct device *dev, int slot, + int is_closed); #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4b2322518909..2c5e15d9f864 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -146,6 +148,15 @@ struct omap_hsmmc_host { struct clk *fclk; struct clk *iclk; struct clk *dbclk; + /* + * vcc == configured supply + * vcc_aux == optional + * - MMC1, supply for DAT4..DAT7 + * - MMC2/MMC2, external level shifter voltage supply, for + * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) + */ + struct regulator *vcc; + struct regulator *vcc_aux; struct semaphore sem; struct work_struct mmc_carddetect_work; void __iomem *base; @@ -171,10 +182,308 @@ struct omap_hsmmc_host { int vdd; int protect_card; int reqs_blocked; + int use_reg; struct omap_mmc_platform_data *pdata; }; +static int omap_hsmmc_card_detect(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + /* NOTE: assumes card detect signal is active-low */ + return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); +} + +static int omap_hsmmc_get_wp(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + /* NOTE: assumes write protect signal is active-high */ + return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); +} + +static int omap_hsmmc_get_cover_state(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + /* NOTE: assumes card detect signal is active-low */ + return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); +} + +#ifdef CONFIG_PM + +static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + disable_irq(mmc->slots[0].card_detect_irq); + return 0; +} + +static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + enable_irq(mmc->slots[0].card_detect_irq); + return 0; +} + +#else + +#define omap_hsmmc_suspend_cdirq NULL +#define omap_hsmmc_resume_cdirq NULL + +#endif + +static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int ret; + + if (mmc_slot(host).before_set_reg) + mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); + + if (power_on) + ret = mmc_regulator_set_ocr(host->vcc, vdd); + else + ret = mmc_regulator_set_ocr(host->vcc, 0); + + if (mmc_slot(host).after_set_reg) + mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); + + return ret; +} + +static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int ret = 0; + + /* + * If we don't see a Vcc regulator, assume it's a fixed + * voltage always-on regulator. + */ + if (!host->vcc) + return 0; + + if (mmc_slot(host).before_set_reg) + mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); + + /* + * Assume Vcc regulator is used only to power the card ... OMAP + * VDDS is used to power the pins, optionally with a transceiver to + * support cards using voltages other than VDDS (1.8V nominal). When a + * transceiver is used, DAT3..7 are muxed as transceiver control pins. + * + * In some cases this regulator won't support enable/disable; + * e.g. it's a fixed rail for a WLAN chip. + * + * In other cases vcc_aux switches interface power. Example, for + * eMMC cards it represents VccQ. Sometimes transceivers or SDIO + * chips/cards need an interface voltage rail too. + */ + if (power_on) { + ret = mmc_regulator_set_ocr(host->vcc, vdd); + /* Enable interface voltage rail, if needed */ + if (ret == 0 && host->vcc_aux) { + ret = regulator_enable(host->vcc_aux); + if (ret < 0) + ret = mmc_regulator_set_ocr(host->vcc, 0); + } + } else { + if (host->vcc_aux) { + ret = regulator_is_enabled(host->vcc_aux); + if (ret > 0) + ret = regulator_disable(host->vcc_aux); + } + if (ret == 0) + ret = mmc_regulator_set_ocr(host->vcc, 0); + } + + if (mmc_slot(host).after_set_reg) + mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); + + return ret; +} + +static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep, + int vdd, int cardsleep) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + return regulator_set_mode(host->vcc, mode); +} + +static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep, + int vdd, int cardsleep) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int err, mode; + + /* + * If we don't see a Vcc regulator, assume it's a fixed + * voltage always-on regulator. + */ + if (!host->vcc) + return 0; + + mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + if (!host->vcc_aux) + return regulator_set_mode(host->vcc, mode); + + if (cardsleep) { + /* VCC can be turned off if card is asleep */ + if (sleep) + err = mmc_regulator_set_ocr(host->vcc, 0); + else + err = mmc_regulator_set_ocr(host->vcc, vdd); + } else + err = regulator_set_mode(host->vcc, mode); + if (err) + return err; + return regulator_set_mode(host->vcc_aux, mode); +} + +static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) +{ + int ret; + + if (gpio_is_valid(pdata->slots[0].switch_pin)) { + pdata->suspend = omap_hsmmc_suspend_cdirq; + pdata->resume = omap_hsmmc_resume_cdirq; + if (pdata->slots[0].cover) + pdata->slots[0].get_cover_state = + omap_hsmmc_get_cover_state; + else + pdata->slots[0].card_detect = omap_hsmmc_card_detect; + pdata->slots[0].card_detect_irq = + gpio_to_irq(pdata->slots[0].switch_pin); + ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); + if (ret) + return ret; + ret = gpio_direction_input(pdata->slots[0].switch_pin); + if (ret) + goto err_free_sp; + } else + pdata->slots[0].switch_pin = -EINVAL; + + if (gpio_is_valid(pdata->slots[0].gpio_wp)) { + pdata->slots[0].get_ro = omap_hsmmc_get_wp; + ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); + if (ret) + goto err_free_cd; + ret = gpio_direction_input(pdata->slots[0].gpio_wp); + if (ret) + goto err_free_wp; + } else + pdata->slots[0].gpio_wp = -EINVAL; + + return 0; + +err_free_wp: + gpio_free(pdata->slots[0].gpio_wp); +err_free_cd: + if (gpio_is_valid(pdata->slots[0].switch_pin)) +err_free_sp: + gpio_free(pdata->slots[0].switch_pin); + return ret; +} + +static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) +{ + if (gpio_is_valid(pdata->slots[0].gpio_wp)) + gpio_free(pdata->slots[0].gpio_wp); + if (gpio_is_valid(pdata->slots[0].switch_pin)) + gpio_free(pdata->slots[0].switch_pin); +} + +static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) +{ + struct regulator *reg; + int ret = 0; + + switch (host->id) { + case OMAP_MMC1_DEVID: + /* On-chip level shifting via PBIAS0/PBIAS1 */ + mmc_slot(host).set_power = omap_hsmmc_1_set_power; + mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep; + break; + case OMAP_MMC2_DEVID: + case OMAP_MMC3_DEVID: + /* Off-chip level shifting, or none */ + mmc_slot(host).set_power = omap_hsmmc_23_set_power; + mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep; + break; + default: + pr_err("MMC%d configuration not supported!\n", host->id); + return -EINVAL; + } + + reg = regulator_get(host->dev, "vmmc"); + if (IS_ERR(reg)) { + dev_dbg(host->dev, "vmmc regulator missing\n"); + /* + * HACK: until fixed.c regulator is usable, + * we don't require a main regulator + * for MMC2 or MMC3 + */ + if (host->id == OMAP_MMC1_DEVID) { + ret = PTR_ERR(reg); + goto err; + } + } else { + host->vcc = reg; + mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg); + + /* Allow an aux regulator */ + reg = regulator_get(host->dev, "vmmc_aux"); + host->vcc_aux = IS_ERR(reg) ? NULL : reg; + + /* + * UGLY HACK: workaround regulator framework bugs. + * When the bootloader leaves a supply active, it's + * initialized with zero usecount ... and we can't + * disable it without first enabling it. Until the + * framework is fixed, we need a workaround like this + * (which is safe for MMC, but not in general). + */ + if (regulator_is_enabled(host->vcc) > 0) { + regulator_enable(host->vcc); + regulator_disable(host->vcc); + } + if (host->vcc_aux) { + if (regulator_is_enabled(reg) > 0) { + regulator_enable(reg); + regulator_disable(reg); + } + } + } + + return 0; + +err: + mmc_slot(host).set_power = NULL; + mmc_slot(host).set_sleep = NULL; + return ret; +} + +static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) +{ + regulator_put(host->vcc); + regulator_put(host->vcc_aux); + mmc_slot(host).set_power = NULL; + mmc_slot(host).set_sleep = NULL; +} + /* * Stop clock to the card */ @@ -835,7 +1144,7 @@ static void omap_hsmmc_detect(struct work_struct *work) sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (slot->card_detect) - carddetect = slot->card_detect(slot->card_detect_irq); + carddetect = slot->card_detect(host->dev, host->slot_id); else { omap_hsmmc_protect_card(host); carddetect = -ENOSYS; @@ -1242,7 +1551,7 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) if (!mmc_slot(host).card_detect) return -ENOSYS; - return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq); + return mmc_slot(host).card_detect(host->dev, host->slot_id); } static int omap_hsmmc_get_ro(struct mmc_host *mmc) @@ -1616,7 +1925,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; - int ret = 0, irq; + int ret, irq; if (pdata == NULL) { dev_err(&pdev->dev, "Platform Data is missing\n"); @@ -1638,10 +1947,14 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) if (res == NULL) return -EBUSY; + ret = omap_hsmmc_gpio_init(pdata); + if (ret) + goto err; + mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; - goto err; + goto err_alloc; } host = mmc_priv(mmc); @@ -1781,7 +2094,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - /* initialize power supplies, gpios, etc */ if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { dev_dbg(mmc_dev(host->mmc), @@ -1789,6 +2101,14 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) goto err_irq_cd_init; } } + + if (!mmc_slot(host).set_power) { + ret = omap_hsmmc_reg_get(host); + if (ret) + goto err_reg; + host->use_reg = 1; + } + mmc->ocr_avail = mmc_slot(host).ocr_mask; /* Request IRQ for card detect */ @@ -1823,19 +2143,22 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) - goto err_cover_switch; + goto err_slot_name; } omap_hsmmc_debugfs(mmc); return 0; -err_cover_switch: - device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); err_slot_name: mmc_remove_host(mmc); -err_irq_cd: free_irq(mmc_slot(host).card_detect_irq, host); +err_irq_cd: + if (host->use_reg) + omap_hsmmc_reg_put(host); +err_reg: + if (host->pdata->cleanup) + host->pdata->cleanup(&pdev->dev); err_irq_cd_init: free_irq(host->irq, host); err_irq: @@ -1847,14 +2170,14 @@ err_irq: clk_disable(host->dbclk); clk_put(host->dbclk); } - err1: iounmap(host->base); + platform_set_drvdata(pdev, NULL); + mmc_free_host(mmc); +err_alloc: + omap_hsmmc_gpio_free(pdata); err: - dev_dbg(mmc_dev(host->mmc), "Probe Failed\n"); release_mem_region(res->start, res->end - res->start + 1); - if (host) - mmc_free_host(mmc); return ret; } @@ -1866,6 +2189,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev) if (host) { mmc_host_enable(host->mmc); mmc_remove_host(host->mmc); + if (host->use_reg) + omap_hsmmc_reg_put(host); if (host->pdata->cleanup) host->pdata->cleanup(&pdev->dev); free_irq(host->irq, host); @@ -1884,6 +2209,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) mmc_free_host(host->mmc); iounmap(host->base); + omap_hsmmc_gpio_free(pdev->dev.platform_data); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- GitLab From d02a900b5952597b6beebd709d92ab392fa3005a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2115/3892] omap: Rename mmc-twl4030 files to hsmmc mmc-twl4030.[ch] no longer has any dependency on twl4030 and should be renamed to reflect that. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 28 +++++++++---------- arch/arm/mach-omap2/board-2430sdp.c | 2 +- arch/arm/mach-omap2/board-3430sdp.c | 2 +- arch/arm/mach-omap2/board-cm-t35.c | 2 +- arch/arm/mach-omap2/board-igep0020.c | 2 +- arch/arm/mach-omap2/board-ldp.c | 2 +- arch/arm/mach-omap2/board-omap3beagle.c | 2 +- arch/arm/mach-omap2/board-omap3evm.c | 2 +- arch/arm/mach-omap2/board-omap3pandora.c | 2 +- arch/arm/mach-omap2/board-omap3touchbook.c | 2 +- arch/arm/mach-omap2/board-overo.c | 2 +- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- arch/arm/mach-omap2/board-zoom-peripherals.c | 2 +- .../arm/mach-omap2/{mmc-twl4030.c => hsmmc.c} | 4 +-- .../arm/mach-omap2/{mmc-twl4030.h => hsmmc.h} | 0 15 files changed, 28 insertions(+), 28 deletions(-) rename arch/arm/mach-omap2/{mmc-twl4030.c => hsmmc.c} (98%) rename arch/arm/mach-omap2/{mmc-twl4030.h => hsmmc.h} (100%) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index af5853f13c7a..dfc49a0c6927 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -87,43 +87,43 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OVERO) += board-overo.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ - mmc-twl4030.o \ + hsmmc.o \ board-sdp-flash.o obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ board-rx51-sdram.o \ board-rx51-peripherals.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \ board-zoom-peripherals.o \ - mmc-twl4030.o \ + hsmmc.o \ board-zoom-debugboard.o obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom3.o \ board-zoom-peripherals.o \ - mmc-twl4030.o \ + hsmmc.o \ board-zoom-debugboard.o obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \ board-zoom-peripherals.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \ - mmc-twl4030.o + hsmmc.o obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 18497b7a8278..a43c0943dbf3 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -38,7 +38,7 @@ #include #include -#include "mmc-twl4030.h" +#include "hsmmc.h" #define SDP2430_CS0_BASE 0x04000000 #define SECONDARY_LCD_GPIO 147 diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 2e38e5bc1cc8..6c7261b6b06f 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -45,7 +45,7 @@ #include "mux.h" #include "sdram-qimonda-hyb18m512160af-6.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define CONFIG_DISABLE_HFCLK 1 diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 0e292317c0ca..ac3c9332d0fa 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -50,7 +50,7 @@ #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define CM_T35_GPIO_PENDOWN 57 diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 9f7543384498..ea7bfbaceddd 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -30,7 +30,7 @@ #include #include "mux.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define IGEP2_SMSC911X_CS 5 #define IGEP2_SMSC911X_GPIO 176 diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index f1699674a2fc..f2b47cb7275a 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -44,7 +44,7 @@ #include #include "mux.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define LDP_SMSC911X_CS 1 #define LDP_SMSC911X_GPIO 152 diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index bf91bf7bd921..7812da065d2f 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -45,7 +45,7 @@ #include #include "mux.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define GPMC_CS0_BASE 0x60 #define GPMC_CS_SIZE 0x30 diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index a221b7a1fcc6..78724d859216 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -45,7 +45,7 @@ #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define OMAP3_EVM_TS_GPIO 175 #define OMAP3_EVM_EHCI_VBUS 22 diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index bc482abdd5d4..63437037fc9f 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -43,7 +43,7 @@ #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define OMAP3_PANDORA_TS_GPIO 94 diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index 63436e9c2069..1e3f53c605ca 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -50,7 +50,7 @@ #include #include "mux.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #include diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 61abe0907265..3fc918b0c655 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -48,7 +48,7 @@ #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define OVERO_GPIO_BT_XGATE 15 #define OVERO_GPIO_W2W_NRESET 16 diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index acafdbc8aa16..b2de2066fb00 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -34,7 +34,7 @@ #include #include "mux.h" -#include "mmc-twl4030.h" +#include "hsmmc.h" #define SYSTEM_REV_B_USES_VAUX3 0x1699 #define SYSTEM_REV_S_USES_VAUX3 0x8 diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 1e3dfb652acc..52940a426d9d 100755 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -24,7 +24,7 @@ #include #include -#include "mmc-twl4030.h" +#include "hsmmc.h" /* Zoom2 has Qwerty keyboard*/ static int board_keymap[] = { diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/hsmmc.c similarity index 98% rename from arch/arm/mach-omap2/mmc-twl4030.c rename to arch/arm/mach-omap2/hsmmc.c index 6f8f29e99ff2..df1cf7273317 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap2/mmc-twl4030.c + * linux/arch/arm/mach-omap2/hsmmc.c * * Copyright (C) 2007-2008 Texas Instruments * Copyright (C) 2008 Nokia Corporation @@ -17,7 +17,7 @@ #include #include -#include "mmc-twl4030.h" +#include "hsmmc.h" #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/hsmmc.h similarity index 100% rename from arch/arm/mach-omap2/mmc-twl4030.h rename to arch/arm/mach-omap2/hsmmc.h -- GitLab From 68ff04231ce9128d400f47762ae3c921be79cd49 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2116/3892] omap: Rename hsmmc symbols to reflect independence from twl4030 hsmmc.[ch] no longer has any dependency on twl4030 and variable names should be renamed to reflect that. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-2430sdp.c | 4 ++-- arch/arm/mach-omap2/board-3430sdp.c | 4 ++-- arch/arm/mach-omap2/board-cm-t35.c | 4 ++-- arch/arm/mach-omap2/board-igep0020.c | 4 ++-- arch/arm/mach-omap2/board-ldp.c | 4 ++-- arch/arm/mach-omap2/board-omap3beagle.c | 4 ++-- arch/arm/mach-omap2/board-omap3evm.c | 4 ++-- arch/arm/mach-omap2/board-omap3pandora.c | 4 ++-- arch/arm/mach-omap2/board-omap3touchbook.c | 4 ++-- arch/arm/mach-omap2/board-overo.c | 4 ++-- arch/arm/mach-omap2/board-rx51-peripherals.c | 18 +++++++-------- arch/arm/mach-omap2/board-zoom-peripherals.c | 4 ++-- arch/arm/mach-omap2/hsmmc.c | 24 ++++++++++---------- arch/arm/mach-omap2/hsmmc.h | 6 ++--- 14 files changed, 45 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index a43c0943dbf3..d6f55ef9059d 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -182,7 +182,7 @@ static int __init omap2430_i2c_init(void) return 0; } -static struct twl4030_hsmmc_info mmc[] __initdata = { +static struct omap2_hsmmc_info mmc[] __initdata = { { .mmc = 1, .wires = 4, @@ -201,7 +201,7 @@ static void __init omap_2430sdp_init(void) platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices)); omap_serial_init(); - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); usb_musb_init(); board_smc91x_init(); diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 6c7261b6b06f..5adef517a2b3 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -328,7 +328,7 @@ static struct twl4030_bci_platform_data sdp3430_bci_data = { .tblsize = ARRAY_SIZE(sdp3430_batt_table), }; -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, /* 8 bits (default) requires S6.3 == ON, @@ -365,7 +365,7 @@ static int sdp3430_twl_gpio_setup(struct device *dev, */ mmc[0].gpio_cd = gpio + 0; mmc[1].gpio_cd = gpio + 1; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters ... we "know" the * regulators will be set up only *after* we return. diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index ac3c9332d0fa..8659c3e2ef6e 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -593,7 +593,7 @@ static struct twl4030_keypad_data cm_t35_kp_data = { .rep = 1, }; -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 4, @@ -642,7 +642,7 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio, /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters */ cm_t35_vmmc1_supply.dev = mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index ea7bfbaceddd..adc1b46fa04e 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -121,7 +121,7 @@ static struct regulator_init_data igep2_vmmc1 = { .consumer_supplies = &igep2_vmmc1_supply, }; -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 4, @@ -142,7 +142,7 @@ static int igep2_twl_gpio_setup(struct device *dev, { /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters ... we "know" the * regulators will be set up only *after* we return. diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index f2b47cb7275a..095adcb642b8 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -359,7 +359,7 @@ static int __init omap_i2c_init(void) return 0; } -static struct twl4030_hsmmc_info mmc[] __initdata = { +static struct omap2_hsmmc_info mmc[] __initdata = { { .mmc = 1, .wires = 4, @@ -396,7 +396,7 @@ static void __init omap_ldp_init(void) omap_serial_init(); usb_musb_init(); - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters */ ldp_vmmc1_supply.dev = mmc[0].dev; } diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 7812da065d2f..1bae69913376 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -108,7 +108,7 @@ static struct platform_device omap3beagle_nand_device = { #include "sdram-micron-mt46h32m32lf-6.h" -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 8, @@ -147,7 +147,7 @@ static int beagle_twl_gpio_setup(struct device *dev, } /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters */ beagle_vmmc1_supply.dev = mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 78724d859216..45227f394758 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -367,7 +367,7 @@ static struct regulator_init_data omap3evm_vsim = { .consumer_supplies = &omap3evm_vsim_supply, }; -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 4, @@ -407,7 +407,7 @@ static int omap3evm_twl_gpio_setup(struct device *dev, /* gpio + 0 is "mmc0_cd" (input/IRQ) */ omap_mux_init_gpio(63, OMAP_PIN_INPUT); mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters */ omap3evm_vmmc1_supply.dev = mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 63437037fc9f..9967b5d24b50 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -192,7 +192,7 @@ static struct twl4030_keypad_data pandora_kp_data = { .rep = 1, }; -static struct twl4030_hsmmc_info omap3pandora_mmc[] = { +static struct omap2_hsmmc_info omap3pandora_mmc[] = { { .mmc = 1, .wires = 4, @@ -231,7 +231,7 @@ static int omap3pandora_twl_gpio_setup(struct device *dev, /* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */ omap3pandora_mmc[0].gpio_cd = gpio + 0; omap3pandora_mmc[1].gpio_cd = gpio + 1; - twl4030_mmc_init(omap3pandora_mmc); + omap2_hsmmc_init(omap3pandora_mmc); /* link regulators to MMC adapters */ pandora_vmmc1_supply.dev = omap3pandora_mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index 1e3f53c605ca..8252ba49a664 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -122,7 +122,7 @@ static struct platform_device omap3touchbook_nand_device = { #include "sdram-micron-mt46h32m32lf-6.h" -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 8, @@ -161,7 +161,7 @@ static int touchbook_twl_gpio_setup(struct device *dev, } /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters */ touchbook_vmmc1_supply.dev = mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 3fc918b0c655..7e6aa8292746 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -272,7 +272,7 @@ static void __init overo_flash_init(void) } } -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, .wires = 4, @@ -297,7 +297,7 @@ static struct regulator_consumer_supply overo_vmmc1_supply = { static int overo_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio) { - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); overo_vmmc1_supply.dev = mmc[0].dev; diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index b2de2066fb00..ab07ca2d4085 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -209,7 +209,7 @@ static struct twl4030_madc_platform_data rx51_madc_data = { .irq_line = 1, }; -static struct twl4030_hsmmc_info mmc[] = { +static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "external", .mmc = 1, @@ -232,15 +232,18 @@ static struct twl4030_hsmmc_info mmc[] = { }; static struct regulator_consumer_supply rx51_vmmc1_supply = { - .supply = "vmmc", + .supply = "vmmc", + .dev_name = "mmci-omap-hs.0", }; static struct regulator_consumer_supply rx51_vmmc2_supply = { - .supply = "vmmc", + .supply = "vmmc", + .dev_name = "mmci-omap-hs.1", }; static struct regulator_consumer_supply rx51_vsim_supply = { - .supply = "vmmc_aux", + .supply = "vmmc_aux", + .dev_name = "mmci-omap-hs.1", }; static struct regulator_init_data rx51_vaux1 = { @@ -375,12 +378,6 @@ static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n) gpio_request(gpio + 7, "speaker_en"); gpio_direction_output(gpio + 7, 1); - /* set up MMC adapters, linking their regulators to them */ - twl4030_mmc_init(mmc); - rx51_vmmc1_supply.dev = mmc[0].dev; - rx51_vmmc2_supply.dev = mmc[1].dev; - rx51_vsim_supply.dev = mmc[1].dev; - return 0; } @@ -751,5 +748,6 @@ void __init rx51_peripherals_init(void) rx51_init_wl1251(); spi_register_board_info(rx51_peripherals_spi_board_info, ARRAY_SIZE(rx51_peripherals_spi_board_info)); + omap2_hsmmc_init(mmc); } diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 52940a426d9d..4278d5e14bb8 100755 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -150,7 +150,7 @@ static struct regulator_init_data zoom_vsim = { .consumer_supplies = &zoom_vsim_supply, }; -static struct twl4030_hsmmc_info mmc[] __initdata = { +static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "external", .mmc = 1, @@ -175,7 +175,7 @@ static int zoom_twl_gpio_setup(struct device *dev, { /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; - twl4030_mmc_init(mmc); + omap2_hsmmc_init(mmc); /* link regulators to MMC adapters ... we "know" the * regulators will be set up only *after* we return. diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index df1cf7273317..2ba0d55c323d 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -26,20 +26,20 @@ static u16 control_devconf1_offset; #define HSMMC_NAME_LEN 9 -static struct twl_mmc_controller { +static struct hsmmc_controller { char name[HSMMC_NAME_LEN + 1]; } hsmmc[OMAP34XX_NR_MMC]; #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) -static int twl4030_mmc_get_context_loss(struct device *dev) +static int hsmmc_get_context_loss(struct device *dev) { /* FIXME: PM DPS not implemented yet */ return 0; } #else -#define twl4030_mmc_get_context_loss NULL +#define hsmmc_get_context_loss NULL #endif static void hsmmc1_before_set_reg(struct device *dev, int slot, @@ -135,9 +135,9 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot, static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; -void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) +void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) { - struct twl4030_hsmmc_info *c; + struct omap2_hsmmc_info *c; int nr_hsmmc = ARRAY_SIZE(hsmmc_data); int i; @@ -150,7 +150,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) } for (c = controllers; c->mmc; c++) { - struct twl_mmc_controller *twl = hsmmc + c->mmc - 1; + struct hsmmc_controller *hc = hsmmc + c->mmc - 1; struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; if (!c->mmc || c->mmc > nr_hsmmc) { @@ -162,25 +162,25 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) continue; } - mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); + mmc = kzalloc(sizeof(struct omap_mmc_platform_data), + GFP_KERNEL); if (!mmc) { pr_err("Cannot allocate memory for mmc device!\n"); goto done; } if (c->name) - strncpy(twl->name, c->name, HSMMC_NAME_LEN); + strncpy(hc->name, c->name, HSMMC_NAME_LEN); else - snprintf(twl->name, ARRAY_SIZE(twl->name), + snprintf(hc->name, ARRAY_SIZE(hc->name), "mmc%islot%i", c->mmc, 1); - mmc->slots[0].name = twl->name; + mmc->slots[0].name = hc->name; mmc->nr_slots = 1; mmc->slots[0].wires = c->wires; mmc->slots[0].internal_clock = !c->ext_clock; mmc->dma_mask = 0xffffffff; - mmc->get_context_loss_count = - twl4030_mmc_get_context_loss; + mmc->get_context_loss_count = hsmmc_get_context_loss; mmc->slots[0].switch_pin = c->gpio_cd; mmc->slots[0].gpio_wp = c->gpio_wp; diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 87d67c10bdec..e946b5f79be1 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -6,7 +6,7 @@ * published by the Free Software Foundation. */ -struct twl4030_hsmmc_info { +struct omap2_hsmmc_info { u8 mmc; /* controller 1/2/3 */ u8 wires; /* 1/4/8 wires */ bool transceiver; /* MMC-2 option */ @@ -23,11 +23,11 @@ struct twl4030_hsmmc_info { #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) -void twl4030_mmc_init(struct twl4030_hsmmc_info *); +void omap2_hsmmc_init(struct omap2_hsmmc_info *); #else -static inline void twl4030_mmc_init(struct twl4030_hsmmc_info *info) +static inline void omap2_hsmmc_init(struct omap2_hsmmc_info *info) { } -- GitLab From e3df0fb4132fff8717cb0c08403c12138fd3ae39 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2117/3892] omap: Reconnect hsmmc context loss count Call the PM context-loss count function, now that there is a prototype for it. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 2ba0d55c323d..cc7e77f09268 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "hsmmc.h" @@ -34,8 +35,7 @@ static struct hsmmc_controller { static int hsmmc_get_context_loss(struct device *dev) { - /* FIXME: PM DPS not implemented yet */ - return 0; + return omap_pm_get_dev_context_loss_count(dev); } #else -- GitLab From ce6f00165d5314698afd04ee20cede156cfcc593 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2118/3892] omap: RX51: Remux to pull eMMC lines down when powering off It has been discovered that, when eMMC is powered off, current will flow from OMAP eMMC data pull-ups to the eMMC voltage supply. Configuring pads for OMAP off-mode does not help because eMMC is powered off independently of OMAP off-mode. Hence the pads are now re-configured when eMMC is powered on or off. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-rx51-peripherals.c | 43 +++++++++++++++++++- arch/arm/mach-omap2/hsmmc.c | 8 ++++ arch/arm/mach-omap2/hsmmc.h | 2 + arch/arm/plat-omap/include/plat/mmc.h | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index ab07ca2d4085..4377a4cf36eb 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -209,6 +209,46 @@ static struct twl4030_madc_platform_data rx51_madc_data = { .irq_line = 1, }; +/* Enable input logic and pull all lines up when eMMC is on. */ +static struct omap_board_mux rx51_mmc2_on_mux[] = { + OMAP3_MUX(SDMMC2_CMD, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT0, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT1, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT2, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT3, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT4, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT5, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT6, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT7, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +/* Disable input logic and pull all lines down when eMMC is off. */ +static struct omap_board_mux rx51_mmc2_off_mux[] = { + OMAP3_MUX(SDMMC2_CMD, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT0, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT1, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT2, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT3, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT4, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT5, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT6, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT7, OMAP_PULL_ENA | OMAP_MUX_MODE0), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +/* + * Current flows to eMMC when eMMC is off and the data lines are pulled up, + * so pull them down. N.B. we pull 8 lines because we are using 8 lines. + */ +static void rx51_mmc2_remux(struct device *dev, int slot, int power_on) +{ + if (power_on) + omap_mux_write_array(rx51_mmc2_on_mux); + else + omap_mux_write_array(rx51_mmc2_off_mux); +} + static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "external", @@ -222,11 +262,12 @@ static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "internal", .mmc = 2, - .wires = 8, + .wires = 8, /* See also rx51_mmc2_remux */ .gpio_cd = -EINVAL, .gpio_wp = -EINVAL, .nonremovable = true, .power_saving = true, + .remux = rx51_mmc2_remux, }, {} /* Terminator */ }; diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index cc7e77f09268..4a05c3722d54 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -48,6 +48,9 @@ static void hsmmc1_before_set_reg(struct device *dev, int slot, u32 reg, prog_io; struct omap_mmc_platform_data *mmc = dev->platform_data; + if (mmc->slots[0].remux) + mmc->slots[0].remux(dev, slot, power_on); + /* * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the * card with Vcc regulator (from twl4030 or whatever). OMAP has both @@ -121,6 +124,9 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot, { struct omap_mmc_platform_data *mmc = dev->platform_data; + if (mmc->slots[0].remux) + mmc->slots[0].remux(dev, slot, power_on); + if (power_on) { /* Only MMC2 supports a CLKIN */ if (mmc->slots[0].internal_clock) { @@ -185,6 +191,8 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) mmc->slots[0].switch_pin = c->gpio_cd; mmc->slots[0].gpio_wp = c->gpio_wp; + mmc->slots[0].remux = c->remux; + if (c->cover_only) mmc->slots[0].cover = 1; diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index e946b5f79be1..f641f592ffad 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -19,6 +19,8 @@ struct omap2_hsmmc_info { char *name; /* or NULL for default */ struct device *dev; /* returned: pointer to mmc adapter */ int ocr_mask; /* temporary HACK */ + /* Remux (pad configuation) when powering on/off */ + void (*remux)(struct device *dev, int slot, int power_on); }; #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 515701bb47d2..8b23d32895f1 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -105,6 +105,7 @@ struct omap_mmc_platform_data { int (*get_ro)(struct device *dev, int slot); int (*set_sleep)(struct device *dev, int slot, int sleep, int vdd, int cardsleep); + void (*remux)(struct device *dev, int slot, int power_on); /* Call back before enabling / disabling regulators */ void (*before_set_reg)(struct device *dev, int slot, int power_on, int vdd); -- GitLab From 1df58db8a25ec7656005f1dd161a9ede044551b7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2119/3892] omap_hsmmc: Allow for power saving without going off An eMMC may be always powered on, so that the lowest power saving state possible is sleeping. Add a field to the platform data to indicate that. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 3 +++ arch/arm/mach-omap2/hsmmc.h | 1 + arch/arm/plat-omap/include/plat/mmc.h | 3 +++ drivers/mmc/host/omap_hsmmc.c | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 4a05c3722d54..e4ab123cd4d0 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -202,6 +202,9 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) if (c->power_saving) mmc->slots[0].power_saving = 1; + if (c->no_off) + mmc->slots[0].no_off = 1; + /* NOTE: MMC slots should have a Vcc regulator set up. * This may be from a TWL4030-family chip, another * controllable regulator, or a fixed supply. diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index f641f592ffad..2453a7aeaf6f 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -14,6 +14,7 @@ struct omap2_hsmmc_info { bool cover_only; /* No card detect - just cover switch */ bool nonremovable; /* Nonremovable e.g. eMMC */ bool power_saving; /* Try to sleep or power off when possible */ + bool no_off; /* power_saving and power is not to go off */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 8b23d32895f1..b46394955f37 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -96,6 +96,9 @@ struct omap_mmc_platform_data { /* Try to sleep or power off when possible */ unsigned power_saving:1; + /* If using power_saving and the MMC power is not to go off */ + unsigned no_off:1; + int switch_pin; /* gpio (card detect) */ int gpio_wp; /* gpio (write protect) */ diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2c5e15d9f864..e15d0f42569d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1656,6 +1656,9 @@ static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); + if (mmc_slot(host).no_off) + return 0; + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && @@ -1671,6 +1674,9 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) if (!mmc_try_claim_host(host->mmc)) return 0; + if (mmc_slot(host).no_off) + return 0; + if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && -- GitLab From 4380eea266940a82e5b8edd5c16ce0289679bcfe Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2120/3892] omap_hsmmc: Fix disable timeouts Disable timeouts are in msecs not jiffies. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- drivers/mmc/host/omap_hsmmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e15d0f42569d..cb94044f3fc4 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1620,7 +1620,7 @@ static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host) if (host->power_mode == MMC_POWER_OFF) return 0; - return msecs_to_jiffies(OMAP_MMC_SLEEP_TIMEOUT); + return OMAP_MMC_SLEEP_TIMEOUT; } /* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */ @@ -1663,7 +1663,7 @@ static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && mmc_slot(host).get_cover_state(host->dev, host->slot_id))) - return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT); + return OMAP_MMC_OFF_TIMEOUT; return 0; } -- GitLab From 6da20c89af64b75302399369a90b9d50c1a87665 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2121/3892] omap_hsmmc: Ensure regulator enable / disable are paired Stop using 'regulator_is_enabled()' and just pair enables with disables so that the regulator reference counts can work correctly. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- drivers/mmc/host/omap_hsmmc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index cb94044f3fc4..d2fad587f371 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -296,11 +296,8 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on, ret = mmc_regulator_set_ocr(host->vcc, 0); } } else { - if (host->vcc_aux) { - ret = regulator_is_enabled(host->vcc_aux); - if (ret > 0) - ret = regulator_disable(host->vcc_aux); - } + if (host->vcc_aux) + ret = regulator_disable(host->vcc_aux); if (ret == 0) ret = mmc_regulator_set_ocr(host->vcc, 0); } @@ -1975,7 +1972,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) host->slot_id = 0; host->mapbase = res->start; host->base = ioremap(host->mapbase, SZ_4K); - host->power_mode = -1; + host->power_mode = MMC_POWER_OFF; platform_set_drvdata(pdev, host); INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); -- GitLab From e0eb2424469ec2333885672d3db8bd07d322455d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:34 -0800 Subject: [PATCH 2122/3892] omap_hsmmc: Allow for a shared VccQ EMMC can have two voltage supplies, Vcc and VccQ which are implemented in the code as consumer supplies vmmc and vmmc_aux. If the regulator that supplies vmmc_aux is shared with other consumers, then sending it to sleep will disrupt those consumers. However, the TWL4030-family regulators may have OFF remapped to SLEEP, in which case 'regulator_disable()' will put the regulator to sleep only when all consumers are disabled - which is the desired behaviour. This patch adds a platform data field to allow that option. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 3 +++ arch/arm/mach-omap2/hsmmc.h | 1 + arch/arm/plat-omap/include/plat/mmc.h | 3 +++ drivers/mmc/host/omap_hsmmc.c | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index e4ab123cd4d0..9ad229594b46 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -205,6 +205,9 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) if (c->no_off) mmc->slots[0].no_off = 1; + if (c->vcc_aux_disable_is_sleep) + mmc->slots[0].vcc_aux_disable_is_sleep = 1; + /* NOTE: MMC slots should have a Vcc regulator set up. * This may be from a TWL4030-family chip, another * controllable regulator, or a fixed supply. diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 2453a7aeaf6f..36f0ba8d89e2 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -15,6 +15,7 @@ struct omap2_hsmmc_info { bool nonremovable; /* Nonremovable e.g. eMMC */ bool power_saving; /* Try to sleep or power off when possible */ bool no_off; /* power_saving and power is not to go off */ + bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index b46394955f37..a1bac07c89eb 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -99,6 +99,9 @@ struct omap_mmc_platform_data { /* If using power_saving and the MMC power is not to go off */ unsigned no_off:1; + /* Regulator off remapped to sleep */ + unsigned vcc_aux_disable_is_sleep:1; + int switch_pin; /* gpio (card detect) */ int gpio_wp; /* gpio (write protect) */ diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d2fad587f371..af374771bed0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -347,7 +347,14 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep, err = regulator_set_mode(host->vcc, mode); if (err) return err; - return regulator_set_mode(host->vcc_aux, mode); + + if (!mmc_slot(host).vcc_aux_disable_is_sleep) + return regulator_set_mode(host->vcc_aux, mode); + + if (sleep) + return regulator_disable(host->vcc_aux); + else + return regulator_enable(host->vcc_aux); } static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) @@ -1982,6 +1989,13 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) else mmc->ops = &omap_hsmmc_ops; + /* + * If regulator_disable can only put vcc_aux to sleep then there is + * no off state. + */ + if (mmc_slot(host).vcc_aux_disable_is_sleep) + mmc_slot(host).no_off = 1; + mmc->f_min = 400000; mmc->f_max = 52000000; -- GitLab From b702b1060ab1c29ac08b904a0c188c61cda880eb Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2123/3892] omap_hsmmc: allow compile without regulator framework It is still possible to use the omap_hsmmc module without the regulator framework. Accordingly, ifdef out regulator-specific functions. Signed-off-by: Adrian Hunter Signed-off-by: Tony Lindgren --- drivers/mmc/host/omap_hsmmc.c | 133 ++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index af374771bed0..83f0affadcae 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -236,6 +236,8 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) #endif +#ifdef CONFIG_REGULATOR + static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on, int vdd) { @@ -357,59 +359,6 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep, return regulator_enable(host->vcc_aux); } -static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) -{ - int ret; - - if (gpio_is_valid(pdata->slots[0].switch_pin)) { - pdata->suspend = omap_hsmmc_suspend_cdirq; - pdata->resume = omap_hsmmc_resume_cdirq; - if (pdata->slots[0].cover) - pdata->slots[0].get_cover_state = - omap_hsmmc_get_cover_state; - else - pdata->slots[0].card_detect = omap_hsmmc_card_detect; - pdata->slots[0].card_detect_irq = - gpio_to_irq(pdata->slots[0].switch_pin); - ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); - if (ret) - return ret; - ret = gpio_direction_input(pdata->slots[0].switch_pin); - if (ret) - goto err_free_sp; - } else - pdata->slots[0].switch_pin = -EINVAL; - - if (gpio_is_valid(pdata->slots[0].gpio_wp)) { - pdata->slots[0].get_ro = omap_hsmmc_get_wp; - ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); - if (ret) - goto err_free_cd; - ret = gpio_direction_input(pdata->slots[0].gpio_wp); - if (ret) - goto err_free_wp; - } else - pdata->slots[0].gpio_wp = -EINVAL; - - return 0; - -err_free_wp: - gpio_free(pdata->slots[0].gpio_wp); -err_free_cd: - if (gpio_is_valid(pdata->slots[0].switch_pin)) -err_free_sp: - gpio_free(pdata->slots[0].switch_pin); - return ret; -} - -static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) -{ - if (gpio_is_valid(pdata->slots[0].gpio_wp)) - gpio_free(pdata->slots[0].gpio_wp); - if (gpio_is_valid(pdata->slots[0].switch_pin)) - gpio_free(pdata->slots[0].switch_pin); -} - static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { struct regulator *reg; @@ -488,6 +437,82 @@ static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) mmc_slot(host).set_sleep = NULL; } +static inline int omap_hsmmc_have_reg(void) +{ + return 1; +} + +#else + +static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) +{ + return -EINVAL; +} + +static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) +{ +} + +static inline int omap_hsmmc_have_reg(void) +{ + return 0; +} + +#endif + +static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) +{ + int ret; + + if (gpio_is_valid(pdata->slots[0].switch_pin)) { + pdata->suspend = omap_hsmmc_suspend_cdirq; + pdata->resume = omap_hsmmc_resume_cdirq; + if (pdata->slots[0].cover) + pdata->slots[0].get_cover_state = + omap_hsmmc_get_cover_state; + else + pdata->slots[0].card_detect = omap_hsmmc_card_detect; + pdata->slots[0].card_detect_irq = + gpio_to_irq(pdata->slots[0].switch_pin); + ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); + if (ret) + return ret; + ret = gpio_direction_input(pdata->slots[0].switch_pin); + if (ret) + goto err_free_sp; + } else + pdata->slots[0].switch_pin = -EINVAL; + + if (gpio_is_valid(pdata->slots[0].gpio_wp)) { + pdata->slots[0].get_ro = omap_hsmmc_get_wp; + ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); + if (ret) + goto err_free_cd; + ret = gpio_direction_input(pdata->slots[0].gpio_wp); + if (ret) + goto err_free_wp; + } else + pdata->slots[0].gpio_wp = -EINVAL; + + return 0; + +err_free_wp: + gpio_free(pdata->slots[0].gpio_wp); +err_free_cd: + if (gpio_is_valid(pdata->slots[0].switch_pin)) +err_free_sp: + gpio_free(pdata->slots[0].switch_pin); + return ret; +} + +static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) +{ + if (gpio_is_valid(pdata->slots[0].gpio_wp)) + gpio_free(pdata->slots[0].gpio_wp); + if (gpio_is_valid(pdata->slots[0].switch_pin)) + gpio_free(pdata->slots[0].switch_pin); +} + /* * Stop clock to the card */ @@ -2119,7 +2144,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) } } - if (!mmc_slot(host).set_power) { + if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) { ret = omap_hsmmc_reg_get(host); if (ret) goto err_reg; -- GitLab From 321cfc851dbb866e4d5efd555eca5919895324ca Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2124/3892] omap3: Clean-up for omap_mux_init Get rid of the ifdeffery in omap_mux_init by creating omap_mux_init_package and omap_mux_init_signals functions. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mux.c | 46 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 5ee2372f3b42..986077f3da15 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -985,6 +985,38 @@ static void __init omap_mux_init_list(struct omap_mux *superset) } } +#ifdef CONFIG_OMAP_MUX + +static void omap_mux_init_package(struct omap_mux *superset, + struct omap_mux *package_subset, + struct omap_ball *package_balls) +{ + if (package_subset) + omap_mux_package_fixup(package_subset, superset); + if (package_balls) + omap_mux_package_init_balls(package_balls, superset); +} + +static void omap_mux_init_signals(struct omap_board_mux *board_mux) +{ + omap_mux_set_cmdline_signals(); + omap_mux_write_array(board_mux); +} + +#else + +static void omap_mux_init_package(struct omap_mux *superset, + struct omap_mux *package_subset, + struct omap_ball *package_balls) +{ +} + +static void omap_mux_init_signals(struct omap_board_mux *board_mux) +{ +} + +#endif + int __init omap_mux_init(u32 mux_pbase, u32 mux_size, struct omap_mux *superset, struct omap_mux *package_subset, @@ -1001,19 +1033,9 @@ int __init omap_mux_init(u32 mux_pbase, u32 mux_size, return -ENODEV; } -#ifdef CONFIG_OMAP_MUX - if (package_subset) - omap_mux_package_fixup(package_subset, superset); - if (package_balls) - omap_mux_package_init_balls(package_balls, superset); -#endif - + omap_mux_init_package(superset, package_subset, package_balls); omap_mux_init_list(superset); - -#ifdef CONFIG_OMAP_MUX - omap_mux_set_cmdline_signals(); - omap_mux_write_array(board_mux); -#endif + omap_mux_init_signals(board_mux); return 0; } -- GitLab From a1e63642a9ed167f74afd10245fb907ac41a54d0 Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2125/3892] omap3: pm: Add T2 Keypad as a wakeup source Changes for setting the padconf value for sys_nirq line which is connected to T2 INTR1. This will fix the T2 keypad wakeup. Signed-off-by: Lesly A M Signed-off-by: Teerth Reddy Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-zoom-peripherals.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 4278d5e14bb8..9a0821fb7ea0 100755 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -24,6 +24,7 @@ #include #include +#include "mux.h" #include "hsmmc.h" /* Zoom2 has Qwerty keyboard*/ @@ -263,9 +264,17 @@ static int __init omap_i2c_init(void) return 0; } +static void enable_board_wakeup_source(void) +{ + /* T2 interrupt line (keypad) */ + omap_mux_init_signal("sys_nirq", + OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); +} + void __init zoom_peripherals_init(void) { omap_i2c_init(); omap_serial_init(); usb_musb_init(); + enable_board_wakeup_source(); } -- GitLab From e3d4d0a2385593e7873e7d7688eeffea949facff Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2126/3892] AM35xx: Introduce am35xx.h file Add base address definations for new AM35xx IPSS modules, like VPFE, USBOTG, CPGMAC. Please note that the OMAP34xx IVA2 memory space is being used for AM35xx IPSS modules. Signed-off-by: Vaibhav Hiremath Signed-off-by: Sriramakrishnan Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-am3517evm.c | 1 + arch/arm/mach-omap2/include/mach/am35xx.h | 26 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 arch/arm/mach-omap2/include/mach/am35xx.h diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 07b857de2500..ad323b46477d 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-omap2/include/mach/am35xx.h b/arch/arm/mach-omap2/include/mach/am35xx.h new file mode 100644 index 000000000000..a705f946fc46 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/am35xx.h @@ -0,0 +1,26 @@ +/*: + * Address mappings and base address for AM35XX specific interconnects + * and peripherals. + * + * Copyright (C) 2009 Texas Instruments + * + * Author: Sriramakrishnan + * Vaibhav Hiremath + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARCH_AM35XX_H +#define __ASM_ARCH_AM35XX_H + +/* + * Base addresses + * Note: OMAP3430 IVA2 memory space is being used for AM35xx IPSS modules + */ +#define AM35XX_IPSS_EMAC_BASE 0x5C000000 +#define AM35XX_IPSS_USBOTGSS_BASE 0x5C040000 +#define AM35XX_IPSS_HECC_BASE 0x5C050000 +#define AM35XX_IPSS_VPFE_BASE 0x5C060000 + +#endif /* __ASM_ARCH_AM35XX_H */ -- GitLab From 07dcbd07866691c33a3ff6f2d845292f23760669 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2127/3892] AM35xx: Add AM35xx intr_clr & sw_rst cntrl reg bit definition AM3517/05 has few additional control module registers to control the new IP's, like VPFE, USBOTG, CPGMAC. This patch adds the bit defination for INTR_CLR and SW_RST control register. Signed-off-by: Vaibhav Hiremath Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/control.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index fcdc71bf4c6e..207447399ad3 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -274,6 +274,23 @@ #define AM35XX_CPGMAC_FCLK_SHIFT 9 #define AM35XX_VPFE_FCLK_SHIFT 10 +/*AM35XX CONTROL_LVL_INTR_CLEAR bits*/ +#define AM35XX_CPGMAC_C0_MISC_PULSE_CLR BIT(0) +#define AM35XX_CPGMAC_C0_RX_PULSE_CLR BIT(1) +#define AM35XX_CPGMAC_C0_RX_THRESH_CLR BIT(2) +#define AM35XX_CPGMAC_C0_TX_PULSE_CLR BIT(3) +#define AM35XX_USBOTGSS_INT_CLR BIT(4) +#define AM35XX_VPFE_CCDC_VD0_INT_CLR BIT(5) +#define AM35XX_VPFE_CCDC_VD1_INT_CLR BIT(6) +#define AM35XX_VPFE_CCDC_VD2_INT_CLR BIT(7) + +/*AM35XX CONTROL_IP_SW_RESET bits*/ +#define AM35XX_USBOTGSS_SW_RST BIT(0) +#define AM35XX_CPGMACSS_SW_RST BIT(1) +#define AM35XX_VPFE_VBUSP_SW_RST BIT(2) +#define AM35XX_HECC_SW_RST BIT(3) +#define AM35XX_VPFE_PCLK_SW_RST BIT(4) + /* * CONTROL OMAP STATUS register to identify OMAP3 features */ -- GitLab From 91fbb8c6d9bb32797d455755ddd34376485bd632 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2128/3892] AM35xx: Update irq.h for AM35xx IPSS module interrupts Signed-off-by: Vaibhav Hiremath Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/irqs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index c0ab7c80f72e..90d8370bc453 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/arch/arm/plat-omap/include/plat/irqs.h @@ -344,6 +344,16 @@ #define INT_34XX_BENCH_MPU_EMUL 3 +#define INT_35XX_HECC0_IRQ 24 +#define INT_35XX_HECC1_IRQ 28 +#define INT_35XX_EMAC_C0_RXTHRESH_IRQ 67 +#define INT_35XX_EMAC_C0_RX_PULSE_IRQ 68 +#define INT_35XX_EMAC_C0_TX_PULSE_IRQ 69 +#define INT_35XX_EMAC_C0_MISC_PULSE_IRQ 70 +#define INT_35XX_USBOTG_IRQ 71 +#define INT_35XX_CCDC_VD0_IRQ 88 +#define INT_35XX_CCDC_VD1_IRQ 92 +#define INT_35XX_CCDC_VD2_IRQ 93 #define IRQ_GIC_START 32 #define INT_44XX_LOCALTIMER_IRQ 29 -- GitLab From 52abcbc9c4aa9cfd06c53afd5883296ca2a58f90 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2129/3892] arm: omap: kill compile warning on board-4430-sdp.c sdp4430_uart_config isn't used anywhere, so remove it. Signed-off-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-4430sdp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index cc4c00de32b3..793ce8f4e927 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -38,10 +38,6 @@ static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, }; -static struct omap_uart_config sdp4430_uart_config __initdata = { - .enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3), -}; - static struct omap_lcd_config sdp4430_lcd_config __initdata = { .ctrl_name = "internal", }; -- GitLab From 57852d761a924a636411eb65fa089de832a4207c Mon Sep 17 00:00:00 2001 From: Jorge Eduardo Candelaria Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2130/3892] OMAP4: IRQ: Add McPDM IRQ definition Support for McPDM IRQs in OMAP4 Signed-off-by: Jorge Eduardo Candelaria Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/irqs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index 90d8370bc453..e8205c13a27a 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/arch/arm/plat-omap/include/plat/irqs.h @@ -442,7 +442,7 @@ #define INT_44XX_PARTHASH_IRQ (79 + IRQ_GIC_START) #define INT_44XX_MMC3_IRQ (94 + IRQ_GIC_START) #define INT_44XX_MMC4_IRQ (96 + IRQ_GIC_START) - +#define INT_44XX_MCPDM_IRQ (112 + IRQ_GIC_START) /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730/850) and * 16 MPUIO lines */ -- GitLab From 302720f3b722b8084bc59b214b8da5f50dd3e0b1 Mon Sep 17 00:00:00 2001 From: Jorge Eduardo Candelaria Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2131/3892] ARM: OMAP4: Add McPDM base address Define McPDM physical and L3 base address for OMAP4 Signed-off-by: Jorge Eduardo Candelaria Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/include/plat/omap44xx.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h index ef870de43c29..2068b39f76bb 100644 --- a/arch/arm/plat-omap/include/plat/omap44xx.h +++ b/arch/arm/plat-omap/include/plat/omap44xx.h @@ -41,6 +41,8 @@ #define OMAP44XX_SCU_BASE 0x48240000 #define OMAP44XX_LOCAL_TWD_BASE 0x48240600 #define OMAP44XX_WKUPGEN_BASE 0x48281000 +#define OMAP44XX_MCPDM_BASE 0x40132000 +#define OMAP44XX_MCPDM_L3_BASE 0x49032000 #define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000) -- GitLab From d6a2d9b800276140abf352908abbd0c240890692 Mon Sep 17 00:00:00 2001 From: Jorge Eduardo Candelaria Date: Mon, 15 Feb 2010 10:03:35 -0800 Subject: [PATCH 2132/3892] OMAP4: MCPDM: Register McPDM platform device Add platform device for McPDM interface in OMAP4 and register its memory and irq resources. Signed-off-by: Jorge Eduardo Candelaria Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/devices.c | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 59f92c8bfc6d..3a3e357fff3c 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -28,6 +28,7 @@ #include #include #include +#include #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE) @@ -192,6 +193,41 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \ + defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE) + +static struct resource mcpdm_resources[] = { + { + .name = "mcpdm_mem", + .start = OMAP44XX_MCPDM_BASE, + .end = OMAP44XX_MCPDM_BASE + SZ_4K, + .flags = IORESOURCE_MEM, + }, + { + .name = "mcpdm_irq", + .start = INT_44XX_MCPDM_IRQ, + .end = INT_44XX_MCPDM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device omap_mcpdm_device = { + .name = "omap-mcpdm", + .id = -1, + .num_resources = ARRAY_SIZE(mcpdm_resources), + .resource = mcpdm_resources, +}; + +static void omap_init_mcpdm(void) +{ + (void) platform_device_register(&omap_mcpdm_device); +} +#else +static inline void omap_init_mcpdm(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) @@ -385,6 +421,7 @@ static int __init omap_init_devices(void) omap_init_dsp(); omap_init_kp(); omap_init_rng(); + omap_init_mcpdm(); omap_init_uwire(); omap_init_wdt(); return 0; -- GitLab From dd2ac961e273c2ac9f58cfa13c9e566e4bdb3b13 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Mon, 15 Feb 2010 01:16:01 +0100 Subject: [PATCH 2133/3892] ARM: 5937/1: Add support for EP9315 based Snapper CL15 board Add support for Bluewater Systems EP9315 based Snapper CL15 single board computer module. Signed-off-by: Ryan Mallon Acked-by: Hartley Sweeten Signed-off-by: Russell King --- arch/arm/mach-ep93xx/Kconfig | 7 ++ arch/arm/mach-ep93xx/Makefile | 1 + arch/arm/mach-ep93xx/snappercl15.c | 172 +++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 arch/arm/mach-ep93xx/snappercl15.c diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 5231a3a2c74b..3a08b18f6433 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -168,6 +168,13 @@ config MACH_SIM_ONE Say 'Y' here if you want your kernel to support the Simplemachines Sim.One board. +config MACH_SNAPPER_CL15 + bool "Support Bluewater Systems Snapper CL15 Module" + depends on EP93XX_SDCE0_PHYS_OFFSET + help + Say 'Y' here if you want your kernel to support the Bluewater + Systems Snapper CL15 Module. + config MACH_TS72XX bool "Support Technologic Systems TS-72xx SBC" depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index c731fa9789d1..33ee2c863d18 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -11,4 +11,5 @@ obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o obj-$(CONFIG_MACH_MICRO9) += micro9.o obj-$(CONFIG_MACH_SIM_ONE) += simone.o +obj-$(CONFIG_MACH_SNAPPER_CL15) += snappercl15.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c new file mode 100644 index 000000000000..51134b0382ca --- /dev/null +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -0,0 +1,172 @@ +/* + * arch/arm/mach-ep93xx/snappercl15.c + * Bluewater Systems Snapper CL15 system module + * + * Copyright (C) 2009 Bluewater Systems Ltd + * Author: Ryan Mallon + * + * NAND code adapted from driver by: + * Andre Renaud + * James R. McKaskill + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define SNAPPERCL15_NAND_BASE (EP93XX_CS7_PHYS_BASE + SZ_16M) + +#define SNAPPERCL15_NAND_WPN (1 << 8) /* Write protect (active low) */ +#define SNAPPERCL15_NAND_ALE (1 << 9) /* Address latch */ +#define SNAPPERCL15_NAND_CLE (1 << 10) /* Command latch */ +#define SNAPPERCL15_NAND_CEN (1 << 11) /* Chip enable (active low) */ +#define SNAPPERCL15_NAND_RDY (1 << 14) /* Device ready */ + +#define NAND_CTRL_ADDR(chip) (chip->IO_ADDR_W + 0x40) + +static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + static u16 nand_state = SNAPPERCL15_NAND_WPN; + u16 set; + + if (ctrl & NAND_CTRL_CHANGE) { + set = SNAPPERCL15_NAND_CEN | SNAPPERCL15_NAND_WPN; + + if (ctrl & NAND_NCE) + set &= ~SNAPPERCL15_NAND_CEN; + if (ctrl & NAND_CLE) + set |= SNAPPERCL15_NAND_CLE; + if (ctrl & NAND_ALE) + set |= SNAPPERCL15_NAND_ALE; + + nand_state &= ~(SNAPPERCL15_NAND_CEN | + SNAPPERCL15_NAND_CLE | + SNAPPERCL15_NAND_ALE); + nand_state |= set; + __raw_writew(nand_state, NAND_CTRL_ADDR(chip)); + } + + if (cmd != NAND_CMD_NONE) + __raw_writew((cmd & 0xff) | nand_state, chip->IO_ADDR_W); +} + +static int snappercl15_nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY); +} + +static const char *snappercl15_nand_part_probes[] = {"cmdlinepart", NULL}; + +static struct mtd_partition snappercl15_nand_parts[] = { + { + .name = "Kernel", + .offset = 0, + .size = SZ_2M, + }, + { + .name = "Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct platform_nand_data snappercl15_nand_data = { + .chip = { + .nr_chips = 1, + .part_probe_types = snappercl15_nand_part_probes, + .partitions = snappercl15_nand_parts, + .nr_partitions = ARRAY_SIZE(snappercl15_nand_parts), + .options = NAND_NO_AUTOINCR, + .chip_delay = 25, + }, + .ctrl = { + .dev_ready = snappercl15_nand_dev_ready, + .cmd_ctrl = snappercl15_nand_cmd_ctrl, + }, +}; + +static struct resource snappercl15_nand_resource[] = { + { + .start = SNAPPERCL15_NAND_BASE, + .end = SNAPPERCL15_NAND_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device snappercl15_nand_device = { + .name = "gen_nand", + .id = -1, + .dev.platform_data = &snappercl15_nand_data, + .resource = snappercl15_nand_resource, + .num_resources = ARRAY_SIZE(snappercl15_nand_resource), +}; + +static struct ep93xx_eth_data snappercl15_eth_data = { + .phy_id = 1, +}; + +static struct i2c_gpio_platform_data snappercl15_i2c_gpio_data = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .sda_is_open_drain = 0, + .scl_pin = EP93XX_GPIO_LINE_EECLK, + .scl_is_open_drain = 0, + .udelay = 0, + .timeout = 0, +}; + +static struct i2c_board_info __initdata snappercl15_i2c_data[] = { + { + /* Audio codec */ + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +static struct ep93xxfb_mach_info snappercl15_fb_info = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, +}; + +static void __init snappercl15_init_machine(void) +{ + ep93xx_init_devices(); + ep93xx_register_eth(&snappercl15_eth_data, 1); + ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data, + ARRAY_SIZE(snappercl15_i2c_data)); + ep93xx_register_fb(&snappercl15_fb_info); + platform_device_register(&snappercl15_nand_device); +} + +MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15") + /* Maintainer: Ryan Mallon */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = snappercl15_init_machine, +MACHINE_END -- GitLab From 2f5265e6e785b2a666dd985ea157bc8c260be8fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Feb 2010 10:45:05 +0100 Subject: [PATCH 2134/3892] mac80211: fix netdev rename Fix a copy bug introduced by commit 47846c9b0c10808d9337d2e7d09361f3e0a0a71a Author: Johannes Berg Date: Wed Nov 25 17:46:19 2009 +0100 mac80211: reduce reliance on netdev This manifested itself only in debug messages and in the debugfs rename failure that would always happen due to trying to rename the dir over itself. Signed-off-by: Johannes Berg Tested-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/iface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 09fff4662e80..0793d7a8d743 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1031,7 +1031,7 @@ static int netdev_notify(struct notifier_block *nb, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - memcpy(sdata->name, sdata->name, IFNAMSIZ); + memcpy(sdata->name, dev->name, IFNAMSIZ); ieee80211_debugfs_rename_netdev(sdata); return 0; -- GitLab From 0e956c132f822d414a4ce84726ac1d1294364581 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Fri, 12 Feb 2010 12:34:50 -0200 Subject: [PATCH 2135/3892] nl80211: does not allow NEW_STATION and DEL_STATION for mesh As discussed in linux-wireless mailing list, adding and removing stations for mesh topologies is not necessary. Since doing it triggers bugs, the sugestion was to simply disable it. Tested using a custom iw command "station new". Works only after using hostapd. "station del" command also works. Signed-off-by: Thadeu Lima de Souza Cascardo Cc: Johannes Berg Cc: Simon Raffeiner Cc: Andrey Yurovsky Cc: Javier Cardona Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 49 +++++++++++------------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5b79ecf17bea..a95ab9e4c19e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2010,6 +2010,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) return -EINVAL; + if (!info->attrs[NL80211_ATTR_STA_AID]) + return -EINVAL; + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); params.supported_rates = nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); @@ -2018,11 +2021,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); - if (info->attrs[NL80211_ATTR_STA_AID]) { - params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); - if (!params.aid || params.aid > IEEE80211_MAX_AID) - return -EINVAL; - } + params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (!params.aid || params.aid > IEEE80211_MAX_AID) + return -EINVAL; if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) params.ht_capa = @@ -2037,6 +2038,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + err = -EINVAL; + goto out; + } + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2044,35 +2051,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) /* validate settings */ err = 0; - switch (dev->ieee80211_ptr->iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - /* all ok but must have AID */ - if (!params.aid) - err = -EINVAL; - break; - case NL80211_IFTYPE_MESH_POINT: - /* disallow things mesh doesn't support */ - if (params.vlan) - err = -EINVAL; - if (params.aid) - err = -EINVAL; - if (params.ht_capa) - err = -EINVAL; - if (params.listen_interval >= 0) - err = -EINVAL; - if (params.supported_rates) - err = -EINVAL; - if (params.sta_flags_mask) - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - if (err) - goto out; - if (!rdev->ops->add_station) { err = -EOPNOTSUPP; goto out; @@ -2113,8 +2091,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) goto out_rtnl; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { err = -EINVAL; goto out; } -- GitLab From 2bf9fa6980a5ca12333634e48c8dd69024b88eba Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 12 Feb 2010 13:02:23 -0800 Subject: [PATCH 2136/3892] wireless: airo_cs build fixes When WEXT_PRIV is not enabled, airo_cs has build errors. It needs to include net/iw_handler.h and it should select WEXT_PRIV, like the airo driver does. drivers/net/wireless/airo.c:7655: error: unknown field 'num_private' specified in initializer drivers/net/wireless/airo.c:7655: warning: initialization makes pointer from integer without a cast drivers/net/wireless/airo.c:7656: error: unknown field 'num_private_args' specified in initializer drivers/net/wireless/airo.c:7656: warning: excess elements in struct initializer drivers/net/wireless/airo.c:7656: warning: (near initialization for 'airo_handler_def') drivers/net/wireless/airo.c:7658: error: unknown field 'private' specified in initializer drivers/net/wireless/airo.c:7658: warning: initialization makes integer from pointer without a cast drivers/net/wireless/airo.c:7658: error: initializer element is not computable at load time drivers/net/wireless/airo.c:7658: error: (near initialization for 'airo_handler_def.num_standard') drivers/net/wireless/airo.c:7659: error: unknown field 'private_args' specified in initializer drivers/net/wireless/airo.c:7659: warning: initialization from incompatible pointer type Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/airo.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 56dd6650c97a..588943660755 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -112,6 +112,7 @@ config AIRO_CS depends on PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT select WEXT_SPY + select WEXT_PRIV select CRYPTO select CRYPTO_AES ---help--- diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2a9f029a3c74..260fb9905e97 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -51,6 +51,7 @@ #include #include +#include #include "airo.h" -- GitLab From 063b2dfffc896fc5ac6943248c940619b94f09c2 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 13 Feb 2010 18:10:52 +0100 Subject: [PATCH 2137/3892] b43legacy: fix typo in ifdef comment Cc: Larry Finger Cc: Stefano Brivio Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/leds.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h index 82167a90088f..9ff6750dc57f 100644 --- a/drivers/net/wireless/b43legacy/leds.h +++ b/drivers/net/wireless/b43legacy/leds.h @@ -45,7 +45,7 @@ enum b43legacy_led_behaviour { void b43legacy_leds_init(struct b43legacy_wldev *dev); void b43legacy_leds_exit(struct b43legacy_wldev *dev); -#else /* CONFIG_B43EGACY_LEDS */ +#else /* CONFIG_B43LEGACY_LEDS */ /* LED support disabled */ struct b43legacy_led { -- GitLab From 634c8d2587abbd680603e016ae1060129abdf46f Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 13 Feb 2010 18:10:53 +0100 Subject: [PATCH 2138/3892] rtl8187: fix typo in ifdef comment Cc: Herton Ronaldo Krzesinski Cc: Larry Finger Signed-off-by: Hauke Mehrtens Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_leds.c | 2 +- drivers/net/wireless/rtl818x/rtl8187_leds.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index f82aa8b4bdde..4637337d5ce6 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -241,5 +241,5 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev) cancel_delayed_work_sync(&priv->led_off); cancel_delayed_work_sync(&priv->led_on); } -#endif /* def CONFIG_RTL8187_LED */ +#endif /* def CONFIG_RTL8187_LEDS */ diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h index efe8041bdda4..d743c96d4a20 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.h +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h @@ -54,6 +54,6 @@ struct rtl8187_led { void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code); void rtl8187_leds_exit(struct ieee80211_hw *dev); -#endif /* def CONFIG_RTL8187_LED */ +#endif /* def CONFIG_RTL8187_LEDS */ #endif /* RTL8187_LED_H */ -- GitLab From 0052b8bb5ad24ff2c5b065adc7ed44dc8390bd4b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 13 Feb 2010 18:10:54 +0100 Subject: [PATCH 2139/3892] ssb: fix typo in ifdef comment Cc: Michael Buesch Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/ssb_private.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 56054be4d113..0331139a726f 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -196,7 +196,7 @@ extern int ssb_devices_thaw(struct ssb_freeze_context *ctx); #ifdef CONFIG_SSB_B43_PCI_BRIDGE extern int __init b43_pci_ssb_bridge_init(void); extern void __exit b43_pci_ssb_bridge_exit(void); -#else /* CONFIG_SSB_B43_PCI_BRIDGR */ +#else /* CONFIG_SSB_B43_PCI_BRIDGE */ static inline int b43_pci_ssb_bridge_init(void) { return 0; @@ -204,6 +204,6 @@ static inline int b43_pci_ssb_bridge_init(void) static inline void b43_pci_ssb_bridge_exit(void) { } -#endif /* CONFIG_SSB_PCIHOST */ +#endif /* CONFIG_SSB_B43_PCI_BRIDGE */ #endif /* LINUX_SSB_PRIVATE_H_ */ -- GitLab From 15a69a81731d337a3d9db51692ff8704c1114f43 Mon Sep 17 00:00:00 2001 From: Shimada Hirofumi Date: Sun, 14 Feb 2010 04:16:16 +0900 Subject: [PATCH 2140/3892] p54usb: Add usbid for Corega CG-WLUSB2GT. Signed-off-by: Shimada Hirofumi Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 92af9b96bb7a..dcb484bd5984 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -36,6 +36,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ + {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */ -- GitLab From cea90e55969ff70b970d64d564076a5469331527 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Feb 2010 20:55:47 +0100 Subject: [PATCH 2141/3892] rt2x00: Introduce SoC interface type. Introduce the SoC interface type to detect SoC devices, instead of having them mimic being PCI devices. This allows for easier detection of SoC devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 38 ++++++++++++------------- drivers/net/wireless/rt2x00/rt2800pci.c | 18 ++++-------- drivers/net/wireless/rt2x00/rt2x00.h | 10 +++++-- drivers/net/wireless/rt2x00/rt2x00soc.c | 6 +--- 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a45e027f2d1f..e78df53b9515 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -89,7 +89,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - if (rt2x00_intf_is_pci(rt2x00dev)) + if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); @@ -118,7 +118,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - if (rt2x00_intf_is_pci(rt2x00dev)) + if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); @@ -218,9 +218,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, u32 reg; /* - * RT2880 and RT3052 don't support MCU requests. + * SOC devices don't support MCU requests. */ - if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052)) + if (rt2x00_is_soc(rt2x00dev)) return; mutex_lock(&rt2x00dev->csr_mutex); @@ -660,7 +660,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) switch ((int)ant->tx) { case 1: rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); - if (rt2x00_intf_is_pci(rt2x00dev)) + if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); break; case 2: @@ -1057,7 +1057,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats); static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - if (rt2x00_intf_is_usb(rt2x00dev) && + if (rt2x00_is_usb(rt2x00dev) && rt2x00_rev(rt2x00dev) == RT3070_VERSION) return 0x1c + (2 * rt2x00dev->lna_gain); else @@ -1109,7 +1109,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) u32 reg; unsigned int i; - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { /* * Wait until BBP and RF are ready. */ @@ -1128,7 +1128,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); - } else if (rt2x00_intf_is_pci(rt2x00dev)) + } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); @@ -1136,7 +1136,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, @@ -1174,7 +1174,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - if (rt2x00_intf_is_usb(rt2x00dev) && + if (rt2x00_is_usb(rt2x00dev) && rt2x00_rev(rt2x00dev) == RT3070_VERSION) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); @@ -1293,7 +1293,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); @@ -1353,7 +1353,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); @@ -1490,7 +1490,7 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION) rt2800_bbp_write(rt2x00dev, 84, 0x19); - if (rt2x00_intf_is_usb(rt2x00dev) && + if (rt2x00_is_usb(rt2x00dev) && rt2x00_rev(rt2x00dev) == RT3070_VERSION) { rt2800_bbp_write(rt2x00dev, 70, 0x0a); rt2800_bbp_write(rt2x00dev, 84, 0x99); @@ -1582,11 +1582,11 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 bbp; - if (rt2x00_intf_is_usb(rt2x00dev) && + if (rt2x00_is_usb(rt2x00dev) && rt2x00_rev(rt2x00dev) != RT3070_VERSION) return 0; - if (rt2x00_intf_is_pci(rt2x00dev)) { + if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) { if (!rt2x00_rf(rt2x00dev, RF3020) && !rt2x00_rf(rt2x00dev, RF3021) && !rt2x00_rf(rt2x00dev, RF3022)) @@ -1603,7 +1603,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { rt2800_rfcsr_write(rt2x00dev, 4, 0x40); rt2800_rfcsr_write(rt2x00dev, 5, 0x03); rt2800_rfcsr_write(rt2x00dev, 6, 0x02); @@ -1624,7 +1624,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 25, 0x01); rt2800_rfcsr_write(rt2x00dev, 27, 0x03); rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); - } else if (rt2x00_intf_is_pci(rt2x00dev)) { + } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) { rt2800_rfcsr_write(rt2x00dev, 0, 0x50); rt2800_rfcsr_write(rt2x00dev, 1, 0x01); rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); @@ -1855,7 +1855,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip_rf(rt2x00dev, value, reg); - if (rt2x00_intf_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev)) { /* * The check for rt2860 is not a typo, some rt2870 hardware * identifies itself as rt2860 in the CSR register. @@ -2039,7 +2039,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Disable powersaving as default on PCI devices. */ - if (rt2x00_intf_is_pci(rt2x00dev)) + if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; /* diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index daea0b7c416e..d57531ce1f82 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1041,18 +1041,12 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM into buffer */ - switch (rt2x00dev->chip.rt) { - case RT2880: - case RT3052: + if (rt2x00_is_soc(rt2x00dev)) rt2800pci_read_eeprom_soc(rt2x00dev); - break; - default: - if (rt2800pci_efuse_detect(rt2x00dev)) - rt2800pci_read_eeprom_efuse(rt2x00dev); - else - rt2800pci_read_eeprom_pci(rt2x00dev); - break; - } + else if (rt2800pci_efuse_detect(rt2x00dev)) + rt2800pci_read_eeprom_efuse(rt2x00dev); + else + rt2800pci_read_eeprom_pci(rt2x00dev); return rt2800_validate_eeprom(rt2x00dev); } @@ -1103,7 +1097,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware. */ - if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052)) + if (!rt2x00_is_soc(rt2x00dev)) __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 43b70c6e4e9c..d741367304bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -160,6 +160,7 @@ struct avg_val { enum rt2x00_chip_intf { RT2X00_CHIP_INTF_PCI, RT2X00_CHIP_INTF_USB, + RT2X00_CHIP_INTF_SOC, }; /* @@ -976,16 +977,21 @@ static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev, return (rt2x00dev->chip.intf == intf); } -static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev) +static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev) { return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); } -static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev) +static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev) { return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); } +static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) +{ + return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); +} + /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 19e684f8ffa1..0d6b43afc4e8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -94,11 +94,7 @@ int rt2x00soc_probe(struct platform_device *pdev, rt2x00dev->irq = platform_get_irq(pdev, 0); rt2x00dev->name = pdev->dev.driver->name; - /* - * SoC devices mimic PCI behavior. - */ - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); - + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); rt2x00_set_chip_rt(rt2x00dev, chipset); retval = rt2x00soc_alloc_reg(rt2x00dev); -- GitLab From 714fa6636331d33c6045efe394f36c964a6c14ee Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Feb 2010 20:55:48 +0100 Subject: [PATCH 2142/3892] rt2x00: Reorganize RT chipset setting for PCI/SOC devices. Don't set the RT chipset for a device from within the generic PCI/SOC code, but rather from the individual drivers, so that individual drivers have more control over what RT chipset is set. Preparation for chip handling updates for rt2800 devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 9 ++++-- drivers/net/wireless/rt2x00/rt2500pci.c | 9 ++++-- drivers/net/wireless/rt2x00/rt2500usb.c | 1 - drivers/net/wireless/rt2x00/rt2800lib.c | 39 ++++++++++++++++++------- drivers/net/wireless/rt2x00/rt2800pci.c | 11 ++++--- drivers/net/wireless/rt2x00/rt2x00.h | 15 ---------- drivers/net/wireless/rt2x00/rt2x00pci.c | 7 ----- drivers/net/wireless/rt2x00/rt2x00pci.h | 1 + drivers/net/wireless/rt2x00/rt2x00soc.c | 5 +--- drivers/net/wireless/rt2x00/rt2x00soc.h | 10 +------ drivers/net/wireless/rt2x00/rt61pci.c | 9 ++++-- drivers/net/wireless/rt2x00/rt73usb.c | 1 - 12 files changed, 58 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 184335950825..9207b9b100b0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1327,6 +1327,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; + u16 chip; u16 value; u16 eeprom; @@ -1335,13 +1336,17 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + /* + * Identify RT chipset. + */ + pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); + /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip_rf(rt2x00dev, value, reg); - rt2x00_print_chip(rt2x00dev); + rt2x00_set_chip(rt2x00dev, chip, value, reg); if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 7dfcffadda2a..0f6d001267ac 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1490,6 +1490,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; + u16 chip; u16 value; u16 eeprom; @@ -1498,13 +1499,17 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + /* + * Identify RT chipset. + */ + pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); + /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip_rf(rt2x00dev, value, reg); - rt2x00_print_chip(rt2x00dev); + rt2x00_set_chip(rt2x00dev, chip, value, reg); if (!rt2x00_rf(rt2x00dev, RF2522) && !rt2x00_rf(rt2x00dev, RF2523) && diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 81ca4ec068db..99b7cb88a648 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1408,7 +1408,6 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); - rt2x00_print_chip(rt2x00dev); if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) || rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e78df53b9515..7340e487df6b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -40,6 +40,9 @@ #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) #include "rt2x00usb.h" #endif +#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE) +#include "rt2x00pci.h" +#endif #include "rt2800lib.h" #include "rt2800.h" #include "rt2800usb.h" @@ -1839,6 +1842,7 @@ EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; + u16 chip; u16 value; u16 eeprom; @@ -1853,25 +1857,40 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip_rf(rt2x00dev, value, reg); - - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_is_pci(rt2x00dev)) { +#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE) + pci_read_config_word(to_pci_dev(rt2x00dev->dev), + PCI_DEVICE_ID, + &chip); +#else + BUG(); +#endif + } else if (rt2x00_is_usb(rt2x00dev)) { /* * The check for rt2860 is not a typo, some rt2870 hardware * identifies itself as rt2860 in the CSR register. */ - if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) || - rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) || - rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) { - rt2x00_set_chip_rt(rt2x00dev, RT2870); - } else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) { - rt2x00_set_chip_rt(rt2x00dev, RT3070); + if (((reg & 0xfff00000) == 0x28600000) || + ((reg & 0xfff00000) == 0x28700000) || + ((reg & 0xfff00000) == 0x28800000)) { + chip = RT2870; + } else if ((reg & 0xffff0000) == 0x30700000) { + chip = RT3070; } else { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } + } else if (rt2x00_is_soc(rt2x00dev)) { +#if defined(CONFIG_RALINK_RT288X) + chip = RT2880; +#elif defined(CONFIG_RALINK_RT305X) + chip = RT3052; +#else + BUG(); +#endif } - rt2x00_print_chip(rt2x00dev); + + rt2x00_set_chip(rt2x00dev, chip, value, reg); if (!rt2x00_rf(rt2x00dev, RF2820) && !rt2x00_rf(rt2x00dev, RF2850) && diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index d57531ce1f82..fc351052229b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1219,11 +1219,10 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); MODULE_LICENSE("GPL"); #ifdef CONFIG_RT2800PCI_SOC -#if defined(CONFIG_RALINK_RT288X) -__rt2x00soc_probe(RT2880, &rt2800pci_ops); -#elif defined(CONFIG_RALINK_RT305X) -__rt2x00soc_probe(RT3052, &rt2800pci_ops); -#endif +static int rt2800soc_probe(struct platform_device *pdev) +{ + return rt2x00soc_probe(pdev, rt2800pci_ops); +} static struct platform_driver rt2800soc_driver = { .driver = { @@ -1231,7 +1230,7 @@ static struct platform_driver rt2800soc_driver = { .owner = THIS_MODULE, .mod_name = KBUILD_MODNAME, }, - .probe = __rt2x00soc_probe, + .probe = rt2800soc_probe, .remove = __devexit_p(rt2x00soc_remove), .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d741367304bb..1fed90acd198 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -923,22 +923,7 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, rt2x00dev->chip.rt = rt; rt2x00dev->chip.rf = rf; rt2x00dev->chip.rev = rev; -} - -static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev, - const u16 rt) -{ - rt2x00dev->chip.rt = rt; -} -static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, - const u16 rf, const u32 rev) -{ - rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); -} - -static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) -{ INFO(rt2x00dev, "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 801be436cf1d..047123b766fc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -272,7 +272,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; - u16 chip; retval = pci_request_regions(pci_dev, pci_name(pci_dev)); if (retval) { @@ -315,12 +314,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); - /* - * Determine RT chipset by reading PCI header. - */ - pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); - rt2x00_set_chip_rt(rt2x00dev, chip); - retval = rt2x00pci_alloc_reg(rt2x00dev); if (retval) goto exit_free_device; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index d4f9449ab0a4..8149ff68410a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -27,6 +27,7 @@ #define RT2X00PCI_H #include +#include /* * This variable should be used with the diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 0d6b43afc4e8..4efdc96010f6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -71,9 +71,7 @@ exit: return -ENOMEM; } -int rt2x00soc_probe(struct platform_device *pdev, - const unsigned short chipset, - const struct rt2x00_ops *ops) +int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) { struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; @@ -95,7 +93,6 @@ int rt2x00soc_probe(struct platform_device *pdev, rt2x00dev->name = pdev->dev.driver->name; rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); - rt2x00_set_chip_rt(rt2x00dev, chipset); retval = rt2x00soc_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 8a3416624af5..4739edfe2f00 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -28,18 +28,10 @@ #define KSEG1ADDR(__ptr) __ptr -#define __rt2x00soc_probe(__chipset, __ops) \ -static int __rt2x00soc_probe(struct platform_device *pdev) \ -{ \ - return rt2x00soc_probe(pdev, (__chipset), (__ops)); \ -} - /* * SoC driver handlers. */ -int rt2x00soc_probe(struct platform_device *pdev, - const unsigned short chipset, - const struct rt2x00_ops *ops); +int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops); int rt2x00soc_remove(struct platform_device *pdev); #ifdef CONFIG_PM int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 881340026c2a..4ca1d48fb737 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2282,6 +2282,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; + u16 chip; u16 value; u16 eeprom; @@ -2290,13 +2291,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + /* + * Identify RT chipset. + */ + pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); + /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip_rf(rt2x00dev, value, reg); - rt2x00_print_chip(rt2x00dev); + rt2x00_set_chip(rt2x00dev, chip, value, reg); if (!rt2x00_rf(rt2x00dev, RF5225) && !rt2x00_rf(rt2x00dev, RF5325) && diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3781eb7b4aa0..2950ac754921 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1821,7 +1821,6 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); - rt2x00_print_chip(rt2x00dev); if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) || rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { -- GitLab From 49e721ec6ca74f90ee99089ad2de1c338a95c6d5 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 13 Feb 2010 20:55:49 +0100 Subject: [PATCH 2143/3892] rt2x00: rework RT chipset and revision determination for PCI an SOC devices. The recent rt2800 devices are no longer really identified by their PCI ID's, but rather by the contents of their CSR0 register. Also for the other chipsets is the contents of this CSR0 register important. Change the chipset determination logic to be more aligned with the rt2800 model. Preparation for the support of rt3070 / rt3090 based devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 9 +-- drivers/net/wireless/rt2x00/rt2400pci.h | 1 + drivers/net/wireless/rt2x00/rt2500pci.c | 9 +-- drivers/net/wireless/rt2x00/rt2500pci.h | 1 + drivers/net/wireless/rt2x00/rt2500usb.c | 3 +- drivers/net/wireless/rt2x00/rt2800.h | 14 ++-- drivers/net/wireless/rt2x00/rt2800lib.c | 92 ++++++++++++----------- drivers/net/wireless/rt2x00/rt2800usb.c | 20 +++-- drivers/net/wireless/rt2x00/rt2x00.h | 41 +++++----- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 +- drivers/net/wireless/rt2x00/rt61pci.c | 19 ++--- drivers/net/wireless/rt2x00/rt61pci.h | 9 +++ drivers/net/wireless/rt2x00/rt73usb.c | 6 +- drivers/net/wireless/rt2x00/rt73usb.h | 2 + 14 files changed, 112 insertions(+), 118 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 9207b9b100b0..676814d3a81b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1327,7 +1327,6 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 chip; u16 value; u16 eeprom; @@ -1336,17 +1335,13 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - /* - * Identify RT chipset. - */ - pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); - /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, chip, value, reg); + rt2x00_set_chip(rt2x00dev, RT2460, value, + rt2x00_get_field32(reg, CSR0_REVISION)); if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index 6c21ef66dfe0..606137738848 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -65,6 +65,7 @@ * CSR0: ASIC revision number. */ #define CSR0 0x0000 +#define CSR0_REVISION FIELD32(0x0000ffff) /* * CSR1: System control register. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0f6d001267ac..c71266142ae9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1490,7 +1490,6 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 chip; u16 value; u16 eeprom; @@ -1499,17 +1498,13 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - /* - * Identify RT chipset. - */ - pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); - /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, chip, value, reg); + rt2x00_set_chip(rt2x00dev, RT2560, value, + rt2x00_get_field32(reg, CSR0_REVISION)); if (!rt2x00_rf(rt2x00dev, RF2522) && !rt2x00_rf(rt2x00dev, RF2523) && diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index b0075674c09b..6471f8e74b35 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -76,6 +76,7 @@ * CSR0: ASIC revision number. */ #define CSR0 0x0000 +#define CSR0_REVISION FIELD32(0x0000ffff) /* * CSR1: System control register. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 99b7cb88a648..ee34c137e7cd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1409,8 +1409,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); - if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) || - rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { + if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 1a7eae357fef..74c0433dba37 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -60,11 +60,11 @@ /* * Chipset version. */ -#define RT2860C_VERSION 0x28600100 -#define RT2860D_VERSION 0x28600101 -#define RT2880E_VERSION 0x28720200 -#define RT2883_VERSION 0x28830300 -#define RT3070_VERSION 0x30700200 +#define RT2860C_VERSION 0x0100 +#define RT2860D_VERSION 0x0101 +#define RT2880E_VERSION 0x0200 +#define RT2883_VERSION 0x0300 +#define RT3070_VERSION 0x0200 /* * Signal information. @@ -408,8 +408,8 @@ * ASIC_VER: 2860 or 2870 */ #define MAC_CSR0 0x1000 -#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) -#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) +#define MAC_CSR0_REVISION FIELD32(0x0000ffff) +#define MAC_CSR0_CHIPSET FIELD32(0xffff0000) /* * MAC_SYS_CTRL: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7340e487df6b..18d4d8e4ae6b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -898,7 +898,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); rt2800_bbp_write(rt2x00dev, 3, bbp); - if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { + if (rt2x00_rt(rt2x00dev, RT2860) && + (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) { if (conf_is_ht40(conf)) { rt2800_bbp_write(rt2x00dev, 69, 0x1a); rt2800_bbp_write(rt2x00dev, 70, 0x0a); @@ -1061,7 +1062,8 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rev(rt2x00dev) == RT3070_VERSION) + rt2x00_rt(rt2x00dev, RT3070) && + (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) return 0x1c + (2 * rt2x00dev->lna_gain); else return 0x2e + rt2x00dev->lna_gain; @@ -1092,7 +1094,8 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count) { - if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) + if (rt2x00_rt(rt2x00dev, RT2860) && + (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) return; /* @@ -1178,7 +1181,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rev(rt2x00dev) == RT3070_VERSION) { + rt2x00_rt(rt2x00dev, RT3070) && + (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); @@ -1205,8 +1209,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); - if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION && - rt2x00_rev(rt2x00dev) < RT3070_VERSION) + if ((rt2x00_rt(rt2x00dev, RT2872) && + (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) || + rt2x00_rt(rt2x00dev, RT2880) || + rt2x00_rt(rt2x00dev, RT2883) || + rt2x00_rt(rt2x00dev, RT2890) || + rt2x00_rt(rt2x00dev, RT3052) || + (rt2x00_rt(rt2x00dev, RT3070) && + (rt2x00_rev(rt2x00dev) < RT3070_VERSION))) rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); else rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); @@ -1485,16 +1495,19 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 103, 0x00); rt2800_bbp_write(rt2x00dev, 105, 0x05); - if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { + if (rt2x00_rt(rt2x00dev, RT2860) && + (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) { rt2800_bbp_write(rt2x00dev, 69, 0x16); rt2800_bbp_write(rt2x00dev, 73, 0x12); } - if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION) + if (rt2x00_rt(rt2x00dev, RT2860) && + (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)) rt2800_bbp_write(rt2x00dev, 84, 0x19); if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rev(rt2x00dev) == RT3070_VERSION) { + rt2x00_rt(rt2x00dev, RT3070) && + (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) { rt2800_bbp_write(rt2x00dev, 70, 0x0a); rt2800_bbp_write(rt2x00dev, 84, 0x99); rt2800_bbp_write(rt2x00dev, 105, 0x05); @@ -1586,7 +1599,8 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 bbp; if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rev(rt2x00dev) != RT3070_VERSION) + rt2x00_rt(rt2x00dev, RT3070) && + (rt2x00_rev(rt2x00dev) != RT3070_VERSION)) return 0; if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) { @@ -1757,7 +1771,12 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); - } else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) { + } else if (rt2x00_rt(rt2x00dev, RT2860) || + rt2x00_rt(rt2x00dev, RT2870) || + rt2x00_rt(rt2x00dev, RT2872) || + rt2x00_rt(rt2x00dev, RT2880) || + (rt2x00_rt(rt2x00dev, RT2883) && + (rt2x00_rev(rt2x00dev) < RT2883_VERSION))) { /* * There is a max of 2 RX streams for RT28x0 series */ @@ -1842,7 +1861,6 @@ EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 chip; u16 value; u16 eeprom; @@ -1857,41 +1875,25 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (rt2x00_is_pci(rt2x00dev)) { -#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE) - pci_read_config_word(to_pci_dev(rt2x00dev->dev), - PCI_DEVICE_ID, - &chip); -#else - BUG(); -#endif - } else if (rt2x00_is_usb(rt2x00dev)) { - /* - * The check for rt2860 is not a typo, some rt2870 hardware - * identifies itself as rt2860 in the CSR register. - */ - if (((reg & 0xfff00000) == 0x28600000) || - ((reg & 0xfff00000) == 0x28700000) || - ((reg & 0xfff00000) == 0x28800000)) { - chip = RT2870; - } else if ((reg & 0xffff0000) == 0x30700000) { - chip = RT3070; - } else { - ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); - return -ENODEV; - } - } else if (rt2x00_is_soc(rt2x00dev)) { -#if defined(CONFIG_RALINK_RT288X) - chip = RT2880; -#elif defined(CONFIG_RALINK_RT305X) - chip = RT3052; -#else - BUG(); -#endif + rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), + value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); + + if (!rt2x00_rt(rt2x00dev, RT2860) && + !rt2x00_rt(rt2x00dev, RT2870) && + !rt2x00_rt(rt2x00dev, RT2872) && + !rt2x00_rt(rt2x00dev, RT2880) && + !rt2x00_rt(rt2x00dev, RT2883) && + !rt2x00_rt(rt2x00dev, RT2890) && + !rt2x00_rt(rt2x00dev, RT3052) && + !rt2x00_rt(rt2x00dev, RT3070) && + !rt2x00_rt(rt2x00dev, RT3071) && + !rt2x00_rt(rt2x00dev, RT3090) && + !rt2x00_rt(rt2x00dev, RT3390) && + !rt2x00_rt(rt2x00dev, RT3572)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; } - rt2x00_set_chip(rt2x00dev, chip, value, reg); - if (!rt2x00_rf(rt2x00dev, RF2820) && !rt2x00_rf(rt2x00dev, RF2850) && !rt2x00_rf(rt2x00dev, RF2720) && diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 82755cf8b73e..79ea3798d597 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -92,7 +92,6 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len) static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len) { - u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; size_t offset = 0; /* @@ -111,9 +110,9 @@ static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, * Check if we need the upper 4kb firmware data or not. */ if ((len == 4096) && - (chipset != 0x2860) && - (chipset != 0x2872) && - (chipset != 0x3070)) + !rt2x00_rt(rt2x00dev, RT2860) && + !rt2x00_rt(rt2x00dev, RT2872) && + !rt2x00_rt(rt2x00dev, RT3070)) return FW_BAD_VERSION; /* @@ -138,14 +137,13 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, u32 reg; u32 offset; u32 length; - u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; /* * Check which section of the firmware we need. */ - if ((chipset == 0x2860) || - (chipset == 0x2872) || - (chipset == 0x3070)) { + if (rt2x00_rt(rt2x00dev, RT2860) || + rt2x00_rt(rt2x00dev, RT2872) || + rt2x00_rt(rt2x00dev, RT3070)) { offset = 0; length = 4096; } else { @@ -200,9 +198,9 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, */ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); - if ((chipset == 0x3070) || - (chipset == 0x3071) || - (chipset == 0x3572)) { + if (rt2x00_rt(rt2x00dev, RT3070) || + rt2x00_rt(rt2x00dev, RT3071) || + rt2x00_rt(rt2x00dev, RT3572)) { udelay(200); rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); udelay(10); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1fed90acd198..d9daa9c406fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -170,25 +170,26 @@ enum rt2x00_chip_intf { */ struct rt2x00_chip { u16 rt; -#define RT2460 0x0101 -#define RT2560 0x0201 -#define RT2570 0x1201 -#define RT2561s 0x0301 /* Turbo */ -#define RT2561 0x0302 -#define RT2661 0x0401 -#define RT2571 0x1300 -#define RT2860 0x0601 /* 2.4GHz PCI/CB */ -#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */ -#define RT2890 0x0701 /* 2.4GHz PCIe */ -#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */ +#define RT2460 0x2460 +#define RT2560 0x2560 +#define RT2570 0x2570 +#define RT2661 0x2661 +#define RT2573 0x2573 +#define RT2860 0x2860 /* 2.4GHz PCI/CB */ +#define RT2870 0x2870 +#define RT2872 0x2872 #define RT2880 0x2880 /* WSOC */ +#define RT2883 0x2883 /* WSOC */ +#define RT2890 0x2890 /* 2.4GHz PCIe */ #define RT3052 0x3052 /* WSOC */ +#define RT3070 0x3070 +#define RT3071 0x3071 #define RT3090 0x3090 /* 2.4GHz PCIe */ -#define RT2870 0x1600 -#define RT3070 0x1800 +#define RT3390 0x3390 +#define RT3572 0x3572 u16 rf; - u32 rev; + u16 rev; enum rt2x00_chip_intf intf; }; @@ -918,14 +919,14 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, * Chipset handlers */ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, - const u16 rt, const u16 rf, const u32 rev) + const u16 rt, const u16 rf, const u16 rev) { rt2x00dev->chip.rt = rt; rt2x00dev->chip.rf = rf; rt2x00dev->chip.rev = rev; INFO(rt2x00dev, - "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", + "Chipset detected - rt: %04x, rf: %04x, rev: %04x.\n", rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); } @@ -939,17 +940,11 @@ static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf) return (rt2x00dev->chip.rf == rf); } -static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev) +static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev) { return rt2x00dev->chip.rev; } -static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev, - const u32 mask, const u32 rev) -{ - return ((rt2x00dev->chip.rev & mask) == rev); -} - static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, enum rt2x00_chip_intf intf) { diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 7d323a763b54..70c04c282efc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -184,7 +184,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->data_length = cpu_to_le32(skb->len); dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); - dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); + dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev); dump_hdr->type = cpu_to_le16(type); dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; @@ -573,7 +573,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, blob->data = data; data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt); data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf); - data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev); + data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev); data += sprintf(data, "\n"); data += sprintf(data, "register\tbase\twords\twordsize\n"); data += sprintf(data, "csr\t%d\t%d\t%d\n", diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 4ca1d48fb737..ee9c696fe1d4 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1131,16 +1131,18 @@ dynamic_cca_tune: */ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) { + u16 chip; char *fw_name; - switch (rt2x00dev->chip.rt) { - case RT2561: + pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); + switch (chip) { + case RT2561_PCI_ID: fw_name = FIRMWARE_RT2561; break; - case RT2561s: + case RT2561s_PCI_ID: fw_name = FIRMWARE_RT2561s; break; - case RT2661: + case RT2661_PCI_ID: fw_name = FIRMWARE_RT2661; break; default: @@ -2282,7 +2284,6 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 chip; u16 value; u16 eeprom; @@ -2291,17 +2292,13 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - /* - * Identify RT chipset. - */ - pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); - /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, chip, value, reg); + rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), + value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); if (!rt2x00_rf(rt2x00dev, RF5225) && !rt2x00_rf(rt2x00dev, RF5325) && diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 6f33f7f5668c..ab20c7758824 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -27,6 +27,13 @@ #ifndef RT61PCI_H #define RT61PCI_H +/* + * RT chip PCI IDs. + */ +#define RT2561s_PCI_ID 0x0301 +#define RT2561_PCI_ID 0x0302 +#define RT2661_PCI_ID 0x0401 + /* * RF chip defines. */ @@ -225,6 +232,8 @@ struct hw_pairwise_ta_entry { * MAC_CSR0: ASIC revision number. */ #define MAC_CSR0 0x3000 +#define MAC_CSR0_REVISION FIELD32(0x0000000f) +#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0) /* * MAC_CSR1: System control register. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 2950ac754921..f39a8ed17841 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1820,10 +1820,10 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2571, value, reg); + rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), + value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); - if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) || - rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { + if (!rt2x00_rt(rt2x00dev, RT2573) || (rt2x00_rev(rt2x00dev) == 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index e783a099a8f1..b4e3ddda06cf 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -142,6 +142,8 @@ struct hw_pairwise_ta_entry { * MAC_CSR0: ASIC revision number. */ #define MAC_CSR0 0x3000 +#define MAC_CSR0_REVISION FIELD32(0x0000000f) +#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0) /* * MAC_CSR1: System control register. -- GitLab From de1ebdceb6a4fe1b7073b81d273285b7c8bed312 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 14 Feb 2010 12:52:05 +0100 Subject: [PATCH 2144/3892] rt2x00: rt2800 - Make rt30xx and rt35xx chipsets configurable. Support for rt30xx- and rt35xx-based devices is currently not functional in rt2800pci and rt2800usb. In order to not confuse users we shouldn't claim the PCI and USB device ID's for these devices. However, to allow for testing it is good to still have them available, although disabled by default. Make support for these device configuration options that default to off. For rt2800usb a 3rd class of devices is added, which are the unknown devices. For these devices it is known that they are either based on rt28xx, rt30xx or rt35xx, but it is not known on what chipset exactly. These devices are disabled by default as well, until it can be established on what chipset exactly they are based. Signed-off-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 67 +++++- drivers/net/wireless/rt2x00/rt2800pci.c | 20 +- drivers/net/wireless/rt2x00/rt2800usb.c | 286 +++++++++++++++--------- 3 files changed, 258 insertions(+), 115 deletions(-) diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 3ca824a91ad9..5239e082cd0f 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -64,7 +64,7 @@ config RT2800PCI_SOC default y config RT2800PCI - tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)" + tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)" depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL select RT2800_LIB select RT2X00_LIB_PCI if RT2800PCI_PCI @@ -75,7 +75,7 @@ config RT2800PCI select CRC_CCITT select EEPROM_93CX6 ---help--- - This adds support for rt2800 wireless chipset family. + This adds support for rt2800/rt3000/rt3500 wireless chipset family. Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 This driver is non-functional at the moment and is intended for @@ -83,6 +83,32 @@ config RT2800PCI When compiled as a module, this driver will be called "rt2800pci.ko". +if RT2800PCI + +config RT2800PCI_RT30XX + bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices" + default n + ---help--- + This adds support for rt30xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT3090, RT3091 & RT3092 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + +config RT2800PCI_RT35XX + bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices" + default n + ---help--- + This adds support for rt35xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT3060, RT3062, RT3562, RT3592 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + +endif + config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB @@ -126,6 +152,43 @@ config RT2800USB When compiled as a module, this driver will be called "rt2800usb.ko". +if RT2800USB + +config RT2800USB_RT30XX + bool "rt2800usb - Include support for rt30xx (USB) devices" + default n + ---help--- + This adds support for rt30xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT3070, RT3071 & RT3072 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + +config RT2800USB_RT35XX + bool "rt2800usb - Include support for rt35xx (USB) devices" + default n + ---help--- + This adds support for rt35xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT3572 + + Support for these devices is non-functional at the moment and is + intended for testers and developers. + +config RT2800USB_UNKNOWN + bool "rt2800usb - Include support for unknown (USB) devices" + default n + ---help--- + This adds support for rt2800 family devices that are known to + have a rt2800 family chipset, but for which the exact chipset + is unknown. + + Support status for these devices is unknown, and enabling these + devices may or may not work. + +endif + config RT2800_LIB tristate diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index fc351052229b..0e4c41766edc 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1185,7 +1185,10 @@ static const struct rt2x00_ops rt2800pci_ops = { * RT2800pci module information. */ static struct pci_device_id rt2800pci_device_table[] = { - { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, @@ -1193,18 +1196,19 @@ static struct pci_device_id rt2800pci_device_table[] = { { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, +#ifdef CONFIG_RT2800PCI_RT30XX { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, +#endif +#ifdef CONFIG_RT2800PCI_RT35XX + { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, +#endif { 0, } }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 79ea3798d597..5e4ee2023fcf 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -805,51 +805,27 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AirTies */ - { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Amigo */ - { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amit */ { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Askey */ { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* ASUS */ { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Belkin */ { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Cisco */ - { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -858,157 +834,257 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, /* D-Link */ { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ + { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Motorola */ + { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* MSI */ + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ + { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sweex */ + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* U-Media*/ + { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ZCOM */ + { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zyxel */ + { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, +#ifdef CONFIG_RT2800USB_RT30XX + /* Abocom */ + { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AirTies */ + { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AzureWave */ + { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Corega */ + { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* D-Link */ { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ - { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* MSI */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Pegatron */ + { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Quanta */ + { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* SMC */ + { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, +#endif +#ifdef CONFIG_RT2800USB_RT35XX + /* Askey */ + { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Cisco */ + { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ + { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, +#endif +#ifdef CONFIG_RT2800USB_UNKNOWN + /* + * Unclear what kind of devices these are (they aren't supported by the + * vendor driver). + */ + /* Allwin */ + { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amigo */ + { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Askey */ + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AzureWave */ + { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Buffalo */ + { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Corega */ + { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Encore */ + { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Hawking */ - { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Linksys */ - { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Logitec */ - { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Motorola */ - { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ovislink */ { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Para */ { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Pegatron */ + { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Philips */ - { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ - { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Quanta */ - { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Ralink */ - { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Samsung */ - { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Siemens */ - { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ - { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sparklan */ - { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sweex */ { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* U-Media*/ - { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* ZCOM */ - { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ - { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, +#endif { 0, } }; -- GitLab From 8404080568613d93ad7cf0a16dfb68459b42a264 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 15 Feb 2010 12:46:39 +0200 Subject: [PATCH 2145/3892] mac80211: reject unhandled action frames 802.11-2007 7.3.1.11 mandates that we need to reject action frames we don't handle by setting the 0x80 bit in the category and returning them to the sender, so do that. In AP mode, hostapd is responsible for this. Additionally, drop completely malformed action frames or ones that should've been encrypted as unusable, userspace shouldn't see those. Signed-off-by: Johannes Berg Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/rx.c | 90 ++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c9755f3d986c..a177472adc13 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007 Johannes Berg + * Copyright 2007-2010 Johannes Berg * * 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 @@ -1855,23 +1855,28 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; + struct sk_buff *nskb; int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) return RX_CONTINUE; if (!rx->sta) - return RX_DROP_MONITOR; + return RX_DROP_UNUSABLE; if (!(rx->flags & IEEE80211_RX_RA_MATCH)) - return RX_DROP_MONITOR; + return RX_DROP_UNUSABLE; if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) - return RX_DROP_MONITOR; + return RX_DROP_UNUSABLE; - /* all categories we currently handle have action_code */ + /* drop too small frames */ + if (len < IEEE80211_MIN_ACTION_SIZE) + return RX_DROP_UNUSABLE; + + /* return action frames that have *only* category */ if (len < IEEE80211_MIN_ACTION_SIZE + 1) - return RX_DROP_MONITOR; + goto return_frame; switch (mgmt->u.action.category) { case WLAN_CATEGORY_BACK: @@ -1884,7 +1889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_AP) - return RX_DROP_MONITOR; + break; switch (mgmt->u.action.u.addba_req.action_code) { case WLAN_ACTION_ADDBA_REQ: @@ -1892,45 +1897,45 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sizeof(mgmt->u.action.u.addba_req))) return RX_DROP_MONITOR; ieee80211_process_addba_request(local, rx->sta, mgmt, len); - break; + goto handled; case WLAN_ACTION_ADDBA_RESP: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.addba_resp))) - return RX_DROP_MONITOR; + break; ieee80211_process_addba_resp(local, rx->sta, mgmt, len); - break; + goto handled; case WLAN_ACTION_DELBA: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.delba))) - return RX_DROP_MONITOR; + break; ieee80211_process_delba(sdata, rx->sta, mgmt, len); - break; + goto handled; } break; case WLAN_CATEGORY_SPECTRUM_MGMT: if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) - return RX_DROP_MONITOR; + break; if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP_MONITOR; + break; switch (mgmt->u.action.u.measurement.action_code) { case WLAN_ACTION_SPCT_MSR_REQ: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.measurement))) - return RX_DROP_MONITOR; + break; ieee80211_process_measurement_req(sdata, mgmt, len); - break; + goto handled; case WLAN_ACTION_SPCT_CHL_SWITCH: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.chan_switch))) - return RX_DROP_MONITOR; + break; if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP_MONITOR; + break; if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) - return RX_DROP_MONITOR; + break; return ieee80211_sta_rx_mgmt(sdata, rx->skb); } @@ -1938,29 +1943,48 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) case WLAN_CATEGORY_SA_QUERY: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.sa_query))) - return RX_DROP_MONITOR; + break; + switch (mgmt->u.action.u.sa_query.action) { case WLAN_ACTION_SA_QUERY_REQUEST: if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP_MONITOR; + break; ieee80211_process_sa_query_req(sdata, mgmt, len); - break; - case WLAN_ACTION_SA_QUERY_RESPONSE: - /* - * SA Query response is currently only used in AP mode - * and it is processed in user space. - */ - return RX_CONTINUE; + goto handled; } break; - default: - /* do not process rejected action frames */ - if (mgmt->u.action.category & 0x80) - return RX_DROP_MONITOR; + } + return_frame: + /* + * For AP mode, hostapd is responsible for handling any action + * frames that we didn't handle, including returning unknown + * ones. For all other modes we will return them to the sender, + * setting the 0x80 bit in the action category, as required by + * 802.11-2007 7.3.1.11. + */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return RX_DROP_MONITOR; - return RX_CONTINUE; + /* do not return rejected action frames */ + if (mgmt->u.action.category & 0x80) + return RX_DROP_UNUSABLE; + + nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, + GFP_ATOMIC); + if (nskb) { + struct ieee80211_mgmt *mgmt = (void *)nskb->data; + + mgmt->u.action.category |= 0x80; + memcpy(mgmt->da, mgmt->sa, ETH_ALEN); + memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN); + + memset(nskb->cb, 0, sizeof(nskb->cb)); + + ieee80211_tx_skb(rx->sdata, nskb); } + handled: rx->sta->rx_packets++; dev_kfree_skb(rx->skb); return RX_QUEUED; -- GitLab From 026331c4d9b526561ea96f95fac4bfc52b69e316 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 15 Feb 2010 12:53:10 +0200 Subject: [PATCH 2146/3892] cfg80211/mac80211: allow registering for and sending action frames This implements a new command to register for action frames that userspace wants to handle instead of the in-kernel rejection. It is then responsible for rejecting ones that it decided not to handle. There is no unregistration, but the socket can be closed for that. Frames that are not registered for will not be forwarded to userspace and will be rejected by the kernel, the cfg80211 API helps implementing that. Additionally, this patch adds a new command that allows doing action frame transmission from userspace. It can be used either to exchange action frames on the current operational channel (e.g., with the AP with which we are currently associated) or to exchange off-channel Public Action frames with the remain-on-channel command. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 41 +++++- include/net/cfg80211.h | 47 ++++++- include/net/mac80211.h | 6 +- net/mac80211/cfg.c | 12 +- net/mac80211/ieee80211_i.h | 6 +- net/mac80211/mlme.c | 35 +++++ net/mac80211/rx.c | 42 ++++-- net/mac80211/status.c | 7 +- net/wireless/core.c | 4 + net/wireless/core.h | 9 ++ net/wireless/mlme.c | 166 +++++++++++++++++++++++ net/wireless/nl80211.c | 260 ++++++++++++++++++++++++++++++++++++- net/wireless/nl80211.h | 8 ++ 13 files changed, 625 insertions(+), 18 deletions(-) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 127a73015760..8e6384f8fda6 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -3,7 +3,7 @@ /* * 802.11 netlink interface public header * - * Copyright 2006, 2007, 2008 Johannes Berg + * Copyright 2006-2010 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch @@ -299,6 +299,31 @@ * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface * and @NL80211_ATTR_TX_RATES the set of allowed rates. * + * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames + * (via @NL80211_CMD_ACTION) for processing in userspace. This command + * requires an interface index and a match attribute containing the first + * few bytes of the frame that should match, e.g. a single byte for only + * a category match or four bytes for vendor frames including the OUI. + * The registration cannot be dropped, but is removed automatically + * when the netlink socket is closed. Multiple registrations can be made. + * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This + * command is used both as a request to transmit an Action frame and as an + * event indicating reception of an Action frame that was not processed in + * kernel code, but is for us (i.e., which may need to be processed in a + * user space application). %NL80211_ATTR_FRAME is used to specify the + * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and + * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on + * which channel the frame is to be transmitted or was received. This + * channel has to be the current channel (remain-on-channel or the + * operational channel). When called, this operation returns a cookie + * (%NL80211_ATTR_COOKIE) that will be included with the TX status event + * pertaining to the TX request. + * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame + * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies + * the TX command and %NL80211_ATTR_FRAME includes the contents of the + * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged + * the frame. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -387,6 +412,10 @@ enum nl80211_commands { NL80211_CMD_SET_TX_BITRATE_MASK, + NL80211_CMD_REGISTER_ACTION, + NL80211_CMD_ACTION, + NL80211_CMD_ACTION_TX_STATUS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -653,6 +682,12 @@ enum nl80211_commands { * rates based on negotiated supported rates information. This attribute * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. * + * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain + * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION. + * + * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was + * acknowledged by the recipient. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -798,6 +833,10 @@ enum nl80211_attrs { NL80211_ATTR_TX_RATES, + NL80211_ATTR_FRAME_MATCH, + + NL80211_ATTR_ACK, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5b3569b2a74c..7188934b64d3 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3,7 +3,7 @@ /* * 802.11 device and configuration interface * - * Copyright 2006-2009 Johannes Berg + * Copyright 2006-2010 Johannes Berg * * 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 @@ -998,6 +998,7 @@ struct cfg80211_pmksa { * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. * This allows the operation to be terminated prior to timeout based on * the duration value. + * @action: Transmit an action frame * * @testmode_cmd: run a test mode command * @@ -1144,6 +1145,11 @@ struct cfg80211_ops { struct net_device *dev, u64 cookie); + int (*action)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); @@ -1445,6 +1451,8 @@ struct cfg80211_cached_keys; * set by driver (if supported) on add_interface BEFORE registering the * netdev and may otherwise be used by driver read-only, will be update * by cfg80211 on change_interface + * @action_registrations: list of registrations for action frames + * @action_registrations_lock: lock for the list */ struct wireless_dev { struct wiphy *wiphy; @@ -1454,6 +1462,9 @@ struct wireless_dev { struct list_head list; struct net_device *netdev; + struct list_head action_registrations; + spinlock_t action_registrations_lock; + struct mutex mtx; struct work_struct cleanup_work; @@ -2291,4 +2302,38 @@ void cfg80211_remain_on_channel_expired(struct net_device *dev, void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); +/** + * cfg80211_rx_action - notification of received, unprocessed Action frame + * @dev: network device + * @freq: Frequency on which the frame was received in MHz + * @buf: Action frame (header + body) + * @len: length of the frame data + * @gfp: context flags + * Returns %true if a user space application is responsible for rejecting the + * unrecognized Action frame; %false if no such application is registered + * (i.e., the driver is responsible for rejecting the unrecognized Action + * frame) + * + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + */ +bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, + size_t len, gfp_t gfp); + +/** + * cfg80211_action_tx_status - notification of TX status for Action frame + * @dev: network device + * @cookie: Cookie returned by cfg80211_ops::action() + * @buf: Action frame (header + body) + * @len: length of the frame data + * @ack: Whether frame was acknowledged + * @gfp: context flags + * + * This function is called whenever an Action frame was requested to be + * transmitted with cfg80211_ops::action() to report the TX status of the + * transmission attempt. + */ +void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp); + #endif /* __NET_CFG80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 314e98173166..80eb7cc42ce9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3,7 +3,7 @@ * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007-2008 Johannes Berg + * Copyright 2007-2010 Johannes Berg * * 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 @@ -264,6 +264,9 @@ struct ieee80211_bss_conf { * be modified again (no seqno assignment, crypto, etc.) * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still * has a radiotap header at skb->data. + * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 + * MLME command (internal to mac80211 to figure out whether to send TX + * status to user space) */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -286,6 +289,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), + IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e1731b7c2523..b7116ef84a3b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1,7 +1,7 @@ /* * mac80211 configuration hooks for cfg80211 * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006-2010 Johannes Berg * * This file is GPLv2 as found in COPYING. */ @@ -1448,6 +1448,15 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); } +static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie) +{ + return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, + channel_type, buf, len, cookie); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1496,4 +1505,5 @@ struct cfg80211_ops mac80211_config_ops = { .set_bitrate_mask = ieee80211_set_bitrate_mask, .remain_on_channel = ieee80211_remain_on_channel, .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, + .action = ieee80211_action, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9dd98b674cbc..241533e1bc03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007-2008 Johannes Berg + * Copyright 2007-2010 Johannes Berg * * 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 @@ -966,6 +966,10 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_disassoc_request *req, void *cookie); +int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_send_pspoll(struct ieee80211_local *local, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bfc4a5070013..41812a15eea0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2084,3 +2084,38 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return 0; } + +int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sk_buff *skb; + + /* Check that we are on the requested channel for transmission */ + if ((chan != local->tmp_channel || + channel_type != local->tmp_channel_type) && + (chan != local->oper_channel || + channel_type != local->oper_channel_type)) + return -EBUSY; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); + if (!skb) + return -ENOMEM; + skb_reserve(skb, local->hw.extra_tx_headroom); + + memcpy(skb_put(skb, len), buf, len); + + if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) + IEEE80211_SKB_CB(skb)->flags |= + IEEE80211_TX_INTFL_DONT_ENCRYPT; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX | + IEEE80211_TX_CTL_REQ_TX_STATUS; + skb->dev = sdata->dev; + ieee80211_tx_skb(sdata, skb); + + *cookie = (unsigned long) skb; + return 0; +} diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a177472adc13..a6080d8d72bb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1856,28 +1856,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; struct sk_buff *nskb; + struct ieee80211_rx_status *status; int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) return RX_CONTINUE; - if (!rx->sta) + /* drop too small frames */ + if (len < IEEE80211_MIN_ACTION_SIZE) return RX_DROP_UNUSABLE; - if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) return RX_DROP_UNUSABLE; - if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_UNUSABLE; - /* drop too small frames */ - if (len < IEEE80211_MIN_ACTION_SIZE) + if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) return RX_DROP_UNUSABLE; - /* return action frames that have *only* category */ - if (len < IEEE80211_MIN_ACTION_SIZE + 1) - goto return_frame; - switch (mgmt->u.action.category) { case WLAN_CATEGORY_BACK: /* @@ -1891,6 +1888,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sdata->vif.type != NL80211_IFTYPE_AP) break; + /* verify action_code is present */ + if (len < IEEE80211_MIN_ACTION_SIZE + 1) + break; + switch (mgmt->u.action.u.addba_req.action_code) { case WLAN_ACTION_ADDBA_REQ: if (len < (IEEE80211_MIN_ACTION_SIZE + @@ -1919,6 +1920,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (sdata->vif.type != NL80211_IFTYPE_STATION) break; + /* verify action_code is present */ + if (len < IEEE80211_MIN_ACTION_SIZE + 1) + break; + switch (mgmt->u.action.u.measurement.action_code) { case WLAN_ACTION_SPCT_MSR_REQ: if (len < (IEEE80211_MIN_ACTION_SIZE + @@ -1954,7 +1959,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) } break; } - return_frame: + /* * For AP mode, hostapd is responsible for handling any action * frames that we didn't handle, including returning unknown @@ -1966,6 +1971,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sdata->vif.type == NL80211_IFTYPE_AP_VLAN) return RX_DROP_MONITOR; + /* + * Getting here means the kernel doesn't know how to handle + * it, but maybe userspace does ... include returned frames + * so userspace can register for those to know whether ones + * it transmitted were processed or returned. + */ + status = IEEE80211_SKB_RXCB(rx->skb); + + if (sdata->vif.type == NL80211_IFTYPE_STATION && + cfg80211_rx_action(rx->sdata->dev, status->freq, + rx->skb->data, rx->skb->len, + GFP_ATOMIC)) + goto handled; + /* do not return rejected action frames */ if (mgmt->u.action.category & 0x80) return RX_DROP_UNUSABLE; @@ -1985,7 +2004,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) } handled: - rx->sta->rx_packets++; + if (rx->sta) + rx->sta->rx_packets++; dev_kfree_skb(rx->skb); return RX_QUEUED; } diff --git a/net/mac80211/status.c b/net/mac80211/status.c index ded98730c111..56d5b9a6ec5b 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2008-2009 Johannes Berg + * Copyright 2008-2010 Johannes Berg * * 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 @@ -288,6 +288,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) msecs_to_jiffies(10)); } + if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) + cfg80211_action_tx_status( + skb->dev, (unsigned long) skb, skb->data, skb->len, + !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); + /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); diff --git a/net/wireless/core.c b/net/wireless/core.c index 71b6b3a9cf1f..51908dc2ea00 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -677,6 +677,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); + INIT_LIST_HEAD(&wdev->action_registrations); + spin_lock_init(&wdev->action_registrations_lock); + mutex_lock(&rdev->devlist_mtx); list_add_rcu(&wdev->list, &rdev->netdev_list); rdev->devlist_generation++; @@ -792,6 +795,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_rcu(&wdev->list); rdev->devlist_generation++; + cfg80211_mlme_purge_actions(wdev); #ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.keys); #endif diff --git a/net/wireless/core.h b/net/wireless/core.h index c326a667022a..d52da913145a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -329,6 +329,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *resp_ie, size_t resp_ie_len, u16 status, bool wextev, struct cfg80211_bss *bss); +int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, + const u8 *match_data, int match_len); +void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); +void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); +int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie); /* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 94d151f6f73e..62bc8855e123 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -728,3 +728,169 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); } EXPORT_SYMBOL(cfg80211_new_sta); + +struct cfg80211_action_registration { + struct list_head list; + + u32 nlpid; + + int match_len; + + u8 match[]; +}; + +int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, + const u8 *match_data, int match_len) +{ + struct cfg80211_action_registration *reg, *nreg; + int err = 0; + + nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); + if (!nreg) + return -ENOMEM; + + spin_lock_bh(&wdev->action_registrations_lock); + + list_for_each_entry(reg, &wdev->action_registrations, list) { + int mlen = min(match_len, reg->match_len); + + if (memcmp(reg->match, match_data, mlen) == 0) { + err = -EALREADY; + break; + } + } + + if (err) { + kfree(nreg); + goto out; + } + + memcpy(nreg->match, match_data, match_len); + nreg->match_len = match_len; + nreg->nlpid = snd_pid; + list_add(&nreg->list, &wdev->action_registrations); + + out: + spin_unlock_bh(&wdev->action_registrations_lock); + return err; +} + +void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) +{ + struct cfg80211_action_registration *reg, *tmp; + + spin_lock_bh(&wdev->action_registrations_lock); + + list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { + if (reg->nlpid == nlpid) { + list_del(®->list); + kfree(reg); + } + } + + spin_unlock_bh(&wdev->action_registrations_lock); +} + +void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) +{ + struct cfg80211_action_registration *reg, *tmp; + + spin_lock_bh(&wdev->action_registrations_lock); + + list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { + list_del(®->list); + kfree(reg); + } + + spin_unlock_bh(&wdev->action_registrations_lock); +} + +int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + const u8 *buf, size_t len, u64 *cookie) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + const struct ieee80211_mgmt *mgmt; + + if (rdev->ops->action == NULL) + return -EOPNOTSUPP; + if (len < 24 + 1) + return -EINVAL; + + mgmt = (const struct ieee80211_mgmt *) buf; + if (!ieee80211_is_action(mgmt->frame_control)) + return -EINVAL; + if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { + /* Verify that we are associated with the destination AP */ + if (!wdev->current_bss || + memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, + ETH_ALEN) != 0 || + memcmp(wdev->current_bss->pub.bssid, mgmt->da, + ETH_ALEN) != 0) + return -ENOTCONN; + } + + if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) + return -EINVAL; + + /* Transmit the Action frame as requested by user space */ + return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, + buf, len, cookie); +} + +bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, + size_t len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_action_registration *reg; + const u8 *action_data; + int action_data_len; + bool result = false; + + /* frame length - min size excluding category */ + action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); + + /* action data starts with category */ + action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; + + spin_lock_bh(&wdev->action_registrations_lock); + + list_for_each_entry(reg, &wdev->action_registrations, list) { + if (reg->match_len > action_data_len) + continue; + + if (memcmp(reg->match, action_data, reg->match_len)) + continue; + + /* found match! */ + + /* Indicate the received Action frame to user space */ + if (nl80211_send_action(rdev, dev, reg->nlpid, freq, + buf, len, gfp)) + continue; + + result = true; + break; + } + + spin_unlock_bh(&wdev->action_registrations_lock); + + return result; +} +EXPORT_SYMBOL(cfg80211_rx_action); + +void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + /* Indicate TX status of the Action frame to user space */ + nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); +} +EXPORT_SYMBOL(cfg80211_action_tx_status); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a95ab9e4c19e..328112081358 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1,7 +1,7 @@ /* * This is the new netlink-based wireless configuration interface. * - * Copyright 2006-2009 Johannes Berg + * Copyright 2006-2010 Johannes Berg */ #include @@ -145,6 +145,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, + [NL80211_ATTR_FRAME] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, }; /* policy for the attributes */ @@ -577,6 +580,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(flush_pmksa, FLUSH_PMKSA); CMD(remain_on_channel, REMAIN_ON_CHANNEL); CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); + CMD(action, ACTION); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -4526,6 +4530,139 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, return err; } +static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + int err; + + if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) + return -EINVAL; + + if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + /* not much point in registering if we can't reply */ + if (!rdev->ops->action) { + err = -EOPNOTSUPP; + goto out; + } + + err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, + nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), + nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); + unlock_rtnl: + rtnl_unlock(); + return err; +} + +static int nl80211_action(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + struct ieee80211_channel *chan; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + u32 freq; + int err; + void *hdr; + u64 cookie; + struct sk_buff *msg; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + if (!rdev->ops->action) { + err = -EOPNOTSUPP; + goto out; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + err = -EINVAL; + goto out; + } + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (chan == NULL) { + err = -EINVAL; + goto out; + } + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto out; + } + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_ACTION); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto free_msg; + } + err = cfg80211_mlme_action(rdev, dev, chan, channel_type, + nla_data(info->attrs[NL80211_ATTR_FRAME]), + nla_len(info->attrs[NL80211_ATTR_FRAME]), + &cookie); + if (err) + goto free_msg; + + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + genlmsg_end(msg, hdr); + err = genlmsg_reply(msg, info); + goto out; + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4806,6 +4943,18 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_REGISTER_ACTION, + .doit = nl80211_register_action, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_ACTION, + .doit = nl80211_action, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { @@ -5478,6 +5627,110 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, nl80211_mlme_mcgrp.id, gfp); } +int nl80211_send_action(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, + int freq, const u8 *buf, size_t len, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + int err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); + + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return err; + } + + err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); + if (err < 0) + return err; + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + return -ENOBUFS; +} + +void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + if (ack) + NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +static int nl80211_netlink_notify(struct notifier_block * nb, + unsigned long state, + void *_notify) +{ + struct netlink_notify *notify = _notify; + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + + if (state != NETLINK_URELEASE) + return NOTIFY_DONE; + + rcu_read_lock(); + + list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) + list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) + cfg80211_mlme_unregister_actions(wdev, notify->pid); + + rcu_read_unlock(); + + return NOTIFY_DONE; +} + +static struct notifier_block nl80211_netlink_notifier = { + .notifier_call = nl80211_netlink_notify, +}; + /* initialisation/exit functions */ int nl80211_init(void) @@ -5511,6 +5764,10 @@ int nl80211_init(void) goto err_out; #endif + err = netlink_register_notifier(&nl80211_netlink_notifier); + if (err) + goto err_out; + return 0; err_out: genl_unregister_family(&nl80211_fam); @@ -5519,5 +5776,6 @@ int nl80211_init(void) void nl80211_exit(void) { + netlink_unregister_notifier(&nl80211_netlink_notifier); genl_unregister_family(&nl80211_fam); } diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 14855b8fb430..4ca511102c6c 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -74,4 +74,12 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); +int nl80211_send_action(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, int freq, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp); + #endif /* __NET_WIRELESS_NL80211_H */ -- GitLab From 31aa8fd6fd30b0f36416df7d09619768d26b4332 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 11:10:03 +0000 Subject: [PATCH 2147/3892] ARM: Add caller information to ioremap This allows the procfs vmallocinfo file to show who created the ioremap regions. Note: __builtin_return_address(0) doesn't do what's expected if its used in an inline function, so we leave __arm_ioremap callers in such places alone. Signed-off-by: Russell King --- arch/arm/include/asm/io.h | 11 ++++++-- arch/arm/mach-davinci/io.c | 2 +- arch/arm/mach-iop13xx/io.c | 7 +++-- arch/arm/mach-msm/io.c | 3 +- arch/arm/mm/ioremap.c | 57 +++++++++++++++++++++++--------------- arch/arm/mm/nommu.c | 12 ++++++++ arch/arm/plat-iop/io.c | 3 +- arch/arm/plat-omap/io.c | 2 +- 8 files changed, 65 insertions(+), 32 deletions(-) diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index d2a59cfc30ce..c980156f3263 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -69,9 +69,16 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); /* * __arm_ioremap takes CPU physical address. * __arm_ioremap_pfn takes a Page Frame Number and an offset into that page + * The _caller variety takes a __builtin_return_address(0) value for + * /proc/vmalloc to use - and should only be used in non-inline functions. */ -extern void __iomem * __arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int); -extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int); +extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long, + size_t, unsigned int, void *); +extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int, + void *); + +extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int); +extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int); extern void __iounmap(volatile void __iomem *addr); /* diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c index 49912b48b1b0..a1c0b6b99edf 100644 --- a/arch/arm/mach-davinci/io.c +++ b/arch/arm/mach-davinci/io.c @@ -24,7 +24,7 @@ void __iomem *davinci_ioremap(unsigned long p, size_t size, unsigned int type) if (BETWEEN(p, IO_PHYS, IO_SIZE)) return XLATE(p, IO_PHYS, IO_VIRT); - return __arm_ioremap(p, size, type); + return __arm_ioremap_caller(p, size, type, __builtin_return_address(0)); } EXPORT_SYMBOL(davinci_ioremap); diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c index 529580997814..48642e66c566 100644 --- a/arch/arm/mach-iop13xx/io.c +++ b/arch/arm/mach-iop13xx/io.c @@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, (cookie - IOP13XX_PCIE_LOWER_MEM_RA)); break; case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA: - retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA + + retval = __arm_ioremap_caller(IOP13XX_PBI_LOWER_MEM_PA + (cookie - IOP13XX_PBI_LOWER_MEM_RA), - size, mtype); + size, mtype, __builtin_return_address(0)); break; case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA: retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie); @@ -75,7 +75,8 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie); break; default: - retval = __arm_ioremap(cookie, size, mtype); + retval = __arm_ioremap_caller(cookie, size, mtype, + __builtin_return_address(0)); } return retval; diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 1c5e7dac086f..05f96b780aa6 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -76,5 +76,6 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) mtype = MT_DEVICE_NONSHARED; } - return __arm_ioremap(phys_addr, size, mtype); + return __arm_ioremap_caller(phys_addr, size, mtype, + __builtin_return_address(0)); } diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 0ab75c60f7cf..28c8b950ef04 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -139,8 +139,8 @@ void __check_kvm_seq(struct mm_struct *mm) * which requires the new ioremap'd region to be referenced, the CPU will * reference the _old_ region. * - * Note that get_vm_area() allocates a guard 4K page, so we need to mask - * the size back to 1MB aligned or we will overflow in the loop below. + * Note that get_vm_area_caller() allocates a guard 4K page, so we need to + * mask the size back to 1MB aligned or we will overflow in the loop below. */ static void unmap_area_sections(unsigned long virt, unsigned long size) { @@ -254,22 +254,8 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, } #endif - -/* - * Remap an arbitrary physical address space into the kernel virtual - * address space. Needed when the kernel wants to access high addresses - * directly. - * - * NOTE! We need to allow non-page-aligned mappings too: we will obviously - * have to convert them into an offset in a page-aligned mapping, but the - * caller shouldn't need to know that small detail. - * - * 'flags' are the extra L_PTE_ flags that you want to specify for this - * mapping. See for more information. - */ -void __iomem * -__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, - unsigned int mtype) +void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, + unsigned long offset, size_t size, unsigned int mtype, void *caller) { const struct mem_type *type; int err; @@ -291,7 +277,7 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, */ size = PAGE_ALIGN(offset + size); - area = get_vm_area(size, VM_IOREMAP); + area = get_vm_area_caller(size, VM_IOREMAP, caller); if (!area) return NULL; addr = (unsigned long)area->addr; @@ -318,10 +304,9 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, flush_cache_vmap(addr, addr + size); return (void __iomem *) (offset + addr); } -EXPORT_SYMBOL(__arm_ioremap_pfn); -void __iomem * -__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) +void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size, + unsigned int mtype, void *caller) { unsigned long last_addr; unsigned long offset = phys_addr & ~PAGE_MASK; @@ -334,7 +319,33 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) if (!size || last_addr < phys_addr) return NULL; - return __arm_ioremap_pfn(pfn, offset, size, mtype); + return __arm_ioremap_pfn_caller(pfn, offset, size, mtype, + caller); +} + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ +void __iomem * +__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, + unsigned int mtype) +{ + return __arm_ioremap_pfn_caller(pfn, offset, size, mtype, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(__arm_ioremap_pfn); + +void __iomem * +__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) +{ + return __arm_ioremap_caller(phys_addr, size, mtype, + __builtin_return_address(0)); } EXPORT_SYMBOL(__arm_ioremap); diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 374a8311bc84..9bfeb6b9509a 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -74,6 +74,12 @@ void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, } EXPORT_SYMBOL(__arm_ioremap_pfn); +void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset, + size_t size, unsigned int mtype, void *caller) +{ + return __arm_ioremap_pfn(pfn, offset, size, mtype); +} + void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) { @@ -81,6 +87,12 @@ void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size, } EXPORT_SYMBOL(__arm_ioremap); +void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size, + unsigned int mtype, void *caller) +{ + return __arm_ioremap(phys_addr, size, mtype); +} + void __iounmap(volatile void __iomem *addr) { } diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c index ed0bbece0d61..e15bc17db90b 100644 --- a/arch/arm/plat-iop/io.c +++ b/arch/arm/plat-iop/io.c @@ -34,7 +34,8 @@ void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size, retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie); break; default: - retval = __arm_ioremap(cookie, size, mtype); + retval = __arm_ioremap_caller(cookie, size, mtype, + __builtin_return_address(0)); } return retval; diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c index 0cfd54f519c4..4cbd4fb3232c 100644 --- a/arch/arm/plat-omap/io.c +++ b/arch/arm/plat-omap/io.c @@ -128,7 +128,7 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type) return XLATE(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_VIRT); } #endif - return __arm_ioremap(p, size, type); + return __arm_ioremap_caller(p, size, type, __builtin_return_address(0)); } EXPORT_SYMBOL(omap_ioremap); -- GitLab From 7921fc4a25800f4210bca96c05dea67a6b736d32 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Jan 2010 17:05:08 +0000 Subject: [PATCH 2148/3892] ARM: remove old RTC support All RTC drivers have been converted to rtclib, so the old code providing the set_rtc function pointer, save_time_delta() and restore_time_delta() functions is obsolete. Remove it. Signed-off-by: Russell King --- arch/arm/include/asm/mach/time.h | 8 ---- arch/arm/kernel/time.c | 74 -------------------------------- 2 files changed, 82 deletions(-) diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h index b2cc1fcd0400..8bffc3ff3acf 100644 --- a/arch/arm/include/asm/mach/time.h +++ b/arch/arm/include/asm/mach/time.h @@ -46,12 +46,4 @@ struct sys_timer { extern struct sys_timer *system_timer; extern void timer_tick(void); -/* - * Kernel time keeping support. - */ -struct timespec; -extern int (*set_rtc)(void); -extern void save_time_delta(struct timespec *delta, struct timespec *rtc); -extern void restore_time_delta(struct timespec *delta, struct timespec *rtc); - #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index d38cdf2c8276..e26f966d117b 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -10,11 +10,6 @@ * * This file contains the ARM-specific time handling details: * reading the RTC at bootup, etc... - * - * 1994-07-02 Alan Modra - * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime - * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include #include @@ -77,11 +72,6 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif -/* - * hook for setting the RTC's idea of the current time. - */ -int (*set_rtc)(void); - #ifndef CONFIG_GENERIC_TIME static unsigned long dummy_gettimeoffset(void) { @@ -89,36 +79,6 @@ static unsigned long dummy_gettimeoffset(void) } #endif -static unsigned long next_rtc_update; - -/* - * If we have an externally synchronized linux clock, then update - * CMOS clock accordingly every ~11 minutes. set_rtc() has to be - * called as close as possible to 500 ms before the new second - * starts. - */ -static inline void do_set_rtc(void) -{ - if (!ntp_synced() || set_rtc == NULL) - return; - - if (next_rtc_update && - time_before((unsigned long)xtime.tv_sec, next_rtc_update)) - return; - - if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) && - xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1)) - return; - - if (set_rtc()) - /* - * rtc update failed. Try again in 60s - */ - next_rtc_update = xtime.tv_sec + 60; - else - next_rtc_update = xtime.tv_sec + 660; -} - #ifdef CONFIG_LEDS static void dummy_leds_event(led_event_t evt) @@ -295,39 +255,6 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); #endif /* !CONFIG_GENERIC_TIME */ -/** - * save_time_delta - Save the offset between system time and RTC time - * @delta: pointer to timespec to store delta - * @rtc: pointer to timespec for current RTC time - * - * Return a delta between the system time and the RTC time, such - * that system time can be restored later with restore_time_delta() - */ -void save_time_delta(struct timespec *delta, struct timespec *rtc) -{ - set_normalized_timespec(delta, - xtime.tv_sec - rtc->tv_sec, - xtime.tv_nsec - rtc->tv_nsec); -} -EXPORT_SYMBOL(save_time_delta); - -/** - * restore_time_delta - Restore the current system time - * @delta: delta returned by save_time_delta() - * @rtc: pointer to timespec for current RTC time - */ -void restore_time_delta(struct timespec *delta, struct timespec *rtc) -{ - struct timespec ts; - - set_normalized_timespec(&ts, - delta->tv_sec + rtc->tv_sec, - delta->tv_nsec + rtc->tv_nsec); - - do_settimeofday(&ts); -} -EXPORT_SYMBOL(restore_time_delta); - #ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. @@ -336,7 +263,6 @@ void timer_tick(void) { profile_tick(CPU_PROFILING); do_leds(); - do_set_rtc(); write_seqlock(&xtime_lock); do_timer(1); write_sequnlock(&xtime_lock); -- GitLab From 373b32abf9b33616ad94283461bb2ab49e8371d5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Jan 2010 17:15:32 +0000 Subject: [PATCH 2149/3892] ARM: move LED support code out of arch/arm/kernel/time.c Signed-off-by: Russell King --- arch/arm/kernel/Makefile | 1 + arch/arm/kernel/leds.c | 115 +++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/time.c | 104 ----------------------------------- 3 files changed, 116 insertions(+), 104 deletions(-) create mode 100644 arch/arm/kernel/leds.c diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index dd00f747e2ad..eb0284cd8661 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -17,6 +17,7 @@ obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o return_address.o setup.o signal.o \ sys_arm.o stacktrace.o time.o traps.o +obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o obj-$(CONFIG_ISA_DMA_API) += dma.o diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c new file mode 100644 index 000000000000..31a316c1777b --- /dev/null +++ b/arch/arm/kernel/leds.c @@ -0,0 +1,115 @@ +/* + * LED support code, ripped out of arch/arm/kernel/time.c + * + * Copyright (C) 1994-2001 Russell King + * + * 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 + +static void dummy_leds_event(led_event_t evt) +{ +} + +void (*leds_event)(led_event_t) = dummy_leds_event; + +struct leds_evt_name { + const char name[8]; + int on; + int off; +}; + +static const struct leds_evt_name evt_names[] = { + { "amber", led_amber_on, led_amber_off }, + { "blue", led_blue_on, led_blue_off }, + { "green", led_green_on, led_green_off }, + { "red", led_red_on, led_red_off }, +}; + +static ssize_t leds_store(struct sys_device *dev, + struct sysdev_attribute *attr, + const char *buf, size_t size) +{ + int ret = -EINVAL, len = strcspn(buf, " "); + + if (len > 0 && buf[len] == '\0') + len--; + + if (strncmp(buf, "claim", len) == 0) { + leds_event(led_claim); + ret = size; + } else if (strncmp(buf, "release", len) == 0) { + leds_event(led_release); + ret = size; + } else { + int i; + + for (i = 0; i < ARRAY_SIZE(evt_names); i++) { + if (strlen(evt_names[i].name) != len || + strncmp(buf, evt_names[i].name, len) != 0) + continue; + if (strncmp(buf+len, " on", 3) == 0) { + leds_event(evt_names[i].on); + ret = size; + } else if (strncmp(buf+len, " off", 4) == 0) { + leds_event(evt_names[i].off); + ret = size; + } + break; + } + } + return ret; +} + +static SYSDEV_ATTR(event, 0200, NULL, leds_store); + +static int leds_suspend(struct sys_device *dev, pm_message_t state) +{ + leds_event(led_stop); + return 0; +} + +static int leds_resume(struct sys_device *dev) +{ + leds_event(led_start); + return 0; +} + +static int leds_shutdown(struct sys_device *dev) +{ + leds_event(led_halted); + return 0; +} + +static struct sysdev_class leds_sysclass = { + .name = "leds", + .shutdown = leds_shutdown, + .suspend = leds_suspend, + .resume = leds_resume, +}; + +static struct sys_device leds_device = { + .id = 0, + .cls = &leds_sysclass, +}; + +static int __init leds_init(void) +{ + int ret; + ret = sysdev_class_register(&leds_sysclass); + if (ret == 0) + ret = sysdev_register(&leds_device); + if (ret == 0) + ret = sysdev_create_file(&leds_device, &attr_event); + return ret; +} + +device_initcall(leds_init); + +EXPORT_SYMBOL(leds_event); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index e26f966d117b..28753805d2d1 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -79,110 +79,6 @@ static unsigned long dummy_gettimeoffset(void) } #endif -#ifdef CONFIG_LEDS - -static void dummy_leds_event(led_event_t evt) -{ -} - -void (*leds_event)(led_event_t) = dummy_leds_event; - -struct leds_evt_name { - const char name[8]; - int on; - int off; -}; - -static const struct leds_evt_name evt_names[] = { - { "amber", led_amber_on, led_amber_off }, - { "blue", led_blue_on, led_blue_off }, - { "green", led_green_on, led_green_off }, - { "red", led_red_on, led_red_off }, -}; - -static ssize_t leds_store(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, size_t size) -{ - int ret = -EINVAL, len = strcspn(buf, " "); - - if (len > 0 && buf[len] == '\0') - len--; - - if (strncmp(buf, "claim", len) == 0) { - leds_event(led_claim); - ret = size; - } else if (strncmp(buf, "release", len) == 0) { - leds_event(led_release); - ret = size; - } else { - int i; - - for (i = 0; i < ARRAY_SIZE(evt_names); i++) { - if (strlen(evt_names[i].name) != len || - strncmp(buf, evt_names[i].name, len) != 0) - continue; - if (strncmp(buf+len, " on", 3) == 0) { - leds_event(evt_names[i].on); - ret = size; - } else if (strncmp(buf+len, " off", 4) == 0) { - leds_event(evt_names[i].off); - ret = size; - } - break; - } - } - return ret; -} - -static SYSDEV_ATTR(event, 0200, NULL, leds_store); - -static int leds_suspend(struct sys_device *dev, pm_message_t state) -{ - leds_event(led_stop); - return 0; -} - -static int leds_resume(struct sys_device *dev) -{ - leds_event(led_start); - return 0; -} - -static int leds_shutdown(struct sys_device *dev) -{ - leds_event(led_halted); - return 0; -} - -static struct sysdev_class leds_sysclass = { - .name = "leds", - .shutdown = leds_shutdown, - .suspend = leds_suspend, - .resume = leds_resume, -}; - -static struct sys_device leds_device = { - .id = 0, - .cls = &leds_sysclass, -}; - -static int __init leds_init(void) -{ - int ret; - ret = sysdev_class_register(&leds_sysclass); - if (ret == 0) - ret = sysdev_register(&leds_device); - if (ret == 0) - ret = sysdev_create_file(&leds_device, &attr_event); - return ret; -} - -device_initcall(leds_init); - -EXPORT_SYMBOL(leds_event); -#endif - #ifdef CONFIG_LEDS_TIMER static inline void do_leds(void) { -- GitLab From e119bfff1f102f8d1505910cd6c09df55c776b43 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Jan 2010 17:23:29 +0000 Subject: [PATCH 2150/3892] ARM: Move creation of /proc/cpu out of alignment.c Always creating this directory avoids other users having to jump through silly hoops when they want to share this directory. Signed-off-by: Russell King --- arch/arm/Kconfig | 4 ++++ arch/arm/kernel/setup.c | 15 ++++++++++++++- arch/arm/mm/alignment.c | 6 +----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c2238cd474c7..b224216c11db 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -52,6 +52,9 @@ config HAVE_TCM bool select GENERIC_ALLOCATOR +config HAVE_PROC_CPU + bool + config NO_IOPORT bool @@ -1229,6 +1232,7 @@ config ALIGNMENT_TRAP bool depends on CPU_CP15_MMU default y if !ARCH_EBSA110 + select HAVE_PROC_CPU if PROC_FS help ARM processors cannot fetch/store information which is not naturally aligned on the bus, i.e., a 4 byte fetch must start at an diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index c6c57b640b6b..5357e48f2c39 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -782,9 +783,21 @@ static int __init topology_init(void) return 0; } - subsys_initcall(topology_init); +#ifdef CONFIG_HAVE_PROC_CPU +static int __init proc_cpu_init(void) +{ + struct proc_dir_entry *res; + + res = proc_mkdir("cpu", NULL); + if (!res) + return -ENOMEM; + return 0; +} +fs_initcall(proc_cpu_init); +#endif + static const char *hwcap_str[] = { "swp", "half", diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index b270d6228fe2..0c5eb6983cef 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -898,11 +898,7 @@ static int __init alignment_init(void) #ifdef CONFIG_PROC_FS struct proc_dir_entry *res; - res = proc_mkdir("cpu", NULL); - if (!res) - return -ENOMEM; - - res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res); + res = create_proc_entry("cpu/alignment", S_IWUSR | S_IRUGO, NULL); if (!res) return -ENOMEM; -- GitLab From 2b0d8c251b8876d530a6bf671eb5425838fa698a Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 11 Jan 2010 23:17:34 +0100 Subject: [PATCH 2151/3892] ARM: 5880/1: arm: use generic infrastructure for early params The ARM setup code includes its own parser for early params, there's also one in the generic init code. This patch removes __early_init (and related code) from arch/arm/kernel/setup.c, and changes users to the generic early_init macro instead. The generic macro takes a char * argument, rather than char **, so we need to update the parser functions a little. Signed-off-by: Jeremy Kerr Signed-off-by: Russell King --- arch/arm/include/asm/setup.h | 12 ------ arch/arm/kernel/setup.c | 62 ++++++++----------------------- arch/arm/kernel/vmlinux.lds.S | 4 -- arch/arm/mach-footbridge/common.c | 7 ++-- arch/arm/mm/init.c | 12 +++--- arch/arm/mm/mmu.c | 41 ++++++++++---------- 6 files changed, 48 insertions(+), 90 deletions(-) diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index 5ccce0a9b03c..f392fb4437af 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -223,18 +223,6 @@ extern struct meminfo meminfo; #define bank_phys_end(bank) ((bank)->start + (bank)->size) #define bank_phys_size(bank) (bank)->size -/* - * Early command line parameters. - */ -struct early_params { - const char *arg; - void (*fn)(char **p); -}; - -#define __early_param(name,fn) \ -static struct early_params __early_##fn __used \ -__attribute__((__section__(".early_param.init"))) = { name, fn } - #endif /* __KERNEL__ */ #endif diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 5357e48f2c39..b01a56a03ed8 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -418,10 +418,11 @@ static int __init arm_add_memory(unsigned long start, unsigned long size) * Pick out the memory size. We look for mem=size@start, * where start and size are "size[KkMm]" */ -static void __init early_mem(char **p) +static int __init early_mem(char *p) { static int usermem __initdata = 0; unsigned long size, start; + char *endp; /* * If the user specifies memory size, we @@ -434,52 +435,15 @@ static void __init early_mem(char **p) } start = PHYS_OFFSET; - size = memparse(*p, p); - if (**p == '@') - start = memparse(*p + 1, p); + size = memparse(p, &endp); + if (*endp == '@') + start = memparse(endp + 1, NULL); arm_add_memory(start, size); -} -__early_param("mem=", early_mem); -/* - * Initial parsing of the command line. - */ -static void __init parse_cmdline(char **cmdline_p, char *from) -{ - char c = ' ', *to = command_line; - int len = 0; - - for (;;) { - if (c == ' ') { - extern struct early_params __early_begin, __early_end; - struct early_params *p; - - for (p = &__early_begin; p < &__early_end; p++) { - int arglen = strlen(p->arg); - - if (memcmp(from, p->arg, arglen) == 0) { - if (to != command_line) - to -= 1; - from += arglen; - p->fn(&from); - - while (*from != ' ' && *from != '\0') - from++; - break; - } - } - } - c = *from++; - if (!c) - break; - if (COMMAND_LINE_SIZE <= ++len) - break; - *to++ = c; - } - *to = '\0'; - *cmdline_p = command_line; + return 0; } +early_param("mem", early_mem); static void __init setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) @@ -740,9 +704,15 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) _edata; init_mm.brk = (unsigned long) _end; - memcpy(boot_command_line, from, COMMAND_LINE_SIZE); - boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; - parse_cmdline(cmdline_p, from); + /* parse_early_param needs a boot_command_line */ + strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); + + /* populate command_line too for later use, preserving boot_command_line */ + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + + parse_early_param(); + paging_init(mdesc); request_standard_resources(&meminfo, mdesc); diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 4957e13ef55b..b16c07914b55 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -43,10 +43,6 @@ SECTIONS INIT_SETUP(16) - __early_begin = .; - *(.early_param.init) - __early_end = .; - INIT_CALLS CON_INITCALL SECURITY_INITCALL diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c index 41febc796b1c..e3bc3f6f6b10 100644 --- a/arch/arm/mach-footbridge/common.c +++ b/arch/arm/mach-footbridge/common.c @@ -32,12 +32,13 @@ unsigned int mem_fclk_21285 = 50000000; EXPORT_SYMBOL(mem_fclk_21285); -static void __init early_fclk(char **arg) +static int __init early_fclk(char *arg) { - mem_fclk_21285 = simple_strtoul(*arg, arg, 0); + mem_fclk_21285 = simple_strtoul(arg, NULL, 0); + return 0; } -__early_param("mem_fclk_21285=", early_fclk); +early_param("mem_fclk_21285", early_fclk); static int __init parse_tag_memclk(const struct tag *tag) { diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index a04ffbbbe253..a340569b991e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -32,19 +32,21 @@ static unsigned long phys_initrd_start __initdata = 0; static unsigned long phys_initrd_size __initdata = 0; -static void __init early_initrd(char **p) +static int __init early_initrd(char *p) { unsigned long start, size; + char *endp; - start = memparse(*p, p); - if (**p == ',') { - size = memparse((*p) + 1, p); + start = memparse(p, &endp); + if (*endp == ',') { + size = memparse(endp + 1, NULL); phys_initrd_start = start; phys_initrd_size = size; } + return 0; } -__early_param("initrd=", early_initrd); +early_param("initrd", early_initrd); static int __init parse_tag_initrd(const struct tag *tag) { diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 1708da82da96..88f5d71248d9 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -100,18 +100,17 @@ static struct cachepolicy cache_policies[] __initdata = { * writebuffer to be turned off. (Note: the write * buffer should not be on and the cache off). */ -static void __init early_cachepolicy(char **p) +static int __init early_cachepolicy(char *p) { int i; for (i = 0; i < ARRAY_SIZE(cache_policies); i++) { int len = strlen(cache_policies[i].policy); - if (memcmp(*p, cache_policies[i].policy, len) == 0) { + if (memcmp(p, cache_policies[i].policy, len) == 0) { cachepolicy = i; cr_alignment &= ~cache_policies[i].cr_mask; cr_no_alignment &= ~cache_policies[i].cr_mask; - *p += len; break; } } @@ -130,36 +129,37 @@ static void __init early_cachepolicy(char **p) } flush_cache_all(); set_cr(cr_alignment); + return 0; } -__early_param("cachepolicy=", early_cachepolicy); +early_param("cachepolicy", early_cachepolicy); -static void __init early_nocache(char **__unused) +static int __init early_nocache(char *__unused) { char *p = "buffered"; printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p); - early_cachepolicy(&p); + early_cachepolicy(p); + return 0; } -__early_param("nocache", early_nocache); +early_param("nocache", early_nocache); -static void __init early_nowrite(char **__unused) +static int __init early_nowrite(char *__unused) { char *p = "uncached"; printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p); - early_cachepolicy(&p); + early_cachepolicy(p); + return 0; } -__early_param("nowb", early_nowrite); +early_param("nowb", early_nowrite); -static void __init early_ecc(char **p) +static int __init early_ecc(char *p) { - if (memcmp(*p, "on", 2) == 0) { + if (memcmp(p, "on", 2) == 0) ecc_mask = PMD_PROTECTION; - *p += 2; - } else if (memcmp(*p, "off", 3) == 0) { + else if (memcmp(p, "off", 3) == 0) ecc_mask = 0; - *p += 3; - } + return 0; } -__early_param("ecc=", early_ecc); +early_param("ecc", early_ecc); static int __init noalign_setup(char *__unused) { @@ -670,9 +670,9 @@ static unsigned long __initdata vmalloc_reserve = SZ_128M; * bytes. This can be used to increase (or decrease) the vmalloc * area - the default is 128m. */ -static void __init early_vmalloc(char **arg) +static int __init early_vmalloc(char *arg) { - vmalloc_reserve = memparse(*arg, arg); + vmalloc_reserve = memparse(arg, NULL); if (vmalloc_reserve < SZ_16M) { vmalloc_reserve = SZ_16M; @@ -687,8 +687,9 @@ static void __init early_vmalloc(char **arg) "vmalloc area is too big, limiting to %luMB\n", vmalloc_reserve >> 20); } + return 0; } -__early_param("vmalloc=", early_vmalloc); +early_param("vmalloc", early_vmalloc); #define VMALLOC_MIN (void *)(VMALLOC_END - vmalloc_reserve) -- GitLab From a9221de66d2d94e6e34c3f56bbdd744935020737 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 20 Jan 2010 17:02:54 +0000 Subject: [PATCH 2152/3892] ARM: add notify_die() support Kernel debuggers want to be informed of die() events, so that they can take some action to allow the problem to be inspected. Provide the hook in a similar manner to x86. Note that we currently don't implement the individual trap hooks. Acked-by: Jason Wessel Signed-off-by: Russell King --- arch/arm/include/asm/system.h | 3 +-- arch/arm/kernel/traps.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 058e7e90881d..ca88e6a84707 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -73,8 +73,7 @@ extern unsigned int mem_fclk_21285; struct pt_regs; -void die(const char *msg, struct pt_regs *regs, int err) - __attribute__((noreturn)); +void die(const char *msg, struct pt_regs *regs, int err); struct siginfo; void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3f361a783f43..1621e5327b2a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -12,15 +12,17 @@ * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably * kill the offending process. */ -#include #include -#include #include #include -#include +#include +#include #include +#include +#include +#include +#include #include -#include #include #include @@ -224,14 +226,21 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #define S_SMP "" #endif -static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) +static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) { struct task_struct *tsk = thread->task; static int die_counter; + int ret; printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", str, err, ++die_counter); sysfs_printk_last_file(); + + /* trap and error numbers are mostly meaningless on ARM */ + ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); + if (ret == NOTIFY_STOP) + return ret; + print_modules(); __show_regs(regs); printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n", @@ -243,6 +252,8 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p dump_backtrace(regs, tsk); dump_instr(KERN_EMERG, regs); } + + return ret; } DEFINE_SPINLOCK(die_lock); @@ -250,16 +261,21 @@ DEFINE_SPINLOCK(die_lock); /* * This function is protected against re-entrancy. */ -NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) +void die(const char *str, struct pt_regs *regs, int err) { struct thread_info *thread = current_thread_info(); + int ret; oops_enter(); spin_lock_irq(&die_lock); console_verbose(); bust_spinlocks(1); - __die(str, err, thread, regs); + ret = __die(str, err, thread, regs); + + if (regs && kexec_should_crash(thread->task)) + crash_kexec(regs); + bust_spinlocks(0); add_taint(TAINT_DIE); spin_unlock_irq(&die_lock); @@ -267,11 +283,10 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) if (in_interrupt()) panic("Fatal exception in interrupt"); - if (panic_on_oops) panic("Fatal exception"); - - do_exit(SIGSEGV); + if (ret != NOTIFY_STOP) + do_exit(SIGSEGV); } void arm_notify_die(const char *str, struct pt_regs *regs, -- GitLab From 24b44a66fa240f6fc63343623ca730d39754047e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 20 Jan 2010 19:05:07 +0100 Subject: [PATCH 2153/3892] ARM: 5889/1: Add atomic64 routines for ARMv6k and above. In preparation for perf-events support, ARM needs to support atomic64_t operations. v6k and above support the ldrexd and strexd instructions to do just that. This patch adds atomic64 support to the ARM architecture. v6k and above make use of new instructions whilst older cores fall back on the generic solution using spinlocks. If and when v7-M cores are supported by Linux, they will need to fall back on the spinlock implementation too. Signed-off-by: Will Deacon Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + arch/arm/include/asm/atomic.h | 228 ++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b224216c11db..762ae536f909 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -12,6 +12,7 @@ config ARM select HAVE_IDE select RTC_LIB select SYS_SUPPORTS_APM_EMULATION + select GENERIC_ATOMIC64 if (!CPU_32v6K) select HAVE_OPROFILE select HAVE_ARCH_KGDB select HAVE_KPROBES if (!XIP_KERNEL) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index d0daeab2234e..e8ddec2cb158 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -235,6 +235,234 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define smp_mb__before_atomic_inc() smp_mb() #define smp_mb__after_atomic_inc() smp_mb() +#ifndef CONFIG_GENERIC_ATOMIC64 +typedef struct { + u64 __aligned(8) counter; +} atomic64_t; + +#define ATOMIC64_INIT(i) { (i) } + +static inline u64 atomic64_read(atomic64_t *v) +{ + u64 result; + + __asm__ __volatile__("@ atomic64_read\n" +" ldrexd %0, %H0, [%1]" + : "=&r" (result) + : "r" (&v->counter) + ); + + return result; +} + +static inline void atomic64_set(atomic64_t *v, u64 i) +{ + u64 tmp; + + __asm__ __volatile__("@ atomic64_set\n" +"1: ldrexd %0, %H0, [%1]\n" +" strexd %0, %2, %H2, [%1]\n" +" teq %0, #0\n" +" bne 1b" + : "=&r" (tmp) + : "r" (&v->counter), "r" (i) + : "cc"); +} + +static inline void atomic64_add(u64 i, atomic64_t *v) +{ + u64 result; + unsigned long tmp; + + __asm__ __volatile__("@ atomic64_add\n" +"1: ldrexd %0, %H0, [%2]\n" +" adds %0, %0, %3\n" +" adc %H0, %H0, %H3\n" +" strexd %1, %0, %H0, [%2]\n" +" teq %1, #0\n" +" bne 1b" + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter), "r" (i) + : "cc"); +} + +static inline u64 atomic64_add_return(u64 i, atomic64_t *v) +{ + u64 result; + unsigned long tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_add_return\n" +"1: ldrexd %0, %H0, [%2]\n" +" adds %0, %0, %3\n" +" adc %H0, %H0, %H3\n" +" strexd %1, %0, %H0, [%2]\n" +" teq %1, #0\n" +" bne 1b" + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter), "r" (i) + : "cc"); + + smp_mb(); + + return result; +} + +static inline void atomic64_sub(u64 i, atomic64_t *v) +{ + u64 result; + unsigned long tmp; + + __asm__ __volatile__("@ atomic64_sub\n" +"1: ldrexd %0, %H0, [%2]\n" +" subs %0, %0, %3\n" +" sbc %H0, %H0, %H3\n" +" strexd %1, %0, %H0, [%2]\n" +" teq %1, #0\n" +" bne 1b" + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter), "r" (i) + : "cc"); +} + +static inline u64 atomic64_sub_return(u64 i, atomic64_t *v) +{ + u64 result; + unsigned long tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_sub_return\n" +"1: ldrexd %0, %H0, [%2]\n" +" subs %0, %0, %3\n" +" sbc %H0, %H0, %H3\n" +" strexd %1, %0, %H0, [%2]\n" +" teq %1, #0\n" +" bne 1b" + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter), "r" (i) + : "cc"); + + smp_mb(); + + return result; +} + +static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new) +{ + u64 oldval; + unsigned long res; + + smp_mb(); + + do { + __asm__ __volatile__("@ atomic64_cmpxchg\n" + "ldrexd %1, %H1, [%2]\n" + "mov %0, #0\n" + "teq %1, %3\n" + "teqeq %H1, %H3\n" + "strexdeq %0, %4, %H4, [%2]" + : "=&r" (res), "=&r" (oldval) + : "r" (&ptr->counter), "r" (old), "r" (new) + : "cc"); + } while (res); + + smp_mb(); + + return oldval; +} + +static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new) +{ + u64 result; + unsigned long tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_xchg\n" +"1: ldrexd %0, %H0, [%2]\n" +" strexd %1, %3, %H3, [%2]\n" +" teq %1, #0\n" +" bne 1b" + : "=&r" (result), "=&r" (tmp) + : "r" (&ptr->counter), "r" (new) + : "cc"); + + smp_mb(); + + return result; +} + +static inline u64 atomic64_dec_if_positive(atomic64_t *v) +{ + u64 result; + unsigned long tmp; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_dec_if_positive\n" +"1: ldrexd %0, %H0, [%2]\n" +" subs %0, %0, #1\n" +" sbc %H0, %H0, #0\n" +" teq %H0, #0\n" +" bmi 2f\n" +" strexd %1, %0, %H0, [%2]\n" +" teq %1, #0\n" +" bne 1b\n" +"2:" + : "=&r" (result), "=&r" (tmp) + : "r" (&v->counter) + : "cc"); + + smp_mb(); + + return result; +} + +static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) +{ + u64 val; + unsigned long tmp; + int ret = 1; + + smp_mb(); + + __asm__ __volatile__("@ atomic64_add_unless\n" +"1: ldrexd %0, %H0, [%3]\n" +" teq %0, %4\n" +" teqeq %H0, %H4\n" +" moveq %1, #0\n" +" beq 2f\n" +" adds %0, %0, %5\n" +" adc %H0, %H0, %H5\n" +" strexd %2, %0, %H0, [%3]\n" +" teq %2, #0\n" +" bne 1b\n" +"2:" + : "=&r" (val), "=&r" (ret), "=&r" (tmp) + : "r" (&v->counter), "r" (u), "r" (a) + : "cc"); + + if (ret) + smp_mb(); + + return ret; +} + +#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) +#define atomic64_inc(v) atomic64_add(1LL, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) +#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) +#define atomic64_dec(v) atomic64_sub(1LL, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) +#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) + +#else /* !CONFIG_GENERIC_ATOMIC64 */ +#include +#endif #include #endif #endif -- GitLab From c5113b61baf7a9a8616eca83e20847e7fecdc679 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 25 Jan 2010 19:43:03 +0100 Subject: [PATCH 2154/3892] ARM: 5897/1: spinlock: don't use deprecated barriers on ARMv7 On ARMv7, the use of the cp15 operations for barriers is deprecated in favour of the isb, dsb, and dmb instructions. Change the locking functions to use the appropriate type of dsb for the architecture being built for. Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- arch/arm/include/asm/spinlock.h | 36 +++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h index c91c64cab922..17eb355707dd 100644 --- a/arch/arm/include/asm/spinlock.h +++ b/arch/arm/include/asm/spinlock.h @@ -5,6 +5,22 @@ #error SMP not supported on pre-ARMv6 CPUs #endif +static inline void dsb_sev(void) +{ +#if __LINUX_ARM_ARCH__ >= 7 + __asm__ __volatile__ ( + "dsb\n" + "sev" + ); +#elif defined(CONFIG_CPU_32v6K) + __asm__ __volatile__ ( + "mcr p15, 0, %0, c7, c10, 4\n" + "sev" + : : "r" (0) + ); +#endif +} + /* * ARMv6 Spin-locking. * @@ -69,13 +85,11 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) __asm__ __volatile__( " str %1, [%0]\n" -#ifdef CONFIG_CPU_32v6K -" mcr p15, 0, %1, c7, c10, 4\n" /* DSB */ -" sev" -#endif : : "r" (&lock->lock), "r" (0) : "cc"); + + dsb_sev(); } /* @@ -132,13 +146,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) __asm__ __volatile__( "str %1, [%0]\n" -#ifdef CONFIG_CPU_32v6K -" mcr p15, 0, %1, c7, c10, 4\n" /* DSB */ -" sev\n" -#endif : : "r" (&rw->lock), "r" (0) : "cc"); + + dsb_sev(); } /* write_can_lock - would write_trylock() succeed? */ @@ -188,14 +200,12 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) " strex %1, %0, [%2]\n" " teq %1, #0\n" " bne 1b" -#ifdef CONFIG_CPU_32v6K -"\n cmp %0, #0\n" -" mcreq p15, 0, %0, c7, c10, 4\n" -" seveq" -#endif : "=&r" (tmp), "=&r" (tmp2) : "r" (&rw->lock) : "cc"); + + if (tmp == 0) + dsb_sev(); } static inline int arch_read_trylock(arch_rwlock_t *rw) -- GitLab From 48ab7e09e0a7c00a217f87e4b57dfbee9c603e79 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 27 Jan 2010 01:13:31 +0100 Subject: [PATCH 2155/3892] ARM: 5906/1: arm: change command_line to cmd_line drivers/of/fdt expects a cmd_line symbol, while arm uses command_line. Change to the former, so that we can eventually share with the fdt code. Signed-off-by: Jeremy Kerr Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b01a56a03ed8..baf5959d639a 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -118,7 +118,7 @@ EXPORT_SYMBOL(elf_platform); static const char *cpu_name; static const char *machine_name; -static char __initdata command_line[COMMAND_LINE_SIZE]; +static char __initdata cmd_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -707,9 +707,9 @@ void __init setup_arch(char **cmdline_p) /* parse_early_param needs a boot_command_line */ strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); - /* populate command_line too for later use, preserving boot_command_line */ - strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); - *cmdline_p = command_line; + /* populate cmd_line too for later use, preserving boot_command_line */ + strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); + *cmdline_p = cmd_line; parse_early_param(); -- GitLab From 11805bcfa411c816b7c76fc40724be6733c74ffc Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 26 Jan 2010 19:09:42 +0100 Subject: [PATCH 2156/3892] ARM: 5905/1: ARM: Global ASID allocation on SMP The current ASID allocation algorithm doesn't ensure the notification of the other CPUs when the ASID rolls over. This may lead to two processes using the same ASID (but different generation) or multiple threads of the same process using different ASIDs. This patch adds the broadcasting of the ASID rollover event to the other CPUs. To avoid a race on multiple CPUs modifying "cpu_last_asid" during the handling of the broadcast, the ASID numbering now starts at "smp_processor_id() + 1". At rollover, the cpu_last_asid will be set to NR_CPUS. Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/mmu.h | 1 + arch/arm/include/asm/mmu_context.h | 15 ++++ arch/arm/mm/context.c | 124 +++++++++++++++++++++++++---- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index b561584d04a1..68870c776671 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -6,6 +6,7 @@ typedef struct { #ifdef CONFIG_CPU_HAS_ASID unsigned int id; + spinlock_t id_lock; #endif unsigned int kvm_seq; } mm_context_t; diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index de6cefb329dd..a0b3cac0547c 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h @@ -43,12 +43,23 @@ void __check_kvm_seq(struct mm_struct *mm); #define ASID_FIRST_VERSION (1 << ASID_BITS) extern unsigned int cpu_last_asid; +#ifdef CONFIG_SMP +DECLARE_PER_CPU(struct mm_struct *, current_mm); +#endif void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); void __new_context(struct mm_struct *mm); static inline void check_context(struct mm_struct *mm) { + /* + * This code is executed with interrupts enabled. Therefore, + * mm->context.id cannot be updated to the latest ASID version + * on a different CPU (and condition below not triggered) + * without first getting an IPI to reset the context. The + * alternative is to take a read_lock on mm->context.id_lock + * (after changing its type to rwlock_t). + */ if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) __new_context(mm); @@ -108,6 +119,10 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, __flush_icache_all(); #endif if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) { +#ifdef CONFIG_SMP + struct mm_struct **crt_mm = &per_cpu(current_mm, cpu); + *crt_mm = next; +#endif check_context(next); cpu_switch_mm(next->pgd, next); if (cache_is_vivt()) diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index a9e22e31eaa1..b0ee9ba3cfab 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -10,12 +10,17 @@ #include #include #include +#include +#include #include #include static DEFINE_SPINLOCK(cpu_asid_lock); unsigned int cpu_last_asid = ASID_FIRST_VERSION; +#ifdef CONFIG_SMP +DEFINE_PER_CPU(struct mm_struct *, current_mm); +#endif /* * We fork()ed a process, and we need a new context for the child @@ -26,13 +31,109 @@ unsigned int cpu_last_asid = ASID_FIRST_VERSION; void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context.id = 0; + spin_lock_init(&mm->context.id_lock); } +static void flush_context(void) +{ + /* set the reserved ASID before flushing the TLB */ + asm("mcr p15, 0, %0, c13, c0, 1\n" : : "r" (0)); + isb(); + local_flush_tlb_all(); + if (icache_is_vivt_asid_tagged()) { + __flush_icache_all(); + dsb(); + } +} + +#ifdef CONFIG_SMP + +static void set_mm_context(struct mm_struct *mm, unsigned int asid) +{ + unsigned long flags; + + /* + * Locking needed for multi-threaded applications where the + * same mm->context.id could be set from different CPUs during + * the broadcast. This function is also called via IPI so the + * mm->context.id_lock has to be IRQ-safe. + */ + spin_lock_irqsave(&mm->context.id_lock, flags); + if (likely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) { + /* + * Old version of ASID found. Set the new one and + * reset mm_cpumask(mm). + */ + mm->context.id = asid; + cpumask_clear(mm_cpumask(mm)); + } + spin_unlock_irqrestore(&mm->context.id_lock, flags); + + /* + * Set the mm_cpumask(mm) bit for the current CPU. + */ + cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); +} + +/* + * Reset the ASID on the current CPU. This function call is broadcast + * from the CPU handling the ASID rollover and holding cpu_asid_lock. + */ +static void reset_context(void *info) +{ + unsigned int asid; + unsigned int cpu = smp_processor_id(); + struct mm_struct *mm = per_cpu(current_mm, cpu); + + /* + * Check if a current_mm was set on this CPU as it might still + * be in the early booting stages and using the reserved ASID. + */ + if (!mm) + return; + + smp_rmb(); + asid = cpu_last_asid + cpu + 1; + + flush_context(); + set_mm_context(mm, asid); + + /* set the new ASID */ + asm("mcr p15, 0, %0, c13, c0, 1\n" : : "r" (mm->context.id)); + isb(); +} + +#else + +static inline void set_mm_context(struct mm_struct *mm, unsigned int asid) +{ + mm->context.id = asid; + cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id())); +} + +#endif + void __new_context(struct mm_struct *mm) { unsigned int asid; spin_lock(&cpu_asid_lock); +#ifdef CONFIG_SMP + /* + * Check the ASID again, in case the change was broadcast from + * another CPU before we acquired the lock. + */ + if (unlikely(((mm->context.id ^ cpu_last_asid) >> ASID_BITS) == 0)) { + cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); + spin_unlock(&cpu_asid_lock); + return; + } +#endif + /* + * At this point, it is guaranteed that the current mm (with + * an old ASID) isn't active on any other CPU since the ASIDs + * are changed simultaneously via IPI. + */ asid = ++cpu_last_asid; if (asid == 0) asid = cpu_last_asid = ASID_FIRST_VERSION; @@ -42,20 +143,15 @@ void __new_context(struct mm_struct *mm) * to start a new version and flush the TLB. */ if (unlikely((asid & ~ASID_MASK) == 0)) { - asid = ++cpu_last_asid; - /* set the reserved ASID before flushing the TLB */ - asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n" - : - : "r" (0)); - isb(); - flush_tlb_all(); - if (icache_is_vivt_asid_tagged()) { - __flush_icache_all(); - dsb(); - } + asid = cpu_last_asid + smp_processor_id() + 1; + flush_context(); +#ifdef CONFIG_SMP + smp_wmb(); + smp_call_function(reset_context, NULL, 1); +#endif + cpu_last_asid += NR_CPUS; } - spin_unlock(&cpu_asid_lock); - cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id())); - mm->context.id = asid; + set_mm_context(mm, asid); + spin_unlock(&cpu_asid_lock); } -- GitLab From 1a28e3d977860dc760909083df625b300f695680 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 1 Feb 2010 23:30:26 +0100 Subject: [PATCH 2157/3892] ARM: 5911/1: ARM: Select CPU_32v6K for CPU_V7 only if ARCH_OMAP2 is not selected Otherwise the kernel built with both CPU_V6 and CPU_V7 will not boot on omap2. Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/mm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index baf638487a2d..4c2e90dc549c 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -399,7 +399,7 @@ config CPU_V6 config CPU_32v6K bool "Support ARM V6K processor extensions" if !SMP depends on CPU_V6 - default y if SMP && !ARCH_MX3 + default y if SMP && !(ARCH_MX3 || ARCH_OMAP2) help Say Y here if your ARMv6 processor supports the 'K' extension. This enables the kernel to use some instructions not present @@ -410,7 +410,7 @@ config CPU_32v6K # ARMv7 config CPU_V7 bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX - select CPU_32v6K + select CPU_32v6K if !ARCH_OMAP2 select CPU_32v7 select CPU_ABRT_EV7 select CPU_PABRT_V7 -- GitLab From d23bc1b3a7e6db935acb9a949a5985d9b77dfd13 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 2 Feb 2010 18:22:16 +0100 Subject: [PATCH 2158/3892] ARM: 5912/1: Define a 32-bit Thumb-2 breakpoint instruction Recognize 0xf7f0 0xa000 as a 32-bit breakpoint instruction for Thumb-2. Signed-off-by: Daniel Jacobowitz Signed-off-by: Russell King --- arch/arm/kernel/ptrace.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index a2ea3854cb3c..bd56673c6a69 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -499,10 +499,41 @@ static struct undef_hook thumb_break_hook = { .fn = break_trap, }; +static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) +{ + unsigned int instr2; + void __user *pc; + + /* Check the second half of the instruction. */ + pc = (void __user *)(instruction_pointer(regs) + 2); + + if (processor_mode(regs) == SVC_MODE) { + instr2 = *(u16 *) pc; + } else { + get_user(instr2, (u16 __user *)pc); + } + + if (instr2 == 0xa000) { + ptrace_break(current, regs); + return 0; + } else { + return 1; + } +} + +static struct undef_hook thumb2_break_hook = { + .instr_mask = 0xffff, + .instr_val = 0xf7f0, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = PSR_T_BIT, + .fn = thumb2_break_trap, +}; + static int __init ptrace_break_init(void) { register_undef_hook(&arm_break_hook); register_undef_hook(&thumb_break_hook); + register_undef_hook(&thumb2_break_hook); return 0; } -- GitLab From 462f39a8c7496c95f4de91ef46d875f46e0fa271 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Feb 2010 10:35:23 +0000 Subject: [PATCH 2159/3892] ARM: ptrace: get rid of PTRACE_{PEEK,POKE}{TEXT,DATA} The generic ptrace_request() handles these for us, so there's no need to duplicate them in arch code. Signed-off-by: Russell King --- arch/arm/kernel/ptrace.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index bd56673c6a69..bdf002bab6a5 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -743,26 +743,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int ret; switch (request) { - /* - * read word at location "addr" in the child process. - */ - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - case PTRACE_PEEKUSR: ret = ptrace_read_user(child, addr, (unsigned long __user *)data); break; - /* - * write the word at location addr. - */ - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - case PTRACE_POKEUSR: ret = ptrace_write_user(child, addr, data); break; -- GitLab From 54cb3dbb4a1cccd6b1bffc169ff638f8e74daf44 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Feb 2010 11:27:45 +0000 Subject: [PATCH 2160/3892] ARM: vfp: fix vfp_sync_state() The more I look at vfp_sync_state(), the more I believe it's trying to do its job in a really obscure way. Essentially, last_VFP_context[] tracks who owns the state in the VFP hardware. If last_VFP_context[] is the context for the thread which we're interested in, then the VFP hardware has context which is not saved in the software state - so we need to bring the software state up to date. If last_VFP_context[] is for some other thread, we really don't care what state the VFP hardware is in; it doesn't contain any information pertinent to the thread we're trying to deal with - so don't touch the hardware. Signed-off-by: Russell King --- arch/arm/vfp/vfpmodule.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f60a5400a25b..86a57aeeda4a 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -444,32 +444,28 @@ void vfp_sync_state(struct thread_info *thread) void vfp_sync_state(struct thread_info *thread) { unsigned int cpu = get_cpu(); - u32 fpexc = fmrx(FPEXC); /* - * If VFP is enabled, the previous state was already saved and - * last_VFP_context updated. + * If the thread we're interested in is the current owner of the + * hardware VFP state, then we need to save its state. */ - if (fpexc & FPEXC_EN) - goto out; - - if (!last_VFP_context[cpu]) - goto out; + if (last_VFP_context[cpu] == &thread->vfpstate) { + u32 fpexc = fmrx(FPEXC); - /* - * Save the last VFP state on this CPU. - */ - fmxr(FPEXC, fpexc | FPEXC_EN); - vfp_save_state(last_VFP_context[cpu], fpexc); - fmxr(FPEXC, fpexc); + /* + * Save the last VFP state on this CPU. + */ + fmxr(FPEXC, fpexc | FPEXC_EN); + vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); + fmxr(FPEXC, fpexc & ~FPEXC_EN); - /* - * Set the context to NULL to force a reload the next time the thread - * uses the VFP. - */ - last_VFP_context[cpu] = NULL; + /* + * Set the context to NULL to force a reload the next time + * the thread uses the VFP. + */ + last_VFP_context[cpu] = NULL; + } -out: put_cpu(); } #endif -- GitLab From ad187f956108e1c56b444706212bf08d84c0bee0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Feb 2010 11:36:23 +0000 Subject: [PATCH 2161/3892] ARM: vfp ptrace: no point flushing hw context for PTRACE_GETVFPREGS If we're only reading the VFP context via the ptrace call, there's no need to invalidate the hardware context - we only need to do that on PTRACE_SETVFPREGS. This allows more efficient monitoring of a traced task. Signed-off-by: Russell King --- arch/arm/include/asm/thread_info.h | 3 ++- arch/arm/kernel/ptrace.c | 6 ++++-- arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 2dfb7d7a66e9..b74970ec02c4 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -115,7 +115,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *); extern void iwmmxt_task_release(struct thread_info *); extern void iwmmxt_task_switch(struct thread_info *); -extern void vfp_sync_state(struct thread_info *thread); +extern void vfp_sync_hwstate(struct thread_info *); +extern void vfp_flush_hwstate(struct thread_info *); #endif diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index bdf002bab6a5..08f899fb76a6 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -700,7 +700,7 @@ static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) union vfp_state *vfp = &thread->vfpstate; struct user_vfp __user *ufp = data; - vfp_sync_state(thread); + vfp_sync_hwstate(thread); /* copy the floating point registers */ if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, @@ -723,7 +723,7 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) union vfp_state *vfp = &thread->vfpstate; struct user_vfp __user *ufp = data; - vfp_sync_state(thread); + vfp_sync_hwstate(thread); /* copy the floating point registers */ if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, @@ -734,6 +734,8 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) if (get_user(vfp->hard.fpscr, &ufp->fpscr)) return -EFAULT; + vfp_flush_hwstate(thread); + return 0; } #endif diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 86a57aeeda4a..def19f83d812 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -430,7 +430,11 @@ static inline void vfp_pm_init(void) { } * saved one. This function is used by the ptrace mechanism. */ #ifdef CONFIG_SMP -void vfp_sync_state(struct thread_info *thread) +void vfp_sync_hwstate(struct thread_info *thread) +{ +} + +void vfp_flush_hwstate(struct thread_info *thread) { /* * On SMP systems, the VFP state is automatically saved at every @@ -441,7 +445,7 @@ void vfp_sync_state(struct thread_info *thread) thread->vfpstate.hard.cpu = NR_CPUS; } #else -void vfp_sync_state(struct thread_info *thread) +void vfp_sync_hwstate(struct thread_info *thread) { unsigned int cpu = get_cpu(); @@ -457,6 +461,23 @@ void vfp_sync_state(struct thread_info *thread) */ fmxr(FPEXC, fpexc | FPEXC_EN); vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); + fmxr(FPEXC, fpexc); + } + + put_cpu(); +} + +void vfp_flush_hwstate(struct thread_info *thread) +{ + unsigned int cpu = get_cpu(); + + /* + * If the thread we're interested in is the current owner of the + * hardware VFP state, then we need to save its state. + */ + if (last_VFP_context[cpu] == &thread->vfpstate) { + u32 fpexc = fmrx(FPEXC); + fmxr(FPEXC, fpexc & ~FPEXC_EN); /* -- GitLab From 424d6b145f863d012c540082d0c1afb5bb4dea48 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 4 Feb 2010 19:35:06 +0100 Subject: [PATCH 2162/3892] ARM: 5916/1: ARM: L2 : Add maintainace by line helper functions This patch adds the cache maintainance by line helper functions. Signed-off-by: Santosh Shilimkar Acked-by: Catalin Marinas Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index cb8fc6573b1b..1a14d18e5713 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -42,6 +42,27 @@ static inline void cache_sync(void) cache_wait(base + L2X0_CACHE_SYNC, 1); } +static inline void l2x0_clean_line(unsigned long addr) +{ + void __iomem *base = l2x0_base; + cache_wait(base + L2X0_CLEAN_LINE_PA, 1); + writel(addr, base + L2X0_CLEAN_LINE_PA); +} + +static inline void l2x0_inv_line(unsigned long addr) +{ + void __iomem *base = l2x0_base; + cache_wait(base + L2X0_INV_LINE_PA, 1); + writel(addr, base + L2X0_INV_LINE_PA); +} + +static inline void l2x0_flush_line(unsigned long addr) +{ + void __iomem *base = l2x0_base; + cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); + writel(addr, base + L2X0_CLEAN_INV_LINE_PA); +} + static inline void l2x0_inv_all(void) { unsigned long flags; @@ -62,23 +83,20 @@ static void l2x0_inv_range(unsigned long start, unsigned long end) spin_lock_irqsave(&l2x0_lock, flags); if (start & (CACHE_LINE_SIZE - 1)) { start &= ~(CACHE_LINE_SIZE - 1); - cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); - writel(start, base + L2X0_CLEAN_INV_LINE_PA); + l2x0_flush_line(start); start += CACHE_LINE_SIZE; } if (end & (CACHE_LINE_SIZE - 1)) { end &= ~(CACHE_LINE_SIZE - 1); - cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); - writel(end, base + L2X0_CLEAN_INV_LINE_PA); + l2x0_flush_line(end); } while (start < end) { unsigned long blk_end = start + min(end - start, 4096UL); while (start < blk_end) { - cache_wait(base + L2X0_INV_LINE_PA, 1); - writel(start, base + L2X0_INV_LINE_PA); + l2x0_inv_line(start); start += CACHE_LINE_SIZE; } @@ -103,8 +121,7 @@ static void l2x0_clean_range(unsigned long start, unsigned long end) unsigned long blk_end = start + min(end - start, 4096UL); while (start < blk_end) { - cache_wait(base + L2X0_CLEAN_LINE_PA, 1); - writel(start, base + L2X0_CLEAN_LINE_PA); + l2x0_clean_line(start); start += CACHE_LINE_SIZE; } @@ -129,8 +146,7 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) unsigned long blk_end = start + min(end - start, 4096UL); while (start < blk_end) { - cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); - writel(start, base + L2X0_CLEAN_INV_LINE_PA); + l2x0_flush_line(start); start += CACHE_LINE_SIZE; } -- GitLab From d309427e792ea750cdd312e7a92cf6047ae44962 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 4 Feb 2010 19:37:09 +0100 Subject: [PATCH 2163/3892] ARM: 5917/1: OMAP4: Add L2 Cache support This patch adds L2 Cache support for OMAP4. External L2 cache is used in OMAP4 CC: Catalin Marinas Signed-off-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/mach-omap2/board-4430sdp.c | 54 ++++++++++++++++++++++ arch/arm/mm/Kconfig | 2 +- arch/arm/plat-omap/include/plat/omap44xx.h | 1 + 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 0c6be6b4a7e2..8ba8fb5b2514 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -28,6 +28,7 @@ #include #include #include +#include static struct platform_device sdp4430_lcd_device = { .name = "sdp4430_lcd", @@ -50,6 +51,59 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = { { OMAP_TAG_LCD, &sdp4430_lcd_config }, }; +#ifdef CONFIG_CACHE_L2X0 +noinline void omap_smc1(u32 fn, u32 arg) +{ + register u32 r12 asm("r12") = fn; + register u32 r0 asm("r0") = arg; + + /* This is common routine cache secure monitor API used to + * modify the PL310 secure registers. + * r0 contains the value to be modified and "r12" contains + * the monitor API number. It uses few CPU registers + * internally and hence they need be backed up including + * link register "lr". + * Explicitly save r11 and r12 the compiler generated code + * won't save it. + */ + asm volatile( + "stmfd r13!, {r11,r12}\n" + "dsb\n" + "smc\n" + "ldmfd r13!, {r11,r12}\n" + : "+r" (r0), "+r" (r12) + : + : "r4", "r5", "r10", "lr", "cc"); +} +EXPORT_SYMBOL(omap_smc1); + +static int __init omap_l2_cache_init(void) +{ + void __iomem *l2cache_base; + + /* To avoid code running on other OMAPs in + * multi-omap builds + */ + if (!cpu_is_omap44xx()) + return -ENODEV; + + /* Static mapping, never released */ + l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); + BUG_ON(!l2cache_base); + + /* Enable PL310 L2 Cache controller */ + omap_smc1(0x102, 0x1); + + /* 32KB way size, 16-way associativity, + * parity disabled + */ + l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff); + + return 0; +} +early_initcall(omap_l2_cache_init); +#endif + static void __init gic_init_irq(void) { void __iomem *base; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 4c2e90dc549c..e859743024a0 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -754,7 +754,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH config CACHE_L2X0 bool "Enable the L2x0 outer cache controller" depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ - REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK + REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK || ARCH_OMAP4 default y select OUTER_CACHE help diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h index ef870de43c29..c7d628ecb467 100644 --- a/arch/arm/plat-omap/include/plat/omap44xx.h +++ b/arch/arm/plat-omap/include/plat/omap44xx.h @@ -40,6 +40,7 @@ #define OMAP44XX_GIC_CPU_BASE 0x48240100 #define OMAP44XX_SCU_BASE 0x48240000 #define OMAP44XX_LOCAL_TWD_BASE 0x48240600 +#define OMAP44XX_L2CACHE_BASE 0x48242000 #define OMAP44XX_WKUPGEN_BASE 0x48281000 #define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000) -- GitLab From 9e65582a8e8715f883a34eea66e0643778ce878d Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 4 Feb 2010 19:42:42 +0100 Subject: [PATCH 2164/3892] ARM: 5919/1: ARM: L2 : Errata 588369: Clean & Invalidate do not invalidate clean lines This patch implements the work-around for the errata 588369.The secure API is used to alter L2 debug register because of trust-zone. This version updated with comments from Russell and Catalin and generated against 2.6.33-rc6 mainline kernel. Detail comments can be found: http://www.spinics.net/lists/linux-omap/msg23431.html Signed-off-by: Woodruff Richard Signed-off-by: Santosh Shilimkar Acked-by: Catalin Marinas Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/Kconfig | 13 +++++++++++++ arch/arm/mm/cache-l2x0.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 762ae536f909..0f1ad743ccdd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -924,6 +924,19 @@ config ARM_ERRATA_460075 ACTLR register. Note that setting specific bits in the ACTLR register may not be available in non-secure mode. +config PL310_ERRATA_588369 + bool "Clean & Invalidate maintenance operations do not invalidate clean lines" + depends on CACHE_L2X0 && ARCH_OMAP4 + help + The PL310 L2 cache controller implements three types of Clean & + Invalidate maintenance operations: by Physical Address + (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). + They are architecturally defined to behave as the execution of a + clean operation followed immediately by an invalidate operation, + both performing to the same memory location. This functionality + is not correctly implemented in PL310 as clean lines are not + invalidated as a result of these operations. Note that this errata + uses Texas Instrument's secure monitor api. endmenu source "arch/arm/common/Kconfig" diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 1a14d18e5713..07334632d3e2 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -56,12 +56,42 @@ static inline void l2x0_inv_line(unsigned long addr) writel(addr, base + L2X0_INV_LINE_PA); } +#ifdef CONFIG_PL310_ERRATA_588369 +static void debug_writel(unsigned long val) +{ + extern void omap_smc1(u32 fn, u32 arg); + + /* + * Texas Instrument secure monitor api to modify the + * PL310 Debug Control Register. + */ + omap_smc1(0x100, val); +} + +static inline void l2x0_flush_line(unsigned long addr) +{ + void __iomem *base = l2x0_base; + + /* Clean by PA followed by Invalidate by PA */ + cache_wait(base + L2X0_CLEAN_LINE_PA, 1); + writel(addr, base + L2X0_CLEAN_LINE_PA); + cache_wait(base + L2X0_INV_LINE_PA, 1); + writel(addr, base + L2X0_INV_LINE_PA); +} +#else + +/* Optimised out for non-errata case */ +static inline void debug_writel(unsigned long val) +{ +} + static inline void l2x0_flush_line(unsigned long addr) { void __iomem *base = l2x0_base; cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); writel(addr, base + L2X0_CLEAN_INV_LINE_PA); } +#endif static inline void l2x0_inv_all(void) { @@ -83,13 +113,17 @@ static void l2x0_inv_range(unsigned long start, unsigned long end) spin_lock_irqsave(&l2x0_lock, flags); if (start & (CACHE_LINE_SIZE - 1)) { start &= ~(CACHE_LINE_SIZE - 1); + debug_writel(0x03); l2x0_flush_line(start); + debug_writel(0x00); start += CACHE_LINE_SIZE; } if (end & (CACHE_LINE_SIZE - 1)) { end &= ~(CACHE_LINE_SIZE - 1); + debug_writel(0x03); l2x0_flush_line(end); + debug_writel(0x00); } while (start < end) { @@ -145,10 +179,12 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) while (start < end) { unsigned long blk_end = start + min(end - start, 4096UL); + debug_writel(0x03); while (start < blk_end) { l2x0_flush_line(start); start += CACHE_LINE_SIZE; } + debug_writel(0x00); if (blk_end < end) { spin_unlock_irqrestore(&l2x0_lock, flags); -- GitLab From 22192b37bbeec5d850c233491f3cb7610363ce34 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 4 Feb 2010 19:44:52 +0100 Subject: [PATCH 2165/3892] ARM: 5920/1: OMAP4: Enable L2 Cache This patch enables L2 cache and associated Errata on the OMAP4430 SDP. Signed-off-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/configs/omap_4430sdp_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig index 3de640ac294b..c48d7b893869 100644 --- a/arch/arm/configs/omap_4430sdp_defconfig +++ b/arch/arm/configs/omap_4430sdp_defconfig @@ -242,10 +242,13 @@ CONFIG_CPU_CP15_MMU=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_HAS_TLS_REG=y +CONFIG_OUTER_CACHE=y +CONFIG_CACHE_L2X0=y CONFIG_ARM_L1_CACHE_SHIFT=5 # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set +CONFIG_PL310_ERRATA_588369=y CONFIG_ARM_GIC=y # -- GitLab From db9ef1af4879c121c354ad2f653f185f1d50fd89 Mon Sep 17 00:00:00 2001 From: Fenkart/Bostandzhyan Date: Sun, 7 Feb 2010 21:45:47 +0100 Subject: [PATCH 2166/3892] ARM: 5926/1: Add "Virtual kernel memory..." printout. Code based on parisc and x86_32. Tested-by: H Hartley Sweeten Signed-off-by: Andreas Fenkart Signed-off-by: Russell King --- arch/arm/mm/init.c | 78 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index a340569b991e..e8e3a74ac5b5 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -562,7 +563,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi) */ void __init mem_init(void) { - unsigned int codesize, datasize, initsize; + unsigned long reserved_pages, free_pages; int i, node; #ifndef CONFIG_DISCONTIGMEM @@ -598,6 +599,33 @@ void __init mem_init(void) totalram_pages += totalhigh_pages; #endif + reserved_pages = free_pages = 0; + + for_each_online_node(node) { + pg_data_t *n = NODE_DATA(node); + struct page *map = pgdat_page_nr(n, 0) - n->node_start_pfn; + + for_each_nodebank(i, &meminfo, node) { + struct membank *bank = &meminfo.bank[i]; + unsigned int pfn1, pfn2; + struct page *page, *end; + + pfn1 = bank_pfn_start(bank); + pfn2 = bank_pfn_end(bank); + + page = map + pfn1; + end = map + pfn2; + + do { + if (PageReserved(page)) + reserved_pages++; + else if (!page_count(page)) + free_pages++; + page++; + } while (page < end); + } + } + /* * Since our memory may not be contiguous, calculate the * real number of pages we have in this system @@ -610,16 +638,48 @@ void __init mem_init(void) } printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); - codesize = _etext - _text; - datasize = _end - _data; - initsize = __init_end - __init_begin; - - printk(KERN_NOTICE "Memory: %luKB available (%dK code, " - "%dK data, %dK init, %luK highmem)\n", - nr_free_pages() << (PAGE_SHIFT-10), codesize >> 10, - datasize >> 10, initsize >> 10, + printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n", + nr_free_pages() << (PAGE_SHIFT-10), + free_pages << (PAGE_SHIFT-10), + reserved_pages << (PAGE_SHIFT-10), totalhigh_pages << (PAGE_SHIFT-10)); +#define MLK(b, t) b, t, ((t) - (b)) >> 10 +#define MLM(b, t) b, t, ((t) - (b)) >> 20 +#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) + + printk(KERN_NOTICE "Virtual kernel memory layout:\n" + " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" +#ifdef CONFIG_HIGHMEM + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif + " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" + " .init : 0x%p" " - 0x%p" " (%4d kB)\n" + " .text : 0x%p" " - 0x%p" " (%4d kB)\n" + " .data : 0x%p" " - 0x%p" " (%4d kB)\n", + + MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + + (PAGE_SIZE)), + MLK(FIXADDR_START, FIXADDR_TOP), + MLM(VMALLOC_START, (unsigned long)VMALLOC_END), + MLM(PAGE_OFFSET, (unsigned long)high_memory), +#ifdef CONFIG_HIGHMEM + MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) * + (PAGE_SIZE)), +#endif + MLM(MODULES_VADDR, MODULES_END), + + MLK_ROUNDUP(__init_begin, __init_end), + MLK_ROUNDUP(_text, _etext), + MLK_ROUNDUP(_data, _edata)); + +#undef MLK +#undef MLM +#undef MLK_ROUNDUP + if (PAGE_SIZE >= 16384 && num_physpages <= 128) { extern int sysctl_overcommit_memory; /* -- GitLab From a7bd08c82e4f74387a39eeebb942712f23967420 Mon Sep 17 00:00:00 2001 From: Fenkart/Bostandzhyan Date: Sun, 7 Feb 2010 21:46:33 +0100 Subject: [PATCH 2167/3892] ARM: 5927/1: Make delimiters of DMA area globally visibly. Adds DMA area to 'virtual memory map' startup message Tested-by: H Hartley Sweeten Signed-off-by: Andreas Fenkart Signed-off-by: Russell King --- arch/arm/include/asm/memory.h | 19 +++++++++++-------- arch/arm/mm/dma-mapping.c | 3 --- arch/arm/mm/init.c | 6 ++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 5421d82a2572..f5e693b8bab3 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -76,6 +76,17 @@ */ #define IOREMAP_MAX_ORDER 24 +/* + * Size of DMA-consistent memory region. Must be multiple of 2M, + * between 2MB and 14MB inclusive. + */ +#ifndef CONSISTENT_DMA_SIZE +#define CONSISTENT_DMA_SIZE SZ_2M +#endif + +#define CONSISTENT_END (0xffe00000UL) +#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE) + #else /* CONFIG_MMU */ /* @@ -112,14 +123,6 @@ #endif /* !CONFIG_MMU */ -/* - * Size of DMA-consistent memory region. Must be multiple of 2M, - * between 2MB and 14MB inclusive. - */ -#ifndef CONSISTENT_DMA_SIZE -#define CONSISTENT_DMA_SIZE SZ_2M -#endif - /* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 26325cb5d368..48eedab1609b 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -29,9 +29,6 @@ #error "CONSISTENT_DMA_SIZE must be multiple of 2MiB" #endif -#define CONSISTENT_END (0xffe00000) -#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE) - #define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT) #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e8e3a74ac5b5..bda481e6bc0f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -651,6 +651,9 @@ void __init mem_init(void) printk(KERN_NOTICE "Virtual kernel memory layout:\n" " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" +#ifdef CONFIG_MMU + " DMA : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" #ifdef CONFIG_HIGHMEM @@ -664,6 +667,9 @@ void __init mem_init(void) MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + (PAGE_SIZE)), MLK(FIXADDR_START, FIXADDR_TOP), +#ifdef CONFIG_MMU + MLM(CONSISTENT_BASE, CONSISTENT_END), +#endif MLM(VMALLOC_START, (unsigned long)VMALLOC_END), MLM(PAGE_OFFSET, (unsigned long)high_memory), #ifdef CONFIG_HIGHMEM -- GitLab From c931b4f655a1b86c929384e674eb8c31795f3bd7 Mon Sep 17 00:00:00 2001 From: Fenkart/Bostandzhyan Date: Sun, 7 Feb 2010 21:47:17 +0100 Subject: [PATCH 2168/3892] ARM: 5928/1: Change type of VMALLOC_END to unsigned long. Makes it consistent with VMALLOC_START Tested-by: H Hartley Sweeten Signed-off-by: Andreas Fenkart Signed-off-by: Russell King --- arch/arm/include/asm/memory.h | 4 ++-- arch/arm/include/asm/pgtable-nommu.h | 4 ++-- arch/arm/mach-davinci/include/mach/hardware.h | 2 +- arch/arm/mach-dove/include/mach/vmalloc.h | 2 +- arch/arm/mach-ep93xx/include/mach/vmalloc.h | 2 +- arch/arm/mach-gemini/include/mach/vmalloc.h | 2 +- arch/arm/mach-iop32x/include/mach/vmalloc.h | 2 +- arch/arm/mach-iop33x/include/mach/vmalloc.h | 2 +- arch/arm/mach-ixp2000/include/mach/vmalloc.h | 2 +- arch/arm/mach-ixp23xx/include/mach/vmalloc.h | 2 +- arch/arm/mach-ixp4xx/include/mach/vmalloc.h | 2 +- arch/arm/mach-kirkwood/include/mach/vmalloc.h | 2 +- arch/arm/mach-lh7a40x/include/mach/vmalloc.h | 2 +- arch/arm/mach-loki/include/mach/vmalloc.h | 2 +- arch/arm/mach-mmp/include/mach/vmalloc.h | 2 +- arch/arm/mach-mv78xx0/include/mach/vmalloc.h | 2 +- arch/arm/mach-nomadik/include/mach/vmalloc.h | 2 +- arch/arm/mach-ns9xxx/include/mach/vmalloc.h | 2 +- arch/arm/mach-orion5x/include/mach/vmalloc.h | 2 +- arch/arm/mach-pxa/include/mach/vmalloc.h | 2 +- arch/arm/mach-realview/include/mach/vmalloc.h | 2 +- arch/arm/mach-s3c24a0/include/mach/vmalloc.h | 2 +- arch/arm/mach-sa1100/include/mach/vmalloc.h | 2 +- arch/arm/mach-u300/include/mach/vmalloc.h | 2 +- arch/arm/mach-ux500/include/mach/vmalloc.h | 2 +- arch/arm/mach-w90x900/include/mach/vmalloc.h | 2 +- arch/arm/mm/init.c | 2 +- arch/arm/plat-mxc/include/mach/vmalloc.h | 2 +- arch/arm/plat-s3c/include/mach/vmalloc.h | 2 +- arch/arm/plat-stmp3xxx/include/mach/vmalloc.h | 2 +- 30 files changed, 32 insertions(+), 32 deletions(-) diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index f5e693b8bab3..4312ee5e3d0b 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -104,11 +104,11 @@ #endif #ifndef PHYS_OFFSET -#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PHYS_OFFSET UL(CONFIG_DRAM_BASE) #endif #ifndef END_MEM -#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) +#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) #endif #ifndef PAGE_OFFSET diff --git a/arch/arm/include/asm/pgtable-nommu.h b/arch/arm/include/asm/pgtable-nommu.h index b011f2e939aa..013cfcdc4839 100644 --- a/arch/arm/include/asm/pgtable-nommu.h +++ b/arch/arm/include/asm/pgtable-nommu.h @@ -86,8 +86,8 @@ extern unsigned int kobjsize(const void *objp); * All 32bit addresses are effectively valid for vmalloc... * Sort of meaningless for non-VM targets. */ -#define VMALLOC_START 0 -#define VMALLOC_END 0xffffffff +#define VMALLOC_START 0UL +#define VMALLOC_END 0xffffffffUL #define FIRST_USER_ADDRESS (0) diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h index 41c89386e39b..c45ba1f62a11 100644 --- a/arch/arm/mach-davinci/include/mach/hardware.h +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -27,7 +27,7 @@ /* * I/O mapping */ -#define IO_PHYS 0x01c00000 +#define IO_PHYS 0x01c00000UL #define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */ #define IO_SIZE 0x00400000 #define IO_VIRT (IO_PHYS + IO_OFFSET) diff --git a/arch/arm/mach-dove/include/mach/vmalloc.h b/arch/arm/mach-dove/include/mach/vmalloc.h index 8b2c974755c6..a28792cf761e 100644 --- a/arch/arm/mach-dove/include/mach/vmalloc.h +++ b/arch/arm/mach-dove/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-dove/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfd800000 +#define VMALLOC_END 0xfd800000UL diff --git a/arch/arm/mach-ep93xx/include/mach/vmalloc.h b/arch/arm/mach-ep93xx/include/mach/vmalloc.h index aed21cd3fe2d..1b3f25d03d39 100644 --- a/arch/arm/mach-ep93xx/include/mach/vmalloc.h +++ b/arch/arm/mach-ep93xx/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-ep93xx/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe800000 +#define VMALLOC_END 0xfe800000UL diff --git a/arch/arm/mach-gemini/include/mach/vmalloc.h b/arch/arm/mach-gemini/include/mach/vmalloc.h index 83e536d9436c..45371eb86fcb 100644 --- a/arch/arm/mach-gemini/include/mach/vmalloc.h +++ b/arch/arm/mach-gemini/include/mach/vmalloc.h @@ -7,4 +7,4 @@ * (at your option) any later version. */ -#define VMALLOC_END 0xF0000000 +#define VMALLOC_END 0xf0000000UL diff --git a/arch/arm/mach-iop32x/include/mach/vmalloc.h b/arch/arm/mach-iop32x/include/mach/vmalloc.h index 85ceb09d85f0..c4862d48e583 100644 --- a/arch/arm/mach-iop32x/include/mach/vmalloc.h +++ b/arch/arm/mach-iop32x/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-iop32x/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe000000 +#define VMALLOC_END 0xfe000000UL diff --git a/arch/arm/mach-iop33x/include/mach/vmalloc.h b/arch/arm/mach-iop33x/include/mach/vmalloc.h index f9f99dea9bc4..48331dc23704 100644 --- a/arch/arm/mach-iop33x/include/mach/vmalloc.h +++ b/arch/arm/mach-iop33x/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-iop33x/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe000000 +#define VMALLOC_END 0xfe000000UL diff --git a/arch/arm/mach-ixp2000/include/mach/vmalloc.h b/arch/arm/mach-ixp2000/include/mach/vmalloc.h index d195e35aed3b..61c8dae24f95 100644 --- a/arch/arm/mach-ixp2000/include/mach/vmalloc.h +++ b/arch/arm/mach-ixp2000/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * The vmalloc() routines leaves a hole of 4kB between each vmalloced * area for the same reason. ;) */ -#define VMALLOC_END 0xfb000000 +#define VMALLOC_END 0xfb000000UL diff --git a/arch/arm/mach-ixp23xx/include/mach/vmalloc.h b/arch/arm/mach-ixp23xx/include/mach/vmalloc.h index dd519f678d10..896c56a1c00e 100644 --- a/arch/arm/mach-ixp23xx/include/mach/vmalloc.h +++ b/arch/arm/mach-ixp23xx/include/mach/vmalloc.h @@ -7,4 +7,4 @@ * specific static I/O. */ -#define VMALLOC_END (0xec000000) +#define VMALLOC_END (0xec000000UL) diff --git a/arch/arm/mach-ixp4xx/include/mach/vmalloc.h b/arch/arm/mach-ixp4xx/include/mach/vmalloc.h index 7b3580b53adf..9bcd64d59854 100644 --- a/arch/arm/mach-ixp4xx/include/mach/vmalloc.h +++ b/arch/arm/mach-ixp4xx/include/mach/vmalloc.h @@ -1,5 +1,5 @@ /* * arch/arm/mach-ixp4xx/include/mach/vmalloc.h */ -#define VMALLOC_END (0xFF000000) +#define VMALLOC_END (0xff000000UL) diff --git a/arch/arm/mach-kirkwood/include/mach/vmalloc.h b/arch/arm/mach-kirkwood/include/mach/vmalloc.h index 8f48260dcdad..bf162ca3d2c1 100644 --- a/arch/arm/mach-kirkwood/include/mach/vmalloc.h +++ b/arch/arm/mach-kirkwood/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-kirkwood/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe800000 +#define VMALLOC_END 0xfe800000UL diff --git a/arch/arm/mach-lh7a40x/include/mach/vmalloc.h b/arch/arm/mach-lh7a40x/include/mach/vmalloc.h index 3fbd49490bb9..d62da7358b16 100644 --- a/arch/arm/mach-lh7a40x/include/mach/vmalloc.h +++ b/arch/arm/mach-lh7a40x/include/mach/vmalloc.h @@ -7,4 +7,4 @@ * version 2 as published by the Free Software Foundation. * */ -#define VMALLOC_END (0xe8000000) +#define VMALLOC_END (0xe8000000UL) diff --git a/arch/arm/mach-loki/include/mach/vmalloc.h b/arch/arm/mach-loki/include/mach/vmalloc.h index 8dc3bfcbf9f0..5dcbd865443f 100644 --- a/arch/arm/mach-loki/include/mach/vmalloc.h +++ b/arch/arm/mach-loki/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-loki/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe800000 +#define VMALLOC_END 0xfe800000UL diff --git a/arch/arm/mach-mmp/include/mach/vmalloc.h b/arch/arm/mach-mmp/include/mach/vmalloc.h index b60ccaf9fee7..1d0bac003ad0 100644 --- a/arch/arm/mach-mmp/include/mach/vmalloc.h +++ b/arch/arm/mach-mmp/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * linux/arch/arm/mach-mmp/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe000000 +#define VMALLOC_END 0xfe000000UL diff --git a/arch/arm/mach-mv78xx0/include/mach/vmalloc.h b/arch/arm/mach-mv78xx0/include/mach/vmalloc.h index 1c4954386a84..ba26fe98e640 100644 --- a/arch/arm/mach-mv78xx0/include/mach/vmalloc.h +++ b/arch/arm/mach-mv78xx0/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-mv78xx0/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfe000000 +#define VMALLOC_END 0xfe000000UL diff --git a/arch/arm/mach-nomadik/include/mach/vmalloc.h b/arch/arm/mach-nomadik/include/mach/vmalloc.h index be12e31ea528..f83d574d9445 100644 --- a/arch/arm/mach-nomadik/include/mach/vmalloc.h +++ b/arch/arm/mach-nomadik/include/mach/vmalloc.h @@ -1,2 +1,2 @@ -#define VMALLOC_END 0xe8000000 +#define VMALLOC_END 0xe8000000UL diff --git a/arch/arm/mach-ns9xxx/include/mach/vmalloc.h b/arch/arm/mach-ns9xxx/include/mach/vmalloc.h index fe964d3bcc47..c8651974c4b0 100644 --- a/arch/arm/mach-ns9xxx/include/mach/vmalloc.h +++ b/arch/arm/mach-ns9xxx/include/mach/vmalloc.h @@ -11,6 +11,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xf0000000) +#define VMALLOC_END (0xf0000000UL) #endif /* ifndef __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-orion5x/include/mach/vmalloc.h b/arch/arm/mach-orion5x/include/mach/vmalloc.h index 7147a297e97f..06b50aeff7b9 100644 --- a/arch/arm/mach-orion5x/include/mach/vmalloc.h +++ b/arch/arm/mach-orion5x/include/mach/vmalloc.h @@ -2,4 +2,4 @@ * arch/arm/mach-orion5x/include/mach/vmalloc.h */ -#define VMALLOC_END 0xfd800000 +#define VMALLOC_END 0xfd800000UL diff --git a/arch/arm/mach-pxa/include/mach/vmalloc.h b/arch/arm/mach-pxa/include/mach/vmalloc.h index e90c5eeb81dd..bfecfbf5f460 100644 --- a/arch/arm/mach-pxa/include/mach/vmalloc.h +++ b/arch/arm/mach-pxa/include/mach/vmalloc.h @@ -8,4 +8,4 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define VMALLOC_END (0xe8000000) +#define VMALLOC_END (0xe8000000UL) diff --git a/arch/arm/mach-realview/include/mach/vmalloc.h b/arch/arm/mach-realview/include/mach/vmalloc.h index fe0de1b507ac..a2a4c6861407 100644 --- a/arch/arm/mach-realview/include/mach/vmalloc.h +++ b/arch/arm/mach-realview/include/mach/vmalloc.h @@ -18,4 +18,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xf8000000 +#define VMALLOC_END 0xf8000000UL diff --git a/arch/arm/mach-s3c24a0/include/mach/vmalloc.h b/arch/arm/mach-s3c24a0/include/mach/vmalloc.h index 4d4fe4849589..914656820794 100644 --- a/arch/arm/mach-s3c24a0/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c24a0/include/mach/vmalloc.h @@ -12,6 +12,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END (0xe0000000UL) #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-sa1100/include/mach/vmalloc.h b/arch/arm/mach-sa1100/include/mach/vmalloc.h index ec8fdc5a3606..b3d002398480 100644 --- a/arch/arm/mach-sa1100/include/mach/vmalloc.h +++ b/arch/arm/mach-sa1100/include/mach/vmalloc.h @@ -1,4 +1,4 @@ /* * arch/arm/mach-sa1100/include/mach/vmalloc.h */ -#define VMALLOC_END (0xe8000000) +#define VMALLOC_END (0xe8000000UL) diff --git a/arch/arm/mach-u300/include/mach/vmalloc.h b/arch/arm/mach-u300/include/mach/vmalloc.h index b00c51a66fbe..ec423b92b81d 100644 --- a/arch/arm/mach-u300/include/mach/vmalloc.h +++ b/arch/arm/mach-u300/include/mach/vmalloc.h @@ -9,4 +9,4 @@ * End must be above the I/O registers and on an even 2MiB boundary. * Author: Linus Walleij */ -#define VMALLOC_END 0xfe800000 +#define VMALLOC_END 0xfe800000UL diff --git a/arch/arm/mach-ux500/include/mach/vmalloc.h b/arch/arm/mach-ux500/include/mach/vmalloc.h index 86cdbbce1842..a4945cb41172 100644 --- a/arch/arm/mach-ux500/include/mach/vmalloc.h +++ b/arch/arm/mach-ux500/include/mach/vmalloc.h @@ -15,4 +15,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xf0000000 +#define VMALLOC_END 0xf0000000UL diff --git a/arch/arm/mach-w90x900/include/mach/vmalloc.h b/arch/arm/mach-w90x900/include/mach/vmalloc.h index 2f9dfb928533..b067e44500a4 100644 --- a/arch/arm/mach-w90x900/include/mach/vmalloc.h +++ b/arch/arm/mach-w90x900/include/mach/vmalloc.h @@ -18,6 +18,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END (0xe0000000UL) #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index bda481e6bc0f..3a2077239474 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -670,7 +670,7 @@ void __init mem_init(void) #ifdef CONFIG_MMU MLM(CONSISTENT_BASE, CONSISTENT_END), #endif - MLM(VMALLOC_START, (unsigned long)VMALLOC_END), + MLM(VMALLOC_START, VMALLOC_END), MLM(PAGE_OFFSET, (unsigned long)high_memory), #ifdef CONFIG_HIGHMEM MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) * diff --git a/arch/arm/plat-mxc/include/mach/vmalloc.h b/arch/arm/plat-mxc/include/mach/vmalloc.h index 62d97623412f..44243a278434 100644 --- a/arch/arm/plat-mxc/include/mach/vmalloc.h +++ b/arch/arm/plat-mxc/include/mach/vmalloc.h @@ -21,6 +21,6 @@ #define __ASM_ARCH_MXC_VMALLOC_H__ /* vmalloc ending address */ -#define VMALLOC_END 0xF4000000 +#define VMALLOC_END 0xf4000000UL #endif /* __ASM_ARCH_MXC_VMALLOC_H__ */ diff --git a/arch/arm/plat-s3c/include/mach/vmalloc.h b/arch/arm/plat-s3c/include/mach/vmalloc.h index bfd2ca6e3074..299d95f365c9 100644 --- a/arch/arm/plat-s3c/include/mach/vmalloc.h +++ b/arch/arm/plat-s3c/include/mach/vmalloc.h @@ -15,6 +15,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END (0xe0000000UL) #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h index 541b880c1863..943c1a29d641 100644 --- a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h +++ b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h @@ -9,4 +9,4 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ -#define VMALLOC_END (0xF0000000) +#define VMALLOC_END 0xf0000000UL -- GitLab From a183927213df225bd93d21857b6aaafbb95e590d Mon Sep 17 00:00:00 2001 From: Fenkart/Bostandzhyan Date: Sun, 7 Feb 2010 21:47:58 +0100 Subject: [PATCH 2169/3892] ARM: 5929/1: Add checks to detect overlap of memory regions. Tested-by: H Hartley Sweeten Signed-off-by: Andreas Fenkart Signed-off-by: Russell King --- arch/arm/mm/init.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 3a2077239474..7829cb5425f5 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -686,6 +686,23 @@ void __init mem_init(void) #undef MLM #undef MLK_ROUNDUP + /* + * Check boundaries twice: Some fundamental inconsistencies can + * be detected at build time already. + */ +#ifdef CONFIG_MMU + BUILD_BUG_ON(VMALLOC_END > CONSISTENT_BASE); + BUG_ON(VMALLOC_END > CONSISTENT_BASE); + + BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR); + BUG_ON(TASK_SIZE > MODULES_VADDR); +#endif + +#ifdef CONFIG_HIGHMEM + BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET); + BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET); +#endif + if (PAGE_SIZE >= 16384 && num_physpages <= 128) { extern int sysctl_overcommit_memory; /* -- GitLab From 18fe1cad889fe6c1acbf4dfc576e82a13cf1a30c Mon Sep 17 00:00:00 2001 From: Fenkart/Bostandzhyan Date: Sun, 7 Feb 2010 21:48:38 +0100 Subject: [PATCH 2170/3892] ARM: 5930/1: Add PKMAP area description to memory.txt. Also adapts delimiters of neighbouring modules area. Tested-by: H Hartley Sweeten Signed-off-by: Andreas Fenkart Signed-off-by: Russell King --- Documentation/arm/memory.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 9d58c7c5eddd..eb0fae18ffb1 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -59,7 +59,11 @@ PAGE_OFFSET high_memory-1 Kernel direct-mapped RAM region. This maps the platforms RAM, and typically maps all platform RAM in a 1:1 relationship. -TASK_SIZE PAGE_OFFSET-1 Kernel module space +PKMAP_BASE PAGE_OFFSET-1 Permanent kernel mappings + One way of mapping HIGHMEM pages into kernel + space. + +MODULES_VADDR MODULES_END-1 Kernel module space Kernel modules inserted via insmod are placed here using dynamic mappings. -- GitLab From 68fd111e02b979876359c7b471a8bcbca0628b75 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 15 Feb 2010 13:43:25 -0800 Subject: [PATCH 2171/3892] x86, numa: Fix numa emulation calculation of big nodes numa=fake=N uses split_nodes_interleave() to partition the system into N fake nodes. Each node size must have be a multiple of FAKE_NODE_MIN_SIZE, otherwise it is possible to get strange alignments. Because of this, the remaining memory from each node when rounded to FAKE_NODE_MIN_SIZE is consolidated into a number of "big nodes" that are bigger than the rest. The calculation of the number of big nodes is incorrect since it is using a logical AND operator when it should be multiplying the rounded-off portion of each node with N. Signed-off-by: David Rientjes LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/x86/mm/numa_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 83bbc70d11bb..2ecbe0ca0dfc 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -427,7 +427,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr, * Calculate the number of big nodes that can be allocated as a result * of consolidating the remainder. */ - big = ((size & ~FAKE_NODE_MIN_HASH_MASK) & nr_nodes) / + big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * nr_nodes) / FAKE_NODE_MIN_SIZE; size &= FAKE_NODE_MIN_HASH_MASK; -- GitLab From 8df5bb34defd685fe86f60746bbf3d47d1c6f033 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 15 Feb 2010 13:43:30 -0800 Subject: [PATCH 2172/3892] x86, numa: Add fixed node size option for numa emulation numa=fake=N specifies the number of fake nodes, N, to partition the system into and then allocates them by interleaving over physical nodes. This requires knowledge of the system capacity when attempting to allocate nodes of a certain size: either very large nodes to benchmark scalability of code that operates on individual nodes, or very small nodes to find bugs in the VM. This patch introduces numa=fake=[MG] so it is possible to specify the size of each node to allocate. When used, nodes of the size specified will be allocated and interleaved over the set of physical nodes. FAKE_NODE_MIN_SIZE was also moved to the more-appropriate include/asm/numa_64.h. Signed-off-by: David Rientjes LKML-Reference: Signed-off-by: H. Peter Anvin --- Documentation/x86/x86_64/boot-options.txt | 4 + arch/x86/include/asm/mmzone_64.h | 6 -- arch/x86/include/asm/numa_64.h | 5 + arch/x86/mm/numa_64.c | 117 ++++++++++++++++++++-- 4 files changed, 118 insertions(+), 14 deletions(-) diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 29a6ff8bc7d3..01150c64aa73 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -166,6 +166,10 @@ NUMA numa=noacpi Don't parse the SRAT table for NUMA setup + numa=fake=[MG] + If given as a memory unit, fills all system RAM with nodes of + size interleaved over physical nodes. + numa=fake=CMDLINE If a number, fakes CMDLINE nodes and ignores NUMA setup of the actual machine. Otherwise, system memory is configured diff --git a/arch/x86/include/asm/mmzone_64.h b/arch/x86/include/asm/mmzone_64.h index a29f48c2a322..288b96f815a6 100644 --- a/arch/x86/include/asm/mmzone_64.h +++ b/arch/x86/include/asm/mmzone_64.h @@ -39,11 +39,5 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) #define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \ NODE_DATA(nid)->node_spanned_pages) - -#ifdef CONFIG_NUMA_EMU -#define FAKE_NODE_MIN_SIZE (64 * 1024 * 1024) -#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) -#endif - #endif #endif /* _ASM_X86_MMZONE_64_H */ diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index c4ae822e415f..823e070e7c26 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -36,6 +36,11 @@ extern void __cpuinit numa_set_node(int cpu, int node); extern void __cpuinit numa_clear_node(int cpu); extern void __cpuinit numa_add_cpu(int cpu); extern void __cpuinit numa_remove_cpu(int cpu); + +#ifdef CONFIG_NUMA_EMU +#define FAKE_NODE_MIN_SIZE ((u64)64 << 20) +#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) +#endif /* CONFIG_NUMA_EMU */ #else static inline void init_cpu_to_node(void) { } static inline void numa_set_node(int cpu, int node) { } diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 2ecbe0ca0dfc..c47c78ba3aca 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -501,6 +501,102 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr, return ret; } +/* + * Returns the end address of a node so that there is at least `size' amount of + * non-reserved memory or `max_addr' is reached. + */ +static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size) +{ + u64 end = start + size; + + while (end - start - e820_hole_size(start, end) < size) { + end += FAKE_NODE_MIN_SIZE; + if (end > max_addr) { + end = max_addr; + break; + } + } + return end; +} + +/* + * Sets up fake nodes of `size' interleaved over physical nodes ranging from + * `addr' to `max_addr'. The return value is the number of nodes allocated. + */ +static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size) +{ + nodemask_t physnode_mask = NODE_MASK_NONE; + u64 min_size; + int ret = 0; + int i; + + if (!size) + return -1; + /* + * The limit on emulated nodes is MAX_NUMNODES, so the size per node is + * increased accordingly if the requested size is too small. This + * creates a uniform distribution of node sizes across the entire + * machine (but not necessarily over physical nodes). + */ + min_size = (max_addr - addr - e820_hole_size(addr, max_addr)) / + MAX_NUMNODES; + min_size = max(min_size, FAKE_NODE_MIN_SIZE); + if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size) + min_size = (min_size + FAKE_NODE_MIN_SIZE) & + FAKE_NODE_MIN_HASH_MASK; + if (size < min_size) { + pr_err("Fake node size %LuMB too small, increasing to %LuMB\n", + size >> 20, min_size >> 20); + size = min_size; + } + size &= FAKE_NODE_MIN_HASH_MASK; + + for (i = 0; i < MAX_NUMNODES; i++) + if (physnodes[i].start != physnodes[i].end) + node_set(i, physnode_mask); + /* + * Fill physical nodes with fake nodes of size until there is no memory + * left on any of them. + */ + while (nodes_weight(physnode_mask)) { + for_each_node_mask(i, physnode_mask) { + u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT; + u64 end; + + end = find_end_of_node(physnodes[i].start, + physnodes[i].end, size); + /* + * If there won't be at least FAKE_NODE_MIN_SIZE of + * non-reserved memory in ZONE_DMA32 for the next node, + * this one must extend to the boundary. + */ + if (end < dma32_end && dma32_end - end - + e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE) + end = dma32_end; + + /* + * If there won't be enough non-reserved memory for the + * next node, this one must extend to the end of the + * physical node. + */ + if (physnodes[i].end - end - + e820_hole_size(end, physnodes[i].end) < size) + end = physnodes[i].end; + + /* + * Setup the fake node that will be allocated as bootmem + * later. If setup_node_range() returns non-zero, there + * is no more memory available on this physical node. + */ + if (setup_node_range(ret++, &physnodes[i].start, + end - physnodes[i].start, + physnodes[i].end) < 0) + node_clear(i, physnode_mask); + } + } + return ret; +} + /* * Splits num_nodes nodes up equally starting at node_start. The return value * is the number of nodes split up and addr is adjusted to be at the end of the @@ -546,14 +642,7 @@ static int __init split_nodes_equally(u64 *addr, u64 max_addr, int node_start, if (i == num_nodes + node_start - 1) end = max_addr; else - while (end - *addr - e820_hole_size(*addr, end) < - size) { - end += FAKE_NODE_MIN_SIZE; - if (end > max_addr) { - end = max_addr; - break; - } - } + end = find_end_of_node(*addr, max_addr, size); if (setup_node_range(i, addr, end - *addr, max_addr) < 0) break; } @@ -588,6 +677,18 @@ static int __init numa_emulation(unsigned long start_pfn, int num_phys_nodes; num_phys_nodes = setup_physnodes(addr, max_addr, acpi, k8); + /* + * If the numa=fake command-line contains a 'M' or 'G', it represents + * the fixed node size. + */ + if (strchr(cmdline, 'M') || strchr(cmdline, 'G')) { + size = memparse(cmdline, &cmdline); + num_nodes = split_nodes_size_interleave(addr, max_addr, size); + if (num_nodes < 0) + return num_nodes; + goto out; + } + /* * If the numa=fake command-line is just a single number N, split the * system RAM into N fake nodes. -- GitLab From ca2107c9d6cf44fb915402d6f12b9d9ff3925cd7 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 15 Feb 2010 13:43:33 -0800 Subject: [PATCH 2173/3892] x86, numa: Remove configurable node size support for numa emulation Now that numa=fake=[MG] is implemented, it is possible to remove configurable node size support. The command-line parsing was already broken (numa=fake=*128, for example, would not work) and since fake nodes are now interleaved over physical nodes, this support is no longer required. Signed-off-by: David Rientjes LKML-Reference: Signed-off-by: H. Peter Anvin --- Documentation/x86/x86_64/boot-options.txt | 16 +-- arch/x86/mm/numa_64.c | 160 ++-------------------- 2 files changed, 16 insertions(+), 160 deletions(-) diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 01150c64aa73..7fbbaf85f5b7 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -170,19 +170,9 @@ NUMA If given as a memory unit, fills all system RAM with nodes of size interleaved over physical nodes. - numa=fake=CMDLINE - If a number, fakes CMDLINE nodes and ignores NUMA setup of the - actual machine. Otherwise, system memory is configured - depending on the sizes and coefficients listed. For example: - numa=fake=2*512,1024,4*256,*128 - gives two 512M nodes, a 1024M node, four 256M nodes, and the - rest split into 128M chunks. If the last character of CMDLINE - is a *, the remaining memory is divided up equally among its - coefficient: - numa=fake=2*512,2* - gives two 512M nodes and the rest split into two nodes. - Otherwise, the remaining system RAM is allocated to an - additional node. + numa=fake= + If given as an integer, fills all system RAM with N fake nodes + interleaved over physical nodes. ACPI diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index c47c78ba3aca..3307ea8bd43a 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -597,73 +597,6 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size) return ret; } -/* - * Splits num_nodes nodes up equally starting at node_start. The return value - * is the number of nodes split up and addr is adjusted to be at the end of the - * last node allocated. - */ -static int __init split_nodes_equally(u64 *addr, u64 max_addr, int node_start, - int num_nodes) -{ - unsigned int big; - u64 size; - int i; - - if (num_nodes <= 0) - return -1; - if (num_nodes > MAX_NUMNODES) - num_nodes = MAX_NUMNODES; - size = (max_addr - *addr - e820_hole_size(*addr, max_addr)) / - num_nodes; - /* - * Calculate the number of big nodes that can be allocated as a result - * of consolidating the leftovers. - */ - big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * num_nodes) / - FAKE_NODE_MIN_SIZE; - - /* Round down to nearest FAKE_NODE_MIN_SIZE. */ - size &= FAKE_NODE_MIN_HASH_MASK; - if (!size) { - printk(KERN_ERR "Not enough memory for each node. " - "NUMA emulation disabled.\n"); - return -1; - } - - for (i = node_start; i < num_nodes + node_start; i++) { - u64 end = *addr + size; - - if (i < big) - end += FAKE_NODE_MIN_SIZE; - /* - * The final node can have the remaining system RAM. Other - * nodes receive roughly the same amount of available pages. - */ - if (i == num_nodes + node_start - 1) - end = max_addr; - else - end = find_end_of_node(*addr, max_addr, size); - if (setup_node_range(i, addr, end - *addr, max_addr) < 0) - break; - } - return i - node_start + 1; -} - -/* - * Splits the remaining system RAM into chunks of size. The remaining memory is - * always assigned to a final node and can be asymmetric. Returns the number of - * nodes split. - */ -static int __init split_nodes_by_size(u64 *addr, u64 max_addr, int node_start, - u64 size) -{ - int i = node_start; - size = (size << 20) & FAKE_NODE_MIN_HASH_MASK; - while (!setup_node_range(i++, addr, size, max_addr)) - ; - return i - node_start; -} - /* * Sets up the system RAM area from start_pfn to last_pfn according to the * numa=fake command-line option. @@ -671,99 +604,32 @@ static int __init split_nodes_by_size(u64 *addr, u64 max_addr, int node_start, static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn, int acpi, int k8) { - u64 size, addr = start_pfn << PAGE_SHIFT; + u64 addr = start_pfn << PAGE_SHIFT; u64 max_addr = last_pfn << PAGE_SHIFT; - int num_nodes = 0, num = 0, coeff_flag, coeff = -1, i; int num_phys_nodes; + int num_nodes; + int i; num_phys_nodes = setup_physnodes(addr, max_addr, acpi, k8); /* * If the numa=fake command-line contains a 'M' or 'G', it represents - * the fixed node size. + * the fixed node size. Otherwise, if it is just a single number N, + * split the system RAM into N fake nodes. */ if (strchr(cmdline, 'M') || strchr(cmdline, 'G')) { + u64 size; + size = memparse(cmdline, &cmdline); num_nodes = split_nodes_size_interleave(addr, max_addr, size); - if (num_nodes < 0) - return num_nodes; - goto out; - } + } else { + unsigned long n; - /* - * If the numa=fake command-line is just a single number N, split the - * system RAM into N fake nodes. - */ - if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) { - long n = simple_strtol(cmdline, NULL, 0); - - num_nodes = split_nodes_interleave(addr, max_addr, - num_phys_nodes, n); - if (num_nodes < 0) - return num_nodes; - goto out; + n = simple_strtoul(cmdline, NULL, 0); + num_nodes = split_nodes_interleave(addr, max_addr, num_phys_nodes, n); } - /* Parse the command line. */ - for (coeff_flag = 0; ; cmdline++) { - if (*cmdline && isdigit(*cmdline)) { - num = num * 10 + *cmdline - '0'; - continue; - } - if (*cmdline == '*') { - if (num > 0) - coeff = num; - coeff_flag = 1; - } - if (!*cmdline || *cmdline == ',') { - if (!coeff_flag) - coeff = 1; - /* - * Round down to the nearest FAKE_NODE_MIN_SIZE. - * Command-line coefficients are in megabytes. - */ - size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK; - if (size) - for (i = 0; i < coeff; i++, num_nodes++) - if (setup_node_range(num_nodes, &addr, - size, max_addr) < 0) - goto done; - if (!*cmdline) - break; - coeff_flag = 0; - coeff = -1; - } - num = 0; - } -done: - if (!num_nodes) - return -1; - /* Fill remainder of system RAM, if appropriate. */ - if (addr < max_addr) { - if (coeff_flag && coeff < 0) { - /* Split remaining nodes into num-sized chunks */ - num_nodes += split_nodes_by_size(&addr, max_addr, - num_nodes, num); - goto out; - } - switch (*(cmdline - 1)) { - case '*': - /* Split remaining nodes into coeff chunks */ - if (coeff <= 0) - break; - num_nodes += split_nodes_equally(&addr, max_addr, - num_nodes, coeff); - break; - case ',': - /* Do not allocate remaining system RAM */ - break; - default: - /* Give one final node */ - setup_node_range(num_nodes, &addr, max_addr - addr, - max_addr); - num_nodes++; - } - } -out: + if (num_nodes < 0) + return num_nodes; memnode_shift = compute_hash_shift(nodes, num_nodes, NULL); if (memnode_shift < 0) { memnode_shift = 0; -- GitLab From 942fa3b63eb525aa0512ba28c42e656d8efc6787 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 8 Feb 2010 10:03:17 +0000 Subject: [PATCH 2174/3892] x86, mtrr: Kill over the top warn Fixes bugzilla: http://bugzilla.kernel.org/show_bug.cgi?id=12558 Fixes bugzilla: http://bugzilla.kernel.org/show_bug.cgi?id=12317 (and if this really needed to be a warn you'd be responding to the bugs left in bugzilla from it...) Signed-off-by: Alan Cox LKML-Reference: <20100208100239.2568.2940.stgit@localhost.localdomain> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/mtrr/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 4d755846fee6..163e59e272d5 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -464,7 +464,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, tmp |= ~((1<<(hi - 1)) - 1); if (tmp != mask_lo) { - WARN_ONCE(1, KERN_INFO "mtrr: your BIOS has set up an incorrect mask, fixing it up.\n"); + printk(KERN_WARNING "mtrr: your BIOS has configured an incorrect mask, fixing it.\n"); mask_lo = tmp; } } -- GitLab From 40331b21f5fdb746e80fc609ef60ef71b5cd47d9 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 15 Feb 2010 13:57:49 +0000 Subject: [PATCH 2175/3892] video: sh_mobile_lcdcfb: Add wait for vsync. Added FBIO_WAITFORVSYNC ioctl for SH-Mobile devices. Tested on MS7724 and MigoR boards against 2.6.33-rc7. Signed-off-by: Phil Edworthy Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 48 +++++++++++++++++++++++++++++++- include/video/sh_mobile_lcdc.h | 2 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a69830d26f7f..37aeced2dc18 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include